diff --git a/app/lib/code-play.coffee b/app/lib/code-play.coffee new file mode 100644 index 00000000000..7d3cb43e624 --- /dev/null +++ b/app/lib/code-play.coffee @@ -0,0 +1,8 @@ +codePlayWhiteList = ["one-wrong-step","forest-evasion","patrol-buster","thumb-biter","gems-or-death","burls-beets-booleans","village-guard","thornbush-farm","ogre-encampment","elseweyr","shield-rush","long-range-division","munchkin-swarm","stillness-in-motion","the-agrippa-defense","a-fine-mint","village-warder","village-champion","tomb-raider","tomb-ghost","short-sighted-burl","seek-and-hide","forest-miners","agrippa-refactored","agrippa-returned","deja-brew","backwoods-bombardier","sarven-gaps","minesweeper","canyon-of-storms","no-pain-no-gain","spinach-power","mirage-maker","preferential-treatment","dungeons-of-kithgard","gems-in-the-deep","shadow-guard","true-names","the-raised-sword","cell-commentary","kithgard-librarian","fire-dancing","loop-da-loop","haunted-kithmaze","the-second-kithmaze","dread-door","known-enemy","master-of-names","closing-the-distance","a-mayhem-of-munchkins","the-final-kithmaze","kithgard-gates","defense-of-plainswood","winding-trail","woodland-cubbies","if-stravaganza","back-to-back","woodland-cleaver","backwoods-standoff","range-finder","peasant-protection","maniac-munchkins","forest-fire-dancing","village-rover","backwoods-fork","leave-it-to-cleaver","backwoods-buddy","go-fetch","friend-and-foe","the-wizards-door","coincrumbs","blind-distance","hit-and-freeze","salted-earth","spring-thunder","usual-day","passing-through","useful-competitors","logical-path","return-to-thornbush-farm","coincucopia","copper-meadows","drop-the-flag","mind-the-trap","signal-corpse","rich-forager","siege-of-stonehold","the-mighty-sand-yak","oasis","basin-stampede","sarven-road","crossroads","thunderhooves","operation-killdeer","interception","crux-of-the-desert","cursed-valley","medical-attention","keeping-time","minesweeper","hoarding-gold","decoy-drill","continuous-alchemy","double-cheek","desert-combat","dust","dont-rush-be-quiet","zig-zag-and-zoom","cubic-minefield","desert-delta","safety-blanket","sarven-savior","bank-raid","wandering-souls","team-work","coordinated-defense","recruiting-queue","second-gem","lurkers","marauder","sarven-shepherd","shine-getter","mad-maxer","sand-snakes","brittle-morale","diamond-dozen","wishing-well","clash-of-clones","reward-and-ruination","white-rabbit","chameleons","burlbole-grove","coin-hunter","metal-detector","star-shower","forest-shadow","teleport-lasso","brawler-hunt","wonderglade","cursed-wonderglade","closed-crossroad","greed-traps"] +codePlayWhiteObject = _.zipObject(codePlayWhiteList, _.times(codePlayWhiteList.length, -> true)) + +canPlay = (slug) -> codePlayWhiteObject[slug] + +module.exports = { + canPlay +} diff --git a/app/views/play/CampaignView.coffee b/app/views/play/CampaignView.coffee index e3f816d80ef..e9fa909eb93 100644 --- a/app/views/play/CampaignView.coffee +++ b/app/views/play/CampaignView.coffee @@ -21,6 +21,7 @@ UserPollsRecord = require 'models/UserPollsRecord' Poll = require 'models/Poll' PollModal = require 'views/play/modal/PollModal' CourseInstance = require 'models/CourseInstance' +codePlay = require('lib/code-play') require 'game-libraries' @@ -195,7 +196,9 @@ module.exports = class CampaignView extends RootView reject = if me.getFourthLevelGroup() is 'signs-and-portents' then 'forgetful-gemsmith' else 'signs-and-portents' context.levels = _.reject context.levels, slug: reject if features.freeOnly - context.levels = _.reject context.levels, 'requiresSubscription' + context.levels = _.reject context.levels, (level) -> + return false if features.codePlay and codePlay.canPlay(level.slug) + return level.requiresSubscription @annotateLevels(context.levels) count = @countLevels context.levels context.levelsCompleted = count.completed @@ -235,6 +238,10 @@ module.exports = class CampaignView extends RootView context.campaigns[campaign.get('slug')] = campaign if @sessions?.loaded levels = _.values($.extend true, {}, campaign.get('levels') ? {}) + if features.freeOnly + levels = _.reject levels, (level) -> + return false if features.codePlay and codePlay.canPlay(level.slug) + return level.requiresSubscription count = @countLevels levels campaign.levelsTotal = count.total campaign.levelsCompleted = count.completed @@ -370,7 +377,7 @@ module.exports = class CampaignView extends RootView level.disabled = true if level.adminOnly and @levelStatusMap[level.slug] not in ['started', 'complete'] level.disabled = false if me.isInGodMode() level.color = 'rgb(255, 80, 60)' - level.color = 'rgb(80, 130, 200)' if level.requiresSubscription + level.color = 'rgb(80, 130, 200)' if level.requiresSubscription and not features.codePlay level.color = 'rgb(200, 80, 200)' if level.adventurer level.color = 'rgb(193, 193, 193)' if level.locked level.unlocksHero = _.find(level.rewards, 'hero')?.hero @@ -646,7 +653,7 @@ module.exports = class CampaignView extends RootView level = _.find _.values(@campaign.get('levels')), slug: levelSlug requiresSubscription = level.requiresSubscription or (me.isOnPremiumServer() and not (level.slug in ['dungeons-of-kithgard', 'gems-in-the-deep', 'shadow-guard', 'forgetful-gemsmith', 'signs-and-portents', 'true-names'])) - canPlayAnyway = not @requiresSubscription or level.adventurer or @levelStatusMap[level.slug] + canPlayAnyway = not @requiresSubscription or level.adventurer or @levelStatusMap[level.slug] or (features.codePlay and codePlay.canPlay(level.slug)) if requiresSubscription and not canPlayAnyway @promptForSubscription levelSlug, 'map level clicked' else diff --git a/server/middleware/levels.coffee b/server/middleware/levels.coffee index cdba1c404e9..36e8e349fe6 100644 --- a/server/middleware/levels.coffee +++ b/server/middleware/levels.coffee @@ -7,6 +7,7 @@ CourseInstance = require '../models/CourseInstance' Classroom = require '../models/Classroom' Course = require '../models/Course' database = require '../commons/database' +codePlay = require '../../app/lib/code-play' module.exports = upsertSession: wrap (req, res) -> @@ -112,7 +113,11 @@ module.exports = else requiresSubscription = level.get('requiresSubscription') or (req.user.isOnPremiumServer() and level.get('campaign') and not (level.slug in ['dungeons-of-kithgard', 'gems-in-the-deep', 'shadow-guard', 'forgetful-gemsmith', 'signs-and-portents', 'true-names'])) - canPlayAnyway = req.user.isPremium() or level.get 'adventurer' + canPlayAnyway = _.any([ + req.user.isPremium(), + level.get('adventurer'), + req.features.codePlay and codePlay.canPlay(level.get('slug')) + ]) if requiresSubscription and not canPlayAnyway throw new errors.PaymentRequired('This level requires a subscription to play')