import { readFileSync, writeFileSync } from 'node:fs'; import { POTIONS } from './lib/data.mjs'; import { prop, codeblock, RUN_LENGTH } from './lib/codeblock.mjs'; import { bootMethods } from './cb/boot.mjs'; import { screensMethods } from './cb/screens.mjs'; import { npcMethods } from './cb/npc.mjs'; import { navigationMethods } from './cb/navigation.mjs'; import { layoutMethods } from './cb/layout.mjs'; import { soulMethods } from './cb/soul.mjs'; import { charSelectMethods } from './cb/charselect.mjs'; import { runMethods } from './cb/run.mjs'; import { deckTurnMethods } from './cb/deckturn.mjs'; import { deckViewMethods } from './cb/deckview.mjs'; import { handMethods } from './cb/hand.mjs'; import { combatMethods } from './cb/combat.mjs'; import { jobMethods } from './cb/jobs.mjs'; import { runEndMethods } from './cb/runend.mjs'; import { renderMethods } from './cb/render.mjs'; import { rewardMethods } from './cb/reward.mjs'; import { itemMethods } from './cb/items.mjs'; import { tooltipMethods } from './cb/tooltip.mjs'; import { mapMethods } from './cb/map.mjs'; import { shopMethods } from './cb/shop.mjs'; import { COMMON_FILE } from './lib/ui-helpers.mjs'; function writeCodeblocks() { const combat = codeblock('SlayDeckController', 'SlayDeckController', [ prop('any', 'DrawPile'), prop('any', 'DiscardPile'), prop('any', 'ExhaustPile'), prop('any', 'Hand'), prop('number', 'Energy', '0'), prop('number', 'MaxEnergy', '3'), prop('number', 'Turn', '0'), prop('number', 'TweenEventId', '0'), prop('number', 'CardHoverTweenId', '0'), prop('number', 'DmgPopSeq', '0'), prop('any', 'EndTurnHandler'), prop('any', 'NewGameHandler'), prop('any', 'WarriorSelectHandler'), prop('any', 'ThiefSelectHandler'), prop('any', 'MageSelectHandler'), prop('any', 'WarriorDeckTabHandler'), prop('any', 'ThiefDeckTabHandler'), prop('any', 'MageDeckTabHandler'), prop('any', 'AscMinusHandler'), prop('any', 'AscPlusHandler'), prop('any', 'JobOpts'), prop('any', 'Jobs'), prop('any', 'JobMeta'), prop('any', 'ClassGroups'), prop('any', 'ClassLineages'), prop('number', 'AscensionLevel', '0'), prop('number', 'AscensionUnlocked', '0'), prop('any', 'StartGameHandler'), prop('any', 'CharBackHandler'), prop('string', 'SelectedClass', '""'), prop('any', 'DrawPileHandler'), prop('any', 'DiscardPileHandler'), prop('any', 'ExhaustPileHandler'), prop('any', 'DeckInspectCloseHandler'), prop('any', 'AllDeckHandler'), prop('any', 'AllDeckCloseHandler'), prop('number', 'SoulPoints', '0'), prop('boolean', 'LobbyBound', 'false'), prop('number', 'LobbyTpTries', '0'), prop('boolean', 'CodexMode', 'false'), prop('any', 'CodexCards'), prop('boolean', 'ClassDeckMode', 'false'), prop('boolean', 'DebugCardPickerMode', 'false'), prop('boolean', 'DebugCtrlDown', 'false'), prop('boolean', 'DebugShiftDown', 'false'), prop('any', 'ClassDeckCards'), prop('string', 'ClassDeckTitle', '""'), prop('string', 'ClassDeckClass', '""'), prop('any', 'SoulUnlocks'), prop('any', 'SoulShopDef'), prop('boolean', 'SoulShopBound', 'false'), prop('string', 'DeckInspectKind', '""'), prop('boolean', 'DeckAllOpen', 'false'), prop('any', 'Cards'), prop('any', 'CardFrames'), prop('any', 'NodeIcons'), prop('any', 'ClassPortraits'), prop('any', 'ClassToFrame'), prop('number', 'PlayerHp', '0'), prop('number', 'PlayerMaxHp', '80'), prop('number', 'PlayerBlock', '0'), prop('number', 'BlockGainMultiplier', '1'), prop('number', 'PlayerDex', '0'), prop('number', 'PlayerThorns', '0'), prop('boolean', 'CombatOver', 'false'), prop('any', 'Monsters'), prop('any', 'Registered'), prop('number', 'TargetIndex', '1'), prop('any', 'RunDeck'), prop('number', 'Gold', '0'), prop('number', 'Floor', '0'), prop('number', 'RunLength', String(RUN_LENGTH)), prop('any', 'RewardChoices'), prop('boolean', 'RunActive', 'false'), prop('any', 'Enemies'), prop('any', 'MapNodes'), prop('any', 'MapStart'), prop('string', 'CurrentNodeId', '""'), prop('string', 'CurrentEnemyId', '""'), prop('any', 'ShopChoices'), prop('any', 'ShopBought'), prop('any', 'Relics'), prop('any', 'RunRelics'), prop('any', 'RelicPool'), prop('string', 'ShopRelic', '""'), prop('boolean', 'ShopRelicBought', 'false'), prop('number', 'DragSlot', '0'), prop('number', 'DragTargetIndex', '0'), prop('boolean', 'FxBusy', 'false'), prop('boolean', 'TurnBusy', 'false'), prop('number', 'PlayerStr', '0'), prop('number', 'PlayerWeak', '0'), prop('number', 'PlayerVuln', '0'), prop('number', 'PlayerIntangible', '0'), prop('any', 'PlayerPowers'), prop('any', 'Potions'), prop('any', 'RunPotions'), prop('number', 'PotionSlots', String(POTIONS.baseSlots)), prop('string', 'ShopPotion', '""'), prop('boolean', 'ShopPotionBought', 'false'), prop('number', 'CardsDrawnThisCombat', '0'), prop('boolean', 'HandCostZeroThisTurn', 'false'), prop('boolean', 'DrawDisabledThisTurn', 'false'), prop('number', 'SkillCostReductionThisTurn', '0'), prop('any', 'SkillSlyOnPlayCards'), prop('any', 'TurnSkillSlyCards'), prop('boolean', 'ShivFirstDamageBonusUsed', 'false'), prop('any', 'CombatCardCostReduction'), prop('number', 'ActiveAttackDamageVsWeakMultiplier', '1'), prop('number', 'DrawDamageThisTurn', '0'), prop('number', 'DrawPoisonThisTurn', '0'), prop('boolean', 'ShivAoeThisCombat', 'false'), prop('number', 'PoisonApplicationsThisCombat', '0'), prop('number', 'EnemyStrengthLossThisTurn', '0'), prop('number', 'ActiveKillReward', '0'), prop('number', 'BonusRewardScreens', '0'), prop('number', 'FightAttackCount', '0'), prop('number', 'TurnAttackCardsPlayed', '0'), prop('number', 'TurnCardsPlayedThisTurn', '0'), prop('number', 'DamageDealtThisTurn', '0'), prop('number', 'TurnDiscardedCards', '0'), prop('boolean', 'FirstHpLossDone', 'false'), prop('number', 'ClayBlockNext', '0'), prop('number', 'PotionMenuSlot', '0'), prop('number', 'Depth', '0'), prop('any', 'VisitedNodes'), prop('boolean', 'ChestOpened', 'false'), prop('string', 'PlayerJob', '""'), prop('number', 'DiscardSelectRemaining', '0'), prop('number', 'DiscardSelectTotal', '0'), prop('number', 'DiscardPostShiv', '0'), prop('number', 'DiscardShivPerPick', '0'), prop('number', 'DiscardPostDraw', '0'), prop('number', 'DiscardDrawPerPick', '0'), prop('boolean', 'RetainSelectActive', 'false'), prop('boolean', 'ReserveSelectActive', 'false'), prop('number', 'NextTurnBlock', '0'), prop('number', 'NextTurnDraw', '0'), prop('boolean', 'NextTurnKeepBlock', 'false'), prop('number', 'NextTurnAttackMultiplier', '1'), prop('number', 'TurnAttackMultiplier', '1'), prop('string', 'NextTurnSelectPrompt', '""'), prop('number', 'NextTurnSelectCopies', '0'), prop('boolean', 'NextSkillCostZero', 'false'), prop('number', 'NextSkillRepeatCount', '0'), prop('any', 'NextTurnAddCards'), ], [ ...bootMethods, ...screensMethods, ...npcMethods, ...navigationMethods, ...soulMethods, ...charSelectMethods, ...runMethods, ...deckTurnMethods, ...deckViewMethods, ...handMethods, ...combatMethods, ...jobMethods, ...runEndMethods, ...renderMethods, ...layoutMethods, ...rewardMethods, ...itemMethods, ...tooltipMethods, ...mapMethods, ...shopMethods, ]); for (const m of combat.ContentProto.Json.Methods) { if (m.ExecSpace === 0) m.ExecSpace = 6; // 기본은 ClientOnly(6), 서버 RPC(Server=1·Client=2) 명시값은 보존 } writeFileSync('RootDesk/MyDesk/SlayDeckController.codeblock', JSON.stringify(combat, null, 2), 'utf8'); } function patchCommon() { const common = JSON.parse(readFileSync(COMMON_FILE, 'utf8')); const entity = common.ContentProto.Entities.find((e) => e.path === '/common'); entity.componentNames = 'script.SlayDeckController'; entity.jsonString['@components'] = [ { '@type': 'script.SlayDeckController', Enable: true, Energy: 0, MaxEnergy: 3, Turn: 0, TweenEventId: 0 }, ]; JSON.parse(JSON.stringify(common)); writeFileSync(COMMON_FILE, JSON.stringify(common, null, 2), 'utf8'); } writeCodeblocks(); patchCommon(); console.log('SlayDeckController/common 생성 완료 (UI는 메이커 저작 — 생성기 미접근).');