Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-10-02 01:20:54 -07:00
commit 228cffde8c
32 changed files with 150 additions and 72 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 KiB

View file

@ -10,5 +10,6 @@ module.exports = class ThangNamesCollection extends CocoCollection
fetch: (options) ->
options ?= {}
_.extend options, {type:'POST', data:{ids:@ids}}
method = if application.isIPadApp then 'GET' else 'POST' # Not sure why this was required that one time.
_.extend options, {type: method, data: {ids: @ids}}
super(options)

View file

@ -105,7 +105,8 @@ watchForErrors = ->
#msg += "\nColumn: #{col}" if col?
#msg += "\nError: #{error}" if error?
#msg += "\nStack: #{stack}" if stack = error?.stack
noty text: message, layout: 'topCenter', type: 'error', killer: false, timeout: 5000, dismissQueue: true, maxVisible: 3, callback: {onClose: -> --currentErrors}
unless webkit?.messageHandlers # Don't show these notys on iPad
noty text: message, layout: 'topCenter', type: 'error', killer: false, timeout: 5000, dismissQueue: true, maxVisible: 3, callback: {onClose: -> --currentErrors}
Backbone.Mediator.publish 'application:error', message: msg # For iOS app
window.addIPadSubscription = (channel) ->

View file

@ -521,12 +521,8 @@ module.exports = Surface = class Surface extends CocoClass
newHeight = newWidth / aspectRatio
return unless newWidth > 0 and newHeight > 0
return if newWidth is oldWidth and newHeight is oldHeight
##if InstallTrigger? # Firefox rendering performance goes down as canvas size goes up
## newWidth = Math.min 924, newWidth
## newHeight = Math.min 589, newHeight
#@normalCanvas.width newWidth
#@normalCanvas.height newHeight
scaleFactor = if application.isIPadApp then 2 else 1 # Retina
#scaleFactor = if application.isIPadApp then 2 else 1 # Retina
scaleFactor = 1
@normalCanvas.add(@webGLCanvas).attr width: newWidth * scaleFactor, height: newHeight * scaleFactor
# Cannot do this to the webGLStage because it does not use scaleX/Y.

View file

@ -129,10 +129,11 @@ class CocoModel extends Backbone.Model
errorMessage = "Error saving #{@get('name') ? @type()}"
console.log 'going to log an error message'
console.warn errorMessage, res.responseJSON
try
noty text: "#{errorMessage}: #{res.status} #{res.statusText}", layout: 'topCenter', type: 'error', killer: false, timeout: 10000
catch notyError
console.warn "Couldn't even show noty error for", error, "because", notyError
unless webkit?.messageHandlers # Don't show these notys on iPad
try
noty text: "#{errorMessage}: #{res.status} #{res.statusText}", layout: 'topCenter', type: 'error', killer: false, timeout: 10000
catch notyError
console.warn "Couldn't even show noty error for", error, "because", notyError
options.success = options.error = null # So the callbacks can be garbage-collected.
@trigger 'save', @
return super attrs, options

View file

@ -7,6 +7,8 @@ $equippedWidth: 450px
$itemSlotMargin: 5px
$itemSlotSize: ($equippedWidth - 6 * 2 * $itemSlotMargin) / 6
$itemSlotSizeWithMargin: $itemSlotSize + 2 * $itemSlotMargin
$itemSlotBorderWidth: 2px
$itemSlotInnerWidth: $itemSlotSize - 2 * $itemSlotBorderWidth
$heroContainerBottomMargin: 10px
$heroContainerWidth: 4 * $itemSlotSizeWithMargin
$heroContainerHeight: $inventoryHeight - 2 * $itemSlotSizeWithMargin - $heroContainerBottomMargin
@ -76,18 +78,63 @@ $stashWidth: $totalWidth - $equippedWidth - $stashMargin
width: 100%
height: 100%
background-size: cover
border: 2px solid #888
@include opacity(0.75)
border: $itemSlotBorderWidth solid #888
@include opacity(0.4)
background-image: url(/images/pages/game-menu/slot-icons.png)
&[data-slot="waist"], &[data-slot="pet"], &[data-slot="minion"], &[data-slot="misc-1"]
// My spooging of the other placeholders had them dimmed; these didn't.
.placeholder
@include opacity(0.35)
border-color: black
&.selected
&[data-slot="waist"], &[data-slot="pet"], &[data-slot="minion"], &[data-slot="misc-1"]
.placeholder
border-color: #28f
&[data-slot="misc-1"] .placeholder
background-position-x: -0 * $itemSlotInnerWidth
&[data-slot="minion"] .placeholder
background-position-x: -1 * $itemSlotInnerWidth
&[data-slot="programming-book"] .placeholder
background-position-x: -2 * $itemSlotInnerWidth
&[data-slot="spellbook"] .placeholder
background-position-x: -3 * $itemSlotInnerWidth
&[data-slot="misc-0"] .placeholder
background-position-x: -4 * $itemSlotInnerWidth
&[data-slot="wrists"] .placeholder
background-position-x: -5 * $itemSlotInnerWidth
&[data-slot="left-ring"] .placeholder
background-position-x: -6 * $itemSlotInnerWidth
&[data-slot="right-ring"] .placeholder
background-position-x: -7 * $itemSlotInnerWidth
&[data-slot="torso"] .placeholder
background-position-x: -8 * $itemSlotInnerWidth
&[data-slot="feet"] .placeholder
background-position-x: -9 * $itemSlotInnerWidth
&[data-slot="neck"] .placeholder
background-position-x: -10 * $itemSlotInnerWidth
&[data-slot="waist"] .placeholder
background-position-x: -11 * $itemSlotInnerWidth
&[data-slot="eyes"] .placeholder
background-position-x: -12 * $itemSlotInnerWidth
&[data-slot="head"] .placeholder
background-position-x: -13 * $itemSlotInnerWidth
&[data-slot="pet"] .placeholder
background-position-x: -14 * $itemSlotInnerWidth
&[data-slot="gloves"] .placeholder
background-position-x: -15 * $itemSlotInnerWidth
&[data-slot="left-hand"] .placeholder
background-position-x: -16 * $itemSlotInnerWidth
&[data-slot="right-hand"] .placeholder
background-position-x: -17 * $itemSlotInnerWidth
.item-container
position: absolute

View file

@ -48,3 +48,11 @@
.modal-header
text-align: center
body.ipad #level-victory-modal
.share-buttons
display: none
.modal-body
font-size: 30px
font-family: Bangers

View file

@ -1,11 +1,13 @@
@import "app/styles/mixins"
@import "app/styles/bootstrap/variables"
$mapHeight: 1536
$forestMapWidth: 2500
$forestMapHeight: 1536
$dungeonMapWidth: 2350
$forestMapSeaBackground: #71bad0
$dungeonMapCaveBackground: rgb(54, 43, 34)
$levelDotWidth: 2%
$levelDotHeight: $levelDotWidth * $forestMapWidth / $forestMapHeight
$levelDotHeight: $levelDotWidth * $forestMapWidth / $mapHeight
$levelDotZ: $levelDotHeight * 0.25
$levelDotHoverZ: $levelDotZ * 2
$levelDotShadowWidth: 0.8 * $levelDotWidth
@ -28,7 +30,12 @@ $gameControlMargin: 30px
#world-map-view
width: 100%
height: 100%
background-color: $forestMapSeaBackground
&.forest
background-color: $forestMapSeaBackground
&.dungeon
background-color: $dungeonMapCaveBackground
.map
position: relative
@ -40,6 +47,7 @@ $gameControlMargin: 30px
.level, .level-shadow
position: absolute
border-radius: 100%
-webkit-transform: scaleY(0.75)
transform: scaleY(0.75)
.level

View file

@ -1,5 +1,5 @@
.map
img.map-background(src="/images/pages/play/map_forest.jpg", alt="")
img.map-background(src="/images/pages/play/map_" + mapType + ".jpg", alt="")
- var seenNext = false;
each campaign in campaigns

View file

@ -14,6 +14,11 @@ block content
a(href="http://codecombat.com/play") play through the campaign
| to try it out, but the only thing you absolutely need to do to be ready is ensure students have access to a computer or iPad.
p
| The iPad version is not publicly available yet, but you can
a(href="https://www.youtube.com/watch?v=jgF4YuN7RBk&feature=youtu.be") see a preview video here
| .
p It is not necessary for teachers to be comfortable with computer science concepts for students to have fun learning with CodeCombat.
h3 Is it violent?
@ -30,31 +35,30 @@ block content
ol
li <strong>Formal notation</strong> - builds an understanding of the importance of syntax in programming.
li <strong>Calling functions</strong> - familiarizes students with parameter-less function calls.
li <strong>Parameters</strong> - how to pass parameters to functions.
li <strong>Calling methods</strong> - familiarizes students with the syntax of object-oriented method calls.
li <strong>Parameters</strong> - trains how to pass parameters to functions.
li <strong>Strings</strong> - teaches students about string notation and passing strings as parameters.
li <strong>Loops</strong> - the pros and cons of designing short programs with loops.
li <strong>Loops</strong> - develops the abstraction of designing short programs with loops.
p Students may continue past level 12, depending on their speed and interest and learn 3 additional concepts in levels 12-20:
p Students may continue past level 12, depending on their speed and interest, to learn two additional concepts in levels 13-20:
ol
li <strong>Conditional logic</strong> - when and how to use if/else to control in-game outcomes.
li <strong>Loop varieties</strong> - when and how to use the different types of loops.
li <strong>Writing functions</strong> - creating and calling functions within other functions.
li <strong>Handling player input</strong> - responding to input events to create a user interface.
h3 System Requirements
p Because CodeCombat is a game, it is more intensive for computers to run smoothly than video or written tutorials. Here are our suggestions for getting the most out of your Hour of Code experience:
p Because CodeCombat is a game, it is more intensive for computers to run smoothly than video or written tutorials. We are continually improving performance and expect to have the game running smoothly on older machines by December. That said, here are our suggestions for getting the most out of your Hour of Code experience:
p For mobile players:
ul
li <strong>Use newer iPads if possible.</strong> Older iPads will work, but will play the game more slowly.
li </strong>Allow players to wear headphones/earbuds to hear the audio.</strong> We help players learn through voiceover and sound effects which will make classrooms noisy and distracting.
li <strong>Use newer iPads if possible.</strong> Older iPads (iPad 2+) will work, but will play the game more slowly. The app requires iOS 8.
li <strong>Allow players to wear headphones/earbuds to hear the audio.</strong> We help players learn through voiceover and sound effects which will make classrooms noisy and distracting.
p For desktop and laptop players:
ul
li <strong>Use newer versions of Chrome or Firefox.</strong> Although CodeCombat will work on browsers as old as IE9, the performance is not as good.
li <strong>Use newer computers.</strong> Older computers, Chromebooks, and netbooks tend to have very few system resources, which makes for a less enjoyable experience.
li </strong>Allow players to wear headphones/earbuds to hear the audio.</strong> We help players learn through voiceover and sound effects which will make classrooms noisy and distracting.
li <strong>Allow players to wear headphones/earbuds to hear the audio.</strong> We help players learn through voiceover and sound effects which will make classrooms noisy and distracting.

View file

@ -103,7 +103,7 @@ module.exports = class InventoryView extends CocoView
for itemSlot in @$el.find '.item-slot'
slot = $(itemSlot).data 'slot'
$(itemSlot).find('.placeholder').css('background-image', "url(/images/pages/game-menu/slot-#{slot}.png)")
#$(itemSlot).find('.placeholder').css('background-image', "url(/images/pages/game-menu/slot-#{slot}.png)")
do (slot) =>
$(itemSlot).droppable
drop: (e, ui) => @onAvailableItemDoubleClick()

View file

@ -4,6 +4,7 @@ LevelSession = require 'models/LevelSession'
CocoCollection = require 'collections/CocoCollection'
AudioPlayer = require 'lib/AudioPlayer'
PlayLevelModal = require 'views/play/modal/PlayLevelModal'
ThangType = require 'models/ThangType'
class LevelSessionsCollection extends CocoCollection
url: ''
@ -34,6 +35,7 @@ module.exports = class WorldMapView extends RootView
@getLevelPlayCounts()
$(window).on 'resize', @onWindowResize
@playAmbientSound()
@preloadTopHeroes()
destroy: ->
$(window).off 'resize', @onWindowResize
@ -73,6 +75,7 @@ module.exports = class WorldMapView extends RootView
context.levelStatusMap = @levelStatusMap
context.levelPlayCountMap = @levelPlayCountMap
context.isIPadApp = application.isIPadApp
context.mapType = 'dungeon'
context
afterRender: ->
@ -145,13 +148,13 @@ module.exports = class WorldMapView extends RootView
@$levelInfo.css('top', top)
onWindowResize: (e) =>
forestMapWidth = 2401
forestMapHeight = 1536
aspectRatio = forestMapWidth / forestMapHeight
mapHeight = 1536
mapWidth = 2350 # 2500 for forest
aspectRatio = mapWidth / mapHeight
pageWidth = $(window).width()
pageHeight = $(window).height()
widthRatio = pageWidth / forestMapWidth
heightRatio = pageHeight / forestMapHeight
widthRatio = pageWidth / mapWidth
heightRatio = pageHeight / mapHeight
if widthRatio > heightRatio
resultingWidth = pageWidth
resultingHeight = resultingWidth / aspectRatio
@ -164,8 +167,9 @@ module.exports = class WorldMapView extends RootView
playAmbientSound: ->
return if @ambientSound
terrain = 'Grass'
return unless file = {Dungeon: 'ambient-map-dungeon', Grass: 'ambient-map-grass'}[terrain]
#terrain = 'Grass'
terrain = 'Dungeon'
return unless file = {Dungeon: 'ambient-dungeon', Grass: 'ambient-map-grass'}[terrain]
src = "/file/interface/#{file}#{AudioPlayer.ext}"
unless AudioPlayer.getStatus(src)?.loaded
AudioPlayer.preloadSound src
@ -174,6 +178,14 @@ module.exports = class WorldMapView extends RootView
@ambientSound = createjs.Sound.play src, loop: -1, volume: 0.1
createjs.Tween.get(@ambientSound).to({volume: 1.0}, 1000)
preloadTopHeroes: ->
for heroID in ['captain', 'knight']
url = "/db/thang.type/#{ThangType.heroes[heroID]}/version"
continue if @supermodel.getModel url
fullHero = new ThangType()
fullHero.setURL url
@supermodel.loadModel fullHero, 'thang'
tutorials = [
{
@ -519,8 +531,8 @@ hero = [
id: 'dungeons-of-kithgard'
original: '528110f30268d018e3000001'
description: 'Grab the gem, but touch nothing else. Start here.'
x: 17.23
y: 36.94
x: 20.24
y: 32.93
}
{
name: 'Gems in the Deep'
@ -529,8 +541,8 @@ hero = [
id: 'gems-in-the-deep'
original: '54173c90844506ae0195a0b4'
description: 'Quickly collect the gems; you will need them.'
x: 22.6
y: 35.1
x: 18.47
y: 49.78
}
{
name: 'Shadow Guard'
@ -539,8 +551,8 @@ hero = [
id: 'shadow-guard'
original: '54174347844506ae0195a0b8'
description: 'Evade the Kithgard minion.'
x: 27.74
y: 35.17
x: 30.89
y: 61.30
}
{
name: 'True Names'
@ -549,8 +561,8 @@ hero = [
id: 'true-names'
original: '541875da4c16460000ab990f'
description: 'Learn an enemy\'s true name to defeat it.'
x: 32.7
y: 36.7
x: 44.39
y: 57.39
}
{
name: 'The Raised Sword'
@ -559,8 +571,8 @@ hero = [
id: 'the-raised-sword'
original: '5418aec24c16460000ab9aa6'
description: 'Learn to equip yourself for combat.'
x: 36.6
y: 39.5
x: 41.83
y: 41.74
}
{
name: 'The First Kithmaze'
@ -569,8 +581,8 @@ hero = [
id: 'the-first-kithmaze'
original: '5418b9d64c16460000ab9ab4'
description: 'The builders of Kith constructed many mazes to confuse travelers.'
x: 38.4
y: 43.5
x: 57.39
y: 48.15
}
{
name: 'The Second Kithmaze'
@ -579,8 +591,8 @@ hero = [
id: 'the-second-kithmaze'
original: '5418cf256bae62f707c7e1c3'
description: 'Many have tried, few have found their way through this maze.'
x: 38.9
y: 48.1
x: 61.72
y: 37.07
}
{
name: 'New Sight'
@ -589,8 +601,8 @@ hero = [
id: 'new-sight'
original: '5418d40f4c16460000ab9ac2'
description: 'A true name can only be seen with the correct lenses.'
x: 39.3
y: 53.1
x: 55.54
y: 26.96
}
{
name: 'Lowly Kithmen'
@ -599,8 +611,8 @@ hero = [
id: 'lowly-kithmen'
original: '541b24511ccc8eaae19f3c1f'
description: 'Use your glasses to seek out and attack the Kithmen.'
x: 39.4
y: 57.7
x: 70.53
y: 27.93
}
{
name: 'A Bolt in the Dark'
@ -609,8 +621,8 @@ hero = [
id: 'a-bolt-in-the-dark'
original: '541b288e1ccc8eaae19f3c25'
description: 'Kithmen are not the only ones to stand in your way.'
x: 40.0
y: 63.2
x: 86.08
y: 40.76
}
{
name: 'The Final Kithmaze'
@ -619,8 +631,8 @@ hero = [
id: 'the-final-kithmaze'
original: '541b434e1ccc8eaae19f3c33'
description: 'To escape you must find your way through an Elder Kithman\'s maze.'
x: 42.67
y: 67.98
x: 96.95
y: 58.15
}
{
name: 'Kithgard Gates'
@ -629,9 +641,9 @@ hero = [
id: 'kithgard-gates'
original: '541c9a30c6362edfb0f34479'
description: 'Escape the Kithgard dungeons and don\'t let the guardians get you.'
x: 47.38
y: 70.55
disabled: true
x: 84.02
y: 72.39
}
{
name: 'Defence of Plainswood'
@ -640,9 +652,9 @@ hero = [
id: 'defence-of-plainswood'
original: '541b67f71ccc8eaae19f3c62'
description: 'Protect the peasants from the pursuing ogres.'
x: 52.66
y: 69.66
disabled: true
x: 95.31
y: 88.26
}
#{
# name: ''

View file

@ -272,7 +272,7 @@ module.exports = class PlayLevelView extends RootView
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
worldName = utils.i18n @level.attributes, 'name'
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel}
_.delay (=> Backbone.Mediator.publish('level:set-debug', debug: true)), 5000 if @isIPadApp() # if me.displayName() is 'Nick'
#_.delay (=> Backbone.Mediator.publish('level:set-debug', debug: true)), 5000 if @isIPadApp() # if me.displayName() is 'Nick'
initVolume: ->
volume = me.get('volume')