Modifying this spell

NeuroToxin

New Member
Reaction score
46
Okay, the spell is called Robot Arms by Inferior. I love the spell and am using it, the only problem, is that in my map its like a hero FFA. And the problem is that, if its a 1v1, then the arms will continuously stun the other hero until it's dead. That's a problem. Because then they can't do anything. But if I set the stun too small, the sfx are crap. Heres the code, what can I add so that way the hero can only be damaged say per 10 seconds once.
JASS:

library RobotArms initializer Init needs Table, GroupUtils, TimerUtils, ABuff, ABuffHeroSkill, BoundSentinel, UnitStatus, IsUnitSpellResistant, xebasic, xefx, xedamage, Rounding
//********************************************************************************************\\
//********************************************************************************************\\
//*                                   Robot Arms By Inferior                                 *\\
//*                                                                                          *\\
//*                                          v1.3                                            *\\
//*                                                                                          *\\
//*                                 **************************                               *\\
//*                                 * Requirements:          *                               *\\
//*                                 * - JassNewGenPack       *                               *\\
//*                                 * - Table                *                               *\\
//*                                 * - GroupUtils           *                               *\\
//*                                 * - TimerUtils           *                               *\\
//*                                 * - ABuff                *                               *\\
//*                                 * - ABuffHeroSkill       *                               *\\
//*                                 * - BoundSentinel        *                               *\\
//*                                 * - UnitStatus           *                               *\\
//*                                 * - IsUnitSpellResistant *                               *\\
//*                                 * - xebasic              *                               *\\
//*                                 * - xefx                 *                               *\\
//*                                 * - xedamage             *                               *\\
//*                                 * - Rounding             *                               *\\
//*                                 **************************                               *\\
//*                                                                                          *\\
//*                                                                                          *\\
//*                                                                                          *\\
//* How To Import:                                                                           *\\
//* - Copy the Spell called 'Robot Arms', the dummy called facingdummy into your map         *\\
//*   and import the "fdummy.mdl" and "RoboticArmsHand" included in this map into yours      *\\
//* - Copy the whole Triggerscript into your map                                             *\\
//* - Change the model of your new Dummymodel and change the RawCodes of the ABILID          *\\
//*   and CHAINID to the Rawcodes in your map                                                *\\
//*                                                                                          *\\
//*    Spelldescription:                                                                     *\\
//*    The Electrician uses his technical knowlegdes to create 3 Robot Arms that act on      *\\
//*    their own. If the Arm detects an enemy, it moves to that enemy and knocks it out on   *\\
//*    contact, dealing absorbing the enemies Life. If the Electrician moves out of the      *\\
//*    enemies Range the Arm moves back. After every action, the Arms have to move back into *\\
//*    their default Position.                                                               *\\
//*                                                                                          *\\
//********************************************************************************************\\
//********************************************************************************************\\
// Globals Setting

    globals
        private constant integer        ABILID          = 'A00J'
        // The AbilityId of your Main Ability
        
        private constant integer        CHAINID         = 'e002'
        // The Rawcode for your dummy. This dummy needs a specific model included in that map. You need this model if you want the full eyecandy
        
        private constant integer        MAXARMS         = 3
        // The Number of Arms. The more arms you use, the higher is the performance lack.
        
        private constant integer        CHAINPARTS      = 16
        // The Parts of Dummies for the Chain of the arm. Do not forget to change the .chain array in the struct.
        
        private constant real           CHAINSIZE       = 1.3
        // The Size of the Chain parts
        
        private constant real           BIRTHSIZE       = 0.5 
        // The Size at which the Chain parts start
        
        private constant real           BIRTHDURATION   = 1.
        // The Duration until the Chain reach its full size
        
        private constant real           ARMSPEED        = 12.
        // The Speed an arm is moving back or to a target
        
        private constant real           DMGTOHEALTH     = 1.
        // Conversionfactor from damage dealt to absorbed Health. This value is only active if USEABSORB = true
        
        private constant real           HEALTHFACTOR    = 0.05
        // The Factor of the targets MaxHealth that is absorbed. This value is only active if USEABSORB = true
        
        private constant real           DEALTDAMAGE     = 1.5 
        // Damage dealt per Period: 0.025*40=1 -> 40*1.5= 60 damage dealt per second. This value is only active if USEABSORB = false
        
        private constant real           DETECTIONRADIUS = 500.
        // The Radius in which an Arm detects an enemy
        
        private constant real           DEFAULTOFFSET   = 250.
        // The Default offset from the Electricians Position. Also defines the DefaultPosition where the arms move back to
        
        private constant real           DEFAULTHEIGHT   = 75.
        // The Default Height of the Chains
        
        private constant real           MAXHEIGHT       = 350.
        // The Maximum Height that can be reached by the arm
        
        private constant real           MINHEIGHT       = 150.
        // The Minimum Height that can be reached by the arm
        
        private constant real           MAXOFFSET       = 750.
        // The Maximum Range an arm can bent
        
        private constant string         CHAINMDL        = "RoboticArmsHand.mdx"
        // The Chains Model effect
        
        private constant string         CHAINATTACH     = "origin"
        // DO NOT CHANGE THIS (the dummy model has no other attachement)
        
        private constant string         CHAINHAND       = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
        // The End of the Arms effect
        
        private constant string         ABSORBMDL       = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"
        // The Effect that is used if USEABSORB = true
        
        private constant boolean        USEABSORB       = true
        // This value defines the type of damage that is dealt. if USEABSORB = false then the damage is dealt periodicly. 
        // For more informations check the .OnAbsorb method.
        
        private          real     array SHOCKTIME
        // The Value that defines the time an arm deals damage to a target. 
        
        // DO NOT CHANGE THIS. Defines the Damage types.
        private          xedamage       dmgOptions
        // DO NOT CHANGE THIS.
        private          unit           TEMPUNIT
        private constant integer        StunCode        = 'BPSE'
    endglobals
    
    private keyword Arm
    
    
    private function SetupSpellVariables takes nothing returns nothing
        set SHOCKTIME[1]=2
        set SHOCKTIME[2]=3
        set SHOCKTIME[3]=4
        set SHOCKTIME[4]=5
    endfunction
    
    private function ConfigureDamageOptions takes nothing returns nothing
        set dmgOptions=xedamage.create()
        set dmgOptions.atype=ATTACK_TYPE_CHAOS
        set dmgOptions.dtype=DAMAGE_TYPE_UNIVERSAL
        set dmgOptions.wtype=WEAPON_TYPE_WHOKNOWS
    endfunction
    
    private function UnitFilter takes nothing returns boolean
        return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(TEMPUNIT)) and IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and not IsUnitSpellImmune(GetFilterUnit()) and not Arm.stunned[GetUnitId(GetFilterUnit())] and GetWidgetLife(GetFilterUnit())>0.405 and GetUnitTypeId(GetFilterUnit())!=CHAINID
    endfunction
    
    // DO NOT TOUCH ANYTHING BELOW THIS COMMENT, ALTHOUGH YOU KNOW WHAT YOU DO.
    // HERE BEGINS THE SPELLS SCRIPT.
    
    private function AngleConv takes real angle returns real
        local integer factor=0
        if angle>=360 then
            set factor=R2I(angle/360)
            return angle-360*factor
        elseif angle<0 then
            set factor=R2I(AbsReal(angle)/360)
            return angle+360*(factor+1)
        endif
        return angle
    endfunction
    
    private function HeightCalc takes real d returns real
        return ((MINHEIGHT-MAXHEIGHT+DEFAULTHEIGHT)/MAXOFFSET)*d+MAXHEIGHT-DEFAULTHEIGHT
    endfunction
    
    // This function defines the Arm parts height
    private function ArmHeight takes real d, integer z returns real
        return HeightCalc(d)*Sin( bj_PI/CHAINPARTS * z ) + DEFAULTHEIGHT
    endfunction 
    
    // Defines the Arm parts Z-Facing.
    // THIS FUNCTION STILL NEEDS PERFECTION. IM STILL SEARCHING FOR A BETTER FORMULA
    private function UnitZFacing takes unit u, real d, integer z returns nothing
        local real s=(MAXHEIGHT-(MAXHEIGHT-MINHEIGHT)/2)/HeightCalc(d)
        local real a=s*HeightCalc(d) * bj_PI/CHAINPARTS * Cos(bj_PI/CHAINPARTS * z)
        local boolean b=a<0
        local integer v=RealRounding(AbsReal(a))
        if not b then
            call SetUnitAnimationByIndex(u,v)
        else
            call SetUnitAnimationByIndex(u,252-v)
        endif
    endfunction
    
    
    // Defines an arms Defaultpositions Facing
    private constant function Angles takes integer int returns real
        return 360./MAXARMS * int
    endfunction
    
    
    private struct Arm
        unit caster
        unit array chain[17] // Add here the value of the CHAINPARTS + 1
        unit hand
        unit targ
        integer pos=CHAINPARTS
        integer phase=0
        // 0=birth
        // 1=search after an enemy
        // 2=haunt an enemy
        // 3=shock an enemy
        // 4=out of range
        real angle
        real startangle
        real offset
        real timed
        
        xefx absorb 
        // this effect is only used if USEABSORB = true
        
        readonly integer index
        
        static integer count=0
        static boolean array done
        static boolean array stunned
        static timer ArmTimer
        static Arm array Data
        static Table array ArmTable
        static Table array HTable
        
        // You may change this function if you want.
        method OnAbsorb takes nothing returns nothing
            if USEABSORB then
                // the time between these too actions is proportional to the number of Chainparts
                if .pos==CHAINPARTS then
                    // this is executed when the Absorption effect runs off the target.
                    call dmgOptions.damageTarget(.caster,.targ,GetUnitState(.targ,UNIT_STATE_MAX_LIFE)*HEALTHFACTOR)
                elseif .pos<0 then
                    // this is executed when the Absorption effect reaches the caster
                    call SetWidgetLife(.caster,GetWidgetLife(.caster)+GetUnitState(.targ,UNIT_STATE_MAX_LIFE)*HEALTHFACTOR*DMGTOHEALTH)
                endif
            else
                // this is executed when USEABSORB=false
                // this is executed once per Timerperiod: every 0.025 seconds
                call dmgOptions.damageTarget(.caster,.targ,DEALTDAMAGE)
            endif
        endmethod
            
        // destroys the Arm on Casters death or Unlearning of the MainAbility
        method KillArm takes nothing returns boolean
            local integer int=0
            loop
                exitwhen int>CHAINPARTS
                call KillUnit(.chain[int])
                set int=int+1
            endloop
            call KillUnit(.hand)
            return true
        endmethod
        
        // sets an Arms Position and the parts Height and facing
        method PosNormal takes real offset returns nothing
            local real dx=GetUnitX(.hand)-GetUnitX(.caster)
            local real dy=GetUnitY(.hand)-GetUnitY(.caster)
            local integer i=0
            local real step=0.
            set .offset=offset
            set .angle=Atan2(dy,dx)
            if .offset>MAXOFFSET then
                set .offset=MAXOFFSET
            endif
            set step=.offset/CHAINPARTS
            loop
                exitwhen i>CHAINPARTS
                call SetUnitX(.chain<i>,GetUnitX(.caster)+step*i*Cos(.angle))
                call SetUnitY(.chain<i>,GetUnitY(.caster)+step*i*Sin(.angle))
                call SetUnitFacing(.chain<i>,.angle*180/bj_PI)
                call SetUnitFlyHeight(.chain<i>,ArmHeight(.offset,i),0)
                set i=i+1
            endloop
            call SetUnitX(.hand,GetUnitX(.chain[CHAINPARTS]))
            call SetUnitY(.hand,GetUnitY(.chain[CHAINPARTS]))
            call SetUnitFlyHeight(.hand,GetUnitFlyHeight(.chain[CHAINPARTS]),0)
        endmethod
        
        // Creates an arm on Casters revive or Learning of the Ability
        method createChain takes nothing returns nothing
            local real x=GetUnitX(.caster)
            local real y=GetUnitY(.caster)
            local integer count=CHAINPARTS
            local real dx=.offset/count
            local integer int=0
            loop
                exitwhen int&gt;count
                set .chain[int]=CreateUnit(GetOwningPlayer(.caster),CHAINID,x,y,.angle)
                call SetUnitScale(.chain[int],CHAINSIZE,CHAINSIZE,CHAINSIZE)
                call SetUnitTimeScale(.chain[int],0.)
                call UnitZFacing(.chain[int],.offset,int)
                call UnitAddAbility(.chain[int],XE_HEIGHT_ENABLER)
                call UnitRemoveAbility(.chain[int],XE_HEIGHT_ENABLER)
                call SetUnitX(.chain[int],x+dx*Cos(.angle*bj_PI/180)*int)
                call SetUnitY(.chain[int],y+dx*Sin(.angle*bj_PI/180)*int)
                call SetUnitFlyHeight(.chain[int],ArmHeight(.offset,int),0)
                call AddSpecialEffectTarget(CHAINMDL,.chain[int],CHAINATTACH)
                set int=int+1
            endloop
            set .hand=CreateUnit(GetOwningPlayer(.caster),CHAINID,GetUnitX(.chain[CHAINPARTS]),GetUnitY(.chain[CHAINPARTS]),.angle)
            call UnitAddAbility(.hand,XE_HEIGHT_ENABLER)
            call UnitRemoveAbility(.hand,XE_HEIGHT_ENABLER)
            call SetUnitFlyHeight(.hand,GetUnitFlyHeight(.chain[CHAINPARTS]),0)
            call AddSpecialEffectTarget(CHAINHAND,.hand,CHAINATTACH)
        endmethod
        
        static method callback takes nothing returns nothing
            local integer int=0
            local Arm data
            local group g
            local unit a
            local real dx
            local real dy
            loop
                exitwhen int==Arm.count
                if not Arm.done[int] then
                    set data=Arm.Data[int]
                    
                    // Searchs possible targets for the Arm
                    if data.phase==0 then
                    
                        set TEMPUNIT=data.caster
                        call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(data.hand),GetUnitY(data.hand),DETECTIONRADIUS,Condition(function UnitFilter))
                        set data.targ=GroupPickRandomUnit(ENUM_GROUP)
                        set TEMPUNIT=null
                        
                        call GroupClear(ENUM_GROUP)
                        
                        if data.targ!=null then
                            set data.phase=1
                        else
                            set data.angle=GetUnitFacing(data.caster)+data.startangle
                            call SetUnitX(data.hand,GetUnitX(data.caster)+DEFAULTOFFSET*Cos(data.angle*bj_DEGTORAD))
                            call SetUnitY(data.hand,GetUnitY(data.caster)+DEFAULTOFFSET*Sin(data.angle*bj_DEGTORAD))
                            call data.PosNormal(DEFAULTOFFSET)
                        endif
                        
                    // Moves the Arm to an target. If the target is out of range the arm moves back into DefaultPosition
                    elseif data.phase==1 then
                    
                        set dx=GetUnitX(data.targ)-GetUnitX(data.hand)
                        set dy=GetUnitY(data.targ)-GetUnitY(data.hand)
                        set data.angle=Atan2(dy,dx)
                        call SetUnitX(data.hand,GetUnitX(data.hand)+ARMSPEED*Cos(data.angle))
                        call SetUnitY(data.hand,GetUnitY(data.hand)+ARMSPEED*Sin(data.angle))
                        set dx=GetUnitX(data.hand)-GetUnitX(data.caster)
                        set dy=GetUnitY(data.hand)-GetUnitY(data.caster)
                        set data.angle=Atan2(dy,dx)
                        set data.offset=SquareRoot(dx*dx+dy*dy)
                        call data.PosNormal(data.offset)
                        
                        if data.offset&gt;=MAXOFFSET then
                            set data.phase=3
                        endif
                        
                        if Arm.stunned[GetUnitId(data.targ)] then
                            set data.phase=3
                        else
                            if IsUnitInRange(data.hand,data.targ,5.0) then
                                call SetUnitX(data.hand,GetUnitX(data.targ))
                                call SetUnitY(data.hand,GetUnitY(data.targ))
                                set dx=GetUnitX(data.hand)-GetUnitX(data.caster)
                                set dy=GetUnitY(data.hand)-GetUnitY(data.caster)
                                set data.angle=Atan2(dy,dx)
                                set data.offset=SquareRoot(dx*dx+dy*dy)
                                if data.offset&gt;=MAXOFFSET then
                                    set data.phase=3
                                else
                                    call data.PosNormal(data.offset)
                                    call StunUnit(data.targ,true)
                                    set Arm.stunned[GetUnitId(data.targ)]=true
                                    set data.phase=2
                                    if USEABSORB then
                                        set data.absorb=xefx.create(GetUnitX(data.chain[.chain.size]),GetUnitY(data.chain[.chain.size]),GetUnitFacing(data.chain[.chain.size]))
                                        set data.absorb.fxpath=ABSORBMDL
                                    endif
                                endif
                            endif
                        endif
                        
                    // If the arm reached an enemy, the enemy is stunned and is sucked hp or damaged based on the USEABSORB value.
                    // The Arm moves back to default Position if the target moves out of range, or the Buff on the target is removed.
                    elseif data.phase==2 then
                        set dx=GetUnitX(data.targ)-GetUnitX(data.caster)
                        set dy=GetUnitY(data.targ)-GetUnitY(data.caster)
                        set data.angle=Atan2(dy,dx)
                        set data.offset=SquareRoot(dx*dx+dy*dy)
                        
                        if data.offset&gt;=MAXOFFSET then
                            set data.phase=3
                            call StunUnit(data.targ,false)
                            set Arm.stunned[GetUnitId(data.targ)]=false
                            set data.timed=0
                            set data.pos=CHAINPARTS
                            set data.targ=null
                            if USEABSORB then
                                call data.absorb.hiddenDestroy()
                            endif
                        else
                            call SetUnitX(data.hand,GetUnitX(data.targ))
                            call SetUnitY(data.hand,GetUnitY(data.targ))
                            call data.PosNormal(data.offset)
                            set data.timed=data.timed+0.025
                            if USEABSORB then
                                set data.absorb.x=GetUnitX(data.chain[data.pos])
                                set data.absorb.y=GetUnitY(data.chain[data.pos])
                                set data.absorb.z=GetUnitFlyHeight(data.chain[data.pos])
                                if data.pos&lt;0 then
                                    call data.absorb.hiddenDestroy()
                                    call data.OnAbsorb()
                                    set data.pos=CHAINPARTS
                                    set data.absorb=xefx.create(GetUnitX(data.chain[.chain.size]),GetUnitY(data.chain[.chain.size]),GetUnitFacing(data.chain[.chain.size]))
                                    set data.absorb.fxpath=ABSORBMDL
                                endif
                                if data.pos==CHAINPARTS then
                                    call data.OnAbsorb()
                                endif
                            else
                                call data.OnAbsorb()
                            endif
                            set data.pos=data.pos-1
                            if data.timed&gt;SHOCKTIME[GetUnitAbilityLevel(data.caster,ABILID)] or GetWidgetLife(data.targ)&lt;0.405 then
                                set data.phase=3
                                call StunUnit(data.targ,false)
                                set Arm.stunned[GetUnitId(data.targ)]=false
                                set data.timed=0
                                set data.pos=CHAINPARTS
                                if USEABSORB then
                                    call data.absorb.hiddenDestroy()
                                endif
                            else
                                call data.PosNormal(data.offset)
                            endif
                        endif
                        
                    // Moves the Arm back to DefaultPosition
                    elseif data.phase==3 then
                    
                        set dx=GetUnitX(data.hand)-GetUnitX(data.caster)-DEFAULTOFFSET*Cos((GetUnitFacing(data.caster)+data.startangle)*bj_DEGTORAD)
                        set dy=GetUnitY(data.hand)-GetUnitY(data.caster)-DEFAULTOFFSET*Sin((GetUnitFacing(data.caster)+data.startangle)*bj_DEGTORAD)
                        set data.angle=Atan2(dy,dx)
                        call SetUnitX(data.hand,GetUnitX(data.hand)-ARMSPEED*Cos(data.angle))
                        call SetUnitY(data.hand,GetUnitY(data.hand)-ARMSPEED*Sin(data.angle))
                        set dx=GetUnitX(data.caster)+DEFAULTOFFSET*Cos((GetUnitFacing(data.caster)+data.startangle)*bj_DEGTORAD)
                        set dy=GetUnitY(data.caster)+DEFAULTOFFSET*Sin((GetUnitFacing(data.caster)+data.startangle)*bj_DEGTORAD)
                        if IsUnitInRangeXY(data.hand,dx,dy,10) then
                            set data.phase=0
                            set data.targ=null
                            set data.offset=DEFAULTOFFSET
                        else
                            set dx=GetUnitX(data.hand)-GetUnitX(data.caster)
                            set dy=GetUnitY(data.hand)-GetUnitY(data.caster)
                            set data.angle=Atan2(dy,dx)
                            set data.offset=SquareRoot(dx*dx+dy*dy)
                            call data.PosNormal(data.offset)
                        endif
                    endif
                endif
                set int=int+1
            endloop
        endmethod
        
        static method create takes nothing returns Arm
            local Arm data=Arm.allocate()
            if Arm.count==0 then
                set Arm.ArmTimer=NewTimer()
                call TimerStart(Arm.ArmTimer,0.025,true,function Arm.callback)
            endif
            set data.index=Arm.count
            set Arm.Data[Arm.count]=data
            set Arm.done[Arm.count]=false
            set Arm.count=Arm.count+1
            return data
        endmethod
    endstruct
    
    globals
        private aBuffType buffType = 0
    endglobals
    
    private function AbilLearn takes aBuff buffType returns nothing
        local integer int=0
        local Arm data
        if Arm.HTable[GetHandleId(buffType.caster)][int]==0 then
            if Arm.ArmTable[buffType]==0 then
                set Arm.ArmTable[buffType]=Table.create()
            endif
            loop
                exitwhen int==MAXARMS
                set Arm.HTable[GetHandleId(buffType.caster)][int]=Table.create()
                set data=Arm.create()
                set Arm.ArmTable[buffType][int]=data
                set data.caster=buffType.caster
                set data.angle=GetUnitFacing(data.caster)+Angles(int)
                set data.startangle=Angles(int)
                set data.offset=DEFAULTOFFSET
                set Arm.HTable[GetHandleId(buffType.caster)][int]=data
                set data.phase=0
                call data.createChain()
                set int=int+1
            endloop
        else 
            loop
                exitwhen int==MAXARMS
                set data=Arm.HTable[GetHandleId(buffType.caster)][int]
                set Arm.done[data.index]=false
                set data.phase=0
                set data.angle=GetUnitFacing(data.caster)+Angles(int)
                set data.startangle=Angles(int)
                set data.offset=DEFAULTOFFSET
                call data.createChain()
                set int=int+1
            endloop
        endif
        
    endfunction
    
    private function CleanArms takes aBuff buffType returns nothing
        local integer int=0
        local Arm data
        loop
            exitwhen int==MAXARMS
            set data=Arm.ArmTable[buffType][int]
            call data.KillArm()
            set Arm.done[data.index]=true
            set int=int+1
        endloop
    endfunction

    private function Init takes nothing returns nothing
        set buffType=aBuffType.create()
        set buffType.eventCreate=AbilLearn
        set buffType.eventCleanup=CleanArms
        set buffType.countsAsBuff=false
        call NewABuffHeroSkill(ABILID,buffType)
        call SetupSpellVariables()
        call ConfigureDamageOptions()
        
        call Preload(CHAINMDL)
        call Preload(CHAINHAND)
        call Preload(ABSORBMDL)
        call PreloadStart()
    endfunction

endlibrary
</i></i></i></i>
 

Laiev

Hey Listen!!
Reaction score
188
NeuroToxin, to do things that you request, you'll need to learn vJass for most of the things..
 

Risen

New Member
Reaction score
4
Give us an example of a failed attempt at making a timer and we'll tell you what you did wrong.
 

emjlr3

Change can be a good thing
Reaction score
395
at the end of [ljass]OnAbsorb[/ljass]. this fires when a target is hit - add it to a group, start a timer, and remove the unit from the group after the timer expiration. Add a check in [ljass]UnitFilter[/ljass] as to whether a unit is in this do not target group.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top