Commit cdd8ab84 authored by timel's avatar timel

feat: card list modal

parent 6ed4caf8
...@@ -47,16 +47,14 @@ export default async (move: MsgMove) => { ...@@ -47,16 +47,14 @@ export default async (move: MsgMove) => {
} }
} }
// log出来看看,后期删掉即可 // log出来看看
await (async () => { console.color("green")(
console.color("green")( `${meta.text.name} ${ygopro.CardZone[from.zone]}:${from.sequence}${
`${meta.text.name} ${ygopro.CardZone[from.zone]}:${from.sequence}:${ from.is_overlay ? ":" + from.overlay_sequence : ""
from.is_overlay ? from.overlay_sequence : "" }${ygopro.CardZone[to.zone]}:${to.sequence}${
}${ygopro.CardZone[to.zone]}:${to.sequence}:${ to.is_overlay ? ":" + to.overlay_sequence : ""
to.is_overlay ? to.overlay_sequence : "" }`
}` );
);
})();
let target: CardType; let target: CardType;
......
...@@ -35,9 +35,9 @@ const helper = async ( ...@@ -35,9 +35,9 @@ const helper = async (
const effectDesc = effectDescCode const effectDesc = effectDescCode
? getCardStr(meta, effectDescCode & 0xf) ? getCardStr(meta, effectDescCode & 0xf)
: undefined; : undefined;
const newOption = { const newOption: Option = {
meta, meta,
location: location.toObject(), location,
level1, level1,
level2, level2,
effectDesc, effectDesc,
......
...@@ -50,8 +50,8 @@ class CardStore { ...@@ -50,8 +50,8 @@ class CardStore {
card.location.zone === zone && card.location.zone === zone &&
card.location.controller === controller && card.location.controller === controller &&
card.location.sequence === sequence && card.location.sequence === sequence &&
card.location.is_overlay == true && card.location.is_overlay === true &&
card.location.overlay_sequence == overlay_sequence card.location.overlay_sequence === overlay_sequence
) )
.at(0); .at(0);
} else { } else {
...@@ -61,7 +61,7 @@ class CardStore { ...@@ -61,7 +61,7 @@ class CardStore {
card.location.zone === zone && card.location.zone === zone &&
card.location.controller === controller && card.location.controller === controller &&
card.location.sequence === sequence && card.location.sequence === sequence &&
card.location.is_overlay == false card.location.is_overlay === false
) )
.at(0); .at(0);
} }
...@@ -70,7 +70,7 @@ class CardStore { ...@@ -70,7 +70,7 @@ class CardStore {
(card) => (card) =>
card.location.zone === zone && card.location.zone === zone &&
card.location.controller === controller && card.location.controller === controller &&
card.location.is_overlay == false card.location.is_overlay === false
); );
} }
} }
...@@ -85,9 +85,9 @@ class CardStore { ...@@ -85,9 +85,9 @@ class CardStore {
): CardType[] { ): CardType[] {
return this.inner.filter( return this.inner.filter(
(card) => (card) =>
card.location.zone == zone && card.location.zone === zone &&
card.location.controller == controller && card.location.controller === controller &&
card.location.sequence == sequence && card.location.sequence === sequence &&
card.location.is_overlay card.location.is_overlay
); );
} }
......
import { Drawer, List } from "antd"; import { Drawer, Space } from "antd";
import React from "react"; import React from "react";
import { useSnapshot } from "valtio"; import { proxy, useSnapshot } from "valtio";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { messageStore } from "@/stores"; import { CardType, messageStore, cardStore } from "@/stores";
import { EffectButton } from "./EffectButton";
import { showCardModal } from "./CardModal"; import { showCardModal } from "./CardModal";
import { ygopro } from "@/api";
import { YgoCard } from "@/ui/Shared";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
...@@ -15,50 +15,69 @@ const CARD_WIDTH = 100; ...@@ -15,50 +15,69 @@ const CARD_WIDTH = 100;
const { cardListModal } = messageStore; const { cardListModal } = messageStore;
// TODO: 显示的位置还需要细细斟酌
const defaultStore = {
zone: ygopro.CardZone.HAND,
controller: 0,
monster: {} as CardType,
isOpen: false,
isZone: true,
};
const store = proxy(defaultStore);
export const CardListModal = () => { export const CardListModal = () => {
const snap = useSnapshot(cardListModal); const { zone, monster, isOpen, isZone, controller } = useSnapshot(store);
const isOpen = snap.isOpen; let cardList: CardType[] = [];
const list = snap.list as typeof cardListModal.list;
if (isZone) {
cardList = cardStore.at(zone, controller);
console.log({ cardList });
} else {
// 看超量素材
cardList = cardStore.findOverlay(
monster.location.zone,
monster.location.controller,
monster.location.sequence
);
}
const handleOkOrCancel = () => { const handleOkOrCancel = () => {
cardListModal.isOpen = false; store.isOpen = false;
}; };
return ( return (
<Drawer open={isOpen} onClose={handleOkOrCancel}> <Drawer
<List open={isOpen}
itemLayout="horizontal" onClose={handleOkOrCancel}
dataSource={list} headerStyle={{ display: "none" }}
renderItem={(item) => ( width={CARD_WIDTH + 66}
<List.Item style={{ maxHeight: "100%" }}
actions={[ >
<EffectButton <Space direction="vertical">
effectInteractivies={item.interactivies} {cardList.map((card) => (
meta={item.meta} <YgoCard
/>, code={card.code}
]} key={card.uuid}
extra={ width={CARD_WIDTH}
<img onClick={() => showCardModal(card)}
alt={item.meta?.text.name} />
src={ ))}
item.meta?.id </Space>
? `${NeosConfig.cardImgUrl}/${item.meta.id}.jpg`
: `${NeosConfig.assetsPath}/card_back.jpg`
}
style={{ width: CARD_WIDTH }}
/>
}
onClick={() => {
showCardModal(item);
}}
>
<List.Item.Meta
title={item.meta?.text.name}
description={item.meta?.text.desc}
/>
</List.Item>
)}
></List>
</Drawer> </Drawer>
); );
}; };
export const displayCardListModal = ({
isZone,
monster,
zone,
controller,
}: Partial<Omit<typeof defaultStore, "isOpen">>) => {
store.isOpen = true;
isZone && (store.isZone = isZone);
monster && (store.monster = monster);
zone && (store.zone = zone);
controller && (store.controller = controller);
};
...@@ -14,7 +14,6 @@ import { ...@@ -14,7 +14,6 @@ import {
Race2StringCodeMap, Race2StringCodeMap,
Type2StringCodeMap, Type2StringCodeMap,
} from "../../../../common"; } from "../../../../common";
import { EffectButton } from "../EffectButton";
import { Drawer, Space, Tag, Divider, Timeline, Typography } from "antd"; import { Drawer, Space, Tag, Divider, Timeline, Typography } from "antd";
import { LeftOutlined } from "@ant-design/icons"; import { LeftOutlined } from "@ant-design/icons";
...@@ -61,13 +60,6 @@ export const CardModal = () => { ...@@ -61,13 +60,6 @@ export const CardModal = () => {
const atk = meta?.data.atk; const atk = meta?.data.atk;
const def = meta?.data.def; const def = meta?.data.def;
const nonEffectInteractivies = snap.interactivies.filter(
(item) => item.desc != "发动效果"
);
const effectInteractivies = snap.interactivies.filter(
(item) => item.desc == "发动效果"
);
return ( return (
// TODO: 宽度要好好设置 根据屏幕宽度 // TODO: 宽度要好好设置 根据屏幕宽度
<Drawer <Drawer
......
import "@/styles/card-modal.scss";
import React from "react";
import { CardMeta, getCardStr, sendSelectIdleCmdResponse } from "@/api";
import { cardStore, messageStore } from "@/stores";
const { cardModal } = messageStore;
export const EffectButton = (props: {
meta?: CardMeta;
effectInteractivies: {
desc: string;
response: number;
effectCode?: number;
}[];
}) => (
<>
{props.effectInteractivies.length > 0 ? (
props.effectInteractivies.length == 1 ? (
// 如果只有一个效果,点击直接触发
<button
className="card-modal-btn"
onClick={() => {
sendSelectIdleCmdResponse(props.effectInteractivies[0].response);
cardModal.isOpen = false;
// 清空互动性
for (const card of cardStore.inner) {
card.idleInteractivities = [];
}
}}
>
{props.effectInteractivies[0].desc}
</button>
) : (
// 如果有多个效果,点击后进入`OptionModal`选择
<button
className="card-modal-btn"
onClick={() => {
for (const effect of props.effectInteractivies) {
const effectMsg =
props.meta && effect.effectCode
? getCardStr(props.meta, effect.effectCode & 0xf) ?? "[:?]"
: "[:?]";
messageStore.optionModal.options.push({
msg: effectMsg,
response: effect.response,
});
}
cardModal.isOpen = false;
// 清空互动性
for (const card of cardStore.inner) {
card.idleInteractivities = [];
}
messageStore.optionModal.isOpen = true;
}}
>
发动效果
</button>
)
) : (
<></>
)}
</>
);
...@@ -3,7 +3,13 @@ import { Button } from "antd"; ...@@ -3,7 +3,13 @@ import { Button } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { useSnapshot, proxy } from "valtio"; import { useSnapshot, proxy } from "valtio";
import { sendSelectOptionResponse } from "@/api"; import {
type CardMeta,
sendSelectOptionResponse,
ygopro,
sendSelectIdleCmdResponse,
getCardStr,
} from "@/api";
import { NeosModal } from "./NeosModal"; import { NeosModal } from "./NeosModal";
type Options = { msg: string; response: number }[]; type Options = { msg: string; response: number }[];
...@@ -54,3 +60,33 @@ export const displayOptionModal = async (options: Options) => { ...@@ -54,3 +60,33 @@ export const displayOptionModal = async (options: Options) => {
await new Promise((resolve) => (rs = resolve)); await new Promise((resolve) => (rs = resolve));
store.isOpen = false; store.isOpen = false;
}; };
export const handleEffectActivation = async (
meta: CardMeta,
effectInteractivies: {
desc: string;
response: number;
effectCode: number | undefined;
}[]
) => {
if (!effectInteractivies.length) {
return;
}
if (effectInteractivies.length === 1) {
// 如果只有一个效果,点击直接触发
sendSelectIdleCmdResponse(effectInteractivies[0].response);
} else {
// optionsModal
const options = effectInteractivies.map((effect) => {
const effectMsg =
meta && effect.effectCode
? getCardStr(meta, effect.effectCode & 0xf) ?? "[:?]"
: "[:?]";
return {
msg: effectMsg,
response: effect.response,
};
});
await displayOptionModal(options); // 主动发动效果,所以不需要await,但是以后可能要留心
}
};
...@@ -31,7 +31,7 @@ import { ...@@ -31,7 +31,7 @@ import {
UpOutlined, UpOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { fetchStrings, sendSelectIdleCmdResponse, type CardMeta } from "@/api"; import { fetchStrings, sendSelectIdleCmdResponse, type CardMeta } from "@/api";
import { displayOptionModal } from "../../Message"; import { displayCardListModal, displayOptionModal } from "../../Message";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
const { HAND, GRAVE, REMOVED, DECK, EXTRA, MZONE, SZONE, TZONE } = const { HAND, GRAVE, REMOVED, DECK, EXTRA, MZONE, SZONE, TZONE } =
...@@ -233,6 +233,7 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => { ...@@ -233,6 +233,7 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => {
overlayClassName="card-dropdown" overlayClassName="card-dropdown"
arrow arrow
trigger={["click"]} trigger={["click"]}
// TODO: 没有交互效果、或者不能点击的卡,不应该显示下拉菜单
> >
<div className={classnames("card-img-wrap", { focus: classFocus })}> <div className={classnames("card-img-wrap", { focus: classFocus })}>
<YgoCard <YgoCard
...@@ -273,20 +274,10 @@ const onCardClick = (card: CardType) => { ...@@ -273,20 +274,10 @@ const onCardClick = (card: CardType) => {
}; };
const onFieldClick = (card: CardType) => { const onFieldClick = (card: CardType) => {
const displayStates = cardStore.at(
card.location.zone,
card.location.controller
);
messageStore.cardListModal.list = displayStates.map((item) => ({
meta: {
id: item.code,
text: item.meta.text,
data: item.meta.data,
},
interactivies: item.idleInteractivities.map((interactivy) => ({
desc: interactTypeToString(interactivy.interactType),
response: interactivy.response,
})),
}));
messageStore.cardListModal.isOpen = true; messageStore.cardListModal.isOpen = true;
displayCardListModal({
isZone: true,
zone: card.location.zone,
controller: card.location.controller,
});
}; };
...@@ -17,7 +17,6 @@ export const Mat: FC = () => { ...@@ -17,7 +17,6 @@ export const Mat: FC = () => {
id="mat" id="mat"
style={{ style={{
width: "100%", width: "100%",
...toCssProperties(matConfig),
}} }}
> >
<Plane> <Plane>
......
...@@ -5,13 +5,17 @@ export type CSSConfig = Record<string, { value: number; unit: UNIT }>; ...@@ -5,13 +5,17 @@ export type CSSConfig = Record<string, { value: number; unit: UNIT }>;
/** 转为CSS变量: BOARD_ROTATE_Z -> --board-rotate-z */ /** 转为CSS变量: BOARD_ROTATE_Z -> --board-rotate-z */
export const toCssProperties = (config: CSSConfig) => export const toCssProperties = (config: CSSConfig) =>
Object.entries(config) Object.entries(config)
.map(([k, v]) => ({ .map(
[`--${k ([k, v]) =>
.split("_") [
.map((s) => s.toLowerCase()) `--${k
.join("-")}`]: `${v.value}${v.unit}`, .split("_")
})) .map((s) => s.toLowerCase())
.reduce((acc, cur) => ({ ...acc, ...cur }), {}); .join("-")}`,
`${v.value}${v.unit}`,
] as [string, string]
)
.reduce((acc, cur) => [...acc, cur], [] as [string, string][]);
enum UNIT { enum UNIT {
PX = "px", PX = "px",
...@@ -81,3 +85,7 @@ export const matConfig = { ...@@ -81,3 +85,7 @@ export const matConfig = {
unit: UNIT.PX, unit: UNIT.PX,
}, },
}; };
toCssProperties(matConfig).forEach(([k, v]) => {
document.body.style.setProperty(k, v);
});
.skeleton-cover { .skeleton-cover {
background-color: gray; background-color: gray;
} }
.ygo-card {
aspect-ratio: var(--card-ratio);
}
...@@ -11,34 +11,38 @@ interface Props { ...@@ -11,34 +11,38 @@ interface Props {
code?: number; code?: number;
style?: CSSProperties; style?: CSSProperties;
width?: number; width?: number;
onClick?: () => void;
} }
export const YgoCard: FC<Props> = (props) => { export const YgoCard: FC<Props> = (props) => {
const { const {
className, className,
code: cardCode = 0, code = 0,
isBack = false, isBack = false,
width = 80, width = 80,
style, style,
onClick = () => {},
} = props; } = props;
return useMemo( return useMemo(
() => ( () => (
<> <>
{cardCode === 0 && !isBack ? ( {code === 0 && !isBack ? (
<div <div
className={classNames("ygo-card", "skeleton-cover")} className={classNames("ygo-card", "skeleton-cover", className)}
style={{ width, ...style }} style={{ width, ...style }}
onClick={onClick}
/> />
) : ( ) : (
<img <img
className={classNames("ygo-card", className)} className={classNames("ygo-card", className)}
src={getCardImgUrl(cardCode, isBack)} src={getCardImgUrl(code, isBack)}
style={{ width, ...style }} style={{ width, ...style }}
onClick={onClick}
/> />
)} )}
</> </>
), ),
[cardCode] [code]
); );
}; };
......
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