Compare commits
394 Commits
971539a72f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f89cd1ad63 | |||
| 758ebd19f2 | |||
| 90494232bc | |||
| ecadf3606e | |||
| 4b559ca7fa | |||
| 30c73c9899 | |||
| ffcec649fa | |||
| 3b678e35d1 | |||
| 47e954266c | |||
| 8b4ece766a | |||
| ee68fb5bb0 | |||
| a7f949fad8 | |||
| 9fbf8e8574 | |||
| d61628d359 | |||
| 18da7a7983 | |||
| 695f048c2d | |||
| 6e82d0f128 | |||
| 1390b9ec50 | |||
| cdfc79cd57 | |||
| bfb9ee5bef | |||
| 5297922f99 | |||
| e3a75c33a3 | |||
| 0a040837d9 | |||
| da0d74f841 | |||
| 7f30803862 | |||
| 2fdd535939 | |||
| 1100cbeb08 | |||
| e14f19e4ed | |||
| 1a10444136 | |||
| 4d8fa0f40f | |||
| 9fd4b2d2e3 | |||
| 0def604f62 | |||
| a2e4f16402 | |||
| e8ea5e249d | |||
| 66985c2af6 | |||
| 1ecccb4ae7 | |||
| 985225dbd2 | |||
| f0b7704fc1 | |||
| 8628727bcc | |||
| 7db67e3ccd | |||
| 1847e2d9b2 | |||
| 5e2fd5db22 | |||
| 17200d47ec | |||
| 95d6155086 | |||
| de917f812d | |||
| 8a43ca91da | |||
| fc03d58ee7 | |||
| ead73b427e | |||
| d78049182b | |||
| 5f615e30e2 | |||
| 222ed92807 | |||
| 72750f3647 | |||
| 1291c52346 | |||
| 926733dbef | |||
| d7813f9912 | |||
| e6f351420b | |||
| b4a4560678 | |||
| 1e0b91294a | |||
| 8f8f17bd8f | |||
| 478fd1e5f0 | |||
| 0c1dfd3162 | |||
| 8d2e320d60 | |||
| 7b5e79bcf2 | |||
| 39356e5038 | |||
| 4878e5d8cc | |||
| 5f047ae41b | |||
| d83a377865 | |||
| 8292e26726 | |||
| 07ae56909a | |||
| f33018194f | |||
| a682baa5dc | |||
| 6d0ebde863 | |||
| 4ce87bec5d | |||
| 0cf714dca6 | |||
| fd00ed12d9 | |||
| 74a2106021 | |||
| a2044e20af | |||
| a3d5174b34 | |||
| 4f9be00ff2 | |||
| 24a79a309f | |||
| ba450f16b0 | |||
| 278007f908 | |||
| 16ebf304a5 | |||
| 5b7f7bb69f | |||
| 34531b184f | |||
| f6650a6c70 | |||
| acf295d56c | |||
| 9278c47901 | |||
| b2bf1bf4dd | |||
| 5da6e8f3aa | |||
| 71435a2c91 | |||
| f64e35668d | |||
| ba1651e52c | |||
| f8414a9c33 | |||
| 6344685052 | |||
| b0f1a0840c | |||
| c703bd9b4d | |||
| 96102dc41f | |||
| 8702d5209e | |||
| 74d4824a1c | |||
| bdea6a8c28 | |||
| 4fa0bc85c0 | |||
| db76870d4e | |||
| 491833b025 | |||
| 83de73c2c1 | |||
| b06ad8e8ee | |||
| 578f4416b2 | |||
| bc80b96875 | |||
| f2828deb19 | |||
| b549abc3b3 | |||
| 5b21e7f436 | |||
| b42d5fcf51 | |||
| 43530bee60 | |||
| 9b8884da81 | |||
| 2b3d77c588 | |||
| 3efb6993c7 | |||
| 5f8475d018 | |||
| afac34d7b5 | |||
| a917a6d82b | |||
| 9fba9b5aaa | |||
| 54d9632534 | |||
| c274322887 | |||
| 5900af087e | |||
| b0d3da2f39 | |||
| 6ef0ba48f6 | |||
| 1b1fce3d6e | |||
| c34a1126fb | |||
| 964cf7cc3d | |||
| 098571e9aa | |||
| ea832ad846 | |||
| 4288c4101b | |||
| 2bb7360a47 | |||
| a5388da2cc | |||
| 8ca48eca60 | |||
| eeca77df35 | |||
| 40e351333e | |||
| 0a83dea2d8 | |||
| fbf4d8d02d | |||
| a141939675 | |||
| 42eb33b579 | |||
| 9f7713267c | |||
| bfa86f0f28 | |||
| c5bb8c18a9 | |||
| 2f9c325c96 | |||
| 420cce561c | |||
| d265c8f918 | |||
| 255781d969 | |||
| b904b29503 | |||
| 0435a76fc1 | |||
| d82e98f832 | |||
| eafd6747a7 | |||
| bc266b1885 | |||
| e6a397cc55 | |||
| fcc103227c | |||
| 44878bab9e | |||
| 064d81d424 | |||
| 62187db5dd | |||
| 1a5953050f | |||
| a902cb8bce | |||
| b23dc3868e | |||
| 98ca1668c8 | |||
| 654a49f3a2 | |||
| 3e4619ed2f | |||
| aa872afa7b | |||
| 1eb6622cf5 | |||
| 8309b25ec5 | |||
| 00903f2659 | |||
| f2c470f972 | |||
| 2e8a1ab869 | |||
| 4228f58b09 | |||
| 5e0eca6cdf | |||
| 4da934585c | |||
| 49069a16cf | |||
| bda35eefc7 | |||
| 44010e0fce | |||
| efa32d0a8f | |||
| 7c776864e2 | |||
| 72370aab23 | |||
| 5377112826 | |||
| 8a5b0d4f8d | |||
| 6c35d959ac | |||
| 67d21a9619 | |||
| b1d0af311a | |||
| 5b41eb78a4 | |||
| 3902c9b1ee | |||
| d1e51878c3 | |||
| cc945fce8b | |||
| 9966065409 | |||
| bc9bc78cef | |||
| 9cb5e1abff | |||
| 1fce0b284a | |||
| e269154d17 | |||
| b65d4af1eb | |||
| d5318ac86b | |||
| bd91c67483 | |||
| b43ee02014 | |||
| 6427d23f50 | |||
| b40c8d11d8 | |||
| f9e7bc3603 | |||
| 256433d3f3 | |||
| 05a06644cf | |||
| 709e6f8f99 | |||
| a88c1d344c | |||
| a24f3592c4 | |||
| 3db11f5d82 | |||
| 6e1f1cf990 | |||
| 304b2f3c2a | |||
| 15bc17b351 | |||
| 6f436ef3eb | |||
| cf193bf51a | |||
| 1e87be2cd6 | |||
| 6cc008e894 | |||
| 760b856576 | |||
| 91bbe7d200 | |||
| 989e3fe000 | |||
| 0e064cc1e9 | |||
| de1e69de7d | |||
| a683f186d4 | |||
| a309da2a99 | |||
| 82bf22d4cc | |||
| f36bc0d14e | |||
| 1f0a8099ee | |||
| a5f6a4509d | |||
| d3ae6c1c62 | |||
| 4d3f6fc0af | |||
| a2b8d6bfb9 | |||
| 8f233296af | |||
| 5f89d61a8b | |||
| 8879647b26 | |||
| 7ee323ea8b | |||
| 7cc311ee91 | |||
| 5cde11647f | |||
| 8296775e21 | |||
| d546d62755 | |||
| 8f58a90746 | |||
| 8fa1079548 | |||
| 9e16465218 | |||
| f67471435e | |||
| fd57e0d56d | |||
| afe995a895 | |||
| 6a6b64cbc5 | |||
| b2693be111 | |||
| 675616bf51 | |||
| 1e48fa35b3 | |||
| aaa68ebe07 | |||
| 35dfcbaffe | |||
| 9aa4721790 | |||
| e553ebe666 | |||
| a814bf2c4b | |||
| 9e162d6e2d | |||
| 8baa97bde8 | |||
| 66c1ac8ee1 | |||
| abd6d00052 | |||
| 2cd672b474 | |||
| 56d958fe19 | |||
| 7aed1943b7 | |||
| 9989a61675 | |||
| 2c28935d95 | |||
| b635cb3a63 | |||
| bcdf9457c8 | |||
| 89056e903d | |||
| fc0a96fcb7 | |||
| 7b6e181cb0 | |||
| e1d298f972 | |||
| 811c8ec2ac | |||
| 6b6037739f | |||
| 80c5daabbf | |||
| 6e8d1a88f5 | |||
| 13d1ccb771 | |||
| d0b8fbe091 | |||
| 2c9a1b351e | |||
| 74e3a70a19 | |||
| 15b342972d | |||
| 1925144f85 | |||
| 2a0ec0ef21 | |||
| 65ad2fe854 | |||
| d7e4e88182 | |||
| 52c03b208e | |||
| 76aaafcf1b | |||
| c69a17abe0 | |||
| 1abd9f7987 | |||
| 1624ef6f3b | |||
| 443aaf83d2 | |||
| 67e8b4c848 | |||
| 52d808eacd | |||
| b5a648fc23 | |||
| 62b2193f2e | |||
| 2a42c4a372 | |||
| 42f9143f73 | |||
| 239dd6caf3 | |||
| e4f7ff10d7 | |||
| 6b8db0b871 | |||
| 4c3be95c86 | |||
| 88a9136398 | |||
| 0a96a6955a | |||
| 00844857ee | |||
| 6df3fcf01c | |||
| 2bf5716fce | |||
| 12f3928ab4 | |||
| eb06663758 | |||
| 02aa73dda3 | |||
| 134353d374 | |||
| 013f946c6b | |||
| 8ff50b428d | |||
| 1de8fac893 | |||
| 248677759c | |||
| 2af67b3b2b | |||
| 7890f4c029 | |||
| 32a0b2437b | |||
| dd2a814eeb | |||
| 4a1c66c5fe | |||
| 869e4d88df | |||
| e876a8ce3a | |||
| f88e6ffeeb | |||
| 5921dfbeb8 | |||
| 4b7ad753a4 | |||
| c80020a464 | |||
| 858f9727dd | |||
| 1c2062b8cc | |||
| d4ec8757ce | |||
| 76cb2cd65e | |||
| d2aba643fa | |||
| d783cccea1 | |||
| c4ad8fc068 | |||
| 4ea9bfe14b | |||
| 18729a2047 | |||
| 50462f3d8a | |||
| 2f73910e47 | |||
| 659ae2a60f | |||
| b5facb7763 | |||
| 1762112296 | |||
| 389e7f36cf | |||
| 24e6aca305 | |||
| d1f894a802 | |||
| c5e28062eb | |||
| c7d795f839 | |||
| 2265bd7fa1 | |||
| fb5f0d6d5b | |||
| 569c1d5eb4 | |||
| 066ad6ddca | |||
| 1a15225ff6 | |||
| 33bc98c015 | |||
| 895e521724 | |||
| cd7ae102ca | |||
| d0353fb81f | |||
| 6eea4f9e17 | |||
| 903a06d233 | |||
| c614b10566 | |||
| 6feb252674 | |||
| 428bdc8a2e | |||
| 271a7991d1 | |||
| 59c699c04b | |||
| 0d517617a3 | |||
| d247115ad7 | |||
| 26c084d951 | |||
| 6349be63aa | |||
| 7167ece6a7 | |||
| 76e60d3350 | |||
| e241382d09 | |||
| f4b349532d | |||
| 683ea88271 | |||
| 516348c0ec | |||
| f211a79c82 | |||
| f33a5507db | |||
| 647516d0cd | |||
| f704d0f14e | |||
| f0569d9a53 | |||
| a5c7d96770 | |||
| 423407325d | |||
| ec45438b3c | |||
| 020be477e6 | |||
| 9eef5eb66e | |||
| 185e0f3a94 | |||
| de23829439 | |||
| 4ef3d1811d | |||
| b14b614d94 | |||
| 0cbcf4c70d | |||
| 1583f7ec26 | |||
| da5dd03183 | |||
| c0cbea42a2 | |||
| de6e12c765 | |||
| f38a3c98b1 | |||
| 62e76f7db2 | |||
| ff91680f18 | |||
| b18c44f0a5 | |||
| 124e49b938 | |||
| c9f82708c8 | |||
| f1d101f6a4 | |||
| 5dfbef4f0f | |||
| fbf5cfe19f | |||
| 9eeb12adf9 | |||
| 68c9333b59 | |||
| 8405395d84 | |||
| f310d2978e |
20
.claude/settings.json
Normal file
20
.claude/settings.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
||||
"permissions": {
|
||||
"deny": [
|
||||
"Read(./ui/*.ui)",
|
||||
"Read(./map/*.map)",
|
||||
"Read(./RootDesk/MyDesk/*.codeblock)",
|
||||
"Edit(./ui/*.ui)",
|
||||
"Edit(./map/*.map)",
|
||||
"Edit(./RootDesk/MyDesk/*.codeblock)",
|
||||
"Edit(./Global/common.gamelogic)",
|
||||
"Edit(./Global/SectorConfig.config)",
|
||||
"Write(./ui/*.ui)",
|
||||
"Write(./map/*.map)",
|
||||
"Write(./RootDesk/MyDesk/*.codeblock)",
|
||||
"Write(./Global/common.gamelogic)",
|
||||
"Write(./Global/SectorConfig.config)"
|
||||
]
|
||||
}
|
||||
}
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -4,8 +4,11 @@
|
||||
# Codex CLI 로컬 설정 — Authorization Bearer 토큰 포함
|
||||
.codex/
|
||||
.agents/
|
||||
# Claude Code 로컬 설정
|
||||
.claude/
|
||||
# Claude Code 로컬 설정 — 단, 팀 공유 하네스 설정(settings.json)은 커밋 (RULES.md 참조)
|
||||
.claude/*
|
||||
!.claude/settings.json
|
||||
# 개인 스킬(superpowers) 브레인스토밍/계획 산출물 — 로컬 전용, 협업 공유 X (프로젝트 설계 문서 docs/*.md 는 추적 유지)
|
||||
docs/superpowers/
|
||||
|
||||
# === OS / 에디터 잡파일 ===
|
||||
Thumbs.db
|
||||
@@ -22,3 +25,5 @@ AGENTS.md
|
||||
Environment/
|
||||
McpScreenshots/
|
||||
*.log
|
||||
# 메이커가 재편(reorg) 중 부모를 잃은 엔티티를 모아두는 임시 폴더 (잡파일)
|
||||
Mislocated/
|
||||
|
||||
7
CLAUDE.md
Normal file
7
CLAUDE.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# SlayMaple — CLAUDE.md
|
||||
|
||||
MapleStory Worlds 기반 Slay the Spire 풍 덱빌더. 게임 전체가 데이터(`data/*.json`) + 생성기(`tools/`) 단일 소스이고, `ui/DefaultGroup.ui`(~7.1MB)·codeblock·map 파일은 **생성 산출물**이다.
|
||||
|
||||
@RULES.md
|
||||
|
||||
위 RULES.md의 하네스 규칙(산출물 Read/Edit 금지·카운트 검증·gitea-pr.mjs PR 절차)을 항상 따른다. `.claude/settings.json`이 산출물에 대한 Read/Edit/Write를 도구 수준에서 차단한다.
|
||||
@@ -24,12 +24,7 @@
|
||||
"map://map03",
|
||||
"map://map04",
|
||||
"map://map05",
|
||||
"map://map06",
|
||||
"map://map07",
|
||||
"map://map08",
|
||||
"map://map09",
|
||||
"map://map10",
|
||||
"map://map11"
|
||||
"map://lobby"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
142
Global/UIButton.model
Normal file
142
Global/UIButton.model
Normal file
@@ -0,0 +1,142 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://uibutton",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "UIButton",
|
||||
"BaseModelId": null,
|
||||
"Id": "uibutton",
|
||||
"Components": [
|
||||
"MOD.Core.UITransformComponent",
|
||||
"MOD.Core.SpriteGUIRendererComponent"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "RectSize",
|
||||
"DisplayName": "RectSize",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.UITransformComponent, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RectSize"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODDataRef, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "ImageRUID",
|
||||
"DisplayName": "ImageRUID",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteGUIRendererComponent, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ImageRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODColor, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "Color",
|
||||
"DisplayName": "Color",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteGUIRendererComponent, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "Color"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.UITransformComponent",
|
||||
"Name": "anchoredPosition",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.UITransformComponent",
|
||||
"Name": "RectSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 200.0,
|
||||
"y": 75.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.UITransformComponent",
|
||||
"Name": "AlignmentOption",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.AlignmentType, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteGUIRendererComponent",
|
||||
"Name": "ImageRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODDataRef, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODDataRef, MOD.Core",
|
||||
"DataId": "cc3457b8e97b3e14f9d5c39ccdd640bf"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteGUIRendererComponent",
|
||||
"Name": "Color",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODColor, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODColor, MOD.Core",
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
205
README.md
205
README.md
@@ -1,7 +1,7 @@
|
||||
# SlayMaple
|
||||
|
||||
[MapleStory Worlds(MSW)](https://maplestoryworlds.nexon.com/) 기반으로 제작하는 **Slay the Spire 풍 덱빌더 로그라이크** 월드.
|
||||
턴제 카드 전투, 덱 구성, 보상 선택, 맵 노드 진행을 메이플 월드 위에서 구현하는 것을 목표로 합니다.
|
||||
로비 마을에서 NPC와 상호작용해 런을 시작하고, 턴제 카드 전투·덱 구성·보상 선택·절차 생성 맵 진행·전직·영혼 메타 성장을 메이플 월드 위에서 구현합니다.
|
||||
|
||||
> 이 저장소는 MSW **로컬 워크스페이스(Local Workspace)** 데이터를 git으로 형상관리하기 위한 것입니다.
|
||||
> 공동작업자는 이 저장소를 통해 월드 데이터를 주고받습니다. (클라우드 공동제작 모드 미사용)
|
||||
@@ -32,9 +32,10 @@ git push
|
||||
```bash
|
||||
git pull
|
||||
```
|
||||
받아온 뒤, 메이커에서 **로컬 워크스페이스를 다시 로드(reload)** 해야 새 codeblock/모델 파일이 에디터 상태로 반영됩니다.
|
||||
받아온 뒤, 메이커에서 **로컬 워크스페이스를 다시 로드(reload)** 해야 새 codeblock/모델/맵 파일이 에디터 상태로 반영됩니다.
|
||||
|
||||
> 💡 같은 파일을 동시에 수정하면 git 충돌이 날 수 있으니, **서로 다른 맵/codeblock/UI를 나눠서** 작업하는 것을 권장합니다.
|
||||
> ⚠️ git pull 후 reload를 빠뜨리면 메이커의 stale 상태가 디스크를 덮어쓸 수 있습니다. 재생성 후에도 reload → 빌드 콘솔 0 에러 확인.
|
||||
|
||||
---
|
||||
|
||||
@@ -42,95 +43,178 @@ git pull
|
||||
|
||||
```
|
||||
slaymaple/
|
||||
├── data/ # 게임 데이터 단일 소스 (생성기가 읽어 주입). 맵은 정적 데이터 없음(절차 생성)
|
||||
│ ├── cards.json # 카드 166장(1~3차 전직 계열별 + 저주) + 클래스별 시작 덱
|
||||
│ ├── enemies.json # 적 18종(일반/정예/보스, 디버프 인텐트 + 외형 appearance)
|
||||
│ ├── encounters.json # 맵별 몬스터 로스터(map01~05 × combat/elite/boss)
|
||||
│ ├── potions.json # 물약 6종 + 드랍률·슬롯·상점가
|
||||
│ ├── relics.json # 유물 19종(StS 효과 × 메이플 장비) + 시작 유물 + 풀
|
||||
│ ├── cardframes.json # 커스텀 카드 프레임 3종(전사/마법사/도적 × normal/unique/legend) + 보상 등급 가중치
|
||||
│ ├── characters.json # 클래스별 초상화 RUID
|
||||
│ ├── cards.xlsx # cards.json 왕복 편집용 엑셀(excel_to_cards.bat / cards_to_excel.bat)
|
||||
│ └── camera.json # 맵별 카메라 설정값(줌·오프셋·고정 영역)
|
||||
├── Global/ # 월드 전역 설정 · 공용 모델 · 게임로직
|
||||
│ ├── common.gamelogic # SlayDeckController 부착 지점 (카드 UI 전투)
|
||||
│ ├── Player.model # 플레이어 모델
|
||||
│ ├── *.model # 몬스터 등 공용 모델
|
||||
│ ├── common.gamelogic # SlayDeckController 부착 지점 (산출물)
|
||||
│ ├── DefaultPlayer.model # 플레이어 모델 (턴전투용 이동 정지 freeze 적용)
|
||||
│ ├── ChaseMonster.model · MoveMonster.model # 몬스터 공용 모델
|
||||
│ ├── SectorConfig.config # 섹터/맵 등록 (lobby + map01~05 = 6 entries)
|
||||
│ ├── WorldConfig.config # 월드 설정
|
||||
│ └── ...
|
||||
├── RootDesk/
|
||||
│ └── MyDesk/ # 작업용 책상 — codeblock(스크립트)·모델·타일셋
|
||||
│ ├── SlayDeckController.codeblock # 카드 UI 전투 컨트롤러 (생성물)
|
||||
│ ├── Monster.codeblock # 필드 액션 몬스터 (HP·피격·리스폰, 카드 전투와 별개)
|
||||
│ ├── MonsterAttack.codeblock
|
||||
│ ├── PlayerAttack.codeblock
|
||||
│ ├── PlayerHit.codeblock
|
||||
│ ├── UIPopup.codeblock
|
||||
│ ├── UIToast.codeblock
|
||||
│ └── RectTileData_Henesys.tileset
|
||||
├── map/
|
||||
│ ├── map01.map ~ map11.map # 맵 11종 (공식 배경 + STS풍 우측 배치)
|
||||
├── tools/ # 결정적 생성기 (단일 소스)
|
||||
│ ├── gen-slaydeck.mjs # 카드/덱 UI · SlayDeckController · common 생성
|
||||
│ ├── gen-cardhand.mjs # 손패 카드 엔티티 생성
|
||||
│ └── gen-maps.mjs # 맵 생성
|
||||
├── ui/ # UI 그룹 (Default / Popup / Toast)
|
||||
│ └── MyDesk/ # 작업용 책상 — codeblock(스크립트)·타일셋
|
||||
│ ├── SlayDeckController.codeblock # 게임 전체 컨트롤러 (★산출물, 직접 편집 금지)
|
||||
│ ├── Monster.codeblock · MonsterAttack.codeblock # 필드 액션 몬스터 (카드 전투와 별개)
|
||||
│ ├── PlayerAttack.codeblock · PlayerHit.codeblock · UIPopup.codeblock · UIToast.codeblock
|
||||
│ ├── CombatMonster.codeblock # 맵 몬스터 EnemyId 마커 + /common 자기등록
|
||||
│ ├── MapCamera.codeblock # 맵별 카메라 적용
|
||||
│ ├── PlayerLock.codeblock # 전투맵 플레이어 입력·이동 잠금
|
||||
│ ├── LobbyNpc.codeblock # 로비 NPC 상호작용(근접·클릭)
|
||||
│ ├── LobbyMobility.codeblock # 로비 이동·공격 해제 + 카메라 추종
|
||||
│ └── Models/Monsters/ # 적 종별 모델 <enemyId>.model (산출물 — 외형·EnemyId 베이크)
|
||||
├── map/ # 맵 6종 (산출물)
|
||||
│ ├── lobby.map # 로비 허브 맵 (마을 배경, NPC 4종, 전투 없음)
|
||||
│ └── map01.map ~ map05.map # 5막 전투/맵 노드 (공식 배경 + STS풍 우측 배치)
|
||||
├── tools/ # 결정적 생성기·도구 (주체별 폴더, 단일 소스)
|
||||
│ ├── deck/ # gen-slaydeck.mjs(★컨트롤러+common 생성 오케스트레이터) · cb/(codeblock Lua 메서드 20모듈: boot·screens·combat·hand·npc·navigation·layout·shop·reward·soul 등) · lib/(공유 상수·데이터·헬퍼) · legacy/(옛 UI emit 휴면)
|
||||
│ ├── map/ # gen-maps.mjs(맵 배경/타일) · gen-lobby-map.mjs(로비 맵+NPC) · gen-map-encounters.mjs(encounters.json 로스터 기반 종별 모델 인스턴스 배치) · rogue-map.mjs(절차 생성 JS 미러)+test
|
||||
│ ├── camera/ # gen-camera.mjs(맵별 고정 카메라 codeblock)
|
||||
│ ├── player/ # gen-player-lock.mjs(전투맵 입력 잠금) · freeze-turn-player.mjs(모델 이동 정지) · gen-lobby-npc.mjs(LobbyNpc·LobbyMobility codeblock)
|
||||
│ ├── monster/ # gen-monster-models.mjs(적 종별 .model) · gen-combat-monster.mjs(자기등록 codeblock) · freeze-turn-monsters.mjs(레거시 AI 정지) · lib/monster-model.mjs(공용 빌더)+test
|
||||
│ ├── balance/ # sim-balance.mjs(전투 밸런스 몬테카를로 시뮬) · sim-balance.test.mjs
|
||||
│ ├── verify/ # count·uimap·cbgap(카운트/UIGroup 매핑/재연결 GAP) · cardkinds(카드 kind↔효과) · cbprops(미선언 self 대입) · cbset(메서드 집합 무손실) · diffcheck(바이트동일)
|
||||
│ └── git/ # gitea-pr.mjs(UTF-8 안전 PR 생성/수정/머지 — RULES.md 참조)
|
||||
├── ui/ # UIGroup 7종 — 메이커 저작(Default/Select/Lobby/Run/Deck/Popup/Toast)
|
||||
├── docs/
|
||||
│ └── slaymaple_basic_framework.md # 전투 프레임워크 설계 문서
|
||||
│ ├── slaymaple_basic_framework.md # 전투 프레임워크 설계 문서
|
||||
│ ├── ui-generation-structure.md # UI 생성 구조 문서
|
||||
│ └── superpowers/specs|plans/ # 각 기능 설계·구현 계획 문서(P1~P15)
|
||||
├── RULES.md # 협업·AI 에이전트 하네스 규칙 (토큰 가드·검증·PR 절차)
|
||||
├── CLAUDE.md # Claude Code 자동 로드 (RULES.md 임포트)
|
||||
└── README.md
|
||||
```
|
||||
|
||||
> ⚠️ **`map/*.map` · `SlayDeckController.codeblock` · `Global/common.gamelogic`는 생성 산출물**입니다 — 직접 편집하면 재생성 때 사라집니다. 게임 로직 변경은 `data/*.json`·`tools/`의 생성기를 고쳐 재생성하세요. **`ui/*.ui`는 메이커 저작**(생성기 미생성)이라 메이커에서만 편집합니다(자세한 규칙은 [`RULES.md`](RULES.md)).
|
||||
> `.mcp.json`, `.codex/` 는 **Authorization 토큰이 포함**되어 있어 git에서 제외됩니다(`.gitignore`). 각자 로컬에서 직접 구성하세요.
|
||||
|
||||
---
|
||||
|
||||
## 직업 컨셉
|
||||
|
||||
3직업 모두 Slay the Spire 2 차용 + 메이플 IP 재해석. 카드 덱 상세 설계는 [`docs/deck-concept.md`](docs/deck-concept.md) 참조.
|
||||
|
||||
- **⚔️ 전사 (탱커, Ironclad 차용, HP80)** — 2차 3종. **파이터**: 공격을 *연속*으로 내면 콤보가 쌓이고(비공격 카드 시 리셋) 콤보로 데미지 증가 = 브루저(콤보 어택·버서크·라이징 어택). **페이지**: 썬더/블리자드 **속성 차지** + 파워 가드. **스피어맨**: 피어스·아이언 월·하이퍼 바디 유지/관통형.
|
||||
- **🗡️ 도적 (단검·독, Silent 차용, HP70)** — 표창 난사 / 독 / 교활·버림. **2차 어쌔신**(표창·독 압박·빠른 마무리)·**시프**(단검·드로우·연계) → **3차 헤르밋**(어쌔신 심화)·**시프 마스터**(시프 심화). 도적 계열만 132장(Silent 완역 포트 + 공식 스킬 아이콘).
|
||||
- **🔮 법사 (약체·게이지, Defect 차용, HP70)** — 2차 3종. **위자드(불·독)**: 독을 묻히고 *독 걸린 적에 불 카드 → 추가 데미지*(독뎀 시너지). **위자드(썬·콜)**: 오브로 썬더(다중 공격)·콜드(빙결=취약+피해), 오브 획득·다중 소모 운용. **클레릭**: 오브 없이 회복·버프 + 언데드엔 힐로 공격하는 보조 힐러.
|
||||
|
||||
## 게임 프레임워크 현황
|
||||
|
||||
현재 전투는 `Global/common.gamelogic`의 `/common` 엔티티에 부착된 **`SlayDeckController` 단일 컴포넌트**로 동작합니다. 모든 카드/덱/전투 관련 산출물(`ui/DefaultGroup.ui` · `RootDesk/MyDesk/SlayDeckController.codeblock` · `common.gamelogic`)은 **`tools/gen-slaydeck.mjs` 단일 소스에서 생성**됩니다(직접 편집 금지, 결정적 출력).
|
||||
**StS2풍 덱빌더 로그라이크가 end-to-end로 완성**됐고, 이제 **로비 마을을 기점으로 반복 런**이 돕니다 (게임 시작 시 MainMenu 없이 바로 로비로 진입):
|
||||
|
||||
| 컴포넌트 | 상태 | 역할 |
|
||||
|---|---|---|
|
||||
| `SlayDeckController` | ✅ 구현됨 | 카드 손패 UI 전투 — 드로우/버림/재셔플, 에너지, 카드 효과(데미지/방어), 적 HP·방어·의도, 턴 진행, 승패 |
|
||||
| `Monster.codeblock` | ✅ 구현됨 | 필드 액션 몬스터(HP·피격·리스폰) — 카드 전투와는 **별개** 시스템 |
|
||||
```
|
||||
로비 맵(NPC 4종) → 모험가 NPC → 캐릭터 선택(전사/도적/마법사) → 절차 생성 맵(5막)
|
||||
→ 전투/엘리트/상점/휴식/유물 방 → 보상·전직·덱 성장 → 보스 → 다음 막
|
||||
→ 런 클리어(승천 해금) → 로비 복귀(영혼 정산) → 다음 런 …
|
||||
```
|
||||
|
||||
### 구현된 카드 전투 (단일 전투 루프)
|
||||
- **카드 손패 UI**: 에너지 3, 매 턴 5장 드로우, 버림 더미·재셔플, 카드 클릭 사용, 종류별 색상.
|
||||
- **카드 3종**: 타격(피해 6) · 방어(방어도 5) · 강타(피해 10). 각 카드에 `damage`/`block` 수치 필드. 시작 덱 10장.
|
||||
- **전투 상태**: 플레이어 `HP`/`Block`, 적 `HP`/`Block`/`Intent(의도)`. 적 의도는 **결정적 사이클**(공격10 → 공격6 → 방어8)로 다음 행동을 미리 표시.
|
||||
- **규칙**: 데미지는 방어도 먼저 차감 후 잔여만 HP에 적용. 플레이어 Block은 턴 시작 시 리셋.
|
||||
- **턴 흐름**: 카드 사용(`Attack`→적 HP↓, `Skill`→플레이어 Block↑) → 턴 종료 → 적 턴(의도 실행) → 다음 플레이어 턴.
|
||||
- **승패**: 적 HP 0 → 승리, 플레이어 HP 0 → 패배. 승패 시 입력 잠금 + 결과 표시(전투 보상 훅 자리 = E 예정).
|
||||
- **UI(CombatHud)**: 적 패널(이름·HP·방어·의도)·플레이어 패널(HP·방어)·승패 결과 텍스트.
|
||||
게임 전체는 `/common` 엔티티에 부착된 **`SlayDeckController` 단일 컴포넌트**로 동작합니다. **UI는 메이커 저작**(7개 UIGroup: Default/Select/Lobby/Run/Deck/Popup/Toast)이고, 컨트롤러가 엔티티 경로(`/ui/<UIGroup>/<Hud>/...`)로 내용을 런타임 주입합니다. 생성기 `tools/deck/gen-slaydeck.mjs`는 **`SlayDeckController.codeblock` + `common.gamelogic`만 생성**(`.ui` 미접근, 결정적 출력 — `RULES.md` 참조). 게임 데이터는 **`data/*.json`**, 맵 구조는 **런타임 절차 생성**(`GenerateMap` Lua ↔ `tools/map/rogue-map.mjs` JS 미러).
|
||||
|
||||
> ⚠️ 플레이어 HP(80)·적 HP(45)·의도 수치(10·6·8)는 **루프 검증용 임시 placeholder**입니다.
|
||||
> 향후 캐릭터 특성별/몬스터별 데이터로 분리할 예정입니다(아래 D 참조).
|
||||
### 구현된 기능 (배포 퀄리티 P1~P15+, PR #34~#104)
|
||||
|
||||
| 영역 | 내용 |
|
||||
|---|---|
|
||||
| **로비 마을** | 전용 물리 맵 `lobby.map`(마을 배경). **NPC 4종 월드 엔티티** — 모험가(런 시작)·사서(카드 도감)·상인(영혼 상점)·안내원(게시판). 근접 시 머리 위 마크 + `↑`키 **또는 직접 클릭**으로 상호작용. **이동·공격 모션은 로비 맵에서만** 풀림(전투맵은 잠금), 카메라는 로비에서 **플레이어 추종**(전투맵은 고정) |
|
||||
| **캐릭터·전직** | 시작 시 **전사(HP80)/도적(HP70)/마법사(HP70)** 3종 선택(**초상화·직업 설명·선택 테두리 강조** 캐릭터 선택 UI), 클래스별 시작 덱. 보스 클리어 시 [유물] vs [**전직**] — 전사→파이터/페이지/스피어맨, 법사→위자드(불·독)/위자드(썬·콜)/클레릭 (2차 3종씩), **도적→어쌔신·시프(2차) → 헤르밋·시프 마스터(3차)**. 전직 시 대표 카드 지급, 전용 카드는 해당 계열 풀만 획득 |
|
||||
| **카드 전투** | 에너지 3·드로우·**드래그 사용**(공격=적에 드롭, 스킬/파워=위로 스윕). 카드 **166장** — kind **Attack(59)/Skill(74)/Power(31)/Status(2)**. kind↔효과 정합성 정적 검증(`cardkinds.mjs`). 메커니즘: 다단히트·방어 무시·자가 디버프·드로·회복·**전체 공격(AoE)**·**독(DoT)**·**retain**(턴 종료 손패 유지)·**sly discard**(버림 트리거) |
|
||||
| **도적 카드 공용 효과** | 카드 효과를 **카드명 하드코딩 대신 `data/cards.json` 공용 필드**로 표현(재사용). **불가침**·**x-cost**(에너지 비례 피해/약화)·드로우 수 비례 데미지·**다음 스킬 반복**·**처치 보상/반복**·카드 설명 **키워드 하이라이트**·드로우 연동(`drawSkillBlock`·`drawPoison`)·독 버스트·랜덤 타깃 등. **Lua + JS 미러 양쪽 구현**. 필드 사전 [`docs/card-effect-fields.md`](docs/card-effect-fields.md) |
|
||||
| **버프/디버프** | StS 표준 — **힘**(+N 영구)·**약화**(주는 피해 −25%)·**취약**(받는 피해 +50%)·**독**(매 행동 틱). 양방향(적 디버프 인텐트 포함), 인텐트는 최종 예상치 표시 |
|
||||
| **전투 연출** | 공격 이펙트·**몬스터 데미지 팝업(자릿수 스킨)**·드래그 타깃 마커·적 개별 차례·**공격/피격/독뎀 모션**(아바타 상태 전이·몬스터 hit 클립·런지/넉백) |
|
||||
| **절차 생성 맵** | 막 시작마다 **경로 생성**(런마다 다름, **가로 진행**). 층 규칙: 1~2층 전투만 → 3층~ 상점/휴식 → 4층~ 엘리트/**유물 방** → 보스 수렴. 점선 경로·상태 4단·층 카운터. 노드 타입별 **몬스터 랜덤 구성**(일반 1~3 / 엘리트 / 보스) + intent 랜덤 행동 |
|
||||
| **몬스터 종별 모델** | 적 종별 전용 `.model`(프리팹) — 외형(stand/hit/die)·EnemyId 베이크, 태생 AI-free. 맵 배치는 **`data/encounters.json` 맵별 로스터**대로 해당 모델 인스턴스 생성(외형=정체성 고정). 능력치·행동은 `enemies.json`, 외형은 `appearance`, 배치는 `encounters.json`로 관심사 분리 |
|
||||
| **유물 19종 / 물약 6종** | 유물: StS 효과 × 메이플 장비 외형, TopBar 아이콘 + 마우스오버 툴팁, 8종 훅. 물약: 승리 40% 드랍·상점·슬롯 메뉴. 보물 방=상자 연출 → 유물+메소 |
|
||||
| **카드 프레임·등급** | 커스텀 프레임 3종(전사/마법사/도적 × normal/unique/legend), 카드 5개 사이트 통합 레이아웃. 보상 등급 가중 추첨 70/25/5 |
|
||||
| **영혼(Soul) 메타 성장** | 승천과 별개의 영구 강화 화폐. 2차 전직 상태로 보스 클리어 시 적립 → 로비 영혼 상점 4종 해금(시작 메소 +60·HP +15·덱 정제·시작 유물 +1). **UserDataStorage 영구 저장** |
|
||||
| **승천(Ascension)** | A1~A10 누적 모디파이어(적 강화·시작 HP 감소·보상 감소). UserDataStorage 유저별 영구 저장, 런 클리어 시 다음 단계 해금 |
|
||||
| **멀티 act** | **5막** 진행(보스 클리어→다음 막 텔레포트, 맵·인카운터 변경, 적 스케일 `1+(막-1)*0.45`), 5막 클리어 시 런 종료 |
|
||||
| **경제** | 화폐 표기 **메소**(코인 아이콘), 카드/유물/물약 메소 가격. 내부 식별자는 Gold 유지 |
|
||||
| **밸런스 시뮬** | `tools/balance/sim-balance.mjs` — 전투 규칙 JS 미러(몬테카를로) + `tools/map/rogue-map.mjs`(맵 생성 미러) + node 단위테스트(현 97종) |
|
||||
|
||||
> ⚠️ 수치(적 스탯·경제·승천 배율)는 1차 조정 상태입니다. 정밀 밸런싱은 `sim-balance.mjs`로 검증하며 진행합니다.
|
||||
> ℹ️ 도적 계열 카드 132장은 STS Silent 완역 포트 + **공식 스킬 아이콘 적용 완료**, rogue 1차 + 어쌔신/시프(2차) + 헤르밋/시프 마스터(3차)로 재편. 남은 작업은 카드명 메이플 재서사·멀티플레이어 전제 카드 싱글 정리 — [`docs/deck-concept.md`](docs/deck-concept.md)·[`docs/bandit-card-audit.md`](docs/bandit-card-audit.md) 참조.
|
||||
|
||||
### 유용한 스크립트 호출
|
||||
`/common` 엔티티(또는 Play Test 컨텍스트)에서:
|
||||
```lua
|
||||
local c = _EntityService:GetEntityByPath("/common").SlayDeckController
|
||||
c:PlayCard(1) -- 손패 slot 카드 사용
|
||||
c:EndPlayerTurn() -- 턴 종료 → 적 턴 → 다음 턴
|
||||
c:StartCombat() -- 전투 재시작(상태 초기화)
|
||||
-- 로비
|
||||
c:OnLobbyNpcInteract("run") -- 모험가(런 시작) / "codex"(도감) / "shop"(영혼상점) / "board"(게시판)
|
||||
c:ShowLobby() -- 로비 맵 복귀 + 상태 초기화
|
||||
-- 런
|
||||
c:SelectClass("warrior") -- "warrior" / "rogue" / "magician"
|
||||
c:StartNewGame() -- 캐릭터 선택 → 런 시작(map01 텔레포트)
|
||||
c:PickNode("r1c2") -- 맵 노드 선택(절차 생성 그리드 id) / "boss"
|
||||
c:PlayCard(1) -- 손패 slot 카드 사용
|
||||
c:EndPlayerTurn() -- 턴 종료 → 적 턴 → 다음 턴
|
||||
c:PickReward(1) -- 보상 카드 1택(0=건너뛰기)
|
||||
c:BuyCard(1) / c:BuyRelic() / c:BuyPotion() -- 상점 구매(메소)
|
||||
c:SetJob("fighter") -- 전직 (보스 보상 화면) — 2차: fighter/page/spearman·firepoison/icelightning/cleric·assassin/thief, 3차: hermit/thiefmaster
|
||||
c:AdjustAscension(1) -- 메뉴에서 승천 단계 +1
|
||||
```
|
||||
|
||||
상세 설계는 [`docs/slaymaple_basic_framework.md`](docs/slaymaple_basic_framework.md) 참조.
|
||||
밸런스 검증: `node tools/balance/sim-balance.mjs [N] [--seed S]` · 테스트: `node --test tools/balance/sim-balance.test.mjs tools/map/rogue-map.test.mjs`.
|
||||
상세 설계는 [`docs/slaymaple_basic_framework.md`](docs/slaymaple_basic_framework.md) 및 `docs/superpowers/specs/` 참조.
|
||||
|
||||
---
|
||||
### 디버그 단축키
|
||||
|
||||
## 향후 설계 (미구현 — 목표 아키텍처)
|
||||
개발·QA용 키보드 단축키. **전투 중**(런 활성 + 전투 진행 중)에만 동작합니다.
|
||||
|
||||
아래는 로그라이크 메타까지 확장했을 때의 **목표 컴포넌트 구조**로, 현재는 미구현입니다. (현재는 `SlayDeckController` 하나가 카드 전투만 담당)
|
||||
|
||||
| 컴포넌트 (계획) | 역할 |
|
||||
| 단축키 | 기능 |
|
||||
|---|---|
|
||||
| `SlayCardCatalog` | 카드 데이터, 시작 덱 구성, 보상 풀, 카드 복제 정의 |
|
||||
| `SlayRunState` | HP·골드·층수·덱·유물·카드 보상 등 런(run) 영속 데이터 관리 |
|
||||
| `SlayCombatManager` | 턴 진행, 드로우/버림/소멸 더미, 에너지, 적 의도, 방어도, 데미지, 승패 처리 |
|
||||
| **Ctrl + Shift + C** | **카드 picker** — 직업 전체 카드 패널을 띄우고, 카드를 클릭하면 **즉시 손패에 추가**. 상단 탭(전사/도적/마법사)으로 직업별 카드 풀 전환. 카드 효과·메커니즘 즉석 테스트용 |
|
||||
| **Ctrl + Shift + E** | **전체 회복 치트** — 체력·에너지를 최대치로 회복 |
|
||||
|
||||
> 위 구조로 가더라도 카드/적 데이터는 `tools/`의 결정적 생성기를 단일 소스로 유지하는 방향을 권장합니다.
|
||||
> 카드 picker는 메이커 저작 UI `DeckUIGroup/DeckAllHud`(120 슬롯 그리드 + 직업 탭 3종)를 사용하고, 컨트롤러가 런타임에 카드 비주얼·버튼을 바인딩합니다. 구현: 키 바인딩 `tools/deck/cb/boot.mjs`, picker 로직 `tools/deck/cb/deckview.mjs`(`OpenDebugCardPicker`/`OnAllDeckCardButton`), 버튼 바인딩 `tools/deck/cb/deckturn.mjs`(`BindButtons`). 옛 picker UI 생성기 `tools/deck/legacy/hud/deckall.mjs`는 UI 메이커-저작 전환 후 **휴면**(Maker UI가 대체).
|
||||
|
||||
### 산출물 재생성
|
||||
```bash
|
||||
node tools/deck/gen-slaydeck.mjs # 컨트롤러+common (UI는 메이커 저작 — 미생성)
|
||||
node tools/map/gen-maps.mjs # map01~05 배경/타일
|
||||
node tools/map/gen-lobby-map.mjs # 로비 맵 + NPC 배치
|
||||
node tools/player/gen-lobby-npc.mjs # 로비 codeblock(LobbyNpc·LobbyMobility)
|
||||
node tools/camera/gen-camera.mjs # 맵별 카메라
|
||||
node tools/player/gen-player-lock.mjs # 전투맵 입력 잠금
|
||||
node tools/monster/gen-monster-models.mjs # 적 종별 모델 .model (외형=enemies.json appearance)
|
||||
node tools/monster/gen-combat-monster.mjs # 자기등록 마커 codeblock
|
||||
node tools/map/gen-map-encounters.mjs # encounters.json 로스터 기반 맵 몬스터 배치
|
||||
```
|
||||
> 산출물 검증은 내용 출력 없이 카운트만: `node tools/verify/count.mjs <ui|cb|common> <regex>...`. 정적 가드 — 카드 kind↔효과 `cardkinds.mjs` · 미선언 self 대입 `cbprops.mjs` · UI 경로 재연결 GAP `cbgap.mjs` · 리팩터 바이트동일 `diffcheck.mjs` (자세한 가드는 [`RULES.md`](RULES.md)).
|
||||
|
||||
---
|
||||
|
||||
## 다음 구현 단계
|
||||
- [x] HP·방어도·에너지·적 의도·손패 카드를 렌더링하는 전투 UI **(완료 — `SlayDeckController` + CombatHud)**
|
||||
- [x] 카드 사용이 실제 데미지/방어/적 의도/승패에 반영되는 단일 전투 루프 **(완료)**
|
||||
- [ ] 카드/적 데이터를 `data/cards.json` · `data/enemies.json`로 외부화 (D)
|
||||
- [ ] 전투를 N회 자동 시뮬레이션하는 밸런스 검증 도구 `tools/sim-balance.mjs` (F, D 선행)
|
||||
- [ ] 전투/엘리트/상점/휴식/이벤트/보스 노드를 가진 맵 노드 UI (E)
|
||||
- [ ] `OnCombatStart` / `OnCardPlayed` / `OnTurnStart` / `OnCombatReward` 훅을 가진 유물 시스템 (E)
|
||||
- [ ] 적 행동 패턴을 데이터로 정의 (현재 단순 결정적 의도 사이클 → 무브셋)
|
||||
- [ ] 런 영속(HP/골드/층/덱/유물) + 저장/불러오기 (E, 루프 end-to-end 후)
|
||||
## 아키텍처 메모
|
||||
|
||||
현재 게임 전체 로직이 `SlayDeckController` 단일 codeblock에 모여 있습니다. 초기 설계의 3분할(`SlayCardCatalog`/`SlayRunState`/`SlayCombatManager`)은 **기능적으로 모두 구현**됐으나 아직 한 컴포넌트 안에 있습니다. 맵 NPC·카메라·입력 잠금 등 **맵 단위 동작은 별도 codeblock**(LobbyNpc/LobbyMobility/MapCamera/PlayerLock/CombatMonster)으로 분리해 각 맵 루트/엔티티에 부착합니다. 카드/적/맵/유물/프레임/카메라 데이터는 `data/*.json`로 외부화돼 있습니다. **2026-06-17**: UI를 단일 `DefaultGroup`에서 7개 UIGroup(Select/Lobby/Run/Deck 등)으로 분리해 **메이커 저작으로 전환** — 생성기는 더 이상 `.ui`를 만들지 않고, 컨트롤러가 새 UIGroup 경로로 재연결됨(옛 UI emit `hud/*`·`gen-cardhand`는 `tools/deck/legacy/` 휴면). 재연결 무결성은 `tools/verify/cbgap.mjs`(GAP 0)로 검증.
|
||||
|
||||
> ⚠️ **전투 규칙과 맵 생성은 Lua(gen-slaydeck 내장)와 JS 미러(sim-balance/rogue-map)로 이중 구현**입니다. 한쪽을 고치면 반드시 다른 쪽도 동기화하고 테스트하세요(`RULES.md` §6).
|
||||
> ⚠️ **카드 `kind`는 효과와 반드시 일치**해야 합니다 — 데미지=`Attack`, 방어/유틸=`Skill`, 지속효과=`Power`. 안 맞으면 런타임 에러 없이 *사용 불가/무효과 死카드*가 됩니다(2026-06-30 Defend·Rage 사고). 새 효과 필드는 `docs/card-effect-fields.md` 등록 + Lua/JS 양쪽 핸들러 구현. 정적 검증 `node tools/verify/cardkinds.mjs`(`RULES.md` §9). cb Lua 지역변수는 의미명 사용(`RULES.md` §8).
|
||||
|
||||
---
|
||||
|
||||
## 향후 개선 계획 (후속 후보)
|
||||
- [x] 전투 루프 · 런 루프 · 절차 생성 맵 · 상점/휴식/유물 방 · 유물 19종 · 물약 · 버프/디버프 · Power · 전직(전사/법사/도적 2차) · 승천+개인 저장 · 전투 모션 · 커스텀 프레임 · **반복 런·로비 맵·NPC·영혼·메소·카메라 추종 (P1~P15 완료)**
|
||||
- [x] **UI 메이커-저작 전환** — 단일 DefaultGroup → 7개 UIGroup 분리, 생성기 UI 저작 폐기(`tools/deck/legacy/`), 컨트롤러 경로 재연결(cbgap GAP 0) (2026-06-17)
|
||||
- [x] **시작 로비 직행 · 캐릭터 선택 UI · 디버그 치트 · map01 로스터 (2026-06-18)** — 게임 시작 시 MainMenu 없이 곧장 로비 진입(MainMenu는 추후 싱글/멀티/종료 메뉴로 재지정); 캐릭터 선택 화면 초상화·직업 설명·선택 테두리·Art 클리핑(MaskComponent) 배선; 디버그 단축키 Ctrl+Shift+C(카드 picker)·Ctrl+Shift+E(체력+에너지 전체 회복); map01 몬스터 18종 로스터(랜덤 행동)
|
||||
- [x] **컨트롤러 관심사별 모듈 분리 · 코드 규칙 (2026-06-26, #94)** — SlayDeckController를 `cb/*.mjs` 20모듈로 분리(런타임은 단일 codeblock 유지), 변수명 의미화, 검증 `cbset.mjs`(집합 무손실)·`cbprops.mjs`(미선언 self)
|
||||
- [x] **도적 계열 대개편 + 3차 전직 · 카드 공용 효과 (2026-06-23~30, #82~#99)** — Silent 포트를 rogue 1차 + 어쌔신/시프(2차) + 헤르밋/시프 마스터(3차)로 재편, 카드 효과를 카드명 하드코딩 대신 `cards.json` 공용 필드로(`docs/card-effect-fields.md`), 카드 **166장**
|
||||
- [x] **코드리뷰 버그수정 + kind↔효과 규칙 (2026-06-29~30, #96·#102)** — 게임버그 6·시뮬 충실도 3·설명 2 수정(Defend kind Attack→Skill·Rage Power→Attack 포함), kind↔효과 정적 검증 `cardkinds.mjs`, 카드 왕복 편집 엑셀(#93)
|
||||
- [ ] **도적 카드명 재서사·설명 한글화** — Silent 직역 카드명을 어쌔신/시프 메이플 스킬명으로 재서사(아이콘은 적용 완료), 2·3차 전직 설명 한글화
|
||||
- [ ] **런 이어하기** — 진행 중 런 직렬화 저장(UserDataStorage 확장, 메뉴 "이어하기" 활성화)
|
||||
- [ ] **카드 제거/업그레이드** — 상점 카드 제거 슬롯, 휴식 노드에서 카드 강화
|
||||
- [ ] **이벤트 노드(?)** — 랜덤 텍스트 이벤트(선택지·리스크/리워드)
|
||||
- [ ] **3차 전직 — 전사·법사 확장** (도적은 완료: 헤르밋·시프 마스터), 후반 막 보상으로
|
||||
- [ ] **궁수 등 추가 클래스** — 캐릭터 선택 슬롯 확장
|
||||
- [ ] **정밀 밸런싱** — 첫 인카운터 승률 완화·직업별 카드 효율 튜닝(`sim-balance.mjs` 리포트 기반)
|
||||
- [ ] **상점 보장 규칙** — 막당 상점 최소 1회 등장
|
||||
- [ ] **연출 보강** — 사운드(타격·획득), 맵 화면에 유물/물약 표시
|
||||
|
||||
---
|
||||
|
||||
@@ -141,4 +225,5 @@ c:StartCombat() -- 전투 재시작(상태 초기화)
|
||||
```
|
||||
2. MSW Maker에서 이 폴더를 **로컬 워크스페이스 경로**로 지정해 월드 열기
|
||||
3. `.mcp.json` / `.codex/` 는 git에 없으므로, 본인 토큰으로 직접 생성 (MCP·Codex 사용 시)
|
||||
4. 작업 전 항상 `git pull`, 작업 후 `git add/commit/push`
|
||||
4. 작업 전 항상 `git pull` + 메이커 reload, 작업 후 `git add/commit/push`
|
||||
5. **AI 에이전트(Claude Code 등)로 작업한다면 [`RULES.md`](RULES.md) 필독** — 생성 산출물 접근 금지(토큰 가드)·검증 절차·PR 도구(`tools/git/gitea-pr.mjs`) 규칙. Claude Code는 `CLAUDE.md`가 자동 적용
|
||||
|
||||
107
RULES.md
Normal file
107
RULES.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# RULES.md — SlayMaple 하네스 엔지니어링 규칙
|
||||
|
||||
AI 에이전트(Claude Code 등)와 협업자가 이 저장소에서 **토큰을 낭비하지 않고 안전하게** 작업하기 위한 공용 규칙.
|
||||
Claude Code는 `CLAUDE.md`가 이 파일을 임포트하므로 자동 적용된다. 다른 도구(Codex 등)를 쓰면 세션 시작 시 이 파일을 읽혀라.
|
||||
|
||||
---
|
||||
|
||||
## 1. 생성 산출물은 읽지도, 고치지도 않는다 (가장 중요)
|
||||
|
||||
이 저장소의 큰 파일들은 전부 **생성기 산출물**이다. 직접 읽으면 토큰이 증발하고, 직접 고치면 다음 재생성 때 사라진다.
|
||||
|
||||
| 산출물 (절대 Read/Edit 금지) | 크기 | 단일 소스 (여기만 편집) | 재생성 명령 |
|
||||
|---|---|---|---|
|
||||
| `ui/*.ui` (Default·Select·Lobby·Run·Deck·Popup·Toast UIGroup 7종) | 9KB~4.5MB | **메이커 저작 (생성기 미생성, 2026-06-17~)** — 메이커에서 시각 편집 | (없음) |
|
||||
| `RootDesk/MyDesk/SlayDeckController.codeblock` | ~270KB | `data/*.json` + `tools/deck/`(`gen-slaydeck.mjs`+`lib/`+`cb/`) | `node tools/deck/gen-slaydeck.mjs` |
|
||||
| `Global/common.gamelogic` | ~1KB | 〃 | 〃 |
|
||||
| `map/map01.map`~`map05.map`, `map/lobby.map` | 각 ~210KB | `tools/map/`·`tools/monster/`·`tools/camera/`·`tools/player/` (↓ 보조 생성기) | 해당 생성기 |
|
||||
| `RootDesk/MyDesk/CombatMonster.codeblock` | ~2KB | `tools/monster/gen-combat-monster.mjs` | `node tools/monster/gen-combat-monster.mjs` |
|
||||
| `RootDesk/MyDesk/Models/Monsters/<enemyId>.model` (적 종별, 최대 18종) | 각 ~5KB | `data/enemies.json`(`appearance`) + `tools/monster/gen-monster-models.mjs` | `node tools/monster/gen-monster-models.mjs` |
|
||||
| `RootDesk/MyDesk/PlayerLock.codeblock` | ~2KB | `tools/player/gen-player-lock.mjs` | `node tools/player/gen-player-lock.mjs` |
|
||||
| `RootDesk/MyDesk/MapCamera.codeblock` | ~2KB | `tools/camera/gen-camera.mjs` (값: `data/camera.json`) | `node tools/camera/gen-camera.mjs` |
|
||||
| `RootDesk/MyDesk/LobbyNpc.codeblock`·`LobbyMobility.codeblock` | 각 ~2-3KB | `tools/player/gen-lobby-npc.mjs` | `node tools/player/gen-lobby-npc.mjs` |
|
||||
| `Global/SectorConfig.config` | ~1KB | `tools/map/gen-maps.mjs`·`gen-lobby-map.mjs` (패치) | 해당 생성기 |
|
||||
|
||||
- `.claude/settings.json`의 permissions.deny가 위 파일의 Read/Edit/Write 도구 사용을 차단한다 (이 저장소를 열면 자동 적용). deny는 **glob** — `ui/*.ui`·`map/*.map`·`RootDesk/MyDesk/*.codeblock`·`Global/common.gamelogic`·`Global/SectorConfig.config`. 따라서 **메이커 저작 codeblock/UI**(`Monster`·`MonsterAttack`·`PlayerAttack`·`PlayerHit`·`UIPopup`·`UIToast`.codeblock, **그리고 모든 `ui/*.ui`** — UI는 6개 UIGroup으로 메이커 저작)**도** Read/Edit 금지 — 이들은 생성기가 없으니 **메이커에서** 편집한다(텍스트 도구로 X). codeblock은 한 줄짜리 JSON이라 Read 시 토큰 폭발.
|
||||
- **게임 로직 수정** = `tools/deck/gen-slaydeck.mjs`(오케스트레이터) + `tools/deck/cb/*.mjs`(codeblock Lua) 또는 `data/*.json`(데이터) 수정 → 재생성(`SlayDeckController.codeblock`+`common.gamelogic`만, **`.ui` 미접근**) → 통째로 커밋. **UI 수정 = 메이커에서**(생성기는 UI를 안 만든다).
|
||||
- **codeblock 메서드(Lua)는 관심사별 모듈** `tools/deck/cb/*.mjs`(boot·screens·npc·navigation·layout·combat·hand·deckview·items·map·shop 등 20종 — 화면전환=`screens`·NPC=`npc`·포지션=`navigation`(월드 텔레포트)/`layout`(UI 슬롯 배치). 새 메서드는 관심사에 맞는 모듈에 작성하고, 한 모듈이 비대해지면 분할한다. 횡단 관심사를 한 모듈에 몰아넣지 않는다). **공유분**: 상수·데이터·lua 테이블 = `tools/deck/lib/{ui-helpers,data,codeblock}.mjs`(cb가 import — `MAX_MONSTERS`=4 등). prop 103개는 오케스트레이터 `writeCodeblocks`에 유지. 특정 메서드 수정은 `cb/<name>.mjs`만(의존: orchestrator→cb→lib 단방향). **cb 모듈은 원본 메서드 순서 보존이 바이트동일 조건**. **UI emit(옛 `hud/*.mjs` 15종·`gen-cardhand.mjs`)은 `tools/deck/legacy/`로 이관 — 휴면(생성기 미사용)**: UI가 메이커 저작이라 생성기가 안 만든다. (롤백용 `legacy/upsert-ui.mjs`는 직접 실행 시에만 옛 `DefaultGroup.ui`를 재생성.)
|
||||
- 리팩터 시 **출력 바이트-동일 검증**: `node tools/deck/gen-slaydeck.mjs` 후 `node tools/verify/diffcheck.mjs [ref]`(워킹트리 vs ref(기본 HEAD) 줄바꿈 정규화 비교 — 산출물 경로를 명령줄에 노출 안 해 deny 회피). 산출물 ` M`은 보통 autocrlf churn이니 `git checkout --`로 복원.
|
||||
- **UI 전면 메이커 저작 (2026-06-17~)**: 단일 `DefaultGroup`을 7개 UIGroup으로 분리 — `DefaultGroup`(MainMenu+월드조작), `SelectUIGroup`(charselect/job), `LobbyUIGroup`(lobby/board/soulshop), `RunUIGroup`(combat/map/shop/rest/treasure/reward/cardhand/deck), `DeckUIGroup`(덱 도감), `PopupGroup`·`ToastGroup`. 컨트롤러(`cb/*.mjs`)는 엔티티 **경로**(`/ui/<UIGroup>/<Hud>/...`)로 텍스트·이미지·표시숨김·상태기반 위치/크기/색을 **런타임 주입**(레이아웃=메이커, 내용=컨트롤러 — 메이커가 이 경로 유지 필수). 몬스터 슬롯 = `RunUIGroup/CombatHud/MonsterStatus{1..4}`(자식 Name·Hp·Intent·HpBarFill·Buffs·BlockBadge·TargetMarker; TargetFrame 없음). **부트 흐름**: `OnBeginPlay`→MainMenu→(`MainMenu/NewGameButton`)→로비→run NPC(`OnLobbyNpcInteract` id=="run")→charselect→런. **재연결 검증**: `node tools/verify/cbgap.mjs`(cb 참조 경로↔.ui GAP 0이어야) + 재생성 후 `git status -- ui/` 변경 0(생성기 .ui 미접근 증명). 섹션→UIGroup 일괄 remap 마이그레이션은 `tools/deck/reconnect-ui-paths.mjs`(멱등). UIGroup별 .ui 분포 확인은 `tools/verify/uimap.mjs`.
|
||||
- **머지 충돌(gen-slaydeck.mjs)**: 다른 브랜치가 단일체를 수정해 충돌나면, 그쪽 버전(`git checkout --theirs tools/deck/gen-slaydeck.mjs`)을 취해 **콘텐츠 마커 기반으로 재모듈화**(라인인덱스 X — 줄 추가에 안전·export 이름 자동 파생·`const x=[]` 직전 전문 상수 walk-back 포함) 후 `node tools/verify/diffcheck.mjs origin/main`으로 ui·codeblock 바이트-동일 확인(손실 0 증명). codeblock 메서드·patchCommon은 오케스트레이터 잔류라 그쪽 변경은 자동 보존됨.
|
||||
- **보조 생성기**(각자 자기 산출물의 단일 소스 — 위 표의 메인 `gen-slaydeck.mjs` 외):
|
||||
- `tools/camera/gen-camera.mjs` → `MapCamera.codeblock` + map01~05 카메라 부착 (값 `data/camera.json`)
|
||||
- `tools/map/gen-maps.mjs` → `map02~05` + `Global/SectorConfig.config` (map01 템플릿 클론)
|
||||
- `tools/map/gen-lobby-map.mjs` → `map/lobby.map` + `SectorConfig.config`
|
||||
- `tools/monster/gen-monster-models.mjs` → `Models/Monsters/<enemyId>.model`(적 종별, 외형·EnemyId 베이크·태생 AI-free). 단일 소스 `data/enemies.json`의 `appearance`. `appearance` 미보유 적은 스킵(메이커 저작 모델 `HolodragonKing`·`Model_monster-43`은 예외 — 이 생성기 대상 아님). 공용 빌더 `tools/monster/lib/monster-model.mjs`.
|
||||
- `tools/map/gen-map-encounters.mjs` → map01~05에 `data/encounters.json` 로스터 기반 **종별 모델 인스턴스** 배치(외형=정체성 고정). 준비도 가드: 로스터에 `appearance` 미보유 적이 있는 맵은 재생성 스킵(기존 보존). 값 검증 `node --test tools/monster/monster-model.test.mjs`.
|
||||
- `tools/monster/gen-combat-monster.mjs` → `CombatMonster.codeblock`(자기등록 마커)만 생성. 맵 부착값(EnemyId/Group)은 `gen-map-encounters.mjs`가 인스턴스에 직접 기록.
|
||||
- `tools/monster/freeze-turn-monsters.mjs` → 레거시 공용 몬스터 `.model`·맵 AI 컴포넌트 제거(신규 종별 모델은 태생 frozen — 대상 아님).
|
||||
- `tools/player/gen-player-lock.mjs` → `PlayerLock.codeblock` + map01~05 부착
|
||||
- `tools/player/gen-lobby-npc.mjs` → `LobbyNpc.codeblock`·`LobbyMobility.codeblock`
|
||||
- `tools/player/freeze-turn-player.mjs` → `Global/DefaultPlayer.model` 이동 0 고정
|
||||
- (옛 `tools/deck/gen-cardhand.mjs`·`hud/*.mjs`는 `tools/deck/legacy/`로 이관 — 휴면, UI 메이커 저작 전환)
|
||||
|
||||
## 2. 산출물 검증은 카운트로, 내용 출력 금지
|
||||
|
||||
재생성 결과 확인이 필요하면 **본문을 출력하지 말고** 존재/개수만 확인한다:
|
||||
|
||||
```bash
|
||||
node tools/deck/gen-slaydeck.mjs # 성공 메시지 1줄
|
||||
grep -c "TreasureHud" ui/DefaultGroup.ui # 개수만
|
||||
grep -c "CalcPlayerAttack" RootDesk/MyDesk/SlayDeckController.codeblock
|
||||
```
|
||||
|
||||
- ⚠️ codeblock은 **한 줄이 수만 자**(JSON 직렬화)다. `grep`(내용 출력)·`sed -n` 광역 범위 출력은 한 줄만 걸려도 토큰 폭발 → `grep -c`/`grep -l`/`grep -o '짧은패턴'`만 사용.
|
||||
- Claude Code의 Grep 도구를 산출물에 쓸 때는 `output_mode: count` 또는 `files_with_matches`만. content 모드 금지.
|
||||
- 진짜 내용 확인이 필요하면 좁은 `grep -o` 또는 `python`으로 슬라이스해서 **수 줄 이내**로.
|
||||
|
||||
## 3. 탐색 규칙
|
||||
|
||||
- 코드 탐색은 `tools/`·`data/`·`docs/`만 대상으로. 저장소 전체 grep은 산출물이 걸리므로 경로를 지정한다.
|
||||
- `git add -A` 전 `git status --short`로 산출물 외 의도치 않은 변경이 없는지 확인 (산출물 diff는 보지 않는다 — 생성기가 결정적이므로 소스 리뷰로 충분).
|
||||
- 게임 동작 확인은 메이커 플레이테스트(스크린샷·로그)로 한다. 산출물 정독으로 동작을 추론하지 않는다.
|
||||
|
||||
## 4. Git/PR 절차
|
||||
|
||||
- 브랜치 → 커밋(기능 단위) → push → **PR은 반드시 `node tools/git/gitea-pr.mjs`로** (인라인 `curl -d` 한글 본문은 Windows에서 CP949로 깨짐 — PR #34~41 사고).
|
||||
- 제목/본문은 UTF-8 spec JSON 파일로 작성 후 `create <spec.json>` / `merge <번호>`.
|
||||
- PR 제목과 본문은 한국어로 작성한다.
|
||||
- 산출물 재생성 커밋은 소스 변경 커밋과 분리하거나, 메시지에 "산출물 재생성"을 명시.
|
||||
- **PR 머지 후 브랜치 삭제**: 머지된 `feature/*`·`docs/*` 브랜치는 로컬·원격 모두 삭제한다. 삭제 전 `git merge-base --is-ancestor origin/<브랜치> origin/main`로 완전 머지 확인(종료코드 0=완전 머지 → 삭제 가능). main에 없는 커밋이 남은 브랜치와 `codex/*` 등 작업 중 브랜치는 보존한다.
|
||||
- **⚠️ main 머지 충돌 시 "머지 전체 revert" 금지 (타인 작업 유실 방지)**: 작업 브랜치에 `git merge main`(또는 origin/main) 했다가 충돌·문제가 나도 **그 머지 커밋을 통째로 `git revert` 하지 말 것.** main에 먼저 들어간 타인의 작업이 collateral로 전부 사라진다. 대신 **소스 충돌만 해소**하고 산출물(codeblock 등)은 **재생성**한다. 충돌이 산출물뿐이면 `git checkout --theirs`/재생성으로 끝. (2026-06-30 사고: codex `#98/#99`가 main 머지 후 그 머지를 revert해 `#96`의 버그수정 11개를 전부 날림 → 다시 재통합해야 했다. 복구는 `git diff <pre-merge> <내브랜치> -- <소스> | git apply --3way` 로 소스만 재적용 후 재생성하면 codex 변경과 충돌 없이 양립.)
|
||||
|
||||
## 5. 메이커(MSW) 연동 주의
|
||||
|
||||
- git pull 후 메이커에서 **로컬 워크스페이스 reload** 필수 (안 하면 메이커의 stale 상태가 디스크를 덮어씀).
|
||||
- 재생성 후 메이커가 켜져 있으면 refresh → 빌드 콘솔 0 에러 확인.
|
||||
- 카드/유물/물약 이미지는 **공식 maplestory 리소스 RUID**만 (계정 업로드 리소스는 로컬 워크스페이스에서 흰 박스).
|
||||
|
||||
## 6. 밸런스·맵 규칙 동기화
|
||||
|
||||
전투 규칙과 맵 생성은 Lua(생성기 내장)와 JS가 **이중 구현**이다. 한쪽을 고치면 반드시 다른 쪽도:
|
||||
|
||||
| 영역 | Lua (gen-slaydeck.mjs 내) | JS 미러 | 테스트 |
|
||||
|---|---|---|---|
|
||||
| 전투 규칙 | PlayCard·CalcPlayerAttack 등 | `tools/balance/sim-balance.mjs` | `node --test tools/balance/sim-balance.test.mjs` |
|
||||
| 맵 생성 | GenerateMap | `tools/map/rogue-map.mjs` | `node --test tools/map/rogue-map.test.mjs` |
|
||||
|
||||
## 7. UI 숫자 표기
|
||||
|
||||
- UI 텍스트에서는 정수값인 숫자에 `.0`을 붙이지 않는다. `1.0/1.0`이 아니라 `1/1`처럼 표시한다.
|
||||
- 생성기 내 Lua UI 코드에서 number 또는 숫자 문자열을 텍스트에 붙일 때는 `FormatNumber` 같은 포맷 헬퍼를 우선 사용한다.
|
||||
- 소수부가 플레이어에게 의미 있을 때만 소수점 표기를 유지한다.
|
||||
|
||||
## 8. codeblock 변수명
|
||||
|
||||
- cb(`tools/deck/cb/*.mjs`)의 Lua 지역변수는 **의미가 드러나는 이름**으로 작성한다(`e`→`entity`, `n`→`count`, `m`→`monster`, `lp`→`localPlayer`, `s`→`soulPoints`, `tr`→`transform`). `a`/`b`/`c` 같은 무의미 단일문자 변수는 금지.
|
||||
- 단, 순수 반복 인덱스 `i`/`j`/`r`/`c`는 관용상 허용한다.
|
||||
- 새 cb 메서드를 작성하거나 기존 메서드를 손댈 때 이 규칙을 적용한다(대규모 일괄 개명은 별도 작업으로).
|
||||
|
||||
## 9. 카드 데이터 규칙 (kind ↔ 효과 일치)
|
||||
|
||||
새 카드를 추가/수정할 때 `data/cards.json`의 `kind`는 카드의 효과·사용 메커니즘과 **반드시 일치**해야 한다. 안 맞으면 카드가 **사용 불가**거나 **재생 시 아무 효과 없는 死카드**가 된다(런타임 에러도 안 나고 sim 테스트도 못 잡음 — 정적 검증 필수).
|
||||
|
||||
- **`ResolveCardDrop` 사용 라우팅이 kind별로 다름**: `Attack`=몬스터 위에 드롭(`FindMonsterAtTouch>0` 필요)·`Skill`/`Power`=위로 스윕(`ui.y>-180`)·`Status`=unplayable. → **block·디버프·드로우 등 유틸만 있고 데미지가 없는 카드를 `Attack`으로 두면 위로 스윕으로 사용할 수 없다**(2026-06-30 아이언 바디 사고: block만 있는 방어카드가 Attack이라 전사 시작덱 4장이 먹통 → Skill로 수정).
|
||||
- **`PlayCard`의 `Power` 분기는 PlayerPowers 등록만 하고 `damage`/`aoe`를 무시**한다. → 데미지 카드=`Attack`, 방어/유틸=`Skill`, 지속효과=`Power`(단 `powerEffect` 또는 지속/온플레이 power 필드 — `turnStart*`·`dex`·`thorns`·`intangible`·`attackPoison`·`drawDamage`·`shivX`·`cardPlayed*` 등 — 이 있어야 함). Power인데 power 효과 필드가 없으면 死카드(2026-06-30 분노 사고: `damage:4/aoe`만 있어 Power 분기서 무시됨 → kind Power→Attack으로 기능화).
|
||||
- 새 효과 필드는 `docs/card-effect-fields.md` 사전에 등록하고 Lua(`tools/deck/cb/*.mjs`) + JS 미러(`tools/balance/sim-balance.mjs`) **양쪽에 핸들러 구현**(§6). 한쪽만 있으면 게임↔시뮬 드리프트.
|
||||
- **검증: `node tools/verify/cardkinds.mjs`** — kind↔효과 위반(Attack-무데미지 / Power-무효과 / 미지원 kind)을 정적 검출(이상 0 = exit 0). 카드 추가/수정 후 반드시 실행. (관련 가드: 미선언 `self.X` = `cbprops.mjs`, UI 경로 = `cbgap.mjs`, 이중구현 = `sim-balance.test.mjs`.)
|
||||
23
RootDesk/MyDesk/01_blue_background_clean_1920x1080.sprite
Normal file
23
RootDesk/MyDesk/01_blue_background_clean_1920x1080.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://ac448e909f89464898708ce232ab8b51",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/ac448e909f89464898708ce232ab8b51/639173152021849887",
|
||||
"upload_hash": "CCC4771B9353971748EF9BEE32D57F15090CE62C4BA6446B11E7842FC7AFDF1F",
|
||||
"name": "01_blue_background_clean_1920x1080",
|
||||
"resource_guid": "ac448e909f89464898708ce232ab8b51",
|
||||
"resource_version": "6a32dd82c325482f6e2bb455"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/Character select bg.sprite
Normal file
23
RootDesk/MyDesk/Character select bg.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://7629b520ced54d508b040681d06741fb",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/7629b520ced54d508b040681d06741fb/639172208899179951",
|
||||
"upload_hash": "C84DCE36101CF3F05E74F93F9B416E7D08D8B78B699E22CF8A6784994115DDAE",
|
||||
"name": "Character select bg",
|
||||
"resource_guid": "7629b520ced54d508b040681d06741fb",
|
||||
"resource_version": "6a316d1a3d5de2eb0c7d345b"
|
||||
}
|
||||
}
|
||||
}
|
||||
74
RootDesk/MyDesk/CombatMonster.codeblock
Normal file
74
RootDesk/MyDesk/CombatMonster.codeblock
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "codeblock://combatmonster",
|
||||
"ContentType": "x-mod/codeblock",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"CoreVersion": {
|
||||
"Major": 0,
|
||||
"Minor": 2
|
||||
},
|
||||
"ScriptVersion": {
|
||||
"Major": 1,
|
||||
"Minor": 0
|
||||
},
|
||||
"Description": "",
|
||||
"Id": "CombatMonster",
|
||||
"Language": 1,
|
||||
"Name": "CombatMonster",
|
||||
"Type": 1,
|
||||
"Source": 0,
|
||||
"Target": null,
|
||||
"Properties": [
|
||||
{
|
||||
"Type": "string",
|
||||
"DefaultValue": "\"\"",
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": "EnemyId"
|
||||
},
|
||||
{
|
||||
"Type": "string",
|
||||
"DefaultValue": "\"combat\"",
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": "Group"
|
||||
},
|
||||
{
|
||||
"Type": "number",
|
||||
"DefaultValue": "0",
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": "RegTries"
|
||||
}
|
||||
],
|
||||
"Methods": [
|
||||
{
|
||||
"Return": {
|
||||
"Type": "void",
|
||||
"DefaultValue": null,
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": null
|
||||
},
|
||||
"Arguments": [],
|
||||
"Code": "self.RegTries = 0\nlocal eventId = 0\nlocal function reg()\n\tself.RegTries = self.RegTries + 1\n\tlocal c = _EntityService:GetEntityByPath(\"/common\")\n\tif c ~= nil and c.SlayDeckController ~= nil then\n\t\tlocal mapName = \"\"\n\t\tif self.Entity.CurrentMapName ~= nil then\n\t\t\tmapName = self.Entity.CurrentMapName\n\t\tend\n\t\tc.SlayDeckController:RegisterMonster(self.Entity, self.EnemyId, self.Group, mapName)\n\t\t_TimerService:ClearTimer(eventId)\n\telseif self.RegTries > 50 then\n\t\t_TimerService:ClearTimer(eventId)\n\tend\nend\neventId = _TimerService:SetTimerRepeat(reg, 0.1)",
|
||||
"Scope": 2,
|
||||
"ExecSpace": 6,
|
||||
"Attributes": [],
|
||||
"Name": "OnBeginPlay"
|
||||
}
|
||||
],
|
||||
"EntityEventHandlers": []
|
||||
}
|
||||
}
|
||||
}
|
||||
60
RootDesk/MyDesk/LobbyMobility.codeblock
Normal file
60
RootDesk/MyDesk/LobbyMobility.codeblock
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "codeblock://lobbymobility",
|
||||
"ContentType": "x-mod/codeblock",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"CoreVersion": {
|
||||
"Major": 0,
|
||||
"Minor": 2
|
||||
},
|
||||
"ScriptVersion": {
|
||||
"Major": 1,
|
||||
"Minor": 0
|
||||
},
|
||||
"Description": "",
|
||||
"Id": "LobbyMobility",
|
||||
"Language": 1,
|
||||
"Name": "LobbyMobility",
|
||||
"Type": 1,
|
||||
"Source": 0,
|
||||
"Target": null,
|
||||
"Properties": [
|
||||
{
|
||||
"Type": "number",
|
||||
"DefaultValue": "0",
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": "Tries"
|
||||
}
|
||||
],
|
||||
"Methods": [
|
||||
{
|
||||
"Return": {
|
||||
"Type": "void",
|
||||
"DefaultValue": null,
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": null
|
||||
},
|
||||
"Arguments": [],
|
||||
"Code": "self.Tries = 0\nlocal eventId = 0\nlocal function apply()\n\tself.Tries = self.Tries + 1\n\tlocal lp = _UserService.LocalPlayer\n\tif lp ~= nil and lp.PlayerControllerComponent ~= nil then\n\t\tlocal pc = lp.PlayerControllerComponent\n\t\tpc.Enable = true\n\t\tpc.FixedLookAt = 0\n\t\tlocal rb = lp.RigidbodyComponent\n\t\tif rb ~= nil then rb.WalkAcceleration = 0.7 end\n\t\tlocal mv = lp.MovementComponent\n\t\tif mv ~= nil then\n\t\t\tmv.InputSpeed = 1.4\n\t\t\tmv.JumpForce = 1.23\n\t\tend\n\t\tlocal cam = lp.CameraComponent\n\t\tif cam == nil then cam = _CameraService:GetCurrentCameraComponent() end\n\t\tif cam ~= nil then\n\t\t\tcam.ZoomRatio = 90\n\t\t\tcam.ConfineCameraArea = false\n\t\t\tcam.ScreenOffset = Vector2(0.5, 0.5)\n\t\t\tcam.CameraOffset = Vector2(0, 0)\n\t\tend\n\t\t_TimerService:ClearTimer(eventId)\n\telseif self.Tries > 50 then\n\t\t_TimerService:ClearTimer(eventId)\n\tend\nend\neventId = _TimerService:SetTimerRepeat(apply, 0.1)",
|
||||
"Scope": 2,
|
||||
"ExecSpace": 6,
|
||||
"Attributes": [],
|
||||
"Name": "OnBeginPlay"
|
||||
}
|
||||
],
|
||||
"EntityEventHandlers": []
|
||||
}
|
||||
}
|
||||
}
|
||||
89
RootDesk/MyDesk/LobbyNpc.codeblock
Normal file
89
RootDesk/MyDesk/LobbyNpc.codeblock
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "codeblock://lobbynpc",
|
||||
"ContentType": "x-mod/codeblock",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"CoreVersion": {
|
||||
"Major": 0,
|
||||
"Minor": 2
|
||||
},
|
||||
"ScriptVersion": {
|
||||
"Major": 1,
|
||||
"Minor": 0
|
||||
},
|
||||
"Description": "",
|
||||
"Id": "LobbyNpc",
|
||||
"Language": 1,
|
||||
"Name": "LobbyNpc",
|
||||
"Type": 1,
|
||||
"Source": 0,
|
||||
"Target": null,
|
||||
"Properties": [
|
||||
{
|
||||
"Type": "string",
|
||||
"DefaultValue": "\"\"",
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": "NpcId"
|
||||
},
|
||||
{
|
||||
"Type": "string",
|
||||
"DefaultValue": "\"\"",
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": "MarkName"
|
||||
},
|
||||
{
|
||||
"Type": "boolean",
|
||||
"DefaultValue": "false",
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": "InRange"
|
||||
}
|
||||
],
|
||||
"Methods": [
|
||||
{
|
||||
"Return": {
|
||||
"Type": "void",
|
||||
"DefaultValue": null,
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": null
|
||||
},
|
||||
"Arguments": [],
|
||||
"Code": "self.InRange = false\nlocal mark = _EntityService:GetEntityByPath(\"/maps/lobby/\" .. self.MarkName)\nif mark ~= nil then mark:SetVisible(false) end\nself.Entity:ConnectEvent(TouchEvent, function(e)\n\tself:Interact()\nend)\n_InputService:ConnectEvent(KeyDownEvent, function(e)\n\tif self.InRange and e.key == KeyboardKey.UpArrow then\n\t\tself:Interact()\n\tend\nend)\nlocal eventId = 0\nlocal function tick()\n\tlocal lp = _UserService.LocalPlayer\n\tif lp == nil then return end\n\tif mark == nil then mark = _EntityService:GetEntityByPath(\"/maps/lobby/\" .. self.MarkName) end\n\tlocal a = lp.TransformComponent.WorldPosition\n\tlocal b = self.Entity.TransformComponent.WorldPosition\n\tlocal d = Vector2.Distance(Vector2(a.x, a.y), Vector2(b.x, b.y))\n\tlocal near = d < 1.2\n\tif near ~= self.InRange then\n\t\tself.InRange = near\n\t\tif mark ~= nil then mark:SetVisible(near) end\n\tend\nend\neventId = _TimerService:SetTimerRepeat(tick, 0.15)",
|
||||
"Scope": 2,
|
||||
"ExecSpace": 6,
|
||||
"Attributes": [],
|
||||
"Name": "OnBeginPlay"
|
||||
},
|
||||
{
|
||||
"Return": {
|
||||
"Type": "void",
|
||||
"DefaultValue": null,
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": null
|
||||
},
|
||||
"Arguments": [],
|
||||
"Code": "local c = _EntityService:GetEntityByPath(\"/common\")\nif c ~= nil and c.SlayDeckController ~= nil then\n\tc.SlayDeckController:OnLobbyNpcInteract(self.NpcId)\nend",
|
||||
"Scope": 2,
|
||||
"ExecSpace": 6,
|
||||
"Attributes": [],
|
||||
"Name": "Interact"
|
||||
}
|
||||
],
|
||||
"EntityEventHandlers": []
|
||||
}
|
||||
}
|
||||
}
|
||||
60
RootDesk/MyDesk/MapCamera.codeblock
Normal file
60
RootDesk/MyDesk/MapCamera.codeblock
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "codeblock://mapcamera",
|
||||
"ContentType": "x-mod/codeblock",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"CoreVersion": {
|
||||
"Major": 0,
|
||||
"Minor": 2
|
||||
},
|
||||
"ScriptVersion": {
|
||||
"Major": 1,
|
||||
"Minor": 0
|
||||
},
|
||||
"Description": "",
|
||||
"Id": "MapCamera",
|
||||
"Language": 1,
|
||||
"Name": "MapCamera",
|
||||
"Type": 1,
|
||||
"Source": 0,
|
||||
"Target": null,
|
||||
"Properties": [
|
||||
{
|
||||
"Type": "number",
|
||||
"DefaultValue": "0",
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": "CamTries"
|
||||
}
|
||||
],
|
||||
"Methods": [
|
||||
{
|
||||
"Return": {
|
||||
"Type": "void",
|
||||
"DefaultValue": null,
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": null
|
||||
},
|
||||
"Arguments": [],
|
||||
"Code": "self.CamTries = 0\nlocal eventId = 0\nlocal function apply()\n\tself.CamTries = self.CamTries + 1\n\tlocal cam = nil\n\tlocal lp = _UserService.LocalPlayer\n\tif lp ~= nil then\n\t\tcam = lp.CameraComponent\n\tend\n\tif cam == nil then\n\t\tcam = _CameraService:GetCurrentCameraComponent()\n\tend\n\tif cam ~= nil then\n\t\tcam.ZoomRatio = 90\n\t\tcam.ScreenOffset = Vector2(0.5, 0.655)\n\t\tcam.ConfineCameraArea = true\n\t\tcam.CameraOffset = Vector2(1.5, -0.83)\n\tend\n\tif cam ~= nil then\n\t\t_TimerService:ClearTimer(eventId)\n\telseif self.CamTries > 30 then\n\t\t_TimerService:ClearTimer(eventId)\n\tend\nend\neventId = _TimerService:SetTimerRepeat(apply, 0.1)",
|
||||
"Scope": 2,
|
||||
"ExecSpace": 6,
|
||||
"Attributes": [],
|
||||
"Name": "OnBeginPlay"
|
||||
}
|
||||
],
|
||||
"EntityEventHandlers": []
|
||||
}
|
||||
}
|
||||
}
|
||||
36
RootDesk/MyDesk/MapleTree.codeblock
Normal file
36
RootDesk/MyDesk/MapleTree.codeblock
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "codeblock://4a220aa8-e014-4c7b-8234-fff8c5c66686",
|
||||
"ContentType": "x-mod/codeblock",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"CoreVersion": {
|
||||
"Major": 0,
|
||||
"Minor": 2
|
||||
},
|
||||
"ScriptVersion": {
|
||||
"Major": 1,
|
||||
"Minor": 1
|
||||
},
|
||||
"Description": "",
|
||||
"Id": "4a220aa8-e014-4c7b-8234-fff8c5c66686",
|
||||
"Language": 1,
|
||||
"Name": "MapleTree",
|
||||
"Type": 1,
|
||||
"Source": 0,
|
||||
"Target": null,
|
||||
"Properties": [],
|
||||
"Methods": [],
|
||||
"EntityEventHandlers": []
|
||||
}
|
||||
}
|
||||
}
|
||||
231
RootDesk/MyDesk/Models/Monsters/blue_mushroom.model
Normal file
231
RootDesk/MyDesk/Models/Monsters/blue_mushroom.model
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-blue_mushroom",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "blue_mushroom",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-blue_mushroom",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "1a176a7afb114fe7aef2bc58ef2d945b"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "1a176a7afb114fe7aef2bc58ef2d945b",
|
||||
"move": "8239541953a6457fbe6d35e17f19f0f8",
|
||||
"hit": "7b405108d05741699893a4dc3d715165",
|
||||
"jump": "a7ea0755262242199ae50ab6a3387034",
|
||||
"die": "9e74e807797d442f9c938ca64aa9f4cd"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "blue_mushroom"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
231
RootDesk/MyDesk/Models/Monsters/dile.model
Normal file
231
RootDesk/MyDesk/Models/Monsters/dile.model
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-dile",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "dile",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-dile",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "68070c6f4abe40658899a208ddaf4081"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"move": "426ba2c6fa2d4cdd92bcb0bb37861dcc",
|
||||
"stand": "68070c6f4abe40658899a208ddaf4081",
|
||||
"skill": "4ba2cdc2f11746afa0f542293b0618d5",
|
||||
"hit": "172640e6d4ce444aa1dfbd9bd9523eb1",
|
||||
"die": "5d50d9aa34c745b9b8932c15da919927"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 2.2,
|
||||
"y": 1.51
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": -0.220000029,
|
||||
"y": 0.755
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "dile"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
229
RootDesk/MyDesk/Models/Monsters/green_mushroom.model
Normal file
229
RootDesk/MyDesk/Models/Monsters/green_mushroom.model
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-green_mushroom",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "green_mushroom",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-green_mushroom",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "f86992ba9c41487c8480fcb893fcbda6"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "f86992ba9c41487c8480fcb893fcbda6",
|
||||
"hit": "d305b942b1704c8084548108ff3b7a6b",
|
||||
"die": "5a563e5fd98c4132b61057dc6bb8aaf2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.00999999,
|
||||
"y": 0.26
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "green_mushroom"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
229
RootDesk/MyDesk/Models/Monsters/junior_bugi.model
Normal file
229
RootDesk/MyDesk/Models/Monsters/junior_bugi.model
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-junior_bugi",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "junior_bugi",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-junior_bugi",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "a2204a21d88942b281d2cac6053ffbaa"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "a2204a21d88942b281d2cac6053ffbaa",
|
||||
"hit": "afc08936b8a64b26bc3dd8c03ead1f26",
|
||||
"die": "fc1c6d9ba9bc413ab53b6dbfae3ac45b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "junior_bugi"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
229
RootDesk/MyDesk/Models/Monsters/junior_neki.model
Normal file
229
RootDesk/MyDesk/Models/Monsters/junior_neki.model
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-junior_neki",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "junior_neki",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-junior_neki",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "48c10437ae8344a9b2a1d3f36185728f"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "48c10437ae8344a9b2a1d3f36185728f",
|
||||
"hit": "9044063647854f5e9128efcf80e909be",
|
||||
"die": "f414577d18c94cc387c275df4abdbc3b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "junior_neki"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
229
RootDesk/MyDesk/Models/Monsters/kapa_drake.model
Normal file
229
RootDesk/MyDesk/Models/Monsters/kapa_drake.model
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-kapa_drake",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "kapa_drake",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-kapa_drake",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "4ca39dbfa1c6492283ba8bd352d12b0a"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "4ca39dbfa1c6492283ba8bd352d12b0a",
|
||||
"hit": "7ac78511036e4ebe988b97c35fc275d1",
|
||||
"die": "740f3f2b2e7a4b71bec5eac84e8539f9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "kapa_drake"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
233
RootDesk/MyDesk/Models/Monsters/king_slime.model
Normal file
233
RootDesk/MyDesk/Models/Monsters/king_slime.model
Normal file
@@ -0,0 +1,233 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-king_slime",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "king_slime",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-king_slime",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "dd9de73d580240faab8cad03b587013b"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"move": "873425127b75475b9944dc86bf77f885",
|
||||
"stand": "dd9de73d580240faab8cad03b587013b",
|
||||
"jump": "6a2b983b7a31417ca19c29c3d1d00817",
|
||||
"attack": "a34d1146057443fd8b578dafeb7c2ed1",
|
||||
"skill": "0b0bb78f0ca44526bad6d994bb16f973",
|
||||
"hit": "d2de42d3233b42a58d9799d5e762a19c",
|
||||
"die": "5bd3969c3bcb4df2bd79c2b940ee03dc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 2.19,
|
||||
"y": 1.39
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.335000038,
|
||||
"y": 0.695
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "king_slime"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
231
RootDesk/MyDesk/Models/Monsters/mano.model
Normal file
231
RootDesk/MyDesk/Models/Monsters/mano.model
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-mano",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "mano",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-mano",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "e035bb90c053401b88de2159dfa230eb"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"move": "3dcd0dc63d2d491b9b8d39b3b9d0a214",
|
||||
"stand": "e035bb90c053401b88de2159dfa230eb",
|
||||
"skill": "c05453dd21fd4ed581d193930ab4c331",
|
||||
"hit": "452cb740ddcb4837a46b75d7935e2ffc",
|
||||
"die": "f430051f6fc34f2eb56fe5e62b346eac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 1.05,
|
||||
"y": 0.95
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.004999995,
|
||||
"y": 0.475
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "mano"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
230
RootDesk/MyDesk/Models/Monsters/modified_snail.model
Normal file
230
RootDesk/MyDesk/Models/Monsters/modified_snail.model
Normal file
@@ -0,0 +1,230 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-modified_snail",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "modified_snail",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-modified_snail",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "17b55730c26f4fd6b8fcfa288da388de"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "17b55730c26f4fd6b8fcfa288da388de",
|
||||
"move": "f40108c8b0b84696a67337b801201f7d",
|
||||
"hit": "eac48e84a9fc4580a4018de5cf52ddb3",
|
||||
"die": "51c2f4b59a2c413db26035aa57002fc8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.75,
|
||||
"y": 0.68
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "modified_snail"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
232
RootDesk/MyDesk/Models/Monsters/mushmom.model
Normal file
232
RootDesk/MyDesk/Models/Monsters/mushmom.model
Normal file
@@ -0,0 +1,232 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-mushmom",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "mushmom",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-mushmom",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "23c38ef3acad4a30ad59120bb939b008"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "23c38ef3acad4a30ad59120bb939b008",
|
||||
"move": "24d8a3a75f96406ba690ed42d7250b8f",
|
||||
"hit": "c826e36ee89c48bca6aab856aa773f38",
|
||||
"attack": "4d7465e950144dc59c263aad01b14e14",
|
||||
"jump": "b7ddbda71a294141ba134249fc34c7da",
|
||||
"die": "f50664a4524147399359cb90a6f3e80c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 1.2,
|
||||
"y": 1.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.02,
|
||||
"y": 0.55
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "mushmom"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
229
RootDesk/MyDesk/Models/Monsters/octopus.model
Normal file
229
RootDesk/MyDesk/Models/Monsters/octopus.model
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-octopus",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "octopus",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-octopus",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "d8f014043ce8418f96700c2b6c9ebf6c"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "d8f014043ce8418f96700c2b6c9ebf6c",
|
||||
"hit": "c3cf643b618346c7bfa6574187b396f9",
|
||||
"die": "a88d9b3d60f941e4890dc89a6ccaa8ee"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "octopus"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
231
RootDesk/MyDesk/Models/Monsters/orange_mushroom.model
Normal file
231
RootDesk/MyDesk/Models/Monsters/orange_mushroom.model
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-orange_mushroom",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "orange_mushroom",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-orange_mushroom",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "6d381bea1bcb4504b518a1fbfa0904ac"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"move": "573fe938562a4abf91eebf951f21afd5",
|
||||
"stand": "6d381bea1bcb4504b518a1fbfa0904ac",
|
||||
"jump": "59823e146a034e48b8667ebb6f0724b1",
|
||||
"hit": "642ece38d8d449b29ce4479100e37a54",
|
||||
"die": "3c99d6b9b89b4295a9c2749eb02e28e9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "orange_mushroom"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
231
RootDesk/MyDesk/Models/Monsters/pig.model
Normal file
231
RootDesk/MyDesk/Models/Monsters/pig.model
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-pig",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "pig",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-pig",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "528a8638b12f41b8b5781a05360d2949"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "528a8638b12f41b8b5781a05360d2949",
|
||||
"move": "8baad61512be4b33b2a0879fec7a266e",
|
||||
"hit": "60e42a918a0342478903cc71adba1dc5",
|
||||
"jump": "c9e27ce6f8344aefba169c5ca6571def",
|
||||
"die": "0644beff80a44ec7acc011ea0961df57"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "pig"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
230
RootDesk/MyDesk/Models/Monsters/red_snail.model
Normal file
230
RootDesk/MyDesk/Models/Monsters/red_snail.model
Normal file
@@ -0,0 +1,230 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-red_snail",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "red_snail",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-red_snail",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "17b55730c26f4fd6b8fcfa288da388de"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "17b55730c26f4fd6b8fcfa288da388de",
|
||||
"move": "f40108c8b0b84696a67337b801201f7d",
|
||||
"hit": "eac48e84a9fc4580a4018de5cf52ddb3",
|
||||
"die": "51c2f4b59a2c413db26035aa57002fc8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "red_snail"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
231
RootDesk/MyDesk/Models/Monsters/slime.model
Normal file
231
RootDesk/MyDesk/Models/Monsters/slime.model
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-slime",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "slime",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-slime",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "50faf654ee5d479cb2958edce9feaef0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "50faf654ee5d479cb2958edce9feaef0",
|
||||
"move": "dc932872543f4a02bf41e977ab79e5ad",
|
||||
"hit": "61c27025a8f14c478f30ede1b49758bc",
|
||||
"jump": "8b89d86b1a9c4c4288650614c6f30e67",
|
||||
"die": "31ecb6c7cbc24599881f00cb01599f09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "slime"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
231
RootDesk/MyDesk/Models/Monsters/slime_boss.model
Normal file
231
RootDesk/MyDesk/Models/Monsters/slime_boss.model
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-slime_boss",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "slime_boss",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-slime_boss",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "50faf654ee5d479cb2958edce9feaef0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "50faf654ee5d479cb2958edce9feaef0",
|
||||
"move": "dc932872543f4a02bf41e977ab79e5ad",
|
||||
"hit": "61c27025a8f14c478f30ede1b49758bc",
|
||||
"jump": "8b89d86b1a9c4c4288650614c6f30e67",
|
||||
"die": "31ecb6c7cbc24599881f00cb01599f09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 1.2,
|
||||
"y": 1.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "slime_boss"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
231
RootDesk/MyDesk/Models/Monsters/slime_elite.model
Normal file
231
RootDesk/MyDesk/Models/Monsters/slime_elite.model
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-slime_elite",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "slime_elite",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-slime_elite",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "50faf654ee5d479cb2958edce9feaef0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "50faf654ee5d479cb2958edce9feaef0",
|
||||
"move": "dc932872543f4a02bf41e977ab79e5ad",
|
||||
"hit": "61c27025a8f14c478f30ede1b49758bc",
|
||||
"jump": "8b89d86b1a9c4c4288650614c6f30e67",
|
||||
"die": "31ecb6c7cbc24599881f00cb01599f09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.85,
|
||||
"y": 0.78
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "slime_elite"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
230
RootDesk/MyDesk/Models/Monsters/stump.model
Normal file
230
RootDesk/MyDesk/Models/Monsters/stump.model
Normal file
@@ -0,0 +1,230 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "model://monster-stump",
|
||||
"ContentType": "x-mod/model",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.3.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"Version": 1,
|
||||
"Name": "stump",
|
||||
"BaseModelId": null,
|
||||
"Id": "monster-stump",
|
||||
"Components": [
|
||||
"MOD.Core.TransformComponent",
|
||||
"MOD.Core.StateAnimationComponent",
|
||||
"MOD.Core.SpriteRendererComponent",
|
||||
"MOD.Core.RigidbodyComponent",
|
||||
"MOD.Core.MovementComponent",
|
||||
"MOD.Core.StateComponent",
|
||||
"MOD.Core.HitComponent",
|
||||
"MOD.Core.DamageSkinSpawnerComponent",
|
||||
"script.Monster",
|
||||
"script.MonsterAttack",
|
||||
"MOD.Core.KinematicbodyComponent",
|
||||
"MOD.Core.SideviewbodyComponent",
|
||||
"MOD.Core.DamageSkinSettingComponent",
|
||||
"script.CombatMonster"
|
||||
],
|
||||
"Properties": [
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "speed",
|
||||
"DisplayName": "speed",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "InputSpeed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "jumpForce",
|
||||
"DisplayName": "jumpForce",
|
||||
"ShowInInspector": true,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MovementComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "JumpForce"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "actionSheet",
|
||||
"DisplayName": "actionSheet",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.StateAnimationComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "ActionSheet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Name": "renderguid",
|
||||
"DisplayName": "renderguid",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "SpriteRUID"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.RenderSettingType, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Name": "renderSetting",
|
||||
"DisplayName": "renderSetting",
|
||||
"ShowInInspector": false,
|
||||
"Link": {
|
||||
"Target": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.SpriteRendererComponent, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Property": "RenderSetting"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Values": [
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "OrderInLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 2
|
||||
},
|
||||
{
|
||||
"TargetType": null,
|
||||
"Name": "renderguid",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "null"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "CollisionGroup",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.Physics.CollisionGroup, MOD.Core, Version=26.3.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.Physics.CollisionGroup, MOD.Core",
|
||||
"Id": "8992acd1e8cd45838db6f10a7b41df09"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SpriteRUID",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "ed3908e24d694bb786023fc1ed073489"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.SpriteRendererComponent",
|
||||
"Name": "SortingLayer",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "MapLayer0"
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.StateAnimationComponent",
|
||||
"Name": "ActionSheet",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODSyncDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"stand": "ed3908e24d694bb786023fc1ed073489",
|
||||
"move": "9a4cad470f304753885e06c043156efb",
|
||||
"hit": "4763c9bebc9245998c9c499b6316aa9f",
|
||||
"die": "b168793b92a844a3a3a6f4ce647a14d2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "BoxSize",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.63,
|
||||
"y": 0.58
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.HitComponent",
|
||||
"Name": "ColliderOffset",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
},
|
||||
"Value": {
|
||||
"$type": "MOD.Core.MODVector2, MOD.Core",
|
||||
"x": 0.0449999869,
|
||||
"y": 0.29
|
||||
}
|
||||
},
|
||||
{
|
||||
"TargetType": "MOD.Core.MovementComponent",
|
||||
"Name": "InputSpeed",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": 0
|
||||
},
|
||||
{
|
||||
"TargetType": "script.CombatMonster",
|
||||
"Name": "EnemyId",
|
||||
"ValueType": {
|
||||
"$type": "MODNativeType",
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
|
||||
},
|
||||
"Value": "stump"
|
||||
}
|
||||
],
|
||||
"EventLinks": [],
|
||||
"Children": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@
|
||||
"Name": null
|
||||
},
|
||||
"Arguments": [],
|
||||
"Code": "local monster = self.Entity.Monster\nif not monster then\n\treturn\nend\n\nself.Shape = BoxShape(Vector2.zero, Vector2.one, 0)\n\n-- sprite 사이즈를 가져와 공격 영역으로 사용한다\n_ResourceService:PreloadAsync({self.Entity.SpriteRendererComponent.SpriteRUID}, function()\n\tlocal clip = _ResourceService:LoadAnimationClipAndWait(self.Entity.SpriteRendererComponent.SpriteRUID)\n\tlocal firstFrameSprite = clip.Frames[1].FrameSprite\n\tlocal firstSpriteSizeInPixel = Vector2(firstFrameSprite.Width, firstFrameSprite.Height)\n\tlocal ppu = firstFrameSprite.PixelPerUnit\n\n\tself.SpriteSize = firstSpriteSizeInPixel / ppu\n\tself.PositionOffset = (firstSpriteSizeInPixel / 2 - firstFrameSprite.PivotPixel:ToVector2()) / ppu\n\t\n\t_TimerService:SetTimerRepeat(function() \n\t\tif monster.IsDead == false then\n\t\t\tself:AttackNear()\n\t\tend\n\tend, self.AttackInterval)\nend)",
|
||||
"Code": "local monster = self.Entity.Monster\nif not monster then\n\treturn\nend\n\nself.Shape = BoxShape(Vector2.zero, Vector2.one, 0)\n\n-- sprite 사이즈를 가져와 공격 영역으로 사용한다\n_ResourceService:PreloadAsync({self.Entity.SpriteRendererComponent.SpriteRUID}, function()\n\tif _ResourceService:GetTypeAndWait(self.Entity.SpriteRendererComponent.SpriteRUID) ~= ResourceType.AnimationClip then\n\t\treturn\n\tend\n\tlocal clip = _ResourceService:LoadAnimationClipAndWait(self.Entity.SpriteRendererComponent.SpriteRUID)\n\tif clip == nil then\n\t\treturn\n\tend\n\tlocal firstFrameSprite = clip.Frames[1].FrameSprite\n\tlocal firstSpriteSizeInPixel = Vector2(firstFrameSprite.Width, firstFrameSprite.Height)\n\tlocal ppu = firstFrameSprite.PixelPerUnit\n\n\tself.SpriteSize = firstSpriteSizeInPixel / ppu\n\tself.PositionOffset = (firstSpriteSizeInPixel / 2 - firstFrameSprite.PivotPixel:ToVector2()) / ppu\n\t\n\t_TimerService:SetTimerRepeat(function() \n\t\tif monster.IsDead == false then\n\t\t\tself:AttackNear()\n\t\tend\n\tend, self.AttackInterval)\nend)",
|
||||
"Scope": 2,
|
||||
"ExecSpace": 1,
|
||||
"Attributes": [],
|
||||
|
||||
60
RootDesk/MyDesk/PlayerLock.codeblock
Normal file
60
RootDesk/MyDesk/PlayerLock.codeblock
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "codeblock://playerlock",
|
||||
"ContentType": "x-mod/codeblock",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"CoreVersion": {
|
||||
"Major": 0,
|
||||
"Minor": 2
|
||||
},
|
||||
"ScriptVersion": {
|
||||
"Major": 1,
|
||||
"Minor": 0
|
||||
},
|
||||
"Description": "",
|
||||
"Id": "PlayerLock",
|
||||
"Language": 1,
|
||||
"Name": "PlayerLock",
|
||||
"Type": 1,
|
||||
"Source": 0,
|
||||
"Target": null,
|
||||
"Properties": [
|
||||
{
|
||||
"Type": "number",
|
||||
"DefaultValue": "0",
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": "LockTries"
|
||||
}
|
||||
],
|
||||
"Methods": [
|
||||
{
|
||||
"Return": {
|
||||
"Type": "void",
|
||||
"DefaultValue": null,
|
||||
"SyncDirection": 0,
|
||||
"Attributes": [],
|
||||
"Name": null
|
||||
},
|
||||
"Arguments": [],
|
||||
"Code": "self.LockTries = 0\nlocal eventId = 0\nlocal function apply()\n\tself.LockTries = self.LockTries + 1\n\tlocal pc = nil\n\tlocal lp = _UserService.LocalPlayer\n\tif lp ~= nil then\n\t\tpc = lp.PlayerControllerComponent\n\tend\n\tif pc ~= nil then\n\t\tpc.LookDirectionX = 1\n\t\tpc.FixedLookAt = true\n\t\tpc.Enable = false\n\tend\n\tif lp ~= nil then\n\t\tif lp.RigidbodyComponent ~= nil then lp.RigidbodyComponent.WalkAcceleration = 0 end\n\t\tif lp.MovementComponent ~= nil then lp.MovementComponent.InputSpeed = 0; lp.MovementComponent.JumpForce = 0 end\n\tend\n\tif pc ~= nil then\n\t\t_TimerService:ClearTimer(eventId)\n\telseif self.LockTries > 30 then\n\t\t_TimerService:ClearTimer(eventId)\n\tend\nend\neventId = _TimerService:SetTimerRepeat(apply, 0.1)",
|
||||
"Scope": 2,
|
||||
"ExecSpace": 6,
|
||||
"Attributes": [],
|
||||
"Name": "OnBeginPlay"
|
||||
}
|
||||
],
|
||||
"EntityEventHandlers": []
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
23
RootDesk/MyDesk/Thumnail.sprite
Normal file
23
RootDesk/MyDesk/Thumnail.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://41ad73da083d41b0ae30bf7b86794376",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/41ad73da083d41b0ae30bf7b86794376/639172145413258274",
|
||||
"upload_hash": "CFC620F96E1621FEE5594456FC8A4157BC6EF0D3E7661C5543293200FD364A85",
|
||||
"name": "Thumnail",
|
||||
"resource_guid": "41ad73da083d41b0ae30bf7b86794376",
|
||||
"resource_version": "6a31544d335c959bb11f45eb"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/archmage(fire_poison).sprite
Normal file
23
RootDesk/MyDesk/archmage(fire_poison).sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://2d659478140c4b1c8f37febbb61bdaa0",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/2d659478140c4b1c8f37febbb61bdaa0/639171361295360405",
|
||||
"upload_hash": "13E6D3B629261148095059F7C1D8EDC012C7A60422FC769ECB574A7C5A75759E",
|
||||
"name": "archmage(fire_poison)",
|
||||
"resource_guid": "2d659478140c4b1c8f37febbb61bdaa0",
|
||||
"resource_version": "6a3022013e53f03801a4ac58"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/archmage(thun_cold).sprite
Normal file
23
RootDesk/MyDesk/archmage(thun_cold).sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://ddd0a729328f452b9ff0802ab1f6f579",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/ddd0a729328f452b9ff0802ab1f6f579/639171361295458274",
|
||||
"upload_hash": "7B874B7774FA37E570B16E369112EC467EEA5EC1395A32E4DF01FB6165062E67",
|
||||
"name": "archmage(thun_cold)",
|
||||
"resource_guid": "ddd0a729328f452b9ff0802ab1f6f579",
|
||||
"resource_version": "6a3022012c6a274be88a0819"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/bandit.sprite
Normal file
23
RootDesk/MyDesk/bandit.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://efa920e58d31426486ef974106e7dc8b",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/efa920e58d31426486ef974106e7dc8b/639171361295547945",
|
||||
"upload_hash": "C4B0469A46B70C2356DC8B0F99D36FD9480BFDA5832E251960DD1FF30C201B7F",
|
||||
"name": "bandit",
|
||||
"resource_guid": "efa920e58d31426486ef974106e7dc8b",
|
||||
"resource_version": "6a302201a81bed5f59770e23"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/bandit_legend.sprite
Normal file
23
RootDesk/MyDesk/bandit_legend.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://c357d2daf31a489d95b8fa47e50dd879",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/c357d2daf31a489d95b8fa47e50dd879/639168711224334184",
|
||||
"upload_hash": "A1639991C7A8CB1025C97E6BE93F618088971DC609F03106C50D8B6EA145F6A2",
|
||||
"name": "bandit_legend",
|
||||
"resource_guid": "c357d2daf31a489d95b8fa47e50dd879",
|
||||
"resource_version": "6a2c16d2cc7e89479f128ffb"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/bandit_normal.sprite
Normal file
23
RootDesk/MyDesk/bandit_normal.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://9487b06867bc46269ed1d855420f457f",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/9487b06867bc46269ed1d855420f457f/639168711224307886",
|
||||
"upload_hash": "FD9F2140D16EFC7A77F0B09CA230702CA6CA25E3178AAF6ACD63EF07D5C2C83E",
|
||||
"name": "bandit_normal",
|
||||
"resource_guid": "9487b06867bc46269ed1d855420f457f",
|
||||
"resource_version": "6a2c16d23d5de2eb0c7d16a2"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/bandit_unique.sprite
Normal file
23
RootDesk/MyDesk/bandit_unique.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://b3081fb2fb1445fa90b12b01481a78ef",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/b3081fb2fb1445fa90b12b01481a78ef/639168711224396185",
|
||||
"upload_hash": "1F5218270148F873D060223A617DFC184AEEE61344D26C85705E40EECC086D5E",
|
||||
"name": "bandit_unique",
|
||||
"resource_guid": "b3081fb2fb1445fa90b12b01481a78ef",
|
||||
"resource_version": "6a2c16d21a7908d59b5dc059"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/bowmaster.sprite
Normal file
23
RootDesk/MyDesk/bowmaster.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://93e615d645e948f5a76656bfdd9dce15",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/93e615d645e948f5a76656bfdd9dce15/639171361295501823",
|
||||
"upload_hash": "A5A1263A9E1F5D58B0F985AC58DE7DDE1EA13E0CC5CEE56FC34C3FD792A8D39E",
|
||||
"name": "bowmaster",
|
||||
"resource_guid": "93e615d645e948f5a76656bfdd9dce15",
|
||||
"resource_version": "6a302201a0766b148f66ec2c"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/cleric.sprite
Normal file
23
RootDesk/MyDesk/cleric.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://3c752ffcd4984dcb9f04baab06544f02",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/3c752ffcd4984dcb9f04baab06544f02/639171361295496567",
|
||||
"upload_hash": "ED1ABC3DBCB04FCBD365BAD0408C8CA1D2458FB337DBDEB4A7EC5DF1BAC32496",
|
||||
"name": "cleric",
|
||||
"resource_guid": "3c752ffcd4984dcb9f04baab06544f02",
|
||||
"resource_version": "6a302201d03493c632770e41"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/darkknight.sprite
Normal file
23
RootDesk/MyDesk/darkknight.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://e207e6839a4a4bd0aab681bd296a609a",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/e207e6839a4a4bd0aab681bd296a609a/639171361295401732",
|
||||
"upload_hash": "D5931943781C46611D43595594234BFB133F8BCCAA920C13BCA7E2F8AC9C09D0",
|
||||
"name": "darkknight",
|
||||
"resource_guid": "e207e6839a4a4bd0aab681bd296a609a",
|
||||
"resource_version": "6a302201644d4c175c75d435"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/hero.sprite
Normal file
23
RootDesk/MyDesk/hero.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://0efbf37bb7414aea82b257781068372b",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/0efbf37bb7414aea82b257781068372b/639171361295431877",
|
||||
"upload_hash": "DE22318162E1F93E7B90A0B6A59BE31FC76DEEC122914979915D6D575A4D99B5",
|
||||
"name": "hero",
|
||||
"resource_guid": "0efbf37bb7414aea82b257781068372b",
|
||||
"resource_version": "6a302201c377d9630d82c463"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/hunter.sprite
Normal file
23
RootDesk/MyDesk/hunter.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://fd460e6ee38a40e3b6b05580d00773b6",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/fd460e6ee38a40e3b6b05580d00773b6/639171361295408991",
|
||||
"upload_hash": "B832DE85217EA6544BA4477F0DBA5D2148E4E392A170944336E0DA74E8D41961",
|
||||
"name": "hunter",
|
||||
"resource_guid": "fd460e6ee38a40e3b6b05580d00773b6",
|
||||
"resource_version": "6a3022013d5de2eb0c7d2a51"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/mage.sprite
Normal file
23
RootDesk/MyDesk/mage.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://3b9ea1f066a744bb859df47fef817277",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/3b9ea1f066a744bb859df47fef817277/639171361295599801",
|
||||
"upload_hash": "770C9D83241F8CE2C0EA8B742887D8351A580E2DE15A6380380653855A974F14",
|
||||
"name": "mage",
|
||||
"resource_guid": "3b9ea1f066a744bb859df47fef817277",
|
||||
"resource_version": "6a302201cc7e89479f12a1ac"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/mage_legend.sprite
Normal file
23
RootDesk/MyDesk/mage_legend.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://cff71f2e472041ce80c6fbd296f42e2d",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/cff71f2e472041ce80c6fbd296f42e2d/639168711224422293",
|
||||
"upload_hash": "040CA63C5D3D52E1661F3A008D229A182B1A7C09D919BB74E23D1305B1AA56A7",
|
||||
"name": "mage_legend",
|
||||
"resource_guid": "cff71f2e472041ce80c6fbd296f42e2d",
|
||||
"resource_version": "6a2c16d2a0766b148f66d799"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/mage_normal.sprite
Normal file
23
RootDesk/MyDesk/mage_normal.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://d788d09f6f50467ebc67f01dec45f9e2",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/d788d09f6f50467ebc67f01dec45f9e2/639168711224258598",
|
||||
"upload_hash": "5D91E6E333564F15A76554AE07402DC0ED39ABC02439F65C2CCB818C71FB6994",
|
||||
"name": "mage_normal",
|
||||
"resource_guid": "d788d09f6f50467ebc67f01dec45f9e2",
|
||||
"resource_version": "6a2c16d2e75b0d4ccdfcee8b"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/mage_unique.sprite
Normal file
23
RootDesk/MyDesk/mage_unique.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://f5def2e8022b4e59a17d3c16414034fe",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/f5def2e8022b4e59a17d3c16414034fe/639168711224271729",
|
||||
"upload_hash": "B07075BE5F13B1D7BFB4AE36F4C47D97A10A3CC7EF763F02DD2A11C2AFC61E67",
|
||||
"name": "mage_unique",
|
||||
"resource_guid": "f5def2e8022b4e59a17d3c16414034fe",
|
||||
"resource_version": "6a2c16d2e75b0d4ccdfcee8a"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/nightlord.sprite
Normal file
23
RootDesk/MyDesk/nightlord.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://994c64290e6d4248bd60aba03a595f72",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/994c64290e6d4248bd60aba03a595f72/639171361295422460",
|
||||
"upload_hash": "A0B7146F6D8E9D72CEACDB7E21A2CD6EEBD4135554D3965B4E1C06BC98FC1211",
|
||||
"name": "nightlord",
|
||||
"resource_guid": "994c64290e6d4248bd60aba03a595f72",
|
||||
"resource_version": "6a30220139613d284615a1e1"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/palladin.sprite
Normal file
23
RootDesk/MyDesk/palladin.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://415d423954764b659574fe829f9aff52",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/415d423954764b659574fe829f9aff52/639171361329450040",
|
||||
"upload_hash": "EB94BA457C18E04D87964201DD50042695A3C7F93651CBC8ED9509BDDE07F331",
|
||||
"name": "palladin",
|
||||
"resource_guid": "415d423954764b659574fe829f9aff52",
|
||||
"resource_version": "6a302205a0766b148f66ec2d"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/pirate.sprite
Normal file
23
RootDesk/MyDesk/pirate.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://94d6417c55da48e9861964c405991219",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/94d6417c55da48e9861964c405991219/639171361329410075",
|
||||
"upload_hash": "EBEC4B43CDBB1759C0BC92C051252A7DF84E6B89C9C56ECBFEFF543A0E260889",
|
||||
"name": "pirate",
|
||||
"resource_guid": "94d6417c55da48e9861964c405991219",
|
||||
"resource_version": "6a3022052c6a274be88a081a"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/restBgImage.sprite
Normal file
23
RootDesk/MyDesk/restBgImage.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://477679b832b44e099a30e4905078dbcb",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/477679b832b44e099a30e4905078dbcb/639172226341792721",
|
||||
"upload_hash": "3E30B07C24C4BC4E373CDEA653035146D2F50ACC6484F6E9DA34E6179BB38F15",
|
||||
"name": "restBgImage",
|
||||
"resource_guid": "477679b832b44e099a30e4905078dbcb",
|
||||
"resource_version": "6a3173ea002bbe95706406b6"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/shadower.sprite
Normal file
23
RootDesk/MyDesk/shadower.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://06c1060586e3457f897f2c596eb5cd71",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/06c1060586e3457f897f2c596eb5cd71/639171361329387468",
|
||||
"upload_hash": "42EE2E63508762E86391486107A23322E11038070F48851D03FE91255CF41596",
|
||||
"name": "shadower",
|
||||
"resource_guid": "06c1060586e3457f897f2c596eb5cd71",
|
||||
"resource_version": "6a302205a81bed5f59770e24"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/shopBgImage.sprite
Normal file
23
RootDesk/MyDesk/shopBgImage.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://28f3b10ac0334fbfbf29677bf963c57a",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/28f3b10ac0334fbfbf29677bf963c57a/639172222414073214",
|
||||
"upload_hash": "01BE0B58F480BA86DA1D18BFE25C01E1B27219A14FE2DCD73456A7A48553CF15",
|
||||
"name": "shopBgImage",
|
||||
"resource_guid": "28f3b10ac0334fbfbf29677bf963c57a",
|
||||
"resource_version": "6a3172612c6a274be88a130e"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/singung.sprite
Normal file
23
RootDesk/MyDesk/singung.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://b2e099f2e5334705af122e3f88840ba7",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/b2e099f2e5334705af122e3f88840ba7/639171361329408374",
|
||||
"upload_hash": "2AB66279D07E64A17CD2AD05BB03F732632805B0076278EC94F51C0227341CC5",
|
||||
"name": "singung",
|
||||
"resource_guid": "b2e099f2e5334705af122e3f88840ba7",
|
||||
"resource_version": "6a302204c377d9630d82c464"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/treasureBgImage.sprite
Normal file
23
RootDesk/MyDesk/treasureBgImage.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://dd6193fd37da4b12bcdbcdcf2fbe8e40",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/dd6193fd37da4b12bcdbcdcf2fbe8e40/639172228832890845",
|
||||
"upload_hash": "3EDD046B291806637ADD12A77BF94CF00BDD9F4F9912C132B14323D9DE5F297C",
|
||||
"name": "treasureBgImage",
|
||||
"resource_guid": "dd6193fd37da4b12bcdbcdcf2fbe8e40",
|
||||
"resource_version": "6a3174e32a2802c06419f288"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/warior_legend.sprite
Normal file
23
RootDesk/MyDesk/warior_legend.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://6d741a60c60743cb98ee740a1e2dbfed",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/6d741a60c60743cb98ee740a1e2dbfed/639168711258121433",
|
||||
"upload_hash": "80E2D8FFC8E56ECE4694BED5A387413F49633841DD37B7AA9FA9AC713962602C",
|
||||
"name": "warior_legend",
|
||||
"resource_guid": "6d741a60c60743cb98ee740a1e2dbfed",
|
||||
"resource_version": "6a2c16d59c3c6c308bfd4bf8"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/warior_normal.sprite
Normal file
23
RootDesk/MyDesk/warior_normal.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://4bb57ef88ef449fdaf958f6cf37fe44b",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/4bb57ef88ef449fdaf958f6cf37fe44b/639168711258172386",
|
||||
"upload_hash": "2832F3B6C4C9530DE69DF061E590FD314D8646BE6BDB65931AFBE68D38DBB0ED",
|
||||
"name": "warior_normal",
|
||||
"resource_guid": "4bb57ef88ef449fdaf958f6cf37fe44b",
|
||||
"resource_version": "6a2c16d53d5de2eb0c7d16a3"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/warior_unique.sprite
Normal file
23
RootDesk/MyDesk/warior_unique.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://4f71c124c8bc4e13b5e9fad392995f68",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/4f71c124c8bc4e13b5e9fad392995f68/639168711257524633",
|
||||
"upload_hash": "F27B2D713455FB18C10E924D381C4582E5E039D5DCCA9CECD2FB0D8E9A4C8135",
|
||||
"name": "warior_unique",
|
||||
"resource_guid": "4f71c124c8bc4e13b5e9fad392995f68",
|
||||
"resource_version": "6a2c16d5a43134e1b8a34b65"
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RootDesk/MyDesk/warrior.sprite
Normal file
23
RootDesk/MyDesk/warrior.sprite
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Id": "",
|
||||
"GameId": "",
|
||||
"EntryKey": "sprite://28c88fdc5ab44f34a8b3fc1e19d4ce78",
|
||||
"ContentType": "x-mod/sprite",
|
||||
"Content": "",
|
||||
"Usage": 0,
|
||||
"UsePublish": 1,
|
||||
"UseService": 0,
|
||||
"CoreVersion": "26.5.0.0",
|
||||
"StudioVersion": "0.1.0.0",
|
||||
"DynamicLoading": 0,
|
||||
"ContentProto": {
|
||||
"Use": "Json",
|
||||
"Json": {
|
||||
"upload_keyname": "30/54/30542a379cb74d2d807104635740a8ea/sprite/28c88fdc5ab44f34a8b3fc1e19d4ce78/639171361330139251",
|
||||
"upload_hash": "2929F452FBB26215631886FFB430EE6035D55EB42B1770E880C1B0A34D97BDA0",
|
||||
"name": "warrior",
|
||||
"resource_guid": "28c88fdc5ab44f34a8b3fc1e19d4ce78",
|
||||
"resource_version": "6a30220539613d284615a1e2"
|
||||
}
|
||||
}
|
||||
}
|
||||
7
cards_to_excel.bat
Normal file
7
cards_to_excel.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
@echo off
|
||||
setlocal
|
||||
chcp 65001 >nul
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0tools\cards\cards_excel.ps1" export
|
||||
echo.
|
||||
echo Press any key to close this window.
|
||||
pause >nul
|
||||
8
data/camera.json
Normal file
8
data/camera.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"zoomRatio": 90,
|
||||
"screenOffsetX": 0.5,
|
||||
"screenOffsetY": 0.655,
|
||||
"confineCameraArea": true,
|
||||
"cameraOffsetX": 1.5,
|
||||
"cameraOffsetY": -0.83
|
||||
}
|
||||
43
data/cardframes.json
Normal file
43
data/cardframes.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"frames": {
|
||||
"warrior": {
|
||||
"normal": "4bb57ef88ef449fdaf958f6cf37fe44b",
|
||||
"unique": "4f71c124c8bc4e13b5e9fad392995f68",
|
||||
"legend": "6d741a60c60743cb98ee740a1e2dbfed"
|
||||
},
|
||||
"magician": {
|
||||
"normal": "d788d09f6f50467ebc67f01dec45f9e2",
|
||||
"unique": "f5def2e8022b4e59a17d3c16414034fe",
|
||||
"legend": "cff71f2e472041ce80c6fbd296f42e2d"
|
||||
},
|
||||
"rogue": {
|
||||
"normal": "9487b06867bc46269ed1d855420f457f",
|
||||
"unique": "b3081fb2fb1445fa90b12b01481a78ef",
|
||||
"legend": "c357d2daf31a489d95b8fa47e50dd879"
|
||||
}
|
||||
},
|
||||
"classToFrame": {
|
||||
"warrior": "warrior",
|
||||
"fighter": "warrior",
|
||||
"crusader": "warrior",
|
||||
"page": "warrior",
|
||||
"knight": "warrior",
|
||||
"spearman": "warrior",
|
||||
"magician": "magician",
|
||||
"firepoison": "magician",
|
||||
"icelightning": "magician",
|
||||
"cleric": "magician",
|
||||
"curse": "rogue",
|
||||
"shiv": "rogue",
|
||||
"rogue": "rogue",
|
||||
"assassin": "rogue",
|
||||
"hermit": "rogue",
|
||||
"thief": "rogue",
|
||||
"thiefmaster": "rogue"
|
||||
},
|
||||
"rewardWeights": {
|
||||
"normal": 70,
|
||||
"unique": 25,
|
||||
"legend": 5
|
||||
}
|
||||
}
|
||||
3039
data/cards.json
3039
data/cards.json
File diff suppressed because it is too large
Load Diff
BIN
data/cards.xlsx
Normal file
BIN
data/cards.xlsx
Normal file
Binary file not shown.
7
data/characters.json
Normal file
7
data/characters.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"portraits": {
|
||||
"warrior": "28c88fdc5ab44f34a8b3fc1e19d4ce78",
|
||||
"magician": "3b9ea1f066a744bb859df47fef817277",
|
||||
"rogue": "efa920e58d31426486ef974106e7dc8b"
|
||||
}
|
||||
}
|
||||
7
data/encounters.json
Normal file
7
data/encounters.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"map01": { "combat": ["junior_bugi", "kapa_drake", "junior_neki", "octopus", "green_mushroom", "orange_mushroom"], "elite": ["dile", "mano"], "boss": ["king_slime"] },
|
||||
"map02": { "combat": ["pig", "green_mushroom", "blue_mushroom", "orange_mushroom", "slime"], "elite": ["mushmom"], "boss": ["slime_boss"] },
|
||||
"map03": { "combat": ["octopus", "junior_neki", "junior_bugi", "slime"], "elite": ["slime_elite"], "boss": ["king_slime"] },
|
||||
"map04": { "combat": ["kapa_drake", "junior_neki", "junior_bugi", "stump"], "elite": ["dile"], "boss": ["mushmom"] },
|
||||
"map05": { "combat": ["kapa_drake", "octopus", "junior_bugi", "junior_neki"], "elite": ["dile", "slime_elite"], "boss": ["king_slime"] }
|
||||
}
|
||||
@@ -7,7 +7,8 @@
|
||||
{ "kind": "Attack", "value": 10 },
|
||||
{ "kind": "Attack", "value": 6 },
|
||||
{ "kind": "Defend", "value": 8 }
|
||||
]
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "50faf654ee5d479cb2958edce9feaef0", "move": "dc932872543f4a02bf41e977ab79e5ad", "hit": "61c27025a8f14c478f30ede1b49758bc", "jump": "8b89d86b1a9c4c4288650614c6f30e67", "die": "31ecb6c7cbc24599881f00cb01599f09" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"slime_elite": {
|
||||
"name": "정예 슬라임",
|
||||
@@ -15,8 +16,10 @@
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 14 },
|
||||
{ "kind": "Attack", "value": 8 },
|
||||
{ "kind": "Defend", "value": 10 }
|
||||
]
|
||||
{ "kind": "Defend", "value": 10 },
|
||||
{ "kind": "Debuff", "effect": "weak", "value": 1 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "50faf654ee5d479cb2958edce9feaef0", "move": "dc932872543f4a02bf41e977ab79e5ad", "hit": "61c27025a8f14c478f30ede1b49758bc", "jump": "8b89d86b1a9c4c4288650614c6f30e67", "die": "31ecb6c7cbc24599881f00cb01599f09" }, "box": { "x": 0.85, "y": 0.78 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"slime_boss": {
|
||||
"name": "슬라임 킹",
|
||||
@@ -24,10 +27,177 @@
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 18 },
|
||||
{ "kind": "Defend", "value": 12 },
|
||||
{ "kind": "Debuff", "effect": "vuln", "value": 2 },
|
||||
{ "kind": "Attack", "value": 10 },
|
||||
{ "kind": "Attack", "value": 22 }
|
||||
]
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "50faf654ee5d479cb2958edce9feaef0", "move": "dc932872543f4a02bf41e977ab79e5ad", "hit": "61c27025a8f14c478f30ede1b49758bc", "jump": "8b89d86b1a9c4c4288650614c6f30e67", "die": "31ecb6c7cbc24599881f00cb01599f09" }, "box": { "x": 1.2, "y": 1.1 }, "off": { "x": 0.0449999869, "y": 0.4 } }
|
||||
},
|
||||
"orange_mushroom": {
|
||||
"name": "주황버섯",
|
||||
"maxHp": 16,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 5 },
|
||||
{ "kind": "Attack", "value": 5 },
|
||||
{ "kind": "Defend", "value": 4 },
|
||||
{ "kind": "Attack", "value": 8 }
|
||||
],
|
||||
"appearance": { "sheet": { "move": "573fe938562a4abf91eebf951f21afd5", "stand": "6d381bea1bcb4504b518a1fbfa0904ac", "jump": "59823e146a034e48b8667ebb6f0724b1", "hit": "642ece38d8d449b29ce4479100e37a54", "die": "3c99d6b9b89b4295a9c2749eb02e28e9" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"blue_mushroom": {
|
||||
"name": "파란버섯",
|
||||
"maxHp": 22,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 4 },
|
||||
{ "kind": "Attack", "value": 4 },
|
||||
{ "kind": "Attack", "value": 10 },
|
||||
{ "kind": "AddCard", "card": "Wound", "count": 1 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "1a176a7afb114fe7aef2bc58ef2d945b", "move": "8239541953a6457fbe6d35e17f19f0f8", "hit": "7b405108d05741699893a4dc3d715165", "jump": "a7ea0755262242199ae50ab6a3387034", "die": "9e74e807797d442f9c938ca64aa9f4cd" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"pig": {
|
||||
"name": "돼지",
|
||||
"maxHp": 18,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 6 },
|
||||
{ "kind": "Attack", "value": 6 },
|
||||
{ "kind": "Defend", "value": 5 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "528a8638b12f41b8b5781a05360d2949", "move": "8baad61512be4b33b2a0879fec7a266e", "hit": "60e42a918a0342478903cc71adba1dc5", "jump": "c9e27ce6f8344aefba169c5ca6571def", "die": "0644beff80a44ec7acc011ea0961df57" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"green_mushroom": {
|
||||
"name": "초록버섯",
|
||||
"maxHp": 20,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 7 },
|
||||
{ "kind": "Defend", "value": 3 },
|
||||
{ "kind": "Attack", "value": 9 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "f86992ba9c41487c8480fcb893fcbda6", "hit": "d305b942b1704c8084548108ff3b7a6b", "die": "5a563e5fd98c4132b61057dc6bb8aaf2" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.00999999, "y": 0.26 } }
|
||||
},
|
||||
"red_snail": {
|
||||
"name": "빨간 달팽이",
|
||||
"maxHp": 14,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 5 },
|
||||
{ "kind": "Defend", "value": 6 },
|
||||
{ "kind": "Attack", "value": 7 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "17b55730c26f4fd6b8fcfa288da388de", "move": "f40108c8b0b84696a67337b801201f7d", "hit": "eac48e84a9fc4580a4018de5cf52ddb3", "die": "51c2f4b59a2c413db26035aa57002fc8" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"stump": {
|
||||
"name": "나무토막",
|
||||
"maxHp": 19,
|
||||
"intents": [
|
||||
{ "kind": "Defend", "value": 5 },
|
||||
{ "kind": "Attack", "value": 8 },
|
||||
{ "kind": "Attack", "value": 6 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "ed3908e24d694bb786023fc1ed073489", "move": "9a4cad470f304753885e06c043156efb", "hit": "4763c9bebc9245998c9c499b6316aa9f", "die": "b168793b92a844a3a3a6f4ce647a14d2" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"mushmom": {
|
||||
"name": "머쉬맘",
|
||||
"maxHp": 75,
|
||||
"intents": [
|
||||
{ "kind": "Defend", "value": 10 },
|
||||
{ "kind": "Debuff", "effect": "weak", "value": 2 },
|
||||
{ "kind": "Attack", "value": 16 },
|
||||
{ "kind": "Attack", "value": 9 },
|
||||
{ "kind": "Defend", "value": 6 },
|
||||
{ "kind": "AddCard", "card": "Burn", "count": 1 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "23c38ef3acad4a30ad59120bb939b008", "move": "24d8a3a75f96406ba690ed42d7250b8f", "hit": "c826e36ee89c48bca6aab856aa773f38", "attack": "4d7465e950144dc59c263aad01b14e14", "jump": "b7ddbda71a294141ba134249fc34c7da", "die": "f50664a4524147399359cb90a6f3e80c" }, "box": { "x": 1.2, "y": 1.1 }, "off": { "x": 0.02, "y": 0.55 } }
|
||||
},
|
||||
"modified_snail": {
|
||||
"name": "변형된 달팽이",
|
||||
"maxHp": 60,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 12 },
|
||||
{ "kind": "Defend", "value": 8 },
|
||||
{ "kind": "Attack", "value": 7 },
|
||||
{ "kind": "Attack", "value": 14 },
|
||||
{ "kind": "Debuff", "effect": "weak", "value": 1 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "17b55730c26f4fd6b8fcfa288da388de", "move": "f40108c8b0b84696a67337b801201f7d", "hit": "eac48e84a9fc4580a4018de5cf52ddb3", "die": "51c2f4b59a2c413db26035aa57002fc8" }, "box": { "x": 0.75, "y": 0.68 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"king_slime": {
|
||||
"name": "킹 슬라임",
|
||||
"maxHp": 130,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 18 },
|
||||
{ "kind": "Defend", "value": 14 },
|
||||
{ "kind": "Debuff", "effect": "vuln", "value": 2 },
|
||||
{ "kind": "Attack", "value": 12 },
|
||||
{ "kind": "Attack", "value": 24 }
|
||||
],
|
||||
"appearance": { "sheet": { "move": "873425127b75475b9944dc86bf77f885", "stand": "dd9de73d580240faab8cad03b587013b", "jump": "6a2b983b7a31417ca19c29c3d1d00817", "attack": "a34d1146057443fd8b578dafeb7c2ed1", "skill": "0b0bb78f0ca44526bad6d994bb16f973", "hit": "d2de42d3233b42a58d9799d5e762a19c", "die": "5bd3969c3bcb4df2bd79c2b940ee03dc" }, "box": { "x": 2.19, "y": 1.39 }, "off": { "x": 0.335000038, "y": 0.695 } }
|
||||
},
|
||||
"octopus": {
|
||||
"name": "문어",
|
||||
"maxHp": 15,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 5 },
|
||||
{ "kind": "Attack", "value": 6 },
|
||||
{ "kind": "Defend", "value": 4 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "d8f014043ce8418f96700c2b6c9ebf6c", "hit": "c3cf643b618346c7bfa6574187b396f9", "die": "a88d9b3d60f941e4890dc89a6ccaa8ee" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"kapa_drake": {
|
||||
"name": "카파 드레이크",
|
||||
"maxHp": 24,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 9 },
|
||||
{ "kind": "Attack", "value": 6 },
|
||||
{ "kind": "Defend", "value": 6 },
|
||||
{ "kind": "Attack", "value": 11 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "4ca39dbfa1c6492283ba8bd352d12b0a", "hit": "7ac78511036e4ebe988b97c35fc275d1", "die": "740f3f2b2e7a4b71bec5eac84e8539f9" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"junior_neki": {
|
||||
"name": "주니어 네키",
|
||||
"maxHp": 18,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 6 },
|
||||
{ "kind": "Attack", "value": 8 },
|
||||
{ "kind": "Debuff", "effect": "weak", "value": 1 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "48c10437ae8344a9b2a1d3f36185728f", "hit": "9044063647854f5e9128efcf80e909be", "die": "f414577d18c94cc387c275df4abdbc3b" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"junior_bugi": {
|
||||
"name": "주니어 부기",
|
||||
"maxHp": 20,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 7 },
|
||||
{ "kind": "Defend", "value": 5 },
|
||||
{ "kind": "Attack", "value": 9 }
|
||||
],
|
||||
"appearance": { "sheet": { "stand": "a2204a21d88942b281d2cac6053ffbaa", "hit": "afc08936b8a64b26bc3dd8c03ead1f26", "die": "fc1c6d9ba9bc413ab53b6dbfae3ac45b" }, "box": { "x": 0.63, "y": 0.58 }, "off": { "x": 0.0449999869, "y": 0.29 } }
|
||||
},
|
||||
"dile": {
|
||||
"name": "다일",
|
||||
"maxHp": 65,
|
||||
"intents": [
|
||||
{ "kind": "Attack", "value": 13 },
|
||||
{ "kind": "Defend", "value": 9 },
|
||||
{ "kind": "Attack", "value": 8 },
|
||||
{ "kind": "Attack", "value": 16 },
|
||||
{ "kind": "Debuff", "effect": "weak", "value": 1 }
|
||||
],
|
||||
"appearance": { "sheet": { "move": "426ba2c6fa2d4cdd92bcb0bb37861dcc", "stand": "68070c6f4abe40658899a208ddaf4081", "skill": "4ba2cdc2f11746afa0f542293b0618d5", "hit": "172640e6d4ce444aa1dfbd9bd9523eb1", "die": "5d50d9aa34c745b9b8932c15da919927" }, "box": { "x": 2.2, "y": 1.51 }, "off": { "x": -0.220000029, "y": 0.755 } }
|
||||
},
|
||||
"mano": {
|
||||
"name": "마노",
|
||||
"maxHp": 80,
|
||||
"intents": [
|
||||
{ "kind": "Defend", "value": 12 },
|
||||
{ "kind": "Attack", "value": 14 },
|
||||
{ "kind": "Debuff", "effect": "vuln", "value": 1 },
|
||||
{ "kind": "Attack", "value": 10 },
|
||||
{ "kind": "AddCard", "card": "Wound", "count": 1 }
|
||||
],
|
||||
"appearance": { "sheet": { "move": "3dcd0dc63d2d491b9b8d39b3b9d0a214", "stand": "e035bb90c053401b88de2159dfa230eb", "skill": "c05453dd21fd4ed581d193930ab4c331", "hit": "452cb740ddcb4837a46b75d7935e2ffc", "die": "f430051f6fc34f2eb56fe5e62b346eac" }, "box": { "x": 1.05, "y": 0.95 }, "off": { "x": 0.004999995, "y": 0.475 } }
|
||||
}
|
||||
},
|
||||
"activeEnemy": "slime"
|
||||
"activeEnemy": "slime",
|
||||
"simEncounter": ["orange_mushroom", "orange_mushroom", "blue_mushroom"]
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"start": ["A", "B"],
|
||||
"nodes": {
|
||||
"A": { "type": "combat", "enemy": "slime", "row": 1, "col": -1, "next": ["C", "D"] },
|
||||
"B": { "type": "combat", "enemy": "slime", "row": 1, "col": 1, "next": ["C", "D"] },
|
||||
"C": { "type": "rest", "row": 2, "col": -1, "next": ["E", "F"] },
|
||||
"D": { "type": "shop", "row": 2, "col": 1, "next": ["E", "F"] },
|
||||
"E": { "type": "elite", "enemy": "slime_elite", "row": 3, "col": -1, "next": ["BOSS"] },
|
||||
"F": { "type": "combat", "enemy": "slime", "row": 3, "col": 1, "next": ["BOSS"] },
|
||||
"BOSS": { "type": "boss", "enemy": "slime_boss", "row": 4, "col": 0, "next": [] }
|
||||
}
|
||||
}
|
||||
11
data/nodeicons.json
Normal file
11
data/nodeicons.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"icons": {
|
||||
"combat": "f98db6823e894a4f90308d61f75894ac",
|
||||
"elite": "793ed8a757534b89a82f460747d2df24",
|
||||
"boss": "423056cdbbc04f4da131b9721c404d96",
|
||||
"shop": "da37e1fac55d455b9ade08569f09f798",
|
||||
"rest": "b86c1b0568bd45f3ae4a4b97e1b4a594",
|
||||
"treasure": "f8a6d58e20f54e2ca899485055df1ce4"
|
||||
},
|
||||
"background": "ef89906dd9844fcbaafc0b2313812eca"
|
||||
}
|
||||
14
data/potions.json
Normal file
14
data/potions.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"potions": {
|
||||
"redPotion": { "name": "빨간 포션", "desc": "HP 20 회복", "effect": "heal", "value": 20, "icon": "393e2a0d8da544899eaa8b22c97f832b" },
|
||||
"firebomb": { "name": "화염병", "desc": "적에게 피해 20", "effect": "damage", "value": 20, "icon": "7ddb464c2574456289a4eb72ce86f193" },
|
||||
"warriorElixir": { "name": "전사의 물약", "desc": "힘 +2", "effect": "strength", "value": 2, "icon": "7cfbd410581e4073815daaf5f3e6c72f" },
|
||||
"guardPotion": { "name": "수호의 물약", "desc": "방어도 +12", "effect": "block", "value": 12, "icon": "8f8402dfa0f746e18bf606ed74302c0a" },
|
||||
"manaElixir": { "name": "마나 엘릭서", "desc": "에너지 +2", "effect": "energy", "value": 2, "icon": "ec2778c366f6477ab0f8e7f06bcd73f4" },
|
||||
"cursedVial": { "name": "저주의 병", "desc": "적에게 약화 3", "effect": "weak", "value": 3, "icon": "a9a2763fdb6849dcba3028c737487680" }
|
||||
},
|
||||
"dropChance": 0.4,
|
||||
"baseSlots": 3,
|
||||
"beltSlots": 5,
|
||||
"shopPrice": 20
|
||||
}
|
||||
@@ -1,10 +1,30 @@
|
||||
{
|
||||
"relics": {
|
||||
"ironHeart": { "name": "강철 심장", "desc": "전투 시작 시 방어도 +6", "hook": "combatStart", "effect": "block", "value": 6 },
|
||||
"energyCore": { "name": "에너지 코어", "desc": "턴 시작 시 에너지 +1", "hook": "turnStart", "effect": "energy", "value": 1 },
|
||||
"vampire": { "name": "흡혈 송곳니", "desc": "공격 카드 사용 시 HP +1", "hook": "cardPlayed", "effect": "healOnAttack", "value": 1 },
|
||||
"goldIdol": { "name": "황금 우상", "desc": "전투 승리 시 골드 +10", "hook": "combatReward", "effect": "gold", "value": 10 }
|
||||
"ironHeart": { "name": "강철 심장", "desc": "전투 시작 시 방어도 +6", "hook": "combatStart", "effect": "block", "value": 6, "icon": "e555b3a62f3c49dbb2c53784e6bd481f" },
|
||||
"energyCore": { "name": "에너지 코어", "desc": "턴 시작 시 에너지 +1", "hook": "turnStart", "effect": "energy", "value": 1, "icon": "a41014f28b47434ab9f49ef104523862" },
|
||||
"vampire": { "name": "흡혈 송곳니", "desc": "공격 카드 사용 시 HP +1", "hook": "cardPlayed", "effect": "healOnAttack", "value": 1, "icon": "ed64cde7e6c44b9e99502847e54f04e9" },
|
||||
"goldIdol": { "name": "황금 우상", "desc": "전투 승리 시 메소 +10", "hook": "combatReward", "effect": "gold", "value": 10, "icon": "03bb05c92b8f45edb0f3dad2e118fd5a" },
|
||||
"potionBelt": { "name": "장인의 벨트", "desc": "물약 슬롯이 5칸으로 늘어난다", "hook": "passive", "effect": "potionSlots", "value": 5, "icon": "36725b4566ac40d4902e2ab2113c2096" },
|
||||
"burningBlood": { "name": "자쿰의 투구", "desc": "전투 승리 시 HP 6 회복", "hook": "combatEnd", "effect": "healOnWin", "value": 6, "icon": "07f994825ce34131b419d43e890c878d" },
|
||||
"vajra": { "name": "미스릴 해머", "desc": "전투 시작 시 힘 +1", "hook": "combatStart", "effect": "strength", "value": 1, "icon": "59d2579d46dc41d590a9e6b141ad458b" },
|
||||
"anchor": { "name": "메이플 실드", "desc": "첫 턴 방어도 +10", "hook": "combatStart", "effect": "block", "value": 10, "icon": "6349413e08cc49848862591863d056a0" },
|
||||
"bagOfPrep": { "name": "모험가의 배낭", "desc": "첫 턴 드로우 +2", "hook": "combatStart", "effect": "draw", "value": 2, "icon": "77b240cb8af245b4801a714380267ae9" },
|
||||
"bloodVial": { "name": "피의 목걸이", "desc": "전투 시작 시 HP 2 회복", "hook": "combatStart", "effect": "heal", "value": 2, "icon": "c782e949506a42c49eb139c7e65527d7" },
|
||||
"bronzeScales": { "name": "브론즈 체인메일", "desc": "피격 시 공격자에게 3 반사", "hook": "onPlayerDamaged", "effect": "thorns", "value": 3, "icon": "87272346b145412391622cf803f888d1" },
|
||||
"strawberry": { "name": "건강의 반지", "desc": "획득 시 최대 HP +7", "hook": "passive", "effect": "maxHp", "value": 7, "icon": "58f643e29c354c2783a5ce9a72ec155c" },
|
||||
"penNib": { "name": "황금 깃펜", "desc": "10번째 공격마다 피해 2배", "hook": "attackCalc", "effect": "penNib", "value": 10, "icon": "4d38d721cc064d14b31b9e9a92754139" },
|
||||
"boot": { "name": "브론즈 부츠", "desc": "5 미만 공격 피해가 5로", "hook": "attackCalc", "effect": "boot", "value": 5, "icon": "d572b3aa4dac4162aa0d9e551b055dce" },
|
||||
"akabeko": { "name": "황소 투구", "desc": "전투 첫 공격 피해 +8", "hook": "attackCalc", "effect": "akabeko", "value": 8, "icon": "eb3330a6e2274eff958639f8792119d3" },
|
||||
"centennialPuzzle": { "name": "백년의 부적", "desc": "전투 첫 피격 시 드로우 3", "hook": "onPlayerDamaged", "effect": "firstLossDraw", "value": 3, "icon": "cfe5ed6556b944fc83ab58b774bb2b73" },
|
||||
"meatOnBone": { "name": "고기 망치", "desc": "승리 시 HP 50% 이하면 12 회복", "hook": "combatEnd", "effect": "healIfLow", "value": 12, "icon": "a93e8e87f184411c98c96b877d9f8b10" },
|
||||
"selfFormingClay": { "name": "점토 갑옷", "desc": "피해를 받으면 다음 턴 방어 +3", "hook": "onPlayerDamaged", "effect": "clayBlock", "value": 3, "icon": "bb446793c5204d5db7d33563fe79f648" },
|
||||
"championBelt": { "name": "챔피언 벨트", "desc": "취약 부여 시 약화 1 추가", "hook": "cardDebuff", "effect": "vulnAddsWeak", "value": 1, "icon": "7ca8c63026034113a561d6adf679fed2" }
|
||||
},
|
||||
"startingRelic": "ironHeart",
|
||||
"relicPool": ["energyCore", "vampire", "goldIdol"]
|
||||
"relicPool": [
|
||||
"energyCore", "vampire", "goldIdol",
|
||||
"potionBelt", "burningBlood", "vajra", "anchor", "bagOfPrep", "bloodVial",
|
||||
"bronzeScales", "strawberry", "penNib", "boot", "akabeko",
|
||||
"centennialPuzzle", "meatOnBone", "selfFormingClay", "championBelt"
|
||||
]
|
||||
}
|
||||
|
||||
7
docs/attack-poison.md
Normal file
7
docs/attack-poison.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# 공격 중독
|
||||
|
||||
`attackPoison`은 전투 동안 유지되는 공용 카드 효과 필드입니다.
|
||||
|
||||
- 공격 카드가 실제 체력 피해를 주면 대상에게 지정된 수치만큼 중독을 부여합니다.
|
||||
- 광역 공격은 피해를 받은 각 적에게 중독을 부여합니다.
|
||||
- 현재 Thief Master와 Hermit의 `베놈`이 이 효과를 사용합니다.
|
||||
72
docs/bandit-card-audit.md
Normal file
72
docs/bandit-card-audit.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# 도적 카드 구성 및 밸런스 기록
|
||||
|
||||
도적 계보의 카드 역할, 직업 이동 금지 대상, 공용 효과 필드를 정리합니다.
|
||||
|
||||
## 직업별 컨셉
|
||||
|
||||
- `rogue`: 시작 카드, 1차 스킬, 기초 공격·회피·방어
|
||||
- `thief`: 단검 난타, 교활, 버리기, 중독의 시작
|
||||
- `thiefmaster`: 교활·버리기 연계 완성, 광역 난타, 중독 증폭
|
||||
- `assassin`: 표창 생성, 표창 연속 공격, 표창 비용·피해 보조
|
||||
- `hermit`: 표창 보존·광역화·지속 생성 등 표창 빌드 완성
|
||||
|
||||
Rogue 단계에서도 분기 방향을 미리 경험할 수 있도록 약한 입문 카드를 유지합니다.
|
||||
|
||||
- 중독: `PoisonedStab`
|
||||
- 표창: `LeadingStrike`
|
||||
- 교활: `Untouchable`
|
||||
|
||||
## 스킬 카드 고정
|
||||
|
||||
실제 직업 스킬을 바탕으로 추가한 아래 카드는 다른 차수나 계열로 이동하지 않습니다.
|
||||
|
||||
- Rogue: `DoubleStab`, `LuckySeven`, `Haste`, `DarkSight`, `FlashJump`, `NimbleBody`
|
||||
- Thief: `SavageBlow` 포함 9장
|
||||
- Thief Master: `EdgeCarnival` 포함 11장
|
||||
- Assassin: `ShurikenBurst` 포함 10장
|
||||
- Hermit: `TripleThrow` 포함 9장
|
||||
|
||||
나머지 비스킬 카드는 컨셉에 맞춰 상위 직업으로 이동할 수 있습니다. 상위 직업은 하위 직업 카드를 함께 사용하므로, 이동은 해당 분기의 보상 풀을 제한하는 역할을 합니다.
|
||||
|
||||
## 공용 효과 필드
|
||||
|
||||
- `poison`, `innate`, `playableWhenDrawPileEmpty`
|
||||
- `retain`, `sly`, `discard`, `discardAll`, `addShiv`, `addShivPerDiscard`, `turnStartShiv`, `retainOne`
|
||||
- `turnStartDraw`, `turnStartDiscard`
|
||||
- `nextTurnBlock`, `nextTurnDraw`, `nextTurnKeepBlock`, `nextTurnAttackMultiplier`, `nextTurnCopies`, `nextTurnSelectHandCard`
|
||||
- `damagePerOtherHandCard`, `damagePerAttackPlayedThisTurn`, `damagePerDiscardedThisTurn`, `damagePerSkillInHand`, `otherHandAtLeast`, `bonusHitsWhenOtherHandAtLeast`
|
||||
- `gainEnergy`, `drawUntilHandSize`, `drawPerDiscarded`, `cardPlayedBlock`, `blockGainMultiplier`, `blockPerDamageDealtThisTurn`, `nextSkillCostZero`, `skillCostReductionThisTurn`
|
||||
- `firstCardDamageBonus`
|
||||
- `drawDamage`, `drawPoison`, `shivDamageBonus`, `firstShivDamageBonus`, `shivRetain`, `shivAoe`, `attackDamageVsWeakMultiplier`, `poisonHits`, `poisonRandomTargets`, `skillSlyOnPlay`, `extraPoisonTicks`, `poisonApplicationBurstEvery`, `poisonApplicationBurstDamage`
|
||||
|
||||
## 중복 제거 및 보정
|
||||
|
||||
- 삭제: `Mirage`, `Accuracy`, `PhantomBlades`, `Adrenaline`, `Afterimage`, `Accelerant`, `Envenom`, `Tracking`
|
||||
- 이유: 상위 직업 스킬 카드와 효과가 같거나, 비용 대비 열세라 별도 선택지가 되지 못함
|
||||
- `Anticipate`: 턴 종료 시 얻은 민첩을 잃도록 실제 효과와 설명을 일치시킴
|
||||
- `Backstab`, `Assassinate`, `TheHunt`, `PiercingWail`: 설명에 있던 소멸을 실제 필드에 반영
|
||||
- 2차 지급: Thief `DaggerAcceleration`, Assassin `JavelinAcceleration`
|
||||
- 3차 지급: Thief Master `Venom`, Hermit `SpiritJavelin`
|
||||
|
||||
## 카드 효율 검증
|
||||
|
||||
`node tools/balance/card-efficiency.mjs --runs 1000`으로 도적 계열 카드 전체를 검증합니다.
|
||||
|
||||
- 각 직업의 기준 덱에서 같은 종류의 카드 한 장을 교체하고 동일 시드로 반복 전투합니다.
|
||||
- 승률, 승리 시 체력, 전투 턴을 합친 점수를 같은 직업·희귀도 중앙값과 비교합니다.
|
||||
- 0코스트 에너지 생성, 재사용 가능한 영구 능력치, 저비용 2배 증폭처럼 자동 플레이가 놓치기 쉬운 구조도 별도로 검사합니다.
|
||||
- 교활, 조건부 중독, 카드 보존처럼 플레이 순서 의존성이 큰 효과는 자동 시뮬레이션 하위권만으로 상향하지 않습니다.
|
||||
|
||||
2026-07-01 검증 결과 구조적 위험은 0장입니다. 주요 조정은 `독맥 터뜨리기`, `메아리 칼자국`, `소리 없는 제압`, `그리드`, `그림자 속도전`, `스틸`, 두 계열의 `피지컬 트레이닝`, `마크 오브 어쌔신`, `자벨린 액셀레이션`, `비장의 패`에 반영했습니다.
|
||||
|
||||
비스킬 카드 78장의 메이플풍 표시 이름은 `docs/rogue-card-names.md`에서 관리합니다. 메이플 원본 스킬 카드 45장의 이름은 변경하지 않습니다.
|
||||
|
||||
## 5섹션 캠페인 검증
|
||||
|
||||
`node tools/balance/rogue-campaign.mjs --runs 5000 --reward-min 5`로 전체 런을 검증합니다.
|
||||
|
||||
- 섹션마다 일반전 4회, 엘리트 1회, 보스 1회를 진행합니다.
|
||||
- 1섹션은 Rogue, 2섹션은 2차 직업, 3~5섹션은 3차 직업 카드 풀을 사용합니다.
|
||||
- 실제 카드 보상 확률, 전직 지급 카드, 시작·획득 유물, 체력 유지와 휴식 회복을 반영합니다.
|
||||
- 몬스터 배율은 `1.00 → 1.075 → 1.15 → 1.30 → 1.45`이며 런타임과 시뮬레이터가 같은 공용 상수를 사용합니다.
|
||||
- 5,000회 결과: Thief Master 완주 2.9%, Hermit 완주 3.6%. 자동 플레이와 일부 공격형 유물 미구현을 감안한 보수적 결과입니다.
|
||||
164
docs/card-effect-fields.md
Normal file
164
docs/card-effect-fields.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# Card Effect Fields
|
||||
|
||||
This file tracks the shared data fields used by `data/cards.json`.
|
||||
The goal is to keep card behavior reusable instead of hardcoding one-off card names.
|
||||
|
||||
## Damage
|
||||
|
||||
- `damage`: base attack damage
|
||||
- `damageFromCurrentBlock`: add current block times this value to attack damage
|
||||
- `damageNameMatch`: substring to match against owned card names
|
||||
- `damagePerOwnedNameMatch`: bonus damage per owned card whose name matches `damageNameMatch`
|
||||
- `damagePerOtherHandCard`: bonus damage per other card in hand
|
||||
- `damagePerAttackPlayedThisTurn`: bonus damage per attack played this turn
|
||||
- `damagePerDiscardedThisTurn`: bonus damage per card discarded this turn
|
||||
- `damagePerSkillInHand`: bonus damage per skill card in hand
|
||||
- `damagePerCardDrawnThisCombat`: bonus damage per card drawn this combat
|
||||
- `damagePerCombo`: bonus base damage per current Combo
|
||||
- `damagePerHolyCharge`: bonus base damage per current Holy Charge
|
||||
- `attackDamagePerCombo`: Power field that adds base damage per current Combo to all Attacks
|
||||
- `attackPlayedDamage`: Power field that deals extra damage after an Attack card is played
|
||||
- `damagePerTurn`: damage applied at turn start
|
||||
- `cardPlayedDamage`: damage when the card is played
|
||||
- `cardPlayedRandomDamage`: random damage when the card is played
|
||||
- `drawOnExhaust`: draw when a card is exhausted
|
||||
- `rewardOnKill`: gain bonus reward screens when the card kills
|
||||
- `maxHpOnKill`: gain max HP when the attack kills
|
||||
- `drawNameMatchAutoPlay`: auto-play drawn cards whose names contain this substring
|
||||
- `randomTargetEachHit`: choose a random alive enemy for each hit
|
||||
- `repeatOnKill`: repeat the attack when it kills at least one enemy
|
||||
- `firstCardDamageBonus`: bonus damage for the first card played this turn
|
||||
- `drawDamage`: damage dealt when a card is drawn
|
||||
- `blockPerDamageDealtThisTurn`: gain block equal to damage dealt this turn
|
||||
- `shivDamageBonus`: bonus damage for all Shivs
|
||||
- `firstShivDamageBonus`: bonus damage for the first Shiv each turn
|
||||
- `attackDamageVsWeakMultiplier`: multiplier when the attack hits Weak targets
|
||||
- `useAllEnergy`: treat the card as spending all available energy
|
||||
- `xDamagePerEnergy`: scale attack damage by energy spent
|
||||
- `xWeakPerEnergy`: scale Weak applied by energy spent
|
||||
|
||||
## Block and utility
|
||||
|
||||
- `block`: gain block
|
||||
- `cardPlayedBlock`: gain block whenever a card is played
|
||||
- `blockGainMultiplier`: multiplier for block gained this turn
|
||||
- `hits`: multi-hit count
|
||||
- `aoe`: hit all enemies
|
||||
- `pierce`: ignore block
|
||||
- `draw`: draw cards immediately
|
||||
- `drawUntilHandSize`: draw until hand reaches a target size
|
||||
- `drawSkillBlock`: gain block for each Skill drawn
|
||||
- `drawPoison`: apply poison when a card is drawn
|
||||
- `exhaustHandNonAttack`: exhaust every non-Attack card in hand
|
||||
- `exhaustHandAll`: exhaust every card in hand
|
||||
- `drawPerExhausted`: draw cards equal to exhausted cards
|
||||
- `blockPerExhaustedCard`: gain block for each card exhausted by the current effect
|
||||
- `addRandomCardCount`: add random cards to hand
|
||||
- `addRandomCardPerExhausted`: add random cards equal to exhausted cards
|
||||
- `addRandomCardKind`: filter random added cards by kind
|
||||
- `addRandomCardSameClass`: restrict random added cards to the source card class
|
||||
- `addedCardsCostZeroThisTurn`: cards added by this effect cost 0 this turn
|
||||
- `playTopDrawPileCount`: play cards from the top of the draw pile
|
||||
- `playTopDrawPileCountPerEnergy`: play cards from the top of the draw pile per energy spent
|
||||
- `handCostZeroThisTurn`: make hand cards cost 0 this turn
|
||||
- `drawDisabledThisTurn`: disable draw for the rest of the turn
|
||||
- `heal`: heal immediately
|
||||
- `gainEnergy`: gain energy immediately
|
||||
- `strength`: gain Strength
|
||||
- `dex`: gain Dexterity
|
||||
- `thorns`: gain Thorns
|
||||
- `selfVuln`: apply Vulnerable to self
|
||||
- `extraPoisonTicks`: add extra poison ticks at enemy turn start
|
||||
- `comboGain`: gain Combo when the card resolves; Attack cards gain it after dealing damage
|
||||
- `comboOnAttack`: Power field that gains Combo whenever an Attack card is played
|
||||
- `comboMax`: Power field that raises the maximum Combo above the default 5
|
||||
- `attackWeak`: Power field that applies Weak after an Attack card is played
|
||||
- `removePlayerDebuffs`: remove player Weak and Vulnerable
|
||||
- `holyForce`: marks a card as Holy Force for Holy Charge Power triggers
|
||||
- `holyChargeGain`: gain Holy Charge directly
|
||||
- `holyChargeOnHolyForce`: Power field that gains Holy Charge after a Holy Force card
|
||||
- `holyChargeMax`: Power field that raises the maximum Holy Charge above the default 3
|
||||
- `blockPerHolyCharge`: gain additional block per current Holy Charge
|
||||
- `healPerHolyCharge`: heal additional HP per current Holy Charge
|
||||
- `holyChargeSpendAll`: consume all Holy Charge after resolving the card
|
||||
- `damageTakenReduction`: Power field that reduces incoming damage; total reduction is capped at 75%
|
||||
- `blockOnDamaged`: Power field that grants block after taking HP damage
|
||||
- `strengthOnDamagedOnce`: Power field that grants Strength on the first HP damage each combat
|
||||
|
||||
## Status
|
||||
|
||||
- `weak`: apply Weak
|
||||
- `vuln`: apply Vulnerable
|
||||
- `poison`: apply Poison
|
||||
- `poisonHits`: apply poison multiple times
|
||||
- `poisonRandomTargets`: spread poison applications across random alive enemies
|
||||
- `poisonIfTargetPoisoned`: apply poison only if the target is already poisoned
|
||||
- `poisonApplicationBurstEvery`: trigger a burst every N poison applications
|
||||
- `poisonApplicationBurstDamage`: burst damage when the poison application threshold is reached
|
||||
- `skillSlyOnPlay`: make a played Skill card count as sly when it is later discarded
|
||||
- `turnHandSlyCount`: mark up to N other Skill cards in hand as sly for this turn
|
||||
- `attackPoison`: apply poison when attack damage is dealt
|
||||
- `intangible`: reduce incoming damage to 1 for the duration
|
||||
- `endTurnDexLoss`: lose Dexterity at end of turn
|
||||
- `combatCostReductionOnPlay`: reduce this card's cost each time it is played this combat
|
||||
- `enemyStrengthLossThisTurn`: reduce enemy Strength for the rest of the turn
|
||||
- `affectsAllEnemies`: apply the card's debuffs to every alive enemy
|
||||
- `removeEnemyBlock`: clear enemy block when the card resolves
|
||||
- `removeEnemyArtifact`: consume enemy Artifact when the card resolves
|
||||
|
||||
`poison` deals damage at enemy turn start and then decreases by 1.
|
||||
|
||||
## Shivs and discard
|
||||
|
||||
- `discard`: discard a chosen number of cards from hand
|
||||
- `discardAll`: discard the whole hand
|
||||
- `drawPerDiscarded`: draw one extra card per discarded card
|
||||
- `addShiv`: create Shiv cards
|
||||
- `addShivPerDiscard`: create one Shiv per discarded card
|
||||
- `shivRetain`: Shiv cards are retained at end of turn
|
||||
- `shivAoe`: Shiv cards hit all enemies for the turn
|
||||
- `sly`: trigger on discard
|
||||
- `retain`: keep the card at end of turn
|
||||
|
||||
## Powers and turn effects
|
||||
|
||||
- `powerEffect: "strengthPerTurn"`
|
||||
- `powerEffect: "energyPerTurn"`
|
||||
- `powerEffect: "blockPerTurn"`
|
||||
- `powerEffect: "poisonPerTurn"`
|
||||
- `powerEffect: "damagePerTurn"`
|
||||
- `powerEffect: "healPerTurn"`
|
||||
- `powerEffect: "retainOne"`
|
||||
- `powerEffect: "keepBlock"`
|
||||
- `turnStartShiv`: create Shivs at turn start
|
||||
- `turnStartDraw`: draw cards at turn start
|
||||
- `turnStartDiscard`: discard cards at turn start
|
||||
|
||||
## Next turn planning
|
||||
|
||||
- `nextTurnBlock`: gain block next turn
|
||||
- `nextTurnDraw`: draw extra cards next turn
|
||||
- `nextTurnKeepBlock`: keep block next turn
|
||||
- `nextTurnAttackMultiplier`: attack multiplier next turn
|
||||
- `nextTurnCopies`: copy a chosen card next turn
|
||||
- `nextTurnSelectHandCard`: choose a card from the current hand for next turn copies
|
||||
- `nextTurnSelectPrompt`: prompt text for selection UI
|
||||
- `nextSkillRepeatCount`: repeat the next Skill's effect
|
||||
- `nextSkillCostZero`: make the next Skill cost 0
|
||||
- `skillCostReductionThisTurn`: reduce Skill costs this turn
|
||||
|
||||
## Misc
|
||||
|
||||
- `innate`: place the card in the opening hand
|
||||
- `playableWhenDrawPileEmpty`: only playable when the draw pile is empty
|
||||
- `exhaust`: exhaust after use
|
||||
- `unplayable`: cannot be played
|
||||
- `curse`: curse card
|
||||
- `token`: token card
|
||||
- `endTurnDamage`: damage if the card remains in hand at end of turn
|
||||
|
||||
## Rules
|
||||
|
||||
- Prefer shared fields over card-specific branches.
|
||||
- Reuse the same field name for the same behavior.
|
||||
- Add a new shared field before adding more special-case card logic.
|
||||
5
docs/card-play-damage.md
Normal file
5
docs/card-play-damage.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 카드 사용 시 피해
|
||||
|
||||
`cardPlayedDamage`는 카드를 사용할 때마다 현재 대상에게 체력을 직접 깎는 공용 효과입니다. 방어도는 무시하고, 같은 필드를 다른 카드에도 그대로 붙여 재사용할 수 있습니다.
|
||||
|
||||
`cardPlayedRandomDamage`는 같은 시점에 살아 있는 적 하나를 랜덤으로 골라 체력을 직접 깎습니다. `Strangle`과 `SerpentForm` 같은 카드가 이 계열을 씁니다.
|
||||
39
docs/codex-workflow.md
Normal file
39
docs/codex-workflow.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Codex Workflow
|
||||
|
||||
이 저장소에서 작업할 때는 토큰과 변경량을 아끼는 쪽을 기본으로 둔다.
|
||||
|
||||
## 작업 원칙
|
||||
|
||||
- 이미 확인한 사실은 다시 읽지 않는다.
|
||||
- 같은 내용을 통째로 지우고 새로 쓰지 않는다.
|
||||
- 수정은 가능한 한 `apply_patch`로 섹션 단위만 한다.
|
||||
- 문서는 전체 재작성보다 부분 수정으로 유지한다.
|
||||
- 카드 구현은 한 번에 하나씩, 공용 필드 우선으로 넣는다.
|
||||
- 새 기능은 `데이터 1곳 + 런타임 1곳 + 테스트 1곳` 순서로 맞춘다.
|
||||
|
||||
## 읽기 원칙
|
||||
|
||||
- 파일은 필요한 것만 읽는다.
|
||||
- 비슷한 파일은 병렬로 한 번에 확인한다.
|
||||
- 같은 정보를 여러 번 요약하지 않는다.
|
||||
|
||||
## 쓰기 원칙
|
||||
|
||||
- 공용으로 표현 가능한 효과는 카드 전용 분기로 만들지 않는다.
|
||||
- 같은 의미의 효과는 같은 필드 이름을 쓴다.
|
||||
- 문서는 카드별 상태표와 공용 필드 사전을 분리해서 유지한다.
|
||||
- 카드 `kind`는 효과와 맞춘다 — 데미지 카드=`Attack`, block·유틸만 있으면=`Skill`, 지속효과=`Power`(`powerEffect` 또는 power 필드 필수). 안 맞으면 사용 불가/死카드가 된다(Power 분기는 damage/aoe 무시, Attack은 몬스터 드롭 라우팅).
|
||||
- 새 효과 필드는 Lua(`cb/*.mjs`)와 JS 미러(`tools/balance/sim-balance.mjs`) 양쪽에 구현한다(한쪽만 = 게임↔시뮬 드리프트).
|
||||
|
||||
## 응답 원칙
|
||||
|
||||
- 중간 보고는 짧게 한다.
|
||||
- 바뀐 점과 남은 점만 말한다.
|
||||
- 불필요한 재설명은 줄인다.
|
||||
|
||||
## 검증·통합 원칙
|
||||
|
||||
- 카드/cb 변경 후 검증 스위트를 돌린다: `node tools/verify/cardkinds.mjs`(kind↔효과)·`cbprops.mjs`(미선언 `self.X` 필드)·`cbgap.mjs`(UI 경로) + `node --test tools/balance/sim-balance.test.mjs`(이중구현 미러). 이상 0을 확인한 뒤 산출물을 갱신한다.
|
||||
- 작업 브랜치에 `main`을 머지했다가 충돌·문제가 나도 그 머지 커밋을 통째로 `git revert`하지 않는다 — main에 먼저 들어간 타인 작업이 collateral로 사라진다(2026-06-30 `#98/#99`가 `#96` 11개 수정을 이렇게 날린 사고). 소스 충돌만 해소하고 산출물(codeblock 등)은 재생성한다.
|
||||
- 하네스 규칙의 최종 권위는 `RULES.md`(§1 산출물 읽기/수정 금지·§4 git/PR·§6 이중구현 동기화·§9 카드 kind)이고, codex 전용 하드룰은 `docs/codex-working-rules.md`다. 작업 전 둘 다 따른다.
|
||||
|
||||
11
docs/codex-working-rules.md
Normal file
11
docs/codex-working-rules.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Codex Working Rules
|
||||
|
||||
1. 사용자가 특정 클래스만 수정하라고 했으면 그 클래스 외의 데이터, 설명문, 밸런스 문구는 건드리지 않는다.
|
||||
2. 기존 한글 텍스트는 요청이 없으면 임의로 바꾸지 않는다.
|
||||
3. 전직 구조를 바꿀 때는 실제 직업명만 사용한다. 임의의 내부 분류명이나 새 직업명을 사용자-facing 구조에 추가하지 않는다.
|
||||
4. 대량 치환 전에 수정 대상 파일과 범위를 먼저 확인하고, 원본 문자열이 깨진 상태면 치환 작업을 진행하지 않는다.
|
||||
5. 생성기 파일을 크게 수정할 때는 `node --check`와 생성기 실행으로 문법을 먼저 검증한 뒤 산출물을 갱신한다.
|
||||
6. 작업 브랜치에 `main`을 머지했다가 충돌·문제가 나도 **그 머지 커밋을 통째로 `git revert`하지 않는다** — main에 먼저 들어간 타인 작업이 collateral로 사라진다(2026-06-30 `#98/#99`가 `#96`의 버그수정 11개를 이렇게 전부 날림). 소스 충돌만 해소하고 산출물(codeblock 등)은 재생성한다. (RULES §4)
|
||||
7. 카드 `kind`는 효과와 일치시킨다 — 데미지 카드=`Attack`, block·유틸만 있으면=`Skill`, 지속효과=`Power`(`powerEffect` 또는 power 필드 필수). 안 맞으면 사용 불가/死카드가 된다(2026-06-30 아이언 바디=Attack인데 block만, 분노=Power인데 damage만 → 둘 다 먹통). 카드 추가/수정 후 `node tools/verify/cardkinds.mjs`로 검증(이상 0 = exit 0). (RULES §9)
|
||||
8. 카드/cb 변경 후 검증 스위트를 돌린다: `node tools/verify/cardkinds.mjs`(kind↔효과)·`cbprops.mjs`(미선언 `self.X` 필드)·`cbgap.mjs`(UI 경로) + `node --test tools/balance/sim-balance.test.mjs`(이중구현 미러). 새 효과 필드는 Lua(`cb/*.mjs`)와 JS 미러(`tools/balance/sim-balance.mjs`) **양쪽**에 구현(한쪽만 = 게임↔시뮬 드리프트). (RULES §6)
|
||||
9. 하네스 규칙의 권위는 `RULES.md`다 — 작업 전 RULES.md(§1 산출물 읽기/수정 금지·§4 git/PR·§6 이중구현 동기화·§9 카드 kind)를 읽고 따른다.
|
||||
86
docs/deck-concept.md
Normal file
86
docs/deck-concept.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# SlayMaple 덱 컨셉 & 직업 스킬셋
|
||||
|
||||
> SlayMaple 카드 덱의 **직업별 컨셉 · 메이플 스킬셋 · Slay the Spire 2 차용 매칭** 설계 문서.
|
||||
> 원칙: 카드 한 장 = **STS2 메커니즘(뼈대) + 메이플 스킬(외형)**. STS 고유 *표현*(카드명·아트·UI)은 모방 금지, *메커니즘*만 차용(IP 해석 심사 대비).
|
||||
> 수치(데미지·코스트·등급)는 `tools/balance/sim-balance.mjs`로 검증. 본 문서는 *어떤 스킬을 어떤 카드로* 만들지의 설계도.
|
||||
|
||||
기준: 메이플 = **클래식(빅뱅 이전)** 스킬 외형, STS = **Slay the Spire 2**.
|
||||
|
||||
---
|
||||
|
||||
## 직업 ↔ STS2 매칭 요약
|
||||
|
||||
| 직업 | 컨셉 | STS2 차용 |
|
||||
|---|---|---|
|
||||
| ⚔️ 전사 | 단단한 탱커/브루저 | The Ironclad (힘·방어·소멸) |
|
||||
| 🗡️ 도적 | 단검 난사 / 독 | The Silent (표창·독·교활) |
|
||||
| 🔮 법사 | 약체 + 게이지 운용 | The Defect (오브·집중) |
|
||||
|
||||
---
|
||||
|
||||
## ⚔️ 전사 (Warrior) — HP80 · 탱커
|
||||
|
||||
방어를 쌓고 버티다 역공하는 브루저. Ironclad의 두 축을 2차 전직으로 분화.
|
||||
|
||||
### 파이터 — 콤보 브루저형 탱커
|
||||
- **콤보 규칙**: 공격 카드를 **연속으로** 사용하면 콤보가 쌓인다. **방어·파워 등 비공격(Skill/Power) 카드를 사용하면 콤보가 리셋(0)** 된다.
|
||||
- 콤보가 쌓일수록 **데미지 증가 버프(힘 계열)** 를 받는다 → 방어를 포기하고 공격을 몰아칠수록 강해지는 리스크/리워드.
|
||||
- 차용: Ironclad 힘 스택/Demon Form + 콤보. 메이플 외형: 콤보 어택·분노·브랜디시.
|
||||
|
||||
### 페이지 — 방어 축적 → 바디 슬램 카운터
|
||||
- **위협**(전체 적 약화+취약 디버프)로 버티며 **방어도를 축적**(아이언 월 등 + 방어 유지 retain).
|
||||
- **바디 슬램**: 현재 방어도에 비례한 피해로 카운터. 파워 가드(반사) 보조.
|
||||
- 차용: Ironclad 방어 빌드(Barricade+Entrench→Body Slam). 메이플 외형: 위협·아이언 월·파워 가드.
|
||||
|
||||
### 스피어맨 — 유지/리치형
|
||||
- 하이퍼 바디(최대 HP↑)·아이언 월(방어 유지)·창 리치 광역. 공격 스케일(파이터)·방어 카운터(페이지)와 구분되는 지속 탱.
|
||||
|
||||
---
|
||||
|
||||
## 🗡️ 도적 (Thief) — HP70 · 단검/독
|
||||
|
||||
Slay the Spire *Silent* 차용. **형(codex)이 Silent 88장 완역 포트 + 스킬 아이콘 적용 완료.** 3대 아키타입:
|
||||
|
||||
- **표창(Shiv) 난사**: 0코스트 표창 토큰 대량 생성 → 공격마다 연계. (정밀=표창 피해↑, 칼날 부채=표창 전체화)
|
||||
- **독(Poison)**: 중독 중첩 → 매턴 틱뎀. (유독 가스·발병·촉진제·독 바르기)
|
||||
- **교활(Sly)·버림(discard)**: 버려질 때 무료 발동, 얇은 덱 빠른 순환.
|
||||
|
||||
### 2차 갈래
|
||||
- **어쌔신** — 표창 난사 + 크리 / 흡혈(드레인) 중심.
|
||||
- **시프** — 단검 난타(새비지 블로우 = 다단히트) + 독 / 버림 중심.
|
||||
|
||||
> 남은 작업: 카드명이 STS 직역(무력화·배신·아드레날린 등) → **어쌔신/시프 메이플 스킬명으로 재서사** + 멀티플레이어 전제 카드(측면 공격·비열함·추적) 싱글 출품용 정리.
|
||||
|
||||
---
|
||||
|
||||
## 🔮 법사 (Magician) — HP70 · 약체/게이지
|
||||
|
||||
몸은 약하나 **게이지(오브) 운용**으로 다중 공격·화력 집중. **오브 메커니즘은 위자드(불/독·썬/콜)에만 적용**, 클레릭은 별도 보조 컨셉.
|
||||
|
||||
### 위자드(불/독) — 독 + 불 시너지
|
||||
- **독을 묻히는 스킬**(포이즌 브레스 등)으로 대상에 독을 부여(독뎀 = DoT).
|
||||
- **독이 묻은 적에게 불 카드(파이어 애로우 등)를 쓰면 추가 데미지** — *독뎀 상수* 보너스(독 스택/상수 비례).
|
||||
- 즉 "독 깔기 → 불로 폭발"의 2단 콤보. 불·독 오브로 운용.
|
||||
|
||||
### 위자드(썬/콜) — 오브 운용(썬더 다중 / 콜드 빙결)
|
||||
- **오브로 썬더·콜드를 보유**. **썬더 = 다중 공격 특화**(AoE·다단). **콜드 = 빙결 부여**(빙결 = *취약과 동일 효과* 를 데미지와 함께).
|
||||
- **오브를 사용하는 만큼 오브를 획득하거나 다중 소모**하는 방식 — 오브 수급/소비 운용이 핵심.
|
||||
|
||||
### 클레릭 — 보조(회복·버프) · 오브 없음
|
||||
- **회복 스킬**(힐)과 **각종 버프**(블레스 등) 중심의 서포트.
|
||||
- **언데드 계열 몬스터에게는 힐로 공격** 가능 — 보조 힐러 정체성.
|
||||
|
||||
> ⚠️ 위자드 오브/게이지·전사 콤보 스택·바디 슬램·독뎀 시너지는 **신규 메커니즘** — `tools/deck/gen-slaydeck.mjs`(전투 규칙) + `tools/balance/sim-balance.mjs`(JS 미러) 양쪽 구현·동기화 필요.
|
||||
|
||||
---
|
||||
|
||||
## 차용 경계 (IP 심사 대비)
|
||||
|
||||
- 차용 OK = **메커니즘**(콤보 스택·방어→피해 전환·독+불 시너지·오브 게이지·빙결=취약 등 시스템).
|
||||
- 모방 금지 = STS 고유 **표현**(카드명·아트·UI 직접 사용).
|
||||
- 만점 루트 = STS2 메커니즘을 **메이플 스킬·외형으로 완전 재서사화**.
|
||||
|
||||
## 참고
|
||||
|
||||
- 카드 데이터 단일 소스: `data/cards.json` (현 122장: 전사 18·마법사 14·도적 88 + Shiv·저주)
|
||||
- 메이플 스킬 외형 매핑·STS2 캐릭터 상세는 박재오 개인 위키 `프로젝트-메이플-덱빌딩-스킬구성` / `프로젝트-메이플-STS2-차용-덱컨셉` 참조.
|
||||
8
docs/draw-count.md
Normal file
8
docs/draw-count.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# 전투 드로우 누적
|
||||
|
||||
`damagePerCardDrawnThisCombat`은 이번 전투 동안 실제로 뽑힌 카드 수를 기준으로 공격력을 올리는 공용 필드입니다.
|
||||
|
||||
적용 예시:
|
||||
|
||||
- `Murder`: 이번 전투 동안 뽑은 카드 1장당 피해량이 1 증가
|
||||
|
||||
22
docs/draw-skill-block.md
Normal file
22
docs/draw-skill-block.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# 드로우 연동 효과
|
||||
|
||||
드로우 결과를 받아 후속 효과를 처리하는 공용 패턴을 정리합니다.
|
||||
|
||||
## 현재 구현
|
||||
|
||||
- `draw`: 카드를 뽑음
|
||||
- `drawUntilHandSize`: 손패가 지정 수치가 될 때까지 뽑음
|
||||
- `drawSkillBlock`: 이번 카드로 뽑힌 카드 중 스킬 카드마다 방어도를 얻음
|
||||
|
||||
## 동작 방식
|
||||
|
||||
- 드로우 함수는 이번에 뽑힌 카드 ID 목록을 반환합니다.
|
||||
- 카드 효과는 그 목록을 보고 조건을 판정합니다.
|
||||
- 그래서 `EscapePlan` 같은 카드뿐 아니라, 나중에 같은 규칙이 필요한 카드에도 같은 필드를 붙이면 됩니다.
|
||||
|
||||
## 예시
|
||||
|
||||
- `EscapePlan`
|
||||
- `draw = 1`
|
||||
- `drawSkillBlock = 3`
|
||||
|
||||
5
docs/intangible.md
Normal file
5
docs/intangible.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 불가침
|
||||
|
||||
`intangible`는 카드를 사용할 때 플레이어에게 불가침 수치를 부여하는 공용 필드입니다. 불가침이 남아 있는 동안 받는 피해는 1로 줄어들고, 턴이 끝날 때 1씩 감소합니다.
|
||||
|
||||
`endTurnDexLoss`는 그 카드가 활성화된 동안 매 턴 종료 시 민첩을 잃게 만드는 공용 필드입니다. `WraithForm` 같은 카드가 이 조합을 사용합니다.
|
||||
12
docs/next-skill-repeat.md
Normal file
12
docs/next-skill-repeat.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Next Skill Repeat
|
||||
|
||||
`nextSkillRepeatCount`는 다음에 사용하는 스킬 카드의 효과를 추가 횟수만큼 다시 적용하는 공용 필드입니다.
|
||||
|
||||
현재 구현은 카드가 발동할 때 이 수치를 전역 상태에 누적해 두고, 다음 스킬 카드가 실제로 사용되면 그 효과를 같은 카드에 대해 다시 한 번 이상 적용합니다. 카드 종류는 고정하지 않았기 때문에, 같은 필드를 다른 카드에도 그대로 붙일 수 있습니다.
|
||||
|
||||
예시:
|
||||
|
||||
- `Burst`
|
||||
- `nextSkillRepeatCount = 1`
|
||||
- 다음 스킬을 한 번 더 적용
|
||||
|
||||
5
docs/reward-on-kill.md
Normal file
5
docs/reward-on-kill.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 처치 보상
|
||||
|
||||
`rewardOnKill`은 해당 카드가 적을 처치했을 때 전투 보상 화면을 한 번 더 이어서 보여주는 공용 필드입니다. 현재 보상 UI는 3장 선택을 유지하고, 보상 화면만 추가로 한 번 더 열립니다.
|
||||
|
||||
`TheHunt`는 이 규칙을 사용합니다. 같은 패턴이 필요한 다른 카드에도 그대로 붙일 수 있습니다.
|
||||
97
docs/rogue-card-names.md
Normal file
97
docs/rogue-card-names.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# 도적 비스킬 카드 이름
|
||||
|
||||
메이플스토리 원본 스킬을 바탕으로 만든 카드 45장은 이름을 고정합니다.
|
||||
아래 78장은 다른 직업의 스킬명을 점유하지 않도록 도적 계열의 독자적인 이름으로 변경했습니다.
|
||||
|
||||
## Rogue
|
||||
|
||||
- `Neutralize`: 무력화 -> 커닝식 견제
|
||||
- `SilentStrike`: 타격 -> 초보 도적의 칼끝
|
||||
- `Survivor`: 생존자 -> 골목길 생존술
|
||||
- `SilentDefend`: 수비 -> 낡은 가죽 방패
|
||||
- `Slice`: 칼질 -> 짧은 단검질
|
||||
- `PoisonedStab`: 독 찌르기 -> 초록 독단검
|
||||
- `SuckerPunch`: 불의의 일격 -> 골목 기습
|
||||
- `LeadingStrike`: 선제 타격 -> 초보 표창 던지기
|
||||
- `Anticipate`: 예측 -> 럭키 예감
|
||||
- `Deflect`: 튕겨내기 -> 단검 쳐내기
|
||||
- `Backflip`: 공중제비 -> 커닝 곡예
|
||||
- `DodgeAndRoll`: 구르기 -> 골목 구르기
|
||||
- `Untouchable`: 범접 불가 -> 연막 속 숨기
|
||||
- `Backstab`: 배신 -> 그림자 등찌르기
|
||||
- `EscapePlan`: 탈출구 -> 비상용 연막탄
|
||||
|
||||
## Thief
|
||||
|
||||
- `DaggerSpray`: 단검 분사 -> 단검비
|
||||
- `DaggerThrow`: 단검 투척 -> 비도 투척
|
||||
- `FollowThrough`: 완수 -> 연달아 찌르기
|
||||
- `FlickFlack`: 재주넘기 -> 커닝 난무
|
||||
- `Prepared`: 예비 -> 비장의 패
|
||||
- `PiercingWail`: 귀를 찢는 비명 -> 골목의 살기
|
||||
- `DeadlyPoison`: 맹독 -> 맹독 조제
|
||||
- `Snakebite`: 뱀 물기 -> 독니 단검
|
||||
- `PreciseCut`: 정밀한 베기 -> 급소 절개
|
||||
- `Finisher`: 마무리 -> 마지막 칼끝
|
||||
- `MementoMori`: 메멘토 모리 -> 사신의 장부
|
||||
- `Strangle`: 목 조르기 -> 그림자 올가미
|
||||
- `Dash`: 돌진 -> 뒷골목 돌파
|
||||
- `CalculatedGamble`: 계산된 도박 -> 메소 건 승부
|
||||
- `Expose`: 들춰내기 -> 약점 들추기
|
||||
- `Acrobatics`: 곡예 -> 지붕 위 곡예
|
||||
- `HandTrick`: 손기술 -> 재빠른 손놀림
|
||||
- `Expertise`: 전문성 -> 노련한 단검술
|
||||
- `BubbleBubble`: 차오르는 독 -> 독액 농축
|
||||
- `Blur`: 흐릿함 -> 흐린 잔영
|
||||
- `LegSweep`: 다리 걸기 -> 발목 베기
|
||||
- `Reflex`: 반사신경 -> 찰나의 반응
|
||||
- `Tactician`: 전략가 -> 골목길 책략
|
||||
- `WellLaidPlans`: 괜찮은 전략 -> 빈틈없는 작전
|
||||
- `Footwork`: 발놀림 -> 사뿐한 발놀림
|
||||
- `NoxiousFumes`: 유독 가스 -> 숨막히는 독연기
|
||||
|
||||
## Thief Master
|
||||
|
||||
- `BouncingFlask`: 탄성 플라스크 -> 통통 독병
|
||||
- `Haze`: 아지랑이 -> 보랏빛 독연기
|
||||
- `Outbreak`: 발병 -> 독맥 터뜨리기
|
||||
- `Speedster`: 스피드스터 -> 그림자 속도전
|
||||
- `GrandFinale`: 대단원의 막 -> 커닝의 대단원
|
||||
- `Assassinate`: 암살 -> 어둠 속 급소
|
||||
- `EchoingSlash`: 메아리 참격 -> 메아리 칼자국
|
||||
- `Murder`: 살해 -> 쌓여가는 살의
|
||||
- `Malaise`: 불쾌 -> 기운 빼는 독
|
||||
- `ShadowStep`: 그림자 걸음 -> 그림자 발자국
|
||||
- `Shadowmeld`: 그림자 은신 -> 연막 속 은신
|
||||
- `CorrosiveWave`: 부식성 파도 -> 부식 독물결
|
||||
- `Burst`: 폭주 -> 연속 술수
|
||||
- `KnifeTrap`: 칼날 함정 -> 숨은 칼날덫
|
||||
- `BulletTime`: 불릿 타임 -> 멈춘 듯한 순간
|
||||
- `Nightmare`: 악몽 -> 검은 꿈
|
||||
- `ToolsOfTheTrade`: 작업 도구 -> 도적의 연장통
|
||||
- `MasterPlanner`: 설계의 대가 -> 작전의 달인
|
||||
- `SerpentForm`: 구렁이의 형상 -> 독사의 몸놀림
|
||||
- `Abrasive`: 연마 -> 거친 숫돌질
|
||||
- `Suppress`: 진압 -> 소리 없는 제압
|
||||
- `WraithForm`: 유령의 형상 -> 유령 같은 몸놀림
|
||||
|
||||
## Assassin
|
||||
|
||||
- `Ricochet`: 도탄 -> 통통 튀는 표창
|
||||
- `BladeDance`: 검무 -> 표창 별무리
|
||||
- `CloakAndDagger`: 망토와 단검 -> 망토 속 별
|
||||
- `Skewer`: 꼬챙이 -> 꿰뚫는 표창
|
||||
- `Flechettes`: 프레췌 -> 표창 셈법
|
||||
- `Pounce`: 덮치기 -> 어둠을 가르는 도약
|
||||
- `Predator`: 천적 -> 표창 끝의 추격
|
||||
- `Pinpoint`: 정밀 사격 -> 한 점 겨냥
|
||||
- `HiddenDaggers`: 숨겨진 표창 -> 숨겨둔 표창
|
||||
- `UpMySleeve`: 비책 -> 소매 속 표창
|
||||
- `InfiniteBlades`: 무한의 검날 -> 끝없는 표창통
|
||||
- `TheHunt`: 사냥 -> 커닝 현상금
|
||||
- `StormOfSteel`: 강철의 폭풍 -> 쇠별 폭풍
|
||||
|
||||
## Hermit
|
||||
|
||||
- `BladeOfInk`: 잉크 칼날 -> 먹빛 표창
|
||||
- `FanOfKnives`: 칼날 부채 -> 사방 표창비
|
||||
213
docs/superpowers/plans/2026-06-09-map-camera.md
Normal file
213
docs/superpowers/plans/2026-06-09-map-camera.md
Normal file
@@ -0,0 +1,213 @@
|
||||
# 맵별 고정 카메라 (런타임 설정) Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 맵 로드 시 플레이어 카메라를 `data/camera.json`의 고정 framing(현재 map01 값)으로 설정하는 `MapCamera` 스크립트를 11맵에 부착.
|
||||
|
||||
**Architecture:** 새 CameraComponent를 만들지 않고(엔진 소유), `MapCamera.codeblock`이 OnBeginPlay에서 플레이어의 기존 CameraComponent 속성(ZoomRatio·ScreenOffset·ConfineCameraArea)을 설정. `gen-camera.mjs`가 codeblock 생성 + 11맵 루트에 `script.MapCamera` 부착(idempotent).
|
||||
|
||||
**Tech Stack:** Node.js ESM 생성기, MSW Lua codeblock/map JSON. 검증은 node --check+재생성+JSON유효+결정성+메이커 Play(카메라 적용 확인).
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
- Create: `data/camera.json` — 카메라 framing 값.
|
||||
- Create: `tools/gen-camera.mjs` — MapCamera.codeblock 생성 + 11맵 루트에 script.MapCamera 부착(idempotent).
|
||||
- 생성물: `RootDesk/MyDesk/MapCamera.codeblock`, `map/map01.map`~`map11.map`(패치).
|
||||
|
||||
검증: MSW Lua 단위테스트 불가 → 생성기 문법·JSON유효·결정성·idempotency·메이커 Play.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: data/camera.json + gen-camera.mjs (codeblock 생성)
|
||||
|
||||
**Files:** Create `data/camera.json`, `tools/gen-camera.mjs`
|
||||
|
||||
- [ ] **Step 1: `data/camera.json`** (현재 map01 추출값)
|
||||
|
||||
```json
|
||||
{
|
||||
"zoomRatio": 100,
|
||||
"screenOffsetX": 0.5,
|
||||
"screenOffsetY": 0.655,
|
||||
"confineCameraArea": true
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: `tools/gen-camera.mjs` 작성 — codeblock 생성 부분**
|
||||
|
||||
```js
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
|
||||
const CAM = JSON.parse(readFileSync('data/camera.json', 'utf8'));
|
||||
const MAP_NUMBERS = Array.from({ length: 11 }, (_, i) => i + 1); // map01~11
|
||||
|
||||
function method(Name, Code, Arguments = [], ExecSpace = 1) {
|
||||
return {
|
||||
Return: { Type: 'void', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: null },
|
||||
Arguments, Code, Scope: 2, ExecSpace, Attributes: [], Name,
|
||||
};
|
||||
}
|
||||
function prop(Type, Name, DefaultValue = 'nil') {
|
||||
return { Type, DefaultValue, SyncDirection: 0, Attributes: [], Name };
|
||||
}
|
||||
|
||||
function writeCodeblock() {
|
||||
const cb = {
|
||||
Id: '', GameId: '', EntryKey: 'codeblock://mapcamera', ContentType: 'x-mod/codeblock',
|
||||
Content: '', Usage: 0, UsePublish: 1, UseService: 0, CoreVersion: '26.5.0.0',
|
||||
StudioVersion: '', DynamicLoading: 0,
|
||||
ContentProto: { Use: 'Json', Json: {
|
||||
CoreVersion: { Major: 0, Minor: 2 }, ScriptVersion: { Major: 1, Minor: 0 },
|
||||
Description: '', Id: 'MapCamera', Language: 1, Name: 'MapCamera', Type: 1, Source: 0, Target: null,
|
||||
Properties: [ prop('number', 'CamTries', '0') ],
|
||||
Methods: [
|
||||
method('OnBeginPlay', `self.CamTries = 0
|
||||
local eventId = 0
|
||||
local function apply()
|
||||
self.CamTries = self.CamTries + 1
|
||||
local cam = nil
|
||||
local lp = _UserService.LocalPlayer
|
||||
if lp ~= nil then
|
||||
cam = lp.CameraComponent
|
||||
end
|
||||
if cam == nil then
|
||||
cam = _CameraService:GetCurrentCameraComponent()
|
||||
end
|
||||
if cam ~= nil then
|
||||
cam.ZoomRatio = ${CAM.zoomRatio}
|
||||
cam.ScreenOffset = Vector2(${CAM.screenOffsetX}, ${CAM.screenOffsetY})
|
||||
cam.ConfineCameraArea = ${CAM.confineCameraArea}
|
||||
_TimerService:ClearTimer(eventId)
|
||||
elseif self.CamTries > 30 then
|
||||
_TimerService:ClearTimer(eventId)
|
||||
end
|
||||
end
|
||||
eventId = _TimerService:SetTimerRepeat(apply, 0.1)`),
|
||||
],
|
||||
EntityEventHandlers: [],
|
||||
} },
|
||||
};
|
||||
writeFileSync('RootDesk/MyDesk/MapCamera.codeblock', JSON.stringify(cb, null, 2), 'utf8');
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 문법 검사 (맵 패치 전, codeblock만)** — 임시로 `writeCodeblock(); console.log('cb ok');` 호출 추가 후:
|
||||
|
||||
Run: `node --check tools/gen-camera.mjs`
|
||||
Expected: 오류 없음
|
||||
|
||||
- [ ] **Step 4: 커밋**
|
||||
|
||||
```bash
|
||||
git add data/camera.json tools/gen-camera.mjs
|
||||
git commit -m "gen-camera(map-camera): camera.json + MapCamera.codeblock 생성기"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: gen-camera.mjs — 11맵 루트에 script.MapCamera 부착
|
||||
|
||||
**Files:** Modify `tools/gen-camera.mjs`
|
||||
|
||||
- [ ] **Step 1: 맵 패치 함수 + 실행부 추가** (Step 2의 writeCodeblock 임시 호출은 제거)
|
||||
|
||||
```js
|
||||
function patchMap(nn) {
|
||||
const tag = String(nn).padStart(2, '0');
|
||||
const file = `map/map${tag}.map`;
|
||||
const map = JSON.parse(readFileSync(file, 'utf8'));
|
||||
const root = map.ContentProto.Entities.find((e) => e.path === `/maps/map${tag}`);
|
||||
if (!root) throw new Error(`[gen-camera] 맵 루트 없음: ${file}`);
|
||||
const comps = root.jsonString['@components'];
|
||||
// idempotent: 기존 script.MapCamera 제거 후 재추가
|
||||
root.jsonString['@components'] = comps.filter((c) => c['@type'] !== 'script.MapCamera');
|
||||
root.jsonString['@components'].push({ '@type': 'script.MapCamera', Enable: true });
|
||||
const names = (root.componentNames || '').split(',').filter((s) => s && s !== 'script.MapCamera');
|
||||
names.push('script.MapCamera');
|
||||
root.componentNames = names.join(',');
|
||||
writeFileSync(file, JSON.stringify(map, null, 2), 'utf8');
|
||||
return `map${tag}`;
|
||||
}
|
||||
|
||||
writeCodeblock();
|
||||
const patched = MAP_NUMBERS.map(patchMap);
|
||||
console.log('MapCamera codeblock written; patched maps:', patched.join(', '));
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 문법 검사**
|
||||
|
||||
Run: `node --check tools/gen-camera.mjs`
|
||||
Expected: 오류 없음
|
||||
|
||||
- [ ] **Step 3: 커밋**
|
||||
|
||||
```bash
|
||||
git add tools/gen-camera.mjs
|
||||
git commit -m "gen-camera(map-camera): 11맵 루트에 script.MapCamera 부착(idempotent)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 실행 + 정적 검증
|
||||
|
||||
**Files:** 생성물
|
||||
|
||||
- [ ] **Step 1: 생성기 실행**
|
||||
|
||||
Run: `node tools/gen-camera.mjs`
|
||||
Expected: `MapCamera codeblock written; patched maps: map01, ..., map11`
|
||||
|
||||
- [ ] **Step 2: codeblock·부착 확인**
|
||||
|
||||
Run: `node -e "const c=JSON.parse(require('fs').readFileSync('RootDesk/MyDesk/MapCamera.codeblock','utf8')); console.log(c.ContentProto.Json.Id==='MapCamera'&&/ScreenOffset = Vector2\(0.5, 0.655\)/.test(c.ContentProto.Json.Methods[0].Code)?'CB OK':'CB BAD'); for(const nn of [1,6,11]){const tag=String(nn).padStart(2,'0'); const m=JSON.parse(require('fs').readFileSync('map/map'+tag+'.map','utf8')); const r=m.ContentProto.Entities.find(e=>e.path==='/maps/map'+tag); const has=r.componentNames.includes('script.MapCamera')&&r.jsonString['@components'].some(x=>x['@type']==='script.MapCamera'); console.log('map'+tag, has?'ATTACHED':'MISSING');}"`
|
||||
Expected: `CB OK`, `map01 ATTACHED`, `map06 ATTACHED`, `map11 ATTACHED`
|
||||
|
||||
- [ ] **Step 3: idempotency (2회 실행 시 중복 부착 없음)**
|
||||
|
||||
Run: `node tools/gen-camera.mjs >/dev/null && node -e "const m=JSON.parse(require('fs').readFileSync('map/map01.map','utf8')); const r=m.ContentProto.Entities.find(e=>e.path==='/maps/map01'); const n=(r.componentNames.match(/script.MapCamera/g)||[]).length; const c=r.jsonString['@components'].filter(x=>x['@type']==='script.MapCamera').length; console.log('componentNames 횟수='+n+' @components 횟수='+c+(n===1&&c===1?' IDEMPOTENT OK':' DUP!'))"`
|
||||
Expected: `IDEMPOTENT OK`
|
||||
|
||||
- [ ] **Step 4: JSON 유효 + 결정성**
|
||||
|
||||
Run: `for f in map/map*.map; do node -e "JSON.parse(require('fs').readFileSync('$f','utf8'))" || echo "BAD $f"; done; node tools/gen-camera.mjs >/dev/null && sha1sum map/map01.map RootDesk/MyDesk/MapCamera.codeblock > /tmp/a.sha && node tools/gen-camera.mjs >/dev/null && sha1sum map/map01.map RootDesk/MyDesk/MapCamera.codeblock > /tmp/b.sha && diff /tmp/a.sha /tmp/b.sha && echo DETERMINISTIC`
|
||||
Expected: BAD 없음, `DETERMINISTIC`
|
||||
|
||||
- [ ] **Step 5: git status**
|
||||
|
||||
Run: `git status --short`
|
||||
Expected: `map/map01~11.map`, `RootDesk/MyDesk/MapCamera.codeblock`, `data/camera.json`, `tools/gen-camera.mjs` (+docs). map02~11은 freeze/카메라로 변경될 수 있음.
|
||||
|
||||
- [ ] **Step 6: 생성물 커밋**
|
||||
|
||||
```bash
|
||||
git add map/*.map RootDesk/MyDesk/MapCamera.codeblock
|
||||
git commit -m "재생성(map-camera): MapCamera codeblock + 11맵 부착 반영"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 메이커 Play 런타임 검증 (ExecSpace 확정)
|
||||
|
||||
**Files:** 없음 (런타임 검증; 필요 시 ExecSpace 조정)
|
||||
|
||||
- [ ] **Step 1: reload → Play → map01 카메라 적용 확인**
|
||||
|
||||
메이커 reload 후 Play. `maker_execute_script`(client)로 현재 카메라 값 확인:
|
||||
```lua
|
||||
local cam = _CameraService:GetCurrentCameraComponent()
|
||||
log("Zoom=" .. tostring(cam.ZoomRatio) .. " SO=(" .. tostring(cam.ScreenOffset.x) .. "," .. tostring(cam.ScreenOffset.y) .. ") Confine=" .. tostring(cam.ConfineCameraArea))
|
||||
```
|
||||
Expected: Zoom 100·SO(0.5,0.655)·Confine true (MapCamera가 적용한 값).
|
||||
|
||||
- [ ] **Step 2: ExecSpace 검증/조정** — 만약 카메라 값이 적용 안 되면(스크립트가 클라에서 안 돎), `gen-camera.mjs`의 `method()` 기본 `ExecSpace`를 1↔6 등으로 바꿔 재생성·재확인. (gen-slaydeck는 6으로 클라 동작 확인됨, Monster는 클라 메서드 1.) 적용되는 값으로 확정.
|
||||
|
||||
- [ ] **Step 3: (선택) framing 변경 반영 확인** — `data/camera.json`의 zoomRatio를 70으로 임시 변경 → 재생성 → Play에서 Zoom 70 확인 → 원복(`git checkout -- data/camera.json` + 재생성).
|
||||
|
||||
---
|
||||
|
||||
## Self-Review
|
||||
- **Spec coverage:** camera.json·codeblock(Task1), 11맵 부착(Task2), 정적검증·idempotency(Task3), 런타임·ExecSpace(Task4). 스펙 항목 매핑.
|
||||
- **Placeholder scan:** 실제 코드/명령 포함. (Task4 ExecSpace 조정은 런타임 결과 의존 — 의도된 검증 분기.)
|
||||
- **Type consistency:** `writeCodeblock`/`patchMap`/`method`/`prop` 일관. codeblock Id 'MapCamera' ↔ componentName `script.MapCamera` ↔ EntryKey `codeblock://mapcamera` 일치. camera.json 필드(zoomRatio/screenOffsetX/Y/confineCameraArea)가 codeblock 생성에서 사용됨.
|
||||
- **리스크:** 맵 루트 스크립트의 client OnBeginPlay 실행/ExecSpace는 런타임 검증으로 확정(Task4). LocalPlayer.CameraComponent 타이밍은 재시도 타이머로 흡수.
|
||||
1064
docs/superpowers/plans/2026-06-10-map-monster-combat.md
Normal file
1064
docs/superpowers/plans/2026-06-10-map-monster-combat.md
Normal file
File diff suppressed because it is too large
Load Diff
361
docs/superpowers/plans/2026-06-10-node-type-monster-groups.md
Normal file
361
docs/superpowers/plans/2026-06-10-node-type-monster-groups.md
Normal file
@@ -0,0 +1,361 @@
|
||||
# 노드 타입별 몬스터 그룹 구현 계획
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 한 맵에서 노드 타입(combat/elite/boss)에 따라 해당 그룹의 몬스터만 등장시킨다.
|
||||
|
||||
**Architecture:** 각 맵 몬스터의 `script.CombatMonster`에 `Group` 태그를 두고, 전투 시작 시 `BuildMonsters`가 현재 노드 타입으로 필터해 일치 그룹만 표시·전투 구성한다. HP바 슬롯 좌표는 `data/monster-slots.json`에 그룹별로 둔다. Group/EnemyId는 메이커 인스펙터에서 저작하므로 생성기는 값을 덮어쓰지 않는다.
|
||||
|
||||
**Tech Stack:** Node.js ESM 생성기(.mjs), MSW Lua codeblock, JSON(.codeblock/.map/data).
|
||||
|
||||
---
|
||||
|
||||
## 배경 / 현재 코드 (구현자용)
|
||||
|
||||
- 생성물(`SlayDeckController.codeblock`·`ui/DefaultGroup.ui`·`common.gamelogic`)은 `tools/deck/gen-slaydeck.mjs`에서만, `CombatMonster.codeblock`+맵 패치는 `tools/monster/gen-combat-monster.mjs`에서만 생성한다(직접 편집 금지). 루트에서 `node tools/<폴더>/<파일>.mjs` 실행.
|
||||
- 현재 `BuildMonsters`는 등록된 몬스터를 노드 타입과 무관하게 전부 사용. 노드 타입은 `self.MapNodes[self.CurrentNodeId].type`로 접근(combat/elite/boss).
|
||||
- 현재 `data/monster-slots.json`은 평면 배열 `[{x,y}×4]`. `MAX_MONSTERS = 4`(gen-slaydeck.mjs 상수).
|
||||
- 전투 규칙(타겟/공격/적턴/승리)은 이 기능에서 **변경하지 않는다**. 따라서 sim/테스트 변경 없음(회귀만 확인).
|
||||
|
||||
## 파일 구조
|
||||
|
||||
| 파일 | 책임 | 변경 |
|
||||
|------|------|------|
|
||||
| `data/monster-slots.json` | 그룹별 HP바 슬롯 좌표 | 평면 배열 → `{combat,elite,boss}` 객체 |
|
||||
| `tools/monster/gen-combat-monster.mjs` | CombatMonster 코드블록 + 맵 부착 | Group 프로퍼티·등록 인자 추가, 부착을 **값 보존(no-clobber)**로 변경 |
|
||||
| `RootDesk/MyDesk/CombatMonster.codeblock` | 생성물 | Group 프로퍼티·register(group) |
|
||||
| `tools/deck/gen-slaydeck.mjs` | 컨트롤러 생성 | SLOTS 객체 처리·StartRun 그룹별 주입·`ActiveSlotPos`·`PositionMonsterSlot`·`RegisterMonster(group)`·`BuildMonsters` 필터 |
|
||||
| 생성물 | `SlayDeckController.codeblock` 재생성 | (ui 변경 없음) |
|
||||
| `map/map01.map` 외 | 몬스터 그룹 태그 | 메이커 저작(코드 외) |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: monster-slots.json 그룹별 구조
|
||||
|
||||
**Files:** Modify `data/monster-slots.json`
|
||||
|
||||
- [ ] **Step 1: 그룹별 좌표 객체로 교체**
|
||||
|
||||
`data/monster-slots.json` 전체를 아래로 교체(각 그룹 4좌표; 추후 플레이테스트로 튜닝):
|
||||
```json
|
||||
{
|
||||
"combat": [
|
||||
{ "x": 430, "y": 140 },
|
||||
{ "x": 600, "y": 140 },
|
||||
{ "x": 770, "y": 140 },
|
||||
{ "x": 900, "y": 140 }
|
||||
],
|
||||
"elite": [
|
||||
{ "x": 430, "y": 160 },
|
||||
{ "x": 650, "y": 160 },
|
||||
{ "x": 850, "y": 160 },
|
||||
{ "x": 980, "y": 160 }
|
||||
],
|
||||
"boss": [
|
||||
{ "x": 520, "y": 200 },
|
||||
{ "x": 760, "y": 160 },
|
||||
{ "x": 940, "y": 150 },
|
||||
{ "x": 1040, "y": 150 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: JSON 유효성 확인**
|
||||
|
||||
Run: `node -e "const s=JSON.parse(require('fs').readFileSync('data/monster-slots.json','utf8'));console.log(['combat','elite','boss'].map(g=>g+':'+s[g].length).join(' '))"`
|
||||
Expected: `combat:4 elite:4 boss:4`
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
```bash
|
||||
git add data/monster-slots.json
|
||||
git commit -m "feat(node-groups): monster-slots.json 을 그룹별 좌표 구조로"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: CombatMonster 에 Group + 생성기 no-clobber
|
||||
|
||||
**Files:** Modify `tools/monster/gen-combat-monster.mjs` (생성물 `RootDesk/MyDesk/CombatMonster.codeblock`, `map/*.map`)
|
||||
|
||||
- [ ] **Step 1: 코드블록에 Group 프로퍼티 추가**
|
||||
|
||||
`tools/monster/gen-combat-monster.mjs`의 `Properties` 줄을 교체:
|
||||
```js
|
||||
Properties: [prop('string', 'EnemyId', '""'), prop('string', 'Group', '"combat"'), prop('number', 'RegTries', '0')],
|
||||
```
|
||||
|
||||
- [ ] **Step 2: OnBeginPlay 등록 호출에 Group 전달**
|
||||
|
||||
`OnBeginPlay` Lua의 등록 줄을 교체:
|
||||
```
|
||||
c.SlayDeckController:RegisterMonster(self.Entity, self.EnemyId, self.Group)
|
||||
```
|
||||
(나머지 OnBeginPlay 본문은 그대로)
|
||||
|
||||
- [ ] **Step 3: patchMap 을 값 보존(no-clobber)로 교체**
|
||||
|
||||
`patchMap` 함수 전체를 아래로 교체. 기존 `script.CombatMonster`가 있으면 사용자가 인스펙터에서 설정한 `EnemyId`/`Group`을 보존하고, 없을 때만 기본값으로 부착한다:
|
||||
```js
|
||||
function patchMap(nn) {
|
||||
const tag = String(nn).padStart(2, '0');
|
||||
const file = `map/map${tag}.map`;
|
||||
const map = JSON.parse(readFileSync(file, 'utf8'));
|
||||
let added = 0, kept = 0;
|
||||
for (const e of map.ContentProto.Entities.filter(isMonster)) {
|
||||
const comps = e.jsonString && e.jsonString['@components'];
|
||||
if (!Array.isArray(comps)) {
|
||||
console.warn(`[gen-combat-monster] entity "${(e.jsonString && e.jsonString.name) || e.path}" has no @components — skipped`);
|
||||
continue;
|
||||
}
|
||||
const name = (e.jsonString && e.jsonString.name) || '';
|
||||
const existing = comps.find((c) => c['@type'] === 'script.CombatMonster');
|
||||
if (existing) {
|
||||
// 사용자가 메이커에서 설정한 값 보존 — 누락된 키만 기본값 채움
|
||||
if (existing.Enable === undefined) existing.Enable = true;
|
||||
if (existing.EnemyId === undefined) existing.EnemyId = NAME_TO_ENEMY[name] || DEFAULT_ENEMY;
|
||||
if (existing.Group === undefined) existing.Group = 'combat';
|
||||
kept++;
|
||||
} else {
|
||||
comps.push({ '@type': 'script.CombatMonster', Enable: true, EnemyId: NAME_TO_ENEMY[name] || DEFAULT_ENEMY, Group: 'combat' });
|
||||
added++;
|
||||
}
|
||||
const names = (e.componentNames || '').split(',').filter((s) => s && s !== 'script.CombatMonster');
|
||||
names.push('script.CombatMonster');
|
||||
e.componentNames = names.join(',');
|
||||
}
|
||||
writeFileSync(file, JSON.stringify(map, null, 2), 'utf8');
|
||||
return `map${tag}(+${added}/keep${kept})`;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 실행 + 값 보존 검증**
|
||||
|
||||
Run: `node tools/monster/gen-combat-monster.mjs`
|
||||
Expected: `... patched maps: map01(+0/keep3), map02(+0/keep2), ...` (기존 몬스터는 이미 CombatMonster 보유 → keep, EnemyId 보존 + Group 기본값 주입).
|
||||
|
||||
Run: `node -e "const m=JSON.parse(require('fs').readFileSync('map/map01.map','utf8'));const ms=m.ContentProto.Entities.filter(e=>(e.componentNames||'').includes('script.CombatMonster'));console.log(ms.map(e=>{const c=e.jsonString['@components'].find(x=>x['@type']==='script.CombatMonster');return e.jsonString.name+':'+c.EnemyId+'/'+c.Group;}).join(', '))"`
|
||||
Expected: 각 몬스터 `이름:EnemyId/combat` (기존 EnemyId 보존, Group=combat 주입).
|
||||
|
||||
- [ ] **Step 5: 멱등 + 코드블록 Group 확인**
|
||||
|
||||
Run: `node tools/monster/gen-combat-monster.mjs` (2회차) — map 재실행에도 값 동일(no-clobber).
|
||||
Run: `node -e "const c=JSON.parse(require('fs').readFileSync('RootDesk/MyDesk/CombatMonster.codeblock','utf8'));const p=c.ContentProto.Json.Properties.map(x=>x.Name);console.log('props:',p.join(','),'| register has Group:',/RegisterMonster\(self.Entity, self.EnemyId, self.Group\)/.test(c.ContentProto.Json.Methods[0].Code))"`
|
||||
Expected: `props: EnemyId,Group,RegTries | register has Group: true`
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
```bash
|
||||
git add tools/monster/gen-combat-monster.mjs RootDesk/MyDesk/CombatMonster.codeblock map/
|
||||
git commit -m "feat(node-groups): CombatMonster 에 Group + 생성기 값 보존(no-clobber)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: gen-slaydeck — SLOTS 객체 플러밍
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`. **생성기는 Task 5까지 실행 금지**, `node --check`만.
|
||||
|
||||
- [ ] **Step 1: upsertUi 슬롯 단언 교체**
|
||||
|
||||
`upsertUi()` 시작부의 단언을 SLOTS 객체용으로 교체:
|
||||
```js
|
||||
for (const g of ['combat', 'elite', 'boss']) {
|
||||
if (!Array.isArray(SLOTS[g]) || SLOTS[g].length < 1) {
|
||||
throw new Error(`[gen-slaydeck] monster-slots.json 의 "${g}" 그룹 좌표가 없습니다`);
|
||||
}
|
||||
}
|
||||
```
|
||||
(기존 `if (SLOTS.length < MAX_MONSTERS) { throw ... }` 블록을 위 코드로 대체)
|
||||
|
||||
- [ ] **Step 2: StartRun 의 SlotPos 주입을 그룹별로 교체**
|
||||
|
||||
`StartRun` Lua의 다음 줄
|
||||
```
|
||||
self.SlotPos = { ${SLOTS.map((s) => `{ x = ${s.x}, y = ${s.y} }`).join(', ')} }
|
||||
```
|
||||
을 아래 헬퍼 기반 그룹별 주입으로 교체. 파일 상단(다른 헬퍼 함수 근처)에 헬퍼 추가:
|
||||
```js
|
||||
function luaSlotGroup(arr) {
|
||||
return '{ ' + arr.map((s) => `{ x = ${s.x}, y = ${s.y} }`).join(', ') + ' }';
|
||||
}
|
||||
```
|
||||
그리고 StartRun 주입 줄을:
|
||||
```js
|
||||
self.SlotPos = { combat = ${luaSlotGroup(SLOTS.combat)}, elite = ${luaSlotGroup(SLOTS.elite)}, boss = ${luaSlotGroup(SLOTS.boss)} }
|
||||
```
|
||||
|
||||
- [ ] **Step 3: ActiveSlotPos 프로퍼티 추가**
|
||||
|
||||
prop 목록에서 `prop('any', 'SlotPos'),` 다음 줄에 추가:
|
||||
```js
|
||||
prop('any', 'ActiveSlotPos'),
|
||||
```
|
||||
|
||||
- [ ] **Step 4: PositionMonsterSlot 이 ActiveSlotPos 를 쓰도록 교체**
|
||||
|
||||
`PositionMonsterSlot` 메서드 본문 첫 줄 `local sp = self.SlotPos` 를 교체:
|
||||
```
|
||||
local sp = self.ActiveSlotPos
|
||||
```
|
||||
(나머지 본문 동일 — `sp[slot]` 사용)
|
||||
|
||||
- [ ] **Step 5: 구문 점검**
|
||||
|
||||
Run: `node --check tools/deck/gen-slaydeck.mjs` → 출력 없음(유효).
|
||||
Run: `node -e "const s=require('fs').readFileSync('tools/deck/gen-slaydeck.mjs','utf8');console.log('luaSlotGroup:',s.includes('function luaSlotGroup'),'| ActiveSlotPos prop:',s.includes(\"'ActiveSlotPos'\"),'| SlotPos combat=:',s.includes('combat = '))"`
|
||||
Expected: 모두 true.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
```bash
|
||||
git add tools/deck/gen-slaydeck.mjs
|
||||
git commit -m "feat(node-groups): 그룹별 슬롯 좌표 플러밍 (SlotPos/ActiveSlotPos)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: gen-slaydeck — RegisterMonster(group) + BuildMonsters 필터
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`. 생성기 실행 금지, `node --check`만.
|
||||
|
||||
- [ ] **Step 1: RegisterMonster 에 group 인자 추가**
|
||||
|
||||
기존
|
||||
```js
|
||||
method('RegisterMonster', `if self.Registered == nil then
|
||||
self.Registered = {}
|
||||
end
|
||||
table.insert(self.Registered, { entity = monster, enemyId = enemyId })`, [
|
||||
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'monster' },
|
||||
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'enemyId' },
|
||||
]),
|
||||
```
|
||||
를 아래로 교체:
|
||||
```js
|
||||
method('RegisterMonster', `if self.Registered == nil then
|
||||
self.Registered = {}
|
||||
end
|
||||
local g = group
|
||||
if g == nil or g == "" then g = "combat" end
|
||||
table.insert(self.Registered, { entity = monster, enemyId = enemyId, group = g })`, [
|
||||
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'monster' },
|
||||
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'enemyId' },
|
||||
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'group' },
|
||||
]),
|
||||
```
|
||||
|
||||
- [ ] **Step 2: BuildMonsters 를 노드 타입 필터로 교체**
|
||||
|
||||
`BuildMonsters` 메서드 전체를 아래로 교체(현재 노드 타입으로 그룹 결정, 전체 숨김 후 일치 그룹만 표시, 그룹 슬롯 좌표 사용). `${MAX_MONSTERS}`는 JS 상수 보간:
|
||||
```js
|
||||
method('BuildMonsters', `self.Monsters = {}
|
||||
local g = "combat"
|
||||
local node = self.MapNodes[self.CurrentNodeId]
|
||||
if node ~= nil and node.type ~= nil then g = node.type end
|
||||
self.ActiveSlotPos = self.SlotPos[g]
|
||||
local reg = self.Registered or {}
|
||||
-- 모든 등록 몬스터 숨김
|
||||
for i = 1, #reg do
|
||||
if reg[i].entity ~= nil and isvalid(reg[i].entity) then
|
||||
reg[i].entity:SetVisible(false)
|
||||
end
|
||||
end
|
||||
-- 현재 그룹만 추려 월드 x 정렬
|
||||
local list = {}
|
||||
for i = 1, #reg do
|
||||
local r = reg[i]
|
||||
if r.entity ~= nil and isvalid(r.entity) and r.group == g then
|
||||
local x = 0
|
||||
if r.entity.TransformComponent ~= nil then
|
||||
x = r.entity.TransformComponent.WorldPosition.x
|
||||
end
|
||||
table.insert(list, { entity = r.entity, enemyId = r.enemyId, x = x })
|
||||
end
|
||||
end
|
||||
table.sort(list, function(a, b) return a.x < b.x end)
|
||||
local mult = 1 + (self.Floor - 1) * 0.6
|
||||
local n = #list
|
||||
if n > ${MAX_MONSTERS} then n = ${MAX_MONSTERS} end
|
||||
for i = 1, n do
|
||||
local item = list[i]
|
||||
local e = self.Enemies[item.enemyId]
|
||||
if e == nil then e = { name = item.enemyId, maxHp = 10, intents = { { kind = "Attack", value = 5 } } } end
|
||||
local intents = {}
|
||||
for k = 1, #e.intents do
|
||||
intents[k] = { kind = e.intents[k].kind, value = math.floor(e.intents[k].value * mult) }
|
||||
end
|
||||
local maxHp = math.floor(e.maxHp * mult)
|
||||
self.Monsters[i] = { entity = item.entity, enemyId = item.enemyId, name = e.name,
|
||||
hp = maxHp, maxHp = maxHp, block = 0, intents = intents, intentIdx = 1, alive = true, slot = i }
|
||||
self:ReviveMonsterEntity(item.entity)
|
||||
self:PositionMonsterSlot(i)
|
||||
end
|
||||
self.TargetIndex = 1`),
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 구문 점검 + 필터 반영 확인**
|
||||
|
||||
Run: `node --check tools/deck/gen-slaydeck.mjs` → 유효.
|
||||
Run: `node -e "const s=require('fs').readFileSync('tools/deck/gen-slaydeck.mjs','utf8');const i=s.indexOf(\"'BuildMonsters'\");const seg=s.slice(i,i+1200);console.log('node.type group:',seg.includes('node.type'),'| group filter:',seg.includes('r.group == g'),'| hide all:',seg.includes('SetVisible(false)'),'| ActiveSlotPos:',seg.includes('self.ActiveSlotPos = self.SlotPos[g]'));console.log('RegisterMonster 3 args:',/RegisterMonster[\\s\\S]{0,400}Name: 'group'/.test(s));"`
|
||||
Expected: 모두 true.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
```bash
|
||||
git add tools/deck/gen-slaydeck.mjs
|
||||
git commit -m "feat(node-groups): RegisterMonster(group) + BuildMonsters 노드 타입 필터"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 재생성 · 검증 · 플레이테스트
|
||||
|
||||
**Files:** 산출 `SlayDeckController.codeblock` 등
|
||||
|
||||
- [ ] **Step 1: 생성기 재실행**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
node tools/monster/gen-combat-monster.mjs
|
||||
node tools/deck/gen-slaydeck.mjs
|
||||
```
|
||||
Expected: 둘 다 에러 없이 완료.
|
||||
|
||||
- [ ] **Step 2: 산출물 검증**
|
||||
|
||||
Run: `node -e "const fs=require('fs');for(const f of ['ui/DefaultGroup.ui','Global/common.gamelogic','RootDesk/MyDesk/SlayDeckController.codeblock'])JSON.parse(fs.readFileSync(f,'utf8'));const c=JSON.parse(fs.readFileSync('RootDesk/MyDesk/SlayDeckController.codeblock','utf8'));const sc=JSON.stringify(c);console.log('SlotPos combat/elite/boss:',sc.includes('combat = {')&&sc.includes('elite = {')&&sc.includes('boss = {'),'| group filter:',sc.includes('r.group == g'));"`
|
||||
Expected: `SlotPos combat/elite/boss: true | group filter: true`
|
||||
|
||||
- [ ] **Step 3: 결정성**
|
||||
|
||||
Run: `git add -A && node tools/deck/gen-slaydeck.mjs && git diff --stat RootDesk/MyDesk/SlayDeckController.codeblock ui/DefaultGroup.ui Global/common.gamelogic`
|
||||
Expected: 비어 있음(결정적).
|
||||
|
||||
- [ ] **Step 4: sim 회귀**
|
||||
|
||||
Run: `node --test tools/balance/sim-balance.test.mjs`
|
||||
Expected: 전체 통과(규칙 불변).
|
||||
|
||||
- [ ] **Step 5: Commit (산출물)**
|
||||
```bash
|
||||
git add RootDesk/MyDesk/SlayDeckController.codeblock
|
||||
git commit -m "feat(node-groups): 컨트롤러 재생성 (그룹 필터·그룹 슬롯)"
|
||||
```
|
||||
|
||||
- [ ] **Step 6: 메이커 플레이테스트 (수동/MCP)**
|
||||
|
||||
먼저 map01에 그룹을 저작(메이커): 일반/엘리트/보스 몬스터를 배치하고 각 `CombatMonster`의 Group(combat/elite/boss)·EnemyId 지정. (또는 검증 목적이면 기존 3마리에 Group을 각각 combat/elite/boss로 임시 지정.)
|
||||
그 후 reload→Play 확인:
|
||||
1. combat 노드 진입 → Group=combat 몬스터만 표시, 나머지 숨김.
|
||||
2. elite 노드 → 엘리트(+졸개) 그룹만.
|
||||
3. boss 노드 → 보스(+졸개) 그룹만.
|
||||
4. 각 그룹 슬롯(HP바·의도)이 해당 몬스터 위에 표시(좌표 안 맞으면 `data/monster-slots.json` 그룹 좌표 튜닝 → 재생성 → reload).
|
||||
5. 전투/타겟/승리 흐름 정상.
|
||||
|
||||
> MCP 검증 보조: `execute_script`로 `RegisterMonster` 후 `self.Registered[i].group` 확인, `CurrentNodeId`를 각 타입 노드로 두고 `BuildMonsters()` 호출 → `self.Monsters` 가 해당 그룹만 담는지 로그.
|
||||
|
||||
---
|
||||
|
||||
## Self-Review 결과 (작성자 점검)
|
||||
|
||||
- **스펙 커버리지**: Group 태그(Task2), 그룹별 슬롯 좌표(Task1·3), no-clobber 저작(Task2), RegisterMonster(group)(Task2·4), BuildMonsters 노드 타입 필터·전체 숨김·그룹 슬롯(Task4), 재생성·검증(Task5) — 전부 매핑됨. sim 불변(Task5 회귀).
|
||||
- **플레이스홀더**: 슬롯 좌표는 초기값+튜닝 명시. 코드 단계는 실제 코드 포함. 메이커 그룹 저작은 코드 외 수동 단계로 명시.
|
||||
- **타입/이름 일관성**: `Group`(string), `RegisterMonster(monster, enemyId, group)`, `Registered{entity,enemyId,group}`, `ActiveSlotPos`, `SlotPos.{combat,elite,boss}`, `BuildMonsters`의 `g = node.type` — Task 간 일치. `MAX_MONSTERS` 보간 유지.
|
||||
- **리스크**: 그룹 좌표 수 < 몬스터 수면 초과 슬롯 미배치(기본 4좌표로 완화). 비combat/rest 노드만 StartCombat 호출되므로 g∈{combat,elite,boss}. MSW 월드 API는 기존과 동일(검증됨).
|
||||
160
docs/superpowers/plans/2026-06-11-act-maps.md
Normal file
160
docs/superpowers/plans/2026-06-11-act-maps.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# 막별 맵 전환 + 맵별 인카운터 (P4) 구현 계획
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development. T3·T4는 컨트롤러 직접.
|
||||
|
||||
**Goal:** 보스 클리어 시 다음 막의 맵(map02, map03)으로 텔레포트하고, 각 맵에 테마 몬스터 그룹(combat3/elite2/boss1)을 자동 구성.
|
||||
|
||||
**Architecture:** 신규 `tools/map/gen-map-encounters.mjs`가 map02~11 몬스터를 전면 교체(결정론). 컨트롤러는 `RegisterMonster`에 mapName 차원 추가 + `BuildMonsters` 플레이어 맵 필터 + 보스 클리어 시 `TeleportToActMap`.
|
||||
|
||||
---
|
||||
|
||||
## 배경 (구현자용)
|
||||
- 생성물은 단일 소스 규칙(gen-slaydeck → ui/codeblock/common). 맵 파일은 전용 생성기가 직접 패치. 산출물(slaydeck 3종)은 마지막에 일괄, **맵 파일은 T1에서 바로 커밋**.
|
||||
- 현재 `RegisterMonster(monster, enemyId, group)`(3인자), `BuildMonsters`는 `r.group == g` 필터. `CombatMonster.codeblock`은 `tools/monster/gen-combat-monster.mjs`가 생성(OnBeginPlay에서 3인자 등록).
|
||||
- gen-maps의 `MONSTER_VARIANTS` 9종(sprite/stand/hit/die RUID)과 `mapGuid(nn, idx)`·`rng(seed)` 패턴 참조: `tools/map/gen-maps.mjs`.
|
||||
- CheckCombatEnd 보스 분기: `self.Floor = self.Floor + 1 ... self:ShowMap()`.
|
||||
- JS 상수: writeCodeblocks 안 `ACT_COUNT = 3` 존재.
|
||||
|
||||
## Task 1: gen-map-encounters.mjs (map02~11 인카운터)
|
||||
|
||||
**Files:** Create `tools/map/gen-map-encounters.mjs`; Modify(산출) `map/map02.map`~`map11.map`
|
||||
|
||||
- [ ] **Step 1: 생성기 작성.** `tools/map/gen-maps.mjs`를 READ해 `MONSTER_VARIANTS`(9종 배열 — 그대로 복사)·`rng`·`mapGuid` 패턴을 가져와 아래 구조로 작성:
|
||||
```js
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
|
||||
// map02~11에 노드 타입별 몬스터 그룹(combat3/elite2/boss1)을 맵별 테마로 자동 구성.
|
||||
// 기존 몬스터 엔티티를 전부 제거하고 첫 몬스터를 템플릿으로 6마리 재생성(결정론).
|
||||
const MAP_NUMBERS = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
||||
const COMBAT_POOL = ['orange_mushroom', 'green_mushroom', 'pig', 'blue_mushroom'];
|
||||
const ELITE_POOL = ['mushmom', 'modified_snail'];
|
||||
const BOSS_POOL = ['king_slime', 'slime_boss'];
|
||||
const LAYOUT = [
|
||||
{ group: 'combat', x: 2.3 }, { group: 'combat', x: 3.8 }, { group: 'combat', x: 5.2 },
|
||||
{ group: 'elite', x: 3.0 }, { group: 'elite', x: 5.0 },
|
||||
{ group: 'boss', x: 4.0 },
|
||||
];
|
||||
const MONSTER_VARIANTS = [ /* gen-maps.mjs에서 9종 그대로 복사 */ ];
|
||||
|
||||
function rng(seed) { let s = seed >>> 0; return () => { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296; }; }
|
||||
function encGuid(nn, idx) {
|
||||
const n = (nn * 1000 + 500 + idx) >>> 0; // gen-maps의 mapGuid(idx 0~)와 비충돌(+500 오프셋)
|
||||
return `${n.toString(16).padStart(8, '0')}-0000-4000-8000-${n.toString(16).padStart(12, '0')}`;
|
||||
}
|
||||
const isMonster = (e) => typeof e.componentNames === 'string' && e.componentNames.includes('script.Monster');
|
||||
const compOf = (e, t) => e.jsonString['@components'].find((c) => c['@type'] === t);
|
||||
|
||||
function pick(rand, pool) { return pool[Math.floor(rand() * pool.length)]; }
|
||||
function pickN(rand, pool, n) { // 중복 없는 n개(부족하면 순환)
|
||||
const a = pool.slice();
|
||||
const out = [];
|
||||
for (let i = 0; i < n; i++) {
|
||||
if (a.length === 0) a.push(...pool);
|
||||
out.push(a.splice(Math.floor(rand() * a.length), 1)[0]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function patchMap(nn) {
|
||||
const tag = String(nn).padStart(2, '0');
|
||||
const file = `map/map${tag}.map`;
|
||||
const map = JSON.parse(readFileSync(file, 'utf8'));
|
||||
const ents = map.ContentProto.Entities;
|
||||
const monsters = ents.filter(isMonster);
|
||||
if (monsters.length === 0) throw new Error(`[gen-map-encounters] ${file} 몬스터 템플릿 없음`);
|
||||
const template = monsters[0];
|
||||
map.ContentProto.Entities = ents.filter((e) => !isMonster(e));
|
||||
const rand = rng(nn * 7919 + 17);
|
||||
const combatIds = pickN(rand, COMBAT_POOL, 3);
|
||||
const eliteIds = pickN(rand, ELITE_POOL, 2);
|
||||
const bossId = pick(rand, BOSS_POOL);
|
||||
const variants = pickN(rand, MONSTER_VARIANTS, 6);
|
||||
LAYOUT.forEach((slot, idx) => {
|
||||
const m = JSON.parse(JSON.stringify(template));
|
||||
const enemyId = slot.group === 'combat' ? combatIds[idx] : slot.group === 'elite' ? eliteIds[idx - 3] : bossId;
|
||||
const name = `${slot.group}_${idx + 1}`;
|
||||
m.id = encGuid(nn, idx);
|
||||
m.path = `/maps/map${tag}/${name}`;
|
||||
m.jsonString.path = m.path;
|
||||
m.jsonString.name = name;
|
||||
const o = m.jsonString.origin;
|
||||
if (o) { if (o.root_entity_id) o.root_entity_id = m.id; if (o.sub_entity_id) o.sub_entity_id = m.id; }
|
||||
const tr = compOf(m, 'MOD.Core.TransformComponent');
|
||||
if (tr && tr.Position) tr.Position.x = slot.x;
|
||||
const v = variants[idx];
|
||||
const sp = compOf(m, 'MOD.Core.SpriteRendererComponent');
|
||||
if (sp) sp.SpriteRUID = v.stand;
|
||||
const sa = compOf(m, 'MOD.Core.StateAnimationComponent');
|
||||
if (sa) sa.ActionSheet = { stand: v.stand, hit: v.hit, die: v.die };
|
||||
let cm = compOf(m, 'script.CombatMonster');
|
||||
if (!cm) {
|
||||
cm = { '@type': 'script.CombatMonster', Enable: true };
|
||||
m.jsonString['@components'].push(cm);
|
||||
const names = (m.componentNames || '').split(',').filter((s) => s && s !== 'script.CombatMonster');
|
||||
names.push('script.CombatMonster');
|
||||
m.componentNames = names.join(',');
|
||||
}
|
||||
cm.EnemyId = enemyId;
|
||||
cm.Group = slot.group;
|
||||
map.ContentProto.Entities.push(m);
|
||||
});
|
||||
writeFileSync(file, JSON.stringify(map, null, 2), 'utf8');
|
||||
return `map${tag}(${combatIds.join('/')}|${eliteIds.join('/')}|${bossId})`;
|
||||
}
|
||||
|
||||
const made = MAP_NUMBERS.map(patchMap);
|
||||
console.log('Encounters:', made.join(', '));
|
||||
```
|
||||
- [ ] **Step 2:** 실행 + 검증: 각 맵 6마리·그룹 3/2/1·EnemyId 전부 enemies.json 존재·dup guid 0:
|
||||
`node tools/map/gen-map-encounters.mjs && node -e "const en=JSON.parse(require('fs').readFileSync('data/enemies.json','utf8')).enemies;let bad=0;for(let n=2;n<=11;n++){const t=String(n).padStart(2,'0');const m=JSON.parse(require('fs').readFileSync('map/map'+t+'.map','utf8'));const ms=m.ContentProto.Entities.filter(e=>(e.componentNames||'').includes('script.CombatMonster'));const g={combat:0,elite:0,boss:0};for(const e of ms){const c=e.jsonString['@components'].find(x=>x['@type']==='script.CombatMonster');g[c.Group]++;if(!en[c.EnemyId]){bad++;console.log('BAD enemy',t,c.EnemyId);}}if(!(g.combat===3&&g.elite===2&&g.boss===1)){bad++;console.log('BAD groups',t,JSON.stringify(g));}const ids=m.ContentProto.Entities.map(e=>e.id);if(ids.length!==new Set(ids).size){bad++;console.log('DUP guid',t);}}console.log(bad===0?'all maps OK':'BAD:'+bad)"`
|
||||
2회 실행 동일(결정론) 확인.
|
||||
- [ ] **Step 3:** Commit: `git add tools/map/gen-map-encounters.mjs map/ && git commit -m "feat(act-maps): map02~11 인카운터 자동 구성 (combat3/elite2/boss1·맵별 테마)"`
|
||||
|
||||
## Task 2: 컨트롤러 — 맵 필터 + 막 텔레포트
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`, `tools/monster/gen-combat-monster.mjs`
|
||||
|
||||
- [ ] **Step 1 (gen-combat-monster):** OnBeginPlay 등록 호출을 4인자로 — 자기 맵 이름 전달:
|
||||
```
|
||||
local mapName = ""
|
||||
if self.Entity.CurrentMapName ~= nil then
|
||||
mapName = self.Entity.CurrentMapName
|
||||
end
|
||||
c.SlayDeckController:RegisterMonster(self.Entity, self.EnemyId, self.Group, mapName)
|
||||
```
|
||||
(reg 함수 내 기존 RegisterMonster 줄 교체. CurrentMapName 미지원이면 빈 문자열 — BuildMonsters에서 빈 값은 항상 통과시켜 하위 호환.)
|
||||
- [ ] **Step 2 (gen-slaydeck):** `RegisterMonster`에 4번째 인자 `mapName`(string) 추가, 저장 항목에 `map = mapName`(nil/빈 처리: `local mp = mapName; if mp == nil then mp = "" end`).
|
||||
- [ ] **Step 3 (gen-slaydeck BuildMonsters):** 그룹 필터 줄을 확장:
|
||||
```
|
||||
local pmap = ""
|
||||
local lp = _UserService.LocalPlayer
|
||||
if lp ~= nil and lp.CurrentMapName ~= nil then pmap = lp.CurrentMapName end
|
||||
```
|
||||
(reg 수집 루프 앞에 추가) 그리고 필터 조건을 `r.group == g and (r.map == nil or r.map == "" or pmap == "" or r.map == pmap)` 로.
|
||||
- [ ] **Step 4 (gen-slaydeck 막 전환):** writeCodeblocks에 `const ACT_MAPS = ['map01', 'map02', 'map03'];` 추가(ACT_COUNT 옆). `CheckCombatEnd` 보스 분기의 `self:RenderRun()` 다음, `self:ShowMap()` **앞**에 `self:TeleportToActMap()` 삽입. 신규 메서드:
|
||||
```js
|
||||
method('TeleportToActMap', `local maps = { ${ACT_MAPS.map((m) => `"${m}"`).join(', ')} }
|
||||
local target = maps[self.Floor]
|
||||
if target == nil then
|
||||
return
|
||||
end
|
||||
local lp = _UserService.LocalPlayer
|
||||
if lp == nil then
|
||||
return
|
||||
end
|
||||
if lp.CurrentMapName == target then
|
||||
return
|
||||
end
|
||||
_TeleportService:TeleportToMapPosition(lp, Vector3(-6, 0.03, 0), target)`),
|
||||
```
|
||||
- [ ] **Step 5:** `node --check` 둘 다 → gen-combat-monster 실행(코드블록 재생성+맵 no-clobber 확인) → gen-slaydeck 실행 → codeblock에 TeleportToActMap·4인자 등록·맵 필터 확인 → **slaydeck 산출물 복원**(codeblock/ui/common), CombatMonster.codeblock은 커밋 대상.
|
||||
- [ ] **Step 6:** Commit: `git add tools/deck/gen-slaydeck.mjs tools/monster/gen-combat-monster.mjs RootDesk/MyDesk/CombatMonster.codeblock map/ && git commit -m "feat(act-maps): 막별 맵 텔레포트 + 등록 맵 필터"` (map/은 gen-combat-monster 재실행이 기존 맵 값 보존하므로 변화 없을 것 — 변화 있으면 확인 후 포함)
|
||||
|
||||
## Task 3 (컨트롤러 직접): 재생성·검증·커밋
|
||||
P2/P3 T5와 동일: gen-slaydeck 재생성→dup0·심볼(TeleportToActMap)·결정성·sim→산출물 커밋.
|
||||
|
||||
## Task 4 (컨트롤러 직접): 메이커 검증 + 푸시 + PR + 머지
|
||||
1막 보스 처치(스크립트)→Floor2 텔레포트→map02 도착(스크린샷: 새 배경·새 몬스터들)→전투 진입(combat 그룹 3마리·새 EnemyId/외형)→registered 맵 필터 로그. 통과 후 푸시→PR→머지.
|
||||
|
||||
## Self-Review
|
||||
- 스펙 §2.1→T2 Step4, §2.2→T2 1~3, §2.3→T1. encGuid +500 오프셋은 gen-maps idx(몬스터 2~)와 비충돌. CombatMonster 값은 T1이 직접 태그(no-clobber 생성기와 호환 — 이미 존재라 keep). CurrentMapName 불확실성은 빈 값 통과 폴백으로 하위 호환(T4 검증).
|
||||
212
docs/superpowers/plans/2026-06-11-card-visuals.md
Normal file
212
docs/superpowers/plans/2026-06-11-card-visuals.md
Normal file
@@ -0,0 +1,212 @@
|
||||
# 메이플 스킬 카드 비주얼 (P2) 구현 계획
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Task 1·6은 메이커 MCP 인터랙티브 작업 — 컨트롤러가 직접 수행.**
|
||||
|
||||
**Goal:** 카드(손패/보상/상점/인스펙터/모든덱)에 메이플 스킬 이미지+프레임을 입히고 이름을 전사 스킬명으로 바꾼다 (효과·밸런스 불변).
|
||||
|
||||
**Architecture:** `data/cards.json`에 `image`(공식 RUID)·새 `name`. `gen-slaydeck.mjs`가 카드 자식 엔티티(Art/NamePlate/CostPlate)를 5표면에 생성하고, 런타임 렌더는 새 `ApplyCardFace(base, cardId)` 단일 헬퍼로 통일(기존 4개 Apply* 함수가 위임). 공식 RUID는 로컬 워크스페이스에서 렌더됨이 실측 검증됨(스펙 §1).
|
||||
|
||||
**Tech Stack:** Node.js ESM 생성기, MSW Lua codeblock, asset_search_resources MCP(수확), maker MCP(선별·검증).
|
||||
|
||||
---
|
||||
|
||||
## 배경 (구현자용)
|
||||
|
||||
- 생성물 3종은 `tools/deck/gen-slaydeck.mjs` 단일 소스(직접 편집 금지). 루트에서 `node tools/deck/gen-slaydeck.mjs`. 각 Task 검증 후 산출물 복원(`git checkout -- ui/DefaultGroup.ui Global/common.gamelogic RootDesk/MyDesk/SlayDeckController.codeblock`), 산출물 커밋은 T5.
|
||||
- 카드 렌더 함수 4종(현재 동일 모양): `ApplyCardVisual`(손패 `/ui/DefaultGroup/CardHand/Card{slot}`), `ApplyRewardVisual`(`/RewardHud/Reward{slot}`), `ApplyInspectCardVisual`(`/DeckInspectHud/Grid/Card{slot}`), `ApplyAllDeckCardVisual`(`/DeckAllHud/Grid/Card{slot}`). 각각 Cost/Name/Desc SetText + 루트 색.
|
||||
- 카드 크기: 손패/보상/상점 180×250(`CARD_W`/`CARD_H`), 그리드(인스펙터/모든덱) 셀 158×214.
|
||||
- 색: ATTACK {0.86,0.42,0.38} / DEFEND {0.42,0.55,0.85} / SKILL {0.46,0.68,0.52} (luaCardsTable의 kind 기반).
|
||||
|
||||
## 파일 구조
|
||||
| 파일 | 책임 |
|
||||
|---|---|
|
||||
| `data/cards.json` | name 3종 변경 + image RUID 3종 (T1) |
|
||||
| `tools/deck/gen-slaydeck.mjs` | luaCardsTable image·ApplyCardFace·4함수 통일(T2), 카드 프레임 엔티티 5표면(T3·T4) |
|
||||
| 산출물 | T5 재생성·커밋 |
|
||||
|
||||
---
|
||||
|
||||
## Task 1 (컨트롤러 직접): RUID 수확 + cards.json
|
||||
|
||||
메이커 MCP 인터랙티브 — subagent 금지, 컨트롤러가 수행.
|
||||
|
||||
- [ ] **Step 1:** `asset_search_resources`(cat=sprite, source=maplestory)로 후보 수집: 질의 "파워 스트라이크"(이미 10건 확보), "슬래시 블러스트", "아이언 바디". 후보 부족 시 보조 질의("슬래시", "강철", "워리어").
|
||||
- [ ] **Step 2:** 메이커 Play→전투 진입 후, 후보 RUID를 Card1 Art 자리(`SpriteGUIRendererComponent.ImageRUID`, Type=0)에 순회 주입 + 스크린샷으로 스킬당 1개 선별(일러스트 적합성 기준: 식별 가능·단일 컷·과도한 투명 여백 없음).
|
||||
- [ ] **Step 3:** `data/cards.json`을 다음 형태로 갱신(RUID는 선별값으로):
|
||||
```json
|
||||
{
|
||||
"cards": {
|
||||
"Strike": { "name": "파워 스트라이크", "cost": 1, "kind": "Attack", "damage": 6, "desc": "피해 6", "image": "<선별RUID>" },
|
||||
"Defend": { "name": "아이언 바디", "cost": 1, "kind": "Skill", "block": 5, "desc": "방어도 5", "image": "<선별RUID>" },
|
||||
"Bash": { "name": "슬래시 블러스트", "cost": 2, "kind": "Attack", "damage": 10, "desc": "피해 10", "image": "<선별RUID>" }
|
||||
},
|
||||
"starterDeck": ["Strike", "Strike", "Strike", "Strike", "Strike", "Defend", "Defend", "Defend", "Defend", "Bash"]
|
||||
}
|
||||
```
|
||||
- [ ] **Step 4:** `node -e "JSON.parse(require('fs').readFileSync('data/cards.json','utf8'));console.log('ok')"` → ok. sim 회귀: `node --test tools/balance/sim-balance.test.mjs` → 14/14 (fixture 자체 카드라 무관).
|
||||
- [ ] **Step 5:** Commit: `git add data/cards.json && git commit -m "feat(card-visuals): 카드를 전사 스킬로 리네임 + 공식 스킬 이미지 RUID"`
|
||||
|
||||
---
|
||||
|
||||
## Task 2: ApplyCardFace 렌더 일원화
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`
|
||||
|
||||
- [ ] **Step 1: luaCardsTable에 image 직렬화.** `function luaCardsTable(cards)`의 fields 구성에 추가:
|
||||
```js
|
||||
if (c.image != null) fields.push(`image = ${luaStr(c.image)}`);
|
||||
```
|
||||
(`if (c.block != null) ...` 줄 다음에.)
|
||||
|
||||
- [ ] **Step 2: ApplyCardFace 메서드 추가** (`ApplyCardVisual` 메서드 정의 바로 앞에):
|
||||
```js
|
||||
method('ApplyCardFace', `local c = self.Cards[cardId]
|
||||
if c == nil then
|
||||
c = { name = cardId, cost = 0, desc = "", kind = "Skill" }
|
||||
end
|
||||
local e = _EntityService:GetEntityByPath(base)
|
||||
if e ~= nil and e.SpriteGUIRendererComponent ~= nil then
|
||||
if c.kind == "Attack" then
|
||||
e.SpriteGUIRendererComponent.Color = Color(0.86, 0.42, 0.38, 1)
|
||||
elseif c.kind == "Skill" then
|
||||
e.SpriteGUIRendererComponent.Color = Color(0.42, 0.55, 0.85, 1)
|
||||
else
|
||||
e.SpriteGUIRendererComponent.Color = Color(0.46, 0.68, 0.52, 1)
|
||||
end
|
||||
end
|
||||
self:SetText(base .. "/Cost", string.format("%d", c.cost))
|
||||
self:SetText(base .. "/Name", c.name)
|
||||
self:SetText(base .. "/Desc", c.desc)
|
||||
local art = _EntityService:GetEntityByPath(base .. "/Art")
|
||||
if art ~= nil then
|
||||
if c.image ~= nil and c.image ~= "" then
|
||||
art.Enable = true
|
||||
if art.SpriteGUIRendererComponent ~= nil then
|
||||
art.SpriteGUIRendererComponent.ImageRUID = c.image
|
||||
end
|
||||
else
|
||||
art.Enable = false
|
||||
end
|
||||
end`, [
|
||||
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'base' },
|
||||
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'cardId' },
|
||||
]),
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 기존 4개 함수를 위임으로 교체.** 각 메서드 본문 전체를:
|
||||
- `ApplyCardVisual`: `self:ApplyCardFace("/ui/DefaultGroup/CardHand/Card" .. tostring(slot), cardId)`
|
||||
- `ApplyRewardVisual`: `self:ApplyCardFace("/ui/DefaultGroup/RewardHud/Reward" .. tostring(slot), cardId)`
|
||||
- `ApplyInspectCardVisual`: `self:ApplyCardFace("/ui/DefaultGroup/DeckInspectHud/Grid/Card" .. tostring(slot), cardId)`
|
||||
- `ApplyAllDeckCardVisual`: 기존 본문에서 카드 면 설정부를 `self:ApplyCardFace("/ui/DefaultGroup/DeckAllHud/Grid/Card" .. tostring(slot), cardId)`로 교체(본문에 수량 배지 등 추가 로직이 있으면 그 부분은 유지 — 현재 본문을 읽고 카드면(Cost/Name/Desc/색) 설정부만 위임).
|
||||
(인자 목록은 변경 없음.)
|
||||
|
||||
- [ ] **Step 4: RenderShop 카드부 위임.** `RenderShop` 본문에서 상점 카드 면 설정부(Card{i}의 Cost/Name/Desc SetText + 색 설정)를 `self:ApplyCardFace(base, cid)` 호출로 교체(가격(Price) SetText·구매 상태 처리는 유지). 본문을 읽고 해당 부분만 정확히 치환.
|
||||
|
||||
- [ ] **Step 5: 검증.** `node --check` → OK. `node tools/deck/gen-slaydeck.mjs` 후:
|
||||
`node -e "const cb=JSON.parse(require('fs').readFileSync('RootDesk/MyDesk/SlayDeckController.codeblock','utf8'));const s=JSON.stringify(cb);const names=cb.ContentProto.Json.Methods.map(m=>m.Name);console.log('face:',names.includes('ApplyCardFace'),'| image in Cards:',s.includes('image = '),'| delegates:',(s.match(/ApplyCardFace\(/g)||[]).length>=5)"`
|
||||
Expected: 모두 true. 산출물 복원.
|
||||
|
||||
- [ ] **Step 6: Commit:** `git add tools/deck/gen-slaydeck.mjs && git commit -m "feat(card-visuals): ApplyCardFace 렌더 일원화 + Cards image 직렬화"`
|
||||
|
||||
---
|
||||
|
||||
## Task 3: 손패 카드 프레임 (Card1~5)
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs` (upsertUi의 손패 카드 갱신부)
|
||||
|
||||
- [ ] **Step 1: 현재 손패 카드 빌드부 읽기.** upsertUi에서 `for (let i = 1; i <= 5; i++)`로 `/ui/DefaultGroup/CardHand/Card{i}`를 byPath 갱신하고 children(['Cost'...],['Name'...],['Desc'...])을 생성/갱신하는 블록을 찾는다.
|
||||
|
||||
- [ ] **Step 2: children 배열을 프레임 배치로 교체.** 기존 children 항목의 cfg를:
|
||||
```js
|
||||
const children = [
|
||||
['Cost', { size: { x: 44, y: 44 }, pos: { x: -68, y: 103 }, value: cards[i - 1].cost, fontSize: 26, bold: true }],
|
||||
['Name', { size: { x: 168, y: 30 }, pos: { x: 0, y: -8 }, value: cards[i - 1].name, fontSize: 20, bold: true }],
|
||||
['Desc', { size: { x: 164, y: 70 }, pos: { x: 0, y: -62 }, value: cards[i - 1].desc, fontSize: 18, bold: false }],
|
||||
];
|
||||
```
|
||||
로 교체(기존 child 갱신 분기에서도 cfg의 size/pos를 반영하도록 — 기존 갱신 분기가 Text/FontSize만 갱신한다면 transform도 cfg로 갱신하는 줄 추가:
|
||||
```js
|
||||
const tr0 = child.jsonString['@components'][0];
|
||||
tr0.RectSize = cfg.size;
|
||||
tr0.anchoredPosition = cfg.pos;
|
||||
tr0.OffsetMin = { x: cfg.pos.x - cfg.size.x / 2, y: cfg.pos.y - cfg.size.y / 2 };
|
||||
tr0.OffsetMax = { x: cfg.pos.x + cfg.size.x / 2, y: cfg.pos.y + cfg.size.y / 2 };
|
||||
```
|
||||
)
|
||||
|
||||
- [ ] **Step 3: 프레임 자식 추가(없으면 생성, byPath 패턴 동일).** children 루프 뒤에 카드별로:
|
||||
```js
|
||||
const frameKids = [
|
||||
['NamePlate', 'uisprite', 'UISprite', 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent', 3,
|
||||
{ size: { x: 168, y: 34 }, pos: { x: 0, y: -8 } }, { r: 0.07, g: 0.08, b: 0.1, a: 0.92 }],
|
||||
['CostPlate', 'uisprite', 'UISprite', 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent', 4,
|
||||
{ size: { x: 44, y: 44 }, pos: { x: -68, y: 103 } }, { r: 0.07, g: 0.08, b: 0.1, a: 0.95 }],
|
||||
['Art', 'uisprite', 'UISprite', 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent', 5,
|
||||
{ size: { x: 96, y: 96 }, pos: { x: 0, y: 52 } }, { r: 1, g: 1, b: 1, a: 1 }],
|
||||
];
|
||||
for (const [suffix, modelId, entryId, componentNames, dOrder, cfg, color] of frameKids) {
|
||||
const fPath = `/ui/DefaultGroup/CardHand/Card${i}/${suffix}`;
|
||||
if (!byPath.get(fPath)) {
|
||||
const fe = entity({
|
||||
id: guid('dck', 100 + i * 10 + dOrder),
|
||||
path: fPath, modelId, entryId, componentNames,
|
||||
displayOrder: dOrder,
|
||||
components: [
|
||||
transform({ parentW: CARD_W, parentH: CARD_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: cfg.size, pos: cfg.pos }),
|
||||
sprite(suffix === 'Art' ? { color, type: 0, raycast: false } : { color, type: 1, raycast: false }),
|
||||
],
|
||||
});
|
||||
ui.ContentProto.Entities.push(fe);
|
||||
byPath.set(fPath, fe);
|
||||
}
|
||||
}
|
||||
```
|
||||
주의: `guid('dck', N)` 기존 사용 대역 확인(grep `guid('dck'`) 후 충돌 시 200+로 이동. Cost/Name/Desc 텍스트가 NamePlate/CostPlate **위에** 그려지도록 displayOrder 관계 확인(텍스트 0/1/2 < 플레이트 3/4면 플레이트가 위 — **플레이트가 텍스트를 가리면 안 되므로** 텍스트 displayOrder를 6/7/8로 올리고 플레이트 3/4·Art 5 유지: Cost→7, Name→6, Desc→8로 child 생성/갱신 분기에서 displayOrder 설정).
|
||||
|
||||
- [ ] **Step 4: 검증.** `node --check` → 실행 → 확인:
|
||||
`node -e "const ui=JSON.parse(require('fs').readFileSync('ui/DefaultGroup.ui','utf8'));const p=ui.ContentProto.Entities.map(e=>e.path);console.log('art:',[1,2,3,4,5].every(i=>p.includes('/ui/DefaultGroup/CardHand/Card'+i+'/Art')),'| plates:',[1,2,3,4,5].every(i=>p.includes('/ui/DefaultGroup/CardHand/Card'+i+'/NamePlate')))"` → 모두 true. dup id 0 확인. 산출물 복원.
|
||||
|
||||
- [ ] **Step 5: Commit:** `git add tools/deck/gen-slaydeck.mjs && git commit -m "feat(card-visuals): 손패 카드 프레임(Art·NamePlate·CostPlate)"`
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 보상/상점/그리드 카드 프레임
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`
|
||||
|
||||
- [ ] **Step 1: 보상 카드(Reward1~3, 180×250).** 보상 카드 빌더(자식 Cost/Name/Desc 생성 루프)에서 자식 cfg를 Task 3 Step 2와 동일 좌표로 바꾸고(Cost 44×44@(-68,103) f26 / Name 168×30@(0,-8) f20 / Desc 164×70@(0,-62) f18), 동일한 NamePlate/CostPlate/Art 3종을 push(부모 RewardHud/Reward{i}, guid('rwd', 100+i*10+dOrder), displayOrder: 텍스트 6/7/8·플레이트 3/4·Art 5).
|
||||
|
||||
- [ ] **Step 2: 상점 카드(ShopHud/Card1~3, 180×250).** 동일 적용하되 Desc는 `{ size: { x: 164, y: 56 }, pos: { x: 0, y: -58 } }` (Price (0,-105)와 1px 간격 — Price·구매로직 불변). guid('shp', 100+i*10+dOrder).
|
||||
|
||||
- [ ] **Step 3: 그리드 카드(DeckInspectHud/Grid/Card{n}·DeckAllHud/Grid/Card{n}, 158×214).** 두 빌더(line≈661, 783)에 비례 축소 프레임: Art 84×84@(0,44) / NamePlate 148×30@(0,-8) / CostPlate 38×38@(-58,86); 텍스트 cfg: Cost 38×38@(-58,86) f22 / Name 148×26@(0,-8) f17 / Desc 144×60@(0,-54) f15. guid는 각 빌더의 기존 네임스페이스 시퀀스 이어쓰기(중복 검증으로 확인).
|
||||
|
||||
- [ ] **Step 4: 검증.** 실행 후:
|
||||
`node -e "const ui=JSON.parse(require('fs').readFileSync('ui/DefaultGroup.ui','utf8'));const E=ui.ContentProto.Entities;const cnt=s=>E.filter(e=>e.path.includes(s)&&e.path.endsWith('/Art')).length;console.log('reward:',cnt('/RewardHud/Reward'),'shop:',cnt('/ShopHud/Card'),'inspect:',cnt('/DeckInspectHud/Grid/'),'alldeck:',cnt('/DeckAllHud/Grid/'));const ids=E.map(e=>e.id);console.log('dup:',ids.filter((x,i)=>ids.indexOf(x)!==i).length)"`
|
||||
Expected: reward:3 shop:3 inspect:(그리드 수) alldeck:(그리드 수), dup:0. 산출물 복원.
|
||||
|
||||
- [ ] **Step 5: Commit:** `git add tools/deck/gen-slaydeck.mjs && git commit -m "feat(card-visuals): 보상·상점·그리드 카드 프레임 적용"`
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 재생성·검증·산출물 커밋
|
||||
|
||||
- [ ] **Step 1:** `node tools/deck/gen-slaydeck.mjs` → exit 0.
|
||||
- [ ] **Step 2:** JSON 3종 파스 + dup 0 + 손패/보상/상점/그리드 Art 존재 + codeblock에 ApplyCardFace·image 직렬화(`image = `)·새 카드명("파워 스트라이크") 포함 확인:
|
||||
`node -e "const fs=require('fs');for(const f of ['ui/DefaultGroup.ui','Global/common.gamelogic','RootDesk/MyDesk/SlayDeckController.codeblock'])JSON.parse(fs.readFileSync(f,'utf8'));const cb=fs.readFileSync('RootDesk/MyDesk/SlayDeckController.codeblock','utf8');console.log('face+image+name:',cb.includes('ApplyCardFace')&&cb.includes('image = ')&&cb.includes('파워 스트라이크'))"` → true.
|
||||
- [ ] **Step 3:** 결정성(재실행 빈 diff) + sim 14/14.
|
||||
- [ ] **Step 4:** Commit: `git add ui/DefaultGroup.ui Global/common.gamelogic RootDesk/MyDesk/SlayDeckController.codeblock && git commit -m "feat(card-visuals): 산출물 재생성"`
|
||||
|
||||
---
|
||||
|
||||
## Task 6 (컨트롤러 직접): 메이커 플레이테스트 + 푸시 + PR
|
||||
|
||||
- refresh → build 0 → play. 4표면 스크린샷: ①손패(전투, 스킬 이미지+프레임+새 이름) ②보상 ③상점 ④모든덱/인스펙터. 이미지 미적용/프레임 깨짐/그리드 셀 영향 발견 시 좌표·RUID 수정 → 재생성 → 재확인.
|
||||
- 통과 후: `git push -u origin feature/p2-card-visuals`(인증 실패 시 1회 재시도) → PR 링크+메시지 제공.
|
||||
|
||||
---
|
||||
|
||||
## Self-Review 결과
|
||||
- **스펙 커버리지**: §2→T1, §3→T1, §4→T3·T4, §5→T2, §6→T1~T5, §8→T5·T6. 전부 매핑.
|
||||
- **플레이스홀더**: T1의 `<선별RUID>`는 수확 절차의 산출물로 정의됨(절차 명시). 그 외 실제 코드.
|
||||
- **일관성**: `ApplyCardFace(base, cardId)` 시그니처·자식명(Art/NamePlate/CostPlate)·displayOrder 규칙(플레이트3/4·Art5·텍스트6/7/8) Task 간 일치. guid 충돌은 각 Task 검증(dup 0)으로 강제.
|
||||
- **주의**: 손패 byPath 갱신 분기·RenderShop/ApplyAllDeckCardVisual 본문은 구현 시 현재 코드를 읽고 지정 부분만 치환(앵커 명시됨).
|
||||
289
docs/superpowers/plans/2026-06-11-combat-feel.md
Normal file
289
docs/superpowers/plans/2026-06-11-combat-feel.md
Normal file
@@ -0,0 +1,289 @@
|
||||
# 전투 연출 (P3) 구현 계획
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development. Task 6은 메이커 MCP — 컨트롤러 직접.
|
||||
|
||||
**Goal:** 카드 드래그→몬스터 지정, 공격 이펙트 후 데미지, 적 개별 차례, 데미지 팝업.
|
||||
|
||||
**Architecture:** 카드에 `UITouchReceiveComponent`(공식 드래그 이벤트). 연출은 컨트롤러 타이머 체인(`FxBusy`/`TurnBusy` 가드). 모든 변경은 `tools/deck/gen-slaydeck.mjs` 단일 소스.
|
||||
|
||||
**Tech Stack:** Node ESM 생성기, MSW Lua, UITouchReceive/UILogic/TimerService.
|
||||
|
||||
---
|
||||
|
||||
## 배경 (구현자용)
|
||||
- 루트에서 `node tools/deck/gen-slaydeck.mjs`. 각 Task: `node --check` → 생성 → 확인 → **산출물 복원**(`git checkout -- ui/DefaultGroup.ui Global/common.gamelogic RootDesk/MyDesk/SlayDeckController.codeblock`) → 소스만 커밋. 산출물 커밋은 T5.
|
||||
- 손패 카드: `/ui/DefaultGroup/CardHand/Card{1..5}`, 원위치 x=`CARD_XS[i]`(-400..400), y=0, 부모 CardHand는 화면 UI좌표 (0,-360) 중심(앵커 bottom-center pos y180).
|
||||
- 몬스터: `self.Monsters[i] = {entity, ..., alive, slot}`; world→screen은 `_UILogic:WorldToScreenPosition(Vector2(wp.x, wp.y+1.4))` 패턴(PositionMonsterSlot 참조).
|
||||
- 기존: `BindButtons`에 카드 클릭 `ConnectEvent(ButtonClickEvent, ... PlayCard(i))` 루프 존재(제거 대상). `PlayCard`는 즉시 `DealDamageToTarget`. `EndPlayerTurn`은 손패 버림→`EnemyTurn()`→`CheckCombatEnd`→타이머로 `StartPlayerTurn`. `KillMonster`는 즉시 `SetVisible(false)`.
|
||||
- guid 'cmb' 사용 대역: 0~10·41~144(+221~224 TargetFrame)·200~216. **신규: SkillFx=230, ActFrame=240+i, DmgPop slot=250+i, player DmgPop=260.**
|
||||
|
||||
## Task 1: 카드 드래그 타겟팅
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`
|
||||
|
||||
- [ ] **Step 1: 카드 엔티티에 UITouchReceiveComponent.** upsertUi 손패 카드(byPath 갱신 분기)에서 Card{i} 루트의 componentNames에 `MOD.Core.UITouchReceiveComponent`가 없으면 추가하고 `@components`에 `{ '@type': 'MOD.Core.UITouchReceiveComponent', Enable: true }` push (기존 ButtonComponent 추가 패턴과 동일한 create-if-missing 방식 — 그 코드를 읽고 모방).
|
||||
|
||||
- [ ] **Step 2: 드래그 상태 prop 추가.** SlayDeckController prop 배열에:
|
||||
```js
|
||||
prop('number', 'DragSlot', '0'),
|
||||
prop('boolean', 'FxBusy', 'false'),
|
||||
prop('boolean', 'TurnBusy', 'false'),
|
||||
```
|
||||
|
||||
- [ ] **Step 3: BindButtons — 카드 클릭 제거 + 드래그 연결.** 기존 `for i = 1, 5 do ... PlayCard(i) ... end`(카드 ButtonClickEvent 루프)를 다음으로 교체:
|
||||
```lua
|
||||
for i = 1, 5 do
|
||||
local cardEntity = _EntityService:GetEntityByPath("/ui/DefaultGroup/CardHand/Card" .. tostring(i))
|
||||
if cardEntity ~= nil and cardEntity.UITouchReceiveComponent ~= nil then
|
||||
cardEntity:ConnectEvent(UITouchBeginDragEvent, function(ev) self:OnCardDragBegin(i) end)
|
||||
cardEntity:ConnectEvent(UITouchDragEvent, function(ev) self:OnCardDrag(i, ev.TouchPoint) end)
|
||||
cardEntity:ConnectEvent(UITouchEndDragEvent, function(ev) self:OnCardDragEnd(i, ev.TouchPoint) end)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 드래그 메서드 3종 + ResolveCardDrop 추가** (CARD_XS는 JS 상수 — 보간으로 Lua 테이블 굽기):
|
||||
```js
|
||||
method('OnCardDragBegin', `if self.CombatOver == true or self.FxBusy == true or self.TurnBusy == true then
|
||||
return
|
||||
end
|
||||
if self.Hand == nil or self.Hand[slot] == nil then
|
||||
return
|
||||
end
|
||||
self.DragSlot = slot`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]),
|
||||
method('OnCardDrag', `if self.DragSlot ~= slot then
|
||||
return
|
||||
end
|
||||
local e = _EntityService:GetEntityByPath("/ui/DefaultGroup/CardHand/Card" .. tostring(slot))
|
||||
if e ~= nil and e.UITransformComponent ~= nil then
|
||||
local ui = _UILogic:ScreenToUIPosition(touchPoint)
|
||||
e.UITransformComponent.anchoredPosition = Vector2(ui.x, ui.y + 360)
|
||||
end`, [
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' },
|
||||
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'touchPoint' },
|
||||
]),
|
||||
method('OnCardDragEnd', `if self.DragSlot ~= slot then
|
||||
return
|
||||
end
|
||||
self.DragSlot = 0
|
||||
local cardXs = { ${CARD_XS.join(', ')} }
|
||||
local e = _EntityService:GetEntityByPath("/ui/DefaultGroup/CardHand/Card" .. tostring(slot))
|
||||
if e ~= nil and e.UITransformComponent ~= nil then
|
||||
e.UITransformComponent.anchoredPosition = Vector2(cardXs[slot], 0)
|
||||
end
|
||||
self:ResolveCardDrop(slot, touchPoint)`, [
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' },
|
||||
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'touchPoint' },
|
||||
]),
|
||||
method('ResolveCardDrop', `if self.CombatOver == true or self.FxBusy == true or self.TurnBusy == true then
|
||||
return
|
||||
end
|
||||
local cardId = self.Hand[slot]
|
||||
if cardId == nil then
|
||||
return
|
||||
end
|
||||
local c = self.Cards[cardId]
|
||||
if c == nil then
|
||||
return
|
||||
end
|
||||
if c.kind == "Attack" then
|
||||
local best = 0
|
||||
local bestDist = 200
|
||||
for i = 1, #self.Monsters do
|
||||
local m = self.Monsters[i]
|
||||
if m.alive == true and m.entity ~= nil and isvalid(m.entity) and m.entity.TransformComponent ~= nil then
|
||||
local wp = m.entity.TransformComponent.WorldPosition
|
||||
local sp = _UILogic:WorldToScreenPosition(Vector2(wp.x, wp.y + 0.7))
|
||||
local dx = sp.x - touchPoint.x
|
||||
local dy = sp.y - touchPoint.y
|
||||
local d = math.sqrt(dx * dx + dy * dy)
|
||||
if d < bestDist then
|
||||
bestDist = d
|
||||
best = i
|
||||
end
|
||||
end
|
||||
end
|
||||
if best > 0 then
|
||||
self.TargetIndex = best
|
||||
self:PlayCard(slot)
|
||||
end
|
||||
else
|
||||
local ui = _UILogic:ScreenToUIPosition(touchPoint)
|
||||
if ui.y > -180 then
|
||||
self:PlayCard(slot)
|
||||
end
|
||||
end`, [
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' },
|
||||
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'touchPoint' },
|
||||
]),
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 검증.** node --check → 생성 → `node -e "const cb=require('fs').readFileSync('RootDesk/MyDesk/SlayDeckController.codeblock','utf8');console.log('drag:',cb.includes('OnCardDragBegin')&&cb.includes('UITouchBeginDragEvent'),'| no card click PlayCard loop:',!/Card\\\" \.\. tostring\(i\)\)[\s\S]{0,220}ButtonClickEvent[\s\S]{0,80}PlayCard\(i\)/.test(cb))"` (두 번째 체크가 어려우면 수동으로 BindButtons에서 카드 ButtonClickEvent 루프 부재 확인). ui에 UITouchReceiveComponent 5장 확인:
|
||||
`node -e "const ui=JSON.parse(require('fs').readFileSync('ui/DefaultGroup.ui','utf8'));console.log(ui.ContentProto.Entities.filter(e=>/CardHand\/Card[1-5]$/.test(e.path)&&e.componentNames.includes('UITouchReceiveComponent')).length)"` → 5. 산출물 복원.
|
||||
|
||||
- [ ] **Step 6: Commit** `feat(combat-feel): 카드 드래그 타겟팅 (UITouchReceive·ResolveCardDrop)`
|
||||
|
||||
## Task 2: 공격 이펙트 → 지연 데미지
|
||||
|
||||
- [ ] **Step 1: SkillFx 엔티티** (upsertUi CombatHud, Result 이전):
|
||||
```js
|
||||
const skillFx = entity({
|
||||
id: guid('cmb', 230), path: '/ui/DefaultGroup/CombatHud/SkillFx',
|
||||
modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 30,
|
||||
components: [
|
||||
transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 110, y: 110 }, pos: { x: 0, y: 0 } }),
|
||||
sprite({ color: { r: 1, g: 1, b: 1, a: 1 }, type: 0, raycast: false }),
|
||||
],
|
||||
});
|
||||
skillFx.jsonString.enable = false;
|
||||
combat.push(skillFx);
|
||||
```
|
||||
|
||||
- [ ] **Step 2: PlayCard Attack 분기 교체.** 기존:
|
||||
```
|
||||
if c.kind == "Attack" then
|
||||
if c.damage ~= nil then
|
||||
self:DealDamageToTarget(c.damage)
|
||||
end
|
||||
self:ApplyRelics("cardPlayed")
|
||||
```
|
||||
→
|
||||
```
|
||||
if c.kind == "Attack" then
|
||||
if c.damage ~= nil then
|
||||
self:PlayAttackFx(self.TargetIndex, c.image, c.damage)
|
||||
end
|
||||
self:ApplyRelics("cardPlayed")
|
||||
```
|
||||
그리고 PlayCard 끝의 `self:CheckCombatEnd()`는 유지(Skill 경로용 — Attack은 PlayAttackFx 완료 시 재호출).
|
||||
|
||||
- [ ] **Step 3: PlayAttackFx 추가:**
|
||||
```js
|
||||
method('PlayAttackFx', `local m = self.Monsters[targetIndex]
|
||||
if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then
|
||||
self:DealDamageToTarget(damage)
|
||||
self:RenderCombat()
|
||||
self:CheckCombatEnd()
|
||||
return
|
||||
end
|
||||
self.FxBusy = true
|
||||
local fx = _EntityService:GetEntityByPath("/ui/DefaultGroup/CombatHud/SkillFx")
|
||||
if fx ~= nil then
|
||||
if fx.SpriteGUIRendererComponent ~= nil and image ~= nil and image ~= "" then
|
||||
fx.SpriteGUIRendererComponent.ImageRUID = image
|
||||
end
|
||||
if fx.UITransformComponent ~= nil and m.entity.TransformComponent ~= nil then
|
||||
local wp = m.entity.TransformComponent.WorldPosition
|
||||
local sp = _UILogic:WorldToScreenPosition(Vector2(wp.x, wp.y + 0.7))
|
||||
fx.UITransformComponent.anchoredPosition = _UILogic:ScreenToUIPosition(sp)
|
||||
end
|
||||
fx.Enable = true
|
||||
end
|
||||
_TimerService:SetTimerOnce(function()
|
||||
if fx ~= nil then fx.Enable = false end
|
||||
self.FxBusy = false
|
||||
self:DealDamageToTarget(damage)
|
||||
self:ShowDmgPop(targetIndex, damage)
|
||||
self:RenderCombat()
|
||||
self:CheckCombatEnd()
|
||||
end, 0.35)`, [
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'targetIndex' },
|
||||
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'image' },
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'damage' },
|
||||
]),
|
||||
```
|
||||
주의: `ShowDmgPop`은 T3에서 추가 — T2 커밋 시점엔 생성기 실행이 깨지지 않음(문자열일 뿐). PlayCard/EndPlayerTurn 시작 가드에 `or self.FxBusy == true or self.TurnBusy == true` 추가(기존 `if self.CombatOver == true then return end`를 확장).
|
||||
|
||||
- [ ] **Step 4: 검증** (codeblock에 PlayAttackFx·SkillFx 존재, PlayCard에 PlayAttackFx 호출). 산출물 복원, 커밋 `feat(combat-feel): 공격 이펙트 후 지연 데미지 (SkillFx·FxBusy)`
|
||||
|
||||
## Task 3: 데미지 팝업 + 사망 지연
|
||||
|
||||
- [ ] **Step 1: DmgPop 엔티티.** 몬스터 슬롯 루프에 자식 추가(dOrder 9, guid cmb 250+i): 텍스트 120×30 @(0, 60), fontSize 24 bold, 색 {1,0.35,0.3,1}, value '', enable=false. PlayerPanel에도 동일(guid cmb 260, 경로 `PlayerPanel/DmgPop`, pos (16, 40), 색 {1,0.4,0.35,1}).
|
||||
- [ ] **Step 2: ShowDmgPop / ShowPlayerDmgPop:**
|
||||
```js
|
||||
method('ShowDmgPop', `local base = "/ui/DefaultGroup/CombatHud/MonsterSlot" .. tostring(slot) .. "/DmgPop"
|
||||
self:SetText(base, "-" .. string.format("%d", amount))
|
||||
self:SetEntityEnabled(base, true)
|
||||
_TimerService:SetTimerOnce(function() self:SetEntityEnabled(base, false) end, 0.6)`, [
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' },
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' },
|
||||
]),
|
||||
method('ShowPlayerDmgPop', `local base = "/ui/DefaultGroup/CombatHud/PlayerPanel/DmgPop"
|
||||
if amount > 0 then
|
||||
self:SetText(base, "-" .. string.format("%d", amount))
|
||||
else
|
||||
self:SetText(base, "막음")
|
||||
end
|
||||
self:SetEntityEnabled(base, true)
|
||||
_TimerService:SetTimerOnce(function() self:SetEntityEnabled(base, false) end, 0.6)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }]),
|
||||
```
|
||||
- [ ] **Step 3: KillMonster 사망 지연.** `m.entity:SetVisible(false)` 즉시 호출을:
|
||||
```
|
||||
local ent = m.entity
|
||||
_TimerService:SetTimerOnce(function() if isvalid(ent) then ent:SetVisible(false) end end, 0.4)
|
||||
```
|
||||
로 교체.
|
||||
- [ ] **Step 4: 검증·복원·커밋** `feat(combat-feel): 데미지 팝업·사망 지연`
|
||||
|
||||
## Task 4: 적 개별 차례
|
||||
|
||||
- [ ] **Step 1: ActFrame 엔티티.** 몬스터 슬롯 루프에 자식(dOrder 0보다 아래는 불가하니 TargetFrame처럼 dOrder 0, guid cmb 240+i — TargetFrame과 별도): 156×108 @(0,0), 색 {0.95,0.3,0.25,0.3}, enable=false. (TargetFrame과 같은 위치 — 적 턴 중에는 TargetFrame 대신 표시됨.)
|
||||
- [ ] **Step 2: EnemyTurn 시퀀스 교체.** `EnemyTurn` 전체를:
|
||||
```js
|
||||
method('EnemyTurn', `self.TurnBusy = true
|
||||
self:EnemyActStep(1)`),
|
||||
method('EnemyActStep', `local idx = 0
|
||||
for i = fromIndex, #self.Monsters do
|
||||
if self.Monsters[i].alive == true then idx = i; break end
|
||||
end
|
||||
if idx == 0 or self.PlayerHp <= 0 then
|
||||
self:FinishEnemyTurn()
|
||||
return
|
||||
end
|
||||
local m = self.Monsters[idx]
|
||||
local base = "/ui/DefaultGroup/CombatHud/MonsterSlot" .. tostring(idx)
|
||||
self:SetEntityEnabled(base .. "/ActFrame", true)
|
||||
_TimerService:SetTimerOnce(function()
|
||||
m.block = 0
|
||||
local intent = m.intents[m.intentIdx]
|
||||
if intent ~= nil then
|
||||
if intent.kind == "Attack" then
|
||||
local before = self.PlayerHp
|
||||
self:DealDamageToPlayer(intent.value)
|
||||
self:ShowPlayerDmgPop(before - self.PlayerHp)
|
||||
elseif intent.kind == "Defend" then
|
||||
m.block = m.block + intent.value
|
||||
end
|
||||
end
|
||||
m.intentIdx = m.intentIdx + 1
|
||||
if m.intentIdx > #m.intents then
|
||||
m.intentIdx = 1
|
||||
end
|
||||
self:RenderCombat()
|
||||
self:SetEntityEnabled(base .. "/ActFrame", false)
|
||||
_TimerService:SetTimerOnce(function() self:EnemyActStep(idx + 1) end, 0.15)
|
||||
end, 0.45)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'fromIndex' }]),
|
||||
method('FinishEnemyTurn', `self.TurnBusy = false
|
||||
self:CheckCombatEnd()
|
||||
if self.CombatOver == true then
|
||||
return
|
||||
end
|
||||
_TimerService:SetTimerOnce(function() self:StartPlayerTurn() end, 0.45)`),
|
||||
```
|
||||
- [ ] **Step 3: EndPlayerTurn 후반 정리.** 기존 EndPlayerTurn에서 `self:EnemyTurn()` 호출 이후의 `self:CheckCombatEnd()`/CombatOver 체크/`SetTimerOnce(... StartPlayerTurn ...)` 블록 **삭제**(FinishEnemyTurn이 담당). 가드 확장 확인(T2에서 FxBusy/TurnBusy).
|
||||
- [ ] **Step 4: RenderCombat의 ActFrame 정리.** RenderCombat 몬스터 루프의 else(사망/없음) 분기는 슬롯 통째 비활성이므로 ActFrame 잔존 위험 없음 — 확인만.
|
||||
- [ ] **Step 5: 검증·복원·커밋** `feat(combat-feel): 적 개별 차례 시퀀스 (ActFrame·EnemyActStep)`
|
||||
|
||||
## Task 5: 재생성·검증·산출물 커밋
|
||||
P2 T5와 동일 절차(생성→JSON·dup0·핵심 심볼(OnCardDragBegin/PlayAttackFx/EnemyActStep/DmgPop)·결정성·sim 14/14→산출물 커밋 `feat(combat-feel): 산출물 재생성`).
|
||||
|
||||
## Task 6 (컨트롤러 직접): 메이커 검증 + 푸시 + PR + 머지
|
||||
- mouse_input 드래그로: 공격 카드→몬스터2 드롭(타겟 변경+이펙트+팝업+HP 감소), Skill 카드 위로 드롭(방어), 빈 곳 드롭 취소, 턴 종료→순차 행동(ActFrame)+플레이어 팝업, 전체 처치 승리. 스크린샷 evidence.
|
||||
- 푸시→Gitea API PR(상세 메시지)→머지.
|
||||
|
||||
## Self-Review
|
||||
- 요구 4종(드래그/모션 후 데미지/개별 차례/팝업·사망) ↔ T1/T2/T4/T3 매핑 완료. ResolveCardDrop의 `TargetIndex` 직접 대입은 SetTarget(RenderCombat 포함)과 달리 렌더 없이 PlayCard로 직행 — PlayCard가 RenderCombat 수행하므로 OK.
|
||||
- 시그니처 일관: PlayAttackFx(targetIndex,image,damage)·ShowDmgPop(slot,amount)·EnemyActStep(fromIndex). guid 230/240+i/250+i/260 비충돌(기존 0~224).
|
||||
- 리스크는 T6 메이커 검증에서 흡수(드래그 좌표 보정 +360, 거리 임계 200, ui.y>-180 스윕 기준 — 실측 튜닝 가능).
|
||||
462
docs/superpowers/plans/2026-06-11-combat-ui-overhaul.md
Normal file
462
docs/superpowers/plans/2026-06-11-combat-ui-overhaul.md
Normal file
@@ -0,0 +1,462 @@
|
||||
# 전투 화면 UI/HUD 전면 정비 (P1) 구현 계획
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 전투 화면을 STS2 배치로 재구성해 UI 겹침 0·시각 위계 확립 (기능 불변, 레이아웃·표시 로직만).
|
||||
|
||||
**Architecture:** 모든 UI/컨트롤러는 `tools/deck/gen-slaydeck.mjs` 단일 소스에서 생성(직접 편집 금지, 루트에서 `node tools/deck/gen-slaydeck.mjs`). UI 엔티티는 `upsertUi()`의 `entity()/transform()/sprite()/text()/button()` 헬퍼, 컨트롤러 Lua는 `method(Name, Code, Args?)` 템플릿 문자열(`${...}`=JS 보간). 좌표계: 부모 중심 원점, anchoredPosition.
|
||||
|
||||
**Tech Stack:** Node.js ESM 생성기, MSW Lua codeblock, JSON 산출물.
|
||||
|
||||
---
|
||||
|
||||
## 배경 (구현자용)
|
||||
|
||||
- 화면 1920×1080 중심좌표(±960, ±540). `DeckHud`=하단 1280×330(y180 bottom-center), `CardHand`=카드 5장(y180), `CombatHud`=전체 1920×1080.
|
||||
- 확인된 겹침: `DeckHud/EndTurnButton`(0,135,170×58) ↔ `DeckHud/Energy`(0,90,220×42) 5px; `AllDeckButton`(470,135)이 버린덱(590,8,132×186)과 5px 간격.
|
||||
- 기존 가시성: `HideGameHud`(전투 HUD 일괄 off)가 이미 존재(사용자 PR) — ShowState는 이를 재사용해 확장.
|
||||
- guid 네임스페이스: `guid('cmb', N)` — 기존 사용 대역: 0~10(순차 cmbN), 41~144(슬롯 6종×4). **신규는 200+ 사용**(TopBar 200~209, PlayerPanel 210~219, TargetFrame 221~224).
|
||||
- 생성기 실행 검증은 매 Task: `node --check` + `node tools/deck/gen-slaydeck.mjs` 성공 + 해당 확인 스크립트. 산출물 커밋은 Task 6에서 일괄(중간 Task는 소스만 커밋하고 산출물은 `git checkout -- ui/DefaultGroup.ui Global/common.gamelogic RootDesk/MyDesk/SlayDeckController.codeblock`로 복원).
|
||||
|
||||
## 파일 구조
|
||||
| 파일 | 책임 |
|
||||
|---|---|
|
||||
| `tools/deck/gen-slaydeck.mjs` | 전 변경(UI 좌표·신규 엔티티·컨트롤러 표시 로직) |
|
||||
| 산출물 3종 | Task 6에서 재생성·커밋 |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 하단 HUD — 에너지 오브(좌)·턴 종료(우)
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`
|
||||
|
||||
- [ ] **Step 1: Energy 텍스트 엔티티를 EnergyOrb 패널로 교체**
|
||||
|
||||
`upsertUi()`에서 `path: '/ui/DefaultGroup/DeckHud/Energy'` 엔티티 push 블록(`add(entity({ ... '에너지 3/3' ... }))`) 전체를 삭제하고, 그 자리에:
|
||||
```js
|
||||
add(entity({
|
||||
id: guid('hud', hud.length),
|
||||
path: '/ui/DefaultGroup/DeckHud/EnergyOrb',
|
||||
modelId: 'uisprite',
|
||||
entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 3,
|
||||
components: [
|
||||
transform({ parentW: 1280, parentH: 330, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 96, y: 96 }, pos: { x: -560, y: 130 }, align: ALIGN_CENTER }),
|
||||
sprite({ color: { r: 0.12, g: 0.2, b: 0.34, a: 0.95 }, type: 1 }),
|
||||
],
|
||||
}));
|
||||
add(entity({
|
||||
id: guid('hud', hud.length),
|
||||
path: '/ui/DefaultGroup/DeckHud/EnergyOrb/Value',
|
||||
modelId: 'uitext',
|
||||
entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 0,
|
||||
components: [
|
||||
transform({ parentW: 96, parentH: 96, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 92, y: 48 }, pos: { x: 0, y: 6 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '3/3', fontSize: 34, bold: true, color: { r: 0.65, g: 0.92, b: 1, a: 1 }, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
add(entity({
|
||||
id: guid('hud', hud.length),
|
||||
path: '/ui/DefaultGroup/DeckHud/EnergyOrb/Label',
|
||||
modelId: 'uitext',
|
||||
entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 1,
|
||||
components: [
|
||||
transform({ parentW: 96, parentH: 96, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 92, y: 24 }, pos: { x: 0, y: -28 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '에너지', fontSize: 14, bold: true, color: { r: 0.55, g: 0.7, b: 0.85, a: 1 }, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
```
|
||||
|
||||
- [ ] **Step 2: EndTurnButton 이동·확대**
|
||||
|
||||
`path: '/ui/DefaultGroup/DeckHud/EndTurnButton'` 엔티티의 transform 줄을
|
||||
```js
|
||||
transform({ parentW: 1280, parentH: 330, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 200, y: 64 }, pos: { x: 560, y: 130 }, align: ALIGN_CENTER }),
|
||||
```
|
||||
로 교체하고, 같은 엔티티의 `text({ value: '턴 종료', fontSize: 25, ...` 를 `fontSize: 28,` 로.
|
||||
|
||||
- [ ] **Step 3: RenderPiles 에너지 경로/포맷 갱신**
|
||||
|
||||
`method('RenderPiles', ...)` 안의
|
||||
```
|
||||
self:SetText("/ui/DefaultGroup/DeckHud/Energy", "에너지 " .. string.format("%d", self.Energy) .. "/" .. string.format("%d", self.MaxEnergy))
|
||||
```
|
||||
를
|
||||
```
|
||||
self:SetText("/ui/DefaultGroup/DeckHud/EnergyOrb/Value", string.format("%d", self.Energy) .. "/" .. string.format("%d", self.MaxEnergy))
|
||||
```
|
||||
로 교체.
|
||||
|
||||
- [ ] **Step 4: 검증** — `node --check tools/deck/gen-slaydeck.mjs` 후 실행:
|
||||
`node tools/deck/gen-slaydeck.mjs && node -e "const ui=JSON.parse(require('fs').readFileSync('ui/DefaultGroup.ui','utf8'));const p=ui.ContentProto.Entities.map(e=>e.path);console.log('orb:',p.includes('/ui/DefaultGroup/DeckHud/EnergyOrb'),'| oldEnergy gone:',!p.includes('/ui/DefaultGroup/DeckHud/Energy'))"`
|
||||
Expected: `orb: true | oldEnergy gone: true`. 그 후 산출물 복원: `git checkout -- ui/DefaultGroup.ui Global/common.gamelogic RootDesk/MyDesk/SlayDeckController.codeblock`
|
||||
|
||||
- [ ] **Step 5: Commit** — `git add tools/deck/gen-slaydeck.mjs && git commit -m "feat(combat-ui): 에너지 오브(좌)·턴 종료 버튼(우) 재배치"`
|
||||
|
||||
---
|
||||
|
||||
## Task 2: 상단 TopBar (막·골드·유물·모든덱보기 통합)
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`
|
||||
|
||||
- [ ] **Step 1: 기존 Floor/Gold/Relics 엔티티 제거**
|
||||
|
||||
`upsertUi()` CombatHud 빌드에서 `['Floor', { x: -820, y: 480 }, ...]`/`['Gold', { x: 820, y: 480 }, ...]` 루프 블록과 `path: '/ui/DefaultGroup/CombatHud/Relics'` push 블록을 삭제.
|
||||
|
||||
- [ ] **Step 2: DeckHud의 AllDeckButton 엔티티 제거**
|
||||
|
||||
`path: '/ui/DefaultGroup/DeckHud/AllDeckButton'` push 블록(레이블 텍스트 포함 엔티티 1개) 삭제.
|
||||
|
||||
- [ ] **Step 3: CombatHud에 TopBar 추가** (Result push 이전 위치에):
|
||||
```js
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 200),
|
||||
path: '/ui/DefaultGroup/CombatHud/TopBar',
|
||||
modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 9,
|
||||
components: [
|
||||
transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 1200, y: 52 }, pos: { x: 0, y: 486 }, align: ALIGN_CENTER }),
|
||||
sprite({ color: { r: 0.06, g: 0.07, b: 0.1, a: 0.82 }, type: 1 }),
|
||||
],
|
||||
}));
|
||||
const topTexts = [
|
||||
['Floor', -520, 160, '막 1/3', GOLD],
|
||||
['Gold', -360, 160, '골드 0', { r: 0.98, g: 0.85, b: 0.4, a: 1 }],
|
||||
['Relics', 60, 560, '유물: 없음', { r: 0.8, g: 0.7, b: 0.95, a: 1 }],
|
||||
];
|
||||
topTexts.forEach(([suffix, x, w, value, color], ti) => {
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 201 + ti),
|
||||
path: `/ui/DefaultGroup/CombatHud/TopBar/${suffix}`,
|
||||
modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: ti,
|
||||
components: [
|
||||
transform({ parentW: 1200, parentH: 52, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: w, y: 40 }, pos: { x: x, y: 0 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value, fontSize: suffix === 'Relics' ? 18 : 22, bold: true, color, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
});
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 205),
|
||||
path: '/ui/DefaultGroup/CombatHud/TopBar/AllDeckButton',
|
||||
modelId: 'uibutton', entryId: 'UIButton',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.ButtonComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 3,
|
||||
components: [
|
||||
transform({ parentW: 1200, parentH: 52, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 150, y: 40 }, pos: { x: 510, y: 0 } }),
|
||||
sprite({ color: DARK, type: 1, raycast: true }),
|
||||
button(),
|
||||
text({ value: '모든덱보기', fontSize: 18, bold: true, color: GOLD, alignment: 0 }),
|
||||
],
|
||||
}));
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 컨트롤러 경로 갱신** (정확 치환 3건)
|
||||
- `RenderRun`: `"/ui/DefaultGroup/CombatHud/Floor"` → `"/ui/DefaultGroup/CombatHud/TopBar/Floor"`, `"/ui/DefaultGroup/CombatHud/Gold"` → `"/ui/DefaultGroup/CombatHud/TopBar/Gold"`
|
||||
- `RenderRelics`(끝부분 SetText): `"/ui/DefaultGroup/CombatHud/Relics"` → `"/ui/DefaultGroup/CombatHud/TopBar/Relics"`
|
||||
- `BindButtons`: `"/ui/DefaultGroup/DeckHud/AllDeckButton"` → `"/ui/DefaultGroup/CombatHud/TopBar/AllDeckButton"`
|
||||
|
||||
- [ ] **Step 5: 검증** — `node --check` 후 실행:
|
||||
`node tools/deck/gen-slaydeck.mjs && node -e "const fs=require('fs');const ui=JSON.parse(fs.readFileSync('ui/DefaultGroup.ui','utf8'));const p=ui.ContentProto.Entities.map(e=>e.path);console.log('topbar:',['/TopBar','/TopBar/Floor','/TopBar/Gold','/TopBar/Relics','/TopBar/AllDeckButton'].every(s=>p.includes('/ui/DefaultGroup/CombatHud'+s)),'| old gone:',!p.includes('/ui/DefaultGroup/CombatHud/Floor')&&!p.includes('/ui/DefaultGroup/CombatHud/Relics')&&!p.includes('/ui/DefaultGroup/DeckHud/AllDeckButton'));const cb=fs.readFileSync('RootDesk/MyDesk/SlayDeckController.codeblock','utf8');console.log('paths updated:',cb.includes('TopBar/Floor')&&cb.includes('TopBar/Relics')&&cb.includes('TopBar/AllDeckButton')&&!cb.includes('DeckHud/AllDeckButton'))"`
|
||||
Expected: 모두 true. 산출물 복원(Task 1과 동일 명령).
|
||||
|
||||
- [ ] **Step 6: Commit** — `git add tools/deck/gen-slaydeck.mjs && git commit -m "feat(combat-ui): 상단 TopBar (막·골드·유물·모든덱보기 통합)"`
|
||||
|
||||
---
|
||||
|
||||
## Task 3: 플레이어 패널 + SetHpBar 폭 인자
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`
|
||||
|
||||
- [ ] **Step 1: SetHpBar에 width 인자 추가**
|
||||
|
||||
`method('SetHpBar', ...)` 전체를 다음으로 교체:
|
||||
```js
|
||||
method('SetHpBar', `local e = _EntityService:GetEntityByPath(path)
|
||||
if e == nil or e.UITransformComponent == nil then
|
||||
return
|
||||
end
|
||||
local ratio = 0
|
||||
if maxHp > 0 then ratio = hp / maxHp end
|
||||
if ratio < 0 then ratio = 0 end
|
||||
local w = width * ratio
|
||||
e.UITransformComponent.RectSize = Vector2(w, 14)`, [
|
||||
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'path' },
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'hp' },
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'maxHp' },
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'width' },
|
||||
]),
|
||||
```
|
||||
그리고 `RenderCombat` 안의 기존 호출 `self:SetHpBar(base .. "/HpBarFill", m.hp, m.maxHp)` 를 `self:SetHpBar(base .. "/HpBarFill", m.hp, m.maxHp, ${HP_BAR_W})` 로 교체.
|
||||
|
||||
- [ ] **Step 2: PlayerBg/PlayerHp/PlayerBlock 엔티티 제거 → PlayerPanel 추가**
|
||||
|
||||
`upsertUi()`에서 `path: '/ui/DefaultGroup/CombatHud/PlayerBg'` push 블록과 `playerTexts` 배열+루프를 삭제하고, 그 자리에:
|
||||
```js
|
||||
const PP = '/ui/DefaultGroup/CombatHud/PlayerPanel';
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 210), path: PP, modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 5,
|
||||
components: [
|
||||
transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 300, y: 96 }, pos: { x: -760, y: -480 }, align: ALIGN_CENTER }),
|
||||
sprite({ color: PANEL_BG, type: 1 }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 211), path: `${PP}/Name`, modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 0,
|
||||
components: [
|
||||
transform({ parentW: 300, parentH: 96, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 280, y: 28 }, pos: { x: 0, y: 28 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '플레이어', fontSize: 18, bold: true, color: GOLD, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 212), path: `${PP}/HpBarBg`, modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 1,
|
||||
components: [
|
||||
transform({ parentW: 300, parentH: 96, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 220, y: 16 }, pos: { x: 16, y: -6 } }),
|
||||
sprite({ color: { r: 0.18, g: 0.05, b: 0.06, a: 1 }, type: 1 }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 213), path: `${PP}/HpBarFill`, modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 2,
|
||||
components: [
|
||||
transform({ parentW: 300, parentH: 96, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0, y: 0.5 }, size: { x: 220, y: 16 }, pos: { x: -94, y: -6 } }),
|
||||
sprite({ color: { r: 0.3, g: 0.78, b: 0.36, a: 1 }, type: 1 }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 214), path: `${PP}/HpText`, modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 3,
|
||||
components: [
|
||||
transform({ parentW: 300, parentH: 96, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 220, y: 24 }, pos: { x: 16, y: -30 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '80/80', fontSize: 16, bold: true, color: { r: 1, g: 1, b: 1, a: 1 }, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
const blockBadge = entity({
|
||||
id: guid('cmb', 215), path: `${PP}/BlockBadge`, modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 4,
|
||||
components: [
|
||||
transform({ parentW: 300, parentH: 96, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 44, y: 40 }, pos: { x: -122, y: -12 } }),
|
||||
sprite({ color: { r: 0.32, g: 0.5, b: 0.85, a: 1 }, type: 1 }),
|
||||
],
|
||||
});
|
||||
blockBadge.jsonString.enable = false;
|
||||
combat.push(blockBadge);
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 216), path: `${PP}/BlockBadge/Value`, modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 0,
|
||||
components: [
|
||||
transform({ parentW: 44, parentH: 40, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 44, y: 36 }, pos: { x: 0, y: 0 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '0', fontSize: 18, bold: true, color: { r: 1, g: 1, b: 1, a: 1 }, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
```
|
||||
|
||||
- [ ] **Step 3: RenderCombat 플레이어부 교체**
|
||||
|
||||
`RenderCombat` 끝의
|
||||
```
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/PlayerHp", "HP " .. string.format("%d", self.PlayerHp) .. "/" .. string.format("%d", self.PlayerMaxHp))
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/PlayerBlock", "방어 " .. string.format("%d", self.PlayerBlock))
|
||||
```
|
||||
를
|
||||
```
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/PlayerPanel/HpText", string.format("%d", self.PlayerHp) .. "/" .. string.format("%d", self.PlayerMaxHp))
|
||||
self:SetHpBar("/ui/DefaultGroup/CombatHud/PlayerPanel/HpBarFill", self.PlayerHp, self.PlayerMaxHp, 220)
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CombatHud/PlayerPanel/BlockBadge", self.PlayerBlock > 0)
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/PlayerPanel/BlockBadge/Value", string.format("%d", self.PlayerBlock))
|
||||
```
|
||||
로 교체.
|
||||
|
||||
- [ ] **Step 4: 검증** — `node --check` 후 실행+확인:
|
||||
`node tools/deck/gen-slaydeck.mjs && node -e "const fs=require('fs');const ui=JSON.parse(fs.readFileSync('ui/DefaultGroup.ui','utf8'));const p=ui.ContentProto.Entities.map(e=>e.path);console.log('panel:',p.includes('/ui/DefaultGroup/CombatHud/PlayerPanel/HpBarFill'),'| old gone:',!p.includes('/ui/DefaultGroup/CombatHud/PlayerHp'));const cb=JSON.parse(fs.readFileSync('RootDesk/MyDesk/SlayDeckController.codeblock','utf8'));const m=cb.ContentProto.Json.Methods.find(x=>x.Name==='SetHpBar');console.log('width arg:',m.Arguments.length===4)"`
|
||||
Expected: 모두 true. 산출물 복원.
|
||||
|
||||
- [ ] **Step 5: Commit** — `git add tools/deck/gen-slaydeck.mjs && git commit -m "feat(combat-ui): 플레이어 패널(HP바·방어 뱃지) + SetHpBar 폭 인자"`
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 타겟 프레임 + 몬스터 슬롯 가독성 + 의도 색상
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`
|
||||
|
||||
- [ ] **Step 1: 슬롯 루프에 TargetFrame 추가 + 가독성 조정**
|
||||
|
||||
`upsertUi()` 몬스터 슬롯 루프(`for (let i = 1; i <= MAX_MONSTERS; i++)`)에서:
|
||||
1. 슬롯 컨테이너 push 직후, Name push 이전에 추가:
|
||||
```js
|
||||
const targetFrame = entity({
|
||||
id: guid('cmb', 220 + i), path: `${base}/TargetFrame`, modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 0,
|
||||
components: [
|
||||
transform({ parentW: SLOT_W, parentH: SLOT_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: SLOT_W + 16, y: SLOT_H + 12 }, pos: { x: 0, y: 0 } }),
|
||||
sprite({ color: { r: 0.95, g: 0.78, b: 0.25, a: 0.28 }, type: 1 }),
|
||||
],
|
||||
});
|
||||
targetFrame.jsonString.enable = false;
|
||||
combat.push(targetFrame);
|
||||
```
|
||||
2. Name/Hp/HpBarBg/HpBarFill/Intent의 `displayOrder`를 각각 1/2/3/4/5로 +1.
|
||||
3. Name `fontSize: 20` → `22`, Hp `fontSize: 18` → `20`.
|
||||
4. 파일 상단 `const HP_BAR_W = 120;` → `const HP_BAR_W = 140;` (몬스터 바 폭 확대 — HpBarBg/Fill·RenderCombat 보간이 모두 이 상수 사용).
|
||||
|
||||
- [ ] **Step 2: RenderCombat 몬스터부 — [타겟] 제거·TargetFrame·의도 색상**
|
||||
|
||||
`RenderCombat`의 몬스터 루프 본문에서
|
||||
```
|
||||
if i == self.TargetIndex then t = "[타겟] " .. t end
|
||||
self:SetText(base .. "/Intent", t)
|
||||
```
|
||||
를
|
||||
```
|
||||
self:SetText(base .. "/Intent", t)
|
||||
self:SetEntityEnabled(base .. "/TargetFrame", i == self.TargetIndex)
|
||||
local intentEntity = _EntityService:GetEntityByPath(base .. "/Intent")
|
||||
if intentEntity ~= nil and intentEntity.TextComponent ~= nil and intent ~= nil then
|
||||
if intent.kind == "Attack" then
|
||||
intentEntity.TextComponent.FontColor = Color(1, 0.45, 0.35, 1)
|
||||
else
|
||||
intentEntity.TextComponent.FontColor = Color(0.5, 0.75, 1, 1)
|
||||
end
|
||||
end
|
||||
```
|
||||
로 교체.
|
||||
|
||||
- [ ] **Step 3: 검증** — `node --check` 후 실행+확인:
|
||||
`node tools/deck/gen-slaydeck.mjs && node -e "const fs=require('fs');const ui=JSON.parse(fs.readFileSync('ui/DefaultGroup.ui','utf8'));const tf=ui.ContentProto.Entities.filter(e=>e.path.endsWith('/TargetFrame')).length;const cb=fs.readFileSync('RootDesk/MyDesk/SlayDeckController.codeblock','utf8');console.log('frames:',tf,'| no [타겟]:',!cb.includes('[타겟]'),'| color:',cb.includes('FontColor = Color(1, 0.45'))"`
|
||||
Expected: `frames: 4 | no [타겟]: true | color: true`. 산출물 복원.
|
||||
|
||||
- [ ] **Step 4: Commit** — `git add tools/deck/gen-slaydeck.mjs && git commit -m "feat(combat-ui): 타겟 프레임·몬스터 슬롯 가독성·의도 색상"`
|
||||
|
||||
---
|
||||
|
||||
## Task 5: ShowState 가시성 통일 + Result 정리
|
||||
|
||||
**Files:** Modify `tools/deck/gen-slaydeck.mjs`
|
||||
|
||||
- [ ] **Step 1: ShowState 메서드 추가** (`HideGameHud` 메서드 바로 다음에):
|
||||
```js
|
||||
method('ShowState', `self:HideGameHud()
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/MainMenu", state == "menu")
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CharacterSelectHud", state == "charselect")
|
||||
if state == "map" then
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/MapHud", true)
|
||||
elseif state == "combat" then
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CombatHud", true)
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/DeckHud", true)
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CardHand", true)
|
||||
elseif state == "shop" then
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/ShopHud", true)
|
||||
elseif state == "rest" then
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/RestHud", true)
|
||||
end`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'state' }]),
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 호출부 치환** (각각 정확 치환)
|
||||
1. `ShowMainMenu`:
|
||||
```
|
||||
self:HideGameHud()
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/MainMenu", true)
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CharacterSelectHud", false)
|
||||
```
|
||||
→ `self:ShowState("menu")`
|
||||
2. `ShowCharacterSelect`:
|
||||
```
|
||||
self:HideGameHud()
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/MainMenu", false)
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CharacterSelectHud", true)
|
||||
```
|
||||
→ `self:ShowState("charselect")`
|
||||
3. `StartNewGame`의
|
||||
```
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/MainMenu", false)
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CharacterSelectHud", false)
|
||||
```
|
||||
→ 삭제(StartRun→ShowMap이 ShowState("map")으로 처리).
|
||||
4. `StartCombat` 첫 4줄
|
||||
```
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/MapHud", false)
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/DeckHud", true)
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CardHand", true)
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CombatHud", true)
|
||||
```
|
||||
→
|
||||
```
|
||||
self:ShowState("combat")
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CombatHud/Result", false)
|
||||
```
|
||||
5. `ShowMap` 첫 3줄(`DeckHud/CardHand/CombatHud` off) → `self:ShowState("map")` (그 아래 `RenderMap`·MapHud enable 블록에서 MapHud enable 부분은 중복되지만 무해 — 기존 `local hud = ...MapHud... hud.Enable = true` 블록은 삭제).
|
||||
6. `ShowShop` 끝의 ShopHud enable 블록(`local hud = ...ShopHud ... end`) → `self:ShowState("shop")` (RenderShop 호출은 유지).
|
||||
7. `ShowRest` 끝의 RestHud enable 블록 → `self:ShowState("rest")` (텍스트·RenderCombat 호출 유지).
|
||||
8. `LeaveNode`는 기존 그대로(ShowMap 경유).
|
||||
|
||||
- [ ] **Step 3: 검증** — `node --check` 후 실행+확인:
|
||||
`node tools/deck/gen-slaydeck.mjs && node -e "const cb=JSON.parse(require('fs').readFileSync('RootDesk/MyDesk/SlayDeckController.codeblock','utf8'));const names=cb.ContentProto.Json.Methods.map(m=>m.Name);const s=JSON.stringify(cb);console.log('ShowState:',names.includes('ShowState'),'| StartCombat resets Result:',/ShowState\(\\\"combat\\\"\)[\s\S]{0,200}Result/.test(s))"`
|
||||
Expected: 둘 다 true. 산출물 복원.
|
||||
|
||||
- [ ] **Step 4: Commit** — `git add tools/deck/gen-slaydeck.mjs && git commit -m "feat(combat-ui): ShowState 가시성 통일 + 전투 시작 시 Result 초기화"`
|
||||
|
||||
---
|
||||
|
||||
## Task 6: 재생성 · 겹침 정적 검사 · 산출물 커밋
|
||||
|
||||
**Files:** 산출물 3종
|
||||
|
||||
- [ ] **Step 1: 재생성** — `node tools/deck/gen-slaydeck.mjs` (exit 0)
|
||||
|
||||
- [ ] **Step 2: JSON·중복 id·결정성**
|
||||
`node -e "const fs=require('fs');for(const f of ['ui/DefaultGroup.ui','Global/common.gamelogic','RootDesk/MyDesk/SlayDeckController.codeblock'])JSON.parse(fs.readFileSync(f,'utf8'));const ui=JSON.parse(fs.readFileSync('ui/DefaultGroup.ui','utf8'));const ids=ui.ContentProto.Entities.map(e=>e.id);console.log('dup:',ids.filter((x,i)=>ids.indexOf(x)!==i).length)"` → `dup: 0`
|
||||
그리고 `git add -A` 후 `node tools/deck/gen-slaydeck.mjs` 재실행 → `git diff --stat` 비어있음(결정적).
|
||||
|
||||
- [ ] **Step 3: 하단 HUD 겹침 정적 검사** (AABB 페어와이즈):
|
||||
`node -e "const ui=JSON.parse(require('fs').readFileSync('ui/DefaultGroup.ui','utf8'));const E=ui.ContentProto.Entities;const get=p=>E.find(e=>e.path===p);const box=p=>{const e=get(p);const t=e.jsonString['@components'].find(c=>c['@type']==='MOD.Core.UITransformComponent');return {p,x:t.anchoredPosition.x,y:t.anchoredPosition.y,w:t.RectSize.x,h:t.RectSize.y};};const items=['/ui/DefaultGroup/DeckHud/EnergyOrb','/ui/DefaultGroup/DeckHud/EndTurnButton','/ui/DefaultGroup/DeckHud/DrawPile','/ui/DefaultGroup/DeckHud/DiscardPile'].map(box);const hit=(a,b)=>Math.abs(a.x-b.x)*2<(a.w+b.w)&&Math.abs(a.y-b.y)*2<(a.h+b.h);let bad=0;for(let i=0;i<items.length;i++)for(let j=i+1;j<items.length;j++)if(hit(items[i],items[j])){bad++;console.log('OVERLAP',items[i].p,items[j].p);}console.log(bad===0?'no overlap ✓':'OVERLAPS:'+bad)"`
|
||||
Expected: `no overlap ✓`
|
||||
|
||||
- [ ] **Step 4: sim 회귀** — `node --test tools/balance/sim-balance.test.mjs` → 14/14
|
||||
|
||||
- [ ] **Step 5: Commit** — `git add ui/DefaultGroup.ui Global/common.gamelogic RootDesk/MyDesk/SlayDeckController.codeblock && git commit -m "feat(combat-ui): UI 정비 산출물 재생성"`
|
||||
|
||||
---
|
||||
|
||||
## Task 7: 메이커 플레이테스트 (수동/MCP — 컨트롤러 주도)
|
||||
|
||||
maker MCP: refresh → build log 0 → play. `execute_script`로 상태 전환하며 스크린샷:
|
||||
1. 초기(menu): 메인메뉴만, 전투 HUD 비침 없음
|
||||
2. `s:ShowCharacterSelect()` → 캐릭터선택만
|
||||
3. `s.SelectedClass="warrior"; s:StartNewGame()` → 맵(MapHud만)
|
||||
4. `s:PickNode("A")` → 전투: TopBar(막/골드/유물/모든덱보기)·에너지 오브(좌)·턴종료(우)·플레이어 패널(HP바)·타겟 프레임(1번 슬롯 골드 하이라이트)
|
||||
5. `s:SetTarget(2)` → 프레임 이동 확인, `s:PlayCard(<방어 슬롯>)` → 방어 뱃지 표시
|
||||
6. 전체 처치 → 보상 → `s:PickReward(1)` → 맵 복귀
|
||||
7. 상점(D)·휴식(C) 화면
|
||||
겹침·비침 발견 시 좌표 조정 → 재생성 → reload → 재확인 → 산출물 커밋(`fix(combat-ui): 플레이테스트 좌표 튜닝`).
|
||||
|
||||
---
|
||||
|
||||
## Self-Review 결과
|
||||
- **스펙 커버리지**: §3.1→T1, §3.2→T2, §3.3→T3, §3.4→T4, §3.5→T5(HideGameHud 재사용으로 구현 — 스펙 의도 동일), §3.6→T7에서 확인(채팅 숨김 API는 비차단), 검증§6→T6·T7. 전 항목 매핑.
|
||||
- **플레이스홀더 없음**: 모든 단계 실제 코드/명령 포함.
|
||||
- **타입/이름 일관성**: `EnergyOrb/Value`·`TopBar/{Floor,Gold,Relics,AllDeckButton}`·`PlayerPanel/{Name,HpBarBg,HpBarFill,HpText,BlockBadge/Value}`·`TargetFrame`·`SetHpBar(path,hp,maxHp,width)`·`ShowState(state)` — Task 간 일치. guid 대역 200~224 기존(0~10·41~144)과 비충돌.
|
||||
- **주의**: T2 Step 1에서 Floor/Gold 루프 제거 시 그 루프가 쓰던 `cmbN` 증가가 사라져 후속 Relics/Result id가 변함 — 전부 재생성이라 무해. T5의 ShowMap 치환 시 기존 MapHud enable 블록 삭제 누락하면 중복(무해하나 정리).
|
||||
79
docs/superpowers/plans/2026-06-11-system-gaps.md
Normal file
79
docs/superpowers/plans/2026-06-11-system-gaps.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# 시스템 갭 보완 (P5) 구현 계획
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development. T3·T5는 컨트롤러 직접.
|
||||
|
||||
**Goal:** 경제 밸런스(첫 상점 구매 가능), 신규 카드 2종+복합 효과, 적 패턴 보강, 런 종료 후 메뉴 복귀.
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 데이터+상수 (경제·적 패턴·신규 카드 골격)
|
||||
|
||||
**Files:** `data/enemies.json`, `data/cards.json`, `tools/deck/gen-slaydeck.mjs`(상수·elite 골드)
|
||||
|
||||
- [ ] enemies.json 의도 패턴 교체(스펙 §2.C 표 그대로; slime 3종·king_slime 유지).
|
||||
- [ ] cards.json에 추가(이미지는 T3에서 채움 — 일단 필드 생략):
|
||||
```json
|
||||
"WarLeap": { "name": "워 리프", "cost": 1, "kind": "Attack", "damage": 4, "block": 3, "desc": "피해 4, 방어도 3" },
|
||||
"Brandish": { "name": "브랜디시", "cost": 2, "kind": "Attack", "damage": 13, "desc": "피해 13" }
|
||||
```
|
||||
- [ ] gen-slaydeck: `GOLD_PER_WIN = 15` → `25`; CheckCombatEnd elite 분기(AddRelic 줄 옆)에 `self.Gold = self.Gold + 15` 추가.
|
||||
- [ ] 검증: JSON 파스, gen-slaydeck 실행 OK(산출물 복원), sim 통과(기존 fixture 무관).
|
||||
- [ ] Commit: `feat(system-gaps): 경제 상향(승리25·엘리트+15)·적 패턴 보강·신규 카드 2종 데이터`
|
||||
|
||||
## Task 2: 복합 카드 로직 + EndRun 복귀 + sim
|
||||
|
||||
**Files:** `tools/deck/gen-slaydeck.mjs`, `tools/balance/sim-balance.mjs`, `tools/balance/sim-balance.test.mjs`
|
||||
|
||||
- [ ] **sim 테스트 먼저** (test 파일에 추가):
|
||||
```js
|
||||
test('simulateCombat: Attack 카드의 block 필드도 적용(복합 카드)', () => {
|
||||
const data = {
|
||||
cards: { Combo: { name: '콤보', cost: 1, kind: 'Attack', damage: 4, block: 3 } },
|
||||
starterDeck: ['Combo', 'Combo', 'Combo', 'Combo', 'Combo'],
|
||||
monsters: [{ name: '적', maxHp: 9, intents: [{ kind: 'Attack', value: 5 }] }],
|
||||
};
|
||||
const r = simulateCombat(data, mulberry32(1));
|
||||
assert.equal(r.win, true); // 3코스트 내 3장: 12딤>9 → 1턴 승리(블록 적용 여부와 무관하게 승리하지만)
|
||||
assert.equal(r.playerHpRemaining, 80); // 피해 받기 전 승리 — 블록 검증은 아래 시나리오로
|
||||
});
|
||||
test('simulateCombat: 복합 카드 블록이 적 공격을 흡수', () => {
|
||||
const data = {
|
||||
cards: { Combo: { name: '콤보', cost: 1, kind: 'Attack', damage: 1, block: 3 } },
|
||||
starterDeck: ['Combo', 'Combo', 'Combo', 'Combo', 'Combo'],
|
||||
monsters: [{ name: '적', maxHp: 100, intents: [{ kind: 'Attack', value: 9 }] }],
|
||||
};
|
||||
const r = simulateCombat(data, mulberry32(1));
|
||||
// 1턴: 3장 사용 → 블록 9 → 적 공격 9 전부 흡수 → 2턴 시작 HP 80 유지 확인 위해 2턴 후 비교 불가(루프) — 간접: MAX_TURNS 도달 draw, hp가 (80 - 0*몇턴)...
|
||||
// 단순 명제: 블록 미적용이면 매턴 -9 → 100/9≈11턴 내 사망. 블록 적용이면 매턴 9블록=무피해 → draw.
|
||||
assert.equal(r.draw, true);
|
||||
assert.equal(r.playerHpRemaining, 80);
|
||||
});
|
||||
```
|
||||
- [ ] sim 구현: simulateCombat Attack 분기에 `if (c.block) pBlock += c.block;` 추가(스탯 bump의 block 합산도 `c.block || 0`로). 테스트 통과.
|
||||
- [ ] gen-slaydeck PlayCard Attack 분기에 추가(PlayAttackFx 호출 다음 줄):
|
||||
```
|
||||
if c.block ~= nil then
|
||||
self.PlayerBlock = self.PlayerBlock + c.block
|
||||
end
|
||||
```
|
||||
- [ ] gen-slaydeck EndRun: 신규 메서드 + CheckCombatEnd 두 지점 교체:
|
||||
```js
|
||||
method('EndRun', `self:ShowResult(text)
|
||||
self.RunActive = false
|
||||
_TimerService:SetTimerOnce(function() self:ShowMainMenu() end, 4)`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'text' }]),
|
||||
```
|
||||
교체: `self:ShowResult("런 클리어!")` + `self.RunActive = false` → `self:EndRun("런 클리어!")`; `self:ShowResult("패배...")` + `self.RunActive = false` → `self:EndRun("패배...")`.
|
||||
- [ ] 검증: sim 전체 통과(16개), gen 실행·심볼 확인 후 산출물 복원.
|
||||
- [ ] Commit: `feat(system-gaps): 복합 카드(피해+방어)·런 종료 후 메뉴 복귀(EndRun)`
|
||||
|
||||
## Task 3 (컨트롤러 직접): 신규 카드 이미지 수확
|
||||
- "워 리프"/"브랜디시" 검색→메이커 선별→cards.json image 채움→커밋.
|
||||
|
||||
## Task 4: 재생성·검증·산출물 커밋 (T3 이후)
|
||||
- 표준 절차 + `node tools/balance/sim-balance.mjs 2000` 결과 기록(참고).
|
||||
|
||||
## Task 5 (컨트롤러 직접): 메이커 검증+푸시+PR+머지
|
||||
- 보상/상점 신규 카드(이미지)·복합 카드 효과·엘리트 골드·패배→4s 메뉴 복귀. 스크린샷.
|
||||
|
||||
## Self-Review
|
||||
- §2.A→T1, §2.B→T1(데이터)+T2(로직)+T3(이미지), §2.C→T1, §2.D→T2. 시그니처 일관(EndRun(text)). 복합 카드 sim 테스트는 블록 적용을 draw/hp로 결정적으로 판별.
|
||||
23
docs/superpowers/plans/2026-06-12-ascension.md
Normal file
23
docs/superpowers/plans/2026-06-12-ascension.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# P11 — 승천 + UserDataStorage 구현 계획
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:executing-plans. 설계: `2026-06-12-ascension-design.md`
|
||||
|
||||
### Task 1: 생성기 — ExecSpace 보존 + 서버 RPC 3종
|
||||
- [ ] `for m of Methods: m.ExecSpace = 6` → `if (m.ExecSpace === 0) m.ExecSpace = 6;` (명시값 보존)
|
||||
- [ ] props: `AscensionLevel`(number 0)·`AscensionUnlocked`(number 0)
|
||||
- [ ] `ReqLoadAscension(userId)`[ExecSpace 1]·`RecvAscension(n, userId)`[2]·`SaveAscension(n, userId)`[1] — 설계 코드 그대로, OnBeginPlay(6)에서 LocalPlayer.UserId로 ReqLoad
|
||||
- [ ] 커밋
|
||||
|
||||
### Task 2: 생성기 — 모디파이어·해금·메뉴 UI
|
||||
- [ ] 헬퍼 5종(AscHpMult/AscAtkMult/AscEliteBonus/AscGoldMult/AscStartHpPenalty) + StartRun/BuildMonsters/CheckCombatEnd/RenderRun 적용
|
||||
- [ ] EndRun 클리어 분기: 해금+1·SaveAscension·"런 클리어! 승천 N 해금!"
|
||||
- [ ] MainMenu `AscMinus/AscLabel/AscPlus` + `AdjustAscension`/`RenderAscension` + BindMenuButtons 연결
|
||||
- [ ] 커밋
|
||||
|
||||
### Task 3: 재생성·메이커 검증·PR
|
||||
- [ ] 재생성·테스트 44건 유지·grep -c 카운트 → 커밋
|
||||
- [ ] 메이커: 메뉴 승천 라벨/[-][+]·승천2로 런 시작(HP·적 배율 로그 확인)·강제 클리어→해금+1·재플레이 로드 → 스크린샷
|
||||
- [ ] push → gitea-pr.mjs PR·머지 → main pull → 메모리 갱신
|
||||
|
||||
## Self-Review
|
||||
- RPC 파라미터 any 금지(허용 타입: string/number) 준수 ✓ / RecvAscension 마지막 인자 userId(특정 클라 응답) ✓ / 시뮬 비대상 명시 ✓
|
||||
377
docs/superpowers/plans/2026-06-12-buffs-power.md
Normal file
377
docs/superpowers/plans/2026-06-12-buffs-power.md
Normal file
@@ -0,0 +1,377 @@
|
||||
# P6 — 버프/디버프·Power 카드·적 방어도 UI 구현 계획
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** StS 표준 약화·취약·힘 버프 시스템 + Power 카드 kind + 적 방어도 배지 UI를 데이터 주도로 구현.
|
||||
|
||||
**Architecture:** `data/cards.json`·`enemies.json` 스키마 확장 → `tools/deck/gen-slaydeck.mjs`의 Lua 생성부(상태 props·전투 메서드·UI 엔티티) 확장 → 산출물 재생성. 밸런스 시뮬(`tools/balance/sim-balance.mjs`)에 동일 규칙 재현.
|
||||
|
||||
**Tech Stack:** Node.js(생성기·시뮬), MSW Lua(생성물), node:test.
|
||||
|
||||
설계 문서: `docs/superpowers/specs/2026-06-12-buffs-power-design.md`
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 신규 카드 이미지 RUID 선별 (메이커)
|
||||
|
||||
**Files:** 없음 (RUID 4개 확보가 산출물)
|
||||
|
||||
- [ ] **Step 1**: `asset_search_resources`(cat=sprite, source=maplestory)로 후보 수집 — 쿼리: "차지 블로우", "위협", "인레이지", "분노" (결과 빈약 시 "스킬", "버프" 등 보조 쿼리)
|
||||
- [ ] **Step 2**: 메이커 Play Test 상태에서 `maker_execute_script`(client)로 후보 RUID를 UIGroup에 격자 배치(아래 패턴) 후 `maker_screenshot`으로 확인, 카드당 1개 선별
|
||||
|
||||
```lua
|
||||
-- 후보 미리보기 패턴 (client 컨텍스트)
|
||||
local ruids = { "<ruid1>", "<ruid2>", "..." }
|
||||
local root = _EntityService:GetEntityByPath("/ui/DefaultGroup")
|
||||
for i = 1, #ruids do
|
||||
local e = _SpawnService:SpawnByModelId("model://uisprite", "RuidPreview" .. i, Vector3(0,0,0), root)
|
||||
e.SpriteGUIRendererComponent.ImageRUID = ruids[i]
|
||||
e.UITransformComponent.anchoredPosition = Vector2(-600 + ((i-1) % 8) * 160, 200 - math.floor((i-1) / 8) * 160)
|
||||
e.UITransformComponent.RectSize = Vector2(140, 140)
|
||||
end
|
||||
```
|
||||
|
||||
- [ ] **Step 3**: 미리보기 엔티티 제거(스크립트로 Destroy) 후 플레이 종료
|
||||
|
||||
### Task 2: 카드·적 데이터 확장
|
||||
|
||||
**Files:**
|
||||
- Modify: `data/cards.json`
|
||||
- Modify: `data/enemies.json`
|
||||
|
||||
- [ ] **Step 1**: `data/cards.json`의 `cards`에 4종 추가 (image는 Task 1 선별값)
|
||||
|
||||
```json
|
||||
"ChargedBlow": { "name": "차지 블로우", "cost": 2, "kind": "Attack", "damage": 8, "vuln": 2, "desc": "피해 8, 취약 2", "image": "<선별RUID>" },
|
||||
"Threaten": { "name": "위협", "cost": 0, "kind": "Skill", "weak": 2, "desc": "약화 2 부여", "image": "<선별RUID>" },
|
||||
"Enrage": { "name": "인레이지", "cost": 1, "kind": "Skill", "strength": 2, "desc": "힘 +2", "image": "<선별RUID>" },
|
||||
"Rage": { "name": "분노", "cost": 1, "kind": "Power", "powerEffect": "strengthPerTurn", "value": 1, "desc": "매 턴 시작 시 힘 +1", "image": "<선별RUID>" }
|
||||
```
|
||||
|
||||
- [ ] **Step 2**: `data/enemies.json` 인텐트에 Debuff 추가 — mushmom에 `{ "kind": "Debuff", "effect": "weak", "value": 2 }` (intents 2번째로 삽입), slime_elite에 `{ "kind": "Debuff", "effect": "weak", "value": 1 }` (마지막), slime_boss·king_slime에 `{ "kind": "Debuff", "effect": "vuln", "value": 2 }` (Defend 다음), modified_snail에 `{ "kind": "Debuff", "effect": "weak", "value": 1 }` (마지막)
|
||||
- [ ] **Step 3**: 커밋 `feat(buffs-power): 신규 카드 4종·적 디버프 인텐트 데이터`
|
||||
|
||||
### Task 3: 생성기 — 직렬화·상태·전투 규칙
|
||||
|
||||
**Files:**
|
||||
- Modify: `tools/deck/gen-slaydeck.mjs` (luaCardsTable ~line 64, props ~1888, StartCombat ~2001, BuildMonsters ~2040, StartPlayerTurn ~2184, EndPlayerTurn ~2191, PlayCard ~2410, DealDamageToTarget ~2520, EnemyActStep ~2599, ApplyCardFace ~2347)
|
||||
|
||||
- [ ] **Step 1**: `luaCardsTable`에 신규 필드 직렬화 추가
|
||||
|
||||
```js
|
||||
if (c.strength != null) fields.push(`strength = ${c.strength}`);
|
||||
if (c.weak != null) fields.push(`weak = ${c.weak}`);
|
||||
if (c.vuln != null) fields.push(`vuln = ${c.vuln}`);
|
||||
if (c.powerEffect != null) fields.push(`powerEffect = ${luaStr(c.powerEffect)}`);
|
||||
if (c.value != null) fields.push(`value = ${c.value}`);
|
||||
```
|
||||
|
||||
- [ ] **Step 2**: props 추가 — `prop('number', 'PlayerStr', '0')`, `prop('number', 'PlayerWeak', '0')`, `prop('number', 'PlayerVuln', '0')`, `prop('any', 'PlayerPowers')`
|
||||
- [ ] **Step 3**: `StartCombat`에 리셋 추가 (`self.PlayerBlock = 0` 다음 줄)
|
||||
|
||||
```lua
|
||||
self.PlayerStr = 0
|
||||
self.PlayerWeak = 0
|
||||
self.PlayerVuln = 0
|
||||
self.PlayerPowers = {}
|
||||
```
|
||||
|
||||
- [ ] **Step 4**: `BuildMonsters`의 몬스터 테이블 생성에 `str = 0, weak = 0, vuln = 0` 필드 추가 (기존 `block = 0` 자리 옆)
|
||||
- [ ] **Step 5**: 플레이어 공격 피해 헬퍼 `CalcPlayerAttack` 메서드 신설 + `PlayCard`의 Attack 분기를 수정 — `c.damage`에 힘·약화 적용한 값을 `PlayAttackFx`에 전달. 버프 필드 공통 처리(Attack/Skill 양쪽): `strength`/`weak`/`vuln` 적용
|
||||
|
||||
```lua
|
||||
-- method CalcPlayerAttack(base) → number
|
||||
local dmg = base + self.PlayerStr
|
||||
if self.PlayerWeak > 0 then
|
||||
dmg = math.floor(dmg * 0.75)
|
||||
end
|
||||
return dmg
|
||||
```
|
||||
|
||||
```lua
|
||||
-- PlayCard 내 교체 (Attack 분기)
|
||||
if c.kind == "Attack" then
|
||||
if c.damage ~= nil then
|
||||
self:PlayAttackFx(self.TargetIndex, c.image, self:CalcPlayerAttack(c.damage))
|
||||
end
|
||||
if c.block ~= nil then
|
||||
self.PlayerBlock = self.PlayerBlock + c.block
|
||||
end
|
||||
self:ApplyRelics("cardPlayed")
|
||||
elseif c.kind == "Skill" then
|
||||
if c.block ~= nil then
|
||||
self.PlayerBlock = self.PlayerBlock + c.block
|
||||
end
|
||||
elseif c.kind == "Power" then
|
||||
if c.powerEffect ~= nil then
|
||||
table.insert(self.PlayerPowers, cardId)
|
||||
end
|
||||
end
|
||||
-- 공통 버프/디버프 적용 (kind 분기 아래, table.remove 위)
|
||||
if c.strength ~= nil then
|
||||
self.PlayerStr = self.PlayerStr + c.strength
|
||||
end
|
||||
if c.weak ~= nil or c.vuln ~= nil then
|
||||
local tm = self.Monsters[self.TargetIndex]
|
||||
if tm ~= nil and tm.alive == true then
|
||||
if c.weak ~= nil then tm.weak = tm.weak + c.weak end
|
||||
if c.vuln ~= nil then tm.vuln = tm.vuln + c.vuln end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
- [ ] **Step 6**: Power 소멸 처리 — `PlayCard`의 `table.insert(self.DiscardPile, cardId)`를 조건부로
|
||||
|
||||
```lua
|
||||
table.remove(self.Hand, slot)
|
||||
if c.kind ~= "Power" then
|
||||
table.insert(self.DiscardPile, cardId)
|
||||
end
|
||||
```
|
||||
|
||||
- [ ] **Step 7**: `DealDamageToTarget`에 취약 배수 (block 차감 **이전**)
|
||||
|
||||
```lua
|
||||
local dmg = amount
|
||||
if m.vuln > 0 then
|
||||
dmg = math.floor(dmg * 1.5)
|
||||
end
|
||||
```
|
||||
|
||||
- [ ] **Step 8**: `EnemyActStep` — Debuff 인텐트 처리 + 적 공격 피해 공식 + 행동 후 적 디버프 감소
|
||||
|
||||
```lua
|
||||
if intent.kind == "Attack" then
|
||||
local atk = intent.value + m.str
|
||||
if m.weak > 0 then
|
||||
atk = math.floor(atk * 0.75)
|
||||
end
|
||||
if self.PlayerVuln > 0 then
|
||||
atk = math.floor(atk * 1.5)
|
||||
end
|
||||
local before = self.PlayerHp
|
||||
self:DealDamageToPlayer(atk)
|
||||
self:ShowPlayerDmgPop(before - self.PlayerHp)
|
||||
elseif intent.kind == "Defend" then
|
||||
m.block = m.block + intent.value
|
||||
elseif intent.kind == "Debuff" then
|
||||
if intent.effect == "weak" then
|
||||
self.PlayerWeak = self.PlayerWeak + intent.value
|
||||
elseif intent.effect == "vuln" then
|
||||
self.PlayerVuln = self.PlayerVuln + intent.value
|
||||
end
|
||||
end
|
||||
-- intentIdx 갱신 직후
|
||||
if m.weak > 0 then m.weak = m.weak - 1 end
|
||||
if m.vuln > 0 then m.vuln = m.vuln - 1 end
|
||||
```
|
||||
|
||||
- [ ] **Step 9**: `EndPlayerTurn`에 플레이어 디버프 감소 (`self:EnemyTurn()` 직전)
|
||||
|
||||
```lua
|
||||
if self.PlayerWeak > 0 then self.PlayerWeak = self.PlayerWeak - 1 end
|
||||
if self.PlayerVuln > 0 then self.PlayerVuln = self.PlayerVuln - 1 end
|
||||
```
|
||||
|
||||
- [ ] **Step 10**: `StartPlayerTurn`에 파워 발동 (`self:ApplyRelics("turnStart")` 다음)
|
||||
|
||||
```lua
|
||||
if self.PlayerPowers ~= nil then
|
||||
for i = 1, #self.PlayerPowers do
|
||||
local pc = self.Cards[self.PlayerPowers[i]]
|
||||
if pc ~= nil and pc.powerEffect == "strengthPerTurn" then
|
||||
self.PlayerStr = self.PlayerStr + pc.value
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
- [ ] **Step 11**: `ApplyCardFace` kind 색 분기에 `elseif c.kind == "Power" then` → `Color(0.46, 0.68, 0.52, 1)` 명시 (기존 else를 Power로)
|
||||
- [ ] **Step 12**: 커밋 `feat(buffs-power): 버프/디버프·Power 전투 규칙 (생성기)`
|
||||
|
||||
### Task 4: 생성기 — UI (적 방어도 배지·버프 라인·인텐트)
|
||||
|
||||
**Files:**
|
||||
- Modify: `tools/deck/gen-slaydeck.mjs` (몬스터 슬롯 UI 생성부 ~line 916-1015, PlayerPanel ~1015-1100, RenderCombat ~2688)
|
||||
|
||||
- [ ] **Step 1**: 몬스터 슬롯 루프에 BlockBadge(guid 270+i)·Value(guid 280+i)·Buffs(guid 290+i) 엔티티 추가 (DmgPop 추가 코드 다음)
|
||||
|
||||
```js
|
||||
const mBlockBadge = entity({
|
||||
id: guid('cmb', 270 + i), path: `${base}/BlockBadge`, modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 6,
|
||||
components: [
|
||||
transform({ parentW: SLOT_W, parentH: SLOT_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 40, y: 36 }, pos: { x: -HP_BAR_W / 2 - 30, y: -14 } }),
|
||||
sprite({ color: { r: 0.32, g: 0.5, b: 0.85, a: 1 }, type: 1 }),
|
||||
],
|
||||
});
|
||||
mBlockBadge.jsonString.enable = false;
|
||||
combat.push(mBlockBadge);
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 280 + i), path: `${base}/BlockBadge/Value`, modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 0,
|
||||
components: [
|
||||
transform({ parentW: 40, parentH: 36, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 40, y: 32 }, pos: { x: 0, y: 0 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '0', fontSize: 17, bold: true, color: { r: 1, g: 1, b: 1, a: 1 }, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 290 + i), path: `${base}/Buffs`, modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 7,
|
||||
components: [
|
||||
transform({ parentW: SLOT_W, parentH: SLOT_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: SLOT_W + 60, y: 22 }, pos: { x: 0, y: -58 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '', fontSize: 15, bold: true, color: { r: 0.85, g: 0.65, b: 1, a: 1 }, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
```
|
||||
|
||||
- [ ] **Step 2**: PlayerPanel에 Buffs 텍스트(guid 217) 추가 (BlockBadge/Value 다음)
|
||||
|
||||
```js
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 217), path: `${PP}/Buffs`, modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 6,
|
||||
components: [
|
||||
transform({ parentW: 300, parentH: 96, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 280, y: 22 }, pos: { x: 0, y: -44 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '', fontSize: 14, bold: true, color: { r: 0.85, g: 0.65, b: 1, a: 1 }, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
```
|
||||
|
||||
- [ ] **Step 3**: 버프 문자열 헬퍼 메서드 `BuffsLabel` 신설 (Lua, str/weak/vuln → "힘+2 약화1 취약2")
|
||||
|
||||
```lua
|
||||
-- method BuffsLabel(str, weak, vuln) → string
|
||||
local parts = {}
|
||||
if str ~= nil and str > 0 then table.insert(parts, "힘+" .. tostring(str)) end
|
||||
if weak ~= nil and weak > 0 then table.insert(parts, "약화" .. tostring(weak)) end
|
||||
if vuln ~= nil and vuln > 0 then table.insert(parts, "취약" .. tostring(vuln)) end
|
||||
return table.concat(parts, " ")
|
||||
```
|
||||
|
||||
- [ ] **Step 4**: `RenderCombat` 확장 — 몬스터 루프 내(SetHpBar 다음)
|
||||
|
||||
```lua
|
||||
self:SetEntityEnabled(base .. "/BlockBadge", m.block > 0)
|
||||
self:SetText(base .. "/BlockBadge/Value", string.format("%d", m.block))
|
||||
self:SetText(base .. "/Buffs", self:BuffsLabel(m.str, m.weak, m.vuln))
|
||||
```
|
||||
|
||||
인텐트 분기 교체 (Attack은 최종 예상치·Debuff 추가):
|
||||
|
||||
```lua
|
||||
local t = ""
|
||||
if intent ~= nil then
|
||||
if intent.kind == "Attack" then
|
||||
local atk = intent.value + m.str
|
||||
if m.weak > 0 then atk = math.floor(atk * 0.75) end
|
||||
if self.PlayerVuln > 0 then atk = math.floor(atk * 1.5) end
|
||||
t = "공격 " .. tostring(atk)
|
||||
elseif intent.kind == "Defend" then t = "방어 " .. tostring(intent.value)
|
||||
elseif intent.kind == "Debuff" then
|
||||
if intent.effect == "weak" then t = "약화 " .. tostring(intent.value) .. " 부여"
|
||||
else t = "취약 " .. tostring(intent.value) .. " 부여" end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
인텐트 색: Attack 빨강(기존), Defend 파랑(기존 else), Debuff 보라 `Color(0.8, 0.5, 1, 1)` 분기 추가.
|
||||
|
||||
플레이어 표시 (기존 BlockBadge 갱신 다음):
|
||||
|
||||
```lua
|
||||
local pb = self:BuffsLabel(self.PlayerStr, self.PlayerWeak, self.PlayerVuln)
|
||||
if self.PlayerPowers ~= nil and #self.PlayerPowers > 0 then
|
||||
local names = {}
|
||||
for i = 1, #self.PlayerPowers do
|
||||
local pc = self.Cards[self.PlayerPowers[i]]
|
||||
if pc ~= nil then table.insert(names, pc.name) end
|
||||
end
|
||||
if pb ~= "" then pb = pb .. " · " end
|
||||
pb = pb .. table.concat(names, " ")
|
||||
end
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/PlayerPanel/Buffs", pb)
|
||||
```
|
||||
|
||||
- [ ] **Step 5**: 커밋 `feat(buffs-power): 적 방어도 배지·버프 라인·디버프 인텐트 UI (생성기)`
|
||||
|
||||
### Task 5: 밸런스 시뮬 동기화 + 테스트
|
||||
|
||||
**Files:**
|
||||
- Modify: `tools/balance/sim-balance.mjs`
|
||||
- Test: `tools/balance/sim-balance.test.mjs`
|
||||
|
||||
- [ ] **Step 1**: 실패 테스트 먼저 추가 — 약화·취약·힘 계산 + Debuff 인텐트 + Power 동작
|
||||
|
||||
```js
|
||||
test('simulateCombat: 취약이 플레이어 공격을 1.5배로', () => {
|
||||
const data = {
|
||||
cards: { Vuln: { name: '취약기', cost: 1, kind: 'Skill', vuln: 9 }, Hit: { name: '타격', cost: 1, kind: 'Attack', damage: 10 } },
|
||||
starterDeck: ['Vuln', 'Hit', 'Hit', 'Hit', 'Hit'],
|
||||
monsters: [{ name: '적', maxHp: 100, intents: [{ kind: 'Defend', value: 0 }] }],
|
||||
};
|
||||
const r = simulateCombat(data, mulberry32(1));
|
||||
// 1턴: 공격 우선 휴리스틱 → Hit×3 (취약 미부여, 30) — 그래도 30+α로 수치 검증은 별도 단위 함수로
|
||||
assert.equal(typeof r.win, 'boolean');
|
||||
});
|
||||
|
||||
test('calcAttack: 힘·약화·취약 공식', () => {
|
||||
assert.equal(calcAttack(6, 2, 0, 0), 8); // 힘+2
|
||||
assert.equal(calcAttack(6, 0, 1, 0), 4); // 약화 floor(6*0.75)
|
||||
assert.equal(calcAttack(6, 0, 0, 1), 9); // 취약 floor(6*1.5)
|
||||
assert.equal(calcAttack(10, 2, 1, 1), 13); // floor(floor(12*0.75)=9 → floor(9*1.5)=13
|
||||
});
|
||||
|
||||
test('simulateCombat: 적 Debuff 인텐트로 플레이어 약화 → 받는 피해 감소 검증', () => {
|
||||
const data = {
|
||||
cards: { Hit: { name: '타격', cost: 1, kind: 'Attack', damage: 1 } },
|
||||
starterDeck: ['Hit', 'Hit', 'Hit', 'Hit', 'Hit'],
|
||||
monsters: [{ name: '적', maxHp: 9999, intents: [{ kind: 'Debuff', effect: 'weak', value: 1 }] }],
|
||||
};
|
||||
const r = simulateCombat(data, mulberry32(1));
|
||||
assert.equal(r.playerHpRemaining, 80); // Debuff만 하는 적 → 피해 0
|
||||
});
|
||||
|
||||
test('simulateCombat: Power(매턴 힘) 누적', () => {
|
||||
const data = {
|
||||
cards: {
|
||||
Rage: { name: '분노', cost: 1, kind: 'Power', powerEffect: 'strengthPerTurn', value: 5 },
|
||||
Hit: { name: '타격', cost: 1, kind: 'Attack', damage: 1 },
|
||||
},
|
||||
starterDeck: ['Rage', 'Hit', 'Hit', 'Hit', 'Hit'],
|
||||
monsters: [{ name: '적', maxHp: 60, intents: [{ kind: 'Defend', value: 0 }] }],
|
||||
};
|
||||
const r = simulateCombat(data, mulberry32(1));
|
||||
assert.equal(r.win, true);
|
||||
assert.ok(r.turns <= 6, `파워 누적으로 빠른 처치 기대, 실제 ${r.turns}턴`);
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2**: `node --test tools/balance/sim-balance.test.mjs` → 신규 테스트 FAIL 확인
|
||||
- [ ] **Step 3**: `sim-balance.mjs` 구현 — `calcAttack(base, str, weak, vulnOnTarget)` export 신설, `simulateCombat`에 pStr/pWeak/pVuln/powers·몬스터 str/weak/vuln 상태 추가, 규칙 재현(부여→감소 타이밍 Lua와 동일), `chooseAction` 확장(Attack 우선 유지, 잔여 에너지로 Power→버프 Skill 사용), Debuff 인텐트 처리. `formatReport`의 kind 루프에 'Power' 포함(효율 계산은 plays만 표시).
|
||||
- [ ] **Step 4**: `node --test tools/balance/sim-balance.test.mjs` → 전체 PASS
|
||||
- [ ] **Step 5**: 커밋 `feat(buffs-power): 밸런스 시뮬 버프/디버프·Power 동기화`
|
||||
|
||||
### Task 6: 산출물 재생성·시뮬 확인·푸시·PR·머지
|
||||
|
||||
**Files:**
|
||||
- Regen: `RootDesk/MyDesk/SlayDeckController.codeblock`, `ui/DefaultGroup.ui`, `Global/common.gamelogic`
|
||||
|
||||
- [ ] **Step 1**: `node tools/deck/gen-slaydeck.mjs` 실행 성공 확인
|
||||
- [ ] **Step 2**: `node tools/balance/sim-balance.mjs` — 승률 0%/100% 극단 아님 확인 (참고용 리포트 기록)
|
||||
- [ ] **Step 3**: 커밋 `feat(buffs-power): 산출물 재생성 (버프/디버프·Power·적 방어도 UI)`
|
||||
- [ ] **Step 4**: `git push -u origin feature/p6-buffs-power`
|
||||
- [ ] **Step 5**: Gitea API로 PR 생성 → 머지 (기존 자동화 패턴: `curl -s -X POST .../repos/gahusb/maplecontest/pulls`, 토큰은 `.mcp.json` 참조 금지 — `git credential` 또는 기존 사용 토큰 경로)
|
||||
|
||||
## Self-Review 결과
|
||||
|
||||
- 설계 요구 전 항목(버프 3종·Power·적 방어도 배지·예시 카드 4종·적 디버프 인텐트·시뮬 동기화) 태스크 매핑 확인
|
||||
- 타입/이름 일관성: `CalcPlayerAttack`·`BuffsLabel`·`PlayerStr/Weak/Vuln`·`PlayerPowers`·`m.str/weak/vuln` 통일 확인
|
||||
- 플레이스홀더: 카드 image RUID만 Task 1 산출물에 의존 (의도된 순서)
|
||||
79
docs/superpowers/plans/2026-06-12-card-frames.md
Normal file
79
docs/superpowers/plans/2026-06-12-card-frames.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# P13 — 커스텀 카드 프레임 구현 계획
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:executing-plans. 설계: `2026-06-12-card-frames-design.md`
|
||||
|
||||
**Goal:** 사용자 제작 프레임 이미지(직업×등급)를 카드 UI 전체에 적용하고 등급을 보상 확률에 반영.
|
||||
|
||||
**Architecture:** 단일 소스(`data/*.json` + `gen-slaydeck.mjs`) → 산출물 재생성. 카드 배경 스프라이트를 프레임 ImageRUID로 교체(A안), `ApplyCardFace` 중앙 함수에서 class×rarity 조회.
|
||||
|
||||
**Tech Stack:** Node.js 생성기, MSW Lua, node --test.
|
||||
|
||||
### Task 1: 리소스 커밋
|
||||
- [ ] `.sprite` 9종 커밋: `git add RootDesk/MyDesk/*.sprite && git commit -m "feat(card-frames): 카드 프레임 스프라이트 9종 로컬 임포트 (warior·mage·bandit × normal·unique·legend)"`
|
||||
|
||||
### Task 2: 데이터 — rarity + cardframes.json
|
||||
- [ ] `data/cardframes.json` 신설 (설계서 JSON 그대로)
|
||||
- [ ] `data/cards.json` 32종에 `"rarity"` 추가 (설계서 표 그대로 — node 스크립트로 일괄 주입 권장)
|
||||
- [ ] 커밋: `feat(card-frames): 카드 등급 배정·프레임 RUID 매핑 데이터`
|
||||
|
||||
### Task 3: 생성기 — 프레임 렌더링
|
||||
- [ ] `CARDFRAMES = JSON.parse(readFileSync('data/cardframes.json'))` 로드, 카드별 검증(throw): rarity ∈ {normal,unique,legend}, class ∈ classToFrame
|
||||
- [ ] `luaCardsTable`: `fields.push(\`rarity = ${luaStr(c.rarity)}\`)`
|
||||
- [ ] OnBeginPlay 주입(luaCardsTable 옆): `luaFramesTable()` — `self.CardFrames = {...}` + `self.ClassToFrame = {...}` / `prop('any','CardFrames')`·`prop('any','ClassToFrame')` 선언
|
||||
- [ ] `ApplyCardFace` Lua: kind 틴트 분기 → 프레임 적용
|
||||
|
||||
```lua
|
||||
local frames = self.CardFrames[self.ClassToFrame[c.class] or "warrior"]
|
||||
local ruid = frames ~= nil and frames[c.rarity or "normal"] or nil
|
||||
if ruid ~= nil then
|
||||
e.SpriteGUIRendererComponent.ImageRUID = ruid
|
||||
e.SpriteGUIRendererComponent.Color = Color(1, 1, 1, 1)
|
||||
end
|
||||
```
|
||||
|
||||
- [ ] `cardFaceLayout(W)` 헬퍼 신설(s=W/180): Cost pos(-68s,103s)/size 44s/font 26s · Name pos(4s,97s)/size(150s,26s)/font 18s · Art pos(0,16s)/size 110s · Desc pos(0,-85s)/size(152s,64s)/font 16s
|
||||
- [ ] 카드 생성 5곳(upsertUi 손패 ~523 · 조회 ~787 · 전체덱 ~928 · 보상 ~1443 · 상점 ~1660)에 헬퍼 적용, NamePlate/CostPlate 생성 제거, 카드 스프라이트 type 0·흰색·프리뷰 프레임 RUID
|
||||
- [ ] CardHand 잔존 단색판 제거: upsertUi 초입 필터에 `/ui/DefaultGroup/CardHand/Card\d+/(NamePlate|CostPlate)` 경로 제거 추가
|
||||
- [ ] 커밋: `feat(card-frames): 생성기 — 프레임 렌더링·레이아웃 통합`
|
||||
|
||||
### Task 4: 보상 가중 추첨 (TDD)
|
||||
- [ ] `tools/balance/sim-balance.test.mjs`에 실패 테스트: `rarityForRoll(70)==='normal'`, `(71)==='unique'`, `(95)==='unique'`, `(96)==='legend'` → 실행해 FAIL 확인
|
||||
- [ ] `tools/balance/sim-balance.mjs`: `export function rarityForRoll(roll){ if (roll > 95) return 'legend'; if (roll > 70) return 'unique'; return 'normal'; }` → PASS 확인
|
||||
- [ ] `OfferReward` Lua 교체:
|
||||
|
||||
```lua
|
||||
local pool = self:CardPool()
|
||||
local byRarity = {}
|
||||
for _, id in ipairs(pool) do
|
||||
local r = self.Cards[id].rarity or "normal"
|
||||
if byRarity[r] == nil then byRarity[r] = {} end
|
||||
table.insert(byRarity[r], id)
|
||||
end
|
||||
self.RewardChoices = {}
|
||||
for i = 1, 3 do
|
||||
local roll = math.random(1, 100)
|
||||
local want = "normal"
|
||||
if roll > 95 then want = "legend" elseif roll > 70 then want = "unique" end
|
||||
local bucket = byRarity[want]
|
||||
if bucket == nil or #bucket == 0 then bucket = pool end
|
||||
self.RewardChoices[i] = bucket[math.random(1, #bucket)]
|
||||
self:ApplyRewardVisual(i, self.RewardChoices[i])
|
||||
end
|
||||
```
|
||||
|
||||
- [ ] 커밋: `feat(card-frames): 보상 등급 가중 추첨 70/25/5 (+JS 미러 테스트)`
|
||||
|
||||
### Task 5: 재생성·검증·산출물 커밋
|
||||
- [ ] `node tools/deck/gen-slaydeck.mjs` → `grep -c "CardFrames" RootDesk/MyDesk/SlayDeckController.codeblock` ≥1, `grep -c "4bb57ef88ef449fdaf958f6cf37fe44b" ui/DefaultGroup.ui` ≥1
|
||||
- [ ] `node --test tools/balance/sim-balance.test.mjs tools/map/rogue-map.test.mjs` 전건 통과
|
||||
- [ ] 커밋: `feat(card-frames): 산출물 재생성`
|
||||
|
||||
### Task 6: 메이커 검증·튜닝
|
||||
- [ ] maker_refresh_workspace → 빌드 콘솔 0에러 → 플레이: 손패 프레임·등급 구분, `_ResourceService` 로드 확인, 보상·덱 조회 스크린샷
|
||||
- [ ] 텍스트/아트 위치 어긋나면 `cardFaceLayout` 수치 조정 → 재생성 → 재확인 (수정 시 커밋)
|
||||
|
||||
### Task 7: PR·머지·메모리
|
||||
- [ ] push → `node tools/git/gitea-pr.mjs create <spec.json>` → merge → main pull → 메모리 갱신 (slaymaple-build-status에 P13 추가)
|
||||
|
||||
## Self-Review
|
||||
- 설계 전 항목에 대응 Task 존재 ✓ / 코드 블록 placeholder 없음 ✓ / CardFrames·ClassToFrame·rarityForRoll 명칭 일관 ✓ / maker_save 덮어쓰기 주의(설계서 '주의' 절) Task 6에서 refresh만 사용 ✓
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user