Commit 3404295a authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/extra_deck' into 'main'

Feat/extra deck

See merge request !92
parents 7ac66454 a20ba050
Pipeline #19775 passed with stages
in 5 minutes and 15 seconds
......@@ -18,6 +18,7 @@ export const clearAllIdleInteractivitiesImpl: DuelReducer<number> = (
state.meMagics,
state.meCemetery,
state.meExclusion,
state.meExtraDeck,
]
: [
state.opHands,
......@@ -25,6 +26,7 @@ export const clearAllIdleInteractivitiesImpl: DuelReducer<number> = (
state.opMagics,
state.opCemetery,
state.opExclusion,
state.opExtraDeck,
];
states.forEach((item) => clearIdleInteractivities(item));
......
import { ActionReducerMapBuilder } from "@reduxjs/toolkit";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { RootState } from "../../store";
import {
createAsyncMetaThunk,
createAsyncRepeatedMetaThunk,
DuelFieldState,
DuelReducer,
extendIdleInteractivities,
extendMeta,
extendState,
Interactivity,
removeCard,
updateCardMeta,
} from "./generic";
import { DuelState } from "./mod";
import { judgeSelf } from "./util";
export interface ExtraDeckState extends DuelFieldState {}
// 初始化额外卡组
export const initMeExtraDeckMeta = createAsyncRepeatedMetaThunk(
"duel/initExtraDeckMeta"
);
// 增加额外卡组
export const fetchExtraDeckMeta = createAsyncMetaThunk(
"duel/fetchExtraDeckMeta"
);
export const extraDeckCase = (builder: ActionReducerMapBuilder<DuelState>) => {
builder.addCase(initMeExtraDeckMeta.pending, (state, action) => {
const _ = action.meta.arg.controler;
const ids = action.meta.arg.codes;
const cards = ids.map((id) => {
return {
occupant: { id, data: {}, text: {} },
location: {
location: ygopro.CardZone.EXTRA,
},
idleInteractivities: [],
};
});
state.meExtraDeck = { inner: cards };
});
builder.addCase(initMeExtraDeckMeta.fulfilled, (state, action) => {
const _ = action.payload.controler;
const metas = action.payload.metas;
updateCardMeta(state.meExtraDeck, metas);
});
builder.addCase(fetchExtraDeckMeta.pending, (state, action) => {
const controler = action.meta.arg.controler;
const sequence = action.meta.arg.sequence;
const code = action.meta.arg.code;
const newExtraDeck = {
occupant: { id: code, data: {}, text: {} },
location: {
controler,
location: ygopro.CardZone.EXTRA,
sequence,
},
idleInteractivities: [],
};
const extraDeck = judgeSelf(controler, state)
? state.meExtraDeck
: state.opExtraDeck;
extendState(extraDeck, newExtraDeck);
});
builder.addCase(fetchExtraDeckMeta.fulfilled, (state, action) => {
const controler = action.payload.controler;
const sequence = action.payload.sequence;
const meta = action.payload.meta;
const extraDeck = judgeSelf(controler, state)
? state.meExtraDeck
: state.opExtraDeck;
extendMeta(extraDeck, meta, sequence);
});
};
// 删除额外卡组
export const removeExtraDeckImpl: DuelReducer<{
controler: number;
sequence: number;
}> = (state, action) => {
const extraDeck = judgeSelf(action.payload.controler, state)
? state.meExtraDeck
: state.opExtraDeck;
removeCard(extraDeck, action.payload.sequence);
};
export const addExtraDeckIdleInteractivitiesImpl: DuelReducer<{
player: number;
sequence: number;
interactivity: Interactivity<number>;
}> = (state, action) => {
const extraDeck = judgeSelf(action.payload.player, state)
? state.meExtraDeck
: state.opExtraDeck;
extendIdleInteractivities(
extraDeck,
action.payload.sequence,
action.payload.interactivity
);
};
export const selectMeExtraDeck = (state: RootState) =>
state.duel.meExtraDeck || { inner: [] };
export const selectOpExtraDeck = (state: RootState) =>
state.duel.opExtraDeck || { inner: [] };
......@@ -18,7 +18,7 @@ export interface DuelFieldState {
export interface CardState {
occupant?: CardMeta; // 占据此位置的卡牌元信息
location: {
controler: number;
controler?: number;
location?: number;
position?: ygopro.CardPosition;
overlay_sequence?: number;
......
......@@ -73,6 +73,7 @@ export const removeHandImpl: CaseReducer<
removeCard(hands, sequence);
};
// 在特定位置增加手牌
export const insertHandMeta = createAsyncMetaThunk("duel/insertHandMeta");
export const updateHandsMeta = createAsyncRepeatedMetaThunk(
......@@ -171,8 +172,6 @@ export const handsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
});
};
// 在特定位置增加手牌
export const selectMeHands = (state: RootState) =>
state.duel.meHands || { inner: [] };
export const selectOpHands = (state: RootState) =>
......
......@@ -95,6 +95,12 @@ import {
clearAllIdleInteractivitiesImpl,
clearAllPlaceInteractivitiesImpl,
} from "./commonSlice";
import {
ExtraDeckState,
extraDeckCase,
removeExtraDeckImpl,
addExtraDeckIdleInteractivitiesImpl,
} from "./extraDeckSlice";
export interface DuelState {
selfType?: number;
......@@ -119,6 +125,9 @@ export interface DuelState {
meDeck?: DeckState; // 自己的卡组状态
opDeck?: DeckState; // 对手的卡组状态
meExtraDeck?: ExtraDeckState; // 自己的额外卡组状态
opExtraDeck?: ExtraDeckState; // 对手的额外卡组状态
meTimeLimit?: TimeLimit; // 自己的计时
opTimeLimit?: TimeLimit; // 对手的计时
......@@ -199,6 +208,10 @@ const duelSlice = createSlice({
// 卡组相关`Reducer`
initDeck: initDeckImpl,
// 额外卡组相关`Reducer`
removeExtraDeck: removeExtraDeckImpl,
addExtraDeckIdleInteractivities: addExtraDeckIdleInteractivitiesImpl,
// 阶段相关
updatePhase: newPhaseImpl,
setEnableBp: setEnableBpImpl,
......@@ -242,6 +255,7 @@ const duelSlice = createSlice({
magicCase(builder);
cemeteryCase(builder);
exclusionCase(builder);
extraDeckCase(builder);
checkCardModalCase(builder);
YesNoModalCase(builder);
optionModalCase(builder);
......@@ -297,6 +311,8 @@ export const {
setOptionModalIsOpen,
resetOptionModal,
initDeck,
removeExtraDeck,
addExtraDeckIdleInteractivities,
initExclusion,
removeExclusion,
addExclusionIdleInteractivities,
......
......@@ -5,6 +5,7 @@ import { fetchMonsterMeta } from "../../reducers/duel/monstersSlice";
import {
removeCemetery,
removeExclusion,
removeExtraDeck,
removeHand,
removeMagic,
removeMonster,
......@@ -13,6 +14,7 @@ import { fetchMagicMeta } from "../../reducers/duel/magicSlice";
import { fetchCemeteryMeta } from "../../reducers/duel/cemeretySlice";
import { insertHandMeta } from "../../reducers/duel/handsSlice";
import { fetchExclusionMeta } from "../../reducers/duel/exclusionSlice";
import { fetchExtraDeckMeta } from "../../reducers/duel/extraDeckSlice";
export default (move: MsgMove, dispatch: AppDispatch) => {
const code = move.code;
......@@ -54,6 +56,13 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
break;
}
case ygopro.CardZone.EXTRA: {
dispatch(
removeExtraDeck({ controler: from.controler, sequence: from.sequence })
);
break;
}
default: {
console.log(`Unhandled zone type ${from.location}`);
break;
......@@ -114,6 +123,17 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
break;
}
case ygopro.CardZone.EXTRA: {
dispatch(
fetchExtraDeckMeta({
controler: to.controler,
sequence: to.sequence,
code,
})
);
break;
}
default: {
console.log(`Unhandled zone type ${to.location}`);
......
......@@ -10,6 +10,7 @@ import {
addCemeteryIdleInteractivities,
clearAllIdleInteractivities,
addExclusionIdleInteractivities,
addExtraDeckIdleInteractivities,
} from "../../reducers/duel/mod";
import MsgSelectIdleCmd = ygopro.StocGameMessage.MsgSelectIdleCmd;
import { ActionCreatorWithPayload } from "@reduxjs/toolkit";
......@@ -91,6 +92,11 @@ export default (selectIdleCmd: MsgSelectIdleCmd, dispatch: AppDispatch) => {
break;
}
case ygopro.CardZone.EXTRA: {
dispatcher(data, interactType, addExtraDeckIdleInteractivities);
break;
}
default: {
console.log(`Unhandled zone type: ${cardInfo.location}`);
}
......
......@@ -4,13 +4,6 @@ import { useAppSelector } from "../../hook";
import { selectMeDeck, selectOpDeck } from "../../reducers/duel/deckSlice";
import SingleSlot, { Depth } from "./singleSlot";
const Deck = () => (
<>
<CommonDeck />
<ExtraDeck />
</>
);
const CommonDeck = () => {
const meDeck = useAppSelector(selectMeDeck).inner;
const opDeck = useAppSelector(selectOpDeck).inner;
......@@ -31,32 +24,6 @@ const CommonDeck = () => {
);
};
const ExtraDeck = () => {
const shape = CONFIG.ExtraDeckSlotShape();
const position = new BABYLON.Vector3(
-3.3,
shape.depth / 2 + CONFIG.Floating,
-3.3
);
const rotation = CONFIG.DeckSlotRotation();
return (
<box
name="extra-deck"
width={shape.width}
height={shape.height}
depth={shape.depth}
position={position}
rotation={rotation}
>
<standardMaterial
name="extra-deck-mat"
diffuseColor={CONFIG.ExtraDeckColor()}
/>
</box>
);
};
const deckPosition = (player: number, deckLength: number) => {
const x = player == 0 ? 3.2 : -3.2;
const y = (Depth * deckLength) / 2 + CONFIG.Floating;
......@@ -65,4 +32,4 @@ const deckPosition = (player: number, deckLength: number) => {
return new BABYLON.Vector3(x, y, z);
};
export default Deck;
export default CommonDeck;
import SingleSlot, { Depth } from "./singleSlot";
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "../../config/ui";
import { useAppSelector } from "../../hook";
import {
selectMeExtraDeck,
selectOpExtraDeck,
} from "../../reducers/duel/extraDeckSlice";
const ExtraDeck = () => {
const meExtraDeck = useAppSelector(selectMeExtraDeck).inner;
const opExtraDeck = useAppSelector(selectOpExtraDeck).inner;
return (
<>
<SingleSlot
state={meExtraDeck}
position={extraDeckPosition(0, meExtraDeck.length)}
rotation={CONFIG.CardSlotRotation(false)}
/>
<SingleSlot
state={opExtraDeck}
position={extraDeckPosition(1, opExtraDeck.length)}
rotation={CONFIG.CardSlotRotation(true)}
/>
</>
);
};
const extraDeckPosition = (player: number, deckLength: number) => {
const x = player == 0 ? -3.3 : 3.3;
const y = (Depth & deckLength) / 2 + CONFIG.Floating;
const z = player == 0 ? -3.3 : 3.3;
return new BABYLON.Vector3(x, y, z);
};
export default ExtraDeck;
......@@ -9,7 +9,7 @@ import CardModal from "./cardModal";
import HintNotification from "./hintNotification";
import Magics from "./magics";
import Field from "./field";
import Deck from "./deck";
import CommonDeck from "./deck";
import Exclusion from "./exclusion";
import Cemeteries from "./cemetery";
import CardListModal from "./cardListModal";
......@@ -19,6 +19,7 @@ import PositionModal from "./positionModal";
import OptionModal from "./optionModal";
import Phase from "./phase";
import CheckCardModalV2 from "./checkCardModalV2";
import ExtraDeck from "./extraDeck";
// Ref: https://github.com/brianzinn/react-babylonjs/issues/126
const NeosDuel = () => (
......@@ -34,7 +35,8 @@ const NeosDuel = () => (
<Monsters />
<Magics />
<Field />
<Deck />
<CommonDeck />
<ExtraDeck />
<Cemeteries />
<Exclusion />
<Field />
......
......@@ -23,6 +23,8 @@ import {
import socketMiddleWare, { socketCmd } from "../middleware/socket";
import sqliteMiddleWare, { sqliteCmd } from "../middleware/sqlite";
import { Button } from "antd";
import { store } from "../store";
import { initMeExtraDeckMeta } from "../reducers/duel/extraDeckSlice";
const READY_STATE = "ready";
......@@ -56,6 +58,7 @@ export default function WaitRoom() {
});
}, []);
const dispatch = store.dispatch;
const joined = useAppSelector(selectJoined);
const chat = useAppSelector(selectChat);
const isHost = useAppSelector(selectIsHost);
......@@ -67,6 +70,7 @@ export default function WaitRoom() {
const deck = await fetchDeck("hero.ydk");
sendUpdateDeck(deck);
dispatch(initMeExtraDeckMeta({ controler: 0, codes: deck.extra || [] }));
setChoseDeck(true);
};
......
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