/// <summary> /// Gives GP to a player for a given guild. /// If the baseAmount is less than 1, nothing will happen. /// If the baseAmount is greater than 1000, the baseAmount will be set to 1000. /// If the player ranks up, a message will be sent to him/her and an OnPlayerGuildRankUp event will be published. /// </summary> /// <param name="player">The player to give GP.</param> /// <param name="guild">The guild this GP will apply to.</param> /// <param name="baseAmount">The baseAmount of GP to grant.</param> public static void GiveGuildPoints(NWPlayer player, GuildType guild, int baseAmount) { if (baseAmount <= 0) { return; } // Clamp max GP baseAmount if (baseAmount > 1000) { baseAmount = 1000; } // Grant a bonus based on the player's guild relations perk rank. Always offset by 1 so we don't end up with multiplication by zero. int perkBonus = PerkService.GetCreaturePerkLevel(player, PerkType.GuildRelations) + 1; baseAmount *= perkBonus; var dbGuild = DataService.Get <Guild>((int)guild); var pcGP = DataService.Single <PCGuildPoint>(x => x.GuildID == (int)guild && x.PlayerID == player.GlobalID); pcGP.Points += baseAmount; // Clamp player GP to the highest rank. int maxRank = RankProgression.Keys.Max(); int maxGP = RankProgression[maxRank]; if (pcGP.Points >= maxGP) { pcGP.Points = maxGP - 1; } // Notify player how much GP they earned. player.SendMessage("You earned " + baseAmount + " " + dbGuild.Name + " guild points."); // Are we able to rank up? bool didRankUp = false; if (pcGP.Rank < maxRank) { // Is it time for a rank up? int nextRank = RankProgression[pcGP.Rank]; if (pcGP.Points >= nextRank) { // Let's do a rank up. pcGP.Rank++; player.SendMessage(ColorTokenService.Green("You've reached rank " + pcGP.Rank + " in the " + dbGuild.Name + "!")); didRankUp = true; } } // Submit changes to the DB/cache. DataService.SubmitDataChange(pcGP, DatabaseActionType.Update); // If the player ranked up, publish an event saying so. if (didRankUp) { MessageHub.Instance.Publish(new OnPlayerGuildRankUp(player.GlobalID, pcGP.Rank)); } }
public static void RunItemRepair(NWPlayer oPC, NWItem item, float amount, float maxReductionAmount) { // Prevent repairing for less than 0.01 if (amount < 0.01f) { return; } float maxDurability = GetMaxDurability(item) - maxReductionAmount; float durability = GetDurability(item) + amount; if (maxDurability < 0.01f) { maxDurability = 0.01f; } if (durability > maxDurability) { durability = maxDurability; } SetMaxDurability(item, maxDurability); SetDurability(item, durability); string durMessage = FormatDurability(durability) + " / " + FormatDurability(maxDurability); oPC.SendMessage(ColorTokenService.Green("You repaired your " + item.Name + ". (" + durMessage + ")")); }
/// <summary> /// Gives GP to a player for a given guild. /// If the baseAmount is less than 1, nothing will happen. /// If the baseAmount is greater than 1000, the baseAmount will be set to 1000. /// If the player ranks up, a message will be sent to him/her and an OnPlayerGuildRankUp event will be published. /// </summary> /// <param name="player">The player to give GP.</param> /// <param name="guild">The guild this GP will apply to.</param> /// <param name="baseAmount">The baseAmount of GP to grant.</param> public static void GiveGuildPoints(NWPlayer player, GuildType guild, int baseAmount) { if (baseAmount <= 0) { return; } // Clamp max GP baseAmount if (baseAmount > 1000) { baseAmount = 1000; } var dbGuild = DataService.Guild.GetByID((int)guild); var pcGP = DataService.PCGuildPoint.GetByPlayerIDAndGuildID(player.GlobalID, (int)guild); pcGP.Points += baseAmount; // Clamp player GP to the highest rank. int maxRank = RankProgression.Keys.Max(); int maxGP = RankProgression[maxRank]; if (pcGP.Points >= maxGP) { pcGP.Points = maxGP - 1; } // Notify player how much GP they earned. player.SendMessage("You earned " + baseAmount + " " + dbGuild.Name + " guild points."); // Are we able to rank up? bool didRankUp = false; if (pcGP.Rank < maxRank) { // Is it time for a rank up? int nextRank = RankProgression[pcGP.Rank]; if (pcGP.Points >= nextRank) { // Let's do a rank up. pcGP.Rank++; player.SendMessage(ColorTokenService.Green("You've reached rank " + pcGP.Rank + " in the " + dbGuild.Name + "!")); didRankUp = true; } } // Submit changes to the DB/cache. DataService.SubmitDataChange(pcGP, DatabaseActionType.Update); // If the player ranked up, publish an event saying so. if (didRankUp) { MessageHub.Instance.Publish(new OnPlayerGuildRankUp(player.GlobalID, pcGP.Rank)); } }
private static void ShowMOTD() { NWPlayer player = GetEnteringObject(); ServerConfiguration config = DataService.ServerConfiguration.Get(); string message = ColorTokenService.Green("Welcome to " + config.ServerName + "!\n\nMOTD: ") + ColorTokenService.White(config.MessageOfTheDay); DelayCommand(6.5f, () => { player.SendMessage(message); }); }
public static bool OnModuleExamine(NWPlayer examiner, NWObject target) { string backupDescription = target.GetLocalString("BACKUP_DESCRIPTION"); if (!string.IsNullOrWhiteSpace(backupDescription)) { target.UnidentifiedDescription = backupDescription; } if (!examiner.IsDM || !target.IsPlayer || target.IsDM) { return(false); } backupDescription = target.IdentifiedDescription; target.SetLocalString("BACKUP_DESCRIPTION", backupDescription); Player playerEntity = DataService.Player.GetByID(target.GlobalID); NWArea area = NWModule.Get().Areas.Single(x => x.Resref == playerEntity.RespawnAreaResref); string respawnAreaName = area.Name; StringBuilder description = new StringBuilder( ColorTokenService.Green("ID: ") + target.GlobalID + "\n" + ColorTokenService.Green("Character Name: ") + target.Name + "\n" + ColorTokenService.Green("Respawn Area: ") + respawnAreaName + "\n" + ColorTokenService.Green("Skill Points: ") + playerEntity.TotalSPAcquired + " (Unallocated: " + playerEntity.UnallocatedSP + ")" + "\n" + ColorTokenService.Green("FP: ") + playerEntity.CurrentFP + " / " + playerEntity.MaxFP + "\n" + ColorTokenService.Green("Skill Levels: ") + "\n\n"); List <PCSkill> pcSkills = SkillService.GetAllPCSkills(target.Object); foreach (PCSkill pcSkill in pcSkills) { Skill skill = SkillService.GetSkill(pcSkill.SkillID); description.Append(skill.Name).Append(" rank ").Append(pcSkill.Rank).AppendLine(); } description.Append("\n\n").Append(ColorTokenService.Green("Perks: ")).Append("\n\n"); var pcPerks = DataService.PCPerk.GetAllByPlayerID(target.GlobalID); foreach (PCPerk pcPerk in pcPerks) { var perk = DataService.Perk.GetByID(pcPerk.PerkID); description.Append(perk.Name).Append(" Lvl. ").Append(pcPerk.PerkLevel).AppendLine(); } description.Append("\n\n").Append(ColorTokenService.Green("Description: \n\n")).Append(backupDescription).AppendLine(); target.UnidentifiedDescription = description.ToString(); _.DelayCommand(0.1f, () => { _.SetDescription(target, backupDescription, false); }); return(true); }
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); } }
public static string BuildBlueprintHeader(NWPlayer player, bool showAddedComponentList) { var model = GetPlayerCraftingData(player); var bp = model.Blueprint; int playerEL = CalculatePCEffectiveLevel(player, model.PlayerSkillRank, (SkillType)bp.SkillID); var baseStructure = bp.BaseStructureID == null ? null : DataService.BaseStructure.GetByID(Convert.ToInt32(bp.BaseStructureID)); var mainComponent = DataService.ComponentType.GetByID(bp.MainComponentTypeID); var secondaryComponent = DataService.ComponentType.GetByID(bp.SecondaryComponentTypeID); var tertiaryComponent = DataService.ComponentType.GetByID(bp.TertiaryComponentTypeID); string header = ColorTokenService.Green("Blueprint: ") + bp.Quantity + "x " + bp.ItemName + "\n"; header += ColorTokenService.Green("Level: ") + (model.AdjustedLevel < 0 ? 0 : model.AdjustedLevel) + " (Base: " + (bp.BaseLevel < 0 ? 0 : bp.BaseLevel) + ")\n"; header += ColorTokenService.Green("Difficulty: ") + CalculateDifficultyDescription(playerEL, model.AdjustedLevel) + "\n"; if (baseStructure != null) { header += ColorTokenService.Green("Raises Atmosphere: "); if (baseStructure.HasAtmosphere) { header += ColorTokenService.Green("Yes"); } else { header += ColorTokenService.Red("No"); } header += "\n"; } header += ColorTokenService.Green("Required Components (Required/Maximum): ") + "\n\n"; string mainCounts = " (" + (model.MainMinimum > 0 ? Convert.ToString(model.MainMinimum) : "Optional") + "/" + model.MainMaximum + ")"; header += ColorTokenService.Green("Main: ") + mainComponent.Name + mainCounts + "\n"; if (bp.SecondaryMinimum > 0 && bp.SecondaryComponentTypeID > 0) { string secondaryCounts = " (" + (model.SecondaryMinimum > 0 ? Convert.ToString(model.SecondaryMinimum) : "Optional") + "/" + model.SecondaryMaximum + ")"; header += ColorTokenService.Green("Secondary: ") + secondaryComponent.Name + secondaryCounts + "\n"; } if (bp.TertiaryMinimum > 0 && bp.TertiaryComponentTypeID > 0) { string tertiaryCounts = " (" + (model.TertiaryMinimum > 0 ? Convert.ToString(model.TertiaryMinimum) : "Optional") + "/" + model.TertiaryMaximum + ")"; header += ColorTokenService.Green("Tertiary: ") + tertiaryComponent.Name + tertiaryCounts + "\n"; } if (bp.EnhancementSlots > 0) { int nSlots = bp.EnhancementSlots; if (model.IsInitialized) { // We have the player's stats, so tell them how many they can actually add. if (model.PlayerPerkLevel / 2 < nSlots) { nSlots = model.PlayerPerkLevel / 2; } } string enhancementSlots = " (0/" + Convert.ToString(nSlots) + ")"; header += ColorTokenService.Green("Enhancement slots: ") + enhancementSlots + "\n"; } if (showAddedComponentList) { header += "\n" + ColorTokenService.Green("Your components:") + "\n\n"; if (!model.HasPlayerComponents) { header += "No components selected yet!"; } else { foreach (var item in model.MainComponents) { header += item.Name + "\n"; } foreach (var item in model.SecondaryComponents) { header += item.Name + "\n"; } foreach (var item in model.TertiaryComponents) { header += item.Name + "\n"; } foreach (var item in model.EnhancementComponents) { header += item.Name + "\n"; } } } return(header); }
/// <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); } }
public static string PrismaticString() { return(ColorTokenService.Red("p") + ColorTokenService.Orange("r") + ColorTokenService.Yellow("i") + ColorTokenService.Green("s") + ColorTokenService.Blue("m") + ColorTokenService.LightPurple("a") + ColorTokenService.Purple("t") + ColorTokenService.White("i") + ColorTokenService.Black("c")); }
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.")); } }
/// <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.")); } }