This commit is contained in:
George Saines 2014-10-13 15:51:48 -07:00
commit 6350debf26
23 changed files with 576 additions and 216 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

View file

@ -29,7 +29,7 @@ module.exports = class LevelBus extends Bus
constructor: ->
super(arguments...)
@changedSessionProperties = {}
@saveSession = _.debounce(@saveSession, 1000, {maxWait: 5000})
@saveSession = _.debounce(@reallySaveSession, 1000, {maxWait: 5000})
@playerIsIdle = false
init: ->
@ -190,7 +190,7 @@ module.exports = class LevelBus extends Bus
state.complete = true
@session.set('state', state)
@changedSessionProperties.state = true
@saveSession()
@reallySaveSession() # Make sure it saves right away; don't debounce it.
onNewGoalStates: ({goalStates})->
state = @session.get 'state'
@ -232,7 +232,8 @@ module.exports = class LevelBus extends Bus
@changedSessionProperties.permissions = true
@saveSession()
saveSession: ->
# Debounced as saveSession
reallySaveSession: ->
return if _.isEmpty @changedSessionProperties
# don't let peeking admins mess with the session accidentally
return unless @session.get('multiplayer') or @session.get('creator') is me.id

View file

@ -8,7 +8,7 @@ module.exports.createAetherOptions = (options) ->
aetherOptions =
functionName: options.functionName
protectAPI: not options.skipProtectAPI
includeFlow: options.includeFlow
includeFlow: Boolean options.includeFlow
yieldConditionally: options.functionName is 'plan'
simpleLoops: true
globals: ['Vector', '_']

View file

@ -6,7 +6,7 @@
** Paths and target pieces (and ghosts?)
** Normal Thangs, bots, wizards (z-indexing based on World-determined sprite.thang.pos.z/y, mainly, instead of sprite-map-determined sprite.z, which we rename to... something)
** Above-thang marks (blood, highlight) and health bars
* Stage (Regular Canvas)
** Camera border
** surfaceTextLayer (speech, names)
@ -14,7 +14,7 @@
*** Letterbox
**** Letterbox top and bottom
*** FPS display, maybe grid axis labels, coordinate hover
** Grid lines--somewhere--we will figure it out, do not really need it at first
###
@ -26,7 +26,7 @@ SingularSprite = require './SingularSprite'
NEVER_RENDER_ANYTHING = false # set to true to test placeholders
module.exports = LayerAdapter = class LayerAdapter extends CocoClass
# Intermediary between a Surface Stage and a top-level static normal Container or hot-swapped WebGL SpriteContainer.
# It handles zooming in different ways and, if webGL, creating and assigning spriteSheets.
@ -79,8 +79,9 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
toString: -> "<Layer #{@layerPriority}: #{@name}>"
#- Layer ordering
updateLayerOrder: ->
return if @destroyed
@container.sortChildren @layerOrderComparator
layerOrderComparator: (a, b) ->
@ -105,7 +106,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
return 0 unless aPos and bPos
return (bPos.y - aPos.y) or (bPos.x - aPos.x)
return az - bz
#- Zoom updating
onZoomUpdated: (e) ->
@ -141,13 +142,13 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
child.scaleY *= @container.scaleY
#- Adding, removing children for WebGL layers.
addLank: (lank) ->
# TODO: Move this into the production DB rather than setting it dynamically.
if lank.thangType?.get('name') is 'Highlight'
lank.thangType.set('spriteType', 'segmented')
lank.options.resolutionFactor = @resolutionFactor
lank.layer = @
@listenTo(lank, 'action-needs-render', @onActionNeedsRender)
@lanks.push lank
@ -164,7 +165,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
@lanks = _.without @lanks, lank
#- Loading network resources dynamically
loadThangType: (thangType) ->
if not thangType.isFullyLoaded()
thangType.setProjection null
@ -185,7 +186,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
@renderNewSpriteSheet()
#- Adding to the list of things we need to render
onActionNeedsRender: (lank, action) ->
@upsertActionToRender(lank.thangType, action.name, lank.options.colorConfig)
@ -214,16 +215,16 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
@_renderNewSpriteSheet(false)
#- Rendering sprite sheets
renderNewSpriteSheet: ->
@willRender = false
return if @numThingsLoading
@_renderNewSpriteSheet()
_renderNewSpriteSheet: (async) ->
@asyncBuilder.stopAsync() if @asyncBuilder
@asyncBuilder = null
async ?= @buildAsync
builder = new createjs.SpriteSheetBuilder()
groups = _.groupBy(@toRenderBundles, ((bundle) -> @renderGroupingKey(bundle.thangType, '', bundle.colorConfig)), @)
@ -233,7 +234,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
dimension = @resolutionFactor * SPRITE_PLACEHOLDER_WIDTH
placeholder.setBounds(0, 0, dimension, dimension)
builder.addFrame(placeholder)
# Add custom graphics
extantGraphics = if @spriteSheet?.resolutionFactor is @resolutionFactor then @spriteSheet.getAnimations() else []
for key, graphic of @customGraphics
@ -244,7 +245,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
else
frame = builder.addFrame(graphic.graphic, graphic.bounds, @resolutionFactor)
builder.addAnimation(key, [frame], false)
# Render ThangTypes
groups = {} if NEVER_RENDER_ANYTHING
for bundleGrouping in _.values(groups)
@ -259,7 +260,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
@renderSingularThangType(args...)
else
@renderRasterThangType(thangType, builder)
if async
try
builder.buildAsync()
@ -272,11 +273,11 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
sheet = builder.build()
@onBuildSpriteSheetComplete({async:async}, builder)
return sheet
onBuildSpriteSheetComplete: (e, builder) ->
return if @initializing or @destroyed
@asyncBuilder = null
if builder.spriteSheet._images.length > 1
total = 0
# get a rough estimate of how much smaller the spritesheet needs to be
@ -285,10 +286,10 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
@resolutionFactor /= (Math.max(1.1, Math.sqrt(total)))
@_renderNewSpriteSheet(e.async)
return
@spriteSheet = builder.spriteSheet
@spriteSheet.resolutionFactor = @resolutionFactor
oldLayer = @container
oldLayer = @container
@container = new createjs.SpriteContainer(@spriteSheet)
for lank in @lanks
console.log 'zombie sprite found on layer', @name if lank.destroyed
@ -307,7 +308,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
lank.updateScale()
lank.updateRotation()
@trigger 'new-spritesheet'
resetSpriteSheet: ->
@removeLank(lank) for lank in @lanks.slice(0)
@toRenderBundles = []
@ -317,9 +318,9 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
@initializing = false
#- Placeholder
createPlaceholder: ->
# TODO: Experiment with this. Perhaps have rectangles if default layer is obstacle or floor,
# TODO: Experiment with this. Perhaps have rectangles if default layer is obstacle or floor,
# and different colors for different layers.
g = new createjs.Graphics()
g.setStrokeStyle(5)
@ -341,7 +342,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
else
g.drawRect(bounds...)
new createjs.Shape(g)
#- Rendering containers for segmented thang types
renderSegmentedThangType: (thangType, colorConfig, actionNames, spriteSheetBuilder) ->
@ -353,7 +354,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
else if action.animation
animationContainers = @getContainersForAnimation(thangType, action.animation, action)
containersToRender[container.gn] = true for container in animationContainers
spriteBuilder = new SpriteBuilder(thangType, {colorConfig: colorConfig})
for containerGlobalName in _.keys(containersToRender)
containerKey = @renderGroupingKey(thangType, containerGlobalName, colorConfig)
@ -374,9 +375,9 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
for animation in thangType.get('raw').animations[animation].animations
containers = containers.concat(@getContainersForAnimation(thangType, animation.gn, action))
return containers
#- Rendering sprite sheets for singular thang types
renderSingularThangType: (thangType, colorConfig, actionNames, spriteSheetBuilder) ->
actionObjects = _.values(thangType.getActions())
animationActions = []
@ -384,14 +385,14 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
continue unless a.animation
continue unless a.name in actionNames
animationActions.push(a)
spriteBuilder = new SpriteBuilder(thangType, {colorConfig: colorConfig})
animationGroups = _.groupBy animationActions, (action) -> action.animation
for animationName, actions of animationGroups
renderAll = _.any actions, (action) -> action.frames is undefined
scale = actions[0].scale or thangType.get('scale') or 1
actionKeys = (@renderGroupingKey(thangType, action.name, colorConfig) for action in actions)
if @spriteSheet?.resolutionFactor is @resolutionFactor and _.all(actionKeys, (key) => key in @spriteSheet.getAnimations())
framesNeeded = _.uniq(_.flatten((@spriteSheet.getAnimation(key)).frames for key in actionKeys))
@ -406,9 +407,9 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
next = @nextForAction(action)
spriteSheetBuilder.addAnimation(key, frames, next)
continue
mc = spriteBuilder.buildMovieClip(animationName, null, null, null, {'temp':0})
if renderAll
res = spriteSheetBuilder.addMovieClip(mc, null, scale * @resolutionFactor)
frames = spriteSheetBuilder._animations['temp'].frames
@ -420,23 +421,23 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
frame = parseInt(frame)
f = _.bind(mc.gotoAndStop, mc, frame)
framesMap[frame] = spriteSheetBuilder.addFrame(mc, null, scale * @resolutionFactor, f)
for action in actions
name = @renderGroupingKey(thangType, action.name, colorConfig)
if action.frames
frames = (framesMap[parseInt(frame)] for frame in action.frames.split(','))
else
frames = _.sortBy(_.values(framesMap))
next = @nextForAction(action)
spriteSheetBuilder.addAnimation(name, frames, next)
spriteSheetBuilder.addAnimation(name, frames, next)
containerActions = []
for a in actionObjects
continue unless a.container
continue unless a.name in actionNames
containerActions.push(a)
containerGroups = _.groupBy containerActions, (action) -> action.container
for containerName, actions of containerGroups
container = spriteBuilder.buildContainerFromStore(containerName)
@ -444,25 +445,25 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
frame = spriteSheetBuilder.addFrame(container, null, scale * @resolutionFactor)
for action in actions
name = @renderGroupingKey(thangType, action.name, colorConfig)
spriteSheetBuilder.addAnimation(name, [frame], false)
spriteSheetBuilder.addAnimation(name, [frame], false)
nextForAction: (action) ->
next = true
next = action.goesTo if action.goesTo
next = false if action.loops is false
return next
#- Rendering frames for raster thang types
renderRasterThangType: (thangType, spriteSheetBuilder) ->
unless thangType.rasterImage
console.error("Cannot render the LayerAdapter SpriteSheet until the raster image for <#{thangType.get('name')}> is loaded.")
bm = new createjs.Bitmap(thangType.rasterImage[0])
scale = thangType.get('scale') or 1
frame = spriteSheetBuilder.addFrame(bm, null, scale)
spriteSheetBuilder.addAnimation(@renderGroupingKey(thangType), [frame], false)
#- Distributing new Segmented/Singular/RasterSprites to Lanks
setSpriteToLank: (lank) ->
@ -474,7 +475,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
sprite.regX = @resolutionFactor * SPRITE_PLACEHOLDER_WIDTH / 2
sprite.regY = @resolutionFactor * SPRITE_PLACEHOLDER_WIDTH
sprite.baseScaleX = sprite.baseScaleY = sprite.scaleX = sprite.scaleY = 10 / (@resolutionFactor * SPRITE_PLACEHOLDER_WIDTH)
else if lank.thangType.get('raster')
sprite = new createjs.Sprite(@spriteSheet)
scale = lank.thangType.get('scale') or 1
@ -483,7 +484,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
sprite.regY = -reg.y * scale
sprite.gotoAndStop(@renderGroupingKey(lank.thangType))
sprite.baseScaleX = sprite.baseScaleY = 1
else
SpriteClass = if (lank.thangType.get('spriteType') or @defaultSpriteType) is 'segmented' then SegmentedSprite else SingularSprite
prefix = @renderGroupingKey(lank.thangType, null, lank.options.colorConfig) + '.'
@ -507,4 +508,4 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
destroy: ->
child.destroy?() for child in @container.children
@asyncBuilder.stopAsync() if @asyncBuilder
super()
super()

View file

@ -1,21 +1,21 @@
module.exports = nativeDescription: "Ελληνικά", englishDescription: "Greek", translation:
home:
slogan: "Μάθε να προγραμμάτιζεις με JavaScript μέσω ενός παιχνιδιού"
no_ie: "Το CodeCombat δεν παίζει με το Internet Explorer 8 ή κάποια παλαιότερη έκδοση. Συγνώμη!" # Warning that only shows up in IE8 and older
slogan: "Μάθε να Προγραμμάτιζεις Παίζοντας ένα Παιχνίδι"
no_ie: "Το CodeCombat δεν τρέχει σε Internet Explorer 9 ή παλαιότερη έκδοση. Συγνώμη!" # Warning that only shows up in IE8 and older
no_mobile: "Το CodeCombat δεν σχεδιάστηκε για κινητά και μπορεί να μην δουλεύει!" # Warning that shows up on mobile devices
play: "Παίξε" # The big play button that just starts playing a level
old_browser: "Ωχ, ο περιηγητής σας είναι πολύ παλιός για να τρέξετε το CodeCombat. Συγνώμη!" # Warning that shows up on really old Firefox/Chrome/Safari
old_browser_suffix: "Μπορείτε να δοκιμάσετε, αλλά πιθανών να μην λειτουργήσει."
old_browser: "Ωχ, ο περιηγητής σας είναι πολύ παλιός για να τρέξει το CodeCombat. Συγνώμη!" # Warning that shows up on really old Firefox/Chrome/Safari
old_browser_suffix: "Μπορείτε να δοκιμάσετε, αλλά πιθανότατα να μην λειτουργήσει."
campaign: "Εκστρατεία"
for_beginners: "Για αρχάριους"
# multiplayer: "Multiplayer" # Not currently shown on home page
multiplayer: "Πολλαπλοί Παίκτες" # Not currently shown on home page
for_developers: "Για προγραμματιστές" # Not currently shown on home page.
# javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers." # Not currently shown on home page
# python_blurb: "Simple yet powerful, Python is a great general purpose programming language." # Not currently shown on home page
# coffeescript_blurb: "Nicer JavaScript syntax." # Not currently shown on home page
# clojure_blurb: "A modern Lisp." # Not currently shown on home page
# lua_blurb: "Game scripting language." # Not currently shown on home page
# io_blurb: "Simple but obscure." # Not currently shown on home page
javascript_blurb: "Η γλώσσα του web. Ιδανική για δημιουργία ιστοσελίδων, web εφαρμογών, παιχνίδια HTML5, και διακομιστές." # Not currently shown on home page
python_blurb: "Απλή αλλά δυνατή, η Python είναι μια πολύ καλή γλώσσα προγραμματισμού γενικής χρήσης." # Not currently shown on home page
coffeescript_blurb: "Καλύτερη JavaScript σύνταξη." # Not currently shown on home page
clojure_blurb: "Μοντέρνα Lisp." # Not currently shown on home page
lua_blurb: "Scripting γλώσσα παιχνιδιών." # Not currently shown on home page
io_blurb: "Απλή αλλά ασαφής." # Not currently shown on home page
nav:
play: "Επίπεδα" # The top nav bar entry where players choose which levels to play
@ -30,7 +30,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
admin: "Διαχειριστής" # Only shows up when you are an admin
home: "Αρχική"
contribute: "Συνεισφέρω"
legal: "Νόμικά"
legal: "Νομικά"
about: "Σχετικά με"
contact: "Επικοινωνία"
twitter_follow: "Ακολούθησε"
@ -44,76 +44,76 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
page_not_found: "Η σελίδα δεν βρέθηκε"
diplomat_suggestion:
title: "Βοηθήστε στην μετάφραση CodeCombat!" # This shows up when a player switches to a non-English language using the language selector.
title: "Βοηθήστε στην μετάφραση του CodeCombat!" # This shows up when a player switches to a non-English language using the language selector.
sub_heading: "Χρειαζόμαστε τις γλωσσικές σας δεξιότητες."
pitch_body: "Αναπτύσσουμε το CodeCombat στα αγγλικά, αλλά ήδη έχουμε παίκτες από όλο τον κόσμο. Πολλοί από αυτούς θέλουν να παίξουν στα αγγλικά, αλλά δεν μιλούν αγγλικά, οπότε αν μπορείτε να μιλήσετε και τις δύο, παρακαλούμε να Αναπτύσσουμε CodeCombat στα αγγλικά, αλλά ήδη έχουμε παίκτες σε όλο τον κόσμο. Πολλοί από αυτούς θέλουν να παίξουν στα Ελληνικά, αλλά δεν μιλούν αγγλικά, οπότε αν μπορείτε να μιλήσετε και τις δύο γλώσσες, παρακαλούμε να σκεφτείτε την εγγραφή ως ένας Διπλωμάτης και βοηθήστε να μεταφραστεί τόσο η ιστοσελίδα CodeCombat και όλα τα επίπεδα στην Ελληνική γλώσσα."
pitch_body: "Αναπτύσσουμε το CodeCombat στα Αγγλικά, αλλά ήδη έχουμε παίκτες από όλο τον κόσμο. Πολλοί από αυτούς θέλουν να παίξουν στα Ελληνικά, αλλά δεν μιλούν Αγγλικά, οπότε αν μπορείτε να μιλήσετε και τις δύο, παρακαλούμε να σκεφτείτε την εγγραφή ως Διπλωμάτης και να βοηθήσετε να μεταφραστεί τόσο η ιστοσελίδα CodeCombat και όλα τα επίπεδα στην Ελληνική."
missing_translations: "Μέχρι να μπορούν να μεταφράσουν τα πάντα σε Ελληνικά, θα δείτε την αγγλική γλώσσα όπου τα Ελληνικά δεν είναι διαθέσιμα."
learn_more: "Μάθετε περισσότερα σχετικά με το να είστε ένας Διπλωμάτης"
subscribe_as_diplomat: "Εγγραφή ως Διπλωμάτης"
play:
# play_as: "Play As" # Ladder page
# spectate: "Spectate" # Ladder page
# players: "players" # Hover over a level on /play
# hours_played: "hours played" # Hover over a level on /play
# items: "Items" # Tooltip on item shop button from /play
# heroes: "Heroes" # Tooltip on hero shop button from /play
# achievements: "Achievements" # Tooltip on achievement list button from /play
# account: "Account" # Tooltip on account button from /play
# settings: "Settings" # Tooltip on settings button from /play
# next: "Next" # Go from choose hero to choose inventory before playing a level
play_as: "Παίξτε ως" # Ladder page
spectate: "Θεατής" # Ladder page
players: "παίκτες" # Hover over a level on /play
hours_played: "ώρες παιχνιδιού" # Hover over a level on /play
items: "Αντικείμενα" # Tooltip on item shop button from /play
heroes: "Ήρωες" # Tooltip on hero shop button from /play
achievements: "Επιτεύγματα" # Tooltip on achievement list button from /play
account: "Λογαριασμός" # Tooltip on account button from /play
settings: "Ρυθμίσεις" # Tooltip on settings button from /play
next: "Επόμενο" # Go from choose hero to choose inventory before playing a level
# change_hero: "Change Hero" # Go back from choose inventory to choose hero
# choose_inventory: "Equip Items"
# older_campaigns: "Older Campaigns"
# anonymous: "Anonymous Player"
choose_inventory: "Εξοπλίσου με Αντικείμενα"
older_campaigns: "Παλαιότερες Εκστρατείες"
anonymous: "Ανώνυμοι Παίκτες"
level_difficulty: "Δυσκολία: "
campaign_beginner: "Εκστρατεία για Αρχάριους"
choose_your_level: "Διάλεξε την πίστα σου" # The rest of this section is the old play view at /play-old and isn't very important.
adventurer_prefix: "Μπορείτε να μεταβείτε σε οποιοδήποτε επίπεδο κάτω, ή να συζητήσετε για τις πίστες στο "
adventurer_forum: "Φόρουμ του \"Τυχοδιώκτη\""
# adventurer_suffix: "."
# campaign_old_beginner: "Old Beginner Campaign"
campaign_beginner_description: "... στο οποίο μπορείτε να μάθετε τη μαγεία του προγραμματισμού"
campaign_dev: "Τυχαία δυσκολότερα επίπεδα"
campaign_dev_description: "... στο οποίο μπορείτε να μάθετε το περιβάλλον, ενώ κάνετε κάτι λίγο πιο δύσκολο."
choose_your_level: "Διάλεξε το επίπεδο σου" # The rest of this section is the old play view at /play-old and isn't very important.
adventurer_prefix: "Μπορείτε να μεταβείτε σε οποιοδήποτε επίπεδο κάτω, ή να συζητήσετε για τις πίστες στο "
adventurer_forum: "Φόρουμ του Adventurer"
adventurer_suffix: "."
campaign_old_beginner: "Παλαιότερη Εκστρατεία Αρχαρίων"
campaign_beginner_description: "... στην οποία μαθαίνετε τη μαγεία του προγραμματισμού."
campaign_dev: "Τυχαία Δυσκολότερα Επίπεδα"
campaign_dev_description: "... στα οποία μπορείτε να μάθετε το περιβάλλον, ενώ κάνετε κάτι λίγο δυσκολότερο."
campaign_multiplayer: "Αρένες Πολλαπλών Παικτών"
campaign_multiplayer_description: "... στο οποίο μπορείτε να προγραμματίσετε σώμα με σώμα έναντι άλλων παικτών."
# campaign_player_created: "Player-Created"
# campaign_player_created_description: "... in which you battle against the creativity of your fellow <a href=\"/contribute#artisan\">Artisan Wizards</a>."
# campaign_classic_algorithms: "Classic Algorithms"
# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science."
campaign_multiplayer_description: "... στις οποίες προγραμματίζετε σώμα-με-σώμα εναντίον άλλων παικτών."
campaign_player_created: "Δημιουργημένη-από-Παίκτες"
campaign_player_created_description: "... στην οποία μάχεστε ενάντια στην δημιουργικότητα των συναδέλφων <a href=\"/contribute#artisan\">Τεχνιτών Μάγων</a>."
campaign_classic_algorithms: "Κλασσικοί Αλγόριθμοι"
campaign_classic_algorithms_description: "... στο οποίο μαθαίνετε του πιο δημοφιλής αλγορίθμους της Επιστήμης της Πληροφορικής."
login:
sign_up: "Δημιούργησε Λογαριασμό"
sign_up: "Δημιουργία Λογαριασμού"
log_in: "Σύνδεση"
# logging_in: "Logging In"
logging_in: "Σύνδεση"
log_out: "Αποσύνδεση"
recover: "Κάντε ανάκτηση του λογαριασμού σας"
recover: "Ανάκτηση λογαριασμού"
signup:
create_account_title: "Δημιουργία λογαριασμού για αποθήκευση της προόδου"
description: "Είναι δωρεάν. Απλώς χρειάζεται να έχεις έναν λογαριασμό και θα είσαι έτοιμος να παίξεις:"
email_announcements: "Λαμβάνετε ανακοινώσεις μέσω e-mail"
create_account_title: "Δημιουργία λογαριασμού για Αποθήκευση της Προόδου"
description: "Είναι δωρεάν. Απλώς χρειάζεται λίγα πράγματα και θα είσαι έτοιμος να παίξεις:"
email_announcements: "Λαμβάνετε ανακοινώσεις μέσω email"
coppa: "13+ ή Εκτός Αμερικής "
coppa_why: "(Γιατί;)"
creating: "Δημιουργία λογαριασμού"
creating: "Δημιουργία Λογαριασμού..."
sign_up: "Εγγραφή"
log_in: "Σύνδεση με κωδικό"
social_signup: "Ή, μπορείς να συνδεθείς μέσω του Facebook ή του G+:"
# required: "You need to log in before you can go that way."
social_signup: "Ή, μπορείς να συνδεθείς μέσω Facebook ή G+:"
required: "Θα πρέπει να συνδεθείτε πριν πάτε προς τα εκεί."
recover:
recover_account_title: "Κάντε ανάκτηση του λογαριασμού σας"
send_password: "Αποστολή κωδικού ανάκτησης"
# recovery_sent: "Recovery email sent."
recover_account_title: "Ανάκτηση λογαριασμού"
send_password: "Αποστολή Κωδικού Ανάκτησης"
recovery_sent: "Email ανάκτησης στάλθηκε."
# items:
# armor: "Armor"
# hands: "Hands"
# accessories: "Accessories"
# books: "Books"
# minions: "Minions"
# misc: "Misc"
items:
armor: "Πανοπλία"
hands: "Χέρια"
accessories: "Εξαρτήματα"
books: "Βιβλία"
minions: "Minions"
misc: "Διάφορα"
common:
loading: "Φορτώνει..."
@ -182,13 +182,13 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
play_level:
done: "Έτοιμο"
home: "Αρχική"
# skip: "Skip"
# game_menu: "Game Menu"
skip: "Παράλειψη"
game_menu: "Μενού Παιχνιδιού"
guide: "Οδηγός"
# restart: "Restart"
restart: "Επανεκκίνηση"
goals: "Στόχοι"
# goal: "Goal"
# success: "Success!"
goal: "Στόχος"
success: "Επιτυχία!"
# incomplete: "Incomplete"
# timed_out: "Ran out of time"
# failing: "Failing"
@ -267,7 +267,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
# tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
# tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
# tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
customize_wizard: "Προσαρμόστε τον Μάγο"
customize_wizard: "Προσαρμογή Μάγου"
game_menu:
# inventory_tab: "Inventory"
@ -363,9 +363,9 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
contribute_prefix: "Αν σας ενδιαφέρει να βοηθήσετε, ελέγξτε την "
contribute_page: "σελίδα συνεισφοράς"
contribute_suffix: "!"
forum_prefix: "Για οτιδήποτε δημόσιο, δοκίμασε "
forum_prefix: "Για οτιδήποτε δημόσιο, παρακαλούμε δοκίμαστε "
forum_page: "το φόρουμ μας"
# forum_suffix: " instead."
forum_suffix: ""
send: "Αποστολή σχολίων"
# contact_candidate: "Contact Candidate" # Deprecated
# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." # Deprecated
@ -379,7 +379,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
upload_picture: "Ανέβασμα φωτογραφίας"
password_tab: "Κωδικός"
emails_tab: "Emails"
# admin: "Admin"
admin: "Διαχειριστής"
new_password: "Καινούργιος Κωδικός"
new_password_verify: " Επαλήθευση Κωδικού"
email_subscriptions: "Συνδρομές Email"
@ -401,7 +401,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
error_saving: "Σφάλμα αποθήκευσης"
saved: "Οι αλλαγές αποθηκεύτηκαν"
password_mismatch: "Οι κωδικοί δεν ταιριάζουν"
# password_repeat: "Please repeat your password."
password_repeat: "Παρακαλώ επαναλάβετε τον κωδικό σας."
# job_profile: "Job Profile" # Rest of this section (the job profile stuff and wizard stuff) is deprecated
# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks."
# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job."
@ -874,7 +874,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
color: "Χρώμα"
group: "Ομάδα"
clothes: "Ρούχα"
# trim: "Trim"
trim: "Τελείωμα"
cloud: "Σύννεφο"
team: "Ομάδα"
spell: "Ξόρκι"
@ -888,9 +888,9 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
edit_profile: "Επεξεργασία προφίλ"
done_editing: "Τέλος επεξεργασίας"
profile_for_prefix: "Προφίλ για "
# profile_for_suffix: ""
# featured: "Featured"
# not_featured: "Not Featured"
profile_for_suffix: ""
featured: "Προτεινόμενα"
not_featured: "Μη Προτεινόμενα"
looking_for: "Αναζήτηση για:"
last_updated: "Τελευταία ενημερώθηκε:"
contact: "Επικοινωνία"

View file

@ -205,6 +205,7 @@
victory_return_to_ladder: "Return to Ladder"
victory_play_next_level: "Play Next Level" # Only in old-style levels.
victory_play_continue: "Continue"
victory_saving_progress: "Saving Progress"
victory_go_home: "Go Home" # Only in old-style levels.
victory_review: "Tell us more!" # Only in old-style levels.
victory_hour_of_code_done: "Are You Done?"

View file

@ -27,12 +27,12 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
profile: "Perfil"
stats: "Estatísticas"
code: "Código"
admin: "Administrador" # Only shows up when you are an admin
admin: "Admin" # Only shows up when you are an admin
home: "Início"
contribute: "Contribuir"
legal: "Legal"
about: "Sobre"
contact: "Contacte"
contact: "Contactar"
twitter_follow: "Seguir"
teachers: "Professores"
@ -216,9 +216,9 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
tome_cast_button_castable: "Lançar Feitiço" # Temporary, if tome_cast_button_run isn't translated.
tome_cast_button_casting: "A Lançar" # Temporary, if tome_cast_button_running isn't translated.
tome_cast_button_cast: "Feitiço Lançado" # Temporary, if tome_cast_button_ran isn't translated.
tome_cast_button_run: "Correr"
tome_cast_button_running: "A Correr"
tome_cast_button_ran: "Corrido"
tome_cast_button_run: "Executar"
tome_cast_button_running: "A Executar"
tome_cast_button_ran: "Executado"
tome_submit_button: "Submeter"
tome_reload_method: "Recarregar o código original para este método" # Title text for individual method reload button.
tome_select_method: "Selecionar um método"
@ -545,9 +545,9 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
# 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: "Atributos da Classe"
# 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."
archmage_attribute_1_pref: "Conhecimento em "
archmage_attribute_1_suf: ", ou vontade de aprender. A maioria do nosso código está nesta linguagem. Se és um fã de Ruby ou Python, vais sentir-te em casa. É igual ao JavaScript, mas com uma sintaxe melhor."
archmage_attribute_2: "Alguma experiência em programação e iniciativa pessoal. Nós ajudamos-te a orientares-te, mas não podemos gastar muito tempo a treinar-te."
how_to_join: "Como Me Junto"
join_desc_1: "Qualquer um pode ajudar! Só tens de conferir o nosso "
join_desc_2: "para começares, e assinalar a caixa abaixo para te declarares um bravo Arcomago e receberes as últimas notícias por e-mail. Queres falar sobre o que fazer ou como te envolveres mais profundamente no projeto? "
@ -591,10 +591,10 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
more_about_scribe: "Aprende Mais Sobre Tornares-te um Escrivão"
scribe_subscribe_desc: "Receber e-mails sobre anúncios relativos à escrita de artigos."
# diplomat_summary: "There is a large interest in CodeCombat in other countries that do not speak English! We are looking for translators who are willing to spend their time translating the site's corpus of words so that CodeCombat is accessible across the world as soon as possible. If you'd like to help getting CodeCombat international, then this class is for you."
# diplomat_introduction_pref: "So, if there's one thing we learned from the "
# diplomat_launch_url: "launch in October"
# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you."
# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!"
diplomat_introduction_pref: "Portanto, se há uma coisa que aprendemos com o nosso "
diplomat_launch_url: "lançamento em Outubro"
diplomat_introduction_suf: "é que há um interesse considerável no CodeCombat noutros países! Estamos a construir um exército de tradutores dispostos a transformar um conjunto de palavras noutro conjuto de palavras, para conseguir que o CodeCombat fique o mais acessível quanto posível em todo o mundo. Se gostas de dar espreitadelas a conteúdos futuros e disponibilizar estes níveis para os teus colegas nacionais o mais depressa possível, então esta classe talvez seja para ti."
diplomat_attribute_1: "Fluência em Inglês e no idioma para o qual gostarias de traduzir. Quando são tentadas passar ideias complicadas, é importante uma excelente compreensão das duas!"
diplomat_join_pref_github: "Encontra o ficheiro 'locale' do teu idioma "
diplomat_github_url: "no GitHub"
diplomat_join_suf_github: ", edita-o online e submete um 'pull request'. Assinala ainda esta caixa abaixo para ficares atualizado em relação a novos desenvolvimentos da internacionalização!"
@ -814,16 +814,16 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
# recruitment_description_ending: "the site remains free and everybody's happy. That's the plan."
copyrights_title: "Direitos Autorais e Licensas"
contributor_title: "Contrato de Licença do Contribuinte (CLA)"
# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our"
contributor_description_prefix: "Todas as contribuições, tanto no sítio como no nosso repositório GitHub, estão sujeitas ao nosso"
cla_url: "CLA"
# contributor_description_suffix: "to which you should agree before contributing."
contributor_description_suffix: "com o qual deves concordar antes de contribuir."
code_title: "Código - MIT"
# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the"
mit_license_url: "licença do MIT"
# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels."
art_title: "Arte/Música - Creative Commons "
# art_description_prefix: "All common content is available under the"
# cc_license_url: "Creative Commons Attribution 4.0 International License"
art_description_prefix: "Todos os conteúdos comuns estão disponíveis à luz da"
cc_license_url: "Licença 'Creative Commons Attribution 4.0 International'"
# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:"
art_music: "Música"
art_sound: "Som"
@ -989,8 +989,8 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
player_code: "Código do Jogador"
employers:
# deprecation_warning_title: "Sorry, CodeCombat is not recruiting right now."
# deprecation_warning: "We are focusing on beginner levels instead of finding expert developers for the time being."
deprecation_warning_title: "Desculpa, o CodeCombat não está a recrutar por agora."
deprecation_warning: "Atualmente, estamos a focar-nos em níveis para iniciantes, em vez de tentar encontar desenvolvedores peritos."
hire_developers_not_credentials: "Não contrates cartas de recomendação, mas sim programadores." # We are not actively recruiting right now, so there's no need to add new translations for the rest of this section.
get_started: "Começar"
already_screened: "Nós já selecionamos tecnicamente todos os nossos candidatos"

View file

@ -108,12 +108,12 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
# recovery_sent: "Recovery email sent."
items:
armor: "Броня" #"Armor"
hands: "Руки" #"Hands"
accessories: "Аксессуары" #"Accessories"
books: "Книги" #"Books"
armor: "Броня"
hands: "Руки"
accessories: "Аксессуары"
books: "Книги"
# minions: "Minions"
misc: "Разное" #"Misc"
misc: "Разное"
common:
loading: "Загрузка..."
@ -277,7 +277,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
# guide_tab: "Guide"
multiplayer_tab: "Мультиплеер"
# inventory_caption: "Equip your hero"
choose_hero_caption: "Выбор героя, языка" #"Choose hero, language"
choose_hero_caption: "Выбор героя, языка"
# save_load_caption: "... and view history"
# options_caption: "Configure settings"
# guide_caption: "Docs and tips"
@ -287,13 +287,13 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
# choose_inventory: "Equip Items"
choose_hero:
choose_hero: "Выберите героя" # "Choose Your Hero"
programming_language: "Язык программирования" # "Programming Language"
programming_language_description: "Какой язык программирования вы хотите использовать?" # "Which programming language do you want to use?"
status: "Статус" # "Status"
weapons: "Оружие" # "Weapons"
health: "Жизнь" # "Health"
speed: "Скорость" # "Speed"
choose_hero: "Выберите героя"
programming_language: "Язык программирования"
programming_language_description: "Какой язык программирования вы хотите использовать?"
status: "Статус"
weapons: "Оружие"
health: "Жизнь"
speed: "Скорость"
save_load:
granularity_saved_games: "Сохранено"

View file

@ -670,29 +670,29 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese
# rules: "Rules"
# winners: "Winners"
# user:
user:
# stats: "Stats"
# singleplayer_title: "Singleplayer Levels"
# multiplayer_title: "Multiplayer Levels"
# achievements_title: "Achievements"
# last_played: "Last Played"
# status: "Status"
# status_completed: "Completed"
# status_unfinished: "Unfinished"
# no_singleplayer: "No Singleplayer games played yet."
# no_multiplayer: "No Multiplayer games played yet."
# no_achievements: "No Achievements earned yet."
# favorite_prefix: "Favorite language is "
# favorite_postfix: "."
singleplayer_title: "單人遊戲等級"
multiplayer_title: "多人遊戲等級"
achievements_title: "成就"
last_played: "最後游玩"
status: "狀態"
status_completed: "已完成"
status_unfinished: "未完成"
no_singleplayer: "還沒有玩過單人遊戲."
no_multiplayer: "還沒有玩過多 人遊戲."
no_achievements: "還沒有取得成就."
favorite_prefix: "語言喜好為"
favorite_postfix: "."
# achievements:
achievements:
# last_earned: "Last Earned"
# amount_achieved: "Amount"
# achievement: "Achievement"
# category_contributor: "Contributor"
amount_achieved: "數量"
achievement: "成就"
category_contributor: "貢獻者"
# category_miscellaneous: "Miscellaneous"
# category_levels: "Levels"
# category_undefined: "Uncategorized"
category_levels: "等級"
category_undefined: "未定義"
# current_xp_prefix: ""
# current_xp_postfix: " in total"
# new_xp_prefix: ""
@ -701,9 +701,9 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese
# left_xp_infix: " until level "
# left_xp_postfix: ""
# account:
# recently_played: "Recently Played"
# no_recent_games: "No games played during the past two weeks."
account:
recently_played: "最近玩過"
no_recent_games: "在過去兩個星期沒有遊戲玩過。"
# loading_error:
# could_not_load: "Error loading from server"

View file

@ -1,2 +1,188 @@
#hero-victory-modal
color: red
//- Header
.background-wrapper
background: url("/images/pages/play/level/modal/victory_modal_background.png")
height: 650px
width: 550px
#victory-header
display: block
margin: 40px auto 0
.modal-header
height: 110px
border: none
//- Achievement panels
.modal-body
padding: 0 20px
.achievement-panel
background: url("/images/pages/play/level/modal/achievement_plate.png")
width: 451px
height: 144px
margin: 5px auto
position: relative
-webkit-transition-duration: 1s
-moz-transition-duration: 1s
-o-transition-duration: 1s
transition-duration: 1s
-webkit-filter: grayscale(100%)
-moz-filter: grayscale(100%)
-o-filter: grayscale(100%)
filter: grayscale(100%)
&.earned
-webkit-filter: none
-moz-filter: none
-o-filter: none
filter: none
.achievement-description
position: absolute
text-align: center
left: 95px
right: 98px
top: 10px
color: white
white-space: nowrap
overflow: hidden
text-overflow: ellipsis
.achievement-rewards
position: absolute
left: 25px
right: 23px
top: 41px
bottom: 18px
//- Reward panels
.reward-panel
background: url("/images/pages/play/level/modal/reward_plate.png")
background: url("/images/pages/play/level/modal/reward_plate.png")
width: 77px
height: 85px
float: left
margin: 0 1.8px
position: relative
.reward-image-container
top: 8px
left: 11px
height: 55px
width: 56px
position: relative
-webkit-transform: scale(0, 0)
-moz-transform: scale(0, 0)
-o-transform: scale(0, 0)
transform: scale(0, 0)
-webkit-transition-duration: 0.5s
-moz-transition-duration: 0.5s
-o-transition-duration: 0.5s
transition-duration: 0.5s
&.show
-webkit-transform: scale(1, 1)
-moz-transform: scale(1, 1)
-o-transform: scale(1, 1)
transform: scale(1, 1)
img
margin: 0
position: absolute
top: 50%
left: 50%
margin-right: -50%
-webkit-transition-duration: 0.5s
-moz-transition-duration: 0.5s
-o-transition-duration: 0.5s
transition-duration: 0.5s
-webkit-transform: translate(-50%, -50%)
-moz-transform: translate(-50%, -50%)
-o-transform: translate(-50%, -50%)
transform: translate(-50%, -50%)
max-width: 56px
max-height: 55px
.reward-text
position: absolute
bottom: 6px
left: 4px
right: 3px
height: 15px
text-align: center
color: white
font-weight: bold
font-size: 12px
white-space: nowrap
overflow: hidden
text-overflow: ellipsis
//- Pulse effect
@-webkit-keyframes pulse
from
-webkit-transform: translate(-50%, -50%) scale(1.0)
50%
-webkit-transform: translate(-50%, -50%) scale(1.3)
to
-webkit-transform: translate(-50%, -50%) scale(1.0)
@-moz-keyframes pulse
from
-moz-transform: translate(-50%, -50%) scale(1.0)
50%
-moz-transform: translate(-50%, -50%) scale(1.3)
to
-moz-transform: translate(-50%, -50%) scale(1.0)
@-o-keyframes pulse
from
-o-transform: translate(-50%, -50%) scale(1.0)
50%
-o-transform: translate(-50%, -50%) scale(1.3)
to
-o-transform: translate(-50%, -50%) scale(1.0)
@keyframes pulse
from
transform: translate(-50%, -50%) scale(1.0)
50%
transform: translate(-50%, -50%) scale(1.3)
to
transform: translate(-50%, -50%) scale(1.0)
.pulse
-webkit-animation: pulse 0.5s infinite
-moz-animation: pulse 0.5s infinite
-o-animation: pulse 0.5s infinite
animation: pulse 0.5s infinite
//- Footer
.modal-content
height: 650px // so the footer appears at the bottom
.modal-footer
position: absolute
bottom: 20px
left: 20px
right: 20px
#totals
color: white

View file

@ -15,7 +15,6 @@
strong.tip(data-i18n='play_level.tip_guide_exists') Click the guide at the top of the page for useful info.
strong.tip(data-i18n='play_level.tip_open_source') CodeCombat is 100% open source!
strong.tip(data-i18n='play_level.tip_beta_launch') CodeCombat launched its beta in October, 2013.
strong.tip(data-i18n='play_level.tip_js_beginning') JavaScript is just the beginning.
strong.tip(data-i18n='play_level.tip_think_solution') Think of the solution, not the problem.
strong.tip(data-i18n='play_level.tip_theory_practice') In theory there is no difference between theory and practice; in practice there is. - Yogi Berra
strong.tip(data-i18n='play_level.tip_error_free') There are two ways to write error-free programs; only the third one works. - Alan Perlis

View file

@ -1,34 +1,54 @@
extends /templates/modal/modal_base
block modal-header-content
h3
span(data-i18n="play_level.victory_title_prefix")
span= levelName
span(data-i18n="play_level.victory_title_suffix") Complete
img(src="/images/pages/play/level/modal/victory_word.png")#victory-header
block modal-body-content
h4 Achievements Unlocked
for achievement in achievements
.panel
img(src=achievement.getImageURL())
h5= achievement.get('name')
p= achievement.get('description')
if achievement.completed
strong Completed
else
strong Incomplete
p Earned #{achievement.get('worth')} xp.
- var animate = achievement.completed && !achievement.completedAWhileAgo
.achievement-panel(class=achievement.completedAWhileAgo ? 'earned' : '' data-achievement-id=achievement.id data-animate=animate)
- var rewards = achievement.get('rewards') || {};
if rewards.gems
p Earned #{achievement.get('rewards').gems} gems.
if rewards.heroes
for hero in rewards.heroes
- var hero = thangTypes[hero];
img(src=hero.getPortraitURL())
if rewards.items
for item in rewards.items
- var item = thangTypes[item];
img(src=item.getPortraitURL())
div.achievement-description= achievement.get('description')
div.achievement-rewards
- var worth = achievement.get('worth', true);
if worth
.reward-panel.numerical(data-number=worth, data-number-unit='xp')
.reward-image-container(class=animate?'':'show')
img(src="/images/pages/play/level/modal/reward_icon_xp.png")
.reward-text= animate ? 'x0' : '+'+worth
if rewards.gems
.reward-panel.numerical(data-number=rewards.gems, data-number-unit='gem')
.reward-image-container(class=animate?'':'show')
img(src="/images/pages/play/level/modal/reward_icon_gems.png")
.reward-text= animate ? 'x0' : '+'+rewards.gems
if rewards.heroes
for hero in rewards.heroes
- var hero = thangTypes[hero];
.reward-panel
.reward-image-container(class=animate?'':'show')
img(src=hero.getPortraitURL())
.reward-text= hero.get('name')
if rewards.items
for item in rewards.items
- var item = thangTypes[item];
.reward-panel
.reward-image-container(class=animate?'':'show')
img(src=item.getPortraitURL())
.reward-text= item.get('name')
block modal-footer-content
| footer
div#totals.pull-left
span.spr Experience Gained:
span#xp-total +0
br
span.spr Gems Gained:
span#gem-total +0
button.btn.btn-warning.hide#saving-progress-label(disabled, data-i18n="play_level.victory_saving_progress") Saving Progress
a.btn.btn-success.world-map-button.hide#continue-button(href="/play-hero", data-dismiss="modal", data-i18n="play_level.victory_play_continue") Continue

View file

@ -206,10 +206,6 @@ module.exports = class PlayLevelView extends RootView
@initVolume()
@listenTo(@session, 'change:multiplayer', @onMultiplayerChanged)
# testing
# modal = new HeroVictoryModal({session: @session, level: @level})
# @openModalView(modal)
@originalSessionState = $.extend(true, {}, @session.get('state'))
@register()
@controlBar.setBus(@bus)
@ -459,9 +455,8 @@ module.exports = class PlayLevelView extends RootView
showVictory: ->
options = {level: @level, supermodel: @supermodel, session: @session}
# ModalClass = if @level.get('type', true) is 'hero' then HeroVictoryModal else VictoryModal
# victoryModal = new ModalClass(options)
victoryModal = new VictoryModal(options)
ModalClass = if @level.get('type', true) is 'hero' then HeroVictoryModal else VictoryModal
victoryModal = new ModalClass(options)
@openModalView(victoryModal)
if me.get('anonymous')
window.nextLevelURL = @getNextLevelURL() # Signup will go here on completion instead of reloading.

View file

@ -1,14 +1,16 @@
ModalView = require 'views/kinds/ModalView'
template = require 'templates/play/level/modal/hero-victory-modal'
Achievement = require 'models/Achievement'
EarnedAchievement = require 'models/EarnedAchievement'
CocoCollection = require 'collections/CocoCollection'
LocalMongo = require 'lib/LocalMongo'
utils = require 'lib/utils'
ThangType = require 'models/ThangType'
module.exports = class UnnamedView extends ModalView
module.exports = class HeroVictoryModal extends ModalView
id: 'hero-victory-modal'
template: template
closeButton: false
constructor: (options) ->
super(options)
@ -21,27 +23,123 @@ module.exports = class UnnamedView extends ModalView
@thangTypes = {}
@achievements = @supermodel.loadCollection(achievements, 'achievements').model
@listenToOnce @achievements, 'sync', @onAchievementsLoaded
@readyToContinue = false
onAchievementsLoaded: ->
thangTypeOriginals = []
achievementIDs = []
for achievement in @achievements.models
rewards = achievement.get('rewards')
console.log 'rewards', rewards
thangTypeOriginals.push rewards.heroes or []
thangTypeOriginals.push rewards.items or []
achievement.completed = LocalMongo.matchesQuery(@session.attributes, achievement.get('query'))
achievementIDs.push(achievement.id) if achievement.completed
thangTypeOriginals = _.uniq _.flatten thangTypeOriginals
console.log 'thang type originals?', thangTypeOriginals
for thangTypeOriginal in thangTypeOriginals
thangType = new ThangType()
thangType.url = "/db/thang.type/#{thangTypeOriginal}/version"
thangType.project = ['original', 'rasterIcon']
thangType.project = ['original', 'rasterIcon', 'name']
@thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model
if achievementIDs.length
url = "/db/earned_achievement?view=get-by-achievement-ids&achievementIDs=#{achievementIDs.join(',')}"
earnedAchievements = new CocoCollection([], {
url: url
model: EarnedAchievement
})
earnedAchievements.sizeShouldBe = achievementIDs.length
res = @supermodel.loadCollection(earnedAchievements, 'earned_achievements')
@earnedAchievements = res.model
@listenTo @earnedAchievements, 'sync', ->
if @earnedAchievements.models.length < @earnedAchievements.sizeShouldBe
@earnedAchievements.fetch()
else
@listenToOnce me, 'sync', ->
@readyToContinue = true
@updateSavingProgressStatus()
me.fetch() unless me.loading
else
@readyToContinue = true
getRenderData: ->
c = super()
c.levelName = utils.i18n @level.attributes, 'name'
earnedAchievementMap = _.indexBy(@earnedAchievements?.models or [], (ea) -> ea.get('achievement'))
for achievement in @achievements.models
achievement.completed = LocalMongo.matchesQuery(@session.attributes, achievement.get('query'))
earnedAchievement = earnedAchievementMap[achievement.id]
if earnedAchievement
achievement.completedAWhileAgo = new Date() - Date.parse(earnedAchievement.get('created')) > 30 * 1000
c.achievements = @achievements.models
# for testing the three states
# if c.achievements.length
# c.achievements = [c.achievements[0].clone(), c.achievements[0].clone(), c.achievements[0].clone()]
# for achievement, index in c.achievements
# achievement.completed = index > 0
# achievement.completedAWhileAgo = index > 1
c.thangTypes = @thangTypes
return c
return c
afterRender: ->
super()
return unless @supermodel.finished()
@updateSavingProgressStatus()
complete = _.once(_.bind(@beginAnimateNumbers, @))
@animatedPanels = $()
panels = @$el.find('.achievement-panel')
for panel in panels
panel = $(panel)
continue unless panel.data('animate')
@animatedPanels = @animatedPanels.add(panel)
panel.delay(500)
panel.queue(->
$(this).addClass('earned') # animate out the grayscale
$(this).dequeue()
)
panel.delay(500)
panel.queue(->
$(this).find('.reward-image-container').addClass('show')
$(this).dequeue()
)
panel.delay(500)
panel.queue(-> complete())
@animationComplete = !@animatedPanels.length
beginAnimateNumbers: ->
@numericalItemPanels = _.map(@animatedPanels.find('.numerical'), (panel) -> {
number: $(panel).data('number')
textEl: $(panel).find('.reward-text')
rootEl: $(panel)
unit: $(panel).data('number-unit')
})
# TODO: mess with this more later. Doesn't seem to work, often times will pulse background red rather than animate
# itemPanel.rootEl.find('.reward-image-container img').addClass('pulse') for itemPanel in @numericalItemPanels
@numberAnimationStart = new Date()
@totalXP = 0
@totalXP += panel.number for panel in @numericalItemPanels when panel.unit is 'xp'
@totalGems = 0
@totalGems += panel.number for panel in @numericalItemPanels when panel.unit is 'gem'
@gemEl = $('#gem-total')
@XPEl = $('#xp-total')
@numberAnimationInterval = setInterval(@tickNumberAnimation, 15 / 1000)
tickNumberAnimation: =>
pct = Math.min(1, (new Date() - @numberAnimationStart) / 1500)
panel.textEl.text('+'+parseInt(panel.number*pct)) for panel in @numericalItemPanels
@XPEl.text('+'+parseInt(@totalXP * pct))
@gemEl.text('+'+parseInt(@totalGems * pct))
@endAnimateNumbers() if pct is 1
endAnimateNumbers: ->
@$el.find('.pulse').removeClass('pulse')
clearInterval(@numberAnimationInterval)
@animationComplete = true
@updateSavingProgressStatus()
updateSavingProgressStatus: ->
return unless @animationComplete
@$el.find('#saving-progress-label').toggleClass('hide', @readyToContinue)
@$el.find('#continue-button').toggleClass('hide', !@readyToContinue)

View file

@ -10,6 +10,7 @@ module.exports = class Problem
@buildAnnotation()
@buildAlertView() if withAlert
@buildMarkerRange() if isCast
Backbone.Mediator.publish("problem:problem-created", line:@annotation.row, text: @annotation.text) if application.isIPadApp
@saveUserCodeProblem() if isCast
destroy: ->

View file

@ -640,6 +640,7 @@ module.exports = class SpellView extends CocoView
@aceSession.removeGutterDecoration start.row, @decoratedGutter[start.row] if @decoratedGutter[start.row] isnt ''
@aceSession.addGutterDecoration start.row, clazz
@decoratedGutter[start.row] = clazz
Backbone.Mediator.publish("tome:highlight-line", line:start.row) if application.isIPadApp
@debugView?.setVariableStates {} unless gotVariableStates
null

View file

@ -0,0 +1,37 @@
// Finds all sessions for given usernames and grab all the code by level.
var usernames = ['Nick'];
usernames.sort(Math.random);
var users = db.users.find({name: {$in: usernames}, anonymous: false}).toArray();
var userIDs = [];
for (var userIndex = 0; userIndex < users.length; ++userIndex) {
userIDs.push('' + users[userIndex]._id);
}
var sessions = db.level.sessions.find({creator: {$in: userIDs}}).toArray();
var levels = {};
for (var i = 0; i < sessions.length; ++i) {
var session = sessions[i];
if (!session) continue;
if (!session.code || !session.levelName) continue;
var userCode = {};
if (session.teamSpells && session.team) {
for (spellName in session.teamSpells[session.team]) {
var spellNameElements = spellName.split('/');
var thangName = spellNameElements[0];
var spellName = spellNameElements[1];
if (thangName && spellName && session.code[thangName] && session.code[thangName][spellName]) {
userCode[thangName] = session.code[thangName] || {};
userCode[thangName][spellName] = session.code[thangName][spellName];
}
}
}
else
userCode = session.code;
var anonymizedUsername = 'user' + userIDs.indexOf(session.creator);
var codeLanguage = session.codeLanguage || 'javascript';
levels[codeLanguage] = levels[codeLanguage] || {};
levels[codeLanguage][session.levelName] = levels[codeLanguage][session.levelName] || {};
levels[codeLanguage][session.levelName][anonymizedUsername] = userCode;
}
levels;

View file

@ -14,6 +14,26 @@ class EarnedAchievementHandler extends Handler
hasAccess: (req) ->
req.method is 'GET' # or req.user.isAdmin()
get: (req, res) ->
return @getByAchievementIDs(req, res) if req.query.view is 'get-by-achievement-ids'
super(arguments...)
getByAchievementIDs: (req, res) ->
query = { user: req.user._id+''}
ids = req.query.achievementIDs
if (not ids) or (ids.length is 0)
return @sendBadInputError(res, 'For a get-by-achievement-ids request, need to provide ids.')
ids = ids.split(',')
for id in ids
if not Handler.isID(id)
return @sendBadInputError(res, "Not a MongoDB ObjectId: #{id}")
query.achievement = {$in: ids}
EarnedAchievement.find query, (err, earnedAchievements) ->
return @sendDatabaseError(res, err) if err
res.send(earnedAchievements)
recalculate: (req, res) ->
onSuccess = (data) => log.debug 'Finished recalculating achievements'
if 'achievements' of req.body # Support both slugs and IDs separated by commas