Commit 890d930a authored by Chunchi Che's avatar Chunchi Che

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

Feat/ui/magic

See merge request mycard/Neos!53
parents e1e017de 44c8a183
import { judgeSelf, Magic, InteractType } from "./util";
import { PayloadAction, CaseReducer } from "@reduxjs/toolkit";
import { DuelState } from "./mod";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { RootState } from "../../store";
export interface MagicState {
magics: Magic[];
}
// 初始化自己的魔法陷阱区状态
export const initMagicsImpl: CaseReducer<DuelState, PayloadAction<number>> = (
state,
action
) => {
const player = action.payload;
const magics = {
magics: [
{
sequence: 0,
},
{
sequence: 1,
},
{
sequence: 2,
},
{
sequence: 3,
},
{
sequence: 4,
},
],
};
if (judgeSelf(player, state)) {
state.meMagics = magics;
} else {
state.opMagics = magics;
}
};
export const addMagicPlaceSelectAbleImpl: CaseReducer<
DuelState,
PayloadAction<[number, number]>
> = (state, action) => {
const controler = action.payload[0];
const sequence = action.payload[1];
const magics = judgeSelf(controler, state) ? state.meMagics : state.opMagics;
if (magics) {
for (const magic of magics.magics) {
if (magic.sequence == sequence) {
magic.selectInfo = {
interactType: InteractType.PLACE_SELECTABLE,
response: {
controler,
zone: ygopro.CardZone.SZONE,
sequence,
},
};
}
}
}
};
export const clearMagicSelectInfoImpl: CaseReducer<
DuelState,
PayloadAction<number>
> = (state, action) => {
const player = action.payload;
const magics = judgeSelf(player, state) ? state.meMagics : state.opMagics;
if (magics) {
magics.magics = [];
}
};
export const selectMeMagics = (state: RootState) =>
state.duel.meMagics || { magics: [] };
...@@ -29,6 +29,12 @@ import { ...@@ -29,6 +29,12 @@ import {
addMonsterPlaceSelectAbleImpl, addMonsterPlaceSelectAbleImpl,
clearMonsterSelectInfoImpl, clearMonsterSelectInfoImpl,
} from "./monstersSlice"; } from "./monstersSlice";
import {
MagicState,
initMagicsImpl,
addMagicPlaceSelectAbleImpl,
clearMagicSelectInfoImpl,
} from "./magicSlice";
export interface DuelState { export interface DuelState {
selfType?: number; selfType?: number;
...@@ -41,6 +47,9 @@ export interface DuelState { ...@@ -41,6 +47,9 @@ export interface DuelState {
meMonsters?: MonsterState; // 自己的怪兽区状态 meMonsters?: MonsterState; // 自己的怪兽区状态
opMonsters?: MonsterState; // 对手的怪兽区状态 opMonsters?: MonsterState; // 对手的怪兽区状态
meMagics?: MagicState; // 自己的魔法陷阱区状态
opMagics?: MagicState; // 对手的魔法陷阱区状态
meTimeLimit?: TimeLimit; // 自己的计时 meTimeLimit?: TimeLimit; // 自己的计时
opTimeLimit?: TimeLimit; // 对手的计时 opTimeLimit?: TimeLimit; // 对手的计时
...@@ -81,6 +90,11 @@ const duelSlice = createSlice({ ...@@ -81,6 +90,11 @@ const duelSlice = createSlice({
addMonsterPlaceSelectAble: addMonsterPlaceSelectAbleImpl, addMonsterPlaceSelectAble: addMonsterPlaceSelectAbleImpl,
clearMonsterSelectInfo: clearMonsterSelectInfoImpl, clearMonsterSelectInfo: clearMonsterSelectInfoImpl,
// 魔法陷阱区相关`Reducer`
initMagics: initMagicsImpl,
addMagicPlaceSelectAble: addMagicPlaceSelectAbleImpl,
clearMagicSelectInfo: clearMagicSelectInfoImpl,
// UI相关`Reducer` // UI相关`Reducer`
setCardModalIsOpen: setCardModalIsOpenImpl, setCardModalIsOpen: setCardModalIsOpenImpl,
setCardModalText: setCardModalTextImpl, setCardModalText: setCardModalTextImpl,
...@@ -108,6 +122,9 @@ export const { ...@@ -108,6 +122,9 @@ export const {
initMonsters, initMonsters,
addMonsterPlaceSelectAble, addMonsterPlaceSelectAble,
clearMonsterSelectInfo, clearMonsterSelectInfo,
initMagics,
addMagicPlaceSelectAble,
clearMagicSelectInfo,
} = duelSlice.actions; } = duelSlice.actions;
export const selectDuelHsStart = (state: RootState) => { export const selectDuelHsStart = (state: RootState) => {
return state.duel.meInitInfo != null; return state.duel.meInitInfo != null;
......
...@@ -72,7 +72,7 @@ export interface Interactivity<T> { ...@@ -72,7 +72,7 @@ export interface Interactivity<T> {
response: T; response: T;
} }
export interface Monster { export interface SlotState {
sequence: number; sequence: number;
occupant?: CardMeta; occupant?: CardMeta;
selectInfo?: Interactivity<{ selectInfo?: Interactivity<{
...@@ -81,3 +81,7 @@ export interface Monster { ...@@ -81,3 +81,7 @@ export interface Monster {
sequence: number; sequence: number;
}>; }>;
} }
export type Monster = SlotState;
export type Magic = SlotState;
import { ygopro } from "../../api/ocgcore/idl/ocgcore"; import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { AppDispatch } from "../../store"; import { AppDispatch } from "../../store";
import MsgSelectPlace = ygopro.StocGameMessage.MsgSelectPlace; import MsgSelectPlace = ygopro.StocGameMessage.MsgSelectPlace;
import { addMonsterPlaceSelectAble } from "../../reducers/duel/mod"; import {
addMonsterPlaceSelectAble,
addMagicPlaceSelectAble,
} from "../../reducers/duel/mod";
export default (selectPlace: MsgSelectPlace, dispatch: AppDispatch) => { export default (selectPlace: MsgSelectPlace, dispatch: AppDispatch) => {
if (selectPlace.count != 1) { if (selectPlace.count != 1) {
...@@ -17,6 +20,11 @@ export default (selectPlace: MsgSelectPlace, dispatch: AppDispatch) => { ...@@ -17,6 +20,11 @@ export default (selectPlace: MsgSelectPlace, dispatch: AppDispatch) => {
break; break;
} }
case ygopro.CardZone.SZONE: {
dispatch(addMagicPlaceSelectAble([place.controler, place.sequence]));
break;
}
default: { default: {
console.warn(`Unhandled zoneType: ${place.zone}`); console.warn(`Unhandled zoneType: ${place.zone}`);
} }
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore"; import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { AppDispatch } from "../../store"; import { AppDispatch } from "../../store";
import { infoInit, setSelfType, initMonsters } from "../../reducers/duel/mod"; import {
infoInit,
setSelfType,
initMonsters,
initMagics,
} from "../../reducers/duel/mod";
export default ( export default (
start: ygopro.StocGameMessage.MsgStart, start: ygopro.StocGameMessage.MsgStart,
...@@ -29,4 +34,6 @@ export default ( ...@@ -29,4 +34,6 @@ export default (
); );
dispatch(initMonsters(0)); dispatch(initMonsters(0));
dispatch(initMonsters(1)); dispatch(initMonsters(1));
dispatch(initMagics(0));
dispatch(initMagics(1));
}; };
import * as BABYLON from "@babylonjs/core"; import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "../../config/ui"; import * as CONFIG from "../../config/ui";
import { selectMeMagics } from "../../reducers/duel/magicSlice";
import { useClick } from "./hook";
import { Magic } from "../../reducers/duel/util";
import { store } from "../../store";
import { useAppSelector } from "../../hook";
import { useRef } from "react";
import { sendSelectPlaceResponse } from "../../api/ocgcore/ocgHelper";
import { clearMagicSelectInfo } from "../../reducers/duel/mod";
// TODO: use config // TODO: use config
const left = -2.15; const left = -2.15;
const gap = 1.05; const gap = 1.05;
const Magics = () => { const Magics = () => {
const magics = useAppSelector(selectMeMagics).magics;
return ( return (
<> <>
{[0, 1, 2, 3, 4].map((idx) => { {magics.map((magic) => {
return <Magic idx={idx} />; return <CMagic state={magic} />;
})} })}
</> </>
); );
}; };
const Magic = (props: { idx: number }) => { const CMagic = (props: { state: Magic }) => {
const state = props.state;
const planeRef = useRef(null);
const shape = CONFIG.CardSlotShape(); const shape = CONFIG.CardSlotShape();
const position = new BABYLON.Vector3( const position = new BABYLON.Vector3(
left + gap * props.idx, left + gap * state.sequence,
shape.depth / 2 + CONFIG.Floating, shape.depth / 2 + CONFIG.Floating,
-2.6 -2.6
); );
const rotation = CONFIG.CardSlotRotation(); const rotation = CONFIG.CardSlotRotation();
const edgesWidth = 2.0;
const edgesColor = BABYLON.Color4.FromColor3(BABYLON.Color3.Yellow());
const dispatch = store.dispatch;
useClick(
(_event) => {
if (state.selectInfo) {
sendSelectPlaceResponse(state.selectInfo.response);
dispatch(clearMagicSelectInfo(0));
dispatch(clearMagicSelectInfo(1));
}
},
planeRef,
[state]
);
return ( return (
<plane <plane
name={`magic-${props.idx}`} name={`magic-${state.sequence}`}
ref={planeRef}
width={shape.width} width={shape.width}
height={shape.height} height={shape.height}
position={position} position={position}
rotation={rotation} rotation={rotation}
enableEdgesRendering
edgesWidth={state.selectInfo ? edgesWidth : 0}
edgesColor={edgesColor}
> >
<standardMaterial <standardMaterial
name={`magic-mat-${props.idx}`} name={`magic-mat-${props.state.sequence}`}
diffuseTexture={ diffuseTexture={
new BABYLON.Texture(`http://localhost:3030/images/card_slot.png`) state.occupant
? new BABYLON.Texture(`http://localhost:3030/images/card_back.jpg`)
: new BABYLON.Texture(`http://localhost:3030/images/card_slot.png`)
} }
alpha={0.2} alpha={0.2}
></standardMaterial> ></standardMaterial>
......
...@@ -42,7 +42,7 @@ const CommonMonster = (props: { state: Monster }) => { ...@@ -42,7 +42,7 @@ const CommonMonster = (props: { state: Monster }) => {
useClick( useClick(
(_event) => { (_event) => {
if (props.state.selectInfo) { if (props.state.selectInfo) {
sendSelectPlaceResponse(props.state.selectInfo?.response); sendSelectPlaceResponse(props.state.selectInfo.response);
dispatch(clearMonsterSelectInfo(0)); dispatch(clearMonsterSelectInfo(0));
dispatch(clearMonsterSelectInfo(1)); dispatch(clearMonsterSelectInfo(1));
} }
......
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