• 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.

Dummy Casting library

Status
Not open for further replies.
Level 7
Joined
Apr 27, 2011
Messages
272
I usually see vJASS casting systems, so i decided to make one for JASS... although this uses some vJASS features I'm planning to change them after sometime... so they can be used with plain JASS...
JASS:
library DummyCast
//===========================================================================
//    DummyCast
//===========================================================================

	//=======================================================================
	// alloc. & dealloc. Caster
	//=======================================================================
		globals
			private integer c =-1
			private integer w = 0
			private unit    cs    
			private unit array rcs
			private constant player  DEFAULT_OWNER    = Player(15)
			private constant integer INITIAL_CASTERS  = 30
			private constant trigger ENDCAST_SENTINEL = CreateTrigger()
			private constant integer SC_DUMMY_UNIT    = 'n000'
		endglobals

	//=======================================================================
		function AllocateCaster takes player pl returns unit
			if(w==0)then
				set cs=CreateUnit(pl,SC_DUMMY_UNIT,0,0,0)
				call TriggerRegisterUnitEvent(ENDCAST_SENTINEL,cs,EVENT_UNIT_SPELL_ENDCAST)
			else
				set w=w-1
				set cs=rcs[w]
				call SetUnitOwner(cs,pl,false)
			endif
			return cs
		endfunction
		
	//=======================================================================
		function DeallocCaster takes unit u returns nothing
			call SetUnitOwner(u,DEFAULT_OWNER,false)
			set rcs[w]=u
			set w=w+1
		endfunction
	
	//=======================================================================
		private function DeallocCasterX takes unit u, integer spellid returns nothing
			call DeallocCaster(u)
			call UnitRemoveAbility(u,spellid)
		endfunction
		
	//=======================================================================
		private function EndcastFilter takes nothing returns boolean
			call DeallocCasterX(GetTriggerUnit(),GetSpellAbilityId())
			return false
		endfunction
		
	//=======================================================================
		private module initA
			private static method onInit takes nothing returns nothing
				local integer nloops=INITIAL_CASTERS
				loop
					exitwhen nloops==0
                    set rcs[w]=CreateUnit(DEFAULT_OWNER,SC_DUMMY_UNIT,0,0,0)
					call TriggerRegisterUnitEvent(ENDCAST_SENTINEL,rcs[w],EVENT_UNIT_SPELL_ENDCAST)
					set w=w+1
					set nloops=nloops-1
				endloop
				call TriggerAddCondition(ENDCAST_SENTINEL,Condition(function EndcastFilter))
			endmethod
		endmodule
		
	//=======================================================================
	// CreateTargetGroup...
	//=======================================================================
		globals
			private unit picked
			private group affected=CreateGroup()
			private filterfunc CTG_FILTER
		endglobals
	
    //=======================================================================
		private function CustomCheck takes unit u returns boolean
			return GetUnitTypeId(u)!=SC_DUMMY_UNIT
		endfunction
		
	//=======================================================================
		private function ctgfilter takes nothing returns boolean
            set picked=GetFilterUnit()
			if(CustomCheck(picked))then
				call GroupAddUnit(affected,picked)
			endif
			return false
		endfunction
	
	//=======================================================================
		private function CreateTargetGroup takes real x, real y, real r returns nothing
			call GroupEnumUnitsInRange(affected,x,y,r,CTG_FILTER) // inline friendly :D
		endfunction
    
	//=======================================================================
		private module initB
			private static method onInit takes nothing returns nothing
				set CTG_FILTER=Filter(function ctgfilter)
			endmethod
		endmodule
		
    //=======================================================================
	// common functions...
    //=======================================================================
	private function AddSpellLeveled takes unit caster, integer id, integer lvl returns nothing
		call UnitAddAbility(caster,id)
		call SetUnitAbilityLevel(caster,id,lvl)
	endfunction

	//=======================================================================
	//! textmacro ScCaster_SetUnitXY takes UNIT, X, Y
		call SetUnitX($UNIT$,$X$)
		call SetUnitY($UNIT$,$Y$)
	//! endtextmacro
	
//===========================================================================
	function CastSpellOnTargetLvl takes unit caster, unit target, integer id, string os, integer lvl returns nothing
		call AddSpellLeveled(caster,id,lvl)
		//! runtextmacro ScCaster_SetUnitXY("caster","GetUnitX(target)","GetUnitY(target)")
		call IssueTargetOrder(caster,os,target)
	endfunction
	//=======================================================================
		function CastSpellOnTarget takes unit caster, unit target, integer id, string os returns nothing
			call CastSpellOnTargetLvl(caster,target,id,os,1)
		endfunction
		
//===========================================================================
	function CastSpellOnAreaLvl  takes unit caster, real x, real y, real r, integer id, string os, boolean v, integer lvl returns nothing
		local player pl=GetOwningPlayer(caster)
		local unit target
		call CreateTargetGroup(x,y,r)
		call DeallocCaster(caster)
		loop
			set target=FirstOfGroup(affected)
			exitwhen target==null
			set caster=AllocateCaster(pl)
			if((IsUnitAlly(target,pl) and v) or (IsUnitEnemy(target,pl) and not v))then
				call CastSpellOnTargetLvl(caster,target,id,os,lvl)
			endif
			call GroupRemoveUnit(affected,target)
		endloop
	endfunction
	//=======================================================================
		function CastSpellOnArea takes unit caster, real x, real y, real r, integer id, string os, boolean v returns nothing
			call CastSpellOnAreaLvl(caster,x,y,r,id,os,v,1)
		endfunction
		
//===========================================================================
	function CastSpellOnPointLvl takes unit caster, real x, real y, real rng, real a, integer id, string os, integer lvl returns nothing
		call AddSpellLeveled(caster,id,lvl)
		//! runtextmacro ScCaster_SetUnitXY("caster","x","y")
		call IssuePointOrder(caster,os,Cos(a)*rng,Sin(a)*rng)
	endfunction
	//=======================================================================
		function CastSpellOnPoint takes unit caster, real x, real y, real rng, real a, integer id, string os returns nothing
			call CastSpellOnPointLvl(caster,x,y,rng,a,id,os,1)
		endfunction
		
//===========================================================================
	function CastSpellInPointLvl takes unit caster, real x, real y, integer id, string os, integer lvl returns nothing
		call AddSpellLeveled(caster,id,lvl)
		//! runtextmacro ScCaster_SetUnitXY("caster","x","y")
		call IssueImmediateOrder(caster,os)
	endfunction
	//=======================================================================
		function CastSpellInPoint takes unit caster, real x, real y, integer id, string os returns nothing
			call CastSpellInPointLvl(caster,x,y,id,os,1)
		endfunction
		
//===========================================================================
	private struct s extends array
		implement initA
		implement initB
	endstruct
	
//===========================================================================
endlibrary

please leave constructive comments about it! :D ( i know the coding sucks that's why i want some comments about it)

there are 6 functions:
-AllocateCaster(pl) : returns a dummy caster under the control of player "pl".
-DeallocateCaster(caster) : deallocates the unit "caster"
-CastSpellOnTarget(caster,target,spellid,orderstr,lvl)
-CastSpellOnAreaLvl(caster,x,y,r,spellid,orderstr,v,lvl) : "v" determines the targets.. I used "caster" as the first argument instead of a player argument directly because i want to keep the library's convention...
-CastSpellOnPointLvl(caster,x,y,range,angle,spellid,orderstr,lvl) : casts a point target spell towards "angle"... from "x" and "y"
-CastSpellInPointLvl(caster,x,y,spellid,orderstr,lvl) : casts a point-blank spell in "x" and "y"

this lib was inspired by CS... this is a lightweight one.

i also managed to somehow integrate this also... targeting multiple units with instant spells, using one dummy caster

and the good news is now we can target 20+ units :D unlike the previous one on the link...
(chicken's the dummy caster)
c0d1c04f35.png
 
Last edited:
lightweight

Nope. :p

The ideal Dummy Casting system would only have one unit, the ability to add abilities to that unit on Map Initialization for casting during the game and the ability to order that dummy caster to either:
Do an immediate order
Do an order targeting a widget
Do an order targeting coordinates

That's all that a Dummy caster system should be.
All you have to do is create the unit, set his animation/cast/attack backswings and animation times to 0 and let the code do the rest of the job ;)

On a side-note, compared to Vexorian's CasterSystem, this is truly OP :p
It's still isn't good enough though ;/
 
Well, now that I think about it, if you support Channeling spells, this will be better than Nestharus' version, so I guess you can go for it.
This is what you can do:

The conceptual way:
Create a unit array. Set u[0] to the dummy caster.
Order this dummy caster to channel spells and cast instant spells as you would do for any caster, BUT before you make an order, you should check if the unit is channeling a spell. If the unit is doing that, set u[index + 1] to another unit (index here is 0) and order that unit to channel the spell.

The real way to do it with code:
You can use a stack to get dummy casters. This stack should only consist of one caster initially (as I said)
When you want to cast a spell, get a dummy from the stack and order it.

Your stack will work like this:
- A cast function is called: call NewDummyCaster()
- NewDummyCaster() should look like NewTimer() from my TimerUtilsEx in the Jass section's Graveyard. (But for units instead of timers)

Before I continue, I want to tell you that you need the user to register the abilities in the system with their durations. Instant spells should get a duration of 0.

When you order the dummy to cast the spell, you would check if the duration is 0.
If it is 0, release the unit in the stack. Else, start a timer and store the unit in a hashtable with the Handle Id of the timer.
When the timer expires, release the unit.

Easy huh? :)
 
although my lib can already do that without using timers, condition checks and registering durations... just by using the EVENT_UNIT_SPELL_ENDCAST event. ;3

Good then, but make sure you attach data to the units so you'd know whether you should recycle them or not (Else, if some hero finishes casting a spell, he'd be put in the list)
 
Level 7
Joined
Apr 27, 2011
Messages
272
or i could just register them on a single trigger( that would release them automatically) upon the moment they are created

JASS:
function AllocateCaster takes player pl returns unit
    if(w==0)then
        set cs=CreateUnit(pl,SC_DUMMY_UNIT,GetRandomInt(0,100),GetRandomInt(0,200),0)
        call TriggerRegisterUnitEvent(ENDCAST_SENTINEL,cs,EVENT_UNIT_SPELL_ENDCAST) // <- ;D
    else
        set w=w-1
        set cs=rcs[w]
        call SetUnitOwner(cs,pl,false)
    endif
    return cs
endfunction
 
Last edited:
Status
Not open for further replies.
Top