Beispiel #1
0
        private void DoPerkRemoval()
        {
            if (!CanRefundPerk())
            {
                return;
            }

            var model        = GetDialogCustomData <Model>();
            var player       = GetPC();
            var pcPerk       = DataService.PCPerk.GetByID(model.PCPerkID);
            var perk         = DataService.Perk.GetByID(pcPerk.PerkID);
            var minimumLevel = 1;

            if (IsGrantedByBackground((PerkType)perk.ID))
            {
                minimumLevel = 2;
            }

            var refundAmount = DataService.PerkLevel.GetAllByPerkID(perk.ID)
                               .Where(x => x.Level <= pcPerk.PerkLevel &&
                                      x.Level >= minimumLevel).Sum(x => x.Price);
            var dbPlayer = DataService.Player.GetByID(player.GlobalID);

            dbPlayer.DatePerkRefundAvailable = DateTime.UtcNow.AddHours(24);
            RemovePerkItem(perk);
            RemovePerkFeat(perk);
            CustomEffectService.RemoveStance(GetPC());
            PlayerStatService.ApplyStatChanges(GetPC(), null);

            dbPlayer.UnallocatedSP += refundAmount;

            var refundAudit = new PCPerkRefund
            {
                PlayerID     = player.GlobalID,
                DateAcquired = pcPerk.AcquiredDate,
                DateRefunded = DateTime.UtcNow,
                Level        = pcPerk.PerkLevel,
                PerkID       = pcPerk.PerkID
            };

            // Bypass caching for perk refunds.
            DataService.DataQueue.Enqueue(new DatabaseAction(refundAudit, DatabaseActionType.Insert));
            DataService.SubmitDataChange(pcPerk, DatabaseActionType.Delete);
            DataService.SubmitDataChange(dbPlayer, DatabaseActionType.Update);

            // If perk refunded was one granted by a background bonus, we need to reapply it.
            ReapplyBackgroundBonus((PerkType)pcPerk.PerkID);

            GetPC().FloatingText("Perk refunded! You reclaimed " + refundAmount + " SP.");
            model.TomeItem.Destroy();

            var handler = PerkService.GetPerkHandler(perk.ID);

            handler.OnRemoved(player);
            MessageHub.Instance.Publish(new OnPerkRefunded(player, pcPerk.PerkID));
        }
Beispiel #2
0
        public bool Run(params object[] args)
        {
            using (new Profiler(nameof(FinishAbilityUse)))
            {
                // These arguments are sent from the AbilityService's ActivateAbility method.
                NWCreature activator    = (NWCreature)args[0];
                string     spellUUID    = Convert.ToString(args[1]);
                int        perkID       = (int)args[2];
                NWObject   target       = (NWObject)args[3];
                int        pcPerkLevel  = (int)args[4];
                int        spellTier    = (int)args[5];
                float      armorPenalty = (float)args[6];

                // Get the relevant perk information from the database.
                Data.Entity.Perk dbPerk = DataService.Single <Data.Entity.Perk>(x => x.ID == perkID);

                // The execution type determines how the perk behaves and the rules surrounding it.
                PerkExecutionType executionType = dbPerk.ExecutionTypeID;

                // Get the class which handles this perk's behaviour.
                IPerkHandler perk = PerkService.GetPerkHandler(perkID);

                // Pull back cooldown information.
                int?cooldownID            = perk.CooldownCategoryID(activator, dbPerk.CooldownCategoryID, spellTier);
                CooldownCategory cooldown = cooldownID == null ? null : DataService.SingleOrDefault <CooldownCategory>(x => x.ID == cooldownID);

                // If the activator interrupted the spell or died, we can bail out early.
                if (activator.GetLocalInt(spellUUID) == (int)SpellStatusType.Interrupted || // Moved during casting
                    activator.CurrentHP < 0 || activator.IsDead)                            // Or is dead/dying
                {
                    activator.DeleteLocalInt(spellUUID);
                    return(false);
                }

                // Remove the temporary UUID which is tracking this spell cast.
                activator.DeleteLocalInt(spellUUID);

                // Force Abilities, Combat Abilities, Stances, and Concentration Abilities
                if (executionType == PerkExecutionType.ForceAbility ||
                    executionType == PerkExecutionType.CombatAbility ||
                    executionType == PerkExecutionType.Stance ||
                    executionType == PerkExecutionType.ConcentrationAbility)
                {
                    // Run the impact script.
                    perk.OnImpact(activator, target, pcPerkLevel, spellTier);

                    // If an animation is specified for this perk, play it now.
                    if (dbPerk.CastAnimationID != null && dbPerk.CastAnimationID > 0)
                    {
                        activator.AssignCommand(() => { _.ActionPlayAnimation((int)dbPerk.CastAnimationID, 1f, 1f); });
                    }

                    // If the target is an NPC, assign enmity towards this creature for that NPC.
                    if (target.IsNPC)
                    {
                        AbilityService.ApplyEnmity(activator, target.Object, dbPerk);
                    }
                }

                // Adjust creature's current FP, if necessary.
                // Adjust FP only if spell cost > 0
                PerkFeat perkFeat = DataService.Single <PerkFeat>(x => x.PerkID == perkID && x.PerkLevelUnlocked == spellTier);
                int      fpCost   = perk.FPCost(activator, perkFeat.BaseFPCost, spellTier);

                if (fpCost > 0)
                {
                    int currentFP = AbilityService.GetCurrentFP(activator);
                    int maxFP     = AbilityService.GetMaxFP(activator);
                    currentFP -= fpCost;
                    AbilityService.SetCurrentFP(activator, currentFP);
                    activator.SendMessage(ColorTokenService.Custom("FP: " + currentFP + " / " + maxFP, 32, 223, 219));
                }

                // Notify activator of concentration ability change and also update it in the DB.
                if (executionType == PerkExecutionType.ConcentrationAbility)
                {
                    AbilityService.StartConcentrationEffect(activator, perkID, spellTier);
                    activator.SendMessage("Concentration ability activated: " + dbPerk.Name);

                    // The Skill Increase effect icon and name has been overwritten. Apply the effect to the player now.
                    // This doesn't do anything - it simply gives a visual cue that the player has an active concentration effect.
                    _.ApplyEffectToObject(_.DURATION_TYPE_PERMANENT, _.EffectSkillIncrease(_.SKILL_USE_MAGIC_DEVICE, 1), activator);
                }

                // Handle applying cooldowns, if necessary.
                if (cooldown != null)
                {
                    AbilityService.ApplyCooldown(activator, cooldown, perk, spellTier, armorPenalty);
                }

                // Mark the creature as no longer busy.
                activator.IsBusy = false;

                // Mark the spell cast as complete.
                activator.SetLocalInt(spellUUID, (int)SpellStatusType.Completed);

                return(true);
            }
        }
        public bool Run(params object[] args)
        {
            using (new Profiler(nameof(FinishAbilityUse)))
            {
                NWPlayer pc          = (NWPlayer)args[0];
                string   spellUUID   = Convert.ToString(args[1]);
                int      perkID      = (int)args[2];
                NWObject target      = (NWObject)args[3];
                int      pcPerkLevel = (int)args[4];
                int      featID      = (int)args[5];

                Data.Entity.Perk  entity        = DataService.Single <Data.Entity.Perk>(x => x.ID == perkID);
                PerkExecutionType executionType = (PerkExecutionType)entity.ExecutionTypeID;
                IPerkHandler      perk          = PerkService.GetPerkHandler(perkID);

                int?cooldownID            = perk.CooldownCategoryID(pc, entity.CooldownCategoryID, featID);
                CooldownCategory cooldown = cooldownID == null ? null : DataService.SingleOrDefault <CooldownCategory>(x => x.ID == cooldownID);

                if (pc.GetLocalInt(spellUUID) == (int)SpellStatusType.Interrupted || // Moved during casting
                    pc.CurrentHP < 0 || pc.IsDead)                                   // Or is dead/dying
                {
                    pc.DeleteLocalInt(spellUUID);
                    return(false);
                }

                pc.DeleteLocalInt(spellUUID);

                if (executionType == PerkExecutionType.ForceAbility ||
                    executionType == PerkExecutionType.CombatAbility ||
                    executionType == PerkExecutionType.Stance)
                {
                    perk.OnImpact(pc, target, pcPerkLevel, featID);

                    if (entity.CastAnimationID != null && entity.CastAnimationID > 0)
                    {
                        pc.AssignCommand(() => { _.ActionPlayAnimation((int)entity.CastAnimationID, 1f, 1f); });
                    }

                    if (target.IsNPC)
                    {
                        AbilityService.ApplyEnmity(pc, (target.Object), entity);
                    }
                }
                else if (executionType == PerkExecutionType.QueuedWeaponSkill)
                {
                    AbilityService.HandleQueueWeaponSkill(pc, entity, perk, featID);
                }


                // Adjust FP only if spell cost > 0
                Data.Entity.Player pcEntity = DataService.Single <Data.Entity.Player>(x => x.ID == pc.GlobalID);
                int fpCost = perk.FPCost(pc, entity.BaseFPCost, featID);

                if (fpCost > 0)
                {
                    pcEntity.CurrentFP = pcEntity.CurrentFP - fpCost;
                    DataService.SubmitDataChange(pcEntity, DatabaseActionType.Update);
                    pc.SendMessage(ColorTokenService.Custom("FP: " + pcEntity.CurrentFP + " / " + pcEntity.MaxFP, 32, 223, 219));
                }

                bool hasChainspell = CustomEffectService.DoesPCHaveCustomEffect(pc, CustomEffectType.Chainspell) &&
                                     executionType == PerkExecutionType.ForceAbility;

                if (!hasChainspell && cooldown != null)
                {
                    // Mark cooldown on category
                    AbilityService.ApplyCooldown(pc, cooldown, perk, featID);
                }

                pc.IsBusy = false;
                pc.SetLocalInt(spellUUID, (int)SpellStatusType.Completed);

                return(true);
            }
        }