mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-28 18:15:52 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
3f9de34ec7
19 changed files with 636 additions and 133 deletions
|
@ -44,8 +44,13 @@ Application = initialize: ->
|
||||||
}, (t) =>
|
}, (t) =>
|
||||||
@router = new Router()
|
@router = new Router()
|
||||||
@router.subscribe()
|
@router.subscribe()
|
||||||
Object.freeze this if typeof Object.freeze is 'function'
|
@idleTracker = new Idle
|
||||||
@router = Router
|
onAway: => @userIsIdle = true
|
||||||
|
onAwayBack: => @userIsIdle = false
|
||||||
|
onHidden: => @userIsIdle = true
|
||||||
|
onVisible: => @userIsIdle = false
|
||||||
|
awayTimeout: 5 * 60 * 1000
|
||||||
|
@idleTracker.start()
|
||||||
|
|
||||||
module.exports = Application
|
module.exports = Application
|
||||||
window.application = Application
|
window.application = Application
|
||||||
|
|
|
@ -105,7 +105,6 @@ module.exports = class GoalManager extends CocoClass
|
||||||
notifyGoalChanges: ->
|
notifyGoalChanges: ->
|
||||||
overallStatus = @checkOverallStatus()
|
overallStatus = @checkOverallStatus()
|
||||||
event = {goalStates: @goalStates, goals: @goals, overallStatus: overallStatus}
|
event = {goalStates: @goalStates, goals: @goals, overallStatus: overallStatus}
|
||||||
#console.log JSON.stringify(event), "new goal states"
|
|
||||||
Backbone.Mediator.publish('goal-manager:new-goal-states', event)
|
Backbone.Mediator.publish('goal-manager:new-goal-states', event)
|
||||||
|
|
||||||
checkOverallStatus: (ignoreIncomplete=false) ->
|
checkOverallStatus: (ignoreIncomplete=false) ->
|
||||||
|
@ -126,6 +125,10 @@ module.exports = class GoalManager extends CocoClass
|
||||||
keyFrame: 0 # when it became a 'success' or 'failure'
|
keyFrame: 0 # when it became a 'success' or 'failure'
|
||||||
}
|
}
|
||||||
@initGoalState(state, [goal.killThangs, goal.saveThangs], 'killed')
|
@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.getToLocations?.who, goal.keepFromLocations?.who], 'arrived')
|
||||||
@initGoalState(state, [goal.leaveOffSides?.who, goal.keepFromLeavingOffSides?.who], 'left')
|
@initGoalState(state, [goal.leaveOffSides?.who, goal.keepFromLeavingOffSides?.who], 'left')
|
||||||
@initGoalState(state, [goal.collectThangs?.who, goal.keepFromCollectingThangs?.who], 'collected')
|
@initGoalState(state, [goal.collectThangs?.who, goal.keepFromCollectingThangs?.who], 'collected')
|
||||||
|
@ -143,7 +146,13 @@ module.exports = class GoalManager extends CocoClass
|
||||||
onThangTouchedGoal: (e, frameNumber) ->
|
onThangTouchedGoal: (e, frameNumber) ->
|
||||||
for goal in @goals ? []
|
for goal in @goals ? []
|
||||||
@checkArrived(goal.id, goal.getToLocations.who, goal.getToLocations.targets, e.actor, e.touched.id, frameNumber) if goal.getToLocations?
|
@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?
|
@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) ->
|
checkArrived: (goalID, who, targets, thang, touchedID, frameNumber) ->
|
||||||
return unless touchedID in targets
|
return unless touchedID in targets
|
||||||
|
@ -191,6 +200,7 @@ module.exports = class GoalManager extends CocoClass
|
||||||
initGoalState: (state, whos, progressObjectName) ->
|
initGoalState: (state, whos, progressObjectName) ->
|
||||||
# 'whos' is an array of goal 'who' values.
|
# 'whos' is an array of goal 'who' values.
|
||||||
# This inits the progress object for the goal tracking.
|
# This inits the progress object for the goal tracking.
|
||||||
|
|
||||||
arrays = (prop for prop in whos when prop?.length)
|
arrays = (prop for prop in whos when prop?.length)
|
||||||
return unless arrays.length
|
return unless arrays.length
|
||||||
state[progressObjectName] = {}
|
state[progressObjectName] = {}
|
||||||
|
@ -240,7 +250,9 @@ module.exports = class GoalManager extends CocoClass
|
||||||
killThangs: 1
|
killThangs: 1
|
||||||
saveThangs: 0
|
saveThangs: 0
|
||||||
getToLocations: 1
|
getToLocations: 1
|
||||||
|
getAllToLocations: 1
|
||||||
keepFromLocations: 0
|
keepFromLocations: 0
|
||||||
|
keepAllFromLocations: 0
|
||||||
leaveOffSides: 1
|
leaveOffSides: 1
|
||||||
keepFromLeavingOffSides: 0
|
keepFromLeavingOffSides: 0
|
||||||
collectThangs: 1
|
collectThangs: 1
|
||||||
|
|
|
@ -63,6 +63,7 @@ module.exports.thangNames = thangNames =
|
||||||
"Annie"
|
"Annie"
|
||||||
"Lukaz"
|
"Lukaz"
|
||||||
"Gorgin"
|
"Gorgin"
|
||||||
|
"Coco"
|
||||||
]
|
]
|
||||||
"Peasant": [
|
"Peasant": [
|
||||||
"Yorik"
|
"Yorik"
|
||||||
|
@ -90,6 +91,7 @@ module.exports.thangNames = thangNames =
|
||||||
]
|
]
|
||||||
"Peasant F": [
|
"Peasant F": [
|
||||||
"Hilda"
|
"Hilda"
|
||||||
|
"Icey"
|
||||||
]
|
]
|
||||||
"Archer F": [
|
"Archer F": [
|
||||||
"Phoebe"
|
"Phoebe"
|
||||||
|
@ -115,6 +117,12 @@ module.exports.thangNames = thangNames =
|
||||||
"Alden"
|
"Alden"
|
||||||
"Cairn"
|
"Cairn"
|
||||||
"Jensen"
|
"Jensen"
|
||||||
|
"Yilitha"
|
||||||
|
"Mirana"
|
||||||
|
"Lina"
|
||||||
|
"Luna"
|
||||||
|
"Alleria"
|
||||||
|
"Vereesa"
|
||||||
]
|
]
|
||||||
"Archer M": [
|
"Archer M": [
|
||||||
"Brian"
|
"Brian"
|
||||||
|
@ -127,6 +135,14 @@ module.exports.thangNames = thangNames =
|
||||||
"Arty"
|
"Arty"
|
||||||
"Gimsley"
|
"Gimsley"
|
||||||
"Fidsdale"
|
"Fidsdale"
|
||||||
|
"Slyvos"
|
||||||
|
"Logos"
|
||||||
|
"Denin"
|
||||||
|
"Lycan"
|
||||||
|
"Loco"
|
||||||
|
"Vican"
|
||||||
|
"Mars"
|
||||||
|
"Dev"
|
||||||
]
|
]
|
||||||
"Ogre Munchkin M": [
|
"Ogre Munchkin M": [
|
||||||
"Brack"
|
"Brack"
|
||||||
|
@ -148,6 +164,7 @@ module.exports.thangNames = thangNames =
|
||||||
"Thabt"
|
"Thabt"
|
||||||
"Snortt"
|
"Snortt"
|
||||||
"Kog"
|
"Kog"
|
||||||
|
"Ursa"
|
||||||
]
|
]
|
||||||
"Ogre Munchkin F": [
|
"Ogre Munchkin F": [
|
||||||
"Iyert"
|
"Iyert"
|
||||||
|
@ -155,6 +172,9 @@ module.exports.thangNames = thangNames =
|
||||||
"Shmeal"
|
"Shmeal"
|
||||||
"Gurzunn"
|
"Gurzunn"
|
||||||
"Yugark"
|
"Yugark"
|
||||||
|
"Dosha"
|
||||||
|
"Inski"
|
||||||
|
"Lacos"
|
||||||
]
|
]
|
||||||
"Ogre M": [
|
"Ogre M": [
|
||||||
"Krogg"
|
"Krogg"
|
||||||
|
@ -168,6 +188,9 @@ module.exports.thangNames = thangNames =
|
||||||
"Vargutt"
|
"Vargutt"
|
||||||
"Grumus"
|
"Grumus"
|
||||||
"Gug"
|
"Gug"
|
||||||
|
"Tarlok"
|
||||||
|
"Gurulax"
|
||||||
|
"Mokrul"
|
||||||
]
|
]
|
||||||
"Ogre F": [
|
"Ogre F": [
|
||||||
"Nareng"
|
"Nareng"
|
||||||
|
@ -175,6 +198,11 @@ module.exports.thangNames = thangNames =
|
||||||
"Glonc"
|
"Glonc"
|
||||||
"Marghurk"
|
"Marghurk"
|
||||||
"Martha"
|
"Martha"
|
||||||
|
"Holkam"
|
||||||
|
"Alkaz"
|
||||||
|
"Gar'ah"
|
||||||
|
"Mak'rah"
|
||||||
|
"Marnag"
|
||||||
]
|
]
|
||||||
"Ogre Brawler": [
|
"Ogre Brawler": [
|
||||||
"Grul'thock"
|
"Grul'thock"
|
||||||
|
@ -190,6 +218,8 @@ module.exports.thangNames = thangNames =
|
||||||
"Grognar"
|
"Grognar"
|
||||||
"Ironjaw"
|
"Ironjaw"
|
||||||
"Tuguro"
|
"Tuguro"
|
||||||
|
"York"
|
||||||
|
"Ork'han"
|
||||||
]
|
]
|
||||||
"Ogre Fangrider": [
|
"Ogre Fangrider": [
|
||||||
"Dreek"
|
"Dreek"
|
||||||
|
@ -205,6 +235,7 @@ module.exports.thangNames = thangNames =
|
||||||
"Gurzthrot"
|
"Gurzthrot"
|
||||||
"Murgark"
|
"Murgark"
|
||||||
"Muttin"
|
"Muttin"
|
||||||
|
"Bortrok"
|
||||||
]
|
]
|
||||||
"Ogre Shaman": [
|
"Ogre Shaman": [
|
||||||
"Sham'uk"
|
"Sham'uk"
|
||||||
|
@ -224,6 +255,11 @@ module.exports.thangNames = thangNames =
|
||||||
"Zo'Goroth"
|
"Zo'Goroth"
|
||||||
"Mogadishu"
|
"Mogadishu"
|
||||||
"Nazgareth"
|
"Nazgareth"
|
||||||
|
"Gror"
|
||||||
|
"Grek"
|
||||||
|
"Gom"
|
||||||
|
"Gogg"
|
||||||
|
"Ghuk"
|
||||||
]
|
]
|
||||||
"Ogre Thrower": [
|
"Ogre Thrower": [
|
||||||
"Kyrgg"
|
"Kyrgg"
|
||||||
|
|
|
@ -8,7 +8,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t
|
||||||
delay_1_sec: "1 seconde"
|
delay_1_sec: "1 seconde"
|
||||||
delay_3_sec: "3 secondes"
|
delay_3_sec: "3 secondes"
|
||||||
delay_5_sec: "5 secondes"
|
delay_5_sec: "5 secondes"
|
||||||
manual: "Handmatig"
|
manual: "Handleiding"
|
||||||
fork: "Fork"
|
fork: "Fork"
|
||||||
play: "Spelen"
|
play: "Spelen"
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t
|
||||||
|
|
||||||
wizard_settings:
|
wizard_settings:
|
||||||
title: "Tovenaar instellingen"
|
title: "Tovenaar instellingen"
|
||||||
customize_avatar: "Bewerk jouw avatar"
|
customize_avatar: "Bewerk je avatar"
|
||||||
clothes: "Kleren"
|
clothes: "Kleren"
|
||||||
trim: "Trim"
|
trim: "Trim"
|
||||||
cloud: "Wolk"
|
cloud: "Wolk"
|
||||||
|
@ -357,7 +357,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t
|
||||||
|
|
||||||
contribute:
|
contribute:
|
||||||
page_title: "Bijdragen"
|
page_title: "Bijdragen"
|
||||||
character_classes_title: "Karakter Klassen"
|
character_classes_title: "Karakterklassen"
|
||||||
introduction_desc_intro: "We hebben hoge verwachtingen over CodeCombat."
|
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_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"
|
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_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_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_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_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."
|
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"
|
more_about_diplomat: "Leer meer over het worden van een geweldige Diplomaat"
|
||||||
|
|
|
@ -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...?
|
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_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."
|
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:
|
contribute:
|
||||||
# page_title: "Contributing"
|
page_title: "Contribuțtii"
|
||||||
# character_classes_title: "Character Classes"
|
character_classes_title: "Clase de caractere"
|
||||||
# introduction_desc_intro: "We have high hopes for CodeCombat."
|
introduction_desc_intro: "Avem speranțe mari pentru 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_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 is totally open source"
|
introduction_desc_github_url: "CodeCombat este complet 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_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: "We hope you'll join our party!"
|
introduction_desc_ending: "Sperăm să vă placă petrecerea noastră!"
|
||||||
# introduction_desc_signature: "- Nick, George, Scott, Michael, and Jeremy"
|
introduction_desc_signature: "- Nick, George, Scott, Michael, și Jeremy"
|
||||||
# alert_account_message_intro: "Hey there!"
|
alert_account_message_intro: "Salutare!"
|
||||||
# alert_account_message_pref: "To subscribe for class emails, you'll need to "
|
alert_account_message_pref: "Pentru a te abona la email-uri de clasă, va trebui să "
|
||||||
# alert_account_message_suf: "first."
|
alert_account_message_suf: "mai întâi."
|
||||||
# alert_account_message_create_url: "create an account"
|
alert_account_message_create_url: "creați un cont"
|
||||||
# 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_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: "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."
|
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: "Class Attributes"
|
class_attributes: "Atribute pe clase"
|
||||||
# archmage_attribute_1_pref: "Knowledge in "
|
archmage_attribute_1_pref: "Cunoștințe în "
|
||||||
# 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_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: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you."
|
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: "How To Join"
|
how_to_join: "Cum să ni te alături"
|
||||||
# join_desc_1: "Anyone can help out! Just check out our "
|
join_desc_1: "Oricine poate să ajute! Doar intrați pe "
|
||||||
# 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_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: ", or find us in our "
|
join_desc_3: ", sau găsește-ne în "
|
||||||
# join_desc_4: "and we'll go from there!"
|
join_desc_4: "și pornim de acolo!"
|
||||||
# join_url_email: "Email us"
|
join_url_email: "Trimite-ne Email"
|
||||||
# join_url_hipchat: "public HipChat room"
|
join_url_hipchat: "public HipChat room"
|
||||||
# more_about_archmage: "Learn More About Becoming an Archmage"
|
more_about_archmage: "Învață mai multe despre cum să devi un Archmage"
|
||||||
# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements."
|
archmage_subscribe_desc: "Primește email-uri despre noi oportunități de progrmare și anunțuri."
|
||||||
# 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_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: "then this class is for you."
|
artisan_summary_suf: "atunci asta e clasa pentru tine."
|
||||||
# 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_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: "then this class might be for you."
|
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_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_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix."
|
||||||
# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!"
|
# artisan_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!"
|
||||||
|
|
|
@ -18,5 +18,13 @@
|
||||||
white-space: nowrap
|
white-space: nowrap
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
|
|
||||||
|
tr.stale
|
||||||
|
opacity: 0.5
|
||||||
|
|
||||||
|
tr.win .state-cell
|
||||||
|
color: #172
|
||||||
|
tr.loss .state-cell
|
||||||
|
color: #712
|
||||||
|
|
||||||
#must-log-in button
|
#must-log-in button
|
||||||
margin-right: 10px
|
margin-right: 10px
|
||||||
|
|
152
app/styles/play/spectate.sass
Normal file
152
app/styles/play/spectate.sass
Normal file
|
@ -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
|
|
@ -73,7 +73,7 @@ block content
|
||||||
li German - Dirk, faabsen, HiroP0, Anon
|
li German - Dirk, faabsen, HiroP0, Anon
|
||||||
li Thai - Kamolchanok Jittrepit
|
li Thai - Kamolchanok Jittrepit
|
||||||
li Vietnamese - An Nguyen Hoang Thien
|
li Vietnamese - An Nguyen Hoang Thien
|
||||||
li Dutch - Glen De Cauwsemaecker
|
li Dutch - Glen De Cauwsemaecker, Guido Zuidhof, Ruben Vereecken
|
||||||
li Greek - Stergios
|
li Greek - Stergios
|
||||||
li Latin American Spanish - Jesús Ruppel, Matthew Burt, Mariano Luzza
|
li Latin American Spanish - Jesús Ruppel, Matthew Burt, Mariano Luzza
|
||||||
li Spain Spanish - Matthew Burt, DanielRodriguezRivero, Anon
|
li Spain Spanish - Matthew Burt, DanielRodriguezRivero, Anon
|
||||||
|
|
|
@ -17,14 +17,15 @@ div#columns.row
|
||||||
button.btn.btn-sm.btn-warning.pull-right.rank-button(data-session-id=team.session.id)
|
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.unavailable.hidden No New Code to Rank
|
||||||
span.rank.hidden Rank My Game!
|
span.rank.hidden Rank My Game!
|
||||||
span.ranking.hidden Submitting...
|
span.submitting.hidden Submitting...
|
||||||
span.ranked.hidden Submitted for Ranking
|
span.submitted.hidden Submitted for Ranking
|
||||||
span.failed.hidden Failed to Rank
|
span.failed.hidden Failed to Rank
|
||||||
|
span.ranking.hidden Game Being Ranked
|
||||||
|
|
||||||
if team.chartData
|
if team.chartData
|
||||||
tr
|
tr
|
||||||
th(colspan=4, style="color: #{team.primaryColor}")
|
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
|
tr
|
||||||
th Result
|
th Result
|
||||||
|
@ -32,7 +33,7 @@ div#columns.row
|
||||||
th When
|
th When
|
||||||
th
|
th
|
||||||
for match in team.matches
|
for match in team.matches
|
||||||
tr
|
tr(class=(match.stale ? "stale " : "") + match.state)
|
||||||
td.state-cell
|
td.state-cell
|
||||||
if match.state === 'win'
|
if match.state === 'win'
|
||||||
span.win Win
|
span.win Win
|
||||||
|
@ -48,7 +49,12 @@ div#columns.row
|
||||||
|
|
||||||
if !team.matches.length
|
if !team.matches.length
|
||||||
tr
|
tr
|
||||||
td(colspan=4).alert.alert-warning
|
if team.isRanking
|
||||||
| No ranked matches for this team!
|
td(colspan=4).alert.alert-info
|
||||||
| Play against some competitors and then come back here to get your game ranked.
|
| 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.
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
.level-content
|
.level-content
|
||||||
#control-bar-view
|
#control-bar-view
|
||||||
|
|
||||||
#canvas-wrapper
|
#canvas-wrapper
|
||||||
canvas(width=924, height=589)#surface
|
canvas(width=1848, height=1178)#surface
|
||||||
#canvas-left-gradient.gradient
|
#canvas-left-gradient.gradient
|
||||||
#canvas-top-gradient.gradient
|
#canvas-top-gradient.gradient
|
||||||
#goals-view.hide
|
#gold-view.secret.expanded
|
||||||
#gold-view.hide.expanded
|
|
||||||
#level-chat-view
|
#level-chat-view
|
||||||
#playback-view
|
#playback-view
|
||||||
#thang-hud
|
#thang-hud
|
||||||
.footer
|
.footer
|
||||||
.content
|
.content
|
||||||
p(class='footer-link-text')
|
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.
|
|
@ -54,7 +54,7 @@ module.exports = class MyMatchesTabView extends CocoView
|
||||||
ctx.levelID = @level.get('slug') or @level.id
|
ctx.levelID = @level.get('slug') or @level.id
|
||||||
ctx.teams = @teams
|
ctx.teams = @teams
|
||||||
|
|
||||||
convertMatch = (match) =>
|
convertMatch = (match, submitDate) =>
|
||||||
opponent = match.opponents[0]
|
opponent = match.opponents[0]
|
||||||
state = 'win'
|
state = 'win'
|
||||||
state = 'loss' if match.metrics.rank > opponent.metrics.rank
|
state = 'loss' if match.metrics.rank > opponent.metrics.rank
|
||||||
|
@ -65,12 +65,14 @@ module.exports = class MyMatchesTabView extends CocoView
|
||||||
opponentID: opponent.userID
|
opponentID: opponent.userID
|
||||||
when: moment(match.date).fromNow()
|
when: moment(match.date).fromNow()
|
||||||
sessionID: opponent.sessionID
|
sessionID: opponent.sessionID
|
||||||
|
stale: match.date < submitDate
|
||||||
}
|
}
|
||||||
|
|
||||||
for team in @teams
|
for team in @teams
|
||||||
team.session = (s for s in @sessions.models when s.get('team') is team.id)[0]
|
team.session = (s for s in @sessions.models when s.get('team') is team.id)[0]
|
||||||
team.readyToRank = @readyToRank(team.session)
|
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.matches.reverse()
|
||||||
team.score = (team.session?.get('totalScore') or 10).toFixed(2)
|
team.score = (team.session?.get('totalScore') or 10).toFixed(2)
|
||||||
team.wins = _.filter(team.matches, {state: 'win'}).length
|
team.wins = _.filter(team.matches, {state: 'win'}).length
|
||||||
|
@ -96,7 +98,12 @@ module.exports = class MyMatchesTabView extends CocoView
|
||||||
button = $(el)
|
button = $(el)
|
||||||
sessionID = button.data('session-id')
|
sessionID = button.data('session-id')
|
||||||
session = _.find @sessions.models, { id: sessionID }
|
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) ->
|
readyToRank: (session) ->
|
||||||
return false unless session?.get('levelID') # If it hasn't been denormalized, then it's not ready.
|
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 }
|
session = _.find @sessions.models, { id: sessionID }
|
||||||
return unless @readyToRank(session)
|
return unless @readyToRank(session)
|
||||||
|
|
||||||
@setRankingButtonText(button, 'ranking')
|
@setRankingButtonText(button, 'submitting')
|
||||||
success = => @setRankingButtonText(button, 'ranked')
|
success = => @setRankingButtonText(button, 'submitted')
|
||||||
failure = => @setRankingButtonText(button, 'failed')
|
failure = => @setRankingButtonText(button, 'failed')
|
||||||
|
|
||||||
ajaxData = { session: sessionID, levelID: @level.id, originalLevelID: @level.attributes.original, levelMajorVersion: @level.attributes.version.major }
|
ajaxData = { session: sessionID, levelID: @level.id, originalLevelID: @level.attributes.original, levelMajorVersion: @level.attributes.version.major }
|
||||||
|
|
|
@ -4,6 +4,7 @@ Simulator = require 'lib/simulator/Simulator'
|
||||||
LevelSession = require 'models/LevelSession'
|
LevelSession = require 'models/LevelSession'
|
||||||
CocoCollection = require 'models/CocoCollection'
|
CocoCollection = require 'models/CocoCollection'
|
||||||
{teamDataFromLevel} = require './ladder/utils'
|
{teamDataFromLevel} = require './ladder/utils'
|
||||||
|
application = require 'application'
|
||||||
|
|
||||||
LadderTabView = require './ladder/ladder_tab'
|
LadderTabView = require './ladder/ladder_tab'
|
||||||
MyMatchesTabView = require './ladder/my_matches_tab'
|
MyMatchesTabView = require './ladder/my_matches_tab'
|
||||||
|
@ -74,12 +75,11 @@ module.exports = class LadderView extends RootView
|
||||||
@sessions.fetch({"success": @refreshViews})
|
@sessions.fetch({"success": @refreshViews})
|
||||||
|
|
||||||
refreshViews: =>
|
refreshViews: =>
|
||||||
return if @destroyed
|
return if @destroyed or application.userIsIdle
|
||||||
@ladderTab.refreshLadder()
|
@ladderTab.refreshLadder()
|
||||||
@myMatchesTab.refreshMatches()
|
@myMatchesTab.refreshMatches()
|
||||||
console.log "refreshed views!"
|
console.log "refreshed views!"
|
||||||
|
|
||||||
|
|
||||||
# Simulations
|
# Simulations
|
||||||
|
|
||||||
onSimulateAllButtonClick: (e) ->
|
onSimulateAllButtonClick: (e) ->
|
||||||
|
|
|
@ -430,6 +430,7 @@ module.exports = class SpellView extends View
|
||||||
flow ?= @spellThang?.castAether?.flow
|
flow ?= @spellThang?.castAether?.flow
|
||||||
return unless flow
|
return unless flow
|
||||||
executed = []
|
executed = []
|
||||||
|
executedRows = {}
|
||||||
matched = false
|
matched = false
|
||||||
states = flow.states ? []
|
states = flow.states ? []
|
||||||
currentCallIndex = null
|
currentCallIndex = null
|
||||||
|
@ -445,20 +446,24 @@ module.exports = class SpellView extends View
|
||||||
matched = true
|
matched = true
|
||||||
break
|
break
|
||||||
_.last(executed).push state
|
_.last(executed).push state
|
||||||
|
executedRows[state.range[0].row] = true
|
||||||
#state.executing = true if state.userInfo?.time is @thang.world.age # no work
|
#state.executing = true if state.userInfo?.time is @thang.world.age # no work
|
||||||
currentCallIndex ?= callNumber - 1
|
currentCallIndex ?= callNumber - 1
|
||||||
#console.log "got call index", currentCallIndex, "for time", @thang.world.age, "out of", states.length
|
#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
|
# TODO: don't redo the markers if they haven't actually changed
|
||||||
for markerRange in (@markerRanges ?= [])
|
for markerRange in (@markerRanges ?= [])
|
||||||
markerRange.start.detach()
|
markerRange.start.detach()
|
||||||
markerRange.end.detach()
|
markerRange.end.detach()
|
||||||
@aceSession.removeMarker markerRange.id
|
@aceSession.removeMarker markerRange.id
|
||||||
@markerRanges = []
|
@markerRanges = []
|
||||||
@aceSession.removeGutterDecoration row, 'executing' for row in [0 ... @aceSession.getLength()]
|
for row in [0 ... @aceSession.getLength()]
|
||||||
@aceSession.removeGutterDecoration row, 'executed' for row in [0 ... @aceSession.getLength()]
|
unless executedRows[row]
|
||||||
$(@ace.container).find('.ace_gutter-cell.executing').removeClass('executing')
|
@aceSession.removeGutterDecoration row, 'executing'
|
||||||
$(@ace.container).find('.ace_gutter-cell.executed').removeClass('executed')
|
@aceSession.removeGutterDecoration row, 'executed'
|
||||||
|
@decoratedGutter[row] = ''
|
||||||
if not executed.length or (@spell.name is "plan" and @spellThang.castAether.metrics.statementsExecuted < 20)
|
if not executed.length or (@spell.name is "plan" and @spellThang.castAether.metrics.statementsExecuted < 20)
|
||||||
@toolbarView?.toggleFlow false
|
@toolbarView?.toggleFlow false
|
||||||
@debugView.setVariableStates {}
|
@debugView.setVariableStates {}
|
||||||
|
@ -486,7 +491,10 @@ module.exports = class SpellView extends View
|
||||||
markerRange.end = @aceDoc.createAnchor markerRange.end
|
markerRange.end = @aceDoc.createAnchor markerRange.end
|
||||||
markerRange.id = @aceSession.addMarker markerRange, clazz, markerType
|
markerRange.id = @aceSession.addMarker markerRange, clazz, markerType
|
||||||
@markerRanges.push markerRange
|
@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
|
@debugView.setVariableStates {} unless gotVariableStates
|
||||||
null
|
null
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ ThangType = require 'models/ThangType'
|
||||||
|
|
||||||
# temp hard coded data
|
# temp hard coded data
|
||||||
World = require 'lib/world/world'
|
World = require 'lib/world/world'
|
||||||
docs = require 'lib/world/docs'
|
|
||||||
|
|
||||||
# tools
|
# tools
|
||||||
Surface = require 'lib/surface/Surface'
|
Surface = require 'lib/surface/Surface'
|
||||||
|
@ -17,7 +16,9 @@ LevelLoader = require 'lib/LevelLoader'
|
||||||
LevelSession = require 'models/LevelSession'
|
LevelSession = require 'models/LevelSession'
|
||||||
Level = require 'models/Level'
|
Level = require 'models/Level'
|
||||||
LevelComponent = require 'models/LevelComponent'
|
LevelComponent = require 'models/LevelComponent'
|
||||||
|
Article = require 'models/Article'
|
||||||
Camera = require 'lib/surface/Camera'
|
Camera = require 'lib/surface/Camera'
|
||||||
|
AudioPlayer = require 'lib/AudioPlayer'
|
||||||
|
|
||||||
# subviews
|
# subviews
|
||||||
TomeView = require './level/tome/tome_view'
|
TomeView = require './level/tome/tome_view'
|
||||||
|
@ -34,8 +35,6 @@ LoadingScreen = require 'lib/LoadingScreen'
|
||||||
|
|
||||||
PROFILE_ME = false
|
PROFILE_ME = false
|
||||||
|
|
||||||
PlayLevelView = require './level_view'
|
|
||||||
|
|
||||||
module.exports = class SpectateLevelView extends View
|
module.exports = class SpectateLevelView extends View
|
||||||
id: 'spectate-level-view'
|
id: 'spectate-level-view'
|
||||||
template: template
|
template: template
|
||||||
|
@ -46,6 +45,8 @@ module.exports = class SpectateLevelView extends View
|
||||||
|
|
||||||
subscriptions:
|
subscriptions:
|
||||||
'level-set-volume': (e) -> createjs.Sound.setVolume(e.volume)
|
'level-set-volume': (e) -> createjs.Sound.setVolume(e.volume)
|
||||||
|
'level-show-victory': 'onShowVictory'
|
||||||
|
'restart-level': 'onRestartLevel'
|
||||||
'level-highlight-dom': 'onHighlightDom'
|
'level-highlight-dom': 'onHighlightDom'
|
||||||
'end-level-highlight-dom': 'onEndHighlight'
|
'end-level-highlight-dom': 'onEndHighlight'
|
||||||
'level-focus-dom': 'onFocusDom'
|
'level-focus-dom': 'onFocusDom'
|
||||||
|
@ -53,33 +54,33 @@ module.exports = class SpectateLevelView extends View
|
||||||
'level-enable-controls': 'onEnableControls'
|
'level-enable-controls': 'onEnableControls'
|
||||||
'god:new-world-created': 'onNewWorld'
|
'god:new-world-created': 'onNewWorld'
|
||||||
'god:infinite-loop': 'onInfiniteLoop'
|
'god:infinite-loop': 'onInfiniteLoop'
|
||||||
|
'level-reload-from-data': 'onLevelReloadFromData'
|
||||||
|
'play-next-level': 'onPlayNextLevel'
|
||||||
'edit-wizard-settings': 'showWizardSettingsModal'
|
'edit-wizard-settings': 'showWizardSettingsModal'
|
||||||
'surface:world-set-up': 'onSurfaceSetUpNewWorld'
|
'surface:world-set-up': 'onSurfaceSetUpNewWorld'
|
||||||
'level:session-will-save': 'onSessionWillSave'
|
'level:session-will-save': 'onSessionWillSave'
|
||||||
'level:set-team': 'setTeam'
|
'level:set-team': 'setTeam'
|
||||||
|
'god:new-world-created': 'loadSoundsForWorld'
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'click #level-done-button': 'onDonePressed'
|
'click #level-done-button': 'onDonePressed'
|
||||||
|
|
||||||
|
shortcuts:
|
||||||
|
'ctrl+s': 'onCtrlS'
|
||||||
|
|
||||||
constructor: (options, @levelID) ->
|
constructor: (options, @levelID) ->
|
||||||
console.profile?() if PROFILE_ME
|
console.profile?() if PROFILE_ME
|
||||||
super options
|
super options
|
||||||
console.log @levelID
|
|
||||||
|
|
||||||
@ogreSessionID = @getQueryVariable 'ogres'
|
|
||||||
@humanSessionID = @getQueryVariable 'humans'
|
|
||||||
|
|
||||||
|
@sessionID = @getQueryVariable 'session'
|
||||||
|
|
||||||
$(window).on('resize', @onWindowResize)
|
$(window).on('resize', @onWindowResize)
|
||||||
@supermodel.once 'error', =>
|
@supermodel.once 'error', @onLevelLoadError
|
||||||
msg = $.i18n.t('play_level.level_load_error', defaultValue: "Level could not be loaded.")
|
|
||||||
@$el.html('<div class="alert">' + msg + '</div>')
|
|
||||||
|
|
||||||
|
|
||||||
@load()
|
@load()
|
||||||
|
|
||||||
|
onLevelLoadError: (e) =>
|
||||||
|
application.router.navigate "/play?not_found=#{@levelID}", {trigger: true}
|
||||||
|
|
||||||
setLevel: (@level, @supermodel) ->
|
setLevel: (@level, @supermodel) ->
|
||||||
@god?.level = @level.serialize @supermodel
|
@god?.level = @level.serialize @supermodel
|
||||||
|
@ -91,7 +92,8 @@ module.exports = class SpectateLevelView extends View
|
||||||
|
|
||||||
load: ->
|
load: ->
|
||||||
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @getQueryVariable('opponent'), team: @getQueryVariable("team")
|
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @getQueryVariable('opponent'), team: @getQueryVariable("team")
|
||||||
@levelLoader.once 'loaded-all', @onLevelLoaderLoaded
|
@levelLoader.once 'loaded-all', @onLevelLoaderLoaded, @
|
||||||
|
@levelLoader.on 'progress', @onLevelLoaderProgressChanged, @
|
||||||
@god = new God()
|
@god = new God()
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
|
@ -103,30 +105,83 @@ module.exports = class SpectateLevelView extends View
|
||||||
window.onPlayLevelViewLoaded? @ # still a hack
|
window.onPlayLevelViewLoaded? @ # still a hack
|
||||||
@loadingScreen = new LoadingScreen(@$el.find('canvas')[0])
|
@loadingScreen = new LoadingScreen(@$el.find('canvas')[0])
|
||||||
@loadingScreen.show()
|
@loadingScreen.show()
|
||||||
|
@$el.find('#level-done-button').hide()
|
||||||
super()
|
super()
|
||||||
|
|
||||||
onLevelLoaderLoaded: =>
|
onLevelLoaderProgressChanged: ->
|
||||||
#needs editing
|
return if @seenDocs
|
||||||
@session = @levelLoader.session
|
return unless showFrequency = @levelLoader.level.get('showGuide')
|
||||||
@world = @levelLoader.world
|
session = @levelLoader.session
|
||||||
@level = @levelLoader.level
|
diff = new Date().getTime() - new Date(session.get('created')).getTime()
|
||||||
@levelLoader.destroy()
|
return if showFrequency is 'first-time' and diff > (5 * 60 * 1000)
|
||||||
@levelLoader = null
|
return unless @levelLoader.level.loaded
|
||||||
|
articles = @levelLoader.supermodel.getModels Article
|
||||||
|
for article in articles
|
||||||
|
return unless article.loaded
|
||||||
|
@showGuide()
|
||||||
|
|
||||||
|
showGuide: ->
|
||||||
|
@seenDocs = true
|
||||||
|
DocsModal = require './level/modal/docs_modal'
|
||||||
|
options = {docs: @levelLoader.level.get('documentation'), supermodel: @supermodel}
|
||||||
|
@openModalView(new DocsModal(options), true)
|
||||||
|
Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @
|
||||||
|
return true
|
||||||
|
|
||||||
|
onLevelLoaderLoaded: ->
|
||||||
|
return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
|
||||||
|
# Save latest level played in local storage
|
||||||
|
if window.currentModal and not window.currentModal.destroyed
|
||||||
|
@loadingScreen.showReady()
|
||||||
|
return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @
|
||||||
|
|
||||||
|
localStorage["lastLevel"] = @levelID if localStorage?
|
||||||
|
@grabLevelLoaderData()
|
||||||
|
team = @getQueryVariable("team") ? @world.teamForPlayer(0)
|
||||||
|
@loadOpponentTeam(team)
|
||||||
@loadingScreen.destroy()
|
@loadingScreen.destroy()
|
||||||
@god.level = @level.serialize @supermodel
|
@god.level = @level.serialize @supermodel
|
||||||
@god.worldClassMap = @world.classMap
|
@god.worldClassMap = @world.classMap
|
||||||
#@setTeam @world.teamForPlayer _.size @session.get 'players' # TODO: players aren't initialized yet?
|
@setTeam team
|
||||||
@setTeam @getQueryVariable("team") ? @world.teamForPlayer(0)
|
|
||||||
@initSurface()
|
@initSurface()
|
||||||
@initGoalManager()
|
@initGoalManager()
|
||||||
@initScriptManager()
|
@initScriptManager()
|
||||||
@insertSubviews()
|
@insertSubviews ladderGame: @otherSession?
|
||||||
@initVolume()
|
@initVolume()
|
||||||
@session.on 'change:multiplayer', @onMultiplayerChanged, @
|
|
||||||
@originalSessionState = _.cloneDeep(@session.get('state'))
|
@originalSessionState = _.cloneDeep(@session.get('state'))
|
||||||
@register()
|
@register()
|
||||||
@controlBar.setBus(@bus)
|
@controlBar.setBus(@bus)
|
||||||
@surface.showLevel()
|
@surface.showLevel()
|
||||||
|
if @otherSession
|
||||||
|
# TODO: colorize name and cloud by team, colorize wizard by user's color config
|
||||||
|
@surface.createOpponentWizard id: @otherSession.get('creator'), name: @otherSession.get('creatorName'), team: @otherSession.get('team')
|
||||||
|
|
||||||
|
grabLevelLoaderData: ->
|
||||||
|
@session = @levelLoader.session
|
||||||
|
@world = @levelLoader.world
|
||||||
|
@level = @levelLoader.level
|
||||||
|
@otherSession = @levelLoader.opponentSession
|
||||||
|
@levelLoader.destroy()
|
||||||
|
@levelLoader = null
|
||||||
|
|
||||||
|
loadOpponentTeam: (myTeam) ->
|
||||||
|
opponentSpells = []
|
||||||
|
for spellTeam, spells of @session.get('teamSpells') ? @otherSession?.get('teamSpells') ? {}
|
||||||
|
continue if spellTeam is myTeam or not myTeam
|
||||||
|
opponentSpells = opponentSpells.concat spells
|
||||||
|
|
||||||
|
opponentCode = @otherSession?.get('submittedCode') or {}
|
||||||
|
myCode = @session.get('code') or {}
|
||||||
|
for spell in opponentSpells
|
||||||
|
[thang, spell] = spell.split '/'
|
||||||
|
c = opponentCode[thang]?[spell]
|
||||||
|
myCode[thang] ?= {}
|
||||||
|
if c then myCode[thang][spell] = c else delete myCode[thang][spell]
|
||||||
|
@session.set('code', myCode)
|
||||||
|
if @session.get('multiplayer') and @otherSession?
|
||||||
|
# For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet.
|
||||||
|
@session.set 'multiplayer', false
|
||||||
|
|
||||||
|
|
||||||
onSupermodelLoadedOne: =>
|
onSupermodelLoadedOne: =>
|
||||||
@modelsLoaded ?= 0
|
@modelsLoaded ?= 0
|
||||||
|
@ -142,38 +197,66 @@ module.exports = class SpectateLevelView extends View
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||||
ctx.fillText("Loaded #{@modelsLoaded} thingies",50,50)
|
ctx.fillText("Loaded #{@modelsLoaded} thingies",50,50)
|
||||||
|
|
||||||
insertSubviews: ->
|
insertSubviews: (subviewOptions) ->
|
||||||
#needs editing
|
@insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel, ladderGame: subviewOptions.ladderGame
|
||||||
@insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel
|
|
||||||
@insertSubView new PlaybackView {}
|
@insertSubView new PlaybackView {}
|
||||||
@insertSubView new GoalsView {}
|
@insertSubView new GoalsView {}
|
||||||
@insertSubView new GoldView {}
|
@insertSubView new GoldView {}
|
||||||
@insertSubView new HUDView {}
|
@insertSubView new HUDView {}
|
||||||
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
|
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
|
||||||
worldName = @level.get('i18n')?[me.lang()]?.name ? @level.get('name')
|
worldName = @level.get('i18n')?[me.lang()]?.name ? @level.get('name')
|
||||||
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel, playableTeams: @world.playableTeams}
|
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel, playableTeams: @world.playableTeams, ladderGame: subviewOptions.ladderGame}
|
||||||
#Backbone.Mediator.publish('level-set-debug', debug: true) if me.displayName() is 'Nick!'
|
#Backbone.Mediator.publish('level-set-debug', debug: true) if me.displayName() is 'Nick!'
|
||||||
|
|
||||||
afterInsert: ->
|
afterInsert: ->
|
||||||
super()
|
super()
|
||||||
|
@showWizardSettingsModal() if not me.get('name')
|
||||||
|
|
||||||
|
# callbacks
|
||||||
|
|
||||||
|
onCtrlS: (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
onLevelReloadFromData: (e) ->
|
||||||
|
isReload = Boolean @world
|
||||||
|
@setLevel e.level, e.supermodel
|
||||||
|
if isReload
|
||||||
|
@scriptManager.setScripts(e.level.get('scripts'))
|
||||||
|
Backbone.Mediator.publish 'tome:cast-spell' # a bit hacky
|
||||||
|
|
||||||
onWindowResize: (s...) ->
|
onWindowResize: (s...) ->
|
||||||
$('#pointer').css('opacity', 0.0)
|
$('#pointer').css('opacity', 0.0)
|
||||||
|
|
||||||
onDisableControls: (e) =>
|
onDisableControls: (e) ->
|
||||||
return if e.controls and not ('level' in e.controls)
|
return if e.controls and not ('level' in e.controls)
|
||||||
@shortcutsEnabled = false
|
@shortcutsEnabled = false
|
||||||
@wasFocusedOn = document.activeElement
|
@wasFocusedOn = document.activeElement
|
||||||
$('body').focus()
|
$('body').focus()
|
||||||
|
|
||||||
onEnableControls: (e) =>
|
onEnableControls: (e) ->
|
||||||
return if e.controls? and not ('level' in e.controls)
|
return if e.controls? and not ('level' in e.controls)
|
||||||
@shortcutsEnabled = true
|
@shortcutsEnabled = true
|
||||||
$(@wasFocusedOn).focus() if @wasFocusedOn
|
$(@wasFocusedOn).focus() if @wasFocusedOn
|
||||||
@wasFocusedOn = null
|
@wasFocusedOn = null
|
||||||
|
|
||||||
onDonePressed: => @showVictory()
|
onDonePressed: -> @showVictory()
|
||||||
|
|
||||||
|
onShowVictory: (e) ->
|
||||||
|
$('#level-done-button').show()
|
||||||
|
@showVictory() if e.showModal
|
||||||
|
setTimeout(@preloadNextLevel, 3000)
|
||||||
|
|
||||||
|
showVictory: ->
|
||||||
|
options = {level: @level, supermodel: @supermodel, session:@session}
|
||||||
|
docs = new VictoryModal(options)
|
||||||
|
@openModalView(docs)
|
||||||
|
window.tracker?.trackEvent 'Saw Victory', level: @world.name, label: @world.name
|
||||||
|
|
||||||
|
onRestartLevel: ->
|
||||||
|
@tome.reloadAllCode()
|
||||||
|
Backbone.Mediator.publish 'level:restarted'
|
||||||
|
$('#level-done-button', @$el).hide()
|
||||||
|
window.tracker?.trackEvent 'Confirmed Restart', level: @world.name, label: @world.name
|
||||||
|
|
||||||
onNewWorld: (e) ->
|
onNewWorld: (e) ->
|
||||||
@world = e.world
|
@world = e.world
|
||||||
|
@ -183,13 +266,21 @@ module.exports = class SpectateLevelView extends View
|
||||||
@openModalView new InfiniteLoopModal()
|
@openModalView new InfiniteLoopModal()
|
||||||
window.tracker?.trackEvent 'Saw Initial Infinite Loop', level: @world.name, label: @world.name
|
window.tracker?.trackEvent 'Saw Initial Infinite Loop', level: @world.name, label: @world.name
|
||||||
|
|
||||||
|
onPlayNextLevel: ->
|
||||||
|
nextLevel = @getNextLevel()
|
||||||
|
nextLevelID = nextLevel.get('slug') or nextLevel.id
|
||||||
|
url = "/play/level/#{nextLevelID}"
|
||||||
|
Backbone.Mediator.publish 'router:navigate', {
|
||||||
|
route: url,
|
||||||
|
viewClass: PlayLevelView,
|
||||||
|
viewArgs: [{supermodel:@supermodel}, nextLevelID]}
|
||||||
|
|
||||||
getNextLevel: ->
|
getNextLevel: ->
|
||||||
nextLevelOriginal = @level.get('nextLevel')?.original
|
nextLevelOriginal = @level.get('nextLevel')?.original
|
||||||
levels = @supermodel.getModels(Level)
|
levels = @supermodel.getModels(Level)
|
||||||
return l for l in levels when l.get('original') is nextLevelOriginal
|
return l for l in levels when l.get('original') is nextLevelOriginal
|
||||||
|
|
||||||
onHighlightDom: (e) =>
|
onHighlightDom: (e) ->
|
||||||
if e.delay
|
if e.delay
|
||||||
delay = e.delay
|
delay = e.delay
|
||||||
delete e.delay
|
delete e.delay
|
||||||
|
@ -243,19 +334,25 @@ module.exports = class SpectateLevelView extends View
|
||||||
), 1)
|
), 1)
|
||||||
|
|
||||||
|
|
||||||
animatePointer: =>
|
animatePointer: ->
|
||||||
pointer = $('#pointer')
|
pointer = $('#pointer')
|
||||||
pointer.css('transition', 'all 0.6s ease-out')
|
pointer.css('transition', 'all 0.6s ease-out')
|
||||||
pointer.css('transform', "rotate(#{@pointerRotation}rad) translate(-3px, #{@pointerRadialDistance-50}px)")
|
pointer.css('transform', "rotate(#{@pointerRotation}rad) translate(-3px, #{@pointerRadialDistance-50}px)")
|
||||||
setTimeout((=>
|
setTimeout((=>
|
||||||
pointer.css('transform', "rotate(#{@pointerRotation}rad) translate(-3px, #{@pointerRadialDistance}px)").css('transition', 'all 0.4s ease-in')), 800)
|
pointer.css('transform', "rotate(#{@pointerRotation}rad) translate(-3px, #{@pointerRadialDistance}px)").css('transition', 'all 0.4s ease-in')), 800)
|
||||||
|
|
||||||
onFocusDom: (e) => $(e.selector).focus()
|
onFocusDom: (e) -> $(e.selector).focus()
|
||||||
|
|
||||||
onEndHighlight: =>
|
onEndHighlight: ->
|
||||||
$('#pointer').css('opacity', 0.0)
|
$('#pointer').css('opacity', 0.0)
|
||||||
clearInterval(@pointerInterval)
|
clearInterval(@pointerInterval)
|
||||||
|
|
||||||
|
onMultiplayerChanged: (e) ->
|
||||||
|
if @session.get('multiplayer')
|
||||||
|
@bus.connect()
|
||||||
|
else
|
||||||
|
@bus.removeFirebaseData =>
|
||||||
|
@bus.disconnect()
|
||||||
|
|
||||||
# initialization
|
# initialization
|
||||||
|
|
||||||
|
@ -273,7 +370,7 @@ module.exports = class SpectateLevelView extends View
|
||||||
@surface.camera.zoomTo({x:0, y:0}, 0.1, 0)
|
@surface.camera.zoomTo({x:0, y:0}, 0.1, 0)
|
||||||
|
|
||||||
initGoalManager: ->
|
initGoalManager: ->
|
||||||
@goalManager = new GoalManager(@world)
|
@goalManager = new GoalManager(@world, @level.get('goals'))
|
||||||
@god.goalManager = @goalManager
|
@god.goalManager = @goalManager
|
||||||
|
|
||||||
initScriptManager: ->
|
initScriptManager: ->
|
||||||
|
@ -297,11 +394,18 @@ module.exports = class SpectateLevelView extends View
|
||||||
if state.playing?
|
if state.playing?
|
||||||
Backbone.Mediator.publish 'level-set-playing', { playing: state.playing }
|
Backbone.Mediator.publish 'level-set-playing', { playing: state.playing }
|
||||||
|
|
||||||
|
preloadNextLevel: =>
|
||||||
|
# TODO: Loading models in the middle of gameplay causes stuttering. Most of the improvement in loading time is simply from passing the supermodel from this level to the next, but if we can find a way to populate the level early without it being noticeable, that would be even better.
|
||||||
|
# return if @destroyed
|
||||||
|
# return if @preloaded
|
||||||
|
# nextLevel = @getNextLevel()
|
||||||
|
# @supermodel.populateModel nextLevel
|
||||||
|
# @preloaded = true
|
||||||
|
|
||||||
register: ->
|
register: ->
|
||||||
@bus = LevelBus.get(@levelID, @session.id)
|
@bus = LevelBus.get(@levelID, @session.id)
|
||||||
@bus.setSession(@session)
|
@bus.setSession(@session)
|
||||||
@bus.setTeamSpellMap @tome.teamSpellMap
|
@bus.setSpells @tome.spells
|
||||||
@bus.connect() if @session.get('multiplayer')
|
@bus.connect() if @session.get('multiplayer')
|
||||||
|
|
||||||
onSessionWillSave: (e) ->
|
onSessionWillSave: (e) ->
|
||||||
|
@ -319,7 +423,20 @@ module.exports = class SpectateLevelView extends View
|
||||||
me.team = team
|
me.team = team
|
||||||
Backbone.Mediator.publish 'level:team-set', team: team
|
Backbone.Mediator.publish 'level:team-set', team: team
|
||||||
|
|
||||||
|
# Dynamic sound loading
|
||||||
|
|
||||||
|
loadSoundsForWorld: (e) ->
|
||||||
|
return if @headless
|
||||||
|
world = e.world
|
||||||
|
thangTypes = @supermodel.getModels(ThangType)
|
||||||
|
for [spriteName, message] in world.thangDialogueSounds()
|
||||||
|
continue unless thangType = _.find thangTypes, (m) -> m.get('name') is spriteName
|
||||||
|
continue unless sound = AudioPlayer.soundForDialogue message, thangType.get('soundTriggers')
|
||||||
|
AudioPlayer.preloadSoundReference sound
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
|
@supermodel?.off 'error', @onLevelLoadError
|
||||||
|
@levelLoader?.off 'loaded-all', @onLevelLoaderLoaded
|
||||||
@levelLoader?.destroy()
|
@levelLoader?.destroy()
|
||||||
@surface?.destroy()
|
@surface?.destroy()
|
||||||
@god?.destroy()
|
@god?.destroy()
|
||||||
|
@ -327,10 +444,14 @@ module.exports = class SpectateLevelView extends View
|
||||||
@scriptManager?.destroy()
|
@scriptManager?.destroy()
|
||||||
$(window).off('resize', @onWindowResize)
|
$(window).off('resize', @onWindowResize)
|
||||||
delete window.world # not sure where this is set, but this is one way to clean it up
|
delete window.world # not sure where this is set, but this is one way to clean it up
|
||||||
|
|
||||||
clearInterval(@pointerInterval)
|
clearInterval(@pointerInterval)
|
||||||
@bus?.destroy()
|
@bus?.destroy()
|
||||||
#@instance.save() unless @instance.loading
|
#@instance.save() unless @instance.loading
|
||||||
console.profileEnd?() if PROFILE_ME
|
console.profileEnd?() if PROFILE_ME
|
||||||
@session.off 'change:multiplayer', @onMultiplayerChanged, @
|
@session?.off 'change:multiplayer', @onMultiplayerChanged, @
|
||||||
|
@onLevelLoadError = null
|
||||||
|
@onLevelLoaderLoaded = null
|
||||||
|
@onSupermodelLoadedOne = null
|
||||||
|
@preloadNextLevel = null
|
||||||
|
@saveScreenshot = null
|
||||||
super()
|
super()
|
||||||
|
|
|
@ -36,9 +36,19 @@ GoalSchema = c.object {title: "Goal", description: "A goal that the player can a
|
||||||
getToLocations: c.object {title: "Get To Locations", description: "Will be set off when any of the \"who\" touch any of the \"targets\" ", required: ["who", "targets"]},
|
getToLocations: c.object {title: "Get To Locations", description: "Will be set off when any of the \"who\" touch any of the \"targets\" ", required: ["who", "targets"]},
|
||||||
who: c.array {title: "Who", description: "The Thangs who must get to the target locations.", minItems: 1}, thang
|
who: c.array {title: "Who", description: "The Thangs who must get to the target locations.", minItems: 1}, thang
|
||||||
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must get.", minItems: 1}, thang
|
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must get.", minItems: 1}, thang
|
||||||
|
getAllToLocations: c.array {title: "Get all to locations", description: "Similar to getToLocations but now a specific \"who\" can have a specific \"target\", also must be used with the HowMany property for desired effect",required: ["getToLocation"]},
|
||||||
|
c.object {title: "", description: ""},
|
||||||
|
getToLocation: c.object {title: "Get To Locations", description: "TODO: explain", required: ["who", "targets"]},
|
||||||
|
who: c.array {title: "Who", description: "The Thangs who must get to the target locations.", minItems: 1}, thang
|
||||||
|
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must get.", minItems: 1}, thang
|
||||||
keepFromLocations: c.object {title: "Keep From Locations", description: "TODO: explain", required: ["who", "targets"]},
|
keepFromLocations: c.object {title: "Keep From Locations", description: "TODO: explain", required: ["who", "targets"]},
|
||||||
who: c.array {title: "Who", description: "The Thangs who must not get to the target locations.", minItems: 1}, thang
|
who: c.array {title: "Who", description: "The Thangs who must not get to the target locations.", minItems: 1}, thang
|
||||||
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must not get.", minItems: 1}, thang
|
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must not get.", minItems: 1}, thang
|
||||||
|
keepAllFromLocations: c.array {title: "Keep ALL From Locations", description: "Similar to keepFromLocations but now a specific \"who\" can have a specific \"target\", also must be used with the HowMany property for desired effect", required: ["keepFromLocation"]},
|
||||||
|
c.object {title: "", description: ""},
|
||||||
|
keepFromLocation: c.object {title: "Keep From Locations", description: "TODO: explain", required: ["who", "targets"]},
|
||||||
|
who: c.array {title: "Who", description: "The Thangs who must not get to the target locations.", minItems: 1}, thang
|
||||||
|
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must not get.", minItems: 1}, thang
|
||||||
leaveOffSides: c.object {title: "Leave Off Sides", description: "Sides of the level to get some Thangs to leave across.", required: ["who", "sides"]},
|
leaveOffSides: c.object {title: "Leave Off Sides", description: "Sides of the level to get some Thangs to leave across.", required: ["who", "sides"]},
|
||||||
who: c.array {title: "Who", description: "The Thangs which must leave off the sides of the level.", minItems: 1}, thang
|
who: c.array {title: "Who", description: "The Thangs which must leave off the sides of the level.", minItems: 1}, thang
|
||||||
sides: c.array {title: "Sides", description: "The sides off which the Thangs must leave.", minItems: 1}, side
|
sides: c.array {title: "Sides", description: "The sides off which the Thangs must leave.", minItems: 1}, side
|
||||||
|
@ -242,3 +252,4 @@ module.exports = LevelSchema
|
||||||
# 3. tv4.addSchema(metaschema.id, metaschema)
|
# 3. tv4.addSchema(metaschema.id, metaschema)
|
||||||
# 4. S = <paste big schema here>
|
# 4. S = <paste big schema here>
|
||||||
# 5. tv4.validateMultiple(S, metaschema) and look for errors
|
# 5. tv4.validateMultiple(S, metaschema) and look for errors
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,10 @@ _.extend LevelSessionSchema.properties,
|
||||||
submittedCode:
|
submittedCode:
|
||||||
type: 'object'
|
type: 'object'
|
||||||
|
|
||||||
|
isRanking:
|
||||||
|
type: 'boolean'
|
||||||
|
description: 'Whether this session is still in the first ranking chain after being submitted.'
|
||||||
|
|
||||||
unsubscribed:
|
unsubscribed:
|
||||||
type: 'boolean'
|
type: 'boolean'
|
||||||
description: 'Whether the player has opted out of receiving email updates about ladder rankings for this session.'
|
description: 'Whether the player has opted out of receiving email updates about ladder rankings for this session.'
|
||||||
|
@ -147,6 +151,7 @@ _.extend LevelSessionSchema.properties,
|
||||||
numberOfWinsAndTies:
|
numberOfWinsAndTies:
|
||||||
type: 'number'
|
type: 'number'
|
||||||
default: 0
|
default: 0
|
||||||
|
|
||||||
numberOfLosses:
|
numberOfLosses:
|
||||||
type: 'number'
|
type: 'number'
|
||||||
default: 0
|
default: 0
|
||||||
|
@ -162,7 +167,6 @@ _.extend LevelSessionSchema.properties,
|
||||||
items:
|
items:
|
||||||
type: 'number'
|
type: 'number'
|
||||||
|
|
||||||
|
|
||||||
matches:
|
matches:
|
||||||
type: 'array'
|
type: 'array'
|
||||||
title: 'Matches'
|
title: 'Matches'
|
||||||
|
|
|
@ -52,7 +52,7 @@ module.exports.createNewTask = (req, res) ->
|
||||||
requestLevelID = req.body.originalLevelID
|
requestLevelID = req.body.originalLevelID
|
||||||
requestCurrentLevelID = req.body.levelID
|
requestCurrentLevelID = req.body.levelID
|
||||||
requestLevelMajorVersion = parseInt(req.body.levelMajorVersion)
|
requestLevelMajorVersion = parseInt(req.body.levelMajorVersion)
|
||||||
|
|
||||||
validatePermissions req, requestSessionID, (error, permissionsAreValid) ->
|
validatePermissions req, requestSessionID, (error, permissionsAreValid) ->
|
||||||
if err? then return errors.serverError res, "There was an error validating permissions"
|
if err? then return errors.serverError res, "There was an error validating permissions"
|
||||||
unless permissionsAreValid then return errors.forbidden res, "You do not have the permissions to submit that game to the leaderboard"
|
unless permissionsAreValid then return errors.forbidden res, "You do not have the permissions to submit that game to the leaderboard"
|
||||||
|
@ -60,24 +60,24 @@ module.exports.createNewTask = (req, res) ->
|
||||||
return errors.badInput res, "The session ID is invalid" unless typeof requestSessionID is "string"
|
return errors.badInput res, "The session ID is invalid" unless typeof requestSessionID is "string"
|
||||||
Level.findOne({_id: requestCurrentLevelID}).lean().select('type').exec (err, levelWithType) ->
|
Level.findOne({_id: requestCurrentLevelID}).lean().select('type').exec (err, levelWithType) ->
|
||||||
if err? then return errors.serverError res, "There was an error finding the level type"
|
if err? then return errors.serverError res, "There was an error finding the level type"
|
||||||
|
|
||||||
if not levelWithType.type or levelWithType.type isnt "ladder"
|
if not levelWithType.type or levelWithType.type isnt "ladder"
|
||||||
console.log "The level type of level with ID #{requestLevelID} is #{levelWithType.type}"
|
console.log "The level type of level with ID #{requestLevelID} is #{levelWithType.type}"
|
||||||
return errors.badInput res, "That level isn't a ladder level"
|
return errors.badInput res, "That level isn't a ladder level"
|
||||||
|
|
||||||
fetchSessionToSubmit requestSessionID, (err, sessionToSubmit) ->
|
fetchSessionToSubmit requestSessionID, (err, sessionToSubmit) ->
|
||||||
if err? then return errors.serverError res, "There was an error finding the given session."
|
if err? then return errors.serverError res, "There was an error finding the given session."
|
||||||
|
|
||||||
updateSessionToSubmit sessionToSubmit, (err, data) ->
|
updateSessionToSubmit sessionToSubmit, (err, data) ->
|
||||||
if err? then return errors.serverError res, "There was an error updating the session"
|
if err? then return errors.serverError res, "There was an error updating the session"
|
||||||
opposingTeam = calculateOpposingTeam(sessionToSubmit.team)
|
opposingTeam = calculateOpposingTeam(sessionToSubmit.team)
|
||||||
fetchInitialSessionsToRankAgainst opposingTeam,requestLevelID, requestLevelMajorVersion, (err, sessionsToRankAgainst) ->
|
fetchInitialSessionsToRankAgainst opposingTeam,requestLevelID, requestLevelMajorVersion, (err, sessionsToRankAgainst) ->
|
||||||
if err? then return errors.serverError res, "There was an error fetching the sessions to rank against"
|
if err? then return errors.serverError res, "There was an error fetching the sessions to rank against"
|
||||||
|
|
||||||
taskPairs = generateTaskPairs(sessionsToRankAgainst, sessionToSubmit)
|
taskPairs = generateTaskPairs(sessionsToRankAgainst, sessionToSubmit)
|
||||||
sendEachTaskPairToTheQueue taskPairs, (taskPairError) ->
|
sendEachTaskPairToTheQueue taskPairs, (taskPairError) ->
|
||||||
if taskPairError? then return errors.serverError res, "There was an error sending the task pairs to the queue"
|
if taskPairError? then return errors.serverError res, "There was an error sending the task pairs to the queue"
|
||||||
|
|
||||||
sendResponseObject req, res, {"message":"All task pairs were succesfully sent to the queue"}
|
sendResponseObject req, res, {"message":"All task pairs were succesfully sent to the queue"}
|
||||||
|
|
||||||
module.exports.dispatchTaskToConsumer = (req, res) ->
|
module.exports.dispatchTaskToConsumer = (req, res) ->
|
||||||
|
@ -118,51 +118,53 @@ module.exports.processTaskResult = (req, res) ->
|
||||||
scoringTaskQueue.deleteMessage clientResponseObject.receiptHandle, (err) ->
|
scoringTaskQueue.deleteMessage clientResponseObject.receiptHandle, (err) ->
|
||||||
console.log "Deleted message."
|
console.log "Deleted message."
|
||||||
if err? then return errors.badInput res, "The queue message is already back in the queue, rejecting results."
|
if err? then return errors.badInput res, "The queue message is already back in the queue, rejecting results."
|
||||||
|
|
||||||
LevelSession.findOne(_id: clientResponseObject.originalSessionID).lean().exec (err, levelSession) ->
|
LevelSession.findOne(_id: clientResponseObject.originalSessionID).lean().exec (err, levelSession) ->
|
||||||
if err? then return errors.serverError res, "There was a problem finding the level session:#{err}"
|
if err? then return errors.serverError res, "There was a problem finding the level session:#{err}"
|
||||||
|
|
||||||
supposedSubmissionDate = new Date(clientResponseObject.sessions[0].submitDate)
|
supposedSubmissionDate = new Date(clientResponseObject.sessions[0].submitDate)
|
||||||
|
|
||||||
if Number(supposedSubmissionDate) isnt Number(levelSession.submitDate)
|
if Number(supposedSubmissionDate) isnt Number(levelSession.submitDate)
|
||||||
return sendResponseObject req, res, {"message":"The game has been resubmitted. Removing from queue..."}
|
return sendResponseObject req, res, {"message":"The game has been resubmitted. Removing from queue..."}
|
||||||
|
|
||||||
logTaskComputation clientResponseObject, taskLog, (logErr) ->
|
logTaskComputation clientResponseObject, taskLog, (logErr) ->
|
||||||
if logErr? then return errors.serverError res, "There as a problem logging the task computation: #{logErr}"
|
if logErr? then return errors.serverError res, "There as a problem logging the task computation: #{logErr}"
|
||||||
|
|
||||||
updateSessions clientResponseObject, (updateError, newScoreArray) ->
|
updateSessions clientResponseObject, (updateError, newScoreArray) ->
|
||||||
if updateError? then return errors.serverError res, "There was an error updating the scores.#{updateError}"
|
if updateError? then return errors.serverError res, "There was an error updating the scores.#{updateError}"
|
||||||
|
|
||||||
newScoresObject = _.indexBy newScoreArray, 'id'
|
newScoresObject = _.indexBy newScoreArray, 'id'
|
||||||
|
|
||||||
addMatchToSessions clientResponseObject, newScoresObject, (err, data) ->
|
addMatchToSessions clientResponseObject, newScoresObject, (err, data) ->
|
||||||
if err? then return errors.serverError res, "There was an error updating the sessions with the match! #{JSON.stringify err}"
|
if err? then return errors.serverError res, "There was an error updating the sessions with the match! #{JSON.stringify err}"
|
||||||
|
|
||||||
originalSessionID = clientResponseObject.originalSessionID
|
originalSessionID = clientResponseObject.originalSessionID
|
||||||
originalSessionTeam = clientResponseObject.originalSessionTeam
|
originalSessionTeam = clientResponseObject.originalSessionTeam
|
||||||
originalSessionRank = parseInt clientResponseObject.originalSessionRank
|
originalSessionRank = parseInt clientResponseObject.originalSessionRank
|
||||||
|
|
||||||
determineIfSessionShouldContinueAndUpdateLog originalSessionID, originalSessionRank, (err, sessionShouldContinue) ->
|
determineIfSessionShouldContinueAndUpdateLog originalSessionID, originalSessionRank, (err, sessionShouldContinue) ->
|
||||||
if err? then return errors.serverError res, "There was an error determining if the session should continue, #{err}"
|
if err? then return errors.serverError res, "There was an error determining if the session should continue, #{err}"
|
||||||
|
|
||||||
if sessionShouldContinue
|
if sessionShouldContinue
|
||||||
opposingTeam = calculateOpposingTeam(originalSessionTeam)
|
opposingTeam = calculateOpposingTeam(originalSessionTeam)
|
||||||
opponentID = _.pull(_.keys(newScoresObject), originalSessionID)
|
opponentID = _.pull(_.keys(newScoresObject), originalSessionID)
|
||||||
sessionNewScore = newScoresObject[originalSessionID].totalScore
|
sessionNewScore = newScoresObject[originalSessionID].totalScore
|
||||||
opponentNewScore = newScoresObject[opponentID].totalScore
|
opponentNewScore = newScoresObject[opponentID].totalScore
|
||||||
|
|
||||||
levelOriginalID = levelSession.level.original
|
levelOriginalID = levelSession.level.original
|
||||||
levelOriginalMajorVersion = levelSession.level.majorVersion
|
levelOriginalMajorVersion = levelSession.level.majorVersion
|
||||||
findNearestBetterSessionID levelOriginalID, levelOriginalMajorVersion, originalSessionID, sessionNewScore, opponentNewScore, opponentID ,opposingTeam, (err, opponentSessionID) ->
|
findNearestBetterSessionID levelOriginalID, levelOriginalMajorVersion, originalSessionID, sessionNewScore, opponentNewScore, opponentID ,opposingTeam, (err, opponentSessionID) ->
|
||||||
if err? then return errors.serverError res, "There was an error finding the nearest sessionID!"
|
if err? then return errors.serverError res, "There was an error finding the nearest sessionID!"
|
||||||
unless opponentSessionID then return sendResponseObject req, res, {"message":"There were no more games to rank(game is at top!"}
|
unless opponentSessionID then return sendResponseObject req, res, {"message":"There were no more games to rank(game is at top!"}
|
||||||
|
|
||||||
addPairwiseTaskToQueue [originalSessionID, opponentSessionID], (err, success) ->
|
addPairwiseTaskToQueue [originalSessionID, opponentSessionID], (err, success) ->
|
||||||
if err? then return errors.serverError res, "There was an error sending the pairwise tasks to the queue!"
|
if err? then return errors.serverError res, "There was an error sending the pairwise tasks to the queue!"
|
||||||
sendResponseObject req, res, {"message":"The scores were updated successfully and more games were sent to the queue!"}
|
sendResponseObject req, res, {"message":"The scores were updated successfully and more games were sent to the queue!"}
|
||||||
else
|
else
|
||||||
console.log "Player lost, achieved rank #{originalSessionRank}"
|
console.log "Player lost, achieved rank #{originalSessionRank}"
|
||||||
sendResponseObject req, res, {"message":"The scores were updated successfully, person lost so no more games are being inserted!"}
|
LevelSession.update {_id: originalSessionID}, {isRanking: false}, {multi: false}, (err, affected) ->
|
||||||
|
if err? then return errors.serverError res, "There was an error marking the completed session as not being ranked."
|
||||||
|
sendResponseObject req, res, {"message":"The scores were updated successfully, person lost so no more games are being inserted!"}
|
||||||
|
|
||||||
|
|
||||||
determineIfSessionShouldContinueAndUpdateLog = (sessionID, sessionRank, cb) ->
|
determineIfSessionShouldContinueAndUpdateLog = (sessionID, sessionRank, cb) ->
|
||||||
|
@ -285,7 +287,7 @@ updateMatchesInSession = (matchObject, sessionID, callback) ->
|
||||||
currentMatchObject.opponents = opponentsArray
|
currentMatchObject.opponents = opponentsArray
|
||||||
|
|
||||||
sessionUpdateObject =
|
sessionUpdateObject =
|
||||||
$push: {matches: currentMatchObject}
|
$push: {matches: {$each: [currentMatchObject], $slice: -200}}
|
||||||
log.info "Updating session #{sessionID}"
|
log.info "Updating session #{sessionID}"
|
||||||
LevelSession.update {"_id":sessionID}, sessionUpdateObject, callback
|
LevelSession.update {"_id":sessionID}, sessionUpdateObject, callback
|
||||||
|
|
||||||
|
@ -304,12 +306,12 @@ updateSessionToSubmit = (sessionToUpdate, callback) ->
|
||||||
submitted: true
|
submitted: true
|
||||||
submittedCode: sessionToUpdate.code
|
submittedCode: sessionToUpdate.code
|
||||||
submitDate: new Date()
|
submitDate: new Date()
|
||||||
matches: []
|
|
||||||
meanStrength: 25
|
meanStrength: 25
|
||||||
standardDeviation: 25/3
|
standardDeviation: 25/3
|
||||||
totalScore: 10
|
totalScore: 10
|
||||||
numberOfWinsAndTies: 0
|
numberOfWinsAndTies: 0
|
||||||
numberOfLosses: 0
|
numberOfLosses: 0
|
||||||
|
isRanking: true
|
||||||
LevelSession.update {_id: sessionToUpdate._id}, sessionUpdateObject, callback
|
LevelSession.update {_id: sessionToUpdate._id}, sessionUpdateObject, callback
|
||||||
|
|
||||||
fetchInitialSessionsToRankAgainst = (opposingTeam, levelID, levelMajorVersion, callback) ->
|
fetchInitialSessionsToRankAgainst = (opposingTeam, levelID, levelMajorVersion, callback) ->
|
||||||
|
@ -321,7 +323,7 @@ fetchInitialSessionsToRankAgainst = (opposingTeam, levelID, levelMajorVersion, c
|
||||||
submittedCode:
|
submittedCode:
|
||||||
$exists: true
|
$exists: true
|
||||||
team: opposingTeam
|
team: opposingTeam
|
||||||
|
|
||||||
sortParameters =
|
sortParameters =
|
||||||
totalScore: 1
|
totalScore: 1
|
||||||
|
|
||||||
|
@ -449,8 +451,7 @@ updateScoreInSession = (scoreObject,callback) ->
|
||||||
meanStrength: scoreObject.meanStrength
|
meanStrength: scoreObject.meanStrength
|
||||||
standardDeviation: scoreObject.standardDeviation
|
standardDeviation: scoreObject.standardDeviation
|
||||||
totalScore: newTotalScore
|
totalScore: newTotalScore
|
||||||
$push:
|
$push: {scoreHistory: {$each: [scoreHistoryAddition], $slice: -1000}}
|
||||||
scoreHistory: scoreHistoryAddition
|
|
||||||
|
|
||||||
LevelSession.update {"_id": scoreObject.id}, updateObject, callback
|
LevelSession.update {"_id": scoreObject.id}, updateObject, callback
|
||||||
log.info "New total score for session #{scoreObject.id} is #{updateObject.totalScore}"
|
log.info "New total score for session #{scoreObject.id} is #{updateObject.totalScore}"
|
||||||
|
|
|
@ -76,7 +76,7 @@ sendLadderUpdateEmail = (session, daysAgo) ->
|
||||||
# (We could look at strongest/weakest, but we'd have to fetch everyone, or denormalize more.)
|
# (We could look at strongest/weakest, but we'd have to fetch everyone, or denormalize more.)
|
||||||
matches = _.filter session.matches, (match) -> match.date >= (new Date() - 86400 * 1000 * daysAgo)
|
matches = _.filter session.matches, (match) -> match.date >= (new Date() - 86400 * 1000 * daysAgo)
|
||||||
defeats = _.filter matches, (match) -> match.metrics.rank is 1 and match.opponents[0].metrics.rank is 0
|
defeats = _.filter matches, (match) -> match.metrics.rank is 1 and match.opponents[0].metrics.rank is 0
|
||||||
victories = _.filter matches, (match) -> match.metrics.rank is 0
|
victories = _.filter matches, (match) -> match.metrics.rank is 0 and match.opponents[0].metrics.rank is 1
|
||||||
defeat = _.last defeats
|
defeat = _.last defeats
|
||||||
victory = _.last victories
|
victory = _.last victories
|
||||||
|
|
||||||
|
|
126
vendor/scripts/idle.js
vendored
Normal file
126
vendor/scripts/idle.js
vendored
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
// https://github.com/shawnmclean/Idle.js
|
||||||
|
(function() {
|
||||||
|
"use strict";
|
||||||
|
var Idle;
|
||||||
|
|
||||||
|
Idle = {};
|
||||||
|
|
||||||
|
Idle = (function() {
|
||||||
|
Idle.isAway = false;
|
||||||
|
|
||||||
|
Idle.awayTimeout = 3000;
|
||||||
|
|
||||||
|
Idle.awayTimestamp = 0;
|
||||||
|
|
||||||
|
Idle.awayTimer = null;
|
||||||
|
|
||||||
|
Idle.onAway = null;
|
||||||
|
|
||||||
|
Idle.onAwayBack = null;
|
||||||
|
|
||||||
|
Idle.onVisible = null;
|
||||||
|
|
||||||
|
Idle.onHidden = null;
|
||||||
|
|
||||||
|
function Idle(options) {
|
||||||
|
var activeMethod, activity;
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
this.awayTimeout = parseInt(options.awayTimeout, 10);
|
||||||
|
this.onAway = options.onAway;
|
||||||
|
this.onAwayBack = options.onAwayBack;
|
||||||
|
this.onVisible = options.onVisible;
|
||||||
|
this.onHidden = options.onHidden;
|
||||||
|
}
|
||||||
|
activity = this;
|
||||||
|
activeMethod = function() {
|
||||||
|
return activity.onActive();
|
||||||
|
};
|
||||||
|
window.onclick = activeMethod;
|
||||||
|
window.onmousemove = activeMethod;
|
||||||
|
window.onmouseenter = activeMethod;
|
||||||
|
window.onkeydown = activeMethod;
|
||||||
|
window.onscroll = activeMethod;
|
||||||
|
window.onmousewheel = activeMethod;
|
||||||
|
document.addEventListener("visibilitychange", (function() {
|
||||||
|
return activity.handleVisibilityChange();
|
||||||
|
}), false);
|
||||||
|
document.addEventListener("webkitvisibilitychange", (function() {
|
||||||
|
return activity.handleVisibilityChange();
|
||||||
|
}), false);
|
||||||
|
document.addEventListener("msvisibilitychange", (function() {
|
||||||
|
return activity.handleVisibilityChange();
|
||||||
|
}), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Idle.prototype.onActive = function() {
|
||||||
|
this.awayTimestamp = new Date().getTime() + this.awayTimeout;
|
||||||
|
if (this.isAway) {
|
||||||
|
if (this.onAwayBack) {
|
||||||
|
this.onAwayBack();
|
||||||
|
}
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
this.isAway = false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Idle.prototype.start = function() {
|
||||||
|
var activity;
|
||||||
|
|
||||||
|
this.awayTimestamp = new Date().getTime() + this.awayTimeout;
|
||||||
|
if (this.awayTimer !== null) {
|
||||||
|
clearTimeout(this.awayTimer);
|
||||||
|
}
|
||||||
|
activity = this;
|
||||||
|
this.awayTimer = setTimeout((function() {
|
||||||
|
return activity.checkAway();
|
||||||
|
}), this.awayTimeout + 100);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Idle.prototype.setAwayTimeout = function(ms) {
|
||||||
|
this.awayTimeout = parseInt(ms, 10);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Idle.prototype.checkAway = function() {
|
||||||
|
var activity, t;
|
||||||
|
|
||||||
|
t = new Date().getTime();
|
||||||
|
if (t < this.awayTimestamp) {
|
||||||
|
this.isAway = false;
|
||||||
|
activity = this;
|
||||||
|
this.awayTimer = setTimeout((function() {
|
||||||
|
return activity.checkAway();
|
||||||
|
}), this.awayTimestamp - t + 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.awayTimer !== null) {
|
||||||
|
clearTimeout(this.awayTimer);
|
||||||
|
}
|
||||||
|
this.isAway = true;
|
||||||
|
if (this.onAway) {
|
||||||
|
return this.onAway();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Idle.prototype.handleVisibilityChange = function() {
|
||||||
|
if (document.hidden || document.msHidden || document.webkitHidden) {
|
||||||
|
if (this.onHidden) {
|
||||||
|
return this.onHidden();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.onVisible) {
|
||||||
|
return this.onVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Idle;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
window.Idle = Idle;
|
||||||
|
|
||||||
|
}).call(this);
|
Loading…
Reference in a new issue