| 08-17-2009, 03:37 AM | #1 |
So for my Race Contest #2 submission, I need a way to produce a cursor on the screen for a player, to which end I devised a library. The library produces a cursor for a specific player and a specific unit, then executes functions onClick and onCancel. That part works fine... sort of. The issue I'm having is the cancel detection trigger is firing when it shouldn't be. What it boils down to is this:
So, I have no idea what's going on... but maybe someone else has an idea. Here's the code: JASS:library ShowCursor initializer Init requires TimerUtils globals private constant integer CANCEL_DETECTION_ABILITY = 'Cncl' private constant string CANCEL_DETECTION_HOTKEY = "l" //Must be lowercase private constant string CANCEL_DETECTION_ORDERSTRING = "starfall" private constant real CANCEL_PERIOD = 0.50 private constant string CAST_ORDERSTRING = "flare" private constant string CAST_HOTKEY = "i" //Must be lowercase constant integer CURSOR_TYPE_GROUND = 0 //Define your own types here constant integer CURSOR_TYPE_UNIT = 1 constant integer CURSOR_TYPE_UNIT_OR_GROUND = 2 constant integer CURSOR_TYPE_AOE_100 = 3 public integer array CursorTypeAbilities //Don't touch this endglobals //! textmacro RegisterCastType takes NAME, ABILITY_ID set CursorTypeAbilities[$NAME$] = '$ABILITY_ID$' //! endtextmacro private function CursorInit takes nothing returns nothing //! runtextmacro RegisterCastType("CURSOR_TYPE_GROUND", "TGnd") //! runtextmacro RegisterCastType("CURSOR_TYPE_UNIT", "TUnt") //! runtextmacro RegisterCastType("CURSOR_TYPE_UNIT_OR_GROUND", "TUoG") //! runtextmacro RegisterCastType("CURSOR_TYPE_AOE_100", "T100") endfunction function interface CursorClick takes player sourcePlayer, unit sourceUnit, real targX, real targY, widget targWidget returns boolean function interface CursorCancel takes player sourcePlayer, unit sourceUnit returns nothing globals private trigger CancelTrig = null private trigger ClickTrig = null private keyword CursorData private CursorData array CDArray endglobals private struct CursorData unit Source = null player P CursorClick ClickFunc CursorCancel CancelFunc integer CursorType timer T = null boolean Ignore = false static method operator [] takes player P returns CursorData return CDArray[GetPlayerId(P)] endmethod endstruct private function OnCancelOrder takes nothing returns boolean local unit U = GetTriggerUnit() local CursorData C if GetIssuedOrderId() == OrderId(CANCEL_DETECTION_ORDERSTRING) and GetUnitAbilityLevel(U, CANCEL_DETECTION_ABILITY) > 0 then call BJDebugMsg("...cancel...") set C = CursorData[GetOwningPlayer(U)] call PauseTimer(C.T) call ReleaseTimer(C.T) set C.T = null call PauseUnit(U, true) call IssueImmediateOrder(U, "stop") call PauseUnit(U, false) call UnitRemoveAbility(U, CANCEL_DETECTION_ABILITY) call UnitRemoveAbility(U, CursorTypeAbilities[C.CursorType]) call C.CancelFunc.execute(C.P, C.Source) endif set U = null return false endfunction private function OnClickOrder takes nothing returns boolean local unit U = GetTriggerUnit() local CursorData C = CursorData[GetOwningPlayer(U)] if GetIssuedOrderId() == OrderId(CAST_ORDERSTRING) and GetUnitAbilityLevel(U, CursorTypeAbilities[C.CursorType]) > 0 then call BJDebugMsg("...click...") call PauseTimer(C.T) call ReleaseTimer(C.T) set C.T = null call UnitRemoveAbility(C.Source, CANCEL_DETECTION_ABILITY) call PauseUnit(U, true) call IssueImmediateOrder(U, "stop") call PauseUnit(U, false) if C.ClickFunc.evaluate(C.P, C.Source, GetOrderPointX(), GetOrderPointY(), GetOrderTarget()) then call UnitRemoveAbility(C.Source, CursorTypeAbilities[C.CursorType]) elseif GetLocalPlayer() == C.P then call ForceUIKey(CAST_HOTKEY) endif endif set U = null return false endfunction private function PrematureCancel takes CursorData C returns nothing call PauseTimer(C.T) call ReleaseTimer(C.T) set C.T = null call UnitRemoveAbility(C.Source, CANCEL_DETECTION_ABILITY) call UnitRemoveAbility(C.Source, CursorTypeAbilities[C.CursorType]) call C.CancelFunc.execute(C.P, C.Source) endfunction private function Periodic takes nothing returns nothing local CursorData C = CursorData(GetTimerData(GetExpiredTimer())) call BJDebugMsg("Periodic") if not C.Ignore then if GetWidgetLife(C.Source) < 0.406 then call PrematureCancel(C) else if GetLocalPlayer() == C.P then call ForceUIKey(CANCEL_DETECTION_HOTKEY) endif endif else if GetLocalPlayer() == C.P then call ForceUIKey(CAST_HOTKEY) endif set C.Ignore = false endif endfunction function ShowCursor takes player whichPlayer, unit sourceUnit, integer cursorType, CursorClick clickFunc, CursorCancel cancelFunc, boolean overWrite returns boolean local CursorData C = CursorData[whichPlayer] if C.T == null then set C.T = NewTimer() set C.Source = sourceUnit set C.ClickFunc = clickFunc set C.CancelFunc = cancelFunc set C.CursorType = cursorType call SetTimerData(C.T, C) elseif not overWrite then return false endif if GetUnitAbilityLevel(sourceUnit, CANCEL_DETECTION_ABILITY) == 0 then call UnitAddAbility(sourceUnit, CANCEL_DETECTION_ABILITY) call UnitMakeAbilityPermanent(sourceUnit, true, CANCEL_DETECTION_ABILITY) endif if GetUnitAbilityLevel(sourceUnit, CursorTypeAbilities[cursorType]) == 0 then call UnitAddAbility(sourceUnit, CursorTypeAbilities[cursorType]) call UnitMakeAbilityPermanent(sourceUnit, true, CursorTypeAbilities[cursorType]) set C.Ignore = true elseif GetLocalPlayer() == whichPlayer then call ForceUIKey(CAST_HOTKEY) endif if GetLocalPlayer() == whichPlayer then call SelectUnit(sourceUnit, false) call SelectUnit(sourceUnit, true) endif call TimerStart(C.T, CANCEL_PERIOD, true, function Periodic) return true endfunction private function Init takes nothing returns nothing local integer J = 0 loop set CDArray[J] = CursorData.create() set CDArray[J].P = Player(J) set J = J+1 exitwhen J >= 12 endloop call CursorInit() set CancelTrig = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(CancelTrig, EVENT_PLAYER_UNIT_ISSUED_ORDER) call TriggerAddCondition(CancelTrig, Condition(function OnCancelOrder)) set ClickTrig = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(ClickTrig, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER) call TriggerRegisterAnyUnitEventBJ(ClickTrig, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER) call TriggerAddCondition(ClickTrig, Condition(function OnClickOrder)) endfunction endlibrary And attached is a testmap. Type "-" to initiate a cursor display. Every time you click a wisp should appear at the clicked location. Whenever you cancel the sequence (or the system detects a cancel), the wisps will disappear. |
| 08-17-2009, 04:40 PM | #2 |
Didn't really look what kind of stuff you do with force ui key, but if you try to pause an unit when it is casting a spell (before SPELL_EFFECT) when you unpause it the unit will try to recast it. So be sure your spell is truly instant. Also the unit get a point order (851973, Location(0.,0.)) when it is stunned/paused (and wasn't already stunned/paused) |
| 08-19-2009, 10:32 AM | #3 |
But it doesn't have the spell when it gets unpaused.... Also, the same issue occurs if I comment out the pausing/stop-ordering. |
| 08-19-2009, 10:44 AM | #4 |
I tested it, it worked fine for me, I will check the code later, there are a few useful librarys I have at home. |
| 08-19-2009, 10:48 AM | #5 |
Try it a few times, you'll get a false cancel eventually. |
| 08-19-2009, 10:50 AM | #6 |
No, not really, I tested it 5 minutes. Anyway, checking code later, school is out now. |
| 08-19-2009, 02:34 PM | #7 |
I tested it too and got false cancels all the time. Weird. Ill see later today if I understand any of that code. |
| 08-19-2009, 02:50 PM | #8 | |
Quote:
holy crap |
| 08-19-2009, 03:47 PM | #9 |
With the test map attached the wisps appear all the time on Location(0.,0.). I don't have edited and saved the map. And yes it also randomly fail. |
| 08-19-2009, 05:12 PM | #10 |
Yeah, I noticed the wisps appearing at (0,0). They used to appear properly, but something went wonky along the way and now they don't... I think it's the second issue you mentioned, Troll-Brain. |
| 08-19-2009, 06:00 PM | #11 | |
Quote:
Maybe in some specific cases RemoveAbility isn't truly instant ? |
| 08-19-2009, 06:03 PM | #12 |
Oh... You're probably right, since it takes a frame to add the ability, it probably takes one to remove it. I'll try disabling and see what happens then. |
