| 06-11-2011, 10:13 PM | #1 |
Introduction PauseUtils is written in Zinc and requires the Jass NewGen Pack along with the latest version of JassHelper.Credits
Unfortunately, you must abide to a few limitations in order to use this snippet to its fullest. All your PauseUnit(unit, true) calls should be replaced with Pause(unit) and all your PauseUnit(unit, false) calls should be replaced with Unpause(unit). The natives would still work normally, but there would be no safety and no responses would be evaluated. With that being said, one can easily conclude that this snippet is best used in a fresh new map.The snippet Requirements: PauseUtils://! zinc library PauseUtils requires TimerUtils, AutoIndex { /** * This is just a simple snippet that is meant to prevent units from being unpaused * prematurely due to the lack of multi-instanceability of the native function. * It also provides the user with responses that are evaluated when a unit is * effectively paused or unpaused as well as pausing units for a specified duration. * * It requires the latest version of JassHelper and the AutoIndex and TimerUtils libraries. * * Credits go to: * 1. BBQ for writing the PauseUtils snippet. * 2. grim001 for his AutoIndex library. * 3. Vexorian for his TimerUtils library, Zinc and JassHelper. * 4. All of the contributors to the Jass NewGen Pack. * * The functions provided by this snippet are as follows: * * - function Pause takes unit whichUnit returns nothing * This is the same as PauseUnit(whichUnit, true), except that it is fully * multi-instanceable. Note that the unit must be indexed in order for this to * be any different than its native counterpart. * * - function Unpause takes unit whichUnit returns nothing * This is the same as PauseUnit(whichUnit, false), except that it is fully * multi-instanceable. Note that the unit must be indexed in order for this to * be any different than its native counterpart. * * - function TimedPause takes unit whichUnit, real duration returns nothing * The unit passed to the function will be paused for the specified duration. * * - function OnUnitPaused takes response whichResponse returns nothing * The "response" function or static method will be evaluated when a unit is * effectively paused. Note that it needs to take unit and return nothing. * The unit it takes is the unit that was paused. * * - function OnUnitUnpaused takes response whichResponse returns nothing * The "response" function or static method will be evaluated when a unit is * effectively unpaused. Again, it needs to take unit and return nothing. * The unit it takes is the unit that was unpaused. * * Unfortunately, you must abide to a few limitations in order to use this snippet to its fullest. * All your PauseUnit(unit, true) calls should be replaced with Pause(unit), * and all your PauseUnit(unit, false) calls should be replaced with Unpause(unit). * The natives would still work normally but there would be no safety and no responses would be evaluated. */ type response extends function(unit); integer pauseResponses_n = 0, unpauseResponses_n = 0, pauseCounter[]; response pauseResponses[], unpauseResponses[]; //! textmacro PauseUtils__runEvents takes which for (n = 1; n <= $which$Responses_n; n += 1) { $which$Responses[n].evaluate(whichUnit); } //! endtextmacro public function OnUnitPaused(response whichResponse) { pauseResponses_n += 1; pauseResponses[pauseResponses_n] = whichResponse; } public function OnUnitUnpaused(response whichResponse) { unpauseResponses_n += 1; unpauseResponses[unpauseResponses_n] = whichResponse; } public function Pause(unit whichUnit) { integer index, n; if (IsUnitIndexed(whichUnit)) { index = GetUnitId(whichUnit); if (pauseCounter[index] == 0) { PauseUnit(whichUnit, true); //! runtextmacro PauseUtils__runEvents("pause") } pauseCounter[index] += 1; } else PauseUnit(whichUnit, true); } public function Unpause(unit whichUnit) { integer index, n; if (IsUnitIndexed(whichUnit) && IsUnitPaused(whichUnit)) { index = GetUnitId(whichUnit); pauseCounter[index] -= 1; if (pauseCounter[index] <= 0) { PauseUnit(whichUnit, false); pauseCounter[index] = 0; //! runtextmacro PauseUtils__runEvents("unpause") } } else PauseUnit(whichUnit, false); } struct pauseData { unit pausedUnit; } public function TimedPause(unit whichUnit, real duration) { pauseData data; timer durationTimer; if (duration <= 0.0) { Pause(whichUnit); Unpause(whichUnit); } else { Pause(whichUnit); durationTimer = NewTimer(); data = pauseData.create(); data.pausedUnit = whichUnit; SetTimerData(durationTimer, integer(data)); TimerStart(durationTimer, duration, false, function() { pauseData data = pauseData(GetTimerData(GetExpiredTimer())); Unpause(data.pausedUnit); data.pausedUnit = null; data.destroy(); ReleaseTimer(GetExpiredTimer()); }); durationTimer = null; } } function onInit() { OnUnitDeindexed(function(unit leavingUnit) { pauseCounter[GetUnitId(leavingUnit)] = 0; /* Since AutoIndex recycles its indices, we need to reset the counter as well. */ }); } } //! endzinc Available functions This snippet provides the following functions to the user: |
| 06-11-2011, 11:27 PM | #2 |
As far as I'm aware it is preferable to disable units instead of pausing them, as disabling does not clear the unit's command card and queued orders like pausing does. This is not a small problem - I've tried pausing units before when making certain spells and the inability to issue or queue new orders while the spell is running was very frustrating for the player. With this in mind, I would always prefer using UnitStatus over PauseUtils, unless there's some advantage pausing has over disabling that I am not aware of. |
| 06-12-2011, 12:10 AM | #3 |
Well, if we're talking about game balance, then pausing units has much more impact on the gameplay than simply stunning them. For example, pause disables evasion, permanent invisibility, true sight, hardened skin and building damage aura, while a stun would do none of that. Moreover, most of the hardcoded buffs have their duration "frozen" by pause. Sure, if you handle all those durations via softcoded means, such thing wouldn't happen, but the above point would still stand true. Generally, I see nothing wrong with pausing units. For example, DotA (yes, I know that DotA is horribly coded and everything) uses it quite commonly, and I am yet to see anyone complain about that. |
| 06-12-2011, 01:10 AM | #4 |
Pause also pauses spell effects. Might be useful for maps which use pause though. |
| 06-13-2011, 07:06 PM | #5 |
| 06-14-2011, 01:00 AM | #6 |
While I do not wish to encourage people to pause units when making spells (I would recommend the disable functionality of UnitStatus in those cases), there can be other uses for pausing where this would be a very helpful library. Approved. You should perhaps point out in the documentation that users who use this in their map should only use this library's functions and not the PauseUnit native. |
| 06-14-2011, 11:09 AM | #7 | |
Quote:
PauseUnit directly should still be fine for the pause/order/unpause trick (so long as you set 'paused' to a variable), though in general you are right. |
| 06-14-2011, 03:01 PM | #8 | |||
Quote:
Zinc:public function Interrupt(unit whichUnit) { if (pauseCounter[GetUnitId(whichUnit)] == 0 && !IsUnitPaused(whichUnit)) { PauseUnit(whichUnit, true); IssueImmediateOrderById(whichUnit, 851972); PauseUnit(whichUnit, false); } } Is the pause/order/unpause trick used with any order other than "stop"? I've only used it (and only seen others using it) with "stop" for interrupting purposes. Quote:
Quote:
|
| 06-14-2011, 04:32 PM | #9 | |
Quote:
JASS:function AbortOrder takes unit u returns boolean if IsUnitPaused(u) then return false else call PauseUnit(u, true) call IssueImmediateOrder(u, "stop") call PauseUnit(u, false) endif return true endfunction |
| 06-27-2011, 01:15 PM | #10 |
|
| 06-27-2011, 01:46 PM | #11 | |
Quote:
|
| 06-27-2011, 06:03 PM | #12 | |
Quote:
I'll also include a version that will use Table instead of AutoIndex. Even though array reading is much faster than hashtable reading, I don't think there would be any noticeable difference in the speed, mainly because using a hashtable has its own advantages over unit indexing, at least in this case. Also, if you feel like the code needs more comments, let me know. |
| 06-27-2011, 07:46 PM | #13 |
Yes, I think looping forward is better. Even if the functionality gain is marginal, it's still worth a lot more than a marginal speed gain. The only reasonable alternative I see is to loop forward on one event but backwards on the other to get a first-in-last-out setup similar to AutoIndex, although I don't really think pause/unpause events need the same strict FILO hierarchy as index/deindex events do - I just brought it up as a rare example of looping backwards being sensible. AutoIndex can already use a hashtable instead of unit custom values, so in this regard a separate Table version of the library is not strictly needed, but Table is a somewhat lighter requirement so if you want to also make a Table version I see nothing wrong with that. The documentation is adequate - note that the library has already been approved as is. If you want to improve it further, however, there is nothing wrong with that. |
| 06-27-2011, 09:24 PM | #14 |
Okay, I totally overestimated hashtables. I don't think that I will be posting a version that uses Table instead of AutoIndex. Anyway,
|
