Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-11-20 19:32:37 -08:00
commit 29cbf16dd7
17 changed files with 232 additions and 135 deletions

View file

@ -0,0 +1,23 @@
CampaignList = require('views/play/WorldMapView').campaigns
# TODO: Is this file structured correctly?
# Per-campaign options, with default fallback set
options =
'default':
autocompleteFontSizePx: 16
'dungeon':
autocompleteFontSizePx: 20
module.exports = CampaignOptions =
getCampaignForSlug: (slug) ->
return unless slug
for campaign in CampaignList
for level in campaign.levels
return campaign.id if level.id is slug
getOption: (levelSlug, option) ->
return unless levelSlug and option
return unless campaign = CampaignOptions.getCampaignForSlug levelSlug
return options[campaign]?[option] if options[campaign]?[option]?
return options.default[option] if options.default[option]?

View file

@ -204,6 +204,14 @@ module.exports = LevelOptions =
hidesCodeToolbar: true
requiredGear: {feet: 'leather-boots', 'right-hand': 'crude-builders-hammer'}
restrictedGear: {feet: 'simple-boots', 'right-hand': 'simple-sword'}
'endangered-burl':
requiredGear: {feet: 'leather-boots', 'right-hand': 'simple-sword', eyes: 'crude-glasses'}
hidesCodeToolbar: true
restrictedGear: {feet: 'simple-boots', 'right-hand': 'crude-builders-hammer'}
'village-guard':
requiredGear: {feet: 'leather-boots', 'right-hand': 'simple-sword', eyes: 'crude-glasses'}
hidesCodeToolbar: true
restrictedGear: {feet: 'simple-boots', 'right-hand': 'crude-builders-hammer'}
'thornbush-farm':
requiredGear: {feet: 'leather-boots', 'right-hand': 'crude-builders-hammer', eyes: 'crude-glasses'}
hidesCodeToolbar: true
@ -235,12 +243,12 @@ module.exports = LevelOptions =
restrictedGear: {}
'drop-the-flag':
requiredGear: {'programming-book': 'programmaticon-i', feet: 'leather-boots', flag: 'basic-flags', eyes: 'wooden-glasses', 'right-hand': 'crude-builders-hammer'}
restrictedGear: {'right-hand': 'longsword'}
restrictedGear: {'right-hand': 'long-sword'}
'deadly-pursuit':
requiredGear: {'programming-book': 'programmaticon-i', feet: 'leather-boots', flag: 'basic-flags', eyes: 'wooden-glasses', 'right-hand': 'crude-builders-hammer'}
restrictedGear: {'right-hand': 'longsword'}
restrictedGear: {'right-hand': 'long-sword'}
'rich-forager':
requiredGear: {'programming-book': 'programmaticon-i', feet: 'leather-boots', flag: 'basic-flags', eyes: 'wooden-glasses', torso: 'leather-tunic', 'right-hand': 'longsword', 'left-hand': 'bronze-shield'}
requiredGear: {'programming-book': 'programmaticon-i', feet: 'leather-boots', flag: 'basic-flags', eyes: 'wooden-glasses', torso: 'leather-tunic', 'right-hand': 'long-sword', 'left-hand': 'bronze-shield'}
restrictedGear: {'right-hand': 'crude-builders-hammer'}
'multiplayer-treasure-grove':
requiredGear: {'programming-book': 'programmaticon-i', feet: 'leather-boots', flag: 'basic-flags', eyes: 'wooden-glasses', torso: 'leather-tunic'}

View file

@ -283,8 +283,9 @@ module.exports = class Camera extends CocoClass
target = @boundTarget @target, @zoom
return if not force and _.isEqual target, @currentTarget
@currentTarget = target
@updateViewports target
Backbone.Mediator.publish 'camera:zoom-updated', camera: @, zoom: @zoom, surfaceViewport: @surfaceViewport
viewportDifference = @updateViewports target
if viewportDifference > 0.1 # Roughly 0.1 pixel difference in what we can see
Backbone.Mediator.publish 'camera:zoom-updated', camera: @, zoom: @zoom, surfaceViewport: @surfaceViewport
boundTarget: (pos, zoom) ->
# Given an {x, y} in Surface coordinates, return one that will keep our viewport on the Surface.
@ -303,6 +304,11 @@ module.exports = class Camera extends CocoClass
sv = width: @canvasWidth / @zoom, height: @canvasHeight / @zoom, cx: target.x, cy: target.y
sv.x = sv.cx - sv.width / 2
sv.y = sv.cy - sv.height / 2
if @surfaceViewport
# Calculate how different this viewport is. (If it's basically not different, we can avoid visualizing the update.)
viewportDifference = Math.abs(@surfaceViewport.x - sv.x) + 1.01 * Math.abs(@surfaceViewport.y - sv.y) + 1.02 * Math.abs(@surfaceViewport.width - sv.width)
else
viewportDifference = 9001
@surfaceViewport = sv
wv = @surfaceToWorld sv # get x and y
@ -312,6 +318,8 @@ module.exports = class Camera extends CocoClass
wv.cy = wv.y + wv.height / 2
@worldViewport = wv
viewportDifference
lock: ->
@target = @currentTarget
@locked = true

View file

@ -16,6 +16,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
console.error @toString(), 'needs a camera.' unless @camera
console.error @toString(), 'needs a layer.' unless @layer
@build()
@performShow = @show
@show = _.debounce @show, 125
Backbone.Mediator.subscribe(channel, @[func], @) for channel, func of @subscriptions
@ -46,6 +47,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
wop.y = Math.round(wop.y)
return if wop.x is @lastPos?.x and wop.y is @lastPos?.y
@lastPos = wop
@lastScreenPos = x: e.x, y: e.y
@hide()
@show() # debounced
@ -58,8 +60,11 @@ module.exports = class CoordinateDisplay extends createjs.Container
Backbone.Mediator.publish 'surface:coordinate-selected', wop
onZoomUpdated: (e) ->
@hide()
@show()
return unless @lastPos
wop = @camera.screenToWorld @lastScreenPos
@lastPos.x = Math.round wop.x
@lastPos.y = Math.round wop.y
@performShow() if @label.parent
onFlagColorSelected: (e) ->
@placingFlag = Boolean e.color

View file

@ -224,8 +224,8 @@ module.exports = class LankBoss extends CocoClass
item = @world.getThangByID itemID
unless item.equipped
console.log thang.id, 'equipping', item, 'in', thang.slot, 'Surface-side, but it cannot equip?' unless item.equip
item.equip()
itemsJustEquipped.push item
item.equip?()
itemsJustEquipped.push item if item.equip
return itemsJustEquipped
cacheObstacles: (updatedObstacles=null) ->

View file

@ -12,7 +12,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
for_developers: "适合开发者" # Not currently shown on home page.
nav:
play: "开始游戏" # The top nav bar entry where players choose which levels to play
play: "关卡选择" # The top nav bar entry where players choose which levels to play
community: "社区"
editor: "编辑器"
blog: "博客"
@ -98,7 +98,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
authenticate_gplus: "使用 G+ 授权"#Authenticate G+"
load_profile: "载入 G+ 档案" # Load G+ Profile"
load_email: "载入 G+ 电子邮件" #Load G+ Email"
finishing: "完成" #Finishing"
finishing: "完成..." #Finishing"
signup:
create_account_title: "创建一个账户来保存进度"
@ -243,13 +243,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
tome_select_a_thang: "选择人物来 "
tome_available_spells: "可用的法术"
tome_your_skills: "你的技能"
# tome_current_method: "Current Method"
tome_current_method: "当前方法"
hud_continue_short: "继续"
code_saved: "代码已保存"
skip_tutorial: "跳过esc"
keyboard_shortcuts: "快捷键"
loading_ready: "载入完成!"
loading_start: "关卡开始"
loading_start: "开战"
problem_alert_title: "修正你的代码"
time_current: "现在:"
time_total: "最大:"
@ -270,7 +270,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
tip_baby_coders: "在未来,就算小孩都能成为大法师."
tip_morale_improves: "在士气提升之前会一直进行读取."
tip_all_species: "我们相信学习编程的机会对任何种族都是平等的。"
# tip_reticulating: "Reticulating spines."
tip_reticulating: "网格状锯齿。(指 Maxis 开发的许多游戏,如《模拟城市》、《孢子》中,加载进程中跑动时出现的卡顿现象)"
tip_harry: "巫师, "
tip_great_responsibility: "更高的编程技巧也意味着更大的调试责任。"
tip_munchkin: "如果你不吃掉你的蔬菜, 一个小矮人将在你睡着之后来找你。"
@ -315,7 +315,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
equip: "装备"
unequip: "取消装备"
# buy_gems:
buy_gems:
few_gems: "几个宝石"
pile_gems: "一堆宝石"
chest_gems: "一箱宝石"
@ -324,7 +324,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
choose_hero: "请选择您的英雄"
programming_language: "编程语言"
programming_language_description: "您希望使用那门编程语言?"
# default: "默认"
default: "默认"
experimental: "实验性的"
python_blurb: "简单而强大, Python是一个伟大的通用编程语言。"
javascript_blurb: "为web开发而生的语言。"
@ -350,23 +350,23 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
granularity_change_history: "历史记录"
options:
# general_options: "General Options" # Check out the Options tab in the Game Menu while playing a level
general_options: "一般设置" # Check out the Options tab in the Game Menu while playing a level
volume_label: "音量"
music_label: "音乐"
music_description: "开/关背景音乐"
autorun_label: "自动运行"
# autorun_description: "Control automatic code execution."
autorun_description: "控制是否自动运行代码"
editor_config: "编辑器配置"
editor_config_title: "编辑器配置"
editor_config_level_language_label: "这个等级的语言"
# editor_config_level_language_description: "Define the programming language for this particular level."
editor_config_level_language_label: "本关卡编程语言"
editor_config_level_language_description: "针对本关设定使用的编程语言。"
editor_config_default_language_label: "默认编程语言"
editor_config_default_language_description: "在开始新游戏前确认你要在这个等级的游戏中使用的编程语言。"
editor_config_keybindings_label: "按键设置s"
editor_config_keybindings_label: "快捷键绑定"
editor_config_keybindings_default: "默认 (Ace)"
editor_config_keybindings_description: "在命令编辑器中增加已知的快捷键。"
# editor_config_livecompletion_label: "Live Autocompletion"
# editor_config_livecompletion_description: "Displays autocomplete suggestions while typing."
editor_config_livecompletion_label: "实时代码补全"
editor_config_livecompletion_description: "当输入代码时显示代码自动补全建议。"
editor_config_invisibles_label: "显示空白字符"
editor_config_invisibles_description: "显示空格或TAB键等空白字符。"
editor_config_indentguides_label: "显示缩进提示"
@ -376,8 +376,8 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
about:
why_codecombat: "为什么选择 CodeCombat?"
why_paragraph_1: "你想学编程?你不用上课。你需要的是写好多代码,并且享受这个过程。"
why_paragraph_2_prefix: "这才是编程的要义。编程必须要好玩。不"
why_paragraph_1: "如果你想学习如何编程,你根本不需要上课。你需要的是写好多代码,并且享受这个过程。"
why_paragraph_2_prefix: "这才是编程的要义。编程应该是有趣的过程。不该"
why_paragraph_2_italic: "哇又一个奖章诶"
why_paragraph_2_center: "那种“好玩”,而是"
why_paragraph_2_italic_caps: "老妈,我得先把这关打完!"
@ -388,16 +388,16 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
press_paragraph_1_link: "成套宣传包"
press_paragraph_1_suffix: "里的所有材料. 所有商标和图像的使用都不必事先联系我们。"
team: "团队"
# george_title: "CEO"
# george_blurb: "Businesser"
# scott_title: "Programmer"
# scott_blurb: "Reasonable One"
# nick_title: "Programmer"
# nick_blurb: "Motivation Guru"
# michael_title: "Programmer"
# michael_blurb: "Sys Admin"
# matt_title: "Programmer"
# matt_blurb: "Bicyclist"
george_title: "CEO"
george_blurb: "商人"
scott_title: "程序员"
scott_blurb: "理性至上"
nick_title: "程序员"
nick_blurb: "充满动力的大牛"
michael_title: "程序员"
michael_blurb: "系统管理员"
matt_title: "程序员"
matt_blurb: "自行车爱好者"
versions:
save_version_title: "保存新版本"
@ -461,22 +461,22 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
wizard_color: "巫师 衣服 颜色"
keyboard_shortcuts:
keyboard_shortcuts: ""
keyboard_shortcuts: "快捷"
space: "空格"
enter: "回车"
escape: "Esc"
shift: "Shift"
run_code: "运行当前代码"
run_real_time: "实时运行"
# continue_script: "Continue past current script."
# skip_scripts: "Skip past all skippable scripts."
continue_script: "继续运行当前脚本。"
skip_scripts: "跳过所有能跳过的脚本。"
toggle_playback: "继续/暂停按钮"
# scrub_playback: "Scrub back and forward through time."
# single_scrub_playback: "Scrub back and forward through time by a single frame."
# scrub_execution: "Scrub through current spell execution."
# toggle_debug: "Toggle debug display."
# toggle_grid: "Toggle grid overlay."
# toggle_pathfinding: "Toggle pathfinding overlay."
scrub_playback: "向前/向后移动一段时间"
single_scrub_playback: "向前/向后移动一帧"
scrub_execution: "向前/向后移动一句语句"
toggle_debug: "显示/关闭调试信息"
toggle_grid: "显示/关闭网格提示"
toggle_pathfinding: "显示/关闭路径寻找提示"
beautify: "利用标准编码格式美化你的代码。"
maximize_editor: "最大化/最小化代码编辑器"
move_wizard: "在关卡中移动你的巫师角色。"
@ -486,7 +486,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
introduction: "看看下面这些你可以参与的项目,如果有你喜欢的就加入进来吧。 我们期待着与您一起工作。"
level_editor_prefix: "使用"
level_editor_suffix: "来创建和编辑关卡。你可以通过这个工具来给你的同学,朋友,兄弟姐妹们设计谜题,或者用于教学或比赛。如果你觉得直接开始建立一个关卡可能非常困难,那么可以先从一个现成(但尚未完成)的关卡开始做起。"
thang_editor_prefix: "我们管游戏中的单位叫 '实体'。 利用"
thang_editor_prefix: "我们管游戏中的单位叫 '物品'。 利用"
thang_editor_suffix: "来改良 CodeCombat 中的原材料。让游戏中的东西可以被捡起来扔出去,改变游戏动画的指向,调整一些东西的生命值,或上传您自制的素材。"
article_editor_prefix: "你在游戏中发现了错误了吗?想要自己设计一些指令吗?来看看我们的"
article_editor_suffix: "来帮助玩家从游戏中学到更多的知识。"
@ -516,7 +516,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
editor:
main_title: "CodeCombat 编辑器"
article_title: "指令编辑器"
thang_title: "实体编辑器"
thang_title: "物品编辑器"
level_title: "关卡编辑器"
achievement_title: "目标编辑器"
back: "后退"
@ -527,7 +527,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
grassy: "草地"
fork_title: "派生新版本"
fork_creating: "正在执行派生..."
# generate_terrain: "Generate Terrain"
generate_terrain: "Generate Terrain"
more: "更多"
wiki: "维基"
live_chat: "在线聊天"
@ -537,14 +537,14 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
level_tab_settings: "设定"
level_tab_components: "组件"
level_tab_systems: "系统"
# level_tab_docs: "Documentation"
level_tab_docs: "文档"
level_tab_thangs_title: "目前所有物体"
level_tab_thangs_all: "所有"
level_tab_thangs_conditions: "启动条件"
level_tab_thangs_add: "增加物体"
delete: "删除"
duplicate: "复制"
# rotate: "Rotate"
rotate: "旋转"
level_settings_title: "设置"
level_component_tab_title: "目前所有组件"
level_component_btn_new: "创建新的组件"
@ -564,7 +564,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
new_thang_title: "创建一个新物品类型"
new_level_title: "创建一个新关卡"
new_article_title_login: "登录以创建新指令"
new_thang_title_login: "登录以创建新实体"
new_thang_title_login: "登录以创建新物品"
new_level_title_login: "登录以创建新关卡"
new_achievement_title: "创建新目标"
new_achievement_title_login: "登录以创建新目标"
@ -577,7 +577,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
# achievement_query_misc: "Key achievement off of miscellanea"
# achievement_query_goals: "Key achievement off of level goals"
level_completion: "关卡完成"
# pop_i18n: "Populate I18N"
pop_i18n: "填写 I18N"
article:
edit_btn_preview: "预览"
@ -611,12 +611,12 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
archmage_subscribe_desc: "通过电子邮件获得新的编码机会和公告。"
artisan_summary_pref: "想要设计 CodeCombat 的关卡吗人们玩的比我们做的快多了现在我们的关卡编辑器还很基本所以做起关卡来会有点麻烦还会有bug。只要你有制作关卡的灵感不管是简单的for循环还是"
artisan_summary_suf: "这种东西,这个职业都很适合你。"
# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to"
# artisan_introduction_suf: ", then this class might be for you."
# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!"
# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix."
# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!"
# artisan_join_desc: "Use the Level Editor in these steps, give or take:"
artisan_introduction_pref: "我们必须设计更多的关卡! 大家为了更多的游戏内容在高声呐喊但是我们靠自己只能创建这些。现在你的电脑就是一关我们的关卡编辑器刚刚完成了基本功能所以创造关卡的时候请小心使用。只要你有制作关卡的灵感不管是简单的for循环还是"
artisan_introduction_suf: "这种东西,这个职业都很适合你。"
artisan_attribute_1: "任何类似的创建内容经验都有加分,无论是暴雪的关卡编辑器,但这不是必须的条件。"
artisan_attribute_2: "渴望完成全部的测试和迭代。要做一个优秀的关卡,你需要把它给别的玩家观察他们怎么玩,然后时刻准备着找到很多细节去打磨。"
artisan_attribute_3: "探险家般的忍耐力。我们的关卡编辑器非常的初级,还会有很多不好用的地方。唔,我已经提前告诉你了~"
artisan_join_desc: "如下步骤使用关卡编辑器:"
artisan_join_step1: "阅读文档."
artisan_join_step2: "创建一个新关卡 以及探索已经存在的关卡."
artisan_join_step3: "来我们的 HipChat 聊天室寻求帮助."
@ -649,7 +649,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
diplomat_attribute_1: "既会说流利的英语,也熟悉自己的语言。编程是一件很复杂的事情,而要翻译复杂的概念,你必须对两种语言都在行!"
diplomat_i18n_page_prefix: "你可以在我们的"
diplomat_i18n_page: "翻译页面"
diplomat_i18n_page_suffix: "开始翻译游戏,或者在GibHub我们的页面上进行。"
diplomat_i18n_page_suffix: "开始翻译游戏,或者在 GitHub 我们的页面上进行。"
diplomat_join_pref_github: ""
diplomat_github_url: " GitHub "
diplomat_join_suf_github: "找到你的语言文件 (中文的是: codecombat/app/locale/zh-HNAS.coffee),在线编辑它,然后提交一个合并请求。同时,选中下面这个复选框来关注最新的国际化开发!"
@ -675,13 +675,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
please_login: "请在对奕之前先登录."
my_matches: "我的对手"
simulate: "模拟"
# simulation_explanation: "By simulating games you can get your game ranked faster!"
simulate_games: "模拟游戏!"
# simulate_all: "RESET AND SIMULATE GAMES"
# games_simulated_by: "Games simulated by you:"
# games_simulated_for: "Games simulated for you:"
# games_simulated: "Games simulated"
# games_played: "Games played"
simulation_explanation: "通过模拟游戏,你可以让你的游戏更快的得到评分。"
simulate_games: "模拟游戏"
simulate_all: "重置并模拟游戏!"
games_simulated_by: "你模拟玩过的游戏:"
games_simulated_for: "待你模拟玩的游戏:"
games_simulated: "游戏已模拟"
games_played: "已玩过"
# ratio: "Ratio"
leaderboard: "排行榜"
battle_as: "我要加入这一方 "
@ -692,13 +692,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
rank_no_code: "没有新代码可供评分"
rank_my_game: "为我的游戏评分!"
rank_submitting: "正在提交..."
# rank_submitted: "Submitted for Ranking"
rank_submitted: "提交评分"
rank_failed: "评分失败"
rank_being_ranked: "已评价"
rank_last_submitted: "已提交"
# help_simulate: "Help simulate games?"
# code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in."
# no_ranked_matches_pre: "No ranked matches for the "
help_simulate: "模拟游戏需要帮助?"
code_being_simulated: "你的新代码正在被其他玩家模拟评分。这个将会刷新,作为一个新游戏开始。"
# no_ranked_matches_pre: "No ranked matches for the "
# no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked."
choose_opponent: "选择一个对手"
select_your_language: "选择你使用的语言!"
@ -714,13 +714,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
social_connect_blurb: "连接然后与朋友对战!"
invite_friends_to_battle: "邀请你的朋友参加战斗!"
fight: "战斗!"
# watch_victory: "Watch your victory"
# defeat_the: "Defeat the"
watch_victory: "观看你的胜利"
defeat_the: "击败了"
# tournament_ends: "Tournament ends"
# tournament_ended: "Tournament ended"
# tournament_rules: "Tournament Rules"
tournament_rules: "锦标赛规则"
# tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details"
# tournament_blurb_criss_cross: "Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details"
tournament_blurb_criss_cross: "赢得竞拍,建造道路,智胜对手,夺取宝石,在纵横交错锦标赛中完成生涯晋级! 现在就查看详情!"
# tournament_blurb_blog: "on our blog"
rules: "规则"
winners: "胜利者"
@ -745,16 +745,16 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
amount_achieved: "数量"
achievement: "成就"
category_contributor: "贡献"
# category_miscellaneous: "Miscellaneous"
category_miscellaneous: "其他"
category_levels: "等级"
# category_undefined: "Uncategorized"
# current_xp_prefix: ""
# current_xp_postfix: " in total"
# new_xp_prefix: ""
new_xp_postfix: "获取"
# left_xp_prefix: ""
# left_xp_infix: " until level "
# left_xp_postfix: ""
category_undefined: "未分类"
current_xp_prefix: "当前总共"
current_xp_postfix: "经验"
new_xp_prefix: "获得"
new_xp_postfix: "经验"
left_xp_prefix: "还需要"
left_xp_infix: "经验"
left_xp_postfix: "到下一等级"
account:
recently_played: "最近玩过的关卡"
@ -787,25 +787,25 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
user_schema: "用户模式"
user_profile: "用户信息"
patches: "补丁"
# patched_model: "Source Document"
# model: "Model"
# system: "System"
# systems: "Systems"
# component: "Component"
# components: "Components"
# thang: "Thang"
# thangs: "Thangs"
patched_model: "源文档"
model: "型号"
system: "系统"
systems: "系统"
component: "组件"
components: "组件"
thang: "物品"
thangs: "物品"
# level_session: "Your Session"
# opponent_session: "Opponent Session"
# article: "Article"
article: "文章"
user_names: "用户名"
# thang_names: "Thang Names"
thang_names: "物品名称"
files: "文件"
# top_simulators: "Top Simulators"
# source_document: "Source Document"
# document: "Document"
# sprite_sheet: "Sprite Sheet"
# employers: "Employers"
document: "文档"
sprite_sheet: "SpriteSheet"
employers: "Employers"
# candidates: "Candidates"
# candidate_sessions: "Candidate Sessions"
# user_remark: "User Remark"
@ -944,23 +944,23 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
done_editing: "完成编辑"
profile_for_prefix: "关于他的基本资料:"
profile_for_suffix: ""
# featured: "Featured"
# not_featured: "Not Featured"
featured: "被推荐"
not_featured: "未入选"
looking_for: "寻找"
last_updated: "最后一次更新:"
contact: "联系"
active: "正期待面试offer"
inactive: "并不期待面试offer"
# complete: "complete"
# next: "Next"
# next_city: "city?"
# next_country: "pick your country."
# next_name: "name?"
# next_short_description: "write a short description."
# next_long_description: "describe your desired position."
# next_skills: "list at least five skills."
# next_work: "chronicle your work history."
# next_education: "recount your educational ordeals."
complete: "完成"
next: "下一步"
next_city: "城市?"
next_country: "选择你的城市。"
next_name: "姓名?"
next_short_description: "写一个简短的描述"
next_long_description: "描述你渴望的职位。"
next_skills: "列出至少五个技能。"
next_work: "你的过往工作经验"
next_education: "教育经历"
# next_projects: "show off up to three projects you've worked on."
# next_links: "add any personal or social links."
# next_photo: "add an optional professional photo."

View file

@ -50,6 +50,7 @@ visa = c.shortString
_.extend UserSchema.properties,
email: c.shortString({title: 'Email', format: 'email'})
iosIdentifierForVendor: c.shortString({format: 'hidden'})
firstName: c.shortString({title: 'First Name'})
lastName: c.shortString({title: 'Last Name'})
gender: {type: 'string', 'enum': ['male', 'female']}

View file

@ -218,7 +218,7 @@ $level-resize-transition-time: 0.5s
#stop-real-time-playback-button
display: none
position: absolute
bottom: 40px
bottom: 70px
right: 15px
font-size: 30px

View file

@ -23,6 +23,7 @@
left: 40px
width: 160px
text-align: center
cursor: pointer
a.levels-link
margin: 0
@ -38,8 +39,11 @@
color: $control-yellow
text-shadow: 1px 1px 0px rgb(143, 123, 62)
&:hover .glyphicon
color: $control-yellow-highlight
&:hover
a.levels-link
text-decoration: underline
.glyphicon
color: $control-yellow-highlight
.left-cap, .right-cap, .center-chain, .right-chain, .wood-background
position: absolute

View file

@ -612,10 +612,32 @@ forest = [
original: '5446cb40ce01c23e05ecf027'
description: 'Stay alive and navigate through the forest.'
nextLevels:
continue: 'thornbush-farm'
continue: 'endangered-burl'
x: 39.03
y: 54.97
}
{
name: 'Endangered Burl'
type: 'hero'
id: 'endangered-burl'
original: ''
description: 'Hunt ogres in the woods, but watch out for lumbering beasts.'
nextLevels:
continue: 'village-guard'
x: 41.09
y: 43.75
}
{
name: 'Village Guard'
type: 'hero'
id: 'village-guard'
original: '546e91b8a4b7840000ee92dc'
description: 'Defend a village from marauding munchkin mayhem.'
nextLevels:
continue: 'thornbush-farm'
x: 48.09
y: 42.75
}
{
name: 'Thornbush Farm'
type: 'hero'

View file

@ -7,6 +7,7 @@ RealTimeModel = require 'models/RealTimeModel'
RealTimeCollection = require 'collections/RealTimeCollection'
LevelSetupManager = require 'lib/LevelSetupManager'
GameMenuModal = require 'views/game-menu/GameMenuModal'
CampaignOptions = require 'lib/CampaignOptions'
module.exports = class ControlBarView extends CocoView
id: 'control-bar-view'
@ -22,6 +23,7 @@ module.exports = class ControlBarView extends CocoView
'click #next-game-button': -> Backbone.Mediator.publish 'level:next-game-pressed', {}
'click #game-menu-button': 'showGameMenuModal'
'click': -> Backbone.Mediator.publish 'tome:focus-editor', {}
'click .levels-link-area': 'onClickHome'
'click .home a': 'onClickHome'
'click .multiplayer-area': 'onClickMultiplayer'
@ -66,7 +68,7 @@ module.exports = class ControlBarView extends CocoView
else if @level.get('type', true) in ['hero', 'hero-coop']
@homeLink = c.homeLink = '/play'
@homeViewClass = require 'views/play/WorldMapView'
campaign = @getCampaignForSlug @level.get 'slug'
campaign = CampaignOptions.getCampaignForSlug @level.get 'slug'
if campaign isnt 'dungeon'
@homeLink += '/' + campaign
@homeViewArgs.push campaign
@ -101,11 +103,6 @@ module.exports = class ControlBarView extends CocoView
@controlsEnabled = enabled
@$el.toggleClass 'controls-disabled', not enabled
getCampaignForSlug: (slug) ->
for campaign in require('views/play/WorldMapView').campaigns
for level in campaign.levels
return campaign.id if level.id is slug
onIPadMemoryWarning: (e) ->
@hasReceivedMemoryWarning = true
@ -142,7 +139,7 @@ class MultiplayerStatusManager
# @playersCollection?.off 'add', @onPlayerAdded
# player.off 'change', @onPlayerChanged for id, player of @players
onMultiplayerPlayerStatus: (e) =>
onMultiplayerPlayerStatus: (e) =>
@status = e.status
@statusChangedCallback()
@ -151,10 +148,10 @@ class MultiplayerStatusManager
# @players[player.id] = new RealTimeModel('multiplayer_players/' + @levelID + '/' + player.id)
# @players[player.id].on 'change', @onPlayerChanged
# @countPlayers player
#
#
# onPlayerChanged: (player) =>
# @countPlayers player
#
#
# countPlayers: (changedPlayer) =>
# # TODO: save this stale hearbeat threshold setting somewhere
# staleHeartbeat = new Date()

View file

@ -8,6 +8,7 @@ utils = require 'lib/utils'
ThangType = require 'models/ThangType'
LadderSubmissionView = require 'views/play/common/LadderSubmissionView'
AudioPlayer = require 'lib/AudioPlayer'
CampaignOptions = require 'lib/CampaignOptions'
module.exports = class HeroVictoryModal extends ModalView
id: 'hero-victory-modal'
@ -265,16 +266,11 @@ module.exports = class HeroVictoryModal extends ModalView
for level in campaign.levels
return level if level.id is slug
getCampaignForSlug: (slug) ->
for campaign in require('views/play/WorldMapView').campaigns
for level in campaign.levels
return campaign.id if level.id is slug
getNextLevelCampaign: ->
# Wouldn't handle skipping/more practice across campaign boundaries, but we don't do that.
campaign = @getCampaignForSlug @level.get 'slug'
campaign = CampaignOptions.getCampaignForSlug @level.get 'slug'
if nextLevelSlug = @getNextLevel 'continue'
campaign = @getCampaignForSlug nextLevelSlug
campaign = CampaignOptions.getCampaignForSlug nextLevelSlug
campaign or 'dungeon'
getNextLevelLink: (type) ->

View file

@ -9,6 +9,7 @@ SpellDebugView = require './SpellDebugView'
SpellToolbarView = require './SpellToolbarView'
LevelComponent = require 'models/LevelComponent'
UserCodeProblem = require 'models/UserCodeProblem'
CampaignOptions = require 'lib/CampaignOptions'
LevelOptions = require 'lib/LevelOptions'
module.exports = class SpellView extends CocoView
@ -216,6 +217,7 @@ module.exports = class SpellView extends CocoView
# TODO: Turn on more autocompletion based on level sophistication
# TODO: E.g. using the language default snippets yields a bunch of crazy non-beginner suggestions
# TODO: Options logic shouldn't exist both here and in updateAutocomplete()
popupFontSizePx = CampaignOptions.getOption(@options.level.get('slug'), 'autocompleteFontSizePx') ? 16
@zatanna = new Zatanna @ace,
basic: false
liveCompletion: false
@ -226,7 +228,7 @@ module.exports = class SpellView extends CocoView
text: @autocomplete
autoLineEndings:
javascript: ';'
popupFontSizePx: 16
popupFontSizePx: popupFontSizePx
popupWidthPx: 380
updateAutocomplete: (@autocomplete) ->
@ -253,7 +255,7 @@ module.exports = class SpellView extends CocoView
if doc?.snippets?[e.language]
entry =
content: doc.snippets[e.language].code
meta: 'press enter'
meta: 'press tab'
name: doc.name
tabTrigger: doc.snippets[e.language].tab
if doc.name is 'findNearestEnemy'

View file

@ -10,7 +10,7 @@ hipchat = require '../hipchat'
deltasLib = require '../../app/lib/deltas'
PROJECT = {original: 1, name: 1, version: 1, description: 1, slug: 1, kind: 1, created: 1, permissions: 1}
FETCH_LIMIT = 500
FETCH_LIMIT = 1000 # So many ThangTypes
module.exports = class Handler
# subclasses should override these properties

View file

@ -15,7 +15,14 @@ module.exports.setup = (app) ->
authentication.use(new LocalStrategy(
(username, password, done) ->
User.findOne({emailLower: username.toLowerCase()}).exec((err, user) ->
# kind of a hacky way to make it possible for iPads to 'log in' with their unique device id
if username.length is 36 and '@' not in username # must be an identifier for vendor
q = { iosIdentifierForVendor: username }
else
q = { emailLower: username.toLowerCase() }
User.findOne(q).exec((err, user) ->
return done(err) if err
return done(null, false, {message: 'not found', property: 'email'}) if not user
passwordReset = (user.get('passwordReset') or '').toLowerCase()

View file

@ -96,7 +96,7 @@ UserSchema.statics.updateMailChimp = (doc, callback) ->
params.email = if existingProps then {leid: existingProps.leid} else {email: doc.get('email')}
params.merge_vars = {groupings: [{id: mail.MAILCHIMP_GROUP_ID, groups: newGroups}]}
params.update_existing = true
params.double_optin = false
params.double_optin = true
onSuccess = (data) ->
doc.set('mailChimp', data)
@ -200,7 +200,7 @@ UserSchema.statics.editableProperties = [
'firstName', 'lastName', 'gender', 'facebookID', 'gplusID', 'emails',
'testGroupNumber', 'music', 'hourOfCode', 'hourOfCodeComplete', 'preferredLanguage',
'wizard', 'aceConfig', 'autocastDelay', 'lastLevel', 'jobProfile', 'savedEmployerFilterAlerts',
'heroConfig'
'heroConfig', 'iosIdentifierForVendor'
]
UserSchema.plugin plugins.NamedPlugin

View file

@ -15,7 +15,31 @@ describe '/auth/whoami', ->
describe '/auth/login', ->
it 'clears Users first', (done) ->
it 'clears Users', (done) ->
clearModels [User], (err) ->
throw err if err
request.get getURL('/auth/whoami'), ->
throw err if err
done()
it 'allows logging in by iosIdentifierForVendor', (done) ->
req = request.post(getURL('/db/user'),
(error, response) ->
expect(response).toBeDefined()
expect(response.statusCode).toBe(200)
req = request.post(urlLogin, (error, response) ->
expect(response.statusCode).toBe(200)
done()
)
form = req.form()
form.append('username', '012345678901234567890123456789012345')
form.append('password', '12345')
)
form = req.form()
form.append('iosIdentifierForVendor', '012345678901234567890123456789012345')
form.append('password', '12345')
it 'clears Users', (done) ->
clearModels [User], (err) ->
throw err if err
request.get getURL('/auth/whoami'), ->
@ -84,7 +108,7 @@ describe '/auth/reset', ->
form = req.form()
form.append('username', 'scott@gmail.com')
it 'can\'t reset an unknow user', (done) ->
it 'can\'t reset an unknown user', (done) ->
req = request.post(urlReset, (error, response) ->
expect(response).toBeDefined()
expect(response.statusCode).toBe(404)