Description
A mini-library for synchronizing navi scripts so that your characters both hunt and refill together.
API
- barrier(string id)
When you call barrier(id) your character will stop walking. When all players in the current navi room has called barrier with the same id the function will return and your character will start walking again.- voteOr(string id, boolean myVote)
When you call voteOr(id, myVote) your character will stop walking. When all players in the current navi room has called voteOr with the same id the function will return and your character will start walking again. The function returns true if any player --that is connected to the current navi room when the vote ends-- voted true, otherwise it returns false.- voteAnd(string id, boolean myVote)
When you call voteAnd(id, myVote) your character will stop walking. When all players in the current navi room has called voteAnd with the same id the function will return and your character will start walking again. The function returns true if all players --that are connected to the current navi room when the vote ends-- voted true, otherwise it returns false.Examples
- Barriers are used to ensure that all characters are in the same stage of the script. For example, they can be used to ensure that a mage does not proceed before the Knight has picked up the loot, or to stop the Knight of proceeding before the Mage has finished picking up the supplies that they just traded, or to ensure that the Knight has gotten half-way to the next killing spot before the Mage leaves the previous one, or to make sure that no character leaves to town before all have finished refilling:
barrier("Leaving Town")- If you want to check whether the party needs to refill you can use voteOr:
if voteOr("Leave Check", needresupply()) then
gotolabel("LeaveSpawn")
end- If you want to check whether to proceed into an optional area you can use voteAnd:
if not voteAnd("Check Hardcore", getuseroption("hardcore")) then
gotolabel("SkipHardcore")
endInstructions
All players should join the navigation room before any of them start the cavebot. If a player joins the room after some other player has already reached a barrier or a vote, then he or she will not receive their vote and will thus get stuck at that vote or barrier, which will cause a deadlock when the other players reach the next vote or label. If you fuck up and deadlock yourself you can unstuck yourself by pausing the cavebot and rejoining the navigation server. If a player disconnects from the navigation server they should not reconnect again. However, reconnecting to the game after a disconnect is fine as long as they never disconnected from the navigation server.
The ids given as a first argument to all barriers and votes should be unique within the current waypoint set. This is mostly to safe-guard against the walker doing wonky stuff as I do not fully trust it to execute waypoints in order. In practice you should be fine as long as you don't re-use ids within short time periods. Also, it's good practice to use an id that describes what you're currently voting about, or waiting for. Also, note that ids may not contain the comma character.
Finally, if you die and remain inside the navigation room you will probably cause the other players to get stuck (assuming your votes and barriers are located in waypoint actions). Therefore it's good practice to disconnect from the navigation server if you die.
Code
init start
local function votingString(topic, thisVote)
return string.format("__VOTE__%s,,%s", tostring(topic), tostring(thisVote))
end
local function parseVote(msg)
return msg:match("__VOTE__(.-),,(.+)")
end
local currentVotes = {}
local function vote(topic, myvote, reducer)
currentVotes[topic] = currentVotes[topic] or {}
navsay(votingString(topic, myvote))
while true do
pausewalking(10000)
local allHasVoted = true
foreach navchar p do
allHasVoted = currentVotes[topic][p.name] and allHasVoted
end
if allHasVoted or not $navigation then
break
else
waitping()
end
end
pausewalking(0)
local allVotes = {}
foreach navchar p do
table.insert(allVotes, currentVotes[topic][p.name])
end
local res = reducer(allVotes)
currentVotes[topic] = {}
return res
end
function voteOr(topic, myvote)
return vote(topic, myvote, function(allVotes)
for _, vote in ipairs(allVotes) do
if vote == "true" then
return true
end
end
return false
end)
end
function voteAnd(topic, myvote)
return vote(topic, myvote, function(allVotes)
for _, vote in ipairs(allVotes) do
if vote == "false" then
return false
end
end
return true
end)
end
function barrier(topic)
voteOr(topic, false)
end
function navmessages(data)
local sender = data.name
local topic, vote = parseVote(data.message)
if topic and vote then
currentVotes[topic] = currentVotes[topic] or {}
currentVotes[topic][sender] = vote
end
end
init end