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
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
2
Merge Requests
2
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
MyCard
Neos
Commits
fef43d79
Commit
fef43d79
authored
Apr 21, 2023
by
timel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: valtio store logic 55%
parent
1802f14a
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
510 additions
and
315 deletions
+510
-315
src/service/duel/selectCard.ts
src/service/duel/selectCard.ts
+12
-1
src/service/duel/selectChain.ts
src/service/duel/selectChain.ts
+23
-1
src/valtioStores/matStore/index.ts
src/valtioStores/matStore/index.ts
+2
-298
src/valtioStores/matStore/methods/fetchCheckCardMeta.ts
src/valtioStores/matStore/methods/fetchCheckCardMeta.ts
+142
-0
src/valtioStores/matStore/methods/fetchHint.ts
src/valtioStores/matStore/methods/fetchHint.ts
+75
-0
src/valtioStores/matStore/methods/index.ts
src/valtioStores/matStore/methods/index.ts
+2
-0
src/valtioStores/matStore/store.ts
src/valtioStores/matStore/store.ts
+248
-0
src/valtioStores/matStore/types.ts
src/valtioStores/matStore/types.ts
+6
-15
No files found.
src/service/duel/selectCard.ts
View file @
fef43d79
...
...
@@ -7,7 +7,10 @@ import {
import
{
fetchCheckCardMeta
}
from
"
@/reducers/duel/modal/mod
"
;
import
{
AppDispatch
}
from
"
@/store
"
;
import
MsgSelectCard
=
ygopro
.
StocGameMessage
.
MsgSelectCard
;
import
{
messageStore
}
from
"
@/valtioStores
"
;
import
{
messageStore
,
fetchCheckCardMeta
as
FIXME_fetchCheckCardMeta
,
}
from
"
@/valtioStores
"
;
import
{
CardZoneToChinese
}
from
"
./util
"
;
...
...
@@ -39,7 +42,15 @@ export default (selectCard: MsgSelectCard, dispatch: AppDispatch) => {
},
})
);
// FIXME: rename
FIXME_fetchCheckCardMeta
(
card
.
location
.
location
,
{
code
:
card
.
code
,
location
:
card
.
location
,
response
:
card
.
response
,
});
}
dispatch
(
setCheckCardModalIsOpen
(
true
));
messageStore
.
checkCardModal
.
isOpen
=
true
;
};
src/service/duel/selectChain.ts
View file @
fef43d79
...
...
@@ -12,8 +12,14 @@ import { fetchCheckCardMeta } from "@/reducers/duel/modal/mod";
import
{
AppDispatch
}
from
"
@/store
"
;
import
{
CardZoneToChinese
}
from
"
./util
"
;
import
MsgSelectChain
=
ygopro
.
StocGameMessage
.
MsgSelectChain
;
import
{
messageStore
,
fetchCheckCardMeta
as
FIXME_fetchCheckCardMeta
,
fetchSelectHintMeta
as
FIXME_fetchSelectHintMeta
,
}
from
"
@/valtioStores
"
;
type
MsgSelectChain
=
ygopro
.
StocGameMessage
.
MsgSelectChain
;
export
default
(
selectChain
:
MsgSelectChain
,
dispatch
:
AppDispatch
)
=>
{
const
player
=
selectChain
.
player
;
const
spCount
=
selectChain
.
special_count
;
...
...
@@ -71,6 +77,12 @@ export default (selectChain: MsgSelectChain, dispatch: AppDispatch) => {
dispatch
(
setCheckCardMOdalCancelAble
(
!
forced
));
dispatch
(
setCheckCardModalCancelResponse
(
-
1
));
messageStore
.
checkCardModal
.
selectMin
=
1
;
messageStore
.
checkCardModal
.
selectMax
=
1
;
messageStore
.
checkCardModal
.
onSubmit
=
"
sendSelectChainResponse
"
;
messageStore
.
checkCardModal
.
cancelAble
=
!
forced
;
messageStore
.
checkCardModal
.
cancelResponse
=
-
1
;
for
(
const
chain
of
chains
)
{
const
tagName
=
CardZoneToChinese
(
chain
.
location
.
location
);
dispatch
(
...
...
@@ -84,14 +96,24 @@ export default (selectChain: MsgSelectChain, dispatch: AppDispatch) => {
},
})
);
FIXME_fetchCheckCardMeta
(
chain
.
location
.
location
,
{
code
:
chain
.
code
,
location
:
chain
.
location
,
response
:
chain
.
response
,
effectDescCode
:
chain
.
effect_description
,
});
}
dispatch
(
fetchSelectHintMeta
({
selectHintData
:
203
,
})
);
FIXME_fetchSelectHintMeta
({
selectHintData
:
203
,
});
dispatch
(
setCheckCardModalIsOpen
(
true
));
messageStore
.
checkCardModal
.
isOpen
=
true
;
break
;
}
...
...
src/valtioStores/matStore/index.ts
View file @
fef43d79
export
*
from
"
./types
"
;
import
{
proxy
}
from
"
valtio
"
;
import
{
type
CardMeta
,
fetchCard
}
from
"
@/api/cards
"
;
import
{
ygopro
}
from
"
@/api/ocgcore/idl/ocgcore
"
;
import
{
DESCRIPTION_LIMIT
,
fetchStrings
,
getStrings
}
from
"
@/api/strings
"
;
import
type
{
BothSide
,
CardsBothSide
,
CardState
,
DuelFieldState
,
InitInfo
,
MatState
,
}
from
"
./types
"
;
import
{
InteractType
}
from
"
./types
"
;
/**
* 生成一个指定长度的卡片数组
*/
const
genBlock
=
(
location
:
ygopro
.
CardZone
,
n
:
number
=
5
):
BothSide
<
DuelFieldState
>
=>
{
return
{
me
:
Array
(
n
)
.
fill
(
null
)
.
map
((
_
)
=>
({
location
:
{
location
,
},
idleInteractivities
:
[],
counters
:
{},
})),
op
:
Array
(
n
)
.
fill
(
null
)
.
map
((
_
)
=>
({
location
:
{
location
,
},
idleInteractivities
:
[],
counters
:
{},
})),
};
};
const
initInfo
:
MatState
[
"
initInfo
"
]
=
proxy
({
me
:
{
masterRule
:
"
UNKNOWN
"
,
life
:
-
1
,
// 特地设置一个不可能的值
deckSize
:
0
,
extraSize
:
0
,
},
op
:
{
masterRule
:
"
UNKNOWN
"
,
life
:
-
1
,
// 特地设置一个不可能的值
deckSize
:
0
,
extraSize
:
0
,
},
set
:
(
controller
:
number
,
obj
:
Partial
<
InitInfo
>
)
=>
{
initInfo
[
getWhom
(
controller
)]
=
{
...
initInfo
[
getWhom
(
controller
)],
...
obj
,
};
},
});
const
hint
:
MatState
[
"
hint
"
]
=
proxy
({
code
:
-
1
,
fetchCommonHintMeta
:
(
code
:
number
)
=>
{
hint
.
code
=
code
;
hint
.
msg
=
fetchStrings
(
"
!system
"
,
code
);
},
fetchSelectHintMeta
:
async
({
selectHintData
,
esHint
})
=>
{
let
selectHintMeta
=
""
;
if
(
selectHintData
>
DESCRIPTION_LIMIT
)
{
// 针对`MSG_SELECT_PLACE`的特化逻辑
const
cardMeta
=
await
fetchCard
(
selectHintData
,
true
);
selectHintMeta
=
fetchStrings
(
"
!system
"
,
569
).
replace
(
"
[%ls]
"
,
cardMeta
.
text
.
name
||
"
[?]
"
);
}
else
{
selectHintMeta
=
await
getStrings
(
selectHintData
);
}
hint
.
code
=
selectHintData
;
if
(
hint
.
code
>
DESCRIPTION_LIMIT
)
{
// 针对`MSG_SELECT_PLACE`的特化逻辑
hint
.
msg
=
selectHintMeta
;
}
else
{
hint
.
esSelectHint
=
selectHintMeta
;
hint
.
esHint
=
esHint
;
}
},
fetchEsHintMeta
:
async
({
originMsg
,
location
,
cardID
})
=>
{
const
newOriginMsg
=
typeof
originMsg
===
"
string
"
?
originMsg
:
fetchStrings
(
"
!system
"
,
originMsg
);
const
cardMeta
=
cardID
?
await
fetchCard
(
cardID
)
:
undefined
;
let
esHint
=
newOriginMsg
;
if
(
cardMeta
?.
text
.
name
)
{
esHint
=
esHint
.
replace
(
"
[?]
"
,
cardMeta
.
text
.
name
);
}
if
(
location
)
{
const
fieldMeta
=
matStore
.
getZone
(
location
.
location
)
.
at
(
location
.
controler
)
.
at
(
location
.
sequence
);
if
(
fieldMeta
?.
occupant
?.
text
.
name
)
{
esHint
=
esHint
.
replace
(
"
[?]
"
,
fieldMeta
.
occupant
.
text
.
name
);
}
}
hint
.
esHint
=
esHint
;
},
});
/**
* 在决斗盘仓库之中,
* 给 `{me: [...], op: [...]}` 这种类型的对象添加一些方法。
* 具体的方法可以看`CardsBothSide`的类型定义
*/
const
wrap
=
<
T
extends
DuelFieldState
>
(
entity
:
BothSide
<
T
>
,
zone
:
ygopro
.
CardZone
):
CardsBothSide
<
T
>
=>
{
/**
* 生成一个卡片,根据`id`获取卡片信息
*/
const
genCard
=
async
(
controller
:
number
,
id
:
number
)
=>
({
occupant
:
await
fetchCard
(
id
,
true
),
location
:
{
controler
:
controller
,
location
:
zone
,
},
counters
:
{},
idleInteractivities
:
[],
});
const
res
:
CardsBothSide
<
T
>
=
proxy
({
...
entity
,
at
:
(
controller
:
number
)
=>
{
return
res
[
getWhom
(
controller
)];
},
remove
:
(
controller
:
number
,
sequence
:
number
)
=>
{
res
[
getWhom
(
controller
)].
splice
(
sequence
,
1
);
},
insert
:
async
(
controller
:
number
,
sequence
:
number
,
id
:
number
)
=>
{
const
card
=
await
genCard
(
controller
,
id
);
res
[
getWhom
(
controller
)].
splice
(
sequence
,
0
,
card
);
},
add
:
async
(
controller
:
number
,
ids
:
number
[])
=>
{
const
cards
=
await
Promise
.
all
(
ids
.
map
(
async
(
id
)
=>
genCard
(
controller
,
id
))
);
res
[
getWhom
(
controller
)].
splice
(
res
[
getWhom
(
controller
)].
length
,
0
,
...
cards
);
},
setOccupant
:
async
(
controller
:
number
,
sequence
:
number
,
id
:
number
,
position
?:
ygopro
.
CardPosition
)
=>
{
const
meta
=
await
fetchCard
(
id
);
const
target
=
res
[
getWhom
(
controller
)][
sequence
];
target
.
occupant
=
meta
;
if
(
position
)
{
target
.
location
.
position
=
position
;
}
},
removeOccupant
:
(
controller
:
number
,
sequence
:
number
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
occupant
=
undefined
;
},
addIdleInteractivity
:
(
controller
:
number
,
sequence
:
number
,
interactivity
:
CardState
[
"
idleInteractivities
"
][
number
]
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
idleInteractivities
.
push
(
interactivity
);
},
clearIdleInteractivities
:
(
controller
:
number
,
sequence
:
number
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
idleInteractivities
=
[];
},
setPlaceInteractivityType
:
(
controller
:
number
,
sequence
:
number
,
interactType
:
InteractType
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
placeInteractivity
=
{
interactType
:
interactType
,
response
:
{
controler
:
controller
,
zone
,
sequence
,
},
};
},
clearPlaceInteractivity
:
(
controller
:
number
,
sequence
:
number
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
placeInteractivity
=
undefined
;
},
});
return
res
;
};
/**
* zone -> matStore
*/
const
getZone
=
(
zone
:
ygopro
.
CardZone
)
=>
{
switch
(
zone
)
{
case
ygopro
.
CardZone
.
MZONE
:
return
matStore
.
monsters
;
case
ygopro
.
CardZone
.
SZONE
:
return
matStore
.
magics
;
case
ygopro
.
CardZone
.
HAND
:
return
matStore
.
hands
;
case
ygopro
.
CardZone
.
DECK
:
return
matStore
.
decks
;
case
ygopro
.
CardZone
.
GRAVE
:
return
matStore
.
graveyards
;
case
ygopro
.
CardZone
.
REMOVED
:
return
matStore
.
banishedZones
;
case
ygopro
.
CardZone
.
EXTRA
:
return
matStore
.
extraDecks
;
default
:
console
.
error
(
"
in error
"
,
zone
);
return
matStore
.
extraDecks
;
}
};
/**
* 💡 决斗盘状态仓库,本文件核心,
* 具体介绍可以点进`PlayMatState`去看
*/
export
const
matStore
:
MatState
=
proxy
<
MatState
>
({
magics
:
wrap
(
genBlock
(
ygopro
.
CardZone
.
SZONE
,
6
),
ygopro
.
CardZone
.
SZONE
),
monsters
:
wrap
(
genBlock
(
ygopro
.
CardZone
.
MZONE
,
7
),
ygopro
.
CardZone
.
MZONE
),
graveyards
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
GRAVE
),
banishedZones
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
REMOVED
),
hands
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
HAND
),
decks
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
DECK
),
extraDecks
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
EXTRA
),
timeLimits
:
{
// 时间限制
me
:
0
,
op
:
0
,
},
initInfo
,
selfType
:
ygopro
.
StocTypeChange
.
SelfType
.
UNKNOWN
,
hint
,
currentPlayer
:
-
1
,
phase
:
{
currentPhase
:
"
UNKNOWN
"
,
// TODO 当前的阶段 应该改成enum
enableBp
:
false
,
// 允许进入战斗阶段
enableM2
:
false
,
// 允许进入M2阶段
enableEp
:
false
,
// 允许回合结束
},
result
:
ygopro
.
StocGameMessage
.
MsgWin
.
ActionType
.
UNKNOWN
,
waiting
:
false
,
unimplemented
:
0
,
// methods
getZone
,
});
/**
* 根据controller判断是自己还是对方
* 不要往外export,尽量逻辑收拢在store内部
*/
const
getWhom
=
(
controller
:
number
):
"
me
"
|
"
op
"
=>
judgeSelf
(
controller
,
matStore
.
selfType
)
?
"
me
"
:
"
op
"
;
const
judgeSelf
=
(
player
:
number
,
selfType
:
number
):
boolean
=>
{
switch
(
selfType
)
{
case
1
:
// 自己是先攻
return
player
===
0
;
case
2
:
// 自己是后攻
return
player
===
1
;
default
:
// 目前不可能出现这种情况
console
.
error
(
"
judgeSelf error
"
,
player
,
selfType
);
return
false
;
}
};
export
*
from
"
./store
"
;
export
*
from
"
./methods
"
;
src/valtioStores/matStore/methods/fetchCheckCardMeta.ts
0 → 100644
View file @
fef43d79
import
{
ygopro
}
from
"
@/api/ocgcore/idl/ocgcore
"
;
import
{
matStore
,
messageStore
}
from
"
@/valtioStores
"
;
import
{
fetchCard
,
getCardStr
}
from
"
@/api/cards
"
;
function
CardZoneToChinese
(
zone
:
ygopro
.
CardZone
):
string
{
switch
(
zone
)
{
case
ygopro
.
CardZone
.
DECK
:
{
return
"
卡组
"
;
}
case
ygopro
.
CardZone
.
HAND
:
{
return
"
手牌
"
;
}
case
ygopro
.
CardZone
.
EXTRA
:
{
return
"
额外卡组
"
;
}
case
ygopro
.
CardZone
.
GRAVE
:
{
return
"
墓地
"
;
}
case
ygopro
.
CardZone
.
FZONE
:
{
return
"
FZONE
"
;
}
case
ygopro
.
CardZone
.
MZONE
:
{
return
"
怪兽区
"
;
}
case
ygopro
.
CardZone
.
SZONE
:
{
return
"
魔法陷阱区
"
;
}
case
ygopro
.
CardZone
.
REMOVED
:
{
return
"
除外区
"
;
}
case
ygopro
.
CardZone
.
OVERLAY
:
{
return
"
超量区
"
;
}
case
ygopro
.
CardZone
.
PZONE
:
{
return
"
灵摆区
"
;
}
case
ygopro
.
CardZone
.
ONFIELD
:
{
return
"
场地区
"
;
}
default
:
{
return
"
未知区域
"
;
}
}
}
type
Location
=
|
ygopro
.
CardLocation
|
ReturnType
<
typeof
ygopro
.
CardLocation
.
prototype
.
toObject
>
;
function
cmpCardLocation
(
left
:
Location
,
right
?:
Location
,
strict
?:
boolean
):
boolean
{
if
(
strict
)
{
return
JSON
.
stringify
(
left
)
===
JSON
.
stringify
(
right
);
}
else
{
return
(
left
.
controler
===
right
?.
controler
&&
left
.
location
===
right
?.
location
&&
left
.
sequence
===
right
?.
sequence
);
}
}
/**
* 这段代码定义了一个异步函数 fetchCheckCardMeta,它的作用是获取一张卡片的元数据并将其添加到某个名为 messageStore.checkCardModal 的对象上。
该函数的第一个参数是一个枚举值 ygopro.CardZone,表示卡片所在的区域。其余参数是一个包含卡片编号、位置、响应码和效果描述代码等信息的对象。
首先,这个函数会根据区域类型调用 CardZoneToChinese() 函数生成一个中文名称。然后,它会调用 fetchCard() 异步函数来获取指定卡片的元数据 meta。
接下来,函数会根据传递进来的 location 对象获取卡片所属的控制者,并根据控制者判断这张卡片是我方的还是对方的。然后,它会根据卡片的位置信息获取卡片的实际 ID,并构造一个新的选项 newOption。
接着,函数会遍历已有的 messageStore.checkCardModal.tags,查找是否存在名为 combinedTagName 的标签。如果找到了,则将新选项 newOption 加入该标签的选项列表中并立即返回。如果找不到,则创建一个新标签,并将新选项 newOption 添加到其中。
最后,函数会再次遍历所有标签,查找是否存在名为 combinedTagName 的标签。如果找到了,则遍历该标签中的所有选项,并查找是否存在与 location 对象中指定的卡片位置信息完全相同的选项。如果找到了,则更新该选项的元数据和效果描述等信息。
*/
export
const
fetchCheckCardMeta
=
async
(
zone
:
ygopro
.
CardZone
,
{
code
,
location
,
response
,
effectDescCode
,
}:
{
code
:
number
;
location
:
ygopro
.
CardLocation
;
response
:
number
;
effectDescCode
?:
number
;
}
)
=>
{
const
tagName
=
CardZoneToChinese
(
zone
);
const
meta
=
await
fetchCard
(
code
);
const
controller
=
location
.
controler
;
const
combinedTagName
=
matStore
.
isMe
(
controller
)
?
`我方的
${
tagName
}
`
:
`对方的
${
tagName
}
`
;
const
newID
=
code
!=
0
?
code
:
matStore
.
getZone
(
location
.
location
).
at
(
controller
)[
location
.
sequence
]
?.
occupant
?.
id
||
0
;
const
newOption
=
{
meta
:
{
id
:
newID
,
data
:
{},
text
:
{}
},
location
:
location
.
toObject
(),
effectDescCode
,
response
,
};
for
(
const
tag
of
messageStore
.
checkCardModal
.
tags
)
{
if
(
tag
.
tagName
===
combinedTagName
)
{
tag
.
options
.
push
(
newOption
);
return
;
}
}
messageStore
.
checkCardModal
.
tags
.
push
({
tagName
:
combinedTagName
,
options
:
[
newOption
],
});
for
(
const
tag
of
messageStore
.
checkCardModal
.
tags
)
{
if
(
tag
.
tagName
===
combinedTagName
)
{
for
(
const
old
of
tag
.
options
)
{
if
(
meta
.
id
==
old
.
meta
.
id
&&
cmpCardLocation
(
location
,
old
.
location
))
{
const
cardID
=
old
.
meta
.
id
;
old
.
meta
=
meta
;
old
.
meta
.
id
=
cardID
;
const
effectDescCode
=
old
.
effectDescCode
;
const
effectDesc
=
effectDescCode
?
getCardStr
(
old
.
meta
,
effectDescCode
&
0xf
)
:
undefined
;
old
.
effectDesc
=
effectDesc
;
}
}
}
}
};
src/valtioStores/matStore/methods/fetchHint.ts
0 → 100644
View file @
fef43d79
import
{
matStore
}
from
"
@/valtioStores
"
;
import
{
fetchCard
}
from
"
@/api/cards
"
;
import
{
DESCRIPTION_LIMIT
,
fetchStrings
,
getStrings
}
from
"
@/api/strings
"
;
import
type
{
ygopro
}
from
"
@/api/ocgcore/idl/ocgcore
"
;
const
{
hint
}
=
matStore
;
export
const
fetchCommonHintMeta
=
(
code
:
number
)
=>
{
hint
.
code
=
code
;
hint
.
msg
=
fetchStrings
(
"
!system
"
,
code
);
};
export
const
fetchSelectHintMeta
=
async
({
selectHintData
,
esHint
,
}:
{
selectHintData
:
number
;
esHint
?:
string
;
})
=>
{
let
selectHintMeta
=
""
;
if
(
selectHintData
>
DESCRIPTION_LIMIT
)
{
// 针对`MSG_SELECT_PLACE`的特化逻辑
const
cardMeta
=
await
fetchCard
(
selectHintData
,
true
);
selectHintMeta
=
fetchStrings
(
"
!system
"
,
569
).
replace
(
"
[%ls]
"
,
cardMeta
.
text
.
name
||
"
[?]
"
);
}
else
{
selectHintMeta
=
await
getStrings
(
selectHintData
);
}
hint
.
code
=
selectHintData
;
if
(
hint
.
code
>
DESCRIPTION_LIMIT
)
{
// 针对`MSG_SELECT_PLACE`的特化逻辑
hint
.
msg
=
selectHintMeta
;
}
else
{
hint
.
esSelectHint
=
selectHintMeta
;
hint
.
esHint
=
esHint
;
}
};
export
const
fetchEsHintMeta
=
async
({
originMsg
,
location
,
cardID
,
}:
{
originMsg
:
string
|
number
;
location
?:
ygopro
.
CardLocation
;
cardID
?:
number
;
})
=>
{
const
newOriginMsg
=
typeof
originMsg
===
"
string
"
?
originMsg
:
fetchStrings
(
"
!system
"
,
originMsg
);
const
cardMeta
=
cardID
?
await
fetchCard
(
cardID
)
:
undefined
;
let
esHint
=
newOriginMsg
;
if
(
cardMeta
?.
text
.
name
)
{
esHint
=
esHint
.
replace
(
"
[?]
"
,
cardMeta
.
text
.
name
);
}
if
(
location
)
{
const
fieldMeta
=
matStore
.
getZone
(
location
.
location
)
.
at
(
location
.
controler
)
.
at
(
location
.
sequence
);
if
(
fieldMeta
?.
occupant
?.
text
.
name
)
{
esHint
=
esHint
.
replace
(
"
[?]
"
,
fieldMeta
.
occupant
.
text
.
name
);
}
}
hint
.
esHint
=
esHint
;
};
src/valtioStores/matStore/methods/index.ts
0 → 100644
View file @
fef43d79
export
*
from
"
./fetchCheckCardMeta
"
;
export
*
from
"
./fetchHint
"
;
src/valtioStores/matStore/store.ts
0 → 100644
View file @
fef43d79
import
{
proxy
}
from
"
valtio
"
;
import
{
fetchCard
}
from
"
@/api/cards
"
;
import
{
ygopro
}
from
"
@/api/ocgcore/idl/ocgcore
"
;
import
type
{
BothSide
,
CardsBothSide
,
CardState
,
DuelFieldState
,
InitInfo
,
MatState
,
}
from
"
./types
"
;
import
{
InteractType
}
from
"
./types
"
;
/**
* 根据controller判断是自己还是对方。
* 这个无需export,尽量逻辑收拢在store内部。
*/
const
getWhom
=
(
controller
:
number
):
"
me
"
|
"
op
"
=>
isMe
(
controller
)
?
"
me
"
:
"
op
"
;
/**
* 根据自己的先后手判断是否是自己
*/
const
isMe
=
(
player
:
number
):
boolean
=>
{
switch
(
matStore
.
selfType
)
{
case
1
:
// 自己是先攻
return
player
===
0
;
case
2
:
// 自己是后攻
return
player
===
1
;
default
:
// 目前不可能出现这种情况
console
.
error
(
"
judgeSelf error
"
,
player
,
matStore
.
selfType
);
return
false
;
}
};
/**
* 生成一个指定长度的卡片数组
*/
const
genBlock
=
(
location
:
ygopro
.
CardZone
,
n
:
number
):
BothSide
<
DuelFieldState
>
=>
{
return
{
me
:
Array
(
n
)
.
fill
(
null
)
.
map
((
_
)
=>
({
location
:
{
location
,
},
idleInteractivities
:
[],
counters
:
{},
})),
op
:
Array
(
n
)
.
fill
(
null
)
.
map
((
_
)
=>
({
location
:
{
location
,
},
idleInteractivities
:
[],
counters
:
{},
})),
};
};
const
initInfo
:
MatState
[
"
initInfo
"
]
=
proxy
({
me
:
{
masterRule
:
"
UNKNOWN
"
,
life
:
-
1
,
// 特地设置一个不可能的值
deckSize
:
0
,
extraSize
:
0
,
},
op
:
{
masterRule
:
"
UNKNOWN
"
,
life
:
-
1
,
// 特地设置一个不可能的值
deckSize
:
0
,
extraSize
:
0
,
},
set
:
(
controller
:
number
,
obj
:
Partial
<
InitInfo
>
)
=>
{
initInfo
[
getWhom
(
controller
)]
=
{
...
initInfo
[
getWhom
(
controller
)],
...
obj
,
};
},
});
const
hint
:
MatState
[
"
hint
"
]
=
proxy
({
code
:
-
1
,
});
/**
* 在决斗盘仓库之中,
* 给 `{me: [...], op: [...]}` 这种类型的对象添加一些方法。
* 具体的方法可以看`CardsBothSide`的类型定义
*/
const
wrap
=
<
T
extends
DuelFieldState
>
(
entity
:
BothSide
<
T
>
,
zone
:
ygopro
.
CardZone
):
CardsBothSide
<
T
>
=>
{
/**
* 生成一个卡片,根据`id`获取卡片信息
*/
const
genCard
=
async
(
controller
:
number
,
id
:
number
)
=>
({
occupant
:
await
fetchCard
(
id
,
true
),
location
:
{
controler
:
controller
,
location
:
zone
,
},
counters
:
{},
idleInteractivities
:
[],
});
const
res
:
CardsBothSide
<
T
>
=
proxy
({
...
entity
,
at
:
(
controller
:
number
)
=>
{
return
res
[
getWhom
(
controller
)];
},
remove
:
(
controller
:
number
,
sequence
:
number
)
=>
{
res
[
getWhom
(
controller
)].
splice
(
sequence
,
1
);
},
insert
:
async
(
controller
:
number
,
sequence
:
number
,
id
:
number
)
=>
{
const
card
=
await
genCard
(
controller
,
id
);
res
[
getWhom
(
controller
)].
splice
(
sequence
,
0
,
card
);
},
add
:
async
(
controller
:
number
,
ids
:
number
[])
=>
{
const
cards
=
await
Promise
.
all
(
ids
.
map
(
async
(
id
)
=>
genCard
(
controller
,
id
))
);
res
[
getWhom
(
controller
)].
splice
(
res
[
getWhom
(
controller
)].
length
,
0
,
...
cards
);
},
setOccupant
:
async
(
controller
:
number
,
sequence
:
number
,
id
:
number
,
position
?:
ygopro
.
CardPosition
)
=>
{
const
meta
=
await
fetchCard
(
id
);
const
target
=
res
[
getWhom
(
controller
)][
sequence
];
target
.
occupant
=
meta
;
if
(
position
)
{
target
.
location
.
position
=
position
;
}
},
removeOccupant
:
(
controller
:
number
,
sequence
:
number
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
occupant
=
undefined
;
},
addIdleInteractivity
:
(
controller
:
number
,
sequence
:
number
,
interactivity
:
CardState
[
"
idleInteractivities
"
][
number
]
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
idleInteractivities
.
push
(
interactivity
);
},
clearIdleInteractivities
:
(
controller
:
number
,
sequence
:
number
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
idleInteractivities
=
[];
},
setPlaceInteractivityType
:
(
controller
:
number
,
sequence
:
number
,
interactType
:
InteractType
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
placeInteractivity
=
{
interactType
:
interactType
,
response
:
{
controler
:
controller
,
zone
,
sequence
,
},
};
},
clearPlaceInteractivity
:
(
controller
:
number
,
sequence
:
number
)
=>
{
res
[
getWhom
(
controller
)][
sequence
].
placeInteractivity
=
undefined
;
},
});
return
res
;
};
/**
* zone -> matStore
*/
const
getZone
=
(
zone
:
ygopro
.
CardZone
)
=>
{
switch
(
zone
)
{
case
ygopro
.
CardZone
.
MZONE
:
return
matStore
.
monsters
;
case
ygopro
.
CardZone
.
SZONE
:
return
matStore
.
magics
;
case
ygopro
.
CardZone
.
HAND
:
return
matStore
.
hands
;
case
ygopro
.
CardZone
.
DECK
:
return
matStore
.
decks
;
case
ygopro
.
CardZone
.
GRAVE
:
return
matStore
.
graveyards
;
case
ygopro
.
CardZone
.
REMOVED
:
return
matStore
.
banishedZones
;
case
ygopro
.
CardZone
.
EXTRA
:
return
matStore
.
extraDecks
;
default
:
console
.
error
(
"
in error
"
,
zone
);
return
matStore
.
extraDecks
;
}
};
/**
* 💡 决斗盘状态仓库,本文件核心,
* 具体介绍可以点进`PlayMatState`去看
*/
export
const
matStore
:
MatState
=
proxy
<
MatState
>
({
magics
:
wrap
(
genBlock
(
ygopro
.
CardZone
.
SZONE
,
6
),
ygopro
.
CardZone
.
SZONE
),
monsters
:
wrap
(
genBlock
(
ygopro
.
CardZone
.
MZONE
,
7
),
ygopro
.
CardZone
.
MZONE
),
graveyards
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
GRAVE
),
banishedZones
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
REMOVED
),
hands
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
HAND
),
decks
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
DECK
),
extraDecks
:
wrap
({
me
:
[],
op
:
[]
},
ygopro
.
CardZone
.
EXTRA
),
timeLimits
:
{
// 时间限制
me
:
0
,
op
:
0
,
},
initInfo
,
selfType
:
ygopro
.
StocTypeChange
.
SelfType
.
UNKNOWN
,
hint
,
currentPlayer
:
-
1
,
phase
:
{
currentPhase
:
"
UNKNOWN
"
,
// TODO 当前的阶段 应该改成enum
enableBp
:
false
,
// 允许进入战斗阶段
enableM2
:
false
,
// 允许进入M2阶段
enableEp
:
false
,
// 允许回合结束
},
result
:
ygopro
.
StocGameMessage
.
MsgWin
.
ActionType
.
UNKNOWN
,
waiting
:
false
,
unimplemented
:
0
,
// methods
getZone
,
isMe
,
});
src/valtioStores/matStore/types.ts
View file @
fef43d79
...
...
@@ -67,7 +67,7 @@ export interface MatState {
timeLimits
:
BothSide
<
number
>
;
// 双方的时间限制
hint
:
HintState
&
HintMethods
;
hint
:
HintState
;
currentPlayer
:
number
;
// 当前的操作方
...
...
@@ -79,7 +79,11 @@ export interface MatState {
unimplemented
:
number
;
// 未处理的`Message`
getZone
:
(
zone
:
ygopro
.
CardZone
)
=>
CardsBothSide
<
DuelFieldState
>
;
// 是否在某个区域
// >>> methods >>>
/** 根据zone获取hands/masters/gy... */
getZone
:
(
zone
:
ygopro
.
CardZone
)
=>
CardsBothSide
<
DuelFieldState
>
;
/** 根据自己的先后手判断是否是自己 */
isMe
:
(
player
:
number
)
=>
boolean
;
}
export
interface
InitInfo
{
...
...
@@ -162,19 +166,6 @@ export interface HintState {
esHint
?:
string
;
esSelectHint
?:
string
;
}
// 和hint相关的方法
export
interface
HintMethods
{
fetchCommonHintMeta
:
(
hintData
:
number
)
=>
void
;
fetchSelectHintMeta
:
(
args
:
{
selectHintData
:
number
;
esHint
?:
string
;
})
=>
Promise
<
void
>
;
fetchEsHintMeta
:
(
args
:
{
originMsg
:
string
|
number
;
location
?:
ygopro
.
CardLocation
;
cardID
?:
number
;
})
=>
Promise
<
void
>
;
}
export
type
PhaseName
=
keyof
typeof
ygopro
.
StocGameMessage
.
MsgNewPhase
.
PhaseType
;
...
...
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