public static void ApplyComponentBonus(NWItem product, ItemProperty sourceIP)
        {
            ComponentBonusType bonusType = (ComponentBonusType)_.GetItemPropertySubType(sourceIP);
            int          amount          = _.GetItemPropertyCostTableValue(sourceIP);
            ItemProperty prop            = null;
            string       sourceTag       = string.Empty;

            // A note about the sourceTags:
            // It's not currently possible to create custom item properties on items. To get around this,
            // we look in an inaccessible container which holds the custom item properties. Then, we get the
            // item that has the item property we want. From there we take that item property and copy it to
            // the crafted item.
            // This is a really roundabout way to do it, but it's the only option for now. Hopefully a feature to
            // directly add the item properties comes in to NWNX in the future.
            for (int x = 1; x <= amount; x++)
            {
                switch (bonusType)
                {
                case ComponentBonusType.ModSocketRed:
                    sourceTag = "rslot_red";
                    break;

                case ComponentBonusType.ModSocketBlue:
                    sourceTag = "rslot_blue";
                    break;

                case ComponentBonusType.ModSocketGreen:
                    sourceTag = "rslot_green";
                    break;

                case ComponentBonusType.ModSocketYellow:
                    sourceTag = "rslot_yellow";
                    break;

                case ComponentBonusType.ModSocketPrismatic:
                    sourceTag = "rslot_prismatic";
                    break;

                case ComponentBonusType.DurabilityUp:
                    var maxDur = DurabilityService.GetMaxDurability(product) + amount;
                    DurabilityService.SetMaxDurability(product, maxDur);
                    DurabilityService.SetDurability(product, maxDur);
                    break;

                case ComponentBonusType.ChargesUp:
                    product.Charges += amount;
                    break;

                case ComponentBonusType.ACUp:
                    product.CustomAC += amount;
                    break;

                case ComponentBonusType.HarvestingUp:
                    product.HarvestingBonus += amount;
                    break;

                case ComponentBonusType.CastingSpeedUp:
                    product.CastingSpeed += amount;
                    break;

                case ComponentBonusType.ArmorsmithUp:
                    product.CraftBonusArmorsmith += amount;
                    break;

                case ComponentBonusType.WeaponsmithUp:
                    product.CraftBonusWeaponsmith += amount;
                    break;

                case ComponentBonusType.CookingUp:
                    product.CraftBonusCooking += amount;
                    break;

                case ComponentBonusType.EngineeringUp:
                    product.CraftBonusEngineering += amount;
                    break;

                case ComponentBonusType.FabricationUp:
                    product.CraftBonusFabrication += amount;
                    break;

                case ComponentBonusType.HPUp:
                    product.HPBonus += amount;
                    break;

                case ComponentBonusType.FPUp:
                    product.FPBonus += amount;
                    break;

                case ComponentBonusType.EnmityUp:
                    product.EnmityRate += amount;
                    break;

                case ComponentBonusType.EnmityDown:
                    product.EnmityRate -= amount;
                    break;

                case ComponentBonusType.DarkPotencyUp:
                    product.DarkPotencyBonus += amount;
                    break;

                case ComponentBonusType.LightPotencyUp:
                    product.LightPotencyBonus += amount;
                    break;

                case ComponentBonusType.MindPotencyUp:
                    product.MindPotencyBonus += amount;
                    break;

                case ComponentBonusType.LuckUp:
                    product.LuckBonus += amount;
                    break;

                case ComponentBonusType.MeditateUp:
                    product.MeditateBonus += amount;
                    break;

                case ComponentBonusType.RestUp:
                    product.RestBonus += amount;
                    break;

                case ComponentBonusType.MedicineUp:
                    product.MedicineBonus += amount;
                    break;

                case ComponentBonusType.HPRegenUp:
                    product.HPRegenBonus += amount;
                    break;

                case ComponentBonusType.FPRegenUp:
                    product.FPRegenBonus += amount;
                    break;

                case ComponentBonusType.BaseAttackBonusUp:
                    product.BaseAttackBonus += amount;
                    break;

                case ComponentBonusType.SneakAttackUp:
                    product.SneakAttackBonus += amount;
                    break;

                case ComponentBonusType.DamageUp:
                    product.DamageBonus += amount;
                    break;

                case ComponentBonusType.DarkPotencyDown:
                    product.DarkPotencyBonus -= amount;
                    break;

                case ComponentBonusType.LightPotencyDown:
                    product.LightPotencyBonus -= amount;
                    break;

                case ComponentBonusType.StructureBonusUp:
                    product.StructureBonus += amount;
                    break;

                case ComponentBonusType.StrengthUp:
                    product.StrengthBonus += amount;
                    break;

                case ComponentBonusType.DexterityUp:
                    product.DexterityBonus += amount;
                    break;

                case ComponentBonusType.ConstitutionUp:
                    product.ConstitutionBonus += amount;
                    break;

                case ComponentBonusType.WisdomUp:
                    product.WisdomBonus += amount;
                    break;

                case ComponentBonusType.IntelligenceUp:
                    product.IntelligenceBonus += amount;
                    break;

                case ComponentBonusType.CharismaUp:
                    product.CharismaBonus += amount;
                    break;

                case ComponentBonusType.AttackBonusUp:
                    prop = _.ItemPropertyAttackBonus(amount);
                    break;

                case ComponentBonusType.DurationUp:
                    product.DurationBonus += amount;
                    break;

                case ComponentBonusType.ScanningUp:
                    product.ScanningBonus += amount;
                    break;

                case ComponentBonusType.ScavengingUp:
                    product.ScavengingBonus += amount;
                    break;

                case ComponentBonusType.MindPotencyDown:
                    product.MindPotencyBonus -= amount;
                    break;

                case ComponentBonusType.ElectricalPotencyUp:
                    product.ElectricalPotencyBonus += amount;
                    break;

                case ComponentBonusType.ElectricalPotencyDown:
                    product.ElectricalPotencyBonus -= amount;
                    break;

                case ComponentBonusType.ForcePotencyUp:
                    product.ForcePotencyBonus += amount;
                    break;

                case ComponentBonusType.ForcePotencyDown:
                    product.ForcePotencyBonus -= amount;
                    break;

                case ComponentBonusType.ForceAccuracyUp:
                    product.ForceAccuracyBonus += amount;
                    break;

                case ComponentBonusType.ForceAccuracyDown:
                    product.ForceAccuracyBonus -= amount;
                    break;

                case ComponentBonusType.ForceDefenseUp:
                    product.ForceDefenseBonus += amount;
                    break;

                case ComponentBonusType.ForceDefenseDown:
                    product.ForceDefenseBonus -= amount;
                    break;

                case ComponentBonusType.ElectricalDefenseUp:
                    product.ElectricalDefenseBonus += amount;
                    break;

                case ComponentBonusType.ElectricalDefenseDown:
                    product.ElectricalDefenseBonus -= amount;
                    break;

                case ComponentBonusType.MindDefenseUp:
                    product.MindDefenseBonus += amount;
                    break;

                case ComponentBonusType.MindDefenseDown:
                    product.MindDefenseBonus -= amount;
                    break;

                case ComponentBonusType.LightDefenseUp:
                    product.LightDefenseBonus += amount;
                    break;

                case ComponentBonusType.LightDefenseDown:
                    product.LightDefenseBonus -= amount;
                    break;

                case ComponentBonusType.DarkDefenseUp:
                    product.DarkDefenseBonus += amount;
                    break;

                case ComponentBonusType.DarkDefenseDown:
                    product.DarkDefenseBonus -= amount;
                    break;

                case ComponentBonusType.PilotingUp:
                    product.PilotingBonus += amount;
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                if (!string.IsNullOrWhiteSpace(sourceTag))
                {
                    prop = ItemService.GetCustomItemPropertyByItemTag(sourceTag);
                }

                if (prop == null)
                {
                    return;
                }

                BiowareXP2.IPSafeAddItemProperty(product, prop, 0.0f, AddItemPropertyPolicy.IgnoreExisting, true, true);
            }
        }
예제 #2
0
        private void OnCompleteSmelt(OnCompleteSmelt data)
        {
            NWPlayer            player         = data.Player;
            string              oreResref      = data.OreResref;
            List <ItemProperty> itemProperties = data.ItemProperties;

            player.IsBusy = false;

            int    rank        = SkillService.GetPCSkillRank(player, SkillType.Harvesting);
            int    level       = CraftService.GetIngotLevel(oreResref);
            string ingotResref = CraftService.GetIngotResref(oreResref);

            if (level < 0 || string.IsNullOrWhiteSpace(ingotResref))
            {
                return;
            }

            int delta = rank - level;
            int count = 2;

            if (delta > 2)
            {
                count = delta;
            }
            if (count > 4)
            {
                count = 4;
            }

            if (RandomService.Random(100) + 1 <= PerkService.GetCreaturePerkLevel(player, PerkType.Lucky))
            {
                count++;
            }

            if (RandomService.Random(100) + 1 <= PerkService.GetCreaturePerkLevel(player, PerkType.ProcessingEfficiency) * 10)
            {
                count++;
            }

            for (int x = 1; x <= count; x++)
            {
                var item = (_.CreateItemOnObject(ingotResref, player.Object));
                int chance;

                switch (x)
                {
                case 1:
                case 2:
                    chance = 100;
                    break;

                case 3:
                    chance = 70;
                    break;

                case 4:
                    chance = 60;
                    break;

                case 5:
                    chance = 50;
                    break;

                default:
                    chance = 30;
                    break;
                }

                foreach (var ip in itemProperties)
                {
                    if (RandomService.D100(1) <= chance)
                    {
                        BiowareXP2.IPSafeAddItemProperty(item, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, true, true);
                    }
                }
            }

            var effectiveStats   = PlayerStatService.GetPlayerItemEffectiveStats(player);
            int harvestingSkill  = SkillService.GetPCSkillRank(player, SkillType.Harvesting);
            int perkBonus        = PerkService.GetCreaturePerkLevel(player, PerkType.StronidiumRefining) + 1;
            int stronidiumAmount = 10 + effectiveStats.Harvesting + harvestingSkill + RandomService.Random(1, 5);

            stronidiumAmount *= perkBonus;
            _.CreateItemOnObject("stronidium", player.Object, stronidiumAmount);

            int xp = (int)SkillService.CalculateRegisteredSkillLevelAdjustedXP(100, level, rank);

            SkillService.GiveSkillXP(player, SkillType.Harvesting, xp);
        }
예제 #3
0
        private Tuple <int, float> RunComponentBonusAttempt(NWPlayer player, NWItem component, float equipmentBonus, float chance, List <NWItem> itemSet)
        {
            int successAmount = 0;

            // Note - this line MUST be outside the foreach loop, as inspecting component properties will reset the component.ItemProperties counter.
            int componentLevel = component.LevelIncrease > 0 ? component.LevelIncrease : component.RecommendedLevel;

            if (componentLevel < 1)
            {
                componentLevel = 1;
            }
            foreach (var ip in component.ItemProperties)
            {
                int ipType = _.GetItemPropertyType(ip);
                if (ipType != (int)CustomItemPropertyType.ComponentBonus)
                {
                    continue;
                }

                int    bonusTypeID            = _.GetItemPropertySubType(ip);
                int    tlkID                  = Convert.ToInt32(_.Get2DAString("iprp_compbon", "Name", bonusTypeID));
                int    amount                 = _.GetItemPropertyCostTableValue(ip);
                string bonusName              = _.GetStringByStrRef(tlkID) + " " + amount;
                float  random                 = RandomService.RandomFloat() * 100.0f;
                float  modifiedEquipmentBonus = equipmentBonus * 0.25f;

                if (random <= chance + modifiedEquipmentBonus)
                {
                    foreach (var item in itemSet)
                    {
                        // If the target item is a component itself, we want to add the component bonuses instead of the
                        // actual item property bonuses.
                        // In other words, we want the custom item property "Component Bonus: AC UP" instead of the "AC Bonus" item property.
                        var componentIP = item.ItemProperties.FirstOrDefault(x => _.GetItemPropertyType(x) == (int)CustomItemPropertyType.ComponentType);
                        if (componentIP == null)
                        {
                            ComponentBonusService.ApplyComponentBonus(item, ip);
                        }
                        else
                        {
                            BiowareXP2.IPSafeAddItemProperty(item, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, false, false);
                        }
                    }
                    player.SendMessage(ColorTokenService.Green("Successfully applied component property: " + bonusName));

                    ComponentBonusType bonusType = (ComponentBonusType)_.GetItemPropertySubType(ip);
                    if (bonusType != ComponentBonusType.DurabilityUp)
                    {
                        // Durability bonuses don't increase the penalty.  Higher level components transfer multiple
                        // properties more easily (to balance the fact that you can fit fewer of them on an item).
                        int penalty;
                        switch (componentLevel)
                        {
                        case 1:
                            penalty = RandomService.Random(1, 19);
                            break;

                        case 2:
                            penalty = RandomService.Random(1, 9);
                            break;

                        case 3:
                            penalty = RandomService.Random(1, 6);
                            break;

                        case 4:
                            penalty = RandomService.Random(1, 4);
                            break;

                        default:
                            penalty = RandomService.Random(1, 3);
                            break;
                        }
                        chance -= penalty;
                        if (chance < 1)
                        {
                            chance = 1;
                        }
                    }

                    successAmount++;
                }
                else
                {
                    player.SendMessage(ColorTokenService.Red("Failed to apply component property: " + bonusName));
                }
            }

            return(new Tuple <int, float>(successAmount, chance));
        }
예제 #4
0
        private int ProcessProperty(int amount, int maxBonuses, ComponentBonusType bonus, float levelsPerBonus = 1.0f)
        {
            string resref  = _componentType.ReassembledResref;
            int    penalty = 0;
            int    luck    = PerkService.GetCreaturePerkLevel(_player, PerkType.Lucky) + (_playerItemStats.Luck / 3);
            int    xp      = 0;

            ItemPropertyUnpacked bonusIP = new ItemPropertyUnpacked
            {
                Property       = (int)ItemPropertyType.ComponentBonus,
                SubType        = (int)bonus,
                CostTable      = 62,
                CostTableValue = 0,
                Param1         = 255,
                Param1Value    = 0,
                UsesPerDay     = 255,
                ChanceToAppear = 100,
                IsUseable      = true,
                SpellID        = -1
            };

            while (amount > 0)
            {
                int chanceToTransfer = CraftService.CalculateReassemblyChance(_player, penalty);
                // Roll to see if the item can be created.
                bool success = RandomService.Random(0, 100) <= chanceToTransfer;

                // Do a lucky roll if we failed the first time.
                if (!success && luck > 0 && RandomService.Random(0, 100) <= luck)
                {
                    _player.SendMessage("Lucky reassemble!");
                    success = true;
                }

                if (amount >= maxBonuses)
                {
                    if (success)
                    {
                        int levelIncrease = (int)(maxBonuses * levelsPerBonus);
                        // Roll succeeded. Create item.
                        bonusIP.CostTableValue = maxBonuses;
                        ItemProperty bonusIPPacked = NWNXItemProperty.PackIP(bonusIP);
                        NWItem       item          = _.CreateItemOnObject(resref, _player);
                        item.RecommendedLevel = levelIncrease;
                        BiowareXP2.IPSafeAddItemProperty(item, bonusIPPacked, 0.0f, AddItemPropertyPolicy.ReplaceExisting, true, false);

                        xp += (150 * maxBonuses + RandomService.Random(0, 5));
                    }
                    else
                    {
                        _player.SendMessage(ColorTokenService.Red("You failed to create a component. (+" + maxBonuses + ")"));
                        xp += (50 + RandomService.Random(0, 5));
                    }
                    // Penalty to chance increases regardless if item was created or not.
                    penalty += (maxBonuses * 5);
                    amount  -= maxBonuses;
                }
                else
                {
                    if (success)
                    {
                        int levelIncrease = (int)(amount * levelsPerBonus);
                        bonusIP.CostTableValue = amount;
                        ItemProperty bonusIPPacked = NWNXItemProperty.PackIP(bonusIP);
                        NWItem       item          = _.CreateItemOnObject(resref, _player);
                        item.RecommendedLevel = levelIncrease;
                        BiowareXP2.IPSafeAddItemProperty(item, bonusIPPacked, 0.0f, AddItemPropertyPolicy.ReplaceExisting, true, false);

                        xp += (150 * amount + RandomService.Random(0, 5));
                    }
                    else
                    {
                        _player.SendMessage(ColorTokenService.Red("You failed to create a component. (+" + amount + ")"));
                        xp += (50 + RandomService.Random(0, 5));
                    }
                    break;
                }
            }

            return(xp);
        }
예제 #5
0
        public void ApplyEffects(NWCreature user, NWItem item, NWObject target, Location targetLocation, CustomData customData)
        {
            NWPlayer        player        = user.Object;
            ResourceQuality quality       = (ResourceQuality)target.GetLocalInt("RESOURCE_QUALITY");
            int             tier          = target.GetLocalInt("RESOURCE_TIER");
            int             remaining     = target.GetLocalInt("RESOURCE_COUNT") - 1;
            string          itemResref    = target.GetLocalString("RESOURCE_RESREF");
            int             ipBonusChance = ResourceService.CalculateChanceForComponentBonus(player, tier, quality);
            int             roll          = RandomService.Random(1, 100);
            int             rank          = SkillService.GetPCSkillRank(player, SkillType.Harvesting);

            if (item.RecommendedLevel < rank)
            {
                rank = item.RecommendedLevel;
            }

            int difficulty = (tier - 1) * 10 + ResourceService.GetDifficultyAdjustment(quality);
            int delta      = difficulty - rank;

            int baseXP = 0;

            if (delta >= 6)
            {
                baseXP = 400;
            }
            else if (delta == 5)
            {
                baseXP = 350;
            }
            else if (delta == 4)
            {
                baseXP = 325;
            }
            else if (delta == 3)
            {
                baseXP = 300;
            }
            else if (delta == 2)
            {
                baseXP = 250;
            }
            else if (delta == 1)
            {
                baseXP = 225;
            }
            else if (delta == 0)
            {
                baseXP = 200;
            }
            else if (delta == -1)
            {
                baseXP = 150;
            }
            else if (delta == -2)
            {
                baseXP = 100;
            }
            else if (delta == -3)
            {
                baseXP = 50;
            }
            else if (delta == -4)
            {
                baseXP = 25;
            }

            int itemHarvestBonus = item.HarvestingBonus;
            int scanningBonus    = user.GetLocalInt(target.GlobalID.ToString());

            ipBonusChance += itemHarvestBonus * 2 + scanningBonus * 2;

            baseXP = baseXP + scanningBonus * 5;

            NWItem resource = _.CreateItemOnObject(itemResref, player.Object);

            if (roll <= ipBonusChance)
            {
                var ip = ResourceService.GetRandomComponentBonusIP(quality);
                BiowareXP2.IPSafeAddItemProperty(resource, ip.Item1, 0.0f, AddItemPropertyPolicy.IgnoreExisting, true, true);

                switch (ip.Item2)
                {
                case 0:
                    resource.Name = ColorTokenService.Green(resource.Name);
                    break;

                case 1:
                    resource.Name = ColorTokenService.Blue(resource.Name);
                    break;

                case 2:
                    resource.Name = ColorTokenService.Purple(resource.Name);
                    break;

                case 3:
                    resource.Name = ColorTokenService.Orange(resource.Name);
                    break;
                }
            }

            float decayMinimum = 0.03f;
            float decayMaximum = 0.07f;

            if (delta > 0)
            {
                decayMinimum += delta * 0.1f;
                decayMaximum += delta * 0.1f;
            }

            user.SendMessage("You harvest " + resource.Name + ".");
            DurabilityService.RunItemDecay(player, item, RandomService.RandomFloat(decayMinimum, decayMaximum));
            int xp = baseXP;

            SkillService.GiveSkillXP(player, SkillType.Harvesting, xp);

            if (remaining <= 0)
            {
                NWPlaceable prop = target.GetLocalObject("RESOURCE_PROP_OBJ");

                if (prop.IsValid)
                {
                    prop.Destroy();
                }

                target.Destroy();
                user.DeleteLocalInt(target.GlobalID.ToString());
            }
            else
            {
                target.SetLocalInt("RESOURCE_COUNT", remaining);
            }

            _.ApplyEffectAtLocation(DURATION_TYPE_INSTANT, _.EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3), target.Location);
        }
예제 #6
0
        public static void ApplyComponentBonus(NWItem product, ItemProperty sourceIP)
        {
            ComponentBonusType bonusType = (ComponentBonusType)_.GetItemPropertySubType(sourceIP);
            int          amount          = _.GetItemPropertyCostTableValue(sourceIP);
            ItemProperty prop            = null;
            string       sourceTag       = string.Empty;
            int          attackBonus     = 0;

            // A note about the sourceTags:
            // It's not currently possible to create custom item properties on items. To get around this,
            // we look in an inaccessible container which holds the custom item properties. Then, we get the
            // item that has the item property we want. From there we take that item property and copy it to
            // the crafted item.
            // This is a really roundabout way to do it, but it's the only option for now. Hopefully a feature to
            // directly add the item properties comes in to NWNX in the future.
            // 2019-06-12: Directly modifying item properties is possible now but I'm not going to do a refactor until later.
            //             Anyone interested in working on this let me know and I can point you in the right direction. - Z
            for (int x = 1; x <= amount; x++)
            {
                switch (bonusType)
                {
                case ComponentBonusType.ModSocketRed:
                    sourceTag = "rslot_red";
                    break;

                case ComponentBonusType.ModSocketBlue:
                    sourceTag = "rslot_blue";
                    break;

                case ComponentBonusType.ModSocketGreen:
                    sourceTag = "rslot_green";
                    break;

                case ComponentBonusType.ModSocketYellow:
                    sourceTag = "rslot_yellow";
                    break;

                case ComponentBonusType.ModSocketPrismatic:
                    sourceTag = "rslot_prismatic";
                    break;

                case ComponentBonusType.DurabilityUp:
                    var maxDur = DurabilityService.GetMaxDurability(product) + amount;
                    DurabilityService.SetMaxDurability(product, maxDur);
                    DurabilityService.SetDurability(product, maxDur);
                    break;

                case ComponentBonusType.ChargesUp:
                    product.Charges += amount;
                    break;

                case ComponentBonusType.ACUp:
                    product.CustomAC += amount;
                    break;

                case ComponentBonusType.HarvestingUp:
                    product.HarvestingBonus += amount;
                    break;

                case ComponentBonusType.CooldownRecoveryUp:
                    product.CooldownRecovery += amount;
                    break;

                case ComponentBonusType.ArmorsmithUp:
                    product.CraftBonusArmorsmith += amount;
                    break;

                case ComponentBonusType.WeaponsmithUp:
                    product.CraftBonusWeaponsmith += amount;
                    break;

                case ComponentBonusType.CookingUp:
                    product.CraftBonusCooking += amount;
                    break;

                case ComponentBonusType.EngineeringUp:
                    product.CraftBonusEngineering += amount;
                    break;

                case ComponentBonusType.FabricationUp:
                    product.CraftBonusFabrication += amount;
                    break;

                case ComponentBonusType.HPUp:
                    product.HPBonus += amount;
                    break;

                case ComponentBonusType.FPUp:
                    product.FPBonus += amount;
                    break;

                case ComponentBonusType.EnmityUp:
                    product.EnmityRate += amount;
                    break;

                case ComponentBonusType.EnmityDown:
                    product.EnmityRate -= amount;
                    break;

                case ComponentBonusType.LuckUp:
                    product.LuckBonus += amount;
                    break;

                case ComponentBonusType.MeditateUp:
                    product.MeditateBonus += amount;
                    break;

                case ComponentBonusType.RestUp:
                    product.RestBonus += amount;
                    break;

                case ComponentBonusType.MedicineUp:
                    product.MedicineBonus += amount;
                    break;

                case ComponentBonusType.HPRegenUp:
                    product.HPRegenBonus += amount;
                    break;

                case ComponentBonusType.FPRegenUp:
                    product.FPRegenBonus += amount;
                    break;

                case ComponentBonusType.BaseAttackBonusUp:
                    product.BaseAttackBonus += amount;
                    break;

                case ComponentBonusType.SneakAttackUp:
                    product.SneakAttackBonus += amount;
                    break;

                case ComponentBonusType.DamageUp:
                    product.DamageBonus += amount;
                    break;

                case ComponentBonusType.StructureBonusUp:
                    product.StructureBonus += amount;
                    break;

                case ComponentBonusType.StrengthUp:
                    product.StrengthBonus += amount;
                    break;

                case ComponentBonusType.DexterityUp:
                    product.DexterityBonus += amount;
                    break;

                case ComponentBonusType.ConstitutionUp:
                    product.ConstitutionBonus += amount;
                    break;

                case ComponentBonusType.WisdomUp:
                    product.WisdomBonus += amount;
                    break;

                case ComponentBonusType.IntelligenceUp:
                    product.IntelligenceBonus += amount;
                    break;

                case ComponentBonusType.CharismaUp:
                    product.CharismaBonus += amount;
                    break;

                case ComponentBonusType.AttackBonusUp:
                    attackBonus += amount;
                    break;

                case ComponentBonusType.DurationUp:
                    product.DurationBonus += amount;
                    break;

                case ComponentBonusType.ScanningUp:
                    product.ScanningBonus += amount;
                    break;

                case ComponentBonusType.ScavengingUp:
                    product.ScavengingBonus += amount;
                    break;

                case ComponentBonusType.PilotingUp:
                    product.PilotingBonus += amount;
                    break;

                // Legacy and other component bonus types won't do anything.
                default:
                    return;
                }

                if (!string.IsNullOrWhiteSpace(sourceTag))
                {
                    prop = ItemService.GetCustomItemPropertyByItemTag(sourceTag);
                }

                if (prop == null)
                {
                    return;
                }

                BiowareXP2.IPSafeAddItemProperty(product, prop, 0.0f, AddItemPropertyPolicy.IgnoreExisting, true, true);
            }

            // Attack bonus is aggregated into one item property, ensuring that the amount doesn't go over 20.
            if (attackBonus > 0)
            {
                // Look for existing properties, get the value and add it. Then remove that item property.
                foreach (var ip in product.ItemProperties)
                {
                    if (_.GetItemPropertyType(ip) == _.ITEM_PROPERTY_ATTACK_BONUS)
                    {
                        amount       = _.GetItemPropertyCostTableValue(ip);
                        attackBonus += amount;

                        _.RemoveItemProperty(product, ip);
                    }
                }

                // Clamp bonus to 20.
                if (attackBonus > 20)
                {
                    attackBonus = 20;
                }

                // Time to add the new item property.
                prop = _.ItemPropertyAttackBonus(attackBonus);
                BiowareXP2.IPSafeAddItemProperty(product, prop, 0.0f, AddItemPropertyPolicy.ReplaceExisting, false, false);
            }
        }