Commit 9750ad07 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/select_sum' into 'main'

Feat/select sum

See merge request !151
parents 5c851ecc a1f9891e
Pipeline #20893 passed with stages
in 16 minutes and 52 seconds
Subproject commit 4f6cdd7ccc3b11b39ff8aa649e423bcf401f7ad5
Subproject commit 3090fbcb9d0c51fa7aa20b3e313917d971cf15ca
This diff is collapsed.
......@@ -49,4 +49,16 @@ export class BufferReaderExt {
});
}
}
readCardShortLocation(): ygopro.CardLocation {
const controler = this.inner.readUint8();
const location = this.inner.readUint8();
const sequence = this.inner.readUint8();
return new ygopro.CardLocation({
controler,
location: numberToCardZone(location),
sequence,
});
}
}
......@@ -51,3 +51,4 @@ export const MSG_WIN = 5;
export const MSG_WAITING = 3;
export const MSG_UPDATE_DATA = 6;
export const MSG_RELOAD_FIELD = 162;
export const MSG_SELECT_SUM = 23;
......@@ -27,6 +27,7 @@ import MsgRecover from "./recover";
import MsgWin from "./win";
import MsgUpdateDataAdapter from "./updateData";
import MsgReloadFieldAdapter from "./reloadField";
import MsgSelectSum from "./selectSum";
import PENETRATE from "./penetrate";
/*
......@@ -160,6 +161,11 @@ export default class GameMsgAdapter implements StocAdapter {
break;
}
case GAME_MSG.MSG_SELECT_SUM: {
gameMsg.select_sum = MsgSelectSum(gameData);
break;
}
default: {
gameMsg.unimplemented = new ygopro.StocGameMessage.MsgUnimplemented({
command: func,
......
import { ygopro } from "../../../idl/ocgcore";
import { BufferReaderExt } from "../../bufferIO";
import MsgSelectSum = ygopro.StocGameMessage.MsgSelectSum;
/*
* Msg Select Sum
*
* @param -
*
* @usage -
* */
export default (data: Uint8Array) => {
const reader = new BufferReaderExt(data);
const overflow = reader.inner.readUint8();
const player = reader.inner.readUint8();
const level = reader.inner.readInt32();
const min = reader.inner.readUint8();
const max = reader.inner.readUint8();
const msg = new MsgSelectSum({
overflow,
player,
level_sum: level,
min,
max,
must_select_cards: [],
selectable_cards: [],
});
const mustCount = reader.inner.readUint8();
for (let i = 0; i < mustCount; i++) {
const code = reader.inner.readInt32();
const location = reader.readCardShortLocation();
const para = reader.inner.readInt32();
msg.must_select_cards.push(
new MsgSelectSum.Info({
code,
location,
level1: para & 0xffff,
level2: para >> 16,
response: i,
})
);
}
const selectAbleCount = reader.inner.readUint8();
for (let i = 0; i < selectAbleCount; i++) {
const code = reader.inner.readInt32();
const location = reader.readCardShortLocation();
const para = reader.inner.readInt32();
msg.selectable_cards.push(
new MsgSelectSum.Info({
code,
location,
level1: para & 0xffff,
level2: para >> 16,
response: i,
})
);
}
return msg;
};
......@@ -10,6 +10,7 @@ import MsgSelectCard = ygopro.StocGameMessage.MsgSelectCard;
* */
export default (data: Uint8Array) => {
// FIXME: handle it correctly
const reader = new BufferReaderExt(data);
const player = reader.inner.readUint8();
......
......@@ -53,6 +53,14 @@ import {
resetCheckCardModalV2Impl,
setCheckCardModalV2ResponseAbleImpl,
checkCardModalV2Case,
setCheckCardModalV3IsOpenImpl,
setCheckCardModalV3MinMaxImpl,
setCheckCardModalV3AllLevelImpl,
setCheckCardModalV3OverFlowImpl,
setCheckCardModalV3ResponseAbleImpl,
resetCheckCardModalV3Impl,
setCheckCardModalV3SelectedImpl,
checkCardModalV3Case,
} from "./modal/mod";
import {
MonsterState,
......@@ -168,6 +176,14 @@ const initialState: DuelState = {
selectableOptions: [],
selectedOptions: [],
},
checkCardModalV3: {
isOpen: false,
overflow: false,
allLevel: 0,
mustSelectList: [],
selectAbleList: [],
selectedList: [],
},
},
};
......@@ -254,6 +270,13 @@ const duelSlice = createSlice({
setCheckCardModalV2IsOpen: setCheckCardModalV2IsOpenImpl,
resetCheckCardModalV2: resetCheckCardModalV2Impl,
setCheckCardModalV2ResponseAble: setCheckCardModalV2ResponseAbleImpl,
setCheckCardModalV3IsOpen: setCheckCardModalV3IsOpenImpl,
setCheckCardModalV3MinMax: setCheckCardModalV3MinMaxImpl,
setCheckCardModalV3AllLevel: setCheckCardModalV3AllLevelImpl,
setCheckCardModalV3OverFlow: setCheckCardModalV3OverFlowImpl,
setCheckCardModalV3ResponseAble: setCheckCardModalV3ResponseAbleImpl,
resetCheckCardModalV3: resetCheckCardModalV3Impl,
setCheckCardModalV3Selected: setCheckCardModalV3SelectedImpl,
// 通用的`Reducer`
clearAllIdleInteractivities: clearAllIdleInteractivitiesImpl,
......@@ -288,6 +311,7 @@ const duelSlice = createSlice({
YesNoModalCase(builder);
optionModalCase(builder);
checkCardModalV2Case(builder);
checkCardModalV3Case(builder);
},
});
......@@ -358,6 +382,13 @@ export const {
setUnimplemented,
updateFieldData,
reloadField,
setCheckCardModalV3IsOpen,
setCheckCardModalV3MinMax,
setCheckCardModalV3AllLevel,
setCheckCardModalV3OverFlow,
setCheckCardModalV3ResponseAble,
resetCheckCardModalV3,
setCheckCardModalV3Selected,
} = duelSlice.actions;
export const selectDuelHsStart = (state: RootState) => {
return state.duel.meInitInfo != null;
......
import { DuelState } from "../mod";
import { DuelReducer } from "../generic";
import {
ActionReducerMapBuilder,
CaseReducer,
createAsyncThunk,
} from "@reduxjs/toolkit";
import { CardMeta, fetchCard } from "../../../api/cards";
import { RootState } from "../../../store";
// 更新打开状态
export const setCheckCardModalV3IsOpenImpl: DuelReducer<boolean> = (
state,
action
) => {
state.modalState.checkCardModalV3.isOpen = action.payload;
};
// 更新选择数目
export const setCheckCardModalV3MinMaxImpl: DuelReducer<{
min: number;
max: number;
}> = (state, action) => {
state.modalState.checkCardModalV3.selectMin = action.payload.min;
state.modalState.checkCardModalV3.selectMax = action.payload.max;
};
export const setCheckCardModalV3AllLevelImpl: DuelReducer<number> = (
state,
action
) => {
state.modalState.checkCardModalV3.allLevel = action.payload;
};
export const setCheckCardModalV3OverFlowImpl: DuelReducer<boolean> = (
state,
action
) => {
state.modalState.checkCardModalV3.overflow = action.payload;
};
export const setCheckCardModalV3ResponseAbleImpl: DuelReducer<boolean> = (
state,
action
) => {
state.modalState.checkCardModalV3.responseable = action.payload;
};
export const setCheckCardModalV3SelectedImpl: DuelReducer<
{
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[]
> = (state, action) => {
state.modalState.checkCardModalV3.selectedList = action.payload;
};
// 增加卡牌选项
export const fetchCheckCardMetasV3 = createAsyncThunk(
"duel/fetchCheckCardMetaV3",
async (param: {
mustSelect: boolean;
options: {
code: number;
level1: number;
level2: number;
response: number;
}[];
}) => {
const metas = await Promise.all(
param.options.map(async (option) => {
return await fetchCard(option.code, true);
})
);
const response = {
mustSelect: param.mustSelect,
metas,
};
return response;
}
);
export const checkCardModalV3Case = (
builder: ActionReducerMapBuilder<DuelState>
) => {
builder.addCase(fetchCheckCardMetasV3.pending, (state, action) => {
const mustSelect = action.meta.arg.mustSelect;
const options = action.meta.arg.options.map((option) => {
return {
meta: { id: option.code, data: {}, text: {} },
level1: option.level1,
level2: option.level2,
response: option.response,
};
});
if (mustSelect) {
state.modalState.checkCardModalV3.mustSelectList = options;
} else {
state.modalState.checkCardModalV3.selectAbleList = options;
}
});
builder.addCase(fetchCheckCardMetasV3.fulfilled, (state, action) => {
const mustSelect = action.payload.mustSelect;
const metas = action.payload.metas;
const options = mustSelect
? state.modalState.checkCardModalV3.mustSelectList
: state.modalState.checkCardModalV3.selectAbleList;
options.forEach((option) => {
metas.forEach((meta) => {
if (option.meta.id == meta.id) {
option.meta = meta;
}
});
});
});
};
export const resetCheckCardModalV3Impl: CaseReducer<DuelState> = (state) => {
const modalState = state.modalState.checkCardModalV3;
modalState.isOpen = false;
modalState.overflow = false;
modalState.allLevel = 0;
modalState.responseable = undefined;
modalState.mustSelectList = [];
modalState.selectAbleList = [];
modalState.selectedList = [];
};
export const selectCheckCardModalV3 = (state: RootState) =>
state.duel.modalState.checkCardModalV3;
......@@ -57,7 +57,7 @@ export interface ModalState {
finishAble: boolean;
selectMin?: number;
selectMax?: number;
responseable: boolean;
responseable?: boolean;
selectableOptions: {
code: number;
name?: string;
......@@ -71,6 +71,34 @@ export interface ModalState {
response: number;
}[];
};
// 卡牌选择弹窗V3
checkCardModalV3: {
isOpen: boolean;
overflow: boolean;
allLevel: number;
selectMin?: number;
selectMax?: number;
responseable?: boolean;
mustSelectList: {
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[];
selectAbleList: {
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[];
// TODO: remove this prop
selectedList: {
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[];
};
}
export * from "./cardModalSlice";
......@@ -80,3 +108,4 @@ export * from "./yesNoModalSlice";
export * from "./positionModalSlice";
export * from "./optionModalSlice";
export * from "./checkCardModalV2Slice";
export * from "./checkCardModalV3Slice";
......@@ -24,6 +24,7 @@ import onMsgWait from "./wait";
import onUnimplemented from "./unimplemented";
import onMsgUpdateData from "./updateData";
import onMsgReloadField from "./reloadField";
import onMsgSelectSum from "./selectSum";
import { setWaiting } from "../../reducers/duel/mod";
const ActiveList = [
......@@ -163,6 +164,11 @@ export default function handleGameMsg(pb: ygopro.YgoStocMsg) {
break;
}
case "select_sum": {
onMsgSelectSum(msg.select_sum, dispatch);
break;
}
case "unimplemented": {
onUnimplemented(msg.unimplemented, dispatch);
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import {
setCheckCardModalV3AllLevel,
setCheckCardModalV3IsOpen,
setCheckCardModalV3MinMax,
setCheckCardModalV3OverFlow,
} from "../../reducers/duel/mod";
import { fetchCheckCardMetasV3 } from "../../reducers/duel/modal/checkCardModalV3Slice";
import { AppDispatch } from "../../store";
import MsgSelectSum = ygopro.StocGameMessage.MsgSelectSum;
export default (selectSum: MsgSelectSum, dispatch: AppDispatch) => {
dispatch(setCheckCardModalV3OverFlow(selectSum.overflow != 0));
dispatch(setCheckCardModalV3AllLevel(selectSum.level_sum));
dispatch(
setCheckCardModalV3MinMax({ min: selectSum.min, max: selectSum.max })
);
dispatch(
fetchCheckCardMetasV3({
mustSelect: true,
options: selectSum.must_select_cards,
})
);
dispatch(
fetchCheckCardMetasV3({
mustSelect: false,
options: selectSum.selectable_cards,
})
);
dispatch(setCheckCardModalV3IsOpen(true));
};
import React, { useState } from "react";
import { useAppSelector } from "../../hook";
import { store } from "../../store";
import { Modal, Button, Card, Row, Col } from "antd";
import { CheckCard } from "@ant-design/pro-components";
import { sendSelectCardResponse } from "../../api/ocgcore/ocgHelper";
import {
resetCheckCardModalV3,
setCheckCardModalV3IsOpen,
setCheckCardModalV3ResponseAble,
} from "../../reducers/duel/mod";
import NeosConfig from "../../../neos.config.json";
import { selectCheckCardModalV3 } from "../../reducers/duel/modal/checkCardModalV3Slice";
const CheckCardModalV3 = () => {
const dispatch = store.dispatch;
const state = useAppSelector(selectCheckCardModalV3);
const isOpen = state.isOpen;
const min = state.selectMin || 0;
const max = state.selectMax || 0;
const mustSelectOptions = state.mustSelectList;
const selectAbleOptions = state.selectAbleList;
const [selectedOptions, setSelectedOptions] = useState(state.selectedList);
const overflow = state.overflow;
const LevelSum = state.allLevel;
const Level1Sum = mustSelectOptions
.concat(selectedOptions)
.map((option) => option.level1)
.reduce((sum, current) => sum + current, 0);
const Level2Sum = mustSelectOptions
.concat(selectedOptions)
.map((option) => option.level2)
.reduce((sum, current) => sum + current, 0);
const responseable =
(overflow
? Level1Sum >= LevelSum || Level2Sum >= LevelSum
: Level1Sum == LevelSum || Level2Sum == LevelSum) &&
selectedOptions.length <= max &&
selectedOptions.length >= min;
const onFinish = () => {
sendSelectCardResponse(
mustSelectOptions.concat(selectedOptions).map((option) => option.response)
);
dispatch(setCheckCardModalV3IsOpen(false));
dispatch(resetCheckCardModalV3());
dispatch(setCheckCardModalV3ResponseAble(false));
};
return (
<Modal
title={`请选择卡片,最少${min}张,最多${max}张`}
open={isOpen}
closable={false}
footer={
<>
<Button disabled={!responseable} onClick={onFinish}>
finish
</Button>
</>
}
width={800}
>
<CheckCard.Group
bordered
size="small"
multiple={true}
onChange={(values: any) => {
console.log(values);
setSelectedOptions(values);
}}
>
<Row>
{selectAbleOptions.map((option, idx) => {
return (
<Col span={4} key={idx}>
<CheckCard
title={option.meta.text.name}
description={option.meta.text.desc}
style={{ width: 120 }}
cover={
<img
alt={option.meta.id.toString()}
src={`${NeosConfig.cardImgUrl}/${option.meta.id}.jpg`}
style={{ width: 100 }}
/>
}
value={option}
/>
</Col>
);
})}
</Row>
</CheckCard.Group>
<p>必须选择的卡片</p>
<Row>
{mustSelectOptions.map((option, idx) => {
return (
<Col span={4} key={idx}>
<Card
hoverable
style={{ width: 120 }}
cover={
<img
alt={option.meta.id.toString()}
src={`${NeosConfig.cardImgUrl}/${option.meta.id}.jpg`}
/>
}
/>
</Col>
);
})}
</Row>
</Modal>
);
};
export default CheckCardModalV3;
......@@ -26,6 +26,7 @@ import { Row } from "antd";
import SendBox from "./sendBox";
import PlayerStatus from "./status";
import Alert from "./alert";
import CheckCardModalV3 from "./checkCardModalV3";
// Ref: https://github.com/brianzinn/react-babylonjs/issues/126
const NeosDuel = () => {
......@@ -46,6 +47,7 @@ const NeosDuel = () => {
<PositionModal />
<OptionModal />
<CheckCardModalV2 />
<CheckCardModalV3 />
</>
);
};
......
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