From 37102923acdd3fd740ce9705576f33ad39ba2102 Mon Sep 17 00:00:00 2001 From: dal4segno Date: Tue, 29 Sep 2026 23:42:13 +0900 Subject: [PATCH] feat: apply captured API configuration for Blue Splash event --- .gitignore | 4 + README.md | 2 +- UPDATES.md | 6 + data/game-events/2026-09-29.json | 2900 +++++++++++++++++ data/game-events/current.json | 5 + docs/game-data-source.md | 10 +- docs/research/event-api-capture-2026-09-29.md | 91 + .../event-config-source-2026-09-29.md | 4 +- package.json | 3 +- scripts/collect-game-events.mjs | 96 + src/lib/data/events-api.json | 72 + src/lib/data/events.ts | 12 +- src/lib/engine/event-api.test.ts | 75 + src/lib/engine/event-optimization.ts | 10 + src/routes/combination/+page.svelte | 13 +- 15 files changed, 3287 insertions(+), 16 deletions(-) create mode 100644 data/game-events/2026-09-29.json create mode 100644 data/game-events/current.json create mode 100644 docs/research/event-api-capture-2026-09-29.md create mode 100644 scripts/collect-game-events.mjs create mode 100644 src/lib/data/events-api.json create mode 100644 src/lib/engine/event-api.test.ts diff --git a/.gitignore b/.gitignore index 038b4df..9129a81 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,7 @@ npm-debug.log* !data/game-db/snapshots/** data/game-db/derived/ data/game-db/review/ + +!data/game-events/ +data/game-events/* +!data/game-events/*.json diff --git a/README.md b/README.md index dc06762..11aedef 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ npm run data:apply 검토 결과는 `data/game-db/review/latest.json`과 `latest.md`에 저장합니다. 원본은 `data/game-db/snapshots/`, 계산기용 중간 결과는 `data/game-db/derived/`에 보관합니다. 해시가 다른 스냅샷이나 누락된 테이블을 외부 자료로 대체하지 않습니다. -채보 본문은 별도 게임 SUS 파일이며, 과거 이벤트 일정·배율은 DB에 없는 수동 기록입니다. DB 등록과 채보 갱신 방법 및 남은 예외는 [데이터 원본 안내](docs/game-data-source.md)를 참고하세요. +채보 본문은 별도 게임 SUS 파일입니다. 신규 이벤트 일정·배율은 검증한 게임 API 응답에서 생성하며, 과거 수동 이벤트 기록은 기존 출처를 유지합니다. DB 등록과 채보 갱신 방법 및 남은 예외는 [데이터 원본 안내](docs/game-data-source.md)를 참고하세요. 특별 버전명이나 번역 이름은 `data/card-overrides.csv`에서 관리합니다. diff --git a/UPDATES.md b/UPDATES.md index dd3ca77..c80d71f 100644 --- a/UPDATES.md +++ b/UPDATES.md @@ -4,6 +4,12 @@ updatedAt: 2026-09-29T00:00:00Z ## 2026년 9월 29일 +### 두근두근 블루 스플래시! 이벤트 + +`NEW` 9월 29일 12시부터 10월 5일 19시 59분 59초까지 진행되는 이벤트의 PT·스코어 계산을 지원합니다. 마린·코요리·코보·벨즈의 멤버·신규 카드·개화 보너스와 Kyapi, BAKU LOVE CHEMISTRY, PROPOSE, Play Dice!의 대응 카드 스코어 보너스를 반영했습니다. + +`FIX` 이벤트 탐색의 저등급 후보 카드를 현재 이벤트의 보너스 멤버 기준으로 선택합니다. + ### 채보에서 분석 점수 확인 `NEW` 배치 분석 결과에 레인·노트 너비·플릭·롱노트 연결을 표시하는 채보를 추가했습니다. 채보를 가리키거나 터치하면 해당 시각의 누적 평균 점수·최고 점수·최고점 유지 확률을 확인할 수 있습니다. 액티브 미발동 설정을 반영하며, 시간 확대와 스페셜 구간 이동을 지원합니다. diff --git a/data/game-events/2026-09-29.json b/data/game-events/2026-09-29.json new file mode 100644 index 0000000..84c174a --- /dev/null +++ b/data/game-events/2026-09-29.json @@ -0,0 +1,2900 @@ +{ + "schemaVersion": 1, + "source": { + "kind": "android-event-api-memory", + "package": "game.qualiarts.hololive.dreams.com", + "appVersion": "1.2.0", + "locale": "kor", + "messageType": "rpc.api.EventListEventInfoResponse.EventInfo", + "api": "rpc.api.Event/ListEventInfo", + "capturedAt": "2026-09-29T14:25:20.484782+00:00", + "rawMemoryExportSha256": "34d8fa8485aa3d7ef60648afc5ecaa3db2a28a0e7105b46827756a864fb1b838", + "descriptorFileSha256": "51e6ffad87242d64621c19d7eb4017a4e17fc32e9c5ce7b31a3b70ead76bdd81", + "libil2cppSha256": "f3c02abd02f8d0c5263e2181e712bf495fa83c80568df8c29414a61809c4fffe", + "method": "Reconstructed decoded protobuf objects retained in the running game; not a raw network capture.", + "excludedAccountFields": [ + "isNew", + "isNoti", + "marathonInfo.marathonChapters[].score" + ] + }, + "units": { + "timestamps": "Unix milliseconds; 0 means unset", + "rates": "per mille (1000 = 1; 100 = 10%)" + }, + "events": [ + { + "eventId": "event_mission-area03-release-260929", + "type": 3, + "name": "이벤트 미션", + "startTime": 1790629200000, + "endTime": 1792958399000, + "exchangeEndTime": 0, + "logoAssetId": "", + "backgroundAssetId": "img_event_mission_bg_area03-release-260929", + "missionGroupId": "mission_grp-area03-release-260929", + "viewConditionGroupId": "", + "unlockConditionGroupId": "", + "marathonInfo": null + }, + { + "eventId": "event_mission-beginner_mission", + "type": 3, + "name": "초보자 미션", + "startTime": 946652400000, + "endTime": 0, + "exchangeEndTime": 0, + "logoAssetId": "", + "backgroundAssetId": "img_event_mission_bg_001", + "missionGroupId": "mission_grp-beginner_mission", + "viewConditionGroupId": "cd-event_mission-beginner_mission-close", + "unlockConditionGroupId": "", + "marathonInfo": null + }, + { + "eventId": "event_mission-comeback-260929", + "type": 3, + "name": "이벤트 미션", + "startTime": 1790647200000, + "endTime": 1792353599000, + "exchangeEndTime": 0, + "logoAssetId": "", + "backgroundAssetId": "img_event_mission_bg_comeback-260929", + "missionGroupId": "mission_grp-comeback-260929", + "viewConditionGroupId": "cd-comeback_user", + "unlockConditionGroupId": "", + "marathonInfo": null + }, + { + "eventId": "marathon_event-normal-005", + "type": 1, + "name": "스코어 챌린지 이벤트", + "startTime": 1790650800000, + "endTime": 1791197999000, + "exchangeEndTime": 1791716399000, + "logoAssetId": "img_marathon_event_normal_logo-005-01", + "backgroundAssetId": "img_marathon_event_normal_bg-005-01", + "missionGroupId": "", + "viewConditionGroupId": "", + "unlockConditionGroupId": "cd-marathon_event", + "marathonInfo": { + "exchangeBoothGroupId": "exchange_booth_group-marathon_event-normal-005", + "aggregationStartTime": 1791212400000, + "aggregatedRankingRevealStartTime": 1791255600000, + "marathonChapters": [ + { + "id": "marathon_event-normal-005-chapter-01", + "chapterNumber": 1, + "characterId": "", + "endTime": 1791197999000, + "scoreName": "이벤트 Pt", + "scoreIconAssetId": "event-pt-03", + "marathonEventBadgeItemId": "item-event_badge-marathon_event-normal-005-chapter-01", + "missionGroupId": "mission_grp-marathon_event-normal-005-chapter-01", + "marathonScoreRewards": [], + "eventStoryChapterId": "", + "autoPlayStoryId": "", + "backgroundAssetId": "img_marathon_event_normal_top-005-01", + "bgmAssetId": "bgm_sys_event-portal-default", + "rankingRevealStartTime": 1791255600000, + "marathonScoreRankingRankRewards": [], + "marathonMusicHighestScoreRankingRankRewards": [ + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0357", + "endRank": 100, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0357-dream", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0357", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0357-diamond", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0357", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0357-platinum", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0357", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0357-gold", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0357", + "endRank": 20000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0357-silver", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0357", + "endRank": 30000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0357-bronze", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0358", + "endRank": 100, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0358-dream", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0358", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0358-diamond", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0358", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0358-platinum", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0358", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0358-gold", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0358", + "endRank": 20000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0358-silver", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0358", + "endRank": 30000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0358-bronze", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0413", + "endRank": 100, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0413-dream", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0413", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0413-diamond", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0413", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0413-platinum", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0413", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0413-gold", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0413", + "endRank": 20000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0413-silver", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0413", + "endRank": 30000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0413-bronze", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0548", + "endRank": 100, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0548-dream", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0548", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0548-diamond", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0548", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0548-platinum", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0548", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0548-gold", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0548", + "endRank": 20000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0548-silver", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01", + "musicId": "m0548", + "endRank": 30000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-normal-005-chapter-01-m0548-bronze", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonTotalMusicHighestScoreRankingRewards": [ + { + "groupId": "total_music_highest_score_reward-marathon_event-normal-005-chapter-01", + "endRank": 500, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-total_music_highest_score_reward-marathon_event-normal-005-chapter-01-dream", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 800 + }, + { + "resourceType": 3, + "resourceId": "item-event_badge-marathon_event-normal-005-chapter-01", + "quantity": 80000 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "total_music_highest_score_reward-marathon_event-normal-005-chapter-01", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-total_music_highest_score_reward-marathon_event-normal-005-chapter-01-diamond", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 700 + }, + { + "resourceType": 3, + "resourceId": "item-event_badge-marathon_event-normal-005-chapter-01", + "quantity": 70000 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "total_music_highest_score_reward-marathon_event-normal-005-chapter-01", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-total_music_highest_score_reward-marathon_event-normal-005-chapter-01-platinum", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 600 + }, + { + "resourceType": 3, + "resourceId": "item-event_badge-marathon_event-normal-005-chapter-01", + "quantity": 60000 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "total_music_highest_score_reward-marathon_event-normal-005-chapter-01", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-total_music_highest_score_reward-marathon_event-normal-005-chapter-01-gold", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 500 + }, + { + "resourceType": 3, + "resourceId": "item-event_badge-marathon_event-normal-005-chapter-01", + "quantity": 40000 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "total_music_highest_score_reward-marathon_event-normal-005-chapter-01", + "endRank": 25000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-total_music_highest_score_reward-marathon_event-normal-005-chapter-01-silver", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 400 + }, + { + "resourceType": 3, + "resourceId": "item-event_badge-marathon_event-normal-005-chapter-01", + "quantity": 30000 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "total_music_highest_score_reward-marathon_event-normal-005-chapter-01", + "endRank": 50000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-total_music_highest_score_reward-marathon_event-normal-005-chapter-01-bronze", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 300 + }, + { + "resourceType": 3, + "resourceId": "item-event_badge-marathon_event-normal-005-chapter-01", + "quantity": 20000 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonMusicScoreBonuses": [ + { + "groupId": "music_score_bonus-marathon_event-normal-005-chapter-01", + "musicId": "m0548", + "number": 1, + "characterId": "", + "cardId": "card-00023-5-uniq-0085-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "scoreUpPermilUp": 100 + }, + { + "groupId": "music_score_bonus-marathon_event-normal-005-chapter-01", + "musicId": "m0413", + "number": 1, + "characterId": "", + "cardId": "card-00037-5-uniq-0086-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "scoreUpPermilUp": 100 + }, + { + "groupId": "music_score_bonus-marathon_event-normal-005-chapter-01", + "musicId": "m0358", + "number": 1, + "characterId": "", + "cardId": "card-03009-5-uniq-0088-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "scoreUpPermilUp": 100 + }, + { + "groupId": "music_score_bonus-marathon_event-normal-005-chapter-01", + "musicId": "m0357", + "number": 1, + "characterId": "", + "cardId": "card-04012-5-uniq-0087-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "scoreUpPermilUp": 100 + } + ], + "marathonMiniGameMarathonScoreBonuses": [ + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 1, + "cardId": "card-00023-5-uniq-0085-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 2, + "cardId": "card-00037-5-uniq-0086-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 3, + "cardId": "card-03009-5-uniq-0088-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 4, + "cardId": "card-04012-5-uniq-0087-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + } + ], + "marathonLiveMarathonScoreBonuses": [ + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 1, + "characterId": "chr-00023", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 300 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 2, + "characterId": "chr-00037", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 300 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 3, + "characterId": "chr-03009", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 300 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 4, + "characterId": "chr-04012", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 300 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 5, + "characterId": "", + "cardId": "card-00023-5-uniq-0085-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 300 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 6, + "characterId": "", + "cardId": "card-00037-5-uniq-0086-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 300 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 7, + "characterId": "", + "cardId": "card-03009-5-uniq-0088-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 300 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 8, + "characterId": "", + "cardId": "card-04012-5-uniq-0087-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 300 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 9, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 10, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 11, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 12, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 13, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 30 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 14, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 60 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 15, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 70 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 16, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 80 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 17, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 90 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 18, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 100 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 19, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 150 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 20, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 180 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 21, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 220 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 22, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 260 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-normal-005-chapter-01", + "number": 23, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 300 + } + ], + "marathonMiniGameMarathonScoreRates": [ + { + "groupId": "mini_game_marathon_score_rate-marathon_event-normal-005", + "miniGameType": 1, + "marathonScorePermilMultiply": 1300, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-normal-005", + "miniGameType": 2, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-normal-005", + "miniGameType": 3, + "marathonScorePermilMultiply": 44, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-normal-005", + "miniGameType": 4, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-normal-005", + "miniGameType": 5, + "marathonScorePermilMultiply": 300, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-normal-005", + "miniGameType": 6, + "marathonScorePermilMultiply": 2700, + "bonusPermilUp": 500 + } + ] + } + ], + "isMarathonScoreRankingDisable": true, + "tipsHintType": 2101 + } + }, + { + "eventId": "marathon_event-relay-002", + "type": 2, + "name": "스포트라이트 이벤트", + "startTime": 1789815600000, + "endTime": 1790506799000, + "exchangeEndTime": 1791025199000, + "logoAssetId": "img_marathon_event_relay_logo-002-01", + "backgroundAssetId": "img_marathon_event_relay_bg-002-00", + "missionGroupId": "mission_grp-marathon_event-relay-002", + "viewConditionGroupId": "", + "unlockConditionGroupId": "cd-marathon_event", + "marathonInfo": { + "exchangeBoothGroupId": "exchange_booth_group-marathon_event-relay-002", + "aggregationStartTime": 1790521200000, + "aggregatedRankingRevealStartTime": 1790564400000, + "marathonChapters": [ + { + "id": "marathon_event-relay-002-chapter-01", + "chapterNumber": 1, + "characterId": "chr-00004", + "endTime": 1789988399000, + "scoreName": "이벤트 Pt", + "scoreIconAssetId": "event-pt-02", + "marathonEventBadgeItemId": "item-event_badge-marathon_event-relay-002-chapter-01", + "missionGroupId": "mission_grp-marathon_event-relay-002-chapter-01", + "marathonScoreRewards": [ + { + "score": 60000, + "rewards": [ + { + "resourceType": 24, + "resourceId": "story-marathon_event-relay-002-chapter-01-02", + "quantity": 1 + } + ] + } + ], + "eventStoryChapterId": "event_story_chapter-marathon_event-relay-002-chapter-01", + "autoPlayStoryId": "story-marathon_event-relay-002-chapter-01-01", + "backgroundAssetId": "img_marathon_event_relay_top-002-01", + "bgmAssetId": "music_short_m0349", + "rankingRevealStartTime": 1790046000000, + "marathonScoreRankingRankRewards": [ + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "endRank": 500, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-dream", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 700 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-diamond", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 650 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-platinum", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 500 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-gold", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 400 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "endRank": 25000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-silver", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 250 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "endRank": 50000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-bronze", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 150 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonMusicHighestScoreRankingRankRewards": [ + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "musicId": "m0349", + "endRank": 100, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-m0349-dream", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "musicId": "m0349", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-m0349-diamond", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "musicId": "m0349", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-m0349-platinum", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "musicId": "m0349", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-m0349-gold", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "musicId": "m0349", + "endRank": 20000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-m0349-silver", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01", + "musicId": "m0349", + "endRank": 30000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-01-m0349-bronze", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonTotalMusicHighestScoreRankingRewards": [], + "marathonMusicScoreBonuses": [ + { + "groupId": "music_score_bonus-marathon_event-relay-002-chapter-01", + "musicId": "m0349", + "number": 1, + "characterId": "", + "cardId": "card-00004-5-uniq-0081-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "scoreUpPermilUp": 100 + } + ], + "marathonMiniGameMarathonScoreBonuses": [ + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 1, + "cardId": "card-00004-5-uniq-0081-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 2, + "cardId": "card-00035-5-uniq-0082-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 3, + "cardId": "card-03005-5-uniq-0084-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 4, + "cardId": "card-04013-5-uniq-0083-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + } + ], + "marathonLiveMarathonScoreBonuses": [ + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 1, + "characterId": "chr-00004", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 2, + "characterId": "", + "cardId": "card-00004-5-uniq-0081-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 3, + "characterId": "", + "cardId": "card-00035-5-uniq-0082-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 4, + "characterId": "", + "cardId": "card-03005-5-uniq-0084-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 5, + "characterId": "", + "cardId": "card-04013-5-uniq-0083-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 6, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 7, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 8, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 9, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 10, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 30 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 11, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 60 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 12, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 70 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 13, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 80 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 14, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 90 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 15, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 100 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 16, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 150 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 17, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 180 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 18, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 220 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 19, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 260 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-01", + "number": 20, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 300 + } + ], + "marathonMiniGameMarathonScoreRates": [ + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 1, + "marathonScorePermilMultiply": 1300, + "bonusPermilUp": 500 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 2, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 3, + "marathonScorePermilMultiply": 44, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 4, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 5, + "marathonScorePermilMultiply": 300, + "bonusPermilUp": 0 + } + ] + }, + { + "id": "marathon_event-relay-002-chapter-02", + "chapterNumber": 2, + "characterId": "chr-04013", + "endTime": 1790161199000, + "scoreName": "이벤트 Pt", + "scoreIconAssetId": "event-pt-02", + "marathonEventBadgeItemId": "item-event_badge-marathon_event-relay-002-chapter-02", + "missionGroupId": "mission_grp-marathon_event-relay-002-chapter-02", + "marathonScoreRewards": [ + { + "score": 60000, + "rewards": [ + { + "resourceType": 24, + "resourceId": "story-marathon_event-relay-002-chapter-02-02", + "quantity": 1 + } + ] + } + ], + "eventStoryChapterId": "event_story_chapter-marathon_event-relay-002-chapter-02", + "autoPlayStoryId": "story-marathon_event-relay-002-chapter-02-01", + "backgroundAssetId": "img_marathon_event_relay_top-002-02", + "bgmAssetId": "music_short_m0351", + "rankingRevealStartTime": 1790218800000, + "marathonScoreRankingRankRewards": [ + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "endRank": 500, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-dream", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 700 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-diamond", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 650 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-platinum", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 500 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-gold", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 400 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "endRank": 25000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-silver", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 250 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "endRank": 50000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-bronze", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 150 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonMusicHighestScoreRankingRankRewards": [ + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "musicId": "m0351", + "endRank": 100, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-m0351-dream", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "musicId": "m0351", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-m0351-diamond", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "musicId": "m0351", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-m0351-platinum", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "musicId": "m0351", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-m0351-gold", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "musicId": "m0351", + "endRank": 20000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-m0351-silver", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02", + "musicId": "m0351", + "endRank": 30000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-02-m0351-bronze", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonTotalMusicHighestScoreRankingRewards": [], + "marathonMusicScoreBonuses": [ + { + "groupId": "music_score_bonus-marathon_event-relay-002-chapter-02", + "musicId": "m0351", + "number": 1, + "characterId": "", + "cardId": "card-04013-5-uniq-0083-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "scoreUpPermilUp": 100 + } + ], + "marathonMiniGameMarathonScoreBonuses": [ + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 1, + "cardId": "card-00004-5-uniq-0081-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 2, + "cardId": "card-00035-5-uniq-0082-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 3, + "cardId": "card-03005-5-uniq-0084-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 4, + "cardId": "card-04013-5-uniq-0083-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + } + ], + "marathonLiveMarathonScoreBonuses": [ + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 1, + "characterId": "chr-04013", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 2, + "characterId": "", + "cardId": "card-00004-5-uniq-0081-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 3, + "characterId": "", + "cardId": "card-00035-5-uniq-0082-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 4, + "characterId": "", + "cardId": "card-03005-5-uniq-0084-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 5, + "characterId": "", + "cardId": "card-04013-5-uniq-0083-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 6, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 7, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 8, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 9, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 10, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 30 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 11, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 60 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 12, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 70 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 13, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 80 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 14, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 90 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 15, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 100 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 16, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 150 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 17, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 180 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 18, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 220 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 19, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 260 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-02", + "number": 20, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 300 + } + ], + "marathonMiniGameMarathonScoreRates": [ + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 1, + "marathonScorePermilMultiply": 1300, + "bonusPermilUp": 500 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 2, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 3, + "marathonScorePermilMultiply": 44, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 4, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 5, + "marathonScorePermilMultiply": 300, + "bonusPermilUp": 0 + } + ] + }, + { + "id": "marathon_event-relay-002-chapter-03", + "chapterNumber": 3, + "characterId": "chr-00035", + "endTime": 1790333999000, + "scoreName": "이벤트 Pt", + "scoreIconAssetId": "event-pt-02", + "marathonEventBadgeItemId": "item-event_badge-marathon_event-relay-002-chapter-03", + "missionGroupId": "mission_grp-marathon_event-relay-002-chapter-03", + "marathonScoreRewards": [ + { + "score": 60000, + "rewards": [ + { + "resourceType": 24, + "resourceId": "story-marathon_event-relay-002-chapter-03-02", + "quantity": 1 + } + ] + } + ], + "eventStoryChapterId": "event_story_chapter-marathon_event-relay-002-chapter-03", + "autoPlayStoryId": "story-marathon_event-relay-002-chapter-03-01", + "backgroundAssetId": "img_marathon_event_relay_top-002-03", + "bgmAssetId": "music_short_m0350", + "rankingRevealStartTime": 1790391600000, + "marathonScoreRankingRankRewards": [ + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "endRank": 500, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-dream", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 700 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-diamond", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 650 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-platinum", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 500 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-gold", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 400 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "endRank": 25000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-silver", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 250 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "endRank": 50000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-bronze", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 150 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonMusicHighestScoreRankingRankRewards": [ + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "musicId": "m0350", + "endRank": 100, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-m0350-dream", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "musicId": "m0350", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-m0350-diamond", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "musicId": "m0350", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-m0350-platinum", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "musicId": "m0350", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-m0350-gold", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "musicId": "m0350", + "endRank": 20000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-m0350-silver", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03", + "musicId": "m0350", + "endRank": 30000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-03-m0350-bronze", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonTotalMusicHighestScoreRankingRewards": [], + "marathonMusicScoreBonuses": [ + { + "groupId": "music_score_bonus-marathon_event-relay-002-chapter-03", + "musicId": "m0350", + "number": 1, + "characterId": "", + "cardId": "card-00035-5-uniq-0082-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "scoreUpPermilUp": 100 + } + ], + "marathonMiniGameMarathonScoreBonuses": [ + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 1, + "cardId": "card-00004-5-uniq-0081-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 2, + "cardId": "card-00035-5-uniq-0082-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 3, + "cardId": "card-03005-5-uniq-0084-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 4, + "cardId": "card-04013-5-uniq-0083-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + } + ], + "marathonLiveMarathonScoreBonuses": [ + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 1, + "characterId": "chr-00035", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 2, + "characterId": "", + "cardId": "card-00004-5-uniq-0081-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 3, + "characterId": "", + "cardId": "card-00035-5-uniq-0082-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 4, + "characterId": "", + "cardId": "card-03005-5-uniq-0084-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 5, + "characterId": "", + "cardId": "card-04013-5-uniq-0083-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 6, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 7, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 8, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 9, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 10, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 30 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 11, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 60 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 12, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 70 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 13, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 80 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 14, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 90 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 15, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 100 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 16, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 150 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 17, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 180 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 18, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 220 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 19, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 260 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-03", + "number": 20, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 300 + } + ], + "marathonMiniGameMarathonScoreRates": [ + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 1, + "marathonScorePermilMultiply": 1300, + "bonusPermilUp": 500 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 2, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 3, + "marathonScorePermilMultiply": 44, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 4, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 5, + "marathonScorePermilMultiply": 300, + "bonusPermilUp": 0 + } + ] + }, + { + "id": "marathon_event-relay-002-chapter-04", + "chapterNumber": 4, + "characterId": "chr-03005", + "endTime": 1790506799000, + "scoreName": "이벤트 Pt", + "scoreIconAssetId": "event-pt-02", + "marathonEventBadgeItemId": "item-event_badge-marathon_event-relay-002-chapter-04", + "missionGroupId": "mission_grp-marathon_event-relay-002-chapter-04", + "marathonScoreRewards": [ + { + "score": 60000, + "rewards": [ + { + "resourceType": 24, + "resourceId": "story-marathon_event-relay-002-chapter-04-02", + "quantity": 1 + } + ] + } + ], + "eventStoryChapterId": "event_story_chapter-marathon_event-relay-002-chapter-04", + "autoPlayStoryId": "story-marathon_event-relay-002-chapter-04-01", + "backgroundAssetId": "img_marathon_event_relay_top-002-04", + "bgmAssetId": "music_short_m0352", + "rankingRevealStartTime": 1790564400000, + "marathonScoreRankingRankRewards": [ + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "endRank": 500, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-dream", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 700 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-diamond", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 650 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-platinum", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 500 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-gold", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 400 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "endRank": 25000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-silver", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 250 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "endRank": 50000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-marathon_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-bronze", + "quantity": 1 + }, + { + "resourceType": 1001, + "resourceId": "", + "quantity": 150 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonMusicHighestScoreRankingRankRewards": [ + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "musicId": "m0352", + "endRank": 100, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-m0352-dream", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-dream" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "musicId": "m0352", + "endRank": 1000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-m0352-diamond", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-diamond" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "musicId": "m0352", + "endRank": 5000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-m0352-platinum", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-platinum" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "musicId": "m0352", + "endRank": 10000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-m0352-gold", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-gold" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "musicId": "m0352", + "endRank": 20000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-m0352-silver", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-silver" + }, + { + "groupId": "music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04", + "musicId": "m0352", + "endRank": 30000, + "rewards": [ + { + "resourceType": 11, + "resourceId": "emblem-music_highest_score_ranking_rank_reward-marathon_event-relay-002-chapter-04-m0352-bronze", + "quantity": 1 + } + ], + "marathonRankingGradeId": "marathon_ranking_grade-bronze" + } + ], + "marathonTotalMusicHighestScoreRankingRewards": [], + "marathonMusicScoreBonuses": [ + { + "groupId": "music_score_bonus-marathon_event-relay-002-chapter-04", + "musicId": "m0352", + "number": 1, + "characterId": "", + "cardId": "card-03005-5-uniq-0084-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "scoreUpPermilUp": 100 + } + ], + "marathonMiniGameMarathonScoreBonuses": [ + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 1, + "cardId": "card-00004-5-uniq-0081-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 2, + "cardId": "card-00035-5-uniq-0082-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 3, + "cardId": "card-03005-5-uniq-0084-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + }, + { + "groupId": "mini_game_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 4, + "cardId": "card-04013-5-uniq-0083-00", + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 200 + } + ], + "marathonLiveMarathonScoreBonuses": [ + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 1, + "characterId": "chr-03005", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 2, + "characterId": "", + "cardId": "card-00004-5-uniq-0081-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 3, + "characterId": "", + "cardId": "card-00035-5-uniq-0082-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 4, + "characterId": "", + "cardId": "card-03005-5-uniq-0084-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 5, + "characterId": "", + "cardId": "card-04013-5-uniq-0083-00", + "cardAttributeType": 0, + "cardRarity": 0, + "cardPotentialUpgradeCount": 0, + "marathonScoreQuantityUpPermilUp": 500 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 6, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 7, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 10 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 8, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 9, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 20 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 10, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 3, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 30 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 11, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 60 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 12, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 70 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 13, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 80 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 14, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 90 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 15, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 4, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 100 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 16, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 1, + "marathonScoreQuantityUpPermilUp": 150 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 17, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 2, + "marathonScoreQuantityUpPermilUp": 180 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 18, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 3, + "marathonScoreQuantityUpPermilUp": 220 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 19, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 4, + "marathonScoreQuantityUpPermilUp": 260 + }, + { + "groupId": "live_marathon_score_bonus-marathon_event-relay-002-chapter-04", + "number": 20, + "characterId": "", + "cardId": "", + "cardAttributeType": 0, + "cardRarity": 5, + "cardPotentialUpgradeCount": 5, + "marathonScoreQuantityUpPermilUp": 300 + } + ], + "marathonMiniGameMarathonScoreRates": [ + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 1, + "marathonScorePermilMultiply": 1300, + "bonusPermilUp": 500 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 2, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 3, + "marathonScorePermilMultiply": 44, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 4, + "marathonScorePermilMultiply": 600, + "bonusPermilUp": 0 + }, + { + "groupId": "mini_game_marathon_score_rate-marathon_event-relay-002", + "miniGameType": 5, + "marathonScorePermilMultiply": 300, + "bonusPermilUp": 0 + } + ] + } + ], + "isMarathonScoreRankingDisable": false, + "tipsHintType": 2102 + } + } + ] +} diff --git a/data/game-events/current.json b/data/game-events/current.json new file mode 100644 index 0000000..a7b6211 --- /dev/null +++ b/data/game-events/current.json @@ -0,0 +1,5 @@ +{ + "file": "2026-09-29.json", + "sha256": "dbb57a74aa28f1c5684c5dc6f2d45788e8e608011e72aef65db238b148788407", + "eventIds": ["marathon_event-normal-005"] +} diff --git a/docs/game-data-source.md b/docs/game-data-source.md index f6d6086..7e073ef 100644 --- a/docs/game-data-source.md +++ b/docs/game-data-source.md @@ -25,7 +25,7 @@ | --- | --- | | 카드·스킬·보드·메모리·업적·한국어 문자열·악곡 메타데이터 | 현재 게임 DB. 영어·일본어 외부 번역을 가져오지 않음 | | 채보 본문·레인·노트 시각·점수 분모 | 게임 SUS 파일. DB의 난이도·노트 수·계수와 교차 검증. 외부 계산기 채보나 점수 참고표를 생성 입력으로 사용하지 않음 | -| 과거 이벤트 기간·배율 | `src/lib/data/events.ts`의 기존 수동 기록. 당시 외부 출처 주석을 유지. 현재 DB에서 이벤트별 설정을 찾지 못함. 앱의 EventListEventInfoResponse에 일정·특효 필드가 존재하나 실제 응답은 아직 미수집 | +| 과거 이벤트 기간·배율 | `src/lib/data/events.ts`의 기존 수동 기록. 당시 외부 출처 주석을 유지. 현재 DB에서 이벤트별 설정을 찾지 못함. 기존 기록의 기간·배율은 그대로 보존 | | 카드 별칭·표시명 | `data/card-overrides.csv`의 사용자 편집 설정 | 이번 전환에서 기존 200곡/800채보를 로컬 게임 파일로 다시 생성하고, 공식 게임 CDN의 Octo revision 93에서 신규·누락 9곡의 SUS 36개를 확보했습니다. 현재 공개된 209곡/836채보를 생성했습니다. 아직 공개되지 않은 2곡은 DB 스냅샷에만 보관합니다. @@ -36,3 +36,11 @@ 기존 외부 점수 참고표와 달랐던 m0337(Pretty Guardian Matsulimit Zero)의 분모는 공식 게임 CDN revision 93에서 재확인했습니다. Hard는 544300 → 539500, Expert는 874750 → 884700이며, 같은 노트 수라도 비가시·제어점 가중치가 포함되는 분모는 별도로 검증해야 합니다. 검증용 게임 SUS는 scripts/fixtures/game-sus/에 보관합니다. 이벤트 설정의 DB·CDN 조사 범위와 서버 API 스키마 확인 결과는 [이벤트 설정 원본 조사](research/event-config-source-2026-09-29.md)를 참고합니다. CDN 목록은 조사했지만 모든 번들 내부를 검사한 것은 아닙니다. + +## 게임 API 이벤트 반영 + +신규 이벤트의 직접 원본은 `data/game-events/2026-09-29.json`이다. 실제 앱이 받은 이벤트 응답을 메모리에서 추출·검증하고 계정별 필드를 제외했다. 마스터 DB 및 과거 수동 이벤트 기록과 출처를 구분한다. + +`data/game-events/current.json`에서 적용할 이벤트 ID와 원본 파일의 SHA-256을 지정한 뒤 `npm run data:collect-events`를 실행한다. 검증한 일정·라이브 Pt·과제곡 스코어 보너스를 `src/lib/data/events-api.json`으로 생성하며 이벤트명은 DB의 포스터 이름으로 확인한다. 기존 PT·스코어 화면은 이 파일을 읽는다. 지원하지 않는 배율 조건이나 여러 챕터가 있으면 변환을 중단한다. + +현재 적용 대상은 `marathon_event-normal-005`이다. 직전 릴레이 이벤트는 수동 기록을 유지하고, 미니게임 환산 계수와 보너스는 API 원본에 보관한다. 이 명령은 네트워크 수집이나 마스터 DB 갱신을 실행하지 않는다. diff --git a/docs/research/event-api-capture-2026-09-29.md b/docs/research/event-api-capture-2026-09-29.md new file mode 100644 index 0000000..625f08c --- /dev/null +++ b/docs/research/event-api-capture-2026-09-29.md @@ -0,0 +1,91 @@ +# 게임 API 이벤트 일정·배율 확보 (2026-09-29) + +앱 1.2.0이 받은 `rpc.api.Event/ListEventInfo` 응답의 디코딩된 객체를 LDPlayer의 실행 중인 테스트 계정 프로세스에서 읽었다. 네트워크 패킷 원본이 아니라, 실제 응답을 담은 protobuf 객체를 필드별로 재구성한 자료다. DB·CDN 파일이나 외부 위키에서 추정한 값이 아니다. + +보관한 설정: [data/game-events/2026-09-29.json](../../data/game-events/2026-09-29.json). 신규 스코어 챌린지의 일정·라이브 Pt·과제곡 스코어 보너스를 계산기에 적용했다. 미니게임 설정은 원본에 보관하며 기존 라이브 계산 화면의 범위를 확장하지 않는다. + +## 확보 범위와 검증 + +- 이벤트 설정 5개: 신규 스코어 챌린지, 직전 스포트라이트, 신규 지역 미션, 복귀 미션, 초보자 미션. +- 마라톤 2개·챕터 5개의 일정, 라이브 Pt 보너스, 악곡 스코어 보너스, 미니게임 Pt 보너스·환산 계수 및 랭킹 보상 설정을 확보했다. +- 보너스 행 131개, 미니게임 계수 행 26개를 보관했다. 보너스의 카드·멤버·악곡 참조 64개를 해시 검증된 게임 DB와 대조해 모두 확인했다. +- 앱의 protobuf 정의 12종과 모든 추출 필드의 이름·타입·구조를 대조했다. 누락·추가 필드는 없고 직렬화/역직렬화 왕복 검증을 통과했다. +- 별도의 메모리 재읽기에서 이벤트 5개의 전체 내용이 동일했다. 표시용 캐시에 있던 4개의 기본 정보도 원래 응답 객체와 모두 일치했다. 복귀 미션은 표시 조건 `cd-comeback_user`가 있으며 이 계정의 표시용 목록에는 없었다. +- 이벤트 탭의 신규 이벤트 종료 표시 `2026/10/05 19:59`도 추출값과 일치한다. 이 계정에서는 메인 퀘스트 1장 4화 클리어 전 이벤트 상세가 잠겨 있었지만 서버 응답의 설정 객체는 이미 수신되어 있었다. +- 계정별 `isNew`, `isNoti`, 챕터의 현재 `score`를 공개 설정에서 제외했다. 토큰·인증키·계정 식별자·메모리 주소는 포함하지 않는다. 랭킹 보상은 플레이어 목록이 아닌 공통 보상 규칙이다. +- 공개 JSON SHA-256: `dbb57a74aa28f1c5684c5dc6f2d45788e8e608011e72aef65db238b148788407`. + +원본 메모리 추출, 재읽기 및 검증 스크립트는 Git에서 제외된 `data/inspection/android-event-2026-09-29/`에 보관했다. 원본 응답 타입·앱 바이너리·descriptor 해시는 공개 JSON의 `source`에 기록했다. 이 목록은 수신 시점의 설정이며, 과거 모든 이벤트나 향후 서버 변경을 포함한다는 뜻은 아니다. + +## 신규 스코어 챌린지 + +ID: `marathon_event-normal-005`. 아래 시각은 모두 한국 시간(UTC+9)이다. + +| 구분 | 서버 값 | +|---|---| +| 시작 | 2026-09-29 12:00:00 | +| 종료 | 2026-10-05 19:59:59 | +| 교환소 종료 | 2026-10-11 19:59:59 | +| 집계 시작 | 2026-10-06 00:00:00 | +| 집계 랭킹 공개 | 2026-10-06 12:00:00 | + +챕터는 1개다. `isMarathonScoreRankingDisable`은 `true`이며, 악곡별 최고점과 합산 최고점 랭킹 보상은 별도로 존재한다. + +### 라이브 Pt + +원본 단위는 퍼밀(‰)이다. `300`은 `+30%`, `100`은 `+10%`다. + +- 마린·코요리·코보·벨즈의 카드: 멤버 보너스 각 +30%. +- 이번 신규 수영복 카드 4종: 신규 카드 보너스 각 +30% 추가. +- 따라서 해당 신규 카드 한 장은 미개화 기준 +60%, 5회 개화 기준 +90%다. +- 속성만을 조건으로 하는 추가 보너스는 이번 응답에 없다. + +| 등급 | 개화 0 | 개화 1 | 개화 2 | 개화 3 | 개화 4 | 개화 5 | +|---|---:|---:|---:|---:|---:|---:| +| ★3 | 0% | 1% | 1% | 2% | 2% | 3% | +| ★4 | 0% | 6% | 7% | 8% | 9% | 10% | +| ★5 | 0% | 15% | 18% | 22% | 26% | 30% | + +개화 보너스는 해당 단계의 값 하나만 적용한다. 앱의 `CardMarathonLiveEventBonusRatioCache.IsBonusApplicable`에서 희귀도와 양수인 개화 횟수를 동등 비교하고, `CalculateBonusRatioPermil`에서 적용되는 규칙을 합산하는 것을 확인했다. 예를 들어 5회 개화에 1~5단계 값을 누적하지 않는다. + +### 과제곡 스코어 + +아래 대응 카드에 각 곡의 스코어 +10% 규칙이 있다. 곡명은 확보된 DB의 `Music.titleLangId → LangMusic_Kor`로 확인했다. + +| 악곡 | ID | 대응 신규 카드 | +|---|---|---| +| Kyapi | `m0548` | 마린 `card-00023-5-uniq-0085-00` | +| BAKU LOVE CHEMISTRY | `m0413` | 코요리 `card-00037-5-uniq-0086-00` | +| PROPOSE | `m0358` | 코보 `card-03009-5-uniq-0088-00` | +| Play Dice! | `m0357` | 벨즈 `card-04012-5-uniq-0087-00` | + +`PARADISE!`(`m0354`)에 대한 스코어 보너스 규칙은 이 응답에 없다. + +### 미니게임 + +신규 카드 4종 각각에 미니게임 Pt +20% 규칙이 있다. 개화·등급에 따른 미니게임 보너스 행은 없다. + +| 미니게임 | `marathonScorePermilMultiply` 원본 | 계수 ÷ 1000 | `bonusPermilUp` | +|---|---:|---:|---:| +| 줄넘기 | 1300 | 1.3 | 0 | +| 메가 서킷 | 600 | 0.6 | 0 | +| 모아 쿠킹 | 44 | 0.044 | 0 | +| 포카장! | 600 | 0.6 | 0 | +| 어둠 속 추격 | 300 | 0.3 | 0 | +| 스플래시 볼 | 2700 | 2.7 | 500 (+50%) | + +이 표는 서버가 제공한 환산 계수와 보너스다. 미니게임별 점수/시간의 변환·반올림까지 모두 재현한 최종 Pt 공식이라는 의미는 아니다. + +## 직전 스포트라이트 및 기타 일정 + +`marathon_event-relay-002`는 2026-09-19 20:00:00~09-27 19:59:59, 교환소 종료는 10-03 19:59:59다. 챕터별 대상 멤버는 아키로제·시오리·라플라스·아냐 순서이고 종료 시각은 각각 09-21·23·25·27의 19:59:59다. + +챕터 대상 멤버 +50%, 해당 이벤트 신규 카드 4종 각 +50%, 대응 과제곡 +10%, 개화 보너스는 위 표와 동일하다. 미니게임 신규 카드 보너스는 각 +20%이고, 미니게임 추가 +50% 대상은 줄넘기다. 이 이벤트는 스플래시 볼 계수 행이 없다. + +| 미션 | 시작 (한국 시간) | 종료 (한국 시간) | +|---|---|---| +| 신규 지역 미션 `area03-release-260929` | 2026-09-29 06:00:00 | 2026-10-26 04:59:59 | +| 복귀 미션 `comeback-260929` | 2026-09-29 11:00:00 | 2026-10-19 04:59:59 | +| 초보자 미션 | 원본의 기본 시작값 2000-01-01 00:00:00 | 미설정 (`0`) | + +원본은 Unix 밀리초를 사용한다. 종료값은 초 단위 `...59.000`이며 기존 수동 기록의 `...59.999`로 보정하지 않았다. 표시·개방 조건이 있는 미션은 기간에 들어왔다는 사실만으로 모든 계정에서 사용할 수 있다고 판단하면 안 된다. diff --git a/docs/research/event-config-source-2026-09-29.md b/docs/research/event-config-source-2026-09-29.md index 6e9a0b0..1b14da6 100644 --- a/docs/research/event-config-source-2026-09-29.md +++ b/docs/research/event-config-source-2026-09-29.md @@ -8,6 +8,6 @@ - MarathonInfo.MarathonChapter: end_time, marathon_music_score_bonuses, marathon_mini_game_marathon_score_bonuses, marathon_live_marathon_score_bonuses - MarathonMusicScoreBonus: music_id, character_id, card_id, card_attribute_type, card_rarity, card_potential_upgrade_count, score_up_permil_up - MarathonLiveMarathonScoreBonus: character_id, card_id, card_attribute_type, card_rarity, card_potential_upgrade_count, marathon_score_quantity_up_permil_up -- 따라서 앱이 이벤트별 일정과 보너스를 서버 API 응답으로 전달받을 수 있는 구조는 확인했다. 실제 응답의 현재 값은 아직 수집하지 않았다. CDN/DB 부재를 이유로 외부 위키가 필수라고 볼 근거는 없다. +- 이후 실행 중인 앱의 실제 응답 객체에서 이벤트 설정 5개와 마라톤 챕터 5개의 일정·배율을 확보했다. protobuf 필드 대조 및 별도 메모리 재읽기로 검증했다. [확보 결과와 배율](event-api-capture-2026-09-29.md), [공개 설정 JSON](../../data/game-events/2026-09-29.json)을 참조한다. 이벤트 일정·배율의 직접 원본은 게임 API 응답이며, 마스터 DB와 구분한다. -로컬 검증 기록: data/inspection/android-master-2026-09-29/cdn-event-catalog.json 및 event-proto-schema.json. 계정 인증 정보는 사용하지 않았다. +DB/CDN 조사 기록: data/inspection/android-master-2026-09-29/cdn-event-catalog.json 및 event-proto-schema.json. API 메모리 추출·검증 기록: data/inspection/android-event-2026-09-29/. 사용자가 허용한 테스트 계정의 실행 상태에서 읽었으며 인증 정보를 공개 파일에 포함하지 않았다. diff --git a/package.json b/package.json index 9ddc093..b0832d7 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "data:validate-song-score-formula": "node scripts/validate-song-score-formula.mjs", "test:sus-score": "node --test scripts/sus-score-weight.test.mjs scripts/sus-timeline.test.mjs", "data:download-charts": "node scripts/download-sus-charts.mjs --all", - "test:game-db": "node --test scripts/game-db-source.test.mjs" + "test:game-db": "node --test scripts/game-db-source.test.mjs", + "data:collect-events": "node scripts/collect-game-events.mjs" }, "devDependencies": { "@sveltejs/adapter-node": "^5.5.7", diff --git a/scripts/collect-game-events.mjs b/scripts/collect-game-events.mjs new file mode 100644 index 0000000..04a9426 --- /dev/null +++ b/scripts/collect-game-events.mjs @@ -0,0 +1,96 @@ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { prepareGameDbSource, readGameDbText, sha256 } from './game-db-source.mjs'; + +// Explicitly select the event to apply; older manual records retain their provenance. +const root = new URL('../data/game-events/', import.meta.url); +const pointer = JSON.parse(readFileSync(new URL('current.json', root), 'utf8')); +assert.match(pointer.file, /^\d{4}-\d{2}-\d{2}\.json$/); +const bytes = readFileSync(new URL(pointer.file, root)); +assert.equal(sha256(bytes), pointer.sha256, 'Event API snapshot hash mismatch'); +const snapshot = JSON.parse(bytes); +assert.equal(snapshot.schemaVersion, 1); +assert.equal(snapshot.source.kind, 'android-event-api-memory'); +assert.equal(snapshot.source.locale, 'kor'); +assert(pointer.eventIds.length > 0); +assert.equal(new Set(pointer.eventIds).size, pointer.eventIds.length); + +const db = prepareGameDbSource('kor', { review: true }); +const table = name => JSON.parse(readGameDbText(db, name)).map(row => row.data); +const posters = table('Poster.json'); +const posterNames = new Map(table('LangPoster_Kor.json').map(row => [row.id, row.text])); +const cards = new Set(table('Card.json').map(row => row.id)); +const characters = new Set(table('Character.json').map(row => row.id)); +const songs = new Set(table('Music.json').map(row => row.id)); +const iso = value => { + assert(Number.isSafeInteger(value) && value > 0, 'Invalid event timestamp'); + return new Date(value).toISOString(); +}; +function uniform(rows, field) { + const values = new Set(rows.map(row => row[field])); + assert(values.size <= 1, `Calculator cannot represent mixed ${field}`); + const value = values.size ? [...values][0] : 0; + assert(Number.isInteger(value) && value >= 0); + return value / 10; +} +function project(event) { + assert(event && event.marathonInfo, 'Selected event is missing marathon configuration'); + // Relay chapters remain historical records until their exact transition semantics are applied. + assert.equal(event.marathonInfo.marathonChapters.length, 1, 'Only single-chapter events are supported by this projection'); + const chapter = event.marathonInfo.marathonChapters[0]; + assert(event.startTime < event.endTime && event.endTime < event.exchangeEndTime); + assert.equal(chapter.endTime, event.endTime); + const formation = [], featured = [], awakening = {}; + for (const row of chapter.marathonLiveMarathonScoreBonuses) { + assert.equal(row.cardAttributeType, 0, 'Attribute bonus needs an explicit calculator implementation'); + const { characterId, cardId, cardRarity: rarity, cardPotentialUpgradeCount: count } = row; + if (characterId && !cardId && !rarity && !count) { + assert(characters.has(characterId)); formation.push(row); + } else if (cardId && !characterId && !rarity && !count) { + assert(cards.has(cardId)); featured.push(row); + } else { + assert(!characterId && !cardId && Number.isInteger(rarity) && rarity > 0); + assert(Number.isInteger(count) && count > 0 && count <= 5); + awakening[rarity] ??= [0]; + assert.equal(awakening[rarity][count], undefined, 'Duplicate awakening rule'); + awakening[rarity][count] = row.marathonScoreQuantityUpPermilUp / 10; + } + } + for (const values of Object.values(awakening)) { + assert.equal(values.length, 6); + assert(Array.from(values).every(value => Number.isFinite(value) && value >= 0), 'Incomplete awakening rules'); + } + const musicRules = chapter.marathonMusicScoreBonuses; + const challengeSongBonusCardIds = {}; + for (const row of musicRules) { + assert(songs.has(row.musicId) && cards.has(row.cardId)); + assert(!row.characterId && !row.cardAttributeType && !row.cardRarity && !row.cardPotentialUpgradeCount); + (challengeSongBonusCardIds[row.musicId] ??= []).push(row.cardId); + } + assert.equal(new Set(formation.map(row => row.characterId)).size, formation.length); + assert.equal(new Set(featured.map(row => row.cardId)).size, featured.length); + const poster = posters.find(row => row.id === `poster-${chapter.id}`); + return { + id: event.eventId, + name: posterNames.get(poster?.nameLangId) ?? event.name, + startsAt: iso(event.startTime), + endsAt: iso(event.endTime), + exchangeEndsAt: iso(event.exchangeEndTime), + bonusCharacterIds: formation.map(row => row.characterId), + featuredCardIds: featured.map(row => row.cardId), + challengeSongBonusCardIds, + formationBonusPercent: uniform(formation, 'marathonScoreQuantityUpPermilUp'), + featuredCardBonusPercent: uniform(featured, 'marathonScoreQuantityUpPermilUp'), + challengeSongScoreBonusPercent: uniform(musicRules, 'scoreUpPermilUp'), + awakeningBonusPercentByRarity: awakening + }; +} +const output = { + source: { file: `data/game-events/${pointer.file}`, sha256: pointer.sha256, + capturedAt: snapshot.source.capturedAt, masterDataVersion: db.masterDataVersion }, + events: pointer.eventIds.map(id => project(snapshot.events.find(event => event.eventId === id))) +}; +const destination = new URL('../src/lib/data/events-api.json', import.meta.url); +writeFileSync(destination, JSON.stringify(output, null, 2) + '\n'); +console.log(`Generated ${output.events.length} event(s): ${fileURLToPath(destination)}`); diff --git a/src/lib/data/events-api.json b/src/lib/data/events-api.json new file mode 100644 index 0000000..97b8696 --- /dev/null +++ b/src/lib/data/events-api.json @@ -0,0 +1,72 @@ +{ + "source": { + "file": "data/game-events/2026-09-29.json", + "sha256": "dbb57a74aa28f1c5684c5dc6f2d45788e8e608011e72aef65db238b148788407", + "capturedAt": "2026-09-29T14:25:20.484782+00:00", + "masterDataVersion": "546b8e2e37db368c6731e148b88611cef105bbaa66ff567f5c1584711ef979a4" + }, + "events": [ + { + "id": "marathon_event-normal-005", + "name": "두근두근 블루 스플래시!", + "startsAt": "2026-09-29T03:00:00.000Z", + "endsAt": "2026-10-05T10:59:59.000Z", + "exchangeEndsAt": "2026-10-11T10:59:59.000Z", + "bonusCharacterIds": [ + "chr-00023", + "chr-00037", + "chr-03009", + "chr-04012" + ], + "featuredCardIds": [ + "card-00023-5-uniq-0085-00", + "card-00037-5-uniq-0086-00", + "card-03009-5-uniq-0088-00", + "card-04012-5-uniq-0087-00" + ], + "challengeSongBonusCardIds": { + "m0548": [ + "card-00023-5-uniq-0085-00" + ], + "m0413": [ + "card-00037-5-uniq-0086-00" + ], + "m0358": [ + "card-03009-5-uniq-0088-00" + ], + "m0357": [ + "card-04012-5-uniq-0087-00" + ] + }, + "formationBonusPercent": 30, + "featuredCardBonusPercent": 30, + "challengeSongScoreBonusPercent": 10, + "awakeningBonusPercentByRarity": { + "3": [ + 0, + 1, + 1, + 2, + 2, + 3 + ], + "4": [ + 0, + 6, + 7, + 8, + 9, + 10 + ], + "5": [ + 0, + 15, + 18, + 22, + 26, + 30 + ] + } + } + ] +} diff --git a/src/lib/data/events.ts b/src/lib/data/events.ts index f7b0053..8f9cc7d 100644 --- a/src/lib/data/events.ts +++ b/src/lib/data/events.ts @@ -1,4 +1,5 @@ import type { EventDefinition } from '$lib/engine/event-optimization.ts'; +import apiEvents from './events-api.json' with { type: 'json' }; const gamersFeaturedCards = [ 'card-00006-5-uniq-0074-00', @@ -18,10 +19,10 @@ const summerChapters = [ ['유능 감독, 성지순례에 나서다', 'chr-03005', 'm0352', 25, 27] ] as const; -export const events = [ +export const events: readonly EventDefinition[] = [ { - // HolodoriDB supplies the card/song IDs; the public master-data diff does not include - // the live-service schedule, so the official event period and bonus rules live here. + // Historical manual record, preserved with its original provenance. + // New event schedules and rates are projected from captured game API responses below. id: 'marathon_event-normal-003', name: '무인도 잭! 한여름의 서바이벌 데이즈', startsAt: '2026-08-29T03:00:00.000Z', @@ -68,5 +69,6 @@ export const events = [ bonusCharacterIds: [characterId], challengeSongBonusCardIds: { [songId]: [summerFeaturedCards[index]] } })) - } -] as const satisfies readonly EventDefinition[]; + }, + ...apiEvents.events +]; diff --git a/src/lib/engine/event-api.test.ts b/src/lib/engine/event-api.test.ts new file mode 100644 index 0000000..ec4a477 --- /dev/null +++ b/src/lib/engine/event-api.test.ts @@ -0,0 +1,75 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { createHash } from 'node:crypto'; +import { events } from '../data/events.ts'; +import { activeEventAt, eventBonusBreakdown, eventChallengeSongScoreBonusPercent, eventOptimizationCardCandidates } from './event-optimization.ts'; + +const readJson = (relative: string) => JSON.parse(readFileSync(new URL(relative, import.meta.url), 'utf8')); +const pointer = readJson('../../../data/game-events/current.json'); +const rawBytes = readFileSync(new URL(`../../../data/game-events/${pointer.file}`, import.meta.url)); +const snapshot = JSON.parse(rawBytes.toString('utf8')); +const raw = snapshot.events.find((event: { eventId: string }) => event.eventId === 'marathon_event-normal-005'); +const chapter = raw.marathonInfo.marathonChapters[0]; +const current = events.find(event => event.id === raw.eventId)!; +const cards = readJson('../data/cards-summary.json').cards as { id: string; characterId: string; rarity: number }[]; + +test('이벤트 원본 해시와 생성된 일정이 확보한 API 설정과 일치한다', () => { + const generated = readJson('../data/events-api.json'); + assert.equal(createHash('sha256').update(rawBytes).digest('hex'), pointer.sha256); + assert.equal(generated.source.sha256, pointer.sha256); + assert.equal(current.name, '두근두근 블루 스플래시!'); + assert.equal(Date.parse(current.startsAt), raw.startTime); + assert.equal(Date.parse(current.endsAt), raw.endTime); + assert.equal(Date.parse(current.exchangeEndsAt!), raw.exchangeEndTime); + assert.equal(activeEventAt(events, raw.startTime - 1), null); + assert.equal(activeEventAt(events, raw.startTime)?.id, raw.eventId); + assert.equal(activeEventAt(events, raw.endTime)?.id, raw.eventId); + assert.equal(activeEventAt(events, raw.endTime + 1), null); + assert.equal(activeEventAt(events, raw.exchangeEndTime), null); +}); + +test('전체 카드와 개화 0~5의 라이브 보너스가 API 조건별 합계와 일치한다', () => { + for (const card of cards) { + for (let awakening = 0; awakening <= 5; awakening++) { + const expected = chapter.marathonLiveMarathonScoreBonuses + .filter((rule: { characterId: string; cardId: string; cardRarity: number; cardPotentialUpgradeCount: number; cardAttributeType: number }) => { + assert.equal(rule.cardAttributeType, 0); + return (!rule.characterId || rule.characterId === card.characterId) + && (!rule.cardId || rule.cardId === card.id) + && (!rule.cardRarity || rule.cardRarity === card.rarity) + && (!rule.cardPotentialUpgradeCount || rule.cardPotentialUpgradeCount === awakening); + }) + .reduce((sum: number, rule: { marathonScoreQuantityUpPermilUp: number }) => sum + rule.marathonScoreQuantityUpPermilUp, 0) / 10; + assert.equal(eventBonusBreakdown(current, [card], () => awakening).totalPercent, expected, `${card.id}, awakening ${awakening}`); + } + } + const featured = cards.filter(card => current.featuredCardIds.includes(card.id)); + assert.equal(featured.length, 4); + assert.equal(eventBonusBreakdown(current, featured, () => 0).totalPercent, 240); + assert.equal(eventBonusBreakdown(current, featured, () => 5).totalPercent, 360); +}); + +test('네 과제곡의 대응 카드만 스코어 보너스를 받고 PARADISE에는 적용하지 않는다', () => { + assert.deepEqual(Object.keys(current.challengeSongBonusCardIds).sort(), ['m0357', 'm0358', 'm0413', 'm0548']); + for (const songId of [...Object.keys(current.challengeSongBonusCardIds), 'm0354', 'm0349']) { + for (const card of cards) { + const expected = chapter.marathonMusicScoreBonuses + .filter((rule: { musicId: string; cardId: string }) => rule.musicId === songId && rule.cardId === card.id) + .reduce((sum: number, rule: { scoreUpPermilUp: number }) => sum + rule.scoreUpPermilUp, 0) / 10; + assert.equal(eventChallengeSongScoreBonusPercent(current, songId, [card.id]), expected, `${songId}, ${card.id}`); + } + } +}); + +test('현재 이벤트 후보는 신규 대상 멤버로 바뀌고 과거 이벤트의 저등급 카드는 제외한다', () => { + const sample = [ + { id: 'marine-three', characterId: 'chr-00023', rarity: 3 }, + { id: 'aki-three', characterId: 'chr-00004', rarity: 3 }, + { id: 'other-four', characterId: 'other', rarity: 4 }, + { id: 'other-five', characterId: 'other', rarity: 5 } + ]; + assert.deepEqual(eventOptimizationCardCandidates(sample, current).map(card => card.id), ['marine-three', 'other-four', 'other-five']); + const previous = activeEventAt(events, Date.parse('2026-09-19T11:00:00Z'))!; + assert.deepEqual(eventOptimizationCardCandidates(sample, previous).map(card => card.id), ['aki-three', 'other-four', 'other-five']); +}); diff --git a/src/lib/engine/event-optimization.ts b/src/lib/engine/event-optimization.ts index fc7533f..6917057 100644 --- a/src/lib/engine/event-optimization.ts +++ b/src/lib/engine/event-optimization.ts @@ -9,6 +9,7 @@ export type EventDefinition = { name: string; startsAt: string; endsAt: string; + exchangeEndsAt?: string; bonusCharacterIds: readonly string[]; featuredCardIds: readonly string[]; challengeSongBonusCardIds: Readonly>; @@ -37,6 +38,15 @@ export function eventOptimizationCardEligible(card: EventCard, bonusCharacterIds return card.rarity === 5 || card.rarity === 4 || bonusCharacterIds.has(card.characterId); } +/** Returns the event-search pool for the active event or relay chapter. */ +export function eventOptimizationCardCandidates( + cards: readonly T[], + event: Pick | null +): T[] { + const bonusCharacterIds = new Set(event?.bonusCharacterIds ?? []); + return cards.filter((card) => eventOptimizationCardEligible(card, bonusCharacterIds)); +} + export function activeEventAt(events: readonly EventDefinition[], now: number): EventDefinition | null { const event = events.find((event) => Date.parse(event.startsAt) <= now && now <= Date.parse(event.endsAt)); if (!event) return null; diff --git a/src/routes/combination/+page.svelte b/src/routes/combination/+page.svelte index 9569971..fc7818c 100644 --- a/src/routes/combination/+page.svelte +++ b/src/routes/combination/+page.svelte @@ -26,7 +26,7 @@ effectiveActiveProbability, eventBonusBreakdown, eventChallengeSongScoreBonusPercent, - eventOptimizationCardEligible, + eventOptimizationCardCandidates, eventPointIndex, generateAnchoredCombinationCandidates, generateCombinationCandidates, @@ -111,10 +111,7 @@ const REDUCTION_LOCK_OPTIONS = [null, 0, 4, 8, 12] as const; const allCards = cardSummary.cards; const fiveStarCards = allCards.filter((card) => card.rarity === 5); - const eventBonusCharacters = new Set(events.flatMap((event) => [...event.bonusCharacterIds, ...('chapters' in event ? event.chapters.flatMap((chapter) => chapter.bonusCharacterIds) : [])])); - const eligibleCards = eventMode - ? allCards.filter((card) => eventOptimizationCardEligible(card, eventBonusCharacters)) - : fiveStarCards; + let eligibleCards = fiveStarCards; const cardById = new Map(allCards.map((card) => [card.id, card])); const allCharts = exactChartCatalog.charts; const initialReleaseClock = createInitialReleaseClock($page.data?.serverNow); @@ -256,6 +253,9 @@ $: currentEvent = eventMode ? activeEventAt(events, releaseNow) : null; + $: eligibleCards = eventMode + ? eventOptimizationCardCandidates(allCards, currentEvent) + : fiveStarCards; $: songs = Array.from(new Map(charts.map((chart) => [chart.songId, { id: chart.songId, title: chart.title }])).values()); $: if (!songs.some((song) => song.id === selectedSongId)) selectedSongId = songs[0]?.id ?? ''; $: selectedChart = charts.find((chart) => chart.songId === selectedSongId && chart.difficulty === difficulty); @@ -1237,6 +1237,7 @@
{currentEvent.name} {new Date(currentEvent.startsAt).toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' })} ~ {new Date(currentEvent.endsAt).toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' })} (한국 시간) + {#if currentEvent.exchangeEndsAt}교환소 종료: {new Date(currentEvent.exchangeEndsAt).toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' })} (한국 시간){/if} 현재 대상: {currentEvent.bonusCharacterIds.map((id) => leaderMembers.find((card) => card.characterId === id)?.name ?? id).join(', ')} 과제곡: {Object.keys(currentEvent.challengeSongBonusCardIds).map((id) => songs.find((song) => song.id === id)?.title ?? '채보 준비 중').join(', ')} 대상 멤버 1명당 +{currentEvent.formationBonusPercent}% · 신규 카드 추가 +{currentEvent.featuredCardBonusPercent}% · 과제곡 대응 카드 스코어 +{currentEvent.challengeSongScoreBonusPercent}% @@ -1276,7 +1277,7 @@ {/if}
-
01

탐색 조건

{ownedCardsOnly ? (eventMode ? '보유 이벤트 후보 대상' : '보유 5성 대상') : (eventMode ? '5성 + 대상 멤버 전 레어리티' : '5성 전체 대상')}
+
01

탐색 조건

{ownedCardsOnly ? (eventMode ? '보유 이벤트 후보 대상' : '보유 5성 대상') : (eventMode ? '4·5성 + 대상 멤버 전 레어리티' : '5성 전체 대상')}
result = null} />