diff --git a/common/locales/en/messages.json b/common/locales/en/messages.json index f10fac9f28..bf75e62a5f 100644 --- a/common/locales/en/messages.json +++ b/common/locales/en/messages.json @@ -21,10 +21,11 @@ "messageDropFood": "You've found <%= dropArticle %><%= dropText %>! <%= dropNotes %>", "messageDropEgg": "You've found a <%= dropText %> Egg! <%= dropNotes %>", "messageDropPotion": "You've found a <%= dropText %> Hatching Potion! <%= dropNotes %>", + "messageDropQuest": "You've found a quest!", "messageFoundQuest": "You've found the quest \"<%= questText %>\"!", "messageAlreadyPurchasedGear": "You purchased this gear in the past, but do not currently own it. You can buy it again in the rewards column on the tasks page.", - "messageAlreadyOwnGear": "You have already own this item. Equip it by going to the equipment page.", + "messageAlreadyOwnGear": "You already own this item. Equip it by going to the equipment page.", "armoireEquipment": "<%= image %> You found a piece of rare Equipment in the Armoire: <%= dropText %>! Awesome!", "armoireFood": "<%= image %> You rummage in the Armoire and find <%= dropArticle %><%= dropText %>. What's that doing in here?", diff --git a/common/locales/en/quests.json b/common/locales/en/quests.json index 7fbc0d9fc9..f0f3918a28 100644 --- a/common/locales/en/quests.json +++ b/common/locales/en/quests.json @@ -11,12 +11,14 @@ "invitations": "Invitations", "completed": "Completed!", "youReceived": "You've Received", + "dropQuestCongrats": "Congratulations on earning this quest scroll! You can invite your party to begin the quest now, or come back to it any time in your Inventory > Quests.", "questSend": "Clicking \"Invite\" will send an invitation to your party members. When all members have accepted or denied, the quest begins. See status under Social > Party.", "inviteParty": "Invite Party", "questInvitation": "Quest Invitation: ", "questInvitationTitle": "Quest Invitation", "questInvitationInfo": "Invitation for the Quest <%= quest %>", "askLater": "Ask Later", + "questLater": "Quest Later", "buyQuest": "Buy Quest", "accepted": "Accepted", "rejected": "Rejected", diff --git a/common/script/index.coffee b/common/script/index.coffee index fc1b0978cb..1aa71bbede 100644 --- a/common/script/index.coffee +++ b/common/script/index.coffee @@ -1538,9 +1538,7 @@ api.wrap = (user, main=true) -> (user.flags.levelDrops ?= {})[k] = true user.markModified? 'flags.levelDrops' mixpanel?.track("Acquire Item",{'itemName':k,'acquireMethod':'Drop'}) - user._tmp.drop = _.defaults content.quests[k], - type: 'Quest' - dialog: i18n.t('messageFoundQuest', {questText: content.quests[k].text(req.language)}, req.language) + user._tmp.drop = {type: 'Quest', key: k} if !user.flags.rebirthEnabled and (user.stats.lvl >= 50 or user.achievements.beastMaster) user.flags.rebirthEnabled = true diff --git a/website/public/css/quests.styl b/website/public/css/quests.styl index 3f5fa8a79b..c9fce043fc 100644 --- a/website/public/css/quests.styl +++ b/website/public/css/quests.styl @@ -5,3 +5,6 @@ quest-rewards hr clear:both + +.quest-icon + margin: .6em diff --git a/website/public/js/controllers/groupsCtrl.js b/website/public/js/controllers/groupsCtrl.js index 2cd61ad518..f42811b9b1 100644 --- a/website/public/js/controllers/groupsCtrl.js +++ b/website/public/js/controllers/groupsCtrl.js @@ -512,12 +512,14 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' } ]) - .controller("PartyCtrl", ['$rootScope','$scope', 'Groups', 'Chat', 'User', 'Challenges', '$state', '$compile', 'Analytics', - function($rootScope,$scope, Groups, Chat, User, Challenges, $state, $compile, Analytics) { + .controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','Challenges','$state','$compile','Analytics','Quests', + function($rootScope,$scope,Groups,Chat,User,Challenges,$state,$compile,Analytics,Quests) { $scope.type = 'party'; $scope.text = window.env.t('party'); $scope.group = $rootScope.party = Groups.party(); $scope.newGroup = new Groups.Group({type:'party'}); + $scope.inviteOrStartParty = Groups.inviteOrStartParty; + $scope.questInit = Quests.questInit; if ($state.is('options.social.party')) { $scope.group.$syncParty(); // Sync party automatically when navigating to party page diff --git a/website/public/js/controllers/inventoryCtrl.js b/website/public/js/controllers/inventoryCtrl.js index 4bc97cbc42..e7e9aba457 100644 --- a/website/public/js/controllers/inventoryCtrl.js +++ b/website/public/js/controllers/inventoryCtrl.js @@ -17,6 +17,7 @@ habitrpg.controller("InventoryCtrl", $scope.questPopover = Quests.questPopover; $scope.showQuest = Quests.showQuest; $scope.closeQuest = Quests.closeQuest; + $scope.questInit = Quests.questInit; // count egg, food, hatchingPotion stack totals var countStacks = function(items) { return _.reduce(items,function(m,v){return m+v;},0);} @@ -146,14 +147,6 @@ habitrpg.controller("InventoryCtrl", User.user.ops.equip({params:{type: 'mount', key: egg + '-' + potion}}); } - $scope.questInit = function(){ - Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'quest','owner':true,'response':'accept','questName':$scope.selectedQuest.key}); - $rootScope.party.$questAccept({key:$scope.selectedQuest.key}, function(){ - $rootScope.party.$get(); - }); - $scope.closeQuest(); - } - $scope.getSeasonalShopArray = function(set){ var flatGearArray = _.toArray(Content.gear.flat); diff --git a/website/public/js/controllers/notificationCtrl.js b/website/public/js/controllers/notificationCtrl.js index 0acfd8a266..6a4f41df88 100644 --- a/website/public/js/controllers/notificationCtrl.js +++ b/website/public/js/controllers/notificationCtrl.js @@ -58,35 +58,44 @@ habitrpg.controller('NotificationCtrl', $rootScope.$watch('user._tmp.drop', function(after, before){ // won't work when getting the same item twice? - if (after == before || !after) return; - $rootScope.playSound('Achievement_Unlocked'); - if (after.type !== 'gear') { - var type = (after.type == 'Food') ? 'food' : - (after.type == 'HatchingPotion') ? 'hatchingPotions' : // can we use camelcase and remove this line? - (after.type.toLowerCase() + 's'); + if (_.isEqual(after, before) || !after) return; + var text, notes, type; + $rootScope.playSound('Item_Drop'); + + if (after.type !== 'gear' && after.type !== 'Quest') { + if (after.type === 'Food') { + type = 'food'; + } else if (after.type === 'HatchingPotion') { + type = 'hatchingPotions'; + } else { + type = after.type.toLowerCase() + 's'; + } if(!User.user.items[type][after.key]){ User.user.items[type][after.key] = 0; } User.user.items[type][after.key]++; } - if(after.type === 'HatchingPotion'){ - var text = Content.hatchingPotions[after.key].text(); - var notes = Content.hatchingPotions[after.key].notes(); + if (after.type === 'HatchingPotion'){ + text = Content.hatchingPotions[after.key].text(); + notes = Content.hatchingPotions[after.key].notes(); Notification.drop(env.t('messageDropPotion', {dropText: text, dropNotes: notes}), after); - }else if(after.type === 'Egg'){ - var text = Content.eggs[after.key].text(); - var notes = Content.eggs[after.key].notes(); + } else if (after.type === 'Egg'){ + text = Content.eggs[after.key].text(); + notes = Content.eggs[after.key].notes(); Notification.drop(env.t('messageDropEgg', {dropText: text, dropNotes: notes}), after); - }else if(after.type === 'Food'){ - var text = Content.food[after.key].text(); - var notes = Content.food[after.key].notes(); + } else if (after.type === 'Food'){ + text = Content.food[after.key].text(); + notes = Content.food[after.key].notes(); Notification.drop(env.t('messageDropFood', {dropArticle: after.article, dropText: text, dropNotes: notes}), after); - }else{ + } else if (after.type === 'Quest') { + $rootScope.selectedQuest = Content.quests[after.key]; + $rootScope.openModal('questDrop', {controller:'PartyCtrl'}); + } else { // Keep support for another type of drops that might be added Notification.drop(User.user._tmp.drop.dialog); } - $rootScope.playSound('Item_Drop'); + Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'acquire item','itemName':after.key,'acquireMethod':'Drop'}); }); @@ -121,17 +130,6 @@ habitrpg.controller('NotificationCtrl', $rootScope.openModal('achievements/contributor'); }); - /*_.each(['weapon', 'head', 'chest', 'shield'], function(watched){ - $rootScope.$watch('user.items.' + watched, function(before, after){ - if (after == before) return; - if (+after < +before) { - //don't want to day "lost a head" - if (watched === 'head') watched = 'helm'; - Notification.text('Lost GP, 1 LVL, ' + watched); - } - }) - });*/ - // Classes modal $rootScope.$watch('!user.flags.classSelected && user.stats.lvl >= 10', function(after, before){ if(after){ diff --git a/website/public/js/services/questServices.js b/website/public/js/services/questServices.js index 1ca6995c38..146240915b 100644 --- a/website/public/js/services/questServices.js +++ b/website/public/js/services/questServices.js @@ -10,10 +10,11 @@ '$rootScope', 'Content', 'Groups', - 'User' + 'User', + 'Analytics' ]; - function questsFactory($rootScope,Content,Groups,User) { + function questsFactory($rootScope,Content,Groups,User,Analytics) { var user = User.user; @@ -84,12 +85,22 @@ $rootScope.selectedQuest = undefined; } + function questInit(){ + Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'quest','owner':true,'response':'accept','questName':$rootScope.selectedQuest.key}); + $rootScope.party.$questAccept({key:$rootScope.selectedQuest.key}, function(){ + $rootScope.party.$get(); + $rootScope.$state.go('options.social.party'); + }); + closeQuest(); + } + return { lockQuest: lockQuest, buyQuest: buyQuest, questPopover: questPopover, showQuest: showQuest, - closeQuest: closeQuest + closeQuest: closeQuest, + questInit: questInit } } }()); diff --git a/website/src/controllers/groups.js b/website/src/controllers/groups.js index 21000ee5e5..982383205c 100644 --- a/website/src/controllers/groups.js +++ b/website/src/controllers/groups.js @@ -917,7 +917,7 @@ api.questAccept = function(req, res, next) { var quest = shared.content.quests[key]; if (!quest) return res.json(404,{err:'Quest ' + key + ' not found'}); if (quest.lvl && user.stats.lvl < quest.lvl) return res.json(400, {err: "You must be level "+quest.lvl+" to begin this quest."}); - if (group.quest.key) return res.json(400, {err: 'Party already on a quest (and only have one quest at a time)'}); + if (group.quest.key) return res.json(400, {err: 'Your party is already on a quest. Try again when the current quest has ended.'}); if (!user.items.quests[key]) return res.json(400, {err: "You don't own that quest scroll"}); group.quest.key = key; group.quest.members = {}; diff --git a/website/views/shared/modals/quests.jade b/website/views/shared/modals/quests.jade index 0b16006351..165e0187e1 100644 --- a/website/views/shared/modals/quests.jade +++ b/website/views/shared/modals/quests.jade @@ -1,5 +1,23 @@ include ./quest-rewards +mixin questInfo + .pull-right-sm.text-center + .col-centered(class='quest_{{::selectedQuest.key}}') + div(ng-if='::selectedQuest.boss') + h4 {{::selectedQuest.boss.name()}} + p + strong=env.t('bossHP') + ': ' + | {{::selectedQuest.boss.hp}} + p + strong=env.t('bossStrength') + ': ' + | {{::selectedQuest.boss.str}} + div(ng-if='::selectedQuest.collect') + p(ng-repeat='(k,v) in ::selectedQuest.collect') + strong=env.t('collect') + ': ' + | {{::selectedQuest.collect[k].count}} {{::selectedQuest.collect[k].text()}} + div(ng-bind-html='::selectedQuest.notes()') + quest-rewards(key='{{::selectedQuest.key}}', header=env.t('rewards')) + script(type='text/ng-template', id='modals/questCompleted.html') .modal-header h4 "{{::Content.quests[user.party.quest.completed].text()}}" @@ -15,24 +33,8 @@ script(type='text/ng-template', id='modals/showQuest.html') .modal-header h4 {{::selectedQuest.text()}} .modal-body - .pull-right-sm.text-center - .col-centered(class='quest_{{::selectedQuest.key}}') - div(ng-if='::selectedQuest.boss') - h4 {{::selectedQuest.boss.name()}} - p - strong=env.t('bossHP') + ': ' - | {{::selectedQuest.boss.hp}} - p - strong=env.t('bossStrength') + ': ' - | {{::selectedQuest.boss.str}} - div(ng-if='::selectedQuest.collect') - p(ng-repeat='(k,v) in ::selectedQuest.collect') - strong=env.t('collect') + ': ' - | {{::selectedQuest.collect[k].count}} {{::selectedQuest.collect[k].text()}} - - div(ng-bind-html='::selectedQuest.notes()') - quest-rewards(key='{{::selectedQuest.key}}', header=env.t('rewards')) - hr + +questInfo + hr .npc_ian.pull-left p=env.t('questSend') p=env.t('questWarning') @@ -44,22 +46,7 @@ script(type='text/ng-template', id='modals/buyQuest.html') .modal-header h4 {{::selectedQuest.text()}} .modal-body - .pull-right-sm.text-center - .col-centered(class='quest_{{::selectedQuest.key}}') - div(ng-if='::selectedQuest.boss') - h4 {{::selectedQuest.boss.name()}} - p - strong=env.t('bossHP') + ': ' - | {{::selectedQuest.boss.hp}} - p - strong=env.t('bossStrength') + ': ' - | {{::selectedQuest.boss.str}} - div(ng-if='::selectedQuest.collect') - p(ng-repeat='(k,v) in ::selectedQuest.collect') - strong=env.t('collect') + ': ' - | {{::selectedQuest.collect[k].count}} {{::selectedQuest.collect[k].text()}} - div(ng-bind-html='::selectedQuest.notes()') - quest-rewards(key='{{::selectedQuest.key}}', header=env.t('rewards')) + +questInfo .modal-footer button.btn.btn-default(ng-click='closeQuest(); $close()')=env.t('neverMind') button.btn.btn-primary(ng-if='::selectedQuest.category !== "gold"', ng-click='purchase("quests", quest); closeQuest(); $close()')=env.t('buyQuest') + ': {{::selectedQuest.value}} ' + env.t('gems') @@ -90,3 +77,18 @@ script(type='text/ng-template', id='modals/questInvitation.html') button.btn.btn-default(ng-click='questHold = true; $close()')=env.t('askLater') button.btn.btn-default(ng-click='questReject(party); $close()')=env.t('reject') button.btn.btn-primary(ng-click='questAccept(party); $close()')=env.t('accept') + +script(type='text/ng-template', id='modals/questDrop.html') + .quest-icon.pull-right(class='inventory_quest_scroll_{{::selectedQuest.key}}') + .modal-header + h4=env.t('messageDropQuest') + .modal-body + h4 {{::selectedQuest.text()}} + +questInfo + hr + .npc_ian.pull-left + p=env.t('dropQuestCongrats') + .modal-footer + button.btn.btn-default(ng-click='closeQuest(); $close()')=env.t('questLater') + button.btn.btn-primary(ng-click='inviteOrStartParty(group); $close()', ng-if='!party.members')=env.t('startAParty') + button.btn.btn-primary(ng-click='questInit(); $close()', ng-if='party.members')=env.t('inviteParty')