• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Mui

  • Like
Reactions: Kanadaj
Hi there, this time with an utility exclusively for GUIers (sorry jassers :c) which I think you gonna love it.

It's well knowed that making MUI spells in JASS is easier than GUI. That is because of the shitty process of making it MUI, instead of just worry about the spell itself.

Some people, do use the array technique; other use hashtables; and crazy ones uses waits with locals. All of these ways work fine, the problem resides in repetitive steps, and, when we are developing it, it is hard to mantain (unless you're using wait-technique, but cmom, waits! >: o)

So, what if we create another way of make MUI abilities with a little bit of dark magic wit?

This is exactly what I'm bringing. A new, ordered, elegant and extremelly easy, way of making MUI abilities in GUI (without need of jass new gen pack).

Let's see an example of an a burning ability, those that really like me c:

  • Burning
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Burning
    • Actions
      • Set set_unit[1] = (Triggering unit)
      • Set set_unit[2] = (Target unit of ability being cast)
      • Set used_units = 2
      • -------- ------------------------------------------------------------------------------------------ --------
      • Set set_real[1] = 5.00
      • Set used_reals = 1
      • -------- ------------------------------------------------------------------------------------------ --------
      • Special Effect - Create a special effect attached to the chest of (Target unit of ability being cast) using Abilities\Spells\Human\FlameStrike\FlameStrikeEmbers.mdl
      • Set set_effect[1] = (Last created special effect)
      • Set used_effects = 1
      • -------- ------------------------------------------------------------------------------------------ --------
      • Set trigger = BurningPeriodic <gen>
      • Set timeout = 1.00
Periodic trigger...

  • BurningPeriodic
    • Events
    • Conditions
    • Actions
      • -------- A second has passed, so update --------
      • Set get_real[1] = (get_real[1] - 1.00)
      • -------- ------------------------------------------------------------------------------------------ --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • get_real[1] Greater than 0.00
        • Then - Actions
          • -------- If there is still time, make damage --------
          • Unit - Cause get_unit[1] to damage get_unit[2], dealing 10.00 damage of attack type Spells and damage type Normal
        • Else - Actions
          • -------- Out of time, finish --------
          • Game - Display to (All players) the text: Finished spell
          • -------- Automatically remove leaks, like a boss --------
          • Set automaticClean = True
          • Set finish = True
Sweet, isn't?

Without need of loops (array technique), without need of loading from hashtable (hashtable technique) and without, of course, ugly waits :). This allow the final user (you), to focus completelly on his ability :).

Hey man, you have leaks in that trigger!
Do I?, this utility can handle all destructors (remove location, destroy group, etc.), so you don't have to worry about it anymore :D.

MUI (utility's name) is yet in experimental-phase. I did not test it exaustly, but it did pass some of the test that I made it.

To use it, just create a trigger called "MUI" (without quotes) and paste this, and don't forget the variables!:

JASS:
// allocator
// thanks nestharus/vexorian c:
function MUI_CreateInstance takes nothing returns integer
	local integer instance

	if ( udg_recycle == 0 ) then
		set udg_instanceCount = udg_instanceCount + 1
		set instance = udg_instanceCount
	else
		set instance = udg_recycle
		set udg_recycle = udg_recycleNext[udg_recycle]
	endif

	// reserving space
	set instance = instance * udg_limit

	return instance
endfunction

// deallocator
// thanks nestharus/vexorian c:
function MUI_RecycleInstance takes integer instance returns nothing
    set instance = instance / udg_limit

	set udg_recycleNext[instance] = udg_recycle
	set udg_recycle = instance
endfunction

function MUI_ShowOverLimitError takes nothing returns nothing
    call BJDebugMsg("No puedes guardar mas de " + I2S(udg_limit) + ". Si necesitas mas, modifica la variable limit.\nYou can't save more than " + I2S(udg_limit) + ". If you need more, modify the variable called 'limit'")
endfunction

// private
function MUI_SaveUnits takes integer instance returns nothing
	local integer i = 1

	loop
		set udg_mui_unit[instance + i] = udg_set_unit[i]
		set udg_set_unit[i] = null

		exitwhen i == udg_used_units
		set i = i + 1
	endloop

	set udg_mui_used_units[instance] = udg_used_units
endfunction

// private
function MUI_SaveReals takes integer instance returns nothing
	local integer i = 1

	loop
		set udg_mui_real[instance + i] = udg_set_real[i]
		set udg_set_real[i] = 0.

		exitwhen i == udg_used_reals
		set i = i + 1
	endloop

	set udg_mui_used_reals[instance] = udg_used_reals
endfunction

// private
function MUI_SavePlayers takes integer instance returns nothing
	local integer i = 1

	loop
		set udg_mui_player[instance + i] = udg_set_player[i]
		set udg_set_player[i] = null

		exitwhen i == udg_used_players
		set i = i + 1
	endloop

	set udg_mui_used_players[instance] = udg_used_players
endfunction

// private
function MUI_SavePoints takes integer instance returns nothing
	local integer i = 1

	loop
		set udg_mui_point[instance + i] = udg_set_point[i]
		set udg_set_point[i] = null

		exitwhen i == udg_used_points
		set i = i + 1
	endloop

	set udg_mui_used_points[instance] = udg_used_points
endfunction

// private
function MUI_SaveEffects takes integer instance returns nothing
	local integer i = 1

	loop
		set udg_mui_effect[instance + i] = udg_set_effect[i]
		set udg_set_effect[i] = null

		exitwhen i == udg_used_effects
		set i = i + 1
	endloop

	set udg_mui_used_effects[instance] = udg_used_effects
endfunction

// private
function MUI_SaveIntegers takes integer instance returns nothing
	local integer i = 1

	loop
		set udg_mui_integer[instance + i] = udg_set_integer[i]
		set udg_set_integer[i] = 0

		exitwhen i == udg_used_integers
		set i = i + 1
	endloop

	set udg_mui_used_integers[instance] = udg_used_integers
endfunction

// private
function MUI_SaveUnitGroups takes integer instance returns nothing
	local integer i = 1

	loop
		set udg_mui_group[instance + i] = udg_set_group[i]
		set udg_set_group[i] = null

		exitwhen i == udg_used_groups
		set i = i + 1
	endloop

	set udg_mui_used_groups[instance] = udg_used_groups
endfunction

// private
function MUI_SaveBooleans takes integer instance returns nothing
	local integer i = 1

	loop
		set udg_mui_boolean[instance + i] = udg_set_boolean[i]
		set udg_set_boolean[i] = false

		exitwhen i == udg_used_booleans
		set i = i + 1
	endloop

	set udg_mui_used_booleans[instance] = udg_used_booleans
endfunction

// private
function MUI_SaveDestructibles takes integer instance returns nothing
	local integer i = 1

	loop
		set udg_mui_destructible[instance + i] = udg_set_destructible[i]
		set udg_set_destructible[i] = null

		exitwhen i == udg_used_destructibles
		set i = i + 1
	endloop

	set udg_mui_used_destructibles[instance] = udg_used_destructibles
endfunction

// private
function MUI_Periodic takes nothing returns nothing
	local timer expiredTimer = GetExpiredTimer()
	local integer expiredTimerId = GetHandleId(expiredTimer)

	local integer instance = LoadInteger(udg_hashtable, expiredTimerId, 0)

	local integer i
    
    // avoid recursion problems
	local unit array prevGetUnit
	local real array prevGetReal
	local player array prevGetPlayer
	local location array prevGetPoint
	local effect array prevGetEffect
	local integer array prevGetInteger
	local group array prevGetGroup
	local boolean array prevGetBoolean
    local destructable array prevGetDestructible

	local boolean prevAutomaticClean = udg_automaticClean
	local boolean prevFinish = udg_finish

	// unit
	if ( udg_mui_used_units[instance] > 0 ) then
		set i = 1

		loop
			set prevGetUnit[i] = udg_get_unit[i]
			set udg_get_unit[i] = udg_mui_unit[instance + i]

			exitwhen i == udg_mui_used_units[instance]
			set i = i + 1
		endloop
	endif

	// real
	if ( udg_mui_used_reals[instance] > 0 ) then
		set i = 1

		loop
			set prevGetReal[i] = udg_get_real[i]
			set udg_get_real[i] = udg_mui_real[instance + i]

			exitwhen i == udg_mui_used_reals[instance]
			set i = i + 1
		endloop
	endif

	// player
	if ( udg_mui_used_players[instance] > 0 ) then
		set i = 1

		loop
			set prevGetPlayer[i] = udg_get_player[i]
			set udg_get_player[i] = udg_mui_player[instance + i]

			exitwhen i == udg_mui_used_players[instance]
			set i = i + 1
		endloop
	endif

	// location
	if ( udg_mui_used_points[instance] > 0 ) then
		set i = 1

		loop
			set prevGetPoint[i] = udg_get_point[i]
			set udg_get_point[i] = udg_mui_point[instance + i]

			exitwhen i == udg_mui_used_points[instance]
			set i = i + 1
		endloop
	endif

	// effect
	if ( udg_mui_used_effects[instance] > 0 ) then
		set i = 1

		loop
			set prevGetEffect[i] = udg_get_effect[i]
			set udg_get_effect[i] = udg_mui_effect[instance + i]

			exitwhen i == udg_mui_used_effects[instance]
			set i = i + 1
		endloop
	endif

	// integer
	if ( udg_mui_used_integers[instance] > 0 ) then
		set i = 1

		loop
			set prevGetInteger[i] = udg_get_integer[i]
			set udg_get_integer[i] = udg_mui_integer[instance + i]

			exitwhen i == udg_mui_used_integers[instance]
			set i = i + 1
		endloop
	endif

	// group
	if ( udg_mui_used_groups[instance] > 0 ) then
		set i = 1

		loop
			set prevGetGroup[i] = udg_get_group[i]
			set udg_get_group[i] = udg_mui_group[instance + i]

			exitwhen i == udg_mui_used_groups[instance]
			set i = i + 1
		endloop
	endif

	// boolean
	if ( udg_mui_used_booleans[instance] > 0 ) then
		set i = 1

		loop
			set prevGetBoolean[i] = udg_get_boolean[i]
			set udg_get_boolean[i] = udg_mui_boolean[instance + i]

			exitwhen i == udg_mui_used_booleans[instance]
			set i = i + 1
		endloop
	endif
    
    // destructible
    if ( udg_mui_used_destructibles[instance] > 0 ) then
        set i = 1

		loop
			set prevGetDestructible[i] = udg_get_destructible[i]
			set udg_get_destructible[i] = udg_mui_destructible[instance + i]

			exitwhen i == udg_mui_used_destructibles[instance]
			set i = i + 1
		endloop
    endif

	call TriggerExecute(LoadTriggerHandle(udg_hashtable, expiredTimerId, 1))

	// unit
	if ( udg_mui_used_units[instance] > 0 ) then
		set i = 1

		loop
			if ( udg_finish ) then
				set udg_mui_unit[instance + i] = null
			else
				set udg_mui_unit[instance + i] = udg_get_unit[i]
			endif

			set udg_get_unit[i] = prevGetUnit[i]
			set prevGetUnit[i] = null

			exitwhen i == udg_mui_used_units[instance]
			set i = i + 1
		endloop
	endif

	// real
	if ( udg_mui_used_reals[instance] > 0 ) then
		set i = 1

		loop
			if ( udg_finish ) then
				set udg_mui_real[instance + i] = 0.
			else
				set udg_mui_real[instance + i] = udg_get_real[i]
			endif

			set udg_get_real[i] = prevGetReal[i]

			exitwhen i == udg_mui_used_reals[instance]
			set i = i + 1
		endloop
	endif

	// player
	if ( udg_mui_used_players[instance] > 0 ) then
		set i = 1

		loop
			if ( udg_finish ) then
				set udg_mui_player[instance + i] = null
			else
				set udg_mui_player[instance + i] = udg_get_player[i]
			endif

			set udg_get_player[i] = prevGetPlayer[i]
			set prevGetPlayer[i] = null

			exitwhen i == udg_mui_used_players[instance]
			set i = i + 1
		endloop
	endif

	// location
	if ( udg_mui_used_points[instance] > 0 ) then
		set i = 1

		loop
			if ( udg_finish ) then
				if ( udg_automaticClean ) then
					call RemoveLocation(udg_mui_point[instance + i])
					call RemoveLocation(udg_get_point[i])
				endif

				set udg_mui_point[instance + i] = null
			else
				if ( udg_mui_point[instance + i] != udg_get_point[i] ) then
					call RemoveLocation(udg_mui_point[instance + i])
					set udg_mui_point[instance + i] = udg_get_point[i]
				endif
			endif

			set udg_get_point[i] = prevGetPoint[i]
			set prevGetPoint[i] = null

			exitwhen i == udg_mui_used_points[instance]
			set i = i + 1
		endloop
	endif

	// effect
	if ( udg_mui_used_effects[instance] > 0 ) then
		set i = 1

		loop
			if ( udg_finish ) then
				if ( udg_automaticClean ) then
					call DestroyEffect(udg_mui_effect[instance + i])
					call DestroyEffect(udg_get_effect[i])
				endif

				set udg_mui_effect[instance + i] = null
			else
				if ( udg_mui_effect[instance + i] != udg_get_effect[i] ) then
					call DestroyEffect(udg_mui_effect[instance + i])
					set udg_mui_effect[instance + i] = udg_get_effect[i]
				endif
			endif

			set udg_get_effect[i] = prevGetEffect[i]
			set prevGetEffect[i] = null

			exitwhen i == udg_mui_used_effects[instance]
			set i = i + 1
		endloop
	endif

	// integer
	if ( udg_mui_used_integers[instance] > 0 ) then
		set i = 1

		loop
			if ( udg_finish ) then
				set udg_mui_integer[instance + i] = 0
			else
				set udg_mui_integer[instance + i] = udg_get_integer[i]
			endif

			set udg_get_integer[i] = prevGetInteger[i]

			exitwhen i == udg_mui_used_integers[instance]
			set i = i + 1
		endloop
	endif

	// groups
	if ( udg_mui_used_groups[instance] > 0 ) then
		set i = 1

		loop
			if ( udg_finish ) then
				if ( udg_automaticClean ) then
					call DestroyGroup(udg_mui_group[instance + i])
					call DestroyGroup(udg_get_group[i])
				endif
				set udg_mui_group[instance + i] = null
			else
				if ( udg_mui_group[instance + i] != udg_get_group[i] ) then
					call DestroyGroup(udg_mui_group[instance + i])
					set udg_mui_group[instance + i] = udg_get_group[i]
				endif
			endif

			set udg_get_group[i] = prevGetGroup[i]
			set prevGetGroup[i] = null

			exitwhen i == udg_mui_used_groups[instance]
			set i = i + 1
		endloop
	endif

	// boolean
	if ( udg_mui_used_booleans[instance] > 0 ) then
		set i = 1

		loop
			if ( udg_finish ) then
				set udg_mui_boolean[instance + i] = false
			else
				set udg_mui_boolean[instance + i] = udg_get_boolean[i]
			endif

			set udg_get_boolean[i] = prevGetBoolean[i]

			exitwhen i == udg_mui_used_booleans[instance]
			set i = i + 1
		endloop
	endif
    
    // destructible
    if ( udg_mui_used_destructibles[instance] > 0 ) then
        set i = 1

		loop
			if ( udg_finish ) then
                if ( udg_automaticClean ) then
                    call RemoveDestructable(udg_mui_destructible[instance + i])
                    call RemoveDestructable(udg_get_destructible[instance + i])
                endif
				set udg_mui_destructible[instance + i] = null
			else
				set udg_mui_destructible[instance + i] = udg_get_destructible[i]
			endif

			set udg_get_destructible[i] = prevGetDestructible[i]

			exitwhen i == udg_mui_used_destructibles[instance]
			set i = i + 1
		endloop
    endif

	if ( udg_finish ) then
        set udg_mui_used_units[instance] = 0
        set udg_mui_used_reals[instance] = 0
        set udg_mui_used_players[instance] = 0
        set udg_mui_used_points[instance] = 0
        set udg_mui_used_effects[instance] = 0
        set udg_mui_used_integers[instance] = 0
        set udg_mui_used_groups[instance] = 0
        set udg_mui_used_booleans[instance] = 0
        set udg_mui_used_destructibles[instance] = 0
    
		call MUI_RecycleInstance(instance)
		call FlushChildHashtable(udg_hashtable, expiredTimerId)

		call PauseTimer(expiredTimer)
		call DestroyTimer(expiredTimer)
	endif

	set udg_automaticClean = prevAutomaticClean
	set udg_finish = prevFinish

	set expiredTimer = null
endfunction

// private
function MUI_OnTimeoutChange takes nothing returns nothing
	local timer periodicTimer = CreateTimer()
	local integer instance = MUI_CreateInstance()
            
    // units
	if ( udg_used_units > 0 ) then
        if ( udg_used_units > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveUnits(instance)
            set udg_used_units = 0
        endif
	endif
    
    // reals
	if ( udg_used_reals > 0 ) then
        if ( udg_used_reals > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveReals(instance)
            set udg_used_reals = 0
        endif
	endif
    
    // players
    if ( udg_used_players > 0 ) then
        if ( udg_used_players > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SavePlayers(instance)
            set udg_used_players = 0
        endif
	endif
    
    // points
    if ( udg_used_points > 0 ) then
        if ( udg_used_points > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SavePoints(instance)
            set udg_used_points = 0
        endif
	endif
    
    // effects
    if ( udg_used_effects > 0 ) then
        if ( udg_used_effects > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveEffects(instance)
            set udg_used_effects = 0
        endif
	endif
    
    // integers
    if ( udg_used_integers > 0 ) then
        if ( udg_used_integers > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveIntegers(instance)
            set udg_used_integers = 0
        endif
	endif
    
    // groups
    if ( udg_used_groups > 0 ) then
        if ( udg_used_groups > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveUnitGroups(instance)
            set udg_used_groups = 0
        endif
	endif
    
    // boolean
    if ( udg_used_booleans > 0 ) then
        if ( udg_used_booleans > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveBooleans(instance)
            set udg_used_booleans = 0
        endif
	endif
    
    // destructibles
    if ( udg_used_destructibles > 0 ) then
        if ( udg_used_destructibles > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveDestructibles(instance)
            set udg_used_destructibles = 0
        endif
    endif

	call SaveInteger(udg_hashtable, GetHandleId(periodicTimer), 0, instance)
	call SaveTriggerHandle(udg_hashtable, GetHandleId(periodicTimer), 1, udg_trigger)

	call TimerStart(periodicTimer, udg_timeout, true, function MUI_Periodic)

	set udg_timeout = 0.
	set udg_trigger = null

	set periodicTimer = null
endfunction

// initializer
function InitTrig_MUI takes nothing returns nothing
	set gg_trg_MUI = CreateTrigger()
	set udg_hashtable = InitHashtable()
	
	call TriggerRegisterVariableEvent(gg_trg_MUI, "udg_timeout", GREATER_THAN, 0)
	call TriggerAddAction(gg_trg_MUI, function MUI_OnTimeoutChange)
endfunction

How does it works?
Like array technique and hashtable, just hidding the process to the final user making it more friendly and easy to work with.

Is it efficient?
If you're really asking me this, I will say: go home my friend, you're drunk.

Can you explain me a little bit more how to save things?
It's very simple.

First, we need something to save. Let's say that we want to save a caster:

  • Set set_unit[1] = (Triggering unit)
Notice that when we save, we have to use the set_x (where x is the type of the data that we are going to save).

After we save something, we need to tell to this utility, how many space do we use. So, if we save 1 unit, we just say:

  • Set used_units = 1
If we're using 2, then we say 2, etc.


When we want to retrieve the data that we just saved, we just need to use the get_x variables (where x is the type, same as set_x).

If I saved this:

  • Set set_unit[1] = (Triggering unit)
  • Set set_unit[2] = (Target unit of ability being cast)
  • Set used_units = 2
To access to (Triggering unit), we just have to use get_unit[1]. To access (Target unit of ...) we just use unit[2]. You got it?, it depends on the order in what we save it.

Same with the other variable types (real, integer, etc.).


What is trigger?
The trigger' variable is used by this utility to know what trigger to execute when the timer expires. Before you set the timeout variable, you must set the trigger first.

What is timeout?
When you set a value to timeout (mean timeout = x) a timer will begin with the timeout of timeout (dah!). When it expires (the timer) it will execute the trigger that you set.

Important: Set timeout at the very last of the trigger.

What is automaticClean?
If you don't wan't to worry about leaks, when you finish your spell, just set it to true. If it is true, this utility will clear leaks for you :).

What is finish?
Set finish to true, when you wan't to finish the spell.

Can I use the variables called mui_x?
Please no, those are used by this utility.


Any bug, let me know ;).

Greetings.

Keywords:
mui, gui, like a boss
Contents

Just another Warcraft III map (Map)

Reviews
15th Dec 2013 Maker: Auseful system that can makes creating spells easier. The system has a bit of overhead since it checks for every type even if they are not used
Level 22
Joined
Sep 24, 2005
Messages
4,821
The debug messages are still not translated to english, it also appears that you have ignored the suggestions others have given you.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Oh, so you did translate it, sorry about that. The latter comment still stands though. Read the code thoroughly this time, looks like the suggestions were implemented.

EDIT: I think the previous instance method should be retained.
 
Last edited:
Level 9
Joined
Dec 12, 2007
Messages
489
a huge overhaul it is, almost no wrapper function,
I want to note that :
- this version has a limit of ROUNDUP(8190/udg_limit)-1 instances running at the same time.
- you're not using map header, how you can be sure that your script run before user's trigger?
- you should add how to import instructions.
 
Level 10
Joined
Sep 19, 2011
Messages
527
yes, i do realize of the limit.

i analize it, and i think that you won't have any problems with it.

- you're not using map header, how you can be sure that your script run before user's trigger?

i don't think that people fire this at the map-init. so it should be ok.

you should add how to import instructions.

i did ._., i have to add that you need to paste the variables.

EDIT: I think the previous instance method should be retained.

why?


i'm more concerned about recursion problems in the set_x variables. but i don't know how to check it :\.
 
Level 9
Joined
Dec 12, 2007
Messages
489
i don't think that people fire this at the map-init. so it should be ok.
nope, what I meant is, the target of this resource is pure GUI non JNGP user. if such user would like to implement this in their 50% done map and change already made spell to conform to this resource, how will they do it? isn't this resource will be compiled at the bottom of the code, not at the top?

i did it ._., i have to add that you need to paste the variables.
rather than information to copy and paste the variable, why not make a GUI trigger using all global variable that just need to be copy-pasted? so user who has enable "Automatically create unknown variables when passing trigger data" or such can just copy that trigger into their map then delete it.

and still, I suggest to add destructable set to this.
 
Level 10
Joined
Sep 19, 2011
Messages
527
nope, what I meant is, the target of this resource is pure GUI non JNGP user. if such user would like to implement this in their 50% done map and change already made spell to conform to this resource, how will they do it? isn't this resource will be compiled at the bottom of the code, not at the top?

but that doesn't really matters. the important thing is that this resource should be loaded before the user fires the timer. that happends on casting spells and those don't happend on init. is that your concern?.

rather than information to copy and paste the variable, why not make a GUI trigger using all global variable that just need to be copy-pasted? so user who has enable "Automatically create unknown variables when passing trigger data" or such can just copy that trigger into their map then delete it.

uhmm, so if people have that option checked the variables will be created automatically?, didn't know that. i will update the example-map later.
 
Level 9
Joined
Dec 12, 2007
Messages
489
but that doesn't really matters. the important thing is that this resource should be loaded before the user fires the timer. that happends on casting spells and those don't happend on init. is that your concern?.
actually after further reading, the user didn't need to call any function just set global variable, so yes it doesn't matter, sorry.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
I meant the previous instancing method, not the instance method. The reason is the array limits will greatly reduce the amount of spell instance per spell type.

but that doesn't really matters. the important thing is that this resource should be loaded before the user fires the timer. that happends on casting spells and those don't happend on init. is that your concern?.
He is talking about syntax errors, your system must be declared above the triggers that will use it, that's why he suggested to put it on the map header section.
 
Level 10
Joined
Sep 19, 2011
Messages
527
I meant the previous instancing method, not the instance method. The reason is the array limits will greatly reduce the amount of spell instance per spell type.

if you put a limit of 50, you will be able to have ~163 instances at a time. 163 spell in the same time, didn't see that before. i really, really think that user will not reach that number.

edit: although, now that i think... i have an entire hashtable that i can use if the user goes over the limit... uhmm c:
edit: yes i will add destructibles too ;).
 
Level 9
Joined
Dec 12, 2007
Messages
489
the only kind of spells in my head which can reach the limit of 50 unit/real/integer variable is a custom Cluster Rockets with each unit variable referring to missile and real variable for its trajectory.

He is talking about syntax errors, your system must be declared above the triggers that will use it, that's why he suggested to put it on the map header section.
yeah at first I actually think the same thing, but after further reading, his script is never been called outside of his script, and the only thing user need to do is setting variable and using it. so yeah, I think this won't need to be inside map init.
 
Level 10
Joined
Sep 19, 2011
Messages
527
Every local variable has to be nulled except integer / real / boolean.
Loop at your periodic function.

pay attention and look closer.


i did realice though that i'm not reseting the counter.

edit:

the only kind of spells in my head which can reach the limit of 50 unit/real/integer variable is a custom Cluster Rockets with each unit variable referring to missile and real variable for its trajectory.

if you need it, you can increase the limit. see 'limit' variable.

edit: damn, acording to nes this can/do have recursion problems : \, i will try to fix it.
 
Last edited:
Another thing to add with your update would be easier importing to new maps.
Make an eventless trigger and set all your variables in it so they can be copied over easily.

[trigger=]
Events
Conditions
Actions
Set boolean[0] = False
Set effect[0] = (Last created special effect)
Set effect_helper = (Last created special effect)
Set group[0] = (Random 4 units from (Units in (Playable map area)))
Set group_helper = (Random 4 units from (Units in (Playable map area)))
Set hashtable = (Last created hashtable)
Set integer[0] = 0
Set integer_helper = 0
Set player[0] = (Owner of (Triggering unit))
Set player_helper = (Owner of (Triggering unit))
Set point[0] = ((Center of (Playable map area)) offset by (0.00, 0.00))
Set point_helper = ((Center of (Playable map area)) offset by (0.00, 0.00))
Set real[0] = 0.00
Set real_helper = 0.00
Set trigger = (This trigger)
Set unit[0] = (Last created unit)
Set unit_helper = (Last created unit)
[/TRIGGER]
 
Level 10
Joined
Sep 19, 2011
Messages
527
updated

+ added reset on finish
+ added destructible support
+ improved map-example

i check for recursion problems... nothing happended so it should work fine ;).

edit: seems like there's a bug because dat-c3's spell is not working properly
edit: after thinking, the only solution that came to me is:


edit: good news, wasn't because of recursion problems, it was because of a mistake of mine c:. the time when your entire utility fails because of a division u.u
 
Last edited:
Level 9
Joined
Dec 12, 2007
Messages
489
this part of code,
JASS:
function MUI_CreateInstance takes nothing returns integer
    local integer instance

    if ( udg_recycle == 0 ) then
        set udg_instanceCount = udg_instanceCount + 1
        set instance = udg_instanceCount
    else
        set instance = udg_recycle
        set udg_recycle = udg_recycleNext[udg_recycle]
    endif

    // reserving space
    if ( instance > 1 ) then
        set instance = instance * udg_limit
    endif

    return instance
endfunction
without the code below the reserving space, the instance available are from start are 1,2,3,4,5,6,7,8,....
using the code below the reserving space, the instance become: 1,100,150,200,250,300,350,400,..., its not using the index of 51-100 for anything which means yours actually have a maximum instance of ROUNDUP(8190/udg_limit)-2 not ROUNDUP(8190/udg_limit)-1 (not much effect actually, only one instance less).
and on the recycleinstance, I haven't checked if integer round up or down when dealing with fractions in calculation, but considering this line
JASS:
    set instance = instance / udg_limit
if instance given is 1, if the integer round up, it will do well, but if it round down to 0, it will bug off the allocation/deallocation to the point it will always create instance as udg_recycle will always 0.
 
Level 9
Joined
Dec 12, 2007
Messages
489
ehm, its still round(8190/limit) - 1 max instance, why?
JASS:
function MUI_CreateInstance takes nothing returns integer
    local integer instance

    if ( udg_recycle == 0 ) then
        set udg_instanceCount = udg_instanceCount + 1
        set instance = udg_instanceCount
    else
        set instance = udg_recycle
        set udg_recycle = udg_recycleNext[udg_recycle]
    endif

    // reserving space
    if ( instance > 0 ) then
        set instance = instance * udg_limit
    endif

    return instance
endfunction

function MUI_RecycleInstance takes integer instance returns nothing
    if ( instance > 0 ) then
        set instance = instance / udg_limit
    endif

    set udg_recycleNext[instance] = udg_recycle
    set udg_recycle = instance
endfunction
your instance given before the //reserving space is still 1,2,3,...
and after the if check, it becomes 50,100,150,... which means index 0-50 is still unused. and by the way, because the instance count always start from 1 and increase, you don't need the if instance > 0 check both in createinstance and recycleinstance, you can just multiply or divide it directly, no need for an if check. like this:
JASS:
function MUI_CreateInstance takes nothing returns integer
    local integer instance

    if ( udg_recycle == 0 ) then
        set udg_instanceCount = udg_instanceCount + 1
        set instance = udg_instanceCount
    else
        set instance = udg_recycle
        set udg_recycle = udg_recycleNext[udg_recycle]
    endif

    // reserving space
    set instance = instance * udg_limit

    return instance
endfunction

function MUI_RecycleInstance takes integer instance returns nothing
    set instance = instance / udg_limit

    set udg_recycleNext[instance] = udg_recycle
    set udg_recycle = instance
endfunction
 
Level 5
Joined
Oct 8, 2010
Messages
134
I like the whole Idea, it let's me focus more on the skill/ability I am creating.
It is a template (eh duh ppl it is in the template section) that takes care of the
tedious things that could annoy and bore you.

The only thing is that you have to make a list for yourself what number corresponds
with which type of saved unit.

Also What would happen if I have a channelled spell and an other spellcaster
uses an ability?
(assuming both triggers use the set(1) for casting unit)
That would cause some errors I'm sure.

so must we have a list of corresponding numbers that are each unique to prevent this?
I hope not...

It would still make for some easier spell making.
Which would be great when triggering minion spells
(no need to explain that term right?)

Looks neat and will try. Hope it works.
or get's improved and then approved.

Vlad727
 
Level 9
Joined
Dec 12, 2007
Messages
489
just wondering, why not try to contact some Spells section moderator to make notice of this resource? I found that some latest submitted resource already moderated while this one left unmoderated for a month.

approval may not be warrant, but at least you can improve this resource through what those moderators found.
 
They'll get to it when they'll get to it.

A resource like this is not an easy thing to moderate because you have to consider the impact this will have on future resources.

@Ruke, have you tested how many handles this works with before the op limit kicks in? (Try something like 20 units, items, destructables, effects, etc...)
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
To be honest, I'm not a fan of the system. It does unnecessary work if there is nothing to loop. And it hides the spell making mechanics from the user, using this can make it harder for people to move from gui to jass/vjass. It can still be useful to some people and it think it is approvable.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
You have more control over the game when you use jass, vjass makes it easier to control that. Anyway, just to clear things up, I'm not against this system.
 
Level 10
Joined
Sep 19, 2011
Messages
527
sorry for the lack of attention here. i need to update this (there is a minor but anoying bug there).

It does unnecessary work if there is nothing to loop.

where?

@Ruke, have you tested how many handles this works with before the op limit kicks in? (Try something like 20 units, items, destructables, effects, etc...)

i did not, but shouldn't be any problem (of course, keep in mind that this sacrifices efficiency for sugar).
 
And it hides the spell making mechanics from the user, using this can make it harder for people to move from gui to jass/vjass.

Yeah... it might even make it hard for them to make MUI if they ever need to make it themselves...

IMHO, it is better to teach users to know how to make MUI by themselves rather than teaching them to rely on a general resource to make MUI for them... that will serve them better in the future... and making MUI after all is not a really complex or hard thing, at least it won't be for much of the things that you can do in GUI...

especially seeing as how the GUI part of this is pretty much all just set-up... and the "hidden" jass part is what does everything...

anyway, yes, the "system" does what it was meant to do... just not fond of this kind of systems...

BTW, it was that pic that made me view this... :)
 
Level 10
Joined
Sep 19, 2011
Messages
527
Yeah... it might even make it hard for them to make MUI if they ever need to make it themselves...

IMHO, it is better to teach users to know how to make MUI by themselves rather than teaching them to rely on a general resource to make MUI for them... that will serve them better in the future... and making MUI after all is not a really complex or hard thing, at least it won't be for much of the things that you can do in GUI...

making mui with gui isn't hard, but anoying/time-consuming/repetitive and it converts our global variables in a mess. this utility fixes those problems.
 
Top