Item Generation
The ItemGeneratorGrain is a stateless worker that creates items with random properties.
Generation Process
Basic Generation
// Generate a rare iron sword at item level 50
var item = await generator.GenerateAsync("iron-sword", ItemRarity.Rare, 50);
Parameters
| Parameter | Description |
|---|---|
baseTypeId | Which base type to use |
rarity | Normal, Magic, Rare, or Unique |
itemLevel | Determines available modifier tiers |
Modifier Rolling
Magic Items (1-2 mods)
private async Task<List<Modifier>> RollMagicModsAsync(BaseType baseType, int itemLevel)
{
var mods = new List<Modifier>();
var count = Random.Shared.Next(1, 3); // 1 or 2
var prefixes = await GetEligibleModifiers(ModifierType.Prefix, baseType, itemLevel);
var suffixes = await GetEligibleModifiers(ModifierType.Suffix, baseType, itemLevel);
// Roll using weighted selection
if (Random.Shared.NextDouble() < 0.5 && prefixes.Any())
mods.Add(SelectWeighted(prefixes));
if (mods.Count < count && suffixes.Any())
mods.Add(SelectWeighted(suffixes));
return mods;
}
Rare Items (3-6 mods)
- Minimum 1 prefix and 1 suffix
- Maximum 3 prefixes and 3 suffixes
- Total 3-6 modifiers
Modifier Selection
Modifiers are selected using weighted random:
private Modifier SelectWeighted(List<Modifier> pool)
{
var totalWeight = pool.Sum(m => m.Weight);
var roll = Random.Shared.Next(totalWeight);
var cumulative = 0;
foreach (var mod in pool)
{
cumulative += mod.Weight;
if (roll < cumulative)
return mod;
}
return pool.Last();
}
Currency Orbs
Titan implements Path of Exile-style currency:
Transmutation Orb
Convert Normal → Magic:
public async Task<Item> TransmuteAsync(Item item)
{
if (item.Rarity != ItemRarity.Normal)
throw new InvalidOperationException("Can only transmute normal items");
var newItem = item with { Rarity = ItemRarity.Magic };
var mods = await RollMagicModsAsync(item.BaseType, item.ItemLevel);
return ApplyModifiers(newItem, mods);
}
Alteration Orb
Reroll Magic item modifiers:
public async Task<Item> AlterAsync(Item item)
{
if (item.Rarity != ItemRarity.Magic)
throw new InvalidOperationException("Can only alter magic items");
var mods = await RollMagicModsAsync(item.BaseType, item.ItemLevel);
return item with { Prefixes = mods.OfType<Prefix>(), Suffixes = mods.OfType<Suffix>() };
}
Regal Orb
Convert Magic → Rare (add 1 modifier):
public async Task<Item> RegalAsync(Item item)
{
if (item.Rarity != ItemRarity.Magic)
throw new InvalidOperationException("Can only regal magic items");
var pool = await GetEligibleModifiers(item);
var newMod = SelectWeighted(pool);
return item with
{
Rarity = ItemRarity.Rare,
Prefixes = item.Prefixes.Append(newMod).Where(m => m.Type == Prefix),
Suffixes = item.Suffixes.Append(newMod).Where(m => m.Type == Suffix)
};
}
Chaos Orb
Reroll all modifiers on a Rare item:
public async Task<Item> ChaosAsync(Item item)
{
if (item.Rarity != ItemRarity.Rare)
throw new InvalidOperationException("Can only chaos rare items");
var mods = await RollRareModsAsync(item.BaseType, item.ItemLevel);
return ApplyModifiers(item, mods);
}
Exalted Orb
Add one modifier to a Rare item:
public async Task<Item> ExaltAsync(Item item)
{
if (item.Rarity != ItemRarity.Rare)
throw new InvalidOperationException("Can only exalt rare items");
if (item.Prefixes.Count >= 3 && item.Suffixes.Count >= 3)
throw new InvalidOperationException("Item is full (6 mods)");
var pool = await GetEligibleModifiers(item);
var newMod = SelectWeighted(pool);
return AddModifier(item, newMod);
}
Socket Rolling
Jeweller's Orb
Reroll socket count:
public async Task<Item> JewellerAsync(Item item)
{
var maxSockets = GetMaxSockets(item.BaseType);
var newCount = RollSocketCount(maxSockets);
return item with { Sockets = GenerateSockets(newCount) };
}
Fusing Orb
Reroll socket links:
public async Task<Item> FusingAsync(Item item)
{
var sockets = item.Sockets.ToList();
for (int i = 0; i < sockets.Count - 1; i++)
{
sockets[i] = sockets[i] with { Linked = Random.Shared.NextDouble() < 0.3 };
}
return item with { Sockets = sockets };
}
Chromatic Orb
Reroll socket colors:
public async Task<Item> ChromaticAsync(Item item)
{
var requirements = item.BaseType.Requirements;
var sockets = item.Sockets.Select(s => s with
{
Color = RollSocketColor(requirements)
});
return item with { Sockets = sockets.ToList() };
}
Socket colors are weighted by attribute requirements:
- High Strength → More Red
- High Dexterity → More Green
- High Intelligence → More Blue
Unique Items
Uniques have fixed modifiers defined in the registry:
public async Task<Item> GenerateUniqueAsync(string uniqueId)
{
var unique = await _registry.GetUniqueAsync(uniqueId);
return new Item
{
BaseTypeId = unique.BaseTypeId,
Name = unique.Name,
Rarity = ItemRarity.Unique,
Prefixes = unique.FixedPrefixes,
Suffixes = unique.FixedSuffixes,
Implicits = unique.Implicits
};
}