HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Manually Ordering a Unit to Sleep

07-20-2007, 08:55 AM#1
Pyrogasm
Well, I'm still trying to simulate sleep (like the Dreadlord ability), and I haven't had much luck. It seems that adding the "sleeping" classification does nothing.

DioD also mentioned that sleep has a hidden integer-only orderid, but I've not had any luck. Through testing, I've discovered that when a unit is slept by a spell, it is issued the point-target order 851973. At first I did not believe it to be the right order, but it evidently is because when a unit is sleept, its current order is 851973.

So, I tried ordering units to do that order at its current location, like so:
Trigger:
Manual Sleep
Collapse Events
Player - Player 6 (Orange) skips a cinematic sequence
Conditions
Collapse Actions
Custom script: set bj_wantDestroyGroup = true
Collapse Unit Group - Pick every unit in (Units currently selected by Player 6 (Orange)) and do (Actions)
Collapse Loop - Actions
Custom script: call IssuePointOrderById(GetEnumUnit(), 851973, GetUnitX(GetEnumUnit()), GetUnitY(GetEnumUnit()))
Game - Display to (All players) the text: Ordered
But the units weren't being affected by this order, so I re-initiated my other trigger to see if it was actually being issued the order, and it wasn't.

I've also tried call IssueImmediateOrderById(GetEnumUnit(), 851973), but the unit was ordered to stop instead. I know that this is not the order for stop or hold position, as those are 851972 and 851993 respectively. Any ideas on how to order a unit to manually sleep?

Additionally, I could simply use a simulation of sleep, which would follow these guidelines:
  1. Units will not auto-acquire artifically slept units (and only the slept unit; adding worker classification won't work)
  2. Can be configured to work for any duration
  3. Can be applied multiple times to the same target (resets duration to that of the longest one when cast)
  4. Doesn't require vJASS (Mac != vJASS)
  5. Artifically slept units will keep their previously issued order until being un-slept
  6. Upon the unit taking damage, the sleep will break
  7. Artifically slept units cannot be issued orders, but will not be paused (I suppose I could deal with being paused)

So... who's got the solution? Feel fry to try out my testmap. Pressing escape will order all currently selected units to 851973 (point-target), and the Dreadlord's sleep can be cast on your own units.
Attached Files
File type: w3xSleeping Test Again.w3x (15.9 KB)
07-20-2007, 12:57 PM#2
Castlemaster
Even though I'm 100% sure you are intentionally not using this method, I have to ask, why are you not using a dummy caster?
07-20-2007, 01:32 PM#3
Toink
I think that 851973 orderid thingy is a smart order.
07-20-2007, 05:27 PM#4
Pyrogasm
Quote:
Originally Posted by Castlemaster
Even though I'm 100% sure you are intentionally not using this method, I have to ask, why are you not using a dummy caster?
Because I'm trying to make a custom sleep system in which the time for a unit to be slept will vary.
07-20-2007, 05:33 PM#5
Rising_Dusk
Quote:
Because I'm trying to make a custom sleep system in which the time for a unit to be slept will vary.
Have a dummy unit cast sleep on the target with duration 0 (Infinity) and then remove the buff after a timer callback for however long you want?
That's how the buff system in DoE works.

You also might consider issuing the order without a target.
Like...
Collapse JASS:
call IssueImmediateOrderById(GetEnumUnit(), 851973)
07-24-2007, 07:07 AM#6
Pyrogasm
Been on vacation for 3 days, but I'm back now with more questions :D
Quote:
Originally Posted by Rising_Dusk
Have a dummy unit cast sleep on the target with duration 0 (Infinity) and then remove the buff after a timer callback for however long you want?
That's how the buff system in DoE works.
Blasphemous. Such a simple solution would be too useful >< I shall go about seeing how such a thing might work with multiple instances of sleep on the same unit.
Quote:
Originally Posted by Rising_Dusk
You also might consider issuing the order without a target.
Like...
Collapse JASS:
call IssueImmediateOrderById(GetEnumUnit(), 851973)
Already tried that and all it did was order the unit to stop.
07-24-2007, 10:07 AM#7
Toink
Just check if a unit who is sleeping is sleep-ed again, then if it is just add how X seconds on the remaining duration of the sleep buff.

I was trying to make the same effects of the condition system in DoE.. Here's what I did..

Collapse JASS:
    struct ailmentdata
        unit poisonsource
        unit bleedsource
        unit burnsource
        unit blindsource
        unit cripplesource
        unit poisoncaster
        unit bleedcaster
        unit burncaster
        unit blindcaster
        unit cripplecaster
        unit poisontarget
        unit bleedtarget
        unit burntarget
        unit blindtarget
        unit crippletarget
        real poisondur
        real bleeddur
        real burndur
        real blinddur
        real crippledur
        integer poison = 0
        integer bleed = 0
        integer burn = 0
        integer cripple = 0
        integer blind = 0
    endstruct
 
    function RemoveStatusAilment takes unit u, integer WhichAilment returns nothing
    local ailmentdata dat
        if GetUnitUserData(u) != 0 then
            set dat = ailmentdata(GetUnitUserData(u))
            if WhichAilment == 0 then
                set dat.poisondur = 0
            elseif WhichAilment == 1 then
                set dat.bleeddur = 0
            elseif WhichAilment == 2 then
                set dat.burndur = 0
            elseif WhichAilment == 3 then
                set dat.crippledur = 0
            elseif WhichAilment == 4 then
                set dat.blinddur = 0
            endif
        endif
    endfunction

    function StatusAilment_Callback takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local ailmentdata dat = ailmentdata(GetAttachedInt(t, "dat"))
        if dat.poison != 0 then
            if dat.poison > 0 and GetWidgetLife(dat.poisontarget) > .405 then
                call DamageUnitByOptions(dat.bleedsource, dat.bleedtarget, .8, DamageTypes(ATTACK_TYPE_CHAOS, DAMAGE_TYPE_POISON)+DamageIgnore(UNIT_TYPE_MECHANICAL))
                set dat.poisondur = dat.poisondur - 0.10
            else
                call UnitRemoveAbility(dat.bleedtarget, 'B000')
                set dat.poison = 0
            endif
        endif
        if dat.bleed != 0 and GetWidgetLife(dat.bleedtarget) > .405 then
            if dat.bleeddur > 0 then
                call DamageUnitByOptions(dat.bleedsource, dat.bleedtarget, 1.2, DamageTypes(ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL)+DamageIgnore(UNIT_TYPE_MECHANICAL))
                set dat.bleeddur = dat.bleeddur - 0.10
            else
                call UnitRemoveAbility(dat.bleedtarget, 'B001')
                set dat.bleed = 0
            endif
        endif
        if dat.burn != 0 then
            if dat.burndur > 0 and GetWidgetLife(dat.burntarget) > .405 then
                call DamageUnitByOptions(dat.burnsource, dat.burntarget, 1.6, DamageTypes(ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL)+DamageIgnore(UNIT_TYPE_MECHANICAL))
                set dat.burndur = dat.burndur - 0.10
            else
                call UnitRemoveAbility(dat.burntarget, 'B002')
                set dat.burn = 0
            endif
        endif
        if dat.cripple != 0 then
            if dat.crippledur > 0 and GetWidgetLife(dat.crippletarget) > .405 then
                set dat.crippledur = dat.crippledur - 0.10
            else
                call UnitRemoveAbility(dat.crippletarget, 'B003')
                set dat.cripple = 0
            endif
        endif
        if dat.blind != 0 and GetWidgetLife(dat.blindtarget) > .405 then
            if dat.blinddur > 0 then
                set dat.blinddur = dat.blinddur - 0.10
            else
                call UnitRemoveAbility(dat.blindtarget, 'B004')
                set dat.blind = 0
            endif
        endif
        if dat.bleed == 0 and dat.burn == 0 and dat.cripple == 0 and dat.blind == 0 then
            call CleanAttachedVars(t)
            call ReleaseTimer(t)
            call ailmentdata.destroy(dat)
        endif
    endfunction


    function ApplyStatusAilment takes unit source, unit target, integer WhatAilment, real dur returns nothing
    local ailmentdata dat
    local unit caster
    local timer t
    local integer i = GetUnitUserData(target)
        if i == 0 then
            set dat = ailmentdata.create()
            call SetUnitUserData(target, dat)
        else
            set dat = ailmentdata(i)
        endif
        if dat.bleed == 0 or dat.burn == 0 or dat.cripple == 0 or dat.blind == 0 then
            set t = NewTimer()
            call AttachInt(t, "dat", dat)
            if WhatAilment == 0 then
                if dat.poison == 0 then
                    call CasterCastAbilityLevel(GetOwningPlayer(source), 'A000', 1, "slow", target, true)
                    set dat.poisontarget = target
                    set dat.poisonsource = source
                    set dat.poisondur = dur
                    set dat.poison = 1
                endif
            elseif WhatAilment == 1 then
                if dat.bleed == 0 then
                    call CasterCastAbilityLevel(GetOwningPlayer(source), 'A001', 1, "innerfire", target, true)
                    set dat.bleedtarget = target
                    set dat.bleedsource = source
                    set dat.bleeddur = dur
                    set dat.bleed = 1
                endif
            elseif WhatAilment == 2 then
                if dat.burn == 0 then
                    call CasterCastAbilityLevel(GetOwningPlayer(source), 'A002', 1, "acidbomb", target, true)
                    set dat.burntarget = target
                    set dat.burnsource = source
                    set dat.burndur = dur
                    set dat.burn = 1
                endif
            elseif WhatAilment == 3 then
                if dat.cripple == 0 then
                    call CasterCastAbilityLevel(GetOwningPlayer(source), 'A003', 1, "cripple", target, true)
                    set dat.crippletarget = target
                    set dat.cripplesource = source
                    set dat.crippledur = dur
                    set dat.cripple = 1
                endif
            elseif WhatAilment == 4 then
                if dat.blind == 0 then
                    call CasterCastAbilityLevel(GetOwningPlayer(source), 'A004', 1, "curse", target, true)
                    set dat.blindtarget = target
                    set dat.blindsource = source
                    set dat.blinddur = dur
                    set dat.blind = 1
                endif
            endif
            call TimerStart(t, 0.10, true, function StatusAilment_Callback)
        else
            if WhatAilment == 0 then
                set ailmentdata(i).poisondur = ailmentdata(i).poisondur + dur
            elseif WhatAilment == 1 then
                set ailmentdata(i).bleeddur = ailmentdata(i).bleeddur + dur
            elseif WhatAilment == 2 then
                set ailmentdata(i).burndur = ailmentdata(i).burndur + dur
            elseif WhatAilment == 3 then
                set ailmentdata(i).crippledur = ailmentdata(i).crippledur + dur
            elseif WhatAilment == 4 then
                set ailmentdata(i).blinddur = ailmentdata(i).blinddur + dur
            endif
        endif
    endfunction

There I can modify the duration of buffs by checking if it has the buff.

EDIT: Oh shit, you're on a Mac.. I forgot >_>
07-24-2007, 01:04 PM#8
blu_da_noob
Adding duration would be pretty bad for buffs as you get perfect stacking (especially of say, stun). The way it's done in DoE is using a timer for buff applied to a unit. When you apply a buff, you check the time remaining on the timer. If the time remaining is less, you start it with your new time, otherwise do nothing. Timers are the easiest way to implement stacking duration like that.

Oh and btw Toink I'm pretty sure that system is bugged.
07-24-2007, 06:58 PM#9
Pyrogasm
Funny... the way the Sleep mechanic works in Melee games is that it overrides any previous cast no matter the duration.

I'm building my own sleep functions to have 2 boolean options that can cause the 4 possible outcomes I need:
  • Completely overrides everything and applies the new sleep
  • Only overrides if the new duration is longer than the current duration on the spell
  • Applies new duration only if there is no duration currently present
  • Extends the current duration
07-25-2007, 10:02 AM#10
Toink
@blu: Yeh I just tested it, so I recoded it. But it still works the same way...

I just use GetUnitAbilityLevel() to check if a unit has the buff then just add the duration, if it doesn't it applies the buff.

But I like how your method works.. How do you get the remaining time of a timer?
07-25-2007, 03:12 PM#11
blu_da_noob
TimerGetRemaining(t)

And TimerGetElapsed for already-passed time.
07-26-2007, 08:55 AM#12
Toink
Thanks for that blu! :) So you check if the unit has the buff to check whether it is crippled, etc,. then just access the timer to extend the duration?
07-26-2007, 09:30 AM#13
Pyrogasm
Yes, that is the basis of it.