Merge branch 'master' into production

This commit is contained in:
Rob 2015-11-17 16:24:33 -08:00
commit c761e8de3b
33 changed files with 389 additions and 238 deletions

View file

@ -20,6 +20,7 @@ module.exports = class LevelBus extends Bus
'tome:spell-changed': 'onSpellChanged'
'tome:spell-created': 'onSpellCreated'
'tome:cast-spells': 'onCastSpells'
'tome:winnability-updated': 'onWinnabilityUpdated'
'application:idle-changed': 'onIdleChanged'
'goal-manager:new-goal-states': 'onNewGoalStates'
'god:new-world-created': 'onNewWorldCreated'
@ -119,6 +120,11 @@ module.exports = class LevelBus extends Bus
@changedSessionProperties.state = true
@saveSession()
onWinnabilityUpdated: (e) ->
return unless @onPoint() and e.winnable
return unless e.level.get('slug') in ['ace-of-coders'] # Mirror matches don't otherwise show victory, so we win here.
@onVictory()
onNewWorldCreated: (e) ->
return unless @onPoint()
# Record the flag history.

View file

@ -440,12 +440,12 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
payment_methods_blurb2: "Si necesitas una forma alternativa de pago, por favor contactarse"
sale_already_subscribed: "¡Ya estás subscrito!"
sale_blurb1: "Ahorra 35%"
sale_blurb2: "de descuento en el precio regular de una subscripción de $120 USD por un año completo!"
sale_blurb2: "de descuento en el precio regular de una suscripción de $120 USD por un año completo!"
sale_button: "Venta!"
sale_button_title: "Ahorra 35% al adquirir una subscripción por 1 año"
sale_button_title: "Ahorra 35% al adquirir una suscripción por 1 año"
sale_click_here: "Haz Click Aquí"
sale_ends: "Termina"
sale_extended: "*Las subscripciones existentes se extenderán por un año."
sale_extended: "*Las suscripciones existentes se extenderán por un año."
sale_feature_here: "Esto es lo que obtendrás:"
sale_feature2: "¡Acceso a 9 poderosos <strong>nuevos héroes</strong> con habilidades únicas!"
sale_feature4: "¡Una bonificación inmediata de <strong>42,000 gemas</strong>!"
@ -453,9 +453,9 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
sale_limited_time: "¡Oferta por tiempo limitado!"
sale_new_heroes: "¡Nuevos héroes!"
sale_title: "Venta de regreso a clases"
sale_view_button: "Compra la subscripción de 1 año por"
sale_view_button: "Compra la suscripción de 1 año por"
stripe_description: "Suscripción Mensual"
stripe_description_year_sale: "Subscripción por 1 año (35% descuento)"
stripe_description_year_sale: "Suscripción por 1 año (35% descuento)"
subscription_required_to_play: "Necesitas una suscripción para jugar este nivel."
unlock_help_videos: "Suscríbete para desbloquear todos los video tutoriales."
personal_sub: "Suscripción Personal" # Accounts Subscription View below
@ -598,12 +598,12 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
jose_blurb: "Despegar"
retrostyle_title: "Ilustración"
retrostyle_blurb: "Juegos con estilo Retro"
# rob_title: "Compiler Engineer"
# rob_blurb: "Codes things and stuff"
# josh_c_title: "Game Designer"
# josh_c_blurb: "Designs games"
# carlos_title: "Region Manager, Brazil"
# carlos_blurb: "Celery Man"
rob_title: "Ingeniero de Compilación"
rob_blurb: "Hace código y demás"
josh_c_title: "Diseñador de Juegos"
josh_c_blurb: "Diseña juegos"
carlos_title: "Manager de Región, Brasil"
carlos_blurb: "Hombre apio"
teachers:
more_info: "Información para profesores"
@ -613,8 +613,8 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
cost_premium_server: "CodeCombat es gratis para lso primeros 5 niveles, después de ellos cuesta $9.99 USD mensuales para accesar a nuestros otros más de 190 niveles en nuestraos exclusivos servidores específicos para cada país."
free_1: "Hay más de 110 niveles gratis que cubren cada concepto."
free_2: "Una suscripción mensual le da acceso a tutoriales en vídeo y niveles extra para practicar."
teacher_subs_title: "¡Los amestros obtienen subscripciones gratuitas!"
teacher_subs_0: "Ofrecemos subscripciones gratuitas a profesores con propósitos de evaluación."
teacher_subs_title: "¡Los amestros obtienen suscripciones gratuitas!"
teacher_subs_0: "Ofrecemos suscripciones gratuitas a profesores con propósitos de evaluación."
teacher_subs_1: "Por favor llene nuestra"
teacher_subs_2: "Encuesta para maestros"
teacher_subs_3: "para configurar su suscripción."
@ -642,7 +642,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
material_premium_server: "Aproximadamente 22 horas de juego repartidas en más de 120 niveles sólo para suscriptores, con cinco nueveos niveles cada semana." # {change}
material_1: "Aproximadamente 8 horas de contenido gratis y un adicional de 14 horas de contenido de suscriptores, con cinco nueveos niveles cada semana." # {change}
concepts_title: "¿Qué conceptos están cubiertos?"
how_much_title: "¿Cuánto cuesta una subscripción mensual?"
how_much_title: "¿Cuánto cuesta una suscripción mensual?"
how_much_1: "una"
how_much_2: "suscribción mensual"
how_much_3: "Cuesta u$s9.99, y puede ser cancelada en cualquier momento."
@ -724,8 +724,8 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
wrong_password: "Contraseña incorrecta"
upload_picture: "Sube una imagen"
delete_this_account: "Borrar esta cuenta permanentemente"
# reset_progress_tab: "Reset All Progress"
# reset_your_progress: "Clear all your progress and start over"
reset_progress_tab: "Reiniciar Todo Progreso"
reset_your_progress: "Limpiar todo tu progreso y comenzar de nuevo"
god_mode: "Modo Dios"
password_tab: "Contraseña"
emails_tab: "Correos"
@ -733,7 +733,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
new_password: "Nueva Contraseña"
new_password_verify: "Verificar"
type_in_email: "Ingrese su correo electrónico para confirmar la eliminación de su cuenta."
# type_in_email_progress: "Type in your email to confirm deleting your progress."
type_in_email_progress: "Ingrese su correo para confirmar la eliminación de su progreso."
type_in_password: "Asimismo, ingrese su contraseña."
email_subscriptions: "Suscripciones de Email"
email_subscriptions_none: "No tienes suscripciones."
@ -857,7 +857,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
track_concepts6b: "Ordene a sus miembros por nombre o progreso"
track_concepts7: "Requiere invitación"
track_concepts8: "para unirse"
private_require_sub: "Los clanes privados requieren una subscripción para crearlos o unírseles."
private_require_sub: "Los clanes privados requieren una suscripción para crearlos o unírseles."
courses:
course: "Curso"
@ -1254,26 +1254,26 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
success: "Listo, fue cobrado. Gracias!"
account_prepaid:
purchase_code: "Adquirir un Código de Subscripción"
# purchase_code1: "Subscription Codes can be redeemed to add premium subscription time to one or more CodeCombat accounts."
# purchase_code2: "Each CodeCombat account can only redeem a particular Subscription Code once."
# purchase_code3: "Subscription Code months will be added to the end of any existing subscription on the account."
purchase_code: "Adquirir un Código de Suscripción"
purchase_code1: "Los códigos de suscripción pueden ser canjeados para agregar tiempo de suscripción premium para una o más cuentas CodeCombat."
purchase_code2: "Cada cuenta CodeCombat puede canjear una sola vez un Código de Suscripción en particular."
purchase_code3: "Los meses del Código de Suscripción serán agregados al final de la suscripción existente de la cuenta."
users: "Usuarios"
months: "Meses"
purchase_total: "Total"
purchase_button: "Enviar Adquisición"
your_codes: "Tus Códigos:" # {change}
redeem_codes: "Reclamar un Código de Subscripción"
redeem_codes: "Reclamar un Código de Suscripción"
prepaid_code: "Código Prepagado"
# lookup_code: "Lookup prepaid code"
# apply_account: "Apply to your account"
# copy_link: "You can copy the code's link and send it to someone."
lookup_code: "Buscar código prepagado"
apply_account: "Aplicara tu cuenta"
copy_link: "Puedes copiarl el enlace del código y enviarlo a alguien."
quantity: "Cantidad"
redeemed: "Reclamado"
no_codes: "¡Aún sin códigos!"
# you_can1: "You can"
# you_can2: "purchase a prepaid code"
# you_can3: "that can be applied to your own account or given to others."
you_can1: "Puedes"
you_can2: "comprar un código prepagado"
you_can3: "que puede ser aplicado a tu propia cuenta o regalado a otros."
loading_error:
could_not_load: "Error cargando del servidor"

View file

@ -81,7 +81,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
campaign_multiplayer: "Arene multigiocatore"
campaign_multiplayer_description: "... nelle quali programmi faccia a faccia contro altri giocatori."
# campaign_old_multiplayer: "(Deprecated) Old Multiplayer Arenas"
# campaign_old_multiplayer_description: "Relics of a more civilized age. No simulations are run for these older, hero-less multiplayer arenas."
campaign_old_multiplayer_description: "Reliquie di un'epoca più civilizzata. Nessuna simulazione viene eseguita per queste arene multi-giocatore più vecchie e senza eroi" #"Relics of a more civilized age. No simulations are run for these older, hero-less multiplayer arenas."
share_progress_modal:
blurb: "Stai facendo grandi progressi! Dì ai tuoi genitori quanto hai imparato con CodeCombat."
@ -159,9 +159,9 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
accepted: "Accettate"
rejected: "Rifiutate"
withdrawn: "Ritirate"
# accept: "Accept"
# reject: "Reject"
# withdraw: "Withdraw"
accept: "Accetta" #"Accept"
reject: "Rifiuta" #"Reject"
withdraw: "Ritirati" #"Withdraw"
submitter: "Autore"
submitted: "Data creazione"
commit_msg: "Messaggio di commit"
@ -217,7 +217,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
play_level:
done: "Fatto"
# next_game: "Next game"
next_game: "Prossimo gioco" #"Next game"
# show_menu: "Show game menu"
home: "Pagina iniziale" # Not used any more, will be removed soon.
level: "Livello" # Like "Level: Dungeons of Kithgard"
@ -296,7 +296,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
tip_scrub_shortcut: "Usa Ctrl+[ e Ctrl+] per tornare indietro o avanzare rapidamente."
tip_guide_exists: "Clicca sulla Guida, nel menù di gioco (in alto nella pagina), per informazioni utili."
tip_open_source: "CodeCombat è 100% open source!"
# tip_tell_friends: "Enjoying CodeCombat? Tell your friends about us!"
tip_tell_friends: "Ti piace CodeCombat? Parla di noi ai tuoi amici!" #"Enjoying CodeCombat? Tell your friends about us!"
tip_beta_launch: "CodeCombat è stato lanciato in beta nell'ottobre 2013."
tip_think_solution: "Pensa alla soluzione, non al problema."
tip_theory_practice: "In teoria, non c'è alcuna differenza tra teoria e pratica. Ma in pratica, c'è. - Yogi Berra"
@ -304,20 +304,20 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
tip_debugging_program: "Se il debug è il processo di rimuovere i bug, allora programmare deve essere il processo di crearli. - Edsger W. Dijkstra"
tip_forums: "Visita i nostri forum e facci sapere cosa pensi!"
tip_baby_coders: "Nel futuro, persino i neonati saranno Arcimaghi."
# tip_morale_improves: "Loading will continue until morale improves."
tip_morale_improves: "Il caricamento continuerà fino a che il morale migliora." #"Loading will continue until morale improves."
tip_all_species: "Crediamo che chiunque debba avere le stesse opportunità di imparare a programmare."
# tip_reticulating: "Reticulating spines."
# tip_harry: "Yer a Wizard, "
tip_great_responsibility: "Da grandi abilità di programmazione derivano grandi responsabilità."
tip_munchkin: "Se non mangi la tua verdura, un munchkin verrà a cercarti mentre dormi."
# tip_binary: "There are only 10 types of people in the world: those who understand binary, and those who don't."
# tip_commitment_yoda: "A programmer must have the deepest commitment, the most serious mind. ~ Yoda"
tip_binary: "Ci sono solo 10 tipi di persone al mondo: quelli che capiscono il binario, e quelli che non lo capiscono." #"There are only 10 types of people in the world: those who understand binary, and those who don't."
tip_commitment_yoda: "Un programmatore il più profondo impegno, la mente più seria deve avere. ~ Yoda" #"A programmer must have the deepest commitment, the most serious mind. ~ Yoda"
tip_no_try: "Fare o non fare. Questo non è provare. - Yoda"
tip_patience: "Pazienza devi avere, giovane Padawan. - Yoda"
tip_documented_bug: "Un bug documentato non è bug; è una feature."
tip_impossible: "Sembra sempre impossibile fino a quando non ci si riesce. - Nelson Mandela"
tip_talk_is_cheap: "A parlare sono bravi tutti. Mostrami il codice. - Linus Torvalds"
# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay"
tip_first_language: "La cosa più disastrosa che potrai mai imparare è il tuo primo linguaggio di programmazione. - Alan Kay" #"The most disastrous thing that you can ever learn is your first programming language. - Alan Kay"
tip_hardware_problem: "Quanti programmatori servono per cambiare una lampadina? Nessuno, è un problema di hardware."
tip_hofstadters_law: "Legge di Hofstadter: Ci vuole sempre più del previsto, anche quando tieni conto della legge di Hofstadter."
tip_premature_optimization: "L'ottimizzazione prematura è l'origine di tutti i mali. - Donald Knuth"
@ -327,9 +327,9 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
tip_control_destiny: "Nel vero open source, hai il diritto di controllare il propio destino. - Linus Torvalds"
tip_no_code: "Nessun codice è più veloce di nessun codice."
tip_code_never_lies: "Il codice non mente mai, ma i commenti a volte lo fanno. — Ron Jeffries"
# tip_reusable_software: "Before software can be reusable it first has to be usable."
tip_reusable_software: "Prima che un software sia riusabile deve intanto essere usabile." #"Before software can be reusable it first has to be usable."
tip_optimization_operator: "Ogni linguaggio ha un operatore di ottimizzazione. Nella maggior parte dei casi questo operatore è //"
# tip_lines_of_code: "Measuring programming progress by lines of code is like measuring aircraft building progress by weight. — Bill Gates"
tip_lines_of_code: "Misurare l'avanzamento di un programma dalle righe di codice è come misurare l'avanzamento nella costruzione di un aereo dal peso. - Bill Gates" #"Measuring programming progress by lines of code is like measuring aircraft building progress by weight. — Bill Gates"
tip_source_code: "Vorrei cambiare il mondo, ma non mi danno il codice sorgente."
tip_javascript_java: "Java sta a JavaScript come Cane sta a Canestro. - Chris Heilmann"
tip_move_forward: "Qualsiasi cosa tu faccia, vai sempre avanti. - Martin Luther King Jr."
@ -340,8 +340,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
tip_recurse: "Iterare e umano, usare la ricorsione è divino. - L. Peter Deutsch"
tip_free_your_mind: "Devi liberarti di tutto questo, Neo. Paura, dubbio, sfiducia. Libera la tua mente. - Morpheus"
tip_strong_opponents: "Anche il più tenace degli avversari ha sempre una debolezza. - Itachi Uchiha"
# tip_paper_and_pen: "Before you start coding, you can always plan with a sheet of paper and a pen."
# tip_solve_then_write: "First, solve the problem. Then, write the code. - John Johnson"
tip_paper_and_pen: "Prima di iniziare a programmare, puoi sempre progettare con un foglio di carta e una penna." #"Before you start coding, you can always plan with a sheet of paper and a pen."
tip_solve_then_write: "Prima, risolvi il problema. Poi, scrivi il codice. - John Johnson" #"First, solve the problem. Then, write the code. - John Johnson"
game_menu:
inventory_tab: "Inventario"
@ -410,7 +410,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
feature7: "Clan <strong>privati</strong>"
free: "Gratis"
month: "mese"
# must_be_logged: "You must be logged in first. Please create an account or log in from the menu above."
must_be_logged: "Devi aver prima effettuato il login. Crea un account o effettua il login dal menu superiore." #"You must be logged in first. Please create an account or log in from the menu above."
subscribe_title: "Abbonati"
unsubscribe: "Disabbonati"
confirm_unsubscribe: "Conferma disabbonamento"
@ -438,10 +438,10 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
payment_methods_title: "Metodi di Pagamento Accetati"
payment_methods_blurb1: "Attualmente accettiamo come metodi di pagamento la carta di credito e Alipay."
payment_methods_blurb2: "Se necessiti di un forma di pagamento diverso.Per favore contattaci"
# sale_already_subscribed: "You're already subscribed!"
sale_already_subscribed: "Sei già abbonato!" #"You're already subscribed!"
sale_blurb1: "Risparmia il 35%"
# sale_blurb2: "off regular subscription price of $120 for a whole year!"
# sale_button: "Sale!"
sale_button: "Saldi!" #"Sale!"
sale_button_title: "Risparmi il 35% quando compri l'abbonamento per 1 anno"
sale_click_here: "Clicca qui"
# sale_ends: "Ends"
@ -472,14 +472,14 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
# group_discounts_1: "We also offer group discounts for bulk subscriptions."
group_discounts_1st: "Prima sottoscrizione"
group_discounts_full: "Prezzo completo"
# group_discounts_2nd: "Subscriptions 2-11"
group_discounts_2nd: "Sottoscrizione 2-11" #"Subscriptions 2-11"
group_discounts_20: "20% disconto"
# group_discounts_12th: "Subscriptions 12+"
group_discounts_12th: "Sottoscrizione 12+" #"Subscriptions 12+"
group_discounts_40: "40% di sconto"
# subscribing: "Subscribing..."
# recipient_emails_placeholder: "Enter email address to subscribe, one per line."
subscribe_users: "Sottoscrivere Utenti"
users_subscribed: "Utenti sottoscritti:"
subscribe_users: "Iscrivere Utenti"
users_subscribed: "Utenti iscritti:"
# no_users_subscribed: "No users subscribed, please double check your email addresses."
# current_recipients: "Current Recipients"
# unsubscribing: "Unsubscribing"
@ -527,8 +527,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
skill_docs:
writable: "scrivibile" # Hover over "attack" in Your Skills while playing a level to see most of this
read_only: "sola lettura"
# action: "Action"
# spell: "Spell"
action: "Azione" #"Action"
spell: "Incantesimo" #"Spell"
action_name: "nome"
action_cooldown: "Richiede"
action_specific_cooldown: "Riposo"
@ -721,11 +721,11 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
picture_tab: "Immagine"
delete_account_tab: "Cancella il tuo account"
wrong_email: "Indirizzo email sbagliato"
# wrong_password: "Wrong Password"
wrong_password: "Password Sbagliata" #"Wrong Password"
upload_picture: "Carica immagine"
delete_this_account: "Cancella questo account per sempre"
# reset_progress_tab: "Reset All Progress"
# reset_your_progress: "Clear all your progress and start over"
reset_your_progress: "Cancella tutti i tuoi progressi e inizia da capo" #"Clear all your progress and start over"
# god_mode: "God Mode"
password_tab: "Password"
emails_tab: "Email"
@ -733,8 +733,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
new_password: "Nuova password"
new_password_verify: "Verifica"
type_in_email: "Scrivi il tuo indirizzo email per confermare la cancellazione" # {change}
# type_in_email_progress: "Type in your email to confirm deleting your progress."
# type_in_password: "Also, type in your password."
type_in_email_progress: "Inserisci la tua email per confermare la cancellazione dei tuoi progressi." #"Type in your email to confirm deleting your progress."
type_in_password: "Inoltre, inserisci la tua password." #"Also, type in your password."
email_subscriptions: "Iscrizioni alle email"
email_subscriptions_none: "Nessuna iscrizione."
email_announcements: "Annunci email"
@ -765,7 +765,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
keyboard_shortcuts: "Scorciatoie da tastiera"
space: "Spazio"
enter: "Invio"
# press_enter: "press enter"
press_enter: "premi invio" #"press enter"
escape: "Esc"
shift: "Maiusc"
run_code: "Esegui codice attuale."
@ -792,7 +792,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
article_editor_prefix: "Hai trovato un errore in uno dei nostri documenti? Vuoi creare delle istruzioni per una delle tue creazioni? Vai a"
article_editor_suffix: "e aiuta i giocatori di CodeCombat ad ottenere il massimo mentre giocano a programmare."
find_us: "Dove trovarci"
# social_github: "Check out all our code on GitHub"
social_github: "Esplora tutto il nostro codice su GitHub" #"Check out all our code on GitHub"
social_blog: "Leggi il blog di CodeCombat su Sett"
social_discource: "Partecipa alle discussioni nel nostro forum Discourse"
social_facebook: "Metti 'mi piace' a CodeCombat su Facebook"
@ -809,7 +809,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
make_private: "Rendi clan privato"
subs_only: "solo per abbonati"
create_clan: "Crea nuovo clan"
# private_preview: "Preview"
private_preview: "Anteprima" #"Preview"
public_clans: "Clan pubblici"
my_clans: "I miei clan"
clan_name: "Nome clan"
@ -979,8 +979,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
indoor: "Interno"
desert: "Deserto"
grassy: "Erboso"
# mountain: "Mountain"
# glacier: "Glacier"
mountain: "Montagna" #"Mountain"
glacier: "Ghiacciaio" #"Glacier"
small: "Piccolo"
large: "Grande"
# fork_title: "Fork New Version"
@ -1189,8 +1189,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
# red_ai: "Red AI" # "Red AI Wins", at end of multiplayer match playback
# blue_ai: "Blue AI"
# wins: "Wins" # At end of multiplayer match playback
# humans: "Red" # Ladder page display team name
# ogres: "Blue"
humans: "Rosso" #"Red" # Ladder page display team name
ogres: "Blu" #"Blue"
user:
stats: "Statistiche"
@ -1226,7 +1226,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
purchased: "Acquistato"
# sale: "Sale"
subscription: "Abbonamento"
# invoices: "Invoices"
invoices: "Fatture" #"Invoices"
service_apple: "Apple"
service_web: "Web"
# paid_on: "Paid On"
@ -1287,7 +1287,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
# bad_input: "Bad input."
server_error: "Errore server."
unknown: "Errore sconosciuto."
# error: "ERROR"
error: "ERRORE" #"ERROR"
resources:
sessions: "Sessioni"
@ -1343,27 +1343,27 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
concepts:
# advanced_strings: "Advanced Strings"
algorithms: "Algoritmi"
# arguments: "Arguments"
# arithmetic: "Arithmetic"
# arrays: "Arrays"
# basic_syntax: "Basic Syntax"
# boolean_logic: "Boolean Logic"
arguments: "Argomenti" #"Arguments"
arithmetic: "Aritmetica" #"Arithmetic"
arrays: "Array"
basic_syntax: "Sintassi di base" #"Basic Syntax"
boolean_logic: "Logica Booleana" #"Boolean Logic"
# break_statements: "Break Statements"
# classes: "Classes"
classes: "Classi" #"Classes"
# continue_statements: "Continue Statements"
# for_loops: "For Loops"
# functions: "Functions"
# graphics: "Graphics"
for_loops: "Cicli For" #"For Loops"
functions: "Funzioni" #"Functions"
graphics: "Grafici" #"Graphics"
# if_statements: "If Statements"
# input_handling: "Input Handling"
# math_operations: "Math Operations"
input_handling: "Gestione dell'Input" #"Input Handling"
math_operations: "Operazioni Matematiche" #"Math Operations"
# object_literals: "Object Literals"
# parameters: "Parameters"
# strings: "Strings"
# variables: "Variables"
# vectors: "Vectors"
# while_loops: "Loops"
# recursion: "Recursion"
parameters: "Parametri" #"Parameters"
strings: "Stringhe" #"Strings"
variables: "Variabili" #"Variables"
vectors: "Vettori" #"Vectors"
while_loops: "Cicli" #"Loops"
recursion: "Ricorsione" #"Recursion"
# delta:
# added: "Added"

View file

@ -598,12 +598,12 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
jose_blurb: "放轻松"
retrostyle_title: "插画师"
retrostyle_blurb: "复古风格的游戏"
# rob_title: "Compiler Engineer"
# rob_blurb: "Codes things and stuff"
# josh_c_title: "Game Designer"
# josh_c_blurb: "Designs games"
# carlos_title: "Region Manager, Brazil"
# carlos_blurb: "Celery Man"
rob_title: "编译器工程师"
rob_blurb: "编代码之类的"
josh_c_title: "游戏设计师"
josh_c_blurb: "设计游戏" # or what
carlos_title: "地区经理, 巴西"
carlos_blurb: "食草男" # unless you have a better one for "celery man"
teachers:
more_info: "教师的说明"
@ -724,16 +724,16 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
wrong_password: "密码错误"
upload_picture: "上传一张图片"
delete_this_account: "永久删除账户"
# reset_progress_tab: "Reset All Progress"
# reset_your_progress: "Clear all your progress and start over"
reset_progress_tab: "重置所有进度"
reset_your_progress: "清除记录并重新开始"
god_mode: "上帝模式"
password_tab: "密码"
emails_tab: "邮件"
admin: "管理"
new_password: "新密码"
new_password_verify: "再次输入密码"
type_in_email: "输入您的邮箱地址来确认删除"
# type_in_email_progress: "Type in your email to confirm deleting your progress."
type_in_email: "输入您的邮箱地址"
type_in_email_progress: "输入邮箱地址来确认删除"
type_in_password: "同样的,输入您的密码。"
email_subscriptions: "邮箱订阅"
email_subscriptions_none: "取消订阅"
@ -846,17 +846,17 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
last_played: "最后玩了"
leagues_explanation: "在部落里与其他成员组成联盟一起参加下面的多人竞技场。"
# track_concepts1: "Track concepts"
# track_concepts2a: "learned by each student"
# track_concepts2b: "learned by each member"
# track_concepts3a: "Track levels completed for each student"
# track_concepts3b: "Track levels completed for each member"
# track_concepts4a: "See your students'"
# track_concepts4b: "See your members'"
# track_concepts5: "solutions"
# track_concepts6a: "Sort students by name or progress"
# track_concepts6b: "Sort members by name or progress"
# track_concepts7: "Requires invitation"
# track_concepts8: "to join"
track_concepts2a: "由每位学生学习"
track_concepts2b: "由每位成员学习"
track_concepts3a: "查看每位同学达到的等级"
track_concepts3b: "查看每位成员达到的等级"
track_concepts4a: "查看你的学生"
track_concepts4b: "查看你的成员"
track_concepts5: "解决方案"
track_concepts6a: "按姓名或进度排序学生"
track_concepts6b: "按姓名或进度排序成员"
track_concepts7: "需要邀请"
track_concepts8: "来加入"
# private_require_sub: "Private clans require a subscription to create or join."
courses:
@ -1258,27 +1258,27 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
# purchase_code1: "Subscription Codes can be redeemed to add premium subscription time to one or more CodeCombat accounts."
# purchase_code2: "Each CodeCombat account can only redeem a particular Subscription Code once."
# purchase_code3: "Subscription Code months will be added to the end of any existing subscription on the account."
# users: "Users"
users: "玩家"
# months: "Months"
purchase_total: "总共"
purchase_button: "提交购买"
your_codes: "你的订阅码:" # {change}
redeem_codes: "兑换订阅码"
# prepaid_code: "Prepaid Code"
# lookup_code: "Lookup prepaid code"
# apply_account: "Apply to your account"
# copy_link: "You can copy the code's link and send it to someone."
# quantity: "Quantity"
# redeemed: "Redeemed"
# no_codes: "No codes yet!"
# you_can1: "You can"
# you_can2: "purchase a prepaid code"
# you_can3: "that can be applied to your own account or given to others."
prepaid_code: "预购码"
lookup_code: "查看预购码"
apply_account: "使用到您的账户"
copy_link: "您可以复制此代码链接发送给别人。"
quantity: "数量"
redeemed: "兑换"
no_codes: "还没有兑换码!"
you_can1: "您可以"
you_can2: "购买一个预购码"
you_can3: "使用在您的账户或者给其他人。"
loading_error:
could_not_load: "载入失败"
connection_failure: "连接失败。"
unauthorized: "您需要登录才行。 您是不是把 cookies 禁用了?"
unauthorized: "您需要登录才行。您是不是禁用了cookie"
forbidden: "您没有权限。"
not_found: "没找到。"
not_allowed: "方法不允许。"

View file

@ -26,6 +26,7 @@ MongoFindQuerySchema =
{type: 'object'}
{type: 'boolean'}
]
properties: {}
additionalProperties: false
definitions: {}

View file

@ -8,6 +8,8 @@ _.extend ClassroomSchema.properties,
ownerID: c.objectId()
description: {type: 'string'}
code: c.shortString(title: "Unique code to redeem")
aceConfig:
language: {type: 'string', 'enum': ['python', 'javascript']}
c.extendBasicProperties ClassroomSchema, 'Classroom'

View file

@ -169,6 +169,11 @@ _.extend LevelSessionSchema.properties,
chat:
type: 'array'
ladderAchievementDifficulty:
type: 'integer'
minimum: 0
description: 'What ogre AI difficulty, 0-4, this human session has beaten in a multiplayer arena.'
meanStrength:
type: 'number'

View file

@ -136,6 +136,7 @@ module.exports =
'tome:winnability-updated': c.object {title: 'Winnability Updated', description: 'When we think we can now win (or can no longer win), we may want to emphasize the submit button versus the run button (or vice versa), so this fires when we get new goal states (even preloaded goal states) suggesting success or failure change.', required: ['winnable']},
winnable: {type: 'boolean'}
level: {type: 'object'}
# Problem Alert
'tome:show-problem-alert': c.object {title: 'Show Problem Alert', description: 'A problem alert needs to be shown.', required: ['problem']},

View file

@ -3,6 +3,11 @@
img.media-object
width: 300px
.edit-classroom-small
cursor: pointer
&:hover
color: grey
#fixed-area
position: fixed

View file

@ -190,7 +190,7 @@
// border-bottom: 1px dotted rgba(0, 51, 255, 0.25)
.ace_text-layer .ace_comment
color: rgb(78, 38, 226)
color: #1900AD
.ace_text-layer .ace_variable
// https://github.com/codecombat/codecombat/issues/6

View file

@ -80,28 +80,26 @@ block content
span.spr(data-i18n="[title]account_prepaid.copy_link;general.code", title="You can copy the code's link and send it to someone.")
span.glyphicon.glyphicon-question-sign(aria-hidden="true")
th(data-i18n="account_prepaid.months")
th(data-i18n="account_prepaid.quantity")
th Remaining Users
th Total Users
th(data-i18n="user.status")
for code in codes.models
if code.get('type') === 'terminal_subscription'
- var owner = (code.get('creator') == me.id ? true : false)
- var properties = code.get('properties')
- var redeemers = code.get('redeemers')
if redeemers
- var redeemed = redeemers.length
else
- var redeemed = '0'
- var redeemed = redeemers ? redeemers.length : 0
tr
td
a(href="/account/prepaid?_ppc=#{code.get('code')}")= code.get('code')
td= properties.months || '-'
if owner
td= code.get('maxRedeemers') - redeemed
else
td -
if owner
td= code.get('maxRedeemers')
td(data-i18n="account.purchased")
else
td -
td -
td(data-i18n="account_prepaid.redeemed")
else
p(data-i18n="account_prepaid.no_codes")

View file

@ -0,0 +1,24 @@
extends /templates/core/modal-base
block modal-header-content
button.close(data-dismiss='modal')
span &times;
h3.modal-title(data-i18n="courses.edit_settings1")
block modal-body-content
.form
.form-group
label(data-i18n="courses.title")
input.form-control.settings-name-input(type='text', value="#{view.classroom.get('name') || ''}")
.form-group
label(data-i18n="courses.description")
textarea.form-control.settings-description-input(rows=2)= view.classroom.get('description')
.form-group
label(data-i18n="choose_hero.programming_language")
select.form-control#programming-language-select
- var aceConfig = view.classroom.get('aceConfig') || {};
option(value="python", selected=aceConfig.language==='python') Python
option(value="javascript", selected=aceConfig.language==='javascript') JavaScript
block modal-footer-content
button#save-settings-btn.btn(data-i18n="common.save_changes")

View file

@ -53,12 +53,7 @@ block content
if courseInstance.get('description')
each line in courseInstance.get('description').split('\n')
div= line
// TODO: migrate these settings to classrooms
//if adminMode && courseInstance
// +settings-dialog
// p
// button.btn.btn-xs(data-toggle='modal', data-target='#settingsModal', data-i18n="courses.edit_settings")
div.well.well-sm(role='tabpanel')
ul.nav.nav-pills(role='tablist')
if adminMode
@ -292,27 +287,3 @@ mixin levels-tab
if levelConceptMap[levelID][concept]
span.spr.progress-level-cell.progress-level-cell-not-started(data-i18n="concepts." + concept)
mixin settings-dialog
.modal#settingsModal
.modal-dialog
.modal-header
button.close(data-dismiss='modal')
span &times;
h3.modal-title(data-i18n="courses.edit_settings1")
.modal-body
.form
.form-group
label(data-i18n="courses.title")
input.form-control.settings-name-input(type='text', value="#{courseInstance.get('name') || ''}")
.form-group
label(data-i18n="courses.description")
textarea.form-control.settings-description-input(rows=2)= courseInstance.get('description')
.form-group
label(data-i18n="choose_hero.programming_language")
select.form-control#programming-language-select
- var aceConfig = view.courseInstance.get('aceConfig') || {};
option(value="python", selected=aceConfig.language==='python') Python
option(value="javascript", selected=aceConfig.language==='javascript') JavaScript
.modal-footer
button.btn.btn-save-settings(data-i18n="common.save_changes")

View file

@ -102,7 +102,15 @@ block content
a.btn.btn-default.btn-xs(href="/courses/purchase") Add
for classroom in view.classrooms.models
h2= classroom.get('name')
h2
span.spr= classroom.get('name')
- var language = (classroom.get('aceConfig') || {}).language || 'python';
if language === 'python'
img(src="/images/common/code_languages/python_icon.png")
if language === 'javascript'
img(src="/images/common/code_languages/javascript_icon.png")
small.spl.edit-classroom-small(data-classroom-id=classroom.id)
span.glyphicon.glyphicon-pencil
- var courseInstances = view.courseInstances.where({classroomID: classroom.id})
@ -111,6 +119,9 @@ block content
.progress-bar(style="width: 100%")
else
- var description = classroom.get('description');
if description
p= description
table.table
tr
th Student

View file

@ -26,48 +26,49 @@ block modal-body-content
textarea(data-i18n="[placeholder]play_level.victory_review_placeholder")
.clearfix
for achievement in achievements
- var animate = achievement.completed && !achievement.completedAWhileAgo
.achievement-panel(class=achievement.completedAWhileAgo ? 'earned' : '' data-achievement-id=achievement.id data-animate=animate)
- var rewards = achievement.get('rewards') || {};
div.achievement-description= achievement.description
div.achievement-rewards
- var worth = achievement.worth;
- var previousWorth = achievement.previousWorth;
- var gems = achievement.gems;
- var previousGems = achievement.previousGems;
if worth
.reward-panel.numerical.xp(data-number=worth, data-number-unit='xp', data-previous-number=previousWorth || 0)
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
img(src="/images/pages/play/level/modal/reward_icon_xp.png")
.reward-text= animate ? '+0' : '+'+worth
if level.get('type', true) === 'hero' || level.get('type') == 'hero-ladder'
for achievement in achievements
- var animate = achievement.completed && !achievement.completedAWhileAgo
.achievement-panel(class=achievement.completedAWhileAgo ? 'earned' : '' data-achievement-id=achievement.id data-animate=animate)
- var rewards = achievement.get('rewards') || {};
if gems
.reward-panel.numerical.gems(data-number=gems, data-number-unit='gem', data-previous-number=previousGems || 0)
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
img(src="/images/pages/play/level/modal/reward_icon_gems.png")
.reward-text= animate ? '+0' : '+'+gems
if rewards.heroes
for hero in rewards.heroes
- var hero = thangTypes[hero];
.reward-panel.hero(data-hero-thang-type=hero.get('original'))
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
img(src=hero.getPortraitURL())
.reward-text= animate ? 'New Hero' : hero.get('name')
div.achievement-description= achievement.description
if rewards.items
for item in rewards.items
- var item = thangTypes[item];
.reward-panel.item(data-item-thang-type=item.get('original'))
div.achievement-rewards
- var worth = achievement.worth;
- var previousWorth = achievement.previousWorth;
- var gems = achievement.gems;
- var previousGems = achievement.previousGems;
if worth
.reward-panel.numerical.xp(data-number=worth, data-number-unit='xp', data-previous-number=previousWorth || 0)
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
img(src=item.getPortraitURL())
if animate
.reward-text(data-i18n="play_level.victory_new_item") New Item
else
.reward-text= i18n(item.attributes, 'name')
img(src="/images/pages/play/level/modal/reward_icon_xp.png")
.reward-text= animate ? '+0' : '+'+worth
if gems
.reward-panel.numerical.gems(data-number=gems, data-number-unit='gem', data-previous-number=previousGems || 0)
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
img(src="/images/pages/play/level/modal/reward_icon_gems.png")
.reward-text= animate ? '+0' : '+'+gems
if rewards.heroes
for hero in rewards.heroes
- var hero = thangTypes[hero];
.reward-panel.hero(data-hero-thang-type=hero.get('original'))
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
img(src=hero.getPortraitURL())
.reward-text= animate ? 'New Hero' : hero.get('name')
if rewards.items
for item in rewards.items
- var item = thangTypes[item];
.reward-panel.item(data-item-thang-type=item.get('original'))
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
img(src=item.getPortraitURL())
if animate
.reward-text(data-i18n="play_level.victory_new_item") New Item
else
.reward-text= i18n(item.attributes, 'name')
block modal-footer-content
#totals

View file

@ -38,7 +38,7 @@ module.exports = class RootView extends CocoView
showNewAchievement: (achievement, earnedAchievement) ->
earnedAchievement.set('notified', true)
earnedAchievement.patch()
return if achievement.get('collection') is 'level.sessions'
return if achievement.get('collection') is 'level.sessions' and not achievement.get('query')?.team
#return if @isIE() # Some bugs in IE right now, TODO fix soon! # Maybe working now with not caching achievement fetches in CocoModel?
new AchievementPopup achievement: achievement, earnedAchievement: earnedAchievement

View file

@ -0,0 +1,26 @@
ModalView = require 'views/core/ModalView'
template = require 'templates/courses/classroom-settings-modal'
module.exports = class AddLevelSystemModal extends ModalView
id: 'classroom-settings-modal'
template: template
events:
'click #save-settings-btn': 'onClickSaveSettingsButton'
initialize: (options) ->
@classroom = options.classroom
onClickSaveSettingsButton: ->
return unless @classroom
if name = $('.settings-name-input').val()
@classroom.set('name', name)
description = $('.settings-description-input').val()
@classroom.set('description', description)
@classroom.set('aceConfig', {
language: @$('#programming-language-select').val()
})
@classroom.patch()
@hide()

View file

@ -19,7 +19,6 @@ module.exports = class CourseDetailsView extends RootView
events:
'change .progress-expand-checkbox': 'onCheckExpandedProgress'
'click .btn-play-level': 'onClickPlayLevel'
'click .btn-save-settings': 'onClickSaveSettings'
'click .btn-select-instance': 'onClickSelectInstance'
'click .progress-member-header': 'onClickMemberHeader'
'click .progress-header': 'onClickProgressHeader'
@ -228,19 +227,6 @@ module.exports = class CourseDetailsView extends RootView
getLevelURL: (levelSlug) ->
"/play/level/#{levelSlug}?course=#{@courseID}&course-instance=#{@courseInstanceID}"
onClickSaveSettings: (e) ->
return unless @courseInstance
if name = $('.settings-name-input').val()
@courseInstance.set('name', name)
description = $('.settings-description-input').val()
console.log 'onClickSaveSettings', description
@courseInstance.set('description', description)
@courseInstance.set('aceConfig', {
language: @$('#programming-language-select').val()
})
@courseInstance.patch()
$('#settingsModal').modal('hide')
onClickSelectInstance: (e) ->
courseInstanceID = $('.select-instance').val()
@noCourseInstanceSelected = false

View file

@ -11,6 +11,7 @@ RootView = require 'views/core/RootView'
template = require 'templates/courses/teacher-courses-view'
utils = require 'core/utils'
InviteToClassroomModal = require 'views/courses/InviteToClassroomModal'
ClassroomSettingsModal = require 'views/courses/ClassroomSettingsModal'
module.exports = class TeacherCoursesView extends RootView
id: 'teacher-courses-view'
@ -22,6 +23,7 @@ module.exports = class TeacherCoursesView extends RootView
'click .course-instance-membership-checkbox': 'onClickCourseInstanceMembershipCheckbox'
'click #save-changes-btn': 'onClickSaveChangesButton'
'click #manage-tab-link': 'onClickManageTabLink'
'click .edit-classroom-small': 'onClickEditClassroomSmall'
constructor: (options) ->
super(options)
@ -71,6 +73,13 @@ module.exports = class TeacherCoursesView extends RootView
@renderSelectors('#manage-tab-pane')
@$('#manage-tab-pane').toggleClass('active', isActive)
onClickEditClassroomSmall: (e) ->
classroomID = $(e.target).closest('small').data('classroom-id')
classroom = @classrooms.get(classroomID)
modal = new ClassroomSettingsModal({classroom: classroom})
@openModalView(modal)
@listenToOnce modal, 'hide', @renderManageTab
onClickAddStudentsButton: (e) ->
classroomID = $(e.target).data('classroom-id')
classroom = @classrooms.get(classroomID)

View file

@ -33,7 +33,7 @@ class LevelSessionsCollection extends CocoCollection
@url = "/db/user/#{me.id}/level.sessions?project=state.complete,levelID,state.difficulty,playtime"
class CampaignsCollection extends CocoCollection
url: '/db/campaign'
url: '/db/campaign/-/overworld'
model: Campaign
project: ['name', 'fullName', 'description', 'i18n']
@ -427,7 +427,8 @@ module.exports = class CampaignView extends RootView
onSessionsLoaded: (e) ->
return if @editorMode
for session in @sessions.models
@levelStatusMap[session.get('levelID')] = if session.get('state')?.complete then 'complete' else 'started'
unless @levelStatusMap[session.get('levelID')] is 'complete' # Don't overwrite a complete session with an incomplete one
@levelStatusMap[session.get('levelID')] = if session.get('state')?.complete then 'complete' else 'started'
@levelDifficultyMap[session.get('levelID')] = session.get('state').difficulty if session.get('state')?.difficulty
@render()
@loadUserPollsRecord() unless me.get 'anonymous'

View file

@ -48,7 +48,7 @@ module.exports = class HeroVictoryModal extends ModalView
@session = options.session
@level = options.level
@thangTypes = {}
if @level.get('type', true) is 'hero'
if @level.get('type', true) in ['hero', 'hero-ladder', 'course', 'course-ladder']
achievements = new CocoCollection([], {
url: "/db/achievement?related=#{@session.get('level').original}"
model: Achievement
@ -212,7 +212,7 @@ module.exports = class HeroVictoryModal extends ModalView
afterRender: ->
super()
@$el.toggleClass 'with-achievements', @level.get('type', true) is 'hero'
@$el.toggleClass 'with-achievements', @level.get('type', true) in ['hero', 'hero-ladder']
return unless @supermodel.finished()
@playSelectionSound hero, true for original, hero of @thangTypes # Preload them
@updateSavingProgressStatus()
@ -222,8 +222,8 @@ module.exports = class HeroVictoryModal extends ModalView
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
initializeAnimations: ->
if @level.get('type', true) is 'hero'
@updateXPBars 0
return @endSequentialAnimations() unless @level.get('type', true) in ['hero', 'hero-ladder']
@updateXPBars 0
#playVictorySound = => @playSound 'victory-title-appear' # TODO: actually add this
@$el.find('#victory-header').delay(250).queue(->
$(@).removeClass('out').dequeue()
@ -253,7 +253,7 @@ module.exports = class HeroVictoryModal extends ModalView
beginSequentialAnimations: ->
return if @destroyed
return unless @level.get('type', true) is 'hero'
return unless @level.get('type', true) in ['hero', 'hero-ladder']
@sequentialAnimatedPanels = _.map(@animatedPanels.find('.reward-panel'), (panel) -> {
number: $(panel).data('number')
previousNumber: $(panel).data('previous-number')

View file

@ -56,7 +56,7 @@ module.exports = class CastButtonView extends CocoView
@$el.find('.submit-button').hide() # Hide Submit for the first few until they run it once.
if @options.session.get('state')?.complete and @options.level.get 'hidesRealTimePlayback'
@$el.find('.done-button').show()
if @options.level.get('slug') is 'thornbush-farm'# and not @options.session.get('state')?.complete
if @options.level.get('slug') in ['course-thornbush-farm', 'thornbush-farm']
@$el.find('.submit-button').hide() # Hide submit until first win so that script can explain it.
@updateReplayability()
@updateLadderSubmissionViews()
@ -114,17 +114,17 @@ module.exports = class CastButtonView extends CocoView
return if @winnable is winnable
@winnable = winnable
@$el.toggleClass 'winnable', @winnable
Backbone.Mediator.publish 'tome:winnability-updated', winnable: @winnable
Backbone.Mediator.publish 'tome:winnability-updated', winnable: @winnable, level: @options.level
if @options.level.get 'hidesRealTimePlayback'
@$el.find('.done-button').toggle @winnable
else if @winnable and @options.level.get('slug') is 'thornbush-farm'
else if @winnable and @options.level.get('slug') in ['course-thornbush-farm', 'thornbush-farm']
@$el.find('.submit-button').show() # Hide submit until first win so that script can explain it.
onGoalsCalculated: (e) ->
# When preloading, with real-time playback enabled, we highlight the submit button when we think they'll win.
return unless e.preload
return if @options.level.get 'hidesRealTimePlayback'
return if @options.level.get('slug') is 'thornbush-farm' # Don't show it until they actually win for this first one.
return if @options.level.get('slug') in ['course-thornbush-farm', 'thornbush-farm'] # Don't show it until they actually win for this first one.
@onNewGoalStates e
updateCastButton: ->

View file

@ -31,6 +31,7 @@ module.exports = class PlayAchievementsModal extends ModalView
'rewards'
'collection'
'function'
'query'
])
earnedAchievementsFetcher = new CocoCollection([], {url: '/db/earned_achievement', model: EarnedAchievement})
@ -72,8 +73,10 @@ module.exports = class PlayAchievementsModal extends ModalView
@onEverythingLoaded()
onEverythingLoaded: =>
@achievements.set(@achievements.filter((m) -> m.get('collection') isnt 'level.sessions'))
console.log 'got achievements', m.attributes for m in @achievements.models
@achievements.set(@achievements.filter((m) -> m.get('collection') isnt 'level.sessions' or m.get('query')?.team))
for achievement in @achievements.models
console.log 'kept achievement', achievement.attributes
if earned = @earnedMap[achievement.id]
achievement.earned = earned
achievement.earnedDate = earned.getCreationDate()

View file

@ -72,6 +72,7 @@
"mongoose-cache": "~0.1.4",
"node-force-domain": "~0.1.0",
"node-gyp": "~0.13.0",
"node-statsd": "^0.1.1",
"passport": "0.1.x",
"passport-local": "0.1.x",
"redis": "",

View file

@ -52,8 +52,22 @@ CampaignHandler = class CampaignHandler extends Handler
documents = (@formatEntity(req, doc) for doc in documents)
@sendSuccess(res, documents)
getOverworld: (req, res) ->
return @sendForbiddenError(res) if not @hasAccess(req)
q = @modelClass.find {}, slug: 1, adjacentCampaigns: 1, fullName: 1, description: 1, color: 1
q.exec (err, documents) =>
return @sendDatabaseError(res, err) if err
formatCampaign = (doc) =>
obj = @formatEntity(req, doc)
obj.adjacentCampaigns = _.mapValues(obj.adjacentCampaigns, (a) -> _.pick(a, ['showIfUnlocked', 'color', 'name', 'description' ]))
obj
documents = (formatCampaign(doc) for doc in documents)
@sendSuccess(res, documents)
getByRelationship: (req, res, args...) ->
relationship = args[1]
return @getOverworld(req,res) if args[0] is '-' and relationship is 'overworld'
if relationship in ['levels', 'achievements']
projection = {}
if req.query.project

View file

@ -11,6 +11,7 @@ ClassroomSchema.statics.privateProperties = []
ClassroomSchema.statics.editableProperties = [
'description'
'name'
'aceConfig'
]
ClassroomSchema.statics.generateNewCode = (done) ->

View file

@ -0,0 +1,43 @@
fs = require 'fs'
path = require 'path'
config = require '../../server_config'
StatsD = require 'node-statsd'
if config.statsd
realClient = new StatsD(config.statsd)
else
mock = new StatsD(mock: true)
exports.client = realClient or mock
exports.middleware = (req, res, next) ->
req.statsd = exports.client
if realClient
time = process.hrtime();
cleanup = ->
res.removeListener 'finish', recordMetrics
res.removeListener 'error', cleanup
res.removeListener 'close', cleanup
recordMetrics = ->
diff = process.hrtime(time);
ms = (diff[0] * 1000 + diff[1] / 1e6);
path = req.route?.path or '/*'
stat = req.method + "." + path.replace /[^A-Za-z0-9]+/g, '_'
realClient.timing stat, ms
res.once 'finish', recordMetrics
res.once 'error', cleanup
res.once 'close', cleanup
else
req.statsd = mock
next() unless not next
exports.trace = (name, callback) ->
return callback unless realClient
time = process.hrtime()
(args...) ->
realClient.timing name, ms
return callback.apply(this, args)

View file

@ -11,6 +11,7 @@ log = require 'winston'
Campaign = require '../campaigns/Campaign'
Course = require '../courses/Course'
CourseInstance = require '../courses/CourseInstance'
Classroom = require '../classrooms/Classroom'
LevelHandler = class LevelHandler extends Handler
modelClass: Level
@ -129,10 +130,16 @@ LevelHandler = class LevelHandler extends Handler
courses = _.filter(courses, (course) -> course.get('campaignID').toString() in campaignStrings)
courseStrings = (course.id.toString() for course in courses)
courseInstances = _.filter(courseInstances, (courseInstance) -> courseInstance.get('courseID').toString() in courseStrings)
aceConfigs = (ci.get('aceConfig') for ci in courseInstances)
aceConfig = _.filter(aceConfigs)[0] or {}
req.codeLanguage = aceConfig.language
@createAndSaveNewSession(sessionQuery, req, res)
classroomIDs = (courseInstance.get('classroomID') for courseInstance in courseInstances)
classroomIDs = _.filter _.uniq classroomIDs, false, (objectID='') -> objectID.toString()
if classroomIDs.length
Classroom.find({ _id: { $in: classroomIDs }}).exec (err, classrooms) =>
aceConfigs = (c.get('aceConfig') for c in classrooms)
aceConfig = _.filter(aceConfigs)[0] or {}
req.codeLanguage = aceConfig.language
@createAndSaveNewSession(sessionQuery, req, res)
else
@createAndSaveNewSession(sessionQuery, req, res)
else
return @sendPaymentRequiredError(res, 'You must be in a course which includes this level to play it')

View file

@ -52,12 +52,13 @@ module.exports.calculateSessionScores = (callback) ->
retrieveOldSessionData = (sessionID, callback) ->
formatOldScoreObject = (session) =>
oldScoreObject =
oldScoreObject =
standardDeviation: session.standardDeviation ? 25/3
meanStrength: session.meanStrength ? 25
totalScore: session.totalScore ? (25 - 1.8*(25/3))
id: sessionID
submittedCodeLanguage: session.submittedCodeLanguage
ladderAchievementDifficulty: session.ladderAchievementDifficulty
if session.leagues?.length
_.find(@clientResponseObject.sessions, sessionID: sessionID).leagues = session.leagues
oldScoreObject.leagues = []
@ -74,7 +75,7 @@ retrieveOldSessionData = (sessionID, callback) ->
return formatOldScoreObject @levelSession if sessionID is @levelSession?._id # No need to fetch again
query = _id: sessionID
selection = 'standardDeviation meanStrength totalScore submittedCodeLanguage leagues'
selection = 'standardDeviation meanStrength totalScore submittedCodeLanguage leagues ladderAchievementDifficulty'
LevelSession.findOne(query).select(selection).lean().exec (err, session) ->
return callback err, {'error': 'There was an error retrieving the session.'} if err?
callback err, formatOldScoreObject session
@ -150,6 +151,13 @@ module.exports.addMatchToSessionsAndUpdate = (newScoreObject, callback) ->
async.each sessionIDs, updateMatchesInSession.bind(@, matchObject), (err) ->
callback err
ladderBenchmarkAIs =
'564ba6cea33967be1312ae59': 0
'564ba830a33967be1312ae61': 1
'564ba91aa33967be1312ae65': 2
'564ba95ca33967be1312ae69': 3
'564ba9b7a33967be1312ae6d': 4
updateMatchesInSession = (matchObject, sessionID, callback) ->
currentMatchObject = {}
currentMatchObject.date = matchObject.date
@ -163,6 +171,11 @@ updateMatchesInSession = (matchObject, sessionID, callback) ->
#currentMatchObject.randomSeed = parseInt(@clientResponseObject.randomSeed or 0, 10) # Uncomment when actively debugging simulation mismatches
sessionUpdateObject = @levelSessionUpdates[sessionID]
sessionUpdateObject.$push.matches = {$each: [currentMatchObject], $slice: -200}
if currentMatchObject.metrics.rank is 0 and defeatedAI = ladderBenchmarkAIs[currentMatchObject.opponents[0].userID]
mySession = _.find @clientResponseObject.sessions, sessionID: sessionID
newLadderAchievementDifficulty = Math.max defeatedAI, mySession.ladderAchievementDifficulty || 0
if newLadderAchievementDifficulty isnt mySession.ladderAchievementDifficulty
sessionUpdateObject.ladderAchievementDifficulty = newLadderAchievementDifficulty
myScoreObject = @newScoresObject[sessionID]
opponentSession = _.find @clientResponseObject.sessions, (session) -> session.sessionID isnt sessionID

View file

@ -459,6 +459,7 @@ UserHandler = class UserHandler extends Handler
sendMail emailParams
getPrepaidCodes: (req, res) ->
return @sendSuccess(res, []) unless req.user?
orQuery = [{ creator: req.user._id }, { 'redeemers.userID' : req.user._id }]
Prepaid.find({}).or(orQuery).exec (err, documents) =>
@sendSuccess(res, documents)

View file

@ -84,5 +84,10 @@ if not config.unittest and not config.isProduction
# change artificially slow down non-static requests for testing
config.slow_down = false
if process.env.COCO_STATSD_HOST
config.statsd =
host: process.env.COCO_STATSD_HOST
port: process.env.COCO_STATSD_PORT or 8125
prefix: process.env.COCO_STATSD_PREFIX or ''
module.exports = config

View file

@ -8,6 +8,7 @@ compressible = require 'compressible'
geoip = require 'geoip-lite'
database = require './server/commons/database'
perfmon = require './server/commons/perfmon'
baseRoute = require './server/routes/base'
user = require './server/users/user_handler'
logging = require './server/commons/logging'
@ -127,8 +128,11 @@ setupRedirectMiddleware = (app) ->
nameOrID = req.path.split('/')[3]
res.redirect 301, "/user/#{nameOrID}/profile"
setupPerfMonMiddleware = (app) ->
app.use perfmon.middleware
exports.setupMiddleware = (app) ->
setupPerfMonMiddleware app
setupCountryRedirectMiddleware app, "china", "CN", "zh", "tokyo"
setupCountryRedirectMiddleware app, "brazil", "BR", "pt-BR", "saoPaulo"
setupMiddlewareToSendOldBrowserWarningWhenPlayersViewLevelDirectly app

View file

@ -68,29 +68,41 @@ describe 'GET /db/level/<id>/session', ->
course.save (err) ->
expect(err).toBeNull()
loginJoe (joe) ->
courseInstance = new CourseInstance({
name: 'Course Instance'
members: [
joe.get('_id')
]
courseID: ObjectId(course.id)
classroom = new Classroom({
name: 'Test Classroom'
members: [ joe.get('_id') ]
aceConfig: { language: 'javascript' }
})
courseInstance.save (err) ->
classroom.save (err, classroom) ->
expect(err).toBeNull()
done()
courseInstance = new CourseInstance({
name: 'Course Instance'
members: [
joe.get('_id')
]
courseID: ObjectId(course.id)
classroomID: ObjectId(classroom.id)
})
courseInstance.save (err) ->
expect(err).toBeNull()
done()
it 'creates a new session if the user is in a course with that level', (done) ->
loginJoe (joe) ->
url = getURL("/db/level/#{levelID}/session")
request.get { uri: url }, (err, res, body) ->
request.get { uri: url, json: true }, (err, res, body) ->
expect(res.statusCode).toBe(200)
expect(body.codeLanguage).toBe('javascript')
done()
it 'does not create a new session if the user is not in a course with that level', (done) ->