Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 86 additions & 2 deletions spec/System/TestTriggers_spec.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,32 @@
describe("TestTriggers", function()
local function equipDreadCaptainsCutlass()
build.itemsTab:CreateDisplayItemFromRaw([[Dread Captain's Cutlass
Ghostflame Blade
League: Allflame
Crafted: true
Prefix: DeepwaterSwordGrantedSkillGhostCannons
Sockets: R-R-R
LevelReq: 68
Implicits: 2
Can be Allflame Crafted as if Rare
Cannot gain Intangibility
Trigger level 20 Ghostly Artillery when you Attack with this Weapon]])
build.itemsTab:AddDisplayItem()
runCallback("OnFrame")
end

local function equipReviewSword()
build.itemsTab:CreateDisplayItemFromRaw([[Rarity: RARE
Review Sword
Rusted Sword
Crafted: true
Implicits: 0
Adds 1000 to 1000 Physical Damage
Hits can't be Evaded]])
build.itemsTab:AddDisplayItem()
runCallback("OnFrame")
end

before_each(function()
newBuild()
end)
Expand Down Expand Up @@ -1437,7 +1465,7 @@ describe("TestTriggers", function()
assert.are.not_equals(math.floor(build.calcsTab.mainOutput.SkillTriggerRate * 100), math.floor(baseRate * 100))
end)

it("skillId config search", function()
it("Trigger Fiery Impact with its source weapon", function()
build.itemsTab:CreateDisplayItemFromRaw([[Rarity: RARE
Physical 1H Mace
Boom Mace
Expand Down Expand Up @@ -1465,7 +1493,63 @@ describe("TestTriggers", function()
build.skillsTab:PasteSocketGroup("Smite 20/0 1\n")
runCallback("OnFrame")

local baseRate = build.calcsTab.mainOutput.SkillTriggerRate
local baseRate = build.calcsTab.mainOutput.EffectiveSourceRate
assert.True(build.calcsTab.mainOutput.SkillTriggerRate ~= nil)

equipReviewSword()
runCallback("OnFrame")

assert.is_true(build.calcsTab.mainOutput.EffectiveSourceRate < baseRate)
assert.is_true(build.calcsTab.mainEnv.player.mainSkill.skillFlags.weapon1Attack)
assert.is_falsy(build.calcsTab.mainEnv.player.mainSkill.skillFlags.weapon2Attack)
end)

it("Trigger Ghostly Artillery with a projectile attack", function()
equipDreadCaptainsCutlass()
build.skillsTab:PasteSocketGroup("Lancing Steel 20/0 1\n")
runCallback("OnFrame")

assert.are.near(build.calcsTab.mainOutput.EffectiveSourceRate, build.calcsTab.mainOutput.SkillTriggerRate, 0.01)
end)

it("Do not add socketed attacks to the Ghostly Artillery trigger rotation", function()
equipDreadCaptainsCutlass()
build.skillsTab:PasteSocketGroup("Smite 20/0 1\n")
runCallback("OnFrame")
local bodyArmourRate = build.calcsTab.mainOutput.SkillTriggerRate

newBuild()
equipDreadCaptainsCutlass()
build.skillsTab:PasteSocketGroup("Slot: Weapon 1\nSmite 20/0 1\n")
runCallback("OnFrame")

assert.are.near(bodyArmourRate, build.calcsTab.mainOutput.SkillTriggerRate, 10 ^ -9)
end)

it("Use only the Cutlass when dual wielding", function()
equipDreadCaptainsCutlass()
build.skillsTab:PasteSocketGroup("Smite 20/0 1\n")
runCallback("OnFrame")
local singleWeaponRate = build.calcsTab.mainOutput.EffectiveSourceRate

newBuild()
equipDreadCaptainsCutlass()
equipReviewSword()
build.skillsTab:PasteSocketGroup("Smite 20/0 1\n")
runCallback("OnFrame")

assert.is_true(build.calcsTab.mainOutput.EffectiveSourceRate < singleWeaponRate)
assert.is_true(build.calcsTab.mainEnv.player.mainSkill.skillFlags.weapon1Attack)
assert.is_falsy(build.calcsTab.mainEnv.player.mainSkill.skillFlags.weapon2Attack)
assert.is_nil(build.calcsTab.mainOutput.OffHand and build.calcsTab.mainOutput.OffHand.AverageHit)

newBuild()
equipReviewSword()
equipDreadCaptainsCutlass()
build.skillsTab:PasteSocketGroup("Smite 20/0 1\n")
runCallback("OnFrame")

assert.is_falsy(build.calcsTab.mainEnv.player.mainSkill.skillFlags.weapon1Attack)
assert.is_true(build.calcsTab.mainEnv.player.mainSkill.skillFlags.weapon2Attack)
end)
end)
23 changes: 20 additions & 3 deletions src/Classes/ItemsTab.lua
Original file line number Diff line number Diff line change
Expand Up @@ -607,10 +607,12 @@ holding Shift will put it in the second.]])
self.controls.displayItemSectionInfluence = new("Control", {"TOPLEFT",self.controls.displayItemSectionEnchant,"BOTTOMLEFT"}, {0, 0, 0, function()
return self.displayItem and self.displayItem.canBeInfluenced and 28 or 0
end})
local influenceTipText = table.concat(main:WrapString("Selecting an influence here will also allow the modifier dropdowns to contain influenced mods.", 16, 140), "\n")
self.controls.displayItemInfluence = new("DropDownControl", {"TOPLEFT",self.controls.displayItemSectionInfluence,"TOPRIGHT"}, {0, 0, 100, 20}, influenceDisplayList, function(index, value)
local otherIndex = self.controls.displayItemInfluence2.selIndex
setDisplayItemInfluence({ index - 1, otherIndex - 1 })
end)
self.controls.displayItemInfluence.tooltipText = influenceTipText
self.controls.displayItemInfluence.shown = function()
return self.displayItem and self.displayItem.canBeInfluenced
end
Expand All @@ -621,6 +623,7 @@ holding Shift will put it in the second.]])
self.controls.displayItemInfluence2.shown = function()
return self.displayItem and self.displayItem.canBeInfluenced
end
self.controls.displayItemInfluence2.tooltipText = influenceTipText

-- Section: Item Quality
self.controls.displayItemSectionQuality = new("Control", {"TOPLEFT",self.controls.displayItemSectionInfluence,"BOTTOMLEFT"}, {0, 0, 0, function()
Expand Down Expand Up @@ -959,7 +962,7 @@ holding Shift will put it in the second.]])
self:AddCustomModifierToDisplayItem()
end)
self.controls.displayItemAddCustom.shown = function()
return self.displayItem and (self.displayItem.rarity == "MAGIC" or self.displayItem.rarity == "RARE")
return self.displayItem and (self.displayItem.rarity == "MAGIC" or self.displayItem.rarity == "RARE" or (self.displayItem.rareLikeUnique and self.displayItem.rareLikeUnique.supportsCustomModifiers))
end

-- Section: Crucible modifiers
Expand Down Expand Up @@ -3465,6 +3468,18 @@ function ItemsTabClass:AddCustomModifierToDisplayItem()
t_insert(sourceList, { label = "Suffix", sourceId = "SUFFIX" })
end
end
if self.displayItem.rareLikeUnique then
local applicableSourceIds = self.displayItem.rareLikeUnique.supportsCustomModifiers
if applicableSourceIds then
local newSourceList = {}
for _, list in ipairs(sourceList) do
if applicableSourceIds[list.sourceId] then
table.insert(newSourceList, list)
end
end
sourceList = newSourceList
end
end
t_insert(sourceList, { label = "Custom", sourceId = "CUSTOM" })
buildMods(sourceList[1].sourceId)
local function addModifier()
Expand All @@ -3477,8 +3492,10 @@ function ItemsTabClass:AddCustomModifierToDisplayItem()
end
else
local listMod = modList[controls.modSelect.selIndex]
for _, line in ipairs(listMod.mod) do
t_insert(item.explicitModLines, { line = line, modTags = listMod.mod.modTags, [listMod.type] = true })
if listMod then
for _, line in ipairs(listMod.mod) do
t_insert(item.explicitModLines, { line = line, modTags = listMod.mod.modTags, [listMod.type] = true })
end
end
end
item:BuildAndParseRaw()
Expand Down
2 changes: 2 additions & 0 deletions src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7952,6 +7952,7 @@ c["Can Allocate Passives from the Templar's starting point"]={{},nil}
c["Can Allocate Passives from the Witch's starting point"]={{},nil}
c["Can Consume 4 Uncorrupted Support Gems"]={nil,"Can Consume 4 Uncorrupted Support Gems "}
c["Can Consume 4 Uncorrupted Support Gems Has not Consumed any Gems"]={nil,"Can Consume 4 Uncorrupted Support Gems Has not Consumed any Gems "}
c["Can be Allflame Crafted as if Rare"]={{},nil}
c["Can be Enchanted by a Kalguuran Runesmith"]={nil,"Can be Enchanted by a Kalguuran Runesmith "}
c["Can be Enchanted by a Kalguuran Runesmith Can have 2 additional Runesmithing Enchantments"]={nil,"Can be Enchanted by a Kalguuran Runesmith Can have 2 additional Runesmithing Enchantments "}
c["Can be Runesmithed as though it were all One Handed Melee Weapon Types"]={nil,"Can be Runesmithed as though it were all One Handed Melee Weapon Types "}
Expand Down Expand Up @@ -8047,6 +8048,7 @@ c["Cannot deal non-Cold Damage"]={{[1]={flags=0,keywordFlags=0,name="DealNoPhysi
c["Cannot deal non-Fire Damage"]={{[1]={flags=0,keywordFlags=0,name="DealNoPhysical",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="DealNoLightning",type="FLAG",value=true},[3]={flags=0,keywordFlags=0,name="DealNoCold",type="FLAG",value=true},[4]={flags=0,keywordFlags=0,name="DealNoChaos",type="FLAG",value=true}},nil}
c["Cannot deal non-Lightning Damage"]={{[1]={flags=0,keywordFlags=0,name="DealNoPhysical",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="DealNoCold",type="FLAG",value=true},[3]={flags=0,keywordFlags=0,name="DealNoFire",type="FLAG",value=true},[4]={flags=0,keywordFlags=0,name="DealNoChaos",type="FLAG",value=true}},nil}
c["Cannot gain Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="CannotGainEnergyShield",type="FLAG",value=true}},nil}
c["Cannot gain Intangibility"]={{},nil}
c["Cannot gain Life during effect"]={{[1]={[1]={type="Condition",var="UsingFlask"},flags=0,keywordFlags=0,name="CannotGainLife",type="FLAG",value=true}},nil}
c["Cannot gain Mana during effect"]={{[1]={[1]={type="Condition",var="UsingFlask"},flags=0,keywordFlags=0,name="CannotGainMana",type="FLAG",value=true}},nil}
c["Cannot gain Power Charges"]={nil,"Cannot gain Power Charges "}
Expand Down
70 changes: 70 additions & 0 deletions src/Data/Skills/other.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5878,6 +5878,76 @@ skills["TriggerSummonedAncestorUtula"] = {
[20] = { 10, 50, cooldown = 20, levelRequirement = 0, storedUses = 1, statInterpolation = { 1, 1, }, },
},
}
skills["GhostCannons"] = {
name = "Ghostly Artillery",
hidden = true,
color = 2,
description = "Manifest a row of Ghostly Cannons, each of which then fires after a short delay dealing the damage of the weapon that triggered it. For each additional projectile this skill would fire, create an additional Ghostly Cannon instead.",
skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.Triggerable] = true, [SkillType.Triggered] = true, [SkillType.Fire] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.Area] = true, [SkillType.Cooldown] = true, },
statDescriptionScope = "skill_stat_descriptions",
castTime = 1,
fromItem = true,
baseFlags = {
attack = true,
projectile = true,
area = true,
},
constantStats = {
{ "skill_physical_damage_%_to_convert_to_fire", 50 },
{ "active_skill_additional_projectiles_fire_parallel_x_dist", 60 },
{ "base_number_of_projectiles", 1 },
{ "active_skill_base_area_of_effect_radius", 2 },
{ "triggered_ghost_cannons_base_number_of_cannons_to_fire", 6 },
},
stats = {
"base_is_projectile",
"skill_has_trigger_from_unique_item",
"modifiers_to_number_of_projectiles_instead_apply_to_number_of_summoned_ghost_cannons",
"is_area_damage",
},
levels = {
[1] = { cooldown = 0.15, levelRequirement = 12, storedUses = 1, },
[2] = { baseMultiplier = 1.032, cooldown = 0.15, damageEffectiveness = 1.032, levelRequirement = 15, storedUses = 1, },
[3] = { baseMultiplier = 1.063, cooldown = 0.15, damageEffectiveness = 1.063, levelRequirement = 19, storedUses = 1, },
[4] = { baseMultiplier = 1.095, cooldown = 0.15, damageEffectiveness = 1.095, levelRequirement = 23, storedUses = 1, },
[5] = { baseMultiplier = 1.126, cooldown = 0.15, damageEffectiveness = 1.126, levelRequirement = 27, storedUses = 1, },
[6] = { baseMultiplier = 1.158, cooldown = 0.15, damageEffectiveness = 1.158, levelRequirement = 31, storedUses = 1, },
[7] = { baseMultiplier = 1.189, cooldown = 0.15, damageEffectiveness = 1.189, levelRequirement = 35, storedUses = 1, },
[8] = { baseMultiplier = 1.221, cooldown = 0.15, damageEffectiveness = 1.221, levelRequirement = 38, storedUses = 1, },
[9] = { baseMultiplier = 1.253, cooldown = 0.15, damageEffectiveness = 1.253, levelRequirement = 41, storedUses = 1, },
[10] = { baseMultiplier = 1.284, cooldown = 0.15, damageEffectiveness = 1.284, levelRequirement = 44, storedUses = 1, },
[11] = { baseMultiplier = 1.316, cooldown = 0.15, damageEffectiveness = 1.316, levelRequirement = 47, storedUses = 1, },
[12] = { baseMultiplier = 1.347, cooldown = 0.15, damageEffectiveness = 1.347, levelRequirement = 50, storedUses = 1, },
[13] = { baseMultiplier = 1.379, cooldown = 0.15, damageEffectiveness = 1.379, levelRequirement = 53, storedUses = 1, },
[14] = { baseMultiplier = 1.411, cooldown = 0.15, damageEffectiveness = 1.411, levelRequirement = 56, storedUses = 1, },
[15] = { baseMultiplier = 1.442, cooldown = 0.15, damageEffectiveness = 1.442, levelRequirement = 59, storedUses = 1, },
[16] = { baseMultiplier = 1.474, cooldown = 0.15, damageEffectiveness = 1.474, levelRequirement = 62, storedUses = 1, },
[17] = { baseMultiplier = 1.505, cooldown = 0.15, damageEffectiveness = 1.505, levelRequirement = 64, storedUses = 1, },
[18] = { baseMultiplier = 1.537, cooldown = 0.15, damageEffectiveness = 1.537, levelRequirement = 66, storedUses = 1, },
[19] = { baseMultiplier = 1.568, cooldown = 0.15, damageEffectiveness = 1.568, levelRequirement = 68, storedUses = 1, },
[20] = { baseMultiplier = 1.6, cooldown = 0.15, damageEffectiveness = 1.6, levelRequirement = 70, storedUses = 1, },
[21] = { baseMultiplier = 1.632, cooldown = 0.15, damageEffectiveness = 1.632, levelRequirement = 72, storedUses = 1, },
[22] = { baseMultiplier = 1.663, cooldown = 0.15, damageEffectiveness = 1.663, levelRequirement = 74, storedUses = 1, },
[23] = { baseMultiplier = 1.695, cooldown = 0.15, damageEffectiveness = 1.695, levelRequirement = 76, storedUses = 1, },
[24] = { baseMultiplier = 1.726, cooldown = 0.15, damageEffectiveness = 1.726, levelRequirement = 78, storedUses = 1, },
[25] = { baseMultiplier = 1.758, cooldown = 0.15, damageEffectiveness = 1.758, levelRequirement = 80, storedUses = 1, },
[26] = { baseMultiplier = 1.789, cooldown = 0.15, damageEffectiveness = 1.789, levelRequirement = 82, storedUses = 1, },
[27] = { baseMultiplier = 1.821, cooldown = 0.15, damageEffectiveness = 1.821, levelRequirement = 84, storedUses = 1, },
[28] = { baseMultiplier = 1.853, cooldown = 0.15, damageEffectiveness = 1.853, levelRequirement = 86, storedUses = 1, },
[29] = { baseMultiplier = 1.884, cooldown = 0.15, damageEffectiveness = 1.884, levelRequirement = 88, storedUses = 1, },
[30] = { baseMultiplier = 1.916, cooldown = 0.15, damageEffectiveness = 1.916, levelRequirement = 90, storedUses = 1, },
[31] = { baseMultiplier = 1.932, cooldown = 0.15, damageEffectiveness = 1.932, levelRequirement = 91, storedUses = 1, },
[32] = { baseMultiplier = 1.947, cooldown = 0.15, damageEffectiveness = 1.947, levelRequirement = 92, storedUses = 1, },
[33] = { baseMultiplier = 1.963, cooldown = 0.15, damageEffectiveness = 1.963, levelRequirement = 93, storedUses = 1, },
[34] = { baseMultiplier = 1.979, cooldown = 0.15, damageEffectiveness = 1.979, levelRequirement = 94, storedUses = 1, },
[35] = { baseMultiplier = 1.995, cooldown = 0.15, damageEffectiveness = 1.995, levelRequirement = 95, storedUses = 1, },
[36] = { baseMultiplier = 2.011, cooldown = 0.15, damageEffectiveness = 2.011, levelRequirement = 96, storedUses = 1, },
[37] = { baseMultiplier = 2.026, cooldown = 0.15, damageEffectiveness = 2.026, levelRequirement = 97, storedUses = 1, },
[38] = { baseMultiplier = 2.042, cooldown = 0.15, damageEffectiveness = 2.042, levelRequirement = 98, storedUses = 1, },
[39] = { baseMultiplier = 2.058, cooldown = 0.15, damageEffectiveness = 2.058, levelRequirement = 99, storedUses = 1, },
[40] = { baseMultiplier = 2.074, cooldown = 0.15, damageEffectiveness = 2.074, levelRequirement = 100, storedUses = 1, },
},
}
skills["SupportUniqueCastCurseOnCurse"] = {
name = "Vixen's Entrapment",
hidden = true,
Expand Down
64 changes: 36 additions & 28 deletions src/Data/Uniques/sword.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@
Skills fire 2 additional Projectiles if you've used a Movement Skill Recently
Far Shot
]],[[
Dread Captain's Cutlass
Ghostflame Blade
Source: Drops from unique{Captainsbane} in normal{The Fathomless Depths}

Check warning on line 33 in src/Data/Uniques/sword.lua

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (Captainsbane)
League: Allflame
Crafted: true
Implicits: 2
Can be Allflame Crafted as if Rare
Cannot gain Intangibility
]],[[
Dreamfeather
Eternal Sword
Variant: Pre 2.0.0
Expand Down Expand Up @@ -804,6 +813,18 @@
{variant:4,5}Attack Skills gain 5% of Physical Damage as Extra Fire Damage per Socketed Red Gem
{variant:4,5}You have Vaal Pact while all Socketed Gems are Red
]],[[
Echoforge
Infernal Sword
Source: Drops from unique{The Maven}
Implicits: 1
30% increased Chaos Damage
Adds (600-650) to (750-800) Chaos Damage
(-16-16)% reduced Attack Speed
+(-200-200) to maximum Life
Your Chaos Damage can Shock
(-40-40)% reduced Area of Effect for Attacks
Deal no Physical or Elemental Damage
]],[[
Edge of Madness
Etched Greatsword
League: Beyond
Expand All @@ -824,6 +845,20 @@
{variant:1,2,4}1% increased Chaos Damage per Level
{variant:2,3,4}Adds 1 to 2 Physical Damage to Attacks per Level
]],[[
The Golden Charlatan
Lion Sword
Source: Drops from unique{Uber Incarnation of Dread} in normal{Moment of Reverence}
Requires Level 65, 104 Str, 122 Dex
Implicits: 1
+50 to Strength and Dexterity
+200 Intelligence Requirement
(200-300)% increased Physical Damage
(10-16)% increased Attack Speed
(100-200)% increased Critical Strike Chance
Critical Strikes with this Weapon do not deal extra Damage
Gain a random Shrine Buff for 30 seconds when you Kill a Rare or Unique Enemy
+1 to maximum Mana per 2 Intelligence
]],[[
Hiltless
Reaver Sword
Variant: Pre 2.6.0
Expand Down Expand Up @@ -893,18 +928,6 @@
{variant:2}Culling Strike against Frozen Enemies
Gain an Endurance Charge if an Attack Freezes an Enemy
]],[[
Echoforge
Infernal Sword
Source: Drops from unique{The Maven}
Implicits: 1
30% increased Chaos Damage
Adds (600-650) to (750-800) Chaos Damage
(-16-16)% reduced Attack Speed
+(-200-200) to maximum Life
Your Chaos Damage can Shock
(-40-40)% reduced Area of Effect for Attacks
Deal no Physical or Elemental Damage
]],[[
Queen's Decree
Ornate Sword
Variant: Pre 2.6.0
Expand Down Expand Up @@ -1048,20 +1071,5 @@
{variant:3}Gain 700% of Weapon Physical Damage as Extra Damage of a random Element
20% increased Area of Effect for Attacks
Deal no Non-Elemental Damage
]],
[[
The Golden Charlatan
Lion Sword
Source: Drops from unique{Uber Incarnation of Dread} in normal{Moment of Reverence}
Requires Level 65, 104 Str, 122 Dex
Implicits: 1
+50 to Strength and Dexterity
+200 Intelligence Requirement
(200-300)% increased Physical Damage
(10-16)% increased Attack Speed
(100-200)% increased Critical Strike Chance
Critical Strikes with this Weapon do not deal extra Damage
Gain a random Shrine Buff for 30 seconds when you Kill a Rare or Unique Enemy
+1 to maximum Mana per 2 Intelligence
]],
]]
}
8 changes: 5 additions & 3 deletions src/Export/Skills/other.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,6 @@ local skills, mod, flag, skill = ...
skill("hitTimeOverride", nil),
div = 1000,
},
["spider_aspect_max_web_count"] = {
mod("Multiplier:SpiderWebApplyStackMax", "BASE", nil),
},
},
#mods

Expand Down Expand Up @@ -1513,6 +1510,11 @@ local skills, mod, flag, skill = ...
},
#mods

#skill GhostCannons Ghostly Artillery
#flags attack projectile area
fromItem = true,
#mods

#skill SupportUniqueCastCurseOnCurse Vixen's Entrapment
#flags spell curse
fromItem = true,
Expand Down
Loading
Loading