Commit 536ed9e6 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/animation/attack' into 'main'

Feat/animation/attack

See merge request mycard/Neos!193
parents 848d06a7 e53123ee
......@@ -74,7 +74,8 @@
},
"commonDelay": 200,
"moveDelay": 500,
"chainingDelay": 800
"chainingDelay": 800,
"attackDelay": 500
},
"unimplementedWhiteList":[
1,
......
......@@ -74,7 +74,8 @@
},
"commonDelay": 200,
"moveDelay": 500,
"chainingDelay": 800
"chainingDelay": 800,
"attackDelay": 500
},
"unimplementedWhiteList":[
1,
......
......@@ -56,3 +56,4 @@ export const MSG_ADD_COUNTER = 101;
export const MSG_REMOVE_COUNTER = 102;
export const MSG_SELECT_COUNTER = 22;
export const MSG_SORT_CARD = 25;
export const MSG_ATTACK = 110;
import { ygopro } from "@/api/ocgcore/idl/ocgcore";
import { BufferReaderExt } from "../../bufferIO";
import MsgAttack = ygopro.StocGameMessage.MsgAttack;
/*
* Msg Attack
*
* @param attacker_location - 攻击者位置
* @param target_location - 攻击目标位置,可能为空
* @param direct_attack - 是否直接攻击玩家
* */
export default (data: Uint8Array) => {
const reader = new BufferReaderExt(data);
const attacker_location = reader.readCardLocation();
const target_location = reader.readCardLocation();
if (
target_location.controler == 0 &&
target_location.location == 0 &&
target_location.sequence == 0
) {
// 全零表示直接攻击玩家
return new MsgAttack({
attacker_location,
direct_attack: true,
});
} else {
return new MsgAttack({
attacker_location,
target_location,
direct_attack: false,
});
}
};
......@@ -7,6 +7,7 @@ import { ygopro } from "../../../idl/ocgcore";
import { StocAdapter, YgoProPacket } from "../../packet";
import * as GAME_MSG from "../../protoDecl";
import MsgAddCounter from "./addCounter";
import MsgAttack from "./attack";
import MsgDamage from "./damage";
import MsgDrawAdapter from "./draw";
import MsgHintAdapter from "./hint";
......@@ -190,6 +191,11 @@ export default class GameMsgAdapter implements StocAdapter {
break;
}
case GAME_MSG.MSG_ATTACK: {
gameMsg.attack = MsgAttack(gameData);
break;
}
default: {
gameMsg.unimplemented = new ygopro.StocGameMessage.MsgUnimplemented({
command: func,
......
......@@ -106,12 +106,6 @@
{ "fieldName": "location", "fieldType": "CardLocation" }
]
},
"110": {
"protoType": "attack",
"fields": [
{ "fieldName": "location", "fieldType": "CardLocation" }
]
},
"112": {
"protoType": "attack_disable",
"fields": []
......
......@@ -29,7 +29,6 @@ const MsgConstructorMap: Map<string, Constructor> = new Map([
["sp_summoning", ygopro.StocGameMessage.MsgSpSummoning],
["sp_summoned", ygopro.StocGameMessage.MsgSpSummoned],
["chaining", ygopro.StocGameMessage.MsgChaining],
["attack", ygopro.StocGameMessage.MsgAttack],
["attack_disable", ygopro.StocGameMessage.MsgAttackDisabled],
["chain_solved", ygopro.StocGameMessage.MsgChainSolved],
]);
......
import { ygopro } from "@/api";
import { fetchEsHintMeta } from "@/stores";
import { fetchEsHintMeta, matStore } from "@/stores";
export default (attack: ygopro.StocGameMessage.MsgAttack) => {
fetchEsHintMeta({
originMsg: "「[?]」攻击时",
location: attack.attacker_location,
});
const attacker = matStore
.in(attack.attacker_location.location)
.of(attack.attacker_location.controler)
.at(attack.attacker_location.sequence);
if (attacker) {
if (attack.direct_attack) {
attacker.directAttack = true;
setTimeout(() => (attacker.directAttack = false), 500);
} else {
const target = matStore
.in(attack.target_location.location)
.of(attack.target_location.controler)
.at(attack.target_location.sequence);
if (target) {
attacker.attackTarget = {
sequence: attack.target_location.sequence,
opponent: !matStore.isMe(attack.target_location.controler),
...target,
};
setTimeout(() => (attacker.attackTarget = undefined), 500);
}
}
}
};
......@@ -52,6 +52,7 @@ function reloadDuelField(
counters: {},
focus: false,
chaining: false,
directAttack: false,
reload: true,
};
});
......
......@@ -41,6 +41,7 @@ export default (start: ygopro.StocGameMessage.MsgStart) => {
},
focus: false,
chaining: false,
directAttack: false,
counters: {},
idleInteractivities: [],
});
......@@ -59,6 +60,7 @@ export default (start: ygopro.StocGameMessage.MsgStart) => {
},
focus: false,
chaining: false,
directAttack: false,
counters: {},
idleInteractivities: [],
});
......@@ -78,6 +80,7 @@ export default (start: ygopro.StocGameMessage.MsgStart) => {
},
focus: false,
chaining: false,
directAttack: false,
counters: {},
idleInteractivities: [],
});
......
......@@ -126,6 +126,8 @@ function handleDelay(stoc: ygopro.YgoStocMsg): number {
matStore.delay = NeosConfig.ui.moveDelay + 500;
} else if (stoc.stoc_game_msg.gameMsg == "chaining") {
matStore.delay = NeosConfig.ui.chainingDelay;
} else if (stoc.stoc_game_msg.gameMsg == "attack") {
matStore.delay = NeosConfig.ui.attackDelay + 200;
}
}
......
......@@ -43,6 +43,7 @@ class CardArray extends Array<CardState> implements ArrayCardState {
},
focus: focus ?? false,
chaining: false,
directAttack: false,
counters: {},
idleInteractivities: [],
});
......@@ -164,6 +165,7 @@ const genBlock = (zone: ygopro.CardZone, n: number) =>
},
focus: false,
chaining: false,
directAttack: false,
idleInteractivities: [],
counters: {},
}));
......
......@@ -132,6 +132,8 @@ export interface CardState {
}; // 位置信息,叫location的原因是为了和ygo对齐
focus: boolean; // 用于实现动画效果,当这个字段为true时,该张卡片会被放大并在屏幕中央展示
chaining: boolean; // 是否在连锁中
directAttack: boolean; // 是否正在直接攻击为玩家
attackTarget?: CardState & { sequence: number; opponent: boolean }; // 攻击目标。(嵌套结构可行么?)
idleInteractivities: Interactivity<number>[]; // IDLE状态下的互动信息
placeInteractivity?: Interactivity<{
controler: number;
......
......@@ -107,7 +107,11 @@ export const Mat = () => {
card.focus ||
(card.chaining && card.location.zone == YgoZone.HAND)
}
fly={card.chaining && card.location.zone != YgoZone.HAND}
fly={
(card.chaining && card.location.zone != YgoZone.HAND) ||
card.attackTarget !== undefined ||
card.directAttack
}
opponent={card.opponent}
onClick={
card.location.zone == YgoZone.SZONE ||
......@@ -128,6 +132,21 @@ export const Mat = () => {
function cardStateToRow(state: RenderCard): number {
if (state.focus) return 2;
if (state.directAttack) {
// 正在直接攻击玩家
if (state.opponent) {
return 4.5;
} else {
return -0.5;
}
}
if (state.attackTarget) {
// 正在攻击怪兽
return (
cardStateToRow(state.attackTarget) -
0.2 * (state.attackTarget.opponent ? -1 : 1)
);
}
if (state.opponent) {
switch (state.location.zone) {
case YgoZone.EXTRA:
......@@ -169,6 +188,10 @@ function cardStateToRow(state: RenderCard): number {
function cardStateToCol(state: RenderCard): number {
if (state.focus) return 2;
if (state.attackTarget) {
// 正在攻击对方怪兽
return cardStateToCol(state.attackTarget);
}
if (state.opponent) {
switch (state.location.zone) {
case YgoZone.EXTRA:
......
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