From 60b3b0c035ab21cae808475d7df5a015200876ed Mon Sep 17 00:00:00 2001
From: FarawayVision <stmobo@gmail.com>
Date: Wed, 1 May 2019 18:12:13 -0400
Subject: [PATCH] Properly integrate Collectibles into the selection screen

Collectibles now have their own special subview within the selection screen,
much like Epilogues.
---
 css/spni.css      |  21 ++++++---
 js/spniDisplay.js | 111 ++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 111 insertions(+), 21 deletions(-)

diff --git a/css/spni.css b/css/spni.css
index f21df8d09d9..96606f3bce5 100644
--- a/css/spni.css
+++ b/css/spni.css
@@ -2034,6 +2034,8 @@ body.modal-open {
     /*height: 35%;*/
     height: auto;
     min-height: 15%;
+    max-height: 82%;
+    overflow-y: auto;
     
     background-color: #555555;
     padding: 1.5%;
@@ -2186,10 +2188,10 @@ body.modal-open {
 }
 
 /************************************************************
- * Classes for the opponent Epilogues view.
+ * Classes for the opponent Epilogues and Collectibles views.
  ************************************************************/
 
-.opponent-epilogue-card {
+.opponent-subview-card {
     padding: 1% 2%;
     margin: 2% 5%;
     background: #FFFFFF;
@@ -2198,14 +2200,14 @@ body.modal-open {
     flex-direction: column;
 }
 
-.opponent-epilogue-title {
+.opponent-subview-title {
     flex: 2;
     
     text-align: left;
     font-size: 2.5vmin;
 }
 
-.opponent-epilogue-row {
+.opponent-subview-row {
     margin: 1% 0;
     display: flex;
     
@@ -2215,7 +2217,7 @@ body.modal-open {
     word-wrap: break-word;
 }
 
-.opponent-epilogue-row > * {
+.opponent-subview-row > * {
     display: flex;
     align-items: center;
     
@@ -2225,7 +2227,7 @@ body.modal-open {
     word-wrap: break-word;
 }
 
-.opponent-epilogue-row > .opponent-epilogue-label {
+.opponent-subview-row > .opponent-subview-label{
     background: linear-gradient(rgb(204, 204, 204), rgb(170, 170, 170)) rgb(204, 204, 204);
     border-right: 2px solid #111111;
     height: auto;
@@ -2233,10 +2235,15 @@ body.modal-open {
     flex: 1;
 }
 
-.opponent-epilogue-row > .opponent-epilogue-value {
+.opponent-subview-row > .opponent-subview-value {
     flex: 3;
 }
 
+.opponent-subview-subtitle {
+    font-size: 1.5vmin;
+}
+
+
 /************************************************************
  * Classes for constrained screen widths.
  * In particular, detect devices with an aspect ratio of
diff --git a/js/spniDisplay.js b/js/spniDisplay.js
index b9ca53426c2..4af16ff3768 100644
--- a/js/spniDisplay.js
+++ b/js/spniDisplay.js
@@ -920,6 +920,7 @@ OpponentDetailsDisplay.prototype.handlePanelNavigation = function (ev) {
         this.updateEpiloguesView();
         this.epiloguesView.show();
     } else if (targetPanel === 'collectibles') {
+        this.updateCollectiblesView();
         this.collectiblesView.show();
     } else {
         this.mainView.show();
@@ -963,22 +964,24 @@ OpponentDetailsDisplay.prototype.clear = function () {
 }
 
 OpponentDetailsDisplay.prototype.createEpilogueCard = function (title, gender, unlockHint) {
-    var container = createElementWithClass('div', 'bordered opponent-epilogue-card');
+    // Add the opponent-epilogue-* classes for future extensibility and also
+    // to minimize disruptions with caching
+    var container = createElementWithClass('div', 'bordered opponent-subview-card opponent-epilogue-card');
     
-    var titleElem = container.appendChild(createElementWithClass('div', 'opponent-epilogue-title'));
+    var titleElem = container.appendChild(createElementWithClass('div', 'opponent-subview-title opponent-epilogue-title'));
     $(titleElem).html(title);
     
-    var genderElem = container.appendChild(createElementWithClass('div', 'bordered left-cap opponent-epilogue-row opponent-epilogue-gender'));
-    var genderLabel = genderElem.appendChild(createElementWithClass('div', 'left-cap opponent-epilogue-label'));
-    var genderValue = genderElem.appendChild(createElementWithClass('div', 'opponent-epilogue-value'));
+    var genderElem = container.appendChild(createElementWithClass('div', 'bordered left-cap opponent-subview-row opponent-epilogue-row opponent-epilogue-gender'));
+    var genderLabel = genderElem.appendChild(createElementWithClass('div', 'left-cap opponent-subview-label opponent-epilogue-label'));
+    var genderValue = genderElem.appendChild(createElementWithClass('div', 'opponent-subview-value opponent-epilogue-value'));
     
     $(genderValue).html(gender);
     $(genderLabel).text("For");
     
     if (unlockHint) {
-        var unlockHintElem = container.appendChild(createElementWithClass('div', 'bordered left-cap opponent-epilogue-row opponent-epilogue-unlock'));
-        var unlockHintLabel = unlockHintElem.appendChild(createElementWithClass('div', 'left-cap opponent-epilogue-label'));
-        var unlockHintValue = unlockHintElem.appendChild(createElementWithClass('div', 'opponent-epilogue-value'));
+        var unlockHintElem = container.appendChild(createElementWithClass('div', 'bordered left-cap opponent-subview-row opponent-epilogue-row opponent-epilogue-unlock'));
+        var unlockHintLabel = unlockHintElem.appendChild(createElementWithClass('div', 'left-cap opponent-subview-label opponent-epilogue-label'));
+        var unlockHintValue = unlockHintElem.appendChild(createElementWithClass('div', 'opponent-subview-value opponent-epilogue-value'));
         $(unlockHintLabel).text("To Unlock");
         $(unlockHintValue).html(unlockHint);
     }
@@ -1039,6 +1042,55 @@ OpponentDetailsDisplay.prototype.updateEpiloguesView = function () {
     this.epiloguesContainer.empty().append(cards);
 };
 
+OpponentDetailsDisplay.prototype.createCollectibleCard = function (collectible) {
+    var container = createElementWithClass('div', 'bordered opponent-subview-card');
+    
+    var titleElem = container.appendChild(createElementWithClass('div', 'opponent-subview-title'));
+    var subtitleElem = container.appendChild(createElementWithClass('div', 'opponent-subview-subtitle'));
+    
+    if (!collectible.detailsHidden || collectible.isUnlocked()) {
+        $(titleElem).html(collectible.title);
+        $(subtitleElem).html(collectible.subtitle);
+    } else {
+        $(titleElem).html("[Locked]");
+        $(subtitleElem).html("");
+    }
+    
+
+    if (collectible.unlock_hint) {
+        var unlockHintElem = container.appendChild(createElementWithClass('div', 'bordered left-cap opponent-subview-row opponent-collectible-unlock'));
+        var unlockHintLabel = unlockHintElem.appendChild(createElementWithClass('div', 'left-cap opponent-subview-label'));
+        var unlockHintValue = unlockHintElem.appendChild(createElementWithClass('div', 'opponent-subview-value'));
+        $(unlockHintLabel).text("To Unlock");
+        $(unlockHintValue).html(collectible.unlock_hint);
+    }
+    
+    if (collectible.counter) {
+        var counterElem = container.appendChild(createElementWithClass('div', 'bordered left-cap opponent-subview-row opponent-collectible-counter'));
+        var counterLabel = counterElem.appendChild(createElementWithClass('div', 'left-cap opponent-subview-label'));
+        var counterValue = counterElem.appendChild(createElementWithClass('div', 'opponent-subview-value'));
+        
+        var curCounter = collectible.getCounter()
+        $(counterLabel).text("Progress");
+        $(counterValue).html(curCounter + ' / ' + collectible.counter);
+    }
+    
+    return container;
+}
+
+OpponentDetailsDisplay.prototype.updateCollectiblesView = function () {
+    if (!COLLECTIBLES_ENABLED || !this.opponent.has_collectibles || !this.opponent.collectibles) return;
+    
+    var cards = this.opponent.collectibles.map(function (collectible) {
+        if (collectible.hidden && !collectible.isUnlocked()) {
+            return null;
+        } else {
+            return this.createCollectibleCard(collectible);
+        }
+    }.bind(this));
+    this.collectiblesContainer.empty().append(cards);
+}
+
 OpponentDetailsDisplay.prototype.update = function (opponent) {
     this.opponent = opponent;
     
@@ -1053,10 +1105,6 @@ OpponentDetailsDisplay.prototype.update = function (opponent) {
     
     this.selectButton.prop('disabled', false);
     
-    // for now
-    this.collectiblesField.removeClass('has-collectibles');
-    
-    
     if (!opponent.ending) {
         this.epiloguesField.removeClass('has-epilogues');
     } else {
@@ -1068,10 +1116,17 @@ OpponentDetailsDisplay.prototype.update = function (opponent) {
         };
         
         var hasConditionalEnding = false;
+        var totalEndings = 0;
+        var unlockedEndings = 0;
         
         opponent.endings.each(function (idx, elem) {
             var $elem = $(elem);
             
+            totalEndings += 1;
+            if (save.hasEnding(opponent.id, $elem.text())) {
+                unlockedEndings += 1;
+            }
+            
             if(EPILOGUE_CONDITIONAL_ATTRIBUTES.some(function (attr) { return !!$elem.attr(attr); })) {
                 hasConditionalEnding = true;
             }
@@ -1099,17 +1154,45 @@ OpponentDetailsDisplay.prototype.update = function (opponent) {
         
         if (epilogueAvailable) {
             this.epiloguesNavButton
-                .text('Available' + (hasConditionalEnding ? ' (Conditional)' : ''))
+                .text((hasConditionalEnding ? 'Conditionally ' : '') + 'Available' + ' (' + unlockedEndings +'/' + totalEndings + ' seen)')
                 .removeClass('smooth-button-red')
                 .addClass('smooth-button-blue');
         } else {
             this.epiloguesNavButton
-                .text((endingGenders.male ? 'Males' : 'Females') + ' Only')
+                .text((endingGenders.male ? 'Males' : 'Females') + ' Only' + ' (' + unlockedEndings +'/' + totalEndings + ' seen)')
                 .removeClass('smooth-button-blue')
                 .addClass('smooth-button-red');
         }
     }
 
+    if (COLLECTIBLES_ENABLED && opponent.has_collectibles) {        
+        var updateCollectiblesBtn = function () {
+            var counts = opponent.collectibles.reduce(function (acc, collectible) {
+                acc.total += 1;
+                if (collectible.isUnlocked()) acc.unlocked += 1;
+                
+                return acc;
+            }, {unlocked:0, total:0});
+            
+            this.collectiblesNavButton.text("Available ("+counts.unlocked+"/"+counts.total+" unlocked)");
+        }.bind(this);
+        
+        this.collectiblesField.addClass('has-collectibles');
+        
+        this.collectiblesNavButton
+            .text("Available")
+            .addClass('smooth-button-blue')
+            .prop('disabled', false);
+            
+        if (!opponent.collectibles) {
+            opponent.loadCollectibles(updateCollectiblesBtn);
+        } else {
+            updateCollectiblesBtn();
+        }
+    } else {
+        this.collectiblesField.removeClass('has-collectibles');
+    }
+
     if (ALT_COSTUMES_ENABLED && opponent.alternate_costumes.length > 0) {
         this.costumeSelector.empty().append($('<option>', {val: '', text: 'Default Skin'})).prop('disabled', false);
         
-- 
GitLab