Fixed 2 bugs relating to duplicate ItemRarity block items and spaces at the end of ItemRarity block items

This commit is contained in:
Ben Wallis 2016-08-30 18:39:08 +01:00
parent ce4366d3fd
commit 6eb17555c0
3 changed files with 102 additions and 95 deletions

View File

@ -835,7 +835,104 @@ namespace Filtration.Parser.Tests.Services
Assert.AreEqual(20, blockItem.Color.G); Assert.AreEqual(20, blockItem.Color.G);
Assert.AreEqual(100, blockItem.Color.B); Assert.AreEqual(100, blockItem.Color.B);
} }
[Test]
public void TranslateStringToItemFilterBlock_MultipleRarityItems_OnlyLastOneUsed()
{
// Arrange
var inputString = @"#8#" + Environment.NewLine +
"Hide" + Environment.NewLine +
"Rarity Magic" + Environment.NewLine +
"DropLevel >= 67" + Environment.NewLine +
"BaseType \"Sorcerer Boots\"" + Environment.NewLine +
"Rarity Rare" + Environment.NewLine +
"SetFontSize 26" + Environment.NewLine +
"SetBackgroundColor 0 20 0";
_testUtility.TestBlock.Enabled = false;
_testUtility.TestBlock.BlockItems.Add(new WidthBlockItem(FilterPredicateOperator.Equal, 4));
// Act
var result = _testUtility.Translator.TranslateStringToItemFilterBlock(inputString, null);
// Assert
Assert.AreEqual(1, result.BlockItems.Count(b => b is RarityBlockItem));
var blockItem = result.BlockItems.OfType<RarityBlockItem>().First();
Assert.AreEqual(ItemRarity.Rare, (ItemRarity)blockItem.FilterPredicate.PredicateOperand);
}
[Test]
public void TranslateStringToItemFilterBlock_SpecificTest_1()
{
// Arrange
var inputString = @"Show" + Environment.NewLine +
"DropLevel >= 67" + Environment.NewLine +
"Rarity Rare" + Environment.NewLine +
" ItemLevel >= 75 " + Environment.NewLine +
" SetBorderColor 250 40 210" + Environment.NewLine +
"BaseType \"Sorcerer Boots\" \"Titan Greaves\" \"Slink Boots\" \"Murder Boots\"" + Environment.NewLine +
"SetBackgroundColor 0 20 0 ##TOP BASE FOR LEVEL### " + Environment.NewLine +
"SetFontSize 28";
_testUtility.TestBlock.Enabled = false;
_testUtility.TestBlock.BlockItems.Add(new WidthBlockItem(FilterPredicateOperator.Equal, 4));
// Act
var result = _testUtility.Translator.TranslateStringToItemFilterBlock(inputString, null);
// Assert
Assert.AreEqual(1, result.BlockItems.Count(b => b is ActionBlockItem));
var actionBlockItem = result.BlockItems.OfType<ActionBlockItem>().First();
Assert.AreEqual(BlockAction.Show, actionBlockItem.Action);
Assert.AreEqual(1, result.BlockItems.Count(b => b is DropLevelBlockItem));
var droplevelBlockItem = result.BlockItems.OfType<DropLevelBlockItem>().First();
Assert.AreEqual(67, droplevelBlockItem.FilterPredicate.PredicateOperand);
Assert.AreEqual(FilterPredicateOperator.GreaterThanOrEqual, droplevelBlockItem.FilterPredicate.PredicateOperator);
Assert.AreEqual(1, result.BlockItems.Count(b => b is RarityBlockItem));
var rarityBlockItem = result.BlockItems.OfType<RarityBlockItem>().First();
Assert.AreEqual(ItemRarity.Rare, (ItemRarity)rarityBlockItem.FilterPredicate.PredicateOperand);
}
[Test]
public void TranslateStringToItemFilterBlock_SpecificTest_2()
{
// Arrange
var inputString = @"#8#" + Environment.NewLine +
"Hide " + Environment.NewLine +
"Rarity Magic " + Environment.NewLine +
"DropLevel >= 67" + Environment.NewLine +
"BaseType \"Sorcerer Boots\"" + Environment.NewLine +
"Rarity Magic " + Environment.NewLine +
"SetFontSize 26" + Environment.NewLine +
"SetBackgroundColor 0 20 0\"";
_testUtility.TestBlock.Enabled = false;
_testUtility.TestBlock.BlockItems.Add(new WidthBlockItem(FilterPredicateOperator.Equal, 4));
// Act
var result = _testUtility.Translator.TranslateStringToItemFilterBlock(inputString, null);
// Assert
Assert.AreEqual(1, result.BlockItems.Count(b => b is ActionBlockItem));
var actionBlockItem = result.BlockItems.OfType<ActionBlockItem>().First();
Assert.AreEqual(BlockAction.Hide, actionBlockItem.Action);
Assert.AreEqual(1, result.BlockItems.Count(b => b is DropLevelBlockItem));
var droplevelBlockItem = result.BlockItems.OfType<DropLevelBlockItem>().First();
Assert.AreEqual(67, droplevelBlockItem.FilterPredicate.PredicateOperand);
Assert.AreEqual(FilterPredicateOperator.GreaterThanOrEqual, droplevelBlockItem.FilterPredicate.PredicateOperator);
Assert.AreEqual(1, result.BlockItems.Count(b => b is RarityBlockItem));
var rarityBlockItem = result.BlockItems.OfType<RarityBlockItem>().First();
Assert.AreEqual(ItemRarity.Magic, (ItemRarity)rarityBlockItem.FilterPredicate.PredicateOperand);
}
[Test] [Test]
public void TranslateItemFilterBlockToString_NothingPopulated_ReturnsCorrectString() public void TranslateItemFilterBlockToString_NothingPopulated_ReturnsCorrectString()
{ {

View File

@ -56,7 +56,7 @@ namespace Filtration.Parser.Services
} }
var adjustedLine = line.Replace("#", " # "); var adjustedLine = line.Replace("#", " # ");
var trimmedLine = adjustedLine.TrimStart(' '); var trimmedLine = adjustedLine.TrimStart(' ').TrimEnd(' ');
var spaceOrEndOfLinePos = trimmedLine.IndexOf(" ", StringComparison.Ordinal) > 0 ? trimmedLine.IndexOf(" ", StringComparison.Ordinal) : trimmedLine.Length; var spaceOrEndOfLinePos = trimmedLine.IndexOf(" ", StringComparison.Ordinal) > 0 ? trimmedLine.IndexOf(" ", StringComparison.Ordinal) : trimmedLine.Length;
@ -104,6 +104,8 @@ namespace Filtration.Parser.Services
} }
case "Rarity": case "Rarity":
{ {
RemoveExistingBlockItemsOfType<RarityBlockItem>(block);
var blockItemValue = new RarityBlockItem(); var blockItemValue = new RarityBlockItem();
var result = Regex.Match(trimmedLine, @"^\w+\s+([><!=]{0,2})\s*(\w+)$"); var result = Regex.Match(trimmedLine, @"^\w+\s+([><!=]{0,2})\s*(\w+)$");
if (result.Groups.Count == 3) if (result.Groups.Count == 3)
@ -113,6 +115,7 @@ namespace Filtration.Parser.Services
blockItemValue.FilterPredicate.PredicateOperand = blockItemValue.FilterPredicate.PredicateOperand =
(int)EnumHelper.GetEnumValueFromDescription<ItemRarity>(result.Groups[2].Value); (int)EnumHelper.GetEnumValueFromDescription<ItemRarity>(result.Groups[2].Value);
} }
block.BlockItems.Add(blockItemValue); block.BlockItems.Add(blockItemValue);
break; break;
} }

View File

@ -1,13 +1,11 @@
A Mother's Parting Gift A Mother's Parting Gift
Abandoned Cavern Map Abandoned Cavern Map
Abandoned Cavern Map
Abandoned Wealth Abandoned Wealth
Abyss Map Abyss Map
Abyssal Axe Abyssal Axe
Abyssal Cry Abyssal Cry
Abyssal Sceptre Abyssal Sceptre
Academy Map Academy Map
Academy Map
Added Chaos Damage Support Added Chaos Damage Support
Added Cold Damage Support Added Cold Damage Support
Added Fire Damage Support Added Fire Damage Support
@ -47,24 +45,19 @@ Antique Rapier
Apex Rapier Apex Rapier
Aquamarine Flask Aquamarine Flask
Arachnid Nest Map Arachnid Nest Map
Arachnid Nest Map
Arc Arc
Arcade Map Arcade Map
Arcade Map
Arcanist Gloves Arcanist Gloves
Arcanist Slippers Arcanist Slippers
Archon Kite Shield Archon Kite Shield
Arctic Armour Arctic Armour
Arctic Armour
Arctic Breath Arctic Breath
Arena Map Arena Map
Arena Plate Arena Plate
Arid Lake Map Arid Lake Map
Arid Lake Map
Arming Axe Arming Axe
Armourer's Scrap Armourer's Scrap
Arsenal Map Arsenal Map
Arsenal Map
Ashscale Talisman Ashscale Talisman
Assassin Bow Assassin Bow
Assassin's Boots Assassin's Boots
@ -78,11 +71,6 @@ Auric Mace
Aventail Helmet Aventail Helmet
Avian Slippers Avian Slippers
Avian Twins Talisman Avian Twins Talisman
Avian Twins Talisman
Avian Twins Talisman
Avian Twins Talisman
Avian Twins Talisman
Avian Twins Talisman
Awl Awl
Backstab Backstab
Baleful Gem Baleful Gem
@ -104,7 +92,6 @@ Battle Lamellar
Battle Plate Battle Plate
Battle Sword Battle Sword
Bazaar Map Bazaar Map
Bazaar Map
Bear Trap Bear Trap
Behemoth Mace Behemoth Mace
Birth of the Three Birth of the Three
@ -133,7 +120,6 @@ Bloodlust Support
Blunt Arrow Quiver Blunt Arrow Quiver
Boarding Axe Boarding Axe
Bog Map Bog Map
Bog Map
Bone Armour Bone Armour
Bone Bow Bone Bow
Bone Circlet Bone Circlet
@ -141,23 +127,8 @@ Bone Offering
Bone Spirit Shield Bone Spirit Shield
Bonespire Talisman Bonespire Talisman
Book of Reform Book of Reform
Book of Reform
Book of Reform
Book of Reform
Book of Regression Book of Regression
Book of Regrets Book of Regrets
Book of Regrets
Book of Skill
Book of Skill
Book of Skill
Book of Skill
Book of Skill
Book of Skill
Book of Skill
Book of Skill
Book of Skill
Book of Skill
Book of Skill
Book of Skill Book of Skill
Boot Blade Boot Blade
Boot Knife Boot Knife
@ -190,7 +161,6 @@ Butcher Sword
Cabalist Regalia Cabalist Regalia
Callous Mask Callous Mask
Canyon Map Canyon Map
Canyon Map
Cardinal Round Shield Cardinal Round Shield
Carnal Armour Carnal Armour
Carnal Boots Carnal Boots
@ -206,13 +176,10 @@ Cast on Melee Kill Support
Cast when Damage Taken Support Cast when Damage Taken Support
Cast when Stunned Support Cast when Stunned Support
Catacomb Map Catacomb Map
Catacomb Map
Cat's Paw Cat's Paw
Caustic Arrow Caustic Arrow
Cedar Tower Shield Cedar Tower Shield
Cells Map Cells Map
Cells Map
Cemetery Map
Cemetery Map Cemetery Map
Ceremonial Axe Ceremonial Axe
Ceremonial Kite Shield Ceremonial Kite Shield
@ -257,7 +224,6 @@ Cold Penetration Support
Cold Snap Cold Snap
Cold to Fire Support Cold to Fire Support
Colonnade Map Colonnade Map
Colonnade Map
Colossal Hybrid Flask Colossal Hybrid Flask
Colossal Life Flask Colossal Life Flask
Colossal Mana Flask Colossal Mana Flask
@ -278,7 +244,6 @@ Conjurer Gloves
Conjurer's Vestment Conjurer's Vestment
Conquest Chainmail Conquest Chainmail
Conservatory Map Conservatory Map
Conservatory Map
Contagion Contagion
Controlled Destruction Support Controlled Destruction Support
Conversion Trap Conversion Trap
@ -298,12 +263,9 @@ Corrugated Buckler
Corsair Sword Corsair Sword
Courtesan Sword Courtesan Sword
Courtyard Map Courtyard Map
Courtyard Map
Coves Map
Coves Map Coves Map
Coveted Possession Coveted Possession
Crematorium Map Crematorium Map
Crematorium Map
Crescent Staff Crescent Staff
Crested Tower Shield Crested Tower Shield
Crimson Jewel Crimson Jewel
@ -318,7 +280,6 @@ Crusader Helmet
Crusader Plate Crusader Plate
Crypt Armour Crypt Armour
Crypt Map Crypt Map
Crypt Map
Crystal Sceptre Crystal Sceptre
Crystal Wand Crystal Wand
Cube Of Absorption Cube Of Absorption
@ -332,7 +293,6 @@ Cyclone
Dagger Axe Dagger Axe
Damage Infusion Damage Infusion
Dark Forest Map Dark Forest Map
Dark Forest Map
Darkwood Sceptre Darkwood Sceptre
Deadhand Talisman Deadhand Talisman
Death Death
@ -388,13 +348,9 @@ Driftwood Sceptre
Driftwood Spiked Shield Driftwood Spiked Shield
Driftwood Wand Driftwood Wand
Dry Peninsula Map Dry Peninsula Map
Dry Peninsula Map
Dry Woods Map
Dry Woods Map Dry Woods Map
Dual Strike Dual Strike
Dunes Map Dunes Map
Dunes Map
Dungeon Map
Dungeon Map Dungeon Map
Dusk Blade Dusk Blade
Dying Anguish Dying Anguish
@ -518,7 +474,6 @@ Gemstone Sword
General's Brigandine General's Brigandine
Generosity Support Generosity Support
Ghetto Map Ghetto Map
Ghetto Map
Giant Life Flask Giant Life Flask
Giant Mana Flask Giant Mana Flask
Gift of the Gemling Queen Gift of the Gemling Queen
@ -555,15 +510,11 @@ Golden Mantle
Golden Mask Golden Mask
Golden Obi Golden Obi
Golden Page Golden Page
Golden Page
Golden Page
Golden Page
Golden Plate Golden Plate
Golden Wreath Golden Wreath
Goliath Gauntlets Goliath Gauntlets
Goliath Greaves Goliath Greaves
Gorge Map Gorge Map
Gorge Map
Gouger Gouger
Grace Grace
Graceful Sword Graceful Sword
@ -573,7 +524,6 @@ Granite Flask
Grappler Grappler
Grave Knowledge Grave Knowledge
Graveyard Map Graveyard Map
Graveyard Map
Great Crown Great Crown
Great Helmet Great Helmet
Great Mallet Great Mallet
@ -584,7 +534,6 @@ Greater Multiple Projectiles Support
Greatwolf Talisman Greatwolf Talisman
Grinning Fetish Grinning Fetish
Grotto Map Grotto Map
Grotto Map
Ground Slam Ground Slam
Grove Bow Grove Bow
Gut Ripper Gut Ripper
@ -698,7 +647,6 @@ Jeweller's Orb
Jingling Spirit Shield Jingling Spirit Shield
Judgement Staff Judgement Staff
Jungle Valley Map Jungle Valley Map
Jungle Valley Map
Kaom's Greaves Kaom's Greaves
Kaom's Plate Kaom's Plate
Karui Axe Karui Axe
@ -810,8 +758,6 @@ Mirrored Spiked Shield
Molten Shell Molten Shell
Molten Strike Molten Strike
Monkey Paw Talisman Monkey Paw Talisman
Monkey Paw Talisman
Monkey Paw Talisman
Monkey Twins Talisman Monkey Twins Talisman
Moon Staff Moon Staff
Moonstone Ring Moonstone Ring
@ -822,20 +768,16 @@ Mortal Ignorance
Mortal Rage Mortal Rage
Mosaic Kite Shield Mosaic Kite Shield
Mountain Ledge Map Mountain Ledge Map
Mountain Ledge Map
Mud Geyser Map
Mud Geyser Map Mud Geyser Map
Multiple Traps Support Multiple Traps Support
Multistrike Support Multistrike Support
Murder Boots Murder Boots
Murder Mitts Murder Mitts
Museum Map Museum Map
Museum Map
Nailed Fist Nailed Fist
Necromancer Circlet Necromancer Circlet
Necromancer Silks Necromancer Silks
Necropolis Map Necropolis Map
Necropolis Map
New Shock Nova New Shock Nova
NewPunishment NewPunishment
Nightmare Bascinet Nightmare Bascinet
@ -867,14 +809,11 @@ Orb of Scouring
Orb of Storms Orb of Storms
Orb of Transmutation Orb of Transmutation
Orchard Map Orchard Map
Orchard Map
Ornate Mace Ornate Mace
Ornate Ringmail Ornate Ringmail
Ornate Spiked Shield Ornate Spiked Shield
Ornate Sword Ornate Sword
Overgrown Ruin Map Overgrown Ruin Map
Overgrown Ruin Map
Overgrown Shrine Map
Overgrown Shrine Map Overgrown Shrine Map
Padded Jacket Padded Jacket
Padded Vest Padded Vest
@ -882,7 +821,6 @@ Pagan Wand
Painted Buckler Painted Buckler
Painted Tower Shield Painted Tower Shield
Palace Map Palace Map
Palace Map
Paua Amulet Paua Amulet
Paua Ring Paua Ring
Pecoraro Pecoraro
@ -893,11 +831,9 @@ Petrified Club
Phantasmagoria Map Phantasmagoria Map
Phantom Mace Phantom Mace
Phase Run Phase Run
Phase Run
Physical Projectile Attack Damage Support Physical Projectile Attack Damage Support
Physical to Lightning Support Physical to Lightning Support
Pier Map Pier Map
Pier Map
Pierce Support Pierce Support
Pig-Faced Bascinet Pig-Faced Bascinet
Piledriver Piledriver
@ -908,7 +844,6 @@ Plague Mask
Plank Kite Shield Plank Kite Shield
Plate Vest Plate Vest
Plateau Map Plateau Map
Plateau Map
Plated Gauntlets Plated Gauntlets
Plated Greaves Plated Greaves
Plated Maul Plated Maul
@ -928,7 +863,6 @@ Power Charge On Critical Support
Power Siphon Power Siphon
Praetor Crown Praetor Crown
Precinct Map Precinct Map
Precinct Map
Prehistoric Claw Prehistoric Claw
Pride Before the Fall Pride Before the Fall
Primal Skull Talisman Primal Skull Talisman
@ -940,7 +874,6 @@ Prismatic Ring
Profane Wand Profane Wand
Projectile Weakness Projectile Weakness
Promenade Map Promenade Map
Promenade Map
Prong Dagger Prong Dagger
Prophecy Prophecy
Prophecy Wand Prophecy Wand
@ -982,7 +915,6 @@ Recurve Bow
Reduced Mana Support Reduced Mana Support
Redwood Spiked Shield Redwood Spiked Shield
Reef Map Reef Map
Reef Map
Reflex Bow Reflex Bow
Regal Orb Regal Orb
Regicide Mask Regicide Mask
@ -992,7 +924,6 @@ Reinforced Tower Shield
Rejuvenation Totem Rejuvenation Totem
Remote Mine Support Remote Mine Support
Residence Map Residence Map
Residence Map
Return Projectiles Support Return Projectiles Support
Ribbon Spool Ribbon Spool
Righteous Fire Righteous Fire
@ -1074,11 +1005,9 @@ Serpentine Staff
Serpentscale Boots Serpentscale Boots
Serpentscale Gauntlets Serpentscale Gauntlets
Serrated Arrow Quiver Serrated Arrow Quiver
Serrated Arrow Quiver
Serrated Foil Serrated Foil
Sewer Keys Sewer Keys
Sewer Map Sewer Map
Sewer Map
Shabby Jerkin Shabby Jerkin
Shackled Boots Shackled Boots
Shadow Axe Shadow Axe
@ -1095,15 +1024,12 @@ Sharktooth Arrow Quiver
Sharktooth Claw Sharktooth Claw
Shield Charge Shield Charge
Shipyard Map Shipyard Map
Shipyard Map
Shock Nova Shock Nova
Shockwave Totem Shockwave Totem
Shore Map Shore Map
Shore Map
Short Bow Short Bow
Shrapnel Shot Shrapnel Shot
Shrine Map Shrine Map
Shrine Map
Siege Axe Siege Axe
Siege Ballista Siege Ballista
Siege Helmet Siege Helmet
@ -1152,8 +1078,6 @@ Spectral Throw
Spell Echo Support Spell Echo Support
Spell Totem Support Spell Totem Support
Spider Forest Map Spider Forest Map
Spider Forest Map
Spider Lair Map
Spider Lair Map Spider Lair Map
Spidersilk Robe Spidersilk Robe
Spiked Bundle Spiked Bundle
@ -1173,7 +1097,6 @@ Split Arrow
Split Projectiles Support Split Projectiles Support
Splitnewt Talisman Splitnewt Talisman
Springs Map Springs Map
Springs Map
Stacked Deck Stacked Deck
Stag Sceptre Stag Sceptre
Static Strike Static Strike
@ -1194,7 +1117,6 @@ Stone Axe
Stone Hammer Stone Hammer
Storm Call Storm Call
Strand Map Strand Map
Strand Map
Strapped Boots Strapped Boots
Strapped Leather Strapped Leather
Strapped Mitts Strapped Mitts
@ -1221,11 +1143,9 @@ Teak Round Shield
Tempered Foil Tempered Foil
Tempest Shield Tempest Shield
Temple Map Temple Map
Temple Map
Temporal Chains Temporal Chains
Tenderizer Tenderizer
Terrace Map Terrace Map
Terrace Map
Terror Claw Terror Claw
Terror Maul Terror Maul
Thaumetic Emblem Thaumetic Emblem
@ -1338,7 +1258,6 @@ The Wolf's Shadow
The Wrath The Wrath
Thicket Bow Thicket Bow
Thicket Map Thicket Map
Thicket Map
Thief's Garb Thief's Garb
Thorium Spirit Shield Thorium Spirit Shield
Thorn Rapier Thorn Rapier
@ -1365,7 +1284,6 @@ Tornado Shot
Tornado Wand Tornado Wand
Torture Cage Torture Cage
Torture Chamber Map Torture Chamber Map
Torture Chamber Map
Totemic Maul Totemic Maul
Touch of God Touch of God
Tower Key Tower Key
@ -1385,8 +1303,6 @@ Tricorne
Trisula Trisula
Triumphant Lamellar Triumphant Lamellar
Tropical Island Map Tropical Island Map
Tropical Island Map
Tunnel Map
Tunnel Map Tunnel Map
Turn the Other Cheek Turn the Other Cheek
Turquoise Amulet Turquoise Amulet
@ -1396,12 +1312,8 @@ Twin Claw
Two-Handed Sword Two-Handed Sword
Two-Point Arrow Quiver Two-Point Arrow Quiver
Two-Stone Ring Two-Stone Ring
Two-Stone Ring
Two-Stone Ring
Tyrant's Sekhem Tyrant's Sekhem
Underground River Map Underground River Map
Underground River Map
Underground Sea Map
Underground Sea Map Underground Sea Map
Undying Flesh Talisman Undying Flesh Talisman
Unset Ring Unset Ring
@ -1440,7 +1352,6 @@ Vaal Molten Shell
Vaal Orb Vaal Orb
Vaal Power Siphon Vaal Power Siphon
Vaal Pyramid Map Vaal Pyramid Map
Vaal Pyramid Map
Vaal Rain of Arrows Vaal Rain of Arrows
Vaal Rapier Vaal Rapier
Vaal Reave Vaal Reave
@ -1454,7 +1365,6 @@ Vaal Storm Call
Vaal Summon Skeletons Vaal Summon Skeletons
Vaal Sweep Vaal Sweep
Vaal Temple Map Vaal Temple Map
Vaal Temple Map
Variscite Blade Variscite Blade
Varnished Coat Varnished Coat
Velvet Gloves Velvet Gloves
@ -1464,7 +1374,6 @@ Vial Of Power
Vigilant Strike Vigilant Strike
Vile Staff Vile Staff
Villa Map Villa Map
Villa Map
Village Ruin Map Village Ruin Map
Vine Circlet Vine Circlet
Vinia's Token Vinia's Token
@ -1490,7 +1399,6 @@ War Plate
War Sword War Sword
Warlord's Mark Warlord's Mark
Waste Pool Map Waste Pool Map
Waste Pool Map
Wasteland Map Wasteland Map
Waterways Map Waterways Map
Waxed Garb Waxed Garb
@ -1499,7 +1407,6 @@ Weapon Elemental Damage Support
Wereclaw Talisman Wereclaw Talisman
Whalebone Rapier Whalebone Rapier
Wharf Map Wharf Map
Wharf Map
Whirling Blades Whirling Blades
Widowsilk Robe Widowsilk Robe
Wild Leather Wild Leather