diff --git a/.changeset/serious-islands-beg.md b/.changeset/serious-islands-beg.md new file mode 100644 index 0000000..296bd2b --- /dev/null +++ b/.changeset/serious-islands-beg.md @@ -0,0 +1,5 @@ +--- +"@gw2api/types": patch +--- + +Add types for `/v2/achievements`, `/v2/achievements/categories` and `/v2/achievements/groups` diff --git a/packages/types/data/achievement-category.ts b/packages/types/data/achievement-category.ts new file mode 100644 index 0000000..fee91a5 --- /dev/null +++ b/packages/types/data/achievement-category.ts @@ -0,0 +1,59 @@ +import type { SchemaAfter, SchemaVersion } from "../schema"; + +/** + * AchievementCategory as returned from `/v2/achievements/categories` + * @see https://wiki.guildwars2.com/wiki/API:2/achievements/categories + */ +export type AchievementCategory = + Schema extends undefined ? AchievementCategory_Base : + Schema extends SchemaAfter<'2022-03-23T19:00:00.000Z'> | 'latest' ? AchievementCategory_2022_03_23 : + AchievementCategory_Base; + + +interface AchievementCategory_Base { + /** The id of the achievement category */ + id: number; + + /** The name of the achievement category */ + name: string; + + /** The description of the achievement category */ + description: string; + + /** The icon of the achievement category */ + icon: string; + + /** The order of the achievement category in which they appear in-game (ascending) */ + order: number; + + /** List of achievement ids that are part of this achievement category */ + achievements: number[]; +} + +interface AchievementCategory_2022_03_23 extends Omit { + /** List of achievements that are currently part of this achievement category */ + achievements: AchievementCategoryAchievement[]; + + /** List of achievements that will be part of this achievement category tomorrow, if this achievement category is on a rotation */ + tomorrow?: AchievementCategoryAchievement[]; +} + +interface AchievementCategoryAchievement { + /** The id of the achievement */ + id: number; + + /** Flags of the achievement */ + flags?: ('PvE' | 'PvP' | 'WvW' | 'SpecialEvent')[]; + + /** The required level range for this achievement to be available in-game (both inclusive) */ + level?: [number, number]; + + /** Required access to an extension for this achievement to be available in-game */ + required_access?: { + /** The extension for this requirement */ + product: 'PathOfFire' | 'HeartOfThorns'; + + /** Condition for this extension */ + condition: 'NoAccess' | 'HasAccess'; + }; +} diff --git a/packages/types/data/achievement-group.ts b/packages/types/data/achievement-group.ts new file mode 100644 index 0000000..4d6a97a --- /dev/null +++ b/packages/types/data/achievement-group.ts @@ -0,0 +1,20 @@ +/** + * AchievementGroup as returned from `/v2/achievements/groups` + * @see https://wiki.guildwars2.com/wiki/API:2/achievements/groups + */ +export interface AchievementGroup { + /** The id of the achievement group */ + id: string; + + /** The name of the achievement group */ + name: string; + + /** The description of the achievement group */ + description: string; + + /** The order in-game (ascending) */ + order: number; + + /** Achievement category ids that are part of this group */ + categories: number[]; +}; diff --git a/packages/types/data/achievement.ts b/packages/types/data/achievement.ts new file mode 100644 index 0000000..b87db04 --- /dev/null +++ b/packages/types/data/achievement.ts @@ -0,0 +1,85 @@ +/** + * Achievement as returned from `/v2/achievements` + * @see https://wiki.guildwars2.com/wiki/API:2/achievements + */ +export interface Achievement { + /** The id of the achievement */ + id: number; + + /** The name of the achievement */ + name: string; + + /** Description of the achievement */ + description: string; + + /** The icon of the achievement if different from the achievement category */ + icon?: string; + + /** The type of the achievement */ + type: 'Default' | 'ItemSet'; + + /** Achievement Flags */ + flags: AchievementFlags[]; + + /** The description of the achievement when it is still locked */ + locked_text: string; + + /** List of achievement ids that have to be completed before unlocking this achievement */ + prerequisites?: number[]; + + /** Achievement requirement */ + requirement: string; + + /** Achievement objectives */ + bits?: AchievementBit[]; + + /** Final rewards */ + rewards?: AchievementReward[]; + + /** Reward tiers */ + tiers: AchievementTier[]; + + /** Maximum AP for repeatable achievements */ + point_cap?: number; +}; + +export type AchievementFlags = + | 'Pvp' + | 'CategoryDisplay' + | 'MoveToTop' + | 'IgnoreNearlyComplete' + | 'Repeatable' + | 'Hidden' + | 'RequiresUnlock' + | 'RepairOnLogin' + | 'Daily' + | 'Weekly' + | 'Monthly' + | 'Permanent' + +export type AchievementBit = + | { type: 'Text', text: string } + | { type: 'Item' | 'Skin' | 'Minipet', id: number } + +export type AchievementReward = + | { type: 'Item', id: number, count: number } + | { type: 'Title', id: number } + | { type: 'Mastery', id: number, region: MasteryRegion } + | { type: 'Coins', count: number } + +export type MasteryRegion = + | 'Tyria' // core + | 'Maguuma' // HoT + | 'Desert' // PoF + | 'Tundra' // Icebrood + | 'Jade' // EoD + | 'Sky' // SotO + | 'Unknown'; // Non whitelisted regions for future expansions + +export type AchievementTier = { + /** Number of objectives that need to be completed */ + count: number; + + /** AP rewarded for this tier */ + points: number; +} diff --git a/packages/types/endpoints.ts b/packages/types/endpoints.ts index 44e612e..12b1ede 100644 --- a/packages/types/endpoints.ts +++ b/packages/types/endpoints.ts @@ -6,6 +6,9 @@ import type { AccountLegendaryarmory } from './data/account-legendaryarmory'; import type { AccountMaterials } from './data/account-material'; import type { AccountWallet } from './data/account-wallet'; import type { AccountWizardsVaultListing, AccountWizardsVaultMetaObjectives, AccountWizardsVaultSpecialObjectives } from './data/account-wizardsvault'; +import type { Achievement } from './data/achievement'; +import type { AchievementCategory } from './data/achievement-category'; +import type { AchievementGroup } from './data/achievement-group'; import type { Character, CharacterBackstory, CharacterBuildTab, CharacterCore, CharacterCrafting, CharacterEquipment, CharacterEquipmentTab, CharacterInventory, CharacterRecipes, CharacterSkills, CharacterSpecializations, CharacterTraining } from './data/character'; import type { Color } from './data/color'; import type { Listing, Price, TransactionCurrent, TransactionHistoric } from './data/commerce'; @@ -419,6 +422,9 @@ export type EndpointType ? BulkExpandedResponseType<'/v2/characters', Url, string, Character> : Url extends CreateSubtokenUrl<'/v2/createsubtoken'> ? Createsubtoken : + Url extends BulkExpandedEndpointUrl<'/v2/achievements/categories', number> ? BulkExpandedResponseType<'/v2/achievements/categories', Url, number, AchievementCategory> : + Url extends BulkExpandedEndpointUrl<'/v2/achievements/groups', number> ? BulkExpandedResponseType<'/v2/achievements/groups', Url, number, AchievementGroup> : + Url extends BulkExpandedEndpointUrl<'/v2/achievements', number> ? BulkExpandedResponseType<'/v2/achievements', Url, number, Achievement> : Url extends BulkExpandedEndpointUrl<'/v2/colors', number> ? BulkExpandedResponseType<'/v2/colors', Url, number, Color> : Url extends BulkExpandedEndpointUrl<'/v2/currencies', number> ? BulkExpandedResponseType<'/v2/currencies', Url, number, Currency> : Url extends BulkExpandedEndpointUrl<'/v2/guild/upgrades', number> ? BulkExpandedResponseType<'/v2/guild/upgrades', Url, number, GuildUpgrade> :