Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-09-04 20:10:45 -07:00
commit c85c39fd92
17 changed files with 100 additions and 136 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -334,7 +334,7 @@ module.exports = class SpriteBoss extends CocoClass
onFlagUpdated: (e) -> onFlagUpdated: (e) ->
return unless e.active return unless e.active
pendingFlag = new FlagSprite @thangTypeFor('Flag'), @createSpriteOptions(thangID: 'Pending Flag ' + Math.random(), color: e.color, team: me.team, isCursor: false, pos: e.pos) pendingFlag = new FlagSprite @thangTypeFor('Flag'), @createSpriteOptions(thangID: 'Pending Flag ' + Math.random(), color: e.color, team: e.team, isCursor: false, pos: e.pos)
@addSprite pendingFlag, pendingFlag.thang.id, @spriteLayers['Floating'] @addSprite pendingFlag, pendingFlag.thang.id, @spriteLayers['Floating']
@pendingFlags.push pendingFlag @pendingFlags.push pendingFlag

View file

@ -657,12 +657,16 @@
why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age."
why_ending: "And hey, it's free. " why_ending: "And hey, it's free. "
why_ending_url: "Start wizarding now!" why_ending_url: "Start wizarding now!"
george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." george_title: "CEO"
scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." george_description: "Businesser"
nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." scott_title: "Programmer"
jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." scott_description: "Reasonable One"
michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." nick_title: "Programmer"
matt_description: "Bicyclist, Software Engineer, reader of heroic fantasy, connoisseur of peanut butter, sipper of coffee." nick_description: "Motivation Guru"
michael_title: "Programmer"
michael_description: "Sys Admin"
matt_title: "Programmer"
matt_description: "Bicyclist"
legal: legal:
page_title: "Legal" page_title: "Legal"

View file

@ -2,8 +2,7 @@ c = require './../schemas'
# TODO add these: http://docs.mongodb.org/manual/reference/operator/query/ # TODO add these: http://docs.mongodb.org/manual/reference/operator/query/
MongoQueryOperatorSchema = MongoQueryOperatorSchema =
title: 'MongoDB Query operator' title: 'Query Operator'
id: 'mongoQueryOperator'
type: 'object' type: 'object'
properties: properties:
'$gt': type: 'number' '$gt': type: 'number'
@ -13,26 +12,23 @@ MongoQueryOperatorSchema =
'$lte': type: 'number' '$lte': type: 'number'
'$ne': type: ['number', 'string'] '$ne': type: ['number', 'string']
'$nin': type: 'array' '$nin': type: 'array'
additionalProperties: true # TODO set to false when the schema's done '$exists': type: 'boolean'
additionalProperties: false
MongoFindQuerySchema = MongoFindQuerySchema =
title: 'MongoDB Query' title: 'Query'
id: 'mongoFindQuery'
type: 'object' type: 'object'
patternProperties: patternProperties:
#'^[-a-zA-Z0-9_]*$': '^[-a-zA-Z0-9.]*$':
'^[-a-zA-Z0-9\.]*$': anyOf: [
oneOf: [ {$ref: '#/definitions/mongoQueryOperator'},
#{$ref: '#/definitions/' + MongoQueryOperatorSchema.id},
{type: 'string'} {type: 'string'}
{type: 'object'} {type: 'object'}
{type: 'boolean'} {type: 'boolean'}
] ]
additionalProperties: true # TODO make Treema accept new pattern matched keys additionalProperties: false
definitions: {} definitions: {}
MongoFindQuerySchema.definitions[MongoQueryOperatorSchema.id] = MongoQueryOperatorSchema
AchievementSchema = c.object() AchievementSchema = c.object()
c.extendNamedProperties AchievementSchema c.extendNamedProperties AchievementSchema
c.extendBasicProperties AchievementSchema, 'achievement' c.extendBasicProperties AchievementSchema, 'achievement'
@ -48,7 +44,7 @@ AchievementSchema.default =
_.extend AchievementSchema.properties, _.extend AchievementSchema.properties,
query: query:
#type:'object' #type:'object'
$ref: '#/definitions/' + MongoFindQuerySchema.id $ref: '#/definitions/mongoFindQuery'
worth: c.float worth: c.float
collection: {type: 'string'} collection: {type: 'string'}
description: c.shortString() description: c.shortString()
@ -93,6 +89,7 @@ _.extend AchievementSchema, # Let's have these on the bottom
additionalProperties: false additionalProperties: false
AchievementSchema.definitions = {} AchievementSchema.definitions = {}
AchievementSchema.definitions[MongoFindQuerySchema.id] = MongoFindQuerySchema AchievementSchema.definitions['mongoQueryOperator'] = MongoQueryOperatorSchema
AchievementSchema.definitions['mongoFindQuery'] = MongoFindQuerySchema
module.exports = AchievementSchema module.exports = AchievementSchema

View file

@ -148,10 +148,7 @@ _.extend LevelComponentSchema.properties,
type: 'boolean' type: 'boolean'
title: 'Official' title: 'Official'
description: 'Whether this is an official CodeCombat Component.' description: 'Whether this is an official CodeCombat Component.'
searchStrings: { searchStrings: {type: 'string'}
type: 'array'
items: { type: 'string' }
}
c.extendBasicProperties LevelComponentSchema, 'level.component' c.extendBasicProperties LevelComponentSchema, 'level.component'
c.extendSearchableProperties LevelComponentSchema c.extendSearchableProperties LevelComponentSchema

View file

@ -5,10 +5,10 @@ module.exports =
session: {type: 'object'} session: {type: 'object'}
'real-time-multiplayer:left-game': c.object {title: 'Multiplayer left game'} 'real-time-multiplayer:left-game': c.object {title: 'Multiplayer left game'}
'real-time-multiplayer:manual-cast': c.object {title: 'Multiplayer manual cast'} 'real-time-multiplayer:manual-cast': c.object {title: 'Multiplayer manual cast'}
'real-time-multiplayer:new-opponent-code': c.object {title: 'Multiplayer new opponent code', required: ['code', 'codeLanguage']}, 'real-time-multiplayer:new-opponent-code': c.object {title: 'Multiplayer new opponent code', required: ['code', 'codeLanguage']},
code: {type: 'object'} code: {type: 'object'}
codeLanguage: {type: 'string'} codeLanguage: {type: 'string'}
team: {type: 'string'}

View file

@ -180,5 +180,5 @@ module.exports = # /app/lib/surface
'surface:remove-selected-flag': c.object {} 'surface:remove-selected-flag': c.object {}
'surface:remove-flag': c.object {required: 'color'}, 'surface:remove-flag': c.object {required: ['color']},
color: {type: 'string'} color: {type: 'string'}

View file

@ -18,6 +18,13 @@
&:hover &:hover
background-color: rgba(200, 244, 255, 0.2) background-color: rgba(200, 244, 255, 0.2)
float: left float: left
width: 100px width: 80px
height: 100px height: 80px
margin-top: 22px margin: 0px 10px 22px 0px
.team_name
margin-top: 0
.team_bio
width: 150px
float: left

View file

@ -121,7 +121,7 @@
background-position-x: -4 * $iconSize background-position-x: -4 * $iconSize
&.prop-label-icon-attackDamage &.prop-label-icon-attackDamage
background-position-x: -5 * $iconSize background-position-x: -5 * $iconSize
&.prop-label-icon-attackRange &.prop-label-icon-attackRange, &.prop-label-icon-attackNearbyEnemyRange
background-position-x: -6 * $iconSize background-position-x: -6 * $iconSize
&.prop-label-icon-maxSpeed &.prop-label-icon-maxSpeed
background-position-x: -7 * $iconSize background-position-x: -7 * $iconSize

View file

@ -2,48 +2,17 @@ extends /templates/base
block content block content
img(src="/images/pages/about/coco_comic.jpg")
.row .row
.col-sm-6 .col-sm-6
h2(data-i18n="about.who_is_codecombat")
| Who is CodeCombat?
p
a(href="http://georgesaines.com/") George
span ,
a(href="http://scotterickson.info/") Scott
span ,
span(data-i18n="general.and") and
span
a(href="http://www.nickwinter.net") Nick
span
span(data-i18n="about.who_description_prefix")
| together started CodeCombat in 2013. We also created
a(href="http://www.skritter.com/") Skritter
span
span(data-i18n="about.who_description_suffix")
| in 2008, growing it to the #1 web and iOS application
| for learning to write Chinese and Japanese characters.
p(data-i18n="about.who_description_ending")
| Now it's time to teach people to write code.
h2(data-i18n="about.why_codecombat") h2(data-i18n="about.why_codecombat")
| Why CodeCombat? | Why CodeCombat?
p(data-i18n="about.why_paragraph_1")
| When making Skritter, George didn't know how to program and was constantly
| frustrated by his inability to implement his ideas. Afterwards,
| he tried learning, but the lessons were too slow. His housemate,
| wanting to reskill and stop teaching, tried Codecademy, but "got bored."
| Each week another friend started Codecademy, then dropped off.
| We realized it was the same problem we'd solved with Skritter:
| people learning a skill via slow, intensive lessons when what they need is fast,
| extensive practice. We know how to fix that.
p(data-i18n="about.why_paragraph_2") p(data-i18n="about.why_paragraph_2")
| Need to learn to code? You don't need lessons. | If you want to learn to program, you don't need lessons.
| You need to write a lot of code and have a great time doing it. | You need to write a lot of code and have a great time doing it.
p p
@ -69,11 +38,13 @@ block content
| If you're going to get addicted to some game, | If you're going to get addicted to some game,
| get addicted to this one and become one of the wizards of the tech age. | get addicted to this one and become one of the wizards of the tech age.
p.lead h2
span(data-i18n="about.why_ending") | Bloggers/Press
| And hey, it's free.
a(href="/", data-i18n="about.why_ending_url") p
| Start wizarding now! | Want to write about us? Feel free to download and use all of the resources included in our
a(href="https://s3.amazonaws.com/CodeCombatMisc/press_packet.zip") press packet.
| All logos and images may be used without contacting us directly.
ul.col-sm-6.team-column ul.col-sm-6.team-column
@ -81,87 +52,74 @@ block content
ul.thumbnails ul.thumbnails
li.row li.row
h2 Team
a(href="http://georgesaines.com") img(src="/images/pages/about/george_small.png").img-thumbnail
img(src="/images/pages/about/george_small.png").img-thumbnail
.col-sm-8 .team_bio
h3 h4.team_name
a(href="http://georgesaines.com") George Saines a(href="http://georgesaines.com") George Saines
p(data-i18n="about.george_title")
| CEO
p(data-i18n="about.george_description") p(data-i18n="about.george_description")
| CEO, business guy, web designer, game designer, | Businesser
| and champion of beginning programmers everywhere.
li.row
a(href="http://scotterickson.info") a(href="http://scotterickson.info")
img(src="/images/pages/about/scott_small.png").img-thumbnail img(src="/images/pages/about/scott_small.png").img-thumbnail
.col-sm-8 .team_bio
h3 h4.team_name
a(href="http://scotterickson.info") Scott Erickson a(href="http://scotterickson.info") Scott Erickson
p(data-i18n="about.scott_title")
| Programmer
p(data-i18n="about.scott_description") p(data-i18n="about.scott_description")
| Programmer extraordinaire, software architect, | Reasonable one
| kitchen wizard, and master of finances.
| Scott is the reasonable one.
li.row li.row
a(href="http://www.nickwinter.net") a(href="http://www.nickwinter.net")
img(src="/images/pages/about/nick_small.png").img-thumbnail img(src="/images/pages/about/nick_small.png").img-thumbnail
.col-sm-8 .team_bio
h3 h4.team_name
a(href="http://www.nickwinter.net") Nick Winter a(href="http://www.nickwinter.net") Nick Winter
p(data-i18n="about.nick_title")
| Programmer
p(data-i18n="about.nick_description") p(data-i18n="about.nick_description")
| Programming wizard, eccentric motivation mage, | Motivation Guru
| and upside-down experimenter.
| Nick can do anything and chooses to build CodeCombat.
li.row
a(href="http://michaelschmatz.com") a(href="http://michaelschmatz.com")
img(src="/images/pages/about/michael_small.png").img-thumbnail img(src="/images/pages/about/michael_small.png").img-thumbnail
.col-sm-8 .team_bio
h3 h4.team_name
a(href="http://michaelschmatz.com/") Michael Schmatz a(href="http://michaelschmatz.com/") Michael Schmatz
p(data-i18n="about.michael_title")
| Programmer
p(data-i18n="about.michael_description") p(data-i18n="about.michael_description")
| Programmer, sys-admin, and undergrad technical wunderkind, | Sys Admin
| Michael is the person keeping our servers online.
li.row li.row
img(src="/images/pages/about/jeremy_small.png").img-thumbnail img(src="/images/pages/about/placeholder.png").img-thumbnail
.col-sm-8 .team_bio
h3 Jeremy Arns h4.team_name
p(data-i18n="about.jeremy_description")
| Customer support mage, usability tester,
| and community organizer; you've probably
| already spoken with Jeremy.
li.row
img(src="/images/pages/contribute/archmage.png").img-thumbnail
.col-sm-8
h3
a(href="http://www.mattlott.com/") Matt Lott a(href="http://www.mattlott.com/") Matt Lott
p(data-i18n="about.matt_title")
| Programmer
p(data-i18n="about.matt_description") p(data-i18n="about.matt_description")
| Bicyclist, Software Engineer, reader of heroic fantasy, connoisseur | Bicyclist
| of peanut butter, sipper of coffee.

View file

@ -28,22 +28,13 @@ module.exports = class NewAchievementModal extends NewModelModal
createQuery: -> createQuery: ->
checked = @$el.find('[name=queryOptions]:checked') checked = @$el.find('[name=queryOptions]:checked')
checkedValues = ($(check).val() for check in checked) checkedValues = ($(check).val() for check in checked)
subQueries = [] query = {}
for id in checkedValues for id in checkedValues
switch id switch id
when 'misc-level-completion' when 'misc-level-completion'
subQueries.push state: complete: true query['state.complete'] = true
else # It's a goal else
q = state: goalStates: {} query["state.goalStates.#{id}.status"] = 'success'
q.state.goalStates[id] = {}
q.state.goalStates[id].status = 'success'
subQueries.push q
unless subQueries.length
query = {}
else if subQueries.length is 1
query = subQueries[0]
else
query = $or: subQueries
query['level.original'] = @level.get 'original' query['level.original'] = @level.get 'original'
query query

View file

@ -3,6 +3,8 @@ template = require 'templates/play/level/level-flags-view'
{me} = require 'lib/auth' {me} = require 'lib/auth'
RealTimeCollection = require 'collections/RealTimeCollection' RealTimeCollection = require 'collections/RealTimeCollection'
multiplayerFlagDelay = 0.5 # Long, static second delay for now; should be more than enough.
module.exports = class LevelFlagsView extends CocoView module.exports = class LevelFlagsView extends CocoView
id: 'level-flags-view' id: 'level-flags-view'
template: template template: template
@ -54,7 +56,9 @@ module.exports = class LevelFlagsView extends CocoView
onStageMouseDown: (e) -> onStageMouseDown: (e) ->
return unless @flagColor and @realTime return unless @flagColor and @realTime
pos = x: e.worldPos.x, y: e.worldPos.y pos = x: e.worldPos.x, y: e.worldPos.y
flag = player: me.id, team: me.team, color: @flagColor, pos: pos, time: @world.dt * @world.frames.length, active: true delay = if @realTimeFlags then multiplayerFlagDelay else 0
now = @world.dt * @world.frames.length
flag = player: me.id, team: me.team, color: @flagColor, pos: pos, time: now + delay, active: true
@flags[@flagColor] = flag @flags[@flagColor] = flag
@flagHistory.push flag @flagHistory.push flag
@realTimeFlags?.create flag @realTimeFlags?.create flag
@ -67,7 +71,9 @@ module.exports = class LevelFlagsView extends CocoView
onRemoveFlag: (e) -> onRemoveFlag: (e) ->
delete @flags[e.color] delete @flags[e.color]
flag = player: me.id, team: me.team, color: e.color, time: @world.dt * @world.frames.length, active: false delay = if @realTimeFlags then multiplayerFlagDelay else 0
now = @world.dt * @world.frames.length
flag = player: me.id, team: me.team, color: e.color, time: now + delay, active: false
@flagHistory.push flag @flagHistory.push flag
Backbone.Mediator.publish 'level:flag-updated', flag Backbone.Mediator.publish 'level:flag-updated', flag
#console.log e.color, 'deleted at time', flag.time #console.log e.color, 'deleted at time', flag.time
@ -79,6 +85,7 @@ module.exports = class LevelFlagsView extends CocoView
onJoinedMultiplayerGame: (e) -> onJoinedMultiplayerGame: (e) ->
@realTimeFlags = new RealTimeCollection('multiplayer_level_sessions/' + e.session.id + '/flagHistory') @realTimeFlags = new RealTimeCollection('multiplayer_level_sessions/' + e.session.id + '/flagHistory')
@realTimeFlags.on 'add', @onRealTimeMultiplayerFlagAdded @realTimeFlags.on 'add', @onRealTimeMultiplayerFlagAdded
@realTimeFlags.on 'remove', @onRealTimeMultiplayerFlagRemoved
onLeftMultiplayerGame: (e) -> onLeftMultiplayerGame: (e) ->
if @realTimeFlags if @realTimeFlags
@ -98,3 +105,5 @@ module.exports = class LevelFlagsView extends CocoView
active: e.get('active') active: e.get('active')
@flagHistory.push flag @flagHistory.push flag
Backbone.Mediator.publish 'level:flag-updated', flag Backbone.Mediator.publish 'level:flag-updated', flag
onRealTimeMultiplayerFlagRemoved: (e) =>

View file

@ -265,7 +265,7 @@ module.exports = class LevelHUDView extends CocoView
return null # included in the bar return null # included in the bar
context = context =
prop: prop prop: prop
hasIcon: prop in ['health', 'pos', 'target', 'collectedThangIDs', 'gold', 'bountyGold', 'visualRange', 'attackDamage', 'attackRange', 'maxSpeed'] hasIcon: prop in ['health', 'pos', 'target', 'collectedThangIDs', 'gold', 'bountyGold', 'visualRange', 'attackDamage', 'attackRange', 'maxSpeed', 'attackNearbyEnemyRange']
hasBar: prop in ['health'] hasBar: prop in ['health']
$(prop_template(context)) $(prop_template(context))

View file

@ -619,6 +619,7 @@ module.exports = class PlayLevelView extends RootView
myPlayer.set 'code', @session.get('code') myPlayer.set 'code', @session.get('code')
myPlayer.set 'codeLanguage', @session.get('codeLanguage') myPlayer.set 'codeLanguage', @session.get('codeLanguage')
myPlayer.set 'state', 'submitted' myPlayer.set 'state', 'submitted'
myPlayer.set 'team', me.team
else else
console.error 'Did not find my player in onRealTimeMultiplayerCast' console.error 'Did not find my player in onRealTimeMultiplayerCast'
if opponentPlayer if opponentPlayer
@ -636,7 +637,7 @@ module.exports = class PlayLevelView extends RootView
onOpponentSubmitted: (opponentPlayer, myPlayer) => onOpponentSubmitted: (opponentPlayer, myPlayer) =>
# Save opponent's code # Save opponent's code
Backbone.Mediator.publish 'real-time-multiplayer:new-opponent-code', {codeLanguage: opponentPlayer.get('codeLanguage'), code: opponentPlayer.get('code')} Backbone.Mediator.publish 'real-time-multiplayer:new-opponent-code', {codeLanguage: opponentPlayer.get('codeLanguage'), code: opponentPlayer.get('code'), team: opponentPlayer.get('team')}
# I'm ready to rumble # I'm ready to rumble
myPlayer.set 'state', 'ready' myPlayer.set 'state', 'ready'
if opponentPlayer.get('state') is 'ready' if opponentPlayer.get('state') is 'ready'

View file

@ -164,11 +164,11 @@ module.exports = class Spell
false false
onNewOpponentCode: (e) => onNewOpponentCode: (e) =>
return unless @spellKey return unless @spellKey and @canWrite e.team
if e.codeLanguage and e.code if e.codeLanguage and e.code
spellkeyComponents = @spellKey.split '/' [thangSlug, methodSlug] = @spellKey.split '/'
if e.code[spellkeyComponents[0]]?[spellkeyComponents[1]] if opponentCode = e.code[thangSlug]?[methodSlug]
@source = e.code[spellkeyComponents[0]][spellkeyComponents[1]] @source = opponentCode
@updateLanguageAether e.codeLanguage @updateLanguageAether e.codeLanguage
else else
console.error 'Spell onNewOpponentCode did not receive code', e console.error 'Spell onNewOpponentCode did not receive code', e