Merge branch 'master' into production

This commit is contained in:
Nick Winter 2015-04-20 11:20:58 -07:00
commit c8c11df64e
20 changed files with 140 additions and 43 deletions

View file

@ -19,7 +19,7 @@ scope = 'https://www.googleapis.com/auth/plus.login email'
module.exports = GPlusHandler = class GPlusHandler extends CocoClass
constructor: ->
@accessToken = storage.load GPLUS_TOKEN_KEY
@accessToken = storage.load GPLUS_TOKEN_KEY, false
super()
subscriptions:
@ -53,7 +53,7 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass
try
# Without removing this, we sometimes get a cross-domain error
d = _.omit(e, 'g-oauth-window')
storage.save(GPLUS_TOKEN_KEY, d)
storage.save(GPLUS_TOKEN_KEY, d, 0)
catch e
console.error 'Unable to save G+ token key', e
@accessToken = e

View file

@ -16,6 +16,7 @@ module.exports = class Angel extends CocoClass
subscriptions:
'level:flag-updated': 'onFlagEvent'
'playback:stop-real-time-playback': 'onStopRealTimePlayback'
'level:escape-pressed': 'onEscapePressed'
constructor: (@shared) ->
super()
@ -165,10 +166,11 @@ module.exports = class Angel extends CocoClass
@worker.postMessage func: 'finalizePreload'
@work.preload = false
infinitelyLooped: =>
infinitelyLooped: (escaped=false) =>
@say 'On infinitely looped! Aborting?', @aborting
return if @aborting
problem = type: 'runtime', level: 'error', id: 'runtime_InfiniteLoop', message: 'Code never finished. It\'s either really slow or has an infinite loop.'
problem.message = 'Escape pressed; code aborted.' if escaped
Backbone.Mediator.publish 'god:user-code-problem', problem: problem
Backbone.Mediator.publish 'god:infinite-loop', firstWorld: @shared.firstWorld
@fireWorker()
@ -239,8 +241,14 @@ module.exports = class Angel extends CocoClass
onStopRealTimePlayback: (e) ->
return unless @running and @work.realTime
@work.realTime = false
@lastRealTimeWork = new Date()
@worker.postMessage func: 'stopRealTimePlayback'
onEscapePressed: (e) ->
return unless @running and not @work.realTime
return if (new Date() - @lastRealTimeWork) < 1000 # Fires right after onStopRealTimePlayback
@infinitelyLooped true
#### Synchronous code for running worlds on main thread (profiling / IE9) ####
simulateSync: (work) =>
console?.profile? "World Generation #{(Math.random() * 1000).toFixed(0)}" if imitateIE9?

View file

@ -1,6 +1,7 @@
module.exports.thangNames = thangNames =
'Ogre Munchkin F': [
# Female
'Anabel'
'Dosha'
'Gurzunn'
'Hoot'
@ -8,6 +9,7 @@ module.exports.thangNames = thangNames =
'Iyert'
'Lacos'
'Palt'
'Paulark'
'Pripp'
'Shmeal'
'Upfish'
@ -19,9 +21,11 @@ module.exports.thangNames = thangNames =
'Brack'
'Dobo'
'Draff'
'Eugen'
'Gert'
'Godel'
'Goreball'
'Toremon'
'Gort'
'Kog'
'Kogpole'

View file

@ -261,6 +261,7 @@
victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code™!"
victory_experience_gained: "XP Gained"
victory_gems_gained: "Gems Gained"
victory_new_item: "New Item"
victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks."
victory_become_a_viking: "Become a Viking"
guide_title: "Guide"

View file

@ -261,6 +261,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
victory_hour_of_code_done_yes: "Да, я закончил мой Час Кода™!"
victory_experience_gained: "Опыта получено"
victory_gems_gained: "Самоцветов получено"
victory_new_item: "Новый предмет"
victory_viking_code_school: "Ого, это было тяжелый уровень! Если вы еще не разработчик программ, вам стоит им стать. Вы только что ускорири принятие в Школу Викингов, где вы сможете поднять свои навыки на новый уровень и стать профессиональным веб-разработчиком за 14 недель."
victory_become_a_viking: "Станьте Викингом"
guide_title: "Руководство"
@ -528,8 +529,6 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
volume_label: "Громкость"
music_label: "Музыка"
music_description: "Фоновая музыка вкл/выкл"
autorun_label: "Автозапуск"
autorun_description: "Настройка автоматического выполнения кода."
editor_config: "Настройки редактора"
editor_config_title: "Настройки редактора"
editor_config_level_language_label: "Язык для этого уровня"
@ -570,7 +569,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
nick_blurb: "Гуру мотивации"
michael_title: "Программист"
michael_blurb: "Сисадмин"
matt_title: "Программист"
matt_title: "Сооснователь"
matt_blurb: "Велосипедист"
cat_title: "Главный ремесленник"
cat_blurb: "Повелитель стихий"
@ -605,8 +604,8 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
material_title: "Как много здесь материала?"
material_china: "Около 22 часов игрового процесса, распределенного более чем на 120 уровней для подписчиков с добавлением 5 уровней каждую неделю."
material_1: "Около 8 часов бесплатного контента и 14 часов дополнительного контента для подписчиков с добавлением 5 уровней каждую неделю."
concepts_title: "О каких концептах мы рассказываем? What concepts are covered?"
how_much_title: "How much does a monthly subscription cost?"
concepts_title: "О каких концептах мы рассказываем?"
how_much_title: "Сколько стоит месячная подписка?"
how_much_1: "Цена"
how_much_2: "месячной подписки"
how_much_3: "- $9.99. Подписка может быть отменена в любой момент."

View file

@ -42,8 +42,8 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak",
diplomat_suggestion:
title: "Pomôžte preložiť CodeCombat!" # This shows up when a player switches to a non-English language using the language selector.
sub_heading: "Potrebujeme tvoje jazykové zručnosti."
pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Slovak but don't speak English, so if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Slovak."
missing_translations: "Until we can translate everything into Slovak, you'll see English when Slovak isn't available."
#pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Slovak but don't speak English, so if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Slovak."
#missing_translations: "Until we can translate everything into Slovak, you'll see English when Slovak isn't available."
learn_more: "Zisti viac, ako byť Diplomat"
subscribe_as_diplomat: "Prihlásiť sa ako Diplomat"

View file

@ -64,7 +64,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
achievements: "成就" # Tooltip on achievement list button from /play
account: "账户" # Tooltip on account button from /play
settings: "设置" # Tooltip on settings button from /play
# poll: "Poll" # Tooltip on poll button from /play
poll: "投票" # Tooltip on poll button from /play
next: "下一步" # Go from choose hero to choose inventory before playing a level
change_hero: "重新选择英雄" # Go back from choose inventory to choose hero
choose_inventory: "装备道具"
@ -261,8 +261,9 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
victory_hour_of_code_done_yes: "是的, 完成了!"
victory_experience_gained: "获得经验"
victory_gems_gained: "获得宝石"
# victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks."
# victory_become_a_viking: "Become a Viking"
victory_new_item: "新的物品"
victory_viking_code_school: "这关真的超难! 如果你想成为一个软件开发人员你就应该去试一下Viking Code School。在这里你可以把你的知识增长到另一个台阶。只需要14周你就能成为一个专业的网页开发人员。"
victory_become_a_viking: "成为一个维京人吧"
guide_title: "指南"
tome_minion_spells: "助手的咒语" # Only in old-style levels.
tome_read_only_spells: "只读的咒语" # Only in old-style levels.
@ -429,15 +430,15 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
# parents_blurb1a: "Computer programming is an essential skill that your child will undoubtedly use as an adult. By 2020, basic software skills will be needed by 77% of jobs, and software engineers are in high demand across the world. Did you know that Computer Science is the highest-paid university degree?"
parents_blurb2: "每月支付9.9美元,他们每周都会有新的挑战,并且通过电子邮件获得专业程序员的指导。" # {change}
parents_blurb3: "无风险承诺100%退款,一键退款。"
# payment_methods: "Payment Methods"
payment_methods: "付费方式"
# payment_methods_title: "Accepted Payment Methods"
# payment_methods_blurb1: "We currently accept credit cards and Alipay."
# payment_methods_blurb2: "If you require an alternate form of payment, please contact"
payment_methods_blurb1: "我们现有的付费方式有信用卡和支付宝"
payment_methods_blurb2: "如果你想用其他付费方式,请联系我们"
stripe_description: "每月订阅"
subscription_required_to_play: "订阅后才可开始本关"
unlock_help_videos: "订阅后才可以解锁视频教学哦!"
# personal_sub: "Personal Subscription" # Accounts Subscription View below
# loading_info: "Loading subscription information..."
loading_info: "正在读入订阅内容..."
# managed_by: "Managed by"
# will_be_cancelled: "Will be cancelled on"
# currently_free: "You currently have a free subscription"
@ -491,7 +492,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
skills: "技能"
# attack_1: "Deals"
# attack_2: "of listed"
# attack_3: "weapon damage."
attack_3: "武器攻击力."
# health_1: "Gains"
# health_2: "of listed"
# health_3: "armor health."
@ -572,11 +573,11 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
michael_blurb: "系统管理员"
matt_title: "程序员"
matt_blurb: "自行车爱好者"
# cat_title: "Chief Artisan"
cat_title: "首席关卡设计师"
# cat_blurb: "Airbender"
# josh_title: "Game Designer"
# josh_blurb: "Floor Is Lava"
# jose_title: "Music"
josh_title: "游戏设计师"
josh_blurb: "地面是熔岩"
jose_title: "音乐"
# jose_blurb: "Taking Off"
# retrostyle_title: "Illustration"
# retrostyle_blurb: "RetroStyle Games"
@ -946,7 +947,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
fight: "战斗!"
watch_victory: "观看你的胜利"
defeat_the: "击败了"
# tournament_started: ", started"
tournament_started: ",锦标赛已开始"
tournament_ends: "锦标赛结束"
tournament_ended: "Tournament ended"
tournament_rules: "锦标赛规则"

View file

@ -253,6 +253,15 @@
font-weight: bold
color: rgb(40, 33, 22)
margin-right: 12px
width: 78px
&.four-digits
font-size: 40px
margin-top: 3px
&.five-digits
font-size: 30px
margin-top: 10px
.total-label
float: left

View file

@ -47,7 +47,10 @@ block modal-body-content
.reward-panel.item(data-item-thang-type=item.get('original'))
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
img(src=item.getPortraitURL())
.reward-text= animate ? 'New Item' : item.get('name')
if animate
.reward-text(data-i18n="play_level.victory_new_item") New Item
else
.reward-text= i18n(item.attributes, 'name')
block modal-footer-content
#totals

View file

@ -68,7 +68,7 @@ module.exports = class HeroVictoryModal extends ModalView
for thangTypeOriginal in thangTypeOriginals
thangType = new ThangType()
thangType.url = "/db/thang.type/#{thangTypeOriginal}/version"
thangType.project = ['original', 'rasterIcon', 'name', 'soundTriggers']
thangType.project = ['original', 'rasterIcon', 'name', 'soundTriggers', 'i18n']
@thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model
@newEarnedAchievements = []
@ -134,6 +134,7 @@ module.exports = class HeroVictoryModal extends ModalView
c.me = me
c.readyToRank = @level.get('type', true) is 'hero-ladder' and @session.readyToRank()
c.level = @level
c.i18n = utils.i18n
elapsed = (new Date() - new Date(me.get('dateCreated')))
isHourOfCode = me.get('hourOfCode') or elapsed < 120 * 60 * 1000
@ -229,6 +230,8 @@ module.exports = class HeroVictoryModal extends ModalView
@updateXPBars(totalXP)
xpTrigger = 'xp-' + (totalXP % 6) # 6 xp sounds
Backbone.Mediator.publish 'audio-player:play-sound', trigger: xpTrigger, volume: 0.5 + ratio / 2
@XPEl.addClass 'four-digits' if totalXP >= 1000 and @lastTotalXP < 1000
@XPEl.addClass 'five-digits' if totalXP >= 10000 and @lastTotalXP < 10000
@lastTotalXP = totalXP
else if panel.unit is 'gem'
newGems = Math.floor(panel.previousNumber + ratio * (panel.number - panel.previousNumber))
@ -238,10 +241,12 @@ module.exports = class HeroVictoryModal extends ModalView
@gemEl.text(totalGems)
gemTrigger = 'gem-' + (parseInt(panel.number * ratio) % 4) # 4 gem sounds
Backbone.Mediator.publish 'audio-player:play-sound', trigger: gemTrigger, volume: 0.5 + ratio / 2
@gemEl.addClass 'four-digits' if totalGems >= 1000 and @lastTotalGems < 1000
@gemEl.addClass 'five-digits' if totalGems >= 10000 and @lastTotalGems < 10000
@lastTotalGems = totalGems
else if panel.item
thangType = @thangTypes[panel.item]
panel.textEl.text(thangType.get('name'))
panel.textEl.text utils.i18n(thangType.attributes, 'name')
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'item-unlocked', volume: 1 if 0.5 < ratio < 0.6
else if panel.hero
thangType = @thangTypes[panel.hero]

View file

@ -153,7 +153,6 @@ module.exports = class SpellView extends CocoView
bindKey: {win: 'Escape', mac: 'Escape'}
readOnly: true
exec: ->
console.log 'esc pressed'
Backbone.Mediator.publish 'level:escape-pressed', {}
addCommand
name: 'toggle-grid'

View file

@ -71,7 +71,7 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None):
current_directory = os.path.dirname(os.path.realpath(sys.argv[0]))
allowedMongoVersions = ["v2.6"]
allowedMongoVersions = ["v2.6", "v3.0"]
if which("mongod") and any(i in subprocess.check_output("mongod --version",shell=True) for i in allowedMongoVersions):
mongo_executable = "mongod"
else:

View file

@ -3,7 +3,7 @@ This file will simulate games on node.js by emulating the browser environment.
In order to use, followed these steps:
1. Setup dev environment as usual
2. Create a `login.coffee` file in coco which contains:
module.exports = username: 'email@example.com', password: 'password'
module.exports = username: 'email@example.com', password: 'your_password'
3. Run `./node_modules/coffee-script/bin/coffee ./headless_client.coffee`
Alternatively, if you wish only to simulate a single game run `coffee ./headless_client.coffee one-game`
Or, if you want to always simulate only one game, change the line below this to "true". This takes way more bandwidth.

View file

@ -1,11 +1,79 @@
cluster = require 'cluster'
numCPUs = require('os').cpus().length
deaths = [
'Killed by a soldier ant.'
'Ascended.'
'Killed by an invisible gnome lord.'
'Died of starvation.'
'Petrified by a cockatrice corpse.'
'Poisoned by a rotted kobold corpse.'
'Fell into a pit.'
'Killed by brainlessness.'
'Slipped while mounting a saddled pony called Rainbow Dash.'
'Killed by a scroll of genocide.'
'Choked on a tin of spinach.'
'Killed by the wrath of Anhur.'
'Killed by a jackal, while fainted from lack of food.'
'Drowned in a pool of water by an electric eel.'
'Killed by falling downstairs.'
'Killed by an ape, while helpless.'
'Burned by a tower of flame.'
'Killed by Ms. Sipaliwini, the shopkeeper.'
'Fell onto a sink.'
'Killed by a killer bee, while praying.'
'Crushed to death by a collapsing drawbridge.'
'Crunched in the head by an iron ball.'
'Killed by exhaustion.'
'Caught itself in its own magical blast.'
'Shot itself with a death ray.'
'Killed by genocidal confusion.'
'Killed by touching Excalibur.'
'Killed by a hallucinogen-distorted dwarf.'
'Dissolved in molten lava.'
'Turned to slime by a green slime.'
'Killed by sipping boiling water.'
'A trickery.'
'Escaped (in celestial disgrace)'
'Killed by kicking a sink.'
'Killed by a kitten called Steve, while sleeping.'
'Went to heaven prematurely.'
'Teleported out of the dungeon and fell to its death.'
'Panic.'
'Killed by a minotuar, while dressing up.'
'Petrified by trying to help a cockatrice out of a pit.'
'Killed by a luckstone.'
'Killed by a panther, while taking off clothes.'
'Killed by a watch captain called The Nymphmaster.'
'Killed by a black pudding, while jumping around.'
'Killed by a hallucinogen-distorted white unicorn, while praying.'
'Choked on a slice of birthday cake.'
'Killed by a long worm, while reading a book.'
'Killed by a giant beetle, while vomiting.'
'Killed by an invisible master mind flayer, while unconscious from rotten food.'
'Burned by burning.'
'Killed by an air elemental, while hiding from thunderstorm (with the Amulet).'
'Killed by wedging into a narrow crevice.'
'Killed by a carnivorous bag.'
'Killed by axing a hard object.'
'Killed by an iron ball collision.'
'Killed by an alchemic blast.'
'Killed by dangerous winds.'
'Killed by psychic blast.'
'Committed suicide.'
'Squished under a boulder.'
'Killed by colliding with the ceiling.'
'Killed by sitting on an iron spike.'
"Quit while already on Charon's boat."
'Fell into a chasm.'
'Turned to slime by a cockatrice egg.'
]
if cluster.isMaster
for i in [0...numCPUs]
cluster.fork()
cluster.on 'exit', (worker, code, signal) ->
message = "Worker #{worker.id} died! Heart attack takin' a dump."
message = "Worker #{worker.id} died! #{deaths[Math.floor Math.random() * deaths.length]}"
console.log message
try
hipchat = require './server/hipchat'

View file

@ -86,10 +86,10 @@ class LinuxMongoDBDownloader(MongoDBDownloader):
@property
def download_url(self):
if self.dependency.config.mem_width == 64:
return u"http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.6.tgz"
return u"http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.2.tgz"
else:
warnings.warn(u"MongoDB *really* doesn't run well on 32 bit systems. You have been warned.")
return u"http://fastdl.mongodb.org/linux/mongodb-linux-i686-2.6.6.tgz"
return u"http://fastdl.mongodb.org/linux/mongodb-linux-i686-3.0.2.tgz"
class WindowsMongoDBDownloader(MongoDBDownloader):
@property
@ -97,11 +97,11 @@ class WindowsMongoDBDownloader(MongoDBDownloader):
#TODO: Implement Windows Vista detection
warnings.warn(u"If you have a version of Windows older than 7, MongoDB may not function properly!")
if self.dependency.config.mem_width == 64:
return u"http://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-2.6.6.zip"
return u"http://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-3.0.2.zip"
else:
return u"http://fastdl.mongodb.org/win32/mongodb-win32-i386-2.6.6.zip"
return u"http://fastdl.mongodb.org/win32/mongodb-win32-i386-3.0.2.zip"
class MacMongoDBDownloader(MongoDBDownloader):
@property
def download_url(self):
return u"http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-2.6.6.tgz"
return u"http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-3.0.2.tgz"

View file

@ -2,9 +2,9 @@ Set-ExecutionPolicy RemoteSigned
$mongoDbPath = "C:\MongoDB"
$mongoDbConfigPath = "$mongoDbPath\mongod.cfg"
$url = "http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-2.6.4.zip"
$url = "http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-3.0.2.zip"
$zipFile = "$mongoDbPath\mongo.zip"
$unzippedFolderContent ="$mongoDbPath\mongodb-win32-x86_64-2008plus-2.6.4.zip"
$unzippedFolderContent ="$mongoDbPath\mongodb-win32-x86_64-2008plus-3.0.2.zip"
if ((Test-Path -path $mongoDbPath) -eq $True)
{

View file

@ -79,7 +79,7 @@ ClanHandler = class ClanHandler extends Handler
return @sendNotFoundError(res, err)
Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err
return @sendDatabaseError(res, err) unless clan
return @sendNotFoundError(res) unless clan
return @sendForbiddenError(res) if clan.get('ownerID')?.equals req.user._id
Clan.update {_id: clanID}, {$pull: {members: req.user._id}}, (err) =>
return @sendDatabaseError(res, err) if err

View file

@ -81,7 +81,7 @@ module.exports = class Handler
sendBadInputError: (res, message) -> errors.badInput(res, message)
sendPaymentRequiredError: (res, message) -> errors.paymentRequired(res, message)
sendDatabaseError: (res, err) ->
return @sendError(res, err.code, err.response) if err.response and err.code
return @sendError(res, err.code, err.response) if err?.response and err?.code
log.error "Database error, #{err}"
errors.serverError(res, 'Database error, ' + err)

View file

@ -22,7 +22,7 @@ fileDelete = (req, res) ->
Grid.gfs.remove {_id: filedata._id, root: 'media'}, (err) ->
return errors.serverError(res) if err
return res.end()
fileGet = (req, res) ->
query = parsePathIntoQuery(req.path)
@ -48,7 +48,7 @@ fileGet = (req, res) ->
res.setHeader('Cache-Control', 'public')
readstream.pipe(res)
handleStreamEnd(res, res)
parsePathIntoQuery = (path) ->
path = path[6..]
path = decodeURI path
@ -130,7 +130,7 @@ savePNG = (req, res) ->
userCanEditFile = (user=null, file=null) ->
# no user means 'anyone'. No file means 'any file'
return false unless user
return true if user.isAdmin()
return true if user.isAdmin() or user.isArtisan()
return false unless file
return true if file.metadata.creator is user.id
return false

View file

@ -189,7 +189,7 @@ UserHandler = class UserHandler extends Handler
leaderboardQuery = User.find(queryParameters.query).select('name simulatedBy simulatedFor').sort({'simulatedBy': queryParameters.sortOrder}).limit(queryParameters.limit)
leaderboardQuery.cache() if req.query.scoreOffset is -1
leaderboardQuery.exec (err, otherUsers) ->
otherUsers = _.reject otherUsers, _id: req.user._id if req.query.scoreOffset isnt -1
otherUsers = _.reject otherUsers, _id: req.user._id if req.query.scoreOffset isnt -1 and req.user
otherUsers ?= []
res.send(otherUsers)
res.end()