diff --git a/common/locales/en/messages.json b/common/locales/en/messages.json index f0c720339c..1c8ce5dcd8 100644 --- a/common/locales/en/messages.json +++ b/common/locales/en/messages.json @@ -13,13 +13,14 @@ "messageDontEnjoyFood": "<%= egg %> eats the <%= foodText %> but doesn't seem to enjoy it.", "messageBought": "Bought <%= itemText %>", "messageEquipped": " <%= itemText %> equipped.", - "messageUnEquipped": "<%= itemText %> un-equipped.", + "messageUnEquipped": "<%= itemText %> unequipped.", "messageMissingEggPotion": "You're missing either that egg or that potion", "messageInvalidEggPotionCombo": "You can't hatch Quest Pet Eggs with Magic Hatching Potions! Try a different egg.", "messageAlreadyPet": "You already have that pet. Try hatching a different combination!", "messageHatched": "Your egg hatched! Visit your stable to equip your pet.", "messageNotEnoughGold": "Not Enough Gold", - "messageTwoHandled": "<%= gearText %> is two handed", + "messageTwoHandedEquip": "Wielding <%= twoHandedText %> takes two hands, so <%= offHandedText %> has been unequipped.", + "messageTwoHandedUnequip": "Wielding <%= twoHandedText %> takes two hands, so it was unequipped when you armed yourself with <%= offHandedText %>.", "messageDropFood": "You've found <%= dropArticle %><%= dropText %>! <%= dropNotes %>", "messageDropEgg": "You've found a <%= dropText %> Egg! <%= dropNotes %>", "messageDropPotion": "You've found a <%= dropText %> Hatching Potion! <%= dropNotes %>", diff --git a/common/script/index.js b/common/script/index.js index aac0735846..b39ff00e89 100644 --- a/common/script/index.js +++ b/common/script/index.js @@ -2063,23 +2063,25 @@ api.wrap = function(user, main) { return content.gear.flat[type + "_base_0"]; } return item; - }, + }, handleTwoHanded: function(item, type, req) { - var message, ref, weapon; + var message, currentWeapon, currentShield; if (type == null) { type = 'equipped'; } - if (item.type === "shield" && ((ref = (weapon = content.gear.flat[user.items.gear[type].weapon])) != null ? ref.twoHanded : void 0)) { + currentShield = content.gear.flat[user.items.gear[type].shield]; + currentWeapon = content.gear.flat[user.items.gear[type].weapon]; + + if (item.type === "shield" && (currentWeapon ? currentWeapon.twoHanded : false)) { user.items.gear[type].weapon = 'weapon_base_0'; - message = i18n.t('messageTwoHandled', { - gearText: weapon.text(req.language) - }, req.language); - } - if (item.twoHanded) { - user.items.gear[type].shield = "shield_base_0"; - message = i18n.t('messageTwoHandled', { - gearText: item.text(req.language) + message = i18n.t('messageTwoHandedUnequip', { + twoHandedText: currentWeapon.text(req.language), offHandedText: item.text(req.language), }, req.language); + } else if (item.twoHanded && (currentShield && user.items.gear[type].shield != "shield_base_0")) { + user.items.gear[type].shield = "shield_base_0"; + message = i18n.t('messageTwoHandedEquip', { + twoHandedText: item.text(req.language), offHandedText: currentShield.text(req.language), + }, req.language); } return message; }, diff --git a/common/script/public/userServices.js b/common/script/public/userServices.js index 67d705e8b7..ba02382fc4 100644 --- a/common/script/public/userServices.js +++ b/common/script/public/userServices.js @@ -106,11 +106,10 @@ angular.module('habitrpg') } if (err) { var message = err.code ? err.message : err; - console.log(message); if (MOBILE_APP) Notification.push({type:'text',text:message}); else Notification.text(message); // In the case of 200s, they're friendly alert messages like "Your pet has hatched!" - still send the op - if ((err.code && err.code >= 400) || !err.code) return; + if ((err.code && err.code >= 400) || !err.code) return; } userServices.log({op:k, params: req.params, query:req.query, body:req.body}); }); diff --git a/test/common/user.ops.equip.test.js b/test/common/user.ops.equip.test.js new file mode 100644 index 0000000000..62f7956e02 --- /dev/null +++ b/test/common/user.ops.equip.test.js @@ -0,0 +1,102 @@ +/* eslint-disable camelcase */ + +import sinon from 'sinon'; // eslint-disable-line no-shadow +import {assert} from 'sinon'; +import i18n from '../../common/script/i18n'; +import shared from '../../common/script/index.js'; +import content from '../../common/script/content/index'; + +describe('user.ops.equip', () => { + let user; + let spy; + + beforeEach(() => { + user = { + items: { + gear: { + owned: { + weapon_warrior_0: true, + weapon_warrior_1: true, + weapon_warrior_2: true, + weapon_wizard_1: true, + weapon_wizard_2: true, + shield_base_0: true, + shield_warrior_1: true, + }, + equipped: { + weapon: 'weapon_warrior_0', + shield: 'shield_base_0', + }, + }, + }, + preferences: {}, + stats: {gp: 200}, + achievements: {}, + flags: {}, + }; + + shared.wrap(user); + spy = sinon.spy(); + }); + + context('Gear', () => { + it('should not send a message if a weapon is equipped while only having zero or one weapons equipped', () => { + // user.ops.equip always calls the callback, even if it isn't sending a message + // so we need to check to see if a single null message was sent. + user.ops.equip({params: {key: 'weapon_warrior_1'}}); + + // one-handed to one-handed + user.ops.equip({params: {key: 'weapon_warrior_2'}}, spy); + + assert.calledOnce(spy); + assert.calledWith(spy, null); + spy.reset(); + + // one-handed to two-handed + user.ops.equip({params: {key: 'weapon_wizard_1'}}, spy); + assert.calledOnce(spy); + assert.calledWith(spy, null); + spy.reset(); + + // two-handed to two-handed + user.ops.equip({params: {key: 'weapon_wizard_2'}}, spy); + assert.calledOnce(spy); + assert.calledWith(spy, null); + spy.reset(); + + // two-handed to one-handed + user.ops.equip({params: {key: 'weapon_warrior_2'}}, spy); + assert.calledOnce(spy); + assert.calledWith(spy, null); + spy.reset(); + }); + + it('should send messages if equipping a two-hander causes the off-hander to be unequipped', () => { + user.ops.equip({params: {key: 'weapon_warrior_1'}}); + user.ops.equip({params: {key: 'shield_warrior_1'}}); + + // equipping two-hander + user.ops.equip({params: {key: 'weapon_wizard_1'}}, spy); + let weapon = content.gear.flat.weapon_wizard_1; + let item = content.gear.flat.shield_warrior_1; + let message = i18n.t('messageTwoHandedEquip', {twoHandedText: weapon.text(null), offHandedText: item.text(null)}); + + assert.calledOnce(spy); + assert.calledWith(spy, {code: 200, message}); + }); + + it('should send messages if equipping an off-hand item causes a two-handed weapon to be unequipped', () => { + // equipping two-hander + user.ops.equip({params: {key: 'weapon_wizard_1'}}); + let weapon = content.gear.flat.weapon_wizard_1; + let shield = content.gear.flat.shield_warrior_1; + + user.ops.equip({params: {key: 'shield_warrior_1'}}, spy); + + let message = i18n.t('messageTwoHandedUnequip', {twoHandedText: weapon.text(null), offHandedText: shield.text(null)}); + + assert.calledOnce(spy); + assert.calledWith(spy, {code: 200, message}); + }); + }); +});