Commit 7c742594 authored by Chunchi Che's avatar Chunchi Che

add historyStore

parent 7cd2a667
Pipeline #28938 passed with stages
in 19 minutes and 2 seconds
...@@ -52,7 +52,7 @@ export enum Region { ...@@ -52,7 +52,7 @@ export enum Region {
} }
export function fetchStrings(region: Region, id: string | number): string { export function fetchStrings(region: Region, id: string | number): string {
return localStorage.getItem(`${region}_${id}`) ?? ""; return localStorage.getItem(`${region}_${id}`) ?? "?";
} }
export function getStrings(description: number): string { export function getStrings(description: number): string {
......
...@@ -2,6 +2,7 @@ import { WebSocketStream } from "@/infra"; ...@@ -2,6 +2,7 @@ import { WebSocketStream } from "@/infra";
import { import {
cardStore, cardStore,
chatStore, chatStore,
historyStore,
matStore, matStore,
placeStore, placeStore,
roomStore, roomStore,
...@@ -22,6 +23,7 @@ export function initUIContainer(conn: WebSocketStream) { ...@@ -22,6 +23,7 @@ export function initUIContainer(conn: WebSocketStream) {
roomStore, roomStore,
chatStore, chatStore,
sideStore, sideStore,
historyStore,
}); });
const container = new Container(context, conn); const container = new Container(context, conn);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import { import {
CardStore, CardStore,
ChatStore, ChatStore,
HistoryStore,
MatStore, MatStore,
PlaceStore, PlaceStore,
RoomStore, RoomStore,
...@@ -16,6 +17,7 @@ interface ContextInitInfo { ...@@ -16,6 +17,7 @@ interface ContextInitInfo {
roomStore?: RoomStore; roomStore?: RoomStore;
chatStore?: ChatStore; chatStore?: ChatStore;
sideStore?: SideStore; sideStore?: SideStore;
historyStore?: HistoryStore;
} }
export class Context { export class Context {
...@@ -25,17 +27,26 @@ export class Context { ...@@ -25,17 +27,26 @@ export class Context {
public roomStore: RoomStore; public roomStore: RoomStore;
public chatStore: ChatStore; public chatStore: ChatStore;
public sideStore: SideStore; public sideStore: SideStore;
public historyStore: HistoryStore;
constructor(); constructor();
constructor(initInfo: ContextInitInfo); constructor(initInfo: ContextInitInfo);
constructor(initInfo?: ContextInitInfo) { constructor(initInfo?: ContextInitInfo) {
const { matStore, cardStore, placeStore, roomStore, chatStore, sideStore } = const {
initInfo ?? {}; matStore,
cardStore,
placeStore,
roomStore,
chatStore,
sideStore,
historyStore,
} = initInfo ?? {};
this.matStore = matStore ?? new MatStore(); this.matStore = matStore ?? new MatStore();
this.cardStore = cardStore ?? new CardStore(); this.cardStore = cardStore ?? new CardStore();
this.placeStore = placeStore ?? new PlaceStore(); this.placeStore = placeStore ?? new PlaceStore();
this.roomStore = roomStore ?? new RoomStore(); this.roomStore = roomStore ?? new RoomStore();
this.chatStore = chatStore ?? new ChatStore(); this.chatStore = chatStore ?? new ChatStore();
this.sideStore = sideStore ?? new SideStore(); this.sideStore = sideStore ?? new SideStore();
this.historyStore = historyStore ?? new HistoryStore();
} }
} }
...@@ -15,6 +15,8 @@ export default ( ...@@ -15,6 +15,8 @@ export default (
if (target) { if (target) {
console.info(`${target.meta.text.name} become target`); console.info(`${target.meta.text.name} become target`);
target.targeted = true; target.targeted = true;
context.historyStore.putTargeted(context, target.code, location);
} else { } else {
console.warn(`<BecomeTarget>target from ${location} is null`); console.warn(`<BecomeTarget>target from ${location} is null`);
} }
......
...@@ -44,6 +44,8 @@ export default async ( ...@@ -44,6 +44,8 @@ export default async (
target.meta = meta; target.meta = meta;
} }
context.historyStore.putEffect(context, meta.id, location);
// 发动效果动画 // 发动效果动画
await callCardFocus(target.uuid); await callCardFocus(target.uuid);
console.color("blue")(`${target.meta.text.name} chaining`); console.color("blue")(`${target.meta.text.name} chaining`);
......
...@@ -63,6 +63,8 @@ export default async ( ...@@ -63,6 +63,8 @@ export default async (
target.meta = { id: 0, data: {}, text: {} }; target.meta = { id: 0, data: {}, text: {} };
} }
} }
context.historyStore.putConfirmed(context, meta.id, target.location);
} else { } else {
console.warn(`card of ${card} is null`); console.warn(`card of ${card} is null`);
} }
......
...@@ -8,9 +8,17 @@ export default ( ...@@ -8,9 +8,17 @@ export default (
flipSummoning: ygopro.StocGameMessage.MsgFlipSummoning, flipSummoning: ygopro.StocGameMessage.MsgFlipSummoning,
) => { ) => {
// playEffect(AudioActionType.SOUND_FILP); // playEffect(AudioActionType.SOUND_FILP);
const context = container.context;
fetchEsHintMeta({ fetchEsHintMeta({
context: container.context, context: context,
originMsg: "「[?]」反转召唤宣言时", originMsg: "「[?]」反转召唤宣言时",
cardID: flipSummoning.code, cardID: flipSummoning.code,
}); });
context.historyStore.putFlipSummon(
context,
flipSummoning.code,
flipSummoning.location,
);
}; };
...@@ -175,6 +175,9 @@ export default async (container: Container, move: MsgMove) => { ...@@ -175,6 +175,9 @@ export default async (container: Container, move: MsgMove) => {
target.targeted = false; target.targeted = false;
} }
if (to.zone !== MZONE)
context.historyStore.putMove(context, code, from, to.zone);
// 维护完了之后,开始播放音效和动画 // 维护完了之后,开始播放音效和动画
if (to.zone === REMOVED) { if (to.zone === REMOVED) {
......
...@@ -13,9 +13,17 @@ export default ( ...@@ -13,9 +13,17 @@ export default (
// } else { // } else {
// playEffect(AudioActionType.SOUND_SPECIAL_SUMMON); // playEffect(AudioActionType.SOUND_SPECIAL_SUMMON);
// } // }
const context = container.context;
fetchEsHintMeta({ fetchEsHintMeta({
context: container.context, context: context,
originMsg: "「[?]」特殊召唤宣言时", originMsg: "「[?]」特殊召唤宣言时",
cardID: spSummoning.code, cardID: spSummoning.code,
}); });
context.historyStore.putSpSummon(
context,
spSummoning.code,
spSummoning.location,
);
}; };
...@@ -11,9 +11,13 @@ export default ( ...@@ -11,9 +11,13 @@ export default (
* 因此这里先注释掉,等解决掉上述问题后再加上召唤的音效。 * 因此这里先注释掉,等解决掉上述问题后再加上召唤的音效。
* */ * */
// playEffect(AudioActionType.SOUND_SUMMON); // playEffect(AudioActionType.SOUND_SUMMON);
const context = container.context;
fetchEsHintMeta({ fetchEsHintMeta({
context: container.context, context: context,
originMsg: "「[?]」通常召唤宣言时", originMsg: "「[?]」通常召唤宣言时",
cardID: summoning.code, cardID: summoning.code,
}); });
context.historyStore.putSummon(context, summoning.code, summoning.location);
}; };
import { proxy } from "valtio";
import { fetchCard, ygopro } from "@/api";
import { Context } from "@/container";
import { NeosStore } from "./shared";
export enum HistoryOp {
MOVE = 1,
EFFECT = 2,
TARGETED = 3,
CONFIRMED = 4,
ATTACK = 5, // TODO
SUMMON = 6,
SP_SUMMON = 7,
FLIP_SUMMON = 8,
}
export interface History {
card?: string;
opponent: boolean;
currentLocation?: ygopro.CardLocation;
operation: HistoryOp;
target?: ygopro.CardZone;
}
export class HistoryStore implements NeosStore {
historys: History[] = [];
putMove(
context: Context,
card: number,
from: ygopro.CardLocation,
to: ygopro.CardZone,
) {
// TODO: Refinement
this.historys.push({
card: fetchCard(card).text.name,
opponent: !context.matStore.isMe(from.controller),
currentLocation: from,
operation: HistoryOp.MOVE,
target: to,
});
}
putEffect(context: Context, card: number, location: ygopro.CardLocation) {
this.historys.push({
card: fetchCard(card).text.name,
opponent: !context.matStore.isMe(location.controller),
currentLocation: location,
operation: HistoryOp.EFFECT,
});
}
putTargeted(context: Context, card: number, location: ygopro.CardLocation) {
this.historys.push({
card: fetchCard(card).text.name,
opponent: !context.matStore.isMe(location.controller),
currentLocation: location,
operation: HistoryOp.TARGETED,
});
}
putConfirmed(context: Context, card: number, location: ygopro.CardLocation) {
this.historys.push({
card: fetchCard(card).text.name,
opponent: !context.matStore.isMe(location.controller),
currentLocation: location,
operation: HistoryOp.CONFIRMED,
});
}
putSummon(context: Context, card: number, location: ygopro.CardLocation) {
this.historys.push({
card: fetchCard(card).text.name,
opponent: !context.matStore.isMe(location.controller),
operation: HistoryOp.SUMMON,
});
}
putSpSummon(context: Context, card: number, location: ygopro.CardLocation) {
this.historys.push({
card: fetchCard(card).text.name,
opponent: !context.matStore.isMe(location.controller),
operation: HistoryOp.SP_SUMMON,
});
}
putFlipSummon(context: Context, card: number, location: ygopro.CardLocation) {
this.historys.push({
card: fetchCard(card).text.name,
opponent: !context.matStore.isMe(location.controller),
operation: HistoryOp.FLIP_SUMMON,
});
}
reset(): void {
this.historys = [];
}
}
export const historyStore = proxy(new HistoryStore());
...@@ -2,6 +2,7 @@ export * from "./accountStore"; ...@@ -2,6 +2,7 @@ export * from "./accountStore";
export * from "./cardStore"; export * from "./cardStore";
export * from "./chatStore"; export * from "./chatStore";
export * from "./deckStore"; export * from "./deckStore";
export * from "./historyStore";
export * from "./initStore"; export * from "./initStore";
export * from "./matStore"; export * from "./matStore";
export * from "./placeStore"; export * from "./placeStore";
...@@ -17,6 +18,7 @@ import { accountStore } from "./accountStore"; ...@@ -17,6 +18,7 @@ import { accountStore } from "./accountStore";
import { cardStore } from "./cardStore"; import { cardStore } from "./cardStore";
import { chatStore } from "./chatStore"; import { chatStore } from "./chatStore";
import { deckStore } from "./deckStore"; import { deckStore } from "./deckStore";
import { historyStore } from "./historyStore";
import { initStore } from "./initStore"; import { initStore } from "./initStore";
import { matStore } from "./matStore"; import { matStore } from "./matStore";
import { placeStore } from "./placeStore"; import { placeStore } from "./placeStore";
...@@ -47,6 +49,7 @@ export const resetUniverse = () => { ...@@ -47,6 +49,7 @@ export const resetUniverse = () => {
replayStore.reset(); replayStore.reset();
roomStore.reset(); roomStore.reset();
sideStore.reset(); sideStore.reset();
historyStore.reset();
}; };
// 重置决斗相关的`Store` // 重置决斗相关的`Store`
...@@ -54,4 +57,5 @@ export const resetDuel = () => { ...@@ -54,4 +57,5 @@ export const resetDuel = () => {
cardStore.reset(); cardStore.reset();
matStore.reset(); matStore.reset();
placeStore.reset(); placeStore.reset();
historyStore.reset();
}; };
...@@ -34,10 +34,24 @@ ...@@ -34,10 +34,24 @@
height: 100%; height: 100%;
.timeline { .timeline {
margin-top: 1rem;
p { p {
font-family: var(--theme-font); font-family: var(--theme-font);
font-size: 1rem; font-size: 1rem;
.card {
color: #48faf0;
}
.current-location {
color: #8484ff;
}
.op {
color: yellow;
font-size: 1.2rem;
}
.target {
color: #f16b3f;
}
} }
} }
} }
...@@ -3,6 +3,8 @@ import { Drawer, Timeline } from "antd"; ...@@ -3,6 +3,8 @@ import { Drawer, Timeline } from "antd";
import React from "react"; import React from "react";
import { proxy, useSnapshot } from "valtio"; import { proxy, useSnapshot } from "valtio";
import { fetchStrings, Region, ygopro } from "@/api";
import { History, HistoryOp, historyStore } from "@/stores";
import { ScrollableArea } from "@/ui/Shared"; import { ScrollableArea } from "@/ui/Shared";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
...@@ -15,6 +17,7 @@ const store = proxy(defaultStore); ...@@ -15,6 +17,7 @@ const store = proxy(defaultStore);
export const ActionHistory: React.FC = () => { export const ActionHistory: React.FC = () => {
const { isOpen } = useSnapshot(store); const { isOpen } = useSnapshot(store);
const { historys } = useSnapshot(historyStore);
return ( return (
<Drawer <Drawer
open={isOpen} open={isOpen}
...@@ -29,20 +32,64 @@ export const ActionHistory: React.FC = () => { ...@@ -29,20 +32,64 @@ export const ActionHistory: React.FC = () => {
<ScrollableArea className={styles.container} maxHeight="var(--height)"> <ScrollableArea className={styles.container} maxHeight="var(--height)">
<Timeline <Timeline
className={styles.timeline} className={styles.timeline}
items={[ items={historys.map((history) => ({
{ color: history.opponent ? "red" : "blue",
color: "red", children: <HistoryItem {...(history as History)} />,
children: <p>我方发动灰流丽的效果</p>, }))}
},
{
color: "blue",
children: <p>对方发动墓穴的指名者</p>,
},
]}
/> />
</ScrollableArea> </ScrollableArea>
</Drawer> </Drawer>
); );
}; };
const HistoryItem: React.FC<History> = ({
card,
currentLocation,
operation,
target,
}) => (
<p>
<span className={styles.card}>{card ?? "未知卡片"}</span>
{currentLocation && (
<span className={styles["current-location"]}>{` [${zone2Text(
currentLocation.zone,
)}]`}</span>
)}
<span>{" "}</span>
<span className={styles.op}>{Op2Text(operation)}</span>
{target && (
<>
<span>{" "}</span>
<span className={styles.target}>{`[${zone2Text(target)}]`}</span>
</>
)}
</p>
);
function zone2Text(zone: ygopro.CardZone): string {
return fetchStrings(Region.System, zone + 1000);
}
// TODO: I18N
function Op2Text(op: HistoryOp): string {
switch (op) {
case HistoryOp.MOVE:
return "移动";
case HistoryOp.EFFECT:
return fetchStrings(Region.System, 1150);
case HistoryOp.TARGETED:
return "被取对象";
case HistoryOp.CONFIRMED:
return "展示";
case HistoryOp.ATTACK:
return fetchStrings(Region.System, 1157);
case HistoryOp.SUMMON:
return fetchStrings(Region.System, 1151);
case HistoryOp.SP_SUMMON:
return fetchStrings(Region.System, 1152);
case HistoryOp.FLIP_SUMMON:
return fetchStrings(Region.System, 1154);
}
}
export const displayActionHistory = () => (store.isOpen = true); export const displayActionHistory = () => (store.isOpen = true);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment