feat(motion): 전투 모션 — 공격/피격/독뎀 (생성기+산출물)
- PlayerAttackMotion(StateComponent ATTACK→IDLE)·PlayerHitMotion(HIT+넉백 틱) - MonsterLunge(공격 시 런지)·MonsterHitMotion(hit 클립 스왑→stand 복귀, 폴백 흔들림) - BuildMonsters에 hit/stand 클립 pcall 캐시·motionBusy - 훅: PlayCard·DealDamageToTarget·PlayAoeFx·독 틱·체인메일 반사·EnemyActStep Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2760,8 +2760,17 @@ for i = 1, n do
|
||||
intents[k] = { kind = e.intents[k].kind, value = v, effect = e.intents[k].effect }
|
||||
end
|
||||
local maxHp = math.floor(e.maxHp * mult * self:AscHpMult())
|
||||
local hitClip = nil
|
||||
local standClip = nil
|
||||
if item.entity.StateAnimationComponent ~= nil then
|
||||
pcall(function()
|
||||
hitClip = item.entity.StateAnimationComponent.ActionSheet["hit"]
|
||||
standClip = item.entity.StateAnimationComponent.ActionSheet["stand"]
|
||||
end)
|
||||
end
|
||||
self.Monsters[i] = { entity = item.entity, enemyId = item.enemyId, name = e.name,
|
||||
hp = maxHp, maxHp = maxHp, block = 0, str = 0, weak = 0, vuln = 0, poison = 0,
|
||||
hitClip = hitClip, standClip = standClip, motionBusy = false,
|
||||
intents = intents, intentIdx = 1, alive = true, slot = i }
|
||||
self:ReviveMonsterEntity(item.entity)
|
||||
self:PositionMonsterSlot(i)
|
||||
@@ -3241,6 +3250,7 @@ end
|
||||
self.Energy = self.Energy - c.cost
|
||||
if c.kind == "Attack" then
|
||||
if c.damage ~= nil then
|
||||
self:PlayerAttackMotion()
|
||||
local total = 0
|
||||
local hitN = c.hits or 1
|
||||
for h = 1, hitN do
|
||||
@@ -3391,6 +3401,7 @@ if m.block > 0 and pierce ~= true then
|
||||
dmg = dmg - absorbed
|
||||
end
|
||||
m.hp = m.hp - dmg
|
||||
self:MonsterHitMotion(m.slot)
|
||||
if m.hp <= 0 then
|
||||
m.hp = 0
|
||||
self:KillMonster(m.slot)
|
||||
@@ -3464,6 +3475,7 @@ _TimerService:SetTimerOnce(function()
|
||||
end
|
||||
m.hp = m.hp - dmg
|
||||
self:ShowDmgPop(i, dmg)
|
||||
self:MonsterHitMotion(i)
|
||||
if m.hp <= 0 then
|
||||
m.hp = 0
|
||||
self:KillMonster(m.slot)
|
||||
@@ -3501,6 +3513,7 @@ if dmg > 0 then
|
||||
local am = self.Monsters[attackerSlot]
|
||||
if am ~= nil and am.alive == true then
|
||||
am.hp = am.hp - 3
|
||||
self:MonsterHitMotion(am.slot)
|
||||
if am.hp <= 0 then
|
||||
am.hp = 0
|
||||
self:KillMonster(am.slot)
|
||||
@@ -3539,6 +3552,7 @@ _TimerService:SetTimerOnce(function()
|
||||
if m.poison ~= nil and m.poison > 0 then
|
||||
m.hp = m.hp - m.poison
|
||||
self:ShowDmgPop(idx, m.poison)
|
||||
self:MonsterHitMotion(idx)
|
||||
m.poison = m.poison - 1
|
||||
if m.hp <= 0 then
|
||||
m.hp = 0
|
||||
@@ -3553,6 +3567,7 @@ _TimerService:SetTimerOnce(function()
|
||||
local intent = m.intents[m.intentIdx]
|
||||
if intent ~= nil then
|
||||
if intent.kind == "Attack" then
|
||||
self:MonsterLunge(idx)
|
||||
local atk = intent.value + m.str
|
||||
if m.weak > 0 then
|
||||
atk = math.floor(atk * 0.75)
|
||||
@@ -3563,6 +3578,7 @@ _TimerService:SetTimerOnce(function()
|
||||
local before = self.PlayerHp
|
||||
self:DealDamageToPlayer(atk, idx)
|
||||
self:ShowPlayerDmgPop(before - self.PlayerHp)
|
||||
self:PlayerHitMotion()
|
||||
elseif intent.kind == "Defend" then
|
||||
m.block = m.block + intent.value
|
||||
elseif intent.kind == "Debuff" then
|
||||
@@ -3829,6 +3845,92 @@ else
|
||||
end
|
||||
self:SetEntityEnabled(base, true)
|
||||
_TimerService:SetTimerOnce(function() self:SetEntityEnabled(base, false) end, 0.6)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' }]),
|
||||
method('PlayerAttackMotion', `local lp = _UserService.LocalPlayer
|
||||
if lp == nil or lp.StateComponent == nil then
|
||||
return
|
||||
end
|
||||
pcall(function() lp.StateComponent:ChangeState("ATTACK") end)
|
||||
_TimerService:SetTimerOnce(function()
|
||||
if lp ~= nil and isvalid(lp) and lp.StateComponent ~= nil then
|
||||
pcall(function() lp.StateComponent:ChangeState("IDLE") end)
|
||||
end
|
||||
end, 0.5)`),
|
||||
method('PlayerHitMotion', `local lp = _UserService.LocalPlayer
|
||||
if lp == nil then
|
||||
return
|
||||
end
|
||||
if lp.StateComponent ~= nil then
|
||||
pcall(function() lp.StateComponent:ChangeState("HIT") end)
|
||||
end
|
||||
local tr = lp.TransformComponent
|
||||
if tr == nil then
|
||||
return
|
||||
end
|
||||
local p = tr.Position
|
||||
tr.Position = Vector3(p.x - 0.15, p.y, p.z)
|
||||
_TimerService:SetTimerOnce(function()
|
||||
if lp ~= nil and isvalid(lp) and lp.TransformComponent ~= nil then
|
||||
lp.TransformComponent.Position = Vector3(p.x, p.y, p.z)
|
||||
end
|
||||
end, 0.15)`),
|
||||
method('MonsterLunge', `local m = self.Monsters[idx]
|
||||
if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then
|
||||
return
|
||||
end
|
||||
if m.motionBusy == true then
|
||||
return
|
||||
end
|
||||
m.motionBusy = true
|
||||
local e = m.entity
|
||||
local tr = e.TransformComponent
|
||||
if tr == nil then
|
||||
m.motionBusy = false
|
||||
return
|
||||
end
|
||||
local p = tr.Position
|
||||
tr.Position = Vector3(p.x - 0.35, p.y, p.z)
|
||||
_TimerService:SetTimerOnce(function()
|
||||
if isvalid(e) and e.TransformComponent ~= nil then
|
||||
e.TransformComponent.Position = Vector3(p.x, p.y, p.z)
|
||||
end
|
||||
m.motionBusy = false
|
||||
end, 0.18)`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'idx' }]),
|
||||
method('MonsterHitMotion', `local m = self.Monsters[slot]
|
||||
if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then
|
||||
return
|
||||
end
|
||||
local e = m.entity
|
||||
if m.hitClip ~= nil and e.SpriteRendererComponent ~= nil then
|
||||
e.SpriteRendererComponent.SpriteRUID = m.hitClip
|
||||
_TimerService:SetTimerOnce(function()
|
||||
if isvalid(e) and e.SpriteRendererComponent ~= nil and m.alive == true and m.standClip ~= nil then
|
||||
e.SpriteRendererComponent.SpriteRUID = m.standClip
|
||||
end
|
||||
end, 0.5)
|
||||
else
|
||||
if m.motionBusy == true then
|
||||
return
|
||||
end
|
||||
m.motionBusy = true
|
||||
local tr = e.TransformComponent
|
||||
if tr == nil then
|
||||
m.motionBusy = false
|
||||
return
|
||||
end
|
||||
local p = tr.Position
|
||||
local seq = { 0.12, -0.12, 0 }
|
||||
for i = 1, #seq do
|
||||
local dx = seq[i]
|
||||
_TimerService:SetTimerOnce(function()
|
||||
if isvalid(e) and e.TransformComponent ~= nil then
|
||||
e.TransformComponent.Position = Vector3(p.x + dx, p.y, p.z)
|
||||
end
|
||||
if i == #seq then
|
||||
m.motionBusy = false
|
||||
end
|
||||
end, 0.06 * i)
|
||||
end
|
||||
end`, [{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'slot' }]),
|
||||
method('SetHpBar', `local e = _EntityService:GetEntityByPath(path)
|
||||
if e == nil or e.UITransformComponent == nil then
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user