Commit 86ee4f20 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/overlay' into 'main'

Feat/overlay

See merge request mycard/Neos!99
parents 414cfd54 96f67f7c
Pipeline #20051 passed with stages
in 5 minutes and 1 second
...@@ -6,6 +6,7 @@ const OFFSET_INT8 = 1; ...@@ -6,6 +6,7 @@ const OFFSET_INT8 = 1;
const OFFSET_UINT16 = 2; const OFFSET_UINT16 = 2;
const OFFSET_UINT32 = 4; const OFFSET_UINT32 = 4;
const OFFSET_INT32 = 4; const OFFSET_INT32 = 4;
const LOCATION_OVERLAY = 0x80;
export class BufferReader { export class BufferReader {
dataView: DataView; dataView: DataView;
...@@ -67,28 +68,28 @@ export class BufferReader { ...@@ -67,28 +68,28 @@ export class BufferReader {
}); });
} }
readCardLocation(overlay?: boolean): ygopro.CardLocation { readCardLocation(): ygopro.CardLocation {
const controler = this.readUint8(); const controler = this.readUint8();
const location = this.readUint8(); const location = this.readUint8();
const sequence = this.readUint8(); const sequence = this.readUint8();
const ss = this.readUint8(); const ss = this.readUint8();
const cardLocation = new ygopro.CardLocation({ if (location & LOCATION_OVERLAY) {
controler, // 超量素材
location: numberToCardZone(location), return new ygopro.CardLocation({
sequence, controler,
}); location: ygopro.CardZone.OVERLAY,
sequence,
if (overlay && overlay) { overlay_sequence: ss,
cardLocation.overlay_sequence = ss; });
} else { } else {
const position = numberToCardPosition(ss); return new ygopro.CardLocation({
if (position) { controler,
cardLocation.position = position; location: numberToCardZone(location),
} sequence,
position: numberToCardPosition(ss),
});
} }
return cardLocation;
} }
} }
......
...@@ -29,6 +29,7 @@ export interface CardState { ...@@ -29,6 +29,7 @@ export interface CardState {
zone: ygopro.CardZone; zone: ygopro.CardZone;
sequence: number; sequence: number;
}>; // 选择位置状态下的互动信息 }>; // 选择位置状态下的互动信息
overlay_materials?: CardMeta[]; // 超量素材
} }
export enum InteractType { export enum InteractType {
...@@ -212,6 +213,18 @@ export function removeOccupant<T extends DuelFieldState>( ...@@ -212,6 +213,18 @@ export function removeOccupant<T extends DuelFieldState>(
} }
} }
export function removeOverlay<T extends DuelFieldState>(
state: T | undefined,
sequence: number
) {
if (state) {
const target = state.inner.find((_, idx) => idx == sequence);
if (target) {
target.overlay_materials = [];
}
}
}
export function insertCard<T extends DuelFieldState>( export function insertCard<T extends DuelFieldState>(
state: T | undefined, state: T | undefined,
sequence: number, sequence: number,
......
...@@ -63,6 +63,7 @@ import { ...@@ -63,6 +63,7 @@ import {
clearMonsterIdleInteractivitiesImpl, clearMonsterIdleInteractivitiesImpl,
removeMonsterImpl, removeMonsterImpl,
setMonsterPositionImpl, setMonsterPositionImpl,
removeOverlayImpl,
monsterCase, monsterCase,
} from "./monstersSlice"; } from "./monstersSlice";
import { import {
...@@ -185,6 +186,7 @@ const duelSlice = createSlice({ ...@@ -185,6 +186,7 @@ const duelSlice = createSlice({
clearMonsterIdleInteractivities: clearMonsterIdleInteractivitiesImpl, clearMonsterIdleInteractivities: clearMonsterIdleInteractivitiesImpl,
setMonsterPosition: setMonsterPositionImpl, setMonsterPosition: setMonsterPositionImpl,
removeMonster: removeMonsterImpl, removeMonster: removeMonsterImpl,
removeOverlay: removeOverlayImpl,
// 魔法陷阱区相关`Reducer` // 魔法陷阱区相关`Reducer`
initMagics: initMagicsImpl, initMagics: initMagicsImpl,
...@@ -285,6 +287,7 @@ export const { ...@@ -285,6 +287,7 @@ export const {
clearMonsterIdleInteractivities, clearMonsterIdleInteractivities,
setMonsterPosition, setMonsterPosition,
removeMonster, removeMonster,
removeOverlay,
initMagics, initMagics,
addMagicPlaceInteractivities, addMagicPlaceInteractivities,
clearMagicPlaceInteractivities, clearMagicPlaceInteractivities,
......
...@@ -3,6 +3,7 @@ import { ...@@ -3,6 +3,7 @@ import {
PayloadAction, PayloadAction,
CaseReducer, CaseReducer,
ActionReducerMapBuilder, ActionReducerMapBuilder,
createAsyncThunk,
} from "@reduxjs/toolkit"; } from "@reduxjs/toolkit";
import { DuelState } from "./mod"; import { DuelState } from "./mod";
import { ygopro } from "../../api/ocgcore/idl/ocgcore"; import { ygopro } from "../../api/ocgcore/idl/ocgcore";
...@@ -18,7 +19,9 @@ import { ...@@ -18,7 +19,9 @@ import {
extendIdleInteractivities, extendIdleInteractivities,
clearIdleInteractivities, clearIdleInteractivities,
setPosition, setPosition,
removeOverlay,
} from "./generic"; } from "./generic";
import { fetchCard } from "../../api/cards";
export interface MonsterState extends DuelFieldState {} export interface MonsterState extends DuelFieldState {}
...@@ -159,6 +162,34 @@ export const clearMonsterIdleInteractivitiesImpl: CaseReducer< ...@@ -159,6 +162,34 @@ export const clearMonsterIdleInteractivitiesImpl: CaseReducer<
// 增加怪兽 // 增加怪兽
export const fetchMonsterMeta = createAsyncMetaThunk("duel/fetchMonsterMeta"); export const fetchMonsterMeta = createAsyncMetaThunk("duel/fetchMonsterMeta");
// 增加怪兽的超量素材
export const fetchOverlayMeta = createAsyncThunk(
"duel/fetchOverlayMeta",
async (param: {
controler: number;
sequence: number;
overlayCodes: number[];
append?: boolean;
}) => {
const controler = param.controler;
const sequence = param.sequence;
const overlayCodes = param.overlayCodes;
const metas = await Promise.all(
overlayCodes.map(async (id) => {
if (id == 0) {
return { id, data: {}, text: {} };
} else {
return await fetchCard(id, true);
}
})
);
const response = { controler, sequence, metas };
return response;
}
);
export const monsterCase = (builder: ActionReducerMapBuilder<DuelState>) => { export const monsterCase = (builder: ActionReducerMapBuilder<DuelState>) => {
builder.addCase(fetchMonsterMeta.pending, (state, action) => { builder.addCase(fetchMonsterMeta.pending, (state, action) => {
// Meta结果没返回之前先更新`ID` // Meta结果没返回之前先更新`ID`
...@@ -185,6 +216,53 @@ export const monsterCase = (builder: ActionReducerMapBuilder<DuelState>) => { ...@@ -185,6 +216,53 @@ export const monsterCase = (builder: ActionReducerMapBuilder<DuelState>) => {
extendOccupant(state.opMonsters, meta, sequence); extendOccupant(state.opMonsters, meta, sequence);
} }
}); });
builder.addCase(fetchOverlayMeta.pending, (state, action) => {
// Meta结果没返回之前先更新`ID`
const controler = action.meta.arg.controler;
const sequence = action.meta.arg.sequence;
const overlayCodes = action.meta.arg.overlayCodes;
const append = action.meta.arg.append;
const metas = overlayCodes.map((id) => {
return { id, data: {}, text: {} };
});
const monsters = judgeSelf(controler, state)
? state.meMonsters
: state.opMonsters;
if (monsters) {
const target = monsters.inner.find((_, idx) => idx == sequence);
if (target && target.occupant) {
if (append) {
target.overlay_materials = (target.overlay_materials || []).concat(
metas
);
} else {
target.overlay_materials = metas;
}
}
}
});
builder.addCase(fetchOverlayMeta.fulfilled, (state, action) => {
const controler = action.payload.controler;
const sequence = action.payload.sequence;
const overlayMetas = action.payload.metas;
const monsters = judgeSelf(controler, state)
? state.meMonsters
: state.opMonsters;
if (monsters) {
const target = monsters.inner.find((_, idx) => idx == sequence);
for (const meta of overlayMetas) {
for (const overlay of target?.overlay_materials || []) {
if (meta.id == overlay.id) {
overlay.data = meta.data;
overlay.text = meta.text;
}
}
}
}
});
}; };
// 删除怪兽 // 删除怪兽
...@@ -199,6 +277,33 @@ export const removeMonsterImpl: CaseReducer< ...@@ -199,6 +277,33 @@ export const removeMonsterImpl: CaseReducer<
: state.opMonsters; : state.opMonsters;
removeOccupant(monsters, action.payload.sequence); removeOccupant(monsters, action.payload.sequence);
removeOverlay(monsters, action.payload.sequence);
};
// 删除超量素材
export const removeOverlayImpl: CaseReducer<
DuelState,
PayloadAction<{
controler: number;
sequence: number;
overlaySequence: number;
}>
> = (state, action) => {
const controler = action.payload.controler;
const sequence = action.payload.sequence;
const overlaySequence = action.payload.overlaySequence;
const monsters = judgeSelf(controler, state)
? state.meMonsters
: state.opMonsters;
if (monsters) {
const target = monsters.inner.find((_, idx) => idx == sequence);
if (target && target.overlay_materials) {
target.overlay_materials = target.overlay_materials.filter(
(_, idx) => idx != overlaySequence
);
}
}
}; };
// 改变怪兽表示形式 // 改变怪兽表示形式
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore"; import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import MsgMove = ygopro.StocGameMessage.MsgMove; import MsgMove = ygopro.StocGameMessage.MsgMove;
import { AppDispatch } from "../../store"; import { AppDispatch } from "../../store";
import { fetchMonsterMeta } from "../../reducers/duel/monstersSlice"; import {
fetchMonsterMeta,
fetchOverlayMeta,
} from "../../reducers/duel/monstersSlice";
import { import {
removeCemetery, removeCemetery,
removeExclusion, removeExclusion,
...@@ -9,6 +12,7 @@ import { ...@@ -9,6 +12,7 @@ import {
removeHand, removeHand,
removeMagic, removeMagic,
removeMonster, removeMonster,
removeOverlay,
} from "../../reducers/duel/mod"; } from "../../reducers/duel/mod";
import { fetchMagicMeta } from "../../reducers/duel/magicSlice"; import { fetchMagicMeta } from "../../reducers/duel/magicSlice";
import { fetchCemeteryMeta } from "../../reducers/duel/cemeretySlice"; import { fetchCemeteryMeta } from "../../reducers/duel/cemeretySlice";
...@@ -16,6 +20,8 @@ import { insertHandMeta } from "../../reducers/duel/handsSlice"; ...@@ -16,6 +20,8 @@ import { insertHandMeta } from "../../reducers/duel/handsSlice";
import { fetchExclusionMeta } from "../../reducers/duel/exclusionSlice"; import { fetchExclusionMeta } from "../../reducers/duel/exclusionSlice";
import { fetchExtraDeckMeta } from "../../reducers/duel/extraDeckSlice"; import { fetchExtraDeckMeta } from "../../reducers/duel/extraDeckSlice";
const OVERLAY_STACK: { code: number; sequence: number }[] = [];
export default (move: MsgMove, dispatch: AppDispatch) => { export default (move: MsgMove, dispatch: AppDispatch) => {
const code = move.code; const code = move.code;
const from = move.from; const from = move.from;
...@@ -63,6 +69,17 @@ export default (move: MsgMove, dispatch: AppDispatch) => { ...@@ -63,6 +69,17 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
break; break;
} }
case ygopro.CardZone.OVERLAY: {
dispatch(
removeOverlay({
controler: from.controler,
sequence: from.sequence,
overlaySequence: from.overlay_sequence,
})
);
break;
}
default: { default: {
console.log(`Unhandled zone type ${from.location}`); console.log(`Unhandled zone type ${from.location}`);
break; break;
...@@ -80,6 +97,19 @@ export default (move: MsgMove, dispatch: AppDispatch) => { ...@@ -80,6 +97,19 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
}) })
); );
// 处理超量素材
const overlayMetarials = OVERLAY_STACK.splice(0, OVERLAY_STACK.length);
let sorted = overlayMetarials
.sort((a, b) => a.sequence - b.sequence)
.map((overlay) => overlay.code);
dispatch(
fetchOverlayMeta({
controler: to.controler,
sequence: to.sequence,
overlayCodes: sorted,
})
);
break; break;
} }
case ygopro.CardZone.SZONE: { case ygopro.CardZone.SZONE: {
...@@ -134,6 +164,25 @@ export default (move: MsgMove, dispatch: AppDispatch) => { ...@@ -134,6 +164,25 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
break; break;
} }
case ygopro.CardZone.OVERLAY: {
if (to.sequence > 6) {
// 超量素材在进行超量召唤时,若玩家未选择超量怪兽的位置,会“沉到决斗盘下面”,这时候素材们的sequence会暂时大于6
// 这时候将它们放到一个栈中,待超量怪兽的Move消息到来时从栈中获取超量素材补充到状态中
OVERLAY_STACK.push({ code, sequence: to.overlay_sequence });
} else {
// 其他情况下,比如“宵星的机神 丁吉尔苏”的“补充超量素材”效果,直接更新状态中
dispatch(
fetchOverlayMeta({
controler: to.controler,
sequence: to.sequence,
overlayCodes: [code],
append: true,
})
);
}
break;
}
default: { default: {
console.log(`Unhandled zone type ${to.location}`); console.log(`Unhandled zone type ${to.location}`);
......
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