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
7ace8dc5
Commit
7ace8dc5
authored
Jun 18, 2023
by
timel
Committed by
Chunchi Che
Jun 22, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: progress 50%
parent
8e322240
Changes
22
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
644 additions
and
25 deletions
+644
-25
neos-protobuf
neos-protobuf
+1
-1
src/main.tsx
src/main.tsx
+5
-1
src/service/duel/selectCard.ts
src/service/duel/selectCard.ts
+16
-5
src/service/duel/selectChain.ts
src/service/duel/selectChain.ts
+14
-2
src/service/duel/selectSum.ts
src/service/duel/selectSum.ts
+23
-1
src/service/duel/selectTribute.ts
src/service/duel/selectTribute.ts
+15
-2
src/service/duel/selectUnselectCard.ts
src/service/duel/selectUnselectCard.ts
+23
-1
src/service/utils/fetchCheckCardMeta.ts
src/service/utils/fetchCheckCardMeta.ts
+82
-0
src/service/utils/index.ts
src/service/utils/index.ts
+1
-0
src/styles/core.scss
src/styles/core.scss
+6
-1
src/ui/Duel/Main.tsx
src/ui/Duel/Main.tsx
+8
-0
src/ui/Duel/Message/NewModal/index.scss
src/ui/Duel/Message/NewModal/index.scss
+17
-0
src/ui/Duel/Message/NewModal/index.tsx
src/ui/Duel/Message/NewModal/index.tsx
+24
-0
src/ui/Duel/Message/NewSelectActionModal/index.scss
src/ui/Duel/Message/NewSelectActionModal/index.scss
+45
-0
src/ui/Duel/Message/NewSelectActionModal/index.tsx
src/ui/Duel/Message/NewSelectActionModal/index.tsx
+255
-0
src/ui/Duel/PlayMat/Bg/index.scss
src/ui/Duel/PlayMat/Bg/index.scss
+27
-1
src/ui/Duel/PlayMat/Bg/index.tsx
src/ui/Duel/PlayMat/Bg/index.tsx
+14
-2
src/ui/Duel/PlayMat/Card/index.tsx
src/ui/Duel/PlayMat/Card/index.tsx
+6
-7
src/ui/Duel/utils/groupBy.ts
src/ui/Duel/utils/groupBy.ts
+1
-1
src/ui/Shared/YgoCard/index.scss
src/ui/Shared/YgoCard/index.scss
+11
-0
src/ui/Shared/YgoCard/index.tsx
src/ui/Shared/YgoCard/index.tsx
+49
-0
src/ui/Shared/index.ts
src/ui/Shared/index.ts
+1
-0
No files found.
neos-protobuf
@
b67b483c
Subproject commit
975e4a815f7fc394247f5af6ccb22a0742379f33
Subproject commit
b67b483ce9db064611619a2e1a8b8767b100d035
src/main.tsx
View file @
7ace8dc5
...
@@ -24,16 +24,20 @@ import zhCN from "antd/locale/zh_CN";
...
@@ -24,16 +24,20 @@ import zhCN from "antd/locale/zh_CN";
import
React
from
"
react
"
;
import
React
from
"
react
"
;
import
ReactDOM
from
"
react-dom/client
"
;
import
ReactDOM
from
"
react-dom/client
"
;
import
{
BrowserRouter
}
from
"
react-router-dom
"
;
import
{
BrowserRouter
}
from
"
react-router-dom
"
;
import
{
ProConfigProvider
}
from
"
@ant-design/pro-provider
"
;
import
Neos
from
"
./ui/Neos
"
;
import
Neos
from
"
./ui/Neos
"
;
const
root
=
ReactDOM
.
createRoot
(
const
root
=
ReactDOM
.
createRoot
(
document
.
getElementById
(
"
root
"
)
as
HTMLElement
document
.
getElementById
(
"
root
"
)
as
HTMLElement
);
);
root
.
render
(
root
.
render
(
<
BrowserRouter
>
<
BrowserRouter
>
<
ConfigProvider
theme=
{
{
algorithm
:
theme
.
darkAlgorithm
}
}
locale=
{
zhCN
}
>
<
ConfigProvider
theme=
{
{
algorithm
:
theme
.
darkAlgorithm
}
}
locale=
{
zhCN
}
>
<
ProConfigProvider
dark
>
<
Neos
/>
<
Neos
/>
</
ProConfigProvider
>
</
ConfigProvider
>
</
ConfigProvider
>
</
BrowserRouter
>
</
BrowserRouter
>
);
);
src/service/duel/selectCard.ts
View file @
7ace8dc5
...
@@ -2,11 +2,11 @@ import { ygopro } from "@/api";
...
@@ -2,11 +2,11 @@ import { ygopro } from "@/api";
import
MsgSelectCard
=
ygopro
.
StocGameMessage
.
MsgSelectCard
;
import
MsgSelectCard
=
ygopro
.
StocGameMessage
.
MsgSelectCard
;
import
{
fetchCheckCardMeta
,
messageStore
}
from
"
@/stores
"
;
import
{
fetchCheckCardMeta
,
messageStore
}
from
"
@/stores
"
;
export
default
(
selectCard
:
MsgSelectCard
)
=>
{
import
{
displaySelectActionsModal
}
from
"
@/ui/Duel/Message/NewSelectActionModal
"
;
const
cancelable
=
selectCard
.
cancelable
;
import
{
fetchCheckCardMeta
as
FIXME_fetchCheckCardMeta
}
from
"
../utils
"
;
const
min
=
selectCard
.
min
;
const
max
=
selectCard
.
max
;
export
default
async
(
selectCard
:
MsgSelectCard
)
=>
{
const
cards
=
selectCard
.
cards
;
const
{
cancelable
,
min
,
max
,
cards
}
=
selectCard
;
// TODO: handle release_param
// TODO: handle release_param
messageStore
.
selectCardActions
.
min
=
min
;
messageStore
.
selectCardActions
.
min
=
min
;
...
@@ -22,4 +22,15 @@ export default (selectCard: MsgSelectCard) => {
...
@@ -22,4 +22,15 @@ export default (selectCard: MsgSelectCard) => {
}
}
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
const
{
selecteds
,
mustSelects
,
selectables
}
=
await
FIXME_fetchCheckCardMeta
(
cards
);
await
displaySelectActionsModal
({
cancelable
,
min
,
max
,
selecteds
,
mustSelects
,
selectables
,
});
};
};
src/service/duel/selectChain.ts
View file @
7ace8dc5
...
@@ -5,11 +5,13 @@ import {
...
@@ -5,11 +5,13 @@ import {
fetchSelectHintMeta
,
fetchSelectHintMeta
,
messageStore
,
messageStore
,
}
from
"
@/stores
"
;
}
from
"
@/stores
"
;
import
{
displaySelectActionsModal
}
from
"
@/ui/Duel/Message/NewSelectActionModal
"
;
import
{
fetchCheckCardMeta
as
FIXME_fetchCheckCardMeta
}
from
"
../utils
"
;
const
NeosConfig
=
useConfig
();
const
NeosConfig
=
useConfig
();
type
MsgSelectChain
=
ygopro
.
StocGameMessage
.
MsgSelectChain
;
type
MsgSelectChain
=
ygopro
.
StocGameMessage
.
MsgSelectChain
;
export
default
(
selectChain
:
MsgSelectChain
)
=>
{
export
default
async
(
selectChain
:
MsgSelectChain
)
=>
{
const
spCount
=
selectChain
.
special_count
;
const
spCount
=
selectChain
.
special_count
;
const
forced
=
selectChain
.
forced
;
const
forced
=
selectChain
.
forced
;
const
_hint0
=
selectChain
.
hint0
;
const
_hint0
=
selectChain
.
hint0
;
...
@@ -83,7 +85,17 @@ export default (selectChain: MsgSelectChain) => {
...
@@ -83,7 +85,17 @@ export default (selectChain: MsgSelectChain) => {
});
});
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
const
{
selecteds
,
mustSelects
,
selectables
}
=
await
FIXME_fetchCheckCardMeta
(
chains
);
await
displaySelectActionsModal
({
isChain
:
true
,
cancelable
:
!
forced
,
min
:
1
,
max
:
1
,
selecteds
,
mustSelects
,
selectables
,
});
break
;
break
;
}
}
case
4
:
{
case
4
:
{
...
...
src/service/duel/selectSum.ts
View file @
7ace8dc5
import
{
ygopro
}
from
"
@/api
"
;
import
{
ygopro
}
from
"
@/api
"
;
import
{
fetchCheckCardMeta
,
messageStore
}
from
"
@/stores
"
;
import
{
fetchCheckCardMeta
,
messageStore
}
from
"
@/stores
"
;
import
{
displaySelectActionsModal
}
from
"
@/ui/Duel/Message/NewSelectActionModal
"
;
import
{
fetchCheckCardMeta
as
FIXME_fetchCheckCardMeta
}
from
"
../utils
"
;
type
MsgSelectSum
=
ygopro
.
StocGameMessage
.
MsgSelectSum
;
type
MsgSelectSum
=
ygopro
.
StocGameMessage
.
MsgSelectSum
;
export
default
(
selectSum
:
MsgSelectSum
)
=>
{
export
default
async
(
selectSum
:
MsgSelectSum
)
=>
{
messageStore
.
selectCardActions
.
overflow
=
selectSum
.
overflow
!=
0
;
messageStore
.
selectCardActions
.
overflow
=
selectSum
.
overflow
!=
0
;
messageStore
.
selectCardActions
.
totalLevels
=
selectSum
.
level_sum
;
messageStore
.
selectCardActions
.
totalLevels
=
selectSum
.
level_sum
;
messageStore
.
selectCardActions
.
min
=
selectSum
.
min
;
messageStore
.
selectCardActions
.
min
=
selectSum
.
min
;
...
@@ -18,4 +20,24 @@ export default (selectSum: MsgSelectSum) => {
...
@@ -18,4 +20,24 @@ export default (selectSum: MsgSelectSum) => {
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
const
{
selecteds
:
selecteds1
,
mustSelects
:
mustSelect1
,
selectables
:
selectable1
,
}
=
await
FIXME_fetchCheckCardMeta
(
selectSum
.
must_select_cards
,
false
,
true
);
const
{
selecteds
:
selecteds2
,
mustSelects
:
mustSelect2
,
selectables
:
selectable2
,
}
=
await
FIXME_fetchCheckCardMeta
(
selectSum
.
selectable_cards
);
await
displaySelectActionsModal
({
overflow
:
selectSum
.
overflow
!==
0
,
totalLevels
:
selectSum
.
level_sum
,
min
:
selectSum
.
min
,
max
:
selectSum
.
max
,
selecteds
:
[...
selecteds1
,
...
selecteds2
],
mustSelects
:
[...
mustSelect1
,
...
mustSelect2
],
selectables
:
[...
selectable1
,
...
selectable2
],
});
};
};
src/service/duel/selectTribute.ts
View file @
7ace8dc5
import
{
ygopro
}
from
"
@/api
"
;
import
{
ygopro
}
from
"
@/api
"
;
import
{
fetchCheckCardMeta
,
messageStore
}
from
"
@/stores
"
;
import
{
fetchCheckCardMeta
,
messageStore
}
from
"
@/stores
"
;
import
{
displaySelectActionsModal
}
from
"
@/ui/Duel/Message/NewSelectActionModal
"
;
import
{
fetchCheckCardMeta
as
FIXME_fetchCheckCardMeta
}
from
"
../utils
"
;
type
MsgSelectTribute
=
ygopro
.
StocGameMessage
.
MsgSelectTribute
;
type
MsgSelectTribute
=
ygopro
.
StocGameMessage
.
MsgSelectTribute
;
export
default
(
selectTribute
:
MsgSelectTribute
)
=>
{
export
default
async
(
selectTribute
:
MsgSelectTribute
)
=>
{
// TODO: 当玩家选择卡数大于`max`时,是否也合法?
// TODO: 当玩家选择卡数大于`max`时,是否也合法?
messageStore
.
selectCardActions
.
overflow
=
true
;
messageStore
.
selectCardActions
.
overflow
=
true
;
messageStore
.
selectCardActions
.
totalLevels
=
0
;
messageStore
.
selectCardActions
.
totalLevels
=
0
;
...
@@ -16,4 +17,16 @@ export default (selectTribute: MsgSelectTribute) => {
...
@@ -16,4 +17,16 @@ export default (selectTribute: MsgSelectTribute) => {
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
const
{
selecteds
,
mustSelects
,
selectables
}
=
await
FIXME_fetchCheckCardMeta
(
selectTribute
.
selectable_cards
);
await
displaySelectActionsModal
({
overflow
:
true
,
totalLevels
:
0
,
min
:
selectTribute
.
min
,
max
:
selectTribute
.
max
,
selecteds
,
mustSelects
,
selectables
,
});
};
};
src/service/duel/selectUnselectCard.ts
View file @
7ace8dc5
import
{
ygopro
}
from
"
@/api
"
;
import
{
ygopro
}
from
"
@/api
"
;
import
{
fetchCheckCardMeta
,
messageStore
}
from
"
@/stores
"
;
import
{
fetchCheckCardMeta
,
messageStore
}
from
"
@/stores
"
;
import
{
displaySelectActionsModal
}
from
"
@/ui/Duel/Message/NewSelectActionModal
"
;
import
{
fetchCheckCardMeta
as
FIXME_fetchCheckCardMeta
}
from
"
../utils
"
;
type
MsgSelectUnselectCard
=
ygopro
.
StocGameMessage
.
MsgSelectUnselectCard
;
type
MsgSelectUnselectCard
=
ygopro
.
StocGameMessage
.
MsgSelectUnselectCard
;
export
default
async
({
export
default
async
({
...
@@ -27,4 +28,25 @@ export default async ({
...
@@ -27,4 +28,25 @@ export default async ({
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isValid
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
messageStore
.
selectCardActions
.
isOpen
=
true
;
const
{
selecteds
:
selecteds1
,
mustSelects
:
mustSelect1
,
selectables
:
selectable1
,
}
=
await
FIXME_fetchCheckCardMeta
(
selectableCards
);
const
{
selecteds
:
selecteds2
,
mustSelects
:
mustSelect2
,
selectables
:
selectable2
,
}
=
await
FIXME_fetchCheckCardMeta
(
selectedCards
,
true
);
await
displaySelectActionsModal
({
finishable
,
cancelable
,
min
:
min
,
max
:
max
,
single
:
true
,
selecteds
:
[...
selecteds1
,
...
selecteds2
],
mustSelects
:
[...
mustSelect1
,
...
mustSelect2
],
selectables
:
[...
selectable1
,
...
selectable2
],
});
};
};
src/service/utils/fetchCheckCardMeta.ts
0 → 100644
View file @
7ace8dc5
import
type
{
ygopro
}
from
"
@/api
"
;
import
{
fetchCard
,
getCardStr
}
from
"
@/api/cards
"
;
import
{
cardStore
}
from
"
@/stores
"
;
import
type
{
Option
}
from
"
@/ui/Duel/Message/NewSelectActionModal
"
;
const
helper
=
async
(
{
code
,
location
,
level1
,
level2
,
response
,
effectDescCode
,
}:
{
code
:
number
;
location
:
ygopro
.
CardLocation
;
level1
?:
number
;
level2
?:
number
;
response
:
number
;
effectDescCode
?:
number
;
},
selecteds
:
Option
[],
mustSelects
:
Option
[],
selectables
:
Option
[],
selected
?:
boolean
,
mustSelect
?:
boolean
)
=>
{
const
controller
=
location
.
controller
;
const
newID
=
code
!=
0
?
code
:
cardStore
.
at
(
location
.
zone
,
controller
,
location
.
sequence
)?.
code
||
0
;
const
meta
=
await
fetchCard
(
newID
);
const
effectDesc
=
effectDescCode
?
getCardStr
(
meta
,
effectDescCode
&
0xf
)
:
undefined
;
const
newOption
=
{
meta
,
location
:
location
.
toObject
(),
level1
,
level2
,
effectDesc
,
response
,
};
if
(
selected
)
{
selecteds
.
push
(
newOption
);
}
else
if
(
mustSelect
)
{
mustSelects
.
push
(
newOption
);
}
else
{
selectables
.
push
(
newOption
);
}
};
export
const
fetchCheckCardMeta
=
async
(
cards
:
{
code
:
number
;
location
:
ygopro
.
CardLocation
;
level1
?:
number
;
level2
?:
number
;
response
:
number
;
effectDescCode
?:
number
;
}[],
selected
?:
boolean
,
mustSelect
?:
boolean
)
=>
{
const
selecteds
:
Option
[]
=
[];
const
mustSelects
:
Option
[]
=
[];
const
selectables
:
Option
[]
=
[];
for
(
const
card
of
cards
)
{
await
helper
(
card
,
selecteds
,
mustSelects
,
selectables
,
selected
,
mustSelect
);
// TODO: 研究下改成并行
}
return
{
selecteds
,
mustSelects
,
selectables
};
};
src/service/utils/index.ts
0 → 100644
View file @
7ace8dc5
export
*
from
"
./fetchCheckCardMeta
"
;
src/styles/core.scss
View file @
7ace8dc5
...
@@ -33,7 +33,7 @@ table {
...
@@ -33,7 +33,7 @@ table {
body
{
body
{
color-scheme
:
light
dark
;
color-scheme
:
light
dark
;
color
:
rgba
(
255
,
255
,
255
,
0
.87
);
color
:
rgba
(
255
,
255
,
255
,
0
.87
);
background-color
:
#2
42424
;
background-color
:
#2
02022
;
font
:
87
.5%
/
1
.5em
"Open Sans"
,
sans-serif
;
font
:
87
.5%
/
1
.5em
"Open Sans"
,
sans-serif
;
display
:
flex
;
display
:
flex
;
margin
:
0
;
margin
:
0
;
...
@@ -89,3 +89,8 @@ p {
...
@@ -89,3 +89,8 @@ p {
width
:
100%
;
width
:
100%
;
max-width
:
1000px
;
max-width
:
1000px
;
}
}
img
{
user-select
:
none
;
-webkit-user-drag
:
none
;
}
src/ui/Duel/Main.tsx
View file @
7ace8dc5
...
@@ -14,10 +14,18 @@ import {
...
@@ -14,10 +14,18 @@ import {
YesNoModal
,
YesNoModal
,
}
from
"
./Message
"
;
}
from
"
./Message
"
;
import
{
LifeBar
,
Mat
,
Menu
}
from
"
./PlayMat
"
;
import
{
LifeBar
,
Mat
,
Menu
}
from
"
./PlayMat
"
;
import
{
NewSelectActionsModal
}
from
"
./Message/NewSelectActionModal
"
;
const
NeosDuel
=
()
=>
{
const
NeosDuel
=
()
=>
{
return
(
return
(
<>
<>
<
NewSelectActionsModal
isValid
isChain
selecteds=
{
[]
}
selectables=
{
[]
}
mustSelects=
{
[]
}
/>
<
Alert
/>
<
Alert
/>
<
Menu
/>
<
Menu
/>
<
LifeBar
/>
<
LifeBar
/>
...
...
src/ui/Duel/Message/NewModal/index.scss
0 → 100644
View file @
7ace8dc5
.neos-modal
{
position
:
fixed
;
left
:
0
;
right
:
0
;
top
:
0
!
important
;
bottom
:
0
!
important
;
top
:
-
webkit-fill-available
;
margin
:
auto
;
height
:
fit-content
;
transition
:
0
.3s
;
}
.neos-modal-mini
{
top
:
100%
!
important
;
bottom
:
0
!
important
;
transform
:
translateY
(
calc
(
50%
-
66px
));
}
src/ui/Duel/Message/NewModal/index.tsx
0 → 100644
View file @
7ace8dc5
import
{
Button
,
Modal
,
type
ModalProps
}
from
"
antd
"
;
import
{
type
FC
,
useRef
,
useState
,
type
CSSProperties
}
from
"
react
"
;
import
{
MinusOutlined
}
from
"
@ant-design/icons
"
;
import
classNames
from
"
classnames
"
;
import
"
./index.scss
"
;
interface
Props
extends
ModalProps
{
canBeMinimized
?:
boolean
;
}
export
const
NewModal
:
FC
<
Props
>
=
(
props
)
=>
{
const
{
canBeMinimized
=
true
}
=
props
;
const
[
mini
,
setMini
]
=
useState
(
false
);
return
(
<
Modal
className=
{
classNames
(
"
neos-modal
"
,
{
"
neos-modal-mini
"
:
mini
})
}
centered
onCancel=
{
()
=>
setMini
(
!
mini
)
}
closeIcon=
{
<
MinusOutlined
/>
}
bodyStyle=
{
{
padding
:
"
10px 0
"
}
}
{
...
props
}
/>
);
};
src/ui/Duel/Message/NewSelectActionModal/index.scss
0 → 100644
View file @
7ace8dc5
.checkcard-container
{
position
:
relative
;
// padding-left: 10px;
// &::after {
// position: absolute;
// width: 3px;
// height: 100%;
// content: "";
// z-index: 1;
// left: 0;
// top: 0;
// background-color: rgb(0, 54, 189);
// }
.btns
{
width
:
100%
;
top
:
50%
;
display
:
flex
;
justify-content
:
space-between
;
padding
:
0
10px
;
box-sizing
:
border-box
;
height
:
0
;
button
{
transform
:
translateY
(
-50%
);
}
}
.ant-pro-checkcard
{
border-radius
:
4px
;
overflow
:
hidden
;
}
// 多选卡片的样式
.ant-pro-checkcard-checked
{
&
:
:
before
{
position
:
absolute
;
width
:
100%
;
height
:
100%
;
content
:
""
;
z-index
:
1
;
background-color
:
#0023bf
32
;
box-shadow
:
0
0
0
2px
#0087e6
inset
;
}
&
:
:
after
{
display
:
none
;
}
}
}
src/ui/Duel/Message/NewSelectActionModal/index.tsx
0 → 100644
View file @
7ace8dc5
import
{
CheckCard
,
CheckCardProps
}
from
"
@ant-design/pro-components
"
;
import
{
Button
,
Card
,
Col
,
Popover
,
Row
,
Tabs
,
Segmented
,
Space
,
Typography
,
}
from
"
antd
"
;
import
{
type
FC
,
useState
,
useEffect
}
from
"
react
"
;
import
{
useSnapshot
,
proxy
}
from
"
valtio
"
;
import
{
fetchStrings
,
sendSelectMultiResponse
,
sendSelectSingleResponse
,
}
from
"
@/api
"
;
import
type
{
CardMeta
,
ygopro
}
from
"
@/api
"
;
import
{
useConfig
}
from
"
@/config
"
;
import
{
matStore
}
from
"
@/stores
"
;
import
{
groupBy
}
from
"
../../utils
"
;
import
{
NewModal
}
from
"
../NewModal
"
;
import
{
YgoCard
}
from
"
@/ui/Shared
"
;
import
"
./index.scss
"
;
const
CANCEL_RESPONSE
=
-
1
;
const
FINISH_RESPONSE
=
-
1
;
const
defaultProps
=
{
isOpen
:
false
,
title
:
"
是否要进行连锁
"
,
// 模态框标题
isValid
:
false
,
// FIXME 看起来是最小化用的,看情况是否需要删掉
isChain
:
false
,
min
:
0
,
max
:
0
,
single
:
true
,
selecteds
:
[]
as
Option
[],
// 最少选择多少卡
selectables
:
[]
as
Option
[],
// 最多选择多少卡
mustSelects
:
[]
as
Option
[],
// 单选
cancelable
:
false
,
// 能否取消
finishable
:
false
,
// 选择足够了之后,能否确认
totalLevels
:
0
,
// 需要的总等级数(用于同调/仪式/...)
overflow
:
false
,
// 选择等级时候,是否可以溢出
};
const
localStore
=
proxy
(
defaultProps
);
export
const
NewSelectActionsModal
:
FC
=
()
=>
{
const
{
title
,
isOpen
,
isValid
,
isChain
,
min
,
max
,
single
,
selecteds
,
selectables
,
mustSelects
,
cancelable
,
finishable
,
totalLevels
,
overflow
,
}
=
useSnapshot
(
localStore
);
const
[
response
,
setResponse
]
=
useState
<
Option
[]
>
([]);
const
[
submitable
,
setSubmitable
]
=
useState
(
false
);
const
hint
=
useSnapshot
(
matStore
.
hint
);
const
preHintMsg
=
hint
?.
esHint
||
""
;
const
selectHintMsg
=
hint
?.
esSelectHint
||
"
请选择卡片
"
;
// 判断是否可以提交
useEffect
(()
=>
{
const
[
sumLevel1
,
sumLevel2
]
=
([
"
level1
"
,
"
level2
"
]
as
const
).
map
((
key
)
=>
[...
mustSelects
,
...
response
]
.
map
((
option
)
=>
option
[
key
]
||
0
)
.
reduce
((
sum
,
current
)
=>
sum
+
current
,
0
)
);
const
levelMatched
=
overflow
?
sumLevel1
>=
totalLevels
||
sumLevel2
>=
totalLevels
:
sumLevel1
===
totalLevels
||
sumLevel2
===
totalLevels
;
setSubmitable
(
single
?
response
.
length
==
1
:
response
.
length
>=
min
&&
response
.
length
<=
max
&&
levelMatched
);
},
[
response
.
length
]);
const
grouped
=
groupBy
(
selectables
,
(
option
)
=>
option
.
location
?.
zone
!
);
const
zoneOptions
=
grouped
.
map
((
x
)
=>
({
value
:
x
[
0
],
label
:
fetchStrings
(
"
!system
"
,
x
[
0
]
+
1000
),
}));
const
[
selectedZone
,
setSelectedZone
]
=
useState
(
zoneOptions
[
0
]?.
value
);
const
onSubmit
=
()
=>
{
const
values
=
mustSelects
.
concat
(
response
)
.
map
((
option
)
=>
option
.
response
);
if
(
isChain
)
{
sendSelectSingleResponse
(
values
[
0
]);
}
else
{
sendSelectMultiResponse
(
values
);
}
rs
();
};
const
onFinish
=
()
=>
{
sendSelectSingleResponse
(
FINISH_RESPONSE
);
rs
();
};
const
onCancel
=
()
=>
{
sendSelectSingleResponse
(
CANCEL_RESPONSE
);
rs
();
};
const
[
submitText
,
finishText
,
cancelText
]
=
[
1211
,
1296
,
1295
].
map
((
n
)
=>
fetchStrings
(
"
!system
"
,
n
)
);
return
(
<
NewModal
title=
{
title
}
width=
{
600
}
okButtonProps=
{
{
disabled
:
!
submitable
,
}
}
open=
{
isOpen
}
footer=
{
<>
<
Button
danger
disabled=
{
!
cancelable
}
onClick=
{
onCancel
}
>
{
cancelText
}
</
Button
>
<
Button
type=
"dashed"
disabled=
{
!
finishable
}
onClick=
{
onFinish
}
>
{
finishText
}
</
Button
>
<
Button
type=
"primary"
disabled=
{
!
submitable
}
onClick=
{
onSubmit
}
>
{
submitText
}
</
Button
>
</>
}
>
<
div
className=
"check-container"
>
<
Space
direction=
"vertical"
style=
{
{
width
:
"
100%
"
,
overflow
:
"
hidden
"
}
}
>
<
Selector
zoneOptions=
{
zoneOptions
}
selectedZone=
{
selectedZone
}
onChange=
{
setSelectedZone
as
any
}
/>
{
grouped
.
map
((
options
,
i
)
=>
(
<
div
className=
"checkcard-container"
key=
{
i
}
>
<
CheckCard
.
Group
onChange=
{
setResponse
as
any
}
// TODO 考虑如何设置默认值,比如只有一个的,就直接选中
multiple
style=
{
{
display
:
"
grid
"
,
gridTemplateColumns
:
"
repeat(6, 1fr)
"
,
gap
:
10
,
}
}
>
{
options
[
1
].
map
((
card
,
j
)
=>
(
<
CheckCard
cover=
{
<
YgoCard
code=
{
card
.
meta
.
id
}
/>
}
style=
{
{
width
:
80
,
aspectRatio
:
5.9
/
8.6
,
marginInlineEnd
:
0
,
marginBlockEnd
:
0
,
flexShrink
:
0
,
}
}
key=
{
j
}
value=
{
card
}
/>
))
}
</
CheckCard
.
Group
>
</
div
>
))
}
</
Space
>
</
div
>
</
NewModal
>
);
};
/** 选择区域 */
const
Selector
:
FC
<
{
zoneOptions
:
{
value
:
ygopro
.
CardZone
;
label
:
string
;
}[];
selectedZone
:
ygopro
.
CardZone
;
onChange
:
(
value
:
ygopro
.
CardZone
)
=>
void
;
}
>
=
({
zoneOptions
,
selectedZone
,
onChange
})
=>
zoneOptions
.
length
>
1
?
(
<
Segmented
block
options=
{
zoneOptions
}
style=
{
{
margin
:
"
10px 0
"
}
}
value=
{
selectedZone
}
onChange=
{
onChange
as
any
}
/>
)
:
(
<></>
);
export
interface
Option
{
// card id
meta
:
CardMeta
;
location
?:
ygopro
.
CardLocation
;
// 效果
effectDesc
?:
string
;
// 作为素材的cost,比如同调召唤的星级
level1
?:
number
;
level2
?:
number
;
response
:
number
;
}
const
config
=
useConfig
();
let
rs
:
(
v
?:
any
)
=>
void
=
()
=>
{};
type
Result
=
Option
[];
export
const
displaySelectActionsModal
=
async
(
args
:
Partial
<
Omit
<
typeof
defaultProps
,
"
isOpen
"
>>
)
=>
{
resetSelectActionsModal
();
// 先重置为初始状态
localStore
.
isOpen
=
true
;
Object
.
entries
(
args
).
forEach
(([
key
,
value
])
=>
{
// @ts-ignore
localStore
[
key
]
=
value
;
});
await
new
Promise
<
Result
>
((
resolve
)
=>
(
rs
=
resolve
));
// 等待在组件内resolve
console
.
log
(
"
here
"
);
localStore
.
isOpen
=
false
;
};
const
resetSelectActionsModal
=
()
=>
{
Object
.
keys
(
defaultProps
).
forEach
((
key
)
=>
{
// @ts-ignore
localStore
[
key
]
=
defaultProps
[
key
];
});
};
src/ui/Duel/PlayMat/Bg/index.scss
View file @
7ace8dc5
...
@@ -19,7 +19,9 @@ section#mat {
...
@@ -19,7 +19,9 @@ section#mat {
height
:
var
(
--
block-height-m
);
height
:
var
(
--
block-height-m
);
width
:
var
(
--
block-width
);
width
:
var
(
--
block-width
);
// background-color: rgba(128, 128, 128, 0.447);
// background-color: rgba(128, 128, 128, 0.447);
box-shadow
:
0
0
0
1px
purple
;
background
:
radial-gradient
(
#232323
,
#212121
);
// box-shadow: 0 0 0 1px purple;
position
:
relative
;
&
.extra
{
&
.extra
{
margin-inline
:
calc
(
var
(
--
block-width
)
/
2
+
var
(
--
col-gap
)
/
2
);
margin-inline
:
calc
(
var
(
--
block-width
)
/
2
+
var
(
--
col-gap
)
/
2
);
}
}
...
@@ -30,5 +32,29 @@ section#mat {
...
@@ -30,5 +32,29 @@ section#mat {
box-shadow
:
0
0
0
1px
#00b0ff
,
0
0
13px
0px
#0077ff
,
box-shadow
:
0
0
0
1px
#00b0ff
,
0
0
13px
0px
#0077ff
,
0
0
11px
0
skyblue
inset
;
0
0
11px
0
skyblue
inset
;
}
}
.triangle
{
width
:
0
;
height
:
0
;
--color
:
#292929
;
border-width
:
5px
;
border-style
:
solid
;
position
:
absolute
;
&
:nth-of-type
(
1
)
{
border-color
:
var
(
--
color
)
transparent
transparent
var
(
--
color
);
}
&
:nth-of-type
(
2
)
{
border-color
:
var
(
--
color
)
var
(
--
color
)
transparent
transparent
;
right
:
0
;
}
&
:nth-of-type
(
3
)
{
border-color
:
transparent
var
(
--
color
)
var
(
--
color
)
transparent
;
right
:
0
;
bottom
:
0
;
}
&
:nth-of-type
(
4
)
{
border-color
:
transparent
transparent
var
(
--
color
)
var
(
--
color
);
bottom
:
0
;
}
}
}
}
}
}
src/ui/Duel/PlayMat/Bg/index.tsx
View file @
7ace8dc5
...
@@ -52,7 +52,9 @@ const BgExtraRow: FC<{
...
@@ -52,7 +52,9 @@ const BgExtraRow: FC<{
onBlockClick
(
meSnap
[
i
].
interactivity
);
onBlockClick
(
meSnap
[
i
].
interactivity
);
onBlockClick
(
opSnap
[
i
].
interactivity
);
onBlockClick
(
opSnap
[
i
].
interactivity
);
}
}
}
}
></
div
>
>
{
<
DecoTriangles
/>
}
</
div
>
))
}
))
}
</
div
>
</
div
>
);
);
...
@@ -73,7 +75,9 @@ const BgRow: FC<{
...
@@ -73,7 +75,9 @@ const BgRow: FC<{
})
}
})
}
style=
{
snap
[
i
].
disabled
?
(
BgDisabledStyle
as
CSSProperties
)
:
{}
}
style=
{
snap
[
i
].
disabled
?
(
BgDisabledStyle
as
CSSProperties
)
:
{}
}
onClick=
{
()
=>
onBlockClick
(
snap
[
i
].
interactivity
)
}
onClick=
{
()
=>
onBlockClick
(
snap
[
i
].
interactivity
)
}
></
div
>
>
{
<
DecoTriangles
/>
}
</
div
>
))
}
))
}
</
div
>
</
div
>
);
);
...
@@ -101,3 +105,11 @@ const onBlockClick = (placeInteractivity: PlaceInteractivity) => {
...
@@ -101,3 +105,11 @@ const onBlockClick = (placeInteractivity: PlaceInteractivity) => {
placeStore
.
clearAllInteractivity
();
placeStore
.
clearAllInteractivity
();
}
}
};
};
const
DecoTriangles
:
FC
=
()
=>
(
<>
{
Array
.
from
({
length
:
4
}).
map
((
_
,
i
)
=>
(
<
div
className=
"triangle"
key=
{
i
}
/>
))
}
</>
);
src/ui/Duel/PlayMat/Card/index.tsx
View file @
7ace8dc5
...
@@ -20,6 +20,8 @@ import {
...
@@ -20,6 +20,8 @@ import {
moveToOutside
,
moveToOutside
,
}
from
"
./springs
"
;
}
from
"
./springs
"
;
import
{
YgoCard
}
from
"
@/ui/Shared
"
;
const
NeosConfig
=
useConfig
();
const
NeosConfig
=
useConfig
();
const
{
HAND
,
GRAVE
,
REMOVED
,
DECK
,
EXTRA
,
MZONE
,
SZONE
,
TZONE
}
=
const
{
HAND
,
GRAVE
,
REMOVED
,
DECK
,
EXTRA
,
MZONE
,
SZONE
,
TZONE
}
=
...
@@ -139,15 +141,12 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => {
...
@@ -139,15 +141,12 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => {
}
}
}
}
>
>
<
div
className=
"card-shadow"
/>
<
div
className=
"card-shadow"
/>
<
div
className=
{
classnames
(
"
card-img-wrap
"
,
{
highlight
})
}
>
<
div
className=
"card-img-wrap"
>
<
img
<
YgoCard
className=
"card-cover"
className=
"card-cover"
onError=
{
()
=>
{
code=
{
snap
.
code
===
0
?
snap
.
meta
.
id
:
snap
.
code
}
console
.
log
(
""
);
}
}
src=
{
getCardImgUrl
(
snap
.
code
==
0
?
snap
.
meta
.
id
:
snap
.
code
)
}
/>
/>
<
img
className=
"card-back"
src=
{
getCardImgUrl
(
0
,
true
)
}
/>
<
YgoCard
className=
"card-back"
isBack
/>
</
div
>
</
div
>
{
snap
.
selected
?
<
div
className=
"card-streamer"
/>
:
<></>
}
{
snap
.
selected
?
<
div
className=
"card-streamer"
/>
:
<></>
}
</
animated
.
div
>
</
animated
.
div
>
...
...
src/ui/Duel/utils/groupBy.ts
View file @
7ace8dc5
export
const
groupBy
=
<
K
,
V
>
(
export
const
groupBy
=
<
K
,
V
extends
Record
<
string
,
any
>
>
(
array
:
readonly
V
[],
array
:
readonly
V
[],
getKey
:
(
cur
:
V
,
idx
:
number
,
src
:
readonly
V
[])
=>
K
getKey
:
(
cur
:
V
,
idx
:
number
,
src
:
readonly
V
[])
=>
K
):
[
K
,
V
[]][]
=>
):
[
K
,
V
[]][]
=>
...
...
src/ui/Shared/YgoCard/index.scss
0 → 100644
View file @
7ace8dc5
.skeleton-cover
{
background-color
:
gray
;
}
.ygo-card
{
width
:
100%
;
height
:
100%
;
position
:
absolute
;
left
:
0
;
top
:
0
;
}
src/ui/Shared/YgoCard/index.tsx
0 → 100644
View file @
7ace8dc5
import
{
type
FC
,
useMemo
,
CSSProperties
}
from
"
react
"
;
import
{
useConfig
}
from
"
@/config
"
;
import
classNames
from
"
classnames
"
;
import
"
./index.scss
"
;
interface
Props
{
className
?:
string
;
isBack
?:
boolean
;
code
?:
number
;
style
?:
CSSProperties
;
}
export
const
YgoCard
:
FC
<
Props
>
=
(
props
)
=>
{
const
{
className
,
code
:
cardCode
=
0
,
isBack
=
false
,
style
}
=
props
;
return
useMemo
(
()
=>
(
<>
{
cardCode
===
0
&&
!
isBack
?
(
<
div
className=
{
classNames
(
"
ygo-card
"
,
"
skeleton-cover
"
)
}
style=
{
style
}
/>
)
:
(
<
img
className=
{
classNames
(
"
ygo-card
"
,
className
)
}
src=
{
getCardImgUrl
(
cardCode
,
isBack
)
}
style=
{
style
}
/>
)
}
</>
),
[
cardCode
]
);
};
const
NeosConfig
=
useConfig
();
function
getCardImgUrl
(
code
:
number
,
back
=
false
)
{
const
ASSETS_BASE
=
import
.
meta
.
env
.
BASE_URL
==
"
/
"
?
NeosConfig
.
assetsPath
:
`
${
import
.
meta
.
env
.
BASE_URL
}${
NeosConfig
.
assetsPath
}
`
;
if
(
back
)
{
return
`
${
ASSETS_BASE
}
/card_back.jpg`
;
}
return
`
${
NeosConfig
.
cardImgUrl
}
/
${
code
}
.jpg`
;
}
src/ui/Shared/index.ts
0 → 100644
View file @
7ace8dc5
export
*
from
"
./YgoCard
"
;
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