1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  5. Travel to distant realms and encounter scenes unknown to the common folk. The Greatest of Adventures is upon us with the 8th Cinematic Contest. Join in on a fun ride.
    Dismiss Notice
  6. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  7. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  8. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  9. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  10. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Nano Plague V1.00

Submitted by Tank-Commander
This bundle is marked as approved. It works and satisfies the submission rules.
Zephyr Contest #14 Winning entry - Nano Plague

Tooltip

Icon
[​IMG]


W - Nano Plague
Releases a nanobot into the caster which consumes them to replicate itself for a few seconds. replicas are thrown out at the target point to seek more things to infect propagating the process

Strength in numbers: The more nanobots alive the stronger each one becomes
Fieldwork: nanobots may instantly replicate when attempting to infect a unit

Level 1 - Nanobot, 5 second infection, 8 second duration, consumes 250 health. Infects Mechanicals
Level 2 - Microbot, 6 second infection, 10 second duration, consumes 450 health. Infects Mechanicals
Level 3 - Minibot, 7 second infection, 12 second duration, consumes 700 health. Infects Mechanicals


Code

Show
Code (vJASS):

////////////////////////////////////////////////////////////////////
//                       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                                                //
////////////////////////////////////////////////////////////////////
 



Spellset Information

- 912 lines of pure JASS
- 43 Configurables reaching all aspects of the ability
- 1 ability 2 parts, compact and powerful
- Extensive Readme to help you configure the ability
- Doesn't interfere with game scorescreen
- Compatiable with Vanilla WE
- Functions for ground and flying heros
- Arcs are stable on uneven terrain
- Features can be adapted to your liking due to the configuration including complete removal
- Attractive yet functional
- Summon stats are almost entirely controlled through Code leading to only one unit being needed for the summon
- Plagues are team coloured!
- Easy to reach target filtering (done through object data)
- Ignores magic immune enemies correctly
- Variable reuse reduces the amount of variables to import to 40
- Buffs for all status conditions
- Works well as an "ultimate Pocket Factory"
- Swapping out models is easy to create a bug plague or other infestation
- Uses a health cost instead of a Manacost

Tips and Tricks

Offensive

- Aim for units you can infect, the Nanobots are stronger the more you have of them, Aiming for the right location can be the difference between a quick failure and a decimating plague
- Nanobots automatically infect susceptible units they find themselves attacking
- You can manually control all of the robots, to infect a unit just tell the robot to attack that unit - if it can infect it, it will
- If you target your own unit with the ability Nanobots will spawn on your location regardless of where you move
- Move the caster away after starting the plague; Nanobots will still be thrown to the target point and reach it in the same time as normal
- Replicated units are thrown back to the original casting area, use this to your advantage when casting on yourself
- High HP infected enemies can be used to prolong an infection via use of the instant replication mechanic
- Nanobots can infect allies so bringing your own mechanical units to a fight can be used to make spawning your swarm easier however they will take a lot of damage as a result of the plague and if positioned poorly the swarm may go to waste

Defensive

- At high levels infected units are done for - run them away from the rest of your army as the Nanobots spawn near their location
- Nanobots have little HP, take them all out with an AOE spell to stop the plague in its tracks
- Nanobots get stronger the more there are of them: Don't let them infect your mechanical units and block their path with other units
- Keep your distance from enemies with mechanicals in their army as they can infect their own units, try to bait the player into using the ability and back off; this will both deal damage to their army without fighting it and waste the nanobots created


Helpful Files

- Variable Creator: Copy and paste into your map, you now have all the variables needed for the spell to run
Variable Creator
  • Variable Creator
    • Events
    • Conditions
    • Actions
      • Set NP_AOE[0] = 0.00
      • Set NP_BuffAngle[0] = 0.00
      • Set NP_BuffNode[0] = 0
      • Set NP_Caster[0] = NP_Unit[0]
      • Set NP_CurrentEffect[0] = NP_CurrentEffect[0]
      • Set NP_CurrentProductionDelay[0] = 0.00
      • Set NP_CurrentZ[0] = 0.00
      • Set NP_DuplicationChance[0] = 0.00
      • Set NP_HealthDamage[0] = 0.00
      • Set NP_InfectionDamageHealth[0] = 0.00
      • Set NP_InfectionDamageMana[0] = 0.00
      • Set NP_InfectionDuration[0] = 0.00
      • Set NP_Instance[0] = 0
      • Set NP_ManaDamage[0] = 0.00
      • Set NP_MapMaxX = 0.00
      • Set NP_MapMaxY = 0.00
      • Set NP_MapMinX = 0.00
      • Set NP_MapMinY = 0.00
      • Set NP_NextNode[0] = 0
      • Set NP_NodeNumber = 0
      • Set NP_Offset[0] = 0.00
      • Set NP_Player[0] = NP_Player[0]
      • Set NP_PrevNode[0] = 0
      • Set NP_ProductionDelay[0] = 0.00
      • Set NP_ProjectileFlightTime[0] = 0.00
      • Set NP_ProjectileSize[0] = 0.00
      • Set NP_RecyclableNodes = 0
      • Set NP_RecycleNodes[0] = 0
      • Set NP_StageID[0] = 0
      • Set NP_SummonArmour[0] = 0
      • Set NP_SummonAttackDamage[0] = 0
      • Set NP_SummonAttackSpeed[0] = 0
      • Set NP_SummonDuration[0] = 0.00
      • Set NP_SummonHealth[0] = 0
      • Set NP_SummonHealthRegen[0] = 0
      • Set NP_SummonLevel[0] = 0
      • Set NP_SummonSize[0] = 0.00
      • Set NP_SwarmStrength[0] = 0
      • Set NP_SwarmStrengthBonus[0] = 0
      • Set NP_TargetSelf[0] = False
      • Set NP_TargetX[0] = 0.00
      • Set NP_TargetY[0] = 0.00
      • Set NP_Timer = NP_Timer
      • Set NP_XVel[0] = 0.00
      • Set NP_YVel[0] = 0.00
      • Set NP_ZLoc = NP_ZLoc
      • Set NP_ZVel[0] = 0.00



WIP Links

- http://www.hiveworkshop.com/forums/...ique-summoning-278518/index9.html#post2819652
- http://www.hiveworkshop.com/forums/...ique-summoning-278518/index9.html#post2819723
- http://www.hiveworkshop.com/forums/...que-summoning-278518/index10.html#post2819885
- http://www.hiveworkshop.com/forums/...que-summoning-278518/index10.html#post2819910
- http://www.hiveworkshop.com/forums/...que-summoning-278518/index11.html#post2819921

Images


Contents

Nano Plague V1.00 (Map)

  1. KILLCIDE

    KILLCIDE

    Administrator

    Joined:
    Jul 22, 2015
    Messages:
    3,497
    Resources:
    20
    Models:
    2
    Icons:
    10
    Spells:
    7
    Tutorials:
    1
    Resources:
    20
    Well documented code, awesome spell mechanic, and a lot of configurables (that are also well documented!). I see no reason for the first place entry to sit in Submissions any longer.

    Approved
     
  2. KILLCIDE

    KILLCIDE

    Administrator

    Joined:
    Jul 22, 2015
    Messages:
    3,497
    Resources:
    20
    Models:
    2
    Icons:
    10
    Spells:
    7
    Tutorials:
    1
    Resources:
    20
    Sorry for the update. I went ahead and added the Contest Entry tag.