mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-24 08:08:15 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
8f40d1f5e2
22 changed files with 236 additions and 127 deletions
|
@ -88,6 +88,8 @@ module.exports = class LevelLoader extends CocoClass
|
|||
@listenToOnce @opponentSession, 'sync', @loadDependenciesForSession
|
||||
|
||||
loadDependenciesForSession: (session) ->
|
||||
if me.id isnt session.get 'creator'
|
||||
session.patch = session.save = -> console.error "Not saving session, since we didn't create it."
|
||||
if session is @session
|
||||
codeLanguage = session.get('codeLanguage') or me.get('aceConfig')?.language or 'python'
|
||||
modulePath = "vendor/aether-#{codeLanguage}"
|
||||
|
@ -136,6 +138,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
@onWorldNecessitiesLoaded()
|
||||
|
||||
addSessionBrowserInfo: (session) ->
|
||||
return unless me.id is session.get 'creator'
|
||||
return unless $.browser?
|
||||
browser = {}
|
||||
browser['desktop'] = $.browser.desktop if $.browser.desktop
|
||||
|
|
|
@ -78,7 +78,7 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
|
|||
awaiting_levels_adventurer_prefix: "Wir veröffentlichen fünf Levels pro Woche."
|
||||
awaiting_levels_adventurer: "Registriere dich als ein Abenteurer"
|
||||
awaiting_levels_adventurer_suffix: "sei der Erste, der neue Levels spielt."
|
||||
# adjust_volume: "Adjust volume"
|
||||
adjust_volume: "Lautstärke anpassen"
|
||||
choose_your_level: "Wähle dein Level" # The rest of this section is the old play view at /play-old and isn't very important.
|
||||
adventurer_prefix: "Du kannst zu jedem Level springen oder diskutiere die Level "
|
||||
adventurer_forum: "im Abenteurerforum"
|
||||
|
@ -157,10 +157,10 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
|
|||
date: "Datum"
|
||||
body: "Inhalt"
|
||||
version: "Version"
|
||||
# pending: "Pending"
|
||||
# accepted: "Accepted"
|
||||
# rejected: "Rejected"
|
||||
# withdrawn: "Withdrawn"
|
||||
pending: "ausstehend"
|
||||
accepted: "akzeptiert"
|
||||
rejected: "abgelehnt"
|
||||
withdrawn: "zurückgezogen"
|
||||
submitter: "Übermittler"
|
||||
submitted: "Übermittelt"
|
||||
commit_msg: "Übertrage Nachricht"
|
||||
|
@ -168,10 +168,10 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
|
|||
version_history: "Versionshistorie"
|
||||
version_history_for: "Versionsgeschichte für: "
|
||||
select_changes: "Wähle zwei Änderungen unten um den Unterschied sehen zu können."
|
||||
# undo_prefix: "Undo"
|
||||
# undo_shortcut: "(Ctrl+Z)"
|
||||
undo_prefix: "Rückgängig"
|
||||
undo_shortcut: "(Strg+Z)"
|
||||
# redo_prefix: "Redo"
|
||||
# redo_shortcut: "(Ctrl+Shift+Z)"
|
||||
redo_shortcut: "(Strg+Umschalt+Z)"
|
||||
play_preview: "Spiele eine Vorschau des momentanen Levels"
|
||||
result: "Ergebnis"
|
||||
results: "Ergebnisse"
|
||||
|
@ -370,9 +370,9 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
|
|||
unsubscribe: "Abmelden"
|
||||
# confirm_unsubscribe: "Confirm Unsubscribe"
|
||||
# never_mind: "Never Mind, I Still Love You"
|
||||
# thank_you_months_prefix: "Thank you for supporting us these last"
|
||||
# thank_you_months_suffix: "months."
|
||||
# thank_you: "Thank you for supporting CodeCombat."
|
||||
thank_you_months_prefix: "Danke für deine Unterstützung in den letzten"
|
||||
thank_you_months_suffix: "Monaten."
|
||||
thank_you: "Danke das du CodeCombat unterstützt."
|
||||
# sorry_to_see_you_go: "Sorry to see you go! Please let us know what we could have done better."
|
||||
# unsubscribe_feedback_placeholder: "O, what have we done?"
|
||||
levels: "25 weitere level! Und 5 neue jede Woche!"
|
||||
|
@ -627,7 +627,7 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
|
|||
# desert: "Desert"
|
||||
grassy: "Grasig"
|
||||
small: "Klein"
|
||||
# large: "Large"
|
||||
large: "Groß"
|
||||
fork_title: "Forke neue Version"
|
||||
fork_creating: "Erzeuge Fork..."
|
||||
generate_terrain: "Generiere Terrain"
|
||||
|
@ -648,7 +648,7 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
|
|||
level_tab_thangs_all: "Alle"
|
||||
level_tab_thangs_conditions: "Startbedingungen"
|
||||
level_tab_thangs_add: "Thangs hinzufügen"
|
||||
# add_components: "Add Components"
|
||||
add_components: "Kommentar hinzufügen"
|
||||
# component_configs: "Component Configurations"
|
||||
# config_thang: "Double click to configure a thang"
|
||||
delete: "Löschen"
|
||||
|
|
|
@ -503,6 +503,46 @@
|
|||
matt_title: "Programmer"
|
||||
matt_blurb: "Bicyclist"
|
||||
|
||||
teachers:
|
||||
title: "CodeCombat for Teachers"
|
||||
preparation_title: "Preparation"
|
||||
preparation_1: "CodeCombat is free to play for the core level progression and does not require students to sign up. We encourage teachers to"
|
||||
preparation_play_campaign: "play through the campaign"
|
||||
preparation_2: "to try it out, but the only thing you absolutely need to do to be ready is ensure students have access to a computer."
|
||||
preparation_3: "It is not necessary for teachers to be comfortable with computer science concepts for students to have fun learning with CodeCombat."
|
||||
violent_title: "Is it violent?"
|
||||
violent_1: "We get this from teachers a lot due to our name. Although CodeCombat does contain cartoon violence, there is nothing graphic in either the visuals or language."
|
||||
violent_2: "If you are comfortable having your students play Angry Birds, you will be comfortable with CodeCombat."
|
||||
for_girls_title: "Is it for girls?"
|
||||
for_girls_1: "There are three game modes in CodeCombat: building, puzzles, and combat. We have intentionally designed each to appeal to both boys and girls and think that the building and puzzle levels especially differentiate the game from violent triple A titles that repel female players."
|
||||
what_cover_title: "What do we cover?"
|
||||
what_cover_1: "There are 20 levels in the Hour of Code tutorial that teach and reinforce 6 specific computer science concepts:"
|
||||
what_cover_notation_1: "Formal notation"
|
||||
what_cover_notation_2: "- builds an understanding of the importance of syntax in programming."
|
||||
what_cover_methods_1: "Calling methods"
|
||||
what_cover_methods_2: "- familiarizes students with the syntax of object-oriented method calls."
|
||||
what_cover_parameters_1: "Parameters"
|
||||
what_cover_parameters_2: "- trains how to pass parameters to functions."
|
||||
what_cover_strings_1: "Strings"
|
||||
what_cover_strings_2: "- teaches students about string notation and passing strings as parameters."
|
||||
what_cover_loops_1: "Loops"
|
||||
what_cover_loops_2: "- develops the abstraction of designing short programs with loops."
|
||||
what_cover_variables_1: "Variables"
|
||||
what_cover_variables_2: "- adds the skill of referencing values that change over time."
|
||||
what_cover_2: "Students may continue past level 20, depending on their speed and interest, to learn two additional concepts in later levels:"
|
||||
what_cover_logic_1: "Conditional logic"
|
||||
what_cover_logic_2: "- when and how to use if/else to control in-game outcomes."
|
||||
what_cover_input_1: "Handling player input"
|
||||
what_cover_input_2: "- responding to input events to create a user interface."
|
||||
sys_requirements_title: "System Requirements"
|
||||
sys_requirements_1: "Because CodeCombat is a game, it is more intensive for computers to run smoothly than video or written tutorials. We have optimized it to run quickly on all modern browsers and on older machines so that everyone can play. That said, here are our suggestions for getting the most out of your Hour of Code experience:"
|
||||
sys_requirements_2: "Use newer versions of Chrome or Firefox."
|
||||
sys_requirements_3: "Although CodeCombat will work on browsers as old as IE9, the performance is not as good. Chrome is best."
|
||||
sys_requirements_4: "Use newer computers."
|
||||
sys_requirements_5: "Older computers, Chromebooks, and netbooks tend to have very few system resources, which makes for a less enjoyable experience. At least 2GB of RAM is required."
|
||||
sys_requirements_6: "Allow players to wear headphones/earbuds to hear the audio."
|
||||
sys_requirements_7: "We help players learn through voiceover and sound effects, which will make classrooms noisy and distracting."
|
||||
|
||||
versions:
|
||||
save_version_title: "Save New Version"
|
||||
new_major_version: "New Major Version"
|
||||
|
|
|
@ -342,7 +342,7 @@ _.extend LevelSchema.properties,
|
|||
type: 'string', links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], format: 'latest-version-original-reference'
|
||||
}}
|
||||
campaign: c.shortString title: 'Campaign', description: 'Which campaign this level is part of (like "desert").', format: 'hidden' # Automatically set by campaign editor.
|
||||
scoreTypes: c.array {title: 'Score Types', description: 'What metric to show leaderboards for.'},
|
||||
scoreTypes: c.array {title: 'Score Types', description: 'What metric to show leaderboards for.', uniqueItems: true},
|
||||
c.shortString(title: 'Score Type', 'enum': ['time', 'damage-taken', 'damage-dealt', 'gold-collected', 'difficulty']) # TODO: good version of LoC; total gear value.
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,3 @@
|
|||
float: right
|
||||
width: 300px
|
||||
margin-left: 20px
|
||||
|
||||
.cc-license-link
|
||||
margin-left: 10px
|
|
@ -16,17 +16,21 @@
|
|||
th
|
||||
text-align: center
|
||||
|
||||
.rank-cell
|
||||
font-weight: bold
|
||||
tbody
|
||||
tr.viewable
|
||||
cursor: pointer
|
||||
|
||||
.name-col-cell
|
||||
max-width: 150px
|
||||
white-space: nowrap
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
.rank-cell
|
||||
font-weight: bold
|
||||
|
||||
.hero-portrait-cell, .code-language-cell
|
||||
background: transparent url(/images/common/code_languages/javascript_small.png) no-repeat center center
|
||||
padding: 0 9px
|
||||
background-size: 30px 30px
|
||||
height: 30px
|
||||
.name-col-cell
|
||||
max-width: 150px
|
||||
white-space: nowrap
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
|
||||
.hero-portrait-cell, .code-language-cell
|
||||
background: transparent url(/images/common/code_languages/javascript_small.png) no-repeat center center
|
||||
background-size: 30px 30px
|
||||
height: 30px
|
||||
width: 32px
|
||||
|
|
|
@ -68,8 +68,7 @@ block content
|
|||
p(data-i18n="about.george_blurb")
|
||||
| Businesser
|
||||
|
||||
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
|
||||
|
||||
.team_bio
|
||||
|
||||
|
@ -122,5 +121,3 @@ block content
|
|||
| Programmer
|
||||
p(data-i18n="about.matt_blurb")
|
||||
| Bicyclist
|
||||
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@ block content
|
|||
| dozens of open source projects, and we love them. See
|
||||
a(href="https://github.com/codecombat/codecombat/wiki/Archmage-Home", data-i18n="legal.archmage_wiki_url")
|
||||
| our Archmage wiki
|
||||
span
|
||||
span(data-i18n="legal.opensource_description_suffix")
|
||||
span.spl(data-i18n="legal.opensource_description_suffix")
|
||||
| for a list of the software that makes this game possible.
|
||||
hr
|
||||
|
||||
|
@ -43,13 +42,11 @@ block content
|
|||
h4(data-i18n="legal.email_title")
|
||||
| Email
|
||||
p
|
||||
span(data-i18n="legal.email_description_prefix")
|
||||
span.spr(data-i18n="legal.email_description_prefix")
|
||||
| We will not inundate you with spam. Through
|
||||
span
|
||||
a(href='/account/settings', data-i18n="legal.email_settings_url")
|
||||
| your email settings
|
||||
span
|
||||
span(data-i18n="legal.email_description_suffix")
|
||||
span.spl(data-i18n="legal.email_description_suffix")
|
||||
| or through links in the emails we send,
|
||||
| you can change your preferences and easily unsubscribe at any time.
|
||||
h4(data-i18n="legal.cost_title")
|
||||
|
@ -64,9 +61,8 @@ block content
|
|||
| Contributor License Agreement
|
||||
|
||||
p
|
||||
span(data-i18n="legal.contributor_description_prefix")
|
||||
span.spr(data-i18n="legal.contributor_description_prefix")
|
||||
| All contributions, both on the site and on our GitHub repository, are subject to our
|
||||
span
|
||||
a(href="/cla", data-i18n="legal.cla_url")
|
||||
| CLA
|
||||
span ,
|
||||
|
@ -77,11 +73,10 @@ block content
|
|||
| Code - MIT
|
||||
|
||||
p
|
||||
span(data-i18n="legal.code_description_prefix")
|
||||
span.spr(data-i18n="legal.code_description_prefix")
|
||||
| All code owned by CodeCombat or hosted on codecombat.com,
|
||||
| both in the GitHub repository or in the codecombat.com database,
|
||||
| is licensed under the
|
||||
span
|
||||
a(href="http://opensource.org/licenses/MIT", data-i18n="legal.mit_license_url")
|
||||
| MIT license
|
||||
span .
|
||||
|
@ -91,14 +86,11 @@ block content
|
|||
|
||||
h3(data-i18n="legal.art_title")
|
||||
| Art/Music - Creative Commons
|
||||
a(rel='license', href='http://creativecommons.org/licenses/by/4.0/').cc-license-link
|
||||
img(alt='Creative Commons License', style='border-width: 0; margin-left: 10px', src='http://i.creativecommons.org/l/by/4.0/88x31.png')
|
||||
|
||||
p
|
||||
span(data-i18n="legal.art_description_prefix")
|
||||
p
|
||||
span.spr(data-i18n="legal.art_description_prefix")
|
||||
| All common content is available under the
|
||||
span
|
||||
a(href="http://creativecommons.org/licenses/by/4.0/", data-i18n="legal.cc_license_url")
|
||||
a(href="https://creativecommons.org/licenses/by/4.0/", data-i18n="legal.cc_license_url")
|
||||
| Creative Commons Attribution 4.0 International License
|
||||
span .
|
||||
span(data-i18n="legal.art_description_suffix")
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
.glyphicon.glyphicon-play
|
||||
span(data-i18n="nav.play").home-text Levels
|
||||
|
||||
if isMultiplayerLevel
|
||||
if isMultiplayerLevel && !observing
|
||||
.multiplayer-area-container
|
||||
.multiplayer-area
|
||||
.multiplayer-label(data-i18n="play_level.control_bar_multiplayer")
|
||||
|
@ -28,17 +28,19 @@ else
|
|||
|
||||
.buttons-area
|
||||
|
||||
button.btn.btn-inverse#game-menu-button(title="Show game menu")
|
||||
.hamburger
|
||||
span.icon-bar
|
||||
span.icon-bar
|
||||
span.icon-bar
|
||||
span.game-menu-text(data-i18n="play_level.game_menu") Game Menu
|
||||
if !observing
|
||||
button.btn.btn-inverse#game-menu-button(title="Show game menu")
|
||||
.hamburger
|
||||
span.icon-bar
|
||||
span.icon-bar
|
||||
span.icon-bar
|
||||
span.game-menu-text(data-i18n="play_level.game_menu") Game Menu
|
||||
|
||||
if spectateGame
|
||||
button.btn.btn-xs.btn-inverse.banner#next-game-button(title="Next Game", data-i18n="play_level.next-game") Next game!
|
||||
|
||||
button.btn.btn-xs.btn-primary.banner#level-done-button(data-i18n="play_level.done") Done
|
||||
if !observing
|
||||
button.btn.btn-xs.btn-primary.banner#level-done-button(data-i18n="play_level.done") Done
|
||||
|
||||
if me.get('anonymous')
|
||||
button.btn.btn-xs.btn-primary.banner#control-bar-sign-up-button(data-toggle='coco-modal', data-target='core/AuthModal', data-i18n="signup.sign_up")
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
button.btn.btn-lg.btn-illustrated.cast-button(title=castVerbose)
|
||||
span(data-i18n="play_level.tome_run_button_ran") Ran
|
||||
|
||||
button.btn.btn-lg.btn-illustrated.submit-button(title=castRealTimeVerbose)
|
||||
span(data-i18n="play_level.tome_submit_button") Submit
|
||||
span.spl.secret.submit-again-time
|
||||
|
||||
button.btn.btn-lg.btn-illustrated.done-button.secret
|
||||
span(data-i18n="play_level.done") Done
|
||||
if !observing
|
||||
button.btn.btn-lg.btn-illustrated.submit-button(title=castRealTimeVerbose)
|
||||
span(data-i18n="play_level.tome_submit_button") Submit
|
||||
span.spl.secret.submit-again-time
|
||||
|
||||
button.btn.btn-lg.btn-illustrated.done-button.secret
|
||||
span(data-i18n="play_level.done") Done
|
||||
|
|
|
@ -11,16 +11,23 @@ if topScores
|
|||
th(colspan=4, data-i18n="general.player")
|
||||
th(data-i18n="general.score")
|
||||
th(data-i18n="general.when")
|
||||
th
|
||||
tbody
|
||||
for row, rank in topScores
|
||||
- var isMyRow = row.creator == me.id
|
||||
tr(class=isMyRow ? "success" : "", data-player-id=row.creator, data-session-id=row.id)
|
||||
- var viewable = rank >= 5 || me.isAdmin();
|
||||
tr(class=isMyRow ? "success" : "" + (viewable ? " viewable" : ""), data-player-id=row.creator, data-session-id=row.session, title=viewable ? "View solution" : "Can't view top 5 solutions")
|
||||
td.rank-cell= rank + 1
|
||||
td.code-language-cell(style="background-image: url(/images/common/code_languages/#{row.codeLanguage}_small.png)" title=_.string.capitalize(row.codeLanguage))
|
||||
td.hero-portrait-cell(style="background-image: url(/file/db/thang.type/#{row.hero}/portrait.png)")
|
||||
td.name-col-cell= row.creatorName || "Anonymous"
|
||||
td.score-cell= row.score
|
||||
td.ago-cell= row.ago
|
||||
td.viewable-cell
|
||||
if viewable
|
||||
.glyphicon.glyphicon-eye-open
|
||||
else
|
||||
.glyphicon.glyphicon-eye-close
|
||||
else if loading
|
||||
h3(data-i18n="common.loading")
|
||||
else
|
||||
|
|
|
@ -6,69 +6,114 @@ block content
|
|||
|
||||
.span5
|
||||
|
||||
h2 CodeCombat for Teachers
|
||||
h2(data-i18n="teachers.title") CodeCombat for Teachers
|
||||
|
||||
h3 Preparation
|
||||
h3(data-i18n="teachers.preparation_title") Preparation
|
||||
|
||||
p CodeCombat is free to play for the core level progression and does not require students to sign up. We encourage teachers to
|
||||
a(href="/play") play through the campaign
|
||||
| to try it out, but the only thing you absolutely need to do to be ready is ensure students have access to a computer.
|
||||
p
|
||||
span.spr(data-i18n="teachers.preparation_1")
|
||||
| CodeCombat is free to play for the core level progression
|
||||
| and does not require students to sign up. We encourage teachers to
|
||||
a(href="/play", data-i18n="teachers.preparation_play_campaign") play through the campaign
|
||||
span.spl(data-i18n="teachers.preparation_2")
|
||||
| to try it out, but the only thing you absolutely need to do
|
||||
| to be ready is ensure students have access to a computer.
|
||||
|
||||
p It is not necessary for teachers to be comfortable with computer science concepts for students to have fun learning with CodeCombat.
|
||||
p(data-i18n="teachers.preparation_3")
|
||||
| It is not necessary for teachers to be comfortable with computer
|
||||
| science concepts for students to have fun learning with CodeCombat.
|
||||
|
||||
h3 Is it violent?
|
||||
h3(data-i18n="teachers.violent_title")
|
||||
| Is it violent?
|
||||
|
||||
p We get this from teachers a lot due to our name. Although CodeCombat does contain cartoon violence, there is nothing graphic in either the visuals or language. If you are comfortable having your students play Angry Birds, you will be comfortable with CodeCombat.
|
||||
p
|
||||
span.spr(data-i18n="teachers.violent_1")
|
||||
| We get this from teachers a lot due to our name. Although CodeCombat
|
||||
| does contain cartoon violence, there is nothing graphic in either the
|
||||
| visuals or language.
|
||||
span(data-i18n="teachers.violent_2")
|
||||
| If you are comfortable having your students play Angry Birds, you will
|
||||
| be comfortable with CodeCombat.
|
||||
|
||||
h3 Is it for girls?
|
||||
h3(data-i18n="teachers.for_girls_title")
|
||||
| Is it for girls?
|
||||
|
||||
p There are three game modes in CodeCombat: building, puzzles, and combat. We have intentionally designed each to appeal to both boys and girls and think that the building and puzzle levels especially differentiate the game from violent triple A titles that repel female players.
|
||||
p(data-i18n="teachers.for_girls_1")
|
||||
| There are three game modes in CodeCombat: building, puzzles, and combat.
|
||||
| We have intentionally designed each to appeal to both boys and girls and
|
||||
| think that the building and puzzle levels especially differentiate the game
|
||||
| from violent triple A titles that repel female players.
|
||||
|
||||
h3 What do we cover?
|
||||
h3(data-i18n="teachers.what_cover_title")
|
||||
| What do we cover?
|
||||
|
||||
p There are 20 levels in the Hour of Code tutorial that teach and reinforce 6 specific computer science concepts:
|
||||
p(data-i18n="teachers.what_cover_1")
|
||||
| There are 20 levels in the Hour of Code tutorial that teach and
|
||||
| reinforce 6 specific computer science concepts:
|
||||
|
||||
ol
|
||||
li
|
||||
strong Formal notation
|
||||
| - builds an understanding of the importance of syntax in programming.
|
||||
strong.spr(data-i18n="teachers.what_cover_notation_1") Formal notation
|
||||
span(data-i18n="teachers.what_cover_notation_2")
|
||||
| - builds an understanding of the importance of syntax in programming.
|
||||
li
|
||||
strong Calling methods
|
||||
| - familiarizes students with the syntax of object-oriented method calls.
|
||||
strong.spr(data-i18n="teachers.what_cover_methods_1") Calling methods
|
||||
span(data-i18n="teachers.what_cover_methods_2")
|
||||
| - familiarizes students with the syntax of object-oriented method calls.
|
||||
li
|
||||
strong Parameters
|
||||
| - trains how to pass parameters to functions.
|
||||
strong.spr(data-i18n="teachers.what_cover_parameters_1") Parameters
|
||||
span(data-i18n="teachers.what_cover_parameters_2")
|
||||
| - trains how to pass parameters to functions.
|
||||
li
|
||||
strong Strings
|
||||
| - teaches students about string notation and passing strings as parameters.
|
||||
strong.spr(data-i18n="teachers.what_cover_strings_1") Strings
|
||||
span(data-i18n="teachers.what_cover_strings_2")
|
||||
| - teaches students about string notation and passing strings as parameters.
|
||||
li
|
||||
strong Loops
|
||||
| - develops the abstraction of designing short programs with loops.
|
||||
strong.spr(data-i18n="teachers.what_cover_loops_1") Loops
|
||||
span(data-i18n="teachers.what_cover_loops_2")
|
||||
| - develops the abstraction of designing short programs with loops.
|
||||
li
|
||||
strong Variables
|
||||
| - adds the skill of referencing values that change over time.
|
||||
strong.spr(data-i18n="teachers.what_cover_variables_1") Variables
|
||||
span(data-i18n="teachers.what_cover_variables_2")
|
||||
| - adds the skill of referencing values that change over time.
|
||||
|
||||
p Students may continue past level 20, depending on their speed and interest, to learn two additional concepts in later levels:
|
||||
p(data-i18n="teachers.what_cover_2")
|
||||
| Students may continue past level 20, depending on their
|
||||
| speed and interest, to learn two additional concepts in later levels:
|
||||
ol
|
||||
li
|
||||
strong Conditional logic
|
||||
| - when and how to use if/else to control in-game outcomes.
|
||||
strong.spr(data-i18n="teachers.what_cover_logic_1") Conditional logic
|
||||
span(data-i18n="teachers.what_cover_logic_2")
|
||||
| - when and how to use if/else to control in-game outcomes.
|
||||
li
|
||||
strong Handling player input
|
||||
| - responding to input events to create a user interface.
|
||||
strong.spr(data-i18n="teachers.what_cover_input_1") Handling player input
|
||||
span(data-i18n="teachers.what_cover_input_2")
|
||||
| - responding to input events to create a user interface.
|
||||
|
||||
|
||||
h3 System Requirements
|
||||
h3(data-i18n="teachers.sys_requirements_title") System Requirements
|
||||
|
||||
p Because CodeCombat is a game, it is more intensive for computers to run smoothly than video or written tutorials. We have optimized it to run quickly on all modern browsers and on older machines so that everyone can play. That said, here are our suggestions for getting the most out of your Hour of Code experience:
|
||||
p(data-i18n="teachers.sys_requirements_1")
|
||||
| Because CodeCombat is a game, it is more intensive for computers
|
||||
| to run smoothly than video or written tutorials. We have optimized
|
||||
| it to run quickly on all modern browsers and on older machines so
|
||||
| that everyone can play. That said, here are our suggestions for getting
|
||||
| the most out of your Hour of Code experience:
|
||||
|
||||
ul
|
||||
li
|
||||
strong Use newer versions of Chrome or Firefox.
|
||||
| Although CodeCombat will work on browsers as old as IE9, the performance is not as good. Chrome is best.
|
||||
strong.spr(data-i18n="teachers.sys_requirements_2") Use newer versions of Chrome or Firefox.
|
||||
span(data-i18n="teachers.sys_requirements_3")
|
||||
| Although CodeCombat will work on browsers as old as IE9, the
|
||||
| performance is not as good. Chrome is best.
|
||||
li
|
||||
strong Use newer computers.
|
||||
| Older computers, Chromebooks, and netbooks tend to have very few system resources, which makes for a less enjoyable experience. At least 2GB of RAM is required.
|
||||
strong.spr(data-i18n="teachers.sys_requirements_4") Use newer computers.
|
||||
span(data-i18n="teachers.sys_requirements_5")
|
||||
| Older computers, Chromebooks, and netbooks tend to have very few
|
||||
| system resources, which makes for a less enjoyable experience.
|
||||
| At least 2GB of RAM is required.
|
||||
li
|
||||
strong Allow players to wear headphones/earbuds to hear the audio.
|
||||
| We help players learn through voiceover and sound effects, which will make classrooms noisy and distracting.
|
||||
strong.spr(data-i18n="teachers.sys_requirements_6") Allow players to wear headphones/earbuds to hear the audio.
|
||||
span(data-i18n="teachers.sys_requirements_7")
|
||||
| We help players learn through voiceover and sound effects, which
|
||||
| will make classrooms noisy and distracting.
|
||||
|
|
|
@ -206,7 +206,7 @@ module.exports = class CampaignView extends RootView
|
|||
for nextLevelOriginal in level.nextLevels ? []
|
||||
if nextLevel = _.find(@campaign.renderedLevels, original: nextLevelOriginal)
|
||||
@createLine level.position, nextLevel.position
|
||||
@showLeaderboard @options.justBeatLevel?.get('slug') if @options.showLeaderboard #or true
|
||||
@showLeaderboard @options.justBeatLevel?.get('slug') if @options.showLeaderboard or true
|
||||
@applyCampaignStyles()
|
||||
@testParticles()
|
||||
|
||||
|
@ -220,7 +220,7 @@ module.exports = class CampaignView extends RootView
|
|||
@openModalView authModal
|
||||
|
||||
showLeaderboard: (levelSlug) ->
|
||||
#levelSlug ?= 'keeping-time' # Testing: show Keeping Time
|
||||
levelSlug ?= 'siege-of-stonehold' # Testing
|
||||
leaderboardModal = new LeaderboardModal supermodel: @supermodel, levelSlug: levelSlug
|
||||
@openModalView leaderboardModal
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ module.exports = class ControlBarView extends CocoView
|
|||
@level = options.level
|
||||
@levelID = @level.get('slug')
|
||||
@spectateGame = options.spectateGame ? false
|
||||
@observing = options.session.get('creator') isnt me.id
|
||||
super options
|
||||
if @level.get('type') in ['hero-ladder'] and me.isAdmin()
|
||||
@isMultiplayerLevel = true
|
||||
|
@ -66,6 +67,7 @@ module.exports = class ControlBarView extends CocoView
|
|||
c.difficultyTitle = "#{$.i18n.t 'play.level_difficulty'}#{c.levelDifficulty}"
|
||||
@lastDifficulty = c.levelDifficulty
|
||||
c.spectateGame = @spectateGame
|
||||
c.observing = @observing
|
||||
@homeViewArgs = [{supermodel: if @hasReceivedMemoryWarning then null else @supermodel}]
|
||||
if @level.get('type', true) in ['ladder', 'ladder-tutorial', 'hero-ladder']
|
||||
levelID = @level.get('slug').replace /\-tutorial$/, ''
|
||||
|
|
|
@ -103,7 +103,7 @@ module.exports = class LevelHUDView extends CocoView
|
|||
if @thang.id in ['Hero Placeholder', 'Hero Placeholder 1']
|
||||
name = {knight: 'Tharin', captain: 'Anya', librarian: 'Hushbaum', sorcerer: 'Pender', 'potion-master': 'Omarn', samurai: 'Hattori', ninja: 'Amara'}[@thang.type] ? 'Hero'
|
||||
else
|
||||
name = if @thang.type then "#{@thang.id} - #{@thang.type}" else @thang.id
|
||||
name = @thang.hudName or (if @thang.type then "#{@thang.id} - #{@thang.type}" else @thang.id)
|
||||
utils.replaceText @$el.find('.thang-name'), name
|
||||
props = @$el.find('.thang-props')
|
||||
props.find('.prop').remove()
|
||||
|
|
|
@ -95,6 +95,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
|
||||
@isEditorPreview = @getQueryVariable 'dev'
|
||||
@sessionID = @getQueryVariable 'session'
|
||||
@observing = @getQueryVariable 'observing'
|
||||
|
||||
@opponentSessionID = @getQueryVariable('opponent')
|
||||
@opponentSessionID ?= @options.opponent
|
||||
|
@ -109,7 +110,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
setTimeout f, 100
|
||||
else
|
||||
@load()
|
||||
application.tracker?.trackEvent 'Started Level Load', category: 'Play Level', level: @levelID, label: @levelID, ['Google Analytics']
|
||||
application.tracker?.trackEvent 'Started Level Load', category: 'Play Level', level: @levelID, label: @levelID, ['Google Analytics'] unless @observing
|
||||
|
||||
setLevel: (@level, givenSupermodel) ->
|
||||
@supermodel.models = givenSupermodel.models
|
||||
|
@ -134,8 +135,9 @@ module.exports = class PlayLevelView extends RootView
|
|||
@loadEndTime = new Date()
|
||||
loadDuration = @loadEndTime - @loadStartTime
|
||||
console.debug "Level unveiled after #{(loadDuration / 1000).toFixed(2)}s"
|
||||
application.tracker?.trackEvent 'Finished Level Load', category: 'Play Level', label: @levelID, level: @levelID, loadDuration: loadDuration, ['Google Analytics']
|
||||
application.tracker?.trackTiming loadDuration, 'Level Load Time', @levelID, @levelID
|
||||
unless @observing
|
||||
application.tracker?.trackEvent 'Finished Level Load', category: 'Play Level', label: @levelID, level: @levelID, loadDuration: loadDuration, ['Google Analytics']
|
||||
application.tracker?.trackTiming loadDuration, 'Level Load Time', @levelID, @levelID
|
||||
|
||||
# CocoView overridden methods ###############################################
|
||||
|
||||
|
@ -147,7 +149,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
afterRender: ->
|
||||
super()
|
||||
window.onPlayLevelViewLoaded? @ # still a hack
|
||||
@insertSubView @loadingView = new LevelLoadingView autoUnveil: @options.autoUnveil, level: @levelLoader?.level ? @level # May not have @level loaded yet
|
||||
@insertSubView @loadingView = new LevelLoadingView autoUnveil: @options.autoUnveil or @observing, level: @levelLoader?.level ? @level # May not have @level loaded yet
|
||||
@$el.find('#level-done-button').hide()
|
||||
$('body').addClass('is-playing')
|
||||
$('body').bind('touchmove', false) if @isIPadApp()
|
||||
|
@ -233,7 +235,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
@god.setGoalManager @goalManager
|
||||
|
||||
insertSubviews: ->
|
||||
@insertSubView @tome = new TomeView levelID: @levelID, session: @session, otherSession: @otherSession, thangs: @world.thangs, supermodel: @supermodel, level: @level
|
||||
@insertSubView @tome = new TomeView levelID: @levelID, session: @session, otherSession: @otherSession, thangs: @world.thangs, supermodel: @supermodel, level: @level, observing: @observing
|
||||
@insertSubView new LevelPlaybackView session: @session, level: @level
|
||||
@insertSubView new GoalsView {}
|
||||
@insertSubView new LevelFlagsView levelID: @levelID, world: @world if @$el.hasClass 'flags'
|
||||
|
@ -283,7 +285,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
|
||||
|
||||
# Save latest level played.
|
||||
if not (@levelLoader.level.get('type') in ['ladder', 'ladder-tutorial'])
|
||||
if not @observing and not (@levelLoader.level.get('type') in ['ladder', 'ladder-tutorial'])
|
||||
me.set('lastLevel', @levelID)
|
||||
me.save()
|
||||
application.tracker?.identify()
|
||||
|
@ -321,7 +323,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
if @otherSession and not (@level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop'])
|
||||
# TODO: colorize name and cloud by team, colorize wizard by user's color config
|
||||
@surface.createOpponentWizard id: @otherSession.get('creator'), name: @otherSession.get('creatorName'), team: @otherSession.get('team'), levelSlug: @level.get('slug'), codeLanguage: @otherSession.get('submittedCodeLanguage')
|
||||
if @isEditorPreview
|
||||
if @isEditorPreview or @observing
|
||||
@loadingView.startUnveiling()
|
||||
@loadingView.unveil()
|
||||
|
||||
|
@ -337,7 +339,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
Backbone.Mediator.publish 'playback:real-time-playback-waiting', {}
|
||||
@realTimeMultiplayerContinueGame @options.realTimeMultiplayerSessionID
|
||||
# TODO: Is it possible to create a Mongoose ObjectId for 'ls', instead of the string returned from get()?
|
||||
application.tracker?.trackEvent 'Started Level', category:'Play Level', levelID: @levelID, ls: @session?.get('_id')
|
||||
application.tracker?.trackEvent 'Started Level', category:'Play Level', levelID: @levelID, ls: @session?.get('_id') unless @observing
|
||||
|
||||
playAmbientSound: ->
|
||||
return if @destroyed
|
||||
|
@ -414,7 +416,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
return if @victorySeen
|
||||
@victorySeen = true
|
||||
victoryTime = (new Date()) - @loadEndTime
|
||||
if victoryTime > 10 * 1000 # Don't track it if we're reloading an already-beaten level
|
||||
if not @observing and victoryTime > 10 * 1000 # Don't track it if we're reloading an already-beaten level
|
||||
application.tracker?.trackEvent 'Saw Victory',
|
||||
category: 'Play Level'
|
||||
level: @level.get('name')
|
||||
|
@ -436,12 +438,12 @@ module.exports = class PlayLevelView extends RootView
|
|||
@tome.reloadAllCode()
|
||||
Backbone.Mediator.publish 'level:restarted', {}
|
||||
$('#level-done-button', @$el).hide()
|
||||
application.tracker?.trackEvent 'Confirmed Restart', category: 'Play Level', level: @level.get('name'), label: @level.get('name')
|
||||
application.tracker?.trackEvent 'Confirmed Restart', category: 'Play Level', level: @level.get('name'), label: @level.get('name') unless @observing
|
||||
|
||||
onInfiniteLoop: (e) ->
|
||||
return unless e.firstWorld
|
||||
@openModalView new InfiniteLoopModal()
|
||||
application.tracker?.trackEvent 'Saw Initial Infinite Loop', category: 'Play Level', level: @level.get('name'), label: @level.get('name')
|
||||
application.tracker?.trackEvent 'Saw Initial Infinite Loop', category: 'Play Level', level: @level.get('name'), label: @level.get('name') unless @observing
|
||||
|
||||
onHighlightDOM: (e) -> @highlightElement e.selector, delay: e.delay, sides: e.sides, offset: e.offset, rotation: e.rotation
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ module.exports = class CastButtonView extends CocoView
|
|||
@spells = options.spells
|
||||
@castShortcut = '⇧↵'
|
||||
@updateReplayabilityInterval = setInterval @updateReplayability, 1000
|
||||
@observing = options.session.get('creator') isnt me.id
|
||||
|
||||
destroy: ->
|
||||
clearInterval @updateReplayabilityInterval
|
||||
|
@ -40,6 +41,7 @@ module.exports = class CastButtonView extends CocoView
|
|||
castRealTimeShortcutVerbose = (if @isMac() then 'Cmd' else 'Ctrl') + '+' + castShortcutVerbose
|
||||
context.castVerbose = castShortcutVerbose + ': ' + $.i18n.t('keyboard_shortcuts.run_code')
|
||||
context.castRealTimeVerbose = castRealTimeShortcutVerbose + ': ' + $.i18n.t('keyboard_shortcuts.run_real_time')
|
||||
context.observing = @observing
|
||||
context
|
||||
|
||||
afterRender: ->
|
||||
|
|
|
@ -15,6 +15,7 @@ module.exports = class Spell
|
|||
@otherSession = options.otherSession
|
||||
@spectateView = options.spectateView
|
||||
@spectateOpponentCodeLanguage = options.spectateOpponentCodeLanguage
|
||||
@observing = options.observing
|
||||
@supermodel = options.supermodel
|
||||
@skipProtectAPI = options.skipProtectAPI
|
||||
@worker = options.worker
|
||||
|
@ -189,6 +190,7 @@ module.exports = class Spell
|
|||
return true if @spectateView # Use transpiled code for both teams if we're just spectating.
|
||||
return true if @isEnemySpell() # Use transpiled for enemy spells.
|
||||
# Players without permissions can't view the raw code.
|
||||
return false if @observing and @levelType is 'hero'
|
||||
return true if @session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions', true))
|
||||
false
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ module.exports = class SpellView extends CocoView
|
|||
@writable = false unless me.team in @spell.permissions.readwrite # TODO: make this do anything
|
||||
@highlightCurrentLine = _.throttle @highlightCurrentLine, 100
|
||||
$(window).on 'resize', @onWindowResize
|
||||
@observing = @session.get('creator') isnt me.id
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
|
@ -119,14 +120,15 @@ module.exports = class SpellView extends CocoView
|
|||
name: 'run-code'
|
||||
bindKey: {win: 'Shift-Enter|Ctrl-Enter', mac: 'Shift-Enter|Command-Enter|Ctrl-Enter'}
|
||||
exec: -> Backbone.Mediator.publish 'tome:manual-cast', {}
|
||||
addCommand
|
||||
name: 'run-code-real-time'
|
||||
bindKey: {win: 'Ctrl-Shift-Enter', mac: 'Command-Shift-Enter|Ctrl-Shift-Enter'}
|
||||
exec: =>
|
||||
if @options.level.get('replayable') and (timeUntilResubmit = @session.timeUntilResubmit()) > 0
|
||||
Backbone.Mediator.publish 'tome:manual-cast-denied', timeUntilResubmit: timeUntilResubmit
|
||||
else
|
||||
Backbone.Mediator.publish 'tome:manual-cast', {realTime: true}
|
||||
unless @observing
|
||||
addCommand
|
||||
name: 'run-code-real-time'
|
||||
bindKey: {win: 'Ctrl-Shift-Enter', mac: 'Command-Shift-Enter|Ctrl-Shift-Enter'}
|
||||
exec: =>
|
||||
if @options.level.get('replayable') and (timeUntilResubmit = @session.timeUntilResubmit()) > 0
|
||||
Backbone.Mediator.publish 'tome:manual-cast-denied', timeUntilResubmit: timeUntilResubmit
|
||||
else
|
||||
Backbone.Mediator.publish 'tome:manual-cast', {realTime: true}
|
||||
addCommand
|
||||
name: 'no-op'
|
||||
bindKey: {win: 'Ctrl-S', mac: 'Command-S|Ctrl-S'}
|
||||
|
|
|
@ -134,6 +134,7 @@ module.exports = class TomeView extends CocoView
|
|||
language: language
|
||||
spectateView: @options.spectateView
|
||||
spectateOpponentCodeLanguage: @options.spectateOpponentCodeLanguage
|
||||
observing: @options.observing
|
||||
levelID: @options.levelID
|
||||
level: @options.level
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ module.exports = class LeaderboardTabView extends CocoView
|
|||
template: template
|
||||
className: 'leaderboard-tab-view'
|
||||
|
||||
events: {}
|
||||
events:
|
||||
'click tbody tr.viewable': 'onClickRow'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
|
@ -67,3 +68,8 @@ module.exports = class LeaderboardTabView extends CocoView
|
|||
@hasShown = true
|
||||
topScores = new TopScoresCollection @level, @scoreType, @timespan
|
||||
@sessions = @supermodel.loadCollection(topScores, 'sessions', null, 0).model
|
||||
|
||||
onClickRow: (e) ->
|
||||
sessionID = $(e.target).closest('tr').data 'session-id'
|
||||
url = "/play/level/#{@level.get('slug')}?session=#{sessionID}&observing=true"
|
||||
window.open url, '_blank'
|
||||
|
|
|
@ -15,7 +15,10 @@ class LevelSessionHandler extends Handler
|
|||
|
||||
formatEntity: (req, document) ->
|
||||
documentObject = super(req, document)
|
||||
if req.user?.isAdmin() or req.user?.id is document.creator or ('employer' in (req.user?.get('permissions') ? []))
|
||||
if req.user?.isAdmin() or
|
||||
req.user?.id is document.creator or
|
||||
('employer' in (req.user?.get('permissions') ? [])) or
|
||||
!document.submittedCode # TODO: only allow leaderboard access to non-top-5 solutions
|
||||
return documentObject
|
||||
else
|
||||
return _.omit documentObject, @privateProperties
|
||||
|
@ -47,8 +50,9 @@ class LevelSessionHandler extends Handler
|
|||
@sendSuccess res, documents
|
||||
|
||||
hasAccessToDocument: (req, document, method=null) ->
|
||||
return true if req.method is 'GET' and document.get('submitted')
|
||||
return true if ('employer' in (req.user?.get('permissions') ? [])) and (method ? req.method).toLowerCase() is 'get'
|
||||
get = (method ? req.method).toLowerCase() is 'get'
|
||||
return true if get and document.get('submitted')
|
||||
return true if get and ('employer' in (req.user?.get('permissions') ? []))
|
||||
super(arguments...)
|
||||
|
||||
getCodeLanguageCounts: (req, res) ->
|
||||
|
|
Loading…
Reference in a new issue