/// <summary> /// Processes and runs the specific chat command entered by the user. /// </summary> /// <param name="commandName">Name of the command</param> /// <param name="sender">The sender object</param> /// <param name="target">The target of the command. OBJECT_INVALID if no target is necessary.</param> /// <param name="targetLocation">The target location of the command. null if no target is necessary.</param> /// <param name="args">User-entered arguments</param> private static void ProcessChatCommand(string commandName, uint sender, uint target, Location targetLocation, string args) { var command = ChatCommands[commandName]; if (targetLocation == null) { targetLocation = new Location(IntPtr.Zero); } var authorization = Authorization.GetAuthorizationLevel(sender); if (command.Permissions.HasFlag(CommandPermissionType.Player) && authorization == AuthorizationLevel.Player || command.Permissions.HasFlag(CommandPermissionType.DM) && authorization == AuthorizationLevel.DM || command.Permissions.HasFlag(CommandPermissionType.Admin) && authorization == AuthorizationLevel.Admin) { string[] argsArr = string.IsNullOrWhiteSpace(args) ? new string[0] : args.Split(' ').ToArray(); string error = command.ValidateArguments(sender, argsArr); if (!string.IsNullOrWhiteSpace(error)) { SendMessageToPC(sender, error); } else { command.DoAction(sender, target, targetLocation, argsArr); } } else { SendMessageToPC(sender, ColorToken.Red("Invalid chat command. Use '/help' to get a list of available commands.")); } }
/// <summary> /// Handles the card list logic. /// </summary> /// <param name="page">The page to build</param> private void ViewCardsPageInit(DialogPage page) { var model = GetDataModel <Model>(); var player = GetPC(); var playerId = GetObjectUUID(player); var dbPlayerTripleTriad = DB.Get <PlayerTripleTriad>(playerId) ?? new PlayerTripleTriad(); var availableCards = TripleTriad.GetAllCardsAtLevel(model.SelectedCardLevel); page.Header = $"{ColorToken.Green("Level: ")} {model.SelectedCardLevel}\n\n" + $"The following is the list of cards available at this level. Cards in {ColorToken.Green("GREEN")} have been acquired. Those in {ColorToken.Red("RED")} have not. Only one card per type can be collected.\n\n" + "Please select a card."; foreach (var(type, card) in availableCards) { if (!card.IsVisibleInMenu) { continue; } var option = dbPlayerTripleTriad.AvailableCards.ContainsKey(type) ? ColorToken.Green(card.Name) : ColorToken.Red(card.Name); page.AddResponse(option, () => { model.SelectedCardType = type; SetLocalInt(player, "CARD_MENU_SELECTED_CARD_ID", (int)model.SelectedCardType); ChangePage(ViewCardDetailsPageId); }); } }
/// <summary> /// Handles the "Sell House Page" header and responses. /// </summary> /// <param name="page">The page we're building.</param> private void SellHousePageInit(DialogPage page) { var player = GetPC(); var playerId = GetObjectUUID(player); var dbHouse = DB.Get <PlayerHouse>(playerId); var model = GetDataModel <Model>(); var houseDetail = Housing.GetHouseTypeDetail(dbHouse.HouseType); var gil = houseDetail.Price / 2; page.Header = ColorToken.Red("WARNING: ") + "You are about to sell your property. All items contained inside will be permanently lost!\n\n" + "It is highly recommended you pick up all items and furniture inside before selling the property.\n\n" + ColorToken.Green($"You will receive {gil} gil for the sale of this property. Are you sure you wish to sell it?"); if (model.IsConfirmingSell) { page.AddResponse(ColorToken.Red($"CONFIRM SELL PROPERTY"), () => { DB.Delete <PlayerHouse>(playerId); GiveGoldToCreature(player, gil); FloatingTextStringOnCreature($"Property sold successfully for {gil} gil.", player, false); EndConversation(); Log.Write(LogGroup.PlayerHousing, $"Player {GetName(player)} (ID = '{playerId}') sold their property for {gil} gil."); }); } else { page.AddResponse(ColorToken.Red("Sell Property"), () => { model.IsConfirmingSell = true; }); } }
public string ValidateArguments(NWGameObject user, params string[] args) { if (args.Length <= 0) { return(ColorToken.Red("Please specify a quantity. Example: /" + nameof(SpawnGold) + " 34")); } return(string.Empty); }
public string ValidateArguments(NWGameObject user, params string[] args) { if (args.Length <= 0) { return(ColorToken.Red("Please specify a resref and optionally a quantity. Example: /" + nameof(SpawnItem) + " my_resref 20")); } return(string.Empty); }
private static string HandleArgumentValidation(uint user, params string[] args) { if (args.Length <= 0) { return(ColorToken.Red("Please specify a resref and optionally a quantity. Example: /spawnitem my_resref 20")); } return(string.Empty); }
private string GetLeaseStatus() { var player = GetPC(); var playerId = GetObjectUUID(player); var dbPlayerStore = DB.Get <PlayerStore>(playerId); var leaseStatus = DateTime.UtcNow > dbPlayerStore.DateLeaseExpires ? ColorToken.Red("EXPIRED") : dbPlayerStore.DateLeaseExpires.ToString("MM/dd/yyyy hh:mm:ss"); return(leaseStatus); }
/// <summary> /// Validates whether all requirements to use ability are met. /// Returns true if successful, false otherwise. /// </summary> /// <param name="stats">The user's ability stats</param> /// <returns>true if successful, false otherwise</returns> private static bool ValidateFeatUse(UserStats stats) { var user = stats.User; var ability = stats.AbilityDefinition; var target = stats.Target; var canUse = ability.CanUse(user, target); if (stats.MP < stats.MPCost) { SendMessageToPC(user, ColorToken.Red("Insufficient MP.")); return(false); } if (!GetIsObjectValid(user)) { return(false); } if (!GetIsObjectValid(target)) { SendMessageToPC(user, ColorToken.Red("Target lost.")); return(false); } if (!string.IsNullOrWhiteSpace(canUse)) { SendMessageToPC(user, ColorToken.Red(canUse)); return(false); } if (stats.Now < stats.CooldownUnlock) { var timeToWait = Time.GetTimeToWaitLongIntervals(stats.Now, stats.CooldownUnlock, false); SendMessageToPC(user, ColorToken.Red($"Ability available in {timeToWait}.")); return(false); } if (!LineOfSightObject(user, target)) { SendMessageToPC(user, ColorToken.Red($"You cannot see your target.")); return(false); } if (GetIsBusy(user) || GetCurrentHitPoints(user) <= 0 || !GetCommandable(user)) { SendMessageToPC(user, ColorToken.Red("You are too busy.")); return(false); } return(true); }
public static void ValidateDualWield() { var creature = OBJECT_SELF; var item = StringToObject(Events.GetEventData("ITEM")); var slot = (InventorySlot)Convert.ToInt32(Events.GetEventData("SLOT")); // Not equipping to the left hand, or there's nothing equipped in the right hand. if (slot != InventorySlot.LeftHand) { return; } if (!GetIsObjectValid(GetItemInSlot(InventorySlot.RightHand, creature))) { return; } var baseItem = GetBaseItemType(item); var dualWieldWeapons = new[] { BaseItem.ShortSword, BaseItem.Longsword, BaseItem.BattleAxe, BaseItem.BastardSword, BaseItem.LightFlail, BaseItem.LightMace, BaseItem.Dagger, BaseItem.Club, BaseItem.HandAxe, BaseItem.Kama, BaseItem.Katana, BaseItem.Kukri, BaseItem.Rapier, BaseItem.Scimitar, BaseItem.Sickle }; if (!dualWieldWeapons.Contains(baseItem)) { return; } var dualWieldLevel = Perk.GetEffectivePerkLevel(creature, PerkType.DualWield); if (dualWieldLevel <= 0) { SendMessageToPC(creature, ColorToken.Red("Equipping two weapons requires the Dual Wield perk.")); Events.SkipEvent(); } }
/// <summary> /// Handles the card details logic. /// </summary> /// <param name="page">The page to build</param> private void ViewCardDetailsPageInit(DialogPage page) { var player = GetPC(); var playerId = GetObjectUUID(player); var dbPlayerTripleTriad = DB.Get <PlayerTripleTriad>(playerId); var model = GetDataModel <Model>(); var card = TripleTriad.GetCardByType(model.SelectedCardType); var dateAcquired = dbPlayerTripleTriad.AvailableCards.ContainsKey(model.SelectedCardType) ? dbPlayerTripleTriad.AvailableCards[model.SelectedCardType].ToString("yyyy-MM-dd hh:mm:ss") : ColorToken.Red("Unacquired"); page.Header = $"{ColorToken.Green("Name: ")} {card.Name}\n" + $"{ColorToken.Green("Level: ")} {card.Level}\n" + $"{ColorToken.Green("Date Acquired: ")} {dateAcquired}"; }
public static void ValidateItemEquip() { var creature = OBJECT_SELF; var item = StringToObject(Events.GetEventData("ITEM")); var error = CanItemBeUsed(creature, item); if (string.IsNullOrWhiteSpace(error)) { ApplyEquipTriggers(); return; } SendMessageToPC(creature, ColorToken.Red(error)); Events.SkipEvent(); }
public static void TakeItem() { var disturbType = GetInventoryDisturbType(); if (disturbType != DisturbType.Removed) { return; } var player = GetLastDisturbed(); var item = GetInventoryDisturbItem(); var resref = GetResRef(item); var device = OBJECT_SELF; var state = Craft.GetPlayerCraftingState(player); if (state.IsAutoCrafting) { SendMessageToPC(player, ColorToken.Red("You are auto-crafting.")); return; } // Auto-craft item if (resref == AutoCraftItemResref) { Item.ReturnItem(device, item); AutoCraftItem(player); } // Manually craft the item else if (resref == CraftItemResref) { Item.ReturnItem(device, item); CraftItem(player); } // Load components into container else if (resref == LoadComponentsResref) { Item.ReturnItem(device, item); LoadComponents(player); } // Select a different recipe else if (resref == SelectRecipeResref) { Item.ReturnItem(device, item); SelectRecipe(player); } }
/// <summary> /// Handles the card selection logic for deck building. /// This differs from the card viewer in that cards show based on which cards the player owns. /// </summary> /// <param name="page">The page to build.</param> private void DeckCardSelectionListPageInit(DialogPage page) { var player = GetPC(); var playerId = GetObjectUUID(player); var dbPlayerTripleTriad = DB.Get <PlayerTripleTriad>(playerId); var model = GetDataModel <Model>(); var cardsAtLevel = TripleTriad.GetAllCardsAtLevel(model.SelectedCardLevel); page.Header = $"{ColorToken.Green("Level: ")} {model.SelectedCardLevel}\n\n" + "Please select cards to add to this deck."; if (model.CurrentCardNumber > 1) { page.AddResponse(ColorToken.Red("Remove Card"), RemoveTopMostCard); } foreach (var(cardType, card) in cardsAtLevel) { if (!card.IsVisibleInMenu) { continue; } // Only one of each card type can be added to decks. if (IsInActiveDeck(cardType)) { continue; } if (dbPlayerTripleTriad.AvailableCards.ContainsKey(cardType)) { page.AddResponse($"Add: {card.Name}", () => { SetLocalInt(player, $"CARD_MENU_DECK_CARD_{model.CurrentCardNumber}", (int)cardType); model.CurrentCardNumber++; // This was the last card. if (model.CurrentCardNumber > 5) { ChangePage(DeckCardSelectionConfirmDeckPageId); } }); } } }
/// <summary> /// Handles the card selection level logic for deck building. /// This differs from the card viewer in that levels show based on which cards the player owns. /// </summary> /// <param name="page">The page to build.</param> private void DeckCardSelectionLevelsPageInit(DialogPage page) { var player = GetPC(); var playerId = GetObjectUUID(player); var dbPlayerTripleTriad = DB.Get <PlayerTripleTriad>(playerId); var model = GetDataModel <Model>(); var levels = new HashSet <int>(); page.Header = "Please select cards to add to this deck."; if (model.CurrentCardNumber > 1) { page.AddResponse(ColorToken.Red("Remove Card"), RemoveTopMostCard); } foreach (var(cardType, _) in dbPlayerTripleTriad.AvailableCards) { var card = TripleTriad.GetCardByType(cardType); if (!card.IsVisibleInMenu) { continue; } if (!levels.Contains(card.Level)) { levels.Add(card.Level); } } page.Header = $"{ColorToken.Green("Select card #")} {model.CurrentCardNumber}"; foreach (var level in levels) { page.AddResponse($"Level {level}", () => { model.SelectedCardLevel = level; ChangePage(DeckCardSelectionListPageId); }); } }
private void MainPageInit(DialogPage page) { var player = GetPC(); var cdKey = GetPCPublicCDKey(player); var account = DB.Get <Account>(cdKey) ?? new Account(); var achievements = account.Achievements; var activeAchievements = Achievement.GetActiveAchievements(); var model = GetDataModel <Model>(); foreach (var achievement in activeAchievements) { var text = achievements.ContainsKey(achievement.Key) ? ColorToken.Green(achievement.Value.Name) : ColorToken.Red(achievement.Value.Name); page.AddResponse(text, () => { model.Type = achievement.Key; ChangePage(AchievementDetailId); }); } }
private void AchievementDetailInit(DialogPage page) { var player = GetPC(); var cdKey = GetPCPublicCDKey(player); var account = DB.Get <Account>(cdKey) ?? new Account(); var activeAchievements = Achievement.GetActiveAchievements(); var model = GetDataModel <Model>(); var achievement = activeAchievements[model.Type]; page.Header = ColorToken.Green("Name: ") + achievement.Name + "\n" + ColorToken.Green("Description: ") + achievement.Description + "\n\n"; if (account.Achievements.ContainsKey(model.Type)) { var pcAchievement = account.Achievements[model.Type]; page.Header += ColorToken.Green("Unlocked: ") + pcAchievement.ToString("yyyy-MM-dd hh:mm:ss"); } else { page.Header += ColorToken.Red("Not yet acquired."); } }
private static void HandleAction(uint user, uint target, Location targetLocation, params string[] args) { string resref = args[0]; int quantity = 1; if (args.Length > 1) { if (!int.TryParse(args[1], out quantity)) { return; } } uint item = (CreateItemOnObject(resref, user, quantity)); if (!GetIsObjectValid(item)) { SendMessageToPC(user, ColorToken.Red("Item not found! Did you enter the correct ResRef?")); return; } SetIdentified(item, true); }
private static void ProcessChatCommand(IChatCommand command, NWGameObject sender, NWGameObject target, Location targetLocation, string args) { if (target == null) { target = new NWGameObject(); } if (targetLocation == null) { targetLocation = new Location(); } CommandDetailsAttribute attribute = command.GetType().GetCustomAttribute <CommandDetailsAttribute>(); var authorization = AuthorizationRegistry.GetAuthorizationLevel(sender); if (attribute != null && (attribute.Permissions.HasFlag(CommandPermissionType.Player) && authorization == AuthorizationLevel.Player || attribute.Permissions.HasFlag(CommandPermissionType.DM) && authorization == AuthorizationLevel.DM || attribute.Permissions.HasFlag(CommandPermissionType.Admin) && authorization == AuthorizationLevel.Admin)) { string[] argsArr = string.IsNullOrWhiteSpace(args) ? new string[0] : args.Split(' ').ToArray(); string error = command.ValidateArguments(sender, argsArr); if (!string.IsNullOrWhiteSpace(error)) { SendMessageToPC(sender, error); } else { command.DoAction(sender, target, targetLocation, argsArr); } } else { SendMessageToPC(sender, ColorToken.Red("Invalid chat command. Use '/help' to get a list of available commands.")); } }
public Dice() { _genericError = ColorToken.Red("Please enter /dice help for more information on how to use this command."); }
/// <summary> /// Handles the auto-craft procedure. This is an automatic (no mini-game) form of crafting /// where success is determined by a player's stats. This simply creates the item on a successful crafting attempt. /// </summary> /// <param name="player">The player performing the auto-craft.</param> private static void AutoCraftItem(uint player) { var state = Craft.GetPlayerCraftingState(player); var device = OBJECT_SELF; float CalculateAutoCraftingDelay() { var baseDelay = 20f; var perk = _autoCraftPerk[state.DeviceSkillType]; switch (Perk.GetEffectivePerkLevel(player, perk)) { case 2: baseDelay -= 4; break; case 3: baseDelay -= 8; break; case 4: baseDelay -= 12; break; case 5: baseDelay -= 16; break; } return(baseDelay); } void CraftItem(bool isSuccessful) { var recipe = Craft.GetRecipe(state.SelectedRecipe); var playerComponents = GetComponents(player, device); var remainingComponents = recipe.Components.ToDictionary(x => x.Key, y => y.Value); for (var index = playerComponents.Count - 1; index >= 0; index--) { var component = playerComponents[index]; var resref = GetResRef(component); // Item does not need any more of this component type. if (!remainingComponents.ContainsKey(resref)) { continue; } var quantity = GetItemStackSize(component); // Player's component stack size is greater than the amount required. if (quantity > remainingComponents[resref]) { SetItemStackSize(component, quantity - remainingComponents[resref]); remainingComponents[resref] = 0; } // Player's component stack size is less than or equal to the amount required. else if (quantity <= remainingComponents[resref]) { remainingComponents[resref] -= quantity; DestroyObject(component); } if (remainingComponents[resref] <= 0) { remainingComponents.Remove(resref); } } if (isSuccessful) { CreateItemOnObject(recipe.Resref, player, recipe.Quantity); } } if (!HasAllComponents(player, device)) { SendMessageToPC(player, ColorToken.Red("You are missing some necessary components...")); return; } var craftingDelay = CalculateAutoCraftingDelay(); state.IsAutoCrafting = true; Player.StartGuiTimingBar(player, craftingDelay); AssignCommand(player, () => ActionPlayAnimation(Animation.LoopingGetMid, 1f, craftingDelay)); DelayCommand(craftingDelay, () => { // Player logged out. if (!GetIsObjectValid(player)) { Craft.ClearPlayerCraftingState(player); return; } var chanceToCraft = Craft.CalculateChanceToCraft(player, state.SelectedRecipe); var roll = Random.NextFloat(0f, 100f); if (roll <= chanceToCraft) { CraftItem(true); } else { CraftItem(false); SendMessageToPC(player, ColorToken.Red("You failed to craft the item...")); } state.IsAutoCrafting = false; }); ApplyEffectToObject(DurationType.Temporary, EffectCutsceneParalyze(), player, craftingDelay); }
/// <summary> /// Sends a message to a player informing them of the current number of items in the container and the maximum allowed. /// If incrementByOne is true, the current count will be increased by one. This is to account for the fact that /// the OnAddItem event fires before the item is actually added to the inventory (therefore it would have an off-by-one error) /// </summary> /// <param name="player">The player receiving the message</param> /// <param name="incrementByOne">Increments current item count by one if true, else does nothing.</param> protected static void SendItemLimitMessage(NWGameObject player, bool incrementByOne) { var container = NWGameObject.OBJECT_SELF; var limit = GetItemLimit(); var count = _.GetInventoryItemCount(container); // The Add event fires before the item exists in the container. Need to increment by one in this scenario. if (incrementByOne) { count++; } _.SendMessageToPC(player, ColorToken.White("Item Limit: " + (count > limit ? limit : count) + " / ") + ColorToken.Red("" + limit)); }
/// <summary> /// Builds all chat commands and puts them into cache. /// </summary> private static void LoadChatCommands() { ChatCommands["bored"] = new ChatCommandDefinition( "Plays a bored animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetPauseBored)); }, (user, args) => string.Empty, false); ChatCommands["bow"] = new ChatCommandDefinition( "Plays a bow animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetBow)); }, (user, args) => string.Empty, false); ChatCommands["bug"] = new BugReportChatCommandDefinition(); ChatCommands["cdkey"] = new ChatCommandDefinition( "Displays your public CD key.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { string cdKey = GetPCPublicCDKey(user); SendMessageToPC(user, "Your public CD Key is: " + cdKey); }, (user, args) => string.Empty, false); ChatCommands["coord"] = new ChatCommandDefinition( "Displays your current coordinates in the area.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { Vector3 position = GetPosition(user); int cellX = (int)(position.X / 10); int cellY = (int)(position.Y / 10); SendMessageToPC(user, $"Current Area Coordinates: ({cellX}, {cellY})"); }, (user, args) => string.Empty, false); ChatCommands["copyitem"] = new ChatCommandDefinition( "Copies the targeted item.", CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { if (GetObjectType(target) != ObjectType.Item) { SendMessageToPC(user, "You can only copy items with this command."); return; } CopyItem(target, user, true); SendMessageToPC(user, "Item copied successfully."); }, (user, args) => string.Empty, true); ChatCommands["day"] = new ChatCommandDefinition( "Sets the world time to 8 AM.", CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { SetTime(8, 0, 0, 0); }, (user, args) => string.Empty, false); ChatCommands["deadback"] = new ChatCommandDefinition( "Plays a dead back animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { LoopingAnimationAction(user, Animation.LoopingDeadBack, args); }, (user, args) => string.Empty, false); ChatCommands["deadfront"] = new ChatCommandDefinition( "Plays a dead front animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { LoopingAnimationAction(user, Animation.LoopingDeadFront, args); }, (user, args) => string.Empty, false); ChatCommands["delete"] = new CharacterDeletionChatCommandDefinition(); ChatCommands["dice"] = new DiceChatCommandDefinition(); ChatCommands["drink"] = new ChatCommandDefinition( "Plays a drinking animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetDrink)); }, (user, args) => string.Empty, false); ChatCommands["drunk"] = new ChatCommandDefinition( "Plays a drunk animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { LoopingAnimationAction(user, Animation.LoopingPauseDrunk, args); }, (user, args) => string.Empty, false); ChatCommands["duck"] = new ChatCommandDefinition( "Plays a duck animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetDodgeDuck)); }, (user, args) => string.Empty, false); ChatCommands["getlocalfloat"] = new GetLocalFloatChatCommandDefinition(); ChatCommands["getlocalint"] = new GetLocalIntChatCommandDefinition(); ChatCommands["getlocalstring"] = new GetLocalStringChatCommandDefinition(); ChatCommands["getplot"] = new ChatCommandDefinition( "Gets whether an object is marked plot.", CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { if (GetPlotFlag(target)) { SendMessageToPC(user, "Target is marked plot."); } else { SendMessageToPC(user, "Target is NOT marked plot."); } }, (user, args) => string.Empty, true); ChatCommands["greet"] = new ChatCommandDefinition( "Plays a greet animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetGreeting)); }, (user, args) => string.Empty, false); ChatCommands["help"] = new ChatCommandDefinition( "Displays all chat commands available to you.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { var authorization = Authorization.GetAuthorizationLevel(user); if (authorization == AuthorizationLevel.DM) { SendMessageToPC(user, HelpTextDM); } else if (authorization == AuthorizationLevel.Admin) { SendMessageToPC(user, HelpTextAdmin); } else { SendMessageToPC(user, HelpTextPlayer); } }, (user, args) => string.Empty, false); ChatCommands["interact"] = new ChatCommandDefinition( "Plays an interact animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.LoopingGetMid)); }, (user, args) => string.Empty, false); ChatCommands["kill"] = new ChatCommandDefinition( "Kills your target.", CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { var amount = GetMaxHitPoints(target) + 11; var damage = EffectDamage(amount); ApplyEffectToObject(DurationType.Instant, damage, target); }, (user, args) => string.Empty, false); ChatCommands["laughing"] = new ChatCommandDefinition( "Plays a laughing animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { LoopingAnimationAction(user, Animation.LoopingTalkLaughing, args); }, (user, args) => string.Empty, false); ChatCommands["listen"] = new ChatCommandDefinition( "Plays a listen animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { LoopingAnimationAction(user, Animation.LoopingListen, args); }, (user, args) => string.Empty, false); ChatCommands["look"] = new ChatCommandDefinition( "Plays a look far animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { LoopingAnimationAction(user, Animation.LoopingLookFar, args); }, (user, args) => string.Empty, false); ChatCommands["name"] = new ChatCommandDefinition( "Plays a drunk animation.", CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { if (GetIsPC(target) || GetIsDM(target)) { SendMessageToPC(user, "PCs cannot be targeted with this command."); return; } string name = string.Empty; foreach (var arg in args) { name += " " + arg; } SetName(target, name); }, (user, args) => { if (args.Length <= 0) { return("Please enter a name. Example: /name My Creature"); } return(string.Empty); }, false); ChatCommands["night"] = new ChatCommandDefinition( "Sets the world time to 8 AM.", CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { SetTime(20, 0, 0, 0); }, (user, args) => string.Empty, false); ChatCommands["pickup"] = new ChatCommandDefinition( "Plays an interact animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.LoopingGetLow)); }, (user, args) => string.Empty, false); ChatCommands["pos"] = new ChatCommandDefinition( "Displays your current position in the area.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { var position = GetPosition(user); SendMessageToPC(user, $"Current Position: ({position.X}, {position.Y}, {position.Z})"); }, (user, args) => string.Empty, false); ChatCommands["read"] = new ChatCommandDefinition( "Plays a read animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetRead)); }, (user, args) => string.Empty, false); ChatCommands["rest"] = new ChatCommandDefinition( "Opens the rest menu.", CommandPermissionType.Player, (user, target, location, args) => { Dialog.StartConversation(user, user, nameof(RestMenu)); }, (user, args) => string.Empty, false); ChatCommands["rez"] = new ChatCommandDefinition( "Revives you, heals you to full, and restores all MP.", CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { if (GetIsDead(user)) { ApplyEffectToObject(DurationType.Instant, EffectResurrection(), user); } ApplyEffectToObject(DurationType.Instant, EffectHeal(999), user); }, (user, args) => string.Empty, false); ChatCommands["salute"] = new ChatCommandDefinition( "Plays a salute animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetSalute)); }, (user, args) => string.Empty, false); ChatCommands["save"] = new ChatCommandDefinition( "Manually saves your character. Your character also saves automatically every few minutes.", CommandPermissionType.Player, (user, target, location, args) => { ExportSingleCharacter(user); SendMessageToPC(user, "Character saved successfully."); }, (user, args) => string.Empty, false); ChatCommands["scratchhead"] = new ChatCommandDefinition( "Plays a scratch head animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetPauseScratchHead)); }, (user, args) => string.Empty, false); ChatCommands["setlocalfloat"] = new SetLocalFloatChatCommandDefinition(); ChatCommands["setlocalint"] = new SetLocalIntChatCommandDefinition(); ChatCommands["setlocalstring"] = new SetLocalStringChatCommandDefinition(); ChatCommands["setportrait"] = new SetPortraitChatCommandDefinition(); ChatCommands["sidestep"] = new ChatCommandDefinition( "Plays a side-step animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetDodgeSide)); }, (user, args) => string.Empty, false); ChatCommands["sit"] = new ChatCommandDefinition( "Makes your character sit down.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { LoopingAnimationAction(user, Animation.LoopingSitCross, args); }, (user, args) => string.Empty, false); ChatCommands["spasm"] = new ChatCommandDefinition( "Plays a spasm animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetSpasm)); }, (user, args) => string.Empty, false); ChatCommands["spawngold"] = new ChatCommandDefinition( "Spawns gold of a specific quantity on your character. Example: /spawngold 33", CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { int quantity = 1; if (args.Length >= 1) { if (!int.TryParse(args[0], out quantity)) { return; } } GiveGoldToCreature(user, quantity); }, (user, args) => { if (args.Length <= 0) { return(ColorToken.Red("Please specify a quantity. Example: /spawngold 34")); } return(string.Empty); }, false); ChatCommands["spawnitem"] = new SpawnItemChatCommandDefinition(); ChatCommands["taunt"] = new ChatCommandDefinition( "Plays a taunt animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetTaunt)); }, (user, args) => string.Empty, false); ChatCommands["time"] = new ChatCommandDefinition( "Returns the current UTC server time.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { DateTime now = DateTime.UtcNow; string nowText = now.ToString("yyyy-MM-dd hh:mm:ss"); SendMessageToPC(user, "Current Server Date: " + nowText); }, (user, args) => string.Empty, false); ChatCommands["tired"] = new ChatCommandDefinition( "Plays a taunt animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { LoopingAnimationAction(user, Animation.LoopingPauseTired, args); }, (user, args) => string.Empty, false); ChatCommands["tpwp"] = new ChatCommandDefinition( "Teleports you to a waypoint with a specified tag.", CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { string tag = args[0]; uint wp = GetWaypointByTag(tag); if (!GetIsObjectValid(wp)) { SendMessageToPC(user, "Invalid waypoint tag. Did you enter the right tag?"); return; } AssignCommand(user, () => ActionJumpToLocation(GetLocation(wp))); }, (user, args) => { if (args.Length < 1) { return("You must specify a waypoint tag. Example: /tpwp MY_WAYPOINT_TAG"); } return(string.Empty); }, false); ChatCommands["victory1"] = new ChatCommandDefinition( "Plays a victory 1 animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetVictory1)); }, (user, args) => string.Empty, false); ChatCommands["victory2"] = new ChatCommandDefinition( "Plays a victory 2 animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetVictory2)); }, (user, args) => string.Empty, false); ChatCommands["victory3"] = new ChatCommandDefinition( "Plays a victory 3 animation.", CommandPermissionType.Player | CommandPermissionType.DM | CommandPermissionType.Admin, (user, target, location, args) => { AssignCommand(user, () => ActionPlayAnimation(Animation.FireForgetVictory3)); }, (user, args) => string.Empty, false); }
public override async Task <int> Main() { var results = new List <ColorToken[]> { new [] { "NAME".White(), "CURRENT".White(), "WANTED".White(), "LATEST".White() } }; var definition = LoadDefinition(); foreach (var dependency in definition?.Dependencies ?? new Dictionary <Name, VersionRange>()) { var repo = definition?.Repositories?.FirstOrDefault(r => r.Name.ToString() == dependency.Key.ToString()); var adapter = new AdapterBuilder(dependency.Key, repo).Adapter(); var versions = (await adapter.GetVersions()).ToList(); var versionMatch = versions.LastOrDefault(version => dependency.Value.IsSatisfied(version)); if (versionMatch == null) { throw new Exception("No matching version found"); } var current = "MISSING".Red(); ColorToken wanted = versionMatch.ToString(); ColorToken latest = versions.Last().ToString(); var pluginDefinition = new FileInfo(Path.Combine(Environment.CurrentDirectory, ConfigurationManager.PluginPath, dependency.Key.Vendor, dependency.Key.Project, ConfigurationManager.DefinitionFile)); if (pluginDefinition.Exists) { var plugin = Plugin.Load(pluginDefinition.FullName); current = plugin.Version.ToString(); current = current.Text != wanted.Text ? current.Red() : current.Green(); wanted = wanted.Text != latest.Text ? wanted.Red() : wanted.Green(); if (!this.All && current.Text == wanted.Text && wanted.Text == latest.Text) { continue; } } results.Add(new[] { dependency.Key.ToString(), current, wanted, latest }); } if (results.Count < 2) { return(0); } var nameLength = Math.Max(Math.Min(50, results.Max(d => d[0].Text.Length)), 10); var currentLength = Math.Max(Math.Min(20, results.Max(d => d[1].Text.ToString().Length)), 7); var wantedLength = Math.Max(Math.Min(20, results.Max(d => d[2].Text.ToString().Length)), 7); var latestLength = Math.Max(Math.Min(20, results.Max(d => d[3].Text.ToString().Length)), 7); foreach (var result in results) { result[0].Text = result[0].Text.Truncate(nameLength).PadRight(nameLength); result[1].Text = result[1].Text.Truncate(currentLength).PadLeft(currentLength); result[2].Text = result[2].Text.Truncate(wantedLength).PadLeft(wantedLength); result[3].Text = result[3].Text.Truncate(latestLength).PadLeft(latestLength); Console.WriteLine(result[0], " | ", result[1], " | ", result[2], " | ", result[3]); } return(await Task.FromResult(0)); }
public static void HandleChatMessage() { uint sender = OBJECT_SELF; string originalMessage = Chat.GetMessage().Trim(); if (!CanHandleChat(sender, originalMessage)) { return; } var split = originalMessage.Split(' ').ToList(); // Commands with no arguments won't be split, so if we didn't split anything then add the command to the split list manually. if (split.Count <= 0) { split.Add(originalMessage); } split[0] = split[0].ToLower(); string command = split[0].Substring(1, split[0].Length - 1); split.RemoveAt(0); Chat.SkipMessage(); if (!ChatCommands.ContainsKey(command)) { SendMessageToPC(sender, ColorToken.Red("Invalid chat command. Use '/help' to get a list of available commands.")); return; } var chatCommand = ChatCommands[command]; string args = string.Join(" ", split); if (!chatCommand.RequiresTarget) { ProcessChatCommand(command, sender, OBJECT_INVALID, null, args); } else { string error = chatCommand.ValidateArguments(sender, split.ToArray()); if (!string.IsNullOrWhiteSpace(error)) { SendMessageToPC(sender, error); return; } SetLocalString(sender, "CHAT_COMMAND", command); SetLocalString(sender, "CHAT_COMMAND_ARGS", command); SendMessageToPC(sender, "Please use your 'Chat Command Targeter' feat to select the target of this chat command."); if (!GetHasFeat(Feat.ChatCommandTargeter, sender) || GetIsDM(sender) || GetIsDMPossessed(sender)) { Creature.AddFeatByLevel(sender, Feat.ChatCommandTargeter, 1); if (GetIsDM(sender) || GetIsDMPossessed(sender)) { var qbs = Player.GetQuickBarSlot(sender, 11); if (qbs.ObjectType == QuickBarSlotType.Empty) { Player.SetQuickBarSlot(sender, 11, PlayerQuickBarSlot.UseFeat(Feat.ChatCommandTargeter)); } } } } }
private void RecipePageInit(DialogPage page) { var model = GetDataModel <Model>(); var player = GetPC(); var meetsRequirements = true; string BuildHeader() { var recipe = Craft.GetRecipe(model.SelectedRecipe); var category = Craft.GetCategoryDetail(recipe.Category); var skill = Skill.GetSkillDetails(recipe.Skill); // Recipe quantity and name. var header = $"{ColorToken.Green("Recipe:")} {recipe.Quantity}x {recipe.Name} \n"; // Associated skill header += $"{ColorToken.Green("Craft:")} {skill.Name}\n"; // Associated category header += $"{ColorToken.Green("Category:")} {category.Name}\n"; // Recipe's description, if available. if (!string.IsNullOrWhiteSpace(recipe.Description)) { header += $"{ColorToken.Green("Description:")} {recipe.Description} \n"; } // Chance to craft header += $"{ColorToken.Green("Chance to Auto-Craft:")} {Craft.CalculateChanceToCraft(player, model.SelectedRecipe)}%"; // List of requirements, if applicable. if (recipe.Requirements.Count > 0) { header += $"\n{ColorToken.Green("Requirements:")}\n\n"; foreach (var req in recipe.Requirements) { // If the player meets the requirement, show it in green. Otherwise show it in red. if (string.IsNullOrWhiteSpace(req.CheckRequirements(player))) { header += $"{ColorToken.Green(req.RequirementText)}\n"; } else { header += $"{ColorToken.Red(req.RequirementText)}\n"; meetsRequirements = false; } } } // List of components header += $"\n\n{ColorToken.Green("Components:")}\n\n"; foreach (var(resref, quantity) in recipe.Components) { var name = Cache.GetItemNameByResref(resref); header += $"{quantity}x {name}\n"; } return(header); } page.Header = BuildHeader(); if (model.IsFabricator && meetsRequirements) { page.AddResponse("Select Recipe", () => { var state = Craft.GetPlayerCraftingState(player); state.SelectedRecipe = model.SelectedRecipe; EndConversation(); Player.ForcePlaceableInventoryWindow(player, OBJECT_SELF); }); } }
private void ListingInit(DialogPage page) { var player = GetPC(); var playerId = GetObjectUUID(player); var dbPlayerStore = DB.Get <PlayerStore>(playerId); var model = GetDataModel <Model>(); var item = dbPlayerStore.ItemsForSale[model.SelectedItemId]; void AdjustPrice(int amount) { item.Price += amount; if (item.Price <= 0) { item.Price = 1; } else if (item.Price > 999999) { item.Price = 999999; } DB.Set(playerId, dbPlayerStore); PlayerMarket.UpdateCacheEntry(playerId, dbPlayerStore); } page.Header = ColorToken.Green("Item: ") + item.StackSize + "x " + item.Name + "\n" + ColorToken.Green("Price: ") + item.Price + "\n\n" + "Please select an option."; if (model.IsConfirmingRemoveItem) { page.AddResponse(ColorToken.Red("CONFIRM REMOVE ITEM"), () => { var inWorldItem = Object.Deserialize(item.Data); Object.AcquireItem(player, inWorldItem); dbPlayerStore.ItemsForSale.Remove(model.SelectedItemId); DB.Set(playerId, dbPlayerStore); PlayerMarket.UpdateCacheEntry(playerId, dbPlayerStore); ChangePage(EditItemListPageId, false); model.IsConfirmingRemoveItem = false; }); } else { page.AddResponse(ColorToken.Red("Remove Item"), () => { model.IsConfirmingRemoveItem = true; }); } page.AddResponse("Increase by 10,000 gil", () => { AdjustPrice(10000); }); page.AddResponse("Increase by 1,000 gil", () => { AdjustPrice(1000); }); page.AddResponse("Increase by 100 gil", () => { AdjustPrice(100); }); page.AddResponse("Increase by 10 gil", () => { AdjustPrice(10); }); page.AddResponse("Increase by 1 gil", () => { AdjustPrice(1); }); page.AddResponse("Decrease by 10,000 gil", () => { AdjustPrice(-10000); }); page.AddResponse("Decrease by 1,000 gil", () => { AdjustPrice(-1000); }); page.AddResponse("Decrease by 100 gil", () => { AdjustPrice(-100); }); page.AddResponse("Decrease by 10 gil", () => { AdjustPrice(-10); }); page.AddResponse("Decrease by 1 gil", () => { AdjustPrice(-1); }); }
private void PerkDetailsPageInit(DialogPage page) { var player = GetPC(); var model = GetDataModel <Model>(); var perkDetail = Perk.GetPerkDetails(model.SelectedPerk); var playerId = GetObjectUUID(player); var dbPlayer = DB.Get <Player>(playerId); var categoryDetail = Perk.GetPerkCategoryDetails(model.SelectedCategory); var rank = dbPlayer.Perks.ContainsKey(model.SelectedPerk) ? dbPlayer.Perks[model.SelectedPerk] : 0; var maxRank = perkDetail.PerkLevels.Count; var currentLevel = perkDetail.PerkLevels.ContainsKey(rank) ? perkDetail.PerkLevels[rank] : null; var nextLevel = perkDetail.PerkLevels.ContainsKey(rank + 1) ? perkDetail.PerkLevels[rank + 1] : null; var price = nextLevel == null ? "N/A" : $"{nextLevel.Price} SP (Available: {dbPlayer.UnallocatedSP} SP)"; var meetsRequirements = true; string BuildPerkSection(bool isCurrent, PerkLevel perkLevel) { var currentOrNext = isCurrent ? "Current" : "Next"; var bonus = perkLevel == null ? "N/A" : perkLevel.Description; return(ColorToken.Green($"{currentOrNext} Bonus: ") + bonus + "\n"); } string BuildRequirements(List <IPerkRequirement> requirements) { if (requirements == null) { return(string.Empty); } string text = ColorToken.Green("Requirements:\n\n"); if (requirements.Count <= 0) { text += "N/A"; } foreach (var req in requirements) { var requirementMet = string.IsNullOrWhiteSpace(req.CheckRequirements(player)); var reqText = requirementMet ? ColorToken.Green(req.RequirementText) : ColorToken.Red(req.RequirementText); text += reqText + "\n"; if (!requirementMet) { meetsRequirements = false; } } return(text); } void PurchaseUpgrade() { if (model.IsConfirmingPurchase) { model.IsConfirmingPurchase = false; DoPerkUpgrade(); } else { model.IsConfirmingPurchase = true; } } bool CanUpgrade() { if (!meetsRequirements) { return(false); } if (rank + 1 > maxRank) { return(false); } if (nextLevel == null) { return(false); } if (dbPlayer.UnallocatedSP < nextLevel.Price) { return(false); } return(true); } void DoPerkUpgrade() { if (!CanUpgrade() || nextLevel == null) { FloatingTextStringOnCreature("You do not meet the requirements to purchase this perk upgrade.", player, false); return; } int perkRank = dbPlayer.Perks.ContainsKey(model.SelectedPerk) ? dbPlayer.Perks[model.SelectedPerk] : 0; dbPlayer.Perks[model.SelectedPerk] = perkRank + 1; dbPlayer.UnallocatedSP -= nextLevel.Price; DB.Set(playerId, dbPlayer); GrantFeats(); ApplyPurchasePerkTriggers(dbPlayer.Perks[model.SelectedPerk]); Events.SignalEvent("FFO_BUY_PERK", player); } void GrantFeats() { foreach (var feat in nextLevel.GrantedFeats) { if (GetHasFeat(feat, player)) { continue; } Creature.AddFeatByLevel(player, feat, 1); AddFeatToHotBar(feat); } } void AddFeatToHotBar(Feat feat) { var qbs = PlayerQuickBarSlot.UseFeat(feat); // Try to add the new feat to the player's hotbar. if (Core.NWNX.Player.GetQuickBarSlot(player, 0).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 0, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 1).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 1, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 2).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 2, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 3).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 3, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 4).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 4, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 5).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 5, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 6).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 6, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 7).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 7, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 8).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 8, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 9).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 9, qbs); } else if (Core.NWNX.Player.GetQuickBarSlot(player, 10).ObjectType == QuickBarSlotType.Empty) { Core.NWNX.Player.SetQuickBarSlot(player, 10, qbs); } } // Applies any Purchase triggers associated with this perk. void ApplyPurchasePerkTriggers(int perkLevel) { if (perkDetail.PurchasedTriggers.Count > 0) { foreach (var action in perkDetail.PurchasedTriggers) { action(player, model.SelectedPerk, perkLevel); } } } var currentPerkLevelDetails = BuildPerkSection(true, currentLevel); var nextPerkLevelDetails = BuildPerkSection(false, nextLevel); var requirementsSection = BuildRequirements(nextLevel?.Requirements); page.Header = ColorToken.Green("Name: ") + perkDetail.Name + "\n" + ColorToken.Green("Description: ") + perkDetail.Description + "\n" + ColorToken.Green("Category: ") + categoryDetail.Name + "\n" + ColorToken.Green("Rank: ") + rank + " / " + maxRank + "\n" + ColorToken.Green("Price: ") + price + "\n" + currentPerkLevelDetails + "\n" + nextPerkLevelDetails + "\n" + requirementsSection; if (CanUpgrade()) { page.AddResponse(model.IsConfirmingPurchase ? "CONFIRM PURCHASE" : "Purchase Upgrade", PurchaseUpgrade); } }
/// <summary> /// Handles the deck details logic. /// </summary> /// <param name="page">The page to build</param> private void DeckDetailsPageInit(DialogPage page) { var player = GetPC(); var playerId = GetObjectUUID(player); var dbPlayerTripleTriad = DB.Get <PlayerTripleTriad>(playerId); var model = GetDataModel <Model>(); var deck = dbPlayerTripleTriad.Decks.ContainsKey(model.SelectedDeckId) ? dbPlayerTripleTriad.Decks[model.SelectedDeckId] : new CardDeck { Name = $"Deck #{model.SelectedDeckId}" }; page.Header = $"{ColorToken.Green("Deck Name: ")} {deck.Name}\n\n" + "What would you like to do with this deck?"; // Deck Renaming page.AddResponse("Change Name", () => { model.IsConfirming = false; ChangePage(ChangeDeckNamePageId); }); // Card Selection page.AddResponse("Select Cards", () => { model.IsConfirming = false; LoadDeckOntoPC(-1); // Intentionally blank out the card display since we're picking new cards. model.CurrentCardNumber = 1; // Clone the stack. We will revert back to this state when the player finishes building the deck. model.NavigationStackBeforeDeckBuilding = new Stack <DialogNavigation>(NavigationStack.Reverse()); // The topmost navigation points back to the deck list page which leads to users having to click "Back" twice after confirming their deck selections. // Pop this since we only need one. model.NavigationStackBeforeDeckBuilding.Pop(); ChangePage(DeckCardSelectionLevelsPageId); }); // Deck Deletion if (model.IsConfirming) { page.AddResponse($"{ColorToken.Red("CONFIRM DELETE DECK")}", () => { if (dbPlayerTripleTriad.Decks.ContainsKey(model.SelectedDeckId)) { dbPlayerTripleTriad.Decks.Remove(model.SelectedDeckId); DB.Set(playerId, dbPlayerTripleTriad); } LoadDeckOntoPC(model.SelectedDeckId); model.IsConfirming = false; }); } else { page.AddResponse($"{ColorToken.Red("Delete Deck")}", () => { model.IsConfirming = true; }); } }
/// <summary> /// Builds the Skill Details page. /// </summary> /// <param name="page">The page to build.</param> private void SkillDetailsInit(DialogPage page) { var model = GetDataModel <Model>(); var player = GetPC(); var playerId = GetObjectUUID(player); void BuildHeader() { var dbPlayer = DB.Get <Player>(playerId); var skill = Skill.GetSkillDetails(model.SelectedSkill); var pcSkill = dbPlayer.Skills[model.SelectedSkill]; var requiredXP = Skill.GetRequiredXP(pcSkill.Rank); string title; if (pcSkill.Rank <= 3) { title = "Untrained"; } else if (pcSkill.Rank <= 7) { title = "Neophyte"; } else if (pcSkill.Rank <= 13) { title = "Novice"; } else if (pcSkill.Rank <= 20) { title = "Apprentice"; } else if (pcSkill.Rank <= 35) { title = "Journeyman"; } else if (pcSkill.Rank <= 50) { title = "Expert"; } else if (pcSkill.Rank <= 65) { title = "Adept"; } else if (pcSkill.Rank <= 80) { title = "Master"; } else if (pcSkill.Rank <= 100) { title = "Grandmaster"; } else { title = "Unknown"; } title += " (" + pcSkill.Rank + ")"; string decayLock = ColorToken.Green("Decay Lock: ") + ColorToken.White("Unlocked"); if (pcSkill.IsLocked) { decayLock = ColorToken.Green("Decay Lock: ") + ColorToken.Red("Locked"); } // Skills which don't contribute to the cap cannot be locked (there's no reason for it.) // Display a message explaining this to the player instead. string noContributeMessage = string.Empty; if (!skill.ContributesToSkillCap) { decayLock = string.Empty; noContributeMessage = ColorToken.Green("This skill does not contribute to your cumulative skill cap.") + "\n\n"; } string unallocatedXP = ColorToken.Green("Unallocated XP: ") + dbPlayer.UnallocatedXP + "\n"; page.Header = ColorToken.Green("Skill: ") + skill.Name + "\n" + ColorToken.Green("Rank: ") + title + "\n" + ColorToken.Green("Exp: ") + Menu.BuildBar(pcSkill.XP, requiredXP, 100, ColorToken.TokenStart(255, 127, 0)) + "\n" + unallocatedXP + noContributeMessage + decayLock + "\n\n" + ColorToken.Green("Description: ") + skill.Description + "\n"; } void DistributeXP() { ChangePage(DistributeXPId); } void ToggleDecayLock() { var dbPlayer = DB.Get <Player>(playerId); dbPlayer.Skills[model.SelectedSkill].IsLocked = !dbPlayer.Skills[model.SelectedSkill].IsLocked; DB.Set(playerId, dbPlayer); } BuildHeader(); page.AddResponse("Distribute XP", DistributeXP); page.AddResponse("Toggle Decay Lock", ToggleDecayLock); }