Compare commits
4 Commits
222ed92807
...
fc03d58ee7
| Author | SHA1 | Date | |
|---|---|---|---|
| fc03d58ee7 | |||
| ead73b427e | |||
| d78049182b | |||
| 5f615e30e2 |
File diff suppressed because one or more lines are too long
@@ -537,7 +537,7 @@
|
|||||||
"kind": "Skill",
|
"kind": "Skill",
|
||||||
"class": "bandit",
|
"class": "bandit",
|
||||||
"rarity": "normal",
|
"rarity": "normal",
|
||||||
"desc": "카드를 1장 뽑습니다. 카드를 1장 버립니다.",
|
"desc": "카드를 1장 버리고, 이번 턴에 준 피해만큼 방어를 얻습니다.",
|
||||||
"blockPerDamageDealtThisTurn": 1,
|
"blockPerDamageDealtThisTurn": 1,
|
||||||
"discard": 1,
|
"discard": 1,
|
||||||
"image": "c1e19219745e44c39ae6ac2f77e347d9"
|
"image": "c1e19219745e44c39ae6ac2f77e347d9"
|
||||||
@@ -943,7 +943,7 @@
|
|||||||
"kind": "Skill",
|
"kind": "Skill",
|
||||||
"class": "bandit",
|
"class": "bandit",
|
||||||
"rarity": "unique",
|
"rarity": "unique",
|
||||||
"desc": "교활. 을 얻습니다.",
|
"desc": "교활. 에너지를 1 얻습니다.",
|
||||||
"gainEnergy": 1,
|
"gainEnergy": 1,
|
||||||
"sly": true,
|
"sly": true,
|
||||||
"image": "c1e19219745e44c39ae6ac2f77e347d9"
|
"image": "c1e19219745e44c39ae6ac2f77e347d9"
|
||||||
@@ -1109,7 +1109,7 @@
|
|||||||
"kind": "Skill",
|
"kind": "Skill",
|
||||||
"class": "bandit",
|
"class": "bandit",
|
||||||
"rarity": "legend",
|
"rarity": "legend",
|
||||||
"desc": "를 얻습니다. 카드를 2장 뽑습니다. 소멸.",
|
"desc": "에너지를 1 얻습니다. 카드를 2장 뽑습니다. 소멸.",
|
||||||
"draw": 2,
|
"draw": 2,
|
||||||
"gainEnergy": 1,
|
"gainEnergy": 1,
|
||||||
"image": "91a2d1c16cb041549adbf1a0d7b1f37f"
|
"image": "91a2d1c16cb041549adbf1a0d7b1f37f"
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ export function simulateCombat(data, rng, stats) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c.blockPerDamageDealtThisTurn && c.blockPerDamageDealtThisTurn > 0 && c.kind !== 'Power') {
|
if (c.blockPerDamageDealtThisTurn && c.blockPerDamageDealtThisTurn > 0 && c.kind !== 'Power') {
|
||||||
blockGained += Math.max(0, damageDealtThisTurn * c.blockPerDamageDealtThisTurn);
|
blockGained += addBlock(Math.max(0, damageDealtThisTurn * c.blockPerDamageDealtThisTurn));
|
||||||
}
|
}
|
||||||
if (recordStats && stats) stats[id] = bump(stats[id], costSpent, dmg, blockGained);
|
if (recordStats && stats) stats[id] = bump(stats[id], costSpent, dmg, blockGained);
|
||||||
}
|
}
|
||||||
@@ -659,7 +659,7 @@ export function simulateCombat(data, rng, stats) {
|
|||||||
const baseCost = c.cost || 0;
|
const baseCost = c.cost || 0;
|
||||||
const combatReduction = combatCardCostReduction[id] || 0;
|
const combatReduction = combatCardCostReduction[id] || 0;
|
||||||
const cost = handCostZeroThisTurn === true ? 0 : (c.useAllEnergy === true ? energy : (skillFree ? 0 : (c.kind === 'Skill' ? Math.max(0, baseCost - skillCostReductionThisTurn) : baseCost)));
|
const cost = handCostZeroThisTurn === true ? 0 : (c.useAllEnergy === true ? energy : (skillFree ? 0 : (c.kind === 'Skill' ? Math.max(0, baseCost - skillCostReductionThisTurn) : baseCost)));
|
||||||
const finalCost = Math.max(0, cost - combatReduction);
|
const finalCost = c.useAllEnergy === true ? cost : Math.max(0, cost - combatReduction);
|
||||||
energy -= finalCost;
|
energy -= finalCost;
|
||||||
resolveCardEffects(id, c, finalCost);
|
resolveCardEffects(id, c, finalCost);
|
||||||
const playedBlock = powerFieldTotal('cardPlayedBlock');
|
const playedBlock = powerFieldTotal('cardPlayedBlock');
|
||||||
|
|||||||
@@ -918,6 +918,21 @@ test('simulateCombat: firstShivDamageBonus는 턴당 첫 Shiv에만 적용 (Lua
|
|||||||
assert.equal(r.turns, 2);
|
assert.equal(r.turns, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('simulateCombat: blockPerDamageDealtThisTurn이 실제 방어를 부여 (Lua 동기화)', () => {
|
||||||
|
// 매턴 Hit(5뎀) → Guard(준 피해만큼 방어 5) → 적 공격 5 상쇄.
|
||||||
|
// 수정(실제 방어): 무한 생존 → 무승부. 버그(방어 미부여): 매턴 5피해 → 사망.
|
||||||
|
const data = {
|
||||||
|
cards: {
|
||||||
|
Hit: { name: '타격', cost: 2, kind: 'Attack', damage: 5 },
|
||||||
|
Guard: { name: '대비', cost: 1, kind: 'Skill', blockPerDamageDealtThisTurn: 1 },
|
||||||
|
},
|
||||||
|
starterDeck: ['Hit', 'Guard'],
|
||||||
|
monsters: [{ name: '적', maxHp: 9999, intents: [{ kind: 'Attack', value: 5 }] }],
|
||||||
|
};
|
||||||
|
const r = simulateCombat(data, mulberry32(1));
|
||||||
|
assert.equal(r.draw, true);
|
||||||
|
});
|
||||||
|
|
||||||
test("simulateCombat: repeatOnKill repeats an attack until no kill occurs", () => {
|
test("simulateCombat: repeatOnKill repeats an attack until no kill occurs", () => {
|
||||||
const shared = {
|
const shared = {
|
||||||
cards: {
|
cards: {
|
||||||
|
|||||||
@@ -52,14 +52,14 @@ if self.HandCostZeroThisTurn == true then
|
|||||||
elseif c.useAllEnergy == true then
|
elseif c.useAllEnergy == true then
|
||||||
cost = self.Energy
|
cost = self.Energy
|
||||||
end
|
end
|
||||||
if c.kind == "Skill" and self.NextSkillCostZero == true then
|
if c.kind == "Skill" and c.useAllEnergy ~= true and self.NextSkillCostZero == true then
|
||||||
cost = 0
|
cost = 0
|
||||||
skillFree = true
|
skillFree = true
|
||||||
end
|
end
|
||||||
if c.kind == "Skill" and self.SkillCostReductionThisTurn ~= nil and self.SkillCostReductionThisTurn > 0 then
|
if c.kind == "Skill" and c.useAllEnergy ~= true and self.SkillCostReductionThisTurn ~= nil and self.SkillCostReductionThisTurn > 0 then
|
||||||
cost = math.max(0, cost - self.SkillCostReductionThisTurn)
|
cost = math.max(0, cost - self.SkillCostReductionThisTurn)
|
||||||
end
|
end
|
||||||
if self.CombatCardCostReduction ~= nil and self.CombatCardCostReduction[cardId] ~= nil then
|
if c.useAllEnergy ~= true and self.CombatCardCostReduction ~= nil and self.CombatCardCostReduction[cardId] ~= nil then
|
||||||
cost = math.max(0, cost - self.CombatCardCostReduction[cardId])
|
cost = math.max(0, cost - self.CombatCardCostReduction[cardId])
|
||||||
end
|
end
|
||||||
if c.kind == "Skill" and self.NextSkillRepeatCount ~= nil and self.NextSkillRepeatCount > 0 then
|
if c.kind == "Skill" and self.NextSkillRepeatCount ~= nil and self.NextSkillRepeatCount > 0 then
|
||||||
@@ -381,7 +381,7 @@ for i = 1, #self.Monsters do
|
|||||||
local m = self.Monsters[i]
|
local m = self.Monsters[i]
|
||||||
if m ~= nil and m.alive == true then
|
if m ~= nil and m.alive == true then
|
||||||
local dmg = amount
|
local dmg = amount
|
||||||
if m.vuln > 0 then
|
if isAttack == true and m.vuln > 0 then
|
||||||
dmg = math.floor(dmg * 1.5)
|
dmg = math.floor(dmg * 1.5)
|
||||||
end
|
end
|
||||||
if m.block > 0 then
|
if m.block > 0 then
|
||||||
@@ -392,11 +392,13 @@ for i = 1, #self.Monsters do
|
|||||||
m.hp = m.hp - dmg
|
m.hp = m.hp - dmg
|
||||||
if dmg > 0 then
|
if dmg > 0 then
|
||||||
self.DamageDealtThisTurn = (self.DamageDealtThisTurn or 0) + dmg
|
self.DamageDealtThisTurn = (self.DamageDealtThisTurn or 0) + dmg
|
||||||
|
if isAttack == true then
|
||||||
local poison = self:AddPowerFieldTotal("attackPoison")
|
local poison = self:AddPowerFieldTotal("attackPoison")
|
||||||
if poison ~= nil and poison > 0 then
|
if poison ~= nil and poison > 0 then
|
||||||
self:ApplyPoisonToMonster(m, poison)
|
self:ApplyPoisonToMonster(m, poison)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
self:ShowDmgPop(i, dmg)
|
self:ShowDmgPop(i, dmg)
|
||||||
self:MonsterHitMotion(i)
|
self:MonsterHitMotion(i)
|
||||||
if m.hp <= 0 then
|
if m.hp <= 0 then
|
||||||
@@ -413,6 +415,7 @@ self:RenderCombat()
|
|||||||
self:CheckCombatEnd()
|
self:CheckCombatEnd()
|
||||||
return killCount > 0`, [
|
return killCount > 0`, [
|
||||||
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' },
|
{ Type: 'number', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'amount' },
|
||||||
|
{ Type: 'boolean', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'isAttack' },
|
||||||
], 0, 'boolean'),
|
], 0, 'boolean'),
|
||||||
method('PlayAttackFx', `local m = self.Monsters[targetIndex]
|
method('PlayAttackFx', `local m = self.Monsters[targetIndex]
|
||||||
if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then
|
if m == nil or m.alive ~= true or m.entity == nil or not isvalid(m.entity) then
|
||||||
|
|||||||
@@ -542,7 +542,7 @@ if c.kind == "Attack" then
|
|||||||
local function resolveAttackRound()
|
local function resolveAttackRound()
|
||||||
local roundKilled = false
|
local roundKilled = false
|
||||||
if useAoe == true then
|
if useAoe == true then
|
||||||
local killed = self:DealDamageToAllMonsters(total)
|
local killed = self:DealDamageToAllMonsters(total, true)
|
||||||
if killed == true then roundKilled = true end
|
if killed == true then roundKilled = true end
|
||||||
elseif c.randomTargetEachHit == true then
|
elseif c.randomTargetEachHit == true then
|
||||||
for h = 1, hitN do
|
for h = 1, hitN do
|
||||||
|
|||||||
Reference in New Issue
Block a user