• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Creating special effect for player

Status
Not open for further replies.
Level 6
Joined
Mar 26, 2008
Messages
239
Explanation: I wanted to create special effect for player (the effect will ve visible only for 1 or group of players), but I didn't know how. Then I read this tutor:
http://www.hiveworkshop.com/forums/jass-ai-scripts-tutorials-280/using-getlocalplayer-59368/
Here is the method I used(For those who don't want to look for it in the tutor:thumbs_up:):
JASS:
function AddSpecialEffectForPlayer takes location where, string modelpath, player whichplayer returns nothing
    local string s = ""
    if GetLocalPlayer() == whichplayer then
       set s = modelpath
endif
       call AddSpecialEffectLoc(modelpath,where)
endfunction
But this method caused desync.
Question:
1)Can it be fixed? And if not then:
2)How can I do that? (I mean any other method)
 
Level 9
Joined
Nov 4, 2007
Messages
931
The desync can't be fixed in this case, its inevitable, but you might be able to change it by changing the model of a dummy unit to an SFX then giving it invisibility limited to only the player(s) that you don't want able to see it.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
You're using the wrong variable in your AddSpecialEffectLoc call. It should be:

JASS:
function AddSpecialEffectLocForPlayer takes player forPlayer, string modelPath, location loc returns effect
    if GetLocalPlayer() != forPlayer then
        set modelPath = ""
    endif
    call AddSpecialEffectLoc( modelPath, loc )
endfunction

I changed it up a little bit but the problem was you using modelpath instead of s. I don't know why this would be causing a desync in any situation though.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
When you use the code I have posted, does it desync? It shouldn't.

LexX said:
What worng variable?

You use modelpath (as I said above) to create the special effect, so setting s in a local-player if-statement won't change anything. What you were doing is creating a special effect that used the same model-path for every player (not localizing it). This also means that the fact that your map is having desync problems has nothing to do with this code because you weren't even doing anything local before but you still reported a desync.

hvo-busterkomo said:
JASS:
function AddSpecialEffectForPlayer takes location where, string modelpath, player whichplayer returns nothing
    local string s = ""
    if GetLocalPlayer() == whichplayer then
       set s = modelpath
endif
       call AddSpecialEffectLoc(modelpath,where)
endfunction
So as you can see, the model path is only correct for one player, for all other players the effect would be blank, thus creating the special effect for only 1 player.

Yea this is wrong. He's setting s = modelpath for the local player but then he is just using modelpath to create the special effect, making the if-statement useless. What a great tutorial.
 
Level 6
Joined
Mar 26, 2008
Messages
239
When you use the code I have posted, does it desync? It shouldn't.

You use modelpath (as I said above) to create the special effect, so setting s in a local-player if-statement won't change anything. What you were doing is creating a special effect that used the same model-path for every player (not localizing it). This also means that the fact that your map is having desync problems has nothing to do with this code because you weren't even doing anything local before but you still reported a desync.

Yea this is wrong. He's setting s = modelpath for the local player but then he is just using modelpath to create the special effect, making the if-statement useless. What a great tutorial.
Well it DOES desync, I used some other things with locals before(like ping minimap, create floating text and some others). Then I made a spell with effects which only owner of caster should see. But everytime I used the spell my friends, with whom I was testing the map, were disconnected.
So...I asked to write the right way to make effect visible for player, and not explain why method in tutor is wrong or not, so PLEASE write it:wink:I need it=)
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
So...I asked to write the right way to make effect visible for player, and not explain why method in tutor is wrong or not, so PLEASE write it:wink:I need it=)

The desync can't be fixed in this case, its inevitable, but you might be able to change it by changing the model of a dummy unit to an SFX then giving it invisibility limited to only the player(s) that you don't want able to see it.

  • SFX for player
    • Events
      • Player - Player 1 (Red) types a chat message containing <Empty String> as A substring
    • Conditions
    • Actions
      • Set p = (Player((Integer((Entered chat string)))))
      • Set loc = (Point(0.00, 0.00))
      • Unit - Create 1 Footman for p at loc facing Default building facing degrees
      • Custom script: if GetLocalPlayer() != udg_p then
      • Unit - Hide (Last created unit)
      • Custom script: endif
      • Special Effect - Create a special effect attached to the overhead of (Last created unit) using Abilities\Spells\Other\TalkToMe\TalkToMe.mdl
      • Custom script: call RemoveLocation(udg_loc)
      • Game - Display to (All players) the text: (Name of p)
of cause you should use a dummy model with nothing but an attachment point
 

Attachments

  • SFX FOR PLAYER.w3x
    16.4 KB · Views: 67
Level 6
Joined
Mar 26, 2008
Messages
239
  • SFX for player
    • Events
      • Player - Player 1 (Red) types a chat message containing <Empty String> as A substring
    • Conditions
    • Actions
      • Set p = (Player((Integer((Entered chat string)))))
      • Set loc = (Point(0.00, 0.00))
      • Unit - Create 1 Footman for p at loc facing Default building facing degrees
      • Custom script: if GetLocalPlayer() != udg_p then
      • Unit - Hide (Last created unit)
      • Custom script: endif
      • Special Effect - Create a special effect attached to the overhead of (Last created unit) using Abilities\Spells\Other\TalkToMe\TalkToMe.mdl
      • Custom script: call RemoveLocation(udg_loc)
      • Game - Display to (All players) the text: (Name of p)
of cause you should use a dummy model with nothing but an attachment point
No, this is not what I need, because what if I want to make an effect for player, attached to weapon (arms, legs, etc.) of any unit?
I need make the effect visible/unvisible without using dummy unit.
 
Level 6
Joined
Mar 26, 2008
Messages
239
if it does not work you could do something like

if local player == playerWhichShallSeeTheEffect then
create special effect on a unit
else
create special effect on a unit which is not visible
endif

so you don't mess up the handle counter
I don't know what it is though
worth a try anyway
"create special effect on a unit which is not visible" means dumy unit which is hidden, and I said that I need to make effect invisible itself and not with help of dummies, because, for example, if I want to make effect attached to a hero (weapon, arms, etc.) it won't work at all.
 
Level 6
Joined
Mar 26, 2008
Messages
239
JASS:
globals
    private effect effectVar = null
endglobals

function addSpecialEffectForPlayer takes player p, real x, real y, string eff returns effect
    local string s = ""

    if GetLocalPlayer() == p then
        set s = eff
    endif

   set effectVar = AddSpecialEffect(s, x, y)
   set s = null
   return effectVar
endfunction
This too?
It is the same like I did but much more complicated.
Here is the part of code in my spell:
JASS:
private function Effect takes nothing returns nothing
 local string s
    if ( GetUnitState(GetEnumUnit(), UNIT_STATE_LIFE) <= 0 ) then
      if (GetLocalPlayer() == GetOwningPlayer(GetTriggerUnit())) then
        set s = "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl"
      endif
      call DestroyEffect( AddSpecialEffect( s , GetUnitX(GetEnumUnit()) , GetUnitY(GetEnumUnit()) ))
      call SetUnitState( GetTriggerUnit(), UNIT_STATE_MANA , GetUnitState(GetTriggerUnit() , UNIT_STATE_MANA) + 5.00 + 5.00 * I2R(GetUnitAbilityLevel(GetTriggerUnit() , 'A01R')) )
      call RemoveUnit( GetEnumUnit() )
      set I = I + 5 + 5 * GetUnitAbilityLevel(GetTriggerUnit() , 'A01R')
    endif
 set s = null
endfunction
 
Level 6
Joined
Mar 26, 2008
Messages
239
Mine also cleans all leaks that were made by my function. Also please try to use my function.
Well, in my function there are no leaks, and result of both systems is the same, just your is more complicated, you set strings and effects about 2 times (first type string for function and then set s = eff, and set effectVar =... and then return effectVar) and I just set s and create effect. This is the only difference.
But still I'll try, but don't know when I'l be able to check if it works or not, so conversation continues=)

EDIT:
Hey, I forgot!
I told 2 times that:
1)I need system which could make effect visible to player or player group, and your system contains only player. OK, it's fixable, then:
2)I need system that could make ANY created effect visible only for player or player group, not only CreateSpecialEffect(...), for example AddSpecailEffectTarget(...). I don't want to make many systems for 1 purpose. So I need 1 system (well if not system then just way, like in my spell, the system is in the spell, not separate function) for all effects and player and player group.
 
1)I need system which could make effect visible to player or player group, and your system contains only player. OK, it's fixable, then:
Yeah, pretty easily to manipulate.

2)I need system that could make ANY created effect visible only for player or player group, not only CreateSpecialEffect(...), for example AddSpecailEffectTarget(...). I don't want to make many systems for 1 purpose. So I need 1 system (well if not system then just way, like in my spell, the system is in the spell, not separate function) for all effects and player and player group.
You need to rewrite every function on your own. Thats how wc3 works.

lol, what about initializing s = "" ? ^^
If it isn't set, its crashes wc3 for everyone else.
 
Level 6
Joined
Mar 26, 2008
Messages
239
Like you see in my piece of spell, I didn't use other function to create effect and make it visible (like the one you wrote), I used it inside of spell, but this way to make it caused desync, so I asked if there is other way which I could use inside of spell too, but fully working.
 
Level 6
Joined
Mar 26, 2008
Messages
239
Just use my function... It should work, I am 100% sure.
And initialize your damn string s variable ...
If I use your function, I'll have to write about 4 functions (player-point, player-unit, player group-point, player group-unit) if not more than 4. It's bad, u know))
And even if I do it, still your function works EXACTLY like piece of code in my spell, can you understand it or not??? They are the SAME, just mine is more simple.
But ANYWAY I'll try it just to calm you down:grin:
 
Level 6
Joined
Mar 26, 2008
Messages
239
They are more general, and can be used in any situation. While your code only creates local effects in the spell, my can be used anywhere from any system. This makes mine far more useable as your.
Agree, but your function can only make player-point effect.
If you add player group, unit attachable effect and also timed effect (if I need it to have effect which disappears in some time) and if ALL THIS will be in 1 system and it will work then it'll be cool=)
 
JASS:
/*
    LocalEffects
    
    Small library by Anachron to create
    effects which are displayed locally
    for players and/or forces only.
*/
library LocalEffects

    globals
        private string  eff = null
        private force   for = null
    endglobals

    function addEffectToUnitForPlayer takes player p, unit u, string a, string e returns effect
        set eff = null
        
        if GetLocalPlayer() == p then
             set eff = e
        endif
        
        return AddSpecialEffectTarget(eff, u, a)    
    endfunction
    
    function addEffectOnPositionForPlayer takes player p, real x, real y, string e returns effect
        set eff = null
        
        if GetLocalPlayer() == p then
             set eff = e
        endif
        
        return AddSpecialEffect(eff, x, y)    
    endfunction
    
    function addEffectToUnitForForce takes force f, unit u, string a, string e returns nothing
        local integer i = 0
        
        loop
            exitwhen i >= 15
            
            if IsPlayerInForce(Player(i), f) then
                call addEffectToUnitForPlayer(Player(i), u, a, e)
            endif
            
            set i = i +1
        endloop 
    endfunction
    
    function addEffectOnPositionForForce takes force f, real x, real y, string e returns nothing
        local integer i = 0
        
        loop
            exitwhen i >= 15
            
            if IsPlayerInForce(Player(i), f) then
                call addEffectOnPositionForPlayer(Player(i), x, y, e)
            endif
            
            set i = i +1
        endloop 
    endfunction

endlibrary

Written out of the head, you have to fix the errors.

Example usage in your code:
JASS:
private function Effect takes nothing returns nothing
    if ( GetUnitState(GetEnumUnit(), UNIT_STATE_LIFE) <= 0 ) then
      call DestroyEffect( addEffectOnPositionForPlayer(GetOwningPlayer(GetEnumUnit()) , GetUnitX(GetEnumUnit()) , GetUnitY(GetEnumUnit()), "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl"))
      call SetUnitState( GetTriggerUnit(), UNIT_STATE_MANA , GetUnitState(GetTriggerUnit() , UNIT_STATE_MANA) + 5.00 + 5.00 * I2R(GetUnitAbilityLevel(GetTriggerUnit() , 'A01R')) )
      call RemoveUnit( GetEnumUnit() )
      set I = I + 5 + 5 * GetUnitAbilityLevel(GetTriggerUnit() , 'A01R')
    endif
 set s = null
endfunction
 
Level 6
Joined
Mar 26, 2008
Messages
239
JASS:
/*
    LocalEffects
    
    Small library by Anachron to create
    effects which are displayed locally
    for players and/or forces only.
*/
library LocalEffects

    globals
        private string  eff = null
        private force   for = null
    endglobals

    function addEffectToUnitForPlayer takes player p, unit u, string a, string e returns effect
        set eff = null
        
        if GetLocalPlayer() == p then
             set eff = e
        endif
        
        return AddSpecialEffectTarget(eff, u, a)    
    endfunction
    
    function addEffectOnPositionForPlayer takes player p, real x, real y, string e returns effect
        set eff = null
        
        if GetLocalPlayer() == p then
             set eff = e
        endif
        
        return AddSpecialEffect(eff, x, y)    
    endfunction
    
    function addEffectToUnitForForce takes force f, unit u, string a, string e returns nothing
        local integer i = 0
        
        loop
            exitwhen i >= 15
            
            if IsPlayerInForce(Player(i), f) then
                call addEffectToUnitForPlayer(Player(i), u, a, e)
            endif
            
            set i = i +1
        endloop 
    endfunction
    
    function addEffectOnPositionForForce takes force f, real x, real y, string e returns nothing
        local integer i = 0
        
        loop
            exitwhen i >= 15
            
            if IsPlayerInForce(Player(i), f) then
                call addEffectOnPositionForPlayer(Player(i), x, y, e)
            endif
            
            set i = i +1
        endloop 
    endfunction

endlibrary
Written out of the head, you have to fix the errors.
1.Well again you set effect = string o_O Almost whole system is wrong o_O
2.I don't understand why you use globals..
3.But I understood how can I make such system, but STILL it uses the SAME way as in tutor and that is why it WILL still cause desync.

EDIT:
Oh sorry about "1." I wrote, I read wrong=)But "2." and especially "3." stay
 
Level 6
Joined
Mar 26, 2008
Messages
239
To prevent leaks.


Wehrm I never had a desync problem with that usage.
What leaks???
you could just make functions return nothing and instead of:
return AddSpecialEffectTarget(eff, u, a)
type:
call DestroyEffect (AddSpecialEffectTarget(eff, u, a))
and instead of global string use local and then set it = null, because if these effects are created veeeeery fast and by not 1 player, then it'll be better to make it with local.
"Wehrm I never had a desync problem with that usage." You just typed it and you say that you used it before? How?=)
And I already told that this way (the way in tutor = the way you wrote) caused desync, I tested it many times, so I cannot understand why you insist that this way works:eekani:
 
What leaks???
Atleast one handle if you want to return that effect.

and instead of global string use local and then set it = null, because if these effects are created veeeeery fast and by not 1 player, then it'll be better to make it with local.
Globals are faster then locals.

"Wehrm I never had a desync problem with that usage." You just typed it and you say that you used it before? How?=)
And I already told that this way (the way in tutor = the way you wrote) caused desync, I tested it many times, so I cannot understand why you insist that this way works
I rewrote, I lost all of my stuff when my HDD crashed.
 
Level 6
Joined
Mar 26, 2008
Messages
239
I wanted to ask why you use:
JASS:
function addEffectToUnitForForce takes force f, unit u, string a, string e returns nothing
 local integer i = 0
    loop
    exitwhen i >= 15
      if IsPlayerInForce(Player(i), f) then
        call addEffectToUnitForPlayer(Player(i), u, a, e)
      endif
    set i = i +1
    endloop
endfunction
instead of:
JASS:
function addEffectToUnitForForce takes force f, unit u, string a, string e returns nothing
    if IsPlayerInForce(GetLocalPlayer(), f) then
      call addEffectToUnitForPlayer(GetLocalPlayer(), u, a, e)
    endif
endfunction
It is more simple, isn't it? (don't know if it's right or not so just asking)
And it is even more simple to write separate functions, because for example in addEffectToUnitForForce you use 2 functions when you can use 1.
 
It is more simple, isn't it? (don't know if it's right or not so just asking)
You don't understand. If you use GetLocalPlayer() in this case, the effect handle is only created for one player. Thus disconnecting everyone.

And it is even more simple to write separate functions, because for example in addEffectToUnitForForce you use 2 functions when you can use 1.
Its not possible to put these functions together with no split.
 
Level 13
Joined
Mar 16, 2008
Messages
941
Because the second version would run the function localy.
JASS:
function addEffectToUnitForPlayer takes player p, unit u, string a, string e returns effect
        set eff = null

        if GetLocalPlayer() == p then
             set eff = e
        endif

        return AddSpecialEffectTarget(eff, u, a)
endfunction
Running this code localy is the same then just normaly
creating an effect localy and this desyncs.
The funtions all work, I used them often enough.

And in addition:
locals aren't more save then globals.
If no waits/timers are used,
it's impossible for globals to fail.

EDIT: hmrf :( :O
 
Level 6
Joined
Mar 26, 2008
Messages
239
You don't understand. If you use GetLocalPlayer() in this case, the effect handle is only created for one player. Thus disconnecting everyone.
That's why I asked=)
And in addition:
locals aren't more save then globals.
If no waits/timers are used,
it's impossible for globals to fail.
I know, but if add to this system smth. like timed effect, then it'll better to use locals.
Ok, I'll check this system and see if it works.
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
I tried this
JASS:
function AddSpecialEffectForPlayer takes player p, real x, real y, string eff returns effect
    local string s = ""

    if GetLocalPlayer() == p then
        set s = eff
    endif

   set udg_effect = AddSpecialEffect(s, x, y)
   set s = null
   set eff = null
   set p = null
   return udg_effect
endfunction
  • Test
    • Events
      • Player - Player 1 (Red) types a chat message containing <Empty String> as A substring
    • Conditions
    • Actions
      • Set p = (Player((Integer((Entered chat string)))))
      • Set s = Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
      • Custom script: call DestroyEffect(AddSpecialEffectForPlayer(udg_p, 0, 0, udg_s))
and it instantly disconnects (online only though - did not test solo but with 2 players)

what's wrong?
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
You don't need to null parameter values.

good to know thanks :grin:
(why is it like that? is it the same with all other parameter variables like locations or only with these?)

Also the escape character sequence is invalid. It has to be \\ in vJass.

might be but it's not JASS it's GUI
it triggers as it is supposed to be (tested in the dummy example map uploaded before)

Just use my functions, what so bad about them?

it's yours except I tried to remove the non-existent leak and renamed the global variable
 
good to know thanks
(why is it like that? is it the same with all other parameter variables like locations or only with these?)
It doesn't leak for any variable. Its because blizzard stores the parameters (I think so) in another variables which will be cleaned after execution.

might be but it's not JASS it's GUI
it triggers as it is supposed to be (tested in the dummy example map uploaded before)
But you pass that value into vJass. Test it with \\ please.

it's yours except I tried to remove the non-existent leak and renamed the global variable
Non-existing leak? You added a global GUI variable, thats the same what I did with the global. Thats really awkward.
 
Level 6
Joined
Mar 26, 2008
Messages
239
I think it causes desync because we set string of effect using GetLocalPlayer(), and the effect will not be blank for other players like it's said in tutor but it'll cause desync...It'll mean that this method is wrong at all, and there should be other way to make effect for player, not by setting string like that.
I didn't test the system now, but I still think it will cause desync=)
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
It doesn't leak for any variable. Its because blizzard stores the parameters (I think so) in another variables which will be cleaned after execution.

I just tried the same with locations and they leak (probably they won't leak with RemoveLocation and without set loc = null but I did not test it)

But you pass that value into vJass. Test it with \\ please.

things with \ are automatically converted to things with \\ as soon as you convert it to custom script


Non-existing leak? You added a global GUI variable, thats the same what I did with the global. Thats really awkward.

renaming globals is not awkward at all if you don't use JNGP and I was talking about
JASS:
set p = null
set eff = null
 
Level 9
Joined
Nov 28, 2008
Messages
704
How about:

JASS:
function SetStringForPlayer takes string s, player p returns string
    if GetLocalPlayer() != p then
        set s = null
    endif
    return s
endfunction

function Something takes nothing returns nothing
    call AddSpecialEffect(SetStringForPlayer("Shiny.mdx", Player(0)), 0, 0)
endfunction

Doesn't seem like it would desync to me. Unless you started setting things globally.

Edit: Tested with a friend, no desyncs. I would recommend using this method.

Edit 2: Attached testmap. Also, dont save it. I forgot that not everyone has cJass. Just push test map or play with it in wc3.
 

Attachments

  • fale.w3m
    13.4 KB · Views: 45
Last edited:
Level 6
Joined
Mar 26, 2008
Messages
239
How about:

JASS:
function SetStringForPlayer takes string s, player p returns string
    if GetLocalPlayer() != p then
        set s = null
    endif
    return s
endfunction

function Something takes nothing returns nothing
    call AddSpecialEffect(SetStringForPlayer("Shiny.mdx", Player(0)), 0, 0)
endfunction
Doesn't seem like it would desync to me. Unless you started setting things globally.

Edit: Tested with a friend, no desyncs. I would recommend using this method.

Edit 2: Attached testmap. Also, dont save it. I forgot that not everyone has cJass. Just push test map or play with it in wc3.
I understood how you made this and will try it as soon as I can. If it really works for me then it's exactly what I need=)
 
Level 9
Joined
Nov 28, 2008
Messages
704
o_O

Could you post the code?

Also:

JASS:
function SetStringForForce takes string s, force f returns string
    if IsPlayerInForce(GetLocalPlayer(), f) then
        set s = null
    endif
    return s
endfunction
 
Last edited:
Level 13
Joined
Mar 16, 2008
Messages
941
Well, this "can" desync.
I thought off this method long time ago,
but someone told me that the string has to
be set to "" first and the string must be inserted
localy. The other way round it "can" happen that the
string-tables get messed up and your new strings
will fail. Never had that problem, just the problem
why people don't use yours.
 
Status
Not open for further replies.
Top