Commit 736537f0 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'fix/select_xx' into 'main'

fix MSG_SELECT_CHAIN, MSG_SELECT_SUM and MSG_CONFIRM_CARDS

See merge request mycard/Neos!423
parents 977849d7 c284e77c
Pipeline #42402 passed with stages
in 1 minute and 20 seconds
......@@ -78,3 +78,5 @@ export const MSG_HAND_RES = 133;
export const MSG_SHUFFLE_HAND = 33;
export const MSG_SHUFFLE_EXTRA = 39;
export const MSG_SIBYL_NAME = 235;
export const MSG_CONFIRM_CARDS = 30;
export const MSG_CONFIRM_DECKTOP = 31;
import { ygopro } from "../../../idl/ocgcore";
import { BufferReaderExt } from "../../bufferIO";
import MsgConfirmCards = ygopro.StocGameMessage.MsgConfirmCards;
/*
* Msg Confirm Cards
*
* @usage - 确认卡片(展示手牌、确认盖卡等)
* */
export default (data: Uint8Array) => {
const reader = new BufferReaderExt(data);
const player = reader.inner.readUint8();
// 新协议在 player 和 count 之间增加了一个字节,用途暂不明确。
// 参考 C# 实现:
// if (condition != Condition.Replay || CurrentReplayUseYRP2)
// reader.ReadByte();
// C# 中在非回放模式或使用 YRP2 格式回放时会跳过这个字节。
// 如果后续需要支持旧版回放文件,可能需要加条件判断。
reader.inner.readUint8();
const count = reader.inner.readUint8();
const cards: ygopro.CardInfo[] = [];
for (let i = 0; i < count; i++) {
cards.push(reader.readCardInfo());
}
return new MsgConfirmCards({
player,
cards,
});
};
......@@ -12,6 +12,7 @@ import MsgAnnounceCard from "./announceCard";
import MsgAnnounceNumber from "./announceNumber";
import MsgAnnounceRace from "./announceRace";
import MsgAttack from "./attack";
import MsgConfirmCardsAdapter from "./confirmCards";
import MsgDamage from "./damage";
import MsgDrawAdapter from "./draw";
import MsgFieldDisabledAdapter from "./fieldDisabled";
......@@ -245,6 +246,11 @@ export default class GameMsgAdapter implements StocAdapter {
gameMsg.sibyl_name = MsgSibylNameAdapter(gameData);
break;
}
case GAME_MSG.MSG_CONFIRM_CARDS:
case GAME_MSG.MSG_CONFIRM_DECKTOP: {
gameMsg.confirm_cards = MsgConfirmCardsAdapter(gameData);
break;
}
default: {
gameMsg.unimplemented = new ygopro.StocGameMessage.MsgUnimplemented({
command: func,
......
......@@ -161,34 +161,7 @@
}
]
},
"30": {
"protoType": "confirm_cards",
"fields": [
{
"fieldName": "player",
"fieldType": "uint8"
},
{
"fieldName": "cards",
"fieldType": "repeated",
"repeatedType": "CardInfo"
}
]
},
"31": {
"protoType": "confirm_cards",
"fields": [
{
"fieldName": "player",
"fieldType": "uint8"
},
{
"fieldName": "cards",
"fieldType": "repeated",
"repeatedType": "CardInfo"
}
]
},
"83": {
"protoType": "become_target",
"fields": [
......
......@@ -32,7 +32,6 @@ const MsgConstructorMap: Map<string, Constructor> = new Map([
["chain_solved", ygopro.StocGameMessage.MsgChainSolved],
["chain_end", ygopro.StocGameMessage.MsgChainEnd],
["lp_update", ygopro.StocGameMessage.MsgLpUpdate],
["confirm_cards", ygopro.StocGameMessage.MsgConfirmCards],
["become_target", ygopro.StocGameMessage.MsgBecomeTarget],
["shuffle_deck", ygopro.StocGameMessage.MsgShuffleDeck],
["rock_paper_scissors", ygopro.StocGameMessage.MsgRockPaperScissors],
......
......@@ -17,35 +17,41 @@ export default (data: Uint8Array) => {
const player = reader.inner.readUint8();
const count = reader.inner.readUint8();
const spCount = reader.inner.readUint8();
const forced = reader.inner.readUint8() !== 0;
const hint0 = reader.inner.readUint32();
const hint1 = reader.inner.readUint32();
const msg = new MsgSelectChain({
player,
special_count: spCount,
forced,
forced: false,
hint0,
hint1,
chains: [],
});
let forceCount = 0;
for (let i = 0; i < count; i++) {
const flag = reader.inner.readUint8();
const code = reader.inner.readUint32();
const forced = reader.inner.readUint8();
forceCount += forced;
const code = reader.inner.readUint32() % 1000000000;
const location = reader.readCardLocation();
const effect_desc = reader.inner.readUint32();
msg.chains.push(
new MsgSelectChain.Chain({
flag: numberToChainFlag(flag),
code,
location,
effect_description: effect_desc,
response: i,
}),
);
const chain = new MsgSelectChain.Chain({
flag: numberToChainFlag(flag),
code,
location,
effect_description: effect_desc,
response: i,
});
// 由于 protobuf 定义中 Chain 没有 forced 字段,使用类型扩展
(chain as any).forced = forced > 0;
msg.chains.push(chain);
}
msg.forced = forceCount > 0;
return msg;
};
......@@ -34,12 +34,23 @@ export default (data: Uint8Array) => {
const location = reader.readCardShortLocation();
const para = reader.inner.readInt32();
let level1 = para & 0xffff;
let level2 = para >> 16;
// 检查 0x80000000 标志位
if ((para & 0x80000000) !== 0) {
level1 = para & 0x7fffffff;
level2 = level1;
}
if (level2 === 0) {
level2 = level1;
}
msg.must_select_cards.push(
new MsgSelectSum.Info({
code,
location,
level1: para & 0xffff,
level2: para >> 16,
level1,
level2,
response: i,
}),
);
......@@ -50,8 +61,17 @@ export default (data: Uint8Array) => {
const code = reader.inner.readInt32();
const location = reader.readCardShortLocation();
const para = reader.inner.readInt32();
const level1 = para & 0xffff;
const level2 = para >> 16 > 0 ? para >> 16 : level1;
let level1 = para & 0xffff;
let level2 = para >> 16;
// 检查 0x80000000 标志位
if ((para & 0x80000000) !== 0) {
level1 = para & 0x7fffffff;
level2 = level1;
}
if (level2 === 0) {
level2 = level1;
}
msg.selectable_cards.push(
new MsgSelectSum.Info({
......
......@@ -10,20 +10,22 @@ export default async (container: Container, selectChain: MsgSelectChain) => {
const conn = container.conn;
const context = container.context;
const spCount = selectChain.special_count;
const forced = selectChain.forced;
const _hint0 = selectChain.hint0;
const _hint1 = selectChain.hint1;
const chains = selectChain.chains;
const chainSetting = context.matStore.chainSetting;
if (chainSetting === ChainSetting.CHAIN_IGNORE) {
// 如果玩家配置了忽略连锁,直接回应后端并返回
// 计算强制发动的卡片数量
const forceCount = chains.filter((chain) => (chain as any).forced).length;
if (chainSetting === ChainSetting.CHAIN_IGNORE && forceCount === 0) {
// 如果玩家配置了忽略连锁,且没有强制发动的卡,直接回应后端并返回
sendSelectSingleResponse(conn, -1);
return;
}
let handle_flag = 0;
if (!forced) {
if (forceCount === 0) {
// 无强制发动的卡
if (spCount === 0) {
// 无关键卡
......@@ -32,8 +34,12 @@ export default async (container: Container, selectChain: MsgSelectChain) => {
handle_flag = 0;
} else {
if (chainSetting === ChainSetting.CHAIN_ALL) {
// 配置了全部连锁,则处理多张
handle_flag = 2;
// 配置了全部连锁,则处理
if (chains.length === 1) {
handle_flag = 1;
} else {
handle_flag = 2;
}
} else {
// 否则不连锁
handle_flag = 0;
......@@ -44,32 +50,45 @@ export default async (container: Container, selectChain: MsgSelectChain) => {
if (chains.length === 0) {
// 根本没卡,直接回答
handle_flag = 0;
} else if (chainSetting === ChainSetting.CHAIN_IGNORE) {
// 配置了忽略连锁
handle_flag = 0;
} else {
// 处理多张
handle_flag = 2;
// 处理
if (chains.length === 1) {
handle_flag = 1;
} else {
handle_flag = 2;
}
}
}
} else {
// 有强制发动的卡
if (chains.length === 1) {
// 只有一个强制发动的连锁项,直接回应
handle_flag = 4;
} else {
// 处理强制发动的卡
// 只有一张卡需要处理(强制发动)
handle_flag = 3;
} else {
// 多张卡需要处理(强制发动)
handle_flag = 4;
}
}
// handle_flag:
// 0 - 无卡,直接回应
// 1 - 一张卡需要处理
// 2 - 多张卡需要处理
// 3 - 一张卡需要处理(强制发动)
// 4 - 多张卡需要处理(强制发动)
switch (handle_flag) {
case 0: {
// 直接回答
sendSelectSingleResponse(conn, -1);
break;
}
case 2: // 处理多张
case 3: {
// 处理强制发动的卡
case 1:
case 2: {
// 处理可选连锁
fetchSelectHintMeta({
selectHintData: 203,
});
......@@ -79,7 +98,7 @@ export default async (container: Container, selectChain: MsgSelectChain) => {
);
await displaySelectActionsModal({
isChain: true,
cancelable: !forced,
cancelable: true,
min: 1,
max: 1,
selecteds,
......@@ -88,10 +107,29 @@ export default async (container: Container, selectChain: MsgSelectChain) => {
});
break;
}
case 4: {
// 一张强制发动的卡,直接回应
case 3: {
// 一张强制发动的卡,直接回应
sendSelectSingleResponse(conn, chains[0].response);
break;
}
case 4: {
// 多张强制发动的卡,弹窗选择
fetchSelectHintMeta({
selectHintData: 203,
});
const { selecteds, mustSelects, selectables } = await fetchCheckCardMeta(
context,
chains,
);
await displaySelectActionsModal({
isChain: true,
cancelable: false,
min: 1,
max: 1,
selecteds,
mustSelects,
selectables,
});
break;
}
default: {
......
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