Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
N
Neos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
love_飞影
Neos
Commits
b4e4a4e8
Commit
b4e4a4e8
authored
Jun 22, 2023
by
Chunchi Che
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev/async_rebase' into 'dev/async'
Dev/async rebase See merge request
mycard/Neos!234
parents
c78b6b62
d0b7a3c9
Changes
22
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
1147 additions
and
48 deletions
+1147
-48
neos.config.json
neos.config.json
+1
-1
src/api/ocgcore/idl/ocgcore.ts
src/api/ocgcore/idl/ocgcore.ts
+762
-5
src/api/ocgcore/ocgAdapter/protoDecl.ts
src/api/ocgcore/ocgAdapter/protoDecl.ts
+3
-0
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/fieldDisabled.ts
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/fieldDisabled.ts
+73
-0
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/mod.ts
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/mod.ts
+13
-0
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/penetrate.json
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/penetrate.json
+9
-0
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/penetrate.ts
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/penetrate.ts
+1
-0
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/shuffleSetCard.ts
...api/ocgcore/ocgAdapter/stoc/stocGameMsg/shuffleSetCard.ts
+32
-0
src/service/duel/becomeTarget.ts
src/service/duel/becomeTarget.ts
+1
-1
src/service/duel/chainEnd.ts
src/service/duel/chainEnd.ts
+8
-0
src/service/duel/fieldDisabled.ts
src/service/duel/fieldDisabled.ts
+19
-0
src/service/duel/gameMsg.ts
src/service/duel/gameMsg.ts
+19
-1
src/service/duel/selectPlace.ts
src/service/duel/selectPlace.ts
+8
-5
src/service/duel/shuffleDeck.ts
src/service/duel/shuffleDeck.ts
+11
-0
src/service/duel/shuffleSetCard.ts
src/service/duel/shuffleSetCard.ts
+50
-0
src/service/duel/start.ts
src/service/duel/start.ts
+1
-0
src/service/duel/updateData.ts
src/service/duel/updateData.ts
+16
-11
src/stores/cardStore.ts
src/stores/cardStore.ts
+1
-2
src/stores/placeStore.ts
src/stores/placeStore.ts
+38
-9
src/ui/Duel/PlayMat/Bg/index.tsx
src/ui/Duel/PlayMat/Bg/index.tsx
+41
-11
src/ui/Duel/PlayMat/Card/index.scss
src/ui/Duel/PlayMat/Card/index.scss
+39
-2
src/ui/Duel/PlayMat/Card/index.tsx
src/ui/Duel/PlayMat/Card/index.tsx
+1
-0
No files found.
neos.config.json
View file @
b4e4a4e8
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
"version"
:
4960
,
"version"
:
4960
,
"servers"
:[
"servers"
:[
{
{
"ip"
:
"koishi
-r
.momobako.com"
,
"ip"
:
"koishi.momobako.com"
,
"port"
:
"7211"
"port"
:
"7211"
}
}
],
],
...
...
src/api/ocgcore/idl/ocgcore.ts
View file @
b4e4a4e8
This diff is collapsed.
Click to expand it.
src/api/ocgcore/ocgAdapter/protoDecl.ts
View file @
b4e4a4e8
...
@@ -35,6 +35,7 @@ export const MSG_NEW_PHASE = 41;
...
@@ -35,6 +35,7 @@ export const MSG_NEW_PHASE = 41;
export
const
MSG_HINT
=
2
;
export
const
MSG_HINT
=
2
;
export
const
MSG_SELECT_IDLE_CMD
=
11
;
export
const
MSG_SELECT_IDLE_CMD
=
11
;
export
const
MSG_SELECT_PLACE
=
18
;
export
const
MSG_SELECT_PLACE
=
18
;
export
const
MSG_SELECT_DISFIELD
=
24
;
export
const
MSG_MOVE
=
50
;
export
const
MSG_MOVE
=
50
;
export
const
MSG_SELECT_CARD
=
15
;
export
const
MSG_SELECT_CARD
=
15
;
export
const
MSG_SELECT_TRIBUTE
=
20
;
export
const
MSG_SELECT_TRIBUTE
=
20
;
...
@@ -63,3 +64,5 @@ export const MSG_ANNOUNCE_CARD = 142;
...
@@ -63,3 +64,5 @@ export const MSG_ANNOUNCE_CARD = 142;
export
const
MSG_ANNOUNCE_NUMBER
=
143
;
export
const
MSG_ANNOUNCE_NUMBER
=
143
;
export
const
MSG_TOSS_COIN
=
130
;
export
const
MSG_TOSS_COIN
=
130
;
export
const
MSG_TOSS_DICE
=
131
;
export
const
MSG_TOSS_DICE
=
131
;
export
const
MSG_SHUFFLE_SET_CARD
=
36
;
export
const
MSG_FIELD_DISABLED
=
56
;
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/fieldDisabled.ts
0 → 100644
View file @
b4e4a4e8
import
{
ygopro
}
from
"
@/api/ocgcore/idl/ocgcore
"
;
import
{
BufferReader
}
from
"
../../../../../../rust-src/pkg/rust_src
"
;
import
MsgFieldDisabled
=
ygopro
.
StocGameMessage
.
MsgFieldDisabled
;
import
CardZone
=
ygopro
.
CardZone
;
/*
* Msg Field Disabled
* @param - TODO
*
* @usage - 区域禁用
* */
export
default
(
data
:
Uint8Array
)
=>
{
const
reader
=
new
BufferReader
(
data
);
const
flag
=
reader
.
readInt32
();
const
actions
=
[];
let
filter
=
0x1
;
for
(
let
i
=
0
;
i
<
5
;
i
++
,
filter
<<=
1
)
{
const
disabled
=
(
flag
&
filter
)
>
0
;
actions
.
push
(
new
MsgFieldDisabled
.
Action
({
controller
:
0
,
zone
:
CardZone
.
MZONE
,
sequence
:
i
,
disabled
,
})
);
}
filter
=
0x100
;
for
(
let
i
=
0
;
i
<
8
;
i
++
,
filter
<<=
1
)
{
const
disabled
=
(
flag
&
filter
)
>
0
;
actions
.
push
(
new
MsgFieldDisabled
.
Action
({
controller
:
0
,
zone
:
CardZone
.
SZONE
,
sequence
:
i
,
disabled
,
})
);
}
filter
=
0x10000
;
for
(
let
i
=
0
;
i
<
5
;
i
++
,
filter
<<=
1
)
{
const
disabled
=
(
flag
&
filter
)
>
0
;
actions
.
push
(
new
MsgFieldDisabled
.
Action
({
controller
:
1
,
zone
:
CardZone
.
MZONE
,
sequence
:
i
,
disabled
,
})
);
}
filter
=
0x1000000
;
for
(
let
i
=
0
;
i
<
8
;
i
++
,
filter
<<=
1
)
{
const
disabled
=
(
flag
&
filter
)
>
0
;
actions
.
push
(
new
MsgFieldDisabled
.
Action
({
controller
:
1
,
zone
:
CardZone
.
SZONE
,
sequence
:
i
,
disabled
,
})
);
}
return
new
MsgFieldDisabled
({
actions
,
});
};
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/mod.ts
View file @
b4e4a4e8
...
@@ -14,6 +14,7 @@ import MsgAnnounceRace from "./announceRace";
...
@@ -14,6 +14,7 @@ import MsgAnnounceRace from "./announceRace";
import
MsgAttack
from
"
./attack
"
;
import
MsgAttack
from
"
./attack
"
;
import
MsgDamage
from
"
./damage
"
;
import
MsgDamage
from
"
./damage
"
;
import
MsgDrawAdapter
from
"
./draw
"
;
import
MsgDrawAdapter
from
"
./draw
"
;
import
MsgFieldDisabledAdapter
from
"
./fieldDisabled
"
;
import
MsgHintAdapter
from
"
./hint
"
;
import
MsgHintAdapter
from
"
./hint
"
;
import
MsgNewPhaseAdapter
from
"
./newPhase
"
;
import
MsgNewPhaseAdapter
from
"
./newPhase
"
;
import
MsgNewTurnAdapter
from
"
./newTurn
"
;
import
MsgNewTurnAdapter
from
"
./newTurn
"
;
...
@@ -33,6 +34,7 @@ import MsgSelectPositionAdapter from "./selectPosition";
...
@@ -33,6 +34,7 @@ import MsgSelectPositionAdapter from "./selectPosition";
import
MsgSelectSum
from
"
./selectSum
"
;
import
MsgSelectSum
from
"
./selectSum
"
;
import
MsgSelectTributeAdapter
from
"
./selectTribute
"
;
import
MsgSelectTributeAdapter
from
"
./selectTribute
"
;
import
MsgSelectUnselectCardAdapter
from
"
./selectUnselectCard
"
;
import
MsgSelectUnselectCardAdapter
from
"
./selectUnselectCard
"
;
import
MsgShuffleSetCard
from
"
./shuffleSetCard
"
;
import
MsgSortCard
from
"
./sortCard
"
;
import
MsgSortCard
from
"
./sortCard
"
;
import
MsgStartAdapter
from
"
./start
"
;
import
MsgStartAdapter
from
"
./start
"
;
import
MsgTossAdapter
from
"
./toss
"
;
import
MsgTossAdapter
from
"
./toss
"
;
...
@@ -95,6 +97,7 @@ export default class GameMsgAdapter implements StocAdapter {
...
@@ -95,6 +97,7 @@ export default class GameMsgAdapter implements StocAdapter {
break
;
break
;
}
}
case
GAME_MSG
.
MSG_SELECT_DISFIELD
:
case
GAME_MSG
.
MSG_SELECT_PLACE
:
{
case
GAME_MSG
.
MSG_SELECT_PLACE
:
{
gameMsg
.
select_place
=
MsgSelectPlaceAdapter
(
gameData
);
gameMsg
.
select_place
=
MsgSelectPlaceAdapter
(
gameData
);
...
@@ -237,6 +240,16 @@ export default class GameMsgAdapter implements StocAdapter {
...
@@ -237,6 +240,16 @@ export default class GameMsgAdapter implements StocAdapter {
break
;
break
;
}
}
case
GAME_MSG
.
MSG_SHUFFLE_SET_CARD
:
{
gameMsg
.
shuffle_set_card
=
MsgShuffleSetCard
(
gameData
);
break
;
}
case
GAME_MSG
.
MSG_FIELD_DISABLED
:
{
gameMsg
.
field_disabled
=
MsgFieldDisabledAdapter
(
gameData
);
break
;
}
default
:
{
default
:
{
gameMsg
.
unimplemented
=
new
ygopro
.
StocGameMessage
.
MsgUnimplemented
({
gameMsg
.
unimplemented
=
new
ygopro
.
StocGameMessage
.
MsgUnimplemented
({
command
:
func
,
command
:
func
,
...
...
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/penetrate.json
View file @
b4e4a4e8
...
@@ -235,5 +235,14 @@
...
@@ -235,5 +235,14 @@
"repeatedType"
:
"CardLocation"
"repeatedType"
:
"CardLocation"
}
}
]
]
},
"32"
:{
"protoType"
:
"shuffle_deck"
,
"fields"
:[
{
"fieldName"
:
"player"
,
"fieldType"
:
"uint8"
}
]
}
}
}
}
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/penetrate.ts
View file @
b4e4a4e8
...
@@ -35,6 +35,7 @@ const MsgConstructorMap: Map<string, Constructor> = new Map([
...
@@ -35,6 +35,7 @@ const MsgConstructorMap: Map<string, Constructor> = new Map([
[
"
lp_update
"
,
ygopro
.
StocGameMessage
.
MsgLpUpdate
],
[
"
lp_update
"
,
ygopro
.
StocGameMessage
.
MsgLpUpdate
],
[
"
confirm_cards
"
,
ygopro
.
StocGameMessage
.
MsgConfirmCards
],
[
"
confirm_cards
"
,
ygopro
.
StocGameMessage
.
MsgConfirmCards
],
[
"
become_target
"
,
ygopro
.
StocGameMessage
.
MsgBecomeTarget
],
[
"
become_target
"
,
ygopro
.
StocGameMessage
.
MsgBecomeTarget
],
[
"
shuffle_deck
"
,
ygopro
.
StocGameMessage
.
MsgShuffleDeck
],
]);
]);
export
interface
penetrateType
{
export
interface
penetrateType
{
...
...
src/api/ocgcore/ocgAdapter/stoc/stocGameMsg/shuffleSetCard.ts
0 → 100644
View file @
b4e4a4e8
import
{
ygopro
}
from
"
@/api/ocgcore/idl/ocgcore
"
;
import
{
BufferReaderExt
}
from
"
../../bufferIO
"
;
import
{
numberToCardZone
}
from
"
../../util
"
;
import
MsgShuffleSetCard
=
ygopro
.
StocGameMessage
.
MsgShuffleSetCard
;
/*
* Msg Shuffle Set Card
* @param - TODO
*
* @usage - 盖卡切洗
* */
export
default
(
data
:
Uint8Array
)
=>
{
const
reader
=
new
BufferReaderExt
(
data
);
const
zone
=
numberToCardZone
(
reader
.
inner
.
readUint8
());
const
count
=
reader
.
inner
.
readUint8
();
const
from_locations
=
[];
const
overlay_locations
=
[];
// TODO: 这个字段是否有用?
for
(
let
i
=
0
;
i
<
count
;
i
++
)
{
from_locations
.
push
(
reader
.
readCardLocation
());
}
for
(
let
i
=
0
;
i
<
count
;
i
++
)
{
overlay_locations
.
push
(
reader
.
readCardLocation
());
}
return
new
MsgShuffleSetCard
({
zone
,
from_locations
,
overlay_locations
,
});
};
src/service/duel/becomeTarget.ts
View file @
b4e4a4e8
...
@@ -10,7 +10,7 @@ export default (becomeTarget: ygopro.StocGameMessage.MsgBecomeTarget) => {
...
@@ -10,7 +10,7 @@ export default (becomeTarget: ygopro.StocGameMessage.MsgBecomeTarget) => {
);
);
if
(
target
)
{
if
(
target
)
{
console
.
info
(
`
${
target
.
meta
.
text
.
name
}
become target`
);
console
.
info
(
`
${
target
.
meta
.
text
.
name
}
become target`
);
// TODO: 动画
target
.
selected
=
true
;
}
else
{
}
else
{
console
.
warn
(
`<BecomeTarget>target from
${
location
}
is null`
);
console
.
warn
(
`<BecomeTarget>target from
${
location
}
is null`
);
}
}
...
...
src/service/duel/chainEnd.ts
View file @
b4e4a4e8
...
@@ -15,4 +15,12 @@ export default (_chainEnd: ygopro.StocGameMessage.MsgChainEnd) => {
...
@@ -15,4 +15,12 @@ export default (_chainEnd: ygopro.StocGameMessage.MsgChainEnd) => {
console
.
warn
(
`<ChainEnd>target from
${
chain
}
is null`
);
console
.
warn
(
`<ChainEnd>target from
${
chain
}
is null`
);
}
}
}
}
// 目前selected字段只会涉及连锁过程某些卡成为效果对象,
// 因此在连锁结束的时候把selected标记清掉。
//
// TODO: 这里每次都要全部遍历一遍,后续可以优化下
for
(
const
card
of
cardStore
.
inner
)
{
card
.
selected
=
false
;
}
};
};
src/service/duel/fieldDisabled.ts
0 → 100644
View file @
b4e4a4e8
import
{
ygopro
}
from
"
@/api
"
;
import
{
placeStore
}
from
"
@/stores
"
;
import
MsgFieldDisabled
=
ygopro
.
StocGameMessage
.
MsgFieldDisabled
;
export
default
(
fieldDisabled
:
MsgFieldDisabled
)
=>
{
for
(
const
action
of
fieldDisabled
.
actions
)
{
switch
(
action
.
zone
)
{
case
ygopro
.
CardZone
.
MZONE
:
case
ygopro
.
CardZone
.
SZONE
:
placeStore
.
set
(
action
.
zone
,
action
.
controller
,
action
.
sequence
,
{
interactivity
:
undefined
,
disabled
:
action
.
disabled
,
});
break
;
default
:
console
.
warn
(
"
<FieldDisabled>zone is not MZONE nor SZONE!
"
);
}
}
};
src/service/duel/gameMsg.ts
View file @
b4e4a4e8
...
@@ -12,6 +12,7 @@ import onMsgChaining from "./chaining";
...
@@ -12,6 +12,7 @@ import onMsgChaining from "./chaining";
import
onMsgChainSolved
from
"
./chainSolved
"
;
import
onMsgChainSolved
from
"
./chainSolved
"
;
import
onConfirmCards
from
"
./confirmCards
"
;
import
onConfirmCards
from
"
./confirmCards
"
;
import
onMsgDraw
from
"
./draw
"
;
import
onMsgDraw
from
"
./draw
"
;
import
onMsgFieldDisabled
from
"
./fieldDisabled
"
;
import
onMsgFilpSummoned
from
"
./flipSummoned
"
;
import
onMsgFilpSummoned
from
"
./flipSummoned
"
;
import
onMsgFlipSummoning
from
"
./flipSummoning
"
;
import
onMsgFlipSummoning
from
"
./flipSummoning
"
;
import
onMsgHint
from
"
./hint
"
;
import
onMsgHint
from
"
./hint
"
;
...
@@ -35,7 +36,9 @@ import onMsgSelectTribute from "./selectTribute";
...
@@ -35,7 +36,9 @@ import onMsgSelectTribute from "./selectTribute";
import
onMsgSelectUnselectCard
from
"
./selectUnselectCard
"
;
import
onMsgSelectUnselectCard
from
"
./selectUnselectCard
"
;
import
onMsgSelectYesNo
from
"
./selectYesNo
"
;
import
onMsgSelectYesNo
from
"
./selectYesNo
"
;
import
onMsgSet
from
"
./set
"
;
import
onMsgSet
from
"
./set
"
;
import
onMsgShuffleDeck
from
"
./shuffleDeck
"
;
import
onMsgShuffleHand
from
"
./shuffleHand
"
;
import
onMsgShuffleHand
from
"
./shuffleHand
"
;
import
onMsgShuffleSetCard
from
"
./shuffleSetCard
"
;
import
onMsgSortCard
from
"
./sortCard
"
;
import
onMsgSortCard
from
"
./sortCard
"
;
import
onMsgSpSummoned
from
"
./spSummoned
"
;
import
onMsgSpSummoned
from
"
./spSummoned
"
;
import
onMsgSpSummoning
from
"
./spSummoning
"
;
import
onMsgSpSummoning
from
"
./spSummoning
"
;
...
@@ -186,7 +189,7 @@ async function _handleGameMsg(pb: ygopro.YgoStocMsg) {
...
@@ -186,7 +189,7 @@ async function _handleGameMsg(pb: ygopro.YgoStocMsg) {
break
;
break
;
}
}
case
"
update_data
"
:
{
case
"
update_data
"
:
{
onMsgUpdateData
(
msg
.
update_data
);
await
onMsgUpdateData
(
msg
.
update_data
);
break
;
break
;
}
}
...
@@ -310,6 +313,21 @@ async function _handleGameMsg(pb: ygopro.YgoStocMsg) {
...
@@ -310,6 +313,21 @@ async function _handleGameMsg(pb: ygopro.YgoStocMsg) {
break
;
break
;
}
}
case
"
shuffle_set_card
"
:
{
await
onMsgShuffleSetCard
(
msg
.
shuffle_set_card
);
break
;
}
case
"
field_disabled
"
:
{
onMsgFieldDisabled
(
msg
.
field_disabled
);
break
;
}
case
"
shuffle_deck
"
:
{
onMsgShuffleDeck
(
msg
.
shuffle_deck
);
break
;
}
case
"
unimplemented
"
:
{
case
"
unimplemented
"
:
{
onUnimplemented
(
msg
.
unimplemented
);
onUnimplemented
(
msg
.
unimplemented
);
...
...
src/service/duel/selectPlace.ts
View file @
b4e4a4e8
...
@@ -14,12 +14,15 @@ export default (selectPlace: MsgSelectPlace) => {
...
@@ -14,12 +14,15 @@ export default (selectPlace: MsgSelectPlace) => {
case
ygopro
.
CardZone
.
MZONE
:
case
ygopro
.
CardZone
.
MZONE
:
case
ygopro
.
CardZone
.
SZONE
:
case
ygopro
.
CardZone
.
SZONE
:
placeStore
.
set
(
place
.
zone
,
place
.
controller
,
place
.
sequence
,
{
placeStore
.
set
(
place
.
zone
,
place
.
controller
,
place
.
sequence
,
{
interactType
:
InteractType
.
PLACE_SELECTABLE
,
interactivity
:
{
response
:
{
interactType
:
InteractType
.
PLACE_SELECTABLE
,
controller
:
place
.
controller
,
response
:
{
zone
:
place
.
zone
,
controller
:
place
.
controller
,
sequence
:
place
.
sequence
,
zone
:
place
.
zone
,
sequence
:
place
.
sequence
,
},
},
},
disabled
:
false
,
});
});
break
;
break
;
}
}
...
...
src/service/duel/shuffleDeck.ts
0 → 100644
View file @
b4e4a4e8
import
{
ygopro
}
from
"
@/api
"
;
import
{
cardStore
}
from
"
@/stores
"
;
export
default
(
shuffleDeck
:
ygopro
.
StocGameMessage
.
MsgShuffleDeck
)
=>
{
const
player
=
shuffleDeck
.
player
;
for
(
const
card
of
cardStore
.
at
(
ygopro
.
CardZone
.
DECK
,
player
))
{
// 把数据抹掉就好了
card
.
code
=
0
;
card
.
meta
=
{
id
:
0
,
data
:
{},
text
:
{}
};
}
};
src/service/duel/shuffleSetCard.ts
0 → 100644
View file @
b4e4a4e8
import
{
ygopro
}
from
"
@/api
"
;
import
{
eventbus
,
Task
}
from
"
@/infra
"
;
import
{
cardStore
}
from
"
@/stores
"
;
import
MsgShuffleSetCard
=
ygopro
.
StocGameMessage
.
MsgShuffleSetCard
;
// 后端传过来的`from_locations`的列表是切洗前场上卡的location,它们在列表里面按照切洗后的顺序排列
export
default
async
(
shuffleSetCard
:
MsgShuffleSetCard
)
=>
{
const
from_locations
=
shuffleSetCard
.
from_locations
;
const
overlay_locations
=
shuffleSetCard
.
overlay_locations
;
if
(
from_locations
.
length
==
0
)
{
console
.
error
(
"
<ShuffleSetCard>from_locations is empty
"
);
return
;
}
if
(
from_locations
.
length
!=
overlay_locations
.
length
)
{
console
.
error
(
"
<ShuffleSetCard>length of from_locations and overlay_locations not matched
"
);
}
const
count
=
from_locations
.
length
;
for
(
let
i
=
0
;
i
<
count
;
i
++
)
{
const
from
=
from_locations
[
i
];
const
target
=
cardStore
.
at
(
from
.
zone
,
from
.
controller
,
from
.
sequence
);
if
(
target
)
{
// 设置code为0,洗切后的code会由`UpdateData`指定
target
.
code
=
0
;
target
.
meta
.
id
=
0
;
target
.
meta
.
text
.
id
=
0
;
}
else
{
console
.
warn
(
`<ShuffleSetCard>target from
${
from
}
is null`
);
}
// 处理超量
const
overlay_location
=
overlay_locations
[
i
];
if
(
overlay_location
.
zone
>
0
)
{
// 如果没有超量素材,后端会全传0
for
(
const
overlay
of
cardStore
.
findOverlay
(
from
.
zone
,
from
.
controller
,
from
.
sequence
))
{
// 更新sequence
overlay
.
location
.
sequence
=
overlay_location
.
sequence
;
// 渲染动画
await
eventbus
.
call
(
Task
.
Move
,
overlay
.
uuid
);
// 这里其实有个疑惑,如果超量素材也跟着洗切的话,洗切的意义好像就没有了,感觉算是个k社没想好的设计?
}
}
}
};
src/service/duel/start.ts
View file @
b4e4a4e8
...
@@ -62,6 +62,7 @@ export default async (start: ygopro.StocGameMessage.MsgStart) => {
...
@@ -62,6 +62,7 @@ export default async (start: ygopro.StocGameMessage.MsgStart) => {
text
:
{},
text
:
{},
},
},
isToken
:
!
((
i
+
1
)
%
3
),
isToken
:
!
((
i
+
1
)
%
3
),
selected
:
false
,
})
})
)
)
)
)
...
...
src/service/duel/updateData.ts
View file @
b4e4a4e8
import
{
ygopro
}
from
"
@/api
"
;
import
{
fetchCard
,
ygopro
}
from
"
@/api
"
;
import
MsgUpdateData
=
ygopro
.
StocGameMessage
.
MsgUpdateData
;
import
MsgUpdateData
=
ygopro
.
StocGameMessage
.
MsgUpdateData
;
import
{
eventbus
,
Task
}
from
"
@/infra
"
;
import
{
cardStore
}
from
"
@/stores
"
;
import
{
cardStore
}
from
"
@/stores
"
;
export
default
(
updateData
:
MsgUpdateData
)
=>
{
export
default
async
(
updateData
:
MsgUpdateData
)
=>
{
const
{
player
:
controller
,
zone
,
actions
}
=
updateData
;
const
{
player
:
controller
,
zone
,
actions
}
=
updateData
;
if
(
controller
!==
undefined
&&
zone
!==
undefined
&&
actions
!==
undefined
)
{
if
(
controller
!==
undefined
&&
zone
!==
undefined
&&
actions
!==
undefined
)
{
const
field
=
cardStore
.
at
(
zone
,
controller
);
const
field
=
cardStore
.
at
(
zone
,
controller
);
actions
.
forEach
((
action
)
=>
{
for
(
const
action
of
actions
)
{
const
sequence
=
action
.
location
?.
sequence
;
const
sequence
=
action
.
location
?.
sequence
;
if
(
typeof
sequence
!==
"
undefined
"
)
{
if
(
typeof
sequence
!==
"
undefined
"
)
{
const
target
=
field
const
target
=
field
.
filter
((
card
)
=>
card
.
location
.
sequence
===
sequence
)
.
filter
((
card
)
=>
card
.
location
.
sequence
===
sequence
)
.
at
(
0
);
.
at
(
0
);
if
(
target
)
{
if
(
target
)
{
const
meta
=
target
.
meta
;
// 目前只更新以下字段
// 目前只更新以下字段
if
(
action
?.
code
>=
0
)
{
if
(
action
?.
code
>=
0
)
{
meta
.
id
=
action
.
code
;
const
newMeta
=
await
fetchCard
(
action
.
code
);
meta
.
text
.
id
=
action
.
code
;
target
.
code
=
action
.
code
;
target
.
meta
=
newMeta
;
}
}
const
meta
=
target
.
meta
;
if
(
action
.
location
!==
undefined
)
{
if
(
action
.
location
!==
undefined
)
{
target
.
location
.
position
=
action
.
location
.
position
;
if
(
target
.
location
.
position
!=
action
.
location
.
position
)
{
// Currently only update position
target
.
location
.
position
=
action
.
location
.
position
;
// animation
await
eventbus
.
call
(
Task
.
Move
,
target
.
uuid
);
}
}
}
if
(
action
?.
type_
>=
0
)
{
if
(
action
?.
type_
>=
0
)
{
meta
.
data
.
type
=
action
.
type_
;
meta
.
data
.
type
=
action
.
type_
;
...
@@ -48,10 +56,7 @@ export default (updateData: MsgUpdateData) => {
...
@@ -48,10 +56,7 @@ export default (updateData: MsgUpdateData) => {
);
);
console
.
info
(
field
);
console
.
info
(
field
);
}
}
if
(
target
?.
reload
)
{
target
.
reload
=
false
;
}
}
}
}
);
}
}
}
};
};
src/stores/cardStore.ts
View file @
b4e4a4e8
...
@@ -20,11 +20,10 @@ export interface CardType {
...
@@ -20,11 +20,10 @@ export interface CardType {
sequence
:
number
;
sequence
:
number
;
}
>
;
// 选择位置状态下的互动信息
}
>
;
// 选择位置状态下的互动信息
counters
:
{
[
type
:
number
]:
number
};
// 指示器
counters
:
{
[
type
:
number
]:
number
};
// 指示器
reload
?:
boolean
;
// 这个字段会在收到MSG_RELOAD_FIELD的时候设置成true,在收到MSG_UPDATE_DATE的时候设置成false
isToken
:
boolean
;
// 是否是token
isToken
:
boolean
;
// 是否是token
chainIndex
?:
number
/*连锁的序号,如果为空表示不在连锁
chainIndex
?:
number
/*连锁的序号,如果为空表示不在连锁
TODO: 目前是妥协的设计,因为其实一张卡是可以在同一个连锁链中被连锁多次的,这里为了避免太过复杂只保存最后的连锁序号*/
;
TODO: 目前是妥协的设计,因为其实一张卡是可以在同一个连锁链中被连锁多次的,这里为了避免太过复杂只保存最后的连锁序号*/
;
selected
:
boolean
;
// 当前卡是否被选择成为效果的对象
}
}
class
CardStore
{
class
CardStore
{
...
...
src/stores/placeStore.ts
View file @
b4e4a4e8
...
@@ -15,31 +15,60 @@ export type PlaceInteractivity =
...
@@ -15,31 +15,60 @@ export type PlaceInteractivity =
const
{
MZONE
,
SZONE
}
=
ygopro
.
CardZone
;
const
{
MZONE
,
SZONE
}
=
ygopro
.
CardZone
;
export
interface
BlockState
{
interactivity
?:
PlaceInteractivity
;
// 互动性
disabled
:
boolean
;
// 是否被禁用
}
export
const
placeStore
=
proxy
({
export
const
placeStore
=
proxy
({
inner
:
{
inner
:
{
[
MZONE
]:
{
[
MZONE
]:
{
me
:
Array
.
from
({
length
:
7
}).
map
(()
=>
undefined
as
PlaceInteractivity
),
me
:
Array
.
from
({
length
:
7
}).
map
(
op
:
Array
.
from
({
length
:
7
}).
map
(()
=>
undefined
as
PlaceInteractivity
),
()
=>
({
interactivity
:
undefined
,
disabled
:
false
,
}
as
BlockState
)
),
op
:
Array
.
from
({
length
:
7
}).
map
(
()
=>
({
interactivity
:
undefined
,
disabled
:
false
,
}
as
BlockState
)
),
},
},
[
SZONE
]:
{
[
SZONE
]:
{
me
:
Array
.
from
({
length
:
6
}).
map
(()
=>
undefined
as
PlaceInteractivity
),
me
:
Array
.
from
({
length
:
6
}).
map
(
op
:
Array
.
from
({
length
:
6
}).
map
(()
=>
undefined
as
PlaceInteractivity
),
()
=>
({
interactivity
:
undefined
,
disabled
:
false
,
}
as
BlockState
)
),
op
:
Array
.
from
({
length
:
6
}).
map
(
()
=>
({
interactivity
:
undefined
,
disabled
:
false
,
}
as
BlockState
)
),
},
},
},
},
set
(
set
(
zone
:
ygopro
.
CardZone
.
MZONE
|
ygopro
.
CardZone
.
SZONE
,
zone
:
ygopro
.
CardZone
.
MZONE
|
ygopro
.
CardZone
.
SZONE
,
controller
:
number
,
controller
:
number
,
sequence
:
number
,
sequence
:
number
,
placeInteractivity
:
PlaceInteractivity
state
:
BlockState
)
{
)
{
placeStore
.
inner
[
zone
][
matStore
.
isMe
(
controller
)
?
"
me
"
:
"
op
"
][
sequence
]
=
placeStore
.
inner
[
zone
][
matStore
.
isMe
(
controller
)
?
"
me
"
:
"
op
"
][
sequence
]
=
placeInteractivity
;
state
;
},
},
clearAll
()
{
clearAll
Interactivity
()
{
([
"
me
"
,
"
op
"
]
as
const
).
forEach
((
who
)
=>
{
([
"
me
"
,
"
op
"
]
as
const
).
forEach
((
who
)
=>
{
([
MZONE
,
SZONE
]
as
const
).
forEach
((
where
)
=>
{
([
MZONE
,
SZONE
]
as
const
).
forEach
((
where
)
=>
{
placeStore
.
inner
[
where
][
who
]
=
placeStore
.
inner
[
where
][
who
].
map
(
placeStore
.
inner
[
where
][
who
]
.
forEach
(
(
)
=>
undefined
(
block
)
=>
(
block
.
interactivity
=
undefined
)
);
);
});
});
});
});
...
...
src/ui/Duel/PlayMat/Bg/index.tsx
View file @
b4e4a4e8
import
"
./index.scss
"
;
import
"
./index.scss
"
;
import
classnames
from
"
classnames
"
;
import
classnames
from
"
classnames
"
;
import
{
type
FC
}
from
"
react
"
;
import
{
type
CSSProperties
,
type
FC
}
from
"
react
"
;
import
{
type
INTERNAL_Snapshot
as
Snapshot
,
useSnapshot
}
from
"
valtio
"
;
import
{
type
INTERNAL_Snapshot
as
Snapshot
,
useSnapshot
}
from
"
valtio
"
;
import
{
sendSelectPlaceResponse
,
ygopro
}
from
"
@/api
"
;
import
{
sendSelectPlaceResponse
,
ygopro
}
from
"
@/api
"
;
import
{
cardStore
,
type
PlaceInteractivity
,
placeStore
}
from
"
@/stores
"
;
import
{
BlockState
,
cardStore
,
type
PlaceInteractivity
,
placeStore
,
}
from
"
@/stores
"
;
// Block被禁用的样式
const
BgDisabledStyle
=
{
background
:
`linear-gradient(
to top right,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0) calc(50% - 1.5px),
red 50%,
rgba(0, 0, 0, 0) calc(50% + 1.5px),
rgba(0, 0, 0, 0) 100%
), linear-gradient(
to bottom right,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0) calc(50% - 1.5px),
red 50%,
rgba(0, 0, 0, 0) calc(50% + 1.5px),
rgba(0, 0, 0, 0) 100%
)`
,
};
const
BgExtraRow
:
FC
<
{
const
BgExtraRow
:
FC
<
{
meSnap
:
Snapshot
<
PlaceInteractivity
[]
>
;
meSnap
:
Snapshot
<
BlockState
[]
>
;
opSnap
:
Snapshot
<
PlaceInteractivity
[]
>
;
opSnap
:
Snapshot
<
BlockState
[]
>
;
}
>
=
({
meSnap
,
opSnap
})
=>
{
}
>
=
({
meSnap
,
opSnap
})
=>
{
return
(
return
(
<
div
className=
{
classnames
(
"
bg-row
"
)
}
>
<
div
className=
{
classnames
(
"
bg-row
"
)
}
>
...
@@ -17,11 +41,16 @@ const BgExtraRow: FC<{
...
@@ -17,11 +41,16 @@ const BgExtraRow: FC<{
<
div
<
div
key=
{
i
}
key=
{
i
}
className=
{
classnames
(
"
block
"
,
"
extra
"
,
{
className=
{
classnames
(
"
block
"
,
"
extra
"
,
{
highlight
:
!!
meSnap
[
i
]
||
!!
opSnap
[
i
]
,
highlight
:
!!
meSnap
[
i
]
.
interactivity
||
!!
opSnap
[
i
].
interactivity
,
})
}
})
}
style=
{
meSnap
[
i
].
disabled
||
opSnap
[
i
].
disabled
?
(
BgDisabledStyle
as
CSSProperties
)
:
{}
}
onClick=
{
()
=>
{
onClick=
{
()
=>
{
onBlockClick
(
meSnap
[
i
]);
onBlockClick
(
meSnap
[
i
]
.
interactivity
);
onBlockClick
(
opSnap
[
i
]);
onBlockClick
(
opSnap
[
i
]
.
interactivity
);
}
}
}
}
>
>
{
<
DecoTriangles
/>
}
{
<
DecoTriangles
/>
}
...
@@ -34,7 +63,7 @@ const BgExtraRow: FC<{
...
@@ -34,7 +63,7 @@ const BgExtraRow: FC<{
const
BgRow
:
FC
<
{
const
BgRow
:
FC
<
{
isSzone
?:
boolean
;
isSzone
?:
boolean
;
opponent
?:
boolean
;
opponent
?:
boolean
;
snap
:
Snapshot
<
PlaceInteractivity
[]
>
;
snap
:
Snapshot
<
BlockState
[]
>
;
}
>
=
({
isSzone
=
false
,
opponent
=
false
,
snap
})
=>
(
}
>
=
({
isSzone
=
false
,
opponent
=
false
,
snap
})
=>
(
<
div
className=
{
classnames
(
"
bg-row
"
,
{
opponent
})
}
>
<
div
className=
{
classnames
(
"
bg-row
"
,
{
opponent
})
}
>
{
Array
.
from
({
length
:
5
}).
map
((
_
,
i
)
=>
(
{
Array
.
from
({
length
:
5
}).
map
((
_
,
i
)
=>
(
...
@@ -42,9 +71,10 @@ const BgRow: FC<{
...
@@ -42,9 +71,10 @@ const BgRow: FC<{
key=
{
i
}
key=
{
i
}
className=
{
classnames
(
"
block
"
,
{
className=
{
classnames
(
"
block
"
,
{
szone
:
isSzone
,
szone
:
isSzone
,
highlight
:
!!
snap
[
i
],
highlight
:
!!
snap
[
i
]
.
interactivity
,
})
}
})
}
onClick=
{
()
=>
onBlockClick
(
snap
[
i
])
}
style=
{
snap
[
i
].
disabled
?
(
BgDisabledStyle
as
CSSProperties
)
:
{}
}
onClick=
{
()
=>
onBlockClick
(
snap
[
i
].
interactivity
)
}
>
>
{
<
DecoTriangles
/>
}
{
<
DecoTriangles
/>
}
</
div
>
</
div
>
...
@@ -72,7 +102,7 @@ const onBlockClick = (placeInteractivity: PlaceInteractivity) => {
...
@@ -72,7 +102,7 @@ const onBlockClick = (placeInteractivity: PlaceInteractivity) => {
if
(
placeInteractivity
)
{
if
(
placeInteractivity
)
{
sendSelectPlaceResponse
(
placeInteractivity
.
response
);
sendSelectPlaceResponse
(
placeInteractivity
.
response
);
cardStore
.
inner
.
forEach
((
card
)
=>
(
card
.
idleInteractivities
=
[]));
cardStore
.
inner
.
forEach
((
card
)
=>
(
card
.
idleInteractivities
=
[]));
placeStore
.
clearAll
();
placeStore
.
clearAll
Interactivity
();
}
}
};
};
...
...
src/ui/Duel/PlayMat/Card/index.scss
View file @
b4e4a4e8
...
@@ -9,8 +9,10 @@ section#mat {
...
@@ -9,8 +9,10 @@ section#mat {
.card-img-wrap
{
.card-img-wrap
{
transform-style
:
preserve-3d
;
transform-style
:
preserve-3d
;
position
:
relative
;
position
:
relative
;
height
:
100%
;
margin
:
auto
auto
;
width
:
100%
;
top
:
2%
;
height
:
96%
;
width
:
96%
;
transform
:
translateZ
(
calc
(
var
(
--
z
)
*
1px
+
0
.1px
))
transform
:
translateZ
(
calc
(
var
(
--
z
)
*
1px
+
0
.1px
))
rotateY
(
calc
(
var
(
--
ry
)
*
1deg
));
rotateY
(
calc
(
var
(
--
ry
)
*
1deg
));
transition
:
0
.2s
scale
;
transition
:
0
.2s
scale
;
...
@@ -47,6 +49,41 @@ section#mat {
...
@@ -47,6 +49,41 @@ section#mat {
background-color
:
transparent
;
background-color
:
transparent
;
// filter: blur(2px);
// filter: blur(2px);
}
}
// 卡片被选中后的流光特效
// ref: https://github.com/Mr-majifu/Animated-Profile-Card02/blob/master/style.css
.card-streamer
{
position
:
absolute
;
inset
:
0
;
background
:
#000
;
overflow
:
hidden
;
}
.
card-streamer
:
:
before
{
content
:
''
;
position
:
absolute
;
top
:
50%
;
left
:
50%
;
width
:
400%
;
height
:
80%
;
background
:
linear-gradient
(
transparent
,
#45f3ff
,
#45f3ff
,
#45f3ff
,
transparent
);
animation
:
stream
2s
linear
infinite
;
}
.
card-streamer
:
:
after
{
content
:
''
;
position
:
absolute
;
/* https://developer.mozilla.org/en-US/docs/Web/CSS/inset */
inset
:
3px
;
background
:
#292929
;
}
@keyframes
stream
{
0
%
{
transform
:
translate
(
-50%
,
-50%
)
rotate
(
0deg
);
}
100
%
{
transform
:
translate
(
-50%
,
-50%
)
rotate
(
360deg
);
}
}
.card-focus
{
.card-focus
{
position
:
absolute
;
position
:
absolute
;
width
:
calc
(
100%
*
var
(
--
focus-scale
));
width
:
calc
(
100%
*
var
(
--
focus-scale
));
...
...
src/ui/Duel/PlayMat/Card/index.tsx
View file @
b4e4a4e8
...
@@ -241,6 +241,7 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => {
...
@@ -241,6 +241,7 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => {
<
YgoCard
className=
"card-back"
isBack
/>
<
YgoCard
className=
"card-back"
isBack
/>
</
div
>
</
div
>
</
Dropdown
>
</
Dropdown
>
{
snap
.
selected
?
<
div
className=
"card-streamer"
/>
:
<></>
}
</
animated
.
div
>
</
animated
.
div
>
);
);
});
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment