//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
Actions | integer | Yes | |
ActionsLast | real | Yes | |
Afk | boolean | Yes | |
Afk_Dialog | dialog | No | |
AFKTime | integer | Yes | |
AI_BuyID | integer | No | |
AI_BuyMaxCosts | integer | No | |
AI_BuyMinCosts | integer | No | |
AI_Command | string | Yes | |
AI_DangerLevel | real | No | |
AI_Debug | boolean | Yes | true |
AI_Debug_Info | texttag | Yes | |
AI_Initialized | boolean | No | |
AI_IsBot | boolean | Yes | |
AI_IsNewBot | boolean | Yes | |
AI_Number | integer | No | |
AI_SafetyLevel | real | No | |
AI_Spell_Aborted | boolean | No | |
AI_Tank | unit | No | |
Assists | integer | Yes | |
AssistSpree | integer | Yes | |
Aura_Creeps | integer | Yes | |
AV_Bool1 | boolean | Yes | |
AV_Bool2 | boolean | Yes | |
AV_Effect1 | effect | Yes | |
AV_Group1 | group | Yes | |
AV_Group2 | group | Yes | |
AV_Handles | integer | Yes | |
AV_Int1 | integer | Yes | |
AV_Int2 | integer | Yes | |
AV_Int3 | integer | Yes | |
AV_Item1 | item | Yes | |
AV_Lightning | lightning | Yes | |
AV_Loc1 | location | Yes | |
AV_Player1 | player | Yes | |
AV_Real1 | real | Yes | |
AV_Real2 | real | Yes | |
AV_Real3 | real | Yes | |
AV_String1 | string | Yes | |
AV_String2 | string | Yes | |
AV_Tag1 | texttag | Yes | |
AV_Timers | timer | Yes | |
AV_Triggers | trigger | Yes | |
AV_Unit1 | unit | Yes | |
AV_Unit2 | unit | Yes | |
AV_Unit3 | unit | Yes | |
AV_Units | unit | Yes | |
BaseFactory | unit | Yes | |
BaseLast | real | Yes | |
BaseProtTower | unit | Yes | |
Cam_Angle | real | No | 90.00 |
Cam_AngleZ | real | No | 56.00 |
Cam_Distance | real | No | 2750.00 |
Color | string | Yes | |
Color_Blue | integer | Yes | |
Color_Green | integer | Yes | |
Color_Red | integer | Yes | |
Command_Center | integer | Yes | |
Conquest_Button | button | Yes | |
Conquest_Dialog | dialog | No | |
Control_Point | unit | Yes | |
CustomOptions_Button | button | Yes | |
CustomOptions_Dialog | dialog | No | |
CV | boolean | No | |
CV_Timer | timer | No | |
CV_Timer_Remain | real | Yes | 0.00 |
CV_Timer_Stop | real | Yes | |
CV_Timer_Team | integer | No | |
CV_TimerWindow | timerdialog | No | |
Damage_Dealt | real | Yes | |
DamageLast | real | Yes | |
Deaths | integer | Yes | |
Draw | boolean | No | |
enumGrp | group | No | |
ExtRequirements | boolean | No | |
Fog | boolean | No | |
Fog_Modifier | fogmodifier | Yes | |
Fog_Modifier_Max | integer | No | |
Force | player | Yes | |
Force_UpgradeGold | integer | Yes | |
GameMode | integer | No | 1 |
GameMode_Button | button | Yes | |
GameMode_Dialog | dialog | No | |
GameMode_Host | player | No | |
GameMode_Name | string | Yes | |
GameTime | timer | No | |
GaveUp | boolean | Yes | |
GiveUp_Count | integer | Yes | |
GiveUp_HasAlreadyVoted | boolean | Yes | |
GiveUp_Progress | boolean | Yes | |
GiveUp_Ready | boolean | Yes | true |
GoldFactor | integer | No | 1 |
GoldFactorBase | real | No | 1.00 |
Handicap_Ready | boolean | Yes | true |
Healer_Effect | effect | Yes | |
Healer_Rune | item | Yes | |
HighTech | boolean | No | |
HQ | unit | Yes | |
IllusionPackCasted | boolean | Yes | |
Income | real | Yes | |
Item_Buy | boolean | No | |
Item_Check | boolean | No | true |
Item_CreateForHero | itemcode | Yes | |
Item_Upgradeable | boolean | No | |
JunkyardRect | rect | Yes | |
Kick_Count | integer | Yes | |
Kick_HasAlreadyVoted | boolean | Yes | |
Kick_Player | player | No | |
Kick_Progress | boolean | No | |
Kick_Ready | boolean | Yes | true |
Kick_Timeout | integer | Yes | 60 |
Kick_Votes_Needed | integer | No | |
KickBoard | leaderboard | No | |
Kicked | boolean | Yes | |
Killboard | multiboard | Yes | |
KillingSpree | integer | Yes | |
KillLast | integer | Yes | |
Kills | integer | Yes | |
Language | string | No | |
Leaver | player | No | |
LeaversToAI | boolean | No | |
MaxAssistStreak | integer | Yes | |
MaxKillStreak | integer | Yes | |
Mode_Command | string | No | |
MonopolyCountTrades | integer | Yes | |
MonopolyLastTrade | real | Yes | |
MonopolyTeam | integer | Yes | |
Move_Points | location | Yes | |
Multiboard_Escape | boolean | No | true |
MultiboardType | integer | Yes | |
Multikill_Count | integer | Yes | |
Multikill_Sounds | sound | Yes | |
NoEffects | boolean | No | true |
NoExploder | boolean | No | |
NoiseForPlayer | real | Yes | |
NoRequirements | boolean | No | |
NoTinker | boolean | No | |
NoTrader | boolean | No | |
NoUpgrades | boolean | No | |
ObserverInGame | boolean | No | |
OnlyTinker | boolean | No | |
p_KickerLeft | boolean | No | |
Playable_Map | rect | No | RectNull |
Player_Team | integer | Yes | |
PlayerIn | boolean | Yes | |
PlayerInStart | boolean | Yes | |
Players | force | No | |
Players_Start | force | No | |
Players_Team | force | Yes | |
Profit_Creeps | real | Yes | |
Profit_Force | real | Yes | |
Profit_Income | real | Yes | |
Profit_Sold | real | Yes | |
Profit_Tanks | real | Yes | |
Profit_Trader | real | Yes | |
Progress_Bar | texttag | Yes | |
Progress_Timer | texttag | Yes | |
ProMode | boolean | No | |
Reconstruction_Ready | boolean | Yes | true |
ReviveCamPan | boolean | No | true |
Selfkills | integer | Yes | |
Show_WeaponRange | real | No | |
Show_WeaponRange_Mode | integer | No | |
Show_WeaponRange_Text | texttag | Yes | |
Spawn_Points | location | Yes | |
SpeedIndicatorNeg | integer | Yes | |
SpeedIndicatorPos | integer | Yes | |
StartingGold | integer | No | |
StatLast | real | Yes | |
Stats | integer | Yes | |
Stats_Buildings | integer | Yes | |
Stats_Chat | integer | Yes | |
Stats_CPs | integer | Yes | |
Stats_CreepBuy | integer | Yes | |
Stats_CreepKills | integer | Yes | |
Stats_Trader | integer | Yes | |
Stats_Upgrades | integer | Yes | |
Support | real | Yes | |
Tank | unit | Yes | |
Tank_AttachedFire | effect | Yes | |
Tank_FireLevel | integer | Yes | |
Tank_HP | real | Yes | |
Tank_Invisible | integer | Yes | |
Tank_Invulnerable | integer | Yes | |
Tank_Timer | timer | Yes | |
Tank_TimerWindow | timerdialog | Yes | |
TankBounty | real | Yes | |
TankCosts | integer | Yes | |
TankMonopoly | boolean | No | |
TC_Food | integer | Yes | |
TC_Unit | integer | Yes | |
TCC_Mana | real | Yes | |
TCC_Max | integer | No | 2 |
Team_CountPlayers | integer | Yes | |
Team_CPs | integer | Yes | 3 |
Team_Rename | integer | Yes | |
Team_Winning | integer | No | |
TempGroup | group | No | |
TempInt | integer | No | |
TempLoc | location | No | |
TempRect | rect | No | |
Time_Dead | real | Yes | |
Time_Value | integer | No | -10 |
TimerStack | timer | Yes | |
TimerStackN | integer | No | |
Tips | string | Yes | |
TowerModuleUsed | boolean | Yes | |
TradeMarket | unit | Yes | |
TradeMarket_Page2 | unit | Yes | |
Trader_Gold | integer | Yes | |
Trader_Wood | integer | Yes | |
Treant | integer | Yes | |
VehicleFactory | unit | Yes | |
VehicleFactory_Page2 | unit | Yes | |
Weapon_Basic | integer | Yes | |
Weapon_Upgrade | integer | Yes | |
WeaponModifier | real | Yes | |
WeaponRange | integer | Yes | |
Weather_Current | integer | No | |
Weather_Effects | weathereffect | Yes | |
Weather_Enabled | boolean | No | false |
Weather_Timer | timer | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
// general game mode / hosting variables
globals
constant string Version = "880c"
constant integer FillAIPlayers = 0 // how much players should be in a single team minimum, missing players will be filled in by the AI
constant boolean OnlyAI = false // when true, an AI will also play for the local player
boolean DebugMode = false // when true, debug messages, information and commands are available
constant boolean BetaMode = false // when true, the beta messages are enabled
constant boolean VIPCheck = true // when true, only the VIPs may host a beta map online
constant boolean AlternateBounty = true
real InitXPFactor = 1.07 // general XP factor for all players (higher = more XP)
//! Gold
real GeneralGoldFactor = 1.00 // general gold factor, increases bounties, changed by game modes
real IncomeFactor = 1.00 // general passive income factor, does not influence force gold, changed by game modes
boolean GameOver = false
boolean LeagueConfirmed = false // shows if the league bots confirmed that the current game is a league game
boolean LeagueImitation = false // league mode, but without the stats recording on the bots
boolean OpenBeta = false // will only be open beta, if it is properly hosted
boolean SpecialMode = false // Game mode initialization in relation to the host bots
boolean VipGame = false // if a VIP is in game, this allows beta hosting outside of singleplayer and bot hosted games
endglobals
// game constants
globals
constant integer DUMMY_ID = 'h01B'
constant integer PROJECTILE_ID = 'h022'
constant integer DUMMY_EXTENDER_ID = 'A0CA' // There is a trigger, that removes dummies, that casted an ability after some time, some skills channel for a longer time
// So, to prevent that trigger to remove those dummies too early, they are given that ability, which lets the trigger wait a bit more
constant integer AWAY_ITEM_ID = 'I048'
constant integer GAME_START_DELAY = 10 // amount of seconds before the actual game starts (creeps spawn, you get income etc)
constant integer MAX_JUNKYARD_ITEM_COUNT = 15
constant integer MAX_ARRAY_SIZE = 8190
// Unit user data for creeps
// They decide over which waypoints are followed and are used to check for player food reduction
constant integer CF_NORMAL = 1 // Nothing special, go along, nothing to see here
constant integer CF_ALTERNATE_ROUTE = 2 // Take a different path then the other creeps (mid etc)
constant integer CF_MANUAL_CONTROL = 4 // Creeps that got ordered by the player -> don't follow waypoints anymore
constant integer CF_COSTS_FOOD = 8 // Unit_dies trigger has to reduce the players food manually
// This is because those units have a timed life and normally don't count towards the food ressource
constant integer CF_MAX_FLAGS = 4 // The number of flags that are currently used
constant string LeagueWelcome1 = "|cFF1CE6B9Welcome to the official |cFFFF0303Battle Tanks League|cFF1CE6B9!"
constant string LeagueWelcome2 = "|cFF1CE6B9Your personal player stats will be transferred to |cFFFF0303www.btanks.net|cFF1CE6B9!"
constant string LeagueWelcome3 = "|cFF1CE6B9Thanks for trying the new League Mode imitation. This mode exists for pure practicing purposes and does not save your stats."
constant string Cgrey = "|cffaaaaaa"
constant string Cred = "|cffff0000"
constant string Cgreen = "|cff00ff00"
constant string Cpurple = "|c00400080"
constant string Clightblue = "|c000080ff"
constant string Cbesch = "|c00808000"
constant string Cdarkblue = "|c000000a0"
string TeamOneName = "Dark Force"
string TeamTwoName = "Light Force"
constant real CamSmooth = 1.
string array ModeName
endglobals
// player related variables
globals
// League variables
integer array TankBounty // the amount of gold a player got through tank kills
integer array CPTeles // the amount of Control Point Teleports
timer array PlayTimer // counts how long each player was in a game
integer array Multikill // the biggest multikill that a player got
boolean array TankDead //! investigate the function of this one!
integer array LeagueMKCounter // counts the number of multikills of each player
integer array BuildingsKilled
// player customization
boolean array SmoothCam
// player stats
integer array GotTeamkilled
integer array DidTeamkill
integer array ManaUpgrade //the buyable Mana Batteries
real array DeathPenalty //The value that decides if a player gets kicked
real array DeathPenaltyValue //The amount that is added, when a player dies
timer array PenaltyTimer //Timer, that reduces those penalties
boolean array DiedRooted // for Guards, used for correct initialization on respawn
endglobals
// temporal information holders
globals
unit tempControlPoint // used for Control Point Teleports
player KickVotePlayer // the player that initiated the current kick vote
integer DivideMoney // Leaver gold
boolean IgnoreNextItemOnJunkyard = false
endglobals
//TESH.scrollpos=69
//TESH.alwaysfold=0
library TimerAndAttachments
// This library includes functions, that enable you to attach several variables
// to timers or units
// --- template for using this system to attach variables to a timer:
// local timer t
// local integer TimerIndex
//
// set t = NewTimer()
// set TimerIndex = NewTimerIndex(t)
// set udg_AV_Unit1[TimerIndex] = GetTriggerUnit()
// set udg_AV_Int1[TimerIndex] = GetUnitAbilityLevel(GetTriggerUnit(),'A000')
// call TimerStart(t, 2.00, true, function Example_Loop)
// --- To use and release this variables, you have to use this:
// function Example_Loop takes nothing returns nothing
// local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
// local unit Caster = udg_AV_Unit1[LoopTimerId]
// local integer lvl = udg_AV_Int1[LoopTimerId]
//
// if lvl > 5 then
// //You only have to call this, when you want the timer to stop looping of course
// call ReleaseTimer(GetExpiredTimer())
// call ReleaseHandleIndex(LoopTimerId)
// endif
// //Do stuff
// endfunction
function NewTimerIndex takes timer h returns integer
local integer hi=GetHandleId(h)
local integer i=hi-(hi/8000)*8000
loop
exitwhen udg_AV_Handles[i]==0
set i=i+1
endloop
set udg_AV_Handles[i]=hi
set udg_AV_Timers[i]=h
return i
endfunction
function NewTriggerIndex takes trigger h returns integer
local integer hi=GetHandleId(h)
local integer i=hi-(hi/8000)*8000
loop
exitwhen udg_AV_Handles[i]==0
set i=i+1
endloop
set udg_AV_Handles[i]=hi
set udg_AV_Triggers[i]=h
return i
endfunction
function GetHandleIndex takes handle h returns integer
local integer hi=GetHandleId(h)
local integer i=hi-(hi/8000)*8000
loop
exitwhen (udg_AV_Handles[i]==hi) or (i==MAX_ARRAY_SIZE)
set i=i+1
endloop
return i
endfunction
globals
WeaponCore array udg_AV_WeapCore[1]
AISkill array udg_AV_AISkill[1]
endglobals
function ReleaseHandleIndex takes integer i returns nothing
set udg_AV_Handles[i] = 0
set udg_AV_Timers[i] = null
set udg_AV_Triggers[i] = null
set udg_AV_Units[i] = null
set udg_AV_Int1[i] = 0
set udg_AV_Int2[i] = 0
set udg_AV_Int3[i] = 0
set udg_AV_Real1[i] = 0.0
set udg_AV_Real2[i] = 0.0
set udg_AV_Real3[i] = 0.0
set udg_AV_Unit1[i] = null
set udg_AV_Unit2[i] = null
set udg_AV_Unit3[i] = null
set udg_AV_Effect1[i] = null
set udg_AV_Item1[i] = null
set udg_AV_WeapCore[i] = 0
set udg_AV_AISkill[i] = 0
set udg_AV_Bool1[i] = false
set udg_AV_Bool2[i] = false
set udg_AV_Lightning[i] = null
set udg_AV_String1[i] = ""
set udg_AV_String2[i] = ""
set udg_AV_Player1[i] = null
if udg_AV_Loc1[i] != null then
call RemoveLocation(udg_AV_Loc1[i])
set udg_AV_Loc1[i] = null
endif
if udg_AV_Group1[i] != null then
//call DestroyGroup(udg_AV_Group1[i])
set udg_AV_Group1[i] = null
endif
if udg_AV_Group2[i] != null then
//call DestroyGroup(udg_AV_Group2[i])
set udg_AV_Group2[i] = null
endif
if udg_AV_Tag1[i] != null then
call DestroyTextTag(udg_AV_Tag1[i])
set udg_AV_Tag1[i] = null
endif
endfunction
function ReleaseUnit takes nothing returns nothing
//call TriggerSleepAction(2.0)
call ReleaseHandleIndex(GetHandleIndex(GetTriggerUnit()))
call DestroyTrigger(GetTriggeringTrigger())
endfunction
function NewUnitIndex takes unit h returns integer
local integer hi=GetHandleId(h)
local integer i=hi-(hi/8000)*8000
local trigger t = CreateTrigger()
loop
exitwhen udg_AV_Handles[i]==0
set i=i+1
endloop
set udg_AV_Handles[i]=hi
set udg_AV_Units[i]=h
call TriggerRegisterUnitEvent( t, h, EVENT_UNIT_DEATH )
call TriggerAddAction( t, function ReleaseUnit )
return i
endfunction
function NewTimer takes nothing returns timer
if udg_TimerStackN==0 then
return CreateTimer()
endif
set udg_TimerStackN=udg_TimerStackN-1
return udg_TimerStack[udg_TimerStackN]
endfunction
function ReleaseTimer takes timer t returns nothing
call PauseTimer(t)
// Though the array is capable of carrying more timers,
// it does not seem intelligent to keep more than 500 unused timers
if udg_TimerStackN==500 then
call DestroyTimer(t)
else
set udg_TimerStack[udg_TimerStackN]=t
set udg_TimerStackN=udg_TimerStackN+1
endif
endfunction
endlibrary
//TESH.scrollpos=168
//TESH.alwaysfold=0
library BTFramework requires Trace
// Note, that this library is not allowed to use FILTER_XXXXXX in its initializer
// This library includes functions, that either extend or simplify wc3 functions
// These functions are meant to replace the genuine functions in every case, to make sure that this map uses a coherent code base
// Functions in this library shall match the following criteria:
// - they replace a specific wc3 function, to make it easier to use or to adapt it to this map (i.e. GetPlayerNr, NewGroup)
// - they simplify a function call by combining several functions into one, to improve the usability (i.e. ShowTextTag)
// - they extend already existing functions to offer more possibilities
// - they shall not have any dependency to any other library, since most other libraries should use this one, and not the other way round
function DebugMsg takes string s returns nothing
if DebugMode then
call BJDebugMsg(s)
endif
endfunction
// May be used to kill an entire thread from within a called function,
// to find the source of an error
function BreakThread takes nothing returns nothing
local integer i = 1/0
endfunction
function WaitForGameTime takes real GameTime returns real
local real r
loop
set r = GameTime - TimerGetElapsed(udg_GameTime)
exitwhen r <= 0
call TriggerSleepAction(r*0.2)
endloop
return -r
endfunction
function GameTimeWait takes real Duration returns real
local real GameTime = TimerGetElapsed(udg_GameTime)+Duration
local real r
loop
set r = GameTime - TimerGetElapsed(udg_GameTime)
exitwhen r <= 0
call TriggerSleepAction(r*0.2)
endloop
return -r
endfunction
globals
integer udg_GroupStackN=0
group array udg_GroupStack
endglobals
// This function is meant to replace CreateGroup, because this function uses a group array
// which improves performance, since it recycles old groups instead of repeatedly creating new ones
function NewGroup takes nothing returns group
if udg_GroupStackN==0 then
return CreateGroup()
endif
//call DebugMsg("Group count: " + I2S(udg_GroupStackN))
set udg_GroupStackN=udg_GroupStackN-1
if BetaMode and (udg_GroupStack[udg_GroupStackN] == null) then
call BJDebugMsg("Please write \"!report empty group\"")
endif
return udg_GroupStack[udg_GroupStackN]
endfunction
// This function has to be used together with NewGroup, to ensure they both work correctly
// It replaces the DestroyGroup function in this context
function ReleaseGroup takes group g returns nothing
// Though the array is capable of carrying more groups,
// it does not seem intelligent to keep more than 500 unused groups
if udg_GroupStackN==500 then
call DestroyGroup(g)
else
call GroupClear(g)
set udg_GroupStack[udg_GroupStackN]=g
set udg_GroupStackN=udg_GroupStackN+1
endif
endfunction
function GetMaxHumanPlayers takes nothing returns integer
//returns the maximum possible number of human players
return 10
endfunction
function GetMaxPlayers takes nothing returns integer
//returns the maximum possible number of players in the game (including Forces)
return 12
endfunction
globals
boolean udg_PlayerNrInitialized = false
integer array udg_ConvertedPlayerNr
player array udg_PlayerByPlayerNr
endglobals
function Init_PlayerNr_GetPlayerNr takes player p returns integer
local integer Id= GetPlayerId(p)
//to make sure every player Id is 1-based,
//instead of a mixed 0- and 1-based system
if ( Id < GetMaxHumanPlayers() ) then
return Id + 1
elseif ( Id == PLAYER_NEUTRAL_PASSIVE ) then
return 15
else
if ( p == udg_Force[1] ) then
return 11
elseif ( p == udg_Force[2] ) then
return 12
endif
endif
return 0
endfunction
function Init_PlayerNr takes nothing returns nothing
local integer i = 0
if udg_PlayerNrInitialized then
return
endif
set udg_ObserverInGame = not ((GetPlayerSlotState(Player(10)) == PLAYER_SLOT_STATE_EMPTY) and (GetPlayerSlotState(Player(11)) == PLAYER_SLOT_STATE_EMPTY))
// udg_Force[i] is required to initialize this correctly
if udg_ObserverInGame then
set udg_Force[1] = Player(bj_PLAYER_NEUTRAL_VICTIM) //Dark Force
set udg_Force[2] = Player(bj_PLAYER_NEUTRAL_EXTRA) //Light Force
else
set udg_Force[1] = Player(10)
set udg_Force[2] = Player(11)
endif
loop
exitwhen i>15
set udg_ConvertedPlayerNr[i] = Init_PlayerNr_GetPlayerNr(Player(i))
set udg_PlayerByPlayerNr[udg_ConvertedPlayerNr[i]] = Player(i)
set i = i + 1
endloop
set udg_PlayerNrInitialized = true
endfunction
function GetPlayerNr takes player p returns integer
// Just to fix Critical, should not be called with "null" at all,
// and if, it should return 0, not 1 (but that causes a crit)
// Once this problem is solved, remove the if to make this function being inlined
//if(p==null) then
//call DebugMsg("GetPlayerNr(null)")
//call Trace_Print()
//endif
return udg_ConvertedPlayerNr[GetPlayerId(p)]
endfunction
function PolarProjX takes real x, real dist, real angle returns real
return x + dist * Cos(angle * bj_DEGTORAD)
endfunction
function PolarProjY takes real y, real dist, real angle returns real
return y + dist * Sin(angle * bj_DEGTORAD)
endfunction
function GetAngle takes real x1, real y1, real x2, real y2 returns real
return bj_RADTODEG*Atan2(y2-y1,x2-x1)
endfunction
function GetUnitsAngleDeg takes unit a, unit b returns real
return bj_RADTODEG*Atan2(GetUnitY(b) - GetUnitY(a), GetUnitX(b) - GetUnitX(a))
endfunction
function GetUnitsDistance takes unit a, unit b returns real
return SquareRoot((GetUnitX(a) - GetUnitX(b)) * (GetUnitX(a) - GetUnitX(b)) + (GetUnitY(a) - GetUnitY(b)) * (GetUnitY(a) - GetUnitY(b)))
endfunction
function GetXYDistance takes real x1, real y1,real x2,real y2 returns real
return SquareRoot((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
endfunction
function GetPlayer takes integer Id returns player
return udg_PlayerByPlayerNr[Id]
endfunction
function GetName takes unit u returns string
if IsUnitType(u, UNIT_TYPE_HERO) then
return GetHeroProperName(u)
endif
return GetUnitName(u)
endfunction
function ShowTextTag takes string s, unit target, real x, real y, player p returns nothing
local texttag tag = CreateTextTag( )
local real PosX
local real PosY
local real PosZ
local boolean visibility
//x, y - additional offset to the target units position
//when unit is null, these two are used for the position completely
if target == null then
set PosX = x
set PosY = y
set PosZ = 300
else
//target - where to show the text tag
set PosX = GetUnitX(target) + x
set PosY = GetUnitY(target) + y
set PosZ = GetUnitFlyHeight(target)
endif
//p - the player who is supposed to see the tag, when null, everyone can see the tag
if p == null then
set visibility = true
else
set visibility = false
if (p == udg_Force[1]) or (p == udg_Force[2]) then
set visibility = IsPlayerAlly(GetLocalPlayer(), p)
elseif GetLocalPlayer() == p then
set visibility = true
endif
endif
//s - string to be shown, including color code
call SetTextTagText(tag, s, 0.023)
call SetTextTagPos(tag, PosX, PosY, PosZ)
call SetTextTagVisibility(tag, visibility)
call SetTextTagVelocity(tag, 0, 0.03)
call SetTextTagFadepoint(tag, 2 )
call SetTextTagLifespan(tag, 3 )
call SetTextTagPermanent(tag, false )
set tag = null
endfunction
function IsUnitNetted takes unit Caster returns boolean
if (GetUnitAbilityLevel(Caster, 'Beng') > 0) or (GetUnitAbilityLevel(Caster, 'Bens') > 0) or (GetUnitAbilityLevel(Caster, 'Bena') > 0) then
return true
endif
return false
endfunction
function IsUnitStunned takes unit Caster returns boolean
if GetUnitAbilityLevel(Caster, 'BSTN')>0 then //stunned
return true
elseif GetUnitAbilityLevel(Caster, 'BNcs')>0 then //stunned (swarm rockets buff)
return true
elseif GetUnitAbilityLevel(Caster, 'BPSE')>0 then //stunned (pause)
return true
elseif GetUnitAbilityLevel(Caster, 'B010')>0 then //System Overload
return true
elseif IsUnitNetted(Caster) then //Ensnare
return true
elseif GetUnitAbilityLevel(Caster, 'B00K')>0 then //Dimension Shift
return true
elseif GetUnitAbilityLevel(Caster, 'B003')>0 then //Ice Prison (pause)
return true
elseif IsUnitPaused(Caster) then //paused unit
return true
endif
return false
endfunction
// Used for the Hostbot API but hidden here! So sshhh!
// Will not be inlined, and that is important
function Code takes real i returns real
local real j = (i/10.)
set j = SquareRoot(j/7.)
return j
endfunction
function HexToInt takes string Hex returns integer
local integer i = 0
local integer result = 0
local string s
loop
exitwhen i >= StringLength(Hex)
set s = SubString(Hex,i,i+1)
set result = result*16
if s == "A" or s=="a" then
set result = result+10
elseif s == "B" or s=="b" then
set result = result+11
elseif s == "C" or s=="c" then
set result = result+12
elseif s == "D" or s=="d" then
set result = result+13
elseif s == "E" or s=="e" then
set result = result+14
elseif s == "F" or s=="f" then
set result = result+15
else
set result = result+S2I(s)
endif
set i = i + 1
endloop
return result
endfunction
function HexString takes integer i returns string
local string alpha = "0123456789abcdef"
return SubString(alpha, i, i+1)
endfunction
function IntToHex takes integer i returns string
local integer r = ModuloInteger( i, 16)
local string result
if (i-r <= 16) then
set result = HexString(r)
else
set result = IntToHex( (i-r)/16 ) + HexString(r)
endif
return result
endfunction
function ExecuteCode takes code c returns nothing
call ForForce(bj_FORCE_PLAYER[0], c)
endfunction
function GetUnitZ takes unit U returns real
call MoveLocation(udg_TempLoc, GetUnitX(U), GetUnitY(U))
return (GetUnitFlyHeight(U) + GetLocationZ(udg_TempLoc))
endfunction
function GetItemCosts takes integer id returns integer
local item temp = CreateItem(id, 0,0)
local integer costs = R2I(GetWidgetLife(temp))
call RemoveItem(temp)
set temp = null
return costs
endfunction
function Round takes real r returns integer
return R2I(r+0.5)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitTypes requires BTFramework
function IsTinkerTower takes unit U returns boolean
local integer Id = GetUnitTypeId(U)
return (Id-'h01A')*(Id-'h01F')*(Id-'h00T')*(Id-'h010')*(Id-'h01G')==0
endfunction
function IsWatchTower takes unit U returns boolean
local integer ID = GetUnitTypeId(U)
return (ID-'h01O')*(ID-'h01N')*(ID-'h01Q')*(ID-'h01P')*(ID-'h01M')==0
endfunction
function IsForceTower takes unit U returns boolean
local integer ID = GetUnitTypeId(U)
local boolean result = false
if (ID == 'h01Y') then // Protective Tower
set result = true
elseif (ID == 'o000') then // Barricade
set result = true
elseif (ID == 'h000') then // Rocket Tower
set result = true
elseif (ID == 'h001') then // Laser Tower
set result = true
elseif (ID == 'o003') then // Teleport Beacon
set result = true
elseif (ID == 'o005') then // Camouflage Generator
set result = true
endif
return result
// the following line apparently returns true, when a Marine ('z000') is checked ... I have no idea why, the code above works though
//return (ID-'h01Y')*(ID-'o000')*(ID-'h000')*(ID-'h001')*(ID-'o003')*(ID-'o005')==0
endfunction
function IsPacifista takes unit U returns boolean
local integer ID = GetUnitTypeId(U)
return ( ID - 'z020' ) * ( ID - 'z021' ) * ( ID - 'z022' ) * ( ID - 'z023' ) * ( ID - 'z024' ) == 0
endfunction
function IsObelisk takes unit U returns integer
local integer ID = GetUnitTypeId(U)
if ( ID == 'h02B') then
return 1
elseif ( ID == 'h02C') then
return 2
elseif ( ID == 'h02D') then
return 3
elseif ( ID == 'h02E') then
return 4
elseif ( ID == 'h02F') then
return 5
endif
return 0
endfunction
// True for force and player summoned creeps (of the factory and TCC)
// False for heroes, buildings, dummies and creeps summoned by skills (<- not sure if this should stay this way or not)
function IsCreep takes unit U, boolean onlyForce returns boolean
local integer ID = GetUnitTypeId(U)
local integer ownerId = GetPlayerNr(GetOwningPlayer(U))
if (IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsUnitType(U, UNIT_TYPE_STRUCTURE)) then
return false
endif
/*
// normal creeps of the force
if ( ID - 'z001' ) * ( ID - 'z002' ) * ( ID - 'z000' ) * ( ID - 'z00C' ) == 0 then
return true
endif
// low bounty creeps
if ( ID - 'z008' ) * ( ID - 'z007' ) * ( ID - 'z006' ) * ( ID - 'z00D' ) == 0 then
return true
endif
// creeps of the Troop Command Center
if ( ID - 'z01E' ) * ( ID - 'z01F' ) * ( ID - 'z01K' ) * ( ID - 'z00Y' ) * ( ID - 'z01O' ) == 0 then
return true
endif
*/
return false
endfunction
function IsDecoy takes unit U returns boolean
local integer ID = GetUnitTypeId(U)
return ( ID - 'n008' ) * ( ID - 'n009' ) * ( ID - 'n00H' ) * ( ID - 'n00V' ) * ( ID - 'n00W' ) == 0
endfunction
function IsItemHealer takes item I returns boolean
// Also returns true for manipulated healers.
local integer typeId = GetItemTypeId(I)
return (typeId-'I04C')*(typeId-'I050')==0
endfunction
function IsDummy takes unit U returns boolean
// Each dummy unit should have this ability, if not, add this ability to the dummy unit
return (GetUnitAbilityLevel(U, 'A09G') > 0)
endfunction
function IsTechMech takes unit U returns boolean
return (GetUnitTypeId(U) == 'n00I')
endfunction
function IsWard takes unit U returns boolean
// here is the thing: there is no way to check directly if a unit is a ward (IsUnitType has no enum for wards)
// So make sure, that every ward has the ability mentioned below, so you can check for it
return (GetUnitAbilityLevel(U, 'A0BZ') > 0)
endfunction
function IsAirUnit takes unit U returns boolean
local integer id = GetUnitTypeId(U)
// H00R = Ghost Tank, H02V = Goliath (with active Offroad Engine)
if (id == 'H00R') or (id == 'H02A') then
return false
endif
return IsUnitType(U, UNIT_TYPE_FLYING)
endfunction
function IsGroundUnit takes unit U returns boolean
local integer id = GetUnitTypeId(U)
// H00R = Ghost Tank, H02V = Goliath (with active Offroad Engine)
if (id == 'H00R') or (id == 'H02A') then
return true
endif
return IsUnitType(U, UNIT_TYPE_GROUND) or IsUnitNetted(U) or IsUnitType(U, UNIT_TYPE_STRUCTURE)
endfunction
function IsRadar takes item I returns boolean
local integer typeId = GetItemTypeId(I)
// Radar, Ultimate Pack, Trader Hunter Pack, Mine Defuse Pack, Mine Defuse Pack (Trader)
return (typeId-'I02G')*(typeId-'I01J')*(typeId-'I00L')*(typeId-'I04R')*(typeId-'I05G')==0
endfunction
function IsTeleporter takes item I returns boolean
local integer typeId = GetItemTypeId(I)
// Teleporter, Ultimate Pack, Speed Pack, Trader Hunter Pack
return (typeId-'I014')*(typeId-'I01J')*(typeId-'I012')*(typeId-'I00L')==0
endfunction
function IsBlockingArmor takes item I returns boolean
local integer typeId = GetItemTypeId(I)
// Burst Armor, Burst Armor (Upgrade), Deflective Armor, Deflective Armor (Upgrade)
return (typeId-'I05N')*(typeId-'I05U')*(typeId-'I05O')*(typeId-'I05T')==0
endfunction
function IsItemWithMagicResistance takes item I returns boolean
local integer typeId = GetItemTypeId(I)
// Negator Pack, Mass Converter
return (typeId-'I05V')*(typeId-'I05S')==0
endfunction
function IsEnergyConverter takes item I returns boolean
local integer typeId = GetItemTypeId(I)
// Energy Converter, Emergency Repair
return (typeId-'I05R')*(typeId-'I06A')==0
endfunction
function GetMineDamage takes unit U returns real
local integer i = GetUnitTypeId(U)
local real dmg = 0.0
if i=='z00P' then // Goblin Riot
return 450.0
elseif i=='n002' then // Demo-Mine 1
set dmg = 320.0
elseif i=='n003' then // Demo-Mine 2
set dmg = 640.0
elseif i=='n004' then // Demo-Mine 3
set dmg = 960.0
elseif i=='n005' then // Demo-Mine 4
set dmg = 1280.0
elseif i=='n000' then // Demo-Mine 5 = normal Mine
set dmg = 1600.0
elseif i=='n001' then // Heavy Mine
set dmg = 3200.0
elseif i=='n00J' then // Huge Mine
set dmg = 4800.0
elseif i=='n00L' then // Carpet Bomb 1
return 500.0
elseif i=='n00R' then // Carpet Bomb 2
return 1000.0
elseif i=='n00S' then // Carpet Bomb 3
return 1500.0
elseif i=='n00T' then // Carpet Bomb 4
return 2000.0
elseif i=='n00U' then // Carpet Bomb 5
return 2500.0
endif
return dmg * (1.0 + 0.03 * I2R(GetPlayerTechCount(GetOwningPlayer(U), 'R002', true)) )
endfunction
function IsMine takes unit U returns boolean
return (GetMineDamage(U) > 0) and GetUnitTypeId( U ) != 'z00P'
endfunction
function IsAirMine takes unit U returns boolean
local integer ID = GetUnitTypeId(U)
return ( ID - 'n016' )==0
endfunction
function IsTransparentUnit takes unit U returns boolean
local integer ID = GetUnitTypeId(U)
// Earth Robot
if (ID == 'H01U') then
return (GetUnitAbilityLevel(U, TRANSPARENT_ARMOR_ABILITY_ID) > 0)
// Ghost Tank
elseif (ID == 'H00R') then
return true
endif
return false
endfunction
endlibrary
//TESH.scrollpos=1018
//TESH.alwaysfold=0
library MapAttachedSettings requires TimerAndAttachments, AIInterface, UnitTypes, Bounty
// This library includes functions, that has been moved out of their respective triggers, to make sure
// that they can be used in other triggers too.
// Functions in this library should match the following criteria:
// - they are used in more than one trigger or are expected to be used in more then one in the future
// - they should not be tied to a specific trigger (through the usage of a trigger specific variables and such)
function L2S takes location loc returns string
return "("+R2S(GetLocationX(loc))+","+R2S(GetLocationY(loc))+")"
endfunction
function DistBetweenUnits takes unit U1, unit U2 returns real
local real dx = GetUnitX(U1)-GetUnitX(U2)
local real dy = GetUnitY(U1)-GetUnitY(U2)
return SquareRoot(dx*dx+dy*dy)
endfunction
function SetXPandUpgradeLevel takes integer lvl returns nothing
local integer Id = 1
loop
exitwhen Id > GetMaxPlayers()
if (Id <= GetMaxHumanPlayers()) then
call SuspendHeroXP( udg_Tank[Id], false )
call SetHeroLevel( udg_Tank[Id], lvl, false )
call SuspendHeroXP( udg_Tank[Id], true )
endif
call SetPlayerTechResearched( GetPlayer(Id), 'R003', lvl )
call SetPlayerTechResearched( GetPlayer(Id), 'R002', lvl )
set Id = Id + 1
endloop
endfunction
function GetWeaponRange takes integer ID returns integer
local integer index = ID - (ID/8192)*8192
if index < 0 then
return udg_WeaponRange[index+8192]
endif
return udg_WeaponRange[index]
endfunction
function GetWeaponDamageModifier takes integer ID returns real
local integer index = ID - (ID/8192)*8192
if index < 0 then
return udg_WeaponModifier[index+8192]
endif
return udg_WeaponModifier[index]
endfunction
globals
constant integer RANGE_AVG = 1
constant integer RANGE_MAX = 2
constant integer RANGE_MIN = 3
endglobals
function GetWeaponRangeMode takes unit U, integer Mode returns real
local integer Slot = 1
local item ItemInSlot
local real ItemCosts
local real ItemRange
local real AllCosts = 0
local real AllRange = 0
//A01J - Tank Cannon, A06M - Creep Sniper, A08Z - Hero Sniper
if ((GetUnitAbilityLevel(U, 'A06M') > 0) or (GetUnitAbilityLevel(U, 'A08Z') > 0)) then
set AllCosts = AllCosts + 8 * I2R(GetUnitAbilityLevel(U, 'A06M'))
set AllCosts = AllCosts + 8 * I2R(GetUnitAbilityLevel(U, 'A08Z'))
set AllRange = 1300
elseif GetUnitAbilityLevel(U, 'A01J') > 0 then
set AllCosts = AllCosts + 8 * I2R(GetUnitAbilityLevel(U, 'A01J'))
set AllRange = 900
endif
if Mode == 1 then
//Mode 1 calculates the average range of this tank
//more expensive weapons have a bigger influence on the range
set AllRange = AllRange * AllCosts
endif
loop
exitwhen Slot > 6
set ItemInSlot = UnitItemInSlotBJ(U, Slot)
set ItemRange = I2R(GetWeaponRange(GetItemTypeId(ItemInSlot)))
if ItemRange != 0 then
if (Mode == RANGE_AVG) then //Average Range
set ItemCosts = GetWidgetLife(ItemInSlot)
set AllRange = AllRange + ItemRange * ItemCosts / 100
set AllCosts = AllCosts + ItemCosts / 100
elseif (Mode == RANGE_MAX) then // Maximum Range
if ItemRange > AllRange then
set AllRange = ItemRange
endif
elseif (Mode == RANGE_MIN) then //Minumum Range
if AllRange == 0 then
set AllRange = ItemRange
else
if ItemRange < AllRange then
set AllRange = ItemRange
endif
endif
endif
endif
set Slot = Slot + 1
endloop
if Mode == RANGE_AVG then
set udg_Show_WeaponRange = AllRange / AllCosts
else
set udg_Show_WeaponRange = AllRange
endif
return udg_Show_WeaponRange
endfunction
function ItemDropInvalid takes unit U, item DropItem returns nothing
local real ItemX = GetItemX(DropItem)
local real ItemY = GetItemY(DropItem)
local real DistX = ItemX-GetUnitX(U)
local real DistY = ItemY-GetUnitY(U)
local integer Team = udg_Player_Team[GetPlayerNr(GetItemPlayer(DropItem))]
local boolean ItemCheck = udg_Item_Check
set udg_Item_Check = false
if DistX*DistX+DistY*DistY <= 40000 then
call SetItemPosition(DropItem, GetItemX(DropItem), GetItemY(DropItem))
else
call SetItemPosition(DropItem, GetUnitX(U), GetUnitY(U))
endif
set udg_Item_Check = ItemCheck
endfunction
function ItemDropAll takes unit U returns nothing
local integer i = 0
local item SlotItem
local integer Team = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
loop
exitwhen i > 5
set SlotItem = UnitItemInSlot(U,i)
if GetItemTypeId(SlotItem)=='I048' or GetItemType(SlotItem)==ITEM_TYPE_POWERUP then
call RemoveItem( SlotItem )
else
call SetItemPosition(SlotItem, GetUnitX(U)+88*Cos((360-(i*60))*bj_DEGTORAD), GetUnitY(U)+88*Sin((360-(i*60))*bj_DEGTORAD))
endif
set i = i + 1
endloop
set SlotItem = null
endfunction
function GiveStartingGold takes integer NormalStartingGold returns nothing
local integer CountTeam1Players = 0
local integer CountTeam2Players = 0
local integer CountTeam1PlayersStart = 0
local integer CountTeam2PlayersStart = 0
local integer CountTeamPlayersStartMax
local integer Team1StartingGold
local integer Team2StartingGold
local integer i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if IsPlayerInForce( GetPlayer(i), udg_Players_Start ) then
if i <= 5 then
set CountTeam1PlayersStart = CountTeam1PlayersStart + 1
else
set CountTeam2PlayersStart = CountTeam2PlayersStart + 1
endif
if IsPlayerInForce( GetPlayer(i), udg_Players ) then
if i <= 5 then
set CountTeam1Players = CountTeam1Players + 1
else
set CountTeam2Players = CountTeam2Players + 1
endif
endif
endif
set i = i + 1
endloop
set CountTeamPlayersStartMax = IMaxBJ(CountTeam1PlayersStart,CountTeam2PlayersStart)
set NormalStartingGold = NormalStartingGold*CountTeamPlayersStartMax
set i = 1
if CountTeam1Players > 0 then
set Team1StartingGold = ( NormalStartingGold / CountTeamPlayersStartMax + NormalStartingGold / CountTeam1Players ) / 2
endif
if CountTeam2Players > 0 then
set Team2StartingGold = ( NormalStartingGold / CountTeamPlayersStartMax + NormalStartingGold / CountTeam2Players ) / 2
endif
loop
exitwhen i > GetMaxHumanPlayers()
if IsPlayerInForce( GetPlayer(i), udg_Players ) then
if i <= 5 then
call SetPlayerState(GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD, Team1StartingGold)
else
call SetPlayerState(GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD, Team2StartingGold)
endif
endif
set i = i + 1
endloop
endfunction
function PlayerAfkReturn takes player P returns nothing
local integer PlayerId = GetPlayerNr(P)
local integer i = 1
local item SlotItem
local unit U
local group G = NewGroup()
set udg_ActionsLast[PlayerId] = udg_Time_Value
call DebugMsg(I2S(R2I(udg_AFKTime[PlayerId])))
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetPlayerName(P) + " has returned (" + I2S(R2I(udg_AFKTime[PlayerId]/60.)) + " minutes afk in this match).|r" )
loop
exitwhen i > GetMaxHumanPlayers()
if udg_Player_Team[PlayerId]==udg_Player_Team[i] and PlayerId!=i then
call SetPlayerAllianceBJ( P, ALLIANCE_SHARED_CONTROL, false, GetPlayer(i) )
endif
set i = i + 1
endloop
call GroupEnumUnitsOfPlayer(G, P, FILTER_NULL)
loop
set U = FirstOfGroup(G)
exitwhen U==null
if UnitInventorySize(U)>0 then
set i = 0
loop
exitwhen i > 5
set SlotItem = UnitItemInSlot(U, i)
if SlotItem!=null then
if GetItemTypeId(SlotItem) == AWAY_ITEM_ID then
call RemoveItem( SlotItem )
elseif GetItemUserData(SlotItem) == 0 then
call SetItemDroppable( SlotItem, true )
endif
endif
set i = i + 1
endloop
endif
call GroupRemoveUnit(G, U)
endloop
call ReleaseGroup(G)
set G = null
set SlotItem = null
set udg_Afk[PlayerId] = false
call RegisterAI( PlayerId, 0 )
if (GetLocalPlayer() == GetPlayer(PlayerId)) then
call MultiboardDisplay( udg_Killboard[PlayerId-1], true )
call MultiboardMinimize( udg_Killboard[PlayerId-1], IsMultiboardMinimized(udg_Killboard[PlayerId-1]) )
endif
endfunction
function PlayerAfkActivate takes player P, string Message, boolean TurnToAI returns nothing
local integer PlayerId = GetPlayerNr(P)
local integer i = 1
local item SlotItem
local unit U
local group G
if TurnToAI then
if (Message!=null) and (Message!="") then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetPlayerName(P) + " is away, units are now controlled by AI. ("+Message+")")
else
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetPlayerName(P) + " is away, units are now controlled by AI.")
endif
call RegisterAI( PlayerId, 1 )
else
if (Message!=null) and (Message!="") then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetPlayerName(P) + " is away. ("+Message+")")
else
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetPlayerName(P) + " is away.")
endif
loop
exitwhen i > GetMaxHumanPlayers()
if udg_Player_Team[PlayerId]==udg_Player_Team[i] and PlayerId!=i then
call SetPlayerAllianceBJ( P, ALLIANCE_SHARED_CONTROL, true, GetPlayer(i) )
endif
set i = i + 1
endloop
set G = NewGroup()
call GroupEnumUnitsOfPlayer(G, P, FILTER_NULL)
loop
set U = FirstOfGroup(G)
exitwhen U==null
if (GetUnitState(U, UNIT_STATE_LIFE)>0) and (UnitInventorySize(U)>0) then
set i = 0
loop
exitwhen i > 5
set SlotItem = UnitItemInSlot(U, i)
if SlotItem==null then
call UnitAddItemById( U, AWAY_ITEM_ID )
else
call SetItemDroppable( SlotItem, false )
endif
set i = i + 1
endloop
endif
call GroupRemoveUnit(G, U)
endloop
call ReleaseGroup(G)
set G = null
set SlotItem = null
endif
set udg_Afk[PlayerId] = true
call DialogDisplay( P, udg_Afk_Dialog, true )
if (GetLocalPlayer() == GetPlayer(PlayerId)) then
call MultiboardDisplay( udg_Killboard[PlayerId-1], true )
call MultiboardMinimize( udg_Killboard[PlayerId-1], IsMultiboardMinimized(udg_Killboard[PlayerId-1]) )
endif
endfunction
function ShowTip takes player ToPlayer returns nothing
local integer tipId = GetRandomInt(1,20)
local string text = "|cfffed312Tip " + I2S(tipId) + "/20:|r |cff9999ff" + udg_Tips[tipId] +"|r"
call DisplayTextToPlayer(ToPlayer, 0, 0, text)
endfunction
function FloatingTimedLife_Child takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local real duration = udg_AV_Real1[LoopTimerId]
local string Pre = udg_AV_String1[LoopTimerId]
local string End = udg_AV_String2[LoopTimerId]
local string msg
if (GetUnitState(Target, UNIT_STATE_LIFE) > 0) and (duration > 0) then
set msg = Pre+I2S(R2I(duration))+End
call ShowTextTag(msg, Target, 0, 0, udg_AV_Player1[LoopTimerId])
set udg_AV_Real1[LoopTimerId] = udg_AV_Real1[LoopTimerId] - 1.0
else
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Target = null
endfunction
function PermanentTimedLife_Explosive takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local real duration = udg_AV_Real1[LoopTimerId]
local real offset = udg_AV_Real2[LoopTimerId]
local texttag tag = udg_AV_Tag1[LoopTimerId]
local string Pre = udg_AV_String1[LoopTimerId]
local string End = udg_AV_String2[LoopTimerId]
local string msg
if (GetUnitState(Target, UNIT_STATE_LIFE) > 0) and (duration > 0) and (GetUnitAbilityLevel(Target, EXPLOSIVE_BUFF_ID) > 0) then
call SetTextTagText(tag, Pre+I2S(R2I(duration+1))+End, 0.023)
call SetTextTagPos(tag, GetUnitX(Target) + offset, GetUnitY(Target), GetUnitFlyHeight(Target) + 150)
call SetTextTagVisibility(tag, IsUnitVisible(Target, GetLocalPlayer()))
set udg_AV_Real1[LoopTimerId] = udg_AV_Real1[LoopTimerId] - 0.02
else
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Target = null
endfunction
function PermanentTimedLife_KineticShield takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local integer tId = GetPlayerNr(GetOwningPlayer(Target))
local real duration = udg_AV_Real1[LoopTimerId]
local real offset = udg_AV_Real2[LoopTimerId]
local real percentage = RMaxBJ(0, (GetUnitUserData(Target) - KS_TakenDamage[tId]) / GetUnitUserData(Target)) * 100
local texttag tag = udg_AV_Tag1[LoopTimerId]
local string Pre = udg_AV_String1[LoopTimerId]
local string End = udg_AV_String2[LoopTimerId]
local string msg = I2S(R2I(percentage))+ "%"
if (GetUnitState(Target, UNIT_STATE_LIFE) > 0) and (duration > 0) then
call SetTextTagText(tag, Pre+msg+End, 0.023)
call SetTextTagPos(tag, GetUnitX(Target) + offset, GetUnitY(Target), GetUnitFlyHeight(Target) + 150)
set udg_AV_Real1[LoopTimerId] = udg_AV_Real1[LoopTimerId] - 0.02
else
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Target = null
endfunction
function PermanentTimedLife_HitnRun takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local integer tId = GetPlayerNr(GetOwningPlayer(Target))
local real duration = udg_AV_Real1[LoopTimerId]
local real offset = udg_AV_Real2[LoopTimerId]
local texttag tag = udg_AV_Tag1[LoopTimerId]
local string Pre = udg_AV_String1[LoopTimerId]
local string End = udg_AV_String2[LoopTimerId]
local string msg = I2S(R2I(hitnRunDamage[tId]))
if (GetUnitState(Target, UNIT_STATE_LIFE) > 0) and (duration > 0) and (GetUnitAbilityLevel(Target, HITNRUN_BUFF_ABILITY_ID) > 0) then
call SetTextTagText(tag, Pre+msg+End, 0.023)
call SetTextTagPos(tag, GetUnitX(Target) + offset, GetUnitY(Target), GetUnitFlyHeight(Target) + 150)
set udg_AV_Real1[LoopTimerId] = udg_AV_Real1[LoopTimerId] - 0.02
else
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Target = null
endfunction
function PermanentTimedLife_HeatSeekingMissile takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local integer tId = GetPlayerNr(GetOwningPlayer(Target))
local integer level = GetUnitAbilityLevel(Target, HSM_ABILITY_ID)
local real offset = udg_AV_Real2[LoopTimerId]
local texttag tag = udg_AV_Tag1[LoopTimerId]
local string Pre = udg_AV_String1[LoopTimerId]
local string End = udg_AV_String2[LoopTimerId]
local string msg = "|cff00ff00"
local integer maxMissiles = HSM_MAX_RESTOCK_BASE + ( level * HSM_MAX_RESTOCK_UP )
local integer i = 1
if (GetUnitTypeId(Target) == 'H02J') then
// first, check if the string to be displayed changed compared to the last loop
if (udg_AV_Real1[LoopTimerId] != HSM_MissileCount[tId]) then
if (HSM_MissileCount[tId] == 0) then
set msg = "|cff000000"
endif
loop
exitwhen (i > maxMissiles)
if (i == HSM_MissileCount[tId]) and (i < maxMissiles) then
set msg = msg + Pre + " |r|cff000000"
else
set msg = msg + Pre + " "
endif
set i = i + 1
endloop
set msg = SubStringBJ(msg, 1, StringLength(msg)-1) + "|r"
else
set msg = udg_AV_String2[LoopTimerId]
endif
set udg_AV_Real1[LoopTimerId] = HSM_MissileCount[tId]
set udg_AV_String2[LoopTimerId] = msg
call SetTextTagText(tag, msg, 0.023)
call SetTextTagPos(tag, GetUnitX(Target) + offset, GetUnitY(Target), GetUnitFlyHeight(Target) + 150)
if (GetUnitState(Target, UNIT_STATE_LIFE) <= 0) then
call SetTextTagVisibility(tag, false)
else
call SetTextTagVisibility(tag, GetLocalPlayer() == GetOwningPlayer(Target))
endif
else
call DebugMsg("End HSM count")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Target = null
endfunction
function PermanentTimedLife takes unit TimedUnit, real duration, player p, string Pre, string End, real OffsetX, code action returns nothing
local timer t
local integer TimerIndex
local string msg
local texttag tag = CreateTextTag()
local boolean visibility
if (p == null) then
set visibility = IsUnitVisible(TimedUnit, GetLocalPlayer())
else
set visibility = GetLocalPlayer() == p
endif
call SetTextTagPos(tag, GetUnitX(TimedUnit) + OffsetX, GetUnitY(TimedUnit), GetUnitFlyHeight(TimedUnit))
call SetTextTagVisibility(tag, visibility)
call SetTextTagVelocity(tag, 0, 0.0)
call SetTextTagPermanent(tag, true )
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = TimedUnit
set udg_AV_Real1[TimerIndex] = duration
set udg_AV_Real2[TimerIndex] = OffsetX
set udg_AV_String1[TimerIndex] = Pre
set udg_AV_String2[TimerIndex] = End
set udg_AV_Tag1[TimerIndex] = tag
call TimerStart(t, 0.02, true, action)
set tag = null
endfunction
//Shows a countdown over the target unit
function FloatingTimedLife takes unit TimedUnit, real duration, player p, string Pre, string End returns nothing
local timer t
local integer TimerIndex
local string msg
set msg = Pre+I2S(R2I(duration))+End
call ShowTextTag(msg, TimedUnit, 0, 0, p)
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = TimedUnit
set udg_AV_Real1[TimerIndex] = duration - 1
set udg_AV_String1[TimerIndex] = Pre
set udg_AV_String2[TimerIndex] = End
set udg_AV_Player1[TimerIndex] = p
call TimerStart(t, 1.0, true, function FloatingTimedLife_Child)
endfunction
function AreCoordsInStrategicLocation takes real X, real Y returns boolean
if RectContainsCoords(gg_rct_Strategic_Location_1, X, Y) then
return true
elseif RectContainsCoords(gg_rct_Strategic_Location_2, X, Y) then
return true
elseif RectContainsCoords(gg_rct_Strategic_Location_3, X, Y) then
return true
elseif RectContainsCoords(gg_rct_Strategic_Location_4, X, Y) then
return true
elseif RectContainsCoords(gg_rct_Strategic_Location_5, X, Y) then
return true
elseif RectContainsCoords(gg_rct_Strategic_Location_6, X, Y) then
return true
elseif RectContainsCoords(gg_rct_Strategic_Location_7, X, Y) then
return true
elseif RectContainsCoords(gg_rct_Strategic_Location_8, X, Y) then
return true
endif
return false
endfunction
function IsUnitInStrategicLocation takes unit U returns boolean
return AreCoordsInStrategicLocation( GetUnitX(U), GetUnitY(U) )
endfunction
function EnableStrategicLocationBuff takes unit Tank, boolean activate returns nothing
/*
if activate then
if (GetUnitState(Tank, UNIT_STATE_LIFE) > 0) then
call SetUnitAbilityLevel( Tank, STRATEGIC_LOCATION_RESISTANCE_ID, 2 )
call SetUnitAbilityLevel( Tank, STRATEGIC_LOCATION_HEALING_ID, 2 )
call UnitAddAbility( Tank, STRATEGIC_LOCATION_BUFF_ABILITY_ID)
endif
else
if (GetUnitState(Tank, UNIT_STATE_LIFE) > 0) then
call SetUnitAbilityLevel( Tank, STRATEGIC_LOCATION_RESISTANCE_ID, 1 )
call SetUnitAbilityLevel( Tank, STRATEGIC_LOCATION_HEALING_ID, 1 )
if GetUnitAbilityLevel(Tank, STRATEGIC_LOCATION_BUFF_ID) > 0 then
call UnitRemoveAbility(Tank, STRATEGIC_LOCATION_BUFF_ABILITY_ID)
call UnitRemoveAbility( Tank, STRATEGIC_LOCATION_BUFF_ID )
endif
endif
endif
*/
endfunction
function AnyAllyHasTankOfType takes player P, integer TankType returns boolean
local integer i = 1
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if udg_Player_Team[i]==udg_Player_Team[GetPlayerNr(P)] then
if GetUnitTypeId(udg_Tank[i])==TankType then
return true
elseif (GetUnitTypeId(udg_Tank[i])=='H013' and TankType=='H012') or (GetUnitTypeId(udg_Tank[i])=='H02A' and TankType=='H01V') then
return true
endif
endif
set i = i + 1
endloop
return false
endfunction
function IsItemUpgradeable takes item BaseItem returns boolean
local integer i = 0
local integer itype = GetItemTypeId(BaseItem)
loop
exitwhen udg_Weapon_Basic[i] == null or udg_Weapon_Basic[i] == itype
endloop
return udg_Weapon_Basic[i] == itype
endfunction
//Determines, which lane should be targetted, based on the current position
function GetTargetMovePoint takes unit U returns integer
local integer TeamNumber = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
local integer MovePoint = 3+25 - TeamNumber
local location EnemyBase = udg_Move_Points[(3+25 - TeamNumber)]
local location OwnBase = udg_Move_Points[TeamNumber+25]
local location Unit = GetUnitLoc(U)
if DistanceBetweenPoints(Unit, OwnBase) < DistanceBetweenPoints(Unit, EnemyBase) then // 20 - TeamNumber
if DistanceBetweenPoints(Unit, udg_Move_Points[10 + TeamNumber * 2]) < DistanceBetweenPoints(Unit, udg_Move_Points[17 + TeamNumber]) then
// Left MovePoint
set MovePoint = 13
elseif DistanceBetweenPoints(Unit, udg_Move_Points[13 + TeamNumber * 2]) < DistanceBetweenPoints(Unit, udg_Move_Points[17 + TeamNumber]) then
// Right MovePoint
set MovePoint = 16
else
// Middle MovePoint
set MovePoint = 20 - TeamNumber
endif
else
// Enemy Base
set MovePoint = 3+25 - TeamNumber
endif
call RemoveLocation(Unit)
set EnemyBase = null
set OwnBase = null
set Unit = null
return MovePoint
endfunction
function TCC_Ability takes player Force, integer UnitID, real X, real Y returns nothing
local unit dummy = CreateUnit(Force,DUMMY_ID, X, Y, bj_UNIT_FACING)
local item scanner
// Scan
if UnitID == '1777' then
call UnitAddAbility(dummy, 'A03P')
set scanner = UnitAddItemById(dummy, 'I05Q')
call UnitUseItem(dummy, scanner)
call UnitApplyTimedLife(dummy, 'BTLF', 7)
call RemoveItem(scanner)
endif
set scanner = null
set dummy = null
endfunction
function UnitDrop takes player Force, integer UnitID, integer number, real X, real Y returns nothing
local unit array U
local effect array E
local real beginGameTime = TimerGetElapsed(udg_GameTime)
local integer i = 1
loop
exitwhen i > number
if UnitID == '1999' then
set U[i] = CreateUnit( Force, udg_TC_Unit[i], X, Y, bj_UNIT_FACING)
elseif UnitID == '1888' then
set U[i] = CreateUnit( Force, udg_Aura_Creeps[i], X, Y, bj_UNIT_FACING)
else
set U[i] = CreateUnit( Force, UnitID, X, Y, bj_UNIT_FACING)
endif
call UnitAddAbility( U[i], 'Amrf' )
call UnitRemoveAbility( U[i], 'Amrf' )
call SetUnitInvulnerable( U[i], true )
call PauseUnit( U[i], true )
call SetUnitFlyHeight(U[i], 1000, 0)
call SetUnitPosition(U[i], X, Y)
call SetUnitFlyHeight(U[i], 0, 200)
if (GetUnitTypeId(U[i]) != 'z00D') then
set E[i] = AddSpecialEffectTarget( "war3mapImported\\parachute.mdx", U[i], "origin" )
endif
set i = i+1
endloop
set i = 1
call WaitForGameTime(beginGameTime + 5.0)
loop
exitwhen i > number
call DestroyEffect( E[i] )
call SetUnitInvulnerable( U[i], false )
call PauseUnit( U[i], false )
//Bomb
if (GetUnitTypeId(U[i]) == 'h00V') then
call UnitApplyTimedLife(U[i], 'BTLF', 3.00)
call FloatingTimedLife(U[i], 3, null, "|cffff0000", "!|r")
//call SetUnitMoveSpeed(U[i], 0)
else
call IssuePointOrderLoc( U[i], "attack", udg_Move_Points[GetTargetMovePoint(U[i])] )
endif
set U[i] = null
set E[i] = null
set i = i+1
endloop
endfunction
function RefreshTransparency takes unit U returns nothing
// Earth Robot
if GetUnitTypeId(U)=='H01U' then
call SetUnitVertexColor( U, 255, 255, 255, R2I(Pow(0.85, GetUnitAbilityLevel(U,TRANSPARENT_ARMOR_ABILITY_ID))*255) )
// Ghost Tank
elseif GetUnitTypeId(U) == 'H00R' then
call SetUnitVertexColor( U, 255, 255, 255, 170 )
else
call SetUnitVertexColor( U, 255, 255, 255, 255 )
endif
endfunction
function ShowSpecialOptions takes player p returns nothing
local string Options = ""
local player tempP
local integer i = 0
if udg_StartingGold!=3000 then
set Options = Options + I2S(udg_StartingGold)+" Gold, "
endif
if udg_CV then
set Options = Options + "Conquest Victory, "
endif
if udg_NoRequirements then
set Options = Options + "No Tank Requirements, "
endif
if udg_NoTinker then
set Options = Options + "No Tinker, "
endif
if udg_NoExploder then
set Options = Options + "No Exploder, "
endif
if udg_NoTrader then
set Options = Options + "No Trader, "
endif
if udg_HighTech then
set Options = Options + "High Tech, "
endif
if udg_Fog then
set Options = Options + "Fog, "
endif
if udg_TankMonopoly then
set Options = Options + "Tank Monopoly, "
endif
if udg_ExtRequirements then
set Options = Options + "Extended Tank Requirements, "
endif
if p==null then
loop
exitwhen i >= 13
if Options=="" then
call DisplayTimedTextToPlayer(Player(i), 0, 0, 20, "No special options were chosen.")
else
call DisplayTimedTextToPlayer(Player(i), 0, 0, 20, "Special options: "+SubString(Options,0,StringLength(Options)-2))
endif
set i = i + 1
endloop
else
if Options=="" then
call DisplayTimedTextToPlayer(p, 0, 0, 20, "No special options were chosen.")
else
call DisplayTimedTextToPlayer(p, 0, 0, 20, "Special options: "+SubString(Options,0,StringLength(Options)-2))
endif
endif
endfunction
function BooleanToColor takes boolean b, boolean enabled returns string
if enabled then
if b == true then
return "|cff00ff00" //green
else
return "|cffff0000" //red
endif
endif
return "|cffaaaaaa" // grey
endfunction
function ApplyManaUpgrade takes integer PlayerId returns nothing
local unit tank = udg_Tank[PlayerId]
local integer level = ManaUpgrade[PlayerId]
local integer manaId = 0
//There are several abilities, because you can't level the mana bonus ability
if (GetUnitState(tank, UNIT_STATE_LIFE) > 0) then
call UnitRemoveAbility(tank, 'A0DQ')
call UnitRemoveAbility(tank, 'A0DX')
call UnitRemoveAbility(tank, 'A0DR')
call UnitRemoveAbility(tank, 'A0DS')
call UnitRemoveAbility(tank, 'A0D9')
call UnitRemoveAbility(tank, 'A0DT')
call UnitRemoveAbility(tank, 'A0DU')
call UnitRemoveAbility(tank, 'A0DV')
call UnitRemoveAbility(tank, 'A0DW')
call UnitRemoveAbility(tank, 'A075')
if (level == 1) then
set manaId = 'A0DQ'
elseif (level == 2) then
set manaId = 'A0DX'
elseif (level == 3) then
set manaId = 'A0DR'
elseif (level == 4) then
set manaId = 'A0DS'
elseif (level == 5) then
set manaId = 'A0D9'
elseif (level == 6) then
set manaId = 'A0DT'
elseif (level == 7) then
set manaId = 'A0DU'
elseif (level == 8) then
set manaId = 'A0DV'
elseif (level == 9) then
set manaId = 'A0DW'
elseif (level == 10) then
set manaId = 'A075'
endif
if (manaId != 0) then
call UnitAddAbility(tank, manaId)
endif
endif
set tank = null
endfunction
function RefreshSkill takes unit U, integer skill returns nothing
local integer level = GetUnitAbilityLevel(U, skill)
if (level > 0) then
call UnitRemoveAbility(U, skill)
call UnitAddAbility(U, skill)
call SetUnitAbilityLevel(U, skill, level)
endif
endfunction
function AddAbilityTimed_Child takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
if (udg_AV_Unit1[LoopTimerId] != null) and (GetUnitAbilityLevel(udg_AV_Unit1[LoopTimerId], udg_AV_Int1[LoopTimerId]) > 0) then
call UnitRemoveAbility(udg_AV_Unit1[LoopTimerId], udg_AV_Int1[LoopTimerId])
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endfunction
function AddAbilityTimed takes unit U, integer skill, integer level, real duration returns nothing
local timer t
local integer LoopTimerId
if (U != null) then
call UnitAddAbility(U, skill)
call SetUnitAbilityLevel(U, skill, level)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Int1[LoopTimerId] = skill
call TimerStart(t, duration, false, function AddAbilityTimed_Child)
else
call DebugMsg("AddAbilityTimed: Unit == null")
endif
endfunction
function RefreshRuinSupply takes unit Ruin returns nothing
if (GetUnitTypeId(Ruin) == 'h00Q') then
call AddUnitToStock(Ruin, BARRICADE_SELL_ID , 1, 1)
call AddUnitToStock(Ruin, ROCKET_TOWER_SELL_ID , 1, 1)
call AddUnitToStock(Ruin, LASER_TOWER_SELL_ID , 1, 1)
call AddUnitToStock(Ruin, TELEPORT_BEACON_SELL_ID , 1, 1)
call AddUnitToStock(Ruin, CAMOUFLAGE_GENERATOR_SELL_ID , 1, 1)
endif
endfunction
function KillTrigger_Child takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
if (udg_AV_Triggers[LoopTimerId] != null) then
call DestroyTrigger(udg_AV_Triggers[LoopTimerId])
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endfunction
function KillTrigger takes trigger trig returns nothing
local timer t
local integer LoopTimerId
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Triggers[LoopTimerId] = trig
call TimerStart(t, 0, false, function KillTrigger_Child)
endfunction
globals
integer ItemCount
real cheapestValue
item cheapestItem
endglobals
function CountItems takes nothing returns nothing
set ItemCount = ItemCount + 1
if ((GetWidgetLife(GetEnumItem()) < cheapestValue) or (cheapestValue == 0)) and (GetItemTypeId(GetEnumItem()) != DUMMY_ITEM_ID) then
set cheapestValue = GetWidgetLife(GetEnumItem())
set cheapestItem = GetEnumItem()
endif
endfunction
function IsCoordInJunkyard takes real X, real Y, integer team returns boolean
return RectContainsCoords(udg_JunkyardRect[team], X, Y)
endfunction
function PlaceItemOnJunkyard takes integer ownerId, item soldItem, boolean droppedOnYard returns nothing
local item NewItem
local integer Team = udg_Player_Team[ownerId]
local integer i = GetItemCharges(soldItem)
local integer soldId = GetItemTypeId(soldItem)
// (TempItemID!='I051') and (TempItemID!='I03N') and (TempItemID!='I04O')
if (GetWidgetLife(soldItem)<700) or (soldId == DUMMY_ITEM_ID) or (soldId=='I051') or (soldId=='I03N') or (soldId=='I04O') then
//items which are worth less are not placed on the Junkyard
return
endif
set ItemCount = 0
set cheapestValue = 0
set cheapestItem = null
call EnumItemsInRect(udg_JunkyardRect[Team], FILTER_NULL, function CountItems)
if (ItemCount >= MAX_JUNKYARD_ITEM_COUNT) then
call RemoveItem(cheapestItem)
call DebugMsg("Removed cheapest item")
endif
// When you place the item directly on the yard, there is no need to create a new one (except when it has charges)
if droppedOnYard then
if i>1 then
call SetItemCharges(soldItem,1)
endif
call SetItemUserData(soldItem, 2)
set i = i - 1
else
if (i == 0) then
set i = i + 1
endif
endif
loop
exitwhen i <= 0
set NewItem = CreateItem(GetItemTypeId(soldItem),GetRandomReal(GetRectMinX(udg_JunkyardRect[Team])+16,GetRectMaxX(udg_JunkyardRect[Team])-16), GetRandomReal(GetRectMinY(udg_JunkyardRect[Team])+16,GetRectMaxY(udg_JunkyardRect[Team])-16))
call SetItemPlayer( NewItem, GetPlayer(ownerId), true )
call SetItemUserData(NewItem, 2)
set i = i - 1
endloop
endfunction
function CountItemTypeInInventory takes unit U, integer itemId returns integer
local integer index = 0
local integer count = 0
loop
if (GetItemTypeId(UnitItemInSlot(U, index)) == itemId) then
set count = count + 1
endif
set index = index + 1
exitwhen index >= bj_MAX_INVENTORY
endloop
return count
endfunction
function CountBlockingArmorInInventory takes unit U returns integer
local integer index = 0
local integer count = 0
loop
if IsBlockingArmor(UnitItemInSlot(U, index)) then
set count = count + 1
endif
set index = index + 1
exitwhen index >= bj_MAX_INVENTORY
endloop
return count
endfunction
function Factory_EnableHealing takes unit building, boolean enable returns nothing
if (GetUnitTypeId(building) == 'h01Z') then
if enable then
call UnitAddAbility(building, 'A00G')
call UnitAddAbility(building, 'A07A')
call UnitAddAbility(building, 'A00Y')
else
call UnitRemoveAbility(building, 'A00G')
call UnitRemoveAbility(building, 'A07A')
call UnitRemoveAbility(building, 'A00Y')
endif
endif
endfunction
function HealOverTime_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local real HealedLife = udg_AV_Real1[LoopTimerId]
local real HealedMana = udg_AV_Real2[LoopTimerId]
local real Intervall = 0.10
local real HealedAmount = 0
local integer Ability = udg_AV_Int1[LoopTimerId]
local real Duration = udg_AV_Real3[LoopTimerId]
local boolean healEnded = false
/*
//remove the buff, when the unit is fully healed
if (GetUnitState(Target, UNIT_STATE_MAX_LIFE) == GetUnitState(Target, UNIT_STATE_LIFE)) and (GetUnitState(Target, UNIT_STATE_MAX_MANA) == GetUnitState(Target, UNIT_STATE_MANA)) then
//call DebugMsg("Stop triggered heal (full hp)")
call UnitRemoveAbility(Target, Ability)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
set Target = null
return
endif
*/
if (Ability == 0) then
if ((udg_AV_Int2[LoopTimerId] * Intervall) > Duration) then
set healEnded = true
endif
else
if (GetUnitAbilityLevel(Target, Ability) <= 0) then
set healEnded = true
endif
endif
if healEnded then
call UnitRemoveAbility(Target, Ability)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set HealedAmount = HealedLife / Duration * Intervall
call SetUnitState(Target, UNIT_STATE_LIFE, GetUnitState(Target, UNIT_STATE_LIFE) + HealedAmount)
set HealedAmount = HealedMana / Duration * Intervall
call SetUnitState(Target, UNIT_STATE_MANA, GetUnitState(Target, UNIT_STATE_MANA) + HealedAmount)
endif
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
set Target = null
endfunction
function HealOverTime takes unit Target, real healHP, real healMana, real duration, integer abilityId, boolean showHeal returns nothing
local timer t
local integer LoopTimerId
if (showHeal) then
if (healHP > 0) then
call ShowTextTag("|cff00ff00+"+I2S(R2I(healHP))+"|r", Target, 0, 0, GetOwningPlayer(Target))
endif
if (healMana > 0) then
call ShowTextTag("|cff3264C8+"+I2S(R2I(healMana))+"|r", Target, 0, 50, GetOwningPlayer(Target))
endif
endif
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Target
set udg_AV_Int1[LoopTimerId] = abilityId
set udg_AV_Int2[LoopTimerId] = 0
set udg_AV_Real1[LoopTimerId] = healHP
set udg_AV_Real2[LoopTimerId] = healMana
set udg_AV_Real3[LoopTimerId] = duration
call TimerStart(t, 0.10, true, function HealOverTime_Loop)
endfunction
function DeactivateAirOnlyWeapons takes unit U returns nothing
local integer i = 0
local integer weaponID
local real ItemLife
loop
exitwhen i > 5
set weaponID = GetItemTypeId(UnitItemInSlot(U, i))
//Bombs, Bombs (Upgrade), Flak, Flak (Upgrade)
if weaponID == 'I02Z' or weaponID == 'I03C' or weaponID == 'I057' or weaponID == 'I058' then
set ItemLife = GetWidgetLife(UnitItemInSlot(U, i))
call RemoveItem(UnitItemInSlot(U, i))
call UnitAddItemToSlotById(U, 'I051', i)
call SetWidgetLife(UnitItemInSlot(U, i), ItemLife)
endif
set i = i + 1
endloop
endfunction
function ActivateAirOnlyWeapons takes unit U returns nothing
local integer i = 0
local integer PlayerId = GetPlayerNr(GetOwningPlayer(U))
local integer weaponID
local item bombs
loop
exitwhen i > 5
if GetItemTypeId(UnitItemInSlot(U, i)) == 'I051' then
if GetWidgetLife(UnitItemInSlot(U, i)) == 6000 then
set weaponID = 'I02Z'
elseif GetWidgetLife(UnitItemInSlot(U, i)) == 7500 then
set weaponID = 'I03C'
elseif GetWidgetLife(UnitItemInSlot(U, i)) == 8000 then
set weaponID = 'I057'
elseif GetWidgetLife(UnitItemInSlot(U, i)) == 11000 then
set weaponID = 'I058'
endif
call RemoveItem(UnitItemInSlot(U, i))
if GetUnitState(U, UNIT_STATE_LIFE) > 0 then
set bombs = UnitAddItemById( U, weaponID)
call SetItemPlayer( bombs, GetOwningPlayer(U), false )
if udg_Afk[PlayerId] then
call SetItemDroppable( bombs, false )
endif
else
//when the tank is dead, give the weapon to him, after he revives
call GiveItemToDeadTank(PlayerId, weaponID)
endif
endif
set i = i + 1
endloop
set bombs = null
endfunction
function TradeMarketTeam takes unit market, integer team returns boolean
return ((market == udg_TradeMarket[team]) or (market == udg_TradeMarket_Page2[team]))
endfunction
function SetLaneCreepFlag takes unit creep, integer flag returns nothing
local integer setFlags = GetUnitUserData(creep)
local integer tempFlags = setFlags
local integer i = CF_MAX_FLAGS
local integer currentFlag
loop
exitwhen i < 0
set currentFlag = R2I(Pow(2, i))
if (tempFlags >= currentFlag) then
set tempFlags = tempFlags - currentFlag
elseif (currentFlag == flag) then
call SetUnitUserData(creep, setFlags + flag)
return
endif
set i = i - 1
endloop
endfunction
function GetLaneCreepFlag takes unit creep, integer flag returns boolean
local integer setFlags = GetUnitUserData(creep)
local integer i = CF_MAX_FLAGS
local integer currentFlag
loop
exitwhen i < 0
set currentFlag = R2I(Pow(2, i))
if (setFlags >= currentFlag) then
if (currentFlag == flag) then
return true
endif
set setFlags = setFlags - currentFlag
endif
set i = i - 1
endloop
return false
endfunction
function GetSupportRewardForItem takes integer itemId returns real
// Troop Command Center, Healing Factory, Spawning Factory
if (itemId=='I04Y') or (itemId=='I00Z') or (itemId=='I04Z') then
return 2.0
// Detector, Teleport Breaker
elseif (itemId=='I03F') or (itemId=='I04P') then
return 0.5
endif
return 0.0
endfunction
function CheckItemRequirements takes item checkItem, player owner returns string
local integer WeaponsLevel = GetPlayerTechCount(owner, 'R002', true)
local integer ArmorLevel = GetPlayerTechCount(owner, 'R003', true)
local integer ReqWeapon = 0
local integer ReqArmor = 0
local integer Id = GetItemTypeId(checkItem)
local boolean BothRequired = true // true, when the item requires both upgrades at the stated level
local string s = null
if Id=='I013' then // Reinforcement
set BothRequired = false
set ReqWeapon = 2
set ReqArmor = 2
elseif Id=='I04X' then // Mortar Team
set ReqWeapon = 1
elseif Id=='I04Q' then // Bomb
set ReqWeapon = 4
elseif Id=='I037' then // Orbital Command
set ReqWeapon = 5
elseif Id=='I00Z' then // Factory
set ReqWeapon = 2
set ReqArmor = 2
elseif Id=='I04Y' then // Troop Command Center
set ReqWeapon = 4
set ReqArmor = 4
elseif Id=='I068' then // Black Sun Project
set ReqWeapon = 6
endif
if (WeaponsLevel < ReqWeapon) then
set s = "|cfffed312You need|r " + I2S(ReqWeapon - WeaponsLevel) + " |cfffed312more weapon"
endif
if (ArmorLevel < ReqArmor) then
if (s != null) then
if BothRequired then
set s = s + " and|r "
else
set s = s + " or|r "
endif
set s = s + I2S(ReqArmor - ArmorLevel) + " |cfffed312more armor upgrades.|r"
elseif (s == null) and BothRequired then
set s = "|cfffed312You need|r " + I2S(ReqArmor - ArmorLevel) + " |cfffed312more armor upgrades.|r"
endif
elseif (s != null) and (BothRequired == false) then
// when only one upgrade type is required, but the armor requirement is fulfilled, erase the message about the weapon requirement again
set s = null
elseif (s != null) then
set s = s + " upgrades.|r"
endif
return s
endfunction
function UnitAddItemToSlot takes unit target, item targetItem, integer slot returns boolean
local integer i = 0
local item SlotItem
if (UnitInventoryCount(target) >= UnitInventorySize(target) ) then
return false
else
// only bother trying to place the item in the given slot, when it is actually free
if (UnitItemInSlot(target, slot) == null) then
loop
exitwhen (i > slot)
if (i != slot) then
if (UnitItemInSlot(target, i) == null) then
call UnitAddItemToSlotById(target, AWAY_ITEM_ID, i)
endif
else
call UnitAddItem(target, targetItem)
endif
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= UnitInventorySize(target)
set SlotItem = UnitItemInSlot(target, i)
if SlotItem!=null then
if GetItemTypeId(SlotItem) == AWAY_ITEM_ID then
call RemoveItem( SlotItem )
endif
endif
set i = i + 1
endloop
set SlotItem = null
else
call UnitAddItem(target, targetItem)
endif
endif
return true
endfunction
function ReactivateBlockingArmor takes unit caster returns nothing
local integer i = 0
local item temp
local real itemLife
loop
exitwhen i >= UnitInventorySize(caster)
set temp = UnitItemInSlot(caster, i)
if IsBlockingArmor(temp) then
call UnitRemoveItem(caster, temp)
// if the unit is on its own Junkyard, then dropped item will be sold, which we don't want
if IsCoordInJunkyard(GetItemX(temp), GetItemY(temp), udg_Player_Team[GetPlayerNr(GetItemPlayer(temp))]) then
set IgnoreNextItemOnJunkyard = true
endif
call UnitAddItemToSlot(caster, temp, i)
endif
set i = i + 1
endloop
if (GetUnitAbilityLevel(caster, DEFLECTIVE_UPGRADE_BUFF_ABILITY_ID) == 0) and UnitHasItemOfTypeBJ(caster, DEFLECTIVE_UPGRADE_ITEM_ID) then
call UnitAddAbility(caster, DEFLECTIVE_UPGRADE_BUFF_ABILITY_ID)
endif
set temp = null
endfunction
function ReAddTempItems takes unit Tank returns nothing
local item TempItem
local integer top = GetPlayerNr(GetOwningPlayer(Tank)) * 6
local integer i = top - 5
call DebugMsg("Readd")
loop
exitwhen i > top
if udg_Item_CreateForHero[i] != null and udg_Item_CreateForHero[i] != 0 then
set TempItem = UnitAddItemById( Tank, udg_Item_CreateForHero[i] )
call DebugMsg("Added " + GetItemName(TempItem))
call SetItemPlayer( TempItem, GetOwningPlayer(Tank), false )
if udg_Afk[GetPlayerNr(GetOwningPlayer(Tank))] then
call SetItemDroppable( TempItem, false )
endif
set udg_Item_CreateForHero[i] = 0
endif
set i = i + 1
endloop
set TempItem = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Bounty requires BTFramework
globals
real KillDeathBountyInfluence = 0.00 // Set by the game mode, determines how much influence your KD stats have on your bounty
real BasicBounty = 0.00 // Set by the game mode, the bounty cannot go under this percantage of your basic bounty
real MinBounty = 0.01 // 125 + TankWorth * MinBounty is the smallest bounty allowed
real MaxBounty = 0.03 // 125 + TankWorth * MaxBounty is the biggest bounty allowed
real BountyIncrease = 0.05 // Only used with the Alternate Bounty Mode: your bounty increases by this percentage times the bounty of your kill
real BountyDecrease = 0.12 // Only used with the Alternate Bounty Mode: your bounty decreases by this percentage when you die
real KillingSpree_Bonus = 0.05 // the percentage of the original bounty that is added for every additional kill in the spree
real AssistSpree_Bonus = 0.05 // the percentage of the original bounty that is added for each additional assist in the spree
endglobals
function GiveItemToDeadTank takes integer playerId, integer weaponId returns nothing
local integer j = 1
loop
exitwhen j == 0
if udg_Item_CreateForHero[(playerId - 1) * 6 + j] == null or udg_Item_CreateForHero[(playerId - 1) * 6 + j] == 0 then
set udg_Item_CreateForHero[(playerId - 1) * 6 + j] = weaponId
set j = 0
else
set j = j + 1
endif
endloop
endfunction
function GetKillDeathRatio takes integer p returns real
local real r
if udg_Deaths[p]-GotTeamkilled[p] != 0 then
if (udg_Kills[p] == 0) then
set r = I2R(udg_Kills[p]+1)/I2R(udg_Deaths[p]-GotTeamkilled[p])
else
set r = I2R(udg_Kills[p])/I2R(udg_Deaths[p]-GotTeamkilled[p])
endif
else
set r = 1.00
endif
return r
endfunction
function GetBountyKillDeathRatio takes integer p returns real
local real r = RMinBJ(1.00, GetKillDeathRatio(p) + BasicBounty)
//if r < 1.00 and GetInventoryIndexOfItemTypeBJ(udg_Tank[p], 'I01W') == 0 and GetInventoryIndexOfItemTypeBJ(udg_Tank[p], 'I04D') == 0 and GetInventoryIndexOfItemTypeBJ(udg_Tank[p], 'I01X') == 0 then
// set r = RMinBJ(1.00, r + ExplosivesFactor)
//endif
set r = 1.00 - (1.00-r) * KillDeathBountyInfluence
return r
endfunction
function GetBountyBonus takes integer killingId returns real
if (udg_KillingSpree[killingId] < 3) then
return 1.0
else
return (1.0 + KillingSpree_Bonus * IMinBJ(10, udg_KillingSpree[killingId]))
endif
return 1.0
endfunction
function GetAssistBonus takes integer assistsId returns real
if (udg_AssistSpree[assistsId] < 3) then
return 0.0
else
return (AssistSpree_Bonus * IMinBJ(10, udg_AssistSpree[assistsId]))
endif
return 0.0
endfunction
function GetBounty takes unit Tank, boolean bounty returns integer
local integer ownerID
if Tank==null then
return 0
endif
set ownerID = GetPlayerNr(GetOwningPlayer(Tank))
if Tank!=udg_Tank[ownerID] then
return 1
endif
if bounty then
return R2I(RMaxBJ(udg_TankBounty[ownerID], 1))
endif
return udg_TankCosts[ownerID]
endfunction
function UpdateBounty takes player owner, integer amount returns nothing
local integer ownerID = GetPlayerNr(owner)
local real minBounty = 125 + udg_TankCosts[ownerID] * MinBounty
local real maxBounty = 125 + udg_TankCosts[ownerID] * MaxBounty
if AlternateBounty then
if (GetPlayerNr(owner) <= GetMaxHumanPlayers()) then
if (amount > 0) then
set udg_TankBounty[ownerID] = RMinBJ(maxBounty * GeneralGoldFactor, udg_TankBounty[ownerID] + (amount * BountyIncrease))
else
set udg_TankBounty[ownerID] = RMaxBJ(minBounty * GeneralGoldFactor, udg_TankBounty[ownerID] + (amount * BountyDecrease))
endif
call ModifyHeroStat( bj_HEROSTAT_STR, udg_Tank[GetPlayerNr(owner)], bj_MODIFYMETHOD_SET, R2I(udg_TankBounty[ownerID]) )
endif
endif
endfunction
function ResetMoveSpeedIndicator takes unit Tank returns nothing
local integer i = 0
loop
exitwhen i > 8
call UnitRemoveAbility(Tank, udg_SpeedIndicatorPos[i])
call UnitRemoveAbility(Tank, udg_SpeedIndicatorNeg[i])
set i = i + 1
endloop
endfunction
function GetRespawnTime takes unit tank, boolean showIncrease returns integer
local integer ownerId = GetPlayerNr(GetOwningPlayer(tank))
local integer ownerTeam = udg_Player_Team[ownerId]
local integer devastatorLevel = GetUnitAbilityLevel(tank, DEVASTATOR_SHOT_BUFF_ID)
local real devastatorFactor = RESPAWN_INCREASE_BASE + ( devastatorLevel * RESPAWN_INCREASE_UP )
local real baseTime = 10.00 + udg_TankCosts[ownerId]/3333.00
local real timeFactor = 1.0
if (ownerTeam == 1) and RectContainsUnit(gg_rct_Team_1_Base_Main, tank) then
set timeFactor = timeFactor + 0.20
elseif (ownerTeam == 2) and RectContainsUnit(gg_rct_Team_2_Base_Main, tank) then
set timeFactor = timeFactor + 0.20
endif
if (devastatorLevel > 0) then
set timeFactor = timeFactor + devastatorFactor
endif
if (showIncrease and (devastatorLevel > 0)) then
call ShowTextTag("+" + I2S(R2I(baseTime * (timeFactor-1))) + "s respawn" , tank , 0 , 100 , null)
endif
return R2I(baseTime * timeFactor)
endfunction
function SetRespawnTimeIndicator takes unit tank returns nothing
//call ModifyHeroStat( bj_HEROSTAT_AGI, tank, bj_MODIFYMETHOD_SET, GetRespawnTime(tank, false) )
endfunction
function SetMoveSpeedIndicator takes unit Tank returns nothing
//local integer defaultSpeed = R2I(GetUnitDefaultMoveSpeed(Tank))
local integer currentSpeed = R2I(GetUnitMoveSpeed(Tank))
//local integer a= IAbsBJ(defaultSpeed-currentSpeed)
//local integer array b
//local integer c=1
//local integer i=0
//local integer max = 8 //the number of speed indicator skills
if currentSpeed>0 then
call ModifyHeroStat( bj_HEROSTAT_INT, Tank, bj_MODIFYMETHOD_SET, currentSpeed )
else
call ModifyHeroStat( bj_HEROSTAT_INT, Tank, bj_MODIFYMETHOD_SET, 1 )
endif
//Idea: display the default speed as a white number and the difference to the current speed in either a green or red number
//Problem: when displaying a red number (substracting int), the tank cannot regenerate any mana
//Problem 2: due to the adding and removing of the abilities, the current aiming order of your tanks gets disrupted
//loop
// exitwhen c==0
// set c=a/2
// set b[i]=a-c*2
// set a=c
// set i=i+1
//endloop
//set i=0
//call ResetMoveSpeedIndicator(Tank)
//if (currentSpeed > defaultSpeed) then
// loop
// exitwhen i>max
// if b[i]==1 then
// call UnitAddAbility(Tank, udg_SpeedIndicatorPos[i])
// else
// call UnitRemoveAbility(Tank, udg_SpeedIndicatorPos[i])
// endif
// set i=i+1
// endloop
//else
// loop
// exitwhen i>max
// if b[i]==1 then
// call UnitAddAbility(Tank, udg_SpeedIndicatorNeg[i])
// else
// call UnitRemoveAbility(Tank, udg_SpeedIndicatorNeg[i])
// endif
// set i=i+1
// endloop
//endif
endfunction
function UpdateTankCosts takes integer ownerID returns nothing
local unit Tank = udg_Tank[ownerID]
local integer i
local integer iend
local integer worth = GetUnitPointValue(Tank)
local integer RewardID
local integer ItemCharges
local item Temp
local unit PickUnit
local group G = NewGroup()
call GroupEnumUnitsOfPlayer(G, GetOwningPlayer(Tank), FILTER_NULL)
loop
set PickUnit = FirstOfGroup( G )
exitwhen PickUnit == null
set i = 0
set iend = UnitInventorySize(PickUnit)
loop
exitwhen i >= iend
set Temp = UnitItemInSlot(PickUnit, i)
if Temp != null then
set ItemCharges = GetItemCharges(Temp)
if ItemCharges == 0 then
set worth = worth + R2I(GetWidgetLife(Temp))
elseif GetItemType(Temp) == ITEM_TYPE_CHARGED then
if udg_Player_Team[ownerID] == 1 then
set RewardID = R2I(GetWidgetLife(Temp))
else
set RewardID = 11 - R2I(GetWidgetLife(Temp))
endif
set worth = worth + ItemCharges * 5 * udg_Trader_Gold[RewardID]
else
set worth = worth + R2I( GetWidgetLife(Temp) * I2R(ItemCharges) )
endif
endif
set i = i + 1
endloop
call GroupRemoveUnit( G, PickUnit )
endloop
call ReleaseGroup(G)
call SetMoveSpeedIndicator(Tank)
set Temp = null
set udg_TankCosts[ownerID] = worth
if not AlternateBounty then
set udg_TankBounty[ownerID] = (((125 + worth / 60) * GetBountyKillDeathRatio(ownerID) * GeneralGoldFactor))
call ModifyHeroStat( bj_HEROSTAT_STR, Tank, bj_MODIFYMETHOD_SET, R2I(udg_TankBounty[ownerID]) )
endif
//call SetRespawnTimeIndicator(Tank)
set Tank = null
set G = null
endfunction
function GetBountyFactor takes nothing returns real
return GeneralGoldFactor+TimerGetElapsed(udg_GameTime)/3600
endfunction
function GetForceIncome takes integer forceGold, integer playersInTeam returns integer
return (4 * forceGold / ( playersInTeam * 9 + 15 ))
endfunction
function GetBaseIncome takes integer playersInTeam returns real
return ( IncomeFactor * (32.0 / ( playersInTeam*3+5 )) )
endfunction
function GetPassiveIncome takes real goldRemainder, integer playersInTeam returns real
local real base = GetBaseIncome(playersInTeam)
local real value = 0
set value = RMaxBJ(goldRemainder/75.0, base)
if (value > goldRemainder) then
set value = goldRemainder
endif
return (value + base)
endfunction
endlibrary
//TESH.scrollpos=134
//TESH.alwaysfold=0
library DamageDetection initializer Init requires Effects
// The interface for functions, that include the code, that gets executed, once a registered unit takes damage
function interface DamageAlterationFunction takes nothing returns real
// The interface for functions, that include the code, that gets executed, after the final damage has been calculated
function interface PostDamageFunction takes real finalDamage returns nothing
globals
constant real MIN_TRIGGER_DAMAGE = 2.0 // at least this much damage has to be dealt to activate the calculations
unit DamageDetection_DamageSource // the unit from which the damage came from
unit DamageDetection_DamageTarget // the unit that suffered the damage
real DamageDetection_Damage // the amount of the taken damage
integer DamageDetection_Progress = 0 // gets bigger than 1, if this trigger gets called recursively -> don't deal damage anymore within this trigger
boolean DamageDetection_Pause = false // set to true, if you want the system to ignore damage being dealt
integer DamageDetection_Count = 0 // counts, how many skill trigger use the damage detection at the moment, when 0, the trigger gets disabled
private integer RegisteredAddendFunctions = 0 // the amount of functions, that alter the taken damage by absolute numbers, used for iterations
DamageAlterationFunction array DamageDetection_AddendCode[MAX_ARRAY_SIZE] // the code that gets executed, once a registered unit takes damage
private integer RegisteredFactorFunctions = 0 // the amount of functions, that alter the taken damage by relative numbers, used for iterations
DamageAlterationFunction array DamageDetection_FactorCode[MAX_ARRAY_SIZE] // the code that gets executed, once a registered unit takes damage
private integer RegisteredPostFunctions = 0 // the amount of functions, that are executed, after the final damage has been calculated, used for iterations
PostDamageFunction array DamageDetection_PostCode[MAX_ARRAY_SIZE] // the code that gets executed, after the final damage has been calculated
private integer array FunctionIsActive[MAX_ARRAY_SIZE] // to reduce the overhead, just check for this variable, instead of using the "evaluate()" function -> better perfomance
private constant integer ADDEND_START_ID = 0
private constant integer FACTOR_START_ID = 2500
private constant integer POST_START_ID = 5000
endglobals
// ---------------------------------------------------------------------------------------
// Example for a function, that's registered with one of the RegisterDamageDetectionCode- functions
// no parameters and returns real, it has to be this way, to match the function interface
function SkillEffect takes nothing returns real
// don't do anything unnecessary, end the function as soon as possible
if GetUnitAbilityLevel(DamageDetection_DamageTarget, 'A123') > 0 then
// if this is registered as a AddendCode function, this will reduce the incoming damage by 100
return -100.0
endif
return 0.0
endfunction
// Example for registering the skill trigger for the damage detection
// This registers a specific function from the skill trigger with the damage detection
// call RegisterDamageDetectionCodeRelative(damDetFunction.Trig_Banish_DamageDetection)
// ---------------------------------------------------------------------------------------
// Since we don't want to waste any performance, this trigger only runs, when it's really needed
// This means, that every skill, that wants to use damage detection, has to activate it with EnableSkillDamageDetection
// but must also deactivate it, once the skill duration is over, with DisableSkillDamageDetection
// So it's discouraged to use this trigger for passive abilities, since they are running all the time
// (which is the case for the upgraded Deflective Armor, so yeah ... so much for that)
// If this trigger is not yet running, activate it and count how often is has been activated
function EnableSkillDamageDetection takes integer functionId returns nothing
if DamageDetection_Count == 0 then
call EnableTrigger( gg_trg_Damage_Detection_System )
endif
set FunctionIsActive[functionId] = FunctionIsActive[functionId] + 1
set DamageDetection_Count = DamageDetection_Count + 1
//call DebugMsg("DD count: " + I2S(DamageDetection_Count))
endfunction
// If no skill trigger needs damage detection at the moment, deactivate it
// Note, that either the damage detection is running for all skill trigger or not at all
// By calling this function, you are not disabling the damage detection for a specific skill
function DisableSkillDamageDetection takes integer functionId returns nothing
if (DamageDetection_Count > 0) then
set DamageDetection_Count = DamageDetection_Count - 1
else
call DebugMsg("Disable SDD - " + I2S(DamageDetection_Count))
call SendBotDataOnline(DEBUG_INFO_DATA, "Disable SDD - " + I2S(DamageDetection_Count))
endif
set FunctionIsActive[functionId] = FunctionIsActive[functionId] - 1
if DamageDetection_Count <= 0 then
call DisableTrigger( gg_trg_Damage_Detection_System )
endif
endfunction
function PauseSkillDamageDetection takes boolean pause returns nothing
set DamageDetection_Pause = pause
endfunction
function RegisterUnitForSkillDamageDetection takes unit U returns nothing
call TriggerRegisterUnitEvent( gg_trg_Damage_Detection_System, U, EVENT_UNIT_DAMAGED )
endfunction
// Registers functions, that modify the taken damage by adding / substracting a constant number
function RegisterDamageDetectionCodeAbsolute takes DamageAlterationFunction ddfunc returns integer
set DamageDetection_AddendCode[RegisteredAddendFunctions] = ddfunc
set RegisteredAddendFunctions = RegisteredAddendFunctions + 1
return ADDEND_START_ID + (RegisteredAddendFunctions-1)
endfunction
// Registers functions, that multiply the taken damage by a certain factor
function RegisterDamageDetectionCodeRelative takes DamageAlterationFunction ddfunc returns integer
set DamageDetection_FactorCode[RegisteredFactorFunctions] = ddfunc
set RegisteredFactorFunctions = RegisteredFactorFunctions + 1
return FACTOR_START_ID + (RegisteredFactorFunctions-1)
endfunction
// Registers functions, that are executed after the final damage has been calculated
// They only evaluate the taken damage, they do not alter it anymore
function RegisterDamageDetectionCodePost takes PostDamageFunction ddfunc returns integer
set DamageDetection_PostCode[RegisteredPostFunctions] = ddfunc
set RegisteredPostFunctions = RegisteredPostFunctions + 1
return POST_START_ID + (RegisteredPostFunctions-1)
endfunction
// Use this function, if you want to deal damage within a skill effect trigger
// This function prevents an endless re-triggering of the damage detection and with it, a crash
function DDS_UnitDamageTarget takes unit source, unit target, real damage returns nothing
//if (DamageDetection_Progress <= 1) then
call PauseSkillDamageDetection(true)
call UnitDamageTarget(source, target, damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call PauseSkillDamageDetection(false)
//endif
endfunction
function Trig_Damage_Detection_System_ShowBlockedDamage takes unit target, real amount returns nothing
local texttag tag
local real PosX
local real PosY
local real PosZ
local boolean visibility = false
if (HitpointChanges) then
set tag = CreateTextTag( )
set PosX = GetUnitX(target)
set PosY = GetUnitY(target)
set PosZ = GetUnitFlyHeight(target)
if GetLocalPlayer() == GetOwningPlayer(target) then
set visibility = true
endif
//s - string to be shown, including color code
call SetTextTagText(tag, "|c00ffdead"+I2S(R2I(amount))+"|r", 0.013)
call SetTextTagPos(tag, PosX, PosY, PosZ)
call SetTextTagVisibility(tag, visibility)
call SetTextTagVelocity(tag, 0, -0.02)
call SetTextTagFadepoint(tag, 0.5 )
call SetTextTagLifespan(tag, 1 )
call SetTextTagPermanent(tag, false )
set tag = null
endif
endfunction
function Trig_Damage_Detection_System_Actions takes nothing returns nothing
local integer i = 0
local real damageFactor = 1.0
local real damageAddend = 0.0
local real damageAdjustment = 0.0
if (DamageDetection_Pause == false) then
set DamageDetection_Progress = DamageDetection_Progress + 1
set DamageDetection_DamageSource = GetEventDamageSource()
set DamageDetection_DamageTarget = GetTriggerUnit()
set DamageDetection_Damage = GetEventDamage()
if (DamageDetection_Damage > MIN_TRIGGER_DAMAGE) then
// first, check all registered functions and their influence on the triggering unit
loop
exitwhen i >= RegisteredFactorFunctions
if (FunctionIsActive[FACTOR_START_ID+i] > 0) then
set damageFactor = damageFactor + DamageDetection_FactorCode[i].evaluate()
endif
//call DebugMsg("Factor: " + R2S(damageFactor))
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= RegisteredAddendFunctions
if (FunctionIsActive[ADDEND_START_ID+i] > 0) then
set damageAddend = damageAddend + DamageDetection_AddendCode[i].evaluate()
endif
set i = i + 1
endloop
// also make sure, that those values don't become too small
set damageFactor = RMaxBJ(damageFactor, 0.0)
set damageAddend = RMaxBJ(damageAddend, -DamageDetection_Damage)
set damageAdjustment = (damageFactor * (DamageDetection_Damage + damageAddend)) - DamageDetection_Damage
set i = 0
loop
exitwhen i >= RegisteredPostFunctions
if (FunctionIsActive[POST_START_ID+i] > 0) then
call DamageDetection_PostCode[i].evaluate(damageAdjustment + DamageDetection_Damage)
endif
set i = i + 1
endloop
if (damageAdjustment == 0.0) then
// do nothing, damage has not been modified
elseif (damageAdjustment < 0.0) then
// heal up the damage, that has been dealt to match the blocked / reduced damage
//call DebugMsg("Blocked damage: " + R2S(-damageAdjustment))
call Trig_Damage_Detection_System_ShowBlockedDamage(DamageDetection_DamageTarget, damageAdjustment)
call DynamicDamageBlock(DamageDetection_DamageTarget, -damageAdjustment)
elseif (damageAdjustment > 0.0) then
call DebugMsg("Extra damage: " + R2S(damageAdjustment))
call DisableTrigger(GetTriggeringTrigger())
call UnitDamageTarget(DamageDetection_DamageSource, DamageDetection_DamageTarget, damageAdjustment, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call EnableTrigger(GetTriggeringTrigger())
endif
endif
set DamageDetection_Progress = DamageDetection_Progress - 1
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Damage_Detection_System = CreateTrigger( )
call DisableTrigger( gg_trg_Damage_Detection_System )
call TriggerAddAction( gg_trg_Damage_Detection_System, function Trig_Damage_Detection_System_Actions )
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Effects requires TimerAndAttachments, MapAttachedSettings
function SetUnitManaDelayed_Child takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = GetHandleIndex(t)
call SetUnitState(udg_AV_Unit1[i], UNIT_STATE_MANA, udg_AV_Real1[i])
call ReleaseTimer(t)
call ReleaseHandleIndex(i)
endfunction
function SetUnitManaDelayed takes unit U, real Mana returns nothing
local timer t = NewTimer()
local integer i = NewTimerIndex(t)
set udg_AV_Unit1[i] = U
set udg_AV_Real1[i] = Mana
call TimerStart(t,0.00,false,function SetUnitManaDelayed_Child)
endfunction
function DestroyTreesInRange_Enum takes nothing returns nothing
local destructable Tree = GetEnumDestructable()
if GetDestructableTypeId(Tree)=='ATtr' and Pow(bj_cineFadeContinueRed-GetDestructableX(Tree),2)+Pow(bj_cineFadeContinueGreen-GetDestructableY(Tree),2) <= bj_enumDestructableRadius then
call KillDestructable(Tree)
endif
set Tree = null
endfunction
function DestroyTreesInRange takes real X, real Y, real Range returns nothing
if not udg_NoEffects then
call SetRect(udg_TempRect, X-Range,Y-Range,X+Range,Y+Range)
set bj_cineFadeContinueRed = X
set bj_cineFadeContinueGreen = Y
set bj_enumDestructableRadius = Range*Range
call EnumDestructablesInRect(udg_TempRect, FILTER_NULL, function DestroyTreesInRange_Enum )
endif
endfunction
function ShowEffectAtPos_Child takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
call ReleaseDummy(udg_AV_Unit1[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endfunction
function ShowEffectAtPos takes string Effect, real x, real y, real z, real scale, real duration returns nothing
local unit EffectDummy = XE_NewDummyUnit(GetPlayer(11), x, y, 270)
local timer t
local integer TimerIndex
call SetUnitScale(EffectDummy, scale, scale, scale)
call SetUnitFlyHeight(EffectDummy, z, 0)
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = EffectDummy
set udg_AV_Effect1[TimerIndex] = AddSpecialEffectTarget(Effect, EffectDummy, "origin")
call TimerStart(t, duration, false, function ShowEffectAtPos_Child)
set EffectDummy = null
endfunction
function CreateExplosionSizedTimed takes player Owner, real x, real y, real scaleSize, real scaleSpeed returns unit
set bj_lastCreatedUnit = CreateUnit( Owner, 'h00W', x, y, 90 )
call SetUnitPathing(bj_lastCreatedUnit,false)
call SetUnitX(bj_lastCreatedUnit,x)
call SetUnitY(bj_lastCreatedUnit,y)
call SetUnitScale(bj_lastCreatedUnit, scaleSize, scaleSize, scaleSize)
call SetUnitTimeScale( bj_lastCreatedUnit, scaleSpeed )
call KillUnit( bj_lastCreatedUnit )
return bj_lastCreatedUnit
endfunction
//Deals max damage in the middle of the area and decreases gradually to the outer area
function AreaSpellDamageFromUnit takes unit Source, real X, real Y, real Rng, real Dmg, real BuildingsFactor, real AlliesFactor, boolexpr filter returns nothing
local unit U
local real Damage
local real DistX
local real DistY
local real Dist
local group G = NewGroup()
if filter==null then
set filter=FILTER_NULL
endif
call GroupEnumUnitsInRange( G, X, Y, Rng, filter )
loop
set U = FirstOfGroup( G )
exitwhen U == null
set DistX = X - GetUnitX(U)
set DistY = Y - GetUnitY(U)
set Dist = SquareRoot((DistX * DistX) + (DistY * DistY))
if Dist <= 0.5 * Rng then
set Damage = Dmg
else
set Damage = (1.75-1.5*(Dist/Rng)) * Dmg
endif
if IsUnitType(U, UNIT_TYPE_STRUCTURE) and IsUnitAlly(U, GetOwningPlayer(Source)) then
//Don't deal any damage to allied buildings
set Damage = 0
else
if IsUnitType(U, UNIT_TYPE_STRUCTURE) then
set Damage=Damage*BuildingsFactor
endif
if IsUnitAlly(U, GetOwningPlayer(Source)) then
set Damage=Damage*AlliesFactor
endif
endif
if (Damage > 0) then
if (IsUnitType(U, UNIT_TYPE_HERO)) and (GetUnitTypeId(Source) != 'z00P') then
call ShowTextTag("|cfffe0101"+I2S(R2I(Damage))+"!|r", U, 50, 50, null)
endif
call UnitDamageTarget(Source, U, Damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
endif
call GroupRemoveUnit( G, U )
endloop
call ReleaseGroup(G)
set G = null
endfunction
function AreaSpellDamageExplosive takes unit Source, real Rng, real Dmg, real BuildingsFactor, real AlliesFactor returns nothing
call AreaSpellDamageFromUnit( Source, GetUnitX(Source), GetUnitY(Source), Rng, Dmg, BuildingsFactor, AlliesFactor, FILTER_VALID_TARGET )
endfunction
//Deals equal damage to each unit in the area
function FixedAreaDamageFromUnit takes unit Source, real X, real Y, real Rng, real Dmg, real BuildingsFactor, real AlliesFactor, boolean ShowDmg, boolexpr filter returns nothing
local unit U
local real Damage
local group G = NewGroup()
if filter==null then
set filter=FILTER_NULL
endif
call GroupEnumUnitsInRange( G, X, Y, Rng, filter )
loop
set U = FirstOfGroup( G )
exitwhen U == null
set Damage = Dmg
if IsUnitType(U, UNIT_TYPE_STRUCTURE) then
set Damage=Damage*BuildingsFactor
endif
if IsUnitAlly(U, GetOwningPlayer(Source)) then
set Damage=Damage*AlliesFactor
endif
if (IsUnitType(U, UNIT_TYPE_HERO)) and ShowDmg then
call ShowTextTag("|cfffe0101"+I2S(R2I(Damage))+"!|r", U, 50, 50, null)
endif
call UnitDamageTarget(Source, U, Damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit( G, U )
endloop
call ReleaseGroup(G)
set G = null
endfunction
function FlashPointSizedTimed takes real x, real y, real power, real size, real startFadeTime, real duration returns nothing
local real distx = x-GetCameraTargetPositionX()
local real disty = y-GetCameraTargetPositionY()
local real dist = SquareRoot(distx*distx + disty*disty)
if dist > size*2 then
set power=0
elseif dist > size then
set power = power*(2*size-dist)/size
endif
if startFadeTime!=0 then
call AbortCinematicFadeBJ()
call SetCineFilterTexture("ReplaceableTextures\\CameraMasks\\White_mask.blp")
call SetCineFilterBlendMode(BLEND_MODE_BLEND)
call SetCineFilterTexMapFlags(TEXMAP_FLAG_NONE)
call SetCineFilterStartUV(0, 0, 1, 1)
call SetCineFilterEndUV(0, 0, 1, 1)
call SetCineFilterStartColor(255, 255, 255, IMaxBJ(R2I(power*2.55),0))
call SetCineFilterEndColor(255, 255, 255, 0)
call SetCineFilterDuration(10000)
call DisplayCineFilter(true)
call GameTimeWait( startFadeTime )
endif
call AbortCinematicFadeBJ()
call SetCineFilterTexture("ReplaceableTextures\\CameraMasks\\White_mask.blp")
call SetCineFilterBlendMode(BLEND_MODE_BLEND)
call SetCineFilterTexMapFlags(TEXMAP_FLAG_NONE)
call SetCineFilterStartUV(0, 0, 1, 1)
call SetCineFilterEndUV(0, 0, 1, 1)
call SetCineFilterStartColor(255, 255, 255, IMaxBJ(R2I(power*2.55),0))
call SetCineFilterEndColor(255, 255, 255, 0)
call SetCineFilterDuration(duration)
call DisplayCineFilter(true)
call FinishCinematicFadeAfterBJ(duration)
endfunction
function CameraAddEQNoiseSave takes real magnitude returns nothing
local real Noise = udg_NoiseForPlayer[GetPlayerNr(GetLocalPlayer())] + magnitude
local real richter
set udg_NoiseForPlayer[GetPlayerNr(GetLocalPlayer())] = Noise
if Noise > 5.0 then
set richter = 5.0
else
if Noise < 2.0 then
set richter = 2.0
else
set richter = Noise
endif
endif
call CameraSetSourceNoise( Noise * 2.0, Noise * Pow( 10, richter ) )
call CameraSetTargetNoise( Noise * 2.0, Noise * Pow( 10, richter ) )
endfunction
function ShakeCamAtLoc_Child takes nothing returns nothing
local real X = bj_meleeNearestMineDist
local real Y = bj_cineFadeContinueRed
local real fadeStart = bj_cineFadeContinueGreen * 0.85
local real fadeEnd = bj_cineFadeContinueGreen * 1.20
local real magnitude = bj_cineFadeContinueBlue
local real duration = bj_cineFadeContinueDuration
local real DistX
local real DistY
local real Dist
local real LastShakingMagnitude = 0
local real NewShakingMagnitude
local real beginGameTime = TimerGetElapsed(udg_GameTime)
loop
exitwhen TimerGetElapsed(udg_GameTime)-beginGameTime < 0.20
set NewShakingMagnitude = -LastShakingMagnitude
set DistX = GetCameraTargetPositionX( ) - X
set DistY = GetCameraTargetPositionY( ) - Y
set Dist = SquareRoot( DistX * DistX + DistY * DistY )
if Dist < fadeStart then
set NewShakingMagnitude = NewShakingMagnitude + magnitude
else
if Dist < fadeEnd then
set NewShakingMagnitude = NewShakingMagnitude + magnitude * ( fadeEnd - Dist ) / 200
endif
endif
set LastShakingMagnitude = LastShakingMagnitude + NewShakingMagnitude
call CameraAddEQNoiseSave( NewShakingMagnitude )
call TriggerSleepAction( 0.20 )
endloop
call CameraAddEQNoiseSave( -LastShakingMagnitude )
endfunction
function ShakeCamAtLoc takes real X, real Y, real range, real magnitude, real duration returns nothing
set bj_meleeNearestMineDist = X
set bj_cineFadeContinueRed = Y
set bj_cineFadeContinueGreen = range
set bj_cineFadeContinueBlue = magnitude
set bj_cineFadeContinueDuration = duration
call ExecuteFunc("ShakeCamAtLoc_Child")
endfunction
function GetExplosiveDamage takes unit U, boolean onDeath returns real
local integer i = 0
local integer ItemType
local real Damage = 0
local real DamageFactor = 1
local real explosiveLevel = GetUnitAbilityLevel(U,EXPLOSIVES_ABILITY_ID)
if onDeath then
if (IsPacifista(U)) then
//This is the level of his inventory ability, it's only below level 6, when he is in 1500 range of the Architect
// -> when the level is 6 or above, no explosion occurs at all
if (GetUnitAbilityLevel(U, PACIFISTA_INVENTORY_ID) < 6) then
set Damage = PACIFISTA_EXPLOSION_DAMAGE_BASE + (GetUnitAbilityLevel(U, PACIFISTA_INVENTORY_ID) * PACIFISTA_EXPLOSION_DAMAGE_UP)
else
return 0.0
endif
else
if (explosiveLevel > 0) then
set DamageFactor = EXPLOSIVES_FACTOR_BASE + (explosiveLevel * EXPLOSIVES_FACTOR_UP)
else
set DamageFactor = 0
endif
endif
endif
loop
exitwhen i > 5
set ItemType = GetItemTypeId(UnitItemInSlot(U, i))
if ItemType == 'I01W' then
set Damage = Damage + 1800
elseif ItemType == 'I01X' then
set Damage = Damage + 3600
elseif ItemType == 'I04D' then
set Damage = Damage + 5400
endif
set i = i + 1
endloop
return (Damage*DamageFactor)
endfunction
function UnitBlowUpExplosives takes unit Exploder, unit Caster, boolean onDeath returns nothing
local real Damage = GetExplosiveDamage(Exploder, onDeath)
local player Owner
local unit dummy
local real wait
local real X
local real Y
if Damage > 0 then
set Owner = GetOwningPlayer(Caster)
set X = GetUnitX(Exploder)
set Y = GetUnitY(Exploder)
if onDeath then
set wait = 0.5
else
set wait = 0
endif
//To make sure, that the AI evades the explosion
set dummy = CreateUnit(Owner, DUMMY_ID, X, Y, 0)
call SetUnitState(dummy, UNIT_STATE_LIFE, 499999)
call UnitApplyTimedLife( dummy, 'BTLF', 1.50 )
set dummy = null
call GameTimeWait(wait)
call CreateExplosionSizedTimed(Owner,X,Y,2.4,0.25)
call CreateExplosionSizedTimed(Owner,X,Y,2.4,0.25)
call GameTimeWait(wait)
if not IsUnitInvisible(Exploder, GetOwningPlayer(Exploder)) then
//call AreaSpellDamageExplosive(Caster,600,Damage,0.25, 0.5)
call AreaSpellDamageFromUnit( Caster, X, Y, 600, Damage, 0.25, 0.5, FILTER_VALID_TARGET )
endif
call DestroyTreesInRange(X,Y,600)
endif
endfunction
function MakeUnitInvulnerable takes unit U, boolean invul returns nothing
local integer PlayerId = GetPlayerNr(GetOwningPlayer(U))
if not IsUnitType(U, UNIT_TYPE_HERO) then
call SetUnitInvulnerable( U, invul )
return
endif
// For tanks there is a stack for invulnerability, so that
// call MakeUnitInvulnerable(U,true)
// call MakeUnitInvulnerable(U,true)
// call MakeUnitInvulnerable(U,false)
// // Still is invulnerable
// call MakeUnitInvulnerable(U,false)
// // Now is vulnerable again
if invul then
set udg_Tank_Invulnerable[PlayerId] = udg_Tank_Invulnerable[PlayerId] + 1
if udg_Tank_Invulnerable[PlayerId] == 1 then
call SetUnitInvulnerable( U, true )
endif
else
if (udg_Tank_Invulnerable[PlayerId] == 0) then
call SendBotDataOnline(DEBUG_INFO_DATA, "MakeUnitInvulnerable - " + I2S(udg_Tank_Invulnerable[PlayerId]))
else
set udg_Tank_Invulnerable[PlayerId] = udg_Tank_Invulnerable[PlayerId] - 1
endif
if udg_Tank_Invulnerable[PlayerId] == 0 and udg_Team_Winning == 0 then
call SetUnitInvulnerable( U, false )
endif
endif
endfunction
function ResetSplashCannon_Child takes nothing returns nothing
local integer ResetTimerId = GetHandleIndex(GetExpiredTimer())
local unit tank = udg_AV_Unit1[ResetTimerId]
call IssueImmediateOrder(tank, "defend")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(ResetTimerId)
set tank = null
endfunction
function ResetSplashCannon takes unit tank returns nothing
local integer Id = GetPlayerNr(GetOwningPlayer(tank))
local timer t
local integer ResetTimerId
if (GetUnitTypeId(tank) == 'H021') then
call GameTimeWait(0)
if SplashIsActive[Id] then
call IssueImmediateOrder(tank, "undefend")
set t = NewTimer()
set ResetTimerId = NewTimerIndex(t)
set udg_AV_Unit1[ResetTimerId] = tank
call TimerStart(t, 0.25, true, function ResetSplashCannon_Child)
else
call IssueImmediateOrder(tank, "undefend")
endif
endif
endfunction
globals
integer DAMAGE_BLOCK_HP_BONUS_ID = 'A0C9'
endglobals
function PostDamageHeal_Child takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local real heal = udg_AV_Real1[LoopTimerId]
call SetUnitState(U, UNIT_STATE_LIFE, GetUnitState(U, UNIT_STATE_LIFE) + heal)
if (GetUnitAbilityLevel(U, DAMAGE_BLOCK_HP_BONUS_ID) > 0) then
call UnitRemoveAbility(U, DAMAGE_BLOCK_HP_BONUS_ID)
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
set U = null
endfunction
function PostDamageHeal takes unit U, real heal returns nothing
local timer t
local integer LoopTimerId
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Real1[LoopTimerId] = heal
call TimerStart(t, 0, false, function PostDamageHeal_Child)
endfunction
//This function combines post- and pre-heal to ensure the triggered heal always heals the desired amount
//The only case this function is not able to cover, is when the damage is higher than the max HP
function DynamicDamageBlock takes unit U, real damage returns nothing
local real curHP = GetUnitState(U, UNIT_STATE_LIFE)
local real maxHP = GetUnitState(U, UNIT_STATE_MAX_LIFE)
if (curHP > 0) then
if ((damage > (maxHP - curHP)) and (damage < (maxHP))) then
if (damage > curHP) then
//Pre-damage heal
call SetUnitState(U, UNIT_STATE_LIFE, maxHP)
call PostDamageHeal(U, damage - (maxHP - curHP))
else
call PostDamageHeal(U, damage)
endif
elseif (damage > (maxHP)) then
call UnitAddAbility(U, DAMAGE_BLOCK_HP_BONUS_ID)
if (GetUnitState(U, UNIT_STATE_LIFE) < damage) then
call DebugMsg("Extra HP und doch zu wenig")
call SetUnitState(U, UNIT_STATE_LIFE, GetUnitState(U, UNIT_STATE_LIFE) + damage)
call PostDamageHeal(U, 0)
else
call PostDamageHeal(U, damage)
endif
else
//Pre-damage heal
call SetUnitState(U, UNIT_STATE_LIFE, curHP + damage)
endif
endif
endfunction
// Attaches fire to the tank or removes it,
// this is used for tanks which do not have a damaged-animation on their own
function Tank_Attached_Fire_Change takes integer PlayerId, integer NewFireLevel returns nothing
local unit Tank = udg_Tank[PlayerId+1]
local integer CurrentFireLevel = udg_Tank_FireLevel[PlayerId+1]
if CurrentFireLevel < NewFireLevel then
loop
exitwhen CurrentFireLevel >= NewFireLevel
set CurrentFireLevel = CurrentFireLevel + 1
if CurrentFireLevel==1 then
set udg_Tank_AttachedFire[(PlayerId*5)+CurrentFireLevel] = AddSpecialEffectTarget("Environment\\SmallBuildingFire\\SmallBuildingFire2.mdl", Tank, "hand, left")
elseif CurrentFireLevel==2 then
set udg_Tank_AttachedFire[(PlayerId*5)+CurrentFireLevel] = AddSpecialEffectTarget("Environment\\SmallBuildingFire\\SmallBuildingFire2.mdl", Tank, "hand, right")
elseif CurrentFireLevel==3 then
set udg_Tank_AttachedFire[(PlayerId*5)+CurrentFireLevel] = AddSpecialEffectTarget("Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl", Tank, "chest")
elseif CurrentFireLevel==4 then
set udg_Tank_AttachedFire[(PlayerId*5)+CurrentFireLevel] = AddSpecialEffectTarget("Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl", Tank, "head")
else
set udg_Tank_AttachedFire[(PlayerId*5)+CurrentFireLevel] = AddSpecialEffectTarget("Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl", Tank, "origin")
endif
endloop
elseif CurrentFireLevel > NewFireLevel then
loop
exitwhen CurrentFireLevel <= NewFireLevel
call DestroyEffect(udg_Tank_AttachedFire[(PlayerId*5)+CurrentFireLevel])
set CurrentFireLevel = CurrentFireLevel - 1
endloop
endif
set udg_Tank_FireLevel[PlayerId+1] = CurrentFireLevel
set Tank = null
endfunction
endlibrary
//TESH.scrollpos=471
//TESH.alwaysfold=0
library Enumerations initializer Init requires BTFramework, UnitTypes
function GetClosestUnitFromGroup takes group G, real X, real Y returns unit
local unit tmp = null
local unit U = null
local real DistX
local real DistY
local real DistXYSq
local real SmallDistSq = 10000000000.0
loop
set tmp = FirstOfGroup( G )
exitwhen tmp == null
set DistX = X - GetUnitX(tmp)
set DistY = Y - GetUnitY(tmp)
set DistXYSq = DistX*DistX+DistY*DistY
if (DistXYSq < SmallDistSq) then
set U = tmp
set SmallDistSq = DistXYSq
endif
call GroupRemoveUnit( G, tmp )
endloop
return U
endfunction
function GroupEnumLocustsInRange takes group g, real x, real y, real radius, boolexpr filter returns nothing
local integer i = 0
local unit u
if filter == null then
set filter = FILTER_NULL
endif
loop
exitwhen i > 11
call GroupEnumUnitsOfPlayer( udg_enumGrp, Player( i ), filter )
loop
set u = FirstOfGroup(udg_enumGrp)
exitwhen u == null
if IsUnitInRangeXY( u, x, y, radius ) and GetUnitAbilityLevel(u,'Aloc') > 0 then
call GroupAddUnit( g, u )
endif
call GroupRemoveUnit(udg_enumGrp,u)
endloop
set i = i + 1
endloop
endfunction
function GroupEnumUnitsInRangeEx takes group g, real x, real y, real radius, boolexpr filter returns nothing
local integer i = 0
local unit u
if filter == null then
set filter = FILTER_NULL
endif
loop
exitwhen i > 11
call GroupEnumUnitsOfPlayer( udg_enumGrp, Player( i ), filter )
loop
set u = FirstOfGroup(udg_enumGrp)
exitwhen u == null
if IsUnitInRangeXY( u, x, y, radius ) then
call GroupAddUnit( g, u )
endif
call GroupRemoveUnit(udg_enumGrp,u)
endloop
set i = i + 1
endloop
endfunction
function GroupEnumLocustsInRect takes group g, rect r, boolexpr filter returns nothing
local integer i = 0
local unit u
local region re = CreateRegion()
call RegionAddRect( re, r )
if filter == null then
set filter = FILTER_NULL
endif
loop
exitwhen i > 11
call GroupEnumUnitsOfPlayer( udg_enumGrp, Player( i ), filter )
loop
set u = FirstOfGroup(udg_enumGrp)
exitwhen u == null
if GetUnitAbilityLevel( u, 'Aloc' ) > 0 and IsUnitInRegion( re, u ) then
call GroupAddUnit( g, u )
endif
call GroupRemoveUnit(udg_enumGrp,u)
endloop
set i = i + 1
endloop
call RegionClearRect( re, r )
call RemoveRegion( re )
set re = null
endfunction
function GroupEnumUnitsInRectEx takes group g, rect r, boolexpr filter returns nothing
local integer i = 0
local unit u
local region re = CreateRegion()
call RegionAddRect( re, r )
if filter == null then
set filter = FILTER_NULL
endif
loop
exitwhen i > 11
call GroupEnumUnitsOfPlayer( udg_enumGrp, Player( i ), filter )
loop
set u = FirstOfGroup(udg_enumGrp)
exitwhen u == null
if IsUnitInRegion( re, u ) then
call GroupAddUnit( g, u )
endif
call GroupRemoveUnit(udg_enumGrp,u)
endloop
set i = i + 1
endloop
call RegionClearRect( re, r )
call RemoveRegion( re )
set re = null
endfunction
function GroupEnumNormalUnitsOfPlayer takes group g, player p, boolexpr filter returns nothing
local unit u
if filter == null then
set filter = FILTER_NULL
endif
call GroupEnumUnitsOfPlayer( udg_enumGrp, p, filter )
loop
set u = FirstOfGroup( udg_enumGrp )
exitwhen u == null
if GetUnitAbilityLevel( u, 'Aloc' ) == 0 then
call GroupAddUnit( g, u )
endif
call GroupRemoveUnit( udg_enumGrp, u )
endloop
endfunction
function GroupEnumNormalUnitsOfType takes group g, string unitName, boolexpr filter returns nothing
local unit u
if filter == null then
set filter = FILTER_NULL
endif
call GroupEnumUnitsOfType( udg_enumGrp, unitName, filter )
loop
set u = FirstOfGroup( udg_enumGrp )
exitwhen u == null
if GetUnitAbilityLevel( u, 'Aloc' ) == 0 then
call GroupAddUnit( g, u )
endif
call GroupRemoveUnit( udg_enumGrp, u )
endloop
endfunction
// +--------------------------------------------
// | Replacements for unsafe Blizzard.j functions
// +--------------------------------------------
// In general, every call to DestroyBoolExpr() can lead to problems,
// so we are trying to avoid any calls to this function.
// As this replacement list is not complete, you should check in the Blizzard.j,
// if a function calls DestroyBoolExpr(), and at least do never use it with a FILTER_XXX constant
// GetUnitsInRectMatching
function GetUnitsInRectMatchingSafe takes rect r, boolexpr filter returns group
local group g = NewGroup()
call GroupEnumUnitsInRect(g, r, filter)
return g
endfunction
// GetUnitsInRectAll
function GetUnitsInRectAllSafe takes rect r returns group
local group g = NewGroup()
call GroupEnumUnitsInRect(g, r, FILTER_NULL)
return g
endfunction
// GetUnitsInRangeOfLocMatching
function GetUnitsInRangeOfLocMatchingSafe takes real radius, location whichLocation, boolexpr filter returns group
local group g = NewGroup()
call GroupEnumUnitsInRangeOfLoc(g, whichLocation, radius, filter)
return g
endfunction
// GetUnitsInRangeOfLocAll
function GetUnitsInRangeOfLocAllSafe takes real radius, location whichLocation returns group
local group g = NewGroup()
call GroupEnumUnitsInRangeOfLoc(g, whichLocation, radius, FILTER_NULL)
return g
endfunction
// GetUnitsOfPlayerMatching
function GetUnitsOfPlayerMatchingSafe takes player whichPlayer, boolexpr filter returns group
local group g = NewGroup()
call GroupEnumUnitsOfPlayer(g, whichPlayer, filter)
return g
endfunction
// GetUnitsOfPlayerAll
function GetUnitsOfPlayerAllSafe takes player whichPlayer returns group
local group g = NewGroup()
call GroupEnumUnitsOfPlayer(g, whichPlayer, FILTER_NULL)
return g
endfunction
// GetPlayersMatching
function GetPlayersMatchingSafe takes boolexpr filter returns force
local force f = CreateForce()
call ForceEnumPlayers(f, filter)
return f
endfunction
// +--------------------------------------------
// | Filter Functions
// +--+-----------------------------------------
// | General units functions
// +-----------------------------------------
function Filter_AntiLeak takes nothing returns boolean
return true
endfunction
function Filter_IsAlive takes nothing returns boolean
return GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.0
endfunction
function Filter_IsValidTarget takes nothing returns boolean
return Filter_IsAlive() and (GetUnitAbilityLevel(GetFilterUnit(), 'Avul') == 0) and (not IsDummy(GetFilterUnit())) and (not IsWard(GetFilterUnit()))
endfunction
function Filter_IsEnemy takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), udg_Filter_Player )
endfunction
function Filter_IsAlly takes nothing returns boolean
return IsUnitAlly(GetFilterUnit(), udg_Filter_Player )
endfunction
function Filter_IsAnyTank takes nothing returns boolean
return Filter_IsValidTarget() and IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO)
endfunction
function Filter_AllyTank takes nothing returns boolean
return Filter_IsAnyTank() and Filter_IsAlly()
endfunction
function Filter_EnemyTank takes nothing returns boolean
return Filter_IsAnyTank() and Filter_IsEnemy()
endfunction
function Filter_IsAnyStructure takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)
endfunction
function Filter_IsAnyCreep takes nothing returns boolean
return Filter_IsValidTarget() and (not Filter_IsAnyTank()) and (not Filter_IsAnyStructure())
endfunction
function Filter_EnemyCreeps takes nothing returns boolean
return Filter_IsAnyCreep() and Filter_IsEnemy()
endfunction
function Filter_AllyCreeps takes nothing returns boolean
return Filter_IsAnyCreep() and Filter_IsAlly()
endfunction
function Filter_EnemyUnits takes nothing returns boolean
return Filter_IsValidTarget() and Filter_IsEnemy()
endfunction
function Filter_AllyUnits takes nothing returns boolean
return Filter_IsValidTarget() and Filter_IsAlly()
endfunction
function Filter_VisibleEnemyUnits takes nothing returns boolean
return IsUnitVisible(GetFilterUnit(), udg_Filter_Player) and Filter_EnemyUnits()
endfunction
function Filter_IsAnyTower takes nothing returns boolean
return Filter_IsAnyStructure() and IsUnitType(GetFilterUnit(), UNIT_TYPE_RANGED_ATTACKER)
endfunction
function Filter_Enemy_NonStructure takes nothing returns boolean
return (not Filter_IsAnyStructure()) and Filter_EnemyUnits()
endfunction
function Filter_IsAirUnit takes nothing returns boolean
return IsAirUnit(GetFilterUnit())
endfunction
function Filter_IsGroundUnit takes nothing returns boolean
return IsGroundUnit(GetFilterUnit())
endfunction
function Filter_IsEnemyGroundUnit takes nothing returns boolean
return Filter_IsGroundUnit() and Filter_EnemyUnits()
endfunction
function Filter_IsAllyGroundUnit takes nothing returns boolean
return Filter_IsGroundUnit() and Filter_AllyUnits()
endfunction
function Filter_IsEnemyAirUnit takes nothing returns boolean
return Filter_IsAirUnit() and Filter_EnemyUnits()
endfunction
function Filter_IsAllyAirUnit takes nothing returns boolean
return Filter_IsAirUnit() and Filter_AllyUnits()
endfunction
function Filter_IsAirTank takes nothing returns boolean
return Filter_IsAirUnit() and Filter_IsAnyTank()
endfunction
function Filter_IsGroundTank takes nothing returns boolean
return Filter_IsGroundUnit() and Filter_IsAnyTank()
endfunction
function Filter_IsEnemyAirTank takes nothing returns boolean
return Filter_IsAirTank() and Filter_EnemyTank()
endfunction
function Filter_IsAllyAirTank takes nothing returns boolean
return Filter_IsAirTank() and Filter_AllyTank()
endfunction
function Filter_IsEnemyGroundTank takes nothing returns boolean
return Filter_IsGroundTank() and Filter_EnemyTank()
endfunction
function Filter_IsAllyGroundTank takes nothing returns boolean
return Filter_IsGroundTank() and Filter_AllyTank()
endfunction
function Filter_IsEnemyTankOrBuilding takes nothing returns boolean
return Filter_EnemyUnits() and (Filter_IsAnyStructure() or Filter_IsAnyTank())
endfunction
// Specific units functions
private function Filter_IsBeacon takes nothing returns boolean
return Filter_IsValidTarget() and (GetUnitTypeId(GetFilterUnit()) == 'o003')
endfunction
private function Filter_IsHyperSpaceBreaker takes nothing returns boolean
return Filter_IsAlive() and Filter_IsEnemy() and (GetUnitTypeId(GetFilterUnit()) == 'o002')
endfunction
// This is the check that is used for cp-capturing, handle with care
private function Filter_IsTowerOrHero takes nothing returns boolean
local integer Id = GetUnitTypeId(GetFilterUnit())
// isn't using the 'IsAnyHero' check, because here, invulnerable targets are also allowed
return Filter_IsAlive() and (IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO) or IsForceTower(GetFilterUnit()))
endfunction
private function Filter_IsEnemyTowerOrHero takes nothing returns boolean
return Filter_IsTowerOrHero() and Filter_IsEnemy()
endfunction
private function Filter_IsTowerRuin takes nothing returns boolean
return Filter_IsAlive() and (GetUnitTypeId(GetFilterUnit())=='h00Q')
endfunction
private function Filter_IsCP takes nothing returns boolean
return (GetUnitTypeId(GetFilterUnit()) == 'h00P')
endfunction
private function Filter_IsCPOrPlayerFactory takes nothing returns boolean
local unit U = GetFilterUnit()
local integer Id = GetUnitTypeId(U)
if Filter_IsCP() then
set U = null
return true
elseif GetUnitState(U, UNIT_STATE_LIFE) <= 0 or (Id != 'h002' and Id != 'h015') then
set U = null
return false
endif
set Id = GetPlayerNr(GetOwningPlayer(U))
set U = null
return Id <= GetMaxHumanPlayers()
endfunction
private function Filter_IsRootedGuard takes nothing returns boolean
return Filter_IsAlive() and ((GetUnitTypeId(GetFilterUnit()) == 'H013') and (GetUnitAbilityLevel(GetFilterUnit(),'A0CH') >= 1))
endfunction
private function Filter_IsEnemyFactory takes nothing returns boolean
local integer Id = GetUnitTypeId(GetFilterUnit())
//Check if the unit is a factory or TCC
return Filter_IsEnemy() and ((Id=='h01Z') or (Id=='h015') or (Id=='h01K'))
endfunction
private function Filter_IsMine takes nothing returns boolean
return IsMine( GetFilterUnit() ) and (GetUnitState( GetFilterUnit() , UNIT_STATE_LIFE ) > 0)
endfunction
private function Filter_IsCPTPGlow takes nothing returns boolean
return (GetUnitTypeId(GetFilterUnit()) == 'h01X')
endfunction
private function Filter_IsValidCPTPTarget takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_TOWNHALL)==true and Filter_IsAlive() and Filter_IsAlly()
endfunction
private function Filter_IsValidCPTPSource takes nothing returns boolean
// It is not allowed to port from a beacon
return Filter_IsValidCPTPTarget() and not Filter_IsBeacon()
endfunction
private function Filter_IsDecoy takes nothing returns boolean
return IsDecoy(GetFilterUnit())
endfunction
private function Filter_IsKineticShield takes nothing returns boolean
return (GetUnitTypeId(GetFilterUnit()) == KINETIC_SHIELD_ID)
endfunction
globals
// This varialble is used to set from which "point of view" we want to enumerate the units,
// required for ALLIED or ENEMY filters.
player udg_Filter_Player
boolexpr FILTER_NULL
boolexpr FILTER_ALIVE
boolexpr FILTER_VALID_TARGET
boolexpr FILTER_ALLY // Requires udg_Filter_Player
boolexpr FILTER_ENEMY // Requires udg_Filter_Player
boolexpr FILTER_ANY_TANK
boolexpr FILTER_ALLY_TANK // Requires udg_Filter_Player
boolexpr FILTER_ENEMY_TANK // Requires udg_Filter_Player
boolexpr FILTER_ANY_STRUCTURE
boolexpr FILTER_ANY_CREEP
boolexpr FILTER_ALLY_CREEP // Requires udg_Filter_Player
boolexpr FILTER_ENEMY_CREEP // Requires udg_Filter_Player
boolexpr FILTER_ALLY_UNITS // Requires udg_Filter_Player
boolexpr FILTER_ENEMY_UNITS // Requires udg_Filter_Player
boolexpr FILTER_VISIBLE_ENEMY_UNITS // Requires udg_Filter_Player
boolexpr FILTER_ENEMY_NONSTRUCTURE // Requires udg_Filter_Player
boolexpr FILTER_AIR_UNIT
boolexpr FILTER_GROUND_UNIT
boolexpr FILTER_ALLY_GROUND_UNIT // Requires udg_Filter_Player
boolexpr FILTER_ENEMY_GROUND_UNIT // Requires udg_Filter_Player
boolexpr FILTER_ALLY_AIR_UNIT // Requires udg_Filter_Player
boolexpr FILTER_ENEMY_AIR_UNIT // Requires udg_Filter_Player
boolexpr FILTER_AIR_TANK
boolexpr FILTER_GROUND_TANK
boolexpr FILTER_ENEMY_AIR_TANK // Requires udg_Filter_Player
boolexpr FILTER_ALLY_AIR_TANK // Requires udg_Filter_Player
boolexpr FILTER_ENEMY_GROUND_TANK // Requires udg_Filter_Player
boolexpr FILTER_ALLY_GROUND_TANK // Requires udg_Filter_Player
boolexpr FILTER_ANY_TOWER
boolexpr FILTER_BEACON
boolexpr FILTER_ENEMY_HYPERSPACE_BREAKER // Requires udg_Filter_Player
boolexpr FILTER_TOWER_OR_HERO
boolexpr FILTER_ENEMY_TOWER_OR_HERO // Requires udg_Filter_Player
boolexpr FILTER_ENEMY_BUILDING_OR_TANK // Requires udg_Filter_Player
boolexpr FILTER_TOWER_RUIN
boolexpr FILTER_CP
boolexpr FILTER_CP_OR_PLAYER_FACTORY
boolexpr FILTER_ROOTED_GUARD
boolexpr FILTER_ENEMY_FACTORY // Requires udg_Filter_Player
boolexpr FILTER_MINE
boolexpr FILTER_CPTPGLOW
boolexpr FILTER_VALID_CPTP_TARGET // Requires udg_Filter_Player
boolexpr FILTER_VALID_CPTP_SOURCE // Requires udg_Filter_Player
boolexpr FILTER_AOE_EXPLOSIVE_TARGET
boolexpr FILTER_DECOY
boolexpr FILTER_KINETIC_SHIELD
endglobals
private function Init takes nothing returns nothing
// This is a function that should be called at the very beginning.
set FILTER_NULL = Filter( function Filter_AntiLeak )
set FILTER_ALIVE = Filter( function Filter_IsAlive )
set FILTER_VALID_TARGET = Filter( function Filter_IsValidTarget )
set FILTER_ALLY = Filter( function Filter_IsAlly )
set FILTER_ENEMY = Filter( function Filter_IsEnemy )
set FILTER_ANY_TANK = Filter( function Filter_IsAnyTank )
set FILTER_ALLY_TANK = Filter( function Filter_AllyTank )
set FILTER_ENEMY_TANK = Filter( function Filter_EnemyTank )
set FILTER_ANY_CREEP = Filter( function Filter_IsAnyCreep )
set FILTER_ENEMY_CREEP = Filter( function Filter_EnemyCreeps )
set FILTER_ALLY_CREEP = Filter( function Filter_AllyCreeps )
set FILTER_ALLY_UNITS = Filter( function Filter_AllyUnits )
set FILTER_ENEMY_UNITS = Filter( function Filter_EnemyUnits )
set FILTER_VISIBLE_ENEMY_UNITS = Filter( function Filter_VisibleEnemyUnits )
set FILTER_ENEMY_NONSTRUCTURE = Filter( function Filter_Enemy_NonStructure )
set FILTER_AIR_UNIT = Filter( function Filter_IsAirUnit )
set FILTER_GROUND_UNIT = Filter( function Filter_IsGroundUnit )
set FILTER_AIR_TANK = Filter( function Filter_IsAirTank )
set FILTER_GROUND_TANK = Filter( function Filter_IsGroundTank )
set FILTER_ALLY_GROUND_UNIT = Filter( function Filter_IsAllyGroundUnit )
set FILTER_ENEMY_GROUND_UNIT = Filter( function Filter_IsEnemyGroundUnit )
set FILTER_ALLY_AIR_UNIT = Filter( function Filter_IsAllyAirUnit )
set FILTER_ENEMY_AIR_UNIT = Filter( function Filter_IsEnemyAirUnit )
set FILTER_ENEMY_AIR_TANK = Filter( function Filter_IsEnemyAirTank )
set FILTER_ALLY_AIR_TANK = Filter( function Filter_IsAllyAirTank )
set FILTER_ENEMY_GROUND_TANK = Filter( function Filter_IsEnemyGroundTank )
set FILTER_ALLY_GROUND_TANK = Filter( function Filter_IsAllyGroundTank )
set FILTER_BEACON = Filter( function Filter_IsBeacon )
set FILTER_ENEMY_HYPERSPACE_BREAKER = Filter( function Filter_IsHyperSpaceBreaker )
set FILTER_TOWER_OR_HERO = Filter( function Filter_IsTowerOrHero )
set FILTER_ENEMY_TOWER_OR_HERO = Filter( function Filter_IsEnemyTowerOrHero )
set FILTER_ENEMY_BUILDING_OR_TANK = Filter( function Filter_IsEnemyTankOrBuilding )
set FILTER_TOWER_RUIN = Filter( function Filter_IsTowerRuin )
set FILTER_ROOTED_GUARD = Filter( function Filter_IsRootedGuard )
set FILTER_CP = Filter( function Filter_IsCP )
set FILTER_CP_OR_PLAYER_FACTORY = Filter( function Filter_IsCPOrPlayerFactory )
set FILTER_ANY_TOWER = Filter( function Filter_IsAnyTower )
set FILTER_ENEMY_FACTORY = Filter( function Filter_IsEnemyFactory )
set FILTER_MINE = Filter( function Filter_IsMine )
set FILTER_CPTPGLOW = Filter( function Filter_IsCPTPGlow )
set FILTER_VALID_CPTP_TARGET = Filter( function Filter_IsValidCPTPTarget )
set FILTER_VALID_CPTP_SOURCE = Filter( function Filter_IsValidCPTPSource )
set FILTER_DECOY = Filter( function Filter_IsDecoy )
set FILTER_KINETIC_SHIELD = Filter( function Filter_IsKineticShield )
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library ProjectileSystem requires BTFramework, TimerAndAttachments
globals
constant real PROJECTILE_MOVE_INTERVAL = 0.03
endglobals
function interface ProjLooperFunction takes ProjectileMover pr returns boolean
function interface ProjDestructorFunction takes ProjectileMover pr returns nothing
struct ProjectileMover
real TargetX
real TargetY
real TargetZ
real ProjectileZ
unit Source
unit Target
unit Projectile
boolean FollowTarget
real DistanceToTarget
real Speed
real Arc
integer TimerIndex
ProjDestructorFunction ProjDestructor
ProjLooperFunction ProjLooper
static method Loop takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer tindex = GetHandleIndex(t)
local ProjectileMover pr = udg_AV_Int1[tindex]
local real DistanceLeft
local real DistX
local real DistY
local real TotalDistance
local real LastHeight = pr.ProjectileZ
local real AccelerationZ
local real VelocityZ
local boolean end
if (pr.Target != null) then
set pr.TargetX = GetUnitX(pr.Target)
set pr.TargetY = GetUnitY(pr.Target)
set pr.TargetZ = GetUnitZ(pr.Target)
endif
set DistX = pr.TargetX - GetUnitX(pr.Projectile)
set DistY = pr.TargetY - GetUnitY(pr.Projectile)
set TotalDistance = SquareRoot(Pow(pr.TargetX - GetUnitX(pr.Source), 2) + Pow(pr.TargetY - GetUnitY(pr.Source), 2))
set DistanceLeft = SquareRoot(DistX * DistX + DistY * DistY)
set pr.DistanceToTarget = DistanceLeft
set end = pr.ProjLooper.evaluate(pr)
if end then
call pr.ProjDestructor.evaluate(pr)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(tindex)
set pr.Target = null
set pr.Projectile = null
set pr.Source = null
call pr.destroy()
else
set AccelerationZ = 8*pr.Arc*pr.Speed*pr.Speed/TotalDistance
set VelocityZ = AccelerationZ * (DistanceLeft/pr.Speed)/2 + pr.Speed * (pr.TargetZ-RMaxBJ(LastHeight,50))/DistanceLeft
set VelocityZ = VelocityZ + AccelerationZ
call SetUnitX(pr.Projectile, GetUnitX(pr.Projectile) + pr.Speed * DistX / DistanceLeft)
call SetUnitY(pr.Projectile, GetUnitY(pr.Projectile) + pr.Speed * DistY / DistanceLeft)
call SetUnitFlyHeight(pr.Projectile, RMaxBJ(GetUnitFlyHeight(pr.Projectile)+LastHeight,50) + VelocityZ - GetUnitZ(pr.Projectile), 0)
// the stop command makes sure, that the projectile does not turn around itself (which would happen from time to time)
call IssueImmediateOrder(pr.Projectile, "stop")
call SetUnitAnimationByIndex(pr.Projectile, R2I(bj_RADTODEG * Atan2(VelocityZ, pr.Speed) + 0.5) + 90)
set pr.ProjectileZ = R2I(GetUnitZ(pr.Projectile))
endif
endmethod
method Initialize takes real Speed, real Arc, ProjLooperFunction Looper, ProjDestructorFunction Destructor returns nothing
set this.Speed = Speed * PROJECTILE_MOVE_INTERVAL
set this.Arc = Arc
set this.ProjLooper = Looper
set this.ProjDestructor = Destructor
endmethod
static method Create takes unit Source, unit Projectile, unit Target, real TargetX, real TargetY returns ProjectileMover
local ProjectileMover pr = ProjectileMover.allocate()
local timer t
local integer tindex
set pr.Source = Source
set pr.Projectile = Projectile
set t = NewTimer()
set pr.TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[pr.TimerIndex] = pr
set pr.ProjectileZ = R2I(GetUnitZ(Projectile))
if (Target == null) then
set pr.FollowTarget = false
set pr.TargetX = TargetX
set pr.TargetY = TargetY
set pr.TargetZ = 0
else
set pr.FollowTarget = true
set pr.Target = Target
set pr.TargetZ = R2I(GetUnitZ(Target))
endif
call TimerStart(t , PROJECTILE_MOVE_INTERVAL , true , function ProjectileMover.Loop)
return pr
endmethod
endstruct
endlibrary
//TESH.scrollpos=87
//TESH.alwaysfold=0
library Teleports requires TimerAndAttachments, MapAttachedSettings
function RectDistToCoords takes rect r, real X, real Y returns real
local real dx1 = GetRectMinX(r)-X
local real dx2 = X-GetRectMaxX(r)
local real dy1 = GetRectMinY(r)-Y
local real dy2 = Y-GetRectMaxY(r)
if dx2>dx1 then
set dx1=dx2
endif
if dy2>dy1 then
set dy1=dy2
endif
if dx1<0.0 then
if dy1<0.0 then
return 0.0
else
return dy1
endif
elseif dy1<0.0 then
return dx1
endif
return SquareRoot(dx1*dx1+dy1*dy1)
endfunction
function RectMoveLocationInside takes rect r, location loc, real tolerance returns nothing
// tolerance describes the maximum distance to each border.
// if tolerance is negative, the location will always be inside the rect.
local real x = GetLocationX(loc)
local real y = GetLocationY(loc)
if x<GetRectMinX(r)-tolerance then
set x = GetRectMinX(r)-tolerance
elseif x>GetRectMaxX(r)+tolerance then
set x = GetRectMaxX(r)+tolerance
endif
if y<GetRectMinY(r)-tolerance then
set y = GetRectMinY(r)-tolerance
elseif y>GetRectMaxY(r)+tolerance then
set y = GetRectMaxY(r)+tolerance
endif
call MoveLocation(loc,x,y)
endfunction
function Get_CP_Teleport_Msg_DistToBase takes real X, real Y, integer team returns real
if team==1 then
return RectDistToCoords(gg_rct_Team_1_Base_Main, X, Y)
endif
return RectDistToCoords(gg_rct_Team_2_Base_Main, X, Y)
endfunction
function Get_CP_Teleport_Msg_MoveLocInBase takes location loc, integer team, real tolerance returns nothing
if team==1 then
call RectMoveLocationInside(gg_rct_Team_1_Base_Main, loc, tolerance)
else
call RectMoveLocationInside(gg_rct_Team_2_Base_Main, loc, tolerance)
endif
endfunction
function Get_CP_Teleport_Msg_CoordsInBase takes real X, real Y, unit Tank returns boolean
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(Tank))] == 1 then
return RectContainsCoords(gg_rct_Team_1_Base_Main, X, Y)
endif
return RectContainsCoords(gg_rct_Team_2_Base_Main, X, Y)
endfunction
// Used by the CP-Teleport, lets you choose a target even out of the normal teleport range
// and moves the location you teleport to, into the range of the CP
function MoveTargetLocInRange takes unit Tank, location targetLoc returns nothing
local group G = NewGroup()
local unit U
local real X = GetLocationX(targetLoc)
local real Y = GetLocationY(targetLoc)
local real DistX
local real DistY
local real DistXY
set tempControlPoint = null
set udg_Filter_Player = GetOwningPlayer(Tank)
call GroupEnumUnitsInRange(G, X, Y, 2500, FILTER_VALID_CPTP_TARGET)
set U = GetClosestUnitFromGroup(G, X, Y)
if U != null and not Get_CP_Teleport_Msg_CoordsInBase( X, Y, Tank) then
set DistX = X - GetUnitX(U)
set DistY = Y - GetUnitY(U)
set DistXY = SquareRoot(DistX*DistX+DistY*DistY)
if (DistXY > 450) then
call MoveLocation(targetLoc, GetUnitX(U)+DistX*400/DistXY, GetUnitY(U)+DistY*400/DistXY)
endif
endif
call ReleaseGroup(G)
set G = null
set tempControlPoint = U
set U = null
endfunction
//Returns true, when the target is a valid CPTP target and there is a Teleport Beacon nearby
function IsFreeTeleport takes unit Tank, location target returns boolean
local group g = NewGroup()
local boolean FreeTeleport = false
local unit CP
set udg_Filter_Player = GetOwningPlayer(Tank)
call GroupEnumUnitsInRange(g, GetLocationX(target), GetLocationY(target), 500, FILTER_VALID_CPTP_SOURCE)
set CP = FirstOfGroup(g)
if (CP != null) then
call GroupEnumUnitsInRange(g, GetUnitX(CP), GetUnitY(CP), 500, FILTER_BEACON)
set FreeTeleport = (FirstOfGroup(g) != null)
else
call GroupEnumUnitsInRange(g, GetLocationX(target), GetLocationY(target), 500, FILTER_BEACON)
set CP = FirstOfGroup(g)
if (CP != null) then
call GroupEnumUnitsInRange(g, GetUnitX(CP), GetUnitY(CP), 500, FILTER_VALID_CPTP_SOURCE)
set FreeTeleport = (FirstOfGroup(g) != null)
endif
endif
call ReleaseGroup(g)
set g = null
set CP = null
return FreeTeleport
endfunction
function Get_CP_Teleport_Msg takes unit Tank, real X, real Y returns string
local string Error = null
local group G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(Tank)
call GroupEnumUnitsInRange(G, GetUnitX(Tank), GetUnitY(Tank), 500, FILTER_VALID_CPTP_SOURCE)
if FirstOfGroup(G) == null and not Get_CP_Teleport_Msg_CoordsInBase( GetUnitX(Tank), GetUnitY(Tank), Tank ) then
set Error = "|cfffed312You have to be next to a Control Point.|r"
else
call GroupClear( G )
call GroupEnumUnitsInRange(G, X, Y, 450, FILTER_VALID_CPTP_TARGET)
if FirstOfGroup(G) == null and not Get_CP_Teleport_Msg_CoordsInBase( X, Y, Tank) then
set Error = "|cfffed312The target has to be next to a Control Point.|r"
else
call GroupClear( G )
endif
endif
call ReleaseGroup(G)
set G = null
return Error
endfunction
function CheckHyperSpaceBreaker takes unit Tank returns nothing
// Should be called after every teleport
local unit dummy
local unit Breaker
local real X
local real Y
local group G = NewGroup()
// SleepAction is important: give the unit time to actually teleport to the target location and the ability to go into cooldown
//call TriggerSleepAction(0)
set udg_Filter_Player = GetOwningPlayer(Tank)
call GroupEnumUnitsInRange(G, GetUnitX(Tank),GetUnitY(Tank),1300,FILTER_ENEMY_HYPERSPACE_BREAKER)
set Breaker = FirstOfGroup( G )
if Breaker != null then
set X = GetUnitX(Breaker)
set Y = GetUnitY(Breaker)
call SetUnitPosition(Tank, X,Y)
set dummy = CreateUnit(GetOwningPlayer(Breaker), DUMMY_ID, X,Y, 270)
call UnitAddAbility(dummy, 'A06K')
call IssueTargetOrder(dummy, "thunderbolt", Tank)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Orc\\LightningBolt\\LightningBoltMissile.mdl", Tank, "origin"))
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl", X, Y ) )
call UnitDamageTarget(dummy, Tank, GetUnitState(Tank, UNIT_STATE_LIFE)/4, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
set dummy = null
set Breaker = null
else
call GroupClear( G )
endif
call ReleaseGroup(G)
set G = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Trace
// Add calls to this function to see a stack trace in the traced version
// the implementation is automatically done by the script
function Trace_Print takes nothing returns nothing
endfunction
endlibrary
//TESH.scrollpos=55
//TESH.alwaysfold=0
library ArmorUtils requires Logarithm, DamageDetection
//******************************************************************************
//* BY: Rising_Dusk
//* http://www.wc3c.net/showthread.php?t=105849
//*
//* This is used to get the exact armor of a given unit. It deals damage to the
//* unit in order to determine armor, meaning that damage detection systems will
//* detect it. If your map has the Intuitive Damage Detection System (IDDS) in
//* it, it will use that system's internal ignored damage type for the check.
//* Using that removes the need to disable/enable any damage detection triggers
//* to avoid infinite loops.
//*
//* The attacktype constant, ATTACK_TYPE_USED, is by default set to use
//* ATTACK_TYPE_CHAOS. Chaos is used because it deals 100% to all types, so if
//* you change it in your map, make sure you update the constant to some type
//* with 100% damage to all armor types.
//*
//* This system can also be used as a means to detect if a unit is invulnerable
//* or not. If GetUnitArmor returns ARMOR_INVULNERABLE, then the unit is
//* invulnerable. The value for it is entirely random and will never be the
//* actual armor value for a unit, so there should be no conflicts.
//*
//* Damage reduction in WC3 due to negative armor is capped at -71%, which has
//* an equivalent armor value of -20. If you have a unit with less than -20
//* armor, this system will always return exactly -20.
//*
//* Default WC3 gameplay constants have the 'Armor Damage Reduction Multiplier'
//* set to 0.06. If you change this constant for your map, be sure to adjust the
//* ARMOR_REDUCTION_MULTIPLIER constant in this script to match.
//*
//* Example Usage:
//* local real armor = GetUnitArmor(MyUnit)
//*
//* Two other functions are included in this library. They are used for
//* calculating a unit's base damage knowing armor-factoring damage and a unit's
//* armor-factoring damage knowing its base damage. These functions do not
//* consider armor type in their calculations. If you want armor type damage
//* adjusting, it is recommended to trigger it.
//*
//* Example Usage:
//* local real basedmg = GetFullDamage(MyUnit, Armor)
//* local real armodmg = GetReducedDamage(MyUnit, Armor)
//*
//* An objectmerger call is included in this script to automatically generate
//* the bonus life ability if necessary. If you do not modify the 'AIlz' ability
//* in your map, you can replace the LIFE_BONUS_SPELL_ID constant with it and
//* not use the objectmerger call. The
//*
globals
//Values that should be changed for your map
private constant real ARMOR_REDUCTION_MULTIPLIER = 0.07
private constant integer LIFE_BONUS_SPELL_ID = 'A0C9' // the same that is used for triggered block / healing
private constant attacktype ATTACK_TYPE_USED = ATTACK_TYPE_CHAOS
//Values that do not need to be changed
constant real ARMOR_INVULNERABLE = 917451.519
private constant real DAMAGE_TEST = 25.
private constant real DAMAGE_LIFE = 40.
private constant real NATLOG_094 =-0.061875
endglobals
function GetUnitArmor takes unit u returns real
local real life = GetWidgetLife(u)
local real test = life
local real redc = 0.
local integer block = GetUnitAbilityLevel(u, HEAVYARMOR_ABILITY_ID)
if u != null and life >= 0.405 then
if GetUnitState(u, UNIT_STATE_MAX_LIFE) <= DAMAGE_TEST then
//Add max life to keep it alive
call UnitAddAbility(u, LIFE_BONUS_SPELL_ID)
endif
if life <= DAMAGE_LIFE then
//If under the threshold, heal it for the moment
call SetWidgetLife(u, DAMAGE_LIFE)
set test = DAMAGE_LIFE
endif
// temporarily remove any skill that reduces the physical damage (damage block etc)
call SetPlayerAbilityAvailable(GetOwningPlayer(u), HEAVYARMOR_ABILITY_ID, false)
call PauseSkillDamageDetection(true)
call UnitDamageTarget(u, u, DAMAGE_TEST, true, false, ATTACK_TYPE_USED, DAMAGE_TYPE_NORMAL, null)
call PauseSkillDamageDetection(false)
// enable skills again
call SetPlayerAbilityAvailable(GetOwningPlayer(u), HEAVYARMOR_ABILITY_ID, true)
set redc = (DAMAGE_TEST-test+GetWidgetLife(u))/DAMAGE_TEST
//Remove the max life ability
call UnitRemoveAbility(u, LIFE_BONUS_SPELL_ID)
call SetWidgetLife(u, life)
if redc >= 1. then
//Invulnerable
return ARMOR_INVULNERABLE
elseif redc < 0. then
//Negative Armor
return -Log(redc+1.)/NATLOG_094
else
//Positive Armor
return redc/(ARMOR_REDUCTION_MULTIPLIER*(1.-redc))
endif
endif
return 0.
endfunction
function GetReducedDamage takes real baseDamage, real armor returns real
if armor >= 0. then
return baseDamage*(1.-((armor*ARMOR_REDUCTION_MULTIPLIER)/(1.+ARMOR_REDUCTION_MULTIPLIER*armor)))
else
return baseDamage*(2.-Pow(0.94,-armor))
endif
endfunction
function GetFullDamage takes real damage, real armor returns real
if armor >= 0. then
return damage/(1.-((armor*ARMOR_REDUCTION_MULTIPLIER)/(1.+ARMOR_REDUCTION_MULTIPLIER*armor)))
else
return damage/(2.-Pow(0.94,-armor))
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library xedummy initializer init requires BTFramework
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
// use the dummy.mdx model, so remember to import it as
// well, just use copy&paste to copy the dummy from the
// xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
// this rawcode to another spell that morphs into a flier
// in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
// raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
// timer that depends on it, if you put a low value
// the movement will look good but it may hurt your
// performance, if instead you use a high value it
// will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
// you got a unit bigger than 197.0 it would be
// a good idea to update this constant, since some
// enums will not find it. Likewise, if none of
// your units can go bellow X and X is much smaller
// than 197.0, it would be a good idea to update
// as well, since it will improve the performance
// those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************
//===========================================================================
globals
constant integer XE_DUMMY_UNITID = 'h022'
constant integer XE_HEIGHT_ENABLER = 'Amrf'
constant integer XE_TREE_RECOGNITION = 'Aeat'
constant real XE_ANIMATION_PERIOD = 0.025
constant real XE_MAX_COLLISION_SIZE = 72.0
endglobals
// 'globals' that are only used within this library
globals
// The number of different angles at which the dummy units will be stored.
private constant integer ANGLE_RESOLUTION = 12
// The total number of xe dummy units that will be preloaded on map initialization.
private constant integer INITIAL_DUMMY_COUNT = 36
// Don't allow to keep more than DUMMY_STACK_LIMIT inactive dummy units.
private constant integer DUMMY_STACK_LIMIT = 240
//Delay in order to show the death animation of the effect correctly when xefx is destroyed.
//You may need to increase this if you are using effects with longer death animations.
private constant real MIN_RECYCLE_DELAY = 5.0
//The delay does not need to be exact so we do cleanup in batches instead of individually.
//This determines how often the recycler runs, should be less than MIN_RECYCLE_DELAY.
private constant real RECYCLE_INTERVAL = 0.5
//if this is true and the xedummy library is present, units will be recycled instead of removed.
private constant boolean RECYCLE_DUMMY_UNITS = true
private timer recycler
endglobals
private keyword xedummy
private struct recycleQueue extends array
recycleQueue next
recycleQueue prev
real angle
integer size
xedummy first
xedummy last
static method onInit takes nothing returns nothing
local integer i=0
loop
exitwhen i==ANGLE_RESOLUTION
set i=i+1
set recycleQueue(i).prev=recycleQueue(i-1)
set recycleQueue(i).next=recycleQueue(i+1)
set recycleQueue(i).angle=(i-0.5)*(360.0/ANGLE_RESOLUTION)
endloop
set recycleQueue(1).prev=recycleQueue(i)
set recycleQueue(i).next=recycleQueue(1)
endmethod
static method get takes real angle returns recycleQueue
return recycleQueue(R2I(angle/360.0*ANGLE_RESOLUTION)+1)
endmethod
endstruct
// ================================================================
struct xedummy
private static group g=CreateGroup()
private unit u
// ----------------------------------------------------------------
private xedummy next
private method queueInsert takes recycleQueue q returns nothing
call SetUnitFacing(.u, q.angle)
if q.size==0 then
set q.first=this
else
set q.last.next=this
endif
set q.last=this
set .next=0
// Recursively check adajcent queues and migrate xedummies as needed.
if q.size>q.next.size then
set this=q.first
set q.first=.next
call .queueInsert(q.next)
elseif q.size>q.prev.size then
set this=q.first
set q.first=.next
call .queueInsert(q.prev)
else
set q.size=q.size+1
endif
endmethod
private static method queueRemove takes recycleQueue q returns xedummy
// Recursively check adajcent queues and migrate xedummies as needed.
local xedummy this
if q.size<q.next.size then
set this=q.last
set q.last=.queueRemove(q.next)
set .next=q.last
call SetUnitFacing(q.last.u, q.angle)
elseif q.size<q.prev.size then
set this=q.last
set q.last=.queueRemove(q.prev)
set .next=q.last
call SetUnitFacing(q.last.u, q.angle)
else
set q.size=q.size-1
if q.size==0 then
set q.last=0
endif
endif
set this=q.first
set q.first=.next
set .next=0
return this
endmethod
// ----------------------------------------------------------------
private static method create takes unit u returns xedummy
local xedummy this
if GetUnitTypeId(u)!=XE_DUMMY_UNITID then
call DebugMsg("ReleaseXEDummy error: Method called on a unit of an incorrect type (" + GetName(u) + ")")
elseif IsUnitInGroup(u, .g) then
call DebugMsg("ReleaseXEDummy error: Method called on an already released unit.")
else
set this=.allocate()
if integer(this)>DUMMY_STACK_LIMIT then
call RemoveUnit(u)
call .deallocate()
return 0
endif
set .u=u
call UnitRemoveAbility(u,GetUnitUserData(u))
call GroupAddUnit(.g, u)
call .queueInsert(recycleQueue.get(GetUnitFacing(u)))
call SetUnitAnimationByIndex(u, 90)
call SetUnitScale(u, 1, 0, 0)
call SetUnitVertexColor(u, 255, 255, 255, 255)
//call ShowUnit(u, false) // Do not hide the unit, it is rather costly and not needed.
return this
endif
return 0
endmethod
private method destroy takes nothing returns nothing
call GroupRemoveUnit(.g, .u)
call ShowUnit(.u, true) // Show the unit in case it was hidden before being recycled.
set .u=null
call .deallocate()
endmethod
// ----------------------------------------------------------------
private static unit dummy
private static method onInit takes nothing returns nothing
local integer i=INITIAL_DUMMY_COUNT
local recycleQueue q=recycleQueue(1)
if i>DUMMY_STACK_LIMIT then
call DebugMsg("xedummy error: INITIAL_DUMMY_COUNT can not be larger than DUMMY_STACK_LIMIT.")
set i=DUMMY_STACK_LIMIT
endif
loop
exitwhen i==0
set .dummy = CreateUnit(Player(15), XE_DUMMY_UNITID, 0.0,0.0,q.angle)
call UnitAddAbility(.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(.dummy,'Aloc')
call UnitRemoveAbility(.dummy,XE_HEIGHT_ENABLER)
call .create(.dummy)
set i=i-1
set q=q.next
endloop
endmethod
// ----------------------------------------------------------------
static method new takes player p, real x, real y, real face returns unit
local recycleQueue q
local xedummy this
loop
exitwhen face>0.0
set face=face+360.0
endloop
loop
exitwhen face<360.0
set face=face-360.0
endloop
set q=recycleQueue.get(face)
if q.size==0 then
set .dummy = CreateUnit(p, XE_DUMMY_UNITID, x,y,face)
call UnitAddAbility(.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(.dummy,'Aloc')
call UnitRemoveAbility(.dummy,XE_HEIGHT_ENABLER)
call SetUnitPathing(.dummy, false)
call SetUnitX(.dummy, x)
call SetUnitY(.dummy, y)
else
set this=.queueRemove(q)
set .dummy=.u
call .destroy()
call SetUnitX(.dummy, x)
call SetUnitY(.dummy, y)
call SetUnitFacing(.dummy, face)
call SetUnitOwner(.dummy, p, true)
endif
return .dummy
endmethod
static method release takes unit u returns nothing
call .create(u)
endmethod
endstruct
// ================================================================
function XE_NewDummyUnit takes player p, real x, real y, real face returns unit
return xedummy.new( p,x,y,face )
endfunction
function XE_ReleaseDummyUnit takes unit u returns nothing
call xedummy.release( u )
endfunction
private struct recyclebin
unit u
private recyclebin next=0
private static recyclebin array list
private static integer readindex=1
private static integer writeindex=0
private static integer count=0
static method Recycle takes nothing returns nothing
local recyclebin this = .list[readindex]
loop
exitwhen this==0
static if RECYCLE_DUMMY_UNITS then
call XE_ReleaseDummyUnit(this.u)
else
call RemoveUnit(this.u)
endif
set this.u=null
set .count=.count-1
call this.destroy()
set this=this.next
endloop
set .list[readindex]=0
set .writeindex=.readindex
set .readindex=.readindex+1
if .readindex>R2I(MIN_RECYCLE_DELAY/RECYCLE_INTERVAL+1.0) then
set .readindex=0
endif
if count!=0 then
call TimerStart(recycler, RECYCLE_INTERVAL, false, function recyclebin.Recycle)
endif
endmethod
static method create takes unit u returns recyclebin
local recyclebin this=recyclebin.allocate()
if GetUnitTypeId(u)!=XE_DUMMY_UNITID then
call DebugMsg("Recycle Dummy error: Method called on a unit of an incorrect type (" + GetName(u) + ")")
else
if .count==0 then
call TimerStart(recycler, RECYCLE_INTERVAL, false, function recyclebin.Recycle)
endif
set .count=.count+1
set .u=u
call SetUnitOwner(u,Player(15),false)
set .next=.list[.writeindex]
set .list[.writeindex]=this
return this
endif
return 0
endmethod
endstruct
private function init takes nothing returns nothing
set recycler=CreateTimer()
endfunction
//==================================================================================================================================
// Public functions
//==================================================================================================================================
function CreateDummyWithAbilityCoord takes player Owner, integer Ability, integer AbilityLevel, real X, real Y, real Z returns unit
set bj_lastCreatedUnit = XE_NewDummyUnit(Owner, X, Y, 270)
//set bj_lastCreatedUnit = CreateUnit(Owner, 'h022', X, Y, 270)
call SetUnitFlyHeight(bj_lastCreatedUnit, Z, 0)
call UnitAddAbility(bj_lastCreatedUnit, Ability)
call SetUnitAbilityLevel(bj_lastCreatedUnit, Ability, AbilityLevel)
call SetUnitUserData(bj_lastCreatedUnit,Ability)
return bj_lastCreatedUnit
endfunction
function CreateDummyWithAbility takes player Owner, integer Ability, integer AbilityLevel, location Loc, real Z returns unit
set bj_lastCreatedUnit = XE_NewDummyUnit(Owner, GetLocationX(Loc), GetLocationY(Loc), 270)
//set bj_lastCreatedUnit = CreateUnit(Owner, 'h022', GetLocationX(Loc), GetLocationY(Loc), 270)
call SetUnitFlyHeight(bj_lastCreatedUnit, Z, 0)
call UnitAddAbility(bj_lastCreatedUnit, Ability)
call SetUnitAbilityLevel(bj_lastCreatedUnit, Ability, AbilityLevel)
call SetUnitUserData(bj_lastCreatedUnit,Ability)
return bj_lastCreatedUnit
endfunction
function ReleaseDummy takes unit U returns nothing
call recyclebin.create(U)
//call RemoveUnit(U)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Logarithm
// by Vexorian
// http://www.wc3c.net/showthread.php?t=101346
globals
private constant integer ITERATIONS=20
endglobals
function Log takes real x returns real
local real min=-88.0
local real max= 88.0
local real mid
local integer i=ITERATIONS
loop
set mid=(min+max)/2
exitwhen(i<=0)
set i=i-1
if (Pow(bj_E,mid)>=x) then
set max=mid
else
set min=mid
endif
endloop
return mid
endfunction
function Logarithm takes real base, real x returns real
local real min=-88.0
local real max= 88.0
local real mid
local integer i=ITERATIONS
loop
set mid=(min+max)/2
exitwhen(i<=0)
set i=i-1
if (Pow(base,mid)>=x) then
set max=mid
else
set min=mid
endif
endloop
return mid
endfunction
endlibrary
//TESH.scrollpos=22
//TESH.alwaysfold=0
library TerrainPathability initializer Init requires BTFramework
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script can be used to detect the type of pathing at a specific point.
//* It is valuable to do it this way because the IsTerrainPathable is very
//* counterintuitive and returns in odd ways and aren't always as you would
//* expect. This library, however, facilitates detecting those things reliably
//* and easily.
//*
//******************************************************************************
//*
//* > function IsTerrainDeepWater takes real x, real y returns boolean
//* > function IsTerrainShallowWater takes real x, real y returns boolean
//* > function IsTerrainLand takes real x, real y returns boolean
//* > function IsTerrainPlatform takes real x, real y returns boolean
//* > function IsTerrainWalkable takes real x, real y returns boolean
//*
//* These functions return true if the given point is of the type specified
//* in the function's name and false if it is not. For the IsTerrainWalkable
//* function, the MAX_RANGE constant below is the maximum deviation range from
//* the supplied coordinates that will still return true.
//*
//* The IsTerrainPlatform works for any preplaced walkable destructable. It will
//* return true over bridges, destructable ramps, elevators, and invisible
//* platforms. Walkable destructables created at runtime do not create the same
//* pathing hole as preplaced ones do, so this will return false for them. All
//* other functions except IsTerrainWalkable return false for platforms, because
//* the platform itself erases their pathing when the map is saved.
//*
//* After calling IsTerrainWalkable(x, y), the following two global variables
//* gain meaning. They return the X and Y coordinates of the nearest walkable
//* point to the specified coordinates. These will only deviate from the
//* IsTerrainWalkable function arguments if the function returned false.
//*
//* Variables that can be used from the library:
//* [real] TerrainPathability_X
//* [real] TerrainPathability_Y
//*
globals
private constant real MAX_RANGE = 10.
constant integer DUMMY_ITEM_ID = 'wolg'
endglobals
globals
item Item = null
private rect Find = null
private item array Hid
unit array Dummy
private integer HidMax = 0
real Walkable_X = 0.
real Walkable_Y = 0.
endglobals
function IsTerrainDeepWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
function IsTerrainShallowWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
function IsTerrainLand takes real x, real y returns boolean
return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
endfunction
function IsTerrainPlatform takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
private function HideItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set Hid[HidMax] = GetEnumItem()
call SetItemVisible(Hid[HidMax], false)
set HidMax = HidMax + 1
endif
endfunction
//This function is faster than the unit based pathability detection, but has it's problems too
//This should mainly be used, when you just want to know, if the given point is pathable
//But points in trees are sometimes considered walkable, even if they aren't
function IsTerrainWalkable takes real x, real y returns boolean
//Hide any items in the area to avoid conflicts with our item
call MoveRectTo(Find, x, y)
call EnumItemsInRect(Find ,null, function HideItem)
if (Item == null) then
set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
endif
//Try to move the test item and get its coords
call SetItemPosition(Item, x, y) //Unhides the item
set Walkable_X = GetItemX(Item)
set Walkable_Y = GetItemY(Item)
call SetItemVisible(Item, false)//Hide it again
//Unhide any items hidden at the start
loop
exitwhen HidMax <= 0
set HidMax = HidMax - 1
call SetItemVisible(Hid[HidMax], true)
set Hid[HidMax] = null
endloop
//Return walkability
return ((Walkable_X-x)*(Walkable_X-x)+(Walkable_Y-y)*(Walkable_Y-y) <= MAX_RANGE*MAX_RANGE) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
//This function is slower, than IsTerrainWalkable (takes about twice as long)
//This should mainly be used, when you want to have a pathable position on or near the given location
//Positions on cliffs are often considered pathable by this function, even if they aren't
//That's why this function has been combined with the one above, to ensure you get a correct result
//Because of it's performance, this one should not be used in a repitative check (like every 0.05 seconds)
function GetPathableLoc takes location P, real Collision, real MaxRange returns boolean
local boolean PathableLocFound = true
local integer dummyNr = 0
local real X
local real Y
local real DistX
local real DistY
if (P == null) then
call BJDebugMsg("GetPathableLoc: null location")
return false
endif
if (Dummy[0] == null) or (GetUnitState(Dummy[0], UNIT_STATE_LIFE) <= 0) then
call BJDebugMsg("GetPathableLoc: null dummy")
endif
if Collision < 16 then
set dummyNr = 1
elseif Collision < 36 then
set dummyNr = 2
endif
//call DebugMsg("Pathing Dummy: " + I2S(dummyNr))
call ShowUnit(Dummy[dummyNr], true)
call SetUnitPositionLoc(Dummy[dummyNr], P)
set X = GetUnitX(Dummy[dummyNr])
set Y = GetUnitY(Dummy[dummyNr])
set DistX = X - GetLocationX(P)
set DistY = Y - GetLocationY(P)
if DistX*DistX+DistY*DistY > MaxRange*MaxRange then
set PathableLocFound = false
else
call MoveLocation(P, X, Y)
//normally, both units can't be on the same position -> if they are, both are on unpathable terrain
call ShowUnit(Dummy[0], true)
call SetUnitPositionLoc(Dummy[0], P)
if X==GetUnitX(Dummy[0]) and Y==GetUnitY(Dummy[0]) then
set PathableLocFound = false
endif
call ShowUnit(Dummy[0], false)
endif
call ShowUnit(Dummy[dummyNr], false)
return (PathableLocFound and IsTerrainWalkable(X, Y))
endfunction
private function Init takes nothing returns nothing
set Find = Rect(0., 0., 128., 128.)
set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
set Dummy[0] = CreateUnit(Player(15),'h016',0,0,0) // Collision: 12, used for proof check
set Dummy[1] = CreateUnit(Player(15),'h016',0,0,0) // Collision: 12
set Dummy[2] = CreateUnit(Player(15),'h00Z',0,0,0) // Collision: 32
call ShowUnit(Dummy[0], false)
call ShowUnit(Dummy[1], false)
call ShowUnit(Dummy[2], false)
call SetItemVisible(Item, false)
endfunction
endlibrary
//TESH.scrollpos=300
//TESH.alwaysfold=0
//! (c) Paladon
library PvJass requires Initilization, MapAttachedSettings
// -------------------------------------------------------------
//! Readme for Paladon's vJass Addon script
// not all added yet
// Pala.TimedUnitRemoval
// takes unit u, real time returns nothing
// PolarProjectionX
// takes real x, real dist, real angle returns real
// PolarProjectionY
// takes real y, real dist, real angle returns real
// GetAngle
// takes real x1, real y1, real x2, real y2 returns real
// GetUnitsAngle
// takes unit a, unit b returns real
// GetUnitsDistance
// takes unit a, unit b returns real
// GetXYDistance
// takes real x1, real y1,real x2,real y2 returns real
// pGetTerrainZ
// takes real x, real y returns real
// pSFX
// takes unit u, real x, real y, real size, string e returns nothing
// ---------------------------------------------------------------
globals
unit pDummy
unit tempUnit
effect pEffect
boolexpr pNull = null
player pPlayer
real pX
real pY
real pZ
private real array R
private location GL = Location(0,0)
//******************
real Timer = 0.01 // Every system is based on this value! Do NOT modify!
//******************
endglobals
function pGetTerrainZ takes real x, real y returns real
call MoveLocation(GL, x, y)
return GetLocationZ(GL)
endfunction
function pGetUnitXYZ takes unit u returns nothing
set pX = GetUnitX(u)
set pY = GetUnitY(u)
set pZ = GetUnitFlyHeight(u)
endfunction
struct Pala
private unit u
private unit t
private real x1
private real x2
private real y1
private real y2
private real z1
private real z2
private real t1
private real t2
private lightning light
private string order
private texttag tag
private static Pala array indx
private static integer counter = 0
private static timer time = CreateTimer()
static method TimeCount takes nothing returns nothing
local Pala d
local integer i = 0
loop
exitwhen i >= Pala.counter
set d = Pala.indx[i]
if d.order == "TimedUnitRemoval" then
if d.t1 >= d.t2 then
set d.order = null
call RemoveUnit(d.u)
set d.u = null
call d.destroy()
set Pala.counter = Pala.counter - 1
set Pala.indx[i] = d.indx[Pala.counter]
set i = i - 1
else
set d.t1 = d.t1 + Timer
endif
elseif d.order == "TimedLightning" then
set d.t1 = d.t1 + Timer
if d.t1 >= d.t2 then
set d.order = null
call DestroyLightning(d.light)
set d.light = null
set d.u = null
set d.t = null
call d.destroy()
set Pala.counter = Pala.counter - 1
set Pala.indx[i] = d.indx[Pala.counter]
set i = i - 1
else
call SetLightningColor(d.light,1,1,1,1-(d.t1/d.t2))
call pGetUnitXYZ(d.u)
call MoveLightningEx(d.light,true,pX,pY,pZ+pGetTerrainZ(pX,pY),GetUnitX(d.t),GetUnitY(d.t),GetUnitFlyHeight(d.t)+pGetTerrainZ(GetUnitX(d.t),GetUnitY(d.t)))
endif
elseif d.order == "StaticLightning" then
set d.t1 = d.t1 + Timer
if d.t1 >= d.t2 then
set d.order = null
call DestroyLightning(d.light)
set d.light = null
call d.destroy()
set Pala.counter = Pala.counter - 1
set Pala.indx[i] = d.indx[Pala.counter]
set i = i - 1
else
call SetLightningColor(d.light,1,1,1,1-(d.t1/d.t2))
call MoveLightningEx(d.light,true,d.x1,d.y1,d.z1,d.x2,d.y2,d.z2)
endif
elseif d.order == "FadeTextTag" then
set d.t1 = d.t1 + Timer
set d.z1 = d.z1 + d.z2
if d.t1 >= d.t2 then
set d.order = null
call SetTextTagColor(d.tag, 255, 255, 255, 255)
call SetTextTagVisibility(d.tag, false )
set d.tag = null
call d.destroy()
set Pala.counter = Pala.counter - 1
set Pala.indx[i] = d.indx[Pala.counter]
set i = i - 1
else
call SetTextTagColor(d.tag, 255, 255, 255, PercentTo255(100.-d.z1))
endif
endif
set i = i + 1
endloop
set i = 0
if Pala.counter == 0 then
call PauseTimer(Pala.time)
endif
endmethod
static method TimedUnitRemoval takes unit u, real ti returns nothing
local Pala d = Pala.allocate()
set d.u = u
set d.t1 = 0
set d.t2 = ti
set d.order = "TimedUnitRemoval"
if Pala.counter == 0 then
call TimerStart(Pala.time,Timer,true,function Pala.TimeCount)
endif
set Pala.indx[Pala.counter] = d
set Pala.counter = Pala.counter + 1
endmethod
static method TimedLightning takes unit u, unit u2, real ti, string lightid returns nothing
// "CLPB" = Chain Lightning Primary
local Pala d = Pala.allocate()
set d.u = u
set d.t = u2
set d.t1 = 0
set d.t2 = ti
call pGetUnitXYZ(u)
set d.light = AddLightningEx(lightid,true,pX,pY,pZ,GetUnitX(u2),GetUnitY(u2),GetUnitFlyHeight(u2))
set d.order = "TimedLightning"
if Pala.counter == 0 then
call TimerStart(Pala.time,Timer,true,function Pala.TimeCount)
endif
set Pala.indx[Pala.counter] = d
set Pala.counter = Pala.counter + 1
endmethod
static method StaticLightning takes real x1, real x2, real y1, real y2, real z1, real z2, real ti, string lightid returns nothing
local Pala d = Pala.allocate()
set d.x1 = x1
set d.x2 = x2
set d.y1 = y1
set d.y2 = y2
set d.z1 = z1
set d.z2 = z2
set d.t1 = 0
set d.t2 = ti
set d.light = AddLightningEx(lightid,true,x1,y1,z1,x2,y2,z2)
set d.order = "StaticLightning"
if Pala.counter == 0 then
call TimerStart(Pala.time,Timer,true,function Pala.TimeCount)
endif
set Pala.indx[Pala.counter] = d
set Pala.counter = Pala.counter + 1
endmethod
static method FadeTextTag takes real t, texttag text returns nothing
local Pala d = Pala.allocate()
set d.z1 = 0
set d.z2 = 100*Timer/t
set d.t1 = 0
set d.t2 = t
set d.tag = text
set d.order = "FadeText"
if Pala.counter == 0 then
call TimerStart(Pala.time,Timer,true,function Pala.TimeCount)
endif
set Pala.indx[Pala.counter] = d
set Pala.counter = Pala.counter + 1
endmethod
endstruct
function pSFX takes unit u, real x, real y, real size, string e returns nothing
call SetUnitPathing(u,false)
call SetUnitX(u,x)
call SetUnitY(u,y)
call SetUnitScale(u,size,size,size)
call DestroyEffect(AddSpecialEffectTarget(e,u,"chest"))
call Pala.TimedUnitRemoval(u,2.00)
endfunction
struct TS
private unit array pr[3]
private effect array eff[3]
private unit source
private unit target
private real speed
private real maxdis
private real sway
private real Z
private real tZ
private real oldX
private real oldY
private integer level
private static TS array indx
private static integer counter = 0
private static timer time = CreateTimer()
static method Looper takes nothing returns nothing
local TS d
local integer i = 0
local integer i2 = 0
local real angle
local real b
local real offset
local real HitHeight = 30.0
local real fz
local boolean targetTeleported = false
loop
exitwhen i >= TS.counter
set d = TS.indx[i]
set targetTeleported = GetXYDistance(GetUnitX(d.target), GetUnitY(d.target), d.oldX, d.oldY) > (1100 * Timer)
if (GetUnitsDistance(d.pr[1],d.target) <= 15.0) or (GetUnitState(d.target,UNIT_STATE_LIFE) <= 0.0) or targetTeleported then
call DestroyEffect(d.eff[0])
call DestroyEffect(d.eff[1])
call DestroyEffect(d.eff[2])
call Pala.TimedUnitRemoval(d.pr[0],3.0)
call Pala.TimedUnitRemoval(d.pr[1],3.0)
call Pala.TimedUnitRemoval(d.pr[2],3.0)
set d.source = null
set d.target = null
set d.pr[0] = null
set d.pr[1] = null
set d.pr[2] = null
call d.destroy()
set TS.counter = TS.counter - 1
set TS.indx[i] = d.indx[TS.counter]
set i = i - 1
elseif d.source != null then
set angle = GetUnitsAngleDeg(d.pr[1],d.target)* bj_DEGTORAD
set b = (d.speed+GetUnitsDistance(d.target,d.pr[1]))/d.maxdis
set offset = Sin(3.14159*b) * d.sway * d.maxdis
set fz = d.Z + offset + (GetUnitFlyHeight(d.target) - d.Z + HitHeight) * (1-b)
set fz = fz - (pGetTerrainZ(GetUnitX(d.pr[1]),GetUnitY(d.pr[1]))-d.tZ) + (pGetTerrainZ(GetUnitX(d.target),GetUnitY(d.target))-d.tZ)
set d.oldX = GetUnitX(d.target)
set d.oldY = GetUnitY(d.target)
call SetUnitX(d.pr[1],GetUnitX(d.pr[1])+d.speed*Cos(angle))
call SetUnitY(d.pr[1],GetUnitY(d.pr[1])+d.speed*Sin(angle))
call SetUnitFlyHeight(d.pr[1],fz,0)
call SetUnitX(d.pr[0],GetUnitX(d.pr[1])+offset*Cos(angle + (3.14159/2)) )
call SetUnitY(d.pr[0],GetUnitY(d.pr[1])+offset*Sin(angle + (3.14159/2)) )
call SetUnitFlyHeight(d.pr[0],fz,0)
call SetUnitX(d.pr[2],GetUnitX(d.pr[1])+offset*Cos(angle - (3.14159/2)) )
call SetUnitY(d.pr[2],GetUnitY(d.pr[1])+offset*Sin(angle - (3.14159/2)) )
call SetUnitFlyHeight(d.pr[2],fz,0)
call SetUnitFacing(d.pr[0],GetUnitsAngleDeg(d.pr[0],d.target))
call SetUnitFacing(d.pr[1],GetUnitsAngleDeg(d.pr[1],d.target))
call SetUnitFacing(d.pr[2],GetUnitsAngleDeg(d.pr[2],d.target))
endif
set i = i + 1
endloop
set i = 0
if TS.counter == 0 then
call PauseTimer(TS.time)
endif
endmethod
static method Create takes unit source, unit target, real speed, real sway, integer level, string e returns nothing
local TS d = TS.allocate()
local integer i = 0
local real x = GetUnitX(source)
local real y = GetUnitY(source)
set d.Z = GetUnitFlyHeight(source)
loop
set d.pr[i] = CreateUnit(GetOwningPlayer(source),PROJECTILE_ID,x,y,GetUnitsAngleDeg(source,target))
call UnitAddAbility(d.pr[i],'Arav')
call UnitRemoveAbility(d.pr[i],'Arav')
call SetUnitFlyHeight(d.pr[i],d.Z,0)
call SetUnitPathing(d.pr[i],false)
call SetUnitX(d.pr[i],x)
call SetUnitY(d.pr[i],y)
set d.eff[i] = AddSpecialEffectTarget(e,d.pr[i],"chest")
set i = i + 1
exitwhen i == 3
endloop
set d.level = level
set d.source = source
set d.target = target
set d.speed = speed
set d.maxdis = GetUnitsDistance(source,target)
set d.sway = sway
set d.oldX = GetUnitX(target)
set d.oldY = GetUnitY(target)
set d.tZ = pGetTerrainZ(x,y)
if TS.counter == 0 then
call TimerStart(TS.time,Timer,true,function TS.Looper)
endif
set TS.indx[TS.counter] = d
set TS.counter = TS.counter + 1
endmethod
endstruct
function TeleporterConditionCheck takes nothing returns boolean
return GetSpellAbilityId() == 'A02X' or GetSpellAbilityId() == 'A00F' or GetSpellAbilityId() == 'A0AN'
endfunction
function IsInvalidTeleporterTarget takes location P returns boolean
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))] == 1 then
return RectContainsLoc(gg_rct_Team_2_Base_Main, P)
endif
return RectContainsLoc(gg_rct_Team_1_Base_Main, P)
endfunction
endlibrary
library Ideenlosigkeit
endlibrary
//TESH.scrollpos=147
//TESH.alwaysfold=0
library LightningManager requires PvJass
//******************************************************************************
//! The following lightning effects are creatable by the Lightning Manager !\\
//******************************************************************************
// lightning type "CLPB", Kettenblitz - Primär
// lightning type "CLSB", Kettenblitz - Sekundär
// lightning type "DRAB", Abziehen
// lightning type "DRAL", Leben Abziehen
// lightning type "DRAM", Mana Abziehen
// lightning type "AFOD", Todesfinger
// lightning type "FORK", Habelblitz
// lightning type "HWPB", Heilwelle - Primär
// lightning type "HWSB", Heilwelle - Sekundär
// lightning type "CHIM", Blitzangriff
// lightning type "LEAS", Zauberlasso
// lightning type "MBUR", Manabrand
// lightning type "MFPB", Mana-Leuchtfeuer
// lightning type "SPLK", Geistverbindung
//******************************************************************************
private function UnitAlive takes unit u returns boolean
return GetUnitState(u, UNIT_STATE_LIFE) > 0
endfunction
struct Lightning
private unit u1
private unit u2
private real x1
private real y1
private real z1
private real x2
private real y2
private real z2
private string typ
private real visibility
private real duration
private real current
private boolean fade
private lightning light
private boolean end
private boolean EndOnDeath
private static Lightning array indx
private static integer counter = 0
private static timer time = CreateTimer()
static method Looper takes nothing returns nothing
local Lightning d
local integer i = 0
loop
exitwhen i >= Lightning.counter
set d = Lightning.indx[i]
set d.current = d.current + Timer
if (d.current >= d.duration) or d.end then
call DestroyLightning(d.light)
set d.light = null
set d.u1 = null
set d.u2 = null
call d.destroy()
set Lightning.counter = Lightning.counter - 1
set Lightning.indx[i] = d.indx[Lightning.counter]
set i = i - 1
elseif d.typ == "CC" then
call MoveLightningEx(d.light,true,d.x1,d.y1,d.z1,d.x2,d.y2,d.z2)
elseif d.typ == "CU" then
if UnitAlive(d.u2) then
call MoveLightningEx(d.light,true,d.x1,d.y1,d.z1,GetUnitX(d.u2),GetUnitY(d.u2),GetUnitFlyHeight(d.u2)+pGetTerrainZ(GetUnitX(d.u2),GetUnitY(d.u2)))
endif
elseif d.typ == "UC" then
if UnitAlive(d.u1) then
call MoveLightningEx(d.light,true,GetUnitX(d.u1),GetUnitY(d.u1),GetUnitFlyHeight(d.u1)+pGetTerrainZ(GetUnitX(d.u1),GetUnitY(d.u1)),d.x2,d.y2,d.z2)
endif
elseif d.typ == "UU" then
if (UnitAlive(d.u1) and UnitAlive(d.u2)) or (d.EndOnDeath == false) then
call MoveLightningEx(d.light,true,GetUnitX(d.u1),GetUnitY(d.u1),GetUnitFlyHeight(d.u1)+pGetTerrainZ(GetUnitX(d.u1),GetUnitY(d.u1)),GetUnitX(d.u2),GetUnitY(d.u2),GetUnitFlyHeight(d.u2)+pGetTerrainZ(GetUnitX(d.u2),GetUnitY(d.u2)))
else
set d.end = true
endif
endif
if d.fade and (d.current < d.duration) then
set d.visibility = 1-(d.current/d.duration)
call SetLightningColor(d.light,1.,1.,1.,d.visibility)
endif
set i = i + 1
endloop
set i = 0
if Lightning.counter == 0 then
call PauseTimer(Lightning.time)
endif
endmethod
static method CreateCC takes string id, real x1, real y1, real z1, real x2, real y2, real z2, boolean fade, real dur returns lightning
local Lightning d = Lightning.allocate()
set d.light = AddLightningEx(id,true,x1,y1,z1,x2,y2,z2)
set d.x1 = x1
set d.x2 = x2
set d.y1 = y1
set d.y2 = y2
set d.z1 = z1
set d.z2 = z2
set d.current = 0.
set d.duration = dur
set d.visibility = 0.
set d.typ = "CC"
set d.fade = fade
if Lightning.counter == 0 then
call TimerStart(Lightning.time,Timer,true,function Lightning.Looper)
endif
set Lightning.indx[Lightning.counter] = d
set Lightning.counter = Lightning.counter + 1
return d.light
endmethod
static method CreateUC takes string id, unit u1, real x2, real y2, real z2, boolean fade, real dur returns lightning
local Lightning d = Lightning.allocate()
set d.light = AddLightningEx(id,true,GetUnitX(u1),GetUnitY(u1),GetUnitFlyHeight(u1)+pGetTerrainZ(GetUnitX(u1),GetUnitY(u1)),x2,y2,z2)
set d.u1 = u1
set d.x2 = x2
set d.y2 = y2
set d.z2 = z2
set d.current = 0.
set d.duration = dur
set d.visibility = 0.
set d.typ = "UC"
set d.fade = fade
if Lightning.counter == 0 then
call TimerStart(Lightning.time,Timer,true,function Lightning.Looper)
endif
set Lightning.indx[Lightning.counter] = d
set Lightning.counter = Lightning.counter + 1
return d.light
endmethod
static method CreateCU takes string id, real x1, real y1, real z1, unit u2, boolean fade, real dur returns lightning
local Lightning d = Lightning.allocate()
set d.light = AddLightningEx(id,true,x1,y1,z1,GetUnitX(u2),GetUnitY(u2),GetUnitFlyHeight(u2)+pGetTerrainZ(GetUnitX(u2),GetUnitY(u2)))
set d.u2 = u2
set d.x1 = x1
set d.y1 = y1
set d.z1 = z1
set d.current = 0.
set d.duration = dur
set d.visibility = 0.
set d.typ = "CU"
set d.fade = fade
if Lightning.counter == 0 then
call TimerStart(Lightning.time,Timer,true,function Lightning.Looper)
endif
set Lightning.indx[Lightning.counter] = d
set Lightning.counter = Lightning.counter + 1
return d.light
endmethod
static method CreateUU takes string id, unit u1, unit u2, boolean fade, boolean endOnDeath, real dur returns lightning
local Lightning d = Lightning.allocate()
set d.light = AddLightningEx(id,true,GetUnitX(u1),GetUnitY(u1),GetUnitFlyHeight(u1)+pGetTerrainZ(GetUnitX(u1),GetUnitY(u1)),GetUnitX(u2),GetUnitY(u2),GetUnitFlyHeight(u2)+pGetTerrainZ(GetUnitX(u2),GetUnitY(u2)))
set d.u1 = u1
set d.u2 = u2
set d.current = 0.
set d.duration = dur
set d.visibility = 0.
set d.typ = "UU"
set d.fade = fade
set d.end = false
set d.EndOnDeath = endOnDeath
if Lightning.counter == 0 then
call TimerStart(Lightning.time,Timer,true,function Lightning.Looper)
endif
set Lightning.indx[Lightning.counter] = d
set Lightning.counter = Lightning.counter + 1
return d.light
endmethod
endstruct
endlibrary
//TESH.scrollpos=11
//TESH.alwaysfold=0
library Initilization requires BTFramework
// Initializes variables and sets the force players
// No function is meant to be called from outside
private function Init_Variables takes nothing returns nothing
local integer i = 1
local texttag tag = CreateTextTag()
//playable map area (d'oh)
set udg_Playable_Map = GetPlayableMapRect()
//both headquarters
set udg_HQ[1] = gg_unit_h004_0013
set udg_HQ[2] = gg_unit_h004_0032
//Junkyard area
set udg_JunkyardRect[1] = gg_rct_Team_1_Junkyard
set udg_JunkyardRect[2] = gg_rct_Team_2_Junkyard
set udg_Time_Value = - GAME_START_DELAY
//team number of each player
set udg_Player_Team[1] = 1
set udg_Player_Team[2] = 1
set udg_Player_Team[3] = 1
set udg_Player_Team[4] = 1
set udg_Player_Team[5] = 1
set udg_Player_Team[6] = 2
set udg_Player_Team[7] = 2
set udg_Player_Team[8] = 2
set udg_Player_Team[9] = 2
set udg_Player_Team[10] = 2
set udg_Player_Team[11] = 1
set udg_Player_Team[12] = 2
//Multikill sounds
set udg_Multikill_Sounds[1] = gg_snd_Kill_1
set udg_Multikill_Sounds[2] = gg_snd_Kill_2
set udg_Multikill_Sounds[3] = gg_snd_Kill_3
set udg_Multikill_Sounds[4] = gg_snd_Kill_4
set udg_Multikill_Sounds[5] = gg_snd_Kill_5
set udg_Multikill_Sounds[6] = gg_snd_Kill_6
set udg_Multikill_Sounds[7] = gg_snd_Kill_7
set udg_Multikill_Sounds[8] = gg_snd_Kill_8
set udg_Multikill_Sounds[9] = gg_snd_Kill_9
set udg_Multikill_Sounds[10] = gg_snd_Kill_10
set udg_Multikill_Sounds[11] = gg_snd_Kill_11
set udg_Multikill_Sounds[12] = gg_snd_Kill_12
//the amount of gold you get for each trade good
//this order applies to the Dark Force, vice versa for Light Force
set udg_Trader_Gold[1] = 250 //Skeleton
set udg_Trader_Gold[2] = 175 //Analysis Results
set udg_Trader_Gold[3] = 115 //Gold
set udg_Trader_Gold[4] = 150 //Oil
set udg_Trader_Gold[5] = 250 //Cheese
set udg_Trader_Gold[6] = 425 //Water
set udg_Trader_Gold[7] = 300 //Salt
set udg_Trader_Gold[8] = 125 //Metal
set udg_Trader_Gold[9] = 475 //Wood
set udg_Trader_Gold[10] = 600 //Fossil
//the amount of wood you get for each trade good
//this order applies to the Dark Force, vice versa for Light Force
set udg_Trader_Wood[1] = 2 //Skeleton
set udg_Trader_Wood[2] = 1 //Analysis Results
set udg_Trader_Wood[3] = 1 //Gold
set udg_Trader_Wood[4] = 1 //Oil
set udg_Trader_Wood[5] = 2 //Cheese
set udg_Trader_Wood[6] = 2 //Water
set udg_Trader_Wood[7] = 2 //Salt
set udg_Trader_Wood[8] = 1 //Metal
set udg_Trader_Wood[9] = 3 //Wood
set udg_Trader_Wood[10] = 3 //Fossil
//how much food is used by Troop Command units
set udg_TC_Food[1] = 1 //Marine
set udg_TC_Food[2] = 1 //Marine
set udg_TC_Food[3] = 2 //Artillery
set udg_TC_Food[4] = 2 //Commander
set udg_TC_Food[5] = 2 //Zeppelin
set udg_TC_Food[6] = 2 //Mortar Team
set udg_TC_Food[7] = 2 //Mortar Team
set udg_TC_Food[8] = 2 //Mortar Team
set udg_TC_Food[9] = 2 //Aura Creep
//creeps summoned by the Troop Command
set udg_TC_Unit[1] = 'z006' //Marine
set udg_TC_Unit[2] = 'z006' //Marine
set udg_TC_Unit[3] = 'z008' //Artillery
set udg_TC_Unit[4] = 'z007' //Commander
set udg_TC_Unit[5] = 'z00D' //Zeppelin
set udg_Aura_Creeps[1] = 'z01E' //Healer
set udg_Aura_Creeps[2] = 'z01F' //Pusher
set udg_Aura_Creeps[3] = 'z01K' //Rusher
//the Treants summoned by the rooted Guard
set udg_Treant[1] = 'z00O'
set udg_Treant[2] = 'z00Q'
set udg_Treant[3] = 'z00R'
set udg_Treant[4] = 'z00N'
set udg_Treant[5] = 'z00M'
//names and colors of each game mode
set ModeName[1] = "Normal"
set ModeName[2] = "Royal Flush"
set ModeName[3] = "Alternative"
set ModeName[4] = "League"
set ModeName[5] = "Options"
//set udg_GameMode_Name[1] = ModeName[1]
//set udg_GameMode_Name[2] = ModeName[2]
//set udg_GameMode_Name[3] = ModeName[3]
//set udg_GameMode_Name[4] = ModeName[4]
//set udg_GameMode_Name[5] = ModeName[5]
//rain and snow effects
set udg_Weather_Effects[1] = AddWeatherEffect( udg_Playable_Map, 'SNhs' ) //Rain
set udg_Weather_Effects[2] = AddWeatherEffect( udg_Playable_Map, 'RAhr' ) //Snow
set udg_Weather_Effects[3] = AddWeatherEffect( udg_Playable_Map, 'FDwl' ) //white fog
set udg_Weather_Effects[4] = AddWeatherEffect( udg_Playable_Map, 'LRaa' ) //sun rays
set udg_Weather_Effects[5] = AddWeatherEffect( udg_Playable_Map, 'WOlw' ) //light wind
//used to show the difference between current and default movement speed with the hero stats ( but doesn't work atm :( )
set udg_SpeedIndicatorPos[0] = 'A0EB'
set udg_SpeedIndicatorPos[1] = 'A0EG'
set udg_SpeedIndicatorPos[2] = 'A0EH'
set udg_SpeedIndicatorPos[3] = 'A0EI'
set udg_SpeedIndicatorPos[4] = 'A0EJ'
set udg_SpeedIndicatorPos[5] = 'A0EK'
set udg_SpeedIndicatorPos[6] = 'A0EL'
set udg_SpeedIndicatorPos[7] = 'A0EM'
set udg_SpeedIndicatorPos[8] = 'A0EN'
set udg_SpeedIndicatorNeg[0] = 'A0EO'
set udg_SpeedIndicatorNeg[1] = 'A0EP'
set udg_SpeedIndicatorNeg[2] = 'A0EQ'
set udg_SpeedIndicatorNeg[3] = 'A0ER'
set udg_SpeedIndicatorNeg[4] = 'A0ES'
set udg_SpeedIndicatorNeg[5] = 'A0ET'
set udg_SpeedIndicatorNeg[6] = 'A0EU'
set udg_SpeedIndicatorNeg[7] = 'A0EV'
set udg_SpeedIndicatorNeg[8] = 'A0EW'
call SetAltMinimapIcon("war3mapImported\\blank_icon.blp")
//for temporary usage
set udg_TempRect = Rect(-10.00, -10.00, 10.00, 10.00)
set udg_TempLoc = Location(0,0)
//this can only be filled by host bots
set udg_Mode_Command = ""
set PWeapons = 0 //Pacifista weapon struct
set i = 0
loop
exitwhen i >= 10
set BuildingsKilled[i] = 0
set SmoothCam[i] = true
set DiedRooted[i] = false
//set WTank[i+1] = 0 //Custom Weapon System struct
set ManaUpgrade[i+1] = 0
set DeathPenalty[i+1] = 0 //Current penalty
set DeathPenaltyValue[i+1] = 2.5 //Value that gets added, when dying
set PenaltyTimer[i+1] = null //Timer, that decreases the penalty again
set udg_MultiboardType[i+1] = 0 //The type of multiboard which should be displayed (0 = default)
set udg_TankBounty[i+1] = 150
set PlayTimer[i] = CreateTimer() // League Variable: shows how long a player was in the game
call TimerStart(PlayTimer[i],999999,false,null)
set i = i + 1
endloop
endfunction
private function Init_MovePoints takes nothing returns nothing
set udg_Spawn_Points[1] = GetRectCenter(gg_rct_Team_1_Spawn_right_1)
set udg_Spawn_Points[2] = GetRectCenter(gg_rct_Team_1_Spawn_right_2)
set udg_Spawn_Points[3] = GetRectCenter(gg_rct_Team_1_Spawn_Artillerie_right)
set udg_Spawn_Points[4] = GetRectCenter(gg_rct_Team_1_Spawn_Artillerie_left)
set udg_Spawn_Points[5] = GetRectCenter(gg_rct_Team_1_Spawn_left_1)
set udg_Spawn_Points[6] = GetRectCenter(gg_rct_Team_1_Spawn_left_2)
set udg_Spawn_Points[7] = GetRectCenter(gg_rct_Team_1_Spawn_front_right)
set udg_Spawn_Points[8] = GetRectCenter(gg_rct_Team_1_Spawn_front_left)
set udg_Spawn_Points[9] = GetRectCenter(gg_rct_Team_2_Spawn_left_1)
set udg_Spawn_Points[10] = GetRectCenter(gg_rct_Team_2_Spawn_left_2)
set udg_Spawn_Points[11] = GetRectCenter(gg_rct_Team_2_Spawn_Artillerie_left)
set udg_Spawn_Points[12] = GetRectCenter(gg_rct_Team_2_Spawn_Artillerie_right)
set udg_Spawn_Points[13] = GetRectCenter(gg_rct_Team_2_Spawn_right_1)
set udg_Spawn_Points[14] = GetRectCenter(gg_rct_Team_2_Spawn_right_2)
set udg_Spawn_Points[15] = GetRectCenter(gg_rct_Team_2_Spawn_front_right)
set udg_Spawn_Points[16] = GetRectCenter(gg_rct_Team_2_Spawn_front_left)
set udg_Move_Points[1] = GetRectCenter(gg_rct_Team_1_Respawn)
set udg_Move_Points[2] = GetRectCenter(gg_rct_Team_2_Respawn)
set udg_Move_Points[3] = GetRectCenter(gg_rct_Team_1_Respawn_Move)
set udg_Move_Points[4] = GetRectCenter(gg_rct_Team_2_Respawn_Move)
set udg_Move_Points[5] = GetRectCenter(gg_rct_Team_1_Trade_Master_Respawn)
set udg_Move_Points[6] = GetRectCenter(gg_rct_Team_1_Trade_Master_Respawn_Move)
set udg_Move_Points[7] = GetRectCenter(gg_rct_Team_2_Trade_Master_Respawn)
set udg_Move_Points[8] = GetRectCenter(gg_rct_Team_2_Trader_Master_Respawn_Move)
set udg_Move_Points[9] = GetRectCenter(gg_rct_Move_Center)
set udg_Move_Points[10] = GetRectCenter(gg_rct_Team_1_Air_Move)
set udg_Move_Points[11] = GetRectCenter(gg_rct_Team_2_Air_Move)
set udg_Move_Points[12] = GetRectCenter(gg_rct_Move_Left)
set udg_Move_Points[13] = GetRectCenter(gg_rct_Move_Left_2)
set udg_Move_Points[14] = GetRectCenter(gg_rct_Move_Left_3)
set udg_Move_Points[15] = GetRectCenter(gg_rct_Move_Right)
set udg_Move_Points[16] = GetRectCenter(gg_rct_Move_Right_2)
set udg_Move_Points[17] = GetRectCenter(gg_rct_Move_Right_3)
set udg_Move_Points[18] = GetRectCenter(gg_rct_Move_Center_Team_1)
set udg_Move_Points[19] = GetRectCenter(gg_rct_Move_Center_Team_2)
set udg_Move_Points[20] = GetRectCenter(gg_rct_Move_Center_Left)
set udg_Move_Points[21] = GetRectCenter(gg_rct_Move_Center_Right)
set udg_Move_Points[22] = GetRectCenter(gg_rct_Team_1_Tank_Respawn)
set udg_Move_Points[23] = GetRectCenter(gg_rct_Team_1_Tank_Respawn_Move)
set udg_Move_Points[24] = GetRectCenter(gg_rct_Team_2_Tank_Respawn)
set udg_Move_Points[25] = GetRectCenter(gg_rct_Team_2_Tank_Respawn_Move)
set udg_Move_Points[26] = GetRectCenter(gg_rct_Team_1_Base_Main)
set udg_Move_Points[27] = GetRectCenter(gg_rct_Team_2_Base_Main)
endfunction
private function Init_Colors takes nothing returns nothing
local integer PlayerId = 1
set udg_Color[1] = "|cFFFF0303"
set udg_Color[2] = "|cFF0042FF"
set udg_Color[3] = "|cFF1CE6B9"
set udg_Color[4] = "|cFF540081"
set udg_Color[5] = "|cFFFFFC01"
set udg_Color[6] = "|cFFFE8A0E"
set udg_Color[7] = "|cFF20C000"
set udg_Color[8] = "|cFFE55BB0"
set udg_Color[9] = "|cFF959697"
set udg_Color[10] = "|cFF7EBFF1"
set udg_Color[11] = "|cFF106246"
set udg_Color[12] = "|cFF4E2A04"
loop
exitwhen PlayerId > 12
set udg_Color_Red[PlayerId] = HexToInt(SubString(udg_Color[PlayerId],4,6))
set udg_Color_Green[PlayerId] = HexToInt(SubString(udg_Color[PlayerId],6,8))
set udg_Color_Blue[PlayerId] = HexToInt(SubString(udg_Color[PlayerId],8,10))
set PlayerId = PlayerId + 1
endloop
endfunction
private function Init_Forces takes nothing returns nothing
// Function not dependant on GetPlayerNr and GetPlayer,
// because Init_PlayerNr is called after Init_Forces
local integer i = 0
local group G
local unit EnumUnit
// Init_PlayerNr() is required, make sure it is initialized (may have been called before)
call Init_PlayerNr()
//The Tower Ruins, located at the Trader Master
//For more information on this, refer to the 'Add Towers to Ruin' trigger
call CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'h00Q', - 1856.0, - 320.0, 270.000)
call CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'h00Q', 1856.0, - 704.0, 270.000)
call SetPlayerName(udg_Force[1], TeamOneName)
call SetPlayerColor(udg_Force[1], PLAYER_COLOR_AQUA)
call SetPlayerTeam( udg_Force[1], 0 )
call SetPlayerController( udg_Force[1], MAP_CONTROL_COMPUTER )
call SetPlayerName(udg_Force[2], TeamTwoName)
call SetPlayerColor(udg_Force[2], PLAYER_COLOR_BROWN)
call SetPlayerTeam( udg_Force[2], 1 )
call SetPlayerController( udg_Force[2], MAP_CONTROL_COMPUTER )
loop
exitwhen i >= 5
call SetPlayerAllianceStateAllyBJ( udg_Force[1], Player(i), true)
call SetPlayerAllianceStateAllyBJ( Player(i), udg_Force[1], true)
call SetPlayerAlliance( udg_Force[1], Player(i), ALLIANCE_SHARED_VISION, true)
call SetPlayerAlliance( Player(i), udg_Force[1], ALLIANCE_SHARED_VISION, true)
call SetPlayerAllianceStateAllyBJ( udg_Force[2], Player(i), false)
call SetPlayerAllianceStateAllyBJ( Player(i), udg_Force[2], false)
if DebugMode then
call SetPlayerAlliance( Player(0), Player(i), ALLIANCE_SHARED_CONTROL, true)
call SetPlayerAlliance( Player(i), Player(0), ALLIANCE_SHARED_CONTROL, true)
endif
set i = i + 1
endloop
loop
exitwhen i >= 10
call SetPlayerAllianceStateAllyBJ( udg_Force[2], Player(i), true)
call SetPlayerAllianceStateAllyBJ( Player(i), udg_Force[2], true)
call SetPlayerAlliance( udg_Force[2], Player(i), ALLIANCE_SHARED_VISION, true)
call SetPlayerAlliance( Player(i), udg_Force[2], ALLIANCE_SHARED_VISION, true)
call SetPlayerAllianceStateAllyBJ( udg_Force[1], Player(i), false)
call SetPlayerAllianceStateAllyBJ( Player(i), udg_Force[1], false)
if DebugMode then
call SetPlayerAlliance( Player(0), Player(i), ALLIANCE_SHARED_CONTROL, true)
call SetPlayerAlliance( Player(i), Player(0), ALLIANCE_SHARED_CONTROL, true)
endif
set i = i + 1
endloop
if udg_ObserverInGame then
//grant control of both bases to the new players
set G = CreateGroup()
call GroupEnumUnitsOfPlayer(G, Player(10), FILTER_NULL)
loop
set EnumUnit = FirstOfGroup(G)
exitwhen EnumUnit==null
call SetUnitOwner( EnumUnit, udg_Force[1], true )
call GroupRemoveUnit(G, EnumUnit)
endloop
call GroupClear(G)
call GroupEnumUnitsOfPlayer(G, Player(11), FILTER_NULL)
loop
set EnumUnit = FirstOfGroup(G)
exitwhen EnumUnit==null
call SetUnitOwner( EnumUnit, udg_Force[2], true )
call GroupRemoveUnit(G, EnumUnit)
endloop
call DestroyGroup(G)
if ((GetLocalPlayer() == Player(10)) or (GetLocalPlayer() == Player(11))) then
set udg_Cam_Distance = 3500
endif
endif
set G = null
set EnumUnit = null
endfunction
// Setting pathability, used for the "Allow pathing" destructable
private function Init_AllowPathingDestructables_Enum_Do takes destructable d returns nothing
local real X = GetDestructableX(d)
local real Y = GetDestructableY(d)
local real minX = X-64+16
local real minY = Y-64+16
local real maxX = X+64-16
local real maxY = Y+64-16
// Loop through all 32x32 blocks inside the 128x128 block which has to be set
set X = minX
loop
exitwhen X>maxX
set Y = minY
loop
exitwhen Y>maxY
call SetTerrainPathable(X,Y,PATHING_TYPE_AMPHIBIOUSPATHING,true)
call SetTerrainPathable(X,Y,PATHING_TYPE_WALKABILITY,true)
call SetTerrainPathable(X,Y,PATHING_TYPE_FLOATABILITY,true)
call SetTerrainPathable(X,Y,PATHING_TYPE_BUILDABILITY,true)
call SetTerrainPathable(X,Y,PATHING_TYPE_FLYABILITY,true)
set Y = Y + 32
endloop
set X = X + 32
endloop
call RemoveDestructable(d)
endfunction
private function Init_AllowPathingDestructables_Enum takes nothing returns nothing
if GetDestructableTypeId(GetEnumDestructable())=='B000' then
call Init_AllowPathingDestructables_Enum_Do(GetEnumDestructable())
endif
endfunction
private function Init_AllowPathingDestructables takes nothing returns nothing
// Note that here is no global filter variable used, as this function is called only once anyways.
call EnumDestructablesInRect(GetWorldBounds(), FILTER_NULL, function Init_AllowPathingDestructables_Enum )
endfunction
private function Init_Tips takes nothing returns nothing
if udg_Language=="German" then
set udg_Tips[1] = "Waffen greifen Gegner automatisch innerhalb der angegebenen Reichweite an."
set udg_Tips[2] = "Du kannst auf deine Waffen klicken um sie zu verbessern."
set udg_Tips[3] = "Gehe immer hinter verbündeten Einheiten in Deckung."
set udg_Tips[4] = "Das Kopfgeld von Creeps und Gebäuden steigt mit der Zeit (100%% in einer Stunde)."
set udg_Tips[5] = "Fabriken und Kontrollpunkte können deinen Panzer reparieren."
set udg_Tips[6] = "Bleibe 10 Sekunden neben einem Kontrollpunkt, um ihn einzunehmen."
set udg_Tips[7] = "Vergiss nicht, neben Waffen auch immer Hüllen oder Panzer zu kaufen."
set udg_Tips[8] = "Waffen mit sehr hoher Reichweite greifen keine Gebäude an."
set udg_Tips[9] = "Mit dem Mine Remote Fuse können Minen entschärft werden."
set udg_Tips[10] = "Halte Abstand von deinen Gegnern, wenn du überleben willst."
set udg_Tips[11] = "Stirb nicht oft, deine Gegner erhalten dafür Gold."
set udg_Tips[12] = "Du kannst dich zwischen Kontrollpunkten hin und her teleportieren (Hotkey: C)."
set udg_Tips[13] = "Um die teuersten Panzer zu kaufen, brauchst du eine bestimmte Anzahl an Verteidigungs-Upgrades."
set udg_Tips[14] = "Diese Karte kann auch mit Bots gespielt werden."
set udg_Tips[15] = "Kaufe anfangs nicht nur Waffen; wenn sich dein Gegner einen stärkeren Panzer kauft, hast du keine Chance mehr."
set udg_Tips[16] = "Im Info-Menü (F9) findest du viele nützliche Chat-Befehle."
set udg_Tips[17] = "Verkaufte Gegenstände landen auf dem Schrottplatz, wo du sie für 75%% der normalen Kosten kaufen kannst."
set udg_Tips[18] = "Minen, Bomben und Orbital Bombardement werden mit jedem Waffen-Upgrade stärker."
set udg_Tips[19] = "Jede Waffe und jede Fähigkeit die die Panzer benutzen, richten magischen Schaden an."
set udg_Tips[20] = "Jeder Schadenstyp von den Creeps und Gebäuden richtet physischen Schaden an."
else
set udg_Tips[1] = "Weapons fire automatically on enemies within the described range."
set udg_Tips[2] = "You can click on your weapons to upgrade them."
set udg_Tips[3] = "Always take cover behind allied units."
set udg_Tips[4] = "The bounty of creeps and buildings increases over time (100%% in one hour)."
set udg_Tips[5] = "Factories and control points can repair your tank."
set udg_Tips[6] = "Stay 10 seconds next to an enemy control point to capture it."
set udg_Tips[7] = "Remember to buy better armor and tanks instead of only weapons, too."
set udg_Tips[8] = "Long-ranged weapons do not attack buildings."
set udg_Tips[9] = "There is a Mine Remote Fuse to defuse mines."
set udg_Tips[10] = "Keeping distance is vital for your survival - Don't kill yourself by going too close to your enemies"
set udg_Tips[11] = "Do not die often, your enemy earns money for killing you."
set udg_Tips[12] = "You can teleport between control points (Hotkey: C)."
set udg_Tips[13] = "You need a certain amount of armor-upgrades to buy the most expensive tanks."
set udg_Tips[14] = "You can also play with bots in this map."
set udg_Tips[15] = "Do not only buy weapons at start; your opponents might get stronger tanks that will instantly kill your weak tank."
set udg_Tips[16] = "You can find a lot of useful chat commands in the info menu (F9)."
set udg_Tips[17] = "Sold items go to the junkyard where you can buy them for 75%% of their original costs."
set udg_Tips[18] = "Mines, Bombs and Orbital Bombardement become stronger with each weapon-upgrade."
set udg_Tips[19] = "Every weapon and skill of a tank deals, without exception, magical damage."
set udg_Tips[20] = "Every damage type of creeps and buildings deals physical damage."
endif
endfunction
function Init_Language takes nothing returns nothing
local unit Dummy = CreateUnit(Player(15),'hfoo',0,0,0)
local string Name = GetUnitName(Dummy)
set udg_Language = "Other"
call RemoveUnit(Dummy)
set Dummy = null
if Name=="Soldat" then
set udg_Language = "German"
endif
if Name=="Footman" then
set udg_Language = "English"
endif
endfunction
function Init_All takes nothing returns nothing
// Requires no previous initialization of anything except for standard blizzard stuff
call Init_Language()
call Init_Variables()
call Init_MovePoints()
call Init_Colors()
call Init_Forces()
call Init_AllowPathingDestructables()
call Init_Tips() // Requires language
endfunction
endlibrary
//TESH.scrollpos=3
//TESH.alwaysfold=0
function Trig_Game_Init_RemovePreloaded takes nothing returns nothing
call RemoveUnit( GetEnumUnit() )
endfunction
function Trig_Game_Init_InitializePlayer takes integer playerId, boolean initialAI returns nothing
local player p = GetPlayer(playerId)
local integer startingLoc = GetPlayerStartLocation(p)
local integer team = udg_Player_Team[playerId]
local unit pilot
call SetPlayerHandicapXP(p,InitXPFactor)
// Set the starting tank up
set pilot = CreateUnit(p,'H01H',GetStartLocationX(startingLoc),GetStartLocationY(startingLoc),45+team*180)
call UnitAddAbility( pilot, 'A08F' )
call SetUnitMoveSpeed( pilot, -1.00 )
set udg_Tank[playerId] = pilot
call UpdateTankCosts(playerId)
if GetLocalPlayer() == p then
call ClearSelection()
call SelectUnit(udg_Tank[playerId], true)
endif
// Level bonus for tank
call SetPlayerTechResearched( p, 'R000', 1 )
call SetPlayerTechResearched( p, 'R001', 0 )
call SetPlayerState( p, PLAYER_STATE_RESOURCE_FOOD_CAP, 40 )
call SetPlayerState( p, PLAYER_STATE_GIVES_BOUNTY, 1 )
// Set up game and team variables
set udg_Team_CountPlayers[team] = udg_Team_CountPlayers[team] + 1
call ForceAddPlayer( udg_Players_Team[team], p )
set udg_PlayerInStart[playerId] = true
call ForceAddPlayer( udg_Players_Start, p )
set udg_PlayerIn[playerId] = true
call ForceAddPlayer( udg_Players, p )
// Register player-specific events
call TriggerRegisterPlayerEvent( gg_trg_Player_Leaves, p, EVENT_PLAYER_LEAVE )
call TriggerRegisterPlayerAllianceChange( gg_trg_Anti_Shared_Control, p, ALLIANCE_SHARED_CONTROL )
call TriggerRegisterPlayerChatEvent( gg_trg_Chat, p, "", false )
call TriggerRegisterPlayerEvent( gg_trg_Multiboard_OpenClose, p, EVENT_PLAYER_END_CINEMATIC )
call TriggerRegisterUnitEvent( gg_trg_Assist_Detection, pilot, EVENT_UNIT_DAMAGED )
call RegisterUnitForSkillDamageDetection(pilot)
// Check if this player is an AI from the beginning
if initialAI then
call SetPlayerName(p,GetRandomName())
// Level of AI is dependant on the team for debugging
if DebugMode then
call RegisterAI(playerId, team)
else
call RegisterAI(playerId, 1)
endif
// Remove the player to disable the standard wc3 AI
if GetPlayerController( p ) == MAP_CONTROL_COMPUTER then
// disabled, until this properly working
//call RemovePlayer( p, PLAYER_GAME_RESULT_DEFEAT )
endif
endif
set udg_MultiboardType[GetPlayerId(p)] = NO_BOARD
if GetPlayerController( p )== MAP_CONTROL_USER then
// Use default multiboard for human players (no matter if their tanks are controlled by AI)
set udg_MultiboardType[GetPlayerId(p)] = DEFAULT_BOARD
endif
endfunction
function Trig_Game_Init_MakeInvulnerable takes nothing returns nothing
call SetUnitInvulnerable( GetEnumUnit(), true )
endfunction
function Trig_Game_Init_PreloadTinker takes nothing returns nothing
local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),'H006',0,0,0)
local integer i = 1
call SetHeroLevel(u, 25, true)
call SelectHeroSkill( u, 'A01J' )
call UnitAddAbility( u, STRATEGIC_LOCATION_RESISTANCE_ID )
call UnitAddAbility( u, STRATEGIC_LOCATION_HEALING_ID )
call UnitAddAbility(u,'A086')
call UnitRemoveAbility(u,'A086')
call UnitAddAbility(u,'A087')
call UnitRemoveAbility(u,'A087')
call UnitAddAbility(u,'A088')
call UnitRemoveAbility(u,'A088')
call UnitAddAbility(u,'A089')
call UnitRemoveAbility(u,'A089')
call UnitAddAbility(u,'A08A')
call UnitAddAbility(u,'A0BW')
// the magic armor abilities
loop
exitwhen (i > 6)
call UnitAddAbility(u,trg_MagicArmorSkills[i])
call UnitRemoveAbility(u,trg_MagicArmorSkills[i])
set i = i + 1
endloop
call RemoveUnit( u )
set u = null
endfunction
function Trig_Game_Init_Actions takes nothing returns nothing
local group G = NewGroup()
local integer i
set bj_lastPlayedMusic = gg_snd_War2IntroMusic01
call PlayMusic( gg_snd_War2IntroMusic01 )
call SetMapMusic( gg_snd_War2IntroMusic01, false, 0 )
call VolumeGroupSetVolume( SOUND_VOLUMEGROUP_MUSIC, 1.0 )
call SetMusicVolume( 127 )
call CameraSetSmoothingFactor( 40.00 )
call GroupEnumUnitsInRect(G, gg_rct_Tank_Preload,FILTER_NULL)
call ForGroup( G, function Trig_Game_Init_RemovePreloaded )
call TimerStart( udg_GameTime, 1000000.00, false, null)
call Init_All()
call Init_WeaponRange()
call Init_WeaponModifier()
call Init_Mode_Command()
call Trig_Game_Init_PreloadTinker()
call SetGameSpeed( MAP_SPEED_NORMAL )
call SetMapFlag( MAP_ALLIANCE_CHANGES_HIDDEN, true )
call SetMapFlag(MAP_LOCK_SPEED, true)
call SuspendTimeOfDay( true )
call SetFloatGameState(GAME_STATE_TIME_OF_DAY, 6.0 )
call SetMapFlag( MAP_LOCK_RESOURCE_TRADING, true )
// Initialize force bounty
call SetPlayerState( udg_Force[1], PLAYER_STATE_GIVES_BOUNTY, 1 )
call SetPlayerState( udg_Force[2], PLAYER_STATE_GIVES_BOUNTY, 1 )
// Initialize players in game
set i = 1
loop
exitwhen i>GetMaxHumanPlayers()
if GetPlayerSlotState(GetPlayer(i))==PLAYER_SLOT_STATE_PLAYING then
call Trig_Game_Init_InitializePlayer(i, OnlyAI or (GetPlayerController(GetPlayer(i)) == MAP_CONTROL_COMPUTER) )
endif
set i = i + 1
endloop
// Fill teams with AI until desired player amount is achieved
if FillAIPlayers>0 then
set i = 1
loop
exitwhen i>GetMaxHumanPlayers()
if udg_Team_CountPlayers[udg_Player_Team[i]]<FillAIPlayers and not udg_PlayerIn[i] then
call Trig_Game_Init_InitializePlayer(i, true)
endif
set i = i + 1
endloop
endif
// Set up camera for all players
call SetCameraField( CAMERA_FIELD_ANGLE_OF_ATTACK, 305.00, 0.00 )
call SetCameraField( CAMERA_FIELD_TARGET_DISTANCE, udg_Cam_Distance, 0.00 )
call SetCameraField( CAMERA_FIELD_ZOFFSET, 0.00, 0.00 )
call SetCameraField( CAMERA_FIELD_FARZ, 10000.00, 0.00 )
call TriggerExecute( gg_trg_Fog_Modifier )
set G = GetUnitsOfTypeIdAll('h004')
call ForGroup( G, function Trig_Game_Init_MakeInvulnerable )
call ReleaseGroup( G )
set G = null
call PauseAllUnitsBJ( true )
call TriggerExecute( gg_trg_Weather_Change )
call GameTimeWait(30)
call DestroyTrigger( GetTriggeringTrigger() )
endfunction
//===========================================================================
function InitTrig_Init_Players takes nothing returns nothing
set gg_trg_Init_Players = CreateTrigger( )
call TriggerAddAction( gg_trg_Init_Players, function Trig_Game_Init_Actions )
endfunction
//TESH.scrollpos=142
//TESH.alwaysfold=0
library ModeHostbot requires BTFramework
// Retrieves information from the host bot
globals
constant integer GAME_MODE_UNKNOWN = 0
constant integer GAME_MODE_NORMAL = 1
constant integer GAME_MODE_ROYAL_FLUSH= 2
constant integer GAME_MODE_ALTERNATIVE= 3
constant integer GAME_MODE_LEAGUE = 4
constant string ModeBotNormal = "nm"
constant string ModeBotRF = "rf"
constant string ModeBotPro = "pr"
constant string ModeBotCV = "cv"
constant string ModeBot5k = "5k"
constant string ModeBotRu = "cr"
constant string ModeBotNoOptions = "no"
constant string ModeBotLeague = "=l"
constant string ModeBotTournament = "tx"
constant string ModeBotBeta = "b="
boolean array ModeEnabled
integer OptionDialogPage = 1
boolean proMode = false
endglobals
function GetHostBotMode takes nothing returns integer
if udg_Mode_Command == ModeBotNormal then
return GAME_MODE_NORMAL
elseif udg_Mode_Command == ModeBotRF then
return GAME_MODE_ROYAL_FLUSH
elseif udg_Mode_Command == ModeBotPro then
return GAME_MODE_ALTERNATIVE
elseif udg_Mode_Command == ModeBot5k then
return GAME_MODE_ALTERNATIVE
elseif udg_Mode_Command == ModeBotCV then
return GAME_MODE_ALTERNATIVE
elseif udg_Mode_Command == ModeBotRu then
return GAME_MODE_ALTERNATIVE
elseif LeagueConfirmed or LeagueImitation then
return GAME_MODE_LEAGUE
endif
return GAME_MODE_UNKNOWN
endfunction
function HostBotAllowsAlternative takes nothing returns boolean
//Limiting mode commands don't actually choose a mode
//they restrict the player from choosing certain options
return udg_Mode_Command != ModeBotNoOptions
endfunction
function SetHostBotOptions takes nothing returns boolean
local string command = udg_Mode_Command
if (command == ModeBotNormal) then
return true
elseif (command == ModeBotRF) then
return true
elseif (command == ModeBotNoOptions) then
return true
elseif (command == ModeBotPro) then
set udg_ProMode = true
set udg_NoTrader = true
set udg_NoTinker = true
set udg_NoExploder = true
return true
elseif (command == ModeBotCV) then
set udg_CV = true
return true
elseif (command == ModeBotRu) then
set udg_StartingGold = 10000
set udg_CV = true
set udg_HighTech = true
return true
elseif (command == ModeBot5k) then
set udg_StartingGold = 5000
return true
endif
return false
endfunction
function ResetHandicap takes nothing returns nothing
local integer i = 1
loop
exitwhen i > GetMaxHumanPlayers()
call SetPlayerHandicap(GetPlayer(i), 1.0)
set i = i + 1
endloop
endfunction
function Init_Mode_Command takes nothing returns nothing
local integer i
local integer j
local integer h
local integer v
local integer co = 0
local integer g = 0
local string chars = "abcdefghijklmnopqrstuvwxyz0123456789 -=,."
local integer array map
local boolean array blocked
// check for Secret Modes
local player p1 = null
local player p2 = null
local integer m = 1
local real n = 0.
local real b = 0.
//precompute mapping [have to avoid invalid and normal handicaps]
set blocked[0] = true
set blocked[50] = true
set blocked[60] = true
set blocked[70] = true
set blocked[80] = true
set blocked[90] = true
set blocked[100] = true
set i = 0
set j = 0
loop
if blocked[j] then
set j = j + 1
endif
exitwhen j >= 256
set map[j] = i
set i = i + 1
set j = j + 1
endloop
//Extract command string from player handicaps
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
set h = R2I(100*GetPlayerHandicap(GetPlayer(i))+0.5)
if not blocked[h] then
set h = map[h]
set v = h/6
set h = h-v*6
call SetPlayerHandicap(GetPlayer(i), 0.5 + h/10.0)
set udg_Mode_Command = udg_Mode_Command + SubString(chars, v, v+1)
endif
set i = i + 1
endloop
// Check for Special Modes
loop
exitwhen m > GetMaxHumanPlayers()
if (GetPlayerSlotState(Player(m-1)) != PLAYER_SLOT_STATE_EMPTY) then
if n == 0. then
set n = Pow(GetPlayerHandicap(GetPlayer(m)),2)
set p1 = GetPlayer(m)
elseif b == 0. then
set b = Pow(GetPlayerHandicap(GetPlayer(m)),2)
set p2 = GetPlayer(m)
exitwhen true
endif
endif
set m = m + 1
endloop
//! Secret Modes
//60/90 league
//80/50 beta
//90/60 league imitation
//argument = (((value/100)^2)^2)*7*10; example for 60: (((60/100)^2)^2)*7*10=9.072
if n == Code(9.072) and b == Code(45.927) then
// league
set LeagueConfirmed = true
set SpecialMode = true
call ResetHandicap()
endif
if n == Code(28.672) and b == Code(4.375) then
// beta
set OpenBeta = BetaMode
set SpecialMode = BetaMode
call ResetHandicap()
endif
if n == Code(45.927) and b == Code(9.072) then
// league imitation
set LeagueImitation = true
set SpecialMode = true
call ResetHandicap()
endif
if (udg_Mode_Command != "") then
if GetHostBotMode()==GAME_MODE_UNKNOWN and HostBotAllowsAlternative() then
loop
call DisplayTimedTextToPlayer(Player(g), 0, 0, 20.00, "Received invalid mode command (" + udg_Mode_Command + ")")
set g = g + 1
exitwhen g == 11
endloop
set udg_Mode_Command = ""
endif
endif
if SpecialMode then
set udg_Mode_Command = ""
set udg_ProMode = false
set udg_NoTrader = false
set udg_NoTinker = false
set udg_NoExploder = false
set udg_CV = false
set udg_StartingGold = 3000
set udg_HighTech = false
set udg_ExtRequirements = false
set udg_TankMonopoly = false
endif
set p1 = null
set p2 = null
endfunction
endlibrary
//TESH.scrollpos=3
//TESH.alwaysfold=0
function B2S takes boolean bool returns string
// Used for text output
if bool then
return "|cff00ff00enabled" //green
endif
return "|cffff0000disabled" //red
endfunction
function Trig_Mode_Dialog_Options_CustomOptionEnabled takes nothing returns boolean
// Return true if any custom mode options is selected
if udg_StartingGold!=3000 or udg_Fog or udg_CV or udg_TankMonopoly then
return true
elseif udg_NoTinker or udg_NoTrader or udg_NoExploder then
return true
elseif udg_HighTech or udg_ExtRequirements or udg_NoRequirements then
return true
endif
return false
endfunction
// The click event for the options dialog
function Trig_Mode_Dialog_Options_Actions takes nothing returns nothing
local button Button = GetClickedButton()
local integer i = 1
local string text
local boolean returnToMainMenu = false
// Change Options
if (Button == udg_CustomOptions_Button[1]) and (OptionDialogPage == 1) then
if udg_StartingGold==5000 then
set udg_StartingGold = 3000
else
set udg_StartingGold = 5000
endif
set text = "Gold has been set to |cfffed312"+I2S(udg_StartingGold)+"|r."
elseif (Button == udg_CustomOptions_Button[2]) and (OptionDialogPage == 1) then
if udg_StartingGold==10000 then
set udg_StartingGold = 3000
else
set udg_StartingGold = 10000
endif
set text = "Gold has been set to |cfffed312"+I2S(udg_StartingGold)+"|r."
elseif (Button == udg_CustomOptions_Button[3]) and (OptionDialogPage == 1) then
set udg_HighTech = not udg_HighTech
set text = "High Tech has been "+B2S(udg_HighTech)
elseif (Button == udg_CustomOptions_Button[4]) and (OptionDialogPage == 1) then
set udg_CV = not udg_CV
set text = "Conquest Victory has been "+B2S(udg_CV)
elseif (Button == udg_CustomOptions_Button[5]) and (OptionDialogPage == 1) then
set udg_TankMonopoly = not udg_TankMonopoly
set text = "Tank Monopoly has been "+B2S(udg_TankMonopoly)
elseif (Button == udg_CustomOptions_Button[6]) and (OptionDialogPage == 1) then
set udg_Fog = not udg_Fog
set text = "Fog has been "+B2S(udg_Fog)
elseif (Button == udg_CustomOptions_Button[7]) and (OptionDialogPage == 1) then
set OptionDialogPage = 2
set text = " "
elseif (Button == udg_CustomOptions_Button[1]) and (OptionDialogPage == 2) then
set udg_NoTinker = not udg_NoTinker
set text = "Tinker has been "+B2S(not udg_NoTinker)
elseif (Button == udg_CustomOptions_Button[2]) and (OptionDialogPage == 2) then
set udg_NoTrader = not udg_NoTrader
set text = "Trader has been "+B2S(not udg_NoTrader)
elseif (Button == udg_CustomOptions_Button[3]) and (OptionDialogPage == 2) then
set udg_NoExploder = not udg_NoExploder
set text = "Exploder has been "+B2S(not udg_NoExploder)
elseif (Button == udg_CustomOptions_Button[4]) and (OptionDialogPage == 2) then
set udg_NoRequirements = not udg_NoRequirements
set text = "No Requirements has been "+B2S(udg_NoRequirements)
if udg_ExtRequirements and udg_NoRequirements then
set udg_ExtRequirements = false
endif
elseif (Button == udg_CustomOptions_Button[5]) and (OptionDialogPage == 2) then
set udg_ExtRequirements = not udg_ExtRequirements
set text = "Extended Requirements has been "+B2S(udg_ExtRequirements)
if udg_ExtRequirements and udg_NoRequirements then
set udg_NoRequirements = false
endif
// Change Dialog Page
elseif (Button == udg_CustomOptions_Button[6]) and (OptionDialogPage == 2) then
set OptionDialogPage = 1
set text = " "
// Return to Main menu
elseif Button == udg_CustomOptions_Button[10] then
set returnToMainMenu = true
if Trig_Mode_Dialog_Options_CustomOptionEnabled() then
if ModeEnabled[GAME_MODE_NORMAL] != false then
set ModeEnabled[GAME_MODE_NORMAL] = false
set text = "Normal Mode has been " + B2S(ModeEnabled[GAME_MODE_NORMAL])
call DisplayTimedTextToPlayer(udg_GameMode_Host, 0,0,15.00, text )
endif
if ModeEnabled[GAME_MODE_LEAGUE] != false then
set ModeEnabled[GAME_MODE_LEAGUE] = false
set text = "League Mode has been " + B2S(ModeEnabled[GAME_MODE_LEAGUE])
call DisplayTimedTextToPlayer(udg_GameMode_Host, 0,0,15.00, text )
endif
if ModeEnabled[GAME_MODE_ALTERNATIVE] == false then
set ModeEnabled[GAME_MODE_ALTERNATIVE] = true
set text = "Alternative Mode has been " + B2S(ModeEnabled[GAME_MODE_ALTERNATIVE])
call DisplayTimedTextToPlayer(udg_GameMode_Host, 0,0,15.00, text )
endif
else
if not ModeEnabled[GAME_MODE_NORMAL] then
set ModeEnabled[GAME_MODE_NORMAL] = true
set text = "Normal Mode has been " + B2S(ModeEnabled[GAME_MODE_NORMAL])
call DisplayTimedTextToPlayer(udg_GameMode_Host, 0,0,15.00, text )
endif
if not ModeEnabled[GAME_MODE_LEAGUE] then
set ModeEnabled[GAME_MODE_LEAGUE] = true
set text = "League Mode has been " + B2S(ModeEnabled[GAME_MODE_LEAGUE])
call DisplayTimedTextToPlayer(udg_GameMode_Host, 0,0,15.00, text )
endif
if ModeEnabled[GAME_MODE_ALTERNATIVE] then
set ModeEnabled[GAME_MODE_ALTERNATIVE] = false
set text = "Alternative Mode has been " + B2S(ModeEnabled[GAME_MODE_ALTERNATIVE])
call DisplayTimedTextToPlayer(udg_GameMode_Host, 0,0,15.00, text )
endif
endif
set text = ""
endif
if text != "" then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0,0,15.00, text )
endif
if returnToMainMenu then
call ShowModeDialog_Main()
else
call ShowModeDialog_Options()
endif
endfunction
//===========================================================================
function InitTrig_Mode_Dialog_Options takes nothing returns nothing
set gg_trg_Mode_Dialog_Options = CreateTrigger( )
call TriggerRegisterDialogEventBJ( gg_trg_Mode_Dialog_Options, udg_CustomOptions_Dialog )
call TriggerAddAction( gg_trg_Mode_Dialog_Options, function Trig_Mode_Dialog_Options_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
// The click event for the main dialog
function Trig_Mode_Dialog_Main_Actions takes nothing returns nothing
local integer clickedButton = 1
// Loop through buttons until the right button is found
loop
exitwhen clickedButton>5 or (GetClickedButton() == udg_GameMode_Button[clickedButton])
set clickedButton = clickedButton + 1
endloop
if clickedButton==5 then
// Options
call ShowModeDialog_Options()
elseif not ModeEnabled[clickedButton] then
// Mode disabled
call ShowModeDialog_Main()
else
// Valid mode selected, start game
set udg_GameMode = clickedButton
call TriggerExecute(gg_trg_Start_Game)
endif
endfunction
//===========================================================================
function InitTrig_Mode_Dialog_Main takes nothing returns nothing
set gg_trg_Mode_Dialog_Main = CreateTrigger( )
call TriggerRegisterDialogEventBJ( gg_trg_Mode_Dialog_Main, udg_GameMode_Dialog )
call TriggerAddAction( gg_trg_Mode_Dialog_Main, function Trig_Mode_Dialog_Main_Actions )
endfunction
//TESH.scrollpos=94
//TESH.alwaysfold=0
library ModeManager initializer Init requires ModeHostbot, MapAttachedSettings
// Sets up the mode, using the other mode libraries.
globals
timer udg_Mode_Timer = CreateTimer()
endglobals
// Called by a timer to show that the mode is locked
function ShowGameModeLocked takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 20, "The game mode is locked now.")
call ShowSpecialOptions(null)
call ReleaseTimer(GetExpiredTimer())
endfunction
// Exit game
function BetaCancel takes nothing returns nothing
local integer co = 0
loop
exitwhen co >= 10
call CustomDefeatBJ( Player(co), "BT Beta not officially hosted." )
set co = co + 1
endloop
endfunction
// Refresh and show the dialog for options
function ShowModeDialog_Options takes nothing returns nothing
local integer i = 1
call DialogClear( udg_CustomOptions_Dialog )
if (OptionDialogPage == 1) then
call DialogSetMessage( udg_CustomOptions_Dialog, "Options 1" )
set udg_CustomOptions_Button[1] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_StartingGold==5000, true) + "5000 Gold|r |cffffffff[1]", 49 )
set udg_CustomOptions_Button[2] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_StartingGold==10000, true) + "10000 Gold|r |cffffffff[2]", 50 )
set udg_CustomOptions_Button[3] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_HighTech, true) + "High Tech|r |cffffffff[3]", 51 )
set udg_CustomOptions_Button[4] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_CV, true) + "Conquest Victory|r |cffffffff[4]",52 )
set udg_CustomOptions_Button[5] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_TankMonopoly, true) + "Tank Monopoly|r |cffffffff[5]" ,53 )
set udg_CustomOptions_Button[6] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_Fog, true) + "Fog|r |cffffffff[6]", 54 )
set udg_CustomOptions_Button[7] = DialogAddButton( udg_CustomOptions_Dialog, "Next page|r |cffffffff[7]", 55 )
set udg_CustomOptions_Button[8] = null
set udg_CustomOptions_Button[9] = null
set udg_CustomOptions_Button[10] = DialogAddButton( udg_CustomOptions_Dialog, "|cfffe8a0eBack (Game-Modes)|r |cffffffff[0]", 48 )
else
call DialogSetMessage( udg_CustomOptions_Dialog, "Options 2" )
set udg_CustomOptions_Button[1] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_NoTinker, true) + "No Tinker|r |cffffffff[1]", 49 )
set udg_CustomOptions_Button[2] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_NoTrader, true) + "No Trader|r |cffffffff[2]", 50 )
set udg_CustomOptions_Button[3] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_NoExploder, true) + "No Exploder|r |cffffffff[3]", 51 )
set udg_CustomOptions_Button[4] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_NoRequirements, true) + "No Requirements|r |cffffffff[4]", 52 )
set udg_CustomOptions_Button[5] = DialogAddButton( udg_CustomOptions_Dialog, BooleanToColor(udg_ExtRequirements, true) + "Extended Requirements|r |cffffffff[5]", 53 )
set udg_CustomOptions_Button[6] = DialogAddButton( udg_CustomOptions_Dialog, "Previous page|r |cffffffff[6]", 54 )
set udg_CustomOptions_Button[7] = null
set udg_CustomOptions_Button[8] = null
set udg_CustomOptions_Button[9] = null
set udg_CustomOptions_Button[10] = DialogAddButton( udg_CustomOptions_Dialog, "|cfffe8a0eBack (Game-Modes)|r |cffffffff[0]", 48 )
endif
call DialogDisplay( udg_GameMode_Host, udg_CustomOptions_Dialog, true )
endfunction
// Refresh and show the dialog for modes
function ShowModeDialog_Main takes nothing returns nothing
local integer i = 1
local integer iEnd = 5
call DialogClear( udg_GameMode_Dialog )
call DialogSetMessage( udg_GameMode_Dialog, "Game-Mode" )
if udg_Mode_Command == ModeBotNoOptions then
set iEnd = 4
endif
loop
exitwhen i > iEnd
if ModeEnabled[i] then
set udg_GameMode_Name[i] = Cgreen+ModeName[i]
else
set udg_GameMode_Name[i] = Cgrey+ModeName[i]
endif
set udg_GameMode_Button[i] = DialogAddButton( udg_GameMode_Dialog, udg_GameMode_Name[i] + " |cffffffff["+I2S(i)+"]", 48+i)
set i = i + 1
endloop
call DialogDisplay( udg_GameMode_Host, udg_GameMode_Dialog, true )
endfunction
private function TimerOver takes nothing returns nothing
// Hide dialogs and set mode to normal
call DialogDisplay( udg_GameMode_Host, udg_GameMode_Dialog, false )
call DialogDisplay( udg_GameMode_Host, udg_CustomOptions_Dialog, false )
set udg_GameMode = GAME_MODE_NORMAL
call TriggerExecute(gg_trg_Start_Game)
endfunction
private function InitDialog takes nothing returns nothing
// The core function starting all the mode decisions
local integer i = 1
local integer j = 20
loop
exitwhen i > 5
set ModeEnabled[i] = true
set i = i + 1
endloop
set ModeEnabled[3] = false
set i = 1
set VipGame = (IsVipInGame() and VIPCheck)
// Somehow dialogs don't like to be created at map initialization
call DialogSetMessage( udg_Afk_Dialog, "Away..." )
call DialogAddButton( udg_Afk_Dialog, "|cfffed312Back|r", 49 )
// Determine the host, just the first player in the game
set udg_GameMode_Host = null
loop
exitwhen i > GetMaxHumanPlayers() or (udg_PlayerIn[i] and not IsAI(i))
set i = i + 1
endloop
if i<=GetMaxHumanPlayers() then
set udg_GameMode_Host = GetPlayer(i)
endif
if BetaMode and not OpenBeta then
if bj_isSinglePlayer or VipGame then
set OpenBeta = true
else
call BetaCancel()
return
endif
endif
// 3000 gold, if nothing else is set
set udg_StartingGold = 3000
set udg_GameMode = GetHostBotMode()
if udg_GameMode==GAME_MODE_UNKNOWN then
if udg_GameMode_Host==null then
set udg_GameMode=GAME_MODE_NORMAL
call TriggerExecute(gg_trg_Start_Game)
else
call TriggerRegisterPlayerEventLeave(gg_trg_Mode_Dialog_Main, udg_GameMode_Host )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00, udg_Color[GetPlayerNr(udg_GameMode_Host)] + GetPlayerName(udg_GameMode_Host)+"|r has |cffff000045|r seconds to choose a mode now.")
call TimerStart(udg_Mode_Timer,45.,false,function TimerOver)
call ShowModeDialog_Main()
endif
else
call SetHostBotOptions()
call TriggerExecute(gg_trg_Start_Game)
endif
endfunction
private function Init takes nothing returns nothing
local trigger m = CreateTrigger()
call TriggerRegisterTimerEventSingle(m, 0.01 )
call TriggerAddAction(m, function InitDialog)
call TimerStart(CreateTimer(), 120.0, false, function ShowGameModeLocked )
endfunction
endlibrary
//TESH.scrollpos=42
//TESH.alwaysfold=0
function Trig_Start_Game_Actions takes nothing returns nothing
local integer i = 0
local integer Id = 1
if udg_Mode_Timer!=null then
call ReleaseTimer(udg_Mode_Timer)
endif
set udg_Mode_Timer = null
call DestroyTrigger(gg_trg_Mode_Dialog_Main)
call DestroyTrigger(gg_trg_Mode_Dialog_Options)
call StartSound( gg_snd_Hint )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00, "Welcome to |cffff0000Battle Tanks|r. If this is your first game, read the " )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00, ( "tooltips of your |cfffed312Pilot|r, or press (|cfffed312F9|r). Game-Mode: " + Cgreen+ModeName[udg_GameMode]+"|r") )
if bj_isSinglePlayer then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00, " " )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00, "This is a singleplayer game. The following commands are available: -gold, -xp, -showrange x (x has to be between 0 and 3)" )
endif
if udg_GameMode == GAME_MODE_LEAGUE then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00, " " )
if LeagueConfirmed then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00,LeagueWelcome1)
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00,LeagueWelcome2)
else
set LeagueImitation = true
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00,LeagueWelcome3)
endif
endif
set IncomeFactor = 1.0
if udg_GameMode == GAME_MODE_ROYAL_FLUSH then
set KillDeathBountyInfluence = 1.00
set BasicBounty = 0.35
set GeneralGoldFactor = 2.00
set udg_ExtRequirements = true
set udg_NoRequirements = false
elseif udg_GameMode == GAME_MODE_ALTERNATIVE then
set KillDeathBountyInfluence = 0.50
set BasicBounty = 0.65
if udg_ProMode then
set IncomeFactor = 1.00
set KillDeathBountyInfluence = 0.20
set BasicBounty = 0.75
endif
elseif udg_GameMode == GAME_MODE_LEAGUE then
set KillDeathBountyInfluence = 0.20
set BasicBounty = 0.75
set udg_NoTrader = true
set udg_NoExploder = true
else // GAME_MODE_NORMAL
set KillDeathBountyInfluence = 0.45
set BasicBounty = 0.70
endif
if udg_Fog then
call EnableTrigger( gg_trg_Fog_Modifier )
call TriggerExecute( gg_trg_Fog_Modifier )
endif
if not udg_NoTrader then
call TriggerExecute( gg_trg_Trader_Init )
endif
if udg_HighTech then
loop
exitwhen Id > GetMaxPlayers()
if udg_Tank[Id]!=null then
call SuspendHeroXP( udg_Tank[Id], false )
call SetHeroLevel( udg_Tank[Id],10, false )
call SuspendHeroXP( udg_Tank[Id], true )
endif
call SetPlayerTechResearched( GetPlayer(Id), 'R003', 5 )
call SetPlayerTechResearched( GetPlayer(Id), 'R002', 5 )
set Id = Id + 1
endloop
endif
if udg_NoRequirements then
set i = GetPlayerTechMaxAllowed(udg_Force[1], 'R008')
else
if udg_ExtRequirements then
set i = GetPlayerTechCount(udg_Force[1], 'R002', true)
else
// set the value to the last tank, that is available without requiring armor upgrades (Frost Robot)
set i = 11
endif
endif
set Id = 1
loop
exitwhen Id > GetMaxPlayers()
call SetPlayerTechResearched( GetPlayer(Id), 'R008', i )
call SetPlayerTechResearched( GetPlayer(Id), 'R009', i )
set Id = Id + 1
endloop
set i = 1
loop
exitwhen i > 10
if udg_Tank[i]!=null then
call SuspendHeroXP( udg_Tank[i], false )
endif
set i = i + 1
endloop
call PauseAllUnitsBJ( false )
call EnableTrigger( gg_trg_Kick_Start )
call EnableTrigger( gg_trg_GiveUp_Vote )
if not IsTriggerEnabled(gg_trg_Camera) then
call EnableTrigger(gg_trg_Camera)
endif
//call EnableTrigger( gg_trg_Player_Income )
call GiveStartingGold(udg_StartingGold)
// Check for players who have already left,
// but the event was supressed in the starting phase to
// completely initialize this player before.
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if udg_PlayerIn[i] and (GetPlayerSlotState(GetPlayer(i)) == PLAYER_SLOT_STATE_LEFT) then
set udg_Leaver = GetPlayer(i)
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetPlayerName(udg_Leaver) + " has left the game." )
call StartSound( gg_snd_Leave )
call TriggerExecute( gg_trg_Player_Remove )
endif
set i = i + 1
endloop
// Begin the AI loops, this call should be remove some day
call BeginAI()
endfunction
//===========================================================================
function InitTrig_Start_Game takes nothing returns nothing
set gg_trg_Start_Game = CreateTrigger( )
call TriggerAddAction( gg_trg_Start_Game, function Trig_Start_Game_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
library VipList
globals
integer udg_VipGameMode = 0
endglobals
private function IsVipInGame_Check takes nothing returns nothing
local string array VipName
local string playerName
local integer i = 0
local integer nameid = 0
set VipName[0] = "Paladon"
set VipName[1] = "Velocity2k"
set VipName[2] = "Phoenix-Exodus"
set VipName[3] = "psycho_dmr"
set VipName[4] = "eSVau"
set VipName[5] = "Indeterminismus"
set VipName[6] = "Saiyuki"
set VipName[7] = "DerSatan"
set VipName[8] = "Metaller"
set VipName[9] = "sam_ach"
set VipName[10] = "Frechheit"
set VipName[11] = "ssl"
set VipName[12] = "LIoOoOoIL"
set VipName[13] = "Bob666"
// Make all names lower case
loop
exitwhen VipName[nameid]==null
set VipName[nameid]=StringCase(VipName[nameid],false)
set nameid = nameid + 1
endloop
// Set standard to no vip in game
set udg_VipGameMode=2
// Check vip state for all players
loop
exitwhen i > 11
set nameid = 0
set playerName = StringCase(GetPlayerName(Player(i)),false)
loop
exitwhen VipName[nameid]==null
if playerName == VipName[nameid] then
// We have a vip, set mode and return
set udg_VipGameMode = 1
return
endif
set nameid = nameid + 1
endloop
set i = i + 1
endloop
endfunction
function IsVipInGame takes nothing returns boolean
// 0 = not initialized
// 1 = vip in game
// 2 = no vip in game
if udg_VipGameMode==0 then
call IsVipInGame_Check()
endif
return udg_VipGameMode==1
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
globals
string array RandomColors[7]
endglobals
function Trig_BetaMessages_Actions takes nothing returns nothing
local integer random
if bj_isSinglePlayer or not OpenBeta then
// Once it turns out that this is no open beta, instantly destroy the trigger
call DestroyTrigger(GetTriggeringTrigger())
return
endif
set random = GetRandomInt(1,6)
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 20, RandomColors[random] + "This is a public beta test. For any bugs or problems, please use \"!report <your text here>\" or visit the bug report section of www.btanks.net!|r")
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 20, RandomColors[random] + "The Changelog is available under (F9).|r")
endfunction
//===========================================================================
function InitTrig_BetaMessages takes nothing returns nothing
set gg_trg_BetaMessages = CreateTrigger( )
set RandomColors[1] = "|cffff3333"
set RandomColors[2] = "|cff39b3d7"
set RandomColors[3] = "|cff8cc63f"
set RandomColors[4] = "|cff555555"
set RandomColors[5] = "|cff35d2ab"
set RandomColors[6] = "|cfff0ad4e"
call TriggerRegisterTimerEventPeriodic( gg_trg_BetaMessages, 200.00 )
call TriggerAddAction( gg_trg_BetaMessages, function Trig_BetaMessages_Actions )
endfunction
//TESH.scrollpos=138
//TESH.alwaysfold=0
scope CPSet initializer Init
globals
private boolean TotalEnd = false
endglobals
private function Trig_Control_Point_Conquest_Victory takes nothing returns nothing
local group G = NewGroup()
set bj_groupEnumTypeId = 'h00P'
call GroupEnumUnitsOfPlayer(G, udg_Force[1], filterGetUnitsOfTypeIdAll)
if FirstOfGroup(G)!=null then
set udg_Team_Winning = 1
call GroupClear(G)
else
set udg_Team_Winning = 2
endif
call ReleaseGroup(G)
set G = null
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 5.00, "|cfffed312Conquest Victory!|r" )
call DestroyTimerDialog( udg_CV_TimerWindow )
call TriggerExecute( gg_trg_Victory_Cinematic )
endfunction
private function Trig_Control_Point_TeamCPCheck takes nothing returns nothing
local integer HandleThisTeam = 0
local real TimeRemain
local unit PickUnit
if udg_Team_CPs[1] == 0 then
set HandleThisTeam = 1
elseif udg_Team_CPs[2] == 0 then
set HandleThisTeam = 2
endif
if udg_CV then
if HandleThisTeam !=0 then
if (udg_CV_Timer_Remain[HandleThisTeam] != 0) then
set TimeRemain = udg_CV_Timer_Remain[HandleThisTeam] + (udg_Time_Value - udg_CV_Timer_Stop[HandleThisTeam])/5
if TimeRemain > 900 then
set TimeRemain = 900
endif
else
set TimeRemain = 900
endif
if udg_Player_Team[GetPlayerNr(GetLocalPlayer())]==HandleThisTeam and GameOver == false then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "|cfffed312You will lose, if you do not conquer a Control Point.|r")
elseif GameOver == false then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "|cfffed312Hold all Control Points to win.|r")
endif
call TimerStart( udg_CV_Timer, TimeRemain, false, function Trig_Control_Point_Conquest_Victory )
set udg_CV_TimerWindow = CreateTimerDialog(udg_CV_Timer)
call TimerDialogSetTitle(udg_CV_TimerWindow, "Conquest Victory")
call TimerDialogDisplay(udg_CV_TimerWindow, true)
set udg_CV_Timer_Team = HandleThisTeam
else
call DebugMsg("Destroying CV timer")
call PauseTimer( udg_CV_Timer )
call DestroyTimerDialog( udg_CV_TimerWindow )
set udg_CV_TimerWindow=null
set udg_CV_Timer_Stop[udg_CV_Timer_Team] = udg_Time_Value
set udg_CV_Timer_Remain[udg_CV_Timer_Team] = TimerGetRemaining(udg_CV_Timer)
endif
endif
endfunction
private function Trig_Control_Point_SetManaLevel takes nothing returns nothing
if GetUnitState(GetEnumUnit(), UNIT_STATE_LIFE) > 0 then
call SetUnitAbilityLevel( GetEnumUnit(), 'A090', udg_Team_CPs[udg_Player_Team[GetPlayerNr(GetOwningPlayer(GetEnumUnit()))]] + 1 )
endif
endfunction
private struct CPCon
private unit cp
private integer cpbounty
private integer id
private integer state
private real progress = 0
private static CPCon array indx
private static integer counter = 0
private static timer time = CreateTimer()
//private static real progress = 0
static method Execution takes nothing returns nothing
local CPCon d
local string basic = "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
local integer i = 0
local integer r = 0
local integer leftSeconds = 0
local integer Conqueror = 0
local real inc = 1
local unit u = null
local boolean NearbyAlly
local boolean NearbyEnemy
local boolean Barricade
local boolean UnitSelected
local boolean array Conquered
local integer OwningTeam
local player Owner
local string timerstring = ""
local group G = NewGroup()
loop
exitwhen i > GetMaxHumanPlayers()
set Conquered[i] = false
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= CPCon.counter
set d = CPCon.indx[i]
if d.state == 0 then
//! Recycle instance
set d.progress = 0
call SetUnitUserData(d.cp, 0 )
call SetTextTagVisibility( udg_Progress_Bar[10 + d.id], false )
call SetTextTagVisibility( udg_Progress_Timer[10 + d.id], false )
set d.cp = null
call d.destroy()
set CPCon.counter = CPCon.counter - 1
set CPCon.indx[i] = d.indx[CPCon.counter]
set i = i - 1
elseif d.state == 1 then
//! conquer
set Owner = GetOwningPlayer(d.cp)
set OwningTeam = udg_Player_Team[GetPlayerNr(Owner)]
call GroupEnumUnitsInRange(G, GetUnitX(d.cp), GetUnitY(d.cp), 500, FILTER_TOWER_OR_HERO)
set NearbyAlly = false
set NearbyEnemy = false
set Barricade = false
set Conqueror = 0
loop
set u = FirstOfGroup( G )
exitwhen u == null
if IsUnitAlly(u, Owner) then
if (GetUnitTypeId(u) == 'o000') then
set Barricade = true
else
set NearbyAlly = true
endif
elseif IsUnitEnemy(u, Owner) then
set NearbyEnemy = true
set Conqueror = Conqueror + 1
endif
call GroupRemoveUnit(G,u)
endloop
call GroupClear(G)
if NearbyEnemy then
//Speed increases, when more enemies are near; 1 enemy = normal speed; 5 enemies = twice the speed
set inc = 1.0 + ((Conqueror - 1.0) / 4.0)
if Barricade then
set inc = inc * 2
else
set inc = inc * 4
endif
if not NearbyAlly then
// Control Point is being taken over
set d.progress = d.progress + inc
call SetUnitUserData( d.cp, 1 )
if d.progress >= 160 then
//! CONQUERED!
call GroupEnumUnitsInRange(G, GetUnitX(d.cp), GetUnitY(d.cp), 500, FILTER_TOWER_OR_HERO)
loop
set u = FirstOfGroup(G)
exitwhen u == null
if IsUnitEnemy(u, GetOwningPlayer(d.cp)) then
if u == udg_Tank[GetPlayerNr(GetOwningPlayer(u))] then
//Conquered makes sure, that you won't get a double award for capturing with a tank and a building
if (Conquered[GetPlayerNr(GetOwningPlayer(u))] == false) then
set udg_Stats_CPs[GetPlayerNr(GetOwningPlayer(u))] = udg_Stats_CPs[GetPlayerNr(GetOwningPlayer(u))] + 1
call MB_SetSupport( GetPlayerNr(GetOwningPlayer(u)), 2.0 )
set Conquered[GetPlayerNr(GetOwningPlayer(u))] = true
endif
call SetPlayerStateBJ( GetOwningPlayer(u), PLAYER_STATE_RESOURCE_GOLD, ( GetPlayerState(GetOwningPlayer(u), PLAYER_STATE_RESOURCE_GOLD) + d.cpbounty ) )
set udg_Profit_Creeps[GetPlayerNr(GetOwningPlayer(u))] = udg_Profit_Creeps[GetPlayerNr(GetOwningPlayer(u))] + d.cpbounty
call ShowTextTag("|cfffed312+"+I2S(d.cpbounty)+"|r", u, 0, 0, GetOwningPlayer(u))
call UpdateBounty(GetOwningPlayer(u), d.cpbounty)
elseif IsUnitType(u, UNIT_TYPE_STRUCTURE) then
if (Conquered[GetPlayerNr(GetOwningPlayer(u))] == false) then
set udg_Stats_CPs[GetPlayerNr(GetOwningPlayer(u))] = udg_Stats_CPs[GetPlayerNr(GetOwningPlayer(u))] + 1
set Conquered[GetPlayerNr(GetOwningPlayer(u))] = true
endif
endif
endif
call GroupRemoveUnit(G, u)
endloop
call GroupClear(G)
set UnitSelected = false
if IsUnitSelected(d.cp, GetLocalPlayer()) == true then
set UnitSelected = true
endif
call SetUnitOwner(d.cp, GetPlayer(GetMaxPlayers()+1 - OwningTeam), true )
if UnitSelected then
call SelectUnit(d.cp, true )
endif
set udg_Team_CPs[OwningTeam] = udg_Team_CPs[OwningTeam] - 1
set udg_Team_CPs[3 - OwningTeam] = udg_Team_CPs[3 - OwningTeam] + 1
// Sets the Mana-regeneration of the Troop Command Centers to the new CP-Ratio
call ForGroupBJ( GetUnitsOfTypeIdAll('h01K'), function Trig_Control_Point_SetManaLevel )
if udg_Player_Team[GetPlayerNr(GetLocalPlayer())]==OwningTeam then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "|cffff0000An enemy unit has conquered a Control Point.|r")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "|cff00ff00An allied unit has conquered a Control Point.|r")
endif
call PingMinimapEx(GetUnitX(d.cp), GetUnitY(d.cp), 0.8, 160, 160, 160, false)
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl", GetUnitX(d.cp), GetUnitY(d.cp) ) )
set d.progress = 0
call SetUnitUserData(d.cp, 0 )
call SetTextTagVisibility( udg_Progress_Bar[10 + d.id], false )
call SetTextTagVisibility( udg_Progress_Timer[10 + d.id], false )
call Trig_Control_Point_TeamCPCheck()
call StartSound( gg_snd_Conquer_Finish )
set d.state = 0
endif
endif
elseif d.progress != 0 then
// There are no nearby enemies
set inc = -2
set d.progress = d.progress + inc
if d.progress <= 0 then
call SetUnitUserData(d.cp, 0 )
set d.progress = 0
call SetTextTagVisibility( udg_Progress_Bar[10 + d.id], false )
call SetTextTagVisibility( udg_Progress_Timer[10 + d.id], false )
set d.state = 0
endif
elseif d.progress <= 0 then
call SetUnitUserData(d.cp, 0 )
set d.progress = 0
call SetTextTagVisibility( udg_Progress_Bar[10 + d.id], false )
call SetTextTagVisibility( udg_Progress_Timer[10 + d.id], false )
set d.state = 0
endif
set r = R2I(d.progress)
if r != 0 then
if r < 160 then
//r has to be an even number, or the progress bar will have display errors
if (ModuloInteger(r, 2) > 0) then
set r = r + 1
endif
call SetTextTagTextBJ( udg_Progress_Bar[10 + d.id], (udg_Color[13 - OwningTeam] + SubStringBJ(basic, 1, r) + "|r|cff000000" + SubStringBJ(basic, 1, (160 - r)) + "|r"), 5.00 )
set r = 160 - r
//treat it this way, so the progress bar slowly recovers to 10 seconds, instead of 20, since 10 is the standard value
if (inc == -2) then
set inc = 4
endif
set timerstring = ""
set leftSeconds = R2I(r / 16.0 / inc * 4.0) + 1
if (leftSeconds < 10) then
set timerstring = "0"
endif
set timerstring = timerstring + I2S(leftSeconds)
call SetTextTagTextBJ( udg_Progress_Timer[10 + d.id], (udg_Color[13 - OwningTeam] + timerstring + "|r"), 12.00 )
endif
endif
endif
set i = i + 1
endloop
set u = null
set i = 0
call ReleaseGroup(G)
set G = null
if CPCon.counter == 0 then
call PauseTimer(CPCon.time)
endif
endmethod
static method SetStruct takes unit u, integer idint, integer bounty returns nothing
local CPCon d = CPCon.allocate()
local CPCon Data
local integer i = 0
local boolean b = false
loop
exitwhen i >= CPCon.counter
set Data = CPCon.indx[i]
if Data.cp == u then
set b = true
exitwhen b
endif
set i = i + 1
endloop
if not b then
set d.cp = u
set d.id = idint
set d.cpbounty = bounty
set d.state = 1
if CPCon.counter == 0 then
call TimerStart(CPCon.time,0.25,true,function CPCon.Execution)
endif
set CPCon.indx[CPCon.counter] = d
set CPCon.counter = CPCon.counter + 1
endif
endmethod
static method Destroy takes unit u returns nothing
local CPCon d
local integer i = 0
loop
exitwhen i >= CPCon.counter
set d = CPCon.indx[i]
if d.cp == u then
set d.state = 0
endif
set i = i + 1
endloop
endmethod
endstruct
private function Actions takes nothing returns boolean
local string basic = "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
local boolean UnitSelected
local boolean CPTakenOver = false
local boolean NearbyAlly
local boolean NearbyEnemy
local boolean Barricade
local integer OwningTeam
local integer ID = 1
local integer i
local integer CPBounty = R2I(75*(GetBountyFactor()))*udg_GoldFactor
local player Owner
local unit PickUnit
local unit U
local group G
local integer amount = 0
local integer a2 = 0
local string timerstring
if TotalEnd then
return false
endif
set G = NewGroup()
loop
exitwhen ID > 6
set U = udg_Control_Point[ID]
if GameOver then
call CPCon.Destroy(U)
set TotalEnd = true
else
set Owner = GetOwningPlayer(U)
set OwningTeam = udg_Player_Team[GetPlayerNr(Owner)]
call GroupEnumUnitsInRange(G, GetUnitX(U), GetUnitY(U), 500, FILTER_TOWER_OR_HERO)
set NearbyAlly = false
set NearbyEnemy = false
set Barricade = false
loop
set PickUnit = FirstOfGroup( G )
exitwhen PickUnit == null
if IsUnitAlly(PickUnit, Owner) then
if (GetUnitTypeId(PickUnit) == 'o000') then
set Barricade = true
else
set NearbyAlly = true
endif
elseif IsUnitEnemy(PickUnit, Owner) then
set NearbyEnemy = true
endif
call GroupRemoveUnit( G, PickUnit )
endloop
if NearbyEnemy then
if not NearbyAlly then
if GetUnitUserData(U) == 0 then
if udg_Player_Team[GetPlayerNr(GetLocalPlayer())]==OwningTeam then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "|cffff0000An enemy unit starts to conquer a Control Point.|r")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "|cff00ff00An allied unit starts to conquer a Control Point.|r")
endif
call CPCon.SetStruct(U,ID,CPBounty)
call PingMinimapEx(GetUnitX(U), GetUnitY(U), 0.8, 160, 160, 160, false)
call SetTextTagVisibility( udg_Progress_Bar[10 + ID], true )
call SetTextTagVisibility( udg_Progress_Timer[10 + ID], true )
call SetTextTagTextBJ( udg_Progress_Timer[10 + ID], (udg_Color[13 - OwningTeam] + "10|r"), 12.00 )
call StartSound( gg_snd_Conquer_Start )
endif
endif
endif
endif
set ID = ID + 1
endloop
call ReleaseGroup(G)
set G = null
set U = null
set PickUnit = null
return false
endfunction
private function CreateFloating takes unit U, integer number returns nothing
local location P = Location(GetUnitX(U) - 50, GetUnitY(U) - 50)
call CreateTextTagLocBJ( "|cff000000|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||r", P, 0, 5.00, 100, 100, 100, 0 )
call SetTextTagVisibility(bj_lastCreatedTextTag, false)
set udg_Progress_Bar[number] = bj_lastCreatedTextTag
call RemoveLocation( P )
set P = Location(GetUnitX(U), GetUnitY(U))
call CreateTextTagLocBJ( "|cff00000010|r", P, 0, 5.00, 100, 100, 100, 0 )
call SetTextTagVisibility(bj_lastCreatedTextTag, false)
set udg_Progress_Timer[number] = bj_lastCreatedTextTag
call RemoveLocation( P )
set P = null
endfunction
private function Init_Delayed takes nothing returns nothing
// The control point trigger is very heave, so the idea is to
// move it at 0.5sec, 1.5sec, 2.5sec etc and hope, that other triggers
// will fire at 1.0, 2.0, 3.0,... seconds.
set gg_trg_Control_Point = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(gg_trg_Control_Point, 1.00 )
call TriggerAddCondition(gg_trg_Control_Point, Condition(function Actions ))
// It is safer to pause the timer before destroying it,
// because there are rumors that a destroyed timer can still fire the callback.
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
endfunction
private function Init takes nothing returns nothing
local integer i
//Control Points initially controlled by the Dark Force
set udg_Control_Point[1] = gg_unit_h00P_0142 //Control Point - left
set udg_Control_Point[2] = gg_unit_h00P_0100 //Control Point - mid
set udg_Control_Point[3] = gg_unit_h00P_0115 //Control Point - right
//Control Points initially controlled by the Light Force
set udg_Control_Point[4] = gg_unit_h00P_0119 //Control Point - left
set udg_Control_Point[5] = gg_unit_h00P_0034 //Control Point - mid
set udg_Control_Point[6] = gg_unit_h00P_0152 //Control Point - right
//Attach the floating conquer bar to the control points
set i = 1
loop
exitwhen i > 6
call CreateFloating( udg_Control_Point[i], 10 + i )
set i = i + 1
endloop
// Initialize main CP trigger after 0.5 seconds.
call TimerStart(CreateTimer(),0.5,false, function Init_Delayed)
endfunction
endscope
//TESH.scrollpos=18
//TESH.alwaysfold=0
globals
boolexpr FILTER_ADD_UNIT_FOG_MODIFIER
endglobals
function Trig_Fog_Modifier_UnitModifier takes nothing returns boolean
local unit U = GetFilterUnit()
if GetUnitState(U, UNIT_STATE_LIFE) > 0 then
if IsUnitType(U, UNIT_TYPE_HERO) then
set udg_Fog_Modifier_Max = udg_Fog_Modifier_Max + 1
set udg_Fog_Modifier[udg_Fog_Modifier_Max] = CreateFogModifierRadius(GetOwningPlayer(U), FOG_OF_WAR_VISIBLE, GetUnitX(U), GetUnitY(U), 1500, true, false)
call FogModifierStart(udg_Fog_Modifier[udg_Fog_Modifier_Max])
elseif IsUnitType(U, UNIT_TYPE_STRUCTURE) or GetUnitTypeId(U) == 'o001' or GetUnitTypeId(U) == 'o002' then
set udg_Fog_Modifier_Max = udg_Fog_Modifier_Max + 1
set udg_Fog_Modifier[udg_Fog_Modifier_Max] = CreateFogModifierRadius(GetOwningPlayer(U), FOG_OF_WAR_VISIBLE, GetUnitX(U), GetUnitY(U), 1300, true, false)
call FogModifierStart(udg_Fog_Modifier[udg_Fog_Modifier_Max])
endif
endif
set U = null
return false
endfunction
globals
integer array udg_Fog_PlayerInDarkness
endglobals
function Trig_Fog_Modifier_Actions takes nothing returns nothing
local integer i = 1
local group G
loop
exitwhen i > udg_Fog_Modifier_Max
call DestroyFogModifier( udg_Fog_Modifier[i] )
set udg_Fog_Modifier[i] = null
set i = i + 1
endloop
set i = 1
if udg_Team_Winning == 0 then
set udg_Fog_Modifier_Max = 0
set G = NewGroup()
loop
exitwhen i > GetMaxPlayers()
if udg_Fog_PlayerInDarkness[i]==0 then
if udg_Fog then
call GroupEnumUnitsOfPlayer(G, GetPlayer(i), FILTER_ADD_UNIT_FOG_MODIFIER)
else
set udg_Fog_Modifier_Max = udg_Fog_Modifier_Max + 1
set udg_Fog_Modifier[udg_Fog_Modifier_Max] = CreateFogModifierRect(GetPlayer(i), FOG_OF_WAR_VISIBLE, udg_Playable_Map, true, false)
call FogModifierStart(udg_Fog_Modifier[udg_Fog_Modifier_Max])
endif
endif
set i = i + 1
endloop
call ReleaseGroup(G)
set G = null
else
loop
exitwhen i > GetMaxPlayers()
set udg_Fog_Modifier[i] = CreateFogModifierRect(GetPlayer(i), FOG_OF_WAR_VISIBLE, udg_Playable_Map, true, false)
call FogModifierStart(udg_Fog_Modifier[i])
set i = i + 1
endloop
set udg_Fog_Modifier_Max = i-1
endif
endfunction
//===========================================================================
function InitTrig_Fog_Modifier takes nothing returns nothing
set gg_trg_Fog_Modifier = CreateTrigger( )
set FILTER_ADD_UNIT_FOG_MODIFIER = Filter(function Trig_Fog_Modifier_UnitModifier)
call DisableTrigger( gg_trg_Fog_Modifier )
call TriggerRegisterTimerEvent(gg_trg_Fog_Modifier, 0.50, true)
call TriggerAddAction( gg_trg_Fog_Modifier, function Trig_Fog_Modifier_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Mill_Conditions takes nothing returns boolean
local integer Id = GetUnitTypeId(GetTriggerUnit())
// Zero, if one of them is zero => if Id=='n00D' or Id=='n00E', but faster
return ((Id-'n00D')*(Id-'n00E')==0)
endfunction
function Trig_Mill_Actions takes nothing returns nothing
call IssuePointOrder( GetTriggerUnit(), "move", GetRandomReal(GetRectMinX(gg_rct_Mill), GetRectMaxX(gg_rct_Mill)), GetRandomReal(GetRectMinY(gg_rct_Mill), GetRectMaxY(gg_rct_Mill)) )
endfunction
//===========================================================================
function InitTrig_Mill takes nothing returns nothing
set gg_trg_Mill = CreateTrigger( )
call TriggerRegisterLeaveRectSimple( gg_trg_Mill, gg_rct_Mill )
call TriggerAddCondition( gg_trg_Mill, Condition( function Trig_Mill_Conditions ) )
call TriggerAddAction( gg_trg_Mill, function Trig_Mill_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope StatProgress initializer Init
globals
real array Kills_StatsProgress[10][10]
real array Deaths_StatsProgress[10][10]
real array Support_StatsProgress[10][10]
endglobals
// tracks stat changes for the kick system and saves roughly when those happened in 2.5 min blocks
private function Actions takes nothing returns nothing
local integer i = 10
local integer j = 1
//call DebugMsg("Kills Player 1: " + Kills_StatsProgress[1][1] + " " + Kills_StatsProgress[1][2] + " " + Kills_StatsProgress[1][3] + " " + Kills_StatsProgress[1][4] + " " + Kills_StatsProgress[1][5] + " " + Kills_StatsProgress[1][6] + " " + Kills_StatsProgress[1][7] + " " + Kills_StatsProgress[1][8] + " " + Kills_StatsProgress[1][9] + " " + Kills_StatsProgress[1][10])
//call DebugMsg("Deaths Player 1: " + Deaths_StatsProgress[1][1] + " " + Deaths_StatsProgress[1][2] + " " + Deaths_StatsProgress[1][3] + " " + Deaths_StatsProgress[1][4] + " " + Deaths_StatsProgress[1][5] + " " + Deaths_StatsProgress[1][6] + " " + Deaths_StatsProgress[1][7] + " " + Deaths_StatsProgress[1][8] + " " + Deaths_StatsProgress[1][9] + " " + Deaths_StatsProgress[1][10])
//call DebugMsg("Deaths Player 1: " + Support_StatsProgress[1][1] + " " + Support_StatsProgress[1][2] + " " + Support_StatsProgress[1][3] + " " + Support_StatsProgress[1][4] + " " + Support_StatsProgress[1][5] + " " + Support_StatsProgress[1][6] + " " + Support_StatsProgress[1][7] + " " + Support_StatsProgress[1][8] + " " + Support_StatsProgress[1][9] + " " + Support_StatsProgress[1][10])
loop
exitwhen i < 1
set j = 0
loop
exitwhen j > 10
if (i == 1) then
set Kills_StatsProgress[j][i] = 0
set Deaths_StatsProgress[j][i] = 0
set Support_StatsProgress[j][i] = 0
else
set Kills_StatsProgress[j][i] = Kills_StatsProgress[j][i-1]
set Deaths_StatsProgress[j][i] = Deaths_StatsProgress[j][i-1]
set Support_StatsProgress[j][i] = Support_StatsProgress[j][i-1]
endif
set j = j + 1
endloop
set i = i - 1
endloop
set Kills_StatsProgress[j][i] = 0
set Deaths_StatsProgress[j][i] = 0
set Support_StatsProgress[j][i] = 0
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(t, 150.00)
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=73
//TESH.alwaysfold=0
scope TimerRun initializer Init
globals
string Current_Time_String = "|cff808080-0:00:10|r"
endglobals
private function IsLocalPlayerInCVTeam takes nothing returns boolean
return IsUnitAlly(udg_Control_Point[1], GetLocalPlayer())
endfunction
private function UpdateTimeString takes nothing returns nothing
local integer hour
local integer min
local integer sec
local string display = ""
set udg_Time_Value = udg_Time_Value + 1
set hour = udg_Time_Value / 3600
set min = udg_Time_Value/60 - 60*hour
set sec = udg_Time_Value - 3600*hour - 60*min
if udg_Time_Value < 0 then
set display = "|cff808080-"
set min = IAbsBJ(min)
set sec = IAbsBJ(sec)
endif
if min > 9 then
set display = display + I2S(hour) + ":" + I2S(min)
else
set display = display + I2S(hour) + ":0" + I2S(min)
endif
if sec > 9 then
set display = display + ":" + I2S(sec)
else
set display = display + ":0" + I2S(sec)
endif
if udg_Time_Value < 0 then
set display = display + "|r"
endif
set Current_Time_String = display
if not GameOver then
call UpdateBoardTime(display)
endif
endfunction
private function UpdateConquestVictoryTimer takes nothing returns nothing
local integer sec
if udg_CV_TimerWindow!=null then
set sec = R2I(TimerGetRemaining(udg_CV_Timer))
if sec == 30 then
if IsLocalPlayerInCVTeam() then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5.00, "|cfffed312Hold all Control Points for 30 seconds to win.|r" )
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5.00, "|cfffed312You will lose in 30 seconds, if you do not conquer a Control Point.|r" )
endif
elseif sec == 60 then
if IsLocalPlayerInCVTeam() then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5.00, "|cfffed312Hold all Control Points for 1 minute to win.|r" )
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5.00, "|cfffed312You will lose in 1 minute, if you do not conquer a Control Point.|r" )
endif
elseif sec == 120 or sec == 300 or sec == 600 then
if IsLocalPlayerInCVTeam() then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5.00, "|cfffed312Hold all Control Points for "+I2S(sec/60)+" minutes to win.|r" )
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5.00, "|cfffed312You will lose in "+I2S(sec/60)+" minutes, if you do not conquer a Control Point.|r" )
endif
endif
endif
endfunction
private function CheckKillingSprees takes nothing returns nothing
local integer i = 1
local texttag tag
local real PosX
local real PosY
local real PosZ
local boolean visibility
loop
exitwhen (i > GetMaxHumanPlayers())
if (udg_KillingSpree[i] > 2) and ((udg_Time_Value - udg_KillLast[i]) >180) then
set udg_KillingSpree[i] = 0
set tag = CreateTextTag( )
set PosX = GetUnitX(udg_Tank[i])
set PosY = GetUnitY(udg_Tank[i])
set PosZ = GetUnitFlyHeight(udg_Tank[i])
set visibility = (GetLocalPlayer() == GetOwningPlayer(udg_Tank[i]))
//s - string to be shown, including color code
call SetTextTagText(tag, "Killing Spree ended.", 0.020)
call SetTextTagPos(tag, PosX, PosY, PosZ)
call SetTextTagVisibility(tag, visibility)
call SetTextTagVelocity(tag, 0, -0.02)
call SetTextTagFadepoint(tag, 2.5 )
call SetTextTagLifespan(tag, 3 )
call SetTextTagPermanent(tag, false )
set tag = null
endif
set i = i + 1
endloop
endfunction
private function AIShopDebug takes nothing returns nothing
local integer i = 1
if IsTriggerEnabled(gg_trg_Actions_Per_Minute) then
loop
exitwhen i > GetMaxHumanPlayers()
//Workaround for stuck AI, trying to buy at the item shop
if udg_Time_Value-udg_ActionsLast[i]>=10 and (udg_AI_Command[i] == "itemshop" or udg_AI_Command[i] == "shop4") and udg_AI_IsBot[i] then
set udg_AI_Command[i] = "attack"
endif
set i = i + 1
endloop
endif
endfunction
private function Actions takes nothing returns nothing
call UpdateTimeString()
call UpdateConquestVictoryTimer()
call CheckKillingSprees()
call AIShopDebug()
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(t, 1.00)
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=27
//TESH.alwaysfold=0
function Trig_Tree_Death_Actions takes nothing returns nothing
local destructable Tree = GetDyingDestructable()
local real X = GetDestructableX(Tree)
local real Y = GetDestructableY(Tree)
local real durEffect1 = GetRandomReal(2,16)
local real durEffect2 = GetRandomReal(2,16)
local real durComplete = GetRandomReal(18,22)
local real r
local effect Effect1 = AddSpecialEffect("Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl",X+GetRandomReal(-50,50),Y+GetRandomReal(-50,50))
local effect Effect2 = AddSpecialEffect("Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl",X+GetRandomReal(-50,50),Y+GetRandomReal(-50,50))
local destructable TreeBurnt = CreateDestructable('B001', X, Y, 270, GetRandomReal(0.7,0.9), GetRandomInt(0,5))
local real beginGameTime = TimerGetElapsed(udg_GameTime)
if durEffect1 > durEffect2 then
set r = durEffect1
set durEffect1 = durEffect2
set durEffect2 = r
endif
if durComplete < durEffect2+6 then
set durComplete = durEffect2+6
endif
call SetDestructableAnimationSpeed( Tree, 0.5 )
call WaitForGameTime(beginGameTime+durEffect1)
call DestroyEffect(Effect1)
set Effect1 = null
call WaitForGameTime(beginGameTime+durEffect2)
call DestroyEffect(Effect2)
set Effect2 = null
call WaitForGameTime(beginGameTime+durComplete-6.0)
call SetDestructableAnimation( Tree, "birth" )
call WaitForGameTime(beginGameTime+durComplete-1.3)
call RemoveDestructable( TreeBurnt )
set TreeBurnt = null
call DestructableRestoreLife( Tree, GetDestructableMaxLife(Tree), false )
call WaitForGameTime(beginGameTime+durComplete-0.1)
call SetDestructableAnimationSpeed( Tree, 1.0 )
set Tree = null
endfunction
function InitTrig_Tree_Death_RegisterDeathEvent takes nothing returns nothing
if GetDestructableTypeId(GetEnumDestructable())=='ATtr' then
call TriggerRegisterDeathEvent(gg_trg_Tree_Death, GetEnumDestructable())
endif
endfunction
function InitTrig_Tree_Death takes nothing returns nothing
set gg_trg_Tree_Death = CreateTrigger()
// Enumeration only called once, no need to use a global boolexpr there
call EnumDestructablesInRect(GetWorldBounds(), FILTER_NULL, function InitTrig_Tree_Death_RegisterDeathEvent )
call TriggerAddAction(gg_trg_Tree_Death, function Trig_Tree_Death_Actions )
endfunction
//TESH.scrollpos=66
//TESH.alwaysfold=0
function Trig_Victory_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'h004'
endfunction
function Trig_Victory_Func032A takes nothing returns nothing
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_ZOFFSET, 0.00, 1.00 )
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_ANGLE_OF_ATTACK, 330.00, 1.00 )
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_TARGET_DISTANCE, 2000.00, 1.00 )
call PanCameraToTimedLocForPlayer( GetEnumPlayer(), GetUnitLoc(GetDyingUnit()), 1.00 )
if ( udg_Team_Winning == 1 ) then
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_ROTATION, 45.00, 1.00 )
else
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_ROTATION, 225.00, 1.00 )
endif
endfunction
function Trig_Victory_Func034A takes nothing returns nothing
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_ZOFFSET, 0.00, 0.00 )
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_ANGLE_OF_ATTACK, 330.00, 0.00 )
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_TARGET_DISTANCE, 2000.00, 0.00 )
call PanCameraToTimedLocForPlayer( GetEnumPlayer(), GetUnitLoc(GetDyingUnit()), 0.00 )
if ( udg_Team_Winning == 1 ) then
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_ROTATION, 45.00, 0.00 )
else
call SetCameraFieldForPlayer( GetEnumPlayer(), CAMERA_FIELD_ROTATION, 225.00, 0.00 )
endif
endfunction
function Trig_Victory_Func038A takes nothing returns nothing
call RotateCameraAroundLocBJ( 360.00, GetUnitLoc(GetTriggerUnit()), GetEnumPlayer(), 45.00 )
endfunction
function Trig_Victory_Func040002 takes nothing returns nothing
call CustomVictoryBJ( GetEnumPlayer(), false, true )
endfunction
function Trig_Victory_Actions takes nothing returns nothing
local integer i = 0
local unit U = GetTriggerUnit()
set GameOver = true
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Other\\Volcano\\VolcanoDeath.mdl", U, "origin" ) )
call DestroyEffect( AddSpecialEffectTarget( "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", U, "origin" ) )
if ( udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))] == 1 ) then
set udg_Team_Winning = 2
call LeagueWin(2)
else
set udg_Team_Winning = 1
call LeagueWin(1)
endif
call LeagueVars()
call ClearTextMessagesBJ( udg_Players )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 120.00, "|cffffe688Visit|r |cffff0000btanks.net|r |cffffe688for information, feedback or the league!|r" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 120.00, "|cffffe688Or write me an email: |r [email protected]" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 120.00, "|cfffed312===================================================|r" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 120.00, ( ( "|cffffe688" + GetPlayerName(udg_Force[udg_Team_Winning]) ) + " is victorious!|r" ) )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 120.00, "|cfffed312===================================================|r" )
call PauseTimer(udg_CV_Timer)
set i = 1
loop
exitwhen i > 10
call PauseTimer( udg_Tank_Timer[i] )
call DestroyTimerDialog( udg_Tank_TimerWindow[i] )
if ( GetUnitState(udg_Tank[i], UNIT_STATE_LIFE) > 0 ) then
call SetUnitInvulnerable( udg_Tank[i], true )
else
endif
set i = i + 1
endloop
call DisableTrigger( gg_trg_Control_Point )
call DisableTrigger( gg_trg_AI_Fight )
call DisableTrigger( gg_trg_Kick_Start )
call DisableTrigger( gg_trg_Kick_Vote )
call DisableTrigger( gg_trg_Kick_End )
call DisableTrigger( gg_trg_GiveUp_Vote )
call DisableTrigger( gg_trg_GiveUp_End )
call DisableTrigger( gg_trg_Player_Leaves )
call DisableTrigger( gg_trg_Player_Income )
call DisableTrigger( gg_trg_Camera )
call DisableTrigger( gg_trg_Unit_Spawn )
call DisableTrigger( gg_trg_Gold_Distribution )
call DisableTrigger( gg_trg_Timer )
call DisableTrigger( gg_trg_Dimension_Shift )
call PauseAllUnitsBJ( true )
if (udg_KickBoard != null) then
call DestroyLeaderboard( udg_KickBoard )
endif
call ForForce( udg_Players, function Trig_Victory_Func032A )
call GameTimeWait(1)
call ForForce( udg_Players, function Trig_Victory_Func034A )
call PlaySoundBJ( gg_snd_VictoryBG )
call PlaySoundBJ( gg_snd_Victory )
call TriggerSleepAction( 0.00 )
call ForForce( udg_Players, function Trig_Victory_Func038A )
call EndgameLeague()
call VictoryStats()
call GameTimeWait(45)
call ForForce( udg_Players, function Trig_Victory_Func040002 )
set U = null
endfunction
//===========================================================================
function InitTrig_Victory takes nothing returns nothing
set gg_trg_Victory = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Victory, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Victory, Condition( function Trig_Victory_Conditions ) )
call TriggerAddAction( gg_trg_Victory, function Trig_Victory_Actions )
endfunction
//TESH.scrollpos=78
//TESH.alwaysfold=0
library VicStats requires MapAttachedSettings
function VictoryStats takes nothing returns nothing
local integer i = 1
loop
exitwhen i > GetMaxPlayers()
//if udg_PlayerIn[i] then
set udg_MultiboardType[i-1] = SCORE_BOARD
call CreateNewMultiboard(GetPlayer(i))
if (GetLocalPlayer() == GetPlayer(i)) then
call MultiboardDisplay( udg_Killboard[i-1], true )
call MultiboardMinimize( udg_Killboard[i-1], false )
endif
//endif
set i = i + 1
endloop
endfunction
function VictoryStatsOld takes nothing returns nothing
local integer PlayerId
local integer StatId
local integer array StatVal
local string array StatName
local string s
local real waitGameTime = TimerGetElapsed(udg_GameTime)
set StatName[1] = "Tanks killed"
set StatName[2] = "Tank Killer"
set StatName[3] = "Bounty gained from tank kills"
set StatName[4] = "Bounty Hunter"
set StatName[5] = "Deaths"
set StatName[6] = "Survivor"
set StatName[7] = "Units"
set StatName[8] = "Troop Commander"
set StatName[9] = "Upgrades researched"
set StatName[10] = "Scientist"
set StatName[11] = "Vehicle Costs"
set StatName[12] = "Expensive Vehicle"
set StatName[13] = "Buildings destroyed"
set StatName[14] = "Destroyer"
set StatName[15] = "Troops killed"
set StatName[16] = "Troop Terminator"
set StatName[17] = "Buildings"
set StatName[18] = "Engineer"
set StatName[19] = "Trade profit"
set StatName[20] = "Trade Master"
set StatName[21] = "Control Points"
set StatName[22] = "Conquerer"
set StatName[23] = "Tank Level"
set StatName[24] = "Veteran"
set StatName[25] = "Chat Letters"
set StatName[26] = "Chat Master"
set StatName[27] = "Actions per Minute"
set StatName[28] = "Speed Freak"
set StatName[29] = "Kill Assists"
set StatName[30] = "Assistant"
set udg_Stats[5] = 100
set PlayerId = 1
loop
exitwhen PlayerId > GetMaxHumanPlayers()
set StatVal[1] = udg_Kills[PlayerId]
set StatVal[3] = TankBounty[PlayerId]
set StatVal[5] = udg_Deaths[PlayerId]
set StatVal[7] = udg_Stats_CreepBuy[PlayerId]
set StatVal[9] = udg_Stats_Upgrades[PlayerId]
set StatVal[11] = GetBounty(udg_Tank[PlayerId], false)
set StatVal[13] = GetPlayerScore(GetPlayer(PlayerId), PLAYER_SCORE_STRUCT_RAZED)
set StatVal[15] = udg_Stats_CreepKills[PlayerId]
set StatVal[17] = udg_Stats_Buildings[PlayerId]
set StatVal[19] = udg_Stats_Trader[PlayerId]
set StatVal[21] = udg_Stats_CPs[PlayerId]
set StatVal[23] = GetHeroXP(udg_Tank[PlayerId])
set StatVal[25] = udg_Stats_Chat[PlayerId]
set StatVal[27] = R2I(60*udg_Actions[PlayerId]/waitGameTime)
set StatVal[29] = udg_Assists[PlayerId]
set StatId = 1
loop
exitwhen StatId > 29
if StatId==5 then
if udg_Stats[StatId] > StatVal[StatId] and IsPlayerInForce(GetPlayer(PlayerId),udg_Players) then
set udg_Stats[StatId] = StatVal[StatId]
set udg_Stats[StatId+1] = PlayerId
endif
elseif udg_Stats[StatId] < StatVal[StatId] then
set udg_Stats[StatId] = StatVal[StatId]
set udg_Stats[StatId+1] = PlayerId
endif
set StatId = StatId + 2
endloop
set PlayerId = PlayerId + 1
endloop
set StatId = 2
loop
exitwhen StatId > 30
if udg_Stats[StatId] != 0 then
set s = StatName[StatId] + ": " + udg_Color[udg_Stats[StatId]] + GetPlayerName(GetPlayer(udg_Stats[StatId])) + "|r (" + StatName[StatId-1]
if StatId==24 then
set s = s + ": " + I2S(GetHeroLevel(udg_Tank[udg_Stats[StatId]])) + ")"
else
set s = s + ": " + I2S(udg_Stats[StatId-1]) + ")"
endif
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 120.00, s )
set waitGameTime = waitGameTime + 2.00
call WaitForGameTime(waitGameTime)
endif
set StatId = StatId + 2
endloop
endfunction
endlibrary
//TESH.scrollpos=4
//TESH.alwaysfold=0
function Trig_Victory_Cinematic_Actions takes nothing returns nothing
local unit HQDestroy = udg_HQ[3 - udg_Team_Winning]
local real X = GetUnitX(HQDestroy)
local real Y = GetUnitY(HQDestroy)
call DisableTrigger( gg_trg_Control_Point )
call DisableTrigger( gg_trg_AI_Fight )
call DisableTrigger( gg_trg_Kick_Vote )
call DisableTrigger( gg_trg_Kick_End )
call DisableTrigger( gg_trg_Player_Leaves )
call DisableTrigger( gg_trg_Player_Income )
call DisableTrigger( gg_trg_Unit_Spawn )
call DisableTrigger( gg_trg_Gold_Distribution )
call DisableTrigger( gg_trg_Timer )
call PauseAllUnitsBJ( true )
call PauseTimer( udg_CV_Timer )
call SetCameraField( CAMERA_FIELD_ZOFFSET, 0.00, 1.00 )
call SetCameraField( CAMERA_FIELD_ANGLE_OF_ATTACK, 330.00, 1.00 )
call SetCameraField( CAMERA_FIELD_TARGET_DISTANCE, 2000.00, 1.00 )
call PanCameraToTimed( X, Y, 1.00 )
if udg_Team_Winning == 1 then
call SetCameraField( CAMERA_FIELD_ROTATION, 45.00, 1.00 )
else
call SetCameraField( CAMERA_FIELD_ROTATION, 225.00, 1.00 )
endif
call TriggerSleepAction( 1.00 )
call KillUnit( HQDestroy )
set HQDestroy = null
endfunction
//===========================================================================
function InitTrig_Victory_Cinematic takes nothing returns nothing
set gg_trg_Victory_Cinematic = CreateTrigger( )
call TriggerAddAction( gg_trg_Victory_Cinematic, function Trig_Victory_Cinematic_Actions )
endfunction
function Trig_Weather_Change_Actions takes nothing returns nothing
set udg_Weather_Current = GetRandomInt(1, 8) //from 1 to 8 to increase the chance of normal weather
call EnableWeatherEffect( udg_Weather_Effects[1], udg_Weather_Enabled and udg_Weather_Current==1 )
call EnableWeatherEffect( udg_Weather_Effects[2], udg_Weather_Enabled and udg_Weather_Current==2 )
call EnableWeatherEffect( udg_Weather_Effects[3], udg_Weather_Enabled and udg_Weather_Current==3 )
call EnableWeatherEffect( udg_Weather_Effects[4], udg_Weather_Enabled and udg_Weather_Current==4 )
call EnableWeatherEffect( udg_Weather_Effects[5], udg_Weather_Enabled and udg_Weather_Current==5 )
call TimerStart(udg_Weather_Timer,GetRandomReal(150, 300),false,function Trig_Weather_Change_Actions)
endfunction
//===========================================================================
function InitTrig_Weather_Change takes nothing returns nothing
set gg_trg_Weather_Change = CreateTrigger( )
call TriggerAddAction( gg_trg_Weather_Change, function Trig_Weather_Change_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Actions_Per_Minute_Conditions takes nothing returns boolean
local integer i = GetPlayerNr(GetTriggerPlayer())
local unit U = GetTriggerUnit()
local string CurrentOrder = OrderId2String(GetUnitCurrentOrder(U))
//Don't count any actions, while you are willingly afk (AFK AI)
if (udg_Afk[i] == false) then
if i<=10 then
if (i == 1) then
//call DebugMsg("Action: " + I2S(GetIssuedOrderId()))
endif
if (udg_ActionsLast[i]<TimerGetElapsed(udg_GameTime)) and (not IsDummy(U)) then
set udg_Actions[i] = udg_Actions[i] + 1
set udg_ActionsLast[i] = TimerGetElapsed(udg_GameTime)
endif
endif
endif
//Units given an order from a player, won't follow the waypoints anymore
if (IsUnitType(U, UNIT_TYPE_HERO)==false) and (i<=GetMaxHumanPlayers()) and (CurrentOrder=="smart") and (IsAI(i)==false) then
call SetLaneCreepFlag(U, CF_MANUAL_CONTROL)
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Actions_Per_Minute takes nothing returns nothing
set gg_trg_Actions_Per_Minute = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Actions_Per_Minute, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Actions_Per_Minute, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
//call TriggerRegisterAnyUnitEventBJ( gg_trg_Actions_Per_Minute, EVENT_PLAYER_UNIT_ISSUED_ORDER ) //<- also counts most orders issued by triggers (e.g. SetUnitPosition is an order)
call TriggerAddCondition( gg_trg_Actions_Per_Minute, Condition( function Trig_Actions_Per_Minute_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Anti_Shared_Control_Reset takes nothing returns nothing
local integer i = 1
local integer j
loop
exitwhen i > GetMaxHumanPlayers()
if not udg_Afk[i] then
set j = 1
loop
exitwhen j > GetMaxHumanPlayers()
if i != j then
call SetPlayerAlliance(GetPlayer(i), GetPlayer(j), ALLIANCE_SHARED_CONTROL, false )
endif
set j = j + 1
endloop
endif
set i = i + 1
endloop
call ReleaseTimer(GetExpiredTimer())
endfunction
function Trig_Anti_Shared_Control_Actions takes nothing returns nothing
call TimerStart(NewTimer(),0.1,false,function Trig_Anti_Shared_Control_Reset)
endfunction
//===========================================================================
function InitTrig_Anti_Shared_Control takes nothing returns nothing
set gg_trg_Anti_Shared_Control = CreateTrigger( )
call TriggerAddAction( gg_trg_Anti_Shared_Control, function Trig_Anti_Shared_Control_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Anti_Team_Attack_Conditions takes nothing returns boolean
return IsUnitAlly(GetTriggerUnit(), GetOwningPlayer(GetAttacker()))
endfunction
function Trig_Anti_Team_Attack_Actions takes nothing returns nothing
if GetOwningPlayer(GetTriggerUnit()) != GetOwningPlayer(GetAttacker()) then
call IssueImmediateOrder( GetAttacker(), "stop" )
endif
endfunction
//===========================================================================
function InitTrig_Anti_Team_Attack takes nothing returns nothing
set gg_trg_Anti_Team_Attack = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Anti_Team_Attack, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_Anti_Team_Attack, Condition( function Trig_Anti_Team_Attack_Conditions ) )
call TriggerAddAction( gg_trg_Anti_Team_Attack, function Trig_Anti_Team_Attack_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Camera_Actions takes nothing returns nothing
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, udg_Cam_Distance, 1)
call SetCameraField(CAMERA_FIELD_ROTATION, udg_Cam_Angle, 1)
call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, 360-udg_Cam_AngleZ, 1)
call SetCameraField(CAMERA_FIELD_FARZ, 8000, 0)
endfunction
//===========================================================================
function InitTrig_Camera takes nothing returns nothing
set gg_trg_Camera = CreateTrigger( )
call DisableTrigger( gg_trg_Camera )
call TriggerRegisterTimerEventPeriodic( gg_trg_Camera, 0.10 )
call TriggerAddAction( gg_trg_Camera, function Trig_Camera_Actions )
endfunction
//TESH.scrollpos=65
//TESH.alwaysfold=0
scope DenialOfPlay initializer Init
globals
constant real ACTION_DELAY = 30.0 // how many seconds since the last player action to start the value addition
constant real ACTION_VALUE = 2.0 // the amount of points every second for doing no action
constant real DAMAGE_DELAY = 60.0 // how many seconds since the last damage against an enemy (or last creep kill) to start the value addition
constant real DAMAGE_VALUE = 1.0 // the amount of points every second for doing no damage or killing no creeps
constant real STAT_DELAY = 180.0 // how many seconds since the last stat change (k/d/a) to start the value addition
constant real STAT_VALUE = 1.0 // the amount of points every second for having static stats
constant real BASE_DELAY = 120.0 // how many seconds since the player last left the base to start the value addition
constant real BASE_VALUE = 1.0 // the amount of points every second for not leaving the base
constant real PENALTY_LIMIT = 300 // The amount of points that are needed to give a penalty to the player
constant real AFK_DELAY = 300 // The amount of seconds after which a tank is automatically set AFK
real array DenialScore[10]
endglobals
function DenialOfPlay_CheckLastAction takes integer playerId returns real
local real value = 0
if (udg_Time_Value-udg_ActionsLast[playerId] > ACTION_DELAY) then
set value = ACTION_VALUE
set udg_AFKTime[playerId] = udg_AFKTime[playerId] + 1
endif
if ((not udg_Afk[playerId]) and (udg_Time_Value-udg_ActionsLast[playerId] > AFK_DELAY)) then
call PlayerAfkActivate(GetPlayer(playerId),"No action for 5 minutes.", udg_LeaversToAI)
endif
return value
endfunction
function DenialOfPlay_CheckLastDamage takes integer playerId returns real
local real value = 0
if (udg_Time_Value-udg_DamageLast[playerId] > DAMAGE_DELAY) then
set value = DAMAGE_VALUE
endif
return value
endfunction
function DenialOfPlay_CheckLastStatChange takes integer playerId returns real
local real value = 0
if (udg_Time_Value-udg_StatLast[playerId] > STAT_DELAY) then
set value = STAT_VALUE
endif
return value
endfunction
function DenialOfPlay_CheckLastBaseExit takes integer playerId returns real
local real value = 0
if (udg_Player_Team[playerId] == 1) then
if (RectContainsCoords(gg_rct_Team_1_Base_Main, GetUnitX(udg_Tank[playerId]), GetUnitY(udg_Tank[playerId])) == false) then
set udg_BaseLast[playerId] = udg_Time_Value
endif
elseif (udg_Player_Team[playerId] == 2) then
if (RectContainsCoords(gg_rct_Team_2_Base_Main, GetUnitX(udg_Tank[playerId]), GetUnitY(udg_Tank[playerId])) == false) then
set udg_BaseLast[playerId] = udg_Time_Value
endif
endif
if (udg_Time_Value-udg_BaseLast[playerId] > BASE_DELAY) then
set value = BASE_VALUE
endif
return value
endfunction
// the purpose of this trigger is to detect not only afk players, but also players that are actively trying to sabotage the game by
// not participating, but still moving around
private function Actions takes nothing returns nothing
local integer i = 1
local real score = 0
loop
exitwhen (i > GetMaxHumanPlayers())
set score = 0
if (udg_PlayerIn[i]) then
if (udg_Tank[i] != null) and (GetUnitState(udg_Tank[i], UNIT_STATE_LIFE) > 0) then
set score = score + DenialOfPlay_CheckLastAction(i)
set score = score + DenialOfPlay_CheckLastDamage(i)
set score = score + DenialOfPlay_CheckLastStatChange(i)
set score = score + DenialOfPlay_CheckLastBaseExit(i)
// reduce the DenialScore if the player was not actively collecting points
// and don't increase the score for a single minor offense
if (score <= 1) then
set DenialScore[i] = RMaxBJ(DenialScore[i] - 0.25, 0)
else
set DenialScore[i] = DenialScore[i] + score
endif
if (DenialScore[i] >= PENALTY_LIMIT) then
call AddPlayerPenalty(i, PENALTY_MESSAGE_AFK)
set DenialScore[i] = DenialScore[i] - PENALTY_LIMIT
endif
endif
endif
set i = i + 1
endloop
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(t, 1.00)
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=72
//TESH.alwaysfold=0
function Trig_Gold_Distribution_Actions takes nothing returns nothing
local string TechName
local integer array MaxTechLevel
local integer array TechLevel
local integer array NewUpgrades
local integer CountTeamPlayers
local integer Tech = 0
local integer TechReq = 0
local integer GoldDivided
local integer team = 1
local integer UpGold
local integer j
local integer k
local integer rand
local integer upgradecount
// gold distribution will happen on the exact 300s mark, but when there is a delay before the game (and clock starts) they will still keep the
// distribution at the same 300s mark, even when the game clock only shows 10s because of the delay
// So, in a really smooth way, this wait keeps the multiboard clock synchronized with the actual gold distribution
call GameTimeWait(GAME_START_DELAY)
loop
exitwhen team > 2
set GoldDivided = GetPlayerState(udg_Force[team], PLAYER_STATE_RESOURCE_GOLD)
set UpGold = 2100 + (300 * udg_Team_CPs[team]) + udg_Force_UpgradeGold[team]
set upgradecount = 2 //it's initialised with 2, to be able to enter the loop
//Check how much upgrades can be researched
// 1 - Weapon, 2 - Armor
set NewUpgrades[1] = 0
set NewUpgrades[2] = 0
set MaxTechLevel[1] = GetPlayerTechMaxAllowed(udg_Force[team], 'R002')
set TechLevel[1] = GetPlayerTechCount(udg_Force[team], 'R002', true)
set MaxTechLevel[2] = GetPlayerTechMaxAllowed(udg_Force[team], 'R003')
set TechLevel[2] = GetPlayerTechCount(udg_Force[team], 'R003', true)
loop
exitwhen (UpGold < 1400) or (upgradecount == 0)
//In case both upgrades have the same level, chose one randomly
if ( (TechLevel[1]+NewUpgrades[1]) == (TechLevel[2]+NewUpgrades[2]) ) then
set rand = GetRandomInt(1,2)
else
set rand = 0
endif
//to prevent an endless loop
set upgradecount = 0
//Take armor upgrades, when the armor level is lower
//or it has been randomly choosen, when both upgrades were equal
if (( (TechLevel[2]+NewUpgrades[2]) < (TechLevel[1]+NewUpgrades[1]) ) or (rand == 2)) and (UpGold >= 1500) then
if (TechLevel[2] + NewUpgrades[2]) < MaxTechLevel[2] then
set NewUpgrades[2] = NewUpgrades[2] + 1
set UpGold = UpGold - 1500
set upgradecount = upgradecount + 1
endif
endif
//Take weapon upgrades, when the weapon level is lower or equal
if (( (TechLevel[1]+NewUpgrades[1]) <= (TechLevel[2]+NewUpgrades[2]) ) or (rand == 1)) and (UpGold >= 1400) then
if (TechLevel[1] + NewUpgrades[1]) < MaxTechLevel[1] then
set NewUpgrades[1] = NewUpgrades[1] + 1
set UpGold = UpGold - 1400
set upgradecount = upgradecount + 1
endif
endif
endloop
//Research the upgrades
set k = 1
loop
exitwhen k > 2
if k==1 then
set Tech = 'R002'
set TechReq = 'R009'
set TechName = "weapons"
else
set Tech = 'R003'
set TechReq = 'R008'
set TechName = "armor"
endif
if ((TechLevel[k] + NewUpgrades[k]) <= MaxTechLevel[k]) and (NewUpgrades[k] > 0) then
//Set the tech level for the force
call SetPlayerTechResearched( udg_Force[team], Tech, TechLevel[k] + NewUpgrades[k] )
call SetPlayerTechResearched( udg_Force[team], TechReq, GetPlayerTechCount(udg_Force[team], Tech, true) )
set j = 1
loop
exitwhen j > GetMaxHumanPlayers()
//Set the tech level for each player in the same team
if IsPlayerInForce(GetPlayer(j), udg_Players_Team[team]) then
call SetPlayerTechResearched( GetPlayer(j), Tech, TechLevel[k] + NewUpgrades[k] )
call SetPlayerTechResearched( GetPlayer(j), TechReq, GetPlayerTechCount(GetPlayer(j), Tech, true) )
call DisplayTextToPlayer(GetPlayer(j), 0, 0, udg_Color[10 + team] + GetPlayerName(udg_Force[team]) + "|r |cfffed312has upgraded your team's " + TechName + " to level " + I2S(TechLevel[k] + NewUpgrades[k]) + " (+|r" + I2S(NewUpgrades[k]) + "|cfffed312)!|r")
endif
set j = j + 1
endloop
endif
set k = k + 1
endloop
//When Upgold is greater than 1500, no further upgrades could be researched
//So distribute the upgrade gold, instead of saving it
if UpGold > 1500 then
set GoldDivided = GoldDivided + UpGold
set UpGold = 0
endif
set udg_Force_UpgradeGold[team] = UpGold
if udg_Team_CountPlayers[team] > 0 and GoldDivided > 0 then
set GoldDivided = GetForceIncome(GoldDivided, udg_Team_CountPlayers[team])
call SetPlayerState( udg_Force[team], PLAYER_STATE_RESOURCE_GOLD, 0 )
set j = 1
loop
exitwhen j > GetMaxHumanPlayers()
if IsPlayerInForce(GetPlayer(j), udg_Players_Team[team]) then
call SetPlayerState(GetPlayer(j), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetPlayer(j), PLAYER_STATE_RESOURCE_GOLD) + GoldDivided)
set udg_Profit_Force[j] = udg_Profit_Force[j] + GoldDivided
call DisplayTextToPlayer(GetPlayer(j), 0, 0, "|Cfffed312Received " + I2S(GoldDivided) + " gold from|r " + udg_Color[10 + team] + GetPlayerName(udg_Force[team]) + "|r|Cfffed312.|r" )
endif
set j = j + 1
endloop
endif
set udg_Income[10 + team] = 0.00
set team = team + 1
endloop
endfunction
//===========================================================================
function InitTrig_Gold_Distribution takes nothing returns nothing
set gg_trg_Gold_Distribution = CreateTrigger( )
call TriggerRegisterTimerEvent( gg_trg_Gold_Distribution, 300.00, true )
call TriggerAddAction( gg_trg_Gold_Distribution, function Trig_Gold_Distribution_Actions )
endfunction
//TESH.scrollpos=69
//TESH.alwaysfold=0
library KickSystem requires Initilization
globals
constant real DECAY_FACTOR = 1.3
constant real DEATH_PENALTY_LIMIT = -125.0
constant integer TARGET_KICK_VALUE = 6
constant real DEATH_PENALTY_DURATION = 300.0
constant integer TEAMKILL_COUNT = 2
constant integer PENALTY_MESSAGE_AFK = 1
constant integer PENALTY_MESSAGE_FEED = 2
constant integer PENALTY_MESSAGE_TEAMKILL = 3
integer array Player_Penalty[10]
string array Player_Penalty_Message[10]
endglobals
function ReducePenalty takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer TimerIndex = GetHandleIndex(t)
local integer pId = udg_AV_Int1[TimerIndex]
set Player_Penalty[pId] = Player_Penalty[pId] - 1
call ReleaseHandleIndex(TimerIndex)
call ReleaseTimer(t)
endfunction
function AddPlayerPenalty takes integer pId, integer messageId returns nothing
local string message = ""
local timer t
local integer TimerIndex
set Player_Penalty[pId] = Player_Penalty[pId] + 1
if (messageId == PENALTY_MESSAGE_AFK) then
set message = "Denial of playing"
elseif (messageId == PENALTY_MESSAGE_FEED) then
set message = "Feeding"
elseif (messageId == PENALTY_MESSAGE_TEAMKILL) then
set message = "Teamkilling"
endif
if GetLocalPlayer() == GetPlayer(pId) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312You received a penalty point. You now have|r " + I2S(Player_Penalty[pId]) + "|cfffed312.")
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312Reason for your penalty:|r " + message)
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "")
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312If you want to know more about penalties, type \"|r-penalty|cfffed312\"|r")
endif
call DebugMsg("Player " + I2S(pId) + " received a penalty for " + message)
if ((Player_Penalty_Message[pId] == "") or (Player_Penalty_Message[pId] == null)) then
set Player_Penalty_Message[pId] = message
elseif (StringPos(Player_Penalty_Message[pId], message, 0) == -1) then
set Player_Penalty_Message[pId] = Player_Penalty_Message[pId] + ", " + message
endif
if (messageId == PENALTY_MESSAGE_FEED) then
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[TimerIndex] = pId
call TimerStart(t, DEATH_PENALTY_DURATION, false, function ReducePenalty)
endif
endfunction
function IncreasePenalty takes unit tank returns nothing
local integer pId = GetPlayerNr(GetOwningPlayer(tank))
local integer i = 1
local real killValue = 0
local real deathValue = 0
local real supportValue = 0
local real total = 0
loop
exitwhen i > 10
set killValue = killValue + ((1/Pow(DECAY_FACTOR, i-1)) * Kills_StatsProgress[pId][i])
set deathValue = deathValue + ((1/Pow(DECAY_FACTOR, i-1)) * Deaths_StatsProgress[pId][i])
set supportValue = supportValue + ((1/Pow(DECAY_FACTOR, i-1)) * Support_StatsProgress[pId][i])
set i = i + 1
endloop
//call DebugMsg("Player " + I2S(pId) + " Total: Kill - " + I2S(R2I(killValue)) + " Death - " + I2S(R2I(deathValue)) + " Suppor - " + I2S(R2I(supportValue)))
set total = PERFORMANCE_KILL_VALUE * killValue + PERFORMANCE_DEATH_VALUE * deathValue + PERFORMANCE_SUPPORT_VALUE * supportValue
if (total <= DEATH_PENALTY_LIMIT) then
call AddPlayerPenalty(pId, PENALTY_MESSAGE_FEED)
endif
endfunction
function VotesNeeded takes integer nr returns integer
local integer team = udg_Player_Team[nr]
if (bj_isSinglePlayer) then
return 1
endif
if ((TARGET_KICK_VALUE - Player_Penalty[nr]) >= udg_Team_CountPlayers[team]) then
// more penalties are needed for this player to be actually kickable
return -1
elseif ((TARGET_KICK_VALUE - Player_Penalty[nr]) < 2) then
// at least one vote is needed (obviously the one, that starts the vote)
return 2
else
return (TARGET_KICK_VALUE - Player_Penalty[nr])
endif
return -1
endfunction
function GetYes takes nothing returns integer
return udg_Kick_Count[1]
endfunction
function IsKickVoteSuccessful takes integer neededVotes returns boolean
return (neededVotes <= GetYes())
endfunction
endlibrary
//TESH.scrollpos=533
//TESH.alwaysfold=0
library Multiboards requires Initilization, MapAttachedSettings
globals
constant integer NO_BOARD = -1
constant integer DEFAULT_BOARD = 0
constant integer SIMPLE_BOARD = 1
constant integer VITAL_BOARD = 2
constant integer SCORE_BOARD = 3
private integer array BoardValues[25][25]
endglobals
function CreateMultiboardEx takes integer cols, integer rows, string title returns multiboard
local multiboard b = CreateMultiboard()
call MultiboardSetRowCount(b, rows)
call MultiboardSetColumnCount(b, cols)
call MultiboardSetTitleText(b, title)
return b
endfunction
function MultiboardSetItemValueEx takes multiboard board, integer column, integer row, string val returns nothing
//Works similar to the MultiboardSetItem* functions.
//Using a Column or Row higher than the current max will result in the function not doing anything.
local integer curCol = 1
local integer curRow = 1
local multiboarditem mbitem
if column > MultiboardGetColumnCount(board) or row > MultiboardGetRowCount(board) then
return
endif
if column == 0 or row == 0 then
if column == 0 and row == 0 then
call MultiboardSetItemsValue(board,val)
return
elseif column == 0 then
loop
exitwhen curCol > MultiboardGetColumnCount(board)
set mbitem = MultiboardGetItem(board, row-1, curCol-1)
call MultiboardSetItemValue(mbitem,val)
call MultiboardReleaseItem(mbitem)
set curCol = curCol + 1
endloop
set mbitem = null
return
else
loop
exitwhen curRow > MultiboardGetRowCount(board)
set mbitem = MultiboardGetItem(board, curRow-1, column-1)
call MultiboardSetItemValue(mbitem,val)
set BoardValues[curRow][column] = S2I(val)
call MultiboardReleaseItem(mbitem)
set curRow = curRow + 1
endloop
set mbitem = null
return
endif
endif
set mbitem = MultiboardGetItem(board, row-1, column-1)
call MultiboardSetItemValue(mbitem,val)
call MultiboardReleaseItem(mbitem)
set mbitem = null
endfunction
function PercentToColor takes real percent returns integer
return R2I(percent*255.0*0.01)
endfunction
function MultiboardSetItemColorEx takes multiboard board, integer column, integer row, real red, real green, real blue, real transparency returns nothing
//Works similar to the MultiboardSetItem* functions.
//Using a Column or Row higher than the current max will result in the function not doing anything.
local integer curCol = 1
local integer curRow = 1
local multiboarditem mbitem
if column > MultiboardGetColumnCount(board) or row > MultiboardGetRowCount(board) then
return
endif
if column == 0 or row == 0 then
if column == 0 and row == 0 then
call MultiboardSetItemsValueColor(board, PercentToColor(red), PercentToColor(green), PercentToColor(blue), PercentToColor(100.0-transparency))
return
elseif column == 0 then
loop
exitwhen curCol > MultiboardGetColumnCount(board)
set mbitem = MultiboardGetItem(board, row-1, curCol-1)
call MultiboardSetItemValueColor(mbitem, PercentToColor(red), PercentToColor(green), PercentToColor(blue), PercentToColor(100.0-transparency))
call MultiboardReleaseItem(mbitem)
set curCol = curCol + 1
endloop
set mbitem = null
return
else
loop
exitwhen curRow > MultiboardGetRowCount(board)
set mbitem = MultiboardGetItem(board, curRow-1, column-1)
call MultiboardSetItemValueColor(mbitem, PercentToColor(red), PercentToColor(green), PercentToColor(blue), PercentToColor(100.0-transparency))
call MultiboardReleaseItem(mbitem)
set curRow = curRow + 1
endloop
set mbitem = null
return
endif
endif
set mbitem = MultiboardGetItem(board, row-1, column-1)
call MultiboardSetItemValueColor(mbitem, PercentToColor(red), PercentToColor(green), PercentToColor(blue), PercentToColor(100.0-transparency))
call MultiboardReleaseItem(mbitem)
set mbitem = null
endfunction
function MultiboardSetItemStyleEx takes multiboard board, integer column, integer row, boolean showValue, boolean showIcon returns nothing
//Works similar to the MultiboardSetItem* functions.
//Using a Column or Row higher than the current max will result in the function not doing anything.
local integer curCol = 1
local integer curRow = 1
local multiboarditem mbitem
if column > MultiboardGetColumnCount(board) or row > MultiboardGetRowCount(board) then
return
endif
if column == 0 or row == 0 then
if column == 0 and row == 0 then
call MultiboardSetItemsStyle(board, showValue, showIcon)
return
elseif column == 0 then
loop
exitwhen curCol > MultiboardGetColumnCount(board)
set mbitem = MultiboardGetItem(board, row-1, curCol-1)
call MultiboardSetItemStyle(mbitem, showValue, showIcon)
call MultiboardReleaseItem(mbitem)
set curCol = curCol + 1
endloop
set mbitem = null
return
else
loop
exitwhen curRow > MultiboardGetRowCount(board)
set mbitem = MultiboardGetItem(board, curRow-1, column-1)
call MultiboardSetItemStyle(mbitem, showValue, showIcon)
call MultiboardReleaseItem(mbitem)
set curRow = curRow + 1
endloop
set mbitem = null
return
endif
endif
set mbitem = MultiboardGetItem(board, row-1, column-1)
call MultiboardSetItemStyle(mbitem, showValue, showIcon)
call MultiboardReleaseItem(mbitem)
set mbitem = null
endfunction
function MultiboardSetItemWidthEx takes multiboard board, integer column, integer row, real width returns nothing
//Works similar to the MultiboardSetItem* functions.
//Using a Column or Row higher than the current max will result in the function not doing anything.
local integer curCol = 1
local integer curRow = 1
local multiboarditem mbitem
if column > MultiboardGetColumnCount(board) or row > MultiboardGetRowCount(board) then
return
endif
if column == 0 or row == 0 then
if column == 0 and row == 0 then
call MultiboardSetItemsWidth(board, width*0.01)
return
elseif column == 0 then
loop
exitwhen curCol > MultiboardGetColumnCount(board)
set mbitem = MultiboardGetItem(board, row-1, curCol-1)
call MultiboardSetItemWidth(mbitem, width*0.01)
call MultiboardReleaseItem(mbitem)
set curCol = curCol + 1
endloop
set mbitem = null
return
else
loop
exitwhen curRow > MultiboardGetRowCount(board)
set mbitem = MultiboardGetItem(board, curRow-1, column-1)
call MultiboardSetItemWidth(mbitem, width*0.01)
call MultiboardReleaseItem(mbitem)
set curRow = curRow + 1
endloop
set mbitem = null
return
endif
endif
set mbitem = MultiboardGetItem(board, row-1, column-1)
call MultiboardSetItemWidth(mbitem, width*0.01)
call MultiboardReleaseItem(mbitem)
set mbitem = null
endfunction
function MultiboardSetItemIconEx takes multiboard board, integer column, integer row, string iconFileName returns nothing
//Works similar to the MultiboardSetItem* functions.
//Using a Column or Row higher than the current max will result in the function not doing anything.
local integer curCol = 1
local integer curRow = 1
local multiboarditem mbitem
if column > MultiboardGetColumnCount(board) or row > MultiboardGetRowCount(board) then
return
endif
if column == 0 or row == 0 then
if column == 0 and row == 0 then
call MultiboardSetItemsIcon(board, iconFileName)
return
elseif column == 0 then
loop
exitwhen curCol > MultiboardGetColumnCount(board)
set mbitem = MultiboardGetItem(board, row-1, curCol-1)
call MultiboardSetItemIcon(mbitem, iconFileName)
call MultiboardReleaseItem(mbitem)
set curCol = curCol + 1
endloop
set mbitem = null
return
else
loop
exitwhen curRow > MultiboardGetRowCount(board)
set mbitem = MultiboardGetItem(board, curRow-1, column-1)
call MultiboardSetItemIcon(mbitem, iconFileName)
call MultiboardReleaseItem(mbitem)
set curRow = curRow + 1
endloop
set mbitem = null
return
endif
endif
set mbitem = MultiboardGetItem(board, row-1, column-1)
call MultiboardSetItemIcon(mbitem, iconFileName)
call MultiboardReleaseItem(mbitem)
set mbitem = null
endfunction
function SetTankIcon takes integer number returns nothing
local integer ID = GetUnitTypeId(udg_Tank[number])
local integer i = 0
local integer row
local integer col
local string Icon = "HeroTinker.blp"
if ID == 'H01H' then
set Icon = "Peasant.blp"
elseif ID == 'H009' then
set Icon = "WarWagon.blp"
elseif ID == 'H008' then
set Icon = "FlyingMachine.blp"
elseif ID == 'H00X' then
set Icon = "Antigrav.blp"
elseif ID == 'H017' then
set Icon = "Ranger.blp"
elseif ID == 'H007' then
set Icon = "Demolisher.blp"
elseif ID == 'H027' then
set Icon = "SpaceOrc_AttackHelicopter_Condor.blp"
elseif ID == 'H025' then
set Icon = "GoblinWarZeppelin.blp"
elseif ID == 'H00C' then
set Icon = "GoblinZeppelin.blp"
elseif ID == 'H00Y' then
set Icon = "BloodElfSupplyWagon.blp"
elseif ID == 'H00B' then
set Icon = "MeatWagon.blp"
elseif ID == 'H014' then
set Icon = "GoblinSapper.blp"
elseif ID == 'H00D' then
set Icon = "SeigeEngine.blp"
elseif ID == 'H00I' then
set Icon = "RoboGoblin.blp"
elseif ID == 'H01S' then
set Icon = "GoblinAssaultTank.blp"
elseif ID == 'H01U' then
set Icon = "RockGolem.blp"
elseif ID == 'H00E' then
set Icon = "UndeadAirBarge.blp"
elseif ID == 'H00F' then
set Icon = "InfernalCannon.blp"
elseif ID == 'H00H' then
set Icon = "FrostRobot.blp"
elseif ID == 'H00K' then
set Icon = "Infernal.blp"
elseif ID == 'H011' then
set Icon = "JunkGolem.blp"
elseif ID == 'H012' or ID == 'H013' then
set Icon = "AncientOfTheEarth.blp"
elseif ID == 'H00R' then
set Icon = "ObsidianStatue.blp"
elseif ID == 'H01L' then
set Icon = "GnomeMobile.blp"
elseif ID == 'H01R' then
set Icon = "DemonShip.blp"
elseif ID == 'H021' then
set Icon = "Brawler.blp"
elseif ID == 'H01I' then
set Icon = "Titan.blp"
elseif ID == 'H01V' or ID == 'H02A' then
set Icon = "KingLion.blp"
elseif ID == 'H02J' then
set Icon = "Distributor.blp"
elseif ID == 'H02K' then
set Icon = "Darkness_Tank.blp"
endif
loop
exitwhen i > GetMaxHumanPlayers()
if (udg_MultiboardType[i] == SCORE_BOARD) then
set col = 1 + number
set row = 2 - ModuloInteger(number, 2)
else
set col = 2
set row = number + udg_Player_Team[number] + 1
endif
call MultiboardSetItemIconEx( udg_Killboard[i], col, row, "ReplaceableTextures\\CommandButtons\\BTN" + Icon )
set i = i + 1
endloop
set Icon = null
endfunction
function IntToHexLimit takes integer int returns string
local string result
local string tmp
set tmp = IntToHex(IMinBJ(IMaxBJ(int, 0), 255))
if StringLength(tmp) == 1 then
set result = "0" + tmp
else
set result = tmp
endif
return result
endfunction
function UpdateBoardVitals takes nothing returns nothing
local multiboarditem mbitem
local string basic = "||||||||||||||||||||||||||||||||||||||||||||||||||"
local integer length = StringLength(basic)
local string hpBar
local string manaBar
local string hpColor
local string manaColor
local integer hp
local integer mana
local integer i = 0
local integer j = 1
// First loop iterates over all multiboards for every player and checks if he is even using the vital board
loop
exitwhen i >= GetMaxPlayers()
if (udg_MultiboardType[i] == VITAL_BOARD) then
// apparently he does, so now update every tank entry of this players multiboard
// but only for his own team (no one should be able to see the HP bars of the enemy on the board
set j = 1
loop
exitwhen j > GetMaxHumanPlayers()
if IsPlayerAlly(GetPlayer(i+1), GetPlayer(j)) and udg_PlayerIn[j] then
// calculate, how long the hp and mana bars have to be (the colored part, that is)
set hp = R2I(GetUnitLifePercent(udg_Tank[j]) * length / 100)
if (GetUnitState(udg_Tank[j], UNIT_STATE_LIFE) <= 0) then
set mana = 0
else
set mana = R2I(GetUnitManaPercent(udg_Tank[j]) * length / 100)
endif
//hp and mana have to be even numbers, otherwise the escape code |r wont be registered and thus displayed
if (ModuloInteger(hp, 2) > 0) then
set hp = hp + 1
endif
if (ModuloInteger(mana, 2) > 0) then
set mana = mana + 1
endif
set hpColor = "|cff" + IntToHexLimit(IMinBJ(R2I(500 - (500 * GetUnitLifePercent(udg_Tank[j])/100)), 150)) + IntToHexLimit(IMinBJ(R2I(500 * GetUnitLifePercent(udg_Tank[j])/100), 150)) + "00"
set manaColor = "|cff" + IntToHexLimit(R2I(125 - (125 * GetUnitManaPercent(udg_Tank[j])/100))) + "00ff"
set hpBar = hpColor + SubString(basic, 0, hp)+ "|r|cffbbbbbb" + SubString(basic, 0, (length - hp)) + "|r"
set manaBar = manaColor + SubString(basic, 0, mana)+ "|r|cffbbbbbb" + SubString(basic, 0, (length - mana)) + "|r"
set mbitem = MultiboardGetItem(udg_Killboard[i], j + udg_Player_Team[j], 1)
call MultiboardSetItemValue(mbitem, hpBar + " " + manaBar)
call MultiboardReleaseItem(mbitem)
endif
set j = j + 1
endloop
endif
set i = i + 1
endloop
endfunction
function UpdateBoardTime takes string s returns nothing
local integer i = 0
local string teamStats = udg_Color[11] + I2S(udg_Kills[11]) + "|r : " + udg_Color[12] + I2S(udg_Kills[12])
loop
exitwhen i > GetMaxPlayers()
if udg_MultiboardType[i] == SIMPLE_BOARD then
call MultiboardSetTitleText( udg_Killboard[i], "|c00ff0000" + SubString(GetLocalizedString("TRIGSTR_1"), 13, 18) + "|r - " + s)
elseif udg_MultiboardType[i] == SCORE_BOARD then
call MultiboardSetTitleText( udg_Killboard[i], "|c00ff0000" + GetLocalizedString("TRIGSTR_1") + "|r - " + Current_Time_String + "|r - " + ModeName[udg_GameMode] + "|r - " + teamStats )
else
call MultiboardSetTitleText( udg_Killboard[i], "|c00ff0000" + GetLocalizedString("TRIGSTR_1") + "|r - " + s + " - |cff5555ffStatistics|r" )
endif
set i = i + 1
endloop
call UpdateBoardVitals()
endfunction
function UpdateBoardKills takes integer nr returns nothing
local multiboarditem mbitem
local integer team = udg_Player_Team[nr]
local integer i = 0
local string s
loop
exitwhen i > GetMaxPlayers()
if (udg_MultiboardType[i] == DEFAULT_BOARD) or (udg_MultiboardType[i] == VITAL_BOARD) then
set mbitem = MultiboardGetItem(udg_Killboard[i], team * 6 - 5, 2)
call MultiboardSetItemValue(mbitem, I2S(udg_Kills[10 + team]))
call MultiboardReleaseItem(mbitem)
if (nr <= GetMaxHumanPlayers()) then
set mbitem = MultiboardGetItem(udg_Killboard[i], nr + team, 2)
call MultiboardSetItemValue(mbitem, I2S(udg_Kills[nr]))
call MultiboardReleaseItem(mbitem)
endif
elseif (udg_MultiboardType[i] == SIMPLE_BOARD) then
set mbitem = MultiboardGetItem(udg_Killboard[i], team * 6 - 5, 2)
call MultiboardSetItemValue(mbitem, I2S(udg_Kills[10 + team]))
call MultiboardReleaseItem(mbitem)
if (nr <= GetMaxHumanPlayers()) then
set mbitem = MultiboardGetItem(udg_Killboard[i], nr + team, 2)
set s = "|cff00ff00" + I2S(udg_Kills[nr]) + "|r/|cffff0000" + I2S(udg_Deaths[nr]) + "|r/|cff00bdff" + I2S(R2I(udg_Support[nr])) + "|r"
call MultiboardSetItemValue(mbitem, s)
call MultiboardReleaseItem(mbitem)
endif
endif
set i = i + 1
endloop
endfunction
function UpdateBoardDeaths takes integer nr returns nothing
local multiboarditem mbitem
local integer team = udg_Player_Team[nr]
local integer i = 0
local string s
loop
exitwhen i > GetMaxPlayers()
if (udg_MultiboardType[i] == DEFAULT_BOARD) or (udg_MultiboardType[i] == VITAL_BOARD) then
set mbitem = MultiboardGetItem(udg_Killboard[i], nr + team, 3)
call MultiboardSetItemValue(mbitem, I2S(udg_Deaths[nr]))
call MultiboardReleaseItem(mbitem)
set mbitem = MultiboardGetItem(udg_Killboard[i], nr + team, 1)
call MultiboardSetItemValueColor(mbitem, 255, 0, 0, 255)
call MultiboardReleaseItem(mbitem)
elseif (udg_MultiboardType[i] == SIMPLE_BOARD) then
set mbitem = MultiboardGetItem(udg_Killboard[i], nr + team, 2)
set s = "|cffff0000" + I2S(udg_Kills[nr]) + "|r/|cffff0000" + I2S(udg_Deaths[nr]) + "|r/|cffff0000" + I2S(R2I(udg_Support[nr])) + "|r"
call MultiboardSetItemValue(mbitem, s)
call MultiboardReleaseItem(mbitem)
endif
set i = i + 1
endloop
endfunction
function UpdateBoardSupport takes integer nr returns nothing
local multiboarditem mbitem
local integer team = udg_Player_Team[nr]
local integer i = 0
local string s
loop
exitwhen i > GetMaxPlayers()
if (udg_MultiboardType[i] == DEFAULT_BOARD) or (udg_MultiboardType[i] == VITAL_BOARD) then
set mbitem = MultiboardGetItem(udg_Killboard[i], nr + team, 4)
call MultiboardSetItemValue(mbitem, I2S(R2I(udg_Support[nr])))
call MultiboardReleaseItem(mbitem)
elseif (udg_MultiboardType[i] == SIMPLE_BOARD) then
set mbitem = MultiboardGetItem(udg_Killboard[i], nr + team, 2)
set s = "|cff00ff00" + I2S(udg_Kills[nr]) + "|r/|cffff0000" + I2S(udg_Deaths[nr]) + "|r/|cff00bdff" + I2S(R2I(udg_Support[nr])) + "|r"
call MultiboardSetItemValue(mbitem, s)
call MultiboardReleaseItem(mbitem)
endif
set i = i + 1
endloop
endfunction
function UpdateBoardPlayerPlayingState takes integer nr returns nothing
local integer k = 0
local integer team = udg_Player_Team[nr]
loop
exitwhen k > GetMaxHumanPlayers()
call MultiboardSetItemColorEx( udg_Killboard[k], 2, nr + team + 1, 40.00, 40.00, 40.00, 0 )
call MultiboardSetItemStyleEx( udg_Killboard[k], 2, nr + team + 1, true, false )
set k = k + 1
endloop
endfunction
function UpdateBoardTankState takes integer nr, boolean isAlive returns nothing
local multiboarditem mbitem
local integer team = udg_Player_Team[nr]
local integer i = 0
local string s
loop
exitwhen i > GetMaxPlayers()
if (udg_MultiboardType[i] == DEFAULT_BOARD) or (udg_MultiboardType[i] == VITAL_BOARD) then
set mbitem = MultiboardGetItem(udg_Killboard[i], nr + team, 1)
call MultiboardSetItemValueColor(mbitem, 0, 255, 0, 255)
call MultiboardReleaseItem(mbitem)
elseif (udg_MultiboardType[i] == SIMPLE_BOARD) then
set mbitem = MultiboardGetItem(udg_Killboard[i], nr + team, 2)
set s = "|cff00ff00" + I2S(udg_Kills[nr]) + "|r/|cffff0000" + I2S(udg_Deaths[nr]) + "|r/|cff00bdff" + I2S(R2I(udg_Support[nr])) + "|r"
call MultiboardSetItemValue(mbitem, s)
call MultiboardReleaseItem(mbitem)
endif
set i = i + 1
endloop
endfunction
function MB_SetSupport takes integer playerId, real value returns nothing
local integer TeamOfSupport
local integer tlh_Level
local real goldbonus
local string op = "+"
if (value == 0) then
return
else
set tlh_Level = GetUnitAbilityLevel(udg_Tank[playerId], TLH_ABILITY_ID)
set TeamOfSupport = udg_Player_Team[playerId]
endif
if (value < 0) then
set op = "" //don't display the '+' when the value is actually negative
endif
set udg_Support[playerId] = udg_Support[playerId] + value
if (GetUnitState(udg_Tank[playerId], UNIT_STATE_LIFE) > 0) then
call ShowTextTag("|cff00bdff"+op+R2SW(value, 1, 1)+"|r", udg_Tank[playerId], 0, 50, GetPlayer(playerId))
endif
if (tlh_Level > 0) then
set goldbonus = (TLH_BONUS_BASE + (tlh_Level * TLH_BONUS_UP)) * value
call SetPlayerState(GetPlayer(playerId), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetPlayer(playerId), PLAYER_STATE_RESOURCE_GOLD) + R2I(goldbonus))
call ShowTextTag("|cfffe960a"+op+I2S(R2I(goldbonus))+"|r", udg_Tank[playerId], 100, 50, GetPlayer(playerId))
endif
set Support_StatsProgress[playerId][1] = Support_StatsProgress[playerId][1] + R2I(value)
call UpdateBoardSupport(playerId)
endfunction
globals
constant integer SCOREBOARD_ROWMODE_HIGHEST = 1
constant integer SCOREBOARD_ROWMODE_LOWEST = 2
constant integer SCOREBOARD_ROWMODE_HIGHEST_TEAM1 = 3
constant integer SCOREBOARD_ROWMODE_HIGHEST_TEAM2 = 4
constant integer PERFORMANCE_KILL_VALUE = 20
constant integer PERFORMANCE_DEATH_VALUE = -35
constant integer PERFORMANCE_SUPPORT_VALUE = 10
constant real PERFORMANCE_DIM_VALUE = 0.0002
endglobals
function Highlight_Scoreboard_GetBestFromRow takes integer nr, integer row, integer mode returns nothing
local integer value = -1
local integer i
local integer start
local integer end
local multiboarditem mbitem
// If you only want to highlight a value from one team, limit the columns in which you want to search
if (mode != SCOREBOARD_ROWMODE_HIGHEST_TEAM2) then
set start = 2
else
set start = 7
endif
if (mode != SCOREBOARD_ROWMODE_HIGHEST_TEAM1) then
set end = MultiboardGetColumnCount(udg_Killboard[nr])
else
set end = 6
endif
// get the highest value from the selected row
set i = start
loop
exitwhen (i > end)
if (mode != SCOREBOARD_ROWMODE_LOWEST) then
if ((BoardValues[row][i] > value) and (BoardValues[row][i] != 0)) then
set value = BoardValues[row][i]
endif
else
if udg_PlayerIn[i-1] then
if ((BoardValues[row][i] < value) or (value == -1)) then
set value = BoardValues[row][i]
endif
endif
endif
set i = i + 1
endloop
// highlight each entry, that is equal to the found value
set i = start
loop
exitwhen (i > end)
if (BoardValues[row][i] == value) then
set mbitem = MultiboardGetItem(udg_Killboard[nr], row - 1, i - 1)
//call MultiboardSetItemValueColor(mbitem, udg_Color_Red[i-1], udg_Color_Green[i-1], udg_Color_Blue[i-1], 255)
call MultiboardSetItemValueColor(mbitem, 255, 204, 0, 255)
call MultiboardReleaseItem(mbitem)
endif
set i = i + 1
endloop
endfunction
function Highlight_Scoreboard_Best takes integer nr returns nothing
local integer i = 3
local integer value
loop
exitwhen (i > MultiboardGetRowCount(udg_Killboard[nr]))
// filter the empty rows
if ((i-7)*(i-12)*(i-17)*(i-23)*(i-25) != 0) then
// all rows, in which we search the lowest value
if ((i == 4) or (i == 22)) then
call Highlight_Scoreboard_GetBestFromRow(nr, i, SCOREBOARD_ROWMODE_LOWEST)
// all rows, in which the best from both teams will be highlighted
elseif (i == 16) then
// team 1
call Highlight_Scoreboard_GetBestFromRow(nr, i, SCOREBOARD_ROWMODE_HIGHEST_TEAM1)
// team 2
call Highlight_Scoreboard_GetBestFromRow(nr, i, SCOREBOARD_ROWMODE_HIGHEST_TEAM2)
// standard, where the highest values will be highlighted
else
call Highlight_Scoreboard_GetBestFromRow(nr, i, SCOREBOARD_ROWMODE_HIGHEST)
endif
endif
set i = i + 1
endloop
endfunction
function Format_Numbers takes integer nr, integer col, integer row, integer value returns string
local integer tempValue
local string final
set BoardValues[row][col] = value
set final = ""
// format the time string
if (row == 22) then
set tempValue = ModuloInteger(value, 60)
if (tempValue < 10) then
set final = ":0"
else
set final = ":"
endif
set final = I2S(R2I(value / 60.0)) + final+ I2S(ModuloInteger(value, 60))
// add a ',' to the number, for better readability
elseif (value >= 1000) then
set final = I2S(value)
set final = SubString(final, 0, StringLength(final)-3) + "," + SubString(final, StringLength(final)-3, StringLength(final))
elseif (final == "") then
set final = I2S(value)
endif
return final
endfunction
function ComputePerformance takes integer Id returns integer
local integer team = udg_Player_Team[Id]
local real gold = udg_Profit_Creeps[Id] + udg_Profit_Tanks[Id] + udg_Stats_Trader[Id]
local real teamGold = 0.0
local integer teamDeaths = 0
local integer teamKills = 0
local integer teamSupport = 0
local integer i
local integer start = (team-1)*5+1
local integer end = team*5
local integer base
local real gold_factor
local real stats_factor
set i = start
loop
exitwhen (i > end)
if udg_PlayerIn[i] then
set teamGold = teamGold + udg_Profit_Creeps[i] + udg_Profit_Tanks[i] + udg_Stats_Trader[i]
set teamKills = teamKills + udg_Kills[i]
set teamDeaths = teamDeaths + udg_Deaths[i]
set teamSupport = teamSupport + R2I(udg_Support[i])
endif
set i = i + 1
endloop
set base = (teamKills * PERFORMANCE_KILL_VALUE + teamDeaths * PERFORMANCE_DEATH_VALUE + teamSupport * PERFORMANCE_SUPPORT_VALUE)
if (base >= 0) then
set stats_factor = 1.0 + (base * PERFORMANCE_DIM_VALUE) / (1.0 + base * PERFORMANCE_DIM_VALUE)
else
set stats_factor = Pow(1.0 - PERFORMANCE_DIM_VALUE, -base)
endif
if (teamGold > 0) and (udg_Team_CountPlayers[team] > 0) then
set gold_factor = gold / (teamGold / udg_Team_CountPlayers[team])
else
set gold_factor = 0
endif
return R2I(1000 * stats_factor * gold_factor)
endfunction
function GetResult takes integer Id returns string
local integer team = udg_Player_Team[Id]
if udg_Kicked[Id] then
return "Kicked"
elseif ((udg_PlayerInStart[Id] == true) and (udg_PlayerIn[Id] == false)) then
return "Left"
elseif udg_GaveUp[team] then
return "Gave Up"
elseif (udg_Team_Winning == team) then
return "Won"
elseif (udg_Team_Winning != 0) then
return "Lost"
endif
return "-"
endfunction
function ScoreBoard_AddPlayers takes integer nr returns nothing
local player p
local integer col
local integer i = 1
local real temp
local integer nameRow
loop
exitwhen i > GetMaxHumanPlayers()
set p = GetPlayer(i)
set col = 1 + i
set nameRow = 2 - ModuloInteger(i, 2)
if udg_PlayerInStart[i] then
if not udg_PlayerIn[i] then
call MultiboardSetItemValueEx( udg_Killboard[nr], col, nameRow, GetPlayerName(p) )
call MultiboardSetItemColorEx( udg_Killboard[nr], col, 0, 40.00, 40.00, 40.00, 0 )
else
call MultiboardSetItemStyleEx( udg_Killboard[nr], col, nameRow, true, true )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, nameRow, udg_Color[col-1]+GetPlayerName(p) )
endif
call SetTankIcon(i)
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 3, Format_Numbers(nr, col, 3, udg_Kills[i]) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 4, Format_Numbers(nr, col, 4, udg_Deaths[i]) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 5, Format_Numbers(nr, col, 5, R2I(udg_Support[i]-udg_Assists[i])) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 6, Format_Numbers(nr, col, 6, udg_Assists[i]) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 8, Format_Numbers(nr, col, 8, udg_Stats_CreepKills[i]) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 9, Format_Numbers(nr, col, 9, udg_Stats_CreepBuy[i]) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 10, Format_Numbers(nr, col, 10, BuildingsKilled[i-1]) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 11, Format_Numbers(nr, col, 11, udg_Stats_Buildings[i]) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 13, Format_Numbers(nr, col, 13, GetBounty(udg_Tank[i], false)) )
set temp = udg_Profit_Creeps[i] + udg_Profit_Tanks[i] + udg_Stats_Trader[i]
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 14, Format_Numbers(nr, col, 14, R2I(temp)))
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 15, Format_Numbers(nr, col, 15, udg_Stats_Upgrades[i]))
if (udg_Damage_Dealt[10+udg_Player_Team[i]] > 0) then
set temp = udg_Damage_Dealt[i] / udg_Damage_Dealt[10+udg_Player_Team[i]] * 100.0
else
set temp = 0
endif
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 16, Format_Numbers(nr, col, 16, R2I(temp)) + "%" )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 18, Format_Numbers(nr, col, 18, GetHeroLevel(udg_Tank[i])) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 19, Format_Numbers(nr, col, 19, CPTeles[i-1]) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 20, Format_Numbers(nr, col, 20, udg_Stats_CPs[i]) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 21, Format_Numbers(nr, col, 21, R2I(60*udg_Actions[i]/TimerGetElapsed(udg_GameTime))) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 22, Format_Numbers(nr, col, 22, R2I(udg_Time_Dead[i])))
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 24, Format_Numbers(nr, col, 24, ComputePerformance(i)) )
call MultiboardSetItemValueEx( udg_Killboard[nr], col, 26, GetResult(i) )
endif
call MultiboardSetItemWidthEx( udg_Killboard[nr], col, nameRow, 12.99 )
if (col > 2) then
call MultiboardSetItemWidthEx( udg_Killboard[nr], col, 3-nameRow, 0.01 )
endif
set i = i + 1
endloop
call Highlight_Scoreboard_Best(nr)
endfunction
function CreateScoreBoard takes player p returns nothing
local integer nr = GetPlayerId(p)
local integer i = 1
local string teamStats = udg_Color[11] + I2S(udg_Kills[11]) + "|r : " + udg_Color[12] + I2S(udg_Kills[12])
set udg_Killboard[nr] = CreateMultiboardEx( 11, 26, "|c00ff0000" + GetLocalizedString("TRIGSTR_1") + "|r - " + Current_Time_String + "|r - " + ModeName[udg_GameMode] + "|r - " + teamStats )
call MultiboardSetItemStyleEx( udg_Killboard[nr], 0, 0, true, false )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 1, 0, 10.00 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 2, 0, 6.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 3, 0, 6.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 4, 0, 6.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 5, 0, 6.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 6, 0, 6.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 7, 0, 6.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 8, 0, 6.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 9, 0, 6.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 10, 0, 6.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 11, 0, 6.50 )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 3, "Kills" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 4, "Deaths" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 5, "Support" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 6, "Assists" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 7, "" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 8, "Creeps Killed" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 9, "Creeps Spawned" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 10, "Buildings Killed" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 11, "Buildings Built" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 12, "" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 13, "Tank Worth" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 14, "Gold Earned" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 15, "Upgrades Bought" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 16, "Damage Dealt" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 17, "" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 18, "Level" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 19, "CPTPs" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 20, "CPs captured" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 21, "APM" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 22, "Time Dead" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 23, "" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 24, "Performance" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 25, "" )
call MultiboardSetItemValueEx( udg_Killboard[nr], 1, 26, "Result" )
call MultiboardSetItemColorEx( udg_Killboard[nr], 2+nr, 0, 65.00, 100.00, 65.00, 0 )
call ScoreBoard_AddPlayers(nr)
if (GetLocalPlayer() == Player(nr)) then
call MultiboardDisplay( udg_Killboard[nr], true )
call MultiboardMinimize( udg_Killboard[nr], false )
endif
endfunction
function DefaultBoard_AddPlayers takes integer nr returns nothing
local player p
local integer row
local integer i = 1
call MultiboardSetItemValueEx ( udg_Killboard[nr], 3, 2, I2S(udg_Kills[11]))
call MultiboardSetItemValueEx ( udg_Killboard[nr], 3, 8, I2S(udg_Kills[12]))
loop
exitwhen i > GetMaxHumanPlayers()
set p = GetPlayer(i)
set row = GetPlayerNr(p) + 1 + udg_Player_Team[GetPlayerNr(p)]
if udg_PlayerInStart[i] then
if not udg_PlayerIn[i] then
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, row, GetPlayerName(p) )
call MultiboardSetItemColorEx( udg_Killboard[nr], 2, row, 40.00, 40.00, 40.00, 0 )
call MultiboardSetItemStyleEx( udg_Killboard[nr], 2, row, true, false )
else
if (udg_MultiboardType[nr] == VITAL_BOARD) and IsPlayerAlly(Player(nr), p) then
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, row, "|cff00ff00|||||||||||||||||||||||||||||||||||||||||||||||||||r" + " " + "|cff0000ff|||||||||||||||||||||||||||||||||||||||||||||||||||r" )
else
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, row, GetPlayerName(p) )
endif
call MultiboardSetItemColorEx( udg_Killboard[nr], 2, row, 0.00, 100.00, 0.00, 0 )
call MultiboardSetItemStyleEx( udg_Killboard[nr], 2, row, true, true )
call SetTankIcon(i)
endif
call MultiboardSetItemValueEx ( udg_Killboard[nr], 3, row, I2S(udg_Kills[i]))
call MultiboardSetItemValueEx ( udg_Killboard[nr], 4, row, I2S(udg_Deaths[i]))
call MultiboardSetItemValueEx ( udg_Killboard[nr], 5, row, I2S(R2I(udg_Support[i])))
endif
set i = i + 1
endloop
endfunction
function CreateDefaultBoard takes player p returns nothing
local integer nr = GetPlayerId(p)
local integer i = 1
set udg_Killboard[nr] = CreateMultiboardEx( 5, 13, "|c00ff0000" + GetLocalizedString("TRIGSTR_1") + "|r - " + Current_Time_String + " - |cff5555ffStatistics|r" )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 1, 0, 1.30 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 2, 0, 12.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 3, 0, 2.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 4, 0, 2.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 5, 0, 2.50 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 2, 0, 40.00, 40.00, 40.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 3, 0, 0.00, 100.00, 0.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 4, 0, 100.00, 0.00, 0.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 5, 0, 0.00, 75.00, 100.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 2, 1, 30.00, 30.00, 100.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 1, 1, 30.00, 30.00, 100.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 0, 2, 80.00, 60.00, 10.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 0, 8, 80.00, 60.00, 10.00, 0 )
call MultiboardSetItemStyleEx( udg_Killboard[nr], 0, 0, true, false )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 0, 0, "0" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 4, 2, "" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 4, 8, "" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 5, 2, "" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 5, 8, "" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 0, "" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, 0, "<empty>" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 1, "Pla" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, 1, "yer" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 3, 1, "K" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 4, 1, "D" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 5, 1, "S" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 2, "=>" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, 2, TeamOneName )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 8, "=>" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, 8, TeamTwoName )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 3, ( udg_Color[1] + "1|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 4, ( udg_Color[2] + "2|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 5, ( udg_Color[3] + "3|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 6, ( udg_Color[4] + "4|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 7, ( udg_Color[5] + "5|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 9, ( udg_Color[6] + "6|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 10, ( udg_Color[7] + "7|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 11, ( udg_Color[8] + "8|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 12, ( udg_Color[9] + "9|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 13, ( udg_Color[10] + "10|r" ) )
call DefaultBoard_AddPlayers(nr)
if (GetLocalPlayer() == Player(nr)) then
call MultiboardDisplay( udg_Killboard[nr], true )
call MultiboardMinimize( udg_Killboard[nr], IsMultiboardMinimized(udg_Killboard[nr]) )
endif
endfunction
function SimpleBoard_AddPlayers takes integer nr returns nothing
local player p
local integer row
local integer i = 1
call MultiboardSetItemValueEx ( udg_Killboard[nr], 3, 2, I2S(udg_Kills[11]))
call MultiboardSetItemValueEx ( udg_Killboard[nr], 3, 8, I2S(udg_Kills[12]))
loop
exitwhen i > GetMaxHumanPlayers()
set p = GetPlayer(i)
set row = GetPlayerNr(p) + 1 + udg_Player_Team[GetPlayerNr(p)]
if udg_PlayerInStart[i] then
call MultiboardSetItemColorEx( udg_Killboard[nr], 2, row, 0.00, 100.00, 0.00, 0 )
call MultiboardSetItemStyleEx( udg_Killboard[nr], 2, row, true, true )
call SetTankIcon(i)
call MultiboardSetItemValueEx ( udg_Killboard[nr], 3, row, "|cff00ff00" + I2S(udg_Kills[i]) + "|r/|cffff0000" + I2S(udg_Deaths[i]) + "|r/|cff00bdff" + I2S(R2I(udg_Support[i])) + "|r" )
if not udg_PlayerIn[i] then
call MultiboardSetItemColorEx( udg_Killboard[nr], 2, row, 40.00, 40.00, 40.00, 0 )
call MultiboardSetItemStyleEx( udg_Killboard[nr], 2, row, true, false )
endif
else
call MultiboardSetItemColorEx( udg_Killboard[nr], 3, row, 40.00, 40.00, 40.00, 0 )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 3, row, "<empty>" )
endif
set i = i + 1
endloop
endfunction
function CreateSimpleBoard takes player p returns nothing
local integer nr = GetPlayerId(p)
local integer i = 1
set udg_Killboard[nr] = CreateMultiboardEx( 3, 13, "|c00ff0000" + SubString(GetLocalizedString("TRIGSTR_1"), 13, 18) + "|r - " + Current_Time_String )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 1, 0, 1.30 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 2, 0, 1.50 )
call MultiboardSetItemWidthEx( udg_Killboard[nr], 3, 0, 5.0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 2, 0, 40.00, 40.00, 40.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 3, 0, 0.00, 100.00, 0.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 2, 1, 30.00, 30.00, 100.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 1, 1, 30.00, 30.00, 100.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 0, 2, 80.00, 60.00, 10.00, 0 )
call MultiboardSetItemColorEx( udg_Killboard[nr], 0, 8, 80.00, 60.00, 10.00, 0 )
call MultiboardSetItemStyleEx( udg_Killboard[nr], 0, 0, true, false )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 0, 0, "0" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 0, "" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, 0, "" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 1, "Pla" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, 1, "yer" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 3, 1, "|cff00ff00K|r / |cffff0000D|r / |cff00bdffS|r" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 2, "=>" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, 2, "" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 8, "=>" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 2, 8, "" )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 3, ( udg_Color[1] + "1|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 4, ( udg_Color[2] + "2|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 5, ( udg_Color[3] + "3|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 6, ( udg_Color[4] + "4|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 7, ( udg_Color[5] + "5|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 9, ( udg_Color[6] + "6|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 10, ( udg_Color[7] + "7|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 11, ( udg_Color[8] + "8|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 12, ( udg_Color[9] + "9|r" ) )
call MultiboardSetItemValueEx ( udg_Killboard[nr], 1, 13, ( udg_Color[10] + "10|r" ) )
call SimpleBoard_AddPlayers(nr)
if (GetLocalPlayer() == Player(nr)) then
call MultiboardDisplay( udg_Killboard[nr], true )
call MultiboardMinimize( udg_Killboard[nr], IsMultiboardMinimized(udg_Killboard[nr]) )
endif
endfunction
// coming up next: crazy workaround
globals
trigger udg_MultiboardRefreshTrig = null
player udg_MultiboardRefreshPlayer
endglobals
function CreateNewMultiboard_Child takes nothing returns nothing
local player p = udg_MultiboardRefreshPlayer
local integer nr = GetPlayerId(p)
local integer board = udg_MultiboardType[nr]
if (udg_Killboard[nr] != null) then
call MultiboardClear(udg_Killboard[nr])
endif
if ((board == DEFAULT_BOARD) or (board == VITAL_BOARD))then
call CreateDefaultBoard(p)
elseif (board == SIMPLE_BOARD) then
call CreateSimpleBoard(p)
elseif (board == SCORE_BOARD) then
call CreateScoreBoard(p)
endif
endfunction
// Create a new trigger, for each multiboad you want to create
// This is done, to avoid reaching the operation limit per trigger
// which would happen, because those multiboard functions perform an awful lot of operations
// When everything would be done in one trigger, the multiboard would appear empty (the player slots)
// for everyone
function CreateNewMultiboard takes player p returns nothing
if(udg_MultiboardRefreshTrig==null) then
set udg_MultiboardRefreshTrig = CreateTrigger()
call TriggerAddAction(udg_MultiboardRefreshTrig, function CreateNewMultiboard_Child)
endif
set udg_MultiboardRefreshPlayer = p
call TriggerExecute(udg_MultiboardRefreshTrig)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Multiboard_OpenClose_Actions takes nothing returns nothing
local player caster = GetTriggerPlayer()
if (GetLocalPlayer() == caster) and udg_Multiboard_Escape then
call MultiboardMinimize( udg_Killboard[GetPlayerId(caster)], not IsMultiboardMinimized(udg_Killboard[GetPlayerId(caster)]) )
endif
endfunction
//===========================================================================
function InitTrig_Multiboard_OpenClose takes nothing returns nothing
set gg_trg_Multiboard_OpenClose = CreateTrigger( )
call TriggerAddAction( gg_trg_Multiboard_OpenClose, function Trig_Multiboard_OpenClose_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Player_Income_Actions takes nothing returns nothing
local integer TeamId
local integer i = 1
local real GoldGiven
local real Factor
loop
exitwhen i > GetMaxHumanPlayers()
set TeamId = udg_Player_Team[i]
//if udg_AI_IsBot[i] and GetAIDifficulty(GetPlayer(i)) == AI_DIFFICULTY_INSANE then
// set Factor = 1.5
//else
set Factor = 1.0
//endif
set GoldGiven = GetPassiveIncome(udg_Income[i], udg_Team_CountPlayers[TeamId])
call SetPlayerState(GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD) + R2I( GoldGiven ))
set udg_Profit_Income[i] = udg_Profit_Income[i] + R2I( GoldGiven )
set udg_Income[i] = udg_Income[i] + GetBaseIncome(udg_Team_CountPlayers[TeamId]) - R2I( GoldGiven )
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_Player_Income takes nothing returns nothing
set gg_trg_Player_Income = CreateTrigger()
call DisableTrigger( gg_trg_Player_Income )
call TriggerRegisterTimerEvent( gg_trg_Player_Income, 1.00, true )
call TriggerAddAction( gg_trg_Player_Income, function Trig_Player_Income_Actions )
endfunction
//TESH.scrollpos=138
//TESH.alwaysfold=0
function Trig_Player_Remove_IsCreep takes unit U returns boolean
local integer Id = GetUnitTypeId(U)
return Id == 'z006' or Id == 'z00D' or Id == 'z008' or Id == 'z007'
endfunction
function Trig_Player_Remove_FilterItem takes nothing returns boolean
local integer team = udg_Player_Team[GetPlayerNr(udg_Leaver)]
if GetItemPlayer(GetFilterItem()) == udg_Leaver then
if ((team==1 and not RectContainsItem(GetFilterItem(),gg_rct_Team_1_Junkyard)) or (team==2 and not RectContainsItem(GetFilterItem(),gg_rct_Team_2_Junkyard))) then
return true
else
call SetItemPlayer(GetFilterItem(),udg_Force[team],false)
endif
endif
return false
endfunction
function Trig_Player_Remove_OwningPlayer takes nothing returns boolean
return GetItemPlayer(GetFilterItem()) == udg_Leaver
endfunction
function Trig_Player_Remove_IsAllyPlayingHighTradeRate takes nothing returns boolean
return IsPlayerInForce(GetFilterPlayer(), udg_Players_Team[udg_Player_Team[GetPlayerNr(udg_Leaver)]]) and udg_Stats_Trader[GetPlayerNr(GetFilterPlayer())] == udg_Stats[1]
endfunction
function Trig_Player_Remove_GetItemCosts takes item TempItem returns integer
local integer Costs = 0
if GetItemType(TempItem) != ITEM_TYPE_CHARGED then
if GetItemCharges(TempItem) == 0 then
set Costs = R2I(GetWidgetLife(TempItem))
else
set Costs = R2I(GetWidgetLife(TempItem)) * GetItemCharges(TempItem)
endif
else
if udg_Player_Team[GetPlayerNr(udg_Leaver)] == 1 then
set Costs = udg_Trader_Gold[R2I(GetWidgetLife(TempItem))] * GetItemCharges(TempItem)
else
set Costs = udg_Trader_Gold[11 - R2I(GetWidgetLife(TempItem))] * GetItemCharges(TempItem)
endif
endif
return Costs
endfunction
function Trig_Player_Remove_PickItem takes nothing returns nothing
local item EnumItem = GetEnumItem()
local integer i
local integer Team = udg_Player_Team[GetPlayerNr(udg_Leaver)]
local item NewItem
if GetItemPlayer( EnumItem ) == udg_Leaver then
if GetItemUserData(EnumItem)==2 then
call SetItemPlayer( EnumItem, GetPlayer(GetMaxHumanPlayers()+Team), true )
else
call AdjustPlayerStateBJ( Trig_Player_Remove_GetItemCosts(EnumItem) / 2, udg_Leaver, PLAYER_STATE_RESOURCE_GOLD )
call DestroyEffect( AddSpecialEffect( "UI\\Feedback\\GoldCredit\\GoldCredit.mdl", GetItemX(EnumItem), GetItemY(EnumItem)) )
if GetWidgetLife(EnumItem)>=1000 then
set i = GetItemCharges(EnumItem)
loop
set NewItem = CreateItem(GetItemTypeId(EnumItem),GetRandomReal(GetRectMinX(udg_JunkyardRect[Team])+16,GetRectMaxX(udg_JunkyardRect[Team])-16), GetRandomReal(GetRectMinY(udg_JunkyardRect[Team])+16,GetRectMaxY(udg_JunkyardRect[Team])-16))
call SetItemUserData(NewItem, 2)
call SetItemPlayer( NewItem, GetPlayer(GetMaxHumanPlayers()+Team), true )
set i = i - 1
exitwhen i <= 0
endloop
set NewItem = null
endif
call RemoveItem(EnumItem)
endif
endif
set EnumItem = null
endfunction
function Trig_Player_Remove_AddToGoldPool takes nothing returns nothing
local integer team = udg_Player_Team[GetPlayerNr(udg_Leaver)]
if ((team==1 and not RectContainsItem(GetFilterItem(),gg_rct_Team_1_Junkyard)) or (team==2 and not RectContainsItem(GetFilterItem(),gg_rct_Team_2_Junkyard))) then
set DivideMoney = DivideMoney + Trig_Player_Remove_GetItemCosts(GetEnumItem())
call RemoveItem(GetEnumItem())
else
call SetItemPlayer(GetEnumItem(),GetPlayer(GetMaxHumanPlayers()+udg_Player_Team[GetPlayerNr(udg_Leaver)]),false)
endif
endfunction
function Trig_Player_Remove_Actions takes nothing returns nothing
local integer PlayerID = GetPlayerNr(udg_Leaver)
local integer PlayerTeam = udg_Player_Team[PlayerID]
local integer i
local integer j
local integer k
local integer TraderValue
local integer TraderID
local integer TempItemID
local item TempItem
local item NewItem
local group G
local unit PickUnit
local boolean b = false
local boolexpr filter = Condition(function Trig_Player_Remove_OwningPlayer)
local string s = ""
set DivideMoney = 0
call StorePlayerVars(GetPlayerId(udg_Leaver))
if udg_PlayerIn[GetPlayerNr(udg_Leaver)] or udg_AI_IsBot[PlayerID] then
set udg_PlayerIn[GetPlayerNr(udg_Leaver)] = false
if IsTriggerEnabled(gg_trg_Kick_Vote) and udg_Leaver == KickVotePlayer then
set udg_p_KickerLeft = true
call TriggerExecute( gg_trg_Kick_End )
endif
// Because AI can't pick up items, they'll be removed
if IsMapFlagSet(MAP_LOCK_RESOURCE_TRADING) then
call EnumItemsInRect( udg_Playable_Map, null, function Trig_Player_Remove_PickItem )
endif
//player becomes Leaver AI when either not a bot already or he's a bot because of the AFK-AI
if udg_LeaversToAI and ((not udg_AI_IsBot[PlayerID]) or (udg_AI_IsBot[PlayerID] and udg_Afk[PlayerID])) then
if udg_Afk[PlayerID] then
call PlayerAfkReturn(udg_Leaver)
endif
if not udg_AI_Initialized then
set udg_AI_Initialized = true
call TriggerExecute( gg_trg_AI_InitTrig )
call TriggerRegisterTimerEvent( gg_trg_AI_Fight, 0.10, true )
endif
if GetUnitTypeId(udg_Tank[PlayerID]) == 'H01H' then
call TriggerExecute( gg_trg_AI_Start )
endif
set udg_AI_IsBot[PlayerID]=true
set udg_AI_Command[PlayerID]="attack"
call SetPlayerName(udg_Leaver, GetPlayerName(udg_Leaver) + " [AI]")
set k = 1
loop
exitwhen k > GetMaxHumanPlayers()
call MultiboardSetItemValueBJ( udg_Killboard[k], 2, ( ( GetPlayerNr(udg_Leaver) + 1 ) + udg_Player_Team[GetPlayerNr(udg_Leaver)] ), GetPlayerName(udg_Leaver) )
set k = k + 1
endloop
else
call ForceRemovePlayer( udg_Players, udg_Leaver )
call ForceRemovePlayer( udg_Players_Team[PlayerTeam], udg_Leaver )
set udg_Team_CountPlayers[PlayerTeam] = udg_Team_CountPlayers[PlayerTeam] - 1
set DivideMoney = GetPlayerState(udg_Leaver, PLAYER_STATE_RESOURCE_GOLD) * 2 + GetBounty(udg_Tank[PlayerID], false)
//Add the gold the player lost due to selling items, to lessen the negative effect of item sellers and leavers
set DivideMoney = DivideMoney + R2I(udg_Profit_Sold[GetPlayerNr(udg_Leaver)])
set G = GetUnitsInRectAllSafe(udg_Playable_Map)
// when the player tank is dead, it won't be added through the method above - so do it manually
if not IsUnitInGroup(udg_Tank[PlayerID], G) then
call GroupAddUnit(G, udg_Tank[PlayerID])
endif
set PickUnit = FirstOfGroup( G )
loop
exitwhen PickUnit == null
if (not IsMapFlagSet(MAP_LOCK_RESOURCE_TRADING)) or GetOwningPlayer(PickUnit) == udg_Leaver then
set i = 0
loop
exitwhen i > 5
set TempItem = UnitItemInSlot(PickUnit, i)
set TempItemID = GetItemTypeId(TempItem)
if TempItem != null and GetItemPlayer(TempItem)==udg_Leaver then
if PickUnit!= udg_Tank[PlayerID] then
set DivideMoney = DivideMoney + Trig_Player_Remove_GetItemCosts(TempItem)
endif
call PlaceItemOnJunkyard(PlayerID, TempItem, false)
call RemoveItem(TempItem)
endif
set i = i + 1
endloop
endif
if GetOwningPlayer(PickUnit) == udg_Leaver then
if GetUnitTypeId( PickUnit ) == 'h002' then // Healing Factory
call KillUnit( PickUnit )
set DivideMoney = DivideMoney + 2500
elseif GetUnitTypeId( PickUnit ) == 'h015' then // Troop Factory
call KillUnit( PickUnit )
set DivideMoney = DivideMoney + 3500
elseif GetUnitTypeId( PickUnit ) == 'h01K' then // Troop Command Center
call KillUnit( PickUnit )
set DivideMoney = DivideMoney + 2750
elseif GetUnitTypeId( PickUnit ) == 'z00I' then // Tech Mech
call KillUnit( PickUnit )
set DivideMoney = DivideMoney + 350
endif
if IsTinkerTower( PickUnit ) then
call KillUnit( PickUnit )
elseif PickUnit!= udg_Tank[PlayerID] then
call SetUnitOwner( PickUnit, GetPlayer(GetMaxHumanPlayers()+PlayerTeam), true )
if Trig_Player_Remove_IsCreep( PickUnit ) then
call IssuePointOrderLoc( PickUnit, "attack", udg_Move_Points[3-PlayerTeam] )
endif
endif
endif
call GroupRemoveUnit( G, PickUnit )
set PickUnit = FirstOfGroup( G )
endloop
call ReleaseGroup(G)
call EnumItemsInRect(bj_mapInitialPlayableArea,filter,function Trig_Player_Remove_AddToGoldPool)
set i = udg_Team_CountPlayers[PlayerTeam]
if i != 0 then
if IsMapFlagSet(MAP_LOCK_RESOURCE_TRADING) then
set DivideMoney = DivideMoney / (4*i)
else
set DivideMoney = DivideMoney / (2*i)
endif
if DivideMoney != 0 then
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if IsPlayerInForce(GetPlayer(i), udg_Players_Team[PlayerTeam]) then
//call AdjustPlayerStateBJ( DivideMoney, GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD )
//set udg_Profit_Force[i] = udg_Profit_Force[i] + DivideMoney
set udg_Income[i] = udg_Income[i] + DivideMoney
endif
set i = i + 1
endloop
call DisplayTextToForce( udg_Players_Team[PlayerTeam], "|cfffed312You will receive " + I2S(DivideMoney) + " leaver gold through your income in the next couple of minutes.|r " )
endif
if GetPlayerState(udg_Leaver, PLAYER_STATE_RESOURCE_LUMBER) != 0 then
set TraderValue = 0
set TraderID = 0
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if IsPlayerInForce(GetPlayer(i), udg_Players_Team[PlayerTeam]) then
if udg_Stats_Trader[i] > TraderValue then
set TraderValue = udg_Stats_Trader[i]
endif
endif
set i = i + 1
endloop
set udg_Stats[1] = TraderValue
set TraderID = GetPlayerNr(ForcePickRandomPlayer(GetPlayersMatchingSafe(Condition(function Trig_Player_Remove_IsAllyPlayingHighTradeRate))))
set udg_Stats[1] = 0
call DisplayTextToForce( GetForceOfPlayer(GetPlayer(TraderID)), "|cfffed312Received " + I2S(GetPlayerState(udg_Leaver, PLAYER_STATE_RESOURCE_LUMBER)) + " wood from|r " + udg_Color[PlayerID] + GetPlayerName(udg_Leaver) + "|r|cfffed312.|r" )
call AdjustPlayerStateBJ( GetPlayerState(udg_Leaver, PLAYER_STATE_RESOURCE_LUMBER), GetPlayer(TraderID), PLAYER_STATE_RESOURCE_LUMBER )
endif
endif
call SetPlayerState( udg_Leaver, PLAYER_STATE_RESOURCE_GOLD, 0 )
call SetPlayerState( udg_Leaver, PLAYER_STATE_RESOURCE_LUMBER, 0 )
call UpdateBoardPlayerPlayingState(PlayerID)
if IsUnitAliveBJ(udg_Tank[PlayerID]) then
call KillUnit( udg_Tank[PlayerID] )
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Other\\Volcano\\VolcanoDeath.mdl", udg_Tank[PlayerID], "origin" ) )
call DestroyEffect( AddSpecialEffectTarget( "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", udg_Tank[PlayerID], "origin" ) )
call DestroyEffect( AddSpecialEffectTarget( "UI\\Feedback\\GoldCredit\\GoldCredit.mdl", udg_Tank[PlayerID], "origin" ) )
else
call PauseTimer( udg_Tank_Timer[PlayerID] )
call DestroyTimerDialog( udg_Tank_TimerWindow[PlayerID] )
endif
set TempItem = null
set G = null
set udg_AI_IsBot[PlayerID]=false
set udg_Tank[PlayerID] = null
endif
if GiveUp_HasVoted[PlayerID] then
set GiveUp_Count[PlayerTeam] = GiveUp_Count[PlayerTeam] - 1
endif
call PauseTimer(PlayTimer[PlayerID-1])
set i = CountPlayersInForceBJ(udg_Players_Team[PlayerTeam])
if i == 0 then
set udg_Team_Winning = 3 - PlayerTeam
call TriggerExecute( gg_trg_Victory_Cinematic )
elseif ( i == GiveUp_Count[PlayerTeam] ) then
set s = GetPlayerName(GetPlayer(10+PlayerTeam)) + " voted to give up. If no vote changes, the game will be over in 10 seconds."
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 10.00, s )
call GameTimeWait(10)
if ( i == GiveUp_Count[PlayerTeam] ) then
set udg_Team_Winning = 3 - PlayerTeam
set udg_GaveUp[PlayerTeam] = true
call TriggerExecute( gg_trg_GiveUp_End )
endif
endif
endif
set udg_Leaver = null
set DivideMoney = 0
endfunction
//===========================================================================
function InitTrig_Player_Remove takes nothing returns nothing
set gg_trg_Player_Remove = CreateTrigger( )
call TriggerAddAction( gg_trg_Player_Remove, function Trig_Player_Remove_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Start_Killboard_Actions takes nothing returns nothing
local integer i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if udg_MultiboardType[i-1] != NO_BOARD then
call CreateNewMultiboard(GetPlayer(i))
endif
set i = i + 1
endloop
if udg_ObserverInGame then
set udg_MultiboardType[10] = DEFAULT_BOARD
set udg_MultiboardType[11] = DEFAULT_BOARD
call CreateNewMultiboard(Player(10))
call CreateNewMultiboard(Player(11))
endif
call TriggerExecute( gg_trg_Unit_Spawn )
call GameTimeWait(GAME_START_DELAY)
call EnableTrigger(gg_trg_Player_Income)
endfunction
//===========================================================================
function InitTrig_Start_Killboard takes nothing returns nothing
set gg_trg_Start_Killboard = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_Start_Killboard, 0.00 )
call TriggerAddAction( gg_trg_Start_Killboard, function Trig_Start_Killboard_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
library StringEval requires BTFramework
// Returns the first occurence of "searchFor" in "searchIn", -1 means no occurence,
// 0 means "searchIn" begings with "searchFor"
function StringPos takes string searchIn, string searchFor, integer offset returns integer
local integer pos = offset
local integer searchInL = StringLength(searchIn)
local integer searchForL = StringLength(searchFor)
local string firstchar
if searchForL<1 or searchForL>searchInL then
return -1
endif
set firstchar = SubString(searchFor,0,1)
if offset<0 then
set offset=0
endif
loop
exitwhen pos > searchInL-searchForL
// First only the first characters are compared to avoid creating
// long strings (as strings do always leak in wc3)
if SubString(searchIn,pos,pos+1)==firstchar then
if searchForL==1 or SubString(searchIn,pos,pos+searchForL)==searchFor then
return pos
endif
endif
set pos = pos + 1
endloop
return -1
endfunction
function StringIsLiteral takes string s returns boolean
local string literals = "abcdefghijklmnopqrstuvwxyz"
local integer i = StringLength(literals)-1
set s = StringCase(s,false)
loop
exitwhen i<0
if SubString(literals,i,i+1)==s then
return true
endif
set i = i - 1
endloop
return false
endfunction
// Takes a lower case color string and returns the player number
function GetPlayerNrFromColorString takes string colorstr returns integer
if(colorstr=="red")then
return 1
elseif(colorstr=="blue")then
return 2
elseif(colorstr=="teal")then
return 3
elseif(colorstr=="purple")then
return 4
elseif(colorstr=="yellow")then
return 5
elseif(colorstr=="orange")then
return 6
elseif(colorstr=="green")then
return 7
elseif(colorstr=="pink")then
return 8
elseif(colorstr=="gray")or(colorstr=="grey")then
return 9
elseif(colorstr=="lightblue")then
return 10
endif
return 0
endfunction
// Returns the player identified by "playerstr",
// numbers, colors and parts of player names are allowed
function GetPlayerFromString takes string playerstr returns player
local integer pid
local integer minPos = 1000
local integer curPos
local integer i
if playerstr=="" or playerstr==null then
return null
endif
set playerstr = StringCase(playerstr,false)
// Check for color
set pid=GetPlayerNrFromColorString(playerstr)
if(pid!=0)then
set minPos = 0
endif
if minPos!=0 then
// Check for number
set pid = S2I(playerstr)
if(pid>0 and pid<=GetMaxHumanPlayers() and StringLength(playerstr)==1+pid/10)then
set minPos = 0
else
set pid = 0
endif
endif
if minPos!=0 then
// Check for part of name
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
set curPos = StringPos(StringCase(GetPlayerName(GetPlayer(i)),false),playerstr,0)
if curPos!=-1 and curPos<minPos then
set pid = i
set minPos = curPos
endif
set i = i + 1
endloop
endif
return GetPlayer(pid)
endfunction
globals
player array udg_PlayerArrayFromString
endglobals
// Writes all players from the string into udg_PlayerArrayFromString[0..n],
// end of player list is indicated by a null-entry
function GetPlayerArrayFromString takes string s, player alwaysIncludePlayer returns nothing
local integer pos = -1
local integer endpos = 0
local integer playersFoundN = 0
local player enumPlayer
local integer PlayerID
local boolean array isPlayerListed
local boolean exit = false
if s==null or s=="" then
set udg_PlayerArrayFromString[0] = alwaysIncludePlayer
set udg_PlayerArrayFromString[1] = null
return
endif
loop
set endpos = StringPos(s," ",pos+1)
if endpos==-1 then
set endpos = StringLength(s)
set exit = true
endif
set enumPlayer = GetPlayerFromString(SubString(s,pos+1,endpos))
if enumPlayer!=null then
set PlayerID = GetPlayerNr(enumPlayer)
if not isPlayerListed[PlayerID] then
set udg_PlayerArrayFromString[playersFoundN] = enumPlayer
set isPlayerListed[PlayerID] = true
set playersFoundN = playersFoundN + 1
endif
endif
exitwhen exit
set pos = endpos
endloop
if alwaysIncludePlayer!=null and not isPlayerListed[GetPlayerNr(alwaysIncludePlayer)] then
set udg_PlayerArrayFromString[playersFoundN] = alwaysIncludePlayer
set playersFoundN = playersFoundN + 1
endif
set udg_PlayerArrayFromString[playersFoundN] = null
endfunction
endlibrary
//TESH.scrollpos=15
//TESH.alwaysfold=0
library ChatCommandEvent requires StringEval
globals
string udg_ChatCmdEventCmd
string udg_ChatCmdEventParams
string array udg_ChatCmd
trigger array udg_ChatCmdTrigger
integer udg_ChatCmdMax=-1
endglobals
function GetEventPlayerChatCommand takes nothing returns string
return udg_ChatCmdEventCmd
endfunction
function GetEventPlayerChatParams takes nothing returns string
return udg_ChatCmdEventParams
endfunction
function TriggerRegisterChatCommandEvent takes trigger t, string s returns nothing
if(s!=null)then
if(s=="")then
set s=null
else
set s=StringCase(s,false)
endif
endif
set udg_ChatCmdMax=udg_ChatCmdMax+1
set udg_ChatCmdTrigger[udg_ChatCmdMax]=t
set udg_ChatCmd[udg_ChatCmdMax]=s
endfunction
endlibrary
function Trig_Command_Event_SingleCommand takes string cmd, string params returns nothing
local integer i=0
set udg_ChatCmdEventCmd=cmd
set udg_ChatCmdEventParams=params
loop
exitwhen i > udg_ChatCmdMax
if ((udg_ChatCmd[i]==cmd) or (udg_ChatCmd[i]==null)) and IsTriggerEnabled(udg_ChatCmdTrigger[i]) then
call TriggerExecute(udg_ChatCmdTrigger[i])
endif
set i = i + 1
endloop
endfunction
function Trig_Command_Event_Actions takes nothing returns nothing
local string s = GetEventPlayerChatString()
local integer pos = 0
local integer exprEnd
local integer cmdEnd
local boolean exit
if SubString(s,0,1)!="-" then
return
endif
loop
// Look for first space
set cmdEnd=StringPos(s," ",pos+1)
if(cmdEnd==-1)then
// If there is no space, there will only be one command
set exprEnd=StringLength(s)
set cmdEnd=exprEnd
set exit=true
else
// If there is a space, the next command can't begin before this space
set exprEnd=StringPos(s," -",cmdEnd)
set exit=false
// If " -" is found, this could also mean a negative number,
// so jump to next " -" as long as it is not followed by a literal
loop
if exprEnd==-1 then
set exit=true
exitwhen true
endif
exitwhen StringIsLiteral(SubString(s,exprEnd+2,exprEnd+3))
set exprEnd=StringPos(s," -",exprEnd+2)
endloop
if exit then
set exprEnd=StringLength(s)
endif
endif
// Evaluate the single command
if(cmdEnd+1>=exprEnd)then
// No parameters
call Trig_Command_Event_SingleCommand(StringCase(SubString(s,pos+1,exprEnd),false),"")
else
call Trig_Command_Event_SingleCommand(StringCase(SubString(s,pos+1,cmdEnd),false),SubString(s,cmdEnd+1,exprEnd))
endif
exitwhen exit
set pos = exprEnd+1
endloop
endfunction
//===========================================================================
function InitTrig_Command_Event takes nothing returns nothing
local integer i=0
set gg_trg_Command_Event = CreateTrigger( )
loop
exitwhen i>11
call TriggerRegisterPlayerChatEvent( gg_trg_Command_Event, Player(i), "-", false )
set i = i + 1
endloop
call TriggerAddAction( gg_trg_Command_Event, function Trig_Command_Event_Actions )
endfunction
//TESH.scrollpos=441
//TESH.alwaysfold=0
function HostCommand takes nothing returns boolean
if udg_GameMode_Host!=GetTriggerPlayer() then
if GetLocalPlayer()==GetTriggerPlayer() then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312This command can only be used by the game leader.|r" )
endif
return false
endif
return true
endfunction
function TimeLimit takes integer sec returns boolean
if udg_Time_Value >= sec then
if GetLocalPlayer()==GetTriggerPlayer() then
if (sec/60)*60==sec then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312This command can only be used in the first "+I2S(sec/60)+" minutes.|r" )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312This command can only be used in the first "+I2S(sec)+" seconds.|r" )
endif
endif
return false
endif
return true
endfunction
function InitShowRange takes nothing returns nothing
local integer i = 1
local texttag tag
//those dots are used for the weapon range single player command
if bj_isSinglePlayer then
loop
exitwhen i > 72
set tag = CreateTextTag()
call SetTextTagText(tag, ".", 0.023)
call SetTextTagPos(tag, 1, 1, 50)
call SetTextTagVisibility(tag, false)
call SetTextTagPermanent(tag, true )
set udg_Show_WeaponRange_Text[i] = tag
set i = i + 1
endloop
endif
set tag = null
endfunction
function Trig_Jass_Commands_Actions takes nothing returns nothing
local player paramPlayer
local integer PlayerID
local integer Tankcosts
local integer Bounty
local string Command = GetEventPlayerChatCommand()
local string Params = GetEventPlayerChatParams()
local string Players = ""
local boolean IsLocalPlayer = GetLocalPlayer()==GetTriggerPlayer()
// temp variables
local integer i
local integer j
local real r
local string s
// Just try and see if this fixes the desynchs in the first second
if (TimerGetElapsed(udg_GameTime) <= 1) then
//call GameTimeWait(3)
endif
if Command == "unstuck" then
set i = GetPlayerNr(GetTriggerPlayer())
call PauseUnit( udg_Tank[i], true )
call IssueImmediateOrder( udg_Tank[i], "stop" )
call PauseUnit( udg_Tank[i], false )
call ShowUnit( udg_Tank[i], true )
call EnableUserControl(true)
if IsLocalPlayer then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312In case this didn't help, try pressing shift once.|r" )
endif
endif
//============================================================================================================
// Game Modes
//============================================================================================================
if Command == "share" and HostCommand() and TimeLimit(120) then
if (not LeagueConfirmed) and (not LeagueImitation) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Gold sharing enabled." )
call SetMapFlag( MAP_LOCK_RESOURCE_TRADING, false )
call DisableTrigger( gg_trg_Anti_Shared_Control )
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
set j = 0
loop
exitwhen j > 5
if GetItemTypeId(UnitItemInSlot(udg_Tank[i], j)) == 'I048' then
call RemoveItem( UnitItemInSlot(udg_Tank[i], j) )
endif
set j = j + 1
endloop
set i = i + 1
endloop
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Not available in the league." )
endif
endif
if (Command == "leaverai" or Command == "lai") and HostCommand() then
if (not LeagueConfirmed) and (not LeagueImitation) then
set udg_LeaversToAI = not udg_LeaversToAI
if udg_LeaversToAI then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Enabled the AI for leavers." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Disabled the AI for leavers." )
endif
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Not available in the league." )
endif
endif
if (Command == "conquestvictory" or Command == "cv") and HostCommand() and TimeLimit(120) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Conquest Victory enabled." )
set udg_CV = true
endif
if (Command == "tankmonopoly" or Command == "tmono") and HostCommand() and TimeLimit(120) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Tank Monopoly enabled." )
set udg_TankMonopoly = true
endif
//============================================================================================================
// Information
//============================================================================================================
if Command == "pos" then
// Store adressed players into udg_PlayerArrayFromString
call GetPlayerArrayFromString(GetEventPlayerChatParams(),null)
if udg_PlayerArrayFromString[0]==null then
set udg_PlayerArrayFromString[0] = GetTriggerPlayer()
set udg_PlayerArrayFromString[1] = null
endif
set i = 0
loop
exitwhen udg_PlayerArrayFromString[i]==null
set PlayerID = GetPlayerNr(udg_PlayerArrayFromString[i])
if udg_Tank[PlayerID] != null and IsUnitAliveBJ(udg_Tank[PlayerID]) and IsUnitVisible(udg_Tank[PlayerID], GetTriggerPlayer()) and GetLocalPlayer() == GetTriggerPlayer() then
call PingMinimapEx(GetUnitX(udg_Tank[PlayerID]), GetUnitY(udg_Tank[PlayerID]), 0.80, 160, 160, 160, false)
endif
set i = i + 1
endloop
endif
if (Command == "itemdamage" or Command == "id") and IsLocalPlayer then
set PlayerID = GetPlayerNr(GetTriggerPlayer())
set r = GetExplosiveDamage(udg_Tank[PlayerID], false)
set j = GetPlayerTechCount(GetTriggerPlayer(), 'R002', true)
if (r > 0) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Explosives damage:|r " + I2S(R2I(r)) )
endif
if (GetUnitAbilityLevel(udg_Tank[PlayerID], 'A04U') > 0) then
set i = GetUnitAbilityLevel(udg_Tank[PlayerID], 'A04U')
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Demolisher Mine damage:|r " + I2S(R2I(320 * i * (1.0 + 0.03 * j))) )
endif
set s = "|cfffed312Mine damage - Normal: |r " + I2S(R2I(1600 * (1.0 + 0.03 * j)))
set s = s + "|cfffed312 | Heavy: |r " + I2S(R2I(3200 * (1.0 + 0.03 * j)))
set s = s + "|cfffed312 | Huge: |r " + I2S(R2I(4800 * (1.0 + 0.03 * j)))
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, s )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Orbital damage (x6):|r " + I2S(R2I(500 * (1.0 + 0.05 * j))) )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Bomb damage:|r " + I2S(R2I(12500 * (1.0 + 0.05 * j))) + " |cfffed312(only in the center)|r" )
endif
if (Command == "income") and IsLocalPlayer then
set PlayerID = GetPlayerNr(GetTriggerPlayer())
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312The amount of gold you got from these sources:|r")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Creeps and Buildings:|r " + I2S(R2I(udg_Profit_Creeps[PlayerID])) )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Tank kills:|r " + I2S(R2I(udg_Profit_Tanks[PlayerID])) )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Force gold:|r " + I2S(R2I(udg_Profit_Force[PlayerID])) )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Income every second:|r " + I2S(R2I(udg_Profit_Income[PlayerID])) )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Lost due to selling:|r " + I2S(R2I(udg_Profit_Sold[PlayerID])) )
set i = ModuloInteger(udg_Time_Value, 300)
set r = GetPlayerState(udg_Force[udg_Player_Team[PlayerID]], PLAYER_STATE_RESOURCE_GOLD) / i * 300
set i = GetForceIncome(R2I(r), udg_Team_CountPlayers[udg_Player_Team[PlayerID]])
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, " " )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Expected next force gold:|r " + I2S(i) )
endif
if (Command == "tech") and IsLocalPlayer then
set i = udg_Player_Team[GetPlayerNr(GetTriggerPlayer())]
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Your team has the following technologies:|r")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312- Weapons:|r " + I2S(GetPlayerTechCount(GetTriggerPlayer(), 'R002', true)) + "|cfffed312/|r30")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312- Armor:|r " + I2S(GetPlayerTechCount(GetTriggerPlayer(), 'R003', true)) + "|cfffed312/|r30")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312- Aura:|r " + I2S(GetPlayerTechCount( GetPlayer(( udg_Player_Team[GetPlayerNr(GetTriggerPlayer())] + 10 )),'R005', true)) + "|cfffed312/|r3")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Your team has the following creep wave buffs left:|r")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312- Damage:|r " + I2S(DamageBuffCount[i]))
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312- Resistance:|r " + I2S(MagicBuffCount[i]))
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312- Mortars:|r " + I2S(MortarBuffCount[i]))
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Your tank has the following technology:|r")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312- Mana:|r " + I2S(ManaUpgrade[GetPlayerNr(GetTriggerPlayer())]) + "|cfffed312/|r10")
endif
if (Command == "mode") and IsLocalPlayer then
if (udg_GameMode == 1) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cff00ff00Normal|r: Destroy the enemy Vehicle Factory." )
endif
if (udg_GameMode == 2) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cff00ff00Royal Flush|r: Destroy the enemy Vehicle Factory. Doubled bounty for kills, gold loss on death." )
endif
if (udg_GameMode == 3) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cff00ff00Alternative|r: Destroy the enemy Vehicle Factory. Various possible settings." )
endif
if (udg_GameMode == 4) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cff00ff00League|r: Destroy the enemy Vehicle Factory." )
endif
call ShowSpecialOptions(GetTriggerPlayer())
endif
if Command == "hp" and IsLocalPlayer then
set HitpointChanges = not HitpointChanges
endif
if (Command == "penalty") and IsLocalPlayer then
set PlayerID = GetPlayerNr(GetTriggerPlayer())
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312With each additional penalty you become easier to kick (and nothing else).|r")
if (Player_Penalty[PlayerID] == 0) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312You don't have any penalty points.|r")
else
if (Player_Penalty[PlayerID] == 1) then
set s = "|cfffed312 penalty"
else
set s = "|cfffed312 penalties"
endif
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312You received |r" + I2S(Player_Penalty[PlayerID]) + s + ", because of the following actions:")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312" + Player_Penalty_Message[PlayerID])
endif
endif
//============================================================================================================
// Customization
//============================================================================================================
if Command == "weather" or Command == "w" and IsLocalPlayer then
set udg_Weather_Enabled = not udg_Weather_Enabled
if udg_Weather_Enabled then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Weather effects enabled.|r" )
if udg_Weather_Current < 6 then
call EnableWeatherEffect( udg_Weather_Effects[udg_Weather_Current], true )
endif
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Weather effects disabled.|r" )
call EnableWeatherEffect( udg_Weather_Effects[1], false )
call EnableWeatherEffect( udg_Weather_Effects[2], false )
call EnableWeatherEffect( udg_Weather_Effects[3], false )
call EnableWeatherEffect( udg_Weather_Effects[4], false )
call EnableWeatherEffect( udg_Weather_Effects[5], false )
endif
return
endif
if Command == "anglez" then
if IsLocalPlayer then
if Params=="" then
set udg_Cam_AngleZ = 56
else
set udg_Cam_AngleZ = ModuloReal( S2R(Params) , 180.00)
endif
endif
elseif Command == "angle" and IsLocalPlayer then
set udg_Cam_Angle = ModuloReal( S2R(Params) + 90.00 , 360.00)
endif
if Command == "zoom" and IsLocalPlayer then
set udg_Cam_Distance = S2R(Params)
if udg_Cam_Distance == 0 then
set udg_Cam_Distance = 2750
elseif udg_Cam_Distance < 500 then
set udg_Cam_Distance = 500
elseif udg_Cam_Distance > 5000 then
set udg_Cam_Distance = 5000
endif
endif
if Command == "clear" and IsLocalPlayer then
call ClearTextMessages()
endif
if (Command == "revivecam" or Command == "rc") and IsLocalPlayer then
set udg_ReviveCamPan = not udg_ReviveCamPan
if udg_ReviveCamPan then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Enabled the revive cam pan." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Disabled the revive cam pan." )
endif
endif
if Command == "smoothcam" or Command == "sc" then
set i = GetPlayerId(GetTriggerPlayer())
set SmoothCam[i] = not SmoothCam[i]
if IsLocalPlayer then
if SmoothCam[i] then
call CameraSetSmoothingFactor(CamSmooth)
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0,0,10.00, "Smooth camera activated." )
else
call CameraSetSmoothingFactor(0)
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0,0,10.00, "Smooth camera deactivated." )
endif
endif
endif
//To prevent using afk before a mode has been chosen (pretty smart, to check for something completely different ... right?)
if IsTriggerEnabled(gg_trg_Player_Income) then
if Command=="afkai" then
if udg_GameMode != 4 then
call PlayerAfkActivate(GetTriggerPlayer(),Params,true)
else
if IsLocalPlayer then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "AI is disabled in League Mode." )
endif
endif
elseif Command=="afk" then
call PlayerAfkActivate(GetTriggerPlayer(),Params,false)
endif
endif
if (Command == "effects" or Command == "e") and HostCommand() then
set udg_NoEffects = not udg_NoEffects
if udg_NoEffects then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Some special effects have been disabled." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "All special effects have been enabled." )
endif
endif
if Command == "mb" then
if Params=="" then
set udg_MultiboardType[GetPlayerId(GetTriggerPlayer())] = 0
else
if (Params == "esc") then
if IsLocalPlayer then
set udg_Multiboard_Escape = not udg_Multiboard_Escape
if udg_Multiboard_Escape then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Multiboard can now be toggled with the escape key.|r" )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Multiboard can no longer be toggled with the escape key.|r" )
endif
endif
else
set i = S2I(Params)
if (i >= 0) and (i <= 2) then
set udg_MultiboardType[GetPlayerId(GetTriggerPlayer())] = i
endif
endif
endif
call CreateNewMultiboard(GetTriggerPlayer())
endif
if Command == "mb esc" and IsLocalPlayer then
endif
if Command == "handicap" then
set PlayerID = GetPlayerNr(GetTriggerPlayer())
set i = S2I(Params)
if (GetUnitState(udg_Tank[PlayerID], UNIT_STATE_LIFE) == GetUnitState(udg_Tank[PlayerID], UNIT_STATE_MAX_LIFE)) then
if (udg_Handicap_Ready[PlayerID]) then
set udg_Handicap_Ready[PlayerID] = false
if (i > 100) then
set i = 100
elseif (i < 10) then
set i = 10
endif
call SetPlayerHandicapBJ(GetTriggerPlayer(), I2R(i))
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Handicap set to|r " + ( I2S(R2I(GetPlayerHandicapBJ(GetTriggerPlayer()))) + "%|cfffed312.|r" ))
call GameTimeWait(120)
set udg_Handicap_Ready[PlayerID] = true
else
if IsLocalPlayer then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312You can only use that command once every 2 minutes.|r " )
endif
endif
else
if IsLocalPlayer then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312Cannot change the handicap when the tank is damaged.|r " )
endif
endif
endif
if Command == "print" and DebugMode then
set i = 1
loop
exitwhen i > GetMaxPlayers()
call WeaponHolder[i].PrintWeapons("Player " + I2S(i))
set i = i + 1
endloop
endif
//============================================================================================================
// Singleplayer
//============================================================================================================
if bj_isSinglePlayer then
if Command == "xp" then
call AddHeroXP(udg_Tank[GetPlayerNr(GetTriggerPlayer())],100000000,true)
endif
if Command == "gold" then
if Params=="" then
call SetPlayerState(GetTriggerPlayer(),PLAYER_STATE_RESOURCE_GOLD,1000000)
else
call SetPlayerState(GetTriggerPlayer(),PLAYER_STATE_RESOURCE_GOLD,S2I(Params))
endif
endif
if Command == "upgrades" then
set i = 1
loop
exitwhen i > GetMaxPlayers()
call SetPlayerTechResearched( GetPlayer(i), 'R002', 30 )
call SetPlayerTechResearched( GetPlayer(i), 'R003', 30 )
call SetPlayerTechResearched( GetPlayer(i), 'R008', 30 )
call SetPlayerTechResearched( GetPlayer(i), 'R009', 30 )
set i = i + 1
endloop
endif
if Command == "showrange" then
if udg_Show_WeaponRange_Text[1]==null then
call InitShowRange( )
endif
set i = 1
set udg_Show_WeaponRange_Mode = S2I(Params)
if udg_Show_WeaponRange_Mode != 0 then
call GetWeaponRangeMode(udg_Tank[GetPlayerNr(udg_GameMode_Host)], udg_Show_WeaponRange_Mode)
call EnableTrigger(gg_trg_Weapon_Range)
loop
exitwhen i > 72
call SetTextTagVisibility(udg_Show_WeaponRange_Text[i], true)
set i = i + 1
endloop
endif
if udg_Show_WeaponRange_Mode == 0 then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Showing weapon range disabled." )
call DisableTrigger( gg_trg_Weapon_Range )
loop
exitwhen i > 72
call SetTextTagVisibility(udg_Show_WeaponRange_Text[i], false)
set i = i + 1
endloop
elseif udg_Show_WeaponRange_Mode == 1 then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Showing average weapon range." )
elseif udg_Show_WeaponRange_Mode == 2 then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Showing maximum weapon range." )
elseif udg_Show_WeaponRange_Mode == 3 then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Showing minimum weapon range." )
elseif (udg_Show_WeaponRange_Mode > 3) or (udg_Show_WeaponRange_Mode < 0) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "The mode has to be between 0 and 3." )
set udg_Show_WeaponRange_Mode = 0
endif
endif
if DebugMode and Command == "kill" then
call KillUnit(FirstOfGroup(GetUnitsSelectedAll(GetTriggerPlayer())))
endif
if (DebugMode and Command == "denial") then
set i = 1
loop
exitwhen (i > GetMaxHumanPlayers())
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Player " + I2S(i) + ": " + R2S(DenialScore[i]) )
set i = i + 1
endloop
endif
endif
//============================================================================================================
// AI Debug Commands
//============================================================================================================
if Command == "debug" and BetaMode then
if Params=="" then
set DebugMode = not DebugMode
if DebugMode then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Debugging activated." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Debugging deactivated." )
endif
endif
if Params == "list" then
//call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "-debug xp" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "-debug finisher" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "-debug weapons" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "-debug tanks" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "-debug heal" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "-debug skill" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "-debug afk" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "-debug com x" )
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "-debug ms x" )
endif
if Params == "xp" then
set udg_AI_Debug[1] = not udg_AI_Debug[1]
if udg_AI_Debug[1] then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "XP-gain activated." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "XP-gain deactivated." )
endif
endif
if Params == "finisher" then
set udg_AI_Debug[2] = not udg_AI_Debug[2]
if udg_AI_Debug[2] then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Finishing abilities activated." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Finishing abilities deactivated." )
endif
endif
if Params == "weapons" then
set udg_AI_Debug[3] = not udg_AI_Debug[3]
if udg_AI_Debug[3] then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Buying weapons activated." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Buying weapons deactivated." )
endif
endif
if Params == "tanks" then
set udg_AI_Debug[4] = not udg_AI_Debug[4]
if udg_AI_Debug[4] then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Buying tanks activated." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Buying tanks deactivated." )
endif
endif
if Params == "heal" then
set udg_AI_Debug[5] = not udg_AI_Debug[5]
if udg_AI_Debug[5] then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Healing activated." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Healing deactivated." )
endif
endif
if Params == "skill" then
set udg_AI_Debug[6] = not udg_AI_Debug[6]
if udg_AI_Debug[6] then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Learning skills activated." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Learning skills deactivated." )
endif
endif
if Params == "afk" then
set udg_AI_Debug[7] = not udg_AI_Debug[7]
if udg_AI_Debug[7] then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Auto-afk activated." )
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "Auto-afk deactivated." )
endif
endif
if SubString(Params,0,3) == "com" then
set PlayerID = GetPlayerNr(GetPlayerFromString(SubString(Params, 4, StringLength(Params))))
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, udg_AI_Command[PlayerID] )
endif
if SubString(Params,0,2) == "ms" then
set PlayerID = GetPlayerNr(GetPlayerFromString(SubString(Params, 3, StringLength(Params))))
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, R2S(GetUnitMoveSpeed(udg_Tank[PlayerID])) )
endif
endif
endfunction
//===========================================================================
function InitTrig_Jass_Commands takes nothing returns nothing
set gg_trg_Jass_Commands = CreateTrigger( )
call TriggerRegisterChatCommandEvent(gg_trg_Jass_Commands,null)
call TriggerAddAction( gg_trg_Jass_Commands, function Trig_Jass_Commands_Actions )
endfunction
//TESH.scrollpos=8
//TESH.alwaysfold=0
function Trig_Stats_Actions takes nothing returns nothing
local integer i = 0
local integer PlayerID
local string array lines
local string divider = ""
// Store adressed players into udg_PlayerArrayFromString
call GetPlayerArrayFromString(GetEventPlayerChatParams(),GetTriggerPlayer())
// Set the titles of stats
set lines[0] = "|cfffed312Statistics:|r "
set lines[1] = "|cfffed312Vehicle costs:|r "
set lines[2] = "|cfffed312Tank kills:|r "
set lines[3] = "|cfffed312Building kills:|r "
set lines[4] = "|cfffed312Unit kills:|r "
set lines[5] = "|cfffed312CPs conquered:|r "
set lines[6] = "|cfffed312Created units:|r "
set lines[7] = "|cfffed312Self kills:|r "
set lines[8] = "|cfffed312Assists:|r "
set lines[9] = "|cfffed312Actions per minute:|r "
// Loop though players and add their data
loop
exitwhen udg_PlayerArrayFromString[i]==null
set PlayerID = GetPlayerNr(udg_PlayerArrayFromString[i])
if udg_PlayerInStart[PlayerID] then
set lines[0] = lines[0] + divider + udg_Color[PlayerID] + GetPlayerName(GetPlayer(PlayerID)) + "|r"
set lines[1] = lines[1] + divider + I2S(GetBounty(udg_Tank[PlayerID], false))
set lines[2] = lines[2] + divider + I2S(udg_Kills[PlayerID])
set lines[3] = lines[3] + divider + I2S(BuildingsKilled[PlayerID-1])
set lines[4] = lines[4] + divider + I2S(udg_Stats_CreepKills[PlayerID])
set lines[5] = lines[5] + divider + I2S(udg_Stats_CPs[PlayerID])
set lines[6] = lines[6] + divider + I2S(udg_Stats_CreepBuy[PlayerID]+udg_Stats_Buildings[PlayerID])
set lines[7] = lines[7] + divider + I2S(udg_Selfkills[PlayerID])
set lines[8] = lines[8] + divider + I2S(udg_Assists[PlayerID])
set lines[9] = lines[9] + divider + I2S(R2I(60*udg_Actions[PlayerID]/TimerGetElapsed(udg_GameTime)))
set divider = " |cfffed312/|r "
endif
set i = i + 1
endloop
// Display all lines
if GetLocalPlayer()==GetTriggerPlayer() then
set i=0
loop
exitwhen i > 9
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, lines[i] )
set i = i + 1
endloop
endif
endfunction
//===========================================================================
function InitTrig_Stats takes nothing returns nothing
set gg_trg_Stats = CreateTrigger( )
call TriggerRegisterChatCommandEvent(gg_trg_Stats,"stats")
call TriggerAddAction( gg_trg_Stats, function Trig_Stats_Actions )
endfunction
function Trig_Chat_Actions takes nothing returns nothing
local integer i = GetPlayerNr(GetTriggerPlayer())
set udg_Stats_Chat[i] = udg_Stats_Chat[i] + StringLength(GetEventPlayerChatString())
endfunction
//===========================================================================
function InitTrig_Chat takes nothing returns nothing
set gg_trg_Chat = CreateTrigger( )
call TriggerAddAction( gg_trg_Chat, function Trig_Chat_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Team_Actions takes nothing returns nothing
local string name = GetEventPlayerChatParams()
local integer i=0
local integer j
local integer pid = GetPlayerNr(GetTriggerPlayer())
loop
exitwhen i > 15
if GetPlayerName(Player(i))==name then
if GetLocalPlayer() == GetTriggerPlayer() then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312This name is already used.|r" )
endif
return
endif
set i = i + 1
endloop
if udg_Team_Rename[pid] >= 5 then
if GetLocalPlayer() == GetTriggerPlayer() then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312This command can only be used 5 times.|r" )
endif
return
endif
call SetPlayerName( udg_Force[udg_Player_Team[pid]], name )
set udg_Team_Rename[pid] = udg_Team_Rename[pid] + 1
if udg_Player_Team[pid]==1 then
set TeamOneName = name
set i = 2
else
set TeamTwoName = name
set i = 8
endif
set j = 0
loop
exitwhen j > GetMaxHumanPlayers()
if (udg_MultiboardType[j] != SIMPLE_BOARD) then
call MultiboardSetItemValueBJ( udg_Killboard[j], 2, i, name )
endif
set j = j + 1
endloop
endfunction
//===========================================================================
function InitTrig_Team takes nothing returns nothing
set gg_trg_Team = CreateTrigger( )
call TriggerRegisterChatCommandEvent(gg_trg_Team,"team")
call TriggerAddAction( gg_trg_Team, function Trig_Team_Actions )
endfunction
//TESH.scrollpos=7
//TESH.alwaysfold=0
function Trig_Give_Actions takes nothing returns nothing
local string param = StringCase(GetEventPlayerChatParams(),false)
local integer nameLen = StringPos(param," ",0)
local string AmountStr
local string S
local integer i = 1
local integer Amount = 0
local integer Target = -1
local integer Length
local player Giver = GetTriggerPlayer()
if IsMapFlagSet(MAP_LOCK_RESOURCE_TRADING) then
if GetTriggerPlayer() == GetLocalPlayer() then
call DisplayTextToPlayer( GetLocalPlayer( ), 0, 0, "|Cfffed312Nopool is enabled. Gold cannot be sent to allied players.|r" )
endif
return
elseif GetPlayerState( GetTriggerPlayer( ), PLAYER_STATE_RESOURCE_GOLD ) == 0 then
return
elseif nameLen==-1 then
return
endif
set AmountStr = SubString(param,nameLen,StringLength(param))
set Target = GetPlayerNr(GetPlayerFromString(SubString(param,0,nameLen)))
if Target != 0 then
set i = GetPlayerState( Giver, PLAYER_STATE_RESOURCE_GOLD )
set Length = StringLength( AmountStr )
if SubString( AmountStr, Length - 3, Length ) == "all" then
set Amount = i
elseif SubString( AmountStr, Length - 1, Length ) == "k" then
set Amount = R2I( 1000.00 * S2R( AmountStr ) )
else
set Amount = S2I( AmountStr )
endif
if Amount > 0 then
if Amount > i then
set Amount = i
endif
if GetLocalPlayer( ) == Giver then
call DisplayTextToPlayer( GetLocalPlayer( ), 0, 0, "|Cfffed312Sent " + I2S( Amount ) + " gold to|r " + udg_Color[Target] + GetPlayerName( GetPlayer( Target ) ) + "|r|Cfffed312.|r" )
elseif GetLocalPlayer( ) == GetPlayer( Target ) then
call DisplayTextToPlayer( GetLocalPlayer( ), 0, 0, "|Cfffed312Received " + I2S( Amount ) + " gold from|r " + udg_Color[GetPlayerNr( Giver )] + GetPlayerName( Giver ) + "|r|Cfffed312.|r" )
endif
call SetPlayerState( Giver, PLAYER_STATE_RESOURCE_GOLD, i - Amount )
call SetPlayerState( GetPlayer( Target ), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState( GetPlayer( Target ), PLAYER_STATE_RESOURCE_GOLD ) + Amount )
endif
endif
endfunction
//===========================================================================
function InitTrig_Give takes nothing returns nothing
set gg_trg_Give = CreateTrigger( )
call TriggerRegisterChatCommandEvent(gg_trg_Give,"give")
call TriggerAddAction( gg_trg_Give, function Trig_Give_Actions )
endfunction
//TESH.scrollpos=103
//TESH.alwaysfold=0
function Trig_Kick_Start_Count takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer TimerIndex = GetHandleIndex(t)
local integer time
set udg_AV_Int1[TimerIndex] = udg_AV_Int1[TimerIndex] - 1
set time = udg_AV_Int1[TimerIndex]
if (time > 0) then
call LeaderboardSetItemLabel(udg_KickBoard, 2, "|cfffed312Time left to vote:|r " + I2S(time))
else
if IsTriggerEnabled(gg_trg_Kick_Vote) then
call TriggerExecute( gg_trg_Kick_End )
endif
call ReleaseHandleIndex(TimerIndex)
call ReleaseTimer(t)
endif
endfunction
function Trig_Kick_Start_Actions takes nothing returns nothing
local player TriggerPlayer = GetTriggerPlayer()
local player kickTarget
local string param = GetEventPlayerChatParams()
local string kickMsg
local integer nameLen = StringPos(param," ",0)
local integer i = 1
local integer playerNr = GetPlayerNr(TriggerPlayer)
local timer t
local integer TimerIndex
if not udg_Kick_Ready[playerNr] then
if GetLocalPlayer()==TriggerPlayer then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312You may only start a kick-vote once every " + I2S(udg_Kick_Timeout[playerNr]) + " seconds.|r" )
endif
return
endif
if nameLen==-1 then
set nameLen=StringLength(param)
set kickMsg = "-No Reason-"
else
set kickMsg = SubString(param,nameLen+1,StringLength(param))
endif
set kickTarget = GetPlayerFromString(SubString(param,0,nameLen))
set i = GetPlayerNr(kickTarget)
if (kickTarget==TriggerPlayer) then
if GetLocalPlayer()==TriggerPlayer then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312You can't kick yourself.|r" )
endif
return
endif
if (kickTarget==null) or (i > GetMaxHumanPlayers()) or (not IsPlayerInForce(kickTarget, udg_Players)) then
if GetLocalPlayer()==TriggerPlayer then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312You have to specify a player to kick.|r" )
endif
return
endif
if IsPlayerEnemy(kickTarget, TriggerPlayer) then
if GetLocalPlayer()==TriggerPlayer then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312You cannot kick your enemies.|r" )
endif
return
endif
if udg_Kick_Progress then
if GetLocalPlayer()==TriggerPlayer then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312A kick vote is currently in progress.|r" )
endif
return
endif
set KickVotePlayer = TriggerPlayer
set udg_Kick_Player = kickTarget
set udg_Kick_Count[1] = 1
//Don't initiate the kick process, when it's not possible to kick anyway
if (VotesNeeded(i) == -1) then
if GetLocalPlayer()==TriggerPlayer then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312This player does not have enough penalties to be kickable. Current penalties: |r" + I2S(Player_Penalty[i]) )
if BetaMode then
//call DisplayTimedTextToPlayer(TriggerPlayer, 0, 0, 5, "|cfffed312If you think this is unjustified, write:|r !report kick " + I2S(udg_Kick_Count[2]))
endif
endif
return
endif
set udg_Kick_Ready[playerNr] = false
set udg_Kick_Votes_Needed = VotesNeeded(i)
call DisplayTextToPlayer(GetLocalPlayer(),0,0, udg_Color[playerNr] + GetPlayerName(TriggerPlayer) + "|r "+ "|cfffed312would like to kick |r" + udg_Color[i] + GetPlayerName(udg_Kick_Player) + "|r." )
//Only display to the team, of the kicking player, but not to the kicking player or target player themself
if (GetLocalPlayer() != udg_Kick_Player) and (GetLocalPlayer() != TriggerPlayer) and ((udg_Player_Team[GetPlayerNr(GetLocalPlayer())] == udg_Player_Team[GetPlayerNr(udg_Kick_Player)])) then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312You have 20 seconds to vote with \"|r-yes|cfffed312\"")
endif
if GetLocalPlayer() == TriggerPlayer then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312Vote registered|r")
endif
call StartSound( gg_snd_Hint )
set udg_KickBoard = CreateLeaderboardBJ( GetPlayersAll(), "Kick Votes: " + I2S(udg_Kick_Count[1]) + " Needed: " + I2S(udg_Kick_Votes_Needed) )
call LeaderboardAddItem(udg_KickBoard, "|cfffed312Kick: |r" + udg_Color[i] + GetPlayerName(udg_Kick_Player),0, udg_Kick_Player)
call LeaderboardAddItem(udg_KickBoard, "|cfffed312Reason: "+kickMsg+"|r",0, udg_Kick_Player)
call LeaderboardAddItem(udg_KickBoard, "|cfffed312Time left to vote:|r 20",0, udg_Kick_Player)
call LeaderboardAddItem(udg_KickBoard, "|cfffed312Received penalties: ",0, udg_Kick_Player)
call LeaderboardAddItem(udg_KickBoard, Player_Penalty_Message[i],0, udg_Kick_Player)
call LeaderboardSetStyle(udg_KickBoard, true, true, false, false)
call LeaderboardSetSizeByItemCount(udg_KickBoard, 5)
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if ( i != GetPlayerNr(TriggerPlayer) ) then
set udg_Kick_HasAlreadyVoted[i] = false
else
set udg_Kick_HasAlreadyVoted[i] = true
endif
set i = i + 1
endloop
set i = 0
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[TimerIndex] = 20
call TimerStart(t, 1, true, function Trig_Kick_Start_Count)
call EnableTrigger( gg_trg_Kick_Vote )
set udg_Kick_Progress = true
set i = GetPlayerNr(udg_Kick_Player)
if not (bj_isSinglePlayer) then
call GameTimeWait(udg_Kick_Timeout[playerNr])
set udg_Kick_Timeout[playerNr] = IMinBJ(960, udg_Kick_Timeout[playerNr] * 2)
else
call TriggerExecute( gg_trg_Kick_End )
endif
set udg_Kick_Ready[playerNr] = true
endfunction
//===========================================================================
function InitTrig_Kick_Start takes nothing returns nothing
set gg_trg_Kick_Start = CreateTrigger( )
call DisableTrigger( gg_trg_Kick_Start )
call TriggerRegisterChatCommandEvent(gg_trg_Kick_Start,"kick")
call TriggerAddAction( gg_trg_Kick_Start, function Trig_Kick_Start_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Kick_Vote_Actions takes nothing returns nothing
local integer i = 1
local integer p = GetPlayerNr(GetTriggerPlayer())
local string Command = GetEventPlayerChatCommand()
local string s = ""
local boolean IsSameTeam = (udg_Player_Team[p] == udg_Player_Team[GetPlayerNr(udg_Kick_Player)])
if (Command == "yes") and (udg_Kick_HasAlreadyVoted[p] == false) and (GetTriggerPlayer() != udg_Kick_Player) and IsSameTeam then
set udg_Kick_Count[1] = udg_Kick_Count[1] + 1
set udg_Kick_HasAlreadyVoted[p] = true
set s = "|cfffed312Vote registered|r"
if (IsKickVoteSuccessful(udg_Kick_Votes_Needed)) then
if IsTriggerEnabled(gg_trg_Kick_Vote) then
call TriggerExecute( gg_trg_Kick_End )
endif
endif
elseif (Command == "no") and (GetTriggerPlayer() != udg_Kick_Player) and IsSameTeam then
// set udg_Kick_Count[2] = udg_Kick_Count[2] + 1
// set udg_Kick_HasAlreadyVoted[p] = true
// set s = "|cfffed312Vote registered|r"
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0,0,10.00, "|cfffed312" + GetPlayerName(GetTriggerPlayer()) + " does not support this kick vote.|r" )
endif
call LeaderboardSetLabel(udg_KickBoard, "Kick Votes: " + I2S(udg_Kick_Count[1]) + " Needed: " + I2S(udg_Kick_Votes_Needed))
if GetLocalPlayer() == GetTriggerPlayer() then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, s)
endif
endfunction
//===========================================================================
function InitTrig_Kick_Vote takes nothing returns nothing
set gg_trg_Kick_Vote = CreateTrigger( )
call DisableTrigger( gg_trg_Kick_Vote )
call TriggerRegisterChatCommandEvent(gg_trg_Kick_Vote,"yes")
call TriggerRegisterChatCommandEvent(gg_trg_Kick_Vote,"no")
call TriggerAddAction( gg_trg_Kick_Vote, function Trig_Kick_Vote_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Kick_End_Actions takes nothing returns nothing
local integer i = CountPlayersInForceBJ(udg_Players)
local integer nr = GetPlayerNr(udg_Kick_Player)
call DisableTrigger( gg_trg_Kick_Vote )
set udg_Kick_Progress = false
set KickVotePlayer = null
if (not IsKickVoteSuccessful(udg_Kick_Votes_Needed)) or ( udg_p_KickerLeft == true) then
set udg_p_KickerLeft = false
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00, GetPlayerName(udg_Kick_Player) + " was not kicked." )
else
if ( IsPlayerInForce(udg_Kick_Player, udg_Players) == true ) then
call SendBotDataOnline(GENERAL_INFO_DATA, "\"Kicked\"," + I2S(nr))
set udg_Kicked[nr] = true
set udg_Leaver = udg_Kick_Player
call TriggerExecute( gg_trg_Player_Remove )
call DisplayTextToForce( udg_Players, ( GetPlayerName(udg_Kick_Player) + " was kicked!" ) )
call CustomVictoryBJ( udg_Kick_Player, false, true )
call PlaySoundBJ( gg_snd_Kick )
if ( CountPlayersInForceBJ(udg_Players_Team[udg_Player_Team[nr]]) == 0 ) then
set udg_Team_Winning = ( 3 - udg_Player_Team[nr] )
endif
endif
endif
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00, "Votes: " + I2S(udg_Kick_Count[1]) + ( " Needed: " + I2S(udg_Kick_Votes_Needed) ) )
call DestroyLeaderboard( udg_KickBoard )
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if (GetLocalPlayer() == GetPlayer(i)) then
call MultiboardDisplay( udg_Killboard[i-1], true )
call MultiboardMinimize( udg_Killboard[i-1], IsMultiboardMinimized(udg_Killboard[i-1]) )
endif
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_Kick_End takes nothing returns nothing
set gg_trg_Kick_End = CreateTrigger( )
call TriggerAddAction( gg_trg_Kick_End, function Trig_Kick_End_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
globals
boolean array GiveUp_HasVoted[10]
boolean array GiveUp_VoteReady[10]
integer array GiveUp_Count[2]
endglobals
function Trig_CountHumanPlayers takes nothing returns boolean
return ( IsPlayerInForce(GetFilterPlayer(), udg_Players_Team[udg_Player_Team[GetPlayerNr(GetTriggerPlayer())]]) == true ) and ( IsAI(GetPlayerNr(GetFilterPlayer())) == false )
endfunction
function Trig_GiveUp_Vote_Actions takes nothing returns nothing
local integer i = 1
local integer pId = GetPlayerNr(GetTriggerPlayer())
local integer team = udg_Player_Team[pId]
local integer teamCount = CountPlayersInForceBJ(GetPlayersMatchingSafe(Condition(function Trig_CountHumanPlayers)))
local boolean giveup = GetEventPlayerChatString() == "-giveup"
local boolean revoke = GetEventPlayerChatString() == "-giveup revoke"
local string s = ""
if (GiveUp_HasVoted[pId]) and giveup then
// only for info, not actually voting
if GetLocalPlayer() == GetTriggerPlayer() then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312Vote count of your team:|r [" + I2S(GiveUp_Count[team]) + "/" + I2S(teamCount) + "]")
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312If you want to withdraw your giveup vote, enter \"|r-giveup revoke|cfffed312\"|r")
endif
elseif ((giveup == false) and (revoke == false)) then
// ignore other messages - do nothing
call DebugMsg("Message: " + GetEventPlayerChatString())
elseif (GiveUp_VoteReady[pId]) then
if giveup then
set GiveUp_VoteReady[pId] = false
set GiveUp_HasVoted[pId] = true
set GiveUp_Count[team] = GiveUp_Count[team] + 1
set s = GetPlayerName(GetTriggerPlayer()) + " has voted to give up |cfffed312[" + I2S(GiveUp_Count[team]) + "/" + I2S(teamCount) + "]|r"
elseif revoke then
if GiveUp_HasVoted[pId] then
set GiveUp_VoteReady[pId] = false
set GiveUp_HasVoted[pId] = false
set GiveUp_Count[team] = GiveUp_Count[team] - 1
set s = GetPlayerName(GetTriggerPlayer()) + " has withdrawn his giveup vote |cfffed312[" + I2S(GiveUp_Count[team]) + "/" + I2S(teamCount) + "]|r"
if (teamCount == GiveUp_Count[team]+1) and (udg_Player_Team[GetPlayerNr(GetLocalPlayer())] == team) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 10.00, GetPlayerName(GetPlayer(10+team)) + " aborted the give up" )
endif
endif
endif
if ((s != "") and (udg_Player_Team[GetPlayerNr(GetLocalPlayer())] == team)) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00, s )
endif
if ( teamCount == GiveUp_Count[team] ) then
set s = GetPlayerName(GetPlayer(10+team)) + " voted to give up. You now have 10s to change your votes with \"-giveup revoke\", otherwise the game will end."
if (udg_Player_Team[GetPlayerNr(GetLocalPlayer())] == team) then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 10.00, s )
endif
call GameTimeWait(10)
if ( teamCount == GiveUp_Count[team] ) then
set udg_Team_Winning = 3 - team
set udg_GaveUp[team] = true
call TriggerExecute( gg_trg_GiveUp_End )
endif
endif
call GameTimeWait(60)
set GiveUp_VoteReady[pId] = true
else
if GetLocalPlayer() == GetTriggerPlayer() then
call DisplayTextToPlayer(GetLocalPlayer(),0,0, "|cfffed312You can only change your vote once every minute|r")
endif
endif
endfunction
//===========================================================================
function InitTrig_GiveUp_Vote takes nothing returns nothing
local integer i = 1
set GiveUp_Count[1] = 0
set GiveUp_Count[2] = 0
loop
exitwhen i > GetMaxHumanPlayers()
set GiveUp_HasVoted[i] = false
set GiveUp_VoteReady[i] = true
set i = i + 1
endloop
set gg_trg_GiveUp_Vote = CreateTrigger( )
call DisableTrigger( gg_trg_GiveUp_Vote )
call TriggerRegisterChatCommandEvent(gg_trg_GiveUp_Vote,"giveup")
//call TriggerRegisterChatCommandEvent(gg_trg_GiveUp_Vote,"giveup revoke")
//call TriggerRegisterChatCommandEvent(gg_trg_GiveUp_Vote,"never gonna give you up")
call TriggerAddAction( gg_trg_GiveUp_Vote, function Trig_GiveUp_Vote_Actions )
endfunction
//TESH.scrollpos=96
//TESH.alwaysfold=0
globals
// Used to store the desired target of a playerswap for each player
integer array udg_Player_Swap
endglobals
function Trig_Playerswap_SwapItemOwner takes nothing returns nothing
local item it = GetEnumItem()
if GetItemPlayer( it ) == GetPlayer(bj_forLoopAIndex) then
call SetItemPlayer( it, GetPlayer(bj_forLoopBIndex), false)
elseif GetItemPlayer( it ) == GetPlayer(bj_forLoopBIndex) then
call SetItemPlayer( it, GetPlayer(bj_forLoopAIndex), false)
endif
set it = null
endfunction
function Trig_Playerswap_Actions takes nothing returns nothing
local player Initiator = GetTriggerPlayer()
local integer PlayId = GetPlayerNr(Initiator)
local integer TargId
local integer i
local integer j
local player Acceptor
local real r
local timer t
local timerdialog td
local group PlayUnits
local group TargUnits
local unit U
if LeagueConfirmed then
if Initiator == GetLocalPlayer() then
call DisplayTextToPlayer(Initiator, 0, 0, "|Cfffed312This command is not allowed in league mode.|r" )
endif
return
endif
set Acceptor = GetPlayerFromString(GetEventPlayerChatParams())
if Acceptor==null then
if Initiator == GetLocalPlayer() then
call DisplayTextToPlayer(Initiator, 0, 0, "|Cfffed312You have to specify a target player.|r" )
endif
set udg_Player_Swap[PlayId] = 0
return
endif
set TargId = GetPlayerNr(Acceptor)
if PlayId==TargId then
if Initiator == GetLocalPlayer() then
call DisplayTextToPlayer( GetLocalPlayer( ), 0, 0, "|Cfffed312You cannot swap your tank with yourself.|r" )
endif
return
endif
if udg_Player_Team[TargId] != udg_Player_Team[PlayId] then
if Initiator == GetLocalPlayer() then
call DisplayTextToPlayer( GetLocalPlayer( ), 0, 0, "|Cfffed312You cannot swap your tank with an enemy.|r" )
endif
return
endif
if udg_Afk[TargId] then
if Initiator == GetLocalPlayer() then
call DisplayTextToPlayer( GetLocalPlayer( ), 0, 0, "|Cfffed312You cannot swap your tank with a player who is afk.|r" )
endif
return
endif
if (udg_Player_Swap[TargId] == PlayId) or (IsAI(TargId) and not udg_Afk[TargId]) then
if Initiator == GetLocalPlayer() or GetPlayer(TargId) == GetLocalPlayer() then
call DisplayTextToPlayer( GetLocalPlayer( ), 0, 0, "|Cfffed312You swapped your tank, weapons and upgrades.|r" )
endif
set udg_Player_Swap[TargId] = 0
set udg_Player_Swap[PlayId] = 0
set i = GetPlayerState(Initiator, PLAYER_STATE_RESOURCE_GOLD)
call SetPlayerState(Initiator, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Acceptor, PLAYER_STATE_RESOURCE_GOLD))
call SetPlayerState(Acceptor, PLAYER_STATE_RESOURCE_GOLD, i)
set i = GetPlayerState( Initiator, PLAYER_STATE_RESOURCE_LUMBER)
call SetPlayerState(Initiator, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(Acceptor, PLAYER_STATE_RESOURCE_LUMBER))
call SetPlayerState(Acceptor, PLAYER_STATE_RESOURCE_LUMBER, i)
set PlayUnits = GetUnitsOfPlayerAllSafe(Initiator)
set TargUnits = GetUnitsOfPlayerAllSafe(Acceptor)
set U = FirstOfGroup( PlayUnits )
loop
exitwhen U == null
call SetUnitOwner( U, Acceptor, true )
set i = 0
loop
exitwhen i > 5
call SetItemPlayer( UnitItemInSlot(U, i), Acceptor, false)
set i = i + 1
endloop
call GroupRemoveUnit( PlayUnits, U )
set U = FirstOfGroup( PlayUnits )
endloop
set U = FirstOfGroup( TargUnits )
loop
exitwhen U == null
call SetUnitOwner( U, Initiator, true )
set i = 0
loop
exitwhen i > 5
call SetItemPlayer( UnitItemInSlot(U, i), Initiator, false)
set i = i + 1
endloop
call GroupRemoveUnit( TargUnits, U )
set U = FirstOfGroup( TargUnits )
endloop
call ReleaseGroup( PlayUnits )
call ReleaseGroup( TargUnits )
set PlayUnits = null
set TargUnits = null
set r = udg_Income[PlayId]
set udg_Income[PlayId] = udg_Income[TargId]
set udg_Income[TargId] = r
set U = udg_Tank[PlayId]
set udg_Tank[PlayId] = udg_Tank[TargId]
set udg_Tank[TargId] = U
set i = GetPlayerTechCount(Initiator, 'R000', true)
call SetPlayerTechResearched(Initiator, 'R000', GetPlayerTechCount(Acceptor, 'R000', true))
call SetPlayerTechResearched(Acceptor, 'R000', i)
set t = udg_Tank_Timer[PlayId]
set udg_Tank_Timer[PlayId] = udg_Tank_Timer[TargId]
set udg_Tank_Timer[TargId] = t
set t = null
set td = udg_Tank_TimerWindow[PlayId]
set udg_Tank_TimerWindow[PlayId] = udg_Tank_TimerWindow[TargId]
set udg_Tank_TimerWindow[TargId] = td
set td = null
set i = 1
loop
exitwhen i > 6
set j = udg_Item_CreateForHero[(PlayId-1)*6+i]
set udg_Item_CreateForHero[(PlayId-1)*6+i] = udg_Item_CreateForHero[(TargId-1)*6+i]
set udg_Item_CreateForHero[(TargId-1)*6+i] = j
set i = i + 1
endloop
call SetTankIcon(PlayId)
call SetTankIcon(TargId)
//Mana Upgrade
set i = ManaUpgrade[PlayId]
set ManaUpgrade[PlayId] = ManaUpgrade[TargId]
set ManaUpgrade[TargId] = i
call ApplyManaUpgrade(PlayId)
call ApplyManaUpgrade(TargId)
//Architect related variables
set U = PWeapons.Holder[PlayId]
set PWeapons.Holder[PlayId] = PWeapons.Holder[TargId]
set PWeapons.Holder[TargId] = U
set U = Pacifista[PlayId]
set Pacifista[PlayId] = Pacifista[TargId]
set Pacifista[TargId] = U
set bj_forLoopAIndex = PlayId
set bj_forLoopBIndex = TargId
call EnumItemsInRect( udg_Playable_Map, FILTER_NULL, function Trig_Playerswap_SwapItemOwner )
else
if Initiator == GetLocalPlayer() then
call DisplayTextToPlayer( GetLocalPlayer( ), 0, 0, "|Cfffed312Player swapping requested. Wait for response.|r" )
endif
if Acceptor == GetLocalPlayer() then
call DisplayTextToPlayer( GetLocalPlayer( ), 0, 0, udg_Color[PlayId] + GetPlayerName(Initiator) + "|Cfffed312 wants to swap with you. Type \"|r-playerswap "+I2S(PlayId)+"|Cfffed312\".|r" )
endif
set udg_Player_Swap[PlayId] = TargId
call GameTimeWait( 60 )
if udg_Player_Swap[PlayId] == TargId then
set udg_Player_Swap[PlayId] = 0
endif
endif
set U = null
endfunction
//===========================================================================
function InitTrig_Playerswap takes nothing returns nothing
set gg_trg_Playerswap = CreateTrigger( )
call TriggerRegisterChatCommandEvent(gg_trg_Playerswap,"playerswap")
call TriggerAddAction( gg_trg_Playerswap, function Trig_Playerswap_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Afk_Return_Actions takes nothing returns nothing
call PlayerAfkReturn(GetTriggerPlayer())
set udg_ActionsLast[GetPlayerNr(GetTriggerPlayer())] = udg_Time_Value
endfunction
//===========================================================================
function InitTrig_Afk_Return takes nothing returns nothing
set gg_trg_Afk_Return = CreateTrigger( )
call TriggerRegisterDialogEventBJ( gg_trg_Afk_Return, udg_Afk_Dialog )
call TriggerAddAction( gg_trg_Afk_Return, function Trig_Afk_Return_Actions )
endfunction
//TESH.scrollpos=48
//TESH.alwaysfold=0
library VeritasCode initializer Security requires ExcubitorCode
//************************************************************
//! Veritas Code (c) by Paladon 868
//************************************************************
// This library offers various commands and new Jass functions
//************************************************************
//! call ReleaseVeritasVersion()
// returns the DataName and current BT-Veritas version
//! call CodeVeritas(integer PlayerID, integer alpha StatusID, integer omega StatusID)
// returns the invoked Veritas Code
//! call VeritasContent(integer PlayerID, integer StatusID)
// returns the current value of a StatusID in a string
//************************************************************
globals
//! Important Variables
constant string DataName = "Gz-1Ln8"
constant string DLSName = "J7nO-2g"
//*************************************
constant integer StatAmount = 26
private constant integer PlayerAmount = 10
//*************************************
constant string PID = ":" //! Player Ident.Integer
constant string NID = "*" //! Name Ident.String
constant string SID = "+" //! Stat Ident.Integer
constant string VID = "," //! Veritas Ident.Integer
constant string EID = "/" //! End Ident.String
//*************************************
private string array VeritasAlpha
//*************************************
integer array VWinLoose[PlayerAmount]
integer array VKills[PlayerAmount]
integer array VMultikill[PlayerAmount]
integer array VDeaths[PlayerAmount]
integer array VBounty[PlayerAmount]
integer array VCKills[PlayerAmount]
integer array VBKills[PlayerAmount]
integer array VWorth[PlayerAmount]
integer array VLevel[PlayerAmount]
integer array VCPTele[PlayerAmount]
integer array VCPConq[PlayerAmount]
integer array VUnitsTrained[PlayerAmount]
integer array VTime[PlayerAmount]
integer array VAfkT[PlayerAmount]
integer array VAPM[PlayerAmount]
integer array VMKills[PlayerAmount]
integer array VSupport[PlayerAmount]
integer array VAssists[PlayerAmount]
integer array VBBuilt[PlayerAmount]
integer array VEarnedGold[PlayerAmount]
integer array VUpgrades[PlayerAmount]
integer array VDamage[PlayerAmount]
integer array VTimeDead[PlayerAmount]
integer array VResult[PlayerAmount]
integer array VMaxKillStreak[PlayerAmount]
integer array VMaxAssistStreak[PlayerAmount]
//! 1 => Win/Lose => x = 1/0
//! 2 => Kills => x
//! 3 => Höchster Multikill => x
//! 4 => Deaths => x
//! 5 => Gold durch Kills => x
//! 6 => Creep Kills => x
//! 7 => Tower Kills => x
//! 8 => Fahrzeugwert => x
//! 9 => Tanklevel => x = 1-25
//! 10 => CP Teleports => x
//! 11 => CPs eingenommen => x
//! 12 => Units trained => x
//! 13 => Spieldauer/Leavezeitpunkt => x in seconds
//! 14 => Time Afk => x in seconds
//! 15 => Actions Per Minute => x
//! 16 => Counter of Multikills => x
//! 17 => Support points => x
//! 18 => Assists => x
//! 19 => Built Buildings => x
//! 20 => Earned Gold => x (excluding Force gold and income)
//! 21 => Bought Creep Upgrades => x
//! 22 => Damage Dealt => x
//! 23 => Time Dead => x in seconds
//! 24 => Game Result => x = Finished normal (0), Gave Up (1), Left (2), Kicked (3)
//! 25 => Highest kill streak => x
//! 26 => Highest assist streak => x
endglobals
//**********************************************************************
function ReleaseVeritasVersion takes nothing returns string
return DataName+Version
endfunction
function VeritasContent takes integer p, integer i returns string
local string s = "NoVeritas"
if i == 0 then
set s = "ERROR - Cheating ID detected! Excubitor Code activated!"
call SyncExcubitor()
elseif i == 1 then
set s = I2S(VWinLoose[p])
elseif i == 2 then
set s = I2S(VKills[p])
elseif i == 3 then
set s = I2S(VMultikill[p])
elseif i == 4 then
set s = I2S(VDeaths[p])
elseif i == 5 then
set s = I2S(VBounty[p])
elseif i == 6 then
set s = I2S(VCKills[p])
elseif i == 7 then
set s = I2S(VBKills[p])
elseif i == 8 then
set s = I2S(VWorth[p])
elseif i == 9 then
set s = I2S(VLevel[p])
elseif i == 10 then
set s = I2S(VCPTele[p])
elseif i == 11 then
set s = I2S(VCPConq[p])
elseif i == 12 then
set s = I2S(VUnitsTrained[p])
elseif i == 13 then
set s = I2S(VTime[p])
elseif i == 14 then
set s = I2S(VAfkT[p])
elseif i == 15 then
set s = I2S(VAPM[p])
elseif i == 16 then
set s = I2S(VMKills[p])
elseif i == 17 then
set s = I2S(VSupport[p])
elseif i == 18 then
set s = I2S(VAssists[p])
elseif i == 19 then
set s = I2S(VBBuilt[p])
elseif i == 20 then
set s = I2S(VEarnedGold[p])
elseif i == 21 then
set s = I2S(VUpgrades[p])
elseif i == 22 then
set s = I2S(VDamage[p])
elseif i == 23 then
set s = I2S(VTimeDead[p])
elseif i == 24 then
set s = I2S(VResult[p])
elseif i == 25 then
set s = I2S(VMaxKillStreak[p])
elseif i == 26 then
set s = I2S(VMaxAssistStreak[p])
endif
if s == "NoVeritas" then
set s = "ERROR - Veritas content not found! Excubitor Code activated!"
call SyncExcubitor()
endif
return s
endfunction
function CodeVeritas takes integer pid, integer v, integer b returns string
local string s = I2S(pid)
local integer i = v
loop
exitwhen i > b
set s = s + VID+VeritasContent(pid,i)
set i = i + 1
endloop
set s = s
return s
endfunction
private function Security takes nothing returns nothing
local integer i = 1
loop
exitwhen i > StatAmount
set VeritasAlpha[i] = I2S(i)
set i = i + 1
endloop
endfunction
endlibrary
//TESH.scrollpos=8
//TESH.alwaysfold=0
library ExcubitorCode
//************************************************************
//! Excubitor Code (c) by Paladon 868
//! Security
globals
integer ExcubitorLevel = 10 // Max Level is 10
endglobals
//************************************************************
function SyncExcubitor takes nothing returns nothing
if ExcubitorLevel >= 10 then
set ExcubitorLevel = 10
else
set ExcubitorLevel = ExcubitorLevel + 1
endif
endfunction
function IsPlayer takes integer i returns boolean
return GetPlayerController(Player(i)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING
endfunction
function Excubitor takes nothing returns boolean
local integer i = 0
local integer e = 0
local integer p = 0
local integer t = 100
local boolean array ValuePlayer
loop
exitwhen i >= 12
set ValuePlayer[i] = false
if IsPlayer(i) then
set p = p + 1
endif
set i = i + 1
endloop
if ExcubitorLevel > p then
set ExcubitorLevel = p
endif
set i = 0
loop
exitwhen i >= 12
if IsPlayer(i) then
if e < ExcubitorLevel then
loop
set t = GetRandomInt(0,11)
if IsPlayer(t) and ValuePlayer[t] == false then
set ValuePlayer[t] = true
set t = 100
endif
exitwhen t == 100
endloop
set e = e + 1
endif
endif
set i = i + 1
endloop
return ValuePlayer[GetPlayerId(GetLocalPlayer())]
endfunction
endlibrary
//TESH.scrollpos=15
//TESH.alwaysfold=0
library BTBots initializer Init requires VeritasCode, ExcubitorCode
//************************************************************************
//! This library provides the data emitter for stat based league tracking.
//************************************************************************
//! call SendBotData(Excubitor(Veritas))
globals
private constant string KeyString = "msg:"
//! Debug Variables
private constant boolean MsgDebug = false
//! Other Variables
private gamecache BotData = null
private timer BotTimer = CreateTimer()
private integer counter = -1
endglobals
function GetGameTimeInSeconds takes nothing returns integer
return R2I(TimerGetElapsed(BotTimer))
endfunction
private function CounterCheat takes integer i returns boolean
return counter != i
endfunction
private struct Emitter
readonly string msg
readonly string key
public static method create takes integer msg_number, string msg returns Emitter
local Emitter this = Emitter.allocate()
set .msg = msg
if CounterCheat(msg_number) then
set .msg = "0"
endif
if MsgDebug then
call BJDebugMsg(.msg)
endif
set .key = I2S(msg_number)
return this
endmethod
public method SendBot takes nothing returns nothing
call StoreInteger(BotData, KeyString+.key, .msg, GetGameTimeInSeconds())
call SyncStoredInteger(BotData, KeyString+.key, .msg)
endmethod
endstruct
function SendBotData takes string s returns nothing
local Emitter Data
if LeagueConfirmed then
set counter = counter + 1
set Data = Emitter.create(counter,s)
if Excubitor() then
call Data.SendBot()
endif
endif
endfunction
private function Init takes nothing returns nothing
call TimerStart(BotTimer,9999999,false,null)
call FlushGameCache(InitGameCache(DataName))
set BotData = InitGameCache(DataName)
endfunction
endlibrary
//TESH.scrollpos=42
//TESH.alwaysfold=0
library BTDLS initializer Init requires VeritasCode, ExcubitorCode, BTBots
//************************************************************************
//! This library provides the data emitter for stat based league tracking.
//************************************************************************
//! call SendBotData(Excubitor(Veritas))
globals
private constant string KeyString = "msg:"
//! Debug Variables
private constant boolean MsgDebug = false
//! Other Variables
private gamecache BotData2 = null
private timer BotTimer2 = CreateTimer()
private integer counter2 = -1
private timer batch_timer = CreateTimer()
private string batch = ""
private string backup_batch = ""
private constant integer MAX_BATCH_LENGTH = 500
constant integer TANK_INFO_DATA = 1
constant integer DEBUG_INFO_DATA = 2
constant integer GENERAL_INFO_DATA = 3
endglobals
private struct Emitter
readonly string msg
readonly string key
public static method create takes integer msg_number, string msg returns Emitter
local Emitter this = Emitter.allocate()
set .msg = msg
set .key = I2S(msg_number)
return this
endmethod
public method SendBot takes nothing returns nothing
call StoreInteger(BotData2, KeyString+.key, .msg, GetGameTimeInSeconds())
call SyncStoredInteger(BotData2, KeyString+.key, .msg)
endmethod
endstruct
// In the end, the message should look like this:
// [timestamp,info-id,[put,random,"info",here,"?"]]
function formatMessage takes string message, integer info_id returns string
local string final_message = "[" + I2S(GetGameTimeInSeconds()) + "," + I2S(info_id) + ",["
set final_message = final_message + message + "]]"
return final_message
endfunction
// Sends the data immidiately to the bot
function SendBotDataOnline takes integer info_id, string s returns nothing
local Emitter Data
local string msg = formatMessage(s, info_id)
set counter2 = counter2 + 1
set Data = Emitter.create(counter2,msg)
if Excubitor() then
call Data.SendBot()
endif
endfunction
// Collects the data and only sends them in batches
function SendBotDataBatch takes integer info_id, string s returns nothing
local string msg = formatMessage(s, info_id)
if (StringLength(batch) + StringLength(msg) + 3) > MAX_BATCH_LENGTH then
if (StringLength(backup_batch) + StringLength(msg) + 3) > MAX_BATCH_LENGTH then
// too much data to send -> discard
else
set backup_batch = backup_batch + ">,<" + msg
endif
else
set batch = batch + ">,<" + msg
endif
endfunction
function BatchSending takes nothing returns nothing
local Emitter Data
if (batch != "") then
set counter2 = counter2 + 1
set Data = Emitter.create(counter2,batch)
if Excubitor() then
call Data.SendBot()
endif
set batch = backup_batch
set backup_batch = ""
endif
endfunction
private function Init takes nothing returns nothing
call TimerStart(BotTimer2,9999999,false,null)
call FlushGameCache(InitGameCache(DLSName))
set BotData2 = InitGameCache(DLSName)
call TimerStart(batch_timer, 5, true, function BatchSending)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library EndgameStats initializer Init requires ExcubitorCode,VeritasCode,BTBots,PvJass,Initilization,MapAttachedSettings
globals
private constant real DataUpdate = 5.00
trigger SyncRealData = CreateTrigger()
integer SyncRealID = 0
endglobals
function GetFinishedState takes integer Id returns integer
local integer team = udg_Player_Team[Id]
if udg_Kicked[Id] then
return 3
elseif ((udg_PlayerInStart[Id] == true) and (udg_PlayerIn[Id] == false)) then
return 2
elseif udg_GaveUp[team] then
return 1
endif
return 0
endfunction
function SendLeagueInit takes nothing returns nothing
call SendBotData(Version)
endfunction
function EndgameLeague takes nothing returns nothing
local integer i = 0
if LeagueConfirmed then
loop
exitwhen i > 9
call SendBotData(CodeVeritas(i,1,StatAmount) + "],[" + CodeVeritas(i+1,1,StatAmount))
set i = i + 2
endloop
endif
endfunction
function LeagueVars takes nothing returns nothing
local integer i = 0
if LeagueConfirmed then
loop
exitwhen i >= 10
if IsPlayer(i) then
if udg_Tank[i+1] == null or TankDead[i] then
//! optional debug
else
set VWorth[i] = GetBounty(udg_Tank[i+1], false)
set VLevel[i] = GetHeroLevel(udg_Tank[i+1])
endif
set VKills[i] = udg_Kills[i+1]
set VDeaths[i] = udg_Deaths[i+1]
set VBounty[i] = TankBounty[i+1]
set VCKills[i] = udg_Stats_CreepKills[i+1]
set VBKills[i] = BuildingsKilled[i]
set VCPConq[i] = udg_Stats_CPs[i+1]
set VAPM[i] = R2I(60*udg_Actions[i+1]/TimerGetElapsed(udg_GameTime))
set VUnitsTrained[i] = udg_Stats_CreepBuy[i+1]
set VCPTele[i] = CPTeles[i]
set VTime[i] = R2I(TimerGetElapsed(PlayTimer[i]))
set VAfkT[i] = R2I(udg_AFKTime[i+1])
set VMultikill[i] = Multikill[i]
set VMKills[i] = LeagueMKCounter[i]
set VSupport[i] = R2I(udg_Support[i+1])
set VAssists[i] = udg_Assists[i+1]
set VBBuilt[i] = udg_Stats_Buildings[i+1]
set VEarnedGold[i] = R2I(udg_Profit_Creeps[i+1] + udg_Profit_Tanks[i+1] + udg_Stats_Trader[i+1])
set VUpgrades[i] = udg_Stats_Upgrades[i+1]
set VDamage[i] = R2I(udg_Damage_Dealt[i+1])
set VTimeDead[i] = R2I(udg_Time_Dead[i+1])
set VResult[i] = GetFinishedState(i+1)
set VMaxKillStreak[i] = udg_MaxKillStreak[i+1]
set VMaxAssistStreak[i] = udg_MaxAssistStreak[i+1]
endif
set i = i + 1
endloop
endif
endfunction
function StorePlayerVars takes integer i returns nothing
local real r = TimerGetElapsed(udg_GameTime)
if LeagueConfirmed then
set VKills[i] = udg_Kills[i+1]
set VDeaths[i] = udg_Deaths[i+1]
set VBounty[i] = TankBounty[i+1]
set VCKills[i] = udg_Stats_CreepKills[i+1]
set VBKills[i] = BuildingsKilled[i]
set VCPConq[i] = udg_Stats_CPs[i+1]
if udg_Tank[i+1] == null or TankDead[i] then
//! optional debug
else
set VWorth[i] = GetBounty(udg_Tank[i+1], false)
set VLevel[i] = GetHeroLevel(udg_Tank[i+1])
endif
if r > 0. then
set VAPM[i] = R2I(60*udg_Actions[i+1]/r)
else
set VAPM[i] = 0
endif
set VUnitsTrained[i] = udg_Stats_CreepBuy[i+1]
set VCPTele[i] = CPTeles[i]
set VTime[i] = R2I(TimerGetElapsed(PlayTimer[i]))
set VAfkT[i] = R2I(udg_AFKTime[i])
set VMultikill[i] = Multikill[i]
set VMKills[i] = LeagueMKCounter[i]
set VSupport[i] = R2I(udg_Support[i+1])
set VAssists[i] = udg_Assists[i+1]
set VBBuilt[i] = udg_Stats_Buildings[i+1]
set VEarnedGold[i] = R2I(udg_Profit_Creeps[i+1] + udg_Profit_Tanks[i+1] + udg_Stats_Trader[i+1])
set VUpgrades[i] = udg_Stats_Upgrades[i+1]
set VDamage[i] = R2I(udg_Damage_Dealt[i+1])
set VTimeDead[i] = R2I(udg_Time_Dead[i+1])
set VResult[i] = GetFinishedState(i+1)
set VMaxKillStreak[i] = udg_MaxKillStreak[i+1]
set VMaxAssistStreak[i] = udg_MaxAssistStreak[i+1]
endif
endfunction
function LeagueWin takes integer win returns nothing
local integer i = 0
if win == 2 then
loop
exitwhen i >= 5
set VWinLoose[i] = 0
set i = i + 1
endloop
loop
exitwhen i >= 10
set VWinLoose[i] = 1
set i = i + 1
endloop
elseif win == 1 then
loop
exitwhen i >= 5
set VWinLoose[i] = 1
set i = i + 1
endloop
loop
exitwhen i >= 10
set VWinLoose[i] = 0
set i = i + 1
endloop
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(t,DataUpdate*60.)
call TriggerAddAction(t, function LeagueVars)
call TimerStart(NewTimer(),0.01,false, function SendLeagueInit )
endfunction
endlibrary
//TESH.scrollpos=1
//TESH.alwaysfold=0
function Trig_LeagueInit_Conditions takes nothing returns boolean
if ( not ( GetPlayerName(GetTriggerPlayer()) == "Paladon" ) ) then
return false
endif
return true
endfunction
function Trig_LeagueInit_Actions takes nothing returns nothing
set LeagueConfirmed = true
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00," ")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00,LeagueWelcome1)
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00,LeagueWelcome2)
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00," ")
call SendLeagueInit()
endfunction
//===========================================================================
function InitTrig_LeagueInit takes nothing returns nothing
local integer i = 0
set gg_trg_LeagueInit = CreateTrigger( )
loop
call TriggerRegisterPlayerChatEvent( gg_trg_LeagueInit, Player(i), "league.init", true )
set i = i + 1
exitwhen i >= 10
endloop
call TriggerAddCondition( gg_trg_LeagueInit, Condition( function Trig_LeagueInit_Conditions ) )
call TriggerAddAction( gg_trg_LeagueInit, function Trig_LeagueInit_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_LeagueUpdate_Conditions takes nothing returns boolean
if ( not ( GetPlayerName(GetTriggerPlayer()) == "Paladon" ) ) then
return false
endif
return true
endfunction
function Trig_LeagueUpdate_Actions takes nothing returns nothing
call LeagueVars()
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00," ")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00,"League data successfully updated.")
endfunction
//===========================================================================
function InitTrig_LeagueUpdate takes nothing returns nothing
local integer i = 0
set gg_trg_LeagueUpdate = CreateTrigger( )
loop
call TriggerRegisterPlayerChatEvent( gg_trg_LeagueUpdate, Player(i), "league.update", true )
set i = i + 1
exitwhen i >= 10
endloop
call TriggerAddCondition( gg_trg_LeagueUpdate, Condition( function Trig_LeagueUpdate_Conditions ) )
call TriggerAddAction( gg_trg_LeagueUpdate, function Trig_LeagueUpdate_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_LeagueSend_Conditions takes nothing returns boolean
if ( not ( GetPlayerName(GetTriggerPlayer()) == "Paladon" ) ) then
return false
endif
return true
endfunction
function Trig_LeagueSend_Actions takes nothing returns nothing
call EndgameLeague()
endfunction
//===========================================================================
function InitTrig_LeagueSend takes nothing returns nothing
local integer i = 0
set gg_trg_LeagueSend = CreateTrigger( )
loop
call TriggerRegisterPlayerChatEvent( gg_trg_LeagueSend, Player(i), "league.sendall", true )
set i = i + 1
exitwhen i >= 10
endloop
call TriggerAddCondition( gg_trg_LeagueSend, Condition( function Trig_LeagueSend_Conditions ) )
call TriggerAddAction( gg_trg_LeagueSend, function Trig_LeagueSend_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_LeagueDestroy_Conditions takes nothing returns boolean
if ( not ( GetPlayerName(GetTriggerPlayer()) == "Paladon" ) ) then
return false
endif
return true
endfunction
function Trig_LeagueDestroy_Actions takes nothing returns nothing
set LeagueConfirmed = false
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00," ")
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 20.00,LeagueWelcome3)
endfunction
//===========================================================================
function InitTrig_LeagueDestroy takes nothing returns nothing
local integer i = 0
set gg_trg_LeagueDestroy = CreateTrigger( )
loop
call TriggerRegisterPlayerChatEvent( gg_trg_LeagueDestroy, Player(i), "league.destroy", true )
set i = i + 1
exitwhen i >= 10
endloop
call TriggerAddCondition( gg_trg_LeagueDestroy, Condition( function Trig_LeagueDestroy_Conditions ) )
call TriggerAddAction( gg_trg_LeagueDestroy, function Trig_LeagueDestroy_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Add_Towers_to_Ruin_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'h00Q'
endfunction
//Reason for this stupid trigger:
//The Tower Ruins sell units, which are recognized in the Build Tower trigger, which replaces the Ruin with the new building
//These units have cooldowns, but it happens that a player buys those, but is not able to build a tower at that position (enemy base etc)
//So the unit goes into cooldown and prevents the other team from building there
//To prevent this, the sold unit gets removed from the stock of the Ruin and readded immediatly, which gets rid of the cooldown
//But apperantly, it's only possible to remove units from the stock, which have been added through triggers
//Because of how this trigger works, preplaced Tower Ruins (through Object Editor) won't get those units and won't have anything to sell
function Trig_Add_Towers_to_Ruin_Actions takes nothing returns nothing
local unit Ruin = GetTriggerUnit()
call RefreshRuinSupply(Ruin)
set Ruin = null
endfunction
//===========================================================================
function InitTrig_Add_Towers_to_Ruin takes nothing returns nothing
set gg_trg_Add_Towers_to_Ruin = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Add_Towers_to_Ruin, GetPlayableMapRect() )
call TriggerAddCondition( gg_trg_Add_Towers_to_Ruin, Condition( function Trig_Add_Towers_to_Ruin_Conditions ) )
call TriggerAddAction( gg_trg_Add_Towers_to_Ruin, function Trig_Add_Towers_to_Ruin_Actions )
endfunction
//TESH.scrollpos=7
//TESH.alwaysfold=0
function Trig_Build_Only_3_Factories_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A06U' or GetSpellAbilityId() == 'A03C'
endfunction
function ContainsAnAlliedFactory takes nothing returns boolean
return (GetUnitTypeId(GetFilterUnit()) == 'h002' or GetUnitTypeId(GetFilterUnit()) == 'h015' or GetUnitTypeId(GetFilterUnit()) == 'h01Z') and IsPlayerAlly(GetOwningPlayer(GetFilterUnit()), GetOwningPlayer(GetTriggerUnit()))
endfunction
function ContainsAnAlliedPlayerFactory takes nothing returns boolean
return ContainsAnAlliedFactory() and GetPlayerNr(GetOwningPlayer(GetFilterUnit())) <= GetMaxHumanPlayers()
endfunction
function IsInvalidTarget takes location P returns boolean
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))] == 1 then
if RectContainsLoc(gg_rct_Team_1_Base_Complete, P) then
return CountUnitsInGroup(GetUnitsInRectMatchingSafe(gg_rct_Team_1_Base_Complete, Condition(function ContainsAnAlliedFactory))) >= 6
endif
elseif RectContainsLoc(gg_rct_Team_2_Base_Complete, P) then
return CountUnitsInGroup(GetUnitsInRectMatchingSafe(gg_rct_Team_2_Base_Complete, Condition(function ContainsAnAlliedFactory))) >= 6
endif
return false
endfunction
function Trig_Build_Only_3_Factories_Actions takes nothing returns nothing
local unit Tank = GetTriggerUnit()
local location P = GetSpellTargetLoc()
local player Owner = GetOwningPlayer(Tank)
if IsInvalidTarget( P ) then
call IssueImmediateOrder( Tank, "stop" )
call DisplayTextToPlayer(Owner, 0, 0, "|cfffed312There are already 6 factories in your base.|r" )
elseif CountUnitsInGroup(GetUnitsInRectMatchingSafe(udg_Playable_Map, Condition(function ContainsAnAlliedPlayerFactory))) >= 3 then
call IssueImmediateOrder( Tank, "stop" )
call DisplayTextToPlayer(Owner, 0, 0, "|cfffed312Your team already has 3 additional Factories.|r" )
else
//build the factory - the stats are already updated in the Building Established trigger
//set udg_Stats_Buildings[GetPlayerNr(Owner)] = udg_Stats_Buildings[GetPlayerNr(Owner)] + 1
endif
call RemoveLocation( P )
set P = null
set Tank = null
endfunction
//===========================================================================
function InitTrig_Build_Only_3_Factories takes nothing returns nothing
set gg_trg_Build_Only_3_Factories = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Build_Only_3_Factories, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Build_Only_3_Factories, Condition( function Trig_Build_Only_3_Factories_Conditions ) )
call TriggerAddAction( gg_trg_Build_Only_3_Factories, function Trig_Build_Only_3_Factories_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Building_Established_Conditions takes nothing returns boolean
//Don't count stats for Watch Towers
return (not IsWatchTower(GetConstructedStructure())) and (IsObelisk(GetConstructedStructure()) <= 0)
endfunction
function Trig_Building_Established_Actions takes nothing returns nothing
local unit builder = GetTriggerUnit()
local unit building = GetConstructedStructure()
local integer i = GetPlayerNr(GetOwningPlayer(builder))
local integer AttachmentId
local integer buildingId = GetUnitTypeId(building)
local integer tccNr = 0
set udg_Stats_Buildings[i] = udg_Stats_Buildings[i] + 1
if (buildingId == 'h01K') then
//save the mana of the Troop Command Center
if (udg_TCC_Mana[udg_TCC_Max*i] != 0) then
set tccNr = 0
else
set tccNr = 1
endif
call SetUnitState(building, UNIT_STATE_MANA, udg_TCC_Mana[udg_TCC_Max*i + tccNr])
set udg_TCC_Mana[udg_TCC_Max*i + tccNr] = 0
elseif (buildingId == 'h01Z') or (buildingId == 'h015') then
//Factory (item) and Spawn Factory
if (IsPlayerAlly(GetLocalPlayer(), GetPlayer(i))) then
call PingMinimap(GetUnitX(builder), GetUnitY(builder), 3)
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, udg_Color[i] + GetPlayerName(GetOwningPlayer(builder)) + "|r|cfffed312 has built a factory.|r" )
endif
call DebugMsg("Factory finished")
call Factory_EnableHealing(building, true)
call UnitAddType(building, UNIT_TYPE_TOWNHALL)
endif
set builder = null
set building = null
endfunction
//===========================================================================
function InitTrig_Building_Established takes nothing returns nothing
set gg_trg_Building_Established = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Building_Established, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH )
call TriggerAddCondition( gg_trg_Building_Established, Condition( function Trig_Building_Established_Conditions ) )
call TriggerAddAction( gg_trg_Building_Established, function Trig_Building_Established_Actions )
endfunction
//TESH.scrollpos=-1
//TESH.alwaysfold=0
function Trig_Building_Start_Conditions takes nothing returns boolean
//Don't count stats for Watch Towers
return (not IsWatchTower(GetConstructedStructure()))
endfunction
function Trig_Building_Start_Actions takes nothing returns nothing
local unit building = GetTriggerUnit()
local integer buildingId = GetUnitTypeId(building)
call DebugMsg("Start building (" + GetUnitName(building) + ")")
if (buildingId == 'h01Z') or (buildingId == 'h015') then
// When you start to build a factory, remove the ability to CPTP to it and its heal
// Don't remove those in the object editor, since an upgrade from one factory to the other won't trigger
// this and the 'Building Established' trigger, so these abilities wouldn't be added then
call Factory_EnableHealing(building, false)
call UnitRemoveType(building, UNIT_TYPE_TOWNHALL)
endif
set building = null
endfunction
//===========================================================================
function InitTrig_Building_Start takes nothing returns nothing
set gg_trg_Building_Start = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Building_Start, EVENT_PLAYER_UNIT_CONSTRUCT_START )
call TriggerAddCondition( gg_trg_Building_Start, Condition( function Trig_Building_Start_Conditions ) )
call TriggerAddAction( gg_trg_Building_Start, function Trig_Building_Start_Actions )
endfunction
//TESH.scrollpos=24
//TESH.alwaysfold=0
scope BuildTower initializer Init
globals
constant integer ROCKET_TOWER_ID = 'h000'
constant integer LASER_TOWER_ID = 'h001'
constant integer BARRICADE_ID = 'o000'
constant integer TELEPORT_BEACON_ID = 'o003'
constant integer CAMOUFLAGE_GENERATOR_ID = 'o005'
constant integer ROCKET_TOWER_SELL_ID = 'z009'
constant integer LASER_TOWER_SELL_ID = 'z00A'
constant integer BARRICADE_SELL_ID = 'z005'
constant integer TELEPORT_BEACON_SELL_ID = 'z026'
constant integer CAMOUFLAGE_GENERATOR_SELL_ID = 'z029'
private constant integer INVIS_ABILITY_ID = 'A0G0'
private constant integer INVIS_ABILITY_BUFF_ID = 'B036'
private constant real CLOAK_AREA = 650
private constant real DEACTIVATION_AREA = 900
private constant real CHECK_INTERVAL = 0.5
private constant real INVISIBILITY_DURATION = 1.32
private constant string CLOAK_MODEL = "war3mapImported\\BlackCloudOfFog.mdx"
endglobals
function Trig_Build_Tower_Conditions takes nothing returns boolean
local integer id = GetUnitTypeId(GetSoldUnit())
if (BARRICADE_SELL_ID == id) then
return true
elseif (ROCKET_TOWER_SELL_ID == id) then
return true
elseif (LASER_TOWER_SELL_ID == id) then
return true
elseif (TELEPORT_BEACON_SELL_ID == id) then
return true
elseif (CAMOUFLAGE_GENERATOR_SELL_ID == id) then
return true
endif
return false
// ToDo: find out why the following line returns true, when a Light Tank 'H009' has been bought. I doesn't make sense!
//return (BARRICADE_SELL_ID-id)*(ROCKET_TOWER_SELL_ID-id)*(LASER_TOWER_SELL_ID-id)*(TELEPORT_BEACON_SELL_ID-id)*(CAMOUFLAGE_GENERATOR_SELL_ID-id) == 0
endfunction
function Start_Camouflage_Generator_CheckTransparency takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit target = udg_AV_Unit1[LoopTimerId]
if (GetUnitAbilityLevel(target, INVIS_ABILITY_BUFF_ID) <= 0) then
call RefreshTransparency(target)
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
set target = null
endfunction
function Start_Camouflage_Generator_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit generator = udg_AV_Unit1[LoopTimerId]
local unit dummy = udg_AV_Unit2[LoopTimerId]
local unit temp
local group G
local timer t
local integer CheckTimerId
if (GetUnitState(generator, UNIT_STATE_LIFE) <= 0) then
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
call ReleaseDummy(dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(generator)
call GroupEnumUnitsInRange(G, GetUnitX(generator),GetUnitY(generator), DEACTIVATION_AREA, FILTER_ENEMY_TANK)
// Only cloak nearby allied tanks, when there are no enemies nearby
if (FirstOfGroup(G) == null) then
call GroupEnumUnitsInRange(G, GetUnitX(generator),GetUnitY(generator), CLOAK_AREA, FILTER_ALLY_TANK)
if (udg_AV_Effect1[LoopTimerId] == null) then
set udg_AV_Effect1[LoopTimerId] = AddSpecialEffectTarget(CLOAK_MODEL , dummy , "origin")
endif
loop
set temp = FirstOfGroup(G)
exitwhen (temp == null)
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(generator), INVIS_ABILITY_ID, 1, GetUnitX(temp), GetUnitY(temp), 0), "invisibility", temp)
if IsTransparentUnit(temp) then
set t = NewTimer()
set CheckTimerId = NewTimerIndex(t)
set udg_AV_Unit1[CheckTimerId] = temp
call TimerStart(t, INVISIBILITY_DURATION, false, function Start_Camouflage_Generator_CheckTransparency)
endif
call GroupRemoveUnit(G, temp)
endloop
else
if (udg_AV_Effect1[LoopTimerId] != null) then
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
set udg_AV_Effect1[LoopTimerId] = null
endif
endif
call ReleaseGroup(G)
endif
set G = null
set generator = null
set dummy = null
endfunction
function Start_Camouflage_Generator takes unit generator returns nothing
local timer t
local integer LoopTimerId
local unit dummy
local effect fx
set dummy = XE_NewDummyUnit(GetOwningPlayer(generator) , GetUnitX(generator) , GetUnitY(generator) , 270)
call SetUnitScale(dummy, 1.6, 1.6, 1.6)
call SetUnitFlyHeight(dummy, 25, 0)
set fx = AddSpecialEffectTarget(CLOAK_MODEL , dummy , "origin")
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = generator
set udg_AV_Unit2[LoopTimerId] = dummy
set udg_AV_Effect1[LoopTimerId] = fx
call TimerStart(t, CHECK_INTERVAL, true, function Start_Camouflage_Generator_Loop)
set dummy = null
endfunction
function IsRuinAtEnemyTradeMaster takes nothing returns boolean
if ( DistanceBetweenPoints(GetUnitLoc(GetTriggerUnit()), GetUnitLoc(udg_TradeMarket[1])) <= 768.00 and udg_Player_Team[GetPlayerNr(GetOwningPlayer(GetSoldUnit()))] != 1 ) then
return true
endif
if ( DistanceBetweenPoints(GetUnitLoc(GetTriggerUnit()), GetUnitLoc(udg_TradeMarket[2])) <= 768.00 and udg_Player_Team[GetPlayerNr(GetOwningPlayer(GetSoldUnit()))] != 2 ) then
return true
endif
return false
endfunction
function IsRuinInEnemyBase takes nothing returns boolean
if ( (RectContainsUnit(gg_rct_Team_1_Base_Complete, GetTriggerUnit()) == true) and (udg_Player_Team[GetPlayerNr(GetOwningPlayer(GetSoldUnit()))] != 1) ) then
return true
endif
if ( (RectContainsUnit(gg_rct_Team_2_Base_Complete, GetTriggerUnit()) == true) and (udg_Player_Team[GetPlayerNr(GetOwningPlayer(GetSoldUnit()))] != 2) ) then
return true
endif
return false
endfunction
function ReplaceRuin takes unit ruin, integer newTower returns unit
local unit tower
local integer AttachmentId
call ShowUnit(ruin, false)
set tower = CreateUnit(GetOwningPlayer(ruin), newTower, GetUnitX(ruin), GetUnitY(ruin), 270)
return tower
endfunction
function IsTowerNearby takes unit Ruin returns boolean
//The ruin belongs to a player, when he builds a tower on it
//So when the PlayerNr is less than the total number of players, a player owns the ruin
//and there should be a tower there already
if GetPlayerNr(GetOwningPlayer(Ruin)) > (10) then
return false
endif
return true
endfunction
function Trig_Build_Tower_Actions takes nothing returns nothing
local unit U = GetBuyingUnit()
local unit Tower = GetSoldUnit()
local unit Ruin = GetTriggerUnit()
local unit New
local player Owner = GetOwningPlayer(U)
local string s = ""
if ( GetUnitTypeId(U) == 'H01H' ) then
set s = "|cfffed312You cannot build towers or barricades with a Pilot. |r"
elseif ( IsRuinInEnemyBase() ) then
set s = "|cfffed312You cannot build towers or barricades in the enemy's base. |r"
elseif ( IsRuinAtEnemyTradeMaster() ) then
set s = "|cfffed312You cannot build towers or barricades near the enemy's Trade Master.|r"
elseif ( IsTowerNearby(Ruin) ) then
set s = "|cfffed312A building has already been built on this Tower Ruin.|r"
elseif ( (GetUnitTypeId(Tower) == LASER_TOWER_SELL_ID) and (GetPlayerTechCount(Owner, 'R002', true) < 1) ) then
set s = "|cfffed312Your team does not have the required weapon upgrades.|r"
endif
if (s != "") then
call RemoveUnitFromStock(Ruin, GetUnitTypeId(Tower))
call RefreshRuinSupply(Ruin)
call SetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD) + GetUnitPointValue(Tower))
call DisplayTextToPlayer(Owner, 0, 0, s )
else
call SetUnitOwner( Ruin, GetOwningPlayer(Tower), true )
if ( GetUnitTypeId(Tower) == ROCKET_TOWER_SELL_ID ) then
set New = ReplaceRuin( Ruin, ROCKET_TOWER_ID )
elseif ( GetUnitTypeId(Tower) == BARRICADE_SELL_ID ) then
set New = ReplaceRuin( Ruin, BARRICADE_ID )
elseif ( GetUnitTypeId(Tower) == TELEPORT_BEACON_SELL_ID ) then
set New = ReplaceRuin( Ruin, TELEPORT_BEACON_ID )
elseif ( GetUnitTypeId(Tower) == CAMOUFLAGE_GENERATOR_SELL_ID ) then
set New = ReplaceRuin( Ruin, CAMOUFLAGE_GENERATOR_ID )
call Start_Camouflage_Generator(New)
else
set New = ReplaceRuin( Ruin, LASER_TOWER_ID )
endif
if (GetUnitTypeId(New) != LASER_TOWER_ID) then
//call ApplyTimedLife(New)
call UnitApplyTimedLife(New, 'B015', 180)
endif
if ((GetUnitTypeId(New) == TELEPORT_BEACON_ID) and IsPlayerAlly(GetLocalPlayer(), Owner)) then
call PingMinimap(GetUnitX(New), GetUnitY(New), 3)
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, udg_Color[GetPlayerNr(Owner)] + GetPlayerName(Owner) + "|r|cfffed312 has built a Teleport Beacon.|r" )
endif
// Reward Support Points based on how much money was payed for the building (<600 = 0.5; > 1200 = 2.0; 1.0 else)
if (GetUnitTypeId(New) == LASER_TOWER_ID) then
call MB_SetSupport( GetPlayerNr(Owner), 2.0 )
elseif (GetUnitTypeId(New) == TELEPORT_BEACON_ID) or (GetUnitTypeId(New) == BARRICADE_ID) or (GetUnitTypeId(New) == CAMOUFLAGE_GENERATOR_ID) then
call MB_SetSupport( GetPlayerNr(Owner), 0.5 )
else
call MB_SetSupport( GetPlayerNr(Owner), 1.0 )
endif
set udg_Stats_Buildings[GetPlayerNr(Owner)] = ( udg_Stats_Buildings[GetPlayerNr(Owner)] + 1 )
endif
set U = null
set Tower = null
set Ruin = null
set New = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Build_Tower = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Build_Tower, EVENT_PLAYER_UNIT_SELL )
call TriggerAddCondition( gg_trg_Build_Tower, Condition( function Trig_Build_Tower_Conditions ) )
call TriggerAddAction( gg_trg_Build_Tower, function Trig_Build_Tower_Actions )
endfunction
endscope
//TESH.scrollpos=33
//TESH.alwaysfold=0
function Trig_Building_Destroyed_Conditions takes nothing returns boolean
if IsDecoy(GetTriggerUnit()) then
return false
endif
//Headquarter
if ( GetUnitTypeId(GetTriggerUnit()) == 'h004' ) then
return false
endif
if ( IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) == true ) then
return true
endif
return false
endfunction
function IsAliveProtectiveTower takes nothing returns boolean
return (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0) and ( 'h01Y' == GetUnitTypeId(GetFilterUnit()) )
endfunction
function IsHQProtected takes integer team returns boolean
local integer hqTowerCount = 0
local group G = GetUnitsOfPlayerMatchingSafe(udg_Force[team], Condition(function IsAliveProtectiveTower))
set hqTowerCount = CountUnitsInGroup(G)
call ReleaseGroup(G)
return ( hqTowerCount > 0 )
endfunction
function Trig_Building_Destroyed_Actions takes nothing returns nothing
local integer KillerId = GetPlayerNr(GetOwningPlayer(GetKillingUnit()))
local integer Id = GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))
local integer i = 1
local unit U = GetTriggerUnit()
local group G
if ( GetUnitTypeId(U) == 'h01K' ) then
set udg_Command_Center[udg_Player_Team[Id]] = ( udg_Command_Center[udg_Player_Team[Id]] - 1 )
endif
if ( IsTinkerTower(U) or IsForceTower(U) ) then
call UnitBlowUpExplosives(U, U, true)
call ItemDropAll(U)
if ( IsForceTower(U) ) then
//look for hidden Tower Ruins on the same position
set G = NewGroup()
call GroupEnumUnitsInRangeEx(G, GetUnitX(U), GetUnitY(U), 150, FILTER_TOWER_RUIN )
if FirstOfGroup(G) != null then
//show the tower ruin again
call ShowUnit(FirstOfGroup(G), true)
call SetUnitOwner(FirstOfGroup(G), Player(PLAYER_NEUTRAL_PASSIVE), true)
else
//create Tower Ruin
call CreateUnitAtLoc( Player(PLAYER_NEUTRAL_PASSIVE), 'h00Q', GetUnitLoc(U), bj_UNIT_FACING )
endif
call ReleaseGroup(G)
set G = null
loop
exitwhen i > 2
if ( IsHQProtected(i) ) then
call SetUnitInvulnerable( udg_HQ[i], true )
else
call SetUnitInvulnerable( udg_HQ[i], false )
endif
set i = i + 1
endloop
else
endif
else
if ( not IsWatchTower(U) ) then
call DestroyEffect( AddSpecialEffectLoc( "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", GetUnitLoc(U) ) )
endif
endif
//League Stats
if (GetOwningPlayer(GetKillingUnit()) != GetOwningPlayer(U)) and (GetKillingUnit() != null) then
set BuildingsKilled[KillerId-1] = BuildingsKilled[KillerId-1] + 1
endif
call DestroyEffect( AddSpecialEffectLoc( "Abilities\\Spells\\Other\\Volcano\\VolcanoDeath.mdl", GetUnitLoc(U) ) )
call TriggerSleepAction( 3.00 )
call RemoveUnit( U )
set U = null
endfunction
//===========================================================================
function InitTrig_Building_Destroyed takes nothing returns nothing
set gg_trg_Building_Destroyed = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Building_Destroyed, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Building_Destroyed, Condition( function Trig_Building_Destroyed_Conditions ) )
call TriggerAddAction( gg_trg_Building_Destroyed, function Trig_Building_Destroyed_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TowerProtection initializer Init
private function C takes nothing returns boolean
local integer i = 0
loop
exitwhen i >= 12
if GetUnitState(udg_BaseProtTower[i], UNIT_STATE_LIFE) > 0 then
call IssueTargetOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(udg_BaseProtTower[i]), 'A0FD', 1, GetUnitX(udg_BaseFactory[i]), GetUnitY(udg_BaseFactory[i]), 0), "innerfire", udg_BaseFactory[i])
endif
set i = i + 1
endloop
return false
endfunction
private function Remove takes nothing returns boolean
local integer i = 0
loop
exitwhen i >= 12
if GetTriggerUnit() == udg_BaseProtTower[i] then
call UnitRemoveAbility(udg_BaseFactory[i],'B01N')
set i = 11
endif
set i = i + 1
endloop
return false
endfunction
private function G takes nothing returns boolean
local trigger t = CreateTrigger()
local integer i = 0
loop
exitwhen i >= 12
call TriggerRegisterUnitEvent(t,udg_BaseProtTower[i], EVENT_UNIT_DEATH )
set i = i + 1
endloop
call TriggerAddCondition(t,Condition(function Remove))
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local trigger g = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(t, 5.00 )
call TriggerAddCondition(t,Condition(function C))
call TriggerRegisterTimerEventSingle(g, 0.01 )
call TriggerAddCondition(g,Condition(function G))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope MultipageShop initializer Init
globals
private constant integer NEXT_PAGE_ID = 'z01V'
private constant integer BACK_PAGE_ID = 'z01W'
private constant integer MARKET_1_ID = 'h00J'
private constant integer MARKET_2_T1_ID = 'h01W'
private constant integer MARKET_2_T2_ID = 'h01E'
private constant integer VEHICLE_1_ID = 'h003'
private constant integer VEHICLE_2_ID = 'h02L'
endglobals
function Multipage_Shop_Action takes nothing returns nothing
local unit Source = GetSoldUnit()
local integer ShopId = GetUnitTypeId(GetSellingUnit())
local integer team = udg_Player_Team[GetPlayerNr(GetOwningPlayer(Source))]
if GetUnitTypeId(Source) == NEXT_PAGE_ID then
if (ShopId == MARKET_1_ID) then
call SelectUnitForPlayerSingle(udg_TradeMarket_Page2[team], GetOwningPlayer(Source))
elseif (ShopId == VEHICLE_1_ID) then
call SelectUnitForPlayerSingle(udg_VehicleFactory_Page2[team], GetOwningPlayer(Source))
endif
call RemoveUnit(Source)
elseif GetUnitTypeId(Source) == BACK_PAGE_ID then
if (ShopId == MARKET_2_T1_ID) or (ShopId == MARKET_2_T2_ID) then
call SelectUnitForPlayerSingle(udg_TradeMarket[team], GetOwningPlayer(Source))
elseif (ShopId == VEHICLE_2_ID) then
call SelectUnitForPlayerSingle(udg_VehicleFactory[team], GetOwningPlayer(Source))
endif
call RemoveUnit(Source)
endif
set Source = null
endfunction
private function Init takes nothing returns nothing
local trigger d = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(d, EVENT_PLAYER_UNIT_SELL)
call TriggerAddAction(d, function Multipage_Shop_Action)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TraderMarketInfo initializer Init
private function Exe takes nothing returns boolean
local unit u = GetSoldUnit()
local unit t = GetTriggerUnit()
if GetUnitTypeId(u) == 'z01X' then // Information
// Normal Market
if GetUnitTypeId(t) == 'h00J' then
call DisplayTimedTextToPlayer(GetOwningPlayer(u),0,0, 5.00,"|cfffed312The Market is a place to buy a trade wagon (Trader) in order to earn and buy goods all over the map. These goods are sold here. You may also hire unique specialists here to turn the tide of the battle.|r")
// Item Page
elseif (GetUnitTypeId(t) == 'h01W') or (GetUnitTypeId(t) == 'h01E') then
call DisplayTimedTextToPlayer(GetOwningPlayer(u),0,0, 5.00,"|cfffed312This menu offers the option to exchange your goods with special items.|r")
endif
call RemoveUnit(u)
endif
set u = null
set t = null
return true
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SELL)
call TriggerAddCondition(t,Condition(function Exe))
endfunction
endscope
//TESH.scrollpos=9
//TESH.alwaysfold=0
function Trig_Unit_Anti_Flee_Conditions takes nothing returns boolean
if ( not udg_ObserverInGame ) then
call DestroyTrigger(GetTriggeringTrigger())
return false
endif
if ( GetIssuedOrderId() != String2OrderIdBJ("move") ) then
return false
endif
if ( ( GetOwningPlayer(GetTriggerUnit()) == udg_Force[1] ) or ( GetOwningPlayer(GetTriggerUnit()) == udg_Force[2] ) ) then
return true
endif
return false
endfunction
function Trig_Unit_Anti_Flee_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local unit target = null
local group G = NewGroup()
call GroupEnumUnitsInRange(G, GetUnitX(U), GetUnitY(U), 1100, FILTER_ANY_TOWER)
set target = GetClosestUnitFromGroup(G, GetUnitX(U), GetUnitY(U))
if (target != null) then
call IssueTargetOrder( U, "attack", target)
else
call IssuePointOrderLoc( U, "attack", udg_Move_Points[GetTargetMovePoint(U)] )
endif
call ReleaseGroup(G)
set G = null
set U = null
set target = null
endfunction
//===========================================================================
function InitTrig_Unit_Anti_Flee takes nothing returns nothing
set gg_trg_Unit_Anti_Flee = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Unit_Anti_Flee, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerAddCondition( gg_trg_Unit_Anti_Flee, Condition( function Trig_Unit_Anti_Flee_Conditions ) )
call TriggerAddAction( gg_trg_Unit_Anti_Flee, function Trig_Unit_Anti_Flee_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope UnitDeath initializer Init
private function Conditions takes nothing returns boolean
return not (IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) or IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE))
endfunction
function Actions takes nothing returns nothing
local unit DyingUnit = GetTriggerUnit()
local integer i = GetUnitTypeId(DyingUnit)
local integer foodcost = 2
local integer k = 0
// 10 and above = summoned by Troop Command / Reinforcements
if GetLaneCreepFlag(DyingUnit, CF_COSTS_FOOD) and (IsDummy(DyingUnit) == false) then
//only Marines and Mortars cost only one food
if (GetUnitTypeId(DyingUnit) == 'z006') then
set foodcost = 1
endif
call SetPlayerState(GetOwningPlayer(DyingUnit), PLAYER_STATE_RESOURCE_FOOD_USED, GetPlayerState(GetOwningPlayer(DyingUnit), PLAYER_STATE_RESOURCE_FOOD_USED) - foodcost)
endif
if i=='z01N' or i=='z01H' or i=='z01O' or i=='z01P' or i=='z01L' or i=='z003' then
call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\SteamTank\\SteamTankImpact.mdl", GetUnitX(DyingUnit), GetUnitY(DyingUnit) ) )
endif
if i != 'h00W' then
if (i != 'u000') and (i != 'z00P') then
if i == 'z001' then
call DestroyEffect( AddSpecialEffect( "Abilities\\Weapons\\SteamTank\\SteamTankImpact.mdl", GetUnitX(DyingUnit), GetUnitY(DyingUnit) ) )
endif
if (GetKillingUnit() != null) and (IsPlayerInForce(GetOwningPlayer(GetKillingUnit()), udg_Players)) then
set i = GetPlayerNr(GetOwningPlayer(GetKillingUnit()))
set udg_Stats_CreepKills[i] = udg_Stats_CreepKills[i] + 1
endif
call Pala.TimedUnitRemoval(DyingUnit,3.00)
endif
else
call Pala.TimedUnitRemoval(DyingUnit,20.00)
endif
set DyingUnit = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t,Condition(function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=48
//TESH.alwaysfold=0
globals
integer array MagicBuffCount[2]
integer array DamageBuffCount[2]
integer array MortarBuffCount[2]
integer MagicBuffAbility = 'A0FV'
integer DamageBuffAbility = 'A0FY'
integer MortarBuffUnitId = 'z01O'
endglobals
function Trig_Unit_Spawn_SpawnAndMove takes unit Factory, integer TypeId, integer SpawnLoc, real Face, integer UserData, integer MoveLoc returns integer
local unit Spawn
local integer team = udg_Player_Team[GetPlayerNr(GetOwningPlayer(Factory))]
if GetUnitState(Factory, UNIT_STATE_LIFE) > 0 then
set Spawn = CreateUnitAtLoc(GetOwningPlayer(Factory), TypeId, udg_Spawn_Points[SpawnLoc], Face)
if (UserData == 2) then
call SetLaneCreepFlag(Spawn, CF_ALTERNATE_ROUTE)
endif
call RemoveGuardPosition(Spawn)
call SetUnitCreepGuard(Spawn, false)
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[MoveLoc] )
if (MagicBuffCount[team] > 0) then
call UnitAddAbility(Spawn, MagicBuffAbility)
endif
if (DamageBuffCount[team] > 0) then
call UnitAddAbility(Spawn, DamageBuffAbility)
endif
set Spawn = null
return 0
endif
return GetUnitPointValueByType(TypeId)*4
endfunction
function Trig_Unit_Spawn_Actions takes nothing returns nothing
local group G
local unit Spawn
local unit U
local integer i
local integer j
local integer int
local player FactoryOwner
local integer PlayerId
local real X
local real Y
local real GoldFactor
// creeps will spawn on the exact 20s mark, but when there is a delay before the game (and clock starts) they will still keep the
// spawn at the same 20s mark, even when the game clock only shows 10s because of the delay
// So, in a really smooth way, this wait keeps the multiboard clock synchronized with the actual spawn
call GameTimeWait(GAME_START_DELAY)
set GoldFactor = GetBountyFactor()
//call DebugMsg("|cffffcc00Distance left:|r " + R2S(DistanceBetweenPoints(GetUnitLoc(udg_Tank[1]), udg_Move_Points[12])) )
//call DebugMsg("|cffffcc00Distance mid:|r " + R2S(DistanceBetweenPoints(GetUnitLoc(udg_Tank[1]), udg_Move_Points[18])) )
//call DebugMsg("|cffffcc00Distance right:|r " + R2S(DistanceBetweenPoints(GetUnitLoc(udg_Tank[1]), udg_Move_Points[15])) )
// Aura Creeps of the Dark Force
//if (udg_Command_Center[1] > 0) then
if ( GetRandomInt(1, 100) <= 11 * GetPlayerTechCountSimple('R005', udg_Force[1])) then
call Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0013, udg_Aura_Creeps[GetRandomInt(1, 3)], 3, 90, 0, 12 )
call Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0013, udg_Aura_Creeps[GetRandomInt(1, 3)], 3, 90, 1, 18 )
call Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0013, udg_Aura_Creeps[GetRandomInt(1, 3)], 3, 0, 0, 15 )
endif
//endif
// Normal Creeps spawned in the base of the Dark Force
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0008, 'z000', 1, 90, 1, 18 )
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0008, 'z000', 1, 90, 0, 12 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0011, 'z000', 2, 90, 1, 18 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0011, 'z000', 2, 90, 0, 12 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0013, 'z001', 3, 90, 1, 18 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0013, 'z001', 3, 90, 0, 12 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0013, 'z001', 4, 0, 2, 18 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0013, 'z001', 4, 0, 0, 15 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0009, 'z000', 5, 0, 2, 18 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0009, 'z000', 5, 0, 0, 15 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0010, 'z000', 6, 0, 2, 18 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0010, 'z000', 6, 0, 0, 15 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0023, 'z002', 7, 180, 1, 18 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0023, 'z002', 7, 180, 0, 12 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0022, 'z002', 8, 270, 2, 18 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0022, 'z002', 8, 270, 0, 15 ) + i
// Additional Mortar units bought by the Mortar Creep Buff
if (MortarBuffCount[1] > 0) then
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0008, MortarBuffUnitId, 1, 90, 0, 12 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0011, MortarBuffUnitId, 2, 90, 0, 12 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0023, MortarBuffUnitId, 7, 180, 1, 18 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0022, MortarBuffUnitId, 8, 270, 2, 18 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0010, MortarBuffUnitId, 6, 0, 0, 15 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0009, MortarBuffUnitId, 5, 0, 0, 15 ) + i
endif
// Compensation gold for destroyed factories
if i > 0 then
set i = R2I(i*GoldFactor)
call AdjustPlayerStateBJ( i, udg_Force[2], PLAYER_STATE_RESOURCE_GOLD )
set udg_Income[12] = udg_Income[12] + i*3/4
endif
// Aura Creeps of the Light Force
if (udg_Command_Center[2] > 0) then
if ( GetRandomInt(1, 100) <= 11 * GetPlayerTechCountSimple('R005', udg_Force[2])) then
call Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0032, udg_Aura_Creeps[GetRandomInt(1, 3)], 11, 180, 0, 14 )
call Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0032, udg_Aura_Creeps[GetRandomInt(1, 3)], 11, 180, 1, 19 )
call Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0032, udg_Aura_Creeps[GetRandomInt(1, 3)], 11, 270, 0, 17 )
endif
endif
// Normal Creeps spawned in the base of the Light Force
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0001, 'z000', 9, 180, 1, 19 )
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0001, 'z000', 9, 180, 0, 14 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0004, 'z000', 10, 180, 1, 19 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0004, 'z000', 10, 180, 0, 14 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0032, 'z001', 11, 180, 1, 19 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0032, 'z001', 11, 180, 0, 14 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0032, 'z001', 12, 270, 2, 19 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h004_0032, 'z001', 12, 270, 0, 17 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0029, 'z000', 13, 270, 2, 19 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0029, 'z000', 13, 270, 0, 17 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0028, 'z000', 14, 270, 2, 19 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0028, 'z000', 14, 270, 0, 17 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0068, 'z002', 15, 0, 2, 19 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0068, 'z002', 15, 0, 0, 17 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0069, 'z002', 16, 0, 1, 19 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0069, 'z002', 16, 0, 0, 14 ) + i
// Additional Mortar units bought by the Mortar Light Buff
if (MortarBuffCount[2] > 0) then
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0001, MortarBuffUnitId, 9, 180, 0, 14 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0004, MortarBuffUnitId, 10, 180, 0, 14 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0069, MortarBuffUnitId, 16, 0, 1, 19 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0068, MortarBuffUnitId, 15, 0, 2, 19 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0028, MortarBuffUnitId, 14, 270, 0, 17 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0029, MortarBuffUnitId, 13, 270, 0, 17 ) + i
endif
// Compensation gold for destroyed factories
if i > 0 then
set i = R2I(i*GoldFactor)
call AdjustPlayerStateBJ( i, udg_Force[1], PLAYER_STATE_RESOURCE_GOLD )
set udg_Income[11] = udg_Income[11] + i*3/4
endif
// Creeps spawned by the Control Points and Factories built by players
set G = GetUnitsInRectMatchingSafe(udg_Playable_Map, FILTER_CP_OR_PLAYER_FACTORY)
set U = FirstOfGroup( G )
loop
exitwhen U == null
set FactoryOwner = GetOwningPlayer(U)
set i = udg_Player_Team[GetPlayerNr(FactoryOwner)]
// First determine where the Control Points and Factories will send their creeps, based on their owning team and position on the map
if i == 1 then
if U == udg_Control_Point[1] then
set j = 12
elseif U == udg_Control_Point[2] then
set j = 21
elseif U == udg_Control_Point[4] then
set j = 17
else
set j = GetTargetMovePoint(U)
endif
else
if U == udg_Control_Point[5] then
set j = 20
elseif U == udg_Control_Point[4] then
set j = 17
elseif U == udg_Control_Point[3] then
set j = 15
else
set j = GetTargetMovePoint(U)
endif
endif
set X = GetUnitX(U)
set Y = GetUnitY(U)
// Creeps spawned by the Control Points
if (GetUnitTypeId(U) == 'h00P') then
set Spawn = CreateUnit(udg_Force[i], 'z000', X, Y, 270)
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[j] )
set Spawn = CreateUnit(udg_Force[i], 'z000', X, Y, 270)
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[j] )
// Creeps spawned by the Spawning Factories
elseif (GetUnitTypeId(U) == 'h015') then
set PlayerId = GetPlayerNr(FactoryOwner)
set i = GetPlayerState(FactoryOwner, PLAYER_STATE_RESOURCE_FOOD_CAP) - GetPlayerState(FactoryOwner, PLAYER_STATE_RESOURCE_FOOD_USED)
// Check before each spawn, if the player has enough free food to support the new units
if i > 1 then
set Spawn = CreateUnit(FactoryOwner, 'z007', X, Y, 270)
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[j] )
set udg_Stats_CreepBuy[PlayerId] = udg_Stats_CreepBuy[PlayerId] + 1
endif
if i > 3 then
set Spawn = CreateUnit(FactoryOwner, 'z008', X, Y, 270)
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[j] )
set udg_Stats_CreepBuy[PlayerId] = udg_Stats_CreepBuy[PlayerId] + 1
endif
if i > 5 then
set Spawn = CreateUnit(FactoryOwner, 'z00D', X, Y, 270)
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[j] )
set udg_Stats_CreepBuy[PlayerId] = udg_Stats_CreepBuy[PlayerId] + 1
endif
if i > 6 then
set Spawn = CreateUnit(FactoryOwner, 'z006', X, Y, 270)
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[j] )
set udg_Stats_CreepBuy[PlayerId] = udg_Stats_CreepBuy[PlayerId] + 1
endif
if i > 7 then
set Spawn = CreateUnit(FactoryOwner, 'z006', X, Y, 270)
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[j] )
set udg_Stats_CreepBuy[PlayerId] = udg_Stats_CreepBuy[PlayerId] + 1
endif
endif
call GroupRemoveUnit( G, U )
set U = FirstOfGroup( G )
endloop
// NewGroup() is called within the GetUnitsInRectMatchingSafe function, so use ReleaseGroup to properly recycle it
call ReleaseGroup( G )
// Gold for the missing spawns of the captured CPs
call AdjustPlayerStateBJ( R2I(4* 24 * udg_Team_CPs[1] * GoldFactor), udg_Force[1], PLAYER_STATE_RESOURCE_GOLD )
call AdjustPlayerStateBJ( R2I(4* 24 * udg_Team_CPs[2] * GoldFactor), udg_Force[2], PLAYER_STATE_RESOURCE_GOLD )
// Rooted Guard spawns
set G = GetUnitsInRectMatchingSafe(udg_Playable_Map, FILTER_ROOTED_GUARD)
set U = FirstOfGroup( G )
loop
exitwhen U == null
set int = GetUnitAbilityLevel(U, 'A0CH')
set i = udg_Treant[int]
set j = 3 - udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
set X = GetUnitX(U)
set Y = GetUnitY(U)
set Spawn = CreateUnit(GetOwningPlayer(U), i, X, Y, 270)
call UnitApplyTimedLife( Spawn, 'BTLF', 10+(int*4) )
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[GetTargetMovePoint(Spawn)] )
call GroupRemoveUnit( G, U )
set U = FirstOfGroup( G )
endloop
// NewGroup() is called within the GetUnitsInRectMatchingSafe function, so use ReleaseGroup to properly recycle it
call ReleaseGroup( G )
call GameTimeWait( 3 )
// Zeppelin creep spawns later because they'd be faster than the other ones
if udg_Team_Winning == 0 then
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0008, 'z00C', 1, 45, 0, 12 )
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0011, 'z00C', 2, 45, 1, 10 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0009, 'z00C', 5, 45, 0, 15 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0010, 'z00C', 6, 45, 2, 10 ) + i
if i > 0 then
set i = R2I(i*GoldFactor)
call AdjustPlayerStateBJ( i, udg_Force[2], PLAYER_STATE_RESOURCE_GOLD )
set udg_Income[12] = udg_Income[12] + i*3/4
endif
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0001, 'z00C', 9, 225, 0, 14 )
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0004, 'z00C', 10, 225, 1, 11 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0029, 'z00C', 13, 225, 0, 17 ) + i
set i = Trig_Unit_Spawn_SpawnAndMove( gg_unit_h002_0028, 'z00C', 14, 225, 2, 11 ) + i
if i > 0 then
set i = R2I(i*GoldFactor)
call AdjustPlayerStateBJ( i, udg_Force[1], PLAYER_STATE_RESOURCE_GOLD )
set udg_Income[11] = udg_Income[11] + i*3/4
endif
endif
set MagicBuffCount[1] = IMaxBJ(0, MagicBuffCount[1] - 1)
set MagicBuffCount[2] = IMaxBJ(0, MagicBuffCount[2] - 1)
set DamageBuffCount[1] = IMaxBJ(0, DamageBuffCount[1] - 1)
set DamageBuffCount[2] = IMaxBJ(0, DamageBuffCount[2] - 1)
set MortarBuffCount[1] = IMaxBJ(0, MortarBuffCount[1] - 1)
set MortarBuffCount[2] = IMaxBJ(0, MortarBuffCount[2] - 1)
set Spawn = null
set G = null
endfunction
//===========================================================================
function InitTrig_Unit_Spawn takes nothing returns nothing
set gg_trg_Unit_Spawn = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_Unit_Spawn, 20.00 )
call TriggerAddAction( gg_trg_Unit_Spawn, function Trig_Unit_Spawn_Actions )
endfunction
//TESH.scrollpos=21
//TESH.alwaysfold=0
function Trig_Unit_Upgrade_Conditions takes nothing returns boolean
local integer Id = GetUnitTypeId(GetSoldUnit())
return Id == 'z004' or Id == 'z00B'
endfunction
function Trig_Unit_Upgrade_Actions takes nothing returns nothing
local unit Upgrader = GetBuyingUnit()
local unit SoldUnit = GetSoldUnit()
local item Reinforcement = null
local integer i = 1
local integer PlayerId = GetPlayerNr(GetOwningPlayer(Upgrader))
local integer PlayerTeam = udg_Player_Team[PlayerId]
local integer Tech
local integer TechReq
local integer TechCosts = GetUnitPointValue(SoldUnit)
local player Owner = GetOwningPlayer(Upgrader)
local string S
if GetUnitTypeId(SoldUnit) == 'z004' then
set Tech = 'R002'
set TechReq = 'R009'
set S = "weapons"
else
set Tech = 'R003'
set TechReq = 'R008'
set S = "armor"
endif
if udg_NoUpgrades then
set S = "|cfffed312Upgrades are disabled.|r"
elseif GetOwningPlayer(SoldUnit) != Owner then
set S = "|cfffed312You cannot buy upgrades for allies.|r"
elseif GetPlayerTechCount(Owner, Tech, true) >= GetPlayerTechMaxAllowed(Owner, Tech) then
set S = "|cfffed312The maximum level is reached.|r"
endif
call RemoveUnit(SoldUnit)
set SoldUnit = null
if S!="weapons" and S!="armor" then
call DisplayTextToPlayer(Owner, 0, 0, S)
call SetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD) + TechCosts)
set S = null
return
endif
loop
exitwhen i > GetMaxPlayers()
if udg_Player_Team[i] == PlayerTeam then
call SetPlayerTechResearched( GetPlayer(i), Tech, GetPlayerTechCount(GetPlayer(i), Tech, true) + 1 )
call SetPlayerTechResearched( GetPlayer(i), TechReq, GetPlayerTechCount(GetPlayer(i), Tech, true) )
endif
set i = i + 1
endloop
set udg_Stats_Upgrades[PlayerId] = udg_Stats_Upgrades[PlayerId] + 1
call MB_SetSupport( PlayerId, 1.0 )
if udg_Player_Team[GetPlayerNr(GetLocalPlayer())] == PlayerTeam then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, udg_Color[PlayerId] + GetPlayerName(Owner) + "|r |cfffed312has upgraded your team's " + S + " to level " + I2S(GetPlayerTechCount(Owner,Tech, true)) + "!|r" )
endif
set Upgrader = null
set S = null
endfunction
//===========================================================================
function InitTrig_Unit_Upgrade takes nothing returns nothing
set gg_trg_Unit_Upgrade = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Unit_Upgrade, EVENT_PLAYER_UNIT_SELL )
call TriggerAddCondition( gg_trg_Unit_Upgrade, Condition( function Trig_Unit_Upgrade_Conditions ) )
call TriggerAddAction( gg_trg_Unit_Upgrade, function Trig_Unit_Upgrade_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Aura_Upgrade_Conditions takes nothing returns boolean
return (GetUnitTypeId(GetSoldUnit()) == 'z019')
endfunction
function Trig_Aura_Upgrade_Actions takes nothing returns nothing
local unit Upgrade = GetSoldUnit()
local player Force = udg_Force[udg_Player_Team[GetPlayerNr(GetOwningPlayer(Upgrade))]]
if ( GetPlayerTechCountSimple('R005', Force) >= 3 ) then
call AdjustPlayerStateBJ( R2I(GetUnitStateSwap(UNIT_STATE_LIFE, Upgrade)), GetOwningPlayer(Upgrade), PLAYER_STATE_RESOURCE_GOLD )
call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(Upgrade)), "|cfffed312You can't buy more than 3 upgrades.|r" )
else
call SetPlayerTechResearchedSwap( 'R005', ( GetPlayerTechCountSimple('R005', Force) + 1 ), Force )
set udg_Stats_Upgrades[GetPlayerNr(GetOwningPlayer(Upgrade))] = ( udg_Stats_Upgrades[GetPlayerNr(GetOwningPlayer(Upgrade))] + 1 )
call MB_SetSupport( GetPlayerNr(GetOwningPlayer(Upgrade)), 1.0 )
call DisplayTextToForce( GetPlayersAllies(GetOwningPlayer(Upgrade)), "|cfffed312Your teams Aura-Creeps have been upgraded.|r" )
endif
set Upgrade = null
endfunction
//===========================================================================
function InitTrig_Aura_Upgrade takes nothing returns nothing
set gg_trg_Aura_Upgrade = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Aura_Upgrade, EVENT_PLAYER_UNIT_SELL )
call TriggerAddCondition( gg_trg_Aura_Upgrade, Condition( function Trig_Aura_Upgrade_Conditions ) )
call TriggerAddAction( gg_trg_Aura_Upgrade, function Trig_Aura_Upgrade_Actions )
endfunction
//TESH.scrollpos=25
//TESH.alwaysfold=0
scope CreepWaveBuffs initializer Init
globals
private constant integer DAMAGE_BUFF_ID = 'z01J' // the ids of the sold units
private constant integer RESISTANCE_BUFF_ID = 'z027'
private constant integer MORTAR_BUFF_ID = 'z028'
private constant integer DAMAGE_BUFF_DURATION = 3
private constant integer RESISTANCE_BUFF_DURATION = 3
private constant integer MORTAR_BUFF_DURATION = 3
private constant integer DAMAGE_WEAPON_REQ = 3
private constant integer RESISTANCE_WEAPON_REQ = 3
private constant integer MORTAR_WEAPON_REQ = 3
endglobals
function Trig_Creep_Wave_Buffs_Conditions takes nothing returns boolean
local integer id = GetUnitTypeId(GetSoldUnit())
return (id-DAMAGE_BUFF_ID)*(id-RESISTANCE_BUFF_ID)*(id-MORTAR_BUFF_ID)==0
endfunction
function Trig_Creep_Wave_Buffs_Actions takes nothing returns nothing
local player Owner = GetOwningPlayer(GetBuyingUnit())
local integer id = GetUnitTypeId(GetSoldUnit())
local integer team = udg_Player_Team[GetPlayerNr(Owner)]
local integer WeaponsLevel = GetPlayerTechCount(Owner, 'R002', true)
local string s = ""
call DebugMsg("Creep Wave Buff")
if (id == DAMAGE_BUFF_ID) and (WeaponsLevel < DAMAGE_WEAPON_REQ) then
set s = "|cfffed312Your team needs at least|r " + I2S(DAMAGE_WEAPON_REQ) + " |cfffed312Weapon Upgrades.|r"
elseif (id == RESISTANCE_BUFF_ID) and (WeaponsLevel < RESISTANCE_WEAPON_REQ) then
set s = "|cfffed312Your team needs at least|r " + I2S(RESISTANCE_WEAPON_REQ) + " |cfffed312Weapon Upgrades.|r"
elseif (id == MORTAR_BUFF_ID) and (WeaponsLevel < MORTAR_WEAPON_REQ) then
set s = "|cfffed312Your team needs at least|r " + I2S(MORTAR_WEAPON_REQ) + " |cfffed312Weapon Upgrades.|r"
endif
if (s != "") then
call AdjustPlayerStateBJ( R2I(GetUnitStateSwap(UNIT_STATE_LIFE, GetSoldUnit())), Owner, PLAYER_STATE_RESOURCE_GOLD )
if (Owner == GetLocalPlayer()) then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, s )
endif
else
if (id == DAMAGE_BUFF_ID) then
set DamageBuffCount[team] = DamageBuffCount[team] + DAMAGE_BUFF_DURATION
set s = "|r |cfffed312has bought the damage buff for|r " + I2S(DAMAGE_BUFF_DURATION) + " |cfffed312additional creep waves!|r"
elseif (id == RESISTANCE_BUFF_ID) then
set MagicBuffCount[team] = MagicBuffCount[team] + RESISTANCE_BUFF_DURATION
set s = "|r |cfffed312has bought the resistance buff for|r " + I2S(RESISTANCE_BUFF_DURATION) + " |cfffed312additional creep waves!|r"
elseif (id == MORTAR_BUFF_ID) then
set MortarBuffCount[team] = MortarBuffCount[team] + MORTAR_BUFF_DURATION
set s = "|r |cfffed312has bought the Mortar buff for|r " + I2S(MORTAR_BUFF_DURATION) + " |cfffed312additional creep waves!|r"
endif
if (s != "") then
call MB_SetSupport( GetPlayerNr(Owner), 1.0 )
set udg_Stats_Upgrades[GetPlayerNr(Owner)] = ( udg_Stats_Upgrades[GetPlayerNr(Owner)] + 1 )
if udg_Player_Team[GetPlayerNr(GetLocalPlayer())] == team then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, udg_Color[GetPlayerNr(Owner)] + GetPlayerName(Owner) + s )
endif
endif
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Creep_Wave_Buffs = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Creep_Wave_Buffs, EVENT_PLAYER_UNIT_SELL )
call TriggerAddCondition( gg_trg_Creep_Wave_Buffs, Condition( function Trig_Creep_Wave_Buffs_Conditions ) )
call TriggerAddAction( gg_trg_Creep_Wave_Buffs, function Trig_Creep_Wave_Buffs_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Left_1_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
if not (GetLaneCreepFlag(U, CF_MANUAL_CONTROL) or IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsDummy(U)) then
call IssuePointOrderLoc( U, "attack", udg_Move_Points[13*i] )
// Array index is (2*team1Target-team2Target)+(team2Target-team1Target)*i
// team1Target = 13
// team2Target = 26
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Left_1 takes nothing returns nothing
set gg_trg_Unit_Enters_Left_1 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Left_1, gg_rct_Move_Left )
call TriggerAddCondition( gg_trg_Unit_Enters_Left_1, Condition( function Trig_Unit_Enters_Left_1_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Left_2_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
if not (GetLaneCreepFlag(U, CF_MANUAL_CONTROL) or IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsDummy(U)) then
call IssuePointOrderLoc( U, "attack", udg_Move_Points[16-2*i] )
// Array index is (2*team1Target-team2Target)+(team2Target-team1Target)*i
// team1Target = 14
// team2Target = 12
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Left_2 takes nothing returns nothing
set gg_trg_Unit_Enters_Left_2 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Left_2, gg_rct_Move_Left_2 )
call TriggerAddCondition( gg_trg_Unit_Enters_Left_2, Condition( function Trig_Unit_Enters_Left_2_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Left_3_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
if not (GetLaneCreepFlag(U, CF_MANUAL_CONTROL) or IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsDummy(U)) then
call IssuePointOrderLoc( U, "attack", udg_Move_Points[41-14*i] )
// Array index is (2*team1Target-team2Target)+(team2Target-team1Target)*i
// team1Target = 27
// team2Target = 13
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Left_3 takes nothing returns nothing
set gg_trg_Unit_Enters_Left_3 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Left_3, gg_rct_Move_Left_3 )
call TriggerAddCondition( gg_trg_Unit_Enters_Left_3, Condition( function Trig_Unit_Enters_Left_3_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Right_1_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
if not (GetLaneCreepFlag(U, CF_MANUAL_CONTROL) or IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsDummy(U)) then
call IssuePointOrderLoc( U, "attack", udg_Move_Points[6+10*i] )
// Array index is (2*team1Target-team2Target)+(team2Target-team1Target)*i
// team1Target = 16
// team2Target = 26
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Right_1 takes nothing returns nothing
set gg_trg_Unit_Enters_Right_1 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Right_1, gg_rct_Move_Right )
call TriggerAddCondition( gg_trg_Unit_Enters_Right_1, Condition( function Trig_Unit_Enters_Right_1_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Right_2_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
if not (GetLaneCreepFlag(U, CF_MANUAL_CONTROL) or IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsDummy(U)) then
call IssuePointOrderLoc( U, "attack", udg_Move_Points[19-2*i] )
// Array index is (2*team1Target-team2Target)+(team2Target-team1Target)*i
// team1Target = 17
// team2Target = 15
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Right_2 takes nothing returns nothing
set gg_trg_Unit_Enters_Right_2 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Right_2, gg_rct_Move_Right_2 )
call TriggerAddCondition( gg_trg_Unit_Enters_Right_2, Condition( function Trig_Unit_Enters_Right_2_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Right_3_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
if not (GetLaneCreepFlag(U, CF_MANUAL_CONTROL) or IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsDummy(U)) then
call IssuePointOrderLoc( U, "attack", udg_Move_Points[38-11*i] )
// Array index is (2*team1Target-team2Target)+(team2Target-team1Target)*i
// team1Target = 27
// team2Target = 16
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Right_3 takes nothing returns nothing
set gg_trg_Unit_Enters_Right_3 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Right_3, gg_rct_Move_Right_3 )
call TriggerAddCondition( gg_trg_Unit_Enters_Right_3, Condition( function Trig_Unit_Enters_Right_3_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Center_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
if not (GetLaneCreepFlag(U, CF_MANUAL_CONTROL) or IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsDummy(U)) then
call IssuePointOrderLoc( U, "attack", udg_Move_Points[20-i] )
// Array index is (2*team1Target-team2Target)+(team2Target-team1Target)*i
// team1Target = 19
// team2Target = 18
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Center takes nothing returns nothing
set gg_trg_Unit_Enters_Center = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Center, gg_rct_Move_Center_Left )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Center, gg_rct_Move_Center_Right )
call TriggerAddCondition( gg_trg_Unit_Enters_Center, Condition( function Trig_Unit_Enters_Center_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Center_Team_1_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
if not (GetLaneCreepFlag(U, CF_MANUAL_CONTROL) or IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsDummy(U)) then
if i == 1 then
if GetLaneCreepFlag(U, CF_ALTERNATE_ROUTE) then
call IssuePointOrderLoc(U, "attack", udg_Move_Points[21])
else
call IssuePointOrderLoc(U, "attack", udg_Move_Points[20])
endif
elseif i == 2 then
call IssuePointOrderLoc(U, "attack", udg_Move_Points[1 + 25])
endif
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Center_Team_1 takes nothing returns nothing
set gg_trg_Unit_Enters_Center_Team_1 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Center_Team_1, gg_rct_Move_Center_Team_1 )
call TriggerAddCondition( gg_trg_Unit_Enters_Center_Team_1, Condition( function Trig_Unit_Enters_Center_Team_1_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Center_Team_2_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
if not (GetLaneCreepFlag(U, CF_MANUAL_CONTROL) or IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_MECHANICAL) or IsDummy(U)) then
if i == 1 then
call IssuePointOrderLoc(U, "attack", udg_Move_Points[2 + 25])
elseif i == 2 then
if GetLaneCreepFlag(U, CF_ALTERNATE_ROUTE) then
call IssuePointOrderLoc(U, "attack", udg_Move_Points[21])
else
call IssuePointOrderLoc(U, "attack", udg_Move_Points[20])
endif
endif
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Center_Team_2 takes nothing returns nothing
set gg_trg_Unit_Enters_Center_Team_2 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Center_Team_2, gg_rct_Move_Center_Team_2 )
call TriggerAddCondition( gg_trg_Unit_Enters_Center_Team_2, Condition( function Trig_Unit_Enters_Center_Team_2_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Air_Team_1_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = GetPlayerNr(GetOwningPlayer(U))
if (i-11)*(i-12)==0 and GetUnitTypeId(U)=='z00C' then
call IssuePointOrderLoc( U, "attack", udg_Move_Points[-70+8*i] )
// Array index is (2*team1Target-team2Target)+(team2Target-team1Target)*i
// team1Target = 18
// team2Target = 26
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Air_Team_1 takes nothing returns nothing
set gg_trg_Unit_Enters_Air_Team_1 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Air_Team_1, gg_rct_Team_1_Air_Move )
call TriggerAddCondition( gg_trg_Unit_Enters_Air_Team_1, Condition( function Trig_Unit_Enters_Air_Team_1_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Unit_Enters_Air_Team_2_Conditions takes nothing returns boolean
// Checks whether the unit U is a creep to order to the next waypoint
// if it's a team 1 creep, the unit is sent to udg_Move_Points[team1Target],
// if it's a team 2 creep, the unit is sent to udg_Move_Points[team2Target]
local unit U = GetTriggerUnit()
local integer i = GetPlayerNr(GetOwningPlayer(U))
if (i-11)*(i-12)==0 and GetUnitTypeId(U)=='z00C' then
call IssuePointOrderLoc( U, "attack", udg_Move_Points[115-i*8] )
// Array index is (2*team1Target-team2Target)+(team2Target-team1Target)*i
// team1Target = 27
// team2Target = 19
endif
set U = null
return false
endfunction
//===========================================================================
function InitTrig_Unit_Enters_Air_Team_2 takes nothing returns nothing
set gg_trg_Unit_Enters_Air_Team_2 = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Unit_Enters_Air_Team_2, gg_rct_Team_2_Air_Move )
call TriggerAddCondition( gg_trg_Unit_Enters_Air_Team_2, Condition( function Trig_Unit_Enters_Air_Team_2_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
globals
real array Damaged[100]
endglobals
function Trig_Assist_Detection_Conditions takes nothing returns boolean
local integer sourceId = GetPlayerNr(GetOwningPlayer(GetEventDamageSource()))
local integer targetId = GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))
// the reason the code is completely written in the condition, is the assumption, that this uses less computing time
if (sourceId <= 10) then
//if GetEventDamage() > 3 then
set Damaged[10 * sourceId + targetId] = TimerGetElapsed(udg_GameTime)
// save how much damage the player dealt
set udg_Damage_Dealt[sourceId] = udg_Damage_Dealt[sourceId] + GetEventDamage()
// save how much damage the whole team dealt
set udg_Damage_Dealt[10+udg_Player_Team[sourceId]] = udg_Damage_Dealt[10+udg_Player_Team[sourceId]] + GetEventDamage()
//endif
// save the last time a player damaged an enemy
if (IsPlayerEnemy(GetPlayer(sourceId), GetPlayer(targetId)) and (GetEventDamage() > 3)) then
set udg_DamageLast[sourceId] = udg_Time_Value
endif
endif
return false
endfunction
//===========================================================================
function InitTrig_Assist_Detection takes nothing returns nothing
set gg_trg_Assist_Detection = CreateTrigger( )
call TriggerAddCondition( gg_trg_Assist_Detection, Condition( function Trig_Assist_Detection_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
globals
boolean HitpointChanges = false
endglobals
function Trig_Debug_HP_Regen_Actions takes nothing returns nothing
local integer i = 1
local real HPdiff
local real MaxHP
if (HitpointChanges) then
loop
exitwhen i > 10
set HPdiff = GetUnitState(udg_Tank[i], UNIT_STATE_LIFE) - udg_Tank_HP[i]
set MaxHP = GetUnitState(udg_Tank[i], UNIT_STATE_MAX_LIFE)
if ((HPdiff >= 0) and (HPdiff < (MaxHP *0.015))) then
//do nothing
elseif (HPdiff > 0) then
call ShowTextTag("|cff00ff00+"+I2S(R2I(HPdiff))+"|r", udg_Tank[i], 0, 0, GetPlayer(i))
else
call ShowTextTag("|cffff0000"+I2S(R2I(HPdiff))+"|r", udg_Tank[i], 0, 0, GetPlayer(i))
endif
set udg_Tank_HP[i] = GetUnitState(udg_Tank[i], UNIT_STATE_LIFE)
set i = i + 1
endloop
endif
endfunction
//===========================================================================
function InitTrig_Debug_HP_Regen takes nothing returns nothing
set gg_trg_Debug_HP_Regen = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_Debug_HP_Regen, 1.00 )
call TriggerAddAction( gg_trg_Debug_HP_Regen, function Trig_Debug_HP_Regen_Actions )
endfunction
//TESH.scrollpos=18
//TESH.alwaysfold=0
globals
integer array trg_MagicArmorSkills[3]
endglobals
function Trig_Magic_Armor_ResetArmor takes unit tank returns nothing
local integer i = 1
loop
exitwhen (i > 6)
call UnitRemoveAbility(tank, trg_MagicArmorSkills[i])
set i = i + 1
endloop
endfunction
function Trig_Magic_Armor_SetArmor takes unit tank, integer armor returns nothing
local integer armorRange = 0
local integer level = 0
if (armor == 0) then
// technically this case is not needed, but since it is the most common one
// just set it at the top, so that all the other cases don't have to be checked everytime the armor is 0
set armorRange = 0
elseif (armor < -20) then
set armorRange = 1
set level = 10
elseif (armor < -10) and (armor >= -20) then
set armorRange = 1
set level = (armor * -1) - 10
elseif (armor < 0) and (armor >= -10) then
set armorRange = 2
set level = armor * -1
elseif (armor > 0) and (armor <= 10) then
set armorRange = 3
set level = armor
elseif (armor > 10) and (armor <= 20) then
set armorRange = 4
set level = armor - 10
elseif (armor > 20) and (armor <= 30) then
set armorRange = 5
set level = armor - 20
elseif (armor > 30) and (armor <= 40) then
set armorRange = 6
set level = armor - 30
elseif (armor > 40) then
set armorRange = 6
set level = 10
endif
if (armorRange == 0) then
// no armor -> no reduction skills needed
call Trig_Magic_Armor_ResetArmor(tank)
else
if (GetUnitAbilityLevel(tank, trg_MagicArmorSkills[armorRange]) > 0) then
call SetUnitAbilityLevel(tank, trg_MagicArmorSkills[armorRange], level)
else
call Trig_Magic_Armor_ResetArmor(tank)
call UnitAddAbility(tank, trg_MagicArmorSkills[armorRange])
call SetUnitAbilityLevel(tank, trg_MagicArmorSkills[armorRange], level)
endif
endif
//call DebugMsg("Set the armor of player " + I2S(GetPlayerNr(GetOwningPlayer(tank))) + " to " + I2S(armor))
endfunction
function Trig_Magic_Armor_Actions takes nothing returns nothing
local integer i = 1
loop
exitwhen (i > GetMaxHumanPlayers())
if (udg_Tank[i] != null) and (GetUnitState(udg_Tank[i], UNIT_STATE_LIFE) > 0) then
call Trig_Magic_Armor_SetArmor(udg_Tank[i], Round(GetUnitArmor(udg_Tank[i])))
endif
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_Magic_Armor takes nothing returns nothing
set gg_trg_Magic_Armor = CreateTrigger( )
set trg_MagicArmorSkills[1] = 'A0GX' // covers the armor from -20 to -11
set trg_MagicArmorSkills[2] = 'A0GT' // covers the armor from -10 to -1
set trg_MagicArmorSkills[3] = 'A0GR' // covers the armor from 1 to 10
set trg_MagicArmorSkills[4] = 'A0GS' // covers the armor from 11 to 20
set trg_MagicArmorSkills[5] = 'A032' // covers the armor from 21 to 30
set trg_MagicArmorSkills[6] = 'A0DG' // covers the armor from 31 to 40
call TriggerRegisterTimerEvent( gg_trg_Magic_Armor, 0.50, true )
call TriggerAddAction( gg_trg_Magic_Armor, function Trig_Magic_Armor_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
globals
integer STRATEGIC_LOCATION_RESISTANCE_ID = 'A057'
integer STRATEGIC_LOCATION_HEALING_ID = 'A054'
integer STRATEGIC_LOCATION_BUFF_ABILITY_ID = 'A0CR'
integer STRATEGIC_LOCATION_BUFF_ID = 'B006'
endglobals
function Trig_Strategic_Loc_Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO)
endfunction
function Trig_Strategic_Loc_Enter_Actions takes nothing returns nothing
call EnableStrategicLocationBuff(GetTriggerUnit(), true)
endfunction
function Trig_Strategic_Loc_Leave_Actions takes nothing returns nothing
call EnableStrategicLocationBuff(GetTriggerUnit(), false)
endfunction
//===========================================================================
function InitTrig_Strategic_Loc takes nothing returns nothing
// Create a region which contains all Strategic Locations
local region Reg = CreateRegion()
call RegionAddRect(Reg, gg_rct_Strategic_Location_1)
call RegionAddRect(Reg, gg_rct_Strategic_Location_2)
call RegionAddRect(Reg, gg_rct_Strategic_Location_3)
call RegionAddRect(Reg, gg_rct_Strategic_Location_4)
call RegionAddRect(Reg, gg_rct_Strategic_Location_5)
call RegionAddRect(Reg, gg_rct_Strategic_Location_6)
call RegionAddRect(Reg, gg_rct_Strategic_Location_7)
call RegionAddRect(Reg, gg_rct_Strategic_Location_8)
set gg_trg_Strategic_Loc = CreateTrigger( )
call TriggerRegisterEnterRegion(gg_trg_Strategic_Loc, Reg, FILTER_ANY_TANK)
call TriggerAddCondition( gg_trg_Strategic_Loc, Condition( function Trig_Strategic_Loc_Conditions ) )
call TriggerAddAction( gg_trg_Strategic_Loc, function Trig_Strategic_Loc_Enter_Actions )
set gg_trg_Strategic_Loc = CreateTrigger( )
call TriggerRegisterLeaveRegion(gg_trg_Strategic_Loc, Reg, FILTER_ANY_TANK)
call TriggerAddCondition( gg_trg_Strategic_Loc, Condition( function Trig_Strategic_Loc_Conditions ) )
call TriggerAddAction( gg_trg_Strategic_Loc, function Trig_Strategic_Loc_Leave_Actions )
endfunction
//TESH.scrollpos=63
//TESH.alwaysfold=0
library TankChangeLibrary initializer Init requires MapAttachedSettings, WeaponInitUpdate
// Everything from changing units, xp, item or initializing tanks is done here
// Except the gold handling, this is done outside of this function
function TankMeetsTechRequirements takes player p, integer Tank returns integer
local integer WeaponsLevel = GetPlayerTechCount(p, 'R002', true)
local integer ArmorLevel = GetPlayerTechCount(p, 'R003', true)
if Tank == 0 then
return -1
endif
if not udg_NoRequirements then
if Tank=='H01I' and ArmorLevel<18 then // Titan
return 18
elseif Tank=='H00K' and ArmorLevel<16 then // Infernal Robot
return 16
elseif Tank=='H01R' and ArmorLevel<14 then // Sky Fortress
return 14
elseif Tank=='H01V' and ArmorLevel<13 then // Goliath
return 13
endif
if udg_ExtRequirements then
if Tank=='H00H' and ArmorLevel<11 then // Frost Robot
return 11
elseif Tank=='H00F' and ArmorLevel<8 then // Demon Tank
return 8
elseif Tank=='H01S' and ArmorLevel<7 then // Hunter
return 7
elseif Tank=='H00E' and ArmorLevel<6 then // Sky Tank
return 6
elseif Tank=='H02K' and ArmorLevel<5 then // Darkness Tank
return 5
elseif Tank=='H01U' and ArmorLevel<5 then // Earth Robot
return 5
elseif Tank=='H00I' and ArmorLevel<4 then // Goblin Tank
return 4
elseif Tank=='H021' and ArmorLevel<4 then // Architect
return 4
elseif Tank=='H00D' and ArmorLevel<3 then // Heavy Tank
return 3
elseif Tank=='H012' and ArmorLevel<3 then // Guard
return 3
elseif Tank=='H00R' and ArmorLevel<2 then // Ghost Tank
return 2
elseif Tank=='H00C' and ArmorLevel<2 then // Air Ship
return 2
elseif Tank=='H00B' and ArmorLevel<2 then // Thunder Tank
return 2
elseif Tank=='H025' and ArmorLevel<2 then // Storm Tank
return 2
endif
endif
endif
return 0
endfunction
function GetRandomStartTankType takes player P returns integer
local integer Gold = GetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD)
local integer array TankTypes
local integer TankTypesMax
local integer Start
local integer i
//Start game tanks
set TankTypes[0] = 'H01L' //Scout
set TankTypes[1] = 'H00X' //Anti-Grav
set TankTypes[2] = 'H009' //Light Tank
set TankTypes[3] = 'H008' //Helicopter
set TankTypes[4] = 'H007' //Demolisher
set TankTypes[5] = 'H017' //Medivac
set TankTypes[6] = 'H027' //Raider
set TankTypes[7] = 'H02J' //Distributor
//Mid game tanks
set TankTypes[10] = 'H011' //Goblin Shredder
set TankTypes[11] = 'H00R' //Ghost Tank
set TankTypes[12] = 'H012' //Guard
set TankTypes[13] = 'H00C' //Air Ship
set TankTypes[14] = 'H00B' //Thunder Tank
set TankTypes[15] = 'H00D' //Heavy Tank
set TankTypes[16] = 'H00I' //Goblin Tank
set TankTypes[17] = 'H021' //Architect
set TankTypes[18] = 'H025' //Storm Tank
//End game tanks
set TankTypes[20] = 'H01R' //Sky Fortress
set TankTypes[21] = 'H00K' //Infernal Robot
set TankTypes[22] = 'H00F' //Demon Tank
set TankTypes[23] = 'H00H' //Frost Robot
set TankTypes[24] = 'H00E' //Sky Tank
set TankTypes[25] = 'H01S' //Hunter
set TankTypes[26] = 'H01U' //Earth Robot
set TankTypes[27] = 'H01V' //Goliath
set TankTypes[28] = 'H02K' //Darkness Tank
if Gold < 10000 then
set TankTypesMax = 7
set Start = 0
elseif Gold < 30000 then
set TankTypesMax = 8
set Start = 10
else
set TankTypesMax = 8
set Start = 20
endif
set i = GetRandomInt(Start,TankTypesMax+Start)
loop
exitwhen ((TankMeetsTechRequirements(P, TankTypes[i]) == 0) and ((not udg_TankMonopoly) or (not AnyAllyHasTankOfType(P,TankTypes[i]))))
set i = i + 1
if i > (TankTypesMax + Start) then
if Start > 0 then
set Start = Start - 10
if Start < 10 then
set TankTypesMax = 7
elseif Start < 20 then
set TankTypesMax = 8
else
set TankTypesMax = 8
endif
set i = GetRandomInt(Start,TankTypesMax+Start)
else
set i = 0
endif
endif
endloop
return TankTypes[i]
endfunction
// ----- Tank initialization functions -----
function InitArchitect takes unit tank returns nothing
if (PWeapons == 0) then
set PWeapons = PacifistaWeapons.create()
endif
endfunction
function InitGuard takes unit tank returns nothing
call SetPlayerAbilityAvailableBJ(true, 'A0CH', GetOwningPlayer(tank) )
endfunction
function InitGhostTank takes unit tank returns nothing
call SetUnitVertexColor(tank, 255, 255, 255, 170 )
endfunction
function InitTankSpecefics takes unit tank returns nothing
if (GetUnitTypeId(tank) == 'H021') then
call InitArchitect(tank)
elseif (GetUnitTypeId(tank) == 'H00R') then
call InitGhostTank(tank)
elseif (GetUnitTypeId(tank) == 'H012') then
call InitGuard(tank)
endif
endfunction
// ----- End of Tank initialization functions -----
// ----- Tank finalization functions -----
function DestroyTinkerTower takes nothing returns boolean
if GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 and IsTinkerTower(GetFilterUnit()) then
call KillUnit( GetFilterUnit() )
endif
return false
endfunction
function FinTinker takes unit tank returns nothing
local group G
// Destroy tinker towers
set G = NewGroup()
call GroupEnumUnitsOfPlayer(G, GetOwningPlayer(tank), FILTER_DESTROY_TINKER_TOWERS)
call ReleaseGroup( G )
set G = null
endfunction
function DestroyPortals takes nothing returns boolean
if GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 and (GetUnitTypeId(GetFilterUnit()) == 'h020') then
//check is units are currently porting to this portal
if (udg_AV_Int2[GetHandleIndex(GetFilterUnit())] > 0) then
//with this boolean set to true, this portal will be destroyed, when the last unit finished it's teleport (new ports are not allowed)
set udg_AV_Bool1[GetHandleIndex(GetFilterUnit())] = true
else
call KillUnit(GetFilterUnit())
endif
endif
return false
endfunction
function FinArchitect takes unit tank returns nothing
local group G
local integer i = 0
local integer Id = GetPlayerNr(GetOwningPlayer(tank))
local unit itemSource = null
// Destroy Portals
set G = NewGroup()
call GroupEnumUnitsOfPlayer(G, GetOwningPlayer(tank), FILTER_DESTROY_PORTALS)
call ReleaseGroup( G )
set G = null
//Move the items from the Pacifista or the temporary item holder to the tank
if (PWeapons.Holder[Id] != null) then
set itemSource = PWeapons.Holder[Id]
elseif (Pacifista[Id] != null) then
set itemSource = Pacifista[Id]
endif
if (itemSource != null) then
loop
exitwhen i > 5
if not UnitAddItem( tank, UnitItemInSlot(itemSource, i) ) then
call SetItemPosition(UnitItemInSlot(itemSource, i), GetUnitX(tank), GetUnitY(tank))
endif
set i = i + 1
endloop
endif
call KillUnit(Pacifista[Id])
endfunction
function FinTankSpecifics takes unit tank returns nothing
if (GetUnitTypeId(tank) == 'H006') then
call FinTinker(tank)
elseif (GetUnitTypeId(tank) == 'H021') then
call FinArchitect(tank)
endif
endfunction
// ----- End of Tank finalization functions -----
//Changes tanks, adjusts tank related variables and events and gives XP and items to the new tank
//costs for the new tank are not considered, this has to be done outside of this function
function ChangeTanks takes unit OldTank, unit NewTank, unit Shop, boolean randomed returns nothing
local boolean IsTraderPlayer
local player Owner = GetOwningPlayer(OldTank)
local integer OwnerId = GetPlayerNr(Owner)
local integer OldTankType = GetUnitTypeId(OldTank)
local integer NewTankType = GetUnitTypeId(NewTank)
local integer SpawnLocId
local integer MoveLocId
local integer i
local string msg
local string tname
local string buy
//Finalize tank related structures or trigger
call FinTankSpecifics(OldTank)
call WeaponHolder[OwnerId].SetHolder(NewTank)
call WeaponHolder[OwnerId].RemoveAllWeapons()
set i = GetUnitPointValue(OldTank)/2
if i != 0 then
// Display gold for the old tank
call SetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD) + i)
set udg_Profit_Sold[GetPlayerNr(Owner)] = udg_Profit_Sold[GetPlayerNr(Owner)] + i
call ShowTextTag("|cfffed312+"+I2S(i)+"|r", OldTank, 0, 0, Owner)
endif
if udg_NoTinker and NewTankType == 'H006' then
// Replace the tinker with a pilot
call RemoveUnit( NewTank )
set NewTank = CreateUnit(Owner, 'H01H', 0, 0, 0)
call SetHeroXP( NewTank, GetHeroXP(OldTank), false )
call SuspendHeroXP( NewTank, true )
call SetUnitMoveSpeed( NewTank, 0.00 )
else
call SetHeroXP( NewTank, GetHeroXP(OldTank), false )
endif
// Change Items for the new tank
//set udg_Item_Check = false
set i = 0
loop
exitwhen i > 5
// ignore trade items
if (GetItemType(UnitItemInSlot(OldTank, i)) != ITEM_TYPE_CHARGED) then
call UnitAddItem( NewTank, UnitItemInSlot(OldTank, i) )
endif
set i = i + 1
endloop
call RemoveUnit( OldTank )
if NewTankType == 'H00Y' and GetPlayerState(Owner, PLAYER_STATE_RESOURCE_LUMBER) < 10 then
// Add 10 base lumber for the trader
call SetPlayerState(Owner, PLAYER_STATE_RESOURCE_LUMBER, 10)
endif
//set udg_Item_Check = true
set udg_Tank[OwnerId] = NewTank
call Tank_Attached_Fire_Change(OwnerId-1, 0)
call SetTankIcon(OwnerId)
//set WTank[OwnerId] = WeaponHolder.create(udg_Tank[OwnerId], OwnerId)
call TriggerRegisterUnitEvent( gg_trg_Assist_Detection, NewTank, EVENT_UNIT_DAMAGED )
call RegisterUnitForSkillDamageDetection(NewTank)
// Only show floating texts for the player of the trader
set i = 1
set IsTraderPlayer = GetUnitTypeId(udg_Tank[GetPlayerNr(GetLocalPlayer())])=='H00Y'
loop
exitwhen i > GetMaxHumanPlayers()
call SetTextTagVisibility(udg_Progress_Bar[i], IsTraderPlayer)
set i = i + 1
endloop
// Move new unit
if TradeMarketTeam(Shop, 1) then
set SpawnLocId = 5
set MoveLocId = 6
elseif TradeMarketTeam(Shop, 2) then
set SpawnLocId = 7
set MoveLocId = 8
elseif Shop == gg_unit_h00S_0132 then
set SpawnLocId = 22
set MoveLocId = 23
elseif Shop == gg_unit_h00S_0133 then
set SpawnLocId = 24
set MoveLocId = 25
else
set SpawnLocId = udg_Player_Team[OwnerId]
set MoveLocId = udg_Player_Team[OwnerId]+2
endif
call SetUnitPositionLoc(NewTank, udg_Move_Points[SpawnLocId])
call SetUnitFacing(NewTank, AngleBetweenPoints(udg_Move_Points[SpawnLocId], udg_Move_Points[MoveLocId]))
call IssuePointOrderLoc( NewTank, "move", udg_Move_Points[MoveLocId] )
//Initialize tank related structures or trigger
call InitTankSpecefics(NewTank)
call ApplyManaUpgrade(OwnerId)
// Select unit
if GetLocalPlayer() == Owner then
call ClearSelection()
call SelectUnit(NewTank, true)
endif
// Send the tank info to the hosting bot (if possible) and
// show the message, that a team mate, got a new tank
// But ignore the case, when someone switches to a Tinker, to get another tank
if not(((OldTankType != 'H01H') and (NewTankType == 'H006')) or (NewTankType == 'H01H')) then
set tname = GetName(NewTank)
set msg = StringCase(SubString(tname,0,1),false)
if (randomed) then
set buy = "randomed"
else
set buy = "bought"
endif
// Change message when tank name starts with a vocal
if(msg=="a" or msg=="e" or msg=="i" or msg=="o" or msg=="u")then
set msg = udg_Color[OwnerId] + GetPlayerName(Owner) + "|r has " + buy + " an |cfffed312" + tname + "|r."
else
set msg = udg_Color[OwnerId] + GetPlayerName(Owner) + "|r has " + buy + " a |cfffed312" + tname + "|r."
endif
if IsPlayerAlly(GetLocalPlayer(), Owner) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, msg)
endif
call SendBotDataOnline(TANK_INFO_DATA, "\"" + GetName(NewTank) + "\"," + I2S(OwnerId))
endif
call UpdateTankCosts(OwnerId)
call UpdateBounty(Owner, 0)
// Bugfix: When you buy a new tank, when you are still invulnerable (eg respawn), this variable cannot be reduced anymore
// So set it to 0, just in case
set udg_Tank_Invulnerable[OwnerId] = 0
endfunction
function BuyRandomStartTank takes player P returns unit
local integer PlayerId = GetPlayerNr(P)
local unit Tank
set Tank = CreateUnitAtLoc(P,GetRandomStartTankType(P),udg_Move_Points[udg_Player_Team[PlayerId]],180*udg_Player_Team[PlayerId]-135)
call ChangeTanks(udg_Tank[PlayerId], Tank, null, true)
call SetPlayerState(P,PLAYER_STATE_RESOURCE_GOLD,GetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD)-GetUnitPointValue(Tank))
return Tank
endfunction
globals
boolexpr FILTER_DESTROY_TINKER_TOWERS
boolexpr FILTER_DESTROY_PORTALS
endglobals
private function Init takes nothing returns nothing
set FILTER_DESTROY_TINKER_TOWERS = Condition(function DestroyTinkerTower)
set FILTER_DESTROY_PORTALS = Condition(function DestroyPortals)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Update_Speed_And_Fire_Actions takes nothing returns nothing
local integer PlayerId = 1
local real HPPercent
local real FullHP
local integer NewFireLevel
local integer Id
local integer speed
loop
exitwhen PlayerId > GetMaxHumanPlayers()
set FullHP = GetUnitState(udg_Tank[PlayerId], UNIT_STATE_MAX_LIFE)
if FullHP>0 then
call SetMoveSpeedIndicator(udg_Tank[PlayerId])
call SetRespawnTimeIndicator(udg_Tank[PlayerId])
set NewFireLevel = 0
set Id = GetUnitTypeId(udg_Tank[PlayerId])
if (Id-'H00I')*(Id-'H00H')*(Id-'H00R')*(Id-'H00K')*(Id-'H011')*(Id-'H01I')*(Id-'H025')==0 then
set HPPercent = GetUnitState(udg_Tank[PlayerId], UNIT_STATE_LIFE)/FullHP
if HPPercent > 0 and HPPercent < 0.8 then
//NewFireLevel Between 0 and 5
set NewFireLevel = R2I((0.95-HPPercent)*5.99)
endif
endif
if NewFireLevel != udg_Tank_FireLevel[PlayerId] then
call Tank_Attached_Fire_Change(PlayerId-1, NewFireLevel)
endif
endif
set PlayerId = PlayerId + 1
endloop
endfunction
//===========================================================================
function InitTrig_Update_Speed_And_Fire takes nothing returns nothing
set gg_trg_Update_Speed_And_Fire = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_Update_Speed_And_Fire, 0.40 )
call TriggerAddAction( gg_trg_Update_Speed_And_Fire, function Trig_Update_Speed_And_Fire_Actions )
endfunction
//TESH.scrollpos=5
//TESH.alwaysfold=0
function Trig_Vehicle_Buy_Conditions takes nothing returns boolean
return IsUnitType(GetSoldUnit(), UNIT_TYPE_HERO)
endfunction
function Trig_Vehicle_Buy_Actions takes nothing returns nothing
local boolean ValidBuy = true
local unit Shop = GetSellingUnit()
local unit OldTank = GetBuyingUnit()
local unit NewTank = GetSoldUnit()
local integer OldTankType = GetUnitTypeId(OldTank)
local integer NewTankType = GetUnitTypeId(NewTank)
local player Owner = GetOwningPlayer(NewTank)
local integer OwnerId = GetPlayerNr(Owner)
local integer ShopId = GetPlayerNr(GetOwningPlayer(GetSellingUnit()))
local integer Id
local integer i
local integer ArmorReq = TankMeetsTechRequirements(Owner, NewTankType)
local item SlotItem
local string s = null
//Check if buying a new tank is valid
if Owner != GetOwningPlayer(OldTank) then
set s = "|cfffed312You cannot buy vehicles for allied players.|r"
set ValidBuy = false
elseif ArmorReq > 0 then
//ArmorReq returns 0, when you have enough armor upgrades, otherwise it returns the required upgrades
set s = "|cfffed312You need at least|r " + I2S(ArmorReq) + "|cfffed312 armor upgrades.|r"
set ValidBuy = false
//ShopId has to be MaxPlayers or lower, so this only affects the tank selling building in the bases and not the neutral ones on the map
elseif ( udg_Player_Team[ShopId] != udg_Player_Team[OwnerId] ) and ( ShopId <= GetMaxPlayers() ) then
set s = "|cfffed312You cannot buy tanks in the enemy base.|r"
set ValidBuy = false
elseif (udg_NoExploder and NewTankType=='H014') or (udg_NoTrader and NewTankType=='H00Y') then
set s = "|cfffed312This tank cannot be used in this Game-Mode.|r"
set ValidBuy = false
elseif IsTechMech(OldTank) then
set s = "|cfffed312The Tech Mech cannot buy tanks.|r"
set ValidBuy = false
elseif IsPacifista(OldTank) then
set s = "|cfffed312The Pacifista cannot buy tanks.|r"
set ValidBuy = false
elseif NewTankType==OldTankType or (OldTankType=='H013' and NewTankType=='H012') or (OldTankType=='H02A' and NewTankType=='H01V') then
// Same Tank or rooted guard buys guard or a Goliath in his second form buys a Goliath
set ValidBuy = false
elseif udg_TankMonopoly and (NewTankType!='H006') and AnyAllyHasTankOfType(Owner, NewTankType) then
set s = "|cfffed312Tank Monopoly is enabled and one of your allies already has that tank.|r"
set ValidBuy = false
else
set i = 0
loop
exitwhen i > 5 or not ValidBuy
set SlotItem = UnitItemInSlot(OldTank, i)
if SlotItem!=null then
if (NewTankType == 'H00Y') then
set Id = GetItemTypeId(SlotItem)
if (GetItemType(SlotItem) == ITEM_TYPE_ARTIFACT) or (Id=='I02H' or Id=='I00R' or Id=='I00Q' or Id=='I04S' or Id=='I04U' or Id=='I04T' or Id=='I011' or Id=='I04Q') then
// Invalid Trader Item
set s = "|cfffed312The Trader cannot carry Weapons, Hulls or a Bomb bought at the Goblin Trader.|r"
set ValidBuy = false
endif
endif
endif
set i = i + 1
endloop
endif
if not ValidBuy then
// Display error message and abort
if s!=null then
call DisplayTextToPlayer(Owner, 0, 0, s )
endif
call SetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD) + GetUnitPointValue(NewTank))
call RemoveUnit( NewTank )
set NewTank = null
set OldTank = null
set SlotItem = null
return
endif
// Tank buying was valid
call ChangeTanks(OldTank, NewTank, Shop, false)
set NewTank = null
set OldTank = null
set SlotItem = null
endfunction
//===========================================================================
function InitTrig_Vehicle_Buy takes nothing returns nothing
set gg_trg_Vehicle_Buy = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Vehicle_Buy, EVENT_PLAYER_UNIT_SELL )
call TriggerAddCondition( gg_trg_Vehicle_Buy, Condition( function Trig_Vehicle_Buy_Conditions ) )
call TriggerAddAction( gg_trg_Vehicle_Buy, function Trig_Vehicle_Buy_Actions )
endfunction
//TESH.scrollpos=209
//TESH.alwaysfold=0
scope VehicleDies initializer Init
globals
private constant integer KILL = 1
private constant integer DEATH = 2
private constant integer ASSIST = 3
private constant integer SELFKILL = 4
endglobals
private function Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) and IsPlayerInForce(GetOwningPlayer(GetTriggerUnit()), udg_Players)
endfunction
private function RegisterKDA takes integer playerId, integer stat returns nothing
local integer team = udg_Player_Team[playerId]
if (stat == KILL) then
set udg_Kills[10 + team] = udg_Kills[10 + team] + 1
if (playerId <= GetMaxHumanPlayers()) then
set udg_KillingSpree[playerId] = udg_KillingSpree[playerId] + 1
if (udg_KillingSpree[playerId] > udg_MaxKillStreak[playerId]) then
set udg_MaxKillStreak[playerId] = udg_KillingSpree[playerId]
endif
set udg_AssistSpree[playerId] = 0
set udg_Kills[playerId] = udg_Kills[playerId] + 1
set Kills_StatsProgress[playerId][1] = Kills_StatsProgress[playerId][1] + 1
set udg_KillLast[playerId] = udg_Time_Value
call UpdateBoardKills(playerId)
endif
elseif (stat == DEATH) then
set udg_Deaths[playerId] = udg_Deaths[playerId] + 1
set udg_KillingSpree[playerId] = 0
// StatsProgress is used for the penalty kick system
set Deaths_StatsProgress[playerId][1] = Deaths_StatsProgress[playerId][1] + 1
call UpdateBoardDeaths(playerId)
elseif (stat == ASSIST) then
call MB_SetSupport( playerId, 1.0 )
set udg_Assists[playerId] = udg_Assists[playerId] + 1
set udg_AssistSpree[playerId] = udg_AssistSpree[playerId] + 1
if (udg_AssistSpree[playerId] > udg_MaxAssistStreak[playerId]) then
set udg_MaxAssistStreak[playerId] = udg_AssistSpree[playerId]
endif
elseif (stat == SELFKILL) then
set udg_Selfkills[playerId] = udg_Selfkills[playerId] + 1
// StatsProgress is used for the penalty kick system
set Deaths_StatsProgress[playerId][1] = Deaths_StatsProgress[playerId][1] + 0.5
call UpdateBoardDeaths(playerId)
endif
set udg_StatLast[playerId] = udg_Time_Value
call UpdateTankCosts(playerId)
endfunction
private function Respawn takes boolean FastRespawn returns nothing
local item TempItem
local unit Tank = GetTriggerUnit()
local player Dying = GetOwningPlayer(Tank)
local integer DyingId = GetPlayerNr(Dying)
local integer TeamOfDying = udg_Player_Team[DyingId]
local integer i
local effect InvulEffect
//avoid antigrav
if GetUnitTypeId(Tank) != 'H00X' and GetUnitFlyHeight(Tank) >= 10. then
call SetUnitFlyHeight(Tank,350.,0.)
endif
if IsPlayerInForce(Dying, udg_Players) and udg_Team_Winning == 0 then
set IgnoreSplashToggle = true
//call DebugMsg("Ignore: true (death)")
call DestroyTimerDialog( udg_Tank_TimerWindow[DyingId] )
if FastRespawn then
call ReviveHero( Tank, GetUnitX(Tank), GetUnitY(Tank), true )
call SetUnitState(Tank, UNIT_STATE_LIFE, RMinBJ(300,GetUnitState(Tank,UNIT_STATE_MAX_LIFE)))
call SetUnitState(Tank, UNIT_STATE_MANA, 0.2 * GetUnitState(Tank,UNIT_STATE_MAX_MANA))
else
call ReviveHeroLoc( Tank, udg_Move_Points[TeamOfDying], true )
endif
set udg_Item_Check = false
set i = 0
loop
//the radar stops working after dying, you have to pick the items up again for the radar to work again
exitwhen i > 5
set TempItem = UnitItemInSlot(Tank, i)
if TempItem != null then
if IsRadar(TempItem) then
call SetItemPosition( TempItem, 0, 0 )
call UnitAddItem( Tank, TempItem )
endif
if udg_Afk[DyingId] then
call SetItemDroppable( TempItem, false )
endif
elseif udg_Afk[DyingId] then
call UnitAddItemById( Tank, 'I048' )
endif
set i = i + 1
endloop
call TriggerExecute(gg_trg_Radar)
//items that the tank should have received while he was dead, are now given to him
//e.g. a weapon that has been upgrading while he died
call ReAddTempItems(Tank)
if not IsUnitInStrategicLocation(Tank) then
//Exploder may revive in a strategic location
call EnableStrategicLocationBuff(Tank, false)
endif
call UpdateTankCosts(DyingId) //To fix an issue, with weapons being upgraded and dying in the process
call RefreshTransparency( Tank ) //For Earth Robot, Ghost Tank and banished units
call ApplyManaUpgrade(DyingId) //Makes sure the tank has the correct amount of mana upgrades
set IgnoreSplashToggle = false
//call DebugMsg("Ignore: false (death)")
call ResetSplashCannon(Tank) //Only for Architects
// Guard Tank Debug
call SetPlayerAbilityAvailableBJ(true, 'A0CH', Dying )
if (GetUnitAbilityLevel( Tank,'A0CJ') == 1) then
call UnitAddAbility(Tank,'A0CH')
elseif (GetUnitAbilityLevel( Tank,'A0CJ') >= 2) then
call SetUnitAbilityLevel(Tank,'A0CH',GetUnitAbilityLevel( Tank,'A0CJ'))
endif
if DiedRooted[DyingId-1] then
set DiedRooted[DyingId-1] = false
call SetPlayerAbilityAvailableBJ( true, 'A0CH', GetOwningPlayer(Tank) )
if (GetUnitAbilityLevel(Tank,'A0CJ') > 0) then
call UnitAddAbility(Tank,'A0CH')
if (GetUnitAbilityLevel(Tank,'A0CJ') > 1) then
call SetUnitAbilityLevel(Tank,'A0CH',GetUnitAbilityLevel(Tank,'A0CJ'))
else
call SetUnitAbilityLevel(Tank,'A0CH',1)
endif
endif
endif
call SetPlayerAbilityAvailable(GetOwningPlayer(Tank),'S001',true) // TPBreakerField Passiv Antibug
call UnitRemoveAbility(Tank,'S002') // TPBreakerField Passiv Antibug
set udg_Item_Check = true
//Make sure the level of the dummy tank skill and the actual phoenix fire match
//This does not apply for the Storm Tank ('H025')
if (GetUnitAbilityLevel(Tank, 'A01J') != GetUnitAbilityLevel(Tank, 'A00W')) and (GetUnitTypeId(Tank) != 'H025') then
call UnitAddAbility( Tank, 'A00W' )
call SetUnitAbilityLevel(Tank, 'A00W', GetUnitAbilityLevel(Tank, 'A01J') )
endif
if GetLocalPlayer() == Dying then
call ClearSelection()
call SelectUnit(Tank, true)
endif
if not FastRespawn then
call IssuePointOrderLoc( Tank, "move", udg_Move_Points[2 + TeamOfDying] )
call UpdateBoardTankState(DyingId, true)
if GetLocalPlayer() == Dying and udg_ReviveCamPan then
call PanCameraToTimed(GetUnitX(Tank), GetUnitY(Tank), 1)
endif
endif
set InvulEffect = AddSpecialEffectTarget("Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl", Tank, "origin")
call MakeUnitInvulnerable( Tank, true)
call GameTimeWait(3)
call MakeUnitInvulnerable( Tank, false)
call DestroyEffect(InvulEffect)
set InvulEffect = null
set TankDead[GetPlayerId(Dying)] = false
endif
set Tank = null
set TempItem = null
endfunction
private function ResetMultikill takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = GetHandleIndex(t)
if udg_AV_Int1[i] == udg_Multikill_Count[udg_AV_Int2[i]] then
set udg_Multikill_Count[udg_AV_Int2[i]] = 0
endif
call ReleaseTimer(t)
call ReleaseHandleIndex(i)
endfunction
private function AddAssists takes unit Tank, real ACode, string msgcolor returns string
local integer i = GetMaxHumanPlayers()
local integer DyingId = GetPlayerNr(GetOwningPlayer(Tank))
local string s = ""
local string acolor = ""
if (ACode > 0) then
if (msgcolor == "|cffff0000") then
set acolor = "|cff99bdff"
else
set acolor = "|cff00bdff"
endif
loop
exitwhen i < 1
if (ACode >= Pow(2, i)) then
set ACode = ACode - Pow(2,i)
set s = ", " + udg_Color[i] + I2S(i) + "|r" + s
endif
set i = i - 1
endloop
return " " + acolor + "(Assisted by: " + SubString(s,2,StringLength(s)) + acolor + ")|r"
endif
return ""
endfunction
private function Death takes unit Tank, player Killer returns nothing
local player Dying = GetOwningPlayer(Tank)
local integer KillerId = GetPlayerNr(Killer)
local integer DyingId = GetPlayerNr(Dying)
local integer TeamOfKiller = udg_Player_Team[KillerId]
local integer TeamOfDying = udg_Player_Team[DyingId]
local integer MultikillCount = 0
local integer Gold = 0
local integer HunterGold = 0
local integer AssistCount = 0
local integer AssistGold = 0
local integer i
local real AssistCode = 0
local real RespawnTime = GetRespawnTime(Tank, true)
local string MultikillAttachment
local string Text
local string Color
local group G
local unit temp
local timer t
local item SlotItem
// In Royal Flush Mode, you also lose money, which is done here
if ( udg_GameMode == 2 ) then
call SetPlayerState(Dying, PLAYER_STATE_RESOURCE_GOLD, IMaxBJ(GetPlayerState(Dying, PLAYER_STATE_RESOURCE_GOLD) - R2I(GetBounty(Tank , true)/2), 0))
call ShowTextTag("|cfffed312-" + I2S(R2I(GetBounty(Tank , true)/2)) + "|r" , Tank , 0 , 0 , Dying)
endif
// Calculate how much gold you get for the kill and for the assists
if IsPlayerEnemy(Dying, Killer) or (Dying == Killer) then
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if ((TimerGetElapsed(udg_GameTime) - Damaged[10 * i + DyingId]) < 5) then
if (i != KillerId) and IsPlayerEnemy(Dying, GetPlayer(i)) then
set AssistCount = AssistCount + 1
set AssistCode = AssistCode + Pow(2, i)
call RegisterKDA(i, ASSIST)
endif
endif
set i = i + 1
endloop
if (AssistCount > 0) then
//1 Assist = 25% Killgold
//4 Assists = 50% / 4 Killgold (everyone gets 12,5%)
//the assist gold each individual player gets
set AssistGold = R2I((1.5*GetBounty(Tank, true) / (7 - AssistCount)) / AssistCount)
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if ((TimerGetElapsed(udg_GameTime) - Damaged[10 * i + DyingId]) < 7.5) then
if (i != KillerId) and IsPlayerEnemy(Dying, GetPlayer(i)) then
set HunterGold = R2I(AssistGold + (GetBounty(Tank, true) * GetAssistBonus(i)))
call ShowTextTag("|cfffed312+"+I2S(HunterGold)+"|r", udg_Tank[i], 0, 0, GetPlayer(i))
call SetPlayerState(GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD) + HunterGold)
call SetPlayerState(GetPlayer(i), PLAYER_STATE_GOLD_GATHERED, GetPlayerState(GetPlayer(i), PLAYER_STATE_GOLD_GATHERED) + HunterGold)
set udg_Profit_Tanks[i] = udg_Profit_Tanks[i] + HunterGold
call AddHeroXP( udg_Tank[i], R2I(HunterGold / 3.5), false )
call UpdateBounty(GetPlayer(i), HunterGold)
if (udg_AssistSpree[i] >= 3) then
//call ShowTextTag("|cff00bdff+"+I2S(udg_AssistSpree[i])+" assists in a row!|r", udg_Tank[i], 0, -100, null)
call ShowTextTag(udg_Color[i] + "Assist Spree:|r " +I2S(udg_AssistSpree[i]), udg_Tank[i], 0, -100, null)
endif
endif
endif
set i = i + 1
endloop
endif
call DestroyEffect(AddSpecialEffectTarget("UI\\Feedback\\GoldCredit\\GoldCredit.mdl", Tank, "origin"))
if (Dying != Killer) then
//A0AH = Bounty Hunter
set Gold = R2I(GetBounty(Tank, true) * GetBountyBonus(KillerId))
set HunterGold = R2I( Gold * 0.04 * GetUnitAbilityLevel(udg_Tank[KillerId], 'A0AH') )
if IsPlayerInForce(Killer, udg_Players) then
call ShowTextTag("|cfffed312+"+I2S(Gold)+"|r", Tank, 0, 0, Killer)
if ( HunterGold != 0 ) then
call ShowTextTag("|cfffe960a+"+I2S(HunterGold)+"|r", Tank, 100, 0, Killer)
endif
endif
set Gold = Gold + HunterGold
call SetPlayerState(Killer, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Killer, PLAYER_STATE_RESOURCE_GOLD) + Gold)
call SetPlayerState(Killer, PLAYER_STATE_GOLD_GATHERED, GetPlayerState(Killer, PLAYER_STATE_GOLD_GATHERED) + Gold)
set udg_Profit_Tanks[KillerId] = udg_Profit_Tanks[KillerId] + Gold
set TankBounty[KillerId]=TankBounty[KillerId]+Gold
if (Gold > 0) then
call RegisterKDA(KillerId, KILL)
endif
if (udg_KillingSpree[KillerId] >= 3) then
//call ShowTextTag("|cff00ff00+"+I2S(udg_KillingSpree[KillerId])+" kills in a row!|r", udg_Tank[KillerId], 0, -100, null)
call ShowTextTag(udg_Color[KillerId] + "Kill Spree:|r " +I2S(udg_KillingSpree[KillerId]), udg_Tank[KillerId], 0, -100, null)
endif
endif
endif
// Increase the bounty of the killing tank (only has effect, when the alternate bounty is active)
call UpdateBounty(Killer, Gold)
// and reduce the bounty of the dying tank
if IsPlayerEnemy(Killer, Dying) then
call UpdateBounty(Dying, -GetBounty(Tank, true))
endif
//Trader loses all of his trade items and gets the paid wood back
set i = 0
loop
exitwhen i > 5
set SlotItem = UnitItemInSlot(Tank, i)
if GetItemType(SlotItem) == ITEM_TYPE_CHARGED then
call SetPlayerState(Dying, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(Dying, PLAYER_STATE_RESOURCE_LUMBER) + GetItemCharges(SlotItem) * 10)
call RemoveItem( SlotItem )
endif
set i = i + 1
endloop
set SlotItem = null
// Start the respawn timer and show the Timer window for the respawn
if udg_Team_Winning == 0 then
call TimerStart( udg_Tank_Timer[DyingId], RespawnTime, false, null )
set udg_Tank_TimerWindow[DyingId] = CreateTimerDialog(udg_Tank_Timer[DyingId])
call TimerDialogSetTitle(udg_Tank_TimerWindow[DyingId], GetPlayerName(Dying))
call TimerDialogSetTitleColor(udg_Tank_TimerWindow[DyingId], udg_Color_Red[DyingId], udg_Color_Green[DyingId], udg_Color_Blue[DyingId], 255)
call TimerDialogDisplay(udg_Tank_TimerWindow[DyingId], true)
endif
// Display the kill message
if Gold!=0 then
if GetLocalPlayer() == Killer then
set Color = "|cff00ff00"
set Text = Color + "You have killed|r " + udg_Color[DyingId] + GetPlayerName(Dying) + "|r" + Color + " for|r " + I2S(Gold) + Color + " Gold!"
elseif GetLocalPlayer() == Dying then
set Color = "|cffff0000"
set Text = udg_Color[KillerId] + GetPlayerName(Killer) + "|r" + Color + " has killed you for|r " + I2S(Gold) + Color + " Gold!"
elseif IsPlayerAlly(GetLocalPlayer(), Dying) then
set Color = "|cffff0000"
set Text = udg_Color[KillerId] + GetPlayerName(Killer) + "|r" + Color + " has killed|r " + udg_Color[DyingId] + GetPlayerName(Dying) + "|r" + Color + " for|r " + I2S(Gold) + Color + " Gold!"
else
set Color = "|cff00ff00"
set Text = udg_Color[KillerId] + GetPlayerName(Killer) + "|r" + Color + " has killed|r " + udg_Color[DyingId] + GetPlayerName(Dying) + "|r" + Color + " for|r " + I2S(Gold) + Color + " Gold!"
endif
set Text = Text + AddAssists(Tank, AssistCode, Color)
elseif Killer == Dying then
//set GotTeamkilled[DyingId] = GotTeamkilled[DyingId] + 1
if GetLocalPlayer() == Killer then
set Color = "|cffff0000"
set Text = Color + "You have killed yourself!"
elseif IsPlayerAlly(GetLocalPlayer(), Dying) then
set Color = "|cffff0000"
set Text = udg_Color[KillerId] + GetPlayerName(Killer) + "|r" + Color + " has killed himself!"
else
set Color = "|cff00ff00"
set Text = udg_Color[KillerId] + GetPlayerName(Killer) + "|r" + Color + " has killed himself!"
endif
set Text = Text + AddAssists(Tank, AssistCode, Color)
else
if GetLocalPlayer() == Killer then
set Color = "|cffff0000"
set Text = Color + "You have teamkilled|r " + udg_Color[DyingId] + GetPlayerName(Dying) + "|r" + Color + "!"
elseif GetLocalPlayer() == Dying then
set Color = "|cffff0000"
set Text = udg_Color[KillerId] + GetPlayerName(Killer) + "|r" + Color + " has teamkilled you!"
elseif IsPlayerAlly(GetLocalPlayer(), Dying) then
set Color = "|cffff0000"
set Text = udg_Color[KillerId] + GetPlayerName(Killer) + "|r" + Color + " has teamkilled|r " + udg_Color[DyingId] + GetPlayerName(Dying) + "|r" + Color + "!"
else
set Color = "|cff00ff00"
set Text = udg_Color[KillerId] + GetPlayerName(Killer) + "|r" + Color + " has teamkilled|r " + udg_Color[DyingId] + GetPlayerName(Dying) + "|r" + Color + "!"
endif
set GotTeamkilled[DyingId] = GotTeamkilled[DyingId] + 1
set DidTeamkill[KillerId] = DidTeamkill[KillerId] + 1
if (ModuloInteger(DidTeamkill[KillerId], TEAMKILL_COUNT) == 0) then
call AddPlayerPenalty(KillerId, PENALTY_MESSAGE_TEAMKILL)
endif
endif
// Check for multikills, and add addional gold if necessary
if Gold!=0 then
set MultikillCount = udg_Multikill_Count[KillerId] + 1
set udg_Multikill_Count[KillerId] = MultikillCount
if Multikill[GetPlayerId(Killer)] < MultikillCount then
set Multikill[GetPlayerId(Killer)] = MultikillCount
endif
if MultikillCount == 2 then
set MultikillAttachment = "Doublekill +1 Spree"
call StartSound( udg_Multikill_Sounds[GetRandomInt(1, 4)] )
elseif MultikillCount == 3 then
set MultikillAttachment = "Triplekill +1 Spree"
call StartSound( udg_Multikill_Sounds[GetRandomInt(5, 8)] )
elseif MultikillCount == 4 then
set MultikillAttachment = "Multikill +1 Spree"
call StartSound( udg_Multikill_Sounds[GetRandomInt(9, 11)] )
elseif MultikillCount >= 5 then
set MultikillAttachment = "Godlike +1 Spree"
call StartSound( udg_Multikill_Sounds[12] )
else
set MultikillAttachment = ""
endif
if MultikillAttachment != "" then
set Text = Text + " (|r" + MultikillAttachment + Color + ")"
set LeagueMKCounter[GetPlayerId(Killer)] = LeagueMKCounter[GetPlayerId(Killer)] + 1
set udg_KillingSpree[KillerId] = udg_KillingSpree[KillerId] + 1
endif
set t = NewTimer()
set i = NewTimerIndex(t)
set udg_AV_Int1[i] = MultikillCount
set udg_AV_Int2[i] = KillerId
call TimerStart(t, 6, false, function ResetMultikill)
endif
// Display the kill message
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, Text + "|r")
if (DyingId != KillerId) then
call RegisterKDA(DyingId, DEATH)
else
call RegisterKDA(DyingId, SELFKILL)
endif
set udg_Time_Dead[DyingId] = udg_Time_Dead[DyingId] + RespawnTime
call StorePlayerVars(GetPlayerId(Dying))
if (GetUnitTypeId(Tank) == 'H013') then
set DiedRooted[GetPlayerId(Dying)] = true
endif
set TankDead[GetPlayerId(Dying)] = true
// Here comes the penalty increase for the death
// But if the tank died near a CP, it is assumed he defended it, so no penalty will be given
set G = NewGroup()
call GroupEnumUnitsInRange(G, GetUnitX(Tank), GetUnitY(Tank), 500, FILTER_CP)
set temp = FirstOfGroup(G)
if (temp != null and IsUnitAlly(temp, Dying) and (GetUnitAbilityLevel(temp, CPTP_DISABLE_ABILITY_ID) > 0)) then
// the tank died defending a CP, so don't give him a penalty
else
//The penalty that influences the kick command
//call IncreasePenalty(Tank, RespawnTime)
call IncreasePenalty(Tank)
endif
call ReleaseGroup(G)
// Wait until the respawn time is over and start the respawn
loop
set RespawnTime=TimerGetRemaining(udg_Tank_Timer[DyingId])
exitwhen RespawnTime <= 0
call TriggerSleepAction(RespawnTime * 0.2)
endloop
call Respawn(false)
set G = null
set temp = null
set Tank = null
endfunction
private function Actions takes nothing returns nothing
local timer t
local integer i
local unit Tank = GetTriggerUnit()
local player Killer = GetOwningPlayer(GetKillingUnit())
local integer PlayerId = GetPlayerNr(GetOwningPlayer(Tank))
local integer level = GetUnitAbilityLevel(Tank,RECONSTRUCTION_ABILITY_ID)
local texttag ReconstructionTag
call UnitBlowUpExplosives(Tank, Tank, true)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Volcano\\VolcanoDeath.mdl", Tank, "origin"))
call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", Tank, "origin"))
call Tank_Attached_Fire_Change(PlayerId-1, 0)
if udg_Reconstruction_Ready[PlayerId] and GetRandomReal(0.0, 1.0) <= (RECONSTRUCTION_CHANCE_BASE + (RECONSTRUCTION_CHANCE_UP * level)) then
set udg_Reconstruction_Ready[PlayerId] = false
call ShowTextTag("|cffff0000Reconstruction!|r", Tank, 0, 0, null)
call GameTimeWait(3)
call Respawn(true)
call GameTimeWait(7)
set udg_Reconstruction_Ready[PlayerId] = true
else
call Death(Tank, Killer)
endif
set Tank = null
endfunction
private function Init takes nothing returns nothing
local integer i = 0
local trigger t = CreateTrigger()
loop
exitwhen i >= GetMaxHumanPlayers()
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_DEATH,pNull)
set i = i + 1
endloop
call TriggerAddCondition(t, Condition( function Conditions ) )
call TriggerAddAction(t, function Actions )
endfunction
endscope
//TESH.scrollpos=4
//TESH.alwaysfold=0
function Trig_Weapon_Range_Conditions takes nothing returns boolean
return udg_Show_WeaponRange_Mode > 0
endfunction
function Trig_Weapon_Range_Actions takes nothing returns nothing
local integer i = 1
local integer playerId = GetPlayerNr(udg_GameMode_Host)
local real PosX
local real PosY
local real X
local real Y
if GetUnitState(udg_Tank[playerId], UNIT_STATE_LIFE) > 0 then
set PosX = GetUnitX(udg_Tank[playerId])
set PosY = GetUnitY(udg_Tank[playerId])
loop
exitwhen i > 72
set X = PosX + udg_Show_WeaponRange * Cos(i*5 * bj_DEGTORAD)
set Y = PosY + udg_Show_WeaponRange * Sin(i* 5 * bj_DEGTORAD)
call SetTextTagPos(udg_Show_WeaponRange_Text[i], X, Y, 50)
set i = i + 1
endloop
endif
endfunction
//===========================================================================
function InitTrig_Weapon_Range takes nothing returns nothing
set gg_trg_Weapon_Range = CreateTrigger( )
call DisableTrigger( gg_trg_Weapon_Range )
call TriggerRegisterTimerEventPeriodic( gg_trg_Weapon_Range, 0.05 )
call TriggerAddCondition( gg_trg_Weapon_Range, Condition( function Trig_Weapon_Range_Conditions ) )
call TriggerAddAction( gg_trg_Weapon_Range, function Trig_Weapon_Range_Actions )
endfunction
//TESH.scrollpos=64
//TESH.alwaysfold=0
function Trig_XP_and_Bounty_IsNearbyHero takes nothing returns boolean
local unit U = GetFilterUnit()
if IsUnitType(U, UNIT_TYPE_HERO) and IsUnitEnemy(U, GetOwningPlayer(GetTriggerUnit())) then
if GetUnitState(U, UNIT_STATE_LIFE) > 0 or U==udg_Tank[GetPlayerNr(GetOwningPlayer(GetKillingUnit()))] then
set U = null
set bj_groupCountUnits = bj_groupCountUnits + 1
return true
endif
endif
set U = null
return false
endfunction
globals
boolexpr FILTER_NEARBY_HERO
endglobals
function Trig_XP_and_Bounty_Actions takes nothing returns nothing
local unit U = GetKillingUnit()
local unit DyingUnit = GetTriggerUnit()
local integer XP
local integer Gold = 0
local player Killer
local group G
if U != null then
set Killer = GetOwningPlayer(U)
if IsUnitType(DyingUnit, UNIT_TYPE_HERO) then
set XP = R2I(GetBounty(DyingUnit, true)/3.5)
else
if ( IsPacifista(DyingUnit) ) then
set Gold=R2I(GetBounty(udg_Tank[GetPlayerNr(GetOwningPlayer(DyingUnit))] , true) / 3)
else
set Gold=R2I(GetUnitPointValue(DyingUnit) * GetBountyFactor())
endif
//XP for killed buildings and creeps
set XP=( Gold / 4 )
endif
call UpdateBounty(GetOwningPlayer(U), Gold)
set U = null
if not IsUnitAlly(DyingUnit, Killer) then
if Gold!=0 then
call DestroyEffect(AddSpecialEffectTarget("UI\\Feedback\\GoldCredit\\GoldCredit.mdl", DyingUnit, "origin"))
call SetPlayerState(Killer, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Killer, PLAYER_STATE_RESOURCE_GOLD) + Gold)
call SetPlayerState(Killer, PLAYER_STATE_GOLD_GATHERED, GetPlayerState(Killer, PLAYER_STATE_GOLD_GATHERED) + Gold)
set udg_Profit_Creeps[GetPlayerNr(Killer)] = udg_Profit_Creeps[GetPlayerNr(Killer)] + Gold
set udg_DamageLast[GetPlayerNr(Killer)] = udg_Time_Value
if IsPlayerInForce(Killer, udg_Players) then
call ShowTextTag("|cfffed312+"+I2S(Gold)+"|r", DyingUnit, 0, 0, Killer)
set U = udg_Tank[GetPlayerNr(Killer)]
endif
elseif IsPlayerInForce(Killer, udg_Players) then
set U = udg_Tank[GetPlayerNr(Killer)]
endif
endif
if IsUnitType(DyingUnit, UNIT_TYPE_STRUCTURE) or IsUnitType(DyingUnit, UNIT_TYPE_HERO) then
set bj_groupCountUnits = 0
// Count nearby heroes
set G = NewGroup()
call GroupEnumUnitsInRange(G, GetUnitX(DyingUnit),GetUnitY(DyingUnit), 1500, FILTER_NEARBY_HERO)
//call DebugMsg("[" + I2S(GetPlayerNr(Killer)) + "] XP: " + I2S(R2I(XP)))
if (U != null) and IsUnitType(U, UNIT_TYPE_HERO) then
if (GetUnitState(U, UNIT_STATE_LIFE) <= 0) then
call AddHeroXP( U, R2I(XP/2.0), false )
else
call AddHeroXP( U, XP, false )
endif
endif
if bj_groupCountUnits > 0 then
// Divide XP
set XP = XP / bj_groupCountUnits
loop
set U = FirstOfGroup( G )
exitwhen U == null
call AddHeroXP( U, XP, false )
call GroupRemoveUnit( G, U )
endloop
endif
call ReleaseGroup(G)
set G = null
elseif U != null then
// Add XP to the owner's tank
set XP = GetUnitLevel(DyingUnit)
if XP == 1 then
call AddHeroXP( U, 3, GetUnitState(U, UNIT_STATE_LIFE) > 0 )
elseif XP == 2 then
call AddHeroXP( U, 6, GetUnitState(U, UNIT_STATE_LIFE) > 0 )
elseif XP == 3 then
call AddHeroXP( U, 12, GetUnitState(U, UNIT_STATE_LIFE) > 0 )
endif
endif
endif
set DyingUnit = null
set U = null
endfunction
//===========================================================================
function InitTrig_XP_and_Bounty takes nothing returns nothing
set gg_trg_XP_and_Bounty = CreateTrigger( )
set FILTER_NEARBY_HERO = Filter( function Trig_XP_and_Bounty_IsNearbyHero )
call TriggerRegisterAnyUnitEventBJ( gg_trg_XP_and_Bounty, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( gg_trg_XP_and_Bounty, function Trig_XP_and_Bounty_Actions )
endfunction
//TESH.scrollpos=18
//TESH.alwaysfold=0
library WeaponInitUpdate initializer WeaponSystemInit requires WeaponHolderFunctions
// This library contains function, that handle the custom phoenixfire weapon system
// It features a projectile system and adjustable effects when the weapon hits
// -- Use these functions for adding and removing these custom weapon skills --
// When you add new skills, specify their parameters in the 'Weapon Holder' trigger
// This function makes sure, that the owner parameter is correctly set
function UpdateTank takes unit tank, integer playerId, integer weaponNr returns nothing
local integer i = 1
//set WTank[playerId].Holder = tank
set WeaponHolder[playerId].Weapons[weaponNr].Owner = tank
endfunction
// Since all weapons are declared as Artifacts, only register the trigger for those items
function Item_Conditions takes nothing returns boolean
local itemtype Type = GetItemType(GetManipulatedItem())
return Type == ITEM_TYPE_ARTIFACT
endfunction
// Add the skill, after you picked the dummy weapon item up
function PickWeapon_Actions takes nothing returns nothing
local item Weapon = GetManipulatedItem()
local integer playerNr = GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))
//call DebugMsg("Weapon picked up: " + GetItemName(Weapon) + " (by: " + I2S(playerNr) + ")")
call UpdateTank(GetTriggerUnit(), playerNr, WeaponHolder[playerNr].AddWeapon(Weapon))
set Weapon = null
endfunction
// Remove the skill, after you dropped the dummy weapon item
function DropWeapon_Actions takes nothing returns nothing
local item Weapon = GetManipulatedItem()
local integer playerNr = GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))
//call DebugMsg("Weapon dropped: " + GetItemName(Weapon))
call WeaponHolder[playerNr].RemoveWeapon(Weapon)
set Weapon = null
endfunction
// Remove all weapons
function RemoveAllWeapons takes unit tank returns nothing
local integer playerNr = GetPlayerNr(GetOwningPlayer(tank))
call WeaponHolder[playerNr].RemoveAllWeapons()
endfunction
// Remove the weapon skill manually
function RemoveWeapon takes unit tank, integer weaponId returns nothing
local integer playerNr = GetPlayerNr(GetOwningPlayer(tank))
call WeaponHolder[playerNr].RemoveWeaponById(weaponId)
endfunction
// This is only used by AddWeaponTimed and removes the skill and releases the timer
function TimerRemoveWeapon takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
call WeaponHolder[udg_AV_Int1[LoopTimerId]].RemoveWeaponById(udg_AV_Int2[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endfunction
// Adds a weapon skill for the specified time, if the time is 0, you keep the skill permanently
function AddWeaponTimed takes unit tank, integer weaponId, real time returns nothing
local integer playerNr = GetPlayerNr(GetOwningPlayer(tank))
local timer t
local integer LoopTimerId
call UpdateTank(tank, playerNr, WeaponHolder[playerNr].AddWeaponById(weaponId))
if (time > 0) then
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Int1[LoopTimerId] = playerNr
set udg_AV_Int2[LoopTimerId] = weaponId
call TimerStart(t , time , false , function TimerRemoveWeapon)
endif
endfunction
// Check if the tank has the specified weapon skill (should not be used for item based weapon skills)
function HasWeapon takes unit tank, integer weaponId returns boolean
local integer playerNr = GetPlayerNr(GetOwningPlayer(tank))
return WeaponHolder[playerNr].HasWeaponById(weaponId)
endfunction
function WeaponSystemInit takes nothing returns nothing
local integer i = 1
local trigger PickWeapon = CreateTrigger()
local trigger DropWeapon = CreateTrigger()
loop
exitwhen i > GetMaxPlayers()
//this is how not to do it
if (i == 11) then
// since the forces don't have tanks, the HQs are registered as weapon holders
// the good way would be to use the udg_HQ variable
// but as it happens, the variable is not yet intialized at this point
call WeaponHolder[i].create(gg_unit_h004_0013, i)
elseif (i == 12) then
call WeaponHolder[i].create(gg_unit_h004_0032, i)
else
call WeaponHolder[i].create(udg_Tank[i], i)
endif
set i = i + 1
endloop
call TriggerRegisterAnyUnitEventBJ( PickWeapon, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerRegisterAnyUnitEventBJ( DropWeapon, EVENT_PLAYER_UNIT_DROP_ITEM )
call TriggerAddCondition(PickWeapon, Condition(function Item_Conditions))
call TriggerAddCondition(DropWeapon, Condition(function Item_Conditions))
call TriggerAddAction(PickWeapon, function PickWeapon_Actions)
call TriggerAddAction(DropWeapon, function DropWeapon_Actions)
endfunction
endlibrary
//TESH.scrollpos=492
//TESH.alwaysfold=0
library WeaponHolderFunctions requires MapAttachedSettings
globals
constant integer MaxWeaponItems = 12 // 6 slots are for the 6 weapons you can carry, the additional 6 are for temporarily deactivated weapons
constant integer MaxWeaponAbilities = 40 // The number 40 has been chosen arbitrarily and can be altered if needed
// but keep in mind, that the MaxWeaponItems are also included (i.e: 40 - 12 -> 28 usable weapon abilities)
constant integer TARGET_EFFECT_DAMAGE = 1
constant integer TARGET_EFFECT_SPLASH = 2
constant integer TARGET_EFFECT_DAMAGE_SLOW = 3
constant integer TARGET_EFFECT_LONG_RANGE = 4
endglobals
// Normal target restrictions (Attack Air, Ground, Enemy)
function AttackNormal takes nothing returns boolean
local unit U = GetFilterUnit()
//TempInt has to be set in the calling function, so this function works properly!
if ( IsUnitAlly(U, udg_Filter_Player) ) or GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
set U = null
return false
endif
// Wards and units under the protection of Support Systems (Medivac) are not valid targets
if IsWard(U) or (GetUnitAbilityLevel(U, 'B00N') > 0) then
set U = null
return false
endif
// Is Invulnerable or Invisible?
if (GetUnitState(U, UNIT_STATE_LIFE) >= 500000) or (IsUnitInvisible(U, udg_Filter_Player) ) or (GetUnitAbilityLevel(U, 'Avul') > 0) then
set U = null
return false
endif
set U = null
return true
endfunction
function AttackAllies takes nothing returns boolean
local unit U = GetFilterUnit()
//udg_Filter_Player has to be set in the calling function, so this function works properly!
if (U == udg_Tank[GetPlayerNr(udg_Filter_Player)]) then
set U = null
return false
endif
if ( IsUnitEnemy(U, udg_Filter_Player) ) or GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
set U = null
return false
endif
// Wards and units under the protection of Support Systems (Medivac) are not valid targets
if IsWard(U) or (GetUnitAbilityLevel(U, 'B00N') > 0) then
set U = null
return false
endif
// Is Invulnerable or Invisible?
if (GetUnitState(U, UNIT_STATE_LIFE) >= 500000) or (IsUnitInvisible(U, udg_Filter_Player) ) or (GetUnitAbilityLevel(U, 'Avul') > 0) then
set U = null
return false
endif
set U = null
return true
endfunction
// A struct that extends an array, cannot contain arrays itself, so a dynamic array has to be declared
type WeaponArray extends WeaponCore array[MaxWeaponAbilities]
// This struct includes all functions that are related to the unit, that is using the weapon skills
struct WeaponHolder extends array
real DamageMod
real CooldownMod
real RangeMod
unit Holder
integer PlayerNr
WeaponArray Weapons
private static integer instanceCount = 0
private static thistype recycle = 0
private thistype recycleNext
static method create takes unit holder, integer playerNr returns thistype
local thistype this
//first check to see if there are any structs waiting to be recycled
if (recycle == 0) then
//if recycle is 0, there are no structs, so increase instance count
set instanceCount = instanceCount + 1
set this = instanceCount
else
//a struct is waiting to be recycled, so use it
set this = recycle
set recycle = recycle.recycleNext
endif
//perform creation code
set this.Holder = holder
set this.PlayerNr = playerNr
set this.Weapons = WeaponArray.create()
return this
endmethod
method destroy takes nothing returns nothing
//add to recycle stack
set recycleNext = recycle
set recycle = this
endmethod
// +++++++++++++++++++++++++++++++++++++++++++
// --------- item based functions ------------
// +++++++++++++++++++++++++++++++++++++++++++
method AddWeapon takes item weapon returns integer
local integer weaponId = GetItemTypeId(weapon)
local real damage = 0
local real cooldown
local real range
local real mana
local integer projectiles
local real hitchance
local real projectileSpeed
local real projectileArc
local real projectileSize
local string pEffect = ""
local code filter
local integer targetEffect
local boolean targetFollow
local WeaponCore core
local integer i = 1
// Bombarding Rockets
if (weaponId == 'I05W') then
set damage = 154
set cooldown = 1.5
set range = 1300
set mana = 0
set projectiles = 1
set hitchance = 100
set projectileSpeed = 1300
set projectileArc = 0.25
set projectileSize = 1.0
set targetFollow = true
set pEffect = "Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_LONG_RANGE
endif
// Bombarding Rockets (Upgrade)
if (weaponId == 'I05X') then
set damage = 192
set cooldown = 1.5
set range = 1300
set mana = 0
set projectiles = 1
set hitchance = 100
set projectileSpeed = 1300
set projectileArc = 0.25
set projectileSize = 1.0
set targetFollow = true
set pEffect = "Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_LONG_RANGE
endif
// Energy Torpedo
if (weaponId == 'I05Y') then
set damage = 478
set cooldown = 3.33
set range = 1300
set mana = 0
set projectiles = 1
set hitchance = 100
set projectileSpeed = 1500
set projectileArc = 0.0
set projectileSize = 1.0
set targetFollow = true
set pEffect = "Abilities\\Spells\\Undead\\DarkSummoning\\DarkSummonMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_LONG_RANGE
endif
// Energy Torpedo (Upgrade)
if (weaponId == 'I05Z') then
set damage = 650
set cooldown = 3.33
set range = 1300
set mana = 0
set projectiles = 1
set hitchance = 100
set projectileSpeed = 1500
set projectileArc = 0.0
set projectileSize = 1.0
set targetFollow = true
set pEffect = "Abilities\\Spells\\Undead\\DarkSummoning\\DarkSummonMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_LONG_RANGE
endif
// Rocket Hail
if (weaponId == 'I060') then
set damage = 154
set cooldown = 1.5
set range = 1300
set mana = 0
set projectiles = 3
set hitchance = 100
set projectileSpeed = 1300
set projectileArc = 0.25
set projectileSize = 1.0
set targetFollow = true
set pEffect = "Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_LONG_RANGE
endif
// Rocket Hail (Upgrade)
if (weaponId == 'I061') then
set damage = 154
set cooldown = 1.5
set range = 1300
set mana = 0
set projectiles = 4
set hitchance = 100
set projectileSpeed = 1300
set projectileArc = 0.25
set projectileSize = 1.0
set targetFollow = true
set pEffect = "Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_LONG_RANGE
endif
// Acid Cannon
if (weaponId == 'I062') then
set damage = 923
set cooldown = 1.5
set range = 1300
set mana = 0
set projectiles = 1
set hitchance = 100
set projectileSpeed = 1500
set projectileArc = 0.0
set projectileSize = 1.0
set targetFollow = true
set pEffect = "Abilities\\Weapons\\ChimaeraAcidMissile\\ChimaeraAcidMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_LONG_RANGE
endif
// Acid Cannon (Upgrade)
if (weaponId == 'I063') then
set damage = 923
set cooldown = 1.05
set range = 1300
set mana = 0
set projectiles = 1
set hitchance = 100
set projectileSpeed = 1500
set projectileArc = 0.0
set projectileSize = 1.0
set targetFollow = true
set pEffect = "Abilities\\Weapons\\ChimaeraAcidMissile\\ChimaeraAcidMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_LONG_RANGE
endif
if (damage != 0) then
//call DebugMsg("Added weapon " + GetItemName(weapon))
loop
exitwhen i > MaxWeaponItems
// Create and save the weapon in a free slot
if (this.Weapons[i] == 0) or ((this.Weapons[i].IsActive == false) and (this.Weapons[i].IsReleasing == false)) then
// Normally all parameters should be given to the create function, but I thought they are kinda too much
// So I seperated them between the create and activate function in no particular order, just the less important ones in the Activate function
set this.Weapons[i] = WeaponCore.create(weapon, weaponId, damage, cooldown, range, projectiles, hitchance, mana, this.Holder, targetFollow)
call this.Weapons[i].ActivateWeapon(pEffect, projectileSpeed, projectileArc, projectileSize, filter, targetEffect, i)
call DebugMsg("Add weapon on " + I2S(i) + " for " + GetName(this.Holder) + " (" + (I2S(GetPlayerNr(GetOwningPlayer(this.Holder))) + ")"))
return i
else
if (this.Weapons[i].IsActive) then
call DebugMsg("Weapon " + I2S(i) + " is active")
endif
if (this.Weapons[i].IsReleasing) then
call DebugMsg("Weapon " + I2S(i) + " is releasing")
endif
set i = i + 1
endif
endloop
endif
return 0
endmethod
method HasWeapon takes item weapon returns boolean
local integer i = 1
loop
exitwhen i > MaxWeaponItems
if (this.Weapons[i].Weapon == weapon) and (this.Weapons[i].IsActive and (this.Weapons[i].IsReleasing == false)) then
return true
endif
set i = i + 1
endloop
return false
endmethod
method RemoveWeapon takes item weapon returns nothing
local integer i = 1
loop
exitwhen i > MaxWeaponItems
if (this.Weapons[i].Weapon == weapon) and (this.Weapons[i].IsActive and (this.Weapons[i].IsReleasing == false)) then
call DebugMsg("Remove " + GetItemName(weapon) + " " + I2S(i))
call this.Weapons[i].DeactivateWeapon(GetPlayerNr(GetOwningPlayer(this.Holder)), i)
return
endif
set i = i + 1
endloop
//call DebugMsg("RemoveWeapon: Not Found (" + GetItemName(weapon) + ")")
endmethod
//For debugging purpose
method PrintWeapons takes string s returns nothing
local integer i = 1
call BJDebugMsg(s)
loop
exitwhen i > MaxWeaponAbilities
if (this.Weapons[i].IsActive) then
call BJDebugMsg("Weapon " + I2S(i) + " of " + GetName(this.Weapons[i].Owner) + ": " + SubString(Weapons[i].Effect, 18, StringLength(Weapons[i].Effect)))
endif
set i = i + 1
endloop
endmethod
// +++++++++++++++++++++++++++++++++++++++++++++++++++
// --------- Id (ability) based functions ------------
// +++++++++++++++++++++++++++++++++++++++++++++++++++
method AddWeaponById takes integer weaponId returns integer
local real damage = 0
local real cooldown
local real range
local real mana
local integer projectiles
local real hitchance
local real projectileSpeed
local real projectileArc
local real projectileSize
local string pEffect = ""
local code filter
local integer targetEffect
local boolean targetFollow
local WeaponCore core
local integer i = MaxWeaponItems+1 // Only the slots after the item weapons are of interest
local integer level
// Architect tank cannon skill
if (weaponId == 'W001') or (weaponId == 'W002') or (weaponId == 'W003') or (weaponId == 'W004') or (weaponId == 'W005') then
set level = weaponId - 'W005' + 5
//call DebugMsg("Level: " + I2S(level))
set damage = 80 * level
set cooldown = 1.5
set range = 950
set mana = level * 0.8
set projectiles = 1
set hitchance = 100
set projectileSpeed = 700
set projectileArc = 0.5
set projectileSize = 2.0
set targetFollow = true
set pEffect = "Abilities\\Weapons\\WaterElementalMissile\\WaterElementalMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_SPLASH
endif
// Architect Modular Weapon skill
if (weaponId == 'W021') or (weaponId == 'W022') or (weaponId == 'W023') or (weaponId == 'W024') or (weaponId == 'W025') then
set level = weaponId - 'W025' + 5
//call DebugMsg("Level: " + I2S(level))
set damage = 80 * level
set cooldown = 1.0
set range = 900
set mana = 0
set projectiles = 1
set hitchance = 75
set projectileSpeed = 1000
set projectileArc = 0.25
set projectileSize = 2.0
set targetFollow = true
set pEffect = "Abilities\\Weapons\\WingedSerpentMissile\\WingedSerpentMissile.mdl"
set filter = function AttackNormal
set targetEffect = TARGET_EFFECT_DAMAGE
endif
if (damage != 0) then
loop
exitwhen i > MaxWeaponAbilities
// Create and save the weapon in a free slot
if (this.Weapons[i] == 0) or ((this.Weapons[i].IsActive == false) and (this.Weapons[i].IsReleasing == false)) then
// Normally all parameters should be given to the create function, but I thought they are kinda too much
// So I seperated them between the create and activate function in no particular order, just the less important ones in the Activate function
set this.Weapons[i] = WeaponCore.createById(weaponId, damage, cooldown, range, projectiles, hitchance, mana, this.Holder, targetFollow)
call this.Weapons[i].ActivateWeapon(pEffect, projectileSpeed, projectileArc, projectileSize, filter, targetEffect, i)
call DebugMsg("Add weapon on " + I2S(i))
return i
else
set i = i + 1
endif
endloop
endif
return 0
endmethod
method HasWeaponById takes integer weaponId returns boolean
local integer i = MaxWeaponItems+1 // Only the slots after the item weapons are of interest
loop
exitwhen i > MaxWeaponAbilities
if (this.Weapons[i].WeaponId == weaponId) and (this.Weapons[i].IsActive and (this.Weapons[i].IsReleasing == false)) then
return true
endif
set i = i + 1
endloop
return false
endmethod
method GetWeaponById takes integer weaponId returns integer
local integer i = 1
loop
exitwhen i > MaxWeaponAbilities
if (this.Weapons[i].WeaponId == weaponId) and (this.Weapons[i].IsActive and (this.Weapons[i].IsReleasing == false)) then
return i
endif
set i = i + 1
endloop
return -1
endmethod
method RemoveWeaponById takes integer weaponId returns nothing
local integer i = MaxWeaponItems+1 // Only the slots after the item weapons are of interest
loop
exitwhen i > MaxWeaponAbilities
if (this.Weapons[i].WeaponId == weaponId) and (this.Weapons[i].IsActive and (this.Weapons[i].IsReleasing == false)) then
call this.Weapons[i].DeactivateWeapon(GetPlayerNr(GetOwningPlayer(this.Holder)), i)
//call this.Weapons[i].destroy()
//set Weapons[i] = 0
return
endif
set i = i + 1
endloop
endmethod
method UpdateWeapon takes integer number, integer weaponID returns nothing
// What was this purpose of this again?
endmethod
method RemoveAllWeapons takes nothing returns nothing
local integer i = 1
loop
exitwhen i > MaxWeaponAbilities
if (this.Weapons[i] != 0) and (this.Weapons[i].IsActive and (this.Weapons[i].IsReleasing == false)) then
call this.Weapons[i].DeactivateWeapon(GetPlayerNr(GetOwningPlayer(this.Holder)), i)
//call Weapons[i].destroy()
//set this.Weapons[i] = 0
endif
set i = i + 1
endloop
endmethod
method PauseInventoryWeapons takes nothing returns nothing
local integer i = 1
loop
exitwhen i > MaxWeaponItems
if (this.Weapons[i] != 0) and (this.Weapons[i].IsActive and (this.Weapons[i].IsReleasing == false)) then
call this.Weapons[i].PauseWeapon(GetPlayerNr(GetOwningPlayer(this.Holder)), i)
endif
set i = i + 1
endloop
endmethod
method ResumeInventoryWeapons takes nothing returns nothing
local integer i = 1
loop
exitwhen i > MaxWeaponItems
if (this.Weapons[i] != 0) and (this.Weapons[i].IsReleasing == false) then
call this.Weapons[i].ResumeWeapon(GetPlayerNr(GetOwningPlayer(this.Holder)), i)
endif
set i = i + 1
endloop
endmethod
method SetHolder takes unit newHolder returns nothing
local integer i = 0
//call DebugMsg("Set new holder for " + GetName(this.Holder) + " " + I2S(this.PlayerNr) + " ("+I2S(GetPlayerNr(GetOwningPlayer(newHolder))) + ")")
set this.Holder = newHolder
loop
exitwhen i > MaxWeaponAbilities
if (this.Weapons[i] != 0) then
set this.Weapons[i].Owner = newHolder
endif
set i = i + 1
endloop
endmethod
endstruct
endlibrary
//TESH.scrollpos=276
//TESH.alwaysfold=0
library WeaponCoreFunctions requires MapAttachedSettings
struct WeaponCore
real Damage
real Cooldown
real Range
integer Projectiles
real HitChance
real Manacost
string Effect
real ProjectileSpeed
real ProjectileArc
real ProjectileSize
unit Owner
static code TargetFilter
integer HitEffect
boolean TargetFollow
item Weapon
integer WeaponId
boolean IsActive
boolean IsReleasing
static real MOVE_INTERVAL = 0.03
static real ZOFFSET = 50
// This constructor is used for item-based weapons
static method create takes item weapon, integer weaponId, real damage, real cooldown, real range, integer projectile, real hitchance, real mana, unit owner, boolean follow returns WeaponCore
local WeaponCore wc = WeaponCore.allocate()
if (wc != 0) then
set wc.WeaponId = weaponId
set wc.Weapon = weapon
set wc.Damage = damage
set wc.Cooldown = cooldown
set wc.Range = range
set wc.Projectiles = projectile
set wc.HitChance = hitchance
set wc.Manacost = mana
set wc.TargetFollow = follow
set wc.Owner = owner
set wc.IsActive = false
set wc.IsReleasing = false
else
call BJDebugMsg("WeaponCore error: max index reached")
endif
return wc
endmethod
// This constructor is used for ability-based weapons
static method createById takes integer weaponId, real damage, real cooldown, real range, integer projectile, real hitchance, real mana, unit owner, boolean follow returns WeaponCore
return WeaponCore.create(null, weaponId, damage, cooldown, range, projectile, hitchance, mana, owner, follow)
endmethod
// Execute the desired effect, when the projectile hits
static method CastTargetEffect takes unit source, unit target, real damage, integer kind returns nothing
if (kind == TARGET_EFFECT_DAMAGE) then //single target damage
// call DebugMsg("Single Target")
call UnitDamageTarget(source , target , damage , true , false , ATTACK_TYPE_CHAOS , DAMAGE_TYPE_MAGIC , WEAPON_TYPE_WHOKNOWS)
elseif (kind == TARGET_EFFECT_SPLASH) then //splash damage
//call DebugMsg("Splash")
call FixedAreaDamageFromUnit(source, GetUnitX(target), GetUnitY(target), 200, damage, 1, 0, false, null)
elseif (kind == TARGET_EFFECT_DAMAGE_SLOW) then //slow + damage
//call DebugMsg("Single Target + Slow")
call UnitDamageTarget(source , target , damage , true , false , ATTACK_TYPE_CHAOS , DAMAGE_TYPE_MAGIC , WEAPON_TYPE_WHOKNOWS)
if (GetUnitState(target, UNIT_STATE_LIFE) > 0) then
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(source), 'A0DE', 1, GetUnitX(target), GetUnitY(target), 0), "shadowstrike", target)
endif
elseif (kind == TARGET_EFFECT_LONG_RANGE) then
//call DebugMsg("Splash")
if (IsUnitType(target, UNIT_TYPE_STRUCTURE)) then
call UnitDamageTarget(source , target , 0.1*damage , true , false , ATTACK_TYPE_CHAOS , DAMAGE_TYPE_MAGIC , WEAPON_TYPE_WHOKNOWS)
else
call UnitDamageTarget(source , target , damage , true , false , ATTACK_TYPE_CHAOS , DAMAGE_TYPE_MAGIC , WEAPON_TYPE_WHOKNOWS)
endif
endif
endmethod
//The algorythm to choose the next target, which the weapon will attack
static method GetTarget takes integer pId, integer wId returns unit
local group G= NewGroup()
local real X= GetUnitX(WeaponHolder[pId].Weapons[wId].Owner)
local real Y= GetUnitY(WeaponHolder[pId].Weapons[wId].Owner)
local unit Target = null
//udg_TempInt has to be set to the player number, so it can be refered to in the filter function
set udg_Filter_Player = GetOwningPlayer(WeaponHolder[pId].Weapons[wId].Owner)
call GroupEnumUnitsInRange(G , X , Y , WeaponHolder[pId].Weapons[wId].Range, Condition(WeaponHolder[pId].Weapons[wId].TargetFilter))
if FirstOfGroup(G) != null then
set Target = GroupPickRandomUnit(G)
//call DebugMsg("Attacker: " + GetUnitName(core.Owner) + ", Range: " + R2S(core.Range) + ", Target: " + GetUnitName(Target))
endif
call ReleaseGroup(G)
set G = null
return Target
endmethod
//The action, that gets executed when the target is hit
static method TargetHit takes unit Projectile, unit Target, unit Attacker, integer wId returns nothing
local integer pId = GetPlayerNr(GetOwningPlayer(Attacker))
local real chance = WeaponHolder[pId].Weapons[wId].HitChance
local real damage = WeaponHolder[pId].Weapons[wId].Damage
// when the chance is 0, that means that the weapon has been reset during the flight towards the target
// in that case, hit every time (because this case is way more common)
if GetRandomInt(0, 100) <= chance or (chance == 0) then
call WeaponCore.CastTargetEffect(Attacker, Target, damage, WeaponHolder[pId].Weapons[wId].HitEffect)
else
call ShowTextTag("|cffff0000"+"Miss!"+"|r", Target, 0, 0, null)
endif
//call DebugMsg("Release: Target Hit")
call ReleaseDummy(Projectile)
set Projectile = null
set Target = null
endmethod
//The loop method, which moves the weapon projectile to it's target
static method MoveProjectile takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Projectile = udg_AV_Unit1[LoopTimerId]
local unit Target = udg_AV_Unit2[LoopTimerId]
local real TotalDist = udg_AV_Real1[LoopTimerId]
local real Speed = udg_AV_Real2[LoopTimerId]
local real TargetX
local real TargetY
local real DistanceLeft
local real DistX
local real DistY
local real TargetHeight
local real LastHeight = I2R(udg_AV_Int2[LoopTimerId])
local real AccelerationZ
local real VelocityZ
local real Arc = udg_AV_Real3[LoopTimerId]
if ( GetUnitState(Projectile , UNIT_STATE_LIFE) <= 0 ) or (Target == null) then
if (GetUnitState(Projectile , UNIT_STATE_LIFE) <= 0) then
call DebugMsg("Projectile dead")
endif
if (Target == null) then
call DebugMsg("Target: " + GetName(Target) + " Caster: " + GetName(udg_AV_Unit3[LoopTimerId]) + " Proj: " + GetName(Projectile))
endif
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
call ReleaseDummy(Projectile)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
//set TargetX = GetLocationX(udg_AV_Loc1[LoopTimerId])
//set TargetY = GetLocationY(udg_AV_Loc1[LoopTimerId])
set TargetX = GetUnitX(Target)
set TargetY = GetUnitY(Target)
set TargetHeight = I2R(udg_AV_Int1[LoopTimerId])
//Target moved faster than the possible max speed, teleport assumed -> disrupt the charge
if (GetXYDistance(GetLocationX(udg_AV_Loc1[LoopTimerId]), GetLocationY(udg_AV_Loc1[LoopTimerId]), TargetX, TargetY) > (600 * WeaponCore.MOVE_INTERVAL)) then
call DebugMsg("Moved too fast! Disrupted")
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
call ReleaseDummy(Projectile)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set DistX = TargetX - GetUnitX(Projectile)
set DistY = TargetY - GetUnitY(Projectile)
set DistanceLeft = SquareRoot(DistX * DistX + DistY * DistY)
if DistanceLeft <= Speed then
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
call WeaponCore.TargetHit(Projectile, Target, udg_AV_Unit3[LoopTimerId], udg_AV_Int3[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set AccelerationZ = 8*Arc*Speed*Speed/TotalDist
set VelocityZ = AccelerationZ * (DistanceLeft/Speed)/2 + Speed * (TargetHeight-RMaxBJ(LastHeight,WeaponCore.ZOFFSET))/DistanceLeft
set VelocityZ = VelocityZ + AccelerationZ
call SetUnitX(Projectile, GetUnitX(Projectile) + Speed * DistX / DistanceLeft)
call SetUnitY(Projectile, GetUnitY(Projectile) + Speed * DistY / DistanceLeft)
call SetUnitFlyHeight(Projectile, RMaxBJ(GetUnitFlyHeight(Projectile)+LastHeight,WeaponCore.ZOFFSET) + VelocityZ - GetUnitZ(Projectile), 0)
// the stop command makes sure, that the projectile does not turn around itself (which would happen from time to time)
call IssueImmediateOrder(Projectile, "stop")
//call DebugMsg("Face: " + R2S(Atan2(DistY, DistX)*bj_RADTODEG) + " Distance: " + R2S(DistanceLeft))
call SetUnitAnimationByIndex(Projectile, R2I(bj_RADTODEG * Atan2(VelocityZ, Speed) + 0.5) + 90)
set udg_AV_Int2[LoopTimerId] = R2I(GetUnitZ(Projectile))
call MoveLocation(udg_AV_Loc1[LoopTimerId], TargetX, TargetY)
endif
endif
endif
set Projectile = null
set Target = null
endmethod
//Create a projectile and move it to the chosen target
static method ShootWeapon takes nothing returns nothing
local timer t
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local integer ShootTimerId
local integer i= 1
local integer pId = udg_AV_Int1[LoopTimerId]
local integer wId = udg_AV_Int2[LoopTimerId]
local unit Target
local unit Projectile
local unit Owner = WeaponHolder[pId].Weapons[wId].Owner //udg_AV_Unit1[LoopTimerId] //
local real Mana
local real ManaCosts = WeaponHolder[pId].Weapons[wId].Manacost
local real size = WeaponHolder[pId].Weapons[wId].ProjectileSize
local real face
local real DistX
local real DistY
local real TargetX
local real TargetY
local real TravelTime
local boolean IsTargetMoving = false
local string TargetOrder
local effect fx
local boolean DisabledInventory = (GetUnitAbilityLevel(Owner, PACIFISTA_INVENTORY_ID) > 5) or (GetUnitAbilityLevel(Owner, 'A079') > 0) // 'A079' = Tech Mech
if (WeaponHolder[pId].Holder != Owner) then
call DebugMsg("inconsistent data!")
endif
if (WeaponHolder[pId].Weapons[wId].IsReleasing == false) and (not DisabledInventory) then
//call DebugMsg("Fire weapon " + I2S(wId) + " for player " + I2S(pId))
loop
exitwhen i > WeaponHolder[pId].Weapons[wId].Projectiles
set Target = WeaponCore.GetTarget(pId, wId)
set Mana = GetUnitState(Owner , UNIT_STATE_MANA)
if ( Target != null ) and ( Mana >= ManaCosts ) and ( GetUnitState(Owner , UNIT_STATE_LIFE) > 0 ) and (IsUnitHidden(Owner) == false) and (not IsUnitPaused(Owner)) then
call SetUnitState(Owner , UNIT_STATE_MANA , Mana - ManaCosts)
set face = bj_RADTODEG * Atan2(GetUnitY(Target) - GetUnitY(Owner), GetUnitX(Target) - GetUnitX(Owner))
set Projectile = XE_NewDummyUnit(GetOwningPlayer(Owner) , GetUnitX(Owner) , GetUnitY(Owner) , face)
call SetUnitScale(Projectile, size, size, size)
call SetUnitFlyHeight(Projectile, GetUnitFlyHeight(Owner)+WeaponCore.ZOFFSET, 0)
set fx = AddSpecialEffectTarget(WeaponHolder[pId].Weapons[wId].Effect , Projectile , "origin")
set DistX = GetUnitX(Target) - GetUnitX(Projectile)
set DistY = GetUnitY(Target) - GetUnitY(Projectile)
set TargetOrder = OrderId2String(GetUnitCurrentOrder(Target))
set IsTargetMoving = ( TargetOrder == "move" or TargetOrder == "patrol" or TargetOrder == "attack" or TargetOrder == "smart" )
//call DebugMsg("Target Order: " + TargetOrder)
// when following the target, you want to hit, where it currently is
// when not following the target, you just want to hit, where the target will be, when the projetiles reaches the target
// but even when you don't want to follow, you'll just hit the target at its current position, when it's not moving
if (WeaponHolder[pId].Weapons[wId].TargetFollow) or (not IsTargetMoving) then
set TargetX = GetUnitX(Target)
set TargetY = GetUnitY(Target)
else
set face = GetUnitFacing(Target)*bj_DEGTORAD
set TravelTime = SquareRoot(DistX * DistX + DistY * DistY) / WeaponHolder[pId].Weapons[wId].ProjectileSpeed
// The assumed position of the target, when the projectile hits
set TargetX = GetUnitX(Target) + GetUnitMoveSpeed(Target)*TravelTime * Cos(face)
set TargetY = GetUnitY(Target) + GetUnitMoveSpeed(Target)*TravelTime * Sin(face)
set DistX = TargetX - GetUnitX(Projectile)
set DistY = TargetY - GetUnitY(Projectile)
endif
set t = NewTimer()
set ShootTimerId = NewTimerIndex(t)
set udg_AV_Unit1[ShootTimerId] = Projectile
set udg_AV_Unit2[ShootTimerId] = Target
set udg_AV_Unit3[ShootTimerId] = Owner
set udg_AV_Loc1[ShootTimerId] = Location(TargetX, TargetY)
set udg_AV_Real1[ShootTimerId] = SquareRoot(DistX * DistX + DistY * DistY)
set udg_AV_Real2[ShootTimerId] = WeaponHolder[pId].Weapons[wId].ProjectileSpeed * WeaponCore.MOVE_INTERVAL
set udg_AV_Real3[ShootTimerId] = WeaponHolder[pId].Weapons[wId].ProjectileArc
set udg_AV_Effect1[ShootTimerId] = fx
set udg_AV_Int1[ShootTimerId] = R2I(GetUnitZ(Target))
set udg_AV_Int2[ShootTimerId] = R2I(GetUnitZ(Projectile))
set udg_AV_Int3[ShootTimerId] = wId
call TimerStart(t , WeaponCore.MOVE_INTERVAL , true , function WeaponCore.MoveProjectile)
endif
set i = i + 1
endloop
else
call DebugMsg("--- Weapon " + I2S(wId) + " stopped ---")
set WeaponHolder[pId].Weapons[wId].IsReleasing = false
set WeaponHolder[pId].Weapons[wId].IsActive = false
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
//call WeaponHolder[pId].Weapons[wId].destroy()
endif
set Target = null
set Projectile = null
set Owner = null
set fx = null
endmethod
//Activate the timer, which periodically launches new projectiles and initiate the projectile graphics
method ActivateWeapon takes string projectile, real speed, real arc, real size, code filter, integer targetEffect, integer wId returns nothing
local integer LoopTimerId
local integer pId = GetPlayerNr(GetOwningPlayer(this.Owner))
local timer t
set this.Effect = projectile
set this.ProjectileSpeed = speed
set this.ProjectileArc = arc
set this.ProjectileSize = size
set this.TargetFilter = filter
set this.HitEffect = targetEffect
set this.IsReleasing = false
set this.IsActive = true
call DebugMsg("Activate weapon " + GetItemName(this.Weapon) + " " + I2S(wId) + " for " + I2S(pId))
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Int1[LoopTimerId] = GetPlayerNr(GetOwningPlayer(this.Owner))
set udg_AV_Int2[LoopTimerId] = wId
set udg_AV_Unit1[LoopTimerId] = this.Owner
call TimerStart(t, this.Cooldown, true, function WeaponCore.ShootWeapon)
endmethod
method PauseWeapon takes integer pId, integer wId returns nothing
set this.IsActive = false
endmethod
method ResumeWeapon takes integer pId, integer wId returns nothing
set this.IsActive = true
endmethod
//Stop the weapon permanently
method DeactivateWeapon takes integer pId, integer wId returns nothing
call DebugMsg("Deactivate weapon " + GetItemName(this.Weapon) + " " + I2S(wId))
set this.IsReleasing = true
set this.Owner = null
set this.Weapon = null
endmethod
endstruct
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library ItemFullResale initializer Init requires MapAttachedSettings
globals
private constant integer MAXITEMS = 100
private constant real RESALEDURATION = 10.0
private item array ResaleItems[MAXITEMS]
endglobals
function FindResaleItem takes item Item returns integer
local integer i = 0
loop
exitwhen (ResaleItems[i] == Item) or (i > MAXITEMS)
set i = i + 1
endloop
if (i <= MAXITEMS) then
return i
else
//call DebugMsg("Could not find resale item")
endif
return -1
endfunction
function SaveItemForFullResale_Child takes nothing returns nothing
local integer TimerId = GetHandleIndex(GetExpiredTimer())
local item Item = udg_AV_Item1[TimerId]
local integer i = 0
set i = FindResaleItem(Item)
if (i != -1) then
set ResaleItems[i] = null
else
call DebugMsg("Item resale: could not find item to remove from array")
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(TimerId)
endfunction
function SaveItemForFullResale takes item Item returns nothing
local integer i = 0
local timer t
local integer TimerId
loop
exitwhen (ResaleItems[i] == null) or (i > MAXITEMS)
set i = i + 1
endloop
if (i <= MAXITEMS) then
set ResaleItems[i] = Item
else
call DebugMsg("Could not save item for full resale")
endif
set t = NewTimer()
set TimerId = NewTimerIndex(t)
set udg_AV_Item1[TimerId] = Item
call TimerStart(t, RESALEDURATION, false, function SaveItemForFullResale_Child)
endfunction
function CheckItemForFullResale takes item Item returns boolean
local integer i = 0
set i = FindResaleItem(Item)
if (i != -1) then
return true
endif
return false
endfunction
function RemoveItemForResale takes nothing returns nothing
local integer i = 0
set i = FindResaleItem(GetManipulatedItem())
if (i != -1) then
set ResaleItems[i] = null
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
// this trigger removes items that have been used from the array, to prevent abuses of the full resale system
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddAction( t, function RemoveItemForResale )
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Items_Buy_Actions takes nothing returns nothing
local item SoldItem = GetSoldItem()
local integer soldItemId = GetItemTypeId(SoldItem)
local unit Buyer = GetBuyingUnit()
local player Owner = GetOwningPlayer(Buyer)
if (soldItemId == 'I04A') then
if (GetHeroLevel(Buyer) == 25) then // Level Upgrade
call DisplayTextToPlayer(Owner,0,0,"|cfffed312Your tank is already on level 25.|r" )
call SetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD) + R2I(GetWidgetLife(SoldItem)))
call RemoveItem( SoldItem )
endif
else
set udg_Item_Buy = true
call SaveItemForFullResale(SoldItem)
endif
if (CheckItemRequirements(SoldItem, Owner) == null) then
// If 'GetSupportRewardForItem' returns 0, the 'MB_SetSupport' function won't do anything
call MB_SetSupport( GetPlayerNr(Owner), GetSupportRewardForItem(soldItemId) )
endif
set Buyer = null
set SoldItem = null
endfunction
//===========================================================================
function InitTrig_Items_Buy takes nothing returns nothing
set gg_trg_Items_Buy = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Buy, EVENT_PLAYER_UNIT_SELL_ITEM )
call TriggerAddAction( gg_trg_Items_Buy, function Trig_Items_Buy_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Items_Take_Conditions takes nothing returns boolean
local itemtype Type = GetItemType(GetManipulatedItem())
local integer Id = GetItemTypeId(GetManipulatedItem())
return udg_Item_Check and (Type==ITEM_TYPE_PERMANENT or Type==ITEM_TYPE_ARTIFACT or Type==ITEM_TYPE_CHARGED)
endfunction
function Trig_Items_Take_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local item Item = GetManipulatedItem()
local player ItemOwner = GetItemPlayer(Item)
local player UnitOwner = GetOwningPlayer(U)
local integer ItemOwnerId = GetPlayerNr(ItemOwner)
local integer UnitOwnerId = GetPlayerNr(UnitOwner)
local integer WeaponsLevel= GetPlayerTechCount(UnitOwner, 'R002', true)
local integer ArmorLevel= GetPlayerTechCount(UnitOwner, 'R003', true)
local integer Id = GetItemTypeId(Item)
local integer i
local string s = null
local integer Gold = 0
local item SlotItem
local boolean IsSecondHandItem = GetItemUserData(Item)==2
//when the item belongs to the Force or was just bought (ItemOwnerId > GetMaxHumanPlayers) anyone can pick it up
if (not IsSecondHandItem) and ItemOwner!=UnitOwner and ItemOwnerId<=GetMaxHumanPlayers() and UnitOwnerId<=GetMaxHumanPlayers() and (IsMapFlagSet(MAP_LOCK_RESOURCE_TRADING) or not IsUnitAlly(U, ItemOwner)) then
// Nopool and Anti-Item-Steal
if IsMapFlagSet(MAP_LOCK_RESOURCE_TRADING) then
set s = "|cfffed312You can only receive your own objects.|r"
else
set s = "|cfffed312You can only receive your own objects or those of your allies.|r"
endif
call ItemDropInvalid( U, Item )
set Item = null
else
if UnitOwnerId <= 10 and not IsSecondHandItem then
call SetItemPlayer( Item, UnitOwner, false )
endif
if GetUnitTypeId(U) == 'H00Y' and (GetItemType(Item) == ITEM_TYPE_ARTIFACT or Id=='I02H' or Id=='I00R' or Id=='I00Q' or Id=='I04S' or Id=='I04U' or Id=='I04T' or Id=='I011' or Id=='I04Q' or Id=='I05V' or Id=='I037') then
// Invalid Trader Item
set s = "|cfffed312The Trader cannot carry Weapons, Hulls or a Bomb bought at the Goblin Trader.|r"
if udg_Item_Buy then
set Gold = R2I(GetWidgetLife(Item))
call RemoveItem( Item )
else
call ItemDropInvalid( U, Item )
endif
set Item = null
else
endif
endif
//Explosives are also disabled in NoExploder-Mode
/*
if s==null then
if udg_NoExploder and (GetItemTypeId(Item) == 'I01W') then
set s = "|cfffed312Explosives are not allowed in this mode.|r"
if s!=null then
if udg_Item_Buy then
set Gold = R2I(GetWidgetLife(Item))
call RemoveItem( Item )
else
call ItemDropInvalid( U, Item )
endif
set Item = null
endif
endif
endif */
//Check if the player meets the requirements for the item
if s==null then
set s = CheckItemRequirements(Item, UnitOwner)
if s!=null then
if udg_Item_Buy then
set Gold = R2I(GetWidgetLife(Item))
call RemoveItem( Item )
else
call ItemDropInvalid( U, Item )
endif
set Item = null
endif
endif
//Concealing Engine
if s==null then
if (Id=='I05P') and (not IsUnitType(U, UNIT_TYPE_GROUND)) then
set s = "|cfffed312This item can only be used by ground units.|r"
endif
if s!=null then
if udg_Item_Buy then
set Gold = R2I(GetWidgetLife(Item))
call RemoveItem( Item )
else
call ItemDropInvalid( U, Item )
endif
set Item = null
endif
endif
//Burst Armor and Deflective Armor
if s==null then
if IsBlockingArmor(Item) and (CountBlockingArmorInInventory(U) >= 2) then
set s = "|cfffed312You can only carry one armor of this type.|r"
endif
if s!=null then
if udg_Item_Buy then
set Gold = R2I(GetWidgetLife(Item))
call RemoveItem( Item )
else
call ItemDropInvalid( U, Item )
endif
set Item = null
endif
endif
if s!=null then
//If buying was invalid, give the money back and display the error message
if Gold!=0 then
call SetPlayerState(UnitOwner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(UnitOwner, PLAYER_STATE_RESOURCE_GOLD) + Gold)
endif
if GetLocalPlayer() == UnitOwner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, s )
endif
else
if IsSecondHandItem then
if not IsUnitAlly(U, ItemOwner) then
if GetLocalPlayer() == UnitOwner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You cannot buy items from the enemy.|r" )
endif
call ItemDropInvalid( U, Item )
set Item = null
else
if GetItemCharges(Item)==0 then
set Gold = R2I(GetWidgetLife(Item))
else
set Gold = R2I(GetWidgetLife(Item)*GetItemCharges(Item))
endif
if UnitOwner==ItemOwner then
set Gold = Gold/2
else
set Gold = Gold*3/4
endif
if Gold <= GetPlayerState(UnitOwner,PLAYER_STATE_RESOURCE_GOLD) then
call DestroyEffect(AddSpecialEffectTarget("UI\\Feedback\\GoldCredit\\GoldCredit.mdl", U, "origin"))
call ShowTextTag("|cfffed312-"+I2S(Gold)+"|r", U, 0, 0, UnitOwner)
call SetPlayerState(UnitOwner,PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(UnitOwner,PLAYER_STATE_RESOURCE_GOLD)-Gold)
if GetLocalPlayer() == UnitOwner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You have bought the item.|r" )
endif
if UnitOwner!=ItemOwner then
if GetLocalPlayer() == ItemOwner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312One of your past items has been sold. You got "+I2S(Gold/3)+" gold.|r" )
endif
call SetPlayerState(ItemOwner,PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(ItemOwner,PLAYER_STATE_RESOURCE_GOLD)+Gold/3)
set udg_Profit_Sold[GetPlayerNr(ItemOwner)] = udg_Profit_Sold[GetPlayerNr(ItemOwner)] - (Gold/3)
else
set udg_Profit_Sold[GetPlayerNr(ItemOwner)] = udg_Profit_Sold[GetPlayerNr(ItemOwner)] - Gold
endif
set udg_Item_Check = false
call SetItemPosition(Item, 0,-512)
call SetItemUserData(Item,0)
call SetItemPlayer( Item, UnitOwner, false )
call UnitAddItem(U, Item)
set udg_Item_Check = true
else
if GetLocalPlayer() == UnitOwner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You don't have "+I2S(Gold)+" gold to buy this item.|r" )
endif
call ItemDropInvalid( U, Item )
set Item = null
endif
endif
endif
if Item!=null then
set ItemOwner = GetItemPlayer(Item)
//automatically change items, when it's restricted to a certain tank type (air / ground)
if (not IsUnitType(U, UNIT_TYPE_STRUCTURE)) and (GetUnitTypeId(U) != PACIFISTA_ITEMHOLDER_ID) and (not IsTechMech(U)) then
//the special weapons, which can only be carried by a certain tank type (air/ground)
//are automatically switched to the fitting version
if (Id=='I02Z' or Id=='I03C') and (( GetUnitTypeId(U) == 'H00R') or (not IsAirUnit(U)) ) then // Bombs
call RemoveItem( Item )
if Id=='I02Z' then
set Item = UnitAddItemById(U, 'I01U')
else
set Item = UnitAddItemById(U, 'I03B')
endif
call SetItemPlayer( Item, ItemOwner, false )
set s = "|cfffed312Ground tanks can't carry Bombs, switched to AA Gun.|r"
elseif (Id=='I01U' or Id=='I03B') and (not (GetUnitTypeId(U) == 'H00R')) and (not IsGroundUnit(U)) then // AA Gun
call RemoveItem( Item )
if Id=='I01U' then
set Item = UnitAddItemById(U, 'I02Z')
else
set Item = UnitAddItemById(U, 'I03C')
endif
call SetItemPlayer( Item, ItemOwner, false )
set s = "|cfffed312Air tanks can't carry AA Gun, switched to Bombs.|r"
elseif (Id=='I057' or Id=='I058') and ((GetUnitTypeId(U) == 'H00R') or (not IsAirUnit(U)) ) then // Flak
call RemoveItem( Item )
if Id=='I057' then
set Item = UnitAddItemById(U, 'I059')
else
set Item = UnitAddItemById(U, 'I05A')
endif
call SetItemPlayer( Item, ItemOwner, false )
set s = "|cfffed312Ground tanks can't carry Flak, switched to Axe Launcher.|r"
elseif (Id=='I059' or Id=='I05A') and (not (GetUnitTypeId(U) == 'H00R')) and (not IsGroundUnit(U)) then // Axe Launcher
call RemoveItem( Item )
if Id=='I059' then
set Item = UnitAddItemById(U, 'I057')
else
set Item = UnitAddItemById(U, 'I058')
endif
call SetItemPlayer( Item, ItemOwner, false )
set s = "|cfffed312Air tanks can't carry Axe Launcher, switched to Flak.|r"
endif
if (GetLocalPlayer() == UnitOwner) and (s != null) then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, s )
endif
//a special Defuse Pack for the Trader, which grants no extra Hitpoints
if (Id=='I04R') and GetUnitTypeId(U) == 'H00Y' then // I04R - normal Defuse Pack, H00Y - Trader
call RemoveItem( Item )
set Item = UnitAddItemById(U, 'I05G')
call SetItemPlayer( Item, ItemOwner, false )
elseif (Id=='I05G') and GetUnitTypeId(U) != 'H00Y' then // I05G - Trader Defuse Pack, H00Y - Trader
call RemoveItem( Item )
set Item = UnitAddItemById(U, 'I04R')
call SetItemPlayer( Item, ItemOwner, false )
endif
endif
if Id!='I04Q' and Id!='I04V' and GetItemCharges(Item) != 0 then
// Stacking Items
set i = 0
loop
exitwhen i > 5
set SlotItem = UnitItemInSlot(U, i)
if GetItemTypeId(SlotItem) == GetItemTypeId(Item) and SlotItem != Item then
call SetItemCharges( SlotItem, GetItemCharges(SlotItem) + GetItemCharges(Item) )
call RemoveItem( Item )
set i = 5
endif
set i = i + 1
endloop
set SlotItem = null
endif
endif
endif
set udg_Item_Buy = false
set Item = null
if UnitOwnerId<=GetMaxHumanPlayers() then
if (udg_Show_WeaponRange_Mode > 0) and (UnitOwnerId == GetPlayerNr(udg_GameMode_Host)) then
call GetWeaponRangeMode(udg_Tank[GetPlayerNr(udg_GameMode_Host)], udg_Show_WeaponRange_Mode)
endif
call UpdateTankCosts(UnitOwnerId)
endif
set U = null
endfunction
//===========================================================================
function InitTrig_Items_Take takes nothing returns nothing
set gg_trg_Items_Take = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Take, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( gg_trg_Items_Take, Condition( function Trig_Items_Take_Conditions ) )
call TriggerAddAction( gg_trg_Items_Take, function Trig_Items_Take_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Items_Sell_Conditions takes nothing returns boolean
return GetItemType(GetManipulatedItem())!=ITEM_TYPE_CHARGED
endfunction
function Trig_Items_Sell_Actions takes nothing returns nothing
local player ItemOwner = GetOwningPlayer(GetTriggerUnit())
local integer i = GetItemCharges(GetSoldItem())
local integer soldItemId = GetItemTypeId(GetSoldItem())
// Check if the item has been bought just recently, if that is the case, sell the item for the full price (and dont place it on the junkyard)
if CheckItemForFullResale(GetSoldItem()) then
if (i != 0) then
call SetPlayerState(ItemOwner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(ItemOwner, PLAYER_STATE_RESOURCE_GOLD) + R2I(i*GetWidgetLife(GetSoldItem())/2))
else
call SetPlayerState(ItemOwner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(ItemOwner, PLAYER_STATE_RESOURCE_GOLD) + R2I(GetWidgetLife(GetSoldItem())/2))
endif
call ShowTextTag("|cfffed312x2", GetTriggerUnit(), -50, 0, ItemOwner)
if GetLocalPlayer() == ItemOwner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312Sold the item for the full price.|r" )
endif
// If 'GetSupportRewardForItem' returns 0, the 'MB_SetSupport' function won't do anything
// Return any eventual bonus gold gained from the 'Tankers little helper' skill of the Distributor
if (i != 0) then
call MB_SetSupport( GetPlayerNr(ItemOwner), -i*GetSupportRewardForItem(soldItemId) )
else
call MB_SetSupport( GetPlayerNr(ItemOwner), -GetSupportRewardForItem(soldItemId) )
endif
else
if (i != 0) then
set udg_Profit_Sold[GetPlayerNr(ItemOwner)] = udg_Profit_Sold[GetPlayerNr(ItemOwner)] + (i*GetWidgetLife(GetSoldItem())/2)
else
set udg_Profit_Sold[GetPlayerNr(ItemOwner)] = udg_Profit_Sold[GetPlayerNr(ItemOwner)] + (GetWidgetLife(GetSoldItem())/2)
endif
call PlaceItemOnJunkyard(GetPlayerNr(ItemOwner), GetSoldItem(), false)
endif
endfunction
//===========================================================================
function InitTrig_Items_Sell takes nothing returns nothing
set gg_trg_Items_Sell = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Sell, EVENT_PLAYER_UNIT_PAWN_ITEM )
call TriggerAddCondition( gg_trg_Items_Sell, Condition( function Trig_Items_Sell_Conditions ) )
call TriggerAddAction( gg_trg_Items_Sell, function Trig_Items_Sell_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Items_Drop_Child takes nothing returns nothing
local integer AV = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[AV]
local player UnitOwner = GetOwningPlayer(U)
local integer Id = GetPlayerNr(UnitOwner)
local item Item = udg_AV_Item1[AV]
local integer Gold
local integer i
local integer Team = udg_Player_Team[Id]
call ReleaseHandleIndex(AV)
call ReleaseTimer(GetExpiredTimer())
//Remove the buff of the Burst Armor
if (GetItemTypeId(Item) == 'I05N') then
call UnitRemoveAbility(U, 'A0EC')
call UnitRemoveAbility(U, 'B026')
endif
if Item!=null and RectContainsCoords(udg_JunkyardRect[Team],GetItemX(Item),GetItemY(Item)) and (GetWidgetLife(Item)>=1000) /*
*/ and (GetItemTypeId(Item) != DUMMY_ITEM_ID) and (IgnoreNextItemOnJunkyard == false) then
if GetItemCharges(Item)==0 then
set Gold = R2I(GetWidgetLife(Item)/2)
else
set Gold = R2I(GetWidgetLife(Item)*GetItemCharges(Item)/2)
endif
call SetPlayerState(UnitOwner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(UnitOwner, PLAYER_STATE_RESOURCE_GOLD) + Gold)
call DestroyEffect(AddSpecialEffectTarget("UI\\Feedback\\GoldCredit\\GoldCredit.mdl", U, "origin"))
call ShowTextTag("|cfffed312+"+I2S(Gold)+"|r", U, 0, 0, UnitOwner)
call PlaceItemOnJunkyard(GetPlayerNr(UnitOwner), Item, true)
endif
if (IgnoreNextItemOnJunkyard) then
set IgnoreNextItemOnJunkyard = false
endif
call UpdateTankCosts(Id)
set U = null
set Item = null
endfunction
function Trig_Items_Drop_Actions takes nothing returns nothing
local timer t
local integer AV
if udg_Item_Check and (GetPlayerNr(GetOwningPlayer(GetTriggerUnit())) <= GetMaxHumanPlayers()) then
set t = NewTimer()
set AV = NewTimerIndex(t)
set udg_AV_Unit1[AV]=GetTriggerUnit()
set udg_AV_Item1[AV]=GetManipulatedItem()
call TimerStart(t,0.00,false,function Trig_Items_Drop_Child)
endif
endfunction
//===========================================================================
function InitTrig_Items_Drop takes nothing returns nothing
set gg_trg_Items_Drop = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Drop, EVENT_PLAYER_UNIT_DROP_ITEM )
call TriggerAddAction( gg_trg_Items_Drop, function Trig_Items_Drop_Actions )
endfunction
//TESH.scrollpos=23
//TESH.alwaysfold=0
function Trig_Items_Healer_Conditions takes nothing returns boolean
return IsItemHealer(GetManipulatedItem())
endfunction
function EraseHealerEffect takes item Healer returns nothing
local integer i = 1
loop
exitwhen i > 500
if udg_Healer_Rune[i] == Healer then
call DestroyEffect(udg_Healer_Effect[i])
set udg_Healer_Effect[i] = null
set udg_Healer_Rune[i] = null
return
endif
set i = i+1
endloop
call BJDebugMsg("Debug: Rune not found")
endfunction
function Trig_Items_Healer_Actions takes nothing returns nothing
local unit Tank = GetTriggerUnit()
local item Healer = GetManipulatedItem()
local real ItemX = GetItemX( Healer )
local real ItemY = GetItemY( Healer )
if not IsUnitType(Tank, UNIT_TYPE_STRUCTURE) then
if GetItemTypeId(Healer) == 'I04C' then
//Normal rune -> heal the target by 10% of his max hp and mana
call SetUnitState( Tank, UNIT_STATE_LIFE, GetUnitState(Tank, UNIT_STATE_LIFE) + GetUnitState(Tank, UNIT_STATE_MAX_LIFE) * 0.1)
call SetUnitState( Tank, UNIT_STATE_MANA, GetUnitState(Tank, UNIT_STATE_MANA) + GetUnitState(Tank, UNIT_STATE_MAX_MANA) * 0.1)
else
call EraseHealerEffect(Healer)
if IsUnitAlly(Tank, GetItemPlayer(Healer)) then
//Scout rune -> heal the ally by 25% of his max hp and mana
call SetUnitState( Tank, UNIT_STATE_LIFE, GetUnitState(Tank, UNIT_STATE_LIFE) + GetUnitState(Tank, UNIT_STATE_MAX_LIFE) * 0.25)
call SetUnitState( Tank, UNIT_STATE_MANA, GetUnitState(Tank, UNIT_STATE_MANA) + GetUnitState(Tank, UNIT_STATE_MAX_MANA) * 0.25)
else
//Scout rune -> damage the enemy by 25% of his current hp and mana
call SetUnitState( Tank, UNIT_STATE_LIFE, GetUnitState(Tank, UNIT_STATE_LIFE) - GetUnitState(Tank, UNIT_STATE_LIFE) * 0.25)
call SetUnitState( Tank, UNIT_STATE_MANA, GetUnitState(Tank, UNIT_STATE_MANA) - GetUnitState(Tank, UNIT_STATE_MANA) * 0.25)
endif
endif
set Tank = null
//life == 1 -> created by the Scout, do not create it again
if GetWidgetLife(Healer) == 2.0 then
call GameTimeWait( 25 )
set Healer = CreateItem( 'I04C', ItemX, ItemY )
call SetItemPosition( Healer, ItemX, ItemY )
endif
else
//well, there is still the effect of the picked up rune ... but whatever
call GameTimeWait( 0.5 )
if GetItemTypeId(Healer) == 'I04C' then
set Healer = CreateItem( 'I04C', ItemX, ItemY )
else
set Healer = CreateItem( 'I050', ItemX, ItemY )
endif
call SetItemPosition( Healer, ItemX, ItemY )
endif
set Healer = null
endfunction
//===========================================================================
function InitTrig_Items_Healer takes nothing returns nothing
set gg_trg_Items_Healer = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Healer, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( gg_trg_Items_Healer, Condition( function Trig_Items_Healer_Conditions ) )
call TriggerAddAction( gg_trg_Items_Healer, function Trig_Items_Healer_Actions )
endfunction
//TESH.scrollpos=30
//TESH.alwaysfold=0
function Trig_Items_Upgrade_Conditions takes nothing returns boolean
return GetItemType(GetManipulatedItem()) == ITEM_TYPE_ARTIFACT or GetItemType(GetManipulatedItem()) == ITEM_TYPE_PERMANENT
endfunction
function Trig_Items_Upgrade_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer ArmorLevel = GetPlayerTechCount(GetOwningPlayer(U), 'R003', true)
local integer PlayerId = GetPlayerNr(GetOwningPlayer(U))
local integer UpgradeNumber = 1
local integer i
local integer Costs
local item Upgrade
local real ItemLife
local real ItemX
local real ItemY
local group G
if IsPacifista(U) then
call DisplayTextToPlayer(GetOwningPlayer(U), 0, 0, "|cfffed312The Pacifista can't upgrade any weapons.|r" )
//this check makes sure, that the Force won't upgrade weapons, that were placed in a tower
elseif (PlayerId <= GetMaxHumanPlayers()) and (udg_Afk[PlayerId] == false) then
loop
exitwhen udg_Weapon_Basic[UpgradeNumber] == null
if GetItemTypeId(GetManipulatedItem()) == udg_Weapon_Basic[UpgradeNumber] then
if ((GetItemTypeId(GetManipulatedItem())=='I05N') or (GetItemTypeId(GetManipulatedItem()) == 'I05O')) and (ArmorLevel<4) then // Burst and Deflective Armor
if GetLocalPlayer() == GetOwningPlayer(U) then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You don't have the required Upgrades.|r" )
endif
else
set Upgrade = CreateItem(udg_Weapon_Upgrade[UpgradeNumber],0,0)
set Costs = R2I(GetWidgetLife(Upgrade) - GetWidgetLife(GetManipulatedItem()))
call RemoveItem( Upgrade )
if GetPlayerState(GetPlayer(PlayerId), PLAYER_STATE_RESOURCE_GOLD) >= Costs then
call AdjustPlayerStateBJ( - Costs, GetPlayer(PlayerId), PLAYER_STATE_RESOURCE_GOLD )
set ItemLife = I2R(Costs) + GetWidgetLife(GetManipulatedItem())
call RemoveItem( GetManipulatedItem() )
set udg_Item_Check = false
if Costs > 0 then
set Upgrade = UnitAddItemById(U, 'I03N')
else
set Upgrade = UnitAddItemById(U, 'I04O')
endif
call SetItemPlayer( Upgrade, GetOwningPlayer(U), false )
set udg_Item_Check = true
call SetWidgetLife( Upgrade, ItemLife)
if Costs > 0 then
call GameTimeWait( 10.00 )
else
call GameTimeWait( 1.50 )
endif
if IsItemOwned( Upgrade ) then
set G = GetUnitsInRectMatchingSafe(udg_Playable_Map, FILTER_NULL)
set U = FirstOfGroup( G )
set i = 1
loop
exitwhen U == null or i == 0
if UnitHasItem(U, Upgrade) then
set i = 0
else
call GroupRemoveUnit( G, U )
set U = FirstOfGroup( G )
endif
endloop
call ReleaseGroup( G )
set G = null
if i == 1 then
loop
exitwhen i > GetMaxHumanPlayers()
set U = udg_Tank[i]
if UnitHasItem(U, Upgrade) then
set i = GetMaxHumanPlayers()+1
else
set i = i + 1
endif
endloop
endif
call RemoveItem( Upgrade )
set PlayerId = GetPlayerNr(GetOwningPlayer(U))
if GetUnitState(U, UNIT_STATE_LIFE) > 0 then
//set udg_Item_Check = false
set Upgrade = UnitAddItemById( U, udg_Weapon_Upgrade[UpgradeNumber] )
call SetItemPlayer( Upgrade, GetOwningPlayer(U), false )
if udg_Afk[PlayerId] then
call SetItemDroppable( Upgrade, false )
endif
//set udg_Item_Check = true
else
if IsPacifista(U) then
call DebugMsg("Pacifista item")
if (PWeapons.Holder[PlayerId] != null) then
call DebugMsg("upgraded Item to Holder")
call UnitAddItemById(PWeapons.Holder[PlayerId], udg_Weapon_Upgrade[UpgradeNumber])
endif
else
call GiveItemToDeadTank(PlayerId, udg_Weapon_Upgrade[UpgradeNumber])
endif
endif
set i = 0
else
set ItemX = GetItemX(Upgrade)
set ItemY = GetItemY(Upgrade)
call RemoveItem( Upgrade )
set Upgrade = CreateItem( udg_Weapon_Upgrade[UpgradeNumber], ItemX, ItemY )
call SetItemPlayer( Upgrade, GetOwningPlayer(U), false )
endif
// Forces AI to recalculate Combat Range
// Sorry, for placing an AI-related command here // it's ok, I forgive you
set udg_GetAICombatRange_Level[PlayerId] = 0
else
if GetLocalPlayer() == GetOwningPlayer(U) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312Not enough gold.|r")
endif
endif
endif
set UpgradeNumber = 0
else
set UpgradeNumber = UpgradeNumber + 1
endif
endloop
endif
set Upgrade = null
set U = null
endfunction
//===========================================================================
function InitTrig_Items_Upgrade takes nothing returns nothing
local integer i = 0
// Machine Gun
set i = i + 1
set udg_Weapon_Basic[i] = 'I008'
set udg_Weapon_Upgrade[i] = 'I00X'
// Acid Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I062'
set udg_Weapon_Upgrade[i] = 'I063'
// Artillery (Normal)
set i = i + 1
set udg_Weapon_Basic[i] = 'I00B'
set udg_Weapon_Upgrade[i] = 'I034'
// Artillery (Ground)
set i = i + 1
set udg_Weapon_Basic[i] = 'I034'
set udg_Weapon_Upgrade[i] = 'I00B'
// AA Gun
set i = i + 1
set udg_Weapon_Basic[i] = 'I01U'
set udg_Weapon_Upgrade[i] = 'I03B'
// Axe Launcher
set i = i + 1
set udg_Weapon_Basic[i] = 'I059'
set udg_Weapon_Upgrade[i] = 'I05A'
// Basic Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I00E'
set udg_Weapon_Upgrade[i] = 'I02I'
// Basic Magic
set i = i + 1
set udg_Weapon_Basic[i] = 'I01F'
set udg_Weapon_Upgrade[i] = 'I02L'
// Blaster Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I01K'
set udg_Weapon_Upgrade[i] = 'I01M'
// Bombarding Rockets
set i = i + 1
set udg_Weapon_Basic[i] = 'I05W'
set udg_Weapon_Upgrade[i] = 'I05X'
// Bombs
set i = i + 1
set udg_Weapon_Basic[i] = 'I02Z'
set udg_Weapon_Upgrade[i] = 'I03C'
// Bonfire
set i = i + 1
set udg_Weapon_Basic[i] = 'I055'
set udg_Weapon_Upgrade[i] = 'I056'
// Confusion Magic
set i = i + 1
set udg_Weapon_Basic[i] = 'I01B'
set udg_Weapon_Upgrade[i] = 'I02Q'
// Darkness Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I01R'
set udg_Weapon_Upgrade[i] = 'I028'
// Death Magic
set i = i + 1
set udg_Weapon_Basic[i] = 'I018'
set udg_Weapon_Upgrade[i] = 'I02J'
// Devils Curse
set i = i + 1
set udg_Weapon_Basic[i] = 'I01Q'
set udg_Weapon_Upgrade[i] = 'I03E'
// Electro Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I00G'
set udg_Weapon_Upgrade[i] = 'I02E'
// Energy Torpedos
set i = i + 1
set udg_Weapon_Basic[i] = 'I05Y'
set udg_Weapon_Upgrade[i] = 'I05Z'
// Fan Of Knives
set i = i + 1
set udg_Weapon_Basic[i] = 'I00A'
set udg_Weapon_Upgrade[i] = 'I026'
// Fear Magic
set i = i + 1
set udg_Weapon_Basic[i] = 'I01G'
set udg_Weapon_Upgrade[i] = 'I02D'
// Fire Arrows
set i = i + 1
set udg_Weapon_Basic[i] = 'I02W'
set udg_Weapon_Upgrade[i] = 'I02R'
// Flak
set i = i + 1
set udg_Weapon_Basic[i] = 'I057'
set udg_Weapon_Upgrade[i] = 'I058'
// Fire Magic
set i = i + 1
set udg_Weapon_Basic[i] = 'I01E'
set udg_Weapon_Upgrade[i] = 'I02V'
// Fireball Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I000'
set udg_Weapon_Upgrade[i] = 'I032'
// Flamer
set i = i + 1
set udg_Weapon_Basic[i] = 'I001'
set udg_Weapon_Upgrade[i] = 'I02X'
// Frost Laser
set i = i + 1
set udg_Weapon_Basic[i] = 'I02U'
set udg_Weapon_Upgrade[i] = 'I030'
// Frost Magic (Creep)
set i = i + 1
set udg_Weapon_Basic[i] = 'I00F'
set udg_Weapon_Upgrade[i] = 'I02C'
// Frost Magic (Normal
set i = i + 1
set udg_Weapon_Basic[i] = 'I02C'
set udg_Weapon_Upgrade[i] = 'I00F'
// Ghosts Of Doom
set i = i + 1
set udg_Weapon_Basic[i] = 'I010'
set udg_Weapon_Upgrade[i] = 'I031'
// Glaive Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I002'
set udg_Weapon_Upgrade[i] = 'I03A'
// Gods Hammer
set i = i + 1
set udg_Weapon_Basic[i] = 'I01H'
set udg_Weapon_Upgrade[i] = 'I035'
// Ice Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I00J'
set udg_Weapon_Upgrade[i] = 'I03D'
// Infernal Rocks
set i = i + 1
set udg_Weapon_Basic[i] = 'I00K'
set udg_Weapon_Upgrade[i] = 'I039'
// Ion Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I01S'
set udg_Weapon_Upgrade[i] = 'I01T'
// Laser (Medium)
set i = i + 1
set udg_Weapon_Basic[i] = 'I01N'
set udg_Weapon_Upgrade[i] = 'I00D'
// Laser (Short)
set i = i + 1
set udg_Weapon_Basic[i] = 'I01O'
set udg_Weapon_Upgrade[i] = 'I01N'
// Lightning Magic
set i = i + 1
set udg_Weapon_Basic[i] = 'I04L'
set udg_Weapon_Upgrade[i] = 'I04N'
// Light Plasma Gun
set i = i + 1
set udg_Weapon_Basic[i] = 'I00C'
set udg_Weapon_Upgrade[i] = 'I02A'
// Magic Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I017'
set udg_Weapon_Upgrade[i] = 'I033'
// Molotov Cocktail
set i = i + 1
set udg_Weapon_Basic[i] = 'I01P'
set udg_Weapon_Upgrade[i] = 'I03H'
// Multi Bow (Normal)
set i = i + 1
set udg_Weapon_Basic[i] = 'I00N'
set udg_Weapon_Upgrade[i] = 'I03I'
// Photon Bombs
set i = i + 1
set udg_Weapon_Basic[i] = 'I01Y'
set udg_Weapon_Upgrade[i] = 'I03J'
// Plasma Waves
set i = i + 1
set udg_Weapon_Basic[i] = 'I003'
set udg_Weapon_Upgrade[i] = 'I02F'
// Poison Magic
set i = i + 1
set udg_Weapon_Basic[i] = 'I016'
set udg_Weapon_Upgrade[i] = 'I03K'
// Psycho Laser
set i = i + 1
set udg_Weapon_Basic[i] = 'I00M'
set udg_Weapon_Upgrade[i] = 'I03L'
// Psycho Magic
set i = i + 1
set udg_Weapon_Basic[i] = 'I019'
set udg_Weapon_Upgrade[i] = 'I027'
// Rocket Hail
set i = i + 1
set udg_Weapon_Basic[i] = 'I060'
set udg_Weapon_Upgrade[i] = 'I061'
// Super Cell
set i = i + 1
set udg_Weapon_Basic[i] = 'I05E'
set udg_Weapon_Upgrade[i] = 'I05F'
// Swarm of Chaos
set i = i + 1
set udg_Weapon_Basic[i] = 'I05C'
set udg_Weapon_Upgrade[i] = 'I05D'
// Swarm Rockets
set i = i + 1
set udg_Weapon_Basic[i] = 'I005'
set udg_Weapon_Upgrade[i] = 'I01A'
// The Light Fantastic
set i = i + 1
set udg_Weapon_Basic[i] = 'I04M'
set udg_Weapon_Upgrade[i] = 'I04K'
// Tornado Summoner
set i = i + 1
set udg_Weapon_Basic[i] = 'I01D'
set udg_Weapon_Upgrade[i] = 'I03M'
// Mystic Cannon
set i = i + 1
set udg_Weapon_Basic[i] = 'I05B'
set udg_Weapon_Upgrade[i] = 'I03E'
// Energy Spears
set i = i + 1
set udg_Weapon_Basic[i] = 'I05J'
set udg_Weapon_Upgrade[i] = 'I05K'
// Gamma Vortex
set i = i + 1
set udg_Weapon_Basic[i] = 'I064'
set udg_Weapon_Upgrade[i] = 'I065'
// Lightning Rdd
set i = i + 1
set udg_Weapon_Basic[i] = 'I066'
set udg_Weapon_Upgrade[i] = 'I067'
//switchable weapons
// Burning Projectiles (Building)
set i = i + 1
set udg_Weapon_Basic[i] = 'I00H'
set udg_Weapon_Upgrade[i] = 'I02P'
// Burning Projectiles (Normal)
set i = i + 1
set udg_Weapon_Basic[i] = 'I02P'
set udg_Weapon_Upgrade[i] = 'I00H'
// Grenade Launcher (Air)
set i = i + 1
set udg_Weapon_Basic[i] = 'I02Y'
set udg_Weapon_Upgrade[i] = 'I02O'
// Grenade Launcher (Normal)
set i = i + 1
set udg_Weapon_Basic[i] = 'I02O'
set udg_Weapon_Upgrade[i] = 'I02Y'
// Plasma Fragments (Normal)
set i = i + 1
set udg_Weapon_Basic[i] = 'I007'
set udg_Weapon_Upgrade[i] = 'I024'
// Plasma Fragments (Air)
set i = i + 1
set udg_Weapon_Basic[i] = 'I024'
set udg_Weapon_Upgrade[i] = 'I007'
// Rock Catapult (Building)
set i = i + 1
set udg_Weapon_Basic[i] = 'I01I'
set udg_Weapon_Upgrade[i] = 'I01Z'
// Rock Catapult (Normal)
set i = i + 1
set udg_Weapon_Basic[i] = 'I01Z'
set udg_Weapon_Upgrade[i] = 'I01I'
// Soulstone (Creep)
set i = i + 1
set udg_Weapon_Basic[i] = 'I038'
set udg_Weapon_Upgrade[i] = 'I01C'
// Soulstone (Hero)
set i = i + 1
set udg_Weapon_Basic[i] = 'I01C'
set udg_Weapon_Upgrade[i] = 'I038'
// Star Shooter (Normal)
set i = i + 1
set udg_Weapon_Basic[i] = 'I05H'
set udg_Weapon_Upgrade[i] = 'I05I'
// Star Shooter (Ground)
set i = i + 1
set udg_Weapon_Basic[i] = 'I05I'
set udg_Weapon_Upgrade[i] = 'I05H'
//Other upgradeble items
// Small Explosive
//set i = i + 1
//set udg_Weapon_Basic[i] = 'I01W'
//set udg_Weapon_Upgrade[i] = 'I01X'
// Large Explosive
//set i = i + 1
//set udg_Weapon_Basic[i] = 'I01X'
//set udg_Weapon_Upgrade[i] = 'I04D'
// Iron Hull
set i = i + 1
set udg_Weapon_Basic[i] = 'I02H'
set udg_Weapon_Upgrade[i] = 'I04S'
// Steel Hull
set i = i + 1
set udg_Weapon_Basic[i] = 'I00R'
set udg_Weapon_Upgrade[i] = 'I04U'
// Gold Hull
set i = i + 1
set udg_Weapon_Basic[i] = 'I00Q'
set udg_Weapon_Upgrade[i] = 'I04T'
// Repair-Robots
set i = i + 1
set udg_Weapon_Basic[i] = 'I00S'
set udg_Weapon_Upgrade[i] = 'I00T'
// Upgraded Speed
set i = i + 1
set udg_Weapon_Basic[i] = 'I00V'
set udg_Weapon_Upgrade[i] = 'I00W'
// Burst Armor
set i = i + 1
set udg_Weapon_Basic[i] = 'I05N'
set udg_Weapon_Upgrade[i] = 'I05U'
// Deflective
set i = i + 1
set udg_Weapon_Basic[i] = 'I05O'
set udg_Weapon_Upgrade[i] = 'I05T'
set gg_trg_Items_Upgrade = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Upgrade, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddCondition( gg_trg_Items_Upgrade, Condition( function Trig_Items_Upgrade_Conditions ) )
call TriggerAddAction( gg_trg_Items_Upgrade, function Trig_Items_Upgrade_Actions )
endfunction
//TESH.scrollpos=204
//TESH.alwaysfold=0
globals
BluePrint SpeedPack
BluePrint PowerPack
BluePrint UltimatePack
BluePrint MineDefusePack
BluePrint StrengthPack
BluePrint TraderHunterPack
BluePrint MassConverter
BluePrint AdvancedTroopCommand
BluePrint NegatorPack
BluePrint EmergencyRepair
BluePrint KineticShield
endglobals
struct BluePrint
integer BlueprintId // The id of the blueprint itself
integer TargetItemId // The id of the item that is being created through the combination
integer PartCount // The number of different items that are required
integer array Parts[6] // The required items
integer array BasicParts[6] // Any item, that may be upgraded / combined into a required item (has to share the same index with the required item)
integer Requirements // The required number of armor upgrades
integer TotalCosts // The sum of the required items costs
static method Create takes integer bpId, integer targetId, integer itemcount, integer req returns BluePrint
local BluePrint i = BluePrint.allocate()
set i.BlueprintId = bpId
set i.TargetItemId = targetId
set i.PartCount = itemcount
set i.Requirements = req
set i.TotalCosts = 0
return i
endmethod
static method GetBluePrint takes integer blueprintId returns BluePrint
if ( blueprintId == SpeedPack.BlueprintId ) or ( blueprintId == SpeedPack.TargetItemId ) then
return SpeedPack
elseif ( blueprintId == PowerPack.BlueprintId ) or ( blueprintId == PowerPack.TargetItemId ) then
return PowerPack
elseif ( blueprintId == UltimatePack.BlueprintId ) or ( blueprintId == UltimatePack.TargetItemId ) then
return UltimatePack
elseif ( blueprintId == TraderHunterPack.BlueprintId ) or ( blueprintId == TraderHunterPack.TargetItemId ) then
return TraderHunterPack
elseif ( blueprintId == MineDefusePack.BlueprintId ) or ( blueprintId == MineDefusePack.TargetItemId ) then
return MineDefusePack
elseif ( blueprintId == StrengthPack.BlueprintId ) or ( blueprintId == StrengthPack.TargetItemId ) then
return StrengthPack
elseif ( blueprintId == MassConverter.BlueprintId ) or ( blueprintId == MassConverter.TargetItemId ) then
return MassConverter
elseif ( blueprintId == AdvancedTroopCommand.BlueprintId ) or ( blueprintId == AdvancedTroopCommand.TargetItemId ) then
return AdvancedTroopCommand
elseif ( blueprintId == NegatorPack.BlueprintId ) or ( blueprintId == NegatorPack.TargetItemId ) then
return NegatorPack
elseif ( blueprintId == EmergencyRepair.BlueprintId ) or ( blueprintId == EmergencyRepair.TargetItemId ) then
return EmergencyRepair
elseif ( blueprintId == KineticShield.BlueprintId ) or ( blueprintId == KineticShield.TargetItemId ) then
return KineticShield
endif
return 0
endmethod
method GetTotalCosts takes nothing returns integer
local integer i = 0
loop
exitwhen i >= this.PartCount
set this.TotalCosts = this.TotalCosts + GetItemCosts(this.Parts[i])
set i = i + 1
endloop
return this.TotalCosts
endmethod
// Checks for items in your inventory and if the are parts of the blueprint you currently want to use
// When the player has enough gold and / or items for the blueprint, a positive number will be returned
// If that is not the case, a negative number will be returned, which represents the amount of gold the player still needs to complete the blueprint
// If the number is positive and the buy flag is true, every found part of the blueprint will be removed from your inventory and the cost of those items will be accounted for, when
// considering the total amount the player still has to pay (this gold will also be removed in this function, so that after the execution, all that is left is adding the actual item)
method CompletePack takes unit target, boolean buy returns integer
local player owner = GetOwningPlayer(target)
local BluePrint subPack
local integer i = 0
local integer soldGold = 0
local integer oldGold = GetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD)
local item array SellThis
local integer array OldItems
local integer result = 0
// save the items before combining them, in case they have to be restored
loop
exitwhen i > UnitInventorySize(target)
set OldItems[i] = GetItemTypeId(UnitItemInSlot(target, i))
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= this.PartCount
if (UnitHasItemOfTypeBJ(target, this.Parts[i])) then
set SellThis[i] = UnitItemInSlot(target, GetInventoryIndexOfItemTypeBJ(target, this.Parts[i])-1)
set soldGold = soldGold + R2I(GetWidgetLife(SellThis[i]))
// the required item is a combination of other items, so check if the unit carries any of these parts
elseif (this.BasicParts[i] == 'PACK') then
// recursive call, combine the parts you already own into the required pack that is part of the item combination you originally wanted to create
// this actually manipulates the items in the inventroy, as well as the players gold
set subPack = BluePrint.GetBluePrint(this.Parts[i])
set result = subPack.CompletePack(target, true)
if (result < 0) then
set soldGold = soldGold + subPack.TotalCosts
//set SellThis[i] = UnitAddItemById( target, subPack.TargetItemId )
//call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl", target, "origin" ) )
else
set soldGold = soldGold + (subPack.TotalCosts - GetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD) - result)
endif
elseif (UnitHasItemOfTypeBJ(target, this.BasicParts[i])) then
set SellThis[i] = UnitItemInSlot(target, GetInventoryIndexOfItemTypeBJ(target, this.BasicParts[i])-1)
set soldGold = soldGold + R2I(GetWidgetLife(SellThis[i]))
endif
set i = i + 1
endloop
// a positive 'result' means, that the player didn't have enough gold to finish the pack that was part of the combination
if (((this.TotalCosts - soldGold) <= GetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD)) and (result <= 0)) then
set i = 0
loop
exitwhen i >= this.PartCount
if (SellThis[i] != null) then
call RemoveItem( SellThis[i] )
endif
set i = i + 1
endloop
if buy then
call SetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD) - this.TotalCosts + soldGold)
endif
set result = -1
else
// combining failed, so revert every change that has been made
set result = this.TotalCosts - soldGold - GetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD)
call SetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD, oldGold)
set i = 0
loop
exitwhen i > (UnitInventorySize(target)-1)
if (OldItems[i] != GetItemTypeId(UnitItemInSlot(target, i))) then
if (UnitItemInSlot(target, i) != null) then
call RemoveItem(UnitItemInSlot(target, i))
endif
call UnitAddItemById(target, OldItems[i])
endif
set i = i + 1
endloop
endif
set i = 0
loop
exitwhen i >= UnitInventorySize(target)
set SellThis[i] = null
set i = i + 1
endloop
return result
endmethod
endstruct
function Trig_Items_Combine_Actions takes nothing returns nothing
local unit U = GetBuyingUnit()
local integer blueprint = GetUnitTypeId(GetSoldUnit())
local integer armorlevel = GetPlayerTechCount(GetOwningPlayer(U), 'R003', true)
local integer result
local BluePrint targetPrint = BluePrint.GetBluePrint(blueprint)
local item temp
local string s = ""
if (targetPrint != 0) then
if ( targetPrint.Requirements <= armorlevel ) then
set result = targetPrint.CompletePack(U, true)
if (result < 0) then
set temp = CreateItem(targetPrint.TargetItemId, GetUnitX(U), GetUnitY(U))
call SetItemPlayer(temp, GetOwningPlayer(U), false)
call UnitAddItem( U, temp )
set temp = null
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl", U, "origin" ) )
else
set s = "|cfffed312You need|r " + I2S(result) + " |cfffed312more gold.|r"
endif
else
set s = "|cfffed312You need at least|r " + I2S(targetPrint.Requirements) + "|cfffed312 armor upgrades.|r"
endif
if ( s != "" ) then
call AdjustPlayerStateBJ( GetUnitPointValue(GetSoldUnit()), GetOwningPlayer(U), PLAYER_STATE_RESOURCE_GOLD )
if GetLocalPlayer() == GetOwningPlayer(U) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, s)
endif
endif
endif
set U = null
endfunction
//===========================================================================
function InitTrig_Items_Combine takes nothing returns nothing
set SpeedPack = BluePrint.Create('z00H', 'I012', 2, 4)
set SpeedPack.Parts[0] = 'I014' // Teleporter
set SpeedPack.Parts[1] = 'I00W' // Speed Boost (Upgrade)
set SpeedPack.BasicParts[1] = 'I00V' // Speed Boost
call SpeedPack.GetTotalCosts()
set PowerPack = BluePrint.Create('z00S', 'I011', 2, 8)
set PowerPack.Parts[0] = 'I04T' // Gold Hull (Upgrade)
set PowerPack.Parts[1] = 'I00P' // Extended Repair Kit
set PowerPack.BasicParts[0] = 'I00Q' // Gold Hull
call PowerPack.GetTotalCosts()
set UltimatePack = BluePrint.Create('z00T', 'I01J', 3, 9)
set UltimatePack.Parts[0] = 'I012' // Speed Pack
set UltimatePack.Parts[1] = 'I02G' // Radar
set UltimatePack.Parts[2] = 'I00T' // Repair Robots (Upgrade)
set UltimatePack.BasicParts[0] = 'PACK' // Dummy
set UltimatePack.BasicParts[2] = 'I00S' // Repair Robots
call UltimatePack.GetTotalCosts()
set MineDefusePack = BluePrint.Create('z00V', 'I04R', 3, 0)
set MineDefusePack.Parts[0] = 'I02K' // Remote Fuse
set MineDefusePack.Parts[1] = 'I02G' // Radar
set MineDefusePack.Parts[2] = 'I04S' // Iron Hull (Upgrade)
set MineDefusePack.BasicParts[2] = 'I02H' // Iron Hull
call MineDefusePack.GetTotalCosts()
set StrengthPack = BluePrint.Create('z01S', 'I052', 2, 3)
set StrengthPack.Parts[0] = 'I04U' // Steel Hull (Upgrade)
set StrengthPack.Parts[1] = 'I00O' // Repair Kit
set StrengthPack.BasicParts[0] = 'I00R' // Steel Hull
call StrengthPack.GetTotalCosts()
set TraderHunterPack = BluePrint.Create('z00U', 'I00L', 2, 3)
set TraderHunterPack.Parts[0] = 'I014' // Teleporter
set TraderHunterPack.Parts[1] = 'I02G' // Radar
call TraderHunterPack.GetTotalCosts()
set MassConverter = BluePrint.Create('z00L', 'I05S', 3, 5)
set MassConverter.Parts[0] = 'I00T' // Repair Robots (Upgrade)
set MassConverter.Parts[1] = 'I05R' // Energy Converter
set MassConverter.Parts[2] = 'I05T' // Deflective Armor (Upgrade)
set MassConverter.BasicParts[0] = 'I00S' // Repair Robots
set MassConverter.BasicParts[2] = 'I05O' // Deflective Armor
call MassConverter.GetTotalCosts()
set AdvancedTroopCommand = BluePrint.Create('z01U', 'I053', 2, 4)
set AdvancedTroopCommand.Parts[0] = 'I00Y' // Troop Command
set AdvancedTroopCommand.Parts[1] = 'I04B' // Siege Pack
call AdvancedTroopCommand.GetTotalCosts()
set NegatorPack = BluePrint.Create('z01D', 'I05V', 2, 5)
set NegatorPack.Parts[0] = 'I052' // Strength Pack
set NegatorPack.Parts[1] = 'I05U' // Burst Armor (Upgrade)
set NegatorPack.BasicParts[0] = 'PACK' // Dummy
set NegatorPack.BasicParts[1] = 'I05N' // Burst Armor
call NegatorPack.GetTotalCosts()
set EmergencyRepair = BluePrint.Create('z02A', 'I06A', 3, 2)
set EmergencyRepair.Parts[0] = 'I069' // Area Boost
set EmergencyRepair.Parts[1] = 'I05R' // Energy Converter
set EmergencyRepair.Parts[2] = 'I00O' // Repair Kit
call EmergencyRepair.GetTotalCosts()
set KineticShield = BluePrint.Create('z02B', 'I06B', 2, 1)
set KineticShield.Parts[0] = 'I069' // Area Boost
set KineticShield.Parts[1] = 'I04S' // Iron Hull (Upgrade)
set KineticShield.BasicParts[1] = 'I02H' // Iron Hull
call KineticShield.GetTotalCosts()
set gg_trg_Items_Combine = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Combine, EVENT_PLAYER_UNIT_SELL )
call TriggerAddAction( gg_trg_Items_Combine, function Trig_Items_Combine_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Explosives_Upgrade_Actions takes nothing returns nothing
local unit U = GetBuyingUnit()
local integer blueprint = GetUnitTypeId(GetSoldUnit())
local string s = ""
if ( blueprint == 'z01C' ) then
// Small -> Large Explosives
if UnitHasItemOfTypeBJ(U, 'I01W') then
call RemoveItem( GetItemOfTypeFromUnitBJ(U, 'I01W') )
call UnitAddItemById( U, 'I01X' )
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl", U, "origin" ) )
// Large -> Huge Explosives
elseif UnitHasItemOfTypeBJ(U, 'I01X') then
call RemoveItem( GetItemOfTypeFromUnitBJ(U, 'I01X') )
call UnitAddItemById( U, 'I04D' )
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl", U, "origin" ) )
else
set s = "|cfffed312You don't have the necessary items.|r"
endif
if ( s != "" ) then
call AdjustPlayerStateBJ( GetUnitPointValue(GetSoldUnit()), GetOwningPlayer(U), PLAYER_STATE_RESOURCE_GOLD )
if GetLocalPlayer() == GetOwningPlayer(U) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, s)
endif
endif
endif
set U = null
endfunction
//===========================================================================
function InitTrig_Items_Explosives_Upgrade takes nothing returns nothing
set gg_trg_Items_Explosives_Upgrade = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Explosives_Upgrade, EVENT_PLAYER_UNIT_SELL )
call TriggerAddAction( gg_trg_Items_Explosives_Upgrade, function Trig_Explosives_Upgrade_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Items_Tinker_Tower_Weapon_Conditions takes nothing returns boolean
return (GetItemType(GetManipulatedItem()) == ITEM_TYPE_ARTIFACT) and (IsTinkerTower(GetTriggerUnit()))
endfunction
function Trig_Items_Tinker_Tower_Weapon_Actions takes nothing returns nothing
local unit tower = GetTriggerUnit()
local unit enum
local item weapon = GetManipulatedItem()
local boolean found = false
local group G = NewGroup()
//Search for the nearby hero and give the item back to him
//Does not work with Tech Mechs as of yet
call GroupEnumUnitsInRange(G, GetUnitX(tower),GetUnitY(tower), 450, FILTER_ANY_TANK )
loop
set enum = FirstOfGroup(G)
exitwhen enum == null
if (enum == udg_Tank[GetPlayerNr(GetOwningPlayer(tower))]) then
set found = true
if (UnitInventoryCount(enum) < 6) then
call UnitAddItem(enum, weapon)
else
call SetItemPosition(weapon, GetUnitX(enum), GetUnitY(enum))
endif
endif
call GroupRemoveUnit(G, enum)
endloop
//When no hero has been found, drop it at the base of the tower (hard to see, because the Tower has no collision size)
if (found == false) then
call ItemDropInvalid(GetTriggerUnit(), GetManipulatedItem())
endif
if GetLocalPlayer() == GetOwningPlayer(GetTriggerUnit()) then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312Tinker Towers cannot carry any weapons.|r")
endif
call ReleaseGroup(G)
set G = null
set tower = null
set weapon = null
endfunction
//===========================================================================
function InitTrig_Items_Tinker_Tower_Weapon takes nothing returns nothing
set gg_trg_Items_Tinker_Tower_Weapon = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Tinker_Tower_Weapon, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( gg_trg_Items_Tinker_Tower_Weapon, Condition( function Trig_Items_Tinker_Tower_Weapon_Conditions ) )
call TriggerAddAction( gg_trg_Items_Tinker_Tower_Weapon, function Trig_Items_Tinker_Tower_Weapon_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Items_Module_Remove_Conditions takes nothing returns boolean
return GetItemType(GetManipulatedItem()) == ITEM_TYPE_POWERUP or GetItemTypeId(GetManipulatedItem()) == 'I051' or GetItemTypeId(GetManipulatedItem()) == 'I048'
endfunction
function Trig_Items_Module_Remove_Actions_Child takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = GetHandleIndex(t)
call RemoveItem( udg_AV_Item1[i] )
call ReleaseTimer(t)
call ReleaseHandleIndex(i)
endfunction
function Trig_Items_Module_Remove_Actions takes nothing returns nothing
local timer t = NewTimer()
local integer i = NewTimerIndex(t)
set udg_AV_Item1[i] = GetManipulatedItem()
call TimerStart(t,0.00,false,function Trig_Items_Module_Remove_Actions_Child)
endfunction
//===========================================================================
function InitTrig_Items_Module_Remove takes nothing returns nothing
set gg_trg_Items_Module_Remove = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Items_Module_Remove, EVENT_PLAYER_UNIT_DROP_ITEM )
call TriggerAddCondition( gg_trg_Items_Module_Remove, Condition( function Trig_Items_Module_Remove_Conditions ) )
call TriggerAddAction( gg_trg_Items_Module_Remove, function Trig_Items_Module_Remove_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ShowItemOwners initializer Init
private function Conditions takes nothing returns boolean
if (GetSoldUnit() != null) then
return GetUnitTypeId(GetSoldUnit())=='z01R'
endif
// Heroes or Tech Mechs
return IsUnitType(GetEnteringUnit(), UNIT_TYPE_HERO) or IsTechMech(GetEnteringUnit())
endfunction
private function Text takes string s, real x, real y, player p returns nothing
local texttag tag = CreateTextTag()
call SetTextTagVisibility(tag,false)
if GetLocalPlayer() == p then
call SetTextTagVisibility(tag,true)
endif
call SetTextTagText(tag, s, 0.017)
call SetTextTagPos(tag,x,y,50.0)
call SetTextTagVelocity(tag, 0, 0.00)
call SetTextTagFadepoint(tag, 2)
call SetTextTagLifespan(tag, 5)
call SetTextTagPermanent(tag, false)
set tag = null
endfunction
private function DisplayItemInfo takes nothing returns nothing
local item Item = GetEnumItem()
local integer Gold = R2I(GetWidgetLife(Item))
local string s
if Gold>=1000 and IsPlayerAlly(GetItemPlayer(Item),GetPlayer(udg_TempInt)) and GetItemUserData(Item)==2 then
if GetItemPlayer(Item)==GetPlayer(udg_TempInt) then
set Gold = Gold/2
else
set Gold = Gold*3/4
endif
set s = udg_Color[GetPlayerNr(GetItemPlayer(Item))]+GetPlayerName(GetItemPlayer(Item))+"|r (|cffffcc00"+I2S(Gold)+"|r)"
call Text(s, GetItemX(Item), GetItemY(Item), GetPlayer(udg_TempInt))
endif
set Item = null
endfunction
private function Actions takes nothing returns nothing
local rect r
if (GetSoldUnit() == null) then
set udg_TempInt = GetPlayerNr(GetOwningPlayer(GetEnteringUnit()))
else
set udg_TempInt = GetPlayerNr(GetOwningPlayer(GetSoldUnit()))
call RemoveUnit(GetSoldUnit())
endif
set r = udg_JunkyardRect[udg_Player_Team[udg_TempInt]]
call SetRect(udg_TempRect,GetRectMinX(r)-500,GetRectMinY(r)-500,GetRectMaxX(r)+500,GetRectMaxY(r)+500)
set r = null
call EnumItemsInRect( udg_TempRect, FILTER_NULL, function DisplayItemInfo)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SELL )
call TriggerRegisterEnterRectSimple( t, gg_rct_Team_1_Junkyard )
call TriggerRegisterEnterRectSimple( t, gg_rct_Team_2_Junkyard )
call TriggerAddCondition(t, Condition( function Conditions ) )
call TriggerAddAction(t, function Actions )
endfunction
endscope
//TESH.scrollpos=16
//TESH.alwaysfold=0
function Trig_Take_items_from_Force_Conditions takes nothing returns boolean
local string order = (OrderId2String(GetUnitCurrentOrder(GetTriggerUnit())))
// should never be the case, but does indeed happen, i.e. at the start of the game
if GetOrderTargetUnit() == null then
return false
endif
//The target has to be a structure with an inventory, owned by the force and the player tank has to be ordered to move to this structure
return (GetPlayerNr(GetOwningPlayer(GetOrderTargetUnit())) > 10) and IsForceTower(GetOrderTargetUnit()) and ((order == "smart") or (order == "move"))
endfunction
function Trig_Take_items_from_Force_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local unit tower = udg_AV_Unit2[LoopTimerId]
local string order = (OrderId2String(GetUnitCurrentOrder(U)))
local integer i = 0
local real dx = GetUnitX(U)-GetUnitX(tower)
local real dy = GetUnitY(U)-GetUnitY(tower)
if dx*dx+dy*dy <= 250*250 then
loop
exitwhen i > 5
//Only get your own items
if(GetItemPlayer(UnitItemInSlot(tower, i)) == GetOwningPlayer(U)) then
//Don't get Tower Modules, since a tank can't use them
if (GetItemType(UnitItemInSlot(tower, i)) != ITEM_TYPE_POWERUP) then
call UnitDropItemTarget(tower, UnitItemInSlot(tower, i), U)
//call UnitDropItemPoint(tower, UnitItemInSlot(tower, i), GetUnitX(tower), GetUnitY(tower))
//call UnitAddItem(U, UnitItemInSlot(tower, i))
endif
endif
set i = i + 1
endloop
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
// When you are not yet near enough, you still need to target the tower to keep this trigger running
elseif (order != "smart") and (order != "move") then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set U = null
set tower = null
endfunction
function Trig_Take_items_from_Force_Actions takes nothing returns nothing
local timer t
local integer LoopTimerId
local unit U = GetTriggerUnit()
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Unit2[LoopTimerId] = GetOrderTargetUnit()
call TimerStart(t , 0.25 , true , function Trig_Take_items_from_Force_Loop)
set U = null
endfunction
//===========================================================================
function InitTrig_Take_items_from_Force takes nothing returns nothing
set gg_trg_Take_items_from_Force = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Take_items_from_Force, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerAddCondition( gg_trg_Take_items_from_Force, Condition( function Trig_Take_items_from_Force_Conditions ) )
call TriggerAddAction( gg_trg_Take_items_from_Force, function Trig_Take_items_from_Force_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Advanced_Troop_Command_Actions takes nothing returns nothing
local integer i = 1
local real beginGameTime = TimerGetElapsed(udg_GameTime)
local unit Caster = GetTriggerUnit()
local unit temp
local player Owner = GetOwningPlayer(Caster)
//local real time = ADVANCED_TROOP_COMMAND_DELAY * (TeamCount_AdvancedTroopCommand[udg_Player_Team[GetPlayerNr(Owner)]]-1)
local real time = ADVANCED_TROOP_COMMAND_DELAY * (TeamCount_TroopCommand[udg_Player_Team[GetPlayerNr(Owner)]]-1)
if ( GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_USED) <= GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_CAP) - udg_TC_Food[1] ) then
loop
exitwhen i > 9
if GetPlayerState(GetOwningPlayer(GetTriggerUnit()), PLAYER_STATE_RESOURCE_FOOD_USED) <= GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_CAP) - udg_TC_Food[i] and not IsUnitDeadBJ(Caster) then
if i < 6 then
set temp = CreateUnit(Owner,udg_TC_Unit[i], GetUnitX(Caster), GetUnitY(Caster), 90)
elseif i < 9 then
set temp = CreateUnit(Owner,'z01O', GetUnitX(Caster), GetUnitY(Caster), 90)
else
set temp = CreateUnit(Owner,udg_Aura_Creeps[GetRandomInt(1, 3)], GetUnitX(Caster), GetUnitY(Caster), 90)
endif
call UnitApplyTimedLife( temp, 'BTLF', 20.00 )
call SetLaneCreepFlag(temp, CF_COSTS_FOOD)
call IssuePointOrderLoc( temp, "attack", udg_Move_Points[GetTargetMovePoint(Caster)] )
call SetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_USED, GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_USED) + udg_TC_Food[i])
set udg_Stats_CreepBuy[GetPlayerNr(Owner)] = udg_Stats_CreepBuy[GetPlayerNr(Owner)] + 1
call GameTimeWait(time)
endif
set i = i + 1
endloop
else
if GetLocalPlayer() == Owner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You reached the unit limit of 40.|r" )
endif
call IssueImmediateOrder( Caster, "stop" )
endif
set Caster = null
set Owner = null
set temp = null
endfunction
//===========================================================================
function InitTrig_Advanced_Troop_Command takes nothing returns nothing
set gg_trg_Advanced_Troop_Command = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Advanced_Troop_Command, 'A09I' )
call TriggerAddAction( gg_trg_Advanced_Troop_Command, function Trig_Advanced_Troop_Command_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Battery_Conditions takes nothing returns boolean
local integer Id = GetUnitTypeId(GetSoldUnit())
return Id == 'z025'
endfunction
function Trig_Battery_Actions takes nothing returns nothing
local unit U = GetBuyingUnit()
local unit battery = GetSoldUnit()
local integer playerId = GetPlayerNr(GetOwningPlayer(U))
if ( ManaUpgrade[playerId] == 10 ) then
call SetPlayerState(GetOwningPlayer(U), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetOwningPlayer(U), PLAYER_STATE_RESOURCE_GOLD) + R2I(GetWidgetLife(battery)))
call DisplayTextToPlayer(GetOwningPlayer(U), 0, 0, "|cfffed312You can't buy more than 10 upgrades for your Mana.|r" )
else
set ManaUpgrade[playerId] = ManaUpgrade[playerId] +1
call ApplyManaUpgrade(playerId)
call DestroyEffect(AddSpecialEffectTarget( "Abilities\\Spells\\Items\\AIim\\AIimTarget.mdl", U, "origin" ))
endif
set U = null
set battery = null
endfunction
//===========================================================================
function InitTrig_Battery takes nothing returns nothing
set gg_trg_Battery = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Battery, EVENT_PLAYER_UNIT_SELL )
call TriggerAddCondition( gg_trg_Battery, Condition( function Trig_Battery_Conditions ) )
call TriggerAddAction( gg_trg_Battery, function Trig_Battery_Actions )
endfunction
//TESH.scrollpos=9
//TESH.alwaysfold=0
scope BlackSunProject initializer Init
globals
private constant integer BUILDING_ID = 'o004'
private constant integer SUN_ID = 'h02I'
private constant integer NIGHT_ID = 'A0FN'
private constant real HP_DRAIN = 0.0075 // percent of its max HP per second
private constant real MANA_DRAIN = 3.0
private constant real CHARGE_RANGE = 700
private constant real ATTACK_RANGE = 1050
private constant real MOVEMENT_SPEED = 75.0
private constant real CHARGE_INTERVAL = 1.0
private constant real MOVE_INTERVAL = 0.05
private constant real ATTACK_INTERVAL = 2.00
endglobals
function Trig_Black_Sun_Project_Conditions takes nothing returns boolean
return (GetUnitTypeId(GetConstructedStructure()) == BUILDING_ID)
endfunction
function Trig_Black_Sun_Project_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Sun = udg_AV_Unit1[LoopTimerId]
local unit Target
local real targetX = udg_AV_Real1[LoopTimerId]
local real targetY = udg_AV_Real2[LoopTimerId]
local group G
local real DistX
local real DistY
local real DistanceLeft
local real speed = MOVEMENT_SPEED * MOVE_INTERVAL
local real damage
call UnitDamageTarget(Sun, Sun, GetUnitState(Sun, UNIT_STATE_MAX_LIFE)*HP_DRAIN*MOVE_INTERVAL, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
if (GetUnitState(Sun, UNIT_STATE_LIFE) <= 0) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
set DistX = targetX-GetUnitX(Sun)
set DistY = targetY-GetUnitY(Sun)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if (GetUnitFlyHeight(Sun) < 500) then
call SetUnitFlyHeight( Sun, GetUnitFlyHeight(Sun) + 1, 0 )
endif
/*
if DistanceLeft <= speed then
call SetUnitX(Sun, targetX)
call SetUnitY(Sun, targetY)
else
call SetUnitX(Sun, GetUnitX(Sun)+speed*DistX/DistanceLeft)
call SetUnitY(Sun, GetUnitY(Sun)+speed*DistY/DistanceLeft)
endif
*/
if (ModuloInteger(udg_AV_Int1[LoopTimerId], R2I(ATTACK_INTERVAL / MOVE_INTERVAL)) == 0) then
call IssueImmediateOrderById( CreateDummyWithAbilityCoord(GetOwningPlayer(Sun), NIGHT_ID, 1, GetUnitX(Sun), GetUnitY(Sun), 0), 852621 )
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(Sun)
call GroupEnumUnitsInRange(G, GetUnitX(Sun),GetUnitY(Sun), ATTACK_RANGE, FILTER_ENEMY_BUILDING_OR_TANK)
if (FirstOfGroup(G) != null) then
set Target = GroupPickRandomUnit(G)
call DestroyEffect(AddSpecialEffectTarget("war3mapImported\\DarkLightning.mdl",Target,"origin"))
call DestroyEffect(AddSpecialEffectTarget("war3mapImported\\DarkLightningNova.mdl",Target,"origin"))
set damage = GetUnitState(Target, UNIT_STATE_MAX_LIFE) / 4
call UnitDamageTarget(Sun, Target, damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
set Target = null
endif
call ReleaseGroup(G)
set G = null
endif
endif
set Sun = null
endfunction
function Trig_Black_Sun_Project_Charge takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Sun = udg_AV_Unit1[LoopTimerId]
local unit Reactor = udg_AV_Unit2[LoopTimerId]
local unit temp
local group G = NewGroup()
local real visibility
local integer team
local timer t
local integer MoveTimerId
local real rallyX
local real rallyY
local real hpPercentage
// Check if the reactor has the pause ability; if yes -> collect mana; if not -> don't collect
if (GetUnitAbilityLevel(Reactor, BSP_PAUSE_ABILITY_ID) > 0) then
call GroupEnumUnitsInRange(G, GetUnitX(Reactor),GetUnitY(Reactor), CHARGE_RANGE, FILTER_ANY_TANK)
//call SetUnitState(Reactor, UNIT_STATE_MANA, GetUnitState(Reactor, UNIT_STATE_MANA) + 1)
loop
set temp = FirstOfGroup(G)
exitwhen (temp == null)
if (GetUnitState(temp, UNIT_STATE_MANA) >= MANA_DRAIN) then
call SetUnitState(temp, UNIT_STATE_MANA, GetUnitState(temp, UNIT_STATE_MANA) - MANA_DRAIN)
call SetUnitState(Reactor, UNIT_STATE_MANA, GetUnitState(Reactor, UNIT_STATE_MANA) + MANA_DRAIN)
call Lightning.CreateUU("DRAM", Reactor, temp, true, false, 0.4)
endif
call GroupRemoveUnit(G, temp)
endloop
endif
if (GetUnitState(Reactor, UNIT_STATE_MANA) >= GetUnitState(Reactor, UNIT_STATE_MAX_MANA)) /*
*/ or (GetUnitState(Reactor, UNIT_STATE_LIFE) <= 0) then
set team = udg_Player_Team[GetPlayerNr(GetOwningPlayer(Reactor))]
call RemoveUnit(Sun)
set Sun = CreateUnit(GetOwningPlayer(Reactor), SUN_ID, GetUnitX(Reactor), GetUnitY(Reactor), 270)
call SetUnitTimeScale( Sun, 0.3 )
if (GetUnitState(Reactor, UNIT_STATE_LIFE) <= 0) then
set hpPercentage = GetUnitState(Reactor, UNIT_STATE_MANA) / GetUnitState(Reactor, UNIT_STATE_MAX_MANA)
call DebugMsg("HP: " + R2S(hpPercentage))
call SetUnitState(Sun, UNIT_STATE_LIFE, hpPercentage * GetUnitState(Sun, UNIT_STATE_MAX_LIFE))
endif
call IssueImmediateOrderById( CreateDummyWithAbilityCoord(GetOwningPlayer(Sun), NIGHT_ID, 1, GetUnitX(Sun), GetUnitY(Sun), 0), 852621 )
set rallyX = GetLocationX(GetUnitRallyPoint(Reactor))
set rallyY = GetLocationY(GetUnitRallyPoint(Reactor))
if ((rallyX + rallyY) == 0) then
// no rally point ( =target for the sun) has been set, take the enemy HQ as a target instead)
set rallyX = GetUnitX(udg_HQ[3-team])
set rallyY = GetUnitY(udg_HQ[3-team])
endif
call IssuePointOrder(Sun, "move", rallyX, rallyY)
set t = NewTimer()
set MoveTimerId = NewTimerIndex(t)
set udg_AV_Unit1[MoveTimerId] = Sun
set udg_AV_Int1[MoveTimerId] = 0
set udg_AV_Real1[MoveTimerId] = rallyX
set udg_AV_Real2[MoveTimerId] = rallyY
call TimerStart(t, MOVE_INTERVAL, true, function Trig_Black_Sun_Project_Loop)
call KillUnit(Reactor)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set visibility = 0 + (255 / GetUnitState(Reactor, UNIT_STATE_MAX_MANA) * GetUnitState(Reactor, UNIT_STATE_MANA))
call SetUnitVertexColor( Sun, 255, 255, 255, R2I(visibility) )
endif
call ReleaseGroup(G)
set G = null
set Reactor = null
set Sun = null
endfunction
function Trig_Black_Sun_Project_Actions takes nothing returns nothing
local unit builder = GetTriggerUnit()
local unit Reactor = GetConstructedStructure()
local timer t
local integer LoopTimerId
local integer team = udg_Player_Team[GetPlayerNr(GetOwningPlayer(builder))]
local unit Sun = CreateUnit(GetOwningPlayer(builder), SUN_ID, GetUnitX(Reactor), GetUnitY(Reactor), 270)
local real height = GetUnitZ(Reactor) - GetUnitZ(Sun)
call UnitAddAbility(Sun, 'Aloc')
call SetUnitFlyHeight( Sun, GetUnitFlyHeight(Sun) + height, 0 )
// Set the position again, so the new height gets updated
call SetUnitPosition(Sun, GetUnitX(Reactor), GetUnitY(Reactor))
call PauseUnit(Sun, true)
call SetUnitVertexColor( Sun, 255, 255, 255, 0 )
call SetUnitTimeScale( Sun, 0.3 )
call MakeUnitInvulnerable(Sun, true)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Sun
set udg_AV_Unit2[LoopTimerId] = Reactor
call TimerStart(t, CHARGE_INTERVAL, true, function Trig_Black_Sun_Project_Charge)
set builder = null
set Reactor = null
set Sun = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Black_Sun_Project = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Black_Sun_Project, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH )
call TriggerAddCondition( gg_trg_Black_Sun_Project, Condition( function Trig_Black_Sun_Project_Conditions ) )
call TriggerAddAction( gg_trg_Black_Sun_Project, function Trig_Black_Sun_Project_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope BlackSunProjectUnPause initializer Init
globals
constant integer BSP_PAUSE_ABILITY_ID = 'A0H5'
constant integer BSP_UNPAUSE_ABILITY_ID = 'A0H6'
endglobals
function Trig_BlackSunProjectUnPause_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer abilityId = GetSpellAbilityId()
if (abilityId == BSP_PAUSE_ABILITY_ID) then
call UnitRemoveAbility(Caster, abilityId)
call UnitAddAbility(Caster, BSP_UNPAUSE_ABILITY_ID)
elseif (abilityId == BSP_UNPAUSE_ABILITY_ID) then
call UnitRemoveAbility(Caster, abilityId)
call UnitAddAbility(Caster, BSP_PAUSE_ABILITY_ID)
endif
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Black_Sun_Project_UnPause = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Black_Sun_Project_UnPause, BSP_PAUSE_ABILITY_ID )
call TriggerRegisterSpellEffectEvent( gg_trg_Black_Sun_Project_UnPause, BSP_UNPAUSE_ABILITY_ID )
call TriggerAddAction( gg_trg_Black_Sun_Project_UnPause, function Trig_BlackSunProjectUnPause_Actions )
endfunction
endscope
//TESH.scrollpos=18
//TESH.alwaysfold=0
function Trig_Bomb_Channel_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02B'
endfunction
function Trig_Bomb_Channel_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local location TargetLoc = GetSpellTargetLoc()
local effect PreEffect
local real beginGameTime = TimerGetElapsed(udg_GameTime)
local real UnitX = GetUnitX(Caster)
local real UnitY = GetUnitY(Caster)
local real timeRemaining
local real DistX
local real DistY
local integer playerNr = GetPlayerNr(GetOwningPlayer(Caster))
local item Bomb
local integer BombOrder = GetUnitCurrentOrder(Caster)
local boolean Allowed = true
local group G = NewGroup()
set udg_Filter_Player =GetOwningPlayer(Caster)
//Unit belongs to team 1 and is in team 1 base -> check if there are enemy factories
if (udg_Player_Team[playerNr] == 1) and RectContainsUnit(gg_rct_Team_1_Base_Main, Caster) then
call GroupEnumUnitsInRect(G, gg_rct_Team_1_Base_Main, FILTER_ENEMY_FACTORY)
set Allowed = FirstOfGroup(G) != null
//Unit belongs to team 2 and is in team 2 base -> check if there are enemy factories
elseif (udg_Player_Team[playerNr] == 2) and RectContainsUnit(gg_rct_Team_2_Base_Main, Caster) then
call GroupEnumUnitsInRect(G, gg_rct_Team_2_Base_Main, FILTER_ENEMY_FACTORY)
set Allowed = FirstOfGroup(G) != null
endif
//When there are no enemy factories, you are forbidden to use the bomb
if (Allowed == false) then
if (GetLocalPlayer() == GetOwningPlayer(Caster)) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, ( "|cfffed312You cannot place a bomb in your own base.|r" ) )
endif
call IssueImmediateOrder( Caster, "stop" )
set Bomb = null
else
call GetPathableLoc(TargetLoc,12,100000)
set DistX = GetLocationX(TargetLoc) - UnitX
set DistY = GetLocationY(TargetLoc) - UnitY
if DistX*DistX+DistY*DistY > 40000 then
//I04Q - normal Bomb
//I04V - Bomb from the Trade Master
set Bomb = UnitItemInSlot(Caster,GetInventoryIndexOfItemTypeBJ(Caster, 'I04Q')-1)
if Bomb==null then
set Bomb = UnitItemInSlot(Caster,GetInventoryIndexOfItemTypeBJ(Caster, 'I04V')-1)
endif
call IssueImmediateOrder( Caster, "stop" )
call UnitUseItemPoint( Caster, Bomb, GetLocationX(TargetLoc), GetLocationY(TargetLoc) )
call TriggerSleepAction( 0 )
call UnitUseItemPoint( Caster, Bomb, GetLocationX(TargetLoc), GetLocationY(TargetLoc) )
set Bomb = null
else
set PreEffect = AddSpecialEffectLoc( "Abilities\\Spells\\Orc\\Voodoo\\VoodooAura.mdl", TargetLoc )
loop
set timeRemaining = beginGameTime+6-TimerGetElapsed(udg_GameTime)
if timeRemaining > 3 then
exitwhen UnitX != GetUnitX(Caster) or UnitY != GetUnitY(Caster) or IsUnitDeadBJ(Caster) or GetUnitCurrentOrder(Caster)!=BombOrder
else
exitwhen timeRemaining <= 0
endif
call TriggerSleepAction( 0.1 )
endloop
call DestroyEffect( PreEffect )
set PreEffect = null
endif
endif
call ReleaseGroup(G)
set G = null
call RemoveLocation( TargetLoc )
set TargetLoc = null
set Caster = null
endfunction
//===========================================================================
function InitTrig_Bomb_Channel takes nothing returns nothing
set gg_trg_Bomb_Channel = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Bomb_Channel, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_Bomb_Channel, Condition( function Trig_Bomb_Channel_Conditions ) )
call TriggerAddAction( gg_trg_Bomb_Channel, function Trig_Bomb_Channel_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Bomb_Setting_Conditions takes nothing returns boolean
return GetUnitTypeId(GetSummonedUnit()) == 'h00V'
endfunction
function Trig_Bomb_Setting_Actions takes nothing returns nothing
call UnitApplyTimedLife(GetSummonedUnit(), 'BTLF', 3.00)
call FloatingTimedLife(GetSummonedUnit(), 3, null, "|cffff0000", "!|r")
endfunction
//===========================================================================
function InitTrig_Bomb_Setting takes nothing returns nothing
set gg_trg_Bomb_Setting = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Bomb_Setting, EVENT_PLAYER_UNIT_SUMMON )
call TriggerAddCondition( gg_trg_Bomb_Setting, Condition( function Trig_Bomb_Setting_Conditions ) )
call TriggerAddAction( gg_trg_Bomb_Setting, function Trig_Bomb_Setting_Actions )
endfunction
//TESH.scrollpos=68
//TESH.alwaysfold=0
function Trig_Bomb_Explosion_Conditions takes nothing returns boolean
if GetUnitTypeId(GetTriggerUnit()) == 'h00V' then
return GetKillingUnit() == null
endif
return GetUnitTypeId(GetTriggerUnit()) == 'h004'
endfunction
function Trig_Bomb_Explosion_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Explosion = udg_AV_Unit1[LoopTimerId]
local integer i = udg_AV_Int1[LoopTimerId]
local real x = GetUnitX(Explosion)
local real y = GetUnitY(Explosion)
local real FireX
local real FireY
local real FireCurrentAngle
local real CurrentRadius = 1000-(IAbsBJ(i-10)*80)
local real Damage = 1000 * (1.0 + 0.05 * I2R(GetPlayerTechCount(GetOwningPlayer(Explosion), 'R002', true)) )
local unit U
local group G = NewGroup()
call DestroyTreesInRange(x, y, CurrentRadius*1.1)
call GroupEnumUnitsInRange(G, x, y, CurrentRadius, FILTER_ALIVE)
if i <= 10 then
set CurrentRadius = CurrentRadius*0.9
set FireCurrentAngle = GetRandomReal(0,11)
loop
exitwhen FireCurrentAngle >= 360
set FireX = x + CurrentRadius*Cos(FireCurrentAngle*bj_DEGTORAD)
set FireY = y + CurrentRadius*Sin(FireCurrentAngle*bj_DEGTORAD)
if not udg_NoEffects then
call DestroyEffect(AddSpecialEffect("war3mapImported\\BreathOfFireDamage2.mdl", FireX + GetRandomReal(-70,70), FireY + GetRandomReal(-70,70)))
call DestroyEffect(AddSpecialEffect("war3mapImported\\ImpaleTargetDust2.mdl", FireX, FireY))
endif
set FireCurrentAngle = FireCurrentAngle + 12
endloop
loop
set U = FirstOfGroup(G)
exitwhen U == null
if GetUnitAbilityLevel(U, 'B01N') > 0 then
call UnitDamageTarget(Explosion, U, Damage/3, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
else
call UnitDamageTarget(Explosion, U, Damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
endif
call GroupRemoveUnit(G, U)
endloop
else
loop
set U = FirstOfGroup(G)
exitwhen U == null
if GetUnitAbilityLevel(U, 'B01N') > 0 then
call UnitDamageTarget(Explosion, U, Damage/12, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
else
call UnitDamageTarget(Explosion, U, Damage/4, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
endif
call GroupRemoveUnit(G, U)
endloop
endif
if i < 20 then
set udg_AV_Int1[LoopTimerId] = i + 1
else
call PauseTimer(GetExpiredTimer())
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
call ReleaseGroup(G)
set G = null
set Explosion = null
endfunction
function Trig_Bomb_Explosion_Actions takes nothing returns nothing
local unit Bomb = GetTriggerUnit()
local real x = GetUnitX(Bomb)
local real y = GetUnitY(Bomb)
local player Owner = GetOwningPlayer(Bomb)
local integer i = 1
local fogmodifier FogMod = CreateFogModifierRadius(Owner, FOG_OF_WAR_VISIBLE, x, y, 1200, true, false)
local integer LoopTimerId
local timer t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
call TimerStart(t,0.23,true,function Trig_Bomb_Explosion_Loop)
call FogModifierStart(FogMod)
if GetUnitTypeId(Bomb) == 'h00V' then
call RemoveUnit(Bomb)
endif
set Bomb = null
set udg_AV_Unit1[LoopTimerId] = CreateExplosionSizedTimed(Owner,x,y,4.8,0.10)
set udg_AV_Int1[LoopTimerId] = 1
set i = 1
loop
call CreateExplosionSizedTimed(Owner,x,y,4.8,0.10)
exitwhen i == 5
set i = i + 1
endloop
set Owner = null
call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", x, y))
call ShakeCamAtLoc(x,y,1000,2,5.0)
call FlashPointSizedTimed(x,y,100,1000,0.5,5.0)
call GameTimeWait( 5.0 )
call DestroyFogModifier( FogMod )
set FogMod = null
endfunction
//===========================================================================
function InitTrig_Bomb_Explosion takes nothing returns nothing
set gg_trg_Bomb_Explosion = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Bomb_Explosion, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Bomb_Explosion, Condition( function Trig_Bomb_Explosion_Conditions ) )
call TriggerAddAction( gg_trg_Bomb_Explosion, function Trig_Bomb_Explosion_Actions )
endfunction
//TESH.scrollpos=6
//TESH.alwaysfold=0
function AdjustManaRegen takes nothing returns nothing
local unit TCC = GetEnumUnit()
local integer nr = GetPlayerNr(GetOwningPlayer(TCC))
if ( GetUnitState(TCC, UNIT_STATE_LIFE) > 0 ) then
call SetUnitAbilityLevel( TCC, 'A090', udg_Team_CPs[udg_Player_Team[nr]] + 1 )
endif
set TCC = null
endfunction
function Trig_Build_Troop_Command_Center_Actions takes nothing returns nothing
local unit Builder = GetTriggerUnit()
local integer nr = GetPlayerNr(GetOwningPlayer(Builder))
local group g
//Because of a timing problem, the mana setting occurs in the "Building established" trigger
if ( udg_Command_Center[udg_Player_Team[nr]] < udg_TCC_Max ) then
set udg_Command_Center[udg_Player_Team[nr]] = ( udg_Command_Center[udg_Player_Team[nr]] + 1 )
set udg_Stats_Buildings[nr] = ( udg_Stats_Buildings[nr] + 1 )
call TriggerSleepAction( 0.00 )
set g = GetUnitsOfTypeIdAll('h01K')
call ForGroup( g, function AdjustManaRegen )
call DestroyGroup( g )
set g = null
else
call IssueImmediateOrder( Builder, "stop" )
if GetLocalPlayer()==GetOwningPlayer(Builder) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312Your team can only have up to two Troop Command Center at a time.|r")
endif
endif
set Builder = null
endfunction
//===========================================================================
function InitTrig_Build_Troop_Command_Center takes nothing returns nothing
set gg_trg_Build_Troop_Command_Center = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Build_Troop_Command_Center, 'A09Y' )
call TriggerAddAction( gg_trg_Build_Troop_Command_Center, function Trig_Build_Troop_Command_Center_Actions )
endfunction
//TESH.scrollpos=191
//TESH.alwaysfold=0
scope BurstArmor initializer Init
globals
constant integer BURST_ITEM_ID = 'I05N'
constant integer BURST_UPGRADE_ITEM_ID = 'I05U'
private constant integer BURST_BUFF_ABILITY_ID = 'A0EC'
private constant integer BURST_UPGRADE_BUFF_ABILITY_ID = 'A00M'
private constant integer BURST_BUFF_ID = 'B026'
private constant integer BURST_UPGRADE_BUFF_ID = 'B02M'
private constant real BURST_BLOCK = 600.0
private constant real BURST_UPGRADE_BLOCK = 999999.0
private constant real BURST_BLOCK_THRESHOLD = 100.0 // you have to take at least this much damage, for the block to trigger
private constant real BURST_UPGRADE_BLOCK_THRESHOLD = 500.0
private constant real BURST_COOLDOWN = 4.0
private constant real BURST_UPGRADE_COOLDOWN = 4.0
private constant real BURST_UPGRADE_DURATION = 0.25
constant integer DEFLECTIVE_ITEM_ID = 'I05O'
constant integer DEFLECTIVE_UPGRADE_ITEM_ID = 'I05T'
constant integer DEFLECTIVE_BUFF_ABILITY_ID = 'A0C7' //'A0AL'
constant integer DEFLECTIVE_UPGRADE_BUFF_ABILITY_ID = 'A04S'
private constant integer DEFLECTIVE_BUFF_ID = 'B02I'
private constant integer DEFLECTIVE_UPGRADE_BUFF_ID = 'B02N'
private constant real DEFLECTIVE_BLOCK = 50.0
private constant real DEFLECTIVE_UPGRADE_BLOCK = 50.0
private constant real DEFLECTIVE_COOLDOWN = 0.33
private constant real DEFLECTIVE_UPGRADE_COOLDOWN = 0.0 // this value is not actually used, since a wait of 0 seconds would still miss some damage instances
private constant real DEFLECTIVE_BLOCK_LIMIT = 0.40 // the maximum percentage of the original damage that is possible to be blocked
private constant real DEFLECTIVE_UPGRADE_BLOCK_LIMIT = 0.40
private integer array deflectiveBlockReady[10]
private boolean array burstUpgradeIsActive[10]
private integer DD_ID
endglobals
function Trig_Blocking_Armor_Reactivate_Child takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local integer itemId = udg_AV_Int2[LoopTimerId]
local integer abilityId = udg_AV_Int1[LoopTimerId]
local integer pId = GetPlayerNr(GetOwningPlayer(udg_AV_Unit1[LoopTimerId]))
if UnitHasItemOfTypeBJ(udg_AV_Unit1[LoopTimerId], itemId) then
if (abilityId == DEFLECTIVE_BUFF_ABILITY_ID) then
if (deflectiveBlockReady[pId] == 0) then
set deflectiveBlockReady[pId] = deflectiveBlockReady[pId] + 1
call EnableSkillDamageDetection(DD_ID)
endif
else
if (GetUnitAbilityLevel(udg_AV_Unit1[LoopTimerId], abilityId) == 0) then
call UnitAddAbility(udg_AV_Unit1[LoopTimerId], abilityId)
call EnableSkillDamageDetection(DD_ID)
endif
endif
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endfunction
function Trig_Blocking_Armor_Reactivate takes unit U, integer armorId returns nothing
local timer t
local integer LoopTimerId
local integer pId = GetPlayerNr(GetOwningPlayer(U))
if (armorId == BURST_ITEM_ID) then
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Int1[LoopTimerId] = BURST_BUFF_ABILITY_ID
set udg_AV_Int2[LoopTimerId] = BURST_ITEM_ID
call TimerStart(t,BURST_COOLDOWN,false, function Trig_Blocking_Armor_Reactivate_Child)
elseif (armorId == BURST_UPGRADE_ITEM_ID) then
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Int1[LoopTimerId] = BURST_UPGRADE_BUFF_ABILITY_ID
set udg_AV_Int2[LoopTimerId] = BURST_UPGRADE_ITEM_ID
call TimerStart(t,BURST_COOLDOWN,false, function Trig_Blocking_Armor_Reactivate_Child)
elseif (armorId == DEFLECTIVE_ITEM_ID) then
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Int1[LoopTimerId] = DEFLECTIVE_BUFF_ABILITY_ID
set udg_AV_Int2[LoopTimerId] = DEFLECTIVE_ITEM_ID
call TimerStart(t,DEFLECTIVE_COOLDOWN,false, function Trig_Blocking_Armor_Reactivate_Child)
elseif (armorId == DEFLECTIVE_UPGRADE_ITEM_ID) then
if (GetUnitAbilityLevel(U, DEFLECTIVE_UPGRADE_BUFF_ABILITY_ID) == 0) then
call UnitAddAbility(U, DEFLECTIVE_UPGRADE_BUFF_ABILITY_ID)
call EnableSkillDamageDetection(DD_ID)
endif
endif
endfunction
function Trig_Blocking_Armor_Deactivate takes unit U, integer armorId returns nothing
local integer pId = GetPlayerNr(GetOwningPlayer(U))
if (armorId == BURST_ITEM_ID) then
if (GetUnitAbilityLevel(U, BURST_BUFF_ABILITY_ID) > 0) then
call DisableSkillDamageDetection(DD_ID)
endif
call UnitRemoveAbility(U, BURST_BUFF_ABILITY_ID)
call UnitRemoveAbility(U, BURST_BUFF_ID)
elseif (armorId == BURST_UPGRADE_ITEM_ID) then
if (GetUnitAbilityLevel(U, BURST_UPGRADE_BUFF_ABILITY_ID) > 0) then
call DisableSkillDamageDetection(DD_ID)
endif
call UnitRemoveAbility(U, BURST_UPGRADE_BUFF_ABILITY_ID)
call UnitRemoveAbility(U, BURST_UPGRADE_BUFF_ID)
elseif (armorId == DEFLECTIVE_ITEM_ID) then
//if (GetUnitAbilityLevel(U, DEFLECTIVE_BUFF_ABILITY_ID) > 0) then
if (deflectiveBlockReady[pId] > 0) then
set deflectiveBlockReady[pId] = deflectiveBlockReady[pId] - 1
call DisableSkillDamageDetection(DD_ID)
endif
// Adding and removing abilities disrupt the target tank, since this happens fairly often with Deflective, the buff has been removed
//call UnitRemoveAbility(U, DEFLECTIVE_BUFF_ABILITY_ID)
//call UnitRemoveAbility(U, DEFLECTIVE_BUFF_ID)
elseif (armorId == DEFLECTIVE_UPGRADE_ITEM_ID) then
if (GetUnitAbilityLevel(U, DEFLECTIVE_UPGRADE_BUFF_ABILITY_ID) > 0) then
call DisableSkillDamageDetection(DD_ID)
endif
call UnitRemoveAbility(U, DEFLECTIVE_UPGRADE_BUFF_ABILITY_ID)
call UnitRemoveAbility(U, DEFLECTIVE_UPGRADE_BUFF_ID)
endif
endfunction
function Trig_Blocking_Armor_Delayed_Reactivation_Child takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local integer itemId = udg_AV_Int2[LoopTimerId]
local unit target = udg_AV_Unit1[LoopTimerId]
set burstUpgradeIsActive[GetPlayerNr(GetOwningPlayer(target))] = false
call Trig_Blocking_Armor_Deactivate(target, itemId)
call Trig_Blocking_Armor_Reactivate(target, itemId)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
set target = null
endfunction
function Trig_Blocking_Armor_Delayed_Reactivation takes unit U, integer armorId returns nothing
local timer t
local integer LoopTimerId
local integer pId = GetPlayerNr(GetOwningPlayer(U))
if (armorId == BURST_UPGRADE_ITEM_ID) and (burstUpgradeIsActive[pId] == false) then
set burstUpgradeIsActive[pId] = true
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Int2[LoopTimerId] = BURST_UPGRADE_ITEM_ID
call TimerStart(t,BURST_UPGRADE_DURATION,false, function Trig_Blocking_Armor_Delayed_Reactivation_Child)
endif
endfunction
function Trig_Blocking_Armor_DamageDetection takes nothing returns real
local integer sId = GetPlayerNr(GetOwningPlayer(DamageDetection_DamageSource))
local integer tId = GetPlayerNr(GetOwningPlayer(DamageDetection_DamageTarget))
local integer burstLevel = GetUnitAbilityLevel(DamageDetection_DamageTarget, BURST_BUFF_ABILITY_ID)
local integer burstUpgradeLevel = GetUnitAbilityLevel(DamageDetection_DamageTarget, BURST_UPGRADE_BUFF_ABILITY_ID)
local integer deflectiveLevel = deflectiveBlockReady[tId]//GetUnitAbilityLevel(DamageDetection_DamageTarget, DEFLECTIVE_BUFF_ABILITY_ID)
local integer deflectiveUpgradeLevel = GetUnitAbilityLevel(DamageDetection_DamageTarget, DEFLECTIVE_UPGRADE_BUFF_ABILITY_ID)
if (sId <= GetMaxHumanPlayers()) then
if (IsUnitEnemy(DamageDetection_DamageSource, GetOwningPlayer(DamageDetection_DamageTarget))) then
if (burstLevel > 0) and (DamageDetection_Damage >= BURST_BLOCK_THRESHOLD) then
call Trig_Blocking_Armor_Deactivate(DamageDetection_DamageTarget, BURST_ITEM_ID)
call Trig_Blocking_Armor_Reactivate(DamageDetection_DamageTarget, BURST_ITEM_ID)
// the damage system interprets postive values as additional damage and negative ones as reduced damage
return -BURST_BLOCK
elseif (burstUpgradeLevel > 0) and (DamageDetection_Damage >= BURST_UPGRADE_BLOCK_THRESHOLD) then
call Trig_Blocking_Armor_Delayed_Reactivation(DamageDetection_DamageTarget, BURST_UPGRADE_ITEM_ID)
// the damage system interprets postive values as additional damage and negative ones as reduced damage
return -BURST_UPGRADE_BLOCK
elseif deflectiveLevel > 0 then
call Trig_Blocking_Armor_Deactivate(DamageDetection_DamageTarget, DEFLECTIVE_ITEM_ID)
call Trig_Blocking_Armor_Reactivate(DamageDetection_DamageTarget, DEFLECTIVE_ITEM_ID)
// the damage system interprets postive values as additional damage and negative ones as reduced damage
return RMaxBJ(-DEFLECTIVE_BLOCK, -DamageDetection_Damage*DEFLECTIVE_BLOCK_LIMIT)
elseif deflectiveUpgradeLevel > 0 then
// the damage system interprets postive values as additional damage and negative ones as reduced damage
return RMaxBJ(-DEFLECTIVE_UPGRADE_BLOCK, -DamageDetection_Damage*DEFLECTIVE_UPGRADE_BLOCK_LIMIT)
endif
endif
endif
return 0.0
endfunction
function Trig_Blocking_Armor_Conditions takes nothing returns boolean
return IsBlockingArmor(GetManipulatedItem())
endfunction
function Trig_Blocking_Armor_DropActions takes nothing returns nothing
local unit U = GetManipulatingUnit()
local item armor = GetManipulatedItem()
call DebugMsg("Dropped blocking armor")
if (GetItemTypeId(armor) == BURST_ITEM_ID) then
call Trig_Blocking_Armor_Deactivate(U, BURST_ITEM_ID)
elseif (GetItemTypeId(armor) == BURST_UPGRADE_ITEM_ID) then
call Trig_Blocking_Armor_Deactivate(U, BURST_UPGRADE_ITEM_ID)
elseif (GetItemTypeId(armor) == DEFLECTIVE_ITEM_ID) then
call Trig_Blocking_Armor_Deactivate(U, DEFLECTIVE_ITEM_ID)
elseif (GetItemTypeId(armor) == DEFLECTIVE_UPGRADE_ITEM_ID) then
call Trig_Blocking_Armor_Deactivate(U, DEFLECTIVE_UPGRADE_ITEM_ID)
endif
set U = null
set armor = null
endfunction
function Trig_Blocking_Armor_Actions takes nothing returns nothing
local unit U = GetManipulatingUnit()
local item armor = GetManipulatedItem()
call DebugMsg("Picked blocking armor up")
if (GetItemTypeId(armor) == BURST_ITEM_ID) then
if UnitHasItemOfTypeBJ(U, DEFLECTIVE_ITEM_ID) or UnitHasItemOfTypeBJ(U, BURST_UPGRADE_ITEM_ID) or UnitHasItemOfTypeBJ(U, DEFLECTIVE_UPGRADE_ITEM_ID) then
// Do nothing, you already have the ability of one of the other armors
elseif (CountItemTypeInInventory(U, BURST_ITEM_ID) == 1) then
call Trig_Blocking_Armor_Reactivate(U, BURST_ITEM_ID)
endif
elseif (GetItemTypeId(armor) == BURST_UPGRADE_ITEM_ID) then
if UnitHasItemOfTypeBJ(U, DEFLECTIVE_ITEM_ID) or UnitHasItemOfTypeBJ(U, BURST_ITEM_ID) or UnitHasItemOfTypeBJ(U, DEFLECTIVE_UPGRADE_ITEM_ID) then
// Do nothing, you already have the ability of one of the other armors
elseif (CountItemTypeInInventory(U, BURST_UPGRADE_ITEM_ID) == 1) then
call Trig_Blocking_Armor_Reactivate(U, BURST_UPGRADE_ITEM_ID)
endif
elseif (GetItemTypeId(armor) == DEFLECTIVE_ITEM_ID) then
if UnitHasItemOfTypeBJ(U, BURST_ITEM_ID) or UnitHasItemOfTypeBJ(U, BURST_UPGRADE_ITEM_ID) or UnitHasItemOfTypeBJ(U, DEFLECTIVE_UPGRADE_ITEM_ID) then
// Do nothing, you already have the ability of one of the other armors
elseif (CountItemTypeInInventory(U, DEFLECTIVE_ITEM_ID) == 1) then
call Trig_Blocking_Armor_Reactivate(U, DEFLECTIVE_ITEM_ID)
endif
elseif (GetItemTypeId(armor) == DEFLECTIVE_UPGRADE_ITEM_ID) then
if UnitHasItemOfTypeBJ(U, BURST_ITEM_ID) or UnitHasItemOfTypeBJ(U, BURST_UPGRADE_ITEM_ID) or UnitHasItemOfTypeBJ(U, DEFLECTIVE_ITEM_ID) then
// Do nothing, you already have the ability of one of the other armors
elseif (CountItemTypeInInventory(U, DEFLECTIVE_UPGRADE_ITEM_ID) == 1) then
call Trig_Blocking_Armor_Reactivate(U, DEFLECTIVE_UPGRADE_ITEM_ID)
endif
endif
set U = null
set armor = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 1
loop
exitwhen (i > 10)
set deflectiveBlockReady[i] = 0
set burstUpgradeIsActive[i] = false
set i = i + 1
endloop
set gg_trg_Blocking_Armor = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodeAbsolute(DamageAlterationFunction.Trig_Blocking_Armor_DamageDetection)
call TriggerRegisterAnyUnitEventBJ( gg_trg_Blocking_Armor, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( gg_trg_Blocking_Armor, Condition( function Trig_Blocking_Armor_Conditions ) )
call TriggerAddAction( gg_trg_Blocking_Armor, function Trig_Blocking_Armor_Actions )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_DROP_ITEM )
call TriggerAddCondition( t, Condition( function Trig_Blocking_Armor_Conditions ) )
call TriggerAddAction( t, function Trig_Blocking_Armor_DropActions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Center_Info_Conditions takes nothing returns boolean
return (GetUnitTypeId(GetTrainedUnit()) == 'z02C')
endfunction
function Trig_Center_Info_Actions takes nothing returns nothing
local integer i = 1
local location CasterLoc = GetUnitLoc(GetTriggerUnit())
local effect array effects
loop
exitwhen i > 36
set effects[i] = AddSpecialEffect("Doodads\\Cinematic\\GlowingRunes\\GlowingRunes6.mdl",GetLocationX(CasterLoc) + 3000.00 * Cos(i*10 * bj_DEGTORAD),GetLocationY(CasterLoc) + 3000.00 * Sin(i*10 * bj_DEGTORAD))
set i = i + 1
endloop
call GameTimeWait( 7.0 )
set i = 1
loop
exitwhen i > 36
call DestroyEffect(effects[i])
set effects[i] = null
set i = i + 1
endloop
call RemoveLocation( CasterLoc )
set CasterLoc = null
endfunction
//===========================================================================
function InitTrig_Center_Info takes nothing returns nothing
set gg_trg_Center_Info = CreateTrigger( )
//call TriggerRegisterSpellEffectEvent( gg_trg_Center_Info, 'A09B' )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Center_Info, EVENT_PLAYER_UNIT_TRAIN_FINISH )
call TriggerAddCondition( gg_trg_Center_Info, Condition( function Trig_Center_Info_Conditions ) )
call TriggerAddAction( gg_trg_Center_Info, function Trig_Center_Info_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Concealing_Engine_Conditions takes nothing returns boolean
return GetItemTypeId(GetManipulatedItem()) == 'I05P'
endfunction
function Trig_Concealing_Engine_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local real duration = 5.0
local location tmpLoc
call SetUnitPathing(Caster, false)
call UnitSetUsesAltIcon(Caster, true)
call GameTimeWait(duration)
set tmpLoc = GetUnitLoc(Caster)
if GetPathableLoc(tmpLoc , 32 , 768) then
call SetUnitPositionLoc(Caster, tmpLoc)
endif
call SetUnitPathing(Caster, true)
call UnitSetUsesAltIcon(Caster, false)
call RemoveLocation(tmpLoc)
set tmpLoc = null
set Caster = null
endfunction
//===========================================================================
function InitTrig_Concealing_Engine takes nothing returns nothing
set gg_trg_Concealing_Engine = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Concealing_Engine, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddCondition( gg_trg_Concealing_Engine, Condition( function Trig_Concealing_Engine_Conditions ) )
call TriggerAddAction( gg_trg_Concealing_Engine, function Trig_Concealing_Engine_Actions )
endfunction
//TESH.scrollpos=18
//TESH.alwaysfold=0
scope DefusePack initializer Init
globals
private constant integer REMOTE_FUSE_ID = 'A06B'
private constant integer DEFUSE_PACK_ID = 'A09W'
private constant real REMOTE_FUSE_RANGE = 125
private constant real DEFUSE_PACK_RANGE = 200
private constant real ALERT_RANGE = 700
endglobals
function Trig_Defuse_Pack_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit U
local player Owner = GetOwningPlayer(Caster)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local group G = NewGroup( )
local integer MinesNearby = 0
local real Range
call GroupEnumUnitsInRange(G, TargetX, TargetY, ALERT_RANGE, FILTER_NULL)
if GetSpellAbilityId() == REMOTE_FUSE_ID then
set Range = REMOTE_FUSE_RANGE
else
set Range = DEFUSE_PACK_RANGE
endif
loop
set U = FirstOfGroup( G )
exitwhen U == null
if (GetUnitState(U, UNIT_STATE_LIFE) > 0) then
// Destroy either any mine or enemy wards (wards are only destroyable by the defuse pack)
if (IsMine( U ) or IsAirMine(U) or (IsWard(U) and GetSpellAbilityId() == DEFUSE_PACK_ID)) then
if Pow(GetUnitX( U )-TargetX,2)+Pow(GetUnitY( U )-TargetY,2)<=Range*Range then
if IsMine(U) then
call SetUnitOwner( U, GetOwningPlayer(Caster), false )
call KillUnit( U )
elseif (IsAirMine(U) and IsUnitEnemy(U, Owner)) then
call SetUnitOwner( U, GetOwningPlayer(Caster), false )
call AirMines_Explode.evaluate( U )
elseif (IsWard(U) and IsUnitEnemy(U, Owner) or IsMine(U)) then
call KillUnit( U )
endif
else
if IsUnitEnemy(U, Owner) then
call ShowTextTag("|c00ff0000!|r", U, GetRandomInt(-200,200), GetRandomInt(-200,200), udg_Force[udg_Player_Team[GetPlayerNr(Owner)]])
endif
endif
endif
if (GetUnitAbilityLevel(U, EXPLOSIVE_BUFF_ID) > 0) and IsUnitEnemy(U, Owner) then
if Pow(GetUnitX( U )-TargetX,2)+Pow(GetUnitY( U )-TargetY,2)<=Range*Range then
call UnitBlowUpExplosives(U, Caster, false)
call UnitRemoveAbility(U, EXPLOSIVE_BUFF_ID)
call UnitRemoveAbility(U, EXPLOSIVE_BUFF_ABILITY_ID)
endif
endif
endif
call GroupRemoveUnit( G, U )
endloop
call ReleaseGroup( G )
set G = null
set U = null
set Caster = null
endfunction
//===========================================================================
function Init takes nothing returns nothing
set gg_trg_Defuse_Pack = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Defuse_Pack, REMOTE_FUSE_ID )
call TriggerRegisterSpellEffectEvent( gg_trg_Defuse_Pack, DEFUSE_PACK_ID )
call TriggerAddAction( gg_trg_Defuse_Pack, function Trig_Defuse_Pack_Actions )
endfunction
endscope
//TESH.scrollpos=5
//TESH.alwaysfold=0
scope EmergencyRepair initializer Init
globals
private constant integer ABILITY_ID = 'A0GD'
private constant integer ARMOR_ABILITY_ID = 'A0H8'
private constant integer BUFF_ID = 'B032'
private constant real MANA_HEAL = 25.0
private constant real LIFE_HEAL = 1000.0
private constant real MANA_UPGRADE_BONUS = 1.875
private constant real LIFE_UPGRADE_BONUS = 75.0
private constant real ARMOR_BONUS = 1.0 // Armor bonus per allied tank in range
private constant real AREA = 1000.0
private constant real DURATION = 10.0
endglobals
function Trig_Emergency_Repair_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit temp
local integer WeaponsLevel = GetPlayerTechCount(GetOwningPlayer(Caster), 'R002', true)
local integer ArmorLevel = GetPlayerTechCount(GetOwningPlayer(Caster), 'R003', true)
local integer unitCount = 0
local real hpHeal = LIFE_HEAL + ( LIFE_UPGRADE_BONUS * (WeaponsLevel + ArmorLevel))
local real manaHeal = MANA_HEAL + ( MANA_UPGRADE_BONUS * (WeaponsLevel + ArmorLevel))
local group G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(Caster)
call GroupEnumUnitsInRange(G, GetUnitX(Caster), GetUnitY(Caster), AREA, FILTER_ALLY_TANK)
loop
set temp = FirstOfGroup(G)
exitwhen (temp == null)
if (GetUnitAbilityLevel(temp, BUFF_ID) <= 0) then
call DebugMsg("Cast heal")
call HealOverTime(temp, hpHeal, manaHeal, DURATION, 0, true)
endif
set unitCount = unitCount + 1
call GroupRemoveUnit(G, temp)
endloop
call IssueImmediateOrderById( CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), ARMOR_ABILITY_ID, IMinBJ(5, unitCount), GetUnitX(Caster), GetUnitY(Caster), 0), 852269)
call ReleaseGroup(G)
set G = null
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Emergency_Repair = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Emergency_Repair, ABILITY_ID )
call TriggerAddAction( gg_trg_Emergency_Repair, function Trig_Emergency_Repair_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope EnergyConverter initializer Init
globals
private constant integer ITEM_ID = 'I05R'
private constant real MANA_REGENERATION = 1.0
endglobals
function Trig_Energy_Converter_Actions takes nothing returns nothing
local unit killer = GetKillingUnit()
local integer i = 0
local boolean result = false
loop
exitwhen (i >= 6) or result
if IsEnergyConverter(UnitItemInSlot(killer, i)) then
set result = true
endif
set i = i + 1
endloop
if (result) and (killer != null) and (GetUnitState(killer, UNIT_STATE_LIFE) > 0) then
call SetUnitState(killer, UNIT_STATE_MANA, GetUnitState(killer, UNIT_STATE_MANA) + MANA_REGENERATION)
endif
set killer = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Energy_Converter = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Energy_Converter, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( gg_trg_Energy_Converter, function Trig_Energy_Converter_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Explosive initializer Init
globals
private constant integer ABILITY_SMALL_ID = 'A08S'
private constant integer ABILITY_LARGE_ID = 'A0AE'
private constant integer ABILITY_HUGE_ID = 'A0AF'
private constant real DURATION = 3.0
private constant real INTERVAL = 0.20
constant integer EXPLOSIVE_BUFF_ABILITY_ID = 'A0FR'
constant integer EXPLOSIVE_BUFF_ID = 'B01X'
endglobals
function Trig_Explosive_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Caster = udg_AV_Unit1[LoopTimerId]
local integer color
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
set color = 55 + IMinBJ(R2I((DURATION - (udg_AV_Int1[LoopTimerId] * INTERVAL * 1.5)) * 200), 200)
call SetUnitVertexColor(Caster, 255, color, color, 255)
if (udg_AV_Int1[LoopTimerId] * INTERVAL >= DURATION) and (GetUnitAbilityLevel(Caster, EXPLOSIVE_BUFF_ID) > 0) then
call UnitBlowUpExplosives(Caster, Caster, false)
call UnitRemoveAbility(Caster, EXPLOSIVE_BUFF_ID)
call UnitRemoveAbility(Caster, EXPLOSIVE_BUFF_ABILITY_ID)
elseif (GetUnitState(Caster, UNIT_STATE_LIFE) <= 0) or IsUnitStunned(Caster) or (udg_AV_Int1[LoopTimerId] * INTERVAL > DURATION) then
call UnitRemoveAbility(Caster, EXPLOSIVE_BUFF_ID)
call UnitRemoveAbility(Caster, EXPLOSIVE_BUFF_ABILITY_ID)
call RefreshTransparency(Caster)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Caster = null
endfunction
function Trig_Explosive_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local timer t
local integer LoopTimerId
call PermanentTimedLife(Caster, DURATION, null, "|cffff0000", "!|r", 0, function PermanentTimedLife_Explosive)
call UnitAddAbility(Caster, EXPLOSIVE_BUFF_ABILITY_ID)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Caster
set udg_AV_Int1[LoopTimerId] = 0
call TimerStart(t, INTERVAL, true, function Trig_Explosive_Loop)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Explosive = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Explosive, ABILITY_SMALL_ID )
call TriggerRegisterSpellEffectEvent( gg_trg_Explosive, ABILITY_LARGE_ID )
call TriggerRegisterSpellEffectEvent( gg_trg_Explosive, ABILITY_HUGE_ID )
call TriggerAddAction( gg_trg_Explosive, function Trig_Explosive_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ExtendedRepairKit initializer Init
globals
private constant integer ABILITY_ID = 'A0C1'
private constant integer BUFF_ID = 'B02L'
private constant real MANA_HEAL = 0.0
private constant real LIFE_HEAL = 5000.0
private constant real MANA_UPGRADE_BONUS = 0.0
private constant real LIFE_UPGRADE_BONUS = 0.0
private constant real DURATION = 2.0
endglobals
function Trig_Extended_Repair_Kit_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer ArmorLevel = GetPlayerTechCount(GetOwningPlayer(Caster), 'R003', true)
local real hpHeal = LIFE_HEAL * (1 + LIFE_UPGRADE_BONUS * ArmorLevel)
local real manaHeal = MANA_HEAL * (1 + MANA_UPGRADE_BONUS * ArmorLevel)
call HealOverTime(Caster, hpHeal, manaHeal, DURATION, 0, false)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Extended_Repair_Kit = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Extended_Repair_Kit, ABILITY_ID )
call TriggerAddAction( gg_trg_Extended_Repair_Kit, function Trig_Extended_Repair_Kit_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Illusion_Pack_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
call DebugMsg("Illu")
if IssueTargetOrderById(CreateDummyWithAbilityCoord(GetOwningPlayer(U), 'A0F4', 1, GetUnitX(U), GetUnitY(U), 0), 852008, U) then
call DebugMsg("cast")
else
call DebugMsg("fail")
endif
set U = null
endfunction
//===========================================================================
function InitTrig_Illusion_Pack takes nothing returns nothing
set gg_trg_Illusion_Pack = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Illusion_Pack, 'A0AP' )
call TriggerAddAction( gg_trg_Illusion_Pack, function Trig_Illusion_Pack_Actions )
endfunction
//TESH.scrollpos=20
//TESH.alwaysfold=0
scope KineticShield initializer Init
globals
private constant integer ABILITY_ID = 'A0GF'
private constant integer BUFF_ABILITY_ID = 'A0GG'
private constant integer INITIAL_BUFF_ID = 'A0HB'
private constant integer BUFF_ID = 'B033'
private constant real DURATION = 10.0
private constant real AREA = 500.0
private constant real DAMAGE_BLOCK_BASE = 1000.0
private constant real DAMAGE_BLOCK_UP = 200.0
private constant real CHECK_INTERVAL = 0.25
constant integer KINETIC_SHIELD_ID = 'h00M'
private unit array Nearby_Shield[10]
private integer array Protected_Tanks_Count[10]
real array KS_TakenDamage[10]
private integer DD_ID
endglobals
function Trig_Kinetic_Shield_DamageDetection takes nothing returns real
local unit shield
local integer level = GetUnitAbilityLevel(DamageDetection_DamageTarget,BUFF_ID)
local integer ShieldId
local integer protectedTanks
local integer i = 1
local real maxBlock
local real damageBlocked = 0
local integer color
local group G
if (level > 0) then
set shield = Nearby_Shield[GetPlayerNr(GetOwningPlayer(DamageDetection_DamageTarget))]
if (shield != null) and (GetUnitState(shield, UNIT_STATE_LIFE) > 0) then
set ShieldId = GetPlayerNr(GetOwningPlayer(shield))
// If the enemy is within the shield, the damage won't get blocked
if (Nearby_Shield[GetPlayerNr(GetOwningPlayer(DamageDetection_DamageSource))] != shield) then
set maxBlock = GetUnitUserData(shield)
// if more than one tank is under the shield, the damage taken does not damage the shield as much
if (Protected_Tanks_Count[ShieldId] > 0) then
set damageBlocked = RMinBJ(DamageDetection_Damage / Protected_Tanks_Count[ShieldId], maxBlock - KS_TakenDamage[ShieldId])
endif
set KS_TakenDamage[ShieldId] = KS_TakenDamage[ShieldId] + damageBlocked
set color = R2I(RMaxBJ(((maxBlock - KS_TakenDamage[ShieldId]) / maxBlock) * 255, 50))
call SetUnitVertexColor( shield, color, color, color, 255 )
if (KS_TakenDamage[ShieldId] >= maxBlock) then
call DebugMsg("Kill Shield")
call KillUnit(shield)
endif
set shield = null
return -RMinBJ(DamageDetection_Damage, KS_TakenDamage[ShieldId])
endif
endif
endif
set shield = null
return 0.0
endfunction
function Trig_Kinetic_Shield_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Shield = udg_AV_Unit1[LoopTimerId]
local unit temp
local group G
local real DistX
local real DistY
local integer i = 1
local integer tId
local integer ShieldId = GetPlayerNr(GetOwningPlayer(Shield))
local integer level = GetUnitAbilityLevel(Shield, ABILITY_ID)
local integer LoopsLeft = udg_AV_Int1[LoopTimerId]
if (GetUnitState(Shield, UNIT_STATE_LIFE) <= 0) then
call DisableSkillDamageDetection(DD_ID)
loop
exitwhen i > GetMaxHumanPlayers()
if (Nearby_Shield[i] == Shield) then
set Nearby_Shield[i] = null
endif
set i = i + 1
endloop
set Protected_Tanks_Count[ShieldId] = 0
set KS_TakenDamage[ShieldId] = 0
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(Shield)
call GroupEnumUnitsInRange(G, GetUnitX(Shield),GetUnitY(Shield), AREA, FILTER_ANY_TANK)
// First reset the references to the current shield, before setting it again
// This makes sure, that only the tanks that actually are under the shield are affected and outdated references are removed as fast as possible
loop
exitwhen i > GetMaxHumanPlayers()
if (Nearby_Shield[i] == Shield) then
set Nearby_Shield[i] = null
endif
set i = i + 1
endloop
set Protected_Tanks_Count[ShieldId] = 0
loop
set temp = FirstOfGroup(G)
set tId = GetPlayerNr(GetOwningPlayer(temp))
exitwhen (temp == null)
if (Nearby_Shield[tId] != null) and (Nearby_Shield[tId] != Shield) then
// this case should not happen
call DebugMsg("Kinetic Shield: Affected by two shields")
else
set Nearby_Shield[tId] = Shield
if IsUnitAlly(temp, GetOwningPlayer(Shield)) then
set Protected_Tanks_Count[ShieldId] = Protected_Tanks_Count[ShieldId] + 1
endif
endif
call GroupRemoveUnit(G, temp)
endloop
call ReleaseGroup(G)
set G = null
endif
set Shield = null
endfunction
function Trig_Kinetic_Shield_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit Shield
local unit temp
local integer casterId = GetPlayerNr(GetOwningPlayer(Caster))
local integer WeaponsLevel = GetPlayerTechCount(GetOwningPlayer(Caster), 'R002', true)
local integer ArmorLevel = GetPlayerTechCount(GetOwningPlayer(Caster), 'R003', true)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local group G = NewGroup()
local timer t
local integer LoopTimerId
call GroupEnumUnitsInRangeEx(G, TargetX, TargetY, 2*AREA-100, FILTER_KINETIC_SHIELD)
if (FirstOfGroup(G) != null) then
call IssueImmediateOrder(Caster, "stop")
call SetUnitManaDelayed(Caster, GetUnitState(Caster, UNIT_STATE_MANA))
call DisplayTextToPlayer(GetOwningPlayer(Caster), 0, 0, "|cfffed312Kinetic Shields may not overlap.|r" )
else
set Shield = CreateUnit(GetOwningPlayer(Caster), KINETIC_SHIELD_ID, TargetX, TargetY, 270)
call UnitAddAbility(Shield, BUFF_ABILITY_ID)
call SetUnitUserData(Shield, R2I(DAMAGE_BLOCK_BASE + ((WeaponsLevel + ArmorLevel) * DAMAGE_BLOCK_UP)))
call UnitApplyTimedLife(Shield, 'B015', DURATION)
call PermanentTimedLife(Shield, DURATION, null, "", "", 0, function PermanentTimedLife_KineticShield)
// the following part instantly applies the shield buff, the aura of the shield unit takes a little time to be applied
// the INITIAL_BUFF_ID ability adds the buff to the unit, but removing the ability does not remove the buff with it, which is why this is working
set udg_Filter_Player = GetOwningPlayer(Shield)
call GroupEnumUnitsInRange(G, GetUnitX(Shield),GetUnitY(Shield), AREA, FILTER_ALLY_TANK)
loop
set temp = FirstOfGroup(G)
exitwhen (temp == null)
call UnitAddAbility(temp, INITIAL_BUFF_ID)
call UnitRemoveAbility(temp, INITIAL_BUFF_ID)
call GroupRemoveUnit(G, temp)
endloop
call EnableSkillDamageDetection(DD_ID)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Shield
set udg_AV_Int1[LoopTimerId] = 0
call TimerStart(t, CHECK_INTERVAL, true, function Trig_Kinetic_Shield_Loop)
endif
call ReleaseGroup(G)
set G = null
set Caster = null
set Shield = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Kinetic_Shield = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodeAbsolute(DamageAlterationFunction.Trig_Kinetic_Shield_DamageDetection)
call TriggerRegisterSpellEffectEvent( gg_trg_Kinetic_Shield, ABILITY_ID )
call TriggerAddAction( gg_trg_Kinetic_Shield, function Trig_Kinetic_Shield_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Maintenance initializer Init
globals
private constant integer ABILITY_ID = 'A0CS'
private constant integer BUFF_ID = 'B01T'
private constant real MANA_HEAL = 0.0
private constant real LIFE_HEAL = 500.0
private constant real MANA_UPGRADE_BONUS = 0.0
private constant real LIFE_UPGRADE_BONUS = 0.2
private constant real DURATION = 7.0
endglobals
function Trig_Maintenance_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer ArmorLevel = GetPlayerTechCount(GetOwningPlayer(Caster), 'R003', true)
local real hpHeal = LIFE_HEAL * (1 + LIFE_UPGRADE_BONUS * ArmorLevel)
local real manaHeal = MANA_HEAL * (1 + MANA_UPGRADE_BONUS * ArmorLevel)
call HealOverTime(Caster, hpHeal, manaHeal, DURATION, 0, true)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Maintenance = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Maintenance, ABILITY_ID )
call TriggerAddAction( gg_trg_Maintenance, function Trig_Maintenance_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope MassConverter initializer Init
globals
private constant integer ITEM_ID = 'I05S'
private constant integer BUFF_ID = 'B035'
private constant real MANA_REGENERATION_PERC = 0.03
private constant real LIFE_REGENERATION_PERC = 0.03
private constant real MANA_REGENERATION_PERC_TANK = 0.15
private constant real LIFE_REGENERATION_PERC_TANK = 0.15
endglobals
function Trig_Mass_Converter_Actions takes nothing returns nothing
local unit killer = GetKillingUnit()
local real manaHeal
local real lifeHeal
if IsDummy(killer) then
set killer = udg_Tank[GetPlayerNr(GetOwningPlayer(killer))]
endif
if (killer != null) and (GetUnitState(killer, UNIT_STATE_LIFE) > 0) and (GetUnitAbilityLevel(killer, BUFF_ID) > 0) then
if (IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO)) then
set manaHeal = MANA_REGENERATION_PERC_TANK
set lifeHeal = LIFE_REGENERATION_PERC_TANK
else
set manaHeal = MANA_REGENERATION_PERC
set lifeHeal = LIFE_REGENERATION_PERC
endif
call SetUnitState(killer, UNIT_STATE_MANA, GetUnitState(killer, UNIT_STATE_MANA) + (manaHeal * GetUnitState(killer, UNIT_STATE_MAX_MANA)))
call SetUnitState(killer, UNIT_STATE_LIFE, GetUnitState(killer, UNIT_STATE_LIFE) + (lifeHeal * GetUnitState(killer, UNIT_STATE_MAX_LIFE)))
endif
set killer = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Mass_Converter = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Mass_Converter, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( gg_trg_Mass_Converter, function Trig_Mass_Converter_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Mine_Conditions_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local location SpellTargetLoc = GetSpellTargetLoc()
local group G = NewGroup()
call GetPathableLoc( SpellTargetLoc, 12, 100000 )
call GroupEnumUnitsInRangeOfLoc(G, SpellTargetLoc, 100, FILTER_MINE)
if FirstOfGroup(G)!=null then
call IssueImmediateOrder( Caster, "stop" )
if GetLocalPlayer() == GetOwningPlayer(Caster) then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You cannot place mines within range of 100 of other mines.|r")
endif
if GetSpellAbilityId() == 'A04U' or GetSpellAbilityId() == 'A02F' then
call SetUnitManaDelayed(Caster, GetUnitState(Caster, UNIT_STATE_MANA))
endif
endif
call RemoveLocation( SpellTargetLoc )
call ReleaseGroup( G )
set SpellTargetLoc = null
set G = null
set Caster = null
endfunction
//===========================================================================
function InitTrig_Mine_Conditions takes nothing returns nothing
set gg_trg_Mine_Conditions = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Mine_Conditions, 'A04F' )
call TriggerRegisterSpellEffectEvent( gg_trg_Mine_Conditions, 'A01K' )
call TriggerRegisterSpellEffectEvent( gg_trg_Mine_Conditions, 'A04U' )
call TriggerRegisterSpellEffectEvent( gg_trg_Mine_Conditions, 'A02F' )
call TriggerRegisterSpellEffectEvent( gg_trg_Mine_Conditions, 'A06Y' )
call TriggerAddAction( gg_trg_Mine_Conditions, function Trig_Mine_Conditions_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Mine_Explodes_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer Id = GetUnitTypeId(U)
local real range
local real Damage = GetMineDamage(U)
local real X
local real Y
if Damage > 0 then
set X = GetUnitX(U)
set Y = GetUnitY(U)
if (Id-'n00L')*(Id-'n00R')*(Id-'n00S')*(Id-'n00T')*(Id-'n00U')==0 then
set range = 500
else
set range = 400
endif
call AreaSpellDamageExplosive(U, range, Damage, 1, 0.5)
call DestroyEffect(AddSpecialEffect( "Abilities\\Spells\\Other\\Volcano\\VolcanoDeath.mdl", X, Y) )
call DestroyEffect(AddSpecialEffect( "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", X, Y ))
call CreateExplosionSizedTimed(GetOwningPlayer(U),X,Y,1.6,0.35)
call DestroyTreesInRange(X, Y, range)
endif
set U = null
endfunction
//===========================================================================
function InitTrig_Mine_Explodes takes nothing returns nothing
set gg_trg_Mine_Explodes = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Mine_Explodes, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( gg_trg_Mine_Explodes, function Trig_Mine_Explodes_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Mine_Place_Explode_UnitDetonatesBomb takes unit U, integer Team returns boolean
if not (udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))] == Team) and (GetUnitTypeId(U) == 'z01Y') then
return true
endif
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))] == Team or not IsUnitType(U, UNIT_TYPE_HERO) then
return false
endif
if GetUnitTypeId(U) == 'H00X' and GetUnitFlyHeight(U) > 100.0 then
return false
endif
if U == GetDyingUnit() then
return true
endif
return GetUnitState( U , UNIT_STATE_LIFE ) > 0 and GetUnitAbilityLevel(U, 'Avul') == 0
endfunction
function Trig_Mine_Place_Explode_ConditionsTeam1Bomb takes nothing returns boolean
if GetTriggerUnit() == GetDyingUnit() or Trig_Mine_Place_Explode_UnitDetonatesBomb(GetTriggerUnit(), 1) then
call ExecuteFunc("Trig_Mine_Place_Explode_Actions")
endif
return false
endfunction
function Trig_Mine_Place_Explode_ConditionsTeam2Bomb takes nothing returns boolean
if GetTriggerUnit() == GetDyingUnit() or Trig_Mine_Place_Explode_UnitDetonatesBomb(GetTriggerUnit(), 2) then
call ExecuteFunc("Trig_Mine_Place_Explode_Actions")
endif
return false
endfunction
function Trig_Mine_Place_Explode_Actions takes nothing returns nothing
local lightning L
local location P
local location TankLoc
local unit Mine
local integer TriggerIndex = GetHandleIndex( GetTriggeringTrigger() )
call DestroyTrigger( GetTriggeringTrigger() )
if GetTriggerUnit() != GetDyingUnit() then
set Mine = udg_AV_Unit1[TriggerIndex]
if (GetUnitTypeId(GetTriggerUnit()) == 'z01Y') then
call RemoveUnit(Mine)
call DestroyEffect(AddSpecialEffect("abilities\\weapons\\DemolisherMissile\\DemolisherMissile.mdl",GetUnitX(Mine),GetUnitY(Mine)))
call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",GetUnitX(Mine),GetUnitY(Mine)))
if (GetRandomInt(0,1) == 1) then
call KillUnit( Mine )
else
call RemoveUnit(Mine)
endif
else
call KillUnit( Mine )
if IsAirUnit( GetTriggerUnit() ) then
set P = GetUnitLoc( Mine )
set TankLoc = GetUnitLoc( GetTriggerUnit() )
set L = AddLightningEx( "LEAS", true, GetLocationX( TankLoc ), GetLocationY( TankLoc ), GetLocationZ( TankLoc ) + 500, GetLocationX( P ), GetLocationY( P ), GetLocationZ( P ) )
call TriggerSleepAction( 0.50 )
call DestroyLightning( L )
set L = null
call RemoveLocation( TankLoc )
call RemoveLocation( P )
set TankLoc = null
set P = null
endif
endif
set Mine = null
endif
call ReleaseHandleIndex(TriggerIndex)
endfunction
function Trig_Mine_Place_Conditions takes nothing returns boolean
return GetMineDamage( GetSummonedUnit() ) != 0 and GetUnitTypeId( GetSummonedUnit() ) != 'z00P'
endfunction
function Trig_Mine_Place_Actions takes nothing returns nothing
local unit mine = GetSummonedUnit()
local trigger t
call GameTimeWait( 3.00 )
set t = CreateTrigger( )
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(mine))] == 1 then
call TriggerAddCondition( t, Condition( function Trig_Mine_Place_Explode_ConditionsTeam1Bomb ) )
else
call TriggerAddCondition( t, Condition( function Trig_Mine_Place_Explode_ConditionsTeam2Bomb ) )
endif
call TriggerRegisterUnitInRange(t, mine,150, null)
call TriggerRegisterUnitEvent( t, mine, EVENT_UNIT_DEATH )
set udg_AV_Unit1[NewTriggerIndex(t)] = mine
set t = null
set mine = null
endfunction
//===========================================================================
function InitTrig_Mine_Place takes nothing returns nothing
set gg_trg_Mine_Place = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Mine_Place, EVENT_PLAYER_UNIT_SUMMON )
call TriggerAddCondition( gg_trg_Mine_Place, Condition( function Trig_Mine_Place_Conditions ) )
call TriggerAddAction( gg_trg_Mine_Place, function Trig_Mine_Place_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Mortar_Team_Command_Actions takes nothing returns nothing
local player Owner = GetOwningPlayer(GetTriggerUnit())
set udg_Stats_CreepBuy[GetPlayerNr(Owner)] = udg_Stats_CreepBuy[GetPlayerNr(Owner)] + 3
endfunction
//===========================================================================
function InitTrig_Mortar_Team_Command takes nothing returns nothing
set gg_trg_Mortar_Team_Command = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Mortar_Team_Command, 'A08W' )
call TriggerAddAction( gg_trg_Mortar_Team_Command, function Trig_Mortar_Team_Command_Actions )
endfunction
//TESH.scrollpos=10
//TESH.alwaysfold=0
scope NegatorPack initializer Init
globals
private constant integer ABILITY_ID = 'A039'
private constant integer EFFECT_ABILITY_ID = 'A0CN'
private constant integer BUFF_ID = 'B02S'
private constant real DURATION = 1.5
private constant real INTERVAL = 0.1
private constant real MIN_DELAY = 0.3
endglobals
function Trig_Negator_Pack_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Caster = udg_AV_Unit1[LoopTimerId]
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
if GetUnitState(Caster, UNIT_STATE_LIFE) <= 0 then
call MakeUnitInvulnerable( Caster, false)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
// wait some time until the actual buff appears
elseif (udg_AV_Int1[LoopTimerId] * INTERVAL > MIN_DELAY) then
if (GetUnitAbilityLevel(Caster, BUFF_ID) <= 0) then
call MakeUnitInvulnerable( Caster, false)
call RefreshTransparency( Caster )
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
endif
set Caster = null
endfunction
function Trig_Negator_Pack_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local timer t
local integer LoopTimerId
if IsUnitStunned(Caster) then
call IssueImmediateOrder( Caster, "stop" )
call SetUnitManaDelayed(Caster, GetUnitState(Caster, UNIT_STATE_MANA))
else
call MakeUnitInvulnerable( Caster, true)
call SetPlayerAbilityAvailable(GetOwningPlayer(Caster), EFFECT_ABILITY_ID, true)
call AddAbilityTimed(Caster, EFFECT_ABILITY_ID, 1, DURATION)
call IssueImmediateOrder(Caster, "phaseshift")
call SetPlayerAbilityAvailable(GetOwningPlayer(Caster), EFFECT_ABILITY_ID, false)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Caster
set udg_AV_Int1[LoopTimerId] = 0
call TimerStart(t, INTERVAL, true, function Trig_Negator_Pack_Loop)
endif
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Negator_Pack = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Negator_Pack, ABILITY_ID )
call TriggerAddAction( gg_trg_Negator_Pack, function Trig_Negator_Pack_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope NetLauncher initializer Init
globals
private constant integer ABILITY_ID = 'A08H'
private constant real DURATION_BASE = 3.0
private constant real DURATION_UP = 0.0
endglobals
private function Actions takes nothing returns nothing
local unit U = GetSpellTargetUnit()
local integer level = GetUnitAbilityLevel(GetSpellAbilityUnit(), ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
call UnitDamageTarget(GetSpellAbilityUnit(), U, 0, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
//deactivate Bombs or Flak, because the tank is now a ground unit
call DeactivateAirOnlyWeapons(U)
call GameTimeWait(duration)
//activate the weapon again, as the net wears off
call ActivateAirOnlyWeapons(U)
set U = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Orbital_Command_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local location TargetLoc = GetSpellTargetLoc()
local real Angle
local real Dist
local real X
local real Y
local real beginGameTime = TimerGetElapsed(udg_GameTime)
local real Damage = 500 * (1.0 + 0.05 * I2R(GetPlayerTechCount(GetOwningPlayer(Caster), 'R002', true)) )
local integer CountE
local integer Strikes = 0
loop
set Angle = GetRandomReal(0,360)
set Dist = GetRandomReal(0,300)
set X = GetLocationX(TargetLoc) + Dist*Cos(Angle*bj_DEGTORAD)
set Y = GetLocationY(TargetLoc) + Dist*Sin(Angle*bj_DEGTORAD)
set CountE = 1
loop
exitwhen CountE > 5
call DestroyEffect(AddSpecialEffect( "Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl", X+12*Cos(72.00 * I2R(CountE)*bj_DEGTORAD), Y+12*Sin(72.00 * I2R(CountE)*bj_DEGTORAD) ))
set CountE = CountE + 1
endloop
call DestroyEffect(AddSpecialEffect( "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl", X, Y ))
call DestroyEffect(AddSpecialEffect( "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", X, Y ))
set udg_Filter_Player = GetOwningPlayer(Caster)
call AreaSpellDamageFromUnit(Caster, X, Y, 400, Damage, 1, 0, FILTER_ENEMY_UNITS)
call DestroyTreesInRange(X, Y, 400)
call ShakeCamAtLoc(X,Y,600,1.5,1)
set Strikes = Strikes + 1
exitwhen Strikes>=6
call WaitForGameTime(beginGameTime+I2R(Strikes)*0.5)
endloop
call RemoveLocation(TargetLoc)
set TargetLoc = null
set Caster = null
endfunction
//===========================================================================
function InitTrig_Orbital_Command takes nothing returns nothing
set gg_trg_Orbital_Command = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Orbital_Command, 'A08R' )
call TriggerAddAction( gg_trg_Orbital_Command, function Trig_Orbital_Command_Actions )
endfunction
//TESH.scrollpos=126
//TESH.alwaysfold=0
scope PlasmaDischarger initializer Init
globals
private constant integer ABILITY_ID = 'A0FM'
private constant integer ITEM_ID = 'I06C'
private constant integer PASSIVE_ITEM_ID = 'I06D'
private constant real ARC = 45.0
private constant real AREA = 1000.0
private constant real ACTIVATION_AREA = 400.0
private constant real PUSH_SPEED = 400.0
private constant real ACTIVE_COOLDOWN = 40.0
private constant real PASSIVE_COOLDOWN = 20.0
private constant real PUSH_INTERVAL = 0.03
private constant real CHECK_INTERVAL = 0.1
private integer array IsDischargerReady[10]
private constant integer PD_DISABLED = 0
private constant integer PD_PASSIVE_COOLDOWN = 1
private constant integer PD_ACTIVE_COOLDOWN = 2
private constant integer PD_READY = 3
endglobals
// ------------------------------------------------------------------------------------------------------
function Trig_Plasma_Discharger_Conditions takes nothing returns boolean
return (GetItemTypeId(GetManipulatedItem()) == ITEM_ID)
endfunction
function Trig_Plasma_Discharger_Pickup_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit target = udg_AV_Unit1[LoopTimerId]
local integer targetId = GetPlayerNr(GetOwningPlayer(target))
local integer dischargerSlot = GetInventoryIndexOfItemTypeBJ(target, ITEM_ID)
local item discharger
local item passiveDischarger
local group G
local real X
local real Y
if (dischargerSlot > 0) then
if (GetUnitState(target, UNIT_STATE_LIFE) > 0) and (IsDischargerReady[targetId] == PD_READY) then
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(target)
call GroupEnumUnitsInRange(G, GetUnitX(target), GetUnitY(target), ACTIVATION_AREA, FILTER_ENEMY_TANK)
if (FirstOfGroup(G) != null) then
set X = GetUnitX(FirstOfGroup(G))
set Y = GetUnitY(FirstOfGroup(G))
call DebugMsg("Add")
set discharger = UnitRemoveItemFromSlot(target, dischargerSlot-1)
set passiveDischarger = UnitAddItemById(target, PASSIVE_ITEM_ID)
if UnitUseItem(target, passiveDischarger) then
call IssuePointOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(target), ABILITY_ID, 1, GetUnitX(target), GetUnitY(target), 0), "shockwave", X, Y )
call DebugMsg("Used (passive): " + I2S(targetId))
set IsDischargerReady[targetId] = PD_PASSIVE_COOLDOWN
set udg_AV_Int1[LoopTimerId] = R2I(PASSIVE_COOLDOWN / CHECK_INTERVAL)
endif
call DebugMsg("Remove")
call RemoveItem(passiveDischarger)
call UnitAddItemToSlot(target, discharger, dischargerSlot-1)
endif
call ReleaseGroup(G)
set G = null
endif
if (IsDischargerReady[targetId] == PD_PASSIVE_COOLDOWN) then
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] - 1
if (udg_AV_Int1[LoopTimerId] <= 0) then
call DebugMsg("Ready (passive): " + I2S(targetId))
set IsDischargerReady[targetId] = PD_READY
endif
endif
else
set IsDischargerReady[targetId] = PD_DISABLED
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set target = null
endfunction
function Trig_Plasma_Discharger_Pickup_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer pId = GetPlayerNr(GetOwningPlayer(U))
local timer t
local integer LoopTimerId
if (IsDischargerReady[pId] == PD_DISABLED) then
set IsDischargerReady[pId] = PD_READY
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Int1[LoopTimerId] = 0
call TimerStart(t,CHECK_INTERVAL,true, function Trig_Plasma_Discharger_Pickup_Loop)
endif
set U = null
endfunction
// ------------------------------------------------------------------------------------------------------
function Trig_Plasma_Discharger_Push_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit target = udg_AV_Unit1[LoopTimerId]
local real distance = udg_AV_Real2[LoopTimerId] * PUSH_INTERVAL
local real angle = udg_AV_Real1[LoopTimerId]
local real X
local real Y
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] - 1
if (GetUnitState(target, UNIT_STATE_LIFE) <= 0) or (udg_AV_Int1[LoopTimerId] <= 0) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set X = PolarProjX(GetUnitX(target), distance, angle)
set Y = PolarProjY(GetUnitY(target), distance, angle)
call SetUnitPosition(target, X, Y)
endif
set target = null
endfunction
function Trig_Plasma_Discharger_Push takes real angle, unit target, real distance returns nothing
local timer t
local integer LoopTimerId
call DebugMsg("Push " + GetName(target))
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Real1[LoopTimerId] = angle
set udg_AV_Real2[LoopTimerId] = distance
set udg_AV_Unit1[LoopTimerId] = target
set udg_AV_Int1[LoopTimerId] = R2I((distance / PUSH_SPEED) / PUSH_INTERVAL)
call TimerStart(t,PUSH_INTERVAL,true, function Trig_Plasma_Discharger_Push_Loop)
endfunction
function Trig_Plasma_Discharger_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit temp
local group G = NewGroup()
local integer casterId = GetPlayerNr(GetOwningPlayer(Caster))
local real targetAngle = GetAngle(GetUnitX(Caster), GetUnitY(Caster), GetSpellTargetX(), GetSpellTargetY())
local real angle
local real distance
call DebugMsg("Cast Push")
set udg_Filter_Player = GetOwningPlayer(Caster)
call GroupEnumUnitsInRange(G, GetUnitX(Caster), GetUnitY(Caster), AREA, FILTER_ENEMY_TANK)
loop
set temp = FirstOfGroup(G)
exitwhen (temp == null)
set angle = targetAngle - GetUnitsAngleDeg(Caster, temp)
set distance = GetUnitsDistance(Caster, temp)
if (distance <= 300) or ((angle >= (ARC * -0.5)) and (angle <= (ARC * 0.5))) then
// before it was the distance between caster and target, now it becomes the distance the target is going to be pushed
set distance = (AREA - distance) / 3.0 + 250.0
call Trig_Plasma_Discharger_Push(GetUnitsAngleDeg(Caster, temp), temp, distance)
endif
call GroupRemoveUnit(G, temp)
endloop
set Caster = null
call ReleaseGroup(G)
set G = null
if (IsDischargerReady[casterId] == PD_READY) then
call DebugMsg("Used: " + I2S(casterId))
set IsDischargerReady[casterId] = PD_ACTIVE_COOLDOWN
call GameTimeWait(ACTIVE_COOLDOWN)
set IsDischargerReady[casterId] = PD_READY
call DebugMsg("Ready: " + I2S(casterId))
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
set gg_trg_Plasma_Discharger = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( t, Condition( function Trig_Plasma_Discharger_Conditions ) )
call TriggerAddAction( t, function Trig_Plasma_Discharger_Pickup_Actions )
call TriggerRegisterSpellEffectEvent( gg_trg_Plasma_Discharger, ABILITY_ID )
call TriggerAddAction( gg_trg_Plasma_Discharger, function Trig_Plasma_Discharger_Actions )
endfunction
endscope
//TESH.scrollpos=42
//TESH.alwaysfold=0
globals
constant integer RADAR_LOW_RANGE_ID = 'A0F5'
constant integer RADAR_HIGH_RANGE_ID = 'A0F6'
constant integer RADAR_BUFF_ABILITY_ID = 'A01W'
constant integer RADAR_BUFF_ID = 'B021'
constant real RADAR_ACTIVATION_DELAY = 1.0
constant real RADAR_DEACTIVATION_DELAY = 3.0
constant real RADAR_CHECK_INTERVAL = 0.25
endglobals
function Trig_Radar_Conditions takes nothing returns boolean
return IsRadar(GetManipulatedItem())
endfunction
function UnitHasRadar takes unit U returns boolean
local integer index
local item indexItem
set index = 0
loop
set indexItem = UnitItemInSlot(U, index)
if (indexItem != null) and IsRadar(indexItem) then
set indexItem = null
return true
endif
set index = index + 1
exitwhen index >= bj_MAX_INVENTORY
endloop
set indexItem = null
return false
endfunction
function Trig_Radar_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local location oldLoc = udg_AV_Loc1[LoopTimerId]
local location newLoc
local boolean isDeactivationDelayRunning = udg_AV_Bool1[LoopTimerId]
//Destroy this trigger when the unit dies or no longer has a radar
//Since heroes are triggered to pick up their radars again on revive, a new trigger will be created anyway
if (GetUnitState(U, UNIT_STATE_LIFE) == 0) or (U == null) or (not UnitHasRadar(U)) then
//call DebugMsg("Radar removed")
if (udg_AV_Unit2[LoopTimerId] != null) then
call ReleaseDummy(udg_AV_Unit2[LoopTimerId])
endif
if (GetUnitAbilityLevel(U, RADAR_BUFF_ID) > 0) then
call UnitRemoveAbility(U, RADAR_BUFF_ID)
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set newLoc = GetUnitLoc(U)
if (DistanceBetweenPoints(oldLoc, newLoc) > 1) then
// When the unit moved, check if the radar is already active
if (not isDeactivationDelayRunning) then
// the deactivation delay just started running, save the time, when it will be over
set udg_AV_Real2[LoopTimerId] = TimerGetElapsed(udg_GameTime) + RADAR_DEACTIVATION_DELAY
set udg_AV_Bool1[LoopTimerId] = true
else
// if the bigger radar is already active and the unit is already moving again, check if the deactivation delay is already over
if (udg_AV_Unit2[LoopTimerId] != null) then
if (TimerGetElapsed(udg_GameTime) > udg_AV_Real2[LoopTimerId]) then
// if the delay is over, remove the dummy with the bigger radar
call ReleaseDummy(udg_AV_Unit2[LoopTimerId])
set udg_AV_Unit2[LoopTimerId] = null
set udg_AV_Bool1[LoopTimerId] = false
if (GetUnitAbilityLevel(U, RADAR_BUFF_ID) > 0) then
call UnitRemoveAbility(U, RADAR_BUFF_ID)
endif
else
// if the delay is not over yet, move the dummy with the unit carrying the radar
call SetUnitPositionLoc(udg_AV_Unit2[LoopTimerId], newLoc)
endif
endif
endif
set udg_AV_Real1[LoopTimerId] = TimerGetElapsed(udg_GameTime)
else
//1 second no movements = biggest radar range
if (TimerGetElapsed(udg_GameTime) - udg_AV_Real1[LoopTimerId]) >= RADAR_ACTIVATION_DELAY then
if udg_AV_Unit2[LoopTimerId] == null then
set udg_AV_Unit2[LoopTimerId] = CreateDummyWithAbility(GetOwningPlayer(U), RADAR_HIGH_RANGE_ID, 1, newLoc, 0)
call DebugMsg("Radar activate!")
//if (GetUnitAbilityLevel(U, RADAR_BUFF_ID) == 0) then
call IssueTargetOrder( CreateDummyWithAbility(GetOwningPlayer(U), RADAR_BUFF_ABILITY_ID, 1, newLoc, 0), "slow", U )
//endif
endif
endif
set udg_AV_Bool1[LoopTimerId] = false
endif
set udg_AV_Loc1[LoopTimerId] = newLoc
endif
call RemoveLocation(oldLoc)
set oldLoc = null
set newLoc = null
set U = null
endfunction
function Trig_Radar_Actions takes nothing returns nothing
local timer t
local unit U = GetTriggerUnit()
local integer LoopTimerId
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Loc1[LoopTimerId] = GetUnitLoc(U)
set udg_AV_Real1[LoopTimerId] = TimerGetElapsed(udg_GameTime) //the time since the unit stands still
set udg_AV_Bool1[LoopTimerId] = false
call TimerStart(t, RADAR_CHECK_INTERVAL, true, function Trig_Radar_Loop)
endfunction
//===========================================================================
function InitTrig_Radar takes nothing returns nothing
set gg_trg_Radar = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Radar, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( gg_trg_Radar, Condition( function Trig_Radar_Conditions ) )
call TriggerAddAction( gg_trg_Radar, function Trig_Radar_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Recharge initializer Init
globals
private constant integer ABILITY_ID = 'A0CT'
private constant integer BUFF_ID = 'B01U'
private constant real MANA_HEAL = 15.0
private constant real LIFE_HEAL = 0.0
private constant real MANA_UPGRADE_BONUS = 0.2
private constant real LIFE_UPGRADE_BONUS = 0.0
private constant real DURATION = 5.0
endglobals
function Trig_Recharge_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer ArmorLevel = GetPlayerTechCount(GetOwningPlayer(Caster), 'R003', true)
local real hpHeal = LIFE_HEAL * (1 + LIFE_UPGRADE_BONUS * ArmorLevel)
local real manaHeal = MANA_HEAL * (1 + MANA_UPGRADE_BONUS * ArmorLevel)
call HealOverTime(Caster, hpHeal, manaHeal, DURATION, 0, true)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Recharge = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Recharge, ABILITY_ID )
call TriggerAddAction( gg_trg_Recharge, function Trig_Recharge_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope RepairKit initializer Init
globals
private constant integer ABILITY_ID = 'A0C2'
private constant integer BUFF_ID = 'B02K'
private constant real MANA_HEAL = 0.0
private constant real LIFE_HEAL = 2500.0
private constant real MANA_UPGRADE_BONUS = 0.0
private constant real LIFE_UPGRADE_BONUS = 0.0
private constant real DURATION = 2.0
endglobals
function Trig_Repair_Kit_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer ArmorLevel = GetPlayerTechCount(GetOwningPlayer(Caster), 'R003', true)
local real hpHeal = LIFE_HEAL * (1 + LIFE_UPGRADE_BONUS * ArmorLevel)
local real manaHeal = MANA_HEAL * (1 + MANA_UPGRADE_BONUS * ArmorLevel)
call HealOverTime(Caster, hpHeal, manaHeal, DURATION, 0, false)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Repair_Kit = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Repair_Kit, ABILITY_ID )
call TriggerAddAction( gg_trg_Repair_Kit, function Trig_Repair_Kit_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Siege_Pack_Actions takes nothing returns nothing
local integer i = 1
local unit Caster = GetTriggerUnit()
local unit temp
local player Owner = GetOwningPlayer(Caster)
local real time = SIEGE_PACK_DELAY * (TeamCount_SiegePack[udg_Player_Team[GetPlayerNr(Owner)]]-1)
local integer array food
if ( GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_USED) <= GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_CAP) - 2 ) then
loop
exitwhen i > 3
if GetPlayerState(GetOwningPlayer(GetTriggerUnit()), PLAYER_STATE_RESOURCE_FOOD_USED) <= GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_CAP) - 2 and not IsUnitDeadBJ(Caster) then
set temp = CreateUnit(GetOwningPlayer(GetTriggerUnit()),'z01O', GetUnitX(Caster), GetUnitY(Caster), 90)
call UnitApplyTimedLife( temp, 'BTLF', 20.00 )
call SetLaneCreepFlag(temp, CF_COSTS_FOOD)
call IssuePointOrderLoc( temp, "attack", udg_Move_Points[GetTargetMovePoint(Caster)] )
call SetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_USED, GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_USED) + 2)
set udg_Stats_CreepBuy[GetPlayerNr(Owner)] = udg_Stats_CreepBuy[GetPlayerNr(Owner)] + 1
call GameTimeWait(time)
endif
set i = i + 1
endloop
else
if GetLocalPlayer() == Owner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You reached the unit limit of 40.|r" )
endif
call IssueImmediateOrder( Caster, "stop" )
endif
set Caster = null
set Owner = null
set temp = null
endfunction
//===========================================================================
function InitTrig_Siege_Pack takes nothing returns nothing
set gg_trg_Siege_Pack = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Siege_Pack, 'A06J' )
call TriggerRegisterSpellEffectEvent( gg_trg_Siege_Pack, 'A08W' )
call TriggerAddAction( gg_trg_Siege_Pack, function Trig_Siege_Pack_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Smoke_Generator_RemoveInvisibility takes nothing returns nothing
if (GetEventDamage() > 1) then
if (GetUnitAbilityLevel(GetTriggerUnit(), 'Apiv') > 0) then
call UnitRemoveAbility(GetTriggerUnit(), 'Apiv')
call UnitRemoveAbility(GetTriggerUnit(), 'B02J')
call RefreshTransparency(GetTriggerUnit())
endif
call DestroyTrigger(GetTriggeringTrigger())
endif
endfunction
function Trig_Smoke_Generator_Actions takes nothing returns nothing
local trigger t = CreateTrigger()
local unit U = GetTriggerUnit()
call UnitAddAbility(U, 'Apiv')
call IssueTargetOrder( CreateDummyWithAbility(GetOwningPlayer(U), 'A0FI', 1, GetUnitLoc(U), 0), "slow", U )
// Only activate the damage detection after one second, so the buff does not get removed instantly, when you are currently taking damage
call GameTimeWait(1)
call TriggerRegisterUnitEvent( t, U, EVENT_UNIT_DAMAGED )
call TriggerAddAction(t, function Trig_Smoke_Generator_RemoveInvisibility)
call GameTimeWait(5)
if (GetUnitAbilityLevel(U, 'Apiv') > 0) then
call UnitRemoveAbility(U, 'Apiv')
call UnitRemoveAbility(U, 'B02J')
call RefreshTransparency(U)
endif
call DestroyTrigger(t)
set U = null
endfunction
//===========================================================================
function InitTrig_Smoke_Generator takes nothing returns nothing
set gg_trg_Smoke_Generator = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Smoke_Generator, 'A0DL' )
call TriggerAddAction( gg_trg_Smoke_Generator, function Trig_Smoke_Generator_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope SpawnDelayRegister initializer Init
globals
constant integer ADVANCED_TROOP_COMMAND_ID = 'I053'
constant integer TROOP_COMMAND_ID = 'I00Y'
constant integer SIEGE_PACK_ID = 'I04B'
constant real ADVANCED_TROOP_COMMAND_DELAY = 0.25
constant real TROOP_COMMAND_DELAY = 0.4
constant real SIEGE_PACK_DELAY = 0.4
integer array TeamCount_AdvancedTroopCommand[2]
integer array TeamCount_TroopCommand[2]
integer array TeamCount_SiegePack[2]
endglobals
function Trig_Spawn_Delay_Register_Conditions takes nothing returns boolean
local integer id = GetItemTypeId(GetManipulatedItem())
return ( id - ADVANCED_TROOP_COMMAND_ID ) * ( id - TROOP_COMMAND_ID ) * ( id - SIEGE_PACK_ID ) == 0
endfunction
function Trig_Spawn_Delay_Register_DropActions takes nothing returns nothing
local unit U = GetManipulatingUnit()
local item Item = GetManipulatedItem()
local integer team = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
call DebugMsg("Drop Delay item")
if (GetItemTypeId(Item) == ADVANCED_TROOP_COMMAND_ID) then
//set TeamCount_AdvancedTroopCommand[team] = TeamCount_AdvancedTroopCommand[team] - 1
set TeamCount_TroopCommand[team] = TeamCount_TroopCommand[team] - 1
elseif (GetItemTypeId(Item) == TROOP_COMMAND_ID) then
set TeamCount_TroopCommand[team] = TeamCount_TroopCommand[team] - 1
elseif (GetItemTypeId(Item) == SIEGE_PACK_ID) then
set TeamCount_SiegePack[team] = TeamCount_SiegePack[team] - 1
endif
set U = null
set Item = null
endfunction
function Trig_Spawn_Delay_Register_PickupActions takes nothing returns nothing
local unit U = GetManipulatingUnit()
local item Item = GetManipulatedItem()
local integer team = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
call DebugMsg("Pickup Delay item")
if (GetItemTypeId(Item) == ADVANCED_TROOP_COMMAND_ID) then
//set TeamCount_AdvancedTroopCommand[team] = TeamCount_AdvancedTroopCommand[team] + 1
set TeamCount_TroopCommand[team] = TeamCount_TroopCommand[team] + 1
elseif (GetItemTypeId(Item) == TROOP_COMMAND_ID) then
set TeamCount_TroopCommand[team] = TeamCount_TroopCommand[team] + 1
elseif (GetItemTypeId(Item) == SIEGE_PACK_ID) then
set TeamCount_SiegePack[team] = TeamCount_SiegePack[team] + 1
endif
set U = null
set Item = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 1
set gg_trg_Spawn_Delay_Register = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spawn_Delay_Register, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( gg_trg_Spawn_Delay_Register, Condition( function Trig_Spawn_Delay_Register_Conditions ) )
call TriggerAddAction( gg_trg_Spawn_Delay_Register, function Trig_Spawn_Delay_Register_PickupActions )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_DROP_ITEM )
call TriggerAddCondition( t, Condition( function Trig_Spawn_Delay_Register_Conditions ) )
call TriggerAddAction( t, function Trig_Spawn_Delay_Register_DropActions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Teleport_Breaker_Actions takes nothing returns nothing
local location TargetLoc = GetSpellTargetLoc()
local unit Caster = GetTriggerUnit()
if GetPathableLoc(TargetLoc,32,200) then
call UnitApplyTimedLife(CreateUnitAtLoc(GetOwningPlayer(Caster),'o002',TargetLoc, 270), 'Beye', 180)
else
call IssueImmediateOrder(Caster,"stop")
if GetLocalPlayer()==GetOwningPlayer(Caster) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312You cannot place a Teleport Breaker there.|r")
endif
endif
call RemoveLocation(TargetLoc)
set TargetLoc = null
set Caster = null
endfunction
//===========================================================================
function InitTrig_Teleport_Breaker takes nothing returns nothing
set gg_trg_Teleport_Breaker = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Teleport_Breaker, 'A04Y' )
call TriggerAddAction( gg_trg_Teleport_Breaker, function Trig_Teleport_Breaker_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Test_Item_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
if (IsUnitType(Caster, UNIT_TYPE_GROUND)) then
call DebugMsg("Test Item")
call UnitRemoveType(Caster, UNIT_TYPE_GROUND)
call UnitAddType(Caster, UNIT_TYPE_FLYING)
call GameTimeWait(5)
call UnitAddType(Caster, UNIT_TYPE_FLYING)
call UnitRemoveType(Caster, UNIT_TYPE_GROUND)
endif
set Caster = null
endfunction
//===========================================================================
function InitTrig_Test_Item takes nothing returns nothing
set gg_trg_Test_Item = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Test_Item, 'A0HA' )
call TriggerAddAction( gg_trg_Test_Item, function Trig_Test_Item_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Trader_Hunter_Pack_Speed_Conditions takes nothing returns boolean
return GetItemTypeId(GetManipulatedItem()) == 'I00L'
endfunction
function Trig_Trader_Hunter_Pack_Speed_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), 'A0D4', 1, GetUnitX(Caster), GetUnitY(Caster), 0), "bloodlust", Caster)
set Caster = null
endfunction
//===========================================================================
function InitTrig_Trader_Hunter_Pack_Speed takes nothing returns nothing
set gg_trg_Trader_Hunter_Pack_Speed = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Trader_Hunter_Pack_Speed, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddCondition( gg_trg_Trader_Hunter_Pack_Speed, Condition( function Trig_Trader_Hunter_Pack_Speed_Conditions ) )
call TriggerAddAction( gg_trg_Trader_Hunter_Pack_Speed, function Trig_Trader_Hunter_Pack_Speed_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Troop_Command_Actions takes nothing returns nothing
local integer i = 1
local real beginGameTime = TimerGetElapsed(udg_GameTime)
local unit Caster = GetTriggerUnit()
local unit temp
local player Owner = GetOwningPlayer(Caster)
local real time = TROOP_COMMAND_DELAY * (TeamCount_TroopCommand[udg_Player_Team[GetPlayerNr(Owner)]]-1)
local integer array food
if ( GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_USED) <= GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_CAP) - udg_TC_Food[1] ) then
loop
exitwhen i > 5
if GetPlayerState(GetOwningPlayer(GetTriggerUnit()), PLAYER_STATE_RESOURCE_FOOD_USED) <= GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_CAP) - udg_TC_Food[i] and not IsUnitDeadBJ(Caster) then
set temp = CreateUnit(GetOwningPlayer(GetTriggerUnit()),udg_TC_Unit[i], GetUnitX(Caster), GetUnitY(Caster), 90)
call UnitApplyTimedLife( temp, 'BTLF', 20.00 )
call SetLaneCreepFlag(temp, CF_COSTS_FOOD)
call IssuePointOrderLoc( temp, "attack", udg_Move_Points[GetTargetMovePoint(Caster)] )
call SetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_USED, GetPlayerState(Owner, PLAYER_STATE_RESOURCE_FOOD_USED) + udg_TC_Food[i])
set udg_Stats_CreepBuy[GetPlayerNr(Owner)] = udg_Stats_CreepBuy[GetPlayerNr(Owner)] + 1
call GameTimeWait(time)
endif
set i = i + 1
endloop
else
if GetLocalPlayer() == Owner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You reached the unit limit of 40.|r" )
endif
call IssueImmediateOrder( Caster, "stop" )
endif
set Caster = null
set Owner = null
set temp = null
endfunction
//===========================================================================
function InitTrig_Troop_Command takes nothing returns nothing
set gg_trg_Troop_Command = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Troop_Command, 'A01I' )
call TriggerRegisterSpellEffectEvent( gg_trg_Troop_Command, 'A01Q' )
call TriggerAddAction( gg_trg_Troop_Command, function Trig_Troop_Command_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TinkerTowers initializer Init
private function Conditions takes nothing returns boolean
return IsTinkerTower(GetConstructingStructure())
endfunction
private function Actions takes nothing returns nothing
local unit Tower = GetConstructingStructure()
local real Life
local real LifePercent = 0
// Set the contruction progress to the current hitpoints
// -> the tower is not finished, when the construction time is up, but rather when it has full HP
loop
call TriggerSleepAction( 0.50 )
set Life = GetUnitState(Tower, UNIT_STATE_LIFE)
exitwhen LifePercent >= 1 or Life <= 0
set LifePercent = Life / GetUnitState(Tower, UNIT_STATE_MAX_LIFE)
call UnitSetConstructionProgress( Tower, R2I(LifePercent * 100) )
call SetUnitState(Tower, UNIT_STATE_LIFE, Life)
endloop
set Tower = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_CONSTRUCT_START)
call TriggerAddCondition(t, Condition( function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=25
//TESH.alwaysfold=0
scope TinkerTowersLimit initializer Init
globals
private constant integer ABILITY_ID_1 = 'A05C' // Tinker Ultimate adds 5 additional, which have better stats
private constant integer ABILITY_ID_2 = 'A0A7'
private constant integer ABILITY_ID_3 = 'A0A8'
private constant integer ABILITY_ID_4 = 'A0A9'
private constant integer ABILITY_ID_5 = 'A0AA'
private constant integer ABILITY_ID_6 = 'A0AB'
private constant integer TOWER_FOOD_COST = 8 // Also has to be set in the Object Editor (check for consistency)
private constant integer MIN_TOWER_DISTANCE = 75
endglobals
private function Conditions takes nothing returns boolean
local integer Id = GetSpellAbilityId()
return (Id-ABILITY_ID_1)*(Id-ABILITY_ID_2)*(Id-ABILITY_ID_3)*(Id-ABILITY_ID_4)*(Id-ABILITY_ID_5)*(Id-ABILITY_ID_6)==0
endfunction
function TinkerTowersLimit_IsTinkerTower takes nothing returns boolean
local unit U = GetFilterUnit()
if IsTinkerTower(U) and (GetUnitState( U , UNIT_STATE_LIFE ) > 0) then
set U = null
return true
endif
set U = null
return false
endfunction
private function Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local player owner = GetOwningPlayer(U)
local location SpellTargetLoc = GetSpellTargetLoc()
local group G = NewGroup()
call GetPathableLoc( SpellTargetLoc, 32, 100000 )
call GroupEnumUnitsInRangeOfLoc(G, SpellTargetLoc, MIN_TOWER_DISTANCE, Condition(function TinkerTowersLimit_IsTinkerTower))
if FirstOfGroup(G)!=null then
call IssueImmediateOrder( U, "stop" )
if GetLocalPlayer() == owner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You cannot place Tinker Tower within range of " + I2S(MIN_TOWER_DISTANCE) + " of other Tinker Tower.|r")
endif
call SetUnitManaDelayed(U, GetUnitState(U, UNIT_STATE_MANA))
elseif ( GetPlayerState(owner, PLAYER_STATE_RESOURCE_FOOD_USED) > GetPlayerState(owner, PLAYER_STATE_RESOURCE_FOOD_CAP) - TOWER_FOOD_COST ) then
call IssueImmediateOrder(U, "stop")
if GetLocalPlayer() == owner then
call DisplayTextToPlayer(GetLocalPlayer(),0,0,"|cfffed312You reached the unit limit.|r")
endif
call SetUnitManaDelayed(U, GetUnitState(U, UNIT_STATE_MANA))
endif
call RemoveLocation( SpellTargetLoc )
call ReleaseGroup( G )
set SpellTargetLoc = null
set G = null
set U = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t, Condition( function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=102
//TESH.alwaysfold=0
scope TowerModules initializer Init
globals
private constant integer ABILITY_ID = 'A03H'
private constant integer MANA_COST_BASE = 0
private constant integer MANA_COST_UP = 5
endglobals
private function GetModuleTypeId takes integer AbilId returns integer
if AbilId=='A07N' or AbilId=='A036' or AbilId=='A07M' or AbilId=='A07O' or AbilId=='A07P' then
return 1
endif
if AbilId=='A07I' or AbilId=='A07U' or AbilId=='A07V' or AbilId=='A07W' or AbilId=='A07X' then
return 2
endif
if AbilId=='A07K' or AbilId=='A07Y' or AbilId=='A07Z' or AbilId=='A080' or AbilId=='A081' then
return 3
endif
if AbilId=='A07L' or AbilId=='A07Q' or AbilId=='A07R' or AbilId=='A07S' or AbilId=='A07T' then
return 4
endif
if AbilId=='A07J' or AbilId=='A082' or AbilId=='A083' or AbilId=='A084' or AbilId=='A085' then
return 5
endif
return 0
endfunction
private function Payback takes nothing returns nothing
local unit c = GetTriggerUnit()
if GetLocalPlayer() == GetOwningPlayer(c) then
call DisplayTextToPlayer(GetLocalPlayer(),0,0,"|cfffed312You can add modules to allied towers only.|r")
endif
call IssueImmediateOrder(c, "stop")
set c = null
endfunction
private function Conditions takes nothing returns boolean
if GetModuleTypeId(GetSpellAbilityId())!=0 and (not udg_TowerModuleUsed[GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))]) then
if IsUnitType(GetSpellTargetUnit(),UNIT_TYPE_STRUCTURE) == false and IsPlayerAlly(GetOwningPlayer(GetSpellTargetUnit()),GetOwningPlayer(GetTriggerUnit())) then
call Payback()
else
return true
endif
endif
return false
endfunction
private function Actions takes nothing returns nothing
local unit Target = GetSpellTargetUnit()
local unit Caster = GetTriggerUnit()
local integer i
local integer j
local integer ModuleType = GetModuleTypeId(GetSpellAbilityId())
local integer SkillLevel = GetUnitAbilityLevel(Caster, ABILITY_ID)
local integer ManaCosts = MANA_COST_BASE + (SkillLevel * MANA_COST_UP)
local integer ModuleLevel
local integer array ModuleTypeId
local item OldModule
local integer ItemsCarried = 0
local integer ItemSlotType
local real Mana
if ModuleType==1 then
// Repair
set ModuleTypeId[1] = 'I03Y'
set ModuleTypeId[2] = 'I03Z'
set ModuleTypeId[3] = 'I03P'
set ModuleTypeId[4] = 'I03W'
set ModuleTypeId[5] = 'I03X'
elseif ModuleType==2 then
//HP
set ModuleTypeId[1] = 'I03V'
set ModuleTypeId[2] = 'I03U'
set ModuleTypeId[3] = 'I03T'
set ModuleTypeId[4] = 'I03S'
set ModuleTypeId[5] = 'I03O'
elseif ModuleType==3 then
//Weapon
set ModuleTypeId[1] = 'I03R'
set ModuleTypeId[2] = 'I044'
set ModuleTypeId[3] = 'I045'
set ModuleTypeId[4] = 'I046'
set ModuleTypeId[5] = 'I047'
elseif ModuleType==4 then
//Troop
set ModuleTypeId[1] = 'I03Q'
set ModuleTypeId[2] = 'I040'
set ModuleTypeId[3] = 'I041'
set ModuleTypeId[4] = 'I042'
set ModuleTypeId[5] = 'I043'
else
//Radar
set ModuleTypeId[1] = 'I04F'
set ModuleTypeId[2] = 'I04G'
set ModuleTypeId[3] = 'I04H'
set ModuleTypeId[4] = 'I04I'
set ModuleTypeId[5] = 'I04J'
endif
set ModuleLevel = 0
set i = 0
loop
exitwhen i > 5
if UnitItemInSlot(Target, i)!=null then
set ItemsCarried = ItemsCarried+1
set j = 1
set ItemSlotType = GetItemTypeId(UnitItemInSlot(Target, i))
loop
exitwhen j > 5
if ItemSlotType == ModuleTypeId[j] then
set OldModule = UnitItemInSlot(Target, i)
set ModuleLevel = j
endif
set j = j + 1
endloop
endif
set i = i + 1
endloop
if ModuleLevel!=0 or UnitInventorySize(Target) > ItemsCarried then
if SkillLevel > ModuleLevel then
if ModuleLevel!=0 then
call RemoveItem(OldModule)
endif
call UnitAddItemById(Target, ModuleTypeId[SkillLevel])
set Mana = GetUnitState(Caster, UNIT_STATE_MANA)
call SetUnitState(Caster, UNIT_STATE_MANA, 0)
call SetUnitManaDelayed(Caster, Mana-ManaCosts)
else
call IssueImmediateOrder( Caster, "stop" )
if GetLocalPlayer() == GetOwningPlayer(Caster) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312The target already has the module on the same or higher level.|r")
endif
call SetUnitManaDelayed(Caster, GetUnitState(Caster, UNIT_STATE_MANA))
endif
else
call IssueImmediateOrder( Caster, "stop" )
if GetLocalPlayer() == GetOwningPlayer(Caster) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312The target has to have an empty inventory slot.|r")
endif
call SetUnitManaDelayed(Caster, GetUnitState(Caster, UNIT_STATE_MANA))
endif
set i= GetPlayerNr(GetOwningPlayer(Caster))
set udg_TowerModuleUsed[i] = true
set Caster = null
set Target = null
call TriggerSleepAction(1)
set udg_TowerModuleUsed[i] = false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition( function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope LearnTowerModules initializer Init
globals
private constant integer ABILITY_ID = 'A03H'
endglobals
private function Conditions takes nothing returns boolean
return GetLearnedSkill() == ABILITY_ID
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer l = GetUnitAbilityLevel(u,GetLearnedSkill())
if l == 1 then
call UnitAddAbility(u,'A086')
elseif l == 2 then
call UnitRemoveAbility(u,'A086')
call UnitAddAbility(u,'A087')
elseif l == 3 then
call UnitRemoveAbility(u,'A087')
call UnitAddAbility(u,'A088')
elseif l == 4 then
call UnitRemoveAbility(u,'A088')
call UnitAddAbility(u,'A089')
elseif l == 5 then
call UnitRemoveAbility(u,'A089')
call UnitAddAbility(u,'A08A')
endif
call UpdateTankCosts(GetPlayerNr(GetOwningPlayer(u)))
set u = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL )
call TriggerAddCondition(t, Condition( function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope EMPShock initializer Init
globals
private constant integer ABILITY_ID = 'A08B'
private constant integer AREA_BASE = 200
private constant integer EFFECT_3_COUNT = 3
private constant real EFFECT_SIZE = 2.75
private constant real HP_LIMIT = 0.2
endglobals
private function Actions takes nothing returns nothing
local integer i = 0
local unit caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(caster,ABILITY_ID)
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local real face = GetUnitFacing(caster)
local player owner = GetOwningPlayer(caster)
call DestroyTreesInRange(x, y, AREA_BASE)
call SetUnitState(caster,UNIT_STATE_LIFE, GetUnitState(caster, UNIT_STATE_LIFE)*HP_LIMIT)
call pSFX(CreateUnit(owner, DUMMY_ID, x, y, face), x, y, EFFECT_SIZE, "Abilities\\Weapons\\Bolt\\BoltImpact.mdl")
loop
exitwhen i >= EFFECT_3_COUNT
call pSFX(CreateUnit(owner, DUMMY_ID, x, y, face), x, y, EFFECT_SIZE, "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl")
call TriggerSleepAction(0.05)
set i = i + 1
endloop
call pSFX(CreateUnit(owner, DUMMY_ID, x, y, face), x, y, EFFECT_SIZE, "Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl")
set caster = null
set owner = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Explosives
globals
constant integer EXPLOSIVES_ABILITY_ID = 'A07H'
constant real EXPLOSIVES_FACTOR_BASE = 0
constant real EXPLOSIVES_FACTOR_UP = 0.12
endglobals
endscope
// You'll find the relevant code in 'Libraries -> Effects -> GetExplosiveDamage'
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Reconstruction
globals
constant integer RECONSTRUCTION_ABILITY_ID = 'A08C'
constant real RECONSTRUCTION_CHANCE_BASE = 0.0
constant real RECONSTRUCTION_CHANCE_UP = 0.07
endglobals
endscope
// You'll find the relevant code in 'Tanks -> Vehicle Dies
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ScoutWatchTower initializer Init
globals
private constant real DURATION_BASE = 35.0
private constant real DURATION_UP = 0.0
endglobals
private function Conditions takes nothing returns boolean
return IsWatchTower(GetConstructingStructure())
endfunction
private function Actions takes nothing returns nothing
local unit Tower = GetConstructingStructure()
local player Owner = GetOwningPlayer(GetTriggerUnit())
local integer LifeTime = R2I(DURATION_BASE)
call UnitApplyTimedLife(Tower, 'B015', LifeTime)
set Tower = null
set Owner = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_CONSTRUCT_START)
call TriggerAddCondition(t, Condition( function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=66
//TESH.alwaysfold=0
scope RuneCarving initializer Init
globals
private constant integer ABILITY_ID = 'A030'
private constant integer NORMAL_RUNE_ID = 'I04C'
private constant integer CARVED_RUNE_ID = 'I050'
private constant string EFFECT_STRING = "Abilities\\Spells\\Other\\Parasite\\ParasiteTarget.mdl"
private constant integer CREATE_RUNES_LEVEL = 3 // Level on which it is possible, to start creating completely new runes
private constant integer MAX_EFFECTS = 500
private constant integer MANA_COST_BASE = 0
private constant integer MANA_COST_UP = 10
endglobals
// These effects are meant as attachments to the healer runes
// But items don't have any attachment points on their models, so these effects
// are simply put on the ground beneath the rune itself
// But you still have to keep track of every placed rune effect
private function SetHealerEffect takes item Healer, effect e returns nothing
local integer i = 1
loop
exitwhen i > MAX_EFFECTS
if udg_Healer_Rune[i] == null then
set udg_Healer_Rune[i] = Healer
set udg_Healer_Effect[i] = e
return
endif
set i = i+1
endloop
call BJDebugMsg("Debug: No more Space for the Rune effect")
endfunction
private function DestroyRuneEffect takes item Healer returns nothing
local integer i = 1
loop
exitwhen i > MAX_EFFECTS
if udg_Healer_Rune[i] == Healer then
call DebugMsg("Unused carving effect detected")
set udg_Healer_Rune[i] = null
call DestroyEffect(udg_Healer_Effect[i])
set udg_Healer_Effect[i] = null
call DebugMsg("Effect destroyed")
return
endif
set i = i+1
endloop
endfunction
private function Actions takes nothing returns nothing
local unit U = GetSpellAbilityUnit()
local unit cu = GetTriggerUnit()
local item rune = GetSpellTargetItem()
local item tmpItem
local player Caster = GetOwningPlayer(U)
local string s = EFFECT_STRING
local real life
local integer i = 1
local integer level = GetUnitAbilityLevel(U, GetSpellAbilityId())
local integer manaCosts = MANA_COST_BASE + (level * MANA_COST_UP)
local real x
local real y
if (rune != null) then
set x = GetItemX(rune)
set y = GetItemY(rune)
call DebugMsg("Manipulate Rune")
else
call DebugMsg("No Target")
endif
// Normal case -> replace a normal rune with a carved one
if (GetItemTypeId(rune) == NORMAL_RUNE_ID) then
set life = GetWidgetLife(rune)
call RemoveItem(rune)
set tmpItem = CreateItem(CARVED_RUNE_ID,x,y)
call SetWidgetLife(tmpItem,life)
call SetItemPlayer(tmpItem,Caster, false)
// Effect is only visible to allies
if IsPlayerEnemy(GetLocalPlayer(), GetItemPlayer(tmpItem)) then
set s = ""
endif
call SetHealerEffect(tmpItem, AddSpecialEffect(s,x,y))
// Rune is already carved, but belongs to the enemy -> change the owning player to the caster
elseif (GetItemTypeId(rune) == CARVED_RUNE_ID) and IsPlayerEnemy(GetItemPlayer(rune), Caster) then
call SetItemPlayer(tmpItem,Caster, false)
// No healer rune as a target and level is high enough -> create a completely new rune
elseif (rune == null) and (level >= CREATE_RUNES_LEVEL) then
call DebugMsg("Create Rune")
set x = GetSpellTargetX()
set y = GetSpellTargetY()
set tmpItem = CreateItem(CARVED_RUNE_ID,x,y)
call SetWidgetLife(tmpItem,1)
call SetItemPlayer(tmpItem,Caster, false)
// Effect is only visible to allies
if IsPlayerEnemy(GetLocalPlayer(), GetItemPlayer(tmpItem)) then
set s = ""
endif
call SetHealerEffect(tmpItem, AddSpecialEffect(s,x,y))
else // No healer rune as a target and level is not high enough -> can't do shit
call IssueImmediateOrder(GetSpellAbilityUnit(), "stop")
call DisplayTextToPlayer(Caster, 0, 0, "|cfffed312You can only manipulate normal Healer-Runes.|r" )
call RefreshSkill(U, ABILITY_ID)
call SetUnitState(U,UNIT_STATE_MANA,(GetUnitState(U,UNIT_STATE_MANA)+(10*level)))
endif
set rune = null
set tmpItem = null
set U = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t,function Actions)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DefensiveSystems initializer Init
globals
private constant integer ABILITY_ID = 'A035'
private constant integer HEAL_ABILITY_ID = 'A09V'
private constant real DURATION_BASE = 12.0
private constant real DURATION_UP = 0.0
constant integer DEFENSIVE_SYSTEMS_RESISTANCE_ID = 'A02U'
endglobals
private function Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(U, ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
//heal
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(U), HEAL_ABILITY_ID, level, GetUnitX(U), GetUnitY(U), 0), "rejuvination", U)
// armor
call AddAbilityTimed(U, DEFENSIVE_SYSTEMS_RESISTANCE_ID, level, duration)
call SetPlayerAbilityAvailable(GetOwningPlayer(U), DEFENSIVE_SYSTEMS_RESISTANCE_ID, false)
set U = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TankEnsnared initializer Init
globals
private constant integer ABILITY_ID = 'A09O'
private constant real DURATION_BASE = 1.8
private constant real DURATION_UP = 0.6
endglobals
private function Actions takes nothing returns nothing
local unit U = GetSpellTargetUnit()
local integer level = GetUnitAbilityLevel(GetSpellAbilityUnit(), ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
local item bombs
local integer i = 0
local integer j = 0
local integer PlayerId
local integer weaponID
local real ItemLife
call UnitDamageTarget(GetSpellAbilityUnit(), U, 0, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
//deactivate Bombs or Flak, because the tank is now a ground unit
loop
exitwhen i > 5
set weaponID = GetItemTypeId(UnitItemInSlot(U, i))
//Bombs, Bombs (Upgrade), Flak, Flak (Upgrade)
if weaponID == 'I02Z' or weaponID == 'I03C' or weaponID == 'I057' or weaponID == 'I058' then
set ItemLife = GetWidgetLife(UnitItemInSlot(U, i))
call RemoveItem(UnitItemInSlot(U, i))
call UnitAddItemToSlotById(U, 'I051', i)
call SetWidgetLife(UnitItemInSlot(U, i), ItemLife)
endif
set i = i + 1
endloop
call GameTimeWait(duration)
set i = 0
set PlayerId = GetPlayerNr(GetOwningPlayer(U))
//activate the weapon again, as the net wears off
loop
exitwhen i > 5
if GetItemTypeId(UnitItemInSlot(U, i)) == 'I051' then
if GetWidgetLife(UnitItemInSlot(U, i)) == 6000 then
set weaponID = 'I02Z'
elseif GetWidgetLife(UnitItemInSlot(U, i)) == 7500 then
set weaponID = 'I03C'
elseif GetWidgetLife(UnitItemInSlot(U, i)) == 8000 then
set weaponID = 'I057'
elseif GetWidgetLife(UnitItemInSlot(U, i)) == 11000 then
set weaponID = 'I058'
endif
call RemoveItem(UnitItemInSlot(U, i))
if GetUnitState(U, UNIT_STATE_LIFE) > 0 then
set bombs = UnitAddItemById( U, weaponID)
call SetItemPlayer( bombs, GetOwningPlayer(U), false )
if udg_Afk[PlayerId] then
call SetItemDroppable( bombs, false )
endif
else
//when the tank is dead, give the weapon to him, after he revives
call GiveItemToDeadTank(PlayerId, weaponID)
endif
endif
set i = i + 1
endloop
set U = null
set bombs = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TripleShot initializer Init
globals
private constant integer ABILITY_ID = 'A02T'
private constant string MISSILE_EFFECT = "Abilities\\Spells\\Other\\TinkerRocket\\TinkerRocketMissile.mdl"
endglobals
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
call TS.Create(u,GetSpellTargetUnit(),13.0,0.15,GetUnitAbilityLevel(u,ABILITY_ID),MISSILE_EFFECT)
set u = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Repair initializer Init
globals
private constant integer ABILITY_ID = 'A0BM'
private constant integer BUFF_ABILITY_ID = 'A0C3'
private constant integer BUFF_ID = 'B018'
private constant real HEAL_BASE = 0.0
private constant real HEAL_UP = 120.0
private constant real HEAL_PERCENTAGE_BASE = 0.0 // percentage is based on the max HP of the target
private constant real HEAL_PERCENTAGE_UP = 0.06
private constant real DURATION_BASE = 5.0
private constant real DURATION_UP = 0
endglobals
function Trig_Repair_Actions takes nothing returns nothing
local unit U = GetSpellAbilityUnit()
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local real hpHeal = HEAL_BASE + (lvl * HEAL_UP) + (GetUnitState(U, UNIT_STATE_MAX_LIFE) * (HEAL_PERCENTAGE_BASE + (lvl * HEAL_PERCENTAGE_UP)))
local real duration = DURATION_BASE + (lvl * DURATION_UP)
call UnitAddAbility(U, BUFF_ABILITY_ID)
call HealOverTime(U, hpHeal, 0, duration, 0, true)
call GameTimeWait(duration)
call UnitRemoveAbility(U, BUFF_ABILITY_ID)
call UnitRemoveAbility(U, BUFF_ID)
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Repair = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Repair, ABILITY_ID )
call TriggerAddAction( gg_trg_Repair, function Trig_Repair_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope MultiRocketShot initializer Init
globals
private constant integer ABILITY_ID = 'A06V'
private constant integer DAMAGE_ABILITY_ID = 'A03W'
private constant real DELAY = 0.75
// The delay is tied to the base ability, it's the approximate time the projectile needs to hit the choosen target
// The actual distance the projetile travels does not seem to influence this time
endglobals
function Trig_Multi_Rocket_Shot_Impact takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer TimerIndex = GetHandleIndex(t)
local integer level = udg_AV_Int1[TimerIndex]
local real X = udg_AV_Real1[TimerIndex]
local real Y = udg_AV_Real2[TimerIndex]
call IssueImmediateOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(udg_AV_Unit1[TimerIndex]), DAMAGE_ABILITY_ID, level, X, Y, 0), "fanofknives" )
call ReleaseHandleIndex(TimerIndex)
call ReleaseTimer(t)
endfunction
function Trig_Multi_Rocket_Shot_Actions takes nothing returns nothing
local timer t = NewTimer()
local integer TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[TimerIndex] = GetUnitAbilityLevel(GetTriggerUnit(),ABILITY_ID)
set udg_AV_Unit1[TimerIndex] = GetTriggerUnit()
set udg_AV_Real1[TimerIndex] = GetSpellTargetX()
set udg_AV_Real2[TimerIndex] = GetSpellTargetY()
call TimerStart(t, DELAY, false, function Trig_Multi_Rocket_Shot_Impact)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Multi_Rocket_Shot = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Multi_Rocket_Shot, ABILITY_ID )
call TriggerAddAction( gg_trg_Multi_Rocket_Shot, function Trig_Multi_Rocket_Shot_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope FireBomb initializer Init
globals
private constant integer ABILITY_ID = 'A01B'
private constant real DAMAGE_BASE = 480.0
private constant real DAMAGE_UP = 160.0
private constant real AREA_BASE = 300.0
private constant real AREA_UP = 0.0
endglobals
function Trig_Fire_Bomb_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(caster,ABILITY_ID)
local real damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local location TargetLoc = GetUnitLoc(GetSpellTargetUnit())
call DestroyEffect(AddSpecialEffectLoc("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",TargetLoc))
set udg_Filter_Player = GetOwningPlayer(caster)
call FixedAreaDamageFromUnit(caster, GetLocationX(TargetLoc), GetLocationY(TargetLoc), area, damage, 1.0, 0, false, FILTER_ENEMY_UNITS)
call DestroyTreesInRange(GetLocationX(TargetLoc), GetLocationY(TargetLoc), area)
call RemoveLocation( TargetLoc )
set TargetLoc = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Fire_Bomb = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Fire_Bomb, ABILITY_ID )
call TriggerAddAction( gg_trg_Fire_Bomb, function Trig_Fire_Bomb_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope EMPTorpedos initializer Init
globals
private constant integer ABILITY_ID = 'A07E'
private constant integer STUN_ABILITY_ID = 'A07F'
private constant real AREA_BASE = 900.0
private constant real AREA_UP = 0.0
endglobals
function Trig_EMP_Torpedos_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local player Owner = GetOwningPlayer(Caster)
local unit Dummy
local real DummyX = GetUnitX(Caster)
local real DummyY = GetUnitY(Caster)
local real DummyFlyHeight = GetUnitFlyHeight(Caster)
local group G = NewGroup()
local unit EnumUnit
local integer AbilityLevel = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real range = AREA_BASE + ( AREA_UP * AbilityLevel )
call GroupEnumUnitsInRange(G, DummyX,DummyY, range, null)
loop
set EnumUnit = FirstOfGroup(G)
exitwhen EnumUnit==null
if GetUnitState(EnumUnit, UNIT_STATE_LIFE) > 0 and IsUnitEnemy(EnumUnit, Owner) then
if IsUnitVisible(EnumUnit, Owner) and GetUnitAbilityLevel(EnumUnit, 'Avul') == 0 then
set Dummy = CreateDummyWithAbilityCoord(Owner, STUN_ABILITY_ID, AbilityLevel, DummyX, DummyY, DummyFlyHeight)
call IssueTargetOrder( Dummy, "thunderbolt", EnumUnit )
endif
endif
call GroupRemoveUnit(G, EnumUnit)
endloop
call ReleaseGroup(G)
set G = null
set Caster = null
set Owner = null
set Dummy = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_EMP_Torpedos = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_EMP_Torpedos, ABILITY_ID )
call TriggerAddAction( gg_trg_EMP_Torpedos, function Trig_EMP_Torpedos_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Jump initializer Init
globals
private constant integer ABILITY_ID = 'A02W'
private constant real MAX_DISTANCE_BASE = 200.0
private constant real MAX_DISTANCE_UP = 400.0
private constant real SPEED_BASE = 1000.0
private constant real SPEED_UP = 0.0
private constant real INTERVAL = 0.02
private constant real MIN_FLY_HEIGHT = 40.0
endglobals
function Trig_Jump_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local location TargetLoc = udg_AV_Loc1[LoopTimerId]
local real Speed = (SPEED_BASE + (udg_AV_Int1[LoopTimerId] * SPEED_UP)) * INTERVAL
local real Distance = udg_AV_Real1[LoopTimerId]
local real DistanceLeft
local real DistanceDone
local real DistX
local real DistY
local real AngleRad
local real HeightChangeDist = Distance/3
if HeightChangeDist>300 then
set HeightChangeDist = 300
endif
if GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
call SetUnitFlyHeight(U,0,400)
call SetUnitPathing(U,true)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call RemoveLocation(TargetLoc)
else
set DistX = GetLocationX(TargetLoc)-GetUnitX(U)
set DistY = GetLocationY(TargetLoc)-GetUnitY(U)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if (DistanceLeft <= 20) then
set DistanceLeft = 0
call SetUnitFlyHeight(U,MIN_FLY_HEIGHT,0)
call SetUnitPathing(U,true)
call SetUnitPositionLoc(U,TargetLoc)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call RemoveLocation(TargetLoc)
else
set DistanceDone = Distance - DistanceLeft
call SetUnitPosition(U,GetUnitX(U)+Speed*DistX/DistanceLeft,GetUnitY(U)+Speed*DistY/DistanceLeft)
if DistanceLeft < HeightChangeDist then
call SetUnitFlyHeight(U,MIN_FLY_HEIGHT+0.7*HeightChangeDist*(1-((DistanceLeft/HeightChangeDist)-1)*((DistanceLeft/HeightChangeDist)-1)),0)
elseif DistanceDone < HeightChangeDist then
call SetUnitFlyHeight(U,MIN_FLY_HEIGHT+0.7*HeightChangeDist*(1-((DistanceDone/HeightChangeDist)-1)*((DistanceDone/HeightChangeDist)-1)),0)
else
call SetUnitFlyHeight(U,MIN_FLY_HEIGHT+0.7*HeightChangeDist,0)
endif
endif
call SetUnitFacing(U, Atan2(DistY, DistX)*bj_RADTODEG)
endif
set TargetLoc = null
set U = null
endfunction
function Trig_Jump_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local location TargetLoc = GetSpellTargetLoc()
local integer PlayerId = GetPlayerNr(GetOwningPlayer(Caster))
local real TargetAngleRad
local real DistanceMax = MAX_DISTANCE_BASE + ( GetUnitAbilityLevel(Caster,ABILITY_ID) * MAX_DISTANCE_UP )
local real DistX = GetLocationX(TargetLoc)-GetUnitX(Caster)
local real DistY = GetLocationY(TargetLoc)-GetUnitY(Caster)
local real Distance = SquareRoot(DistX*DistX+DistY*DistY)
local boolean InvalidJump = false
local timer t
local integer LoopTimerId
if Distance > DistanceMax then
set Distance = DistanceMax
set TargetAngleRad = Atan2(GetLocationY(TargetLoc) - GetUnitY(Caster), GetLocationX(TargetLoc) - GetUnitX(Caster))
call MoveLocation(TargetLoc,GetUnitX(Caster)+Distance*Cos(TargetAngleRad),GetUnitY(Caster)+Distance*Sin(TargetAngleRad))
elseif Distance < 100 then
set Distance = 100
set TargetAngleRad = Atan2(GetLocationY(TargetLoc) - GetUnitY(Caster), GetLocationX(TargetLoc) - GetUnitX(Caster))
call MoveLocation(TargetLoc,GetUnitX(Caster)+Distance*Cos(TargetAngleRad),GetUnitY(Caster)+Distance*Sin(TargetAngleRad))
endif
//if IsTerrainWalkable(GetLocationX(TargetLoc), GetLocationY(TargetLoc)) then
if GetPathableLoc(TargetLoc, 32, 768) then
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(Caster))] == 1 then
set InvalidJump = RectContainsLoc(gg_rct_Team_2_Base_Main, TargetLoc)
else
set InvalidJump = RectContainsLoc(gg_rct_Team_1_Base_Main, TargetLoc)
endif
//set InvalidJump = false
if InvalidJump then
call DisplayTextToPlayer(GetOwningPlayer(Caster),0,0,"|cfffed312You cannot jump into the enemy base.|r" )
endif
else
set InvalidJump = true
call DisplayTextToPlayer(GetOwningPlayer(Caster),0,0,"|cfffed312There is no space to land.|r" )
endif
if InvalidJump then
set udg_AI_Spell_Aborted = true
call IssueImmediateOrder( Caster, "stop" )
call RemoveLocation(TargetLoc)
call SetUnitManaDelayed(Caster, GetUnitState(Caster, UNIT_STATE_MANA))
//set TargetLoc = null
set Caster = null
return
endif
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set DistX = GetLocationX(TargetLoc)-GetUnitX(Caster)
set DistY = GetLocationY(TargetLoc)-GetUnitY(Caster)
set udg_AV_Unit1[LoopTimerId] = Caster
set udg_AV_Loc1[LoopTimerId] = TargetLoc
set udg_AV_Real1[LoopTimerId] = SquareRoot(DistX*DistX+DistY*DistY)
set udg_AV_Int1[LoopTimerId] = GetUnitAbilityLevel(Caster, ABILITY_ID)
call TimerStart(t, INTERVAL, true, function Trig_Jump_Loop)
call UnitAddAbility(Caster,'Amrf')
call UnitRemoveAbility(Caster,'Amrf')
call SetUnitPathing(Caster,false)
set Caster = null
set TargetLoc = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Jump = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Jump, ABILITY_ID )
call TriggerAddAction( gg_trg_Jump, function Trig_Jump_Actions )
endfunction
endscope
//TESH.scrollpos=23
//TESH.alwaysfold=0
scope DimensionShift initializer Init
globals
private constant integer ABILITY_ID = 'A07G'
private constant integer MARKER_ABILITY_ID = 'A097' // does nothing, but giving the possibility to check for this to see if the unit is affected by Dimension Shift
private constant real DAMAGE_PERCENTAGE_BASE = 0.15
private constant real DAMAGE_PERCENTAGE_UP = 0.0
private constant real DURATION_BASE = 2.1
private constant real DURATION_UP = 0.7
endglobals
function Trig_Dimension_Shift_Actions takes nothing returns nothing
local unit Target = GetSpellTargetUnit()
local integer AbilityLevel = GetUnitAbilityLevel(GetTriggerUnit(),ABILITY_ID)
local effect E = AddSpecialEffectTarget("Abilities\\Spells\\Other\\Drain\\ManaDrainTarget.mdl",Target,"origin")
local real beginGameTime = TimerGetElapsed(udg_GameTime)
local boolean EffectBreak = false
local real timeRemaining
local real duration = DURATION_BASE + ( AbilityLevel * DURATION_UP )
local real damagePercentage = DAMAGE_PERCENTAGE_BASE + ( AbilityLevel * DAMAGE_PERCENTAGE_UP )
call UnitAddAbility(Target, MARKER_ABILITY_ID)
call IssueImmediateOrder(Target,"stop")
call UnitDamageTarget(GetTriggerUnit(), Target, GetUnitState(Target, UNIT_STATE_LIFE)*damagePercentage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
set IgnoreSplashToggle = true
call MakeUnitInvulnerable(Target, true)
call PauseUnit( Target, true )
set IgnoreSplashToggle = false
loop
set timeRemaining = duration+beginGameTime-TimerGetElapsed(udg_GameTime)
exitwhen timeRemaining <= 0
if timeRemaining > 1 and not EffectBreak then
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\DarkRitual\\DarkRitualTarget.mdl",Target,"origin"))
endif
set EffectBreak = not EffectBreak
call TriggerSleepAction(0)
endloop
set IgnoreSplashToggle = true
call PauseUnit( Target, false )
call MakeUnitInvulnerable(Target, false)
set IgnoreSplashToggle = false
call ResetSplashCannon(Target)
call UnitRemoveAbility(Target, MARKER_ABILITY_ID)
call DestroyEffect(E)
set E = null
set Target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Dimension_Shift = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Dimension_Shift, ABILITY_ID )
call TriggerAddAction( gg_trg_Dimension_Shift, function Trig_Dimension_Shift_Actions )
endfunction
endscope
//TESH.scrollpos=42
//TESH.alwaysfold=0
scope SuperThrust initializer Init
globals
private constant integer ABILITY_ID = 'A0BA'
private constant integer SPEED_ABILITY_ID = 'A0BB'
private constant integer DAMAGE_ABILITY_ID = 'A0BJ'
private constant real MAX_DISTANCE_BASE = 1300.0
private constant real MAX_DISTANCE_UP = 0.0
private constant real ILLUSION_SPEED_BASE = 1100.0
private constant real ILLUSION_SPEED_UP = 0.0
private constant real INTERVAL = 0.02
private constant real ACTIVATION_RANGE = 175.0
endglobals
function Trig_Superthrust_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local unit Dummy = udg_AV_Unit2[LoopTimerId]
local location TargetLoc = udg_AV_Loc1[LoopTimerId]
local group G = NewGroup()
local real DistanceLeft = udg_AV_Real1[LoopTimerId]
local real DistX
local real DistY
local integer level = GetUnitAbilityLevel(U,ABILITY_ID)
local real moveDistance = (ILLUSION_SPEED_BASE + ( level * ILLUSION_SPEED_UP )) * INTERVAL
local integer LoopsLeft = udg_AV_Int1[LoopTimerId]
set udg_Filter_Player = GetOwningPlayer(U)
call GroupEnumUnitsInRange(G, GetUnitX(Dummy),GetUnitY(Dummy), ACTIVATION_RANGE, FILTER_ENEMY_TANK)
if FirstOfGroup(G) != null then
call IssueImmediateOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(U), DAMAGE_ABILITY_ID, level, GetUnitX(FirstOfGroup(G)), GetUnitY(FirstOfGroup(G)), 0), "fanofknives")
call SetUnitVertexColor( Dummy, 255, 255, 255, 150 )
call KillUnit(Dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call RemoveLocation(TargetLoc)
else
set DistX = GetLocationX(TargetLoc)-GetUnitX(Dummy)
set DistY = GetLocationY(TargetLoc)-GetUnitY(Dummy)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
set udg_AV_Int1[LoopTimerId] = LoopsLeft - 1
//LoopsLeft prevents the dummy from getting stuck on the map border forever
if (DistanceLeft <= moveDistance) or (LoopsLeft == 0) then
call ShowUnit(Dummy, false)
call KillUnit(Dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call RemoveLocation(TargetLoc)
else
// Either don't use SetUnitX/Y or check if the illusion is still within the playable map area
call SetUnitPosition( Dummy, GetUnitX(Dummy) + moveDistance*DistX/DistanceLeft, GetUnitY(Dummy) + moveDistance*DistY/DistanceLeft )
call SetUnitFacing(Dummy, Atan2(DistY, DistX)*bj_RADTODEG)
call SetUnitVertexColor( Dummy, 255, 255, 255, R2I(150*DistanceLeft/850) )
set udg_AV_Real1[LoopTimerId] = DistanceLeft
endif
endif
call ReleaseGroup(G)
set G = null
set TargetLoc = null
set U = null
endfunction
function Trig_Superthrust_Actions takes nothing returns nothing
local timer t
local unit U = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(U,ABILITY_ID)
local real facerad = GetUnitFacing(U)*bj_DEGTORAD
local real Distance = MAX_DISTANCE_BASE + ( level * MAX_DISTANCE_UP )
local real Speed = ILLUSION_SPEED_BASE + ( level * ILLUSION_SPEED_UP )
local real CasterX = GetUnitX(U)
local real CasterY = GetUnitY(U)
local location targetloc = Location(CasterX + Distance * Cos(facerad), CasterY + Distance * Sin(facerad))
local integer LoopTimerId
local unit Dummy = CreateUnit(GetOwningPlayer(U), 'h019', CasterX, CasterY, GetUnitFacing(U))
call SetUnitVertexColor( Dummy, 255, 255, 255, 150 )
call SetUnitFlyHeight( Dummy, GetUnitFlyHeight(U), 0 )
//speed bonus
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(U), SPEED_ABILITY_ID, 1, GetUnitX(U), GetUnitY(U), 0), "slow", U)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\OrbOfDeath\\OrbOfDeathMissile.mdl",U,"foot"))
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Loc1[LoopTimerId] = targetloc
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Unit2[LoopTimerId] = Dummy
set udg_AV_Int1[LoopTimerId] = R2I(Distance / ( Speed * INTERVAL )) // < number of iterations, before the destination is reached
set udg_AV_Real1[LoopTimerId] = Distance
call TimerStart(t, INTERVAL, true, function Trig_Superthrust_Loop)
set U = null
set targetloc = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Superthrust = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Superthrust, ABILITY_ID )
call TriggerAddAction( gg_trg_Superthrust, function Trig_Superthrust_Actions )
endfunction
endscope
//TESH.scrollpos=19
//TESH.alwaysfold=0
scope LifeConverter initializer Init
globals
private constant integer ABILITY_ID = 'A0B8'
private constant real LEECH_AREA_BASE = 225.0
private constant real LEECH_AREA_UP = 0.0
private constant real HEAL_AREA_BASE = 700.0
private constant real HEAL_AREA_UP = 0.0
private constant real HP_LEECH_BASE = 0.0
private constant real HP_LEECH_UP = 0.08
endglobals
function Trig_Life_Converter_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local player Owner = GetOwningPlayer(Caster)
local real CasterX = GetUnitX(Caster)
local real CasterY = GetUnitY(Caster)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local real damage
local real totaldamage = 0
local group G = NewGroup()
local unit EnumUnit
local integer Level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real leechRange = LEECH_AREA_BASE + ( Level * LEECH_AREA_UP )
local real healRange = HEAL_AREA_BASE + ( Level * HEAL_AREA_UP )
local real leechPercentage = HP_LEECH_BASE + ( Level * HP_LEECH_UP )
set udg_Filter_Player = Owner
call GroupEnumUnitsInRange(G, TargetX,TargetY, leechRange, FILTER_ENEMY_CREEP)
set udg_TempGroup = NewGroup()
call GroupEnumUnitsInRange(udg_TempGroup, TargetX,TargetY, leechRange, FILTER_DECOY)
// add the units of the TempGroup into group G
call GroupAddGroup(udg_TempGroup, G)
loop
set EnumUnit = FirstOfGroup(G)
exitwhen EnumUnit==null
if (IsDecoy(EnumUnit) and IsUnitAlly(EnumUnit, Owner)) then
set damage = GetUnitState(EnumUnit, UNIT_STATE_LIFE)
call KillUnit(EnumUnit)
elseif (GetUnitState(EnumUnit, UNIT_STATE_LIFE) < GetUnitState(EnumUnit, UNIT_STATE_MAX_LIFE)*leechPercentage) then
set damage = GetUnitState(EnumUnit, UNIT_STATE_LIFE)
else
set damage = GetUnitState(EnumUnit, UNIT_STATE_MAX_LIFE)*leechPercentage
endif
set totaldamage = totaldamage + damage
call UnitDamageTarget(Caster, EnumUnit, damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(G, EnumUnit)
endloop
set udg_Filter_Player = Owner
call GroupEnumUnitsInRange(G, CasterX,CasterY, healRange, FILTER_ALLY_TANK)
//set damage = totaldamage / CountUnitsInGroup(G)
loop
set EnumUnit = FirstOfGroup(G)
exitwhen EnumUnit==null
call ShowTextTag("|cff00ff00+"+I2S(R2I(totaldamage))+"|r", EnumUnit, 0, 50, null)
call SetUnitState(EnumUnit, UNIT_STATE_LIFE, GetUnitState(EnumUnit, UNIT_STATE_LIFE)+totaldamage)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\ReplenishHealth\\ReplenishHealthCasterOverhead.mdl",EnumUnit,"overhead"))
call GroupRemoveUnit(G, EnumUnit)
endloop
call ReleaseGroup(G)
call ReleaseGroup(udg_TempGroup)
set G = null
set Caster = null
set Owner = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Life_Converter = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Life_Converter, ABILITY_ID )
call TriggerAddAction( gg_trg_Life_Converter, function Trig_Life_Converter_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Decoy initializer Init
globals
private constant integer ABILITY_ID = 'A07D'
private constant integer SUMMON_CHANCE_BASE = 25
private constant integer SUMMON_CHANCE_UP = 5
private constant real DURATION_BASE = 20.0
private constant real DURATION_UP = 0.0
endglobals
private function Conditions takes nothing returns boolean
local integer Level
local player p = GetOwningPlayer(GetKillingUnit())
if p==null then
return false
endif
set Level = GetUnitAbilityLevel(udg_Tank[GetPlayerNr(p)],ABILITY_ID)
if Level <= 0 then
return false
else
//call DebugMsg("Decoy Level " + I2S(Level))
endif
return GetRandomInt(1, 100) <= (SUMMON_CHANCE_BASE + ( Level * SUMMON_CHANCE_UP ))
endfunction
private function Actions takes nothing returns nothing
local unit Target = GetTriggerUnit()
local unit Decoy
local integer unitId
local integer level = GetUnitAbilityLevel(udg_Tank[GetPlayerNr(GetOwningPlayer(GetKillingUnit()))],ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
if IsUnitType(Target,UNIT_TYPE_STRUCTURE) == false then
if level == 1 then
set unitId = 'n008'
elseif level == 2 then
set unitId = 'n009'
elseif level == 3 then
set unitId = 'n00H'
elseif level == 4 then
set unitId = 'n00V'
elseif level == 5 then
set unitId = 'n00W'
else
set Target = null
return
endif
set Decoy = CreateUnit(GetOwningPlayer(GetKillingUnit()), unitId, GetUnitX(Target), GetUnitY(Target), 270)
call UnitApplyTimedLife(Decoy, 'BTLF', duration)
call DestroyEffect( AddSpecialEffect("Abilities\\Spells\\Orc\\FeralSpirit\\feralspirittarget.mdl", GetUnitX(Target), GetUnitY(Target)) )
//call DestroyEffect( AddSpecialEffect("Abilities\\Spells\\Orc\\Reincarnation\\ReincarnationTarget.mdl", GetUnitX(Target), GetUnitY(Target)) )
endif
set Decoy = null
set Target = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition(t, Condition( function Conditions))
call TriggerAddAction(t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope SupportSystems initializer Init
globals
private constant integer ABILITY_ID = 'A0BL'
private constant integer PROTECTION_ID = 'A07C'
private constant real DUMMY_DURATION = 1.00
private constant real INTERVAL = 0.02
endglobals
private function Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local unit dummy = udg_AV_Unit2[LoopTimerId]
local real X = GetUnitX(U)
local real Y = GetUnitY(U)
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] - 1
if (GetUnitState(U, UNIT_STATE_LIFE) <= 0) or (udg_AV_Int1[LoopTimerId] <= 0) then
call ReleaseDummy(dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
call SetUnitPosition(dummy,X,Y)
endif
set dummy = null
set U = null
endfunction
private function Actions takes nothing returns nothing
local timer t
local unit U = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(U,ABILITY_ID)
local integer LoopTimerId
local unit dummy = CreateDummyWithAbilityCoord(GetOwningPlayer(U), PROTECTION_ID, level, GetUnitX(U),GetUnitY(U),GetUnitFlyHeight(U))
call DebugMsg("Support Systems")
call SetUnitFlyHeight(dummy, GetUnitFlyHeight(U), 0)
call AddSpecialEffectTarget("Abilities\\Spells\\Undead\\ReplenishHealth\\ReplenishHealthCasterOverhead.mdl", dummy, "origin")
call SetUnitScale(dummy, 8, 8, 8)
call SetUnitVertexColor( dummy, 255, 255, 255, 70 )
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Unit2[LoopTimerId] = dummy
set udg_AV_Int1[LoopTimerId] = R2I(DUMMY_DURATION / INTERVAL)
call TimerStart(t, INTERVAL, true, function Loop)
set U = null
set dummy = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=112
//TESH.alwaysfold=0
scope HeatSeekingMissile initializer Init
globals
private constant real SPEED_BASE = 700.0
private constant real SPEED_UP = 0.0
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 100.0
private constant real AREA_BASE = 225.0
private constant real AREA_UP = 0.0
private constant real RESTOCK_INTERVAL_BASE = 28.0
private constant real RESTOCK_INTERVAL_UP = -3.0
private constant real SEEKING_AREA = 1200.0
private constant real PROJETILE_TIMED_LIFE = 20.0
constant integer HSM_ABILITY_ID = 'A0FU'
constant integer HSM_MAX_RESTOCK_BASE = 3
constant integer HSM_MAX_RESTOCK_UP = 0
integer array HSM_MissileCount[10]
endglobals
function Trig_HeatSeeking_Missile_Learn_Conditions takes nothing returns boolean
return GetLearnedSkill() == HSM_ABILITY_ID
endfunction
function Trig_Trig_HeatSeeking_Missile_Learn_Restock takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Source = udg_AV_Unit1[LoopTimerId]
local integer learnedLevel = udg_AV_Int1[LoopTimerId]
local integer currentLevel = GetUnitAbilityLevel(Source, HSM_ABILITY_ID)
local integer sourceId = GetPlayerNr(GetOwningPlayer(Source))
local integer maxMissiles = HSM_MAX_RESTOCK_BASE + (currentLevel * HSM_MAX_RESTOCK_UP)
// each time you level up the ability, a new timer is started (timer interval may change with each level)
// so kill the current timer, when it's running for the old skill level
// this also stops the timer, when you change the tank
if (learnedLevel != currentLevel) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
if (GetUnitState(Source, UNIT_STATE_LIFE) > 0) then
set HSM_MissileCount[sourceId] = IMinBJ(HSM_MissileCount[sourceId] + 1, maxMissiles)
endif
endif
set Source = null
endfunction
function Trig_HeatSeeking_Missile_Learn_Actions takes nothing returns nothing
local timer t
local integer ShootTimerId
local unit Source = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(Source, HSM_ABILITY_ID)
local real restockInterval = RESTOCK_INTERVAL_BASE + ( level * RESTOCK_INTERVAL_UP )
if (level == 1) then
call DebugMsg("First Level HSM")
set HSM_MissileCount[GetPlayerNr(GetOwningPlayer(Source))] = 1
call PermanentTimedLife(Source, -1, GetOwningPlayer(Source), "||||", "|cff000000", -20, function PermanentTimedLife_HeatSeekingMissile)
endif
set t = NewTimer()
set ShootTimerId = NewTimerIndex(t)
set udg_AV_Unit1[ShootTimerId] = Source
set udg_AV_Int1[ShootTimerId] = level
call TimerStart(t , restockInterval , true , function Trig_Trig_HeatSeeking_Missile_Learn_Restock)
set Source = null
endfunction
function Trig_HeatSeeking_Missile_Destructor takes ProjectileMover pm returns nothing
call ShowEffectAtPos("war3mapImported\\NewAirEX.mdx", GetUnitX(pm.Projectile), GetUnitY(pm.Projectile), GetUnitFlyHeight(pm.Projectile), 2, 3)
call DestroyEffect(udg_AV_Effect1[pm.TimerIndex])
call ReleaseDummy(pm.Projectile)
endfunction
function Trig_HeatSeeking_Missile_Loop takes ProjectileMover pm returns boolean
local integer level = udg_AV_Int2[pm.TimerIndex]
local real damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local group G
local boolean result = false
// check if there is another unit, that is now closer to the missile
if ModuloInteger(udg_AV_Int3[pm.TimerIndex], 10) == 0 then
set G = NewGroup()
//call DebugMsg("Source: " + GetName(pm.Source))
set udg_Filter_Player = GetOwningPlayer(pm.Source)
call GroupEnumUnitsInRange(G, GetUnitX(pm.Projectile),GetUnitY(pm.Projectile), SEEKING_AREA, FILTER_ENEMY_UNITS )
if (FirstOfGroup(G) != null) then
set pm.Target = GetClosestUnitFromGroup(G, GetUnitX(pm.Projectile),GetUnitY(pm.Projectile))
//call DebugMsg("Target: " + GetName(pm.Target))
call SetUnitFacing(pm.Projectile, bj_RADTODEG * Atan2(GetUnitY(pm.Target) - GetUnitY(pm.Projectile), GetUnitX(pm.Target) - GetUnitX(pm.Projectile)))
else
set pm.Target = null
endif
call ReleaseGroup(G)
set G = null
endif
set udg_AV_Int3[pm.TimerIndex] = udg_AV_Int3[pm.TimerIndex] + 1
if ( GetUnitState(pm.Projectile , UNIT_STATE_LIFE) <= 0 ) or (pm.Target == null) then
set result = true
elseif (pm.DistanceToTarget <= pm.Speed) then
set udg_Filter_Player = GetOwningPlayer(pm.Source)
call FixedAreaDamageFromUnit(pm.Projectile, GetUnitX(pm.Target), GetUnitY(pm.Target), area, damage, 0.5, 0, false, FILTER_ENEMY_UNITS )
set result = true
endif
return result
endfunction
function Trig_HeatSeeking_Missile_Actions takes nothing returns nothing
local unit Source = GetTriggerUnit()
local unit Projectile
local integer sourceId = GetPlayerNr(GetOwningPlayer(Source))
local real face = GetUnitFacing(Source)
local integer level = GetUnitAbilityLevel(Source, HSM_ABILITY_ID)
local effect fx
local ProjectileMover pm
local real Speed = SPEED_BASE + ( level * SPEED_UP )
if (HSM_MissileCount[sourceId] > 0) then
set Projectile = XE_NewDummyUnit(GetOwningPlayer(Source) , GetUnitX(Source) , GetUnitY(Source) , face)
call SetUnitScale(Projectile, 1.5, 1.5, 1.5)
call SetUnitFlyHeight(Projectile, GetUnitFlyHeight(Source), 0)
set fx = AddSpecialEffectTarget("Abilities\\Weapons\\GreenDragonMissile\\GreenDragonMissile.mdl" , Projectile , "origin")
set pm = ProjectileMover.Create(Source, Projectile, null, 0, 0)
call pm.Initialize(Speed, 0.2, ProjLooperFunction.Trig_HeatSeeking_Missile_Loop, ProjDestructorFunction.Trig_HeatSeeking_Missile_Destructor)
set udg_AV_Int2[pm.TimerIndex] = level
set udg_AV_Int3[pm.TimerIndex] = 0
set udg_AV_Effect1[pm.TimerIndex] = fx
set HSM_MissileCount[sourceId] = HSM_MissileCount[sourceId] - 1
else
call SetUnitManaDelayed(Source, GetUnitState(Source, UNIT_STATE_MANA))
endif
set Projectile = null
set Source = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t
set gg_trg_HeatSeeking_Missile = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_HeatSeeking_Missile, HSM_ABILITY_ID )
call TriggerAddAction( gg_trg_HeatSeeking_Missile, function Trig_HeatSeeking_Missile_Actions )
set t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL )
call TriggerAddCondition(t, Condition( function Trig_HeatSeeking_Missile_Learn_Conditions))
call TriggerAddAction( t, function Trig_HeatSeeking_Missile_Learn_Actions )
endfunction
endscope
//TESH.scrollpos=17
//TESH.alwaysfold=0
scope ReactiveArmor initializer Init
globals
private constant integer ABILITY_ID = 'A0FS'
private constant integer BUFF_ID = 'B01Y'
private constant real BLOCK_BASE = 1.0
private constant real BLOCK_UP = 0.0
private constant real BLOCK_COUNT_BASE = 0.0
private constant real BLOCK_COUNT_UP = 0.5
private constant real DURATION_BASE = 6.0
private constant real DURATION_UP = 0.0
integer array ReactiveArmor_Level[10]
integer array ReactiveArmor_Blocked[10]
private integer DD_ID
endglobals
function Trig_Reactive_Armor_Damage takes nothing returns real
local real targetHP = GetUnitState(DamageDetection_DamageTarget, UNIT_STATE_LIFE)
local integer sourceId = GetPlayerNr(GetOwningPlayer(DamageDetection_DamageSource))
local integer targetId = GetPlayerNr(GetOwningPlayer(DamageDetection_DamageTarget))
local integer level = ReactiveArmor_Level[targetId]
local real maxBlock = BLOCK_COUNT_BASE + ( level * BLOCK_COUNT_UP )
local real blockedDamage
if (GetUnitAbilityLevel(DamageDetection_DamageTarget, BUFF_ID) > 0) and (sourceId <= GetMaxHumanPlayers()) then
set blockedDamage = ((BLOCK_BASE + ( level * BLOCK_UP ))) * DamageDetection_Damage
set ReactiveArmor_Blocked[targetId] = ReactiveArmor_Blocked[targetId] + 1
call SetUnitState(DamageDetection_DamageTarget, UNIT_STATE_LIFE, GetUnitState(DamageDetection_DamageTarget, UNIT_STATE_LIFE) + blockedDamage)
call ShowTextTag("|cff00ff00+"+I2S(R2I(blockedDamage))+"|r", DamageDetection_DamageTarget, 0, 50, null)
if (ReactiveArmor_Blocked[targetId] >= maxBlock) then
call UnitRemoveAbility(DamageDetection_DamageTarget, BUFF_ID)
endif
// the damage system interprets postive values as additional damage and negative ones as reduced damage
return -(BLOCK_BASE + ( level * BLOCK_UP ))
endif
return 0.0
endfunction
function Trig_Reactive_Armor_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local integer level = GetUnitAbilityLevel(caster, ABILITY_ID)
local real duration = DURATION_BASE + (level * DURATION_UP)
set ReactiveArmor_Level[GetPlayerNr(GetOwningPlayer(target))] = level
set ReactiveArmor_Blocked[GetPlayerNr(GetOwningPlayer(target))] = 0
call EnableSkillDamageDetection(DD_ID)
call GameTimeWait(duration)
call DisableSkillDamageDetection(DD_ID)
set caster = null
set target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Reactive_Armor = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodeRelative(DamageAlterationFunction.Trig_Reactive_Armor_Damage)
call TriggerRegisterSpellEffectEvent( gg_trg_Reactive_Armor, ABILITY_ID )
call TriggerAddAction( gg_trg_Reactive_Armor, function Trig_Reactive_Armor_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TankersLittleHelper
globals
constant integer TLH_ABILITY_ID = 'A0FT'
constant real TLH_BONUS_BASE = 0
constant real TLH_BONUS_UP = 60.0
endglobals
endscope
// You'll find the relevant code in 'Players -> Multiboards -> MB_SetSupport'
//TESH.scrollpos=42
//TESH.alwaysfold=0
scope SharingIsCaring initializer Init
globals
private constant integer ABILITY_ID = 'A0FW'
private constant integer BUFF_ABILITY_ID = 'A0FX'
private constant integer BUFF_ID = 'B02W'
private constant real DURATION_BASE = 3.0
private constant real DURATION_UP = 1.0
private constant real DAMAGE_SHARING_BASE = 0.25
private constant real DAMAGE_SHARING_UP = 0.0
private constant real AREA_BASE = 500.0
private constant real AREA_UP = 100.0
group array SIC_Groups[10]
private integer DD_ID
private unit currentEffectTarget
private integer array buffSource[10]
endglobals
function Trig_Sharing_Is_Caring_Damage takes real finalDamage returns nothing
local unit temp
local integer lvl = GetUnitAbilityLevel(DamageDetection_DamageTarget, BUFF_ABILITY_ID)
local integer sourceId
local real damage = (DAMAGE_SHARING_BASE + (lvl * DAMAGE_SHARING_UP)) * finalDamage
local group G
if (lvl > 0) then
set sourceId = buffSource[GetPlayerNr(GetOwningPlayer(DamageDetection_DamageTarget))]
set G = NewGroup()
call GroupAddGroup(SIC_Groups[sourceId], G)
loop
set temp = FirstOfGroup(G)
exitwhen (temp == null)
if (temp != DamageDetection_DamageTarget) then
call DebugMsg("Damage " + GetName(temp) + " for: " + I2S(R2I(damage)))
if (damage > GetUnitState(temp, UNIT_STATE_LIFE)) then
call DDS_UnitDamageTarget(DamageDetection_DamageSource, temp, damage)
else
call SetUnitState(temp, UNIT_STATE_LIFE, RMaxBJ(GetUnitState(temp, UNIT_STATE_LIFE) - damage, 1.0))
endif
endif
call GroupRemoveUnit(G, temp)
endloop
call ReleaseGroup(G)
set G = null
endif
endfunction
function Trig_Sharing_Is_Caring_Effect takes nothing returns nothing
local integer lvl = GetUnitAbilityLevel(GetEnumUnit(), BUFF_ABILITY_ID)
local real duration = DURATION_BASE + (lvl * DURATION_UP)
call Lightning.CreateUU("SPLK", currentEffectTarget, GetEnumUnit(), true, false, duration)
endfunction
function Trig_Sharing_Is_Caring_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit temp
local integer casterId = GetPlayerNr(GetOwningPlayer(Caster))
local integer lvl = GetUnitAbilityLevel(Caster, ABILITY_ID)
local real duration = DURATION_BASE + (lvl * DURATION_UP)
local real area = AREA_BASE + (lvl * AREA_UP)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local group G = NewGroup()
local group effectG
set udg_Filter_Player = GetOwningPlayer(Caster)
// deal 0 damage, to trigger the assist detection
call AreaSpellDamageFromUnit(Caster, TargetX, TargetY, area, 0, 1.0, 0, FILTER_ENEMY_TANK )
call GroupEnumUnitsInRange(G, TargetX, TargetY, area, FILTER_ENEMY_TANK)
set SIC_Groups[casterId] = NewGroup()
if (FirstOfGroup(G) != null) then
call GroupAddGroup(G, SIC_Groups[casterId])
set effectG = NewGroup()
loop
set temp = FirstOfGroup(G)
exitwhen (temp == null)
set buffSource[GetPlayerNr(GetOwningPlayer(temp))] = casterId
call AddAbilityTimed(temp, BUFF_ABILITY_ID, lvl, duration)
if (FirstOfGroup(effectG) != null) then
set currentEffectTarget = temp
call ForGroup(effectG, function Trig_Sharing_Is_Caring_Effect)
else
call Lightning.CreateUU("SPLK", Caster, temp, true, false, 1.0)
endif
call GroupAddUnit(effectG, temp)
call GroupRemoveUnit(G, temp)
endloop
call ReleaseGroup(effectG)
set effectG = null
endif
call ReleaseGroup(G)
call EnableSkillDamageDetection(DD_ID)
call GameTimeWait(duration)
call DisableSkillDamageDetection(DD_ID)
call ReleaseGroup(SIC_Groups[casterId])
set SIC_Groups[casterId] = null
set G = null
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Sharing_Is_Caring = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodePost(PostDamageFunction.Trig_Sharing_Is_Caring_Damage)
call TriggerRegisterSpellEffectEvent( gg_trg_Sharing_Is_Caring, ABILITY_ID )
call TriggerAddAction( gg_trg_Sharing_Is_Caring, function Trig_Sharing_Is_Caring_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ArtilleryShot initializer Init
globals
private constant integer ABILITY_ID = 'A0B5' // <- dummy ability, that doesn't do anything
private constant integer REAL_ABILITY_ID = 'A02A'
endglobals
function Trig_Artillery_Shot_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer lvl = GetUnitAbilityLevel(Caster, ABILITY_ID)
local player owner = GetOwningPlayer(Caster)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
//The dummy cast has to make sure, that casting this ability won't be interrupted
//by giving the Demolisher another order right after the cast
call IssuePointOrder( CreateDummyWithAbilityCoord(owner, REAL_ABILITY_ID, lvl, GetUnitX(Caster), GetUnitY(Caster), 0), "clusterrockets", TargetX, TargetY )
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Artillery_Shot = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Artillery_Shot, ABILITY_ID )
call TriggerAddAction( gg_trg_Artillery_Shot, function Trig_Artillery_Shot_Actions )
endfunction
endscope
//TESH.scrollpos=131
//TESH.alwaysfold=0
scope BurningOil initializer Init
globals
private constant integer ABILITY_ID = 'A02F'
private constant integer BUFF_ABILITY_ID = 'A0FP'
private constant integer BUFF_ID = 'B00A'
private constant real DURATION_BASE = 15.0
private constant real DURATION_UP = 0.0
private constant real SPEED_BASE = 600.0
private constant real SPEED_UP = 0.0
private constant real DAMAGE_BASE = 90.0
private constant real DAMAGE_UP = 30.0
private constant real AREA_BASE = 300.0
private constant real AREA_UP = 0.0
private constant real MANA_LOSS_BASE = 1.5
private constant real MANA_LOSS_UP = 0.5
private constant real DAMAGE_INTERVAL = 0.50
endglobals
function Trig_Burning_Oil_DamageTargets takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local unit Attacker = udg_AV_Unit2[LoopTimerId]
local unit temp
local integer level = udg_AV_Int1[LoopTimerId]
local real TargetX = GetUnitX(Target)
local real TargetY = GetUnitY(Target)
local real Area = ( AREA_BASE + ( level * AREA_UP ) )
local real Damage = ( DAMAGE_BASE + ( level * DAMAGE_UP ) ) * DAMAGE_INTERVAL
local real ManaLoss = ( MANA_LOSS_BASE + ( level * MANA_LOSS_UP ) ) * DAMAGE_INTERVAL
local real Duration = ( DURATION_BASE + ( level * DURATION_UP ) )
local real Mana
local group G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(Attacker)
if (GetUnitState(Target, UNIT_STATE_LIFE) > 0) then
call GroupEnumUnitsInRange(G, TargetX, TargetY, Area, FILTER_ENEMY_UNITS)
endif
call GroupAddGroup(udg_AV_Group1[LoopTimerId], G)
call GroupAddGroup(G, udg_AV_Group1[LoopTimerId])
loop
set temp = FirstOfGroup(G)
exitwhen (temp == null)
if (GetUnitState(temp, UNIT_STATE_LIFE) > 0) then
if (GetUnitAbilityLevel(temp, BUFF_ABILITY_ID) == 0) then
call UnitAddAbility(temp, BUFF_ABILITY_ID)
endif
set Mana = GetUnitState(temp, UNIT_STATE_MANA)
if ManaLoss > Mana then
set ManaLoss = Mana
endif
call SetUnitState(temp, UNIT_STATE_MANA, (Mana - ManaLoss))
call UnitDamageTarget(Attacker, temp, Damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
else
call GroupRemoveUnit(udg_AV_Group1[LoopTimerId], temp)
call UnitRemoveAbility(temp, BUFF_ABILITY_ID)
call UnitRemoveAbility(temp, BUFF_ID)
endif
call GroupRemoveUnit(G, temp)
endloop
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
if (udg_AV_Int2[LoopTimerId]*DAMAGE_INTERVAL >= Duration) then
loop
set temp = FirstOfGroup(udg_AV_Group1[LoopTimerId])
exitwhen (temp == null)
call UnitRemoveAbility(temp, BUFF_ABILITY_ID)
call UnitRemoveAbility(temp, BUFF_ID)
call GroupRemoveUnit(udg_AV_Group1[LoopTimerId], temp)
endloop
call ReleaseGroup(udg_AV_Group1[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Target = null
set Attacker = null
call ReleaseGroup(G)
set G = null
endfunction
function Trig_Burning_Oil_Destructor takes ProjectileMover pm returns nothing
call DestroyEffect(udg_AV_Effect1[pm.TimerIndex])
call ReleaseDummy(pm.Projectile)
endfunction
function Trig_Burning_Oil_Loop takes ProjectileMover pm returns boolean
local unit temp
local integer level = udg_AV_Int2[pm.TimerIndex]
local real TargetX = GetUnitX(pm.Target)
local real TargetY = GetUnitY(pm.Target)
local real Area = ( AREA_BASE + ( level * AREA_UP ) )
local real Damage = ( DAMAGE_BASE + ( level * DAMAGE_UP ) ) * DAMAGE_INTERVAL
local real ManaLoss = ( MANA_LOSS_BASE + ( level * MANA_LOSS_UP ) ) * DAMAGE_INTERVAL
local group G
local timer t
local integer DamageTimerId
local boolean result = false
if ( GetUnitState(pm.Projectile , UNIT_STATE_LIFE) <= 0 ) or (pm.Target == null) then
set result = true
elseif (pm.DistanceToTarget <= pm.Speed) then
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(pm.Source)
call GroupEnumUnitsInRange(G, TargetX, TargetY, Area, FILTER_ENEMY_UNITS)
set t = NewTimer()
set DamageTimerId = NewTimerIndex(t)
set udg_AV_Unit1[DamageTimerId] = pm.Target
set udg_AV_Unit2[DamageTimerId] = pm.Source
set udg_AV_Int1[DamageTimerId] = level
set udg_AV_Int2[DamageTimerId] = 0
set udg_AV_Group1[DamageTimerId] = NewGroup()
call TimerStart(t , DAMAGE_INTERVAL , true , function Trig_Burning_Oil_DamageTargets)
call GroupAddGroup(G, udg_AV_Group1[DamageTimerId])
loop
set temp = FirstOfGroup(G)
exitwhen (temp == null)
call UnitAddAbility(temp, BUFF_ABILITY_ID)
if ManaLoss > GetUnitState(temp, UNIT_STATE_MANA) then
set ManaLoss = GetUnitState(temp, UNIT_STATE_MANA)
endif
call SetUnitState(temp, UNIT_STATE_MANA, (GetUnitState(temp, UNIT_STATE_MANA) - ManaLoss))
call UnitDamageTarget(pm.Source, temp, Damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(G, temp)
endloop
call ReleaseGroup(G)
set G = null
set result = true
else
// Check if the target teleported away
if (DistanceBetweenPoints(udg_AV_Loc1[pm.TimerIndex], GetUnitLoc(pm.Target)) > 550 * PROJECTILE_MOVE_INTERVAL) then
set result = true
else
call MoveLocation(udg_AV_Loc1[pm.TimerIndex], TargetX, TargetY)
endif
endif
return result
endfunction
function Trig_Burning_Oil_Actions takes nothing returns nothing
local timer t
local integer ShootTimerId
local unit Source = GetTriggerUnit()
local unit Target = GetSpellTargetUnit()
local unit Projectile
local ProjectileMover pm
local real face
local integer level = GetUnitAbilityLevel(Source, ABILITY_ID)
local real Speed = SPEED_BASE + ( level * SPEED_UP )
local effect fx
set face = bj_RADTODEG * Atan2(GetUnitY(Target) - GetUnitY(Source), GetUnitX(Target) - GetUnitX(Source))
set Projectile = XE_NewDummyUnit(GetOwningPlayer(Source) , GetUnitX(Source) , GetUnitY(Source) , face)
call SetUnitScale(Projectile, 1.5, 1.5, 1.5)
call SetUnitFlyHeight(Projectile, GetUnitFlyHeight(Source), 0)
set fx = AddSpecialEffectTarget("Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl" , Projectile , "origin")
set pm = ProjectileMover.Create(Source, Projectile, Target, 0, 0)
call pm.Initialize(Speed, 0.3, ProjLooperFunction.Trig_Burning_Oil_Loop, ProjDestructorFunction.Trig_Burning_Oil_Destructor)
set udg_AV_Int2[pm.TimerIndex] = level
set udg_AV_Loc1[pm.TimerIndex] = GetUnitLoc(Target)
set udg_AV_Effect1[pm.TimerIndex] = fx
set Target = null
set Projectile = null
set Source = null
set fx = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Burning_Oil = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Burning_Oil, ABILITY_ID )
call TriggerAddAction( gg_trg_Burning_Oil, function Trig_Burning_Oil_Actions )
endfunction
endscope
//TESH.scrollpos=21
//TESH.alwaysfold=0
scope StaticCharge initializer Init
globals
private constant integer ABILITY_ID = 'A0H7'
private constant integer BUFF_ABILITY_ID = 'A0CB'
private constant integer BUFF_ID = 'B02B'
private constant integer CD_INDICATOR_ID = 'A0BY'
private constant real DURATION_BASE = 10.0
private constant real DURATION_UP = 0.0
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 175.0
private constant real AREA_BASE = 0.0
private constant real AREA_UP = 125.0
private constant real COOLDOWN_BASE = 6.0 // Cooldown: 7 / 6 / 5 / 4 / 3
private constant real COOLDOWN_UP = 0.0 // Check consistency with the real ability
real array ChargeDamage[10]
private integer DD_ID
endglobals
function Trig_Static_Charge_Effect takes location center, real range returns nothing
local integer i = 1
local integer count = R2I(range / 25.0)
local real angle = 360 / count
loop
exitwhen i > count
call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl",GetLocationX(center) + range * Cos(i*angle * bj_DEGTORAD),GetLocationY(center) + range * Sin(i*angle * bj_DEGTORAD)))
set i = i + 1
endloop
endfunction
function Trig_Static_Charge_Cooldown takes real finalDamage returns nothing
local real targetHP = GetUnitState(DamageDetection_DamageTarget, UNIT_STATE_LIFE)
local integer targetId = GetPlayerNr(GetOwningPlayer(DamageDetection_DamageTarget))
local boolean visibility = false
local real PosX
local real PosY
local real PosZ
local texttag tag
if (GetUnitAbilityLevel(DamageDetection_DamageTarget, CD_INDICATOR_ID) > 1) then
set ChargeDamage[targetId] = ChargeDamage[targetId] + finalDamage
//Reset the Static Charge cooldown, when the casting unit takes enough damage
if ((targetHP * 0.15) < ChargeDamage[targetId]) then
call RefreshSkill(DamageDetection_DamageTarget, ABILITY_ID)
set ChargeDamage[targetId] = 0
// the 'ShowTextTag' function isn't used, because of some custom changes to the behaviour
set tag = CreateTextTag( )
set PosX = GetUnitX(DamageDetection_DamageTarget)
set PosY = GetUnitY(DamageDetection_DamageTarget)
set PosZ = GetUnitFlyHeight(DamageDetection_DamageTarget)
if GetLocalPlayer() == GetOwningPlayer(DamageDetection_DamageTarget) then
set visibility = true
endif
call SetTextTagText(tag, "Reset", 0.016)
call SetTextTagPos(tag, PosX, PosY, PosZ)
call SetTextTagVisibility(tag, visibility)
call SetTextTagVelocity(tag, 0, 0)
call SetTextTagFadepoint(tag, 0.5 )
call SetTextTagLifespan(tag, 1 )
call SetTextTagPermanent(tag, false )
set tag = null
// For an explanation of this, look below this trigger
if (GetUnitAbilityLevel(DamageDetection_DamageTarget, CD_INDICATOR_ID) > 1) then
call SetUnitAbilityLevel(DamageDetection_DamageTarget, CD_INDICATOR_ID, GetUnitAbilityLevel(DamageDetection_DamageTarget, CD_INDICATOR_ID) - 1)
else
call UnitRemoveAbility(DamageDetection_DamageTarget, CD_INDICATOR_ID)
endif
call DebugMsg("Cooldown Refresh")
endif
endif
endfunction
function Trig_Static_Charge_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local integer lvl = GetUnitAbilityLevel(caster, ABILITY_ID)
local real damage = DAMAGE_BASE + (lvl * DAMAGE_UP)
local real range = AREA_BASE + (lvl * AREA_UP)
local real duration = DURATION_BASE + (lvl * DURATION_UP)
local real cooldown = COOLDOWN_BASE + (lvl * COOLDOWN_UP)
if (GetUnitAbilityLevel(target, BUFF_ID) > 0) then
set udg_Filter_Player = GetOwningPlayer(caster)
call FixedAreaDamageFromUnit(caster, GetUnitX(target), GetUnitY(target), range, damage, 0.5, 0, false, FILTER_ENEMY_UNITS)
call Trig_Static_Charge_Effect(GetUnitLoc(target), range)
call UnitRemoveAbility(target, BUFF_ID)
else
// this ability only adds the static charge buff; this buff could be placed by the ability that triggered this trigger here, but it would be a bit problematic
// when it's the second charge (in which case it only triggers the first one, but doesn't place a buff itself), because the base skill would add the buff regardless
// if the target already had one or not and you also can't just remove it, because you have to wait about half a second until the new buff appears
// so it's easier to just add the buff yourself with another skill, when you actually want it
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(caster), BUFF_ABILITY_ID, 1, GetUnitX(target), GetUnitY(target), 0), "shadowstrike", target)
endif
// As long as the tank has this dummy ability, the trigger knows, that the skill is still in cooldown
// A feature of this ability is the reset of the Static Charge Cooldown, when you take damage
// but the reset should only happen, when the ability is actually in cooldown (if not, you may interupt the targeting with the ability)
// For an explanation of this, look below this trigger
if (GetUnitAbilityLevel(caster, CD_INDICATOR_ID) > 0) then
call SetUnitAbilityLevel(caster, CD_INDICATOR_ID, 3)
else
call UnitAddAbility(caster, CD_INDICATOR_ID)
call SetUnitAbilityLevel(caster, CD_INDICATOR_ID, 2)
endif
// This damage detection here is only used for the cooldown related stuff
call EnableSkillDamageDetection(DD_ID)
call GameTimeWait(cooldown)
call DisableSkillDamageDetection(DD_ID)
// For an explanation of this, look below this trigger
if (GetUnitAbilityLevel(caster, CD_INDICATOR_ID) <= 2) then
call UnitRemoveAbility(caster, CD_INDICATOR_ID)
else
call SetUnitAbilityLevel(caster, CD_INDICATOR_ID, GetUnitAbilityLevel(caster, CD_INDICATOR_ID) - 1)
endif
set caster = null
set target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Static_Charge = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodePost(PostDamageFunction.Trig_Static_Charge_Cooldown)
call TriggerRegisterSpellEffectEvent( gg_trg_Static_Charge, ABILITY_ID )
call TriggerAddAction( gg_trg_Static_Charge, function Trig_Static_Charge_Actions )
endfunction
endscope
// This is the problem of the cooldown indicator:
// It is used as a condition for the damage detection trigger: only register the damage, as long as the Static Charge skill is in cooldown
// So this skill is added to the tank, so the trigger can check for it
// There are two ways, how this indicator can be removed: either after the normal cooldown is up, or when the tank took enough damage for the reset
// But the thing is, the trigger _always_ tries to remove the indicator after the cooldown, regardless if this already happened because of the damage
// Why is this a problem? Well, because when the cooldown from cast A has been reset, the player can use the skill again.
// When he does (cast B), before the normal cooldown duration from cast A is up, then the indicator will be added for cast B
// as always and then the trigger from cast A will remove the indicator after the cooldown duration
// Since the indicator is gone, the damage trigger won't check anymore and no reset for cast B will happen
// So, here is how it is done, to solve this problem: the indicator skill has 3 levels
// The indicator is added with level 2. When the static charge skill is reset because of the damage, the indicator level is set to 1
// Whenever the indicator level is 1 or 2 after the cooldown duration, it gets removed
// But whenever the indicator level is 1 when the skill is cast again (thats in the time between the damage reset and the cooldown remove),
// the level will be set to 3, instead of 2.
// Now, when the cooldown is up and the level is 3, it is clear, that two casts are overlapping and the indicator won't be removed, but rather only get its level reduced
// With this, the problem explained above should be avoided.
// Pretty simple, isn't it?
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ShapeMemoryAlloy initializer Init
globals
private constant integer ABILITY_ID = 'A0FA'
private constant integer BUFF_ID = 'B02C'
private constant real DURATION_BASE = 4.0
private constant real DURATION_UP = 0.0
private constant real HEAL_FACTOR_BASE = 1.0
private constant real HEAL_FACTOR_UP = 0.0
private constant real HEAL_LIMIT_BASE = 0.0 // the percentage is based on the tanks max HP
private constant real HEAL_LIMIT_UP = 0.12
private constant real HEAL_DURATION_BASE = 1.5
private constant real HEAL_DURATION_UP = 0.0
real array smaDamage[10]
private integer DD_ID
endglobals
function Trig_Shape_Memory_Alloy_Damage takes real finalDamage returns nothing
local integer targetId = GetPlayerNr(GetOwningPlayer(DamageDetection_DamageTarget))
if (GetUnitAbilityLevel(DamageDetection_DamageTarget, BUFF_ID) > 0) then
//call DebugMsg("SMA dmg")
set smaDamage[targetId] = smaDamage[targetId] + finalDamage
endif
endfunction
function Trig_Shape_Memory_Alloy_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local integer pId = GetPlayerNr(GetOwningPlayer(U))
local real duration = DURATION_BASE + (lvl * DURATION_UP)
local real healDuration = HEAL_DURATION_BASE + (lvl * HEAL_DURATION_UP)
local real healFactor = HEAL_FACTOR_BASE + (lvl * HEAL_FACTOR_UP)
local real healLimit = HEAL_LIMIT_BASE + (lvl * HEAL_LIMIT_UP)
local real healAmount
set smaDamage[pId] = 0
//call PermanentTimedLife(U, duration, GetOwningPlayer(U), "|cff00ff00", "|r", -150)
call EnableSkillDamageDetection(DD_ID)
call GameTimeWait(duration)
call DisableSkillDamageDetection(DD_ID)
set healAmount = RMinBJ(smaDamage[pId] * healFactor, healLimit * GetUnitState(U, UNIT_STATE_MAX_LIFE))
if (GetUnitState(U, UNIT_STATE_LIFE) > 0) then
//call SetUnitState(U, UNIT_STATE_LIFE, GetUnitState(U, UNIT_STATE_LIFE) + (healAmount))
call HealOverTime(U, healAmount, 0, healDuration, 0, false)
call ShowTextTag("|cff00ff00+"+I2S(R2I((healAmount)))+"|r", U, 0, 50, null)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\AIhe\\AIheTarget.mdl", U, "overhead"))
else
call ShowTextTag("|cffff0000Too late!|r", U, 0, 50, null)
endif
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Shape_Memory_Alloy = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodePost(PostDamageFunction.Trig_Shape_Memory_Alloy_Damage)
call TriggerRegisterSpellEffectEvent( gg_trg_Shape_Memory_Alloy, ABILITY_ID )
call TriggerAddAction( gg_trg_Shape_Memory_Alloy, function Trig_Shape_Memory_Alloy_Actions )
endfunction
endscope
//TESH.scrollpos=4
//TESH.alwaysfold=0
scope Ricochet initializer Init
globals
private constant integer ABILITY_ID = 'A0BN'
private constant real DURATION_BASE = 5.0
private constant real DURATION_UP = 0.0
private constant real FIXED_DAMAGE_BASE = 0.0
private constant real FIXED_DAMAGE_UP = 15.0
private constant real DAMAGE_RETURN_FACTOR_BASE = 0.0
private constant real DAMAGE_RETURN_FACTOR_UP = 0.0
private constant real INTERVAL = 0.05
constant integer RICOCHET_RESISTANCE_ID = 'A0H0'
private integer DD_ID
endglobals
function Trig_Ricochet_Damage takes real finalDamage returns nothing
local integer lvl = GetUnitAbilityLevel(DamageDetection_DamageTarget, RICOCHET_RESISTANCE_ID)
local real damageReturn = FIXED_DAMAGE_BASE + (lvl * FIXED_DAMAGE_UP) + ((DAMAGE_RETURN_FACTOR_BASE + (lvl * DAMAGE_RETURN_FACTOR_UP)) * finalDamage )
if (GetUnitAbilityLevel(DamageDetection_DamageTarget, RICOCHET_RESISTANCE_ID) > 0) then
//call DebugMsg("Ricochet dmg")
if IsUnitEnemy(DamageDetection_DamageSource, GetOwningPlayer(DamageDetection_DamageTarget)) then
call DDS_UnitDamageTarget(DamageDetection_DamageTarget, DamageDetection_DamageSource, damageReturn)
endif
endif
endfunction
// Everything this loop does, is to move the dummy with the thorns aura effect along with the Raider
// A dummy has been used to make the effect bigger as it would have been, when it would have been added to the Raider itself
function Trig_Ricochet_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Caster = udg_AV_Unit1[LoopTimerId]
local unit Dummy = udg_AV_Unit2[LoopTimerId]
if (GetUnitState(Caster, UNIT_STATE_LIFE) > 0) and (GetUnitAbilityLevel(Caster, RICOCHET_RESISTANCE_ID) > 0) then
call SetUnitX(Dummy, GetUnitX(Caster))
call SetUnitY(Dummy, GetUnitY(Caster))
call SetUnitFlyHeight(Dummy, GetUnitFlyHeight(Caster), 1000)
else
call RemoveUnit(Dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Caster = null
set Dummy = null
endfunction
function Trig_Ricochet_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local integer pId = GetPlayerNr(GetOwningPlayer(U))
local real duration = DURATION_BASE + (lvl * DURATION_UP)
local timer t
local unit dummy = CreateUnit(GetOwningPlayer(U) , DUMMY_ID , GetUnitX(U) , GetUnitY(U) , 270)
local integer TimerIndex
call SetUnitFlyHeight(dummy, GetUnitFlyHeight(U), 0)
call AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\ThornsAura\\ThornsAura.mdl", dummy, "origin")
call SetUnitScale(dummy, 2.5, 2.5, 2.5)
call SetUnitAnimation( U, "Attack Two Spell" )
call UnitAddAbility(U, RICOCHET_RESISTANCE_ID)
call SetUnitAbilityLevel(U, RICOCHET_RESISTANCE_ID, lvl)
//call SetPlayerAbilityAvailable(GetOwningPlayer(U), RICOCHET_RESISTANCE_ID, false)
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = U
set udg_AV_Unit2[TimerIndex] = dummy
call TimerStart(t, INTERVAL, true, function Trig_Ricochet_Loop)
call EnableSkillDamageDetection(DD_ID)
call GameTimeWait(duration)
call DisableSkillDamageDetection(DD_ID)
call UnitRemoveAbility(U, RICOCHET_RESISTANCE_ID)
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Ricochet = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodePost(PostDamageFunction.Trig_Ricochet_Damage)
call TriggerRegisterSpellEffectEvent( gg_trg_Ricochet, ABILITY_ID )
call TriggerAddAction( gg_trg_Ricochet, function Trig_Ricochet_Actions )
endfunction
endscope
//TESH.scrollpos=60
//TESH.alwaysfold=0
scope HitnRun initializer Init
globals
private constant integer ABILITY_ID = 'A06S'
private constant integer CANCEL_ABILITY_ID = 'A0AY'
private constant integer BUFF_ID = 'B02D'
private constant real DURATION_BASE = 6.0
private constant real DURATION_UP = 0.0
private constant real MAX_DAMAGE_BASE = 900.0
private constant real MAX_DAMAGE_UP = 300.0
private constant real AREA_BASE = 750.0
private constant real AREA_UP = 0.0
// Teleport range is a parameter of the used based skill
constant integer HITNRUN_BUFF_ABILITY_ID = 'A0FE'
unit array HitnRunCaster[10]
real array hitnRunDamage[10]
location array HitnRunCastLocation[10]
effect array HitnRunCastEffect[10]
private integer DD_ID
endglobals
function Trig_HitnRun_Damage takes real finalDamage returns nothing
local integer targetId = GetPlayerNr(GetOwningPlayer(DamageDetection_DamageTarget))
local integer lvl
local real maxDmg
if (GetUnitAbilityLevel(DamageDetection_DamageTarget, HITNRUN_BUFF_ABILITY_ID) > 0) then
set lvl = GetUnitAbilityLevel(DamageDetection_DamageTarget, ABILITY_ID)
set maxDmg = MAX_DAMAGE_BASE + (lvl * MAX_DAMAGE_UP)
set hitnRunDamage[targetId] = RMinBJ(maxDmg, hitnRunDamage[targetId] + finalDamage)
endif
endfunction
function Trig_HitnRun_FinalEffect takes integer pId, boolean dealDamage returns nothing
local integer lvl = GetUnitAbilityLevel(HitnRunCaster[pId], ABILITY_ID)
local real maxDmg = MAX_DAMAGE_BASE + (lvl * MAX_DAMAGE_UP)
local real area = AREA_BASE + (lvl * AREA_UP)
local real finalDamage
local integer targetCount
local group G
if (GetUnitState(HitnRunCaster[pId], UNIT_STATE_LIFE) > 0) and (HitnRunCastLocation[pId] != null) then
if (dealDamage) then
if (hitnRunDamage[pId] > 0) then
set udg_Filter_Player = GetOwningPlayer(HitnRunCaster[pId])
call AreaSpellDamageFromUnit(HitnRunCaster[pId], GetUnitX(HitnRunCaster[pId]), GetUnitY(HitnRunCaster[pId]), area, hitnRunDamage[pId], 0.5, 0, FILTER_ENEMY_UNITS )
call ShowEffectAtPos("war3mapImported\\NewAirEX.mdx",GetUnitX(HitnRunCaster[pId]), GetUnitY(HitnRunCaster[pId]), GetUnitFlyHeight(HitnRunCaster[pId]), 5, 5)
endif
endif
// This emulates a behavior of a normal teleport: projectile dodging
call UnitAddAbility(HitnRunCaster[pId], 'Apiv')
call UnitRemoveAbility(HitnRunCaster[pId], 'Apiv')
call SetUnitPositionLoc(HitnRunCaster[pId], HitnRunCastLocation[pId])
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(HitnRunCaster[pId]), GetUnitY(HitnRunCaster[pId])))
call RemoveLocation(HitnRunCastLocation[pId])
set HitnRunCastLocation[pId] = null
endif
if (HitnRunCastEffect[pId] != null) then
call DestroyEffect(HitnRunCastEffect[pId])
set HitnRunCastEffect[pId] = null
endif
call SetPlayerAbilityAvailable(GetOwningPlayer(udg_Tank[pId]), ABILITY_ID, true)
call UnitRemoveAbility(HitnRunCaster[pId], CANCEL_ABILITY_ID)
call UnitRemoveAbility(HitnRunCaster[pId], HITNRUN_BUFF_ABILITY_ID)
call UnitRemoveAbility(HitnRunCaster[pId], BUFF_ID)
endfunction
function Trig_HitnRun_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local integer pId = GetPlayerNr(GetOwningPlayer(U))
local real duration = DURATION_BASE + (lvl * DURATION_UP)
if ( GetSpellAbilityId() == CANCEL_ABILITY_ID ) then
call Trig_HitnRun_FinalEffect(pId, false)
elseif ( GetSpellAbilityId() == ABILITY_ID ) then
call SetPlayerAbilityAvailable(GetOwningPlayer(U), ABILITY_ID, false)
call UnitAddAbility(U, CANCEL_ABILITY_ID)
set HitnRunCaster[pId] = U
set hitnRunDamage[pId] = 0
set HitnRunCastLocation[pId] = GetUnitLoc(U)
set HitnRunCastEffect[pId] = AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTo.mdl", GetUnitX(U), GetUnitY(U))
call UnitAddAbility(U, HITNRUN_BUFF_ABILITY_ID)
call PermanentTimedLife(U, duration, GetOwningPlayer(U), "|cffff0000", "|r", 150, function PermanentTimedLife_HitnRun)
// The wait is needed, so this ability actually finishes casting, before the stun of the Teleport Breaker is applied
call GameTimeWait(0)
call CheckHyperSpaceBreaker(U)
call EnableSkillDamageDetection(DD_ID)
call GameTimeWait(duration)
call DisableSkillDamageDetection(DD_ID)
call Trig_HitnRun_FinalEffect(pId, true)
endif
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_HitnRun = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodePost(PostDamageFunction.Trig_HitnRun_Damage)
call TriggerRegisterSpellEffectEvent( gg_trg_HitnRun, ABILITY_ID )
call TriggerRegisterSpellEffectEvent( gg_trg_HitnRun, CANCEL_ABILITY_ID )
call TriggerAddAction( gg_trg_HitnRun, function Trig_HitnRun_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Trader_Init_CreateFloating takes unit U, integer number returns nothing
local location P = Location(GetUnitX(U) - 50, GetUnitY(U) - 50)
call CreateTextTagLocBJ( "|cff00cc00|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||r", P, 0, 5.00, 100, 100, 100, 0 )
call SetTextTagVisibility(bj_lastCreatedTextTag, false)
set udg_Progress_Bar[number] = bj_lastCreatedTextTag
call RemoveLocation( P )
set P = null
endfunction
function Trig_Trader_Init_Actions takes nothing returns nothing
call Trig_Trader_Init_CreateFloating( gg_unit_n00C_0086, 1 )
call Trig_Trader_Init_CreateFloating( gg_unit_n00B_0075, 2 )
call Trig_Trader_Init_CreateFloating( gg_unit_n00M_0106, 3 )
call Trig_Trader_Init_CreateFloating( gg_unit_n00O_0056, 4 )
call Trig_Trader_Init_CreateFloating( gg_unit_n00A_0027, 5 )
call Trig_Trader_Init_CreateFloating( gg_unit_n00Q_0057, 6 )
call Trig_Trader_Init_CreateFloating( gg_unit_n00F_0103, 7 )
call Trig_Trader_Init_CreateFloating( gg_unit_n00N_0053, 8 )
call Trig_Trader_Init_CreateFloating( gg_unit_n00P_0055, 9 )
call Trig_Trader_Init_CreateFloating( gg_unit_n00G_0048, 10 )
call TriggerRegisterTimerEvent( gg_trg_Trader_Floating, 1.00, true )
call DestroyTrigger( GetTriggeringTrigger() )
endfunction
//===========================================================================
function InitTrig_Trader_Init takes nothing returns nothing
set gg_trg_Trader_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Trader_Init, function Trig_Trader_Init_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Trader_Floating_ShowFloating takes unit U, integer number returns nothing
local integer chars = R2I( GetUnitManaPercent(U) * 0.8 ) * 2
local string basic = "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
if chars == 160 then
call SetTextTagTextBJ( udg_Progress_Bar[number], ("|cff00cc00" + basic + "|r"), 5.00 )
else
call SetTextTagTextBJ( udg_Progress_Bar[number], ("|cffcc0000" + SubStringBJ(basic, 1, chars) + "|r|cff000000" + SubStringBJ(basic, 1, (160 - chars)) + "|r"), 5.00 )
endif
set basic = null
endfunction
function Trig_Trader_Floating_Actions takes nothing returns nothing
call Trig_Trader_Floating_ShowFloating( gg_unit_n00C_0086, 1 )
call Trig_Trader_Floating_ShowFloating( gg_unit_n00B_0075, 2 )
call Trig_Trader_Floating_ShowFloating( gg_unit_n00M_0106, 3 )
call Trig_Trader_Floating_ShowFloating( gg_unit_n00O_0056, 4 )
call Trig_Trader_Floating_ShowFloating( gg_unit_n00A_0027, 5 )
call Trig_Trader_Floating_ShowFloating( gg_unit_n00Q_0057, 6 )
call Trig_Trader_Floating_ShowFloating( gg_unit_n00F_0103, 7 )
call Trig_Trader_Floating_ShowFloating( gg_unit_n00N_0053, 8 )
call Trig_Trader_Floating_ShowFloating( gg_unit_n00P_0055, 9 )
call Trig_Trader_Floating_ShowFloating( gg_unit_n00G_0048, 10 )
endfunction
//===========================================================================
function InitTrig_Trader_Floating takes nothing returns nothing
set gg_trg_Trader_Floating = CreateTrigger( )
call TriggerAddAction( gg_trg_Trader_Floating, function Trig_Trader_Floating_Actions )
endfunction
//TESH.scrollpos=1
//TESH.alwaysfold=0
scope Trading initializer Init
private function Conditions takes nothing returns boolean
local integer Id = GetUnitTypeId(GetSoldUnit())
if Id == 'z011' or Id == 'z013' or Id == 'z014' or Id == 'z00I' or Id == 'z00J' then
return true
elseif Id == 'z010' or Id == 'z012' or Id == 'z015' or Id == 'z016' or Id == 'z017' then
return true
elseif Id == 'z018' or Id == 'z00W' or Id == 'z00E' or Id == 'z00F' or Id == 'z00X' then
return true
endif
return Id == 'z01M' or Id == 'z01Q'
endfunction
private function SellAll takes nothing returns nothing
local unit U = GetBuyingUnit()
local integer i = 1
local integer RewardGold = 0
local integer RewardWood = 0
local integer RewardXP = 0
local integer RewardID
local integer ItemCharges
local item TempItem
loop
exitwhen i > 6
set TempItem = UnitItemInSlotBJ(U, i)
if GetItemType(TempItem) == ITEM_TYPE_CHARGED then
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))] == 1 then
set RewardID = R2I(GetItemLifeBJ(TempItem))
else
set RewardID = 11 - R2I(GetItemLifeBJ(TempItem))
endif
set ItemCharges = GetItemCharges(TempItem)
set RewardGold = RewardGold + ItemCharges * udg_Trader_Gold[RewardID]
set RewardWood = RewardWood + ItemCharges * ( 10 + udg_Trader_Wood[RewardID] )
call RemoveItem(TempItem)
endif
set i = i + 1
endloop
if RewardGold != 0 then
if CountPlayersInForceBJ(udg_Players_Team[udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]]) == 1 then
call AdjustPlayerStateBJ( RewardGold, GetOwningPlayer(U), PLAYER_STATE_RESOURCE_GOLD )
call ShowTextTag("|cfffe960a+"+I2S(RewardGold)+"|r", U, 0, 0, GetOwningPlayer(U))
else
call AdjustPlayerStateBJ( ( RewardGold / 2 ), GetOwningPlayer(U), PLAYER_STATE_RESOURCE_GOLD )
call ShowTextTag("|cfffe960a+"+I2S(RewardGold/2)+"|r", U, 0, 0, GetOwningPlayer(U))
set i = ( ( udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))] * 5 ) - 4 )
loop
exitwhen i > udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))] * 5
if IsPlayerInForce(GetPlayer(i), udg_Players) and GetPlayer(i) != GetOwningPlayer(U) then
call AdjustPlayerStateBJ( ( RewardGold / 2 / ( CountPlayersInForceBJ(udg_Players_Team[udg_Player_Team[i]]) - 1 ) ), GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD )
call ShowTextTag("|cfffe960a+"+I2S(RewardGold / 2 / ( CountPlayersInForceBJ(udg_Players_Team[udg_Player_Team[i]]) - 1 ))+"|r", udg_Tank[i], 0, 0, GetPlayer(i))
endif
set i = i + 1
endloop
endif
call AdjustPlayerStateBJ( RewardWood, GetOwningPlayer(U), PLAYER_STATE_RESOURCE_LUMBER )
set RewardXP = R2I(RewardGold*0.75/udg_GoldFactor)
call AddHeroXP(U,RewardXP, true )
if GetOwningPlayer(U)==GetLocalPlayer() then
call DisplayTimedTextToPlayer( GetLocalPlayer(),0,0, 3.00, ( "Sold items: |cffffcc00" + I2S(RewardGold) + "|r Gold, |cff009900" + I2S(RewardWood) + "|r Wood, |c007d3eb7" + I2S(RewardXP) + "|r XP" ) )
endif
call DestroyEffect(AddSpecialEffectTarget("UI\\Feedback\\GoldCredit\\GoldCredit.mdl",U,"origin"))
set udg_Stats_Trader[GetPlayerNr(GetOwningPlayer(U))] = udg_Stats_Trader[GetPlayerNr(GetOwningPlayer(U))] + RewardGold
endif
call SelectUnitForPlayerSingle( U, GetOwningPlayer(U) )
set TempItem = null
set U = null
endfunction
private function SellCombo takes nothing returns nothing
local unit U = GetBuyingUnit()
local integer array ID
local integer array IDAmount
local integer i = GetUnitTypeId(GetSoldUnit())
local integer RewardItemID = 0
local integer RewardWood = 0
local item TempItem
if i == 'z017' then
set ID[1] = 'I02N' // Fossil
set IDAmount[1] = 2 // +
set ID[2] = 'I01L' // Cheese
set IDAmount[2] = 1 // +
set ID[3] = 'I021' // Oil
set IDAmount[3] = 2 // =
set RewardItemID = 'I00Y' // Troop Command (Team 1)
elseif i == 'z018' then // ----------------
set ID[1] = 'I02B' // Skeleton
set IDAmount[1] = 2 // +
set ID[2] = 'I023' // Water
set IDAmount[2] = 1 // +
set ID[3] = 'I02M' // Salt
set IDAmount[3] = 2 // =
set RewardItemID = 'I00Y' // Troop Command (Team 2)
elseif i == 'z013' then // ----------------
set ID[1] = 'I02M' // Salt
set IDAmount[1] = 3 // +
set ID[2] = 'I023' // Water
set IDAmount[2] = 2 // +
set ID[3] = 'I02S' // Metal
set IDAmount[3] = 3 // =
set RewardItemID = 'I014' // Teleporter (Team 1)
elseif i == 'z014' then // ----------------
set ID[1] = 'I021' // Oil
set IDAmount[1] = 3 // +
set ID[2] = 'I01L' // Cheese
set IDAmount[2] = 2 // +
set ID[3] = 'I020' // Gold
set IDAmount[3] = 3 // =
set RewardItemID = 'I014' // Teleporter (Team 2)
elseif i == 'z00I' then // ----------------
set ID[1] = 'I02N' // Fossil
set IDAmount[1] = 1 // +
set ID[2] = 'I01L' // Cheese
set IDAmount[2] = 2 // +
set ID[3] = 'I02M' // Salt
set IDAmount[3] = 2 // =
set RewardItemID = 'I00Z' // Factory (Team 1)
elseif i == 'z00J' then // ----------------
set ID[1] = 'I02B' // Skeleton
set IDAmount[1] = 1 // +
set ID[2] = 'I023' // Water
set IDAmount[2] = 2 // +
set ID[3] = 'I021' // Oil
set IDAmount[3] = 2 // =
set RewardItemID = 'I00Z' // Factory (Team 2)
elseif i == 'z010' then // ----------------
set ID[1] = 'I023' // Water
set IDAmount[1] = 2 // +
set ID[2] = 'I022' // Wood
set IDAmount[2] = 1 // +
set ID[3] = 'I020' // Gold
set IDAmount[3] = 2 // =
set RewardItemID = 'I00S' // Repair-Robots (Team 1)
elseif i == 'z012' then // ----------------
set ID[1] = 'I01L' // Cheese
set IDAmount[1] = 2 // +
set ID[2] = 'I029' // Analysis-Results
set IDAmount[2] = 1 // +
set ID[3] = 'I02S' // Metal
set IDAmount[3] = 2 // =
set RewardItemID = 'I00S' // Repair-Robots (Team 2)
elseif i == 'z015' then // ----------------
set ID[1] = 'I02M' // Salt
set IDAmount[1] = 3 // +
set ID[2] = 'I023' // Water
set IDAmount[2] = 3 // +
set ID[3] = 'I01L' // Cheese
set IDAmount[3] = 2 // =
set RewardItemID = 'I00L' // Trader-Hunter-Pack (Team 1)
elseif i == 'z016' then // ----------------
set ID[1] = 'I021' // Oil
set IDAmount[1] = 3 // +
set ID[2] = 'I01L' // Cheese
set IDAmount[2] = 3 // +
set ID[3] = 'I023' // Water
set IDAmount[3] = 2 // =
set RewardItemID = 'I00L' // Trader-Hunter-Pack (Team 2)
elseif i == 'z00W' then // ----------------
set ID[1] = 'I02N' // Fossil
set IDAmount[1] = 2 // +
set ID[2] = 'I022' // Wood
set IDAmount[2] = 3 // +
set ID[3] = 'I023' // Water
set IDAmount[3] = 4 // =
set RewardItemID = 'I012' // Speed-Pack (Team 1)
elseif i == 'z00X' then // ----------------
set ID[1] = 'I02B' // Skeleton
set IDAmount[1] = 2 // +
set ID[2] = 'I029' // Analysis-Results
set IDAmount[2] = 3 // +
set ID[3] = 'I01L' // Cheese
set IDAmount[3] = 4 // =
set RewardItemID = 'I012' // Speed-Pack (Team 2)
elseif i == 'z00E' then // ----------------
set ID[1] = 'I02N' // Fossil
set IDAmount[1] = 1 // +
set ID[2] = 'I022' // Wood
set IDAmount[2] = 2 // +
set ID[3] = 'I02M' // Salt
set IDAmount[3] = 3 // =
set RewardItemID = 'I04V' // Bomb (Team 1)
elseif i == 'z00F' then // ----------------
set ID[1] = 'I02B' // Skeleton
set IDAmount[1] = 1 // +
set ID[2] = 'I029' // Analysis-Results
set IDAmount[2] = 2 // +
set ID[3] = 'I021' // Oil
set IDAmount[3] = 3 // =
set RewardItemID = 'I04V' // Bomb (Team 2)
elseif i == 'z01M' then // ----------------
set ID[1] = 'I02B' // Skeleton
set IDAmount[1] = 2 // +
set ID[2] = 'I022' // Wood
set IDAmount[2] = 2 // +
set ID[3] = 'I029' // Analysis-Results
set IDAmount[3] = 3 // =
set RewardItemID = 'I04Y' // Troop Command Center (Team 1)
elseif i == 'z01Q' then // ----------------
set ID[1] = 'I02N' // Fossil
set IDAmount[1] = 2 // +
set ID[2] = 'I029' // Analysis-Results
set IDAmount[2] = 2 // +
set ID[3] = 'I022' // Wood
set IDAmount[3] = 3 // =
set RewardItemID = 'I04Y' // Troop Command Center (Team 2)
endif
set i = 1
loop
exitwhen ID[i] == null
if GetItemCharges(GetItemOfTypeFromUnitBJ(U, ID[i])) < IDAmount[i] then
if GetLocalPlayer() == GetOwningPlayer(U) then
call DisplayTimedTextToPlayer( GetLocalPlayer(),0,0, 3.00, ( "|cfffed312Necessary items were not available.|r" ) )
endif
set i = 0
set TempItem = null
set U = null
return
endif
set i = i + 1
endloop
// Remove used items
set i = 1
loop
exitwhen ID[i] == null
set TempItem = GetItemOfTypeFromUnitBJ(U, ID[i])
if GetItemCharges(TempItem) == IDAmount[i] then
call RemoveItem( TempItem )
else
call SetItemCharges( TempItem, ( GetItemCharges(TempItem) - IDAmount[i] ) )
endif
set RewardWood = RewardWood + 10 * IDAmount[i]
set i = i + 1
endloop
call AdjustPlayerStateBJ( RewardWood, GetOwningPlayer(U), PLAYER_STATE_RESOURCE_LUMBER )
if RewardItemID != 0 then
call UnitAddItemById(U, RewardItemID)
set udg_Stats_Trader[GetPlayerNr(GetOwningPlayer(U))] = udg_Stats_Trader[GetPlayerNr(GetOwningPlayer(U))] + R2I(GetItemLifeBJ(GetLastCreatedItem()))
endif
set TempItem = null
set U = null
endfunction
private function Actions takes nothing returns nothing
local unit Buyer = GetBuyingUnit()
local unit Item = GetSoldUnit()
local player Owner = GetOwningPlayer(Buyer)
local integer Team = udg_Player_Team[GetPlayerNr(Owner)]
if GetOwningPlayer(Item) != Owner then
if GetLocalPlayer() == Owner then
call DisplayTimedTextToPlayer( GetLocalPlayer(),0,0, 3.00, ( "|cfffed312You cannot trade for your ally.|r" ) )
endif
return
endif
if GetUnitTypeId(Buyer) != 'H00Y' then
if GetLocalPlayer() == Owner then
call DisplayTimedTextToPlayer( GetLocalPlayer(),0,0, 3.00, ( "|cfffed312Requires a Trader.|r" ) )
endif
return
endif
//+++++++++++++++++++++++++++++++++
// Check correct Market
if not TradeMarketTeam(GetTriggerUnit(), Team) then
call DisplayTimedTextToPlayer( Owner,0,0, 3.00, ( "|cfffed312You cannot trade with your enemy.|r" ) )
return
endif
//+++++++++++++++++++++++++++++++++
if GetUnitTypeId(Item) == 'z011' then
call SellAll()
else
call SellCombo()
endif
call RemoveUnit(Item)
set Item = null
set Buyer = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SELL)
call TriggerAddCondition(t, Condition( function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=129
//TESH.alwaysfold=0
function Trig_Trader_Trade_Skill_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A010' or GetSpellAbilityId() == 'A08X'
endfunction
globals
boolexpr FILTER_TRADER_BUILDING
boolexpr FILTER_TRADE_MASTER
endglobals
function Trig_Trader_Trade_Skill_IsTraderBuilding takes nothing returns boolean
local integer Id = GetUnitTypeId(GetFilterUnit())
if Id == 'n00C' or Id == 'n00Q' or Id == 'n00B' or Id == 'n00M' or Id == 'n00F' then
return true
endif
return Id == 'n00N' or Id == 'n00A' or Id == 'n00G' or Id == 'n00P' or Id == 'n00O'
endfunction
function Trig_Trader_Trade_Skill_IsTradeMaster takes nothing returns boolean
local integer Id = GetUnitTypeId(GetFilterUnit())
return Id == 'h00M' or Id == 'h00J'
endfunction
function Trig_Trader_Trade_Skill_TradeMasterAllied takes unit U returns boolean
local integer Team = udg_Player_Team[GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))]
if not TradeMarketTeam(U, Team) then
call DisplayTimedTextToPlayer( GetOwningPlayer(GetTriggerUnit()),0,0, 3.00, ( "|cfffed312You cannot trade with your enemy.|r" ) )
return false
endif
return true
endfunction
function Trig_Trader_Trade_Skill_Actions takes nothing returns nothing
local group G
local unit Trader = GetTriggerUnit()
local unit U
local force F
local location P = GetUnitLoc(Trader)
local integer i = 1
local integer RewardID
local integer RewardGold = 0
local integer RewardWood = 0
local integer RewardXP = 0
local integer ItemID
local item TempItem
local string tagtext
local boolean ValidTrade = false
local real GameTime
local integer MonopolyLevel
set G = GetUnitsInRangeOfLocMatchingSafe(384.00, P, FILTER_TRADER_BUILDING)
if FirstOfGroup(G) != null then
if GetPlayerState(GetOwningPlayer(Trader ), PLAYER_STATE_RESOURCE_LUMBER) >= 10 then
set U = FirstOfGroup(G)
if GetUnitManaPercent(U) == 100.00 then
set ItemID = GetItemTypeId(UnitItemInSlotBJ(U, 1))
if UnitInventoryCount(Trader) != 6 then
set TempItem = CreateItem( ItemID, 0,0 )
set i = R2I(GetWidgetLife(TempItem))
call UnitAddItem( Trader, TempItem )
call AdjustPlayerStateSimpleBJ(GetOwningPlayer(Trader), PLAYER_STATE_RESOURCE_LUMBER, -10)
call SetUnitState(U, UNIT_STATE_MANA, 0)
set ValidTrade=true
else
if UnitHasItemOfTypeBJ(Trader , ItemID) then
set TempItem = GetItemOfTypeFromUnitBJ(Trader, ItemID)
set i = R2I(GetWidgetLife(TempItem))
call SetItemCharges( TempItem, ( GetItemCharges(TempItem) + 1 ) )
call AdjustPlayerStateSimpleBJ(GetOwningPlayer(Trader), PLAYER_STATE_RESOURCE_LUMBER, -10)
call SetUnitState(U, UNIT_STATE_MANA, 0)
set ValidTrade=true
else
set ValidTrade=false
if GetOwningPlayer(Trader)==GetLocalPlayer() then
call DisplayTextToPlayer( GetLocalPlayer(),0,0, ( "|cfffed312Your inventory is full.|r" ) )
endif
endif
endif
if ValidTrade then
// Monopoly
set GameTime = TimerGetElapsed(udg_GameTime)
set MonopolyLevel = GetUnitAbilityLevel(Trader,'A08X')
if udg_MonopolyTeam[i] == udg_Player_Team[GetPlayerNr(GetOwningPlayer(Trader))] and (udg_MonopolyLastTrade[i]+120)>GameTime then
set udg_MonopolyCountTrades[i] = udg_MonopolyCountTrades[i] + 1
if udg_MonopolyCountTrades[i]>=7-MonopolyLevel and MonopolyLevel!=0 then
call SetUnitState(U, UNIT_STATE_MANA, 10)
set tagtext = "|cff9898ffMonopoly!|r"
elseif udg_MonopolyCountTrades[i]==1 then
set tagtext = "|cff9898ff1st Trade!|r"
elseif udg_MonopolyCountTrades[i]==2 then
set tagtext = "|cff9898ff2nd Trade!|r"
elseif udg_MonopolyCountTrades[i]==3 then
set tagtext = "|cff9898ff3rd Trade!|r"
else
set tagtext = "|cff9898ff"+I2S(udg_MonopolyCountTrades[i])+"th Trade!|r"
endif
else
set udg_MonopolyCountTrades[i] = 1
set udg_MonopolyTeam[i] = udg_Player_Team[GetPlayerNr(GetOwningPlayer(Trader))]
set tagtext = "|cff9898ff1st Trade!|r"
endif
call ShowTextTag(tagtext, Trader, 0, 0, GetOwningPlayer(Trader))
set udg_MonopolyLastTrade[i] = GameTime
call TriggerExecute( gg_trg_Trader_Floating )
// Since the Trader does not usually damage enemies, use successful trades for this stat instead (used for the Denial of Play detection)
set udg_DamageLast[GetPlayerNr(GetOwningPlayer(Trader))] = udg_Time_Value
endif
set TempItem = null
else
call DisplayTextToPlayer(GetOwningPlayer(Trader),0,0, ( "|cfffed312Item is available again in " + I2S(R2I( 40.50 - GetUnitStateSwap(UNIT_STATE_MANA, U ))) + " seconds.|r" ) )
endif
set U = null
else
call DisplayTextToPlayer(GetOwningPlayer(Trader),0,0, ( "|cfffed312You don't have enough wood.|r" ) )
endif
else
call ReleaseGroup( G )
set G = GetUnitsInRangeOfLocMatchingSafe(384.00, P, FILTER_TRADE_MASTER)
call DebugMsg("Check for trade master")
if FirstOfGroup(G) != null then
if Trig_Trader_Trade_Skill_TradeMasterAllied(FirstOfGroup(G)) then
call DebugMsg("alright")
loop
exitwhen i > 6
set TempItem = UnitItemInSlotBJ(Trader, i)
if GetItemType(TempItem) == ITEM_TYPE_CHARGED then
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(Trader))] == 1 then
set RewardID = R2I(GetWidgetLife(TempItem))
else
set RewardID = 11 - R2I(GetWidgetLife(TempItem))
endif
set RewardGold = RewardGold + (GetItemCharges(TempItem) * udg_Trader_Gold[RewardID] * udg_GoldFactor)
set RewardWood = RewardWood + GetItemCharges(TempItem) * (10 + udg_Trader_Wood[RewardID] )
call RemoveItem(TempItem)
endif
set i = i + 1
endloop
if RewardGold != 0 then
if CountPlayersInForceBJ(udg_Players_Team[udg_Player_Team[GetPlayerNr(GetOwningPlayer(Trader))]]) == 1 then
call AdjustPlayerStateBJ( RewardGold, GetOwningPlayer(Trader), PLAYER_STATE_RESOURCE_GOLD )
call ShowTextTag("|cfffe960a+"+I2S(RewardGold)+"|r", Trader, 0, 0, GetOwningPlayer(Trader))
call UpdateBounty(GetOwningPlayer(Trader), RewardGold)
else
call AdjustPlayerStateBJ( ( RewardGold / 2 ), GetOwningPlayer(Trader), PLAYER_STATE_RESOURCE_GOLD )
call ShowTextTag("|cfffe960a+"+I2S(RewardGold/2)+"|r", Trader, 0, 0, GetOwningPlayer(Trader))
call UpdateBounty(GetOwningPlayer(Trader), RewardGold / 2)
set i = ( ( udg_Player_Team[GetPlayerNr(GetOwningPlayer(Trader))] * 5 ) - 4 )
loop
exitwhen i > udg_Player_Team[GetPlayerNr(GetOwningPlayer(Trader))] * 5
if IsPlayerInForce(GetPlayer(i), udg_Players) and GetPlayer(i) != GetOwningPlayer(Trader) then
call AdjustPlayerStateBJ( ( RewardGold / 2 / ( CountPlayersInForceBJ(udg_Players_Team[udg_Player_Team[i]]) - 1 ) ), GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD )
call ShowTextTag("|cfffe960a+"+I2S(RewardGold / 2 / ( CountPlayersInForceBJ(udg_Players_Team[udg_Player_Team[i]]) - 1 ))+"|r", udg_Tank[i], 0, 0, GetPlayer(i))
endif
set i = i + 1
endloop
endif
call AdjustPlayerStateBJ( RewardWood, GetOwningPlayer(Trader), PLAYER_STATE_RESOURCE_LUMBER )
set RewardXP = R2I(RewardGold*0.75/udg_GoldFactor)
call AddHeroXP(Trader,RewardXP, true )
if GetOwningPlayer(Trader)==GetLocalPlayer() then
call DisplayTimedTextToPlayer( GetLocalPlayer(),0,0, 3.00, ( "Sold items: |cffffcc00" + I2S(RewardGold) + "|r Gold, |cff009900" + I2S(RewardWood) + "|r Wood, |c007d3eb7" + I2S(RewardXP) + "|r XP" ) )
endif
call DestroyEffect(AddSpecialEffectTarget("UI\\Feedback\\GoldCredit\\GoldCredit.mdl",Trader,"origin"))
set udg_Stats_Trader[GetPlayerNr(GetOwningPlayer(Trader))] = udg_Stats_Trader[GetPlayerNr(GetOwningPlayer(Trader))] + RewardGold
endif
call SelectUnitForPlayerSingle( Trader, GetOwningPlayer(Trader) )
set TempItem = null
endif
endif
endif
call ReleaseGroup( G )
set G = null
set Trader = null
endfunction
//===========================================================================
function InitTrig_Trader_Trade_Skill takes nothing returns nothing
set gg_trg_Trader_Trade_Skill = CreateTrigger( )
set FILTER_TRADER_BUILDING = Filter(function Trig_Trader_Trade_Skill_IsTraderBuilding)
set FILTER_TRADE_MASTER = Filter(function Trig_Trader_Trade_Skill_IsTradeMaster)
call TriggerRegisterAnyUnitEventBJ( gg_trg_Trader_Trade_Skill, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_Trader_Trade_Skill, Condition( function Trig_Trader_Trade_Skill_Conditions ) )
call TriggerAddAction( gg_trg_Trader_Trade_Skill, function Trig_Trader_Trade_Skill_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope MetalStars initializer Init
globals
private constant integer ABILITY_ID = 'A03D' // yes, it is actually A03D and A0D3, thats no type
private constant integer SECOND_ABILITY_ID = 'A0D3' // Second wave is the same as the first, except without mana
private constant real WAVE_DELAY = 0.5
endglobals
function Trig_Metal_Stars_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local player owner = GetOwningPlayer(U)
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
call GameTimeWait(WAVE_DELAY)
call IssueImmediateOrder( CreateDummyWithAbilityCoord(owner, SECOND_ABILITY_ID, lvl, GetUnitX(U), GetUnitY(U), 0), "fanofknives" )
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Metal_Stars = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Metal_Stars, ABILITY_ID )
call TriggerAddAction( gg_trg_Metal_Stars, function Trig_Metal_Stars_Actions )
endfunction
endscope
//TESH.scrollpos=88
//TESH.alwaysfold=0
scope MagneticPull initializer Init
globals
private constant integer ABILITY_ID = 'A052'
private constant integer STUN_ABILITY_ID = 'A0DY'
private constant integer BUFF_ABILITY_ID = 'A0DO'
private constant real AREA_BASE = 600.0
private constant real AREA_UP = 0.0
private constant real DURATION_BASE = 1.0
private constant real DURATION_UP = 1.0
private constant real FORCE_BASE = 80.0
private constant real FORCE_UP = 0.0
private constant real STUN_FREQUENCY_BASE = 1.5
private constant real STUN_FREQUENCY_UP = 0.0
private constant real INTERVAL = 0.05
endglobals
function Trig_Magnetic_Pull_Loop_IsMovable takes unit U returns boolean
if (GetUnitState(U, UNIT_STATE_LIFE) <= 0) or (GetUnitAbilityLevel(U, 'Avul') > 0) then
return false
endif
if IsUnitAlly(U, GetPlayer(udg_TempInt)) then
return false
endif
if GetUnitTypeId(U) == 'H013' then
//rooted Guard
return false
endif
if GetUnitTypeId(U) == 'H01H' then
//Pilot
return false
endif
if IsDummy(U) then
return false
endif
if (IsUnitType(U, UNIT_TYPE_STRUCTURE)) then
return false
endif
return true
endfunction
function Trig_Magnetic_Pull_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit EnumUnit
local unit Caster = udg_AV_Unit1[LoopTimerId]
local unit Dummy = udg_AV_Unit2[LoopTimerId]
local group G
local integer lvl = udg_AV_Int1[LoopTimerId]
local real DistX
local real DistY
local real AngleRad
local real DistanceLeft
local real Force = ( FORCE_BASE + ( lvl * FORCE_UP ) ) * INTERVAL
local integer stunFrequency = R2I(( STUN_FREQUENCY_BASE + ( lvl * STUN_FREQUENCY_UP ) ) / INTERVAL)
local integer duration = R2I(( DURATION_BASE + ( lvl * DURATION_UP ) ) / INTERVAL)
local integer range = R2I(AREA_BASE + ( lvl * AREA_UP ))
//Stun every 1.5 seconds
if (ModuloInteger(udg_AV_Int2[LoopTimerId], stunFrequency) == 0) then
call IssueImmediateOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), STUN_ABILITY_ID, 1, GetUnitX(Caster), GetUnitY(Caster), 0), "stomp")
endif
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
call SetUnitX(Dummy, GetUnitX(Caster))
call SetUnitY(Dummy, GetUnitY(Caster))
if ((udg_AV_Int2[LoopTimerId] > duration) or (GetUnitState(Caster, UNIT_STATE_LIFE) <= 0)) then
call UnitRemoveAbility(Caster, BUFF_ABILITY_ID)
call RemoveUnit(Dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set G = NewGroup()
set udg_TempInt = GetPlayerNr(GetOwningPlayer(Caster))
call GroupEnumUnitsInRange(G, GetUnitX(Caster),GetUnitY(Caster), range, null )
loop
set EnumUnit = FirstOfGroup(G)
exitwhen EnumUnit==null
if Trig_Magnetic_Pull_Loop_IsMovable(EnumUnit) then
set DistX = GetUnitX(Caster)-GetUnitX(EnumUnit)
set DistY = GetUnitY(Caster)-GetUnitY(EnumUnit)
set AngleRad = Atan2(DistY, DistX)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if DistanceLeft >= 75 then
// Check if it's even possible to move the unit to the new location, to prevent it to pull them up cliffs etc.
if IsUnitType(EnumUnit, UNIT_TYPE_FLYING) or IsTerrainWalkable(GetUnitX(EnumUnit) + Force*Cos(AngleRad), GetUnitY(EnumUnit) + Force*Sin(AngleRad)) then
call SetUnitX(EnumUnit, GetUnitX(EnumUnit) + Force*Cos(AngleRad))
call SetUnitY(EnumUnit, GetUnitY(EnumUnit) + Force*Sin(AngleRad))
endif
endif
endif
call GroupRemoveUnit(G, EnumUnit)
endloop
call ReleaseGroup(G)
set G = null
endif
set Caster = null
set Dummy = null
set EnumUnit = null
endfunction
function Trig_Magnetic_Pull_Actions takes nothing returns nothing
local timer t
local unit U = GetTriggerUnit()
local unit dummy = CreateUnit(GetOwningPlayer(U) , DUMMY_ID , GetUnitX(U) , GetUnitY(U) , 270)
local integer TimerIndex
call AddSpecialEffectTarget("Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget.mdl", dummy, "origin")
call SetUnitScale(dummy, 7, 7, 7)
//Buff aura
call UnitAddAbility(U, BUFF_ABILITY_ID)
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[TimerIndex] = GetUnitAbilityLevel(U,ABILITY_ID)
set udg_AV_Int2[TimerIndex] = 1
set udg_AV_Unit1[TimerIndex] = U
set udg_AV_Unit2[TimerIndex] = dummy
call TimerStart(t, INTERVAL, true, function Trig_Magnetic_Pull_Loop)
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Magnetic_Pull = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Magnetic_Pull, ABILITY_ID )
call TriggerAddAction( gg_trg_Magnetic_Pull, function Trig_Magnetic_Pull_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope GoblinSynergy initializer Init
globals
private constant integer ABILITY_ID = 'A0D7'
private constant integer SPEED_ID = 'A0GZ'
private constant integer SPEED_BUFF_ID = 'B01Z'
private constant real AREA_BASE = 100.0
private constant real AREA_UP = 150.0
private constant real INTERVAL = 0.5
constant integer GOBLIN_SYNERGY_RESISTANCE_ID = 'A0GY'
endglobals
function Trig_Goblin_Synergy_Conditions takes nothing returns boolean
return GetLearnedSkill() == ABILITY_ID
endfunction
function Trig_Goblin_Synergy_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local unit dummy = udg_AV_Unit2[LoopTimerId]
local group G
local integer count
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local real range = AREA_BASE + (lvl * AREA_UP)
if GetUnitTypeId(U) != 'H011' then
call ReleaseDummy(dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call DebugMsg("No longer a Shredder!")
elseif (GetUnitState(U, UNIT_STATE_LIFE) > 0) then
set G = NewGroup()
call GroupEnumUnitsInRange(G, GetUnitX(U),GetUnitY(U), range, FILTER_ANY_TANK )
set count = CountUnitsInGroup(G)
call SetUnitAbilityLevel(U, GOBLIN_SYNERGY_RESISTANCE_ID, count)
call SetUnitAbilityLevel(dummy, SPEED_ID, count)
call SetUnitPosition(dummy, GetUnitX(U), GetUnitY(U))
call IssueTargetOrder(dummy, "bloodlust", U)
// Calculate the new color value
set count = R2I(255 * (0.5-(count/20.0)))
call SetUnitVertexColor( U, count, count, count, 255 )
call ReleaseGroup(G)
set G = null
endif
set U = null
set dummy = null
endfunction
function Trig_Goblin_Synergy_Actions takes nothing returns nothing
local timer t
local unit U = GetTriggerUnit()
local unit dummy
local integer TimerIndex
if (GetUnitAbilityLevel(U, GetLearnedSkill()) == 1) then
call DebugMsg("Learned!")
call UnitAddAbility(U, GOBLIN_SYNERGY_RESISTANCE_ID)
//call SetPlayerAbilityAvailable(GetOwningPlayer(U), GOBLIN_SYNERGY_RESISTANCE_ID, false)
set dummy = CreateDummyWithAbilityCoord(GetOwningPlayer(U), SPEED_ID, 1, GetUnitX(U), GetUnitY(U), 0)
// DUMMY_EXTENDER prevents the dummy from being removed automatically, after he has cast a skill
call UnitAddAbility(dummy, DUMMY_EXTENDER_ID)
call IssueTargetOrder(dummy, "bloodlust", U)
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[TimerIndex] = GetPlayerNr(GetOwningPlayer(U))
set udg_AV_Unit1[TimerIndex] = U
set udg_AV_Unit2[TimerIndex] = dummy
call TimerStart(t, INTERVAL, true, function Trig_Goblin_Synergy_Loop)
endif
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Goblin_Synergy = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Goblin_Synergy, EVENT_PLAYER_HERO_SKILL )
call TriggerAddCondition( gg_trg_Goblin_Synergy, Condition( function Trig_Goblin_Synergy_Conditions ) )
call TriggerAddAction( gg_trg_Goblin_Synergy, function Trig_Goblin_Synergy_Actions )
endfunction
endscope
//TESH.scrollpos=6
//TESH.alwaysfold=0
scope UnitTeleport initializer Init
globals
private constant integer ABILITY_ID = 'A04N'
private constant integer SLOW_ABILITY_ID = 'A0DP'
private constant real TELEPORT_RANGE_RATIO = (1.0/3.0) // how far is the final location on the line from shredder to target (between 0 and 1)
endglobals
function Trig_Unit_Teleport_Actions takes nothing returns nothing
local unit Target= GetSpellTargetUnit()
local unit Caster= GetTriggerUnit()
local player Owner= GetOwningPlayer(Caster)
local location tmpLoc
local real angle
local real dist
local real X
local real Y
if GetUnitMoveSpeed(Target) == 0.00 then
if GetLocalPlayer() == Owner then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312You cannot teleport an unmovable unit.|r")
endif
call IssueImmediateOrder(Caster, "stop")
call SetUnitManaDelayed(Caster , GetUnitState(Caster, UNIT_STATE_MANA))
else
// this should trigger the assist detection and grant an assist, even when you didn't do any damage otherwise
call UnitDamageTarget(Caster, Target, 0, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
//call TriggerSleepAction(0.00)
set X=GetUnitX(Target) - GetUnitX(Caster)
set Y=GetUnitY(Target) - GetUnitY(Caster)
set dist=SquareRoot(X * X + Y * Y)
set angle=bj_RADTODEG * Atan2(GetUnitY(Target) - GetUnitY(Caster), GetUnitX(Target) - GetUnitX(Caster))
set X=GetUnitX(Caster) + ( dist * TELEPORT_RANGE_RATIO + 32 ) * Cos(angle * bj_DEGTORAD)
set Y=GetUnitY(Caster) + ( dist * TELEPORT_RANGE_RATIO + 32 ) * Sin(angle * bj_DEGTORAD)
set tmpLoc=Location(X, Y)
//First check if the position for the Shredder is pathable
if GetPathableLoc(tmpLoc , 32 , 768) then
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(Caster), GetUnitY(Caster)))
//call SetUnitPositionLoc(Caster, tmpLoc)
call SetUnitX(Caster, GetLocationX(tmpLoc))
call SetUnitY(Caster, GetLocationY(tmpLoc))
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(Caster), GetUnitY(Caster)))
//then place the teleported unit in front of him
set X=GetUnitX(Caster) + 32 * Cos(angle * bj_DEGTORAD)
set Y=GetUnitY(Caster) + 32 * Sin(angle * bj_DEGTORAD)
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(Target), GetUnitY(Target)))
//call SetUnitPosition(Target, X, Y)
call SetUnitX(Target, X)
call SetUnitY(Target, Y)
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(Target), GetUnitY(Target)))
call IssueTargetOrder(CreateDummyWithAbilityCoord(Owner , SLOW_ABILITY_ID , 1 , GetUnitX(Target) , GetUnitY(Target) , 0), "slow", Target)
else
if GetLocalPlayer() == Owner then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312There is no room for you to teleport to.|r")
endif
call IssueImmediateOrder(Caster, "stop")
call RefreshSkill(Caster, ABILITY_ID)
call SetUnitManaDelayed(Caster , GetUnitState(Caster, UNIT_STATE_MANA))
endif
endif
call RemoveLocation(tmpLoc)
set tmpLoc=null
set Target=null
set Caster=null
set Owner=null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Unit_Teleport = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Unit_Teleport, ABILITY_ID )
call TriggerAddAction( gg_trg_Unit_Teleport, function Trig_Unit_Teleport_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope LightningStrike initializer Init
globals
private constant integer ABILITY_ID = 'A02N'
private constant integer DAMAGE_ABILITY_ID = 'A03F'
endglobals
private function Actions takes nothing returns nothing
local unit Target = GetSpellTargetUnit()
local unit Caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real x = GetUnitX(Target)
local real y = GetUnitY(Target)
local real z = GetUnitZ(Target)
call IssueImmediateOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), DAMAGE_ABILITY_ID, level, x, y, GetUnitFlyHeight(Target)), "fanofknives")
call ShowEffectAtPos("Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl", x, y, GetUnitFlyHeight(Target), 2, 0.5)
call DestroyTreesInRange(x,y,200)
call Pala.StaticLightning(x,x,y,y,z+1750.0,z,1.0,"CLPB")
call Pala.StaticLightning(x,x,y,y,z+1750.0,z,1.0,"FORK")
set Target = null
set Caster = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ThunderStorm initializer Init
globals
private constant integer ABILITY_ID = 'A04B'
private constant integer CHANNEL_ABILITY_ID = 'A04A'
endglobals
private function Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
call DestroyTreesInRange(x,y,450)
call TriggerSleepAction(0.01)
call IssuePointOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), CHANNEL_ABILITY_ID, level, x, y, 0), "blizzard", x, y)
set Caster = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=48
//TESH.alwaysfold=0
scope ChainLightning initializer Init
globals
private constant integer ABILITY_ID = 'A029'
private constant real MAX_DISTANCE_BASE = 1050.0
private constant real MAX_DISTANCE_UP = 350.0
private constant real DAMAGE_BASE = 525.0
private constant real DAMAGE_UP = 175.0
private constant real DAMAGE_BONUS = 0.07
private constant real INTERVAL = 0.35
endglobals
function Trig_ChainLightning_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Caster = udg_AV_Unit1[LoopTimerId]
local unit LastTarget = udg_AV_Unit2[LoopTimerId]
local unit NewTarget
local group OldTargets = udg_AV_Group1[LoopTimerId]
local real DistanceLeft = udg_AV_Real1[LoopTimerId]
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local group G = NewGroup()
//call DebugMsg("Distance Left: " + R2S(DistanceLeft))
set udg_Filter_Player = GetOwningPlayer(Caster)
call GroupEnumUnitsInRange(G, udg_AV_Real2[LoopTimerId],udg_AV_Real3[LoopTimerId], DistanceLeft, FILTER_ENEMY_UNITS)
// Remove all units that already have been hit by the chain lightning (OldTargets) from the group that is currently around the last target (G)
call GroupRemoveGroup(OldTargets, G)
if FirstOfGroup(G) == null then
call ReleaseGroup(OldTargets)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set NewTarget = GetClosestUnitFromGroup(G, GetUnitX(LastTarget), GetUnitY(LastTarget))
// Damage
set udg_AV_Int1[LoopTimerId] = R2I(udg_AV_Int1[LoopTimerId] * (1.0 + DAMAGE_BONUS))
//call DebugMsg("LastTarget: " + GetName(LastTarget) + " NewTarget: " + GetName(NewTarget))
call Lightning.CreateUU("CLPB", LastTarget, NewTarget, true, false, 3*INTERVAL)
call UnitDamageTarget(Caster, NewTarget, udg_AV_Int1[LoopTimerId], true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
call GroupAddUnit(OldTargets, NewTarget)
set udg_AV_Real1[LoopTimerId] = DistanceLeft - GetUnitsDistance(LastTarget, NewTarget)
if (IsUnitType(NewTarget, UNIT_TYPE_HERO)) then
call ShowTextTag("|cffff0000" + I2S(udg_AV_Int1[LoopTimerId]) + "!|r", NewTarget, 0, 50, null)
endif
set udg_AV_Unit2[LoopTimerId] = NewTarget
set udg_AV_Real2[LoopTimerId] = GetUnitX(NewTarget)
set udg_AV_Real3[LoopTimerId] = GetUnitY(NewTarget)
endif
call ReleaseGroup(G)
set G = null
set Caster = null
set LastTarget = null
set NewTarget = null
endfunction
function Trig_ChainLightning_Actions takes nothing returns nothing
local timer t
local integer LoopTimerId
local unit Caster = GetTriggerUnit()
local unit Target = GetSpellTargetUnit()
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real Damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real Distance = MAX_DISTANCE_BASE + ( level * MAX_DISTANCE_UP )
local group G = NewGroup()
call UnitDamageTarget(Caster, Target, Damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
call Lightning.CreateUU("CLPB", Caster, Target, true, false, 3*INTERVAL)
call GroupAddUnit(G, Target)
set Distance = Distance - GetUnitsDistance(Caster, Target)
if (IsUnitType(Target, UNIT_TYPE_HERO)) then
call ShowTextTag("|cffff0000" + I2S(R2I(Damage)) + "!|r", Target, 0, 50, null)
endif
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Caster
set udg_AV_Unit2[LoopTimerId] = Target
set udg_AV_Real1[LoopTimerId] = Distance
set udg_AV_Real2[LoopTimerId] = GetUnitX(Target)
set udg_AV_Real3[LoopTimerId] = GetUnitY(Target)
set udg_AV_Int1[LoopTimerId] = R2I(Damage)
set udg_AV_Group1[LoopTimerId] = G
call TimerStart(t, INTERVAL, true, function Trig_ChainLightning_Loop)
set Caster = null
set Target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Chain_Lightning = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Chain_Lightning, ABILITY_ID )
call TriggerAddAction( gg_trg_Chain_Lightning, function Trig_ChainLightning_Actions )
endfunction
endscope
//TESH.scrollpos=83
//TESH.alwaysfold=0
scope EnergyLeash initializer Init
globals
private constant integer ABILITY_ID = 'A0E4'
private constant integer CANCEL_ABILITY_ID = 'A08Q'
private constant real DURATION_BASE = 0.0
private constant real DURATION_UP = 0.75
private constant real FORCE_BASE = 250.0
private constant real FORCE_UP = 0.0
private constant real INTERVAL = 0.05
private constant real MAX_RANGE = 2000
private constant real MIN_RANGE = 550
boolean array CancelEnergyLeash[10]
endglobals
function Trig_Energy_Leash_Cancel takes unit U, unit Dummy returns nothing
set CancelEnergyLeash[GetPlayerNr(GetOwningPlayer(U))] = false
call SetPlayerAbilityAvailable(GetOwningPlayer(U), ABILITY_ID, true)
if (GetUnitAbilityLevel(U, CANCEL_ABILITY_ID) > 0) then
call UnitRemoveAbility(U, CANCEL_ABILITY_ID)
endif
call KillUnit(Dummy)
endfunction
function Trig_Energy_Leash_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Caster = udg_AV_Unit1[LoopTimerId]
local unit Target = udg_AV_Unit2[LoopTimerId]
local unit Dummy = udg_AV_Unit3[LoopTimerId]
local integer lvl = udg_AV_Int1[LoopTimerId]
local lightning light = udg_AV_Lightning[LoopTimerId]
local real DistX
local real DistY
local real AngleRad
local real DistanceLeft
local real Force = (FORCE_BASE + (lvl * FORCE_UP)) * INTERVAL
local real Duration = DURATION_BASE + (lvl * DURATION_UP)
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
//stop the timer when either target or source is dead or the target became invisible
if (GetUnitState(Caster, UNIT_STATE_LIFE) <= 0) or (GetUnitState(Target, UNIT_STATE_LIFE) <= 0) or not IsUnitVisible(Target, GetOwningPlayer(Caster)) or (GetUnitAbilityLevel(Target, 'Avul') > 0) then
call Trig_Energy_Leash_Cancel(Caster, Dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
// also stop the timer, when the duration is over or the user canceled the effect
elseif (udg_AV_Int2[LoopTimerId] > (Duration / INTERVAL) or CancelEnergyLeash[GetPlayerNr(GetOwningPlayer(Caster))]) then
call Trig_Energy_Leash_Cancel(Caster, Dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set DistX = GetUnitX(Caster)-GetUnitX(Target)
set DistY = GetUnitY(Caster)-GetUnitY(Target)
set AngleRad = Atan2(DistY, DistX)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
// The dummy is used, to be able to end the lightning effect prematurely, since the lightning system does not provide such functionality
// So the dummy is set to the position of the tank, so it looks like it has the same position as the caster
// When the lightning effect should be ended, the Dummy is killed
call SetUnitPosition(Dummy, GetUnitX(Caster), GetUnitY(Caster))
if DistanceLeft >= MIN_RANGE then
if DistanceLeft < MAX_RANGE then
//Air Units are drawn towards you
if (IsAirUnit(Target) and IsUnitEnemy(Target, GetOwningPlayer(Caster))) then
call SetUnitX(Target, GetUnitX(Target) + Force*Cos(AngleRad))
call SetUnitY(Target, GetUnitY(Target) + Force*Sin(AngleRad))
//and you are drawn towards ground units and allies
else
call SetUnitX(Caster, GetUnitX(Caster) - Force*Cos(AngleRad))
call SetUnitY(Caster, GetUnitY(Caster) - Force*Sin(AngleRad))
endif
else
call Trig_Energy_Leash_Cancel(Caster, Dummy)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
endif
endif
set Caster = null
set Target = null
set Dummy = null
endfunction
function Trig_Energy_Leash_Actions takes nothing returns nothing
local timer t
local unit U = GetTriggerUnit()
local unit dummy
local player Owner = GetOwningPlayer(U)
local integer TimerIndex
local integer lvl = GetUnitAbilityLevel(U,ABILITY_ID)
local real duration = DURATION_BASE + (lvl * DURATION_UP)
if (GetSpellAbilityId() == CANCEL_ABILITY_ID) then
set CancelEnergyLeash[GetPlayerNr(Owner)] = true
call SetPlayerAbilityAvailable(Owner, ABILITY_ID, true)
call UnitRemoveAbility(U, CANCEL_ABILITY_ID)
elseif (GetSpellAbilityId() == ABILITY_ID) then
call SetPlayerAbilityAvailable(Owner, ABILITY_ID, false)
call UnitAddAbility(U, CANCEL_ABILITY_ID)
set dummy = CreateUnit(GetOwningPlayer(U) , DUMMY_ID , GetUnitX(U) , GetUnitY(U) , 270)
call SetUnitFlyHeight(dummy, GetUnitFlyHeight(U), 0)
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[TimerIndex] = lvl
set udg_AV_Int2[TimerIndex] = 1
set udg_AV_Unit1[TimerIndex] = U
set udg_AV_Unit2[TimerIndex] = GetSpellTargetUnit()
set udg_AV_Unit3[TimerIndex] = dummy
set udg_AV_Lightning[TimerIndex] = Lightning.CreateUU("FORK", dummy, GetSpellTargetUnit(), false, true, duration)
call TimerStart(t, INTERVAL, true, function Trig_Energy_Leash_Loop)
// this should trigger the assist detection and grant an assist, even when you didn't do any damage otherwise
call UnitDamageTarget(U, GetSpellTargetUnit(), 0, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
endif
set U = null
set dummy = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Energy_Leash = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Energy_Leash, ABILITY_ID )
call TriggerRegisterSpellEffectEvent( gg_trg_Energy_Leash, CANCEL_ABILITY_ID )
call TriggerAddAction( gg_trg_Energy_Leash, function Trig_Energy_Leash_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope StormShock initializer Init
globals
private integer ABILITY_ID = 'A0F8'
private real DAMAGE_BASE = 0.0
private real DAMAGE_UP = 100.0
private real AREA_BASE = 400.0
private real AREA_UP = 0.0
endglobals
function Trig_Storm_Shock_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer lvl = GetUnitAbilityLevel(Caster, ABILITY_ID)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local real area = AREA_BASE + (lvl * AREA_UP)
local real damage = DAMAGE_BASE + (lvl * DAMAGE_UP)
call ShowEffectAtPos("war3mapImported\\Cyclon Explosion.mdx",TargetX, TargetY, 250, 1.7, 0.1)
set udg_Filter_Player = GetOwningPlayer(Caster)
//Air tanks get damaged twice
call FixedAreaDamageFromUnit(Caster, TargetX, TargetY, area, damage, 0, 0, false, FILTER_ENEMY_AIR_UNIT)
call FixedAreaDamageFromUnit(Caster, TargetX, TargetY, area, damage, 0, 0, false, FILTER_ENEMY_UNITS)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Storm_Shock = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Storm_Shock, ABILITY_ID )
call TriggerAddAction( gg_trg_Storm_Shock, function Trig_Storm_Shock_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope AirMines initializer Init
function interface iTrig_Air_Mines_Explode takes unit Mine returns nothing
globals
private constant integer ABILITY_ID = 'A0E8'
private constant real MINE_DURATION_BASE = 180.0
private constant real MINE_DURATION_UP = 0.0
private constant real MINE_SPEED_BASE = 450.0
private constant real MINE_SPEED_UP = 0.0
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 250.0
private constant real WEAPON_UPGRADE_FACTOR = 0.03
private constant real DAMAGE_AREA_BASE = 500.0
private constant real DAMAGE_AREA_UP = 0.0
private constant real INTERVAL = 0.05
private constant real IDLE_INTERVAL = 0.5
private constant real ACTIVATION_RANGE = 150
private constant real FOLLOW_SEARCH = 500
private constant real MAX_FOLLOW_RANGE = 1000
iTrig_Air_Mines_Explode AirMines_Explode = Trig_Air_Mines_Explode
endglobals
function Trig_Air_Mines_Explode takes unit Mine returns nothing
local real MineX = GetUnitX(Mine)
local real MineY = GetUnitY(Mine)
local integer lvl = GetUnitUserData(Mine)
local real weaponUpAmp = (1.0 + WEAPON_UPGRADE_FACTOR * I2R(GetPlayerTechCount(GetOwningPlayer(Mine), 'R002', true)) )
local real damage = (DAMAGE_BASE + (lvl * DAMAGE_UP)) * weaponUpAmp
local real area = DAMAGE_AREA_BASE + (lvl * DAMAGE_AREA_UP)
set udg_Filter_Player = GetOwningPlayer(Mine)
call AreaSpellDamageFromUnit(Mine, MineX, MineY, area, damage, 1, 0, FILTER_ENEMY_UNITS)
call IssueImmediateOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(Mine), 'A0DI', lvl, GetUnitX(Mine), GetUnitY(Mine), 0), "thunderclap")
call ShowEffectAtPos("war3mapImported\\NewAirEX.mdx",MineX, MineY, GetUnitFlyHeight(Mine), 3, 3)
call KillUnit(Mine)
endfunction
globals
//This is part of a workaround, the functions Trig_Air_Mines_Check and Trig_Air_Mines_Follow call each other
//because one has to be declared before the other, there is a problem with the function call (the function called is still unknown to the function that got declared first)
//so the following code variable is used as a replacement for the call and filled in the init function
code MinesFollow
endglobals
function Trig_Air_Mines_Check takes nothing returns nothing
local timer t
local integer TimerIndex
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Mine = udg_AV_Unit1[LoopTimerId]
local group G
if (Mine == null) or (GetUnitState(Mine, UNIT_STATE_LIFE) <= 0) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
//Look for any enemy tanks near the mine
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(Mine)
call GroupEnumUnitsInRange(G, GetUnitX(Mine),GetUnitY(Mine), ACTIVATION_RANGE, FILTER_ENEMY_TANK )
//Enemy tank right next to the mine -> explode
if (FirstOfGroup(G) != null) then
call Trig_Air_Mines_Explode(Mine)
call DebugMsg("Now explode!")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
//Look for Air Tanks near the mine
set udg_Filter_Player = GetOwningPlayer(Mine)
call GroupEnumUnitsInRange(G, GetUnitX(Mine),GetUnitY(Mine), FOLLOW_SEARCH, FILTER_ENEMY_AIR_TANK )
//If there is an Air Tank, try to catch him
if (FirstOfGroup(G) != null) then
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = Mine
set udg_AV_Unit2[TimerIndex] = FirstOfGroup(G)
call TimerStart(t, INTERVAL, true, MinesFollow)
call DebugMsg("Now follow!")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
endif
call ReleaseGroup(G)
endif
set Mine = null
set G = null
endfunction
function Trig_Air_Mines_Wait takes unit Mine returns nothing
local timer t
local integer TimerIndex
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = Mine
call TimerStart(t, IDLE_INTERVAL, true, function Trig_Air_Mines_Check)
endfunction
function Trig_Air_Mines_Follow takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Mine = udg_AV_Unit1[LoopTimerId]
local unit Target = udg_AV_Unit2[LoopTimerId]
local integer lvl = GetUnitUserData(Mine)
local real Speed = (MINE_SPEED_BASE + (lvl * MINE_SPEED_UP)) * INTERVAL
local real DistX
local real DistY
local real AngleRad
local real DistanceLeft
if (GetUnitState(Mine, UNIT_STATE_LIFE) <= 0) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set DistX = GetUnitX(Target) - GetUnitX(Mine)
set DistY = GetUnitY(Target) - GetUnitY(Mine)
set AngleRad = Atan2(DistY, DistX)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if (DistanceLeft > MAX_FOLLOW_RANGE) or (GetUnitState(Target, UNIT_STATE_LIFE) <= 0) then
//Don't follow anymore and become stationary instead
call Trig_Air_Mines_Wait(Mine)
call DebugMsg("Now wait!")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
if DistanceLeft > Speed then
call SetUnitPosition(Mine, GetUnitX(Mine) + Speed * DistX / DistanceLeft, GetUnitY(Mine) + Speed * DistY / DistanceLeft)
call SetUnitFacing(Mine , Atan2(DistY , DistX) * bj_RADTODEG)
else
//Reched the targt unit -> explode
call Trig_Air_Mines_Explode(Mine)
call DebugMsg("Now explode!")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
endif
endif
set Mine = null
set Target = null
endfunction
function Trig_Air_Mines_Launch takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local timer t
local integer TimerIndex
local unit Mine = udg_AV_Unit1[LoopTimerId]
local real TargetX = udg_AV_Real1[LoopTimerId]
local real TargetY = udg_AV_Real2[LoopTimerId]
local real DistX
local real DistY
local real AngleRad
local real DistanceLeft
local integer lvl = GetUnitUserData(Mine)
local real Speed = (MINE_SPEED_BASE + (lvl * MINE_SPEED_UP)) * INTERVAL
local group G = NewGroup()
if (GetUnitState(Mine, UNIT_STATE_LIFE) <= 0) then
call DebugMsg("Air Mine Dead")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set DistX = TargetX - GetUnitX(Mine)
set DistY = TargetY - GetUnitY(Mine)
set AngleRad = Atan2(DistY, DistX)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if DistanceLeft > Speed then
call SetUnitPosition(Mine, GetUnitX(Mine) + Speed * DistX / DistanceLeft, GetUnitY(Mine) + Speed * DistY / DistanceLeft)
call SetUnitFacing(Mine , Atan2(DistY , DistX) * bj_RADTODEG)
//Look for any enemy tanks near the mine
set udg_Filter_Player = GetOwningPlayer(Mine)
call GroupEnumUnitsInRange(G, GetUnitX(Mine),GetUnitY(Mine), ACTIVATION_RANGE, FILTER_ENEMY_TANK )
//Enemy tank right next to the mine -> explode
if (FirstOfGroup(G) != null) then
call Trig_Air_Mines_Explode(Mine)
call DebugMsg("Now explode!")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
//Look for Air Tanks near the mine
set udg_Filter_Player = GetOwningPlayer(Mine)
call GroupEnumUnitsInRange(G, GetUnitX(Mine),GetUnitY(Mine), FOLLOW_SEARCH, FILTER_ENEMY_AIR_TANK )
//If there is an Air Tank, don't try to reach the initial target anymore, but rather lock onto the Air Tank
if (FirstOfGroup(G) != null) then
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = Mine
set udg_AV_Unit2[TimerIndex] = FirstOfGroup(G)
call TimerStart(t, INTERVAL, true, function Trig_Air_Mines_Follow)
call DebugMsg("Now follow!")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
endif
else
//Target has been reached, the Mine now waits for it's victim in the targeted location
call Trig_Air_Mines_Wait(Mine)
call DebugMsg("Now wait!")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
endif
call ReleaseGroup(G)
set Mine = null
set G = null
endfunction
function Trig_Air_Mines_Actions takes nothing returns nothing
local timer t
local unit Caster = GetTriggerUnit()
local unit Mine
local integer TimerIndex
local real face
local integer lvl = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local real duration = MINE_DURATION_BASE + (lvl * MINE_DURATION_UP)
call DebugMsg("Go X: " + R2S(TargetX))
set face = bj_RADTODEG * Atan2(TargetY - GetUnitY(Caster), TargetX - GetUnitX(Caster))
set Mine = CreateUnit(GetOwningPlayer(Caster) , 'n016' , GetUnitX(Caster) , GetUnitY(Caster) , face)
call SetUnitUserData(Mine, lvl)
call UnitApplyTimedLife(Mine, 'B015', duration)
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = Mine
set udg_AV_Real1[TimerIndex] = TargetX
set udg_AV_Real2[TimerIndex] = TargetY
call TimerStart(t, INTERVAL, true, function Trig_Air_Mines_Launch)
set Caster = null
set Mine = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set MinesFollow = function Trig_Air_Mines_Follow
set gg_trg_Air_Mines = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Air_Mines, ABILITY_ID )
call TriggerAddAction( gg_trg_Air_Mines, function Trig_Air_Mines_Actions )
endfunction
endscope
//TESH.scrollpos=36
//TESH.alwaysfold=0
scope EyeOfTheStorm initializer Init
globals
private constant integer ABILITY_ID = 'A0EF'
private constant integer ALLY_SPEED_ID = 'A0ED'
private constant integer ENEMY_SPEED_ID = 'A0EE'
private constant real DURATION_BASE = 6.0
private constant real DURATION_UP = 0.0
private constant real DAMAGE_BASE = 75.0
private constant real DAMAGE_UP = 25.0
private constant real DAMAGE_INTERVAL = 1.0
private constant real EFFECT_INTERVAL = 0.02
private constant real OUTER_RANGE = 1100
private constant real INNER_RANGE = 650
endglobals
function Trig_Eye_of_the_Storm_Effect takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Caster = udg_AV_Unit1[LoopTimerId]
local unit Tornado = udg_AV_Unit2[LoopTimerId]
if ((GetUnitState(Caster, UNIT_STATE_LIFE) <= 0) or (GetUnitState(Tornado, UNIT_STATE_LIFE) <= 0)) then
call KillUnit(Tornado)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
call SetUnitPosition(Tornado, GetUnitX(Caster), GetUnitY(Caster))
endif
set Caster = null
set Tornado = null
endfunction
function Trig_Eye_of_the_Storm_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Caster = udg_AV_Unit1[LoopTimerId]
local integer lvl = udg_AV_Int1[LoopTimerId]
local real damage = DAMAGE_BASE + (DAMAGE_UP*lvl)
local real duration = DURATION_BASE + (DURATION_UP*lvl)
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
if ((GetUnitState(Caster, UNIT_STATE_LIFE) <= 0) or udg_AV_Int2[LoopTimerId] > (duration / DAMAGE_INTERVAL)) then
call UnitRemoveAbility(Caster, ENEMY_SPEED_ID)
call UnitRemoveAbility(Caster, ALLY_SPEED_ID)
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set udg_Filter_Player = GetOwningPlayer(Caster)
call FixedAreaDamageFromUnit(Caster, GetUnitX(Caster), GetUnitY(Caster), OUTER_RANGE, damage, 0, 0, false, FILTER_ENEMY)
call FixedAreaDamageFromUnit(Caster, GetUnitX(Caster), GetUnitY(Caster), INNER_RANGE, damage, 0, 0, false, FILTER_ENEMY)
endif
set Caster = null
endfunction
function Trig_Eye_of_the_Storm_Actions takes nothing returns nothing
local timer t
local timer t2
local unit U = GetTriggerUnit()
local unit tornado
local integer TimerIndex
local integer TimerIndex2
local integer lvl = GetUnitAbilityLevel(U, GetSpellAbilityId())
call UnitAddAbility(U, ENEMY_SPEED_ID) //Enemy speed aura
call SetUnitAbilityLevel(U, ENEMY_SPEED_ID, lvl)
call UnitAddAbility(U, ALLY_SPEED_ID) //Ally speed aura
call SetUnitAbilityLevel(U, ALLY_SPEED_ID, lvl)
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[TimerIndex] = lvl
set udg_AV_Int2[TimerIndex] = 1
set udg_AV_Unit1[TimerIndex] = U
call TimerStart(t, DAMAGE_INTERVAL, true, function Trig_Eye_of_the_Storm_Loop)
set tornado = CreateUnit(GetOwningPlayer(U) , 'h026' , GetUnitX(U) , GetUnitY(U) , 270)
call UnitApplyTimedLife(tornado, 'B015', 6)
set t2 = NewTimer()
set TimerIndex2 = NewTimerIndex(t2)
set udg_AV_Unit1[TimerIndex2] = U
set udg_AV_Unit2[TimerIndex2] = tornado
call TimerStart(t2, EFFECT_INTERVAL, true, function Trig_Eye_of_the_Storm_Effect)
set U = null
set tornado = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Eye_of_the_Storm = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Eye_of_the_Storm, ABILITY_ID )
call TriggerAddAction( gg_trg_Eye_of_the_Storm, function Trig_Eye_of_the_Storm_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope AirCannon initializer Init
globals
private constant integer NORMAL_ABILITY_ID = 'A0FB'
private constant integer AIR_ABILITY_ID = 'A0EA'
private constant integer NORMAL_EFFECT_ID = 'A01J'
private constant integer AIR_EFFECT_ID = 'A0E9'
endglobals
function Trig_Air_Cannon_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(U, GetSpellAbilityId())
if (GetSpellAbilityId() == NORMAL_ABILITY_ID) then
call UnitAddAbility(U, AIR_ABILITY_ID)
call SetUnitAbilityLevel(U, AIR_ABILITY_ID, level)
call UnitAddAbility(U, AIR_EFFECT_ID)
call SetUnitAbilityLevel(U, AIR_EFFECT_ID, level)
call UnitRemoveAbility(U, NORMAL_EFFECT_ID)
call UnitRemoveAbility(U, NORMAL_ABILITY_ID)
if GetLocalPlayer() == GetOwningPlayer(U) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312Changed to Air Cannon.|r")
endif
else
call UnitAddAbility(U, NORMAL_ABILITY_ID)
call SetUnitAbilityLevel(U, NORMAL_ABILITY_ID, level)
call UnitAddAbility(U, NORMAL_EFFECT_ID)
call SetUnitAbilityLevel(U, NORMAL_EFFECT_ID, level)
call UnitRemoveAbility(U, AIR_EFFECT_ID)
call UnitRemoveAbility(U, AIR_ABILITY_ID)
if GetLocalPlayer() == GetOwningPlayer(U) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312Changed to Normal Cannon.|r")
endif
endif
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Air_Cannon = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Air_Cannon, NORMAL_ABILITY_ID )
call TriggerRegisterSpellEffectEvent( gg_trg_Air_Cannon, AIR_ABILITY_ID )
call TriggerAddAction( gg_trg_Air_Cannon, function Trig_Air_Cannon_Actions )
endfunction
endscope
//TESH.scrollpos=11
//TESH.alwaysfold=0
scope ElectroShockAirTank initializer Init
globals
private constant integer ABILITY_ID = 'A023'
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 170.0
private constant real DAMAGE_INCREASE = 7.5 // percentage
private constant integer MAX_TARGETS = 5
private constant real AREA_BASE = 350.0
private constant real AREA_UP = 0.0
endglobals
private function Actions takes nothing returns nothing
local unit target = GetSpellTargetUnit()
local unit caster = GetTriggerUnit()
local unit random
local group g = NewGroup()
local integer i = 1
local integer lvl = GetUnitAbilityLevel(caster, ABILITY_ID)
local real dmg = DAMAGE_BASE + ( lvl * DAMAGE_UP )
local real area = AREA_BASE + ( lvl * AREA_UP )
set udg_Filter_Player = GetOwningPlayer(caster)
call GroupEnumUnitsInRange(g, GetUnitX(target), GetUnitY(target), area, FILTER_ENEMY_NONSTRUCTURE)
// first, pick MAX_TARGETS-1 units that are not the target from the group of units around the target and damage them
loop
set random = GroupPickRandomUnit(g)
if (random == null) or (i > (MAX_TARGETS - 1)) then
exitwhen true
else
if (random == target ) then
call GroupRemoveUnit(g,random)
else
call Lightning.CreateCU("AFOD", GetUnitX(caster), GetUnitY(caster), GetUnitFlyHeight(caster)+pGetTerrainZ(GetUnitX(caster), GetUnitY(caster)), random, true, 0.7)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl", random, "chest"))
call UnitDamageTarget(caster, random, dmg, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(g, random)
set i = i + 1
endif
endif
endloop
// now deal damage to the primary target and increase it, if the group above had less than MAX_TARGETS-1 units
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl",target,"chest"))
set dmg = dmg * (1.0 + (MAX_TARGETS-i)*(DAMAGE_INCREASE/100))
call Lightning.CreateCU("AFOD",GetUnitX(caster),GetUnitY(caster),GetUnitFlyHeight(caster)+pGetTerrainZ(GetUnitX(caster),GetUnitY(caster)),target,true,0.7)
call UnitDamageTarget(caster,target,dmg,true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
call ReleaseGroup(g)
set g = null
set target = null
set caster = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Roots initializer Init
globals
private constant integer ABILITY_ID = 'A03Y'
private constant integer ROOTED_GUARD_ID = 'H013'
constant integer ROOTS_RESISTANCE_ID = 'A0H1'
endglobals
function Trig_Roots_Conditions takes nothing returns boolean
return ( GetSpellAbilityId() == ABILITY_ID ) and (GetUnitState(GetTriggerUnit(), UNIT_STATE_LIFE) > 0)
endfunction
function Trig_Roots_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(U, ABILITY_ID)
if ( GetUnitTypeId(U) == ROOTED_GUARD_ID ) then
call SetUnitAbilityLevel(U, 'A0AV', level ) //Craft Of Nature (Heal)
call SetUnitAbilityLevel(U, 'A047', level ) //Craft Of Nature (Mana)
call UnitAddAbility(U, 'A04T' ) //Natural Healing
call SetUnitAbilityLevel(U, 'A04T', level )
call UnitAddAbility(U, ROOTS_RESISTANCE_ID ) //Magic Armor
call SetUnitAbilityLevel(U, ROOTS_RESISTANCE_ID, level )
endif
//Add Tank Cannon
if ( GetUnitAbilityLevel(U, 'A01J') != 0 ) then
call UnitAddAbility(U, 'A00W' )
call SetUnitAbilityLevel(U, 'A00W', GetUnitAbilityLevel(U, 'A01J') )
endif
//When rooted in a strategic location, add the extra regeneration and magic resistance
if IsUnitInStrategicLocation(U) then
call EnableStrategicLocationBuff(U, true)
endif
call ReactivateBlockingArmor(U)
call ApplyManaUpgrade(GetPlayerNr(GetOwningPlayer(U)))
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Roots = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Roots, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Roots, Condition( function Trig_Roots_Conditions ) )
call TriggerAddAction( gg_trg_Roots, function Trig_Roots_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope SummonTreants initializer Init
globals
private constant integer ABILITY_ID = 'A0CH'
private constant real DURATION_BASE = 10.0
private constant real DURATION_UP = 4.0
endglobals
private function Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(caster, ABILITY_ID)
local integer treantId = udg_Treant[level]
local real X = GetUnitX(caster)
local real Y = GetUnitY(caster)
local real duration = DURATION_BASE + ( level * DURATION_UP )
local unit Spawn
set Spawn = CreateUnit(GetOwningPlayer(caster), treantId, X, Y, 270)
call UnitApplyTimedLife( Spawn, 'BTLF', duration )
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[GetTargetMovePoint(Spawn)] )
set Spawn = CreateUnit(GetOwningPlayer(caster), treantId, X, Y, 270)
call UnitApplyTimedLife( Spawn, 'BTLF', duration )
call IssuePointOrderLoc( Spawn, "attack", udg_Move_Points[GetTargetMovePoint(Spawn)] )
set Spawn = null
set caster = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions )
endfunction
endscope
//TESH.scrollpos=24
//TESH.alwaysfold=0
scope NaturalEnergy initializer Init
globals
private constant integer ABILITY_ID = 'A0AM'
private constant integer ROOTED_GUARD_ID = 'H013'
private constant real HP_HEAL_BASE = 0.0
private constant real HP_HEAL_UP = 0.06
private constant real MANA_HEAL_BASE = 0.0
private constant real MANA_HEAL_UP = 0.04
private constant real AREA_BASE = 400.0
private constant real AREA_UP = 0.0
endglobals
function Trig_Natural_Energy_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit U
local integer level = GetUnitAbilityLevel(GetTriggerUnit(), ABILITY_ID)
local real hpHeal = HP_HEAL_BASE + ( level * HP_HEAL_UP )
local real manaHeal = MANA_HEAL_BASE + ( level * MANA_HEAL_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local real X = GetSpellTargetX()
local real Y = GetSpellTargetY()
local group Targets = NewGroup()
set udg_Filter_Player = GetOwningPlayer(Caster)
call GroupEnumUnitsInRange(Targets,X,Y,area,FILTER_ALLY_TANK)
loop
set U=FirstOfGroup(Targets)
exitwhen U==null
// Guard is normally excluded from the heal, except when he is rooted
if U != Caster or (U == Caster and GetUnitTypeId(Caster) == ROOTED_GUARD_ID) then
call SetUnitState( U, UNIT_STATE_LIFE, GetUnitState(U, UNIT_STATE_LIFE) + (GetUnitState(U, UNIT_STATE_MAX_LIFE) * hpHeal))
call SetUnitState( U, UNIT_STATE_MANA, GetUnitState(U, UNIT_STATE_MANA) + (GetUnitState(U, UNIT_STATE_MAX_MANA) * manaHeal))
call DestroyEffect(AddSpecialEffectTarget( "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl", U, "origin" ))
endif
call GroupRemoveUnit(Targets,U)
endloop
call ReleaseGroup(Targets)
set Targets = null
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Natural_Energy = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Natural_Energy, ABILITY_ID )
call TriggerAddAction( gg_trg_Natural_Energy, function Trig_Natural_Energy_Actions )
endfunction
endscope
//TESH.scrollpos=4
//TESH.alwaysfold=0
scope EntanglingRoots initializer Init
globals
private constant integer ABILITY_ID = 'A041'
private constant integer DAMAGE_ABILITY_ID = 'A040'
private constant integer ROOTED_GUARD_ID = 'H013'
private constant real DURATION_BASE = 1.5
private constant real DURATION_UP = 0.5
endglobals
function Trig_Entangling_Roots_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local real targetX = GetSpellTargetX()
local real targetY = GetSpellTargetY()
local real effectX
local real effectY
local real distance = 0.
local real angle = 0.
local integer level = GetUnitAbilityLevel(caster, ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
call ShowEffectAtPos("Abilities\\Spells\\NightElf\\EntanglingRoots\\EntanglingRootsTarget.mdl",targetX, targetY, 0, 3, duration)
call IssueImmediateOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(caster), DAMAGE_ABILITY_ID, level, targetX, targetY, 0 ), "stomp" )
loop
exitwhen angle >= 360.
loop
exitwhen distance >= 175.
set effectX = PolarProjX(targetX,distance,angle)
set effectY = PolarProjY(targetY,distance,angle)
call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",effectX,effectY))
set distance = distance + 50
endloop
set distance = 0.
set angle = angle + 30.
endloop
call GameTimeWait(0.0)
if (GetUnitTypeId(caster) == ROOTED_GUARD_ID) then
call SetUnitAnimation( caster, "attack alternate" )
endif
set caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Entangling_Roots = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Entangling_Roots, ABILITY_ID )
call TriggerAddAction( gg_trg_Entangling_Roots, function Trig_Entangling_Roots_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope SoulTransfer initializer Init
globals
private constant integer ABILITY_ID = 'A06X'
private constant integer SLOW_ABILITY_ID = 'A0AK'
private constant integer SLOW_BUFF_ID = 'B00H'
private constant real INTERVAL = 0.5
//the timer shouldn't be called more often than every 0.5 seconds, because
//the buff needs some time to be placed on the target unit and if the timer is too fast
//the trigger won't register the buff on the target
endglobals
function Trig_Soul_Transfer_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local unit Caster = udg_AV_Unit2[LoopTimerId]
if GetUnitState(Target, UNIT_STATE_LIFE) <= 0 then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
// instantly remove the slow from the target, when the skill is not channeled anymore
if ( GetUnitCurrentOrder(Caster) != String2OrderIdBJ("drain") or GetUnitState(Caster, UNIT_STATE_LIFE) <= 0) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call UnitRemoveAbility(Target, SLOW_BUFF_ID)
endif
endif
set Target = null
set Caster = null
endfunction
function Trig_Soul_Transfer_Actions takes nothing returns nothing
local timer t
local unit U = GetTriggerUnit()
local unit Target = GetSpellTargetUnit()
local integer LoopTimerId
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(U), SLOW_ABILITY_ID, 1, GetUnitX(Target), GetUnitY(Target), 0), "slow", Target)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Target
set udg_AV_Unit2[LoopTimerId] = U
call TimerStart(t, INTERVAL, true, function Trig_Soul_Transfer_Loop)
set U = null
set Target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Soul_Transfer = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Soul_Transfer, ABILITY_ID )
call TriggerAddAction( gg_trg_Soul_Transfer, function Trig_Soul_Transfer_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope SoulCollector initializer Init
globals
private constant integer ABILITY_ID = 'A06L'
private constant real HERO_HEAL_BASE = 0.0
private constant real HERO_HEAL_UP = 500.0
private constant real CREEP_HEAL_BASE = 0.0
private constant real CREEP_HEAL_UP = 15.0
private constant real AREA_BASE = 1000.0
private constant real AREA_UP = 0.0
endglobals
function Trig_Soul_Collector_Actions takes nothing returns nothing
local unit dying = GetTriggerUnit()
local integer i = 1
local integer lvl
local real DistX
local real DistY
local real Life
local real area
local boolean SoulCollected = false
// Aloc - locust ability
if (GetUnitAbilityLevel(dying,'Aloc') <= 0) and (not IsDummy(dying)) then
loop
exitwhen i > GetMaxHumanPlayers()
set lvl = GetUnitAbilityLevel( udg_Tank[i], ABILITY_ID )
if lvl != 0 then
set area = AREA_BASE + ( lvl * AREA_UP )
set Life = GetUnitState(udg_Tank[i], UNIT_STATE_LIFE)
if Life > 0 then
if (IsPlayerEnemy(GetOwningPlayer(udg_Tank[i]), GetOwningPlayer(dying) )) then
set DistX = GetUnitX(udg_Tank[i]) - GetUnitX(dying)
set DistY = GetUnitY(udg_Tank[i]) - GetUnitY(dying)
if DistX*DistX + DistY*DistY < area*area then
set SoulCollected = true
if ( IsUnitType(dying, UNIT_TYPE_HERO) == true ) then
call SetUnitState(udg_Tank[i], UNIT_STATE_LIFE, Life + (HERO_HEAL_BASE + ( lvl * HERO_HEAL_UP )) )
else
call SetUnitState(udg_Tank[i], UNIT_STATE_LIFE, Life + (CREEP_HEAL_BASE + ( lvl * CREEP_HEAL_UP )) )
endif
endif
endif
endif
endif
set i = i + 1
endloop
if SoulCollected then
call DestroyEffect( AddSpecialEffect("Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl", GetUnitX(dying), GetUnitY(dying)) )
endif
endif
set dying = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Soul_Collector = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Soul_Collector, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( gg_trg_Soul_Collector, function Trig_Soul_Collector_Actions )
endfunction
endscope
//TESH.scrollpos=44
//TESH.alwaysfold=0
scope SoulRestore initializer Init
globals
private constant integer ABILITY_ID = 'A093'
private constant integer HP_1_ABILITY_ID = 'A0EY'
private constant integer HP_2_ABILITY_ID = 'A0EZ'
private constant integer HP_3_ABILITY_ID = 'A0F0'
private constant integer HP_4_ABILITY_ID = 'A0F1'
private constant integer HP_5_ABILITY_ID = 'A0F2'
private constant integer HP_BUFF_ID = 'A0F3'
private constant real AREA_BASE = 600.0
private constant real AREA_UP = 0.0
endglobals
function Trig_Soul_Restore_HasHPBonus takes unit U returns integer
if (GetUnitAbilityLevel(U, HP_1_ABILITY_ID) > 0) then
return 1
elseif (GetUnitAbilityLevel(U, HP_2_ABILITY_ID) > 0) then
return 2
elseif (GetUnitAbilityLevel(U, HP_3_ABILITY_ID) > 0) then
return 3
elseif (GetUnitAbilityLevel(U, HP_4_ABILITY_ID) > 0) then
return 4
elseif (GetUnitAbilityLevel(U, HP_5_ABILITY_ID) > 0) then
return 5
endif
return 0
endfunction
function Trig_Soul_Restore_AddHPBonus takes unit U, integer lvl returns nothing
local integer id
//remove likely lower level hp ability
call UnitRemoveAbility(U, HP_1_ABILITY_ID)
call UnitRemoveAbility(U, HP_2_ABILITY_ID)
call UnitRemoveAbility(U, HP_3_ABILITY_ID)
call UnitRemoveAbility(U, HP_4_ABILITY_ID)
call UnitRemoveAbility(U, HP_5_ABILITY_ID)
call UnitRemoveAbility(U, HP_BUFF_ID)
if (lvl == 1) then
set id = HP_1_ABILITY_ID
elseif (lvl == 2) then
set id = HP_2_ABILITY_ID
elseif (lvl == 3) then
set id = HP_3_ABILITY_ID
elseif (lvl == 4) then
set id = HP_4_ABILITY_ID
elseif (lvl == 5) then
set id = HP_5_ABILITY_ID
endif
call UnitAddAbility(U, HP_BUFF_ID)
call UnitAddAbility(U, id)
endfunction
function Trig_Soul_Restore_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local unit Target
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local real area = AREA_BASE + ( lvl * AREA_UP )
local group G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(U)
call GroupEnumUnitsInRange(G, GetUnitX(U),GetUnitY(U), area, FILTER_ALLY_CREEP )
loop
set Target = FirstOfGroup(G)
exitwhen (Target == null)
if (Trig_Soul_Restore_HasHPBonus(Target) >= lvl) then
//do nothing
else
call Trig_Soul_Restore_AddHPBonus(Target, lvl)
endif
call GroupRemoveUnit(G, Target)
endloop
call ReleaseGroup(G)
set G = null
set U = null
set Target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Soul_Restore = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Soul_Restore, ABILITY_ID )
call TriggerAddAction( gg_trg_Soul_Restore, function Trig_Soul_Restore_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope HeavyArmor
globals
constant integer HEAVYARMOR_ABILITY_ID = 'A06R'
endglobals
endscope
// This id is used in the ArmorUtils trigger (found in the Libraries folder)
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope HailOfBombs initializer Init
globals
private constant integer ABILITY_ID = 'A0B6'
private constant integer DAMAGE_ABILITY_ID = 'A0B7'
private constant integer CLUSTER_COUNT_BASE = 5
private constant integer CLUSTER_COUNT_UP = 0
private constant real OFFSET_BASE = 400.0 // distance between each cluster (cluster aoe = 400)
private constant real OFFSET_UP = 0.0
endglobals
function Trig_Hail_of_Bombs_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local player owner = GetOwningPlayer(U)
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local integer i = 1
local integer count = CLUSTER_COUNT_BASE + ( lvl * CLUSTER_COUNT_UP )
local real offset = OFFSET_BASE + ( lvl * OFFSET_UP )
local real facerad = GetUnitFacing(U)*bj_DEGTORAD
local real Distance = 0
local real CasterX = GetUnitX(U)
local real CasterY = GetUnitY(U)
local real TargetX
local real TargetY
loop
exitwhen (i > count) or (GetUnitState(U, UNIT_STATE_LIFE) <= 0)
set TargetX = CasterX + Distance * Cos(facerad)
set TargetY = CasterY + Distance * Sin(facerad)
//GetUnitX is used here, to move with the tank
call IssuePointOrder( CreateDummyWithAbilityCoord(owner, DAMAGE_ABILITY_ID, lvl, GetUnitX(U), GetUnitY(U), 0), "clusterrockets", TargetX, TargetY )
set Distance = Distance + offset
set i = i + 1
call GameTimeWait(0.1)
endloop
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Hail_of_Bombs = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Hail_of_Bombs, ABILITY_ID )
call TriggerAddAction( gg_trg_Hail_of_Bombs, function Trig_Hail_of_Bombs_Actions )
endfunction
endscope
//TESH.scrollpos=12
//TESH.alwaysfold=0
scope SplashCannon initializer Init
globals
private constant integer ABILITY_ID = 'A0DN'
private constant integer CANNON_1_ID = 'W001' // those are not actual abilities
private constant integer CANNON_2_ID = 'W002' // they have been arbitrarily defined
private constant integer CANNON_3_ID = 'W003' // they are checked in the custom weapon system
private constant integer CANNON_4_ID = 'W004'
private constant integer CANNON_5_ID = 'W005'
boolean IgnoreSplashToggle = false
boolean array SplashIsActive[10]
endglobals
function Trig_Splash_Cannon_Conditions takes nothing returns boolean
return OrderId2String(GetIssuedOrderId()) == "defend" or OrderId2String(GetIssuedOrderId()) == "undefend"
endfunction
function Trig_Splash_Cannon_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(U, ABILITY_ID)
if (not IgnoreSplashToggle) and (level > 0) then
if ( OrderId2String(GetIssuedOrderId()) == "defend" ) then
if (level == 1) then
call AddWeaponTimed(U, CANNON_1_ID, 0)
elseif (level == 2) then
call AddWeaponTimed(U, CANNON_2_ID, 0)
elseif (level == 3) then
call AddWeaponTimed(U, CANNON_3_ID, 0)
elseif (level == 4) then
call AddWeaponTimed(U, CANNON_4_ID, 0)
elseif (level == 5) then
call AddWeaponTimed(U, CANNON_5_ID, 0)
endif
set SplashIsActive[GetPlayerNr(GetOwningPlayer(U))] = true
call DebugMsg("Splash: True (" + I2S(GetPlayerNr(GetOwningPlayer(U))) + ")")
elseif ( OrderId2String(GetIssuedOrderId()) == "undefend" ) then
call RemoveWeapon(U, CANNON_1_ID)
call RemoveWeapon(U, CANNON_2_ID)
call RemoveWeapon(U, CANNON_3_ID)
call RemoveWeapon(U, CANNON_4_ID)
call RemoveWeapon(U, CANNON_5_ID)
if (GetUnitState(U, UNIT_STATE_LIFE) > 0) then
set SplashIsActive[GetPlayerNr(GetOwningPlayer(U))] = false
call DebugMsg("Splash: False (" + I2S(GetPlayerNr(GetOwningPlayer(U))) + ")")
endif
endif
endif
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Splash_Cannon = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_Splash_Cannon, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition( gg_trg_Splash_Cannon, Condition( function Trig_Splash_Cannon_Conditions ) )
call TriggerAddAction( gg_trg_Splash_Cannon, function Trig_Splash_Cannon_Actions )
endfunction
endscope
//TESH.scrollpos=50
//TESH.alwaysfold=0
scope CannonModule initializer Init
globals
private constant integer ABILITY_ID = 'A0D8'
private constant integer MODULE_1_ID = 'W021' // those are not actual abilities
private constant integer MODULE_2_ID = 'W022' // they have been arbitrarily defined
private constant integer MODULE_3_ID = 'W023' // they are checked in the custom weapon system
private constant integer MODULE_4_ID = 'W024'
private constant integer MODULE_5_ID = 'W025'
private constant integer BUFF_ID = 'A0BR'
private constant real DURATION_BASE = 30.0
private constant real DURATION_UP = 0.0
private constant real CHECK_INTERVAL = 0.25
private boolean array RemoveBuff[10]
endglobals
function Trig_Cannon_Module_BuffCheck takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit target = udg_AV_Unit1[LoopTimerId]
local integer pId = GetPlayerNr(GetOwningPlayer(target))
local integer weaponId = udg_AV_Int1[LoopTimerId]
local real buffEnd = udg_AV_Real1[LoopTimerId]
if (RemoveBuff[pId]) then
// End the check, weapon already has been removed
set RemoveBuff[pId] = false
call DebugMsg("Ended module timer: rebuffed")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
if (buffEnd <= TimerGetElapsed(udg_GameTime)) or (GetUnitState(target, UNIT_STATE_LIFE) <= 0) then
call DebugMsg("Ended module timer: time")
call WeaponHolder[pId].RemoveWeaponById(weaponId)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
endif
set target = null
endfunction
function Trig_Cannon_Module_HasModule takes unit target returns integer
local integer level = 0
if HasWeapon(target, MODULE_1_ID) then
set level = 1
elseif HasWeapon(target, MODULE_2_ID) then
set level = 2
elseif HasWeapon(target, MODULE_3_ID) then
set level = 3
elseif HasWeapon(target, MODULE_4_ID) then
set level = 4
elseif HasWeapon(target, MODULE_5_ID) then
set level = 5
endif
return level
endfunction
function Trig_Cannon_Module_Actions takes nothing returns nothing
local unit source = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local integer targetId = GetPlayerNr(GetOwningPlayer(target))
local integer level = GetUnitAbilityLevel(source, ABILITY_ID)
local integer moduleLevel
local real duration = DURATION_BASE + ( level * DURATION_UP )
local timer t
local integer LoopTimerId
set moduleLevel = Trig_Cannon_Module_HasModule(target)
if (moduleLevel > 0) then
call DebugMsg("Removed module level " + I2S(moduleLevel))
call WeaponHolder[targetId].RemoveWeaponById('W020' + moduleLevel)
set RemoveBuff[targetId] = true
endif
call UpdateTank(target, targetId, WeaponHolder[targetId].AddWeaponById('W020' + level))
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(source), BUFF_ID, 1, GetUnitX(source), GetUnitY(source), 0), "slow", target)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Int1[LoopTimerId] = 'W020' + level
set udg_AV_Unit1[LoopTimerId] = target
set udg_AV_Real1[LoopTimerId] = TimerGetElapsed(udg_GameTime) + duration
call TimerStart(t , CHECK_INTERVAL, true, function Trig_Cannon_Module_BuffCheck)
set source = null
set target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Cannon_Module = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Cannon_Module, ABILITY_ID )
call TriggerAddAction( gg_trg_Cannon_Module, function Trig_Cannon_Module_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope FreezingMissile initializer Init
globals
private constant integer ABILITY_ID = 'A0DC'
private constant integer SLOW_ABILITY_ID = 'S002'
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 250.0
private constant real AREA_BASE = 500.0
private constant real AREA_UP = 0.0
private constant real SLOW_DURATION_BASE = 5.0
private constant real SLOW_DURATION_UP = 0.0
private constant real MISSILE_SPEED_BASE = 550.0
private constant real MISSILE_SPEED_UP = 0.0
private constant real SLOW_INTERVAL = 0.1
endglobals
function Trig_Freezing_Missile_UpdateAura takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local unit Aura = udg_AV_Unit2[LoopTimerId]
local integer level = udg_AV_Int2[LoopTimerId]
local real maxDuration = ( SLOW_DURATION_BASE + ( level * SLOW_DURATION_UP ) ) / SLOW_INTERVAL
if (udg_AV_Int1[LoopTimerId] < maxDuration) and (GetUnitState(Target, UNIT_STATE_LIFE) > 0) then
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
call SetUnitX(Aura, GetUnitX(Target))
call SetUnitY(Aura, GetUnitY(Target))
else
call ReleaseDummy(Aura)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Aura = null
set Target = null
endfunction
function Trig_Freezing_Missile_Destructor takes ProjectileMover pm returns nothing
call DestroyEffect(udg_AV_Effect1[pm.TimerIndex])
//call ReleaseDummy(pm.Projectile)
endfunction
function Trig_Freezing_Missile_Loop takes ProjectileMover pm returns boolean
local integer level = udg_AV_Int2[pm.TimerIndex]
local real TargetX = GetUnitX(pm.Target)
local real TargetY = GetUnitY(pm.Target)
local real damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local timer t
local integer RemoveTimerId
local boolean result = false
if ( GetUnitState(pm.Projectile , UNIT_STATE_LIFE) <= 0 ) or (pm.Target == null) then
set result = true
elseif (pm.DistanceToTarget <= pm.Speed) then
set udg_Filter_Player = GetOwningPlayer(pm.Projectile)
call FixedAreaDamageFromUnit(pm.Projectile, TargetX, TargetY, area, damage, 0.5, 0, false, FILTER_ENEMY_UNITS)
set t = NewTimer()
set RemoveTimerId = NewTimerIndex(t)
set udg_AV_Unit1[RemoveTimerId] = pm.Target
set udg_AV_Unit2[RemoveTimerId] = pm.Projectile
set udg_AV_Int1[RemoveTimerId] = 0
set udg_AV_Int2[RemoveTimerId] = level
call TimerStart(t , SLOW_INTERVAL , true , function Trig_Freezing_Missile_UpdateAura)
//The dummy that shows the big ice effect
call ShowEffectAtPos("Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl",TargetX, TargetY, 0, 3, 3)
set result = true
else
// Check if the target teleported away
if (DistanceBetweenPoints(udg_AV_Loc1[pm.TimerIndex], GetUnitLoc(pm.Target)) > 600 * PROJECTILE_MOVE_INTERVAL) then
call ReleaseDummy(pm.Projectile)
set result = true
else
call MoveLocation(udg_AV_Loc1[pm.TimerIndex], TargetX, TargetY)
endif
endif
return result
endfunction
function Trig_Freezing_Missile_Actions takes nothing returns nothing
local timer t
local integer ShootTimerId
local unit Source = GetTriggerUnit()
local unit Target = GetSpellTargetUnit()
local unit Projectile
local real face
local integer level = GetUnitAbilityLevel(Source, ABILITY_ID)
local effect fx
local ProjectileMover pm
local real Speed = MISSILE_SPEED_BASE + ( level * MISSILE_SPEED_UP )
set face = bj_RADTODEG * Atan2(GetUnitY(Target) - GetUnitY(Source), GetUnitX(Target) - GetUnitX(Source))
set Projectile = CreateDummyWithAbilityCoord(GetOwningPlayer(Source), SLOW_ABILITY_ID, level, GetUnitX(Source) , GetUnitY(Source), GetUnitFlyHeight(Source))
set fx = AddSpecialEffectTarget("Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl" , Projectile , "origin")
call SetUnitFacing(Projectile, face)
call SetUnitScale(Projectile, 2, 2, 2)
set pm = ProjectileMover.Create(Source, Projectile, Target, 0, 0)
call pm.Initialize(Speed, 0.25, ProjLooperFunction.Trig_Freezing_Missile_Loop, ProjDestructorFunction.Trig_Freezing_Missile_Destructor)
set udg_AV_Int2[pm.TimerIndex] = level
set udg_AV_Loc1[pm.TimerIndex] = GetUnitLoc(Target)
set udg_AV_Effect1[pm.TimerIndex] = fx
set Target = null
set Projectile = null
set Source = null
set fx = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Freezing_Missile = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Freezing_Missile, ABILITY_ID )
call TriggerAddAction( gg_trg_Freezing_Missile, function Trig_Freezing_Missile_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope BuildPortal initializer Init
globals
private constant integer ABILITY_ID = 'A0DD'
private constant integer PORTAL_ID = 'h020'
unit array Portal_Target[MAX_ARRAY_SIZE]
integer array Portal_Level[MAX_ARRAY_SIZE]
integer array Portal_IncomingUnits[MAX_ARRAY_SIZE]
boolean array Portal_DestroyOnFinish[MAX_ARRAY_SIZE]
boolean array Portal_IsActive[MAX_ARRAY_SIZE]
endglobals
function PortalsOwnedByCaster takes nothing returns boolean
if (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) <= 0) then
return false
endif
return (GetUnitTypeId(GetFilterUnit()) == PORTAL_ID) and (GetOwningPlayer(GetFilterUnit()) == GetOwningPlayer(GetTriggerUnit()))
endfunction
function Trig_Build_Portal_Conditions takes nothing returns boolean
local integer Id = GetUnitTypeId(GetConstructingStructure())
return Id == PORTAL_ID
endfunction
function Action_Portal_Build_Finish takes nothing returns nothing
local integer AttachmentId = GetHandleIndex(GetTriggerUnit())
call SetUnitVertexColor( GetTriggerUnit(), 255, 255, 255, 255 )
//call SetUnitAnimation(GetTriggerUnit(), "stand")
set Portal_IsActive[AttachmentId] = true
endfunction
function Trig_Build_Portal_Actions takes nothing returns nothing
local unit portal = GetConstructingStructure()
local unit source = udg_Tank[GetPlayerNr(GetOwningPlayer(portal))]
local unit oldPortal = null
local integer level = GetUnitAbilityLevel(source, ABILITY_ID)
local real GameTime = TimerGetElapsed(udg_GameTime)
local real creationTime = 0
local group G
local integer AttachmentId
//save the time, when the portal was build, to determine which portal is the oldest
call SetUnitUserData(portal, R2I(GameTime))
//attach some info to the unit
set AttachmentId = NewUnitIndex(portal)
set Portal_Level[AttachmentId] = level
set Portal_IncomingUnits[AttachmentId] = 0 //number of units currently being ported to this portal
set Portal_DestroyOnFinish[AttachmentId] = false //tells, whether it will be destroyed soon
//the following boolean determines, whether it is currently possible to use this portal or not
//it is set to false (no tp), when the portal is still building up and during it's cooldown
set Portal_IsActive[AttachmentId] = false
call SetUnitVertexColor( portal, 100, 100, 100, 255 )
//find the oldest portal and destroy it
set G = GetUnitsInRectMatchingSafe(udg_Playable_Map, Condition(function PortalsOwnedByCaster))
if CountUnitsInGroup(G) > 2 then
loop
exitwhen FirstOfGroup(G) == null
set portal = FirstOfGroup(G)
if (creationTime == 0) or (GetUnitUserData(portal) < creationTime) then
set creationTime = GetUnitUserData(portal)
set oldPortal = portal
endif
call GroupRemoveUnit(G, portal)
endloop
endif
call ReleaseGroup(G)
if (oldPortal != null) then
//check if units are currently porting to the old portal
if (Portal_IncomingUnits[GetHandleIndex(oldPortal)] > 0) then
//with this boolean set to true, this portal will be destroyed, when the last unit finished it's teleport (new ports are not allowed)
set Portal_DestroyOnFinish[GetHandleIndex(oldPortal)] = true
else
call KillUnit(oldPortal)
endif
endif
set G = GetUnitsInRectMatchingSafe(udg_Playable_Map, Condition(function PortalsOwnedByCaster))
//although killed, the old portal is still not dead yet -> remove it manually
call GroupRemoveUnit(G, oldPortal)
set portal = FirstOfGroup(G)
call GroupRemoveUnit(G, portal)
set oldPortal = FirstOfGroup(G)
call GroupRemoveUnit(G, oldPortal)
call ReleaseGroup(G)
//update the portal counterpart
if (udg_AV_Units[AttachmentId] == portal) then
set Portal_Target[AttachmentId] = oldPortal
set AttachmentId = GetHandleIndex(oldPortal)
set Portal_Target[AttachmentId] = portal
elseif (udg_AV_Units[AttachmentId] == oldPortal) then
set Portal_Target[AttachmentId] = portal
set AttachmentId = GetHandleIndex(portal)
set Portal_Target[AttachmentId] = oldPortal
endif
//play the active portal animation, when it's possible to teleport
//but yeah, doesn't work, whatever the reason
if (Portal_Target[GetHandleIndex(portal)] != null) then
//call SetUnitAnimation(portal, "stand alternate")
//call SetUnitAnimation(oldPortal, "stand alternate")
else
//call SetUnitAnimation(portal, "death")
endif
set source = null
set portal = null
set oldPortal = null
set G = null
//messy code, shame on me :(
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger BuildFinish = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(BuildFinish,EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddAction(BuildFinish, function Action_Portal_Build_Finish)
set gg_trg_Build_Portal = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Build_Portal, EVENT_PLAYER_UNIT_CONSTRUCT_START )
call TriggerAddCondition( gg_trg_Build_Portal, Condition( function Trig_Build_Portal_Conditions ) )
call TriggerAddAction( gg_trg_Build_Portal, function Trig_Build_Portal_Actions )
endfunction
endscope
//TESH.scrollpos=198
//TESH.alwaysfold=0
scope PortalTeleport initializer Init
globals
private constant integer ABILITY_ID = 'A0DC'
private constant integer PORTAL_ID = 'h020'
private constant integer STUN_ABILITY_ID = 'A06K'
private constant real STUN_DAMAGE_PERCENTAGE = 0.25 // this percentage is taken from the targets current life
private constant real COOLDOWN_BASE = 12.0
private constant real COOLDOWN_UP = -2.0
private constant real TRAVEL_SPEED_BASE = 1200.0
private constant real TRAVEL_SPEED_UP = 0.0
private constant real ACTIVATION_DISTANCE = 250.0
private constant real MOVE_INTERVAL = 0.05
private constant real CHECK_INTERVAL = 0.25
private constant real LOCATION_CHECK_INTERVAL = 0.5
endglobals
function Trig_Portal_Teleport_Conditions takes nothing returns boolean
local string order = (OrderId2String(GetUnitCurrentOrder(GetTriggerUnit())))
return (GetUnitTypeId(GetOrderTargetUnit()) == PORTAL_ID) and ((order == "smart") or (order == "move"))
endfunction
function Trig_Portal_Teleport_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local unit targetPortal = udg_AV_Unit2[LoopTimerId]
local unit dummy = udg_AV_Unit3[LoopTimerId]
local real DistX = GetUnitX(targetPortal)-GetUnitX(dummy)
local real DistY = GetUnitY(targetPortal)-GetUnitY(dummy)
local real DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
local integer level = Portal_Level[GetHandleIndex(targetPortal)]
local real travelSpeed = (TRAVEL_SPEED_BASE + ( level * TRAVEL_SPEED_UP )) * MOVE_INTERVAL
local boolean orderedToBeDestroyed = Portal_DestroyOnFinish[GetHandleIndex(targetPortal)]
//call DebugMsg("Port Loop: " + R2S(GetUnitX(dummy)))
if (GetUnitState(targetPortal, UNIT_STATE_LIFE) > 0) then
if DistanceLeft <= 150 then
//show the teleported unit again, set the destination and show the effect
set IgnoreSplashToggle = true
call PauseUnit(U, false)
call ShowUnit(U, true)
set IgnoreSplashToggle = false
if (GetLocalPlayer() == GetOwningPlayer(U)) then
call ClearSelection()
call SelectUnit(U, true)
endif
call SetUnitPosition(U, GetUnitX(dummy), GetUnitY(dummy))
call KillUnit(dummy)
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(U), GetUnitY(U) ) )
call DestroyEffect( udg_AV_Effect1[LoopTimerId] )
//update the information of the target portal and destroy it, if necessary
set Portal_IncomingUnits[GetHandleIndex(targetPortal)] = Portal_IncomingUnits[GetHandleIndex(targetPortal)] - 1 //number of units currently being ported to this portal
call DebugMsg("Units porting: " + I2S(Portal_IncomingUnits[GetHandleIndex(targetPortal)]))
// When there are no more units teleporting to this portal and the destroy order was given to this portal
// -> destroy the portal; otherwise wait until there are no more teleporting units
if (Portal_IncomingUnits[GetHandleIndex(targetPortal)] <= 0) and orderedToBeDestroyed then
call KillUnit(targetPortal)
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call ResetSplashCannon(U) //only for Architects
else
// Check if the current position is pathable, but only twice a second
// This is done, to find a safe fallback position, in case the target portal is destroyed and the traveling interrupted
if udg_AV_Int1[LoopTimerId] >= (LOCATION_CHECK_INTERVAL / MOVE_INTERVAL ) then
if GetPathableLoc(Location(GetUnitX(dummy), GetUnitY(dummy)), 32, 120) then
call MoveLocation(udg_AV_Loc1[LoopTimerId], GetUnitX(dummy), GetUnitY(dummy))
call DebugMsg("Position saved")
endif
set udg_AV_Int1[LoopTimerId] = 0
else
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
endif
//call DebugMsg("Level: " + I2S(udg_AV_Int1[GetHandleIndex(targetPortal)]))
//call SetUnitX(dummy, GetUnitX(dummy)+travelSpeed*DistX/DistanceLeft)
//call SetUnitY(dummy, GetUnitY(dummy)+travelSpeed*DistY/DistanceLeft)
call SetUnitPosition(dummy, GetUnitX(dummy)+travelSpeed*DistX/DistanceLeft, GetUnitY(dummy)+travelSpeed*DistY/DistanceLeft)
endif
else
call DebugMsg("Stop teleport")
//show the teleported unit again, set the destination and show the effect
if not GetPathableLoc(Location(GetUnitX(dummy), GetUnitY(dummy)), 32, 120) then
call SetUnitPositionLoc(U, udg_AV_Loc1[LoopTimerId])
else
call SetUnitPosition(U, GetUnitX(dummy), GetUnitY(dummy))
endif
set IgnoreSplashToggle = true
call PauseUnit(U, false)
call ShowUnit(U, true)
set IgnoreSplashToggle = false
if (GetLocalPlayer() == GetOwningPlayer(U)) then
call ClearSelection()
call SelectUnit(U, true)
endif
call KillUnit(dummy)
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(U), GetUnitY(U) ) )
call DestroyEffect( udg_AV_Effect1[LoopTimerId] )
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call ResetSplashCannon(U)
//Unit is forced out of the teleport and suffers the same effect as from the Teleport Breaker
set dummy = CreateDummyWithAbilityCoord(GetOwningPlayer(U), STUN_ABILITY_ID, 1, GetUnitX(U), GetUnitY(U), 0)
call IssueTargetOrder(dummy, "thunderbolt", U)
call UnitDamageTarget(dummy, U, GetUnitState(U, UNIT_STATE_LIFE)* STUN_DAMAGE_PERCENTAGE, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
endif
set U = null
set targetPortal = null
set dummy = null
endfunction
function Trig_Portal_Reactivate takes nothing returns nothing
local integer TimerId = GetHandleIndex(GetExpiredTimer())
local unit portal = udg_AV_Unit1[TimerId]
call SetUnitVertexColor( portal, 255, 255, 255, 255 )
//call SetUnitAnimation(GetTriggerUnit(), "stand")
set Portal_IsActive[GetHandleIndex(portal)] = true
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(TimerId)
set portal = null
endfunction
function Trig_Portal_Target_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local unit startPortal = udg_AV_Unit2[LoopTimerId]
local unit targetPortal
local unit dummy
local integer level = Portal_Level[GetHandleIndex(startPortal)]
local real cooldown = COOLDOWN_BASE + ( level * COOLDOWN_UP )
local string order = (OrderId2String(GetUnitCurrentOrder(U)))
local timer t
local integer LoopTimerTravelId
local boolean Splash = SplashIsActive[GetPlayerNr(GetOwningPlayer(U))]
if (GetUnitsDistance(U, startPortal) <= ACTIVATION_DISTANCE) and (GetUnitState(startPortal, UNIT_STATE_LIFE) > 0) and (not IsUnitPaused(U)) then
set targetPortal = Portal_Target[GetHandleIndex(startPortal)]
set Portal_IncomingUnits[GetHandleIndex(targetPortal)] = Portal_IncomingUnits[GetHandleIndex(targetPortal)] + 1 //number of units currently being ported to this portal
call DebugMsg("Set splash")
set SplashIsActive[GetPlayerNr(GetOwningPlayer(U))] = Splash
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(U), GetUnitY(U) ) )
set IgnoreSplashToggle = true
call PauseUnit(U, true)
call ShowUnit(U, false)
set IgnoreSplashToggle = false
set dummy = CreateUnit(GetOwningPlayer(U), DUMMY_ID, GetUnitX(U), GetUnitY(U), 270)
call SetUnitScale(dummy, 2, 2, 2)
call SetUnitFlyHeight(dummy, 50, 0)
//Timer that moves the unit to it's new destination
set t = NewTimer()
set LoopTimerTravelId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerTravelId] = U
set udg_AV_Unit2[LoopTimerTravelId] = targetPortal
set udg_AV_Unit3[LoopTimerTravelId] = dummy
set udg_AV_Int1[LoopTimerTravelId] = 0
set udg_AV_Loc1[LoopTimerTravelId] = Location(GetUnitX(U), GetUnitY(U))
set udg_AV_Effect1[LoopTimerTravelId] = AddSpecialEffectTarget("Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl", dummy, "origin")
call DebugMsg("post effect")
call TimerStart(t , MOVE_INTERVAL , true , function Trig_Portal_Teleport_Loop)
call DebugMsg("Cooldown: " + I2S(R2I(cooldown)) + " Level: " + I2S(level))
//Deactivate the portal for some time and the timer will reactivate it
call SetUnitVertexColor( startPortal, 100, 100, 100, 255 )
set Portal_IsActive[GetHandleIndex(startPortal)] = false
set t = NewTimer()
set LoopTimerTravelId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerTravelId] = startPortal
call TimerStart(t , cooldown , true , function Trig_Portal_Reactivate)
//Timer that triggered this function (none of the two started above)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
// When you are not yet near enough, you still need to target the portal to keep this trigger running
elseif (order != "smart") and (order != "move") or (GetUnitState(startPortal, UNIT_STATE_LIFE) <= 0) then
if IsUnitPaused(U) then
call DebugMsg("Skipped port")
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set U = null
set startPortal = null
set targetPortal = null
set dummy = null
endfunction
function Trig_Portal_Teleport_Actions takes nothing returns nothing
local timer t
local integer LoopTimerId
local unit U = GetTriggerUnit()
local unit Portal = GetOrderTargetUnit()
local unit theOtherPortal = Portal_Target[GetHandleIndex(Portal)]
local boolean destructionIssued = Portal_DestroyOnFinish[GetHandleIndex(theOtherPortal)]
local boolean isReady = Portal_IsActive[GetHandleIndex(Portal)]
local string msg = ""
if (IsUnitType(U, UNIT_TYPE_STRUCTURE)) then
set msg = "|cfffed312Buildings cannot be teleported.|r"
elseif (theOtherPortal == null) or (GetUnitState(theOtherPortal, UNIT_STATE_LIFE) <= 0) then
set msg = "|cfffed312The portal does not have a valid counterpart.|r"
// When the player issued the order to destroy the Portal, no more teleports are allowed
elseif (destructionIssued == true) then
set msg = "|cfffed312The portal will be destroyed shortly.|r"
elseif (isReady == false) then
set msg = "|cfffed312The portal takes some time to be ready.|r"
endif
if (msg != "") then
if GetLocalPlayer() == GetOwningPlayer(U) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, msg)
endif
else
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Unit2[LoopTimerId] = Portal
call TimerStart(t , CHECK_INTERVAL , true , function Trig_Portal_Target_Loop)
endif
set U = null
set Portal = null
set theOtherPortal = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Portal_Teleport = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Portal_Teleport, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerAddCondition( gg_trg_Portal_Teleport, Condition( function Trig_Portal_Teleport_Conditions ) )
call TriggerAddAction( gg_trg_Portal_Teleport, function Trig_Portal_Teleport_Actions )
endfunction
endscope
//TESH.scrollpos=30
//TESH.alwaysfold=0
struct PacifistaWeapons
static unit array Holder[10]
static method MoveItemsToHolder takes integer Id returns nothing
local integer i = 0
set Holder[Id] = CreateUnit(GetPlayer(Id), PACIFISTA_ITEMHOLDER_ID, 7000,-7500, 270)
loop
exitwhen i > 5
call UnitAddItem( Holder[Id], UnitItemInSlot(Pacifista[Id], i) )
set i = i + 1
endloop
//call PWeapons.ShowHolderItems(Id)
endmethod
static method ShowHolderItems takes integer Id returns nothing
local integer i = 0
call DebugMsg("Items for Holder " + I2S(Id))
loop
exitwhen i > 5
if (UnitItemInSlot(Holder[Id], i) != null) then
call DebugMsg(I2S(i+1) + ": " + GetItemName(UnitItemInSlot(Holder[Id], i)) )
endif
set i = i + 1
endloop
endmethod
static method MoveItemsToPacifista takes integer Id returns nothing
local integer i = 0
//call PWeapons.ShowHolderItems(Id)
loop
exitwhen i > 5
call UnitAddItem( Pacifista[Id], UnitItemInSlot(Holder[Id], i) )
set i = i + 1
endloop
call KillUnit(Holder[Id])
set Holder[Id] = null
endmethod
endstruct
scope BuildPacifista initializer Init
globals
private constant integer ABILITY_ID = 'A0DJ'
private constant real ACTIVE_RANGE = 1250.0
private constant real INTERVAL = 0.5
// these ones are used in the 'UnitBlowUpExplosives' function
constant integer PACIFISTA_INVENTORY_ID = 'A0DK'
constant real PACIFISTA_EXPLOSION_DAMAGE_BASE = 2250.0
constant real PACIFISTA_EXPLOSION_DAMAGE_UP = 750.0
constant integer PACIFISTA_RESISTANCE_ID = 'A03Q'
constant integer PACIFISTA_ITEMHOLDER_ID = 'h023'
PacifistaWeapons PWeapons
unit array Pacifista[10]
endglobals
function Action_Pacifista_Dies takes nothing returns nothing
if (GetDyingUnit() == Pacifista[GetPlayerNr(GetOwningPlayer(GetDyingUnit()))]) then
call PWeapons.MoveItemsToHolder(GetPlayerNr(GetOwningPlayer(GetDyingUnit())))
call UnitBlowUpExplosives(GetDyingUnit(), GetDyingUnit(), true)
endif
endfunction
function DropAndTakeItems takes unit U, integer level returns nothing
local integer i = 0
local item array TempItem
//All items have to be dropped and picked up again, for the changed inventory options to take effect
loop
exitwhen i > 5
set TempItem[i] = UnitItemInSlot(U, i)
if TempItem[i] != null then
call SetItemPosition( TempItem[i], 0, 0 )
endif
set i = i + 1
endloop
call SetUnitAbilityLevel(U, PACIFISTA_INVENTORY_ID, level)
set i = 0
loop
exitwhen i > 5
if TempItem[i] != null then
call UnitAddItem( U, TempItem[i] )
endif
set TempItem[i] = null
set i = i + 1
endloop
endfunction
//Disables the inventory of the Pacifista if it walks too far away from the Architect
function Trig_Build_Pacifista_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local unit Pacifista = udg_AV_Unit2[LoopTimerId]
local real Distance
local real DistX
local real DistY
if (GetUnitState(U, UNIT_STATE_LIFE) == 0) or (GetUnitState(Pacifista, UNIT_STATE_LIFE) == 0) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call KillUnit(Pacifista)
else
set DistX = GetUnitX(U)-GetUnitX(Pacifista)
set DistY = GetUnitY(U)-GetUnitY(Pacifista)
set Distance = SquareRoot(DistX*DistX+DistY*DistY)
if Distance > ACTIVE_RANGE then
//The inventory has 10 levels, the levels above 5 are the same as the 5 before, only that the items are disabled
if (GetUnitAbilityLevel(Pacifista, PACIFISTA_INVENTORY_ID) <= 5) then
//call ShowTextTag("|cff64ffffItems disabled|r", Pacifista, 0, 0, GetOwningPlayer(Pacifista))
call DropAndTakeItems(Pacifista, GetUnitAbilityLevel(Pacifista, PACIFISTA_INVENTORY_ID) + 5)
call SetUnitVertexColor( Pacifista, 100, 100, 255, 255 )
endif
else
//Pacifista is in range, activate his items again
if (GetUnitAbilityLevel(Pacifista, PACIFISTA_INVENTORY_ID) > 5) then
//call ShowTextTag("|cff64ffffItems enabled|r", Pacifista, 0, 0, GetOwningPlayer(Pacifista))
call DropAndTakeItems(Pacifista, GetUnitAbilityLevel(Pacifista, PACIFISTA_INVENTORY_ID) - 5)
call SetUnitVertexColor( Pacifista, 255, 255, 255, 255 )
endif
endif
endif
set U = null
set Pacifista = null
endfunction
function Trig_Build_Pacifista_Actions takes nothing returns nothing
local unit source = GetTriggerUnit()
local integer i = 0
local integer Id = GetPlayerNr(GetOwningPlayer(source))
local integer lvl = GetUnitAbilityLevel(source, ABILITY_ID)
local integer summonId
local timer t
local integer LoopTimerId
if (Pacifista[Id] == null) or GetUnitState(Pacifista[Id], UNIT_STATE_LIFE) <= 0 then
if lvl == 1 then
set summonId = 'z020'
elseif lvl == 2 then
set summonId = 'z021'
elseif lvl == 3 then
set summonId = 'z022'
elseif lvl == 4 then
set summonId = 'z023'
elseif lvl == 5 then
set summonId = 'z024'
endif
set Pacifista[Id] = CreateUnit(GetOwningPlayer(source), summonId, GetUnitX(source), GetUnitY(source), 270)
call SetUnitAbilityLevel(Pacifista[Id], PACIFISTA_INVENTORY_ID, lvl)
call SetPlayerAbilityAvailable(GetOwningPlayer(source), PACIFISTA_RESISTANCE_ID, false)
if (PWeapons.Holder[Id] != null) then
call PWeapons.MoveItemsToPacifista(Id)
endif
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = source
set udg_AV_Unit2[LoopTimerId] = Pacifista[Id]
call TimerStart(t, INTERVAL, true, function Trig_Build_Pacifista_Loop)
else
call SetUnitState(Pacifista[Id], UNIT_STATE_LIFE, GetUnitState(Pacifista[Id], UNIT_STATE_MAX_LIFE))
endif
set source = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger PacifistaDeath = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(PacifistaDeath,EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction(PacifistaDeath, function Action_Pacifista_Dies)
set gg_trg_Build_Pacifista = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Build_Pacifista, ABILITY_ID )
call TriggerAddAction( gg_trg_Build_Pacifista, function Trig_Build_Pacifista_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ThunderHammer initializer Init
globals
private constant integer ABILITY_ID = 'A01O'
endglobals
function Trig_Thunder_Hammer_Actions takes nothing returns nothing
local unit Target = GetSpellTargetUnit()
call DestroyTreesInRange(GetUnitX(Target),GetUnitY(Target),200)
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl", GetUnitX(Target), GetUnitY(Target)))
set Target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Thunder_Hammer = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Thunder_Hammer, ABILITY_ID )
call TriggerAddAction( gg_trg_Thunder_Hammer, function Trig_Thunder_Hammer_Actions )
endfunction
endscope
//TESH.scrollpos=26
//TESH.alwaysfold=0
scope ThunderHammerSpeed initializer Init
globals
private constant integer TANK_ID = 'H00I'
private constant integer SPEED_ABILITY_ID = 'A08E'
private constant integer SPEED_BUFF_ID = 'B01F'
private constant real MAX_FOLLOW_RANGE = 1250.0
private constant real INTERVAL = 0.5
//the timer shouldn't be called more often than every 0.5 seconds, because
//the buff needs some time to be placed on the target unit and if the timer is too fast
//the trigger won't register the buff on the target
endglobals
function Trig_Thunder_Hammer_Speed_Conditions takes nothing returns boolean
return ( GetUnitTypeId(GetTriggerUnit()) == TANK_ID ) and ( GetIssuedOrderIdBJ() == String2OrderIdBJ("thunderbolt") )
endfunction
function Trig_Thunder_Hammer_Speed_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Caster = udg_AV_Unit1[LoopTimerId]
local unit Target = udg_AV_Unit2[LoopTimerId]
local real DistanceLeft
local real DistX
local real DistY
if ( GetUnitCurrentOrder(Caster) != String2OrderIdBJ("thunderbolt") ) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
//Unit has Buff, but is not ordered to use Thunder Hammer anymore -> remove Buff
if GetUnitAbilityLevel(Caster, SPEED_BUFF_ID) > 0 then
call UnitRemoveAbility(Caster, SPEED_BUFF_ID)
endif
else
set DistX = GetUnitX(Target)-GetUnitX(Caster)
set DistY = GetUnitY(Target)-GetUnitY(Caster)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if ( DistanceLeft <= MAX_FOLLOW_RANGE ) and( GetUnitAbilityLevel(Caster, SPEED_BUFF_ID) <= 0 ) then
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), SPEED_ABILITY_ID, 1, GetUnitX(Caster), GetUnitY(Caster), 0), "bloodlust", Caster)
else
//Unit has Buff and is more than 1250 units away -> remove Buff
if DistanceLeft > MAX_FOLLOW_RANGE then
call UnitRemoveAbility(Caster, SPEED_BUFF_ID)
endif
endif
endif
set Caster = null
set Target = null
endfunction
function Trig_Thunder_Hammer_Speed_Actions takes nothing returns nothing
local timer t
local unit Caster = GetOrderedUnit()
local integer LoopTimerId
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Caster
set udg_AV_Unit2[LoopTimerId] = GetOrderTargetUnit()
call TimerStart(t, INTERVAL, true, function Trig_Thunder_Hammer_Speed_Loop)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Thunder_Hammer_Speed = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Thunder_Hammer_Speed, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerAddCondition( gg_trg_Thunder_Hammer_Speed, Condition( function Trig_Thunder_Hammer_Speed_Conditions ) )
call TriggerAddAction( gg_trg_Thunder_Hammer_Speed, function Trig_Thunder_Hammer_Speed_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Shockwave initializer Init
globals
private constant integer ABILITY_ID = 'A026'
private constant integer EFFECT_ID = 'A022'
private constant real DAMAGE_BASE = 930.0
private constant real DAMAGE_UP = 310.0
private constant real AREA_BASE = 750.0
private constant real AREA_UP = 0.0
endglobals
function Trig_Shockwave_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local integer i = 1
local location CasterLoc = GetUnitLoc(caster)
local location P
local unit dummy
local integer lvl = GetUnitAbilityLevel(caster, ABILITY_ID)
local real area = AREA_BASE + ( lvl * AREA_UP )
local real damage = DAMAGE_BASE + ( lvl * DAMAGE_UP )
loop
exitwhen i > 24
set P = PolarProjectionBJ(CasterLoc, 8.00, I2R(i*15))
call IssuePointOrder( CreateDummyWithAbility(GetOwningPlayer(caster), EFFECT_ID, 1, P, 0), "carrionswarm", GetLocationX(CasterLoc)+(GetLocationX(P)-GetLocationX(CasterLoc))*4, GetLocationY(CasterLoc)+(GetLocationY(P)-GetLocationY(CasterLoc))*4 )
call RemoveLocation( P )
set i = i + 1
endloop
call TriggerSleepAction( 0.10 )
set udg_Filter_Player = GetOwningPlayer(caster)
call FixedAreaDamageFromUnit(caster, GetUnitX(caster), GetUnitY(caster), area, damage, 1.0, 0, false, FILTER_ENEMY_UNITS)
call DestroyTreesInRange(GetLocationX(CasterLoc), GetLocationY(CasterLoc), area)
call RemoveLocation( CasterLoc )
set CasterLoc = null
set dummy = null
set P = null
set caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Shockwave = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Shockwave, ABILITY_ID )
call TriggerAddAction( gg_trg_Shockwave, function Trig_Shockwave_Actions )
endfunction
endscope
//TESH.scrollpos=12
//TESH.alwaysfold=0
scope Dustwave initializer Init
globals
private constant integer ABILITY_ID = 'A09Q'
private constant real RANGE_BASE = 500.0
private constant real RANGE_UP = 150.0
private constant real DURATION_BASE = 0.5
private constant real DURATION_UP = 0.15
private constant real INTERVAL = 0.1
endglobals
function Trig_Dustwave_EffectLoop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local integer level = udg_AV_Int2[LoopTimerId]
local real X
local real Y
local real DistanceLeft
local real DistX
local real DistY
local real range = RANGE_BASE + ( level * RANGE_UP )
local real duration = DURATION_BASE + ( level * DURATION_UP )
local real speed = range / duration * INTERVAL
call PauseUnit(udg_AV_Unit1[LoopTimerId], true)
set DistX = GetLocationX(udg_AV_Loc1[LoopTimerId])-GetUnitX(udg_AV_Unit1[LoopTimerId])
set DistY = GetLocationY(udg_AV_Loc1[LoopTimerId])-GetUnitY(udg_AV_Unit1[LoopTimerId])
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
set X = udg_AV_Real1[LoopTimerId]+(speed*udg_AV_Int1[LoopTimerId])*DistX/DistanceLeft
set Y = udg_AV_Real2[LoopTimerId]+(speed*udg_AV_Int1[LoopTimerId])*DistY/DistanceLeft
//set X = udg_AV_Real1[LoopTimerId]*(1-udg_AV_Int1[LoopTimerId]*0.1)+(GetLocationX(udg_AV_Loc1[LoopTimerId])*udg_AV_Int1[LoopTimerId]*0.1)
//set Y = udg_AV_Real2[LoopTimerId]*(1-udg_AV_Int1[LoopTimerId]*0.1)+(GetLocationY(udg_AV_Loc1[LoopTimerId])*udg_AV_Int1[LoopTimerId]*0.1)
call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl",X,Y))
call DestroyEffect(AddSpecialEffect("abilities\\weapons\\DemolisherMissile\\DemolisherMissile.mdl",X,Y))
call DestroyTreesInRange(X, Y, 100)
if GetUnitState(udg_AV_Unit1[LoopTimerId], UNIT_STATE_LIFE) <= 0 then
call PauseUnit(udg_AV_Unit1[LoopTimerId], false)
call MakeUnitInvulnerable(udg_AV_Unit1[LoopTimerId], false)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
if udg_AV_Int1[LoopTimerId] >= (duration / INTERVAL) then
call PauseUnit(udg_AV_Unit1[LoopTimerId], false)
call MakeUnitInvulnerable(udg_AV_Unit1[LoopTimerId], false)
call GetPathableLoc(udg_AV_Loc1[LoopTimerId],32,256)
call SetUnitPositionLoc(udg_AV_Unit1[LoopTimerId],udg_AV_Loc1[LoopTimerId])
call SetUnitAnimation(udg_AV_Unit1[LoopTimerId],"birth")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
endif
endfunction
function Trig_Dustwave_Actions takes nothing returns nothing
local location TargetLoc = GetSpellTargetLoc()
local unit Caster = GetTriggerUnit()
local real CasterX = GetUnitX(Caster)
local real CasterY = GetUnitY(Caster)
local real DistX = GetLocationX(TargetLoc)-CasterX
local real DistY = GetLocationY(TargetLoc)-CasterY
local real TargetDist = SquareRoot(DistX*DistX+DistY*DistY)
local integer level = GetUnitAbilityLevel(Caster, ABILITY_ID)
local real range = RANGE_BASE + ( level * RANGE_UP )
local timer t
local integer LoopTimerId
call MoveLocation(TargetLoc, CasterX+range/TargetDist*DistX,CasterY+range/TargetDist*DistY)
if not GetPathableLoc(TargetLoc,32,256) then
call IssueImmediateOrder( Caster, "stop" )
call SetUnitAnimation(Caster,"stand")
call SetUnitManaDelayed(Caster, GetUnitState(Caster, UNIT_STATE_MANA))
if GetLocalPlayer() == GetOwningPlayer(GetTriggerUnit()) then
call DisplayTextToPlayer(GetLocalPlayer(),0,0,"|cfffed312There is no space to move to the target point.|r" )
endif
call RemoveLocation(TargetLoc)
set TargetLoc = null
set Caster = null
return
endif
call MoveLocation(TargetLoc, CasterX+range/TargetDist*DistX,CasterY+range/TargetDist*DistY)
call MakeUnitInvulnerable(Caster, true)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Real1[LoopTimerId] = GetUnitX(Caster)
set udg_AV_Real2[LoopTimerId] = GetUnitY(Caster)
set udg_AV_Unit1[LoopTimerId] = Caster
set udg_AV_Loc1[LoopTimerId] = TargetLoc
set udg_AV_Int1[LoopTimerId] = 0
set udg_AV_Int2[LoopTimerId] = level
call TimerStart(t,INTERVAL,true, function Trig_Dustwave_EffectLoop)
set TargetLoc = null
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Dustwave = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Dustwave, ABILITY_ID )
call TriggerAddAction( gg_trg_Dustwave, function Trig_Dustwave_Actions )
endfunction
endscope
//TESH.scrollpos=34
//TESH.alwaysfold=0
scope GraniticDefense initializer Init
globals
private constant integer ABILITY_ID = 'A09S'
private constant integer BUFF_ID = 'B019'
private constant real DURATION_BASE = 5.0
private constant real DURATION_UP = 0.0
private constant real DAMAGE_REDUCTION_BASE = 0.0 // in percent
private constant real DAMAGE_REDUCTION_UP = 0.12
private constant real INTERVAL = 0.01
private integer DD_ID
endglobals
function Trig_Granitic_Defense_DamageDetection takes nothing returns real
local integer level = GetUnitAbilityLevel(DamageDetection_DamageTarget, ABILITY_ID)
if GetUnitAbilityLevel(DamageDetection_DamageTarget, BUFF_ID) > 0 then
// the damage system interprets postive values as additional damage and negative ones as reduced damage
return -(DAMAGE_REDUCTION_BASE + ( level * DAMAGE_REDUCTION_UP ))
endif
return 0.0
endfunction
function Trig_Granitic_Defense_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local integer current_Loop = udg_AV_Int1[LoopTimerId]
local integer max_Loop = udg_AV_Int2[LoopTimerId]
local real current_HP = GetUnitState(udg_AV_Unit1[LoopTimerId], UNIT_STATE_LIFE)
local real last_HP = udg_AV_Real1[LoopTimerId]
if (current_Loop >= max_Loop) or (current_HP <= 0)then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
if (current_HP > last_HP) then
call SetUnitState(udg_AV_Unit1[LoopTimerId], UNIT_STATE_LIFE, last_HP)
endif
set udg_AV_Real1[LoopTimerId] = GetUnitState(udg_AV_Unit1[LoopTimerId], UNIT_STATE_LIFE)
endif
endfunction
function Trig_Granitic_Defense_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local timer t
local integer LoopTimerId
local integer level = GetUnitAbilityLevel(Caster, ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
// Start a timer, that checks the tanks HP, which prevents the tank from gaining any HP
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Real1[LoopTimerId] = GetUnitState(Caster, UNIT_STATE_LIFE)
set udg_AV_Unit1[LoopTimerId] = Caster
set udg_AV_Int1[LoopTimerId] = 0
set udg_AV_Int2[LoopTimerId] = R2I(duration / INTERVAL)
call TimerStart(t,INTERVAL,true, function Trig_Granitic_Defense_Loop)
// Enable the damage reduction
call EnableSkillDamageDetection(DD_ID)
call GameTimeWait( duration )
call DisableSkillDamageDetection(DD_ID)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Granitic_Defense = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodeRelative(DamageAlterationFunction.Trig_Granitic_Defense_DamageDetection)
call TriggerRegisterSpellEffectEvent( gg_trg_Granitic_Defense, ABILITY_ID )
call TriggerAddAction( gg_trg_Granitic_Defense, function Trig_Granitic_Defense_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TransparentArmor
globals
constant integer TRANSPARENT_ARMOR_ABILITY_ID = 'A091'
endglobals
endscope
// Used in the 'RefreshTransparency function in the General Mapwide functions library
//TESH.scrollpos=6
//TESH.alwaysfold=0
scope Earthquake initializer Init
globals
private constant integer ABILITY_ID = 'A09R'
private constant real DAMAGE_BASE = 1500.0
private constant real DAMAGE_UP = 500.0
private constant real AREA_BASE = 500.0
private constant real AREA_UP = 0.0
private constant real DURATION_BASE = 3.0
private constant real DURATION_UP = 0.0
private constant real INTERVAL = 0.5
endglobals
function Trig_Earthquake_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit U
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real t = TimerGetElapsed(udg_GameTime)
local real area = AREA_BASE + ( level * AREA_UP )
local real duration = DURATION_BASE + ( level * DURATION_UP )
local real Damage = (DAMAGE_BASE + ( level * DAMAGE_UP )) / ( duration / INTERVAL )
local real EffectAngle
local real EffectDist
local boolean b = false
call DestroyTreesInRange(TargetX, TargetY, area)
loop
exitwhen OrderId2String(GetUnitCurrentOrder(Caster))!="earthquake"
set udg_Filter_Player = GetOwningPlayer(Caster)
call FixedAreaDamageFromUnit(Caster, TargetX, TargetY, area, Damage, 1.0, 0, false, FILTER_ENEMY_GROUND_UNIT)
set EffectAngle = GetRandomReal(0,360)
set EffectDist = SquareRoot(GetRandomReal(0,1))*450
call DestroyEffect(AddSpecialEffect("war3mapImported\\ImpaleTargetDust2.mdl", TargetX + EffectDist*Cos(EffectAngle*bj_DEGTORAD), TargetY + EffectDist*Sin(EffectAngle*bj_DEGTORAD)))
set EffectAngle = GetRandomReal(0,360)
set EffectDist = SquareRoot(GetRandomReal(0,1))*350
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\EarthQuake\\EarthQuakeTarget.mdl", TargetX + EffectDist*Cos(EffectAngle*bj_DEGTORAD), TargetY + EffectDist*Sin(EffectAngle*bj_DEGTORAD)))
set t = t + INTERVAL
call WaitForGameTime(t)
endloop
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Earthquake = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Earthquake, ABILITY_ID )
call TriggerAddAction( gg_trg_Earthquake, function Trig_Earthquake_Actions )
endfunction
endscope
//TESH.scrollpos=9
//TESH.alwaysfold=0
scope OrbOfDarkness initializer Init
globals
private constant integer ABILITY_ID = 'A0G3'
private constant integer STUN_ABILITY_ID = 'A0G4'
private constant integer ORB_ID = 'n00X'
private constant real SPEED_BASE = 450.0
private constant real SPEED_UP = 0.0
private constant real AREA_BASE = 450.0
private constant real AREA_UP = 0.0
private constant real BASE_DAMAGE_BASE = 0.0
private constant real BASE_DAMAGE_UP = 150.0
private constant real DAMAGE_BONUS_BASE = 4.00
private constant real DAMAGE_BONUS_UP = 0.0
endglobals
function Trig_Orb_of_Darkness_Destructor takes ProjectileMover pm returns nothing
if (GetUnitState(pm.Projectile, UNIT_STATE_LIFE) > 0) then
call KillUnit(pm.Projectile)
endif
endfunction
function Trig_Orb_of_Darkness_Loop takes ProjectileMover pm returns boolean
local integer level = udg_AV_Int2[pm.TimerIndex]
local real current_HP = GetUnitState(pm.Projectile, UNIT_STATE_LIFE)
local real area = AREA_BASE + (level * AREA_UP)
local real baseDamage = BASE_DAMAGE_BASE + (level * BASE_DAMAGE_UP)
local real bonusDamage = 1 + (DAMAGE_BONUS_BASE + (level * DAMAGE_BONUS_UP)) * (1 - (current_HP / GetUnitState(pm.Projectile, UNIT_STATE_MAX_LIFE)) )
local integer stunLevel = Round((1 - (current_HP / GetUnitState(pm.Projectile, UNIT_STATE_MAX_LIFE))) * 4 + 1)
local real ProjX = GetUnitX(pm.Projectile)
local real ProjY = GetUnitY(pm.Projectile)
local boolean result = false
if (current_HP <= 0) or (pm.DistanceToTarget <= pm.Speed) then
set udg_Filter_Player = GetOwningPlayer(pm.Source)
call FixedAreaDamageFromUnit(pm.Source, ProjX, ProjY, area, baseDamage*bonusDamage, 0.5, 0, true, FILTER_ENEMY_UNITS)
call ShowEffectAtPos("war3mapImported\\NewAirEX.mdx",ProjX, ProjY, 100, 3, 3)
call IssueImmediateOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(pm.Source), STUN_ABILITY_ID, stunLevel, ProjX, ProjY, 0), "stomp")
set result = true
endif
return result
endfunction
function Trig_Orb_of_Darkness_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit Projectile
local ProjectileMover pm
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local integer level = GetUnitAbilityLevel(Caster, ABILITY_ID)
local real speed = SPEED_BASE + (level * SPEED_UP)
set Projectile = CreateUnit(GetOwningPlayer(Caster), ORB_ID, GetUnitX(Caster), GetUnitY(Caster), GetUnitFacing(Caster))
set pm = ProjectileMover.Create(Caster, Projectile, null, TargetX, TargetY)
call pm.Initialize(speed, 0.0, ProjLooperFunction.Trig_Orb_of_Darkness_Loop, ProjDestructorFunction.Trig_Orb_of_Darkness_Destructor)
set udg_AV_Int2[pm.TimerIndex] = level
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Orb_of_Darkness = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Orb_of_Darkness, ABILITY_ID )
call TriggerAddAction( gg_trg_Orb_of_Darkness, function Trig_Orb_of_Darkness_Actions )
endfunction
endscope
//TESH.scrollpos=18
//TESH.alwaysfold=0
scope Conservation initializer Init
globals
private constant integer ABILITY_ID = 'A0BI'
private constant integer BUFF_ABILITY_ID = 'A0G2'
private constant real DURATION_BASE = 2.0
private constant real DURATION_UP = 1.0
private constant real AREA_BASE = 300.0
private constant real AREA_UP = 0.0
private constant real DAMAGE_BASE = 0.02 // Damage in percentage of max HP per second
private constant real DAMAGE_UP = 0.0
private constant real INTERVAL = 0.01
endglobals
function Trig_Conservation_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local integer current_Loop = udg_AV_Int1[LoopTimerId]
local integer max_Loop = udg_AV_Int2[LoopTimerId]
local integer level = udg_AV_Int3[LoopTimerId]
local unit Target = udg_AV_Unit1[LoopTimerId]
local unit Caster = udg_AV_Unit2[LoopTimerId]
local real current_HP = GetUnitState(Target, UNIT_STATE_LIFE)
local real last_HP = udg_AV_Real1[LoopTimerId]
local real damage = GetUnitState(Target, UNIT_STATE_MAX_LIFE) * (DAMAGE_BASE + (level * DAMAGE_UP)) * INTERVAL
if (current_Loop >= max_Loop) or (current_HP <= 0)then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
if (current_HP > last_HP) then
call SetUnitState(Target, UNIT_STATE_LIFE, RMaxBJ(last_HP, 1.0))
endif
if (GetUnitState(Target, UNIT_STATE_LIFE) <= 2*damage) then
call UnitDamageTarget(Caster, Target, 10*damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
else
call SetUnitState(Target, UNIT_STATE_LIFE, GetUnitState(Target, UNIT_STATE_LIFE) - damage)
endif
set udg_AV_Real1[LoopTimerId] = GetUnitState(Target, UNIT_STATE_LIFE)
endif
endfunction
function Trig_Conservation_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit Target
local timer t
local integer LoopTimerId
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local integer level = GetUnitAbilityLevel(Caster, ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
local real area = AREA_BASE + (level * AREA_UP)
local group G = NewGroup()
call DestroyEffect(AddSpecialEffect("war3mapImported\\DarkLightningNova.mdl", TargetX, TargetY))
set udg_Filter_Player = GetOwningPlayer(Caster)
call GroupEnumUnitsInRange(G, TargetX, TargetY, area, FILTER_ENEMY_TANK)
loop
set Target = FirstOfGroup(G)
exitwhen (Target == null)
call AddAbilityTimed(Target, BUFF_ABILITY_ID, level, duration)
// Start a timer, that checks the tanks HP, which prevents the tank from gaining any HP
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Real1[LoopTimerId] = GetUnitState(Target, UNIT_STATE_LIFE)
set udg_AV_Unit1[LoopTimerId] = Target
set udg_AV_Unit2[LoopTimerId] = Caster
set udg_AV_Int1[LoopTimerId] = 0
set udg_AV_Int2[LoopTimerId] = R2I(duration / INTERVAL)
set udg_AV_Int3[LoopTimerId] = level
call TimerStart(t,INTERVAL,true, function Trig_Conservation_Loop)
call GroupRemoveUnit(G, Target)
endloop
call ReleaseGroup(G)
set G = null
set Caster = null
set Target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Conservation = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Conservation, ABILITY_ID )
call TriggerAddAction( gg_trg_Conservation, function Trig_Conservation_Actions )
endfunction
endscope
//TESH.scrollpos=27
//TESH.alwaysfold=0
scope EnergyLeak initializer Init
globals
private constant integer ABILITY_ID = 'A0G5'
private constant integer BUFF_ID = 'B031'
private constant real COOLDOWN_BASE = 2.0
private constant real COOLDOWN_UP = 0.0
private constant real MANA_BURN_BASE = 5.0
private constant real MANA_BURN_UP = 5.0
private constant real BURN_DAMAGE_BASE = 0.0
private constant real BURN_DAMAGE_UP = 4.0
private constant real SEARCH_AREA = 1100.0 // just needs to be about 50 units bigger than the actual aura area, it's just used to search for the tank with the aura
private boolean array BurnIsActive[10]
endglobals
function Trig_Energy_Leak_Conditions takes nothing returns boolean
return (GetUnitAbilityLevel(GetTriggerUnit(), BUFF_ID) > 0)
endfunction
function Trig_Energy_Leak_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local unit Burner = null
local unit temp
local integer level
local real manaBurn
local real damage
local real cooldown
local group G
set manaBurn = GetUnitState(Caster, UNIT_STATE_MANA)
call GameTimeWait(0.5)
set manaBurn = manaBurn - GetUnitState(Caster, UNIT_STATE_MANA)
call DebugMsg("Used Mana: " + I2S(R2I(manaBurn)))
if (manaBurn > 0) then
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(Caster)
call GroupEnumUnitsInRange(G, GetUnitX(Caster), GetUnitY(Caster), SEARCH_AREA, FILTER_ENEMY_TANK)
loop
set temp = FirstOfGroup(G)
exitwhen ((temp == null) or (Burner != null))
set level = GetUnitAbilityLevel(temp, ABILITY_ID)
if ((level > 0) and BurnIsActive[GetPlayerNr(GetOwningPlayer(temp))]) then
set Burner = temp
endif
call GroupRemoveUnit(G, temp)
endloop
call ReleaseGroup(G)
if (Burner != null) then
set manaBurn = MANA_BURN_BASE + ( level * MANA_BURN_UP )
if (manaBurn > GetUnitState(Caster, UNIT_STATE_MANA)) then
set manaBurn = GetUnitState(Caster, UNIT_STATE_MANA)
endif
set damage = manaBurn * ( BURN_DAMAGE_BASE + ( level * BURN_DAMAGE_UP ) )
call SetUnitState(Caster, UNIT_STATE_MANA, GetUnitState(Caster, UNIT_STATE_MANA) - manaBurn)
call UnitDamageTarget(Burner, Caster, damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call Lightning.CreateUU("MBUR", Burner, Caster, true, false, 1.0)
set cooldown = COOLDOWN_BASE + ( level * COOLDOWN_UP )
set BurnIsActive[GetPlayerNr(GetOwningPlayer(temp))] = false
call GameTimeWait(cooldown)
set BurnIsActive[GetPlayerNr(GetOwningPlayer(temp))] = true
endif
endif
set Caster = null
set Burner = null
set temp = null
set G = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local integer i = 1
loop
set BurnIsActive[i] = true
set i = i + 1
exitwhen (i > 10)
endloop
set gg_trg_Energy_Leak = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Energy_Leak, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Energy_Leak, Condition( function Trig_Energy_Leak_Conditions ) )
call TriggerAddAction( gg_trg_Energy_Leak, function Trig_Energy_Leak_Actions )
endfunction
endscope
//TESH.scrollpos=93
//TESH.alwaysfold=0
scope DarknesSphere initializer Init
globals
private constant integer ABILITY_ID = 'A0G1'
private constant integer ENEMY_SLOW_ID = 'A0G8'
private constant integer ALLY_SLOW_ID = 'A0G7'
private constant real DURATION_BASE = 4.5
private constant real DURATION_UP = 1.5
private constant real AREA_BASE = 700.0
private constant real AREA_UP = 0.0
constant integer VISION_ABILITY_ID = 'A0G6'
constant real DARKNESS_SPHERE_TIMESTEP = 0.1
endglobals
struct DarknessSphere
unit Caster
real x
real y
real radius
real timeleft
fogmodifier array playerInsideVision [10]
boolean array playerInside [10]
method SetPlayerIn takes integer id, boolean inside returns nothing
local integer i
local integer team = udg_Player_Team[id]
set playerInside[id] = inside
if inside then
set udg_Fog_PlayerInDarkness[id] = udg_Fog_PlayerInDarkness[id] + 1
set playerInsideVision[id] = CreateFogModifierRadius(GetPlayer(id),FOG_OF_WAR_VISIBLE, x, y, radius, true, false)
call FogModifierStart(playerInsideVision[id])
if (GetUnitAbilityLevel(udg_Tank[id], VISION_ABILITY_ID) <= 0) then
call UnitAddAbility(udg_Tank[id], VISION_ABILITY_ID)
endif
else
set udg_Fog_PlayerInDarkness[id] = udg_Fog_PlayerInDarkness[id] - 1
call DestroyFogModifier(playerInsideVision[id])
set playerInsideVision[id] = null
if (GetUnitAbilityLevel(udg_Tank[id], VISION_ABILITY_ID) > 0) then
call UnitRemoveAbility(udg_Tank[id], VISION_ABILITY_ID)
endif
endif
set i = (team - 1) * 5 + 1
loop
exitwhen (i > (team*5))
if (i != id) then
call SetPlayerAlliance( GetPlayer(id), GetPlayer(i), ALLIANCE_SHARED_VISION, not inside)
call SetPlayerAlliance( GetPlayer(i), GetPlayer(id), ALLIANCE_SHARED_VISION, not inside)
endif
set i = i + 1
endloop
call SetPlayerAlliance( udg_Force[team], GetPlayer(id), ALLIANCE_SHARED_VISION, not inside)
call SetPlayerAlliance( GetPlayer(id), udg_Force[team], ALLIANCE_SHARED_VISION, not inside)
endmethod
method Refresh takes nothing returns nothing
local integer i = 1
local real dx
local real dy
local boolean inside
local boolean changed = false
local boolean expired = (timeleft<=0.0)
loop
exitwhen i>GetMaxHumanPlayers()
set inside = false
if (not expired) and (udg_Tank[i]!=null) and (GetUnitState(udg_Tank[i],UNIT_STATE_LIFE)>0.0) then
set dx = x-GetUnitX(udg_Tank[i])
set dy = y-GetUnitY(udg_Tank[i])
set inside = (dx*dx+dy*dy<radius*radius)
endif
if (inside!=playerInside[i]) and IsUnitEnemy(this.Caster, GetPlayer(i)) then
set changed = true
call SetPlayerIn(i,inside)
endif
set i = i + 1
endloop
if changed then
call TriggerExecute(gg_trg_Fog_Modifier)
endif
endmethod
static method Loop takes nothing returns nothing
// Timer callback
local timer t = GetExpiredTimer()
local integer tindex = GetHandleIndex(t)
local DarknessSphere ds = udg_AV_Int1[tindex]
local boolean expired = (ds.timeleft<=0.0)
local integer i = 0
local integer count = 3
local real part = 360/count
local real angle = udg_AV_Real1[tindex]
local real range = udg_AV_Real2[tindex]
call ds.Refresh()
if expired then
call ReleaseHandleIndex(tindex)
call ReleaseTimer(t)
//call SetBlight(GetOwningPlayer(ds.Caster), ds.x, ds.y, ds.radius, false)
set ds.Caster = null
call ds.destroy()
else
if (ModuloInteger(udg_AV_Int3[tindex], 1) == 0) then
loop
exitwhen i >= count
call DestroyEffect(AddSpecialEffect("Doodads\\Cinematic\\GlowingRunes\\GlowingRunes7.mdl",ds.x + range * Cos((i*(part)-angle) * bj_DEGTORAD),ds.y + range * Sin((i*(part)-angle) * bj_DEGTORAD)))
call DestroyEffect(AddSpecialEffect("Doodads\\Cinematic\\GlowingRunes\\GlowingRunes7.mdl",ds.x + ds.radius * Cos((i*(part)+angle) * bj_DEGTORAD),ds.y + ds.radius * Sin((i*(part)+angle) * bj_DEGTORAD)))
set i = i + 1
endloop
set udg_AV_Real1[tindex] = udg_AV_Real1[tindex] + (360 / udg_AV_Int2[tindex])
set udg_AV_Real2[tindex] = udg_AV_Real2[tindex] - (2*ds.radius / udg_AV_Int2[tindex])
// deal 0 damage, to trigger the assist detection
set udg_Filter_Player = GetOwningPlayer(ds.Caster)
call AreaSpellDamageFromUnit(ds.Caster, ds.x, ds.y, ds.radius, 0, 1.0, 0, FILTER_ENEMY_TANK )
endif
set udg_AV_Int3[tindex] = udg_AV_Int3[tindex] + 1
set ds.timeleft = ds.timeleft-DARKNESS_SPHERE_TIMESTEP
endif
endmethod
static method Create takes unit Caster, real posx, real posy, real range, real duration returns DarknessSphere
local DarknessSphere ds = DarknessSphere.allocate()
local unit dummy
local integer i = 1
local timer t = NewTimer()
local integer tindex = NewTimerIndex(t)
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local integer count = R2I(range / 50.0)
local real angle = 360 / count
loop
exitwhen i>GetMaxHumanPlayers()
set ds.playerInside[i] = false
set ds.playerInsideVision[i] = null
set i = i + 1
endloop
call ShowEffectAtPos("war3mapImported\\BlackCloudOfFog.mdx", posx, posy, 100, 3, duration)
//call SetBlight(GetOwningPlayer(Caster), posx, posy, range, true)
//The following code is a workaround for the bugged cloud skill
//for some reason, this skill ignores which team the caster belongs to
//and always slows down units of the Light Force
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(Caster))] == 1 then
//Dark Force - normal skill, slows enemies
set dummy = CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), ENEMY_SLOW_ID, level, posx, posy, 0)
else
//Light Force - weird skill, slows allies
//but since the skill somehow believes it belongs to the dark force -> slowed enemies
set dummy = CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), ALLY_SLOW_ID, level, posx, posy, 0)
endif
call IssuePointOrder( dummy, "cloudoffog", posx, posy )
set dummy = null
set ds.Caster = Caster
set ds.x = posx
set ds.y = posy
set ds.radius = range
set ds.timeleft = duration
call ds.Refresh()
set udg_AV_Int1[tindex] = ds
set udg_AV_Int2[tindex] = R2I(duration / (DARKNESS_SPHERE_TIMESTEP * 1))
set udg_AV_Int3[tindex] = 0
set udg_AV_Real1[tindex] = 0
set udg_AV_Real2[tindex] = range
call TimerStart(t, DARKNESS_SPHERE_TIMESTEP, true, function DarknessSphere.Loop)
return ds
endmethod
endstruct
function Trig_Darkness_Sphere_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local real area = AREA_BASE + (level * AREA_UP)
local real duration = DURATION_BASE + (level * DURATION_UP)
call DarknessSphere.Create(Caster, TargetX, TargetY, area, duration)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Darkness_Sphere = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Darkness_Sphere, ABILITY_ID )
call TriggerAddAction( gg_trg_Darkness_Sphere, function Trig_Darkness_Sphere_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope MissileBattery initializer Init
globals
private constant integer ABILITY_ID = 'A0GB'
private constant integer DAMAGE_ABILITY_ID = 'A0GA'
private constant real DURATION_BASE = 2.0
private constant real DURATION_UP = 0.0
endglobals
function Trig_Missile_Battey_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(Caster, ABILITY_ID)
local real duration = DURATION_BASE + (level * DURATION_UP)
call AddAbilityTimed(Caster, DAMAGE_ABILITY_ID, level, duration)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Missile_Battey = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Missile_Battey, ABILITY_ID )
call TriggerAddAction( gg_trg_Missile_Battey, function Trig_Missile_Battey_Actions )
endfunction
endscope
//TESH.scrollpos=1
//TESH.alwaysfold=0
scope ThunderQuake initializer Init
globals
private constant integer ABILITY_ID = 'A0C0'
private constant real QUAKE_SPEED_BASE = 200.0
private constant real QUAKE_SPEED_UP = 0.0
private constant real DURATION_BASE = 3.0
private constant real DURATION_UP = 0.0
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 400.0
private constant real AREA_BASE = 350.0
private constant real AREA_UP = 0.0
private constant real ENEMY_SEARCH_DISTANCE = 1000.0
private constant real INTERVAL = 0.5
endglobals
function Trig_Lightning_Quake_TargetEffect takes unit source, location targetLoc, integer level returns nothing
local real area = AREA_BASE + ( level * AREA_UP )
local real duration = DURATION_BASE + ( level * DURATION_UP )
local real damage = (DAMAGE_BASE + ( level * DAMAGE_UP )) / (duration / INTERVAL)
local real x
local real y
local integer i = 1
loop
exitwhen i > 3
set x = GetRandomInt(-R2I(area/2), R2I(area/2)) + GetLocationX(targetLoc)
set y = GetRandomInt(-R2I(area/2), R2I(area/2)) + GetLocationY(targetLoc)
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl", x, y))
set i = i + 1
endloop
set udg_Filter_Player = GetOwningPlayer(source)
call FixedAreaDamageFromUnit(source, GetLocationX(targetLoc), GetLocationY(targetLoc), area, damage, 1.0, 0, false, FILTER_ENEMY_GROUND_UNIT)
endfunction
function Trig_Lightning_Quake_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit target
local integer level = udg_AV_Int1[LoopTimerId]
local real locX = GetLocationX(udg_AV_Loc1[LoopTimerId])
local real locY = GetLocationY(udg_AV_Loc1[LoopTimerId])
local real duration = DURATION_BASE + ( level * DURATION_UP )
local real speed = ( QUAKE_SPEED_BASE + ( level * QUAKE_SPEED_UP ) ) * INTERVAL
local real DistanceLeft
local real DistX
local real DistY
local group G
if (udg_AV_Int2[LoopTimerId] >= (duration / INTERVAL)) then
call KillUnit(udg_AV_Unit1[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(udg_AV_Unit1[LoopTimerId])
call GroupEnumUnitsInRange(G, locX, locY, ENEMY_SEARCH_DISTANCE, FILTER_ENEMY_GROUND_UNIT )
set target = GetClosestUnitFromGroup(G, locX, locY)
call ReleaseGroup(G)
if (target != null) then
set DistX = GetUnitX(target)-locX
set DistY = GetUnitY(target)-locY
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if DistanceLeft <= speed then
call MoveLocation(udg_AV_Loc1[LoopTimerId], GetUnitX(target), GetUnitY(target))
else
call MoveLocation(udg_AV_Loc1[LoopTimerId], locX+speed*DistX/DistanceLeft, locY+speed*DistY/DistanceLeft)
endif
call Trig_Lightning_Quake_TargetEffect(udg_AV_Unit1[LoopTimerId], udg_AV_Loc1[LoopTimerId], level)
endif
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
endif
set target = null
set G = null
endfunction
function Trig_Lightning_Quake_Actions takes nothing returns nothing
local timer t
local integer LoopTimerId
local integer level = GetUnitAbilityLevel(GetTriggerUnit(),ABILITY_ID)
local unit dummy = CreateUnit(GetOwningPlayer(GetTriggerUnit()),DUMMY_ID, 0.0, 0.0 ,0.0)
local location targetLoc = GetSpellTargetLoc()
call Trig_Lightning_Quake_TargetEffect(dummy, targetLoc, level)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = dummy // only needed as a damage source
set udg_AV_Loc1[LoopTimerId] = targetLoc
set udg_AV_Int1[LoopTimerId] = level
set udg_AV_Int2[LoopTimerId] = 1
call TimerStart(t, INTERVAL, true, function Trig_Lightning_Quake_Loop)
set dummy = null
set targetLoc = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Lightning_Quake = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Lightning_Quake, ABILITY_ID )
call TriggerAddAction( gg_trg_Lightning_Quake, function Trig_Lightning_Quake_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope EnergyBomb initializer Init
globals
private constant integer ABILITY_ID = 'A049'
private constant integer DUMMY_ABILITY_ID = 'A02U'
private constant real DAMAGE_BASE = 960.0
private constant real DAMAGE_UP = 320.0
private constant real AREA_BASE = 300.0
private constant real AREA_UP = 0.0
endglobals
function Trig_Energy_Bomb_Actions takes nothing returns nothing
local location TargetLoc = GetUnitLoc(GetSpellTargetUnit())
local location P
local unit caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(caster,ABILITY_ID)
local real damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local integer i = 1
loop
exitwhen i > 9
set P = PolarProjectionBJ(TargetLoc, 220.00, I2R(i*40))
call IssuePointOrderLoc( CreateDummyWithAbility(GetOwningPlayer(caster), DUMMY_ABILITY_ID, 1, P, 0), "carrionswarm", TargetLoc )
call RemoveLocation( P )
set i = i + 1
endloop
call TriggerSleepAction( 0 )
call DestroyEffect(AddSpecialEffectLoc("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",TargetLoc))
set udg_Filter_Player = GetOwningPlayer(caster)
call FixedAreaDamageFromUnit(caster, GetLocationX(TargetLoc), GetLocationY(TargetLoc), area, damage, 1.0, 0, false, FILTER_ENEMY_UNITS)
call DestroyTreesInRange(GetLocationX(TargetLoc), GetLocationY(TargetLoc), area)
call RemoveLocation( TargetLoc )
set TargetLoc = null
set P = null
set caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Energy_Bomb = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Energy_Bomb, ABILITY_ID )
call TriggerAddAction( gg_trg_Energy_Bomb, function Trig_Energy_Bomb_Actions )
endfunction
endscope
//TESH.scrollpos=2
//TESH.alwaysfold=0
scope MainGun initializer Init
globals
private constant integer ABILITY_ID = 'A0AG'
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 500.0
private constant real AREA_BASE = 400.0
private constant real AREA_UP = 0.0
private constant real MAX_RANGE_BASE = 2000.0
private constant real MAX_RANGE_UP = 0.0
private constant real MIN_DAMAGE_PERCENT = 0.25
private constant real DELAY = 0.66
// The delay is tied to the base ability, it's the approximate time the projectile needs to hit the choosen target
// The actual distance the projetile travels does not seem to influence this time
endglobals
function Trig_Main_Gun_Impact takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer TimerIndex = GetHandleIndex(t)
local integer level = udg_AV_Int1[TimerIndex]
local real damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local real MaxRange = MAX_RANGE_BASE + ( level * MAX_RANGE_UP )
local real Range = udg_AV_Real1[TimerIndex]
local real X = udg_AV_Real2[TimerIndex]
local real Y = udg_AV_Real3[TimerIndex]
set damage = (MIN_DAMAGE_PERCENT + (1-MIN_DAMAGE_PERCENT) * (Range / MaxRange) ) * damage
set udg_Filter_Player = GetOwningPlayer(udg_AV_Unit1[TimerIndex])
call AreaSpellDamageFromUnit(udg_AV_Unit1[TimerIndex], X, Y, area, damage, 0.5, 0, FILTER_ENEMY_UNITS )
call DestroyEffect(AddSpecialEffect( "Abilities\\Spells\\Other\\Volcano\\VolcanoDeath.mdl", X, Y) )
call DestroyEffect(AddSpecialEffect( "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", X, Y ))
call CreateExplosionSizedTimed(GetOwningPlayer(udg_AV_Unit1[TimerIndex]),X,Y,1.6,0.35)
call DestroyTreesInRange(X, Y, area)
call ReleaseHandleIndex(TimerIndex)
call ReleaseTimer(t)
endfunction
function Trig_Main_Gun_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local timer t = NewTimer()
local integer TimerIndex = NewTimerIndex(t)
local real CasterX = GetUnitX(Caster)
local real CasterY = GetUnitY(Caster)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local real dist = SquareRoot(Pow(CasterX-TargetX,2)+Pow(CasterY-TargetY,2))
set udg_AV_Int1[TimerIndex] = GetUnitAbilityLevel(Caster,ABILITY_ID)
set udg_AV_Real1[TimerIndex] = dist
set udg_AV_Real2[TimerIndex] = TargetX
set udg_AV_Real3[TimerIndex] = TargetY
set udg_AV_Unit1[TimerIndex] = Caster
call TimerStart(t, DELAY, false, function Trig_Main_Gun_Impact)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Main_Gun = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Main_Gun, ABILITY_ID )
call TriggerAddAction( gg_trg_Main_Gun, function Trig_Main_Gun_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope AcidCloud initializer Init
globals
private constant integer ABILITY_ID = 'A0A0'
private constant integer ENEMY_SLOW_ID = 'A08U'
private constant integer ALLY_SLOW_ID = 'A0AQ'
private constant integer DAMAGE_ID = 'A053'
endglobals
function Trig_Acid_Cloud_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local unit dummy
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local player owner = GetOwningPlayer(U)
local integer ownerId = GetPlayerNr(owner)
//The following code is a workaround for the bugged cloud skill
//for some reason, this skill ignores which team the caster belongs to
//and always slows down units of the Light Force
if udg_Player_Team[ownerId] == 1 then
//Dark Force - normal skill, slows enemies
set dummy = CreateDummyWithAbilityCoord(owner, ENEMY_SLOW_ID, lvl, TargetX, TargetY, 0)
else
//Light Force - weird skill, slows allies
//but since the skill somehow believes it belongs to the dark force -> slowed enemies
set dummy = CreateDummyWithAbilityCoord(owner, ALLY_SLOW_ID, lvl, TargetX, TargetY, 0)
endif
call IssuePointOrder( dummy, "cloudoffog", TargetX, TargetY )
set dummy = CreateDummyWithAbilityCoord(owner, DAMAGE_ID, lvl, TargetX, TargetY, 0)
call IssuePointOrder( dummy, "deathanddecay", TargetX, TargetY )
set U = null
set dummy = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Acid_Cloud = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Acid_Cloud, ABILITY_ID )
call TriggerAddAction( gg_trg_Acid_Cloud, function Trig_Acid_Cloud_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope GravityGrenade initializer Init
globals
private constant integer ABILITY_ID = 'A0AI'
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 500.0
private constant real AREA_BASE = 500.0
private constant real AREA_UP = 0.0
private constant real DURATION_BASE = 1.5
private constant real DURATION_UP = 0.5
private constant real SPEED_BASE = 40.0
private constant real SPEED_UP = 0.0
private constant real INTERVAL = 0.05
endglobals
function Trig_Gravity_Granade_Loop_IsMovable takes unit U returns boolean
if (GetUnitState(U, UNIT_STATE_LIFE) <= 0) or (GetUnitAbilityLevel(U, 'Avul') > 0) then
return false
endif
if not IsUnitType(U, UNIT_TYPE_HERO) then
return false
endif
if GetUnitTypeId(U) == 'H013' then
//rooted Guard
return false
endif
if GetUnitTypeId(U) == 'H01H' then
//Pilot
return false
endif
if IsDummy(U) then
return false
endif
return true
endfunction
function Trig_Gravity_Grenade_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit EnumUnit
local real TargetX = udg_AV_Real1[LoopTimerId]
local real TargetY = udg_AV_Real2[LoopTimerId]
local group G
local integer lvl = udg_AV_Int1[LoopTimerId]
local real area = AREA_BASE + ( lvl * AREA_UP )
local real duration = ( DURATION_BASE + ( lvl * DURATION_UP ) ) / INTERVAL
local real speed = ( SPEED_BASE + ( lvl * SPEED_UP ) ) * INTERVAL
local real DistX
local real DistY
local real AngleRad
local real DistanceLeft
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
if udg_AV_Int2[LoopTimerId] > duration then
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set G = NewGroup()
call GroupEnumUnitsInRange(G, TargetX,TargetY, area, null )
loop
set EnumUnit = FirstOfGroup(G)
exitwhen EnumUnit==null
if Trig_Gravity_Granade_Loop_IsMovable(EnumUnit) then
set DistX = TargetX-GetUnitX(EnumUnit)
set DistY = TargetY-GetUnitY(EnumUnit)
set AngleRad = Atan2(DistY, DistX)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if DistanceLeft >= 100 then
call SetUnitPosition(EnumUnit,GetUnitX(EnumUnit)+speed*Cos(AngleRad),GetUnitY(EnumUnit)+speed*Sin(AngleRad))
else
//To prevent the units from freely using any abilities / teleports
call IssueImmediateOrder(EnumUnit, "stop")
endif
endif
call GroupRemoveUnit(G, EnumUnit)
endloop
call ReleaseGroup(G)
set G = null
endif
set EnumUnit = null
endfunction
function Trig_Gravity_Grenade_Actions takes nothing returns nothing
local timer t
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local unit U = GetTriggerUnit()
local integer TimerIndex
local integer lvl = GetUnitAbilityLevel(U,ABILITY_ID)
local real area = AREA_BASE + ( lvl * AREA_UP )
call GameTimeWait(0.8)
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeTarget.mdl", TargetX, TargetY))
call DestroyEffect(AddSpecialEffect("Units\\NightElf\\Wisp\\WispExplode.mdl", TargetX, TargetY))
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[TimerIndex] = lvl
set udg_AV_Int2[TimerIndex] = 1
set udg_AV_Real1[TimerIndex] = TargetX
set udg_AV_Real2[TimerIndex] = TargetY
set udg_AV_Effect1[TimerIndex] = AddSpecialEffect("Doodads\\Cinematic\\EyeOfSargeras\\EyeOfSargeras.mdl", TargetX, TargetY)
call TimerStart(t, INTERVAL, true, function Trig_Gravity_Grenade_Loop)
call DestroyTreesInRange(TargetX, TargetY, area)
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Gravity_Grenade = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Gravity_Grenade, ABILITY_ID )
call TriggerAddAction( gg_trg_Gravity_Grenade, function Trig_Gravity_Grenade_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope GravityGrenadeDummyCast initializer Init
globals
private constant integer ABILITY_ID = 'A094'
private constant integer DUMMY_ABILITY_ID = 'A0AI'
endglobals
function Trig_Gravity_Grenade_Dummy_Cast_Actions takes nothing returns nothing
local unit U = GetSpellAbilityUnit()
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
call IssuePointOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(U), DUMMY_ABILITY_ID, lvl, GetUnitX(U), GetUnitY(U), 0), "clusterrockets", TargetX, TargetY )
set U = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Gravity_Grenade_Dummy_Cast = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Gravity_Grenade_Dummy_Cast, ABILITY_ID )
call TriggerAddAction( gg_trg_Gravity_Grenade_Dummy_Cast, function Trig_Gravity_Grenade_Dummy_Cast_Actions )
endfunction
endscope
//TESH.scrollpos=3
//TESH.alwaysfold=0
scope Banish initializer Init
globals
private constant integer ABILITY_ID = 'A0B3'
private constant integer BUFF_ID = 'B01K'
private constant real DURATION_BASE = 1.0
private constant real DURATION_UP = 1.0
private constant real DAMAGE_BONUS_BASE = 0.25 // in percent
private constant real DAMAGE_BONUS_UP = 0.0
private integer DD_ID
endglobals
function Trig_Banish_DamageDetection takes nothing returns real
local integer level = GetUnitAbilityLevel(DamageDetection_DamageTarget,BUFF_ID)
if level > 0 then
return DAMAGE_BONUS_BASE + ( level * DAMAGE_BONUS_UP )
endif
return 0.0
endfunction
function Trig_Banish_End takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer TimerIndex = GetHandleIndex(t)
call DisableSkillDamageDetection(DD_ID)
call RefreshTransparency( udg_AV_Unit1[TimerIndex] )
call ReleaseHandleIndex(TimerIndex)
call ReleaseTimer(t)
endfunction
function Trig_Banish_Actions takes nothing returns nothing
local integer level = GetUnitAbilityLevel(GetTriggerUnit(),ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
local timer t = NewTimer()
// this should trigger the assist detection and grant an assist, even when you didn't do any damage otherwise
call UnitDamageTarget(GetTriggerUnit(), GetSpellTargetUnit(), 0, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call EnableSkillDamageDetection(DD_ID)
call SetUnitVertexColor( GetSpellTargetUnit(), 255, 255, 255, 90 )
set udg_AV_Unit1[NewTimerIndex(t)] = GetSpellTargetUnit()
call TimerStart(t, duration+0.01, false, function Trig_Banish_End)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Banish = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodeRelative(DamageAlterationFunction.Trig_Banish_DamageDetection)
call TriggerRegisterSpellEffectEvent( gg_trg_Banish, ABILITY_ID )
call TriggerAddAction( gg_trg_Banish, function Trig_Banish_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DemonFire initializer Init
globals
private constant integer ABILITY_ID = 'A04G'
private constant integer DEMON_FIRE_ID = 'A0E3'
private constant integer BANISH_ID = 'A0B3'
private constant integer LAVA_SHOT_ID = 'A01D'
private constant integer HELL_FIRE_ID = 'A02H'
private constant real AREA_BASE = 500.0 // area should match the one of Hell Fire
private constant real AREA_UP = 0.0
private constant real DELAY = 0.5
endglobals
function Trig_Demon_Fire_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local unit Target = GetSpellTargetUnit()
local integer level = GetUnitAbilityLevel(U, ABILITY_ID)
local real area = AREA_BASE + ( level * AREA_UP )
local group G
//Banish
if (GetSpellAbilityId() == BANISH_ID) then
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(U), DEMON_FIRE_ID, level, GetUnitX(Target), GetUnitY(Target), 0), "acidbomb", Target)
//Lava Shot
elseif (GetSpellAbilityId() == LAVA_SHOT_ID) then
//The dummy is positioned next to the Demon Tank, so the Demon Fire hits the target the same moment, the Lava Shot hits (or both wont hit in case of a teleport)
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(U), DEMON_FIRE_ID, level, GetUnitX(U), GetUnitY(U), 0), "acidbomb", Target)
//Hell Fire
elseif (GetSpellAbilityId() == HELL_FIRE_ID) then
call GameTimeWait(DELAY)
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(U)
call GroupEnumUnitsInRange(G, GetUnitX(U),GetUnitY(U), area, FILTER_ENEMY_UNITS)
loop
set Target = FirstOfGroup(G)
exitwhen Target == null
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(U), DEMON_FIRE_ID, level, GetUnitX(Target), GetUnitY(Target), 0), "acidbomb", Target)
call GroupRemoveUnit(G, Target)
endloop
call ReleaseGroup(G)
set G = null
endif
set U = null
set Target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Demon_Fire = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Demon_Fire, BANISH_ID )
call TriggerRegisterSpellEffectEvent( gg_trg_Demon_Fire, HELL_FIRE_ID )
call TriggerRegisterSpellEffectEvent( gg_trg_Demon_Fire, LAVA_SHOT_ID )
call TriggerAddAction( gg_trg_Demon_Fire, function Trig_Demon_Fire_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope HellFire initializer Init
globals
private constant integer ABILITY_ID = 'A02H'
private constant real DAMAGE_BASE = 1050.0
private constant real DAMAGE_UP = 350.0
private constant real AREA_BASE = 600.0
private constant real AREA_UP = 0.0
private constant real PULL_AREA_BASE = 750.0
private constant real PULL_AREA_UP = 0.0
private constant real PULL_SPEED_BASE = 500.0
private constant real PULL_SPEED_UP = 0.0
private constant real DELAY = 0.5
private constant real INTERVAL = 0.05
endglobals
function Trig_Hell_Fire_Loop_IsMovable takes unit U returns boolean
if (GetUnitState(U, UNIT_STATE_LIFE) <= 0) or (GetUnitAbilityLevel(U, 'Avul') > 0) then
return false
endif
if IsUnitAlly(U, GetPlayer(udg_TempInt)) then
return false
endif
if (GetUnitTypeId(U) == 'H013') or (GetUnitTypeId(U) == 'H01H') then
//rooted Guard, Pilot
return false
endif
if IsDummy(U) or IsWard(U) or IsMine(U) then
return false
endif
if (IsUnitType(U, UNIT_TYPE_STRUCTURE)) then
return false
endif
return true
endfunction
function Trig_Hell_Fire_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit EnumUnit
local unit Caster = udg_AV_Unit1[LoopTimerId]
local unit Dummy = udg_AV_Unit2[LoopTimerId]
local group G
local integer lvl = udg_AV_Int1[LoopTimerId]
local real DistX
local real DistY
local real AngleRad
local real DistanceLeft
local real Force = ( PULL_SPEED_BASE + ( lvl * PULL_SPEED_UP ) ) * INTERVAL
local integer duration = R2I(DELAY / INTERVAL)
local integer range = R2I(PULL_AREA_BASE + ( lvl * PULL_AREA_UP ))
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
if ((udg_AV_Int2[LoopTimerId] > duration) or (GetUnitState(Caster, UNIT_STATE_LIFE) <= 0)) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set G = NewGroup()
set udg_TempInt = GetPlayerNr(GetOwningPlayer(Caster))
call GroupEnumUnitsInRange(G, GetUnitX(Caster),GetUnitY(Caster), range, null )
loop
set EnumUnit = FirstOfGroup(G)
exitwhen EnumUnit==null
if Trig_Hell_Fire_Loop_IsMovable(EnumUnit) then
set DistX = GetUnitX(Caster)-GetUnitX(EnumUnit)
set DistY = GetUnitY(Caster)-GetUnitY(EnumUnit)
set AngleRad = Atan2(DistY, DistX)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if DistanceLeft >= 150 then
// Check if it's even possible to move the unit to the new location, to prevent it to pull them up cliffs etc.
if IsUnitType(EnumUnit, UNIT_TYPE_FLYING) or IsTerrainWalkable(GetUnitX(EnumUnit) + Force*Cos(AngleRad), GetUnitY(EnumUnit) + Force*Sin(AngleRad)) then
call SetUnitX(EnumUnit, GetUnitX(EnumUnit) + Force*Cos(AngleRad))
call SetUnitY(EnumUnit, GetUnitY(EnumUnit) + Force*Sin(AngleRad))
endif
endif
endif
call GroupRemoveUnit(G, EnumUnit)
endloop
call ReleaseGroup(G)
set G = null
endif
set Caster = null
set Dummy = null
set EnumUnit = null
endfunction
function Trig_Hell_Fire_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(caster,ABILITY_ID)
local real damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local real X = GetUnitX(caster)
local real Y = GetUnitY(caster)
local integer effectCount = 12
local real angle = 360 / effectCount
local effect array effects
local timer t
local integer TimerIndex
local integer i = 1
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeTarget.mdl", X, Y))
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Int1[TimerIndex] = GetUnitAbilityLevel(caster,ABILITY_ID)
set udg_AV_Int2[TimerIndex] = 1
set udg_AV_Unit1[TimerIndex] = caster
call TimerStart(t, INTERVAL, true, function Trig_Hell_Fire_Loop)
loop
exitwhen i > effectCount
set effects[i] = AddSpecialEffect("Doodads\\Cinematic\\TownBurningFireEmitter\\TownBurningFireEmitter.mdl",X + area/2 * Cos(i*angle * bj_DEGTORAD),Y + area/2 * Sin(i*angle * bj_DEGTORAD))
set i = i + 1
endloop
call GameTimeWait( DELAY )
set i = 1
loop
exitwhen i > effectCount
call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",X + area/2 * Cos(i*angle * bj_DEGTORAD), Y + area/2 * Sin(i*angle * bj_DEGTORAD)))
call DestroyEffect(effects[i])
set effects[i] = null
set i = i + 1
endloop
call DestroyTreesInRange(X, Y, area)
set udg_Filter_Player = GetOwningPlayer(caster)
//call FixedAreaDamageFromUnit(caster, X, Y, area, damage, 1.0, 0, false, FILTER_ENEMY_UNITS)
call AreaSpellDamageFromUnit(caster, X, Y, area, damage, 1.0, 0, FILTER_ENEMY_UNITS )
set caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Hell_Fire = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Hell_Fire, ABILITY_ID )
call TriggerAddAction( gg_trg_Hell_Fire, function Trig_Hell_Fire_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope IcePrison initializer Init
globals
private constant integer ABILITY_ID = 'A0E0'
private constant integer STUN_ABILITY_ID = 'A02Y'
private constant integer SLOW_ABILITY_ID = 'A0DE'
private constant real SPEED_BASE = 1300.0
private constant real SPEED_UP = 0.0
endglobals
function Trig_Ice_Prison_Destructor takes ProjectileMover pm returns nothing
call DestroyEffect(udg_AV_Effect1[pm.TimerIndex])
call ReleaseDummy(pm.Projectile)
endfunction
function Trig_Ice_Prison_Loop takes ProjectileMover pm returns boolean
local integer level = udg_AV_Int2[pm.TimerIndex]
local real TargetX = GetUnitX(pm.Target)
local real TargetY = GetUnitY(pm.Target)
local boolean result = false
if ( GetUnitState(pm.Projectile , UNIT_STATE_LIFE) <= 0 ) or (pm.Target == null) then
set result = true
elseif (pm.DistanceToTarget <= pm.Speed) then
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl", pm.Target, "origin"))
//Stun and slow the target
call IssueTargetOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(pm.Source), STUN_ABILITY_ID, level, TargetX, TargetY, 0), "thunderbolt", pm.Target )
call IssueTargetOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(pm.Source), SLOW_ABILITY_ID, 1, TargetX, TargetY, 0), "slow", pm.Target )
set result = true
else
// Check if the target teleported away
if (DistanceBetweenPoints(udg_AV_Loc1[pm.TimerIndex], GetUnitLoc(pm.Target)) > 600 * PROJECTILE_MOVE_INTERVAL) then
set result = true
else
call MoveLocation(udg_AV_Loc1[pm.TimerIndex], TargetX, TargetY)
endif
endif
return result
endfunction
function Trig_Ice_Prison_Actions takes nothing returns nothing
local unit Source = GetTriggerUnit()
local unit Target = GetSpellTargetUnit()
local unit Projectile
local ProjectileMover pm
local real face
local integer level = GetUnitAbilityLevel(Source, ABILITY_ID)
local real Speed = SPEED_BASE + ( level * SPEED_UP )
local effect fx
set face = bj_RADTODEG * Atan2(GetUnitY(Target) - GetUnitY(Source), GetUnitX(Target) - GetUnitX(Source))
set Projectile = XE_NewDummyUnit(GetOwningPlayer(Source) , GetUnitX(Source) , GetUnitY(Source) , face)
call SetUnitScale(Projectile, 2, 2, 2)
call SetUnitFlyHeight(Projectile, 100, 0)
set fx = AddSpecialEffectTarget("Abilities\\Weapons\\LichMissile\\LichMissile.mdl" , Projectile , "origin")
set pm = ProjectileMover.Create(Source, Projectile, Target, 0, 0)
call pm.Initialize(Speed, 0.25, ProjLooperFunction.Trig_Ice_Prison_Loop, ProjDestructorFunction.Trig_Ice_Prison_Destructor)
set udg_AV_Int2[pm.TimerIndex] = level
set udg_AV_Loc1[pm.TimerIndex] = GetUnitLoc(Target)
set udg_AV_Effect1[pm.TimerIndex] = fx
set Target = null
set Projectile = null
set Source = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Ice_Prison = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Ice_Prison, ABILITY_ID )
call TriggerAddAction( gg_trg_Ice_Prison, function Trig_Ice_Prison_Actions )
endfunction
endscope
//TESH.scrollpos=249
//TESH.alwaysfold=0
globals
real TIMED_LOOK_AT_TIMESTEP = 0.04
endglobals
library LookAt requires MapAttachedSettings
struct TimedLookAt
static TimedLookAt array currentlyExisting
static integer currentlyExistingN = 0
static timer periodicRefreshTimer = null
unit U
unit Target
unit dummy
real TargetX
real TargetY
real TargetZ
real TargetZOffset
real AngVel
real AngVelZ
real AngRelative
real AngRelativeZ
boolean relative
string bone
boolean callSetUnitLookAt
boolean destroyWhenDone
// Internal methods
private method Refresh takes real timestep returns boolean
local real unitFacing
local real diff
local real dxy
local real dx
local real dy
local real dz
local real targAngRel
local real targAngRelZ
local real Ux
local real Uy
local real Uz
local boolean done = false
if U==null then
// Destroy
set destroyWhenDone = true
return true
endif
if GetUnitState(U, UNIT_STATE_LIFE)<=0.0 then
// Destroy, if max life is smaller or equal 0.0,
// because then the unit was removed from the game already.
if (GetUnitState(U, UNIT_STATE_MAX_LIFE)<=0.0) then
set destroyWhenDone = true
else
set AngRelative = 0.0
set AngRelativeZ= 0.0
set callSetUnitLookAt = true
endif
return true
endif
set Ux = GetUnitX(U)
set Uy = GetUnitY(U)
set Uz = GetUnitZ(U)
if Target==U then
set targAngRel = TargetX
if (TargetY>0.0)!=relative then
set unitFacing = GetUnitFacing(U)*bj_DEGTORAD
if relative then
// We are working in relative coordinates, transform into relative angle:
set targAngRel = targAngRel-unitFacing
else
// Angle is given relative, transform into absolute angle
set targAngRel = targAngRel+unitFacing
endif
elseif relative then
set unitFacing = GetUnitFacing(U)*bj_DEGTORAD
endif
set targAngRelZ= TargetZ
else
if Target!=null and GetUnitState(Target,UNIT_STATE_LIFE)>0.0 then
// Use the Target-unit
set TargetX = GetUnitX(Target)
set TargetY = GetUnitY(Target)
set TargetZ = GetUnitZ(Target)+TargetZOffset
endif
set dx = TargetX-Ux
set dy = TargetY-Uy
set dz = TargetZ-Uz
set dxy = SquareRoot(dx*dx+dy*dy)
if relative then
set unitFacing = GetUnitFacing(U)*bj_DEGTORAD
set targAngRel = Atan2(dy,dx)-unitFacing
else
set targAngRel = Atan2(dy,dx)
endif
set targAngRelZ= Atan2(dz,dxy)
endif
// Use targAngRel relative to current Facing
set diff = AngRelative-targAngRel
// Set diff to be in [-pi, pi] using modulo:
if diff>0.0 then
set diff = diff-R2I((diff+bj_PI)/(2.0*bj_PI))*2.0*bj_PI
else
set diff = diff+R2I((-diff+bj_PI)/(2.0*bj_PI))*2.0*bj_PI
endif
if diff<AngVel*timestep and diff>-AngVel*timestep then
// Move instant
set AngRelative = targAngRel
elseif diff>0.0 then
// Move by AngVel
set AngRelative = AngRelative-AngVel*timestep
else
// Move by AngVel
set AngRelative = AngRelative+AngVel*timestep
endif
// Use targAngRelZ relative to current Facing
set diff = AngRelativeZ-targAngRelZ
// Set diff to be in [-pi, pi] using modulo:
if diff>0.0 then
set diff = diff-R2I((diff+bj_PI)/(2.0*bj_PI))*2.0*bj_PI
else
set diff = diff+R2I((-diff+bj_PI)/(2.0*bj_PI))*2.0*bj_PI
endif
if diff<AngVelZ*timestep and diff>-AngVelZ*timestep then
// Move instant
set AngRelativeZ = targAngRelZ
// So angleZ is at the desired angle, we are done, if this was also true for angleXY:
set done = AngRelative==targAngRel
elseif diff>0.0 then
// Move by AngVel
set AngRelativeZ = AngRelativeZ-AngVelZ*timestep
else
// Move by AngVel
set AngRelativeZ = AngRelativeZ+AngVelZ*timestep
endif
// Now we refreshed AngRelative and AngRelativeZ, set absolute:
if relative then
set targAngRel = AngRelative+unitFacing
else
set targAngRel = AngRelative
endif
set targAngRelZ= AngRelativeZ
set dz = Sin(targAngRelZ)
set dxy = Cos(targAngRelZ)
set dx = Cos(targAngRel)*dxy
set dy = Sin(targAngRel)*dxy
call MoveLocation(udg_TempLoc, Ux+dx*1024.0, Uy+dy*1024.0)
call SetUnitFlyHeight(dummy, Uz+dz*1024.0+1024.0-GetLocationZ(udg_TempLoc), 0.0)
call SetUnitX(dummy, Ux+dx*1024.0)
call SetUnitY(dummy, Uy+dy*1024.0)
if callSetUnitLookAt then
set callSetUnitLookAt = false
call SetUnitLookAt(U,bone,dummy,0.0,0.0,-1024.0)
endif
return done
endmethod
private static method TimerCallback takes nothing returns nothing
local integer i = 0
local integer j
local unit U
local boolean done
loop
exitwhen i>=TimedLookAt.currentlyExistingN
set done = TimedLookAt.currentlyExisting[i].Refresh( TIMED_LOOK_AT_TIMESTEP )
if done and TimedLookAt.currentlyExisting[i].destroyWhenDone then
// Destroy
set U = TimedLookAt.currentlyExisting[i].U
call ResetUnitLookAt(U)
call RemoveUnit(TimedLookAt.currentlyExisting[i].dummy)
set TimedLookAt.currentlyExisting[i].dummy = null
call TimedLookAt.currentlyExisting[i].destroy()
set TimedLookAt.currentlyExistingN = TimedLookAt.currentlyExistingN - 1
set TimedLookAt.currentlyExisting[i] = TimedLookAt.currentlyExisting[TimedLookAt.currentlyExistingN]
// LookAt has been reset for all bones, so if there are still existing TimedLookAts for this unit, they
// have to call SetUnitLookAt again:
set j = 0
loop
exitwhen j>=TimedLookAt.currentlyExistingN
if TimedLookAt.currentlyExisting[j].U==U then
set TimedLookAt.currentlyExisting[j].callSetUnitLookAt = true
endif
set j = j + 1
endloop
set U=null
else
set i = i + 1
endif
endloop
if TimedLookAt.currentlyExistingN<=0 then
// No more TimedLookAts existing, also destroy the timer.
call ReleaseTimer(TimedLookAt.periodicRefreshTimer)
set TimedLookAt.periodicRefreshTimer = null
endif
endmethod
private static method create takes unit fromUnit, real angVel, real angVelZ, string moveBone, boolean relativeMovement returns TimedLookAt
// angular velocities are taken in degrees per second
local TimedLookAt look = TimedLookAt.allocate()
set look.U = fromUnit
set look.AngVel = angVel*bj_DEGTORAD
set look.AngVelZ = angVelZ*bj_DEGTORAD
set look.AngRelativeZ= 0.0
set look.Target = fromUnit
set look.TargetX = 0.0
set look.TargetY = 0.0
set look.TargetZ = 0.0
set look.TargetZOffset = 0.0
set look.bone = StringCase(moveBone,false)
set look.destroyWhenDone = false
set look.dummy = CreateUnit(GetOwningPlayer(fromUnit),DUMMY_ID, 0.0, 0.0 ,0.0)
call UnitAddAbility(look.dummy, 'Amrf')
call UnitRemoveAbility(look.dummy,'Amrf')
set look.callSetUnitLookAt = true
set look.relative = relativeMovement
if relativeMovement then
set look.AngRelative = 0.0
else
set look.AngRelative = GetUnitFacing(fromUnit)*bj_DEGTORAD
endif
call look.Refresh(0.0)
set TimedLookAt.currentlyExisting[TimedLookAt.currentlyExistingN] = look
set TimedLookAt.currentlyExistingN = TimedLookAt.currentlyExistingN + 1
if TimedLookAt.periodicRefreshTimer==null then
// Make sure the periodic refresh is running
set TimedLookAt.periodicRefreshTimer=NewTimer()
call TimerStart(TimedLookAt.periodicRefreshTimer, TIMED_LOOK_AT_TIMESTEP, true, function TimedLookAt.TimerCallback)
endif
return look
endmethod
// External methods
public method SetTargetUnit takes unit targ, real offsetZ returns nothing
set Target = targ
if U!=targ then
set TargetZOffset = offsetZ
else
set TargetX = 0.0
if offsetZ>0.0 then
set TargetZ = 0.5*bj_PI
elseif offsetZ<0.0 then
set TargetZ = -0.5*bj_PI
else
set TargetZ = 0.0
endif
endif
set destroyWhenDone = false
endmethod
public method SetTargetAngle takes real angleXY, real angleZ, boolean relativeAngle returns nothing
set TargetX= angleXY
set TargetZ= angleZ
set Target = U
set destroyWhenDone = false
// Set TargetY, just to save some variables.
if relativeAngle then
set TargetY= 1.0
else
set TargetY=-1.0
endif
endmethod
public method SetTargetPosition takes real x, real y, real z returns nothing
set TargetX = x
set TargetY = y
set TargetZ = z
set Target = null
set destroyWhenDone = false
endmethod
public method GetFacingXY takes nothing returns real
if relative then
return AngRelative + GetUnitFacing(U)*bj_DEGTORAD
endif
return AngRelative
endmethod
public method GetFacingZ takes nothing returns real
return AngRelativeZ
endmethod
public method DestroyWhenDone takes nothing returns nothing
// Reset facing
call SetTargetAngle(0.0,0.0,true)
set destroyWhenDone = true
endmethod
public static method Get takes unit fromUnit, real angVel, real angVelZ, string moveBone, boolean relativeMovement returns TimedLookAt
// angular velocities are taken in degrees per second
local integer i = 0
local TimedLookAt look
set moveBone = StringCase(moveBone,false)
loop
exitwhen (i>=TimedLookAt.currentlyExistingN) or ((TimedLookAt.currentlyExisting[i].U==fromUnit) and (TimedLookAt.currentlyExisting[i].bone==moveBone))
set i = i + 1
endloop
if i>=TimedLookAt.currentlyExistingN then
return TimedLookAt.create(fromUnit,angVel,angVelZ,moveBone,relativeMovement)
endif
set look = TimedLookAt.currentlyExisting[i]
// Overwrite properties of the old instance:
set look.AngVel = angVel*bj_DEGTORAD
set look.AngVelZ= angVelZ*bj_DEGTORAD
if look.relative!=relativeMovement then
if relativeMovement then
// AngRelative is saved absolute, but needs to be relative:
set look.AngRelative = look.AngRelative-GetUnitFacing(fromUnit)*bj_DEGTORAD
else
// AngRelative is saved relative, but needs to be absolute:
set look.AngRelative = look.AngRelative+GetUnitFacing(fromUnit)*bj_DEGTORAD
endif
set look.relative=relativeMovement
endif
return look
endmethod
endstruct
function GetGoliathWeaponPosition takes unit tank returns nothing
local real scale = 1.0
local real sideDist = 54.0*scale
local real weaponLength=163.0*scale
local real weaponHeadZ=17.5*scale
local real weaponBaseZ=82.0*scale
local real X = GetUnitX(tank)
local real Y = GetUnitY(tank)
local real Z = GetUnitZ(tank)
local real angle
local real angleZ
local real angleCos
local real angleSin
local real angleZCos
local real angleZSin
set X = X + sideDist*angleSin + weaponLength*angleCos*angleZCos - weaponHeadZ*angleCos*angleZSin
set Y = Y - sideDist*angleCos + weaponLength*angleSin*angleZCos - weaponHeadZ*angleSin*angleZSin
set Z = Z + weaponBaseZ + weaponLength*angleZSin + weaponHeadZ*angleZCos
endfunction
endlibrary
//TESH.scrollpos=46
//TESH.alwaysfold=0
scope HeavyTankCannon initializer Init
globals
private constant integer ABILITY_ID = 'A02L'
private constant real SPEED_BASE = 1500.0
private constant real SPEED_UP = 0.0
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 200.0
private constant real RANGE_BASE = 900.0
private constant real RANGE_UP = 0.0
private constant real AIM_RANGE_BASE = 1300.0
private constant real AIM_RANGE_UP = 0.0
private constant real AREA_BASE = 200.0
private constant real AREA_UP = 0.0
private constant real PROJETILE_TIMED_LIFE = 20.0
private constant real MOVE_INTERVAL = 0.05
private constant real FIRE_INTERVAL_BASE = 3.0
private constant real FIRE_INTERVAL_UP = 0.0
private boolean array KeepTargetAngle[10]
endglobals
function Trig_Heavy_Tank_Cannon_Conditions takes nothing returns boolean
return GetLearnedSkill() == ABILITY_ID
endfunction
function Trig_Heavy_Tank_Cannon_ResetAiming takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Source = udg_AV_Unit1[LoopTimerId]
local real faceXY
local real faceZ
if (Take_Aim_Targets[GetPlayerNr(GetOwningPlayer(Source))] == null) then
//call ResetUnitLookAt(Source)
//call TimedLookAt.Get(Source, 90, 90, "head", true).DestroyWhenDone()
set faceXY = TimedLookAt.Get(Source, 90, 90, "head", true).GetFacingXY()
set faceZ = TimedLookAt.Get(Source, 90, 90, "head", true).GetFacingZ()
call TimedLookAt.Get(Source, 270, 90, "head", true).SetTargetAngle(faceXY, faceZ, false)
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
set Source = null
endfunction
//The loop method, which moves the weapon projectile to it's target
function Trig_Heavy_Tank_Cannon_MoveProjectile takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Projectile = udg_AV_Unit1[LoopTimerId]
local unit Attacker = udg_Tank[GetPlayerNr(GetOwningPlayer(Projectile))]
local integer level = udg_AV_Int1[LoopTimerId]
local real TargetX = GetLocationX(udg_AV_Loc1[LoopTimerId])
local real TargetY = GetLocationY(udg_AV_Loc1[LoopTimerId])
local real DistanceLeft
local real DistX
local real DistY
local real Speed = ( SPEED_BASE + ( level * SPEED_UP ) ) * MOVE_INTERVAL
local real area = AREA_BASE + ( level * AREA_UP )
local real damage = DAMAGE_BASE + ( level * DAMAGE_UP )
if ( GetUnitState(Projectile , UNIT_STATE_LIFE) <= 0 ) then
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
call ReleaseDummy(Projectile)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set DistX = TargetX - GetUnitX(Projectile)
set DistY = TargetY - GetUnitY(Projectile)
set DistanceLeft = SquareRoot(DistX * DistX + DistY * DistY)
//Projectile reached it's target
if (DistanceLeft <= 2*Speed) then
set udg_Filter_Player = GetOwningPlayer(Attacker)
call FixedAreaDamageFromUnit(Attacker, TargetX, TargetY, area, damage, 1.0, 0, false, FILTER_ENEMY_UNITS)
call DestroyEffect(udg_AV_Effect1[LoopTimerId])
call ReleaseDummy(Projectile)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
call SetUnitPosition(Projectile , GetUnitX(Projectile) + Speed * DistX / DistanceLeft , GetUnitY(Projectile) + Speed * DistY / DistanceLeft)
endif
endif
set Projectile = null
set Attacker = null
endfunction
function Trig_Heavy_Tank_Cannon_GetTarget takes unit source returns unit
local unit target = null
local integer playerId = GetPlayerNr(GetOwningPlayer(source))
local integer level = GetUnitAbilityLevel(source, ABILITY_ID)
local real aimRange = AIM_RANGE_BASE + ( level * AIM_RANGE_UP )
local real normalRange = RANGE_BASE + ( level * RANGE_UP )
local group G
if (Take_Aim_Targets[playerId] != null) and (GetUnitState(Take_Aim_Targets[playerId], UNIT_STATE_LIFE) > 0) then
if (GetUnitsDistance(Take_Aim_Targets[playerId], source) <= aimRange) then
set target = Take_Aim_Targets[playerId]
else
// Aim target not in range, search normal targets
endif
endif
if (target == null) then
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(source)
call GroupEnumUnitsInRange(G, GetUnitX(source),GetUnitY(source), normalRange, FILTER_ENEMY_UNITS )
if FirstOfGroup(G) != null then
set target = GroupPickRandomUnit(G)
endif
call ReleaseGroup(G)
endif
set G = null
return target
endfunction
function Trig_Heavy_Tank_Cannon_SetAiming takes nothing returns nothing
local timer t
local integer ShootTimerId
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit source = udg_AV_Unit1[LoopTimerId]
local unit target = udg_AV_Unit2[LoopTimerId]
local unit projectile
local real face
local effect fx
// if the target died or became invalid while targeting, get a new one
// but don't wait for the animation this time, since we don't want to extend the cooldown between shots
if (target == null) or (GetUnitState(target, UNIT_STATE_LIFE) <= 0) then
set target = Trig_Heavy_Tank_Cannon_GetTarget(source)
endif
if (target != null) then
set face = bj_RADTODEG * Atan2(GetUnitY(target) - GetUnitY(source), GetUnitX(target) - GetUnitX(source))
set projectile= XE_NewDummyUnit(GetOwningPlayer(source) , GetUnitX(source) , GetUnitY(source) , face)
call SetUnitScale(projectile, 2, 2, 2)
call SetUnitFlyHeight(projectile, GetUnitFlyHeight(source), 0)
set fx = AddSpecialEffectTarget("Abilities\\Weapons\\BoatMissile\\BoatMissile.mdl" , projectile , "origin")
call SetUnitAnimation( source, "Attack - 1" )
set t = NewTimer()
set ShootTimerId = NewTimerIndex(t)
set udg_AV_Unit1[ShootTimerId] = projectile
set udg_AV_Int1[ShootTimerId] = udg_AV_Int1[LoopTimerId]
set udg_AV_Loc1[ShootTimerId] = GetUnitLoc(target)
set udg_AV_Effect1[ShootTimerId] = fx
call TimerStart(t , MOVE_INTERVAL , true , function Trig_Heavy_Tank_Cannon_MoveProjectile)
// only aim, when you don't have a specific target already
if (Take_Aim_Targets[GetPlayerNr(GetOwningPlayer(source))] == null) then
set t = NewTimer()
set ShootTimerId = NewTimerIndex(t)
set udg_AV_Unit1[ShootTimerId] = source
call TimerStart(t , 0.75 , false , function Trig_Heavy_Tank_Cannon_ResetAiming)
endif
endif
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
set source = null
set target = null
set projectile = null
endfunction
function Trig_Heavy_Tank_Cannon_Fire takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Source = udg_AV_Unit1[LoopTimerId]
local unit Target = null
local integer learnedLevel = udg_AV_Int1[LoopTimerId]
local timer t
local integer ShootTimerId
local real face
local integer currentLevel = GetUnitAbilityLevel(Source, ABILITY_ID)
// each time you level up the ability, a new timer is started (timer interval may change with each level)
// so kill the current timer, when it's running for the old skill level
// this also stops the timer, when you change the tank
if (learnedLevel != currentLevel) then
call DebugMsg("Heavy Tank Cannon level " + I2S(learnedLevel) + " stopped")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
if (GetUnitState(Source, UNIT_STATE_LIFE) > 0) then
set Target = Trig_Heavy_Tank_Cannon_GetTarget(Source)
if (Target != null) then
// after finding a target, don't shoot immidiatly, but rather give the tank some time aim at the target
if (Take_Aim_Targets[GetPlayerNr(GetOwningPlayer(Source))] == null) then
call TimedLookAt.Get(Source, 140, 90, "head", true).SetTargetUnit(Target, 50)
endif
set KeepTargetAngle[GetPlayerNr(GetOwningPlayer(Source))] = true
set t = NewTimer()
set ShootTimerId = NewTimerIndex(t)
set udg_AV_Unit1[ShootTimerId] = Source
set udg_AV_Unit2[ShootTimerId] = Target
set udg_AV_Int1[ShootTimerId] = currentLevel
call TimerStart(t , 0.5 , false , function Trig_Heavy_Tank_Cannon_SetAiming)
else
if (KeepTargetAngle[GetPlayerNr(GetOwningPlayer(Source))] == true) then
call TimedLookAt.Get(Source, 90, 90, "head", true).DestroyWhenDone()
endif
set KeepTargetAngle[GetPlayerNr(GetOwningPlayer(Source))] = false
endif
else
// Do nothing
endif
endif
set Target = null
set Source = null
endfunction
function Trig_Heavy_Tank_Cannon_Actions takes nothing returns nothing
local timer t
local integer ShootTimerId
local unit Source = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(Source, ABILITY_ID)
local real fireInterval = FIRE_INTERVAL_BASE + ( level * FIRE_INTERVAL_UP )
set t = NewTimer()
set ShootTimerId = NewTimerIndex(t)
set udg_AV_Unit1[ShootTimerId] = Source
set udg_AV_Int1[ShootTimerId] = level
call TimerStart(t , fireInterval , true , function Trig_Heavy_Tank_Cannon_Fire)
set Source = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Heavy_Tank_Cannon = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_Heavy_Tank_Cannon, EVENT_PLAYER_HERO_SKILL )
call TriggerAddCondition(gg_trg_Heavy_Tank_Cannon, Condition( function Trig_Heavy_Tank_Cannon_Conditions))
call TriggerAddAction( gg_trg_Heavy_Tank_Cannon, function Trig_Heavy_Tank_Cannon_Actions )
endfunction
endscope
//TESH.scrollpos=41
//TESH.alwaysfold=0
scope OffroadEngine initializer Init
globals
private constant integer ABILITY_ID = 'A02V'
private constant integer SPEED_ABILITY_ID = 'A056'
private constant integer BUFF_ID = 'B02P'
private constant integer GOLIATH_NORMAL_ID = 'H01V'
private constant real DAMAGE_BASE = 300.0 // Damage per second
private constant real DAMAGE_UP = 0.0
private constant real DAMAGE_AREA_BASE = 250.0
private constant real DAMAGE_AREA_UP = 0.0
private constant real DURATION_BASE = 0.0
private constant real DURATION_UP = 3.0
private constant real INTERVAL = 0.25
endglobals
function Trig_Offroad_Engine_Conditions takes nothing returns boolean
return (GetSpellAbilityId() == ABILITY_ID)
endfunction
function Trig_Offroad_Engine_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit caster = udg_AV_Unit1[LoopTimerId]
local real finishTime = udg_AV_Real1[LoopTimerId]
local integer level = GetUnitAbilityLevel(caster, ABILITY_ID)
local real damage = DAMAGE_BASE + (level * DAMAGE_UP)
local real area = DAMAGE_AREA_BASE + (level * DAMAGE_AREA_UP)
//if ( TimerGetElapsed(udg_GameTime) >= finishTime ) or (GetUnitState(caster, UNIT_STATE_LIFE) <= 0) then
if (( TimerGetElapsed(udg_GameTime) >= finishTime ) and ( GetUnitAbilityLevel(caster, BUFF_ID) <= 0 )) or (GetUnitState(caster, UNIT_STATE_LIFE) <= 0) then
// if the tank is currently not over pathable terrain, place him at the last pathable terrain he passed over
if not GetPathableLoc(GetUnitLoc(caster), 32, 128) then
call SetUnitPositionLoc(caster, udg_AV_Loc1[LoopTimerId])
endif
call ReactivateBlockingArmor(caster)
call ApplyManaUpgrade(GetPlayerNr(GetOwningPlayer(caster)))
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set udg_Filter_Player = GetOwningPlayer(caster)
call FixedAreaDamageFromUnit(caster, GetUnitX(caster), GetUnitY(caster), area, damage, 1.0, 0, false, FILTER_ENEMY_UNITS)
// if the current terrain is pathable, save the position
if GetPathableLoc(Location(GetUnitX(caster), GetUnitY(caster)), 32, 128) then
call MoveLocation(udg_AV_Loc1[LoopTimerId], GetUnitX(caster), GetUnitY(caster))
endif
endif
set caster = null
endfunction
function Trig_Offroad_Engine_Actions takes nothing returns nothing
local timer t
local integer LoopTimerId
local unit temp
local unit caster = GetTriggerUnit()
local integer pId = GetPlayerNr(GetOwningPlayer(caster))
local integer level = GetUnitAbilityLevel(caster, ABILITY_ID)
local real duration = DURATION_BASE + (level * DURATION_UP)
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(caster), SPEED_ABILITY_ID, level, GetUnitX(caster), GetUnitY(caster), 0), "slow", caster)
call ReactivateBlockingArmor(caster)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = caster
set udg_AV_Real1[LoopTimerId] = TimerGetElapsed(udg_GameTime) + duration
set udg_AV_Loc1[LoopTimerId] = Location(GetUnitX(caster), GetUnitY(caster))
call TimerStart(t , INTERVAL , true , function Trig_Offroad_Engine_Loop)
set temp = udg_Tank[pId]
set udg_Tank[pId] = caster
call DebugMsg("Caster: " + UnitId2String(GetUnitTypeId(caster)))
call ApplyManaUpgrade(pId)
set udg_Tank[pId] = temp
set caster = null
set temp = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Offroad_Engine = CreateTrigger( )
//call TriggerRegisterSpellEffectEvent( gg_trg_Offroad_Engine, ABILITY_ID )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Offroad_Engine, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Offroad_Engine, Condition( function Trig_Offroad_Engine_Conditions ) )
call TriggerAddAction( gg_trg_Offroad_Engine, function Trig_Offroad_Engine_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TakeAim initializer Init
globals
private constant integer ABILITY_ID = 'A0E1'
private constant integer BUFF_ID = 'B02U'
private constant real DURATION_BASE = 16.0
private constant real DURATION_UP = 0.0
private constant real DAMAGE_INCREASE_BASE = 0.0
private constant real DAMAGE_INCREASE_UP = 0.05
private constant integer MAX_STACKS_BASE = 4
private constant integer MAX_STACKS_UP = 0
private constant real CHECK_INTERVAL = 0.5
unit array Take_Aim_Targets[10]
integer array Take_Aim_Stacks[10]
private integer DD_ID
endglobals
function Trig_Take_Aim_DamageDetection takes nothing returns real
local integer sourceId = GetPlayerNr(GetOwningPlayer(DamageDetection_DamageSource))
local integer level = GetUnitAbilityLevel(DamageDetection_DamageSource, ABILITY_ID)
if (Take_Aim_Targets[sourceId] == DamageDetection_DamageTarget) then
// the damage system interprets postive values as additional damage and negative ones as reduced damage
return (DAMAGE_INCREASE_BASE + ( level * DAMAGE_INCREASE_UP )) * Take_Aim_Stacks[sourceId]
endif
return 0.0
endfunction
function Trig_Take_Aim_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local unit Caster = udg_AV_Unit2[LoopTimerId]
local integer pId = GetPlayerNr(GetOwningPlayer(Caster))
local boolean finish = false
if (Take_Aim_Targets[pId] != Target) then
call UnitRemoveAbility(Target, BUFF_ID)
set finish = true
elseif (GetUnitAbilityLevel(Target, BUFF_ID) == 0) or (GetUnitState(Target, UNIT_STATE_LIFE) <= 0) then
set Take_Aim_Targets[pId] = null
set Take_Aim_Stacks[pId] = 0
if (GetUnitState(Caster, UNIT_STATE_LIFE) > 0) then
call TimedLookAt.Get(Caster, 90, 90, "head", true).DestroyWhenDone()
endif
set finish = true
endif
if finish then
call DisableSkillDamageDetection(DD_ID)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
set Target = null
set Caster = null
endfunction
function Trig_Take_Aim_Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local unit Target = GetSpellTargetUnit()
local integer lvl = GetUnitAbilityLevel(U, ABILITY_ID)
local integer pId = GetPlayerNr(GetOwningPlayer(U))
local real bonus = DAMAGE_INCREASE_BASE + (lvl * DAMAGE_INCREASE_UP)
local integer maxStacks = MAX_STACKS_BASE + (lvl * MAX_STACKS_UP)
local timer t
local integer LoopTimerId
call TimedLookAt.Get(U, 180, 90, "head", true).SetTargetUnit(Target, 50)
if (not IsUnitType(Target, UNIT_TYPE_HERO)) then
call RegisterUnitForSkillDamageDetection(Target)
endif
if (Take_Aim_Stacks[pId] == 0) or ((Take_Aim_Targets[pId] != null) and (Take_Aim_Targets[pId] != Target)) then
call EnableSkillDamageDetection(DD_ID)
set Take_Aim_Stacks[pId] = 1
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Target
set udg_AV_Unit2[LoopTimerId] = U
call TimerStart(t , CHECK_INTERVAL , true , function Trig_Take_Aim_Loop)
else
if (Take_Aim_Stacks[pId] < maxStacks) then
set Take_Aim_Stacks[pId] = Take_Aim_Stacks[pId] + 1
endif
endif
set Take_Aim_Targets[pId] = Target
call ShowTextTag("+"+I2S(R2I(bonus*Take_Aim_Stacks[pId]*100+1))+"%", Target, 0, 50, GetOwningPlayer(U))
set U = null
set Target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Take_Aim = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodeRelative(DamageAlterationFunction.Trig_Take_Aim_DamageDetection)
call TriggerRegisterSpellEffectEvent( gg_trg_Take_Aim, ABILITY_ID )
call TriggerAddAction( gg_trg_Take_Aim, function Trig_Take_Aim_Actions )
endfunction
endscope
//TESH.scrollpos=20
//TESH.alwaysfold=0
scope Exoarmor initializer Init
globals
private constant integer ABILITY_ID = 'A0BO'
private constant integer BUFF_ID = 'B02O'
private constant real DURATION_BASE = 7.0
private constant real DURATION_UP = 0.0
private constant real DAMAGE_REDUCTION_BASE = 0.60
private constant real DAMAGE_REDUCTION_UP = 0.0
private constant real DAMAGE_REDUCTION_ANGLE_BASE = 0.0
private constant real DAMAGE_REDUCTION_ANGLE_UP = 30.0
private constant real SHIELD_SPEED_BASE = 35.0 // movement around the tank in degree per second
private constant real SHIELD_SPEED_UP = 0.0
private constant integer SHIELD_NUMBER_BASE = 0
private constant integer SHIELD_NUMBER_UP = 1
private constant real MOVE_INTERVAL = 0.02
private constant real TARGET_SEARCH_AREA = 1500.0
private constant real TARGET_SEARCH_INTERVAL = 1.0
group array Exoarmor_Shields[10]
real array Exoarmor_ShieldsAngle[10]
private integer DD_ID
endglobals
function Trig_Mobile_Shields_DamageDetection takes nothing returns real
local integer targetId = GetPlayerNr(GetOwningPlayer(DamageDetection_DamageTarget))
local integer lvl = GetUnitAbilityLevel(DamageDetection_DamageTarget, ABILITY_ID)
local real shieldAngle
local real targetAngle
// See if the tank has the buff, only reduce the damage in this case (note that the buff level is always 1, when the skill is active)
if GetUnitAbilityLevel(DamageDetection_DamageTarget, BUFF_ID) > 0 then
// the angle between the shields and the target
set targetAngle = GetUnitsAngleDeg(DamageDetection_DamageTarget, DamageDetection_DamageSource) - Exoarmor_ShieldsAngle[targetId]
// the total angle covered by the shields
set shieldAngle = DAMAGE_REDUCTION_ANGLE_BASE + ( lvl * DAMAGE_REDUCTION_ANGLE_UP )
call DebugMsg("Target Angle: " + R2S(targetAngle) + " Shield Angle: " + R2S(shieldAngle))
if (targetAngle >= (shieldAngle * -0.5)) and (targetAngle <= (shieldAngle * 0.5)) then
// the damage system interprets postive values as additional damage and negative ones as reduced damage
return -(DAMAGE_REDUCTION_BASE + ( lvl * DAMAGE_REDUCTION_UP ))
endif
endif
return 0.0
endfunction
function Trig_Mobile_Shields_DestroyShields takes integer casterId returns nothing
local unit tmp = null
loop
set tmp = FirstOfGroup(Exoarmor_Shields[casterId])
exitwhen tmp == null
call RemoveUnit(tmp)
call GroupRemoveUnit(Exoarmor_Shields[casterId],tmp)
endloop
call ReleaseGroup(Exoarmor_Shields[casterId])
set Exoarmor_Shields[casterId] = null
endfunction
function Trig_Mobile_Shields_SetShieldFacing takes unit caster, real angle returns nothing
local unit shield
local integer casterId = GetPlayerNr(GetOwningPlayer(caster))
local integer groupSize = CountUnitsInGroup(Exoarmor_Shields[casterId])
local integer lvl = GetUnitAbilityLevel(caster, ABILITY_ID)
local integer i = 0
local real totalAngle = DAMAGE_REDUCTION_ANGLE_BASE + ( lvl * DAMAGE_REDUCTION_ANGLE_UP )
local real shieldAngle
local real dx
local real dy
local group G = NewGroup()
call GroupAddGroup(Exoarmor_Shields[casterId], G)
loop
exitwhen i >= groupSize
set shield = FirstOfGroup(G)
set shieldAngle = (((totalAngle / I2R(groupSize)) / 2.0) + (i * totalAngle / I2R(groupSize))) + angle - (totalAngle / 2.0)
set dx = GetUnitX(caster) + 275.0 * Cos(shieldAngle * bj_DEGTORAD)
set dy = GetUnitY(caster) + 275.0 * Sin(shieldAngle * bj_DEGTORAD)
call SetUnitPosition(shield, dx, dy)
call SetUnitFacing(shield, shieldAngle)
call GroupRemoveUnit(G, shield)
set i = i + 1
endloop
set Exoarmor_ShieldsAngle[casterId] = angle
call ReleaseGroup(G)
set G = null
set shield = null
endfunction
function Trig_Mobile_Shields_MoveShields takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit caster = udg_AV_Unit1[LoopTimerId]
local unit target = udg_AV_Unit2[LoopTimerId]
local integer level = udg_AV_Int1[LoopTimerId]
local integer targetChangeInterval = R2I(TARGET_SEARCH_INTERVAL / MOVE_INTERVAL)
local integer casterId = GetPlayerNr(GetOwningPlayer(caster))
local real finishTime = udg_AV_Real1[LoopTimerId]
local real dx
local real dy
local real dxy
local real angle
local real finalAngle
local real diff
local real shieldSpeed = (SHIELD_SPEED_BASE + ( level * SHIELD_SPEED_UP )) * MOVE_INTERVAL
local group G
if ( GetUnitState(caster , UNIT_STATE_LIFE) <= 0 ) or ( TimerGetElapsed(udg_GameTime) >= finishTime ) then
call Trig_Mobile_Shields_DestroyShields(casterId)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
// because of perfomance reasons, a new target will only be chosen, when it's necessary or after a certain interval is over
if (target == null) or (GetUnitState(target, UNIT_STATE_LIFE) <= 0) or (ModuloInteger(udg_AV_Int2[LoopTimerId], targetChangeInterval) == 0) then
set target = null
if (Take_Aim_Targets[casterId] != null) then
set target = Take_Aim_Targets[casterId]
else
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(caster)
call GroupEnumUnitsInRange(G, GetUnitX(caster),GetUnitY(caster), TARGET_SEARCH_AREA, FILTER_ENEMY_TANK )
if (FirstOfGroup(G) != null) then
set target = GetClosestUnitFromGroup(G, GetUnitX(caster),GetUnitY(caster))
endif
call ReleaseGroup(G)
endif
set udg_AV_Unit2[LoopTimerId] = target
endif
if (target != null) then
set angle = GetUnitsAngleDeg(caster, target)
else
set angle = GetUnitFacing(caster)
endif
// the difference between the angle between the tanks and its target and the current facing of the shields
set diff = Exoarmor_ShieldsAngle[casterId]-angle
// Set diff to be in [-180, 180] using modulo:
if diff>0.0 then
set diff = diff-R2I((diff+180.0)/(360.0))*360.0
else
set diff = diff+R2I((-diff+180.0)/(360.0))*360.0
endif
if diff<shieldSpeed and diff>-shieldSpeed then
set finalAngle = angle
elseif diff>0.0 then
set finalAngle = Exoarmor_ShieldsAngle[casterId]-shieldSpeed
else
set finalAngle = Exoarmor_ShieldsAngle[casterId]+shieldSpeed
endif
call Trig_Mobile_Shields_SetShieldFacing(caster, finalAngle)
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
endif
set caster = null
set G = null
endfunction
function Trig_Mobile_Shields_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit dummy
local integer casterId = GetPlayerNr(GetOwningPlayer(caster))
local integer lvl = GetUnitAbilityLevel(caster, ABILITY_ID)
local real duration = DURATION_BASE + (lvl * DURATION_UP)
local timer t
local integer LoopTimerId
local integer i = 1
local integer shieldCount = SHIELD_NUMBER_BASE + ( lvl * SHIELD_NUMBER_UP )
// create the shields and save them in the global group
set Exoarmor_Shields[casterId] = NewGroup()
loop
exitwhen i > shieldCount
set dummy = CreateUnit(GetOwningPlayer(caster) , DUMMY_ID , GetUnitX(caster) , GetUnitY(caster) , 270)
call AddSpecialEffectTarget("Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl", dummy, "origin")
call GroupAddUnit(Exoarmor_Shields[casterId], dummy)
set i = i + 1
endloop
call Trig_Mobile_Shields_SetShieldFacing(caster, GetUnitFacing(caster))
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = caster
set udg_AV_Unit2[LoopTimerId] = null
set udg_AV_Real1[LoopTimerId] = TimerGetElapsed(udg_GameTime) + duration
set udg_AV_Int1[LoopTimerId] = lvl
set udg_AV_Int2[LoopTimerId] = 0
call TimerStart(t , MOVE_INTERVAL , true , function Trig_Mobile_Shields_MoveShields)
call EnableSkillDamageDetection(DD_ID)
call GameTimeWait( duration )
call DisableSkillDamageDetection(DD_ID)
set dummy = null
set caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Mobile_Shields = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodeRelative(DamageAlterationFunction.Trig_Mobile_Shields_DamageDetection)
call TriggerRegisterSpellEffectEvent( gg_trg_Mobile_Shields, ABILITY_ID )
call TriggerAddAction( gg_trg_Mobile_Shields, function Trig_Mobile_Shields_Actions )
endfunction
endscope
//TESH.scrollpos=112
//TESH.alwaysfold=0
scope DevastatorShot initializer Init
globals
private constant integer ABILITY_ID = 'A04P'
private constant real SPEED_BASE = 1500.0
private constant real SPEED_UP = 0.0
private constant real DAMAGE_BASE = 1500.0
private constant real DAMAGE_UP = 500.0
private constant real RANGE_BASE = 2000.0
private constant real RANGE_UP = 0.0
private constant real AREA_BASE = 150.0
private constant real AREA_UP = 0.0
private constant real BUFF_DURATION_BASE = 10.0
private constant real BUFF_DURATION_UP = 0.0
private constant real PROJETILE_TIMED_LIFE = 20.0
private constant real MOVE_INTERVAL = 0.05
constant integer DEVASTATOR_ABILITY_ID = ABILITY_ID
constant integer DEVASTATOR_SHOT_BUFF_ID = 'A0BX'
constant real RESPAWN_INCREASE_BASE = 0.15
constant real RESPAWN_INCREASE_UP = 0.05
endglobals
// Each projectile should damage any given target only once, so save those targets in a own group
function Trig_Devastator_Shot_DamageTarget takes unit source, group checkTargets, group excludedTargets returns nothing
local unit EnumUnit
local integer level = GetUnitAbilityLevel(source, ABILITY_ID)
local real damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real duration = BUFF_DURATION_BASE + ( level * BUFF_DURATION_UP )
loop
set EnumUnit = FirstOfGroup(checkTargets)
exitwhen EnumUnit==null
if not IsUnitInGroup(EnumUnit, excludedTargets) then
// Cast the buff on the target
if IsUnitType(EnumUnit, UNIT_TYPE_HERO) then
call AddAbilityTimed(EnumUnit, DEVASTATOR_SHOT_BUFF_ID, level, duration)
endif
if IsUnitType(EnumUnit, UNIT_TYPE_STRUCTURE) then
call UnitDamageTarget(source, EnumUnit, damage / 2, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
else
call UnitDamageTarget(source, EnumUnit, damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
endif
call GroupAddUnit(excludedTargets, EnumUnit)
endif
call GroupRemoveUnit(checkTargets, EnumUnit)
endloop
endfunction
//The loop method, which moves the weapon projectile to it's target
function Trig_Devastator_Shot_MoveProjectile takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Projectile1 = udg_AV_Unit1[LoopTimerId]
local unit Projectile2 = udg_AV_Unit2[LoopTimerId]
local unit Attacker = udg_Tank[GetPlayerNr(GetOwningPlayer(Projectile1))]
local integer level = udg_AV_Int1[LoopTimerId]
local real TargetX = udg_AV_Real1[LoopTimerId]
local real TargetY = udg_AV_Real2[LoopTimerId]
local real DistanceLeft
local real DistX
local real DistY
local real Speed = ( SPEED_BASE + ( level * SPEED_UP ) ) * MOVE_INTERVAL
local real area = AREA_BASE + ( level * AREA_UP )
local group G
if ( GetUnitState(Projectile1 , UNIT_STATE_LIFE) <= 0 ) or ( GetUnitState(Projectile2 , UNIT_STATE_LIFE) <= 0 ) then
call RemoveUnit(Projectile1)
call RemoveUnit(Projectile2)
call ReleaseGroup(udg_AV_Group1[LoopTimerId])
call ReleaseGroup(udg_AV_Group2[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
if ModuloInteger(udg_AV_Int2[LoopTimerId], 3) == 0 then
call DestroyEffect(AddSpecialEffect("war3mapImported\\ImpaleTargetDust2.mdx",GetUnitX(Projectile1),GetUnitY(Projectile1)))
call DestroyEffect(AddSpecialEffect("war3mapImported\\ImpaleTargetDust2.mdx",GetUnitX(Projectile2),GetUnitY(Projectile2)))
endif
set udg_AV_Int2[LoopTimerId] = udg_AV_Int2[LoopTimerId] + 1
set DistX = TargetX - GetUnitX(Projectile1)
set DistY = TargetY - GetUnitY(Projectile1)
set DistanceLeft = SquareRoot(DistX * DistX + DistY * DistY)
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(Attacker)
call GroupEnumUnitsInRange(G, GetUnitX(Projectile1),GetUnitY(Projectile1), area, FILTER_ENEMY_UNITS )
call Trig_Devastator_Shot_DamageTarget(Attacker, G, udg_AV_Group1[LoopTimerId])
call GroupEnumUnitsInRange(G, GetUnitX(Projectile2),GetUnitY(Projectile2), area, FILTER_ENEMY_UNITS )
call Trig_Devastator_Shot_DamageTarget(Attacker, G, udg_AV_Group2[LoopTimerId])
call ReleaseGroup(G)
//Projectile reached it's target
if (DistanceLeft <= 2*Speed) then
call RemoveUnit(Projectile1)
call RemoveUnit(Projectile2)
call ReleaseGroup(udg_AV_Group1[LoopTimerId])
call ReleaseGroup(udg_AV_Group2[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
call SetUnitPosition(Projectile1 , GetUnitX(Projectile1) + Speed * DistX / DistanceLeft , GetUnitY(Projectile1) + Speed * DistY / DistanceLeft)
call SetUnitPosition(Projectile2 , GetUnitX(Projectile2) + Speed * DistX / DistanceLeft , GetUnitY(Projectile2) + Speed * DistY / DistanceLeft)
endif
endif
set Projectile1 = null
set Projectile2 = null
set Attacker = null
set G = null
endfunction
function Trig_Devastator_Shot_Actions takes nothing returns nothing
local unit Source = GetTriggerUnit()
local unit Projectile1
local unit Projectile2
local integer pId = GetPlayerNr(GetOwningPlayer(Source))
local integer level = GetUnitAbilityLevel(Source, ABILITY_ID)
local real range = RANGE_BASE + ( level * RANGE_UP )
local real face = Atan2(GetSpellTargetY() - GetUnitY(Source), GetSpellTargetX() - GetUnitX(Source))
local real targetX = GetUnitX(Source) + range * Cos(face)
local real targetY = GetUnitY(Source) + range * Sin(face)
local real projX
local real projY
local timer t
local integer LoopTimerId
if (Take_Aim_Targets[pId] != null) then
call TimedLookAt.Get(Source, 180, 90, "head", true).SetTargetAngle(0.0,0.0,true)
endif
set face = bj_RADTODEG * face
set projX = PolarProjX(GetUnitX(Source), 50, face - 90)
set projY = PolarProjY(GetUnitY(Source), 50, face - 90)
set Projectile1 = CreateUnit(GetOwningPlayer(Source) , PROJECTILE_ID , projX , projY , face)
call SetUnitScale(Projectile1, 2, 2, 2)
call SetUnitFlyHeight(Projectile1, GetUnitFlyHeight(Source), 0)
call AddSpecialEffectTarget("Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl" , Projectile1 , "origin")
call UnitApplyTimedLife(Projectile1, 'B015', PROJETILE_TIMED_LIFE)
call SetUnitPathing(Projectile1, false)
call SetUnitPosition(Projectile1, projX, projY)
set projX = PolarProjX(GetUnitX(Source), 50, face + 90)
set projY = PolarProjY(GetUnitY(Source), 50, face + 90)
set Projectile2 = CreateUnit(GetOwningPlayer(Source) , PROJECTILE_ID , projX , projY , face)
call SetUnitScale(Projectile2, 2, 2, 2)
call SetUnitFlyHeight(Projectile2, GetUnitFlyHeight(Source), 0)
call AddSpecialEffectTarget("Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl" , Projectile2 , "origin")
call UnitApplyTimedLife(Projectile2, 'B015', PROJETILE_TIMED_LIFE)
call SetUnitPathing(Projectile2, false)
call SetUnitPosition(Projectile2, projX, projY)
call SetUnitAnimation( Source, "Attack Slam Attack Defense" )
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Projectile1
set udg_AV_Unit2[LoopTimerId] = Projectile2
set udg_AV_Real1[LoopTimerId] = targetX
set udg_AV_Real2[LoopTimerId] = targetY
set udg_AV_Group1[LoopTimerId] = NewGroup()
set udg_AV_Group2[LoopTimerId] = NewGroup()
set udg_AV_Int1[LoopTimerId] = level
set udg_AV_Int2[LoopTimerId] = 0
call TimerStart(t , MOVE_INTERVAL , true , function Trig_Devastator_Shot_MoveProjectile)
call GameTimeWait(0.75)
if (Take_Aim_Targets[pId] != null) then
call TimedLookAt.Get(Source, 180, 90, "head", true).SetTargetUnit(Take_Aim_Targets[pId], 50)
endif
set Projectile1 = null
set Projectile2 = null
set Source = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Devastator_Shot = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Devastator_Shot, ABILITY_ID )
call TriggerAddAction( gg_trg_Devastator_Shot, function Trig_Devastator_Shot_Actions )
endfunction
endscope
//TESH.scrollpos=-1
//TESH.alwaysfold=0
globals
constant integer DEVASTATOR_EFFECT_ABILITY_ID = 'A0CP'
endglobals
function Trig_Devastator_Shot_Animation_Conditions takes nothing returns boolean
return (GetSpellAbilityId() == DEVASTATOR_ABILITY_ID)
endfunction
function Trig_Devastator_Shot_Animation_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
call DebugMsg("Devastator Start")
call UnitAddAbility(Caster, DEVASTATOR_EFFECT_ABILITY_ID)
call GameTimeWait(1.25)
call UnitRemoveAbility(Caster, DEVASTATOR_EFFECT_ABILITY_ID)
set Caster = null
endfunction
//===========================================================================
function InitTrig_Devastator_Shot_Animation takes nothing returns nothing
set gg_trg_Devastator_Shot_Animation = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Devastator_Shot_Animation, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_Devastator_Shot_Animation, Condition( function Trig_Devastator_Shot_Animation_Conditions ) )
call TriggerAddAction( gg_trg_Devastator_Shot_Animation, function Trig_Devastator_Shot_Animation_Actions )
endfunction
//TESH.scrollpos=6
//TESH.alwaysfold=0
scope TurboBoost initializer Init
globals
private constant integer ABILITY_ID = 'A09C'
private constant integer DAMAGE_ABILITY_ID = 'A09D'
private constant real SPEED_BASE = 900.0
private constant real SPEED_UP = 0.0
private constant real DISTANCE_BASE = 800.0
private constant real DISTANCE_UP = 200.0
private constant real INTERVAL = 0.02
endglobals
function Trig_Turbo_Boost_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit U = udg_AV_Unit1[LoopTimerId]
local location TargetLoc = udg_AV_Loc1[LoopTimerId]
local integer level = GetUnitAbilityLevel(U,ABILITY_ID)
local real speed = ( SPEED_BASE + ( level * SPEED_UP ) ) * INTERVAL
local real OldDistance = udg_AV_Real1[LoopTimerId]
local real DistanceLeft
local real DistX
local real DistY
if (GetUnitState(U, UNIT_STATE_LIFE) <= 0) or IsUnitStunned(U) then
call DebugMsg("End Turbo Boost - Dead or Stunned")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call RemoveLocation(TargetLoc)
else
set DistX = GetLocationX(TargetLoc)-GetUnitX(U)
set DistY = GetLocationY(TargetLoc)-GetUnitY(U)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
call SetUnitPosition(U,GetUnitX(U)+speed*DistX/DistanceLeft,GetUnitY(U)+speed*DistY/DistanceLeft)
call SetUnitFacing(U, Atan2(DistY, DistX)*bj_RADTODEG)
set DistX = GetLocationX(TargetLoc)-GetUnitX(U)
set DistY = GetLocationY(TargetLoc)-GetUnitY(U)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
set udg_AV_Real1[LoopTimerId] = DistanceLeft
if DistanceLeft <= speed then
//call DebugMsg("End Turbo Boost - Reached Destination")
call SetUnitPositionLoc(U,TargetLoc)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call RemoveLocation(TargetLoc)
else
// The check just has to make sure that the unit is still on its way to the target location in a straight line
// If this is not possible (because its e.g. out of the playable map region), the movement has to be interrupted, so it won't get stuck or move forever.
if (DistanceLeft >= OldDistance) then
call DebugMsg("End Turbo Boost - Moved away from target")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call RemoveLocation(TargetLoc)
endif
endif
endif
set TargetLoc = null
set U = null
endfunction
function Trig_Turbo_Boost_Actions takes nothing returns nothing
local timer t
local unit U = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(U,ABILITY_ID)
local real facerad = GetUnitFacing(U)*bj_DEGTORAD
local real Distance = DISTANCE_BASE + ( level * DISTANCE_UP )
local real CasterX = GetUnitX(U)
local real CasterY = GetUnitY(U)
local location targetloc = Location(CasterX + Distance * Cos(facerad), CasterY + Distance * Sin(facerad))
local integer LoopTimerId
local integer CheckCount = 5
local unit Dummy = CreateDummyWithAbilityCoord(GetOwningPlayer(U), DAMAGE_ABILITY_ID, level, CasterX, CasterY, 0)
call DebugMsg("X: " + I2S(R2I(CasterX)) + " Y: " + I2S(R2I(CasterY)))
call DebugMsg("T_X: " + I2S(R2I(GetLocationX(targetloc))) + " T_Y: " + I2S(R2I(GetLocationY(targetloc))))
call SetUnitPosition(Dummy,CasterX,CasterY)
set CasterX = GetUnitX(Dummy)
set CasterY = GetUnitY(Dummy)
//to ensure the damage ability is cast; it's not possible when the target is on a cliff
loop
exitwhen IssuePointOrder( Dummy, "carrionswarm", CasterX+CheckCount*10*Cos(facerad), CasterY+CheckCount*10*Sin(facerad) )
if CheckCount>200 then
set U = null
call RemoveUnit(Dummy)
set Dummy = null
call IssueImmediateOrder( U, "stop" )
if GetLocalPlayer() == GetOwningPlayer(U) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312The terrain is too hilly.|r")
endif
call SetUnitManaDelayed(U, GetUnitState(U, UNIT_STATE_MANA))
return
else
set CheckCount=CheckCount+1
endif
endloop
call SetUnitScale(Dummy, 2, 2, 2)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Loc1[LoopTimerId] = targetloc
set udg_AV_Unit1[LoopTimerId] = U
set udg_AV_Real1[LoopTimerId] = Distance
call TimerStart(t, INTERVAL, true, function Trig_Turbo_Boost_Loop)
set U = null
set targetloc = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Turbo_Boost = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Turbo_Boost, ABILITY_ID )
call TriggerAddAction( gg_trg_Turbo_Boost, function Trig_Turbo_Boost_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope BombCarpet initializer Init
globals
private constant integer ABILITY_ID = 'A09U'
private constant integer BOMB_COUNT_BASE = 5
private constant integer BOMB_COUNT_UP = 0
private constant real BOMB_TIMED_LIFE = 2.0
private constant real DROP_INTERVAL = 1.0
endglobals
private function Actions takes nothing returns nothing
local unit U = GetTriggerUnit()
local unit Bomb
local real beginGameTime = TimerGetElapsed(udg_GameTime)
local real X
local real Y
local real Z
local integer Level = GetUnitAbilityLevel(U, ABILITY_ID)
local integer i = 1
local integer tries = BOMB_COUNT_BASE + ( Level * BOMB_COUNT_UP )
local integer BombId
if Level == 1 then
set BombId = 'n00L'
elseif Level == 2 then
set BombId = 'n00R'
elseif Level == 3 then
set BombId = 'n00S'
elseif Level == 4 then
set BombId = 'n00T'
else
set BombId = 'n00U'
endif
loop
exitwhen i > tries or (GetUnitState(U, UNIT_STATE_LIFE) <= 0)
// when the Fortress is caught in the Dimension Shift, the Bombs cannot be dropped
// -> wait until it's possible to drop them again (by increasing the maximum number of tries to drop a bomb)
if GetUnitAbilityLevel(U, 'A097')>0 then
set tries = tries + 1
call DebugMsg ("Delay")
else
call DebugMsg ("Drop")
set X = GetUnitX(U)
set Y = GetUnitY(U)
set Z = GetUnitFlyHeight(U)
set Bomb = CreateUnit( GetOwningPlayer(U), BombId, X, Y, bj_UNIT_FACING)
call UnitAddAbility( Bomb, 'Amrf' )
call UnitRemoveAbility( Bomb, 'Amrf' )
call SetUnitFlyHeight(Bomb, Z, 0)
call SetUnitPosition(Bomb, X, Y)
call SetUnitFlyHeight(Bomb, 0, 180)
call UnitApplyTimedLife( Bomb, 'BTLF', BOMB_TIMED_LIFE )
endif
call WaitForGameTime(beginGameTime + (i*DROP_INTERVAL))
set i = i + 1
endloop
set Bomb = null
set U = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterSpellEffectEvent( t, ABILITY_ID )
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=16
//TESH.alwaysfold=0
scope SystemOverload initializer Init
globals
private constant integer ABILITY_ID = 'A09E'
private constant integer BUFF_ID = 'B010'
private constant real SPEED_BASE = 50.0
private constant real SPEED_UP = 0.0
private constant real INTERVAL = 0.05
private constant real ARMOR_INC_INTERVAL = 0.5
constant integer SYSTEM_OVERLOAD_RESISTANCE_ID = 'A0H2'
endglobals
function Trig_System_Overload_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Target = udg_AV_Unit1[LoopTimerId]
local unit Fortress = udg_AV_Unit2[LoopTimerId]
local location TargetLoc = udg_AV_Loc1[LoopTimerId]
local integer level = GetUnitAbilityLevel(Fortress,ABILITY_ID)
local integer armorLevel
local real speed = ( SPEED_BASE + ( level * SPEED_UP ) ) * INTERVAL
local real DistX
local real DistY
local real AngleRad
local real DistanceLeft
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
if GetUnitState(Target, UNIT_STATE_LIFE) <= 0 then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call RemoveLocation(TargetLoc)
call UnitRemoveAbility(Fortress, SYSTEM_OVERLOAD_RESISTANCE_ID)
else
if (GetUnitAbilityLevel(Target, BUFF_ID) > 0) then
if IsAirUnit(Target) then
set DistX = GetLocationX(TargetLoc)-GetUnitX(Target)
set DistY = GetLocationY(TargetLoc)-GetUnitY(Target)
set AngleRad = Atan2(DistY, DistX)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if DistanceLeft >= 200 then
call SetUnitPosition(Target,GetUnitX(Target)+speed*Cos(AngleRad),GetUnitY(Target)+speed*Sin(AngleRad))
endif
endif
set armorLevel = R2I(udg_AV_Int1[LoopTimerId]* INTERVAL / ARMOR_INC_INTERVAL)
if (armorLevel > GetUnitAbilityLevel(Fortress, SYSTEM_OVERLOAD_RESISTANCE_ID)) then
call SetUnitAbilityLevel(Fortress, SYSTEM_OVERLOAD_RESISTANCE_ID, armorLevel)
endif
else
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
call RemoveLocation(TargetLoc)
call UnitRemoveAbility(Fortress, SYSTEM_OVERLOAD_RESISTANCE_ID)
endif
endif
set TargetLoc = null
set Target = null
set Fortress = null
endfunction
function Trig_System_Overload_Actions takes nothing returns nothing
local timer t
local unit U = GetTriggerUnit()
local unit Target = GetSpellTargetUnit()
local location castloc = GetUnitLoc(U)
local real Distance = DistanceBetweenPoints(castloc, GetUnitLoc(Target))
local integer LoopTimerId
// magical resistance
call UnitAddAbility(U, SYSTEM_OVERLOAD_RESISTANCE_ID)
// this should trigger the assist detection and grant an assist, even when you didn't do any damage otherwise
call UnitDamageTarget(U, Target, 0, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Loc1[LoopTimerId] = castloc
set udg_AV_Unit1[LoopTimerId] = Target
set udg_AV_Unit2[LoopTimerId] = U
set udg_AV_Int1[LoopTimerId] = 0
call TimerStart(t, INTERVAL, true, function Trig_System_Overload_Loop)
set U = null
set Target = null
set castloc = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_System_Overload = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_System_Overload, ABILITY_ID )
call TriggerAddAction( gg_trg_System_Overload, function Trig_System_Overload_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ChaosTeleportStart initializer Init
globals
private constant integer ABILITY_ID = 'A04L'
private constant integer TELEPORT_DUMMY_ID = 'h01C'
endglobals
function Trig_Chaos_Teleport_Start_Conditions takes nothing returns boolean
return GetSpellAbilityId() == ABILITY_ID
endfunction
function Trig_Chaos_Teleport_Start_Actions takes nothing returns nothing
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local real beginGameTime = TimerGetElapsed(udg_GameTime)
//call WaitForGameTime(beginGameTime + 0.6)
//call SetUnitAnimation(GetTriggerUnit(), "death")
call KillUnit( CreateUnit( GetOwningPlayer(GetTriggerUnit()), TELEPORT_DUMMY_ID, TargetX, TargetY, 0 ) )
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Chaos_Teleport_Start = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Chaos_Teleport_Start, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_Chaos_Teleport_Start, Condition( function Trig_Chaos_Teleport_Start_Conditions ) )
call TriggerAddAction( gg_trg_Chaos_Teleport_Start, function Trig_Chaos_Teleport_Start_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ChaosTeleport initializer Init
globals
private constant integer ABILITY_ID = 'A04L'
private constant integer STUN_ABILITY_ID = 'A04J'
private constant integer TELEPORT_DUMMY_ID = 'h01C'
endglobals
function Trig_Chaos_Teleport_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local real beginGameTime = TimerGetElapsed(udg_GameTime)
call KillUnit( CreateUnit( GetOwningPlayer(GetTriggerUnit()), TELEPORT_DUMMY_ID, TargetX, TargetY, 0 ) )
call WaitForGameTime(beginGameTime + 0.5)
call DestroyTreesInRange(TargetX, TargetY, 350)
call IssueImmediateOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), STUN_ABILITY_ID, GetUnitAbilityLevel(Caster, ABILITY_ID), TargetX, TargetY, 0), "stomp" )
call SetUnitPosition( Caster, TargetX, TargetY )
call SetUnitAnimation(Caster, "birth")
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Chaos_Teleport = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Chaos_Teleport, ABILITY_ID )
call TriggerAddAction( gg_trg_Chaos_Teleport, function Trig_Chaos_Teleport_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ChaosWave initializer Init
globals
private constant integer ABILITY_ID = 'A03E'
private constant integer EFFECT_ABILITY_ID = 'A08P'
private constant real DAMAGE_BASE = 0.0
private constant real DAMAGE_UP = 450.0
private constant real AREA_BASE = 800.0
private constant real AREA_UP = 0.0
private constant real DELAY = 0.1
endglobals
function Trig_Chaos_Wave_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local integer i = 1
local location P
local integer level = GetUnitAbilityLevel(caster,ABILITY_ID)
local real damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local real X = GetUnitX(caster)
local real Y = GetUnitY(caster)
local unit dummy
loop
exitwhen i > 24
set P = PolarProjectionBJ(GetUnitLoc(caster), 8.00, I2R(i*15))
call IssuePointOrder( CreateDummyWithAbility(GetOwningPlayer(caster), EFFECT_ABILITY_ID, 1, P, 0), "carrionswarm", X+(GetLocationX(P)-X)*4, Y+(GetLocationY(P)-Y)*4 )
call RemoveLocation( P )
set i = i + 1
endloop
call TriggerSleepAction( DELAY )
set udg_Filter_Player = GetOwningPlayer(caster)
call FixedAreaDamageFromUnit(caster, X, Y, area, damage, 1.0, 0, false, FILTER_ENEMY_UNITS)
call DestroyTreesInRange(X, Y, area)
set dummy = null
set P = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Chaos_Wave = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Chaos_Wave, ABILITY_ID )
call TriggerAddAction( gg_trg_Chaos_Wave, function Trig_Chaos_Wave_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ChaosServants initializer Init
globals
private constant integer ABILITY_ID = 'A02C'
private constant integer SERVANT_ID = 'z00K'
private constant integer SUMMON_CHANCE_BASE = 0
private constant integer SUMMON_CHANCE_UP = 2
private constant real DURATION_BASE = 30.0
private constant real DURATION_UP = 0.0
endglobals
function Trig_Chaos_Servant_Conditions takes nothing returns boolean
local integer KillerId = GetUnitTypeId(GetKillingUnit())
local integer Level
local integer chance
if KillerId != SERVANT_ID and (not IsDummy(GetKillingUnit())) and KillerId != 'H00K' then
return false
endif
set Level = GetUnitAbilityLevel(udg_Tank[GetPlayerNr(GetOwningPlayer(GetKillingUnit()))],ABILITY_ID)
set chance = SUMMON_CHANCE_BASE + ( Level * SUMMON_CHANCE_UP )
if Level <= 0 then
return false
endif
return GetRandomInt(1, 100) <= chance
endfunction
function Trig_Chaos_Servant_Actions takes nothing returns nothing
local unit Servant
local integer level = GetUnitAbilityLevel(udg_Tank[GetPlayerNr(GetOwningPlayer(GetKillingUnit()))],ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
local real X = GetUnitX(GetTriggerUnit())
local real Y = GetUnitY(GetTriggerUnit())
if IsUnitType(GetTriggerUnit(),UNIT_TYPE_STRUCTURE) == false then
set Servant = CreateUnit(GetOwningPlayer(GetKillingUnit()), SERVANT_ID, X, Y, 270)
call UnitApplyTimedLife(Servant, 'BTLF', duration)
call IssuePointOrderLoc( Servant, "attack", udg_Move_Points[GetTargetMovePoint(Servant)] )
set Servant = null
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Chaos_Servant = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Chaos_Servant, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Chaos_Servant, Condition( function Trig_Chaos_Servant_Conditions ) )
call TriggerAddAction( gg_trg_Chaos_Servant, function Trig_Chaos_Servant_Actions )
endfunction
endscope
//TESH.scrollpos=18
//TESH.alwaysfold=0
scope InfernalFireRain initializer Init
globals
private constant integer ABILITY_ID = 'A08Y'
private constant integer SLOW_ABILITY_ID = 'A00Q'
private constant integer SLOW_BUFF_ID = 'B00O'
private constant integer WAVE_COUNT_BASE = 5
private constant integer WAVE_COUNT_UP = 0
private constant real DAMAGE_BASE = 480.0 // damage per wave
private constant real DAMAGE_UP = 160.0
private constant real AREA_BASE = 900.0
private constant real AREA_UP = 0.0
private constant real BUILDING_DAMAGE_FACTOR = 0.5
private constant real WAVE_DELAY = 1.0
endglobals
function Trig_Infernal_Fire_Rain_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real Damage = DAMAGE_BASE + ( level * DAMAGE_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local real beginGameTime = TimerGetElapsed(udg_GameTime)
local group Targets = NewGroup()
local unit U
local integer CountWaves = WAVE_COUNT_BASE + ( level * WAVE_COUNT_UP )
local integer Wave = 1
call IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), SLOW_ABILITY_ID, 1, GetUnitX(Caster), GetUnitY(Caster), 0), "slow", Caster)
loop
exitwhen ((Wave > CountWaves) or (GetUnitState(Caster, UNIT_STATE_LIFE) <= 0) or IsUnitStunned(Caster))
set udg_Filter_Player = GetOwningPlayer(Caster)
call GroupEnumUnitsInRange(Targets,GetUnitX(Caster),GetUnitY(Caster),area, FILTER_VISIBLE_ENEMY_UNITS)
loop
set U=FirstOfGroup(Targets)
exitwhen U==null
if IsUnitType(U, UNIT_TYPE_STRUCTURE)==true then
call UnitDamageTarget(Caster,U,Damage*BUILDING_DAMAGE_FACTOR,true,false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
else
call UnitDamageTarget(Caster,U,Damage,true,false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
endif
call DestroyEffect(AddSpecialEffectTarget( "Units\\Demon\\Infernal\\InfernalBirth.mdl", U, "origin" ))
call GroupRemoveUnit(Targets,U)
endloop
if Wave!=CountWaves then
call WaitForGameTime(beginGameTime+(I2R(Wave)*WAVE_DELAY))
endif
set Wave = Wave + 1
endloop
if (GetUnitState(Caster, UNIT_STATE_LIFE) > 0) then
call UnitRemoveAbility(Caster, SLOW_BUFF_ID)
endif
call ReleaseGroup(Targets)
set Caster = null
set Targets = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Infernal_Fire_Rain = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Infernal_Fire_Rain, ABILITY_ID )
call TriggerAddAction( gg_trg_Infernal_Fire_Rain, function Trig_Infernal_Fire_Rain_Actions )
endfunction
endscope
//TESH.scrollpos=155
//TESH.alwaysfold=0
scope Obelisk initializer Init
globals
private constant integer ABILITY_ID = 'A0C6'
private constant integer BUFF_ABILITY_ID = 'A03X'
private constant integer BUFF_ID = 'B02R'
private constant string CPTP_ORDER = "spies"
private constant real COOLDOWN_BASE = 8.0 // the cooldown of the pullback
private constant real COOLDOWN_UP = -1.0
private constant real AREA_BASE = 900.0 // the area in which the obelisk checks for targets leaving it, to pull them back
private constant real AREA_UP = 0.0
private constant real PULL_DURATION_BASE = 2.0 // the time it takes to pull the target back to the obelisk
private constant real PULL_DURATION_UP = 0.0
private constant real DISTANCE = 300.0 // the distance between target and obelisk after the pull
private constant real DURATION = 15.0
private constant real ACTIVATION_DELAY = 1.0
private constant real CHECK_INTERVAL = 0.25
private constant real PULL_INTERVAL = 0.02
endglobals
private function Conditions takes nothing returns boolean
return IsObelisk(GetConstructingStructure()) > 0
endfunction
function Trig_Lightning_Obelisk_SearchFilter takes nothing returns boolean
return Filter_EnemyTank() and OrderId2String(GetUnitCurrentOrder(GetFilterUnit())) != CPTP_ORDER
endfunction
function Trig_Lightning_Obelisk_Pull takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit target = udg_AV_Unit1[LoopTimerId]
local real targetX = udg_AV_Real1[LoopTimerId]
local real targetY = udg_AV_Real2[LoopTimerId]
local real speed = udg_AV_Real3[LoopTimerId]
local real DistX
local real DistY
local real AngleRad
local real DistanceLeft
local real level = udg_AV_Int2[LoopTimerId]
local real duration = PULL_DURATION_BASE + (level * PULL_DURATION_UP)
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
if (GetUnitState(target, UNIT_STATE_LIFE) <= 0) or (GetUnitAbilityLevel(target, 'Avul') > 0) or (udg_AV_Int1[LoopTimerId] * PULL_INTERVAL >= duration) then
call SetUnitPathing(target, true)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set DistX = targetX-GetUnitX(target)
set DistY = targetY-GetUnitY(target)
set AngleRad = Atan2(DistY, DistX)
set DistanceLeft = SquareRoot(DistX*DistX+DistY*DistY)
if DistanceLeft > speed then
call IssueImmediateOrder(target, "stop")
call SetUnitX(target, GetUnitX(target)+speed*Cos(AngleRad))
call SetUnitY(target, GetUnitY(target)+speed*Sin(AngleRad))
else
call SetUnitPathing(target, true)
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endif
endif
set target = null
endfunction
function Trig_Lightning_Obelisk_PullBack takes unit target, unit obelisk returns nothing
local timer t
local integer LoopTimerId
local integer level = IsObelisk(obelisk)
local real facerad = GetUnitsAngleDeg(obelisk, target)* bj_DEGTORAD
local location targetLoc = Location(GetUnitX(obelisk) + DISTANCE * Cos(facerad), GetUnitY(obelisk) + DISTANCE * Sin(facerad))
local real duration = PULL_DURATION_BASE + (level * PULL_DURATION_UP)
local real totalDistance
local real pullSpeed
local integer i = 0
// the call of GetPathableLoc actually moves the given location, if it isn't pathable to a pathable location
loop
exitwhen GetPathableLoc(targetLoc , 32 , 768) or (i > 10)
call MoveLocation(targetLoc, GetLocationX(targetLoc) - 100 * Cos(facerad), GetLocationY(targetLoc) - 100 * Sin(facerad))
set i = i + 1
endloop
call DestroyEffect(AddSpecialEffectLoc("Doodads\\Cinematic\\GlowingRunes\\GlowingRunes8.mdl",targetLoc))
call Lightning.CreateUU("AFOD", obelisk, target, false, true, duration)
set totalDistance = GetXYDistance(GetUnitX(target), GetUnitY(target), GetLocationX(targetLoc), GetLocationY(targetLoc))
set pullSpeed = (totalDistance / (duration)) * PULL_INTERVAL
call IssueTargetOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(obelisk), BUFF_ABILITY_ID, 1, GetUnitX(target), GetUnitY(target), 0), "slow", target )
call SetUnitPathing(target, false)
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = target
set udg_AV_Real1[LoopTimerId] = GetLocationX(targetLoc)
set udg_AV_Real2[LoopTimerId] = GetLocationY(targetLoc)
set udg_AV_Real3[LoopTimerId] = pullSpeed
set udg_AV_Int1[LoopTimerId] = 0
set udg_AV_Int2[LoopTimerId] = level
call TimerStart(t , PULL_INTERVAL , true , function Trig_Lightning_Obelisk_Pull)
call RemoveLocation(targetLoc)
set targetLoc = null
endfunction
function Trig_Lightning_Obelisk_Check takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit tower = udg_AV_Unit1[LoopTimerId]
local integer level = udg_AV_Int1[LoopTimerId]
local real lastCast = udg_AV_Real1[LoopTimerId]
local real cooldown = COOLDOWN_BASE + ( level * COOLDOWN_UP )
local real area = AREA_BASE + ( level * AREA_UP )
local boolean cptpOrder
local group G
local unit temp
if ( GetUnitState(tower , UNIT_STATE_LIFE) <= 0 ) or ( tower == null ) then
call ReleaseGroup(udg_AV_Group1[LoopTimerId])
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(tower)
call GroupEnumUnitsInRange(G, GetUnitX(tower),GetUnitY(tower), area, Condition(function Trig_Lightning_Obelisk_SearchFilter) )
// Remove all units that are currently around the obelisk (group G) from the group of the last time step
// Any unit that remains is a unit that was around the obelisk, but currently isn't anymore -> the unit left the area around the obelisk
call GroupRemoveGroup(G, udg_AV_Group1[LoopTimerId])
loop
set temp = FirstOfGroup(udg_AV_Group1[LoopTimerId])
exitwhen (temp == null)
if (GetUnitState(temp , UNIT_STATE_LIFE) > 0) then
set cptpOrder = OrderId2String(GetUnitCurrentOrder(temp)) == CPTP_ORDER
if (lastCast + cooldown <= TimerGetElapsed(udg_GameTime)) and (GetUnitAbilityLevel(temp, BUFF_ID) == 0) and not (cptpOrder) then
call Trig_Lightning_Obelisk_PullBack(temp, tower)
set udg_AV_Real1[LoopTimerId] = TimerGetElapsed(udg_GameTime)
exitwhen true
endif
endif
call GroupRemoveUnit(udg_AV_Group1[LoopTimerId], temp)
endloop
call GroupClear(udg_AV_Group1[LoopTimerId])
call GroupAddGroup(G, udg_AV_Group1[LoopTimerId])
call ReleaseGroup(G)
set G = null
endif
set tower = null
set temp = null
endfunction
function Trig_Lightning_Obelisk_Actions takes nothing returns nothing
local unit Tower = GetConstructingStructure()
local unit caster = GetTriggerUnit()
local integer lvl = GetUnitAbilityLevel(caster, ABILITY_ID)
local real area = AREA_BASE + ( lvl * AREA_UP )
local integer i = 1
local effect array effects
local string RuneEffect = ""
local timer t
local integer LoopTimerId
local integer LifeTime = R2I(DURATION)
call DebugMsg("Titan: Ligthning Obelisk")
call UnitApplyTimedLife(Tower, 'B015', LifeTime)
call SetUnitVertexColor( Tower, 0, 0, 0, 255 )
if IsPlayerAlly(GetLocalPlayer(), GetOwningPlayer(Tower)) then
set RuneEffect = "Doodads\\Cinematic\\GlowingRunes\\GlowingRunes1.mdl"
else
set RuneEffect = "Doodads\\Cinematic\\GlowingRunes\\GlowingRunes0.mdl"
endif
call GameTimeWait(ACTIVATION_DELAY)
call SetUnitVertexColor( Tower, 255, 255, 255, 255 )
loop
exitwhen i > 18
set effects[i] = AddSpecialEffect(RuneEffect,PolarProjX(GetUnitX(Tower), area, i*20), PolarProjY(GetUnitY(Tower), area, i*20))
set i = i + 1
endloop
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Tower
set udg_AV_Real1[LoopTimerId] = 0
set udg_AV_Int1[LoopTimerId] = lvl
set udg_AV_Group1[LoopTimerId] = NewGroup()
call TimerStart(t , CHECK_INTERVAL , true , function Trig_Lightning_Obelisk_Check)
loop
exitwhen ((Tower == null) or (GetUnitState(Tower, UNIT_STATE_LIFE) == 0))
call GameTimeWait( 0.5 )
endloop
set i = 1
loop
exitwhen i > 18
call DestroyEffect(effects[i])
set effects[i] = null
set i = i + 1
endloop
set caster = null
set Tower = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Lightning_Obelisk = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_Lightning_Obelisk, EVENT_PLAYER_UNIT_CONSTRUCT_START)
call TriggerAddAction( gg_trg_Lightning_Obelisk, function Trig_Lightning_Obelisk_Actions )
call TriggerAddCondition(gg_trg_Lightning_Obelisk, Condition( function Conditions))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DevilFire initializer Init
globals
private constant integer ABILITY_ID = 'A08V'
private constant integer EFFECT_ID = 'A08O'
private constant real AREA_BASE = 900.0
private constant real AREA_UP = 0.0
private constant real DAMAGE_BASE = 0.0 // total damage
private constant real DAMAGE_UP = 1000.0
private constant real DURATION_BASE = 3.0
private constant real DURATION_UP = 0.0
private constant real INTERVAL = 0.1
endglobals
function Trig_Devil_Fire_Loop takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit Caster = udg_AV_Unit1[LoopTimerId]
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real Range = AREA_BASE + ( level * AREA_UP )
local real Duration = DURATION_BASE + ( level * DURATION_UP )
local real Damage = (DAMAGE_BASE + ( level * DAMAGE_UP )) / ( Duration / INTERVAL )
local real CurrentAngle = 360.0 / udg_AV_Real1[LoopTimerId] * I2R(udg_AV_Int1[LoopTimerId])
local real LineSpace = 360.0 / udg_AV_Real1[LoopTimerId] * 5.0
local real LineAngle
local real CasterX = udg_AV_Real2[LoopTimerId]
local real CasterY = udg_AV_Real3[LoopTimerId]
local real X
local real Y
local real CountLines = 0
if (udg_AV_Int1[LoopTimerId] >= (Duration / INTERVAL)) then
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
else
set X = CasterX+Range*Cos(CurrentAngle*bj_DEGTORAD)
set Y = CasterY+Range*Sin(CurrentAngle*bj_DEGTORAD)
call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", X, Y))
if (ModuloInteger(udg_AV_Int1[LoopTimerId], 5) == 0) then
set LineAngle = 90+18
loop
exitwhen CountLines>=5
set LineAngle = LineAngle + 180 - 36
set X = CasterX - Range*Cos((LineAngle-18)*bj_DEGTORAD)
set Y = CasterY - Range*Sin((LineAngle-18)*bj_DEGTORAD)
set X = X+udg_AV_Int1[LoopTimerId]*LineSpace*Cos(LineAngle*bj_DEGTORAD)
set Y = Y+udg_AV_Int1[LoopTimerId]*LineSpace*Sin(LineAngle*bj_DEGTORAD)
call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", X, Y))
set CountLines = CountLines + 1
endloop
endif
set udg_Filter_Player = GetOwningPlayer(Caster)
call FixedAreaDamageFromUnit(Caster, CasterX, CasterY, Range, Damage, 0.5, 0, false, FILTER_ENEMY_GROUND_UNIT)
set udg_AV_Int1[LoopTimerId] = udg_AV_Int1[LoopTimerId] + 1
endif
set Caster = null
endfunction
function Trig_Devil_Fire_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local real CasterX = GetUnitX(Caster)
local real CasterY = GetUnitY(Caster)
local integer level = GetUnitAbilityLevel(Caster,ABILITY_ID)
local real Range = AREA_BASE + ( level * AREA_UP )
local real Duration = DURATION_BASE + ( level * DURATION_UP )
local timer t
local integer LoopTimerId
call DebugMsg("Titan: Devil Fire")
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = Caster
set udg_AV_Int1[LoopTimerId] = 0
set udg_AV_Real1[LoopTimerId] = Duration / INTERVAL
set udg_AV_Real2[LoopTimerId] = CasterX
set udg_AV_Real3[LoopTimerId] = CasterY
call TimerStart(t , INTERVAL , true , function Trig_Devil_Fire_Loop)
call ShowEffectAtPos("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",CasterX, CasterY, 0, 5, Duration)
call DestroyTreesInRange(CasterX, CasterY, Range)
set Caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Devil_Fire = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Devil_Fire, ABILITY_ID )
call TriggerAddAction( gg_trg_Devil_Fire, function Trig_Devil_Fire_Actions )
endfunction
endscope
//TESH.scrollpos=4
//TESH.alwaysfold=0
scope UnstableProjectiles initializer Init
globals
private constant integer ABILITY_ID = 'A08J'
private constant integer CHANCE_BASE = 0
private constant integer CHANCE_UP = 5
private constant real DAMAGE_BASE = 2000.0
private constant real DAMAGE_UP = 0.0
private constant real AREA_BASE = 300.0
private constant real AREA_UP = 0.0
private constant real DELAY = 0.1
endglobals
function Trig_Unstable_Projectiles_Conditions takes nothing returns boolean
local integer Level = GetUnitAbilityLevel(GetKillingUnit(), ABILITY_ID)
local integer chance = CHANCE_BASE + ( Level * CHANCE_UP )
if Level<=0 then
return false
endif
return GetRandomInt(1, 100) <= chance
endfunction
function Trig_Unstable_Projectiles_Actions takes nothing returns nothing
local unit caster = GetKillingUnit()
local real X = GetUnitX(GetTriggerUnit())
local real Y = GetUnitY(GetTriggerUnit())
local integer Level = GetUnitAbilityLevel(caster, ABILITY_ID)
local real area = AREA_BASE + ( Level * AREA_UP )
local real damage = DAMAGE_BASE + ( Level * DAMAGE_UP )
call DebugMsg("Titan: Unstable Projectiles")
call TriggerSleepAction( DELAY )
call DestroyEffect(AddSpecialEffect( "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", X, Y ) )
call DestroyTreesInRange(X,Y,area)
set udg_Filter_Player = GetOwningPlayer(caster)
call FixedAreaDamageFromUnit(caster, X, Y, area, damage, 1, 0, false, FILTER_ENEMY_UNITS)
set caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Unstable_Projectiles = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Unstable_Projectiles, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Unstable_Projectiles, Condition( function Trig_Unstable_Projectiles_Conditions ) )
call TriggerAddAction( gg_trg_Unstable_Projectiles, function Trig_Unstable_Projectiles_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope OrbitalStrike initializer Init
globals
private constant integer ABILITY_ID = 'A0C7'
private constant integer STUN_ID = 'A0C8'
private constant integer ORBITAL_DUMMY_ID = 'h02G'
private constant real AREA_BASE = 500.0
private constant real AREA_UP = 0.0
private constant real AREA_CENTER_BASE = 250.0
private constant real AREA_CENTER_UP = 0.0
private constant real FULL_DAMAGE_BASE = 0.0
private constant real FULL_DAMAGE_UP = 1000.0
private constant real DELAY_BASE = 1.2
private constant real DELAY_UP = 0.0
endglobals
function Trig_Orbital_Strike_FinalEffect takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
local unit caster = udg_AV_Unit1[LoopTimerId]
local unit dummy = udg_AV_Unit2[LoopTimerId]
local integer level = udg_AV_Int1[LoopTimerId]
local real TargetX = udg_AV_Real1[LoopTimerId]
local real TargetY = udg_AV_Real2[LoopTimerId]
local real area = AREA_BASE + ( level * AREA_UP )
local real areaCenter = AREA_CENTER_BASE + ( level * AREA_CENTER_UP )
local real damage = (FULL_DAMAGE_BASE + ( level * FULL_DAMAGE_UP ))/2.0
local integer i = 0
// this is not a normal dummy, so don't recycle it!
call KillUnit(dummy)
call IssueImmediateOrder( CreateDummyWithAbilityCoord(GetOwningPlayer(caster), STUN_ID, level, TargetX, TargetY, 0), "stomp" )
set udg_Filter_Player = GetOwningPlayer(caster)
call FixedAreaDamageFromUnit(caster, TargetX, TargetY, area , damage, 1, 0, false, FILTER_ENEMY_UNITS)
call FixedAreaDamageFromUnit(caster, TargetX, TargetY, areaCenter, damage, 1, 0, false, FILTER_ENEMY_UNITS)
call DestroyTreesInRange(TargetX, TargetY, area)
set caster = null
set dummy = null
endfunction
function Trig_Orbital_Strike_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local real TargetX = GetSpellTargetX()
local real TargetY = GetSpellTargetY()
local integer level = GetUnitAbilityLevel(caster, ABILITY_ID)
local real area = AREA_BASE + ( level * AREA_UP )
local real delay = DELAY_BASE + ( level * DELAY_UP )
local real X
local real Y
local timer t
local integer LoopTimerId
local unit dummy = CreateUnit( GetOwningPlayer(caster), ORBITAL_DUMMY_ID, TargetX, TargetY, 90 )
call SetUnitPathing(dummy,false)
call SetUnitTimeScale( dummy, 1.6 )
call DebugMsg("Titan: Orbital Strike")
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_Unit1[LoopTimerId] = caster
set udg_AV_Real1[LoopTimerId] = TargetX
set udg_AV_Real2[LoopTimerId] = TargetY
set udg_AV_Int1[LoopTimerId] = level
set udg_AV_Int2[LoopTimerId] = 0
call TimerStart(t , delay , false , function Trig_Orbital_Strike_FinalEffect)
set caster = null
set dummy = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Orbital_Strike = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Orbital_Strike, ABILITY_ID )
call TriggerAddAction( gg_trg_Orbital_Strike, function Trig_Orbital_Strike_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope KeepOnFighting initializer Init
globals
private constant integer ABILITY_ID = 'A0CI'
private constant integer BUFF_ABILITY_ID = 'A0CJ'
private constant integer BUFF_ID = 'B00P'
private constant real HP_THRESHOLD_BASE = 0.25 // in percent
private constant real HP_THRESHOLD_UP = 0.0
private constant real DURATION_BASE = 2.4
private constant real DURATION_UP = 0.8
private constant real HEAL_BASE = 500.0 // heal per second
private constant real HEAL_UP = 0.0
private integer array KoF_StackCount[10] // counts how many instances of this ability are active on a single unit
private integer DD_ID
endglobals
function Trig_Keep_On_Fighting_DamageDetection takes nothing returns real
local integer level = GetUnitAbilityLevel(DamageDetection_DamageTarget, BUFF_ID)
local real CurrentLife = GetUnitState(DamageDetection_DamageTarget, UNIT_STATE_LIFE)
local real MaxLife = GetUnitState(DamageDetection_DamageTarget, UNIT_STATE_MAX_LIFE)
if level > 0 then
if CurrentLife-DamageDetection_Damage < (MaxLife*(HP_THRESHOLD_BASE + ( level * HP_THRESHOLD_UP))) then
// the damage system interprets postive values as additional damage and negative ones as reduced damage
// -1 = no damage at all
return -1.0
endif
endif
return 0.0
endfunction
function Trig_Keep_On_Fighting_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local integer casterId = GetPlayerNr(GetOwningPlayer(caster))
local integer targetId = GetPlayerNr(GetOwningPlayer(target))
local integer level = GetUnitAbilityLevel(caster,ABILITY_ID)
local real duration = DURATION_BASE + ( level * DURATION_UP )
local real heal = (HEAL_BASE + ( level * HEAL_UP )) * duration
call DebugMsg("Titan: Keep On Fighting")
call UnitAddAbility(target, BUFF_ABILITY_ID)
set KoF_StackCount[targetId] = KoF_StackCount[targetId] + 1
//call HealOverTime(target, heal, 0, duration, BUFF_ID, false)
if (caster != target) then
call UnitAddAbility(caster, BUFF_ABILITY_ID)
set KoF_StackCount[casterId] = KoF_StackCount[casterId] + 1
//call HealOverTime(caster, heal, 0, duration, BUFF_ID, false)
endif
call EnableSkillDamageDetection(DD_ID)
call GameTimeWait( duration )
call DisableSkillDamageDetection(DD_ID)
set KoF_StackCount[targetId] = KoF_StackCount[targetId] - 1
if (KoF_StackCount[targetId] <= 0) then
set KoF_StackCount[targetId] = 0 // only in case it is actually lower (which should not be possible, but you never know)
call UnitRemoveAbility(target, BUFF_ABILITY_ID)
call UnitRemoveAbility(target, BUFF_ID)
endif
if (caster != target) then
set KoF_StackCount[casterId] = KoF_StackCount[casterId] - 1
if (KoF_StackCount[casterId] <= 0) then
set KoF_StackCount[casterId] = 0 // only in case it is actually lower (which should not be possible, but you never know)
call UnitRemoveAbility(caster, BUFF_ABILITY_ID)
call UnitRemoveAbility(caster, BUFF_ID)
endif
endif
set caster = null
set target = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Keep_On_Fighting = CreateTrigger( )
set DD_ID = RegisterDamageDetectionCodeRelative(DamageAlterationFunction.Trig_Keep_On_Fighting_DamageDetection)
call TriggerRegisterSpellEffectEvent( gg_trg_Keep_On_Fighting, ABILITY_ID )
call TriggerAddAction( gg_trg_Keep_On_Fighting, function Trig_Keep_On_Fighting_Actions )
endfunction
endscope
//TESH.scrollpos=6
//TESH.alwaysfold=0
function Trig_CP_Teleport_Start_Conditions takes nothing returns boolean
//CP-Teleport for tanks and CP-Teleport for the Tech Mech
return GetSpellAbilityId() == 'A06C' or GetSpellAbilityId() == 'A0B4'
endfunction
function Trig_CP_Teleport_Start_Actions takes nothing returns nothing
local location P = GetSpellTargetLoc()
local unit Tank = GetTriggerUnit()
local player Owner = GetOwningPlayer(Tank)
local string Error
local boolean ValidTeleport = false
local string s = "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl"
local integer Costs = 75
local unit u
local real x
local real y
local real face
local group g = NewGroup()
//if the target loc is more than 450 units away from the nearest CP, the target loc will be moved into range
//set P = MoveTargetLocInRange(Tank, P)
call MoveTargetLocInRange(Tank, P)
// Make sure, that the location is pathable
//call GetPathableLoc(P, 32, 768)
set x = GetUnitX(tempControlPoint)
set y = GetUnitY(tempControlPoint)
set face = Atan2(y - GetLocationY(P), x - GetLocationX(P))
loop
exitwhen GetPathableLoc(P, 32, 50) and IsTerrainWalkable(GetLocationX(P), GetLocationY(P))
call MoveLocation(P, GetLocationX(P) + 50 * Cos(face), GetLocationY(P) + 50 * Sin(face))
endloop
//The Control Point Teleport for the Tech Mech (A0B4) doesn't cost anything
if (GetSpellAbilityId() == 'A0B4') or IsFreeTeleport(Tank, P) then
set Costs = 0
endif
if (GetPlayerState( Owner, PLAYER_STATE_RESOURCE_GOLD ) < Costs) then
call IssueImmediateOrder( Tank, "stop" )
call DisplayTextToPlayer(Owner, 0, 0, "|cfffed312You do not have enough gold to teleport.|r" )
else
set Error = Get_CP_Teleport_Msg(Tank, GetLocationX(P), GetLocationY(P))
if Error == null then
set ValidTeleport = true
else
call IssueImmediateOrder( Tank, "stop" )
call DisplayTextToPlayer(Owner, 0, 0, Error )
set Error = null
endif
endif
//set ValidTeleport = IsTerrainPathable(GetLocationX(P), GetLocationY(P), PATHING_TYPE_BUILDABILITY)
if ValidTeleport then
//To make sure, that the AI recognizes the teleport of others
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(Tank), DUMMY_ID, GetLocationX(P), GetLocationY(P), 270)
set Costs = GetBounty(Tank, false)
call SetUnitState(bj_lastCreatedUnit, UNIT_STATE_LIFE, Costs)
call UnitApplyTimedLife( bj_lastCreatedUnit, 'BTLF', 2.00 )
if IsPlayerEnemy(GetLocalPlayer(), Owner ) then
set s = ""
endif
//Only show the special effect when a tank is teleporting
if GetSpellAbilityId() == 'A06C' then
call DestroyEffect( AddSpecialEffect( s, GetLocationX(P), GetLocationY(P) ) )
call GroupEnumLocustsInRange(g,x,y,200.,FILTER_CPTPGLOW)
if GetUnitTypeId(tempControlPoint) == 'h00P' and FirstOfGroup(g) == null then
set u = CreateUnit(Owner,'h01X',x,y,0.)
call SetUnitPathing(u,false)
call SetUnitX(u,x)
call SetUnitY(u,y)
call SetUnitScale(u,5.5,5.5,5.5)
call SetUnitVertexColor(u, 255, 255, 255, 200)
call UnitApplyTimedLife(u, 'BTLF', 1.5)
call Pala.TimedUnitRemoval(u,2.)
endif
endif
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(Tank), GetUnitY(Tank) ) )
call GameTimeWait( 1.25 )
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(Tank), GetUnitY(Tank) ) )
endif
call RemoveLocation( P )
call ReleaseGroup(g)
set g = null
set P = null
set Owner = null
set Tank = null
set u = null
endfunction
//===========================================================================
function InitTrig_CP_Teleport_Start takes nothing returns nothing
set gg_trg_CP_Teleport_Start = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_CP_Teleport_Start, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_CP_Teleport_Start, Condition( function Trig_CP_Teleport_Start_Conditions ) )
call TriggerAddAction( gg_trg_CP_Teleport_Start, function Trig_CP_Teleport_Start_Actions )
endfunction
//TESH.scrollpos=42
//TESH.alwaysfold=0
function Trig_CP_Teleport_ActivateBeacon takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer TimerIndex = GetHandleIndex(t)
local unit beacon = udg_AV_Unit1[TimerIndex]
call UnitAddType(beacon, UNIT_TYPE_TOWNHALL)
call SetUnitVertexColor( beacon, 255, 255, 255, 255 )
call SetUnitTimeScale(beacon, 1)
call ReleaseHandleIndex(TimerIndex)
call ReleaseTimer(t)
set beacon = null
endfunction
function Trig_CP_Teleport_DeactivateBeacon takes unit beacon, player p returns nothing
local timer t
local integer TimerIndex
if (GetUnitTypeId(beacon) == 'o003') and IsUnitAlly(beacon, p) then
call UnitRemoveType(beacon, UNIT_TYPE_TOWNHALL)
call SetUnitVertexColor( beacon, 50, 50, 50, 255 )
call SetUnitTimeScale(beacon, 0)
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = beacon
call TimerStart(t, 4.00, false, function Trig_CP_Teleport_ActivateBeacon)
endif
endfunction
function Trig_CP_Teleport_Actions takes nothing returns nothing
local unit Tank = GetTriggerUnit()
local location P = GetSpellTargetLoc()
local string Error
local integer Costs = 75
local unit drone
local real x
local real y
local real face
//if the target loc is more than 450 units away from the nearest CP, the target loc will be moved into range
//set P = MoveTargetLocInRange(Tank, P)
call MoveTargetLocInRange(Tank, P)
// Make sure, that the location is pathable
//call GetPathableLoc(P, 32, 768)
set x = GetUnitX(tempControlPoint)
set y = GetUnitY(tempControlPoint)
set face = Atan2(y - GetLocationY(P), x - GetLocationX(P))
loop
exitwhen GetPathableLoc(P, 32, 50) and IsTerrainWalkable(GetLocationX(P), GetLocationY(P))
call MoveLocation(P, GetLocationX(P) + 50 * Cos(face), GetLocationY(P) + 50 * Sin(face))
endloop
//The Control Point Teleport for the Tech Mech doesn't cost anything
if (GetSpellAbilityId() == 'A0B4') or IsFreeTeleport(Tank, P) then
set Costs = 0
endif
//call TriggerSleepAction( 0.00 )
set Error = Get_CP_Teleport_Msg(Tank, GetLocationX(P), GetLocationY(P))
if Error != null then
call IssueImmediateOrder( Tank, "stop" )
call DisplayTextToPlayer(GetOwningPlayer(Tank), 0, 0, Error )
set Error = null
elseif GetUnitState(Tank, UNIT_STATE_LIFE) > 0 then
if GetPlayerState( GetOwningPlayer(Tank), PLAYER_STATE_RESOURCE_GOLD ) < Costs then
call IssueImmediateOrder( Tank, "stop" )
call DisplayTextToPlayer(GetOwningPlayer(Tank), 0, 0, "|cfffed312You do not have enough gold to teleport.|r" )
else
call SetPlayerState(GetOwningPlayer(Tank), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetOwningPlayer(Tank), PLAYER_STATE_RESOURCE_GOLD) - Costs)
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(Tank), GetUnitY(Tank) ) )
//call SetUnitPositionLoc( Tank, P )
call SetUnitX(Tank, GetLocationX(P))
call SetUnitY(Tank, GetLocationY(P))
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(Tank), GetUnitY(Tank) ) )
set CPTeles[GetPlayerId(GetOwningPlayer(Tank))] = CPTeles[GetPlayerId(GetOwningPlayer(Tank))] + 1
call Trig_CP_Teleport_DeactivateBeacon(tempControlPoint, GetOwningPlayer(Tank))
endif
endif
call RemoveLocation( P )
set P = null
set Tank = null
set drone = null
endfunction
//===========================================================================
function InitTrig_CP_Teleport takes nothing returns nothing
set gg_trg_CP_Teleport = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_CP_Teleport, 'A06C' )
call TriggerRegisterSpellEffectEvent( gg_trg_CP_Teleport, 'A0B4' )
call TriggerAddAction( gg_trg_CP_Teleport, function Trig_CP_Teleport_Actions )
endfunction
//TESH.scrollpos=47
//TESH.alwaysfold=0
library DeactiTeleItem requires PvJass
function DisableTeleporter takes unit U, real duration returns nothing
local item tele
local integer i = 0
local integer j = 0
local integer PlayerId
local integer itemID
local real ItemLife
//deactivate
loop
exitwhen i > 5
set itemID = GetItemTypeId(UnitItemInSlot(U, i))
//speed pack,teleporter,traderhunterpack,ultimatepack,
if itemID == 'I012' or itemID == 'I014' or itemID == 'I00L' or itemID == 'I01J' then
set ItemLife = GetWidgetLife(UnitItemInSlot(U, i))
call RemoveItem(UnitItemInSlot(U, i))
call UnitAddItemToSlotById(U, 'I01Q', i)
call SetWidgetLife(UnitItemInSlot(U, i), ItemLife)
endif
set i = i + 1
endloop
call GameTimeWait(duration)
set i = 0
set PlayerId = GetPlayerNr(GetOwningPlayer(U))
//activate the weapon again
loop
exitwhen i > 5
if GetItemTypeId(UnitItemInSlot(U, i)) == 'I01Q' then
if GetWidgetLife(UnitItemInSlot(U, i)) == 6000 then
set itemID = 'I012'
elseif GetWidgetLife(UnitItemInSlot(U, i)) == 3000 then
set itemID = 'I014'
elseif GetWidgetLife(UnitItemInSlot(U, i)) == 4250 then
set itemID = 'I00L'
elseif GetWidgetLife(UnitItemInSlot(U, i)) == 11000 then
set itemID = 'I01J'
endif
call RemoveItem(UnitItemInSlot(U, i))
if GetUnitState(U, UNIT_STATE_LIFE) > 0 then
set tele = UnitAddItemById( U, itemID)
call SetItemPlayer( tele, GetOwningPlayer(U), false )
if udg_Afk[PlayerId] then
call SetItemDroppable( tele, false )
endif
else
//when the tank is dead, give the weapon to him, after he revives
//therefore, save the weapon in an array
set j = 1
loop
exitwhen j == 0
if udg_Item_CreateForHero[(PlayerId - 1) * 6 + j] == null or udg_Item_CreateForHero[(PlayerId - 1) * 6 + j] == 0 then
set udg_Item_CreateForHero[(PlayerId - 1) * 6 + j] = itemID
set j = 0
else
set j = j + 1
endif
endloop
endif
endif
set i = i + 1
endloop
set U = null
set tele = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DestroyTowers initializer Init
private function Actions takes nothing returns nothing
if (GetSpellAbilityId() == 'A058') or (GetSpellAbilityId() == 'A0GN') then
call KillUnit(GetTriggerUnit())
endif
if GetSpellAbilityId() == 'A01R' then
//Check if there are still unit porting to this portal
if (udg_AV_Int2[GetHandleIndex(GetTriggerUnit())] > 0) then
//with this boolean set to true, this portal will be destroyed, when the last unit finished it's teleport (new ports are not allowed)
set udg_AV_Bool1[GetHandleIndex(GetTriggerUnit())] = true
call DisplayTextToPlayer(GetOwningPlayer(GetTriggerUnit()), 0, 0, "|cfffed312This portal will be destroyed soon.|r" )
else
call KillUnit(GetTriggerUnit())
endif
endif
endfunction
private function Init takes nothing returns nothing
set gg_trg_Destroy_Towers_Mines_and_Portals = CreateTrigger()
call TriggerRegisterSpellEffectEvent( gg_trg_Destroy_Towers_Mines_and_Portals, 'A058' )
call TriggerRegisterSpellEffectEvent( gg_trg_Destroy_Towers_Mines_and_Portals, 'A01R' )
call TriggerRegisterSpellEffectEvent( gg_trg_Destroy_Towers_Mines_and_Portals, 'A0GN' )
call TriggerAddAction( gg_trg_Destroy_Towers_Mines_and_Portals, function Actions )
endfunction
endscope
//TESH.scrollpos=6
//TESH.alwaysfold=0
globals
constant integer CPTP_DISABLE_ABILITY_ID = 'A0GL'
endglobals
function Trig_Factory_Heal_Actions takes nothing returns nothing
local integer ID = 1
local unit Target
local unit U
local unit Dummy
local group G = NewGroup()
local real hpHeal
local real manaHeal
local real duration = 2
local boolean enemyNear = false
loop
exitwhen ID > 6
set U = udg_Control_Point[ID]
set udg_Filter_Player = GetOwningPlayer(U)
call GroupEnumUnitsInRange(G, GetUnitX(U), GetUnitY(U), 500, FILTER_ENEMY_TOWER_OR_HERO)
set enemyNear = FirstOfGroup(G) != null
call GroupClear(G)
call GroupEnumUnitsInRange(G, GetUnitX(U), GetUnitY(U), 500, FILTER_ALLY_TANK)
if enemyNear then
call SetUnitVertexColor( U, 100, 100, 100, 255 )
call SetUnitTimeScale( U, 0.5 )
call UnitAddAbility(U, CPTP_DISABLE_ABILITY_ID)
else
call SetUnitVertexColor( U, 255, 255, 255, 255 )
call SetUnitTimeScale( U, 1 )
if (GetUnitAbilityLevel(U, CPTP_DISABLE_ABILITY_ID) > 0) then
call UnitRemoveAbility(U, CPTP_DISABLE_ABILITY_ID)
endif
endif
loop
set Target = FirstOfGroup(G)
exitwhen (Target == null)
if (GetUnitAbilityLevel(U, CPTP_DISABLE_ABILITY_ID) > 0) then
if (GetUnitAbilityLevel(Target, 'B01V') > 0) then
call UnitRemoveAbility(Target, 'B01V')
endif
else
//Check whether the target already got the heal buff
if (GetUnitState(Target, UNIT_STATE_MAX_LIFE) > GetUnitState(Target, UNIT_STATE_LIFE)) or (GetUnitState(Target, UNIT_STATE_MAX_MANA) > GetUnitState(Target, UNIT_STATE_MANA)) then
if (GetUnitAbilityLevel(Target, 'B01V') == 0) then
//852609 = Factory Heal ('A0CU')
set Dummy = CreateDummyWithAbilityCoord(GetOwningPlayer(U), 'A0CU', 1, GetUnitX(U), GetUnitY(U), 0)
call IssueTargetOrderById( Dummy, 852609, Target )
else
//This ability also places the same buff, but doesn't trigger the heal trigger
//This is done to ensure, that the buff stays on the target all the time, while it is healing, but without stacking healing
//852609 = Factory Heal Buff Placer('A0BK')
set Dummy = CreateDummyWithAbilityCoord(GetOwningPlayer(U), 'A0BK', 1, GetUnitX(U), GetUnitY(U), 0)
call IssueTargetOrderById( Dummy, 852609, Target )
endif
endif
endif
call GroupRemoveUnit(G, Target)
endloop
call GroupClear(G)
set ID = ID + 1
endloop
call ReleaseGroup(G)
set G = null
set U = null
set Target = null
set Dummy = null
endfunction
//===========================================================================
function InitTrig_Factory_Heal takes nothing returns nothing
set gg_trg_Factory_Heal = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_Factory_Heal, 1.01 )
call TriggerAddAction( gg_trg_Factory_Heal, function Trig_Factory_Heal_Actions )
endfunction
//TESH.scrollpos=19
//TESH.alwaysfold=0
function Trig_Invisibility_End takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer TimerIndex = GetHandleIndex(t)
local integer PlayerId = GetPlayerNr(GetOwningPlayer(udg_AV_Unit1[TimerIndex]))
set udg_Tank_Invisible[PlayerId] = udg_Tank_Invisible[PlayerId] - 1
if udg_Tank_Invisible[PlayerId] == 0 then
call UnitRemoveAbility( udg_AV_Unit1[TimerIndex], 'Apiv' )
call RefreshTransparency( udg_AV_Unit1[TimerIndex] )
endif
call ReleaseHandleIndex(TimerIndex)
call ReleaseTimer(t)
endfunction
function Trig_Invisibility_Actions takes nothing returns nothing
local unit Tank = GetTriggerUnit()
local integer PlayerId = GetPlayerNr(GetOwningPlayer(Tank))
local real duration = 5
local timer t = NewTimer()
//Camouflage (Exploder)
if GetSpellAbilityId() == 'A0AD' then
set duration = 2.1 + 0.7 * I2R(GetUnitAbilityLevel(Tank, 'A0AD'))
endif
//Illusion Pack
if GetSpellAbilityId() == 'A0AP' then
set duration = 5
endif
set udg_Tank_Invisible[PlayerId] = udg_Tank_Invisible[PlayerId] + 1
if udg_Tank_Invisible[PlayerId] == 1 then
call UnitAddAbility( Tank, 'Apiv' )
endif
set udg_AV_Unit1[NewTimerIndex(t)] = Tank
// Why +0.01? But probably has a good reason
call TimerStart(t, duration+0.01, false, function Trig_Invisibility_End)
set Tank = null
endfunction
//===========================================================================
function InitTrig_Invisibility takes nothing returns nothing
set gg_trg_Invisibility = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Invisibility, 'A07D' )
call TriggerRegisterSpellEffectEvent( gg_trg_Invisibility, 'A056' )
call TriggerRegisterSpellEffectEvent( gg_trg_Invisibility, 'A0AD' )
//call TriggerRegisterSpellEffectEvent( gg_trg_Invisibility, 'A0AP' )
call TriggerAddAction( gg_trg_Invisibility, function Trig_Invisibility_Actions )
endfunction
function Trig_Move_Summoned_Conditions takes nothing returns boolean
local integer Id = GetUnitTypeId(GetSummonedUnit())
// Mortars (1) Mortars (2) Mortars (3) Mortars (4) Mortars (5) Goblin Riot Dead
return Id=='z01N' or Id=='z01H' or Id=='z01O' or Id=='z01P' or Id=='z01L' or Id=='z00P' or Id=='z003' or Id=='z006'
endfunction
function Trig_Move_Summoned_Actions takes nothing returns nothing
call IssuePointOrderLoc( GetSummonedUnit(), "attack", udg_Move_Points[GetTargetMovePoint(GetSummoningUnit())] )
endfunction
//===========================================================================
function InitTrig_Move_Summoned takes nothing returns nothing
set gg_trg_Move_Summoned = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Move_Summoned, EVENT_PLAYER_UNIT_SUMMON )
call TriggerAddCondition( gg_trg_Move_Summoned, Condition( function Trig_Move_Summoned_Conditions ) )
call TriggerAddAction( gg_trg_Move_Summoned, function Trig_Move_Summoned_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope RandomTank initializer Init
private function Actions takes nothing returns nothing
local player p = GetOwningPlayer(GetTriggerUnit())
if GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) < 1900 then
call DisplayTimedTextToPlayer(p, 0, 0, 20, "You don't have enough gold to get a random tank")
else
call SetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD,(GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD)*105)/100)
call BuyRandomStartTank(p)
endif
set p = null
endfunction
private function Init takes nothing returns nothing
set gg_trg_Random_Tank = CreateTrigger()
call TriggerRegisterSpellEffectEvent( gg_trg_Random_Tank, 'A08F' )
call TriggerAddAction( gg_trg_Random_Tank, function Actions )
endfunction
endscope
//TESH.scrollpos=50
//TESH.alwaysfold=0
function Trig_Repack_Building_Conditions takes nothing returns boolean
return GetUnitTypeId(GetSoldUnit()) == 'z00G'
endfunction
function Trig_Repack_Building_Actions takes nothing returns nothing
local unit Building = GetTriggerUnit()
local integer BuildingID = GetUnitTypeId(Building)
local integer AttachmentId
local player Owner = GetOwningPlayer(GetBuyingUnit())
local integer goldcost
local texttag BountyText
local item BuildingItem = null
local integer i = 0
local integer tccNr = 0
local real tccMana
if BuildingID == 'h01Z' then
// is a Factory
set goldcost = 500 + R2I( 0.50 * 2500 * ( 1 - ( GetUnitState(Building,UNIT_STATE_LIFE) / GetUnitState(Building,UNIT_STATE_MAX_LIFE) ) ) )
elseif BuildingID == 'h015' then
// is a Troop Factory
set goldcost = 500 + R2I( 0.50 * 3500 * ( 1 - ( GetUnitState(Building,UNIT_STATE_LIFE) / GetUnitState(Building,UNIT_STATE_MAX_LIFE) ) ) )
else
// is a Troop Command Center
set goldcost = 500 + R2I( 0.50 * 2750 * ( 1 - ( GetUnitState(Building,UNIT_STATE_LIFE) / GetUnitState(Building,UNIT_STATE_MAX_LIFE) ) ) )
set tccMana = GetUnitState(Building, UNIT_STATE_MANA)
endif
if GetOwningPlayer(GetTriggerUnit()) != Owner then
if GetLocalPlayer() == Owner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You can only use that ability on your own Buildings.|r" )
endif
elseif ( GetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD) >= goldcost ) then
call SetPlayerState( Owner, PLAYER_STATE_RESOURCE_GOLD, ( GetPlayerState(Owner, PLAYER_STATE_RESOURCE_GOLD) - ( goldcost ) ) )
call KillUnit( Building )
if BuildingID == 'h01Z' then
// is a Factory
set i = GetInventoryIndexOfItemTypeBJ(GetBuyingUnit(), 'I00Z')
if i!=0 then
call SetItemCharges( UnitItemInSlot(GetBuyingUnit(), i - 1), GetItemCharges(UnitItemInSlot(GetBuyingUnit(), i - 1)) + 1 )
else
set BuildingItem = CreateItem('I00Z', GetUnitX(Building), GetUnitY(Building))
endif
elseif BuildingID == 'h015' then
// is a Troop Factory
set i = GetInventoryIndexOfItemTypeBJ(GetBuyingUnit(), 'I04Z')
if i!=0 then
call SetItemCharges( UnitItemInSlot(GetBuyingUnit(), i - 1), GetItemCharges(UnitItemInSlot(GetBuyingUnit(), i - 1)) + 1 )
else
set BuildingItem = CreateItem('I04Z', GetUnitX(Building), GetUnitY(Building))
endif
else
// is a Troop Command Center
set i = GetInventoryIndexOfItemTypeBJ(GetBuyingUnit(), 'I04Y')
if i!=0 then
call SetItemCharges( UnitItemInSlot(GetBuyingUnit(), i - 1), GetItemCharges(UnitItemInSlot(GetBuyingUnit(), i - 1)) + 1 )
else
set BuildingItem = CreateItem('I04Y', GetUnitX(Building), GetUnitY(Building))
endif
if (udg_TCC_Mana[udg_TCC_Max*GetPlayerNr(Owner)] == 0) then
set tccNr = 0
else
set tccNr = 1
endif
set udg_TCC_Mana[udg_TCC_Max*GetPlayerNr(Owner) + tccNr] = tccMana
endif
if BuildingItem != null then
call SetItemPlayer( BuildingItem, Owner, false )
call UnitAddItem(GetBuyingUnit(),BuildingItem)
set BuildingItem = null
endif
set BountyText = CreateTextTag( )
call SetTextTagText(BountyText, "-" + I2S(goldcost), 0.023)
call SetTextTagPos(BountyText, GetUnitX(Building), GetUnitY(Building), GetUnitFlyHeight(Building))
call SetTextTagColor(BountyText, 254, 211, 18, 255)
call SetTextTagVisibility(BountyText, GetLocalPlayer() == Owner)
call SetTextTagVelocity(BountyText, 0, 0.03)
call SetTextTagFadepoint(BountyText, 2 )
call SetTextTagLifespan(BountyText, 3 )
call SetTextTagPermanent(BountyText, false )
set BountyText = null
elseif GetLocalPlayer() == Owner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You don't have enough Gold.|r" )
endif
call RemoveUnit(GetSoldUnit())
set Building = null
endfunction
//===========================================================================
function InitTrig_Repack_Building takes nothing returns nothing
set gg_trg_Repack_Building = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Repack_Building, EVENT_PLAYER_UNIT_SELL )
call TriggerAddCondition( gg_trg_Repack_Building, Condition( function Trig_Repack_Building_Conditions ) )
call TriggerAddAction( gg_trg_Repack_Building, function Trig_Repack_Building_Actions )
endfunction
function Trig_Show_Tip_Actions takes nothing returns nothing
call ShowTip(GetOwningPlayer(GetTriggerUnit()))
endfunction
//===========================================================================
function InitTrig_Show_Tip takes nothing returns nothing
set gg_trg_Show_Tip = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Show_Tip, 'A025' )
call TriggerAddAction( gg_trg_Show_Tip, function Trig_Show_Tip_Actions )
endfunction
//TESH.scrollpos=21
//TESH.alwaysfold=0
library SpellEffectEvent requires StringEval
globals
integer array udg_SpellEffectId
trigger array udg_SpellEffectTrigger
integer udg_SpellEffectMax=-1
endglobals
function TriggerRegisterSpellEffectEvent takes trigger t, integer AbilId returns nothing
// Insert the new AbilId in the sorted array
// Start at the end and move all elements to the next index
local integer i = udg_SpellEffectMax
loop
exitwhen i<0 or udg_SpellEffectId[i]<=AbilId
set udg_SpellEffectId[i+1] = udg_SpellEffectId[i]
set udg_SpellEffectTrigger[i+1] = udg_SpellEffectTrigger[i]
set i = i-1
endloop
// Insert the new ability behind [i]
set udg_SpellEffectMax = udg_SpellEffectMax + 1
set udg_SpellEffectTrigger[i+1] = t
set udg_SpellEffectId[i+1] = AbilId
endfunction
endlibrary
function Trig_Spell_Effect_Event_Effects takes integer SpellId returns nothing
local real x
local real y
local real range = 0
//A055 - Plasma Cluster, A02A - Artillery Shot, A04O - Burning Oil
if SpellId=='A055' or SpellId=='A02A' or SpellId=='A04O' then
set range = 200
//A04M - Swarm Rockets, A001 - Bombardment, A01P - Flamestrike, A0B7 - Hail of Bombs, A0F8 - Storm Shock
elseif SpellId=='A04M' or SpellId=='A001' or SpellId=='A01P' or SpellId=='A0B7' or SpellId=='A0F8' then
set range = 300
//A02Z - Plasma Rain, A04R - Ice Rain
elseif SpellId=='A02Z' or SpellId=='A04R' then
set range = 400
//A04K - Lightning Quake, A08O - Hailfire, A0A0 - Acid Cloud
elseif SpellId=='A04K' or SpellId=='A08O' or SpellId=='A0A0' then
set range = 450
//A094 - Gravity Grenade
elseif SpellId=='A094' then
set range = 500
endif
if range!=0 then
set x = GetSpellTargetX()
set y = GetSpellTargetY()
call TriggerSleepAction( 0.50 )
call DestroyTreesInRange(x,y,range)
endif
endfunction
function Trig_Spell_Effect_Event_Actions takes nothing returns nothing
// Binary search for the registered skill
local integer SpellId = GetSpellAbilityId()
local integer hi = udg_SpellEffectMax
local integer lo = 0
local integer mid
loop
exitwhen lo==hi
set mid = (lo+hi)/2
if SpellId>udg_SpellEffectId[mid] then
set lo=mid+1
else
set hi=mid
endif
endloop
// If the skill is registered, it is registered at [hi]
// if it is registered multiple times, these are at [hi+1], [hi+2] and so on
loop
exitwhen udg_SpellEffectId[hi]!=SpellId
call TriggerExecute(udg_SpellEffectTrigger[hi])
set hi = hi+1
endloop
// If effects are enabled, destroy trees
// It is important that this is called at the end, because the function contains a wait
if not udg_NoEffects then
call Trig_Spell_Effect_Event_Effects(SpellId)
endif
endfunction
//===========================================================================
function InitTrig_Spell_Effect_Event takes nothing returns nothing
set gg_trg_Spell_Effect_Event = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spell_Effect_Event, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddAction( gg_trg_Spell_Effect_Event, function Trig_Spell_Effect_Event_Actions )
endfunction
//TESH.scrollpos=3
//TESH.alwaysfold=0
function Trig_Summon_Troops_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'h01K'
endfunction
function Trig_Summon_Troops_Actions takes nothing returns nothing
local unit Center = GetTriggerUnit()
local unit Summoner = GetBuyingUnit()
local player Owner = GetOwningPlayer(Summoner)
local real Manacost
local integer UnitID = GetUnitTypeId(GetSoldUnit())
local integer SummonID
local integer Number
local integer CPs = udg_Team_CPs[udg_Player_Team[GetPlayerNr(Owner)]]
local integer ReqCPs = 0
local real rallyX = GetLocationX(GetUnitRallyPoint(Center))
local real rallyY = GetLocationY(GetUnitRallyPoint(Center))
local boolean Allowed = true
local string s = ""
if (UnitID == 'z00Z') then
set Manacost = 400.00 // Reinforcements
set SummonID = '1999'
set Number = 5
elseif (UnitID == 'z01A') then
set Manacost = 300.00 // Mortar Team
set SummonID = 'z01H'
set Number = 3
elseif (UnitID == 'z01B') then
set Manacost = 300.00 // Sniper
set SummonID = 'z00Y'
set Number = 3
elseif (UnitID == 'z01Z') then
set Manacost = 150.00 // Seeker
set SummonID = 'z01Y'
set Number = 3
elseif (UnitID == 'z01G') then
set Manacost = 500.00 // Aura Creeps
set SummonID = '1888'
set Number = 3
elseif (UnitID == 'z01I') then
set Manacost = 200.00 // Scan
set SummonID = '1777'
set Number = 1
elseif (UnitID == 'z01T') then
set Manacost = 1000.00 // Bomb
set SummonID = 'h00V'
set Number = 1
//set ReqCPs = 6
else
set Center = null
set Summoner = null
return
endif
//Check if you are allowed to use the bomb in your own base
if (UnitID == 'z01T') then
set udg_TempInt = GetPlayerNr(Owner)
set udg_Filter_Player = Owner
//Unit belongs to team 1 and is in team 1 base -> check if there are enemy factories
if (udg_Player_Team[udg_TempInt] == 1) and RectContainsLoc(gg_rct_Team_1_Base_Main, GetUnitRallyPoint(Center)) then
call GroupClear(udg_TempGroup)
call GroupEnumUnitsInRect(udg_TempGroup, gg_rct_Team_1_Base_Main, FILTER_ENEMY_FACTORY)
set Allowed = FirstOfGroup(udg_TempGroup) != null
//Unit belongs to team 2 and is in team 2 base -> check if there are enemy factories
elseif (udg_Player_Team[udg_TempInt] == 2) and RectContainsLoc(gg_rct_Team_2_Base_Main, GetUnitRallyPoint(Center)) then
call GroupClear(udg_TempGroup)
call GroupEnumUnitsInRect(udg_TempGroup, gg_rct_Team_2_Base_Main, FILTER_ENEMY_FACTORY)
set Allowed = FirstOfGroup(udg_TempGroup) != null
endif
//When there are no enemy factories, you are forbidden to use the bomb
if (Allowed == false) then
set s = "|cfffed312You cannot place a bomb in your own base.|r"
endif
endif
if (s == "") and (IsUnitEnemy(Summoner, GetOwningPlayer(Center)) == true) then
set s = "|cfffed312You can't summon troops from an enemy Command Center.|r"
endif
if (s == "") and (GetUnitState(Center, UNIT_STATE_MANA) < Manacost) then
set s = "|cfffed312Not enough Mana.|r"
endif
if (s == "") and (GetOwningPlayer(Center) != Owner) and ((GetUnitState(Center, UNIT_STATE_MANA) - Manacost) < (GetUnitState(Center, UNIT_STATE_MANA)*0.5)) then
set s = "|cfffed312Only the owner of the TCC may spend the lower half of the mana pool.|r"
endif
if (s == "") and (rallyX + rallyY == 0.00) then
set s = "|cfffed312No Rally-Point set.|r"
endif
if (s == "") and (ReqCPs > CPs) then
set s = "|cfffed312Your team needs to control all Control Points to use this ability.|r"
endif
if (s == "") and (DistanceBetweenPoints(GetUnitLoc(Center), GetUnitRallyPoint(Center)) >= 3000.00) then
set s = "|cfffed312You can't summon troops more than 3000 units away from the Command Center.|r"
endif
if (s == "") then
call SetUnitManaBJ( Center, ( GetUnitState(Center, UNIT_STATE_MANA) - Manacost ) )
if (SummonID == '1777') then
call TCC_Ability( GetPlayer(( GetMaxHumanPlayers() + udg_Player_Team[GetPlayerNr(Owner)] )), SummonID, rallyX, rallyY )
else
set udg_Stats_CreepBuy[GetPlayerNr(Owner)] = ( udg_Stats_CreepBuy[GetPlayerNr(Owner)] + Number )
call UnitDrop(GetPlayer(( GetMaxHumanPlayers() + udg_Player_Team[GetPlayerNr(Owner)] )), SummonID, Number, rallyX, rallyY )
endif
else
if GetLocalPlayer() == Owner then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, s )
endif
endif
set Center = null
set Summoner = null
endfunction
//===========================================================================
function InitTrig_Summon_Troops takes nothing returns nothing
set gg_trg_Summon_Troops = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Summon_Troops, EVENT_PLAYER_UNIT_SELL )
call TriggerAddCondition( gg_trg_Summon_Troops, Condition( function Trig_Summon_Troops_Conditions ) )
call TriggerAddAction( gg_trg_Summon_Troops, function Trig_Summon_Troops_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Tank_Factory_IsNearRect takes real X, real Y, rect R returns boolean
return X>GetRectCenterX(R)-600 and X<GetRectCenterX(R)+600 and Y>GetRectCenterY(R)-600 and Y<GetRectCenterY(R)+600
endfunction
function Trig_Tank_Factory_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local real CasterX = GetUnitX(Caster)
local real CasterY = GetUnitY(Caster)
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", CasterX, CasterY ) )
call GameTimeWait(1.25)
if Caster==null or IsUnitDeadBJ(Caster) then
return
endif
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", CasterX, CasterY ) )
if IsPlayerInForce(GetOwningPlayer(Caster), udg_Players_Team[1]) then
if Trig_Tank_Factory_IsNearRect(CasterX,CasterY,gg_rct_Team_1_Respawn) then
set CasterX = GetRectCenterX(gg_rct_Team_1_Tank_Respawn)
set CasterY = GetRectCenterY(gg_rct_Team_1_Tank_Respawn)
elseif Trig_Tank_Factory_IsNearRect(CasterX,CasterY,gg_rct_Team_1_Tank_Respawn) then
set CasterX = GetRectCenterX(gg_rct_Team_1_Trade_Master_Respawn)
set CasterY = GetRectCenterY(gg_rct_Team_1_Trade_Master_Respawn)
else
set CasterX = GetRectCenterX(gg_rct_Team_1_Respawn)
set CasterY = GetRectCenterY(gg_rct_Team_1_Respawn)
endif
else
if Trig_Tank_Factory_IsNearRect(CasterX,CasterY,gg_rct_Team_2_Respawn) then
set CasterX = GetRectCenterX(gg_rct_Team_2_Tank_Respawn)
set CasterY = GetRectCenterY(gg_rct_Team_2_Tank_Respawn)
elseif Trig_Tank_Factory_IsNearRect(CasterX,CasterY,gg_rct_Team_2_Tank_Respawn) then
set CasterX = GetRectCenterX(gg_rct_Team_2_Trade_Master_Respawn)
set CasterY = GetRectCenterY(gg_rct_Team_2_Trade_Master_Respawn)
else
set CasterX = GetRectCenterX(gg_rct_Team_2_Respawn)
set CasterY = GetRectCenterY(gg_rct_Team_2_Respawn)
endif
endif
call SetUnitPosition(Caster,CasterX,CasterY)
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", CasterX, CasterY ) )
if GetLocalPlayer() == GetOwningPlayer(Caster) then
call PanCameraToTimed(GetUnitX(Caster), GetUnitY(Caster), 0)
endif
endfunction
//===========================================================================
function InitTrig_Tank_Factory_Teleport takes nothing returns nothing
set gg_trg_Tank_Factory_Teleport = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Tank_Factory_Teleport, 'A08G' )
call TriggerAddAction( gg_trg_Tank_Factory_Teleport, function Trig_Tank_Factory_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Target_Factory_Heal_Actions takes nothing returns nothing
local unit Target = GetSpellTargetUnit()
local real HealedLife
local real HealedMana
local integer Ability
local integer Duration
set Duration = 2
set HealedLife = ((GetUnitState(Target, UNIT_STATE_MAX_LIFE) * 0.02) + 25) * Duration
set HealedMana = 5
set Ability = 'B01V'
call HealOverTime(Target, HealedLife, HealedMana, Duration, Ability, false)
set Target = null
endfunction
//===========================================================================
function InitTrig_Target_Factory_Heal takes nothing returns nothing
set gg_trg_Target_Factory_Heal = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Target_Factory_Heal, 'A0CU' )
call TriggerAddAction( gg_trg_Target_Factory_Heal, function Trig_Target_Factory_Heal_Actions )
endfunction
//TESH.scrollpos=5
//TESH.alwaysfold=0
scope TechMechDetector initializer Init
globals
private constant integer ABILITY_ID = 'A0FF'
private constant integer DETECTOR_ID = 'o001'
private constant integer DETECTOR_ITEM_ID = 'I03F'
private constant real DURATION = 300.0
endglobals
function Trig_Tech_Mech_Detector_Actions takes nothing returns nothing
local location TargetLoc = GetSpellTargetLoc()
local unit Caster = GetTriggerUnit()
local integer i = 0
local item detector
local boolean hasDetector = false
loop
exitwhen ((i >= 6) or hasDetector)
set detector = UnitItemInSlot(Caster, i)
if (GetItemTypeId(detector) == DETECTOR_ITEM_ID) then
set hasDetector = true
endif
set i = i + 1
endloop
if hasDetector then
call UnitApplyTimedLife(CreateUnitAtLoc(GetOwningPlayer(Caster),DETECTOR_ID,TargetLoc, 270), 'Beye', DURATION)
if (GetItemCharges(detector) == 1) then
call RemoveItem(detector)
else
call SetItemCharges(detector, GetItemCharges(detector) -1)
endif
else
call IssueImmediateOrder(Caster,"stop")
if GetLocalPlayer()==GetOwningPlayer(Caster) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312The Tech Mech does not carry any Detectors.|r")
endif
endif
call RemoveLocation(TargetLoc)
set TargetLoc = null
set Caster = null
set detector = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Tech_Mech_Detector = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Tech_Mech_Detector, ABILITY_ID )
call TriggerAddAction( gg_trg_Tech_Mech_Detector, function Trig_Tech_Mech_Detector_Actions )
endfunction
endscope
//TESH.scrollpos=6
//TESH.alwaysfold=0
scope TechMechNetLauncher initializer Init
globals
private constant integer ABILITY_ID = 'A0FK'
private constant integer NET_ABILITY_ID = 'A0FK'
private constant integer NET_ITEM_ID = 'I04W'
private constant real DURATION = 3.0
endglobals
function Trig_Tech_Mech_Net_Launcher_Actions takes nothing returns nothing
local unit Target = GetSpellTargetUnit()
local unit Caster = GetTriggerUnit()
local integer i = 0
local item net
local boolean hasNet = false
loop
exitwhen ((i >= 6) or hasNet)
set net = UnitItemInSlot(Caster, i)
if (GetItemTypeId(net) == NET_ITEM_ID) then
set hasNet = true
endif
set i = i + 1
endloop
if hasNet then
call DebugMsg("Caster: " + GetName(Caster) + " Target: " + GetName(Target))
//if IssueTargetOrder(CreateDummyWithAbilityCoord(GetOwningPlayer(Caster), NET_ABILITY_ID, 1, GetUnitX(Caster), GetUnitY(Caster), 0), "ensnare",Target) then
if (GetItemCharges(net) == 1) then
call RemoveItem(net)
else
call SetItemCharges(net, GetItemCharges(net) -1)
endif
//deactivate Bombs or Flak, because the tank is now a ground unit
call DeactivateAirOnlyWeapons(Target)
call GameTimeWait(DURATION)
//activate the weapon again, as the net wears off
call ActivateAirOnlyWeapons(Target)
else
call IssueImmediateOrder(Caster,"stop")
if GetLocalPlayer()==GetOwningPlayer(Caster) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312The Tech Mech does not carry any Net Launchers.|r")
endif
endif
set Target = null
set Caster = null
set net = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Tech_Mech_Net_Launcher = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Tech_Mech_Net_Launcher, ABILITY_ID )
call TriggerAddAction( gg_trg_Tech_Mech_Net_Launcher, function Trig_Tech_Mech_Net_Launcher_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Tech_Mech_Repair_Actions takes nothing returns nothing
local unit target = GetSpellTargetUnit()
if (IsUnitType(target, UNIT_TYPE_HERO)) or IsTechMech(target) then
call SetUnitState(target,UNIT_STATE_LIFE, GetUnitState(target,UNIT_STATE_LIFE)*1.02)
else
call SetUnitState(target,UNIT_STATE_LIFE, GetUnitState(target,UNIT_STATE_LIFE)+90)
endif
set target = null
endfunction
//===========================================================================
function InitTrig_Tech_Mech_Repair takes nothing returns nothing
set gg_trg_Tech_Mech_Repair = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Tech_Mech_Repair, 'A06T' )
call TriggerAddAction( gg_trg_Tech_Mech_Repair, function Trig_Tech_Mech_Repair_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TechMechTeleportBreaker initializer Init
globals
private constant integer ABILITY_ID = 'A0FC'
private constant integer BREAKER_ID = 'o002'
private constant integer BREAKER_ITEM_ID = 'I04P'
private constant real DURATION = 180.0
endglobals
function Trig_Tech_Mech_Teleport_Breaker_Actions takes nothing returns nothing
local location TargetLoc = GetSpellTargetLoc()
local unit Caster = GetTriggerUnit()
local integer i = 0
local item breaker
local boolean hasBreaker = false
loop
exitwhen ((i >= 6) or hasBreaker)
set breaker = UnitItemInSlot(Caster, i)
if (GetItemTypeId(breaker) == BREAKER_ITEM_ID) then
set hasBreaker = true
endif
set i = i + 1
endloop
if hasBreaker then
if GetPathableLoc(TargetLoc,32,200) then
call UnitApplyTimedLife(CreateUnitAtLoc(GetOwningPlayer(Caster),BREAKER_ID,TargetLoc, 270), 'Beye', DURATION)
if (GetItemCharges(breaker) == 1) then
call RemoveItem(breaker)
else
call SetItemCharges(breaker, GetItemCharges(breaker) -1)
endif
else
call IssueImmediateOrder(Caster,"stop")
if GetLocalPlayer()==GetOwningPlayer(Caster) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312You cannot place a Teleport Breaker there.|r")
endif
endif
else
call IssueImmediateOrder(Caster,"stop")
if GetLocalPlayer()==GetOwningPlayer(Caster) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312The Tech Mech does not carry any Teleport Breakers.|r")
endif
endif
call RemoveLocation(TargetLoc)
set TargetLoc = null
set Caster = null
set breaker = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_Tech_Mech_Teleport_Breaker = CreateTrigger( )
call TriggerRegisterSpellEffectEvent( gg_trg_Tech_Mech_Teleport_Breaker, ABILITY_ID )
call TriggerAddAction( gg_trg_Tech_Mech_Teleport_Breaker, function Trig_Tech_Mech_Teleport_Breaker_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Teleport_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02X' or GetSpellAbilityId() == 'A00F' or GetSpellAbilityId() == 'A0AN' or GetSpellAbilityId() == 'A0BV'
endfunction
function Trig_Teleport_IsInvalidTeleporterTarget takes location P returns boolean
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))] == 1 then
return RectContainsLoc(gg_rct_Team_2_Base_Main, P)
endif
return RectContainsLoc(gg_rct_Team_1_Base_Main, P)
endfunction
function Trig_Teleport_Impact takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer TimerIndex = GetHandleIndex(t)
call CheckHyperSpaceBreaker(udg_AV_Unit1[TimerIndex])
call ReleaseHandleIndex(TimerIndex)
call ReleaseTimer(t)
endfunction
function Trig_Teleport_Actions takes nothing returns nothing
local unit Tank = GetTriggerUnit()
local location P = GetSpellTargetLoc()
local timer t
local integer TimerIndex
if Trig_Teleport_IsInvalidTeleporterTarget( P ) then
call IssueImmediateOrder( Tank, "stop" )
if GetLocalPlayer() == GetOwningPlayer(Tank) then
call DisplayTextToPlayer( GetLocalPlayer(), 0, 0, "|cfffed312You cannot teleport into the enemies' base.|r" )
endif
if GetSpellAbilityId() == 'A02X' or GetSpellAbilityId() == 'A00F' then
call SetUnitManaDelayed(Tank, GetUnitState(Tank, UNIT_STATE_MANA))
endif
else
call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(Tank), GetUnitY(Tank) ) )
call DestroyEffect( AddSpecialEffectLoc( "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", P ) )
set t = NewTimer()
set TimerIndex = NewTimerIndex(t)
set udg_AV_Unit1[TimerIndex] = Tank
call TimerStart(t, 0, false, function Trig_Teleport_Impact)
endif
call RemoveLocation( P )
set P = null
set Tank = null
endfunction
//===========================================================================
function InitTrig_Teleport takes nothing returns nothing
set gg_trg_Teleport = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Teleport, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Teleport, Condition( function Trig_Teleport_Conditions ) )
call TriggerAddAction( gg_trg_Teleport, function Trig_Teleport_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Troop_Command_Center_Rally_Point_Conditions takes nothing returns boolean
local string order
if GetUnitTypeId(GetOrderedUnit()) != 'h01K' then
return false
endif
set order = OrderId2String(GetIssuedOrderId())
return (order=="smart") or (order=="setrally")
endfunction
function Trig_Troop_Command_Center_Rally_Point_Child takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = GetHandleIndex(t)
local unit U = udg_AV_Unit1[i]
local location RallyPoint = GetUnitRallyPoint(U)
local real DistX = GetLocationX(RallyPoint)-GetUnitX(U)
local real DistY = GetLocationY(RallyPoint)-GetUnitY(U)
local real DistXY = SquareRoot(DistX*DistX+DistY*DistY)
call ReleaseTimer(t)
call ReleaseHandleIndex(i)
if DistXY > 3000 then
call IssuePointOrder(U, "setrally", GetUnitX(U)+DistX*2999/DistXY, GetUnitY(U)+DistY*2999/DistXY)
if GetLocalPlayer()==GetOwningPlayer(U) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cfffed312The Command Center only has a range of 3000.|r")
endif
endif
set U = null
call RemoveLocation(RallyPoint)
set RallyPoint = null
endfunction
function Trig_Troop_Command_Center_Rally_Point_Actions takes nothing returns nothing
local timer t = NewTimer()
local integer i = NewTimerIndex(t)
set udg_AV_Unit1[i] = GetTriggerUnit()
call TimerStart(t,0.00,false,function Trig_Troop_Command_Center_Rally_Point_Child)
endfunction
//===========================================================================
function InitTrig_Troop_Command_Center_Rally_Point takes nothing returns nothing
set gg_trg_Troop_Command_Center_Rally_Point = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Troop_Command_Center_Rally_Point, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Troop_Command_Center_Rally_Point, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerAddCondition( gg_trg_Troop_Command_Center_Rally_Point, Condition( function Trig_Troop_Command_Center_Rally_Point_Conditions ) )
call TriggerAddAction( gg_trg_Troop_Command_Center_Rally_Point, function Trig_Troop_Command_Center_Rally_Point_Actions )
endfunction
//TESH.scrollpos=157
//TESH.alwaysfold=0
library AIGeneralFunctions requires MapAttachedSettings, TankChangeLibrary
function GetRandomName takes nothing returns string
local string array Name
local string RetName=null
local integer count
local integer NameId
local integer i
set Name[1] = "Zonk [AI]"
set Name[2] = "Pete [AI]"
set Name[3] = "TheDeath [AI]"
set Name[4] = "KillerTank [AI]"
set Name[5] = "MassacreMan [AI]"
set Name[6] = "Freak [AI]"
set Name[7] = "BotKiller [AI]"
set Name[8] = "TankMaster [AI]"
set Name[9] = "Deathbringer [AI]"
set Name[10] = "Overlord [AI]"
set Name[11] = "TheEnemy [AI]"
set Name[12] = "Flozz [AI]"
set Name[13] = "FearMan [AI]"
set Name[14] = "Destroyer [AI]"
set Name[15] = "Destructomatic [AI]"
set Name[16] = "Punisher [AI]"
set Name[17] = "Guardian [AI]"
set Name[18] = "TheOnlyOne [AI]"
set Name[19] = "TheInvisible [AI]"
set Name[20] = "TheMachine [AI]"
set Name[21] = "Darkness [AI]"
set Name[22] = "Firepower [AI]"
set Name[23] = "GodOfFire [AI]"
set Name[24] = "Elite [AI]"
set Name[25] = "Goliath [AI]"
set count = 25
set NameId = GetRandomInt(1,count)
loop
exitwhen RetName!=null
set RetName = Name[NameId]
set i = 1
loop
exitwhen i > GetMaxPlayers()
if RetName == GetPlayerName(GetPlayer(i)) then
set RetName = null
endif
set i = i + 1
endloop
if NameId == count then
set NameId = 0
else
set NameId = NameId + 1
endif
endloop
return RetName
endfunction
function Init_WeaponRange takes nothing returns nothing
set udg_WeaponRange[ModuloInteger('I01U',8192)] = 700 // AA Gun
set udg_WeaponRange[ModuloInteger('I03B',8192)] = 700 // AA Gun (Upgrade)
set udg_WeaponRange[ModuloInteger('I062',8192)] = 1300 // Acid Cannon
set udg_WeaponRange[ModuloInteger('I063',8192)] = 1300 // Acid Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I00B',8192)] = 1050 // Artillery (Normal)
set udg_WeaponRange[ModuloInteger('I034',8192)] = 1050 // Artillery (Ground)
set udg_WeaponRange[ModuloInteger('I059',8192)] = 800 // Axe Launcher
set udg_WeaponRange[ModuloInteger('I05A',8192)] = 800 // Axe Launcher (Upgrade)
set udg_WeaponRange[ModuloInteger('I00E',8192)] = 860 // Basic Cannon
set udg_WeaponRange[ModuloInteger('I02I',8192)] = 860 // Basic Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I01F',8192)] = 999 // Basic Magic
set udg_WeaponRange[ModuloInteger('I02L',8192)] = 999 // Basic Magic (Upgrade)
set udg_WeaponRange[ModuloInteger('I01K',8192)] = 660 // Blaster Cannon
set udg_WeaponRange[ModuloInteger('I01M',8192)] = 660 // Blaster Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I05W',8192)] = 1300 // Bombarding Rockets
set udg_WeaponRange[ModuloInteger('I05X',8192)] = 1300 // Bombarding Rockets (Upgrade)
set udg_WeaponRange[ModuloInteger('I02Z',8192)] = 700 // Bombs
set udg_WeaponRange[ModuloInteger('I03C',8192)] = 700 // Bombs (Upgrade)
set udg_WeaponRange[ModuloInteger('I055',8192)] = 666 // Bonfire
set udg_WeaponRange[ModuloInteger('I056',8192)] = 666 // Bonfire (Upgrade)
set udg_WeaponRange[ModuloInteger('I00H',8192)] = 1050 // Burning Projectiles (Building)
set udg_WeaponRange[ModuloInteger('I02P',8192)] = 1050 // Burning Projectiles (Normal)
set udg_WeaponRange[ModuloInteger('I01B',8192)] = 888 // Confusion Magic
set udg_WeaponRange[ModuloInteger('I02Q',8192)] = 888 // Confusion Magic (Upgrade)
set udg_WeaponRange[ModuloInteger('I01R',8192)] = 750 // Darkness Cannon
set udg_WeaponRange[ModuloInteger('I028',8192)] = 750 // Darkness Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I018',8192)] = 1300 // Death Magic
set udg_WeaponRange[ModuloInteger('I02J',8192)] = 1300 // Death Magic (Upgrade)
set udg_WeaponRange[ModuloInteger('I00G',8192)] = 1050 // Electro Cannon
set udg_WeaponRange[ModuloInteger('I02E',8192)] = 1050 // Electro Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I066',8192)] = 777 // Emerald Rod
set udg_WeaponRange[ModuloInteger('I067',8192)] = 777 // Emerald Rod (Upgrade)
set udg_WeaponRange[ModuloInteger('I05J',8192)] = 850 // Energy Spears
set udg_WeaponRange[ModuloInteger('I05K',8192)] = 850 // Energy Spears (Upgrade)
set udg_WeaponRange[ModuloInteger('I05Y',8192)] = 1300 // Energy Torpedo
set udg_WeaponRange[ModuloInteger('I05Z',8192)] = 1300 // Energy Torpedo (Upgrade)
set udg_WeaponRange[ModuloInteger('I00A',8192)] = 750 // Fan of Knives
set udg_WeaponRange[ModuloInteger('I026',8192)] = 950 // Fan of Knives (Upgrade)
set udg_WeaponRange[ModuloInteger('I01G',8192)] = 999 // Fear Magic
set udg_WeaponRange[ModuloInteger('I02D',8192)] = 999 // Fear Magic (Upgrade)
set udg_WeaponRange[ModuloInteger('I02W',8192)] = 850 // Fire Arrows
set udg_WeaponRange[ModuloInteger('I02R',8192)] = 850 // Fire Arrows (Upgrade)
set udg_WeaponRange[ModuloInteger('I01E',8192)] = 888 // Fire Magic
set udg_WeaponRange[ModuloInteger('I02V',8192)] = 888 // Fire Magic (Upgrade)
set udg_WeaponRange[ModuloInteger('I000',8192)] = 950 // Fireball Cannon
set udg_WeaponRange[ModuloInteger('I032',8192)] = 950 // Fireball Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I057',8192)] = 800 // Flak
set udg_WeaponRange[ModuloInteger('I058',8192)] = 800 // Flak (Upgrade)
set udg_WeaponRange[ModuloInteger('I001',8192)] = 600 // Flamer
set udg_WeaponRange[ModuloInteger('I02X',8192)] = 600 // Flamer (Upgrade)
set udg_WeaponRange[ModuloInteger('I02U',8192)] = 950 // Frost Laser
set udg_WeaponRange[ModuloInteger('I030',8192)] = 950 // Frost Laser (Upgrade)
set udg_WeaponRange[ModuloInteger('I00F',8192)] = 999 // Frost Magic (Creep)
set udg_WeaponRange[ModuloInteger('I02C',8192)] = 999 // Frost Magic (Normal)
set udg_WeaponRange[ModuloInteger('I064',8192)] = 950 // Gamma Vortex
set udg_WeaponRange[ModuloInteger('I065',8192)] = 950 // Gamma Vortex (Upgrade)
set udg_WeaponRange[ModuloInteger('I010',8192)] = 777 // Ghosts of Doom
set udg_WeaponRange[ModuloInteger('I031',8192)] = 777 // Ghosts of Doom (Upgrade)
set udg_WeaponRange[ModuloInteger('I002',8192)] = 750 // Glaive Cannon
set udg_WeaponRange[ModuloInteger('I03A',8192)] = 750 // Glaive Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I01H',8192)] = 750 // God's Hammer
set udg_WeaponRange[ModuloInteger('I035',8192)] = 1050 // God's Hammer (Upgrade)
set udg_WeaponRange[ModuloInteger('I02Y',8192)] = 950 // Grenade Launcher (Normal)
set udg_WeaponRange[ModuloInteger('I02O',8192)] = 950 // Grenade Launcher (Air)
set udg_WeaponRange[ModuloInteger('I00J',8192)] = 600 // Ice Cannon
set udg_WeaponRange[ModuloInteger('I03D',8192)] = 600 // Ice Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I00K',8192)] = 750 // Infernal Rocks
set udg_WeaponRange[ModuloInteger('I039',8192)] = 1050 // Infernal Rocks (Upgrade)
set udg_WeaponRange[ModuloInteger('I01S',8192)] = 900 // Ion Cannon
set udg_WeaponRange[ModuloInteger('I01T',8192)] = 900 // Ion Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I00D',8192)] = 1000 // Laser (long)
set udg_WeaponRange[ModuloInteger('I01N',8192)] = 800 // Laser (medium)
set udg_WeaponRange[ModuloInteger('I01O',8192)] = 580 // Laser (short)
set udg_WeaponRange[ModuloInteger('I00C',8192)] = 950 // Light Plasma Gun
set udg_WeaponRange[ModuloInteger('I02A',8192)] = 950 // Light Plasma Gun (Upgrade)
set udg_WeaponRange[ModuloInteger('I04L',8192)] = 999 // Lightning Magic
set udg_WeaponRange[ModuloInteger('I04N',8192)] = 999 // Lightning Magic (Upgrade)
set udg_WeaponRange[ModuloInteger('I008',8192)] = 700 // Machine Gun
set udg_WeaponRange[ModuloInteger('I00X',8192)] = 700 // Machine Gun (Upgrade)
set udg_WeaponRange[ModuloInteger('I017',8192)] = 777 // Magic Cannon
set udg_WeaponRange[ModuloInteger('I033',8192)] = 777 // Magic Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I01P',8192)] = 950 // Molotov Cocktail
set udg_WeaponRange[ModuloInteger('I03H',8192)] = 950 // Molotov Cocktail
set udg_WeaponRange[ModuloInteger('I00N',8192)] = 800 // Multibow
set udg_WeaponRange[ModuloInteger('I03I',8192)] = 800 // Multibow (Upgrade)
set udg_WeaponRange[ModuloInteger('I05B',8192)] = 950 // Mystic Cannon
set udg_WeaponRange[ModuloInteger('I03E',8192)] = 950 // Mystic Cannon (Upgrade)
set udg_WeaponRange[ModuloInteger('I01Y',8192)] = 1000 // Photon Bombs
set udg_WeaponRange[ModuloInteger('I03J',8192)] = 1000 // Photon Bombs (Upgrade)
set udg_WeaponRange[ModuloInteger('I007',8192)] = 950 // Plasma Fragments
set udg_WeaponRange[ModuloInteger('I024',8192)] = 950 // Plasma Fragments (Upgrade)
set udg_WeaponRange[ModuloInteger('I003',8192)] = 750 // Plasma Waves
set udg_WeaponRange[ModuloInteger('I02F',8192)] = 750 // Plasma Waves (Upgrade)
set udg_WeaponRange[ModuloInteger('I016',8192)] = 555 // Poison Magic
set udg_WeaponRange[ModuloInteger('I03K',8192)] = 555 // Poison Magic (Upgrade)
set udg_WeaponRange[ModuloInteger('I00M',8192)] = 850 // Psycho Laser
set udg_WeaponRange[ModuloInteger('I03L',8192)] = 850 // Psycho Laser (Upgrade)
set udg_WeaponRange[ModuloInteger('I019',8192)] = 999 // Psycho Magic
set udg_WeaponRange[ModuloInteger('I027',8192)] = 999 // Psycho Magic (Upgrade)
set udg_WeaponRange[ModuloInteger('I01I',8192)] = 1050 // Rock Catapult (Building)
set udg_WeaponRange[ModuloInteger('I01Z',8192)] = 1050 // Rock Catapult (Normal)
set udg_WeaponRange[ModuloInteger('I060',8192)] = 1300 // Rocket Hail
set udg_WeaponRange[ModuloInteger('I061',8192)] = 1300 // Rocket Hail (Upgrade)
set udg_WeaponRange[ModuloInteger('I01C',8192)] = 850 // Soulstone (Hero)
set udg_WeaponRange[ModuloInteger('I038',8192)] = 850 // Soulstone (Creep)
set udg_WeaponRange[ModuloInteger('I05I',8192)] = 900 // Star Shooter (Ground)
set udg_WeaponRange[ModuloInteger('I05H',8192)] = 900 // Star Shooter (Normal)
set udg_WeaponRange[ModuloInteger('I05E',8192)] = 1050 // Supercell
set udg_WeaponRange[ModuloInteger('I05F',8192)] = 1050 // Supercell (Upgrade)
set udg_WeaponRange[ModuloInteger('I005',8192)] = 1000 // Swarm Rockets
set udg_WeaponRange[ModuloInteger('I01A',8192)] = 1000 // Swarm Rockets (Upgrade)
set udg_WeaponRange[ModuloInteger('I05C',8192)] = 675 // Swarm of Chaos
set udg_WeaponRange[ModuloInteger('I05D',8192)] = 675 // Swarm of Chaos (Upgrade)
set udg_WeaponRange[ModuloInteger('I01D',8192)] = 888 // Tornado Summoner
set udg_WeaponRange[ModuloInteger('I03M',8192)] = 888 // Tornado Summoner (Upgrade)
set udg_WeaponRange[ModuloInteger('I04M',8192)] = 800 // The Light Fantastic
set udg_WeaponRange[ModuloInteger('I04K',8192)] = 800 // The Light Fantastic (Upgrade)
endfunction
globals
constant real WEAPON_MOD_TARGET_AIR = 0.25
constant real WEAPON_MOD_TARGET_GROUND = 0.25
constant real WEAPON_MOD_CARRY_AIR = 0.25
constant real WEAPON_MOD_CARRY_GROUND = 0.25
constant real WEAPON_MOD_TARGET_CREEP = 0.75
constant real WEAPON_MOD_TARGET_HERO = 0.0
constant real WEAPON_MOD_TARGET_BUILDINGS = 0.75
constant real WEAPON_MOD_TARGET_LONGRANGE = 0.0
constant real WEAPON_MOD_TARGET_NO_BUILDINGS = 0.05
endglobals
function Init_WeaponModifier takes nothing returns nothing
set udg_WeaponModifier[ModuloInteger('I01U',8192)] = 1 + WEAPON_MOD_CARRY_GROUND + WEAPON_MOD_TARGET_AIR // AA Gun
set udg_WeaponModifier[ModuloInteger('I03B',8192)] = 1 + WEAPON_MOD_CARRY_GROUND + WEAPON_MOD_TARGET_AIR // AA Gun (Upgrade)
set udg_WeaponModifier[ModuloInteger('I062',8192)] = 1 + WEAPON_MOD_TARGET_LONGRANGE // Acid Cannon
set udg_WeaponModifier[ModuloInteger('I063',8192)] = 1 + WEAPON_MOD_TARGET_LONGRANGE // Acid Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I00B',8192)] = 1 // Artillery (Normal)
set udg_WeaponModifier[ModuloInteger('I034',8192)] = 1 + WEAPON_MOD_TARGET_GROUND // Artillery (Ground)
set udg_WeaponModifier[ModuloInteger('I059',8192)] = 1 + WEAPON_MOD_CARRY_GROUND + WEAPON_MOD_TARGET_GROUND // Axe Launcher
set udg_WeaponModifier[ModuloInteger('I05A',8192)] = 1 + WEAPON_MOD_CARRY_GROUND + WEAPON_MOD_TARGET_GROUND // Axe Launcher (Upgrade)
set udg_WeaponModifier[ModuloInteger('I00E',8192)] = 1 // Basic Cannon
set udg_WeaponModifier[ModuloInteger('I02I',8192)] = 1 // Basic Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01F',8192)] = 1 // Basic Magic
set udg_WeaponModifier[ModuloInteger('I02L',8192)] = 1 // Basic Magic (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01K',8192)] = 1 // Blaster Cannon
set udg_WeaponModifier[ModuloInteger('I01M',8192)] = 1 // Blaster Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I05W',8192)] = 1 + WEAPON_MOD_TARGET_LONGRANGE // Bombarding Rockets
set udg_WeaponModifier[ModuloInteger('I05X',8192)] = 1 + WEAPON_MOD_TARGET_LONGRANGE // Bombarding Rockets (Upgrade)
set udg_WeaponModifier[ModuloInteger('I02Z',8192)] = 1 + WEAPON_MOD_CARRY_AIR + WEAPON_MOD_TARGET_GROUND // Bombs
set udg_WeaponModifier[ModuloInteger('I03C',8192)] = 1 + WEAPON_MOD_CARRY_AIR + WEAPON_MOD_TARGET_GROUND // Bombs (Upgrade)
set udg_WeaponModifier[ModuloInteger('I055',8192)] = 1 // Bonfire
set udg_WeaponModifier[ModuloInteger('I056',8192)] = 1 // Bonfire (Upgrade)
set udg_WeaponModifier[ModuloInteger('I00H',8192)] = 1 + WEAPON_MOD_TARGET_BUILDINGS // Burning Projectiles (Building)
set udg_WeaponModifier[ModuloInteger('I02P',8192)] = 1 // Burning Projectiles (Normal)
set udg_WeaponModifier[ModuloInteger('I01B',8192)] = 1 // Confusion Magic
set udg_WeaponModifier[ModuloInteger('I02Q',8192)] = 1 // Confusion Magic (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01R',8192)] = 1 // Darkness Cannon
set udg_WeaponModifier[ModuloInteger('I028',8192)] = 1 // Darkness Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I018',8192)] = 1 + WEAPON_MOD_TARGET_CREEP // Death Magic
set udg_WeaponModifier[ModuloInteger('I02J',8192)] = 1 + WEAPON_MOD_TARGET_CREEP // Death Magic (Upgrade)
set udg_WeaponModifier[ModuloInteger('I00G',8192)] = 1 // Electro Cannon
set udg_WeaponModifier[ModuloInteger('I02E',8192)] = 1 // Electro Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I066',8192)] = 1 // Emerald Rod
set udg_WeaponModifier[ModuloInteger('I067',8192)] = 1 // Emerald Rod (Upgrade)
set udg_WeaponModifier[ModuloInteger('I05J',8192)] = 1 + WEAPON_MOD_TARGET_NO_BUILDINGS // Energy Spears
set udg_WeaponModifier[ModuloInteger('I05K',8192)] = 1 + WEAPON_MOD_TARGET_NO_BUILDINGS // Energy Spears (Upgrade)
set udg_WeaponModifier[ModuloInteger('I05Y',8192)] = 1 + WEAPON_MOD_TARGET_LONGRANGE // Energy Torpedo
set udg_WeaponModifier[ModuloInteger('I05Z',8192)] = 1 + WEAPON_MOD_TARGET_LONGRANGE // Energy Torpedo (Upgrade)
set udg_WeaponModifier[ModuloInteger('I00A',8192)] = 1 // Fan of Knives
set udg_WeaponModifier[ModuloInteger('I026',8192)] = 1 // Fan of Knives (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01G',8192)] = 1 // Fear Magic
set udg_WeaponModifier[ModuloInteger('I02D',8192)] = 1 // Fear Magic (Upgrade)
set udg_WeaponModifier[ModuloInteger('I02W',8192)] = 1 // Fire Arrows
set udg_WeaponModifier[ModuloInteger('I02R',8192)] = 1 // Fire Arrows (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01E',8192)] = 1 // Fire Magic
set udg_WeaponModifier[ModuloInteger('I02V',8192)] = 1 // Fire Magic (Upgrade)
set udg_WeaponModifier[ModuloInteger('I000',8192)] = 1 // Fireball Cannon
set udg_WeaponModifier[ModuloInteger('I032',8192)] = 1 // Fireball Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I057',8192)] = 1 + WEAPON_MOD_CARRY_GROUND + WEAPON_MOD_TARGET_AIR // Flak
set udg_WeaponModifier[ModuloInteger('I058',8192)] = 1 + WEAPON_MOD_CARRY_GROUND + WEAPON_MOD_TARGET_AIR // Flak (Upgrade)
set udg_WeaponModifier[ModuloInteger('I001',8192)] = 1 // Flamer
set udg_WeaponModifier[ModuloInteger('I02X',8192)] = 1 // Flamer (Upgrade)
set udg_WeaponModifier[ModuloInteger('I02U',8192)] = 1 // Frost Laser
set udg_WeaponModifier[ModuloInteger('I030',8192)] = 1 // Frost Laser (Upgrade)
set udg_WeaponModifier[ModuloInteger('I00F',8192)] = 1 + WEAPON_MOD_TARGET_CREEP // Frost Magic (Creep)
set udg_WeaponModifier[ModuloInteger('I02C',8192)] = 1 // Frost Magic (Normal)
set udg_WeaponModifier[ModuloInteger('I064',8192)] = 1 // Gamma Vortex
set udg_WeaponModifier[ModuloInteger('I065',8192)] = 1 // Gamma Vortex (Upgrade)
set udg_WeaponModifier[ModuloInteger('I010',8192)] = 1 // Ghosts of Doom
set udg_WeaponModifier[ModuloInteger('I031',8192)] = 1 // Ghosts of Doom (Upgrade)
set udg_WeaponModifier[ModuloInteger('I002',8192)] = 1 // Glaive Cannon
set udg_WeaponModifier[ModuloInteger('I03A',8192)] = 1 // Glaive Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01H',8192)] = 1 + WEAPON_MOD_TARGET_HERO // God's Hammer
set udg_WeaponModifier[ModuloInteger('I035',8192)] = 1 + WEAPON_MOD_TARGET_HERO // God's Hammer (Upgrade)
set udg_WeaponModifier[ModuloInteger('I02Y',8192)] = 1 // Grenade Launcher (Normal)
set udg_WeaponModifier[ModuloInteger('I02O',8192)] = 1 + WEAPON_MOD_TARGET_AIR // Grenade Launcher (Air)
set udg_WeaponModifier[ModuloInteger('I00J',8192)] = 1 // Ice Cannon
set udg_WeaponModifier[ModuloInteger('I03D',8192)] = 1 // Ice Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I00K',8192)] = 1 // Infernal Rocks
set udg_WeaponModifier[ModuloInteger('I039',8192)] = 1 // Infernal Rocks (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01S',8192)] = 1 // Ion Cannon
set udg_WeaponModifier[ModuloInteger('I01T',8192)] = 1 // Ion Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I00D',8192)] = 1 // Laser (long)
set udg_WeaponModifier[ModuloInteger('I01N',8192)] = 1 // Laser (medium)
set udg_WeaponModifier[ModuloInteger('I01O',8192)] = 1 // Laser (short)
set udg_WeaponModifier[ModuloInteger('I00C',8192)] = 1 // Light Plasma Gun
set udg_WeaponModifier[ModuloInteger('I02A',8192)] = 1 // Light Plasma Gun (Upgrade)
set udg_WeaponModifier[ModuloInteger('I04L',8192)] = 1 // Lightning Magic
set udg_WeaponModifier[ModuloInteger('I04N',8192)] = 1 // Lightning Magic (Upgrade)
set udg_WeaponModifier[ModuloInteger('I008',8192)] = 1 // Machine Gun
set udg_WeaponModifier[ModuloInteger('I00X',8192)] = 1 // Machine Gun (Upgrade)
set udg_WeaponModifier[ModuloInteger('I017',8192)] = 1 // Magic Cannon
set udg_WeaponModifier[ModuloInteger('I033',8192)] = 1 // Magic Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01P',8192)] = 1 // Molotov Cocktail
set udg_WeaponModifier[ModuloInteger('I03H',8192)] = 1 // Molotov Cocktail
set udg_WeaponModifier[ModuloInteger('I00N',8192)] = 1 + WEAPON_MOD_TARGET_CREEP // Multibow
set udg_WeaponModifier[ModuloInteger('I03I',8192)] = 1 + WEAPON_MOD_TARGET_CREEP // Multibow (Upgrade)
set udg_WeaponModifier[ModuloInteger('I05B',8192)] = 1 // Mystic Cannon
set udg_WeaponModifier[ModuloInteger('I03E',8192)] = 1 // Mystic Cannon (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01Y',8192)] = 1 // Photon Bombs
set udg_WeaponModifier[ModuloInteger('I03J',8192)] = 1 // Photon Bombs (Upgrade)
set udg_WeaponModifier[ModuloInteger('I007',8192)] = 1 // Plasma Fragments (Normal)
set udg_WeaponModifier[ModuloInteger('I024',8192)] = 1 + WEAPON_MOD_TARGET_AIR // Plasma Fragments (Air)
set udg_WeaponModifier[ModuloInteger('I003',8192)] = 1 // Plasma Waves
set udg_WeaponModifier[ModuloInteger('I02F',8192)] = 1 // Plasma Waves (Upgrade)
set udg_WeaponModifier[ModuloInteger('I016',8192)] = 1 // Poison Magic
set udg_WeaponModifier[ModuloInteger('I03K',8192)] = 1 // Poison Magic (Upgrade)
set udg_WeaponModifier[ModuloInteger('I00M',8192)] = 1 // Psycho Laser
set udg_WeaponModifier[ModuloInteger('I03L',8192)] = 1 // Psycho Laser (Upgrade)
set udg_WeaponModifier[ModuloInteger('I019',8192)] = 1 // Psycho Magic
set udg_WeaponModifier[ModuloInteger('I027',8192)] = 1 // Psycho Magic (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01I',8192)] = 1 + WEAPON_MOD_TARGET_BUILDINGS // Rock Catapult (Building)
set udg_WeaponModifier[ModuloInteger('I01Z',8192)] = 1 // Rock Catapult (Normal)
set udg_WeaponModifier[ModuloInteger('I060',8192)] = 1 + WEAPON_MOD_TARGET_LONGRANGE // Rocket Hail
set udg_WeaponModifier[ModuloInteger('I061',8192)] = 1 + WEAPON_MOD_TARGET_LONGRANGE // Rocket Hail (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01C',8192)] = 1 + WEAPON_MOD_TARGET_HERO // Soulstone (Hero)
set udg_WeaponModifier[ModuloInteger('I038',8192)] = 1 + WEAPON_MOD_TARGET_CREEP // Soulstone (Creep)
set udg_WeaponModifier[ModuloInteger('I05I',8192)] = 1 + WEAPON_MOD_TARGET_GROUND // Star Shooter (Ground)
set udg_WeaponModifier[ModuloInteger('I05H',8192)] = 1 // Star Shooter (Normal)
set udg_WeaponModifier[ModuloInteger('I05E',8192)] = 1 // Supercell
set udg_WeaponModifier[ModuloInteger('I05F',8192)] = 1 // Supercell (Upgrade)
set udg_WeaponModifier[ModuloInteger('I005',8192)] = 1 // Swarm Rockets
set udg_WeaponModifier[ModuloInteger('I01A',8192)] = 1 // Swarm Rockets (Upgrade)
set udg_WeaponModifier[ModuloInteger('I05C',8192)] = 1 // Swarm of Chaos
set udg_WeaponModifier[ModuloInteger('I05D',8192)] = 1 // Swarm of Chaos (Upgrade)
set udg_WeaponModifier[ModuloInteger('I01D',8192)] = 1 // Tornado Summoner
set udg_WeaponModifier[ModuloInteger('I03M',8192)] = 1 // Tornado Summoner (Upgrade)
set udg_WeaponModifier[ModuloInteger('I04M',8192)] = 1 // The Light Fantastic
set udg_WeaponModifier[ModuloInteger('I04K',8192)] = 1 // The Light Fantastic (Upgrade)
endfunction
function GetAverageRange takes unit U, boolean WantAttackBuilding returns real
local integer Slot = 1
local item ItemInSlot
local real ItemCosts
local real ItemRange
local real AllCosts = 8 * I2R(GetUnitAbilityLevel(U, 'A01J'))
local real AllRange = 900 * AllCosts
if not WantAttackBuilding and ((GetUnitAbilityLevel(U, 'A06M') > 0) or (GetUnitAbilityLevel(U, 'A08Z') > 0)) then
set AllCosts = AllCosts + 8 * I2R(GetUnitAbilityLevel(U, 'A06M'))
set AllCosts = AllCosts + 8 * I2R(GetUnitAbilityLevel(U, 'A08Z'))
set AllRange = AllRange + 1300 * AllCosts
endif
loop
exitwhen Slot > 6
set ItemInSlot = UnitItemInSlotBJ(U, Slot)
set ItemRange = I2R(GetWeaponRange(GetItemTypeId(ItemInSlot)))
if ItemRange != 0 then
if not WantAttackBuilding or ItemRange < 1050 then
set ItemCosts = GetWidgetLife(ItemInSlot)
set AllRange = AllRange + ItemRange * ItemCosts / 100
set AllCosts = AllCosts + ItemCosts / 100
endif
endif
set Slot = Slot + 1
endloop
if AllCosts != 0 then
return AllRange / AllCosts
elseif WantAttackBuilding then
return GetRandomReal(600.00, 1050.00)
endif
return GetRandomReal(600.00, 1300.00)
endfunction
function AIWantsWeapon takes unit Tank returns boolean
if GetUnitPointValue(Tank) >= 25000 then
return true
elseif GetUnitPointValue(Tank) == 0 then
return false
endif
//H00Y = Trader, H014 = Exploder, H006 = Tinker
if (GetUnitTypeId(Tank)!='H00Y') and (GetUnitTypeId(Tank)!='H014') and (GetUnitTypeId(Tank)!='H006') then
if R2I(GetUnitState(Tank, UNIT_STATE_MAX_LIFE)) > ( GetBounty(Tank, false) / GetAverageRange(Tank, false) * 260 ) then
return true
endif
endif
return false
endfunction
function CheckBuyItem takes integer number, integer ID, integer Costs, real Chance returns nothing
local real random = GetRandomReal(0.00, 1.00)
if (Costs > udg_AI_BuyMinCosts) and (Costs <= udg_AI_BuyMaxCosts) and (Chance > random) then
//I03N = Upgrading item, in case the AI is just upgrading into an item it wants to buy
if (not UnitHasItemOfTypeBJ(udg_Tank[number], ID)) and (not UnitHasItemOfTypeBJ(udg_Tank[number], 'I03N')) then
set udg_AI_BuyID = ID
set udg_AI_BuyMinCosts = Costs
endif
endif
endfunction
function GetBestItem takes integer number returns nothing
local player P = GetPlayer(number)
local integer i = (3 - udg_Player_Team[number]) * 5
local integer j = i - 4
local integer ms = 0
local integer k = 0
set udg_AI_BuyID = 0
set udg_AI_BuyMaxCosts = GetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD)
set udg_AI_BuyMinCosts = R2I(GetUnitState(udg_Tank[number], UNIT_STATE_MAX_LIFE))
//Check if the Bot needs a hull
if (GetBounty(udg_Tank[number], false) > GetUnitState(udg_Tank[number], UNIT_STATE_MAX_LIFE) * 2.5) then
call CheckBuyItem(number, 'I02H', 1250, 0.50)
call CheckBuyItem(number, 'I00R', 2500, 0.50)
call CheckBuyItem(number, 'I00Q', 5000, 0.50)
endif
set udg_AI_BuyMinCosts = 0
//Get the average speed of the enemy team
loop
exitwhen (j > i)
if GetUnitMoveSpeed(udg_Tank[j]) > 5 then
set ms = ms + R2I(GetUnitMoveSpeed(udg_Tank[j]))
set k = k + 1
endif
set j = j + 1
endloop
if k != 0 then
set ms = ms / k
else
set ms = 0
endif
// Only check the following options, when the tank has no Speed or Ultimate Pack already
if (not UnitHasItemOfTypeBJ(udg_Tank[number], 'I012')) and (not UnitHasItemOfTypeBJ(udg_Tank[number], 'I01J')) and (udg_AI_BuyID == 0) then
// Check if Speed Boost is necessary
if ms > (GetUnitMoveSpeed(udg_Tank[number]) + 15) then
// If the tank already has Teleport -> combine
if UnitHasItemOfTypeBJ(udg_Tank[number], 'I014') then
// Speed Pack Blueprint
call CheckBuyItem(number, 'I012', 3600, 0.25)
else
// Speed Boost
if not UnitHasItemOfTypeBJ(udg_Tank[number], 'I00W') then
call CheckBuyItem(number, 'I00V', 1500, 0.25)
endif
endif
endif
// Check if a Teleporter is a viable option
if (GetBounty(udg_Tank[number], false) > 15000) and (udg_AI_BuyID == 0) then
// If the tank already has Speed Boost (Upgrade) -> combine
if UnitHasItemOfTypeBJ(udg_Tank[number], 'I00W') then
// Speed Pack Blueprint
call CheckBuyItem(number, 'I012', 3600, 0.25)
// If the tank already has normal Speed Boost -> combine
elseif UnitHasItemOfTypeBJ(udg_Tank[number], 'I00V') then
// Speed Pack Blueprint
call CheckBuyItem(number, 'I012', 5100, 0.25)
else
// Teleporter
call CheckBuyItem(number, 'I014', 3000, 0.25)
endif
endif
elseif UnitHasItemOfTypeBJ(udg_Tank[number], 'I012') then
// Ultimate Pack Blueprint
call CheckBuyItem(number, 'I01J', 6650, 0.50)
endif
// Only check the following options, when the tank has no Advanced Troop Command already
if (not UnitHasItemOfTypeBJ(udg_Tank[number], 'I053')) and (udg_AI_BuyID == 0) then
if UnitHasItemOfTypeBJ(udg_Tank[number], 'I00Y') then
//Advanced Troop Command
call CheckBuyItem(number, 'I053', 3500, 0.50)
else
//Troop Command
//Guard and Ghost Tank should buy Troop Command more likely
if (GetUnitTypeId(udg_Tank[number]) == 'H012') or (GetUnitTypeId(udg_Tank[number]) == 'H00R') then
call CheckBuyItem(number, 'I00Y', 2500, 0.50)
else
call CheckBuyItem(number, 'I00Y', 2500, 0.15)
endif
endif
endif
if udg_AI_BuyID != 0 then
set udg_AI_Command[number] = "itemshop"
endif
endfunction
function SellPackParts takes unit U returns nothing
local integer i
local integer ID
local item SellThis
//Speed Pack, Advanced Troop Command, Ultimate Pack
if ((udg_AI_BuyID - 'I012')*(udg_AI_BuyID - 'I053')*(udg_AI_BuyID - 'I01J')) == 0 then
set i = 0
loop
exitwhen i > 5
set ID = GetItemTypeId(UnitItemInSlot(U, i))
//Sell parts for Speed Pack
if (udg_AI_BuyID == 'I012') then
if (ID == 'I014') or (ID == 'I00W') or (ID == 'I00V') then
set SellThis = UnitItemInSlot(U, i)
endif
//Sell parts for Advanced Troop Command
elseif (udg_AI_BuyID == 'I053') then
if (ID == 'I00Y') then
set SellThis = UnitItemInSlot(U, i)
endif
//Sell parts for Ultimate Pack
elseif (udg_AI_BuyID == 'I01J') then
if (ID == 'I012') then
set SellThis = UnitItemInSlot(U, i)
endif
endif
set i = i + 1
endloop
call RemoveItem( SellThis )
endif
set SellThis = null
endfunction
function BuyBestItem takes unit U returns nothing
local integer i
local integer ID
local item SellThis
local item NewItem
local player P = GetOwningPlayer(U)
local integer Team = udg_Player_Team[GetPlayerNr(P)]
call GetBestItem(GetPlayerNr(GetOwningPlayer(U)))
if udg_AI_BuyID != 0 then
call SellPackParts(U)
if UnitInventoryCount(U) == 6 then
set SellThis = UnitItemInSlot(U, 0)
set i = 1
loop
exitwhen i > 5
if ( GetWidgetLife(UnitItemInSlot(U, i)) < GetWidgetLife(SellThis) ) then
set SellThis = UnitItemInSlot(U, i)
endif
set i = i + 1
endloop
set i = GetItemCharges(SellThis)
loop
set NewItem = CreateItem(GetItemTypeId(SellThis),GetRandomReal(GetRectMinX(udg_JunkyardRect[Team])+16,GetRectMaxX(udg_JunkyardRect[Team])-16), GetRandomReal(GetRectMinY(udg_JunkyardRect[Team])+16,GetRectMaxY(udg_JunkyardRect[Team])-16))
call SetItemUserData(NewItem, 2)
call SetItemPlayer( NewItem, P, true )
set i = i - 1
exitwhen i <= 0
endloop
set NewItem = null
call AdjustPlayerStateBJ( R2I(GetWidgetLife(SellThis)), P, PLAYER_STATE_RESOURCE_GOLD )
call RemoveItem( SellThis )
call DestroyEffect( AddSpecialEffectTarget("UI\\Feedback\\GoldCredit\\GoldCredit.mdl", U, "origin") )
set SellThis = null
set i = 0
endif
set bj_lastCreatedItem = UnitAddItemById(U, udg_AI_BuyID)
call SetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD) - R2I(GetWidgetLife(bj_lastCreatedItem)))
endif
set udg_AI_Command[GetPlayerNr(P)] = "attack"
endfunction
function CheckBuyTank takes player P, integer ID, integer Costs returns nothing
if Costs >= udg_AI_BuyMinCosts and Costs <= udg_AI_BuyMaxCosts then
if (TankMeetsTechRequirements(P, ID) == 0) and not AnyAllyHasTankOfType(P,ID) then
set udg_AI_BuyID = ID
set udg_AI_BuyMinCosts = Costs
endif
endif
endfunction
function GetBestTank takes integer number returns nothing
local player P = GetPlayer(number)
set udg_AI_BuyID = 0
set udg_AI_BuyMaxCosts = GetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD) + GetUnitPointValue(udg_Tank[number]) / 2
if GetUnitTypeId(udg_Tank[number])=='H00Y' or GetUnitTypeId(udg_Tank[number])=='H014' or GetUnitTypeId(udg_Tank[number])=='H006' then
set udg_AI_BuyMinCosts = 0
else
set udg_AI_BuyMinCosts = R2I(GetUnitState(udg_Tank[number], UNIT_STATE_MAX_LIFE)) * 2
endif
if udg_AI_BuyMinCosts > 25000 then
set udg_AI_BuyMinCosts = 25000
endif
call CheckBuyTank(P,'H00B',4000)
if GetRandomInt(0,1)==0 then
call CheckBuyTank(P,'H00C',4500)
call CheckBuyTank(P,'H00R',4500)
else
call CheckBuyTank(P,'H00R',4500)
call CheckBuyTank(P,'H00C',4500)
endif
call CheckBuyTank(P,'H012',5000)
call CheckBuyTank(P,'H00D',5500)
call CheckBuyTank(P,'H00I',6500)
call CheckBuyTank(P,'H01U',7500)
call CheckBuyTank(P,'H00E',8000)
call CheckBuyTank(P,'H01S',9000)
call CheckBuyTank(P,'H00F',10000)
call CheckBuyTank(P,'H00H',13000)
call CheckBuyTank(P,'H01R',16000)
call CheckBuyTank(P,'H00K',18000)
call CheckBuyTank(P,'H01I',25000)
endfunction
function CheckBuyObject takes integer ID, integer Costs, real AverageRange returns nothing
local integer Range = GetWeaponRange(ID)
local real RangeFactor
local real random = GetRandomReal(0.15, 0.25)
if AverageRange > Range then
set RangeFactor = I2R(Range) / AverageRange * 0.75 + random
else
set RangeFactor = AverageRange / I2R(Range) * 0.75 + random
endif
if I2R(Costs) * RangeFactor >= I2R(udg_AI_BuyMinCosts) and Costs <= udg_AI_BuyMaxCosts then
set udg_AI_BuyID = ID
set udg_AI_BuyMinCosts = Costs
endif
endfunction
function GetBestWeapon takes integer number returns nothing
local integer TargetShop = 0
local integer BuyID = 0
local integer i
local real AverageRange = GetAverageRange( udg_Tank[number], false )
local item SellThis
set udg_AI_BuyID = 0
set udg_AI_BuyMaxCosts = GetPlayerState(GetPlayer(number), PLAYER_STATE_RESOURCE_GOLD)
set udg_AI_BuyMinCosts = IMinBJ( (GetBounty(udg_Tank[number], false) - GetUnitPointValue(udg_Tank[number]) ) * 2 / 5, 30000 )
if UnitInventoryCount(udg_Tank[number]) == 6 then
if udg_Afk[number] then
return
endif
set SellThis = UnitItemInSlot(udg_Tank[number], 0)
set i = 1
loop
exitwhen i > 5
if ( GetWidgetLife(UnitItemInSlot(udg_Tank[number], i)) < GetWidgetLife(SellThis) ) then
set SellThis = UnitItemInSlot(udg_Tank[number], i)
endif
set i = i + 1
endloop
set i = 0
set udg_AI_BuyMaxCosts = udg_AI_BuyMaxCosts + R2I(GetWidgetLife(SellThis))
set udg_AI_BuyMinCosts = IMaxBJ(udg_AI_BuyMinCosts,R2I(GetWidgetLife(SellThis))*6/5)
endif
if udg_AI_Command[number] == "shop1" then
set TargetShop = 1
elseif udg_AI_Command[number] == "shop2" then
set TargetShop = 2
elseif udg_AI_Command[number] == "shop3" then
set TargetShop = 3
elseif udg_AI_Command[number] == "shop4" then
set TargetShop = 4
endif
if TargetShop == 0 or TargetShop == 1 then
call CheckBuyObject('I00N',1100,AverageRange)
call CheckBuyObject('I002',1500,AverageRange)
call CheckBuyObject('I01P',1500,AverageRange)
//call CheckBuyObject('I02Y',1750,AverageRange)
call CheckBuyObject('I00E',2000,AverageRange)
call CheckBuyObject('I05W',2000,AverageRange)
call CheckBuyObject('I00C',2000,AverageRange)
call CheckBuyObject('I000',2200,AverageRange)
call CheckBuyObject('I00A',2200,AverageRange)
call CheckBuyObject('I00G',2700,AverageRange)
call CheckBuyObject('I05Y',2800,AverageRange)
call CheckBuyObject('I00J',3000,AverageRange)
if BuyID != udg_AI_BuyID then
set BuyID = udg_AI_BuyID
set udg_AI_Command[number] = "shop1"
endif
endif
if TargetShop == 0 or TargetShop == 2 then
//call CheckBuyObject('I01I',3000,AverageRange)
call CheckBuyObject('I02W',3500,AverageRange)
call CheckBuyObject('I003',4000,AverageRange)
//call CheckBuyObject('I038',4800,AverageRange)
//call CheckBuyObject('I00B',5000,AverageRange)
call CheckBuyObject('I04M',6000,AverageRange)
call CheckBuyObject('I01H',6000,AverageRange)
//call CheckBuyObject('I007',6000,AverageRange)
call CheckBuyObject('I001',6750,AverageRange)
call CheckBuyObject('I01O',7000,AverageRange)
//call CheckBuyObject('I00H',7000,AverageRange)
call CheckBuyObject('I00K',8500,AverageRange)
if BuyID != udg_AI_BuyID then
set BuyID = udg_AI_BuyID
set udg_AI_Command[number] = "shop2"
endif
endif
if TargetShop == 0 or TargetShop == 3 then
call CheckBuyObject('I01F',1111,AverageRange)
call CheckBuyObject('I01D',2222,AverageRange)
call CheckBuyObject('I017',3333,AverageRange)
call CheckBuyObject('I01B',4444,AverageRange)
call CheckBuyObject('I01G',5050,AverageRange)
call CheckBuyObject('I016',5555,AverageRange)
call CheckBuyObject('I00F',6060,AverageRange)
call CheckBuyObject('I04L',6666,AverageRange)
call CheckBuyObject('I010',7070,AverageRange)
call CheckBuyObject('I018',7777,AverageRange)
call CheckBuyObject('I01E',8888,AverageRange)
call CheckBuyObject('I019',9999,AverageRange)
if BuyID != udg_AI_BuyID then
set BuyID = udg_AI_BuyID
set udg_AI_Command[number] = "shop3"
endif
endif
if TargetShop == 0 or TargetShop == 4 then
call CheckBuyObject('I008',2500,AverageRange)
call CheckBuyObject('I005',3300,AverageRange)
call CheckBuyObject('I060',6000,AverageRange)
call CheckBuyObject('I01U',6000,AverageRange)
call CheckBuyObject('I02Z',6000,AverageRange)
call CheckBuyObject('I01S',7500,AverageRange)
call CheckBuyObject('I01K',11000,AverageRange)
call CheckBuyObject('I062',12000,AverageRange)
call CheckBuyObject('I01R',15000,AverageRange)
call CheckBuyObject('I01Y',20000,AverageRange)
call CheckBuyObject('I00M',25000,AverageRange)
call CheckBuyObject('I02U',30000,AverageRange)
//A different shop, but the same to the AI
call CheckBuyObject('I055',1000,AverageRange)
call CheckBuyObject('I059',8000,AverageRange)
call CheckBuyObject('I057',8000,AverageRange)
call CheckBuyObject('I05E',25000,AverageRange)
call CheckBuyObject('I05C',30000,AverageRange)
if BuyID != udg_AI_BuyID then
set BuyID = udg_AI_BuyID
set udg_AI_Command[number] = "shop4"
endif
endif
endfunction
function BuyBestWeapon takes unit U returns nothing
local integer i
local item SellThis
local item NewItem
local player P = GetOwningPlayer(U)
local integer Team = udg_Player_Team[GetPlayerNr(P)]
call GetBestWeapon(GetPlayerNr(GetOwningPlayer(U)))
if udg_AI_BuyID != 0 then
if UnitInventoryCount(U) == 6 then
set SellThis = UnitItemInSlot(U, 0)
set i = 1
loop
exitwhen i > 5
if ( GetWidgetLife(UnitItemInSlot(U, i)) < GetWidgetLife(SellThis) ) then
set SellThis = UnitItemInSlot(U, i)
endif
set i = i + 1
endloop
set i = GetItemCharges(SellThis)
loop
set NewItem = CreateItem(GetItemTypeId(SellThis),GetRandomReal(GetRectMinX(udg_JunkyardRect[Team])+16,GetRectMaxX(udg_JunkyardRect[Team])-16), GetRandomReal(GetRectMinY(udg_JunkyardRect[Team])+16,GetRectMaxY(udg_JunkyardRect[Team])-16))
call SetItemUserData(NewItem, 2)
call SetItemPlayer( NewItem, P, true )
set i = i - 1
exitwhen i <= 0
endloop
set NewItem = null
call AdjustPlayerStateBJ( R2I(GetWidgetLife(SellThis)), P, PLAYER_STATE_RESOURCE_GOLD )
call RemoveItem( SellThis )
call DestroyEffect( AddSpecialEffectTarget("UI\\Feedback\\GoldCredit\\GoldCredit.mdl", U, "origin") )
set SellThis = null
set i = 0
endif
set bj_lastCreatedItem = UnitAddItemById(U, udg_AI_BuyID)
call SetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD) - R2I(GetWidgetLife(bj_lastCreatedItem)))
endif
set udg_AI_Command[GetPlayerNr(P)] = "attack"
endfunction
function CoordsInBase takes real X, real Y, unit Tank returns boolean
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(Tank))] == 1 then
return RectContainsCoords(gg_rct_Team_1_Base_Main, X, Y)
endif
return RectContainsCoords(gg_rct_Team_2_Base_Main, X, Y)
endfunction
function GetBestTarget takes real NearX, real NearY, group G returns unit
local unit PickUnit = FirstOfGroup( G )
local unit Target = null
local real PickUnitDist
local real TargetDist = 0
local real dx
local real dy
loop
exitwhen PickUnit == null
set dx = GetUnitX(PickUnit) - NearX
set dy = GetUnitY(PickUnit) - NearY
set PickUnitDist = (dx * dx + dy * dy)
if PickUnitDist < TargetDist or TargetDist == 0 then
set Target = PickUnit
set TargetDist = PickUnitDist
endif
call GroupRemoveUnit( G, PickUnit )
set PickUnit = FirstOfGroup( G )
endloop
set PickUnit = null
return Target
endfunction
function UseCPTeleporter takes real TargetX, real TargetY, unit Tank returns boolean
local unit CPStart
local unit CPEnd
local real TankX = GetUnitX(Tank)
local real TankY = GetUnitY(Tank)
local real DistX = TankX-TargetX
local real DistY = TankY-TargetY
local real FullDistance = SquareRoot(DistX*DistX+DistY*DistY)
local real StartDistance
local real EndDistance
local real factor
local real ms = GetUnitMoveSpeed(Tank)
local real BaseX = GetLocationX(udg_Move_Points[udg_Player_Team[GetPlayerNr(GetOwningPlayer(Tank))]+25])
local real BaseY = GetLocationY(udg_Move_Points[udg_Player_Team[GetPlayerNr(GetOwningPlayer(Tank))]+25])
local group G
if GetPlayerState( GetOwningPlayer(Tank), PLAYER_STATE_RESOURCE_GOLD ) < 75 then
return false
endif
set udg_TempInt = GetPlayerNr(GetOwningPlayer(Tank))
//Ground tanks need longer to cover a distance
if IsUnitType(Tank, UNIT_TYPE_FLYING) then
set factor = 1.0
else
set factor = 1.2
endif
set FullDistance = FullDistance * factor
set G = NewGroup()
//The distance from the Bot to the nearest CP
set udg_Filter_Player = GetOwningPlayer(Tank)
call GroupEnumUnitsInRect(G, udg_Playable_Map, FILTER_VALID_CPTP_SOURCE)
set CPStart = GetBestTarget( TankX, TankY, G )
if CPStart != null then
set DistX = GetUnitX(CPStart) - TankX
set DistY = GetUnitY(CPStart) - TankY
if CoordsInBase(TankX,TankY,Tank) then
set StartDistance = 0
else
set StartDistance = SquareRoot(DistX*DistX+DistY*DistY) * factor
endif
else
set StartDistance = 1000000
endif
call GroupClear(G)
//The distance from the chosen target to the nearest CP
call GroupEnumUnitsInRect(G, udg_Playable_Map, FILTER_VALID_CPTP_TARGET)
set CPEnd = GetBestTarget( TargetX, TargetY, G )
if CPEnd != null then
set DistX = GetUnitX(CPEnd) - TargetX
set DistY = GetUnitY(CPEnd) - TargetY
set EndDistance = SquareRoot(DistX*DistX+DistY*DistY) * factor
else
set EndDistance = 1000000
endif
call GroupClear(G)
//Check if driving to the base is faster
set DistX = BaseX - TankX
set DistY = BaseY - TankY
if StartDistance > (SquareRoot(DistX*DistX+DistY*DistY)-1400)*factor then
set TankX = BaseX
set TankY = BaseY
else
set TankX = GetUnitX(CPStart)
set TankY = GetUnitY(CPStart)
endif
set TargetX = GetUnitX(CPEnd)
set TargetY = GetUnitY(CPEnd)
set CPStart = null
set CPEnd = null
call ReleaseGroup(G)
set G = null
//No need to teleport in between the base
if CoordsInBase(TankX,TankY,Tank) and CoordsInBase(TargetX,TargetY,Tank) then
return false
endif
//Check which option is faster
if StartDistance + EndDistance + 3*ms < FullDistance then
//Teleport if near a CP or order Bot to drive near a CP
if (StartDistance <= 500) then
call IssuePointOrder( Tank, "spies", TargetX, TargetY )
return true
else
call IssuePointOrder( Tank, "move", TankX, TankY )
return true
endif
endif
return false
endfunction
function GetGroupDanger_Enum takes nothing returns nothing
local unit U = GetEnumUnit()
local real r = GetUnitState(U, UNIT_STATE_LIFE)
local integer i = 0
if r <= 0 or r >= 500000 then
set U = null
return
endif
if IsUnitType(U, UNIT_TYPE_HERO) then
loop
exitwhen i > 5
set r = r + GetWidgetLife(UnitItemInSlot(U,i))
set i = i + 1
endloop
set r = r * GetUnitState(U, UNIT_STATE_LIFE) / GetUnitState(U, UNIT_STATE_MAX_LIFE)
elseif IsUnitType(U, UNIT_TYPE_STRUCTURE)==true then
if r>24000 then
set r = 12000
else
set r = r/2
endif
endif
if IsUnitEnemy(U, GetPlayer(bj_forLoopAIndexEnd)) then
set udg_AI_DangerLevel = (udg_AI_DangerLevel + r) * 1.05
elseif IsUnitAlly(U, GetPlayer(bj_forLoopAIndexEnd)) then
set udg_AI_SafetyLevel = (udg_AI_SafetyLevel + r) * 1.05
endif
set U = null
endfunction
endlibrary
//TESH.scrollpos=50
//TESH.alwaysfold=0
function Trig_AI_Move_Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) and udg_AI_IsBot[GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))]
endfunction
function Trig_AI_Move_Anti_Leak_Condition takes nothing returns boolean
return true
endfunction
function Trig_AI_Move_Actions takes nothing returns nothing
local real DangerLevel
local integer MP
local string lane
local unit U = GetTriggerUnit()
local real Id = GetPlayerNr(GetOwningPlayer(U))
local real WaitTime
local group G = NewGroup()
//Each bot has to wait for a different time, to make sure, they won't teleport to the same
//CP, because the danger level was still the same
//The CP-TP trigger makes sure, that the AI considers other bots, which attempt to port to a CP
if Id > 5 then
set WaitTime = (Id - 5) / 2
else
set WaitTime = Id / 2
endif
call GameTimeWait(WaitTime)
set udg_AI_DangerLevel = 0
set udg_AI_SafetyLevel = 0
//Used in the function 'GetGroupDanger_Enum
//crappy style of programming, use an own global variable instead!
set bj_forLoopAIndexEnd = GetPlayerNr(GetOwningPlayer(U))
//Mid, Mid
set MP = 9
call GroupEnumUnitsInRangeEx(G,GetLocationX(udg_Move_Points[MP]),GetLocationY(udg_Move_Points[MP]),3000, Condition(function Trig_AI_Move_Anti_Leak_Condition))
call ForGroup(G,function GetGroupDanger_Enum)
call GroupClear(G)
set DangerLevel = (udg_AI_DangerLevel - udg_AI_SafetyLevel)//*GetRandomReal(0.8,1.2)
set lane = "mid"
set udg_AI_DangerLevel = 0
set udg_AI_SafetyLevel = 0
//right Lane, Mid
set MP = 16
call GroupEnumUnitsInRangeEx(G,GetLocationX(udg_Move_Points[MP]),GetLocationY(udg_Move_Points[MP]),3000, Condition(function Trig_AI_Move_Anti_Leak_Condition))
call ForGroup(G,function GetGroupDanger_Enum)
call GroupClear(G)
if (udg_AI_DangerLevel - udg_AI_SafetyLevel) > DangerLevel then
set DangerLevel = (udg_AI_DangerLevel - udg_AI_SafetyLevel)//*GetRandomReal(0.8,1.2)
set lane = "right"
endif
set udg_AI_DangerLevel = 0
set udg_AI_SafetyLevel = 0
//left Lane, Mid
set MP = 13
call GroupEnumUnitsInRangeEx(G,GetLocationX(udg_Move_Points[MP]),GetLocationY(udg_Move_Points[MP]),3000, Condition(function Trig_AI_Move_Anti_Leak_Condition))
call ForGroup(G,function GetGroupDanger_Enum)
call GroupClear(G)
//*GetRandomReal(0.8,1.2)
if ((udg_AI_DangerLevel - udg_AI_SafetyLevel)) > DangerLevel then
set lane = "left"
endif
if lane == "mid" then
set MP = 9
elseif lane == "left" then
set MP = 13
else
set MP = 16
endif
//call DebugMsg("Player: " + R2S(Id))
//call DebugMsg("Lane: " + lane)
//call DebugMsg("DangerLevel: " + R2S(DangerLevel))
//call DebugMsg("-------------------")
if not UseCPTeleporter(GetLocationX(udg_Move_Points[MP]),GetLocationY(udg_Move_Points[MP]), U) then
call IssuePointOrderLocBJ( U, "move", udg_Move_Points[MP] )
endif
call ReleaseGroup(G)
set G = null
set U = null
endfunction
//===========================================================================
function InitTrig_AI_Move takes nothing returns nothing
set gg_trg_AI_Move = CreateTrigger( )
call TriggerAddCondition( gg_trg_AI_Move, Condition( function Trig_AI_Move_Conditions ) )
call TriggerAddAction( gg_trg_AI_Move, function Trig_AI_Move_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_AI_Fight_Anti_Leak_Condition takes nothing returns boolean
return true
endfunction
function Trig_AI_Fight_IsStrongEnemy takes nothing returns boolean
local unit U = GetFilterUnit()
if ( not IsUnitEnemy(U, GetPlayer(udg_AI_Number)) ) or GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
set U = null
return false
endif
if IsUnitType(U, UNIT_TYPE_HERO) or GetUnitTypeId(U) == 'h000' or GetUnitTypeId(U) == 'h001' then
set U = null
return true
endif
set U = null
return false
endfunction
function Trig_AI_Fight_IsProtected takes unit U returns boolean
local group NearUnits = NewGroup()
local boolean Ret
call GroupEnumUnitsInRange(NearUnits, GetUnitX(U), GetUnitY(U), 1000.00, Condition(function Trig_AI_Fight_IsStrongEnemy))
set Ret = (FirstOfGroup(NearUnits) != null)
call ReleaseGroup( NearUnits )
set NearUnits = null
return Ret
endfunction
function Trig_AI_Fight_IsUnprotectedEnemyCP takes nothing returns boolean
local unit U = GetFilterUnit()
if GetUnitTypeId(U) == 'h00P' and IsUnitEnemy( U, GetPlayer(udg_AI_Number) ) then
if not Trig_AI_Fight_IsProtected(U) then
set U = null
return true
endif
endif
set U = null
return false
endfunction
function Trig_AI_Fight_IsValidNearbyTarget takes nothing returns boolean
local unit U = GetFilterUnit()
if (not IsUnitEnemy(U, GetPlayer(udg_AI_Number))) or GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
set U = null
return false
endif
// Is Control Point?
if GetUnitTypeId(U) == 'h00P' then
if (not IsTriggerEnabled(gg_trg_Control_Point)) or Trig_AI_Fight_IsProtected(U) then
set U = null
return false
endif
else
// Is Invulnerable or Invisible?
if (GetUnitState(U, UNIT_STATE_LIFE) >= 500000) or (IsUnitInvisible(U, GetPlayer(udg_AI_Number)) ) then
set U = null
return false
endif
endif
set U = null
return true
endfunction
function Trig_AI_Fight_IsAlliedCPTakenOver takes nothing returns boolean
local unit U = GetFilterUnit()
if IsUnitAlly(U, GetPlayer(udg_AI_Number)) then
if GetUnitTypeId(U) == 'h00P' then
if Trig_AI_Fight_IsProtected(U) then
set U = null
return true
endif
endif
endif
set U = null
return false
endfunction
function Trig_AI_Fight_IsValidMoveTarget takes nothing returns boolean
local unit U = GetFilterUnit()
if not ( IsUnitEnemy(U, GetPlayer(udg_AI_Number)) ) or GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
set U = null
return false
endif
if IsUnitType(U, UNIT_TYPE_HERO) or IsUnitType(U, UNIT_TYPE_STRUCTURE)==true then
set U = null
return true
endif
set U = null
return false
endfunction
function Trig_AI_Fight_GetBestTargetFromBase takes real NearX, real NearY, group G returns unit
local unit PickUnit = FirstOfGroup( G )
local unit Target = null
local real PickUnitDist
local real TargetDist = 0
local real BaseX = GetUnitX(udg_HQ[udg_Player_Team[udg_AI_Number]])
local real BaseY = GetUnitY(udg_HQ[udg_Player_Team[udg_AI_Number]])
local real dx
local real dy
loop
exitwhen PickUnit == null
set dx = GetUnitX(PickUnit) - NearX
set dy = GetUnitY(PickUnit) - NearY
set PickUnitDist = dx * dx + dy * dy
set dx = GetUnitX(PickUnit) - BaseX
set dy = GetUnitY(PickUnit) - BaseY
set PickUnitDist = PickUnitDist * (dx+dy)*(dx+dy)
if (PickUnitDist < TargetDist or TargetDist == 0) and (IsUnitVisible(PickUnit, GetPlayer(udg_AI_Number))) then
set Target = PickUnit
set TargetDist = PickUnitDist
endif
call GroupRemoveUnit( G, PickUnit )
set PickUnit = FirstOfGroup( G )
endloop
set PickUnit = null
return Target
endfunction
function Trig_AI_Fight_Think_UseSpell takes unit Caster, unit Target, integer FinisherType returns nothing
local real DistX = GetUnitX(Target)-GetUnitX(Caster)
local real DistY = GetUnitY(Target)-GetUnitY(Caster)
local real TargetDist = SquareRoot(DistX*DistX+DistY*DistY)
local integer TankType = GetUnitTypeId(Caster)
if (GetUnitState(Caster, UNIT_STATE_LIFE) > 0) and (GetUnitState(Target, UNIT_STATE_LIFE) > 0) then
if TankType=='H01L' then //Scout
if TargetDist<=1000 and GetUnitAbilityLevel(Caster,'A09O')!=0 then //Ensnare
call IssueTargetOrder (Caster,"ensnare", Target)
endif
elseif TankType=='H009' then //Light Tank
if FinisherType==0 and TargetDist<=1000 and GetUnitAbilityLevel(Caster,'A03W')!=0 then //Multi Rocket Shot
call IssueImmediateOrder (Caster,"fanofknives")
elseif TargetDist<=1000 and GetUnitAbilityLevel(Caster,'A02T')!=0 then //Mini-Rocket
call IssueTargetOrder(Caster,"thunderbolt",Target)
endif
elseif TankType=='H008' then //Helicopter
if FinisherType==0 and TargetDist<=650 and GetUnitAbilityLevel(Caster,'A01B')!=0 then //Fire Bomb
call IssueTargetOrder(Caster,"shadowstrike",Target)
elseif TargetDist<=1000 and GetUnitAbilityLevel(Caster,'A02T')!=0 then //Mini-Rocket
call IssueTargetOrder(Caster,"thunderbolt",Target)
endif
elseif TankType=='H00X' then //Antigrav
if FinisherType==0 and TargetDist<=800 and GetUnitAbilityLevel(Caster,'A07E')!=0 then //EMP Torpedos
call IssueImmediateOrder (Caster,"fanofknives")
elseif TargetDist<=1000 and GetUnitAbilityLevel(Caster,'A055')!=0 then //Plasma Cluster
call IssuePointOrder(Caster,"clusterrockets",GetUnitX(Target),GetUnitY(Target))
endif
elseif TankType=='H011' then //Goblin Shredder
if FinisherType==0 and TargetDist<=800 and GetUnitAbilityLevel(Caster,'A03D')!=0 then //Metal Stars
call IssueImmediateOrder (Caster,"fanofknives")
elseif TargetDist<=(600 + 200 * GetUnitAbilityLevel(Caster,'A04N')) and GetUnitAbilityLevel(Caster,'A04N')!=0 then //Unit Teleport
call IssueTargetOrder(Caster,"shadowstrike",Target)
endif
elseif TankType=='H007' then //Demolisher
if FinisherType==0 and TargetDist<=900 and GetUnitAbilityLevel(Caster,'A02R')!=0 then //Jet Wave
call IssuePointOrder(Caster,"carrionswarm",GetUnitX(Target),GetUnitY(Target))
elseif TargetDist<=700 and GetUnitAbilityLevel(Caster,'A02F')!=0 then //Burning Oil
call IssueTargetOrder(Caster,"acidbomb",Target)
endif
elseif TankType=='H00C' then //Air Ship
if FinisherType==0 and TargetDist<=900 and GetUnitAbilityLevel(Caster,'A023')!=0 then //Electro Shocker
call IssueTargetOrder(Caster,"forkedlightning",Target)
elseif TargetDist<=1000 and GetUnitAbilityLevel(Caster,'A02Z')!=0 then //Plasma Rain
call IssuePointOrder(Caster,"blizzard",GetUnitX(Target),GetUnitY(Target))
endif
elseif TankType=='H00B' then //Thunder Tank
if FinisherType==0 and TargetDist<=1000 and GetUnitAbilityLevel(Caster,'A032')!=0 then //Chain Lightning
call IssueTargetOrder(Caster,"chainlightning",Target)
elseif TargetDist<=1000 and GetUnitAbilityLevel(Caster,'A02N')!=0 then //Lightning Strike
call IssueTargetOrder(Caster,"thunderbolt",Target)
endif
elseif TankType=='H012' or TankType=='H013' then //Guard
if FinisherType==0 and TargetDist<=1200 and GetUnitAbilityLevel(Caster,'A03Z')!=0 then //Entangling Roots
call IssuePointOrder(Caster,"clusterrockets",GetUnitX(Target),GetUnitY(Target))
endif
elseif TankType=='H00D' then //Heavy Tank
if FinisherType==0 and TargetDist<=1500 and GetUnitAbilityLevel(Caster,'A0B6')!=0 then //Hail Of Bombs
call IssueImmediateOrder (Caster,"fanofknives")
elseif TargetDist<=2000 and GetUnitAbilityLevel(Caster,'A024')!=0 then //Aiming Rocket
call IssueTargetOrder(Caster,"thunderbolt",Target)
endif
elseif TankType=='H00I' then //Goblin Tank
if FinisherType==0 and TargetDist<=500 and GetUnitAbilityLevel(Caster,'A00Z')!=0 then //Goblin Riots
call IssueImmediateOrder (Caster,"waterelemental")
elseif TargetDist<=750 and GetUnitAbilityLevel(Caster,'A026')!=0 then //Shockwave
call IssueTargetOrder(Caster,"thunderbolt",Target)
endif
elseif TankType=='H01U' then //Earth Robot
if TargetDist<=1000 and IsUnitType(Target, UNIT_TYPE_GROUND)==true and GetUnitAbilityLevel(Caster,'A09R')!=0 then //Earthquake
call IssuePointOrder(Caster,"earthquake",GetUnitX(Target),GetUnitY(Target))
endif
elseif TankType=='H00E' then //Sky Tank
if FinisherType==0 and TargetDist<=700 and IsUnitType(Target, UNIT_TYPE_GROUND)==true and GetUnitAbilityLevel(Caster,'A04K')!=0 then //Lightning Quake
call IssuePointOrder(Caster,"blizzard",GetUnitX(Target),GetUnitY(Target))
elseif TargetDist<=900 and GetUnitAbilityLevel(Caster,'A049')!=0 then //Energy Bomb
call IssueTargetOrder(Caster,"shadowstrike",Target)
endif
elseif TankType=='H01S' then //Hunter
if FinisherType==0 and TargetDist<=2000 and GetUnitAbilityLevel(Caster,'A0AG')!=0 then //Main Gun
call IssueTargetOrder(Caster,"healingspray",Target)
elseif TargetDist<=1200 and GetUnitAbilityLevel(Caster,'A094')!=0 then //Gravity Grenade
call IssueTargetOrder(Caster,"flamestrike",Target)
endif
elseif TankType=='H00F' then //Demon Tank
if FinisherType==0 and TargetDist<=900 and GetUnitAbilityLevel(Caster,'A030')!=0 then //Banish
call IssueTargetOrder(Caster,"banish",Target)
elseif TargetDist<=1500 and GetUnitAbilityLevel(Caster,'A01D')!=0 then //Lava Shot
call IssueTargetOrder(Caster,"thunderbolt",Target)
endif
elseif TankType=='H00H' then //Frost Robot
if FinisherType==0 and TargetDist<=1000 and GetUnitAbilityLevel(Caster,'A04R')!=0 then //Ice Rain
call IssuePointOrder(Caster,"blizzard",GetUnitX(Target),GetUnitY(Target))
elseif TargetDist<=1200 and GetUnitAbilityLevel(Caster,'A02Y')!=0 then //Ice Prison
call IssueTargetOrder(Caster,"thunderbolt",Target)
endif
elseif TankType=='H01R' then //Sky Fortress
if FinisherType==0 and TargetDist<=(800 + 200 * GetUnitAbilityLevel(Caster,'A09C')) and GetUnitAbilityLevel(Caster,'A09C')!=0 then //Turbo Boost
call IssueImmediateOrder (Caster,"fanofknives")
elseif TargetDist<=(500 + 100 * GetUnitAbilityLevel(Caster,'A09E')) and GetUnitAbilityLevel(Caster,'A09E')!=0 then //System Overload
call IssueTargetOrder(Caster,"magicleash",Target)
endif
elseif TankType=='H00K' then //Infernal Robot
if FinisherType==0 and TargetDist<=900 and GetUnitAbilityLevel(Caster,'A08Y')!=0 then //Infernal Fire Rain
call IssueImmediateOrder (Caster,"stomp")
elseif TargetDist<=800 and GetUnitAbilityLevel(Caster,'A03E')!=0 then //Chaos Wave
call IssueImmediateOrder (Caster,"fanofknives")
endif
elseif TankType=='H01I' then //Titan
if FinisherType==0 and TargetDist<=1300 and GetUnitAbilityLevel(Caster,'A08O')!=0 then //Hail Fire
call IssueTargetOrder(Caster,"clusterrockets",Target)
elseif TargetDist<=900 and GetUnitAbilityLevel(Caster,'A08V')!=0 then //Devil Explosion
call IssueImmediateOrder (Caster,"fanofknives")
endif
endif
endif
endfunction
function Trig_AI_Fight_IsAlliedHealingUnit takes nothing returns boolean
local unit U = GetFilterUnit()
if not ( IsUnitAlly(U, GetPlayer(udg_AI_Number)) ) or (GetUnitState(U, UNIT_STATE_LIFE) <= 0) or ( U == udg_AI_Tank ) then
set U = null
return false
endif
// Does the target repair the tank?
//A00G = Item Factory; A0CY = Headquarters; A0CW = Control Point; A0AV = Guard
if GetUnitAbilityLevel(U, 'A00G') >= 1 or GetUnitAbilityLevel(U, 'A0CY') >= 1 or GetUnitAbilityLevel(U, 'A0CW') >= 1 or GetUnitAbilityLevel(U, 'A0AV') >= 1 then
set U = null
return true
endif
set U = null
return false
endfunction
function Trig_AI_Fight_IsAlliedTank takes nothing returns boolean
local unit U = GetFilterUnit()
if not ( IsUnitAlly(U, GetPlayer(udg_AI_Number)) ) or GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
set U = null
return false
endif
if IsUnitType(U, UNIT_TYPE_HERO) and ( U != udg_AI_Tank ) and (GetUnitTypeId(U) != 'H013') then
set U = null
return true
endif
set U = null
return false
endfunction
function Trig_AI_Fight_Guard_Unroot takes integer range returns nothing
local boolean Unroot = false
// H013 = rooted Guard
if (GetUnitTypeId(udg_AI_Tank) == 'H013') then
call GroupEnumUnitsInRange(udg_TempGroup, GetUnitX(udg_AI_Tank),GetUnitY(udg_AI_Tank), range, Condition(function Trig_AI_Fight_IsAlliedTank))
set Unroot = FirstOfGroup(udg_TempGroup) == null
call GroupClear(udg_TempGroup)
//Only unroot when there are no units to be healed around
if ( Unroot ) then
call IssueImmediateOrder(udg_AI_Tank, "unrobogoblin")
endif
endif
endfunction
function Trig_AI_Fight_UseItem takes nothing returns nothing
local integer i = 0
local integer ID = 0
local item TempItem
//Check if the AI has a usable item
loop
exitwhen i > 5
set TempItem = UnitItemInSlot(udg_AI_Tank, i)
if TempItem != null then
set ID = GetItemTypeId(TempItem)
// Troop Command, Advanced Troop Command
if ID=='I00Y' or ID=='I053' then
set i = 6
else
set TempItem = null
endif
endif
set i = i + 1
endloop
if TempItem != null then
call UnitUseItem(udg_AI_Tank, TempItem)
set TempItem = null
endif
endfunction
function Trig_AI_Fight_Think_HighHP takes nothing returns nothing
local unit Target
local real MoveX
local real MoveY
local real TargetX
local real TargetY
local real MoveDist
local real Angle
local real TankX = GetUnitX(udg_AI_Tank)
local real TankY = GetUnitY(udg_AI_Tank)
local integer TeamNumber = udg_Player_Team[GetPlayerNr(GetOwningPlayer(udg_AI_Tank))]
local real HP = (GetUnitLifePercent(udg_AI_Tank)+1)/100
local string CurrentOrder = OrderId2String(GetUnitCurrentOrder(udg_AI_Tank))
local boolean IsUsingAbility = not ( CurrentOrder == "move" or CurrentOrder == "stop" or CurrentOrder == "smart" or CurrentOrder == null )
call Trig_AI_Fight_Guard_Unroot(700)
// Take over factories?
if udg_AI_Command[udg_AI_Number] == "conquer" then
call GroupEnumUnitsInRange(udg_TempGroup, TankX,TankY,500, Condition(function Trig_AI_Fight_IsUnprotectedEnemyCP))
if FirstOfGroup(udg_TempGroup) == null then
set udg_AI_Command[udg_AI_Number] = "attack"
else
call GroupClear(udg_TempGroup)
endif
else
set udg_AI_Command[udg_AI_Number] = "attack"
endif
if udg_AI_Command[udg_AI_Number] == "attack" and IsUsingAbility then
call GroupEnumUnitsInRange(udg_TempGroup, TankX,TankY,500, Condition(function Trig_AI_Fight_IsValidNearbyTarget))
//Check if the bot drives too deep into the enemies
if CountUnitsInGroup(udg_TempGroup) > R2I(GetUnitLifePercent(udg_AI_Tank)/25) then
set IsUsingAbility = false
set udg_AI_Command[udg_AI_Number] = "heal"
endif
call GroupClear( udg_TempGroup )
endif
if udg_AI_Command[udg_AI_Number] == "attack" and not IsUsingAbility then
call GroupEnumUnitsInRange(udg_TempGroup, TankX,TankY,1450, Condition(function Trig_AI_Fight_IsValidNearbyTarget))
if FirstOfGroup(udg_TempGroup) != null then
set Target = GetBestTarget( TankX, TankY, udg_TempGroup )
if Pow(GetUnitX(Target)-TankX,2)+Pow(GetUnitY(Target)-TankY,2)>1050*1050 then
call GroupEnumUnitsInRect(udg_TempGroup, udg_Playable_Map, Condition(function Trig_AI_Fight_IsAlliedCPTakenOver))
if FirstOfGroup(udg_TempGroup) != null then
set Target = Trig_AI_Fight_GetBestTargetFromBase( TankX, TankY, udg_TempGroup )
call GroupEnumUnitsInRange(udg_TempGroup, GetUnitX(Target), GetUnitY(Target), 1000.00, Condition(function Trig_AI_Fight_IsValidNearbyTarget))
set Target = Trig_AI_Fight_GetBestTargetFromBase( TankX, TankY, udg_TempGroup )
endif
endif
else
call GroupEnumUnitsInRect(udg_TempGroup, udg_Playable_Map, Condition(function Trig_AI_Fight_IsAlliedCPTakenOver))
if FirstOfGroup(udg_TempGroup) != null then
set Target = Trig_AI_Fight_GetBestTargetFromBase( TankX, TankY, udg_TempGroup )
call GroupEnumUnitsInRange(udg_TempGroup,GetUnitX(Target), GetUnitY(Target), 1000.00, Condition(function Trig_AI_Fight_IsValidNearbyTarget))
set Target = Trig_AI_Fight_GetBestTargetFromBase( TankX, TankY, udg_TempGroup )
else
call GroupEnumUnitsInRect(udg_TempGroup, udg_Playable_Map, Condition(function Trig_AI_Fight_IsValidMoveTarget))
set Target = Trig_AI_Fight_GetBestTargetFromBase( TankX, TankY, udg_TempGroup )
endif
endif
set TargetX = GetUnitX(Target)
set TargetY = GetUnitY(Target)
if not UseCPTeleporter(TargetX, TargetY, udg_AI_Tank) then
set Angle = Atan2(TankY - TargetY, TankX - TargetX)
//If distance between the target and the own base is less than between the target and the enemy base
if DistanceBetweenPoints(GetUnitLoc(Target), udg_Move_Points[TeamNumber+25]) > DistanceBetweenPoints(GetUnitLoc(Target), udg_Move_Points[(3+25 - TeamNumber)]) then
//If distance between the tank and the own base is less than between the tank and the enemy base
if DistanceBetweenPoints(GetUnitLoc(udg_AI_Tank), udg_Move_Points[TeamNumber+25]) < DistanceBetweenPoints(GetUnitLoc(udg_AI_Tank), udg_Move_Points[(3+25 - TeamNumber)]) - 200 then
if DistanceBetweenPoints(GetUnitLoc(udg_AI_Tank), udg_Move_Points[13]) < 2000 then
call IssuePointOrderLoc( udg_AI_Tank, "move", udg_Move_Points[13] )
elseif DistanceBetweenPoints(GetUnitLoc(udg_AI_Tank), udg_Move_Points[16]) < 2000 then
call IssuePointOrderLoc( udg_AI_Tank, "move", udg_Move_Points[16] )
endif
endif
endif
if GetUnitTypeId(Target) == 'h00P' then
set MoveX = TargetX + 200*Cos(Angle)
set MoveY = TargetY + 200*Sin(Angle)
set udg_AI_Command[udg_AI_Number] = "conquer"
else
call GroupEnumUnitsInRange(udg_TempGroup,TargetX, TargetY, 1000.00, Condition(function Trig_AI_Fight_IsAlliedCPTakenOver))
if FirstOfGroup(udg_TempGroup) != null then
set MoveX = GetUnitX( FirstOfGroup(udg_TempGroup) ) + 200*Cos(Angle)
set MoveY = GetUnitY( FirstOfGroup(udg_TempGroup) ) + 200*Sin(Angle)
else
set MoveDist = GetAverageRange(udg_AI_Tank, IsUnitType(Target, UNIT_TYPE_STRUCTURE)) - 100
set udg_AI_DangerLevel = 0
set udg_AI_SafetyLevel = 0
//this is used in GetGroupDanger_Enum - crappy style!
set bj_forLoopAIndexEnd = GetPlayerNr(GetOwningPlayer(udg_AI_Tank))
call GroupEnumUnitsInRange(udg_TempGroup,(TankX+TargetX)/2,(TankY+TargetY)/2,800, Condition(function Trig_AI_Fight_Anti_Leak_Condition))
call ForGroup(udg_TempGroup,function GetGroupDanger_Enum)
//call GroupEnumUnitsInRange(udg_TempGroup,TargetX, TargetY,800, Condition(function Trig_AI_Fight_Anti_Leak_Condition))
//call ForGroup(udg_TempGroup,function GetGroupDanger_Enum)
//call GroupClear(udg_TempGroup)
//call GroupEnumUnitsInRange(udg_TempGroup,TankX, TankY,800, Condition(function Trig_AI_Fight_Anti_Leak_Condition))
//call ForGroup(udg_TempGroup,function GetGroupDanger_Enum)
set MoveDist = MoveDist+RMaxBJ(RMinBJ(udg_AI_DangerLevel/HP*0.02 - udg_AI_SafetyLevel*HP*0.02, 1000),-250)
set Angle = Angle + GetRandomReal(-15.00, 15.00)*bj_DEGTORAD
set MoveX = TargetX + MoveDist*Cos(Angle)
set MoveY = TargetY + MoveDist*Sin(Angle)
if MoveDist > 700 then
call Trig_AI_Fight_UseItem()
endif
endif
endif
call IssuePointOrder( udg_AI_Tank, "move", MoveX, MoveY )
endif
call GroupClear(udg_TempGroup)
endif
set Target = null
endfunction
function Trig_AI_Fight_Think_LowHP_JumpCheck takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = GetHandleIndex(t)
if OrderId2String(GetUnitCurrentOrder(udg_AV_Unit1[i]))=="stop" then
call IssuePointOrderLoc( udg_AV_Unit1[i], "move", udg_AV_Loc1[i] )
endif
call ReleaseHandleIndex(i)
call ReleaseTimer(t)
endfunction
function Trig_AI_Fight_Think_LowHP takes nothing returns nothing
local group G = GetUnitsInRectMatchingSafe(udg_Playable_Map, Condition(function Trig_AI_Fight_IsAlliedHealingUnit))
local unit Target = GetBestTarget( GetUnitX(udg_AI_Tank),GetUnitY(udg_AI_Tank), G )
local real TargetX = GetUnitX(Target)
local real TargetY = GetUnitY(Target)
local real DistX = GetUnitX(udg_AI_Tank) - TargetX
local real DistY = GetUnitY(udg_AI_Tank) - TargetY
local real AngleRad
local timer t
local integer i = 0
local integer j
local item TempItem = null
call ReleaseGroup( G )
set udg_AI_Command[udg_AI_Number] = "heal"
if DistX*DistX+DistY*DistY < 160000 then // Dist < 400
call IssueImmediateOrder( udg_AI_Tank, "stop" )
else
set AngleRad = Atan2(GetUnitY(udg_AI_Tank) - TargetY, GetUnitX(udg_AI_Tank) - TargetX)
set TargetX = TargetX + 200 * Cos(AngleRad)
set TargetY = TargetY + 200 * Sin(AngleRad)
set udg_AI_Spell_Aborted = false
//Check if the AI has a Teleport-Item
loop
exitwhen i > 5
set TempItem = UnitItemInSlot(udg_AI_Tank, i)
if TempItem != null then
set j = GetItemTypeId(TempItem)
// Teleporter, Speed Pack, Ultimate Pack
if j=='I014' or j=='I012' or j=='I01J' then
set i = 6
else
set TempItem = null
endif
endif
set i = i + 1
endloop
if ( GetUnitAbilityLevel(udg_AI_Tank,'A02W')!=0 and IssuePointOrder(udg_AI_Tank, "blink", TargetX, TargetY) ) then
set t = NewTimer()
set i = NewTimerIndex(t)
set udg_AV_Unit1[i] = udg_AI_Tank
set udg_AV_Loc1[i] = Location(TargetX, TargetY)
call TimerStart(t, 0.10, false, function Trig_AI_Fight_Think_LowHP_JumpCheck )
else
if (TempItem != null) and (DistX*DistX+DistY*DistY > 1000000) then // Distance > 1000
call UnitUseItemPoint(udg_AI_Tank, TempItem, TargetX, TargetY)
endif
call Trig_AI_Fight_Guard_Unroot(500)
call IssuePointOrder( udg_AI_Tank, "move", TargetX, TargetY )
endif
endif
set Target = null
set G = null
set TempItem = null
endfunction
function Trig_AI_Fight_MustHeal takes nothing returns boolean
local boolean Heal = false
local real LifePercent = GetUnitState(udg_AI_Tank, UNIT_STATE_LIFE)/GetUnitState(udg_AI_Tank, UNIT_STATE_MAX_LIFE)
if udg_AI_Command[udg_AI_Number]=="heal" then
call GroupEnumUnitsInRange(udg_TempGroup, GetUnitX(udg_AI_Tank),GetUnitY(udg_AI_Tank), 2210.00 - LifePercent * 2210.00, Condition(function Trig_AI_Fight_IsAlliedHealingUnit))
set Heal = (FirstOfGroup(udg_TempGroup) != null) or (LifePercent < 0.475)
call GroupClear(udg_TempGroup)
elseif LifePercent < 0.475 then
set Heal = true
elseif LifePercent < 0.90 then
call GroupEnumUnitsInRange(udg_TempGroup, GetUnitX(udg_AI_Tank),GetUnitY(udg_AI_Tank), 2210.00 - LifePercent * 1800.00, Condition(function Trig_AI_Fight_IsAlliedHealingUnit))
set Heal = FirstOfGroup(udg_TempGroup) != null
call GroupClear(udg_TempGroup)
endif
return Heal
endfunction
function Trig_AI_Fight_Think takes nothing returns nothing
set udg_AI_Tank = udg_Tank[udg_AI_Number]
if udg_AI_Debug[5] then
if Trig_AI_Fight_MustHeal() then
call Trig_AI_Fight_Think_LowHP()
else
call Trig_AI_Fight_Think_HighHP()
endif
else
call Trig_AI_Fight_Think_HighHP()
endif
endfunction
function Trig_AI_Fight_IsAIReady takes integer CPID returns boolean
return udg_AI_IsBot[CPID] and (udg_AI_Command[CPID]=="attack" or udg_AI_Command[CPID]=="heal" or udg_AI_Command[CPID]=="conquer")
endfunction
function Trig_AI_Fight_Actions takes nothing returns nothing
local integer i = 1
local integer j
local integer Number
local real TankHP
local integer FinisherType
local string CurrentOrder
local integer MaxNo = GetMaxHumanPlayers()
// Set the next bot
if udg_AI_Number == GetMaxHumanPlayers() then
set Number = 1
else
set Number = udg_AI_Number + 1
endif
// Check all bots for their current HP
if udg_AI_Debug[5] then
loop
exitwhen i > MaxNo
if i != Number and Trig_AI_Fight_IsAIReady(i) and udg_AI_Command[i]!="heal" then
if GetUnitState(udg_Tank[i],UNIT_STATE_LIFE)/GetUnitState(udg_Tank[i],UNIT_STATE_MAX_LIFE) <= 0.475 then
set udg_AI_Number = i
set udg_AI_Tank = udg_Tank[i]
call Trig_AI_Fight_Think_LowHP()
endif
endif
set i = i + 1
endloop
endif
// The choosen AI receives its order
set udg_AI_Number = Number
if Trig_AI_Fight_IsAIReady(Number) then
call Trig_AI_Fight_Think()
endif
if udg_AI_Debug[2] then
//FinisherType just has to make sure, that the AI won't use both of it's finisher spells to kill an enemy
set FinisherType = udg_AI_Number-(udg_AI_Number/2)*2
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
set TankHP = GetUnitState(udg_Tank[i],UNIT_STATE_LIFE)
if TankHP > 0 and (TankHP < 600 or TankHP/GetUnitState(udg_Tank[i],UNIT_STATE_MAX_LIFE) < 0.3) then
set j = 1
loop
exitwhen j > MaxNo
if Trig_AI_Fight_IsAIReady(j) and GetAIDifficulty(GetPlayer(j))!=AI_DIFFICULTY_NEWBIE then
set CurrentOrder = OrderId2String(GetUnitCurrentOrder(udg_Tank[j]))
if IsUnitEnemy(udg_Tank[i],GetPlayer(j)) and ( CurrentOrder == "move" or CurrentOrder == "stop" or CurrentOrder == "smart" or CurrentOrder == null ) then
if IsUnitInvisible(udg_Tank[i], GetPlayer(j)) then
call Trig_AI_Fight_Think_UseSpell(udg_Tank[j],udg_Tank[i],FinisherType)
endif
endif
endif
set j = j + 1
endloop
endif
set i = i + 1
endloop
endif
endfunction
//===========================================================================
function InitTrig_AI_Fight takes nothing returns nothing
set gg_trg_AI_Fight = CreateTrigger( )
call TriggerAddAction( gg_trg_AI_Fight, function Trig_AI_Fight_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_AI_Weapons_Conditions takes nothing returns boolean
if not (IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) and udg_AI_IsBot[GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))]) then
return false
endif
return udg_AI_Command[GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))] != "pause"
endfunction
function Trig_AI_Weapons_Actions takes nothing returns nothing
local unit Tank = GetTriggerUnit()
local integer PlayerId = GetPlayerNr(GetOwningPlayer(Tank))
local integer PlayerTeam = udg_Player_Team[PlayerId]
if AIWantsWeapon(Tank) and not udg_Afk[PlayerId] then
if RectContainsUnit(gg_rct_Team_1_Respawn, Tank) or RectContainsUnit(gg_rct_Team_2_Respawn, Tank) then
call GameTimeWait( 1.00 )
if GetUnitState(Tank, UNIT_STATE_LIFE) <= 0 then
return
endif
endif
call GetBestWeapon(PlayerId)
if udg_AI_Command[PlayerId] == "shop1" then
if PlayerTeam == 1 then
call IssueTargetOrder( Tank, "smart", gg_unit_h00O_0021 )
else
call IssueTargetOrder( Tank, "smart", gg_unit_h00O_0070 )
endif
elseif udg_AI_Command[PlayerId] == "shop2" then
if PlayerTeam == 1 then
call IssueTargetOrder( Tank, "smart", gg_unit_h00N_0020 )
else
call IssueTargetOrder( Tank, "smart", gg_unit_h00N_0071 )
endif
elseif udg_AI_Command[PlayerId] == "shop3" then
if PlayerTeam == 1 then
call IssueTargetOrder( Tank, "smart", gg_unit_h00G_0005 )
else
call IssueTargetOrder( Tank, "smart", gg_unit_h00G_0061 )
endif
endif
if ( udg_AI_Command[PlayerId] == "shop4" ) then
if PlayerTeam == 1 then
call IssueTargetOrder( Tank, "smart", gg_unit_h005_0014 )
else
call IssueTargetOrder( Tank, "smart", gg_unit_h005_0054 )
endif
endif
endif
set Tank = null
endfunction
//===========================================================================
function InitTrig_AI_Weapons takes nothing returns nothing
set gg_trg_AI_Weapons = CreateTrigger( )
call TriggerAddCondition( gg_trg_AI_Weapons, Condition( function Trig_AI_Weapons_Conditions ) )
call TriggerAddAction( gg_trg_AI_Weapons, function Trig_AI_Weapons_Actions )
endfunction
//TESH.scrollpos=85
//TESH.alwaysfold=0
function Trig_AI_Respawn_Conditions takes nothing returns boolean
return udg_AI_IsBot[GetPlayerNr(GetOwningPlayer(GetTriggerUnit()))]
endfunction
function Trig_AI_Respawn_CheckItems takes item SlotItem returns boolean
local integer Item = GetItemTypeId(SlotItem)
// Power Pack Speed Boost Speed Boost(U) Speed Pack Strength Pack Teleporter
if (Item-'I011')*(Item-'I00V')*(Item-'I00W')*(Item-'I012')*(Item-'I052')*(Item-'I014')==0 then
return true
endif
//Adv Troop Command Troop Command Ultimate Pack
if (Item-'I053') * (Item-'I00Y') * (Item-'I01J')==0 then
return true
endif
// Hulls
if (Item-'I02H')*(Item-'I00R')*(Item-'I00Q')*(Item-'I04S')*(Item-'I04U')*(Item-'I04T')==0 then
return true
endif
if GetItemType(SlotItem) == ITEM_TYPE_ARTIFACT then
return true
endif
return false
endfunction
function Trig_AI_Respawn_KillTinkerTower takes nothing returns nothing
if IsTinkerTower( GetEnumUnit() ) then
call KillUnit( GetEnumUnit() )
endif
endfunction
function Trig_AI_Respawn_Actions takes nothing returns nothing
local unit tank = GetTriggerUnit()
local unit newTank
local player owner = GetOwningPlayer(tank)
local integer ownerId = GetPlayerNr(owner)
local integer i = 0
local item SlotItem
loop
exitwhen i > 5
set SlotItem = UnitItemInSlot(tank, i)
if Trig_AI_Respawn_CheckItems(SlotItem) then
call UnitUseItem( tank, SlotItem )
elseif not udg_Afk[ownerId] and SlotItem != null then
call SetPlayerState(owner,PLAYER_STATE_RESOURCE_GOLD,GetPlayerState(owner,PLAYER_STATE_RESOURCE_GOLD)+R2I(GetWidgetLife(SlotItem)))
call RemoveItem( SlotItem )
call DestroyEffect( AddSpecialEffectTarget( "origin", tank, "UI\\Feedback\\GoldCredit\\GoldCredit.mdl" ) )
endif
set i = i + 1
endloop
set SlotItem = null
call GameTimeWait(1)
if IsUnitAliveBJ(tank) then
set udg_AI_Command[ownerId] = "attack"
if not udg_Afk[ownerId] then
if AIWantsWeapon(tank) then
if udg_AI_Debug[3] then
call GetBestWeapon(ownerId)
if udg_AI_Command[ownerId] == "shop1" then
if ( udg_Player_Team[ownerId] == 1 ) then
call IssueTargetOrder( tank, "smart", gg_unit_h00O_0021 )
else
call IssueTargetOrder( tank, "smart", gg_unit_h00O_0070 )
endif
elseif udg_AI_Command[ownerId] == "shop2" then
if ( udg_Player_Team[ownerId] == 1 ) then
call IssueTargetOrder( tank, "smart", gg_unit_h00N_0020 )
else
call IssueTargetOrder( tank, "smart", gg_unit_h00N_0071 )
endif
elseif udg_AI_Command[ownerId] == "shop3" then
if ( udg_Player_Team[ownerId] == 1 ) then
call IssueTargetOrder( tank, "smart", gg_unit_h00G_0005 )
else
call IssueTargetOrder( tank, "smart", gg_unit_h00G_0061 )
endif
endif
if ( udg_AI_Command[ownerId] == "shop4" ) then
if ( udg_Player_Team[ownerId] == 1 ) then
call IssueTargetOrder( tank, "smart", gg_unit_h005_0014 )
else
call IssueTargetOrder( tank, "smart", gg_unit_h005_0054 )
endif
endif
endif
else
if udg_AI_Debug[4] then
call GetBestTank(ownerId)
if ( udg_AI_BuyID != 0 ) then
set newTank = CreateUnitAtLoc( owner, udg_AI_BuyID, udg_Move_Points[udg_Player_Team[ownerId]], 180*udg_Player_Team[ownerId]-135 )
call ChangeTanks(tank, newTank, null, false)
set udg_AI_Tank = newTank
call AdjustPlayerStateBJ( ( ( GetUnitPointValue(tank) / 2 ) - GetUnitPointValue(newTank) ), owner, PLAYER_STATE_RESOURCE_GOLD )
call ModifyHeroSkillPoints( udg_AI_Tank, bj_MODIFYMETHOD_SET, 0 )
set i = GetHeroLevel(udg_AI_Tank)
loop
exitwhen i < 1
call ModifyHeroSkillPoints( udg_AI_Tank, bj_MODIFYMETHOD_ADD, 1 )
call TriggerExecute( gg_trg_AI_Skills )
set i = i - 1
endloop
else
//Easy AI shouldn't buy any items
if GetAIDifficulty(GetPlayer(ownerId))!=AI_DIFFICULTY_NEWBIE then
call GetBestItem(ownerId)
if ( udg_AI_BuyID != 0 ) then
if ( udg_Player_Team[ownerId] == 1 ) then
call IssueTargetOrder( tank, "smart", gg_unit_h00A_0018 )
else
call IssueTargetOrder( tank, "smart", gg_unit_h00A_0072 )
endif
endif
endif
endif
endif
endif
endif
endif
set tank = null
set newTank = null
set owner = null
endfunction
//===========================================================================
function InitTrig_AI_Respawn takes nothing returns nothing
set gg_trg_AI_Respawn = CreateTrigger( )
call TriggerAddCondition( gg_trg_AI_Respawn, Condition( function Trig_AI_Respawn_Conditions ) )
call TriggerAddAction( gg_trg_AI_Respawn, function Trig_AI_Respawn_Actions )
endfunction
//TESH.scrollpos=54
//TESH.alwaysfold=0
globals
texttag array tmd_tags
boolean tmd_enabled = false
endglobals
function Trig_ThreatMap_Debug_Loop takes nothing returns nothing
local integer i = 0
local real minx = GetCameraTargetPositionX()-2*AI_THREAT_MAP_BLOCK_SIZE
local real miny = GetCameraTargetPositionY()-2*AI_THREAT_MAP_BLOCK_SIZE
local real maxx = minx+4.5*AI_THREAT_MAP_BLOCK_SIZE
local real maxy = miny+4.5*AI_THREAT_MAP_BLOCK_SIZE
local real stepsize = AI_THREAT_MAP_BLOCK_SIZE
local real x = minx
local real y
local real r
local location loc
set i=0
// Threat per position
loop
exitwhen x>maxx
set y = miny
loop
exitwhen y>maxy
if tmd_enabled then
if tmd_tags[i]==null then
set tmd_tags[i] = CreateTextTag()
call SetTextTagText(tmd_tags[i], "#", 0.04)
call SetTextTagPermanent( tmd_tags[i], true)
call SetTextTagVisibility(tmd_tags[i], true)
endif
call SetTextTagPos(tmd_tags[i], x, y, 100.0)
set r = ThreatMap.GetThreatDensity(x, y, 1)
call SetTextTagColor(tmd_tags[i],R2I(255*(0.5+r*0.5)),R2I(255*(0.5-r*0.5)),0,255)
elseif tmd_tags[i]!=null then
call SetTextTagPermanent( tmd_tags[i], false )
call SetTextTagLifespan( tmd_tags[i], 0.0 )
call DestroyTextTag( tmd_tags[i] )
set tmd_tags[i] = null
endif
set i = i +1
set y = y + stepsize
endloop
set x = x + stepsize
endloop
// Gradient at center
if tmd_enabled then
set x = GetCameraTargetPositionX()
set y = GetCameraTargetPositionY()
if tmd_tags[i]==null then
set tmd_tags[i] = CreateTextTag()
call SetTextTagText(tmd_tags[i], "#", 0.04)
call SetTextTagPermanent( tmd_tags[i], true)
call SetTextTagVisibility(tmd_tags[i], true)
endif
set loc = ThreatMap.GetThreatGradient(x, y, 1)
call SetTextTagPos(tmd_tags[i], x-GetLocationX(loc)*150.0, y-GetLocationY(loc)*150.0, 100.0)
call SetTextTagColor(tmd_tags[i],255,255,255,255)
call RemoveLocation(loc)
set loc = null
elseif tmd_tags[i]!=null then
call SetTextTagPermanent( tmd_tags[i], false )
call SetTextTagLifespan( tmd_tags[i], 0.0 )
call DestroyTextTag( tmd_tags[i] )
set tmd_tags[i] = null
endif
if not tmd_enabled then
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
endif
endfunction
function Trig_ThreatMap_Debug_Actions takes nothing returns nothing
set tmd_enabled = DebugMode and not tmd_enabled
if tmd_enabled then
call TimerStart(CreateTimer(), 0.01, true, function Trig_ThreatMap_Debug_Loop)
endif
endfunction
//===========================================================================
function InitTrig_ThreatMap_Debug takes nothing returns nothing
set gg_trg_ThreatMap_Debug = CreateTrigger( )
call TriggerRegisterChatCommandEvent(gg_trg_ThreatMap_Debug,"threatmap")
call TriggerAddAction( gg_trg_ThreatMap_Debug, function Trig_ThreatMap_Debug_Actions )
endfunction
//TESH.scrollpos=18
//TESH.alwaysfold=0
function Trig_AI_Debug_Info_Conditions takes nothing returns boolean
return DebugMode
endfunction
function Trig_AI_Debug_Info_GetTag takes integer i returns texttag
if udg_AI_Debug_Info[i]!=null then
return udg_AI_Debug_Info[i]
endif
set udg_AI_Debug_Info[i] = CreateTextTag()
call SetTextTagText(udg_AI_Debug_Info[i], "", 0.023)
call SetTextTagPos(udg_AI_Debug_Info[i], 1, 1, 50)
call SetTextTagVisibility(udg_AI_Debug_Info[i], false)
call SetTextTagPermanent(udg_AI_Debug_Info[i], true )
return udg_AI_Debug_Info[i]
endfunction
function Trig_AI_Debug_Info_Actions takes nothing returns nothing
local integer i = 1
local real PosX
local real PosY
local string s = ""
local string array threatMood
set threatMood[1] = ":-P"
set threatMood[2] = ":-)"
set threatMood[3] = ":-/"
set threatMood[4] = ":-("
set threatMood[5] = ":-O"
loop
exitwhen i > 10
if (udg_AI_IsNewBot[i]) and (GetUnitState(udg_Tank[i], UNIT_STATE_LIFE) > 0) then
call Trig_AI_Debug_Info_GetTag(i)
call SetTextTagVisibility(udg_AI_Debug_Info[i], true)
set PosX = GetUnitX(udg_Tank[i])
set PosY = GetUnitY(udg_Tank[i])
call SetTextTagPos(udg_AI_Debug_Info[i], PosX, PosY, 200)
//set s = AI[i].SecOrder
//set s = "Nr: " + I2S(AI[i].AINr) + "|nPO: " + AI[i].PrimOrder + "|nTarget: " + GetUnitName(AI[i].Target) + "|nShop: " + AI[i].ShopOrder + "|nTL: " + R2S(AI[i].DangerLevel - (AI[i].SafetyLevel * AI[i].CurrentLife/100)) + ": " + I2S(AI[i].CalculateThreatLevel())
//set s = "Nr: " + I2S(AI[i].AINr) + "|nCS: " + R2S(AI[i].CurrentStrength) + "|nDL: " + R2S(AI[i].DangerLevel) + "|nSL: " + R2S(AI[i].SafetyLevel) + "|nLevel: " + I2S(AI[i].CalculateThreatLevel())
set s = AIOrder2String(AI[i].Behaviour.Order)
set s = s+ "|nTarget: "+GetName(AI[i].Behaviour.Target)
set s = s + "|nThreat: "+I2S(R2I(AI[i].ThreatRaw*0.01))+"00"
set s = s + "|n" + threatMood[AI[i].ThreatLevel] // R2S(AI[i].DangerLevel - (AI[i].SafetyLevel * AI[i].CurrentLife/100)) + ": " +
call SetTextTagText(udg_AI_Debug_Info[i], s, 0.023)
else
call SetTextTagVisibility(udg_AI_Debug_Info[i], false)
endif
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_AI_Debug_Info takes nothing returns nothing
set gg_trg_AI_Debug_Info = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_AI_Debug_Info, 0.05 )
call TriggerAddAction( gg_trg_AI_Debug_Info, function Trig_AI_Debug_Info_Actions )
call TriggerAddCondition( gg_trg_AI_Debug_Info, Condition( function Trig_AI_Debug_Info_Conditions ) )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AIInterface requires BTFramework
globals
boolean AIstarted = false
constant integer NO_AI = 0
constant integer OLD_AI = 1
constant integer NEW_AI = 2
endglobals
function IsAI takes integer pid returns boolean
return udg_AI_IsBot[pid] or udg_AI_IsNewBot[pid]
endfunction
// Not yet ready to use, but should make it much easier to work with the AI
function RegisterAI takes integer pid, integer level returns nothing
local integer i = 1
local boolean ai = false
if level==OLD_AI or level==NEW_AI then
if level == OLD_AI then
set udg_AI_IsBot[pid] = true
set udg_AI_IsNewBot[pid] = false
else
set udg_AI_IsBot[pid] = false
if not udg_AI_IsNewBot[pid] then
call AICore.create(pid)
call TriggerExecute( gg_trg_AI_Init )
endif
set udg_AI_IsNewBot[pid] = true
endif
if not udg_AI_Initialized then
set udg_AI_Initialized = true
call TriggerExecute( gg_trg_AI_InitTrig )
call TriggerRegisterTimerEvent( gg_trg_AI_Fight, 0.10, true )
endif
if GetUnitTypeId(udg_Tank[pid]) == 'H01H' and AIstarted then
call TriggerExecute( gg_trg_AI_Start )
endif
set udg_AI_Command[pid]="attack"
else
set udg_AI_IsBot[pid] = false
set udg_AI_IsNewBot[pid] = false
//if ( udg_AI_IsBot[nr] == true ) then
// if ( not CheckForAI() ) then
// call DisableTrigger( gg_trg_AI_Fight )
// call DisableTrigger( gg_trg_AI_Level )
// call DisableTrigger( gg_trg_AI_Weapons )
// call DisableTrigger( gg_trg_AI_Weapons_1 )
// call DisableTrigger( gg_trg_AI_Weapons_2 )
// call DisableTrigger( gg_trg_AI_Weapons_3 )
// call DisableTrigger( gg_trg_AI_Respawn )
// call DisableTrigger( gg_trg_AI_Die )
// endif
//endif
endif
loop
exitwhen i > GetMaxHumanPlayers()
if udg_AI_IsNewBot[i] then
set ai = true
endif
set i = i + 1
endloop
set ThreatMap.Enabled = ai
endfunction
function BeginAI takes nothing returns nothing
// Remove this function, let the AI decide on the fly whether the game is already
// running, by checking whether the tank is paused, otherwise just skip
local integer i = 0
set AIstarted = true
loop
exitwhen i>GetMaxHumanPlayers()
if udg_AI_IsBot[i] and udg_PlayerIn[i] then
call TriggerExecute( gg_trg_AI_Start )
return
endif
set i = i + 1
endloop
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AIFunctions requires MapAttachedSettings, PvJass, TankChangeLibrary, AICombatRange
globals
Index PrimIndex
Index SecIndex
endglobals
struct Index
private integer index
integer maxIndex
integer minIndex
static method Create takes integer min, integer max, integer start returns Index
local Index i = Index.allocate()
set i.minIndex = min
set i.maxIndex = max
set i.index = start
return i
endmethod
method Inc takes nothing returns integer
if (this.index == this.maxIndex) then
set this.index = this.minIndex
else
set this.index = this.index + 1
endif
return this.index
endmethod
method Dec takes nothing returns integer
if (this.index == this.minIndex) then
set this.index = this.maxIndex
else
set this.index = this.index - 1
endif
return this.index
endmethod
endstruct
function AIOrder2String takes integer order returns string
if order==AI_ORDER_HEAL then
return "heal"
elseif order==AI_ORDER_ATTACK then
return "attack"
elseif order==AI_ORDER_MOVE_ATTACK then
return "moveattack"
elseif order==AI_ORDER_MOVE then
return "move"
endif
return "unknown"
endfunction
function GetTerritoryProgression takes real x, real y returns real
// Returns -1 for dark force and 1 for light force,
// this function is used to prevent the AI from moving past an enemy
// Map center is (0.0,-512.0)
local real baseOffset = 7168.0
local real dx = x
local real dy = y+512.0
if dx+dy>0 then
// Light force side
return 1.0-SquareRoot( (dx-baseOffset)*(dx-baseOffset) + (dy-baseOffset)*(dy-baseOffset) )/(baseOffset*2.0)
endif
// dark force side
return SquareRoot( (dx+baseOffset)*(dx+baseOffset) + (dy+baseOffset)*(dy+baseOffset) )/(baseOffset*2.0)-1.0
endfunction
function GetLane takes real x, real y returns integer
// Map center is (0.0,-512.0)
// We will create lines from the bases to
// (centerX-laneSeperator,centerY+laneSeperator) for top lane
// and (centerX+laneSeperator,centerY-laneSeperator) for bottom lane.
// Then we can check, on which side of the line a tank is and find its lane.
// The baseOffset sets where the bases are, e.g. (centerX-baseOffset,centerY-baseOffset) for the dark force.
// Lines will be created through these points.
local real laneSeperator = 2560.0
local real baseOffset = 6656.0
local integer lane = AI_LANE_MID
// Check for top lane
// Create line from tank to laneSeperator:
local real dx = -laneSeperator-x
local real dy = laneSeperator-y-512.0
// Create line from base one to laneSeperator, check direction:
if dy*(-laneSeperator+baseOffset)-dx*(laneSeperator+baseOffset)<0.0 then
// We are on the left side of the line, which means:
return AI_LANE_TOP
// Create line from laneSeperator to base two, check direction:
elseif dy*(baseOffset+laneSeperator)-dx*(baseOffset-laneSeperator)<0.0 then
// We are on the left side of the line, which means:
return AI_LANE_TOP
endif
// Check for bottom lane
// Create line from tank to laneSeperator:
set dx = laneSeperator-x
set dy = -laneSeperator-y-512.0
// Create line from base one to laneSeperator, check direction:
if dy*(laneSeperator+baseOffset)-dx*(-laneSeperator+baseOffset)>0.0 then
// We are on the right side of the line, which means:
return AI_LANE_BOTTOM
// Create line from laneSeperator to base two, check direction:
elseif dy*(baseOffset-laneSeperator)-dx*(baseOffset+laneSeperator)>0.0 then
// We are on the right side of the line, which means:
return AI_LANE_BOTTOM
endif
// No side lane, so it has to be mid.
return AI_LANE_MID
endfunction
function ShowPlayerGold takes nothing returns nothing
local integer gold1
local integer gold2
local integer creeps = 0
local integer tps = 0
local integer array total
local integer i = 1
loop
exitwhen i > GetMaxHumanPlayers()
if udg_PlayerIn[i] then
set gold1 = GetBounty(udg_Tank[i], false)
set gold2 = GetPlayerState(GetPlayer(i), PLAYER_STATE_RESOURCE_GOLD)
set total[i] = gold1 + gold2
//call DebugMsg(udg_Color[i] + "Pl" + I2S(i) + "|r total: " + I2S(gold1 + gold2) + " un: " + I2S(gold2))
endif
set i = i + 1
endloop
set i = 1
set gold1 = 0
loop
exitwhen i > 5
set gold1 = gold1 + total[i]
set creeps = creeps + udg_Stats_CreepKills[i]
set tps = tps + CPTeles[i]
set i = i + 1
endloop
call DebugMsg("|cFF106246Gold:|r " + I2S(gold1) + " (~" + I2S(R2I(gold1/udg_Team_CountPlayers[1])) + ")")
call DebugMsg("|cFF106246Creeps:|r " + I2S(creeps) + " (~" + I2S(R2I(creeps/udg_Team_CountPlayers[1])) + ")")
call DebugMsg("|cFF106246TPs:|r " + I2S(tps) + " (~" + I2S(R2I(tps*AI_CPTP_COSTS/udg_Team_CountPlayers[1])) + " lost)")
set gold1 = 0
set creeps = 0
set tps = 0
loop
exitwhen i > 10
set gold1 = gold1 + total[i]
set creeps = creeps + udg_Stats_CreepKills[i]
set tps = tps + CPTeles[i]
set i = i + 1
endloop
call DebugMsg("|cFF4E2A04Gold:|r " + I2S(gold1) + " (~" + I2S(R2I(gold1/udg_Team_CountPlayers[2])) + ")")
call DebugMsg("|cFF4E2A04Creeps:|r " + I2S(creeps) + " (~" + I2S(R2I(creeps/udg_Team_CountPlayers[2])) + ")")
call DebugMsg("|cFF4E2A04TPs:|r " + I2S(tps) + " (~" + I2S(R2I(tps*AI_CPTP_COSTS/udg_Team_CountPlayers[2])) + " lost)")
endfunction
function LearnSkill takes unit tank, integer abilId returns nothing
// Learns one skill to the highest level possible
local integer skillPoints = GetHeroSkillPoints(tank)
local integer lastSkillPoints = skillPoints+1
loop
exitwhen skillPoints==lastSkillPoints
set lastSkillPoints=skillPoints
call SelectHeroSkill( tank, abilId )
set skillPoints = GetHeroSkillPoints(tank)
endloop
endfunction
function LearnSkills takes unit tank returns nothing
call LearnSkill( tank, 'A01J' ) // Tank Cannon (normal)
if ( GetUnitTypeId(tank) == 'H01L' ) then // --- Scout ---
call LearnSkill( tank, 'A09O' ) // Ensnare
call LearnSkill( tank, 'A06M' ) // Creep Cannon
call LearnSkill( tank, 'A035' ) // Defensive Systems
call LearnSkill( tank, 'A09X' ) // Watch Tower
call LearnSkill( tank, 'A030' ) // Rune Carving
endif
if ( GetUnitTypeId(tank) == 'H009' ) then // --- Light Tank ---
call LearnSkill( tank, 'A06V' ) // Multi Rocket Shot
call LearnSkill( tank, 'A02T' ) // Triple Rocket Shot
call LearnSkill( tank, 'A04M' ) // Cluster Shot
call LearnSkill( tank, 'A0BM' ) // Repair
endif
if ( GetUnitTypeId(tank) == 'H008' ) then // --- Helicopter ---
call LearnSkill( tank, 'A01B' ) // Fire Bomb
call LearnSkill( tank, 'A02T' ) // Triple Rocket Shot
call LearnSkill( tank, 'A031' ) // Jet Propulsion
call LearnSkill( tank, 'A001' ) // Bombardement
endif
if ( GetUnitTypeId(tank) == 'H00X' ) then // --- Anti-Grav ---
if ( GetUnitAbilityLevel(tank, 'A02W') < 2 ) then
call LearnSkill( tank, 'A02W' ) // Learn at least two level of Jump
endif
call LearnSkill( tank, 'A07G' ) // Dimension Shift
call LearnSkill( tank, 'A07E' ) // EMP Torpedos
call LearnSkill( tank, 'A055' ) // Plasma Cluster
call LearnSkill( tank, 'A02W' ) // Jump
endif
if ( GetUnitTypeId(tank) == 'H017' ) then // --- Medivac ---
call LearnSkill( tank, 'A0BL' ) // Support Systems
call LearnSkill( tank, 'A0BA' ) // Super Thrust
call LearnSkill( tank, 'A07D' ) // Decoy
call LearnSkill( tank, 'A0B8' ) // Life Converter
endif
if ( GetUnitTypeId(tank) == 'H02J' ) then // --- Distributor ---
call LearnSkill( tank, 'A0FW' ) // S.I.C.
call LearnSkill( tank, 'A0FU' ) // Heat-Seeking Missiles
call LearnSkill( tank, 'A0FT' ) // Tankers Little Helper
call LearnSkill( tank, 'A0FS' ) // Reactive Armor
endif
if ( GetUnitTypeId(tank) == 'H027' ) then // --- Raider ---
call LearnSkill( tank, 'A06S' ) // Hit&Run
call LearnSkill( tank, 'A0CB' ) // Static Charge
call LearnSkill( tank, 'A0FA' ) // Shape Memory Alloy
call LearnSkill( tank, 'A0BN' ) // Ricochet
endif
if ( GetUnitTypeId(tank) == 'H007' ) then // --- Demolisher ---
call LearnSkill( tank, 'A02F' ) // Burning Oil
call LearnSkill( tank, 'A02R' ) // Jet Wave
call LearnSkill( tank, 'A0B5' ) // Artillery Shot
call LearnSkill( tank, 'A04U' ) // Mines
endif
if ( GetUnitTypeId(tank) == 'H011' ) then // --- Goblin Shredder ---
call LearnSkill( tank, 'A04N' ) // Unit Teleport
call LearnSkill( tank, 'A03D' ) // Metal Stars
call LearnSkill( tank, 'A0D7' ) // Goblin Synergy
call LearnSkill( tank, 'A052' ) // Magnetic Pull
endif
if ( GetUnitTypeId(tank) == 'H00C' ) then // --- Air Ship ---
call LearnSkill( tank, 'A02Z' ) // Plasma Rain
call LearnSkill( tank, 'A023' ) // Electro Shocker
call LearnSkill( tank, 'A0GI' ) // Jet Propulsion
call LearnSkill( tank, 'A06W' ) // Healing Drones
endif
if ( GetUnitTypeId(tank) == 'H025' ) then // --- Storm Tank ---
call LearnSkill( tank, 'A0EF' ) // Eye of the Storm
call LearnSkill( tank, 'A0F7' ) // Air Cannon
call LearnSkill( tank, 'A0F8' ) // Storm Shock
call LearnSkill( tank, 'A0E4' ) // Energy Leash
call LearnSkill( tank, 'A0E8' ) // Air Mines
endif
if ( GetUnitTypeId(tank) == 'H00B' ) then // --- Thunder Tank ---
call LearnSkill( tank, 'A029' ) // Chain Lightning
call LearnSkill( tank, 'A02N' ) // Lightning Strike
call LearnSkill( tank, 'A034' ) // Electro Aura
call LearnSkill( tank, 'A04B' ) // Thunder Storm
endif
if ( GetUnitTypeId(tank) == 'H00R' ) then // --- Ghost Tank ---
call LearnSkill( tank, 'A093' ) // Soul Restore
call LearnSkill( tank, 'A03A' ) // Summoning of the Dead
call LearnSkill( tank, 'A06L' ) // Soul Collector
call LearnSkill( tank, 'A06X' ) // Soul Transfer
endif
if ( GetUnitTypeId(tank) == 'H012' ) then // --- Guard ---
call LearnSkill( tank, 'A041' ) // Entangling Roots
call LearnSkill( tank, 'A03Y' ) // Roots
call LearnSkill( tank, 'A04Q' ) // Summon Treants
call LearnSkill( tank, 'A0AM' ) // Natural Energy
endif
if ( GetUnitTypeId(tank) == 'H00D' ) then // --- Heavy Tank ---
call LearnSkill( tank, 'A0B6' ) // Hail of Bombs
call LearnSkill( tank, 'A024' ) // Aiming Rocket
call LearnSkill( tank, 'A06R' ) // Heavy Armor
call LearnSkill( tank, 'A00Z' ) // Mortar Teams
endif
if ( GetUnitTypeId(tank) == 'H021' ) then // --- Architect ---
call LearnSkill( tank, 'A0DJ' ) // Pacifista
call LearnSkill( tank, 'A0DN' ) // Splash Cannon
call LearnSkill( tank, 'A0DC' ) // Freezing Missile
call LearnSkill( tank, 'A0D8' ) // Cannon Module
call LearnSkill( tank, 'A0DD' ) // Portal
endif
if ( GetUnitTypeId(tank) == 'H00I' ) then // --- Goblin Tanks ---
call LearnSkill( tank, 'A026' ) // Shockwave
call LearnSkill( tank, 'A03Z' ) // Goblin Riot
call LearnSkill( tank, 'A08I' ) // Goblin Turbo
call LearnSkill( tank, 'A01O' ) // Thunder Hammer
endif
if ( GetUnitTypeId(tank) == 'H02K' ) then // --- Darkness Tank ---
call LearnSkill( tank, 'A0G1' ) // Darkness Sphere
call LearnSkill( tank, 'A0GB' ) // Missile Battery
call LearnSkill( tank, 'A0G3' ) // Orb of Darkness
call LearnSkill( tank, 'A0G5' ) // Energy Leak
call LearnSkill( tank, 'A0BI' ) // Conservation
endif
if ( GetUnitTypeId(tank) == 'H01U' ) then // --- Earth Robot ---
call LearnSkill( tank, 'A09R' ) // Earthquake
call LearnSkill( tank, 'A09Q' ) // Dustwave
call LearnSkill( tank, 'A091' ) // Transparent Armor
call LearnSkill( tank, 'A09S' ) // Granitic Defense
endif
if ( GetUnitTypeId(tank) == 'H00E' ) then // --- Sky Tank ---
call LearnSkill( tank, 'A049' ) // Energy Bomb
call LearnSkill( tank, 'A01P' ) // Flame Strike
call LearnSkill( tank, 'A09Z' ) // Lord of the Sky
call LearnSkill( tank, 'A0C0' ) // Lightning Strike
endif
if ( GetUnitTypeId(tank) == 'H01S' ) then // --- Hunter ---
call LearnSkill( tank, 'A094' ) // Gravity Grenade
call LearnSkill( tank, 'A08Z' ) // Hero Sniper
call LearnSkill( tank, 'A0AH' ) // Bounty Hunter
call LearnSkill( tank, 'A0AG' ) // Main Gun
call LearnSkill( tank, 'A0A0' ) // Acid Cloud
endif
if ( GetUnitTypeId(tank) == 'H00F' ) then // --- Demon Tank ---
call LearnSkill( tank, 'A02H' ) // Hell Implosion
call LearnSkill( tank, 'A01D' ) // Lava-Shot
call LearnSkill( tank, 'A04G' ) // Demon Fire
call LearnSkill( tank, 'A0B3' ) // Banish
endif
if ( GetUnitTypeId(tank) == 'H00H' ) then // --- Frost Robot ---
call LearnSkill( tank, 'A04R' ) // Ice Rain
call LearnSkill( tank, 'A0E0' ) // Ice Prison
call LearnSkill( tank, 'A03B' ) // Frost Bombs
call LearnSkill( tank, 'S000' ) // Arctic Aura
endif
if ( GetUnitTypeId(tank) == 'H01V' ) then // --- Goliath ---
call LearnSkill( tank, 'A04P' ) // Devastator Shot
call LearnSkill( tank, 'A02L' ) // Heavy Tank Cannon
call LearnSkill( tank, 'A02V' ) // Offroad Engine
call LearnSkill( tank, 'A0BO' ) // Mobile Shields
call LearnSkill( tank, 'A0E1' ) // Take Aim
endif
if ( GetUnitTypeId(tank) == 'H01R' ) then // --- Sky Fortress ---
call LearnSkill( tank, 'A09E' ) // System Overload
call LearnSkill( tank, 'A09C' ) // Turbo Boost
call LearnSkill( tank, 'A09J' ) // Fortified Armor
call LearnSkill( tank, 'A09U' ) // Bomb Carpet
endif
if ( GetUnitTypeId(tank) == 'H00K' ) then // --- Infernal Robot ---
call LearnSkill( tank, 'A08Y' ) // Infernal Fire Rain
call LearnSkill( tank, 'A04L' ) // Chaos Teleport
call LearnSkill( tank, 'A03E' ) // Chaos Wave
call LearnSkill( tank, 'A02C' ) // Chaos Servants
endif
if ( GetUnitTypeId(tank) == 'H01I' ) then // --- Titan ---
call LearnSkill( tank, 'A0CI' ) // Keep on Fighting
call LearnSkill( tank, 'A0C7' ) // Orbital Strike
call LearnSkill( tank, 'A08V' ) // Devil Fire
call LearnSkill( tank, 'A08J' ) // Unstable Projectiles
call LearnSkill( tank, 'A0C6' ) // Build Obelisk
endif
endfunction
function CoordsInBase2 takes real X, real Y, unit Tank returns boolean
if udg_Player_Team[GetPlayerNr(GetOwningPlayer(Tank))] == 1 then
return RectContainsCoords(gg_rct_Team_1_Base_Main, X, Y)
endif
return RectContainsCoords(gg_rct_Team_2_Base_Main, X, Y)
endfunction
function IsValidCPTeleporterTarget2 takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_TOWNHALL)==true and IsUnitAlly(GetFilterUnit(), GetPlayer(udg_TempInt)) and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0
endfunction
globals
real udg_AIGetNearestTeleport_X = 0.0
real udg_AIGetNearestTeleport_Y = 0.0
real udg_AIGetNearestTeleport_Dist=0.0
endglobals
// Sets the globals to the return values, please copy those values right after receiving them
function AIGetNearestTeleport takes integer Id, real X, real Y returns nothing
local real dx
local real dy
local real d
local integer i
local integer iMax
local unit cp = null
local unit U
local real minDist
local group G
local location loc
//The distance from the Bot to the nearest CP
set udg_AIGetNearestTeleport_Dist = Get_CP_Teleport_Msg_DistToBase( X, Y, udg_Player_Team[Id])
if udg_AIGetNearestTeleport_Dist>0.0 then
// Extract healers from threatmap, this is much faster than looping over the whole map.
set i = ThreatMap.Healers_Begin[udg_Player_Team[Id]]
set iMax = ThreatMap.Healers_End[udg_Player_Team[Id]]
loop
exitwhen i>iMax
set U = ThreatMap.Units[i]
set dx = X-GetUnitX(U)
set dy = Y-GetUnitY(U)
set d = dx*dx+dy*dy
if (IsUnitType(U, UNIT_TYPE_TOWNHALL)==true) and (cp==null or d<minDist) then
set cp = U
set minDist = d
endif
set i = i + 1
endloop
if cp != null then
set dx = X-GetUnitX(cp)
set dy = Y-GetUnitY(cp)
set d = SquareRoot(minDist)
if d-AI_CP_RANGE<udg_AIGetNearestTeleport_Dist then
if d-AI_CP_RANGE>0.0 then
set udg_AIGetNearestTeleport_Dist = d-AI_CP_RANGE
set udg_AIGetNearestTeleport_X = GetUnitX(cp)+dx*(AI_CP_RANGE-AI_CP_SAFETY_TOLERANCE_DIST)/d
set udg_AIGetNearestTeleport_Y = GetUnitY(cp)+dy*(AI_CP_RANGE-AI_CP_SAFETY_TOLERANCE_DIST)/d
else
set udg_AIGetNearestTeleport_Dist = 0.0
set udg_AIGetNearestTeleport_X = X
set udg_AIGetNearestTeleport_Y = Y
endif
else
set cp = null
endif
endif
endif
if cp==null then
set loc = Location(X,Y)
call Get_CP_Teleport_Msg_MoveLocInBase(loc, udg_Player_Team[Id],-AI_CP_SAFETY_TOLERANCE_DIST)
set udg_AIGetNearestTeleport_X = GetLocationX(loc)
set udg_AIGetNearestTeleport_Y = GetLocationY(loc)
call RemoveLocation(loc)
set loc = null
endif
set cp=null
endfunction
function AIUseCPTP takes integer Id, location TargetLoc, boolean beFast returns location
// Checks whether it is useful to teleport, then either returns the location
// of the cp to teleport from, or automatically teleport and return null.
// If teleporting isn't useful, a copy of TargetLoc is returned.
local unit Tank = AI[Id].Tank
local real TankX = GetUnitX(Tank)
local real TankY = GetUnitY(Tank)
local real TargetX = GetLocationX(TargetLoc)
local real TargetY = GetLocationY(TargetLoc)
local real moveSpeed = GetUnitMoveSpeed(Tank)
local real CPStartX
local real CPStartY
local real CPEndX
local real CPEndY
local real StartDistance
local real EndDistance
local real DirectDistance
local real cpTimeLoss
if GetPlayerState( GetOwningPlayer(Tank), PLAYER_STATE_RESOURCE_GOLD ) < AI_CPTP_COSTS then
// No Teleport, just move to the target location
return Location(TargetX, TargetY)
endif
set DirectDistance = SquareRoot((TankX-TargetX)*(TankX-TargetX)+(TankY-TargetY)*(TankY-TargetY))
// Distance from tank to nearest CP
// Function sets global variables as return
call AIGetNearestTeleport( Id, TankX, TankY )
set CPStartX = udg_AIGetNearestTeleport_X
set CPStartY = udg_AIGetNearestTeleport_Y
set StartDistance = udg_AIGetNearestTeleport_Dist
if StartDistance>=DirectDistance then
// Even the own cp is further away than the target
return Location(TargetX, TargetY)
endif
// Distance from target to nearest CP
// Function sets global variables as return
call AIGetNearestTeleport( Id, TargetX, TargetY )
set CPEndX = udg_AIGetNearestTeleport_X
set CPEndY = udg_AIGetNearestTeleport_Y
set EndDistance = udg_AIGetNearestTeleport_Dist
if StartDistance+EndDistance>=DirectDistance then
// Even not considering the cptp duration, the total way is longer
return Location(TargetX, TargetY)
endif
// Ground tanks have to move around obstacles,
// so they effectively have a lower moveSpeed
if IsUnitType(Tank, UNIT_TYPE_FLYING)==false then
set moveSpeed = 0.8*moveSpeed
endif
// Set constant time the cp teleport takes
if beFast then
set cpTimeLoss = 3.0
else
// If it is not only about speed, the price is also important
// That is why we need the time it takes to earn that money
// Assuming 10.0 gold per second:
set cpTimeLoss = 3.0+AI_CPTP_COSTS*0.1
endif
// Check which option is better
// TODO: Also check hp, because while porting some hp will be healed
if StartDistance + EndDistance + cpTimeLoss*moveSpeed < DirectDistance then
// Teleport if near a CP or order Bot to drive near a CP
// Orders return true, if they were ordered successfully (no cooldown, mana problem whatever)
if StartDistance <= 0.0 then
// TODO: Check whether the target CP is currently under heavy attack,
// if it is, then wait for other players or teleport very late to give other players the change to help,
// while not losing the CP.
if IssuePointOrder( Tank, "spies", CPEndX, CPEndY ) then
return null
endif
return Location( CPStartX, CPStartY )
else
return Location( CPStartX, CPStartY )
endif
endif
// No Teleport, just move to the target location
return Location(TargetX, TargetY)
endfunction
endlibrary
//TESH.scrollpos=105
//TESH.alwaysfold=0
library AIGroupConditions requires MapAttachedSettings, AIFunctions
function IsAlliedHealingUnit2 takes nothing returns boolean
local unit U = GetFilterUnit()
if not ( IsUnitAlly(U, GetPlayer(ActiveAI)) ) or (GetUnitState(U, UNIT_STATE_LIFE) <= 0) or ( U == AI[ActiveAI].Tank ) then
set U = null
return false
endif
// Does the target repair the tank?
//A00G = Item Factory; A0CY = Headquarters; A0CW = Control Point; A0AV = Guard; 'A0CV' = Base Factory
if GetUnitAbilityLevel(U, 'A00G') >= 1 or GetUnitAbilityLevel(U, 'A0CV') >= 1 or GetUnitAbilityLevel(U, 'A0CY') >= 1 or GetUnitAbilityLevel(U, 'A0CW') >= 1 or GetUnitAbilityLevel(U, 'A0AV') >= 1 then
set U = null
return true
endif
set U = null
return false
endfunction
function IsAlliedTank2 takes nothing returns boolean
local unit U = GetFilterUnit()
if not ( IsUnitAlly(U, GetPlayer(ActiveAI)) ) or GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
set U = null
return false
endif
if IsUnitType(U, UNIT_TYPE_HERO) and ( U != AI[ActiveAI].Tank ) and (GetUnitTypeId(U) != 'H013') then
set U = null
return true
endif
set U = null
return false
endfunction
function IsStrongEnemy2 takes nothing returns boolean
local unit U = GetFilterUnit()
if ( IsUnitAlly(U, GetPlayer(ActiveAI)) ) or GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
set U = null
return false
endif
//h000 = Rocket Tower, h001 = Laser Tower
if IsUnitType(U, UNIT_TYPE_HERO) or GetUnitTypeId(U) == 'h000' or GetUnitTypeId(U) == 'h001' then
set U = null
return true
endif
set U = null
return false
endfunction
function IsProtected2 takes unit U returns boolean
local group NearUnits = NewGroup()
local boolean Ret
call GroupEnumUnitsInRange(NearUnits, GetUnitX(U), GetUnitY(U), 2000.00, Condition(function IsStrongEnemy2))
set Ret = (FirstOfGroup(NearUnits) != null)
call ReleaseGroup( NearUnits )
set NearUnits = null
return Ret
endfunction
function IsAlliedCPInDanger2 takes nothing returns boolean
local unit U = GetFilterUnit()
if IsUnitAlly(U, GetPlayer(ActiveAI)) then
if GetUnitTypeId(U) == 'h00P' then
if IsProtected2(U) then
set U = null
return true
endif
endif
endif
set U = null
return false
endfunction
function IsUnprotectedEnemyCP2 takes nothing returns boolean
local unit U = GetFilterUnit()
if GetUnitTypeId(U) == 'h00P' and IsUnitEnemy( U, GetPlayer(ActiveAI) ) then
if not IsProtected2(U) then
set U = null
return true
endif
endif
set U = null
return false
endfunction
function GetBestTargetFromBaseOnLane takes group G, real NearX, real NearY, integer lane returns unit
local unit PickUnit = FirstOfGroup( G )
local unit Target = null
local real PickUnitDist
local real TargetDist = 0
local real BaseX = GetUnitX(udg_HQ[udg_Player_Team[ActiveAI]])
local real BaseY = GetUnitY(udg_HQ[udg_Player_Team[ActiveAI]])
local real dx
local real dy
local real ux
local real uy
loop
exitwhen PickUnit == null
set ux = GetUnitX(PickUnit)
set uy = GetUnitY(PickUnit)
if lane==AI_LANE_UNKNOWN or lane==GetLane(ux,uy) then
set dx = ux - NearX
set dy = uy - NearY
set PickUnitDist = dx * dx + dy * dy
set dx = ux - BaseX
set dy = uy - BaseY
set PickUnitDist = PickUnitDist * (dx+dy)*(dx+dy)
if (PickUnitDist < TargetDist or TargetDist == 0) and (IsUnitVisible(PickUnit, GetPlayer(ActiveAI))) then
set Target = PickUnit
set TargetDist = PickUnitDist
endif
endif
call GroupRemoveUnit( G, PickUnit )
set PickUnit = FirstOfGroup( G )
endloop
set PickUnit = null
return Target
endfunction
function IsValidNearbyTarget2 takes nothing returns boolean
local unit U = GetFilterUnit()
if (not IsUnitEnemy(U, GetPlayer(ActiveAI))) or GetUnitState(U, UNIT_STATE_LIFE) <= 0 then
set U = null
return false
endif
if IsUnprotectedEnemyCP2() then
set U = null
return true
endif
// Is Invulnerable or Invisible?
if (GetUnitState(U, UNIT_STATE_LIFE) >= 500000) or (IsUnitInvisible(U, GetPlayer(ActiveAI)) ) then
set U = null
return false
endif
set U = null
return true
endfunction
endlibrary
//TESH.scrollpos=453
//TESH.alwaysfold=0
library AIThreatMap initializer Init requires MapAttachedSettings
// This library periodically loops over all units on the map and creates
// a threat map which can be used to improve the AI commands.
// It also stores all healers and cps per team in arrays, so the
// AI can look for nearby healers faster.
globals
// The finest possible resolution is AI_THREAT_MAP_BLOCK_SIZE = Sqrt(MapSizeX*MapSizeY/2048) = 317.0
// A greate block size means a lower resolution, a threatmap which is not that precise, but
// increases performance for lookups and blurs the map, so that sometimes a greater block size might even be better
constant real AI_THREAT_MAP_BLOCK_SIZE = 512.00
// The position of the second buffer, normally 4096.
// This is used, so that one buffer can be recalculated, while the old one is still active,
// however, it is not yet implemented. By spreading out the calculations, there won't be one
// lagging frame per second. Currently not implemented though.
constant integer AI_THREAT_MAP_BUFFER_SWITCH = 4096
// Time in seconds to refresh the threat map
constant real AI_THREAT_MAP_REFRESH_RATE = 1.0
boolexpr FILTER_REFRESH_THREAT_MAP
endglobals
function Threat takes real allyRating, real enemyRating returns real
// This function is used to to change the definition of threat.
// The current output is:
// * 1.0 - only enemies
// *-1.0 - only allies
if enemyRating+allyRating>0.0 then
return (enemyRating-allyRating)/(enemyRating+allyRating)
endif
return 0.0
endfunction
function GetUnitThreatRating takes unit U returns real
local real CurHP = GetUnitState(U, UNIT_STATE_LIFE)
local real MaxHP = GetUnitState(U, UNIT_STATE_MAX_LIFE)
local real r
// Either dead or invulnerable
if CurHP <= 0.45 or ((CurHP >= 500000) and (GetUnitTypeId(U)!='h00P')) then
return 0.0
endif
if IsUnitType(U, UNIT_TYPE_HERO)==true then
// Use Tank Costs to determine strength
set r = (0.25 + (0.75 * CurHP / MaxHP)) * udg_TankCosts[GetPlayerNr(GetOwningPlayer(U))]
else
// Use MaxHP to determine strength
set r = (0.25 + (0.75 * CurHP / MaxHP)) * MaxHP
if IsUnitType(U, UNIT_TYPE_STRUCTURE)==true then
set r = r*0.5
endif
if r>10000.0 then
set r = 10000.0
endif
endif
return r
endfunction
struct ThreatGroup
// Used as a return struct
real array rating [3]
real array centerX [3]
real array centerY [3]
static method create takes nothing returns ThreatGroup
local ThreatGroup ret = ThreatGroup.allocate()
set ret.rating[1] = 0.0
set ret.rating[2] = 0.0
set ret.centerX[1]= 0.0
set ret.centerY[1]= 0.0
set ret.centerX[2]= 0.0
set ret.centerY[2]= 0.0
return ret
endmethod
static method merge takes ThreatGroup tg1, ThreatGroup tg2 returns ThreatGroup
// Merges two ThreatGroups into ones. Note that the source groups are not destroyed.
local ThreatGroup ret = ThreatGroup.allocate()
set ret.rating[1] = tg1.rating[1]+tg2.rating[1]
set ret.rating[2] = tg1.rating[2]+tg2.rating[2]
if ret.rating[1]!=0.0 then
set ret.centerX[1]= (tg1.centerX[1]*tg1.rating[1]+tg2.centerX[1]*tg2.rating[1])/ret.rating[1]
set ret.centerY[1]= (tg1.centerY[1]*tg1.rating[1]+tg2.centerY[1]*tg2.rating[1])/ret.rating[1]
else
set ret.centerX[1]= (tg1.centerX[1]+tg2.centerX[1])*0.5
set ret.centerY[1]= (tg1.centerY[1]+tg2.centerY[1])*0.5
endif
if ret.rating[2]!=0.0 then
set ret.centerX[2]= (tg1.centerX[2]*tg1.rating[2]+tg2.centerX[2]*tg2.rating[2])/ret.rating[2]
set ret.centerY[2]= (tg1.centerY[2]*tg1.rating[2]+tg2.centerY[2]*tg2.rating[2])/ret.rating[2]
else
set ret.centerX[2]= (tg1.centerX[2]+tg2.centerX[2])*0.5
set ret.centerY[2]= (tg1.centerY[2]+tg2.centerY[2])*0.5
endif
return ret
endmethod
method AddUnitScaled takes unit U, real scalar, real x, real y returns nothing
// Adds the unit scaled to the ThreatGroup (also, if it's already in).
local integer team = udg_Player_Team[GetPlayerNr(GetOwningPlayer(U))]
local real oldRating
local real unitRating
if team==0 then
return
endif
set unitRating= GetUnitThreatRating( U )*scalar
set oldRating = rating[team]
set rating[team] = rating[team] + unitRating
if rating[team]<=0.0 then
set rating[team]=0.0
else
set centerX[team]= (centerX[team]*oldRating+x*unitRating)/rating[team]
set centerY[team]= (centerY[team]*oldRating+y*unitRating)/rating[team]
endif
endmethod
method AddUnit takes unit U, real x, real y returns nothing
// Adds the unit to the ThreatGroup (also, if it's already in).
call AddUnitScaled(U, 1.0, x, y)
endmethod
method RemoveUnit takes unit U, real x, real y returns nothing
// Removes the unit to the ThreatGroup (also, if it's not in).
call AddUnitScaled(U,-1.0, x, y)
endmethod
method GetAllyCenterX takes integer team returns real
return centerX[team]
endmethod
method GetAllyCenterY takes integer team returns real
return centerY[team]
endmethod
method GetEnemyCenterX takes integer team returns real
return centerX[3-team]
endmethod
method GetEnemyCenterY takes integer team returns real
return centerY[3-team]
endmethod
method GetAllyRating takes integer team returns real
return rating[team]
endmethod
method GetEnemyRating takes integer team returns real
return rating[3-team]
endmethod
method GetThreat takes integer team returns real
return Threat(rating[team],rating[3-team])
endmethod
endstruct
struct ThreatMap
// As calculating the threat map is quite costly,
// you can set ThreatMap.Enabled = false if it is not required.
static boolean Enabled = true
// The actual data map
static real array Rating
// If we are already looping through all units, we may also find
// healers and factories for the AI
static unit array Units
// Here are the counters for these
// Units[Healers_Begin[1]....Healers_End[1]]
// contains all healers for team one for example.
static integer array Healers_Begin
static integer array Healers_End
static integer array CPs_Begin
static integer array CPs_End
// The map boundaries
static real MinX
static real MinY
static real MaxX
static real MaxY
// The number of corners saved in each dimension
static integer PointsX_N
static integer PointsY_N
static integer Blocks_N
// The enumeration team
static integer Team
private static method IsHealer takes unit U returns boolean
// Does the target repair tanks?
//A00G = Item Factory; A0CY = Headquarters; A0CW = Control Point; A0AV = Guard; 'A0CV' = Base Factory
return GetUnitTypeId(U)=='h00P' or GetUnitAbilityLevel(U, 'A00G') >= 1 or GetUnitAbilityLevel(U, 'A0CV') >= 1 or GetUnitAbilityLevel(U, 'A0CY') >= 1 or GetUnitAbilityLevel(U, 'A0CW') >= 1 or GetUnitAbilityLevel(U, 'A0AV') >= 1
endmethod
private static method IsCP takes unit U returns boolean
return GetUnitTypeId(U)=='h00P'
endmethod
private static method GetIndex takes real X, real Y, integer team returns integer
return ThreatMap.PointsY_N*R2I((X-ThreatMap.MinX)/AI_THREAT_MAP_BLOCK_SIZE)+R2I((Y-ThreatMap.MinY)/AI_THREAT_MAP_BLOCK_SIZE)+(team-1)*ThreatMap.Blocks_N
endmethod
static method GetTeamDensity takes real X, real Y, integer team returns real
// A very fast lookup for the threat density at a certain position,
// this means, scale the threat to receive the threat for another area.
// The output value gives the result for a AI_THREAT_MAP_BLOCK_SIZE*AI_THREAT_MAP_BLOCK_SIZE area.
// Get unit coordinates in translated coordinate system with (0,0) at the map corner
// Scaled so that x=1.0 means the border of the first block, x=2.0 2nd block etc.
local real x = (X-ThreatMap.MinX)/AI_THREAT_MAP_BLOCK_SIZE
local real y = (Y-ThreatMap.MinY)/AI_THREAT_MAP_BLOCK_SIZE
local integer ix = R2I(x)
local integer iy = R2I(y)
local integer ioff
local real ret
if x<0.0 or y<0.0 or x>ThreatMap.PointsX_N or y>ThreatMap.PointsX_N then
return 0.0
endif
set ioff = ThreatMap.PointsY_N*ix+iy+(team-1)*ThreatMap.Blocks_N
set x = x-I2R(ix)
set y = y-I2R(iy)
// Read rating from the corners and interpolate
// Bottom left:
set ret = ThreatMap.Rating[ioff]*(1.0-x)*(1.0-y)
// Top left:
set ret = ret + ThreatMap.Rating[ioff+1]*(1.0-x)*y
// Bottom right:
set ret = ret + ThreatMap.Rating[ioff+ThreatMap.PointsY_N]*x*(1.0-y)
// Top right:
set ret = ret + ThreatMap.Rating[ioff+ThreatMap.PointsY_N+1]*x*y
// In fact, this should be divided by
// (AI_THREAT_MAP_BLOCK_SIZE*AI_THREAT_MAP_BLOCK_SIZE) to give a real "density" value,
// however, that number seems too big and kills the data.
return ret
endmethod
static method GetThreatDensity takes real X, real Y, integer team returns real
return Threat(GetTeamDensity(X,Y,team),GetTeamDensity(X,Y,3-team))
endmethod
static method GetThreatGradient takes real X, real Y, integer team returns location
// Returns the threat gradient at a given location.
// For example, if the threat is higher on the right side, the x-coordinate of the return value will be postive.
// If this turns out to be useful, this could probably be implemented in a faster way
local real gradientX = GetThreatDensity(X+AI_THREAT_MAP_BLOCK_SIZE,Y,team)-GetThreatDensity(X-AI_THREAT_MAP_BLOCK_SIZE,Y,team)
local real gradientY = GetThreatDensity(X,Y+AI_THREAT_MAP_BLOCK_SIZE,team)-GetThreatDensity(X,Y-AI_THREAT_MAP_BLOCK_SIZE,team)
return Location(gradientX,gradientY)
endmethod
static method GetThreatGroupLine takes real X1, real Y1, real X2, real Y2, real Range returns ThreatGroup
local integer ixMin = R2I((RMinBJ(X1, X2)-Range-ThreatMap.MinX)/AI_THREAT_MAP_BLOCK_SIZE)
local integer ixMax = R2I((RMaxBJ(X1, X2)+Range-ThreatMap.MinX)/AI_THREAT_MAP_BLOCK_SIZE)+1
local integer iyMin = R2I((RMinBJ(Y1, Y2)-Range-ThreatMap.MinY)/AI_THREAT_MAP_BLOCK_SIZE)
local integer iyMax = R2I((RMaxBJ(Y1, Y2)+Range-ThreatMap.MinY)/AI_THREAT_MAP_BLOCK_SIZE)+1
local integer ix
local integer iy
local real dX
local real dY
local real rating
local real totalArea=0.0
local ThreatGroup ret = ThreatGroup.create()
// The ranges at which we can consider the corner completely inside (weight 1.0) or completely outside (weight 0.0)
local real rangeOutsideSq = (Range+AI_THREAT_MAP_BLOCK_SIZE*0.5)*(Range+AI_THREAT_MAP_BLOCK_SIZE*0.5)
local real rangeInsideSq = 0.0
local boolean foundInThisLine = false
local real dirX = X2-X1
local real dirY = Y2-Y1
local real r = dirX*dirX + dirY*dirY
local real dist = 0.0
if r>0 then
set dist = SquareRoot( r )
set dirX = dirX/dist
set dirY = dirY/dist
else
set dirX = 1.0
set dirY = 0.0
endif
// Bounds checking
if ixMin<0 then
set ixMin = 0
endif
if ixMax>ThreatMap.PointsX_N-1 then
set ixMax = ThreatMap.PointsX_N-1
endif
if iyMin<0 then
set iyMin = 0
endif
if iyMax>ThreatMap.PointsY_N-1 then
set iyMax = ThreatMap.PointsY_N-1
endif
if Range-AI_THREAT_MAP_BLOCK_SIZE*0.5>0.0 then
set rangeInsideSq = (Range-AI_THREAT_MAP_BLOCK_SIZE*0.5)*(Range-AI_THREAT_MAP_BLOCK_SIZE*0.5)
endif
set ix = ixMin
loop
exitwhen ix>ixMax
set foundInThisLine = false
set iy = iyMin
loop
exitwhen iy>iyMax
// The distance from the current corner to the line
set dX = ix*AI_THREAT_MAP_BLOCK_SIZE+ThreatMap.MinX-X1
set dY = iy*AI_THREAT_MAP_BLOCK_SIZE+ThreatMap.MinY-Y2
// Project vector parallel to the line
set r = dX*dirX + dY*dirY
if r > 0 then
if r > dist then
set r = r - dist
else
set r = 0
endif
endif
// Project vector perpendicular to the line and add it to the dist square
set r = r*r + (dY*dirX - dX*dirY)*(dY*dirX - dX*dirY)
// Smooth fadeout
set r = (rangeOutsideSq-r)/(rangeOutsideSq-rangeInsideSq)
if r>0.0 then
if r>1.0 then
set r=1.0
endif
// team 1
set rating = r*ThreatMap.Rating[ThreatMap.PointsY_N*ix+iy]
set ret.rating[1] = ret.rating[1] + rating
set ret.centerX[1]= ret.centerX[1]+ rating*dX
set ret.centerY[1]= ret.centerY[1]+ rating*dY
// team 2
set rating = r*ThreatMap.Rating[ThreatMap.PointsY_N*ix+iy+ThreatMap.Blocks_N]
set ret.rating[2] = ret.rating[2] + rating
set ret.centerX[2]= ret.centerX[2]+ rating*dX
set ret.centerY[2]= ret.centerY[2]+ rating*dY
set totalArea = totalArea + r*AI_THREAT_MAP_BLOCK_SIZE*AI_THREAT_MAP_BLOCK_SIZE
set foundInThisLine = true
else
// If the area is outside the circle, but there already were some areas inside,
// then there won't be any area coming. Circle is intersected already
exitwhen foundInThisLine
endif
set iy = iy + 1
endloop
set ix = ix +1
endloop
// The following requires something to be found. Should actually always be true,
// but just be safe to not divide by zero
if totalArea>0.0 then
// Center is now scaled by rating and relative to X and Y, fix that:
if ret.rating[1]>0.0 then
set ret.centerX[1] = X1+ret.centerX[1]/ret.rating[1]
set ret.centerY[1] = Y1+ret.centerY[1]/ret.rating[1]
else
set ret.centerX[1] = (X1+X2)*0.5
set ret.centerY[1] = (Y1+Y2)*0.5
endif
if ret.rating[2]>0.0 then
set ret.centerX[2] = X1+ret.centerX[2]/ret.rating[2]
set ret.centerY[2] = Y1+ret.centerY[2]/ret.rating[2]
else
set ret.centerX[2] = (X1+X2)*0.5
set ret.centerY[2] = (Y1+Y2)*0.5
endif
// Maybe the total summed up area wasn't just right, because the corners are not weighted perfectly,
// in that case, scale the whole rating to return the true threat/area
set r = Range * ( Range*bj_PI + dist ) / totalArea
set ret.rating[1] = ret.rating[1] * r
set ret.rating[2] = ret.rating[2] * r
endif
return ret
endmethod
static method GetThreatGroupCircle takes real X, real Y, real Range returns ThreatGroup
return GetThreatGroupLine( X, Y, X, Y, Range )
endmethod
static method Refresh_Enum takes nothing returns boolean
local unit U = GetFilterUnit()
local real r = GetUnitThreatRating( U )
local real x
local real y
local integer ix
local integer iy
local integer ioff
if r>0.0 then
// Get unit coordinates in translated coordinate system with (0,0) at the map corner
// Scaled so that x=1.0 means the border of the first block, x=2.0 2nd block etc.
set x = (GetUnitX(U)-ThreatMap.MinX)/AI_THREAT_MAP_BLOCK_SIZE
set y = (GetUnitY(U)-ThreatMap.MinY)/AI_THREAT_MAP_BLOCK_SIZE
// Get the indices for min ix and min iy, that is the lower left corner of the block
set ix= R2I(x)
set iy= R2I(y)
// Get the relative coordinates to the lower left corner of the block
// with 0.0 = left border, 1.0 = right border
set x= x-ix
set y= y-iy
// Get the rating index of the bottom left corner, considering the team:
set ioff = ThreatMap.PointsY_N*ix+iy+(ThreatMap.Team-1)*ThreatMap.Blocks_N
// Add unit rating to the corners, weight the rating between the four nearby corners
// Bottom left:
set ThreatMap.Rating[ioff] = ThreatMap.Rating[ioff] + r*(1.0-x)*(1.0-y)
// Top left:
set ThreatMap.Rating[ioff+1] = ThreatMap.Rating[ioff+1] + r*(1.0-x)*y
// Bottom right:
set ThreatMap.Rating[ioff+ThreatMap.PointsY_N] = ThreatMap.Rating[ioff+ThreatMap.PointsY_N] + r*x*(1.0-y)
// Top right:
set ThreatMap.Rating[ioff+ThreatMap.PointsY_N+1] = ThreatMap.Rating[ioff+ThreatMap.PointsY_N+1] + r*x*y
// If we are already looping through all units, we may also find
// healers and factories for the AI
if ThreatMap.IsHealer( U ) then
set ThreatMap.Healers_End[ThreatMap.Team] = ThreatMap.Healers_End[ThreatMap.Team] + 1
set ThreatMap.Units[ThreatMap.Healers_End[ThreatMap.Team]] = U
if ThreatMap.IsCP( U ) then
set ThreatMap.CPs_End[ThreatMap.Team] = ThreatMap.CPs_End[ThreatMap.Team] + 1
set ThreatMap.Units[ThreatMap.CPs_End[ThreatMap.Team]] = U
endif
endif
endif
set U = null
return false
endmethod
static method Refresh takes nothing returns nothing
local group g
local integer i
local integer team
if not ThreatMap.Enabled then
return
endif
set g = NewGroup()
set ThreatMap.MinX = GetRectMinX(udg_Playable_Map)
set ThreatMap.MinY = GetRectMinY(udg_Playable_Map)
set ThreatMap.MaxX = GetRectMaxX(udg_Playable_Map)
set ThreatMap.MaxY = GetRectMaxY(udg_Playable_Map)
set ThreatMap.PointsX_N = R2I((ThreatMap.MaxX-ThreatMap.MinX)/AI_THREAT_MAP_BLOCK_SIZE)+1
set ThreatMap.PointsY_N = R2I((ThreatMap.MaxY-ThreatMap.MinY)/AI_THREAT_MAP_BLOCK_SIZE)+1
set ThreatMap.Blocks_N = ThreatMap.PointsX_N*ThreatMap.PointsY_N
// Reset threat map
set i = 0
loop
exitwhen i>=2*ThreatMap.Blocks_N
set ThreatMap.Rating[i] = 0
set i = i + 1
endloop
set ThreatMap.Healers_Begin[1] = 0
set ThreatMap.Healers_End[1] = -1
set ThreatMap.Healers_Begin[2] = 100
set ThreatMap.Healers_End[2] = 100-1
set ThreatMap.CPs_Begin[1] = 200
set ThreatMap.CPs_End[1] = 200-1
set ThreatMap.CPs_Begin[2] = 210
set ThreatMap.CPs_End[2] = 210-1
// Write new threat map
set i = 1
loop
exitwhen i>GetMaxPlayers()
set ThreatMap.Team = udg_Player_Team[i]
call GroupEnumUnitsOfPlayer( g, GetPlayer(i), FILTER_REFRESH_THREAT_MAP )
set i = i + 1
endloop
call ReleaseGroup(g)
set g = null
// For both teams, enumerate the healers and multiply the nearby threat
set team=1
loop
exitwhen team>2
set i = ThreatMap.Healers_Begin[team]
loop
exitwhen i>ThreatMap.Healers_End[team]
// ThreatMap.Units[i]
// TODO: Multiply threat
set i = i + 1
endloop
set team = team + 1
endloop
endmethod
endstruct
private function Init takes nothing returns nothing
// Even if the ThreatMap is not used, set these variables, so no script
// tries to access some contents and causes serious errors.
set ThreatMap.Healers_Begin[1] = 0
set ThreatMap.Healers_End[1] = -1
set ThreatMap.Healers_Begin[2] = 100
set ThreatMap.Healers_End[2] = 100-1
set ThreatMap.CPs_Begin[1] = 200
set ThreatMap.CPs_End[1] = 200-1
set ThreatMap.CPs_Begin[2] = 210
set ThreatMap.CPs_End[2] = 210-1
set FILTER_REFRESH_THREAT_MAP = Filter( function ThreatMap.Refresh_Enum )
call TimerStart(CreateTimer(),AI_THREAT_MAP_REFRESH_RATE, true, function ThreatMap.Refresh )
endfunction
endlibrary
//TESH.scrollpos=99
//TESH.alwaysfold=0
library AIWeaponRanges requires AIGeneralFunctions
// This struct stores the weapon ranges and dps of each tank (not only AI),
// it can then be used to find the perfect combat range.
// Weapon ranges are stored from lowest to highest
struct WeaponRanges
// Weapon ranges to look up, arrays are 0-based
static WeaponRanges array PlayerRanges
unit Tank
real array Ranges [10]
real array Dps [10]
integer N
method Clear takes nothing returns nothing
set this.N = 0
endmethod
method AddWeapon takes real range, real dps returns nothing
// Save this weapon into the struct,
// the weapons are sorted descending by range
local integer j = 0
local integer k
loop
exitwhen j>=this.N or range>=this.Ranges[j]
set j = j + 1
endloop
if j<this.N and range==this.Ranges[j] then
// Merge weapons
set this.Dps[j] = this.Dps[j] + dps
else
// Insert between
// Move all weapons behind and including [j] one index higher,
// so [j] is free.
// No weapon is moved, if the weapon is inserted at the end
// (i.e. highest range)
set k = this.N
loop
exitwhen k<=j
set this.Ranges[k] = this.Ranges[k-1]
set this.Dps[k] = this.Dps[k-1]
set k=k-1
endloop
// New highest range, insert behind
set this.Ranges[k] = range
set this.Dps[k] = dps
set this.N = this.N + 1
endif
endmethod
method ScaleDps takes real r returns nothing
// Scales the dps of all weapons by factor r
local integer i = 0
loop
exitwhen i>=this.N
set this.Dps[i] = this.Dps[i]*r
set i = i + 1
endloop
endmethod
method Add takes WeaponRanges wr returns nothing
// Add a complete weaponstruct
local integer i = 0
loop
exitwhen i>=wr.N
call this.AddWeapon( wr.Ranges[i], wr.Dps[i] )
set i = i + 1
endloop
endmethod
method Refresh takes unit U returns nothing
local integer i = 0
local item ItemInSlot
local real checkRange
local real dps = 0
set this.Tank = U
// Clear all weapons from this struct
call this.Clear( )
// Add tank cannon skills
// Tank cannon
set i = GetUnitAbilityLevel(U, 'A01J')
if i>0 then
call this.AddWeapon( 900.0, 60.0*i )
endif
// Creep sniper, dps reduced so the AI does not rely on this that much, as it's only-creep
set i = GetUnitAbilityLevel(U, 'A06M')
if i>0 then
call this.AddWeapon( 1050.0, 90.0*i )
endif
// Hero sniper
set i = GetUnitAbilityLevel(U, 'A08Z')
if i>0 then
call this.AddWeapon( 1300.0, 41.0*i )
endif
// Air Cannon
set i = GetUnitAbilityLevel(U, 'A0EA')
if i>0 then
call this.AddWeapon( 1050.0, 64.0*i )
endif
// Add items
loop
exitwhen i > 5
set ItemInSlot = UnitItemInSlot(U, i)
// Get the weapon range
set checkRange = I2R(GetWeaponRange(GetItemTypeId(ItemInSlot)))
// Only check this item, if it is a weapon
if checkRange>0 then
// Add weapon to struct
// This is the basic weapons formula without any bonus
set dps = (66.667*GetWidgetLife(ItemInSlot)/checkRange) * GetWeaponDamageModifier(GetItemTypeId(ItemInSlot))
call this.AddWeapon( checkRange, dps )
endif
set i = i + 1
endloop
call ModifyHeroStat( bj_HEROSTAT_AGI, U, bj_MODIFYMETHOD_SET, IMaxBJ(R2I(GetDPS(1)), 1) )
set ItemInSlot = null
endmethod
static method Create takes unit U returns WeaponRanges
local integer i = 0
local integer j
local item ItemInSlot
local WeaponRanges ws = WeaponRanges.allocate()
set ws.N = 0
call ws.Refresh( U )
return ws
endmethod
method Copy takes nothing returns WeaponRanges
local WeaponRanges ws = WeaponRanges.allocate()
local integer i = 0
set ws.N = this.N
set ws.Tank = this.Tank
loop
exitwhen i>=this.N
set ws.Dps[i] = this.Dps[i]
set ws.Ranges[i] = this.Ranges[i]
set i = i + 1
endloop
return ws
endmethod
method GetDPS takes real atRange returns real
// Returns the dps that the weapons deal all together
local integer i = 0
local real ret=0.0
loop
exitwhen i>=this.N or this.Ranges[i]<atRange
set ret = ret + this.Dps[i]
set i=i+1
endloop
return ret
endmethod
method GetKillTime takes real atRange, real targHP returns real
// Returns the duration it takes to kill the target at the given range
return targHP/this.GetDPS(atRange)
endmethod
method GetDamageTakenToKill takes WeaponRanges targRanges, real targHP, real atRange returns real
// dmgTaken(t) = targDps*t
// targHP(t)= targHP - srcDps*t
// Looking for targHP(t) = 0 gives:
return targHP*targRanges.GetDPS(atRange)/this.GetDPS(atRange)
endmethod
method GetBestRange takes WeaponRanges targRanges, real sourceHP, real targHP, boolean ecoMode returns real
// See above, that the damage taken to kill a target does not depend on the dps difference,
// but in most cases the enemy can escape easily, if we don't deal enough damage, so:
// if ecoMode is on, we rate by dps quotient
// if ecoMode is off, we rate by dps difference
// Besides, we scale the dps by the source and target HP, so that we get a "hp percentage per second"
local integer i
local integer i1=0
local integer i2=0
local real dps1=0.0
local real dps2=0.0
local real curdps1=0.0
local real curdps2=0.0
local real curVal
local real curRange
local real bestVal=0.0
local real bestRange=-AI_RANGE_PRECISION
// Start with highest range, then add weapon by weapon and check the ratio
loop
exitwhen i1>=this.N and i2>=targRanges.N
// Adjust curRange to the highest range not yet added to dps
set curRange = this.Ranges[i1]
if targRanges.Ranges[i2]>curRange then
set curRange = targRanges.Ranges[i2]
endif
// If the next weapons can fire within that range, add the dps
loop
exitwhen this.Ranges[i1]<curRange
set dps1 = dps1 + this.Dps[i1]
set i1 = i1 + 1
endloop
loop
exitwhen targRanges.Ranges[i2]<curRange
set dps2 = dps2 + targRanges.Dps[i2]
set i2 = i2 + 1
endloop
// Theoretically, we have compared the dps now, but practically the AI
// is unable to hold the distance in such a small span, so
// we need to consider weapons with a slightly smaller range, too.
// However, do not "remove" this weapons from the list, but temporarly add up the new dps:
// Note, that these loops look like a performance killer, but actually they will be looped through
// very rarely.
set curdps1 = dps1
set curdps2 = dps2
set i = i1
loop
exitwhen this.Ranges[i]<curRange-AI_RANGE_PRECISION
set curdps1 = curdps1 + this.Dps[i]
set i = i + 1
endloop
set i = i2
loop
exitwhen targRanges.Ranges[i]<curRange-AI_RANGE_PRECISION
set curdps2 = curdps2 + targRanges.Dps[i]
set i = i + 1
endloop
// Compare dps
if ecoMode then
// Ratio should be as big as possible,
// we could return right here, if dps2==0.0, but if the source
// has more weapons with about that range, these would be better
set curVal = (curdps1+0.01)/(curdps2+0.01)
else
// Difference should be as big as possible
// Actually: curdps1/targHP-curdps2/sourceHP,
// but scaling gives no problems, so:
set curVal = curdps1*sourceHP-curdps2*targHP
endif
if bestRange<=-AI_RANGE_PRECISION or curVal>bestVal then
set bestVal = curVal
set bestRange = curRange-AI_RANGE_PRECISION*0.5
endif
endloop
if bestRange<0.0 then
return 0.0
endif
//call DebugMsg("My range: "+R2S(this.Ranges[0])+", target: "+R2S(targRanges.Ranges[0])+", i choose: "+R2S(bestRange))
return bestRange
endmethod
static method Get takes integer playerId returns WeaponRanges
// playerId is 1-based
if PlayerRanges[playerId]==0 then
set PlayerRanges[playerId]=WeaponRanges.Create(udg_Tank[playerId])
endif
return PlayerRanges[playerId]
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AICombatRange requires AIGeneralFunctions
globals
// Variables to cache the combat range,
// Level and Costs are used to check for changes,
// Range and RangeBuilding store the results
integer array udg_GetAICombatRange_Level
real array udg_GetAICombatRange_Costs
real array udg_GetAICombatRange_Range
real array udg_GetAICombatRange_RangeBuilding
endglobals
// Do not call this function, it is just used to refresh the combat range
function GetAICombatRange_Core takes unit U, boolean wantAttackBuilding returns real
// Weapons list
local integer weaponsN = 0
local real array weaponsRange
local real array weaponsCost // in 1000
// Other variables
local real checkRange
local real totalValue
local real bestRange
local real totalValueMax = 0
local integer i
local integer j
local integer abilLvl
local item ItemInSlot
// Tank cannon
set abilLvl = GetUnitAbilityLevel(U, 'A01J')
if abilLvl>0 then
set weaponsCost[weaponsN] = 0.8 * I2R(abilLvl)
set weaponsRange[weaponsN] = 900
set weaponsN = weaponsN + 1
endif
// Creep sniper
set abilLvl = GetUnitAbilityLevel(U, 'A06M')
if abilLvl>0 then //and not wantAttackBuilding then
set weaponsCost[weaponsN] = 0.8 * I2R(abilLvl)
set weaponsRange[weaponsN] = 1050
set weaponsN = weaponsN + 1
endif
// Hero sniper
set abilLvl = GetUnitAbilityLevel(U,'A0EA')
if abilLvl>0 then
set weaponsCost[weaponsN] = 0.8 * I2R(abilLvl)
set weaponsRange[weaponsN] = 1050
set weaponsN = weaponsN + 1
endif
// Hero sniper
set abilLvl = GetUnitAbilityLevel(U,'A08Z')
if abilLvl>0 and not wantAttackBuilding then
set weaponsCost[weaponsN] = 1.2 * I2R(abilLvl)
set weaponsRange[weaponsN] = 1300
set weaponsN = weaponsN + 1
endif
// Inventory weapons
set i = 0
loop
exitwhen i > 5
set ItemInSlot = UnitItemInSlot(U, i)
// Get the weapon range
set checkRange = I2R(GetWeaponRange(GetItemTypeId(ItemInSlot)))
// Only check this item, if it is a weapon which can attack the desired target
if checkRange>0 and (checkRange<=1050.0 or not wantAttackBuilding) then
// If a weapon with this range already exists, merge them,
// because there will be an O(n^2) loop later
set weaponsRange[weaponsN] = checkRange
set j = 0
loop
exitwhen j>=weaponsN or weaponsRange[weaponsN]==weaponsRange[j]
set j = j + 1
endloop
// Add weapon cost to that weapon,
// j will be weaponsN, if no matching weapon was found, so a new array index is used
set weaponsCost[j] = weaponsCost[j] + GetWidgetLife(ItemInSlot)*0.001
if j>=weaponsN then
set weaponsN = weaponsN + 1
endif
endif
set i = i + 1
endloop
set ItemInSlot = null
// No weapon there, return some random range
if weaponsN<=0 then
if wantAttackBuilding then
return 1050.00//GetRandomReal(500.00, 1050.00)
else
return 1300.00//GetRandomReal(500.00, 1300.00)
endif
endif
// For each weapon range, check the total value
// (reducing long-range weapon value and ignoring low-range weapons)
set i = 0
loop
exitwhen i>=weaponsN
set checkRange = weaponsRange[i]
// Loop though each weapon for this range and sum up the total value
set totalValue = 0
set j = 0
loop
exitwhen j>=weaponsN
// Ignore weapons with lower range
if weaponsRange[j] >= checkRange then
// Use the weapon formula to estimate value
// Weapons to shoot below their maximum range are treated like
// weapons with checkRange (losing value).
set totalValue = totalValue + weaponsCost[j]*checkRange/weaponsRange[j]
endif
set j = j + 1
endloop
// The currently checked range is better than all before
if totalValue>totalValueMax then
set totalValueMax = totalValue
set bestRange = checkRange
endif
set i = i + 1
endloop
// Note that this is the perfect combat range, but in reality the tank needs to
// move closer to the target, because every small movement of the enemy would get him out of range
// otherwise
return bestRange
endfunction
// Returns the combat range, recalculates if necessary
function GetAICombatRange takes unit U, boolean wantAttackBuilding returns real
local integer pid = GetPlayerNr(GetOwningPlayer(U))
if U==udg_Tank[pid] then
if udg_GetAICombatRange_Costs[pid]==udg_TankCosts[pid] and udg_GetAICombatRange_Level[pid]==GetHeroLevel(U) then
if wantAttackBuilding then
return udg_GetAICombatRange_RangeBuilding[pid]
else
return udg_GetAICombatRange_Range[pid]
endif
else
set udg_GetAICombatRange_Costs[pid] = udg_TankCosts[pid]
set udg_GetAICombatRange_Level[pid] = GetHeroLevel(U)
set udg_GetAICombatRange_Range[pid] = GetAICombatRange_Core(U, false)
set udg_GetAICombatRange_RangeBuilding[pid] = GetAICombatRange_Core(U, true)
endif
endif
return GetAICombatRange_Core(U,wantAttackBuilding)
endfunction
function GetAITotalWeaponValue takes unit U, boolean wantAttackBuilding returns real
// Returns the approximate price of a the "overall weapon" of the tank,
// that is, the price of a imaginary weapon having the same dps as all active weapons together,
// but only the range of CombatRange. Weapons with lower range are ignored completely.
local real costs = 0
local real combatRange = GetAICombatRange(U, wantAttackBuilding)
local real checkRange
local integer i
local integer abilLvl
local item ItemInSlot
// Tank cannon
set abilLvl = GetUnitAbilityLevel(U, 'A01J')
if abilLvl>0 and combatRange<=900 then
set costs = costs + 800*I2R(abilLvl)*combatRange/900
endif
// Air cannon
set abilLvl = GetUnitAbilityLevel(U, 'A0E9')
if abilLvl>0 and combatRange<=1050 then
set costs = costs + 800*I2R(abilLvl)*combatRange/1050
endif
// Creep sniper
set abilLvl = GetUnitAbilityLevel(U, 'A06M')
if abilLvl>0 and combatRange<=1050 and not wantAttackBuilding then
set costs = costs + 800*I2R(abilLvl)*combatRange/1050
endif
// Missile Battery
set abilLvl = GetUnitAbilityLevel(U, 'A0GB')
if abilLvl>0 and combatRange<=900 then
set costs = costs + 1000*I2R(abilLvl)*combatRange/900
endif
// Hero sniper
set abilLvl = GetUnitAbilityLevel(U,'A08Z')
if abilLvl>0 and combatRange<=1300 and not wantAttackBuilding then
set costs = costs + 1200*I2R(abilLvl)*combatRange/1300
endif
// Inventory weapons
set i = 0
loop
exitwhen i > 5
set ItemInSlot = UnitItemInSlot(U, i)
// Get the weapon range
set checkRange = I2R(GetWeaponRange(GetItemTypeId(ItemInSlot)))
if checkRange>0 and checkRange<=combatRange then
set costs = costs + GetWidgetLife(ItemInSlot)*combatRange/checkRange
endif
set i = i + 1
endloop
set ItemInSlot = null
return costs
endfunction
function GetAIMostExpensiveWeapon takes unit U returns integer
local integer i = 0
local integer costsMax=0
local integer j
local item ItemInSlot
loop
exitwhen i > 5
set ItemInSlot = UnitItemInSlot(U, i)
// Get the weapon range
set j = GetWeaponRange(GetItemTypeId(ItemInSlot))
if j>0 then
set j = R2I(GetWidgetLife(ItemInSlot))
if j>costsMax then
set costsMax = j
endif
endif
set i = i + 1
endloop
set ItemInSlot = null
return costsMax
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AIGlobalPlanner initializer Init requires AIThreatMap, AIInterface
// Does calculations required by all AI players and may give orders to single AI players
function RefreshGlobalData_ThreatEndangersCP takes integer team, ThreatGroup cpThreat returns boolean
return cpThreat.GetThreat( team )>0.0
endfunction
function DistBetweenUnitAndLoc takes unit U, location loc returns real
local real dx = GetUnitX(U)-GetLocationX(loc)
local real dy = GetUnitY(U)-GetLocationY(loc)
return SquareRoot(dx*dx+dy*dy)
endfunction
function AITeamProtectCPs_GetNearCP takes integer pid returns unit
// Note, that we can use the ThreatMap, though this is no AI-player,
// because AITeamProtectCPs is only called if there is an AI.
// Also note, that we are looping through healers, not the actual CPs,
// that is, because a player can also teleport from or to other factories.
// This just requires an additional check for town halls.
local integer cpidStart = ThreatMap.Healers_Begin[udg_Player_Team[pid]]
local integer cpidEnd = ThreatMap.Healers_End[udg_Player_Team[pid]]
local integer cpid = cpidStart
local real tankX = GetUnitX(udg_Tank[pid])
local real tankY = GetUnitY(udg_Tank[pid])
local real dx
local real dy
local real dsq
local real minDsq
local unit nearCP = null
loop
exitwhen cpid>cpidEnd
if IsUnitType(ThreatMap.Units[cpid], UNIT_TYPE_TOWNHALL)==true then
set dx = GetUnitX(ThreatMap.Units[cpid]) - tankX
set dy = GetUnitY(ThreatMap.Units[cpid]) - tankY
set dsq= dx*dx+dy*dy
if nearCP==null or dsq<minDsq then
set nearCP = ThreatMap.Units[cpid]
set minDsq = dsq
endif
endif
set cpid = cpid+1
endloop
return nearCP
endfunction
function AITeamProtectCPs takes integer team returns nothing
// TODO: Even though players might be in threat range, they still have to be ordered to the actual CP
// TODO: Sometimes it's better to call a player who is further away, but has a safe lane?
// TODO: Order AI to a point in the direction of an attacker
// TODO: Add inner check with lower range, to prevent the enemies from "sneaking" to the CP
// TODO: Consider tanks inside the base to have zero dist to cp
// TODO: Use AICPTP-functions
local integer cpidStart = ThreatMap.CPs_Begin[team]
local integer cpidEnd = ThreatMap.CPs_End[team]
// Add 1 here, because if start==end, we still have the cp at [start]
local integer cpsN = cpidEnd-cpidStart+1
// Note that cpidStart and cpidEnd just mark the position in the array we retrieve the CPs from.
// In fact, cpid is in [0, cpsN-1]
local integer cpid
local boolean anyCPInDanger = false
// Arrays for storing data for the cps [0,cpsN-1]
local boolean array cpInDangerInner
local boolean array cpInDangerOuter
// We use two threatgroups, so that enemies are detected at a long range, while still
// situations are detected, where there are allies around in long range, but an enemy directly near the CP.
local ThreatGroup array cpThreatInner
local ThreatGroup array cpThreatOuter
local unit U
// Arrays for players, probably explained by their names
local boolean array PlayerAvailable
local unit array PlayerNearCP
local real array PlayerNearCPDist
// Variables for finding the closest player
local integer minDistNr
local real minDist
local real curDist
local integer i
// The target of an AI player
local location aiTargetLoc
// This team has no CPs, so nothing to protect. Actually the base, but whatever.
if cpsN==0 then
return
endif
// STEP 1: Loop though CPs and get the threatmaps around,
// also check if any CP is in danger, as otherwise we don't do any further investigations
set cpid = 0
loop
exitwhen cpid>=cpsN
set U = ThreatMap.Units[cpidStart+cpid]
set cpThreatInner[cpid] = ThreatMap.GetThreatGroupCircle( GetUnitX(U), GetUnitY(U), AI_CP_THREAT_RANGE_INNER )
set cpThreatOuter[cpid] = ThreatMap.GetThreatGroupCircle( GetUnitX(U), GetUnitY(U), AI_CP_THREAT_RANGE_OUTER )
// We don't want the CP itself to change the threat rating, so remove it from the threatgroup
call cpThreatInner[cpid].RemoveUnit( U, GetUnitX(U), GetUnitY(U) )
call cpThreatOuter[cpid].RemoveUnit( U, GetUnitX(U), GetUnitY(U) )
// Save the result for this CP.
set cpInDangerInner[cpid] = RefreshGlobalData_ThreatEndangersCP(team, cpThreatInner[cpid])
set cpInDangerOuter[cpid] = RefreshGlobalData_ThreatEndangersCP(team, cpThreatOuter[cpid])
// There is a CP in danger, at least we know that, so we can't exit.
if cpInDangerInner[cpid] or cpInDangerOuter[cpid] then
set anyCPInDanger = true
endif
set cpid = cpid + 1
endloop
if not anyCPInDanger then
// The rest of this function takes some performance, so exit, if there is no cp in danger.
// Clear cpThreat[] first:
set cpid = 0
loop
exitwhen cpid>=cpsN
call cpThreatInner[cpid].destroy()
call cpThreatOuter[cpid].destroy()
set cpid = cpid + 1
endloop
return
endif
// STEP 2: Loop through players, and check whether they are available to help, if it is the case,
// then get the near CP and check whether this is in danger,
// and check if the player can be removed from that CP without any problem.
set i = 1
loop
exitwhen i>GetMaxHumanPlayers()
// First of all, only players are available matching these conditions:
// * Player is in the defender team
// * Tank is alive
// * Player has enough money to cptp
// There could be some other checks for cptp-money,
// but assuming that most of the time a player has more than 75 gold,
// it's okay to just exclude him completely.
set PlayerAvailable[i] = (udg_Player_Team[i]==team) and (udg_Tank[i]!=null) and (GetUnitState(udg_Tank[i],UNIT_STATE_LIFE)>=0.0) and (GetPlayerState(GetPlayer(i),PLAYER_STATE_RESOURCE_GOLD)>=AI_CPTP_COSTS)
if PlayerAvailable[i] then
// Get the near cp
if udg_AI_IsNewBot[i] then
// For the AI, we have comfortable cached data.
set PlayerNearCP[i] = AICore.Get(i).NearCP
set PlayerNearCPDist[i] = AICore.Get(i).NearCPDist
else
// For players, we need to search for the nearest CP
set PlayerNearCP[i] = AITeamProtectCPs_GetNearCP(i)
set PlayerNearCPDist[i] = DistBetweenUnits(PlayerNearCP[i],udg_Tank[i])
endif
// Now, if the player is already protecting a CP, we need to check it:
if PlayerNearCPDist[i] < AI_CP_THREAT_RANGE_OUTER then
// Look for the near cp in our CP array, and if we find it, check whether it is attacked
set cpid = 0
loop
exitwhen cpid>=cpsN
if ThreatMap.Units[cpidStart+cpid]==PlayerNearCP[i] then
if cpInDangerInner[cpid] or cpInDangerOuter[cpid] then
// CP is in danger, player can't help the other CPs
set PlayerAvailable[i] = false
// However, the player might still be too far away to actual help, if there's danger near the CP
// so move it to the CP, if necessary.
if cpInDangerInner[cpid] and PlayerNearCPDist[i] > AI_CP_THREAT_RANGE_INNER then
// Order to defend the CP, check if it worked
if AICore.Get(minDistNr).Behaviour.SetTargetOrder(AI_ORDER_MOVE, PlayerNearCP[i]) then
// The AI was ordered to the center, so we can add this tank to the ratings.
call cpThreatInner[cpid].AddUnit(udg_Tank[i],GetUnitX(udg_Tank[i]),GetUnitY(udg_Tank[i]))
endif
endif
else
// CP is not in danger, let's see, whether it is still not in danger, when this player is removed from it.
call cpThreatOuter[cpid].RemoveUnit(udg_Tank[i],GetUnitX(udg_Tank[i]),GetUnitY(udg_Tank[i]))
if RefreshGlobalData_ThreatEndangersCP(team, cpThreatOuter[cpid]) then
// Oh, removing our player has endangered the CP, so he has to stay.
set PlayerAvailable[i] = false
// Restore the unit to the threat group, maybe it would alter the overall result otherwise.
call cpThreatOuter[cpid].AddUnit(udg_Tank[i],GetUnitX(udg_Tank[i]),GetUnitY(udg_Tank[i]))
elseif PlayerNearCPDist[i] < AI_CP_THREAT_RANGE_INNER then
// Removing it from the outer area worked, but what about the inner area, if he's inside that?
call cpThreatInner[cpid].RemoveUnit(udg_Tank[i],GetUnitX(udg_Tank[i]),GetUnitY(udg_Tank[i]))
if RefreshGlobalData_ThreatEndangersCP(team, cpThreatInner[cpid]) then
// Oh, removing our player has endangered the CP, so he has to stay.
set PlayerAvailable[i] = false
// Restore the unit to the threat group, maybe it would alter the overall result otherwise.
call cpThreatInner[cpid].AddUnit(udg_Tank[i],GetUnitX(udg_Tank[i]),GetUnitY(udg_Tank[i]))
call cpThreatOuter[cpid].AddUnit(udg_Tank[i],GetUnitX(udg_Tank[i]),GetUnitY(udg_Tank[i]))
endif
endif
// If the player is still available, we keep it removed from the threat group,
// as maybe the cp is in danger, if even more players leave the CP.
endif
// No need to check the other CPs, since we just found the one we were looking for.
exitwhen true
endif
set cpid = cpid + 1
endloop
endif
endif
set i = i + 1
endloop
// STEP 3: Now loop through all CPs and find those, which are in danger.
// Then order players to defend them.
// Loop through CPs
set cpid = 0
loop
exitwhen cpid>=cpsN
set U = ThreatMap.Units[cpidStart+cpid]
// Do a loop, and in each run get the best possible player to defend the CP,
// if that player is enough, everything is fine, otherwise, run the loop again to send the next player
loop
// Exit the loop, if the cp is not in danger (any more)
exitwhen not (cpInDangerInner[cpid] or cpInDangerOuter[cpid])
// Loop through players and get the best helper
// Set the Dist limit, don't call players which are in a completely bad situation to help
set minDist = AI_CP_DEFEND_RANGE_LIMIT
set minDistNr = 0
set i = 1
loop
exitwhen i>GetMaxHumanPlayers()
if PlayerAvailable[i] then
// Calculate the Dist to defend the CP here
if PlayerNearCPDist[i]<minDist then
set minDist=PlayerNearCPDist[i]
set minDistNr=i
endif
endif
set i = i + 1
endloop
// If there is no AI to help that CP, give it up,
// this will finally happen if one player after another are ordered and can't help.
// In every loop, one AI which was available is set to be not available, so this loop will terminate.
exitwhen minDistNr==0
// If it is an AI, order it to defend the CP,
// else hope that it is a player who understands by himself,
// that defending that CP now is something he should definetely do.
if udg_AI_IsNewBot[minDistNr] then
// Order to defend the CP, check if it worked
if AICore.Get(minDistNr).Behaviour.SetTargetOrder(AI_ORDER_MOVE, U) then
// Order accepted. Add a reset timer of 3 seconds, since some other player
// may already move there or stuff, so that the AI stops the move,
// if it isn't reordered to the CP in the next few executions of the global planner.
call AICore.Get(minDistNr).Behaviour.SetOrderResetTime(3.0)
//call DebugMsg("AI ordered to defend.")
else
// Player is actually not available, the AI denied the command.
set PlayerAvailable[minDistNr] = false
endif
endif
// If the order worked, or the player is human:
if PlayerAvailable[minDistNr] then
// Order accepted, now add this unit to the groupDanger
call cpThreatInner[cpid].AddUnit(udg_Tank[minDistNr], GetUnitX(U), GetUnitY(U))
call cpThreatOuter[cpid].AddUnit(udg_Tank[minDistNr], GetUnitX(U), GetUnitY(U))
// So the cpThreat has changed, refresh if it still is in danger
set cpInDangerInner[cpid] = RefreshGlobalData_ThreatEndangersCP(team, cpThreatInner[cpid])
set cpInDangerOuter[cpid] = RefreshGlobalData_ThreatEndangersCP(team, cpThreatOuter[cpid])
// AI or player was just orderd or expected to defend that CP, so
// it is no longer available
set PlayerAvailable[minDistNr] = false
endif
endloop
// Not forgetting the clean-up, this loop is the last time cpThreat[] is accessed
call cpThreatInner[cpid].destroy( )
call cpThreatOuter[cpid].destroy( )
set cpid = cpid + 1
endloop
endfunction
function RefreshGlobalData_Team takes integer team returns nothing
// Refresh tanks near CPs:
// Check for every tank if it is in range of a CP in order to speed up some other calculations,
// and get a list of tanks that could teleport instantly to a CP.
// This is useful when the AI considers conquering a CP.
// TODO: Implement this
// CP Protection:
// Loop through every allied CP and check whether it is in danger
call AITeamProtectCPs(team)
endfunction
function RefreshGlobalData takes nothing returns nothing
local integer i
local boolean array isAIinTeam
// Refresh weapon structs used to calculate dps at given ranges
set i = 1
loop
exitwhen i>GetMaxHumanPlayers()
if udg_Tank[i]!=null then
call WeaponRanges.Get(i).Refresh(udg_Tank[i])
endif
if udg_AI_IsNewBot[i] then
set isAIinTeam[udg_Player_Team[i]] = true
endif
set i = i + 1
endloop
// Check if cps are in danger and stuff
if isAIinTeam[1] then
call RefreshGlobalData_Team(1)
endif
if isAIinTeam[2] then
call RefreshGlobalData_Team(2)
endif
endfunction
private function Init_Delayed takes nothing returns nothing
call TimerStart(CreateTimer(),1.0,true, function RefreshGlobalData )
endfunction
private function Init takes nothing returns nothing
call TimerStart(CreateTimer(),0.5,false, function Init_Delayed )
endfunction
endlibrary
//TESH.scrollpos=15
//TESH.alwaysfold=0
library AIShopping requires MapAttachedSettings, AICombatRange, TankChangeLibrary
struct AIShopping
// Subclass of AI to contain all shop-related functionality
AICore Parent
integer CurrentShop
integer CurrentItem
integer CurrentValue
integer MinCosts
integer MaxCosts
integer RandomSeed
real RandomSeedExpireTime
method GetSeededRandom takes integer seed, real min, real max returns real
// This method is used to calculate the chance for buying an item.
// The "RandomSeed" is changed every few minutes, so that in between
// the AI won't change its opinion suddenly. The parameter should be an
// item Id or something, as the chance should not change for the same item.
// The return value will never be max.
local integer i = RandomSeed*12389*seed+RandomSeed*90123+seed*seed+seed*58791+RandomSeed*seed*seed*23
// Don't know what results modulo would give for negative numbers (caused by overflow)
if i<0 then
set i = -i
endif
// Modulo:
return min+I2R(i-(i/100)*100)*(max-min)*0.01
endmethod
method GetChance takes integer seed, real chance returns boolean
return GetSeededRandom(seed,0.0,1.0)<chance
endmethod
method SetNewRandomSeed takes nothing returns nothing
set RandomSeed = GetRandomInt(0,100000)
set RandomSeedExpireTime = TimerGetElapsed(udg_GameTime)+AI_SHOP_RANDOM_SEED_TIMEOUT
endmethod
static method Create takes AICore source returns AIShopping
local AIShopping sub = AIShopping.allocate( )
set sub.Parent = source
call sub.SetNewRandomSeed()
return sub
endmethod
method GetShopUnit takes integer shopId returns unit
local integer team = Parent.Team
local unit target = null
if shopId == AI_SHOP_WEAPONS_1 then
if team == 1 then
set target = gg_unit_h00O_0021
else
set target = gg_unit_h00O_0070
endif
elseif shopId == AI_SHOP_WEAPONS_2 then
if team == 1 then
set target = gg_unit_h00N_0020
else
set target = gg_unit_h00N_0071
endif
elseif shopId == AI_SHOP_SPIRIT then
if team == 1 then
set target = gg_unit_h00G_0005
else
set target = gg_unit_h00G_0061
endif
elseif shopId == AI_SHOP_RESEARCH then
if team == 1 then
set target = gg_unit_h005_0014
else
set target = gg_unit_h005_0054
endif
elseif shopId == AI_SHOP_SIDE then
if team == 1 then
set target = gg_unit_n007_0185
else
set target = gg_unit_n007_0184
endif
elseif shopId == AI_SHOP_TRADER then
if team == 1 then
set target = udg_TradeMarket[1]
else
set target = udg_TradeMarket[2]
endif
elseif shopId == AI_SHOP_TANKHALL then
if team == 1 then
set target = gg_unit_h00S_0132
else
set target = gg_unit_h00S_0133
endif
elseif shopId == AI_SHOP_ITEM then
if team == 1 then
set target = gg_unit_h00A_0018
else
set target = gg_unit_h00A_0072
endif
elseif shopId == AI_SHOP_VEHICLEFACTORY then
if team == 1 then
set target = gg_unit_h003_0012
else
set target = gg_unit_h003_0051
endif
elseif shopId == AI_SHOP_MID then
set target = gg_unit_n00K_0102
endif
return target
endmethod
method GetDistanceToShop takes integer shopId returns real
local unit shopU = GetShopUnit(shopId)
local real dx
local real dy
if shopU==null then
return 1000000000.0
endif
set dx = GetUnitX(Parent.Tank) - GetUnitX(shopU)
set dy = GetUnitY(Parent.Tank) - GetUnitY(shopU)
return SquareRoot(dx*dx+dy*dy)
endmethod
method OrderMoveToShop takes integer shopId returns nothing
local unit shopU = GetShopUnit(shopId)
if shopU==null then
return
endif
call Parent.Behaviour.SetTargetOrder( AI_ORDER_MOVE_ATTACK, shopU )
endmethod
method WantsWeapon takes nothing returns boolean
local unit U = this.Parent.Tank
local integer i = GetUnitPointValue(U)
//20000 = point value of the most expensive tank
if i >= 20000 then
return true
elseif i == 0 then
return false
endif
set i = GetUnitTypeId(U)
//H00Y = Trader, H014 = Exploder, H006 = Tinker
if (i!='H00Y') and (i!='H014') and (i!='H006') then
if R2I(GetUnitState(U, UNIT_STATE_MAX_LIFE)) > ( GetBounty(U, false) / GetAICombatRange(U, false) * 240 ) then
return true
endif
endif
return false
endmethod
static method IsWeaponInDesiredMode takes item SlotItem returns boolean
local integer Item = GetItemTypeId(SlotItem)
// Keep normal modes of these weapons:
// Burning projectiles, Frost magic, grenade launcher, plasma fragments, rock catapult, star shooter, soulstone, artillery
return (Item-'I02P')*(Item-'I02C')*(Item-'I02Y')*(Item-'I007')*(Item-'I01Z')*(Item-'I05H')*(Item-'I01C')*(Item-'I00B')==0
endmethod
static method IsItemUseful takes item SlotItem returns boolean
local integer Item = GetItemTypeId(SlotItem)
//Artifact = all weapons
if GetItemType(SlotItem) == ITEM_TYPE_ARTIFACT then
return true
endif
//Only keep those items, sell all the others
// Power Pack Speed Boost Speed Boost(U) Speed Pack Strength Pack Teleporter
if (Item-'I011')*(Item-'I00V')*(Item-'I00W')*(Item-'I012')*(Item-'I052')*(Item-'I014')==0 then
return true
endif
//Adv Troop Command Troop Command Ultimate Pack
if (Item-'I053') * (Item-'I00Y') * (Item-'I01J')==0 then
return true
endif
// Hulls
if (Item-'I02H')*(Item-'I00R')*(Item-'I00Q')*(Item-'I04S')*(Item-'I04U')*(Item-'I04T')==0 then
return true
endif
return false
endmethod
method SellUselessItems takes nothing returns nothing
local item SlotItem
local integer i = 0
if udg_Afk[Parent.AINr] then
// Do not sell items if it's an afk-ai
return
endif
loop
exitwhen i > 5
set SlotItem = UnitItemInSlot( Parent.Tank, i )
// Check if it's a usable item for the AI, if not, sell it
if SlotItem != null and not AIShopping.IsItemUseful(SlotItem) then
call SetPlayerState( Parent.Owner, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Parent.Owner,PLAYER_STATE_RESOURCE_GOLD)+R2I(GetWidgetLife(SlotItem)))
call RemoveItem( SlotItem )
call DestroyEffect( AddSpecialEffectTarget( "origin", Parent.Tank, "UI\\Feedback\\GoldCredit\\GoldCredit.mdl" ) )
endif
set i = i + 1
endloop
set SlotItem = null
endmethod
method UpgradeWeapons takes nothing returns nothing
local item SlotItem
local integer i = 0
loop
exitwhen i > 5
set SlotItem = UnitItemInSlot( Parent.Tank, i )
// If it is a weapon, try to use it. If the AI has enough money, it will upgrade
if SlotItem!=null and GetItemType(SlotItem) == ITEM_TYPE_ARTIFACT and not IsWeaponInDesiredMode(SlotItem) then
call UnitUseItem( Parent.Tank, SlotItem )
endif
set i = i + 1
endloop
set SlotItem = null
endmethod
method CheckBuyItem takes integer ID, integer Costs, real Chance returns nothing
if (Costs > CurrentValue) and (Costs >= MinCosts) and (Costs <= MaxCosts) and GetChance(ID,Chance) then
//I03N = Upgrading item, in case the AI is just upgrading into an item it wants to buy
if (not UnitHasItemOfTypeBJ(Parent.Tank, ID)) and (not UnitHasItemOfTypeBJ(Parent.Tank, 'I03N')) then
set CurrentItem = ID
set CurrentValue = Costs
endif
endif
endmethod
method GetMoneyLeftAfterCPTP takes integer Money, integer TargetShop returns integer
if GetDistanceToShop( TargetShop ) > AI_SHOP_CPTP_RANGE then
return Money-AI_CPTP_COSTS
endif
return Money
endmethod
method SellPackParts takes integer packId returns nothing
local integer i
local integer ID
local integer number = Parent.AINr
local item SellThis
local unit U = Parent.Tank
//Altough the items are sold, the gold for the items won't be added
//since the price is already calculated into the new pack
//Speed Pack, Advanced Troop Command, Ultimate Pack
if ((packId - 'I012')*(packId - 'I053')*(packId - 'I01J')) == 0 then
set i = 0
loop
exitwhen i > 5
set ID = GetItemTypeId(UnitItemInSlot(U, i))
//Sell parts for Speed Pack
if (packId == 'I012') then
if (ID == 'I014') or (ID == 'I00W') or (ID == 'I00V') then
set SellThis = UnitItemInSlot(U, i)
endif
//Sell parts for Advanced Troop Command
elseif (packId == 'I053') then
if (ID == 'I00Y') then
set SellThis = UnitItemInSlot(U, i)
endif
//Sell parts for Ultimate Pack
elseif (packId == 'I01J') then
if (ID == 'I012') then
set SellThis = UnitItemInSlot(U, i)
endif
endif
set i = i + 1
endloop
call RemoveItem( SellThis )
endif
set SellThis = null
endmethod
method GetBestItem takes integer shopId returns nothing
local integer number = Parent.AINr
local player P = GetPlayer(number)
local integer i = (3 - udg_Player_Team[number]) * 5
local integer j = i - 4
local integer ms = 0
local integer k = 0
set CurrentItem = 0
set CurrentValue = 0
set CurrentShop = AI_SHOP_UNKNOWN
if (shopId!=AI_SHOP_UNKNOWN) and (shopId!=AI_SHOP_ITEM) then
// Items can only be bought from AI_SHOP_ITEM
return
endif
set MaxCosts = GetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD)
set MinCosts = R2I(GetUnitState(Parent.Tank, UNIT_STATE_MAX_LIFE))
set MaxCosts = GetMoneyLeftAfterCPTP( MaxCosts, AI_SHOP_ITEM )
//Check if the Bot needs a hull
if (GetBounty(Parent.Tank, false) > GetUnitState(Parent.Tank, UNIT_STATE_MAX_LIFE) * 2.5) then
call CheckBuyItem('I02H', 1250, 0.50)
call CheckBuyItem('I00R', 2500, 0.50)
call CheckBuyItem('I00Q', 5000, 0.50)
endif
set MinCosts = 0
//Get the average speed of the enemy team, to check whether you need more speed or not
loop
exitwhen (j > i)
if GetUnitMoveSpeed(udg_Tank[j]) > 5 then
set ms = ms + R2I(GetUnitMoveSpeed(udg_Tank[j]))
set k = k + 1
endif
set j = j + 1
endloop
if k != 0 then
set ms = ms / k
else
set ms = 0
endif
// Only check the following options, when the tank has no Speed or Ultimate Pack already
if (not UnitHasItemOfTypeBJ(Parent.Tank, 'I012')) and (not UnitHasItemOfTypeBJ(Parent.Tank, 'I01J')) and (CurrentItem == 0) then
// Check if Speed Boost is necessary
if ms > (GetUnitMoveSpeed(Parent.Tank) + 15) then
// If the tank already has Teleport -> combine
if UnitHasItemOfTypeBJ(Parent.Tank, 'I014') then
// Speed Pack Blueprint
call CheckBuyItem('I012', 3600, 0.25)
else
// Speed Boost
if not UnitHasItemOfTypeBJ(Parent.Tank, 'I00W') then
call CheckBuyItem('I00V', 1500, 0.25)
endif
endif
endif
// Check if a Teleporter is a viable option
if (GetBounty(Parent.Tank, false) > 15000) and (CurrentItem == 0) then
// If the tank already has Speed Boost (Upgrade) -> combine
if UnitHasItemOfTypeBJ(Parent.Tank, 'I00W') then
// Speed Pack Blueprint
call CheckBuyItem('I012', 3600, 0.25)
// If the tank already has normal Speed Boost -> combine
elseif UnitHasItemOfTypeBJ(Parent.Tank, 'I00V') then
// Speed Pack Blueprint
call CheckBuyItem('I012', 5100, 0.25)
else
// Teleporter
call CheckBuyItem('I014', 3000, 0.25)
endif
endif
elseif UnitHasItemOfTypeBJ(Parent.Tank, 'I012') then
// Ultimate Pack Blueprint
call CheckBuyItem('I01J', 6650, 0.50)
endif
// Only check the following options, when the tank has no Advanced Troop Command already
if (not UnitHasItemOfTypeBJ(Parent.Tank, 'I053')) and (CurrentItem == 0) then
if UnitHasItemOfTypeBJ(Parent.Tank, 'I00Y') then
//Advanced Troop Command
call CheckBuyItem('I053', 3500, 0.50)
else
//Troop Command
//Guard and Ghost Tank should buy Troop Command more likely
if (GetUnitTypeId(Parent.Tank) == 'H012') or (GetUnitTypeId(Parent.Tank) == 'H00R') then
call CheckBuyItem('I00Y', 2500, 0.50)
else
call CheckBuyItem('I00Y', 2500, 0.15)
endif
endif
endif
if CurrentItem != 0 then
set CurrentShop = AI_SHOP_ITEM
endif
endmethod
method CheckBuyTank takes integer ID, integer Costs returns nothing
local integer number = Parent.AINr
local player P = Parent.Owner
if (Costs >= CurrentValue or (Costs==CurrentValue and GetChance(ID,50))) and (Costs >= MinCosts) and (Costs <= MaxCosts) then
if (TankMeetsTechRequirements(P, ID) == 0) and not (udg_TankMonopoly and AnyAllyHasTankOfType(P,ID)) then
set CurrentItem = ID
set CurrentValue = Costs
endif
endif
endmethod
method GetBestTank takes nothing returns nothing
local player P = Parent.Owner
local integer number = Parent.AINr
// Reset buy plan
set CurrentItem = 0
set CurrentShop = 0
set CurrentValue= 0
// As the tank is sold, we can spend that money, too
set MaxCosts = GetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD) + GetUnitPointValue(udg_Tank[number]) / 2
if GetUnitTypeId(Parent.Tank)=='H00Y' or GetUnitTypeId(Parent.Tank)=='H014' or GetUnitTypeId(Parent.Tank)=='H006' then
// We need a new tank anyways
set MinCosts = 0
else
// It's only worth to buy a new tank, if its expensive enough
set MinCosts = R2I(GetUnitState(Parent.Tank, UNIT_STATE_MAX_LIFE) * 1.75)
endif
// But if we haven't got the most expensive tank in the game yet, this is still an option
if MinCosts > 20000 then
set MinCosts = 20000
endif
set MaxCosts = GetMoneyLeftAfterCPTP( MaxCosts, AI_SHOP_VEHICLEFACTORY )
call CheckBuyTank('H00B',4000)
call CheckBuyTank('H025',4000)
call CheckBuyTank('H00C',4500)
call CheckBuyTank('H00R',4500)
call CheckBuyTank('H012',5000)
call CheckBuyTank('H00D',5500)
call CheckBuyTank('H021',6000)
call CheckBuyTank('H00I',6500)
call CheckBuyTank('H01U',7500)
call CheckBuyTank('H02K',7500)
call CheckBuyTank('H00E',8000)
call CheckBuyTank('H01S',9000)
call CheckBuyTank('H00F',10000)
call CheckBuyTank('H00H',13000)
call CheckBuyTank('H01V',15000)
call CheckBuyTank('H01R',16000)
call CheckBuyTank('H00K',18000)
call CheckBuyTank('H01I',20000)
if CurrentItem!=0 then
// Currently the AI can buy all tanks in its base
set CurrentShop = AI_SHOP_VEHICLEFACTORY
endif
endmethod
method CheckBuyWeapon takes integer ID, integer Costs, location ExistingWeaponData returns nothing
local integer Range = GetWeaponRange(ID)
local real existingValue = GetLocationX(ExistingWeaponData)
local real existingRange = GetLocationY(ExistingWeaponData)
local integer effectiveValue
// Basically treats all existing weapons as one and reduces their value,
// if a new weapon with shorter range is bought, because they would have to act
// on a smaller range.
// On the other hand, if a weapon with higher range is bought, this cannot be
// used to its fullest.
// Randomize the value a bit, so the AI does not always buy the same weapons
// Slightly raise this value for higher ranges, since the AI normally works better
// with long-range weapons
if Range > existingRange then
set effectiveValue = R2I((Costs*existingRange/Range)*GetSeededRandom(ID,0.8,1.2))
else
set effectiveValue = R2I((Costs+existingValue*(Range/existingRange-1.0))*GetSeededRandom(ID,0.8,1.2))
endif
// Test: Let the AI only buy long range
//if Range<1045 then
// set effectiveValue = 0
//endif
if (effectiveValue > CurrentValue) and (Costs >= MinCosts) and (Costs <= MaxCosts) then
// Avoid low range weapons at the start
if (Costs < existingValue) or (Range >= 800) then
set CurrentItem = ID
set CurrentValue = effectiveValue
endif
endif
endmethod
method GetBestWeapon takes integer TargetShop returns nothing
local integer number = Parent.AINr
local integer BuyID = 0
local integer i
local integer cleanMaxCosts
// The location is actually an object storing total weapons value and the combat range
local location AverageRange
local item SellThis
local real totalValue = GetAITotalWeaponValue( Parent.Tank, false )
local item temp
set AverageRange = Location(totalValue, GetAICombatRange( udg_Tank[number], false ))
// TODO: Also check for cptp-costs
set CurrentItem = 0
set CurrentValue = R2I(totalValue*0.4)
set MaxCosts = GetPlayerState(Parent.Owner, PLAYER_STATE_RESOURCE_GOLD)
// Weapon has to be at least 80% as expensive at the most expesinve weapon the AI has,
// it should also be 40 percent of the owned weapons, and it should cost more than
// 80% of the current gold
// but a weapon for 30000 is always okay, since there are no more expensive weapons.
set MinCosts = IMaxBJ(GetAIMostExpensiveWeapon( Parent.Tank ), MaxCosts*3/4 )
set MinCosts = IMinBJ( MinCosts, 30000 )
if UnitInventoryCount(Parent.Tank) == 6 then
if udg_Afk[number] then
return
endif
set SellThis = UnitItemInSlot(Parent.Tank, 0)
set i = 1
loop
exitwhen i > 5
if ( GetWidgetLife(UnitItemInSlot(Parent.Tank, i)) < GetWidgetLife(SellThis) ) then
set SellThis = UnitItemInSlot(Parent.Tank, i)
endif
set i = i + 1
endloop
set i = 0
// If we sell that weapon, we have more money to spend
set MaxCosts = MaxCosts + R2I(GetWidgetLife(SellThis))
// But it's worthless to buy a new weapon cheaper than twice the old weapon price
set MinCosts = IMaxBJ(MinCosts,R2I(GetWidgetLife(SellThis))*2)
endif
set cleanMaxCosts = MaxCosts
if TargetShop == AI_SHOP_UNKNOWN or TargetShop == AI_SHOP_WEAPONS_1 then
set MaxCosts = GetMoneyLeftAfterCPTP( cleanMaxCosts, AI_SHOP_WEAPONS_1 )
call CheckBuyWeapon('I00N',1100,AverageRange)
call CheckBuyWeapon('I002',1500,AverageRange)
call CheckBuyWeapon('I01P',1500,AverageRange)
call CheckBuyWeapon('I02Y',1750,AverageRange)
call CheckBuyWeapon('I00E',2000,AverageRange)
call CheckBuyWeapon('I05W',2000,AverageRange)
call CheckBuyWeapon('I00C',2000,AverageRange)
call CheckBuyWeapon('I000',2200,AverageRange)
call CheckBuyWeapon('I00A',2200,AverageRange)
call CheckBuyWeapon('I00G',2700,AverageRange)
call CheckBuyWeapon('I05Y',2800,AverageRange)
call CheckBuyWeapon('I00J',3000,AverageRange)
// If a new object was found, refresh shop id
if BuyID != CurrentItem then
set BuyID = CurrentItem
set CurrentShop = AI_SHOP_WEAPONS_1
endif
endif
if TargetShop == AI_SHOP_UNKNOWN or TargetShop == AI_SHOP_WEAPONS_2 then
set MaxCosts = GetMoneyLeftAfterCPTP( cleanMaxCosts, AI_SHOP_WEAPONS_2 )
call CheckBuyWeapon('I01I',3000,AverageRange)
call CheckBuyWeapon('I02W',3500,AverageRange)
call CheckBuyWeapon('I003',4000,AverageRange)
//call CheckBuyWeapon('I038',4800,AverageRange)
call CheckBuyWeapon('I00B',5000,AverageRange)
call CheckBuyWeapon('I04M',6000,AverageRange)
call CheckBuyWeapon('I01H',6000,AverageRange)
call CheckBuyWeapon('I007',6000,AverageRange)
call CheckBuyWeapon('I001',6750,AverageRange)
call CheckBuyWeapon('I01O',7000,AverageRange)
call CheckBuyWeapon('I00H',7000,AverageRange)
call CheckBuyWeapon('I00K',8500,AverageRange)
// If a new object was found, refresh shop id
if BuyID != CurrentItem then
set BuyID = CurrentItem
set CurrentShop = AI_SHOP_WEAPONS_2
endif
endif
if TargetShop == AI_SHOP_UNKNOWN or TargetShop == AI_SHOP_SPIRIT then
set MaxCosts = GetMoneyLeftAfterCPTP( cleanMaxCosts, AI_SHOP_SPIRIT )
call CheckBuyWeapon('I01F',1111,AverageRange)
call CheckBuyWeapon('I01D',2222,AverageRange)
call CheckBuyWeapon('I017',3333,AverageRange)
call CheckBuyWeapon('I01B',4444,AverageRange)
call CheckBuyWeapon('I01G',5050,AverageRange)
call CheckBuyWeapon('I016',5555,AverageRange)
call CheckBuyWeapon('I00F',6060,AverageRange)
call CheckBuyWeapon('I04L',6666,AverageRange)
call CheckBuyWeapon('I010',7070,AverageRange)
//call CheckBuyWeapon('I018',7777,AverageRange)
call CheckBuyWeapon('I01E',8888,AverageRange)
call CheckBuyWeapon('I019',9999,AverageRange)
// If a new object was found, refresh shop id
if BuyID != CurrentItem then
set BuyID = CurrentItem
set CurrentShop = AI_SHOP_SPIRIT
endif
endif
if TargetShop == AI_SHOP_UNKNOWN or TargetShop == AI_SHOP_MID then
set MaxCosts = GetMoneyLeftAfterCPTP( cleanMaxCosts, AI_SHOP_MID )
call CheckBuyWeapon('I008',2500,AverageRange)
call CheckBuyWeapon('I005',3300,AverageRange)
call CheckBuyWeapon('I060',6000,AverageRange)
call CheckBuyWeapon('I01U',6000,AverageRange)
call CheckBuyWeapon('I02Z',6000,AverageRange)
call CheckBuyWeapon('I01S',7500,AverageRange)
call CheckBuyWeapon('I01K',11000,AverageRange)
call CheckBuyWeapon('I062',12000,AverageRange)
call CheckBuyWeapon('I01R',15000,AverageRange)
call CheckBuyWeapon('I01Y',20000,AverageRange)
call CheckBuyWeapon('I00M',25000,AverageRange)
call CheckBuyWeapon('I02U',30000,AverageRange)
// If a new object was found, refresh shop id
if BuyID != CurrentItem then
set BuyID = CurrentItem
set CurrentShop = AI_SHOP_MID
endif
endif
if TargetShop == AI_SHOP_UNKNOWN or TargetShop == AI_SHOP_SIDE then
set MaxCosts = GetMoneyLeftAfterCPTP( cleanMaxCosts, AI_SHOP_SIDE )
call CheckBuyWeapon('I055',1000,AverageRange)
call CheckBuyWeapon('I05H',1400,AverageRange)
call CheckBuyWeapon('I05J',4600,AverageRange)
call CheckBuyWeapon('I05B',5000,AverageRange)
call CheckBuyWeapon('I059',8000,AverageRange)
call CheckBuyWeapon('I057',8000,AverageRange)
call CheckBuyWeapon('I064',16000,AverageRange)
call CheckBuyWeapon('I066',23333,AverageRange)
call CheckBuyWeapon('I05E',25000,AverageRange)
call CheckBuyWeapon('I05C',30000,AverageRange)
// If a new object was found, refresh shop id
if BuyID != CurrentItem then
set BuyID = CurrentItem
set CurrentShop = AI_SHOP_SIDE
endif
endif
// The Current*** variables now contain the item
endmethod
method BuyBestItem takes integer shopId, boolean IsWeapon returns boolean
local integer i
local integer ID
local item SellThis
local item NewItem
local player P = Parent.Owner
local integer Team = udg_Player_Team[GetPlayerNr(P)]
local integer number = GetPlayerNr(P)
local boolean wantsWeapon = WantsWeapon( )
if IsWeapon then
if not wantsWeapon then
return false
endif
call GetBestWeapon(shopId)
else
if wantsWeapon then
return false
endif
call GetBestItem(shopId)
endif
if CurrentItem != 0 then
// Check if the AI is near the shop
if GetDistanceToShop( CurrentShop ) > AI_SHOPPING_RANGE then
call OrderMoveToShop( CurrentShop )
return true
endif
//If the wanted item is a blue print, remove already bought parts
call SellPackParts( CurrentItem )
if UnitInventoryCount( Parent.Tank ) == 6 then
set SellThis = UnitItemInSlot(Parent.Tank, 0)
set i = 1
loop
exitwhen i > 5
if ( GetWidgetLife(UnitItemInSlot( Parent.Tank, i )) < GetWidgetLife(SellThis) ) then
set SellThis = UnitItemInSlot( Parent.Tank, i )
endif
set i = i + 1
endloop
set i = GetItemCharges(SellThis)
loop
set NewItem = CreateItem(GetItemTypeId(SellThis),GetRandomReal(GetRectMinX(udg_JunkyardRect[Team])+16,GetRectMaxX(udg_JunkyardRect[Team])-16), GetRandomReal(GetRectMinY(udg_JunkyardRect[Team])+16,GetRectMaxY(udg_JunkyardRect[Team])-16))
call SetItemUserData(NewItem, 2)
call SetItemPlayer( NewItem, P, true )
set i = i - 1
exitwhen i <= 0
endloop
set NewItem = null
call AdjustPlayerStateBJ( R2I(GetWidgetLife(SellThis)), P, PLAYER_STATE_RESOURCE_GOLD )
call RemoveItem( SellThis )
call DestroyEffect( AddSpecialEffectTarget("UI\\Feedback\\GoldCredit\\GoldCredit.mdl", Parent.Tank, "origin") )
set SellThis = null
set i = 0
endif
set bj_lastCreatedItem = UnitAddItemById(Parent.Tank, CurrentItem)
call SetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(P, PLAYER_STATE_RESOURCE_GOLD) - R2I(GetWidgetLife(bj_lastCreatedItem)))
return true
endif
return false
endmethod
method BuyTank takes nothing returns boolean
local unit newTank
call GetBestTank( )
if CurrentItem != 0 then
if GetDistanceToShop( CurrentShop ) > AI_SHOPPING_RANGE then
call OrderMoveToShop( CurrentShop )
return true
endif
// Note that the location does not matter, because ChangeTanks() moves the tank to where it belongs.
set newTank = CreateUnit( Parent.Owner, CurrentItem, 0.0, 0.0, bj_UNIT_FACING )
call SetPlayerState(Parent.Owner,PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Parent.Owner,PLAYER_STATE_RESOURCE_GOLD)+GetUnitPointValue(Parent.Tank)/2-GetUnitPointValue(newTank))
call ChangeTanks(Parent.Tank, newTank, GetShopUnit( CurrentShop ), false )
// We also need to refresh the tank
set Parent.Tank = newTank
return true
endif
return false
endmethod
method CheckPlan takes nothing returns nothing
if TimerGetElapsed(udg_GameTime)>RandomSeedExpireTime then
call SetNewRandomSeed()
endif
if WantsWeapon( ) then
// Try to buy a weapon
call BuyBestItem( AI_SHOP_UNKNOWN, true )
// Now also upgrade items, even though you might already be in a state,
// where a tank would be better. However, the AI can buy only-building weapons
// and use the change option, which is only executed, when UpgradeWeapons( )
// is called.
call UpgradeWeapons( )
else
// Check for tanks or hulls
if not BuyTank( ) then
call BuyBestItem( AI_SHOP_UNKNOWN, false )
endif
endif
endmethod
endstruct
endlibrary
//TESH.scrollpos=235
//TESH.alwaysfold=0
library AISkills requires MapAttachedSettings, PvJass
globals
private integer ABILITY_TYPE_INSTANT = 1
private integer ABILITY_TYPE_TARGET_UNIT = 2
private integer ABILITY_TYPE_TARGET_POINT = 3
private integer ABILITY_TYPE_AREA = 4
private integer ABILITY_TYPE_PASSIVE = 5
endglobals
// This struct contains the logic of how to use a particular skill
struct AISkill
AISkillUsage Parent
unit Tank
// The data that is used to identify and categorize the skill
integer abilityId
string command
boolexpr targetType
integer abilityType
boolean IsActive // Is true, when it is off cooldown
// The numbers that describe the skills effect
real range_base
real range_up
real aoe_base
real aoe_up
real cooldown_base
real cooldown_up
// Categories that roughly describe what the skill is doing or how it should be used
// Tags that define what kind of skill it is
boolean IsNuke
boolean IsDisable
boolean IsBuff
boolean IsDebuff
boolean IsBuilding
boolean IsTeleport
boolean IsEscape // This skill helps you escaping a dangerous situation (speed buff, teleport etc)
boolean IsSummoning
// Tags that define how a skill should be used
boolean IsDangerous // Dangerous refers to the fact, that it harms allies also
boolean IsFacing // The way the tank is facing is important for this skill
boolean IsIgnoringUntil3 // Especially made for Rune Carving; only use the skill when it's at least level 3
boolean IsToggle // With this option, the AI toggles to the given skill Id, when units of the given unit filter are around you
boolean IsHealBuff // Special kind of buff, that either heals its target or protects it in some way
boolean BuffExcludeSelf // This is true, when the casting tank can't benefit from his own buff
boolean BuffOnlySelf // This is true, when the buff is only castable on yourself
boolean IsChanneling // When a skill is channeling, don't disrupt the casting on your own, let it finish
static method Create takes AISkillUsage parent, integer id, integer abilityType, boolexpr targetType, string command returns AISkill
local AISkill ai = AISkill.allocate()
set ai.Parent = parent
set ai.Tank = ai.Parent.Core.Tank
set ai.abilityId = id
set ai.abilityType = abilityType
set ai.targetType = targetType
set ai.command = command
set ai.IsActive = true
return ai
endmethod
method SetSkillData takes real range_base, real range_up, real aoe_base, real aoe_up, real cooldown_base, real cooldown_up returns nothing
set this.range_base = range_base
set this.range_up = range_up
set this.aoe_base = aoe_base
set this.aoe_up = aoe_up
set this.cooldown_base = cooldown_base
set this.cooldown_up = cooldown_up
endmethod
private method ExecuteTargetUnitSkill takes unit target returns boolean
local boolean result = false
local real range = this.range_base + (this.range_up * GetUnitAbilityLevel(this.Tank, this.abilityId))
if (GetUnitsDistance(target, this.Tank) <= (range * 1.2)) then
if (this.IsNuke or this.IsDebuff) and (this.Parent.Core.ThreatLevel > 2) then
if (target != null) then
set result = IssueTargetOrder(this.Tank, this.command, target)
endif
endif
// Don't try to disable already stunned targets, since they are disabled already
// You could argue that prolonging the stun may be worth it, but since you don't know how long the target already has been stunned
// you may want to wait a bit until you try to disable the target, to maximize the total stunning time
if (this.IsDisable) and (not IsUnitStunned(target)) then
if (target != null) then
set result = IssuePointOrder(this.Tank, this.command, GetUnitX(target), GetUnitY(target))
endif
endif
if (result == false) and (this.IsBuff) then
if (target != null) then
// Check if you try to target yourself although it's not possible or if you try to target another tank, even though it has to be you
if ((target == this.Tank) and (this.BuffExcludeSelf == false)) or ((target != this.Tank) and (this.BuffOnlySelf == false)) then
set result = IssuePointOrder(this.Tank, this.command, GetUnitX(target), GetUnitY(target))
endif
endif
endif
endif
return result
endmethod
private method ExecuteTargetUnitSkillCoord takes real X, real Y returns boolean
local group G
local unit temp
local boolean result = false
// When you are given only coordinates, search for a nearby unit to use this target ability on
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(this.Tank)
call GroupEnumUnitsInRange(G, X, Y, 500, this.targetType )
if (FirstOfGroup(G) != null) then
set temp = GetClosestUnitFromGroup(G, X, Y)
set result = ExecuteTargetUnitSkill(temp)
endif
call ReleaseGroup(G)
set G = null
return result
endmethod
private method ExecuteTargetAreaSkillCoord takes real X, real Y returns boolean
local boolean result = true
local real range = this.range_base + (this.range_up * GetUnitAbilityLevel(this.Tank, this.abilityId))
local real aoe = this.aoe_base + (this.aoe_up * GetUnitAbilityLevel(this.Tank, this.abilityId))
local group G
if (GetXYDistance(GetUnitX(this.Tank), GetUnitY(this.Tank), X, Y) <= (range * 1.2)) then
// Check if there are any valid targets in the area
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(this.Tank)
call GroupEnumUnitsInRange(G, X, Y, aoe, this.targetType )
if (this.IsBuff) and (this.BuffExcludeSelf) then
call GroupRemoveUnit(G, this.Tank)
endif
if (FirstOfGroup(G) == null) then
set result = false
endif
call ReleaseGroup(G)
set G = null
if (result) and (this.IsNuke or this.IsDebuff) then // and (this.Parent.Core.ThreatLevel > 2) then
if (this.IsDangerous) then
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(this.Tank)
call GroupEnumUnitsInRange(G, X, Y, aoe, FILTER_ALLY_TANK )
// Hitting one teammate at max is considered acceptable
if (CountUnitsInGroup(G) > 1) then
set result = false
endif
call ReleaseGroup(G)
set G = null
endif
endif
else
set result = false
endif
if result then
set result = IssuePointOrder(this.Tank, this.command, X, Y)
endif
return result
endmethod
private method ExecuteTargetAreaSkill takes unit target returns boolean
return ExecuteTargetAreaSkillCoord(GetUnitX(target), GetUnitY(target))
endmethod
private method ExecuteTargetPointSkillCoord takes real X, real Y returns boolean
local location TargetLoc
local real range = this.range_base + (this.range_up * GetUnitAbilityLevel(this.Tank, this.abilityId))
local boolean result = false
if (this.IsBuilding) then //and (this.Parent.Core.ThreatLevel > 2) then
set TargetLoc = Location(X, Y)
if (GetPathableLoc(TargetLoc, 32, 256)) then
set result = IssuePointOrderLoc(this.Tank, this.command, TargetLoc)
endif
call RemoveLocation(TargetLoc)
set TargetLoc = null
endif
if (result == false) and (GetXYDistance(GetUnitX(this.Tank), GetUnitY(this.Tank), X, Y) <= (range * 1.2)) then
if (this.IsNuke) then //and (this.Parent.Core.ThreatLevel > 2) then
set result = IssuePointOrder(this.Tank, this.command, X, Y)
endif
if (not result) and (this.IsTeleport) then
set result = IssuePointOrder(this.Tank, this.command, X, Y)
endif
endif
return result
endmethod
private method ExecuteTargetPointSkill takes unit target returns boolean
local real Angle = GetUnitFacing(this.Tank)
local real TargX
local real TargY
local real range = this.range_base + (this.range_up * GetUnitAbilityLevel(this.Tank, this.abilityId))
local boolean result = false
if (this.IsBuilding) then
set TargX = GetUnitX(this.Tank) + range*Cos(Angle)
set TargY = GetUnitY(this.Tank) + range*Sin(Angle)
elseif (target != null) then
set TargX = GetUnitX(target)
set TargY = GetUnitY(target)
else
return result
endif
return ExecuteTargetPointSkillCoord(TargX, TargY)
endmethod
private method ExecuteInstantSkill takes unit target returns boolean
local group G
local real aoe = this.aoe_base + (this.aoe_up * GetUnitAbilityLevel(this.Tank, this.abilityId))
local real targetAngle
local real tankFacing
local boolean result = true
if (this.IsFacing) and (target != null) then
call SetUnitFacingToFaceUnitTimed(this.Tank, target, 0.5)
set targetAngle = GetUnitsAngleDeg(this.Tank, target)
set tankFacing = GetUnitFacing(this.Tank)
// only execute this skill, when you are already roughly facing the right direction
if ((targetAngle - tankFacing) < -22) or ((targetAngle - tankFacing) > 22) then
set result = false
endif
endif
if (this.BuffOnlySelf) then
// well, in this case you know it is ok, since you always have to be around yourself!
elseif (result) then
set G = NewGroup()
set udg_Filter_Player = GetOwningPlayer(this.Tank)
call GroupEnumUnitsInRange(G, GetUnitX(this.Tank),GetUnitY(this.Tank), aoe, this.targetType )
if (this.IsBuff) and (this.BuffExcludeSelf) then
call GroupRemoveUnit(G, this.Tank)
endif
if (FirstOfGroup(G) == null) then
//call DebugMsg("Nothing to nuke")
// No target around and the toggle skill is in standard mode -> change mode so you may hit the alternate targets
if (this.IsToggle) and (GetUnitAbilityLevel(this.Tank, this.abilityId) > 0) then
set result = true
else
set result = false
endif
else
// Valid targets are around and the toggle skill in not in his normal mode (for which the filter is made), so switch now
if (this.IsToggle) and (GetUnitAbilityLevel(this.Tank, this.abilityId) == 0) then
set result = true
endif
endif
call ReleaseGroup(G)
set G = null
if (result) and (this.IsNuke) then
/* if (this.Parent.Core.ThreatLevel > 2) then
// alright, do it!
else
set result = false
endif */
endif
endif
if result then
set result = IssueImmediateOrder(this.Tank, this.command)
endif
return result
endmethod
private method ExecuteInstantSkillCoord takes real X, real Y returns boolean
local real targetAngle
local real tankFacing
if (this.IsFacing) then
call SetUnitFacing(this.Tank, GetAngle(GetUnitX(this.Tank), GetUnitY(this.Tank), X, Y))
set targetAngle = GetAngle(GetUnitX(this.Tank), GetUnitY(this.Tank), X, Y)
set tankFacing = GetUnitFacing(this.Tank)
// only execute this skill, when you are already roughly facing the right direction
if ((targetAngle - tankFacing) < -22) or ((targetAngle - tankFacing) > 22) then
return false
endif
endif
return ExecuteInstantSkill(null)
endmethod
static method SetSkillOnCooldown_Reset takes nothing returns nothing
local integer LoopTimerId = GetHandleIndex(GetExpiredTimer())
// Check if the tank still has the skill, if not he might have changed tanks
if (GetUnitAbilityLevel(udg_AV_AISkill[LoopTimerId].Tank, udg_AV_AISkill[LoopTimerId].abilityId) > 0) then
set udg_AV_AISkill[LoopTimerId].IsActive = true
endif
call DebugMsg("--- --- " + GetName(udg_AV_AISkill[LoopTimerId].Tank) + " skill is ready again")
call ReleaseTimer(GetExpiredTimer())
call ReleaseHandleIndex(LoopTimerId)
endmethod
method SetSkillOnCooldown takes nothing returns nothing
local timer t
local integer LoopTimerId
local real cooldown = this.cooldown_base + (this.cooldown_up * GetUnitAbilityLevel(this.Tank, this.abilityId))
call DebugMsg("--- " + GetName(this.Tank) + " skill goes into cooldown")
set this.IsActive = false
set t = NewTimer()
set LoopTimerId = NewTimerIndex(t)
set udg_AV_AISkill[LoopTimerId] = this
call TimerStart(t , cooldown , false , function AISkill.SetSkillOnCooldown_Reset)
call DebugMsg("--- - " + GetName(this.Tank) + " skill goes into cooldown END")
endmethod
method ExecuteSkill takes unit target returns boolean
local boolean result = false
if (this.IsActive) and (GetUnitAbilityLevel(this.Tank, this.abilityId) > 0) then
if (abilityType == ABILITY_TYPE_PASSIVE) then
// well, nothing to do here!
set result = true
elseif (abilityType == ABILITY_TYPE_INSTANT) then
set result = this.ExecuteInstantSkill(target)
elseif (abilityType == ABILITY_TYPE_TARGET_UNIT) then
set result = this.ExecuteTargetUnitSkill(target)
elseif (abilityType == ABILITY_TYPE_TARGET_POINT) then
set result = this.ExecuteTargetPointSkill(target)
elseif (abilityType == ABILITY_TYPE_AREA) then
set result = this.ExecuteTargetAreaSkill(target)
endif
endif
if (this.IsActive == false) then
call DebugMsg(GetName(this.Tank) + " can't use because CD")
endif
if (result) then
//call this.SetSkillOnCooldown()
endif
return result
endmethod
method ExecuteSkillCoord takes real X, real Y returns boolean
local boolean result = false
if (this.IsActive) and (GetUnitAbilityLevel(this.Tank, this.abilityId) > 0) then
if (this.abilityType == ABILITY_TYPE_PASSIVE) then
// well, nothing to do here!
set result = true
elseif (this.abilityType == ABILITY_TYPE_INSTANT) then
set result = this.ExecuteInstantSkillCoord(X, Y)
elseif (this.abilityType == ABILITY_TYPE_TARGET_UNIT) then
set result = this.ExecuteTargetUnitSkillCoord(X, Y)
elseif (this.abilityType == ABILITY_TYPE_TARGET_POINT) then
set result = this.ExecuteTargetPointSkillCoord(X, Y)
elseif (this.abilityType == ABILITY_TYPE_AREA) then
set result = this.ExecuteTargetAreaSkillCoord(X, Y)
endif
endif
if (result) then
//call this.SetSkillOnCooldown()
endif
return result
endmethod
endstruct
// This struct decides when and where to use the skills of a given tank
struct AISkillUsage
AICore Core
integer MAX_SKILLS = 5
AISkill array Skills[6]
static method Create takes AICore core returns AISkillUsage
local AISkillUsage ai = AISkillUsage.allocate()
set ai.Core = core
call ai.InitiateSkillsStruct(ai.Core.Tank)
return ai
endmethod
method WantsToNuke takes unit target returns boolean
local integer i = 1
local boolean result = false
if (target == null) then
// for now, lets just call it a day!
set result = false
else
loop
exitwhen (i > MAX_SKILLS) or (result)
if (this.Skills[i].IsNuke) then
set result = this.Skills[i].ExecuteSkill(target)
endif
set i = i + 1
endloop
endif
if result then
//call DebugMsg("+" + GetName(this.Core.Tank) + " nuke: " + GetName(target))
else
//call DebugMsg("-" + GetName(this.Core.Tank) + " nuke: " + GetName(target))
endif
return result
endmethod
method WantsToNukeCoord takes real X, real Y returns boolean
local integer i = 1
local boolean result = false
loop
exitwhen (i > MAX_SKILLS) or (result)
if (this.Skills[i].IsNuke) then
set result = this.Skills[i].ExecuteSkillCoord(X, Y)
endif
set i = i + 1
endloop
return result
endmethod
method WantsToDisable takes unit target returns boolean
local integer i = 1
local boolean result = false
if (target == null) then
// for now, lets just call it a day!
set result = false
else
loop
exitwhen (i > MAX_SKILLS) or (result)
if (this.Skills[i].IsDisable or this.Skills[i].IsDebuff) then
set result = this.Skills[i].ExecuteSkill(target)
endif
set i = i + 1
endloop
endif
return result
endmethod
method WantsToDisableCoord takes real X, real Y returns boolean
local integer i = 1
local boolean result = false
loop
exitwhen (i > MAX_SKILLS) or (result)
if (this.Skills[i].IsDisable or this.Skills[i].IsDebuff) then
set result = this.Skills[i].ExecuteSkillCoord(X, Y)
endif
set i = i + 1
endloop
return result
endmethod
method WantsToEscape takes unit target returns boolean
local integer i = 1
local boolean result = false
if (target == null) then
loop
exitwhen (i > MAX_SKILLS) or (result)
if (this.Skills[i].IsEscape) then
set result = this.Skills[i].ExecuteSkill(target)
endif
set i = i + 1
endloop
else
loop
exitwhen (i > MAX_SKILLS) or (result)
if (this.Skills[i].IsTeleport) then
set result = this.Skills[i].ExecuteSkill(target)
endif
set i = i + 1
endloop
endif
return result
endmethod
method WantsToEscapeCoord takes real X, real Y returns boolean
local integer i = 1
local boolean result = false
loop
exitwhen (i > MAX_SKILLS) or (result)
if (this.Skills[i].IsTeleport) then
set result = this.Skills[i].ExecuteSkillCoord(X, Y)
endif
set i = i + 1
endloop
return result
endmethod
method WantsToProtect takes unit target returns boolean
local integer i = 1
local boolean result = false
if (target == null) then
// for now, lets just call it a day!
set result = false
else
loop
exitwhen (i > MAX_SKILLS) or (result)
if (this.Skills[i].IsHealBuff) then
set result = this.Skills[i].ExecuteSkill(target)
endif
set i = i + 1
endloop
endif
return result
endmethod
method WantsToBuff takes unit target returns boolean
return false
endmethod
method HasAoeNuke takes nothing returns boolean
local integer i = 1
local boolean result = false
loop
exitwhen (i > MAX_SKILLS) or (result)
if (this.Skills[i].IsNuke and ((this.Skills[i].abilityType == ABILITY_TYPE_AREA) or (this.Skills[i].abilityType == ABILITY_TYPE_TARGET_POINT)) ) then
if (this.Skills[i].IsActive) then
set result = true
endif
endif
set i = i + 1
endloop
return result
endmethod
method IsCasting takes nothing returns boolean
local string CurrentOrder = OrderId2String(GetUnitCurrentOrder(this.Core.Tank))
local boolean IsUsingAbility = not ( CurrentOrder == "move" or CurrentOrder == "stop" or CurrentOrder == "smart" or CurrentOrder == null )
return IsUsingAbility
endmethod
method AbortCasting takes boolean ignoreChanneling returns nothing
local string CurrentOrder
local integer i = 1
local boolean result = true
if (ignoreChanneling == false) then
set CurrentOrder = OrderId2String(GetUnitCurrentOrder(this.Core.Tank))
loop
exitwhen (i > MAX_SKILLS) or (result == false)
if ((this.Skills[i].command == CurrentOrder) and this.Skills[i].IsChanneling) then
set result = false
endif
set i = i + 1
endloop
endif
if (result) then
call IssueImmediateOrder(this.Core.Tank, "stop")
endif
endmethod
// +++++++++++++++++++++++++
// + Skill initializsation +
// +++++++++++++++++++++++++
private method ScoutSkills takes nothing returns nothing
// Watch Tower
set this.Skills[1] = AISkill.Create(this, 'A09X', ABILITY_TYPE_TARGET_POINT, FILTER_NULL, "summonfactory")
call this.Skills[1].SetSkillData(200.0, 0.0, 0.0, 0.0, 35.0, 0.0)
set this.Skills[1].IsBuilding = true
// Rune Carving (this one is pretty hard to categorize)
set this.Skills[2] = AISkill.Create(this, 'A030', ABILITY_TYPE_TARGET_POINT, FILTER_NULL, "blink")
call this.Skills[2].SetSkillData(500.0, 0.0, 0.0, 0.0, 55.0, -5.0)
set this.Skills[2].IsBuff = true
set this.Skills[2].IsHealBuff = true
set this.Skills[2].IsBuilding = true
set this.Skills[2].IsIgnoringUntil3 = true
// Defensive Systems
set this.Skills[3] = AISkill.Create(this, 'A035', ABILITY_TYPE_INSTANT, FILTER_NULL, "windwalk")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 35.0, 0.0)
set this.Skills[3].IsBuff = true
set this.Skills[3].IsHealBuff = true
set this.Skills[3].BuffOnlySelf = true
// Ensnare
set this.Skills[4] = AISkill.Create(this, 'A09O', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "ensnare")
call this.Skills[4].SetSkillData(1000.0, 0.0, 0.0, 0.0, 50.0, 0.0)
set this.Skills[4].IsDisable = true
// Creep Cannon
// No need for a struct here
endmethod
private method LightTankSkills takes nothing returns nothing
// Cluster Shot
set this.Skills[1] = AISkill.Create(this, 'A04M', ABILITY_TYPE_AREA, FILTER_ENEMY, "clusterrockets")
call this.Skills[1].SetSkillData(1100.0, 0.0, 300.0, 0.0, 30.0, 0.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsChanneling = true
// Triple Rocket
set this.Skills[2] = AISkill.Create(this, 'A02T', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "thunderbolt")
call this.Skills[2].SetSkillData(1000.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsNuke = true
set this.Skills[2].IsDisable = true
// Repair
set this.Skills[3] = AISkill.Create(this, 'A0BM', ABILITY_TYPE_INSTANT, FILTER_NULL, "windwalk")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 44.0, -4.0)
set this.Skills[3].IsBuff = true
set this.Skills[3].IsHealBuff = true
set this.Skills[3].BuffOnlySelf = true
// Multi-Rocket Shot
set this.Skills[4] = AISkill.Create(this, 'A06V', ABILITY_TYPE_AREA, FILTER_ENEMY, "healingspray")
call this.Skills[4].SetSkillData(500.0, 0.0, 1000.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
// Tank Cannon
// No need for a struct here
endmethod
private method HelicopterSkills takes nothing returns nothing
// Bombardement
set this.Skills[1] = AISkill.Create(this, 'A001', ABILITY_TYPE_AREA, FILTER_ENEMY_GROUND_UNIT, "clusterrockets")
call this.Skills[1].SetSkillData(850.0, 0.0, 300.0, 0.0, 30.0, 0.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsChanneling = true
// Triple Rocket
set this.Skills[2] = AISkill.Create(this, 'A02T', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "thunderbolt")
call this.Skills[2].SetSkillData(1000.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsNuke = true
set this.Skills[2].IsDisable = true
// Jet Propulsion
set this.Skills[3] = AISkill.Create(this, 'A031', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Fire Bomb
set this.Skills[4] = AISkill.Create(this, 'A01B', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY, "shadowstrike")
call this.Skills[4].SetSkillData(650.0, 0.0, 300.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
// Tank Cannon
// No need for a struct here
endmethod
private method AntiGravSkills takes nothing returns nothing
// Plasma Cluster
set this.Skills[1] = AISkill.Create(this, 'A055', ABILITY_TYPE_AREA, FILTER_ENEMY, "clusterrockets")
call this.Skills[1].SetSkillData(1200.0, 0.0, 200.0, 0.0, 30.0, 0.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsChanneling = true
// EMP Torpedos
set this.Skills[2] = AISkill.Create(this, 'A07E', ABILITY_TYPE_INSTANT, FILTER_ENEMY_TANK, "fanofknives")
call this.Skills[2].SetSkillData(0.0, 0.0, 900.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsNuke = true
set this.Skills[2].IsDisable = true
// Jump
set this.Skills[3] = AISkill.Create(this, 'A02W', ABILITY_TYPE_TARGET_POINT, FILTER_NULL, "blink")
call this.Skills[3].SetSkillData(200.0, 400.0, 0.0, 0.0, 18.0, 0.0)
set this.Skills[3].IsTeleport = true
set this.Skills[3].IsEscape = true
// Dimension Shift
set this.Skills[4] = AISkill.Create(this, 'A07G', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "shadowstrike")
call this.Skills[4].SetSkillData(900.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsDisable = true
// Tank Cannon
// No need for a struct here
endmethod
private method MedivacSkills takes nothing returns nothing
// Superthrust
set this.Skills[1] = AISkill.Create(this, 'A0BA', ABILITY_TYPE_INSTANT, FILTER_ENEMY_TANK, "berserk")
call this.Skills[1].SetSkillData(1300.0, 0.0, 400.0, 0.0, 18.0, -2.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsBuff = true
set this.Skills[1].BuffOnlySelf = true
set this.Skills[1].IsFacing = true
set this.Skills[1].IsEscape = true
// Life Converter
// Kinda difficult to correctly categorize this skill, as it has
// both a damaging and a buffing part
set this.Skills[2] = AISkill.Create(this, 'A0B8', ABILITY_TYPE_AREA, FILTER_ENEMY_CREEP, "channel")
call this.Skills[2].SetSkillData(1000.0, 0.0, 225.0, 0.0, 25.0, 0.0)
set this.Skills[2].IsBuff = true
set this.Skills[2].IsHealBuff = true
// Decoy
set this.Skills[3] = AISkill.Create(this, 'A07D', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Support Systems
set this.Skills[4] = AISkill.Create(this, 'A0BL', ABILITY_TYPE_INSTANT, FILTER_ALLY_TANK, "divineshield")
call this.Skills[4].SetSkillData(0.0, 0.0, 900.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsBuff = true
set this.Skills[4].IsHealBuff = true
// Tank Cannon
// No need for a struct here
endmethod
private method DistributorSkills takes nothing returns nothing
// Heat-Seeking Missile
set this.Skills[1] = AISkill.Create(this, 'A0FU', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "berserk")
call this.Skills[1].SetSkillData(0.0, 0.0, 1200.0, 0.0, 5.0, 0.0)
set this.Skills[1].IsNuke = true
// Reactive Armor
set this.Skills[2] = AISkill.Create(this, 'A0FS', ABILITY_TYPE_TARGET_UNIT, FILTER_ALLY_TANK, "unholyfrenzy")
call this.Skills[2].SetSkillData(1050.0, 0.0, 0.0, 0.0, 28.0, -3.0)
set this.Skills[2].IsBuff = true
set this.Skills[2].IsHealBuff = true
// Tankers Little Helper
set this.Skills[3] = AISkill.Create(this, 'A0FT', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// S.I.C.
set this.Skills[4] = AISkill.Create(this, 'A0FW', ABILITY_TYPE_AREA, FILTER_ENEMY_TANK, "flamestrike")
call this.Skills[4].SetSkillData(1050.0, 0.0, 400.0, 100.0, 40.0, 0.0)
set this.Skills[4].IsDebuff = true
// Tank Cannon
// No need for a struct here
endmethod
private method RaiderSkills takes nothing returns nothing
// Static Charge
// The cooldown is stated shorter than it actually is on purpose, because of the reset
set this.Skills[1] = AISkill.Create(this, 'A0CB', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "shadowstrike")
call this.Skills[1].SetSkillData(1000.0, 0.0, 50.0, 50.0, 3.0, 0.0)
set this.Skills[1].IsNuke = true
// Shape Memory Alloy
set this.Skills[2] = AISkill.Create(this, 'A0FA', ABILITY_TYPE_INSTANT, FILTER_NULL, "berserk")
call this.Skills[2].SetSkillData(0.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsBuff = true
set this.Skills[2].BuffOnlySelf = true
set this.Skills[2].IsHealBuff = true
// Ricochet
set this.Skills[3] = AISkill.Create(this, 'A0BN', ABILITY_TYPE_INSTANT, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 30.0, 0.0)
set this.Skills[3].IsBuff = true
set this.Skills[3].BuffOnlySelf = true
// Hit&Run
set this.Skills[4] = AISkill.Create(this, 'A06S', ABILITY_TYPE_TARGET_POINT, FILTER_NULL, "blink")
call this.Skills[4].SetSkillData(600.0, 200.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsTeleport = true
// Tank Cannon
// No need for a struct here
endmethod
private method DemolisherSkills takes nothing returns nothing
// Jet Wave
set this.Skills[1] = AISkill.Create(this, 'A02R', ABILITY_TYPE_TARGET_POINT, FILTER_ENEMY, "carrionswarm")
call this.Skills[1].SetSkillData(1000.0, 0.0, 150.0, 0.0, 30.0, 0.0)
set this.Skills[1].IsNuke = true
// Artillery Shot
set this.Skills[2] = AISkill.Create(this, 'A0B5', ABILITY_TYPE_AREA, FILTER_ENEMY, "clusterrockets")
call this.Skills[2].SetSkillData(2000.0, 0.0, 180.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsNuke = true
set this.Skills[2].IsDisable = true
// Mines
set this.Skills[3] = AISkill.Create(this, 'A04U', ABILITY_TYPE_TARGET_POINT, FILTER_NULL, "")
call this.Skills[3].SetSkillData(150.0, 0.0, 250.0, 0.0, 60.0, 0.0)
set this.Skills[3].IsBuilding = true
// Burning Oil
set this.Skills[4] = AISkill.Create(this, 'A02F', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "blink")
call this.Skills[4].SetSkillData(800.0, 0.0, 400.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
set this.Skills[4].IsDebuff = true
// Tank Cannon
// No need for a struct here
endmethod
private method GoblinShredderSkills takes nothing returns nothing
// Metal Stars
set this.Skills[1] = AISkill.Create(this, 'A03D', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "fanofknives")
call this.Skills[1].SetSkillData(0.0, 0.0, 800.0, 0.0, 22.0, 0.0)
set this.Skills[1].IsNuke = true
// Magnetic Pull
set this.Skills[2] = AISkill.Create(this, 'A052', ABILITY_TYPE_INSTANT, FILTER_ENEMY_TANK, "berserk")
call this.Skills[2].SetSkillData(0.0, 0.0, 600.0, 0.0, 20.0, 0.0)
set this.Skills[2].IsDisable = true
// Goblin Synergy
set this.Skills[3] = AISkill.Create(this, 'A0D7', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Unit Teleport
set this.Skills[4] = AISkill.Create(this, 'A04N', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "shadowstrike")
call this.Skills[4].SetSkillData(600.0, 200.0, 0.0, 0.0, 30.0, 0.0)
set this.Skills[4].IsDebuff = true
set this.Skills[4].IsDisable = true
// Tank Cannon
// No need for a struct here
endmethod
private method StormTankSkills takes nothing returns nothing
// Storm Shock
set this.Skills[1] = AISkill.Create(this, 'A0F8', ABILITY_TYPE_AREA, FILTER_ENEMY, "flamestrike")
call this.Skills[1].SetSkillData(900.0, 0.0, 400.0, 0.0, 15.0, 0.0)
set this.Skills[1].IsNuke = true
// Energy Leash
set this.Skills[2] = AISkill.Create(this, 'A0E4', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_AIR_TANK, "channel")
call this.Skills[2].SetSkillData(1200.0, 0.0, 0.0, 0.0, 25.0, 0.0)
set this.Skills[2].IsDisable = true
// Air Mines
set this.Skills[3] = AISkill.Create(this, 'A0E8', ABILITY_TYPE_TARGET_POINT, FILTER_NULL, "")
call this.Skills[3].SetSkillData(900.0, 0.0, 500.0, 0.0, 45.0, 0.0)
set this.Skills[3].IsDebuff = true
set this.Skills[3].IsNuke = true
// Eye of the Storm
set this.Skills[4] = AISkill.Create(this, 'A0EF', ABILITY_TYPE_INSTANT, FILTER_NULL, "berserk")
call this.Skills[4].SetSkillData(0.0, 0.0, 1100.0, 0.0, 50.0, 0.0)
set this.Skills[4].IsDebuff = true
set this.Skills[4].IsBuff = true
set this.Skills[4].IsEscape = true
// Air Cannon
set this.Skills[5] = AISkill.Create(this, 'A0EA', ABILITY_TYPE_INSTANT, FILTER_ENEMY_AIR_TANK, "fanofknives")
call this.Skills[5].SetSkillData(0.0, 0.0, 1050.0, 0.0, 2.0, 0.0)
set this.Skills[5].IsToggle = true
endmethod
private method AirShipSkills takes nothing returns nothing
// Electro Shocker
set this.Skills[1] = AISkill.Create(this, 'A023', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY, "forkedlightning")
call this.Skills[1].SetSkillData(900.0, 0.0, 250.0, 0.0, 25.0, 0.0)
set this.Skills[1].IsNuke = true
// Healing Drones
set this.Skills[2] = AISkill.Create(this, 'A06W', ABILITY_TYPE_INSTANT, FILTER_ENEMY_TANK, "Locustswarm")
call this.Skills[2].SetSkillData(0.0, 0.0, 1000.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsNuke = true
// Jet Propulsion
set this.Skills[3] = AISkill.Create(this, 'A0GI', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Plasma Rain
set this.Skills[4] = AISkill.Create(this, 'A02Z', ABILITY_TYPE_AREA, FILTER_ENEMY, "blizzard")
call this.Skills[4].SetSkillData(1000.0, 0.0, 400.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
// Tank Cannon
// No need for a struct here
endmethod
private method ThunderTankSkills takes nothing returns nothing
// Lightning Strike
set this.Skills[1] = AISkill.Create(this, 'A02N', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "thunderbolt")
call this.Skills[1].SetSkillData(1200.0, 0.0, 600.0, 0.0, 40.0, 0.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsDisable = true
// Thunder Storm
set this.Skills[2] = AISkill.Create(this, 'A04B', ABILITY_TYPE_AREA, FILTER_ENEMY, "clusterrockets")
call this.Skills[2].SetSkillData(1100.0, 0.0, 450.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsNuke = true
set this.Skills[2].IsChanneling = true
// Electro Aura
set this.Skills[3] = AISkill.Create(this, 'A034', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Chain Lightning
set this.Skills[4] = AISkill.Create(this, 'A029', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "chainlightning")
call this.Skills[4].SetSkillData(750.0, 250.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
// Tank Cannon
// No need for a struct here
endmethod
private method GhostTankSkills takes nothing returns nothing
// Soul Transfer
set this.Skills[1] = AISkill.Create(this, 'A06X', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "drain")
call this.Skills[1].SetSkillData(700.0, 0.0, 0.0, 0.0, 25.0, 0.0)
set this.Skills[1].IsDisable = true
set this.Skills[1].IsChanneling = true
// Summoning of the Dead
set this.Skills[2] = AISkill.Create(this, 'A03A', ABILITY_TYPE_INSTANT, FILTER_NULL, "spiritwolf")
call this.Skills[2].SetSkillData(0.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsSummoning = true
// Soul Collector
set this.Skills[3] = AISkill.Create(this, 'A06L', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Soul Restore
set this.Skills[4] = AISkill.Create(this, 'A093', ABILITY_TYPE_INSTANT, FILTER_ALLY_CREEP, "replenishlife")
call this.Skills[4].SetSkillData(0.0, 0.0, 600.0, 0.0, 5.0, 0.0)
set this.Skills[4].IsBuff = true
set this.Skills[4].IsHealBuff = true
set this.Skills[4].BuffExcludeSelf = true
// Tank Cannon
// No need for a struct here
endmethod
private method GuardSkills takes nothing returns nothing
// Roots (kinda hard to categorize, needs some more thought)
//set this.Skills[1] = AISkill.Create(this, 'A03Y', ABILITY_TYPE_INSTANT, FILTER_ALLY_TANK, "drain")
//call this.Skills[1].SetSkillData(0.0, 0.0, 0.0, 0.0, 5.0, 0.0)
//set this.Skills[1].IsBuff = true
// Natural Energy
set this.Skills[2] = AISkill.Create(this, 'A0AM', ABILITY_TYPE_AREA, FILTER_ALLY_TANK, "healingspray")
call this.Skills[2].SetSkillData(1300.0, 0.0, 400.0, 0.0, 30.0, 0.0)
set this.Skills[2].IsBuff = true
set this.Skills[2].IsHealBuff = true
set this.Skills[2].BuffExcludeSelf = true
// Summon Treants
set this.Skills[3] = AISkill.Create(this, 'A0CH', ABILITY_TYPE_INSTANT, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[3].IsSummoning = true
// Entangling Roots
set this.Skills[4] = AISkill.Create(this, 'A041', ABILITY_TYPE_AREA, FILTER_ENEMY_TANK, "clusterrockets")
call this.Skills[4].SetSkillData(1200.0, 0.0, 350.0, 0.0, 60.0, 0.0)
set this.Skills[4].IsDisable = true
// Tank Cannon
// No need for a struct here
endmethod
private method HeavyTankSkills takes nothing returns nothing
// Aiming Rocket
set this.Skills[1] = AISkill.Create(this, 'A024', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "thunderbolt")
call this.Skills[1].SetSkillData(2000.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[1].IsDisable = true
set this.Skills[1].IsNuke = true
// Mortar Teams
set this.Skills[2] = AISkill.Create(this, 'A00Z', ABILITY_TYPE_INSTANT, FILTER_NULL, "waterelemental")
call this.Skills[2].SetSkillData(0.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsSummoning = true
// Heavy Armor
set this.Skills[3] = AISkill.Create(this, 'A06R', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Hail of Bombs
set this.Skills[4] = AISkill.Create(this, 'A0B6', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "channel")
call this.Skills[4].SetSkillData(1600.0, 0.0, 400.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
set this.Skills[4].IsFacing = true
// Tank Cannon
// No need for a struct here
endmethod
private method ArchitectSkills takes nothing returns nothing
// Freezing Missile
set this.Skills[1] = AISkill.Create(this, 'A0DC', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY, "channel")
call this.Skills[1].SetSkillData(900.0, 0.0, 500.0, 0.0, 30.0, 0.0)
set this.Skills[1].IsDisable = true
set this.Skills[1].IsNuke = true
// Cannon Module
set this.Skills[2] = AISkill.Create(this, 'A0D8', ABILITY_TYPE_TARGET_UNIT, FILTER_ALLY_TANK, "chainlightning")
call this.Skills[2].SetSkillData(500.0, 0.0, 0.0, 0.0, 15.0, 0.0)
set this.Skills[2].IsBuff = true
// Portal
set this.Skills[3] = AISkill.Create(this, 'A0DD', ABILITY_TYPE_TARGET_POINT, FILTER_NULL, "")
call this.Skills[3].SetSkillData(200.0, 0.0, 0.0, 0.0, 35.0, -5.0)
set this.Skills[3].IsBuilding = true
// Pacifista
set this.Skills[4] = AISkill.Create(this, 'A0DJ', ABILITY_TYPE_INSTANT, FILTER_NULL, "channel")
call this.Skills[4].SetSkillData(0.0, 0.0, 0.0, 0.0, 60.0, 0.0)
set this.Skills[4].IsSummoning = true
// Splash Cannon
set this.Skills[5] = AISkill.Create(this, 'A0DN', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "defend")
call this.Skills[5].SetSkillData(0.0, 0.0, 950.0, 0.0, 3.0, 0.0)
set this.Skills[5].IsToggle = true
endmethod
private method GoblinTankSkills takes nothing returns nothing
// Thunder Hammer
set this.Skills[1] = AISkill.Create(this, 'A01O', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "thunderbolt")
call this.Skills[1].SetSkillData(500.0, 0.0, 0.0, 0.0, 30.0, 0.0)
set this.Skills[1].IsDisable = true
set this.Skills[1].IsNuke = true
//set this.Skills[1].IsChanneling = true // ???
// Goblin Riot
set this.Skills[2] = AISkill.Create(this, 'A03Z', ABILITY_TYPE_INSTANT, FILTER_NULL, "spiritwolf")
call this.Skills[2].SetSkillData(0.0, 0.0, 0.0, 0.0, 45.0, -5.0)
set this.Skills[2].IsSummoning = true
set this.Skills[2].IsNuke = true
// Goblin Turbo
set this.Skills[3] = AISkill.Create(this, 'A08I', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Shockwave
set this.Skills[4] = AISkill.Create(this, 'A026', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "shockwave")
call this.Skills[4].SetSkillData(0.0, 0.0, 750.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
// Tank Cannon
// No need for a struct here
endmethod
private method DarknessTankSkills takes nothing returns nothing
// Orb of Darkness
set this.Skills[1] = AISkill.Create(this, 'A0G3', ABILITY_TYPE_AREA, FILTER_ENEMY, "blizzard")
call this.Skills[1].SetSkillData(1750.0, 0.0, 250.0, 50.0, 20.0, 0.0)
set this.Skills[1].IsDisable = true
set this.Skills[1].IsNuke = true
// Conservation
set this.Skills[2] = AISkill.Create(this, 'A0BI', ABILITY_TYPE_AREA, FILTER_ENEMY_TANK, "clusterrockets")
call this.Skills[2].SetSkillData(900.0, 0.0, 300.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsDebuff = true
// Energy Leak
set this.Skills[3] = AISkill.Create(this, 'A0G5', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Darkness Sphere
set this.Skills[4] = AISkill.Create(this, 'A0G1', ABILITY_TYPE_AREA, FILTER_ENEMY_TANK, "flamestrike")
call this.Skills[4].SetSkillData(900.0, 0.0, 700.0, 0.0, 30.0, 0.0)
set this.Skills[4].IsDebuff = true
set this.Skills[4].IsDisable = true
// Missile Battery
set this.Skills[5] = AISkill.Create(this, 'A0GB', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "berserk")
call this.Skills[5].SetSkillData(0.0, 0.0, 900.0, 0.0, 10.0, 0.0)
set this.Skills[5].IsNuke = true
endmethod
private method EarthRobotSkills takes nothing returns nothing
// Dustwave
set this.Skills[1] = AISkill.Create(this, 'A09Q', ABILITY_TYPE_TARGET_POINT, FILTER_ENEMY, "shockwave")
call this.Skills[1].SetSkillData(500.0, 150.0, 175.0, 0.0, 40.0, 0.0)
set this.Skills[1].IsEscape = true
set this.Skills[1].IsNuke = true
// Granitic Defense
set this.Skills[2] = AISkill.Create(this, 'A09S', ABILITY_TYPE_INSTANT, FILTER_NULL, "berserk")
call this.Skills[2].SetSkillData(0.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsBuff = true
set this.Skills[2].IsHealBuff = true
set this.Skills[2].BuffOnlySelf = true
// Transparent Armor
set this.Skills[3] = AISkill.Create(this, 'A08I', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Earthquake
set this.Skills[4] = AISkill.Create(this, 'A09R', ABILITY_TYPE_AREA, FILTER_ENEMY_GROUND_UNIT, "earthquake")
call this.Skills[4].SetSkillData(1000.0, 0.0, 500.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
set this.Skills[4].IsDisable = true
set this.Skills[4].IsChanneling = true
// Tank Cannon
// No need for a struct here
endmethod
private method SkyTankSkills takes nothing returns nothing
// Flamestrike
set this.Skills[1] = AISkill.Create(this, 'A01P', ABILITY_TYPE_AREA, FILTER_ENEMY_GROUND_UNIT, "flamestrike")
call this.Skills[1].SetSkillData(1200.0, 0.0, 250.0, 0.0, 40.0, 0.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsChanneling = true
// Lightning Quake
set this.Skills[2] = AISkill.Create(this, 'A0C0', ABILITY_TYPE_AREA, FILTER_ENEMY_GROUND_UNIT, "clusterrockets")
call this.Skills[2].SetSkillData(600.0, 0.0, 350.0, 0.0, 30.0, 0.0)
set this.Skills[2].IsNuke = true
// Lord of the Sky
set this.Skills[3] = AISkill.Create(this, 'A09Z', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Energy Bomb
set this.Skills[4] = AISkill.Create(this, 'A049', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY, "shadowstrike")
call this.Skills[4].SetSkillData(700.0, 0.0, 300.0, 0.0, 50.0, 0.0)
set this.Skills[4].IsNuke = true
// Tank Cannon
// No need for a struct here
endmethod
private method HunterSkills takes nothing returns nothing
// Main Gun
set this.Skills[1] = AISkill.Create(this, 'A0AG', ABILITY_TYPE_AREA, FILTER_ENEMY, "healingspray")
call this.Skills[1].SetSkillData(2000.0, 0.0, 400.0, 0.0, 40.0, 0.0)
set this.Skills[1].IsNuke = true
// Acid Cloud
set this.Skills[2] = AISkill.Create(this, 'A0A0', ABILITY_TYPE_AREA, FILTER_ENEMY_GROUND_UNIT, "clusterrockets")
call this.Skills[2].SetSkillData(1200.0, 0.0, 450.0, 0.0, 32.0, 0.0)
set this.Skills[2].IsDisable = true
// Bounty Hunter
set this.Skills[3] = AISkill.Create(this, 'A0AH', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Gravity Grenade
set this.Skills[4] = AISkill.Create(this, 'A094', ABILITY_TYPE_AREA, FILTER_ENEMY_TANK, "flamestrike")
call this.Skills[4].SetSkillData(1200.0, 0.0, 500.0, 0.0, 50.0, 0.0)
set this.Skills[4].IsDisable = true
set this.Skills[4].IsDangerous = true
// Tank Cannon
// No need for a struct here
endmethod
private method DemonTankSkills takes nothing returns nothing
// Lava Shot
set this.Skills[1] = AISkill.Create(this, 'A01D', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "thunderbolt")
call this.Skills[1].SetSkillData(1500.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsDisable = true
// Banish
set this.Skills[2] = AISkill.Create(this, 'A0B3', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_AIR_TANK, "cripple")
call this.Skills[2].SetSkillData(900.0, 0.0, 0.0, 0.0, 30.0, 0.0)
set this.Skills[2].IsDisable = true
// Demon Fire
set this.Skills[3] = AISkill.Create(this, 'A04G', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Hell Implosion
set this.Skills[4] = AISkill.Create(this, 'A02H', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "shockwave")
call this.Skills[4].SetSkillData(0.0, 0.0, 500.0, 0.0, 30.0, 0.0)
set this.Skills[4].IsNuke = true
// Tank Cannon
// No need for a struct here
endmethod
private method FrostRobotSkills takes nothing returns nothing
// Ice Prison
set this.Skills[1] = AISkill.Create(this, 'A0E0', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "channel")
call this.Skills[1].SetSkillData(1200.0, 0.0, 0.0, 0.0, 30.0, 0.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsDisable = true
// Frost Bombs
set this.Skills[2] = AISkill.Create(this, 'A03B', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "fanofknives")
call this.Skills[2].SetSkillData(0.0, 0.0, 750.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsNuke = true
// Arctic Aura
set this.Skills[3] = AISkill.Create(this, 'S000', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Ice Rain
set this.Skills[4] = AISkill.Create(this, 'A04R', ABILITY_TYPE_AREA, FILTER_ENEMY, "blizzard")
call this.Skills[4].SetSkillData(1000.0, 0.0, 400.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
set this.Skills[4].IsChanneling = true
// Tank Cannon
// No need for a struct here
endmethod
private method GoliathSkills takes nothing returns nothing
// Offroad Engine
set this.Skills[1] = AISkill.Create(this, 'A02V', ABILITY_TYPE_INSTANT, FILTER_NULL, "awaken")
call this.Skills[1].SetSkillData(0.0, 0.0, 0.0, 0.0, 30.0, 0.0)
set this.Skills[1].IsBuff = true
set this.Skills[1].BuffOnlySelf = true
set this.Skills[1].IsEscape = true
// Take Aim
set this.Skills[2] = AISkill.Create(this, 'A0E1', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY_TANK, "unholyfrenzy")
call this.Skills[2].SetSkillData(1250.0, 0.0, 0.0, 0.0, 8.0, 0.0)
set this.Skills[2].IsDebuff = true
// Mobile Shields
set this.Skills[3] = AISkill.Create(this, 'A0BO', ABILITY_TYPE_INSTANT, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[3].IsBuff = true
set this.Skills[3].IsHealBuff = true
set this.Skills[3].BuffOnlySelf = true
// Devastator Shot
set this.Skills[4] = AISkill.Create(this, 'A04P', ABILITY_TYPE_TARGET_POINT, FILTER_ENEMY, "stomp")
call this.Skills[4].SetSkillData(2000.0, 0.0, 250.0, 0.0, 30.0, 0.0)
set this.Skills[4].IsNuke = true
set this.Skills[4].IsChanneling = true
// Tank Cannon
// No need for a struct here
endmethod
private method SkyFortressSkills takes nothing returns nothing
// Turbo Boost
set this.Skills[1] = AISkill.Create(this, 'A09C', ABILITY_TYPE_INSTANT, FILTER_NULL, "awaken")
call this.Skills[1].SetSkillData(0.0, 0.0, 800.0, 200.0, 40.0, 0.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsFacing = true
set this.Skills[1].IsEscape = true
// Bomb Carpet
set this.Skills[2] = AISkill.Create(this, 'A09U', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "berserk")
call this.Skills[2].SetSkillData(0.0, 0.0, 500.0, 0.0, 30.0, 0.0)
set this.Skills[2].IsNuke = true
set this.Skills[2].IsDangerous = true
// Fortified Armor
set this.Skills[3] = AISkill.Create(this, 'A09J', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// System Overload
set this.Skills[4] = AISkill.Create(this, 'A09E', ABILITY_TYPE_TARGET_UNIT, FILTER_ENEMY, "magicleash")
call this.Skills[4].SetSkillData(425.0, 75.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsDisable = true
set this.Skills[4].IsChanneling = true
// Tank Cannon
// No need for a struct here
endmethod
private method InfernalRobotSkills takes nothing returns nothing
// Chaos Teleport
set this.Skills[1] = AISkill.Create(this, 'A04L', ABILITY_TYPE_AREA, FILTER_ENEMY, "clusterrockets")
call this.Skills[1].SetSkillData(1500.0, 0.0, 350.0, 0.0, 40.0, 0.0)
set this.Skills[1].IsNuke = true
set this.Skills[1].IsDisable = true
set this.Skills[1].IsEscape = true
// Chaos Wave
set this.Skills[2] = AISkill.Create(this, 'A03E', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "fanofknives")
call this.Skills[2].SetSkillData(0.0, 0.0, 700.0, 0.0, 40.0, 0.0)
set this.Skills[2].IsNuke = true
// Chaos Servants
set this.Skills[3] = AISkill.Create(this, 'A02C', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[3].IsBuff = true
// Infernal Fire Rain
set this.Skills[4] = AISkill.Create(this, 'A08Y', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "stomp")
call this.Skills[4].SetSkillData(0.0, 0.0, 900.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsNuke = true
// Tank Cannon
// No need for a struct here
endmethod
private method TitanSkills takes nothing returns nothing
// Build Obelisk
set this.Skills[1] = AISkill.Create(this, 'A0C6', ABILITY_TYPE_TARGET_POINT, FILTER_NULL, "ambush")
call this.Skills[1].SetSkillData(600.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[1].IsBuilding = true
// Orbital Strike
set this.Skills[2] = AISkill.Create(this, 'A0C7', ABILITY_TYPE_AREA, FILTER_ENEMY, "flamestrike")
call this.Skills[2].SetSkillData(1600.0, 0.0, 250.0, 0.0, 30.0, 0.0)
set this.Skills[2].IsNuke = true
set this.Skills[2].IsDisable = true
// Devil Fire
set this.Skills[3] = AISkill.Create(this, 'A08V', ABILITY_TYPE_INSTANT, FILTER_ENEMY, "")
call this.Skills[3].SetSkillData(0.0, 0.0, 900.0, 0.0, 40.0, 0.0)
set this.Skills[3].IsNuke = true
// Keep on Fighting
set this.Skills[4] = AISkill.Create(this, 'A0CI', ABILITY_TYPE_TARGET_UNIT, FILTER_ALLY, "spellshield")
call this.Skills[4].SetSkillData(800.0, 0.0, 0.0, 0.0, 40.0, 0.0)
set this.Skills[4].IsBuff = true
set this.Skills[4].IsHealBuff = true
// Unstable Projectiles
set this.Skills[5] = AISkill.Create(this, 'A08J', ABILITY_TYPE_PASSIVE, FILTER_NULL, "")
call this.Skills[5].SetSkillData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
set this.Skills[5].IsBuff = true
endmethod
method InitiateSkillsStruct takes unit tank returns nothing
local integer Id = GetUnitTypeId(tank)
if ( Id == 'H01L' ) then
call ScoutSkills()
elseif ( Id == 'H009' ) then
call LightTankSkills()
elseif ( Id == 'H008' ) then
call HelicopterSkills()
elseif ( Id == 'H00X' ) then
call AntiGravSkills()
elseif ( Id == 'H017' ) then
call MedivacSkills()
elseif ( Id == 'H02J' ) then
call DistributorSkills()
elseif ( Id == 'H027' ) then
call RaiderSkills()
elseif ( Id == 'H007' ) then
call DemolisherSkills()
elseif ( Id == 'H011' ) then
call GoblinShredderSkills()
elseif ( Id == 'H025' ) then
call StormTankSkills()
elseif ( Id == 'H00C' ) then
call AirShipSkills()
elseif ( Id == 'H00B' ) then
call ThunderTankSkills()
elseif ( Id == 'H00R' ) then
call GhostTankSkills()
elseif ( Id == 'H012' ) then
call GuardSkills()
elseif ( Id == 'H00D' ) then
call HeavyTankSkills()
elseif ( Id == 'H021' ) then
call ArchitectSkills()
elseif ( Id == 'H00I' ) then
call GoblinTankSkills()
elseif ( Id == 'H01U' ) then
call EarthRobotSkills()
elseif ( Id == 'H02K' ) then
call DarknessTankSkills()
elseif ( Id == 'H00E' ) then
call SkyTankSkills()
elseif ( Id == 'H01S' ) then
call HunterSkills()
elseif ( Id == 'H00F' ) then
call DemonTankSkills()
elseif ( Id == 'H00H' ) then
call FrostRobotSkills()
elseif ( Id == 'H01V' ) then
call GoliathSkills()
elseif ( Id == 'H01R' ) then
call SkyFortressSkills()
elseif ( Id == 'H00K' ) then
call InfernalRobotSkills()
elseif ( Id == 'H01I' ) then
call TitanSkills()
endif
endmethod
method Reset takes nothing returns nothing
local integer i = 1
loop
exitwhen (i > MAX_SKILLS)
if (this.Skills[i] != 0) then
call this.Skills[i].destroy()
endif
set i = i + 1
endloop
call InitiateSkillsStruct( Core.Tank )
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AICombatPosition requires MapAttachedSettings, AIFunctions
globals
constant real RATE_POS_RANGE_INC_COLLISION = 32
endglobals
struct RatePosUnitData
unit U
real x
real y
real hp
real hpChange
real curdps
real bounty
real nearbyN
real speed
real range
WeaponRanges weapons
static method create takes unit U returns RatePosUnitData
local RatePosUnitData data = RatePosUnitData.allocate()
set data.U = U
set data.weapons = -1
return data
endmethod
endstruct
function GetUnitCollisionSize takes unit U returns real
if IsUnitType( U, UNIT_TYPE_STRUCTURE ) == true then
return 72.0
elseif IsUnitType( U, UNIT_TYPE_HERO ) == true then
return 32.0
else
return 12.0
endif
endfunction
function GetGeneralBounty takes unit U returns integer
if U == udg_Tank[GetPlayerNr(GetOwningPlayer( U ) )] then
return GetBounty( U, true )
endif
return R2I(GetUnitPointValue(U) * GetBountyFactor())
endfunction
function GetUnitDps takes unit U returns real
local integer unitType = GetUnitTypeId( U )
local real dps = 0.0
if unitType == 'h000' then // Rocket Tower
set dps = 200
elseif unitType == 'h001' then // Laser Tower
set dps = 400
elseif unitType == 'h01Y' then // Protective Tower
set dps = 800
elseif unitType == 'z000' then // Marine
set dps = 40
elseif unitType == 'z001' or unitType == 'z008' then // Artillery
set dps = 45
elseif unitType == 'z002' or unitType == 'z007' then // Commander
set dps = 112
elseif unitType == 'z00D' or unitType == 'z00C' then // Zeppelin
set dps = 60
elseif unitType == 'z00Y' then // Sniper
set dps = 40
elseif unitType == 'z01F' then // Pusher
set dps = 50
endif
return dps*(1+0.1*GetPlayerTechCount( GetOwningPlayer( U ), 'R002', false ) )
endfunction
function GetUnitRange takes unit U returns real
local integer unitType = GetUnitTypeId( U )
if unitType == 'h000' then // Rocket Tower
return 1050. // 200 dps
elseif unitType == 'h001' then // Laser Tower
return 1050. // 400 dps
elseif unitType == 'h01Y' then // Protective Tower
return 1050. // 800 dps
elseif unitType == 'z000' then // Marine
return 500. // 40 dps
elseif unitType == 'z001' or unitType == 'z008' then // Artillery
return 700. // 45 dps
elseif unitType == 'z002' or unitType == 'z007' then // Commander
return 225. // 112 dps
elseif unitType == 'z00D' or unitType == 'z00C' then // Zeppelin
return 600. // 60 dps
elseif unitType == 'z00Y' then // Sniper
return 1300. // 40 dps
elseif unitType == 'z01F' then // Pusher
return 800. // 50 dps
endif
return 0.
endfunction
struct AIRatedPosition
AISituation Parent
real X
real Y
unit PrimaryTarget
real HPChange
real GoldChange
real Rating
method GetIncomingDps takes nothing returns real
// Enumerate enemies and check their DPS on this position, distributed on all units within their range
// Blur the damage by the chance of the situation to happen
// Result is damage/sec
local AISituation sit = this.Parent
local integer playerId = sit.Parent.AINr
local real incomingDPS
local integer i
local integer j
local WeaponRanges weapons
local real distSq
local real dist
local real ms
local real timestep = 1.5
local real r
local unit U
local RatePosUnitData data
set incomingDPS = 0
set i = 0
loop
exitwhen i >= sit.Enemies_N
set data = sit.Enemies[i]
set distSq = (data.x-X)*(data.x-X) + (data.y-Y)*(data.y-Y)
// Is enemy tank?
if data.weapons != -1 then
// For each weapon, calculate the damage it would deal on that given location, if the tank would move its closest range to this position
set weapons = data.weapons
// Get all weapons which endanger the rated location
set j = weapons.N - 1
set dist = SquareRoot( distSq )
loop
exitwhen j < 0
set r = weapons.Ranges[j]+RATE_POS_RANGE_INC_COLLISION-dist
if r>0 then
// Already in range
set r = 1
elseif r+data.speed*timestep>0 then
// The fraction of the timestep in range if the tank is moving
set r = 1+r/(data.speed*timestep)
endif
exitwhen r<=0
set incomingDPS = incomingDPS + r * weapons.Dps[j]
set j = j - 1
endloop
else
// Is within range?
set r = data.range+RATE_POS_RANGE_INC_COLLISION
if distSq < r*r then
set incomingDPS = incomingDPS + GetUnitDps( data.U )/(data.nearbyN+1)
endif
endif
set i = i + 1
endloop
// Healing by strategic locations
if AreCoordsInStrategicLocation( X, Y ) then
set incomingDPS = incomingDPS*0.8 - 25
endif
// Healer value
// Calculate distance to nearest CP, which should be NearCP
set U = AICore.Get(playerId).NearCP
set distSq = Pow( GetUnitX(U)-X, 2 ) + Pow( GetUnitY(U)-Y, 2 )
if distSq < AI_CP_RANGE * AI_CP_RANGE then
set incomingDPS = incomingDPS - 50 - 0.04*GetUnitState( udg_Tank[playerId], UNIT_STATE_MAX_LIFE )
endif
return incomingDPS
endmethod
method GetIncomingGoldPS takes real fightingTime returns real
// Enumerate enemies within range, the distribution of damage on them, and weigh the estimated damage with bounty
// Result is gold/sec
local AISituation sit = this.Parent
local integer playerId = sit.Parent.AINr
local real incomingGoldPS
local real tankms = GetUnitMoveSpeed( udg_Tank[playerId] )
local integer i
local integer j
local integer k
local WeaponRanges weapons
local real array unitsNearbyN
local real array weaponGoldPS
local real array weaponWeigh
local real distSq
local real dist
local real ms
local real r
local real timestep = 1.5
local unit U
local real curdps
local RatePosUnitData data
local RatePosUnitData data2
local real bestValue = 0.0
local RatePosUnitData bestUnitData = -1
set weapons = WeaponRanges.Get( playerId )
set i = 0
loop
exitwhen i >= weapons.N
set unitsNearbyN[i] = 0
set weaponGoldPS[i] = 0
set i = i + 1
endloop
// First loop over all targets and weapons to find how many units are within range for each weapon,
// then in the next run actually calculate the damage to be dealt on each unit and the resulting income
set incomingGoldPS = 0
set k = 0
loop
exitwhen k>1
set i = 0
loop
exitwhen i >= sit.Targets_N
set data = sit.Targets[i]
set curdps = 0
set distSq = (data.x-X)*(data.x-X) + (data.y-Y)*(data.y-Y)
set ms = 0
if data.U == udg_Tank[GetPlayerNr( GetOwningPlayer( data.U ) )] then
set ms = 2*data.speed-tankms
if ms<0 then
set ms = 0
endif
endif
set dist = SquareRoot( distSq )
// For each weapon
set j = weapons.N - 1
loop
exitwhen j < 0
// Calculate distance which the target could move away before the weapon stops firing
set r = weapons.Ranges[j]+RATE_POS_RANGE_INC_COLLISION-dist
// Since the ranges are sorted, the range will only get lower from here on
exitwhen r<=0
if ms>0 then
// Calculate the time it would take for the target tank to evade
set r = r/ms
if r>1 then
set r = 1
endif
else
set r = 1
endif
// Target can be shot at
// How long is the target within range, if it moves away? (only tanks move away)
// If its a tank, the healing is also to be considered, scaled by nearby firepower, since the healing may be negated by allied weapons
if k == 0 then
set unitsNearbyN[j] = unitsNearbyN[j] + r
else
set curdps = curdps + r * weapons.Dps[j] / unitsNearbyN[j]
endif
set j = j - 1
endloop
if k!=0 then
if data.hpChange<0 then
set r = curdps
else
set r = curdps - data.hpChange
endif
if r > 0 then
if data.hp / r < timestep then
// The target will die before the timestep is over,
// so the maximum dps in that period is its full hp in the timestep
set r = data.hp / timestep
endif
// The enemy hp are going down, but will it die before the own tank?
if data.hp / r > fightingTime then
// It wont die, but still, sometimes its worth to attack,
// so still keep a fraction of that income
set r = r / 3.0
endif
set r = r * data.bounty / data.hp
if r > bestValue then
set bestValue = r
set bestUnitData = data
endif
set incomingGoldPS = incomingGoldPS + r
endif
endif
set i = i + 1
endloop
set k = k + 1
endloop
if bestUnitData!=-1 then
set this.PrimaryTarget = bestUnitData.U
endif
return incomingGoldPS
endmethod
method RatePosition takes nothing returns real
local integer playerId = this.Parent.Parent.AINr
local real estimatedIncome
local real goldBeforeDeath
local real deathGoldLoss
local real fightingTime = 3600
local real respawnTime
local real incomingDPS
local real incomingGoldPS
local real tankHP = GetUnitState( udg_Tank[playerId], UNIT_STATE_LIFE )
local real progression = (3-2*udg_Player_Team[playerId])*GetTerritoryProgression( X, Y )
local integer i
local WeaponRanges weapons
local real array unitsNearbyN
local real array weaponGoldPS
local real array weaponWeigh
local real distSq
local real ms
local real r
local real timestep = 1.5
local unit U
local RatePosUnitData data
local AISituation sit = this.Parent
local unit conquerCP = sit.TargetCP
// STEP 1 : Defensive value
set incomingDPS = GetIncomingDps( )
// Calcualte the time the tank would be able to fight in this location before going to heal
if incomingDPS>0 then
set fightingTime = tankHP / incomingDPS
//set fightingTime = (tankHP - 200 - 0.4*GetUnitState( Parent.Tank, UNIT_STATE_MAX_LIFE ) ) / incomingDPS
if fightingTime<0 then
set fightingTime = 0
endif
endif
if fightingTime > 10 then
set fightingTime = 10
endif
// STEP 2 : Offensive value
set incomingGoldPS = GetIncomingGoldPS( fightingTime )
if conquerCP!=null then
set distSq = Pow( GetUnitX( conquerCP ) - X, 2 ) + Pow( GetUnitY( conquerCP ) - Y, 2 )
if distSq<AI_CP_RANGE*AI_CP_RANGE then
set incomingGoldPS = incomingGoldPS + 100
endif
endif
// Calculate time until death by incoming damage
// Result is sec
if incomingDPS>0 then
set goldBeforeDeath = incomingGoldPS * fightingTime
//set respawnTime = 10 + 2 * AICore.Get(playerId).NearCPDist / (GetUnitMoveSpeed( udg_Tank[playerId] ) + 0.01)
//set r = GetUnitState( Parent.Tank, UNIT_STATE_MAX_LIFE )
//set respawnTime = r / (50 + 0.04*r) + 2 * AICore.Get(playerId).NearCPDist / (GetUnitMoveSpeed( udg_Tank[playerId] ) + 0.01)
set respawnTime = GetRespawnTime(sit.Parent.Tank, true) + 3
// Rating is (gold before death - death gold loss) / (fighting time + respawn time)
//set estimatedIncome = (goldBeforeDeath) / (fightingTime + respawnTime)
set estimatedIncome = (goldBeforeDeath - GetBounty(udg_Tank[playerId], true) - 75) / (fightingTime + respawnTime)
else
set estimatedIncome = incomingGoldPS
endif
// STEP 3 : Position tweaking for long-term safety
// If the tank is moving too far into the enemy, subtract some gold from its income,
// so it wont prefer this position, but still use it if all positions are behind enemy lines
if progression-sit.MaxProgression > 0 then
set estimatedIncome = estimatedIncome - 1000*(progression-sit.MaxProgression)
endif
// To prevent the AI from going lone wolf, it only allows to get a certain distance from allies
set r = 5000*5000
set i = 0
loop
exitwhen i >= sit.Allies_N
set data = sit.Allies[i]
set distSq = (data.x-X)*(data.x-X) + (data.y-Y)*(data.y-Y)
if distSq < r then
set r = distSq
endif
set i = i + 1
endloop
// Since the control points are not considered regular units, but are good allies, too,
// this is checked additionally
set r = SquareRoot( r )
if AICore.Get(playerId).NearCPDist<r then
set r = sit.Parent.NearCPDist
endif
// The distance to the nearest ally is now stored in r, subtract a certain offset in which the distance
// doesn't matter
set r = r - 700
// If the distance is higher, then rate the position down the farther it is
if r > 0 then
set estimatedIncome = estimatedIncome - 0.05*r
endif
set this.HPChange = -incomingDPS
set this.GoldChange = incomingGoldPS
set this.Rating = estimatedIncome
return estimatedIncome
endmethod
static method Create takes AISituation Situation, real X, real Y returns AIRatedPosition
local AIRatedPosition rp = AIRatedPosition.allocate()
set rp.Parent = Situation
set rp.X = X
set rp.Y = Y
set rp.PrimaryTarget = null
set rp.HPChange = 0.0
set rp.GoldChange = 0.0
set rp.Rating = 0.0
call rp.RatePosition()
return rp
endmethod
endstruct
struct AISituation
RatePosUnitData array Allies[300]
RatePosUnitData array Enemies[300]
RatePosUnitData array Targets[300]
integer Allies_N
integer Enemies_N
integer Targets_N
real MaxProgression
real NearCP_X
real NearCP_Y
unit TargetCP
AICore Parent
static method Create takes AICore forAI returns AISituation
local AISituation p = AISituation.allocate()
set p.Parent = forAI
return p
endmethod
method GetMovePosition takes nothing returns AIRatedPosition
// Enumerate units in range of influence and save data
local unit Tank = Parent.Tank
local integer playerId = Parent.AINr
local group G = NewGroup()
local unit U
local player TankPlayer = GetOwningPlayer( Tank )
local real x = GetUnitX( Tank )
local real y = GetUnitY( Tank )
local real curx
local real cury
local integer unitIndex
local integer i = 0
local integer j
local integer k
local real hp
local real timestep = 1.5
local real radius = 1.5 * timestep * GetUnitMoveSpeed( Tank )
local real distSq
local real r
local real array unitsNearbyN
local real array unitsNearbyHP
local real dps
local RatePosUnitData data
local RatePosUnitData data2
local WeaponRanges weapons = WeaponRanges.Get( playerId )
local real maxRange = weapons.Ranges[weapons.N-1]
local integer lane = GetLane( x, y )
local boolean protectCP = false
local integer team = udg_Player_Team[ playerId ]
local unit conquerCP = null
local boolean array tankNearby
local string msg
local real curprog
local real bestprog
local AIRatedPosition curRatedPos
local AIRatedPosition bestRatedPos = -1
set U = Parent.NearCP
set this.NearCP_X = GetUnitX( U )
set this.NearCP_Y = GetUnitY( U )
call GroupEnumUnitsInRange( G, x, y, 2000, null )
set this.Allies_N = 0
set this.Enemies_N = 0
set this.Targets_N = 0
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
set tankNearby[i] = false
set i = i + 1
endloop
loop
set U = FirstOfGroup( G )
exitwhen U == null
set hp = GetUnitState( U, UNIT_STATE_LIFE )
if GetUnitTypeId( U ) == 'h00P' and IsUnitEnemy( U, TankPlayer ) then
set conquerCP = U
endif
if hp>0 and U!=Tank and hp<500000 and not IsUnitInvisible(U, GetPlayer(playerId)) then
// Save unit
set data = RatePosUnitData.create( U )
if IsUnitAlly( U, TankPlayer ) then
// Save as ally (to threat map)
set this.Allies[this.Allies_N] = data
set this.Allies_N = this.Allies_N + 1
else
// Save as enemy, with dps and so on
set this.Enemies[this.Enemies_N] = data
set this.Enemies_N = this.Enemies_N + 1
endif
set data.x = GetUnitX( U )
set data.y = GetUnitY( U )
set data.hp = hp
set data.hpChange = 0
set data.speed = GetUnitMoveSpeed( U )
set data.bounty = GetGeneralBounty( U )
if U == udg_Tank[GetPlayerNr(GetOwningPlayer( U ) )] then
// Increase the bounty, since the gold damage for the other team is
// also one dead tank not fighting. So a tank is a way better target than creeps with the same bounty
set data.bounty = data.bounty * 2
set tankNearby[GetPlayerNr(GetOwningPlayer( U ) )] = true
endif
if GetUnitAbilityLevel( U, 'B01V' ) > 0 then // Is healed by factory
set data.hpChange = 50 + 0.04*GetUnitState( U, UNIT_STATE_MAX_LIFE )
endif
set data.nearbyN = 0
endif
call GroupRemoveUnit( G, U )
endloop
// TODO: Take care of tanks which could teleport to nearby control points
//set conquerCP = null
if conquerCP!=null then
// Now also check, if it is a CP which can be taken over,
// for this check it is assumed that all units nearby the cp are listed already
set i = 0
set k = 0
loop
exitwhen i >= this.Enemies_N
set data = this.Enemies[i]
if data.U == udg_Tank[GetPlayerNr( GetOwningPlayer( data.U ) )] or IsUnitType( data.U, UNIT_TYPE_STRUCTURE ) then
// Strong enemy found
set distSq = Pow( GetUnitX( conquerCP ) - data.x, 2 )+Pow( GetUnitY( conquerCP ) - data.y, 2 )
if distSq < AI_CP_RANGE * AI_CP_RANGE then
set k = 1
exitwhen true
endif
endif
set i = i + 1
endloop
set i = 1
loop
exitwhen i > GetMaxHumanPlayers()
set U = udg_Tank[i]
if (not tankNearby[i]) and udg_Player_Team[i]!=team and U!=null and GetUnitState( U, UNIT_STATE_LIFE )>0.0 then
set udg_Filter_Player = GetPlayer(i)
call GroupEnumUnitsInRange(G, GetUnitX(U), GetUnitY(U), 500, FILTER_VALID_CPTP_SOURCE)
if FirstOfGroup(G) != null or Get_CP_Teleport_Msg_CoordsInBase( GetUnitX(U), GetUnitY(U), U ) then
// Can teleport
// Save as enemy, with dps and so on, but without bounty
set data = RatePosUnitData.create( U )
set this.Enemies[this.Enemies_N] = data
set this.Enemies_N = this.Enemies_N + 1
set data.x = GetUnitX( conquerCP )
set data.y = GetUnitY( conquerCP )
set data.hp = hp
set data.speed = GetUnitMoveSpeed( U )
set data.hpChange = 50 + 0.04*GetUnitState( U, UNIT_STATE_MAX_LIFE )
set data.bounty = 0
set data.nearbyN = 0
endif
endif
set i = i + 1
endloop
if k==1 then
// The control point is protected, there is no need to stand next to it
set conquerCP = null
endif
endif
// For each enemy, find all allies within range and estimate the protection they grant
set i = 0
loop
exitwhen i >= this.Enemies_N
// Do
set data = this.Enemies[i]
if data.U == udg_Tank[GetPlayerNr( GetOwningPlayer( data.U ) )] then
// For each weapon, calculate the damage it would deal on that given location, if the tank would move its closest range to this position
set weapons = WeaponRanges.Get( GetPlayerNr( GetOwningPlayer( data.U ) ) ).Copy()
set data.weapons = weapons
set data.range = weapons.Ranges[weapons.N-1]
// Reset counted units within range for every weapon, also calculate total dps
set j = 0
set dps = 0
loop
exitwhen j >= weapons.N
set unitsNearbyN[j] = 0
set unitsNearbyHP[j] = 0
set dps = dps + weapons.Dps[j]
set j = j + 1
endloop
if dps>0 then
// Loop through nearby allies and check whether they can be attacked by any weapon
set k = 0
loop
exitwhen k >= this.Allies_N
set data2 = this.Allies[k]
set distSq = (data2.x-data.x)*(data2.x-data.x) + (data2.y-data.y)*(data2.y-data.y)
set j = weapons.N - 1
loop
exitwhen j < 0 or (weapons.Ranges[j]+RATE_POS_RANGE_INC_COLLISION)*(weapons.Ranges[j]+RATE_POS_RANGE_INC_COLLISION) <= distSq
// Target can be shot at
// How long is the target within range, if it moves away? (only tanks move away)
// If its a tank, the healing is also to be considered, scaled by nearby firepower, since the healing may be negated by allied weapons
set unitsNearbyN[j] = unitsNearbyN[j] + 1
set unitsNearbyHP[j] = unitsNearbyHP[j] + data2.hp
set j = j - 1
endloop
set k = k + 1
endloop
// TODO: Find a better way to know how long the protection will survive
// For now, use total dps on total hp in the maximum range
// The time then is
set r = unitsNearbyHP[weapons.N-1] / dps
// Assuming the protection behaves linearly, at the end of the frame it will only be:
// Now average it over the timestep
if r>timestep then
set r = 0.5*(2 - (timestep / r))
else
set r = 0.5*( r / timestep )
endif
set j = weapons.N - 1
loop
exitwhen j < 0
// Calculate the dps which will arrive at the rated location, distributed on all other nearby units
set data.weapons.Dps[j] = data.weapons.Dps[j] / (unitsNearbyN[j]*r + 1)
set j = j - 1
endloop
endif
else
set r = GetUnitRange( data.U )
set data.range = r
if r>0 then
set j = 0
loop
exitwhen j >= this.Allies_N
set data2 = this.Allies[j]
set distSq = (data.x-data2.x)*(data.x-data2.x) + (data.y-data2.y)*(data.y-data2.y)
// Is within range?
if distSq<r*r then
set data.nearbyN = data.nearbyN + 1
endif
set j = j + 1
endloop
endif
endif
// Now check if it is possible to attack that unit
set distSq = (data.x-x)*(data.x-x)+(data.y-y)*(data.y-y)
if distSq < (maxRange+RATE_POS_RANGE_INC_COLLISION+radius)*(maxRange+RATE_POS_RANGE_INC_COLLISION+radius) then
set this.Targets[this.Targets_N] = data
set this.Targets_N = this.Targets_N + 1
endif
// Now also check if its near the allied cp, to know if the tank has to defend it,
// note that right now it also defends against creeps, which is not necessary, but should not be a problem either
set protectCP = protectCP or (data.x-this.NearCP_X)*(data.x-this.NearCP_X) + (data.y-this.NearCP_Y)*(data.y-this.NearCP_Y)<=700*700
set i = i + 1
endloop
call ReleaseGroup( G )
set G = null
// Check how far the tank is allowed to drive, by getting the border of enemy territory
set bestprog = 1.0
// Progression multiplier for the team, team2: -1, team1: +1
set r = 3-2*team
// First, check all enemy CPs on the current lane
set i = ThreatMap.CPs_Begin[3-team]
loop
exitwhen i>ThreatMap.CPs_End[3-team]
set U = ThreatMap.Units[i]
set curx = GetUnitX ( U )
set cury = GetUnitY ( U )
if GetLane( curx, cury ) == lane or lane == AI_LANE_UNKNOWN then
set curprog = r*GetTerritoryProgression( curx, cury )
if curprog<bestprog then
set bestprog = curprog
endif
endif
set i = i + 1
endloop
// Then, check enemy tanks
set i = 1
loop
exitwhen i>GetMaxHumanPlayers()
if udg_Player_Team[i]!=team and udg_Tank[i]!=null and GetUnitState( udg_Tank[i], UNIT_STATE_LIFE )>0.0 then
set curx = GetUnitX ( udg_Tank[i] )
set cury = GetUnitY ( udg_Tank[i] )
if GetLane( curx, cury ) == lane or lane == AI_LANE_UNKNOWN then
set curprog = r*GetTerritoryProgression( curx, cury )
if curprog<bestprog then
set bestprog = curprog
endif
endif
endif
set i = i + 1
endloop
// This is the maximum progression of any enemy on that lane
set this.MaxProgression = bestprog
// Check some positions and find the best one
// by calling RateMovePosition
// TODO: Follow the gradient to a local maximum, but block the path if there is a cliff?
// Right now, brute force search
if protectCP then
// We need to protect the CP, so we might as well just look for the best position around that CP
set x = this.NearCP_X
set y = this.NearCP_Y
set radius = AI_CP_RANGE
endif
set curx = x
set cury = y
if conquerCP!=null then
set curx = GetUnitX( conquerCP )
set cury = GetUnitY( conquerCP )
set this.TargetCP = conquerCP
endif
set i = 0
loop
exitwhen i>20
set curRatedPos = AIRatedPosition.Create( this, curx, cury )
if bestRatedPos==-1 or curRatedPos.Rating>bestRatedPos.Rating then
if bestRatedPos!=-1 then
call bestRatedPos.destroy()
endif
set bestRatedPos = curRatedPos
else
call curRatedPos.destroy()
endif
loop
set curx = x + radius*GetRandomReal(-1,1)
set cury = y + radius*GetRandomReal(-1,1)
exitwhen (curx-x)*(curx-x)+(cury-y)*(cury-y)<=radius*radius and (IsUnitType( udg_Tank[playerId], UNIT_TYPE_FLYING ) or IsTerrainWalkable(curx, cury))
endloop
set i = i + 1
endloop
// Cleanup
set i = 0
loop
exitwhen i >= this.Enemies_N
set data = this.Enemies[i]
if data.weapons!=-1 then
call data.weapons.destroy()
endif
call data.destroy()
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= this.Allies_N
set data = this.Allies[i]
if data.weapons!=-1 then
call data.weapons.destroy()
endif
call data.destroy()
set i = i + 1
endloop
return bestRatedPos
endmethod
endstruct
function GetMovePosition takes integer playerId returns location
local AISituation p = AISituation.Create( AICore.Get(playerId) )
local AIRatedPosition pos = p.GetMovePosition()
local real x = pos.X
local real y = pos.Y
set AICore.Get(playerId).Behaviour.Target = pos.PrimaryTarget
call pos.destroy()
call p.destroy()
return Location( x, y )
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AICombat requires AIFunctions, AIGroupConditions, AICombatPosition
struct AICombat
// Subclass of AI to contain all shop-related functionality
public AICore Parent
// Struct of the tanks weapons
public WeaponRanges Weapons
// Data used to interpolate the target position
public unit LastTarget
public location LastTargetLoc
static method Create takes AICore source returns AICombat
local AICombat sub = AICombat.allocate( )
set sub.Parent = source
set sub.Weapons = WeaponRanges.Get( source.AINr )
set sub.LastTargetLoc = Location(0,0)
set sub.LastTarget = null
return sub
endmethod
static method RestrictLocationNearCP takes location TargetLoc, unit CP returns nothing
// Moves TargetLoc within range of CP
local real cpX = GetUnitX(CP)
local real cpY = GetUnitY(CP)
local real dX = GetLocationX(TargetLoc)-cpX
local real dY = GetLocationY(TargetLoc)-cpY
local real distSq = dX*dX+dY*dY
local real r
// Is out of range
if distSq>AI_CP_RANGE*AI_CP_RANGE then
// Move to exact range
set r = AI_CP_RANGE/(SquareRoot(distSq)+0.001)
call MoveLocation(TargetLoc,cpX+dX*r,cpY+dY*r)
endif
endmethod
method Attack takes nothing returns nothing
// TODO: Still from the old AI, rewrite for general targets, not only a single specific one
// Choose best target - try to aquire equal lane distribution
// Try to conquer all CPs, after that attack the base
// Check if it's the right time to use your skills or combos
local integer Id = Parent.AINr
local unit Target = Parent.Behaviour.Target
local real TankX = GetUnitX(Parent.Tank)
local real TankY = GetUnitY(Parent.Tank)
local string CurrentOrder = OrderId2String(GetUnitCurrentOrder(Parent.Tank))
local location targetLoc = null
local location moveLoc = null
local unit U = null
local ThreatGroup gd = 0
local boolean needToBeFast = false
local boolean port = false
local unit conquerCP = null
local real TargetDist = 10000000.0
local real r = 0.0
local real dx
local real dy
local real len
local integer i
set ActiveAI = Id
call GroupEnumUnitsInRange(udg_TempGroup, TankX,TankY, AI_TARGET_ACQUISITION_RANGE, Condition(function IsValidNearbyTarget2))
if FirstOfGroup(udg_TempGroup) != null then
set Target = GetClosestUnitFromGroup( udg_TempGroup, TankX, TankY )
endif
if Target==null then
// We have no target, so what to do?
call Parent.Behaviour.SetImmediateOrder( AI_ORDER_UNKNOWN )
return
endif
// Get the target location
set targetLoc = GetUnitLoc( Target )
// Order the tank to that position, eventually use a teleport if it seems useful
// Note, that the target is actually the target unit, so even if the AI is in heal mode,
// it tries to CPTP to the actual offensive unit,
// so we disable CPTP, if the unit has very low HP. (Do not teleport to protect allied CPs then)
if Parent.CurrentLife > AI_START_HEAL_PERCENT then
// Try to teleport
set moveLoc = AIUseCPTP( Parent.AINr, targetLoc, needToBeFast )
call RemoveLocation( targetLoc )
else
set moveLoc = targetLoc
endif
set targetLoc = null
if moveLoc!=null then
// Get a good move position, that is, do not simply drive to the target, but check
// nearby enemies and so on and decide where to go
set r = SquareRoot( Pow( GetLocationX( moveLoc )-TankX, 2 ) + Pow( GetLocationY( moveLoc )-TankY, 2 ) )
if r < 1300 then
set moveLoc = GetMovePosition( Parent.AINr )
else
if IsUnitEnemy(Target,Parent.Owner)==true then
set r = 1200.0
else
set r = 200.0
endif
// Now get a position with distance r to moveLoc, in a direction
// which should be the "normal" attack direction at that position
set i = 1
if GetLocationX( moveLoc )+GetLocationY( moveLoc )+512.0>0.0 then
// Light force side
set i = 2
endif
set U = udg_HQ[i]
if udg_Player_Team[Id]==i then
set r = -r
endif
set dx = GetLocationX( moveLoc ) - GetUnitX( U )
set dy = GetLocationY( moveLoc ) - GetUnitY( U )
set len = SquareRoot( dx*dx + dy*dy )
if len>1.0 then
set dx = dx/len
set dy = dy/len
endif
call MoveLocation( moveLoc, GetLocationX( moveLoc ) + dx*r, GetLocationY( moveLoc ) + dy*r )
endif
// If the AI wants to heal and is next to a CP, make sure it does not leave that area,
// however if the AI is not yet there, let AIGetMovePosition() guide it there.
if Parent.Behaviour.Order == AI_ORDER_HEAL and Parent.NearCPDist<=AI_CP_RANGE then
call RestrictLocationNearCP( moveLoc, Parent.NearCP )
endif
call IssuePointOrderLoc(Parent.Tank, "move", moveLoc )
// Right after the actual order, maybe overwrite that order by casting a spell
// Only, if the tank does not CP-Teleport
//call AIUseSkills( )
// there are some cases, where a unit will not stop the casting process on its own for several seconds, more or less making it immobile
// with this, those castings will be stopped (with the 'false' parameter channeling spells will not be interupted)
call Parent.Skills.AbortCasting(false)
if GetRandomInt(0,2)==1 then
call Parent.Skills.WantsToDisable( Parent.Behaviour.Target )
else
call Parent.Skills.WantsToNuke( Parent.Behaviour.Target )
endif
if (Parent.Skills.IsCasting() == false) then
call IssuePointOrderLoc(Parent.Tank, "move", moveLoc )
endif
endif
call RemoveLocation( moveLoc )
set moveLoc = null
//set Parent.SecOrder = "Nr: " + I2S(Parent.AINr) + "|nTarget: " + GetUnitName(Target) + "|nX: " + R2S(GetUnitX(Target)) + " Y: " + R2S(GetUnitY(Target)) + "|nX2: " + R2S(GetUnitX(Parent.Tank)) + " Y2: " + R2S(GetUnitY(Parent.Tank)) + "|nX3: " + R2S(MoveX) + " Y3: " + R2S(MoveY)
set Target = null
endmethod
method MoveDirect takes location targLoc, boolean aggressiveMode returns nothing
local ThreatGroup tg = ThreatMap.GetThreatGroupCircle(Parent.PosX, Parent.PosY, 1600.0)
local real dx = GetLocationX(targLoc) - Parent.PosX
local real dy = GetLocationY(targLoc) - Parent.PosY
local real dSq = dx*dx+dy*dy
local real d = SquareRoot(dSq)
local real enemydX = tg.GetEnemyCenterX( Parent.Team ) - Parent.PosX
local real enemydY = tg.GetEnemyCenterY( Parent.Team ) - Parent.PosY
local real allydX = tg.GetAllyCenterX( Parent.Team ) - Parent.PosX
local real allydY = tg.GetAllyCenterY( Parent.Team ) - Parent.PosX
local real allydSq= allydX*allydX+allydY*allydY
local real allyRating = tg.GetAllyRating( Parent.Team )
local real enemydSq = enemydX*enemydX+enemydY*enemydY
local real enemyRating = tg.GetEnemyRating( Parent.Team )
local real additiveLen
local real dirX
local real dirY
local real dirLen
// If there are enemies nearby, we try to find a way around them.
if enemyRating>0.0 and d>0.0 and enemydSq>0.0 then
// Normalize direction
set dx=dx/d
set dy=dy/d
// Use threat map to determine path change
set enemydX = (0.9*enemyRating*enemydX-0.1*allyRating*allydX)*d/(enemydSq*(udg_TankCosts[Parent.AINr]+100.0))
set enemydY = (0.9*enemyRating*enemydY-0.1*allyRating*allydY)*d/(enemydSq*(udg_TankCosts[Parent.AINr]+100.0))
set additiveLen = SquareRoot(enemydX*enemydX+enemydY*enemydY)
// We don't want the enemy part to take the complete control, so keep it under 0.8
if additiveLen>0.8 then
set enemydX=0.8*enemydX/additiveLen
set enemydY=0.8*enemydY/additiveLen
set additiveLen=0.8
endif
// Calcualte resulting rated direction
set dirX = dx-enemydX
set dirY = dy-enemydY
// Normalize that direction
set dirLen = SquareRoot(dirX*dirX+dirY*dirY)
set dirX = dirX/dirLen
set dirY = dirY/dirLen
// Now set the target distance, use 2000.0, so that ground tanks may not get stuck in small one-ways.
// If the distance to the target is less than 2000.0, we use the distance to the target instead.
if d>2000.0 then
set d = 2000.0
endif
set dx = dirX*d
set dy = dirY*d
endif
if Parent.ItemTeleporter!=null and d>1000.0 then
call UnitUseItemPoint(Parent.Tank,Parent.ItemTeleporter,GetLocationX(targLoc),GetLocationY(targLoc))
endif
call IssuePointOrder(Parent.Tank, "move", Parent.PosX+dx, Parent.PosY+dy)
call tg.destroy()
endmethod
method Move takes location targLoc, boolean aggressiveMode returns nothing
local group g
local unit U
local real dxMove
local real dyMove
local real dMove
local real dx = GetLocationX(targLoc) - Parent.PosX
local real dy = GetLocationY(targLoc) - Parent.PosY
local real dSq = dx*dx+dy*dy
local location moveLoc
// If we are there, we can do something else
// Since we do not know, if the AI wants to heal or buy, check both ranges
if (dSq<AI_SHOPPING_RANGE*AI_SHOPPING_RANGE) and (dSq<AI_CP_RANGE*AI_CP_RANGE) then
call Parent.Behaviour.SetImmediateOrder( AI_ORDER_UNKNOWN )
return
endif
// Else, we need to move to the target.
// If a CPTP is useful, get the location or execute the CPTP.
set moveLoc = AIUseCPTP( Parent.AINr, targLoc, false )
if moveLoc==null then
// CPTP started, no need to do any more stuff
return
endif
// TODO: Only check for possible targets in the way, if tank is not extremely damaged and needs to heal
set g = NewGroup()
set ActiveAI = Parent.AINr
call GroupEnumUnitsInRange( g, Parent.PosX, Parent.PosY, AI_TARGET_ACQUISITION_RANGE, function IsValidNearbyTarget2 )
if aggressiveMode then
if FirstOfGroup( g )!=null then
// Target in acquisition range, attack, and instantly change mode,
// even if the Behaviour-class does not know about it yet.
call Parent.Behaviour.SetImmediateOrder( AI_ORDER_ATTACK )
call ReleaseGroup( g )
call RemoveLocation( moveLoc )
set moveLoc = null
set U = null
call Attack( )
return
endif
else
// Set move target direction. Note that we are using the location,
// that may eventually be the near cp, and not the target itself
set dxMove = GetLocationX( moveLoc ) - Parent.PosX
set dyMove = GetLocationY( moveLoc ) - Parent.PosY
// Normalize target direction
set dMove = SquareRoot( dxMove*dxMove+dyMove*dyMove )
set dxMove = dxMove/dMove
set dyMove = dyMove/dMove
loop
set U = FirstOfGroup( g )
exitwhen U==null
set dx = GetUnitX( U ) - Parent.PosX
set dy = GetUnitY( U ) - Parent.PosY
// Check dot product between both directions.
// If it is positive, the unit is in movement direction.
if dxMove*dx+dyMove*dy>0.0 then
// In the path, normalize distance to unit
set dSq = SquareRoot(dx*dx+dy*dy)
set dx = dx/dSq
set dy = dy/dSq
if dxMove*dx+dyMove*dy>0.5 then
// The projection of the unit distance vector onto the direction vector
// is greater than 0.5, which means an angle of 60 degrees.
// Okay, this is a bad situation, since the AI wants to move to the target, but an enemy is blocking the way
// Best would be to move around the units, but that isn't easy.
// For now, just ignore the situation
//call Parent.Behaviour.SetImmediateOrder( AI_ORDER_ATTACK )
//call ReleaseGroup( g )
//call RemoveLocation( moveLoc )
//set moveLoc = null
//set U = null
//call Attack( )
//return
endif
endif
call GroupRemoveUnit( g, U )
endloop
endif
call ReleaseGroup( g )
set g = null
set U = null
// Move to moveLoc, which is either the targetloc itself, or the nearby CP
call MoveDirect( moveLoc, aggressiveMode )
call RemoveLocation( moveLoc )
set moveLoc = null
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AIBehaviour requires AIFunctions, AIGroupConditions, AIThreatMap
// This library is used to decide what the bot needs to do on a macroscopic scale.
// It calls the different combat procedures, which, in same cases, can alternate the order, too.
struct AIBehaviour
// Subclass of AI to contain all decision-making functionality
public AICore Parent
public integer Order
public unit Target
public location TargetLoc
public real OrderResetTime
public boolean HealerOrdered
public boolean CastingSpell
public AIBehaviour Secondary
static method Create takes AICore source returns AICombat
local AIBehaviour sub = AIBehaviour.allocate( )
set sub.Parent = source
set sub.OrderResetTime=-0.1
set sub.Order = AI_ORDER_UNKNOWN
set sub.Target = null
set sub.TargetLoc = Location(0.0, 0.0)
set sub.Secondary = 0
set sub.CastingSpell= false
return sub
endmethod
// Orders called from outside, for example by the global planner.
// These may later return different values, if the AI doesn't want to take that order, or is dead, etc...
method SetPointOrder takes integer orderId, real targX, real targY returns boolean
set Order = orderId
set Target= null
set OrderResetTime = -1.0
call MoveLocation(TargetLoc, targX, targY)
return true
endmethod
method SetPointOrderLoc takes integer orderId, location targLoc returns boolean
set Order = orderId
set Target= null
set OrderResetTime = -1.0
// Copy the location, so if the source location is destroyed, we still have this one.
call MoveLocation(TargetLoc, GetLocationX(targLoc), GetLocationY(targLoc))
return true
endmethod
method SetTargetOrder takes integer orderId, unit targU returns boolean
set Order = orderId
set Target= targU
set OrderResetTime = -1.0
call MoveLocation(TargetLoc, GetUnitX(targU),GetUnitY(targU) )
return true
endmethod
method SetImmediateOrder takes integer orderId returns boolean
set Order = orderId
set Target= null
set OrderResetTime = -1.0
return true
endmethod
method SetOrderResetTime takes real time returns nothing
// Resets the order to unknown after "time" seconds.
// When this is called again later, it overwrites the existant condition, so that
// it can be used to only keep a command if it's periodically assigned.
set OrderResetTime = TimerGetElapsed(udg_GameTime)+time
endmethod
method GetTargetLoc takes nothing returns location
// Returns the location where the tank is planning to go to,
// this can be useful when seperating the tanks to lanes, or checking if the AI
// already wants to defend something etc.
if Order==AI_ORDER_HEAL then
return GetUnitLoc(Parent.NearCP)
elseif Order==AI_ORDER_MOVE or Order==AI_ORDER_MOVE_ATTACK then
return Location(GetLocationX(TargetLoc),GetLocationY(TargetLoc))
endif //Order==AI_ORDER_ATTACK then
return GetUnitLoc(Parent.Tank)
endmethod
static method GetPlayerTargetLoc takes integer playerId returns location
if udg_AI_IsNewBot[playerId] then
return AICore.Get(playerId).Behaviour.GetTargetLoc()
endif
return GetUnitLoc(udg_Tank[playerId])
endmethod
method GetEmptyLane takes nothing returns integer
// This function returns a lane AI_LANE_MID, AI_LANE_BOTTOM or AI_LANE_TOP if one
// of the lanes has no ally on it. (The player itself might be already there)
// If there is no free lane, AI_LANE_UNKNOWN is returned.
local integer pid = 1
local location tankTargLoc
local boolean laneTopFree = true
local boolean laneBotFree = true
local boolean laneMidFree = true
local integer lane
loop
exitwhen pid>GetMaxHumanPlayers()
if udg_Player_Team[pid]==Parent.Team and pid!=Parent.AINr then
set tankTargLoc = AIBehaviour.GetPlayerTargetLoc(pid)
set lane = GetLane(GetLocationX(tankTargLoc),GetLocationY(tankTargLoc))
if lane==AI_LANE_TOP then
set laneTopFree = false
elseif lane==AI_LANE_BOTTOM then
set laneBotFree = false
elseif lane==AI_LANE_MID then
set laneMidFree = false
endif
call RemoveLocation(tankTargLoc)
endif
set pid = pid + 1
endloop
set tankTargLoc=null
if laneMidFree then
// Mid lane has highest priority, if it is free.
return AI_LANE_MID
endif
if laneTopFree and ((not laneBotFree) or GetRandomInt(0,1)==0) then
// Top lane is free, and bottom lane is not or top won the 50/50 chance.
return AI_LANE_TOP
elseif laneBotFree then
// Bottom lane is free
return AI_LANE_BOTTOM
endif
// No free lane
return AI_LANE_UNKNOWN
endmethod
static method PickUpHealer_Enum takes nothing returns nothing
local AICore ai
if IsItemHealer(GetEnumItem()) and GetWidgetLife(GetEnumItem())>0.0 then
set ai = AICore.Get(ActiveAI)
// Make sure the threat at the healer is less than current threat, so the AI
// does not run for healers too offensive
if ThreatMap.GetThreatDensity(GetWidgetX(GetEnumItem()), GetWidgetY(GetEnumItem()), ai.Team)<=ThreatMap.GetThreatDensity(ai.PosX, ai.PosY, ai.Team) then
set ai.Behaviour.HealerOrdered = true
call IssueTargetOrder(ai.Tank,"smart",GetEnumItem())
endif
endif
endmethod
method PickUpHealer takes nothing returns boolean
call SetRect(udg_TempRect, Parent.PosX-AI_HEALER_PICKUP_RANGE, Parent.PosY-AI_HEALER_PICKUP_RANGE, Parent.PosX+AI_HEALER_PICKUP_RANGE, Parent.PosY+AI_HEALER_PICKUP_RANGE)
set ActiveAI = Parent.AINr
set HealerOrdered = false
call EnumItemsInRect(udg_TempRect, FILTER_NULL, function AIBehaviour.PickUpHealer_Enum)
return HealerOrdered
endmethod
method Execute takes nothing returns nothing
local integer lastOrder = Order
// No matter what the tank wants to do, learn its skills:
if GetHeroSkillPoints(Parent.Tank)>0 then
call Parent.LearnNewSkill()
endif
// And pick up healers in ranger, if hp is below 90%.
if Parent.CurrentLife<70.0 then
if PickUpHealer() then
// Forget anything else, we got a healer!
return
endif
endif
if Order==AI_ORDER_HEAL then
if Parent.ItemRepair!=null then
call UnitUseItem(Parent.Tank,Parent.ItemRepair)
endif
if Parent.ItemStealth!=null then
call UnitUseItem(Parent.Tank,Parent.ItemStealth)
endif
if Parent.NearCPDist<AI_CP_RANGE then
// Already is near CP, so try to fight back
call Parent.Combat.Attack( )
else
call MoveLocation( TargetLoc, GetUnitX( Parent.NearCP ), GetUnitY( Parent.NearCP ) )
call Parent.Combat.Move( TargetLoc, false )
endif
elseif Order==AI_ORDER_MOVE then
call Parent.Combat.Move( TargetLoc, false )
elseif Order==AI_ORDER_MOVE_ATTACK then
call Parent.Combat.Move( TargetLoc, true )
else //Order==AI_ORDER_ATTACK then
if Parent.ItemTroop!=null then
call UnitUseItem(Parent.Tank,Parent.ItemTroop)
endif
if Parent.ItemMortar!=null then
call UnitUseItem(Parent.Tank,Parent.ItemMortar)
endif
call Parent.Combat.Attack( )
if Parent.ItemWard!=null then
call UnitUseItemPoint(Parent.Tank,Parent.ItemWard,Parent.PosX,Parent.PosY)
endif
endif
// TODO: If the order has changed, maybe execute the changed order, too.
if lastOrder!=Order then
// Be careful not to induce an infinite loop
endif
endmethod
method FindBestOrder takes nothing returns nothing
// This method is called, when the order is AI_ORDER_UNKNOWN,
// so the AI can find a completely new order, including buying and so on.
if Secondary!=0 then
// If there is a secondary order, move its data into this struct and
// remove the secondary order.
set OrderResetTime=Secondary.OrderResetTime
set Order = Secondary.Order
set Target = Secondary.Target
set TargetLoc = Secondary.TargetLoc
set Secondary = Secondary.Secondary
// This should be a true order, so return.
return
endif
// Maybe the AI is ordered to heal now, but it can still receive new targets
if Parent.CurrentLife < AI_BORING_HEAL_PERCENT then
// If the tank has less than 90 percent of its hp, it can use this free time to heal
call SetImmediateOrder(AI_ORDER_HEAL)
else
// The CheckPlan( ) will eventually find a weapon to buy and buy it
call Parent.Shopping.CheckPlan( )
if Order==AI_ORDER_UNKNOWN then
// Nothing to buy, hp are okay, no enemy nearby, so look for a good target on the whole map,
// maybe changing the lane
set ActiveAI = Parent.AINr
call GroupEnumUnitsInRect(udg_TempGroup, udg_Playable_Map, Condition(function IsValidNearbyTarget2))
set Target = GetBestTargetFromBaseOnLane( udg_TempGroup, Parent.PosX, Parent.PosY, GetEmptyLane() )
call SetTargetOrder( AI_ORDER_MOVE_ATTACK, Target )
endif
endif
endmethod
method Check takes boolean fullCheck returns boolean
local string CurrentTankOrder
// Check if the current behaviour is still good,
// maybe change the behaviour
// If fullCheck is false only do a rough check.
set CurrentTankOrder = OrderId2String(GetUnitCurrentOrder(Parent.Tank))
// Maybe the AI still has a pilot, then it's time to buy a tank.
if GetUnitTypeId(Parent.Tank) == 'H01H' then
// Issue the command for the 'Random Tank' ability of the Pilot
call IssueImmediateOrder(Parent.Tank,"board")
call Parent.LearnNewSkill()
// No order to execute, because this was the complete order.
return false
endif
// Note that the initialization of the ai player is already done
if IsUnitPaused(Parent.Tank) or Parent.CurrentLife<=0.00 then
// AI is either dead or paused, maybe game has not even started yet
// Returning false: No Behaviour will be executed
call SetImmediateOrder(AI_ORDER_UNKNOWN)
return false
endif
if HealerOrdered then
// If the tank is currently moving to a healer, then let him go, even if the HP
// are low or anything like that, since the healer gives some HP.
// However, if the tank has the "stop" order, we need to execute the next command fast,
// since the AI could be in a bad situation, because it was running for that healer.
return not PickUpHealer()
endif
if Parent.PredictedLife < AI_START_HEAL_PERCENT and Order != AI_ORDER_HEAL then
// Critical HP, react fast
call SetImmediateOrder(AI_ORDER_HEAL)
set CastingSpell = false
return true
endif
// If it's not the full Check:
// Go on, if the order is completely unknown (target lost in last execution),
// or if the AI is currently casting a spell, since we want to get control of the AI,
// as soon as its finished casting, since it might be in a bad situation now.
if not ( fullCheck or CastingSpell or Order==AI_ORDER_UNKNOWN ) then
// Only a fast check was called, so we won't do any further investigations
return false
endif
//
// Fast Check ends here.
//
if Parent.PredictedLife > AI_START_HEAL_PERCENT and not ( CurrentTankOrder == "move" or CurrentTankOrder == "stop" or CurrentTankOrder == "smart" or CurrentTankOrder == null ) then
// The tank is casting a spell, don't move or do anything else
return false
endif
// Reset command, if this is wanted:
if OrderResetTime>0.0 and TimerGetElapsed(udg_GameTime)>OrderResetTime then
call SetImmediateOrder(AI_ORDER_UNKNOWN)
endif
//Check the criteria, which define your next behavior
if Parent.PredictedLife < AI_START_HEAL_PERCENT or (Parent.PredictedLife < AI_BORING_HEAL_PERCENT and Order == AI_ORDER_UNKNOWN) then
// We need to heal
if Order != AI_ORDER_HEAL then
// As the AI will probably not fight in the next time, it can upgrade weapons now
if Parent.Shopping.WantsWeapon( ) then
call Parent.Shopping.UpgradeWeapons( )
endif
call SetImmediateOrder(AI_ORDER_HEAL)
endif
set CastingSpell = false
return true
endif
if Order==AI_ORDER_HEAL and (Parent.CurrentLife >= AI_FINISH_HEAL_PERCENT) then
call SetImmediateOrder(AI_ORDER_UNKNOWN)
endif
if Order==AI_ORDER_UNKNOWN then
// There is no current order, so we can decide a new macro strategy
call FindBestOrder( )
endif
// Now, as we decided what to do, we can execute the order
set CastingSpell = false
return true
endmethod
endstruct
endlibrary
//TESH.scrollpos=28
//TESH.alwaysfold=0
library AICoreFunctions requires MapAttachedSettings, AIFunctions, AIGeneralFunctions, AIThreatMap, AIShopping, AICombat
globals
constant integer AI_ORDER_ATTACK = 0 // No Target, may temporarily set a target,
// fights all nearby enemies, tries to survive, eventually
// conquers or heals. May switch to unknown after healing or if no enemy is nearby.
constant integer AI_ORDER_HEAL = 1 // No Target, actually similiar to attack, but restricted to a CP
constant integer AI_ORDER_MOVE = 2 // Location Target, does not offensively fight enemies on the way,
// only if they are blocking the way
constant integer AI_ORDER_MOVE_ATTACK=3 // Location Target, moves to a target and engages enemies on the way,
// switches to attack mode, as soon as an enemy is seen
constant integer AI_ORDER_UNKNOWN = 4 // Maybe the execution of a command noticed that it is finished,
// a new behaviour can be chosen now.
// The hp percentage at which the AI wants to heal, if no enemy is nearby
constant real AI_BORING_HEAL_PERCENT = 70
// The hp percentage at which the AI stops healing
constant real AI_FINISH_HEAL_PERCENT = 95
// The hp percentage at which the AI always wants to heal.
constant real AI_START_HEAL_PERCENT = 40
// The range to look for new targets
constant real AI_TARGET_ACQUISITION_RANGE = 2500.0
// The range at which the tank is expected to be healed and able to teleport
constant real AI_CP_RANGE = 500.0
// The range at which the tank can buy items
constant real AI_SHOPPING_RANGE = 500.0
// Constants used to indentify the lanes and spread the AI out.
constant integer AI_LANE_UNKNOWN = 0
constant integer AI_LANE_TOP = 1
constant integer AI_LANE_MID = 2
constant integer AI_LANE_BOTTOM = 3
// The safety range to cp-teleport, so that the AI does no get stuck on the border
// and tries to teleport. This is the distance to the border.
constant real AI_CP_SAFETY_TOLERANCE_DIST = 100.0
// The inner scan range for threat near an attacked cp
constant real AI_CP_THREAT_RANGE_INNER = 1000.0
// The outer scan range for threat near an attacked cp
constant real AI_CP_THREAT_RANGE_OUTER = 2500.0
// The limit of range a player should move to a CP, just to defend another one
constant real AI_CP_DEFEND_RANGE_LIMIT = 4000.0
// The range at which an AI picks up any healer it finds.
constant real AI_HEALER_PICKUP_RANGE = 500.0
// Defines a span of ranges at which the AI operates.
// Smaller range spans would be better, however, the AI won't be able to move
// perfectly to that range. This is the approximate span:
constant real AI_RANGE_PRECISION = 100.0
// The AI shops by id, the actual units may differ per team
constant integer AI_SHOP_UNKNOWN = 0
constant integer AI_SHOP_WEAPONS_1 = 1
constant integer AI_SHOP_WEAPONS_2 = 2
constant integer AI_SHOP_SPIRIT = 3
constant integer AI_SHOP_MID = 4
constant integer AI_SHOP_SIDE = 5
constant integer AI_SHOP_TANKHALL = 6
constant integer AI_SHOP_TRADER = 7
constant integer AI_SHOP_RESEARCH = 8
constant integer AI_SHOP_ITEM = 9
constant integer AI_SHOP_VEHICLEFACTORY=10
// The range at which the AI does not take possible cptp-costs into account
constant real AI_SHOP_CPTP_RANGE= 3000.0
// The time in seconds after which the AI resets the random seed for buying items,
// a higher value would mean, that the AI does very rarely change its opinion,
// a lower value might cause the AI to buy a lot of low-chance items and being unable to decide what to buy.
constant real AI_SHOP_RANDOM_SEED_TIMEOUT=240.0
// Control Point Teleport Costs
constant integer AI_CPTP_COSTS = 75
AICore array AI
endglobals
struct AICore
public AIShopping Shopping
public AICombat Combat
public AIBehaviour Behaviour
public AISkillUsage Skills
public integer Team
public integer AINr
public unit Tank
public player Owner
// Nearest healer
public unit NearCP
public real NearCPDist
// Current tank location
public real PosX
public real PosY
public real CurrentStrength
public real CurrentLife
public real PredictedLife
public real LastLife
public real HPRate
public item ItemTeleporter
public item ItemTroop
public item ItemMortar
public item ItemRepair
public item ItemWard
public item ItemStealth
public item ItemFactory
public item ItemFuse
public integer ThreatLevel
public real ThreatRaw
public ThreatGroup Danger
public ThreatGroup DangerLocal
static method create takes integer nr returns AICore
local AICore ai = AICore.allocate()
set ai.AINr = nr
set ai.Tank = udg_Tank[nr]
set ai.Owner = GetPlayer(nr)
set ai.Danger = 0
set ai.DangerLocal = 0
set ai.Team = udg_Player_Team[nr]
// Create subclasses, mainly for readability
set ai.Shopping = AIShopping. Create( ai )
set ai.Combat = AICombat. Create( ai )
set ai.Behaviour= AIBehaviour.Create( ai )
set ai.Skills = AISkillUsage.Create( ai )
set AI[nr] = ai
return ai
endmethod
static method Get takes integer playerId returns AICore
return AI[playerId]
endmethod
static method AntiLeakCondition takes nothing returns boolean
return true
endmethod
method RefreshThreat takes nothing returns nothing
local real TankStrength = GetBounty(Tank, false)
// Get threat for region around tank
local ThreatGroup tg = ThreatMap.GetThreatGroupCircle(PosX, PosY, 2000)
// Get threat for region around the enemy center
local ThreatGroup tgEnemy = ThreatMap.GetThreatGroupCircle(tg.GetEnemyCenterX(Team),tg.GetEnemyCenterY(Team),2000)
// As in a fight, the units behind you are almost useless, just consider your allies near the enemy center,
// and the enemies near the allies center:
local real threatRaw = tg.GetEnemyRating(Team) - (tgEnemy.GetAllyRating(Team) * this.PredictedLife/100)
// DEBUG:
set ThreatRaw = tg.GetEnemyRating(Team) - tgEnemy.GetAllyRating(Team)
// Set ThreatLevel
if (threatRaw <= (TankStrength * -2.0)) then
set ThreatLevel = 1 // very low threat level
elseif (threatRaw <= (TankStrength * -0.75)) then
set ThreatLevel = 2 // low threat level
elseif (threatRaw <= (TankStrength * 0.75)) then
set ThreatLevel = 3 // medium threat level
elseif (threatRaw <= (TankStrength * 2.0)) then
set ThreatLevel = 4 // high threat level
elseif (threatRaw > (TankStrength * 2.0)) then
set ThreatLevel = 5 // very high threat level
endif
call tg.destroy( )
call tgEnemy.destroy( )
endmethod
method GetRandomTank takes nothing returns unit
local unit tank = BuyRandomStartTank(Owner)
set this.Tank = tank
return tank
endmethod
method AIHasTeleporter takes nothing returns item
local integer i = 0
local item TempItem = null
loop
exitwhen i > 5
set TempItem = UnitItemInSlot(this.Tank, i)
if TempItem != null then
if IsTeleporter(TempItem) then
set i = 6
else
set TempItem = null
endif
endif
set i = i + 1
endloop
return TempItem
endmethod
method LearnNewSkill takes nothing returns nothing
call LearnSkills( Tank )
endmethod
method RefreshPosition takes nothing returns nothing
set PosX = GetUnitX( Tank )
set PosY = GetUnitY( Tank )
endmethod
method RefreshNearCP takes nothing returns nothing
// Requires PosX and PosY to be up to date
// Use the listed healers from the ThreatMap:
local integer i = ThreatMap.Healers_Begin[Team]
local integer iEnd = ThreatMap.Healers_End[Team]
local real dx
local real dy
local real closestdSq = 0.0
local real currentdSq
local unit closestU = null
// Loop through all allied healers and find the closest one
loop
exitwhen i>iEnd
set dx = GetUnitX(ThreatMap.Units[i])-PosX
set dy = GetUnitY(ThreatMap.Units[i])-PosY
set currentdSq = dx*dx+dy*dy
if closestU==null or currentdSq<closestdSq then
set closestdSq = currentdSq
set closestU = ThreatMap.Units[i]
endif
set i = i + 1
endloop
set NearCP = closestU
set NearCPDist = SquareRoot(closestdSq)
set closestU = null
endmethod
method RefreshLife takes nothing returns nothing
local real life
// Get current hp percent
set life = GetUnitLifePercent(Tank)
set CurrentLife = life
set HPRate = CurrentLife-LastLife
// Predict HP
set PredictedLife = CurrentLife+1.5*HPRate
// Save the current real hp state, so the AI can get its true hp rate
set LastLife = life
set CurrentStrength = GetUnitLifePercent(Tank) * GetBounty(Tank, false) / 100
endmethod
method RefreshItems takes nothing returns nothing
// TODO: Implement
local integer i = 0
local item SlotItem
local integer itemType
set ItemTeleporter = null
set ItemTroop = null
set ItemMortar = null
set ItemRepair = null
set ItemWard = null
set ItemStealth = null
set ItemFactory = null
set ItemFuse = null
loop
exitwhen i>5
set SlotItem = UnitItemInSlot(Tank,i)
if SlotItem!=null and (GetItemType(SlotItem)!=ITEM_TYPE_ARTIFACT) then
set itemType=GetItemTypeId(SlotItem)
if IsTeleporter(SlotItem) then
set ItemTeleporter = SlotItem
// advanced troop-command, troop-command, reinforcement
elseif (itemType-'I053')*(itemType-'I00Y')*(itemType-'I013')==0 then
set ItemTroop = SlotItem
// siege pack, mortar team
elseif (itemType-'I04B')*(itemType-'I04X')==0 then
set ItemMortar = SlotItem
// extended repair kit, power pack, repair kit, strength pack
elseif (itemType-'I00P')*(itemType-'I011')*(itemType-'I00O')*(itemType-'I052')==0 then
set ItemRepair = SlotItem
// heavy mines, huges mines, mines, teleport breaker, detector
elseif (itemType-'I009')*(itemType-'I04E')*(itemType-'I015')*(itemType-'I04P')*(itemType-'I03F')==0 then
set ItemWard = SlotItem
// concealing engine, smoke generator
elseif (itemType-'I05P')*(itemType-'I00U')==0 then
set ItemStealth = SlotItem
// factory
elseif (itemType-'I00Z')==0 then
set ItemFactory = SlotItem
// mine defuse pack, remote fuse
elseif (itemType-'I04R')*(itemType-'I02K')==0 then
set ItemFuse = SlotItem
endif
endif
set i = i + 1
endloop
endmethod
method InitSituation takes boolean fullInit returns nothing
// If the AI changes the tank, the AICore.Tank variable might not be refreshed,
// so do it here.
local boolean tankChanged = Tank!=udg_Tank[AINr]
if tankChanged then
set this.Tank = udg_Tank[AINr]
call this.Skills.Reset()
endif
call RefreshPosition( )
call RefreshLife( )
if CurrentLife<=0.0 or not fullInit then
// The most important things are done, only continue if you want a full initialization
return
endif
call RefreshItems( )
call RefreshNearCP( )
call RefreshThreat( )
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope AILoop initializer Init
globals
integer ActiveAI = 1
integer TmpAI //to be used for static method calls outside of the combat trigger loop
endglobals
function Trig_AI_Loop_Actions takes nothing returns nothing
local integer SecBot = SecIndex.Inc()
// Set the next bot
set ActiveAI = PrimIndex.Inc()
// every primary orders are performed here
if udg_AI_IsNewBot[ActiveAI] then
// Initializes the situation, checks if the behaviour is correct,
// and then executes the chosen behaviour
call AI[ActiveAI].InitSituation( true )
if AI[ActiveAI].Behaviour.Check( true ) then
// There is a behaviour to execute, so do it
call AI[ActiveAI].Behaviour.Execute( )
// If the AI has lost its order, try it again
if AI[ActiveAI].Behaviour.Order==AI_ORDER_UNKNOWN then
if AI[ActiveAI].Behaviour.Check( false ) then
call AI[ActiveAI].Behaviour.Execute( )
endif
endif
endif
endif
// check if it's necessary to heal or adjust your own position otherwise
if udg_AI_IsNewBot[SecBot] then
// Initializes parts of the situation, so a fast check can be done,
// then checks if the behaviour changes
call AI[SecBot].InitSituation( false )
if AI[SecBot].Behaviour.Check( false ) then
// There is a behaviour to execute, so initialize the situation completely
// and execute the behaviour
call AI[SecBot].InitSituation( true )
call AI[SecBot].Behaviour.Execute( )
endif
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set gg_trg_AI_Loop = CreateTrigger( )
call TriggerAddAction( gg_trg_AI_Loop, function Trig_AI_Loop_Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
globals
boolean udg_AI2_Initialized = false
endglobals
function AI_Init_Actions takes nothing returns nothing
if udg_AI2_Initialized then
return
endif
set udg_AI2_Initialized = true
set PrimIndex = Index.Create(1, GetMaxHumanPlayers(), 1)
set SecIndex = Index.Create(1,GetMaxHumanPlayers(), R2I(GetMaxHumanPlayers()/2))
call TriggerRegisterTimerEventPeriodic(gg_trg_AI_Loop, 0.10 )
endfunction
//===========================================================================
function InitTrig_AI_Init takes nothing returns nothing
set gg_trg_AI_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_AI_Init, function AI_Init_Actions )
endfunction