mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 08:50:58 -05:00
Merge pull request #1388 from jayant1992/terrain-generator
Terrain generator and level editor updates
This commit is contained in:
commit
0ebe77098b
15 changed files with 339 additions and 74 deletions
|
@ -151,6 +151,8 @@ $mobile: 1050px
|
||||||
input
|
input
|
||||||
width: $addPaletteWidth
|
width: $addPaletteWidth
|
||||||
margin: 0
|
margin: 0
|
||||||
|
margin-top: 5px
|
||||||
|
padding-left: 5px
|
||||||
@media screen and (max-width: $mobile)
|
@media screen and (max-width: $mobile)
|
||||||
margin: 0 5px
|
margin: 0 5px
|
||||||
|
|
||||||
|
@ -208,6 +210,21 @@ $mobile: 1050px
|
||||||
#canvas-wrapper
|
#canvas-wrapper
|
||||||
width: 100%
|
width: 100%
|
||||||
position: relative
|
position: relative
|
||||||
|
|
||||||
|
#canvas-overlay
|
||||||
|
position: absolute
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
background: white
|
||||||
|
opacity: 0.5
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
#randomize-button
|
||||||
|
position: absolute
|
||||||
|
top: 45%
|
||||||
|
height: 40px
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Below snatched from play/level.sass; should refactor?
|
// Below snatched from play/level.sass; should refactor?
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
h3(data-i18n="editor.level_tab_thangs_add") Add Thangs
|
h3(data-i18n="editor.level_tab_thangs_add") Add Thangs
|
||||||
input(type="search", id="thang-search")
|
input(type="search", id="thang-search", placeholder="Search thangs")
|
||||||
div.editor-nano-container.nano
|
div.editor-nano-container.nano
|
||||||
#thangs-list.nano-content
|
#thangs-list.nano-content
|
||||||
for group in groups
|
for group in groups
|
||||||
|
|
|
@ -38,6 +38,12 @@ block header
|
||||||
span.navbar-brand #{level.attributes.name}
|
span.navbar-brand #{level.attributes.name}
|
||||||
|
|
||||||
ul.nav.navbar-nav.navbar-right
|
ul.nav.navbar-nav.navbar-right
|
||||||
|
li#undo-button(title="Undo (Ctrl+Z)")
|
||||||
|
a
|
||||||
|
span.glyphicon-arrow-left.glyphicon
|
||||||
|
li#redo-button(title="Redo (Ctrl+Shift+Z)")
|
||||||
|
a
|
||||||
|
span.glyphicon-repeat.glyphicon
|
||||||
if authorized
|
if authorized
|
||||||
li#commit-level-start-button
|
li#commit-level-start-button
|
||||||
a
|
a
|
||||||
|
|
|
@ -12,5 +12,5 @@ block modal-body-content
|
||||||
div.preset-size.name-label.capitalize
|
div.preset-size.name-label.capitalize
|
||||||
span(data-i18n="editor."+size) #{size}
|
span(data-i18n="editor."+size) #{size}
|
||||||
div.preset-name.capitalize
|
div.preset-name.capitalize
|
||||||
span(data-i18n="editor.grassy") #{preset.type}
|
span(data-i18n="editor."+preset.type) #{preset.type}
|
||||||
block modal-footer
|
block modal-footer
|
||||||
|
|
|
@ -23,6 +23,8 @@ button.navbar-toggle.toggle.btn-primary#thangs-palette-toggle(type="button", dat
|
||||||
.world-container.thangs-column
|
.world-container.thangs-column
|
||||||
h3(data-i18n="editor.level_tab_thangs_conditions") Starting Conditions
|
h3(data-i18n="editor.level_tab_thangs_conditions") Starting Conditions
|
||||||
#canvas-wrapper
|
#canvas-wrapper
|
||||||
|
#canvas-overlay
|
||||||
|
button.btn.btn-primary(id="randomize-button", data-toggle="coco-modal", data-target="editor/level/modals/TerrainRandomizeModal", data-i18n="editor.randomize", title="Randomize Terrain") Randomize
|
||||||
ul.dropdown-menu#contextmenu
|
ul.dropdown-menu#contextmenu
|
||||||
li#delete
|
li#delete
|
||||||
a(data-i18n="editor.delete") Delete
|
a(data-i18n="editor.delete") Delete
|
||||||
|
|
|
@ -69,4 +69,10 @@ module.exports = class ThangComponentConfigView extends CocoView
|
||||||
@changed = true
|
@changed = true
|
||||||
@callback?(@data())
|
@callback?(@data())
|
||||||
|
|
||||||
|
undo: ->
|
||||||
|
@editThangTreema.undo()
|
||||||
|
|
||||||
|
redo: ->
|
||||||
|
@editThangTreema.redo()
|
||||||
|
|
||||||
data: -> @editThangTreema.data
|
data: -> @editThangTreema.data
|
||||||
|
|
|
@ -184,6 +184,12 @@ module.exports = class ThangComponentEditView extends CocoView
|
||||||
reportChanges: ->
|
reportChanges: ->
|
||||||
@callback?($.extend(true, [], @extantComponentsTreema.data))
|
@callback?($.extend(true, [], @extantComponentsTreema.data))
|
||||||
|
|
||||||
|
undo: ->
|
||||||
|
if @configView is null or @configView?.editing is false then @extantComponentsTreema.undo() else @configView.undo()
|
||||||
|
|
||||||
|
redo: ->
|
||||||
|
if @configView is null or @configView?.editing is false then @extantComponentsTreema.redo() else @configView.redo()
|
||||||
|
|
||||||
class ThangComponentsArrayNode extends TreemaArrayNode
|
class ThangComponentsArrayNode extends TreemaArrayNode
|
||||||
valueClass: 'treema-thang-components-array'
|
valueClass: 'treema-thang-components-array'
|
||||||
editable: false
|
editable: false
|
||||||
|
|
|
@ -29,6 +29,8 @@ module.exports = class LevelEditView extends RootView
|
||||||
'click #commit-level-start-button': 'startCommittingLevel'
|
'click #commit-level-start-button': 'startCommittingLevel'
|
||||||
'click #fork-level-start-button': 'startForkingLevel'
|
'click #fork-level-start-button': 'startForkingLevel'
|
||||||
'click #level-history-button': 'showVersionHistory'
|
'click #level-history-button': 'showVersionHistory'
|
||||||
|
'click #undo-button': 'onUndo'
|
||||||
|
'click #redo-button': 'onRedo'
|
||||||
'click #patches-tab': -> @patchesView.load()
|
'click #patches-tab': -> @patchesView.load()
|
||||||
'click #components-tab': -> @componentsTab.refreshLevelThangsTreema @level.get('thangs')
|
'click #components-tab': -> @componentsTab.refreshLevelThangsTreema @level.get('thangs')
|
||||||
'click #level-patch-button': 'startPatchingLevel'
|
'click #level-patch-button': 'startPatchingLevel'
|
||||||
|
@ -40,6 +42,7 @@ module.exports = class LevelEditView extends RootView
|
||||||
super options
|
super options
|
||||||
@supermodel.shouldSaveBackups = (model) ->
|
@supermodel.shouldSaveBackups = (model) ->
|
||||||
model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem', 'ThangType']
|
model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem', 'ThangType']
|
||||||
|
@subViews = {}
|
||||||
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, headless: true, editorMode: true
|
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, headless: true, editorMode: true
|
||||||
@level = @levelLoader.level
|
@level = @levelLoader.level
|
||||||
@files = new DocumentFiles(@levelLoader.level)
|
@files = new DocumentFiles(@levelLoader.level)
|
||||||
|
@ -66,11 +69,11 @@ module.exports = class LevelEditView extends RootView
|
||||||
return unless @supermodel.finished()
|
return unless @supermodel.finished()
|
||||||
@$el.find('a[data-toggle="tab"]').on 'shown.bs.tab', (e) =>
|
@$el.find('a[data-toggle="tab"]').on 'shown.bs.tab', (e) =>
|
||||||
Backbone.Mediator.publish 'level:view-switched', e
|
Backbone.Mediator.publish 'level:view-switched', e
|
||||||
@thangsTab = @insertSubView new ThangsTabView world: @world, supermodel: @supermodel, level: @level
|
@subViews['thangsTab'] = @insertSubView new ThangsTabView world: @world, supermodel: @supermodel, level: @level
|
||||||
@settingsTab = @insertSubView new SettingsTabView supermodel: @supermodel
|
@subViews['settingsTab'] = @insertSubView new SettingsTabView supermodel: @supermodel
|
||||||
@scriptsTab = @insertSubView new ScriptsTabView world: @world, supermodel: @supermodel, files: @files
|
@subViews['scriptsTab'] = @insertSubView new ScriptsTabView world: @world, supermodel: @supermodel, files: @files
|
||||||
@componentsTab = @insertSubView new ComponentsTabView supermodel: @supermodel
|
@subViews['componentsTab'] = @insertSubView new ComponentsTabView supermodel: @supermodel
|
||||||
@systemsTab = @insertSubView new SystemsTabView supermodel: @supermodel
|
@subViews['systemsTab'] = @insertSubView new SystemsTabView supermodel: @supermodel
|
||||||
Backbone.Mediator.publish 'level-loaded', level: @level
|
Backbone.Mediator.publish 'level-loaded', level: @level
|
||||||
@showReadOnly() if me.get('anonymous')
|
@showReadOnly() if me.get('anonymous')
|
||||||
@patchesView = @insertSubView(new PatchesView(@level), @$el.find('.patches-view'))
|
@patchesView = @insertSubView(new PatchesView(@level), @$el.find('.patches-view'))
|
||||||
|
@ -101,6 +104,17 @@ module.exports = class LevelEditView extends RootView
|
||||||
@childWindow.onPlayLevelViewLoaded = (e) => sendLevel() # still a hack
|
@childWindow.onPlayLevelViewLoaded = (e) => sendLevel() # still a hack
|
||||||
@childWindow.focus()
|
@childWindow.focus()
|
||||||
|
|
||||||
|
onUndo: ->
|
||||||
|
@getCurrentView()?.undo()
|
||||||
|
|
||||||
|
onRedo: ->
|
||||||
|
@getCurrentView()?.redo()
|
||||||
|
|
||||||
|
getCurrentView: ->
|
||||||
|
tabText = $('li.active')[0]?.textContent.toLowerCase()
|
||||||
|
currentView = @subViews[tabText + 'Tab' ]
|
||||||
|
currentView
|
||||||
|
|
||||||
startPatchingLevel: (e) ->
|
startPatchingLevel: (e) ->
|
||||||
@openModalView new SaveVersionModal({model: @level})
|
@openModalView new SaveVersionModal({model: @level})
|
||||||
Backbone.Mediator.publish 'level:view-switched', e
|
Backbone.Mediator.publish 'level:view-switched', e
|
||||||
|
|
|
@ -3,31 +3,97 @@ template = require 'templates/editor/level/modal/terrain_randomize'
|
||||||
CocoModel = require 'models/CocoModel'
|
CocoModel = require 'models/CocoModel'
|
||||||
|
|
||||||
clusters = {
|
clusters = {
|
||||||
'rocks': ['Rock 1', 'Rock 2', 'Rock 3', 'Rock 4', 'Rock 5', 'Rock Cluster 1', 'Rock Cluster 2', 'Rock Cluster 3']
|
'rocks': {
|
||||||
'trees': ['Tree 1', 'Tree 2', 'Tree 3', 'Tree 4']
|
'thangs': ['Rock 1', 'Rock 2', 'Rock 3', 'Rock 4', 'Rock 5', 'Rock Cluster 1', 'Rock Cluster 2', 'Rock Cluster 3']
|
||||||
'shrubs': ['Shrub 1', 'Shrub 2', 'Shrub 3']
|
'margin': 1
|
||||||
'houses': ['House 1', 'House 2', 'House 3', 'House 4']
|
}
|
||||||
'animals': ['Cow', 'Horse']
|
'trees': {
|
||||||
'wood': ['Firewood 1', 'Firewood 2', 'Firewood 3', 'Barrel']
|
'thangs': ['Tree 1', 'Tree 2', 'Tree 3', 'Tree 4']
|
||||||
'farm': ['Farm']
|
'margin': 0
|
||||||
|
}
|
||||||
|
'shrubs': {
|
||||||
|
'thangs': ['Shrub 1', 'Shrub 2', 'Shrub 3']
|
||||||
|
'margin': 0
|
||||||
|
}
|
||||||
|
'houses': {
|
||||||
|
'thangs': ['House 1', 'House 2', 'House 3', 'House 4']
|
||||||
|
'margin': 4
|
||||||
|
}
|
||||||
|
'animals': {
|
||||||
|
'thangs': ['Cow', 'Horse']
|
||||||
|
'margin': 1
|
||||||
|
}
|
||||||
|
'wood': {
|
||||||
|
'thangs': ['Firewood 1', 'Firewood 2', 'Firewood 3', 'Barrel']
|
||||||
|
'margin': 1
|
||||||
|
}
|
||||||
|
'farm': {
|
||||||
|
'thangs': ['Farm']
|
||||||
|
'margin': 9
|
||||||
|
}
|
||||||
|
'cave': {
|
||||||
|
'thangs': ['Cave']
|
||||||
|
'margin': 5
|
||||||
|
}
|
||||||
|
'stone': {
|
||||||
|
'thangs': ['Gargoyle', 'Rock Cluster 1', 'Rock Cluster 2', 'Rock Cluster 3']
|
||||||
|
'margin': 1
|
||||||
|
}
|
||||||
|
'doors': {
|
||||||
|
'thangs': ['Dungeon Door']
|
||||||
|
'margin': -1
|
||||||
|
}
|
||||||
|
'grass_floor': {
|
||||||
|
'thangs': ['Grass01', 'Grass02', 'Grass03', 'Grass04', 'Grass05']
|
||||||
|
'margin': -1
|
||||||
|
}
|
||||||
|
'dungeon_wall': {
|
||||||
|
'thangs': ['Dungeon Wall']
|
||||||
|
'margin': -1
|
||||||
|
}
|
||||||
|
'dungeon_floor': {
|
||||||
|
'thangs': ['Dungeon Floor']
|
||||||
|
'margin': -1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
presets = {
|
presets = {
|
||||||
# 'dungeon': {
|
'dungeon': {
|
||||||
# 'type':'dungeon'
|
'type':'dungeon'
|
||||||
# 'borders':['Dungeon Wall']
|
'borders':'dungeon_wall'
|
||||||
# 'floors':['Dungeon Floor']
|
'borderNoise':0
|
||||||
# 'decorations':[]
|
'borderSize':4
|
||||||
# }
|
'floors':'dungeon_floor'
|
||||||
|
'decorations': {
|
||||||
|
'cave': {
|
||||||
|
'num':[1,1]
|
||||||
|
'width': 10
|
||||||
|
'height': 10
|
||||||
|
'clusters': {
|
||||||
|
'cave':[1,1]
|
||||||
|
'stone':[2,4]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'Room': {
|
||||||
|
'num': [1,1]
|
||||||
|
'width': [12, 20]
|
||||||
|
'height': [8, 16]
|
||||||
|
'thickness': [2,2]
|
||||||
|
'cluster': 'dungeon_wall'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
'grassy': {
|
'grassy': {
|
||||||
'type':'grassy'
|
'type':'grassy'
|
||||||
'borders':['Tree 1', 'Tree 2', 'Tree 3']
|
'borders':'trees'
|
||||||
'floors':['Grass01', 'Grass02', 'Grass03', 'Grass04', 'Grass05']
|
'borderNoise':1
|
||||||
|
'borderSize':0
|
||||||
|
'floors':'grass_floor'
|
||||||
'decorations': {
|
'decorations': {
|
||||||
'house': {
|
'house': {
|
||||||
'num':[1,2] #min-max
|
'num':[1,2] #min-max
|
||||||
'width': 20
|
'width': 15
|
||||||
'height': 20
|
'height': 15
|
||||||
'clusters': {
|
'clusters': {
|
||||||
'houses':[1,1]
|
'houses':[1,1]
|
||||||
'trees':[1,2]
|
'trees':[1,2]
|
||||||
|
@ -36,9 +102,9 @@ presets = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'farm': {
|
'farm': {
|
||||||
'num':[1,2] #min-max
|
'num':[1,1] #min-max
|
||||||
'width': 20
|
'width': 25
|
||||||
'height': 20
|
'height': 15
|
||||||
'clusters': {
|
'clusters': {
|
||||||
'farm':[1,1]
|
'farm':[1,1]
|
||||||
'shrubs':[2,3]
|
'shrubs':[2,3]
|
||||||
|
@ -76,8 +142,6 @@ thangSizes = {
|
||||||
module.exports = class TerrainRandomizeModal extends ModalView
|
module.exports = class TerrainRandomizeModal extends ModalView
|
||||||
id: 'terrain-randomize-modal'
|
id: 'terrain-randomize-modal'
|
||||||
template: template
|
template: template
|
||||||
thangs = []
|
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'click .choose-option': 'onRandomize'
|
'click .choose-option': 'onRandomize'
|
||||||
|
|
||||||
|
@ -98,87 +162,194 @@ module.exports = class TerrainRandomizeModal extends ModalView
|
||||||
@hide()
|
@hide()
|
||||||
|
|
||||||
randomizeThangs: (presetName, presetSize) ->
|
randomizeThangs: (presetName, presetSize) ->
|
||||||
|
@falseCount = 0
|
||||||
preset = presets[presetName]
|
preset = presets[presetName]
|
||||||
presetSize = presetSizes[presetSize]
|
presetSize = presetSizes[presetSize]
|
||||||
@thangs = []
|
@thangs = []
|
||||||
|
@rects = []
|
||||||
@randomizeFloor preset, presetSize
|
@randomizeFloor preset, presetSize
|
||||||
@randomizeBorder preset, presetSize
|
@randomizeBorder preset, presetSize, preset.borderNoise
|
||||||
@randomizeDecorations preset, presetSize
|
@randomizeDecorations preset, presetSize
|
||||||
|
|
||||||
randomizeFloor: (preset, presetSize) ->
|
randomizeFloor: (preset, presetSize) ->
|
||||||
for i in _.range(0, presetSize.x, thangSizes.floorSize.x)
|
for i in _.range(0, presetSize.x, thangSizes.floorSize.x)
|
||||||
for j in _.range(0, presetSize.y, thangSizes.floorSize.y)
|
for j in _.range(0, presetSize.y, thangSizes.floorSize.y)
|
||||||
@thangs.push {
|
@thangs.push {
|
||||||
'id': @getRandomThang(preset.floors)
|
'id': @getRandomThang(clusters[preset.floors].thangs)
|
||||||
'pos': {
|
'pos': {
|
||||||
'x': i + thangSizes.floorSize.x/2
|
'x': i + thangSizes.floorSize.x/2
|
||||||
'y': j + thangSizes.floorSize.y/2
|
'y': j + thangSizes.floorSize.y/2
|
||||||
}
|
}
|
||||||
|
'margin': clusters[preset.floors].margin
|
||||||
}
|
}
|
||||||
|
|
||||||
randomizeBorder: (preset, presetSize) ->
|
randomizeBorder: (preset, presetSize, noiseFactor=1) ->
|
||||||
for i in _.range(0, presetSize.x, thangSizes.borderSize.x)
|
for i in _.range(0, presetSize.x, thangSizes.borderSize.x)
|
||||||
for j in _.range(thangSizes.borderSize.thickness)
|
for j in _.range(thangSizes.borderSize.thickness)
|
||||||
@thangs.push {
|
while not @addThang {
|
||||||
'id': @getRandomThang(preset.borders)
|
'id': @getRandomThang(clusters[preset.borders].thangs)
|
||||||
'pos': {
|
'pos': {
|
||||||
'x': i + _.random(-thangSizes.borderSize.x/2, thangSizes.borderSize.x/2)
|
'x': i + preset.borderSize/2 + noiseFactor * _.random(-thangSizes.borderSize.x/2, thangSizes.borderSize.x/2)
|
||||||
'y': 0 + _.random(-thangSizes.borderSize.y/2, thangSizes.borderSize.y)
|
'y': 0 + preset.borderSize/2 + noiseFactor * _.random(-thangSizes.borderSize.y/2, thangSizes.borderSize.y)
|
||||||
}
|
}
|
||||||
|
'margin': clusters[preset.borders].margin
|
||||||
}
|
}
|
||||||
@thangs.push {
|
continue
|
||||||
'id': @getRandomThang(preset.borders)
|
while not @addThang {
|
||||||
|
'id': @getRandomThang(clusters[preset.borders].thangs)
|
||||||
'pos': {
|
'pos': {
|
||||||
'x': i + _.random(-thangSizes.borderSize.x/2, thangSizes.borderSize.x/2)
|
'x': i + preset.borderSize/2 + noiseFactor * _.random(-thangSizes.borderSize.x/2, thangSizes.borderSize.x/2)
|
||||||
'y': presetSize.y + _.random(-thangSizes.borderSize.y, thangSizes.borderSize.y/2)
|
'y': presetSize.y - preset.borderSize/2 + noiseFactor * _.random(-thangSizes.borderSize.y, thangSizes.borderSize.y/2)
|
||||||
}
|
}
|
||||||
|
'margin': clusters[preset.borders].margin
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
|
||||||
for i in _.range(0, presetSize.y, thangSizes.borderSize.y)
|
for i in _.range(0, presetSize.y, thangSizes.borderSize.y)
|
||||||
for j in _.range(3)
|
for j in _.range(3)
|
||||||
@thangs.push {
|
while not @addThang {
|
||||||
'id': @getRandomThang(preset.borders)
|
'id': @getRandomThang(clusters[preset.borders].thangs)
|
||||||
'pos': {
|
'pos': {
|
||||||
'x': 0 + _.random(-thangSizes.borderSize.x/2, thangSizes.borderSize.x)
|
'x': 0 + preset.borderSize/2 + noiseFactor * _.random(-thangSizes.borderSize.x/2, thangSizes.borderSize.x)
|
||||||
'y': i + _.random(-thangSizes.borderSize.y/2, thangSizes.borderSize.y/2)
|
'y': i + preset.borderSize/2 + noiseFactor * _.random(-thangSizes.borderSize.y/2, thangSizes.borderSize.y/2)
|
||||||
}
|
}
|
||||||
|
'margin': clusters[preset.borders].margin
|
||||||
}
|
}
|
||||||
@thangs.push {
|
continue
|
||||||
'id': @getRandomThang(preset.borders)
|
while not @addThang {
|
||||||
|
'id': @getRandomThang(clusters[preset.borders].thangs)
|
||||||
'pos': {
|
'pos': {
|
||||||
'x': presetSize.x + _.random(-thangSizes.borderSize.x, thangSizes.borderSize.x/2)
|
'x': presetSize.x - preset.borderSize/2 + noiseFactor * _.random(-thangSizes.borderSize.x, thangSizes.borderSize.x/2)
|
||||||
'y': i + _.random(-thangSizes.borderSize.y/2, thangSizes.borderSize.y/2)
|
'y': i + preset.borderSize/2 + noiseFactor * _.random(-thangSizes.borderSize.y/2, thangSizes.borderSize.y/2)
|
||||||
}
|
}
|
||||||
|
'margin': clusters[preset.borders].margin
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
|
||||||
randomizeDecorations: (preset, presetSize)->
|
randomizeDecorations: (preset, presetSize)->
|
||||||
|
if presetSize is presetSizes['small'] then sizeFactor = 1 else sizeFactor = 2
|
||||||
for name, decoration of preset.decorations
|
for name, decoration of preset.decorations
|
||||||
for num in _.range(_.random(decoration.num[0], decoration.num[1]))
|
for num in _.range(sizeFactor * _.random(decoration.num[0], decoration.num[1]))
|
||||||
center =
|
if @['build'+name] isnt undefined
|
||||||
{
|
@['build'+name](preset, presetSize, decoration)
|
||||||
'x':_.random(decoration.width, presetSize.x - decoration.width),
|
continue
|
||||||
'y':_.random(decoration.height, presetSize.y - decoration.height)
|
while true
|
||||||
}
|
rect = {
|
||||||
min =
|
'x':_.random(decoration.width/2 + preset.borderSize/2 + thangSizes.borderSize.x, presetSize.x - decoration.width/2 - preset.borderSize/2 - thangSizes.borderSize.x),
|
||||||
{
|
'y':_.random(decoration.height/2 + preset.borderSize/2 + thangSizes.borderSize.y, presetSize.y - decoration.height/2 - preset.borderSize/2 - thangSizes.borderSize.y)
|
||||||
'x':center.x - decoration.width/2
|
'width':decoration.width
|
||||||
'y':center.y - decoration.height/2
|
'height':decoration.height
|
||||||
}
|
}
|
||||||
max =
|
break if @addRect rect
|
||||||
{
|
|
||||||
'x':center.x + decoration.width/2
|
|
||||||
'y':center.y + decoration.height/2
|
|
||||||
}
|
|
||||||
for cluster, range of decoration.clusters
|
for cluster, range of decoration.clusters
|
||||||
for i in _.range(_.random(range[0], range[1]))
|
for i in _.range(_.random(range[0], range[1]))
|
||||||
@thangs.push {
|
while not @addThang {
|
||||||
'id':@getRandomThang(clusters[cluster])
|
'id':@getRandomThang(clusters[cluster].thangs)
|
||||||
'pos':{
|
'pos':{
|
||||||
'x':_.random(min.x, max.x)
|
'x':_.random(rect.x - rect.width/2, rect.x + rect.width/2)
|
||||||
'y':_.random(min.y, max.y)
|
'y':_.random(rect.y - rect.height/2, rect.y + rect.height/2)
|
||||||
}
|
}
|
||||||
|
'margin':clusters[cluster].margin
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
|
||||||
|
buildRoom: (preset, presetSize, room) ->
|
||||||
|
if presetSize is presetSizes['small'] then sizeFactor = 1 else sizeFactor = 2
|
||||||
|
while true
|
||||||
|
rect = {
|
||||||
|
'width':sizeFactor * (room.width[0] + preset.borderSize * _.random(0, (room.width[1] - room.width[0])/preset.borderSize))
|
||||||
|
'height':sizeFactor * (room.height[0] + preset.borderSize * _.random(0, (room.height[1] - room.height[0])/preset.borderSize))
|
||||||
|
}
|
||||||
|
roomThickness = _.random(room.thickness[0], room.thickness[1])
|
||||||
|
rect.x = _.random(rect.width/2 + preset.borderSize * (roomThickness+1), presetSize.x - rect.width/2 - preset.borderSize * (roomThickness+1))
|
||||||
|
rect.y = _.random(rect.height/2 + preset.borderSize * (roomThickness+1), presetSize.y - rect.height/2 - preset.borderSize * (roomThickness+1))
|
||||||
|
break if @addRect {
|
||||||
|
'x': rect.x
|
||||||
|
'y': rect.y
|
||||||
|
'width': rect.width + 2 * roomThickness * preset.borderSize
|
||||||
|
'height': rect.height + 2 * roomThickness * preset.borderSize
|
||||||
|
}
|
||||||
|
|
||||||
|
xRange = _.range(rect.x - rect.width/2 + preset.borderSize, rect.x + rect.width/2, preset.borderSize)
|
||||||
|
topDoor = _.random(1) > 0.5
|
||||||
|
topDoorX = xRange[_.random(0, xRange.length-1)]
|
||||||
|
bottomDoor = if not topDoor then true else _.random(1) > 0.5
|
||||||
|
bottomDoorX = xRange[_.random(0, xRange.length-1)]
|
||||||
|
|
||||||
|
for t in _.range(0, roomThickness+1)
|
||||||
|
for i in _.range(rect.x - rect.width/2 - (t-1) * preset.borderSize, rect.x + rect.width/2 + t * preset.borderSize, preset.borderSize)
|
||||||
|
thang = {
|
||||||
|
'id': @getRandomThang(clusters[room.cluster].thangs)
|
||||||
|
'pos': {
|
||||||
|
'x': i
|
||||||
|
'y': rect.y - rect.height/2 - t * preset.borderSize
|
||||||
|
}
|
||||||
|
'margin': clusters[room.cluster].margin
|
||||||
|
}
|
||||||
|
if i is bottomDoorX and bottomDoor
|
||||||
|
thang.id = @getRandomThang(clusters['doors'].thangs)
|
||||||
|
thang.pos.y -= preset.borderSize/3
|
||||||
|
@addThang thang unless i is bottomDoorX and t isnt roomThickness and bottomDoor
|
||||||
|
|
||||||
|
thang = {
|
||||||
|
'id': @getRandomThang(clusters[room.cluster].thangs)
|
||||||
|
'pos': {
|
||||||
|
'x': i
|
||||||
|
'y': rect.y + rect.height/2 + t * preset.borderSize
|
||||||
|
}
|
||||||
|
'margin': clusters[room.cluster].margin
|
||||||
|
}
|
||||||
|
if i is topDoorX and topDoor
|
||||||
|
thang.id = @getRandomThang(clusters['doors'].thangs)
|
||||||
|
thang.pos.y -= preset.borderSize
|
||||||
|
@addThang thang unless i is topDoorX and t isnt roomThickness and topDoor
|
||||||
|
|
||||||
|
for t in _.range(0, roomThickness)
|
||||||
|
for i in _.range(rect.y - rect.height/2 - t * preset.borderSize, rect.y + rect.height/2 + (t+1) * preset.borderSize, preset.borderSize)
|
||||||
|
@addThang {
|
||||||
|
'id': @getRandomThang(clusters[room.cluster].thangs)
|
||||||
|
'pos': {
|
||||||
|
'x': rect.x - rect.width/2 - t * preset.borderSize
|
||||||
|
'y': i
|
||||||
|
}
|
||||||
|
'margin': clusters[room.cluster].margin
|
||||||
|
}
|
||||||
|
|
||||||
|
@addThang {
|
||||||
|
'id': @getRandomThang(clusters[room.cluster].thangs)
|
||||||
|
'pos': {
|
||||||
|
'x': rect.x + rect.width/2 + t * preset.borderSize
|
||||||
|
'y': i
|
||||||
|
}
|
||||||
|
'margin': clusters[room.cluster].margin
|
||||||
|
}
|
||||||
|
|
||||||
|
addThang: (thang) ->
|
||||||
|
if @falseCount > 100
|
||||||
|
console.log 'infinite loop', thang
|
||||||
|
@falseCount = 0
|
||||||
|
return true
|
||||||
|
for existingThang in @thangs
|
||||||
|
if existingThang.margin is -1 or thang.margin is -1
|
||||||
|
continue
|
||||||
|
if Math.abs(existingThang.pos.x - thang.pos.x) <= thang.margin + existingThang.margin and Math.abs(existingThang.pos.y - thang.pos.y) <= thang.margin + existingThang.margin
|
||||||
|
@falseCount++
|
||||||
|
return false
|
||||||
|
@thangs.push thang
|
||||||
|
true
|
||||||
|
|
||||||
|
addRect: (rect) ->
|
||||||
|
if @falseCount > 100
|
||||||
|
console.log 'infinite loop', rect
|
||||||
|
@falseCount = 0
|
||||||
|
return true
|
||||||
|
for existingRect in @rects
|
||||||
|
if Math.abs(existingRect.x - rect.x) <= rect.width/2 + existingRect.width/2 and Math.abs(existingRect.y - rect.y) <= rect.height/2 + existingRect.height/2
|
||||||
|
@falseCount++
|
||||||
|
return false
|
||||||
|
@rects.push rect
|
||||||
|
true
|
||||||
|
|
||||||
getRandomThang: (thangList) ->
|
getRandomThang: (thangList) ->
|
||||||
return thangList[_.random(0, thangList.length-1)]
|
return thangList[_.random(0, thangList.length-1)]
|
||||||
|
|
|
@ -86,6 +86,12 @@ module.exports = class ScriptsTabView extends CocoView
|
||||||
onScriptChanged: =>
|
onScriptChanged: =>
|
||||||
@scriptsTreema.set(@selectedScriptPath, @scriptTreema.data)
|
@scriptsTreema.set(@selectedScriptPath, @scriptTreema.data)
|
||||||
|
|
||||||
|
undo: ->
|
||||||
|
@scriptsTreema.undo() if @scriptTreema.undo() is undefined
|
||||||
|
|
||||||
|
redo: ->
|
||||||
|
@scriptsTreema.redo() if @scriptTreema.redo() is undefined
|
||||||
|
|
||||||
class ScriptNode extends TreemaObjectNode
|
class ScriptNode extends TreemaObjectNode
|
||||||
valueClass: 'treema-script'
|
valueClass: 'treema-script'
|
||||||
collection: false
|
collection: false
|
||||||
|
|
|
@ -53,3 +53,9 @@ module.exports = class SettingsTabView extends CocoView
|
||||||
for key in @editableSettings
|
for key in @editableSettings
|
||||||
continue if @settingsTreema.data[key] is undefined
|
continue if @settingsTreema.data[key] is undefined
|
||||||
@level.set key, @settingsTreema.data[key]
|
@level.set key, @settingsTreema.data[key]
|
||||||
|
|
||||||
|
undo: ->
|
||||||
|
@settingsTreema.undo()
|
||||||
|
|
||||||
|
redo: ->
|
||||||
|
@settingsTreema.redo()
|
||||||
|
|
|
@ -115,6 +115,18 @@ module.exports = class LevelSystemEditView extends CocoView
|
||||||
@levelSystem.watch(button.find('.watch').is(':visible'))
|
@levelSystem.watch(button.find('.watch').is(':visible'))
|
||||||
button.find('> span').toggleClass('secret')
|
button.find('> span').toggleClass('secret')
|
||||||
|
|
||||||
|
undo: ->
|
||||||
|
if @$el.find('li.active > a#system-config-schema-tab')
|
||||||
|
@configSchemaTreema.undo()
|
||||||
|
if @$el.find('li.active > a#system-settings-tab')
|
||||||
|
@systemSettingsTreema.undo()
|
||||||
|
|
||||||
|
redo: ->
|
||||||
|
if @$el.find('li.active > a#system-config-schema-tab')
|
||||||
|
@configSchemaTreema.redo()
|
||||||
|
if @$el.find('li.active > a#system-settings-tab')
|
||||||
|
@systemSettingsTreema.redo()
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
@editor?.destroy()
|
@editor?.destroy()
|
||||||
super()
|
super()
|
||||||
|
|
|
@ -125,6 +125,13 @@ module.exports = class SystemsTabView extends CocoView
|
||||||
{original: '528114e60268d018e300001a', majorVersion: 0} # UI
|
{original: '528114e60268d018e300001a', majorVersion: 0} # UI
|
||||||
{original: '528114040268d018e3000011', majorVersion: 0} # Physics
|
{original: '528114040268d018e3000011', majorVersion: 0} # Physics
|
||||||
]
|
]
|
||||||
|
undo: ->
|
||||||
|
return unless @levelSystemEditView
|
||||||
|
@levelSystemEditView.undo()
|
||||||
|
|
||||||
|
redo: ->
|
||||||
|
return unless @levelSystemEditView
|
||||||
|
@levelSystemEditView.redo()
|
||||||
|
|
||||||
class LevelSystemNode extends TreemaObjectNode
|
class LevelSystemNode extends TreemaObjectNode
|
||||||
valueClass: 'treema-level-system'
|
valueClass: 'treema-level-system'
|
||||||
|
|
|
@ -92,3 +92,11 @@ module.exports = class LevelThangEditView extends CocoView
|
||||||
onComponentsChanged: (components) =>
|
onComponentsChanged: (components) =>
|
||||||
@thangData.components = components
|
@thangData.components = components
|
||||||
@saveThang()
|
@saveThang()
|
||||||
|
|
||||||
|
undo: ->
|
||||||
|
return unless @thangComponentEditView
|
||||||
|
@thangComponentEditView.undo()
|
||||||
|
|
||||||
|
redo: ->
|
||||||
|
return unless @thangComponentEditView
|
||||||
|
@thangComponentEditView.redo()
|
||||||
|
|
|
@ -58,8 +58,8 @@ module.exports = class ThangsTabView extends CocoView
|
||||||
'delete, del, backspace': 'deleteSelectedExtantThang'
|
'delete, del, backspace': 'deleteSelectedExtantThang'
|
||||||
'left': -> @moveAddThangSelection -1
|
'left': -> @moveAddThangSelection -1
|
||||||
'right': -> @moveAddThangSelection 1
|
'right': -> @moveAddThangSelection 1
|
||||||
'ctrl+z': 'undoAction'
|
'ctrl+z': 'undo'
|
||||||
'ctrl+shift+z': 'redoAction'
|
'ctrl+shift+z': 'redo'
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super options
|
super options
|
||||||
|
@ -116,6 +116,8 @@ module.exports = class ThangsTabView extends CocoView
|
||||||
$(window).resize @onWindowResize
|
$(window).resize @onWindowResize
|
||||||
@addThangsView = @insertSubView new AddThangsView world: @world, supermodel: @supermodel
|
@addThangsView = @insertSubView new AddThangsView world: @world, supermodel: @supermodel
|
||||||
@buildInterface() # refactor to not have this trigger when this view re-renders?
|
@buildInterface() # refactor to not have this trigger when this view re-renders?
|
||||||
|
if @thangsTreema.data.length
|
||||||
|
@$el.find('#canvas-overlay').css('display', 'none')
|
||||||
|
|
||||||
onFilterExtantThangs: (e) ->
|
onFilterExtantThangs: (e) ->
|
||||||
@$el.find('#extant-thangs-filter button.active').button('toggle')
|
@$el.find('#extant-thangs-filter button.active').button('toggle')
|
||||||
|
@ -233,6 +235,8 @@ module.exports = class ThangsTabView extends CocoView
|
||||||
@addThang @addThangType, thang.pos, true
|
@addThang @addThangType, thang.pos, true
|
||||||
@batchInsert()
|
@batchInsert()
|
||||||
@selectAddThangType null
|
@selectAddThangType null
|
||||||
|
@$el.find('#canvas-overlay').css('display', 'none')
|
||||||
|
|
||||||
|
|
||||||
# TODO: figure out a good way to have all Surface clicks and Treema clicks just proxy in one direction, so we can maintain only one way of handling selection and deletion
|
# TODO: figure out a good way to have all Surface clicks and Treema clicks just proxy in one direction, so we can maintain only one way of handling selection and deletion
|
||||||
onExtantThangSelected: (e) ->
|
onExtantThangSelected: (e) ->
|
||||||
|
@ -473,11 +477,11 @@ module.exports = class ThangsTabView extends CocoView
|
||||||
$('#add-thangs-column').toggle()
|
$('#add-thangs-column').toggle()
|
||||||
@onWindowResize e
|
@onWindowResize e
|
||||||
|
|
||||||
undoAction: (e) ->
|
undo: (e) ->
|
||||||
@thangsTreema.undo()
|
if not @editThangView then @thangsTreema.undo() else @editThangView.undo()
|
||||||
|
|
||||||
redoAction: (e) ->
|
redo: (e) ->
|
||||||
@thangsTreema.redo()
|
if not @editThangView then @thangsTreema.redo() else @editThangView.redo()
|
||||||
|
|
||||||
class ThangsNode extends TreemaNode.nodeMap.array
|
class ThangsNode extends TreemaNode.nodeMap.array
|
||||||
valueClass: 'treema-array-replacement'
|
valueClass: 'treema-array-replacement'
|
||||||
|
|
Loading…
Reference in a new issue