mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-01-05 20:22:44 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
eb70d90d9c
33 changed files with 324 additions and 134 deletions
BIN
app/assets/images/pages/about/sean_small.png
Normal file
BIN
app/assets/images/pages/about/sean_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
BIN
app/assets/images/pages/play/portal-beta-campaigns.png
Normal file
BIN
app/assets/images/pages/play/portal-beta-campaigns.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1 MiB |
|
@ -769,7 +769,7 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
|
||||||
|
|
||||||
about:
|
about:
|
||||||
main_title: "Wenn du das Programmieren erlernen willst, musst du (viel) Code schreiben."
|
main_title: "Wenn du das Programmieren erlernen willst, musst du (viel) Code schreiben."
|
||||||
main_description: "Bei CodeCombat ist es unser Job das du das mit einem Lächeln im Gesicht tust."
|
main_description: "Bei CodeCombat ist es unser Job, dass du das mit einem Lächeln im Gesicht tust."
|
||||||
mission_link: "Mission"
|
mission_link: "Mission"
|
||||||
team_link: "Team"
|
team_link: "Team"
|
||||||
story_link: "Geschichte"
|
story_link: "Geschichte"
|
||||||
|
|
|
@ -304,6 +304,7 @@
|
||||||
signup_as_individual: "Sign up as an Individual"
|
signup_as_individual: "Sign up as an Individual"
|
||||||
enter_class_code: "Enter your Class Code"
|
enter_class_code: "Enter your Class Code"
|
||||||
enter_birthdate: "Enter your birthdate:"
|
enter_birthdate: "Enter your birthdate:"
|
||||||
|
parent_use_birthdate: "Parents, use your own birthdate."
|
||||||
ask_teacher_1: "Ask your teacher for your Class Code."
|
ask_teacher_1: "Ask your teacher for your Class Code."
|
||||||
ask_teacher_2: "Not part of a class? Create an "
|
ask_teacher_2: "Not part of a class? Create an "
|
||||||
ask_teacher_3: "Individual Account"
|
ask_teacher_3: "Individual Account"
|
||||||
|
@ -475,6 +476,7 @@
|
||||||
victory_experience_gained: "XP Gained"
|
victory_experience_gained: "XP Gained"
|
||||||
victory_gems_gained: "Gems Gained"
|
victory_gems_gained: "Gems Gained"
|
||||||
victory_new_item: "New Item"
|
victory_new_item: "New Item"
|
||||||
|
victory_new_hero: "New Hero"
|
||||||
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_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_become_a_viking: "Become a Viking"
|
||||||
victory_no_progress_for_teachers: "Progress is not saved for teachers. But, you can add a student account to your classroom for yourself."
|
victory_no_progress_for_teachers: "Progress is not saved for teachers. But, you can add a student account to your classroom for yourself."
|
||||||
|
@ -571,6 +573,18 @@
|
||||||
tip_good_idea: "The best way to have a good idea is to have a lot of ideas. - Linus Pauling"
|
tip_good_idea: "The best way to have a good idea is to have a lot of ideas. - Linus Pauling"
|
||||||
tip_programming_not_about_computers: "Computer Science is no more about computers than astronomy is about telescopes. - Edsger Dijkstra"
|
tip_programming_not_about_computers: "Computer Science is no more about computers than astronomy is about telescopes. - Edsger Dijkstra"
|
||||||
tip_mulan: "Believe you can, then you will. - Mulan"
|
tip_mulan: "Believe you can, then you will. - Mulan"
|
||||||
|
|
||||||
|
play_game_dev_level:
|
||||||
|
created_by: "Created by {{name}}"
|
||||||
|
how_to_play_title: "How to play:"
|
||||||
|
how_to_play_1: "Use the mouse to control the hero!"
|
||||||
|
how_to_play_2: "Click anywhere on the map to move to that location."
|
||||||
|
how_to_play_3: "Click on the ogres to attack them."
|
||||||
|
restart: "Restart Level"
|
||||||
|
play: "Play Level"
|
||||||
|
play_more_codecombat: "Play More CodeCombat"
|
||||||
|
default_student_instructions: "Click to control your hero and win your game!"
|
||||||
|
back_to_coding: "Back to Coding"
|
||||||
|
|
||||||
game_menu:
|
game_menu:
|
||||||
inventory_tab: "Inventory"
|
inventory_tab: "Inventory"
|
||||||
|
@ -804,6 +818,7 @@
|
||||||
elliot_title: "Partnership Manager"
|
elliot_title: "Partnership Manager"
|
||||||
elliot_blurb: "Mindreader"
|
elliot_blurb: "Mindreader"
|
||||||
lisa_title: "Market Development Rep"
|
lisa_title: "Market Development Rep"
|
||||||
|
sean_title: "Territory Manager"
|
||||||
retrostyle_title: "Illustration"
|
retrostyle_title: "Illustration"
|
||||||
retrostyle_blurb: "RetroStyle Games"
|
retrostyle_blurb: "RetroStyle Games"
|
||||||
jose_title: "Music"
|
jose_title: "Music"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", translation:
|
module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", translation:
|
||||||
home:
|
home:
|
||||||
slogan: "גם לשחק וגם ללמוד לתכנת"
|
slogan: "גם לשחק וגם ללמוד לתכנת"
|
||||||
no_ie: "המשחק לא עובד באקפלורר 8 וישן יותר. סליחה!" # Warning that only shows up in IE8 and older
|
no_ie: "המשחק לא עובד באקפלורר 8 וישן יותר. סליחה!" # Warning that only shows up in IE8 and older
|
||||||
|
|
|
@ -132,7 +132,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
|
||||||
help_suff: "en we nemen contact op!"
|
help_suff: "en we nemen contact op!"
|
||||||
|
|
||||||
modal:
|
modal:
|
||||||
# cancel: "Cancel"
|
cancel: "Annuleren"
|
||||||
close: "Sluiten"
|
close: "Sluiten"
|
||||||
okay: "Oké"
|
okay: "Oké"
|
||||||
|
|
||||||
|
@ -256,13 +256,13 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
|
||||||
signup_switch: "Wil je een account maken?"
|
signup_switch: "Wil je een account maken?"
|
||||||
|
|
||||||
signup:
|
signup:
|
||||||
# create_student_header: "Create Student Account"
|
create_student_header: "Creëer studenten account"
|
||||||
# create_teacher_header: "Create Teacher Account"
|
create_teacher_header: "Creeër leraren account"
|
||||||
# create_individual_header: "Create Individual Account"
|
create_individual_header: "Creeër persoonlijk account"
|
||||||
# create_header: "Create Account"
|
create_header: "Creëer Account"
|
||||||
email_announcements: "Ontvang aankondigingen via e-mail" # {change}
|
email_announcements: "Ontvang aankondigingen via e-mail" # {change}
|
||||||
creating: "Account aanmaken..."
|
creating: "Account aanmaken..."
|
||||||
# create_account: "Create Account"
|
create_account: "Creëer account"
|
||||||
sign_up: "Aanmelden"
|
sign_up: "Aanmelden"
|
||||||
log_in: "inloggen met wachtwoord"
|
log_in: "inloggen met wachtwoord"
|
||||||
required: "Je moet inloggen om daarheen te gaan."
|
required: "Je moet inloggen om daarheen te gaan."
|
||||||
|
@ -270,7 +270,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
|
||||||
school_name: "Schoolnaam en stad"
|
school_name: "Schoolnaam en stad"
|
||||||
optional: "optioneel"
|
optional: "optioneel"
|
||||||
school_name_placeholder: "Voorbeeld middelbare school, Amsterdam"
|
school_name_placeholder: "Voorbeeld middelbare school, Amsterdam"
|
||||||
# connect_with: "Connect with:"
|
connect_with: "Verbind met:"
|
||||||
connected_gplus_header: "Je bent ingelogd met Google+!"
|
connected_gplus_header: "Je bent ingelogd met Google+!"
|
||||||
connected_gplus_p: "Maak je inschrijving compleet zodat je kan inloggen met je Google+ account."
|
connected_gplus_p: "Maak je inschrijving compleet zodat je kan inloggen met je Google+ account."
|
||||||
gplus_exists: "Jouw Google+ account is al gekoppeld!"
|
gplus_exists: "Jouw Google+ account is al gekoppeld!"
|
||||||
|
@ -280,35 +280,35 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
|
||||||
hey_students: "Leerlingen, voer hier de klassencode van je docent in."
|
hey_students: "Leerlingen, voer hier de klassencode van je docent in."
|
||||||
birthday: "Verjaardag"
|
birthday: "Verjaardag"
|
||||||
# parent_email_blurb: "We know you can't wait to learn programming — we're excited too! Your parents will receive an email with further instructions on how to create an account for you. Email {{email_link}} if you have any questions."
|
# parent_email_blurb: "We know you can't wait to learn programming — we're excited too! Your parents will receive an email with further instructions on how to create an account for you. Email {{email_link}} if you have any questions."
|
||||||
# classroom_not_found: "No classes exist with this Class Code. Check your spelling or ask your teacher for help."
|
classroom_not_found: "Er zijn geen klassen met deze klassencode. Controleer je spelling of vraag je leraar om hulp."
|
||||||
# checking: "Checking..."
|
checking: "Controleren..."
|
||||||
# account_exists: "This email is already in use:" # {change}
|
account_exists: "Dit emailadres bestaat al:" # {change}
|
||||||
# sign_in: "Sign in"
|
sign_in: "Log in"
|
||||||
# email_good: "Email looks good!"
|
email_good: "Email ziet er goed uit!"
|
||||||
# name_taken: "Username already taken! Try {{suggestedName}}?"
|
name_taken: "Gebruikersnaam bestaat al! Probeer {{suggestedName}}?"
|
||||||
# name_available: "Username available!"
|
name_available: "Gebruikersnaam beschikbaar!"
|
||||||
# name_is_email: "Username may not be an email"
|
name_is_email: "Gebruikersnaam mag geen email zijn"
|
||||||
# choose_type: "Choose your account type:"
|
choose_type: "Kies je account type:"
|
||||||
# teacher_type_1: "Teach programming using CodeCombat!"
|
teacher_type_1: "Leer ze programmeren met gebruik van CodeCombat!"
|
||||||
# teacher_type_2: "Set up your class"
|
teacher_type_2: "Maak je klas"
|
||||||
# teacher_type_3: "Access Course Guides"
|
# teacher_type_3: "Access Course Guides"
|
||||||
# teacher_type_4: "View student progress"
|
teacher_type_4: "Bekijk voortgang studenten"
|
||||||
# signup_as_teacher: "Sign up as a Teacher"
|
signup_as_teacher: "Registreer als een docent"
|
||||||
# student_type_1: "Learn to program while playing an engaging game!"
|
student_type_1: "Leer programmeren terwijl je een uitdagend spel speelt!"
|
||||||
# student_type_2: "Play with your class"
|
student_type_2: "Speel met je klas"
|
||||||
# student_type_3: "Compete in arenas"
|
student_type_3: "Strijd in arena's"
|
||||||
# student_type_4: "Choose your hero!"
|
student_type_4: "Kies je held!"
|
||||||
# student_type_5: "Have your Class Code ready!"
|
student_type_5: "Heb je klassencode bij de hand!"
|
||||||
# signup_as_student: "Sign up as a Student"
|
signup_as_student: "Registreer als een student"
|
||||||
# individuals_or_parents: "Individuals & Parents"
|
individuals_or_parents: "Individueel & Ouders"
|
||||||
# individual_type: "For players learning to code outside of a class. Parents should sign up for an account here."
|
individual_type: "Voor spelers die leren coderen buiten school. Ouders moeten zich hier aanmelden."
|
||||||
# signup_as_individual: "Sign up as an Individual"
|
signup_as_individual: "Registreer als een individu (persoonlijk)"
|
||||||
# enter_class_code: "Enter your Class Code"
|
enter_class_code: "Vul je klassencode in"
|
||||||
# enter_birthdate: "Enter your birthdate:"
|
enter_birthdate: "Vul je geboortedatum in:"
|
||||||
# ask_teacher_1: "Ask your teacher for your Class Code."
|
ask_teacher_1: "Vraag je leraar om een klassencode."
|
||||||
# ask_teacher_2: "Not part of a class? Create an "
|
ask_teacher_2: "Maak je geen deel uit een klas? Maak dan een "
|
||||||
# ask_teacher_3: "Individual Account"
|
ask_teacher_3: "Individuele account"
|
||||||
# ask_teacher_4: " instead."
|
ask_teacher_4: "."
|
||||||
# about_to_join: "You're about to join:"
|
# about_to_join: "You're about to join:"
|
||||||
# enter_parent_email: "Enter your parent’s email address:"
|
# enter_parent_email: "Enter your parent’s email address:"
|
||||||
# parent_email_error: "Something went wrong when trying to send the email. Check the email address and try again."
|
# parent_email_error: "Something went wrong when trying to send the email. Check the email address and try again."
|
||||||
|
|
|
@ -16,7 +16,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
||||||
|
|
||||||
new_home:
|
new_home:
|
||||||
slogan: "O jogo mais envolvente para aprender programação."
|
slogan: "O jogo mais envolvente para aprender programação."
|
||||||
# classroom_edition: "Classroom Edition:"
|
classroom_edition: "Editar sala de aula:"
|
||||||
learn_to_code: "Aprenda a programar:"
|
learn_to_code: "Aprenda a programar:"
|
||||||
teacher: "Professor"
|
teacher: "Professor"
|
||||||
student: "Aluno"
|
student: "Aluno"
|
||||||
|
@ -25,38 +25,38 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
||||||
im_a_student: "Eu sou um Aluno"
|
im_a_student: "Eu sou um Aluno"
|
||||||
learn_more: "Aprenda mais"
|
learn_more: "Aprenda mais"
|
||||||
classroom_in_a_box: "Uma sala de aula in-a-box para o ensino de ciência da computação."
|
classroom_in_a_box: "Uma sala de aula in-a-box para o ensino de ciência da computação."
|
||||||
# codecombat_is: "CodeCombat is a platform <strong>for students</strong> to learn computer science while playing through a real game."
|
codecombat_is: "CodeCombat é uma plataforma <strong>para estudantes</strong> aprenderem ciência da computação através de um jogo real."
|
||||||
# our_courses: "Our courses have been specifically playtested to <strong>excel in the classroom</strong>, even by teachers with little to no prior programming experience."
|
our_courses: "Nossos cursos foram pensados especificamente para <strong>o uso em sala de aula</strong>, mesmo para professores com pouco conhecimento prévio em programação."
|
||||||
top_screenshots_hint: "Alunos escrevem seus códigos e veem suas mudanças em tempo real."
|
top_screenshots_hint: "Alunos escrevem seus códigos e veem suas mudanças em tempo real."
|
||||||
designed_with: "Projetado com professores em mente"
|
designed_with: "Projetado com professores em mente"
|
||||||
real_code: "Código escrito, de verdade"
|
real_code: "Código escrito, de verdade"
|
||||||
from_the_first_level: "a partir do primeiro nível"
|
from_the_first_level: "a partir do primeiro nível"
|
||||||
# getting_students: "Getting students to typed code as quickly as possible is critical to learning programming syntax and proper structure."
|
getting_students: "Fazer os estudantes digitarem o código o mais rapido possível é fundamental para aprender a sintaxe de programação e estrurutura apropriada."
|
||||||
educator_resources: "Recursos do educador"
|
educator_resources: "Recursos do educador"
|
||||||
course_guides: "e guia dos cursos"
|
course_guides: "e guia dos cursos"
|
||||||
# teaching_computer_science: "Teaching computer science does not require a costly degree, because we provide tools to support educators of all backgrounds."
|
teaching_computer_science: "Ensinar ciência da computação não requer um diploma oneroso, pois nós disponibilizamos ferramentas para apoiar todoos os tipos de educadores."
|
||||||
accessible_to: "Acessível a"
|
accessible_to: "Acessível a"
|
||||||
everyone: "todos"
|
everyone: "todos"
|
||||||
democratizing: "Democratizar o processo de aprendizagem de codificação é o objectivo da nossa filosofia. Qualquer um deve ser capaz de aprender a programar."
|
democratizing: "Democratizar o processo de aprendizagem de codificação é o objectivo da nossa filosofia. Qualquer um deve ser capaz de aprender a programar."
|
||||||
forgot_learning: "Eu acho que eles realmente esqueceram que estavam aprendendo de verdade."
|
forgot_learning: "Eu acho que eles realmente esqueceram que estavam aprendendo de verdade."
|
||||||
wanted_to_do: "Programar é algo que eu sempre quis fazer, e eu nunca pensei que seria capaz de aprender isso na escola."
|
wanted_to_do: "Programar é algo que eu sempre quis fazer, e eu nunca pensei que seria capaz de aprender isso na escola."
|
||||||
# why_games: "Why is learning through games important?"
|
why_games: "Porque é importante aprender através de jogos?"
|
||||||
# games_reward: "Games reward the productive struggle."
|
games_reward: "Jogos recompensam o esforço produtivo."
|
||||||
# encourage: "Gaming is a medium that encourages interaction, discovery, and trial-and-error. A good game challenges the player to master skills over time, which is the same critical process students go through as they learn."
|
encourage: "Jogar é um meio de encorajar a interação, descoberta, e a tentativa e erro. Um bom jogo desafia o jogador a dominar as habilidades com o tempo, que é o mesmo processo crítico que alunos passam quando eles estão aprendendo algo."
|
||||||
# excel: "Games excel at rewarding"
|
excel: "Jogos destacam-se pela recompesa do"
|
||||||
# struggle: "productive struggle"
|
struggle: "esforço produtivo"
|
||||||
# kind_of_struggle: "the kind of struggle that results in learning that’s engaging and"
|
kind_of_struggle: "o tipo de esforço resultante do aprendizado é cativante,"
|
||||||
motivating: "motivador"
|
motivating: "motivador"
|
||||||
# not_tedious: "not tedious."
|
not_tedious: "e divertido."
|
||||||
gaming_is_good: "Estudos indicam que jogos são bons para o cérebro das crianças. (é verdade!)"
|
gaming_is_good: "Estudos indicam que jogos são bons para o cérebro das crianças. (é verdade!)"
|
||||||
# game_based: "When game-based learning systems are"
|
game_based: "Quando sistemas de aprendizado baseados em jogos são"
|
||||||
compared: "comparado"
|
compared: "comparados"
|
||||||
# conventional: "against conventional assessment methods, the difference is clear: games are better at helping students retain knowledge, concentrate and"
|
conventional: "com métodos de avaliação convencional a diferença é clara: jogos são melhores e ajudam alunos a reter o conhecimento, concentração e"
|
||||||
# perform_at_higher_level: "perform at a higher level of achievement"
|
perform_at_higher_level: "desenvolver um nível superior de realização"
|
||||||
# feedback: "Games also provide real-time feedback that allows students to adjust their solution path and understand concepts more holistically, instead of being limited to just “correct” or “incorrect” answers."
|
feedback: "Jogos também fornecem respostas em tempo real permitindo que os alunos criem seus caminhos para a solução e entendam conceitos mais holisticamente, ao invés de limitar as repostas como “corretas” ou “incorretas”."
|
||||||
real_game: "Um jogo de verdade, com programação de verdade."
|
real_game: "Um jogo de verdade, com programação de verdade."
|
||||||
# great_game: "A great game is more than just badges and achievements - it’s about a player’s journey, well-designed puzzles, and the ability to tackle challenges with agency and confidence."
|
great_game: "Um grande jogo é mais do que apenas emblemas e realizações - Isso é sobre a jornada de um jogador, quebra-cabeças bem desenhados, e a habilidade para enfrentar desafios com ação e confiança."
|
||||||
# agency: "CodeCombat is a game that gives players that agency and confidence with our robust typed code engine, which helps beginner and advanced students alike write proper, valid code."
|
agency: "CodeCombat é um jogo que fornece aos jogadores essa ação e confiança com nosso robusto motor de digitação de código, que ajuda alunos iniciantes e avançados tanto na escrita quanto na validação do código."
|
||||||
# request_demo_title: "Get your students started today!"
|
# request_demo_title: "Get your students started today!"
|
||||||
# request_demo_subtitle: "Request a demo and get your students started in less than an hour."
|
# request_demo_subtitle: "Request a demo and get your students started in less than an hour."
|
||||||
# get_started_title: "Set up your class today"
|
# get_started_title: "Set up your class today"
|
||||||
|
|
|
@ -278,6 +278,7 @@ LevelSchema = c.object {
|
||||||
c.extendNamedProperties LevelSchema # let's have the name be the first property
|
c.extendNamedProperties LevelSchema # let's have the name be the first property
|
||||||
_.extend LevelSchema.properties,
|
_.extend LevelSchema.properties,
|
||||||
description: {title: 'Description', description: 'A short explanation of what this level is about.', type: 'string', maxLength: 65536, format: 'markdown'}
|
description: {title: 'Description', description: 'A short explanation of what this level is about.', type: 'string', maxLength: 65536, format: 'markdown'}
|
||||||
|
studentPlayInstructions: {title: 'Student Play Instructions', description: 'Instructions for game dev levels when students play them.', type: 'string', maxLength: 65536, format: 'markdown'}
|
||||||
loadingTip: { type: 'string', title: 'Loading Tip', description: 'What to show for this level while it\'s loading.' }
|
loadingTip: { type: 'string', title: 'Loading Tip', description: 'What to show for this level while it\'s loading.' }
|
||||||
documentation: c.object {title: 'Documentation', description: 'Documentation articles relating to this level.', 'default': {specificArticles: [], generalArticles: []}},
|
documentation: c.object {title: 'Documentation', description: 'Documentation articles relating to this level.', 'default': {specificArticles: [], generalArticles: []}},
|
||||||
specificArticles: c.array {title: 'Specific Articles', description: 'Specific documentation articles that live only in this level.', uniqueItems: true }, SpecificArticleSchema
|
specificArticles: c.array {title: 'Specific Articles', description: 'Specific documentation articles that live only in this level.', uniqueItems: true }, SpecificArticleSchema
|
||||||
|
@ -312,7 +313,7 @@ _.extend LevelSchema.properties,
|
||||||
body: {type: 'string', format: 'markdown', title: 'Body Text', description: 'Inserted into the Victory Modal once this level is complete. Tell the player they did a good job and what they accomplished!'},
|
body: {type: 'string', format: 'markdown', title: 'Body Text', description: 'Inserted into the Victory Modal once this level is complete. Tell the player they did a good job and what they accomplished!'},
|
||||||
i18n: {type: 'object', format: 'i18n', props: ['body'], description: 'Help translate this victory message'}
|
i18n: {type: 'object', format: 'i18n', props: ['body'], description: 'Help translate this victory message'}
|
||||||
}
|
}
|
||||||
i18n: {type: 'object', format: 'i18n', props: ['name', 'description', 'loadingTip'], description: 'Help translate this level'}
|
i18n: {type: 'object', format: 'i18n', props: ['name', 'description', 'loadingTip', 'studentPlayInstructions'], description: 'Help translate this level'}
|
||||||
icon: {type: 'string', format: 'image-file', title: 'Icon'}
|
icon: {type: 'string', format: 'image-file', title: 'Icon'}
|
||||||
banner: {type: 'string', format: 'image-file', title: 'Banner'}
|
banner: {type: 'string', format: 'image-file', title: 'Banner'}
|
||||||
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
|
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
|
||||||
|
|
|
@ -117,6 +117,7 @@ module.exports =
|
||||||
|
|
||||||
'level:show-victory': c.object {required: ['showModal']},
|
'level:show-victory': c.object {required: ['showModal']},
|
||||||
showModal: {type: 'boolean'}
|
showModal: {type: 'boolean'}
|
||||||
|
manual: { type: 'boolean' }
|
||||||
|
|
||||||
'level:highlight-dom': c.object {required: ['selector']},
|
'level:highlight-dom': c.object {required: ['selector']},
|
||||||
selector: {type: 'string'}
|
selector: {type: 'string'}
|
||||||
|
|
|
@ -16,3 +16,7 @@
|
||||||
|
|
||||||
.teacher-name
|
.teacher-name
|
||||||
font-size: 14pt
|
font-size: 14pt
|
||||||
|
|
||||||
|
.parent_birthdate
|
||||||
|
font-size: 11pt
|
||||||
|
margin-top: 20px
|
||||||
|
|
|
@ -592,6 +592,79 @@ $gameControlMargin: 30px
|
||||||
margin: 15px 0
|
margin: 15px 0
|
||||||
min-width: 100px
|
min-width: 100px
|
||||||
|
|
||||||
|
.beta-container
|
||||||
|
$betaImagesWidth: 1902px
|
||||||
|
width: $campaignWidth
|
||||||
|
height: $campaignHeight
|
||||||
|
display: inline-block
|
||||||
|
flex-shrink: 0
|
||||||
|
position: relative
|
||||||
|
|
||||||
|
.beta-campaign
|
||||||
|
width: $campaignWidth
|
||||||
|
height: $campaignHeight / 2
|
||||||
|
display: inline-block
|
||||||
|
flex-shrink: 0
|
||||||
|
position: relative
|
||||||
|
cursor: pointer
|
||||||
|
// http://easings.net/#easeOutBack plus tweaked a bit: http://cubic-bezier.com/#.11,.67,.08,1.42
|
||||||
|
@include transition(0.25s cubic-bezier(0.11, 0.67, 0.8, 1.42))
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
@include scale($campaignHoverScale)
|
||||||
|
|
||||||
|
&.silhouette
|
||||||
|
@include filter(contrast(50%) brightness(65%))
|
||||||
|
pointer-events: none
|
||||||
|
|
||||||
|
&.locked
|
||||||
|
@include filter(contrast(80%) brightness(80%))
|
||||||
|
pointer-events: none
|
||||||
|
|
||||||
|
.campaign-label
|
||||||
|
position: absolute
|
||||||
|
top: 40%
|
||||||
|
width: 100%
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
.campaign-name, .levels-completed, .campaign-locked
|
||||||
|
margin: 0
|
||||||
|
color: white
|
||||||
|
text-shadow: black 2px 2px 0, black -2px -2px 0, black 2px -2px 0, black -2px 2px 0, black 2px 0px 0, black 0px -2px 0, black -2px 0px 0, black 0px 2px 0
|
||||||
|
|
||||||
|
.campaign-locked
|
||||||
|
margin: 32px 0
|
||||||
|
|
||||||
|
.campaign-description
|
||||||
|
margin: 0px 40px
|
||||||
|
background: transparent url(/images/level/popover_border_background.png) no-repeat
|
||||||
|
background-size: 100% 100%
|
||||||
|
padding: 12px
|
||||||
|
color: black
|
||||||
|
font-size: 12px
|
||||||
|
|
||||||
|
.levels-completed
|
||||||
|
font-size: 22px
|
||||||
|
|
||||||
|
.play-button
|
||||||
|
margin: 10px 0
|
||||||
|
min-width: 100px
|
||||||
|
color: white
|
||||||
|
|
||||||
|
.background-container
|
||||||
|
position: absolute
|
||||||
|
left: $campaignWidth / 4
|
||||||
|
width: $campaignWidth / 2
|
||||||
|
height: $campaignHeight / 2
|
||||||
|
background: transparent url(/images/pages/play/portal-beta-campaigns.png) no-repeat 0 0
|
||||||
|
background-size: $betaImagesWidth / 2
|
||||||
|
|
||||||
|
&.campaign-web-dev-1
|
||||||
|
background-position: -151px 0px
|
||||||
|
&.campaign-game-dev-1
|
||||||
|
background-position: -454px 0px
|
||||||
|
|
||||||
|
|
||||||
.small-nav-logo, .picoctf-powered-by
|
.small-nav-logo, .picoctf-powered-by
|
||||||
position: absolute
|
position: absolute
|
||||||
top: 1%
|
top: 1%
|
||||||
|
|
|
@ -52,6 +52,7 @@ body.dialogue-view-active
|
||||||
|
|
||||||
.spell-palette-popover.popover
|
.spell-palette-popover.popover
|
||||||
// Only those popovers which are our direct children (spell documentation)
|
// Only those popovers which are our direct children (spell documentation)
|
||||||
|
top: 80px !important
|
||||||
left: auto !important
|
left: auto !important
|
||||||
right: 45%
|
right: 45%
|
||||||
max-width: 600px
|
max-width: 600px
|
||||||
|
|
|
@ -146,6 +146,13 @@ block content
|
||||||
small(data-i18n="about.lisa_title")
|
small(data-i18n="about.lisa_title")
|
||||||
br
|
br
|
||||||
|
|
||||||
|
li
|
||||||
|
img(src="/images/pages/about/sean_small.png").img-thumbnail
|
||||||
|
.team-bio
|
||||||
|
h6.label.team-name Sean McNulty
|
||||||
|
small(data-i18n="about.sean_title")
|
||||||
|
br
|
||||||
|
|
||||||
// Part time / contract
|
// Part time / contract
|
||||||
li
|
li
|
||||||
a(href="http://floor.is/lava/" rel="external")
|
a(href="http://floor.is/lava/" rel="external")
|
||||||
|
|
|
@ -50,6 +50,7 @@ form.modal-body.segment-check
|
||||||
- var thisYear = new Date().getFullYear()
|
- var thisYear = new Date().getFullYear()
|
||||||
for year in _.range(thisYear, thisYear - 100, -1)
|
for year in _.range(thisYear, thisYear - 100, -1)
|
||||||
option(selected=(year == view.signupState.get('birthdayYear'))) #{year}
|
option(selected=(year == view.signupState.get('birthdayYear'))) #{year}
|
||||||
|
.parent_birthdate(data-i18n="signup.parent_use_birthdate")
|
||||||
|
|
||||||
default
|
default
|
||||||
p
|
p
|
||||||
|
|
|
@ -22,12 +22,9 @@ block content
|
||||||
|
|
||||||
#article-treema
|
#article-treema
|
||||||
|
|
||||||
#article-view
|
|
||||||
|
|
||||||
h3(data-i18n="resources.patches") Patches
|
h3(data-i18n="resources.patches") Patches
|
||||||
.patches-view
|
.patches-view
|
||||||
|
|
||||||
hr
|
hr
|
||||||
|
|
||||||
div#error-view
|
div#error-view
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ mixin box
|
||||||
div
|
div
|
||||||
a.teacher-btn.btn.btn-primary.btn-lg.btn-block(data-event-action="Homepage Click Teacher Button CTA", data-i18n="new_home.im_a_teacher")
|
a.teacher-btn.btn.btn-primary.btn-lg.btn-block(data-event-action="Homepage Click Teacher Button CTA", data-i18n="new_home.im_a_teacher")
|
||||||
div
|
div
|
||||||
a.student-btn.btn.btn-forest.btn-lg.btn-block(href="/courses", data-event-action="Homepage Click Student Button CTA", data-i18n="new_home.im_a_student")
|
a.student-btn.btn.btn-forest.btn-lg.btn-block(href="/home#create-account-student", data-event-action="Homepage Click Student Button CTA", data-i18n="new_home.im_a_student")
|
||||||
h6#learn-to-code-header(data-i18n="new_home.learn_to_code")
|
h6#learn-to-code-header(data-i18n="new_home.learn_to_code")
|
||||||
a.btn.btn-gold.btn-lg.btn-block.play-btn(href=view.playURL, data-event-action="Homepage Play Now CTA", data-i18n="new_home.play_now")
|
a.btn.btn-gold.btn-lg.btn-block.play-btn(href=view.playURL, data-event-action="Homepage Play Now CTA", data-i18n="new_home.play_now")
|
||||||
|
|
||||||
|
|
|
@ -100,28 +100,57 @@ if view.showAds()
|
||||||
else
|
else
|
||||||
.portal
|
.portal
|
||||||
.portals
|
.portals
|
||||||
for campaignSlug in ['dungeon', 'forest', 'desert', 'mountain', 'glacier', 'volcano']
|
for campaignSlug in ['dungeon', 'beta-campaigns', 'forest', 'desert', 'mountain', 'glacier', 'volcano']
|
||||||
- var campaign = campaigns[campaignSlug];
|
if campaignSlug === 'beta-campaigns'
|
||||||
- var godmode = me.get('permissions', true).indexOf('godmode') != -1;
|
- var betaSlugs = _.shuffle(['campaign-game-dev-1', 'campaign-web-dev-1']);
|
||||||
div(class="campaign #{campaignSlug}" + (campaign ? "" : " silhouette") + (campaign && campaign.locked && !godmode ? " locked" : ""), data-campaign-slug=campaignSlug)
|
.beta-container
|
||||||
.campaign-label
|
each campaignSlug in betaSlugs
|
||||||
h2.campaign-name
|
- var campaign = campaigns[campaignSlug];
|
||||||
if campaign
|
if !campaign
|
||||||
span= i18n(campaign.attributes, 'fullName')
|
- continue;
|
||||||
else
|
div(class="beta-campaign" + (campaign ? "" : " silhouette") + (campaign && campaign.locked && !godmode ? " locked" : ""), data-campaign-slug=campaignSlug)
|
||||||
span ???
|
.background-container(class="#{campaignSlug}")
|
||||||
if campaign && campaign.levelsTotal
|
.campaign-label
|
||||||
h3.levels-completed
|
h3.campaign-name
|
||||||
span= campaign.levelsCompleted
|
if campaign
|
||||||
| /
|
span= i18n(campaign.attributes, 'fullName')
|
||||||
span= campaign.levelsTotal
|
if campaign.levelsTotal
|
||||||
if campaign && campaign.locked && !godmode
|
span.spl= campaign.levelsCompleted
|
||||||
h3.campaign-locked(data-i18n="play.locked") Locked
|
| /
|
||||||
else if campaign
|
span= campaign.levelsTotal
|
||||||
btn(data-i18n="common.play").btn.btn-illustrated.btn-lg.btn-success.play-button
|
else
|
||||||
if campaign && campaign.get('description')
|
span ???
|
||||||
p.campaign-description
|
if campaign && campaign.locked && !godmode
|
||||||
span= i18n(campaign.attributes, 'description')
|
h4.campaign-locked(data-i18n="play.locked") Locked
|
||||||
|
else if campaign
|
||||||
|
btn.btn.btn-illustrated.btn-lg.btn-primary.play-button(data-i18n="common.play")
|
||||||
|
if campaign && campaign.get('description')
|
||||||
|
p.campaign-description
|
||||||
|
span= i18n(campaign.attributes, 'description')
|
||||||
|
else
|
||||||
|
- var campaign = campaigns[campaignSlug];
|
||||||
|
if !campaign
|
||||||
|
- continue;
|
||||||
|
- var godmode = me.get('permissions', true).indexOf('godmode') != -1;
|
||||||
|
div(class="campaign #{campaignSlug}" + (campaign ? "" : " silhouette") + (campaign && campaign.locked && !godmode ? " locked" : ""), data-campaign-slug=campaignSlug)
|
||||||
|
.campaign-label
|
||||||
|
h2.campaign-name
|
||||||
|
if campaign
|
||||||
|
span= i18n(campaign.attributes, 'fullName')
|
||||||
|
else
|
||||||
|
span ???
|
||||||
|
if campaign && campaign.levelsTotal
|
||||||
|
h3.levels-completed
|
||||||
|
span= campaign.levelsCompleted
|
||||||
|
| /
|
||||||
|
span= campaign.levelsTotal
|
||||||
|
if campaign && campaign.locked && !godmode
|
||||||
|
h3.campaign-locked(data-i18n="play.locked") Locked
|
||||||
|
else if campaign
|
||||||
|
btn(data-i18n="common.play").btn.btn-illustrated.btn-lg.btn-success.play-button
|
||||||
|
if campaign && campaign.get('description')
|
||||||
|
p.campaign-description
|
||||||
|
span= i18n(campaign.attributes, 'description')
|
||||||
|
|
||||||
.game-controls.header-font.picoctf-hide
|
.game-controls.header-font.picoctf-hide
|
||||||
button.btn.poll.hidden(data-i18n="[title]play.poll")
|
button.btn.poll.hidden(data-i18n="[title]play.poll")
|
||||||
|
|
|
@ -79,7 +79,10 @@ block modal-body-content
|
||||||
.reward-panel.hero(data-hero-thang-type=hero.get('original'))
|
.reward-panel.hero(data-hero-thang-type=hero.get('original'))
|
||||||
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
|
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
|
||||||
img(src=hero.getPortraitURL())
|
img(src=hero.getPortraitURL())
|
||||||
.reward-text= animate ? 'New Hero' : hero.get('name')
|
if animate
|
||||||
|
.reward-text(data-i18n="play_level.victory_new_hero") New Hero
|
||||||
|
else
|
||||||
|
.reward-text= i18n(hero.attributes, 'name')
|
||||||
|
|
||||||
if rewards.items
|
if rewards.items
|
||||||
for item in rewards.items
|
for item in rewards.items
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
if view.level.id && view.session.id
|
if view.level.id && view.session.id
|
||||||
h3.m-y-1= view.level.get('name')
|
h3.m-y-1= view.level.get('name')
|
||||||
h4 Created by #{view.session.get('creatorName')}
|
h4= view.state.get('creatorString')
|
||||||
hr
|
hr
|
||||||
|
|
||||||
if view.state.get('loading')
|
if view.state.get('loading')
|
||||||
|
@ -24,24 +24,24 @@
|
||||||
.progress-bar(style="width: #{view.state.get('progress')}")
|
.progress-bar(style="width: #{view.state.get('progress')}")
|
||||||
|
|
||||||
if ready
|
if ready
|
||||||
h3 Goals
|
h3(data-i18n="play_level.goals")
|
||||||
for goalName in view.state.get('goalNames')
|
for goalName in view.state.get('goalNames')
|
||||||
p= goalName
|
p= goalName
|
||||||
|
|
||||||
hr
|
hr
|
||||||
|
|
||||||
h3 How to play:
|
h3(data-i18n="play_game_dev_level.how_to_play_title")
|
||||||
p Use the mouse to control the hero!
|
p(data-i18n="play_game_dev_level.how_to_play_1")
|
||||||
p Click anywhere on the map to move to that location.
|
p(data-i18n="play_game_dev_level.how_to_play_2")
|
||||||
p Click on the ogres to attack them.
|
p(data-i18n="play_game_dev_level.how_to_play_3")
|
||||||
|
|
||||||
if ready
|
if ready
|
||||||
.panel-footer
|
.panel-footer
|
||||||
- var playing = view.state.get('playing')
|
- var playing = view.state.get('playing')
|
||||||
if playing
|
if playing
|
||||||
button#play-btn.btn.btn-lg.btn-burgandy.btn-block Restart Level
|
button#play-btn.btn.btn-lg.btn-burgandy.btn-block(data-i18n="play_game_dev_level.restart")
|
||||||
else
|
else
|
||||||
button#play-btn.btn.btn-lg.btn-forest.btn-block Play Level
|
button#play-btn.btn.btn-lg.btn-forest.btn-block(data-i18n="play_game_dev_level.play")
|
||||||
|
|
||||||
#share-row.m-t-3
|
#share-row.m-t-3
|
||||||
if ready
|
if ready
|
||||||
|
@ -55,4 +55,4 @@
|
||||||
span(data-i18n='sharing.copy_url')
|
span(data-i18n='sharing.copy_url')
|
||||||
|
|
||||||
.panel-body
|
.panel-body
|
||||||
a#play-more-codecombat-btn.btn.btn-lg.btn-navy-alt.pull-right(href="/") Play More CodeCombat
|
a#play-more-codecombat-btn.btn.btn-lg.btn-navy-alt.pull-right(href="/", data-i18n="play_game_dev_level.play_more_codecombat")
|
||||||
|
|
|
@ -52,17 +52,15 @@ if view.showAds()
|
||||||
|
|
||||||
button.btn.btn-lg.btn-warning.banner.header-font#stop-real-time-playback-button(title="Stop real-time playback")
|
button.btn.btn-lg.btn-warning.banner.header-font#stop-real-time-playback-button(title="Stop real-time playback")
|
||||||
if view.level && view.level.isType('game-dev')
|
if view.level && view.level.isType('game-dev')
|
||||||
| Back to coding
|
span(data-i18n="play_game_dev_level.back_to_coding")
|
||||||
else
|
else
|
||||||
span(data-i18n="play_level.skip")
|
span(data-i18n="play_level.skip")
|
||||||
|
|
||||||
#how-to-play-game-dev-panel.panel.panel-default.hide.style-flat
|
#how-to-play-game-dev-panel.panel.panel-default.hide.style-flat
|
||||||
.panel-heading
|
.panel-heading
|
||||||
h3.panel-title How to play:
|
h3.panel-title(data-i18n="play_game_dev_level.how_to_play_title")
|
||||||
.panel-body
|
|
||||||
p Use the mouse to control the hero!
|
.panel-body!= view.howToPlayText
|
||||||
p Click anywhere on the map to move to that location.
|
|
||||||
p Click on the ogres to attack them.
|
|
||||||
|
|
||||||
.hints-view.hide
|
.hints-view.hide
|
||||||
|
|
||||||
|
|
|
@ -84,13 +84,14 @@ module.exports = class NewHomeView extends RootView
|
||||||
|
|
||||||
onClickStudentButton: (e) ->
|
onClickStudentButton: (e) ->
|
||||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', []
|
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', []
|
||||||
|
@render?() if document.location.href.search('/home#create-account-student') isnt -1
|
||||||
|
|
||||||
onClickTeacherButton: (e) ->
|
onClickTeacherButton: (e) ->
|
||||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', []
|
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', []
|
||||||
if me.isTeacher()
|
if me.isTeacher()
|
||||||
application.router.navigate('/teachers', { trigger: true })
|
application.router.navigate('/teachers', { trigger: true })
|
||||||
else
|
else
|
||||||
@scrollToLink('.request-demo-row', 600)
|
application.router.navigate('/teachers/signup', { trigger: true })
|
||||||
|
|
||||||
onClickViewProfile: (e) ->
|
onClickViewProfile: (e) ->
|
||||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', []
|
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', []
|
||||||
|
|
|
@ -16,7 +16,7 @@ module.exports = class SettingsTabView extends CocoView
|
||||||
'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals',
|
'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals',
|
||||||
'type', 'terrain', 'showsGuide', 'banner', 'employerDescription', 'loadingTip', 'requiresSubscription',
|
'type', 'terrain', 'showsGuide', 'banner', 'employerDescription', 'loadingTip', 'requiresSubscription',
|
||||||
'helpVideos', 'replayable', 'scoreTypes', 'concepts', 'picoCTFProblem', 'practice', 'practiceThresholdMinutes'
|
'helpVideos', 'replayable', 'scoreTypes', 'concepts', 'picoCTFProblem', 'practice', 'practiceThresholdMinutes'
|
||||||
'shareable'
|
'shareable', 'studentPlayInstructions'
|
||||||
]
|
]
|
||||||
|
|
||||||
subscriptions:
|
subscriptions:
|
||||||
|
|
|
@ -17,6 +17,8 @@ module.exports = class I18NEditLevelView extends I18NEditModelView
|
||||||
@wrapRow 'Level description', ['description'], description, i18n[lang]?.description, []
|
@wrapRow 'Level description', ['description'], description, i18n[lang]?.description, []
|
||||||
if loadingTip = @model.get('loadingTip')
|
if loadingTip = @model.get('loadingTip')
|
||||||
@wrapRow 'Loading tip', ['loadingTip'], loadingTip, i18n[lang]?.loadingTip, []
|
@wrapRow 'Loading tip', ['loadingTip'], loadingTip, i18n[lang]?.loadingTip, []
|
||||||
|
if studentPlayInstructions = @model.get('studentPlayInstructions')
|
||||||
|
@wrapRow 'Student Play Instructions', ['studentPlayInstructions'], studentPlayInstructions, i18n[lang]?.studentPlayInstructions, []
|
||||||
|
|
||||||
# goals
|
# goals
|
||||||
for goal, index in @model.get('goals') ? []
|
for goal, index in @model.get('goals') ? []
|
||||||
|
|
|
@ -55,6 +55,7 @@ module.exports = class CampaignView extends RootView
|
||||||
'click #back-button': 'onClickBack'
|
'click #back-button': 'onClickBack'
|
||||||
'click #clear-storage-button': 'onClickClearStorage'
|
'click #clear-storage-button': 'onClickClearStorage'
|
||||||
'click .portal .campaign': 'onClickPortalCampaign'
|
'click .portal .campaign': 'onClickPortalCampaign'
|
||||||
|
'click .portal .beta-campaign': 'onClickPortalCampaign'
|
||||||
'mouseenter .portals': 'onMouseEnterPortals'
|
'mouseenter .portals': 'onMouseEnterPortals'
|
||||||
'mouseleave .portals': 'onMouseLeavePortals'
|
'mouseleave .portals': 'onMouseLeavePortals'
|
||||||
'mousemove .portals': 'onMouseMovePortals'
|
'mousemove .portals': 'onMouseMovePortals'
|
||||||
|
@ -365,7 +366,7 @@ module.exports = class CampaignView extends RootView
|
||||||
return experienceScore
|
return experienceScore
|
||||||
|
|
||||||
createLine: (o1, o2) ->
|
createLine: (o1, o2) ->
|
||||||
mapHeight = parseFloat($(".map").css("height"))
|
mapHeight = parseFloat($(".map").css("height"))
|
||||||
mapWidth = parseFloat($(".map").css("width"))
|
mapWidth = parseFloat($(".map").css("width"))
|
||||||
return unless mapHeight > 0
|
return unless mapHeight > 0
|
||||||
ratio = mapWidth / mapHeight
|
ratio = mapWidth / mapHeight
|
||||||
|
@ -668,7 +669,7 @@ module.exports = class CampaignView extends RootView
|
||||||
console.error "CampaignView hero update couldn't find hero slug for original:", hero
|
console.error "CampaignView hero update couldn't find hero slug for original:", hero
|
||||||
|
|
||||||
onClickPortalCampaign: (e) ->
|
onClickPortalCampaign: (e) ->
|
||||||
campaign = $(e.target).closest('.campaign')
|
campaign = $(e.target).closest('.campaign, .beta-campaign')
|
||||||
return if campaign.is('.locked') or campaign.is('.silhouette')
|
return if campaign.is('.locked') or campaign.is('.silhouette')
|
||||||
campaignSlug = campaign.data('campaign-slug')
|
campaignSlug = campaign.data('campaign-slug')
|
||||||
Backbone.Mediator.publish 'router:navigate',
|
Backbone.Mediator.publish 'router:navigate',
|
||||||
|
|
|
@ -33,6 +33,7 @@ module.exports = class PlayGameDevLevelView extends RootView
|
||||||
@state = new State({
|
@state = new State({
|
||||||
loading: true
|
loading: true
|
||||||
progress: 0
|
progress: 0
|
||||||
|
creatorString: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
@supermodel.on 'update-progress', (progress) =>
|
@supermodel.on 'update-progress', (progress) =>
|
||||||
|
@ -92,6 +93,7 @@ module.exports = class PlayGameDevLevelView extends RootView
|
||||||
loading: false
|
loading: false
|
||||||
goalNames
|
goalNames
|
||||||
shareURL
|
shareURL
|
||||||
|
creatorString: $.i18n.t('play_game_dev_level.created_by').replace('{{name}}', @session.get('creatorName'))
|
||||||
})
|
})
|
||||||
@eventProperties = {
|
@eventProperties = {
|
||||||
category: 'Play GameDev Level'
|
category: 'Play GameDev Level'
|
||||||
|
|
|
@ -211,7 +211,12 @@ module.exports = class PlayLevelView extends RootView
|
||||||
@$el.addClass 'web-dev' # Hide some of the elements we won't be using
|
@$el.addClass 'web-dev' # Hide some of the elements we won't be using
|
||||||
return
|
return
|
||||||
@world = @levelLoader.world
|
@world = @levelLoader.world
|
||||||
@$el.addClass 'game-dev' if @level.isType('game-dev')
|
if @level.isType('game-dev')
|
||||||
|
@$el.addClass 'game-dev'
|
||||||
|
@howToPlayText = utils.i18n(@level.attributes, 'studentPlayInstructions')
|
||||||
|
@howToPlayText ?= $.i18n.t('play_game_dev_level.default_student_instructions')
|
||||||
|
@howToPlayText = marked(@howToPlayText, { sanitize: true })
|
||||||
|
@renderSelectors('#how-to-play-game-dev-panel')
|
||||||
@$el.addClass 'hero' if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') # TODO: figure out what this does and comment it
|
@$el.addClass 'hero' if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') # TODO: figure out what this does and comment it
|
||||||
@$el.addClass 'flags' if _.any(@world.thangs, (t) -> (t.programmableProperties and 'findFlags' in t.programmableProperties) or t.inventory?.flag) or @level.get('slug') is 'sky-span'
|
@$el.addClass 'flags' if _.any(@world.thangs, (t) -> (t.programmableProperties and 'findFlags' in t.programmableProperties) or t.inventory?.flag) or @level.get('slug') is 'sky-span'
|
||||||
# TODO: Update terminology to always be opponentSession or otherSession
|
# TODO: Update terminology to always be opponentSession or otherSession
|
||||||
|
@ -548,9 +553,9 @@ module.exports = class PlayLevelView extends RootView
|
||||||
|
|
||||||
onDonePressed: -> @showVictory()
|
onDonePressed: -> @showVictory()
|
||||||
|
|
||||||
onShowVictory: (e) ->
|
onShowVictory: (e={}) ->
|
||||||
$('#level-done-button').show() unless @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev')
|
$('#level-done-button').show() unless @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev')
|
||||||
@showVictory() if e.showModal
|
@showVictory(_.pick(e, 'manual')) if e.showModal
|
||||||
return if @victorySeen
|
return if @victorySeen
|
||||||
@victorySeen = true
|
@victorySeen = true
|
||||||
victoryTime = (new Date()) - @loadEndTime
|
victoryTime = (new Date()) - @loadEndTime
|
||||||
|
@ -563,8 +568,9 @@ module.exports = class PlayLevelView extends RootView
|
||||||
ls: @session?.get('_id')
|
ls: @session?.get('_id')
|
||||||
application.tracker?.trackTiming victoryTime, 'Level Victory Time', @levelID, @levelID
|
application.tracker?.trackTiming victoryTime, 'Level Victory Time', @levelID, @levelID
|
||||||
|
|
||||||
showVictory: ->
|
showVictory: (options={}) ->
|
||||||
return if @level.hasLocalChanges() # Don't award achievements when beating level changed in level editor
|
return if @level.hasLocalChanges() # Don't award achievements when beating level changed in level editor
|
||||||
|
return if @level.isType('game-dev') and @level.get('shareable') and not options.manual
|
||||||
@endHighlight()
|
@endHighlight()
|
||||||
options = {level: @level, supermodel: @supermodel, session: @session, hasReceivedMemoryWarning: @hasReceivedMemoryWarning, courseID: @courseID, courseInstanceID: @courseInstanceID, world: @world}
|
options = {level: @level, supermodel: @supermodel, session: @session, hasReceivedMemoryWarning: @hasReceivedMemoryWarning, courseID: @courseID, courseInstanceID: @courseInstanceID, world: @world}
|
||||||
ModalClass = if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') then HeroVictoryModal else VictoryModal
|
ModalClass = if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') then HeroVictoryModal else VictoryModal
|
||||||
|
@ -638,18 +644,21 @@ module.exports = class PlayLevelView extends RootView
|
||||||
if @level.isType('game-dev')
|
if @level.isType('game-dev')
|
||||||
panel = @$('#how-to-play-game-dev-panel')
|
panel = @$('#how-to-play-game-dev-panel')
|
||||||
panel.removeClass('hide')
|
panel.removeClass('hide')
|
||||||
lines = switch @level.get('slug')
|
# TODO: Remove this once these levels have studentPlayInstructions set.
|
||||||
when 'over-the-garden-wall' then ['Watch to see if the peasants are properly protected.']
|
if not @level.get('studentPlayInstructions')
|
||||||
when 'click-gait' then ['Move to each red "X".', 'Click on the screen to move the Knight there.']
|
lines = switch @level.get('slug')
|
||||||
when 'heros-journey' then ['Move to each red "X".', 'Click on the screen to move the Knight there.']
|
when 'over-the-garden-wall' then ['Watch to see if the peasants are properly protected.']
|
||||||
when 'a-maze-ing' then ['Move to the chest of gems.', 'Click on the screen to move the Duelist there.']
|
when 'click-gait' then ['Move to each red "X".', 'Click on the screen to move the Knight there.']
|
||||||
when 'gemtacular' then ['Move to each of the gems.', 'Click on the screen to move the Captain there.']
|
when 'heros-journey' then ['Move to each red "X".', 'Click on the screen to move the Knight there.']
|
||||||
when 'vorpal-mouse' then ['Slay the ogres.', 'Click on the screen to move the Guardian there.', 'Click on the munchkins to attack them!']
|
when 'a-maze-ing' then ['Move to the chest of gems.', 'Click on the screen to move the Duelist there.']
|
||||||
when 'crushing-it' then ['Slay the ogres.', 'Click on the screen to move the Goliath there.', 'Click on the munchkins to attack them!']
|
when 'gemtacular' then ['Move to each of the gems.', 'Click on the screen to move the Captain there.']
|
||||||
when 'tabula-rasa' then ['Slay any ogres.', 'Collect any coins.', 'Click on the screen to move the Raider there.', 'Click on any munchkins to attack them!']
|
when 'vorpal-mouse' then ['Slay the ogres.', 'Click on the screen to move the Guardian there.', 'Click on the munchkins to attack them!']
|
||||||
else ['Click to control your hero and win your game!']
|
when 'crushing-it' then ['Slay the ogres.', 'Click on the screen to move the Goliath there.', 'Click on the munchkins to attack them!']
|
||||||
html = _.map(lines, (line) -> "<p>#{line}</p>").join('')
|
when 'tabula-rasa' then ['Slay any ogres.', 'Collect any coins.', 'Click on the screen to move the Raider there.', 'Click on any munchkins to attack them!']
|
||||||
panel.find('.panel-body').html(html)
|
else null
|
||||||
|
if lines
|
||||||
|
html = _.map(lines, (line) -> "<p>#{line}</p>").join('')
|
||||||
|
panel.find('.panel-body').html(html)
|
||||||
|
|
||||||
@onWindowResize()
|
@onWindowResize()
|
||||||
|
|
||||||
|
|
|
@ -324,7 +324,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
@playSound 'item-unlocked' if 0.5 < ratio < 0.6
|
@playSound 'item-unlocked' if 0.5 < ratio < 0.6
|
||||||
else if panel.hero
|
else if panel.hero
|
||||||
thangType = @thangTypes[panel.hero]
|
thangType = @thangTypes[panel.hero]
|
||||||
panel.textEl.text(thangType.get('name'))
|
panel.textEl.text utils.i18n(thangType.attributes, 'name')
|
||||||
@playSelectionSound thangType if 0.5 < ratio < 0.6
|
@playSelectionSound thangType if 0.5 < ratio < 0.6
|
||||||
if ratio is 1
|
if ratio is 1
|
||||||
panel.rootEl.removeClass('animating').find('.reward-image-container img').removeClass('pulse')
|
panel.rootEl.removeClass('animating').find('.reward-image-container img').removeClass('pulse')
|
||||||
|
@ -413,7 +413,17 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
AudioPlayer.playSound name, 1
|
AudioPlayer.playSound name, 1
|
||||||
|
|
||||||
getNextLevelCampaign: ->
|
getNextLevelCampaign: ->
|
||||||
{'kithgard-gates': 'forest', 'kithgard-mastery': 'forest', 'siege-of-stonehold': 'desert', 'clash-of-clones': 'mountain', 'summits-gate': 'glacier'}[@level.get('slug')] or @level.get 'campaign' # Much easier to just keep this updated than to dynamically figure it out.
|
# Much easier to just keep this updated than to dynamically figure it out.
|
||||||
|
# TODO: only go back to world selector if any beta campaigns are incomplete
|
||||||
|
{
|
||||||
|
'kithgard-gates': '',
|
||||||
|
'kithgard-mastery': '',
|
||||||
|
'tabula-rasa': '',
|
||||||
|
'wanted-poster': '',
|
||||||
|
'siege-of-stonehold': '',
|
||||||
|
'clash-of-clones': 'mountain',
|
||||||
|
'summits-gate': 'glacier'
|
||||||
|
}[@level.get('slug')] ? @level.get 'campaign'
|
||||||
|
|
||||||
getNextLevelLink: (returnToCourse=false) ->
|
getNextLevelLink: (returnToCourse=false) ->
|
||||||
if @level.isType('course', 'game-dev', 'web-dev') and nextLevel = @level.get('nextLevel') and not returnToCourse
|
if @level.isType('course', 'game-dev', 'web-dev') and nextLevel = @level.get('nextLevel') and not returnToCourse
|
||||||
|
|
|
@ -81,7 +81,7 @@ module.exports = class CastButtonView extends CocoView
|
||||||
onDoneButtonClick: (e) ->
|
onDoneButtonClick: (e) ->
|
||||||
return if @options.level.hasLocalChanges() # Don't award achievements when beating level changed in level editor
|
return if @options.level.hasLocalChanges() # Don't award achievements when beating level changed in level editor
|
||||||
@options.session.recordScores @world?.scores, @options.level
|
@options.session.recordScores @world?.scores, @options.level
|
||||||
Backbone.Mediator.publish 'level:show-victory', showModal: true
|
Backbone.Mediator.publish 'level:show-victory', { showModal: true, manual: true }
|
||||||
|
|
||||||
onSpellChanged: (e) ->
|
onSpellChanged: (e) ->
|
||||||
@updateCastButton()
|
@updateCastButton()
|
||||||
|
|
|
@ -198,10 +198,10 @@ module.exports = class Zatanna
|
||||||
editor.completer.autoInsert = false
|
editor.completer.autoInsert = false
|
||||||
editor.completer.showPopup(editor)
|
editor.completer.showPopup(editor)
|
||||||
|
|
||||||
# Hide popup if more than 10 suggestions
|
# Hide popup if too many suggestions
|
||||||
# TODO: Completions aren't asked for unless we show popup, so this is super hacky
|
# TODO: Completions aren't asked for unless we show popup, so this is super hacky
|
||||||
# TODO: Backspacing to yield more suggestions does not close popup
|
# TODO: Backspacing to yield more suggestions does not close popup
|
||||||
if editor.completer?.completions?.filtered?.length > 10
|
if editor.completer?.completions?.filtered?.length > 20
|
||||||
editor.completer.detach()
|
editor.completer.detach()
|
||||||
|
|
||||||
# Update popup CSS after it's been launched
|
# Update popup CSS after it's been launched
|
||||||
|
@ -244,6 +244,7 @@ module.exports = class Zatanna
|
||||||
|
|
||||||
addCodeCombatSnippets: (level, spellView, e) ->
|
addCodeCombatSnippets: (level, spellView, e) ->
|
||||||
snippetEntries = []
|
snippetEntries = []
|
||||||
|
source = spellView.getSource()
|
||||||
haveFindNearestEnemy = false
|
haveFindNearestEnemy = false
|
||||||
haveFindNearest = false
|
haveFindNearest = false
|
||||||
for group, props of e.propGroups
|
for group, props of e.propGroups
|
||||||
|
@ -279,7 +280,6 @@ module.exports = class Zatanna
|
||||||
else 'while true'
|
else 'while true'
|
||||||
# For now, update autocomplete to use hero instead of self/this, if hero is already used in the source.
|
# For now, update autocomplete to use hero instead of self/this, if hero is already used in the source.
|
||||||
# Later, we should make this happen all the time - or better yet update the snippets.
|
# Later, we should make this happen all the time - or better yet update the snippets.
|
||||||
source = spellView.getSource()
|
|
||||||
if /hero/.test(source) or not /(self[\.\:]|this\.|\@)/.test(source)
|
if /hero/.test(source) or not /(self[\.\:]|this\.|\@)/.test(source)
|
||||||
thisToken =
|
thisToken =
|
||||||
'python': /self/,
|
'python': /self/,
|
||||||
|
@ -318,6 +318,15 @@ module.exports = class Zatanna
|
||||||
attackEntry.content = attackEntry.content.replace '${1:enemy}', '"${1:Enemy Name}"'
|
attackEntry.content = attackEntry.content.replace '${1:enemy}', '"${1:Enemy Name}"'
|
||||||
snippetEntries.push attackEntry
|
snippetEntries.push attackEntry
|
||||||
|
|
||||||
|
# Add copied hero. entries for most important ones that start with hero.
|
||||||
|
sortedEntries = _.sortBy snippetEntries, (entry) -> -1 * parseInt(entry.importance ? 0)
|
||||||
|
for entry in sortedEntries
|
||||||
|
if entry.content?.indexOf('hero.') is 0
|
||||||
|
newEntry = _.cloneDeep(entry)
|
||||||
|
entry.name = "hero.#{newEntry.name}"
|
||||||
|
snippetEntries.push(newEntry)
|
||||||
|
break if snippetEntries.length - sortedEntries.length >= 10
|
||||||
|
|
||||||
if haveFindNearest and not haveFindNearestEnemy
|
if haveFindNearest and not haveFindNearestEnemy
|
||||||
spellView.translateFindNearest()
|
spellView.translateFindNearest()
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,16 @@ function createCloseLead(zpContact, done) {
|
||||||
if (zpContact.phone) {
|
if (zpContact.phone) {
|
||||||
postData.contacts[0].phones = [{phone: zpContact.phone}];
|
postData.contacts[0].phones = [{phone: zpContact.phone}];
|
||||||
}
|
}
|
||||||
|
if (zpContact.district) {
|
||||||
|
postData.custom['demo_nces_district'] = zpContact.district;
|
||||||
|
postData.custom['demo_nces_name'] = zpContact.organization;
|
||||||
|
}
|
||||||
|
if (zpContact.nces_district_id) {
|
||||||
|
postData.custom['demo_nces_district_id'] = zpContact.nces_district_id;
|
||||||
|
}
|
||||||
|
if (zpContact.nces_school_id) {
|
||||||
|
postData.custom['demo_nces_id'] = zpContact.nces_school_id;
|
||||||
|
}
|
||||||
const options = {
|
const options = {
|
||||||
uri: `https://${closeIoApiKey}:X@app.close.io/api/v1/lead/`,
|
uri: `https://${closeIoApiKey}:X@app.close.io/api/v1/lead/`,
|
||||||
body: JSON.stringify(postData)
|
body: JSON.stringify(postData)
|
||||||
|
@ -146,16 +156,31 @@ function getZPContactsPage(contacts, searchQuery, done) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const data = JSON.parse(body);
|
const data = JSON.parse(body);
|
||||||
for (let contact of data.contacts) {
|
for (let contact of data.contacts) {
|
||||||
let organization = contact.organization_name;
|
const newContact = {
|
||||||
if (contact.custom_fields && contact.custom_fields.school_name) organization = contact.custom_fields.school_name;
|
organization: contact.organization_name,
|
||||||
contacts.push({
|
|
||||||
organization: organization,
|
|
||||||
name: contact.name,
|
name: contact.name,
|
||||||
title: contact.title,
|
title: contact.title,
|
||||||
email: contact.email,
|
email: contact.email,
|
||||||
phone: contact.phone,
|
phone: contact.phone,
|
||||||
data: contact
|
data: contact
|
||||||
});
|
};
|
||||||
|
// Check custom fields, school_name set means organization_name is district name
|
||||||
|
if (contact.custom_fields) {
|
||||||
|
if (contact.custom_fields.school_name) {
|
||||||
|
newContact.district = contact.organization_name;
|
||||||
|
newContact.organization = contact.custom_fields.school_name;
|
||||||
|
// console.log(`DEBUG: found contact with school name ${newContact.email} ${contact.custom_fields.school_name}`);
|
||||||
|
}
|
||||||
|
if (contact.custom_fields.nces_district_id) {
|
||||||
|
newContact.nces_district_id = contact.custom_fields.nces_district_id;
|
||||||
|
// console.log(`DEBUG: found contact with district id ${newContact.email} ${newContact.nces_district_id}`);
|
||||||
|
}
|
||||||
|
if (contact.custom_fields.nces_school_id) {
|
||||||
|
newContact.nces_school_id = contact.custom_fields.nces_school_id;
|
||||||
|
// console.log(`DEBUG: found contact with school id ${newContact.email} ${newContact.nces_school_id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contacts.push(newContact);
|
||||||
}
|
}
|
||||||
return done(null, data.pipeline_total);
|
return done(null, data.pipeline_total);
|
||||||
});
|
});
|
||||||
|
|
|
@ -68,7 +68,8 @@ LevelHandler = class LevelHandler extends Handler
|
||||||
'scoreTypes'
|
'scoreTypes'
|
||||||
'concepts'
|
'concepts'
|
||||||
'picoCTFProblem'
|
'picoCTFProblem'
|
||||||
'practiceThresholdMinutes'
|
'practiceThresholdMinutes',
|
||||||
|
'studentPlayInstructions'
|
||||||
]
|
]
|
||||||
|
|
||||||
postEditableProperties: ['name']
|
postEditableProperties: ['name']
|
||||||
|
|
|
@ -107,7 +107,7 @@ module.exports =
|
||||||
getStudents: wrap (req, res, next) ->
|
getStudents: wrap (req, res, next) ->
|
||||||
throw new errors.Unauthorized('You must be an administrator.') unless req.user?.isAdmin()
|
throw new errors.Unauthorized('You must be an administrator.') unless req.user?.isAdmin()
|
||||||
query = $or: [{role: 'student'}, {$and: [{schoolName: {$exists: true}}, {schoolName: {$ne: ''}}, {anonymous: false}]}]
|
query = $or: [{role: 'student'}, {$and: [{schoolName: {$exists: true}}, {schoolName: {$ne: ''}}, {anonymous: false}]}]
|
||||||
users = yield User.find(query).select('lastIP schoolName').lean()
|
users = yield User.find(query).select('lastIP').lean()
|
||||||
for user in users
|
for user in users
|
||||||
if ip = user.lastIP
|
if ip = user.lastIP
|
||||||
user.geo = geoip.lookup(ip)
|
user.geo = geoip.lookup(ip)
|
||||||
|
|
|
@ -48,7 +48,7 @@ describe 'RequestQuoteView', ->
|
||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
})
|
})
|
||||||
_.defer done # Let SuperModel finish
|
view.supermodel.once('loaded-all', done)
|
||||||
|
|
||||||
it 'shows request received', ->
|
it 'shows request received', ->
|
||||||
expect(view.$('#request-form').hasClass('hide')).toBe(true)
|
expect(view.$('#request-form').hasClass('hide')).toBe(true)
|
||||||
|
@ -220,7 +220,7 @@ describe 'RequestQuoteView', ->
|
||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
})
|
})
|
||||||
_.defer done # Let SuperModel finish
|
view.supermodel.once('loaded-all', done)
|
||||||
|
|
||||||
it 'shows form with data from the most recent request', ->
|
it 'shows form with data from the most recent request', ->
|
||||||
expect(view.$('input[name="firstName"]').val()).toBe('First')
|
expect(view.$('input[name="firstName"]').val()).toBe('First')
|
||||||
|
|
Loading…
Reference in a new issue