mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-26 14:03:28 -04:00
You can now buy cross-class items once you have a hero of that class. When you click to buy an item you can't afford, it takes you to the gem shop. Increased amount of items you can purchase a bit more.
This commit is contained in:
parent
f9e6c167bc
commit
9accd0cb04
10 changed files with 161 additions and 50 deletions
app
locale
models
styles
templates/play/modal
views
|
@ -96,10 +96,10 @@
|
|||
logging_in: "Logging In"
|
||||
log_out: "Log Out"
|
||||
recover: "recover account"
|
||||
authenticate_gplus: 'Authenticate G+'
|
||||
load_profile: 'Load G+ Profile'
|
||||
load_email: 'Load G+ Email'
|
||||
finishing: 'Finishing'
|
||||
authenticate_gplus: "Authenticate G+"
|
||||
load_profile: "Load G+ Profile"
|
||||
load_email: "Load G+ Email"
|
||||
finishing: "Finishing"
|
||||
|
||||
signup:
|
||||
create_account_title: "Create Account to Save Progress"
|
||||
|
@ -319,12 +319,15 @@
|
|||
unequip: "Unequip"
|
||||
|
||||
buy_gems:
|
||||
few_gems: 'A few gems'
|
||||
pile_gems: 'Pile of gems'
|
||||
chest_gems: 'Chest of gems'
|
||||
purchasing: 'Purchasing...'
|
||||
declined: 'Your card was declined'
|
||||
retrying: 'Server error, retrying.'
|
||||
few_gems: "A few gems"
|
||||
pile_gems: "Pile of gems"
|
||||
chest_gems: "Chest of gems"
|
||||
purchasing: "Purchasing..."
|
||||
declined: "Your card was declined"
|
||||
retrying: "Server error, retrying."
|
||||
prompt_title: "Not Enough Gems"
|
||||
prompt_body: "Do you want to get more?"
|
||||
prompt_button: "Enter Shop"
|
||||
|
||||
choose_hero:
|
||||
choose_hero: "Choose Your Hero"
|
||||
|
|
|
@ -19,6 +19,10 @@ module.exports = class ThangType extends CocoModel
|
|||
librarian: '52fbf74b7e01835453bd8d8e'
|
||||
'potion-master': '52e9adf7427172ae56002172'
|
||||
sorcerer: '52fd1524c7e6cf99160e7bc9'
|
||||
@heroClasses:
|
||||
Warrior: ['captain', 'knight', 'samurai']
|
||||
Ranger: ['ninja', 'forest-archer', 'trapper']
|
||||
Wizard: ['librarian', 'potion-master', 'sorcerer']
|
||||
@items:
|
||||
'simple-boots': '53e237bf53457600003e3f05'
|
||||
urlRoot: '/db/thang.type'
|
||||
|
@ -447,7 +451,7 @@ module.exports = class ThangType extends CocoModel
|
|||
levelRequiredForItem: ->
|
||||
return console.error "Trying to determine what level is required for #{@get('name')}, but it has no tier." unless @get('tier')?
|
||||
itemTier = @get 'tier'
|
||||
playerTier = itemTier / 2
|
||||
playerTier = itemTier / 2.5
|
||||
playerLevel = me.constructor.levelForTier playerTier
|
||||
#console.log 'Level required for', @get('name'), 'is', playerLevel, 'player tier', playerTier, 'because it is itemTier', itemTier, 'which is normally level', me.constructor.levelForTier(itemTier)
|
||||
playerLevel
|
||||
|
|
|
@ -95,6 +95,13 @@ module.exports = class User extends CocoModel
|
|||
ownsItem: (itemOriginal) -> itemOriginal in @items()
|
||||
ownsLevel: (levelOriginal) -> levelOriginal in @levels()
|
||||
|
||||
getHeroClasses: ->
|
||||
idsToSlugs = _.invert ThangType.heroes
|
||||
myHeroSlugs = (idsToSlugs[id] for id in @heroes())
|
||||
myHeroClasses = []
|
||||
myHeroClasses.push heroClass for heroClass, heroSlugs of ThangType.heroClasses when _.intersection(myHeroSlugs, heroSlugs).length
|
||||
myHeroClasses
|
||||
|
||||
getBranchingGroup: ->
|
||||
return @branchingGroup if @branchingGroup
|
||||
group = me.get('testGroupNumber') % 4
|
||||
|
@ -107,4 +114,14 @@ module.exports = class User extends CocoModel
|
|||
application.tracker.identify branchingGroup: @branchingGroup unless me.isAdmin()
|
||||
@branchingGroup
|
||||
|
||||
getGemPromptGroup: ->
|
||||
return @gemPromptGroup if @gemPromptGroup
|
||||
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
|
||||
|
||||
tiersByLevel = [-1, 0, 0.05, 0.14, 0.18, 0.32, 0.41, 0.5, 0.64, 0.82, 0.91, 1.04, 1.22, 1.35, 1.48, 1.65, 1.78, 1.96, 2.1, 2.24, 2.38, 2.55, 2.69, 2.86, 3.03, 3.16, 3.29, 3.42, 3.58, 3.74, 3.89, 4.04, 4.19, 4.32, 4.47, 4.64, 4.79, 4.96]
|
||||
|
|
|
@ -228,6 +228,9 @@ kbd
|
|||
border-width: 15px 20px
|
||||
.arrow
|
||||
display: none
|
||||
.btn
|
||||
font-size: 20px
|
||||
width: 100%
|
||||
|
||||
.btn.btn-illustrated
|
||||
background: 0
|
||||
|
@ -242,6 +245,9 @@ kbd
|
|||
font-weight: bold
|
||||
color: rgb(248, 197, 146)
|
||||
|
||||
&:hover
|
||||
color: lighten(rgb(248, 197, 146), 5%)
|
||||
|
||||
&:active
|
||||
border-image: url(/images/common/button-background-pressed-border.png) 14 16 16 20 fill round
|
||||
padding: 2px 0 0 2px
|
||||
|
|
|
@ -307,6 +307,13 @@
|
|||
opacity: 1
|
||||
color: rgba(255,255,255, 0.4)
|
||||
|
||||
// Make sure this shows up above our modals.
|
||||
.popover.buy-gems-prompt
|
||||
z-index: 1050
|
||||
text-align: center
|
||||
|
||||
button
|
||||
margin-top: 20px
|
||||
|
||||
//- Use the two-column layout and background image if we are on a narrow screen.
|
||||
|
||||
|
|
6
app/templates/play/modal/buy-gems-prompt.jade
Normal file
6
app/templates/play/modal/buy-gems-prompt.jade
Normal file
|
@ -0,0 +1,6 @@
|
|||
.popover.buy-gems-prompt(role="tooltip")
|
||||
.arrow
|
||||
h2(data-i18n="buy_gems.prompt_title") Not Enough Gems
|
||||
p(data-i18n="buy_gems.prompt_body") Do you want to get more?
|
||||
button.btn.btn-success.btn-illustrated.btn-lg.buy-gems-prompt-button(data-i18n="buy_gems.prompt_button") Enter Shop
|
||||
|
|
@ -37,7 +37,7 @@ if item && !item.owned
|
|||
// Temp, while we only have Warriors: prevent them from buying non-Warrior stuff
|
||||
button.btn.big-font.disabled.unequippable #{item.get('heroClass')} Only
|
||||
else
|
||||
button#selected-item-unlock-button.btn.big-font.unlock-button(disabled=!item.affordable, data-item-id=item.id)
|
||||
button#selected-item-unlock-button.btn.big-font.unlock-button(data-item-id=item.id)
|
||||
span(data-i18n="play.unlock") Unlock
|
||||
span.spl= '('+item.get('gems')
|
||||
img(src="/images/common/gem.png", draggable="false")
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
// Temp, while we only have Warriors: prevent them from buying non-Warrior stuff
|
||||
span.big-font.unequippable= item.get('heroClass')
|
||||
else
|
||||
button.btn.unlock-button.big-font(data-i18n="play.unlock", disabled=!item.affordable, data-item-id=item.id)
|
||||
button.btn.unlock-button.big-font(data-i18n="play.unlock", data-item-id=item.id)
|
||||
.clearfix
|
||||
|
||||
#item-details-view
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/game-menu/inventory-modal'
|
||||
buyGemsPromptTemplate = require 'templates/play/modal/buy-gems-prompt'
|
||||
{me} = require 'lib/auth'
|
||||
ThangType = require 'models/ThangType'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
|
@ -8,6 +9,7 @@ SpriteBuilder = require 'lib/sprites/SpriteBuilder'
|
|||
ItemDetailsView = require 'views/play/modal/ItemDetailsView'
|
||||
Purchase = require 'models/Purchase'
|
||||
LevelOptions = require 'lib/LevelOptions'
|
||||
BuyGemsModal = require 'views/play/modal/BuyGemsModal'
|
||||
|
||||
hasGoneFullScreenOnce = false
|
||||
|
||||
|
@ -31,6 +33,8 @@ module.exports = class InventoryModal extends ModalView
|
|||
'click #equip-item-viewed': 'onClickEquipItemViewed'
|
||||
'click #unequip-item-viewed': 'onClickUnequipItemViewed'
|
||||
'click #close-modal': 'hide'
|
||||
'click .buy-gems-prompt-button': 'onBuyGemsPromptButtonClicked'
|
||||
'click': 'onClickedSomewhere'
|
||||
|
||||
shortcuts:
|
||||
'esc': 'clearSelection'
|
||||
|
@ -224,40 +228,6 @@ module.exports = class InventoryModal extends ModalView
|
|||
@selectUnequippedItem(itemEl)
|
||||
@equipSelectedItem()
|
||||
|
||||
onUnlockButtonClicked: (e) ->
|
||||
button = $(e.target).closest('button')
|
||||
if button.hasClass('confirm')
|
||||
item = @items.get($(e.target).data('item-id'))
|
||||
purchase = Purchase.makeFor(item)
|
||||
purchase.save()
|
||||
|
||||
#- set local changes to mimic what should happen on the server...
|
||||
purchased = me.get('purchased') ? {}
|
||||
purchased.items ?= []
|
||||
purchased.items.push(item.get('original'))
|
||||
|
||||
me.set('purchased', purchased)
|
||||
me.set('spent', (me.get('spent') ? 0) + item.get('gems'))
|
||||
|
||||
#- ...then rerender key bits
|
||||
@itemGroups.lockedItems.remove(item)
|
||||
# Redo all item sorting to make sure that we don't clobber state changes since last render.
|
||||
equipped = _.values @getCurrentEquipmentConfig()
|
||||
@sortItem(item, equipped) for item in @items.models
|
||||
@renderSelectors('#unequipped', '#gems-count')
|
||||
|
||||
@requireLevelEquipment()
|
||||
@delegateEvents()
|
||||
@setUpDraggableEventsForAvailableEquipment()
|
||||
@itemDetailsView.setItem(item)
|
||||
|
||||
Backbone.Mediator.publish 'store:item-purchased', item: item, itemSlug: item.get('slug')
|
||||
else
|
||||
button.addClass('confirm').text($.i18n.t('play.confirm'))
|
||||
@$el.one 'click', (e) ->
|
||||
button.removeClass('confirm').text($.i18n.t('play.unlock')) if e.target isnt button[0]
|
||||
|
||||
|
||||
#- Select/equip higher-level, all encompassing methods the callbacks all use
|
||||
|
||||
selectItemSlot: (slotEl) ->
|
||||
|
@ -470,7 +440,70 @@ module.exports = class InventoryModal extends ModalView
|
|||
else
|
||||
callback?()
|
||||
|
||||
#- TODO: DRY this between PlayItemsModal and InventoryModal
|
||||
|
||||
onUnlockButtonClicked: (e) ->
|
||||
e.stopPropagation()
|
||||
button = $(e.target).closest('button')
|
||||
item = @items.get(button.data('item-id'))
|
||||
affordable = item.affordable
|
||||
if not affordable
|
||||
@askToBuyGems button
|
||||
else if button.hasClass('confirm')
|
||||
purchase = Purchase.makeFor(item)
|
||||
purchase.save()
|
||||
|
||||
#- set local changes to mimic what should happen on the server...
|
||||
purchased = me.get('purchased') ? {}
|
||||
purchased.items ?= []
|
||||
purchased.items.push(item.get('original'))
|
||||
|
||||
me.set('purchased', purchased)
|
||||
me.set('spent', (me.get('spent') ? 0) + item.get('gems'))
|
||||
|
||||
#- ...then rerender key bits
|
||||
@itemGroups.lockedItems.remove(item)
|
||||
# Redo all item sorting to make sure that we don't clobber state changes since last render.
|
||||
equipped = _.values @getCurrentEquipmentConfig()
|
||||
@sortItem(item, equipped) for item in @items.models
|
||||
@renderSelectors('#unequipped', '#gems-count')
|
||||
|
||||
@requireLevelEquipment()
|
||||
@delegateEvents()
|
||||
@setUpDraggableEventsForAvailableEquipment()
|
||||
@itemDetailsView.setItem(item)
|
||||
|
||||
Backbone.Mediator.publish 'store:item-purchased', item: item, itemSlug: item.get('slug')
|
||||
else
|
||||
button.addClass('confirm').text($.i18n.t('play.confirm'))
|
||||
@$el.one 'click', (e) ->
|
||||
button.removeClass('confirm').text($.i18n.t('play.unlock')) if e.target isnt button[0]
|
||||
|
||||
askToBuyGems: (unlockButton) ->
|
||||
if me.getGemPromptGroup() is 'no-prompt'
|
||||
return @openModalView new BuyGemsModal()
|
||||
@$el.find('.unlock-button').popover 'destroy'
|
||||
popoverTemplate = buyGemsPromptTemplate {}
|
||||
unlockButton.popover(
|
||||
animation: true
|
||||
trigger: 'manual'
|
||||
placement: 'top'
|
||||
content: ' ' # template has it
|
||||
container: @$el
|
||||
template: popoverTemplate
|
||||
).popover 'show'
|
||||
popover = unlockButton.data('bs.popover')
|
||||
popover?.$tip?.i18n()
|
||||
|
||||
onBuyGemsPromptButtonClicked: (e) ->
|
||||
@openModalView new BuyGemsModal()
|
||||
|
||||
onClickedSomewhere: (e) ->
|
||||
return if @destroyed
|
||||
@$el.find('.unlock-button').popover 'destroy'
|
||||
|
||||
destroy: ->
|
||||
@$el.find('.unlock-button').popover 'destroy'
|
||||
@stage?.removeAllChildren()
|
||||
super()
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/play/modal/play-items-modal'
|
||||
buyGemsPromptTemplate = require 'templates/play/modal/buy-gems-prompt'
|
||||
ItemDetailsView = require './ItemDetailsView'
|
||||
BuyGemsModal = require 'views/play/modal/BuyGemsModal'
|
||||
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
ThangType = require 'models/ThangType'
|
||||
|
@ -46,7 +48,9 @@ module.exports = class PlayItemsModal extends ModalView
|
|||
'click .item': 'onItemClicked'
|
||||
'shown.bs.tab': 'onTabClicked'
|
||||
'click .unlock-button': 'onUnlockButtonClicked'
|
||||
'click .buy-gems-prompt-button': 'onBuyGemsPromptButtonClicked'
|
||||
'click #close-modal': 'hide'
|
||||
'click': 'onClickedSomewhere'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
|
@ -89,7 +93,7 @@ module.exports = class PlayItemsModal extends ModalView
|
|||
model.affordable = cost <= gemsOwned
|
||||
model.silhouetted = not model.owned and model.isSilhouettedItem()
|
||||
model.level = model.levelRequiredForItem() if model.get('tier')?
|
||||
model.unequippable = not ('Warrior' in model.getAllowedHeroClasses()) # Temp: while there are no wizards/rangers
|
||||
model.unequippable = not _.intersection(me.getHeroClasses(), model.getAllowedHeroClasses()).length
|
||||
model.comingSoon = not model.getFrontFacingStats().props.length and not _.size(model.getFrontFacingStats().stats) and not model.owned # Temp: while there are placeholder items
|
||||
@idToItem[model.id] = model
|
||||
|
||||
|
@ -140,9 +144,14 @@ module.exports = class PlayItemsModal extends ModalView
|
|||
$($(e.target).attr('href')).find('.nano').nanoScroller({alwaysVisible: true})
|
||||
|
||||
onUnlockButtonClicked: (e) ->
|
||||
e.stopPropagation()
|
||||
button = $(e.target).closest('button')
|
||||
if button.hasClass('confirm')
|
||||
item = @idToItem[$(e.target).data('item-id')]
|
||||
item = @idToItem[button.data('item-id')]
|
||||
affordable = item.affordable
|
||||
if not affordable
|
||||
@askToBuyGems button
|
||||
else if button.hasClass('confirm')
|
||||
|
||||
purchase = Purchase.makeFor(item)
|
||||
purchase.save()
|
||||
|
||||
|
@ -163,3 +172,29 @@ module.exports = class PlayItemsModal extends ModalView
|
|||
button.addClass('confirm').text($.i18n.t('play.confirm'))
|
||||
@$el.one 'click', (e) ->
|
||||
button.removeClass('confirm').text($.i18n.t('play.unlock')) if e.target isnt button[0]
|
||||
|
||||
askToBuyGems: (unlockButton) ->
|
||||
if me.getGemPromptGroup() is 'no-prompt'
|
||||
return @openModalView new BuyGemsModal()
|
||||
@$el.find('.unlock-button').popover 'destroy'
|
||||
popoverTemplate = buyGemsPromptTemplate {}
|
||||
unlockButton.popover(
|
||||
animation: true
|
||||
trigger: 'manual'
|
||||
content: ' ' # template has it
|
||||
container: @$el
|
||||
template: popoverTemplate
|
||||
).popover 'show'
|
||||
popover = unlockButton.data('bs.popover')
|
||||
popover?.$tip?.i18n()
|
||||
|
||||
onBuyGemsPromptButtonClicked: (e) ->
|
||||
@openModalView new BuyGemsModal()
|
||||
|
||||
onClickedSomewhere: (e) ->
|
||||
return if @destroyed
|
||||
@$el.find('.unlock-button').popover 'destroy'
|
||||
|
||||
destroy: ->
|
||||
@$el.find('.unlock-button').popover 'destroy'
|
||||
super()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue