diff --git a/package-lock.json b/package-lock.json
index 34fba602b5..cdf26d5341 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "habitica",
- "version": "4.28.0",
+ "version": "4.28.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index bed67e00ce..e6068ace2d 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
- "version": "4.28.0",
+ "version": "4.28.1",
"main": "./website/server/index.js",
"greenkeeper": {
"ignore": [
diff --git a/test/common/ops/sell.js b/test/common/ops/sell.js
index 11c9676c03..9631fb9650 100644
--- a/test/common/ops/sell.js
+++ b/test/common/ops/sell.js
@@ -75,6 +75,16 @@ describe('shared.ops.sell', () => {
}
});
+ it('returns an error when the requested amount is negative', (done) => {
+ try {
+ sell(user, {params: { type, key }, query: {amount: -42} });
+ } catch (err) {
+ expect(err).to.be.an.instanceof(BadRequest);
+ expect(err.message).to.equal(i18n.t('positiveAmountRequired', {type}));
+ done();
+ }
+ });
+
it('reduces item count from user', () => {
sell(user, {params: { type, key } });
diff --git a/website/client/assets/images/npc/broken/market_broken_background.png b/website/client/assets/images/npc/broken/market_broken_background.png
new file mode 100644
index 0000000000..a1000472c6
Binary files /dev/null and b/website/client/assets/images/npc/broken/market_broken_background.png differ
diff --git a/website/client/assets/images/npc/broken/market_broken_layer.png b/website/client/assets/images/npc/broken/market_broken_layer.png
new file mode 100644
index 0000000000..a9f310ee09
Binary files /dev/null and b/website/client/assets/images/npc/broken/market_broken_layer.png differ
diff --git a/website/client/assets/images/npc/broken/market_broken_npc.png b/website/client/assets/images/npc/broken/market_broken_npc.png
new file mode 100644
index 0000000000..62d7fe69b9
Binary files /dev/null and b/website/client/assets/images/npc/broken/market_broken_npc.png differ
diff --git a/website/client/assets/images/npc/broken/rage-strike-market-scaled@2x.png b/website/client/assets/images/npc/broken/rage-strike-market-scaled@2x.png
new file mode 100644
index 0000000000..56fac8fe2b
Binary files /dev/null and b/website/client/assets/images/npc/broken/rage-strike-market-scaled@2x.png differ
diff --git a/website/client/components/groups/tavern.vue b/website/client/components/groups/tavern.vue
index 7ed00400dd..71224e012d 100644
--- a/website/client/components/groups/tavern.vue
+++ b/website/client/components/groups/tavern.vue
@@ -76,7 +76,7 @@
.m-auto(@click="showWorldBossRage('seasonalShop')")
img.rage-strike(src="~assets/images/world-boss/rage_strike@2x.png", v-if="!group.quest.extra.worldDmg.seasonalShop")
img.rage-strike-active(src="~assets/images/world-boss/rage_strike-seasonalShop@2x.png", v-if="group.quest.extra.worldDmg.seasonalShop")
- .m-auto
+ .m-auto(@click="showWorldBossRage('market')")
img.rage-strike(src="~assets/images/world-boss/rage_strike@2x.png", v-if="!group.quest.extra.worldDmg.market")
img.rage-strike-active(src="~assets/images/world-boss/rage_strike-market@2x.png", v-if="group.quest.extra.worldDmg.market")
.m-auto
@@ -760,6 +760,7 @@ export default {
},
showWorldBossRage (npc) {
if (this.group.quest.extra.worldDmg[npc]) {
+ this.$store.state.rageModalOptions.npc = npc;
this.$root.$emit('bv::show::modal', 'world-boss-rage');
}
},
diff --git a/website/client/components/shops/market/index.vue b/website/client/components/shops/market/index.vue
index 3952ab31d6..db3da6abda 100644
--- a/website/client/components/shops/market/index.vue
+++ b/website/client/components/shops/market/index.vue
@@ -27,7 +27,8 @@
)
.standard-page
div.featuredItems
- .background
+ .background(:class="{broken: broken}")
+ .background(:class="{cracked: broken, broken: broken}")
div.npc
div.featured-label
span.rectangle
@@ -312,8 +313,24 @@
left: 80px;
}
}
- }
+ .background.broken {
+ background: url('~assets/images/npc/broken/market_broken_background.png');
+
+ background-repeat: repeat-x;
+ }
+
+ .background.cracked {
+ background: url('~assets/images/npc/broken/market_broken_layer.png');
+
+ background-repeat: repeat-x;
+ }
+
+ .broken .npc {
+ background: url('~assets/images/npc/broken/market_broken_npc.png');
+ background-repeat: no-repeat;
+ }
+ }
}
.market .gems-left {
@@ -443,8 +460,14 @@ export default {
hideLocked: false,
hidePinned: false,
+
+ broken: false,
};
},
+ async mounted () {
+ const worldState = await this.$store.dispatch('worldState:getWorldState');
+ this.broken = worldState.worldBoss.extra.worldDmg.market;
+ },
computed: {
...mapState({
content: 'content',
diff --git a/website/client/components/shops/market/sellModal.vue b/website/client/components/shops/market/sellModal.vue
index cfeaef7b48..b22bd3fb74 100644
--- a/website/client/components/shops/market/sellModal.vue
+++ b/website/client/components/shops/market/sellModal.vue
@@ -26,7 +26,7 @@
b.how-many-to-sell {{ $t('howManyToSell') }}
div
- b-input.itemsToSell(type="number", v-model="selectedAmountToSell", :max="itemCount", min="1")
+ b-input.itemsToSell(type="number", v-model="selectedAmountToSell", :max="itemCount", min="1", @keyup.native="preventNegative($event)")
span.svg-icon.inline.icon-32(aria-hidden="true", v-html="icons.gold")
span.value {{ item.value }}
@@ -141,6 +141,13 @@
this.selectedAmountToSell = 1;
},
+ preventNegative ($event) {
+ let value = $event.target.value;
+
+ if (isNaN($event.target.valueAsNumber) || Number(value) < 0) {
+ this.selectedAmountToSell = 0;
+ }
+ },
sellItems () {
this.$store.dispatch('shops:sellItems', {
type: this.itemType,
diff --git a/website/client/components/world-boss/worldBossRageModal.vue b/website/client/components/world-boss/worldBossRageModal.vue
index bcae7a5a0d..73e8c1be27 100644
--- a/website/client/components/world-boss/worldBossRageModal.vue
+++ b/website/client/components/world-boss/worldBossRageModal.vue
@@ -1,13 +1,23 @@
b-modal#world-boss-rage(title="", :hide-footer="true", :hide-header="true")
- .modal-header.d-flex.align-items-center.justify-content-center
- .reduce {{ $t('seasonalShopRageStrikeHeader') }}
- img.npc-background(src='~assets/images/npc/broken/rage-strike-seasonalShop-scaled@2x.png')
- .modal-body
- .row
- .col-12.text-center.padding-24
- h2 {{ $t('seasonalShopRageStrikeLead') }}
- p {{ $t('seasonalShopRageStrikeRecap') }}
+ div(v-if="npc === 'seasonalShop'")
+ .modal-header.d-flex.align-items-center.justify-content-center
+ .reduce {{ $t('seasonalShopRageStrikeHeader') }}
+ img.npc-background(src='~assets/images/npc/broken/rage-strike-seasonalShop-scaled@2x.png')
+ .modal-body
+ .row
+ .col-12.text-center.padding-24
+ h2 {{ $t('seasonalShopRageStrikeLead') }}
+ p {{ $t('seasonalShopRageStrikeRecap') }}
+ div(v-if="npc === 'market'")
+ .modal-header.d-flex.align-items-center.justify-content-center
+ .reduce {{ $t('marketRageStrikeHeader') }}
+ img.npc-background(src='~assets/images/npc/broken/rage-strike-market-scaled@2x.png')
+ .modal-body
+ .row
+ .col-12.text-center.padding-24
+ h2 {{ $t('marketRageStrikeLead') }}
+ p {{ $t('marketRageStrikeRecap') }}