diff --git a/RootDesk/MyDesk/SlayDeckController.codeblock b/RootDesk/MyDesk/SlayDeckController.codeblock index 39bca2e..cfde1d9 100644 --- a/RootDesk/MyDesk/SlayDeckController.codeblock +++ b/RootDesk/MyDesk/SlayDeckController.codeblock @@ -218,20 +218,6 @@ "Attributes": [], "Name": "TargetIndex" }, - { - "Type": "any", - "DefaultValue": "nil", - "SyncDirection": 0, - "Attributes": [], - "Name": "SlotPos" - }, - { - "Type": "any", - "DefaultValue": "nil", - "SyncDirection": 0, - "Attributes": [], - "Name": "ActiveSlotPos" - }, { "Type": "any", "DefaultValue": "nil", @@ -527,7 +513,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 = { combat = { { x = 430, y = 140 }, { x = 600, y = 140 }, { x = 770, y = 140 }, { x = 900, y = 140 } }, elite = { { x = 430, y = 160 }, { x = 650, y = 160 }, { x = 850, y = 160 }, { x = 980, y = 160 } }, boss = { { x = 520, y = 200 }, { x = 760, y = 160 }, { x = 940, y = 150 }, { x = 1040, y = 150 } } }\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\tpig = { name = \"돼지\", maxHp = 18, intents = { { kind = \"Attack\", value = 6 }, { kind = \"Defend\", value = 3 } } },\n\tgreen_mushroom = { name = \"초록버섯\", maxHp = 20, intents = { { kind = \"Attack\", value = 7 }, { kind = \"Attack\", value = 4 } } },\n\tmushmom = { name = \"머쉬맘\", maxHp = 75, intents = { { kind = \"Attack\", value = 14 }, { kind = \"Defend\", value = 10 }, { kind = \"Attack\", value = 9 } } },\n\tmodified_snail = { name = \"변형된 달팽이\", maxHp = 60, intents = { { kind = \"Attack\", value = 12 }, { kind = \"Attack\", value = 7 }, { kind = \"Defend\", value = 8 } } },\n\tking_slime = { name = \"킹 슬라임\", maxHp = 130, intents = { { kind = \"Attack\", value = 18 }, { kind = \"Defend\", value = 14 }, { kind = \"Attack\", value = 12 }, { kind = \"Attack\", value = 24 } } },\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.CurrentNodeId = \"\"\nself.CurrentEnemyId = \"\"\nself:BindButtons()\nself:AddRelic(\"ironHeart\")\nself:ShowMap()", "Scope": 2, "ExecSpace": 6, "Attributes": [], @@ -594,7 +580,7 @@ "Name": null }, "Arguments": [], - "Code": "self.Monsters = {}\nlocal g = \"combat\"\nlocal node = self.MapNodes[self.CurrentNodeId]\nif node ~= nil and node.type ~= nil then g = node.type end\nself.ActiveSlotPos = self.SlotPos[g]\nlocal reg = self.Registered or {}\nfor i = 1, #reg do\n\tif reg[i].entity ~= nil and isvalid(reg[i].entity) then\n\t\treg[i].entity:SetVisible(false)\n\tend\nend\nlocal list = {}\nfor i = 1, #reg do\n\tlocal r = reg[i]\n\tif r.entity ~= nil and isvalid(r.entity) and r.group == g then\n\t\tlocal x = 0\n\t\tif r.entity.TransformComponent ~= nil then\n\t\t\tx = r.entity.TransformComponent.WorldPosition.x\n\t\tend\n\t\ttable.insert(list, { entity = r.entity, enemyId = r.enemyId, x = x })\n\tend\nend\ntable.sort(list, function(a, b) return a.x < b.x end)\nlocal mult = 1 + (self.Floor - 1) * 0.6\nlocal n = #list\nif n > 4 then n = 4 end\nfor i = 1, n do\n\tlocal item = list[i]\n\tlocal e = self.Enemies[item.enemyId]\n\tif e == nil then e = { name = item.enemyId, maxHp = 10, intents = { { kind = \"Attack\", value = 5 } } } end\n\tlocal intents = {}\n\tfor k = 1, #e.intents do\n\t\tintents[k] = { kind = e.intents[k].kind, value = math.floor(e.intents[k].value * mult) }\n\tend\n\tlocal maxHp = math.floor(e.maxHp * mult)\n\tself.Monsters[i] = { entity = item.entity, enemyId = item.enemyId, name = e.name,\n\t\thp = maxHp, maxHp = maxHp, block = 0, intents = intents, intentIdx = 1, alive = true, slot = i }\n\tself:ReviveMonsterEntity(item.entity)\n\tself:PositionMonsterSlot(i)\nend\nself.TargetIndex = 1", + "Code": "self.Monsters = {}\nlocal g = \"combat\"\nlocal node = self.MapNodes[self.CurrentNodeId]\nif node ~= nil and node.type ~= nil then g = node.type end\nlocal reg = self.Registered or {}\nfor i = 1, #reg do\n\tif reg[i].entity ~= nil and isvalid(reg[i].entity) then\n\t\treg[i].entity:SetVisible(false)\n\tend\nend\nlocal list = {}\nfor i = 1, #reg do\n\tlocal r = reg[i]\n\tif r.entity ~= nil and isvalid(r.entity) and r.group == g then\n\t\tlocal x = 0\n\t\tif r.entity.TransformComponent ~= nil then\n\t\t\tx = r.entity.TransformComponent.WorldPosition.x\n\t\tend\n\t\ttable.insert(list, { entity = r.entity, enemyId = r.enemyId, x = x })\n\tend\nend\ntable.sort(list, function(a, b) return a.x < b.x end)\nlocal mult = 1 + (self.Floor - 1) * 0.6\nlocal n = #list\nif n > 4 then n = 4 end\nfor i = 1, n do\n\tlocal item = list[i]\n\tlocal e = self.Enemies[item.enemyId]\n\tif e == nil then e = { name = item.enemyId, maxHp = 10, intents = { { kind = \"Attack\", value = 5 } } } end\n\tlocal intents = {}\n\tfor k = 1, #e.intents do\n\t\tintents[k] = { kind = e.intents[k].kind, value = math.floor(e.intents[k].value * mult) }\n\tend\n\tlocal maxHp = math.floor(e.maxHp * mult)\n\tself.Monsters[i] = { entity = item.entity, enemyId = item.enemyId, name = e.name,\n\t\thp = maxHp, maxHp = maxHp, block = 0, intents = intents, intentIdx = 1, alive = true, slot = i }\n\tself:ReviveMonsterEntity(item.entity)\n\tself:PositionMonsterSlot(i)\nend\nself.TargetIndex = 1", "Scope": 2, "ExecSpace": 6, "Attributes": [], @@ -1281,7 +1267,7 @@ "Name": "slot" } ], - "Code": "local sp = self.ActiveSlotPos\nif sp == nil or sp[slot] == nil then\n\treturn\nend\nlocal e = _EntityService:GetEntityByPath(\"/ui/DefaultGroup/CombatHud/MonsterSlot\" .. tostring(slot))\nif e ~= nil and e.UITransformComponent ~= nil then\n\te.UITransformComponent.anchoredPosition = Vector2(sp[slot].x, sp[slot].y)\nend", + "Code": "local m = self.Monsters[slot]\nif m == nil or m.entity == nil or not isvalid(m.entity) then\n\treturn\nend\nlocal tr = m.entity.TransformComponent\nif tr == nil then\n\treturn\nend\nlocal wp = tr.WorldPosition\nlocal screen = _UILogic:WorldToScreenPosition(Vector2(wp.x, wp.y + 1.4))\nlocal uipos = _UILogic:ScreenToUIPosition(screen)\nlocal e = _EntityService:GetEntityByPath(\"/ui/DefaultGroup/CombatHud/MonsterSlot\" .. tostring(slot))\nif e ~= nil and e.UITransformComponent ~= nil then\n\te.UITransformComponent.anchoredPosition = uipos\nend", "Scope": 2, "ExecSpace": 6, "Attributes": [], diff --git a/data/enemies.json b/data/enemies.json index 47263c6..ab47c11 100644 --- a/data/enemies.json +++ b/data/enemies.json @@ -44,6 +44,50 @@ { "kind": "Attack", "value": 8 }, { "kind": "Attack", "value": 4 } ] + }, + "pig": { + "name": "돼지", + "maxHp": 18, + "intents": [ + { "kind": "Attack", "value": 6 }, + { "kind": "Defend", "value": 3 } + ] + }, + "green_mushroom": { + "name": "초록버섯", + "maxHp": 20, + "intents": [ + { "kind": "Attack", "value": 7 }, + { "kind": "Attack", "value": 4 } + ] + }, + "mushmom": { + "name": "머쉬맘", + "maxHp": 75, + "intents": [ + { "kind": "Attack", "value": 14 }, + { "kind": "Defend", "value": 10 }, + { "kind": "Attack", "value": 9 } + ] + }, + "modified_snail": { + "name": "변형된 달팽이", + "maxHp": 60, + "intents": [ + { "kind": "Attack", "value": 12 }, + { "kind": "Attack", "value": 7 }, + { "kind": "Defend", "value": 8 } + ] + }, + "king_slime": { + "name": "킹 슬라임", + "maxHp": 130, + "intents": [ + { "kind": "Attack", "value": 18 }, + { "kind": "Defend", "value": 14 }, + { "kind": "Attack", "value": 12 }, + { "kind": "Attack", "value": 24 } + ] } }, "activeEnemy": "slime", diff --git a/data/monster-slots.json b/data/monster-slots.json deleted file mode 100644 index 378dd10..0000000 --- a/data/monster-slots.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "combat": [ - { "x": 430, "y": 140 }, - { "x": 600, "y": 140 }, - { "x": 770, "y": 140 }, - { "x": 900, "y": 140 } - ], - "elite": [ - { "x": 430, "y": 160 }, - { "x": 650, "y": 160 }, - { "x": 850, "y": 160 }, - { "x": 980, "y": 160 } - ], - "boss": [ - { "x": 520, "y": 200 }, - { "x": 760, "y": 160 }, - { "x": 940, "y": 150 }, - { "x": 1040, "y": 150 } - ] -} diff --git a/map/map01.map b/map/map01.map index a9a8ef4..2941431 100644 --- a/map/map01.map +++ b/map/map01.map @@ -6652,7 +6652,7 @@ { "@type": "script.CombatMonster", "Enable": true, - "EnemyId": "orange_mushroom", + "EnemyId": "pig", "Group": "combat" } ], @@ -6794,12 +6794,442 @@ { "@type": "script.CombatMonster", "Enable": true, - "EnemyId": "orange_mushroom", + "EnemyId": "green_mushroom", "Group": "combat" } ], "@version": 1 } + }, + { + "id": "b289e720-40fa-4c28-b5bf-6cd30ddf9c6b", + "path": "/maps/map01/머쉬맘", + "componentNames": "MOD.Core.TransformComponent,MOD.Core.StateAnimationComponent,MOD.Core.SpriteRendererComponent,MOD.Core.RigidbodyComponent,MOD.Core.MovementComponent,MOD.Core.StateComponent,MOD.Core.HitComponent,MOD.Core.DamageSkinSpawnerComponent,script.Monster,script.MonsterAttack,MOD.Core.KinematicbodyComponent,MOD.Core.SideviewbodyComponent,script.CombatMonster", + "jsonString": { + "name": "머쉬맘", + "path": "/maps/map01/머쉬맘", + "nameEditable": true, + "enable": true, + "visible": true, + "localize": false, + "displayOrder": 7, + "pathConstraints": "///", + "revision": 1, + "origin": { + "type": "Model", + "entry_id": "ChaseMonster", + "sub_entity_id": null, + "root_entity_id": "b289e720-40fa-4c28-b5bf-6cd30ddf9c6b", + "replaced_model_id": null + }, + "modelId": "chasemonster", + "@components": [ + { + "@type": "MOD.Core.TransformComponent", + "Position": { + "x": 3, + "y": 0.03499998, + "z": 999.999 + }, + "QuaternionRotation": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "Enable": true + }, + { + "@type": "MOD.Core.StateAnimationComponent", + "ActionSheet": { + "move": "f3bf3c053e444315b83a9663ea85a37f", + "stand": "2688d39a56874f24aa0d46efbf89ff21", + "jump": "2f45374c97224e0cb108241398710a3c", + "attack": "907f4089e0b840a993967c5211af9b89", + "hit": "b771488c84fe437e9707f233c48ec477", + "die": "c03225c35c124bcbaf9ec9299b7d8a1f" + }, + "Enable": true + }, + { + "@type": "MOD.Core.SpriteRendererComponent", + "ActionSheet": {}, + "EndFrameIndex": 0, + "RenderSetting": 1, + "SortingLayer": "MapLayer0", + "SpriteRUID": "2688d39a56874f24aa0d46efbf89ff21", + "StartFrameIndex": 0, + "Enable": true + }, + { + "@type": "MOD.Core.RigidbodyComponent", + "MoveVelocity": { + "x": 0, + "y": 0 + }, + "RealMoveVelocity": { + "x": 0, + "y": 0 + }, + "Enable": true + }, + { + "@type": "MOD.Core.MovementComponent", + "InputSpeed": 1.5, + "JumpForce": 6, + "Enable": true + }, + { + "@type": "MOD.Core.StateComponent", + "IsLegacy": false, + "Enable": true + }, + { + "@type": "MOD.Core.HitComponent", + "BoxSize": { + "x": 1.19, + "y": 1.1 + }, + "ColliderOffset": { + "x": 0.005000055, + "y": 0.55 + }, + "IsLegacy": false, + "Enable": true + }, + { + "@type": "MOD.Core.DamageSkinSpawnerComponent", + "Enable": true + }, + { + "@type": "script.Monster", + "Enable": true, + "IsDead": false + }, + { + "@type": "script.MonsterAttack", + "Enable": true, + "SpriteSize": { + "x": 0, + "y": 0 + }, + "PositionOffset": { + "x": 0, + "y": 0 + } + }, + { + "@type": "MOD.Core.KinematicbodyComponent", + "MoveVelocity": { + "x": 0, + "y": 0 + }, + "Enable": true + }, + { + "@type": "MOD.Core.SideviewbodyComponent", + "MoveVelocity": { + "x": 0, + "y": 0 + }, + "Enable": true + }, + { + "@type": "script.CombatMonster", + "Enable": true, + "EnemyId": "mushmom", + "Group": "elite" + } + ], + "@version": 1 + } + }, + { + "id": "aa4b464c-a4ea-48e7-a475-9015771ca2ef", + "path": "/maps/map01/변형된 달팽이", + "componentNames": "MOD.Core.TransformComponent,MOD.Core.StateAnimationComponent,MOD.Core.SpriteRendererComponent,MOD.Core.RigidbodyComponent,MOD.Core.MovementComponent,MOD.Core.StateComponent,MOD.Core.HitComponent,MOD.Core.DamageSkinSpawnerComponent,script.Monster,script.MonsterAttack,MOD.Core.KinematicbodyComponent,MOD.Core.SideviewbodyComponent,script.CombatMonster", + "jsonString": { + "name": "변형된 달팽이", + "path": "/maps/map01/변형된 달팽이", + "nameEditable": true, + "enable": true, + "visible": true, + "localize": false, + "displayOrder": 8, + "pathConstraints": "///", + "revision": 1, + "origin": { + "type": "Model", + "entry_id": "MoveMonster", + "sub_entity_id": null, + "root_entity_id": "aa4b464c-a4ea-48e7-a475-9015771ca2ef", + "replaced_model_id": null + }, + "modelId": "movemonster", + "@components": [ + { + "@type": "MOD.Core.TransformComponent", + "Position": { + "x": 5, + "y": 0.03499998, + "z": 999.999 + }, + "QuaternionRotation": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "Enable": true + }, + { + "@type": "MOD.Core.StateAnimationComponent", + "ActionSheet": { + "stand": "be8403cdd1534522ac060ec8497371cd", + "move": "1e24c789979b4ababce55b34861ace25", + "attack": "11eb051bbc134831851e8764befc155e", + "skill": "220a397a05f4460395721591cdcc023d", + "hit": "7200391494bb4dea8109202bb3e2cf47", + "die": "c5d61976c96c4130903ab227c7bf72ce" + }, + "Enable": true + }, + { + "@type": "MOD.Core.SpriteRendererComponent", + "ActionSheet": {}, + "EndFrameIndex": 0, + "RenderSetting": 1, + "SortingLayer": "MapLayer0", + "SpriteRUID": "1e24c789979b4ababce55b34861ace25", + "StartFrameIndex": 0, + "Enable": true + }, + { + "@type": "MOD.Core.RigidbodyComponent", + "MoveVelocity": { + "x": 0, + "y": 0 + }, + "RealMoveVelocity": { + "x": 0, + "y": 0 + }, + "Enable": true + }, + { + "@type": "MOD.Core.MovementComponent", + "InputSpeed": 1, + "JumpForce": 0, + "Enable": true + }, + { + "@type": "MOD.Core.StateComponent", + "IsLegacy": false, + "Enable": true + }, + { + "@type": "MOD.Core.HitComponent", + "BoxSize": { + "x": 1.42, + "y": 1.42 + }, + "ColliderOffset": { + "x": -0.0500000119, + "y": 0.69 + }, + "IsLegacy": false, + "Enable": true + }, + { + "@type": "MOD.Core.DamageSkinSpawnerComponent", + "Enable": true + }, + { + "@type": "script.Monster", + "Enable": true, + "IsDead": false + }, + { + "@type": "script.MonsterAttack", + "Enable": true, + "SpriteSize": { + "x": 0, + "y": 0 + }, + "PositionOffset": { + "x": 0, + "y": 0 + } + }, + { + "@type": "MOD.Core.KinematicbodyComponent", + "MoveVelocity": { + "x": 0, + "y": 0 + }, + "Enable": true + }, + { + "@type": "MOD.Core.SideviewbodyComponent", + "MoveVelocity": { + "x": 0, + "y": 0 + }, + "Enable": true + }, + { + "@type": "script.CombatMonster", + "Enable": true, + "EnemyId": "modified_snail", + "Group": "elite" + } + ], + "@version": 1 + } + }, + { + "id": "5d2a7707-d1d2-4f89-b87f-86786f4a305e", + "path": "/maps/map01/monster-2326", + "componentNames": "MOD.Core.TransformComponent,MOD.Core.StateAnimationComponent,MOD.Core.SpriteRendererComponent,MOD.Core.RigidbodyComponent,MOD.Core.MovementComponent,MOD.Core.StateComponent,MOD.Core.HitComponent,MOD.Core.DamageSkinSpawnerComponent,script.Monster,script.MonsterAttack,MOD.Core.KinematicbodyComponent,MOD.Core.SideviewbodyComponent,script.CombatMonster", + "jsonString": { + "name": "monster-2326", + "path": "/maps/map01/monster-2326", + "nameEditable": true, + "enable": true, + "visible": true, + "localize": false, + "displayOrder": 9, + "pathConstraints": "///", + "revision": 1, + "origin": { + "type": "Model", + "entry_id": "ChaseMonster", + "sub_entity_id": null, + "root_entity_id": "5d2a7707-d1d2-4f89-b87f-86786f4a305e", + "replaced_model_id": null + }, + "modelId": "chasemonster", + "@components": [ + { + "@type": "MOD.Core.TransformComponent", + "Position": { + "x": 4, + "y": 0.03499998, + "z": 999.999 + }, + "QuaternionRotation": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "Enable": true + }, + { + "@type": "MOD.Core.StateAnimationComponent", + "ActionSheet": { + "move": "297ad7bed08046e8a4a0bb47fed0f7d1", + "stand": "6401ef4c5ccb4269a5c97831fa8fd329", + "jump": "e4ae46df71794213b2a5432906ed1f85", + "attack": "763ee1a40786483f9671435c1a8e8537", + "skill": "bf6150842fff4f4aa0f3e8e97b574e59", + "hit": "a660f29769d74e4b81c49d9435a7f5b2", + "die": "193c446258954f9cb7dfddab7b498bd8" + }, + "Enable": true + }, + { + "@type": "MOD.Core.SpriteRendererComponent", + "ActionSheet": {}, + "EndFrameIndex": 0, + "RenderSetting": 1, + "SortingLayer": "MapLayer0", + "SpriteRUID": "6401ef4c5ccb4269a5c97831fa8fd329", + "StartFrameIndex": 0, + "Enable": true + }, + { + "@type": "MOD.Core.RigidbodyComponent", + "MoveVelocity": { + "x": 0, + "y": 0 + }, + "RealMoveVelocity": { + "x": 0, + "y": 0 + }, + "Enable": true + }, + { + "@type": "MOD.Core.MovementComponent", + "InputSpeed": 1.5, + "JumpForce": 6, + "Enable": true + }, + { + "@type": "MOD.Core.StateComponent", + "IsLegacy": false, + "Enable": true + }, + { + "@type": "MOD.Core.HitComponent", + "BoxSize": { + "x": 2.19, + "y": 1.39 + }, + "ColliderOffset": { + "x": 0.335000038, + "y": 0.695 + }, + "IsLegacy": false, + "Enable": true + }, + { + "@type": "MOD.Core.DamageSkinSpawnerComponent", + "Enable": true + }, + { + "@type": "script.Monster", + "Enable": true, + "IsDead": false + }, + { + "@type": "script.MonsterAttack", + "Enable": true, + "SpriteSize": { + "x": 0, + "y": 0 + }, + "PositionOffset": { + "x": 0, + "y": 0 + } + }, + { + "@type": "MOD.Core.KinematicbodyComponent", + "MoveVelocity": { + "x": 0, + "y": 0 + }, + "Enable": true + }, + { + "@type": "MOD.Core.SideviewbodyComponent", + "MoveVelocity": { + "x": 0, + "y": 0 + }, + "Enable": true + }, + { + "@type": "script.CombatMonster", + "Enable": true, + "EnemyId": "king_slime", + "Group": "boss" + } + ], + "@version": 1 + } } ] } diff --git a/tools/deck/gen-slaydeck.mjs b/tools/deck/gen-slaydeck.mjs index ca011f0..8cf39dc 100644 --- a/tools/deck/gen-slaydeck.mjs +++ b/tools/deck/gen-slaydeck.mjs @@ -26,7 +26,6 @@ for (const [id, n] of Object.entries(MAP.nodes)) { const MAX_ROW = Math.max(...Object.values(MAP.nodes).map((n) => n.row)); const RELICS = JSON.parse(readFileSync('data/relics.json', 'utf8')); -const SLOTS = JSON.parse(readFileSync('data/monster-slots.json', 'utf8')); if (!RELICS.relics[RELICS.startingRelic]) throw new Error(`[gen-slaydeck] startingRelic 없음: ${RELICS.startingRelic}`); for (const id of RELICS.relicPool) { if (!RELICS.relics[id]) throw new Error(`[gen-slaydeck] relicPool에 없는 유물 id: ${id}`); @@ -73,9 +72,6 @@ function luaCardsTable(cards) { function luaDeckTable(deck) { return `self.DrawPile = { ${deck.map(luaStr).join(', ')} }`; } -function luaSlotGroup(arr) { - return '{ ' + arr.map((s) => `{ x = ${s.x}, y = ${s.y} }`).join(', ') + ' }'; -} const UI_FILE = 'ui/DefaultGroup.ui'; const COMMON_FILE = 'Global/common.gamelogic'; @@ -88,6 +84,7 @@ const DEFEND = { r: 0.42, g: 0.55, b: 0.85, a: 1 }; const SKILL = { r: 0.46, g: 0.68, b: 0.52, a: 1 }; const MAX_MONSTERS = 4; +const HEAD_OFFSET_Y = 1.4; // 몬스터 월드 원점 위로 띄울 높이(머리 위) — world→screen 변환 전 가산 const HP_BAR_W = 120; const CARD_W = 180; @@ -311,11 +308,6 @@ function entity({ id, path, modelId, entryId, componentNames, components, displa } function upsertUi() { - for (const g of ['combat', 'elite', 'boss']) { - if (!Array.isArray(SLOTS[g]) || SLOTS[g].length < MAX_MONSTERS) { - throw new Error(`[gen-slaydeck] monster-slots.json "${g}" 그룹 좌표(${SLOTS[g] ? SLOTS[g].length : 0}) < MAX_MONSTERS(${MAX_MONSTERS})`); - } - } const ui = JSON.parse(readFileSync(UI_FILE, 'utf8')); const E = ui.ContentProto.Entities; ui.ContentProto.Entities = E.filter((e) => !e.path.startsWith('/ui/DefaultGroup/DeckHud') && !e.path.startsWith('/ui/DefaultGroup/DeckInspectHud') && !e.path.startsWith('/ui/DefaultGroup/DeckAllHud') && !e.path.startsWith('/ui/DefaultGroup/CombatHud') && !e.path.startsWith('/ui/DefaultGroup/RewardHud') && !e.path.startsWith('/ui/DefaultGroup/MapHud') && !e.path.startsWith('/ui/DefaultGroup/ShopHud') && !e.path.startsWith('/ui/DefaultGroup/RestHud') && !e.path.startsWith('/ui/DefaultGroup/MainMenu') && !e.path.startsWith('/ui/DefaultGroup/CharacterSelectHud')); @@ -1564,8 +1556,6 @@ function writeCodeblocks() { prop('any', 'Monsters'), prop('any', 'Registered'), prop('number', 'TargetIndex', '1'), - prop('any', 'SlotPos'), - prop('any', 'ActiveSlotPos'), prop('any', 'RunDeck'), prop('number', 'Gold', '0'), prop('number', 'Floor', '0'), @@ -1677,7 +1667,6 @@ self.RelicPool = { ${RELICS.relicPool.map(luaStr).join(', ')} } ${luaEnemiesTable(ENEMIES.enemies)} ${luaMapNodesTable(MAP.nodes)} ${luaStartArray(MAP.start)} -self.SlotPos = { combat = ${luaSlotGroup(SLOTS.combat)}, elite = ${luaSlotGroup(SLOTS.elite)}, boss = ${luaSlotGroup(SLOTS.boss)} } self.CurrentNodeId = "" self.CurrentEnemyId = "" self:BindButtons() @@ -1718,7 +1707,6 @@ table.insert(self.Registered, { entity = monster, enemyId = enemyId, group = g } local g = "combat" local node = self.MapNodes[self.CurrentNodeId] if node ~= nil and node.type ~= nil then g = node.type end -self.ActiveSlotPos = self.SlotPos[g] local reg = self.Registered or {} for i = 1, #reg do if reg[i].entity ~= nil and isvalid(reg[i].entity) then @@ -2285,13 +2273,20 @@ e.UITransformComponent.RectSize = Vector2(w, 14)`, [ { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'hp' }, { Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'maxHp' }, ]), - method('PositionMonsterSlot', `local sp = self.ActiveSlotPos -if sp == nil or sp[slot] == nil then + method('PositionMonsterSlot', `local m = self.Monsters[slot] +if m == nil or m.entity == nil or not isvalid(m.entity) then return end +local tr = m.entity.TransformComponent +if tr == nil then + return +end +local wp = tr.WorldPosition +local screen = _UILogic:WorldToScreenPosition(Vector2(wp.x, wp.y + ${HEAD_OFFSET_Y})) +local uipos = _UILogic:ScreenToUIPosition(screen) local e = _EntityService:GetEntityByPath("/ui/DefaultGroup/CombatHud/MonsterSlot" .. tostring(slot)) if e ~= nil and e.UITransformComponent ~= nil then - e.UITransformComponent.anchoredPosition = Vector2(sp[slot].x, sp[slot].y) + e.UITransformComponent.anchoredPosition = uipos end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]), method('SetTarget', `if self.Monsters[slot] ~= nil and self.Monsters[slot].alive == true then self.TargetIndex = slot