Commit e597a650 authored by timel's avatar timel

refactor: register and call

parent a8c0b184
...@@ -12,10 +12,13 @@ export enum Task { ...@@ -12,10 +12,13 @@ export enum Task {
const getEnd = (task: Task) => `${task}-end`; const getEnd = (task: Task) => `${task}-end`;
/** 在组件之中注册方法 */ /** 在组件之中注册方法 */
const register = (task: Task, fn: (...args: any[]) => Promise<any>) => { const register = <T extends unknown[]>(
task: Task,
fn: (...args: T) => Promise<void>
) => {
eventEmitter.on( eventEmitter.on(
task, task,
async ({ taskId, args }: { taskId: string; args: any[] }) => { async ({ taskId, args }: { taskId: string; args: T }) => {
await fn(...args); await fn(...args);
eventEmitter.emit(getEnd(task), taskId); eventEmitter.emit(getEnd(task), taskId);
} }
......
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { eventbus, sleep, Task } from "@/infra"; import { sleep } from "@/infra";
import { cardStore, fetchEsHintMeta } from "@/stores"; import { cardStore, fetchEsHintMeta } from "@/stores";
import { callCardAttack } from "@/ui/Duel/PlayMat/Card";
export default async (attack: ygopro.StocGameMessage.MsgAttack) => { export default async (attack: ygopro.StocGameMessage.MsgAttack) => {
fetchEsHintMeta({ fetchEsHintMeta({
...@@ -16,14 +17,14 @@ export default async (attack: ygopro.StocGameMessage.MsgAttack) => { ...@@ -16,14 +17,14 @@ export default async (attack: ygopro.StocGameMessage.MsgAttack) => {
if (attacker) { if (attacker) {
if (attack.direct_attack) { if (attack.direct_attack) {
await eventbus.call(Task.Attack, attacker.uuid, true); await callCardAttack(attacker.uuid, {
directAttack: true,
});
} else { } else {
await eventbus.call( await callCardAttack(attacker.uuid, {
Task.Attack, directAttack: false,
attacker.uuid, target: attack.target_location,
false, });
attack.target_location
);
} }
} else { } else {
console.warn(`<Attack>attacker from ${attack.attacker_location} is null`); console.warn(`<Attack>attacker from ${attack.attacker_location} is null`);
......
import { fetchCard, ygopro } from "@/api"; import { fetchCard, ygopro } from "@/api";
import { eventbus, Task } from "@/infra";
import { cardStore, fetchEsHintMeta } from "@/stores"; import { cardStore, fetchEsHintMeta } from "@/stores";
import { callCardMove } from "@/ui/Duel/PlayMat/Card";
export default async (draw: ygopro.StocGameMessage.MsgDraw) => { export default async (draw: ygopro.StocGameMessage.MsgDraw) => {
fetchEsHintMeta({ originMsg: "玩家抽卡时" }); fetchEsHintMeta({ originMsg: "玩家抽卡时" });
...@@ -27,6 +27,6 @@ export default async (draw: ygopro.StocGameMessage.MsgDraw) => { ...@@ -27,6 +27,6 @@ export default async (draw: ygopro.StocGameMessage.MsgDraw) => {
await Promise.all( await Promise.all(
cardStore cardStore
.at(ygopro.CardZone.HAND, draw.player) .at(ygopro.CardZone.HAND, draw.player)
.map((card) => eventbus.call(Task.Move, card.uuid)) .map((card) => callCardMove(card.uuid))
); );
}; };
import { fetchCard, ygopro } from "@/api"; import { fetchCard, ygopro } from "@/api";
import { eventbus, Task } from "@/infra";
import { cardStore, CardType } from "@/stores"; import { cardStore, CardType } from "@/stores";
import { REASON_MATERIAL, TYPE_TOKEN } from "../../common"; import { REASON_MATERIAL, TYPE_TOKEN } from "../../common";
import { callCardMove } from "@/ui/Duel/PlayMat/Card";
type MsgMove = ygopro.StocGameMessage.MsgMove; type MsgMove = ygopro.StocGameMessage.MsgMove;
const { HAND, GRAVE, REMOVED, DECK, EXTRA, MZONE, TZONE } = ygopro.CardZone; const { HAND, GRAVE, REMOVED, DECK, EXTRA, MZONE, TZONE } = ygopro.CardZone;
...@@ -114,7 +114,7 @@ export default async (move: MsgMove) => { ...@@ -114,7 +114,7 @@ export default async (move: MsgMove) => {
overlayMaterial.location.zone = to.zone; overlayMaterial.location.zone = to.zone;
overlayMaterial.location.sequence = to.sequence; overlayMaterial.location.sequence = to.sequence;
await eventbus.call(Task.Move, overlayMaterial.uuid); await callCardMove(overlayMaterial.uuid);
} else { } else {
console.warn( console.warn(
`<Move>overlayMaterial from zone=${location.zone}, controller=${location.controller}, sequence=${location.sequence}, overlay_sequence=${location.overlay_sequence} is null` `<Move>overlayMaterial from zone=${location.zone}, controller=${location.controller}, sequence=${location.sequence}, overlay_sequence=${location.overlay_sequence} is null`
...@@ -157,13 +157,13 @@ export default async (move: MsgMove) => { ...@@ -157,13 +157,13 @@ export default async (move: MsgMove) => {
target.location = to; target.location = to;
// 维护完了之后,开始动画 // 维护完了之后,开始动画
const p = eventbus.call(Task.Move, target.uuid, from.zone); const p = callCardMove(target.uuid, { fromZone: from.zone });
// 如果from或者to是手卡,那么需要刷新除了这张卡之外,这个玩家的所有手卡 // 如果from或者to是手卡,那么需要刷新除了这张卡之外,这个玩家的所有手卡
if ([from.zone, to.zone].includes(HAND)) { if ([from.zone, to.zone].includes(HAND)) {
const pHands = cardStore const pHands = cardStore
.at(HAND, target.location.controller) .at(HAND, target.location.controller)
.filter((c) => c.uuid !== target.uuid) .filter((c) => c.uuid !== target.uuid)
.map(async (c) => await eventbus.call(Task.Move, c.uuid)); .map(async (c) => await callCardMove(c.uuid));
await Promise.all([p, ...pHands]); await Promise.all([p, ...pHands]);
} else { } else {
await p; await p;
...@@ -181,7 +181,7 @@ export default async (move: MsgMove) => { ...@@ -181,7 +181,7 @@ export default async (move: MsgMove) => {
overlay.location.sequence = to.sequence; overlay.location.sequence = to.sequence;
overlay.location.position = to.position; overlay.location.position = to.position;
await eventbus.call(Task.Move, overlay.uuid); await callCardMove(overlay.uuid);
} }
} }
}; };
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import MsgPosChange = ygopro.StocGameMessage.MsgPosChange; import MsgPosChange = ygopro.StocGameMessage.MsgPosChange;
import { eventbus, Task } from "@/infra";
import { cardStore, fetchEsHintMeta } from "@/stores"; import { cardStore, fetchEsHintMeta } from "@/stores";
import { callCardMove } from "@/ui/Duel/PlayMat/Card";
export default async (posChange: MsgPosChange) => { export default async (posChange: MsgPosChange) => {
const { location, controller, sequence } = posChange.card_info; const { location, controller, sequence } = posChange.card_info;
...@@ -10,7 +12,7 @@ export default async (posChange: MsgPosChange) => { ...@@ -10,7 +12,7 @@ export default async (posChange: MsgPosChange) => {
target.location.position = posChange.cur_position; target.location.position = posChange.cur_position;
// TODO: 暂时用`Move`动画,后续可以单独实现一个改变表示形式的动画 // TODO: 暂时用`Move`动画,后续可以单独实现一个改变表示形式的动画
await eventbus.call(Task.Move, target.uuid); await callCardMove(target.uuid);
} else { } else {
console.warn(`<PosChange>target from ${posChange.card_info} is null`); console.warn(`<PosChange>target from ${posChange.card_info} is null`);
} }
......
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { eventbus, Task } from "@/infra";
import { cardStore } from "@/stores"; import { cardStore } from "@/stores";
import { callCardMove } from "@/ui/Duel/PlayMat/Card";
type MsgShuffleHandExtra = ygopro.StocGameMessage.MsgShuffleHandExtra; type MsgShuffleHandExtra = ygopro.StocGameMessage.MsgShuffleHandExtra;
...@@ -23,7 +23,7 @@ export default async (shuffleHandExtra: MsgShuffleHandExtra) => { ...@@ -23,7 +23,7 @@ export default async (shuffleHandExtra: MsgShuffleHandExtra) => {
hash.set(card.code, sequences); hash.set(card.code, sequences);
// 触发动画 // 触发动画
await eventbus.call(Task.Move, card.uuid); await callCardMove(card.uuid);
} else { } else {
console.warn( console.warn(
`<ShuffleHandExtra>sequence poped is none, controller=${controller}, code=${card.code}, sequence=${sequence}` `<ShuffleHandExtra>sequence poped is none, controller=${controller}, code=${card.code}, sequence=${sequence}`
......
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { eventbus, Task } from "@/infra";
import { cardStore } from "@/stores"; import { cardStore } from "@/stores";
import { callCardMove } from "@/ui/Duel/PlayMat/Card";
import MsgShuffleSetCard = ygopro.StocGameMessage.MsgShuffleSetCard; import MsgShuffleSetCard = ygopro.StocGameMessage.MsgShuffleSetCard;
// 后端传过来的`from_locations`的列表是切洗前场上卡的location,它们在列表里面按照切洗后的顺序排列 // 后端传过来的`from_locations`的列表是切洗前场上卡的location,它们在列表里面按照切洗后的顺序排列
...@@ -42,7 +42,7 @@ export default async (shuffleSetCard: MsgShuffleSetCard) => { ...@@ -42,7 +42,7 @@ export default async (shuffleSetCard: MsgShuffleSetCard) => {
// 更新sequence // 更新sequence
overlay.location.sequence = overlay_location.sequence; overlay.location.sequence = overlay_location.sequence;
// 渲染动画 // 渲染动画
await eventbus.call(Task.Move, overlay.uuid); await callCardMove(overlay.uuid);
// 这里其实有个疑惑,如果超量素材也跟着洗切的话,洗切的意义好像就没有了,感觉算是个k社没想好的设计? // 这里其实有个疑惑,如果超量素材也跟着洗切的话,洗切的意义好像就没有了,感觉算是个k社没想好的设计?
} }
} }
......
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { eventbus, Task } from "@/infra"; import { eventbus, Task } from "@/infra";
import { cardStore } from "@/stores"; import { cardStore } from "@/stores";
import { callCardMove } from "@/ui/Duel/PlayMat/Card";
import MsgSwapGraveDeck = ygopro.StocGameMessage.MsgSwapGraveDeck; import MsgSwapGraveDeck = ygopro.StocGameMessage.MsgSwapGraveDeck;
const { DECK, GRAVE } = ygopro.CardZone; const { DECK, GRAVE } = ygopro.CardZone;
...@@ -12,11 +13,11 @@ export default async (swapGraveDeck: MsgSwapGraveDeck) => { ...@@ -12,11 +13,11 @@ export default async (swapGraveDeck: MsgSwapGraveDeck) => {
for (const card of deck) { for (const card of deck) {
card.location.zone = GRAVE; card.location.zone = GRAVE;
await eventbus.call(Task.Move, card.uuid); await callCardMove(card.uuid);
} }
for (const card of grave) { for (const card of grave) {
card.location.zone = DECK; card.location.zone = DECK;
await eventbus.call(Task.Move, card.uuid); await callCardMove(card.uuid);
} }
}; };
import { fetchCard, ygopro } from "@/api"; import { fetchCard, ygopro } from "@/api";
import MsgUpdateData = ygopro.StocGameMessage.MsgUpdateData; import { callCardMove } from "@/ui/Duel/PlayMat/Card";
import { eventbus, Task } from "@/infra"; import { eventbus, Task } from "@/infra";
import { cardStore } from "@/stores"; import { cardStore } from "@/stores";
import MsgUpdateData = ygopro.StocGameMessage.MsgUpdateData;
export default async (updateData: MsgUpdateData) => { export default async (updateData: MsgUpdateData) => {
const { player: controller, zone, actions } = updateData; const { player: controller, zone, actions } = updateData;
if (controller !== undefined && zone !== undefined && actions !== undefined) { if (controller !== undefined && zone !== undefined && actions !== undefined) {
...@@ -28,7 +28,7 @@ export default async (updateData: MsgUpdateData) => { ...@@ -28,7 +28,7 @@ export default async (updateData: MsgUpdateData) => {
// Currently only update position // Currently only update position
target.location.position = action.location.position; target.location.position = action.location.position;
// animation // animation
await eventbus.call(Task.Move, target.uuid); await callCardMove(target.uuid);
} }
} }
if (action?.type_ >= 0) { if (action?.type_ >= 0) {
......
...@@ -27,11 +27,9 @@ import { interactTypeToString } from "../../utils"; ...@@ -27,11 +27,9 @@ import { interactTypeToString } from "../../utils";
import { import {
attack, attack,
focus, focus,
moveToDeck, move,
moveToGround, type MoveOptions,
moveToHand, type AttackOptions,
moveToOutside,
moveToToken,
} from "./springs"; } from "./springs";
import type { SpringApiProps } from "./springs/types"; import type { SpringApiProps } from "./springs/types";
import { preloadCardImage } from "./springs/utils"; import { preloadCardImage } from "./springs/utils";
...@@ -62,32 +60,9 @@ export const Card: React.FC<{ idx: number }> = React.memo(({ idx }) => { ...@@ -62,32 +60,9 @@ export const Card: React.FC<{ idx: number }> = React.memo(({ idx }) => {
} satisfies SpringApiProps) } satisfies SpringApiProps)
); );
const move = async (toZone: ygopro.CardZone, fromZone?: ygopro.CardZone) => {
switch (toZone) {
case MZONE:
case SZONE:
await moveToGround({ card, api, fromZone });
break;
case HAND:
await moveToHand({ card, api, fromZone });
break;
case DECK:
case EXTRA:
await moveToDeck({ card, api, fromZone });
break;
case GRAVE:
case REMOVED:
await moveToOutside({ card, api, fromZone });
break;
case TZONE:
await moveToToken({ card, api, fromZone });
break;
}
};
// 每张卡都需要移动到初始位置 // 每张卡都需要移动到初始位置
useEffect(() => { useEffect(() => {
move(card.location.zone); addToAnimation(() => move({ card, api }));
}, []); }, []);
const [glowing, setGrowing] = useState(false); const [glowing, setGrowing] = useState(false);
...@@ -102,44 +77,32 @@ export const Card: React.FC<{ idx: number }> = React.memo(({ idx }) => { ...@@ -102,44 +77,32 @@ export const Card: React.FC<{ idx: number }> = React.memo(({ idx }) => {
animationQueue.current = animationQueue.current.then(p).then(rs); animationQueue.current = animationQueue.current.then(p).then(rs);
}); });
useEffect(() => { const register = <T extends any[]>(
eventbus.register( task: Task,
Task.Move, fn: (...args: T) => Promise<unknown>
async (uuid: string, fromZone?: ygopro.CardZone) => { ) => {
eventbus.register(task, async (uuid, ...rest: T) => {
if (uuid === card.uuid) { if (uuid === card.uuid) {
await addToAnimation(async () => { await fn(...rest);
await preloadCardImage(card.code);
await move(card.location.zone, fromZone);
});
} }
} });
); };
eventbus.register(Task.Focus, async (uuid: string) => { useEffect(() => {
if (uuid === card.uuid) { register(Task.Move, async (options?: MoveOptions) => {
await addToAnimation(async () => { await addToAnimation(() => move({ card, api, options }));
});
register(Task.Focus, async () => {
await preloadCardImage(card.code); await preloadCardImage(card.code);
setClassFocus(true); setClassFocus(true);
setTimeout(() => setClassFocus(false), 1000); setTimeout(() => setClassFocus(false), 1000);
await focus({ card, api }); await focus({ card, api });
}); });
}
});
eventbus.register( register(Task.Attack, async (options: AttackOptions) => {
Task.Attack, await addToAnimation(() => attack({ card, api, options }));
async ( });
uuid: string,
directAttack: boolean,
target?: ygopro.CardLocation
) => {
if (uuid === card.uuid) {
await addToAnimation(() =>
attack({ card, api, target, directAttack })
);
}
}
);
}, []); }, []);
// <<< 动画 <<< // <<< 动画 <<<
...@@ -382,3 +345,13 @@ const handleEffectActivation = ( ...@@ -382,3 +345,13 @@ const handleEffectActivation = (
}; };
// <<< 下拉菜单 <<< // <<< 下拉菜单 <<<
const call =
<Options,>(task: Task) =>
async (uuid: string, options?: Options extends {} ? Options : never) => {
eventbus.call(task, uuid, options);
};
export const callCardMove = call<MoveOptions>(Task.Move);
export const callCardFocus = call(Task.Focus);
export const callCardAttack = call<AttackOptions>(Task.Attack);
...@@ -5,34 +5,29 @@ import { ygopro } from "@/api"; ...@@ -5,34 +5,29 @@ import { ygopro } from "@/api";
import { CardType, isMe } from "@/stores"; import { CardType, isMe } from "@/stores";
import { matConfig } from "@/ui/Shared"; import { matConfig } from "@/ui/Shared";
import type { SpringApi } from "./types"; import type { SpringApi, AttackFunc } from "./types";
import { asyncStart } from "./utils"; import { asyncStart } from "./utils";
const { BLOCK_WIDTH, BLOCK_HEIGHT_M, BLOCK_HEIGHT_S, COL_GAP, ROW_GAP } = const { BLOCK_WIDTH, BLOCK_HEIGHT_M, BLOCK_HEIGHT_S, COL_GAP, ROW_GAP } =
matConfig; matConfig;
export const attack = async (props: { export const attack: AttackFunc = async (props) => {
card: CardType; const { card, api, options } = props;
api: SpringApi;
directAttack: boolean;
target?: ygopro.CardLocation;
}) => {
const { card, api, directAttack, target } = props;
const current = api.current[0].get(); const current = api.current[0].get();
let x = current.x; let x = current.x;
let y = current.y; let y = current.y;
let rz = current.rz; let rz = current.rz;
if (directAttack) { if (options?.directAttack) {
// 直接攻击 // 直接攻击
y = BLOCK_HEIGHT_M + BLOCK_HEIGHT_S; y = BLOCK_HEIGHT_M + BLOCK_HEIGHT_S;
if (isMe(card.location.controller)) { if (isMe(card.location.controller)) {
y = -y; y = -y;
} }
} else if (target) { } else if (options?.target) {
// 攻击`target` // 攻击`target`
const { controller, sequence } = target; const { controller, sequence } = options.target;
if (sequence > 4) { if (sequence > 4) {
// 额外怪兽区 // 额外怪兽区
x = (sequence > 5 ? 1 : -1) * (BLOCK_WIDTH + COL_GAP); x = (sequence > 5 ? 1 : -1) * (BLOCK_WIDTH + COL_GAP);
......
export * from "./attack"; export * from "./attack";
export * from "./focus"; export * from "./focus";
export * from "./moveToDeck"; export * from "./move";
export * from "./moveToGround";
export * from "./moveToHand";
export * from "./moveToOutside";
export * from "./moveToToken";
export * from "./utils"; export * from "./utils";
export * from "./types";
import { ygopro } from "@/api";
import type { MoveFunc } from "./types";
import { moveToGround } from "./moveToGround";
import { moveToHand } from "./moveToHand";
import { moveToDeck } from "./moveToDeck";
import { moveToOutside } from "./moveToOutside";
import { moveToToken } from "./moveToToken";
const { HAND, GRAVE, REMOVED, DECK, EXTRA, MZONE, SZONE, TZONE } =
ygopro.CardZone;
export const move: MoveFunc = async (props) => {
const { card } = props;
switch (card.location.zone) {
case MZONE:
case SZONE:
await moveToGround(props);
break;
case HAND:
await moveToHand(props);
break;
case DECK:
case EXTRA:
await moveToDeck(props);
break;
case GRAVE:
case REMOVED:
await moveToOutside(props);
break;
case TZONE:
await moveToToken(props);
break;
}
};
...@@ -2,7 +2,8 @@ import { ygopro } from "@/api"; ...@@ -2,7 +2,8 @@ import { ygopro } from "@/api";
import { isMe } from "@/stores"; import { isMe } from "@/stores";
import { matConfig } from "@/ui/Shared"; import { matConfig } from "@/ui/Shared";
import { asyncStart, type MoveFunc } from "./utils"; import { asyncStart } from "./utils";
import type { MoveFunc } from "./types";
const { const {
BLOCK_WIDTH, BLOCK_WIDTH,
......
...@@ -4,7 +4,8 @@ import { ygopro } from "@/api"; ...@@ -4,7 +4,8 @@ import { ygopro } from "@/api";
import { isMe } from "@/stores"; import { isMe } from "@/stores";
import { matConfig } from "@/ui/Shared"; import { matConfig } from "@/ui/Shared";
import { asyncStart, type MoveFunc } from "./utils"; import { asyncStart } from "./utils";
import type { MoveFunc } from "./types";
const { const {
BLOCK_WIDTH, BLOCK_WIDTH,
...@@ -20,7 +21,7 @@ const { ...@@ -20,7 +21,7 @@ const {
const { MZONE, SZONE, TZONE } = ygopro.CardZone; const { MZONE, SZONE, TZONE } = ygopro.CardZone;
export const moveToGround: MoveFunc = async (props) => { export const moveToGround: MoveFunc = async (props) => {
const { card, api, fromZone } = props; const { card, api, options } = props;
const { location } = card; const { location } = card;
...@@ -87,7 +88,8 @@ export const moveToGround: MoveFunc = async (props) => { ...@@ -87,7 +88,8 @@ export const moveToGround: MoveFunc = async (props) => {
: 0; : 0;
// 动画 // 动画
if (fromZone === TZONE) { const isToken = options?.fromZone === TZONE;
if (isToken) {
// 如果是Token,直接先移动到那个位置,然后再放大 // 如果是Token,直接先移动到那个位置,然后再放大
api.set({ api.set({
x, x,
...@@ -115,10 +117,12 @@ export const moveToGround: MoveFunc = async (props) => { ...@@ -115,10 +117,12 @@ export const moveToGround: MoveFunc = async (props) => {
await asyncStart(api)({ await asyncStart(api)({
height, height,
z: 0, z: 0,
subZ: isToken ? 100 : 0,
zIndex: is_overlay ? 1 : 3, zIndex: is_overlay ? 1 : 3,
config: { config: {
easing: easings.easeInQuad, easing: easings.easeInQuad,
clamp: true, clamp: true,
}, },
}); });
if (isToken) api.set({ subZ: 0 });
}; };
...@@ -2,7 +2,8 @@ import { ygopro } from "@/api"; ...@@ -2,7 +2,8 @@ import { ygopro } from "@/api";
import { cardStore, isMe } from "@/stores"; import { cardStore, isMe } from "@/stores";
import { matConfig } from "@/ui/Shared"; import { matConfig } from "@/ui/Shared";
import { asyncStart, type MoveFunc } from "./utils"; import { asyncStart } from "./utils";
import type { MoveFunc } from "./types";
const { const {
BLOCK_HEIGHT_M, BLOCK_HEIGHT_M,
......
...@@ -2,7 +2,8 @@ import { ygopro } from "@/api"; ...@@ -2,7 +2,8 @@ import { ygopro } from "@/api";
import { isMe } from "@/stores"; import { isMe } from "@/stores";
import { matConfig } from "@/ui/Shared"; import { matConfig } from "@/ui/Shared";
import { asyncStart, type MoveFunc } from "./utils"; import { asyncStart } from "./utils";
import type { MoveFunc } from "./types";
const { const {
BLOCK_WIDTH, BLOCK_WIDTH,
......
import { asyncStart, type MoveFunc } from "./utils"; import { asyncStart } from "./utils";
import type { MoveFunc } from "./types";
export const moveToToken: MoveFunc = async (props) => { export const moveToToken: MoveFunc = async (props) => {
const { api } = props; const { api } = props;
......
import { type SpringRef } from "@react-spring/web"; import type { ygopro } from "@/api";
import type { CardType } from "@/stores";
import type { SpringRef } from "@react-spring/web";
export interface SpringApiProps { export interface SpringApiProps {
x: number; x: number;
...@@ -20,3 +22,19 @@ export interface SpringApiProps { ...@@ -20,3 +22,19 @@ export interface SpringApiProps {
} }
export type SpringApi = SpringRef<SpringApiProps>; export type SpringApi = SpringRef<SpringApiProps>;
type OptionsToFunc<Options> = (props: {
card: CardType;
api: SpringApi;
options?: Options;
}) => Promise<void>;
export type MoveOptions = { fromZone?: ygopro.CardZone };
export type MoveFunc = OptionsToFunc<MoveOptions>;
export type AttackOptions =
| {
directAttack: true;
}
| { directAttack: false; target: ygopro.CardLocation };
export type AttackFunc = OptionsToFunc<AttackOptions>;
import { type SpringConfig, type SpringRef } from "@react-spring/web"; import { type SpringConfig, type SpringRef } from "@react-spring/web";
import type { ygopro } from "@/api";
import { type CardType } from "@/stores";
import { getCardImgUrl } from "@/ui/Shared"; import { getCardImgUrl } from "@/ui/Shared";
import type { SpringApi } from "./types";
export const asyncStart = <T extends {}>(api: SpringRef<T>) => { export const asyncStart = <T extends {}>(api: SpringRef<T>) => {
return (p: Partial<T> & { config?: SpringConfig }) => return (p: Partial<T> & { config?: SpringConfig }) =>
new Promise((resolve) => { new Promise((resolve) => {
...@@ -16,12 +12,6 @@ export const asyncStart = <T extends {}>(api: SpringRef<T>) => { ...@@ -16,12 +12,6 @@ export const asyncStart = <T extends {}>(api: SpringRef<T>) => {
}); });
}; };
export type MoveFunc = (props: {
card: CardType;
api: SpringApi;
fromZone?: ygopro.CardZone;
}) => Promise<void>;
// >>> preload image >>> // >>> preload image >>>
const preloadImageSet = new Set<string>(); const preloadImageSet = new Set<string>();
export const preloadImage = (src: string) => export const preloadImage = (src: string) =>
......
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