mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-28 10:06:08 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
318b499e3e
11 changed files with 146 additions and 74 deletions
|
@ -39,7 +39,12 @@ module.exports = class Angel extends CocoClass
|
|||
|
||||
# say: debugging stuff, usually off; log: important performance indicators, keep on
|
||||
say: (args...) -> #@log args...
|
||||
log: (args...) -> console.info "|#{@shared.godNick}'s #{@nick}|", args...
|
||||
log: ->
|
||||
# console.info.apply is undefined in IE9, CofeeScript splats invocation won't work.
|
||||
# http://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function
|
||||
message = "|#{@shared.godNick}'s #{@nick}|"
|
||||
message += " #{arg}" for arg in arguments
|
||||
console.info message
|
||||
|
||||
testWorker: =>
|
||||
return if @destroyed
|
||||
|
@ -238,7 +243,13 @@ module.exports = class Angel extends CocoClass
|
|||
console?.profile? "World Generation #{(Math.random() * 1000).toFixed(0)}" if imitateIE9?
|
||||
work.t0 = now()
|
||||
work.testWorld = testWorld = new World work.userCodeMap
|
||||
work.testWorld.levelSessionIDs = work.levelSessionIDs
|
||||
work.testWorld.submissionCount = work.submissionCount
|
||||
work.testWorld.flagHistory = work.flagHistory ? []
|
||||
testWorld.loadFromLevel work.level
|
||||
work.testWorld.preloading = work.preload
|
||||
work.testWorld.headless = work.headless
|
||||
work.testWorld.realTime = work.realTime
|
||||
if @shared.goalManager
|
||||
testGM = new GoalManager(testWorld)
|
||||
testGM.setGoals work.goals
|
||||
|
@ -254,7 +265,7 @@ module.exports = class Angel extends CocoClass
|
|||
work.testWorld.goalManager.worldGenerationEnded() if work.testWorld.ended
|
||||
serialized = testWorld.serialize()
|
||||
window.BOX2D_ENABLED = false
|
||||
World.deserialize serialized.serializedWorld, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates), serialized.startFrame, work.level, serialized.endFrame
|
||||
World.deserialize serialized.serializedWorld, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates), serialized.startFrame, serialized.endFrame, work.level
|
||||
window.BOX2D_ENABLED = true
|
||||
@shared.lastSerializedWorldFrames = serialized.serializedWorld.frames
|
||||
|
||||
|
|
|
@ -51,3 +51,4 @@ functionParameters =
|
|||
initializeCentroids: []
|
||||
update: []
|
||||
getNearestEnemy: []
|
||||
die: []
|
||||
|
|
|
@ -49,11 +49,15 @@
|
|||
body:not(.dialogue-view-active)
|
||||
.spell-palette-popover.popover
|
||||
right: 45%
|
||||
min-width: 350px
|
||||
min-width: 500px
|
||||
|
||||
.spell-palette-popover.popover
|
||||
// Only those popovers which are our direct children (spell documentation)
|
||||
max-width: 600px
|
||||
padding: 0
|
||||
border-image: url(/images/level/popover_background.png) 29 39 fill stretch
|
||||
border-width: 15px 20px
|
||||
@include box-shadow(0 0 0 #000)
|
||||
|
||||
// Jiggle animation
|
||||
// TODO: consolidate with problem_alert.sass jiggle
|
||||
|
@ -98,13 +102,8 @@ body:not(.dialogue-view-active)
|
|||
&:hover
|
||||
@include opacity(1)
|
||||
|
||||
padding: 0
|
||||
border-image: url(/images/level/popover_background.png) 29 39 fill stretch
|
||||
border-width: 15px 20px
|
||||
@include box-shadow(0 0 0 #000)
|
||||
|
||||
h1:not(.not-code), h2:not(.not-code), h3:not(.not-code), h4:not(.not-code), h5:not(.not-code), h6:not(.not-code)
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace
|
||||
font-family: Monaco, Menlo, Ubuntu Mono, Consolas, "source-code-pro", monospace !important
|
||||
font-variant: normal
|
||||
|
||||
.popover-title
|
||||
|
@ -129,6 +128,24 @@ body:not(.dialogue-view-active)
|
|||
&.right .arrow
|
||||
left: -3%
|
||||
|
||||
.docs-ace-container
|
||||
padding: 2px 4px
|
||||
border-radius: 4px
|
||||
|
||||
&, .docs-ace
|
||||
background-color: #f9f2f4
|
||||
font-size: 12px
|
||||
font-family: Monaco, Menlo, Ubuntu Mono, Consolas, "source-code-pro", monospace !important
|
||||
|
||||
.docs-ace
|
||||
.ace_cursor, .ace_bracket
|
||||
display: none
|
||||
|
||||
code
|
||||
color: black
|
||||
font-family: Monaco, Menlo, Ubuntu Mono, Consolas, "source-code-pro", monospace !important
|
||||
font-size: 12px
|
||||
|
||||
html.no-borderimage
|
||||
.spell-palette-popover.popover
|
||||
background: transparent url(/images/level/popover_background.png)
|
||||
|
|
|
@ -62,25 +62,28 @@ if !selectedMethod
|
|||
strong
|
||||
span(data-i18n="skill_docs.example") Example
|
||||
| :
|
||||
div!= marked("```\n" + doc.example + "```")
|
||||
.docs-ace-container
|
||||
.docs-ace= doc.example
|
||||
else if doc.type == 'function' && argumentExamples.length
|
||||
p.example
|
||||
strong
|
||||
span(data-i18n="skill_docs.example") Example
|
||||
| :
|
||||
div
|
||||
if language == 'javascript'
|
||||
code= doc.owner + '.' + doc.name + '(' + argumentExamples.join(', ') + ');'
|
||||
else if language == 'coffeescript'
|
||||
code= doc.ownerName + (doc.ownerName == '@' ? '' : '.') + doc.name + ' ' + argumentExamples.join(', ')
|
||||
else if language == 'python'
|
||||
code= doc.ownerName + '.' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||
else if language == 'clojure'
|
||||
code= '(.' + doc.name + ' ' + doc.ownerName + ' ' + argumentExamples.join(', ') + ')'
|
||||
else if language == 'lua'
|
||||
code= doc.ownerName + ':' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||
else if language == 'io'
|
||||
code= (doc.ownerName == 'this' ? '' : doc.ownerName + ' ') + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||
.docs-ace-container
|
||||
.docs-ace
|
||||
if language == 'javascript'
|
||||
span= doc.owner + '.' + doc.name + '(' + argumentExamples.join(', ') + ');'
|
||||
else if language == 'coffeescript'
|
||||
span= doc.ownerName + (doc.ownerName == '@' ? '' : '.') + doc.name + ' ' + argumentExamples.join(', ')
|
||||
else if language == 'python'
|
||||
span= doc.ownerName + '.' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||
else if language == 'clojure'
|
||||
span= '(.' + doc.name + ' ' + doc.ownerName + ' ' + argumentExamples.join(', ') + ')'
|
||||
else if language == 'lua'
|
||||
span= doc.ownerName + ':' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||
else if language == 'io'
|
||||
span= (doc.ownerName == 'this' ? '' : doc.ownerName + ' ') + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||
|
||||
if (doc.type != 'function' && doc.type != 'snippet') || doc.name == 'now'
|
||||
p.value
|
||||
|
|
|
@ -15,6 +15,10 @@ clusters = {
|
|||
'thangs': ['Tree 1', 'Tree 2', 'Tree 3', 'Tree 4']
|
||||
'margin': 0.5
|
||||
}
|
||||
'tree_stands': {
|
||||
'thangs': ['Tree Stand 1', 'Tree Stand 2', 'Tree Stand 3', 'Tree Stand 4', 'Tree Stand 5', 'Tree Stand 6']
|
||||
'margin': 3
|
||||
}
|
||||
'shrubs': {
|
||||
'thangs': ['Shrub 1', 'Shrub 2', 'Shrub 3']
|
||||
'margin': 0.5
|
||||
|
@ -165,10 +169,10 @@ presets = {
|
|||
'grassy': {
|
||||
'terrainName': 'Grass'
|
||||
'type':'grassy'
|
||||
'borders':'trees'
|
||||
'borders':'tree_stands'
|
||||
'borderNoise':1
|
||||
'borderSize':0
|
||||
'borderThickness':3
|
||||
'borderSize':2
|
||||
'borderThickness':2
|
||||
'floors':'grass_floor'
|
||||
'decorations': {
|
||||
'hero': {
|
||||
|
|
|
@ -728,7 +728,6 @@ forest = [
|
|||
description: 'Join forces with a new hero: Amara Arrowhead.'
|
||||
nextLevels:
|
||||
continue: 'swift-dagger'
|
||||
disabled: not me.isAdmin()
|
||||
x: 64.37
|
||||
y: 69.18
|
||||
}
|
||||
|
@ -740,7 +739,6 @@ forest = [
|
|||
description: 'Deal damage from a distance with your new hero.'
|
||||
nextLevels:
|
||||
continue: 'shrapnel'
|
||||
disabled: not me.isAdmin()
|
||||
x: 66
|
||||
y: 75.61
|
||||
}
|
||||
|
@ -752,7 +750,6 @@ forest = [
|
|||
description: 'Explore the explosive arts.'
|
||||
nextLevels:
|
||||
continue: 'coinucopia'
|
||||
disabled: not me.isAdmin()
|
||||
x: 67
|
||||
y: 81
|
||||
}
|
||||
|
@ -766,7 +763,6 @@ forest = [
|
|||
description: 'Stand your ground against large ogres with a new hero: Ms. Hushbaum.'
|
||||
nextLevels:
|
||||
continue: 'touch-of-death'
|
||||
disabled: not me.isAdmin()
|
||||
x: 64.37
|
||||
y: 55.18
|
||||
}
|
||||
|
@ -778,7 +774,6 @@ forest = [
|
|||
description: 'Learn your first spell to siphon life from your foes.'
|
||||
nextLevels:
|
||||
continue: 'bonemender'
|
||||
disabled: not me.isAdmin()
|
||||
x: 65
|
||||
y: 48
|
||||
}
|
||||
|
@ -790,7 +785,6 @@ forest = [
|
|||
description: 'Cast regeneration on allied soldiers to withstand a siege.'
|
||||
nextLevels:
|
||||
continue: 'coinucopia'
|
||||
disabled: not me.isAdmin()
|
||||
x: 66
|
||||
y: 40
|
||||
}
|
||||
|
|
|
@ -64,37 +64,24 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
thangType.project = ['original', 'rasterIcon', 'name', 'soundTriggers']
|
||||
@thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model
|
||||
|
||||
if achievementIDs.length
|
||||
url = "/db/earned_achievement?view=get-by-achievement-ids&achievementIDs=#{achievementIDs.join(',')}"
|
||||
earnedAchievements = new CocoCollection([], {
|
||||
url: url
|
||||
model: EarnedAchievement
|
||||
@newEarnedAchievements = []
|
||||
for achievement in @achievements.models
|
||||
continue unless achievement.completed
|
||||
ea = new EarnedAchievement({
|
||||
collection: achievement.get('collection')
|
||||
triggeredBy: @session.id
|
||||
achievement: achievement.id
|
||||
})
|
||||
earnedAchievements.sizeShouldBe = achievementIDs.length
|
||||
res = @supermodel.loadCollection(earnedAchievements, 'earned_achievements')
|
||||
@earnedAchievements = res.model
|
||||
@listenToOnce @earnedAchievements, 'sync', ->
|
||||
@newEarnedAchievements = []
|
||||
recorded = (earned.get('achievement') for earned in @earnedAchievements.length)
|
||||
for achievement in @achievements.models
|
||||
continue unless achievement.completed
|
||||
earnedObjects = []
|
||||
if achievement.id not in recorded
|
||||
ea = new EarnedAchievement({
|
||||
collection: achievement.get('collection')
|
||||
triggeredBy: @session.id
|
||||
achievement: achievement.id
|
||||
})
|
||||
ea.save()
|
||||
@newEarnedAchievements.push ea
|
||||
@listenToOnce ea, 'sync', ->
|
||||
if _.all((ea.id for ea in @newEarnedAchievements))
|
||||
@listenToOnce me, 'sync', ->
|
||||
@readyToContinue = true
|
||||
@updateSavingProgressStatus()
|
||||
me.fetch() unless me.loading
|
||||
else
|
||||
@readyToContinue = true
|
||||
ea.save()
|
||||
@newEarnedAchievements.push ea
|
||||
@listenToOnce ea, 'sync', ->
|
||||
if _.all((ea.id for ea in @newEarnedAchievements))
|
||||
@listenToOnce me, 'sync', ->
|
||||
@readyToContinue = true
|
||||
@updateSavingProgressStatus()
|
||||
me.fetch() unless me.loading
|
||||
|
||||
@readyToContinue = true if not @achievements.models.length
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
|
|
|
@ -3,6 +3,7 @@ template = require 'templates/play/level/tome/spell_palette_entry'
|
|||
{me} = require 'lib/auth'
|
||||
filters = require 'lib/image_filter'
|
||||
DocFormatter = require './DocFormatter'
|
||||
SpellView = require 'views/play/level/tome/SpellView'
|
||||
|
||||
module.exports = class SpellPaletteEntryView extends CocoView
|
||||
tagName: 'div' # Could also try <code> instead of <div>, but would need to adjust colors
|
||||
|
@ -28,6 +29,7 @@ module.exports = class SpellPaletteEntryView extends CocoView
|
|||
@docFormatter = new DocFormatter options
|
||||
@doc = @docFormatter.doc
|
||||
@doc.initialHTML = @docFormatter.formatPopover()
|
||||
@aceEditors = []
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
|
@ -52,6 +54,31 @@ module.exports = class SpellPaletteEntryView extends CocoView
|
|||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: "spell-palette-entry-open-#{soundIndex}", volume: 0.75
|
||||
popover = @$el.data('bs.popover')
|
||||
popover?.$tip?.i18n()
|
||||
codeLanguage = @options.language
|
||||
oldEditor.destroy() for oldEditor in @aceEditors
|
||||
@aceEditors = []
|
||||
aceEditors = @aceEditors
|
||||
popover?.$tip?.find('.docs-ace').each ->
|
||||
contents = $(@).text()
|
||||
editor = ace.edit @
|
||||
editor.setOptions maxLines: Infinity
|
||||
editor.setReadOnly true
|
||||
editor.setTheme 'ace/theme/textmate'
|
||||
editor.setShowPrintMargin false
|
||||
editor.setShowFoldWidgets false
|
||||
editor.setHighlightActiveLine false
|
||||
editor.setHighlightActiveLine false
|
||||
editor.setBehavioursEnabled false
|
||||
editor.renderer.setShowGutter false
|
||||
editor.setValue contents
|
||||
editor.clearSelection()
|
||||
session = editor.getSession()
|
||||
session.setUseWorker false
|
||||
session.setMode SpellView.editModes[codeLanguage]
|
||||
session.setWrapLimitRange null
|
||||
session.setUseWrapMode true
|
||||
session.setNewLineMode 'unix'
|
||||
aceEditors.push editor
|
||||
|
||||
onMouseEnter: (e) ->
|
||||
# Make sure the doc has the updated Thang so it can regenerate its prop value
|
||||
|
@ -121,4 +148,5 @@ module.exports = class SpellPaletteEntryView extends CocoView
|
|||
@togglePinned() if @popoverPinned
|
||||
@$el.popover 'destroy'
|
||||
@$el.off()
|
||||
oldEditor.destroy() for oldEditor in @aceEditors
|
||||
super()
|
||||
|
|
|
@ -20,7 +20,7 @@ module.exports = class SpellView extends CocoView
|
|||
eventsSuppressed: true
|
||||
writable: true
|
||||
|
||||
editModes:
|
||||
@editModes:
|
||||
'javascript': 'ace/mode/javascript'
|
||||
'coffeescript': 'ace/mode/coffee'
|
||||
'python': 'ace/mode/python'
|
||||
|
@ -91,7 +91,7 @@ module.exports = class SpellView extends CocoView
|
|||
@aceSession = @ace.getSession()
|
||||
@aceDoc = @aceSession.getDocument()
|
||||
@aceSession.setUseWorker false
|
||||
@aceSession.setMode @editModes[@spell.language]
|
||||
@aceSession.setMode SpellView.editModes[@spell.language]
|
||||
@aceSession.setWrapLimitRange null
|
||||
@aceSession.setUseWrapMode true
|
||||
@aceSession.setNewLineMode 'unix'
|
||||
|
@ -324,7 +324,7 @@ module.exports = class SpellView extends CocoView
|
|||
|
||||
# window.zatannaInstance = @zatanna
|
||||
# window.snippetEntries = snippetEntries
|
||||
lang = @editModes[e.language].substr 'ace/mode/'.length
|
||||
lang = SpellView.editModes[e.language].substr 'ace/mode/'.length
|
||||
@zatanna.addSnippets snippetEntries, lang
|
||||
|
||||
onMultiplayerChanged: ->
|
||||
|
@ -904,8 +904,8 @@ module.exports = class SpellView extends CocoView
|
|||
|
||||
onChangeLanguage: (e) ->
|
||||
return unless @spell.canWrite()
|
||||
@aceSession.setMode @editModes[e.language]
|
||||
@zatanna?.set 'language', @editModes[e.language].substr('ace/mode/')
|
||||
@aceSession.setMode SpellView.editModes[e.language]
|
||||
@zatanna?.set 'language', SpellView.editModes[e.language].substr('ace/mode/')
|
||||
wasDefault = @getSource() is @spell.originalSource
|
||||
@spell.setLanguage e.language
|
||||
@reloadCode true if wasDefault
|
||||
|
|
|
@ -246,6 +246,7 @@ module.exports = class PlayHeroesModal extends ModalView
|
|||
heroEntry = @$el.find(".hero-item[data-hero-id='#{@visibleHero.get('original')}']")
|
||||
heroEntry.find('.hero-status-value').attr('data-i18n', 'play.available').i18n()
|
||||
heroEntry.removeClass 'locked purchasable'
|
||||
@selectedHero = @visibleHero
|
||||
@rerenderFooter()
|
||||
|
||||
Backbone.Mediator.publish 'store:hero-purchased', hero: @visibleHero, heroSlug: @visibleHero.get('slug')
|
||||
|
|
|
@ -61,19 +61,45 @@ class EarnedAchievementHandler extends Handler
|
|||
EarnedAchievement.findOne q, (err, earned) -> callback(err, earned)
|
||||
}, (err, { achievement, trigger, earned } ) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
if earned
|
||||
return @sendSuccess(res, earned.toObject())
|
||||
if not achievement
|
||||
return @sendNotFoundError(res, 'Could not find achievement.')
|
||||
if not trigger
|
||||
else if not trigger
|
||||
return @sendNotFoundError(res, 'Could not find trigger.')
|
||||
if achievement.get('proportionalTo')
|
||||
else if earned
|
||||
achievementEarned = achievement.get('rewards')
|
||||
actuallyEarned = earned.get('earnedRewards')
|
||||
if not _.isEqual(achievementEarned, actuallyEarned)
|
||||
earned.set('earnedRewards', achievementEarned)
|
||||
earned.save((err) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@upsertNonNumericRewards(req.user, achievement, (err) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendSuccess(res, earned.toObject())
|
||||
)
|
||||
)
|
||||
else
|
||||
@upsertNonNumericRewards(req.user, achievement, (err) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendSuccess(res, earned.toObject())
|
||||
)
|
||||
else if achievement.get('proportionalTo')
|
||||
return @sendBadInputError(res, 'Cannot currently do this to repeatable docs...')
|
||||
EarnedAchievement.createForAchievement(achievement, trigger, null, (earnedAchievementDoc) =>
|
||||
@sendCreated(res, earnedAchievementDoc.toObject())
|
||||
)
|
||||
|
||||
else
|
||||
EarnedAchievement.createForAchievement(achievement, trigger, null, (earnedAchievementDoc) =>
|
||||
@sendCreated(res, earnedAchievementDoc.toObject())
|
||||
)
|
||||
)
|
||||
|
||||
upsertNonNumericRewards: (user, achievement, done) ->
|
||||
update = {}
|
||||
for rewardType, rewards of achievement.get('rewards') ? {}
|
||||
continue if rewardType is 'gems'
|
||||
if rewards.length
|
||||
update.$addToSet ?= {}
|
||||
update.$addToSet["earned.#{rewardType}"] = $each: rewards
|
||||
User.update {_id: user._id}, update, {}, (err, count) ->
|
||||
log.error err if err?
|
||||
done?(err)
|
||||
|
||||
getByAchievementIDs: (req, res) ->
|
||||
query = { user: req.user._id+''}
|
||||
|
|
Loading…
Reference in a new issue