• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[JASS] Item dissapear help! new in jass.

Status
Not open for further replies.
Level 1
Joined
Mar 2, 2006
Messages
4
i posted an askin for help in the map forum about how to do something, and got the tips to try to write the trigger in JASS instead, problem is i have never used JASS so i have done my best to get this to work after the help i got in the map forum.

what i want to do is so when a unit dies it creates an item for the weapon he carried at his corpse, and that the item dissapears after about 20 seconds.

however i cant get my script to work, if someone can point out what i did wrong and how it should be done i would be very gratefull, cause i tried and tried different scripts for about 1 hour and cant seem to understand JASS and what im doing wrong fully.

my "script" is however like this:


Code:
function Trig_item_Func001C takes nothing returns boolean
    if ( not ( GetUnitTypeId(GetDyingUnit()) == 'h00C' ) ) then
        return false
    endif
    return true
endfunction

function Trig_item_Func002C takes nothing returns boolean
    if ( not ( GetUnitTypeId(GetDyingUnit()) == 'h00A' ) ) then
        return false
    endif
    return true
endfunction

function Trig_item_Func005001 takes nothing returns boolean
    local item i
    return ( CheckItemStatus(i, bj_ITEM_STATUS_OWNED) == true )
endfunction

function Trig_item_Actions takes nothing returns nothing
    local item i=GetLastCreatedItem()
    if ( Trig_item_Func001C() ) then
        call CreateItemLoc( 'I009', GetUnitLoc(GetDyingUnit()) )
    else
    endif
    if ( Trig_item_Func002C() ) then
        call CreateItemLoc( 'I00B', GetUnitLoc(GetDyingUnit()) )
    else
    endif
    set i= GetLastCreatedItem()
    call TriggerSleepAction( 2.00 )
    if ( Trig_item_Func005001() ) then
        call DoNothing(  )
    else
        call RemoveItem( i )
    endif
endfunction

//===========================================================================
function InitTrig_item takes nothing returns nothing
    set gg_trg_item = CreateTrigger(  )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_item, Player(1), EVENT_PLAYER_UNIT_DEATH )
    call TriggerAddAction( gg_trg_item, function Trig_item_Actions )
endfunction
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
here we go.

basic JASS sort of lesson

first, you use an if/then type of condition function. they suck. Period. all of that can be replaced with

JASS:
return (yourcondition)

instead of

JASS:
if (yourcondition) then
        return true
endif
return false

second, for If/Then functions, you dont bother with a seperate function. just putting the condition itself inside the if/then will work fine.

example - instead of

JASS:
function Trig_item_Func001C takes nothing returns boolean
    if ( not ( GetUnitTypeId(GetDyingUnit()) == 'h00C' ) ) then
        return false
    endif
    return true
endfunction 

if ( Trig_item_Func001C() ) then
        call CreateItemLoc( 'I009', GetUnitLoc(GetDyingUnit()) )
    else
    endif

you can say

JASS:
if GetUnitTypeId( GetDyingUnit() ) == 'h00C' then
call CreateItemLoc( 'I009', GetUnitLoc( GetDyingUnit() ) )
else
endif

third, clean up leaks, like

JASS:
GetUnitLoc( GetDyingUnit() )

leaks. fix this by

JASS:
local location l = GetUnitLoc( GetDyingUnit() )

//use location here

call RemoveLocation( l )
set l = null

next, never use BJ functions

BJ functions include funcs that end with...

BJ

Swap

Swapped

PointLoc

and much much more

next, NEVER use something like Dying Unit if you can substitute Triggering Unit for it ( Triggering Unit runs faster. the reason i used GetDyingUnit earlier is so my code was exactly how urs was. )

next, GetLastCreatedxxx is not like GetTriggerUnit. GetTriggerUnit is a native, and what it returns is built into the wc3 game engine. the GetLastCreated funcs return a bj_lastCreated variable. seeing as it is a variable, it has to be set, and is only set by BJ funcs you shouldnt use anyways. in this case, use set ( yourvariable ) = Create , then do whatever with ( yourvariable )

next, DoNothing does, well, NOTHING! delete it.

next, dont use no then but an else. in that case, just use an if NOT then

next, dont put else if there is nothing there

if then
endif

works just fine like

if then
else
endif

next, Simple or any other function, like Periodic or Single, just removes a part of the code that you can do manually and save space.

ex.
JASS:
TriggerRegisterPlayerUnitEventSimple( t, p, EVENT_PLAYER_UNIT_DEATH )
becomes

JASS:
TriggerRegisterPlayerUnitEvent( t, p, EVENT_PLAYER_UNIT_DEATH, null )

after having mauled your code, the finished result is...

JASS:
function Trig_item_Actions takes nothing returns nothing
    local item i
    local unit u = GetTriggerUnit()
    local location l = GetUnitLoc( u )
    if GetUnitTypeId(u) == 'h00C' then
        set i = CreateItemLoc( 'I009', l )
    endif
    if GetUnitTypeId(u) == 'h00A' then
        set i = CreateItemLoc( 'I00B', l )
    endif
    call RemoveLocation( l )
    call TriggerSleepAction( 2.00 )
    if not CheckItemStatus( i, bj_ITEM_STATUS_OWNED ) then
        call RemoveItem( i )
    endif
    set l = null
    set u = null
    set i = null
endfunction

//===========================================================================
function InitTrig_item takes nothing returns nothing
    set gg_trg_item = CreateTrigger(  )
    call TriggerRegisterPlayerUnitEvent( gg_trg_item, Player(1), EVENT_PLAYER_UNIT_DEATH, null )
    call TriggerAddAction( gg_trg_item, function Trig_item_Actions )
endfunction
 
Level 5
Joined
May 22, 2006
Messages
150
But this whould make the item disappear after two seconds instead of twenty, so replace
JASS:
call TriggerSleepAction( 2.00 )
with
JASS:
call TriggerSleepAction(20.00)
.
 
Level 2
Joined
Sep 21, 2005
Messages
27
TriggerSleepAction isn't always accurate depending on processor type. X2's literally speed the game beyond 1:1, so with a few of them TriggerSleepAction(2.00) could fire again in 800ms or 40ms. :shock:

JASS:
function Trig_item_Actions takes nothing returns nothing
	local unit DyingUnit = GetDyingUnit()
	local integer UnitType = GetUnitTypeId(DyingUnit)
	local item SpawnedItem = null
	local timer WaitTimer

	if(UnitType == 'h00C') then
		set SpawnedItem = CreateItem('I009', GetUnitX(DyingUnit), GetUnitY(DyingUnit))
	elseif(UnitType == 'h00A') then
		set SpawnedItem = CreateItem('I00B', GetUnitX(DyingUnit), GetUnitY(DyingUnit))
	endif
	set DyingUnit = null


	if(SpawnedItem != null) then
		set WaitTimer = CreateTimer()


		call TimerStart(WaitTimer, 20.00, false, null)
		loop
			call TriggerSleepAction(1.00)

			exitwhen(TimerGetRemaining(WaitTimer) <= 0.00)
		endloop
		call DestroyTimer(WaitTimer)
		set WaitTimer = null


		if not IsItemOwned(SpawnedItem) then
			call RemoveItem(SpawnedItem)
		endif


		set SpawnedItem = null
	endif
endfunction

//===========================================================================
function InitTrig_item takes nothing returns nothing
	set gg_trg_item = CreateTrigger()
	call TriggerRegisterPlayerUnitEvent( gg_trg_item, Player(1), EVENT_PLAYER_UNIT_DEATH, null )
	call TriggerAddAction( gg_trg_item, function Trig_item_Actions )
endfunction

Ahh...it gets longer and longer the more stable it becomes. :roll:
 
Level 5
Joined
Feb 16, 2006
Messages
151
That's the right direction, but what you wrote would do exactly the same as before, since as you said, there is "TriggerSleepAction".
You have to work with "HandleLocals"
Oh, and, create a global variable of type "GameCache" called "gamecache" ...>_>;(Type: gamecache, Name: gamecache 8))

JASS:
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function game_cache takes nothing returns gamecache   
    if (udg_gamecache==null) then
        call FlushGameCache(InitGameCache("OK.w3v"))
        set udg_gamecache=InitGameCache("OK.w3v")
    endif
    return udg_gamecache
endfunction
 
function SetHandleHandle takes handle subject, string name, handle value returns nothing
    if value==null then
        call FlushStoredInteger(game_cache(),I2S(H2I(subject)),name)
    else
        call StoreInteger(game_cache(), I2S(H2I(subject)), name, H2I(value))
    endif
endfunction

function GetHandleItem takes handle subject, string name returns item
    return GetStoredInteger(game_cache(), I2S(H2I(subject)), name)
    return null
endfunction

function FlushHandleLocals takes handle subject returns nothing
    call FlushStoredMission(game_cache(), I2S(H2I(subject)) )
endfunction
//I would write those into the header, but shrugs....

function remove_item takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local item SpawnedItem = GetHandleItem(t,"Spawned Item")
    if not IsItemOwned(SpawnedItem) then
        call RemoveItem(SpawnedItem)
    endif
    call DestroyTimer(t)
    call FlushHandleLocals(t)
    set t = null
    set SpawnedItem = null
endfunction
    

function Trig_item_Actions takes nothing returns nothing
    local unit DyingUnit = GetDyingUnit()
    local integer UnitType = GetUnitTypeId(DyingUnit)
    local item SpawnedItem = null
    local timer ri_timer = CreateTimer()
     
    if(UnitType == 'h00C') then
        set SpawnedItem = CreateItem('I009', GetUnitX(DyingUnit), GetUnitY(DyingUnit))
    elseif(UnitType == 'h00A') then
        set SpawnedItem = CreateItem('I00B', GetUnitX(DyingUnit), GetUnitY(DyingUnit))
    endif     
    if (SpawnedItem != null) then      
        call SetHandleHandle(ri_timer,"Spawned Item",SpawnedItem)
        call TimerStart(ri_timer, 20.00, false, function remove_item)   //No parameter!!            
    endif
    set DyingUnit = null   
    set SpawnedItem = null
    set ri_timer =  null
endfunction
 
//===========================================================================
function InitTrig_item takes nothing returns nothing
    set gg_trg_item = CreateTrigger()
    call TriggerRegisterPlayerUnitEvent( gg_trg_item, Player(1), EVENT_PLAYER_UNIT_DEATH, null )
    call TriggerAddAction( gg_trg_item, function Trig_item_Actions )
endfunction
 
Level 5
Joined
May 22, 2006
Messages
150
Ah, if that is not a kind of experienced scripter!
Well, maybe you are able to tell me, why a local variable has to be set to "null" after destroying the referenced object to prevent a memory leak - or what it is, that leaks there.

By the way... A function of name "H2I" does exist nor in "common.j" neither in "blizzard.j".

And if you may finally explain the use of this cache handling, I whould be very grateful as I have no idea, what it may be good for. ^^
 
Level 5
Joined
May 22, 2006
Messages
150
So you create this cache only as an object/primitive converter!?
What a waste...

May you tell me, what "flush" means?
I do not think it has anything to do with "becoming red", "dancing around because of victory" or "discarding the contents of a lavatory".
This is what I found in my dictionary. ^^

May it mean to remove the integer from the cache?
That seems not to make much sense...
Or does it?
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Kramy --> thats just PolledWait you're doing there

Kramy and UnMi ---> and TriggerSleepAction is accurate enough for long waits that noone will notice the difference, and there is no point bloating the script for it

LordZsar1 --> H2I is a custom function, part of the Local Handle Variables, which work on Gamecaches
Also, FlushHandleLocals just prevents leaks ( as in, the data stored in a gamecache sits there after becoming unneeded, and this cleans it up. it is also part of the Local Handle Variables.
 
Level 5
Joined
May 22, 2006
Messages
150
So you use one function for two different operations...
As I supposed...
My informatics teacher whould kill you but I can feel comfortable with that. ^^

Still, why should not it work this way as good?
JASS:
function transformHandleInteger takes handle subject returns integer
return subject
return 0
endfunction

Reversed it does.
 
Level 5
Joined
Feb 16, 2006
Messages
151
PurplePoot said:
Kramy and UnMi ---> and TriggerSleepAction is accurate enough for long waits that noone will notice the difference, and there is no point bloating the script for it
No...
The longer the TriggerSleepAction and the bigger the latency is, the bigger will be the the difference, and believe me, it is a lot!
If you want it really accurate, you have to use Timers.
But if you want something like circa 20 seconds, you can always do TriggerSleepActions...
 
Level 5
Joined
May 22, 2006
Messages
150
Well, I think it depends on the mathematical function, that is linking the two values together.

if it is exponential - something like
"waitingTime*a -> Power(randomDivergence;a)" -
it whould create a real problem on bigger values,
if it is logarithmical - like
"a*waitingTime*c -> b*lg(randomDivergence)/lg(c)" -
it whould become less and less important the longer we want to wait. ^^

Maybe it is simply something like "a*waitingTime -> b*randomDivergence"...

So, collect some epirical data and then try to find the function. ^^
I do not know, how it is called in English, but we are calling it "Komplexitätsuntersuchung" and it is a duty, I hate to do.

But do not let me stopping you - take a bunch of real values, which have a large difference between them - 2500.00, 5000.00, 7500.00 and 10000.00 for example - and time the divergence from the specified value.
Do this five or more times for each value, calculate the arithmetical means and try to work out a function, which fits for them.

It is a really big piece of work, but without you will not be able to answer the question, if timers are necessary for bigger waiting times or not.

It whould be very nice if you whould share your knowledge afterwards. ^^
 
Level 5
Joined
Feb 16, 2006
Messages
151
I can't say I understood anything, but I know myself for sure that the delay of TriggerSleepAction can be very bothersome..
Like, if you live in Germany and play a game on USEast, you will notice the delay no matter what.
And oh, ja, versuchs doch mal selbst >>, musst aber USeast oder so sein.
Am besten kannst du das herausfinden, indem du Texte (Sound)fuer bestimmte Zeitintervalle ausgibst.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
it seems that If 75% of (the wait you want) is > .27 then you use 75% of the wait you want as the wait.. its always worked fine for me

also, im not sure if anyone cares if the item lasts 10s or 11.5s

LordZsar1 said:
Still, why should not it work this way as good?

thats exactly the same thing as H2I, just with renamed values

and of course it works both ways xD
 
Level 2
Joined
Sep 21, 2005
Messages
27
UnMi said:
But if you want something like circa 20 seconds, you can always do TriggerSleepActions...

That's exactly the time I would not use them. I experimented with a friend, and using X2's we were able to totally mess up many maps. For example, the FM map Legacies: Tides of the Serpent has trading unlocked instantly rather than in 10 minutes, because of TriggerSleepAction(). That means it's firing about 600x sooner than it should. :?

SWAT: Aftermath also had that problem until the creator replaced TriggerSleepAction() with code equivalent to PolledWait(). Radiation would soar about 10 per second, rather than 1 per minute. That's another case where it's exactly 600x faster than it should be.

Then there's maps like Card Shuffle, which randomly malfunction, but nobody knows why. :roll:

And crappily coded/balanced TDs seem to randomly have time between rounds shorten or lengthen if they don't use timers, depending on who joins those games.

However, that doesn't mean that that's the only direction it can go. I've played with someone that has a 550mhz, and he actually forced TriggerSleepAction the other way. TriggerSleepAction(1.00) could fire in 2.5 seconds or more.

TriggerSleepAction should never be trusted to keep accurate time. Only use it where you don't care if it fires too soon or too late, or you know everyone playing is going to have relatively decent non-dualcore computers.
 
Level 5
Joined
Feb 16, 2006
Messages
151
Uh, you actually said the same as I did, or did I use the wrong english words?*looking up*
The difference is, that the longer the TriggerSleepAction is, the bigger could be the delay.
In this case, something like TriggerSleepAction(20) won't be bothersome, because I don't think you care wether it's actually 20 seconds or 30, aka. circa 20 seconds...
I don't believe it can be scretched up to 1 minute, but I'm not sure.(If yes, screw the TriggerSleepActions)
So a TriggerSleepAction of 10 minutes is another story, there you have to use timers.
And, I have to agree with your point about TriggerSleepActions:
Don't trust them.
TimerHandles are just leet hax!
 
Level 5
Joined
Feb 16, 2006
Messages
151
...
PolledWaits, are even worse than TriggerSleepActions, imo...
JASS:
function PolledWait takes real duration returns nothing
    local timer t
    local real  timeRemaining

    if (duration > 0) then
        set t = CreateTimer()
        call TimerStart(t, duration, false, null)
        loop
            set timeRemaining = TimerGetRemaining(t)
            exitwhen timeRemaining <= 0

            // If we have a bit of time left, skip past 10% of the remaining
            // duration instead of checking every interval, to minimize the
            // polling on long waits.
            if (timeRemaining > bj_POLLED_WAIT_SKIP_THRESHOLD) then
                call TriggerSleepAction(0.1 * timeRemaining)
            else
                call TriggerSleepAction(bj_POLLED_WAIT_INTERVAL)
            endif
        endloop
        call DestroyTimer(t)
    endif
endfunction
Sure, they use Timers, but in the end they still use TriggerSleepActions, even if 0.1 by 0.1...
 
Status
Not open for further replies.
Top