using System;
using ACE.Common;
using ACE.Database.Models.World;
using ACE.Entity.Enum;
using ACE.Server.Factories.Entity;
using ACE.Server.Factories.Tables;
using ACE.Server.WorldObjects;
namespace ACE.Server.Factories
{
public static partial class LootGenerationFactory
{
private static void AssignMagic(WorldObject wo, TreasureDeath profile, TreasureRoll roll, bool isArmor = false)
{
AssignSpells(wo, profile, roll);
wo.UiEffects = UiEffects.Magical;
var maxBaseMana = GetMaxBaseMana(wo);
wo.ManaRate = CalculateManaRate(maxBaseMana);
var maxSpellMana = maxBaseMana;
if (wo.SpellDID != null)
{
var spell = new Server.Entity.Spell(wo.SpellDID.Value);
var castableMana = (int)spell.BaseMana * 5;
if (castableMana > maxSpellMana)
maxSpellMana = castableMana;
}
wo.ItemMaxMana = RollItemMaxMana(wo, roll, maxSpellMana);
wo.ItemCurMana = wo.ItemMaxMana;
wo.ItemSpellcraft = RollSpellcraft(wo, roll);
AddActivationRequirements(wo, roll);
}
///
/// Returns the maximum BaseMana from the spells in item's spellbook
///
private static int GetMaxBaseMana(WorldObject wo)
{
var maxBaseMana = 0;
if (wo.Biota.PropertiesSpellBook != null)
{
foreach (var spellId in wo.Biota.PropertiesSpellBook.Keys)
{
var spell = new Server.Entity.Spell(spellId);
if (spell.BaseMana > maxBaseMana)
maxBaseMana = (int)spell.BaseMana;
}
}
return maxBaseMana;
}
///
/// Rolls the ItemMaxMana for an object
///
private static int RollItemMaxMana(WorldObject wo, TreasureRoll roll, int maxSpellMana)
{
// verified matches up with magloot eor logs
var workmanship = WorkmanshipChance.GetModifier(wo.ItemWorkmanship - 1);
(int min, int max) range;
if (roll.IsClothing || roll.IsArmor || roll.IsWeapon || roll.IsDinnerware)
{
range.min = 6;
range.max = 15;
}
else if (roll.IsJewelry)
{
// includes crowns
range.min = 12;
range.max = 20;
}
else if (roll.IsGem)
{
range.min = 1;
range.max = 1;
}
else
{
log.Error($"RollItemMaxMana({wo.Name}, {roll.ItemType}, {maxSpellMana}) - unknown item type");
return 1;
}
var rng = ThreadSafeRandom.Next(range.min, range.max);
return (int)Math.Ceiling(maxSpellMana * workmanship * rng);
}
///
/// Calculates the ManaRate for an item
///
private static float CalculateManaRate(int maxBaseMana)
{
if (maxBaseMana <= 0)
maxBaseMana = 1;
// verified with eor data
return -1.0f / (float)Math.Ceiling(1200.0f / maxBaseMana);
}
private static int RollSpellcraft(WorldObject wo, TreasureRoll roll)
{
var maxSpellPower = GetMaxSpellPower(wo);
(float min, float max) range = (1.0f, 1.0f);
if (roll.IsClothing || roll.IsArmor || roll.IsWeapon || roll.IsJewelry || roll.IsDinnerware)
{
range.min = 0.9f;
range.max = 1.1f;
}
else if (!roll.IsGem)
{
log.Error($"RollSpellcraft({wo.Name}, {roll.ItemType}) - unknown item type");
}
var rng = ThreadSafeRandom.Next(range.min, range.max);
var spellcraft = (int)Math.Ceiling(maxSpellPower * rng);
// retail was capped at 370
spellcraft = Math.Min(spellcraft, 370);
return spellcraft;
}
///
/// Returns the maximum power from the spells in item's SpellDID / spellbook
///
private static int GetMaxSpellPower(WorldObject wo)
{
var maxSpellPower = 0;
if (wo.SpellDID != null)
{
var spell = new Server.Entity.Spell(wo.SpellDID.Value);
if (spell.Power > maxSpellPower)
maxSpellPower = (int)spell.Power;
}
if (wo.Biota.PropertiesSpellBook != null)
{
foreach (var spellId in wo.Biota.PropertiesSpellBook.Keys)
{
var spell = new Server.Entity.Spell(spellId);
if (spell.Power > maxSpellPower)
maxSpellPower = (int)spell.Power;
}
}
return maxSpellPower;
}
private static void AddActivationRequirements(WorldObject wo, TreasureRoll roll)
{
// ItemSkill/LevelLimit
TryMutate_ItemSkillLimit(wo, roll);
// Arcane Lore / ItemDifficulty
wo.ItemDifficulty = CalculateArcaneLore(wo, roll);
}
private static bool TryMutate_ItemSkillLimit(WorldObject wo, TreasureRoll roll)
{
if (!RollItemSkillLimit(roll))
return false;
wo.ItemSkillLevelLimit = wo.ItemSpellcraft + 20;
var skill = Skill.None;
if (roll.IsMeleeWeapon || roll.IsMissileWeapon)
{
skill = wo.WeaponSkill;
}
else if (roll.IsArmor)
{
var rng = ThreadSafeRandom.Next(0.0f, 1.0f);
if (rng < 0.5f)
{
skill = Skill.MeleeDefense;
}
else
{
skill = Skill.MissileDefense;
wo.ItemSkillLevelLimit = (int)(wo.ItemSkillLevelLimit * 0.7f);
}
}
else
{
log.Error($"RollItemSkillLimit({wo.Name}, {roll.ItemType}) - unknown item type");
return false;
}
wo.ItemSkillLimit = skill;
return true;
}
private static bool RollItemSkillLimit(TreasureRoll roll)
{
if (roll.IsMeleeWeapon || roll.IsMissileWeapon)
{
return true;
}
else if (roll.IsArmor)
{
var rng = ThreadSafeRandom.Next(0.0f, 1.0f);
return rng < 0.55f;
}
return false;
}
///
/// Calculates the Arcane Lore requirement / ItemDifficulty
///
private static int CalculateArcaneLore(WorldObject wo, TreasureRoll roll)
{
// spellcraft - (itemSkillLevelLimit / 2.0f) + creatureLifeEnchantments + cantrips
var spellcraft = wo.ItemSpellcraft.Value;
// - mutates 100% of the time for melee / missile weapons
// - mutates 55% of the time for armor
// - mutates 0% of the time for all other item types
var itemSkillLevelFactor = 0.0f;
if (wo.ItemSkillLevelLimit > 0)
itemSkillLevelFactor = wo.ItemSkillLevelLimit.Value / 2.0f;
var fArcane = spellcraft - itemSkillLevelFactor;
if (fArcane < 0)
fArcane = 0;
return (int)Math.Floor(fArcane + roll.ItemDifficulty);
}
}
}