mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-25 12:20:32 -04:00
Merge branch 'master' into production
This commit is contained in:
commit
ce4567c868
12 changed files with 854 additions and 751 deletions
app
locale
styles
templates
views
server/purchases
|
@ -301,10 +301,13 @@
|
|||
choose_inventory: "Equip Items"
|
||||
equipped_item: "Equipped"
|
||||
available_item: "Available"
|
||||
restricted_title: "Restricted"
|
||||
should_equip: "(double-click to equip)"
|
||||
equipped: "(equipped)"
|
||||
locked: "(locked)"
|
||||
restricted: "(restricted in this level)"
|
||||
equip: "Equip"
|
||||
unequip: "Unequip"
|
||||
|
||||
choose_hero:
|
||||
choose_hero: "Choose Your Hero"
|
||||
|
|
|
@ -1,18 +1,8 @@
|
|||
@import "app/styles/mixins"
|
||||
|
||||
$totalWidth: 706px - 2 * 20px
|
||||
$inventoryHeight: 445px
|
||||
$equippedWidth: 450px
|
||||
$itemSlotMargin: 5px
|
||||
$itemSlotSize: ($equippedWidth - 6 * 2 * $itemSlotMargin) / 6
|
||||
$itemSlotSizeWithMargin: $itemSlotSize + 2 * $itemSlotMargin
|
||||
$itemSlotBorderWidth: 2px
|
||||
$itemSlotInnerWidth: $itemSlotSize - 2 * $itemSlotBorderWidth
|
||||
$heroContainerWidth: 4 * $itemSlotSizeWithMargin
|
||||
$heroContainerHeight: $inventoryHeight - $itemSlotSizeWithMargin
|
||||
$selectedAreaHeight: 150px
|
||||
$stashMargin: 20px
|
||||
$stashWidth: $totalWidth - $equippedWidth - $stashMargin
|
||||
$itemSlotSize: 55px
|
||||
$itemSlotInnerWidth: $itemSlotSize - 4
|
||||
$itemSlotGridHeight: 70px
|
||||
|
||||
.ui-effects-transfer
|
||||
outline: 2px solid #28f
|
||||
|
@ -20,318 +10,434 @@ $stashWidth: $totalWidth - $equippedWidth - $stashMargin
|
|||
z-index: 9001
|
||||
|
||||
#inventory-modal
|
||||
|
||||
//- Overall modal structure
|
||||
.modal-dialog
|
||||
margin: 30px auto 0 auto
|
||||
width: 720px
|
||||
width: 1017px
|
||||
height: 660px
|
||||
|
||||
.modal-content
|
||||
height: 100%
|
||||
width: 100%
|
||||
|
||||
.modal-body
|
||||
height: 450px
|
||||
margin: 0
|
||||
|
||||
+user-select(none)
|
||||
|
||||
h3
|
||||
.modal-body
|
||||
height: 450px
|
||||
margin: 0
|
||||
|
||||
.draggable-item
|
||||
width: $itemSlotSize
|
||||
height: $itemSlotSize
|
||||
+user-select(none)
|
||||
|
||||
|
||||
//- Background
|
||||
|
||||
#play-items-modal-narrow-bg
|
||||
position: absolute
|
||||
top: -69px
|
||||
left: -8px
|
||||
|
||||
|
||||
//- Gems count
|
||||
|
||||
#gems-count-container
|
||||
position: absolute
|
||||
left: 213px
|
||||
top: 10px
|
||||
width: 160px
|
||||
height: 66px
|
||||
@include rotate(5deg)
|
||||
|
||||
#gems-count
|
||||
position: absolute
|
||||
left: 75px
|
||||
top: 17px
|
||||
font-size: 25px
|
||||
color: rgb(1,64,91)
|
||||
|
||||
|
||||
//- Close modal button
|
||||
|
||||
#close-modal
|
||||
position: absolute
|
||||
left: 390px
|
||||
top: 23px
|
||||
width: 60px
|
||||
height: 60px
|
||||
color: white
|
||||
text-align: center
|
||||
font-size: 30px
|
||||
padding-top: 7px
|
||||
cursor: pointer
|
||||
@include rotate(-3deg)
|
||||
|
||||
&:hover
|
||||
color: yellow
|
||||
|
||||
|
||||
//- Equipped area
|
||||
|
||||
#equipped
|
||||
width: $equippedWidth
|
||||
width: 330px
|
||||
background: white
|
||||
border: 3px solid black
|
||||
position: absolute
|
||||
left: 20px
|
||||
top: 0
|
||||
bottom: 0
|
||||
//bottom: $selectedAreaHeight + 10
|
||||
right: 0
|
||||
top: 112px
|
||||
height: 450px
|
||||
overflow: hidden
|
||||
|
||||
.item-slot-row
|
||||
//background-color: rgba(35, 112, 124, 0.5)
|
||||
height: $itemSlotSizeWithMargin
|
||||
clear: both
|
||||
margin: 0px auto
|
||||
#hero-image
|
||||
@include filter(contrast(0%) brightness(0%))
|
||||
opacity: 0.4
|
||||
width: 225px
|
||||
height: 410px
|
||||
position: absolute
|
||||
left: 10px
|
||||
top: 20px
|
||||
|
||||
&.row-4
|
||||
width: 4 * $itemSlotSizeWithMargin
|
||||
|
||||
.item-slot-column
|
||||
//background-color: rgba(112, 124, 35, 0.5)
|
||||
width: $itemSlotSizeWithMargin
|
||||
height: 5 * $itemSlotSizeWithMargin
|
||||
float: left
|
||||
//margin-top: 30px
|
||||
|
||||
.item-slot
|
||||
width: $itemSlotSize
|
||||
height: $itemSlotSize
|
||||
margin: $itemSlotMargin
|
||||
background-color: white
|
||||
float: left
|
||||
margin: 5px
|
||||
background-color: rgba(255,255,255,0.4)
|
||||
border: 2px dashed rgb(100,100,150)
|
||||
position: relative
|
||||
cursor: pointer
|
||||
@include transition(0.5s ease)
|
||||
|
||||
&.selected
|
||||
.placeholder, .item-container .item-view img
|
||||
border-color: #28f
|
||||
@include box-shadow(0 0 10px #28f)
|
||||
|
||||
//&.disabled
|
||||
// opacity: 0.5
|
||||
|
||||
&.selected
|
||||
.placeholder, img.item
|
||||
border-color: rgb(81,153,236)
|
||||
background-color: rgb(81,153,236)
|
||||
@include box-shadow(0 0 10px rgb(81,153,236))
|
||||
img.item
|
||||
background: rgb(81,153,236)
|
||||
|
||||
&.should-equip
|
||||
background-color: #8fa
|
||||
outline: 2px solid #8af
|
||||
@include box-shadow(2px 2px 4px black)
|
||||
|
||||
|
||||
&.droppable
|
||||
outline: 2px solid blue
|
||||
@include box-shadow(4px 4px 6px black)
|
||||
|
||||
|
||||
&.droppable-hover
|
||||
outline: 4px solid blue
|
||||
@include box-shadow(6px 6px 8px black)
|
||||
|
||||
|
||||
.placeholder
|
||||
width: 100%
|
||||
height: 100%
|
||||
background-size: cover
|
||||
border: $itemSlotBorderWidth solid #888
|
||||
@include opacity(0.4)
|
||||
@include opacity(0.7)
|
||||
background-image: url(/images/pages/game-menu/slot-icons.png)
|
||||
|
||||
|
||||
&[data-slot="misc-1"] .placeholder
|
||||
background-position: (-0 * $itemSlotInnerWidth) 0px
|
||||
// A terrible awful bit of styling, but will be gone or messed around with soon anyway
|
||||
|
||||
&[data-slot="minion"] .placeholder
|
||||
background-position: (-1 * $itemSlotInnerWidth) 0px
|
||||
&[data-slot="misc-1"]
|
||||
display: none // hiding for now
|
||||
position: absolute
|
||||
left: 250px
|
||||
top: 20px + ($itemSlotGridHeight * 3)
|
||||
.placeholder
|
||||
background-position: (-0 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="misc-0"]
|
||||
display: none // hiding for now
|
||||
position: absolute
|
||||
left: 250px
|
||||
top: 20px + ($itemSlotGridHeight * 2)
|
||||
.placeholder
|
||||
background-position: (-4 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="programming-book"] .placeholder
|
||||
background-position: (-3 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="minion"]
|
||||
position: absolute
|
||||
left: 250px
|
||||
top: 20px + ($itemSlotGridHeight * 1)
|
||||
.placeholder
|
||||
background-position: (-1 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="programming-book"]
|
||||
position: absolute
|
||||
left: 250px
|
||||
top: 20px + ($itemSlotGridHeight * 4)
|
||||
.placeholder
|
||||
background-position: (-3 * $itemSlotInnerWidth) 0px
|
||||
|
||||
// Only for wizards...
|
||||
//&[data-slot="spellbook"] .placeholder
|
||||
// background-position: (-2 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="misc-0"] .placeholder
|
||||
background-position: (-4 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="wrists"] .placeholder
|
||||
background-position: (-5 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="left-ring"] .placeholder
|
||||
background-position: (-6 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="right-ring"] .placeholder
|
||||
background-position: (-7 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="torso"] .placeholder
|
||||
background-position: (-8 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="feet"] .placeholder
|
||||
background-position: (-9 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="neck"] .placeholder
|
||||
background-position: (-10 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="waist"] .placeholder
|
||||
background-position: (-11 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="eyes"] .placeholder
|
||||
background-position: (-12 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="head"] .placeholder
|
||||
background-position: (-13 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="pet"] .placeholder
|
||||
background-position: (-14 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="gloves"] .placeholder
|
||||
background-position: (-15 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="left-hand"] .placeholder
|
||||
background-position: (-16 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="right-hand"] .placeholder
|
||||
background-position: (-17 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="flag"] .placeholder
|
||||
//background-position: (-18 * $itemSlotInnerWidth) 0px
|
||||
background-position: (-2 * $itemSlotInnerWidth) 0px
|
||||
|
||||
.item-container
|
||||
|
||||
&[data-slot="wrists"]
|
||||
position: absolute
|
||||
left: 0
|
||||
top: 0
|
||||
left: 20px
|
||||
top: 20px + ($itemSlotGridHeight * 2.5)
|
||||
.placeholder
|
||||
background-position: (-5 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="left-ring"]
|
||||
position: absolute
|
||||
left: 250px
|
||||
top: 20px + ($itemSlotGridHeight * 2)
|
||||
.placeholder
|
||||
background-position: (-6 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="right-ring"]
|
||||
position: absolute
|
||||
left: 250px
|
||||
top: 20px + ($itemSlotGridHeight * 3)
|
||||
.placeholder
|
||||
background-position: (-7 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="torso"]
|
||||
position: absolute
|
||||
left: 90px
|
||||
top: 20px + ($itemSlotGridHeight * 3)
|
||||
.placeholder
|
||||
background-position: (-8 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="feet"]
|
||||
position: absolute
|
||||
left: 90px
|
||||
top: 20px + ($itemSlotGridHeight * 5)
|
||||
.placeholder
|
||||
background-position: (-9 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="neck"]
|
||||
position: absolute
|
||||
left: 90px
|
||||
top: 20px + ($itemSlotGridHeight * 2)
|
||||
.placeholder
|
||||
background-position: (-10 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="waist"]
|
||||
position: absolute
|
||||
left: 90px
|
||||
top: 20px + ($itemSlotGridHeight * 4)
|
||||
.placeholder
|
||||
background-position: (-11 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="eyes"]
|
||||
position: absolute
|
||||
left: 90px
|
||||
top: 20px + $itemSlotGridHeight
|
||||
.placeholder
|
||||
background-position: (-12 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="head"]
|
||||
position: absolute
|
||||
left: 90px
|
||||
top: 20px
|
||||
.placeholder
|
||||
background-position: (-13 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="pet"]
|
||||
position: absolute
|
||||
left: 250px
|
||||
top: 20px
|
||||
.placeholder
|
||||
background-position: (-14 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="gloves"]
|
||||
position: absolute
|
||||
left: 160px
|
||||
top: 20px + ($itemSlotGridHeight * 2.5)
|
||||
.placeholder
|
||||
background-position: (-15 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="left-hand"]
|
||||
position: absolute
|
||||
left: 160px
|
||||
top: 20px + ($itemSlotGridHeight * 3.5)
|
||||
.placeholder
|
||||
background-position: (-16 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="right-hand"]
|
||||
position: absolute
|
||||
left: 20px
|
||||
top: 20px + ($itemSlotGridHeight * 3.5)
|
||||
.placeholder
|
||||
background-position: (-17 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="flag"]
|
||||
position: absolute
|
||||
left: 250px
|
||||
top: 20px + ($itemSlotGridHeight * 5)
|
||||
.placeholder
|
||||
background-position: (-2 * $itemSlotInnerWidth) 0px
|
||||
|
||||
img.item
|
||||
position: absolute
|
||||
left: -2px
|
||||
top: -2px
|
||||
|
||||
.item-view
|
||||
img
|
||||
width: $itemSlotSize
|
||||
height: $itemSlotSize
|
||||
border: 2px solid black
|
||||
background-color: white
|
||||
width: $itemSlotSize
|
||||
height: $itemSlotSize
|
||||
border: 2px solid black
|
||||
background-color: white
|
||||
|
||||
.item-info
|
||||
display: none
|
||||
|
||||
//- dragging styling
|
||||
|
||||
#equipped
|
||||
|
||||
.item-slot.disabled
|
||||
opacity: 0.5
|
||||
&.droppable
|
||||
outline: 2px solid blue
|
||||
@include box-shadow(4px 4px 6px black)
|
||||
|
||||
.hero-container
|
||||
//background-color: rgba(31, 0, 200, 0.25)
|
||||
float: left
|
||||
position: relative
|
||||
@include transition(0.5s ease)
|
||||
&.droppable-hover
|
||||
outline: 4px solid blue
|
||||
@include box-shadow(6px 6px 8px black)
|
||||
|
||||
.draggable-item
|
||||
width: $itemSlotSize * 1.2
|
||||
height: $itemSlotSize * 1.2
|
||||
|
||||
&.droppable
|
||||
outline: 2px solid blue
|
||||
@include box-shadow(4px 4px 6px black)
|
||||
|
||||
&.droppable-hover
|
||||
outline: 4px solid blue
|
||||
@include box-shadow(6px 6px 8px black)
|
||||
|
||||
.equipped-hero-canvas, .hero-feature-image
|
||||
width: $heroContainerWidth
|
||||
height: $heroContainerHeight
|
||||
|
||||
.hero-feature-image
|
||||
text-align: center
|
||||
|
||||
img
|
||||
height: $heroContainerHeight
|
||||
|
||||
#available-equipment
|
||||
width: $stashWidth
|
||||
position: absolute
|
||||
right: 20px
|
||||
top: 0
|
||||
bottom: 0
|
||||
overflow-y: scroll
|
||||
border: 2px solid #ccc
|
||||
padding: 4px
|
||||
background-color: white
|
||||
|
||||
&.Warrior .list-group-item:not(.Warrior), &.Ranger .list-group-item:not(.Ranger), &.Wizard .list-group-item:not(.Wizard)
|
||||
|
||||
//- Available equipment
|
||||
|
||||
&.Warrior #unequipped img.item:not(.Warrior), &.Ranger #unequipped img.item:not(.Ranger), &.Wizard #unequipped img.item:not(.Wizard)
|
||||
// Our code hides and shows (modifies display), but we can be invisible this other way.
|
||||
visibility: hidden
|
||||
position: absolute
|
||||
|
||||
.list-group-item
|
||||
padding: 4px 0
|
||||
@include transition(0.5s ease)
|
||||
|
||||
&.active
|
||||
background-color: #e0f0f5
|
||||
|
||||
.status-message .should-equip-message
|
||||
display: inline
|
||||
|
||||
&.should-equip
|
||||
background-color: #8fa
|
||||
outline: 2px solid #8af
|
||||
@include box-shadow(4px 4px 6px black)
|
||||
z-index: 1
|
||||
|
||||
.status-message .should-equip-message
|
||||
display: inline
|
||||
font-weight: bold
|
||||
|
||||
&.equipped
|
||||
background-color: #ff5
|
||||
|
||||
.item-view
|
||||
cursor: default
|
||||
|
||||
.status-message .equipped-message
|
||||
display: inline
|
||||
|
||||
&.restricted
|
||||
background-color: rgba(255, 80, 67, 0.25)
|
||||
|
||||
.item-view
|
||||
cursor: default
|
||||
|
||||
.status-message .restricted-message
|
||||
display: inline
|
||||
|
||||
&.locked
|
||||
background-image: url(/images/pages/game-menu/lock.png)
|
||||
background-size: 25px 25px
|
||||
background-repeat: no-repeat
|
||||
background-position: 98% 90%
|
||||
|
||||
.item-view
|
||||
cursor: default
|
||||
|
||||
h4, img
|
||||
//@include filter(contrast(50%) brightness(65%))
|
||||
@include opacity(0.6)
|
||||
|
||||
.status-message .locked-message
|
||||
display: inline
|
||||
|
||||
&.silhouette
|
||||
h4
|
||||
visibility: hidden
|
||||
position: absolute
|
||||
h4:before
|
||||
content: '???'
|
||||
visibility: visible
|
||||
.item-view .status-message .locked-message
|
||||
display: none
|
||||
img
|
||||
@include filter(contrast(25%) brightness(25%))
|
||||
|
||||
.item-view
|
||||
cursor: pointer
|
||||
|
||||
#selected-items
|
||||
$selectedItemsContainerMargin: 20px
|
||||
$selectedItemMargin: 10px
|
||||
$selectedItemImageSize: 75px
|
||||
|
||||
#unequipped
|
||||
width: 222px
|
||||
position: absolute
|
||||
top: $selectedItemsContainerMargin
|
||||
right: $selectedItemsContainerMargin
|
||||
bottom: $selectedItemsContainerMargin
|
||||
left: $selectedItemsContainerMargin
|
||||
text-align: center
|
||||
left: 370px
|
||||
top: 112px
|
||||
height: 450px
|
||||
border: 3px solid black
|
||||
padding: 9px 0 9px 9px
|
||||
background-color: white
|
||||
|
||||
#selected-equipped-item, #selected-available-item
|
||||
text-align: left
|
||||
overflow-y: scroll
|
||||
margin: 0
|
||||
height: 48.4%
|
||||
height: -webkit-calc(50% - $selectedItemMargin / 2)
|
||||
height: calc(50% - $selectedItemMargin / 2)
|
||||
width: 100%
|
||||
padding: 10px 5px 10px 10px
|
||||
position: relative
|
||||
display: none
|
||||
#double-click-hint
|
||||
margin: 20px 0 70px
|
||||
|
||||
h4
|
||||
clear: both
|
||||
margin-bottom: 10px
|
||||
margin-top: 20px
|
||||
font-size: 24px
|
||||
text-transform: uppercase
|
||||
font-weight: bold
|
||||
|
||||
img.item
|
||||
float: left
|
||||
border: 1px solid black
|
||||
margin: 3px
|
||||
padding: 1px
|
||||
width: 60px
|
||||
height: 60px
|
||||
cursor: pointer
|
||||
|
||||
&.active
|
||||
background-color: rgb(81,153,236)
|
||||
|
||||
//.status-message .should-equip-message
|
||||
// display: inline
|
||||
|
||||
img
|
||||
margin-top: 21px
|
||||
width: $selectedItemImageSize
|
||||
height: $selectedItemImageSize
|
||||
margin-right: 10px
|
||||
&.should-equip
|
||||
background-color: #8fa
|
||||
outline: 2px solid #8af
|
||||
@include box-shadow(4px 4px 6px black)
|
||||
z-index: 1
|
||||
|
||||
//.status-message .should-equip-message
|
||||
// display: inline
|
||||
// font-weight: bold
|
||||
|
||||
.item-info
|
||||
width: 110px
|
||||
width: -webkit-calc(100% - 75px - 10px)
|
||||
width: calc(100% - 75px - 10px)
|
||||
&.equipped
|
||||
background-color: #ff5
|
||||
display: none
|
||||
cursor: default
|
||||
|
||||
//.item-view
|
||||
// cursor: default
|
||||
//
|
||||
//.status-message .equipped-message
|
||||
// display: inline
|
||||
|
||||
&.restricted
|
||||
background-color: rgba(255, 80, 67, 0.25)
|
||||
cursor: default
|
||||
|
||||
//.item-view
|
||||
// cursor: default
|
||||
//
|
||||
//.status-message .restricted-message
|
||||
// display: inline
|
||||
|
||||
&.locked
|
||||
cursor: default
|
||||
//background-color: gray
|
||||
|
||||
&.silhouette
|
||||
cursor: default
|
||||
pointer-events: none
|
||||
@include filter(contrast(25%) brightness(25%))
|
||||
opacity: 0.5
|
||||
|
||||
|
||||
//- Hero/Play buttons
|
||||
|
||||
> h3
|
||||
position: absolute
|
||||
left: 0px
|
||||
top: 0px
|
||||
padding: 5px
|
||||
#choose-hero-button, #play-level-button
|
||||
top: 572px
|
||||
position: absolute
|
||||
background: url(/images/pages/play/modal/confirm-button.png)
|
||||
width: 209px
|
||||
height: 65px
|
||||
background-size: 209px 65px
|
||||
border: 0
|
||||
|
||||
#selected-equipped-item
|
||||
margin-bottom: $selectedItemMargin
|
||||
padding-bottom: 20px
|
||||
background-color: #ff5
|
||||
&:disabled
|
||||
opacity: 1
|
||||
@include filter(grayscale(100%))
|
||||
|
||||
|
||||
#choose-hero-button
|
||||
left: 20px
|
||||
|
||||
#play-level-button
|
||||
right: 414px
|
||||
|
||||
#selected-available-item
|
||||
padding-top: 15px
|
||||
background-color: #e0f0f5
|
||||
bottom: 0
|
||||
|
||||
//- Item details. Non-specific item-details-view styling is in item-details-view.sass.
|
||||
|
||||
#item-details-view
|
||||
|
||||
#item-title
|
||||
left: 698px
|
||||
top: 56px
|
||||
|
||||
#item-details-body
|
||||
left: 650px
|
||||
|
||||
#selected-item-unlock-button
|
||||
left: 646px
|
||||
|
||||
|
||||
//- Equip/unequip/extra
|
||||
|
||||
#item-details-extra
|
||||
position: absolute
|
||||
left: 644px
|
||||
top: 589px
|
||||
|
||||
& > *
|
||||
width: 338px
|
||||
height: 50px
|
||||
|
||||
.alert
|
||||
text-align: center
|
||||
font-weight: bold
|
||||
|
||||
button
|
||||
border: 3px solid rgb(46,46,46)
|
||||
background: white
|
||||
font-size: 16px
|
||||
|
|
82
app/styles/play/modal/item-details-view.sass
Normal file
82
app/styles/play/modal/item-details-view.sass
Normal file
|
@ -0,0 +1,82 @@
|
|||
#item-details-view
|
||||
|
||||
.nano-content
|
||||
padding: 10px
|
||||
|
||||
#item-title
|
||||
position: absolute
|
||||
width: 228px
|
||||
height: 50px
|
||||
left: 910px
|
||||
top: 60px
|
||||
z-index: 2
|
||||
|
||||
h2
|
||||
font-size: 20px
|
||||
margin: 12px 20px
|
||||
text-align: center
|
||||
color: rgb(53,40,25)
|
||||
|
||||
#item-details-body
|
||||
position: absolute
|
||||
left: 860px
|
||||
top: 126px
|
||||
width: 330px
|
||||
height: 449px
|
||||
//background: rgba(100,100,100,0.5)
|
||||
|
||||
#item-container
|
||||
height: 163px
|
||||
width: 100%
|
||||
|
||||
.item-img, .item-shadow
|
||||
width: 130px
|
||||
height: 130px
|
||||
|
||||
.item-img
|
||||
top: 15px
|
||||
|
||||
.item-shadow
|
||||
top: 25px
|
||||
|
||||
img.hr
|
||||
width: 80%
|
||||
margin: 0 10% -3px
|
||||
|
||||
&.faded
|
||||
opacity: 0.4
|
||||
|
||||
.stat-row
|
||||
height: 24px
|
||||
position: relative
|
||||
font-size: 20px
|
||||
font-weight: bold
|
||||
|
||||
.stat-label
|
||||
position: absolute
|
||||
left: 54px
|
||||
color: rgb(93,73,52)
|
||||
|
||||
.stat
|
||||
position: absolute
|
||||
left: 150px
|
||||
color: rgb(42,38,28)
|
||||
|
||||
#skills
|
||||
margin: 25px
|
||||
|
||||
h3
|
||||
color: rgb(41,35,25)
|
||||
|
||||
strong
|
||||
color: rgb(50,50,30)
|
||||
|
||||
#selected-item-unlock-button
|
||||
left: 856px
|
||||
top: 594px
|
||||
width: 337px
|
||||
height: 41px
|
||||
font-size: 16px
|
||||
|
||||
img
|
||||
height: 16px
|
|
@ -123,8 +123,8 @@
|
|||
.tab-pane
|
||||
height: 100%
|
||||
|
||||
.nano-content
|
||||
padding: 26px 51px 26px 26px
|
||||
.nano-content
|
||||
padding: 26px 51px 26px 26px
|
||||
|
||||
|
||||
//- Item box
|
||||
|
@ -222,6 +222,23 @@
|
|||
background: url(/images/pages/play/modal/item-box-background-selected.png)
|
||||
|
||||
|
||||
//- Item details. Non-specific item-details-view styling is in item-details-view.sass.
|
||||
|
||||
#item-details-view
|
||||
|
||||
#item-title
|
||||
left: 910px
|
||||
top: 60px
|
||||
|
||||
#item-details-body
|
||||
left: 860px
|
||||
|
||||
#selected-item-unlock-button
|
||||
left: 856px
|
||||
|
||||
|
||||
#play-items-modal, #inventory-modal
|
||||
|
||||
//- Item list scrollbar
|
||||
|
||||
.nano-pane
|
||||
|
@ -236,86 +253,6 @@
|
|||
margin-left: -3px
|
||||
margin-right: -3px
|
||||
|
||||
// color: red
|
||||
|
||||
|
||||
//- Item details
|
||||
|
||||
#item-title
|
||||
position: absolute
|
||||
width: 228px
|
||||
height: 50px
|
||||
left: 910px
|
||||
top: 60px
|
||||
z-index: 2
|
||||
|
||||
h2
|
||||
font-size: 20px
|
||||
margin: 12px 20px
|
||||
text-align: center
|
||||
color: rgb(53,40,25)
|
||||
|
||||
#item-details-body
|
||||
position: absolute
|
||||
left: 860px
|
||||
top: 126px
|
||||
width: 330px
|
||||
height: 449px
|
||||
//background: rgba(100,100,100,0.5)
|
||||
|
||||
#item-container
|
||||
height: 163px
|
||||
width: 100%
|
||||
|
||||
.item-img, .item-shadow
|
||||
width: 130px
|
||||
height: 130px
|
||||
|
||||
.item-img
|
||||
top: 15px
|
||||
|
||||
.item-shadow
|
||||
top: 25px
|
||||
|
||||
img.hr
|
||||
width: 80%
|
||||
margin: 0 10% -3px
|
||||
|
||||
&.faded
|
||||
opacity: 0.4
|
||||
|
||||
.stat-row
|
||||
height: 24px
|
||||
position: relative
|
||||
font-size: 20px
|
||||
font-weight: bold
|
||||
|
||||
.stat-label
|
||||
position: absolute
|
||||
left: 54px
|
||||
color: rgb(93,73,52)
|
||||
|
||||
.stat
|
||||
position: absolute
|
||||
left: 150px
|
||||
color: rgb(42,38,28)
|
||||
|
||||
#skills
|
||||
margin: 25px
|
||||
|
||||
h3
|
||||
color: rgb(41,35,25)
|
||||
|
||||
strong
|
||||
color: rgb(50,50,30)
|
||||
|
||||
#selected-item-unlock-button
|
||||
left: 856px
|
||||
top: 594px
|
||||
width: 337px
|
||||
height: 41px
|
||||
font-size: 16px
|
||||
|
||||
|
||||
//- Item icons w/shadows (both in list and details areas)
|
||||
|
||||
|
@ -355,6 +292,9 @@
|
|||
opacity: 1
|
||||
color: rgba(255,255,255, 0.4)
|
||||
|
||||
|
||||
//- Use the two-column layout and background image if we are on a narrow screen.
|
||||
|
||||
@media only screen and (max-width: 1300px)
|
||||
#play-items-modal
|
||||
overflow-x: hidden
|
||||
|
|
|
@ -1,68 +1,52 @@
|
|||
extends /templates/modal/modal_base
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
img(src="/images/pages/play/modal/items-background-narrow.png")#play-items-modal-narrow-bg
|
||||
|
||||
block modal-header-content
|
||||
h1#choose-inventory-header.choose-inventory-active(data-i18n="inventory.choose_inventory") Equip Items
|
||||
div#gems-count-container
|
||||
span#gems-count.big-font= gems
|
||||
|
||||
block modal-body-content
|
||||
#equipped
|
||||
.item-slot-row
|
||||
for slot in ['left-ring', 'neck', 'eyes', 'head', 'wrists', 'right-ring']
|
||||
div#close-modal
|
||||
span.glyphicon.glyphicon-remove
|
||||
|
||||
#equipped
|
||||
if selectedHero
|
||||
img(src="/file/"+selectedHero.get('featureImage'))#hero-image
|
||||
|
||||
for slot in ['head', 'eyes', 'neck', 'torso', 'gloves', 'wrists', 'left-hand', 'right-hand', 'waist', 'feet', 'left-ring', 'right-ring', 'minion', 'flag', 'pet', 'programming-book', 'misc-0', 'misc-1']
|
||||
.item-slot(data-slot=slot)
|
||||
.placeholder
|
||||
.item-container
|
||||
if equipment[slot]
|
||||
.replace-me(data-item-id=equipment[slot].get('original'))
|
||||
|
||||
.item-slot-column.pull-left
|
||||
// TODO: add in 'misc-0' again somehow? Used to be where 'flag' is now.
|
||||
for slot in ['minion', 'torso', 'gloves', 'left-hand', 'flag']
|
||||
.item-slot(data-slot=slot)
|
||||
.placeholder
|
||||
.item-container
|
||||
if equipment[slot]
|
||||
.replace-me(data-item-id=equipment[slot].get('original'))
|
||||
|
||||
.hero-container
|
||||
canvas.equipped-hero-canvas
|
||||
.hero-feature-image
|
||||
img
|
||||
#selected-items
|
||||
#selected-equipped-item.well
|
||||
h3(data-i18n="inventory.equipped_item") Equipped
|
||||
.item-view-stub
|
||||
#selected-available-item.well
|
||||
h3(data-i18n="inventory.available_item") Available
|
||||
.item-view-stub
|
||||
|
||||
.item-slot-column.pull-right
|
||||
for slot in ['pet', 'waist', 'feet', 'right-hand', 'programming-book']
|
||||
.item-slot(data-slot=slot)
|
||||
.placeholder
|
||||
.item-container
|
||||
if equipment[slot]
|
||||
.replace-me(data-item-id=equipment[slot].get('original'))
|
||||
|
||||
// TODO: work in misc 1 again
|
||||
//hr.slot-row-separator
|
||||
//
|
||||
//.item-slot-row.row-4
|
||||
// for slot in ['misc-1']
|
||||
// .item-slot(data-slot=slot)
|
||||
// .placeholder
|
||||
// .item-container
|
||||
// if equipment[slot]
|
||||
// .replace-me(data-item-id=equipment[slot].get('original'))
|
||||
|
||||
#available-equipment
|
||||
h4#unlocked-description
|
||||
ul.list-group
|
||||
for item in unlockedItems
|
||||
li.list-group-item(class=item.classes, data-item-id=item.get('original'))
|
||||
h4#locked-description
|
||||
ul.list-group
|
||||
for item in lockedItems
|
||||
li.list-group-item(class=item.classes, data-item-id=item.get('original'), style="display: none")
|
||||
if equipment[slot]
|
||||
img.item(src=equipment[slot].getPortraitURL(), data-item-id=equipment[slot].id)
|
||||
|
||||
block modal-footer-content
|
||||
button#choose-hero-button.btn.btn-lg.btn-primary.choose-inventory-active.pull-left(data-i18n="play.change_hero") Change Hero
|
||||
button#play-level-button.btn.btn-lg.btn-success.choose-inventory-active(data-i18n="common.play") Play
|
||||
#unequipped
|
||||
.nano
|
||||
.nano-content
|
||||
if itemGroups
|
||||
if itemGroups.availableItems.models.length
|
||||
h4#available-description(data-i18n="inventory.available_item")
|
||||
for item in itemGroups.availableItems.models
|
||||
img.item(src=item.getPortraitURL(), class=item.classes, data-item-id=item.id)
|
||||
.clearfix
|
||||
|
||||
#double-click-hint.alert.alert-info.secret(data-i18n="inventory.should_equip")
|
||||
|
||||
if itemGroups.restrictedItems.models.length
|
||||
h4#restricted-description(data-i18n="inventory.restricted_title")
|
||||
for item in itemGroups.restrictedItems.models
|
||||
img.item(src=item.getPortraitURL(), class=item.classes, data-item-id=item.id)
|
||||
.clearfix
|
||||
|
||||
if itemGroups.lockedItems.models.length
|
||||
h4#locked-description(data-i18n="play.locked")
|
||||
for item in itemGroups.lockedItems.models
|
||||
img.item(src=item.getPortraitURL(), class=item.classes, data-item-id=item.id)
|
||||
.clearfix
|
||||
|
||||
#item-details-view
|
||||
#item-details-extra
|
||||
button#equip-item-viewed.btn.secret(data-i18n="inventory.equip")
|
||||
button#unequip-item-viewed.btn.secret(data-i18n="inventory.unequip")
|
||||
.alert.alert-danger#restricted-item-viewed.secret(data-i18n="inventory.restricted")
|
||||
|
||||
button#choose-hero-button.btn.btn-lg.btn-primary.choose-inventory-active(data-i18n="play.change_hero") Change Hero
|
||||
button#play-level-button.btn.btn-lg.btn-success.choose-inventory-active(data-i18n="common.play") Play
|
||||
|
|
|
@ -33,4 +33,9 @@
|
|||
p Only admins will see it for now.
|
||||
|
||||
if item && !item.owned
|
||||
button#selected-item-unlock-button.btn.big-font.unlock-button(disabled=!item.affordable, data-item-id=item.id, data-i18n="play.unlock") Unlock
|
||||
button#selected-item-unlock-button.btn.big-font.unlock-button(disabled=!item.affordable, data-item-id=item.id)
|
||||
span(data-i18n="play.unlock") Unlock
|
||||
span.spl= '('+item.get('gems')
|
||||
img(src="/images/common/gem.png")
|
||||
span )
|
||||
|
|
@ -4,6 +4,8 @@ WizardLank = require 'lib/surface/WizardLank'
|
|||
ThangType = require 'models/ThangType'
|
||||
Simulator = require 'lib/simulator/Simulator'
|
||||
|
||||
InventoryModal = require 'views/game-menu/InventoryModal'
|
||||
|
||||
{me} = require '/lib/auth'
|
||||
|
||||
module.exports = class HomeView extends RootView
|
||||
|
@ -34,4 +36,8 @@ module.exports = class HomeView extends RootView
|
|||
e.preventDefault()
|
||||
e.stopImmediatePropagation()
|
||||
window.tracker?.trackEvent 'Homepage', Action: 'Play'
|
||||
window.open '/play', '_blank'
|
||||
window.open '/play', '_blank'
|
||||
|
||||
afterInsert: ->
|
||||
super(arguments...)
|
||||
@openModalView(new InventoryModal({levelID: 'the-raised-sword'}))
|
|
@ -5,6 +5,8 @@ ThangType = require 'models/ThangType'
|
|||
CocoCollection = require 'collections/CocoCollection'
|
||||
ItemView = require './ItemView'
|
||||
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
|
||||
ItemDetailsView = require 'views/play/modal/ItemDetailsView'
|
||||
Purchase = require 'models/Purchase'
|
||||
LevelOptions = require 'lib/LevelOptions'
|
||||
|
||||
hasGoneFullScreenOnce = false
|
||||
|
@ -14,101 +16,130 @@ module.exports = class InventoryModal extends ModalView
|
|||
className: 'modal fade play-modal'
|
||||
template: template
|
||||
slots: ['head', 'eyes', 'neck', 'torso', 'wrists', 'gloves', 'left-ring', 'right-ring', 'right-hand', 'left-hand', 'waist', 'feet', 'programming-book', 'pet', 'minion', 'flag'] #, 'misc-0', 'misc-1'] # TODO: bring in misc slot(s) again when we have space
|
||||
closesOnClickOutside: false # because draggable somehow triggers hide when you don't drag onto a draggable
|
||||
|
||||
events:
|
||||
'click .item-slot': 'onItemSlotClick'
|
||||
'click #available-equipment .list-group-item:not(.equipped)': 'onAvailableItemClick'
|
||||
'dblclick #available-equipment .list-group-item:not(.equipped)': 'onAvailableItemDoubleClick'
|
||||
'doubletap #available-equipment .list-group-item:not(.equipped)': 'onAvailableItemDoubleClick'
|
||||
'dblclick .item-slot .item-view': 'onEquippedItemDoubleClick'
|
||||
'doubletap .item-slot .item-view': 'onEquippedItemDoubleClick'
|
||||
'click #unequipped img.item': 'onUnequippedItemClick'
|
||||
'doubletap #unequipped img.item': 'onUnequippedItemDoubleClick'
|
||||
'doubletap .item-slot img.item': 'onEquippedItemDoubleClick'
|
||||
'shown.bs.modal': 'onShown'
|
||||
'click #choose-hero-button': 'onClickChooseHero'
|
||||
'click #play-level-button': 'onClickPlayLevel'
|
||||
'click .unlock-button': 'onUnlockButtonClicked'
|
||||
'click #equip-item-viewed': 'onClickEquipItemViewed'
|
||||
'click #unequip-item-viewed': 'onClickUnequipItemViewed'
|
||||
'click #close-modal': 'hide'
|
||||
|
||||
shortcuts:
|
||||
'esc': 'clearSelection'
|
||||
'enter': 'onClickPlayLevel'
|
||||
|
||||
|
||||
#- Setup
|
||||
|
||||
initialize: (options) ->
|
||||
super(arguments...)
|
||||
@items = new CocoCollection([], {model: ThangType})
|
||||
@items.url = '/db/thang.type?view=items&project=name,slug,components,original,rasterIcon,gems,description,heroClass'
|
||||
# TODO: switch to item store loading system?
|
||||
@items.url = '/db/thang.type?view=items'
|
||||
@items.setProjection [
|
||||
'name',
|
||||
'slug',
|
||||
'components',
|
||||
'original',
|
||||
'rasterIcon',
|
||||
'gems',
|
||||
'description',
|
||||
'heroClass',
|
||||
'i18n'
|
||||
]
|
||||
@supermodel.loadCollection(@items, 'items')
|
||||
@equipment = {} # Assign for real when we have loaded the session
|
||||
@equipment = {} # Assign for real when we have loaded the session and items.
|
||||
|
||||
destroy: ->
|
||||
@stage?.removeAllChildren()
|
||||
super()
|
||||
|
||||
onLoaded: ->
|
||||
onItemsLoaded: ->
|
||||
item.notInLevel = true for item in @items.models
|
||||
@equipment = @options.equipment or @options.session?.get('heroConfig')?.inventory or me.get('heroConfig')?.inventory or {}
|
||||
@equipment = $.extend true, {}, @equipment
|
||||
@requireLevelEquipment()
|
||||
@itemGroups = {}
|
||||
@itemGroups.availableItems = new Backbone.Collection()
|
||||
@itemGroups.restrictedItems = new Backbone.Collection()
|
||||
@itemGroups.lockedItems = new Backbone.Collection()
|
||||
itemGroup.comparator = 'gems' for itemGroup in _.values @itemGroups
|
||||
|
||||
equipped = _.values(@equipment)
|
||||
@sortItem(item, equipped) for item in @items.models
|
||||
|
||||
sortItem: (item, equipped) ->
|
||||
equipped ?= _.values(@equipment)
|
||||
|
||||
# general starting classes
|
||||
item.classes = _.clone(item.getAllowedSlots())
|
||||
for heroClass in item.getAllowedHeroClasses()
|
||||
item.classes.push heroClass
|
||||
item.classes.push 'equipped' if item.get('original') in equipped
|
||||
|
||||
# sort into one of the four groups
|
||||
locked = not (item.get('original') in me.items())
|
||||
|
||||
if locked and item.get('slug') isnt 'simple-boots'
|
||||
@itemGroups.lockedItems.add(item)
|
||||
item.classes.push 'locked'
|
||||
item.classes.push 'silhouette' if item.isSilhouettedItem()
|
||||
else if item.get('slug') in _.values(LevelOptions[@options.levelID]?.restrictedGear ? {})
|
||||
@itemGroups.restrictedItems.add(item)
|
||||
item.classes.push 'restricted'
|
||||
else
|
||||
@itemGroups.availableItems.add(item)
|
||||
|
||||
onLoaded: ->
|
||||
# Both items and session have been loaded.
|
||||
@onItemsLoaded()
|
||||
super()
|
||||
|
||||
getRenderData: (context={}) ->
|
||||
context = super(context)
|
||||
context.equipped = _.values(@equipment)
|
||||
context.items = @items.models
|
||||
|
||||
for item in @items.models
|
||||
item.classes = item.getAllowedSlots()
|
||||
item.classes.push 'equipped' if item.get('original') in context.equipped
|
||||
locked = not (item.get('original') in me.items())
|
||||
item.classes.push 'locked' if locked and item.get('slug') isnt 'simple-boots'
|
||||
for heroClass in item.getAllowedHeroClasses()
|
||||
item.classes.push heroClass
|
||||
item.classes.push 'silhouette' if item.isSilhouettedItem()
|
||||
item.classes.push 'restricted' if item.get('slug') in _.values(LevelOptions[@options.levelID]?.restrictedGear ? {})
|
||||
|
||||
@items.models.sort (a, b) ->
|
||||
lockScore = 90019001 * (('locked' in a.classes) - ('locked' in b.classes))
|
||||
gemScore = a.get('gems') - b.get('gems')
|
||||
lockScore + gemScore
|
||||
|
||||
context.unlockedItems = []
|
||||
context.lockedItems = []
|
||||
for item in @items.models
|
||||
(if 'locked' in item.classes then context.lockedItems else context.unlockedItems).push item
|
||||
|
||||
context.itemGroups = @itemGroups
|
||||
context.slots = @slots
|
||||
context.selectedHero = @selectedHero
|
||||
context.equipment = _.clone @equipment
|
||||
for slot, itemOriginal of context.equipment
|
||||
item = _.find @items.models, (item) -> item.get('original') is itemOriginal
|
||||
context.equipment[slot] = item
|
||||
context.equipment[slot] = @items.findWhere {original: itemOriginal} for slot, itemOriginal of context.equipment
|
||||
context.gems = me.gems()
|
||||
context
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
@$el.find('.modal-footer button').css('visibility', 'hidden')
|
||||
@$el.find('#play-level-button').css('visibility', 'hidden')
|
||||
return unless @supermodel.finished()
|
||||
@$el.find('.modal-footer button').css('visibility', 'visible')
|
||||
@$el.find('#play-level-button').css('visibility', 'visible')
|
||||
|
||||
keys = (item.get('original') for item in @items.models)
|
||||
itemMap = _.zipObject keys, @items.models
|
||||
@setUpDraggableEventsForAvailableEquipment()
|
||||
@setUpDraggableEventsForEquippedArea()
|
||||
@delegateEvents()
|
||||
@itemDetailsView = new ItemDetailsView()
|
||||
@insertSubView(@itemDetailsView)
|
||||
@requireLevelEquipment()
|
||||
@$el.find('.nano').nanoScroller()
|
||||
|
||||
# Fill in equipped items
|
||||
for slottedItemStub in @$el.find('.replace-me')
|
||||
itemID = $(slottedItemStub).data('item-id')
|
||||
item = itemMap[itemID]
|
||||
itemView = new ItemView({item: item, includes: {}})
|
||||
itemView.render()
|
||||
$(slottedItemStub).replaceWith(itemView.$el)
|
||||
@registerSubView(itemView)
|
||||
afterInsert: ->
|
||||
super()
|
||||
@canvasWidth = @$el.find('canvas').innerWidth()
|
||||
@canvasHeight = @$el.find('canvas').innerHeight()
|
||||
@inserted = true
|
||||
@requireLevelEquipment()
|
||||
|
||||
for availableItemEl in @$el.find('#available-equipment .list-group-item')
|
||||
itemID = $(availableItemEl).data('item-id')
|
||||
item = itemMap[itemID]
|
||||
itemView = new ItemView({item: item, includes: {name: true}})
|
||||
itemView.render()
|
||||
$(availableItemEl).append(itemView.$el)
|
||||
@registerSubView(itemView)
|
||||
continue if $(availableItemEl).hasClass('locked') or $(availableItemEl).hasClass('restricted')
|
||||
dragHelper = itemView.$el.find('img').clone().addClass('draggable-item')
|
||||
do (dragHelper, itemView) =>
|
||||
itemView.$el.draggable
|
||||
#- Draggable logic
|
||||
|
||||
setUpDraggableEventsForAvailableEquipment: ->
|
||||
for availableItemEl in @$el.find('#unequipped img.item')
|
||||
availableItemEl = $(availableItemEl)
|
||||
continue if availableItemEl.hasClass('locked') or availableItemEl.hasClass('restricted')
|
||||
dragHelper = availableItemEl.clone().addClass('draggable-item')
|
||||
do (dragHelper, availableItemEl) =>
|
||||
availableItemEl.draggable
|
||||
revert: 'invalid'
|
||||
appendTo: @$el
|
||||
cursorAt: {left: 35.5, top: 35.5}
|
||||
|
@ -116,43 +147,32 @@ module.exports = class InventoryModal extends ModalView
|
|||
revertDuration: 200
|
||||
distance: 10
|
||||
scroll: false
|
||||
zIndex: 10000
|
||||
itemView.$el.on 'dragstart', =>
|
||||
@onAvailableItemClick target: itemView.$el.parent() unless itemView.$el.parent().hasClass 'active'
|
||||
zIndex: 1100
|
||||
availableItemEl.on 'dragstart', => @selectUnequippedItem(availableItemEl)
|
||||
|
||||
setUpDraggableEventsForEquippedArea: ->
|
||||
for itemSlot in @$el.find '.item-slot'
|
||||
slot = $(itemSlot).data 'slot'
|
||||
do (slot, itemSlot) =>
|
||||
$(itemSlot).droppable
|
||||
drop: (e, ui) => @onAvailableItemDoubleClick()
|
||||
drop: (e, ui) => @equipSelectedItem()
|
||||
accept: (el) -> $(el).parent().hasClass slot
|
||||
activeClass: 'droppable'
|
||||
hoverClass: 'droppable-hover'
|
||||
tolerance: 'touch'
|
||||
@makeEquippedSlotDraggable $(itemSlot)
|
||||
|
||||
@$el.find('.hero-container').droppable
|
||||
drop: (e, ui) => @onAvailableItemDoubleClick()
|
||||
@$el.find('#equipped').droppable
|
||||
drop: (e, ui) => @equipSelectedItem()
|
||||
accept: (el) -> true
|
||||
activeClass: 'droppable'
|
||||
hoverClass: 'droppable-hover'
|
||||
tolerance: 'pointer'
|
||||
|
||||
@$el.find('#selected-items').hide() # Hide until one is selected
|
||||
@delegateEvents()
|
||||
|
||||
if @selectedHero and not @startedLoadingFirstHero
|
||||
@loadHero()
|
||||
@requireLevelEquipment()
|
||||
|
||||
afterInsert: ->
|
||||
super()
|
||||
@canvasWidth = @$el.find('canvas').innerWidth()
|
||||
@canvasHeight = @$el.find('canvas').innerHeight()
|
||||
@inserted = true
|
||||
|
||||
makeEquippedSlotDraggable: (slot) ->
|
||||
unequip = => @unequipItemFromSlot slot
|
||||
unequip = =>
|
||||
@unequipItemFromSlot slot
|
||||
@requireLevelEquipment()
|
||||
shouldStayEquippedWhenDropped = (isValidDrop) ->
|
||||
pos = $(@).position()
|
||||
revert = Math.abs(pos.left) < $(@).outerWidth() and Math.abs(pos.top) < $(@).outerHeight()
|
||||
|
@ -166,179 +186,158 @@ module.exports = class InventoryModal extends ModalView
|
|||
revertDuration: 200
|
||||
distance: 10
|
||||
scroll: false
|
||||
zIndex: 10000
|
||||
zIndex: 100
|
||||
slot.on 'dragstart', => @selectItemSlot(slot)
|
||||
|
||||
clearSelection: ->
|
||||
@$el.find('.item-slot.selected').removeClass 'selected'
|
||||
@$el.find('.list-group-item').removeClass('active')
|
||||
@onSelectionChanged()
|
||||
|
||||
#- Select/equip event handlers
|
||||
|
||||
onItemSlotClick: (e) ->
|
||||
return if @remainingRequiredEquipment?.length # Don't let them select a slot if we need them to first equip some require gear.
|
||||
slot = $(e.target).closest('.item-slot')
|
||||
wasActive = slot.hasClass('selected')
|
||||
@unselectAllSlots()
|
||||
@unselectAllAvailableEquipment() if slot.hasClass('disabled')
|
||||
if wasActive
|
||||
@hideSelectedSlotItem()
|
||||
@unselectAllAvailableEquipment()
|
||||
@selectItemSlot($(e.target).closest('.item-slot'))
|
||||
|
||||
onUnequippedItemClick: (e) ->
|
||||
return if @justDoubleClicked
|
||||
itemEl = $(e.target).closest('img.item')
|
||||
@selectUnequippedItem(itemEl)
|
||||
|
||||
onUnequippedItemDoubleClick: (e) ->
|
||||
item = $(e.target).closest('img.item')
|
||||
return if item.hasClass('locked') or item.hasClass('restricted')
|
||||
@equipSelectedItem()
|
||||
@justDoubleClicked = true
|
||||
_.defer => @justDoubleClicked = false
|
||||
|
||||
onEquippedItemDoubleClick: -> @unequipSelectedItem()
|
||||
onClickEquipItemViewed: -> @equipSelectedItem()
|
||||
onClickUnequipItemViewed: -> @unequipSelectedItem()
|
||||
|
||||
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
|
||||
@requireLevelEquipment()
|
||||
@itemGroups.lockedItems.remove(item)
|
||||
@sortItem(item)
|
||||
@renderSelectors("#unequipped", "#gems-count")
|
||||
@delegateEvents()
|
||||
@setUpDraggableEventsForAvailableEquipment()
|
||||
@itemDetailsView.setItem(item)
|
||||
else
|
||||
@selectSlot(slot)
|
||||
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) ->
|
||||
@clearSelection()
|
||||
slotEl.addClass('selected')
|
||||
selectedSlotItemID = slotEl.find('img.item').data('item-id')
|
||||
item = @items.get(selectedSlotItemID)
|
||||
if item then @showItemDetails(item, 'unequip')
|
||||
@onSelectionChanged()
|
||||
|
||||
onAvailableItemClick: (e) ->
|
||||
itemContainer = $(e.target).closest('.list-group-item')
|
||||
return if itemContainer.hasClass('locked') or itemContainer.hasClass('restricted')
|
||||
wasActive = itemContainer.hasClass 'active'
|
||||
@unselectAllAvailableEquipment()
|
||||
@selectAvailableItem(itemContainer) unless wasActive
|
||||
selectUnequippedItem: (itemEl) ->
|
||||
@clearSelection()
|
||||
itemEl.addClass('active')
|
||||
showExtra = if itemEl.hasClass('restricted') then 'restricted' else if not itemEl.hasClass('locked') then 'equip' else ''
|
||||
@showItemDetails(@items.get(itemEl.data('item-id')), showExtra)
|
||||
@onSelectionChanged()
|
||||
|
||||
onAvailableItemDoubleClick: (e) ->
|
||||
if e
|
||||
itemContainer = $(e.target).closest('.list-group-item')
|
||||
return if itemContainer.hasClass('locked') or itemContainer.hasClass('restricted')
|
||||
@selectAvailableItem itemContainer
|
||||
@onSelectionChanged()
|
||||
slot = @getSelectedSlot()
|
||||
slot = @$el.find('.item-slot:not(.disabled):first') if not slot.length
|
||||
$(e.target).effect('transfer', to: slot, duration: 500, easing: 'easeOutCubic') if e
|
||||
@unequipItemFromSlot(slot)
|
||||
@equipSelectedItemToSlot(slot)
|
||||
equipSelectedItem: ->
|
||||
selectedItemEl = @getSelectedUnequippedItem()
|
||||
selectedItem = @items.get(selectedItemEl.data('item-id'))
|
||||
return unless selectedItem
|
||||
allowedSlots = selectedItem.getAllowedSlots()
|
||||
slotEl = @$el.find(".item-slot[data-slot='#{allowedSlots[0]}']")
|
||||
selectedItemEl.effect('transfer', to: slotEl, duration: 500, easing: 'easeOutCubic')
|
||||
unequipped = @unequipItemFromSlot(slotEl)
|
||||
selectedItemEl.addClass('equipped')
|
||||
slotEl.append(selectedItemEl.clone())
|
||||
@clearSelection()
|
||||
@showItemDetails(selectedItem, 'unequip')
|
||||
slotEl.addClass('selected')
|
||||
selectedItem.classes.push 'equipped'
|
||||
@makeEquippedSlotDraggable slotEl
|
||||
@requireLevelEquipment()
|
||||
@onSelectionChanged()
|
||||
|
||||
onEquippedItemDoubleClick: (e) ->
|
||||
@unselectAllAvailableEquipment()
|
||||
slot = $(e.target).closest('.item-slot')
|
||||
@selectAvailableItem(@unequipItemFromSlot(slot))
|
||||
unequipSelectedItem: ->
|
||||
slotEl = @getSelectedSlot()
|
||||
@clearSelection()
|
||||
itemEl = @unequipItemFromSlot(slotEl)
|
||||
return unless itemEl
|
||||
itemEl.addClass('active')
|
||||
slotEl.effect('transfer', to: itemEl, duration: 500, easing: 'easeOutCubic')
|
||||
selectedSlotItemID = itemEl.data('item-id')
|
||||
item = @items.get(selectedSlotItemID)
|
||||
item.classes = _.without item.classes, 'equipped'
|
||||
@showItemDetails(item, 'equip')
|
||||
@requireLevelEquipment()
|
||||
@onSelectionChanged()
|
||||
|
||||
getSelectedSlot: ->
|
||||
@$el.find('#equipped .item-slot.selected')
|
||||
|
||||
unselectAllAvailableEquipment: ->
|
||||
@$el.find('#available-equipment .list-group-item').removeClass('active')
|
||||
#- Select/equip helpers
|
||||
|
||||
unselectAllSlots: ->
|
||||
clearSelection: ->
|
||||
@deselectAllSlots()
|
||||
@deselectAllUnequippedItems()
|
||||
@hideItemDetails()
|
||||
|
||||
unequipItemFromSlot: (slotEl) ->
|
||||
itemEl = slotEl.find('img.item')
|
||||
itemIDToUnequip = itemEl.data('item-id')
|
||||
return unless itemIDToUnequip
|
||||
itemEl.remove()
|
||||
@$el.find("#unequipped img.item[data-item-id=#{itemIDToUnequip}]").removeClass('equipped')
|
||||
|
||||
deselectAllSlots: ->
|
||||
@$el.find('#equipped .item-slot.selected').removeClass('selected')
|
||||
|
||||
selectSlot: (slot) ->
|
||||
slot.addClass('selected')
|
||||
deselectAllUnequippedItems: ->
|
||||
@$el.find('#unequipped img.item').removeClass('active')
|
||||
|
||||
getSlot: (name) ->
|
||||
@$el.find(".item-slot[data-slot=#{name}]")
|
||||
|
||||
getSelectedAvailableItemContainer: ->
|
||||
@$el.find('#available-equipment .list-group-item.active')
|
||||
getSelectedSlot: ->
|
||||
@$el.find('#equipped .item-slot.selected')
|
||||
|
||||
getAvailableItemContainer: (itemID) ->
|
||||
@$el.find("#available-equipment .list-group-item[data-item-id='#{itemID}']")
|
||||
|
||||
selectAvailableItem: (itemContainer) ->
|
||||
itemContainer?.addClass('active')
|
||||
|
||||
unequipItemFromSlot: (slot) ->
|
||||
itemIDToUnequip = slot.find('.item-view').data('item-id')
|
||||
return unless itemIDToUnequip
|
||||
slot.find('.item-view').detach()
|
||||
for el in @$el.find('#available-equipment .list-group-item')
|
||||
itemID = $(el).find('.item-view').data('item-id')
|
||||
if itemID is itemIDToUnequip
|
||||
unequipped = $(el).removeClass('equipped')
|
||||
break
|
||||
if unequipped
|
||||
@clearSelection()
|
||||
@requireLevelEquipment()
|
||||
return unequipped
|
||||
|
||||
equipSelectedItemToSlot: (slot) ->
|
||||
selectedItemContainer = @getSelectedAvailableItemContainer()
|
||||
newItemHTML = selectedItemContainer.html()
|
||||
selectedItemContainer.addClass('equipped')
|
||||
slotContainer = slot.find('.item-container')
|
||||
slotContainer.html(newItemHTML)
|
||||
slotContainer.find('.item-view').data('item-id', selectedItemContainer.find('.item-view').data('item-id'))
|
||||
@$el.find('.list-group-item').removeClass('active')
|
||||
@makeEquippedSlotDraggable slot
|
||||
@requireLevelEquipment()
|
||||
getSelectedUnequippedItem: ->
|
||||
@$el.find('#unequipped img.item.active')
|
||||
|
||||
onSelectionChanged: ->
|
||||
@$el.find('.item-slot').show()
|
||||
|
||||
selectedSlot = @$el.find('.item-slot.selected')
|
||||
selectedItem = @$el.find('#available-equipment .list-group-item.active')
|
||||
|
||||
if selectedSlot.length
|
||||
@$el.find('#available-equipment .list-group-item').hide()
|
||||
unlockedCount = @$el.find("#available-equipment .list-group-item.#{selectedSlot.data('slot')}:not(.locked)").show().length
|
||||
lockedCount = @$el.find("#available-equipment .list-group-item.#{selectedSlot.data('slot')}.locked").show().length
|
||||
@$el.find('#unlocked-description').text("#{unlockedCount} #{selectedSlot.data('slot')} items owned").toggle unlockedCount > 0
|
||||
@$el.find('#locked-description').text("#{lockedCount} #{selectedSlot.data('slot')} items locked").toggle lockedCount > 0
|
||||
selectedSlotItemID = selectedSlot.find('.item-view').data('item-id')
|
||||
if selectedSlotItemID
|
||||
item = _.find @items.models, {id: selectedSlotItemID}
|
||||
@showSelectedSlotItem(item)
|
||||
else
|
||||
@hideSelectedSlotItem()
|
||||
else
|
||||
unlockedCount = @$el.find('#available-equipment .list-group-item:not(.locked)').show().length
|
||||
@$el.find('#available-equipment .list-group-item.locked').hide()
|
||||
@$el.find('#unlocked-description').text("#{unlockedCount} items owned").toggle unlockedCount > 0
|
||||
@$el.find('#locked-description').text("#{lockedCount} items locked").hide()
|
||||
#@$el.find('#available-equipment .list-group-item.equipped').hide()
|
||||
|
||||
@$el.find('.item-slot').removeClass('disabled')
|
||||
if selectedItem.length
|
||||
item = _.find @items.models, {id:selectedItem.find('.item-view').data('item-id')}
|
||||
# update which slots are enabled
|
||||
allowedSlots = item.getAllowedSlots()
|
||||
for slotEl in @$el.find('.item-slot')
|
||||
slotName = $(slotEl).data('slot')
|
||||
if slotName not in allowedSlots
|
||||
$(slotEl).addClass('disabled')
|
||||
@showSelectedAvailableItem(item)
|
||||
else
|
||||
@hideSelectedAvailableItem()
|
||||
|
||||
@delegateEvents()
|
||||
|
||||
showSelectedSlotItem: (item) ->
|
||||
if not @selectedEquippedItemView
|
||||
@selectedEquippedItemView = new ItemView({
|
||||
item: item, includes: {name: true, stats: true, props: true}})
|
||||
@insertSubView(@selectedEquippedItemView, @$el.find('#selected-equipped-item .item-view-stub'))
|
||||
else
|
||||
@selectedEquippedItemView.$el.show()
|
||||
@selectedEquippedItemView.item = item
|
||||
@selectedEquippedItemView.render()
|
||||
@$el.find('#selected-items').show()
|
||||
@$el.find('#selected-equipped-item').show()
|
||||
|
||||
hideSelectedSlotItem: ->
|
||||
@selectedEquippedItemView?.$el.hide().parent().hide()
|
||||
@$el.find('#selected-items').hide() unless @selectedEquippedItemView?.$el?.is(':visible')
|
||||
showItemDetails: (item, showExtra) ->
|
||||
@itemDetailsView.setItem(item)
|
||||
@$el.find('#item-details-extra > *').addClass('secret')
|
||||
@$el.find("##{showExtra}-item-viewed").removeClass('secret')
|
||||
|
||||
showSelectedAvailableItem: (item) ->
|
||||
if not @selectedAvailableItemView
|
||||
@selectedAvailableItemView = new ItemView({
|
||||
item: item, includes: {name: true, stats: true, props: true}})
|
||||
@insertSubView(@selectedAvailableItemView, @$el.find('#selected-available-item .item-view-stub'))
|
||||
else
|
||||
@selectedAvailableItemView.$el.show()
|
||||
@selectedAvailableItemView.item = item
|
||||
@selectedAvailableItemView.render()
|
||||
@$el.find('#selected-items').show()
|
||||
@$el.find('#selected-available-item').show()
|
||||
|
||||
hideSelectedAvailableItem: ->
|
||||
@selectedAvailableItemView?.$el.hide().parent().hide()
|
||||
@$el.find('#selected-items').hide() unless @selectedEquippedItemView?.$el?.is(':visible')
|
||||
hideItemDetails: ->
|
||||
@itemDetailsView.setItem(null)
|
||||
@$el.find('#item-details-extra > *').addClass('secret')
|
||||
|
||||
getCurrentEquipmentConfig: ->
|
||||
config = {}
|
||||
for slot in @$el.find('.item-slot')
|
||||
slotName = $(slot).data('slot')
|
||||
slotItemID = $(slot).find('.item-view').data('item-id')
|
||||
slotItemID = $(slot).find('img.item').data('item-id')
|
||||
continue unless slotItemID
|
||||
item = _.find @items.models, {id:slotItemID}
|
||||
config[slotName] = item.get('original')
|
||||
|
@ -371,10 +370,13 @@ module.exports = class InventoryModal extends ModalView
|
|||
(item is 'leather-boots' and equipped is gear['simple-boots']) or
|
||||
(item is 'simple-boots' and equipped is gear['leather-boots'])
|
||||
)
|
||||
availableSlotSelector = "#available-equipment li[data-item-id='#{gear[item]}']"
|
||||
itemModel = @items.findWhere {slug: item}
|
||||
continue unless itemModel
|
||||
availableSlotSelector = "#unequipped .item[data-item-id='#{itemModel.id}']"
|
||||
@highlightElement availableSlotSelector, delay: 500, sides: ['right'], rotation: Math.PI / 2
|
||||
@$el.find(availableSlotSelector).addClass 'should-equip'
|
||||
@$el.find("#equipped div[data-slot='#{slot}']").addClass 'should-equip'
|
||||
@$el.find('#double-click-hint').removeClass('secret')
|
||||
@remainingRequiredEquipment.push slot: slot, item: gear[item]
|
||||
if hadRequired and not @remainingRequiredEquipment.length
|
||||
@endHighlight()
|
||||
|
@ -382,54 +384,12 @@ module.exports = class InventoryModal extends ModalView
|
|||
$('#play-level-button').prop('disabled', @remainingRequiredEquipment.length > 0)
|
||||
|
||||
setHero: (@selectedHero) ->
|
||||
@loadHero()
|
||||
@$el.removeClass('Warrior Ranger Wizard').addClass(@selectedHero.get('heroClass'))
|
||||
|
||||
loadHero: ->
|
||||
return unless @supermodel.finished() and @selectedHero and not @$el.hasClass 'secret'
|
||||
@startedLoadingFirstHero = true
|
||||
@stage?.removeAllChildren()
|
||||
if featureImage = @selectedHero.get 'featureImage'
|
||||
@$el.find(".equipped-hero-canvas").hide()
|
||||
@$el.find(".hero-feature-image").show().find('img').prop('src', '/file/' + featureImage)
|
||||
return
|
||||
if @selectedHero.loaded and movieClip = @movieClips?[@selectedHero.get('original')]
|
||||
@stage.addChild(movieClip)
|
||||
@stage.update()
|
||||
return
|
||||
onLoaded = =>
|
||||
return unless canvas = @$el.find(".equipped-hero-canvas")
|
||||
@canvasWidth ||= canvas.width()
|
||||
@canvasHeight ||= canvas.height()
|
||||
canvas.prop width: @canvasWidth, height: @canvasHeight
|
||||
builder = new SpriteBuilder(@selectedHero)
|
||||
movieClip = builder.buildMovieClip(@selectedHero.get('actions').attack?.animation ? @selectedHero.get('actions').idle.animation)
|
||||
movieClip.scaleX = movieClip.scaleY = canvas.prop('height') / 120 # Average hero height is ~110px at normal resolution
|
||||
if @selectedHero.get('name') in ['Knight', 'Robot Walker'] # These are too big, so shrink them.
|
||||
movieClip.scaleX *= 0.7
|
||||
movieClip.scaleY *= 0.7
|
||||
movieClip.regX = -@selectedHero.get('positions').registration.x
|
||||
movieClip.regY = -@selectedHero.get('positions').registration.y
|
||||
movieClip.x = canvas.prop('width') * 0.5
|
||||
movieClip.y = canvas.prop('height') * 0.95 # This is where the feet go.
|
||||
movieClip.gotoAndPlay 0
|
||||
@stage ?= new createjs.Stage(canvas[0])
|
||||
@stage.addChild movieClip
|
||||
@stage.update()
|
||||
@movieClips ?= {}
|
||||
@movieClips[@selectedHero.get('original')] = movieClip
|
||||
if @selectedHero.loaded
|
||||
if @selectedHero.isFullyLoaded()
|
||||
_.defer onLoaded
|
||||
else
|
||||
console.error 'Hmm, trying to render a hero we have not loaded...?', @selectedHero
|
||||
else
|
||||
@listenToOnce @selectedHero, 'sync', onLoaded
|
||||
@render()
|
||||
|
||||
onShown: ->
|
||||
# Called when we switch tabs to this within the modal
|
||||
@requireLevelEquipment()
|
||||
@loadHero()
|
||||
|
||||
onHidden: ->
|
||||
# Called when the modal itself is dismissed
|
||||
|
@ -471,6 +431,13 @@ module.exports = class InventoryModal extends ModalView
|
|||
else
|
||||
callback?()
|
||||
|
||||
destroy: ->
|
||||
@stage?.removeAllChildren()
|
||||
super()
|
||||
|
||||
|
||||
|
||||
|
||||
gear =
|
||||
'simple-boots': '53e237bf53457600003e3f05'
|
||||
'simple-sword': '53e218d853457600003e3ebe'
|
||||
|
|
76
app/views/play/modal/ItemDetailsView.coffee
Normal file
76
app/views/play/modal/ItemDetailsView.coffee
Normal file
|
@ -0,0 +1,76 @@
|
|||
CocoView = require 'views/kinds/CocoView'
|
||||
template = require 'templates/play/modal/item-details-view'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
LevelComponent = require 'models/LevelComponent'
|
||||
|
||||
utils = require 'lib/utils'
|
||||
|
||||
module.exports = class ItemDetailsView extends CocoView
|
||||
id: "item-details-view"
|
||||
template: template
|
||||
|
||||
constructor: ->
|
||||
super(arguments...)
|
||||
@propDocs = {}
|
||||
|
||||
setItem: (@item) ->
|
||||
if @item
|
||||
@item.name = utils.i18n @item.attributes, 'name'
|
||||
@item.affordable = me.gems() >= @item.get('gems')
|
||||
@item.owned = me.ownsItem @item.get('original')
|
||||
@item.comingSoon = not @item.getFrontFacingStats().props.length and not _.size @item.getFrontFacingStats().stats # Temp: while there are placeholder items
|
||||
|
||||
stats = @item.getFrontFacingStats()
|
||||
props = (p for p in stats.props when not @propDocs[p])
|
||||
if props.length > 0
|
||||
|
||||
docs = new CocoCollection([], {
|
||||
url: '/db/level.component?view=prop-doc-lookup'
|
||||
model: LevelComponent
|
||||
project: [
|
||||
'propertyDocumentation.name'
|
||||
'propertyDocumentation.description'
|
||||
'propertyDocumentation.i18n'
|
||||
]
|
||||
})
|
||||
|
||||
docs.fetch({ data: {
|
||||
componentOriginals: [c.original for c in @item.get('components')].join(',')
|
||||
propertyNames: props.join(',')
|
||||
}})
|
||||
@listenToOnce docs, 'sync', @onDocsLoaded
|
||||
|
||||
@render()
|
||||
@$el.find('.nano:visible').nanoScroller()
|
||||
|
||||
onDocsLoaded: (levelComponents) ->
|
||||
for component in levelComponents.models
|
||||
for propDoc in component.get('propertyDocumentation')
|
||||
@propDocs[propDoc.name] = propDoc
|
||||
@render()
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.item = @item
|
||||
if @item
|
||||
stats = @item.getFrontFacingStats()
|
||||
c.stats = _.values(stats.stats)
|
||||
_.last(c.stats).isLast = true if c.stats.length
|
||||
c.props = []
|
||||
progLang = (me.get('aceConfig') ? {}).language or 'python'
|
||||
for prop in stats.props
|
||||
description = utils.i18n @propDocs[prop] ? {}, 'description'
|
||||
|
||||
if _.isObject description
|
||||
description = description[progLang] or _.values(description)[0]
|
||||
if _.isString description
|
||||
description = description.replace(/#{spriteName}/g, 'hero')
|
||||
if fact = stats.stats.shieldDefenseFactor
|
||||
description = description.replace(/#{shieldDefensePercent}%/g, fact.display)
|
||||
description = $(marked(description)).html()
|
||||
|
||||
c.props.push {
|
||||
name: prop
|
||||
description: description or '...'
|
||||
}
|
||||
c
|
|
@ -1,8 +1,6 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
CocoView = require 'views/kinds/CocoView'
|
||||
|
||||
template = require 'templates/play/modal/play-items-modal'
|
||||
itemDetailsTemplate = require 'templates/play/modal/item-details-view'
|
||||
ItemDetailsView = require './ItemDetailsView'
|
||||
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
ThangType = require 'models/ThangType'
|
||||
|
@ -139,7 +137,7 @@ module.exports = class PlayItemsModal extends ModalView
|
|||
$($(e.target).attr('href')).find('.nano').nanoScroller({alwaysVisible: true})
|
||||
|
||||
onUnlockButtonClicked: (e) ->
|
||||
button = $(e.target)
|
||||
button = $(e.target).closest('button')
|
||||
if button.hasClass('confirm')
|
||||
item = @idToItem[$(e.target).data('item-id')]
|
||||
purchase = Purchase.makeFor(item)
|
||||
|
@ -161,67 +159,3 @@ module.exports = class PlayItemsModal extends ModalView
|
|||
@$el.one 'click', (e) ->
|
||||
button.removeClass('confirm').text($.i18n.t('play.unlock')) if e.target isnt button[0]
|
||||
|
||||
class ItemDetailsView extends CocoView
|
||||
id: "item-details-view"
|
||||
template: itemDetailsTemplate
|
||||
|
||||
constructor: ->
|
||||
super(arguments...)
|
||||
@propDocs = {}
|
||||
|
||||
setItem: (@item) ->
|
||||
@render()
|
||||
|
||||
if @item
|
||||
stats = @item.getFrontFacingStats()
|
||||
props = (p for p in stats.props when not @propDocs[p])
|
||||
return if props.length is 0
|
||||
|
||||
docs = new CocoCollection([], {
|
||||
url: '/db/level.component?view=prop-doc-lookup'
|
||||
model: LevelComponent
|
||||
project: [
|
||||
'propertyDocumentation.name'
|
||||
'propertyDocumentation.description'
|
||||
'propertyDocumentation.i18n'
|
||||
]
|
||||
})
|
||||
|
||||
docs.fetch({ data: {
|
||||
componentOriginals: [c.original for c in @item.get('components')].join(',')
|
||||
propertyNames: props.join(',')
|
||||
}})
|
||||
@listenToOnce docs, 'sync', @onDocsLoaded
|
||||
@$el.find('.nano:visible').nanoScroller()
|
||||
|
||||
onDocsLoaded: (levelComponents) ->
|
||||
for component in levelComponents.models
|
||||
for propDoc in component.get('propertyDocumentation')
|
||||
@propDocs[propDoc.name] = propDoc
|
||||
@render()
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.item = @item
|
||||
if @item
|
||||
stats = @item.getFrontFacingStats()
|
||||
c.stats = _.values(stats.stats)
|
||||
_.last(c.stats).isLast = true if c.stats.length
|
||||
c.props = []
|
||||
progLang = (me.get('aceConfig') ? {}).language or 'python'
|
||||
for prop in stats.props
|
||||
description = utils.i18n @propDocs[prop] ? {}, 'description'
|
||||
|
||||
if _.isObject description
|
||||
description = description[progLang] or _.values(description)[0]
|
||||
if _.isString description
|
||||
description = description.replace(/#{spriteName}/g, 'hero')
|
||||
if fact = stats.stats.shieldDefenseFactor
|
||||
description = description.replace(/#{shieldDefensePercent}%/g, fact.display)
|
||||
description = $(marked(description)).html()
|
||||
|
||||
c.props.push {
|
||||
name: prop
|
||||
description: description or '...'
|
||||
}
|
||||
c
|
||||
|
|
|
@ -4,6 +4,6 @@ log = require 'winston'
|
|||
{handlers} = require '../commons/mapping'
|
||||
|
||||
PurchaseSchema = new mongoose.Schema({status: String}, {strict: false})
|
||||
PurchaseSchema.index({recipient: 1, 'purchase.original': 1}, {unique: true, name: 'unique purchase'})
|
||||
PurchaseSchema.index({recipient: 1, 'purchased.original': 1}, {unique: true, name: 'unique purchase'})
|
||||
|
||||
module.exports = mongoose.model('purchase', PurchaseSchema)
|
||||
|
|
|
@ -40,7 +40,7 @@ PurchaseHandler = class PurchaseHandler extends Handler
|
|||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res) unless purchasedItem
|
||||
return @sendBadInputError(res, 'This cannot be purchased.') if not cost = purchasedItem.get('gems')
|
||||
return @sendForbiddenError(res, 'Not enough gems.') if cost > req.user.get('gems')
|
||||
return @sendForbiddenError(res, 'Not enough gems.') if cost > req.user.gems()
|
||||
req.purchasedItem = purchasedItem # for safekeeping
|
||||
|
||||
criteria = {
|
||||
|
@ -69,7 +69,7 @@ PurchaseHandler = class PurchaseHandler extends Handler
|
|||
when 'Hero' then 'heroes'
|
||||
else 'levels'
|
||||
|
||||
original = item.get('original')
|
||||
original = item.get('original') + ''
|
||||
purchased[group] ?= []
|
||||
unless original in purchased[group]
|
||||
#- add the purchase to the list of purchases
|
||||
|
|
Loading…
Add table
Reference in a new issue