Merge pull request 'Map monster combat' from feature/map-monster-combat
# Conflicts: # RootDesk/MyDesk/SlayDeckController.codeblock
This commit is contained in:
@@ -12,7 +12,6 @@ for (const id of CARDS.starterDeck) {
|
||||
if (!ENEMIES.enemies[ENEMIES.activeEnemy]) {
|
||||
throw new Error(`[gen-slaydeck] activeEnemy가 enemies에 없음: ${ENEMIES.activeEnemy}`);
|
||||
}
|
||||
const ACTIVE_ENEMY = ENEMIES.enemies[ENEMIES.activeEnemy];
|
||||
|
||||
const MAP = JSON.parse(readFileSync('data/map.json', 'utf8'));
|
||||
for (const id of MAP.start) {
|
||||
@@ -27,6 +26,7 @@ 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,15 +73,6 @@ function luaCardsTable(cards) {
|
||||
function luaDeckTable(deck) {
|
||||
return `self.DrawPile = { ${deck.map(luaStr).join(', ')} }`;
|
||||
}
|
||||
function luaIntentsTable(intents) {
|
||||
const lines = intents.map((it) => `\t{ kind = ${luaStr(it.kind)}, value = ${it.value} },`);
|
||||
return `self.EnemyIntents = {\n${lines.join('\n')}\n}`;
|
||||
}
|
||||
function intentText(it) {
|
||||
if (it.kind === 'Attack') return `의도: 공격 ${it.value}`;
|
||||
if (it.kind === 'Defend') return `의도: 방어 ${it.value}`;
|
||||
return '';
|
||||
}
|
||||
|
||||
const UI_FILE = 'ui/DefaultGroup.ui';
|
||||
const COMMON_FILE = 'Global/common.gamelogic';
|
||||
@@ -93,6 +84,9 @@ const ATTACK = { r: 0.86, g: 0.42, b: 0.38, a: 1 };
|
||||
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 HP_BAR_W = 120;
|
||||
const CARD_W = 180;
|
||||
const CARD_H = 250;
|
||||
const CARD_SPACING = 200;
|
||||
@@ -285,6 +279,9 @@ function entity({ id, path, modelId, entryId, componentNames, components, displa
|
||||
}
|
||||
|
||||
function upsertUi() {
|
||||
if (SLOTS.length < MAX_MONSTERS) {
|
||||
throw new Error(`[gen-slaydeck] monster-slots.json 항목(${SLOTS.length}) < 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'));
|
||||
@@ -721,40 +718,73 @@ function upsertUi() {
|
||||
sprite({ color: TRANSPARENT }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 1),
|
||||
path: '/ui/DefaultGroup/CombatHud/EnemyBg',
|
||||
modelId: 'uisprite',
|
||||
entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 0,
|
||||
components: [
|
||||
transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 380, y: 170 }, pos: { x: 0, y: 300 }, align: ALIGN_CENTER }),
|
||||
sprite({ color: PANEL_BG, type: 1 }),
|
||||
],
|
||||
}));
|
||||
const enemyTexts = [
|
||||
['EnemyName', { x: 0, y: 358 }, { x: 360, y: 44 }, ACTIVE_ENEMY.name, 28, true, GOLD],
|
||||
['EnemyHp', { x: 0, y: 316 }, { x: 360, y: 40 }, `HP ${ACTIVE_ENEMY.maxHp}/${ACTIVE_ENEMY.maxHp}`, 24, true, { r: 1, g: 1, b: 1, a: 1 }],
|
||||
['EnemyBlock', { x: 0, y: 280 }, { x: 360, y: 36 }, '방어 0', 20, false, { r: 0.6, g: 0.8, b: 1, a: 1 }],
|
||||
['EnemyIntent', { x: 0, y: 244 }, { x: 360, y: 38 }, intentText(ACTIVE_ENEMY.intents[0]), 22, true, { r: 1, g: 0.72, b: 0.5, a: 1 }],
|
||||
];
|
||||
let cmbN = 2;
|
||||
for (const [suffix, pos, size, value, fontSize, bold, color] of enemyTexts) {
|
||||
combat.push(entity({
|
||||
id: guid('cmb', cmbN++),
|
||||
path: `/ui/DefaultGroup/CombatHud/${suffix}`,
|
||||
modelId: 'uitext',
|
||||
entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: enemyTexts.findIndex(([s]) => s === suffix) + 1,
|
||||
const SLOT_W = 140, SLOT_H = 96;
|
||||
for (let i = 1; i <= MAX_MONSTERS; i++) {
|
||||
const base = `/ui/DefaultGroup/CombatHud/MonsterSlot${i}`;
|
||||
const slot = entity({
|
||||
id: guid('cmb', 40 + i),
|
||||
path: base,
|
||||
modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.ButtonComponent',
|
||||
displayOrder: 20 + i,
|
||||
components: [
|
||||
transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size, pos }),
|
||||
transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: SLOT_W, y: SLOT_H }, pos: { x: (i - 2.5) * 320, y: 300 } }),
|
||||
sprite({ color: { r: 0, g: 0, b: 0, a: 0.0001 }, type: 1, raycast: true }),
|
||||
button(),
|
||||
],
|
||||
});
|
||||
slot.jsonString.enable = false;
|
||||
combat.push(slot);
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 60 + i), path: `${base}/Name`, modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 0,
|
||||
components: [
|
||||
transform({ parentW: SLOT_W, parentH: SLOT_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: SLOT_W, y: 30 }, pos: { x: 0, y: 34 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value, fontSize, bold, color }),
|
||||
text({ value: '', fontSize: 20, bold: true, color: GOLD, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 80 + i), path: `${base}/Hp`, modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 1,
|
||||
components: [
|
||||
transform({ parentW: SLOT_W, parentH: SLOT_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: SLOT_W, y: 26 }, pos: { x: 0, y: 6 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '', fontSize: 18, bold: true, color: { r: 1, g: 1, b: 1, a: 1 }, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 100 + i), path: `${base}/HpBarBg`, modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 2,
|
||||
components: [
|
||||
transform({ parentW: SLOT_W, parentH: SLOT_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: HP_BAR_W, y: 14 }, pos: { x: 0, y: -14 } }),
|
||||
sprite({ color: { r: 0.18, g: 0.05, b: 0.06, a: 1 }, type: 1 }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 120 + i), path: `${base}/HpBarFill`, modelId: 'uisprite', entryId: 'UISprite',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||
displayOrder: 3,
|
||||
components: [
|
||||
transform({ parentW: SLOT_W, parentH: SLOT_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0, y: 0.5 }, size: { x: HP_BAR_W, y: 14 }, pos: { x: -HP_BAR_W / 2, y: -14 } }),
|
||||
sprite({ color: { r: 0.86, g: 0.35, b: 0.32, a: 1 }, type: 1 }),
|
||||
],
|
||||
}));
|
||||
combat.push(entity({
|
||||
id: guid('cmb', 140 + i), path: `${base}/Intent`, modelId: 'uitext', entryId: 'UIText',
|
||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||
displayOrder: 4,
|
||||
components: [
|
||||
transform({ parentW: SLOT_W, parentH: SLOT_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: SLOT_W + 40, y: 24 }, pos: { x: 0, y: -36 } }),
|
||||
sprite({ color: TRANSPARENT }),
|
||||
text({ value: '', fontSize: 17, bold: true, color: { r: 1, g: 0.72, b: 0.5, a: 1 }, alignment: 4 }),
|
||||
],
|
||||
}));
|
||||
}
|
||||
let cmbN = 2;
|
||||
combat.push(entity({
|
||||
id: guid('cmb', cmbN++),
|
||||
path: '/ui/DefaultGroup/CombatHud/PlayerBg',
|
||||
@@ -1318,13 +1348,11 @@ function writeCodeblocks() {
|
||||
prop('number', 'PlayerHp', '0'),
|
||||
prop('number', 'PlayerMaxHp', '80'),
|
||||
prop('number', 'PlayerBlock', '0'),
|
||||
prop('number', 'EnemyHp', '0'),
|
||||
prop('number', 'EnemyMaxHp', String(ACTIVE_ENEMY.maxHp)),
|
||||
prop('number', 'EnemyBlock', '0'),
|
||||
prop('number', 'EnemyIntentIndex', '1'),
|
||||
prop('boolean', 'CombatOver', 'false'),
|
||||
prop('any', 'EnemyIntents'),
|
||||
prop('any', 'EnemyName'),
|
||||
prop('any', 'Monsters'),
|
||||
prop('any', 'Registered'),
|
||||
prop('number', 'TargetIndex', '1'),
|
||||
prop('any', 'SlotPos'),
|
||||
prop('any', 'RunDeck'),
|
||||
prop('number', 'Gold', '0'),
|
||||
prop('number', 'Floor', '0'),
|
||||
@@ -1378,6 +1406,7 @@ self.RelicPool = { ${RELICS.relicPool.map(luaStr).join(', ')} }
|
||||
${luaEnemiesTable(ENEMIES.enemies)}
|
||||
${luaMapNodesTable(MAP.nodes)}
|
||||
${luaStartArray(MAP.start)}
|
||||
self.SlotPos = { ${SLOTS.map((s) => `{ x = ${s.x}, y = ${s.y} }`).join(', ')} }
|
||||
self.CurrentNodeId = ""
|
||||
self.CurrentEnemyId = ""
|
||||
self:BindButtons()
|
||||
@@ -1385,18 +1414,7 @@ self:AddRelic("${RELICS.startingRelic}")
|
||||
self:ShowMap()`),
|
||||
method('StartCombat', `self.MaxEnergy = 3
|
||||
self.Turn = 0
|
||||
local enemy = self.Enemies[self.CurrentEnemyId]
|
||||
local mult = 1 + (self.Floor - 1) * 0.6
|
||||
self.PlayerBlock = 0
|
||||
self.EnemyName = enemy.name
|
||||
self.EnemyMaxHp = math.floor(enemy.maxHp * mult)
|
||||
self.EnemyHp = self.EnemyMaxHp
|
||||
self.EnemyBlock = 0
|
||||
self.EnemyIntents = {}
|
||||
for i = 1, #enemy.intents do
|
||||
self.EnemyIntents[i] = { kind = enemy.intents[i].kind, value = math.floor(enemy.intents[i].value * mult) }
|
||||
end
|
||||
self.EnemyIntentIndex = 1
|
||||
self.CombatOver = false
|
||||
self.DiscardPile = {}
|
||||
self.Hand = {}
|
||||
@@ -1406,10 +1424,55 @@ for i = 1, #self.RunDeck do
|
||||
self.DrawPile[i] = self.RunDeck[i]
|
||||
end
|
||||
self:Shuffle(self.DrawPile)
|
||||
self:BuildMonsters()
|
||||
self:RenderCombat()
|
||||
self:StartPlayerTurn()
|
||||
self:ApplyRelics("combatStart")
|
||||
self:RenderCombat()`),
|
||||
method('RegisterMonster', `if self.Registered == nil then
|
||||
self.Registered = {}
|
||||
end
|
||||
table.insert(self.Registered, { entity = monster, enemyId = enemyId })`, [
|
||||
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'monster' },
|
||||
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'enemyId' },
|
||||
]),
|
||||
method('BuildMonsters', `self.Monsters = {}
|
||||
local reg = self.Registered or {}
|
||||
local list = {}
|
||||
for i = 1, #reg do
|
||||
local r = reg[i]
|
||||
if r.entity ~= nil and isvalid(r.entity) then
|
||||
local x = 0
|
||||
if r.entity.TransformComponent ~= nil then
|
||||
x = r.entity.TransformComponent.WorldPosition.x
|
||||
end
|
||||
table.insert(list, { entity = r.entity, enemyId = r.enemyId, x = x })
|
||||
end
|
||||
end
|
||||
table.sort(list, function(a, b) return a.x < b.x end)
|
||||
local mult = 1 + (self.Floor - 1) * 0.6
|
||||
local n = #list
|
||||
if n > ${MAX_MONSTERS} then n = ${MAX_MONSTERS} end
|
||||
for i = 1, n do
|
||||
local item = list[i]
|
||||
local e = self.Enemies[item.enemyId]
|
||||
if e == nil then e = { name = item.enemyId, maxHp = 10, intents = { { kind = "Attack", value = 5 } } } end
|
||||
local intents = {}
|
||||
for k = 1, #e.intents do
|
||||
intents[k] = { kind = e.intents[k].kind, value = math.floor(e.intents[k].value * mult) }
|
||||
end
|
||||
local maxHp = math.floor(e.maxHp * mult)
|
||||
self.Monsters[i] = { entity = item.entity, enemyId = item.enemyId, name = e.name,
|
||||
hp = maxHp, maxHp = maxHp, block = 0, intents = intents, intentIdx = 1, alive = true, slot = i }
|
||||
self:ReviveMonsterEntity(item.entity)
|
||||
self:PositionMonsterSlot(i)
|
||||
end
|
||||
self.TargetIndex = 1`),
|
||||
method('ReviveMonsterEntity', `if monster == nil or not isvalid(monster) then
|
||||
return
|
||||
end
|
||||
monster:SetEnable(true)
|
||||
monster:SetVisible(true)`, [{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'monster' }]),
|
||||
method('Shuffle', `if list == nil then
|
||||
\treturn
|
||||
end
|
||||
@@ -1506,6 +1569,12 @@ end
|
||||
local restLeave = _EntityService:GetEntityByPath("/ui/DefaultGroup/RestHud/Leave")
|
||||
if restLeave ~= nil and restLeave.ButtonComponent ~= nil then
|
||||
restLeave:ConnectEvent(ButtonClickEvent, function() self:LeaveNode() end)
|
||||
end
|
||||
for i = 1, ${MAX_MONSTERS} do
|
||||
local ms = _EntityService:GetEntityByPath("/ui/DefaultGroup/CombatHud/MonsterSlot" .. tostring(i))
|
||||
if ms ~= nil and ms.ButtonComponent ~= nil then
|
||||
ms:ConnectEvent(ButtonClickEvent, function() self:SetTarget(i) end)
|
||||
end
|
||||
end`),
|
||||
method('StartPlayerTurn', `self.Turn = self.Turn + 1
|
||||
self.Energy = self.MaxEnergy
|
||||
@@ -1772,7 +1841,7 @@ end
|
||||
self.Energy = self.Energy - c.cost
|
||||
if c.kind == "Attack" then
|
||||
if c.damage ~= nil then
|
||||
self:DealDamageToEnemy(c.damage)
|
||||
self:DealDamageToTarget(c.damage)
|
||||
end
|
||||
self:ApplyRelics("cardPlayed")
|
||||
elseif c.kind == "Skill" then
|
||||
@@ -1787,16 +1856,39 @@ self:RenderPiles()
|
||||
self:RenderCombat()
|
||||
self:CheckCombatEnd()`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]),
|
||||
method('Toast', `log(message)`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'message' }]),
|
||||
method('DealDamageToEnemy', `local dmg = amount
|
||||
if self.EnemyBlock > 0 then
|
||||
local absorbed = math.min(self.EnemyBlock, dmg)
|
||||
self.EnemyBlock = self.EnemyBlock - absorbed
|
||||
method('DealDamageToTarget', `local m = self.Monsters[self.TargetIndex]
|
||||
if m == nil or m.alive ~= true then
|
||||
m = nil
|
||||
for i = 1, #self.Monsters do
|
||||
if self.Monsters[i].alive == true then m = self.Monsters[i]; self.TargetIndex = i; break end
|
||||
end
|
||||
end
|
||||
if m == nil then
|
||||
return
|
||||
end
|
||||
local dmg = amount
|
||||
if m.block > 0 then
|
||||
local absorbed = math.min(m.block, dmg)
|
||||
m.block = m.block - absorbed
|
||||
dmg = dmg - absorbed
|
||||
end
|
||||
self.EnemyHp = self.EnemyHp - dmg
|
||||
if self.EnemyHp < 0 then
|
||||
self.EnemyHp = 0
|
||||
m.hp = m.hp - dmg
|
||||
if m.hp <= 0 then
|
||||
m.hp = 0
|
||||
self:KillMonster(m.slot)
|
||||
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }]),
|
||||
method('KillMonster', `local m = self.Monsters[slot]
|
||||
if m == nil then
|
||||
return
|
||||
end
|
||||
m.alive = false
|
||||
if m.entity ~= nil and isvalid(m.entity) then
|
||||
m.entity:SetVisible(false)
|
||||
end
|
||||
self:SetEntityEnabled("/ui/DefaultGroup/CombatHud/MonsterSlot" .. tostring(slot), false)
|
||||
for i = 1, #self.Monsters do
|
||||
if self.Monsters[i].alive == true then self.TargetIndex = i; break end
|
||||
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]),
|
||||
method('DealDamageToPlayer', `local dmg = amount
|
||||
if self.PlayerBlock > 0 then
|
||||
local absorbed = math.min(self.PlayerBlock, dmg)
|
||||
@@ -1807,21 +1899,30 @@ self.PlayerHp = self.PlayerHp - dmg
|
||||
if self.PlayerHp < 0 then
|
||||
self.PlayerHp = 0
|
||||
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }]),
|
||||
method('EnemyTurn', `self.EnemyBlock = 0
|
||||
local intent = self.EnemyIntents[self.EnemyIntentIndex]
|
||||
if intent ~= nil then
|
||||
if intent.kind == "Attack" then
|
||||
self:DealDamageToPlayer(intent.value)
|
||||
elseif intent.kind == "Defend" then
|
||||
self.EnemyBlock = self.EnemyBlock + intent.value
|
||||
method('EnemyTurn', `for i = 1, #self.Monsters do
|
||||
local m = self.Monsters[i]
|
||||
if m.alive == true then
|
||||
m.block = 0
|
||||
local intent = m.intents[m.intentIdx]
|
||||
if intent ~= nil then
|
||||
if intent.kind == "Attack" then
|
||||
self:DealDamageToPlayer(intent.value)
|
||||
elseif intent.kind == "Defend" then
|
||||
m.block = m.block + intent.value
|
||||
end
|
||||
end
|
||||
m.intentIdx = m.intentIdx + 1
|
||||
if m.intentIdx > #m.intents then
|
||||
m.intentIdx = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
self.EnemyIntentIndex = self.EnemyIntentIndex + 1
|
||||
if self.EnemyIntentIndex > #self.EnemyIntents then
|
||||
self.EnemyIntentIndex = 1
|
||||
end
|
||||
self:RenderCombat()`),
|
||||
method('CheckCombatEnd', `if self.EnemyHp <= 0 then
|
||||
method('CheckCombatEnd', `local anyAlive = false
|
||||
for i = 1, #self.Monsters do
|
||||
if self.Monsters[i].alive == true then anyAlive = true; break end
|
||||
end
|
||||
if anyAlive == false then
|
||||
self.CombatOver = true
|
||||
self.Gold = self.Gold + ${GOLD_PER_WIN}
|
||||
self:ApplyRelics("combatReward")
|
||||
@@ -1854,22 +1955,54 @@ local entity = _EntityService:GetEntityByPath("/ui/DefaultGroup/CombatHud/Result
|
||||
if entity ~= nil then
|
||||
entity.Enable = true
|
||||
end`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'text' }]),
|
||||
method('RenderCombat', `self:SetText("/ui/DefaultGroup/CombatHud/EnemyName", self.EnemyName)
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/EnemyHp", "HP " .. string.format("%d", self.EnemyHp) .. "/" .. string.format("%d", self.EnemyMaxHp))
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/EnemyBlock", "방어 " .. string.format("%d", self.EnemyBlock))
|
||||
local intent = self.EnemyIntents[self.EnemyIntentIndex]
|
||||
local intentText = ""
|
||||
if intent ~= nil then
|
||||
if intent.kind == "Attack" then
|
||||
intentText = "의도: 공격 " .. tostring(intent.value)
|
||||
elseif intent.kind == "Defend" then
|
||||
intentText = "의도: 방어 " .. tostring(intent.value)
|
||||
method('RenderCombat', `for i = 1, ${MAX_MONSTERS} do
|
||||
local base = "/ui/DefaultGroup/CombatHud/MonsterSlot" .. tostring(i)
|
||||
local m = self.Monsters[i]
|
||||
if m ~= nil and m.alive == true then
|
||||
self:SetEntityEnabled(base, true)
|
||||
self:SetText(base .. "/Name", m.name)
|
||||
self:SetText(base .. "/Hp", string.format("%d", m.hp) .. "/" .. string.format("%d", m.maxHp))
|
||||
local intent = m.intents[m.intentIdx]
|
||||
local t = ""
|
||||
if intent ~= nil then
|
||||
if intent.kind == "Attack" then t = "공격 " .. tostring(intent.value)
|
||||
elseif intent.kind == "Defend" then t = "방어 " .. tostring(intent.value) end
|
||||
end
|
||||
if i == self.TargetIndex then t = "[타겟] " .. t end
|
||||
self:SetText(base .. "/Intent", t)
|
||||
self:SetHpBar(base .. "/HpBarFill", m.hp, m.maxHp)
|
||||
else
|
||||
self:SetEntityEnabled(base, false)
|
||||
end
|
||||
end
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/EnemyIntent", intentText)
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/PlayerHp", "HP " .. string.format("%d", self.PlayerHp) .. "/" .. string.format("%d", self.PlayerMaxHp))
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/PlayerBlock", "방어 " .. string.format("%d", self.PlayerBlock))
|
||||
self:RenderRun()`),
|
||||
method('SetHpBar', `local e = _EntityService:GetEntityByPath(path)
|
||||
if e == nil or e.UITransformComponent == nil then
|
||||
return
|
||||
end
|
||||
local ratio = 0
|
||||
if maxHp > 0 then ratio = hp / maxHp end
|
||||
if ratio < 0 then ratio = 0 end
|
||||
local w = ${HP_BAR_W} * ratio
|
||||
e.UITransformComponent.RectSize = Vector2(w, 14)`, [
|
||||
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'path' },
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'hp' },
|
||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'maxHp' },
|
||||
]),
|
||||
method('PositionMonsterSlot', `local sp = self.SlotPos
|
||||
if sp == nil or sp[slot] == nil then
|
||||
return
|
||||
end
|
||||
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)
|
||||
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
|
||||
self:RenderCombat()
|
||||
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]),
|
||||
method('RenderRun', `self:SetText("/ui/DefaultGroup/CombatHud/Floor", "막 " .. string.format("%d", self.Floor) .. "/" .. string.format("%d", self.RunLength))
|
||||
self:SetText("/ui/DefaultGroup/CombatHud/Gold", "골드 " .. string.format("%d", self.Gold))`),
|
||||
method('OfferReward', `local pool = {}
|
||||
|
||||
Reference in New Issue
Block a user