From 4d0e234d0ca7f098073641dc9bdb89863fc1b686 Mon Sep 17 00:00:00 2001 From: Kyle Kemp Date: Fri, 30 Jun 2023 10:42:53 -0500 Subject: [PATCH] feat(inventory): add item compare modal pre-equip. closes #76 --- .../compare-items.component.html | 98 +++++++++++++++++++ .../compare-items.component.scss | 35 +++++++ .../compare-items/compare-items.component.ts | 45 +++++++++ .../app/pages/inventory/inventory.page.html | 10 +- .../src/app/pages/inventory/inventory.page.ts | 88 +++++++++++++---- client/src/app/shared.module.ts | 2 + 6 files changed, 253 insertions(+), 25 deletions(-) create mode 100644 client/src/app/components/modals/compare-items/compare-items.component.html create mode 100644 client/src/app/components/modals/compare-items/compare-items.component.scss create mode 100644 client/src/app/components/modals/compare-items/compare-items.component.ts diff --git a/client/src/app/components/modals/compare-items/compare-items.component.html b/client/src/app/components/modals/compare-items/compare-items.component.html new file mode 100644 index 0000000..2159bb8 --- /dev/null +++ b/client/src/app/components/modals/compare-items/compare-items.component.html @@ -0,0 +1,98 @@ + + + + + Compare Items + + + Equip + Close + + + + + + + + + + + + + + + + + {{ item1.name }} +
+ Lv.{{ item1.levelRequirement }} +
+
+
+
+ + + + + + {{ stat }} + + + + {{ item1.stats[stat] > 0 ? '+' : '' }} + {{ item1.stats[stat] || 0 | number }} + + + + +
+ + + + (nothing) + + + + + + + + + + + + {{ item2.name }} +
+ Lv.{{ item2.levelRequirement }} +
+
+
+
+ + + + + + {{ stat }} + + + + {{ item2.stats[stat] > 0 ? '+' : '' }} + {{ item2.stats[stat] || 0 | number }} + + + + +
+
+
+
+
diff --git a/client/src/app/components/modals/compare-items/compare-items.component.scss b/client/src/app/components/modals/compare-items/compare-items.component.scss new file mode 100644 index 0000000..091ab29 --- /dev/null +++ b/client/src/app/components/modals/compare-items/compare-items.component.scss @@ -0,0 +1,35 @@ + +.name-row { + + .icon { + max-width: 80px; + display: flex; + justify-content: center; + align-items: center; + } + + .name { + display: flex; + align-items: center; + font-weight: bold; + } +} + +.stat-row { + + &.higher { + color: var(--ion-color-success); + } + + &.lower { + color: var(--ion-color-danger); + } + + .stat { + + } + + .value { + font-weight: bold; + } +} diff --git a/client/src/app/components/modals/compare-items/compare-items.component.ts b/client/src/app/components/modals/compare-items/compare-items.component.ts new file mode 100644 index 0000000..c03a2db --- /dev/null +++ b/client/src/app/components/modals/compare-items/compare-items.component.ts @@ -0,0 +1,45 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { IEquipment, Stat } from '@interfaces'; +import { ModalController } from '@ionic/angular'; + +@Component({ + selector: 'app-compare-items', + templateUrl: './compare-items.component.html', + styleUrls: ['./compare-items.component.scss'], +}) +export class CompareItemsModalComponent implements OnInit { + @Input() item1!: IEquipment; + @Input() item2!: IEquipment | undefined; + + public commonStats: Stat[] = []; + + constructor(private modalCtrl: ModalController) {} + + ngOnInit() { + const stats = new Set(); + Object.keys(this.item1.stats).forEach((stat) => stats.add(stat)); + + if (this.item2) { + Object.keys(this.item2.stats).forEach((stat) => stats.add(stat)); + } + + this.commonStats = Array.from(stats).sort() as Stat[]; + } + + dismiss(value?: any) { + this.modalCtrl.dismiss(value); + } + + getStatClassBetweenItems( + stat: Stat, + item1: IEquipment, + item2?: IEquipment, + ): string { + if (!item2) return 'higher'; + + if (item1.stats[stat] > (item2.stats[stat] ?? 0)) return 'higher'; + if (item1.stats[stat] < item2.stats[stat]) return 'lower'; + + return ''; + } +} diff --git a/client/src/app/pages/inventory/inventory.page.html b/client/src/app/pages/inventory/inventory.page.html index 8bf828c..d8867bf 100644 --- a/client/src/app/pages/inventory/inventory.page.html +++ b/client/src/app/pages/inventory/inventory.page.html @@ -7,7 +7,9 @@ - + @@ -116,7 +118,7 @@ Equip Armor @@ -124,7 +126,7 @@ Equip Weapon @@ -135,7 +137,7 @@ Equip Accessory (Slot {{ slot }}) diff --git a/client/src/app/pages/inventory/inventory.page.ts b/client/src/app/pages/inventory/inventory.page.ts index 727a215..dedb72b 100644 --- a/client/src/app/pages/inventory/inventory.page.ts +++ b/client/src/app/pages/inventory/inventory.page.ts @@ -6,16 +6,19 @@ import { IEquipment, IItem, IPlayer, + ItemSlot, Weapon, } from '@interfaces'; import { ContentService } from '@services/content.service'; import { PlayerService } from '@services/player.service'; +import { CompareItemsModalComponent } from '@components/modals/compare-items/compare-items.component'; import { itemValue } from '@helpers/item'; +import { ModalController } from '@ionic/angular'; import { Select, Store } from '@ngxs/store'; import { GameplayService } from '@services/gameplay.service'; import { UserService } from '@services/user.service'; -import { PlayerStore } from '@stores'; +import { InventoryStore, PlayerStore } from '@stores'; import { Observable } from 'dexie'; @Component({ @@ -25,6 +28,9 @@ import { Observable } from 'dexie'; }) export class InventoryPage implements OnInit { @Select(PlayerStore.player) player$!: Observable; + @Select(InventoryStore.equipped) equipped$!: Observable< + Record + >; public readonly basicEquipTypes = [ 'body', @@ -62,6 +68,7 @@ export class InventoryPage implements OnInit { private store: Store, public playerService: PlayerService, public contentService: ContentService, + private modalController: ModalController, private gameplayService: GameplayService, private userService: UserService, ) {} @@ -140,9 +147,21 @@ export class InventoryPage implements OnInit { ); } - // job check, job check, job check, level check + getEquippedItem( + slot: ItemSlot | string, + equipment?: Record, + ): IEquipment | undefined { + return equipment?.[slot as ItemSlot]; + } + canEquipItem(player: unknown, item: IEquipment) { - return (player as IPlayer).level >= item.levelRequirement; + const playerRef = player as IPlayer; + const playerJob = this.contentService.getJob(playerRef.job); + return ( + playerRef.level >= item.levelRequirement && + (playerJob?.armorSlots[item.type as Armor] || + playerJob?.weapons[item.type as Weapon]) + ); } canEquipWeapon(player: unknown, item: IEquipment) { @@ -161,27 +180,54 @@ export class InventoryPage implements OnInit { return jobRef.armorSlots[item.type as Armor]; } - equipArmor(item: IEquipment) { - this.gameplayService - .equipItem(item.type as Armor, item.instanceId ?? '') - .subscribe(() => { - this.updateItems(); - }); + private async compareItems( + item1: IItem, + item2: IItem | undefined, + success: () => void, + ) { + const modal = await this.modalController.create({ + component: CompareItemsModalComponent, + componentProps: { + item1, + item2, + }, + }); + + await modal.present(); + + const { data } = await modal.onWillDismiss(); + if (data) { + success(); + } + } + + equipArmor(item: IEquipment, currentItem?: IEquipment) { + this.compareItems(item, currentItem, () => { + this.gameplayService + .equipItem(item.type as Armor, item.instanceId ?? '') + .subscribe(() => { + this.updateItems(); + }); + }); } - equipWeapon(item: IEquipment) { - this.gameplayService - .equipItem('weapon', item.instanceId ?? '') - .subscribe(() => { - this.updateItems(); - }); + equipWeapon(item: IEquipment, currentItem?: IEquipment) { + this.compareItems(item, currentItem, () => { + this.gameplayService + .equipItem('weapon', item.instanceId ?? '') + .subscribe(() => { + this.updateItems(); + }); + }); } - equipAccessory(item: IEquipment, slot: number) { - this.gameplayService - .equipItem(`accessory${slot as 1 | 2 | 3}`, item.instanceId ?? '') - .subscribe(() => { - this.updateItems(); - }); + equipAccessory(item: IEquipment, slot: number, currentItem?: IEquipment) { + this.compareItems(item, currentItem, () => { + this.gameplayService + .equipItem(`accessory${slot as 1 | 2 | 3}`, item.instanceId ?? '') + .subscribe(() => { + this.updateItems(); + }); + }); } } diff --git a/client/src/app/shared.module.ts b/client/src/app/shared.module.ts index 8816708..a983010 100644 --- a/client/src/app/shared.module.ts +++ b/client/src/app/shared.module.ts @@ -12,6 +12,7 @@ import { ItemIconComponent } from '@components/item-icon/item-icon.component'; import { ItemRarityComponent } from '@components/item-rarity/item-rarity.component'; import { ItemStatsComponent } from '@components/item-stats/item-stats.component'; import { ChooseAvatarModalComponent } from '@components/modals/choose-avatar/choose-avatar.component'; +import { CompareItemsModalComponent } from '@components/modals/compare-items/compare-items.component'; import { StoreTextComponent } from '@components/store-text/store-text.component'; import { RelativeTimePipe } from '@helpers/relativetime.pipe'; import { IonicModule } from '@ionic/angular'; @@ -23,6 +24,7 @@ const components = [ CardOnlineUsersComponent, HeroComponent, ChooseAvatarModalComponent, + CompareItemsModalComponent, HeaderBarComponent, AvatarComponent, ItemIconComponent,