Skip to content

Commit

Permalink
feat(inventory): add item compare modal pre-equip. closes #76
Browse files Browse the repository at this point in the history
  • Loading branch information
seiyria committed Jun 30, 2023
1 parent 92220bd commit 4d0e234
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start"></ion-buttons>

<ion-title>Compare Items</ion-title>

<ion-buttons slot="end">
<ion-button (click)="dismiss(true)" [strong]="true">Equip</ion-button>
<ion-button color="medium" (click)="dismiss()">Close</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>

<ion-content class="ion-padding">
<ion-card>
<ion-card-content>
<ion-row>
<ion-col>
<ion-row>
<ion-col>
<ion-row class="name-row">
<ion-col class="icon">
<app-item-icon [item]="item1" size="small"></app-item-icon>
</ion-col>
<ion-col class="name">
{{ item1.name }}
<br />
Lv.{{ item1.levelRequirement }}
</ion-col>
</ion-row>
</ion-col>
</ion-row>

<ion-row
*ngFor="let stat of commonStats"
class="stat-row"
[ngClass]="getStatClassBetweenItems(stat, item1, item2)"
>
<ion-col>
<ion-row>
<ion-col class="stat">
{{ stat }}
</ion-col>

<ion-col class="value">
{{ item1.stats[stat] > 0 ? '+' : '' }}
{{ item1.stats[stat] || 0 | number }}
</ion-col>
</ion-row>
</ion-col>
</ion-row>
</ion-col>

<ion-col *ngIf="!item2">
<ion-row>
<ion-col>(nothing)</ion-col>
</ion-row>
</ion-col>

<ion-col *ngIf="item2">
<ion-row>
<ion-col>
<ion-row class="name-row">
<ion-col class="icon">
<app-item-icon [item]="item2" size="small"></app-item-icon>
</ion-col>
<ion-col class="name">
{{ item2.name }}
<br />
Lv.{{ item2.levelRequirement }}
</ion-col>
</ion-row>
</ion-col>
</ion-row>

<ion-row
*ngFor="let stat of commonStats"
class="stat-row"
[ngClass]="getStatClassBetweenItems(stat, item2, item1)"
>
<ion-col>
<ion-row>
<ion-col class="stat">
{{ stat }}
</ion-col>

<ion-col class="value">
{{ item2.stats[stat] > 0 ? '+' : '' }}
{{ item2.stats[stat] || 0 | number }}
</ion-col>
</ion-row>
</ion-col>
</ion-row>
</ion-col>
</ion-row>
</ion-card-content>
</ion-card>
</ion-content>
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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<string>();
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 '';
}
}
10 changes: 6 additions & 4 deletions client/src/app/pages/inventory/inventory.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
<app-header-bar></app-header-bar>
</ion-header>

<ion-grid *ngIf="{ player: player$ | async } as data">
<ion-grid
*ngIf="{ player: player$ | async, equipped: equipped$ | async } as data"
>
<ion-row>
<ion-col>
<ion-card>
Expand Down Expand Up @@ -116,15 +118,15 @@
<ion-item
class="cursor-pointer"
*ngIf="basicEquipTypes.includes(row.type) && canEquipItem(data.player, row) && canEquipArmor(data.player, row)"
(click)="equipArmor(row); popover.dismiss()"
(click)="equipArmor(row, getEquippedItem(row.type, $any(data.equipped))); popover.dismiss()"
>
Equip Armor
</ion-item>

<ion-item
class="cursor-pointer"
*ngIf="weaponEquipTypes.includes(row.type) && canEquipItem(data.player, row) && canEquipWeapon(data.player, row)"
(click)="equipWeapon(row); popover.dismiss()"
(click)="equipWeapon(row, getEquippedItem('weapon', $any(data.equipped))); popover.dismiss()"
>
Equip Weapon
</ion-item>
Expand All @@ -135,7 +137,7 @@
<ion-item
class="cursor-pointer"
*ngFor="let slot of [1, 2, 3]"
(click)="equipAccessory(row, slot); popover.dismiss()"
(click)="equipAccessory(row, slot, getEquippedItem('accessory' + slot, $any(data.equipped))); popover.dismiss()"
>
Equip Accessory (Slot {{ slot }})
</ion-item>
Expand Down
88 changes: 67 additions & 21 deletions client/src/app/pages/inventory/inventory.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -25,6 +28,9 @@ import { Observable } from 'dexie';
})
export class InventoryPage implements OnInit {
@Select(PlayerStore.player) player$!: Observable<IPlayer>;
@Select(InventoryStore.equipped) equipped$!: Observable<
Record<ItemSlot, IEquipment>
>;

public readonly basicEquipTypes = [
'body',
Expand Down Expand Up @@ -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,
) {}
Expand Down Expand Up @@ -140,9 +147,21 @@ export class InventoryPage implements OnInit {
);
}

// job check, job check, job check, level check
getEquippedItem(
slot: ItemSlot | string,
equipment?: Record<ItemSlot, IEquipment>,
): 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) {
Expand All @@ -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();
});
});
}
}
2 changes: 2 additions & 0 deletions client/src/app/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -23,6 +24,7 @@ const components = [
CardOnlineUsersComponent,
HeroComponent,
ChooseAvatarModalComponent,
CompareItemsModalComponent,
HeaderBarComponent,
AvatarComponent,
ItemIconComponent,
Expand Down

0 comments on commit 4d0e234

Please sign in to comment.