Dice and pickpocketing
Dice
kcds.world.Dice lets people play on the game's dice screen. The server rolls all the dice and checks
each move against the game's rules. Players can use the game's dice kinds and badges.
A match between two players
const { Dice } = kcds.world; const { Events } = kcds.core; const { Player } = kcds.players; Events.on('diceTableUse', (player, table, match) => { if (match !== 0) { return; } const opponent = Player.nearest(player.position, { radius: 4, except: player }); if (opponent) { Dice.start(player.id, opponent.id, { targetScore: 1500 }); } }); Events.on('diceMatchEnd', (match, first, second, winner, reason) => { console.info(`Match ${match} ended: ${reason}`); });
Dice.start(firstId, secondId, options) requires both players to be within 4 m of each other at a
table. Its options are targetScore (default 2000), firstName, secondName, firstDice,
secondDice, firstBadge and secondBadge. Players within 20 m can watch.
A match ends when someone reaches the target score, or with one of these reasons: gaveUp, left,
timedOut (3 minutes without a move), failed, or stopped (from Dice.stop(match)).
To look things up, use Dice.tables(), Dice.kinds(), Dice.badges() and Dice.gameOf(playerId).
A match against an NPC
Dice.startAgainstNpc(player, options) matches a player at a table against an opponent the server
plays. The server makes each throw and turn, and the player's game shows them like another player's.
kcds.world.Dice.startAgainstNpc(player, { difficulty: 'hard', npcName: 'Gambler', targetScore: 1500, });
| Option | Meaning |
|---|---|
difficulty | 'easy', 'normal' (default), 'hard', or a skill from 0 to 100 |
npc | an NPC to use; otherwise the server makes a stand-in |
npcName, playerName | names to show |
targetScore | the score to reach |
playerDice, npcDice | the dice each side uses |
playerBadge, npcBadge | badges; the NPC plays passive ones only |
A skilled opponent keeps its most valuable dice and takes more risks when far behind. An easy one banks early and sometimes keeps fewer dice than it could.
diceMatchEnd fires as usual. The NPC's seat holds null instead of a player, so pay any bet according
to the winning seat. The server's dice resource starts this kind of match with
/dicenpc [easy|normal|hard].
The stand-in sits on the table's free chair with the game's animation. Everyone sees it there, and the player's game runs it until the match ends.
To seat your own NPC smoothly, walk it to where a free chair's sit-down begins before starting the
match. Dice.tables() gives each level table's chairs, as { position, player, sitFrom }, where
player is null for a free chair. Pin the NPC to the player, because only the game running an NPC can
sit it down:
const { Dice } = kcds.world; const { Npc } = kcds.characters; const { Player } = kcds.players; const table = Dice.tables().find((row) => row.chairs.some((chair) => chair.player === null)); if (table) { const chair = table.chairs.find((candidate) => candidate.player === null); const gambler = Npc.create({ position: table.position }); gambler.pin(Player.all()[0]); gambler.moveTo(chair.sitFrom.position, { speed: 'walk' }); // When npcIntentDone fires: call gambler.lookAt(chair.sitFrom.lookAt), then start the match. }
Sitting down first
A player can take one of a table's two chairs and wait. Their game walks them there and plays the sit-down. A match between the two seated players plays from their chairs, and both stay seated after it.
const { Dice } = kcds.world; const { Events, Chat } = kcds.core; const { Player } = kcds.players; Events.on('diceTableUse', (player, table, match) => { if (match === 0 && Dice.sit(player.id) < 0) { Chat.sendToPlayer(player, 'Both chairs are taken.'); } }); setInterval(() => { for (const table of Dice.tables()) { const [first, second] = Dice.sittersAt(table.id).map((id) => { return id === null ? null : Player.getById(id); }); const bothSeated = first?.seated && second?.seated; if (bothSeated && Dice.gameOf(first.id) === 0 && Dice.gameOf(second.id) === 0) { Dice.start(first.id, second.id); } } }, 500);
Dice.sit(playerId)returns the chair, 0 or 1, that the player sits on or already holds. It returns -1 if they are playing, not at a table, or both chairs are taken.Dice.sittersAt(tableId)lists who holds each chair, withnullfor a free one. A player walking to a chair already holds it, andplayer.seatedturns true when they sit.- A chair frees up when its player stands up or leaves. The walk and sit-down can take up to 10 seconds first.
The resources/dice resource that comes with the server works this way. Using a table (E, "Play dice")
sits you down, and the match begins when a second player sits on the other chair.
Reference: Dice.
Pickpocketing
kcds.players.Pickpocketing lets players rob each other using the game's own pickpocketing. The
thief's game runs the minigame, and the server decides the result.
const { Pickpocketing } = kcds.players; Pickpocketing.setEnabled(true); Pickpocketing.setVictimNotice(true, '{thief} had a hand in your pocket!'); kcds.core.Events.on('playerPickpocketStart', (thief, victim) => { return thief.dimension === victim.dimension; });
Returning false from playerPickpocketStart refuses the attempt. The other events are
playerPickpocketCaught and playerPickpocketed. kcds.players.Inventory.setStolenMarks(enabled)
turns the game's stolen marks on or off.
Reference: Pickpocketing.