Commit 451e94e1 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/service/move' into 'main'

Feat/service/move

See merge request mycard/Neos!54
parents 890d930a cdf8a91f
neos-protobuf @ 621489ac
Subproject commit 8cfeb7ac4563b27f2f56e36b53b1453a953d9a9c
Subproject commit 621489ace4b9d2ecb653fe0da25279b68154d206
......@@ -18,6 +18,16 @@ export namespace ygopro {
FZONE = 9,
PZONE = 10,
}
export enum CardPosition {
FACEUP_ATTACK = 0,
FACEDOWN_ATTACK = 1,
FACEUP_DEFENSE = 2,
FACEDOWN_DEFENSE = 3,
FACEUP = 4,
FACEDOWN = 5,
ATTACK = 6,
DEFENSE = 7,
}
export enum HandType {
UNKNOWN = 0,
SCISSORS = 1,
......@@ -170,6 +180,180 @@ export namespace ygopro {
return CardInfo.deserialize(bytes);
}
}
export class CardLocation extends pb_1.Message {
#one_of_decls: number[][] = [];
constructor(
data?:
| any[]
| {
controler?: number;
location?: number;
sequence?: number;
position?: CardPosition;
overlay_sequence?: number;
}
) {
super();
pb_1.Message.initialize(
this,
Array.isArray(data) ? data : [],
0,
-1,
[],
this.#one_of_decls
);
if (!Array.isArray(data) && typeof data == "object") {
if ("controler" in data && data.controler != undefined) {
this.controler = data.controler;
}
if ("location" in data && data.location != undefined) {
this.location = data.location;
}
if ("sequence" in data && data.sequence != undefined) {
this.sequence = data.sequence;
}
if ("position" in data && data.position != undefined) {
this.position = data.position;
}
if ("overlay_sequence" in data && data.overlay_sequence != undefined) {
this.overlay_sequence = data.overlay_sequence;
}
}
}
get controler() {
return pb_1.Message.getFieldWithDefault(this, 1, 0) as number;
}
set controler(value: number) {
pb_1.Message.setField(this, 1, value);
}
get location() {
return pb_1.Message.getFieldWithDefault(this, 2, 0) as number;
}
set location(value: number) {
pb_1.Message.setField(this, 2, value);
}
get sequence() {
return pb_1.Message.getFieldWithDefault(this, 3, 0) as number;
}
set sequence(value: number) {
pb_1.Message.setField(this, 3, value);
}
get position() {
return pb_1.Message.getFieldWithDefault(
this,
4,
CardPosition.FACEUP_ATTACK
) as CardPosition;
}
set position(value: CardPosition) {
pb_1.Message.setField(this, 4, value);
}
get overlay_sequence() {
return pb_1.Message.getFieldWithDefault(this, 5, 0) as number;
}
set overlay_sequence(value: number) {
pb_1.Message.setField(this, 5, value);
}
static fromObject(data: {
controler?: number;
location?: number;
sequence?: number;
position?: CardPosition;
overlay_sequence?: number;
}): CardLocation {
const message = new CardLocation({});
if (data.controler != null) {
message.controler = data.controler;
}
if (data.location != null) {
message.location = data.location;
}
if (data.sequence != null) {
message.sequence = data.sequence;
}
if (data.position != null) {
message.position = data.position;
}
if (data.overlay_sequence != null) {
message.overlay_sequence = data.overlay_sequence;
}
return message;
}
toObject() {
const data: {
controler?: number;
location?: number;
sequence?: number;
position?: CardPosition;
overlay_sequence?: number;
} = {};
if (this.controler != null) {
data.controler = this.controler;
}
if (this.location != null) {
data.location = this.location;
}
if (this.sequence != null) {
data.sequence = this.sequence;
}
if (this.position != null) {
data.position = this.position;
}
if (this.overlay_sequence != null) {
data.overlay_sequence = this.overlay_sequence;
}
return data;
}
serialize(): Uint8Array;
serialize(w: pb_1.BinaryWriter): void;
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
const writer = w || new pb_1.BinaryWriter();
if (this.controler != 0) writer.writeInt32(1, this.controler);
if (this.location != 0) writer.writeInt32(2, this.location);
if (this.sequence != 0) writer.writeInt32(3, this.sequence);
if (this.position != CardPosition.FACEUP_ATTACK)
writer.writeEnum(4, this.position);
if (this.overlay_sequence != 0)
writer.writeInt32(5, this.overlay_sequence);
if (!w) return writer.getResultBuffer();
}
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): CardLocation {
const reader =
bytes instanceof pb_1.BinaryReader
? bytes
: new pb_1.BinaryReader(bytes),
message = new CardLocation();
while (reader.nextField()) {
if (reader.isEndGroup()) break;
switch (reader.getFieldNumber()) {
case 1:
message.controler = reader.readInt32();
break;
case 2:
message.location = reader.readInt32();
break;
case 3:
message.sequence = reader.readInt32();
break;
case 4:
message.position = reader.readEnum();
break;
case 5:
message.overlay_sequence = reader.readInt32();
break;
default:
reader.skipField();
}
}
return message;
}
serializeBinary(): Uint8Array {
return this.serialize();
}
static deserializeBinary(bytes: Uint8Array): CardLocation {
return CardLocation.deserialize(bytes);
}
}
export class YgoCtosMsg extends pb_1.Message {
#one_of_decls: number[][] = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]];
constructor(
......@@ -3979,7 +4163,7 @@ export namespace ygopro {
}
}
export class StocGameMessage extends pb_1.Message {
#one_of_decls: number[][] = [[1, 2, 3, 4, 5, 6, 7]];
#one_of_decls: number[][] = [[1, 2, 3, 4, 5, 6, 7, 8]];
constructor(
data?:
| any[]
......@@ -3992,6 +4176,7 @@ export namespace ygopro {
hint?: never;
select_idle_cmd?: never;
select_place?: never;
move?: never;
}
| {
start?: never;
......@@ -4001,6 +4186,7 @@ export namespace ygopro {
hint?: never;
select_idle_cmd?: never;
select_place?: never;
move?: never;
}
| {
start?: never;
......@@ -4010,6 +4196,7 @@ export namespace ygopro {
hint?: never;
select_idle_cmd?: never;
select_place?: never;
move?: never;
}
| {
start?: never;
......@@ -4019,6 +4206,7 @@ export namespace ygopro {
hint?: never;
select_idle_cmd?: never;
select_place?: never;
move?: never;
}
| {
start?: never;
......@@ -4028,6 +4216,7 @@ export namespace ygopro {
hint?: StocGameMessage.MsgHint;
select_idle_cmd?: never;
select_place?: never;
move?: never;
}
| {
start?: never;
......@@ -4037,6 +4226,7 @@ export namespace ygopro {
hint?: never;
select_idle_cmd?: StocGameMessage.MsgSelectIdleCmd;
select_place?: never;
move?: never;
}
| {
start?: never;
......@@ -4046,6 +4236,17 @@ export namespace ygopro {
hint?: never;
select_idle_cmd?: never;
select_place?: StocGameMessage.MsgSelectPlace;
move?: never;
}
| {
start?: never;
draw?: never;
new_turn?: never;
new_phase?: never;
hint?: never;
select_idle_cmd?: never;
select_place?: never;
move?: StocGameMessage.MsgMove;
}
))
) {
......@@ -4080,6 +4281,9 @@ export namespace ygopro {
if ("select_place" in data && data.select_place != undefined) {
this.select_place = data.select_place;
}
if ("move" in data && data.move != undefined) {
this.move = data.move;
}
}
}
get start() {
......@@ -4173,6 +4377,19 @@ export namespace ygopro {
get has_select_place() {
return pb_1.Message.getField(this, 7) != null;
}
get move() {
return pb_1.Message.getWrapperField(
this,
StocGameMessage.MsgMove,
8
) as StocGameMessage.MsgMove;
}
set move(value: StocGameMessage.MsgMove) {
pb_1.Message.setOneofWrapperField(this, 8, this.#one_of_decls[0], value);
}
get has_move() {
return pb_1.Message.getField(this, 8) != null;
}
get gameMsg() {
const cases: {
[index: number]:
......@@ -4183,7 +4400,8 @@ export namespace ygopro {
| "new_phase"
| "hint"
| "select_idle_cmd"
| "select_place";
| "select_place"
| "move";
} = {
0: "none",
1: "start",
......@@ -4193,8 +4411,11 @@ export namespace ygopro {
5: "hint",
6: "select_idle_cmd",
7: "select_place",
8: "move",
};
return cases[pb_1.Message.computeOneofCase(this, [1, 2, 3, 4, 5, 6, 7])];
return cases[
pb_1.Message.computeOneofCase(this, [1, 2, 3, 4, 5, 6, 7, 8])
];
}
static fromObject(data: {
start?: ReturnType<typeof StocGameMessage.MsgStart.prototype.toObject>;
......@@ -4212,6 +4433,7 @@ export namespace ygopro {
select_place?: ReturnType<
typeof StocGameMessage.MsgSelectPlace.prototype.toObject
>;
move?: ReturnType<typeof StocGameMessage.MsgMove.prototype.toObject>;
}): StocGameMessage {
const message = new StocGameMessage({});
if (data.start != null) {
......@@ -4241,6 +4463,9 @@ export namespace ygopro {
data.select_place
);
}
if (data.move != null) {
message.move = StocGameMessage.MsgMove.fromObject(data.move);
}
return message;
}
toObject() {
......@@ -4260,6 +4485,7 @@ export namespace ygopro {
select_place?: ReturnType<
typeof StocGameMessage.MsgSelectPlace.prototype.toObject
>;
move?: ReturnType<typeof StocGameMessage.MsgMove.prototype.toObject>;
} = {};
if (this.start != null) {
data.start = this.start.toObject();
......@@ -4282,6 +4508,9 @@ export namespace ygopro {
if (this.select_place != null) {
data.select_place = this.select_place.toObject();
}
if (this.move != null) {
data.move = this.move.toObject();
}
return data;
}
serialize(): Uint8Array;
......@@ -4310,6 +4539,8 @@ export namespace ygopro {
writer.writeMessage(7, this.select_place, () =>
this.select_place.serialize(writer)
);
if (this.has_move)
writer.writeMessage(8, this.move, () => this.move.serialize(writer));
if (!w) return writer.getResultBuffer();
}
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): StocGameMessage {
......@@ -4372,6 +4603,12 @@ export namespace ygopro {
StocGameMessage.MsgSelectPlace.deserialize(reader))
);
break;
case 8:
reader.readMessage(
message.move,
() => (message.move = StocGameMessage.MsgMove.deserialize(reader))
);
break;
default:
reader.skipField();
}
......@@ -5835,5 +6072,173 @@ export namespace ygopro {
}
}
}
export class MsgMove extends pb_1.Message {
#one_of_decls: number[][] = [];
constructor(
data?:
| any[]
| {
code?: number;
from?: CardLocation;
to?: CardLocation;
reason?: number;
}
) {
super();
pb_1.Message.initialize(
this,
Array.isArray(data) ? data : [],
0,
-1,
[],
this.#one_of_decls
);
if (!Array.isArray(data) && typeof data == "object") {
if ("code" in data && data.code != undefined) {
this.code = data.code;
}
if ("from" in data && data.from != undefined) {
this.from = data.from;
}
if ("to" in data && data.to != undefined) {
this.to = data.to;
}
if ("reason" in data && data.reason != undefined) {
this.reason = data.reason;
}
}
}
get code() {
return pb_1.Message.getFieldWithDefault(this, 1, 0) as number;
}
set code(value: number) {
pb_1.Message.setField(this, 1, value);
}
get from() {
return pb_1.Message.getWrapperField(
this,
CardLocation,
2
) as CardLocation;
}
set from(value: CardLocation) {
pb_1.Message.setWrapperField(this, 2, value);
}
get has_from() {
return pb_1.Message.getField(this, 2) != null;
}
get to() {
return pb_1.Message.getWrapperField(
this,
CardLocation,
3
) as CardLocation;
}
set to(value: CardLocation) {
pb_1.Message.setWrapperField(this, 3, value);
}
get has_to() {
return pb_1.Message.getField(this, 3) != null;
}
get reason() {
return pb_1.Message.getFieldWithDefault(this, 4, 0) as number;
}
set reason(value: number) {
pb_1.Message.setField(this, 4, value);
}
static fromObject(data: {
code?: number;
from?: ReturnType<typeof CardLocation.prototype.toObject>;
to?: ReturnType<typeof CardLocation.prototype.toObject>;
reason?: number;
}): MsgMove {
const message = new MsgMove({});
if (data.code != null) {
message.code = data.code;
}
if (data.from != null) {
message.from = CardLocation.fromObject(data.from);
}
if (data.to != null) {
message.to = CardLocation.fromObject(data.to);
}
if (data.reason != null) {
message.reason = data.reason;
}
return message;
}
toObject() {
const data: {
code?: number;
from?: ReturnType<typeof CardLocation.prototype.toObject>;
to?: ReturnType<typeof CardLocation.prototype.toObject>;
reason?: number;
} = {};
if (this.code != null) {
data.code = this.code;
}
if (this.from != null) {
data.from = this.from.toObject();
}
if (this.to != null) {
data.to = this.to.toObject();
}
if (this.reason != null) {
data.reason = this.reason;
}
return data;
}
serialize(): Uint8Array;
serialize(w: pb_1.BinaryWriter): void;
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
const writer = w || new pb_1.BinaryWriter();
if (this.code != 0) writer.writeInt32(1, this.code);
if (this.has_from)
writer.writeMessage(2, this.from, () => this.from.serialize(writer));
if (this.has_to)
writer.writeMessage(3, this.to, () => this.to.serialize(writer));
if (this.reason != 0) writer.writeInt32(4, this.reason);
if (!w) return writer.getResultBuffer();
}
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): MsgMove {
const reader =
bytes instanceof pb_1.BinaryReader
? bytes
: new pb_1.BinaryReader(bytes),
message = new MsgMove();
while (reader.nextField()) {
if (reader.isEndGroup()) break;
switch (reader.getFieldNumber()) {
case 1:
message.code = reader.readInt32();
break;
case 2:
reader.readMessage(
message.from,
() => (message.from = CardLocation.deserialize(reader))
);
break;
case 3:
reader.readMessage(
message.to,
() => (message.to = CardLocation.deserialize(reader))
);
break;
case 4:
message.reason = reader.readInt32();
break;
default:
reader.skipField();
}
}
return message;
}
serializeBinary(): Uint8Array {
return this.serialize();
}
static deserializeBinary(bytes: Uint8Array): MsgMove {
return MsgMove.deserialize(bytes);
}
}
}
}
......@@ -33,3 +33,4 @@ export const MSG_NEW_PHASE = 41;
export const MSG_HINT = 2;
export const MSG_SELECT_IDLE_CMD = 11;
export const MSG_SELECT_PLACE = 18;
export const MSG_MOVE = 50;
......@@ -13,6 +13,7 @@ import MsgNewPhaseAdapter from "./newPhase";
import MsgHintAdapter from "./hint";
import MsgSelectIdleCmdAdapter from "./selectIdleCmd";
import MsgSelectPlaceAdapter from "./selectPlace";
import MsgMoveAdapter from "./move";
/*
* STOC GameMsg
......@@ -73,6 +74,11 @@ export default class GameMsgAdapter implements StocAdapter {
break;
}
case GAME_MSG.MSG_MOVE: {
gameMsg.move = MsgMoveAdapter(gameData);
break;
}
default: {
console.log("Unhandled GameMessage function=", func);
......
import { ygopro } from "../../../idl/ocgcore";
import { BufferReader } from "../../bufferIO";
import { cardZoneToNumber, numberToCardZone } from "../../util";
import MsgMove = ygopro.StocGameMessage.MsgMove;
/*
* Msg Move
* @param - TODO
*
* @usage - 服务端告知前端/客户端卡牌移动信息
* */
export default (data: Uint8Array) => {
const reader = new BufferReader(data, true);
const code = reader.readUint32();
const readCardLocation = () => {
const controler = reader.readUint8();
const location = reader.readUint8();
const sequence = reader.readUint8();
const ss = reader.readUint8();
const cardLocation = new ygopro.CardLocation({
controler,
location: numberToCardZone(location),
sequence,
});
if (location != cardZoneToNumber(ygopro.CardZone.OVERLAY)) {
cardLocation.position = ss;
} else {
cardLocation.overlay_sequence = ss;
}
return cardLocation;
};
const fromLocation = readCardLocation();
const toLocation = readCardLocation();
return new MsgMove({
code,
from: fromLocation,
to: toLocation,
reason: reader.readUint8(),
});
};
......@@ -113,3 +113,46 @@ export function cardZoneToNumber(zone: ygopro.CardZone): number {
}
}
}
export function numberToCardZone(
location: number
): ygopro.CardZone | undefined {
switch (location) {
case 0x01: {
return ygopro.CardZone.DECK;
}
case 0x02: {
return ygopro.CardZone.HAND;
}
case 0x04: {
return ygopro.CardZone.MZONE;
}
case 0x08: {
return ygopro.CardZone.SZONE;
}
case 0x10: {
return ygopro.CardZone.GRAVE;
}
case 0x20: {
return ygopro.CardZone.REMOVED;
}
case 0x40: {
return ygopro.CardZone.EXTRA;
}
case 0x80: {
return ygopro.CardZone.OVERLAY;
}
case 0x0c: {
return ygopro.CardZone.ONFIELD;
}
case 0x100: {
return ygopro.CardZone.FZONE;
}
case 0x200: {
return ygopro.CardZone.PZONE;
}
default: {
return undefined;
}
}
}
......@@ -7,12 +7,12 @@ import {
import { DuelState } from "./mod";
import { RootState } from "../../store";
import { fetchCard, CardMeta } from "../../api/cards";
import { judgeSelf, Card, Interactivity } from "./util";
import { judgeSelf, Hand, Interactivity } from "./util";
import * as UICONFIG from "../../config/ui";
export interface Hands {
// 注意:手牌的位置顺序是有约束的
cards: Card[];
cards: Hand[];
}
// 增加手牌
......@@ -86,7 +86,7 @@ export const handsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
// 更新手牌的位置和旋转信息
//
// TODO: 兼容对方手牌
function setHandsTransform(hands: Card[]): void {
function setHandsTransform(hands: Hand[]): void {
const groundShape = UICONFIG.GroundShape();
const handShape = UICONFIG.HandShape();
const gap = groundShape.width / (hands.length - 1);
......@@ -140,6 +140,20 @@ export const addHandsInteractivityImpl: CaseReducer<
}
};
// 删除手牌
export const removeHandImpl: CaseReducer<
DuelState,
PayloadAction<[number, number]>
> = (state, action) => {
const controler = action.payload[0];
const sequence = action.payload[1];
const hands = judgeSelf(controler, state) ? state.meHands : state.opHands;
if (hands) {
hands.cards = hands.cards.filter((_, idx) => idx != sequence);
}
};
export const selectMeHands = (state: RootState) =>
state.duel.meHands || { cards: [] };
export const selectOpHands = (state: RootState) =>
......
import { judgeSelf, Magic, InteractType } from "./util";
import { PayloadAction, CaseReducer } from "@reduxjs/toolkit";
import {
PayloadAction,
CaseReducer,
createAsyncThunk,
ActionReducerMapBuilder,
} from "@reduxjs/toolkit";
import { DuelState } from "./mod";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { RootState } from "../../store";
import { CardMeta, fetchCard } from "../../api/cards";
export interface MagicState {
magics: Magic[];
......@@ -74,8 +80,76 @@ export const clearMagicSelectInfoImpl: CaseReducer<
const magics = judgeSelf(player, state) ? state.meMagics : state.opMagics;
if (magics) {
magics.magics = [];
for (const magic of magics.magics) {
magic.selectInfo = undefined;
}
}
};
// 增加魔法陷阱
export const fetchMagicMeta = createAsyncThunk(
"duel/fetchMagicMeta",
async (param: [number, number, number]) => {
const controler = param[0];
const sequence = param[1];
const code = param[2];
const meta = await fetchCard(code);
const response: [number, number, CardMeta] = [controler, sequence, meta];
return response;
}
);
export const magicCase = (builder: ActionReducerMapBuilder<DuelState>) => {
builder.addCase(fetchMagicMeta.pending, (state, action) => {
// Meta结果没返回之前先更新`ID`
const controler = action.meta.arg[0];
const sequence = action.meta.arg[1];
const code = action.meta.arg[2];
const meta = { id: code, data: {}, text: {} };
if (judgeSelf(controler, state)) {
if (state.meMagics) {
for (const magic of state.meMagics.magics) {
if (magic.sequence == sequence) {
magic.occupant = meta;
}
}
}
} else {
if (state.opMagics) {
for (const magic of state.opMagics.magics) {
if (magic.sequence == sequence) {
magic.occupant = meta;
}
}
}
}
});
builder.addCase(fetchMagicMeta.fulfilled, (state, action) => {
const controler = action.payload[0];
const sequence = action.payload[1];
const meta = action.payload[2];
if (judgeSelf(controler, state)) {
if (state.meMagics) {
for (const magic of state.meMagics.magics) {
if (magic.sequence == sequence) {
magic.occupant = meta;
}
}
}
} else {
if (state.opMagics) {
for (const magic of state.opMagics.magics) {
if (magic.sequence == sequence) {
magic.occupant = meta;
}
}
}
}
});
};
export const selectMeMagics = (state: RootState) =>
......
......@@ -11,6 +11,7 @@ import {
handsCase,
clearHandsInteractivityImpl,
addHandsInteractivityImpl,
removeHandImpl,
} from "./handsSlice";
import { newTurnImpl } from "./turnSlice";
import { newPhaseImpl } from "./phaseSlice";
......@@ -28,12 +29,14 @@ import {
initMonstersImpl,
addMonsterPlaceSelectAbleImpl,
clearMonsterSelectInfoImpl,
monsterCase,
} from "./monstersSlice";
import {
MagicState,
initMagicsImpl,
addMagicPlaceSelectAbleImpl,
clearMagicSelectInfoImpl,
magicCase,
} from "./magicSlice";
export interface DuelState {
......@@ -84,6 +87,7 @@ const duelSlice = createSlice({
// 手牌相关`Reducer`
clearHandsInteractivity: clearHandsInteractivityImpl,
addHandsInteractivity: addHandsInteractivityImpl,
removeHand: removeHandImpl,
// 怪兽区相关`Reducer`
initMonsters: initMonstersImpl,
......@@ -104,6 +108,8 @@ const duelSlice = createSlice({
extraReducers(builder) {
handsCase(builder);
hintCase(builder);
monsterCase(builder);
magicCase(builder);
},
});
......@@ -125,6 +131,7 @@ export const {
initMagics,
addMagicPlaceSelectAble,
clearMagicSelectInfo,
removeHand,
} = duelSlice.actions;
export const selectDuelHsStart = (state: RootState) => {
return state.duel.meInitInfo != null;
......
import { judgeSelf, Monster, InteractType } from "./util";
import { PayloadAction, CaseReducer } from "@reduxjs/toolkit";
import {
PayloadAction,
CaseReducer,
createAsyncThunk,
ActionReducerMapBuilder,
} from "@reduxjs/toolkit";
import { DuelState } from "./mod";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { RootState } from "../../store";
import { CardMeta, fetchCard } from "../../api/cards";
export interface MonsterState {
monsters: Monster[];
......@@ -78,8 +84,76 @@ export const clearMonsterSelectInfoImpl: CaseReducer<
: state.opMonsters;
if (monsters) {
monsters.monsters = [];
for (const monster of monsters.monsters) {
monster.selectInfo = undefined;
}
}
};
// 增加怪兽
export const fetchMonsterMeta = createAsyncThunk(
"duel/fetchMonsterMeta",
async (param: [number, number, number]) => {
const controler = param[0];
const sequence = param[1];
const code = param[2];
const meta = await fetchCard(code);
const response: [number, number, CardMeta] = [controler, sequence, meta];
return response;
}
);
export const monsterCase = (builder: ActionReducerMapBuilder<DuelState>) => {
builder.addCase(fetchMonsterMeta.pending, (state, action) => {
// Meta结果没返回之前先更新`ID`
const controler = action.meta.arg[0];
const sequence = action.meta.arg[1];
const code = action.meta.arg[2];
const cardMeta = { id: code, data: {}, text: {} };
if (judgeSelf(controler, state)) {
if (state.meMonsters) {
for (const monster of state.meMonsters.monsters) {
if (monster.sequence == sequence) {
monster.occupant = cardMeta;
}
}
}
} else {
if (state.opMonsters) {
for (const monster of state.opMonsters.monsters) {
if (monster.sequence == sequence) {
monster.occupant = cardMeta;
}
}
}
}
});
builder.addCase(fetchMonsterMeta.fulfilled, (state, action) => {
const controler = action.payload[0];
const sequence = action.payload[1];
const meta = action.payload[2];
if (judgeSelf(controler, state)) {
if (state.meMonsters) {
for (const monster of state.meMonsters.monsters) {
if (monster.sequence == sequence) {
monster.occupant = meta;
}
}
}
} else {
if (state.opMonsters) {
for (const monster of state.opMonsters.monsters) {
if (monster.sequence == sequence) {
monster.occupant = meta;
}
}
}
}
});
};
export const selectMeMonsters = (state: RootState) =>
......
......@@ -25,10 +25,7 @@ export function judgeSelf(player: number, state: Draft<DuelState>): boolean {
}
}
/*
* `Neos`中表示卡牌的通用结构
* */
export interface Card {
export interface Hand {
meta: CardMeta;
transform: CardTransform;
interactivities: Interactivity<number>[];
......
......@@ -7,6 +7,7 @@ import onMsgNewPhase from "./newPhase";
import onMsgHint from "./hint";
import onMsgSelectIdleCmd from "./selectIdleCmd";
import onMsgSelectPlace from "./selectPlace";
import onMsgMove from "./move";
export default function handleGameMsg(pb: ygopro.YgoStocMsg) {
const dispatch = store.dispatch;
......@@ -62,6 +63,13 @@ export default function handleGameMsg(pb: ygopro.YgoStocMsg) {
break;
}
case "move": {
const move = msg.move;
onMsgMove(move, dispatch);
break;
}
default: {
break;
}
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import MsgMove = ygopro.StocGameMessage.MsgMove;
import { AppDispatch } from "../../store";
import { fetchMonsterMeta } from "../../reducers/duel/monstersSlice";
import { removeHand } from "../../reducers/duel/mod";
import { fetchMagicMeta } from "../../reducers/duel/magicSlice";
export default (move: MsgMove, dispatch: AppDispatch) => {
const code = move.code;
const from = move.from;
const to = move.to;
// TODO: reason
switch (from.location) {
case ygopro.CardZone.HAND: {
dispatch(removeHand([from.controler, from.sequence]));
break;
}
default: {
console.log(`Unhandled zone type ${from.location}`);
break;
}
}
switch (to.location) {
case ygopro.CardZone.MZONE: {
dispatch(fetchMonsterMeta([to.controler, to.sequence, code]));
break;
}
case ygopro.CardZone.SZONE: {
dispatch(fetchMagicMeta([to.controler, to.sequence, code]));
break;
}
default: {
console.log(`Unhandled zone type ${to.location}`);
break;
}
}
};
......@@ -2,7 +2,7 @@ import * as BABYLON from "@babylonjs/core";
import { useAppSelector } from "../../hook";
import { selectMeHands } from "../../reducers/duel/handsSlice";
import * as CONFIG from "../../config/ui";
import { Card, InteractType } from "../../reducers/duel/util";
import { Hand, InteractType } from "../../reducers/duel/util";
import {
setCardModalImgUrl,
setCardModalIsOpen,
......@@ -20,13 +20,13 @@ const Hands = () => {
return (
<>
{hands.map((hand, idx) => {
return <Hand state={hand} idx={idx} key={idx} />;
return <CHand state={hand} idx={idx} key={idx} />;
})}
</>
);
};
const Hand = (props: { state: Card; idx: number }) => {
const CHand = (props: { state: Hand; idx: number }) => {
const handShape = CONFIG.HandShape();
const hoverScale = CONFIG.HandHoverScaling();
const defaultScale = new BABYLON.Vector3(1, 1, 1);
......
......@@ -71,7 +71,7 @@ const CMagic = (props: { state: Magic }) => {
? new BABYLON.Texture(`http://localhost:3030/images/card_back.jpg`)
: new BABYLON.Texture(`http://localhost:3030/images/card_slot.png`)
}
alpha={0.2}
alpha={state.occupant ? 1 : 0}
></standardMaterial>
</plane>
);
......
......@@ -72,7 +72,7 @@ const CommonMonster = (props: { state: Monster }) => {
)
: new BABYLON.Texture(`http://localhost:3030/images/card_slot.png`)
}
alpha={0.2}
alpha={props.state.occupant ? 1 : 0}
></standardMaterial>
</plane>
);
......
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