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;
const OFFSET_UINT16 = 2;
const OFFSET_UINT32 = 4;
const OFFSET_INT32 = 4;
const LOCATION_OVERLAY = 0x80;
export class BufferReader {
dataView: DataView;
......@@ -67,28 +68,28 @@ export class BufferReader {
});
}
readCardLocation(overlay?: boolean): ygopro.CardLocation {
readCardLocation(): ygopro.CardLocation {
const controler = this.readUint8();
const location = this.readUint8();
const sequence = this.readUint8();
const ss = this.readUint8();
const cardLocation = new ygopro.CardLocation({
controler,
location: numberToCardZone(location),
sequence,
});
if (overlay && overlay) {
cardLocation.overlay_sequence = ss;
if (location & LOCATION_OVERLAY) {
// 超量素材
return new ygopro.CardLocation({
controler,
location: ygopro.CardZone.OVERLAY,
sequence,
overlay_sequence: ss,
});
} else {
const position = numberToCardPosition(ss);
if (position) {
cardLocation.position = position;
}
return new ygopro.CardLocation({
controler,
location: numberToCardZone(location),
sequence,
position: numberToCardPosition(ss),
});
}
return cardLocation;
}
}
......
......@@ -29,6 +29,7 @@ export interface CardState {
zone: ygopro.CardZone;
sequence: number;
}>; // 选择位置状态下的互动信息
overlay_materials?: CardMeta[]; // 超量素材
}
export enum InteractType {
......@@ -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>(
state: T | undefined,
sequence: number,
......
......@@ -63,6 +63,7 @@ import {
clearMonsterIdleInteractivitiesImpl,
removeMonsterImpl,
setMonsterPositionImpl,
removeOverlayImpl,
monsterCase,
} from "./monstersSlice";
import {
......@@ -185,6 +186,7 @@ const duelSlice = createSlice({
clearMonsterIdleInteractivities: clearMonsterIdleInteractivitiesImpl,
setMonsterPosition: setMonsterPositionImpl,
removeMonster: removeMonsterImpl,
removeOverlay: removeOverlayImpl,
// 魔法陷阱区相关`Reducer`
initMagics: initMagicsImpl,
......@@ -285,6 +287,7 @@ export const {
clearMonsterIdleInteractivities,
setMonsterPosition,
removeMonster,
removeOverlay,
initMagics,
addMagicPlaceInteractivities,
clearMagicPlaceInteractivities,
......
......@@ -3,6 +3,7 @@ import {
PayloadAction,
CaseReducer,
ActionReducerMapBuilder,
createAsyncThunk,
} from "@reduxjs/toolkit";
import { DuelState } from "./mod";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
......@@ -18,7 +19,9 @@ import {
extendIdleInteractivities,
clearIdleInteractivities,
setPosition,
removeOverlay,
} from "./generic";
import { fetchCard } from "../../api/cards";
export interface MonsterState extends DuelFieldState {}
......@@ -159,6 +162,34 @@ export const clearMonsterIdleInteractivitiesImpl: CaseReducer<
// 增加怪兽
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>) => {
builder.addCase(fetchMonsterMeta.pending, (state, action) => {
// Meta结果没返回之前先更新`ID`
......@@ -185,6 +216,53 @@ export const monsterCase = (builder: ActionReducerMapBuilder<DuelState>) => {
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<
: state.opMonsters;
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 MsgMove = ygopro.StocGameMessage.MsgMove;
import { AppDispatch } from "../../store";
import { fetchMonsterMeta } from "../../reducers/duel/monstersSlice";
import {
fetchMonsterMeta,
fetchOverlayMeta,
} from "../../reducers/duel/monstersSlice";
import {
removeCemetery,
removeExclusion,
......@@ -9,6 +12,7 @@ import {
removeHand,
removeMagic,
removeMonster,
removeOverlay,
} from "../../reducers/duel/mod";
import { fetchMagicMeta } from "../../reducers/duel/magicSlice";
import { fetchCemeteryMeta } from "../../reducers/duel/cemeretySlice";
......@@ -16,6 +20,8 @@ import { insertHandMeta } from "../../reducers/duel/handsSlice";
import { fetchExclusionMeta } from "../../reducers/duel/exclusionSlice";
import { fetchExtraDeckMeta } from "../../reducers/duel/extraDeckSlice";
const OVERLAY_STACK: { code: number; sequence: number }[] = [];
export default (move: MsgMove, dispatch: AppDispatch) => {
const code = move.code;
const from = move.from;
......@@ -63,6 +69,17 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
break;
}
case ygopro.CardZone.OVERLAY: {
dispatch(
removeOverlay({
controler: from.controler,
sequence: from.sequence,
overlaySequence: from.overlay_sequence,
})
);
break;
}
default: {
console.log(`Unhandled zone type ${from.location}`);
break;
......@@ -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;
}
case ygopro.CardZone.SZONE: {
......@@ -134,6 +164,25 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
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: {
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