• 🏆 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!

Question about multi player quest mechanics

Status
Not open for further replies.
Level 4
Joined
Apr 19, 2013
Messages
86
I don't have multiple computers / wc3's, and none of my friends are into the game anymore, so I don't have a way to figure this out for myself.

I really wonder how quests work in multi player mode. I noticed in the wc3 editor's variable manager quests can be configured to be arrays, this may just be arbitrary, but the only reason for making a quest an array is maybe to help with making it repeatable or for multiple players. So I've always assumed its possible, but before I code for hours and hours I wanna get some confirmation if anyone has expertise about this.

Suppose I made a 4 Player map with 3 identical quests. Would the players be able to complete these quests discretely on their on terms and in their own time?

I also noticed that in single player, or even when I click test map, toggling the quest menu pauses the game. That kind of makes me doubt sometimes that multiplayer quests are feasible at all. Or does toggling the quest menu in a multi player game actually not pause the game?

Any insights would be great, ty
 
The way quests are currently designed, they are natively completed/discovered/failed globally. However, there are ways to avoid this through clever use of GetLocalPlayer(). You will have the same quest for everyone, but you set it to discovered/completed locally depending on which player you want to disable/enable it for.

GetLocalPlayer() is a function that retrieves the player currently executing the code at that instant of time. By doing something like this:
JASS:
if GetLocalPlayer() == Player(0) then
    call BJDebugMsg("Hello World!")
endif
You can perform actions for just one player. The above example will check "if the player executing the code is player 1 (red), then display "Hello World!". Since that condition will only be true for Player 1 (red), the message is only displayed to Player 1 (Red). If Player 2 (Blue) runs through it, GetLocalPlayer() will refer to Player 2 (Blue), so it is impossible for them to get into the if-block.

However, there is a downside. Warcraft 3 checks whether certain things are synchronized (mostly things that affect gameplay). For example, let's say you move a unit locally for Player 1 (red). Player 1 (red) will show the unit in one location, but all other units will show it in another area. If the unit is issued an order to another point, for Player 1 (red) it may take 10 seconds but for all the other players it may take some different length of time, e.g. 5 seconds. Instead of accounting for it all, Warcraft 3 will just disconnect the players. This limits what you can and cannot do with GetLocalPlayer().

For more info, check out the link "GetLocalPlayer()" in my signature. I highly recommend understanding the nature of the function before trying to use it. With it, you can locally discover/complete quests, which is done in things like TKoK/Gaia's (I assume).
 
Level 4
Joined
Apr 19, 2013
Messages
86
Whoa, that is awesome, thank you for the solution. I read through your tutorial.

I think GetLocalPlayer will be a reasonable solution, I simply want to use it to discover/complete quests as well as locally update quest requirements for each player.

My only question now is: Would I still need quest arrays? Suppose 2 players are working on the same gather type of quest but Player(0) has gathered 6/10 metal ores, and Player(1) has only gathered 2/10 metal ores. My quest system simply displays a quest update and quest requirement change each time a metal ore is acquired. If quests are globally discovered/failed/ect then the quest requirement changes are also global right? Is it possible for Player(0)'s quest requirement to be changed each time he acquire's metal ore without interfering with Player(1)'s quest progress using the GetLocalPlayer native? And if not, would an array help?

I was thinking as a fail safe a quest could be disabled for all other players and only enabled for the discovering player. The next player to discover it will have discovered the next array of the quest. GatherQuest[1], as oppused to GatherQuest[0].

As for the hazards of this native, there would't be any for me, if I just display the quest requirement change/ update for one player (that is possible right?)

or is it possible that there would be a few seconds of desync before the player sees the quest update as to whether his metal ore he picked up counts towards the quest?
 
Whoa, that is awesome, thank you for the solution. I read through your tutorial.

I think GetLocalPlayer will be a reasonable solution, I simply want to use it to discover/complete quests as well as locally update quest requirements for each player.

My only question now is: Would I still need quest arrays? Suppose 2 players are working on the same gather type of quest but Player(0) has gathered 6/10 metal ores, and Player(1) has only gathered 2/10 metal ores. My quest system simply displays a quest update and quest requirement change each time a metal ore is acquired. If quests are globally discovered/failed/ect then the quest requirement changes are also global right? Is it possible for Player(0)'s quest requirement to be changed each time he acquire's metal ore without interfering with Player(1)'s quest progress using the GetLocalPlayer native? And if not, would an array help?

I was thinking as a fail safe a quest could be disabled for all other players and only enabled for the discovering player. The next player to discover it will have discovered the next array of the quest. GatherQuest[1], as oppused to GatherQuest[0].

As for the hazards of this native, there would't be any for me, if I just display the quest requirement change/ update for one player (that is possible right?)

or is it possible that there would be a few seconds of desync before the player sees the quest update as to whether his metal ore he picked up counts towards the quest?

You can use either one. A lot of times I resort to the "failsafe" way of having arrays and one per player. For example, if you have a quest array to refer to one quest, you'll have a bunch of indexes (and instead of doing it as "next array of quest", you would just use the player's id):

For each loop_index from 1 to 12, do actions
--- Set Quest[loop_index] = New quest with title... icon...
--- Disable quest
--- Custom script: if GetLocalPlayer() == Player(udg_loop_index - 1) then
--- Enable quest
--- Custom script: endif

That will be the pseudo code. Then when you have a player update the ore count, you would just make a quest update for the Quest[loop_index]. Like so:

Event: Unit gets ore
Quest - Display quest update OreCount / 10 for Quest[Player ID of (Owner of (Triggering unit))]

Something like that. Obviously, that is pseudo code and probably looks nothing like that actual GUI code. I am just forgetful and don't have the editor with me. You may be wondering, don't I need to set it locally? Not really. The beauty of having one separate quest for each player is that you only need to use GetLocalPlayer() for disabling/discovering/completing/enabling, but for updating the quest and all that, you don't really need to do anything. It'll also make it easier to perform checks. It is a bit complicated to explain. I'm sure I can paint a better mental diagram, but I'm kind of sleepy so I'll leave it at this. There are benefits to both methods. If you use only one quest and make the changes locally, then you only need one quest. You will likely need to use GetLocalPlayer() a lot more though.

Hopefully I can come up with a working example on Monday (I hope I don't forget). It might clear some things up. GetLocalPlayer() is a kind of weird topic and is difficult to fully grasp without examples.

----
Visual effects normally don't have desyncs. However, there are always sneaky issues that can trick you. For example, let's say you set a quest as complete locally for a player. Then you check "If quest is complete". It is complete for player 1, but not for player 2. Player 1 will pass the condition, and only player 1 will actually execute the code in the if block. Why? Because for player 2, it sees that the quest is not complete. So if you create a unit within that if-block, the unit will only exist and will only show up for player 1. And, as my tutorial says, that will create a desync.
 
Status
Not open for further replies.
Top