From 16a717aec1aa36cb39f21b9a5a8672a28f9ddad2 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 21 Nov 2014 10:14:02 -0800 Subject: [PATCH 1/8] Disallow finding enemy names by selecting them before the HUD is fully enabled. --- app/views/play/level/LevelHUDView.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/play/level/LevelHUDView.coffee b/app/views/play/level/LevelHUDView.coffee index 23a6c9617..e2f5fcb5c 100644 --- a/app/views/play/level/LevelHUDView.coffee +++ b/app/views/play/level/LevelHUDView.coffee @@ -56,6 +56,7 @@ module.exports = class LevelHUDView extends CocoView setThang: (thang, thangType) -> if not thang? and not @thang? then return if thang? and @thang? and thang.id is @thang.id then return + if thang? and @hidesHUD and thang.id isnt 'Hero Placeholder' then return # Don't let them find the names of their opponents this way @thang = thang @thangType = thangType return unless @thang From c77d38d59fdb854729b069f7ec70c8a90480a5a4 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Fri, 21 Nov 2014 10:34:30 -0800 Subject: [PATCH 2/8] Made sure Apple receipts can't be re-used with different accounts. --- server/payments/payment_handler.coffee | 5 ++++- test/server/functional/payment.spec.coffee | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/server/payments/payment_handler.coffee b/server/payments/payment_handler.coffee index d4c60abeb..ae2393d67 100644 --- a/server/payments/payment_handler.coffee +++ b/server/payments/payment_handler.coffee @@ -88,10 +88,13 @@ PaymentHandler = class PaymentHandler extends Handler #- Check existence transactionID = transaction.transaction_id - criteria = { recipient: req.user._id, 'ios.transactionID': transactionID } + criteria = { 'ios.transactionID': transactionID } Payment.findOne(criteria).exec((err, payment) => if payment + unless payment.get('recipient').equals(req.user._id) + return @sendForbiddenError(res) + @recalculateGemsFor(req.user, (err) => return @sendDatabaseError(res, err) if err @sendSuccess(res, @formatEntity(req, payment)) diff --git a/test/server/functional/payment.spec.coffee b/test/server/functional/payment.spec.coffee index a779b8778..ec316a621 100644 --- a/test/server/functional/payment.spec.coffee +++ b/test/server/functional/payment.spec.coffee @@ -52,6 +52,12 @@ describe '/db/payment', -> done() ) + it 'prevents other users from reusing payment receipts', (done) -> + loginSam -> + request.post {uri: paymentURL, json: firstApplePayment}, (err, res, body) -> + expect(res.statusCode).toBe 403 + done() + it 'processes only the transactionID that is given', (done) -> loginJoe -> request.post {uri: paymentURL, json: secondApplePayment}, (err, res, body) -> From e5b87e51580fff2de45f9035695373250589ea78 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Fri, 21 Nov 2014 10:59:48 -0800 Subject: [PATCH 3/8] Tweaked, re-enabled achievement specs. --- .../earned_achievement_handler.coffee | 2 +- .../server/functional/achievement.spec.coffee | 259 +++++++++--------- 2 files changed, 130 insertions(+), 131 deletions(-) diff --git a/server/achievements/earned_achievement_handler.coffee b/server/achievements/earned_achievement_handler.coffee index f49ff545a..cfb2a1f62 100644 --- a/server/achievements/earned_achievement_handler.coffee +++ b/server/achievements/earned_achievement_handler.coffee @@ -67,7 +67,7 @@ class EarnedAchievementHandler extends Handler if achievement.get('proportionalTo') return @sendBadInputError(res, 'Cannot currently do this to repeatable docs...') EarnedAchievement.createForAchievement(achievement, trigger, null, (earnedAchievementDoc) => - @sendSuccess(res, earnedAchievementDoc.toObject()) + @sendCreated(res, earnedAchievementDoc.toObject()) ) ) diff --git a/test/server/functional/achievement.spec.coffee b/test/server/functional/achievement.spec.coffee index d1390a65c..1afac63ce 100644 --- a/test/server/functional/achievement.spec.coffee +++ b/test/server/functional/achievement.spec.coffee @@ -122,134 +122,133 @@ describe 'Achievement', -> # TODO: Took level achievements out of this auto achievement business, so fix these tests -#describe 'Achieving Achievements', -> -# it 'wait for achievements to be loaded', (done) -> -# Achievement.loadAchievements (achievements) -> -# expect(Object.keys(achievements).length).toBe(1) -# -# loadedAchievements = Achievement.getLoadedAchievements() -# expect(Object.keys(loadedAchievements).length).toBe(1) -# done() -# -# it 'saving an object that should trigger an unlockable achievement', (done) -> -# unittest.getNormalJoe (joe) -> -# session = new LevelSession -# permissions: simplePermissions -# creator: joe._id -# level: original: 'dungeon-arena' -# session.save (err, doc) -> -# expect(err).toBeNull() -# expect(doc).toBeDefined() -# expect(doc.creator).toBe(session.creator) -# done() -# -# it 'verify that an unlockable achievement has been earned', (done) -> -# unittest.getNormalJoe (joe) -> -# EarnedAchievement.find {}, (err, docs) -> -# expect(err).toBeNull() -# expect(docs.length).toBe(1) -# achievement = docs[0] -# expect(achievement).toBeDefined() -# -# expect(achievement.get 'achievement').toBe unlockable._id -# expect(achievement.get 'user').toBe joe._id.toHexString() -# expect(achievement.get 'notified').toBeFalsy() -# expect(achievement.get 'earnedPoints').toBe unlockable.worth -# expect(achievement.get 'achievedAmount').toBeUndefined() -# expect(achievement.get 'previouslyAchievedAmount').toBeUndefined() -# done() -# -# it 'saving an object that should trigger a repeatable achievement', (done) -> -# unittest.getNormalJoe (joe) -> -# expect(joe.get 'simulatedBy').toBeFalsy() -# joe.set('simulatedBy', 2) -# joe.save (err, doc) -> -# expect(err).toBeNull() -# done() -# -# it 'verify that a repeatable achievement has been earned', (done) -> -# unittest.getNormalJoe (joe) -> -# EarnedAchievement.find {achievementName: repeatable.name}, (err, docs) -> -# expect(err).toBeNull() -# expect(docs.length).toBe(1) -# achievement = docs[0] -# -# expect(achievement.get 'achievement').toBe repeatable._id -# expect(achievement.get 'user').toBe joe._id.toHexString() -# expect(achievement.get 'notified').toBeFalsy() -# expect(achievement.get 'earnedPoints').toBe 2 * repeatable.worth -# expect(achievement.get 'achievedAmount').toBe 2 -# expect(achievement.get 'previouslyAchievedAmount').toBeFalsy() -# done() -# -# -# it 'verify that the repeatable achievement with complex exp has been earned', (done) -> -# unittest.getNormalJoe (joe) -> -# EarnedAchievement.find {achievementName: diminishing.name}, (err, docs) -> -# expect(err).toBeNull() -# expect(docs.length).toBe 1 -# achievement = docs[0] -# -# expect(achievement.get 'achievedAmount').toBe 2 -# expect(achievement.get 'earnedPoints').toBe (Math.log(.5 * (2 + .5)) + 1) * diminishing.worth -# -# done() +describe 'Level Session Achievement', -> + it 'does not generate earned achievements automatically, they need to be created manually', (done) -> + unittest.getNormalJoe (joe) -> + session = new LevelSession + permissions: simplePermissions + creator: joe._id + level: original: 'dungeon-arena' + session.save (err, session) -> + expect(err).toBeNull() + expect(session).toBeDefined() + expect(session.creator).toBe(session.creator) + + EarnedAchievement.find {}, (err, earnedAchievements) -> + expect(err).toBeNull() + expect(earnedAchievements.length).toBe(0) + + json = {achievement: unlockable._id, triggeredBy: session._id, collection: 'level.sessions'} + request.post {uri: getURL('/db/earned_achievement'), json: json}, (err, res, body) -> + expect(res.statusCode).toBe(201) + expect(body.achievement).toBe unlockable._id+'' + expect(body.user).toBe joe._id.toHexString() + expect(body.notified).toBeFalsy() + expect(body.earnedPoints).toBe unlockable.worth + expect(body.achievedAmount).toBeUndefined() + expect(body.previouslyAchievedAmount).toBeUndefined() + done() -#describe 'Recalculate Achievements', -> -# EarnedAchievementHandler = require '../../../server/achievements/earned_achievement_handler' -# -# it 'remove earned achievements', (done) -> -# clearModels [EarnedAchievement], (err) -> -# expect(err).toBeNull() -# EarnedAchievement.find {}, (err, earned) -> -# expect(earned.length).toBe 0 -# -# User.update {}, {$set: {points: 0}}, {multi:true}, (err) -> -# expect(err).toBeNull() -# done() -# -# it 'can not be accessed by regular users', (done) -> -# loginJoe -> request.post {uri:getURL '/admin/earned_achievement/recalculate'}, (err, res, body) -> -# expect(res.statusCode).toBe 403 -# done() -# -# it 'can recalculate a selection of achievements', (done) -> -# loginAdmin -> -# EarnedAchievementHandler.constructor.recalculate ['dungeon-arena-started'], -> -# EarnedAchievement.find {}, (err, earnedAchievements) -> -# expect(earnedAchievements.length).toBe 1 -# -# # Recalculate again, doesn't change a thing -# EarnedAchievementHandler.constructor.recalculate ['dungeon-arena-started'], -> -# EarnedAchievement.find {}, (err, earnedAchievements) -> -# expect(earnedAchievements.length).toBe 1 -# -# unittest.getNormalJoe (joe) -> -# User.findById joe.get('id'), (err, guy) -> -# expect(err).toBeNull() -# expect(guy.get 'points').toBe unlockable.worth -# done() -# -# it 'can recalculate all achievements', (done) -> -# loginAdmin -> -# Achievement.count {}, (err, count) -> -# expect(count).toBe 3 -# EarnedAchievementHandler.constructor.recalculate -> -# EarnedAchievement.find {}, (err, earnedAchievements) -> -# expect(earnedAchievements.length).toBe 3 -# unittest.getNormalJoe (joe) -> -# User.findById joe.get('id'), (err, guy) -> -# expect(err).toBeNull() -# expect(guy.get 'points').toBe unlockable.worth + 2 * repeatable.worth + (Math.log(.5 * (2 + .5)) + 1) * diminishing.worth -# done() -# -# it 'cleaning up test: deleting all Achievements and related', (done) -> -# clearModels [Achievement, EarnedAchievement, LevelSession], (err) -> -# expect(err).toBeNull() -# -# # reset achievements in memory as well -# Achievement.resetAchievements() -# loadedAchievements = Achievement.getLoadedAchievements() -# expect(Object.keys(loadedAchievements).length).toBe(0) -# -# done() + +describe 'Achieving Achievements', -> + it 'wait for achievements to be loaded', (done) -> + Achievement.loadAchievements (achievements) -> + expect(Object.keys(achievements).length).toBe(1) + + loadedAchievements = Achievement.getLoadedAchievements() + expect(Object.keys(loadedAchievements).length).toBe(1) + done() + + it 'saving an object that should trigger a repeatable achievement', (done) -> + unittest.getNormalJoe (joe) -> + expect(joe.get 'simulatedBy').toBeFalsy() + joe.set('simulatedBy', 2) + joe.save (err, doc) -> + expect(err).toBeNull() + done() + + it 'verify that a repeatable achievement has been earned', (done) -> + unittest.getNormalJoe (joe) -> + EarnedAchievement.find {achievementName: repeatable.name}, (err, docs) -> + expect(err).toBeNull() + expect(docs.length).toBe(1) + achievement = docs[0] + + expect(achievement.get 'achievement').toBe repeatable._id + expect(achievement.get 'user').toBe joe._id.toHexString() + expect(achievement.get 'notified').toBeFalsy() + expect(achievement.get 'earnedPoints').toBe 2 * repeatable.worth + expect(achievement.get 'achievedAmount').toBe 2 + expect(achievement.get 'previouslyAchievedAmount').toBeFalsy() + done() + + it 'verify that the repeatable achievement with complex exp has been earned', (done) -> + unittest.getNormalJoe (joe) -> + EarnedAchievement.find {achievementName: diminishing.name}, (err, docs) -> + expect(err).toBeNull() + expect(docs.length).toBe 1 + achievement = docs[0] + + expect(achievement.get 'achievedAmount').toBe 2 + expect(achievement.get 'earnedPoints').toBe (Math.log(.5 * (2 + .5)) + 1) * diminishing.worth + + done() + +describe 'Recalculate Achievements', -> + EarnedAchievementHandler = require '../../../server/achievements/earned_achievement_handler' + + it 'remove earned achievements', (done) -> + clearModels [EarnedAchievement], (err) -> + expect(err).toBeNull() + EarnedAchievement.find {}, (err, earned) -> + expect(earned.length).toBe 0 + + User.update {}, {$set: {points: 0}}, {multi:true}, (err) -> + expect(err).toBeNull() + done() + + it 'can not be accessed by regular users', (done) -> + loginJoe -> request.post {uri:getURL '/admin/earned_achievement/recalculate'}, (err, res, body) -> + expect(res.statusCode).toBe 403 + done() + + it 'can recalculate a selection of achievements', (done) -> + loginAdmin -> + EarnedAchievementHandler.constructor.recalculate ['dungeon-arena-started'], -> + EarnedAchievement.find {}, (err, earnedAchievements) -> + expect(earnedAchievements.length).toBe 1 + + # Recalculate again, doesn't change a thing + EarnedAchievementHandler.constructor.recalculate ['dungeon-arena-started'], -> + EarnedAchievement.find {}, (err, earnedAchievements) -> + expect(earnedAchievements.length).toBe 1 + + unittest.getNormalJoe (joe) -> + User.findById joe.get('id'), (err, guy) -> + expect(err).toBeNull() + expect(guy.get 'points').toBe unlockable.worth + done() + + it 'can recalculate all achievements', (done) -> + loginAdmin -> + Achievement.count {}, (err, count) -> + expect(count).toBe 3 + EarnedAchievementHandler.constructor.recalculate -> + EarnedAchievement.find {}, (err, earnedAchievements) -> + expect(earnedAchievements.length).toBe 3 + unittest.getNormalJoe (joe) -> + User.findById joe.get('id'), (err, guy) -> + expect(err).toBeNull() + expect(guy.get 'points').toBe unlockable.worth + 2 * repeatable.worth + (Math.log(.5 * (2 + .5)) + 1) * diminishing.worth + done() + + it 'cleaning up test: deleting all Achievements and related', (done) -> + clearModels [Achievement, EarnedAchievement, LevelSession], (err) -> + expect(err).toBeNull() + + # reset achievements in memory as well + Achievement.resetAchievements() + loadedAchievements = Achievement.getLoadedAchievements() + expect(Object.keys(loadedAchievements).length).toBe(0) + + done() From cfe1b020c363b6246a9a383c91593d552157f8cd Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 21 Nov 2014 11:07:46 -0800 Subject: [PATCH 4/8] Fixed esc shortcut when editor is disabled. --- app/styles/play/level/tome/spell.sass | 2 +- app/views/play/level/tome/SpellView.coffee | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/styles/play/level/tome/spell.sass b/app/styles/play/level/tome/spell.sass index b3b0a82ec..39f65f6d4 100644 --- a/app/styles/play/level/tome/spell.sass +++ b/app/styles/play/level/tome/spell.sass @@ -66,7 +66,7 @@ &.disabled @include opacity(0.8) .ace_cursor, .executing, .ace_active-line, .ace_gutter-active-line - @include opacity(0.2) + @include opacity(0.1) .ace_gutter background-color: transparent diff --git a/app/views/play/level/tome/SpellView.coffee b/app/views/play/level/tome/SpellView.coffee index 39d3445ec..c333825b7 100644 --- a/app/views/play/level/tome/SpellView.coffee +++ b/app/views/play/level/tome/SpellView.coffee @@ -131,13 +131,12 @@ module.exports = class SpellView extends CocoView addCommand name: 'toggle-playing' bindKey: {win: 'Ctrl-P', mac: 'Command-P|Ctrl-P'} + readOnly: true exec: -> Backbone.Mediator.publish 'level:toggle-playing', {} addCommand name: 'end-current-script' bindKey: {win: 'Shift-Space', mac: 'Shift-Space'} - # passEvent: true # https://github.com/ajaxorg/ace/blob/master/lib/ace/keyboard/keybinding.js#L114 - # No easy way to selectively cancel shift+space, since we don't get access to the event. - # Maybe we could temporarily set ourselves to read-only if we somehow know that a script is active? + readOnly: true exec: => if @scriptRunning Backbone.Mediator.publish 'level:shift-space-pressed', {} @@ -147,34 +146,44 @@ module.exports = class SpellView extends CocoView addCommand name: 'end-all-scripts' bindKey: {win: 'Escape', mac: 'Escape'} - exec: -> Backbone.Mediator.publish 'level:escape-pressed', {} + readOnly: true + exec: -> + console.log 'esc pressed' + Backbone.Mediator.publish 'level:escape-pressed', {} addCommand name: 'toggle-grid' bindKey: {win: 'Ctrl-G', mac: 'Command-G|Ctrl-G'} + readOnly: true exec: -> Backbone.Mediator.publish 'level:toggle-grid', {} addCommand name: 'toggle-debug' bindKey: {win: 'Ctrl-\\', mac: 'Command-\\|Ctrl-\\'} + readOnly: true exec: -> Backbone.Mediator.publish 'level:toggle-debug', {} addCommand name: 'toggle-pathfinding' bindKey: {win: 'Ctrl-O', mac: 'Command-O|Ctrl-O'} + readOnly: true exec: -> Backbone.Mediator.publish 'level:toggle-pathfinding', {} addCommand name: 'level-scrub-forward' bindKey: {win: 'Ctrl-]', mac: 'Command-]|Ctrl-]'} + readOnly: true exec: -> Backbone.Mediator.publish 'level:scrub-forward', {} addCommand name: 'level-scrub-back' bindKey: {win: 'Ctrl-[', mac: 'Command-[|Ctrl-]'} + readOnly: true exec: -> Backbone.Mediator.publish 'level:scrub-back', {} addCommand name: 'spell-step-forward' bindKey: {win: 'Ctrl-Alt-]', mac: 'Command-Alt-]|Ctrl-Alt-]'} + readOnly: true exec: -> Backbone.Mediator.publish 'tome:spell-step-forward', {} addCommand name: 'spell-step-backward' bindKey: {win: 'Ctrl-Alt-[', mac: 'Command-Alt-[|Ctrl-Alt-]'} + readOnly: true exec: -> Backbone.Mediator.publish 'tome:spell-step-backward', {} addCommand name: 'spell-beautify' @@ -815,10 +824,11 @@ module.exports = class SpellView extends CocoView return if enabled is @controlsEnabled @controlsEnabled = enabled and @writable disabled = not enabled - $('body').focus() if disabled and $(document.activeElement).is('.ace_text-input') + wasFocused = @ace.isFocused() @ace.setReadOnly disabled @ace[if disabled then 'setStyle' else 'unsetStyle'] 'disabled' @toggleBackground() + $('body').focus() if disabled and wasFocused toggleBackground: => # TODO: make the background an actual background and do the CSS trick From c5ae253a45a5941e1e633fe7cb80e3e5dc60c3fb Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 21 Nov 2014 11:56:31 -0800 Subject: [PATCH 5/8] Fixed next-level popovers appearing in wrong place on world map. --- app/views/play/WorldMapView.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/play/WorldMapView.coffee b/app/views/play/WorldMapView.coffee index 0e0ed80b3..db3b29a70 100644 --- a/app/views/play/WorldMapView.coffee +++ b/app/views/play/WorldMapView.coffee @@ -40,7 +40,7 @@ module.exports = class WorldMapView extends RootView @levelStatusMap = {} @levelPlayCountMap = {} @sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', null, 0).model - + # Temporary attempt to make sure all earned rewards are accounted for. Figure out a better solution... @earnedAchievements = new CocoCollection([], {url: '/db/earned_achievement', model:EarnedAchievement, project: ['earnedRewards']}) @listenToOnce @earnedAchievements, 'sync', -> @@ -56,7 +56,7 @@ module.exports = class WorldMapView extends RootView earned[group].push(reward) addedSomething = true @supermodel.loadCollection(@earnedAchievements, 'achievements') - + @listenToOnce @sessions, 'sync', @onSessionsLoaded @getLevelPlayCounts() $(window).on 'resize', @onWindowResize @@ -136,7 +136,7 @@ module.exports = class WorldMapView extends RootView if levelID = @$el.find('.level.next').data('level-id') @$levelInfo = @$el.find(".level-info-container[data-level-id=#{levelID}]").show() pos = @$el.find('.level.next').offset() - @adjustLevelInfoPosition pageX: pos.left, pageY: pos.top + 250 + @adjustLevelInfoPosition pageX: pos.left, pageY: pos.top @manuallyPositionedLevelInfoID = levelID afterInsert: -> @@ -203,6 +203,7 @@ module.exports = class WorldMapView extends RootView @$levelInfo = @$el.find(".level-info-container[data-level-id=#{levelID}]").show() @adjustLevelInfoPosition e @endHighlight() + @manuallyPositionedLevelInfoID = false onMouseLeaveLevel: (e) -> return if application.isIPadApp From cee017c7ec0db268b0a753953826ef31f5321082 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 21 Nov 2014 12:14:37 -0800 Subject: [PATCH 6/8] Moved spell palette popovers to top placement if dialogue view is active. --- app/styles/play/level/tome/spell_palette_entry.sass | 8 ++++++-- app/views/play/level/LevelDialogueView.coffee | 6 ++---- app/views/play/level/tome/SpellPaletteEntryView.coffee | 3 ++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/styles/play/level/tome/spell_palette_entry.sass b/app/styles/play/level/tome/spell_palette_entry.sass index 93640e9ef..fdda33886 100644 --- a/app/styles/play/level/tome/spell_palette_entry.sass +++ b/app/styles/play/level/tome/spell_palette_entry.sass @@ -45,11 +45,15 @@ // color: rgb(197, 6, 11) color: rgb(243, 169, 49) + +body:not(.dialogue-view-active) + .spell-palette-popover.popover + right: 45% + min-width: 350px + .spell-palette-popover.popover // Only those popovers which are our direct children (spell documentation) max-width: 600px - right: 45% - min-width: 350px &.pinned left: auto !important diff --git a/app/views/play/level/LevelDialogueView.coffee b/app/views/play/level/LevelDialogueView.coffee index 3629ba687..6c6b117bb 100644 --- a/app/views/play/level/LevelDialogueView.coffee +++ b/app/views/play/level/LevelDialogueView.coffee @@ -19,13 +19,10 @@ module.exports = class LevelDialogueView extends CocoView onClick: (e) -> Backbone.Mediator.publish 'tome:focus-editor', {} - onFrameChanged: (e) -> - @timeProgress = e.progress - @update() - onSpriteDialogue: (e) -> return unless e.message @$el.addClass 'active speaking' + $('body').addClass('dialogue-view-active') @setMessage e.message, e.mood, e.responses window.tracker?.trackEvent 'Heard Sprite', {message: e.message, label: e.message}, ['Google Analytics'] @@ -35,6 +32,7 @@ module.exports = class LevelDialogueView extends CocoView onSpriteClearDialogue: -> @$el.removeClass 'active speaking' + $('body').removeClass('dialogue-view-active') setMessage: (message, mood, responses) -> message = marked message diff --git a/app/views/play/level/tome/SpellPaletteEntryView.coffee b/app/views/play/level/tome/SpellPaletteEntryView.coffee index d6870656d..a66d70131 100644 --- a/app/views/play/level/tome/SpellPaletteEntryView.coffee +++ b/app/views/play/level/tome/SpellPaletteEntryView.coffee @@ -37,10 +37,11 @@ module.exports = class SpellPaletteEntryView extends CocoView afterRender: -> super() @$el.addClass(@doc.type) + placement = -> if $('body').hasClass('dialogue-view-active') then 'top' else 'left' @$el.popover( animation: false html: true - placement: 'left' + placement: placement trigger: 'manual' # Hover, until they click, which will then pin it until unclick. content: @docFormatter.formatPopover() container: 'body' From 074d9f33c2c0294f85d1fe2171e55f8ba52ae766 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 21 Nov 2014 12:20:24 -0800 Subject: [PATCH 7/8] Fixed bugs with unequipping restricted items not then requiring the proper item afterward. --- app/views/game-menu/InventoryModal.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/game-menu/InventoryModal.coffee b/app/views/game-menu/InventoryModal.coffee index 618af9815..fae444711 100644 --- a/app/views/game-menu/InventoryModal.coffee +++ b/app/views/game-menu/InventoryModal.coffee @@ -378,11 +378,13 @@ module.exports = class InventoryModal extends ModalView unless itemModel and heroClass in itemModel.classes console.log 'Unequipping', itemModel.get('heroClass'), 'item', itemModel.get('name'), 'from slot due to class restrictions.' @unequipItemFromSlot @$el.find(".item-slot[data-slot='#{slot}']") + delete equipment[slot] for slot, item of restrictedGear equipped = equipment[slot] if equipped and equipped is gear[restrictedGear[slot]] console.log 'Unequipping restricted item', restrictedGear[slot], 'for', slot, 'before level', @options.levelID @unequipItemFromSlot @$el.find(".item-slot[data-slot='#{slot}']") + delete equipment[slot] if heroClass is 'Warrior' # After they switch to a ranger or wizard, we stop being so finicky about gear. for slot, item of requiredGear From f12dcec0ffe63432671de88de33702a070c346a0 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 21 Nov 2014 13:08:40 -0800 Subject: [PATCH 8/8] Paths for non-admins. Making sure paths are showing when level first loads and playback ends (not sure why they are not showing up at first otherwise). --- app/lib/surface/Surface.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/surface/Surface.coffee b/app/lib/surface/Surface.coffee index 016fc81d6..195dab4b2 100644 --- a/app/lib/surface/Surface.coffee +++ b/app/lib/surface/Surface.coffee @@ -342,6 +342,7 @@ module.exports = Surface = class Surface extends CocoClass @ended = true @setPaused true Backbone.Mediator.publish 'surface:playback-ended', {} + @updatePaths() # TODO: this is a hack to make sure paths are on the first time the level loads else if @currentFrame < @world.totalFrames and @ended @ended = false @setPaused false @@ -586,7 +587,6 @@ module.exports = Surface = class Surface extends CocoClass updatePaths: -> return unless @options.paths and @heroLank - return unless me.isAdmin() # TODO: Fix world thang points, targets, then remove this @hidePaths() return if @world.showPaths is 'never' layerAdapter = @lankBoss.layerAdapters['Path']