diff --git a/website/client/src/assets/css/sprites.css b/website/client/src/assets/css/sprites.css index e38bb7c2bf..ee34061c2a 100755 --- a/website/client/src/assets/css/sprites.css +++ b/website/client/src/assets/css/sprites.css @@ -1,17 +1,11 @@ -.quest_dysheartener { - background: url("~@/assets/images/quest_dysheartener.gif") no-repeat; - width: 219px; - height: 219px; -} - .quest_lostMasterclasser4 { - background: url("~@/assets/images/quest_lostMasterclasser4.gif") no-repeat; + background: url("~@/assets/images/animated/quest_lostMasterclasser4.gif") no-repeat; width: 219px; height: 219px; } .Pet_HatchingPotion_Veggie { - background: url("~@/assets/images/Pet_HatchingPotion_Veggie.gif") no-repeat; + background: url("~@/assets/images/animated/Pet_HatchingPotion_Veggie.gif") no-repeat; width: 68px; height: 68px; } @@ -51,7 +45,7 @@ /* Critical */ .weapon_special_critical { - background: url("~@/assets/images/weapon_special_critical.gif") no-repeat; + background: url("~@/assets/images/animated/weapon_special_critical.gif") no-repeat; width: 90px; height: 90px; margin-left:-12px; @@ -68,32 +62,32 @@ } .head_special_0 { - background: url("~@/assets/images/BackerOnly-Equip-ShadeHelmet.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Equip-ShadeHelmet.gif") no-repeat; } .head_special_1 { - background: url("~@/assets/images/ContributorOnly-Equip-CrystalHelmet.gif") no-repeat; + background: url("~@/assets/images/animated/ContributorOnly-Equip-CrystalHelmet.gif") no-repeat; margin-top: 3px; } .broad_armor_special_0,.slim_armor_special_0 { - background: url("~@/assets/images/BackerOnly-Equip-ShadeArmor.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Equip-ShadeArmor.gif") no-repeat; } .broad_armor_special_1,.slim_armor_special_1 { - background: url("~@/assets/images/ContributorOnly-Equip-CrystalArmor.gif") no-repeat; + background: url("~@/assets/images/animated/ContributorOnly-Equip-CrystalArmor.gif") no-repeat; } .shield_special_0 { - background: url("~@/assets/images/BackerOnly-Shield-TormentedSkull.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Shield-TormentedSkull.gif") no-repeat; } .weapon_special_0 { - background: url("~@/assets/images/BackerOnly-Weapon-DarkSoulsBlade.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Weapon-DarkSoulsBlade.gif") no-repeat; } .Pet-Wolf-Cerberus { width: 105px; height: 72px; - background: url("~@/assets/images/BackerOnly-Pet-CerberusPup.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Pet-CerberusPup.gif") no-repeat; } .broad_armor_special_ks2019, .slim_armor_special_ks2019, .eyewear_special_ks2019, .head_special_ks2019, .shield_special_ks2019 { @@ -102,29 +96,29 @@ } .broad_armor_special_ks2019, .slim_armor_special_ks2019 { - background: url("~@/assets/images/BackerOnly-Equip-MythicGryphonArmor.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Equip-MythicGryphonArmor.gif") no-repeat; } .eyewear_special_ks2019 { - background: url("~@/assets/images/BackerOnly-Equip-MythicGryphonVisor.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Equip-MythicGryphonVisor.gif") no-repeat; } .head_special_ks2019 { - background: url("~@/assets/images/BackerOnly-Equip-MythicGryphonHelm.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Equip-MythicGryphonHelm.gif") no-repeat; } .shield_special_ks2019 { - background: url("~@/assets/images/BackerOnly-Equip-MythicGryphonShield.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Equip-MythicGryphonShield.gif") no-repeat; } .weapon_special_ks2019 { - background: url("~@/assets/images/BackerOnly-Equip-MythicGryphonGlaive.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Equip-MythicGryphonGlaive.gif") no-repeat; width: 120px; height: 120px; } .Pet-Gryphon-Gryphatrice { - background: url("~@/assets/images/BackerOnly-Pet-Gryphatrice.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Pet-Gryphatrice.gif") no-repeat; width: 81px; height: 99px; } @@ -135,11 +129,28 @@ } .Mount_Head_Gryphon-Gryphatrice { - background: url("~@/assets/images/BackerOnly-Mount-Head-Gryphatrice.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Mount-Head-Gryphatrice.gif") no-repeat; } .Mount_Body_Gryphon-Gryphatrice { - background: url("~@/assets/images/BackerOnly-Mount-Body-Gryphatrice.gif") no-repeat; + background: url("~@/assets/images/animated/BackerOnly-Mount-Body-Gryphatrice.gif") no-repeat; +} + +.background_airship, .background_clocktower, .background_steamworks { + width: 141px; + height: 147px; +} + +.background_airship { + background: url("~@/assets/images/animated/background_airship.gif") no-repeat; +} + +.background_clocktower { + background: url("~@/assets/images/animated/background_airship.gif") no-repeat; +} + +.background_steamworks { + background: url("~@/assets/images/animated/background_steamworks.gif") no-repeat; } /* FIXME figure out how to handle customize menu!! diff --git a/website/client/src/assets/images/BackerOnly-Equip-MythicGryphonArmor.gif b/website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonArmor.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Equip-MythicGryphonArmor.gif rename to website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonArmor.gif diff --git a/website/client/src/assets/images/BackerOnly-Equip-MythicGryphonGlaive.gif b/website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonGlaive.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Equip-MythicGryphonGlaive.gif rename to website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonGlaive.gif diff --git a/website/client/src/assets/images/BackerOnly-Equip-MythicGryphonHelm.gif b/website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonHelm.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Equip-MythicGryphonHelm.gif rename to website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonHelm.gif diff --git a/website/client/src/assets/images/BackerOnly-Equip-MythicGryphonShield.gif b/website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonShield.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Equip-MythicGryphonShield.gif rename to website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonShield.gif diff --git a/website/client/src/assets/images/BackerOnly-Equip-MythicGryphonVisor.gif b/website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonVisor.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Equip-MythicGryphonVisor.gif rename to website/client/src/assets/images/animated/BackerOnly-Equip-MythicGryphonVisor.gif diff --git a/website/client/src/assets/images/BackerOnly-Equip-ShadeArmor.gif b/website/client/src/assets/images/animated/BackerOnly-Equip-ShadeArmor.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Equip-ShadeArmor.gif rename to website/client/src/assets/images/animated/BackerOnly-Equip-ShadeArmor.gif diff --git a/website/client/src/assets/images/BackerOnly-Equip-ShadeHelmet.gif b/website/client/src/assets/images/animated/BackerOnly-Equip-ShadeHelmet.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Equip-ShadeHelmet.gif rename to website/client/src/assets/images/animated/BackerOnly-Equip-ShadeHelmet.gif diff --git a/website/client/src/assets/images/BackerOnly-Mount-Body-Gryphatrice.gif b/website/client/src/assets/images/animated/BackerOnly-Mount-Body-Gryphatrice.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Mount-Body-Gryphatrice.gif rename to website/client/src/assets/images/animated/BackerOnly-Mount-Body-Gryphatrice.gif diff --git a/website/client/src/assets/images/BackerOnly-Mount-Head-Gryphatrice.gif b/website/client/src/assets/images/animated/BackerOnly-Mount-Head-Gryphatrice.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Mount-Head-Gryphatrice.gif rename to website/client/src/assets/images/animated/BackerOnly-Mount-Head-Gryphatrice.gif diff --git a/website/client/src/assets/images/BackerOnly-Pet-CerberusPup.gif b/website/client/src/assets/images/animated/BackerOnly-Pet-CerberusPup.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Pet-CerberusPup.gif rename to website/client/src/assets/images/animated/BackerOnly-Pet-CerberusPup.gif diff --git a/website/client/src/assets/images/BackerOnly-Pet-Gryphatrice.gif b/website/client/src/assets/images/animated/BackerOnly-Pet-Gryphatrice.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Pet-Gryphatrice.gif rename to website/client/src/assets/images/animated/BackerOnly-Pet-Gryphatrice.gif diff --git a/website/client/src/assets/images/BackerOnly-Shield-TormentedSkull.gif b/website/client/src/assets/images/animated/BackerOnly-Shield-TormentedSkull.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Shield-TormentedSkull.gif rename to website/client/src/assets/images/animated/BackerOnly-Shield-TormentedSkull.gif diff --git a/website/client/src/assets/images/BackerOnly-Weapon-DarkSoulsBlade.gif b/website/client/src/assets/images/animated/BackerOnly-Weapon-DarkSoulsBlade.gif similarity index 100% rename from website/client/src/assets/images/BackerOnly-Weapon-DarkSoulsBlade.gif rename to website/client/src/assets/images/animated/BackerOnly-Weapon-DarkSoulsBlade.gif diff --git a/website/client/src/assets/images/ContributorOnly-Equip-CrystalArmor.gif b/website/client/src/assets/images/animated/ContributorOnly-Equip-CrystalArmor.gif similarity index 100% rename from website/client/src/assets/images/ContributorOnly-Equip-CrystalArmor.gif rename to website/client/src/assets/images/animated/ContributorOnly-Equip-CrystalArmor.gif diff --git a/website/client/src/assets/images/ContributorOnly-Equip-CrystalHelmet.gif b/website/client/src/assets/images/animated/ContributorOnly-Equip-CrystalHelmet.gif similarity index 100% rename from website/client/src/assets/images/ContributorOnly-Equip-CrystalHelmet.gif rename to website/client/src/assets/images/animated/ContributorOnly-Equip-CrystalHelmet.gif diff --git a/website/client/src/assets/images/Pet_HatchingPotion_Veggie.gif b/website/client/src/assets/images/animated/Pet_HatchingPotion_Veggie.gif similarity index 100% rename from website/client/src/assets/images/Pet_HatchingPotion_Veggie.gif rename to website/client/src/assets/images/animated/Pet_HatchingPotion_Veggie.gif diff --git a/website/client/src/assets/images/animated/background_airship.gif b/website/client/src/assets/images/animated/background_airship.gif new file mode 100644 index 0000000000..106f0cde58 Binary files /dev/null and b/website/client/src/assets/images/animated/background_airship.gif differ diff --git a/website/client/src/assets/images/animated/background_steamworks.gif b/website/client/src/assets/images/animated/background_steamworks.gif new file mode 100644 index 0000000000..581684f9d0 Binary files /dev/null and b/website/client/src/assets/images/animated/background_steamworks.gif differ diff --git a/website/client/src/assets/images/npc_ian.gif b/website/client/src/assets/images/animated/npc_ian.gif similarity index 100% rename from website/client/src/assets/images/npc_ian.gif rename to website/client/src/assets/images/animated/npc_ian.gif diff --git a/website/client/src/assets/images/quest_bewilder.gif b/website/client/src/assets/images/animated/quest_bewilder.gif similarity index 100% rename from website/client/src/assets/images/quest_bewilder.gif rename to website/client/src/assets/images/animated/quest_bewilder.gif diff --git a/website/client/src/assets/images/quest_burnout.gif b/website/client/src/assets/images/animated/quest_burnout.gif similarity index 100% rename from website/client/src/assets/images/quest_burnout.gif rename to website/client/src/assets/images/animated/quest_burnout.gif diff --git a/website/client/src/assets/images/quest_dysheartener.gif b/website/client/src/assets/images/animated/quest_dysheartener.gif similarity index 100% rename from website/client/src/assets/images/quest_dysheartener.gif rename to website/client/src/assets/images/animated/quest_dysheartener.gif diff --git a/website/client/src/assets/images/quest_lostMasterclasser4.gif b/website/client/src/assets/images/animated/quest_lostMasterclasser4.gif similarity index 100% rename from website/client/src/assets/images/quest_lostMasterclasser4.gif rename to website/client/src/assets/images/animated/quest_lostMasterclasser4.gif diff --git a/website/client/src/assets/images/weapon_special_critical.gif b/website/client/src/assets/images/animated/weapon_special_critical.gif similarity index 100% rename from website/client/src/assets/images/weapon_special_critical.gif rename to website/client/src/assets/images/animated/weapon_special_critical.gif diff --git a/website/client/src/components/shops/timeTravelers/index.vue b/website/client/src/components/shops/timeTravelers/index.vue index b399ecbd65..dffc0f04b9 100644 --- a/website/client/src/components/shops/timeTravelers/index.vue +++ b/website/client/src/components/shops/timeTravelers/index.vue @@ -390,9 +390,9 @@ export default { // force update for now until we restructure the data let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line - const normalGroups = _filter(apiCategories, c => c.identifier === 'mounts' || c.identifier === 'pets' || c.identifier === 'quests'); + const normalGroups = _filter(apiCategories, c => c.identifier === 'mounts' || c.identifier === 'pets' || c.identifier === 'quests' || c.identifier === 'backgrounds'); - const setGroups = _filter(apiCategories, c => c.identifier !== 'mounts' && c.identifier !== 'pets' && c.identifier !== 'quests'); + const setGroups = _filter(apiCategories, c => c.identifier !== 'mounts' && c.identifier !== 'pets' && c.identifier !== 'quests' && c.identifier !== 'backgrounds'); const setCategory = { identifier: 'sets', diff --git a/website/client/src/store/actions/shops.js b/website/client/src/store/actions/shops.js index e79beb187f..d06b2fcb06 100644 --- a/website/client/src/store/actions/shops.js +++ b/website/client/src/store/actions/shops.js @@ -160,6 +160,9 @@ export async function genericPurchase (store, params) { // resetting type to pinType only here return buyItem(store, { ...params, type: params.pinType }); case 'background': + if (params.currency === 'hourglasses') { + return purchaseHourglassItem(store, params); + } return unlock(store, { query: { path: `background.${params.key}`, diff --git a/website/common/locales/en/subscriber.json b/website/common/locales/en/subscriber.json index bad5adb794..988d680830 100644 --- a/website/common/locales/en/subscriber.json +++ b/website/common/locales/en/subscriber.json @@ -180,6 +180,7 @@ "notEnoughHourglasses": "You don't have enough Mystic Hourglasses.", "hourglassBuyEquipSetConfirm": "Buy this full set of items for 1 Mystic Hourglass?", "hourglassBuyItemConfirm": "Buy this item for 1 Mystic Hourglass?", + "backgroundsAlreadyOwned": "Background already owned.", "petsAlreadyOwned": "Pet already owned.", "mountsAlreadyOwned": "Mount already owned.", "typeNotAllowedHourglass": "Item type not supported for purchase with Mystic Hourglass. Allowed types: <%= allowedTypes %>", diff --git a/website/common/script/content/appearance/backgrounds.js b/website/common/script/content/appearance/backgrounds.js index 5afd305265..23af2fa64e 100644 --- a/website/common/script/content/appearance/backgrounds.js +++ b/website/common/script/content/appearance/backgrounds.js @@ -973,6 +973,26 @@ const backgrounds = { currency: 'loginIncentive', }, }, + timeTravelBackgrounds: { + airship: { + text: t('backgroundAirshipText'), + notes: t('backgroundAirshipNotes'), + price: 1, + currency: 'hourglasses', + }, + clocktower: { + text: t('backgroundClocktowerText'), + notes: t('backgroundClocktowerNotes'), + price: 1, + currency: 'hourglasses', + }, + steamworks: { + text: t('backgroundSteamworksText'), + notes: t('backgroundSteamworksNotes'), + price: 1, + currency: 'hourglasses', + }, + }, }; /* eslint-enable quote-props */ @@ -982,7 +1002,7 @@ forOwn(backgrounds, (backgroundsInSet, set) => { forOwn(backgroundsInSet, (background, bgKey) => { background.key = bgKey; background.set = set; - background.price = 7; + background.price = background.price || 7; flat[bgKey] = background; }); diff --git a/website/common/script/errors/commonErrorMessages.js b/website/common/script/errors/commonErrorMessages.js index 7f0530f5ff..b71b37c5b4 100644 --- a/website/common/script/errors/commonErrorMessages.js +++ b/website/common/script/errors/commonErrorMessages.js @@ -13,6 +13,7 @@ export default { invalidTypeEquip: '"type" must be one of "equipped", "pet", "mount", "costume"', missingPetFoodFeed: '"pet" and "food" are required parameters.', missingEggHatchingPotion: '"egg" and "hatchingPotion" are required parameters.', + useUnlockForCosmetics: 'Use the "unlock" route to purchase backgrounds and avatar customizations using Gems.', invalidPetName: 'Invalid pet name supplied.', invalidFoodName: 'Invalid food name supplied.', diff --git a/website/common/script/libs/shops.js b/website/common/script/libs/shops.js index 949044ca3e..abd6ea734d 100644 --- a/website/common/script/libs/shops.js +++ b/website/common/script/libs/shops.js @@ -326,6 +326,25 @@ shops.getTimeTravelersCategories = function getTimeTravelersCategories (user, la } categories.push(questCategory); + const backgroundCategory = { + identifier: 'backgrounds', + text: i18n.t('backgrounds', language), + items: [], + }; + for (const bg in content.backgrounds.timeTravelBackgrounds) { + if (!user.purchased.background[bg]) { + const item = getItemInfo( + user, + 'background', + content.backgroundsFlat[bg], + officialPinnedItems, + language, + ); + backgroundCategory.items.push(item); + } + } + categories.push(backgroundCategory); + for (const type of Object.keys(stable)) { const category = { identifier: type, diff --git a/website/common/script/ops/buy/buy.js b/website/common/script/ops/buy/buy.js index 7b9795986d..6394005927 100644 --- a/website/common/script/ops/buy/buy.js +++ b/website/common/script/ops/buy/buy.js @@ -43,6 +43,10 @@ export default function buy ( buyRes = buyOp.purchase(); break; } + case 'backgrounds': + if (!hourglass) throw new BadRequest(errorMessage('useUnlockForCosmetics')); + buyRes = hourglassPurchase(user, req, analytics); + break; case 'mystery': buyRes = buyMysterySet(user, req, analytics); break; diff --git a/website/common/script/ops/buy/hourglassPurchase.js b/website/common/script/ops/buy/hourglassPurchase.js index f721acbc43..e3997957c2 100644 --- a/website/common/script/ops/buy/hourglassPurchase.js +++ b/website/common/script/ops/buy/hourglassPurchase.js @@ -16,7 +16,21 @@ export default function purchaseHourglass (user, req = {}, analytics, quantity = const type = get(req, 'params.type'); if (!type) throw new BadRequest(errorMessage('missingTypeParam')); - if (type === 'quests') { + if (type === 'backgrounds') { + if (!content.backgroundsFlat[key] || content.backgroundsFlat[key].currency !== 'hourglasses') { + throw new NotAuthorized(i18n.t('notAllowedHourglass', req.language)); + } + if (user.purchased.background[key]) { + throw new NotAuthorized(i18n.t('backgroundAlreadyOwned', req.language)); + } + if (user.purchased.plan.consecutive.trinkets <= 0) { + throw new NotAuthorized(i18n.t('notEnoughHourglasses', req.language)); + } + + user.purchased.background[key] = true; + user.purchased.plan.consecutive.trinkets -= 1; + if (user.markModified) user.markModified('purchased.background'); + } else if (type === 'quests') { if (!content.quests[key] || content.quests[key].category !== 'timeTravelers') throw new NotAuthorized(i18n.t('notAllowedHourglass', req.language)); if (user.purchased.plan.consecutive.trinkets < quantity) { throw new NotAuthorized(i18n.t('notEnoughHourglasses', req.language)); diff --git a/website/raw_sprites/spritesmith/backgrounds/icons/icon_background_airship.png b/website/raw_sprites/spritesmith/backgrounds/icons/icon_background_airship.png new file mode 100644 index 0000000000..5de5ee4220 Binary files /dev/null and b/website/raw_sprites/spritesmith/backgrounds/icons/icon_background_airship.png differ diff --git a/website/raw_sprites/spritesmith/backgrounds/icons/icon_background_clocktower.png b/website/raw_sprites/spritesmith/backgrounds/icons/icon_background_clocktower.png new file mode 100644 index 0000000000..0713083355 Binary files /dev/null and b/website/raw_sprites/spritesmith/backgrounds/icons/icon_background_clocktower.png differ diff --git a/website/raw_sprites/spritesmith/backgrounds/icons/icon_background_steamworks.png b/website/raw_sprites/spritesmith/backgrounds/icons/icon_background_steamworks.png new file mode 100644 index 0000000000..25b49fdb58 Binary files /dev/null and b/website/raw_sprites/spritesmith/backgrounds/icons/icon_background_steamworks.png differ