Working on the inventory view. Added a way to get the current equipment config from the inventory view.

This commit is contained in:
Scott Erickson 2014-08-13 17:21:37 -07:00
parent 7286d069a0
commit c31a509472
11 changed files with 409 additions and 13 deletions

View file

@ -15,6 +15,7 @@ module.exports = class CocoRouter extends Backbone.Router
routes:
'': go('HomeView')
'items': go('game-menu/InventoryView')
'about': go('AboutView')

View file

@ -944,6 +944,7 @@
candidate_sessions: "Candidate Sessions"
user_remark: "User Remark"
versions: "Versions"
items: "Items"
delta:
added: "Added"

View file

@ -5,6 +5,8 @@ module.exports = class LevelComponent extends CocoModel
@schema: require 'schemas/models/level_component'
@EquipsID: '53e217d253457600003e3ebb'
@ItemID: '53e12043b82921000051cdf9'
@AttacksID: '524b7ba57fc0f6d519000016'
urlRoot: '/db/level.component'
set: (key, val, options) ->

View file

@ -1,5 +1,6 @@
CocoModel = require './CocoModel'
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
LevelComponent = require './LevelComponent'
buildQueue = []
@ -262,3 +263,55 @@ module.exports = class ThangType extends CocoModel
@wizardType.url = -> url
@wizardType.fetch()
@wizardType
getPortraitURL: -> "/file/db/thang.type/#{@get('original')}/portrait.png"
# Item functions
getAllowedSlots: ->
itemComponentRef = _.find(
@get('components') or [],
(compRef) -> compRef.original is LevelComponent.ItemID)
return itemComponentRef?.config?.slots or []
getFrontFacingStats: ->
stats = []
for component in @get('components') or []
continue unless config = component.config
if config.attackDamage
stats.push { name: 'Attack Damage', value: config.attackDamage }
if config.attackRange
stats.push { name: 'Attack Range', value: "#{config.attackRange}m" }
if config.cooldown
stats.push { name: 'Cooldown', value: "#{config.cooldown}s" }
if config.maxSpeed
stats.push { name: 'Speed', value: "#{config.maxSpeed}m/s" }
if config.maxAcceleration
stats.push { name: 'Acceleration', value: "#{config.maxAcceleration}m/s^2" }
if config.stats
for stat, value of config.stats
if value.factor
value = "x#{value.factor}"
if value.addend and value.addend > 0
value = "+#{value.addend}"
if value.addend and value.addend < 0
value = "#{value.addend}"
if value.setTo
value = "=#{value.setTo}"
if stat is 'maxHealth'
stats.push { name: 'Health', value: value }
if stat is 'healthReplenishRate'
stats.push { name: 'Regen', value: value }
if config.programmableProperties
props = config.programmableProperties
if props.length
stats.push { name: 'Allows', value: props.join(', ') }
if config.visualRange
value = config.visualRange
if value is 9001 then value is "Infinite"
stats.push { name: 'Visual Range', value: "#{value}m"}
if config.programmableSnippets
snippets = config.programmableSnippets
if snippets.length
stats.push { name: 'Snippets', value: snippets.join(', ') }
stats

View file

@ -1,3 +1,97 @@
$selected-area-height: 150px
#inventory-view
position: relative
height: 600px
background-color: white
user-select: none
h3
text-decoration: underline
margin: 0
#equipped
padding: 10px
width: 74%
position: absolute
left: 0
top: 0
bottom: $selected-area-height + 10
right: 0
overflow: scroll
.item-slot.disabled
opacity: 0.5
.panel
text-align: center
width: 31%
margin: 5px 2% 5px 0
float: left
cursor: pointer
.panel-heading
padding: 5px
.panel-info .panel-body
background-color: #e0f0f5
.panel-body
height: 50px
padding: 5px
overflow: scroll
font-size: 12px
#available-equipment
width: 24%
padding: 10px
position: absolute
right: 1%
top: 0
bottom: $selected-area-height + 10
overflow: scroll
user-select: none
h3
margin-bottom: 5px
.list-group-item.active
background-color: #e0f0f5
.list-group-item.equipped
display: none
.item-mixin
&.active
background-color: lightblue
.well
padding: 5px
cursor: pointer
#selected-items
position: absolute
height: $selected-area-height
left: 0
right: 0
bottom: 0
#selected-equipped-item, #selected-available-item
position: absolute
bottom: 0
top: 0
overflow: scroll
padding: 10px
img
width: 100px
height: 100px
.item-info
margin-left: 110px
#selected-equipped-item
left: 0
width: 48.5%
#selected-available-item
right: 2%
width: 48.5%

View file

@ -0,0 +1,14 @@
.item-mixin, .item-view
width: 100%
img
float: left
width: 40px
height: 40px
.item-info
margin-left: 45px
ul
margin-top: 5px
padding-left: 20px

View file

@ -1,11 +1,27 @@
img(src="/images/pages/game-menu/inventory-stub.png")
div(data-i18n="inventory.temp") Temp
h3 Interactions
ul
li Click an item slot. It is highlighted and items that can go in that slot show up on the right with short descriptions. Full info about it shows up on the lower left.
li Click an item on the menu. It shows up on the lower right.
li To equip an item: drag (if ipad), double click (if web), click swap button (either)
li Click an item on the menu. It swaps the item into the slot.
li If the equipment changed and the player clicks done, a new LevelSession is created with this new equipment. If “use current code” is selected, the code for the current session is copied over to the new session. Modal closes, data is loaded, world runs, etc.
div#equipped
h3 Equipped
- for (var i=0; i < slots.length; i += 3) {
div
- for (var j=i; j < slots.length && j < i + 3; j++) {
- var slot = slots[j];
div.panel.panel-default.item-slot(data-slot=slot)
.panel-heading
.panel-title.slot-name= slot
.panel-body.slot-item
if equipment[slot]
- var item = equipment[slot]
.replace-me(data-item-id=item.id)
- }
.clearfix
- }
div#available-equipment
h3 Available
for item in items
.list-group-item(class=item.classes, data-item-id=item.id)
div#selected-items
#selected-equipped-item.well
.item-view-stub
#selected-available-item.well
.item-view-stub

View file

@ -0,0 +1,12 @@
img(src=item.getPortraitURL()).img-thumbnail
div.item-info
if includes.name
strong= item.get('name')
if includes.stats
- var stats = item.getFrontFacingStats()
ul
for stat in stats
li #{stat.name}: #{stat.value}
.clearfix

View file

@ -2,15 +2,197 @@ CocoView = require 'views/kinds/CocoView'
template = require 'templates/game-menu/inventory-view'
{me} = require 'lib/auth'
ThangType = require 'models/ThangType'
CocoCollection = require 'collections/CocoCollection'
ItemView = require './ItemView'
DEFAULT_EQUIPMENT = {
'right-hand': '53e21249b82921000051ce11'
'feet':'53e214f153457600003e3eab'
'eyes': '53e2167653457600003e3eb3'
'left-hand': '53e22aa153457600003e3ef5'
}
module.exports = class InventoryView extends CocoView
id: 'inventory-view'
className: 'tab-pane'
template: template
slots: ["head","eyes","neck","torso","wrists","gloves","left-ring","right-ring","right-hand","left-hand","waist","feet","spellbook","programming-book","pet","minion","misc-0","misc-1","misc-2","misc-3","misc-4"]
events:
'click .item-slot': 'onItemSlotClick'
'click #available-equipment .list-group-item': 'onAvailableItemClick'
'dblclick #available-equipment .list-group-item': 'onAvailableItemDoubleClick'
'dblclick .item-slot .item-view': 'onEquippedItemDoubleClick'
shortcuts:
'esc': 'clearSelection'
initialize: (options) ->
super(arguments...)
@items = new CocoCollection([], { model: ThangType })
@equipment = options.equipment or DEFAULT_EQUIPMENT
@items.url = '/db/thang.type?view=items&project=name,description,components,original'
@supermodel.loadCollection(@items, 'items')
onLoaded: ->
super()
getRenderData: (context={}) ->
context = super(context)
context.equipped = _.values(@equipment)
context.items = @items.models
for item in @items.models
item.classes = item.getAllowedSlots()
item.classes.push 'equipped' if item.get('original') in context.equipped
context.slots = @slots
context.equipment = _.clone @equipment
for slot, itemOriginal of context.equipment
item = _.find @items.models, (item) -> item.get('original') is itemOriginal
context.equipment[slot] = item
context
afterRender: ->
super()
return unless @supermodel.finished()
keys = (item.id for item in @items.models)
itemMap = _.zipObject keys, @items.models
# Fill in equipped items
for slottedItemStub in @$el.find('.replace-me')
itemID = $(slottedItemStub).data('item-id')
item = itemMap[itemID]
itemView = new ItemView({item:item, includes:{name:true}})
itemView.render()
$(slottedItemStub).replaceWith(itemView.$el)
@registerSubView(itemView)
for availableItemEl in @$el.find('#available-equipment .list-group-item')
itemID = $(availableItemEl).data('item-id')
item = itemMap[itemID]
itemView = new ItemView({item:item, includes:{name:true}})
itemView.render()
$(availableItemEl).append(itemView.$el)
@registerSubView(itemView)
@delegateEvents()
clearSelection: ->
@$el.find('.panel-info').removeClass('panel-info')
@$el.find('.list-group-item').removeClass('active')
@onSelectionChanged()
onItemSlotClick: (e) ->
slot = $(e.target).closest('.panel')
wasActive = slot.hasClass('panel-info')
@$el.find('#equipped .panel').removeClass('panel-info')
@$el.find('#available-equipment .list-group-item').removeClass('active') if slot.hasClass('disabled')
slot.addClass('panel-info') # unless wasActive
@onSelectionChanged()
onAvailableItemClick: (e) ->
itemEl = $(e.target).closest('.list-group-item')
@$el.find('#available-equipment .list-group-item').removeClass('active')
itemEl.addClass('active')
@onSelectionChanged()
onAvailableItemDoubleClick: ->
slot = @$el.find('#equipped .item-slot.panel-info')
slot = $('.panel:not(.disabled):first') if not slot.length
@unequipItemFromSlot(slot)
@equipSelectedItemToSlot(slot)
@onSelectionChanged()
onEquippedItemDoubleClick: (e) ->
slot = $(e.target).closest('.item-slot')
@unequipItemFromSlot(slot)
@onSelectionChanged()
unequipItemFromSlot: (slot) ->
itemIDToUnequip = slot.find('.item-view').data('item-id')
return unless itemIDToUnequip
slot.find('.item-view').detach()
for el in @$el.find('#available-equipment .list-group-item')
itemID = $(el).find('.item-view').data('item-id')
if itemID is itemIDToUnequip
$(el).removeClass('equipped')
equipSelectedItemToSlot: (slot) ->
selectedItemContainer = @$el.find('#available-equipment .list-group-item.active')
newItemHTML = selectedItemContainer.html()
@$el.find('#available-equipment .list-group-item.active').addClass('equipped')
container = slot.find('.panel-body')
container.html(newItemHTML)
container.find('.item-view').data('item-id', selectedItemContainer.find('.item-view').data('item-id'))
@$el.find('.list-group-item').removeClass('active')
onSelectionChanged: ->
@$el.find('.item-slot').show()
selectedSlot = @$el.find('.panel.panel-info')
selectedItem = @$el.find('#available-equipment .list-group-item.active')
if selectedSlot.length
@$el.find('#available-equipment .list-group-item').hide()
@$el.find("#available-equipment .list-group-item.#{selectedSlot.data('slot')}").show()
selectedSlotItemID = selectedSlot.find('.item-view').data('item-id')
if selectedSlotItemID
item = _.find @items.models, {id:selectedSlotItemID}
if not @selectedEquippedItemView
@selectedEquippedItemView = new ItemView({
item: item, includes: {name: true, stats: true}})
@insertSubView(@selectedEquippedItemView, @$el.find('#selected-equipped-item .item-view-stub'))
else
@selectedEquippedItemView.$el.show()
@selectedEquippedItemView.item = item
@selectedEquippedItemView.render()
else
@selectedEquippedItemView?.$el.hide()
else
@$el.find('#available-equipment .list-group-item').show()
@$el.find('#available-equipment .list-group-item.equipped').hide()
@$el.find('.item-slot').removeClass('disabled')
if selectedItem.length
item = _.find @items.models, {id:selectedItem.find('.item-view').data('item-id')}
# update which slots are enabled
allowedSlots = item.getAllowedSlots()
for slotEl in @$el.find('.item-slot')
slotName = $(slotEl).data('slot')
if slotName not in allowedSlots
$(slotEl).addClass('disabled')
# updated selected item view
if not @selectedAvailableItemView
@selectedAvailableItemView = new ItemView({
item: item, includes: {name: true, stats: true}})
@insertSubView(@selectedAvailableItemView, @$el.find('#selected-available-item .item-view-stub'))
else
@selectedAvailableItemView.$el.show()
@selectedAvailableItemView.item = item
@selectedAvailableItemView.render()
else
@selectedAvailableItemView?.$el.hide()
@delegateEvents()
getCurrentEquipmentConfig: ->
config = {}
for slot in @$el.find('.item-slot')
slotName = $(slot).data('slot')
slotItemID = $(slot).find('.item-view').data('item-id')
continue unless slotItemID
item = _.find @items.models, {id:slotItemID}
config[slotName] = item.get('original')
config

View file

@ -0,0 +1,21 @@
CocoView = require 'views/kinds/CocoView'
template = require 'templates/game-menu/item-view'
module.exports = class ItemView extends CocoView
className: 'item-view'
template: template
initialize: (options) ->
super(arguments...)
@item = options.item
@includes = options.includes or {}
getRenderData: ->
c = super()
c.item = @item
c.includes = @includes
c
afterRender: ->
@$el.data('item-id', @item.id)

View file

@ -31,7 +31,7 @@ ThangTypeHandler = class ThangTypeHandler extends Handler
projection = {}
if req.query.project
projection[field] = 1 for field in req.query.project.split(',')
ThangType.find({ 'kind': 'Item' }, projection).exec (err, documents) =>
ThangType.find({ 'kind': 'Item', slug: { $exists: true } }, projection).exec (err, documents) =>
return @sendDatabaseError(res, err) if err
documents = (@formatEntity(req, doc) for doc in documents)
@sendSuccess(res, documents)