Commit 20c8ba1a authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/service/select_option' into 'main'

Feat/service/select option

See merge request mycard/Neos!69
parents 19af9718 0b32f9ac
neos-protobuf @ 707b028e
Subproject commit 836412c292c4351ea9b7d499b31472672157e0dd
Subproject commit 707b028ef6ecbe6de328f9e1114707553e0f3df2
This diff is collapsed.
......@@ -7,6 +7,7 @@ import adaptSelectCardResponse from "./selectCard";
import adaptSelectChainResponse from "./selectChain";
import adaptSelectEffectYnResponse from "./selectEffectYn";
import adaptSelectPositionResponse from "./selectPosition";
import adaptSelectOptionResponse from "./selectOption";
/*
* CTOS CTOS_RESPONSE
......@@ -52,6 +53,11 @@ export default class CtosResponsePacket extends YgoProPacket {
break;
}
case "select_option": {
extraData = adaptSelectOptionResponse(response.select_option);
break;
}
default: {
break;
}
......
import { ygopro } from "../../../idl/ocgcore";
import { BufferWriter } from "../../bufferIO";
export default (response: ygopro.CtosGameMsgResponse.SelectOptionResponse) => {
const array = new Uint8Array(4);
const writer = new BufferWriter(array, true);
writer.writeUint32(response.code);
return array;
};
......@@ -38,3 +38,4 @@ export const MSG_SELECT_CARD = 15;
export const MSG_SELECT_CHAIN = 16;
export const MSG_SELECT_EFFECTYN = 12;
export const MSG_SELECT_POSITION = 19;
export const MSG_SELECT_OPTION = 14;
......@@ -18,6 +18,7 @@ import MsgSelectCardAdapter from "./selectCard";
import MsgSelectChainAdapter from "./selectChain";
import MsgSelectEffectYnAdapter from "./selectEffectYn";
import MsgSelectPositionAdapter from "./selectPosition";
import MsgSelectOptionAdapter from "./selectOption";
/*
* STOC GameMsg
......@@ -103,6 +104,11 @@ export default class GameMsgAdapter implements StocAdapter {
break;
}
case GAME_MSG.MSG_SELECT_OPTION: {
gameMsg.select_option = MsgSelectOptionAdapter(gameData);
break;
}
default: {
console.log("Unhandled GameMessage function=", func);
......
import { ygopro } from "../../../idl/ocgcore";
import { BufferReader } from "../../bufferIO";
import MsgSelectOption = ygopro.StocGameMessage.MsgSelectOption;
/*
* Msg Select Option
*
* @param - see: https://code.mycard.moe/mycard/neos-protobuf/-/blob/main/idl/ocgcore.neos-protobuf
* @usage - 玩家选择选项
*
* */
export default (data: Uint8Array) => {
const reader = new BufferReader(data, true);
const player = reader.readUint8();
const count = reader.readUint8();
const msg = new MsgSelectOption({
player,
options: [],
});
for (let i = 0; i < count; i++) {
const option = new MsgSelectOption.Option({
code: reader.readUint32(),
response: i,
});
msg.options.push(option);
}
return msg;
};
......@@ -202,3 +202,16 @@ export function sendSelectPositionResponse(value: ygopro.CardPosition) {
socketMiddleWare({ cmd: socketCmd.SEND, payload });
}
export function sendSelectOptionResponse(value: number) {
const response = new ygopro.YgoCtosMsg({
ctos_response: new ygopro.CtosGameMsgResponse({
select_option: new ygopro.CtosGameMsgResponse.SelectOptionResponse({
code: value,
}),
}),
});
const payload = new GameMsgResponse(response).serialize();
socketMiddleWare({ cmd: socketCmd.SEND, payload });
}
......@@ -37,6 +37,9 @@ import {
setPositionModalIsOpenImpl,
setPositionModalPositionsImpl,
resetPositionModalImpl,
setOptionModalIsOpenImpl,
resetOptionModalImpl,
optionModalCase,
} from "./modalSlice";
import {
MonsterState,
......@@ -91,6 +94,7 @@ const initialState: DuelState = {
checkCardModal: { isOpen: false, cancelAble: false, tags: [] },
yesNoModal: { isOpen: false },
positionModal: { isOpen: false, positions: [] },
optionModal: { isOpen: false, options: [] },
},
};
......@@ -141,6 +145,8 @@ const duelSlice = createSlice({
setPositionModalIsOpen: setPositionModalIsOpenImpl,
setPositionModalPositions: setPositionModalPositionsImpl,
resetPositionModal: resetPositionModalImpl,
setOptionModalIsOpen: setOptionModalIsOpenImpl,
resetOptionModal: resetOptionModalImpl,
},
extraReducers(builder) {
handsCase(builder);
......@@ -150,6 +156,7 @@ const duelSlice = createSlice({
cemeteryCase(builder);
checkCardModalCase(builder);
YesNoModalCase(builder);
optionModalCase(builder);
},
});
......@@ -185,6 +192,8 @@ export const {
setPositionModalIsOpen,
setPositionModalPositions,
resetPositionModal,
setOptionModalIsOpen,
resetOptionModal,
} = duelSlice.actions;
export const selectDuelHsStart = (state: RootState) => {
return state.duel.meInitInfo != null;
......
......@@ -58,6 +58,11 @@ export interface ModalState {
isOpen: boolean;
positions: ygopro.CardPosition[];
};
// 选项选择弹窗
optionModal: {
isOpen: boolean;
options: { msg: string; response: number }[];
};
}
// 更新卡牌弹窗打开状态
......@@ -288,11 +293,43 @@ export const setPositionModalPositionsImpl: CaseReducer<
state.modalState.positionModal.positions = action.payload;
};
export const setOptionModalIsOpenImpl: CaseReducer<
DuelState,
PayloadAction<boolean>
> = (state, action) => {
state.modalState.optionModal.isOpen = action.payload;
};
export const resetOptionModalImpl: CaseReducer<DuelState> = (state) => {
state.modalState.optionModal.options = [];
};
export const resetPositionModalImpl: CaseReducer<DuelState> = (state) => {
state.modalState.positionModal.isOpen = false;
state.modalState.positionModal.positions = [];
};
// 增加选项
export const fetchOptionMeta = createAsyncThunk(
"duel/fetchOptionMeta",
async (param: { code: number; response: number }) => {
const meta = await fetchCard(param.code >> 4);
const msg = getCardStr(meta, param.code & 0xf) || "[?]";
const response = { msg, response: param.response };
return response;
}
);
export const optionModalCase = (
builder: ActionReducerMapBuilder<DuelState>
) => {
builder.addCase(fetchOptionMeta.fulfilled, (state, action) => {
state.modalState.optionModal.options.push(action.payload);
});
};
export const selectCardModalIsOpen = (state: RootState) =>
state.duel.modalState.cardModal.isOpen;
export const selectCardModalName = (state: RootState) =>
......@@ -331,3 +368,7 @@ export const selectPositionModalIsOpen = (state: RootState) =>
state.duel.modalState.positionModal.isOpen;
export const selectPositionModalPositions = (state: RootState) =>
state.duel.modalState.positionModal.positions;
export const selectOptionModalIsOpen = (state: RootState) =>
state.duel.modalState.optionModal.isOpen;
export const selectOptionModalOptions = (state: RootState) =>
state.duel.modalState.optionModal.options;
......@@ -12,6 +12,7 @@ import onMsgSelectCard from "./selectCard";
import onMsgSelectChain from "./selectChain";
import onMsgSelectEffectYn from "./selectEffectYn";
import onMsgSelectPosition from "./selectPosition";
import onMsgSelectOption from "./selectOption";
export default function handleGameMsg(pb: ygopro.YgoStocMsg) {
const dispatch = store.dispatch;
......@@ -90,6 +91,12 @@ export default function handleGameMsg(pb: ygopro.YgoStocMsg) {
break;
}
case "select_option": {
const selectOption = msg.select_option;
onMsgSelectOption(selectOption, dispatch);
break;
}
default: {
break;
}
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { setOptionModalIsOpen } from "../../reducers/duel/mod";
import { fetchOptionMeta } from "../../reducers/duel/modalSlice";
import { AppDispatch } from "../../store";
import MsgSelectOption = ygopro.StocGameMessage.MsgSelectOption;
export default (selectOption: MsgSelectOption, dispatch: AppDispatch) => {
const player = selectOption.player;
const options = selectOption.options;
for (let option of options) {
dispatch(fetchOptionMeta(option));
}
dispatch(setOptionModalIsOpen(true));
};
......@@ -16,6 +16,7 @@ import CardListModal from "./cardListModal";
import CheckCardModal from "./checkCardModal";
import YesNoModal from "./yesNoModal";
import PositionModal from "./positionModal";
import OptionModal from "./optionModal";
// Ref: https://github.com/brianzinn/react-babylonjs/issues/126
const NeosDuel = () => (
......@@ -46,6 +47,7 @@ const NeosDuel = () => (
<CheckCardModal />
<YesNoModal />
<PositionModal />
<OptionModal />
</>
);
......
import React, { useState } from "react";
import { useAppSelector } from "../../hook";
import { store } from "../../store";
import { Modal, Button } from "antd";
import { CheckCard } from "@ant-design/pro-components";
import {
selectOptionModalIsOpen,
selectOptionModalOptions,
} from "../../reducers/duel/modalSlice";
import { sendSelectOptionResponse } from "../../api/ocgcore/ocgHelper";
import {
resetOptionModal,
setOptionModalIsOpen,
} from "../../reducers/duel/mod";
const OptionModal = () => {
const dispatch = store.dispatch;
const isOpen = useAppSelector(selectOptionModalIsOpen);
const options = useAppSelector(selectOptionModalOptions);
const [selected, setSelected] = useState<number | undefined>(undefined);
return (
<Modal
title="请选择需要发动的效果"
open={isOpen}
closable={false}
footer={
<Button
disabled={selected === undefined}
onClick={() => {
if (selected !== undefined) {
sendSelectOptionResponse(selected);
dispatch(setOptionModalIsOpen(false));
dispatch(resetOptionModal());
}
}}
>
submit
</Button>
}
>
<CheckCard.Group
bordered
size="small"
onChange={(value) => {
// @ts-ignore
setSelected(value);
}}
>
{options.map((option, idx) => (
<CheckCard key={idx} title={option.msg} value={option.response} />
))}
</CheckCard.Group>
</Modal>
);
};
export default OptionModal;
......@@ -34,7 +34,7 @@ const PositionModal = () => {
if (selected !== undefined) {
sendSelectPositionResponse(selected);
dispatch(setPositionModalIsOpen(false));
dispatch(resetPositionModal);
dispatch(resetPositionModal());
}
}}
>
......
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