Skip to content

Commit f088aaf

Browse files
committed
Adding in the missing Dealer 2.0 script.
1 parent 9c5f35f commit f088aaf

File tree

2 files changed

+424
-14
lines changed

2 files changed

+424
-14
lines changed

Dealer/2.0/Dealer.js

+287
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
// Dealer
2+
// Last Updated: 2019-09-03
3+
// A script to deal and take cards to selected users from specified decks.
4+
// Syntax is !deal --[give,take] [number of cards as integer] --[deck name]|[card name]
5+
on('ready', () => {
6+
const version = '2.0';
7+
8+
const processInlinerolls = (msg) => {
9+
if(_.has(msg,'inlinerolls')){
10+
return _.chain(msg.inlinerolls)
11+
.reduce(function(m,v,k){
12+
let ti=_.reduce(v.results.rolls,function(m2,v2){
13+
if(_.has(v2,'table')){
14+
m2.push(_.reduce(v2.results,function(m3,v3){
15+
m3.push(v3.tableItem.name);
16+
return m3;
17+
},[]).join(', '));
18+
}
19+
return m2;
20+
},[]).join(', ');
21+
m['$[['+k+']]']= (ti.length && ti) || v.results.total || 0;
22+
return m;
23+
},{})
24+
.reduce(function(m,v,k){
25+
return m.replace(k,v);
26+
},msg.content)
27+
.value();
28+
} else {
29+
return msg.content;
30+
}
31+
};
32+
33+
34+
log('-=> Dealer v' + version + ' <=-');
35+
36+
//Interface elements
37+
38+
const openReport = `<div style = 'display: block; position:relative;left: -5px; background-color:#888; border-radius:18px; text-decoration:none;color:#000; font-family:Arial; font-size:13px; padding: 8px;'>`;
39+
const openSection = `<div style = 'background-color:#ccc; color:#111; border: 1px solid black; padding:3px; border-radius:15px;margin-top:10px;'>`
40+
const openHeader = `<div style = 'display: block; background-color:#333; color: #3b0; font-weight: bold; padding:2px; border-radius:20px; text-align:center;'>`;
41+
const openSubhead = `<div style = 'background-color:#333; color: #ccc; font-weight: bold; padding:2px; border-radius:20px; text-align:center;'>`;
42+
const openSubheadMargin = `<div style = 'background-color:#333; color: #ccc; font-weight: bold; padding:2px; border-radius:20px; text-align:center; margin-bottom:5px;'>`;
43+
const openPageHead = `<div style = 'background-color:#aaa; color: #111; font-weight: bold; padding:2px; margin-bottom:6px; border-radius:20px; text-align:center;'>`;
44+
const closeReport = `</div>`;
45+
const dealerHelp = openReport + openHeader +"Dealer v."+ version + "</div>" +
46+
"Dealer deals and takes cards from players sepcified by deck or deck & card. It works on selected tokens or by specifying a player_id.<BR>" +
47+
openSection +openSubhead + "Syntax</div><BR>" +
48+
"<code>!deal --[give,take] [#] --[deck name]|[Card Name] --[ids|Player_id]</code><BR>" +
49+
"If give/take is not specified, it gives a card to the player controlling the selected token If deck name is not specified, it defaults to 'Playing Cards'. If a card name is not specified, it defaults to a random card from the specified deck.<BR>" +
50+
"You can specify a number of cards to give or take. After the action word, type an integer, after a space:<BR>" +
51+
"<code>!deal --give 5 --Playing Cards</code><BR>" +
52+
"You can specify a card to deal by name. If no card exists by that name in that deck, the script will inform the user by chat message. Note that it is possible to give multiple copies of the same card even from a finite deck:<BR>" +
53+
"<code>!deal --give --Playing Cards|Six of Hearts</code><BR>" +
54+
"The script will deal cards to the player from the specified deck so long as there are enough available. If the deck has cycled through all cards, it will automatically shuffle.<BR>" +
55+
"If a token has more than one controller or is controlled by All and one or more players, it will select the first single player in the controlled by list.<BR>" +
56+
"Script will try to let you know if you have not prepared a command or deck properly.<BR>" +
57+
"If deck does not deal a card, you may need to manually shuffle (Roll20 bug). If the deck is shuffled, it may not recognize all cards in hand.<BR>" +
58+
"If you do not wish to select a token, you may specify the plyer by using their player id. Use the optional <BR><code> --ids|[player_id]</code> at the end of a command. You can get a list of player ids in the campaign by using the command <BR><code>!deal --players</code></div>" +
59+
openSection +openSubhead +"Uses:</div><BR>" +
60+
"Games which deal or take playing cards at random from a standard deck<BR>" +
61+
"Awarding inspiration--or Bardic Inspiration from a separate deck.<BR>" +
62+
"Awarding a random potion/scroll/treasure/piece of equipment from a properly prepared deck.</div>" +
63+
openSection +openSubhead +"Examples</div><BR>" +
64+
"<code>!deal --give --Inspiration</code><BR>" +
65+
"This will deal a card from a deck called 'Inspiration' to the player whose token is selected. This would be ideal as a token ability or macro bar macro to allow GMs to award Inspiration to the player of a selected token.<BR>" +
66+
"<BR>" +
67+
"<code>!deal --take --Inspiration</code><BR>" +
68+
"This will take a card from a deck called 'Inspiration' from the hand player whose token is selected. This would be ideal as a token ability to allow players to spend Inspiration<BR>" +
69+
"<BR>" +
70+
"<code>!deal --give</code> or <BR><code>!deal --give --Playing Cards</code><BR>" +
71+
"This will deal a card from the Playing Cards deck to the player whose token is selected.<BR>" +
72+
"<code>!deal --take</code><BR>" +
73+
"This will take a card from the Playing Cards deck from the hand player whose token is selected.</div></div>";
74+
75+
76+
const sendMessage = function(title,theMessage) {
77+
sendChat ('Dealer','/w gm ' +openSection+openHeader+title+'</div>'+theMessage+closeReport);
78+
return;
79+
}
80+
81+
on('chat:message', (msg) => {
82+
if ('api' === msg.type && /!deal(\b\s|$)/i.test(msg.content)) {
83+
let playerList = '';
84+
let IDs = '';
85+
const players=findObjs({_type:'player'});
86+
_.each(players,function (obj){
87+
playerList = playerList + ('<b>'+obj.get('displayname')+':</b> '+obj.get('id'))+'<BR>';
88+
});
89+
90+
if (msg.content === '!deal --players'){
91+
//For when I add multiple players
92+
//let howToUse = '<BR> To specify a player to send a card to, copy one or more player IDs above. Use them at the end of a command using the format:<BR><code>--ids|ID1,ID2...</code><BR>Be sure to include the dash at the beginning of an id, and to use no spaces in the string.'
93+
let howToUse = '<BR> To specify a player to send a card to, copy one of the player IDs above. Use it at the end of a command using the format:<BR><code>--ids|ID1</code><BR>Be sure to include the dash at the beginning of the id, and to use no spaces in the string. Currently, Dealer only supports one token or player ID per command.'
94+
95+
//playerList = openSection+openHeader+'Player ID list</div>'+playerList+howToUse+closeReport;
96+
sendMessage("Player List",playerList+howToUse);
97+
return;
98+
};
99+
100+
if (msg.content === '!deal --help'){
101+
//playerList = openSection+openHeader+'Player ID list</div>'+playerList+howToUse+closeReport;
102+
sendChat("Dealer",dealerHelp);
103+
return;
104+
};
105+
106+
if (msg.content.includes(' --ids|')){
107+
IDs = msg.content.split(' --ids|')[1].split(',');
108+
//For now, we only want the first. We will add the ability to do multiples later.
109+
IDs = IDs[0];
110+
msg.content = msg.content.split(' --ids|')[0];}
111+
112+
else{
113+
if(!msg.selected){
114+
sendMessage ("No Player Identified", "You must select a token controlled by a player, or use the --ids command to specify a player ID. Player Id's can be found with the command <code>!deal --players</code>.");
115+
return;
116+
}
117+
118+
119+
}
120+
121+
122+
//get parameter and use default of 'give' if parameter is missing or malformed
123+
const args = processInlinerolls(msg).split(/\s+--/);
124+
125+
if (args.length < 2) {
126+
if (args[0] !== '!deal') {
127+
sendMessage('Malformed Command', 'Please use !deal --[give/take] --[Deckname] --ids|player_ids.');
128+
return;
129+
} else {
130+
args[1] = 'give';
131+
}
132+
}
133+
let action = args[1].split(/\s+/)[0];
134+
135+
136+
let numCards = args[1].split(/\s+/)[1];
137+
numCards = Number((Number.isInteger(Number(numCards))) ? numCards : 1);
138+
139+
const actions = ['give', 'take'];
140+
let cardAction = 'give';
141+
if (action && actions.includes(action)) {
142+
cardAction = action;
143+
}
144+
let choices = args[2] || 'Playing Cards';
145+
146+
147+
let deckChoice = choices.split(/\|/)[0] || 'Playing Cards';
148+
let cardChoice = choices.split(/\|/)[1] || '';
149+
150+
151+
152+
//getid of deck
153+
let theDeck = findObjs({
154+
_type: "deck",
155+
name: deckChoice
156+
})[0];
157+
158+
//test if deck exists
159+
if (!theDeck) {
160+
sendMessage('No Such Deck', 'Create a deck named ' + deckChoice + '. If the intent is an Inspiration deck, it must be an infinite deck of one card only.');
161+
return;
162+
}
163+
164+
165+
let deckID = theDeck.id;
166+
let deckCards = theDeck.get('_currentDeck');
167+
168+
169+
170+
if (msg.selected){
171+
172+
if (msg.selected.length > 1) {
173+
sendMessage('Multiple Tokens', 'Please select only one token. It must be controlled by a specific player, or represent a player-controlled character.');
174+
return;
175+
}
176+
}
177+
178+
if (msg.selected){
179+
let token = getObj(msg.selected[0]._type, msg.selected[0]._id);
180+
181+
//assign associated character to a variable
182+
if (!token.get('represents')) {
183+
sendMessage('No Player Specified', 'This token does not represent a player character. Only players get cards.');
184+
return;
185+
}
186+
let character = getObj("character", token.get('represents'));
187+
188+
//Get owner IDs of each -- Not needed at this point
189+
// If the token represents a character, get the character's controller, otherwise the token's
190+
let ownerids = (token.get('controlledby').split(','));
191+
192+
193+
if (character) {
194+
ownerids = (character.get('controlledby').split(','));
195+
}
196+
//reduces to one ownerid that is not ['all']
197+
ownerid = ownerids.filter(s => s !== 'all')[0];
198+
}
199+
200+
if (IDs !==''){
201+
ownerid = IDs;
202+
}
203+
if (undefined===ownerid || ownerid===''){
204+
sendMessage ('No Player ID specified', 'Dealer does not know whom to send this card to.');
205+
return;
206+
}
207+
208+
// give card to player
209+
// If the ownerid is undefined (no valid controller) explain and exit
210+
if (!ownerid) {
211+
sendMessage('Needs a Player Controller', 'If a token represents a character controlled by \'All Players\', an individual player must be also be specified. If there are multiple controllers, only the first will get inspiration.');
212+
return;
213+
}
214+
215+
//If a card is specified by name
216+
if (cardChoice !== '') {
217+
let theCard = findObjs({
218+
_type: 'card',
219+
name: cardChoice,
220+
_deckid: deckID
221+
})[0];
222+
if (theCard !== undefined) {
223+
do {
224+
let specificCardID = theCard.id;
225+
if (cardAction == 'give') {
226+
giveCardToPlayer(specificCardID, ownerid);
227+
numCards--;
228+
} else {
229+
takeCardFromPlayer(ownerid, {cardid: specificCardID})
230+
numCards--;
231+
}
232+
}
233+
while (numCards > 0);
234+
return;
235+
} else {
236+
sendMessage('No Such Card', 'There does not seem to be a card named ' + cardChoice + ' in the deck ' + deckChoice);
237+
return;
238+
}
239+
}
240+
241+
242+
//If this is a random card
243+
do {
244+
245+
//get id of card
246+
let cardid = drawCard(deckID);
247+
248+
if (!cardid) {
249+
shuffleDeck(deckID);
250+
cardid = drawCard(deckID);
251+
}
252+
// get playerId of Token controller
253+
//assign selected token to a variable
254+
255+
switch (cardAction) {
256+
case 'take':
257+
258+
let hand = findObjs({
259+
type: 'hand',
260+
parentid: ownerid
261+
})[0];
262+
let theHand = hand.get('currentHand');
263+
264+
cardid = (theHand.split(',').filter(x => deckCards.split(',').includes(x)))[0];
265+
266+
if (theHand.length !== 0 && cardid !== undefined) {
267+
268+
takeCardFromPlayer(ownerid, {
269+
cardid: cardid
270+
});
271+
} else {
272+
let deckName = theDeck.get('name');
273+
sendMessage('Deck Empty', token.get('name') + ' has no cards left to take from the ' + deckName + ' deck.');
274+
}
275+
276+
break;
277+
default:
278+
giveCardToPlayer(cardid, ownerid);
279+
break;
280+
}
281+
282+
numCards--;
283+
}
284+
while (numCards > 0);
285+
}
286+
});
287+
});

0 commit comments

Comments
 (0)