Commit 9c3989e3 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'optimize/generic' into 'main'

Optimize/generic

See merge request mycard/Neos!70
parents 20c8ba1a cc4f29ba
Pipeline #19428 passed with stages
in 4 minutes and 15 seconds
import { judgeSelf, Cemetery } from "./util";
import { judgeSelf } from "./util";
import {
PayloadAction,
CaseReducer,
......@@ -8,9 +8,11 @@ import {
import { DuelState } from "./mod";
import { RootState } from "../../store";
import { fetchCard } from "../../api/cards";
import { CardState } from "./generic";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
export interface CemeteryState {
cemetery: Cemetery[];
cemetery: CardState[];
}
// 初始化墓地状态
......@@ -50,18 +52,26 @@ export const cemeteryCase = (builder: ActionReducerMapBuilder<DuelState>) => {
const sequence = action.meta.arg.sequence;
const code = action.meta.arg.code;
const meta = { id: code, data: {}, text: {} };
const newCemetery = {
occupant: { id: code, data: {}, text: {} },
location: {
controler,
location: ygopro.CardZone.GRAVE,
sequence,
},
idleInteractivities: [],
};
if (judgeSelf(controler, state)) {
if (state.meCemetery) {
state.meCemetery.cemetery.push({ sequence, meta });
state.meCemetery.cemetery.push(newCemetery);
} else {
state.meCemetery = { cemetery: [{ sequence, meta }] };
state.meCemetery = { cemetery: [newCemetery] };
}
} else {
if (state.opCemetery) {
state.opCemetery.cemetery.push({ sequence, meta });
state.opCemetery.cemetery.push(newCemetery);
} else {
state.opCemetery = { cemetery: [{ sequence, meta }] };
state.opCemetery = { cemetery: [newCemetery] };
}
}
});
......@@ -73,16 +83,16 @@ export const cemeteryCase = (builder: ActionReducerMapBuilder<DuelState>) => {
if (judgeSelf(controler, state)) {
if (state.meCemetery) {
for (const cemetery of state.meCemetery.cemetery) {
if (cemetery.sequence == sequence) {
cemetery.meta = meta;
if (cemetery.location.sequence == sequence) {
cemetery.occupant = meta;
}
}
}
} else {
if (state.opCemetery) {
for (const cemetery of state.opCemetery.cemetery) {
if (cemetery.sequence == sequence) {
cemetery.meta = meta;
if (cemetery.location.sequence == sequence) {
cemetery.occupant = meta;
}
}
}
......
import { CardMeta } from "../../api/cards";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
export interface CardState {
occupant?: CardMeta; // 占据此位置的卡牌元信息
location: {
controler: number;
location?: number;
sequence: number;
position?: ygopro.CardPosition;
overlay_sequence?: number;
}; // 位置信息
idleInteractivities: Interactivity<number>[]; // IDLE状态下的互动信息
placeInteractivities?: Interactivity<{
controler: number;
zone: ygopro.CardZone;
sequence: number;
}>; // 选择位置状态下的互动信息
}
export enum InteractType {
// 可普通召唤
SUMMON = 1,
// 可特殊召唤
SP_SUMMON = 2,
// 可改变表示形式
POS_CHANGE = 3,
// 可前场放置
MSET = 4,
// 可后场放置
SSET = 5,
// 可发动效果
ACTIVATE = 6,
// 可作为位置选择
PLACE_SELECTABLE = 7,
}
export interface Interactivity<T> {
interactType: InteractType;
// 如果`interactType`是`ACTIVATE`,这个字段是对应的效果编号
activateIndex?: number;
// 用户点击后,需要回传给服务端的`response`
response: T;
}
......@@ -7,11 +7,13 @@ import {
import { DuelState } from "./mod";
import { RootState } from "../../store";
import { fetchCard, CardMeta } from "../../api/cards";
import { judgeSelf, Hand, Interactivity } from "./util";
import { judgeSelf } from "./util";
import { CardState, Interactivity } from "./generic";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
export interface Hands {
export interface HandState {
// 注意:手牌的位置顺序是有约束的
cards: Hand[];
hands: CardState[];
}
// 增加手牌
......@@ -42,24 +44,28 @@ export const handsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
const player = action.meta.arg[0];
const ids = action.meta.arg[1];
const cards = ids.map((id) => {
const cards = ids.map((id, idx) => {
return {
meta: { id, data: {}, text: {} },
transform: {},
interactivities: [],
occupant: { id, data: {}, text: {} },
location: {
controler: player,
location: ygopro.CardZone.HAND,
sequence: idx,
},
idleInteractivities: [],
};
});
if (judgeSelf(player, state)) {
if (state.meHands) {
state.meHands.cards = state.meHands.cards.concat(cards);
state.meHands.hands = state.meHands.hands.concat(cards);
} else {
state.meHands = { cards };
state.meHands = { hands: cards };
}
} else {
if (state.opHands) {
state.opHands.cards = state.opHands.cards.concat(cards);
state.opHands.hands = state.opHands.hands.concat(cards);
} else {
state.opHands = { cards };
state.opHands = { hands: cards };
}
}
});
......@@ -70,10 +76,10 @@ export const handsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
const hands = judgeSelf(player, state) ? state.meHands : state.opHands;
if (hands) {
for (let hand of hands.cards) {
for (let hand of hands.hands) {
for (let meta of metas) {
if (hand.meta.id === meta.id) {
hand.meta = meta;
if (hand.occupant?.id === meta.id) {
hand.occupant = meta;
}
}
}
......@@ -82,7 +88,7 @@ export const handsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
};
// 清空手牌互动性
export const clearHandsInteractivityImpl: CaseReducer<
export const clearHandsIdleInteractivityImpl: CaseReducer<
DuelState,
PayloadAction<number>
> = (state, action) => {
......@@ -91,18 +97,18 @@ export const clearHandsInteractivityImpl: CaseReducer<
const hands = judgeSelf(player, state) ? state.meHands : state.opHands;
if (hands) {
for (let hand of hands.cards) {
hand.interactivities = [];
for (let hand of hands.hands) {
hand.idleInteractivities = [];
}
}
};
// 添加手牌互动性
export const addHandsInteractivityImpl: CaseReducer<
export const addHandsIdleInteractivityImpl: CaseReducer<
DuelState,
PayloadAction<{
player: number;
index: number;
sequence: number;
interactivity: Interactivity<number>;
}>
> = (state, action) => {
......@@ -110,10 +116,10 @@ export const addHandsInteractivityImpl: CaseReducer<
const hands = judgeSelf(player, state) ? state.meHands : state.opHands;
if (hands) {
const index = action.payload.index;
const sequence = action.payload.sequence;
const interactivity = action.payload.interactivity;
hands.cards[index].interactivities.push(interactivity);
hands.hands[sequence].idleInteractivities.push(interactivity);
}
};
......@@ -127,11 +133,13 @@ export const removeHandImpl: CaseReducer<
const hands = judgeSelf(controler, state) ? state.meHands : state.opHands;
if (hands) {
hands.cards = hands.cards.filter((_, idx) => idx != sequence);
hands.hands = hands.hands.filter(
(card) => card.location.sequence != sequence
);
}
};
export const selectMeHands = (state: RootState) =>
state.duel.meHands || { cards: [] };
state.duel.meHands || { hands: [] };
export const selectOpHands = (state: RootState) =>
state.duel.opHands || { cards: [] };
state.duel.opHands || { hands: [] };
import { judgeSelf, Magic, InteractType } from "./util";
import { judgeSelf } from "./util";
import {
PayloadAction,
CaseReducer,
......@@ -9,9 +9,10 @@ import { DuelState } from "./mod";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { RootState } from "../../store";
import { fetchCard } from "../../api/cards";
import { CardState, InteractType } from "./generic";
export interface MagicState {
magics: Magic[];
magics: CardState[];
}
// 初始化自己的魔法陷阱区状态
......@@ -23,19 +24,44 @@ export const initMagicsImpl: CaseReducer<DuelState, PayloadAction<number>> = (
const magics = {
magics: [
{
sequence: 0,
location: {
controler: player,
location: ygopro.CardZone.SZONE,
sequence: 0,
},
idleInteractivities: [],
},
{
sequence: 1,
location: {
controler: player,
location: ygopro.CardZone.SZONE,
sequence: 1,
},
idleInteractivities: [],
},
{
sequence: 2,
location: {
controler: player,
location: ygopro.CardZone.SZONE,
sequence: 2,
},
idleInteractivities: [],
},
{
sequence: 3,
location: {
controler: player,
location: ygopro.CardZone.SZONE,
sequence: 3,
},
idleInteractivities: [],
},
{
sequence: 4,
location: {
controler: player,
location: ygopro.CardZone.SZONE,
sequence: 4,
},
idleInteractivities: [],
},
],
};
......@@ -47,7 +73,7 @@ export const initMagicsImpl: CaseReducer<DuelState, PayloadAction<number>> = (
}
};
export const addMagicPlaceSelectAbleImpl: CaseReducer<
export const addMagicPlaceInteractivitiesImpl: CaseReducer<
DuelState,
PayloadAction<[number, number]>
> = (state, action) => {
......@@ -57,8 +83,8 @@ export const addMagicPlaceSelectAbleImpl: CaseReducer<
const magics = judgeSelf(controler, state) ? state.meMagics : state.opMagics;
if (magics) {
for (const magic of magics.magics) {
if (magic.sequence == sequence) {
magic.selectInfo = {
if (magic.location.sequence == sequence) {
magic.placeInteractivities = {
interactType: InteractType.PLACE_SELECTABLE,
response: {
controler,
......@@ -71,7 +97,7 @@ export const addMagicPlaceSelectAbleImpl: CaseReducer<
}
};
export const clearMagicSelectInfoImpl: CaseReducer<
export const clearMagicPlaceInteractivitiesImpl: CaseReducer<
DuelState,
PayloadAction<number>
> = (state, action) => {
......@@ -81,7 +107,7 @@ export const clearMagicSelectInfoImpl: CaseReducer<
if (magics) {
for (const magic of magics.magics) {
magic.selectInfo = undefined;
magic.placeInteractivities = undefined;
}
}
};
......@@ -120,18 +146,18 @@ export const magicCase = (builder: ActionReducerMapBuilder<DuelState>) => {
if (judgeSelf(controler, state)) {
if (state.meMagics) {
for (const magic of state.meMagics.magics) {
if (magic.sequence == sequence) {
if (magic.location.sequence == sequence) {
magic.occupant = meta;
magic.position = position;
magic.location.position = position;
}
}
}
} else {
if (state.opMagics) {
for (const magic of state.opMagics.magics) {
if (magic.sequence == sequence) {
if (magic.location.sequence == sequence) {
magic.occupant = meta;
magic.position = position;
magic.location.position = position;
}
}
}
......@@ -145,7 +171,7 @@ export const magicCase = (builder: ActionReducerMapBuilder<DuelState>) => {
if (judgeSelf(controler, state)) {
if (state.meMagics) {
for (const magic of state.meMagics.magics) {
if (magic.sequence == sequence) {
if (magic.location.sequence == sequence) {
magic.occupant = meta;
}
}
......@@ -153,7 +179,7 @@ export const magicCase = (builder: ActionReducerMapBuilder<DuelState>) => {
} else {
if (state.opMagics) {
for (const magic of state.opMagics.magics) {
if (magic.sequence == sequence) {
if (magic.location.sequence == sequence) {
magic.occupant = meta;
}
}
......
......@@ -7,10 +7,10 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { InitInfo, infoInitImpl } from "./initInfoSlice";
import { TimeLimit, updateTimeLimitImpl } from "./timeLimit";
import {
Hands,
HandState,
handsCase,
clearHandsInteractivityImpl,
addHandsInteractivityImpl,
clearHandsIdleInteractivityImpl,
addHandsIdleInteractivityImpl,
removeHandImpl,
} from "./handsSlice";
import { newTurnImpl } from "./turnSlice";
......@@ -40,19 +40,19 @@ import {
setOptionModalIsOpenImpl,
resetOptionModalImpl,
optionModalCase,
} from "./modalSlice";
} from "./modal/mod";
import {
MonsterState,
initMonstersImpl,
addMonsterPlaceSelectAbleImpl,
clearMonsterSelectInfoImpl,
addMonsterPlaceInteractivitiesImpl,
clearMonsterPlaceInteractivitiesImpl,
monsterCase,
} from "./monstersSlice";
import {
MagicState,
initMagicsImpl,
addMagicPlaceSelectAbleImpl,
clearMagicSelectInfoImpl,
addMagicPlaceInteractivitiesImpl,
clearMagicPlaceInteractivitiesImpl,
magicCase,
} from "./magicSlice";
import { CemeteryState, initCemeteryImpl, cemeteryCase } from "./cemeretySlice";
......@@ -62,8 +62,8 @@ export interface DuelState {
meInitInfo?: InitInfo; // 自己的初始状态
opInitInfo?: InitInfo; // 对手的初始状态
meHands?: Hands; // 自己的手牌
opHands?: Hands; // 对手的手牌
meHands?: HandState; // 自己的手牌
opHands?: HandState; // 对手的手牌
meMonsters?: MonsterState; // 自己的怪兽区状态
opMonsters?: MonsterState; // 对手的怪兽区状态
......@@ -111,19 +111,19 @@ const duelSlice = createSlice({
updateTimeLimit: updateTimeLimitImpl,
// 手牌相关`Reducer`
clearHandsInteractivity: clearHandsInteractivityImpl,
addHandsInteractivity: addHandsInteractivityImpl,
clearHandsIdleInteractivity: clearHandsIdleInteractivityImpl,
addHandsIdleInteractivity: addHandsIdleInteractivityImpl,
removeHand: removeHandImpl,
// 怪兽区相关`Reducer`
initMonsters: initMonstersImpl,
addMonsterPlaceSelectAble: addMonsterPlaceSelectAbleImpl,
clearMonsterSelectInfo: clearMonsterSelectInfoImpl,
addMonsterPlaceInteractivities: addMonsterPlaceInteractivitiesImpl,
clearMonsterPlaceInteractivities: clearMonsterPlaceInteractivitiesImpl,
// 魔法陷阱区相关`Reducer`
initMagics: initMagicsImpl,
addMagicPlaceSelectAble: addMagicPlaceSelectAbleImpl,
clearMagicSelectInfo: clearMagicSelectInfoImpl,
addMagicPlaceInteractivities: addMagicPlaceInteractivitiesImpl,
clearMagicPlaceInteractivities: clearMagicPlaceInteractivitiesImpl,
// 墓地相关`Reducer`
initCemetery: initCemeteryImpl,
......@@ -165,19 +165,19 @@ export const {
infoInit,
updateTurn,
updatePhase,
clearHandsInteractivity,
addHandsInteractivity,
clearHandsIdleInteractivity,
addHandsIdleInteractivity,
updateTimeLimit,
setCardModalIsOpen,
setCardModalText,
setCardModalImgUrl,
setCardModalInteractivies,
initMonsters,
addMonsterPlaceSelectAble,
clearMonsterSelectInfo,
addMonsterPlaceInteractivities,
clearMonsterPlaceInteractivities,
initMagics,
addMagicPlaceSelectAble,
clearMagicSelectInfo,
addMagicPlaceInteractivities,
clearMagicPlaceInteractivities,
removeHand,
initCemetery,
setCardListModalIsOpen,
......
import { PayloadAction, CaseReducer } from "@reduxjs/toolkit";
import { DuelState } from "../mod";
import { RootState } from "../../../store";
// 更新卡牌列表弹窗打开状态
export const setCardListModalIsOpenImpl: CaseReducer<
DuelState,
PayloadAction<boolean>
> = (state, action) => {
state.modalState.cardListModal.isOpen = action.payload;
};
// 更新卡牌列表数据
export const setCardListModalInfoImpl: CaseReducer<
DuelState,
PayloadAction<{ name?: string; desc?: string; imgUrl?: string }[]>
> = (state, action) => {
const list = action.payload;
state.modalState.cardListModal.list = list;
};
export const selectCardListModalIsOpen = (state: RootState) =>
state.duel.modalState.cardListModal.isOpen;
export const selectCardListModalInfo = (state: RootState) =>
state.duel.modalState.cardListModal.list;
import { PayloadAction, CaseReducer } from "@reduxjs/toolkit";
import { DuelState } from "../mod";
import { RootState } from "../../../store";
// 更新卡牌弹窗打开状态
export const setCardModalIsOpenImpl: CaseReducer<
DuelState,
PayloadAction<boolean>
> = (state, action) => {
state.modalState.cardModal.isOpen = action.payload;
};
// 更新卡牌弹窗文本
export const setCardModalTextImpl: CaseReducer<
DuelState,
PayloadAction<[string?, string?]>
> = (state, action) => {
const name = action.payload[0];
const desc = action.payload[1];
state.modalState.cardModal.name = name;
state.modalState.cardModal.desc = desc;
};
// 更新卡牌弹窗图片Url
export const setCardModalImgUrlImpl: CaseReducer<
DuelState,
PayloadAction<string>
> = (state, action) => {
state.modalState.cardModal.imgUrl = action.payload;
};
// 更新卡牌弹窗互动选项
export const setCardModalInteractiviesImpl: CaseReducer<
DuelState,
PayloadAction<{ desc: string; response: number }[]>
> = (state, action) => {
state.modalState.cardModal.interactivies = action.payload;
};
export const selectCardModalIsOpen = (state: RootState) =>
state.duel.modalState.cardModal.isOpen;
export const selectCardModalName = (state: RootState) =>
state.duel.modalState.cardModal.name;
export const selectCardModalDesc = (state: RootState) =>
state.duel.modalState.cardModal.desc;
export const selectCardModalImgUrl = (state: RootState) =>
state.duel.modalState.cardModal.imgUrl;
export const selectCardModalInteractivies = (state: RootState) =>
state.duel.modalState.cardModal.interactivies;
......@@ -4,120 +4,10 @@ import {
createAsyncThunk,
ActionReducerMapBuilder,
} from "@reduxjs/toolkit";
import { CardMeta, fetchCard, getCardStr } from "../../api/cards";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { fetchStrings } from "../../api/strings";
import { RootState } from "../../store";
import { DuelState } from "./mod";
import { judgeSelf } from "./util";
export interface ModalState {
// 卡牌弹窗
cardModal: {
isOpen: boolean;
name?: string;
desc?: string;
imgUrl?: string;
interactivies: { desc: string; response: number }[];
};
// 卡牌列表弹窗
cardListModal: {
isOpen: boolean;
list: {
name?: string;
desc?: string;
imgUrl?: string;
}[];
};
// 卡牌选择弹窗
checkCardModal: {
isOpen: boolean;
onSubmit?: string;
selectMin?: number;
selectMax?: number;
cancelAble: boolean;
cancelResponse?: number;
tags: {
tagName: string;
options: {
code: number;
name?: string;
desc?: string;
effectDesc?: string;
response: number;
}[];
}[];
};
// Yes or No弹窗
yesNoModal: {
isOpen: boolean;
msg?: string;
};
// 表示形式选择弹窗
positionModal: {
isOpen: boolean;
positions: ygopro.CardPosition[];
};
// 选项选择弹窗
optionModal: {
isOpen: boolean;
options: { msg: string; response: number }[];
};
}
// 更新卡牌弹窗打开状态
export const setCardModalIsOpenImpl: CaseReducer<
DuelState,
PayloadAction<boolean>
> = (state, action) => {
state.modalState.cardModal.isOpen = action.payload;
};
// 更新卡牌弹窗文本
export const setCardModalTextImpl: CaseReducer<
DuelState,
PayloadAction<[string?, string?]>
> = (state, action) => {
const name = action.payload[0];
const desc = action.payload[1];
state.modalState.cardModal.name = name;
state.modalState.cardModal.desc = desc;
};
// 更新卡牌弹窗图片Url
export const setCardModalImgUrlImpl: CaseReducer<
DuelState,
PayloadAction<string>
> = (state, action) => {
state.modalState.cardModal.imgUrl = action.payload;
};
// 更新卡牌弹窗互动选项
export const setCardModalInteractiviesImpl: CaseReducer<
DuelState,
PayloadAction<{ desc: string; response: number }[]>
> = (state, action) => {
state.modalState.cardModal.interactivies = action.payload;
};
// 更新卡牌列表弹窗打开状态
export const setCardListModalIsOpenImpl: CaseReducer<
DuelState,
PayloadAction<boolean>
> = (state, action) => {
state.modalState.cardListModal.isOpen = action.payload;
};
// 更新卡牌列表数据
export const setCardListModalInfoImpl: CaseReducer<
DuelState,
PayloadAction<{ name?: string; desc?: string; imgUrl?: string }[]>
> = (state, action) => {
const list = action.payload;
state.modalState.cardListModal.list = list;
};
import { RootState } from "../../../store";
import { DuelState } from "../mod";
import { judgeSelf } from "../util";
import { fetchCard, getCardStr } from "../../../api/cards";
// 更新卡牌选择弹窗打开状态
export const setCheckCardModalIsOpenImpl: CaseReducer<
......@@ -244,106 +134,6 @@ export const resetCheckCardModalImpl: CaseReducer<DuelState> = (state) => {
state.modalState.checkCardModal.tags = [];
};
// 更新YesNo弹窗是否打开状态
export const setYesNoModalIsOpenImpl: CaseReducer<
DuelState,
PayloadAction<boolean>
> = (state, action) => {
state.modalState.yesNoModal.isOpen = action.payload;
};
// 设置YesNo弹窗展示内容
export const fetchYesNoMeta = createAsyncThunk(
"duel/fetchYesNoMeta",
async (param: {
code: number;
location: ygopro.CardLocation;
descCode: number;
textGenerator: (
desc: string,
cardMeta: CardMeta,
cardLocation: ygopro.CardLocation
) => string;
}) => {
const desc = await fetchStrings("!system", param.descCode);
const meta = await fetchCard(param.code);
// TODO: 国际化文案
return param.textGenerator(desc, meta, param.location);
}
);
export const YesNoModalCase = (builder: ActionReducerMapBuilder<DuelState>) => {
builder.addCase(fetchYesNoMeta.fulfilled, (state, action) => {
state.modalState.yesNoModal.msg = action.payload;
});
};
export const setPositionModalIsOpenImpl: CaseReducer<
DuelState,
PayloadAction<boolean>
> = (state, action) => {
state.modalState.positionModal.isOpen = action.payload;
};
export const setPositionModalPositionsImpl: CaseReducer<
DuelState,
PayloadAction<ygopro.CardPosition[]>
> = (state, action) => {
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) =>
state.duel.modalState.cardModal.name;
export const selectCardModalDesc = (state: RootState) =>
state.duel.modalState.cardModal.desc;
export const selectCardModalImgUrl = (state: RootState) =>
state.duel.modalState.cardModal.imgUrl;
export const selectCardModalInteractivies = (state: RootState) =>
state.duel.modalState.cardModal.interactivies;
export const selectCardListModalIsOpen = (state: RootState) =>
state.duel.modalState.cardListModal.isOpen;
export const selectCardListModalInfo = (state: RootState) =>
state.duel.modalState.cardListModal.list;
export const selectCheckCardModalIsOpen = (state: RootState) =>
state.duel.modalState.checkCardModal.isOpen;
export const selectCheckCardModalMinMax = (state: RootState) => {
......@@ -360,15 +150,3 @@ export const selectCheckCardModalCancelAble = (state: RootState) =>
state.duel.modalState.checkCardModal.cancelAble;
export const selectCheckCardModalCacnelResponse = (state: RootState) =>
state.duel.modalState.checkCardModal.cancelResponse;
export const selectYesNoModalIsOpen = (state: RootState) =>
state.duel.modalState.yesNoModal.isOpen;
export const selectYesNOModalMsg = (state: RootState) =>
state.duel.modalState.yesNoModal.msg;
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;
import { ygopro } from "../../../api/ocgcore/idl/ocgcore";
export interface ModalState {
// 卡牌弹窗
cardModal: {
isOpen: boolean;
name?: string;
desc?: string;
imgUrl?: string;
interactivies: { desc: string; response: number }[];
};
// 卡牌列表弹窗
cardListModal: {
isOpen: boolean;
list: {
name?: string;
desc?: string;
imgUrl?: string;
}[];
};
// 卡牌选择弹窗
checkCardModal: {
isOpen: boolean;
onSubmit?: string;
selectMin?: number;
selectMax?: number;
cancelAble: boolean;
cancelResponse?: number;
tags: {
tagName: string;
options: {
code: number;
name?: string;
desc?: string;
effectDesc?: string;
response: number;
}[];
}[];
};
// Yes or No弹窗
yesNoModal: {
isOpen: boolean;
msg?: string;
};
// 表示形式选择弹窗
positionModal: {
isOpen: boolean;
positions: ygopro.CardPosition[];
};
// 选项选择弹窗
optionModal: {
isOpen: boolean;
options: { msg: string; response: number }[];
};
}
export * from "./cardModalSlice";
export * from "./cardListModalSlice";
export * from "./checkCardModalSlice";
export * from "./yesNoModalSlice";
export * from "./positionModalSlice";
export * from "./optionModalSlice";
import {
PayloadAction,
CaseReducer,
createAsyncThunk,
ActionReducerMapBuilder,
} from "@reduxjs/toolkit";
import { DuelState } from "../mod";
import { fetchCard, getCardStr } from "../../../api/cards";
import { RootState } from "../../../store";
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 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 selectOptionModalIsOpen = (state: RootState) =>
state.duel.modalState.optionModal.isOpen;
export const selectOptionModalOptions = (state: RootState) =>
state.duel.modalState.optionModal.options;
import { PayloadAction, CaseReducer } from "@reduxjs/toolkit";
import { RootState } from "../../../store";
import { DuelState } from "../mod";
import { ygopro } from "../../../api/ocgcore/idl/ocgcore";
export const setPositionModalIsOpenImpl: CaseReducer<
DuelState,
PayloadAction<boolean>
> = (state, action) => {
state.modalState.positionModal.isOpen = action.payload;
};
export const setPositionModalPositionsImpl: CaseReducer<
DuelState,
PayloadAction<ygopro.CardPosition[]>
> = (state, action) => {
state.modalState.positionModal.positions = action.payload;
};
export const resetPositionModalImpl: CaseReducer<DuelState> = (state) => {
state.modalState.positionModal.isOpen = false;
state.modalState.positionModal.positions = [];
};
export const selectPositionModalIsOpen = (state: RootState) =>
state.duel.modalState.positionModal.isOpen;
export const selectPositionModalPositions = (state: RootState) =>
state.duel.modalState.positionModal.positions;
import {
PayloadAction,
CaseReducer,
createAsyncThunk,
ActionReducerMapBuilder,
} from "@reduxjs/toolkit";
import { CardMeta, fetchCard } from "../../../api/cards";
import { ygopro } from "../../../api/ocgcore/idl/ocgcore";
import { fetchStrings } from "../../../api/strings";
import { RootState } from "../../../store";
import { DuelState } from "../mod";
// 更新YesNo弹窗是否打开状态
export const setYesNoModalIsOpenImpl: CaseReducer<
DuelState,
PayloadAction<boolean>
> = (state, action) => {
state.modalState.yesNoModal.isOpen = action.payload;
};
// 设置YesNo弹窗展示内容
export const fetchYesNoMeta = createAsyncThunk(
"duel/fetchYesNoMeta",
async (param: {
code: number;
location: ygopro.CardLocation;
descCode: number;
textGenerator: (
desc: string,
cardMeta: CardMeta,
cardLocation: ygopro.CardLocation
) => string;
}) => {
const desc = await fetchStrings("!system", param.descCode);
const meta = await fetchCard(param.code);
// TODO: 国际化文案
return param.textGenerator(desc, meta, param.location);
}
);
export const YesNoModalCase = (builder: ActionReducerMapBuilder<DuelState>) => {
builder.addCase(fetchYesNoMeta.fulfilled, (state, action) => {
state.modalState.yesNoModal.msg = action.payload;
});
};
export const selectYesNoModalIsOpen = (state: RootState) =>
state.duel.modalState.yesNoModal.isOpen;
export const selectYesNOModalMsg = (state: RootState) =>
state.duel.modalState.yesNoModal.msg;
import { judgeSelf, Monster, InteractType } from "./util";
import { judgeSelf } from "./util";
import {
PayloadAction,
CaseReducer,
......@@ -9,9 +9,10 @@ import { DuelState } from "./mod";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { RootState } from "../../store";
import { fetchCard } from "../../api/cards";
import { CardState, InteractType } from "./generic";
export interface MonsterState {
monsters: Monster[];
monsters: CardState[];
}
// 初始化怪兽区状态
......@@ -23,19 +24,44 @@ export const initMonstersImpl: CaseReducer<DuelState, PayloadAction<number>> = (
const monsters = {
monsters: [
{
sequence: 0,
location: {
controler: player,
location: ygopro.CardZone.MZONE,
sequence: 0,
},
idleInteractivities: [],
},
{
sequence: 1,
location: {
controler: player,
location: ygopro.CardZone.MZONE,
sequence: 1,
},
idleInteractivities: [],
},
{
sequence: 2,
location: {
controler: player,
location: ygopro.CardZone.MZONE,
sequence: 2,
},
idleInteractivities: [],
},
{
sequence: 3,
location: {
controler: player,
location: ygopro.CardZone.MZONE,
sequence: 3,
},
idleInteractivities: [],
},
{
sequence: 4,
location: {
controler: player,
location: ygopro.CardZone.MZONE,
sequence: 4,
},
idleInteractivities: [],
},
],
};
......@@ -47,7 +73,7 @@ export const initMonstersImpl: CaseReducer<DuelState, PayloadAction<number>> = (
}
};
export const addMonsterPlaceSelectAbleImpl: CaseReducer<
export const addMonsterPlaceInteractivitiesImpl: CaseReducer<
DuelState,
PayloadAction<[number, number]>
> = (state, action) => {
......@@ -59,8 +85,8 @@ export const addMonsterPlaceSelectAbleImpl: CaseReducer<
: state.opMonsters;
if (monsters) {
for (const monster of monsters.monsters) {
if (monster.sequence == sequence) {
monster.selectInfo = {
if (monster.location.sequence == sequence) {
monster.placeInteractivities = {
interactType: InteractType.PLACE_SELECTABLE,
response: {
controler,
......@@ -73,7 +99,7 @@ export const addMonsterPlaceSelectAbleImpl: CaseReducer<
}
};
export const clearMonsterSelectInfoImpl: CaseReducer<
export const clearMonsterPlaceInteractivitiesImpl: CaseReducer<
DuelState,
PayloadAction<number>
> = (state, action) => {
......@@ -85,7 +111,7 @@ export const clearMonsterSelectInfoImpl: CaseReducer<
if (monsters) {
for (const monster of monsters.monsters) {
monster.selectInfo = undefined;
monster.placeInteractivities = undefined;
}
}
};
......@@ -124,18 +150,18 @@ export const monsterCase = (builder: ActionReducerMapBuilder<DuelState>) => {
if (judgeSelf(controler, state)) {
if (state.meMonsters) {
for (const monster of state.meMonsters.monsters) {
if (monster.sequence == sequence) {
if (monster.location.sequence == sequence) {
monster.occupant = meta;
monster.position = position;
monster.location.position = position;
}
}
}
} else {
if (state.opMonsters) {
for (const monster of state.opMonsters.monsters) {
if (monster.sequence == sequence) {
if (monster.location.sequence == sequence) {
monster.occupant = meta;
monster.position = position;
monster.location.position = position;
}
}
}
......@@ -149,7 +175,7 @@ export const monsterCase = (builder: ActionReducerMapBuilder<DuelState>) => {
if (judgeSelf(controler, state)) {
if (state.meMonsters) {
for (const monster of state.meMonsters.monsters) {
if (monster.sequence == sequence) {
if (monster.location.sequence == sequence) {
monster.occupant = meta;
}
}
......@@ -157,7 +183,7 @@ export const monsterCase = (builder: ActionReducerMapBuilder<DuelState>) => {
} else {
if (state.opMonsters) {
for (const monster of state.opMonsters.monsters) {
if (monster.sequence == sequence) {
if (monster.location.sequence == sequence) {
monster.occupant = meta;
}
}
......
......@@ -3,10 +3,8 @@
*
* */
import { CardMeta } from "../../api/cards";
import { DuelState } from "./mod";
import { Draft } from "@reduxjs/toolkit";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
/*
* 通过`player`和`selfType`判断是应该处理自己还是对手
......@@ -24,53 +22,3 @@ export function judgeSelf(player: number, state: Draft<DuelState>): boolean {
return false;
}
}
export interface Hand {
meta: CardMeta;
interactivities: Interactivity<number>[];
}
export enum InteractType {
// 可普通召唤
SUMMON = 1,
// 可特殊召唤
SP_SUMMON = 2,
// 可改变表示形式
POS_CHANGE = 3,
// 可前场放置
MSET = 4,
// 可后场放置
SSET = 5,
// 可发动效果
ACTIVATE = 6,
// 可作为位置选择
PLACE_SELECTABLE = 7,
}
export interface Interactivity<T> {
interactType: InteractType;
// 如果`interactType`是`ACTIVATE`,这个字段是对应的效果编号
activateIndex?: number;
// 用户点击后,需要回传给服务端的`response`
response: T;
}
export interface SlotState {
sequence: number;
occupant?: CardMeta;
position?: ygopro.CardPosition;
selectInfo?: Interactivity<{
controler: number;
zone: ygopro.CardZone;
sequence: number;
}>;
}
export type Monster = SlotState;
export type Magic = SlotState;
export interface Cemetery {
sequence: number;
meta: CardMeta;
}
......@@ -5,7 +5,7 @@ import {
setCheckCardModalMinMax,
setCheckCardModalOnSubmit,
} from "../../reducers/duel/mod";
import { fetchCheckCardMeta } from "../../reducers/duel/modalSlice";
import { fetchCheckCardMeta } from "../../reducers/duel/modal/mod";
import MsgSelectCard = ygopro.StocGameMessage.MsgSelectCard;
import { CardZoneToChinese } from "./util";
......
......@@ -7,7 +7,7 @@ import {
setCheckCardModalMinMax,
setCheckCardModalOnSubmit,
} from "../../reducers/duel/mod";
import { fetchCheckCardMeta } from "../../reducers/duel/modalSlice";
import { fetchCheckCardMeta } from "../../reducers/duel/modal/mod";
import { AppDispatch } from "../../store";
import { CardZoneToChinese } from "./util";
import MsgSelectChain = ygopro.StocGameMessage.MsgSelectChain;
......
import { CardMeta } from "../../api/cards";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { setYesNoModalIsOpen } from "../../reducers/duel/mod";
import { fetchYesNoMeta } from "../../reducers/duel/modalSlice";
import { fetchYesNoMeta } from "../../reducers/duel/modal/mod";
import { AppDispatch } from "../../store";
import { CardZoneToChinese } from "./util";
import MsgSelectEffectYn = ygopro.StocGameMessage.MsgSelectEffectYn;
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { AppDispatch } from "../../store";
import { InteractType } from "../../reducers/duel/util";
import { InteractType } from "../../reducers/duel/generic";
import {
clearHandsInteractivity,
addHandsInteractivity,
clearHandsIdleInteractivity,
addHandsIdleInteractivity,
} from "../../reducers/duel/mod";
import MsgSelectIdleCmd = ygopro.StocGameMessage.MsgSelectIdleCmd;
......@@ -12,7 +12,7 @@ export default (selectIdleCmd: MsgSelectIdleCmd, dispatch: AppDispatch) => {
const cmds = selectIdleCmd.idle_cmds;
// 先清掉之前的手牌互动性
dispatch(clearHandsInteractivity(player));
dispatch(clearHandsIdleInteractivity(player));
for (let cmd of cmds) {
let interactType;
......@@ -50,9 +50,9 @@ export default (selectIdleCmd: MsgSelectIdleCmd, dispatch: AppDispatch) => {
if (interactType === InteractType.ACTIVATE) {
// 发动效果会多一个字段
dispatch(
addHandsInteractivity({
addHandsIdleInteractivity({
player,
index: card_info.sequence,
sequence: card_info.sequence,
interactivity: {
interactType,
activateIndex: data.effect_description,
......@@ -62,9 +62,9 @@ export default (selectIdleCmd: MsgSelectIdleCmd, dispatch: AppDispatch) => {
);
} else if (interactType) {
dispatch(
addHandsInteractivity({
addHandsIdleInteractivity({
player,
index: card_info.sequence,
sequence: card_info.sequence,
interactivity: { interactType, response: data.response },
})
);
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { setOptionModalIsOpen } from "../../reducers/duel/mod";
import { fetchOptionMeta } from "../../reducers/duel/modalSlice";
import { fetchOptionMeta } from "../../reducers/duel/modal/mod";
import { AppDispatch } from "../../store";
import MsgSelectOption = ygopro.StocGameMessage.MsgSelectOption;
......
......@@ -2,8 +2,8 @@ import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { AppDispatch } from "../../store";
import MsgSelectPlace = ygopro.StocGameMessage.MsgSelectPlace;
import {
addMonsterPlaceSelectAble,
addMagicPlaceSelectAble,
addMonsterPlaceInteractivities,
addMagicPlaceInteractivities,
} from "../../reducers/duel/mod";
export default (selectPlace: MsgSelectPlace, dispatch: AppDispatch) => {
......@@ -16,12 +16,16 @@ export default (selectPlace: MsgSelectPlace, dispatch: AppDispatch) => {
for (const place of selectPlace.places) {
switch (place.zone) {
case ygopro.CardZone.MZONE: {
dispatch(addMonsterPlaceSelectAble([place.controler, place.sequence]));
dispatch(
addMonsterPlaceInteractivities([place.controler, place.sequence])
);
break;
}
case ygopro.CardZone.SZONE: {
dispatch(addMagicPlaceSelectAble([place.controler, place.sequence]));
dispatch(
addMagicPlaceInteractivities([place.controler, place.sequence])
);
break;
}
......
......@@ -4,7 +4,7 @@ import { store } from "../../store";
import {
selectCardListModalIsOpen,
selectCardListModalInfo,
} from "../../reducers/duel/modalSlice";
} from "../../reducers/duel/modal/mod";
import { setCardListModalIsOpen } from "../../reducers/duel/mod";
import { Modal, List, Popover, Card } from "antd";
......
......@@ -7,10 +7,10 @@ import {
selectCardModalDesc,
selectCardModalImgUrl,
selectCardModalInteractivies,
} from "../../reducers/duel/modalSlice";
} from "../../reducers/duel/modal/mod";
import {
setCardModalIsOpen,
clearHandsInteractivity,
clearHandsIdleInteractivity,
} from "../../reducers/duel/mod";
import { Modal, Card, Button } from "antd";
import { sendSelectIdleCmdResponse } from "../../api/ocgcore/ocgHelper";
......@@ -47,7 +47,7 @@ const CardModal = () => {
onClick={() => {
sendSelectIdleCmdResponse(interactive.response);
dispatch(setCardModalIsOpen(false));
dispatch(clearHandsInteractivity(0));
dispatch(clearHandsIdleInteractivity(0));
}}
>
{interactive.desc}
......
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "../../config/ui";
import { Cemetery } from "../../reducers/duel/util";
import { CardState } from "../../reducers/duel/generic";
import {
selectMeCemetery,
selectOpCemetery,
......@@ -38,7 +38,7 @@ const Cemeteries = () => {
};
const CCemetery = (props: {
state: Cemetery[];
state: CardState[];
position: BABYLON.Vector3;
rotation: BABYLON.Vector3;
}) => {
......@@ -52,9 +52,9 @@ const CCemetery = (props: {
setCardListModalInfo(
props.state.map((cemetery) => {
return {
name: cemetery.meta.text.name,
desc: cemetery.meta.text.desc,
imgUrl: `https://cdn02.moecube.com:444/images/ygopro-images-zh-CN/${cemetery.meta.id}.jpg`,
name: cemetery.occupant?.text.name,
desc: cemetery.occupant?.text.desc,
imgUrl: `https://cdn02.moecube.com:444/images/ygopro-images-zh-CN/${cemetery.occupant?.id}.jpg`,
};
})
)
......
......@@ -8,7 +8,7 @@ import {
selectCheckCardModalMinMax,
selectCheckCardModalOnSubmit,
selectCheckCardModalTags,
} from "../../reducers/duel/modalSlice";
} from "../../reducers/duel/modal/mod";
import {
resetCheckCardModal,
setCheckCardModalIsOpen,
......
......@@ -2,7 +2,7 @@ import * as BABYLON from "@babylonjs/core";
import { useAppSelector } from "../../hook";
import { selectMeHands, selectOpHands } from "../../reducers/duel/handsSlice";
import * as CONFIG from "../../config/ui";
import { Hand } from "../../reducers/duel/util";
import { CardState } from "../../reducers/duel/generic";
import {
setCardModalImgUrl,
setCardModalIsOpen,
......@@ -22,9 +22,9 @@ const handShape = CONFIG.HandShape();
const handRotation = CONFIG.HandRotation();
const Hands = () => {
const meHands = useAppSelector(selectMeHands).cards;
const meHands = useAppSelector(selectMeHands).hands;
const meHandPositions = handPositons(0, meHands);
const opHands = useAppSelector(selectOpHands).cards;
const opHands = useAppSelector(selectOpHands).hands;
const opHandPositions = handPositons(1, opHands);
return (
......@@ -60,7 +60,7 @@ const Hands = () => {
};
const CHand = (props: {
state: Hand;
state: CardState;
sequence: number;
position: BABYLON.Vector3;
rotation: BABYLON.Vector3;
......@@ -108,15 +108,17 @@ const CHand = (props: {
useClick(
() => {
dispatch(setCardModalText([state.meta.text.name, state.meta.text.desc]));
dispatch(
setCardModalText([state.occupant?.text.name, state.occupant?.text.desc])
);
dispatch(
setCardModalImgUrl(
`https://cdn02.moecube.com:444/images/ygopro-images-zh-CN/${state.meta.id}.jpg`
`https://cdn02.moecube.com:444/images/ygopro-images-zh-CN/${state.occupant?.id}.jpg`
)
);
dispatch(
setCardModalInteractivies(
state.interactivities.map((interactive) => {
state.idleInteractivities.map((interactive) => {
return {
desc: interactTypeToString(interactive.interactType),
response: interactive.response,
......@@ -141,19 +143,25 @@ const CHand = (props: {
position={spring.position}
rotation={props.rotation}
enableEdgesRendering
edgesWidth={state.interactivities.length == 0 ? 0 : edgesWidth}
edgesWidth={
state.idleInteractivities.length > 0 || state.placeInteractivities
? edgesWidth
: 0
}
edgesColor={edgesColor}
>
<animated.standardMaterial
name={`hand-mat-${props.sequence}`}
diffuseTexture={new BABYLON.Texture(props.cover(state.meta.id))}
diffuseTexture={
new BABYLON.Texture(props.cover(state.occupant?.id || 0))
}
/>
</animated.plane>
</animated.transformNode>
);
};
const handPositons = (player: number, hands: Hand[]) => {
const handPositons = (player: number, hands: CardState[]) => {
const gap = groundShape.width / (hands.length - 1);
const x = (idx: number) =>
player == 0 ? left + gap * idx : -left - gap * idx;
......
......@@ -2,13 +2,13 @@ import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "../../config/ui";
import { selectMeMagics, selectOpMagics } from "../../reducers/duel/magicSlice";
import { useClick } from "./hook";
import { Magic } from "../../reducers/duel/util";
import { CardState } from "../../reducers/duel/generic";
import { store } from "../../store";
import { useAppSelector } from "../../hook";
import { useRef } from "react";
import { sendSelectPlaceResponse } from "../../api/ocgcore/ocgHelper";
import {
clearMagicSelectInfo,
clearMagicPlaceInteractivities,
setCardModalImgUrl,
setCardModalIsOpen,
setCardModalText,
......@@ -33,7 +33,7 @@ const Magics = () => {
return (
<CMagic
state={magic}
key={magic.sequence}
key={magic.location.sequence}
position={position}
rotation={CONFIG.CardSlotRotation(false)}
/>
......@@ -43,7 +43,7 @@ const Magics = () => {
return (
<CMagic
state={magic}
key={magic.sequence}
key={magic.location.sequence}
position={position}
rotation={CONFIG.CardSlotRotation(true)}
/>
......@@ -54,26 +54,26 @@ const Magics = () => {
};
const CMagic = (props: {
state: Magic;
state: CardState;
position: BABYLON.Vector3;
rotation: BABYLON.Vector3;
}) => {
const state = props.state;
const planeRef = useRef(null);
const faceDown =
state.position === ygopro.CardPosition.FACEDOWN ||
state.position === ygopro.CardPosition.FACEDOWN_ATTACK ||
state.position === ygopro.CardPosition.FACEDOWN_DEFENSE;
state.location.position === ygopro.CardPosition.FACEDOWN ||
state.location.position === ygopro.CardPosition.FACEDOWN_ATTACK ||
state.location.position === ygopro.CardPosition.FACEDOWN_DEFENSE;
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));
if (state.placeInteractivities) {
sendSelectPlaceResponse(state.placeInteractivities.response);
dispatch(clearMagicPlaceInteractivities(0));
dispatch(clearMagicPlaceInteractivities(1));
} else if (state.occupant) {
dispatch(
setCardModalText([state.occupant.text.name, state.occupant.text.desc])
......@@ -92,18 +92,22 @@ const CMagic = (props: {
return (
<plane
name={`magic-${state.sequence}`}
name={`magic-${state.location.sequence}`}
ref={planeRef}
width={shape.width}
height={shape.height}
position={props.position}
rotation={props.rotation}
enableEdgesRendering
edgesWidth={state.selectInfo ? edgesWidth : 0}
edgesWidth={
state.placeInteractivities || state.idleInteractivities.length > 0
? edgesWidth
: 0
}
edgesColor={edgesColor}
>
<standardMaterial
name={`magic-mat-${props.state.sequence}`}
name={`magic-mat-${props.state.location.sequence}`}
diffuseTexture={
state.occupant
? faceDown
......@@ -121,13 +125,15 @@ const CMagic = (props: {
);
};
const magicPositions = (player: number, magics: Magic[]) => {
const magicPositions = (player: number, magics: CardState[]) => {
const x = (sequence: number) =>
player == 0 ? left + gap * sequence : -left - gap * sequence;
const y = shape.depth / 2 + CONFIG.Floating;
const z = player == 0 ? -2.6 : 2.6;
return magics.map((magic) => new BABYLON.Vector3(x(magic.sequence), y, z));
return magics.map(
(magic) => new BABYLON.Vector3(x(magic.location.sequence), y, z)
);
};
export default Magics;
......@@ -2,12 +2,12 @@ import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "../../config/ui";
import { useClick } from "./hook";
import { store } from "../../store";
import { Monster } from "../../reducers/duel/util";
import { CardState } from "../../reducers/duel/generic";
import "react-babylonjs";
import { useRef } from "react";
import { sendSelectPlaceResponse } from "../../api/ocgcore/ocgHelper";
import {
clearMonsterSelectInfo,
clearMonsterPlaceInteractivities,
setCardModalImgUrl,
setCardModalInteractivies,
setCardModalIsOpen,
......@@ -62,7 +62,7 @@ const Monsters = () => {
};
const CommonMonster = (props: {
state: Monster;
state: CardState;
position: BABYLON.Vector3;
rotation: BABYLON.Vector3;
deffenseRotation: BABYLON.Vector3;
......@@ -70,9 +70,9 @@ const CommonMonster = (props: {
const planeRef = useRef(null);
const rotation =
props.state.position === ygopro.CardPosition.DEFENSE ||
props.state.position === ygopro.CardPosition.FACEUP_DEFENSE ||
props.state.position === ygopro.CardPosition.FACEDOWN_DEFENSE
props.state.location.position === ygopro.CardPosition.DEFENSE ||
props.state.location.position === ygopro.CardPosition.FACEUP_DEFENSE ||
props.state.location.position === ygopro.CardPosition.FACEDOWN_DEFENSE
? props.deffenseRotation
: props.rotation;
const edgesWidth = 2.0;
......@@ -80,16 +80,16 @@ const CommonMonster = (props: {
const dispatch = store.dispatch;
const faceDown =
props.state.position === ygopro.CardPosition.FACEDOWN_DEFENSE ||
props.state.position === ygopro.CardPosition.FACEDOWN_ATTACK ||
props.state.position === ygopro.CardPosition.FACEDOWN;
props.state.location.position === ygopro.CardPosition.FACEDOWN_DEFENSE ||
props.state.location.position === ygopro.CardPosition.FACEDOWN_ATTACK ||
props.state.location.position === ygopro.CardPosition.FACEDOWN;
useClick(
(_event) => {
if (props.state.selectInfo) {
sendSelectPlaceResponse(props.state.selectInfo.response);
dispatch(clearMonsterSelectInfo(0));
dispatch(clearMonsterSelectInfo(1));
if (props.state.placeInteractivities) {
sendSelectPlaceResponse(props.state.placeInteractivities.response);
dispatch(clearMonsterPlaceInteractivities(0));
dispatch(clearMonsterPlaceInteractivities(1));
} else if (props.state.occupant) {
dispatch(
setCardModalText([
......@@ -112,18 +112,23 @@ const CommonMonster = (props: {
return (
<plane
name={`monster-${props.state.selectInfo}`}
name={`monster-${props.state.location.sequence}`}
ref={planeRef}
width={shape.width}
height={shape.height}
position={props.position}
rotation={rotation}
enableEdgesRendering
edgesWidth={props.state.selectInfo ? edgesWidth : 0}
edgesWidth={
props.state.placeInteractivities ||
props.state.idleInteractivities.length > 0
? edgesWidth
: 0
}
edgesColor={edgesColor}
>
<standardMaterial
name={`monster-mat-${props.state.sequence}`}
name={`monster-mat-${props.state.location.sequence}`}
diffuseTexture={
props.state.occupant
? faceDown
......@@ -171,14 +176,14 @@ const ExtraMonsters = () => {
);
};
const monsterPositions = (player: number, monsters: Monster[]) => {
const monsterPositions = (player: number, monsters: CardState[]) => {
const x = (sequence: number) =>
player == 0 ? left + gap * sequence : -left - gap * sequence;
const y = shape.depth / 2 + CONFIG.Floating;
const z = player == 0 ? -1.35 : 1.35;
return monsters.map(
(monster) => new BABYLON.Vector3(x(monster.sequence), y, z)
(monster) => new BABYLON.Vector3(x(monster.location.sequence), y, z)
);
};
......
......@@ -6,7 +6,7 @@ import { CheckCard } from "@ant-design/pro-components";
import {
selectOptionModalIsOpen,
selectOptionModalOptions,
} from "../../reducers/duel/modalSlice";
} from "../../reducers/duel/modal/mod";
import { sendSelectOptionResponse } from "../../api/ocgcore/ocgHelper";
import {
resetOptionModal,
......
......@@ -6,7 +6,7 @@ import { sendSelectPositionResponse } from "../../api/ocgcore/ocgHelper";
import {
selectPositionModalIsOpen,
selectPositionModalPositions,
} from "../../reducers/duel/modalSlice";
} from "../../reducers/duel/modal/mod";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import {
resetPositionModal,
......
import { InteractType } from "../../reducers/duel/util";
import { InteractType } from "../../reducers/duel/generic";
export function zip<S1, S2>(
firstCollection: Array<S1>,
......
......@@ -6,7 +6,7 @@ import { sendSelectEffectYnResponse } from "../../api/ocgcore/ocgHelper";
import {
selectYesNoModalIsOpen,
selectYesNOModalMsg,
} from "../../reducers/duel/modalSlice";
} from "../../reducers/duel/modal/mod";
import { setYesNoModalIsOpen } from "../../reducers/duel/mod";
const YesNoModal = () => {
......
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