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

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

Feat/animation/attack

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