Commit b5e2cf80 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/ui/rock_paper_scissors' into 'main'

Feat/ui/rock paper scissors

See merge request mycard/Neos!238
parents 8988e67a c5475a23
Pipeline #22497 passed with stages
in 13 minutes and 55 seconds
...@@ -66,3 +66,4 @@ export const MSG_TOSS_COIN = 130; ...@@ -66,3 +66,4 @@ export const MSG_TOSS_COIN = 130;
export const MSG_TOSS_DICE = 131; export const MSG_TOSS_DICE = 131;
export const MSG_SHUFFLE_SET_CARD = 36; export const MSG_SHUFFLE_SET_CARD = 36;
export const MSG_FIELD_DISABLED = 56; export const MSG_FIELD_DISABLED = 56;
export const MSG_HAND_RES = 133;
...@@ -15,6 +15,7 @@ import MsgAttack from "./attack"; ...@@ -15,6 +15,7 @@ import MsgAttack from "./attack";
import MsgDamage from "./damage"; import MsgDamage from "./damage";
import MsgDrawAdapter from "./draw"; import MsgDrawAdapter from "./draw";
import MsgFieldDisabledAdapter from "./fieldDisabled"; import MsgFieldDisabledAdapter from "./fieldDisabled";
import MsgHandResultAdapter from "./handResult";
import MsgHintAdapter from "./hint"; import MsgHintAdapter from "./hint";
import MsgNewPhaseAdapter from "./newPhase"; import MsgNewPhaseAdapter from "./newPhase";
import MsgNewTurnAdapter from "./newTurn"; import MsgNewTurnAdapter from "./newTurn";
...@@ -250,6 +251,11 @@ export default class GameMsgAdapter implements StocAdapter { ...@@ -250,6 +251,11 @@ export default class GameMsgAdapter implements StocAdapter {
break; break;
} }
case GAME_MSG.MSG_HAND_RES: {
gameMsg.hand_res = MsgHandResultAdapter(gameData);
break;
}
default: { default: {
gameMsg.unimplemented = new ygopro.StocGameMessage.MsgUnimplemented({ gameMsg.unimplemented = new ygopro.StocGameMessage.MsgUnimplemented({
command: func, command: func,
......
...@@ -330,7 +330,7 @@ async function _handleGameMsg(pb: ygopro.YgoStocMsg) { ...@@ -330,7 +330,7 @@ async function _handleGameMsg(pb: ygopro.YgoStocMsg) {
break; break;
} }
case "rock_paper_scissors": { case "rock_paper_scissors": {
onMsgRockPaperScissors(msg.rock_paper_scissors); await onMsgRockPaperScissors(msg.rock_paper_scissors);
break; break;
} }
......
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { matStore } from "@/stores";
import MsgHandResult = ygopro.StocGameMessage.MsgHandResult; import MsgHandResult = ygopro.StocGameMessage.MsgHandResult;
export default (res: MsgHandResult) => { export default (res: MsgHandResult) => {
console.log(res); const { result1, result2 } = res;
// TODO
matStore.handResults.set(0, result1);
matStore.handResults.set(1, result2);
}; };
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { displayOptionModal } from "@/ui/Duel/Message";
export default (mora: ygopro.StocGameMessage.MsgRockPaperScissors) => { export default async (mora: ygopro.StocGameMessage.MsgRockPaperScissors) => {
console.log(mora); const _player = mora.player;
// TODO
// TODO: I18n
await displayOptionModal("请选择猜拳", [
{ msg: "剪刀", response: 1 },
{ msg: "石头", response: 2 },
{ msg: "", response: 3 },
]);
}; };
import { fetchCard, getCardStr, ygopro } from "@/api"; import { fetchCard, fetchStrings, getCardStr, ygopro } from "@/api";
import MsgSelectOption = ygopro.StocGameMessage.MsgSelectOption; import MsgSelectOption = ygopro.StocGameMessage.MsgSelectOption;
import { displayOptionModal } from "@/ui/Duel/Message"; import { displayOptionModal } from "@/ui/Duel/Message";
export default async (selectOption: MsgSelectOption) => { export default async (selectOption: MsgSelectOption) => {
const options = selectOption.options; const options = selectOption.options;
await displayOptionModal( await displayOptionModal(
fetchStrings("!system", 556),
await Promise.all( await Promise.all(
options.map(async ({ code, response }) => { options.map(async ({ code, response }) => {
const meta = await fetchCard(code >> 4); const meta = await fetchCard(code >> 4);
......
...@@ -81,6 +81,14 @@ export const matStore: MatState = proxy<MatState>({ ...@@ -81,6 +81,14 @@ export const matStore: MatState = proxy<MatState>({
enableEp: false, // 允许回合结束 enableEp: false, // 允许回合结束
}, },
unimplemented: 0, unimplemented: 0,
handResults: {
me: 0,
op: 0,
of: (controller: number) => matStore.handResults[getWhom(controller)],
set(controller, result) {
matStore.handResults[getWhom(controller)] = result;
},
},
// methods // methods
isMe, isMe,
}); });
......
...@@ -37,6 +37,10 @@ export interface MatState { ...@@ -37,6 +37,10 @@ export interface MatState {
tossResult?: string; // 骰子/硬币结果 tossResult?: string; // 骰子/硬币结果
handResults: BothSide<HandResult> & {
set: (controller: number, result: HandResult) => void;
}; // 猜拳结果
/** 根据自己的先后手判断是否是自己 */ /** 根据自己的先后手判断是否是自己 */
isMe: (player: number) => boolean; isMe: (player: number) => boolean;
} }
...@@ -94,4 +98,11 @@ export interface PhaseState { ...@@ -94,4 +98,11 @@ export interface PhaseState {
enableM2: boolean; // 允许进入M2阶段 enableM2: boolean; // 允许进入M2阶段
enableEp: boolean; // 允许回合结束 enableEp: boolean; // 允许回合结束
} }
export enum HandResult {
UNKNOWN = 0,
SCISSOR = 1,
ROCK = 2,
PAPER = 3,
}
// <<< play mat state <<< // <<< play mat state <<<
...@@ -7,7 +7,7 @@ import { useSnapshot } from "valtio"; ...@@ -7,7 +7,7 @@ import { useSnapshot } from "valtio";
import { fetchStrings } from "@/api"; import { fetchStrings } from "@/api";
import { Phase2StringCodeMap } from "@/common"; import { Phase2StringCodeMap } from "@/common";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { matStore } from "@/stores"; import { HandResult, matStore } from "@/stores";
const style = { const style = {
borderStyle: "groove", borderStyle: "groove",
...@@ -22,9 +22,8 @@ export const HintNotification = () => { ...@@ -22,9 +22,8 @@ export const HintNotification = () => {
const snap = useSnapshot(matStore); const snap = useSnapshot(matStore);
const hintState = snap.hint; const hintState = snap.hint;
const toss = snap.tossResult; const toss = snap.tossResult;
const handResults = snap.handResults;
const currentPhase = snap.phase.currentPhase; const currentPhase = snap.phase.currentPhase;
// const waiting = snap.waiting;
const result = snap.result; const result = snap.result;
const [notify, notifyContextHolder] = notification.useNotification({ const [notify, notifyContextHolder] = notification.useNotification({
...@@ -54,6 +53,21 @@ export const HintNotification = () => { ...@@ -54,6 +53,21 @@ export const HintNotification = () => {
} }
}, [toss]); }, [toss]);
// TODO: I18n
useEffect(() => {
const meHand = handResults.me;
const opHand = handResults.op;
if (meHand !== HandResult.UNKNOWN && opHand !== HandResult.UNKNOWN) {
notify.open({
message: `{我方出示${getHandResultText(
meHand
)},对方出示${getHandResultText(opHand)}}`,
placement: "topLeft",
style: style,
});
}
}, [handResults]);
useEffect(() => { useEffect(() => {
if (currentPhase) { if (currentPhase) {
const message = fetchStrings( const message = fetchStrings(
...@@ -117,3 +131,17 @@ export const showWaiting = (open: boolean) => { ...@@ -117,3 +131,17 @@ export const showWaiting = (open: boolean) => {
} }
} }
}; };
// TODO: I18n
function getHandResultText(res: HandResult): string {
switch (res) {
case HandResult.UNKNOWN:
return "[?]";
case HandResult.ROCK:
return "拳头";
case HandResult.PAPER:
return "";
case HandResult.SCISSOR:
return "剪刀";
}
}
...@@ -5,6 +5,7 @@ import { proxy, useSnapshot } from "valtio"; ...@@ -5,6 +5,7 @@ import { proxy, useSnapshot } from "valtio";
import { import {
type CardMeta, type CardMeta,
fetchStrings,
getCardStr, getCardStr,
sendSelectIdleCmdResponse, sendSelectIdleCmdResponse,
sendSelectOptionResponse, sendSelectOptionResponse,
...@@ -15,6 +16,7 @@ import { NeosModal } from "./NeosModal"; ...@@ -15,6 +16,7 @@ import { NeosModal } from "./NeosModal";
type Options = { msg: string; response: number }[]; type Options = { msg: string; response: number }[];
const defaultStore = { const defaultStore = {
title: "",
isOpen: false, isOpen: false,
options: [] satisfies Options as Options, options: [] satisfies Options as Options,
}; };
...@@ -23,7 +25,7 @@ const store = proxy(defaultStore); ...@@ -23,7 +25,7 @@ const store = proxy(defaultStore);
export const OptionModal = () => { export const OptionModal = () => {
const snap = useSnapshot(store); const snap = useSnapshot(store);
const { isOpen, options } = snap; const { title, isOpen, options } = snap;
const [selected, setSelected] = useState<number | undefined>(undefined); const [selected, setSelected] = useState<number | undefined>(undefined);
...@@ -36,7 +38,7 @@ export const OptionModal = () => { ...@@ -36,7 +38,7 @@ export const OptionModal = () => {
return ( return (
<NeosModal <NeosModal
title="请选择需要发动的效果" title={title}
open={isOpen} open={isOpen}
footer={ footer={
<Button disabled={selected === undefined} onClick={onClick}> <Button disabled={selected === undefined} onClick={onClick}>
...@@ -54,9 +56,10 @@ export const OptionModal = () => { ...@@ -54,9 +56,10 @@ export const OptionModal = () => {
}; };
let rs: (v?: any) => void = () => {}; let rs: (v?: any) => void = () => {};
export const displayOptionModal = async (options: Options) => { export const displayOptionModal = async (title: string, options: Options) => {
store.isOpen = true; store.title = title;
store.options = options; store.options = options;
store.isOpen = true;
await new Promise((resolve) => (rs = resolve)); await new Promise((resolve) => (rs = resolve));
store.isOpen = false; store.isOpen = false;
}; };
...@@ -87,6 +90,6 @@ export const handleEffectActivation = async ( ...@@ -87,6 +90,6 @@ export const handleEffectActivation = async (
response: effect.response, response: effect.response,
}; };
}); });
await displayOptionModal(options); // 主动发动效果,所以不需要await,但是以后可能要留心 await displayOptionModal(fetchStrings("!system", 556), options); // 主动发动效果,所以不需要await,但是以后可能要留心
} }
}; };
...@@ -6,7 +6,12 @@ import classnames from "classnames"; ...@@ -6,7 +6,12 @@ import classnames from "classnames";
import React, { type CSSProperties, useEffect, useState } from "react"; import React, { type CSSProperties, useEffect, useState } from "react";
import { proxy, useSnapshot } from "valtio"; import { proxy, useSnapshot } from "valtio";
import { getCardStr, sendSelectIdleCmdResponse, ygopro } from "@/api"; import {
fetchStrings,
getCardStr,
sendSelectIdleCmdResponse,
ygopro,
} from "@/api";
import { eventbus, Task } from "@/infra"; import { eventbus, Task } from "@/infra";
import { cardStore, CardType, Interactivity, InteractType } from "@/stores"; import { cardStore, CardType, Interactivity, InteractType } from "@/stores";
import { showCardModal as displayCardModal } from "@/ui/Duel/Message/CardModal"; import { showCardModal as displayCardModal } from "@/ui/Duel/Message/CardModal";
...@@ -250,7 +255,7 @@ const handleEffectActivation = ( ...@@ -250,7 +255,7 @@ const handleEffectActivation = (
response: effect.response, response: effect.response,
}; };
}); });
displayOptionModal(options); // 主动发动效果,所以不需要await,但是以后可能要留心 displayOptionModal(fetchStrings("!system", 556), options); // 主动发动效果,所以不需要await,但是以后可能要留心
} }
}; };
......
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