mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 15:48:11 -05:00
Crude steps towards using your hero equipment in items levels.
This commit is contained in:
parent
9404c40b47
commit
0f983bdcf1
9 changed files with 108 additions and 60 deletions
|
@ -31,6 +31,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
@opponentSessionID = options.opponentSessionID
|
||||
@team = options.team
|
||||
@headless = options.headless
|
||||
@inLevelEditor = options.inLevelEditor
|
||||
@spectateMode = options.spectateMode ? false
|
||||
|
||||
@worldNecessities = []
|
||||
|
@ -83,6 +84,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
for itemThangType in _.values(heroConfig.inventory)
|
||||
url = "/db/thang.type/#{itemThangType}/version?project=name,components,original"
|
||||
@worldNecessities.push @maybeLoadURL(url, ThangType, 'thang')
|
||||
@populateHero() if @level?.loaded
|
||||
|
||||
# Supermodel (Level) Loading
|
||||
|
||||
|
@ -96,6 +98,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
|
||||
onLevelLoaded: ->
|
||||
@populateLevel()
|
||||
@populateHero() if @session?.loaded
|
||||
|
||||
populateLevel: ->
|
||||
thangIDs = []
|
||||
|
@ -149,6 +152,16 @@ module.exports = class LevelLoader extends CocoClass
|
|||
|
||||
@worldNecessities = @worldNecessities.concat worldNecessities
|
||||
|
||||
populateHero: ->
|
||||
return if @inLevelEditor
|
||||
return unless @level.get('type') is 'hero' and hero = _.find @level.get('thangs'), id: 'Hero Placeholder'
|
||||
heroConfig = @session.get('heroConfig')
|
||||
hero.thangType = heroConfig.thangType
|
||||
hero.inventory = heroConfig.inventory # Will take effect in Level's denormalizeThang
|
||||
hero.placeholderComponents = hero.components # Will be replaced in Level's denormalizeThang
|
||||
hero.components = []
|
||||
#hero.id = ... ? # What do we want to do about this?
|
||||
|
||||
loadItemThangsEquippedByLevelThang: (levelThang) ->
|
||||
return unless levelThang.components
|
||||
for component in levelThang.components
|
||||
|
@ -178,7 +191,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
levelThang = $.extend true, {}, levelThang
|
||||
@level.denormalizeThang(levelThang, @supermodel)
|
||||
equipsComponent = _.find levelThang.components, {original: LevelComponent.EquipsID}
|
||||
inventory = equipsComponent.config?.inventory
|
||||
inventory = equipsComponent?.config?.inventory
|
||||
continue unless inventory
|
||||
for itemThangType in _.values inventory
|
||||
url = "/db/thang.type/#{itemThangType}/version?project=name,components,original"
|
||||
|
|
|
@ -9,8 +9,7 @@ module.exports = class Level extends CocoModel
|
|||
urlRoot: '/db/level'
|
||||
|
||||
serialize: (supermodel) ->
|
||||
# o = _.cloneDeep @attributes # slow in level editor when there are hundreds of Thangs
|
||||
o = $.extend true, {}, @attributes
|
||||
o = @denormalize supermodel
|
||||
|
||||
# Figure out Components
|
||||
o.levelComponents = _.cloneDeep (lc.attributes for lc in supermodel.getModels LevelComponent)
|
||||
|
@ -31,8 +30,10 @@ module.exports = class Level extends CocoModel
|
|||
|
||||
denormalize: (supermodel) ->
|
||||
o = $.extend true, {}, @attributes
|
||||
for levelThang in o.thangs
|
||||
@denormalizeThang(levelThang, supermodel)
|
||||
if @get('type') is 'hero'
|
||||
# TOOD: figure out if/when/how we are doing this for non-Hero levels that aren't expecting denormalization.
|
||||
for levelThang in o.thangs
|
||||
@denormalizeThang(levelThang, supermodel)
|
||||
o
|
||||
|
||||
denormalizeThang: (levelThang, supermodel) ->
|
||||
|
@ -41,16 +42,38 @@ module.exports = class Level extends CocoModel
|
|||
configs = {}
|
||||
for thangComponent in levelThang.components
|
||||
configs[thangComponent.original] = thangComponent
|
||||
placeholders = {}
|
||||
for thangComponent in levelThang.placeholderComponents ? []
|
||||
placeholders[thangComponent.original] = thangComponent
|
||||
|
||||
for defaultThangComponent in thangType.get('components')
|
||||
if levelThangComponent = configs[defaultThangComponent.original]
|
||||
# take the thang type default components and merge level-specific component config into it
|
||||
# Take the ThangType default Components and merge level-specific Component config into it
|
||||
copy = $.extend true, {}, defaultThangComponent.config
|
||||
levelThangComponent.config = _.merge copy, levelThangComponent.config
|
||||
|
||||
else
|
||||
# just add the component as is
|
||||
levelThang.components.push $.extend true, {}, defaultThangComponent
|
||||
# Just add the Component as is
|
||||
levelThangComponent = $.extend true, {}, defaultThangComponent
|
||||
levelThang.components.push levelThangComponent
|
||||
|
||||
if placeholderComponent = placeholders[defaultThangComponent.original]
|
||||
placeholderConfig = placeholderComponent.config ? {}
|
||||
if placeholderConfig.pos # Pull in Physical pos x and y
|
||||
levelThangComponent.config.pos ?= {}
|
||||
levelThangComponent.config.pos.x = placeholderConfig.pos.x
|
||||
levelThangComponent.config.pos.y = placeholderConfig.pos.y
|
||||
else if placeholderConfig.team # Pull in Allied team
|
||||
levelThangComponent.config.team = placeholderConfig.team
|
||||
else if placeholderConfig.programmableMethods
|
||||
# Take the ThangType default Programmable and merge level-specific Component config into it
|
||||
copy = $.extend true, {}, placeholderConfig
|
||||
levelThangComponent.config = _.merge copy, levelThangComponent.config
|
||||
|
||||
if levelThang.inventory and equips = _.find levelThang.components, {original: LevelComponent.EquipsID}
|
||||
# inventory is assigned from the LevelSession in LevelLoader's populateHero
|
||||
equips.config.inventory = $.extend true, {}, levelThang.inventory
|
||||
|
||||
|
||||
sortSystems: (levelSystems, systemModels) ->
|
||||
[sorted, originalsSeen] = [[], {}]
|
||||
|
|
|
@ -55,10 +55,13 @@ _.extend LevelSessionSchema.properties,
|
|||
|
||||
screenshot:
|
||||
type: 'string'
|
||||
|
||||
heroConfig: c.object {},
|
||||
inventory: c.object()
|
||||
thangType: c.objectId()
|
||||
|
||||
heroConfig: c.object {description: 'Which hero the player is using, equipped with what inventory.'},
|
||||
inventory:
|
||||
type: 'object'
|
||||
description: 'The inventory of the hero: slots to item ThangTypes.'
|
||||
additionalProperties: c.objectId(description: 'An item ThangType.')
|
||||
thangType: c.objectId(links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], title: 'Thang Type', description: 'The ThangType of the hero.', format: 'thang-type')
|
||||
|
||||
state: c.object {},
|
||||
complete:
|
||||
|
|
|
@ -12,8 +12,8 @@ nodes = require '../level/treema_nodes'
|
|||
ThangType = require 'models/ThangType'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
|
||||
class ThangTypeSearchCollection extends CocoCollection
|
||||
url: '/db/thang.type?project=original,name,version,slug,kind,components'
|
||||
class ItemThangTypeSearchCollection extends CocoCollection
|
||||
url: '/db/thang.type?view=items&project=original,name,version,slug,kind,components'
|
||||
model: ThangType
|
||||
|
||||
module.exports = class ThangComponentsEditView extends CocoView
|
||||
|
@ -32,7 +32,7 @@ module.exports = class ThangComponentsEditView extends CocoView
|
|||
@level = options.level
|
||||
@loadComponents(@components)
|
||||
# Need to grab the ThangTypes so that we can autocomplete items in inventory based on them.
|
||||
@thangTypes = @supermodel.loadCollection(new ThangTypeSearchCollection(), 'thangs').model
|
||||
@itemThangTypes = @supermodel.loadCollection(new ItemThangTypeSearchCollection(), 'thangs').model
|
||||
|
||||
loadComponents: (components) ->
|
||||
for componentRef in components
|
||||
|
|
|
@ -47,7 +47,7 @@ module.exports = class LevelEditView extends RootView
|
|||
super options
|
||||
@supermodel.shouldSaveBackups = (model) ->
|
||||
model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem', 'ThangType']
|
||||
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, headless: true
|
||||
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, headless: true, inLevelEditor: true
|
||||
@level = @levelLoader.level
|
||||
@files = new DocumentFiles(@levelLoader.level)
|
||||
@supermodel.loadCollection(@files, 'file_names')
|
||||
|
|
|
@ -335,8 +335,8 @@ module.exports = class ThangsTabView extends CocoView
|
|||
|
||||
adjustThangPos: (sprite, thang, pos) ->
|
||||
snap = sprite?.data?.snap or sprite?.thangType?.get('snap') or {x: 0.01, y: 0.01} # Centimeter resolution by default
|
||||
pos.x = Math.round((pos.x - thang.width / 2) / snap.x) * snap.x + thang.width / 2
|
||||
pos.y = Math.round((pos.y - thang.height / 2) / snap.y) * snap.y + thang.height / 2
|
||||
pos.x = Math.round((pos.x - (thang.width ? 1) / 2) / snap.x) * snap.x + (thang.width ? 1) / 2
|
||||
pos.y = Math.round((pos.y - (thang.height ? 1) / 2) / snap.y) * snap.y + (thang.height ? 1) / 2
|
||||
pos.z = thang.depth / 2
|
||||
thang.pos = pos
|
||||
@surface.spriteBoss.update true # Make sure Obstacle layer resets cache
|
||||
|
|
|
@ -9,32 +9,32 @@ 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"]
|
||||
|
||||
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'
|
||||
'click #swap-button': 'onClickSwapButton'
|
||||
|
||||
|
||||
shortcuts:
|
||||
'esc': 'clearSelection'
|
||||
|
||||
|
||||
initialize: (options) ->
|
||||
super(arguments...)
|
||||
@items = new CocoCollection([], { model: ThangType })
|
||||
@equipment = options.equipment or {}
|
||||
@items = new CocoCollection([], {model: ThangType})
|
||||
@equipment = options.equipment or @options.session?.get('heroConfig')?.inventory or {}
|
||||
@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
|
||||
context.items = @items.models
|
||||
|
||||
for item in @items.models
|
||||
item.classes = item.getAllowedSlots()
|
||||
|
@ -50,7 +50,7 @@ module.exports = class InventoryView extends CocoView
|
|||
afterRender: ->
|
||||
super()
|
||||
return unless @supermodel.finished()
|
||||
|
||||
|
||||
keys = (item.id for item in @items.models)
|
||||
itemMap = _.zipObject keys, @items.models
|
||||
|
||||
|
@ -58,7 +58,7 @@ module.exports = class InventoryView extends CocoView
|
|||
for slottedItemStub in @$el.find('.replace-me')
|
||||
itemID = $(slottedItemStub).data('item-id')
|
||||
item = itemMap[itemID]
|
||||
itemView = new ItemView({item:item, includes:{name:true}})
|
||||
itemView = new ItemView({item: item, includes: {name: true}})
|
||||
itemView.render()
|
||||
$(slottedItemStub).replaceWith(itemView.$el)
|
||||
@registerSubView(itemView)
|
||||
|
@ -66,13 +66,13 @@ module.exports = class InventoryView extends CocoView
|
|||
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 = 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')
|
||||
|
@ -85,7 +85,7 @@ module.exports = class InventoryView extends CocoView
|
|||
@unselectAllAvailableEquipment() if slot.hasClass('disabled')
|
||||
@selectSlot(slot) unless wasActive and not $(e.target).closest('.item-view')[0]
|
||||
@onSelectionChanged()
|
||||
|
||||
|
||||
onAvailableItemClick: (e) ->
|
||||
itemContainer = $(e.target).closest('.list-group-item')
|
||||
@unselectAllAvailableEquipment()
|
||||
|
@ -98,7 +98,7 @@ module.exports = class InventoryView extends CocoView
|
|||
@unequipItemFromSlot(slot)
|
||||
@equipSelectedItemToSlot(slot)
|
||||
@onSelectionChanged()
|
||||
|
||||
|
||||
onEquippedItemDoubleClick: (e) ->
|
||||
@unselectAllAvailableEquipment()
|
||||
slot = $(e.target).closest('.item-slot')
|
||||
|
@ -115,31 +115,31 @@ module.exports = class InventoryView extends CocoView
|
|||
@selectAvailableItem(itemContainer)
|
||||
@selectSlot(slot)
|
||||
@onSelectionChanged()
|
||||
|
||||
getSelectedSlot: ->
|
||||
|
||||
getSelectedSlot: ->
|
||||
@$el.find('#equipped .item-slot.panel-info')
|
||||
|
||||
unselectAllAvailableEquipment: ->
|
||||
|
||||
unselectAllAvailableEquipment: ->
|
||||
@$el.find('#available-equipment .list-group-item').removeClass('active')
|
||||
|
||||
|
||||
unselectAllSlots: ->
|
||||
@$el.find('#equipped .panel').removeClass('panel-info')
|
||||
|
||||
|
||||
selectSlot: (slot) ->
|
||||
slot.addClass('panel-info')
|
||||
|
||||
|
||||
getSlot: (name) ->
|
||||
@$el.find(".item-slot[data-slot=#{name}]")
|
||||
|
||||
|
||||
getSelectedAvailableItemContainer: ->
|
||||
@$el.find('#available-equipment .list-group-item.active')
|
||||
|
||||
|
||||
getAvailableItemContainer: (itemID) ->
|
||||
@$el.find("#available-equipment .list-group-item[data-item-id='#{itemID}']")
|
||||
|
||||
|
||||
selectAvailableItem: (itemContainer) ->
|
||||
itemContainer?.addClass('active')
|
||||
|
||||
|
||||
unequipItemFromSlot: (slot) ->
|
||||
itemIDToUnequip = slot.find('.item-view').data('item-id')
|
||||
return unless itemIDToUnequip
|
||||
|
@ -157,22 +157,22 @@ module.exports = class InventoryView extends CocoView
|
|||
slotContainer.html(newItemHTML)
|
||||
slotContainer.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}
|
||||
@showSelectedSlotItem(item)
|
||||
|
||||
|
||||
else
|
||||
@hideSelectedSlotItem()
|
||||
|
||||
|
@ -183,7 +183,7 @@ module.exports = class InventoryView extends CocoView
|
|||
@$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')
|
||||
|
@ -192,12 +192,12 @@ module.exports = class InventoryView extends CocoView
|
|||
$(slotEl).addClass('disabled')
|
||||
|
||||
@showSelectedAvailableItem(item)
|
||||
|
||||
|
||||
else
|
||||
@hideSelectedAvailableItem()
|
||||
|
||||
|
||||
@delegateEvents()
|
||||
|
||||
|
||||
showSelectedSlotItem: (item) ->
|
||||
if not @selectedEquippedItemView
|
||||
@selectedEquippedItemView = new ItemView({
|
||||
|
@ -208,10 +208,10 @@ module.exports = class InventoryView extends CocoView
|
|||
@selectedEquippedItemView.$el.show()
|
||||
@selectedEquippedItemView.item = item
|
||||
@selectedEquippedItemView.render()
|
||||
|
||||
|
||||
hideSelectedSlotItem: ->
|
||||
@selectedEquippedItemView?.$el.hide()
|
||||
|
||||
|
||||
showSelectedAvailableItem: (item) ->
|
||||
if not @selectedAvailableItemView
|
||||
@selectedAvailableItemView = new ItemView({
|
||||
|
@ -222,7 +222,7 @@ module.exports = class InventoryView extends CocoView
|
|||
@selectedAvailableItemView.$el.show()
|
||||
@selectedAvailableItemView.item = item
|
||||
@selectedAvailableItemView.render()
|
||||
|
||||
|
||||
hideSelectedAvailableItem: ->
|
||||
@selectedAvailableItemView?.$el.hide()
|
||||
|
||||
|
@ -234,5 +234,14 @@ module.exports = class InventoryView extends CocoView
|
|||
continue unless slotItemID
|
||||
item = _.find @items.models, {id:slotItemID}
|
||||
config[slotName] = item.get('original')
|
||||
|
||||
config
|
||||
|
||||
config
|
||||
|
||||
onHidden: ->
|
||||
inventory = @getCurrentEquipmentConfig()
|
||||
heroConfig = @options.session.get('heroConfig') ? {}
|
||||
unless _.isEqual inventory, heroConfig.inventory
|
||||
heroConfig.inventory = inventory
|
||||
heroConfig.thangType ?= '529ffbf1cf1818f2be000001' # Temp: assign Tharin as the hero
|
||||
@options.session.set 'heroConfig', heroConfig
|
||||
@options.session.patch()
|
||||
|
|
|
@ -9,7 +9,7 @@ import sys
|
|||
current_directory = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
coco_path = os.getenv("COCO_DIR",os.path.join(current_directory,os.pardir))
|
||||
brunch_path = coco_path + os.sep + "node_modules" + os.sep + ".bin" + os.sep + "brunch"
|
||||
subprocess.Popen("ulimit -n 100000",shell=True)
|
||||
subprocess.Popen("ulimit -n 10000", shell=True)
|
||||
while True:
|
||||
print("Starting brunch. After the first compile, it'll keep running and watch for changes.")
|
||||
call(brunch_path + " w",shell=True,cwd=coco_path)
|
||||
|
|
|
@ -45,7 +45,7 @@ LevelSessionSchema.pre 'save', (next) ->
|
|||
LevelSessionSchema.statics.privateProperties = ['code', 'submittedCode', 'unsubscribed']
|
||||
LevelSessionSchema.statics.editableProperties = ['multiplayer', 'players', 'code', 'codeLanguage', 'completed', 'state',
|
||||
'levelName', 'creatorName', 'levelID', 'screenshot',
|
||||
'chat', 'teamSpells', 'submitted', 'submittedCodeLanguage', 'unsubscribed', 'playtime']
|
||||
'chat', 'teamSpells', 'submitted', 'submittedCodeLanguage', 'unsubscribed', 'playtime', 'heroConfig']
|
||||
LevelSessionSchema.statics.jsonSchema = jsonschema
|
||||
|
||||
LevelSessionSchema.index {user: 1, changed: -1}, {sparse: true, name: 'last played index'}
|
||||
|
|
Loading…
Reference in a new issue