- Joined
- Jul 22, 2015
- Messages
- 3,485
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
Approved
Tooltip
W - Nano Plague
Icon
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
JASS://////////////////////////////////////////////////////////////////// // 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
- 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
- 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
- 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
ImagesTooltip
Levels
Showcases
GIFs
Level 1
Level 2
Level 3
Distribution
Buff
Teamcolouring
Multiple Infection
Mixed Infection
Ongoing Assault
Assault Remains
Basic Cast
Infectious Assault
Follow Caster