diff --git a/app/models/ThangType.coffee b/app/models/ThangType.coffee index add003f56..4a31875c0 100644 --- a/app/models/ThangType.coffee +++ b/app/models/ThangType.coffee @@ -294,7 +294,11 @@ module.exports = class ThangType extends CocoModel itemComponentRef = _.find( @get('components') or [], (compRef) -> compRef.original is LevelComponent.ItemID) - return itemComponentRef?.config?.slots or [] + return itemComponentRef?.config?.slots or ['right-hand'] # ['right-hand'] is default + + getAllowedHeroClasses: -> + return [heroClass] if heroClass = @get 'heroClass' + ['Warrior', 'Ranger', 'Wizard'] getFrontFacingStats: -> components = @get('components') or [] @@ -341,3 +345,10 @@ module.exports = class ThangType extends CocoModel display = display.join ', ' display = display.replace /9001m?/, 'Infinity' name: name, display: display + + isSilhouettedItem: -> + # TODO: have items have actual levels instead of just going by their gem count + return console.error "Trying to determine whether #{@get('name')} should be a silhouetted item, but it has no gem cost." unless @get 'gems' + points = me.get('points') + expectedTotalGems = (points ? 0) * 1.5 # Not actually true, but roughly kinda close for tier 0, kinda tier 1 + @get('gems') > (100 + expectedTotalGems) * 2 diff --git a/app/styles/game-menu/inventory-view.sass b/app/styles/game-menu/inventory-view.sass index eb7084142..165c1d0f4 100644 --- a/app/styles/game-menu/inventory-view.sass +++ b/app/styles/game-menu/inventory-view.sass @@ -14,6 +14,11 @@ $selectedAreaHeight: 150px $stashMargin: 20px $stashWidth: $totalWidth - $equippedWidth - $stashMargin +.ui-effects-transfer + outline: 2px solid #28f + @include box-shadow(0 0 10px #28f) + z-index: 9001 + #inventory-view position: relative height: $inventoryHeight @@ -200,6 +205,11 @@ $stashWidth: $totalWidth - $equippedWidth - $stashMargin padding: 4px background-color: white + &.Warrior .list-group-item:not(.Warrior), &.Ranger .list-group-item:not(.Ranger), &.Wizard .list-group-item:not(.Wizard) + // Our code hides and shows (modifies display), but we can be invisible this other way. + visibility: hidden + position: absolute + .list-group-item padding: 4px 0 @include transition(0.5s ease) @@ -244,6 +254,18 @@ $stashWidth: $totalWidth - $equippedWidth - $stashMargin .item-info:after content: ' (locked)' + &.silhouette + h4 + visibility: hidden + position: absolute + h4:before + content: '???' + visibility: visible + .item-info:after + display: none + img + @include filter(contrast(25%) brightness(25%)) + .item-view cursor: pointer diff --git a/app/templates/game-menu/inventory-view.jade b/app/templates/game-menu/inventory-view.jade index 3e5d3bd19..2b3248cae 100644 --- a/app/templates/game-menu/inventory-view.jade +++ b/app/templates/game-menu/inventory-view.jade @@ -55,5 +55,5 @@ h4#locked-description ul.list-group for item in lockedItems - li.list-group-item(class=item.classes, data-item-id=item.get('original')) + li.list-group-item(class=item.classes, data-item-id=item.get('original'), style="display: none") diff --git a/app/views/game-menu/InventoryView.coffee b/app/views/game-menu/InventoryView.coffee index 51ab7f6a1..c2cdb0d07 100644 --- a/app/views/game-menu/InventoryView.coffee +++ b/app/views/game-menu/InventoryView.coffee @@ -48,15 +48,24 @@ module.exports = class InventoryView extends CocoView context.equipped = _.values(@equipment) context.items = @items.models - context.unlockedItems = [] - context.lockedItems = [] for item in @items.models item.classes = item.getAllowedSlots() item.classes.push 'equipped' if item.get('original') in context.equipped locked = @allowedItems and not (item.get('original') in @allowedItems) - item.classes.push 'locked' if locked - (if locked then context.lockedItems else context.unlockedItems).push item - @items.models.sort (a, b) -> ('locked' in a.classes) - ('locked' in b.classes) + item.classes.push 'locked' if locked and item.get('slug') isnt 'simple-boots' + for heroClass in item.getAllowedHeroClasses() + item.classes.push heroClass + item.classes.push 'silhouette' if item.isSilhouettedItem() + + @items.models.sort (a, b) -> + lockScore = 90019001 * (('locked' in a.classes) - ('locked' in b.classes)) + gemScore = a.get('gems') - b.get('gems') + lockScore + gemScore + + context.unlockedItems = [] + context.lockedItems = [] + for item in @items.models + (if 'locked' in item.classes then context.lockedItems else context.unlockedItems).push item context.slots = @slots context.equipment = _.clone @equipment @@ -184,6 +193,7 @@ module.exports = class InventoryView extends CocoView @onSelectionChanged() slot = @getSelectedSlot() slot = @$el.find('.item-slot:not(.disabled):first') if not slot.length + $(e.target).effect('transfer', to: slot, duration: 500, easing: 'easeOutCubic') if e @unequipItemFromSlot(slot) @equipSelectedItemToSlot(slot) @onSelectionChanged() @@ -261,9 +271,9 @@ module.exports = class InventoryView extends CocoView @hideSelectedSlotItem() else unlockedCount = @$el.find('#available-equipment .list-group-item:not(.locked)').show().length - lockedCount = @$el.find('#available-equipment .list-group-item.locked').show().length + @$el.find('#available-equipment .list-group-item.locked').hide() @$el.find('#unlocked-description').text("#{unlockedCount} items owned").toggle unlockedCount > 0 - @$el.find('#locked-description').text("#{lockedCount} items locked").toggle lockedCount > 0 + @$el.find('#locked-description').text("#{lockedCount} items locked").hide() #@$el.find('#available-equipment .list-group-item.equipped').hide() @$el.find('.item-slot').removeClass('disabled') @@ -327,30 +337,30 @@ module.exports = class InventoryView extends CocoView # This is temporary, until we have a more general way of awarding items and configuring needed/locked items per level. gear = 'simple-boots': '53e237bf53457600003e3f05' - 'longsword': '53e218d853457600003e3ebe' + 'simple-sword': '53e218d853457600003e3ebe' 'leather-tunic': '53e22eac53457600003e3efc' 'leather-boots': '53e2384453457600003e3f07' 'programmaticon-i': '53e4108204c00d4607a89f78' - 'crude-glasses': '53e238df53457600003e3f0b' + 'crude-wooden-glasses': '53e238df53457600003e3f0b' 'builders-hammer': '53f4e6e3d822c23505b74f42' gearByLevel = 'dungeons-of-kithgard': {feet: 'simple-boots'} 'gems-in-the-deep': {feet: 'simple-boots'} 'forgetful-gemsmith': {feet: 'simple-boots'} 'shadow-guard': {feet: 'simple-boots'} - 'true-names': {feet: 'simple-boots', 'right-hand': 'longsword'} - 'the-raised-sword': {feet: 'simple-boots', 'right-hand': 'longsword', torso: 'leather-tunic'} + 'true-names': {feet: 'simple-boots', 'right-hand': 'simple-sword'} + 'the-raised-sword': {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic'} 'the-first-kithmaze': {feet: 'simple-boots', 'programming-book': 'programmaticon-i'} 'the-second-kithmaze': {feet: 'simple-boots', 'programming-book': 'programmaticon-i'} - 'new-sight': {'right-hand': 'longsword', 'programming-book': 'programmaticon-i'} - 'lowly-kithmen': {feet: 'simple-boots', 'right-hand': 'longsword', 'programming-book': 'programmaticon-i', eyes: 'crude-glasses'} - 'closing-the-distance': {feet: 'simple-boots', 'right-hand': 'longsword', torso: 'leather-tunic', eyes: 'crude-glasses'} - 'the-final-kithmaze': {feet: 'simple-boots', 'right-hand': 'longsword', torso: 'leather-tunic', 'programming-book': 'programmaticon-i', eyes: 'crude-glasses'} + 'new-sight': {'right-hand': 'simple-sword', 'programming-book': 'programmaticon-i'} + 'lowly-kithmen': {feet: 'simple-boots', 'right-hand': 'simple-sword', 'programming-book': 'programmaticon-i', eyes: 'crude-wooden-glasses'} + 'closing-the-distance': {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', eyes: 'crude-wooden-glasses'} + 'the-final-kithmaze': {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', 'programming-book': 'programmaticon-i', eyes: 'crude-wooden-glasses'} 'kithgard-gates': {feet: 'simple-boots', 'right-hand': 'builders-hammer', torso: 'leather-tunic'} 'defense-of-plainswood': {feet: 'simple-boots', 'right-hand': 'builders-hammer'} 'winding-trail': {feet: 'leather-boots', 'right-hand': 'builders-hammer'} - 'thornbush-farm': {feet: 'leather-boots', 'right-hand': 'builders-hammer', eyes: 'crude-glasses'} - 'a-fiery-trap': {feet: 'leather-boots', 'right-hand': 'builders-hammer', eyes: 'crude-glasses'} + 'thornbush-farm': {feet: 'leather-boots', 'right-hand': 'builders-hammer', eyes: 'crude-wooden-glasses'} + 'a-fiery-trap': {feet: 'leather-boots', 'right-hand': 'builders-hammer', eyes: 'crude-wooden-glasses'} return unless necessaryGear = gearByLevel[@options.levelID] if @inserted if @supermodel.finished() @@ -363,7 +373,7 @@ module.exports = class InventoryView extends CocoView inWorldMap = $('#world-map-view').length for slot, item of necessaryGear continue if item is 'leather-tunic' and inWorldMap # Don't tell them they need it until they need it in the level - continue if equipment[slot] and not ((item is 'builders-hammer' and equipment[slot] is gear.longsword) or (item is 'leather-boots' and equipment[slot] is gear['simple-boots'])) + continue if equipment[slot] and not ((item is 'builders-hammer' and equipment[slot] is gear['simple-sword']) or (item is 'leather-boots' and equipment[slot] is gear['simple-boots'])) availableSlotSelector = "#available-equipment li[data-item-id='#{gear[item]}']" @highlightElement availableSlotSelector, delay: 500, sides: ['right'], rotation: Math.PI / 2 @$el.find(availableSlotSelector).addClass 'should-equip' @@ -386,6 +396,7 @@ module.exports = class InventoryView extends CocoView onHeroSelectionUpdated: (e) -> @selectedHero = e.hero @loadHero() + @$el.removeClass('Warrior Ranger Wizard').addClass(@selectedHero.get('heroClass')) loadHero: -> return unless @supermodel.finished() and @selectedHero and not @$el.hasClass 'secret' diff --git a/server/commons/Handler.coffee b/server/commons/Handler.coffee index 5cbd3e4d6..15ecc3b11 100644 --- a/server/commons/Handler.coffee +++ b/server/commons/Handler.coffee @@ -46,9 +46,9 @@ module.exports = class Handler omissions = ['original'].concat(deltasLib.DOC_SKIP_PATHS) delta = differ.diff(_.omit(document.toObject(), omissions), _.omit(req.body, omissions)) flattened = deltasLib.flattenDelta(delta) - _.all(flattened, (delta) -> + _.all flattened, (delta) -> # sometimes coverage gets moved around... allow other changes to happen to i18nCoverage - return _.isArray(delta.o) and (('i18n' in delta.dataPath and delta.o.length is 1) or 'i18nCoverage' in delta.dataPath)) + return _.isArray(delta.o) and (('i18n' in delta.dataPath and delta.o.length is 1) or 'i18nCoverage' in delta.dataPath) formatEntity: (req, document) -> document?.toObject() getEditableProperties: (req, document) -> diff --git a/server/levels/thangs/thang_type_handler.coffee b/server/levels/thangs/thang_type_handler.coffee index 69c663c1e..8013197dd 100644 --- a/server/levels/thangs/thang_type_handler.coffee +++ b/server/levels/thangs/thang_type_handler.coffee @@ -60,6 +60,7 @@ ThangTypeHandler = class ThangTypeHandler extends Handler query = slug: {$exists: true} if req.query.view is 'items' query.kind = 'Item' + query.gems = {$exists: true} # Items without gems don't show up anywhere else if req.query.view is 'heroes' #query.kind = 'Hero' # TODO: when all the heroes are tagged, just use this query.original = {$in: _.values heroes} # TODO: when all the heroes are tagged, don't do this