Newer
Older
for (let i=1;i<5;i++) {
if (players[i]) {
usage_tracking_report.table[i] = players[i].id;
$.ajax({
url: USAGE_TRACKING_ENDPOINT,
method: 'POST',
data: JSON.stringify(usage_tracking_report),
contentType: 'application/json',
error: function (jqXHR, status, err) {
console.error("Could not send usage tracking report - error "+status+": "+err);
},
});
}
players.forEach(function(player) {
player.preloadStageImages(0);
});
advanceToNextScreen($selectScreen);
}
/************************************************************
* The player clicked on the back button on the main select
* screen.
************************************************************/
function backSelectScreen () {
screenTransition($selectScreen, $titleScreen);
}
/* The player selected an alternate costume for an opponent.
* `slot` is the 1-based opponent slot affected.
* `inGroup` is true if the affected opponent is on the group selection screen.
*/
function altCostumeSelected(slot, inGroup) {
var costumeSelector = (inGroup ? $groupCostumeSelectors[slot-1] : $individualCostumeSelectors[slot-1]);
var selectImage = (inGroup ? $groupImages[slot-1] : $individualImages[slot-1]);
var opponent = (inGroup ? selectableGroups[groupSelectScreen][groupPage[groupSelectScreen]].opponents[slot-1] : shownIndividuals[slot-1]);
var selectedCostume = costumeSelector.val();
var costumeDesc = undefined;
if (selectedCostume.length > 0) {
for (let i=0;i<opponent.alternate_costumes.length;i++) {

FarawayVision
committed
if (opponent.alternate_costumes[i].folder === selectedCostume) {
costumeDesc = opponent.alternate_costumes[i];
break;
}
}
}
if (costumeDesc) {
opponent.selectAlternateCostume(selectedCostume);

FarawayVision
committed
selectImage.attr('src', selectedCostume+costumeDesc.image);
} else {
opponent.selectAlternateCostume(null);
selectImage.attr('src', opponent.folder + opponent.image);
}
}
/**********************************************************************
***** Display Functions *****
**********************************************************************/
/************************************************************
* Displays all of the current players on the main select
* screen.
************************************************************/
function updateSelectionVisuals () {
/* update all opponents */
for (var i = 1; i < players.length; i++) {

ReformCopyright
committed
$selectDialogues[i-1].html(fixupDialogue(players[i].chosenState.dialogue));
if (players[i].folder + players[i].chosenState.image

ReformCopyright
committed
!= $selectImages[i-1].attr('src')) {
var slot = i;
$selectImages[i-1].attr('src', players[i].folder + players[i].chosenState.image);

ReformCopyright
committed
$selectImages[i-1].one('load', function() {

ReformCopyright
committed
$selectBubbles[slot-1].show();

ReformCopyright
committed
$selectImages[slot-1].css('height', players[slot].scale + '%');

ReformCopyright
committed
$selectImages[slot-1].show();
});
} else {

ReformCopyright
committed
$selectBubbles[i-1].show();
$selectBubbles[i-1].children('.dialogue-bubble').attr('class', 'dialogue-bubble arrow-'+(players[i].chosenState.direction));
bubbleArrowOffsetRules[i-1][0].style.left = players[i].chosenState.location;
bubbleArrowOffsetRules[i-1][1].style.top = players[i].chosenState.location;

ReformCopyright
committed
$selectImages[i-1].show();
}
ReformCopyright
committed
$selectLabels[i-1].html(players[i].label.initCap());
/* change the button */
$selectButtons[i-1].html("Remove Opponent");
$selectButtons[i-1].removeClass("smooth-button-green");
$selectButtons[i-1].addClass("smooth-button-red");
} else {
/* clear the view */
$selectDialogues[i-1].html("");
$selectAdvanceButtons[i-1].css({opacity : 0});
$selectBubbles[i-1].hide();

ReformCopyright
committed
$selectImages[i-1].hide();
$selectLabels[i-1].html("Opponent "+i);
/* change the button */
$selectButtons[i-1].html("Select Opponent");
$selectButtons[i-1].removeClass("smooth-button-red");
$selectButtons[i-1].addClass("smooth-button-green");
}
}

ReformCopyright
committed
/* Check to see if all opponents are loaded. */

ReformCopyright
committed
var filled = 0, loaded = 0;
players.forEach(function(p, idx) {
if (idx > 0) {
filled++;

ReformCopyright
committed
if (!p.isLoaded()) {
$selectButtons[idx-1].html('Loading...');
} else {
loaded++;
}

ReformCopyright
committed
$selectButtons[idx-1].attr('disabled', !p.isLoaded());

ReformCopyright
committed
});

ReformCopyright
committed
/* if enough opponents are selected, and all those are loaded, then enable progression */
$selectMainButton.attr('disabled', filled < 2 || loaded < filled);

ReformCopyright
committed
/* if all slots are taken, disable fill buttons */
$selectRandomButtons.attr('disabled', filled >= 4);

ReformCopyright
committed
$selectRemoveAllButton.attr('disabled', filled <= 0 || loaded < filled);
/* Disable buttons while loading is going on */
$selectRandomTableButton.attr('disabled', loaded < filled);
$groupButton.attr('disabled', loaded < filled);
/* Update suggestions images. */
var current_player_count = countLoadedOpponents();
if (current_player_count >= 3) {

FarawayVision
committed
var suggested_opponents = loadedOpponents.filter(function(opp) {
/* hide selected opponents */
if (players.some(function(p) { return p && p.id == opp.id; })) {
return false;
}

FarawayVision
committed
return true;
});

FarawayVision
committed
/* sort opponents */
suggested_opponents.sort(sortOpponentsByMostTargeted());
var suggestion_idx = 0;
for (var i=1;i<players.length;i++) {

FarawayVision
committed
if (players[i] === undefined) {
updateSuggestions(i-1, suggested_opponents, suggestion_idx);
$selectSuggestions[i-1].show();
suggestion_idx += 4;
} else {
$selectSuggestions[i-1].hide();
}
}
} else {
for (var i=0;i<4;i++) {
$selectSuggestions[i].hide();
}
}
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
/************************************************************
* This is the callback for the group clicked rows, it
* updates information on the group screen.
************************************************************/
function updateGroupScreen (playerObject) {
/* find a spot to store this player */
for (var i = 0; i < storedGroup.length; i++) {
if (!storedGroup[i]) {
storedGroup[i] = playerObject;
$groupLabels[i+1].html(playerObject.label);
break;
}
}
/* enable the button */
$groupButton.attr('disabled', false);
}
/************************************************************
* Hides the table on the single selection screen.
************************************************************/
function hideSelectionTable() {
mainSelectHidden = !mainSelectHidden;
if (mainSelectHidden) {
$selectTable.hide();
}
else {
$selectTable.show();
}
}
/************************************************************
* Hides the table on the single selection screen.
************************************************************/
function hideSingleSelectionTable() {
singleSelectHidden = !singleSelectHidden;
if (singleSelectHidden) {
$individualSelectTable.hide();
}
else {
$individualSelectTable.show();
}
}
/************************************************************
* Hides the table on the single group screen.
************************************************************/
function hideGroupSelectionTable() {
groupSelectHidden = !groupSelectHidden;
if (groupSelectHidden) {
$groupSelectTable.hide();
}
else {
$groupSelectTable.show();
}
}
function openSearchModal() {
/* build the list of tags for the filter (once) */
if (!$tagList.children('option').length) {
tagList.forEach(function(tag) {
$tagList.append('<option value="' + tag + '"/>');
});
}
$searchModal.modal('show');
}
function closeSearchModal() {
Chase Southwood
committed
// perform the search and sort logic
updateSelectableOpponents();
// update
updateIndividualSelectScreen();
updateIndividualCountStats();
function clearSearch() {
$searchName.val(null);
$searchTag.val(null);
$searchSource.val(null);
closeSearchModal();
}
function changeSearchGender(gender) {
chosenGender = gender;
setActiveOption($searchGenderOptions, gender);
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
function openGroupSearchModal() {
$groupSearchModal.modal('show');
}
function closeGroupSearchModal() {
// perform the search and sort logic
updateSelectableGroups(groupSelectScreen);
// update
updateGroupSelectScreen();
updateGroupCountStats();
}
function clearGroupSearch() {
$groupSearchName.val(null);
$groupSearchGroupName.val(null);
$groupSearchTag.val(null);
$groupSearchSource.val(null);
closeGroupSearchModal();
}
function changeGroupSearchGender(gender) {
chosenGroupGender = gender;
setActiveOption($groupSearchGenderOptions, gender);
}
/************************************************************
* Sorting Functions
************************************************************/
* Callback for Arrays.sort to sort an array of objects by the given field.
* Prefixing "-" to a field will cause the sort to be done in reverse.
* Examples:
* // sorts myArr by each element's first name (A-Z)
* myArr.sort(sortOpponentsByField("first"));
* // sorts myArr by each element's last name (Z-A)
* myArr.sort(sortOpponentsByField("-last"));
*/
function sortOpponentsByField(field) {
// check for prefix
var order = 1; // 1 = forward, -1 = reversed
order = -1;
field = field.substr(1);
}
return function(opp1, opp2) {
var compare = 0;
if (opp1[field] < opp2[field]) {
compare = -1;
}
else if (opp1[field] > opp2[field]) {
compare = 1;
}
return order * compare;
}
}
/**
* Callback for Arrays.sort to sort an array of objects over multiple given fields.
* Prefixing "-" to a field will cause the sort to be done in reverse.
* This should allow more flexibility in the sorting order.
* Example:
* // sorts myArr by each element's number of layers (low to high),
* // and for elements whose layers are equivalent, sort them by first name (Z-A)
* myArr.sort(sortOpponentsByMultipleFields("layers", "-first"));
*/
function sortOpponentsByMultipleFields() {
var fields = arguments; // retrieve the args passed in
return function(opp1, opp2) {
var i = 0;
var compare = 0;
// if both elements have the same field, check the next ones
while (compare === 0 && i < fields.length) {
compare = sortOpponentsByField(fields[i])(opp1, opp2);
i++;
}
return compare;
}
}
ReformCopyright
committed
/**
* Special Callback for Arrays.sort to sort an array of opponents on
* the total number of lines targeting them the currently selected
* opponents have.
*/
function sortOpponentsByMostTargeted() {
return function(opp1, opp2) {
counts = [opp1, opp2].map(function(opp) {
return players.reduce(function(sum, p) {
if (p && p.targetedLines && opp.id in p.targetedLines) {
ReformCopyright
committed
sum += p.targetedLines[opp.id].count;
}
return sum;
}, 0);
});
if (counts[0] > counts[1]) return -1;
if (counts[0] < counts[1]) return 1;
return 0;
}
}
function setSortingMode(mode) {
sortingMode = mode;
$("#sort-dropdown-selection").html(sortingMode); // change the dropdown text to the selected option
individualPage = 0; // reset the page number
}
/** Event handler for the sort dropdown options. Fires when user clicks on a dropdown item. */
$sortingOptionsItems.on("click", function(e) {
setSortingMode($(this).find('a').html());
/************************************************************
* Word wrapping Functions
************************************************************/
/**
* Inserts a fixed-size HTML element with the specified text to allow the content
* to be either word-wrapped (if the text is long and spaces are present)
* or word-broken (if text is long and no spaces are present).
*/
function wordWrapHtml(text) {
return "<table class=\"wrap-text\"><tr><td>" + text + "</td></tr></table>";
/************************************************************
* Dynamic dialogue and image counting functions
************************************************************/
/** Event handler for the individual selection screen credits button. */
$individualCreditsButton.on('click', function(e) {
updateIndividualCountStats()
/** Event handler for the group selection screen credits button. */
$groupCreditsButton.on('click', function(e) {
updateGroupCountStats();
* Loads and displays the number of unique dialogue lines and the number of pose images
* into the character's player object for those currently on the selection screen.
* Only loads if the unique line count or image count is not known.
*/
function updateOpponentCountStats(opponentArr, uiElements) {
opponentArr.forEach(function(opp, idx) {
// load behaviour file if line/image count is not known
if (opp && (opp.uniqueLineCount === undefined || opp.posesImageCount === undefined)) {
uiElements.countBoxes[idx].css("visibility", "visible");
// retrieve line and image counts
if (DEBUG) {
console.log("[LineImageCount] Fetching counts for " + opp.label + " in slot " + idx);
var countsPromise = new Promise(function (resolve, reject) {
fetchCompressedURL(
opp.folder + 'behaviour.xml',
resolve, reject
);
});
countsPromise.then(countLinesImages).then(function(response) {
opp.uniqueLineCount = response.numUniqueLines;
opp.posesImageCount = response.numPoses;
// show line and image counts
if (DEBUG) {
console.log("[LineImageCount] Loaded " + opp.label + " from behaviour: " +
opp.uniqueLineCount + " lines, " + opp.posesImageCount + " images");
uiElements.lineLabels[idx].html(opp.uniqueLineCount);
uiElements.poseLabels[idx].html(opp.posesImageCount);
// this character's counts were previously loaded
if (DEBUG) {
console.log("[LineImageCount] Loaded previous count for " + opp.label + ": " +
opp.uniqueLineCount + " lines, " + opp.posesImageCount + " images)");
uiElements.countBoxes[idx].css("visibility", "visible");
uiElements.lineLabels[idx].html(opp.uniqueLineCount);
uiElements.poseLabels[idx].html(opp.posesImageCount);
// there is no character in the slot
uiElements.countBoxes[idx].css("visibility", "hidden");
uiElements.lineLabels[idx].html("");
uiElements.poseLabels[idx].html("");
/** Dialogue/image count update function for the individual selection screen. */
function updateIndividualCountStats() {
if (individualCreditsShown) {
var individualUIElements = {
countBoxes : $individualCountBoxes,
lineLabels : $individualLineCountLabels,
poseLabels : $individualPoseCountLabels
};
updateOpponentCountStats(shownIndividuals, individualUIElements);
}
}
/** Dialogue/image count update function for the group selection screen. */
function updateGroupCountStats() {
if (groupCreditsShown) {
var groupUIElements = {
countBoxes : $groupCountBoxes,
lineLabels : $groupLineCountLabels,
poseLabels : $groupPoseCountLabels
};
updateOpponentCountStats(shownGroup, groupUIElements);
/**
* Callback to parse the number of lines of dialogue and number of images
* given a character's behaviour XML. Returns the counts as an object with
* properties numTotalLines, numUniqueLines, and numPoses.
*/
function countLinesImages(xml) {
// parse all lines of dialogue and all images

ReformCopyright
committed
var numTotalLines = 0;
var numUniqueDialogueLines = 0;
var numUniqueUsedPoses = 0;
var lines = {};
var poses = {};
$(xml).find('state').each(function(idx, data) {

ReformCopyright
committed
numTotalLines++;
// count only unique lines of dialogue
if (lines[data.textContent.trim()] === undefined) numUniqueDialogueLines++;
lines[data.textContent.trim()] = 1;
// count unique number of poses used in dialogue
// note that this number may differ from actual image count if some images
// are never used, or if images that don't exist are used in the dialogue
if (poses[data.getAttribute("img")] === undefined) numUniqueUsedPoses++;
poses[data.getAttribute("img")] = 1;

ReformCopyright
committed
numTotalLines : numTotalLines,
numUniqueLines : numUniqueDialogueLines,
numPoses : numUniqueUsedPoses