Commit 6fc21e22 authored by Chunchi Che's avatar Chunchi Che

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

Feat/service/chain

See merge request !198
parents 7bc9f266 e37fe4ad
Pipeline #21747 passed with stages
in 15 minutes and 4 seconds
......@@ -49,20 +49,12 @@ export interface CardText {
* @returns 卡片数据
*
* */
export async function fetchCard(
id: number,
local: boolean = true
): Promise<CardMeta> {
if (local) {
const res = await sqliteMiddleWare({
cmd: sqliteCmd.SELECT,
payload: { id },
});
return res.selectResult ? res.selectResult : { id, data: {}, text: {} };
}
const res = await axios.get<CardMeta>("http://localhost:3030/cards/" + id);
return res.data;
export async function fetchCard(id: number): Promise<CardMeta> {
const res = await sqliteMiddleWare({
cmd: sqliteCmd.SELECT,
payload: { id },
});
return res.selectResult ? res.selectResult : { id, data: {}, text: {} };
}
export function getCardStr(meta: CardMeta, idx: number): string | undefined {
......
......@@ -30,6 +30,6 @@ export async function getStrings(description: number): Promise<string> {
const code = description >> 4;
const index = description & 0xf;
return getCardStr(await fetchCard(code, true), index) || "";
return getCardStr(await fetchCard(code), index) || "";
}
}
// web平台上websocket的消息到达是保序的,但是不能保证对这些消息的逻辑处理是保序的。
// 现在我们有这样一个需求:需要保证每次只处理一个消息,在上一个消息处理完后,再进行下一个消息的处理。
//
// 因此封装了一个`WebSocketStream`类,当每次Websocket连接中有消息到达时,往流中添加event,
// 同时执行器会不断地从流中获取event进行处理。
import { sleep } from "./sleep";
const SLEEP_INTERVAL = 200;
......
import { ygopro } from "@/api";
import { matStore } from "@/stores";
export default (chainSolved: ygopro.StocGameMessage.MsgChainSolved) => {
console.log(chainSolved);
const location = matStore.chains
.splice(chainSolved.solved_index - 1, 1)
.at(0);
if (location) {
// 设置被连锁状态为空
matStore.setChained(location, undefined);
} else {
console.warn("pop from chains return null!");
}
};
......@@ -9,9 +9,15 @@ export default async (chaining: ygopro.StocGameMessage.MsgChaining) => {
cardID: chaining.code,
});
matStore.setChaining(chaining.location, chaining.code, true);
await matStore.setChaining(chaining.location, chaining.code, true);
await sleep(useConfig().ui.chainingDelay);
matStore.setChaining(chaining.location, chaining.code, false);
// TODO: set chained
const location = chaining.location;
// 恢复成非`chaining`状态
await matStore.setChaining(location, chaining.code, false);
// 将`location`添加到连锁栈
matStore.chains.push(location);
// 设置被连锁状态
matStore.setChained(location, matStore.chains.length);
};
......@@ -22,6 +22,7 @@ export default async (move: MsgMove) => {
// FIXME: 考虑超量素材的情况
let uuid;
let chainIndex;
switch (from.location) {
case ygopro.CardZone.MZONE:
case ygopro.CardZone.SZONE: {
......@@ -32,6 +33,7 @@ export default async (move: MsgMove) => {
target.occupant = undefined;
target.overlay_materials = [];
uuid = target.uuid;
chainIndex = target.chainIndex;
// 需要重新分配UUID
target.uuid = v4uuid();
break;
......@@ -47,6 +49,7 @@ export default async (move: MsgMove) => {
.of(from.controler)
.remove(from.sequence);
uuid = removed.uuid;
chainIndex = removed.chainIndex;
break;
}
......@@ -77,8 +80,12 @@ export default async (move: MsgMove) => {
.of(to.controler)
.setOccupant(to.sequence, code, to.position, true);
if (uuid) {
// 设置UUID
matStore.in(to.location).of(to.controler)[to.sequence].uuid = uuid;
}
// 设置连锁序号
matStore.in(to.location).of(to.controler)[to.sequence].chainIndex =
chainIndex;
await sleep(NeosConfig.ui.moveDelay);
matStore.in(to.location).of(to.controler)[to.sequence].focus = false;
......@@ -92,7 +99,7 @@ export default async (move: MsgMove) => {
matStore
.in(to.location)
.of(to.controler)
.insert(uuid, code, to.sequence, to.position);
.insert(uuid, code, to.sequence, to.position, false, chainIndex);
}
break;
}
......@@ -106,7 +113,8 @@ export default async (move: MsgMove) => {
code,
to.sequence,
ygopro.CardPosition.FACEUP_ATTACK,
true
true,
chainIndex
);
await sleep(NeosConfig.ui.moveDelay);
......
......@@ -6,7 +6,7 @@ type MsgSortCard = ygopro.StocGameMessage.MsgSortCard;
export default async (sortCard: MsgSortCard) => {
await Promise.all(
sortCard.options.map(async ({ code, response }) => {
const meta = await fetchCard(code!, true);
const meta = await fetchCard(code!);
messageStore.sortCardModal.options.push({
meta,
response: response!,
......
......@@ -21,7 +21,7 @@ export const fetchSelectHintMeta = async ({
let selectHintMeta = "";
if (selectHintData > DESCRIPTION_LIMIT) {
// 针对`MSG_SELECT_PLACE`的特化逻辑
const cardMeta = await fetchCard(selectHintData, true);
const cardMeta = await fetchCard(selectHintData);
selectHintMeta = fetchStrings("!system", 569).replace(
"[%ls]",
cardMeta.text.name || "[?]"
......
......@@ -31,10 +31,11 @@ class CardArray extends Array<CardState> implements ArrayCardState {
controller: number,
id: number,
position?: ygopro.CardPosition,
focus?: boolean
focus?: boolean,
chainIndex?: number
) => ({
uuid,
occupant: await fetchCard(id, true),
occupant: await fetchCard(id),
location: {
controler: controller,
zone: this.zone,
......@@ -43,6 +44,7 @@ class CardArray extends Array<CardState> implements ArrayCardState {
},
focus: focus ?? false,
chaining: false,
chainIndex,
directAttack: false,
counters: {},
idleInteractivities: [],
......@@ -56,14 +58,16 @@ class CardArray extends Array<CardState> implements ArrayCardState {
id: number,
sequence: number,
position?: ygopro.CardPosition,
focus?: boolean
focus?: boolean,
chainIndex?: number
) {
const card = await this.genCard(
uuid,
this.getController(),
id,
position,
focus
focus,
chainIndex
);
this.splice(sequence, 0, card);
}
......@@ -234,6 +238,8 @@ export const matStore: MatState = proxy<MatState>({
decks: genDuelCardArray([], DECK),
extraDecks: genDuelCardArray([], EXTRA),
chains: [],
timeLimits: {
// 时间限制
me: -1,
......@@ -262,15 +268,17 @@ export const matStore: MatState = proxy<MatState>({
// methods
in: getZone,
isMe,
setChaining(location, code, isChaining) {
async setChaining(location, code, isChaining) {
const target = this.in(location.location)
.of(location.controler)
.at(location.sequence);
if (target) {
target.chaining = isChaining;
if (target.occupant && isChaining) {
// 目前需要判断`isChaining`为ture才设置id,因为有些手坑发效果后会move到墓地,运行到这里的时候已经和原来的位置对不上了,这时候不设置id
target.occupant.id = code;
// 目前需要判断`isChaining`为ture才设置meta,因为有些手坑发效果后会move到墓地,
// 运行到这里的时候已经和原来的位置对不上了,这时候不设置meta
const meta = await fetchCard(code);
target.occupant = meta;
}
if (target.location.zone == ygopro.CardZone.HAND) {
target.location.position = isChaining
......@@ -279,6 +287,14 @@ export const matStore: MatState = proxy<MatState>({
}
}
},
setChained(location, chainIndex) {
const target = this.in(location.location)
.of(location.controler)
.at(location.sequence);
if (target) {
target.chainIndex = chainIndex;
}
},
});
// @ts-ignore 挂到全局,便于调试
......
......@@ -21,7 +21,8 @@ export interface DuelFieldState extends Array<CardState> {
id: number,
sequence: number,
position?: ygopro.CardPosition,
focus?: boolean
focus?: boolean,
chainIndex?: number
) => Promise<void>;
/** 在末尾添加卡片 */
add: (
......@@ -78,6 +79,8 @@ export interface MatState {
extraDecks: BothSide<ExtraDeckState>; // 双方的额外卡组状态
chains: ygopro.CardLocation[]; // 连锁的卡片位置
timeLimits: BothSide<number> & {
set: (controller: number, time: number) => void;
}; // 双方的时间限制
......@@ -108,7 +111,9 @@ export interface MatState {
location: ygopro.CardLocation,
code: number,
isChaining: boolean
) => void;
) => Promise<void>;
// 添加被连锁状态
setChained: (location: ygopro.CardLocation, chainIndex?: number) => void;
}
export interface InitInfo {
......@@ -132,6 +137,8 @@ export interface CardState {
}; // 位置信息,叫location的原因是为了和ygo对齐
focus: boolean; // 用于实现动画效果,当这个字段为true时,该张卡片会被放大并在屏幕中央展示
chaining: boolean; // 是否在连锁中
chainIndex?: number /*连锁的序号,如果为空表示不在连锁
TODO: 目前是妥协的设计,因为其实一张卡是可以在同一个连锁链中被连锁多次的,这里为了避免太过复杂只保存最后的连锁序号*/;
directAttack: boolean; // 是否正在直接攻击为玩家
attackTarget?: CardState & { sequence: number; opponent: boolean }; // 攻击目标。(嵌套结构可行么?)
idleInteractivities: Interactivity<number>[]; // IDLE状态下的互动信息
......
......@@ -76,10 +76,6 @@ p {
}
.container {
// left: 50%;
// position: fixed;
// top: 50%;
// transform: translate(-50%, -50%);
margin: 0 auto;
width: 100%;
max-width: 300px;
......
......@@ -48,6 +48,8 @@ export const CardListModal = () => {
}
onClick={() => {
messageStore.cardModal.meta = item.meta;
messageStore.cardModal.interactivies = item.interactivies;
messageStore.cardModal.counters = [];
messageStore.cardModal.isOpen = true;
}}
>
......
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