From f33a5507dbf87f3ba0c4f4de553da609874968d6 Mon Sep 17 00:00:00 2001 From: gahusb Date: Wed, 10 Jun 2026 02:15:40 +0900 Subject: [PATCH] =?UTF-8?q?fix(combat):=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B0=98=EC=98=81=20=E2=80=94=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=EC=A0=84=EC=9D=B4=20=EC=8B=A4=ED=96=89?= =?UTF-8?q?=EA=B3=B5=EA=B0=84=20=EC=97=90=EB=9F=AC=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?+=20=EC=8A=AC=EB=A1=AF=20=EC=A2=8C=ED=91=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ReviveMonsterEntity/KillMonster의 StateComponent:ChangeState 제거 (client 실행공간에서 LEA-3022 InvalidExecSpace 발생) → SetVisible 기반 표시/숨김으로 대체 - monster-slots.json 좌표를 맵 우측 몬스터 무리 위로 조정 - 메이커 플레이테스트로 전체 전투 루프(등록·타겟·공격·적턴·처치·승리·보상) 무에러 확인 Co-Authored-By: Claude Opus 4.8 (1M context) --- RootDesk/MyDesk/SlayDeckController.codeblock | 6 +++--- data/monster-slots.json | 8 ++++---- tools/deck/gen-slaydeck.mjs | 11 ++--------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/RootDesk/MyDesk/SlayDeckController.codeblock b/RootDesk/MyDesk/SlayDeckController.codeblock index d760939..6266788 100644 --- a/RootDesk/MyDesk/SlayDeckController.codeblock +++ b/RootDesk/MyDesk/SlayDeckController.codeblock @@ -382,7 +382,7 @@ "Name": null }, "Arguments": [], - "Code": "self.PlayerMaxHp = 80\nself.PlayerHp = self.PlayerMaxHp\nself.Gold = 0\nself.Floor = 1\nself.RunLength = 3\nself.RunDeck = { \"Strike\", \"Strike\", \"Strike\", \"Strike\", \"Strike\", \"Defend\", \"Defend\", \"Defend\", \"Defend\", \"Bash\" }\nself.RunActive = true\nself.RunRelics = {}\nself.Relics = {\n\tironHeart = { name = \"강철 심장\", desc = \"전투 시작 시 방어도 +6\", hook = \"combatStart\", effect = \"block\", value = 6 },\n\tenergyCore = { name = \"에너지 코어\", desc = \"턴 시작 시 에너지 +1\", hook = \"turnStart\", effect = \"energy\", value = 1 },\n\tvampire = { name = \"흡혈 송곳니\", desc = \"공격 카드 사용 시 HP +1\", hook = \"cardPlayed\", effect = \"healOnAttack\", value = 1 },\n\tgoldIdol = { name = \"황금 우상\", desc = \"전투 승리 시 골드 +10\", hook = \"combatReward\", effect = \"gold\", value = 10 },\n}\nself.RelicPool = { \"energyCore\", \"vampire\", \"goldIdol\" }\nself.Enemies = {\n\tslime = { name = \"슬라임\", maxHp = 45, intents = { { kind = \"Attack\", value = 10 }, { kind = \"Attack\", value = 6 }, { kind = \"Defend\", value = 8 } } },\n\tslime_elite = { name = \"정예 슬라임\", maxHp = 70, intents = { { kind = \"Attack\", value = 14 }, { kind = \"Attack\", value = 8 }, { kind = \"Defend\", value = 10 } } },\n\tslime_boss = { name = \"슬라임 킹\", maxHp = 120, intents = { { kind = \"Attack\", value = 18 }, { kind = \"Defend\", value = 12 }, { kind = \"Attack\", value = 10 }, { kind = \"Attack\", value = 22 } } },\n\torange_mushroom = { name = \"주황버섯\", maxHp = 16, intents = { { kind = \"Attack\", value = 5 }, { kind = \"Defend\", value = 4 }, { kind = \"Attack\", value = 7 } } },\n\tblue_mushroom = { name = \"파란버섯\", maxHp = 22, intents = { { kind = \"Attack\", value = 8 }, { kind = \"Attack\", value = 4 } } },\n}\nself.MapNodes = {\n\tA = { type = \"combat\", enemy = \"slime\", row = 1, col = -1, next = { \"C\", \"D\" } },\n\tB = { type = \"combat\", enemy = \"slime\", row = 1, col = 1, next = { \"C\", \"D\" } },\n\tC = { type = \"rest\", row = 2, col = -1, next = { \"E\", \"F\" } },\n\tD = { type = \"shop\", row = 2, col = 1, next = { \"E\", \"F\" } },\n\tE = { type = \"elite\", enemy = \"slime_elite\", row = 3, col = -1, next = { \"BOSS\" } },\n\tF = { type = \"combat\", enemy = \"slime\", row = 3, col = 1, next = { \"BOSS\" } },\n\tBOSS = { type = \"boss\", enemy = \"slime_boss\", row = 4, col = 0, next = { } },\n}\nself.MapStart = { \"A\", \"B\" }\nself.SlotPos = { { x = -480, y = 300 }, { x = -160, y = 300 }, { x = 160, y = 300 }, { x = 480, y = 300 } }\nself.CurrentNodeId = \"\"\nself.CurrentEnemyId = \"\"\nself:BindButtons()\nself:AddRelic(\"ironHeart\")\nself:ShowMap()", + "Code": "self.PlayerMaxHp = 80\nself.PlayerHp = self.PlayerMaxHp\nself.Gold = 0\nself.Floor = 1\nself.RunLength = 3\nself.RunDeck = { \"Strike\", \"Strike\", \"Strike\", \"Strike\", \"Strike\", \"Defend\", \"Defend\", \"Defend\", \"Defend\", \"Bash\" }\nself.RunActive = true\nself.RunRelics = {}\nself.Relics = {\n\tironHeart = { name = \"강철 심장\", desc = \"전투 시작 시 방어도 +6\", hook = \"combatStart\", effect = \"block\", value = 6 },\n\tenergyCore = { name = \"에너지 코어\", desc = \"턴 시작 시 에너지 +1\", hook = \"turnStart\", effect = \"energy\", value = 1 },\n\tvampire = { name = \"흡혈 송곳니\", desc = \"공격 카드 사용 시 HP +1\", hook = \"cardPlayed\", effect = \"healOnAttack\", value = 1 },\n\tgoldIdol = { name = \"황금 우상\", desc = \"전투 승리 시 골드 +10\", hook = \"combatReward\", effect = \"gold\", value = 10 },\n}\nself.RelicPool = { \"energyCore\", \"vampire\", \"goldIdol\" }\nself.Enemies = {\n\tslime = { name = \"슬라임\", maxHp = 45, intents = { { kind = \"Attack\", value = 10 }, { kind = \"Attack\", value = 6 }, { kind = \"Defend\", value = 8 } } },\n\tslime_elite = { name = \"정예 슬라임\", maxHp = 70, intents = { { kind = \"Attack\", value = 14 }, { kind = \"Attack\", value = 8 }, { kind = \"Defend\", value = 10 } } },\n\tslime_boss = { name = \"슬라임 킹\", maxHp = 120, intents = { { kind = \"Attack\", value = 18 }, { kind = \"Defend\", value = 12 }, { kind = \"Attack\", value = 10 }, { kind = \"Attack\", value = 22 } } },\n\torange_mushroom = { name = \"주황버섯\", maxHp = 16, intents = { { kind = \"Attack\", value = 5 }, { kind = \"Defend\", value = 4 }, { kind = \"Attack\", value = 7 } } },\n\tblue_mushroom = { name = \"파란버섯\", maxHp = 22, intents = { { kind = \"Attack\", value = 8 }, { kind = \"Attack\", value = 4 } } },\n}\nself.MapNodes = {\n\tA = { type = \"combat\", enemy = \"slime\", row = 1, col = -1, next = { \"C\", \"D\" } },\n\tB = { type = \"combat\", enemy = \"slime\", row = 1, col = 1, next = { \"C\", \"D\" } },\n\tC = { type = \"rest\", row = 2, col = -1, next = { \"E\", \"F\" } },\n\tD = { type = \"shop\", row = 2, col = 1, next = { \"E\", \"F\" } },\n\tE = { type = \"elite\", enemy = \"slime_elite\", row = 3, col = -1, next = { \"BOSS\" } },\n\tF = { type = \"combat\", enemy = \"slime\", row = 3, col = 1, next = { \"BOSS\" } },\n\tBOSS = { type = \"boss\", enemy = \"slime_boss\", row = 4, col = 0, next = { } },\n}\nself.MapStart = { \"A\", \"B\" }\nself.SlotPos = { { x = 430, y = 140 }, { x = 600, y = 140 }, { x = 770, y = 140 }, { x = 900, y = 140 } }\nself.CurrentNodeId = \"\"\nself.CurrentEnemyId = \"\"\nself:BindButtons()\nself:AddRelic(\"ironHeart\")\nself:ShowMap()", "Scope": 2, "ExecSpace": 6, "Attributes": [], @@ -465,7 +465,7 @@ "Name": "monster" } ], - "Code": "if monster == nil or not isvalid(monster) then\n\treturn\nend\nmonster:SetEnable(true)\nmonster:SetVisible(true)\nif monster.StateComponent ~= nil then\n\tmonster.StateComponent:ChangeState(\"IDLE\")\nend", + "Code": "if monster == nil or not isvalid(monster) then\n\treturn\nend\nmonster:SetEnable(true)\nmonster:SetVisible(true)", "Scope": 2, "ExecSpace": 6, "Attributes": [], @@ -805,7 +805,7 @@ "Name": "slot" } ], - "Code": "local m = self.Monsters[slot]\nif m == nil then\n\treturn\nend\nm.alive = false\nif m.entity ~= nil and isvalid(m.entity) then\n\tif m.entity.StateComponent ~= nil then\n\t\tm.entity.StateComponent:ChangeState(\"DEAD\")\n\tend\n\tlocal ent = m.entity\n\t_TimerService:SetTimerOnce(function() if isvalid(ent) then ent:SetVisible(false) end end, 0.6)\nend\nself:SetEntityEnabled(\"/ui/DefaultGroup/CombatHud/MonsterSlot\" .. tostring(slot), false)\nfor i = 1, #self.Monsters do\n\tif self.Monsters[i].alive == true then self.TargetIndex = i; break end\nend", + "Code": "local m = self.Monsters[slot]\nif m == nil then\n\treturn\nend\nm.alive = false\nif m.entity ~= nil and isvalid(m.entity) then\n\tm.entity:SetVisible(false)\nend\nself:SetEntityEnabled(\"/ui/DefaultGroup/CombatHud/MonsterSlot\" .. tostring(slot), false)\nfor i = 1, #self.Monsters do\n\tif self.Monsters[i].alive == true then self.TargetIndex = i; break end\nend", "Scope": 2, "ExecSpace": 6, "Attributes": [], diff --git a/data/monster-slots.json b/data/monster-slots.json index 494d402..8bbc468 100644 --- a/data/monster-slots.json +++ b/data/monster-slots.json @@ -1,6 +1,6 @@ [ - { "x": -480, "y": 300 }, - { "x": -160, "y": 300 }, - { "x": 160, "y": 300 }, - { "x": 480, "y": 300 } + { "x": 430, "y": 140 }, + { "x": 600, "y": 140 }, + { "x": 770, "y": 140 }, + { "x": 900, "y": 140 } ] diff --git a/tools/deck/gen-slaydeck.mjs b/tools/deck/gen-slaydeck.mjs index 04c053b..1e4349c 100644 --- a/tools/deck/gen-slaydeck.mjs +++ b/tools/deck/gen-slaydeck.mjs @@ -1173,10 +1173,7 @@ self.TargetIndex = 1`), return end monster:SetEnable(true) -monster:SetVisible(true) -if monster.StateComponent ~= nil then - monster.StateComponent:ChangeState("IDLE") -end`, [{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'monster' }]), +monster:SetVisible(true)`, [{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'monster' }]), method('Shuffle', `if list == nil then \treturn end @@ -1414,11 +1411,7 @@ if m == nil then end m.alive = false if m.entity ~= nil and isvalid(m.entity) then - if m.entity.StateComponent ~= nil then - m.entity.StateComponent:ChangeState("DEAD") - end - local ent = m.entity - _TimerService:SetTimerOnce(function() if isvalid(ent) then ent:SetVisible(false) end end, 0.6) + m.entity:SetVisible(false) end self:SetEntityEnabled("/ui/DefaultGroup/CombatHud/MonsterSlot" .. tostring(slot), false) for i = 1, #self.Monsters do