Warcraft III resources & community, 2003–2006 · archived

Item dissapear help! new in jass.

20 posts
#1

Item dissapear help! new in jass.

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:


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
#2
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

return (yourcondition)


instead of

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

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

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


third, clean up leaks, like

GetUnitLoc( GetDyingUnit() )


leaks. fix this by

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.
TriggerRegisterPlayerUnitEventSimple( t, p, EVENT_PLAYER_UNIT_DEATH )

becomes

TriggerRegisterPlayerUnitEvent( t, p, EVENT_PLAYER_UNIT_DEATH, null )


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

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
#3
But this whould make the item disappear after two seconds instead of twenty, so replace
call TriggerSleepAction( 2.00 )
with
call TriggerSleepAction(20.00)
.
#4
i know, i just kept what he had xD

anyways, in taht type of map, make them disappear after 10s MAX, to prevent lag. there will be enuff miniguns around anyways...
#5
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:

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:
#6
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))


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
#7
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. ^^
#9
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?
#10
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.
#11
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?
function transformHandleInteger takes handle subject returns integer
return subject
return 0
endfunction


Reversed it does.
#12
PurplePoot

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...
#13
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. ^^
#14
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.
#15
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

LordZsar1Still, 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