mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-24 08:08:15 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
1221265d08
14 changed files with 60 additions and 82 deletions
|
@ -117,51 +117,15 @@ module.exports = class User extends CocoModel
|
|||
application.tracker.identify announcesActionAudioGroup: @announcesActionAudioGroup unless me.isAdmin()
|
||||
@announcesActionAudioGroup
|
||||
|
||||
getGemPromptGroup: ->
|
||||
# A/B Testing whether extra prompt when low gems leads to more gem purchases
|
||||
# TODO: Rename gem purchase event in BuyGemsModal to 'Started gem purchase' after this test is over
|
||||
return @gemPromptGroup if @gemPromptGroup
|
||||
getFourthLevelGroup: ->
|
||||
return @fourthLevelGroup if @fourthLevelGroup
|
||||
group = me.get('testGroupNumber') % 8
|
||||
@gemPromptGroup = switch group
|
||||
when 0, 1, 2, 3 then 'prompt'
|
||||
when 4, 5, 6, 7 then 'no-prompt'
|
||||
@gemPromptGroup = 'prompt' if me.isAdmin()
|
||||
application.tracker.identify gemPromptGroup: @gemPromptGroup unless me.isAdmin()
|
||||
@gemPromptGroup
|
||||
|
||||
getForeshadowsLevels: ->
|
||||
return false if $.browser.msie
|
||||
return @foreshadowsLevels if @foreshadowsLevels?
|
||||
group = me.get('testGroupNumber') % 16
|
||||
@foreshadowsLevels = switch group
|
||||
when 0, 1, 2, 3, 4, 5, 6, 7 then true
|
||||
when 8, 9, 10, 11, 12, 13, 14, 15 then false
|
||||
@foreshadowsLevels = true if me.isAdmin()
|
||||
application.tracker.identify foreshadowsLevels: @foreshadowsLevels unless me.isAdmin()
|
||||
@foreshadowsLevels
|
||||
|
||||
getLeaderboardsGroup: ->
|
||||
return @leaderboardsGroup if @leaderboardsGroup?
|
||||
group = me.get('testGroupNumber') % 64
|
||||
if group < 16
|
||||
@leaderboardsGroup = 'always'
|
||||
else if group < 32
|
||||
@leaderboardsGroup = 'early'
|
||||
else if group < 48
|
||||
@leaderboardsGroup = 'late'
|
||||
else
|
||||
@leaderboardsGroup = 'never'
|
||||
@leaderboardsGroup = 'always' if me.isAdmin()
|
||||
application.tracker.identify leaderboardsGroup: @leaderboardsGroup unless me.isAdmin()
|
||||
@leaderboardsGroup
|
||||
|
||||
getShowsPortal: ->
|
||||
return @showsPortal if @showsPortal?
|
||||
group = me.get('testGroupNumber')
|
||||
@showsPortal = if group < 128 then true else false
|
||||
@showsPortal = true if me.isAdmin()
|
||||
application.tracker.identify showsPortal: @showsPortal unless me.isAdmin()
|
||||
@showsPortal
|
||||
@fourthLevelGroup = switch group
|
||||
when 0, 1, 2, 3 then 'signs-and-portents'
|
||||
when 4, 5, 6, 7 then 'forgetful-gemsmith'
|
||||
@fourthLevelGroup = 'signs-and-portents' if me.isAdmin()
|
||||
application.tracker.identify fourthLevelGroup: @fourthLevelGroup unless me.isAdmin()
|
||||
@fourthLevelGroup
|
||||
|
||||
getVideoTutorialStylesIndex: (numVideos=0)->
|
||||
# A/B Testing video tutorial styles
|
||||
|
|
|
@ -402,9 +402,9 @@ $gameControlMargin: 30px
|
|||
|
||||
.level-indicator
|
||||
margin-left: 15px
|
||||
color: #E5C100
|
||||
color: white
|
||||
display: inline-block
|
||||
margin: 0p 2px
|
||||
margin: 0 2px
|
||||
|
||||
.player-hero-icon
|
||||
margin-left: 10px
|
||||
|
|
|
@ -83,7 +83,8 @@ else
|
|||
button.btn.achievements(data-toggle='coco-modal', data-target='play/modal/PlayAchievementsModal', data-i18n="[title]play.achievements")
|
||||
if me.get('anonymous') === false || me.get('iosIdentifierForVendor') || isIPadApp
|
||||
button.btn.gems(data-toggle='coco-modal', data-target='play/modal/BuyGemsModal', data-i18n="[title]play.buy_gems")
|
||||
button.btn.account(data-toggle='coco-modal', data-target='play/modal/PlayAccountModal', data-i18n="[title]play.account")
|
||||
if !me.get('anonymous', true)
|
||||
button.btn.account(data-toggle='coco-modal', data-target='play/modal/PlayAccountModal', data-i18n="[title]play.account")
|
||||
if me.isAdmin()
|
||||
button.btn.settings(data-toggle='coco-modal', data-target='play/modal/PlaySettingsModal', data-i18n="[title]play.settings")
|
||||
else if me.get('anonymous', true)
|
||||
|
|
|
@ -59,8 +59,6 @@ module.exports = class CampaignView extends RootView
|
|||
@editorMode = options?.editorMode
|
||||
if @editorMode
|
||||
@terrain ?= 'dungeon'
|
||||
else unless me.getShowsPortal()
|
||||
@terrain ?= 'dungeon'
|
||||
@levelStatusMap = {}
|
||||
@levelPlayCountMap = {}
|
||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', {cache: false}, 0).model
|
||||
|
@ -160,6 +158,9 @@ module.exports = class CampaignView extends RootView
|
|||
context = super(context)
|
||||
context.campaign = @campaign
|
||||
context.levels = _.values($.extend true, {}, @campaign?.get('levels') ? {})
|
||||
if me.level() < 12 and @terrain is 'dungeon' and not @editorMode
|
||||
reject = if me.getFourthLevelGroup() is 'signs-and-portents' then 'forgetful-gemsmith' else 'signs-and-portents'
|
||||
context.levels = _.reject context.levels, slug: reject
|
||||
@annotateLevel level for level in context.levels
|
||||
count = @countLevels context.levels
|
||||
context.levelsCompleted = count.completed
|
||||
|
@ -257,6 +258,7 @@ module.exports = class CampaignView extends RootView
|
|||
level.locked = false if me.isInGodMode()
|
||||
level.disabled = true if level.adminOnly and @levelStatusMap[level.slug] not in ['started', 'complete']
|
||||
level.disabled = false if me.isInGodMode()
|
||||
level.locked = false
|
||||
level.color = 'rgb(255, 80, 60)'
|
||||
if level.requiresSubscription
|
||||
level.color = 'rgb(80, 130, 200)'
|
||||
|
@ -323,7 +325,7 @@ module.exports = class CampaignView extends RootView
|
|||
@playAmbientSound()
|
||||
|
||||
testParticles: ->
|
||||
return unless @campaign?.loaded and me.getForeshadowsLevels()
|
||||
return unless @campaign?.loaded and $.browser.chrome # Sometimes this breaks in non-Chrome browsers, according to A/B tests.
|
||||
@particleMan ?= new ParticleMan()
|
||||
@particleMan.removeEmitters()
|
||||
@particleMan.attach @$el.find('.map')
|
||||
|
|
|
@ -150,11 +150,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
# Show the "I'm done" button between 30 - 120 minutes if they definitely came from Hour of Code
|
||||
c.showHourOfCodeDoneButton = me.get('hourOfCode') and showDone
|
||||
|
||||
if @level.get('scoreTypes')?.length
|
||||
lg = me.getLeaderboardsGroup()
|
||||
c.showLeaderboard = lg is 'always'
|
||||
c.showLeaderboard = true if me.level() >= 3 and lg.group is 'early'
|
||||
c.showLeaderboard = true if me.level() >= 5 and lg.group is 'late'
|
||||
c.showLeaderboard = @level.get('scoreTypes')?.length > 0
|
||||
|
||||
return c
|
||||
|
||||
|
|
|
@ -563,9 +563,6 @@ module.exports = class InventoryModal extends ModalView
|
|||
return @openModalView authModal
|
||||
|
||||
askToBuyGems: (unlockButton) ->
|
||||
if me.getGemPromptGroup() is 'no-prompt'
|
||||
return @askToSignUp() if me.get('anonymous')
|
||||
return @openModalView new BuyGemsModal()
|
||||
@$el.find('.unlock-button').popover 'destroy'
|
||||
popoverTemplate = buyGemsPromptTemplate {}
|
||||
unlockButton.popover(
|
||||
|
|
|
@ -65,8 +65,7 @@ module.exports = class BuyGemsModal extends ModalView
|
|||
Backbone.Mediator.publish 'buy-gems-modal:purchase-initiated', { productID: productID }
|
||||
|
||||
else
|
||||
# TODO: rename this event to 'Started gem purchase' after gemPrompt A/B test is over
|
||||
application.tracker?.trackEvent 'Started purchase', { productID: productID }
|
||||
application.tracker?.trackEvent 'Started gem purchase', { productID: productID }
|
||||
stripeHandler.open({
|
||||
description: $.t(product.i18n)
|
||||
amount: product.amount
|
||||
|
|
|
@ -265,9 +265,6 @@ module.exports = class PlayHeroesModal extends ModalView
|
|||
return @openModalView authModal
|
||||
|
||||
askToBuyGems: (unlockButton) ->
|
||||
if me.getGemPromptGroup() is 'no-prompt'
|
||||
return @askToSignUp() if me.get('anonymous')
|
||||
return @openModalView new BuyGemsModal()
|
||||
@$el.find('.unlock-button').popover 'destroy'
|
||||
popoverTemplate = buyGemsPromptTemplate {}
|
||||
unlockButton.popover(
|
||||
|
|
|
@ -216,9 +216,6 @@ module.exports = class PlayItemsModal extends ModalView
|
|||
return @openModalView authModal
|
||||
|
||||
askToBuyGems: (unlockButton) ->
|
||||
if me.getGemPromptGroup() is 'no-prompt'
|
||||
return @askToSignUp() if me.get('anonymous')
|
||||
return @openModalView new BuyGemsModal()
|
||||
@$el.find('.unlock-button').popover 'destroy'
|
||||
popoverTemplate = buyGemsPromptTemplate {}
|
||||
unlockButton.popover(
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// foreshadowsLevels A/B Results
|
||||
// Test started 2015-01-29
|
||||
// Test started 2015-01-29, ended 2015-02-26
|
||||
// Fixed some particle problems on 2015-02-02
|
||||
// Fixed more particle problems in old browsers on 2015-02-19
|
||||
// Final results: tests showed no difference in completion rates, but slight drops in level start rates for non-Chrome browsers, so we stopped doing it outside of Chrome.
|
||||
|
||||
// Usage:
|
||||
// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
|
||||
|
@ -9,18 +11,18 @@ load('abTestHelpers.js');
|
|||
|
||||
var scriptStartTime = new Date();
|
||||
try {
|
||||
var startDay = '2015-02-03'
|
||||
var startDay = '2015-02-20';
|
||||
log("Today is " + new Date().toISOString().substr(0, 10));
|
||||
log("Start day is " + startDay);
|
||||
|
||||
var eventFunnel = ['Started Level', 'Saw Victory'];
|
||||
var levelSlugs = ['dungeons-of-kithgard', 'gems-in-the-deep', 'shadow-guard', 'forgetful-gemsmith'];
|
||||
var levelSlugs = ['dungeons-of-kithgard', 'gems-in-the-deep', 'shadow-guard', 'forgetful-gemsmith', 'kounter-kithwise', 'kithgard-gates', 'rich-forager', 'village-guard'];
|
||||
|
||||
// getForeshadowsLevels
|
||||
var testGroupFn = function (testGroupNumber) {
|
||||
var group = testGroupNumber % 16
|
||||
return group >= 0 && group <= 7;
|
||||
}
|
||||
};
|
||||
|
||||
var funnelData = getFunnelData(startDay, eventFunnel, testGroupFn, levelSlugs);
|
||||
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
// gemPromptGroup A/B Results
|
||||
// Test started 2014-11-24
|
||||
// Test started 2014-11-24, ended 2015-02-26
|
||||
// Final results:
|
||||
// no-prompt 3789 gem shop shown, 62 purchased
|
||||
// prompt 2658 gem shop shown, 78 purchased
|
||||
// Decided prompt was better, so now always prompt. (Yay being nice.)
|
||||
|
||||
// Usage:
|
||||
// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
|
||||
|
||||
// TODO: Why is no-prompt group 50% larger?
|
||||
|
||||
load('abTestHelpers.js');
|
||||
|
||||
var scriptStartTime = new Date();
|
||||
try {
|
||||
var startDay = '2014-11-24'
|
||||
var startDay = '2014-11-24';
|
||||
// startDay = '2015-01-15'
|
||||
log("Today is " + new Date().toISOString().substr(0, 10));
|
||||
log("Start day is " + startDay);
|
||||
|
@ -21,7 +23,7 @@ try {
|
|||
var testGroupFn = function (testGroupNumber) {
|
||||
var group = testGroupNumber % 8
|
||||
return group >= 0 && group <= 3 ? 'prompt' : 'no-prompt';
|
||||
}
|
||||
};
|
||||
|
||||
var funnelData = getFunnelData(startDay, eventFunnel, testGroupFn);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// leaderboardsGroup A/B Results
|
||||
// Test started 2015-01-30
|
||||
// Test started 2015-01-30, ended 2015-02-26
|
||||
// Final results: no differences in level starts or completions. Perhaps they affect playtime or purchases, but harder to say. At least they don't hurt, so wejust turned them on for everyone always.
|
||||
|
||||
// Usage:
|
||||
// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
|
||||
|
@ -8,12 +9,12 @@ load('abTestHelpers.js');
|
|||
|
||||
var scriptStartTime = new Date();
|
||||
try {
|
||||
var startDay = '2015-01-30'
|
||||
var startDay = '2015-02-07';
|
||||
log("Today is " + new Date().toISOString().substr(0, 10));
|
||||
log("Start day is " + startDay);
|
||||
|
||||
var eventFunnel = ['Started Level', 'Saw Victory'];
|
||||
var levelSlugs = ['dungeons-of-kithgard', 'gems-in-the-deep', 'shadow-guard', 'forgetful-gemsmith'];
|
||||
var levelSlugs = ['dungeons-of-kithgard', 'gems-in-the-deep', 'shadow-guard', 'forgetful-gemsmith', 'kounter-kithwise', 'kithgard-gates', 'rich-forager', 'village-guard'];
|
||||
|
||||
// getLeaderboardsGroup
|
||||
var testGroupFn = function (testGroupNumber) {
|
||||
|
@ -22,7 +23,7 @@ try {
|
|||
if (group < 32) return 'early';
|
||||
if (group < 48) return 'late';
|
||||
return 'never';
|
||||
}
|
||||
};
|
||||
|
||||
var funnelData = getFunnelData(startDay, eventFunnel, testGroupFn, levelSlugs);
|
||||
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
// showsPortal A/B Results
|
||||
// Test started 2015-02-05
|
||||
// Test started 2015-02-05, ended 2015-02-26
|
||||
// Final results: seems to help people get to the later levels, and at least definitely doesn't hurt:
|
||||
// dungeons-of-kithgard false 64605 49956 77.33
|
||||
// dungeons-of-kithgard true 65380 50590 77.38
|
||||
// gems-in-the-deep false 45339 40788 89.96
|
||||
// gems-in-the-deep true 45922 41455 90.27
|
||||
// kithgard-gates false 7415 6904 93.11
|
||||
// kithgard-gates true 7783 7249 93.14
|
||||
// kounter-kithwise true 95 92 96.84
|
||||
// kounter-kithwise false 86 77 89.53
|
||||
// rich-forager false 1067 822 77.04
|
||||
// rich-forager true 1111 834 75.07
|
||||
// shadow-guard false 38089 35239 92.52
|
||||
// shadow-guard true 38774 35975 92.78
|
||||
// the-mighty-sand-yak true 505 400 79.21
|
||||
// the-mighty-sand-yak false 425 329 77.41
|
||||
//
|
||||
// Group totals:
|
||||
// false 157026 134115 85.41
|
||||
// true 159570 136595 85.60
|
||||
|
||||
|
||||
// Usage:
|
||||
// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
|
||||
|
@ -13,7 +33,7 @@ try {
|
|||
log("Start day is " + startDay);
|
||||
|
||||
var eventFunnel = ['Started Level', 'Saw Victory'];
|
||||
var levelSlugs = ['dungeons-of-kithgard', 'gems-in-the-deep', 'shadow-guard', 'forgetful-gemsmith'];
|
||||
var levelSlugs = ['dungeons-of-kithgard', 'gems-in-the-deep', 'shadow-guard', 'kounter-kithwise', 'kithgard-gates', 'rich-forager', 'the-mighty-sand-yak'];
|
||||
|
||||
// getShowsPortal
|
||||
var testGroupFn = function (testGroupNumber) {
|
||||
|
|
|
@ -345,11 +345,11 @@ LevelHandler = class LevelHandler extends Handler
|
|||
@sendSuccess res, data
|
||||
|
||||
hasAccessToDocument: (req, document, method=null) ->
|
||||
return true if req.user?.isArtisan()
|
||||
method ?= req.method
|
||||
return true if method is null or method is 'get'
|
||||
super(req, document, method)
|
||||
|
||||
|
||||
getLevelPlaytimesBySlugs: (req, res) ->
|
||||
# Returns an array of per-day level average playtimes
|
||||
# Parameters:
|
||||
|
|
Loading…
Reference in a new issue