Пример #1
0
 public static DatabaseActionType Add(this DatabaseActionType oldAction, DatabaseActionType newAction)
 {
     switch (oldAction)
     {
         case DatabaseActionType.Unchanged:
             return newAction;
         case DatabaseActionType.Insert:
             switch (newAction)
             {
                 case DatabaseActionType.Insert:
                 case DatabaseActionType.Update:
                     return DatabaseActionType.Insert;
                 case DatabaseActionType.Delete:
                     return DatabaseActionType.Unchanged;
             }
             break;
         case DatabaseActionType.Update:
             switch (newAction)
             {
                 case DatabaseActionType.Update:
                     return DatabaseActionType.Update;
                 case DatabaseActionType.Delete:
                     return DatabaseActionType.Delete;
             }
             break;
         case DatabaseActionType.Delete:
             switch (newAction)
             {
                 case DatabaseActionType.Insert:
                     return DatabaseActionType.Unchanged;
             }
             break;
     }
     throw new InvalidOperationException("Invalid action");
 }
Пример #2
0
        public void GiveReward(NWPlayer player)
        {
            if (_amount <= 0 || _fameRegionID <= 0)
            {
                return;
            }

            PCRegionalFame     fame   = DataService.PCRegionalFame.GetByPlayerIDAndFameRegionIDOrDefault(player.GlobalID, _fameRegionID);
            DatabaseActionType action = DatabaseActionType.Update;

            if (fame == null)
            {
                fame = new PCRegionalFame
                {
                    PlayerID     = player.GlobalID,
                    FameRegionID = _fameRegionID,
                    Amount       = 0
                };

                action = DatabaseActionType.Insert;
            }

            fame.Amount += _amount;
            DataService.SubmitDataChange(fame, action);
        }
Пример #3
0
 public DatabaseArgs(DatabaseActionType type, string key, byte[] data = null, int?user = null)
 {
     Type = type;
     Key  = key;
     Data = data;
     User = user;
 }
Пример #4
0
 public DatabaseAction(IEntity data, DatabaseActionType action)
 {
     Data = new List <IEntity>();
     Data.Add(data);
     DataType     = data.GetType();
     Action       = action;
     IsEnumerable = false;
 }
        public void AdjustVisibility(NWPlayer player, NWObject target, bool isVisible)
        {
            if (!player.IsPlayer)
            {
                return;
            }
            if (target.IsPlayer || target.IsDM)
            {
                return;
            }

            string visibilityObjectID = target.GetLocalString("VISIBILITY_OBJECT_ID");

            if (string.IsNullOrWhiteSpace(visibilityObjectID))
            {
                target.AssignCommand(() =>
                {
                    _.SpeakString("Unable to locate VISIBILITY_OBJECT_ID variable. Need this in order to adjust visibility. Notify an admin if you see this message.");
                });
                return;
            }

            var visibility            = _data.SingleOrDefault <PCObjectVisibility>(x => x.PlayerID == player.GlobalID && x.VisibilityObjectID == visibilityObjectID);
            DatabaseActionType action = DatabaseActionType.Update;

            if (visibility == null)
            {
                visibility = new PCObjectVisibility
                {
                    PlayerID           = player.GlobalID,
                    VisibilityObjectID = visibilityObjectID
                };
                action = DatabaseActionType.Insert;
            }

            visibility.IsVisible = isVisible;
            _data.SubmitDataChange(visibility, action);

            if (visibility.IsVisible)
            {
                _nwnxPlayer.SetVisibilityOverride(player, target, (int)PlayerVisibilityType.Visible);
            }
            else
            {
                _nwnxPlayer.SetVisibilityOverride(player, target, (int)PlayerVisibilityType.Hidden);
            }
        }
Пример #6
0
        /// <summary>
        /// Sends a request to change data into the queue. Processing is asynchronous
        /// and you cannot reliably retrieve the data directly from the database immediately afterwards.
        /// However, data in the cache will be up to date as soon as a value is changed.
        /// </summary>
        /// <param name="data">The data to submit for processing</param>
        /// <param name="actionType">The type (Insert, Update, Delete, etc.) of change to make.</param>
        public void SubmitDataChange(IEntity data, DatabaseActionType actionType)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            if (actionType == DatabaseActionType.Insert || actionType == DatabaseActionType.Update)
            {
                SetIntoCache(data.GetType(), GetEntityKey(data), data);
            }
            else if (actionType == DatabaseActionType.Delete)
            {
                DeleteFromCache(data.GetType(), GetEntityKey(data));
            }

            DataQueue.Enqueue(new DatabaseAction(data, actionType));
        }
Пример #7
0
        /// <summary>
        /// Sends a request to change data into the queue. Processing is asynchronous
        /// and you cannot reliably retrieve the data directly from the database immediately afterwards.
        /// However, data in the cache will be up to date as soon as a value is changed.
        /// </summary>
        /// <param name="data">The data to submit for processing</param>
        /// <param name="actionType">The type (Insert, Update, Delete, etc.) of change to make.</param>
        public static void SubmitDataChange <T>(T data, DatabaseActionType actionType)
            where T : class, IEntity
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            if (actionType == DatabaseActionType.Insert || actionType == DatabaseActionType.Update)
            {
                SetIntoCache(data);
            }
            else if (actionType == DatabaseActionType.Delete)
            {
                RemoveFromCache(data);
            }

            DataQueue.Enqueue(new DatabaseAction(data, actionType));
        }
Пример #8
0
        public DatabaseAction(IEnumerable <IEntity> data, DatabaseActionType action)
        {
            Data = new List <IEntity>();
            foreach (var item in data)
            {
                if (DataType == null)
                {
                    DataType = item.GetType();
                }
                else if (item.GetType() != DataType)
                {
                    throw new InvalidOperationException("All objects in a single database action must be of the same type.");
                }

                Data.Add(item);
            }
            Action = action;

            IsEnumerable = true;
        }
Пример #9
0
        private static void SaveMapProgression(NWArea area, NWPlayer player)
        {
            var map = DataService.PCMapProgression.GetByPlayerIDAndAreaResrefOrDefault(player.GlobalID, area.Resref);
            DatabaseActionType action = DatabaseActionType.Update;

            if (map == null)
            {
                map = new PCMapProgression
                {
                    PlayerID    = player.GlobalID,
                    AreaResref  = area.Resref,
                    Progression = string.Empty
                };

                action = DatabaseActionType.Insert;
            }

            map.Progression = NWNXPlayer.GetAreaExplorationState(player, area);
            DataService.SubmitDataChange(map, action);
        }
Пример #10
0
        private void SaveMapProgression(NWArea area, NWPlayer player)
        {
            var map      = _data.GetAll <PCMapProgression>().SingleOrDefault(x => x.PlayerID == player.GlobalID && x.AreaResref == area.Resref);
            int areaSize = area.Width * area.Height;
            DatabaseActionType action = DatabaseActionType.Update;

            if (map == null || areaSize != map.Progression.Length)
            {
                if (map != null)
                {
                    _data.SubmitDataChange(map, DatabaseActionType.Delete);
                }

                map = new PCMapProgression
                {
                    PlayerID    = player.GlobalID,
                    AreaResref  = area.Resref,
                    Progression = string.Empty.PadLeft(areaSize, '0')
                };

                action = DatabaseActionType.Insert;
            }

            string progression = string.Empty;

            for (int x = 0; x < area.Width; x++)
            {
                for (int y = 0; y < area.Height; y++)
                {
                    bool visible = _.GetTileExplored(player, area, x, y) == TRUE;
                    progression += visible ? '1' : '0';
                }
            }

            map.Progression = progression;
            _data.SubmitDataChange(map, action);
        }
Пример #11
0
        public void DoPerkUpgrade(NWPlayer oPC, int perkID, bool freeUpgrade = false)
        {
            var perk       = _data.Single <Data.Entity.Perk>(x => x.ID == perkID);
            var perkLevels = _data.Where <PerkLevel>(x => x.PerkID == perkID);
            var pcPerk     = _data.SingleOrDefault <PCPerk>(x => x.PlayerID == oPC.GlobalID && x.PerkID == perkID);
            var player     = _data.Single <Player>(x => x.ID == oPC.GlobalID);

            if (freeUpgrade || CanPerkBeUpgraded(oPC, perkID))
            {
                DatabaseActionType action = DatabaseActionType.Update;
                if (pcPerk == null)
                {
                    pcPerk = new PCPerk();
                    DateTime dt = DateTime.UtcNow;
                    pcPerk.AcquiredDate = dt;
                    pcPerk.PerkID       = perk.ID;
                    pcPerk.PlayerID     = oPC.GlobalID;
                    pcPerk.PerkLevel    = 0;

                    action = DatabaseActionType.Insert;
                }

                PerkLevel nextPerkLevel = FindPerkLevel(perkLevels, pcPerk.PerkLevel + 1);
                if (nextPerkLevel == null)
                {
                    return;
                }

                pcPerk.PerkLevel++;
                _data.SubmitDataChange(pcPerk, action);

                if (!freeUpgrade)
                {
                    player.UnallocatedSP -= nextPerkLevel.Price;
                    _data.SubmitDataChange(player, DatabaseActionType.Update);
                }

                // If a perk is activatable, create the item on the PC.
                // Remove any existing cast spell unique power properties and add the correct one based on the DB flag.
                if (!string.IsNullOrWhiteSpace(perk.ItemResref))
                {
                    if (_.GetIsObjectValid(_.GetItemPossessedBy(oPC.Object, perk.ItemResref)) == FALSE)
                    {
                        NWItem spellItem = (_.CreateItemOnObject(perk.ItemResref, oPC.Object));
                        spellItem.IsCursed = true;
                        spellItem.SetLocalInt("ACTIVATION_PERK_ID", perk.ID);

                        foreach (ItemProperty ipCur in spellItem.ItemProperties)
                        {
                            int ipType    = _.GetItemPropertyType(ipCur);
                            int ipSubType = _.GetItemPropertySubType(ipCur);
                            if (ipType == ITEM_PROPERTY_CAST_SPELL &&
                                (ipSubType == IP_CONST_CASTSPELL_UNIQUE_POWER ||
                                 ipSubType == IP_CONST_CASTSPELL_UNIQUE_POWER_SELF_ONLY ||
                                 ipSubType == IP_CONST_CASTSPELL_ACTIVATE_ITEM))
                            {
                                _.RemoveItemProperty(spellItem.Object, ipCur);
                            }
                        }

                        ItemProperty ip;
                        if (perk.IsTargetSelfOnly)
                        {
                            ip = _.ItemPropertyCastSpell(IP_CONST_CASTSPELL_UNIQUE_POWER_SELF_ONLY, IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE);
                        }
                        else
                        {
                            ip = _.ItemPropertyCastSpell(IP_CONST_CASTSPELL_UNIQUE_POWER, IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE);
                        }

                        _biowareXP2.IPSafeAddItemProperty(spellItem, ip, 0.0f, AddItemPropertyPolicy.ReplaceExisting, false, false);
                    }

                    _.SetName(_.GetItemPossessedBy(oPC.Object, perk.ItemResref), perk.Name + " (Lvl. " + pcPerk.PerkLevel + ")");
                }
                // If a feat ID is assigned, add the feat to the player if it doesn't exist yet.
                else if (perk.FeatID != null &&
                         perk.FeatID > 0 &&
                         _.GetHasFeat((int)perk.FeatID, oPC.Object) == FALSE)
                {
                    _nwnxCreature.AddFeatByLevel(oPC, (int)perk.FeatID, 1);

                    var qbs = _nwnxQBS.UseFeat((int)perk.FeatID);

                    // Try to add the new feat to the player's hotbar.
                    if (_nwnxPlayer.GetQuickBarSlot(oPC, 0).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 0, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 1).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 1, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 2).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 2, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 3).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 3, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 4).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 4, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 5).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 5, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 6).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 6, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 7).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 7, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 8).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 8, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 9).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 9, qbs);
                    }
                    else if (_nwnxPlayer.GetQuickBarSlot(oPC, 10).ObjectType == QuickBarSlotType.Empty)
                    {
                        _nwnxPlayer.SetQuickBarSlot(oPC, 10, qbs);
                    }
                }

                oPC.SendMessage(_color.Green("Perk Purchased: " + perk.Name + " (Lvl. " + pcPerk.PerkLevel + ")"));

                App.ResolveByInterface <IPerk>("Perk." + perk.ScriptName, (perkScript) =>
                {
                    if (perkScript == null)
                    {
                        return;
                    }
                    perkScript.OnPurchased(oPC, pcPerk.PerkLevel);
                });
            }
            else
            {
                oPC.FloatingText(_color.Red("You cannot purchase the perk at this time."));
            }
        }
Пример #12
0
        private void TogglePermission(NWPlayer player, BasePermission permission)
        {
            var data         = _base.GetPlayerTempData(GetPC());
            var dbPermission = _data.SingleOrDefault <PCBasePermission>(x => x.PlayerID == player.GlobalID && x.PCBaseID == data.PCBaseID);

            DatabaseActionType action = DatabaseActionType.Update;

            if (dbPermission == null)
            {
                dbPermission = new PCBasePermission
                {
                    PCBaseID = data.PCBaseID,
                    PlayerID = player.GlobalID
                };
                action = DatabaseActionType.Insert;
            }

            switch (permission)
            {
            case BasePermission.CanPlaceEditStructures:
                dbPermission.CanPlaceEditStructures = !dbPermission.CanPlaceEditStructures;
                break;

            case BasePermission.CanAccessStructureInventory:
                dbPermission.CanAccessStructureInventory = !dbPermission.CanAccessStructureInventory;
                break;

            case BasePermission.CanManageBaseFuel:
                dbPermission.CanManageBaseFuel = !dbPermission.CanManageBaseFuel;
                break;

            case BasePermission.CanExtendLease:
                dbPermission.CanExtendLease = !dbPermission.CanExtendLease;
                break;

            case BasePermission.CanEnterBuildings:
                dbPermission.CanEnterBuildings = !dbPermission.CanEnterBuildings;
                break;

            case BasePermission.CanRetrieveStructures:
                dbPermission.CanRetrieveStructures = !dbPermission.CanRetrieveStructures;
                break;

            case BasePermission.CanRenameStructures:
                dbPermission.CanRenameStructures = !dbPermission.CanRenameStructures;
                break;

            case BasePermission.CanEditPrimaryResidence:
                dbPermission.CanEditPrimaryResidence = !dbPermission.CanEditPrimaryResidence;
                break;

            case BasePermission.CanRemovePrimaryResidence:
                dbPermission.CanRemovePrimaryResidence = !dbPermission.CanRemovePrimaryResidence;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(permission), permission, null);
            }

            _data.SubmitDataChange(dbPermission, action);
        }
Пример #13
0
        public static void DoPerkUpgrade(NWPlayer oPC, int perkID, bool freeUpgrade = false)
        {
            var perk       = DataService.Single <Data.Entity.Perk>(x => x.ID == perkID);
            var perkLevels = DataService.Where <PerkLevel>(x => x.PerkID == perkID);
            var pcPerk     = DataService.SingleOrDefault <PCPerk>(x => x.PlayerID == oPC.GlobalID && x.PerkID == perkID);
            var player     = DataService.Single <Player>(x => x.ID == oPC.GlobalID);

            if (freeUpgrade || CanPerkBeUpgraded(oPC, perkID))
            {
                DatabaseActionType action = DatabaseActionType.Update;
                if (pcPerk == null)
                {
                    pcPerk = new PCPerk();
                    DateTime dt = DateTime.UtcNow;
                    pcPerk.AcquiredDate = dt;
                    pcPerk.PerkID       = perk.ID;
                    pcPerk.PlayerID     = oPC.GlobalID;
                    pcPerk.PerkLevel    = 0;

                    action = DatabaseActionType.Insert;
                }

                PerkLevel nextPerkLevel = FindPerkLevel(perkLevels, pcPerk.PerkLevel + 1);
                if (nextPerkLevel == null)
                {
                    return;
                }

                pcPerk.PerkLevel++;
                DataService.SubmitDataChange(pcPerk, action);

                if (!freeUpgrade)
                {
                    player.UnallocatedSP -= nextPerkLevel.Price;
                    DataService.SubmitDataChange(player, DatabaseActionType.Update);
                }

                // Look for any perk levels to grant.
                var perkFeatsToGrant = DataService.Where <PerkFeat>(x => x.PerkID == perkID && x.PerkLevelUnlocked == pcPerk.PerkLevel);

                // If at least one feat ID is assigned, add the feat(s) to the player if it doesn't exist yet.
                if (perkFeatsToGrant.Count > 0)
                {
                    foreach (var perkFeat in perkFeatsToGrant)
                    {
                        if (_.GetHasFeat(perkFeat.FeatID, oPC.Object) == TRUE)
                        {
                            continue;
                        }

                        NWNXCreature.AddFeatByLevel(oPC, perkFeat.FeatID, 1);

                        var qbs = NWNXPlayerQuickBarSlot.UseFeat(perkFeat.FeatID);

                        // Try to add the new feat to the player's hotbar.
                        if (NWNXPlayer.GetQuickBarSlot(oPC, 0).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 0, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 1).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 1, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 2).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 2, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 3).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 3, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 4).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 4, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 5).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 5, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 6).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 6, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 7).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 7, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 8).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 8, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 9).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 9, qbs);
                        }
                        else if (NWNXPlayer.GetQuickBarSlot(oPC, 10).ObjectType == QuickBarSlotType.Empty)
                        {
                            NWNXPlayer.SetQuickBarSlot(oPC, 10, qbs);
                        }
                    }
                }

                oPC.SendMessage(ColorTokenService.Green("Perk Purchased: " + perk.Name + " (Lvl. " + pcPerk.PerkLevel + ")"));

                var handler = GetPerkHandler(perkID);
                handler.OnPurchased(oPC, pcPerk.PerkLevel);
                MessageHub.Instance.Publish(new PerkUpgradedMessage(oPC, perkID));
            }
            else
            {
                oPC.FloatingText(ColorTokenService.Red("You cannot purchase the perk at this time."));
            }
        }
Пример #14
0
        private void ApplyPCEffect(NWCreature caster, NWCreature target, int customEffectID, int ticks, int effectiveLevel, string data)
        {
            Data.Entity.CustomEffect customEffect = _data.Single <Data.Entity.CustomEffect>(x => x.ID == customEffectID);
            PCCustomEffect           pcEffect     = _data.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == target.GlobalID && x.CustomEffectID == customEffectID);
            CustomEffectCategoryType category     = (CustomEffectCategoryType)customEffect.CustomEffectCategoryID;

            if (category == CustomEffectCategoryType.FoodEffect)
            {
                var customEffectPC = _data.Get <Data.Entity.CustomEffect>(pcEffect.CustomEffectID);
                if (pcEffect != null && customEffectPC.CustomEffectCategoryID == (int)category)
                {
                    caster.SendMessage("You are not hungry.");
                    return;
                }
            }

            DatabaseActionType action = DatabaseActionType.Update;

            if (pcEffect == null)
            {
                pcEffect = new PCCustomEffect {
                    PlayerID = target.GlobalID
                };
                action = DatabaseActionType.Insert;
            }

            if (pcEffect.EffectiveLevel > effectiveLevel)
            {
                caster.SendMessage("A more powerful effect already exists on your target.");
                return;
            }

            pcEffect.CustomEffectID    = customEffectID;
            pcEffect.EffectiveLevel    = effectiveLevel;
            pcEffect.Ticks             = ticks;
            pcEffect.CasterNWNObjectID = _.ObjectToString(caster);
            _data.SubmitDataChange(pcEffect, action);

            target.SendMessage(customEffect.StartMessage);

            App.ResolveByInterface <ICustomEffect>("CustomEffect." + customEffect.ScriptHandler, handler =>
            {
                if (string.IsNullOrWhiteSpace(data))
                {
                    data = handler?.Apply(caster, target, effectiveLevel);
                }

                if (string.IsNullOrWhiteSpace(data))
                {
                    data = string.Empty;
                }
                pcEffect.Data = data;
                _data.SubmitDataChange(pcEffect, DatabaseActionType.Update);

                // Was already queued for removal, but got cast again. Take it out of the list to be removed.
                if (_cache.PCEffectsForRemoval.Contains(pcEffect.ID))
                {
                    _cache.PCEffectsForRemoval.Remove(pcEffect.ID);
                }
            });
        }
Пример #15
0
        /// <summary>
        /// Performs a perk purchase for a player. This handles deducting SP, inserting perk records,
        /// and adjusting hotbar slots as necessary.
        /// </summary>
        /// <param name="oPC">The player receiving the perk upgrade.</param>
        /// <param name="perkID">The ID number of the perk.</param>
        /// <param name="freeUpgrade">If true, no SP will be deducted. Otherwise, SP will be deducted from player.</param>
        public static void DoPerkUpgrade(NWPlayer oPC, int perkID, bool freeUpgrade = false)
        {
            var perk       = DataService.Perk.GetByID(perkID);
            var perkLevels = DataService.PerkLevel.GetAllByPerkID(perkID);
            var pcPerk     = DataService.PCPerk.GetByPlayerAndPerkIDOrDefault(oPC.GlobalID, perkID);
            var player     = DataService.Player.GetByID(oPC.GlobalID);

            if (freeUpgrade || CanPerkBeUpgraded(oPC, perkID))
            {
                DatabaseActionType action = DatabaseActionType.Update;
                if (pcPerk == null)
                {
                    pcPerk = new PCPerk();
                    DateTime dt = DateTime.UtcNow;
                    pcPerk.AcquiredDate = dt;
                    pcPerk.PerkID       = perk.ID;
                    pcPerk.PlayerID     = oPC.GlobalID;
                    pcPerk.PerkLevel    = 0;

                    action = DatabaseActionType.Insert;
                }

                PerkLevel nextPerkLevel = FindPerkLevel(perkLevels, pcPerk.PerkLevel + 1);

                if (nextPerkLevel == null)
                {
                    return;
                }
                pcPerk.PerkLevel++;
                DataService.SubmitDataChange(pcPerk, action);

                if (!freeUpgrade)
                {
                    player.UnallocatedSP -= nextPerkLevel.Price;
                    DataService.SubmitDataChange(player, DatabaseActionType.Update);
                }

                // Look for a perk feat to grant.
                var perkFeatToGrant = DataService.PerkFeat.GetByPerkIDAndLevelUnlockedOrDefault(perkID, pcPerk.PerkLevel);

                // Add the feat(s) to the player if it doesn't exist yet.
                if (perkFeatToGrant != null && _.GetHasFeat((Feat)perkFeatToGrant.FeatID, oPC.Object) == false)
                {
                    NWNXCreature.AddFeatByLevel(oPC, (Feat)perkFeatToGrant.FeatID, 1);

                    var qbs = NWNXPlayerQuickBarSlot.UseFeat((Feat)perkFeatToGrant.FeatID);

                    // Try to add the new feat to the player's hotbar.
                    if (NWNXPlayer.GetQuickBarSlot(oPC, 0).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 0, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 1).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 1, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 2).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 2, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 3).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 3, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 4).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 4, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 5).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 5, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 6).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 6, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 7).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 7, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 8).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 8, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 9).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 9, qbs);
                    }
                    else if (NWNXPlayer.GetQuickBarSlot(oPC, 10).ObjectType == QuickBarSlotType.Empty)
                    {
                        NWNXPlayer.SetQuickBarSlot(oPC, 10, qbs);
                    }
                }

                oPC.SendMessage(ColorTokenService.Green("Perk Purchased: " + perk.Name + " (Lvl. " + pcPerk.PerkLevel + ")"));

                MessageHub.Instance.Publish(new OnPerkUpgraded(oPC, perkID));

                var handler = GetPerkHandler(perkID);
                handler.OnPurchased(oPC, pcPerk.PerkLevel);
            }
            else
            {
                oPC.FloatingText(ColorTokenService.Red("You cannot purchase the perk at this time."));
            }
        }
Пример #16
0
        private static void OnCreatureDeath()
        {
            NWCreature creature = Object.OBJECT_SELF;

            int npcGroupID = creature.GetLocalInt("NPC_GROUP");

            if (npcGroupID <= 0)
            {
                return;
            }

            NWObject oKiller = _.GetLastKiller();

            if (!oKiller.IsPlayer)
            {
                return;
            }

            string areaResref = creature.Area.Resref;

            List <KeyValuePair <NWPlayer, int> > playersToAdvance = new List <KeyValuePair <NWPlayer, int> >();
            NWPlayer oPC = _.GetFirstFactionMember(oKiller);

            while (oPC.IsValid)
            {
                if (areaResref != oPC.Area.Resref)
                {
                    oPC = _.GetNextFactionMember(oKiller);
                    continue;
                }

                if (_.GetDistanceBetween(creature, oPC) <= 0.0f || _.GetDistanceBetween(creature, oPC) > 20.0f)
                {
                    oPC = _.GetNextFactionMember(oKiller);
                    continue;
                }

                var playerID    = oPC.GlobalID;
                var killTargets = DataService.Where <PCQuestKillTargetProgress>(x => x.PlayerID == playerID && x.NPCGroupID == npcGroupID).ToList();

                foreach (var kt in killTargets)
                {
                    var questStatus = DataService.Get <PCQuestStatus>(kt.PCQuestStatusID);
                    var quest       = DataService.Get <Quest>(questStatus.QuestID);
                    var npcGroup    = DataService.Get <NPCGroup>(kt.NPCGroupID);

                    kt.RemainingToKill--;
                    string             targetGroupName = npcGroup.Name;
                    string             updateMessage   = "[" + quest.Name + "] " + targetGroupName + " remaining: " + kt.RemainingToKill;
                    DatabaseActionType action          = DatabaseActionType.Update;

                    if (kt.RemainingToKill <= 0)
                    {
                        updateMessage += " " + ColorTokenService.Green(" {COMPLETE}");
                        playersToAdvance.Add(new KeyValuePair <NWPlayer, int>(oPC, quest.ID));
                        action = DatabaseActionType.Delete;
                    }

                    DataService.SubmitDataChange(kt, action);

                    var pc = oPC;
                    _.DelayCommand(1.0f, () =>
                    {
                        pc.SendMessage(updateMessage);
                    });

                    string ruleName = quest.OnKillTargetRule;
                    if (!string.IsNullOrWhiteSpace(ruleName))
                    {
                        var pcCopy = oPC;
                        var rule   = GetQuestRule(ruleName);

                        string[] args = null;
                        if (!string.IsNullOrWhiteSpace(quest.OnKillTargetArgs))
                        {
                            args = quest.OnKillTargetArgs.Split(',');
                        }
                        rule.Run(pcCopy, creature, quest.ID, args);
                    }
                }

                oPC = _.GetNextFactionMember(oKiller);
            }

            foreach (var player in playersToAdvance)
            {
                AdvanceQuestState(player.Key, null, player.Value);
            }
        }
Пример #17
0
 /// <summary>
 /// Initializes a new instance of <see cref="DatabaseAction{T}"/>.
 /// </summary>
 /// <param name="item">The item to perform the required action with.</param>
 /// <param name="actionType">The type of action to perform.</param>
 public DatabaseAction(T item, DatabaseActionType actionType)
 {
     _item       = item;
     _actionType = actionType;
 }
Пример #18
0
        private static void ApplyPCEffect(NWCreature caster, NWCreature target, int customEffectID, int ticks, int effectiveLevel, string data)
        {
            PCCustomEffect           pcEffect = DataService.PCCustomEffect.GetByPlayerIDAndCustomEffectIDOrDefault(target.GlobalID, customEffectID);
            ICustomEffectHandler     handler  = GetCustomEffectHandler(customEffectID);
            CustomEffectCategoryType category = handler.CustomEffectCategoryType;

            if (category == CustomEffectCategoryType.FoodEffect)
            {
                var customEffectPC = DataService.CustomEffect.GetByID(pcEffect.CustomEffectID);
                if (customEffectPC != null)
                {
                    var foodHandler = GetCustomEffectHandler(customEffectPC.ID);
                    if (foodHandler.CustomEffectCategoryType == category)
                    {
                        caster.SendMessage("You are not hungry.");
                    }
                    return;
                }
            }

            DatabaseActionType action = DatabaseActionType.Update;

            if (pcEffect == null)
            {
                pcEffect = new PCCustomEffect {
                    PlayerID = target.GlobalID
                };
                action = DatabaseActionType.Insert;
            }

            if (pcEffect.EffectiveLevel > effectiveLevel)
            {
                caster.SendMessage("A more powerful effect already exists on your target.");
                return;
            }

            pcEffect.CustomEffectID    = customEffectID;
            pcEffect.EffectiveLevel    = effectiveLevel;
            pcEffect.Ticks             = ticks;
            pcEffect.CasterNWNObjectID = _.ObjectToString(caster);
            DataService.SubmitDataChange(pcEffect, action);

            target.SendMessage(handler.StartMessage);
            if (string.IsNullOrWhiteSpace(data))
            {
                data = handler?.Apply(caster, target, effectiveLevel);
            }

            if (string.IsNullOrWhiteSpace(data))
            {
                data = string.Empty;
            }
            pcEffect.Data = data;
            DataService.SubmitDataChange(pcEffect, DatabaseActionType.Update);

            // Was already queued for removal, but got cast again. Take it out of the list to be removed.
            if (AppCache.PCEffectsForRemoval.Contains(pcEffect.ID))
            {
                AppCache.PCEffectsForRemoval.Remove(pcEffect.ID);
            }
        }
Пример #19
0
        public bool Run(params object[] args)
        {
            NWPlaceable container = Object.OBJECT_SELF;
            NWObject    owner     = container.GetLocalObject("QUEST_OWNER");

            NWPlayer player            = _.GetLastDisturbed();
            NWItem   item              = _.GetInventoryDisturbItem();
            int      disturbType       = _.GetInventoryDisturbType();
            string   crafterPlayerID   = item.GetLocalString("CRAFTER_PLAYER_ID");
            Guid?    crafterPlayerGUID = null;

            if (!string.IsNullOrWhiteSpace(crafterPlayerID))
            {
                crafterPlayerGUID = new Guid(crafterPlayerID);
            }

            if (disturbType == INVENTORY_DISTURB_TYPE_ADDED)
            {
                int                 questID  = container.GetLocalInt("QUEST_ID");
                PCQuestStatus       status   = _data.Single <PCQuestStatus>(x => x.PlayerID == player.GlobalID && x.QuestID == questID);
                PCQuestItemProgress progress = _data.SingleOrDefault <PCQuestItemProgress>(x => x.PCQuestStatusID == status.ID && x.Resref == item.Resref);
                DatabaseActionType  action   = DatabaseActionType.Update;

                if (progress == null)
                {
                    _.CopyItem(item, player, TRUE);
                    player.SendMessage(_color.Red("That item is not required for this quest."));
                }
                else if (progress.MustBeCraftedByPlayer && crafterPlayerGUID != player.GlobalID)
                {
                    _.CopyItem(item, player, TRUE);
                    player.SendMessage(_color.Red("You may only submit items which you have personally created for this quest."));
                }
                else
                {
                    progress.Remaining--;

                    if (progress.Remaining <= 0)
                    {
                        var progressCopy = progress;
                        progress = _data.Single <PCQuestItemProgress>(x => x.ID == progressCopy.ID);
                        action   = DatabaseActionType.Delete;
                    }
                    _data.SubmitDataChange(progress, action);

                    // Recalc the remaining items needed.
                    int remainingCount = _data.GetAll <PCQuestItemProgress>().Count(x => x.PCQuestStatusID == status.ID);
                    if (remainingCount <= 0)
                    {
                        _quest.AdvanceQuestState(player, owner, questID);
                    }

                    player.SendMessage("You need " + progress.Remaining + " " + item.Name + " for this quest.");
                }
                item.Destroy();

                var questItemProgresses = _data.Where <PCQuestItemProgress>(x => x.PCQuestStatusID == status.ID);
                if (!questItemProgresses.Any())
                {
                    string conversation = _.GetLocalString(owner, "CONVERSATION");
                    if (!string.IsNullOrWhiteSpace(conversation))
                    {
                        _dialog.StartConversation(player, owner, conversation);
                    }
                    else
                    {
                        player.AssignCommand(() =>
                        {
                            _.ActionStartConversation(owner, "", TRUE, FALSE);
                        });
                    }
                }
            }

            return(true);
        }
Пример #20
0
        /// <summary>
        /// Updates a player's quest status if the creature is part of an ongoing quest.
        /// Progresses the player to the next state if all requirements are met.
        /// </summary>
        private static void OnCreatureDeath()
        {
            NWCreature creature = _.OBJECT_SELF;

            int npcGroupID = creature.GetLocalInt("NPC_GROUP");

            if (npcGroupID <= 0)
            {
                return;
            }

            NWObject oKiller = GetLastKiller();

            if (!oKiller.IsPlayer)
            {
                return;
            }

            string areaResref = creature.Area.Resref;

            List <KeyValuePair <NWPlayer, int> > playersToAdvance = new List <KeyValuePair <NWPlayer, int> >();
            NWPlayer oPC = GetFirstFactionMember(oKiller);

            while (oPC.IsValid)
            {
                if (areaResref != oPC.Area.Resref)
                {
                    oPC = GetNextFactionMember(oKiller);
                    continue;
                }

                if (GetDistanceBetween(creature, oPC) <= 0.0f || GetDistanceBetween(creature, oPC) > 40.0f)
                {
                    oPC = GetNextFactionMember(oKiller);
                    continue;
                }

                var playerID    = oPC.GlobalID;
                var killTargets = DataService.PCQuestKillTargetProgress.GetAllByPlayerIDAndNPCGroupID(playerID, npcGroupID).ToList();

                foreach (var kt in killTargets)
                {
                    var questStatus = DataService.PCQuestStatus.GetByID(kt.PCQuestStatusID);
                    var quest       = GetQuestByID(questStatus.QuestID);
                    var npcGroup    = DataService.NPCGroup.GetByID(kt.NPCGroupID);

                    kt.RemainingToKill--;
                    string             targetGroupName = npcGroup.Name;
                    string             updateMessage   = "[" + quest.Name + "] " + targetGroupName + " remaining: " + kt.RemainingToKill;
                    DatabaseActionType action          = DatabaseActionType.Update;

                    if (kt.RemainingToKill <= 0)
                    {
                        updateMessage += " " + ColorTokenService.Green(" {COMPLETE}");
                        playersToAdvance.Add(new KeyValuePair <NWPlayer, int>(oPC, quest.QuestID));
                        action = DatabaseActionType.Delete;
                    }

                    DataService.SubmitDataChange(kt, action);

                    var pc = oPC;
                    DelayCommand(1.0f, () =>
                    {
                        pc.SendMessage(updateMessage);
                    });
                }

                oPC = GetNextFactionMember(oKiller);
            }

            foreach (var player in playersToAdvance)
            {
                var quest = GetQuestByID(player.Value);
                quest.Advance(player.Key, creature);
            }
        }
Пример #21
0
        private void TogglePermission(Guid playerID, BasePermission permission, bool isPublicPermission)
        {
            var data         = BaseService.GetPlayerTempData(GetPC());
            var dbPermission = isPublicPermission ?
                               DataService.SingleOrDefault <PCBasePermission>(x => x.PCBaseID == data.PCBaseID &&
                                                                              x.IsPublicPermission) :
                               DataService.SingleOrDefault <PCBasePermission>(x => x.PlayerID == playerID &&
                                                                              x.PCBaseID == data.PCBaseID &&
                                                                              !x.IsPublicPermission);

            DatabaseActionType action = DatabaseActionType.Update;

            if (dbPermission == null)
            {
                dbPermission = new PCBasePermission
                {
                    PCBaseID           = data.PCBaseID,
                    PlayerID           = playerID,
                    IsPublicPermission = isPublicPermission
                };
                action = DatabaseActionType.Insert;
            }

            switch (permission)
            {
            case BasePermission.CanPlaceEditStructures:
                dbPermission.CanPlaceEditStructures = !dbPermission.CanPlaceEditStructures;
                break;

            case BasePermission.CanAccessStructureInventory:
                dbPermission.CanAccessStructureInventory = !dbPermission.CanAccessStructureInventory;
                break;

            case BasePermission.CanManageBaseFuel:
                dbPermission.CanManageBaseFuel = !dbPermission.CanManageBaseFuel;
                break;

            case BasePermission.CanExtendLease:
                dbPermission.CanExtendLease = !dbPermission.CanExtendLease;
                break;

            case BasePermission.CanEnterBuildings:
                dbPermission.CanEnterBuildings = !dbPermission.CanEnterBuildings;
                break;

            case BasePermission.CanRetrieveStructures:
                dbPermission.CanRetrieveStructures = !dbPermission.CanRetrieveStructures;
                break;

            case BasePermission.CanRenameStructures:
                dbPermission.CanRenameStructures = !dbPermission.CanRenameStructures;
                break;

            case BasePermission.CanEditPrimaryResidence:
                dbPermission.CanEditPrimaryResidence = !dbPermission.CanEditPrimaryResidence;
                break;

            case BasePermission.CanRemovePrimaryResidence:
                dbPermission.CanRemovePrimaryResidence = !dbPermission.CanRemovePrimaryResidence;
                break;

            case BasePermission.CanChangeStructureMode:
                dbPermission.CanChangeStructureMode = !dbPermission.CanChangeStructureMode;
                break;

            case BasePermission.CanAdjustPublicPermissions:
                dbPermission.CanAdjustPublicPermissions = !dbPermission.CanAdjustPublicPermissions;
                break;

            case BasePermission.CanFlyStarship:
                dbPermission.CanFlyStarship = !dbPermission.CanFlyStarship;
                break;

            case BasePermission.CanDockStarship:
                dbPermission.CanDockStarship = !dbPermission.CanDockStarship;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(permission), permission, null);
            }

            DataService.SubmitDataChange(dbPermission, action);
        }
Пример #22
0
        public static void CompleteQuest(NWPlayer player, NWObject questOwner, int questID, ItemVO selectedItem)
        {
            if (!player.IsPlayer)
            {
                return;
            }

            Quest         quest   = DataService.Single <Quest>(x => x.ID == questID);
            PCQuestStatus pcState = DataService.Single <PCQuestStatus>(x => x.PlayerID == player.GlobalID && x.QuestID == questID);

            QuestState finalState = DataService.GetAll <QuestState>().Where(x => x.QuestID == questID).OrderBy(o => o.Sequence).Last();

            if (finalState == null)
            {
                player.SendMessage("Could not find final state of quest. Please notify an admin this quest is bugged. (QuestID: " + questID + ")");
                return;
            }

            pcState.CurrentQuestStateID = finalState.ID;
            pcState.CompletionDate      = DateTime.UtcNow;

            if (selectedItem == null)
            {
                var rewardItems = DataService.Where <QuestRewardItem>(x => x.QuestID == questID);
                foreach (QuestRewardItem reward in rewardItems)
                {
                    _.CreateItemOnObject(reward.Resref, player.Object, reward.Quantity);
                }
            }
            else
            {
                _.CreateItemOnObject(selectedItem.Resref, player.Object, selectedItem.Quantity);
            }

            if (quest.RewardGold > 0)
            {
                _.GiveGoldToCreature(player.Object, quest.RewardGold);
            }

            if (quest.RewardKeyItemID != null)
            {
                KeyItemService.GivePlayerKeyItem(player, (int)quest.RewardKeyItemID);
            }

            if (quest.RemoveStartKeyItemAfterCompletion && quest.StartKeyItemID != null)
            {
                KeyItemService.RemovePlayerKeyItem(player, (int)quest.StartKeyItemID);
            }

            if (!string.IsNullOrWhiteSpace(quest.MapNoteTag))
            {
                MapPinService.DeleteMapPin(player, "QST_MAP_NOTE_" + questID);
            }

            if (quest.RewardFame > 0)
            {
                PCRegionalFame     fame   = DataService.SingleOrDefault <PCRegionalFame>(x => x.PlayerID == player.GlobalID && x.FameRegionID == quest.FameRegionID);
                DatabaseActionType action = DatabaseActionType.Update;

                if (fame == null)
                {
                    fame = new PCRegionalFame
                    {
                        PlayerID     = player.GlobalID,
                        FameRegionID = quest.FameRegionID,
                        Amount       = 0
                    };

                    action = DatabaseActionType.Insert;
                }

                fame.Amount += quest.RewardFame;
                DataService.SubmitDataChange(fame, action);
            }

            player.SendMessage("Quest '" + quest.Name + "' complete!");
            DataService.SubmitDataChange(pcState, DatabaseActionType.Update);
            _.RemoveJournalQuestEntry(quest.JournalTag, player, FALSE);

            if (!string.IsNullOrWhiteSpace(quest.OnCompleteRule) && questOwner != null)
            {
                var rule = GetQuestRule(quest.OnCompleteRule);

                string[] args = null;
                if (!string.IsNullOrWhiteSpace(quest.OnCompleteArgs))
                {
                    args = quest.OnCompleteArgs.Split(',');
                }
                rule.Run(player, questOwner, questID, args);
            }

            MessageHub.Instance.Publish(new QuestCompletedMessage(player, questID));
        }
Пример #23
0
        public void Main()
        {
            NWPlaceable container = NWGameObject.OBJECT_SELF;
            NWObject    owner     = container.GetLocalObject("QUEST_OWNER");

            NWPlayer player            = _.GetLastDisturbed();
            NWItem   item              = _.GetInventoryDisturbItem();
            int      disturbType       = _.GetInventoryDisturbType();
            string   crafterPlayerID   = item.GetLocalString("CRAFTER_PLAYER_ID");
            Guid?    crafterPlayerGUID = null;

            if (!string.IsNullOrWhiteSpace(crafterPlayerID))
            {
                crafterPlayerGUID = new Guid(crafterPlayerID);
            }

            if (disturbType == _.INVENTORY_DISTURB_TYPE_ADDED)
            {
                int                 questID  = container.GetLocalInt("QUEST_ID");
                PCQuestStatus       status   = DataService.PCQuestStatus.GetByPlayerAndQuestID(player.GlobalID, questID);
                PCQuestItemProgress progress = DataService.PCQuestItemProgress.GetByPCQuestStatusIDAndResrefOrDefault(status.ID, item.Resref);
                DatabaseActionType  action   = DatabaseActionType.Update;

                if (progress == null)
                {
                    _.CopyItem(item, player, _.TRUE);
                    player.SendMessage(ColorTokenService.Red("That item is not required for this quest."));
                }
                else if (progress.MustBeCraftedByPlayer && crafterPlayerGUID != player.GlobalID)
                {
                    _.CopyItem(item, player, _.TRUE);
                    player.SendMessage(ColorTokenService.Red("You may only submit items which you have personally created for this quest."));
                }
                else
                {
                    progress.Remaining--;

                    if (progress.Remaining <= 0)
                    {
                        var progressCopy = progress;
                        progress = DataService.PCQuestItemProgress.GetByID(progressCopy.ID);
                        action   = DatabaseActionType.Delete;
                    }
                    DataService.SubmitDataChange(progress, action);

                    // Recalc the remaining items needed.
                    int remainingCount = DataService.PCQuestItemProgress.GetCountByPCQuestStatusID(status.ID);
                    if (remainingCount <= 0)
                    {
                        QuestService.AdvanceQuestState(player, owner, questID);
                    }

                    player.SendMessage("You need " + progress.Remaining + "x " + item.Name + " for this quest.");
                }
                item.Destroy();

                var questItemProgresses = DataService.PCQuestItemProgress.GetAllByPCQuestStatusID(status.ID);
                if (!questItemProgresses.Any())
                {
                    string conversation = _.GetLocalString(owner, "CONVERSATION");

                    // Either start a SWLOR conversation
                    if (!string.IsNullOrWhiteSpace(conversation))
                    {
                        DialogService.StartConversation(player, owner, conversation);
                    }
                    // Or a regular NWN conversation.
                    else
                    {
                        player.AssignCommand(() => { _.ActionStartConversation(owner, "", _.TRUE, _.FALSE); });
                    }
                }
            }
        }