Merge branch 'master' into production

This commit is contained in:
Nick Winter 2015-02-26 11:34:02 -08:00
commit 22e7bb8643
9 changed files with 121 additions and 22 deletions

View file

@ -391,7 +391,7 @@
prompt_body: "Do you want to get more?" prompt_body: "Do you want to get more?"
prompt_button: "Enter Shop" prompt_button: "Enter Shop"
recovered: "Previous gems purchase recovered. Please refresh the page." recovered: "Previous gems purchase recovered. Please refresh the page."
or_subscribe: "Or 3500 gems/mo if you..." price: "x3500 / mo"
subscribe: subscribe:
comparison_blurb: "Sharpen your skills with a CodeCombat subscription!" comparison_blurb: "Sharpen your skills with a CodeCombat subscription!"
@ -455,6 +455,14 @@
blocks: "Blocks" # As in "this shield blocks this much damage" blocks: "Blocks" # As in "this shield blocks this much damage"
backstab: "Backstab" # As in "this dagger does this much backstab damage" backstab: "Backstab" # As in "this dagger does this much backstab damage"
skills: "Skills" skills: "Skills"
attack_1: "Deals"
attack_2: "of listed"
attack_3: "weapon damage."
health_1: "Gains"
health_2: "of listed"
health_3: "armor health."
speed_1: "Moves at"
speed_2: "meters per second."
available_for_purchase: "Available for Purchase" # Shows up when you have unlocked, but not purchased, a hero in the hero store available_for_purchase: "Available for Purchase" # Shows up when you have unlocked, but not purchased, a hero in the hero store
level_to_unlock: "Level to unlock:" # Label for which level you have to beat to unlock a particular hero (click a locked hero in the store to see) level_to_unlock: "Level to unlock:" # Label for which level you have to beat to unlock a particular hero (click a locked hero in the store to see)
restricted_to_certain_heroes: "Only certain heroes can play this level." restricted_to_certain_heroes: "Only certain heroes can play this level."
@ -534,10 +542,10 @@
cat_blurb: "Airbender" cat_blurb: "Airbender"
josh_title: "Game Designer" josh_title: "Game Designer"
josh_blurb: "Floor Is Lava" josh_blurb: "Floor Is Lava"
retrostyle_title: "Illustration"
retrostyle_blurb: "RetroStyle"
jose_title: "Music" jose_title: "Music"
jose_blurb: "Taking Off" jose_blurb: "Taking Off"
retrostyle_title: "Illustration"
retrostyle_blurb: "RetroStyle Games"
teachers: teachers:
title: "CodeCombat for Teachers" title: "CodeCombat for Teachers"

View file

@ -356,13 +356,22 @@ module.exports = class ThangType extends CocoModel
else else
classSpecificScore = stat * 5 classSpecificScore = stat * 5
classAverage = @classStatAverages[prop][@get('heroClass')] classAverage = @classStatAverages[prop][@get('heroClass')]
stats[prop] = Math.round(2 * ((classAverage - 2.5) + classSpecificScore / 2)) / 2 / 10 stats[prop] =
relative: Math.round(2 * ((classAverage - 2.5) + classSpecificScore / 2)) / 2 / 10
absolute: stat
pieces = ($.i18n.t "choose_hero.#{prop}_#{num}" for num in [1 .. 3])
percent = Math.round(stat * 100) + '%'
className = $.i18n.t "general.#{_.string.slugify @get('heroClass')}"
stats[prop].description = [pieces[0], percent, pieces[1], className, pieces[2]].join ' '
minSpeed = 4 minSpeed = 4
maxSpeed = 16 maxSpeed = 16
speedRange = maxSpeed - minSpeed speedRange = maxSpeed - minSpeed
speedPoints = rawNumbers.speed - minSpeed speedPoints = rawNumbers.speed - minSpeed
stats.speed = Math.round(20 * speedPoints / speedRange) / 2 / 10 stats.speed =
relative: Math.round(20 * speedPoints / speedRange) / 2 / 10
absolute: rawNumbers.speed
description: "#{$.i18n.t 'choose_hero.speed_1'} #{rawNumbers.speed} #{$.i18n.t 'choose_hero.speed_2'}"
stats.skills = (_.string.titleize(_.string.humanize(skill)) for skill in programmableConfig.programmableProperties when skill isnt 'say') stats.skills = (_.string.titleize(_.string.humanize(skill)) for skill in programmableConfig.programmableProperties when skill isnt 'say')

View file

@ -4,7 +4,7 @@ PaymentSchema = c.object({title: 'Payment', required: []}, {
purchaser: c.objectId(links: [ {rel: 'extra', href: '/db/user/{($)}'} ]) # in case of gifts purchaser: c.objectId(links: [ {rel: 'extra', href: '/db/user/{($)}'} ]) # in case of gifts
recipient: c.objectId(links: [ {rel: 'extra', href: '/db/user/{($)}'} ]) recipient: c.objectId(links: [ {rel: 'extra', href: '/db/user/{($)}'} ])
service: { enum: ['stripe', 'ios' ]} service: { enum: ['stripe', 'ios', 'invoice']}
amount: { type: 'integer', description: 'Payment in cents.' } amount: { type: 'integer', description: 'Payment in cents.' }
created: c.date({title: 'Created', readOnly: true}) created: c.date({title: 'Created', readOnly: true})
gems: { type: 'integer', description: 'The number of gems acquired.' } gems: { type: 'integer', description: 'The number of gems acquired.' }

View file

@ -146,9 +146,9 @@ block content
.team_bio .team_bio
h4.team_name h4.team_name
a(href="http://retrostylegames.com/") Pavel Konstantinov a(href="http://retrostylegames.com/") Pavel Konstantinov
p(data-i18n="about.pavel_title") p(data-i18n="about.retrostyle_title")
| Illustration | Illustration
p(data-i18n="about.pavel_blurb") p(data-i18n="about.retrostyle_blurb")
| RetroStyle Games | RetroStyle Games
a(href="http://retrostylegames.com/") a(href="http://retrostylegames.com/")
@ -156,7 +156,7 @@ block content
.team_bio .team_bio
h4.team_name h4.team_name
a(href="http://retrostylegames.com/") Oleg Ulyanickiy a(href="http://retrostylegames.com/") Oleg Ulyanickiy
p(data-i18n="about.oleg_title") p(data-i18n="about.retrostyle_title")
| Illustration | Illustration
p(data-i18n="about.oleg_blurb") p(data-i18n="about.retrostyle_blurb")
| RetroStyle Games | RetroStyle Games

View file

@ -20,7 +20,7 @@
span= product.price span= product.price
.product .product
h4 x3500 / mo h4(data-i18n="buy_gems.price") x3500 / mo
h3(data-i18n="account.subscription") h3(data-i18n="account.subscription")
button.start-subscription-button.btn.btn-lg.btn-illustrated.btn-success(data-i18n="subscribe.subscribe_title") Subscribe button.start-subscription-button.btn.btn-lg.btn-illustrated.btn-success(data-i18n="subscribe.subscribe_title") Subscribe
@ -45,4 +45,3 @@
div#close-modal div#close-modal
span.glyphicon.glyphicon-remove span.glyphicon.glyphicon-remove

View file

@ -52,11 +52,11 @@
.stat-label(data-i18n='choose_hero.skills') .stat-label(data-i18n='choose_hero.skills')
.stat-value= hero.stats.skills.join(', ') .stat-value= hero.stats.skills.join(', ')
for stat in ['attack', 'health', 'speed'] for stat in ['attack', 'health', 'speed']
.hero-stat-row(class=stat) .hero-stat-row(class=stat, title=hero.stats[stat].description)
.stat-label(data-i18n='choose_hero.'+stat) .stat-label(data-i18n='choose_hero.'+stat)
.stat-value .stat-value
.stat-progress .stat-progress
.stat-progress-bar(style="width: " + (parseInt(hero.stats[stat]*100)) + "%") .stat-progress-bar(style="width: " + (parseInt(hero.stats[stat].relative * 100)) + "%")
a.left(role="button", data-slide="prev", href="#hero-carousel") a.left(role="button", data-slide="prev", href="#hero-carousel")
span.glyphicon.glyphicon-play span.glyphicon.glyphicon-play

View file

@ -266,6 +266,7 @@ module.exports = class CampaignEditorView extends RootView
class LevelsNode extends TreemaObjectNode class LevelsNode extends TreemaObjectNode
valueClass: 'treema-levels' valueClass: 'treema-levels'
@levels: {} @levels: {}
ordered: true
buildValueForDisplay: (valEl, data) -> buildValueForDisplay: (valEl, data) ->
@buildValueForDisplaySimply valEl, ''+_.size(data) @buildValueForDisplaySimply valEl, ''+_.size(data)

View file

@ -29,6 +29,18 @@ module.exports = class SaveCampaignModal extends ModalView
onClickSaveButton: -> onClickSaveButton: ->
@showLoading() @showLoading()
@reverseLevelsBeforeSave()
modelsBeingSaved = (model.patch() for model in @modelsToSave.models) modelsBeingSaved = (model.patch() for model in @modelsToSave.models)
modelsBeingSaved = modelsBeingSaved
$.when(_.compact(modelsBeingSaved)...).done(-> document.location.reload()) $.when(_.compact(modelsBeingSaved)...).done(-> document.location.reload())
reverseLevelsBeforeSave: ->
# For some unfathomable reason, not in our code anywhere, the levels get reversed during the save somehow.
# Since we want to maintain their orders, we reverse them first, so that when they're reversed again, it's right.
# Yaaaay!
return unless campaign = _.find @modelsToSave.models, (m) -> m.constructor.className is 'Campaign'
levelsReversed = {}
levels = campaign.get 'levels'
levelIDs = _.keys(levels).reverse()
for levelID in levelIDs
levelsReversed[levelID] = levels[levelID]
campaign.set 'levels', levelsReversed

View file

@ -0,0 +1,70 @@
// Add externally purchased subscriptions
// Usage:
// Edit hard coded data below.
// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
// Skips duplicate payments, but this might be incorrect depending on the scenario
// TODO: output emails not found
var emails = ['pam@fred.com', 'Bob@fred.com'];
var purchaserID = '54ed0ac0ca7f1c421c025b3d';
var endDate = '2015-06-01';
var gems = 10500;
var amount = 1750;
var service = 'invoice';
emails = emails.map(function(e) { return e.toLowerCase();});
log("Input Data");
log("service\t" + service);
log("purchaserID\t" + purchaserID);
log("end date\t" + endDate);
log("gems\t" + gems);
log("amount\t" + amount);
log("emails");
log(emails);
// 1. Set free = endDate, updated purchased.gems
db.users.update(
{emailLower: {$in: emails}, "stripe.free": {$ne: endDate}},
{
$set: {
"stripe.free": endDate
},
$inc: {
"purchased.gems": gems
}
},
{
multi: true
}
);
// 2. create Payment objects
var cursor = db.users.find({emailLower: {$in: emails}});
while (cursor.hasNext()) {
var doc = cursor.next();
var criteria = {
purchaser: ObjectId(purchaserID),
recipient: doc._id,
service: service,
gems: gems,
amount: amount
}
if (db.payments.findOne(criteria)) {
log("Already have a payment for " + doc.email);
}
else {
db.payments.insert(criteria);
log("Added payment for " + doc.email);
}
}
function log(str) {
print(new Date().toISOString() + " " + str);
}