• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJASS] Knockback System Help

Status
Not open for further replies.
Level 5
Joined
Feb 22, 2013
Messages
161
I am creating a knockback script for a campaign my friend is making, and so far the syntax checks out but for some reason it doesn't even register the event

JASS:
library KnockbackAttack

	globals
		private real KB_distanceTotal = 500.00
		private real KB_interval = 0.035
		private integer KB_totalExecutions = R2I(KB_distanceTotal/KB_interval)
		private real KB_moveDistanceLoop = 2*KB_distanceTotal/(KB_totalExecutions + 1)
		private real KB_moveDistanceLoopDecel = KB_moveDistanceLoop/KB_totalExecutions
		private real KB_damageDealt = 800.00
		private timer KB_loopTimer = CreateTimer()
		private integer KB_newestIndex = 0
		private integer array KB_structCurrentIndex
	endglobals

	struct KnockbackStruct
		unit attackedUnit
		real angle
		effect targetEffect
		integer counter
		
		static method create takes unit u, real a returns thistype
			local thistype this = thistype.allocate()
			
			set KB_newestIndex = KB_newestIndex + 1
			set this.attackedUnit = u
			set this.angle = a
			set this.targetEffect = AddSpecialEffectTarget("Abilities\\Spells\\Other\\Silence\\SilenceAreaBirth.mdl", u, "chest")
			set this.counter = 0
			
			call BJDebugMsg("KB Struct Instance Created.")
			
			call SetUnitPosition(this.attackedUnit, GetUnitX(this.attackedUnit), GetUnitY(this.attackedUnit))
			call PauseUnit(this.attackedUnit, true)
			
			return this
		endmethod
		
		static method KB_unitMove takes nothing returns nothing
			local thistype this
			local integer i = 1
			local real x
			local real y
			
			loop
				exitwhen i > KB_newestIndex
				set this = KB_structCurrentIndex[i]
				set this.counter = this.counter + 1
				if this.counter == KB_totalExecutions then
					call this.destroy()
				elseif this.counter < KB_totalExecutions then
					set x = GetUnitX(this.attackedUnit) + KB_moveDistanceLoop*Cos(this.angle)
					set y = GetUnitY(this.attackedUnit) + KB_moveDistanceLoop*Sin(this.angle)
					
					call SetUnitX(this.attackedUnit, x)
					call SetUnitY(this.attackedUnit, y)
				endif
				set i = i + 1
			endloop
			
			if KB_newestIndex == 0 then
				call PauseTimer(KB_loopTimer)
			endif
		endmethod
		
		 static method setup takes nothing returns nothing
			local thistype this
			local unit u
			local real a
			local group grp
			local real x = GetUnitX(udg_Sauron) + 160.00*Cos(GetUnitFacing(udg_Sauron)*bj_DEGTORAD)
			local real y = GetUnitY(udg_Sauron) + 160.00*Sin(GetUnitFacing(udg_Sauron)*bj_DEGTORAD)
			
			call BJDebugMsg("KB Running Setup.")
			
			call GroupEnumUnitsInRange(grp, x, y, 160.00, null)
			
			loop
				set u = FirstOfGroup(grp)
				set a = (180.00/3.14159265358979323846)*Atan2(GetUnitY(u) - GetUnitY(udg_Sauron), GetUnitX(u) - GetUnitX(udg_Sauron))
                call BJDebugMsg("Enum Unit = " + GetUnitName(u))
				exitwhen u == null
				if u != udg_Sauron then
					set this = thistype.create(u, a)
					set KB_structCurrentIndex[KB_newestIndex] = this
					
					if KB_newestIndex == 1 then
						call TimerStart(KB_loopTimer, KB_interval, true, function thistype.KB_unitMove)
					endif
				endif
				call GroupRemoveUnit(grp, u)
			endloop
			
		endmethod
		
		static method attackConditions takes nothing returns boolean
			if GetAttacker() == udg_Sauron then
				call thistype.setup()
				call BJDebugMsg("KB Condition Registered.")
				return true
			else
				call BJDebugMsg("KB Condition Registered But != Sauron.")
				return false
			endif
		endmethod
		
		static method onInit takes nothing returns nothing
			set gg_trg_KnockbackAttack = CreateTrigger()
			call BJDebugMsg("KB Initialized.")
			call TriggerRegisterAnyUnitEventBJ(gg_trg_KnockbackAttack, EVENT_PLAYER_UNIT_ATTACKED)
			call TriggerAddCondition(gg_trg_KnockbackAttack, Condition(function thistype.attackConditions))
		endmethod
	endstruct
	
endlibrary

Why isn't it?

EDIT: Solved that problem but now the setup method doesn't run the create method

EDIT2: So I figured out that the problem has to do with the loop in the setup method for some reason, because it wouldn't even display the BJDebugMsg in the loop.
 
Last edited:
grp isn't initialized. Change it to:
JASS:
local group grp = CreateGroup()

P.S. for this:
JASS:
        static method attackConditions takes nothing returns boolean
            if GetAttacker() == udg_Sauron then
                call thistype.setup()
                call BJDebugMsg("KB Condition Registered.")
                return true
            else
                call BJDebugMsg("KB Condition Registered But != Sauron.")
                return false
            endif
        endmethod
I recommend changing it. I am not sure how that compiled for you, unless you have an older PJASS. Wc3 might not treat it so well (esp. on later patches). I would change it to:
JASS:
static method attackConditions takes nothing returns boolean
    if GetAttacker() == udg_Sauron then
        call thistype.setup()
        call BJDebugMsg("KB Condition Registered.")
        return true // this could be return false, since you don't have any actions anyway
    endif
    call BJDebugMsg("KB Condition Registered But != Sauron")
    return false
endfunction

Wc3/the syntax checker became very picky about returns after the return bug was removed (and after further exploits, particularly the return nothing bug).
 
Level 5
Joined
Feb 22, 2013
Messages
161
I fixed all the bugs... So now it works well and I added fly height to the units being knockedback..

By the way Purge the boolexpr compiles just fine no errors occured

anyways... How did I do?

JASS:
library KnockbackAttack

	globals
		real KB_distanceTotal = 500.00
		real KB_duration = 1.00
		real KB_interval = 0.035
		integer KB_totalExecutions = R2I(KB_duration/KB_interval)
		real KB_moveDistanceLoop = 2*KB_distanceTotal/(KB_totalExecutions + 1)
		real KB_damageDealt = 800.00
		timer KB_loopTimer = CreateTimer()
		integer KB_newestIndex = 0
		integer array KB_structCurrentIndex
	endglobals

	struct KnockbackStruct
		unit attackedUnit
		real angle
		effect targetEffect
		integer counter
		
		static method create takes unit u returns thistype
			local thistype this = thistype.allocate()
			local real x
			local real y
			
			set KB_newestIndex = KB_newestIndex + 1
			set this.attackedUnit = u
			set this.angle = Atan2(GetUnitY(u) - GetUnitY(udg_Sauron), GetUnitX(u) - GetUnitX(udg_Sauron))
			set this.targetEffect = AddSpecialEffectTarget("Abilities\\Spells\\Other\\Silence\\SilenceAreaBirth.mdl", u, "chest")
			set this.counter = 0
			
			
            call SetUnitAnimation(this.attackedUnit, "death")
			call SetUnitPosition(this.attackedUnit, GetUnitX(this.attackedUnit), GetUnitY(this.attackedUnit))
			call PauseUnit(this.attackedUnit, true)
			call UnitAddAbility(this.attackedUnit, 'Aave')
			call SetUnitFlyHeight(this.attackedUnit, 200.00, 600.00)
			
			return this
		endmethod
		
		method destroy takes nothing returns nothing
			set KB_newestIndex = KB_newestIndex - 1
			
			call PauseUnit(this.attackedUnit, false)
			call SetUnitAnimation(this.attackedUnit, "stand")
			
			call DestroyEffect(this.targetEffect)
			set this.attackedUnit = null
			set this.targetEffect = null
		endmethod
		
		static method KB_unitMove takes nothing returns nothing
			local thistype this
			local integer i = 1
			local real x
			local real y
			
			loop
				exitwhen i > KB_newestIndex
				set this = KB_structCurrentIndex[i]
				set this.counter = this.counter + 1
				if this.counter == KB_totalExecutions then
					set KB_structCurrentIndex[i] = KB_structCurrentIndex[KB_newestIndex]
					call this.destroy()
				elseif this.counter < KB_totalExecutions then
					set x = GetUnitX(this.attackedUnit) + KB_moveDistanceLoop*Cos(this.angle)
                    set y = GetUnitY(this.attackedUnit) + KB_moveDistanceLoop*Sin(this.angle)
                        
                    call SetUnitX(this.attackedUnit, x)
                    call SetUnitY(this.attackedUnit, y)
				endif
				if this.counter >= KB_totalExecutions/2 then
					call SetUnitFlyHeight(this.attackedUnit, GetUnitDefaultFlyHeight(this.attackedUnit), 600.00)
					call UnitRemoveAbility(this.attackedUnit, 'Aave')
				endif
				set i = i + 1
			endloop
			
			if KB_newestIndex == 0 then
				call PauseTimer(KB_loopTimer)
			endif
		endmethod
		
		 static method setup takes nothing returns nothing
			local thistype this
			local unit u
			local group grp = CreateGroup()
			local real x = GetUnitX(udg_Sauron) + 160.00*Cos(GetUnitFacing(udg_Sauron)*bj_DEGTORAD)
			local real y = GetUnitY(udg_Sauron) + 160.00*Sin(GetUnitFacing(udg_Sauron)*bj_DEGTORAD)
			
			
			call GroupEnumUnitsInRange(grp, x, y, 160.00, null)
			
			loop
				set u = FirstOfGroup(grp)
				exitwhen u == null
				if u != udg_Sauron then
					set this = thistype.create(u)
					set KB_structCurrentIndex[KB_newestIndex] = this
					
					if KB_newestIndex == 1 then
						call TimerStart(KB_loopTimer, KB_interval, true, function thistype.KB_unitMove)
					endif
				endif
				call GroupRemoveUnit(grp, u)
			endloop
			
			set grp = null
            set u = null
		endmethod
		
		static method attackConditions takes nothing returns boolean
			if GetAttacker() == udg_Sauron then
				call thistype.setup()
				return true
			else
				return false
			endif
		endmethod
		
		static method onInit takes nothing returns nothing
			set gg_trg_KnockbackAttack = CreateTrigger()
			call TriggerRegisterAnyUnitEventBJ(gg_trg_KnockbackAttack, EVENT_PLAYER_UNIT_ATTACKED)
			call TriggerAddCondition(gg_trg_KnockbackAttack, Condition(function thistype.attackConditions))
		endmethod
	endstruct
	
endlibrary


P.S. I know there is no pathability checks for the knocked units, but it's not needed for the purpose of this library... And I'm not exactly sure how I would go about making that check for pathability...

Also, how do I make it so where when the unit actually hits the knock will begin. Because I've noticed that he'll stand there and wont even play the attack animation yet, but the units will go flying, how do I fix that?
 
Level 37
Joined
Mar 6, 2006
Messages
9,243
  • No need to null u in setup, due to exitwhen u == null
  • You could apply private keyword to some methods and variables to make them unaccessible from outside the library
  • You forgot to destroy the group in setup. You could use a global group you never destroy instead of creating/destroying local groups
  • Perhaps you could use a variable for GetUnitFacing(udg_Sauron)*bj_DEGTORAD
  • Precalculate this KB_moveDistanceLoop*Cos(this.angle) and the sin conterpart in start
  • Try using http://www.hiveworkshop.com/forums/jass-resources-412/system-physical-damage-detection-228456/ to make the timing correct
  • I don't recommend pausing the units. You could stun them instead
  • The flying height maniulation could be a bit smoother
 
Status
Not open for further replies.
Top