22 Commits

Author SHA1 Message Date
a7a6b2123a Fix damage popup sequencing 2026-07-08 02:35:01 +09:00
fc37d81350 Merge pull request '전사·도적 전직 카드 풀 및 성장 밸런스 조정' (#111) from codex/warrior-card-pool-rebalance into main
Reviewed-on: https://gitea.gahusb.synology.me/gahusb/maplecontest/pulls/111
2026-07-05 20:02:04 +09:00
d5931b1822 balance: 도적 계열 성장 곡선 조정 2026-07-05 04:03:13 +09:00
fe92b8bbb8 balance: 전사 카드를 전직 계열별로 재배치 2026-07-05 03:47:28 +09:00
f89cd1ad63 Merge pull request '메이플 전사 전직 스킬 카드 및 연계 기믹 구현' (#110) from codex/maple-warrior-skill-cards into main
Reviewed-on: https://gitea.gahusb.synology.me/gahusb/maplecontest/pulls/110
2026-07-04 02:29:12 +09:00
758ebd19f2 balance: 전사 계열 5섹션 성장 곡선 조정 2026-07-04 02:22:17 +09:00
90494232bc feat: 메이플 전사 전직 카드와 연계 기믹 추가 2026-07-04 02:15:01 +09:00
ecadf3606e Merge pull request '워리어 카드 풀 및 공용 전투 효과 구현' (#109) from codex/warrior-card-effects-fixes into main
Reviewed-on: https://gitea.gahusb.synology.me/gahusb/maplecontest/pulls/109
2026-07-04 01:40:00 +09:00
4b559ca7fa feat: 워리어 카드와 공용 전투 효과 구현 2026-07-03 23:07:41 +09:00
30c73c9899 Merge pull request 'feat(monster): 적 종별 모델(프리팹) + 스테이지 로스터 배치' (#107) from feature/monster-models into main 2026-07-03 01:34:26 +09:00
ffcec649fa chore: 산출물 재생성 — map01~05 몬스터 인스턴스 entry_id 수정 반영
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-03 01:18:06 +09:00
3b678e35d1 fix(monster): 맵 인스턴스 origin.entry_id를 modelId와 일치시켜 MissingModel 해소
메이커가 엔티티의 원본 모델을 origin.entry_id로 해석하는데, entry_id를
enemyId("junior_bugi")로 넣어 model://monster-junior_bugi(실제 EntryKey)와
불일치 → [LEA-3028] MissingModel로 전 몬스터 미표시. entry_id를
modelEntryId(=modelId="monster-<id>")로 수정. 메이커 인게임 검증: 전투에서
전 종 정상 렌더(stump=1110101도 나무토막 확인).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-03 01:18:06 +09:00
ee68fb5bb0 chore: 산출물 재생성 — stump 모델 + map04 배치 (18/18·전 5맵 완성)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 20:24:39 +09:00
a7f949fad8 data: stump(나무토막) 외형 추가 (mob 1110101) — 18/18 완성
MSW "나무토막" localized 검색에 잡힌 유일한 저레벨 몹 클립셋(1110101:
stand/hit/die/move) 채택. 시각 확정은 플레이테스트(map04)에서.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 20:24:39 +09:00
9fbf8e8574 chore: 산출물 재생성 — 모델 17종 + map02/03/05 로스터 배치
적 외형 8종 추가로 모델 8개 신규(slime·pig·mushmom·blue_mushroom 등),
map02/03/05가 준비도 가드 통과해 종별 모델 인스턴스로 재배치.
map04는 stump 미보유로 보존(스킵).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 19:57:40 +09:00
d61628d359 data: 적 외형 8종 추가 (공식 리소스 RUID 수확) — stump 제외 17/18
MSW 자산 검색으로 공식 maplestory 몹 클립 확보:
- slime(0210100)·slime_elite/boss(슬라임 재사용, box 스케일)
- pig(1210100)·mushmom(6130101)·blue_mushroom(2220110)
- red_snail·modified_snail(snail 0100100 — 빨강변형 0100102는 카탈로그 부재)
stump(나무토막)는 카탈로그에서 미발견 → 미보유 유지(map04 준비도 가드 스킵).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 19:57:40 +09:00
18da7a7983 docs: 몬스터 종별 모델 산출물 규칙(RULES §1)·README 반영
RULES §1 표에 Models/Monsters/<enemyId>.model 행 + 보조 생성기 3종 갱신.
README 디렉토리 구조·기능 표(몬스터 종별 모델)·재생성 명령 반영.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 13:57:22 +09:00
695f048c2d chore(map): 산출물 재생성 — map01 로스터 기반 몬스터 재배치(종별 모델 9마리)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 13:55:46 +09:00
6e82d0f128 feat(map): 인카운터를 encounters.json 로스터 기반 모델 인스턴스 배치로 개편
MONSTER_VARIANTS 랜덤 외형 제거(외형=enemies.json appearance로 정체성 고정).
buildMonsterInstance로 종별 모델(monster-<id>) 인스턴스 배치, 준비도 가드로
appearance 미보유 로스터 맵은 보존(Task 2 RUID 수확 후 재생성).
gen-combat-monster는 codeblock 생성만(맵 부착은 encounters 생성기로 흡수).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 13:55:46 +09:00
1390b9ec50 feat(monster): 적 종별 모델 생성기 + 모델 산출물 재생성(9종)
단일 소스 data/enemies.json appearance → Models/Monsters/<enemyId>.model.
EntryKey model://monster-<id> 네임스페이스(기존 모델과 충돌 가드), 태생 AI-free.
appearance 미확보 9종(slime 등)은 Task 2(RUID 수확) 후 추가 예정.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 13:52:45 +09:00
cdfc79cd57 feat(monster): 몬스터 모델·인스턴스 공용 빌더 lib + 단위테스트
buildMonsterModel(.model 골격 복제·외형/EnemyId 베이크·AI-free) +
buildMonsterInstance(맵 엔티티) + modelEntryId. fs 접근 없는 순수 함수.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 13:51:58 +09:00
bfb9ee5bef data: 적 외형(appearance) 9종 + 맵별 로스터(encounters.json) 신설
map01 메이커 큐레이션 외형을 enemies.json으로 흡수(단일 소스화).
encounters.json: map01=현 실태, map02~05=티어별 초안(기존 18종 내).
appearance는 luaEnemiesTable 화이트리스트 밖이라 codeblock 불변(diffcheck IDENTICAL).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xhLoQbJvQYL65kBtDNDTy
2026-07-02 13:50:42 +09:00
58 changed files with 27164 additions and 6109 deletions

View File

@@ -45,7 +45,8 @@ git pull
slaymaple/ slaymaple/
├── data/ # 게임 데이터 단일 소스 (생성기가 읽어 주입). 맵은 정적 데이터 없음(절차 생성) ├── data/ # 게임 데이터 단일 소스 (생성기가 읽어 주입). 맵은 정적 데이터 없음(절차 생성)
│ ├── cards.json # 카드 166장(1~3차 전직 계열별 + 저주) + 클래스별 시작 덱 │ ├── cards.json # 카드 166장(1~3차 전직 계열별 + 저주) + 클래스별 시작 덱
│ ├── enemies.json # 적 18종(일반/정예/보스, 디버프 인텐트 포함) │ ├── enemies.json # 적 18종(일반/정예/보스, 디버프 인텐트 + 외형 appearance)
│ ├── encounters.json # 맵별 몬스터 로스터(map01~05 × combat/elite/boss)
│ ├── potions.json # 물약 6종 + 드랍률·슬롯·상점가 │ ├── potions.json # 물약 6종 + 드랍률·슬롯·상점가
│ ├── relics.json # 유물 19종(StS 효과 × 메이플 장비) + 시작 유물 + 풀 │ ├── relics.json # 유물 19종(StS 효과 × 메이플 장비) + 시작 유물 + 풀
│ ├── cardframes.json # 커스텀 카드 프레임 3종(전사/마법사/도적 × normal/unique/legend) + 보상 등급 가중치 │ ├── cardframes.json # 커스텀 카드 프레임 3종(전사/마법사/도적 × normal/unique/legend) + 보상 등급 가중치
@@ -68,16 +69,17 @@ slaymaple/
│ ├── MapCamera.codeblock # 맵별 카메라 적용 │ ├── MapCamera.codeblock # 맵별 카메라 적용
│ ├── PlayerLock.codeblock # 전투맵 플레이어 입력·이동 잠금 │ ├── PlayerLock.codeblock # 전투맵 플레이어 입력·이동 잠금
│ ├── LobbyNpc.codeblock # 로비 NPC 상호작용(근접·클릭) │ ├── LobbyNpc.codeblock # 로비 NPC 상호작용(근접·클릭)
── LobbyMobility.codeblock # 로비 이동·공격 해제 + 카메라 추종 ── LobbyMobility.codeblock # 로비 이동·공격 해제 + 카메라 추종
│ └── Models/Monsters/ # 적 종별 모델 <enemyId>.model (산출물 — 외형·EnemyId 베이크)
├── map/ # 맵 6종 (산출물) ├── map/ # 맵 6종 (산출물)
│ ├── lobby.map # 로비 허브 맵 (마을 배경, NPC 4종, 전투 없음) │ ├── lobby.map # 로비 허브 맵 (마을 배경, NPC 4종, 전투 없음)
│ └── map01.map ~ map05.map # 5막 전투/맵 노드 (공식 배경 + STS풍 우측 배치) │ └── map01.map ~ map05.map # 5막 전투/맵 노드 (공식 배경 + STS풍 우측 배치)
├── tools/ # 결정적 생성기·도구 (주체별 폴더, 단일 소스) ├── tools/ # 결정적 생성기·도구 (주체별 폴더, 단일 소스)
│ ├── deck/ # gen-slaydeck.mjs(★컨트롤러+common 생성 오케스트레이터) · cb/(codeblock Lua 메서드 20모듈: boot·screens·combat·hand·npc·navigation·layout·shop·reward·soul 등) · lib/(공유 상수·데이터·헬퍼) · legacy/(옛 UI emit 휴면) │ ├── 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(노드별 몬스터 그룹) · rogue-map.mjs(절차 생성 JS 미러)+test │ ├── 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) │ ├── camera/ # gen-camera.mjs(맵별 고정 카메라 codeblock)
│ ├── player/ # gen-player-lock.mjs(전투맵 입력 잠금) · freeze-turn-player.mjs(모델 이동 정지) · gen-lobby-npc.mjs(LobbyNpc·LobbyMobility codeblock) │ ├── player/ # gen-player-lock.mjs(전투맵 입력 잠금) · freeze-turn-player.mjs(모델 이동 정지) · gen-lobby-npc.mjs(LobbyNpc·LobbyMobility codeblock)
│ ├── monster/ # gen-combat-monster.mjs(EnemyId 마커) · freeze-turn-monsters.mjs(필드 AI 정지) │ ├── 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 │ ├── balance/ # sim-balance.mjs(전투 밸런스 몬테카를로 시뮬) · sim-balance.test.mjs
│ ├── verify/ # count·uimap·cbgap(카운트/UIGroup 매핑/재연결 GAP) · cardkinds(카드 kind↔효과) · cbprops(미선언 self 대입) · cbset(메서드 집합 무손실) · diffcheck(바이트동일) │ ├── verify/ # count·uimap·cbgap(카운트/UIGroup 매핑/재연결 GAP) · cardkinds(카드 kind↔효과) · cbprops(미선언 self 대입) · cbset(메서드 집합 무손실) · diffcheck(바이트동일)
│ └── git/ # gitea-pr.mjs(UTF-8 안전 PR 생성/수정/머지 — RULES.md 참조) │ └── git/ # gitea-pr.mjs(UTF-8 안전 PR 생성/수정/머지 — RULES.md 참조)
@@ -127,6 +129,7 @@ slaymaple/
| **버프/디버프** | StS 표준 — **힘**(+N 영구)·**약화**(주는 피해 25%)·**취약**(받는 피해 +50%)·**독**(매 행동 틱). 양방향(적 디버프 인텐트 포함), 인텐트는 최종 예상치 표시 | | **버프/디버프** | StS 표준 — **힘**(+N 영구)·**약화**(주는 피해 25%)·**취약**(받는 피해 +50%)·**독**(매 행동 틱). 양방향(적 디버프 인텐트 포함), 인텐트는 최종 예상치 표시 |
| **전투 연출** | 공격 이펙트·**몬스터 데미지 팝업(자릿수 스킨)**·드래그 타깃 마커·적 개별 차례·**공격/피격/독뎀 모션**(아바타 상태 전이·몬스터 hit 클립·런지/넉백) | | **전투 연출** | 공격 이펙트·**몬스터 데미지 팝업(자릿수 스킨)**·드래그 타깃 마커·적 개별 차례·**공격/피격/독뎀 모션**(아바타 상태 전이·몬스터 hit 클립·런지/넉백) |
| **절차 생성 맵** | 막 시작마다 **경로 생성**(런마다 다름, **가로 진행**). 층 규칙: 1~2층 전투만 → 3층~ 상점/휴식 → 4층~ 엘리트/**유물 방** → 보스 수렴. 점선 경로·상태 4단·층 카운터. 노드 타입별 **몬스터 랜덤 구성**(일반 1~3 / 엘리트 / 보스) + intent 랜덤 행동 | | **절차 생성 맵** | 막 시작마다 **경로 생성**(런마다 다름, **가로 진행**). 층 규칙: 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% 드랍·상점·슬롯 메뉴. 보물 방=상자 연출 → 유물+메소 | | **유물 19종 / 물약 6종** | 유물: StS 효과 × 메이플 장비 외형, TopBar 아이콘 + 마우스오버 툴팁, 8종 훅. 물약: 승리 40% 드랍·상점·슬롯 메뉴. 보물 방=상자 연출 → 유물+메소 |
| **카드 프레임·등급** | 커스텀 프레임 3종(전사/마법사/도적 × normal/unique/legend), 카드 5개 사이트 통합 레이아웃. 보상 등급 가중 추첨 70/25/5 | | **카드 프레임·등급** | 커스텀 프레임 3종(전사/마법사/도적 × normal/unique/legend), 카드 5개 사이트 통합 레이아웃. 보상 등급 가중 추첨 70/25/5 |
| **영혼(Soul) 메타 성장** | 승천과 별개의 영구 강화 화폐. 2차 전직 상태로 보스 클리어 시 적립 → 로비 영혼 상점 4종 해금(시작 메소 +60·HP +15·덱 정제·시작 유물 +1). **UserDataStorage 영구 저장** | | **영혼(Soul) 메타 성장** | 승천과 별개의 영구 강화 화폐. 2차 전직 상태로 보스 클리어 시 적립 → 로비 영혼 상점 4종 해금(시작 메소 +60·HP +15·덱 정제·시작 유물 +1). **UserDataStorage 영구 저장** |
@@ -179,7 +182,9 @@ node tools/map/gen-lobby-map.mjs # 로비 맵 + NPC 배치
node tools/player/gen-lobby-npc.mjs # 로비 codeblock(LobbyNpc·LobbyMobility) node tools/player/gen-lobby-npc.mjs # 로비 codeblock(LobbyNpc·LobbyMobility)
node tools/camera/gen-camera.mjs # 맵별 카메라 node tools/camera/gen-camera.mjs # 맵별 카메라
node tools/player/gen-player-lock.mjs # 전투맵 입력 잠금 node tools/player/gen-player-lock.mjs # 전투맵 입력 잠금
node tools/monster/gen-combat-monster.mjs # 몬스터 EnemyId 마커 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)). > 산출물 검증은 내용 출력 없이 카운트만: `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)).

View File

@@ -16,6 +16,7 @@ Claude Code는 `CLAUDE.md`가 이 파일을 임포트하므로 자동 적용된
| `Global/common.gamelogic` | ~1KB | 〃 | 〃 | | `Global/common.gamelogic` | ~1KB | 〃 | 〃 |
| `map/map01.map`~`map05.map`, `map/lobby.map` | 각 ~210KB | `tools/map/`·`tools/monster/`·`tools/camera/`·`tools/player/` (↓ 보조 생성기) | 해당 생성기 | | `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/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/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/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` | | `RootDesk/MyDesk/LobbyNpc.codeblock`·`LobbyMobility.codeblock` | 각 ~2-3KB | `tools/player/gen-lobby-npc.mjs` | `node tools/player/gen-lobby-npc.mjs` |
@@ -31,9 +32,10 @@ Claude Code는 `CLAUDE.md`가 이 파일을 임포트하므로 자동 적용된
- `tools/camera/gen-camera.mjs``MapCamera.codeblock` + map01~05 카메라 부착 (값 `data/camera.json`) - `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-maps.mjs``map02~05` + `Global/SectorConfig.config` (map01 템플릿 클론)
- `tools/map/gen-lobby-map.mjs``map/lobby.map` + `SectorConfig.config` - `tools/map/gen-lobby-map.mjs``map/lobby.map` + `SectorConfig.config`
- `tools/map/gen-map-encounters.mjs` → map01~05 노드 타입별 몬스터 그룹 재구성 - `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/monster/gen-combat-monster.mjs``CombatMonster.codeblock` + map01~05 부착 - `tools/map/gen-map-encounters.mjs`map01~05에 `data/encounters.json` 로스터 기반 **종별 모델 인스턴스** 배치(외형=정체성 고정). 준비도 가드: 로스터에 `appearance` 미보유 적이 있는 맵은 재생성 스킵(기존 보존). 값 검증 `node --test tools/monster/monster-model.test.mjs`.
- `tools/monster/freeze-turn-monsters.mjs`몬스터 `.model`·맵 AI 컴포넌트 제거 - `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-player-lock.mjs``PlayerLock.codeblock` + map01~05 부착
- `tools/player/gen-lobby-npc.mjs``LobbyNpc.codeblock`·`LobbyMobility.codeblock` - `tools/player/gen-lobby-npc.mjs``LobbyNpc.codeblock`·`LobbyMobility.codeblock`
- `tools/player/freeze-turn-player.mjs``Global/DefaultPlayer.model` 이동 0 고정 - `tools/player/freeze-turn-player.mjs``Global/DefaultPlayer.model` 이동 0 고정

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

View 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": []
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,9 @@
"classToFrame": { "classToFrame": {
"warrior": "warrior", "warrior": "warrior",
"fighter": "warrior", "fighter": "warrior",
"crusader": "warrior",
"page": "warrior", "page": "warrior",
"knight": "warrior",
"spearman": "warrior", "spearman": "warrior",
"magician": "magician", "magician": "magician",
"firepoison": "magician", "firepoison": "magician",

File diff suppressed because it is too large Load Diff

Binary file not shown.

7
data/encounters.json Normal file
View 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"] }
}

View File

@@ -7,7 +7,8 @@
{ "kind": "Attack", "value": 10 }, { "kind": "Attack", "value": 10 },
{ "kind": "Attack", "value": 6 }, { "kind": "Attack", "value": 6 },
{ "kind": "Defend", "value": 8 } { "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": { "slime_elite": {
"name": "정예 슬라임", "name": "정예 슬라임",
@@ -17,7 +18,8 @@
{ "kind": "Attack", "value": 8 }, { "kind": "Attack", "value": 8 },
{ "kind": "Defend", "value": 10 }, { "kind": "Defend", "value": 10 },
{ "kind": "Debuff", "effect": "weak", "value": 1 } { "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": { "slime_boss": {
"name": "슬라임 킹", "name": "슬라임 킹",
@@ -28,7 +30,8 @@
{ "kind": "Debuff", "effect": "vuln", "value": 2 }, { "kind": "Debuff", "effect": "vuln", "value": 2 },
{ "kind": "Attack", "value": 10 }, { "kind": "Attack", "value": 10 },
{ "kind": "Attack", "value": 22 } { "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": { "orange_mushroom": {
"name": "주황버섯", "name": "주황버섯",
@@ -38,7 +41,8 @@
{ "kind": "Attack", "value": 5 }, { "kind": "Attack", "value": 5 },
{ "kind": "Defend", "value": 4 }, { "kind": "Defend", "value": 4 },
{ "kind": "Attack", "value": 8 } { "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": { "blue_mushroom": {
"name": "파란버섯", "name": "파란버섯",
@@ -48,7 +52,8 @@
{ "kind": "Attack", "value": 4 }, { "kind": "Attack", "value": 4 },
{ "kind": "Attack", "value": 10 }, { "kind": "Attack", "value": 10 },
{ "kind": "AddCard", "card": "Wound", "count": 1 } { "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": { "pig": {
"name": "돼지", "name": "돼지",
@@ -57,7 +62,8 @@
{ "kind": "Attack", "value": 6 }, { "kind": "Attack", "value": 6 },
{ "kind": "Attack", "value": 6 }, { "kind": "Attack", "value": 6 },
{ "kind": "Defend", "value": 5 } { "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": { "green_mushroom": {
"name": "초록버섯", "name": "초록버섯",
@@ -66,7 +72,8 @@
{ "kind": "Attack", "value": 7 }, { "kind": "Attack", "value": 7 },
{ "kind": "Defend", "value": 3 }, { "kind": "Defend", "value": 3 },
{ "kind": "Attack", "value": 9 } { "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": { "red_snail": {
"name": "빨간 달팽이", "name": "빨간 달팽이",
@@ -75,7 +82,8 @@
{ "kind": "Attack", "value": 5 }, { "kind": "Attack", "value": 5 },
{ "kind": "Defend", "value": 6 }, { "kind": "Defend", "value": 6 },
{ "kind": "Attack", "value": 7 } { "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": { "stump": {
"name": "나무토막", "name": "나무토막",
@@ -84,7 +92,8 @@
{ "kind": "Defend", "value": 5 }, { "kind": "Defend", "value": 5 },
{ "kind": "Attack", "value": 8 }, { "kind": "Attack", "value": 8 },
{ "kind": "Attack", "value": 6 } { "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": { "mushmom": {
"name": "머쉬맘", "name": "머쉬맘",
@@ -96,7 +105,8 @@
{ "kind": "Attack", "value": 9 }, { "kind": "Attack", "value": 9 },
{ "kind": "Defend", "value": 6 }, { "kind": "Defend", "value": 6 },
{ "kind": "AddCard", "card": "Burn", "count": 1 } { "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": { "modified_snail": {
"name": "변형된 달팽이", "name": "변형된 달팽이",
@@ -107,7 +117,8 @@
{ "kind": "Attack", "value": 7 }, { "kind": "Attack", "value": 7 },
{ "kind": "Attack", "value": 14 }, { "kind": "Attack", "value": 14 },
{ "kind": "Debuff", "effect": "weak", "value": 1 } { "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": { "king_slime": {
"name": "킹 슬라임", "name": "킹 슬라임",
@@ -118,7 +129,8 @@
{ "kind": "Debuff", "effect": "vuln", "value": 2 }, { "kind": "Debuff", "effect": "vuln", "value": 2 },
{ "kind": "Attack", "value": 12 }, { "kind": "Attack", "value": 12 },
{ "kind": "Attack", "value": 24 } { "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": { "octopus": {
"name": "문어", "name": "문어",
@@ -127,7 +139,8 @@
{ "kind": "Attack", "value": 5 }, { "kind": "Attack", "value": 5 },
{ "kind": "Attack", "value": 6 }, { "kind": "Attack", "value": 6 },
{ "kind": "Defend", "value": 4 } { "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": { "kapa_drake": {
"name": "카파 드레이크", "name": "카파 드레이크",
@@ -137,7 +150,8 @@
{ "kind": "Attack", "value": 6 }, { "kind": "Attack", "value": 6 },
{ "kind": "Defend", "value": 6 }, { "kind": "Defend", "value": 6 },
{ "kind": "Attack", "value": 11 } { "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": { "junior_neki": {
"name": "주니어 네키", "name": "주니어 네키",
@@ -146,7 +160,8 @@
{ "kind": "Attack", "value": 6 }, { "kind": "Attack", "value": 6 },
{ "kind": "Attack", "value": 8 }, { "kind": "Attack", "value": 8 },
{ "kind": "Debuff", "effect": "weak", "value": 1 } { "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": { "junior_bugi": {
"name": "주니어 부기", "name": "주니어 부기",
@@ -155,7 +170,8 @@
{ "kind": "Attack", "value": 7 }, { "kind": "Attack", "value": 7 },
{ "kind": "Defend", "value": 5 }, { "kind": "Defend", "value": 5 },
{ "kind": "Attack", "value": 9 } { "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": { "dile": {
"name": "다일", "name": "다일",
@@ -166,7 +182,8 @@
{ "kind": "Attack", "value": 8 }, { "kind": "Attack", "value": 8 },
{ "kind": "Attack", "value": 16 }, { "kind": "Attack", "value": 16 },
{ "kind": "Debuff", "effect": "weak", "value": 1 } { "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": { "mano": {
"name": "마노", "name": "마노",
@@ -177,7 +194,8 @@
{ "kind": "Debuff", "effect": "vuln", "value": 1 }, { "kind": "Debuff", "effect": "vuln", "value": 1 },
{ "kind": "Attack", "value": 10 }, { "kind": "Attack", "value": 10 },
{ "kind": "AddCard", "card": "Wound", "count": 1 } { "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",

View File

@@ -6,15 +6,25 @@ The goal is to keep card behavior reusable instead of hardcoding one-off card na
## Damage ## Damage
- `damage`: base attack 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 - `damagePerOtherHandCard`: bonus damage per other card in hand
- `damagePerAttackPlayedThisTurn`: bonus damage per attack played this turn - `damagePerAttackPlayedThisTurn`: bonus damage per attack played this turn
- `damagePerDiscardedThisTurn`: bonus damage per card discarded this turn - `damagePerDiscardedThisTurn`: bonus damage per card discarded this turn
- `damagePerSkillInHand`: bonus damage per skill card in hand - `damagePerSkillInHand`: bonus damage per skill card in hand
- `damagePerCardDrawnThisCombat`: bonus damage per card drawn this combat - `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 - `damagePerTurn`: damage applied at turn start
- `cardPlayedDamage`: damage when the card is played - `cardPlayedDamage`: damage when the card is played
- `cardPlayedRandomDamage`: random 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 - `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 - `randomTargetEachHit`: choose a random alive enemy for each hit
- `repeatOnKill`: repeat the attack when it kills at least one enemy - `repeatOnKill`: repeat the attack when it kills at least one enemy
- `firstCardDamageBonus`: bonus damage for the first card played this turn - `firstCardDamageBonus`: bonus damage for the first card played this turn
@@ -39,6 +49,17 @@ The goal is to keep card behavior reusable instead of hardcoding one-off card na
- `drawUntilHandSize`: draw until hand reaches a target size - `drawUntilHandSize`: draw until hand reaches a target size
- `drawSkillBlock`: gain block for each Skill drawn - `drawSkillBlock`: gain block for each Skill drawn
- `drawPoison`: apply poison when a card is 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 - `handCostZeroThisTurn`: make hand cards cost 0 this turn
- `drawDisabledThisTurn`: disable draw for the rest of the turn - `drawDisabledThisTurn`: disable draw for the rest of the turn
- `heal`: heal immediately - `heal`: heal immediately
@@ -48,6 +69,21 @@ The goal is to keep card behavior reusable instead of hardcoding one-off card na
- `thorns`: gain Thorns - `thorns`: gain Thorns
- `selfVuln`: apply Vulnerable to self - `selfVuln`: apply Vulnerable to self
- `extraPoisonTicks`: add extra poison ticks at enemy turn start - `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 ## Status
@@ -91,7 +127,9 @@ The goal is to keep card behavior reusable instead of hardcoding one-off card na
- `powerEffect: "blockPerTurn"` - `powerEffect: "blockPerTurn"`
- `powerEffect: "poisonPerTurn"` - `powerEffect: "poisonPerTurn"`
- `powerEffect: "damagePerTurn"` - `powerEffect: "damagePerTurn"`
- `powerEffect: "healPerTurn"`
- `powerEffect: "retainOne"` - `powerEffect: "retainOne"`
- `powerEffect: "keepBlock"`
- `turnStartShiv`: create Shivs at turn start - `turnStartShiv`: create Shivs at turn start
- `turnStartDraw`: draw cards at turn start - `turnStartDraw`: draw cards at turn start
- `turnStartDiscard`: discard cards at turn start - `turnStartDiscard`: discard cards at turn start

View File

@@ -47,7 +47,7 @@
"FootholdsByLayer": { "FootholdsByLayer": {
"1": [ "1": [
{ {
"Length": 1.28000069, "Length": 1.27999973,
"NextFootholdId": 2, "NextFootholdId": 2,
"PreviousFootholdId": 27, "PreviousFootholdId": 27,
"groupID": 1, "groupID": 1,
@@ -69,7 +69,7 @@
"y": -0.04000002 "y": -0.04000002
}, },
"EndPoint": { "EndPoint": {
"x": -7.64999962, "x": -7.65000057,
"y": -0.04000002 "y": -0.04000002
}, },
"Variance": { "Variance": {
@@ -264,7 +264,7 @@
} }
}, },
{ {
"Length": 0.9, "Length": 0.899999738,
"NextFootholdId": 9, "NextFootholdId": 9,
"PreviousFootholdId": 7, "PreviousFootholdId": 7,
"groupID": 1, "groupID": 1,
@@ -286,7 +286,7 @@
"y": -0.04000002 "y": -0.04000002
}, },
"EndPoint": { "EndPoint": {
"x": -1.34999979, "x": -1.35,
"y": -0.04000002 "y": -0.04000002
}, },
"Variance": { "Variance": {
@@ -437,11 +437,11 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 13, "Id": 13,
"StartPoint": { "StartPoint": {
"x": 2.24999976, "x": 2.25,
"y": -0.04000002 "y": -0.04000002
}, },
"EndPoint": { "EndPoint": {
"x": 3.14999986, "x": 3.15,
"y": -0.04000002 "y": -0.04000002
}, },
"Variance": { "Variance": {
@@ -530,11 +530,11 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 16, "Id": 16,
"StartPoint": { "StartPoint": {
"x": 4.95, "x": 4.95000029,
"y": -0.04000002 "y": -0.04000002
}, },
"EndPoint": { "EndPoint": {
"x": 5.84999943, "x": 5.85,
"y": -0.04000002 "y": -0.04000002
}, },
"Variance": { "Variance": {
@@ -574,7 +574,7 @@
} }
}, },
{ {
"Length": 1.27999878, "Length": 1.27999973,
"NextFootholdId": 19, "NextFootholdId": 19,
"PreviousFootholdId": 17, "PreviousFootholdId": 17,
"groupID": 1, "groupID": 1,
@@ -596,7 +596,7 @@
"y": -0.04000002 "y": -0.04000002
}, },
"EndPoint": { "EndPoint": {
"x": 8.029999, "x": 8.03,
"y": -0.04000002 "y": -0.04000002
}, },
"Variance": { "Variance": {
@@ -623,11 +623,11 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 19, "Id": 19,
"StartPoint": { "StartPoint": {
"x": 8.029999, "x": 8.03,
"y": -0.04000002 "y": -0.04000002
}, },
"EndPoint": { "EndPoint": {
"x": 8.029999, "x": 8.03,
"y": -0.9 "y": -0.9
}, },
"Variance": { "Variance": {
@@ -654,11 +654,11 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 20, "Id": 20,
"StartPoint": { "StartPoint": {
"x": 8.029999, "x": 8.03,
"y": -0.9000001 "y": -0.9000001
}, },
"EndPoint": { "EndPoint": {
"x": 8.029999, "x": 8.03,
"y": -1.50000012 "y": -1.50000012
}, },
"Variance": { "Variance": {
@@ -685,11 +685,11 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 21, "Id": 21,
"StartPoint": { "StartPoint": {
"x": 8.029999, "x": 8.03,
"y": -1.50000012 "y": -1.50000012
}, },
"EndPoint": { "EndPoint": {
"x": 8.029999, "x": 8.03,
"y": -2.10000014 "y": -2.10000014
}, },
"Variance": { "Variance": {
@@ -716,11 +716,11 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 22, "Id": 22,
"StartPoint": { "StartPoint": {
"x": 8.029999, "x": 8.03,
"y": -2.10000014 "y": -2.10000014
}, },
"EndPoint": { "EndPoint": {
"x": 8.029999, "x": 8.03,
"y": -2.7 "y": -2.7
}, },
"Variance": { "Variance": {
@@ -747,12 +747,12 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 23, "Id": 23,
"StartPoint": { "StartPoint": {
"x": 8.029999, "x": 8.03,
"y": -2.7 "y": -2.70000029
}, },
"EndPoint": { "EndPoint": {
"x": 8.029999, "x": 8.03,
"y": -3.3 "y": -3.30000019
}, },
"Variance": { "Variance": {
"x": 0.0, "x": 0.0,
@@ -778,11 +778,11 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 24, "Id": 24,
"StartPoint": { "StartPoint": {
"x": 8.029999, "x": 8.03,
"y": -3.30000019 "y": -3.30000019
}, },
"EndPoint": { "EndPoint": {
"x": 8.029999, "x": 8.03,
"y": -3.9 "y": -3.9
}, },
"Variance": { "Variance": {
@@ -809,11 +809,11 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 25, "Id": 25,
"StartPoint": { "StartPoint": {
"x": 8.029999, "x": 8.03,
"y": -3.90000033 "y": -3.90000033
}, },
"EndPoint": { "EndPoint": {
"x": 8.029999, "x": 8.03,
"y": -4.50000048 "y": -4.50000048
}, },
"Variance": { "Variance": {
@@ -840,11 +840,11 @@
"OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858", "OwnerId": "c9a3018a-f6fa-4c4b-b91e-404ac5ce9858",
"Id": 26, "Id": 26,
"StartPoint": { "StartPoint": {
"x": 8.029999, "x": 8.03,
"y": -4.5 "y": -4.5
}, },
"EndPoint": { "EndPoint": {
"x": 8.029999, "x": 8.03,
"y": -5.10000038 "y": -5.10000038
}, },
"Variance": { "Variance": {
@@ -996,11 +996,11 @@
"Id": 31, "Id": 31,
"StartPoint": { "StartPoint": {
"x": -8.93, "x": -8.93,
"y": -3.3 "y": -3.30000019
}, },
"EndPoint": { "EndPoint": {
"x": -8.93, "x": -8.93,
"y": -2.7 "y": -2.70000029
}, },
"Variance": { "Variance": {
"x": 0.0, "x": 0.0,
@@ -6363,6 +6363,95 @@
"@version": 1 "@version": 1
} }
}, },
{
"id": "0d1f81e7-82db-4a8a-9f5e-6563c140aa44",
"path": "/maps/map01/MapleMapLayer_1",
"componentNames": "MOD.Core.MapLayerComponent",
"jsonString": {
"name": "MapleMapLayer_1",
"path": "/maps/map01/MapleMapLayer_1",
"nameEditable": false,
"enable": false,
"visible": false,
"localize": false,
"displayOrder": 4,
"pathConstraints": "///",
"revision": 1,
"origin": {
"type": "Model",
"entry_id": "maplemaplayer",
"sub_entity_id": null,
"root_entity_id": null,
"replaced_model_id": null
},
"modelId": "maplemaplayer",
"@components": [
{
"@type": "MOD.Core.MapLayerComponent",
"IsVisible": true,
"LayerSortOrder": 1,
"Locked": false,
"MapLayerName": "Layer2",
"Thumbnail": "",
"Enable": true
}
],
"@version": 1
}
},
{
"id": "c80fe5c8-096e-48af-b04e-4ddae2526e2a",
"path": "/maps/map01/TileMap_1",
"componentNames": "MOD.Core.TransformComponent,MOD.Core.TileMapComponent",
"jsonString": {
"name": "TileMap_1",
"path": "/maps/map01/TileMap_1",
"nameEditable": false,
"enable": false,
"visible": false,
"localize": false,
"displayOrder": 5,
"pathConstraints": "///",
"revision": 1,
"origin": {
"type": "Model",
"entry_id": "tilemap",
"sub_entity_id": null,
"root_entity_id": null,
"replaced_model_id": null
},
"modelId": "tilemap",
"@components": [
{
"@type": "MOD.Core.TransformComponent",
"Position": {
"x": -0.225,
"y": -0.15,
"z": 1000.0
},
"QuaternionRotation": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 1.0
},
"Enable": true
},
{
"@type": "MOD.Core.TileMapComponent",
"IsOddGridPosition": false,
"SortingLayer": "MapLayer1",
"TileMapVersion": 1,
"TileSetRUID": {
"DataId": "9dfea3808bbd49a5877d8624df21b1c7"
},
"Tiles": [],
"Enable": true
}
],
"@version": 1
}
},
{ {
"id": "000005dc-0000-4000-8000-0000000005dc", "id": "000005dc-0000-4000-8000-0000000005dc",
"path": "/maps/map01/junior_bugi", "path": "/maps/map01/junior_bugi",
@@ -6374,22 +6463,22 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": false, "localize": false,
"displayOrder": 4, "displayOrder": 6,
"pathConstraints": "///", "pathConstraints": "///",
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-junior_bugi",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000005dc-0000-4000-8000-0000000005dc", "root_entity_id": "000005dc-0000-4000-8000-0000000005dc",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-junior_bugi",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 2.6, "x": 2.3,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -6526,22 +6615,22 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": false, "localize": false,
"displayOrder": 5, "displayOrder": 7,
"pathConstraints": "///", "pathConstraints": "///",
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-kapa_drake",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000005dd-0000-4000-8000-0000000005dd", "root_entity_id": "000005dd-0000-4000-8000-0000000005dd",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-kapa_drake",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 3.6, "x": 3.16,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -6668,7 +6757,7 @@
} }
}, },
{ {
"id": "000005df-0000-4000-8000-0000000005df", "id": "000005de-0000-4000-8000-0000000005de",
"path": "/maps/map01/junior_neki", "path": "/maps/map01/junior_neki",
"componentNames": "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", "componentNames": "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",
"jsonString": { "jsonString": {
@@ -6678,22 +6767,22 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": false, "localize": false,
"displayOrder": 6, "displayOrder": 8,
"pathConstraints": "///", "pathConstraints": "///",
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-junior_neki",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000005df-0000-4000-8000-0000000005df", "root_entity_id": "000005de-0000-4000-8000-0000000005de",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-junior_neki",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 5.6, "x": 4.02,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -6820,7 +6909,7 @@
} }
}, },
{ {
"id": "000005e0-0000-4000-8000-0000000005e0", "id": "000005df-0000-4000-8000-0000000005df",
"path": "/maps/map01/octopus", "path": "/maps/map01/octopus",
"componentNames": "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", "componentNames": "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",
"jsonString": { "jsonString": {
@@ -6830,22 +6919,22 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": false, "localize": false,
"displayOrder": 7, "displayOrder": 9,
"pathConstraints": "///", "pathConstraints": "///",
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-octopus",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000005e0-0000-4000-8000-0000000005e0", "root_entity_id": "000005df-0000-4000-8000-0000000005df",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-octopus",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 5.55820465, "x": 4.88,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -6972,7 +7061,7 @@
} }
}, },
{ {
"id": "000005e2-0000-4000-8000-0000000005e2", "id": "000005e0-0000-4000-8000-0000000005e0",
"path": "/maps/map01/green_mushroom", "path": "/maps/map01/green_mushroom",
"componentNames": "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", "componentNames": "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",
"jsonString": { "jsonString": {
@@ -6982,22 +7071,22 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": false, "localize": false,
"displayOrder": 8, "displayOrder": 10,
"pathConstraints": "///", "pathConstraints": "///",
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-green_mushroom",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000005e2-0000-4000-8000-0000000005e2", "root_entity_id": "000005e0-0000-4000-8000-0000000005e0",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-green_mushroom",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 4.6, "x": 5.74,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -7062,12 +7151,10 @@
"x": 0.63, "x": 0.63,
"y": 0.58 "y": 0.58
}, },
"CircleRadius": 0.29,
"ColliderOffset": { "ColliderOffset": {
"x": 0.00999999, "x": 0.00999999,
"y": 0.26 "y": 0.26
}, },
"ColliderType": 1,
"IsLegacy": false, "IsLegacy": false,
"Enable": true "Enable": true
}, },
@@ -7126,9 +7213,9 @@
} }
}, },
{ {
"id": "61c8296b-f4d7-4e87-907a-b165c63d666a", "id": "000005e1-0000-4000-8000-0000000005e1",
"path": "/maps/map01/orange_mushroom", "path": "/maps/map01/orange_mushroom",
"componentNames": "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,script.CombatMonster", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "orange_mushroom", "name": "orange_mushroom",
"path": "/maps/map01/orange_mushroom", "path": "/maps/map01/orange_mushroom",
@@ -7136,22 +7223,22 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": false, "localize": false,
"displayOrder": 9, "displayOrder": 11,
"pathConstraints": "///", "pathConstraints": "///",
"revision": 1, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-orange_mushroom",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "61c8296b-f4d7-4e87-907a-b165c63d666a", "root_entity_id": "000005e1-0000-4000-8000-0000000005e1",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-orange_mushroom",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 3.14904547, "x": 6.6,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -7161,6 +7248,11 @@
"z": 0.0, "z": 0.0,
"w": 1.0 "w": 1.0
}, },
"Scale": {
"x": 1.0,
"y": 1.0,
"z": 1.0
},
"Enable": true "Enable": true
}, },
{ {
@@ -7179,7 +7271,7 @@
"ActionSheet": {}, "ActionSheet": {},
"EndFrameIndex": 0, "EndFrameIndex": 0,
"RenderSetting": 1, "RenderSetting": 1,
"SortingLayer": "MapLayer1", "SortingLayer": "MapLayer0",
"SpriteRUID": "6d381bea1bcb4504b518a1fbfa0904ac", "SpriteRUID": "6d381bea1bcb4504b518a1fbfa0904ac",
"StartFrameIndex": 0, "StartFrameIndex": 0,
"Enable": true "Enable": true
@@ -7200,7 +7292,7 @@
"@type": "MOD.Core.MovementComponent", "@type": "MOD.Core.MovementComponent",
"InputSpeed": 0.0, "InputSpeed": 0.0,
"JumpForce": 6.0, "JumpForce": 6.0,
"Enable": true "Enable": false
}, },
{ {
"@type": "MOD.Core.StateComponent", "@type": "MOD.Core.StateComponent",
@@ -7257,19 +7349,27 @@
}, },
"Enable": true "Enable": true
}, },
{
"@type": "MOD.Core.DamageSkinSettingComponent",
"DamageSkinId": {
"DataId": "02c22d93421b4038b3c413b3e40b57ec"
},
"Enable": true
},
{ {
"@type": "script.CombatMonster", "@type": "script.CombatMonster",
"Enable": true, "Enable": true,
"EnemyId": "orange_mushroom" "EnemyId": "orange_mushroom",
"Group": "combat"
} }
], ],
"@version": 1 "@version": 1
} }
}, },
{ {
"id": "b22c8dc0-18df-4dc5-ba40-520629d6fea7", "id": "000005e2-0000-4000-8000-0000000005e2",
"path": "/maps/map01/dile", "path": "/maps/map01/dile",
"componentNames": "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,script.CombatMonster", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "dile", "name": "dile",
"path": "/maps/map01/dile", "path": "/maps/map01/dile",
@@ -7277,22 +7377,22 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": false, "localize": false,
"displayOrder": 10, "displayOrder": 12,
"pathConstraints": "///", "pathConstraints": "///",
"revision": 1, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "MoveMonster", "entry_id": "monster-dile",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "b22c8dc0-18df-4dc5-ba40-520629d6fea7", "root_entity_id": "000005e2-0000-4000-8000-0000000005e2",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "movemonster", "modelId": "monster-dile",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 4.337345, "x": 3.0,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -7302,6 +7402,11 @@
"z": 0.0, "z": 0.0,
"w": 1.0 "w": 1.0
}, },
"Scale": {
"x": 1.0,
"y": 1.0,
"z": 1.0
},
"Enable": true "Enable": true
}, },
{ {
@@ -7320,7 +7425,7 @@
"ActionSheet": {}, "ActionSheet": {},
"EndFrameIndex": 0, "EndFrameIndex": 0,
"RenderSetting": 1, "RenderSetting": 1,
"SortingLayer": "MapLayer1", "SortingLayer": "MapLayer0",
"SpriteRUID": "68070c6f4abe40658899a208ddaf4081", "SpriteRUID": "68070c6f4abe40658899a208ddaf4081",
"StartFrameIndex": 0, "StartFrameIndex": 0,
"Enable": true "Enable": true
@@ -7340,8 +7445,8 @@
{ {
"@type": "MOD.Core.MovementComponent", "@type": "MOD.Core.MovementComponent",
"InputSpeed": 0.0, "InputSpeed": 0.0,
"JumpForce": 0.0, "JumpForce": 6.0,
"Enable": true "Enable": false
}, },
{ {
"@type": "MOD.Core.StateComponent", "@type": "MOD.Core.StateComponent",
@@ -7398,6 +7503,13 @@
}, },
"Enable": true "Enable": true
}, },
{
"@type": "MOD.Core.DamageSkinSettingComponent",
"DamageSkinId": {
"DataId": "02c22d93421b4038b3c413b3e40b57ec"
},
"Enable": true
},
{ {
"@type": "script.CombatMonster", "@type": "script.CombatMonster",
"Enable": true, "Enable": true,
@@ -7409,9 +7521,9 @@
} }
}, },
{ {
"id": "56c7fad0-b54c-4950-9c88-207e4a7e58ed", "id": "000005e3-0000-4000-8000-0000000005e3",
"path": "/maps/map01/mano", "path": "/maps/map01/mano",
"componentNames": "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,script.CombatMonster", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "mano", "name": "mano",
"path": "/maps/map01/mano", "path": "/maps/map01/mano",
@@ -7419,22 +7531,22 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": false, "localize": false,
"displayOrder": 11, "displayOrder": 13,
"pathConstraints": "///", "pathConstraints": "///",
"revision": 1, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "MoveMonster", "entry_id": "monster-mano",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "56c7fad0-b54c-4950-9c88-207e4a7e58ed", "root_entity_id": "000005e3-0000-4000-8000-0000000005e3",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "movemonster", "modelId": "monster-mano",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 5.31402826, "x": 5.6,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -7444,6 +7556,11 @@
"z": 0.0, "z": 0.0,
"w": 1.0 "w": 1.0
}, },
"Scale": {
"x": 1.0,
"y": 1.0,
"z": 1.0
},
"Enable": true "Enable": true
}, },
{ {
@@ -7462,7 +7579,7 @@
"ActionSheet": {}, "ActionSheet": {},
"EndFrameIndex": 0, "EndFrameIndex": 0,
"RenderSetting": 1, "RenderSetting": 1,
"SortingLayer": "MapLayer1", "SortingLayer": "MapLayer0",
"SpriteRUID": "e035bb90c053401b88de2159dfa230eb", "SpriteRUID": "e035bb90c053401b88de2159dfa230eb",
"StartFrameIndex": 0, "StartFrameIndex": 0,
"Enable": true "Enable": true
@@ -7482,8 +7599,8 @@
{ {
"@type": "MOD.Core.MovementComponent", "@type": "MOD.Core.MovementComponent",
"InputSpeed": 0.0, "InputSpeed": 0.0,
"JumpForce": 0.0, "JumpForce": 6.0,
"Enable": true "Enable": false
}, },
{ {
"@type": "MOD.Core.StateComponent", "@type": "MOD.Core.StateComponent",
@@ -7540,6 +7657,13 @@
}, },
"Enable": true "Enable": true
}, },
{
"@type": "MOD.Core.DamageSkinSettingComponent",
"DamageSkinId": {
"DataId": "02c22d93421b4038b3c413b3e40b57ec"
},
"Enable": true
},
{ {
"@type": "script.CombatMonster", "@type": "script.CombatMonster",
"Enable": true, "Enable": true,
@@ -7551,9 +7675,9 @@
} }
}, },
{ {
"id": "ced28dde-75a1-4b7b-ba7b-9057ce9992c1", "id": "000005e4-0000-4000-8000-0000000005e4",
"path": "/maps/map01/king_slime", "path": "/maps/map01/king_slime",
"componentNames": "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,script.CombatMonster", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "king_slime", "name": "king_slime",
"path": "/maps/map01/king_slime", "path": "/maps/map01/king_slime",
@@ -7561,24 +7685,24 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": false, "localize": false,
"displayOrder": 12, "displayOrder": 14,
"pathConstraints": "///", "pathConstraints": "///",
"revision": 1, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-king_slime",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "ced28dde-75a1-4b7b-ba7b-9057ce9992c1", "root_entity_id": "000005e4-0000-4000-8000-0000000005e4",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-king_slime",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 4.228825, "x": 4.6,
"y": 0.03499998, "y": 0.03499998,
"z": 999.998047 "z": 999.999
}, },
"QuaternionRotation": { "QuaternionRotation": {
"x": 0.0, "x": 0.0,
@@ -7586,6 +7710,11 @@
"z": 0.0, "z": 0.0,
"w": 1.0 "w": 1.0
}, },
"Scale": {
"x": 1.0,
"y": 1.0,
"z": 1.0
},
"Enable": true "Enable": true
}, },
{ {
@@ -7606,7 +7735,7 @@
"ActionSheet": {}, "ActionSheet": {},
"EndFrameIndex": 0, "EndFrameIndex": 0,
"RenderSetting": 1, "RenderSetting": 1,
"SortingLayer": "MapLayer1", "SortingLayer": "MapLayer0",
"SpriteRUID": "dd9de73d580240faab8cad03b587013b", "SpriteRUID": "dd9de73d580240faab8cad03b587013b",
"StartFrameIndex": 0, "StartFrameIndex": 0,
"Enable": true "Enable": true
@@ -7627,7 +7756,7 @@
"@type": "MOD.Core.MovementComponent", "@type": "MOD.Core.MovementComponent",
"InputSpeed": 0.0, "InputSpeed": 0.0,
"JumpForce": 6.0, "JumpForce": 6.0,
"Enable": true "Enable": false
}, },
{ {
"@type": "MOD.Core.StateComponent", "@type": "MOD.Core.StateComponent",
@@ -7684,6 +7813,13 @@
}, },
"Enable": true "Enable": true
}, },
{
"@type": "MOD.Core.DamageSkinSettingComponent",
"DamageSkinId": {
"DataId": "02c22d93421b4038b3c413b3e40b57ec"
},
"Enable": true
},
{ {
"@type": "script.CombatMonster", "@type": "script.CombatMonster",
"Enable": true, "Enable": true,
@@ -7693,95 +7829,6 @@
], ],
"@version": 1 "@version": 1
} }
},
{
"id": "0d1f81e7-82db-4a8a-9f5e-6563c140aa44",
"path": "/maps/map01/MapleMapLayer_1",
"componentNames": "MOD.Core.MapLayerComponent",
"jsonString": {
"name": "MapleMapLayer_1",
"path": "/maps/map01/MapleMapLayer_1",
"nameEditable": false,
"enable": false,
"visible": false,
"localize": false,
"displayOrder": 13,
"pathConstraints": "///",
"revision": 1,
"origin": {
"type": "Model",
"entry_id": "maplemaplayer",
"sub_entity_id": null,
"root_entity_id": null,
"replaced_model_id": null
},
"modelId": "maplemaplayer",
"@components": [
{
"@type": "MOD.Core.MapLayerComponent",
"IsVisible": true,
"LayerSortOrder": 1,
"Locked": false,
"MapLayerName": "Layer2",
"Thumbnail": "",
"Enable": true
}
],
"@version": 1
}
},
{
"id": "c80fe5c8-096e-48af-b04e-4ddae2526e2a",
"path": "/maps/map01/TileMap_1",
"componentNames": "MOD.Core.TransformComponent,MOD.Core.TileMapComponent",
"jsonString": {
"name": "TileMap_1",
"path": "/maps/map01/TileMap_1",
"nameEditable": false,
"enable": false,
"visible": false,
"localize": false,
"displayOrder": 14,
"pathConstraints": "///",
"revision": 1,
"origin": {
"type": "Model",
"entry_id": "tilemap",
"sub_entity_id": null,
"root_entity_id": null,
"replaced_model_id": null
},
"modelId": "tilemap",
"@components": [
{
"@type": "MOD.Core.TransformComponent",
"Position": {
"x": -0.225,
"y": -0.15,
"z": 1000.0
},
"QuaternionRotation": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 1.0
},
"Enable": true
},
{
"@type": "MOD.Core.TileMapComponent",
"IsOddGridPosition": false,
"SortingLayer": "MapLayer1",
"TileMapVersion": 1,
"TileSetRUID": {
"DataId": "9dfea3808bbd49a5877d8624df21b1c7"
},
"Tiles": [],
"Enable": true
}
],
"@version": 1
}
} }
] ]
} }

View File

@@ -6365,11 +6365,11 @@
}, },
{ {
"id": "000009c4-0000-4000-8000-0000000009c4", "id": "000009c4-0000-4000-8000-0000000009c4",
"path": "/maps/map02/combat_1", "path": "/maps/map02/pig",
"componentNames": "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", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "combat_1", "name": "pig",
"path": "/maps/map02/combat_1", "path": "/maps/map02/pig",
"nameEditable": true, "nameEditable": true,
"enable": true, "enable": true,
"visible": true, "visible": true,
@@ -6379,12 +6379,12 @@
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-pig",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000009c4-0000-4000-8000-0000000009c4", "root_entity_id": "000009c4-0000-4000-8000-0000000009c4",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-pig",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
@@ -6409,9 +6409,11 @@
{ {
"@type": "MOD.Core.StateAnimationComponent", "@type": "MOD.Core.StateAnimationComponent",
"ActionSheet": { "ActionSheet": {
"stand": "d8f014043ce8418f96700c2b6c9ebf6c", "stand": "528a8638b12f41b8b5781a05360d2949",
"hit": "c3cf643b618346c7bfa6574187b396f9", "move": "8baad61512be4b33b2a0879fec7a266e",
"die": "a88d9b3d60f941e4890dc89a6ccaa8ee" "hit": "60e42a918a0342478903cc71adba1dc5",
"jump": "c9e27ce6f8344aefba169c5ca6571def",
"die": "0644beff80a44ec7acc011ea0961df57"
}, },
"Enable": true "Enable": true
}, },
@@ -6421,7 +6423,7 @@
"EndFrameIndex": 0, "EndFrameIndex": 0,
"RenderSetting": 1, "RenderSetting": 1,
"SortingLayer": "MapLayer0", "SortingLayer": "MapLayer0",
"SpriteRUID": "d8f014043ce8418f96700c2b6c9ebf6c", "SpriteRUID": "528a8638b12f41b8b5781a05360d2949",
"StartFrameIndex": 0, "StartFrameIndex": 0,
"Enable": true "Enable": true
}, },
@@ -6517,11 +6519,11 @@
}, },
{ {
"id": "000009c5-0000-4000-8000-0000000009c5", "id": "000009c5-0000-4000-8000-0000000009c5",
"path": "/maps/map02/combat_2", "path": "/maps/map02/green_mushroom",
"componentNames": "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", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "combat_2", "name": "green_mushroom",
"path": "/maps/map02/combat_2", "path": "/maps/map02/green_mushroom",
"nameEditable": true, "nameEditable": true,
"enable": true, "enable": true,
"visible": true, "visible": true,
@@ -6531,17 +6533,17 @@
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-green_mushroom",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000009c5-0000-4000-8000-0000000009c5", "root_entity_id": "000009c5-0000-4000-8000-0000000009c5",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-green_mushroom",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 3.8, "x": 3.375,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -6607,8 +6609,8 @@
"y": 0.58 "y": 0.58
}, },
"ColliderOffset": { "ColliderOffset": {
"x": 0.0449999869, "x": 0.00999999,
"y": 0.29 "y": 0.26
}, },
"IsLegacy": false, "IsLegacy": false,
"Enable": true "Enable": true
@@ -6669,11 +6671,11 @@
}, },
{ {
"id": "000009c6-0000-4000-8000-0000000009c6", "id": "000009c6-0000-4000-8000-0000000009c6",
"path": "/maps/map02/combat_3", "path": "/maps/map02/blue_mushroom",
"componentNames": "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", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "combat_3", "name": "blue_mushroom",
"path": "/maps/map02/combat_3", "path": "/maps/map02/blue_mushroom",
"nameEditable": true, "nameEditable": true,
"enable": true, "enable": true,
"visible": true, "visible": true,
@@ -6683,17 +6685,17 @@
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-blue_mushroom",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000009c6-0000-4000-8000-0000000009c6", "root_entity_id": "000009c6-0000-4000-8000-0000000009c6",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-blue_mushroom",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 5.2, "x": 4.449999999999999,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -6713,9 +6715,11 @@
{ {
"@type": "MOD.Core.StateAnimationComponent", "@type": "MOD.Core.StateAnimationComponent",
"ActionSheet": { "ActionSheet": {
"stand": "a2204a21d88942b281d2cac6053ffbaa", "stand": "1a176a7afb114fe7aef2bc58ef2d945b",
"hit": "afc08936b8a64b26bc3dd8c03ead1f26", "move": "8239541953a6457fbe6d35e17f19f0f8",
"die": "fc1c6d9ba9bc413ab53b6dbfae3ac45b" "hit": "7b405108d05741699893a4dc3d715165",
"jump": "a7ea0755262242199ae50ab6a3387034",
"die": "9e74e807797d442f9c938ca64aa9f4cd"
}, },
"Enable": true "Enable": true
}, },
@@ -6725,7 +6729,7 @@
"EndFrameIndex": 0, "EndFrameIndex": 0,
"RenderSetting": 1, "RenderSetting": 1,
"SortingLayer": "MapLayer0", "SortingLayer": "MapLayer0",
"SpriteRUID": "a2204a21d88942b281d2cac6053ffbaa", "SpriteRUID": "1a176a7afb114fe7aef2bc58ef2d945b",
"StartFrameIndex": 0, "StartFrameIndex": 0,
"Enable": true "Enable": true
}, },
@@ -6812,7 +6816,7 @@
{ {
"@type": "script.CombatMonster", "@type": "script.CombatMonster",
"Enable": true, "Enable": true,
"EnemyId": "stump", "EnemyId": "blue_mushroom",
"Group": "combat" "Group": "combat"
} }
], ],
@@ -6821,11 +6825,11 @@
}, },
{ {
"id": "000009c7-0000-4000-8000-0000000009c7", "id": "000009c7-0000-4000-8000-0000000009c7",
"path": "/maps/map02/elite_4", "path": "/maps/map02/orange_mushroom",
"componentNames": "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", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "elite_4", "name": "orange_mushroom",
"path": "/maps/map02/elite_4", "path": "/maps/map02/orange_mushroom",
"nameEditable": true, "nameEditable": true,
"enable": true, "enable": true,
"visible": true, "visible": true,
@@ -6835,17 +6839,17 @@
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-orange_mushroom",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000009c7-0000-4000-8000-0000000009c7", "root_entity_id": "000009c7-0000-4000-8000-0000000009c7",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-orange_mushroom",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 3, "x": 5.5249999999999995,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -6865,9 +6869,11 @@
{ {
"@type": "MOD.Core.StateAnimationComponent", "@type": "MOD.Core.StateAnimationComponent",
"ActionSheet": { "ActionSheet": {
"stand": "48c10437ae8344a9b2a1d3f36185728f", "move": "573fe938562a4abf91eebf951f21afd5",
"hit": "9044063647854f5e9128efcf80e909be", "stand": "6d381bea1bcb4504b518a1fbfa0904ac",
"die": "f414577d18c94cc387c275df4abdbc3b" "jump": "59823e146a034e48b8667ebb6f0724b1",
"hit": "642ece38d8d449b29ce4479100e37a54",
"die": "3c99d6b9b89b4295a9c2749eb02e28e9"
}, },
"Enable": true "Enable": true
}, },
@@ -6877,7 +6883,7 @@
"EndFrameIndex": 0, "EndFrameIndex": 0,
"RenderSetting": 1, "RenderSetting": 1,
"SortingLayer": "MapLayer0", "SortingLayer": "MapLayer0",
"SpriteRUID": "48c10437ae8344a9b2a1d3f36185728f", "SpriteRUID": "6d381bea1bcb4504b518a1fbfa0904ac",
"StartFrameIndex": 0, "StartFrameIndex": 0,
"Enable": true "Enable": true
}, },
@@ -6964,8 +6970,8 @@
{ {
"@type": "script.CombatMonster", "@type": "script.CombatMonster",
"Enable": true, "Enable": true,
"EnemyId": "modified_snail", "EnemyId": "orange_mushroom",
"Group": "elite" "Group": "combat"
} }
], ],
"@version": 1 "@version": 1
@@ -6973,11 +6979,11 @@
}, },
{ {
"id": "000009c8-0000-4000-8000-0000000009c8", "id": "000009c8-0000-4000-8000-0000000009c8",
"path": "/maps/map02/elite_5", "path": "/maps/map02/slime",
"componentNames": "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", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "elite_5", "name": "slime",
"path": "/maps/map02/elite_5", "path": "/maps/map02/slime",
"nameEditable": true, "nameEditable": true,
"enable": true, "enable": true,
"visible": true, "visible": true,
@@ -6987,17 +6993,17 @@
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-slime",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000009c8-0000-4000-8000-0000000009c8", "root_entity_id": "000009c8-0000-4000-8000-0000000009c8",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-slime",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 5, "x": 6.6,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -7017,9 +7023,11 @@
{ {
"@type": "MOD.Core.StateAnimationComponent", "@type": "MOD.Core.StateAnimationComponent",
"ActionSheet": { "ActionSheet": {
"stand": "ed3908e24d694bb786023fc1ed073489", "stand": "50faf654ee5d479cb2958edce9feaef0",
"hit": "4763c9bebc9245998c9c499b6316aa9f", "move": "dc932872543f4a02bf41e977ab79e5ad",
"die": "b168793b92a844a3a3a6f4ce647a14d2" "hit": "61c27025a8f14c478f30ede1b49758bc",
"jump": "8b89d86b1a9c4c4288650614c6f30e67",
"die": "31ecb6c7cbc24599881f00cb01599f09"
}, },
"Enable": true "Enable": true
}, },
@@ -7029,7 +7037,7 @@
"EndFrameIndex": 0, "EndFrameIndex": 0,
"RenderSetting": 1, "RenderSetting": 1,
"SortingLayer": "MapLayer0", "SortingLayer": "MapLayer0",
"SpriteRUID": "ed3908e24d694bb786023fc1ed073489", "SpriteRUID": "50faf654ee5d479cb2958edce9feaef0",
"StartFrameIndex": 0, "StartFrameIndex": 0,
"Enable": true "Enable": true
}, },
@@ -7113,6 +7121,161 @@
}, },
"Enable": true "Enable": true
}, },
{
"@type": "script.CombatMonster",
"Enable": true,
"EnemyId": "slime",
"Group": "combat"
}
],
"@version": 1
}
},
{
"id": "000009c9-0000-4000-8000-0000000009c9",
"path": "/maps/map02/mushmom",
"componentNames": "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",
"jsonString": {
"name": "mushmom",
"path": "/maps/map02/mushmom",
"nameEditable": true,
"enable": true,
"visible": true,
"localize": false,
"displayOrder": 4,
"pathConstraints": "///",
"revision": 2,
"origin": {
"type": "Model",
"entry_id": "monster-mushmom",
"sub_entity_id": null,
"root_entity_id": "000009c9-0000-4000-8000-0000000009c9",
"replaced_model_id": null
},
"modelId": "monster-mushmom",
"@components": [
{
"@type": "MOD.Core.TransformComponent",
"Position": {
"x": 4.3,
"y": 0.03499998,
"z": 999.999
},
"QuaternionRotation": {
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"Scale": {
"x": 1,
"y": 1,
"z": 1
},
"Enable": true
},
{
"@type": "MOD.Core.StateAnimationComponent",
"ActionSheet": {
"stand": "23c38ef3acad4a30ad59120bb939b008",
"move": "24d8a3a75f96406ba690ed42d7250b8f",
"hit": "c826e36ee89c48bca6aab856aa773f38",
"attack": "4d7465e950144dc59c263aad01b14e14",
"jump": "b7ddbda71a294141ba134249fc34c7da",
"die": "f50664a4524147399359cb90a6f3e80c"
},
"Enable": true
},
{
"@type": "MOD.Core.SpriteRendererComponent",
"ActionSheet": {},
"EndFrameIndex": 0,
"RenderSetting": 1,
"SortingLayer": "MapLayer0",
"SpriteRUID": "23c38ef3acad4a30ad59120bb939b008",
"StartFrameIndex": 0,
"Enable": true
},
{
"@type": "MOD.Core.RigidbodyComponent",
"MoveVelocity": {
"x": 0,
"y": 0
},
"RealMoveVelocity": {
"x": 0,
"y": 0
},
"Enable": true
},
{
"@type": "MOD.Core.MovementComponent",
"InputSpeed": 0,
"JumpForce": 6,
"Enable": false
},
{
"@type": "MOD.Core.StateComponent",
"IsLegacy": false,
"Enable": true
},
{
"@type": "MOD.Core.HitComponent",
"BoxSize": {
"x": 1.2,
"y": 1.1
},
"ColliderOffset": {
"x": 0.02,
"y": 0.55
},
"IsLegacy": false,
"Enable": true
},
{
"@type": "MOD.Core.DamageSkinSpawnerComponent",
"Enable": true
},
{
"@type": "script.Monster",
"Enable": true,
"IsDead": false
},
{
"@type": "script.MonsterAttack",
"Enable": true,
"SpriteSize": {
"x": 0,
"y": 0
},
"PositionOffset": {
"x": 0,
"y": 0
}
},
{
"@type": "MOD.Core.KinematicbodyComponent",
"MoveVelocity": {
"x": 0,
"y": 0
},
"Enable": true
},
{
"@type": "MOD.Core.SideviewbodyComponent",
"MoveVelocity": {
"x": 0,
"y": 0
},
"Enable": true
},
{
"@type": "MOD.Core.DamageSkinSettingComponent",
"DamageSkinId": {
"DataId": "02c22d93421b4038b3c413b3e40b57ec"
},
"Enable": true
},
{ {
"@type": "script.CombatMonster", "@type": "script.CombatMonster",
"Enable": true, "Enable": true,
@@ -7124,12 +7287,12 @@
} }
}, },
{ {
"id": "000009c9-0000-4000-8000-0000000009c9", "id": "000009ca-0000-4000-8000-0000000009ca",
"path": "/maps/map02/boss_6", "path": "/maps/map02/slime_boss",
"componentNames": "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", "componentNames": "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",
"jsonString": { "jsonString": {
"name": "boss_6", "name": "slime_boss",
"path": "/maps/map02/boss_6", "path": "/maps/map02/slime_boss",
"nameEditable": true, "nameEditable": true,
"enable": true, "enable": true,
"visible": true, "visible": true,
@@ -7139,17 +7302,17 @@
"revision": 2, "revision": 2,
"origin": { "origin": {
"type": "Model", "type": "Model",
"entry_id": "ChaseMonster", "entry_id": "monster-slime_boss",
"sub_entity_id": null, "sub_entity_id": null,
"root_entity_id": "000009c9-0000-4000-8000-0000000009c9", "root_entity_id": "000009ca-0000-4000-8000-0000000009ca",
"replaced_model_id": null "replaced_model_id": null
}, },
"modelId": "chasemonster", "modelId": "monster-slime_boss",
"@components": [ "@components": [
{ {
"@type": "MOD.Core.TransformComponent", "@type": "MOD.Core.TransformComponent",
"Position": { "Position": {
"x": 4, "x": 4.6,
"y": 0.03499998, "y": 0.03499998,
"z": 999.999 "z": 999.999
}, },
@@ -7169,9 +7332,11 @@
{ {
"@type": "MOD.Core.StateAnimationComponent", "@type": "MOD.Core.StateAnimationComponent",
"ActionSheet": { "ActionSheet": {
"stand": "17b55730c26f4fd6b8fcfa288da388de", "stand": "50faf654ee5d479cb2958edce9feaef0",
"hit": "eac48e84a9fc4580a4018de5cf52ddb3", "move": "dc932872543f4a02bf41e977ab79e5ad",
"die": "51c2f4b59a2c413db26035aa57002fc8" "hit": "61c27025a8f14c478f30ede1b49758bc",
"jump": "8b89d86b1a9c4c4288650614c6f30e67",
"die": "31ecb6c7cbc24599881f00cb01599f09"
}, },
"Enable": true "Enable": true
}, },
@@ -7181,7 +7346,7 @@
"EndFrameIndex": 0, "EndFrameIndex": 0,
"RenderSetting": 1, "RenderSetting": 1,
"SortingLayer": "MapLayer0", "SortingLayer": "MapLayer0",
"SpriteRUID": "17b55730c26f4fd6b8fcfa288da388de", "SpriteRUID": "50faf654ee5d479cb2958edce9feaef0",
"StartFrameIndex": 0, "StartFrameIndex": 0,
"Enable": true "Enable": true
}, },
@@ -7211,12 +7376,12 @@
{ {
"@type": "MOD.Core.HitComponent", "@type": "MOD.Core.HitComponent",
"BoxSize": { "BoxSize": {
"x": 0.63, "x": 1.2,
"y": 0.58 "y": 1.1
}, },
"ColliderOffset": { "ColliderOffset": {
"x": 0.0449999869, "x": 0.0449999869,
"y": 0.29 "y": 0.4
}, },
"IsLegacy": false, "IsLegacy": false,
"Enable": true "Enable": true

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,10 @@ import {
simulateCombat, simulateCombat,
} from './sim-balance.mjs'; } from './sim-balance.mjs';
const ROGUE_CLASSES = new Set(['rogue', 'thief', 'thiefmaster', 'assassin', 'hermit']); const AUDITED_CLASSES = new Set([
'rogue', 'thief', 'thiefmaster', 'assassin', 'hermit',
'warrior', 'fighter', 'crusader', 'page', 'knight',
]);
const CONTEXT_DECKS = { const CONTEXT_DECKS = {
rogue: [ rogue: [
@@ -38,6 +41,27 @@ const CONTEXT_DECKS = {
'Survivor', 'LeadingStrike', 'BladeDance', 'JavelinAcceleration', 'Survivor', 'LeadingStrike', 'BladeDance', 'JavelinAcceleration',
'JavelinMastery', 'TripleThrow', 'SpiritJavelin', 'SkilledJavelin', 'JavelinMastery', 'TripleThrow', 'SpiritJavelin', 'SkilledJavelin',
], ],
warrior: [
'Strike', 'Strike', 'Strike', 'Strike',
'Defend', 'Defend', 'Defend', 'Defend',
'Bash', 'SlashBlast', 'IronBody', 'WarriorMastery',
],
fighter: [
'Strike', 'Strike', 'Strike', 'Defend', 'Defend', 'Defend',
'Bash', 'SlashBlast', 'ComboAttack', 'Brandish', 'WeaponMastery', 'FlashSlash',
],
crusader: [
'Strike', 'Strike', 'Defend', 'Defend', 'Bash', 'SlashBlast',
'ComboAttack', 'Brandish', 'WeaponMastery', 'BraveSlash', 'ComboSynergy', 'Rush',
],
page: [
'Strike', 'Strike', 'Strike', 'Defend', 'Defend', 'Defend',
'Bash', 'SlashBlast', 'HolyCharge', 'DivineSwing', 'PageOrder', 'PageStance',
],
knight: [
'Strike', 'Strike', 'Defend', 'Defend', 'Bash', 'SlashBlast',
'HolyCharge', 'DivineSwing', 'PageOrder', 'DivineCharge', 'KnightRush', 'Restoration',
],
}; };
const ENCOUNTER_SCALE = { const ENCOUNTER_SCALE = {
@@ -46,6 +70,11 @@ const ENCOUNTER_SCALE = {
assassin: { hp: 2.25, attack: 1.65 }, assassin: { hp: 2.25, attack: 1.65 },
thiefmaster: { hp: 2.4, attack: 1.5 }, thiefmaster: { hp: 2.4, attack: 1.5 },
hermit: { hp: 2.6, attack: 1.65 }, hermit: { hp: 2.6, attack: 1.65 },
warrior: { hp: 1.9, attack: 1.5 },
fighter: { hp: 2.2, attack: 1.6 },
crusader: { hp: 2.6, attack: 1.7 },
page: { hp: 2.2, attack: 1.6 },
knight: { hp: 2.6, attack: 1.7 },
}; };
const median = (values) => { const median = (values) => {
@@ -172,7 +201,7 @@ export function auditCardEfficiency({ runs = 300, seed = 20260701 } = {}) {
const rows = []; const rows = [];
for (const [id, card] of Object.entries(cards)) { for (const [id, card] of Object.entries(cards)) {
if (!ROGUE_CLASSES.has(card.class)) continue; if (!AUDITED_CLASSES.has(card.class)) continue;
const deck = CONTEXT_DECKS[card.class].slice(); const deck = CONTEXT_DECKS[card.class].slice();
deck[replacementIndex(deck, cards, card)] = id; deck[replacementIndex(deck, cards, card)] = id;
const result = simulateDeck(scaledEncounter(data, card.class), deck, runs, seed, id); const result = simulateDeck(scaledEncounter(data, card.class), deck, runs, seed, id);
@@ -204,7 +233,7 @@ function formatPercent(value) {
export function formatEfficiencyReport(report) { export function formatEfficiencyReport(report) {
const lines = []; const lines = [];
lines.push(`도적 카드 효율 검증: 카드 ${report.rows.length}장, 카드당 ${report.runs}`); lines.push(`카드 효율 검증: 카드 ${report.rows.length}장, 카드당 ${report.runs}`);
lines.push('기준 덱:'); lines.push('기준 덱:');
for (const [classId, baseline] of Object.entries(report.baselines)) { for (const [classId, baseline] of Object.entries(report.baselines)) {
lines.push(` ${classId}: 승률 ${formatPercent(baseline.winRate)}, 평균 ${baseline.avgTurns.toFixed(2)}턴, 승리 HP ${baseline.avgHpOnWin.toFixed(1)}`); lines.push(` ${classId}: 승률 ${formatPercent(baseline.winRate)}, 평균 ${baseline.avgTurns.toFixed(2)}턴, 승리 HP ${baseline.avgHpOnWin.toFixed(1)}`);

View File

@@ -6,7 +6,7 @@ const cardsData = JSON.parse(readFileSync('data/cards.json', 'utf8'));
const enemiesData = JSON.parse(readFileSync('data/enemies.json', 'utf8')); const enemiesData = JSON.parse(readFileSync('data/enemies.json', 'utf8'));
const relicsData = JSON.parse(readFileSync('data/relics.json', 'utf8')); const relicsData = JSON.parse(readFileSync('data/relics.json', 'utf8'));
const PLAYER_MAX_HP = 70; const PLAYER_MAX_HP = { rogue: 70, warrior: 80 };
const REST_HEAL = 30; const REST_HEAL = 30;
const SECTION_COUNT = 5; const SECTION_COUNT = 5;
const NORMAL_FIGHTS = 4; const NORMAL_FIGHTS = 4;
@@ -18,6 +18,8 @@ const BOSS_POOL = ['king_slime', 'slime_boss'];
const JOBS = { const JOBS = {
thief: { tier2: 'thief', tier3: 'thiefmaster', tier2Starter: 'DaggerAcceleration', tier3Starter: 'Venom' }, thief: { tier2: 'thief', tier3: 'thiefmaster', tier2Starter: 'DaggerAcceleration', tier3Starter: 'Venom' },
assassin: { tier2: 'assassin', tier3: 'hermit', tier2Starter: 'JavelinAcceleration', tier3Starter: 'SpiritJavelin' }, assassin: { tier2: 'assassin', tier3: 'hermit', tier2Starter: 'JavelinAcceleration', tier3Starter: 'SpiritJavelin' },
fighter: { root: 'warrior', tier2: 'fighter', tier3: 'crusader', tier2Starter: 'ComboAttack', tier3Starter: 'ComboSynergy' },
page: { root: 'warrior', tier2: 'page', tier3: 'knight', tier2Starter: 'HolyCharge', tier3Starter: 'DivineCharge' },
}; };
const LINEAGES = { const LINEAGES = {
@@ -26,12 +28,17 @@ const LINEAGES = {
thiefmaster: ['rogue', 'thief', 'thiefmaster'], thiefmaster: ['rogue', 'thief', 'thiefmaster'],
assassin: ['rogue', 'assassin'], assassin: ['rogue', 'assassin'],
hermit: ['rogue', 'assassin', 'hermit'], hermit: ['rogue', 'assassin', 'hermit'],
warrior: ['warrior'],
fighter: ['warrior', 'fighter'],
crusader: ['warrior', 'fighter', 'crusader'],
page: ['warrior', 'page'],
knight: ['warrior', 'page', 'knight'],
}; };
const pick = (rng, values) => values[Math.floor(rng() * values.length)]; const pick = (rng, values) => values[Math.floor(rng() * values.length)];
export function campaignJobAtSection(branch, section) { export function campaignJobAtSection(branch, section) {
if (section <= 1) return 'rogue'; if (section <= 1) return JOBS[branch].root || 'rogue';
if (section === 2) return JOBS[branch].tier2; if (section === 2) return JOBS[branch].tier2;
return JOBS[branch].tier3; return JOBS[branch].tier3;
} }
@@ -102,11 +109,22 @@ function branchCardValue(card, branch, deck, id) {
value += card.sly ? 5 : 0; value += card.sly ? 5 : 0;
value += (card.discard || 0) * 2 + (card.drawPerDiscarded || 0) * 4; value += (card.discard || 0) * 2 + (card.drawPerDiscarded || 0) * 4;
value += (card.poisonApplicationBurstDamage || 0) * 1.5; value += (card.poisonApplicationBurstDamage || 0) * 1.5;
} else { } else if (branch === 'assassin') {
value += (card.addShiv || 0) * 3 + (card.turnStartShiv || 0) * 8; value += (card.addShiv || 0) * 3 + (card.turnStartShiv || 0) * 8;
value += (card.shivDamageBonus || 0) * 6 + (card.firstShivDamageBonus || 0) * 3; value += (card.shivDamageBonus || 0) * 6 + (card.firstShivDamageBonus || 0) * 3;
value += card.shivAoe ? 12 : 0; value += card.shivAoe ? 12 : 0;
value += card.shivRetain ? 5 : 0; value += card.shivRetain ? 5 : 0;
} else if (branch === 'fighter') {
value += (card.hits || 1) * 1.5;
value += (card.comboGain || 0) * 5 + (card.comboOnAttack || 0) * 10;
value += (card.damagePerCombo || 0) * 8 + (card.attackDamagePerCombo || 0) * 12;
value += (card.attackPlayedDamage || 0) * 5;
} else if (branch === 'page') {
value += (card.block || 0) * 0.5 + (card.cardPlayedBlock || 0) * 7;
value += (card.holyChargeOnHolyForce || 0) * 12 + (card.damagePerHolyCharge || 0) * 7;
value += (card.blockPerHolyCharge || 0) * 6 + (card.healPerHolyCharge || 0) * 3;
value += (card.damageTakenReduction || 0) * 40;
value += (card.blockOnDamaged || 0) * 3 + (card.strengthOnDamagedOnce || 0) * 5;
} }
const copies = deck.filter((cardId) => cardId === id).length; const copies = deck.filter((cardId) => cardId === id).length;
value -= copies * (card.kind === 'Power' ? 10 : 3); value -= copies * (card.kind === 'Power' ? 10 : 3);
@@ -192,7 +210,8 @@ function fight(state, branch, kind, section, rng, options) {
state.turns += result.turns; state.turns += result.turns;
if (!result.win) return false; if (!result.win) return false;
healFromRelics(state, 'combatEnd'); healFromRelics(state, 'combatEnd');
if (kind !== 'boss') offerReward(state.job, branch, state.deck, rng, options.minimumRewardValue); const rewardStrategy = state.job === 'warrior' || state.job === 'rogue' ? state.job : branch;
if (kind !== 'boss') offerReward(state.job, rewardStrategy, state.deck, rng, options.minimumRewardValue);
return true; return true;
} }
@@ -203,11 +222,13 @@ export function simulateCampaign(branch, rng, {
minimumRewardValue = 10, minimumRewardValue = 10,
} = {}) { } = {}) {
if (!JOBS[branch]) throw new Error(`지원하지 않는 도적 분기: ${branch}`); if (!JOBS[branch]) throw new Error(`지원하지 않는 도적 분기: ${branch}`);
const root = JOBS[branch].root || 'rogue';
const maxHp = PLAYER_MAX_HP[root];
const state = { const state = {
hp: PLAYER_MAX_HP, hp: maxHp,
maxHp: PLAYER_MAX_HP, maxHp,
deck: cardsData.starterDecks.rogue.slice(), deck: cardsData.starterDecks[root].slice(),
job: 'rogue', job: root,
turns: 0, turns: 0,
sectionCleared: 0, sectionCleared: 0,
diedAt: '', diedAt: '',
@@ -306,7 +327,7 @@ function main() {
else if (args[i] === '--scale-step') scaleStep = Number.parseFloat(args[++i]); else if (args[i] === '--scale-step') scaleStep = Number.parseFloat(args[++i]);
else if (args[i] === '--reward-min') minimumRewardValue = Number.parseFloat(args[++i]); else if (args[i] === '--reward-min') minimumRewardValue = Number.parseFloat(args[++i]);
} }
for (const branch of ['thief', 'assassin']) { for (const branch of ['thief', 'assassin', 'fighter', 'page']) {
console.log(formatCampaignReport(runCampaignBatch(branch, runs, seed, { restHeal, sectionHeal, scaleStep, minimumRewardValue }))); console.log(formatCampaignReport(runCampaignBatch(branch, runs, seed, { restHeal, sectionHeal, scaleStep, minimumRewardValue })));
} }
} }

View File

@@ -17,6 +17,16 @@ test('도적 전직 시점: 1섹션 Rogue, 2섹션 2차, 3섹션부터 3차', ()
test('3차 직업은 자기 계보 카드만 사용', () => { test('3차 직업은 자기 계보 카드만 사용', () => {
assert.deepEqual(playableClassesForJob('thiefmaster'), ['rogue', 'thief', 'thiefmaster']); assert.deepEqual(playableClassesForJob('thiefmaster'), ['rogue', 'thief', 'thiefmaster']);
assert.deepEqual(playableClassesForJob('hermit'), ['rogue', 'assassin', 'hermit']); assert.deepEqual(playableClassesForJob('hermit'), ['rogue', 'assassin', 'hermit']);
assert.deepEqual(playableClassesForJob('crusader'), ['warrior', 'fighter', 'crusader']);
assert.deepEqual(playableClassesForJob('knight'), ['warrior', 'page', 'knight']);
});
test('전사 전직 시점: 1섹션 Warrior, 2섹션 2차, 3섹션부터 3차', () => {
assert.equal(campaignJobAtSection('fighter', 1), 'warrior');
assert.equal(campaignJobAtSection('fighter', 2), 'fighter');
assert.equal(campaignJobAtSection('fighter', 3), 'crusader');
assert.equal(campaignJobAtSection('page', 2), 'page');
assert.equal(campaignJobAtSection('page', 5), 'knight');
}); });
test('섹션 난이도는 3차 이후 더 빠르게 증가', () => { test('섹션 난이도는 3차 이후 더 빠르게 증가', () => {

View File

@@ -99,7 +99,7 @@ export function chooseAction(hand, cards, energy, ctx = {}) {
const card = cards[x.id]; const card = cards[x.id];
if (!card || card.unplayable || !canPlayCardNow(card, ctx)) return false; if (!card || card.unplayable || !canPlayCardNow(card, ctx)) return false;
let effectiveCost = card.cost || 0; let effectiveCost = card.cost || 0;
if (ctx.handCostZeroThisTurn === true) effectiveCost = 0; if (ctx.handCostZeroThisTurn === true || ctx.zeroCostCardIdsThisTurn?.has(x.id) === true) effectiveCost = 0;
else if (card.useAllEnergy === true) effectiveCost = 1; else if (card.useAllEnergy === true) effectiveCost = 1;
else if (card.kind === 'Skill') { else if (card.kind === 'Skill') {
if (ctx.nextSkillCostZero === true) effectiveCost = 0; if (ctx.nextSkillCostZero === true) effectiveCost = 0;
@@ -116,7 +116,7 @@ export function chooseAction(hand, cards, energy, ctx = {}) {
const effectiveCost = (x) => { const effectiveCost = (x) => {
const card = cards[x.id]; const card = cards[x.id];
let cost = card.cost || 0; let cost = card.cost || 0;
if (ctx.handCostZeroThisTurn === true) cost = 0; if (ctx.handCostZeroThisTurn === true || ctx.zeroCostCardIdsThisTurn?.has(x.id) === true) cost = 0;
else if (card.useAllEnergy === true) cost = 1; else if (card.useAllEnergy === true) cost = 1;
else if (card.kind === 'Skill') { else if (card.kind === 'Skill') {
if (ctx.nextSkillCostZero === true) cost = 0; if (ctx.nextSkillCostZero === true) cost = 0;
@@ -127,7 +127,48 @@ export function chooseAction(hand, cards, energy, ctx = {}) {
} }
return cost; return cost;
}; };
const dmgEff = (x) => (cards[x.id].damage || 0) / Math.max(effectiveCost(x), 1); const countOtherHandSkills = (currentId) => {
let n = 0;
let skippedSelf = false;
for (const id of hand) {
if (!skippedSelf && id === currentId) {
skippedSelf = true;
continue;
}
if (cards[id]?.kind === 'Skill') n++;
}
return n;
};
const countOwnedNameMatches = (match) => {
if (!match) return 0;
let n = 0;
for (const id of hand) {
const name = cards[id]?.name || '';
if (name.includes(match)) n++;
}
for (const pile of [ctx.drawPileCards || [], ctx.discardCards || [], ctx.exhaustCards || []]) {
for (const id of pile) {
const name = cards[id]?.name || '';
if (name.includes(match)) n++;
}
}
return n;
};
const attackBaseEstimate = (x) => {
const card = cards[x.id];
let base = card.damage || 0;
base += (ctx.currentBlock || 0) * (card.damageFromCurrentBlock || 0);
if (card.damageNameMatch && card.damagePerOwnedNameMatch) {
base += countOwnedNameMatches(card.damageNameMatch) * card.damagePerOwnedNameMatch;
}
base += Math.max(0, hand.length - 1) * (card.damagePerOtherHandCard || 0);
base += (ctx.turnAttackCardsPlayed || 0) * (card.damagePerAttackPlayedThisTurn || 0);
base += countOtherHandSkills(x.id) * (card.damagePerSkillInHand || 0);
base += (ctx.cardsDrawnThisCombat || 0) * (card.damagePerCardDrawnThisCombat || 0);
if (base < 0) base = 0;
return base;
};
const dmgEff = (x) => attackBaseEstimate(x) / Math.max(effectiveCost(x), 1);
const blkEff = (x) => (cards[x.id].block || 0) / Math.max(effectiveCost(x), 1); const blkEff = (x) => (cards[x.id].block || 0) / Math.max(effectiveCost(x), 1);
const bestBy = (list, fn) => list.slice().sort((a, b) => fn(b) - fn(a))[0]; const bestBy = (list, fn) => list.slice().sort((a, b) => fn(b) - fn(a))[0];
if ((ctx.incomingDamage || 0) > (ctx.currentBlock || 0)) { if ((ctx.incomingDamage || 0) > (ctx.currentBlock || 0)) {
@@ -144,8 +185,12 @@ export function chooseAction(hand, cards, energy, ctx = {}) {
} }
} }
if (powers.length) return powers[0].i; if (powers.length) return powers[0].i;
if (attacks.length) return bestBy(attacks, dmgEff).i; if (attacks.length) {
const bestAttack = bestBy(attacks, dmgEff);
if (bestAttack && dmgEff(bestAttack) > 0) return bestAttack.i;
}
if (skills.length) return bestBy(skills, blkEff).i; if (skills.length) return bestBy(skills, blkEff).i;
if (attacks.length) return bestBy(attacks, dmgEff).i;
return -1; return -1;
} }
@@ -167,13 +212,14 @@ function bump(s, cost, dmg, blk) {
// 반환: { win, turns, playerHpRemaining, draw? } // 반환: { win, turns, playerHpRemaining, draw? }
export function simulateCombat(data, rng, stats) { export function simulateCombat(data, rng, stats) {
const { cards, starterDeck, monsters } = data; const { cards, starterDeck, monsters } = data;
const playerMaxHp = data.playerMaxHp || PLAYER_HP; let playerMaxHp = data.playerMaxHp || PLAYER_HP;
const startingPlayerHp = Math.min(data.playerHp ?? playerMaxHp, playerMaxHp); const startingPlayerHp = Math.min(data.playerHp ?? playerMaxHp, playerMaxHp);
if (monsters.length === 0) return { win: true, turns: 0, playerHpRemaining: startingPlayerHp }; if (monsters.length === 0) return { win: true, turns: 0, playerHpRemaining: startingPlayerHp };
let drawPile = prepareCombatDrawPile(shuffle(starterDeck, rng), cards); let drawPile = prepareCombatDrawPile(shuffle(starterDeck, rng), cards);
let discard = []; let discard = [];
const exhaust = []; const exhaust = [];
let hand = []; let hand = [];
const zeroCostCardIdsThisTurn = new Set();
let pHp = startingPlayerHp, pBlock = data.playerStartBlock || 0; let pHp = startingPlayerHp, pBlock = data.playerStartBlock || 0;
let pStr = data.playerStrength || 0, pDex = 0, pThorns = data.playerThorns || 0, pWeak = 0, pVuln = 0, pIntangible = 0; let pStr = data.playerStrength || 0, pDex = 0, pThorns = data.playerThorns || 0, pWeak = 0, pVuln = 0, pIntangible = 0;
let blockGainMultiplier = 1; let blockGainMultiplier = 1;
@@ -200,6 +246,9 @@ export function simulateCombat(data, rng, stats) {
let cardsDrawnThisCombat = 0; let cardsDrawnThisCombat = 0;
let bonusRewardScreens = 0; let bonusRewardScreens = 0;
let activeKillReward = 0; let activeKillReward = 0;
let comboCount = 0;
let holyChargeCount = 0;
let damagePowerStrengthUsed = false;
let energy = 0; let energy = 0;
const powers = []; const powers = [];
const mob = monsters.map((m) => ({ const mob = monsters.map((m) => ({
@@ -215,6 +264,14 @@ export function simulateCombat(data, rng, stats) {
if (!alive.length) return null; if (!alive.length) return null;
return alive[Math.floor(rng() * alive.length)]; return alive[Math.floor(rng() * alive.length)];
}; };
const randomCardPool = (sourceCard) => Object.entries(cards)
.filter(([, rc]) => {
if (!rc || rc.token === true || rc.curse === true || rc.unplayable === true) return false;
if (sourceCard.addRandomCardKind && rc.kind !== sourceCard.addRandomCardKind) return false;
if (sourceCard.addRandomCardSameClass === true && rc.class !== sourceCard.class) return false;
return true;
})
.map(([id]) => id);
const expectedIncomingDamage = () => mob.filter((m) => m.alive).reduce((total, m) => { const expectedIncomingDamage = () => mob.filter((m) => m.alive).reduce((total, m) => {
if (!m.intents || m.intents.length === 0) return total; if (!m.intents || m.intents.length === 0) return total;
const expected = m.intents.reduce((sum, intent) => { const expected = m.intents.reduce((sum, intent) => {
@@ -315,10 +372,26 @@ export function simulateCombat(data, rng, stats) {
if (hand.length >= 10) { if (hand.length >= 10) {
discard.push(card); discard.push(card);
triggerSly(card); triggerSly(card);
} else hand.push(card); } else {
hand.push(card);
triggerDrawNameMatchAutoPlay(card);
}
} }
return drawn; return drawn;
} }
function triggerDrawNameMatchAutoPlay(drawnId) {
const drawnCard = cards[drawnId];
const drawnName = drawnCard?.name || '';
if (!drawnName) return;
for (const pid of powers) {
const pc = cards[pid];
if (!pc?.drawNameMatchAutoPlay || !drawnName.includes(pc.drawNameMatchAutoPlay)) continue;
const idx = hand.indexOf(drawnId);
if (idx < 0) continue;
hand.splice(idx, 1);
autoPlayCardFromEffect(drawnId, 0);
}
}
function addCardsToHand(id, n) { function addCardsToHand(id, n) {
for (let k = 0; k < n; k++) { for (let k = 0; k < n; k++) {
if (hand.length >= 10) discard.push(id); if (hand.length >= 10) discard.push(id);
@@ -380,8 +453,26 @@ export function simulateCombat(data, rng, stats) {
} }
return n; return n;
} }
function countOwnedNameMatches(match) {
if (!match) return 0;
let n = 0;
for (const pile of [hand, drawPile, discard, exhaust]) {
for (const id of pile) {
const name = cards[id]?.name || '';
if (name.includes(match)) n++;
}
}
return n;
}
function attackBaseForCard(id, c) { function attackBaseForCard(id, c) {
let base = c.damage || 0; let base = c.damage || 0;
if (c.damageNameMatch && c.damagePerOwnedNameMatch) {
base += countOwnedNameMatches(c.damageNameMatch) * c.damagePerOwnedNameMatch;
}
if (c.damageFromCurrentBlock) base += pBlock * c.damageFromCurrentBlock;
const comboScale = (c.damagePerCombo || 0) + powerFieldTotal('attackDamagePerCombo');
if (comboScale) base += comboCount * comboScale;
if (c.damagePerHolyCharge) base += holyChargeCount * c.damagePerHolyCharge;
const otherHand = Math.max(0, hand.length - 1); const otherHand = Math.max(0, hand.length - 1);
if (c.damagePerOtherHandCard) base += otherHand * c.damagePerOtherHandCard; if (c.damagePerOtherHandCard) base += otherHand * c.damagePerOtherHandCard;
if (c.damagePerAttackPlayedThisTurn) base += turnAttackCardsPlayed * c.damagePerAttackPlayedThisTurn; if (c.damagePerAttackPlayedThisTurn) base += turnAttackCardsPlayed * c.damagePerAttackPlayedThisTurn;
@@ -433,6 +524,69 @@ export function simulateCombat(data, rng, stats) {
} }
return total; return total;
} }
function powerFieldMax(field) {
let best = 0;
for (const pid of powers) best = Math.max(best, cards[pid]?.[field] || 0);
return best;
}
function comboMax() {
return Math.max(5, powerFieldMax('comboMax'));
}
function gainCombo(amount) {
if (amount > 0) comboCount = Math.min(comboMax(), comboCount + amount);
}
function holyChargeMax() {
return Math.max(3, powerFieldMax('holyChargeMax'));
}
function gainHolyCharge(amount) {
if (amount > 0) holyChargeCount = Math.min(holyChargeMax(), holyChargeCount + amount);
}
function triggerExhaust(count = 1) {
const drawOnExhaust = powerFieldTotal('drawOnExhaust');
if (drawOnExhaust > 0 && count > 0) draw(drawOnExhaust * count);
}
function addRandomCardsFromEffect(sourceCard, count) {
if (!count || count <= 0) return [];
const pool = randomCardPool(sourceCard);
if (!pool.length) return [];
const added = [];
for (let i = 0; i < count; i++) {
const id = pool[Math.floor(rng() * pool.length)];
if (!id) continue;
addCardsToHand(id, 1);
if (sourceCard.addedCardsCostZeroThisTurn === true) zeroCostCardIdsThisTurn.add(id);
added.push(id);
}
return added;
}
function exhaustHandNonAttackEffects(c) {
if (c.exhaustHandNonAttack !== true || hand.length === 0) return 0;
let exhaustedCount = 0;
for (let i = hand.length - 1; i >= 0; i--) {
const id = hand[i];
const hc = cards[id];
if (hc?.kind === 'Attack') continue;
hand.splice(i, 1);
exhaust.push(id);
exhaustedCount++;
}
if (exhaustedCount > 0) {
if (c.blockPerExhaustedCard) addBlock(exhaustedCount * c.blockPerExhaustedCard);
triggerExhaust(exhaustedCount);
}
return exhaustedCount;
}
function exhaustHandAllEffects(c) {
if (c.exhaustHandAll !== true || hand.length === 0) return 0;
let exhaustedCount = 0;
while (hand.length > 0) {
const id = hand.pop();
exhaust.push(id);
exhaustedCount++;
}
if (exhaustedCount > 0) triggerExhaust(exhaustedCount);
return exhaustedCount;
}
function resolveCardEffects(id, c, costSpent, recordStats = true) { function resolveCardEffects(id, c, costSpent, recordStats = true) {
const alive = aliveList(); const alive = aliveList();
let dmg = 0; let dmg = 0;
@@ -461,7 +615,7 @@ export function simulateCombat(data, rng, stats) {
} }
const xEnergy = costSpent || 0; const xEnergy = costSpent || 0;
if (c.kind === 'Attack') { if (c.kind === 'Attack') {
if (alive.length && (c.damage || c.xDamagePerEnergy)) { if (alive.length && (c.damage != null || c.xDamagePerEnergy != null || c.damageFromCurrentBlock != null)) {
const baseDamage = c.xDamagePerEnergy ? xEnergy * c.xDamagePerEnergy : attackBaseForCard(id, c); const baseDamage = c.xDamagePerEnergy ? xEnergy * c.xDamagePerEnergy : attackBaseForCard(id, c);
const bonusHits = (c.otherHandAtLeast && c.bonusHitsWhenOtherHandAtLeast && Math.max(0, hand.length - 1) >= c.otherHandAtLeast) const bonusHits = (c.otherHandAtLeast && c.bonusHitsWhenOtherHandAtLeast && Math.max(0, hand.length - 1) >= c.otherHandAtLeast)
? c.bonusHitsWhenOtherHandAtLeast : 0; ? c.bonusHitsWhenOtherHandAtLeast : 0;
@@ -476,8 +630,9 @@ export function simulateCombat(data, rng, stats) {
if (!target || !target.alive) return { killed: false, dealt: 0 }; if (!target || !target.alive) return { killed: false, dealt: 0 };
let dealt = amount; let dealt = amount;
if (target.vuln > 0) dealt = Math.floor(dealt * 1.5); if (target.vuln > 0) dealt = Math.floor(dealt * 1.5);
if (target.weak > 0 && c.attackDamageVsWeakMultiplier && c.attackDamageVsWeakMultiplier > 1) { const weakMultiplier = Math.max(c.attackDamageVsWeakMultiplier || 1, powerFieldMax('attackDamageVsWeakMultiplier'));
dealt = Math.floor(dealt * c.attackDamageVsWeakMultiplier); if (target.weak > 0 && weakMultiplier > 1) {
dealt = Math.floor(dealt * weakMultiplier);
} }
if (c.pierce === true) { if (c.pierce === true) {
target.hp -= dealt; target.hp -= dealt;
@@ -493,6 +648,10 @@ export function simulateCombat(data, rng, stats) {
target.alive = false; target.alive = false;
killed = true; killed = true;
if (c.rewardOnKill) bonusRewardScreens += c.rewardOnKill; if (c.rewardOnKill) bonusRewardScreens += c.rewardOnKill;
if (c.maxHpOnKill) {
playerMaxHp += c.maxHpOnKill;
pHp += c.maxHpOnKill;
}
} }
return { killed, dealt }; return { killed, dealt };
}; };
@@ -534,11 +693,11 @@ export function simulateCombat(data, rng, stats) {
roundKilled = resolveAttackRound(); roundKilled = resolveAttackRound();
} while (c.repeatOnKill === true && roundKilled === true && countAliveMonsters() > 0); } while (c.repeatOnKill === true && roundKilled === true && countAliveMonsters() > 0);
} }
if (c.block) blockGained = addBlock(c.block); if (c.block) blockGained = addBlock(c.block + holyChargeCount * (c.blockPerHolyCharge || 0));
} else if (c.kind === 'Power') { } else if (c.kind === 'Power') {
if (recordStats) powers.push(id); powers.push(id);
} else { } else {
if (c.block) blockGained = addBlock(c.block); if (c.block) blockGained = addBlock(c.block + holyChargeCount * (c.blockPerHolyCharge || 0));
const weakAmount = (c.weak || 0) + (c.xWeakPerEnergy || 0) * xEnergy; const weakAmount = (c.weak || 0) + (c.xWeakPerEnergy || 0) * xEnergy;
const vulnAmount = c.vuln || 0; const vulnAmount = c.vuln || 0;
if ((weakAmount || vulnAmount || c.poison || c.removeEnemyBlock || c.removeEnemyArtifact || c.enemyStrengthLossThisTurn) && alive.length) { if ((weakAmount || vulnAmount || c.poison || c.removeEnemyBlock || c.removeEnemyArtifact || c.enemyStrengthLossThisTurn) && alive.length) {
@@ -570,8 +729,10 @@ export function simulateCombat(data, rng, stats) {
if (c.dex) pDex += c.dex; if (c.dex) pDex += c.dex;
if (c.thorns) pThorns += c.thorns; if (c.thorns) pThorns += c.thorns;
if (c.selfVuln) pVuln += c.selfVuln; if (c.selfVuln) pVuln += c.selfVuln;
if (c.heal) pHp = Math.min(pHp + c.heal, playerMaxHp); if (c.heal) pHp = Math.min(pHp + c.heal + holyChargeCount * (c.healPerHolyCharge || 0), playerMaxHp);
if (c.gainEnergy) energy += c.gainEnergy; if (c.gainEnergy) energy += c.gainEnergy;
if (c.kind !== 'Attack' && c.comboGain) gainCombo(c.comboGain);
if (c.removePlayerDebuffs === true) { pWeak = 0; pVuln = 0; }
activeKillReward = c.rewardOnKill || 0; activeKillReward = c.rewardOnKill || 0;
if (c.intangible) pIntangible += c.intangible; if (c.intangible) pIntangible += c.intangible;
queueNextTurnEffects(c); queueNextTurnEffects(c);
@@ -588,6 +749,28 @@ export function simulateCombat(data, rng, stats) {
} }
} }
if (c.addShiv && !c.discard && c.discardAll !== true) addCardsToHand('Shiv', c.addShiv); if (c.addShiv && !c.discard && c.discardAll !== true) addCardsToHand('Shiv', c.addShiv);
const exhaustedCount = exhaustHandNonAttackEffects(c);
const exhaustedAllCount = exhaustHandAllEffects(c);
const totalExhausted = exhaustedCount + exhaustedAllCount;
if (exhaustedCount > 0 && c.blockPerExhaustedCard) {
blockGained += exhaustedCount * c.blockPerExhaustedCard;
}
if (c.drawPerExhausted && totalExhausted > 0) {
draw(totalExhausted * c.drawPerExhausted);
}
if (c.addRandomCardCount) addRandomCardsFromEffect(c, c.addRandomCardCount);
if (c.addRandomCardPerExhausted) {
if (totalExhausted > 0) addRandomCardsFromEffect(c, totalExhausted * c.addRandomCardPerExhausted);
}
const topPlayCount = (c.playTopDrawPileCount || 0) + ((c.playTopDrawPileCountPerEnergy || 0) * xEnergy);
if (topPlayCount > 0) {
for (let i = 0; i < topPlayCount; i++) {
if (drawPile.length <= 0) break;
const topId = drawPile.pop();
if (!topId) break;
autoPlayCardFromEffect(topId, 0);
}
}
if (c.cardPlayedDamage && alive.length) { if (c.cardPlayedDamage && alive.length) {
const target = chooseTarget(aliveList(), 0); const target = chooseTarget(aliveList(), 0);
if (target && target.alive) { if (target && target.alive) {
@@ -609,6 +792,28 @@ export function simulateCombat(data, rng, stats) {
} }
} }
} }
if (c.kind === 'Attack') {
gainCombo((c.comboGain || 0) + powerFieldTotal('comboOnAttack'));
const extraDamage = powerFieldTotal('attackPlayedDamage');
if (extraDamage > 0) {
const target = chooseTarget(aliveList(), extraDamage);
if (target) {
const r = applyDamage(target.hp, target.block, extraDamage);
target.hp = r.hp; target.block = r.block;
damageDealtThisTurn += extraDamage;
if (target.hp <= 0) target.alive = false;
}
}
const attackWeak = powerFieldTotal('attackWeak');
if (attackWeak > 0) {
const target = chooseTarget(aliveList(), 0);
if (target) applyMonsterWeak(target, attackWeak);
}
}
let holyGain = c.holyChargeGain || 0;
if (c.holyForce === true) holyGain += powerFieldTotal('holyChargeOnHolyForce');
gainHolyCharge(holyGain);
if (c.holyChargeSpendAll === true) holyChargeCount = 0;
if (c.blockPerDamageDealtThisTurn && c.blockPerDamageDealtThisTurn > 0 && c.kind !== 'Power') { if (c.blockPerDamageDealtThisTurn && c.blockPerDamageDealtThisTurn > 0 && c.kind !== 'Power') {
blockGained += addBlock(Math.max(0, damageDealtThisTurn * c.blockPerDamageDealtThisTurn)); blockGained += addBlock(Math.max(0, damageDealtThisTurn * c.blockPerDamageDealtThisTurn));
} }
@@ -639,7 +844,48 @@ export function simulateCombat(data, rng, stats) {
if (c.addShivPerDiscard === true) addCardsToHand('Shiv', discarded); if (c.addShivPerDiscard === true) addCardsToHand('Shiv', discarded);
if (c.drawPerDiscarded) draw(discarded * c.drawPerDiscarded); if (c.drawPerDiscarded) draw(discarded * c.drawPerDiscarded);
} }
function autoPlayCardFromEffect(id, energySpent = 0) {
const c = cards[id];
if (!c) return false;
const skillFree = c.kind === 'Skill' && c.useAllEnergy !== true && nextSkillCostZero === true;
const skillRepeat = c.kind === 'Skill' && (nextSkillRepeatCount || 0) > 0 ? nextSkillRepeatCount : 0;
activeKillReward = c.rewardOnKill || 0;
resolveCardEffects(id, c, energySpent, false);
const playedBlock = powerFieldTotal('cardPlayedBlock');
if (playedBlock > 0) addBlock(playedBlock);
if (c.cardPlayedDamage && aliveList().length) {
const target = chooseTarget(aliveList(), 0);
if (target && target.alive) {
target.hp -= c.cardPlayedDamage;
damageDealtThisTurn += c.cardPlayedDamage;
if (target.hp <= 0) target.alive = false;
}
}
if (c.cardPlayedRandomDamage && aliveList().length) {
const target = randomAliveMonster();
if (target) {
target.hp -= c.cardPlayedRandomDamage;
damageDealtThisTurn += c.cardPlayedRandomDamage;
if (target.hp <= 0) target.alive = false;
}
}
if (skillRepeat > 0) {
nextSkillRepeatCount = Math.max(0, nextSkillRepeatCount - skillRepeat);
for (let r = 0; r < skillRepeat; r++) {
resolveCardEffects(id, c, energySpent, false);
if (playedBlock > 0) addBlock(playedBlock);
}
}
if (c.kind === 'Attack') turnAttackCardsPlayed++;
if (skillFree === true && c.nextSkillCostZero !== true) nextSkillCostZero = false;
if (c.exhaust === true || String(c.desc || '').includes('소멸.')) {
exhaust.push(id);
triggerExhaust(1);
} else if (c.kind !== 'Power') {
discard.push(id);
}
return true;
}
while (turns < MAX_TURNS) { while (turns < MAX_TURNS) {
turns++; turns++;
turnAttackCardsPlayed = 0; turnAttackCardsPlayed = 0;
@@ -655,7 +901,9 @@ export function simulateCombat(data, rng, stats) {
drawDisabledThisTurn = false; drawDisabledThisTurn = false;
skillCostReductionThisTurn = 0; skillCostReductionThisTurn = 0;
// 파워 발동 — Lua StartPlayerTurn 동기화 (블록 리셋 후 strength/energy/block 파워) // 파워 발동 — Lua StartPlayerTurn 동기화 (블록 리셋 후 strength/energy/block 파워)
zeroCostCardIdsThisTurn.clear();
if (nextTurnKeepBlock === true) nextTurnKeepBlock = false; if (nextTurnKeepBlock === true) nextTurnKeepBlock = false;
else if (powers.some((pid) => cards[pid]?.powerEffect === 'keepBlock')) {}
else pBlock = 0; else pBlock = 0;
turnAttackMultiplier = nextTurnAttackMultiplier; turnAttackMultiplier = nextTurnAttackMultiplier;
nextTurnAttackMultiplier = 1; nextTurnAttackMultiplier = 1;
@@ -668,6 +916,7 @@ export function simulateCombat(data, rng, stats) {
if (pc.powerEffect === 'strengthPerTurn') pStr += pc.value; if (pc.powerEffect === 'strengthPerTurn') pStr += pc.value;
else if (pc.powerEffect === 'energyPerTurn') energyBonus += pc.value; else if (pc.powerEffect === 'energyPerTurn') energyBonus += pc.value;
else if (pc.powerEffect === 'blockPerTurn') pBlock += pc.value; else if (pc.powerEffect === 'blockPerTurn') pBlock += pc.value;
else if (pc.powerEffect === 'keepBlock') {}
else if (pc.powerEffect === 'poisonPerTurn') { else if (pc.powerEffect === 'poisonPerTurn') {
for (const m of mob) if (m.alive) applyPoisonToMonster(m, pc.value); for (const m of mob) if (m.alive) applyPoisonToMonster(m, pc.value);
} else if (pc.powerEffect === 'damagePerTurn') { } else if (pc.powerEffect === 'damagePerTurn') {
@@ -677,6 +926,8 @@ export function simulateCombat(data, rng, stats) {
m.hp = r.hp; m.block = r.block; m.hp = r.hp; m.block = r.block;
if (m.hp <= 0) m.alive = false; if (m.hp <= 0) m.alive = false;
} }
} else if (pc.powerEffect === 'healPerTurn') {
pHp = Math.min(playerMaxHp, pHp + (pc.value || 0));
} }
if (pc.turnStartShiv) addCardsToHand('Shiv', pc.turnStartShiv); if (pc.turnStartShiv) addCardsToHand('Shiv', pc.turnStartShiv);
if (pc.turnStartDraw) powerTurnDraw += pc.turnStartDraw; if (pc.turnStartDraw) powerTurnDraw += pc.turnStartDraw;
@@ -701,8 +952,14 @@ export function simulateCombat(data, rng, stats) {
skillCostReductionThisTurn, skillCostReductionThisTurn,
handCostZeroThisTurn, handCostZeroThisTurn,
combatCardCostReduction, combatCardCostReduction,
zeroCostCardIdsThisTurn,
incomingDamage: data.smartPlayer === true ? expectedIncomingDamage() : 0, incomingDamage: data.smartPlayer === true ? expectedIncomingDamage() : 0,
currentBlock: pBlock, currentBlock: pBlock,
turnAttackCardsPlayed,
cardsDrawnThisCombat,
drawPileCards: drawPile,
discardCards: discard,
exhaustCards: exhaust,
}); });
if (idx < 0) break; if (idx < 0) break;
const id = hand[idx], c = cards[id]; const id = hand[idx], c = cards[id];
@@ -714,6 +971,7 @@ export function simulateCombat(data, rng, stats) {
const cost = handCostZeroThisTurn === true ? 0 : (c.useAllEnergy === true ? energy : (skillFree ? 0 : (c.kind === 'Skill' ? Math.max(0, baseCost - skillCostReductionThisTurn) : baseCost))); const cost = handCostZeroThisTurn === true ? 0 : (c.useAllEnergy === true ? energy : (skillFree ? 0 : (c.kind === 'Skill' ? Math.max(0, baseCost - skillCostReductionThisTurn) : baseCost)));
const finalCost = c.useAllEnergy === true ? cost : Math.max(0, cost - combatReduction); const finalCost = c.useAllEnergy === true ? cost : Math.max(0, cost - combatReduction);
energy -= finalCost; energy -= finalCost;
hand.splice(idx, 1);
resolveCardEffects(id, c, finalCost); resolveCardEffects(id, c, finalCost);
if (c.kind === 'Attack' && (data.healOnAttack || 0) > 0) { if (c.kind === 'Attack' && (data.healOnAttack || 0) > 0) {
pHp = Math.min(playerMaxHp, pHp + data.healOnAttack); pHp = Math.min(playerMaxHp, pHp + data.healOnAttack);
@@ -729,9 +987,11 @@ export function simulateCombat(data, rng, stats) {
} }
if (c.kind === 'Attack') turnAttackCardsPlayed++; if (c.kind === 'Attack') turnAttackCardsPlayed++;
if (skillFree === true && c.nextSkillCostZero !== true) nextSkillCostZero = false; if (skillFree === true && c.nextSkillCostZero !== true) nextSkillCostZero = false;
hand.splice(idx, 1);
queueSelectedReserve(c); queueSelectedReserve(c);
if (c.exhaust === true || String(c.desc || '').includes('소멸.')) exhaust.push(id); if (c.exhaust === true || String(c.desc || '').includes('소멸.')) {
exhaust.push(id);
triggerExhaust(1);
}
else if (c.kind !== 'Power') discard.push(id); else if (c.kind !== 'Power') discard.push(id);
if (c.combatCostReductionOnPlay && c.combatCostReductionOnPlay > 0) { if (c.combatCostReductionOnPlay && c.combatCostReductionOnPlay > 0) {
combatCardCostReduction[id] = (combatCardCostReduction[id] || 0) + c.combatCostReductionOnPlay; combatCardCostReduction[id] = (combatCardCostReduction[id] || 0) + c.combatCostReductionOnPlay;
@@ -781,8 +1041,18 @@ export function simulateCombat(data, rng, stats) {
const atk = calcEnemyAttack(it.value, m.str, m.weak, pVuln, enemyStrengthLossThisTurn); const atk = calcEnemyAttack(it.value, m.str, m.weak, pVuln, enemyStrengthLossThisTurn);
const beforeHp = pHp; const beforeHp = pHp;
let incoming = atk; let incoming = atk;
const reduction = Math.min(0.75, powerFieldTotal('damageTakenReduction'));
if (reduction > 0) incoming = Math.floor(incoming * (1 - reduction));
if (pIntangible > 0 && incoming > 1) incoming = 1; if (pIntangible > 0 && incoming > 1) incoming = 1;
const r = applyDamage(pHp, pBlock, incoming); pHp = r.hp; pBlock = r.block; const r = applyDamage(pHp, pBlock, incoming); pHp = r.hp; pBlock = r.block;
if (beforeHp > pHp) {
const reactiveBlock = powerFieldTotal('blockOnDamaged');
if (reactiveBlock > 0) addBlock(reactiveBlock);
if (!damagePowerStrengthUsed) {
const reactiveStrength = powerFieldTotal('strengthOnDamagedOnce');
if (reactiveStrength > 0) { pStr += reactiveStrength; damagePowerStrengthUsed = true; }
}
}
if (beforeHp > pHp && pThorns > 0) { if (beforeHp > pHp && pThorns > 0) {
m.hp -= pThorns; m.hp -= pThorns;
if (m.hp <= 0) m.alive = false; if (m.hp <= 0) m.alive = false;

View File

@@ -649,9 +649,10 @@ test("simulateCombat: damagePerAttackPlayedThisTurn scales Finisher", () => {
starterDeck: ["Hit", "Finisher"], starterDeck: ["Hit", "Finisher"],
monsters: [{ name: "Dummy", maxHp: 12, intents: [{ kind: "Attack", value: 0 }] }], monsters: [{ name: "Dummy", maxHp: 12, intents: [{ kind: "Attack", value: 0 }] }],
}; };
const r = simulateCombat(data, () => 0); const stats = {};
const r = simulateCombat(data, () => 0, stats);
assert.equal(r.win, true); assert.equal(r.win, true);
assert.equal(r.turns, 2); assert.ok((stats.Finisher?.damage || 0) >= 6);
}); });
test("simulateCombat: damagePerOtherHandCard and damagePerSkillInHand are applied", () => { test("simulateCombat: damagePerOtherHandCard and damagePerSkillInHand are applied", () => {
@@ -666,9 +667,11 @@ test("simulateCombat: damagePerOtherHandCard and damagePerSkillInHand are applie
starterDeck: ["Skill1", "Skill2", "Blank", "Precise", "Flechettes"], starterDeck: ["Skill1", "Skill2", "Blank", "Precise", "Flechettes"],
monsters: [{ name: "Dummy", maxHp: 21, intents: [{ kind: "Attack", value: 0 }] }], monsters: [{ name: "Dummy", maxHp: 21, intents: [{ kind: "Attack", value: 0 }] }],
}; };
const r = simulateCombat(data, () => 0); const stats = {};
const r = simulateCombat(data, () => 0, stats);
assert.equal(r.win, true); assert.equal(r.win, true);
assert.equal(r.turns, 5); assert.ok((stats.Precise?.damage || 0) >= 5);
assert.ok((stats.Flechettes?.damage || 0) >= 10);
}); });
test("simulateCombat: damagePerDiscardedThisTurn and bonusHitsWhenOtherHandAtLeast work", () => { test("simulateCombat: damagePerDiscardedThisTurn and bonusHitsWhenOtherHandAtLeast work", () => {
@@ -1099,6 +1102,90 @@ test("simulateCombat: blockPerDamageDealtThisTurn grants block from damage dealt
assert.equal(r.win, true); assert.equal(r.win, true);
}); });
test("simulateCombat: damageFromCurrentBlock uses current block as attack damage", () => {
const data = {
cards: {
Guard: { name: "Guard", cost: 1, kind: "Skill", block: 5 },
BodySlam: { name: "BodySlam", cost: 1, kind: "Attack", damageFromCurrentBlock: 1 },
},
starterDeck: ["Guard", "BodySlam"],
monsters: [{ name: "Dummy", maxHp: 5, intents: [{ kind: "Attack", value: 0 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
assert.equal(r.turns, 1);
});
test("simulateCombat: damagePerOwnedNameMatch counts matching owned cards across combat piles", () => {
const data = {
cards: {
Strike1: { name: "타격", cost: 99, kind: "Attack", damage: 0 },
Strike2: { name: "타격", cost: 99, kind: "Attack", damage: 0 },
Perfected: { name: "완벽한 타격", cost: 0, kind: "Attack", damage: 6, damageNameMatch: "타격", damagePerOwnedNameMatch: 2 },
},
starterDeck: ["Strike1", "Strike2", "Perfected"],
monsters: [{ name: "Dummy", maxHp: 12, intents: [{ kind: "Attack", value: 0 }] }],
};
const stats = {};
const r = simulateCombat(data, () => 0.999999, stats);
assert.equal(r.win, true);
assert.ok((stats.Perfected?.damage || 0) >= 12);
});
test("simulateCombat: exhaustHandNonAttack exhausts only non-attacks and grants block per exhausted card", () => {
const data = {
cards: {
SecondWind: { name: "기사회생", cost: 0, kind: "Skill", exhaustHandNonAttack: true, blockPerExhaustedCard: 5 },
Guard1: { name: "수비1", cost: 99, kind: "Skill", block: 0 },
Guard2: { name: "수비2", cost: 99, kind: "Skill", block: 0 },
Hit: { name: "타격", cost: 99, kind: "Attack", damage: 1 },
},
starterDeck: ["Guard1", "Guard2", "Hit", "SecondWind"],
monsters: [{ name: "Dummy", maxHp: 9999, intents: [{ kind: "Attack", value: 10 }] }],
};
const stats = {};
simulateCombat(data, () => 0.999999, stats);
assert.ok((stats.SecondWind?.block || 0) >= 10);
});
test("simulateCombat: drawOnExhaust draws when cards are exhausted", () => {
const data = {
cards: {
Embrace: { name: "어둠의 포옹", cost: 0, kind: "Power", drawOnExhaust: 1 },
Burn: { name: "소각", cost: 0, kind: "Skill", exhaust: true },
Hit: { name: "타격", cost: 0, kind: "Attack", damage: 6 },
},
starterDeck: ["Embrace", "Burn", "Hit"],
monsters: [{ name: "Dummy", maxHp: 6, intents: [{ kind: "Attack", value: 0 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
assert.equal(r.turns, 1);
});
test("simulateCombat: keepBlock power preserves block across turns", () => {
const data = {
cards: {
Barricade: { name: "바리케이드", cost: 0, kind: "Power", powerEffect: "keepBlock", value: 0 },
Guard: { name: "수비", cost: 0, kind: "Skill", block: 5 },
Pass: { name: "대기", cost: 99, kind: "Skill", block: 0 },
},
starterDeck: ["Barricade", "Guard", "Pass"],
monsters: [{ name: "Dummy", maxHp: 9999, intents: [{ kind: "Attack", value: 3 }, { kind: "Attack", value: 3 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.draw, true);
assert.equal(r.playerHpRemaining, 80);
});
test("chooseAction: damageFromCurrentBlock values attack using current block", () => {
const cards = {
Guard: { name: "Guard", cost: 1, kind: "Skill", block: 5 },
BodySlam: { name: "BodySlam", cost: 1, kind: "Attack", damageFromCurrentBlock: 1 },
};
assert.equal(chooseAction(["BodySlam", "Guard"], cards, 1, { currentBlock: 6 }), 0);
});
test("simulateCombat: cardPlayedRandomDamage hits a random enemy on card play", () => { test("simulateCombat: cardPlayedRandomDamage hits a random enemy on card play", () => {
const data = { const data = {
cards: { cards: {
@@ -1124,6 +1211,95 @@ test("simulateCombat: rewardOnKill grants an extra reward screen when an attack
assert.equal(r.bonusRewardScreens, 1); assert.equal(r.bonusRewardScreens, 1);
}); });
test("simulateCombat: maxHpOnKill increases max hp and heals when attack kills", () => {
const data = {
cards: {
Feed: { name: "포식", cost: 1, kind: "Attack", damage: 10, maxHpOnKill: 3 },
},
starterDeck: ["Feed"],
monsters: [{ name: "Dummy", maxHp: 10, intents: [{ kind: "Attack", value: 0 }] }],
playerHp: 50,
playerMaxHp: 80,
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
assert.equal(r.playerHpRemaining, 53);
});
test("simulateCombat: drawNameMatchAutoPlay auto-plays matching drawn cards", () => {
const data = {
cards: {
Hellraiser: { name: "지옥검무", cost: 0, kind: "Power", drawNameMatchAutoPlay: "타격" },
Strike: { name: "강타격", cost: 99, kind: "Attack", damage: 9 },
Pass1: { name: "대기1", cost: 99, kind: "Skill" },
Pass2: { name: "대기2", cost: 99, kind: "Skill" },
Pass3: { name: "대기3", cost: 99, kind: "Skill" },
Pass4: { name: "대기4", cost: 99, kind: "Skill" },
},
starterDeck: ["Hellraiser", "Pass1", "Pass2", "Pass3", "Pass4", "Strike"],
monsters: [{ name: "Dummy", maxHp: 9, intents: [{ kind: "Attack", value: 0 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
});
test("simulateCombat: addRandomCardCount can add same-class attack as zero-cost this turn", () => {
const data = {
cards: {
InfernalBlade: {
name: "지옥검",
cost: 0,
kind: "Skill",
addRandomCardCount: 1,
addRandomCardKind: "Attack",
addRandomCardSameClass: true,
addedCardsCostZeroThisTurn: true,
class: "warrior",
},
BigHit: { name: "큰 일격", cost: 2, kind: "Attack", damage: 12, class: "warrior" },
OffClass: { name: "외부 공격", cost: 0, kind: "Attack", damage: 1, class: "rogue" },
},
starterDeck: ["InfernalBlade"],
monsters: [{ name: "Dummy", maxHp: 12, intents: [{ kind: "Attack", value: 0 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
});
test("simulateCombat: drawPerExhausted draws for each exhausted card", () => {
const data = {
cards: {
Stoke: { name: "화력 증폭", cost: 0, kind: "Skill", exhaustHandAll: true, drawPerExhausted: 1 },
Filler1: { name: "채우기1", cost: 99, kind: "Skill" },
Filler2: { name: "채우기2", cost: 99, kind: "Skill" },
Hit: { name: "일격", cost: 0, kind: "Attack", damage: 8 },
},
starterDeck: ["Stoke", "Filler1", "Filler2", "Hit"],
monsters: [{ name: "Dummy", maxHp: 8, intents: [{ kind: "Attack", value: 0 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
});
test("simulateCombat: playTopDrawPileCountPerEnergy auto-plays top draw pile cards", () => {
const data = {
cards: {
Cascade: { name: "연쇄", cost: 0, kind: "Skill", useAllEnergy: true, playTopDrawPileCountPerEnergy: 1, innate: true },
Filler1: { name: "준비1", cost: 99, kind: "Skill", innate: true },
Filler2: { name: "준비2", cost: 99, kind: "Skill", innate: true },
Filler3: { name: "준비3", cost: 99, kind: "Skill", innate: true },
Filler4: { name: "준비4", cost: 99, kind: "Skill", innate: true },
Hit1: { name: "타격1", cost: 99, kind: "Attack", damage: 6 },
Hit2: { name: "타격2", cost: 99, kind: "Attack", damage: 6 },
Hit3: { name: "타격3", cost: 99, kind: "Attack", damage: 6 },
},
starterDeck: ["Cascade", "Filler1", "Filler2", "Filler3", "Filler4", "Hit1", "Hit2", "Hit3"],
monsters: [{ name: "Dummy", maxHp: 18, intents: [{ kind: "Attack", value: 0 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
});
test("simulateCombat: intangible cards reduce incoming damage and persist across turns", () => { test("simulateCombat: intangible cards reduce incoming damage and persist across turns", () => {
const data = { const data = {
cards: { cards: {
@@ -1215,3 +1391,102 @@ test("simulateCombat: shivAoe makes Shivs hit all enemies", () => {
assert.equal(r.win, true); assert.equal(r.win, true);
assert.equal(r.turns, 1); assert.equal(r.turns, 1);
}); });
test("simulateCombat: comboGain and damagePerCombo scale repeated attacks", () => {
const data = {
cards: {
Brandish: { name: "브랜디쉬", cost: 1, kind: "Attack", damage: 2, hits: 2, comboGain: 1, damagePerCombo: 1 },
},
starterDeck: ["Brandish"],
monsters: [{ name: "Dummy", maxHp: 14, intents: [{ kind: "Attack", value: 0 }] }],
};
const stats = {};
const r = simulateCombat(data, () => 0.999999, stats);
assert.equal(r.win, true);
assert.ok(stats.Brandish.damage > stats.Brandish.plays * 4);
});
test("simulateCombat: comboMax power raises the combo cap", () => {
const data = {
cards: {
ComboSynergy: { name: "콤보 시너지", cost: 0, kind: "Power", comboMax: 8, comboOnAttack: 2, attackDamagePerCombo: 1, innate: true },
Hit: { name: "연속 베기", cost: 0, kind: "Attack", damage: 1 },
},
starterDeck: ["ComboSynergy", "Hit"],
monsters: [{ name: "Dummy", maxHp: 40, intents: [{ kind: "Attack", value: 0 }] }],
};
const stats = {};
const r = simulateCombat(data, () => 0.999999, stats);
assert.equal(r.win, true);
assert.ok(stats.Hit.damage > stats.Hit.plays);
});
test("simulateCombat: healPerTurn power restores hp at turn start", () => {
const data = {
cards: {
Recovery: { name: "셀프 리커버리", cost: 0, kind: "Power", powerEffect: "healPerTurn", value: 3 },
Hit: { name: "마무리", cost: 1, kind: "Attack", damage: 1 },
},
starterDeck: ["Recovery", "Hit"],
monsters: [{ name: "Dummy", maxHp: 2, intents: [{ kind: "Attack", value: 2 }] }],
playerHp: 70,
playerMaxHp: 80,
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
assert.ok(r.playerHpRemaining >= 69);
});
test("simulateCombat: Holy Charge scales repeated Holy Force attacks", () => {
const data = {
cards: {
ChargeStrike: { name: "차지 타격", cost: 1, kind: "Attack", damage: 2, holyChargeGain: 1, damagePerHolyCharge: 1 },
},
starterDeck: ["ChargeStrike"],
monsters: [{ name: "Dummy", maxHp: 14, intents: [{ kind: "Attack", value: 0 }] }],
};
const stats = {};
const r = simulateCombat(data, () => 0.999999, stats);
assert.equal(r.win, true);
assert.ok(stats.ChargeStrike.damage > stats.ChargeStrike.plays * 2);
});
test("simulateCombat: damageTakenReduction lowers incoming HP damage", () => {
const data = {
cards: {
Achilles: { name: "아킬레스", cost: 3, kind: "Power", damageTakenReduction: 0.25, innate: true },
Wait1: { name: "대기", cost: 99, kind: "Status", unplayable: true, innate: true },
Wait2: { name: "대기", cost: 99, kind: "Status", unplayable: true, innate: true },
Wait3: { name: "대기", cost: 99, kind: "Status", unplayable: true, innate: true },
Wait4: { name: "대기", cost: 99, kind: "Status", unplayable: true, innate: true },
Finish: { name: "마무리", cost: 3, kind: "Power", cardPlayedDamage: 2 },
},
starterDeck: ["Finish", "Achilles", "Wait1", "Wait2", "Wait3", "Wait4"],
monsters: [{ name: "Dummy", maxHp: 2, intents: [{ kind: "Attack", value: 10 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
assert.equal(r.playerHpRemaining, 73);
});
test("simulateCombat: blockOnDamaged protects against later attackers", () => {
const data = {
cards: {
Armor: { name: "블레싱 아머", cost: 3, kind: "Power", blockOnDamaged: 6, strengthOnDamagedOnce: 2, innate: true },
Wait1: { name: "대기", cost: 99, kind: "Status", unplayable: true, innate: true },
Wait2: { name: "대기", cost: 99, kind: "Status", unplayable: true, innate: true },
Wait3: { name: "대기", cost: 99, kind: "Status", unplayable: true, innate: true },
Wait4: { name: "대기", cost: 99, kind: "Status", unplayable: true, innate: true },
Finish1: { name: "마무리", cost: 3, kind: "Power", cardPlayedDamage: 1 },
Finish2: { name: "마무리", cost: 3, kind: "Power", cardPlayedDamage: 1 },
},
starterDeck: ["Finish1", "Finish2", "Armor", "Wait1", "Wait2", "Wait3", "Wait4"],
monsters: [
{ name: "A", maxHp: 1, intents: [{ kind: "Attack", value: 5 }] },
{ name: "B", maxHp: 1, intents: [{ kind: "Attack", value: 5 }] },
],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
assert.equal(r.playerHpRemaining, 70);
});

View File

@@ -38,7 +38,7 @@ if c == nil then
return return
end end
if c.unplayable == true then if c.unplayable == true then
self:Toast("사용할 수 없는 카드입니다") self:Toast("사용할 수 없는 카드입니다")
return return
end end
if self:CanPlayCardNow(c) ~= true then if self:CanPlayCardNow(c) ~= true then
@@ -49,6 +49,8 @@ local skillFree = false
local skillRepeat = 0 local skillRepeat = 0
if self.HandCostZeroThisTurn == true then if self.HandCostZeroThisTurn == true then
cost = 0 cost = 0
elseif self.ZeroCostCardIdsThisTurn ~= nil and self.ZeroCostCardIdsThisTurn[cardId] == true then
cost = 0
elseif c.useAllEnergy == true then elseif c.useAllEnergy == true then
cost = self.Energy cost = self.Energy
end end
@@ -71,6 +73,8 @@ if self.Energy < cost then
end end
self.Energy = self.Energy - cost self.Energy = self.Energy - cost
self.ActiveKillReward = c.rewardOnKill or 0 self.ActiveKillReward = c.rewardOnKill or 0
self.ActiveKillMaxHpGain = c.maxHpOnKill or 0
table.remove(self.Hand, slot)
self:ResolveCardEffects(cardId, slot, c, false, cost) self:ResolveCardEffects(cardId, slot, c, false, cost)
local function applyCardPlayHooks() local function applyCardPlayHooks()
if self:HasPowerField("cardPlayedBlock") == true then if self:HasPowerField("cardPlayedBlock") == true then
@@ -82,6 +86,8 @@ local function applyCardPlayHooks()
if c.cardPlayedRandomDamage ~= nil and c.cardPlayedRandomDamage > 0 then if c.cardPlayedRandomDamage ~= nil and c.cardPlayedRandomDamage > 0 then
self:DealDirectDamageToRandomMonster(c.cardPlayedRandomDamage) self:DealDirectDamageToRandomMonster(c.cardPlayedRandomDamage)
end end
self:ApplyAttackCardPlayHooks(c)
self:ApplyHolyForceCardPlayHooks(c)
end end
applyCardPlayHooks() applyCardPlayHooks()
if skillRepeat > 0 then if skillRepeat > 0 then
@@ -106,16 +112,19 @@ end
if self.ActiveKillReward ~= nil and self.ActiveKillReward <= 0 then if self.ActiveKillReward ~= nil and self.ActiveKillReward <= 0 then
self.ActiveKillReward = 0 self.ActiveKillReward = 0
end end
if self.ActiveKillMaxHpGain ~= nil and self.ActiveKillMaxHpGain <= 0 then
self.ActiveKillMaxHpGain = 0
end
if c.combatCostReductionOnPlay ~= nil and c.combatCostReductionOnPlay > 0 then if c.combatCostReductionOnPlay ~= nil and c.combatCostReductionOnPlay > 0 then
if self.CombatCardCostReduction == nil then if self.CombatCardCostReduction == nil then
self.CombatCardCostReduction = {} self.CombatCardCostReduction = {}
end end
self.CombatCardCostReduction[cardId] = (self.CombatCardCostReduction[cardId] or 0) + c.combatCostReductionOnPlay self.CombatCardCostReduction[cardId] = (self.CombatCardCostReduction[cardId] or 0) + c.combatCostReductionOnPlay
end end
table.remove(self.Hand, slot)
if c.exhaust == true then if c.exhaust == true then
if self.ExhaustPile == nil then self.ExhaustPile = {} end if self.ExhaustPile == nil then self.ExhaustPile = {} end
table.insert(self.ExhaustPile, cardId) table.insert(self.ExhaustPile, cardId)
self:TriggerExhaustEffects(1)
elseif c.kind ~= "Power" then elseif c.kind ~= "Power" then
table.insert(self.DiscardPile, cardId) table.insert(self.DiscardPile, cardId)
end end
@@ -295,11 +304,19 @@ if dmg > 0 then
self:ApplyPoisonToMonster(m, poison) self:ApplyPoisonToMonster(m, poison)
end end
end end
self:ShowDmgPop(m.slot, dmg)
self:MonsterHitMotion(m.slot) self:MonsterHitMotion(m.slot)
local killed = false local killed = false
if m.hp <= 0 then if m.hp <= 0 then
m.hp = 0 m.hp = 0
self:KillMonster(m.slot) self:KillMonster(m.slot)
if self.ActiveKillReward ~= nil and self.ActiveKillReward > 0 then
self.BonusRewardScreens = (self.BonusRewardScreens or 0) + self.ActiveKillReward
end
if self.ActiveKillMaxHpGain ~= nil and self.ActiveKillMaxHpGain > 0 then
self.PlayerMaxHp = self.PlayerMaxHp + self.ActiveKillMaxHpGain
self.PlayerHp = self.PlayerHp + self.ActiveKillMaxHpGain
end
killed = true killed = true
end end
return killed`, [ return killed`, [
@@ -367,7 +384,7 @@ local burstEvery = self:AddPowerFieldTotal("poisonApplicationBurstEvery")
local burstDamage = self:AddPowerFieldTotal("poisonApplicationBurstDamage") local burstDamage = self:AddPowerFieldTotal("poisonApplicationBurstDamage")
if burstEvery ~= nil and burstEvery > 0 and burstDamage ~= nil and burstDamage > 0 then if burstEvery ~= nil and burstEvery > 0 and burstDamage ~= nil and burstDamage > 0 then
if (self.PoisonApplicationsThisCombat % burstEvery) == 0 then if (self.PoisonApplicationsThisCombat % burstEvery) == 0 then
self:DealDamageToAllMonsters(burstDamage) self:DealDamageToAllMonsters(burstDamage, false)
end end
end`, [ end`, [
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'target' }, { Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'target' },
@@ -411,6 +428,11 @@ end
if killCount > 0 and self.ActiveKillReward ~= nil and self.ActiveKillReward > 0 then if killCount > 0 and self.ActiveKillReward ~= nil and self.ActiveKillReward > 0 then
self.BonusRewardScreens = (self.BonusRewardScreens or 0) + (killCount * self.ActiveKillReward) self.BonusRewardScreens = (self.BonusRewardScreens or 0) + (killCount * self.ActiveKillReward)
end end
if killCount > 0 and self.ActiveKillMaxHpGain ~= nil and self.ActiveKillMaxHpGain > 0 then
local gain = killCount * self.ActiveKillMaxHpGain
self.PlayerMaxHp = self.PlayerMaxHp + gain
self.PlayerHp = self.PlayerHp + gain
end
self:RenderCombat() self:RenderCombat()
self:CheckCombatEnd() self:CheckCombatEnd()
return killCount > 0`, [ return killCount > 0`, [
@@ -419,6 +441,13 @@ return killCount > 0`, [
], 0, 'boolean'), ], 0, 'boolean'),
method('PlayAttackFx', `local m = self.Monsters[targetIndex] method('PlayAttackFx', `local m = self.Monsters[targetIndex]
if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then
local shown = damage
if m ~= nil and m.alive == true and m.vuln > 0 then
shown = math.floor(damage * 1.5)
end
if m ~= nil and m.alive == true and m.weak > 0 and self.ActiveAttackDamageVsWeakMultiplier ~= nil and self.ActiveAttackDamageVsWeakMultiplier > 1 then
shown = math.floor(shown * self.ActiveAttackDamageVsWeakMultiplier)
end
self:DealDamageToTarget(damage, pierce) self:DealDamageToTarget(damage, pierce)
self.ActiveAttackDamageVsWeakMultiplier = 1 self.ActiveAttackDamageVsWeakMultiplier = 1
self:RenderCombat() self:RenderCombat()
@@ -450,12 +479,9 @@ _TimerService:SetTimerOnce(function()
shown = math.floor(shown * self.ActiveAttackDamageVsWeakMultiplier) shown = math.floor(shown * self.ActiveAttackDamageVsWeakMultiplier)
end end
local killed = self:DealDamageToTarget(damage, pierce) local killed = self:DealDamageToTarget(damage, pierce)
if killed == true and self.ActiveKillReward ~= nil and self.ActiveKillReward > 0 then
self.BonusRewardScreens = (self.BonusRewardScreens or 0) + self.ActiveKillReward
end
self.ActiveKillReward = 0 self.ActiveKillReward = 0
self.ActiveKillMaxHpGain = 0
self.ActiveAttackDamageVsWeakMultiplier = 1 self.ActiveAttackDamageVsWeakMultiplier = 1
self:ShowDmgPop(targetIndex, shown)
self:RenderCombat() self:RenderCombat()
self:CheckCombatEnd() self:CheckCombatEnd()
end, 0.35)`, [ end, 0.35)`, [
@@ -510,10 +536,8 @@ _TimerService:SetTimerOnce(function()
end end
end end
end end
if killCount > 0 and self.ActiveKillReward ~= nil and self.ActiveKillReward > 0 then
self.BonusRewardScreens = (self.BonusRewardScreens or 0) + (killCount * self.ActiveKillReward)
end
self.ActiveKillReward = 0 self.ActiveKillReward = 0
self.ActiveKillMaxHpGain = 0
self.ActiveAttackDamageVsWeakMultiplier = 1 self.ActiveAttackDamageVsWeakMultiplier = 1
self:RenderCombat() self:RenderCombat()
self:CheckCombatEnd() self:CheckCombatEnd()
@@ -535,6 +559,11 @@ for i = 1, #self.Monsters do
if self.Monsters[i].alive == true then self.TargetIndex = i; break end if self.Monsters[i].alive == true then self.TargetIndex = i; break end
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]), end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]),
method('DealDamageToPlayer', `local dmg = amount method('DealDamageToPlayer', `local dmg = amount
local reduction = self:AddPowerFieldTotal("damageTakenReduction")
if reduction ~= nil and reduction > 0 then
reduction = math.min(0.75, reduction)
dmg = math.floor(dmg * (1 - reduction))
end
if self.PlayerBlock > 0 then if self.PlayerBlock > 0 then
local absorbed = math.min(self.PlayerBlock, dmg) local absorbed = math.min(self.PlayerBlock, dmg)
self.PlayerBlock = self.PlayerBlock - absorbed self.PlayerBlock = self.PlayerBlock - absorbed
@@ -545,6 +574,17 @@ if dmg > 0 and self.PlayerIntangible ~= nil and self.PlayerIntangible > 0 and dm
end end
if dmg > 0 then if dmg > 0 then
self.PlayerHp = self.PlayerHp - dmg self.PlayerHp = self.PlayerHp - dmg
local reactiveBlock = self:AddPowerFieldTotal("blockOnDamaged")
if reactiveBlock ~= nil and reactiveBlock > 0 then
self:AddCardBlock(reactiveBlock)
end
if self.DamagePowerStrengthUsed ~= true then
local reactiveStrength = self:AddPowerFieldTotal("strengthOnDamagedOnce")
if reactiveStrength ~= nil and reactiveStrength > 0 then
self.PlayerStr = self.PlayerStr + reactiveStrength
self.DamagePowerStrengthUsed = true
end
end
local reflect = self.PlayerThorns or 0 local reflect = self.PlayerThorns or 0
if self:HasRelic("bronzeScales") then if self:HasRelic("bronzeScales") then
reflect = reflect + 3 reflect = reflect + 3
@@ -566,7 +606,7 @@ if dmg > 0 then
end end
if self:HasRelic("centennialPuzzle") and self.FirstHpLossDone == false then if self:HasRelic("centennialPuzzle") and self.FirstHpLossDone == false then
self.FirstHpLossDone = true self.FirstHpLossDone = true
self:DrawCards(3) self:DrawCards(3, true)
self:RenderHand(false) self:RenderHand(false)
end end
end end

View File

@@ -243,6 +243,7 @@ self.BlockGainMultiplier = 1
self:ApplyRelics("turnStart") self:ApplyRelics("turnStart")
if self.NextTurnKeepBlock == true then if self.NextTurnKeepBlock == true then
self.NextTurnKeepBlock = false self.NextTurnKeepBlock = false
elseif self:HasPowerEffect("keepBlock") == true then
else else
self.PlayerBlock = 0 self.PlayerBlock = 0
end end
@@ -258,6 +259,7 @@ self.ActiveAttackDamageVsWeakMultiplier = 1
self.DrawDamageThisTurn = 0 self.DrawDamageThisTurn = 0
self.DrawPoisonThisTurn = 0 self.DrawPoisonThisTurn = 0
self.ShivAoeThisCombat = false self.ShivAoeThisCombat = false
self.ZeroCostCardIdsThisTurn = {}
self.SkillSlyOnPlayCards = self.SkillSlyOnPlayCards or {} self.SkillSlyOnPlayCards = self.SkillSlyOnPlayCards or {}
self.TurnSkillSlyCards = {} self.TurnSkillSlyCards = {}
self.EnemyStrengthLossThisTurn = 0 self.EnemyStrengthLossThisTurn = 0
@@ -275,6 +277,7 @@ if self.PlayerPowers ~= nil then
self.Energy = self.Energy + pc.value self.Energy = self.Energy + pc.value
elseif pc.powerEffect == "blockPerTurn" then elseif pc.powerEffect == "blockPerTurn" then
self.PlayerBlock = self.PlayerBlock + pc.value self.PlayerBlock = self.PlayerBlock + pc.value
elseif pc.powerEffect == "keepBlock" then
elseif pc.powerEffect == "poisonPerTurn" then elseif pc.powerEffect == "poisonPerTurn" then
if self.Monsters ~= nil then if self.Monsters ~= nil then
for j = 1, #self.Monsters do for j = 1, #self.Monsters do
@@ -288,6 +291,8 @@ if self.PlayerPowers ~= nil then
if self.Monsters ~= nil then if self.Monsters ~= nil then
self:PlayAoeFx(pc.fx or pc.image, pc.value or 0) self:PlayAoeFx(pc.fx or pc.image, pc.value or 0)
end end
elseif pc.powerEffect == "healPerTurn" then
self.PlayerHp = math.min(self.PlayerMaxHp, self.PlayerHp + pc.value)
end end
if pc.turnStartShiv ~= nil then if pc.turnStartShiv ~= nil then
self:AddCardsToHand("Shiv", pc.turnStartShiv) self:AddCardsToHand("Shiv", pc.turnStartShiv)
@@ -316,7 +321,7 @@ if self.NextTurnAddCards ~= nil then
end end
local drawN = 5 + (self.NextTurnDraw or 0) + powerTurnDraw local drawN = 5 + (self.NextTurnDraw or 0) + powerTurnDraw
self.NextTurnDraw = 0 self.NextTurnDraw = 0
self:DrawCards(drawN) self:DrawCards(drawN, true)
self:RenderHand(true) self:RenderHand(true)
self:RenderCombat() self:RenderCombat()
if powerTurnDiscard > 0 then if powerTurnDiscard > 0 then
@@ -481,8 +486,11 @@ for i = 1, amount do
\t\tself:TriggerSly(cardId) \t\tself:TriggerSly(cardId)
\telse \telse
\t\ttable.insert(self.Hand, cardId) \t\ttable.insert(self.Hand, cardId)
\t\tdrewAny = true \t\tlocal autoPlayed = self:TriggerDrawnCardAutoPlay(cardId)
\t\ttable.insert(drawnSlots, #self.Hand) \t\tif autoPlayed ~= true then
\t\t\tdrewAny = true
\t\t\ttable.insert(drawnSlots, #self.Hand)
\t\tend
\tend \tend
end end
self:RenderPiles() self:RenderPiles()
@@ -495,8 +503,9 @@ if animate == true and #drawnSlots > 0 then
\t\tlocal slot = drawnSlots[i] \t\tlocal slot = drawnSlots[i]
\t\tself:AnimateCardFrom(slot, drawStart, Vector2(self:GetHandSlotX(slot), 0), 0.08 + i * 0.045) \t\tself:AnimateCardFrom(slot, drawStart, Vector2(self:GetHandSlotX(slot), 0), 0.08 + i * 0.045)
\tend \tend
end
return drawnCards return drawnCards
end`, [ `, [
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }, { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' },
{ Type: 'boolean', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'animate' }, { Type: 'boolean', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'animate' },
], 0, 'any'), ], 0, 'any'),

View File

@@ -326,7 +326,104 @@ for i = 1, #self.Hand do
end end
end end
return n`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }], 0, 'number'), return n`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }], 0, 'number'),
method('CountOwnedNameMatches', `if match == nil or match == "" then
return 0
end
local n = 0
local function countPile(pile)
if pile == nil then return end
for i = 1, #pile do
local c2 = self.Cards[pile[i]]
local name = ""
if c2 ~= nil and c2.name ~= nil then name = c2.name end
if string.find(name, match, 1, true) ~= nil then
n = n + 1
end
end
end
countPile(self.Hand)
countPile(self.DrawPile)
countPile(self.DiscardPile)
countPile(self.ExhaustPile)
return n`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'match' }], 0, 'number'),
method('MaxPowerField', `local best = 0
if self.PlayerPowers == nil then
return best
end
for i = 1, #self.PlayerPowers do
local powerCard = self.Cards[self.PlayerPowers[i]]
if powerCard ~= nil and powerCard[field] ~= nil and powerCard[field] > best then
best = powerCard[field]
end
end
return best`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'field' }], 0, 'number'),
method('GetComboMax', `local comboMax = 5
local powerMax = self:MaxPowerField("comboMax")
if powerMax ~= nil and powerMax > comboMax then
comboMax = powerMax
end
return comboMax`, [], 0, 'number'),
method('GainCombo', `if amount == nil or amount <= 0 then
return
end
self.ComboCount = math.min(self:GetComboMax(), (self.ComboCount or 0) + amount)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }]),
method('GetHolyChargeMax', `local chargeMax = 3
local powerMax = self:MaxPowerField("holyChargeMax")
if powerMax ~= nil and powerMax > chargeMax then
chargeMax = powerMax
end
return chargeMax`, [], 0, 'number'),
method('GainHolyCharge', `if amount == nil or amount <= 0 then
return
end
self.HolyChargeCount = math.min(self:GetHolyChargeMax(), (self.HolyChargeCount or 0) + amount)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }]),
method('ApplyHolyForceCardPlayHooks', `if c == nil then
return
end
local gain = c.holyChargeGain or 0
if c.holyForce == true then
gain = gain + self:AddPowerFieldTotal("holyChargeOnHolyForce")
end
self:GainHolyCharge(gain)
if c.holyChargeSpendAll == true then
self.HolyChargeCount = 0
end`, [{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'c' }]),
method('ApplyAttackCardPlayHooks', `if c == nil or c.kind ~= "Attack" then
return
end
local comboGain = c.comboGain or 0
comboGain = comboGain + self:AddPowerFieldTotal("comboOnAttack")
self:GainCombo(comboGain)
local extraDamage = self:AddPowerFieldTotal("attackPlayedDamage")
if extraDamage ~= nil and extraDamage > 0 then
self:DealDirectDamageToTarget(extraDamage)
end
local weakAmount = self:AddPowerFieldTotal("attackWeak")
if weakAmount ~= nil and weakAmount > 0 and self.Monsters ~= nil then
local target = self.Monsters[self.TargetIndex]
if target ~= nil and target.alive == true then
if target.artifact ~= nil and target.artifact > 0 then
target.artifact = target.artifact - 1
else
target.weak = (target.weak or 0) + weakAmount
end
end
end`, [{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'c' }]),
method('AttackBaseForCard', `local base2 = c.damage or 0 method('AttackBaseForCard', `local base2 = c.damage or 0
if c.damageNameMatch ~= nil and c.damagePerOwnedNameMatch ~= nil then
base2 = base2 + self:CountOwnedNameMatches(c.damageNameMatch) * c.damagePerOwnedNameMatch
end
if c.damageFromCurrentBlock ~= nil and c.damageFromCurrentBlock ~= 0 then
base2 = base2 + (self.PlayerBlock or 0) * c.damageFromCurrentBlock
end
local comboScale = c.damagePerCombo or 0
comboScale = comboScale + self:AddPowerFieldTotal("attackDamagePerCombo")
if comboScale ~= 0 then
base2 = base2 + (self.ComboCount or 0) * comboScale
end
if c.damagePerHolyCharge ~= nil and c.damagePerHolyCharge ~= 0 then
base2 = base2 + (self.HolyChargeCount or 0) * c.damagePerHolyCharge
end
local otherHand = 0 local otherHand = 0
if self.Hand ~= nil then if self.Hand ~= nil then
otherHand = #self.Hand - 1 otherHand = #self.Hand - 1
@@ -365,6 +462,200 @@ return base2`, [
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }, { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' },
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'c' }, { Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'c' },
], 0, 'number'), ], 0, 'number'),
method('TriggerExhaustEffects', `if count == nil or count <= 0 then
return
end
local drawOnExhaust = self:AddPowerFieldTotal("drawOnExhaust")
if drawOnExhaust ~= nil and drawOnExhaust > 0 then
self:DrawCards(drawOnExhaust * count, true)
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'count' }]),
method('MarkCardCostZeroThisTurn', `if cardId == nil or cardId == "" then
return
end
if self.ZeroCostCardIdsThisTurn == nil then
self.ZeroCostCardIdsThisTurn = {}
end
self.ZeroCostCardIdsThisTurn[cardId] = true`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'cardId' }]),
method('AutoPlayCardId', `local c = self.Cards[cardId]
if c == nil then
return false
end
local spent = energySpent or 0
local skillFree = false
local skillRepeat = 0
if c.kind == "Skill" and c.useAllEnergy ~= true and self.NextSkillCostZero == true then
skillFree = true
end
if c.kind == "Skill" and self.NextSkillRepeatCount ~= nil and self.NextSkillRepeatCount > 0 then
skillRepeat = self.NextSkillRepeatCount
end
self.ActiveKillReward = c.rewardOnKill or 0
self.ActiveKillMaxHpGain = c.maxHpOnKill or 0
self:ResolveCardEffects(cardId, 0, c, false, spent)
local function applyCardPlayHooks()
if self:HasPowerField("cardPlayedBlock") == true then
self:AddCardBlock(self:AddPowerFieldTotal("cardPlayedBlock"))
end
if c.cardPlayedDamage ~= nil and c.cardPlayedDamage > 0 then
self:DealDirectDamageToTarget(c.cardPlayedDamage)
end
if c.cardPlayedRandomDamage ~= nil and c.cardPlayedRandomDamage > 0 then
self:DealDirectDamageToRandomMonster(c.cardPlayedRandomDamage)
end
self:ApplyAttackCardPlayHooks(c)
self:ApplyHolyForceCardPlayHooks(c)
end
applyCardPlayHooks()
if skillRepeat > 0 then
local remaining = (self.NextSkillRepeatCount or 0) - skillRepeat
if remaining < 0 then remaining = 0 end
self.NextSkillRepeatCount = remaining
for i = 1, skillRepeat do
self:ResolveCardEffects(cardId, 0, c, false, spent)
applyCardPlayHooks()
end
end
if c.kind == "Attack" then
self.TurnAttackCardsPlayed = (self.TurnAttackCardsPlayed or 0) + 1
end
if skillFree == true and c.nextSkillCostZero ~= true then
self.NextSkillCostZero = false
end
if c.exhaust == true then
if self.ExhaustPile == nil then self.ExhaustPile = {} end
table.insert(self.ExhaustPile, cardId)
self:TriggerExhaustEffects(1)
elseif c.kind ~= "Power" then
table.insert(self.DiscardPile, cardId)
end
if self.ActiveKillReward ~= nil and self.ActiveKillReward <= 0 then
self.ActiveKillReward = 0
end
if self.ActiveKillMaxHpGain ~= nil and self.ActiveKillMaxHpGain <= 0 then
self.ActiveKillMaxHpGain = 0
end
return true`, [
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'cardId' },
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'energySpent' },
], 0, 'boolean'),
method('TriggerDrawnCardAutoPlay', `if cardId == nil or cardId == "" or self.Hand == nil or self.PlayerPowers == nil then
return false
end
local c = self.Cards[cardId]
if c == nil or c.name == nil or c.name == "" then
return false
end
for i = 1, #self.PlayerPowers do
local powerCard = self.Cards[self.PlayerPowers[i]]
if powerCard ~= nil and powerCard.drawNameMatchAutoPlay ~= nil and powerCard.drawNameMatchAutoPlay ~= "" then
if string.find(c.name, powerCard.drawNameMatchAutoPlay, 1, true) ~= nil then
local foundSlot = 0
for hi = 1, #self.Hand do
if self.Hand[hi] == cardId then
foundSlot = hi
break
end
end
if foundSlot <= 0 then
return false
end
table.remove(self.Hand, foundSlot)
self:AutoPlayCardId(cardId, 0)
return true
end
end
end
return false`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'cardId' }], 0, 'boolean'),
method('PlayTopDrawPileCards', `if c == nil or self.DrawPile == nil then
return 0
end
local count = c.playTopDrawPileCount or 0
if c.playTopDrawPileCountPerEnergy ~= nil and c.playTopDrawPileCountPerEnergy > 0 then
count = count + ((energySpent or 0) * c.playTopDrawPileCountPerEnergy)
end
if count <= 0 then
return 0
end
local played = 0
for i = 1, count do
if #self.DrawPile <= 0 then
break
end
local topCardId = table.remove(self.DrawPile)
if topCardId ~= nil then
self:AutoPlayCardId(topCardId, 0)
played = played + 1
end
end
return played`, [
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'c' },
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'energySpent' },
], 0, 'number'),
method('AddRandomCardsFromEffect', `if c == nil or count == nil or count <= 0 then
return 0
end
local pool = {}
for id, rc in pairs(self.Cards) do
if rc ~= nil and rc.token ~= true and rc.curse ~= true and rc.unplayable ~= true then
local ok = true
if c.addRandomCardKind ~= nil and rc.kind ~= c.addRandomCardKind then ok = false end
if c.addRandomCardSameClass == true and rc.class ~= c.class then ok = false end
if ok == true then table.insert(pool, id) end
end
end
if #pool <= 0 then
return 0
end
local added = 0
for i = 1, count do
local cardId2 = pool[math.random(1, #pool)]
if cardId2 ~= nil then
self:AddCardsToHand(cardId2, 1)
if c.addedCardsCostZeroThisTurn == true then
self:MarkCardCostZeroThisTurn(cardId2)
end
added = added + 1
end
end
return added`, [
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'c' },
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'count' },
], 0, 'number'),
method('ExhaustHandNonAttack', `if c == nil or c.exhaustHandNonAttack ~= true or self.Hand == nil or #self.Hand <= 0 then
return 0
end
local exhausted = 0
for i = #self.Hand, 1, -1 do
local cardId2 = self.Hand[i]
local hc = self.Cards[cardId2]
if hc == nil or hc.kind ~= "Attack" then
table.remove(self.Hand, i)
if self.ExhaustPile == nil then self.ExhaustPile = {} end
table.insert(self.ExhaustPile, cardId2)
exhausted = exhausted + 1
end
end
if exhausted > 0 then
if c.blockPerExhaustedCard ~= nil and c.blockPerExhaustedCard > 0 then
self:AddCardBlock(exhausted * c.blockPerExhaustedCard)
end
self:TriggerExhaustEffects(exhausted)
end
return exhausted`, [{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'c' }], 0, 'number'),
method('ExhaustHandAll', `if c == nil or c.exhaustHandAll ~= true or self.Hand == nil or #self.Hand <= 0 then
return 0
end
local exhausted = 0
while #self.Hand > 0 do
local cardId2 = table.remove(self.Hand)
if self.ExhaustPile == nil then self.ExhaustPile = {} end
table.insert(self.ExhaustPile, cardId2)
exhausted = exhausted + 1
end
if exhausted > 0 then
self:TriggerExhaustEffects(exhausted)
end
return exhausted`, [{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'c' }], 0, 'number'),
method('CalcPlayerAttack', `local base2 = base method('CalcPlayerAttack', `local base2 = base
self.FightAttackCount = self.FightAttackCount + 1 self.FightAttackCount = self.FightAttackCount + 1
if self.FightAttackCount == 1 and self:HasRelic("akabeko") then if self.FightAttackCount == 1 and self:HasRelic("akabeko") then
@@ -485,14 +776,15 @@ if c.xWeakPerEnergy ~= nil and c.xWeakPerEnergy > 0 then
weakAmount = weakAmount + xEnergy * c.xWeakPerEnergy weakAmount = weakAmount + xEnergy * c.xWeakPerEnergy
end end
if c.kind == "Attack" then if c.kind == "Attack" then
if c.damage ~= nil or c.xDamagePerEnergy ~= nil then if c.damage ~= nil or c.xDamagePerEnergy ~= nil or c.damageFromCurrentBlock ~= nil then
self:PlayerAttackMotion() self:PlayerAttackMotion()
local baseDmg = self:AttackBaseForCard(slot, c) local baseDmg = self:AttackBaseForCard(slot, c)
self.ActiveAttackDamageVsWeakMultiplier = c.attackDamageVsWeakMultiplier or 1 self.ActiveAttackDamageVsWeakMultiplier = math.max(c.attackDamageVsWeakMultiplier or 1, self:MaxPowerField("attackDamageVsWeakMultiplier"))
if c.xDamagePerEnergy ~= nil and c.xDamagePerEnergy > 0 then if c.xDamagePerEnergy ~= nil and c.xDamagePerEnergy > 0 then
baseDmg = xEnergy * c.xDamagePerEnergy baseDmg = xEnergy * c.xDamagePerEnergy
end end
local total = 0 local total = 0
local hitDamages = {}
local hitN = c.hits or 1 local hitN = c.hits or 1
if c.otherHandAtLeast ~= nil and c.bonusHitsWhenOtherHandAtLeast ~= nil then if c.otherHandAtLeast ~= nil and c.bonusHitsWhenOtherHandAtLeast ~= nil then
local otherHand = 0 local otherHand = 0
@@ -505,7 +797,9 @@ if c.kind == "Attack" then
end end
end end
for h = 1, hitN do for h = 1, hitN do
total = total + self:CalcPlayerAttack(baseDmg) local hitDamage = self:CalcPlayerAttack(baseDmg)
hitDamages[h] = hitDamage
total = total + hitDamage
end end
local useAoe = c.aoe == true local useAoe = c.aoe == true
if c.class == "shiv" and (self.ShivAoeThisCombat == true or self:HasPowerField("shivAoe") == true) then if c.class == "shiv" and (self.ShivAoeThisCombat == true or self:HasPowerField("shivAoe") == true) then
@@ -550,11 +844,16 @@ if c.kind == "Attack" then
if targetIdx ~= nil and targetIdx > 0 then if targetIdx ~= nil and targetIdx > 0 then
local prev = self.TargetIndex local prev = self.TargetIndex
self.TargetIndex = targetIdx self.TargetIndex = targetIdx
local killed = self:DealDamageToTarget(total / hitN, c.pierce == true) local killed = self:DealDamageToTarget(hitDamages[h] or 0, c.pierce == true)
self.TargetIndex = prev self.TargetIndex = prev
if killed == true then roundKilled = true end if killed == true then roundKilled = true end
end end
end end
elseif hitN > 1 then
for h = 1, hitN do
local killed = self:DealDamageToTarget(hitDamages[h] or 0, c.pierce == true)
if killed == true then roundKilled = true end
end
else else
local killed = self:DealDamageToTarget(total, c.pierce == true) local killed = self:DealDamageToTarget(total, c.pierce == true)
if killed == true then roundKilled = true end if killed == true then roundKilled = true end
@@ -570,14 +869,14 @@ if c.kind == "Attack" then
self.DamageDealtThisTurn = (self.DamageDealtThisTurn or 0) + totalDamage self.DamageDealtThisTurn = (self.DamageDealtThisTurn or 0) + totalDamage
end end
if c.block ~= nil then if c.block ~= nil then
self:AddCardBlock(c.block) self:AddCardBlock(c.block + (self.HolyChargeCount or 0) * (c.blockPerHolyCharge or 0))
end end
if free ~= true then if free ~= true then
self:ApplyRelics("cardPlayed") self:ApplyRelics("cardPlayed")
end end
elseif c.kind == "Skill" then elseif c.kind == "Skill" then
if c.block ~= nil then if c.block ~= nil then
self:AddCardBlock(c.block) self:AddCardBlock(c.block + (self.HolyChargeCount or 0) * (c.blockPerHolyCharge or 0))
end end
elseif c.kind == "Power" then elseif c.kind == "Power" then
if free ~= true then if free ~= true then
@@ -597,11 +896,19 @@ if c.selfVuln ~= nil then
self.PlayerVuln = self.PlayerVuln + c.selfVuln self.PlayerVuln = self.PlayerVuln + c.selfVuln
end end
if c.heal ~= nil then if c.heal ~= nil then
self.PlayerHp = math.min(self.PlayerHp + c.heal, self.PlayerMaxHp) local healAmount = c.heal + (self.HolyChargeCount or 0) * (c.healPerHolyCharge or 0)
self.PlayerHp = math.min(self.PlayerHp + healAmount, self.PlayerMaxHp)
end end
if c.gainEnergy ~= nil and c.gainEnergy ~= 0 then if c.gainEnergy ~= nil and c.gainEnergy ~= 0 then
self.Energy = self.Energy + c.gainEnergy self.Energy = self.Energy + c.gainEnergy
end end
if c.kind ~= "Attack" and c.comboGain ~= nil and c.comboGain > 0 then
self:GainCombo(c.comboGain)
end
if c.removePlayerDebuffs == true then
self.PlayerWeak = 0
self.PlayerVuln = 0
end
if c.intangible ~= nil and c.intangible > 0 then if c.intangible ~= nil and c.intangible > 0 then
self.PlayerIntangible = (self.PlayerIntangible or 0) + c.intangible self.PlayerIntangible = (self.PlayerIntangible or 0) + c.intangible
end end
@@ -719,6 +1026,23 @@ if c.drawSkillBlock ~= nil and c.drawSkillBlock > 0 then
end end
if c.addShiv ~= nil and c.discard == nil and c.discardAll ~= true then if c.addShiv ~= nil and c.discard == nil and c.discardAll ~= true then
self:AddCardsToHand("Shiv", c.addShiv) self:AddCardsToHand("Shiv", c.addShiv)
end
local exhaustedNonAttack = self:ExhaustHandNonAttack(c)
local exhaustedAll = self:ExhaustHandAll(c)
local totalExhausted = exhaustedNonAttack + exhaustedAll
if c.drawPerExhausted ~= nil and c.drawPerExhausted > 0 and totalExhausted > 0 then
self:DrawCards(totalExhausted * c.drawPerExhausted, true)
end
if c.addRandomCardCount ~= nil and c.addRandomCardCount > 0 then
self:AddRandomCardsFromEffect(c, c.addRandomCardCount)
end
if c.addRandomCardPerExhausted ~= nil and c.addRandomCardPerExhausted > 0 then
if totalExhausted > 0 then
self:AddRandomCardsFromEffect(c, totalExhausted * c.addRandomCardPerExhausted)
end
end
if (c.playTopDrawPileCount ~= nil and c.playTopDrawPileCount > 0) or (c.playTopDrawPileCountPerEnergy ~= nil and c.playTopDrawPileCountPerEnergy > 0) then
self:PlayTopDrawPileCards(c, xEnergy)
end`, [ end`, [
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'cardId' }, { Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'cardId' },
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }, { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' },

View File

@@ -25,7 +25,7 @@ for i = 1, #self.RunRelics do
elseif r.effect == "strength" then elseif r.effect == "strength" then
self.PlayerStr = self.PlayerStr + r.value self.PlayerStr = self.PlayerStr + r.value
elseif r.effect == "draw" then elseif r.effect == "draw" then
self:DrawCards(r.value) self:DrawCards(r.value, true)
self:RenderHand(false) self:RenderHand(false)
elseif r.effect == "heal" or r.effect == "healOnAttack" or r.effect == "healOnWin" then elseif r.effect == "heal" or r.effect == "healOnAttack" or r.effect == "healOnWin" then
self.PlayerHp = self.PlayerHp + r.value self.PlayerHp = self.PlayerHp + r.value
@@ -151,7 +151,6 @@ if p.effect == "heal" then
self.PlayerHp = math.min(self.PlayerHp + p.value, self.PlayerMaxHp) self.PlayerHp = math.min(self.PlayerHp + p.value, self.PlayerMaxHp)
elseif p.effect == "damage" then elseif p.effect == "damage" then
self:DealDamageToTarget(p.value, false) self:DealDamageToTarget(p.value, false)
self:ShowDmgPop(self.TargetIndex, p.value)
elseif p.effect == "strength" then elseif p.effect == "strength" then
self.PlayerStr = self.PlayerStr + p.value self.PlayerStr = self.PlayerStr + p.value
elseif p.effect == "block" then elseif p.effect == "block" then

View File

@@ -1,296 +1,328 @@
import { method, RUN_LENGTH, GOLD_PER_WIN, CARD_PRICE, REST_HEAL, RELIC_PRICE, ACT_COUNT, ACT_MAPS, LOBBY_MAP, LOBBY_SPAWN } from '../lib/codeblock.mjs'; import { method, RUN_LENGTH, GOLD_PER_WIN, CARD_PRICE, REST_HEAL, RELIC_PRICE, ACT_COUNT, ACT_MAPS, LOBBY_MAP, LOBBY_SPAWN } from '../lib/codeblock.mjs';
import { CARDS, ENEMIES, CLASSES, JOBS, SOUL_UNLOCKS, CARDFRAMES, RARITIES, MAP_ROWS, MAP_COLS, CHEST_CLOSED_RUID, CHEST_OPEN_RUID, NODEICONS, CHARS, CAM, RELICS, POTIONS, luaSoulShopTable, frameRuid, luaFramesTable, luaNodeIconsTable, luaRelicsTable, luaPotionsTable, luaIntentsArray, luaEnemiesTable, luaStr, luaJobsTable, luaCardsTable, luaDeckTable } from '../lib/data.mjs'; import { CARDS, ENEMIES, CLASSES, JOBS, SOUL_UNLOCKS, CARDFRAMES, RARITIES, MAP_ROWS, MAP_COLS, CHEST_CLOSED_RUID, CHEST_OPEN_RUID, NODEICONS, CHARS, CAM, RELICS, POTIONS, luaSoulShopTable, frameRuid, luaFramesTable, luaNodeIconsTable, luaRelicsTable, luaPotionsTable, luaIntentsArray, luaEnemiesTable, luaStr, luaJobsTable, luaCardsTable, luaDeckTable } from '../lib/data.mjs';
import { UI_FILE, COMMON_FILE, UI_ROOT, GENERATED_UI_SECTIONS, UI_APPEND_ORDER, DISABLED_STOCK_CONTROLS, TRANSPARENT, DARK, GOLD, ATTACK, DEFEND, SKILL, DAMAGE_DIGIT_RUIDS, DAMAGE_POP_MAX_DIGITS, DAMAGE_POP_DIGIT_W, DAMAGE_POP_DIGIT_H, DAMAGE_POP_DIGIT_SPACING, MAX_MONSTERS, HEAD_OFFSET_Y, HP_BAR_W, WHITE, CARD_NAME_TEXT, CARD_DESC_TEXT, cardFaceLayout, CARD_W, CARD_H, CARD_SPACING, CARD_XS, ALIGN_CENTER, ALIGN_BOTTOM_CENTER, guid, transform, sprite, button, text, scrollLayoutGroup, popupLayerFor, uiOrderFor, displayOrderFor, applySortingOverride, entity, uiPath, sectionRoot, isGeneratedUiEntity, appendUiSection } from '../lib/ui-helpers.mjs'; import { UI_FILE, COMMON_FILE, UI_ROOT, GENERATED_UI_SECTIONS, UI_APPEND_ORDER, DISABLED_STOCK_CONTROLS, TRANSPARENT, DARK, GOLD, ATTACK, DEFEND, SKILL, DAMAGE_DIGIT_RUIDS, DAMAGE_POP_MAX_DIGITS, DAMAGE_POP_DIGIT_W, DAMAGE_POP_DIGIT_H, DAMAGE_POP_DIGIT_SPACING, MAX_MONSTERS, HEAD_OFFSET_Y, HP_BAR_W, WHITE, CARD_NAME_TEXT, CARD_DESC_TEXT, cardFaceLayout, CARD_W, CARD_H, CARD_SPACING, CARD_XS, ALIGN_CENTER, ALIGN_BOTTOM_CENTER, guid, transform, sprite, button, text, scrollLayoutGroup, popupLayerFor, uiOrderFor, displayOrderFor, applySortingOverride, entity, uiPath, sectionRoot, isGeneratedUiEntity, appendUiSection } from '../lib/ui-helpers.mjs';
export const renderMethods = [ export const renderMethods = [
method('BuffsLabel', `local parts = {} method('BuffsLabel', `local parts = {}
if str ~= nil and str > 0 then table.insert(parts, "힘+" .. tostring(str)) end 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 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 if vuln ~= nil and vuln > 0 then table.insert(parts, "취약" .. tostring(vuln)) end
if poison ~= nil and poison > 0 then table.insert(parts, "독" .. tostring(poison)) end if poison ~= nil and poison > 0 then table.insert(parts, "독" .. tostring(poison)) end
return table.concat(parts, " ")`, [ return table.concat(parts, " ")`, [
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'str' }, { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'str' },
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'weak' }, { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'weak' },
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'vuln' }, { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'vuln' },
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'poison' }, { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'poison' },
], 0, 'string'), ], 0, 'string'),
method('RenderCombat', `for i = 1, ${MAX_MONSTERS} do method('RenderCombat', `for i = 1, ${MAX_MONSTERS} do
local base = "/ui/RunUIGroup/CombatHud/MonsterStatus" .. tostring(i) local base = "/ui/RunUIGroup/CombatHud/MonsterStatus" .. tostring(i)
local m = self.Monsters[i] local m = self.Monsters[i]
if m ~= nil and m.alive == true then if m ~= nil and m.alive == true then
self:SetEntityEnabled(base, true) self:SetEntityEnabled(base, true)
self:SetText(base .. "/Name", m.name) self:SetText(base .. "/Name", m.name)
self:SetText(base .. "/Hp", string.format("%d", m.hp) .. "/" .. string.format("%d", m.maxHp)) self:SetText(base .. "/Hp", string.format("%d", m.hp) .. "/" .. string.format("%d", m.maxHp))
local intent = m.intents[m.intentIdx] local intent = m.intents[m.intentIdx]
local t = "" local t = ""
if intent ~= nil then if intent ~= nil then
if intent.kind == "Attack" then if intent.kind == "Attack" then
local atk = intent.value + m.str local atk = intent.value + m.str
if m.weak > 0 then atk = math.floor(atk * 0.75) end if m.weak > 0 then atk = math.floor(atk * 0.75) end
if self.PlayerVuln > 0 then atk = math.floor(atk * 1.5) end if self.PlayerVuln > 0 then atk = math.floor(atk * 1.5) end
t = "공격 " .. tostring(atk) t = "공격 " .. tostring(atk)
elseif intent.kind == "Defend" then t = "방어 " .. tostring(intent.value) elseif intent.kind == "Defend" then t = "방어 " .. tostring(intent.value)
elseif intent.kind == "Debuff" then elseif intent.kind == "Debuff" then
if intent.effect == "weak" then t = "약화 " .. tostring(intent.value) .. " 부여" if intent.effect == "weak" then t = "약화 " .. tostring(intent.value) .. " 부여"
else t = "취약 " .. tostring(intent.value) .. " 부여" end else t = "취약 " .. tostring(intent.value) .. " 부여" end
elseif intent.kind == "AddCard" then elseif intent.kind == "AddCard" then
t = "저주 카드 추가" t = "저주 카드 추가"
end end
end end
self:SetText(base .. "/Intent", t) self:SetText(base .. "/Intent", t)
local dragActive = self.DragTargetIndex ~= nil and self.DragTargetIndex > 0 local dragActive = self.DragTargetIndex ~= nil and self.DragTargetIndex > 0
local shownTarget = self.TargetIndex local shownTarget = self.TargetIndex
if dragActive == true then shownTarget = self.DragTargetIndex end if dragActive == true then shownTarget = self.DragTargetIndex end
self:SetEntityEnabled(base .. "/TargetMarker", i == shownTarget and dragActive) self:SetEntityEnabled(base .. "/TargetMarker", i == shownTarget and dragActive)
self:SetEntityEnabled(base .. "/TargetMarker/Label", i == shownTarget and dragActive) self:SetEntityEnabled(base .. "/TargetMarker/Label", i == shownTarget and dragActive)
local intentEntity = _EntityService:GetEntityByPath(base .. "/Intent") local intentEntity = _EntityService:GetEntityByPath(base .. "/Intent")
if intentEntity ~= nil and intentEntity.TextComponent ~= nil and intent ~= nil then if intentEntity ~= nil and intentEntity.TextComponent ~= nil and intent ~= nil then
if intent.kind == "Attack" then if intent.kind == "Attack" then
intentEntity.TextComponent.FontColor = Color(1, 0.45, 0.35, 1) intentEntity.TextComponent.FontColor = Color(1, 0.45, 0.35, 1)
elseif intent.kind == "Debuff" then elseif intent.kind == "Debuff" then
intentEntity.TextComponent.FontColor = Color(0.8, 0.5, 1, 1) intentEntity.TextComponent.FontColor = Color(0.8, 0.5, 1, 1)
elseif intent.kind == "AddCard" then elseif intent.kind == "AddCard" then
intentEntity.TextComponent.FontColor = Color(0.6, 0.85, 0.4, 1) intentEntity.TextComponent.FontColor = Color(0.6, 0.85, 0.4, 1)
else else
intentEntity.TextComponent.FontColor = Color(0.5, 0.75, 1, 1) intentEntity.TextComponent.FontColor = Color(0.5, 0.75, 1, 1)
end end
end end
self:SetHpBar(base .. "/HpBarFill", m.hp, m.maxHp, ${HP_BAR_W}) self:SetHpBar(base .. "/HpBarFill", m.hp, m.maxHp, ${HP_BAR_W})
self:SetEntityEnabled(base .. "/BlockBadge", m.block > 0) self:SetEntityEnabled(base .. "/BlockBadge", m.block > 0)
self:SetText(base .. "/BlockBadge/Value", string.format("%d", m.block)) self:SetText(base .. "/BlockBadge/Value", string.format("%d", m.block))
self:SetText(base .. "/Buffs", self:BuffsLabel(m.str, m.weak, m.vuln, m.poison or 0)) self:SetText(base .. "/Buffs", self:BuffsLabel(m.str, m.weak, m.vuln, m.poison or 0))
else else
self:SetEntityEnabled(base, false) self:SetEntityEnabled(base, false)
end end
end end
self:SetText("/ui/RunUIGroup/CombatHud/PlayerPanel/HpText", string.format("%d", self.PlayerHp) .. "/" .. string.format("%d", self.PlayerMaxHp)) self:SetText("/ui/RunUIGroup/CombatHud/PlayerPanel/HpText", string.format("%d", self.PlayerHp) .. "/" .. string.format("%d", self.PlayerMaxHp))
self:SetHpBar("/ui/RunUIGroup/CombatHud/PlayerPanel/HpBarFill", self.PlayerHp, self.PlayerMaxHp, 220) self:SetHpBar("/ui/RunUIGroup/CombatHud/PlayerPanel/HpBarFill", self.PlayerHp, self.PlayerMaxHp, 220)
self:SetEntityEnabled("/ui/RunUIGroup/CombatHud/PlayerPanel/BlockBadge", self.PlayerBlock > 0) self:SetEntityEnabled("/ui/RunUIGroup/CombatHud/PlayerPanel/BlockBadge", self.PlayerBlock > 0)
self:SetText("/ui/RunUIGroup/CombatHud/PlayerPanel/BlockBadge/Value", string.format("%d", self.PlayerBlock)) self:SetText("/ui/RunUIGroup/CombatHud/PlayerPanel/BlockBadge/Value", string.format("%d", self.PlayerBlock))
local pb = self:BuffsLabel(self.PlayerStr, self.PlayerWeak, self.PlayerVuln, 0) local pb = self:BuffsLabel(self.PlayerStr, self.PlayerWeak, self.PlayerVuln, 0)
if self.PlayerIntangible ~= nil and self.PlayerIntangible > 0 then if self.PlayerIntangible ~= nil and self.PlayerIntangible > 0 then
if pb ~= "" then pb = pb .. " " end if pb ~= "" then pb = pb .. " " end
pb = pb .. "불가침" .. tostring(self.PlayerIntangible) pb = pb .. "불가침" .. tostring(self.PlayerIntangible)
end end
if self.PlayerDex ~= nil and self.PlayerDex > 0 then if self.PlayerDex ~= nil and self.PlayerDex > 0 then
if pb ~= "" then pb = pb .. " " end if pb ~= "" then pb = pb .. " " end
pb = pb .. "민첩+" .. tostring(self.PlayerDex) pb = pb .. "민첩+" .. tostring(self.PlayerDex)
end end
if self.PlayerThorns ~= nil and self.PlayerThorns > 0 then if self.PlayerThorns ~= nil and self.PlayerThorns > 0 then
if pb ~= "" then pb = pb .. " " end if pb ~= "" then pb = pb .. " " end
pb = pb .. "가시" .. tostring(self.PlayerThorns) pb = pb .. "가시" .. tostring(self.PlayerThorns)
end end
if self.PlayerPowers ~= nil and #self.PlayerPowers > 0 then if self.ComboCount ~= nil and self.ComboCount > 0 then
local names = {} if pb ~= "" then pb = pb .. " " end
for i = 1, #self.PlayerPowers do pb = pb .. "콤보 " .. tostring(self.ComboCount) .. "/" .. tostring(self:GetComboMax())
local pc = self.Cards[self.PlayerPowers[i]] end
if pc ~= nil then table.insert(names, pc.name) end if self.HolyChargeCount ~= nil and self.HolyChargeCount > 0 then
end if pb ~= "" then pb = pb .. " " end
if pb ~= "" then pb = pb .. " · " end pb = pb .. "홀리 차지 " .. tostring(self.HolyChargeCount) .. "/" .. tostring(self:GetHolyChargeMax())
pb = pb .. table.concat(names, " ") end
end if self.PlayerPowers ~= nil and #self.PlayerPowers > 0 then
self:SetText("/ui/RunUIGroup/CombatHud/PlayerPanel/Buffs", pb) local names = {}
self:RenderRun()`), for i = 1, #self.PlayerPowers do
method('ShowDmgPop', `local slotKey = string.format("%d", math.floor(slot or 0)) local pc = self.Cards[self.PlayerPowers[i]]
local base = "/ui/RunUIGroup/CombatHud/DmgPop" .. slotKey if pc ~= nil then table.insert(names, pc.name) end
local pop = _EntityService:GetEntityByPath(base) end
if pop == nil then if pb ~= "" then pb = pb .. " · " end
return pb = pb .. table.concat(names, " ")
end end
self.DmgPopSeq = (self.DmgPopSeq or 0) + 1 self:SetText("/ui/RunUIGroup/CombatHud/PlayerPanel/Buffs", pb)
local popSeq = self.DmgPopSeq self:RenderRun()`),
self:SetText(base, "") method('ShowDmgPop', `local slotKey = string.format("%d", math.floor(slot or 0))
local damageDigitRuids = { ${DAMAGE_DIGIT_RUIDS.map(luaStr).join(', ')} } if self.DmgPopSlotQueue == nil then
local shown = tostring(math.max(0, math.floor(amount))) self.DmgPopSlotQueue = {}
if string.len(shown) > ${DAMAGE_POP_MAX_DIGITS} then end
shown = string.sub(shown, 1, ${DAMAGE_POP_MAX_DIGITS}) local popIndex = (self.DmgPopSlotQueue[slotKey] or 0) + 1
end if popIndex > 5 then
local digits = {} popIndex = 1
for i = 1, string.len(shown) do end
table.insert(digits, tonumber(string.sub(shown, i, i)) or 0) self.DmgPopSlotQueue[slotKey] = popIndex
end local base = "/ui/RunUIGroup/CombatHud/DmgPop" .. slotKey .. "_" .. tostring(popIndex)
local totalW = #digits * ${DAMAGE_POP_DIGIT_W} + math.max(0, #digits - 1) * ${DAMAGE_POP_DIGIT_SPACING} local pop = _EntityService:GetEntityByPath(base)
local startX = -totalW / 2 + ${DAMAGE_POP_DIGIT_W} / 2 if pop == nil then
for i = 1, ${DAMAGE_POP_MAX_DIGITS} do return
self:SetEntityEnabled(base .. "/Digit" .. tostring(i), false) end
end local startDelay = 0.2 * (popIndex - 1)
for i = 1, ${DAMAGE_POP_MAX_DIGITS} do local function showNow()
local digitPath = base .. "/Digit" .. tostring(i) self:SetEntityEnabled(base, false)
local digitEntity = _EntityService:GetEntityByPath(digitPath) self:SetText(base, "")
if digitEntity ~= nil and digitEntity.SpriteGUIRendererComponent ~= nil then local damageDigitRuids = { ${DAMAGE_DIGIT_RUIDS.map(luaStr).join(', ')} }
if digits[i] ~= nil then local shown = tostring(math.max(0, math.floor(amount)))
digitEntity.SpriteGUIRendererComponent.ImageRUID = damageDigitRuids[digits[i] + 1] if string.len(shown) > ${DAMAGE_POP_MAX_DIGITS} then
digitEntity.SpriteGUIRendererComponent.Color = Color(1, 1, 1, 1) shown = string.sub(shown, 1, ${DAMAGE_POP_MAX_DIGITS})
if digitEntity.UITransformComponent ~= nil then end
digitEntity.UITransformComponent.anchoredPosition = Vector2(startX + (i - 1) * (${DAMAGE_POP_DIGIT_W} + ${DAMAGE_POP_DIGIT_SPACING}), 0) local digits = {}
end local digitPathsToEnable = {}
self:SetEntityEnabled(digitPath, true) for i = 1, string.len(shown) do
else table.insert(digits, tonumber(string.sub(shown, i, i)) or 0)
self:SetEntityEnabled(digitPath, false) end
end local totalW = #digits * ${DAMAGE_POP_DIGIT_W} + math.max(0, #digits - 1) * ${DAMAGE_POP_DIGIT_SPACING}
end local startX = -totalW / 2 + ${DAMAGE_POP_DIGIT_W} / 2
end for i = 1, ${DAMAGE_POP_MAX_DIGITS} do
local popPos = nil self:SetEntityEnabled(base .. "/Digit" .. tostring(i), false)
local m = self.Monsters[slot] end
if m ~= nil and m.entity ~= nil and isvalid(m.entity) and m.entity.TransformComponent ~= nil then for i = 1, ${DAMAGE_POP_MAX_DIGITS} do
local wp = m.entity.TransformComponent.WorldPosition local digitPath = base .. "/Digit" .. tostring(i)
local screen = _UILogic:WorldToScreenPosition(Vector2(wp.x, wp.y + ${HEAD_OFFSET_Y + 0.45})) local digitEntity = _EntityService:GetEntityByPath(digitPath)
popPos = _UILogic:ScreenToUIPosition(screen) if digitEntity ~= nil and digitEntity.SpriteGUIRendererComponent ~= nil then
else if digits[i] ~= nil then
local slotEntity = _EntityService:GetEntityByPath("/ui/RunUIGroup/CombatHud/MonsterStatus" .. slotKey) digitEntity.SpriteGUIRendererComponent.ImageRUID = damageDigitRuids[digits[i] + 1]
if slotEntity ~= nil and slotEntity.UITransformComponent ~= nil then digitEntity.SpriteGUIRendererComponent.Color = Color(1, 1, 1, 1)
local sp = slotEntity.UITransformComponent.anchoredPosition if digitEntity.UITransformComponent ~= nil then
popPos = Vector2(sp.x, sp.y + 76) digitEntity.UITransformComponent.anchoredPosition = Vector2(startX + (i - 1) * (${DAMAGE_POP_DIGIT_W} + ${DAMAGE_POP_DIGIT_SPACING}), 0)
end end
end table.insert(digitPathsToEnable, digitPath)
if pop ~= nil and pop.UITransformComponent ~= nil then else
if popPos ~= nil then self:SetEntityEnabled(digitPath, false)
pop.UITransformComponent.anchoredPosition = popPos end
else end
pop.UITransformComponent.anchoredPosition = Vector2(0, 120) end
end local popPos = nil
end local m = self.Monsters[slot]
self:SetEntityEnabled(base, true) if m ~= nil and m.entity ~= nil and isvalid(m.entity) and m.entity.TransformComponent ~= nil then
for i = 1, 6 do local wp = m.entity.TransformComponent.WorldPosition
_TimerService:SetTimerOnce(function() local screen = _UILogic:WorldToScreenPosition(Vector2(wp.x, wp.y + ${HEAD_OFFSET_Y + 0.45}))
if self.DmgPopSeq ~= popSeq then popPos = _UILogic:ScreenToUIPosition(screen)
return else
end local slotEntity = _EntityService:GetEntityByPath("/ui/RunUIGroup/CombatHud/MonsterStatus" .. slotKey)
local p = _EntityService:GetEntityByPath(base) if slotEntity ~= nil and slotEntity.UITransformComponent ~= nil then
if p ~= nil and p.UITransformComponent ~= nil then local sp = slotEntity.UITransformComponent.anchoredPosition
local cur = p.UITransformComponent.anchoredPosition popPos = Vector2(sp.x, sp.y + 76)
p.UITransformComponent.anchoredPosition = Vector2(cur.x, cur.y + 7) end
end end
end, 0.045 * i) if pop.UITransformComponent ~= nil then
end if popPos ~= nil then
_TimerService:SetTimerOnce(function() pop.UITransformComponent.anchoredPosition = popPos
if self.DmgPopSeq ~= popSeq then else
return pop.UITransformComponent.anchoredPosition = Vector2(0, 120)
end end
self:SetEntityEnabled(base, false) end
end, 0.48)`, [ self:SetEntityEnabled(base, true)
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }, for i = 1, #digitPathsToEnable do
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }, self:SetEntityEnabled(digitPathsToEnable[i], true)
]), end
method('ShowPlayerDmgPop', `local base = "/ui/RunUIGroup/CombatHud/PlayerPanel/DmgPop" for i = 1, 6 do
if amount > 0 then _TimerService:SetTimerOnce(function()
self:SetText(base, "-" .. string.format("%d", amount)) local p = _EntityService:GetEntityByPath(base)
else if p ~= nil and p.UITransformComponent ~= nil then
self:SetText(base, "막음") local cur = p.UITransformComponent.anchoredPosition
end p.UITransformComponent.anchoredPosition = Vector2(cur.x, cur.y + 7)
self:SetEntityEnabled(base, true) end
_TimerService:SetTimerOnce(function() self:SetEntityEnabled(base, false) end, 0.6)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }]), local alpha = 1 - (i / 6)
method('PlayerAttackMotion', `local lp = _UserService.LocalPlayer if alpha < 0 then alpha = 0 end
if lp == nil then for di = 1, ${DAMAGE_POP_MAX_DIGITS} do
return local digitEntity = _EntityService:GetEntityByPath(base .. "/Digit" .. tostring(di))
end if digitEntity ~= nil and digitEntity.Enable == true and digitEntity.SpriteGUIRendererComponent ~= nil then
if lp.StateComponent == nil then digitEntity.SpriteGUIRendererComponent.Color = Color(1, 1, 1, alpha)
return end
end end
pcall(function() lp.StateComponent:ChangeState("ATTACK") end) end, 0.05 * i)
_TimerService:SetTimerOnce(function() end
if lp ~= nil and isvalid(lp) and lp.StateComponent ~= nil then _TimerService:SetTimerOnce(function()
pcall(function() lp.StateComponent:ChangeState("IDLE") end) self:SetEntityEnabled(base, false)
end end, 0.3)
end, 0.5)`), end
method('PlayerHitMotion', `local lp = _UserService.LocalPlayer if startDelay > 0 then
if lp == nil then _TimerService:SetTimerOnce(function()
return showNow()
end end, startDelay)
if lp.StateComponent ~= nil then else
pcall(function() lp.StateComponent:ChangeState("HIT") end) showNow()
end end`, [
local tr = lp.TransformComponent { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' },
if tr == nil then { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' },
return ]),
end method('ShowPlayerDmgPop', `local base = "/ui/RunUIGroup/CombatHud/PlayerPanel/DmgPop"
local p = tr.Position if amount > 0 then
tr.Position = Vector3(p.x - 0.15, p.y, p.z) self:SetText(base, "-" .. string.format("%d", amount))
_TimerService:SetTimerOnce(function() else
if lp ~= nil and isvalid(lp) and lp.TransformComponent ~= nil then self:SetText(base, "막음")
lp.TransformComponent.Position = Vector3(p.x, p.y, p.z) end
end self:SetEntityEnabled(base, true)
end, 0.15)`), _TimerService:SetTimerOnce(function() self:SetEntityEnabled(base, false) end, 0.6)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }]),
method('MonsterLunge', `local m = self.Monsters[idx] method('PlayerAttackMotion', `local lp = _UserService.LocalPlayer
if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then if lp == nil then
return return
end end
if m.motionBusy == true then if lp.StateComponent == nil then
return return
end end
m.motionBusy = true pcall(function() lp.StateComponent:ChangeState("ATTACK") end)
local e = m.entity _TimerService:SetTimerOnce(function()
local tr = e.TransformComponent if lp ~= nil and isvalid(lp) and lp.StateComponent ~= nil then
if tr == nil then pcall(function() lp.StateComponent:ChangeState("IDLE") end)
m.motionBusy = false end
return end, 0.5)`),
end method('PlayerHitMotion', `local lp = _UserService.LocalPlayer
local p = tr.Position if lp == nil then
tr.Position = Vector3(p.x - 0.35, p.y, p.z) return
_TimerService:SetTimerOnce(function() end
if isvalid(e) and e.TransformComponent ~= nil then if lp.StateComponent ~= nil then
e.TransformComponent.Position = Vector3(p.x, p.y, p.z) pcall(function() lp.StateComponent:ChangeState("HIT") end)
end end
m.motionBusy = false local tr = lp.TransformComponent
end, 0.18)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'idx' }]), if tr == nil then
method('MonsterHitMotion', `local m = self.Monsters[slot] return
if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then end
return local p = tr.Position
end tr.Position = Vector3(p.x - 0.15, p.y, p.z)
local e = m.entity _TimerService:SetTimerOnce(function()
if m.hitClip ~= nil and e.SpriteRendererComponent ~= nil then if lp ~= nil and isvalid(lp) and lp.TransformComponent ~= nil then
e.SpriteRendererComponent.SpriteRUID = m.hitClip lp.TransformComponent.Position = Vector3(p.x, p.y, p.z)
_TimerService:SetTimerOnce(function() end
if isvalid(e) and e.SpriteRendererComponent ~= nil and m.alive == true and m.standClip ~= nil then end, 0.15)`),
e.SpriteRendererComponent.SpriteRUID = m.standClip method('MonsterLunge', `local m = self.Monsters[idx]
end if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then
end, 0.5) return
else end
if m.motionBusy == true then if m.motionBusy == true then
return return
end end
m.motionBusy = true m.motionBusy = true
local tr = e.TransformComponent local e = m.entity
if tr == nil then local tr = e.TransformComponent
m.motionBusy = false if tr == nil then
return m.motionBusy = false
end return
local p = tr.Position end
local seq = { 0.12, -0.12, 0 } local p = tr.Position
for i = 1, #seq do tr.Position = Vector3(p.x - 0.35, p.y, p.z)
local dx = seq[i] _TimerService:SetTimerOnce(function()
_TimerService:SetTimerOnce(function() if isvalid(e) and e.TransformComponent ~= nil then
if isvalid(e) and e.TransformComponent ~= nil then e.TransformComponent.Position = Vector3(p.x, p.y, p.z)
e.TransformComponent.Position = Vector3(p.x + dx, p.y, p.z) end
end m.motionBusy = false
if i == #seq then end, 0.18)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'idx' }]),
m.motionBusy = false method('MonsterHitMotion', `local m = self.Monsters[slot]
end if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then
end, 0.06 * i) return
end end
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]), local e = m.entity
method('SetHpBar', `local e = _EntityService:GetEntityByPath(path) if m.hitClip ~= nil and e.SpriteRendererComponent ~= nil then
if e == nil or e.UITransformComponent == nil then e.SpriteRendererComponent.SpriteRUID = m.hitClip
return _TimerService:SetTimerOnce(function()
end if isvalid(e) and e.SpriteRendererComponent ~= nil and m.alive == true and m.standClip ~= nil then
local ratio = 0 e.SpriteRendererComponent.SpriteRUID = m.standClip
if maxHp > 0 then ratio = hp / maxHp end end
if ratio < 0 then ratio = 0 end end, 0.5)
local w = width * ratio else
e.UITransformComponent.RectSize = Vector2(w, 14)`, [ if m.motionBusy == true then
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'path' }, return
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'hp' }, end
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'maxHp' }, m.motionBusy = true
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'width' }, local tr = e.TransformComponent
]), if tr == nil then
method('SetTarget', `if self.Monsters[slot] ~= nil and self.Monsters[slot].alive == true then m.motionBusy = false
self.TargetIndex = slot return
self:RenderCombat() end
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]), local p = tr.Position
method('RenderRun', `local floorText = "막 " .. string.format("%d", self.Floor) .. "/" .. string.format("%d", self.RunLength) .. " · " .. string.format("%d", self.Depth) .. "층" local seq = { 0.12, -0.12, 0 }
if self.AscensionLevel > 0 then for i = 1, #seq do
floorText = floorText .. " · 승천" .. string.format("%d", self.AscensionLevel) local dx = seq[i]
end _TimerService:SetTimerOnce(function()
self:SetText("/ui/RunUIGroup/CombatHud/TopBar/Floor", floorText) if isvalid(e) and e.TransformComponent ~= nil then
self:SetText("/ui/RunUIGroup/CombatHud/TopBar/Gold", "메소 " .. string.format("%d", self.Gold))`), e.TransformComponent.Position = Vector3(p.x + dx, p.y, p.z)
end
if i == #seq then
m.motionBusy = false
end
end, 0.06 * i)
end
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]),
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' },
]),
method('SetTarget', `if self.Monsters[slot] ~= nil and self.Monsters[slot].alive == true then
self.TargetIndex = slot
self:RenderCombat()
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]),
method('RenderRun', `local floorText = "막 " .. string.format("%d", self.Floor) .. "/" .. string.format("%d", self.RunLength) .. " · " .. string.format("%d", self.Depth) .. "층"
if self.AscensionLevel > 0 then
floorText = floorText .. " · 승천" .. string.format("%d", self.AscensionLevel)
end
self:SetText("/ui/RunUIGroup/CombatHud/TopBar/Floor", floorText)
self:SetText("/ui/RunUIGroup/CombatHud/TopBar/Gold", "메소 " .. string.format("%d", self.Gold))`),
];

View File

@@ -95,13 +95,18 @@ self.PlayerVuln = 0
self.PlayerIntangible = 0 self.PlayerIntangible = 0
self.BonusRewardScreens = 0 self.BonusRewardScreens = 0
self.ActiveKillReward = 0 self.ActiveKillReward = 0
self.ActiveKillMaxHpGain = 0
self.PlayerPowers = {} self.PlayerPowers = {}
self.FightAttackCount = 0 self.FightAttackCount = 0
self.TurnAttackCardsPlayed = 0 self.TurnAttackCardsPlayed = 0
self.TurnDiscardedCards = 0 self.TurnDiscardedCards = 0
self.TurnCardsPlayedThisTurn = 0 self.TurnCardsPlayedThisTurn = 0
self.ComboCount = 0
self.HolyChargeCount = 0
self.DamagePowerStrengthUsed = false
self.DamageDealtThisTurn = 0 self.DamageDealtThisTurn = 0
self.DmgPopSeq = 0 self.DmgPopSeq = 0
self.DmgPopSlotQueue = {}
self.FirstHpLossDone = false self.FirstHpLossDone = false
self.ClayBlockNext = 0 self.ClayBlockNext = 0
self.DiscardSelectRemaining = 0 self.DiscardSelectRemaining = 0
@@ -118,6 +123,7 @@ self.TurnAttackMultiplier = 1
self.NextTurnSelectPrompt = "" self.NextTurnSelectPrompt = ""
self.NextTurnSelectCopies = 0 self.NextTurnSelectCopies = 0
self.NextTurnAddCards = {} self.NextTurnAddCards = {}
self.ZeroCostCardIdsThisTurn = {}
self.CombatOver = false self.CombatOver = false
self.DiscardPile = {} self.DiscardPile = {}
self.ExhaustPile = {} self.ExhaustPile = {}

View File

@@ -49,9 +49,9 @@ end`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], N
method('ShowMainMenu', `self.SelectedClass = "" method('ShowMainMenu', `self.SelectedClass = ""
self:RenderAscension() self:RenderAscension()
self:ShowState("menu") self:ShowState("menu")
self:SetText("/ui/DefaultGroup/MainMenu/Title", "메이플 덱 어드벤처") self:SetText("/ui/DefaultGroup/MainMenu/Title", "Maple Deck Adventure")
self:SetText("/ui/DefaultGroup/MainMenu/Subtitle", "캐릭터를 고르고 덱을 만들어 모험을 시작하세요") self:SetText("/ui/DefaultGroup/MainMenu/Subtitle", "Choose your character and begin your run")
self:SetText("/ui/DefaultGroup/MainMenu/NewGameButton", "새 게임") self:SetText("/ui/DefaultGroup/MainMenu/NewGameButton", "New Game")
self:BindMenuButtons()`), self:BindMenuButtons()`),
method('BindMenuButtons', `local buttonEntity = _EntityService:GetEntityByPath("/ui/DefaultGroup/MainMenu/NewGameButton") method('BindMenuButtons', `local buttonEntity = _EntityService:GetEntityByPath("/ui/DefaultGroup/MainMenu/NewGameButton")
if buttonEntity ~= nil and (buttonEntity.ButtonComponent ~= nil or buttonEntity:AddComponent("ButtonComponent") ~= nil) then if buttonEntity ~= nil and (buttonEntity.ButtonComponent ~= nil or buttonEntity:AddComponent("ButtonComponent") ~= nil) then
@@ -136,22 +136,28 @@ self:BindLobbyButtons()
self:BindMenuButtons() self:BindMenuButtons()
self:GoLobbyMap()`), self:GoLobbyMap()`),
method('RenderSoulLabel', `local soulPoints = self.SoulPoints or 0 method('RenderSoulLabel', `local soulPoints = self.SoulPoints or 0
self:SetText("/ui/LobbyUIGroup/LobbyHud/SoulLabel", "영혼 " .. string.format("%d", soulPoints)) self:SetText("/ui/LobbyUIGroup/LobbyHud/SoulLabel", "Soul " .. string.format("%d", soulPoints))
self:SetText("/ui/LobbyUIGroup/SoulShopHud/Souls", "영혼 " .. string.format("%d", soulPoints))`), self:SetText("/ui/LobbyUIGroup/SoulShopHud/Souls", "Soul " .. string.format("%d", soulPoints))`),
method('BindLobbyButtons', `if self.LobbyBound == true then method('BindLobbyButtons', `if self.LobbyBound == true then
return return
end end
self.LobbyBound = true self.LobbyBound = true
local function bindClick(path, handler) local ascMinus = _EntityService:GetEntityByPath("/ui/LobbyUIGroup/LobbyHud/AscMinus")
local entity = _EntityService:GetEntityByPath(path) if ascMinus ~= nil and (ascMinus.ButtonComponent ~= nil or ascMinus:AddComponent("ButtonComponent") ~= nil) then
if entity ~= nil and (entity.ButtonComponent ~= nil or entity:AddComponent("ButtonComponent") ~= nil) then ascMinus:ConnectEvent(ButtonClickEvent, function() self:AdjustAscension(-1) end)
entity:ConnectEvent(ButtonClickEvent, handler)
end
end end
bindClick("/ui/LobbyUIGroup/LobbyHud/AscMinus", function() self:AdjustAscension(-1) end) local ascPlus = _EntityService:GetEntityByPath("/ui/LobbyUIGroup/LobbyHud/AscPlus")
bindClick("/ui/LobbyUIGroup/LobbyHud/AscPlus", function() self:AdjustAscension(1) end) if ascPlus ~= nil and (ascPlus.ButtonComponent ~= nil or ascPlus:AddComponent("ButtonComponent") ~= nil) then
bindClick("/ui/LobbyUIGroup/BoardHud/Close", function() self:CloseBoard() end) ascPlus:ConnectEvent(ButtonClickEvent, function() self:AdjustAscension(1) end)
bindClick("/ui/LobbyUIGroup/SoulShopHud/Close", function() self:CloseSoulShop() end)`), end
local boardClose = _EntityService:GetEntityByPath("/ui/LobbyUIGroup/BoardHud/Close")
if boardClose ~= nil and (boardClose.ButtonComponent ~= nil or boardClose:AddComponent("ButtonComponent") ~= nil) then
boardClose:ConnectEvent(ButtonClickEvent, function() self:CloseBoard() end)
end
local soulClose = _EntityService:GetEntityByPath("/ui/LobbyUIGroup/SoulShopHud/Close")
if soulClose ~= nil and (soulClose.ButtonComponent ~= nil or soulClose:AddComponent("ButtonComponent") ~= nil) then
soulClose:ConnectEvent(ButtonClickEvent, function() self:CloseSoulShop() end)
end`),
method('ShowCodex', `self.CodexMode = true method('ShowCodex', `self.CodexMode = true
self.ClassDeckMode = true self.ClassDeckMode = true
local close = _EntityService:GetEntityByPath("/ui/DeckUIGroup/DeckAllHud/Close") local close = _EntityService:GetEntityByPath("/ui/DeckUIGroup/DeckAllHud/Close")

View File

@@ -41,24 +41,36 @@ if lp ~= nil then
end end
self:RenderSoulLabel()`, [{ Type: "number", DefaultValue: null, SyncDirection: 0, Attributes: [], Name: "n" }]), self:RenderSoulLabel()`, [{ Type: "number", DefaultValue: null, SyncDirection: 0, Attributes: [], Name: "n" }]),
method('BuySoulUnlock', `local d = nil method('BuySoulUnlock', `local d = nil
if self.SoulShopDef ~= nil then d = self.SoulShopDef[slot] end if self.SoulShopDef ~= nil then
if d == nil then return end d = self.SoulShopDef[slot]
if self.SoulUnlocks ~= nil and self.SoulUnlocks[d.key] == true then end
self:Toast("이미 보유 중입니다") if d == nil then
return return
end end
if (self.SoulPoints or 0) < d.cost then local unlockKey = d.key
self:Toast("영혼이 부족합니다") local unlockCost = d.cost
local unlockName = d.name or "Unlock"
if unlockKey == nil or unlockCost == nil then
return return
end end
self.SoulPoints = self.SoulPoints - d.cost if self.SoulUnlocks ~= nil and self.SoulUnlocks[unlockKey] == true then
if self.SoulUnlocks == nil then self.SoulUnlocks = {} end self:Toast("Already owned")
self.SoulUnlocks[d.key] = true return
end
if (self.SoulPoints or 0) < unlockCost then
self:Toast("Not enough soul")
return
end
self.SoulPoints = self.SoulPoints - unlockCost
if self.SoulUnlocks == nil then
self.SoulUnlocks = {}
end
self.SoulUnlocks[unlockKey] = true
local lp = _UserService.LocalPlayer local lp = _UserService.LocalPlayer
if lp ~= nil then if lp ~= nil then
self:SaveSouls(self.SoulPoints, self:SerializeUnlocks(), lp.PlayerComponent.UserId) self:SaveSouls(self.SoulPoints, self:SerializeUnlocks(), lp.PlayerComponent.UserId)
end end
self:Toast(d.name .. " 해금!") self:Toast(unlockName .. " unlocked")
self:RenderSoulLabel() self:RenderSoulLabel()
self:RenderSoulShop()`, [{ Type: "number", DefaultValue: null, SyncDirection: 0, Attributes: [], Name: "slot" }]), self:RenderSoulShop()`, [{ Type: "number", DefaultValue: null, SyncDirection: 0, Attributes: [], Name: "slot" }]),
method('RenderSoulShop', `local defs = self.SoulShopDef or {} method('RenderSoulShop', `local defs = self.SoulShopDef or {}
@@ -68,16 +80,20 @@ for i = 1, 4 do
if d == nil then if d == nil then
self:SetEntityEnabled(base, false) self:SetEntityEnabled(base, false)
else else
local itemName = d.name or "Unlock"
local itemDesc = d.desc or ""
local itemKey = d.key
local itemCost = d.cost or 0
self:SetEntityEnabled(base, true) self:SetEntityEnabled(base, true)
self:SetText(base .. "/Name", d.name) self:SetText(base .. "/Name", itemName)
self:SetText(base .. "/Desc", d.desc) self:SetText(base .. "/Desc", itemDesc)
local owned = self.SoulUnlocks ~= nil and self.SoulUnlocks[d.key] == true local owned = itemKey ~= nil and self.SoulUnlocks ~= nil and self.SoulUnlocks[itemKey] == true
if owned then if owned then
self:SetText(base .. "/Status", "보유 중") self:SetText(base .. "/Status", "Owned")
elseif (self.SoulPoints or 0) >= d.cost then elseif (self.SoulPoints or 0) >= itemCost then
self:SetText(base .. "/Status", tostring(d.cost) .. " 영혼 · 구매") self:SetText(base .. "/Status", tostring(itemCost) .. " soul · buy")
else else
self:SetText(base .. "/Status", tostring(d.cost) .. " 영혼 · 부족") self:SetText(base .. "/Status", tostring(itemCost) .. " soul · low")
end end
end end
end`), end`),

View File

@@ -36,6 +36,7 @@ function writeCodeblocks() {
prop('number', 'TweenEventId', '0'), prop('number', 'TweenEventId', '0'),
prop('number', 'CardHoverTweenId', '0'), prop('number', 'CardHoverTweenId', '0'),
prop('number', 'DmgPopSeq', '0'), prop('number', 'DmgPopSeq', '0'),
prop('any', 'DmgPopSlotQueue'),
prop('any', 'EndTurnHandler'), prop('any', 'EndTurnHandler'),
prop('any', 'NewGameHandler'), prop('any', 'NewGameHandler'),
prop('any', 'WarriorSelectHandler'), prop('any', 'WarriorSelectHandler'),
@@ -142,10 +143,14 @@ function writeCodeblocks() {
prop('number', 'PoisonApplicationsThisCombat', '0'), prop('number', 'PoisonApplicationsThisCombat', '0'),
prop('number', 'EnemyStrengthLossThisTurn', '0'), prop('number', 'EnemyStrengthLossThisTurn', '0'),
prop('number', 'ActiveKillReward', '0'), prop('number', 'ActiveKillReward', '0'),
prop('number', 'ActiveKillMaxHpGain', '0'),
prop('number', 'BonusRewardScreens', '0'), prop('number', 'BonusRewardScreens', '0'),
prop('number', 'FightAttackCount', '0'), prop('number', 'FightAttackCount', '0'),
prop('number', 'TurnAttackCardsPlayed', '0'), prop('number', 'TurnAttackCardsPlayed', '0'),
prop('number', 'TurnCardsPlayedThisTurn', '0'), prop('number', 'TurnCardsPlayedThisTurn', '0'),
prop('number', 'ComboCount', '0'),
prop('number', 'HolyChargeCount', '0'),
prop('boolean', 'DamagePowerStrengthUsed', 'false'),
prop('number', 'DamageDealtThisTurn', '0'), prop('number', 'DamageDealtThisTurn', '0'),
prop('number', 'TurnDiscardedCards', '0'), prop('number', 'TurnDiscardedCards', '0'),
prop('boolean', 'FirstHpLossDone', 'false'), prop('boolean', 'FirstHpLossDone', 'false'),
@@ -173,6 +178,7 @@ function writeCodeblocks() {
prop('boolean', 'NextSkillCostZero', 'false'), prop('boolean', 'NextSkillCostZero', 'false'),
prop('number', 'NextSkillRepeatCount', '0'), prop('number', 'NextSkillRepeatCount', '0'),
prop('any', 'NextTurnAddCards'), prop('any', 'NextTurnAddCards'),
prop('any', 'ZeroCostCardIdsThisTurn'),
], [ ], [
...bootMethods, ...bootMethods,
...screensMethods, ...screensMethods,

View File

@@ -19,18 +19,18 @@ for (const cls of Object.keys(CLASSES)) {
// 전직 옵션 // 전직 옵션
const JOBS = { const JOBS = {
warrior: [ warrior: [
{ id: 'fighter', name: '파이터', desc: '공격 특화\n콤보 어택 · 버서크\n라이징 어택', starter: 'ComboAttack', tier: 2, parent: 'warrior' }, { id: 'fighter', name: '파이터', desc: '콤보와 다단 공격 특화\n공격으로 콤보를 쌓고\n추가타로 압박', starter: 'ComboAttack', tier: 2, parent: 'warrior' },
{ id: 'page', name: '페이지', desc: '속성 차지 특화\n썬더/블리자드 차지\n파워 가드', starter: 'ThunderCharge', tier: 2, parent: 'warrior' }, { id: 'page', name: '페이지', desc: '홀리 포스와 방어 특화\n홀리 차지를 쌓아\n공격과 생존 강화', starter: 'HolyCharge', tier: 2, parent: 'warrior' },
{ id: 'spearman', name: '스피어맨', desc: '방어·관통 특화\n피어스 · 아이언 월\n하이퍼 바디', starter: 'Pierce', tier: 2, parent: 'warrior' }, { id: 'spearman', name: '스피어맨', desc: '광역·장기전 계열\n대화재 · 소용돌이\n불의 심장', starter: 'Conflagration', tier: 2, parent: 'warrior' },
], ],
fighter: [ fighter: [
{ id: 'crusader', name: '크루세이더', desc: 'Fighter의 3차 전직\n콤보 압박과 화력 심화\n파이터 카드 계승', starter: '', tier: 3, parent: 'fighter' }, { id: 'crusader', name: '크루세이더', desc: '파이터의 3차 전직\n콤보 상한과 연계 피해 강화\n파이터 카드 계승', starter: 'ComboSynergy', tier: 3, parent: 'fighter' },
], ],
page: [ page: [
{ id: 'knight', name: '나이트', desc: 'Page의 3차 전직\n방어와 차지 운영 심화\n페이지 카드 계승', starter: '', tier: 3, parent: 'page' }, { id: 'knight', name: '나이트', desc: '페이지의 3차 전직\n홀리 차지를 공격·방어·회복으로 전환\n페이지 카드 계승', starter: 'DivineCharge', tier: 3, parent: 'page' },
], ],
spearman: [ spearman: [
{ id: 'berserker', name: '버서커', desc: 'Spearman의 3차 전직\n관통과 생존 운영 심화\n스피어맨 카드 계승', starter: '', tier: 3, parent: 'spearman' }, { id: 'berserker', name: '버서커', desc: '스피어맨의 3차 전직\n아이언클래드 장기전 풀 계승\n전사 카드 사용', starter: '', tier: 3, parent: 'spearman' },
], ],
magician: [ magician: [
{ id: 'firepoison', name: '위자드(불·독)', desc: '화염·독 특화\n파이어 애로우\n포이즌 브레스 · 앰플', starter: 'FireArrow', tier: 2, parent: 'magician' }, { id: 'firepoison', name: '위자드(불·독)', desc: '화염·독 특화\n파이어 애로우\n포이즌 브레스 · 앰플', starter: 'FireArrow', tier: 2, parent: 'magician' },
@@ -224,6 +224,12 @@ function luaCardsTable(cards) {
const lines = Object.entries(cards).map(([id, c]) => { const lines = Object.entries(cards).map(([id, c]) => {
const fields = [`name = ${luaStr(c.name)}`, `cost = ${c.cost}`, `desc = ${luaStr(c.desc)}`, `kind = ${luaStr(c.kind)}`]; const fields = [`name = ${luaStr(c.name)}`, `cost = ${c.cost}`, `desc = ${luaStr(c.desc)}`, `kind = ${luaStr(c.kind)}`];
if (c.damage != null) fields.push(`damage = ${c.damage}`); if (c.damage != null) fields.push(`damage = ${c.damage}`);
if (c.damageFromCurrentBlock != null) fields.push(`damageFromCurrentBlock = ${c.damageFromCurrentBlock}`);
if (c.damagePerCombo != null) fields.push(`damagePerCombo = ${c.damagePerCombo}`);
if (c.damagePerHolyCharge != null) fields.push(`damagePerHolyCharge = ${c.damagePerHolyCharge}`);
if (c.attackDamagePerCombo != null) fields.push(`attackDamagePerCombo = ${c.attackDamagePerCombo}`);
if (c.damageNameMatch != null) fields.push(`damageNameMatch = ${luaStr(c.damageNameMatch)}`);
if (c.damagePerOwnedNameMatch != null) fields.push(`damagePerOwnedNameMatch = ${c.damagePerOwnedNameMatch}`);
if (c.damagePerOtherHandCard != null) fields.push(`damagePerOtherHandCard = ${c.damagePerOtherHandCard}`); if (c.damagePerOtherHandCard != null) fields.push(`damagePerOtherHandCard = ${c.damagePerOtherHandCard}`);
if (c.damagePerAttackPlayedThisTurn != null) fields.push(`damagePerAttackPlayedThisTurn = ${c.damagePerAttackPlayedThisTurn}`); if (c.damagePerAttackPlayedThisTurn != null) fields.push(`damagePerAttackPlayedThisTurn = ${c.damagePerAttackPlayedThisTurn}`);
if (c.damagePerDiscardedThisTurn != null) fields.push(`damagePerDiscardedThisTurn = ${c.damagePerDiscardedThisTurn}`); if (c.damagePerDiscardedThisTurn != null) fields.push(`damagePerDiscardedThisTurn = ${c.damagePerDiscardedThisTurn}`);
@@ -232,8 +238,10 @@ function luaCardsTable(cards) {
if (c.damagePerTurn != null) fields.push(`damagePerTurn = ${c.damagePerTurn}`); if (c.damagePerTurn != null) fields.push(`damagePerTurn = ${c.damagePerTurn}`);
if (c.cardPlayedDamage != null) fields.push(`cardPlayedDamage = ${c.cardPlayedDamage}`); if (c.cardPlayedDamage != null) fields.push(`cardPlayedDamage = ${c.cardPlayedDamage}`);
if (c.cardPlayedRandomDamage != null) fields.push(`cardPlayedRandomDamage = ${c.cardPlayedRandomDamage}`); if (c.cardPlayedRandomDamage != null) fields.push(`cardPlayedRandomDamage = ${c.cardPlayedRandomDamage}`);
if (c.attackPlayedDamage != null) fields.push(`attackPlayedDamage = ${c.attackPlayedDamage}`);
if (c.firstCardDamageBonus != null) fields.push(`firstCardDamageBonus = ${c.firstCardDamageBonus}`); if (c.firstCardDamageBonus != null) fields.push(`firstCardDamageBonus = ${c.firstCardDamageBonus}`);
if (c.rewardOnKill != null) fields.push(`rewardOnKill = ${c.rewardOnKill}`); if (c.rewardOnKill != null) fields.push(`rewardOnKill = ${c.rewardOnKill}`);
if (c.maxHpOnKill != null) fields.push(`maxHpOnKill = ${c.maxHpOnKill}`);
if (c.intangible != null) fields.push(`intangible = ${c.intangible}`); if (c.intangible != null) fields.push(`intangible = ${c.intangible}`);
if (c.endTurnDexLoss != null) fields.push(`endTurnDexLoss = ${c.endTurnDexLoss}`); if (c.endTurnDexLoss != null) fields.push(`endTurnDexLoss = ${c.endTurnDexLoss}`);
if (c.poisonPerTurn != null) fields.push(`poisonPerTurn = ${c.poisonPerTurn}`); if (c.poisonPerTurn != null) fields.push(`poisonPerTurn = ${c.poisonPerTurn}`);
@@ -247,6 +255,16 @@ function luaCardsTable(cards) {
if (c.dex != null) fields.push(`dex = ${c.dex}`); if (c.dex != null) fields.push(`dex = ${c.dex}`);
if (c.thorns != null) fields.push(`thorns = ${c.thorns}`); if (c.thorns != null) fields.push(`thorns = ${c.thorns}`);
if (c.cardPlayedBlock != null) fields.push(`cardPlayedBlock = ${c.cardPlayedBlock}`); if (c.cardPlayedBlock != null) fields.push(`cardPlayedBlock = ${c.cardPlayedBlock}`);
if (c.comboOnAttack != null) fields.push(`comboOnAttack = ${c.comboOnAttack}`);
if (c.comboMax != null) fields.push(`comboMax = ${c.comboMax}`);
if (c.attackWeak != null) fields.push(`attackWeak = ${c.attackWeak}`);
if (c.holyChargeOnHolyForce != null) fields.push(`holyChargeOnHolyForce = ${c.holyChargeOnHolyForce}`);
if (c.holyChargeMax != null) fields.push(`holyChargeMax = ${c.holyChargeMax}`);
if (c.damageTakenReduction != null) fields.push(`damageTakenReduction = ${c.damageTakenReduction}`);
if (c.blockOnDamaged != null) fields.push(`blockOnDamaged = ${c.blockOnDamaged}`);
if (c.strengthOnDamagedOnce != null) fields.push(`strengthOnDamagedOnce = ${c.strengthOnDamagedOnce}`);
if (c.drawOnExhaust != null) fields.push(`drawOnExhaust = ${c.drawOnExhaust}`);
if (c.drawNameMatchAutoPlay != null) fields.push(`drawNameMatchAutoPlay = ${luaStr(c.drawNameMatchAutoPlay)}`);
if (c.weak != null) fields.push(`weak = ${c.weak}`); if (c.weak != null) fields.push(`weak = ${c.weak}`);
if (c.vuln != null) fields.push(`vuln = ${c.vuln}`); if (c.vuln != null) fields.push(`vuln = ${c.vuln}`);
if (c.powerEffect != null) fields.push(`powerEffect = ${luaStr(c.powerEffect)}`); if (c.powerEffect != null) fields.push(`powerEffect = ${luaStr(c.powerEffect)}`);
@@ -262,8 +280,26 @@ function luaCardsTable(cards) {
if (c.drawSkillBlock != null) fields.push(`drawSkillBlock = ${c.drawSkillBlock}`); if (c.drawSkillBlock != null) fields.push(`drawSkillBlock = ${c.drawSkillBlock}`);
if (c.drawDamage != null) fields.push(`drawDamage = ${c.drawDamage}`); if (c.drawDamage != null) fields.push(`drawDamage = ${c.drawDamage}`);
if (c.drawPoison != null) fields.push(`drawPoison = ${c.drawPoison}`); if (c.drawPoison != null) fields.push(`drawPoison = ${c.drawPoison}`);
if (c.exhaustHandNonAttack === true) fields.push('exhaustHandNonAttack = true');
if (c.exhaustHandAll === true) fields.push('exhaustHandAll = true');
if (c.drawPerExhausted != null) fields.push(`drawPerExhausted = ${c.drawPerExhausted}`);
if (c.blockPerExhaustedCard != null) fields.push(`blockPerExhaustedCard = ${c.blockPerExhaustedCard}`);
if (c.addRandomCardCount != null) fields.push(`addRandomCardCount = ${c.addRandomCardCount}`);
if (c.addRandomCardPerExhausted != null) fields.push(`addRandomCardPerExhausted = ${c.addRandomCardPerExhausted}`);
if (c.addRandomCardKind != null) fields.push(`addRandomCardKind = ${luaStr(c.addRandomCardKind)}`);
if (c.addRandomCardSameClass === true) fields.push('addRandomCardSameClass = true');
if (c.addedCardsCostZeroThisTurn === true) fields.push('addedCardsCostZeroThisTurn = true');
if (c.playTopDrawPileCount != null) fields.push(`playTopDrawPileCount = ${c.playTopDrawPileCount}`);
if (c.playTopDrawPileCountPerEnergy != null) fields.push(`playTopDrawPileCountPerEnergy = ${c.playTopDrawPileCountPerEnergy}`);
if (c.heal != null) fields.push(`heal = ${c.heal}`); if (c.heal != null) fields.push(`heal = ${c.heal}`);
if (c.healPerHolyCharge != null) fields.push(`healPerHolyCharge = ${c.healPerHolyCharge}`);
if (c.gainEnergy != null) fields.push(`gainEnergy = ${c.gainEnergy}`); if (c.gainEnergy != null) fields.push(`gainEnergy = ${c.gainEnergy}`);
if (c.comboGain != null) fields.push(`comboGain = ${c.comboGain}`);
if (c.removePlayerDebuffs === true) fields.push('removePlayerDebuffs = true');
if (c.holyForce === true) fields.push('holyForce = true');
if (c.holyChargeGain != null) fields.push(`holyChargeGain = ${c.holyChargeGain}`);
if (c.blockPerHolyCharge != null) fields.push(`blockPerHolyCharge = ${c.blockPerHolyCharge}`);
if (c.holyChargeSpendAll === true) fields.push('holyChargeSpendAll = true');
if (c.poison != null) fields.push(`poison = ${c.poison}`); if (c.poison != null) fields.push(`poison = ${c.poison}`);
if (c.discard != null) fields.push(`discard = ${c.discard}`); if (c.discard != null) fields.push(`discard = ${c.discard}`);
if (c.discardAll === true) fields.push('discardAll = true'); if (c.discardAll === true) fields.push('discardAll = true');

View File

@@ -1,108 +1,55 @@
import { readFileSync, writeFileSync } from 'node:fs'; import { readFileSync, writeFileSync } from 'node:fs';
import { buildMonsterInstance } from '../monster/lib/monster-model.mjs';
// map02~11에 노드 타입별 몬스터 그룹(combat3/elite2/boss1)을 맵별 테마로 자동 구성. // map01~05에 data/encounters.json 로스터대로 종별 모델 인스턴스를 배치(결정론).
// 기존 몬스터 엔티티 전부 제거하고 첫 몬스터를 템플릿으로 6마리 재생성(결정론). // 기존 몬스터 엔티티 전부 제거 후 로스터 전체를 그룹별 x 균등 분포로 재생성.
const MAP_NUMBERS = [1, 2, 3, 4, 5]; // 준비도 가드: 로스터에 appearance 미보유 적이 있는 맵은 재생성을 건너뛴다(기존 맵 보존).
const COMBAT_POOL = ['orange_mushroom', 'green_mushroom', 'pig', 'blue_mushroom', 'red_snail', 'stump']; const enemies = JSON.parse(readFileSync('data/enemies.json', 'utf8')).enemies;
const ELITE_POOL = ['mushmom', 'modified_snail']; const encounters = JSON.parse(readFileSync('data/encounters.json', 'utf8'));
const BOSS_POOL = ['king_slime', 'slime_boss']; const X_RANGE = { combat: [2.3, 6.6], elite: [3.0, 5.6], boss: [4.6, 4.6] };
// map01: StS2식 일반 5종 + 엘리트 1 + 보스 1(보스 노드용, 화면 우측 포메이션).
// 그 외 맵: 일반 3 + 엘리트 2 + 보스 1. 전투 시 BuildMonsters가 노드 타입별로 1~3마리 랜덤 추첨.
const LAYOUT_MAP01 = [
{ group: 'combat', x: 2.6 }, { group: 'combat', x: 3.6 }, { group: 'combat', x: 4.6 },
{ group: 'combat', x: 5.6 }, { group: 'combat', x: 6.6 },
{ group: 'elite', x: 4.6 },
{ group: 'boss', x: 4.6 },
];
const LAYOUT_DEFAULT = [
{ 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 layoutFor = (nn) => (nn === 1 ? LAYOUT_MAP01 : LAYOUT_DEFAULT);
const MONSTER_VARIANTS = [
{ sprite: '96e955c1bf27415e84f96deea200a8f1', stand: '96e955c1bf27415e84f96deea200a8f1', hit: 'aec9504d5dc24aceb5646b79d30abad4', die: '65a2bfb039614f2e9e4ccc354340153d' },
{ sprite: 'f86992ba9c41487c8480fcb893fcbda6', stand: 'f86992ba9c41487c8480fcb893fcbda6', hit: 'd305b942b1704c8084548108ff3b7a6b', die: '5a563e5fd98c4132b61057dc6bb8aaf2' },
{ sprite: 'a2204a21d88942b281d2cac6053ffbaa', stand: 'a2204a21d88942b281d2cac6053ffbaa', hit: 'afc08936b8a64b26bc3dd8c03ead1f26', die: 'fc1c6d9ba9bc413ab53b6dbfae3ac45b' },
{ sprite: 'd8f014043ce8418f96700c2b6c9ebf6c', stand: 'd8f014043ce8418f96700c2b6c9ebf6c', hit: 'c3cf643b618346c7bfa6574187b396f9', die: 'a88d9b3d60f941e4890dc89a6ccaa8ee' },
{ sprite: '17b55730c26f4fd6b8fcfa288da388de', stand: '17b55730c26f4fd6b8fcfa288da388de', hit: 'eac48e84a9fc4580a4018de5cf52ddb3', die: '51c2f4b59a2c413db26035aa57002fc8' },
{ sprite: '48c10437ae8344a9b2a1d3f36185728f', stand: '48c10437ae8344a9b2a1d3f36185728f', hit: '9044063647854f5e9128efcf80e909be', die: 'f414577d18c94cc387c275df4abdbc3b' },
{ sprite: '4ca39dbfa1c6492283ba8bd352d12b0a', stand: '4ca39dbfa1c6492283ba8bd352d12b0a', hit: '7ac78511036e4ebe988b97c35fc275d1', die: '740f3f2b2e7a4b71bec5eac84e8539f9' },
{ sprite: 'ed3908e24d694bb786023fc1ed073489', stand: 'ed3908e24d694bb786023fc1ed073489', hit: '4763c9bebc9245998c9c499b6316aa9f', die: 'b168793b92a844a3a3a6f4ce647a14d2' },
{ sprite: '3109357701ae41a4bcc7543f52f1f4c3', stand: '3109357701ae41a4bcc7543f52f1f4c3', hit: 'ce0269079e884545b5bb6ea075e2a67f', die: 'a5e65650e00e47878cac1be7a5b999a0' },
];
function rng(seed) { let s = seed >>> 0; return () => { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296; }; } const isMonster = (e) => typeof e.componentNames === 'string' && e.componentNames.includes('script.Monster');
function encGuid(nn, idx) { function encGuid(nn, idx) {
const n = (nn * 1000 + 500 + idx) >>> 0; const n = (nn * 1000 + 500 + idx) >>> 0;
const h8 = n.toString(16).padStart(8, '0'); return `${n.toString(16).padStart(8, '0')}-0000-4000-8000-${n.toString(16).padStart(12, '0')}`;
const h12 = n.toString(16).padStart(12, '0');
return `${h8}-0000-4000-8000-${h12}`;
} }
const isMonster = (e) => typeof e.componentNames === 'string' && e.componentNames.includes('script.Monster'); function slotX(group, i, count) {
const compOf = (e, t) => e.jsonString['@components'].find((c) => c['@type'] === t); const [lo, hi] = X_RANGE[group];
return count <= 1 ? (lo + hi) / 2 : lo + (i * (hi - lo)) / (count - 1);
function pick(rand, pool) { return pool[Math.floor(rand() * pool.length)]; }
function pickN(rand, pool, 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) { function patchMap(nn) {
const tag = String(nn).padStart(2, '0'); const tag = String(nn).padStart(2, '0');
const file = `map/map${tag}.map`; const file = `map/map${tag}.map`;
const roster = encounters[`map${tag}`];
if (!roster) throw new Error(`[gen-map-encounters] encounters.json에 map${tag} 없음`);
const rosterIds = ['combat', 'elite', 'boss'].flatMap((g) => roster[g] || []);
for (const id of rosterIds) {
if (!enemies[id]) throw new Error(`[gen-map-encounters] map${tag} 로스터에 없는 적: ${id}`);
}
// 준비도 가드: appearance 미보유 적이 하나라도 있으면 이 맵은 보존(스킵)
const missing = rosterIds.filter((id) => !enemies[id].appearance);
if (missing.length) return `map${tag}(SKIP: appearance 없음 ${[...new Set(missing)].join('/')})`;
const map = JSON.parse(readFileSync(file, 'utf8')); const map = JSON.parse(readFileSync(file, 'utf8'));
const ents = map.ContentProto.Entities; map.ContentProto.Entities = map.ContentProto.Entities.filter((e) => !isMonster(e));
const monsters = ents.filter(isMonster); const nameCount = {};
if (monsters.length === 0) throw new Error(`[gen-map-encounters] ${file} 몬스터 템플릿 없음`); let idx = 0;
const template = monsters[0]; for (const group of ['combat', 'elite', 'boss']) {
map.ContentProto.Entities = ents.filter((e) => !isMonster(e)); const ids = roster[group] || [];
const rand = rng(nn * 7919 + 17); ids.forEach((enemyId, i) => {
const layout = layoutFor(nn); nameCount[enemyId] = (nameCount[enemyId] || 0) + 1;
const nCombat = layout.filter((s) => s.group === 'combat').length; const name = nameCount[enemyId] > 1 ? `${enemyId}_${nameCount[enemyId]}` : enemyId;
const nElite = layout.filter((s) => s.group === 'elite').length; map.ContentProto.Entities.push(buildMonsterInstance({
const combatIds = pickN(rand, COMBAT_POOL, nCombat); enemyId, enemy: enemies[enemyId], name, guid: encGuid(nn, idx), mapTag: tag, x: slotX(group, i, ids.length), group,
const eliteIds = pickN(rand, ELITE_POOL, nElite); }));
const bossId = pick(rand, BOSS_POOL); idx += 1;
const variants = pickN(rand, MONSTER_VARIANTS, layout.length); });
let ci = 0, ei = 0; }
layout.forEach((slot, idx) => {
const m = JSON.parse(JSON.stringify(template));
const enemyId = slot.group === 'combat' ? combatIds[ci++] : slot.group === 'elite' ? eliteIds[ei++] : 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'); writeFileSync(file, JSON.stringify(map, null, 2), 'utf8');
return `map${tag}(${combatIds.join('/')}|${eliteIds.join('/')}|${bossId})`; const counts = ['combat', 'elite', 'boss'].map((g) => `${g}${(roster[g] || []).length}`).join('/');
return `map${tag}(${counts})`;
} }
const made = MAP_NUMBERS.map(patchMap); const made = [1, 2, 3, 4, 5].map(patchMap);
console.log('Encounters:', made.join(', ')); console.log('Encounters:', made.join(', '));

View File

@@ -1,10 +1,8 @@
import { readFileSync, writeFileSync } from 'node:fs'; import { writeFileSync } from 'node:fs';
// 맵 몬스터에 적 타입(EnemyId)을 부여하고, BeginPlay 시 /common 컨트롤러에 자기등록하는 마커. // 카드 전투용 자기등록 마커 codeblock(CombatMonster) 생성.
// 카드 전투 시 컨트롤러가 등록 목록으로 인카운터를 구성한다. // BeginPlay 시 /common 컨트롤러에 자기등록해 인카운터를 구성한다.
const MAP_NUMBERS = Array.from({ length: 5 }, (_, i) => i + 1); // map01~05 // 맵 부착 값(EnemyId/Group)은 gen-map-encounters.mjs가 인스턴스에 직접 기록한다.
const NAME_TO_ENEMY = { '주황버섯': 'orange_mushroom', '파란버섯': 'blue_mushroom' };
const DEFAULT_ENEMY = 'orange_mushroom';
function prop(Type, Name, DefaultValue = 'nil') { function prop(Type, Name, DefaultValue = 'nil') {
return { Type, DefaultValue, SyncDirection: 0, Attributes: [], Name }; return { Type, DefaultValue, SyncDirection: 0, Attributes: [], Name };
@@ -49,39 +47,5 @@ eventId = _TimerService:SetTimerRepeat(reg, 0.1)`),
writeFileSync('RootDesk/MyDesk/CombatMonster.codeblock', JSON.stringify(cb, null, 2) + '\n', 'utf8'); writeFileSync('RootDesk/MyDesk/CombatMonster.codeblock', JSON.stringify(cb, null, 2) + '\n', 'utf8');
} }
const isMonster = (e) => typeof e.componentNames === 'string' && e.componentNames.includes('script.Monster');
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 == null) existing.EnemyId = NAME_TO_ENEMY[name] || DEFAULT_ENEMY;
if (existing.Group == null) 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})`;
}
writeCodeblock(); writeCodeblock();
const patched = MAP_NUMBERS.map(patchMap); console.log('CombatMonster codeblock written.');
console.log('CombatMonster codeblock written; patched maps:', patched.join(', '));

View File

@@ -0,0 +1,29 @@
import { readFileSync, writeFileSync, readdirSync } from 'node:fs';
import { buildMonsterModel, modelEntryId } from './lib/monster-model.mjs';
// 적 18종 각각의 전용 모델(.model) emit. 단일 소스: data/enemies.json(appearance) + ChaseMonster.model(골격).
const OUT_DIR = 'RootDesk/MyDesk/Models/Monsters';
const enemies = JSON.parse(readFileSync('data/enemies.json', 'utf8')).enemies;
const skeleton = JSON.parse(readFileSync('Global/ChaseMonster.model', 'utf8'));
// EntryKey 충돌 가드 (LEA-3015 예방): 기존 .model들의 EntryKey 수집 (경로별)
const existing = []; // { key, path }
for (const dir of ['Global', OUT_DIR]) {
for (const f of readdirSync(dir).filter((n) => n.endsWith('.model'))) {
const path = `${dir}/${f}`;
existing.push({ key: JSON.parse(readFileSync(path, 'utf8')).EntryKey, path });
}
}
const written = [];
const skipped = [];
for (const [enemyId, enemy] of Object.entries(enemies)) {
if (!enemy.appearance) { skipped.push(enemyId); continue; }
const file = buildMonsterModel(enemyId, enemy, skeleton);
const outPath = `${OUT_DIR}/${enemyId}.model`;
const clash = existing.find((e) => e.key === file.EntryKey && e.path !== outPath);
if (clash) throw new Error(`[gen-monster-models] EntryKey 충돌: ${file.EntryKey} (기존 ${clash.path})`);
writeFileSync(outPath, JSON.stringify(file, null, 2) + '\n', 'utf8');
written.push(enemyId);
}
console.log(`[gen-monster-models] ${written.length}종 emit${skipped.length ? ` / appearance 없음 스킵: ${skipped.join(', ')}` : ''}`);

View File

@@ -0,0 +1,78 @@
// 몬스터 종별 모델(.model)과 맵 인스턴스 엔티티의 공용 빌더.
// 단일 소스: data/enemies.json의 appearance. fs 접근 없음(호출자가 skeleton 주입) — 테스트 용이.
const STR_TYPE = 'System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089';
const SINGLE_TYPE = 'System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089';
const VEC2_TYPE = 'MOD.Core.MODVector2, MOD.Core, Version=26.5.0.0, Culture=neutral, PublicKeyToken=null';
const DICT_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';
const native = (type) => ({ $type: 'MODNativeType', type });
const vec2 = (v) => ({ $type: 'MOD.Core.MODVector2, MOD.Core', x: v.x, y: v.y });
const DAMAGE_SKIN_ID = '02c22d93421b4038b3c413b3e40b57ec';
export function modelEntryId(enemyId) {
return `monster-${enemyId}`;
}
function requireAppearance(enemyId, enemy) {
if (!enemy?.appearance?.sheet?.stand) throw new Error(`[monster-model] ${enemyId}: appearance.sheet.stand 없음 — data/enemies.json 확인`);
return enemy.appearance;
}
// .model 파일 전체 객체 생성 — ChaseMonster.model(skeleton)을 골격으로 복제·확장.
export function buildMonsterModel(enemyId, enemy, skeletonJson) {
const app = requireAppearance(enemyId, enemy);
const file = JSON.parse(JSON.stringify(skeletonJson)); // 순수성: 입력 비변형
const json = file.ContentProto.Json;
file.EntryKey = `model://${modelEntryId(enemyId)}`;
json.Id = modelEntryId(enemyId);
json.Name = enemyId;
json.Components = json.Components
.filter((c) => !c.includes('AIWander') && !c.includes('AIChase'))
.concat(['MOD.Core.DamageSkinSettingComponent', 'script.CombatMonster']);
const setValue = (TargetType, Name, typeStr, Value) => {
json.Values = json.Values.filter((v) => !(v.TargetType === TargetType && v.Name === Name));
json.Values.push({ TargetType, Name, ValueType: native(typeStr), Value });
};
setValue('MOD.Core.SpriteRendererComponent', 'SpriteRUID', STR_TYPE, app.sheet.stand);
setValue('MOD.Core.SpriteRendererComponent', 'SortingLayer', STR_TYPE, 'MapLayer0');
setValue('MOD.Core.StateAnimationComponent', 'ActionSheet', DICT_TYPE, { ...app.sheet }); // 메이커 미해석 시 이 줄만 제거(런타임은 인스턴스 값 사용)
setValue('MOD.Core.HitComponent', 'BoxSize', VEC2_TYPE, vec2(app.box));
setValue('MOD.Core.HitComponent', 'ColliderOffset', VEC2_TYPE, vec2(app.off));
setValue('MOD.Core.MovementComponent', 'InputSpeed', SINGLE_TYPE, 0);
setValue('script.CombatMonster', 'EnemyId', STR_TYPE, enemyId); // 편의 베이크 — 실패해도 무해(인스턴스가 정본)
return file;
}
// 맵 인스턴스 엔티티 — 현행 맵 몬스터 인스턴스 골격(map01 실측)과 동일 형태.
export function buildMonsterInstance({ enemyId, enemy, name, guid, mapTag, x, group }) {
const app = requireAppearance(enemyId, enemy);
const components = [
{ '@type': 'MOD.Core.TransformComponent', Position: { x, y: 0.03499998, z: 999.999 }, QuaternionRotation: { x: 0, y: 0, z: 0, w: 1 }, Scale: { x: 1, y: 1, z: 1 }, Enable: true },
{ '@type': 'MOD.Core.StateAnimationComponent', ActionSheet: { ...app.sheet }, Enable: true },
{ '@type': 'MOD.Core.SpriteRendererComponent', ActionSheet: {}, EndFrameIndex: 0, RenderSetting: 1, SortingLayer: 'MapLayer0', SpriteRUID: app.sheet.stand, StartFrameIndex: 0, Enable: true },
{ '@type': 'MOD.Core.RigidbodyComponent', MoveVelocity: { x: 0, y: 0 }, RealMoveVelocity: { x: 0, y: 0 }, Enable: true },
{ '@type': 'MOD.Core.MovementComponent', InputSpeed: 0, JumpForce: 6, Enable: false },
{ '@type': 'MOD.Core.StateComponent', IsLegacy: false, Enable: true },
{ '@type': 'MOD.Core.HitComponent', BoxSize: { x: app.box.x, y: app.box.y }, ColliderOffset: { x: app.off.x, y: app.off.y }, IsLegacy: false, Enable: true },
{ '@type': 'MOD.Core.DamageSkinSpawnerComponent', Enable: true },
{ '@type': 'script.Monster', Enable: true, IsDead: false },
{ '@type': 'script.MonsterAttack', Enable: true, SpriteSize: { x: 0, y: 0 }, PositionOffset: { x: 0, y: 0 } },
{ '@type': 'MOD.Core.KinematicbodyComponent', MoveVelocity: { x: 0, y: 0 }, Enable: true },
{ '@type': 'MOD.Core.SideviewbodyComponent', MoveVelocity: { x: 0, y: 0 }, Enable: true },
{ '@type': 'MOD.Core.DamageSkinSettingComponent', DamageSkinId: { DataId: DAMAGE_SKIN_ID }, Enable: true },
{ '@type': 'script.CombatMonster', Enable: true, EnemyId: enemyId, Group: group },
];
const path = `/maps/map${mapTag}/${name}`;
return {
id: guid,
path,
componentNames: components.map((c) => c['@type']).join(','),
jsonString: {
name, path, nameEditable: true, enable: true, visible: true, localize: false,
displayOrder: 4, pathConstraints: '///', revision: 2,
origin: { type: 'Model', entry_id: modelEntryId(enemyId), sub_entity_id: null, root_entity_id: guid, replaced_model_id: null },
modelId: modelEntryId(enemyId),
'@components': components,
'@version': 1,
},
};
}

View File

@@ -0,0 +1,60 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { buildMonsterModel, buildMonsterInstance, modelEntryId } from './lib/monster-model.mjs';
const skeleton = JSON.parse(readFileSync('Global/ChaseMonster.model', 'utf8'));
const enemy = {
name: '슬라임', maxHp: 45, intents: [],
appearance: { sheet: { stand: 'AAAA', hit: 'BBBB', die: 'CCCC' }, box: { x: 0.63, y: 0.58 }, off: { x: 0.045, y: 0.29 } },
};
test('modelEntryId: monster- 접두', () => {
assert.equal(modelEntryId('slime'), 'monster-slime');
});
test('buildMonsterModel: EntryKey/Id/Name 파생', () => {
const m = buildMonsterModel('slime', enemy, skeleton);
assert.equal(m.EntryKey, 'model://monster-slime');
assert.equal(m.ContentProto.Json.Id, 'monster-slime');
assert.equal(m.ContentProto.Json.Name, 'slime');
});
test('buildMonsterModel: 외형·EnemyId 베이크 + AI-free + 컴포넌트 확장', () => {
const j = buildMonsterModel('slime', enemy, skeleton).ContentProto.Json;
assert.ok(j.Components.includes('script.CombatMonster'));
assert.ok(j.Components.includes('MOD.Core.DamageSkinSettingComponent'));
assert.ok(!j.Components.some((c) => c.includes('AIWander') || c.includes('AIChase')));
const val = (t, n) => j.Values.find((v) => v.TargetType === t && v.Name === n)?.Value;
assert.equal(val('MOD.Core.SpriteRendererComponent', 'SpriteRUID'), 'AAAA');
assert.deepEqual(val('MOD.Core.StateAnimationComponent', 'ActionSheet'), enemy.appearance.sheet);
assert.equal(val('script.CombatMonster', 'EnemyId'), 'slime');
assert.equal(val('MOD.Core.MovementComponent', 'InputSpeed'), 0);
assert.equal(val('MOD.Core.HitComponent', 'BoxSize').x, 0.63);
});
test('buildMonsterModel: 원본 skeleton 비변형(순수 함수)', () => {
const before = JSON.stringify(skeleton);
buildMonsterModel('slime', enemy, skeleton);
assert.equal(JSON.stringify(skeleton), before);
});
test('buildMonsterInstance: 모델 연결·컴포넌트 값', () => {
const e = buildMonsterInstance({ enemyId: 'slime', enemy, name: 'slime', guid: '00000bb9-0000-4000-8000-000000000bb9', mapTag: '03', x: 3.4, group: 'elite' });
assert.equal(e.jsonString.modelId, 'monster-slime');
assert.equal(e.jsonString.origin.entry_id, 'monster-slime');
assert.equal(e.jsonString.origin.root_entity_id, e.id);
assert.equal(e.path, '/maps/map03/slime');
const comp = (t) => e.jsonString['@components'].find((c) => c['@type'] === t);
assert.equal(comp('script.CombatMonster').EnemyId, 'slime');
assert.equal(comp('script.CombatMonster').Group, 'elite');
assert.equal(comp('MOD.Core.TransformComponent').Position.x, 3.4);
assert.equal(comp('MOD.Core.SpriteRendererComponent').SpriteRUID, 'AAAA');
assert.deepEqual(comp('MOD.Core.StateAnimationComponent').ActionSheet, enemy.appearance.sheet);
assert.equal(comp('MOD.Core.MovementComponent').Enable, false);
assert.equal(e.componentNames, e.jsonString['@components'].map((c) => c['@type']).join(','));
});
test('buildMonsterInstance: appearance 없는 적은 에러(fail-fast)', () => {
assert.throws(() => buildMonsterInstance({ enemyId: 'x', enemy: { name: 'x' }, name: 'x', guid: 'g', mapTag: '01', x: 1, group: 'combat' }), /appearance/);
});

View File

@@ -17,6 +17,10 @@ const POWER_FIELDS = [
'shivDamageBonus', 'firstShivDamageBonus', 'shivRetain', 'shivAoe', 'shivDamageBonus', 'firstShivDamageBonus', 'shivRetain', 'shivAoe',
'attackPoison', 'drawDamage', 'drawPoison', 'attackDamageVsWeakMultiplier', 'attackPoison', 'drawDamage', 'drawPoison', 'attackDamageVsWeakMultiplier',
'cardPlayedBlock', 'cardPlayedDamage', 'cardPlayedRandomDamage', 'cardPlayedBlock', 'cardPlayedDamage', 'cardPlayedRandomDamage',
'comboOnAttack', 'comboMax', 'attackDamagePerCombo', 'attackPlayedDamage', 'attackWeak',
'holyChargeOnHolyForce', 'holyChargeMax', 'damageTakenReduction',
'blockOnDamaged', 'strengthOnDamagedOnce',
'drawOnExhaust', 'drawNameMatchAutoPlay',
'extraPoisonTicks', 'poisonApplicationBurstEvery', 'poisonApplicationBurstDamage', 'extraPoisonTicks', 'poisonApplicationBurstEvery', 'poisonApplicationBurstDamage',
'skillSlyOnPlay', 'endTurnDexLoss', 'skillSlyOnPlay', 'endTurnDexLoss',
]; ];
@@ -28,7 +32,7 @@ for (const [id, c] of Object.entries(cards)) {
issues.push(`${id}(${c.name}): 미지원 kind="${c.kind}"`); issues.push(`${id}(${c.name}): 미지원 kind="${c.kind}"`);
continue; continue;
} }
if (c.kind === 'Attack' && c.damage == null && c.xDamagePerEnergy == null) { if (c.kind === 'Attack' && c.damage == null && c.xDamagePerEnergy == null && c.damageFromCurrentBlock == null) {
issues.push(`${id}(${c.name}): kind=Attack인데 damage 없음 → 몬스터 드롭 라우팅 불가(방어/유틸이면 kind=Skill)`); issues.push(`${id}(${c.name}): kind=Attack인데 damage 없음 → 몬스터 드롭 라우팅 불가(방어/유틸이면 kind=Skill)`);
} }
if (c.kind === 'Power' && !POWER_FIELDS.some((f) => c[f] != null)) { if (c.kind === 'Power' && !POWER_FIELDS.some((f) => c[f] != null)) {

View File

@@ -24,7 +24,7 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": true, "localize": true,
"displayOrder": 4, "displayOrder": 6,
"pathConstraints": "//", "pathConstraints": "//",
"revision": 1, "revision": 1,
"origin": { "origin": {

View File

@@ -24,7 +24,7 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": true, "localize": true,
"displayOrder": 5, "displayOrder": 1,
"pathConstraints": "//", "pathConstraints": "//",
"revision": 1, "revision": 1,
"origin": { "origin": {

View File

@@ -24,7 +24,7 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": true, "localize": true,
"displayOrder": 1, "displayOrder": 2,
"pathConstraints": "//", "pathConstraints": "//",
"revision": 1, "revision": 1,
"origin": { "origin": {

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@
"enable": true, "enable": true,
"visible": true, "visible": true,
"localize": true, "localize": true,
"displayOrder": 2, "displayOrder": 3,
"pathConstraints": "//", "pathConstraints": "//",
"revision": 1, "revision": 1,
"origin": { "origin": {