-
Notifications
You must be signed in to change notification settings - Fork 0
/
script.js
351 lines (294 loc) · 13.5 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
"use strict"
const endpoint = "https://api.jsonbin.io/v3/b/";
const urlParams = new URLSearchParams(window.location.search);
const sessionParam = urlParams.get("sessionId");
const apiKey = urlParams.get('apikey');
const isDM = sessionParam == null;
const ATTACK = "attack";
const DEFEND = "defend";
const FEINT = "defend";
const MANEUVER = "maneuver";
const BACK = "back";
const LOCALSTORAGEKEY ="mouseGuardConflict";
const playerColors = [
"a9294f",
"6f9eaf",
"c7753d",
"f6d887"
];
let gameState = {
selectedCard:0,
isSelecting: false,
isDM :isDM,
sessionId: isDM ? null: sessionParam,
conflictCaptain: undefined,
slots : [
{ visible: false, selected : "" },
{ visible: false, selected : "" },
{ visible: false, selected : "" },
{ visible: false, selected : "" },
{ visible: false, selected : "" },
{ visible: false, selected : "" }],
players: [
],
localMouse: undefined
};
setInterval( () => {
if(!gameState.isSelecting && gameState.initialLoadComplete) {
setLoader(true);
getLatest().then(()=> setLoader(false));
}
},9000);
window.onload = () => {
if(sessionParam == null && apiKey == null) {
showModal(`Hi, You'll need an jsonbin.io apikey to use the app as GM. load the site using ${window.location.origin}?apiKey=JSONBINAPIKEY once you have one.`);
return;
}
let storedGame = localStorage.getItem(LOCALSTORAGEKEY,gameState);
if (isDM) {
gmOnLoad(storedGame);
} else if(!isDM) {
playerOnLoad(storedGame)
}
};
function gmOnLoad(storedGame) {
gameState.localMouse ='GM';
if (storedGame == null) {
setLoader(true);
sendData().then( () => {
gameState.initialLoadComplete =true;
setLoader(false);
});
showModal(`welcome, you can select GM team cards (bottom row). In the top left there's a menu that has GM features , the session sharing link or players and clearing ALL cards selected `)
} else {
gameState = JSON.parse(storedGame);
gameState.initialLoadComplete =true;
renderCards();
renderPlayers();
}
}
function playerOnLoad( storedGame) {
document.querySelector(".burgerMenu").style.display='none';
document.querySelector(".revealButtons").style.display='none';
getLatest().then( () => { gameState.initialLoadComplete = true;} );
if(storedGame !== null) {
gameState = JSON.parse(storedGame);
}
if(gameState.localMouse == undefined) {
setCharacterName();
}
}
function setCharacterName( ) {
let captureForm = document.querySelector("#mouseCapture")
captureForm.showModal();
captureForm.addEventListener('close', function onClose() {
gameState.localMouse = captureForm.returnValue;
if ( gameState.players.some( (item) => item == gameState.localMouse)) {
showModal(`Mouse ${gameState.localMouse} already exists`);
captureForm.showModal();
}else {
gameState.players.push(gameState.localMouse);
localStorage.setItem(LOCALSTORAGEKEY,JSON.stringify(gameState));
sendData();
}
});
document.querySelector("#mouseName").addEventListener('change', function onSelect(e) {
confirmBtn.value = e.target.value;
});
}
function showModal(content) {
let modal = document.querySelector("#modalMessage");
let modalContent= document.querySelector(".modalContent");
modalContent.textContent = content;
modal.showModal();
}
function mapStateToJson() {
return {
conflictCaptain: gameState.conflictCaptain,
action: gameState.slots.map( e => {
return {
visible: e.visible,
action: e.selected
};
}),
players: gameState.players
}
}
function setLoader(on) {
if(on) {
document.querySelector(".loader").style.display = "inline-block";
}else {
document.querySelector(".loader").style.display = "none";
}
}
function updateStateFromFetch(data) {
data.record.action.forEach( (item, index) => {
let shouldUpdate = (isDM && index <3) || (!isDM)
if(shouldUpdate){
gameState.slots[index].selected = item.action;
gameState.slots[index].visible = item.visible;
}
});
gameState.conflictCaptain = data.record.conflictCaptain;
gameState.players = data.record.players ?? [];
if(gameState.localMouse && !gameState.players.includes(gameState.localMouse)) {
gameState.players.push(gameState.localMouse);
}
}
function getLatest() {
if( gameState.sessionId) {
return fetch(`${endpoint}${gameState.sessionId}/latest`).then( function(response) {
if(response.status == "200") {
return response.json().then( (data)=> {
updateStateFromFetch(data);
localStorage.setItem(LOCALSTORAGEKEY,JSON.stringify(gameState));
renderCards();
renderPlayers();
});
} else {
console.log(response);
}
}, function(err) { console.log(err);});
}
}
function renderCards() {
gameState.slots.forEach( (item, index) => {
renderCard(item,`#card${index+1}`,index > 2)
});
};
function renderCard(round,card,dmCard){
const action = round.selected;
const cardElement = document.querySelector(card);
cardElement.className ="";
const showHidden = (!isDM && !dmCard) || (isDM && dmCard) ;
if(action == "") {
cardElement.classList.add(`unselectedCard`);
}else if (round.visible == false && showHidden) {
cardElement.classList.add(`${action}Card`);
cardElement.classList.add(`fuzzy`);
}
else if(round.visible == true ) {
cardElement.classList.add(`${action}Card`);
} else {
cardElement.classList.add(`backCard`);
}
}
function toggleSideMenu() {
document.querySelector(".sideMenu").classList.toggle("showNav");
document.querySelector(".burgerMenu").classList.toggle("cancelIcon");
}
function playerClick(playerIndex) {
if(isDM) {
showModal(`${gameState.players[playerIndex]} set as conflict captain `);
gameState.conflictCaptain = gameState.players[playerIndex];
sendData();
}
}
function renderPlayers() {
let players = document.querySelector(".players");
while (players.firstChild) {
players.lastChild.remove()
}
gameState.players.forEach( (e,i) => {
let container = document.createElement("div");
players.appendChild(container);
container.addEventListener('click', function(e) { playerClick(i);},true);
let element = document.createElement("span");
element.setAttribute("style", `background-color : ${playerColors[i]}`);
container.appendChild(element );
let label = document.createElement("label");
label.textContent = `${e} ${e == gameState.conflictCaptain ? '(C)' : ''}`;
label.setAttribute("style", `color : ${playerColors[i]}`);
container.appendChild(label );
});
}
function clearActions() {
gameState.slots.forEach(e => { e.selected =""; e.visible =false;});
sendData();
}
function selectCard(index) {
if( (!isDM && index > 3 ) || isDM && index < 4 || (!isDM && gameState.conflictCaptain != gameState.localMouse) ) {
return;
}
gameState.isSelecting =true;
gameState.selectedCard = index-1;
document.querySelector(".selectionPanel").style.display="inline-block";
}
function cardSelected(action) {
gameState.slots[gameState.selectedCard].selected = action;
document.querySelector(".selectionPanel").style.display="none";
renderCards();
sendData();
gameState.isSelecting = false;
}
function reveal(row) {
gameState.slots[row-1].visible = true;
gameState.slots[row+2].visible = true;
renderCards();
sendData();
}
function resolve(row) {
const playerSlot =gameState.slots[row-1];
const gmSlot = gameState.slots[row+2];
const playerAction = playerSlot.selected
const gmAction = gmSlot.selected;
if(playerAction == "" || gmAction == "" || gmSlot.reveal == false) {
showModal("Action isn't ready to resolve, both parties must select an action to proceed!");
return;
}
const yourAction = isDM ? gmAction : playerAction;
const theirAction = isDM ? playerAction : gmAction;
showModal(resolveActionGrid(yourAction,theirAction))
}
function resolveActionGrid(yourAction, opponentAction) {
const grid = [
{yourAction: "attack", opponentAction: "attack", message: " Roll your 'attack' skill in VS Test. If you roll more successes, opponents disposition reduced by net difference and vice versa"},
{yourAction: "attack", opponentAction: "defend", message: " Roll your 'attack' skill in VS Test. If you roll more successes, opponents disposition reduced by the net difference ,if opponent rolls more they gain disposition equal to the net difference "},
{yourAction: "attack", opponentAction: "feint", message: " Roll your 'attack' skill reduce opponents disposition by successes. Opponent rolls nothing."},
{yourAction: "attack", opponentAction: "maneuver", message: " Roll your 'attack' skill in VS Test. If you roll more successes reduce opponents disposition by net successes. Opponent gains maneuver benefits based on net success"},
{yourAction: "defend", opponentAction: "attack", message: " Roll your 'defend' skill in VS Test. If you roll more successes, increase your disposition by net difference if opponent rolls more you lose disposition equal to net difference. "},
{yourAction: "defend", opponentAction: "defend", message: " Roll your 'defend' skill in Ob(3) test. increase disposition by net successes. Opponent does same"},
{yourAction: "defend", opponentAction: "feint", message: " You roll nothing, opponent rolls to reduce your disposition"},
{yourAction: "defend", opponentAction: "maneuver", message: " Roll your 'defend' skill in VS Test. If you roll more successes,increase your disposition by net successes. Opponent gains maneuver benefits based on net success"},
{yourAction: "feint", opponentAction: "attack", message: " you roll nothing, opponent rolls to reduce your disposition"},
{yourAction: "feint", opponentAction: "defend", message: " roll 'feint' skill vs Ob(0) test, decrese opponent disposition by net success. Opponent does nothing" },
{yourAction: "feint", opponentAction: "feint", message: " Roll you 'feint' skill in a VS test,if you roll more successes opponents disposition decreased by net success and vice versa"},
{yourAction: "feint", opponentAction: "maneuver", message: " roll 'feint' skill vs Ob(0) test, decrese opponent disposition by net success. opponent makes independant maneuver roll"},
{yourAction: "maneuver", opponentAction: "attack", message: " Roll your 'maneuver' skill in VS test. If you roll more succcesses you may gain : 1 Net success : Impede -1D to opponents next roll, 2 net success: Gain Position +2D to your next roll, 3 net success Disarm -remove an opponent's weapon or disable a trait for this combat OR take both Impede and Gain position."},
{yourAction: "maneuver", opponentAction: "defend", message: " Roll your 'maneuver' skill in VS test. If you roll more succcesses you may gain : 1 Net success : Impede -1D to opponents next roll, 2 net success: Gain Position +2D to your next roll, 3 net success Disarm -remove an opponent's weapon or disable a trait for this combat OR take both Impede and Gain position."},
{yourAction: "maneuver", opponentAction: "feint", message: " Roll your 'maneuver' skill in Ob(0) test. your successes can be used as follows: 1 success : Impede -1D to opponents next roll, 2 success: Gain Position +2D to your next roll, 3 success Disarm -remove an opponent's weapon or disable a trait for this combat OR take both Impede and Gain position."},
{yourAction: "maneuver", opponentAction: "maneuver", message: " Roll your 'maneuver' skill in Ob(0) test. your successes can be used as follows: 1 success : Impede -1D to opponents next roll, 2 success: Gain Position +2D to your next roll, 3 success Disarm -remove an opponent's weapon or disable a trait for this combat OR take both Impede and Gain position."},
]
return grid.filter( (e) => e.yourAction == yourAction && e.opponentAction == opponentAction)[0].message;
}
function sendData() {
var headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-Bin-Private': 'false',
'versioning': 'false'
};
if(!gameState.sessionId) {
headers['X-Master-Key']= apiKey;
}
return fetch(`${endpoint}${ gameState.sessionId ?? ""}`,
{
method: gameState.sessionId != null ? 'PUT' : 'POST',
body: JSON.stringify(mapStateToJson()),
headers: headers
}).then( function(response) {
if(response.status == "200") {
return response.json().then( (data)=> {
gameState.sessionId = data.metadata.id ?? data.metadata.parentId;
localStorage.setItem(LOCALSTORAGEKEY,JSON.stringify(gameState));
renderCards(data);
document.querySelector(".loader").style.display = "none";
});
} else {
console.log(response);
}
}, function(err) { console.log(err);});
}
function dismissModal () {
document.querySelector('.Modal').style.display='none';
}