//TESH.scrollpos=0
//TESH.alwaysfold=0
function EnableScriptUsage takes nothing returns nothing
endfunction
// Map header custom code
// SimError by Vexorian at wc3c.net
// Sim Error (modified)
function CSS_SimError takes string s returns nothing
local string msg = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00" + s + "|r"
local player ForPlayer = GetTriggerPlayer()
local sound error = CreateSoundFromLabel("InterfaceError", false, false, false, 10, 10)
if GetLocalPlayer() == ForPlayer then
call ClearTextMessages()
call DisplayTimedTextToPlayer(ForPlayer, 0.52, 0.96, 2.00, msg)
call StartSound(error)
endif
set ForPlayer = null
endfunction
function CSS_SimNotification takes string s returns nothing
local string msg = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cff32cd32" + s + "|r"
local player ForPlayer = GetTriggerPlayer()
local sound notify = CreateSoundFromLabel("ItemReward", false, false, false, 10, 10)
if GetLocalPlayer() == ForPlayer then
call ClearTextMessages()
call DisplayTimedTextToPlayer(ForPlayer, 0.52, 0.96, 2.00, msg)
call StartSound (notify)
endif
set ForPlayer = null
endfunction
// Bound Int by Magtheridon96 at hiveworkshop.com
// BoundInt
function BoundInt takes integer i, integer min, integer max returns integer
return IMaxBJ(IMinBJ(i, max), min)
endfunction
// Bonus Handling Code
function CSS_AddBonus takes unit u, integer amount, integer bonusType returns nothing
local integer max = udg_CSS_Power[17]
local integer min = -udg_CSS_Power[17]
local integer i = 16
local integer j = LoadInteger (udg_CSS_Hashtable, GetHandleId(u), bonusType)
if amount > max - 1 or amount < min then
call CSS_SimError ("Value too high or too low")
return
endif
if amount + j >= max or amount + j <= min then
call CSS_SimError ("Current value at maximum or minimum")
return
endif
set amount = amount + j
call BoundInt (amount, min, max - 1)
if bonusType < 0 or bonusType > 10 then
call CSS_SimError ("CSS Error: Invalid bonus type (" + I2S(bonusType) + ")")
return
elseif bonusType == 8 or bonusType == 9 then
if bonusType == 8 and amount*1. + GetUnitState(u, UNIT_STATE_MAX_LIFE) <= 0 then
call CSS_SimError ("Unit's current max life is lower than the negative bonus amount. Unable to subtract.")
return
elseif bonusType == 9 and amount*1. + GetUnitState(u, UNIT_STATE_MAX_MANA) <= 0 then
call CSS_SimError ("Unit's current max mana is lower than the negative bonus amount. Unable to subtract.")
return
endif
call SaveInteger(udg_CSS_Hashtable, GetHandleId(u), bonusType, amount)
if amount < 0 then
set amount = max + amount
else
call UnitRemoveAbility(u, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
endif
loop
if amount >= udg_CSS_Power[i] then
call UnitAddAbility(u, udg_CSS_Abilities[bonusType*18 + i])
call UnitMakeAbilityPermanent(u, true, udg_CSS_Abilities[bonusType*18 + i])
set amount = amount - udg_CSS_Power[i]
else
call UnitRemoveAbility(u, udg_CSS_Abilities[bonusType*18 + i])
endif
set i = i - 1
exitwhen i < 0
endloop
if LoadInteger(udg_CSS_Hashtable, GetHandleId(u), bonusType) < 0 then
call UnitAddAbility(u, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
call UnitMakeAbilityPermanent(u, true, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
endif
else
call SaveInteger(udg_CSS_Hashtable, GetHandleId(u), bonusType, amount)
if amount < 0 then
set amount = max + amount
call UnitAddAbility(u, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
call UnitMakeAbilityPermanent(u, true, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
else
call UnitRemoveAbility(u, udg_CSS_Abilities[(bonusType+1)*18 - 1])
endif
loop
if amount >= udg_CSS_Power[i] then
call UnitAddAbility(u, udg_CSS_Abilities[bonusType*18 + i])
call UnitMakeAbilityPermanent(u, true, udg_CSS_Abilities[bonusType*18 + i])
set amount = amount - udg_CSS_Power[i]
else
call UnitRemoveAbility(u, udg_CSS_Abilities[bonusType*18 + i])
endif
set i = i - 1
exitwhen i < 0
endloop
endif
endfunction
Name | Type | is_array | initial_value |
CSS_Abilities | abilcode | Yes | |
CSS_Hashtable | hashtable | No | |
CSS_Power | integer | Yes | |
CSS_PreloadBoolean | boolean | No | true |
NP_AOE | real | Yes | |
NP_BuffAngle | real | Yes | |
NP_BuffNode | integer | Yes | |
NP_Caster | unit | Yes | |
NP_CurrentEffect | effect | Yes | |
NP_CurrentProductionDelay | real | Yes | |
NP_CurrentZ | real | Yes | |
NP_DuplicationChance | real | Yes | |
NP_HealthDamage | real | Yes | |
NP_InfectionDamageHealth | real | Yes | |
NP_InfectionDamageMana | real | Yes | |
NP_InfectionDuration | real | Yes | |
NP_Instance | integer | Yes | |
NP_ManaDamage | real | Yes | |
NP_MapMaxX | real | No | |
NP_MapMaxY | real | No | |
NP_MapMinX | real | No | |
NP_MapMinY | real | No | |
NP_NextNode | integer | Yes | |
NP_NodeNumber | integer | No | |
NP_Offset | real | Yes | |
NP_Player | player | Yes | |
NP_PrevNode | integer | Yes | |
NP_ProductionDelay | real | Yes | |
NP_ProjectileFlightTime | real | Yes | |
NP_ProjectileSize | real | Yes | |
NP_RecyclableNodes | integer | No | |
NP_RecycleNodes | integer | Yes | |
NP_StageID | integer | Yes | |
NP_SummonArmour | integer | Yes | |
NP_SummonAttackDamage | integer | Yes | |
NP_SummonAttackSpeed | integer | Yes | |
NP_SummonDuration | real | Yes | |
NP_SummonHealth | integer | Yes | |
NP_SummonHealthRegen | integer | Yes | |
NP_SummonLevel | integer | Yes | |
NP_SummonSize | real | Yes | |
NP_SwarmStrength | integer | Yes | |
NP_SwarmStrengthBonus | integer | Yes | |
NP_TargetSelf | boolean | Yes | |
NP_TargetX | real | Yes | |
NP_TargetY | real | Yes | |
NP_Timer | timer | No | |
NP_Unit | unit | Yes | |
NP_XVel | real | Yes | |
NP_YVel | real | Yes | |
NP_ZLoc | location | No | |
NP_ZVel | real | Yes |
//TESH.scrollpos=0
//TESH.alwaysfold=0
//************************************************************************************************************
//* *
//* CUSTOM STAT SYSTEM (CSS) *
//* *
//* Author: Doomlord *
//* Version: 1.5g *
//* *
//* Credits: *
//* + Earth-Fury: BonusMod binary algoritm; implementation macro. *
//* + Crigges: A great amount of help and support. *
//* + Geries: Help me with the item hashtable values cleanup. *
//* + rulerofiron99: Item Socketing method referenced from [GUI]Right Click Item Recipe v1.05. *
//* + Vexorian: CSS_SimError [url]http://www.wc3c.net/showthread.php?t=101260[/url] *
//* + Magtheridon96: [Snippet]BoundInt [url]http://www.hiveworkshop.com/forums/2294066-post804.html[/url] *
//* + WaterKnight: Help with the stack for custom Event Response. *
//* + PurgeandFire: Pinpoint a possible desync bug with the system. *
//* + Nestharus: Mentioning the possible negative life bug in his Bonus lib. *
//* *
//************************************************************************************************************
//**************************************************************************************
//* INTRODUCTION: *
//* *
//* An alternative to BonusMod for those who prefer a vanilla JASS approach. *
//* *
//* Just follow the API and you are pretty much done. *
//**************************************************************************************
//********************************************************************************************************
//* REQUIREMENTS: *
//* *
//* JNGP [url]http://www.hiveworkshop.com/forums/tools-560/jassnewgenpack-5d-227445[/url] (Recommended) *
//* OR: *
//* Your superhuman capability to transfer 198 abilities to your map. (Not Recommended) *
//********************************************************************************************************
//************************************************************************************************************************************************
//* INSTALLATION INSTRUCTION: *
//* *
//* Step 1: Copy the custom code for bonus handling to your map header. *
//* Step 2: Use JNGP to implement the system's abilities through macro. Instruction is included in the Implementation Macro trigger. *
//* Step 3: Copy the whole CSS folder to your map. Don't forget to turn on "Automatically create unknown variables while pasting trigger data". *
//* Step 4: Except for this trigger, delete every other useless elements. *
//* Step 5: Use this BonusMod alternative however you want. *
//* *
//************************************************************************************************************************************************
//**************************************************************************************
//* Bonus Types Identifier: *
//* *
//* Armor Bonus: 0 *
//* Attack Speed Bonus: 1 *
//* Damage Bonus: 2 *
//* Agility Bonus: 3 *
//* Intelligence Bonus: 4 *
//* Strength Bonus: 5 *
//* Life Regen Bonus: 6 *
//* Mana Regen Bonus: 7 *
//* Life Bonus: 8 *
//* Mana Bonus: 9 *
//* Sight Range Bonus: 10 *
//**************************************************************************************
//********************************************************************************
//* Generic Bonus APIs *
//* *
//* CSS_GetBonus takes unit u, integer bonusType returns integer *
//* CSS_AddBonus takes unit u, integer amount, integer bonusType returns nothing *
//* CSS_ClearBonus takes unit u, integer bonusType *
//********************************************************************************
// Clear bonus
function CSS_ClearBonus takes unit u, integer bonusType returns nothing
if bonusType > 10 or bonusType < 0 or GetUnitTypeId (u) == 0 or IsUnitType (u, UNIT_TYPE_DEAD) then
return
endif
call CSS_AddBonus (u, -LoadInteger (udg_CSS_Hashtable, GetHandleId (u), bonusType), bonusType)
endfunction
// Get current bonus
function CSS_GetBonus takes unit u, integer bonusType returns integer
if bonusType > 10 or bonusType < 0 or GetUnitTypeId (u) == 0 or IsUnitType (u, UNIT_TYPE_DEAD) then
return 0
endif
return LoadInteger (udg_CSS_Hashtable, GetHandleId (u), bonusType)
endfunction
// For preloading abilities
function CSS_Preload takes nothing returns nothing
local integer i = 0
local unit u = CreateUnit(Player(15), 'hfoo', 0, 0, 0.00)
loop
exitwhen i > 197
call UnitAddAbility(u, udg_CSS_Abilities[i])
set i = i + 1
endloop
call RemoveUnit(u)
set u = null
endfunction
//===========================================================================
function InitTrig_CSS_Standalone_Bonus takes nothing returns nothing
local integer i = 0
local integer a = 1
set udg_CSS_Abilities[0] = 'ZxA0'
set udg_CSS_Abilities[1] = 'ZxA1'
set udg_CSS_Abilities[2] = 'ZxA2'
set udg_CSS_Abilities[3] = 'ZxA3'
set udg_CSS_Abilities[4] = 'ZxA4'
set udg_CSS_Abilities[5] = 'ZxA5'
set udg_CSS_Abilities[6] = 'ZxA6'
set udg_CSS_Abilities[7] = 'ZxA7'
set udg_CSS_Abilities[8] = 'ZxA8'
set udg_CSS_Abilities[9] = 'ZxA9'
set udg_CSS_Abilities[10] = 'ZxAa'
set udg_CSS_Abilities[11] = 'ZxAb'
set udg_CSS_Abilities[12] = 'ZxAc'
set udg_CSS_Abilities[13] = 'ZxAd'
set udg_CSS_Abilities[14] = 'ZxAe'
set udg_CSS_Abilities[15] = 'ZxAf'
set udg_CSS_Abilities[16] = 'ZxAg'
set udg_CSS_Abilities[17] = 'ZxAh'
set udg_CSS_Abilities[18] = 'ZxI0'
set udg_CSS_Abilities[19] = 'ZxI1'
set udg_CSS_Abilities[20] = 'ZxI2'
set udg_CSS_Abilities[21] = 'ZxI3'
set udg_CSS_Abilities[22] = 'ZxI4'
set udg_CSS_Abilities[23] = 'ZxI5'
set udg_CSS_Abilities[24] = 'ZxI6'
set udg_CSS_Abilities[25] = 'ZxI7'
set udg_CSS_Abilities[26] = 'ZxI8'
set udg_CSS_Abilities[27] = 'ZxI9'
set udg_CSS_Abilities[28] = 'ZxIa'
set udg_CSS_Abilities[29] = 'ZxIb'
set udg_CSS_Abilities[30] = 'ZxIc'
set udg_CSS_Abilities[31] = 'ZxId'
set udg_CSS_Abilities[32] = 'ZxIe'
set udg_CSS_Abilities[33] = 'ZxIf'
set udg_CSS_Abilities[34] = 'ZxIg'
set udg_CSS_Abilities[35] = 'ZxIh'
set udg_CSS_Abilities[36] = 'ZxB0'
set udg_CSS_Abilities[37] = 'ZxB1'
set udg_CSS_Abilities[38] = 'ZxB2'
set udg_CSS_Abilities[39] = 'ZxB3'
set udg_CSS_Abilities[40] = 'ZxB4'
set udg_CSS_Abilities[41] = 'ZxB5'
set udg_CSS_Abilities[42] = 'ZxB6'
set udg_CSS_Abilities[43] = 'ZxB7'
set udg_CSS_Abilities[44] = 'ZxB8'
set udg_CSS_Abilities[45] = 'ZxB9'
set udg_CSS_Abilities[46] = 'ZxBa'
set udg_CSS_Abilities[47] = 'ZxBb'
set udg_CSS_Abilities[48] = 'ZxBc'
set udg_CSS_Abilities[49] = 'ZxBd'
set udg_CSS_Abilities[50] = 'ZxBe'
set udg_CSS_Abilities[51] = 'ZxBf'
set udg_CSS_Abilities[52] = 'ZxBg'
set udg_CSS_Abilities[53] = 'ZxBh'
set udg_CSS_Abilities[54] = 'ZxG0'
set udg_CSS_Abilities[55] = 'ZxG1'
set udg_CSS_Abilities[56] = 'ZxG2'
set udg_CSS_Abilities[57] = 'ZxG3'
set udg_CSS_Abilities[58] = 'ZxG4'
set udg_CSS_Abilities[59] = 'ZxG5'
set udg_CSS_Abilities[60] = 'ZxG6'
set udg_CSS_Abilities[61] = 'ZxG7'
set udg_CSS_Abilities[62] = 'ZxG8'
set udg_CSS_Abilities[63] = 'ZxG9'
set udg_CSS_Abilities[64] = 'ZxGa'
set udg_CSS_Abilities[65] = 'ZxGb'
set udg_CSS_Abilities[66] = 'ZxGc'
set udg_CSS_Abilities[67] = 'ZxGd'
set udg_CSS_Abilities[68] = 'ZxGe'
set udg_CSS_Abilities[69] = 'ZxGf'
set udg_CSS_Abilities[70] = 'ZxGg'
set udg_CSS_Abilities[71] = 'ZxGh'
set udg_CSS_Abilities[72] = 'ZxH0'
set udg_CSS_Abilities[73] = 'ZxH1'
set udg_CSS_Abilities[74] = 'ZxH2'
set udg_CSS_Abilities[75] = 'ZxH3'
set udg_CSS_Abilities[76] = 'ZxH4'
set udg_CSS_Abilities[77] = 'ZxH5'
set udg_CSS_Abilities[78] = 'ZxH6'
set udg_CSS_Abilities[79] = 'ZxH7'
set udg_CSS_Abilities[80] = 'ZxH8'
set udg_CSS_Abilities[81] = 'ZxH9'
set udg_CSS_Abilities[82] = 'ZxHa'
set udg_CSS_Abilities[83] = 'ZxHb'
set udg_CSS_Abilities[84] = 'ZxHc'
set udg_CSS_Abilities[85] = 'ZxHd'
set udg_CSS_Abilities[86] = 'ZxHe'
set udg_CSS_Abilities[87] = 'ZxHf'
set udg_CSS_Abilities[88] = 'ZxHg'
set udg_CSS_Abilities[89] = 'ZxHh'
set udg_CSS_Abilities[90] = 'ZxF0'
set udg_CSS_Abilities[91] = 'ZxF1'
set udg_CSS_Abilities[92] = 'ZxF2'
set udg_CSS_Abilities[93] = 'ZxF3'
set udg_CSS_Abilities[94] = 'ZxF4'
set udg_CSS_Abilities[95] = 'ZxF5'
set udg_CSS_Abilities[96] = 'ZxF6'
set udg_CSS_Abilities[97] = 'ZxF7'
set udg_CSS_Abilities[98] = 'ZxF8'
set udg_CSS_Abilities[99] = 'ZxF9'
set udg_CSS_Abilities[100] = 'ZxFa'
set udg_CSS_Abilities[101] = 'ZxFb'
set udg_CSS_Abilities[102] = 'ZxFc'
set udg_CSS_Abilities[103] = 'ZxFd'
set udg_CSS_Abilities[104] = 'ZxFe'
set udg_CSS_Abilities[105] = 'ZxFf'
set udg_CSS_Abilities[106] = 'ZxFg'
set udg_CSS_Abilities[107] = 'ZxFh'
set udg_CSS_Abilities[108] = 'ZxJ0'
set udg_CSS_Abilities[109] = 'ZxJ1'
set udg_CSS_Abilities[110] = 'ZxJ2'
set udg_CSS_Abilities[111] = 'ZxJ3'
set udg_CSS_Abilities[112] = 'ZxJ4'
set udg_CSS_Abilities[113] = 'ZxJ5'
set udg_CSS_Abilities[114] = 'ZxJ6'
set udg_CSS_Abilities[115] = 'ZxJ7'
set udg_CSS_Abilities[116] = 'ZxJ8'
set udg_CSS_Abilities[117] = 'ZxJ9'
set udg_CSS_Abilities[118] = 'ZxJa'
set udg_CSS_Abilities[119] = 'ZxJb'
set udg_CSS_Abilities[120] = 'ZxJc'
set udg_CSS_Abilities[121] = 'ZxJd'
set udg_CSS_Abilities[122] = 'ZxJe'
set udg_CSS_Abilities[123] = 'ZxJf'
set udg_CSS_Abilities[124] = 'ZxJg'
set udg_CSS_Abilities[125] = 'ZxJh'
set udg_CSS_Abilities[126] = 'ZxK0'
set udg_CSS_Abilities[127] = 'ZxK1'
set udg_CSS_Abilities[128] = 'ZxK2'
set udg_CSS_Abilities[129] = 'ZxK3'
set udg_CSS_Abilities[130] = 'ZxK4'
set udg_CSS_Abilities[131] = 'ZxK5'
set udg_CSS_Abilities[132] = 'ZxK6'
set udg_CSS_Abilities[133] = 'ZxK7'
set udg_CSS_Abilities[134] = 'ZxK8'
set udg_CSS_Abilities[135] = 'ZxK9'
set udg_CSS_Abilities[136] = 'ZxKa'
set udg_CSS_Abilities[137] = 'ZxKb'
set udg_CSS_Abilities[138] = 'ZxKc'
set udg_CSS_Abilities[139] = 'ZxKd'
set udg_CSS_Abilities[140] = 'ZxKe'
set udg_CSS_Abilities[141] = 'ZxKf'
set udg_CSS_Abilities[142] = 'ZxKg'
set udg_CSS_Abilities[143] = 'ZxKh'
set udg_CSS_Abilities[144] = 'ZxE0'
set udg_CSS_Abilities[145] = 'ZxE1'
set udg_CSS_Abilities[146] = 'ZxE2'
set udg_CSS_Abilities[147] = 'ZxE3'
set udg_CSS_Abilities[148] = 'ZxE4'
set udg_CSS_Abilities[149] = 'ZxE5'
set udg_CSS_Abilities[150] = 'ZxE6'
set udg_CSS_Abilities[151] = 'ZxE7'
set udg_CSS_Abilities[152] = 'ZxE8'
set udg_CSS_Abilities[153] = 'ZxE9'
set udg_CSS_Abilities[154] = 'ZxEa'
set udg_CSS_Abilities[155] = 'ZxEb'
set udg_CSS_Abilities[156] = 'ZxEc'
set udg_CSS_Abilities[157] = 'ZxEd'
set udg_CSS_Abilities[158] = 'ZxEe'
set udg_CSS_Abilities[159] = 'ZxEf'
set udg_CSS_Abilities[160] = 'ZxEg'
set udg_CSS_Abilities[161] = 'ZxEh'
set udg_CSS_Abilities[162] = 'ZxD0'
set udg_CSS_Abilities[163] = 'ZxD1'
set udg_CSS_Abilities[164] = 'ZxD2'
set udg_CSS_Abilities[165] = 'ZxD3'
set udg_CSS_Abilities[166] = 'ZxD4'
set udg_CSS_Abilities[167] = 'ZxD5'
set udg_CSS_Abilities[168] = 'ZxD6'
set udg_CSS_Abilities[169] = 'ZxD7'
set udg_CSS_Abilities[170] = 'ZxD8'
set udg_CSS_Abilities[171] = 'ZxD9'
set udg_CSS_Abilities[172] = 'ZxDa'
set udg_CSS_Abilities[173] = 'ZxDb'
set udg_CSS_Abilities[174] = 'ZxDc'
set udg_CSS_Abilities[175] = 'ZxDd'
set udg_CSS_Abilities[176] = 'ZxDe'
set udg_CSS_Abilities[177] = 'ZxDf'
set udg_CSS_Abilities[178] = 'ZxDg'
set udg_CSS_Abilities[179] = 'ZxDh'
set udg_CSS_Abilities[180] = 'ZxC0'
set udg_CSS_Abilities[181] = 'ZxC1'
set udg_CSS_Abilities[182] = 'ZxC2'
set udg_CSS_Abilities[183] = 'ZxC3'
set udg_CSS_Abilities[184] = 'ZxC4'
set udg_CSS_Abilities[185] = 'ZxC5'
set udg_CSS_Abilities[186] = 'ZxC6'
set udg_CSS_Abilities[187] = 'ZxC7'
set udg_CSS_Abilities[188] = 'ZxC8'
set udg_CSS_Abilities[189] = 'ZxC9'
set udg_CSS_Abilities[190] = 'ZxCa'
set udg_CSS_Abilities[191] = 'ZxCb'
set udg_CSS_Abilities[192] = 'ZxCc'
set udg_CSS_Abilities[193] = 'ZxCd'
set udg_CSS_Abilities[194] = 'ZxCe'
set udg_CSS_Abilities[195] = 'ZxCf'
set udg_CSS_Abilities[196] = 'ZxCg'
set udg_CSS_Abilities[197] = 'ZxCh'
loop
exitwhen i > 30
set udg_CSS_Power[i] = a
set a = a*2
set i = i + 1
endloop
set udg_CSS_Hashtable = InitHashtable()
if udg_CSS_PreloadBoolean then
call CSS_Preload()
endif
endfunction
////////////////////////////////////////////////////////////////////
// NANO PLAGUE V1.00 //
// Author: Tank-Commander //
// Purpose: Sacrafice yourself to decimate mechanical forces //
// //
// Requires: //
// - Custom Stat System (Created by Doomlord) //
// - SimError (Created by Vexorian) //
// - BoundInt (Created by Magtheridon96) //
// The requirements of the CSS are in the map header //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the system //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// - Others mentioned in the requirements //
// //
// If you have used this spell in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you would like to use snippets of code from this for //
// whatever, getting permission and crediting the source/linking //
// would be much appreciated. //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you paste in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
// //
// While the remaining object editor based data is not required //
// to function (provided they're replaced with equivelents) //
// it's recommended that they are also imported, if their data //
// value are not the same as listed in the configuration, those //
// configurables will need to be changed to work correctly //
//----------------------------------------------------------------//
// Changing Valid targets: //
// What is considered a valid target is controlled by the //
// object data for the infection ability used by Nanobots //
// (NP_InfectAbilityID) //
//----------------------------------------------------------------//
// MISC //
//----------------------------------------------------------------//
// TimerSpeed: the time in seconds between each iteration of //
// the main loop function (default is 0.031250000) it's //
// recommended you leave it like that //
constant function NP_TimerSpeed takes nothing returns real
return 0.031250000
endfunction
//----------------------------------------------------------------//
// AbilityID: This is the data value of the ability used as the //
// base, make sure it is based off channel (to view raw data //
// press ctrl + d, pressing again switches back) //
constant function NP_AbilityID takes nothing returns integer
return 'A001'
endfunction
//----------------------------------------------------------------//
// InfectAbilityID: This is the data value of the ability used //
// to infect additional units with the plague //
constant function NP_InfectAbilityID takes nothing returns integer
return 'A002'
endfunction
//----------------------------------------------------------------//
// DummyID: This is the data value of the unit used to create //
// the buffs and projectiles used by the spell //
constant function NP_DummyID takes nothing returns integer
return 'u000'
endfunction
//----------------------------------------------------------------//
// BuffID: This is the data value of the ability used as a buff //
// for infected units that appears below the unit data //
constant function NP_BuffID takes nothing returns integer
return 'A000'
endfunction
//----------------------------------------------------------------//
// SummonedUnitID: This is the data value of the unit summoned //
// by the ability (the nanobots) //
constant function NP_SummonedUnitID takes nothing returns integer
return 'u002'
endfunction
//----------------------------------------------------------------//
// SummonBuffID: This is the data value of the buff assigned to //
// the nanobots to give the timed life text //
constant function NP_SummonBuffID takes nothing returns integer
return 'B001'
endfunction
//----------------------------------------------------------------//
// AutoInfect: This will cause your Nanobots to automatically //
// attempt to infect valid targets //
constant function NP_AutoInfect takes nothing returns boolean
return true
endfunction
//----------------------------------------------------------------//
// AttackOrder: This is the order ID of the ability used to //
// infect enemies - only matters when AutoInfect is true //
constant function NP_AttackOrder takes nothing returns integer
return 851983
endfunction
//----------------------------------------------------------------//
// DummyPlayerID: This is the player that owns all of the dummy //
// units as to not interfere with the scoreboard at the end of //
// playing a map, 14 Player(14) is the default value //
constant function NP_DummyPlayerID takes nothing returns player
return Player(14)
endfunction
//----------------------------------------------------------------//
// AttachmentPoint: This is the attachment point all effects //
// used by the Dummy Unit are placed onto //
constant function NP_AttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// VISUALS //
//----------------------------------------------------------------//
// BuffModel: This is the model path for the buff placed above //
// infected units, remmeber to double slash (\\) the pathname //
constant function NP_BuffModel takes nothing returns string
return "Units\\Creeps\\HeroTinkerFactory\\HeroTinkerFactory.mdl"
endfunction
//----------------------------------------------------------------//
// BuffSpawnModel: This is the effect used on the body of a //
// unit when it has been infected //
constant function NP_BuffSpawnModel takes nothing returns string
return "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl"
endfunction
//----------------------------------------------------------------//
// ProjectileModel: This is the model used for projectiles //
// containing Nanobots that get thrown out of the unit //
constant function NP_ProjectileModel takes nothing returns string
return "Units\\Creeps\\HeroTinkerFactory\\HeroTinkerFactoryMissle.mdl"
endfunction
//----------------------------------------------------------------//
// SpawnBuffModel: This is the effect/buff used on projectiles //
// when they are freshly created (their spawning effect) //
constant function NP_SpawnBuffModel takes nothing returns string
return "Objects\\Spawnmodels\\Other\\ToonBoom\\ToonBoom.mdl"
endfunction
//----------------------------------------------------------------//
// UseTeamColouredBuff: determines if the buffs created above //
// infected units use teamcolour (set to false if the buff model //
// has no team colour to increase efficiency) //
constant function NP_UseTeamColouredBuff takes nothing returns boolean
return true
endfunction
//----------------------------------------------------------------//
// BuffFacing: This is the facing angle of the buff created //
// above infected units //
constant function NP_BuffFacing takes nothing returns real
return 270.
endfunction
//----------------------------------------------------------------//
// BuffHeightOffset: This is how high above the model of //
// infected units the infected buff is placed //
constant function NP_BuffHeightOffset takes nothing returns real
return 150.
endfunction
//----------------------------------------------------------------//
// BuffOffset: This is how far away from the centre of an //
// infected unit the buff is moved to when there's more than //
// one infection buff //
constant function NP_BuffOffset takes nothing returns real
return 70.
endfunction
//----------------------------------------------------------------//
// Gravity: This is the strength of the force pulling //
// projectiles toward the ground - increasing the value results //
// in steeper Arcs //
constant function NP_Gravity takes nothing returns real
return 1.20
endfunction
//----------------------------------------------------------------//
// BuffSize: This is the size of the buff created above //
// infected units (1 = 100% scaling) //
function NP_BuffSize takes real rlevel returns real
return 0.275 + (0.025 * rlevel)
endfunction
//----------------------------------------------------------------//
// ProjectileSize: This is the size of the projectiles carrying //
// nanobots within //
function NP_ProjectileSize takes real rlevel returns real
return 0.8 + (0.025 * rlevel)
endfunction
//----------------------------------------------------------------//
// MAIN SPELL //
//----------------------------------------------------------------//
// InfectionLimit: This is the maximum amount of infections a //
// single unit can have at any given time //
constant function NP_InfectionLimit takes nothing returns integer
return 3
endfunction
//----------------------------------------------------------------//
// AOE: This is the size of the area that nanobots can land in //
// when they are spawned //
function NP_AOE takes real rlevel returns real
return 250 + (25 * rlevel)
endfunction
//----------------------------------------------------------------//
// ProjectileFlightTime: This is how long (in seconds) it takes //
// for a projectile carrying a Nanobot to reach the target //
function NP_ProjectileFlightTime takes real rlevel returns real
return 2 + (-0.2 * rlevel)
endfunction
//----------------------------------------------------------------//
// InfectDuration: This is how long (in second) a unit will //
// produce nanobots while infected //
function NP_InfectDuration takes real rlevel returns real
return 4 + (1 * rlevel)
endfunction
//----------------------------------------------------------------//
// InfectDPSHealth: This is how much health (per second) the //
// Nanobot will drain from an infected unit //
function NP_InfectDPSHealth takes real rlevel returns real
return 25 + (25 * rlevel)
endfunction
//----------------------------------------------------------------//
// InfectDPSMana: This is how much mana (per second) the //
// Nanobot will drain from an infected unit //
function NP_InfectDPSMana takes real rlevel returns real
return 0.
endfunction
//----------------------------------------------------------------//
// InfectBonusDamageHealth: This is the amount of health damage //
// that is dealt to a unit when a Nanobot attempts to infect an //
// already infected unit (or at its infection limit) //
function NP_InfectBonusDamageHealth takes real rlevel returns real
return 10 * rlevel
endfunction
//----------------------------------------------------------------//
// InfectBonusDamageMana: This is the amount of mana damage //
// that is dealt to a unit when a Nanobot attempts to infect an //
// already infected unit (or at its infection limit) //
function NP_InfectBonusDamageMana takes real rlevel returns real
return 0.
endfunction
//----------------------------------------------------------------//
// InstantDuplicationChance: This is the probability that //
// when a Nanobot attempts to infect an already infected unit //
// (or at its infection limit) that a new Nanobot will be //
// instantly produces (1 = 100%) //
function NP_InstantDuplicationChance takes real rlevel returns real
return 0.05 * rlevel
endfunction
//----------------------------------------------------------------//
// ProductionPS: This is the amount of Nanobots produced (per //
// second) by a unit infected by the plague //
function NP_ProductionPS takes real rlevel returns real
return 1.50 + (0.25 * rlevel)
endfunction
//----------------------------------------------------------------//
// SummonDuration: This is the amount of time (in seconds) that //
// each Nanobot lasts for after reaching the ground //
function NP_SummonDuration takes real rlevel returns real
return 6 + (2 * rlevel)
endfunction
//----------------------------------------------------------------//
// SummonSize: This is the size of the nanobot (1 = 100% scale) //
function NP_SummonSize takes real rlevel returns real
return 0.15 + (0.05 * rlevel)
endfunction
//----------------------------------------------------------------//
// SummonHealthBonus: This is the amount of extra health the //
// Nanobot obtains when spawned //
function NP_SummonHealthBonus takes integer rlevel returns integer
return -50 + 50 * rlevel
endfunction
//----------------------------------------------------------------//
// SummonHealthRegenBonus: This is the amount of extra health //
// regen the Nanobot obtains when spawned //
function NP_SummonHealthRegenBonus takes integer rlevel returns integer
return 1 * rlevel
endfunction
//----------------------------------------------------------------//
// SummonArmourBonus: This is the amount of extra armour the //
// Nanobot obtains when spawned //
function NP_SummonArmourBonus takes integer rlevel returns integer
return -1 + (1 * rlevel)
endfunction
//----------------------------------------------------------------//
// SummonAttackDamageBonus: This is the amount of extra damage //
// the Nanobot obtains when spawned //
function NP_SummonAttackDamageBonus takes integer rlevel returns integer
return 5 * rlevel
endfunction
//----------------------------------------------------------------//
// SummonAttackSpeedBonus: This is the amount of extra attack //
// speed the Nanobot obtains when spawned //
function NP_SummonAttackSpeedBonus takes integer rlevel returns integer
return 0
endfunction
//----------------------------------------------------------------//
// SwarmStrengthAttackBonus: This is the extra damage given to //
// the Nanobot for every Nanobot currently alive in the Swarm //
function NP_SwarmStrengthAttackBonus takes integer SwarmStrength returns integer
return R2I(0.5 * SwarmStrength)
endfunction
//----------------------------------------------------------------//
// DAMAGE SETTINGS //
//----------------------------------------------------------------//
// AttackType: This is the attacktype which is used when //
// health is being drained from an infected unit and as the //
// bonus infection damage //
constant function NP_AttackType takes nothing returns attacktype
return ATTACK_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
// DamageType: This is the damagetype which is used when //
// health is being drained from an infected unit and as the //
// bonus infection damage //
constant function NP_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
// WeaponType: This is the weapontype which is used when //
// health is being drained from an infected unit and as the //
// bonus infection damage //
constant function NP_WeaponType takes nothing returns weapontype
return null
endfunction
//----------------------------------------------------------------//
// READ ONLY //
//----------------------------------------------------------------//
// These Values are read only: Do not attempt to change them //
constant function NP_InfectionStageID takes nothing returns integer
return 1
endfunction
//----------------------------------------------------------------//
constant function NP_ProjectileStageID takes nothing returns integer
return 2
endfunction
//----------------------------------------------------------------//
constant function NP_NanobotStageID takes nothing returns integer
return 3
endfunction
//----------------------------------------------------------------//
constant function NP_BuffStageID takes nothing returns integer
return 4
endfunction
//----------------------------------------------------------------//
constant function NP_WaitingStageID takes nothing returns integer
return 5
endfunction
//----------------------------------------------------------------//
// END OF CONFIGURATION //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function used to get the Z location height at a given point //
////////////////////////////////////////////////////////////////////
function NP_GetZ takes real x, real y returns real
call MoveLocation(udg_NP_ZLoc, x, y)
return GetLocationZ(udg_NP_ZLoc)
endfunction
////////////////////////////////////////////////////////////////////
// Function used to make sure that the location is within the //
// map bounds so that units cannot be moved outside of it and //
// get permanently stuck //
////////////////////////////////////////////////////////////////////
function NP_ValidateLocation takes real x, real y returns boolean
//Check if the point is within the map bounds
return (x < udg_NP_MapMaxX) and (x > udg_NP_MapMinX) and (y < udg_NP_MapMaxY) and (y > udg_NP_MapMinY)
endfunction
////////////////////////////////////////////////////////////////////
// Function used to remove instances from the linked list once //
// they have expired //
////////////////////////////////////////////////////////////////////
function NP_RecycleNode takes integer node returns nothing
set udg_NP_RecycleNodes[udg_NP_RecyclableNodes] = node
set udg_NP_RecyclableNodes = udg_NP_RecyclableNodes + 1
set udg_NP_NextNode[udg_NP_PrevNode[node]] = udg_NP_NextNode[node]
set udg_NP_PrevNode[udg_NP_NextNode[node]] = udg_NP_PrevNode[node]
endfunction
////////////////////////////////////////////////////////////////////
// Function used to add new nodes to the linked list used by the //
// system //
////////////////////////////////////////////////////////////////////
function NP_CreateNode takes nothing returns integer
local integer node
if (udg_NP_RecyclableNodes == 0) then
set udg_NP_NodeNumber = udg_NP_NodeNumber + 1
set node = udg_NP_NodeNumber
else
set udg_NP_RecyclableNodes = udg_NP_RecyclableNodes - 1
set node = udg_NP_RecycleNodes[udg_NP_RecyclableNodes]
endif
set udg_NP_NextNode[node] = 0
set udg_NP_NextNode[udg_NP_PrevNode[0]] = node
set udg_NP_PrevNode[node] = udg_NP_PrevNode[0]
set udg_NP_PrevNode[0] = node
return node
endfunction
////////////////////////////////////////////////////////////////////
// Function used to tell if the passed unit is infected with a //
// specific instance //
////////////////////////////////////////////////////////////////////
function NP_IsInfected takes unit u, integer instance returns boolean
local integer node = 0
loop
set node = udg_NP_NextNode[node]
exitwhen node == 0 or (udg_NP_Instance[node] == instance and udg_NP_Unit[node] == u)
endloop
return udg_NP_Instance[node] == instance and udg_NP_Unit[node] == u
endfunction
////////////////////////////////////////////////////////////////////
// Function used to get the total amount of infections a given //
// unit currently has //
////////////////////////////////////////////////////////////////////
function NP_GetInfections takes unit u returns integer
local integer node = 0
local integer infections = 0
loop
set node = udg_NP_NextNode[node]
exitwhen node == 0
if udg_NP_Unit[node] == u then
set infections = infections + 1
endif
endloop
return infections
endfunction
////////////////////////////////////////////////////////////////////
// Function used to attribute each infection to the original //
// unique cast of the ability, as each unit can be infected //
// multiple times, this is only used for getting summoned units //
////////////////////////////////////////////////////////////////////
function NP_GetNode takes unit u returns integer
local integer node = 0
loop
set node = udg_NP_NextNode[node]
exitwhen node == 0 or udg_NP_Unit[node] == u
endloop
return node
endfunction
////////////////////////////////////////////////////////////////////
// Function used to move all buffs on an infected unit when a //
// buff has either been added or removed from the unit //
////////////////////////////////////////////////////////////////////
function NP_MoveBuffs takes unit u, integer buffCount returns nothing
//Set up locals
local integer node = 0
local real angle = 0.
local real increment = (bj_PI * 2) / buffCount
local integer tempInt = 0
//Locate all buffs belonging to this unit
loop
set node = udg_NP_NextNode[node]
exitwhen tempInt == buffCount
if udg_NP_Caster[node] == u and udg_NP_StageID[node] == NP_BuffStageID() then
//Set up their new position
if buffCount > 1 then
set udg_NP_Offset[node] = NP_BuffOffset()
set angle = angle + increment
set udg_NP_BuffAngle[node] = angle
else
set udg_NP_Offset[node] = 0.
set udg_NP_BuffAngle[node] = 0.
endif
set tempInt = tempInt + 1
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// Function used to remove the infection buff from units and //
// subsequently rearrange all others using the MoveBuff function //
////////////////////////////////////////////////////////////////////
function NP_DestroyBuff takes integer node, unit u returns nothing
local integer infections = NP_GetInfections(u)
//Remove the buff and recycle it
call NP_RecycleNode(node)
call KillUnit(udg_NP_Unit[node])
call DestroyEffect(udg_NP_CurrentEffect[node])
//Rearrange remaining buffs
if infections > 1 then
call NP_MoveBuffs(u, infections - 1)
endif
endfunction
////////////////////////////////////////////////////////////////////
// Function used to add the infection buff to units and //
// subsequently rearrange all others using the MoveBuff function //
////////////////////////////////////////////////////////////////////
function NP_CreateBuff takes unit u, integer buffCount, real rlevel, player pl returns integer
//set up locals
local integer node = NP_CreateNode()
//Create new buff
set udg_NP_Unit[node] = CreateUnit(NP_DummyPlayerID(), NP_DummyID(), GetUnitX(u), GetUnitY(u), NP_BuffFacing())
set udg_NP_CurrentEffect[node] = AddSpecialEffectTarget(NP_BuffModel(), udg_NP_Unit[node], NP_AttachmentPoint())
//Apply optional teamcolour
if NP_UseTeamColouredBuff() then
call SetUnitColor(udg_NP_Unit[node], GetPlayerColor(pl))
endif
//Set up buff data
call PauseUnit(udg_NP_Unit[node], true)
if UnitAddAbility(udg_NP_Unit[node], 'Amrf') and UnitRemoveAbility(udg_NP_Unit[node], 'Amrf') then
endif
call SetUnitScale(udg_NP_Unit[node], NP_BuffSize(rlevel), 0., 0.)
call SetUnitFlyHeight(udg_NP_Unit[node], GetUnitFlyHeight(u) + NP_BuffHeightOffset(), 0.)
set udg_NP_Caster[node] = u
set udg_NP_StageID[node] = NP_BuffStageID()
//Create spawn effect on the affected unit
call DestroyEffect(AddSpecialEffectTarget(NP_BuffSpawnModel(), u, NP_AttachmentPoint()))
//Move all Buffs to fit around the circle
call NP_MoveBuffs(u, buffCount + 1)
//Return the newly created buff
return node
endfunction
////////////////////////////////////////////////////////////////////
// Function used to produce new nanobots either from a virus //
// or from the instant duplication effect //
////////////////////////////////////////////////////////////////////
function NP_CreateProjectile takes real x, real y, real z, integer node returns nothing
local integer tempNode = NP_CreateNode()
local real x2
local real y2
local real offset
local real angle = GetRandomReal(-bj_PI, bj_PI)
local real tempReal = udg_NP_ProjectileFlightTime[udg_NP_Instance[node]] / NP_TimerSpeed()
local real dy
local real dx
//Get target centre
if udg_NP_TargetSelf[node] then
set x2 = GetUnitX(udg_NP_Unit[node])
set y2 = GetUnitY(udg_NP_Unit[node])
else
set x2 = udg_NP_TargetX[node]
set y2 = udg_NP_TargetY[node]
endif
//Get random location from the target point (Uniform distribution)
set offset = GetRandomReal(0, udg_NP_AOE[udg_NP_Instance[node]]) + GetRandomReal(0, udg_NP_AOE[udg_NP_Instance[node]])
if offset > udg_NP_AOE[udg_NP_Instance[node]] then
set offset = 2 * udg_NP_AOE[udg_NP_Instance[node]] - offset
endif
set x2 = x2 + offset * Cos(angle)
set y2 = y2 + offset * Sin(angle)
//Create projectile
set udg_NP_StageID[tempNode] = NP_ProjectileStageID()
set udg_NP_Unit[tempNode] = CreateUnit(NP_DummyPlayerID(), NP_DummyID(), x, y, angle * bj_RADTODEG)
set udg_NP_Instance[tempNode] = udg_NP_Instance[node]
call SetUnitScale(udg_NP_Unit[tempNode], udg_NP_ProjectileSize[udg_NP_Instance[node]], 0., 0.)
set udg_NP_CurrentEffect[tempNode] = AddSpecialEffectTarget(NP_ProjectileModel(), udg_NP_Unit[tempNode], NP_AttachmentPoint())
if UnitAddAbility(udg_NP_Unit[tempNode], 'Amrf') and UnitRemoveAbility(udg_NP_Unit[tempNode], 'Amrf') then
endif
call DestroyEffect(AddSpecialEffectTarget(NP_SpawnBuffModel(), udg_NP_Unit[tempNode], NP_AttachmentPoint()))
call SetUnitFlyHeight(udg_NP_Unit[tempNode], z, 0.)
set udg_NP_CurrentZ[tempNode] = z + NP_GetZ(x, y)
call PauseUnit(udg_NP_Unit[tempNode], true)
//Set up movement
set udg_NP_XVel[tempNode] = (x2 - x) / (udg_NP_ProjectileFlightTime[udg_NP_Instance[node]] / NP_TimerSpeed())
set udg_NP_YVel[tempNode] = (y2 - y) / (udg_NP_ProjectileFlightTime[udg_NP_Instance[node]] / NP_TimerSpeed())
set udg_NP_ZVel[tempNode] = ((NP_GetZ(x2, y2) - udg_NP_CurrentZ[tempNode]) + ((NP_Gravity() * (tempReal * tempReal)) / 2)) / tempReal
endfunction
////////////////////////////////////////////////////////////////////
// Function used to run the main engine of the spell, handles //
// creation of new units, buff control and projectile control //
////////////////////////////////////////////////////////////////////
function NP_Loop takes nothing returns nothing
//Set up locals
local integer node = 0
local integer tempNode
local real x
local real y
local real x2
local real y2
loop
set node = udg_NP_NextNode[node]
exitwhen node == 0
//Infections which are producing nanobots
if udg_NP_StageID[node] == NP_InfectionStageID() then
//Check if the infection is over
if udg_NP_InfectionDuration[node] > 0. and not(IsUnitType(udg_NP_Unit[node], UNIT_TYPE_DEAD)) then
//Deal infection damage
set udg_NP_SwarmStrengthBonus[node] = NP_SwarmStrengthAttackBonus(udg_NP_SwarmStrength[node])
call UnitDamageTarget(udg_NP_Caster[node], udg_NP_Unit[node], udg_NP_InfectionDamageHealth[udg_NP_Instance[node]], true, false, NP_AttackType(), NP_DamageType(), NP_WeaponType())
call SetUnitState(udg_NP_Unit[node], UNIT_STATE_MANA, GetUnitState(udg_NP_Unit[node], UNIT_STATE_MANA) - udg_NP_InfectionDamageMana[udg_NP_Instance[node]])
set udg_NP_InfectionDuration[node] = udg_NP_InfectionDuration[node] - NP_TimerSpeed()
//Check if it's time to produce a new nanobot
if udg_NP_CurrentProductionDelay[node] <= 0. then
set udg_NP_CurrentProductionDelay[node] = udg_NP_ProductionDelay[udg_NP_Instance[node]]
//Produce new nanobot
call NP_CreateProjectile(GetUnitX(udg_NP_Unit[udg_NP_BuffNode[node]]), GetUnitY(udg_NP_Unit[udg_NP_BuffNode[node]]), GetUnitFlyHeight(udg_NP_Unit[udg_NP_BuffNode[node]]), node)
set udg_NP_SwarmStrength[udg_NP_Instance[node]] = udg_NP_SwarmStrength[udg_NP_Instance[node]] + 1
else
set udg_NP_CurrentProductionDelay[node] = udg_NP_CurrentProductionDelay[node] - NP_TimerSpeed()
endif
else
//Change the ID to the waiting period
set udg_NP_StageID[node] = NP_WaitingStageID()
set udg_NP_SwarmStrength[udg_NP_Instance[node]] = udg_NP_SwarmStrength[udg_NP_Instance[node]] - 1
endif
//Projectiles
elseif udg_NP_StageID[node] == NP_ProjectileStageID() then
//Move projectiles
set x = GetUnitX(udg_NP_Unit[node]) + udg_NP_XVel[node]
set y = GetUnitY(udg_NP_Unit[node]) + udg_NP_YVel[node]
set udg_NP_ZVel[node] = udg_NP_ZVel[node] - NP_Gravity()
set udg_NP_CurrentZ[node] = udg_NP_CurrentZ[node] + udg_NP_ZVel[node]
if NP_ValidateLocation(x, y) then
call SetUnitX(udg_NP_Unit[node], x)
call SetUnitY(udg_NP_Unit[node], y)
endif
set x2 = udg_NP_CurrentZ[node] - NP_GetZ(x,y)
call SetUnitFlyHeight(udg_NP_Unit[node], x2, 0.)
if x2 < 0 then
//Crash, remove projectile data
call DestroyEffect(udg_NP_CurrentEffect[node])
call KillUnit(udg_NP_Unit[node])
call NP_RecycleNode(node)
//Create summon
set tempNode = NP_CreateNode()
set udg_NP_Unit[tempNode] = CreateUnit(udg_NP_Player[udg_NP_Instance[node]], NP_SummonedUnitID(), x, y, GetUnitFacing(udg_NP_Unit[node]))
call UnitApplyTimedLife(udg_NP_Unit[tempNode], NP_SummonBuffID(), udg_NP_SummonDuration[udg_NP_Instance[node]])
call SetUnitScale(udg_NP_Unit[tempNode], udg_NP_SummonSize[udg_NP_Instance[node]], 0., 0.)
call UnitAddAbility(udg_NP_Unit[tempNode], NP_InfectAbilityID())
call SetUnitAbilityLevel(udg_NP_Unit[tempNode], NP_InfectAbilityID(), udg_NP_SummonLevel[udg_NP_Instance[node]])
//Apply bonuses to stats
call CSS_AddBonus(udg_NP_Unit[tempNode], udg_NP_SummonArmour[udg_NP_Instance[node]], 0)
call CSS_AddBonus(udg_NP_Unit[tempNode], udg_NP_SummonAttackSpeed[udg_NP_Instance[node]], 1)
call CSS_AddBonus(udg_NP_Unit[tempNode], udg_NP_SummonAttackDamage[udg_NP_Instance[node]], 2)
call CSS_AddBonus(udg_NP_Unit[tempNode], udg_NP_SummonHealthRegen[udg_NP_Instance[node]], 6)
call CSS_AddBonus(udg_NP_Unit[tempNode], udg_NP_SummonHealth[udg_NP_Instance[node]], 8)
//Set up logic
set udg_NP_StageID[tempNode] = NP_NanobotStageID()
set udg_NP_Instance[tempNode] = udg_NP_Instance[node]
set udg_NP_Caster[tempNode] = udg_NP_Caster[udg_NP_Instance[node]]
endif
//Nanobots produced by the spell
elseif udg_NP_StageID[node] == NP_NanobotStageID() then
//Check if it's still alive
if (IsUnitType(udg_NP_Unit[node], UNIT_TYPE_DEAD)) then
set udg_NP_SwarmStrength[udg_NP_Instance[node]] = udg_NP_SwarmStrength[udg_NP_Instance[node]] - 1
//Recycling
call FlushChildHashtable(udg_CSS_Hashtable, GetHandleId(udg_NP_Unit[node]))
call NP_RecycleNode(node)
else
//Apply buff
call CSS_ClearBonus(udg_NP_Unit[node], 2)
call CSS_AddBonus(udg_NP_Unit[node], udg_NP_SummonAttackDamage[udg_NP_Instance[node]] + udg_NP_SwarmStrengthBonus[udg_NP_Instance[node]], 2)
endif
//Infection buffs
elseif udg_NP_StageID[node] == NP_BuffStageID() then
//Update location of Buffs
set x = GetUnitX(udg_NP_Caster[node])
set y = GetUnitY(udg_NP_Caster[node])
set x2 = x + udg_NP_Offset[node] * Cos(udg_NP_BuffAngle[node])
set y2 = y + udg_NP_Offset[node] * Sin(udg_NP_BuffAngle[node])
call SetUnitX(udg_NP_Unit[node], x2)
call SetUnitY(udg_NP_Unit[node], y2)
call SetUnitFlyHeight(udg_NP_Unit[node], GetUnitFlyHeight(udg_NP_Caster[node]) + NP_BuffHeightOffset() + (NP_GetZ(x, y) - NP_GetZ(x2, y2)), 0.)
//Infection instances that are no longer producing
elseif udg_NP_SwarmStrength[udg_NP_Instance[node]] > 0 then
set udg_NP_SwarmStrengthBonus[node] = NP_SwarmStrengthAttackBonus(udg_NP_SwarmStrength[node])
else
call NP_DestroyBuff(udg_NP_BuffNode[node], udg_NP_Unit[node])
call NP_RecycleNode(node)
//If the unit has no other infections, remove the buff
if NP_GetInfections(udg_NP_Unit[node]) == 0 then
call UnitRemoveAbility(udg_NP_Unit[node], NP_BuffID())
//Stop the timer if this was the last instance
if (udg_NP_PrevNode[0] == 0) then
call PauseTimer(udg_NP_Timer)
endif
endif
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// Function used to start an instance of the plague //
////////////////////////////////////////////////////////////////////
function NP_StartPlague takes nothing returns boolean
//Set up locals
local integer node
local integer spellID = GetSpellAbilityId()
local integer instance
local integer infections
local integer ilevel
local real rlevel
local unit u
local unit u2
local boolean bNew = false
local boolean bTargetSelf = false
//Check if something was infected
if spellID == NP_AbilityID() or spellID == NP_InfectAbilityID() then
set u = GetSpellTargetUnit()
set u2 = GetTriggerUnit()
//Check if a the unit was infected by a summoned unit or by itself
if spellID == NP_InfectAbilityID() then
set infections = NP_GetInfections(u)
set instance = NP_GetNode(u2)
//Check if the unit has been infected from this instance before
if GetUnitTypeId(u) == NP_SummonedUnitID() or NP_IsInfected(u, udg_NP_Instance[instance]) or (infections >= NP_InfectionLimit()) then
//Deal bonus damage when attempting to infect
call UnitDamageTarget(u2, u, udg_NP_HealthDamage[instance], true, false, NP_AttackType(), NP_DamageType(), NP_WeaponType())
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_NP_ManaDamage[instance])
//Instantly create a clone
if GetRandomReal(0, 1) <= udg_NP_DuplicationChance[udg_NP_Instance[instance]] then
call NP_CreateProjectile(GetUnitX(udg_NP_Unit[instance]), GetUnitY(udg_NP_Unit[instance]), GetUnitFlyHeight(udg_NP_Unit[instance]), udg_NP_Instance[instance])
set udg_NP_SwarmStrength[udg_NP_Instance[instance]] = udg_NP_SwarmStrength[udg_NP_Instance[instance]] + 1
endif
else
//Remove the infecting unit
set bTargetSelf = true
call RemoveUnit(udg_NP_Unit[instance])
call NP_RecycleNode(instance)
set bNew = true
endif
else
//Prevent targetting of other units
if not(u == u2) then
set u = u2
else
set bTargetSelf = true
endif
set infections = NP_GetInfections(u)
if infections < NP_InfectionLimit() then
set bNew = true
endif
endif
//Check if a new instance needs to be created
if (bNew) then
//Initialise Noe
set node = NP_CreateNode()
if udg_NP_PrevNode[node] == 0 then
call TimerStart(udg_NP_Timer, NP_TimerSpeed(), true, function NP_Loop)
endif
//Set up plague data
set ilevel = GetUnitAbilityLevel(u2, spellID)
set rlevel = ilevel
set udg_NP_Unit[node] = u
set udg_NP_Player[node] = GetTriggerPlayer()
set udg_NP_StageID[node] = NP_InfectionStageID()
set udg_NP_BuffNode[node] = NP_CreateBuff(u, infections, rlevel, udg_NP_Player[node])
set udg_NP_TargetSelf[node] = bTargetSelf
set udg_NP_TargetX[node] = GetSpellTargetX()
set udg_NP_TargetY[node] = GetSpellTargetY()
set udg_NP_ProductionDelay[node] = 1 / NP_ProductionPS(rlevel)
set udg_NP_CurrentProductionDelay[node] = udg_NP_ProductionDelay[node]
set udg_NP_InfectionDuration[node] = NP_InfectDuration(rlevel)
//Pass instance along if the unit was infected by an existing plague
if spellID == NP_InfectAbilityID() then
set udg_NP_Instance[node] = udg_NP_Instance[instance]
set udg_NP_Caster[node] = udg_NP_Caster[instance]
set udg_NP_SwarmStrength[node] = 0
else
//Set up data only needed by the original instance
set udg_NP_Instance[node] = node
set udg_NP_Caster[node] = u
set udg_NP_SwarmStrength[node] = 1
set udg_NP_AOE[node] = NP_AOE(rlevel)
set udg_NP_ProjectileSize[node] = NP_ProjectileSize(rlevel)
set udg_NP_ProjectileFlightTime[node] = NP_ProjectileFlightTime(rlevel)
set udg_NP_InfectionDamageHealth[node] = NP_InfectDPSHealth(rlevel) * NP_TimerSpeed()
set udg_NP_InfectionDamageMana[node] = NP_InfectDPSMana(rlevel) * NP_TimerSpeed()
set udg_NP_DuplicationChance[node] = NP_InstantDuplicationChance(rlevel)
set udg_NP_HealthDamage[node] = NP_InfectBonusDamageHealth(rlevel)
set udg_NP_ManaDamage[node] = NP_InfectBonusDamageMana(rlevel)
set udg_NP_SummonDuration[node] = NP_SummonDuration(rlevel)
set udg_NP_SummonSize[node] = NP_SummonSize(rlevel)
set udg_NP_SummonHealth[node] = NP_SummonHealthBonus(ilevel)
set udg_NP_SummonHealthRegen[node] = NP_SummonHealthRegenBonus(ilevel)
set udg_NP_SummonArmour[node] = NP_SummonArmourBonus(ilevel)
set udg_NP_SummonAttackDamage[node] = NP_SummonAttackDamageBonus(ilevel)
set udg_NP_SummonAttackSpeed[node] = NP_SummonAttackSpeedBonus(ilevel)
set udg_NP_SummonLevel[node] = ilevel
endif
//Add buff if this is the first infection
if infections == 0 then
call UnitAddAbility(udg_NP_Unit[node], NP_BuffID())
endif
endif
set u2 = null
set u = null
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// Function used to enable automatic infections //
////////////////////////////////////////////////////////////////////
function NP_AutoInfection takes nothing returns boolean
local unit u = GetAttacker()
if GetUnitTypeId(u) == NP_SummonedUnitID() then
call IssueTargetOrderById(u, NP_AttackOrder(), GetTriggerUnit())
endif
set u = null
return false
endfunction
////////////////////////////////////////////////////////////////////
// Function used to register the trigger of the ability //
////////////////////////////////////////////////////////////////////
function InitTrig_Nano_Plague takes nothing returns nothing
//Set up local variables
local trigger t = CreateTrigger()
//Set up trigger
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function NP_StartPlague))
set udg_NP_ZLoc = Location(0., 0.)
//Create the trigger which automates the infection process if wanted
if NP_AutoInfect() then
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ATTACKED)
call TriggerAddCondition(t, Condition(function NP_AutoInfection))
endif
//Sets up the variables used to make sure a point is within the map area
set udg_NP_MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set udg_NP_MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
set udg_NP_MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set udg_NP_MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
////////////////////////////////////////////////////////////////////
//END OF THE SPELL //
////////////////////////////////////////////////////////////////////