diff --git a/app/application.coffee b/app/application.coffee index 6b0c7f80b..860aee96e 100644 --- a/app/application.coffee +++ b/app/application.coffee @@ -44,8 +44,13 @@ Application = initialize: -> }, (t) => @router = new Router() @router.subscribe() - Object.freeze this if typeof Object.freeze is 'function' - @router = Router + @idleTracker = new Idle + onAway: => @userIsIdle = true + onAwayBack: => @userIsIdle = false + onHidden: => @userIsIdle = true + onVisible: => @userIsIdle = false + awayTimeout: 5 * 60 * 1000 + @idleTracker.start() module.exports = Application window.application = Application diff --git a/app/lib/world/GoalManager.coffee b/app/lib/world/GoalManager.coffee index 850b06859..b017482b8 100644 --- a/app/lib/world/GoalManager.coffee +++ b/app/lib/world/GoalManager.coffee @@ -105,7 +105,6 @@ module.exports = class GoalManager extends CocoClass notifyGoalChanges: -> overallStatus = @checkOverallStatus() event = {goalStates: @goalStates, goals: @goals, overallStatus: overallStatus} - #console.log JSON.stringify(event), "new goal states" Backbone.Mediator.publish('goal-manager:new-goal-states', event) checkOverallStatus: (ignoreIncomplete=false) -> @@ -126,6 +125,10 @@ module.exports = class GoalManager extends CocoClass keyFrame: 0 # when it became a 'success' or 'failure' } @initGoalState(state, [goal.killThangs, goal.saveThangs], 'killed') + for getTo in goal.getAllToLocations ? [] + @initGoalState(state,[ getTo.getToLocation?.who , [] ], 'arrived') + for keepFrom in goal.keepAllFromLocations ? [] + @initGoalState(state,[ [] , keepFrom.keepFromLocation?.who], 'arrived') @initGoalState(state, [goal.getToLocations?.who, goal.keepFromLocations?.who], 'arrived') @initGoalState(state, [goal.leaveOffSides?.who, goal.keepFromLeavingOffSides?.who], 'left') @initGoalState(state, [goal.collectThangs?.who, goal.keepFromCollectingThangs?.who], 'collected') @@ -143,7 +146,13 @@ module.exports = class GoalManager extends CocoClass onThangTouchedGoal: (e, frameNumber) -> for goal in @goals ? [] @checkArrived(goal.id, goal.getToLocations.who, goal.getToLocations.targets, e.actor, e.touched.id, frameNumber) if goal.getToLocations? + if goal.getAllToLocations? + for getTo in goal.getAllToLocations + @checkArrived(goal.id, getTo.getToLocation.who, getTo.getToLocation.targets, e.actor, e.touched.id, frameNumber) @checkArrived(goal.id, goal.keepFromLocations.who, goal.keepFromLocations.targets, e.actor, e.touched.id, frameNumber) if goal.keepFromLocations? + if goal.keepAllFromLocations? + for keepFrom in goal.keepAllFromLocations + @checkArrived(goal.id, keepFrom.keepFromLocation.who , keepFrom.keepFromLocation.targets, e.actor, e.touched.id, frameNumber ) checkArrived: (goalID, who, targets, thang, touchedID, frameNumber) -> return unless touchedID in targets @@ -191,6 +200,7 @@ module.exports = class GoalManager extends CocoClass initGoalState: (state, whos, progressObjectName) -> # 'whos' is an array of goal 'who' values. # This inits the progress object for the goal tracking. + arrays = (prop for prop in whos when prop?.length) return unless arrays.length state[progressObjectName] = {} @@ -240,7 +250,9 @@ module.exports = class GoalManager extends CocoClass killThangs: 1 saveThangs: 0 getToLocations: 1 + getAllToLocations: 1 keepFromLocations: 0 + keepAllFromLocations: 0 leaveOffSides: 1 keepFromLeavingOffSides: 0 collectThangs: 1 diff --git a/app/lib/world/names.coffee b/app/lib/world/names.coffee index 3b1cd0080..385d2f630 100644 --- a/app/lib/world/names.coffee +++ b/app/lib/world/names.coffee @@ -63,6 +63,7 @@ module.exports.thangNames = thangNames = "Annie" "Lukaz" "Gorgin" + "Coco" ] "Peasant": [ "Yorik" @@ -90,6 +91,7 @@ module.exports.thangNames = thangNames = ] "Peasant F": [ "Hilda" + "Icey" ] "Archer F": [ "Phoebe" @@ -115,6 +117,12 @@ module.exports.thangNames = thangNames = "Alden" "Cairn" "Jensen" + "Yilitha" + "Mirana" + "Lina" + "Luna" + "Alleria" + "Vereesa" ] "Archer M": [ "Brian" @@ -127,6 +135,14 @@ module.exports.thangNames = thangNames = "Arty" "Gimsley" "Fidsdale" + "Slyvos" + "Logos" + "Denin" + "Lycan" + "Loco" + "Vican" + "Mars" + "Dev" ] "Ogre Munchkin M": [ "Brack" @@ -148,6 +164,7 @@ module.exports.thangNames = thangNames = "Thabt" "Snortt" "Kog" + "Ursa" ] "Ogre Munchkin F": [ "Iyert" @@ -155,6 +172,9 @@ module.exports.thangNames = thangNames = "Shmeal" "Gurzunn" "Yugark" + "Dosha" + "Inski" + "Lacos" ] "Ogre M": [ "Krogg" @@ -168,6 +188,9 @@ module.exports.thangNames = thangNames = "Vargutt" "Grumus" "Gug" + "Tarlok" + "Gurulax" + "Mokrul" ] "Ogre F": [ "Nareng" @@ -175,6 +198,11 @@ module.exports.thangNames = thangNames = "Glonc" "Marghurk" "Martha" + "Holkam" + "Alkaz" + "Gar'ah" + "Mak'rah" + "Marnag" ] "Ogre Brawler": [ "Grul'thock" @@ -190,6 +218,8 @@ module.exports.thangNames = thangNames = "Grognar" "Ironjaw" "Tuguro" + "York" + "Ork'han" ] "Ogre Fangrider": [ "Dreek" @@ -205,6 +235,7 @@ module.exports.thangNames = thangNames = "Gurzthrot" "Murgark" "Muttin" + "Bortrok" ] "Ogre Shaman": [ "Sham'uk" @@ -224,6 +255,11 @@ module.exports.thangNames = thangNames = "Zo'Goroth" "Mogadishu" "Nazgareth" + "Gror" + "Grek" + "Gom" + "Gogg" + "Ghuk" ] "Ogre Thrower": [ "Kyrgg" diff --git a/app/locale/nl.coffee b/app/locale/nl.coffee index f4c45edc5..99a0a54dc 100644 --- a/app/locale/nl.coffee +++ b/app/locale/nl.coffee @@ -8,7 +8,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t delay_1_sec: "1 seconde" delay_3_sec: "3 secondes" delay_5_sec: "5 secondes" - manual: "Handmatig" + manual: "Handleiding" fork: "Fork" play: "Spelen" @@ -103,7 +103,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t wizard_settings: title: "Tovenaar instellingen" - customize_avatar: "Bewerk jouw avatar" + customize_avatar: "Bewerk je avatar" clothes: "Kleren" trim: "Trim" cloud: "Wolk" @@ -357,7 +357,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t contribute: page_title: "Bijdragen" - character_classes_title: "Karakter Klassen" + character_classes_title: "Karakterklassen" introduction_desc_intro: "We hebben hoge verwachtingen over CodeCombat." introduction_desc_pref: "We willen zijn waar programmeurs van alle niveaus komen om te leren en samen te spelen, anderen introduceren aan de wondere wereld van code, en de beste delen van de gemeenschap te reflecteren. We kunnen en willen dit niet alleen doen; wat projecten zoals GitHub, Stack Overflow en Linux groots en succesvol maken, zijn de mensen die deze software gebruiken en verbeteren. Daartoe, " introduction_desc_github_url: "CodeCombat is volledig open source" @@ -422,7 +422,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t diplomat_launch_url: "release in oktober" diplomat_introduction_suf: "dan is het wel dat er een significante interesse is in CodeCombat in andere landen, vooral Brazilië! We zijn een corps aan vertalers aan het creëren dat ijverig de ene set woorden in een andere omzet om CodeCombat zo toegankelijk te maken als mogelijk in heel de wereld. Als jij het leuk vindt glimpsen op te vangen van aankomende content en deze levels zo snel mogelijk naar je landgenoten te krijgen, dan is dit de klasse voor jou." diplomat_attribute_1: "Vloeiend Engels en de taal waar naar je wilt vertalen kunnen spreken. Wanneer je moeilijke ideeën wilt overbrengen, is het belangrijk beide goed te kunnen!" - diplomat_join_pref_github: "Vind jouw taal haar locale bestand " + diplomat_join_pref_github: "Vind van jouw taal het locale bestand " diplomat_github_url: "op GitHub" diplomat_join_suf_github: ", edit het online, en submit een pull request. Daarnaast kun je hieronder aanvinken als je up-to-date wilt worden gehouden met nieuwe internationalisatie-ontwikkelingen." more_about_diplomat: "Leer meer over het worden van een geweldige Diplomaat" diff --git a/app/locale/ro.coffee b/app/locale/ro.coffee index 5038a79d8..5a6ce33ae 100644 --- a/app/locale/ro.coffee +++ b/app/locale/ro.coffee @@ -345,40 +345,40 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman rights_clarification: "Pentru a clarifica, orice este valabil in Editorul de Nivele pentru scopul de a crea nivele se află sub CC,pe când conținutul creat cu Editorul de Nivele sau încărcat pentru a face nivelul nu se află." #CC stands for...? nutshell_title: "Pe scurt" nutshell_description: "Orice resurse vă punem la dispoziție în Editorul de Nivele puteți folosi liber cum vreți pentru a crea nivele. Dar ne rezervăm dreptul de a rezerva distribuția de nivele în sine (care sunt create pe codecombat.com) astfel încât să se poată percepe o taxă pentru ele pe vitor, dacă se va ajunge la așa ceva." - canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." + canonical: "Versiunea in engleză a acestui document este cea definitivă, versiunea canonică. Dacă există orice discrepanțe între traduceri, documentul in engleză are prioritate." -# contribute: -# page_title: "Contributing" -# character_classes_title: "Character Classes" -# introduction_desc_intro: "We have high hopes for CodeCombat." -# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " -# introduction_desc_github_url: "CodeCombat is totally open source" -# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." -# introduction_desc_ending: "We hope you'll join our party!" -# introduction_desc_signature: "- Nick, George, Scott, Michael, and Jeremy" -# alert_account_message_intro: "Hey there!" -# alert_account_message_pref: "To subscribe for class emails, you'll need to " -# alert_account_message_suf: "first." -# alert_account_message_create_url: "create an account" -# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." -# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." -# class_attributes: "Class Attributes" -# archmage_attribute_1_pref: "Knowledge in " -# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." -# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." -# how_to_join: "How To Join" -# join_desc_1: "Anyone can help out! Just check out our " -# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " -# join_desc_3: ", or find us in our " -# join_desc_4: "and we'll go from there!" -# join_url_email: "Email us" -# join_url_hipchat: "public HipChat room" -# more_about_archmage: "Learn More About Becoming an Archmage" -# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." -# artisan_summary_pref: "Want to design levels and expand CodeCombat's arsenal? People are playing through our content at a pace faster than we can build! Right now, our level editor is barebone, so be wary. Making levels will be a little challenging and buggy. If you have visions of campaigns spanning for-loops to" -# artisan_summary_suf: "then this class is for you." -# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" -# artisan_introduction_suf: "then this class might be for you." + contribute: + page_title: "Contribuțtii" + character_classes_title: "Clase de caractere" + introduction_desc_intro: "Avem speranțe mari pentru CodeCombat." + introduction_desc_pref: "Vrem să fie locul unde programatori de toate rangurile vin să învețe și să se distreze împreună, introduc pe alții in minunata lume a programării, și reflectă cele mai bune părți ale comunității. Nu vrem și nu putem să facem asta singuri; ceea ce face proiectele precum GitHub, Stack Overflow și Linux geniale sunt oameni care le folosesc și construiec peste ele. Cu scopul acesta, " + introduction_desc_github_url: "CodeCombat este complet open source" + introduction_desc_suf: ", și ne propunem să vă punem la dispoziție pe cât de mult posibil modalități de a lua parte la acest proiect pentru a-l face la fel de mult as vostru cât și al nostru." + introduction_desc_ending: "Sperăm să vă placă petrecerea noastră!" + introduction_desc_signature: "- Nick, George, Scott, Michael, și Jeremy" + alert_account_message_intro: "Salutare!" + alert_account_message_pref: "Pentru a te abona la email-uri de clasă, va trebui să " + alert_account_message_suf: "mai întâi." + alert_account_message_create_url: "creați un cont" + archmage_summary: "Interesat să lucrezi la grafica jocului, interfața grafică cu utilizatorul, baze de date și organizare server , multiplayer networking, fizică, sunet, sau performanțe game engine ? Vrei să ajuți la construirea unui joc pentru a învăța pe alții ceea ce te pricepi? Avem o grămadă de făcut dacă ești un programator experimentat și vrei sa dezvolți pentru CodeCombat, această clasă este pentru tine. Ne-ar plăcea să ne ajuți să construim cel mai bun joc de programare făcut vreodată." + archmage_introduction: "Una dintre cele mai bune părți despre construirea unui joc este că sintetizează atât de multe lucruri diferite. Grafică, sunet, networking în timp real, social networking, și desigur multe dintre aspectele comune ale programării, de la gestiune low-level a bazelor de date , și administrare server până la construirea de interfețe. Este mult de muncă, și dacă ești un programator cu experiență, cu un dor de a se arunca cu capul înainte îm CodeCombat, această clasă ți se potrivește. Ne-ar plăcea să ne ajuți să construim cel mai bun joc de programare făcut vreodată." + class_attributes: "Atribute pe clase" + archmage_attribute_1_pref: "Cunoștințe în " + archmage_attribute_1_suf: ", sau o dorință de a învăța. Majoritatea codului este în acest limbaj. Dacă ești fan Ruby sau Python, te vei simți ca acasă. Este JavaScript, dar cu o sintaxă mai frumoasă." + archmage_attribute_2: "Ceva experiență în programare și inițiativă personală. Te vom ajuta să te orientezi, dar nu putem aloca prea mult timp pentru a te pregăti." + how_to_join: "Cum să ni te alături" + join_desc_1: "Oricine poate să ajute! Doar intrați pe " + join_desc_2: "pentru a începe, și bifați căsuța de dedesubt pentru a te marca ca un Archmage curajos și pentru a primi ultimele știri pe email. Vrei să discuți despre ce să faci sau cum să te implici mai mult? " + join_desc_3: ", sau găsește-ne în " + join_desc_4: "și pornim de acolo!" + join_url_email: "Trimite-ne Email" + join_url_hipchat: "public HipChat room" + more_about_archmage: "Învață mai multe despre cum să devi un Archmage" + archmage_subscribe_desc: "Primește email-uri despre noi oportunități de progrmare și anunțuri." + artisan_summary_pref: "Vrei să creezi nivele și să extinzi arsenalul CodeCombat? Oamenii ne termină nivelele mai repede decât putem să le creăm! Momentan, editorul nostru de nivele este rudimentar, așa că aveți grijă. Crearea de nivele va fi o mică provocare și va mai avea câteva bug-uri. Dacă ai viziuni cu campanii care cuprind loop-uri for pentru" + artisan_summary_suf: "atunci asta e clasa pentru tine." + artisan_introduction_pref: "Trebuie să construim nivele adiționale! Oamenii sunt nerăbdători pentru mai mult conținut, și noi putem face doar atât singuri. Momentan editorul de nivele abia este utilizabil până și de creatorii lui, așa că aveți grijă. Dacă ai viziuni cu campanii care cuprind loop-uri for pentru" + artisan_introduction_suf: "atunci aceasta ar fi clasa pentru tine." # artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" # artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." # artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" diff --git a/app/styles/play/ladder.sass b/app/styles/play/ladder.sass index 6904c5739..fc9bc6abc 100644 --- a/app/styles/play/ladder.sass +++ b/app/styles/play/ladder.sass @@ -18,5 +18,13 @@ white-space: nowrap overflow: hidden + tr.stale + opacity: 0.5 + + tr.win .state-cell + color: #172 + tr.loss .state-cell + color: #712 + #must-log-in button - margin-right: 10px \ No newline at end of file + margin-right: 10px diff --git a/app/styles/play/spectate.sass b/app/styles/play/spectate.sass new file mode 100644 index 000000000..9de885caa --- /dev/null +++ b/app/styles/play/spectate.sass @@ -0,0 +1,152 @@ +@import "app/styles/bootstrap/mixins" +@import "app/styles/mixins" + +#spectate-level-view + margin: 0 auto + @include user-select(none) + + .level-content + position: relative + + #canvas-wrapper + width: 55% + position: relative + + canvas#surface + background-color: #ddd + width: 100% + display: block + z-index: 1 + + + //max-width: 1680px // guideline, but for now let's let it stretch out + min-width: 1024px + position: relative + + #code-area + @include box-sizing(border-box) + padding: 10px 1% + width: 45% + background: transparent url(/images/level/wood_texture.png) + background-size: 100% 100% + position: absolute + right: 0 + top: 0px + bottom: 0 + + #pointer + position: absolute + left: 0 + top: 0 + height: 100px + opacity: 0.0 + pointer-events: none + z-index: 10 + + // Level Docs + .ui-effects-transfer + border: 2px dotted gray + + .modal + img + float: right + + img.diagram + float: none + + #multiplayer-join-link + font-size: 12px + + #level-done-button + position: absolute + right: 46% + top: 43px + @include box-shadow(4px 4px 15px black) + + // Custom Buttons + .btn.banner + @include banner-button(#FFF, #333) + @include box-shadow(2px 2px 2px rgba(0, 0, 0, 0.5)) + border: 1px solid black + text-shadow: none + + $buttonConfig: 'primary' #6CA8EA, 'info' #71AACC, 'success' #90B236, 'warning' #CD6800, 'danger' #B43C20, 'inverse' #3A537F + @each $tuple in $buttonConfig + &.btn-#{nth($tuple, 1)} + @include banner-button(nth($tuple, 2), #FFF) + + .footer .footer-link-text a + @include opacity(0.75) + @include transition(opacity .10s linear) + + &:hover, &:active + @include opacity(1) + + $GI: 0.5 // gradient intensity; can tweak this 0-1 + + .gradient + position: absolute + z-index: 10 + + #code-area-gradient + top: 0px + width: 3px + background: linear-gradient(to right, rgba(0,0,0,0) 0%,rgba(0,0,0,$GI) 100%) + left: -3px + bottom: 0 + + #hud-top-gradient + top: -32px + background: linear-gradient(to bottom, rgba(0,0,0,0) 0%,rgba(0,0,0,0.8*$GI) 100%) + left: 0 + right: 0 + bottom: 0 + height: 3px + + #canvas-left-gradient + left: 0px + width: 5px + background: linear-gradient(to left, rgba(0,0,0,0) 0%,rgba(0,0,0,0.8*$GI) 100%) + bottom: -30px + top: 0 + + #canvas-top-gradient + top: 0 + height: 5px + left: 0 + right: 0 + background: linear-gradient(to top, rgba(0,0,0,0) 0%,rgba(0,0,0,0.8*$GI) 100%) + + #hud-left-gradient + background: linear-gradient(to right, rgba(0,0,0,$GI) 0%,rgba(0,0,0,0) 100%) + left: 0 + top: 0 + height: 100% + width: 2% + + #hud-right-gradient + background: linear-gradient(to right, rgba(0,0,0,0) 0%,rgba(0,0,0,$GI) 100%) + right: 0 + position: absolute + top: 0 + height: 100% + width: 2% + + .footer + @media screen and (min-aspect-ratio: 17/10) + display: none + + &:not(:hover) + @include opacity(0.6) + + .hour-of-code-explanation + margin-top: 5px + color: white + font-size: 12px + + &:not(:hover) + @include opacity(0.75) + + a + color: white + text-decoration: underline diff --git a/app/templates/contribute/diplomat.jade b/app/templates/contribute/diplomat.jade index 06743761c..9f75161de 100644 --- a/app/templates/contribute/diplomat.jade +++ b/app/templates/contribute/diplomat.jade @@ -73,7 +73,7 @@ block content li German - Dirk, faabsen, HiroP0, Anon li Thai - Kamolchanok Jittrepit li Vietnamese - An Nguyen Hoang Thien - li Dutch - Glen De Cauwsemaecker + li Dutch - Glen De Cauwsemaecker, Guido Zuidhof, Ruben Vereecken li Greek - Stergios li Latin American Spanish - Jesús Ruppel, Matthew Burt, Mariano Luzza li Spain Spanish - Matthew Burt, DanielRodriguezRivero, Anon diff --git a/app/templates/play/ladder/my_matches_tab.jade b/app/templates/play/ladder/my_matches_tab.jade index 0eb83dddb..b9cf618a2 100644 --- a/app/templates/play/ladder/my_matches_tab.jade +++ b/app/templates/play/ladder/my_matches_tab.jade @@ -17,14 +17,15 @@ div#columns.row button.btn.btn-sm.btn-warning.pull-right.rank-button(data-session-id=team.session.id) span.unavailable.hidden No New Code to Rank span.rank.hidden Rank My Game! - span.ranking.hidden Submitting... - span.ranked.hidden Submitted for Ranking + span.submitting.hidden Submitting... + span.submitted.hidden Submitted for Ranking span.failed.hidden Failed to Rank + span.ranking.hidden Game Being Ranked if team.chartData tr th(colspan=4, style="color: #{team.primaryColor}") - img(src="https://chart.googleapis.com/chart?chs=450x125&cht=lxy&chco=#{team.chartColor}&chtt=Score%3A+#{team.currentScore}&chts=#{team.chartColor},16,c&chf=a,s,000000FF&chls=2&chm=o,#{team.chartColor},0,4&chd=t:#{team.chartData}") + img(src="https://chart.googleapis.com/chart?chs=450x125&cht=lxy&chco=#{team.chartColor}&chtt=Score%3A+#{team.currentScore}&chts=#{team.chartColor},16,r&chf=a,s,000000FF&chls=2&chm=o,#{team.chartColor},0,4&chd=t:#{team.chartData}") tr th Result @@ -32,7 +33,7 @@ div#columns.row th When th for match in team.matches - tr + tr(class=(match.stale ? "stale " : "") + match.state) td.state-cell if match.state === 'win' span.win Win @@ -48,7 +49,12 @@ div#columns.row if !team.matches.length tr - td(colspan=4).alert.alert-warning - | No ranked matches for this team! - | Play against some competitors and then come back here to get your game ranked. - + if team.isRanking + td(colspan=4).alert.alert-info + | Your new code is being simulated by other players for ranking. + | This will refresh as new matches come in. + else + td(colspan=4).alert.alert-warning + | No ranked matches for the #{team.name} team! + | Play against some competitors and then come back here to get your game ranked. + diff --git a/app/templates/play/spectate.jade b/app/templates/play/spectate.jade index 9be37b46a..cfaba9234 100644 --- a/app/templates/play/spectate.jade +++ b/app/templates/play/spectate.jade @@ -1,16 +1,22 @@ .level-content #control-bar-view - #canvas-wrapper - canvas(width=924, height=589)#surface + canvas(width=1848, height=1178)#surface #canvas-left-gradient.gradient #canvas-top-gradient.gradient - #goals-view.hide - #gold-view.hide.expanded + #gold-view.secret.expanded #level-chat-view #playback-view #thang-hud .footer .content p(class='footer-link-text') - a(title='Contact', tabindex=-1, data-toggle="coco-modal", data-target="modal/contact", data-i18n="nav.contact") Contact + a(title='Send CodeCombat a message', tabindex=-1, data-toggle="coco-modal", data-target="modal/contact", data-i18n="nav.contact") Contact + if explainHourOfCode + // Does not show up unless lang is en-US. + div.hour-of-code-explanation + | The 'Hour of Code' is a nationwide initiative by + a(href="http://csedweek.org") Computer Science Education Week + | and + a(href="http://code.org") Code.org + | to introduce millions of students to one hour of computer science and computer programming. \ No newline at end of file diff --git a/app/views/play/ladder/my_matches_tab.coffee b/app/views/play/ladder/my_matches_tab.coffee index 660114111..073b80a0c 100644 --- a/app/views/play/ladder/my_matches_tab.coffee +++ b/app/views/play/ladder/my_matches_tab.coffee @@ -54,7 +54,7 @@ module.exports = class MyMatchesTabView extends CocoView ctx.levelID = @level.get('slug') or @level.id ctx.teams = @teams - convertMatch = (match) => + convertMatch = (match, submitDate) => opponent = match.opponents[0] state = 'win' state = 'loss' if match.metrics.rank > opponent.metrics.rank @@ -65,12 +65,14 @@ module.exports = class MyMatchesTabView extends CocoView opponentID: opponent.userID when: moment(match.date).fromNow() sessionID: opponent.sessionID + stale: match.date < submitDate } for team in @teams team.session = (s for s in @sessions.models when s.get('team') is team.id)[0] team.readyToRank = @readyToRank(team.session) - team.matches = (convertMatch(match) for match in team.session?.get('matches') or []) + team.isRanking = team.session?.get('isRanking') + team.matches = (convertMatch(match, team.session.get('submitDate')) for match in team.session?.get('matches') or []) team.matches.reverse() team.score = (team.session?.get('totalScore') or 10).toFixed(2) team.wins = _.filter(team.matches, {state: 'win'}).length @@ -96,7 +98,12 @@ module.exports = class MyMatchesTabView extends CocoView button = $(el) sessionID = button.data('session-id') session = _.find @sessions.models, { id: sessionID } - @setRankingButtonText button, if @readyToRank(session) then 'rank' else 'unavailable' + rankingState = 'unavailable' + if @readyToRank session + rankingState = 'rank' + else if session.get 'isRanking' + rankingState = 'ranking' + @setRankingButtonText button, rankingState readyToRank: (session) -> return false unless session?.get('levelID') # If it hasn't been denormalized, then it's not ready. @@ -110,8 +117,8 @@ module.exports = class MyMatchesTabView extends CocoView session = _.find @sessions.models, { id: sessionID } return unless @readyToRank(session) - @setRankingButtonText(button, 'ranking') - success = => @setRankingButtonText(button, 'ranked') + @setRankingButtonText(button, 'submitting') + success = => @setRankingButtonText(button, 'submitted') failure = => @setRankingButtonText(button, 'failed') ajaxData = { session: sessionID, levelID: @level.id, originalLevelID: @level.attributes.original, levelMajorVersion: @level.attributes.version.major } diff --git a/app/views/play/ladder_view.coffee b/app/views/play/ladder_view.coffee index b7cf49599..e12304f96 100644 --- a/app/views/play/ladder_view.coffee +++ b/app/views/play/ladder_view.coffee @@ -4,6 +4,7 @@ Simulator = require 'lib/simulator/Simulator' LevelSession = require 'models/LevelSession' CocoCollection = require 'models/CocoCollection' {teamDataFromLevel} = require './ladder/utils' +application = require 'application' LadderTabView = require './ladder/ladder_tab' MyMatchesTabView = require './ladder/my_matches_tab' @@ -74,12 +75,11 @@ module.exports = class LadderView extends RootView @sessions.fetch({"success": @refreshViews}) refreshViews: => - return if @destroyed + return if @destroyed or application.userIsIdle @ladderTab.refreshLadder() @myMatchesTab.refreshMatches() console.log "refreshed views!" - # Simulations onSimulateAllButtonClick: (e) -> diff --git a/app/views/play/level/tome/spell_view.coffee b/app/views/play/level/tome/spell_view.coffee index 8c98db854..dd9875b16 100644 --- a/app/views/play/level/tome/spell_view.coffee +++ b/app/views/play/level/tome/spell_view.coffee @@ -430,6 +430,7 @@ module.exports = class SpellView extends View flow ?= @spellThang?.castAether?.flow return unless flow executed = [] + executedRows = {} matched = false states = flow.states ? [] currentCallIndex = null @@ -445,20 +446,24 @@ module.exports = class SpellView extends View matched = true break _.last(executed).push state + executedRows[state.range[0].row] = true #state.executing = true if state.userInfo?.time is @thang.world.age # no work currentCallIndex ?= callNumber - 1 #console.log "got call index", currentCallIndex, "for time", @thang.world.age, "out of", states.length + @decoratedGutter = @decoratedGutter || {} + # TODO: don't redo the markers if they haven't actually changed for markerRange in (@markerRanges ?= []) markerRange.start.detach() markerRange.end.detach() @aceSession.removeMarker markerRange.id @markerRanges = [] - @aceSession.removeGutterDecoration row, 'executing' for row in [0 ... @aceSession.getLength()] - @aceSession.removeGutterDecoration row, 'executed' for row in [0 ... @aceSession.getLength()] - $(@ace.container).find('.ace_gutter-cell.executing').removeClass('executing') - $(@ace.container).find('.ace_gutter-cell.executed').removeClass('executed') + for row in [0 ... @aceSession.getLength()] + unless executedRows[row] + @aceSession.removeGutterDecoration row, 'executing' + @aceSession.removeGutterDecoration row, 'executed' + @decoratedGutter[row] = '' if not executed.length or (@spell.name is "plan" and @spellThang.castAether.metrics.statementsExecuted < 20) @toolbarView?.toggleFlow false @debugView.setVariableStates {} @@ -486,7 +491,10 @@ module.exports = class SpellView extends View markerRange.end = @aceDoc.createAnchor markerRange.end markerRange.id = @aceSession.addMarker markerRange, clazz, markerType @markerRanges.push markerRange - @aceSession.addGutterDecoration start.row, clazz + if executedRows[start.row] and @decoratedGutter[start.row] isnt clazz + @aceSession.removeGutterDecoration start.row, @decoratedGutter[start.row] if @decoratedGutter[start.row] isnt '' + @aceSession.addGutterDecoration start.row, clazz + @decoratedGutter[start.row] = clazz @debugView.setVariableStates {} unless gotVariableStates null diff --git a/app/views/play/spectate_view.coffee b/app/views/play/spectate_view.coffee index e2686e90d..17dbcf6d3 100644 --- a/app/views/play/spectate_view.coffee +++ b/app/views/play/spectate_view.coffee @@ -5,7 +5,6 @@ ThangType = require 'models/ThangType' # temp hard coded data World = require 'lib/world/world' -docs = require 'lib/world/docs' # tools Surface = require 'lib/surface/Surface' @@ -17,7 +16,9 @@ LevelLoader = require 'lib/LevelLoader' LevelSession = require 'models/LevelSession' Level = require 'models/Level' LevelComponent = require 'models/LevelComponent' +Article = require 'models/Article' Camera = require 'lib/surface/Camera' +AudioPlayer = require 'lib/AudioPlayer' # subviews TomeView = require './level/tome/tome_view' @@ -34,8 +35,6 @@ LoadingScreen = require 'lib/LoadingScreen' PROFILE_ME = false -PlayLevelView = require './level_view' - module.exports = class SpectateLevelView extends View id: 'spectate-level-view' template: template @@ -46,6 +45,8 @@ module.exports = class SpectateLevelView extends View subscriptions: 'level-set-volume': (e) -> createjs.Sound.setVolume(e.volume) + 'level-show-victory': 'onShowVictory' + 'restart-level': 'onRestartLevel' 'level-highlight-dom': 'onHighlightDom' 'end-level-highlight-dom': 'onEndHighlight' 'level-focus-dom': 'onFocusDom' @@ -53,33 +54,33 @@ module.exports = class SpectateLevelView extends View 'level-enable-controls': 'onEnableControls' 'god:new-world-created': 'onNewWorld' 'god:infinite-loop': 'onInfiniteLoop' + 'level-reload-from-data': 'onLevelReloadFromData' + 'play-next-level': 'onPlayNextLevel' 'edit-wizard-settings': 'showWizardSettingsModal' 'surface:world-set-up': 'onSurfaceSetUpNewWorld' 'level:session-will-save': 'onSessionWillSave' 'level:set-team': 'setTeam' + 'god:new-world-created': 'loadSoundsForWorld' events: 'click #level-done-button': 'onDonePressed' + shortcuts: + 'ctrl+s': 'onCtrlS' constructor: (options, @levelID) -> console.profile?() if PROFILE_ME super options - console.log @levelID - - @ogreSessionID = @getQueryVariable 'ogres' - @humanSessionID = @getQueryVariable 'humans' + @sessionID = @getQueryVariable 'session' $(window).on('resize', @onWindowResize) - @supermodel.once 'error', => - msg = $.i18n.t('play_level.level_load_error', defaultValue: "Level could not be loaded.") - @$el.html('