예제 #1
0
        public static void CloseDevice()
        {
            var player = GetLastClosedBy();

            if (!GetIsPC(player) || GetIsDM(player))
            {
                return;
            }

            var device = OBJECT_SELF;

            for (var item = GetFirstItemInInventory(device); GetIsObjectValid(item); item = GetNextItemInInventory(device))
            {
                var resref = GetResRef(item);

                if (CommandResrefs.Contains(resref))
                {
                    DestroyObject(item);
                }
                else
                {
                    Item.ReturnItem(player, item);
                }
            }

            // If player is quitting crafting, clear out their state.
            var state = Craft.GetPlayerCraftingState(player);

            if (!state.IsOpeningMenu)
            {
                Craft.ClearPlayerCraftingState(player);
            }
        }
예제 #2
0
        public override PlayerDialog SetUp(uint player)
        {
            var model = new Model();

            // This menu can be entered one of two ways:
            //    1.) From the player's rest menu.
            //    2.) From using a crafting fabricator.
            // If the second event happens, we need to skip over the first page.
            var state = Craft.GetPlayerCraftingState(player);

            model.SelectedSkill = state.DeviceSkillType;

            if (model.SelectedSkill != SkillType.Invalid)
            {
                model.IsFabricator = true;
            }

            var builder = new DialogBuilder()
                          .WithDataModel(model)
                          .AddBackAction(Back)
                          .AddEndAction(End);

            if (!model.IsFabricator)
            {
                builder.AddPage(MainPageId, MainPageInit);
            }

            builder.AddPage(CategoryPageId, CategoryPageInit)
            .AddPage(RecipeListPageId, RecipeListPageInit)
            .AddPage(RecipePageId, RecipePageInit);

            return(builder.Build());
        }
예제 #3
0
        /// <summary>
        /// Opens the recipe menu so that a player can select a different recipe to create.
        /// </summary>
        /// <param name="player">The player object</param>
        private static void SelectRecipe(uint player)
        {
            var device = OBJECT_SELF;
            var state  = Craft.GetPlayerCraftingState(player);

            state.IsOpeningMenu = true;

            Dialog.StartConversation(player, device, nameof(RecipeDialog));
        }
예제 #4
0
        public static void OpenDevice()
        {
            var player = GetLastOpenedBy();

            if (!GetIsPC(player) || GetIsDM(player))
            {
                return;
            }

            var state  = Craft.GetPlayerCraftingState(player);
            var device = OBJECT_SELF;

            state.IsOpeningMenu = false;

            // A recipe isn't selected. Open the menu to pick.
            if (state.SelectedRecipe == RecipeType.Invalid)
            {
                var skillType = (SkillType)GetLocalInt(OBJECT_SELF, "CRAFTING_SKILL_TYPE_ID");
                state.DeviceSkillType = skillType;
                state.IsOpeningMenu   = true;

                Dialog.StartConversation(player, OBJECT_SELF, nameof(RecipeDialog));
            }
            // Recipe has been picked. Spawn the command items into this device's inventory.
            else
            {
                var recipe = Craft.GetRecipe(state.SelectedRecipe);

                uint command;

                // Auto-Craft command: Only available if perk has been purchased.
                // todo: Need to write the mini-game. For now, only auto-craft will be available.
                //if (Perk.GetEffectivePerkLevel(player, _autoCraftPerk[state.DeviceSkillType]) > 0)
                {
                    command = CreateItemOnObject(AutoCraftItemResref, device);
                    SetName(command, $"Auto Craft: {recipe.Quantity}x {recipe.Name}");
                }

                // Craft command
                // todo: Need to write the mini-game. For now, only auto-craft will be available.
                //command = CreateItemOnObject(CraftItemResref, device);
                //SetName(command, $"Craft: {recipe.Quantity}x {recipe.Name}");

                // Load Components command
                command = CreateItemOnObject(LoadComponentsResref, device);
                SetName(command, "Load Components");

                // Select Recipe command
                command = CreateItemOnObject(SelectRecipeResref, device);
                SetName(command, "Select Recipe");
            }
        }
예제 #5
0
        /// <summary>
        /// Searches a player's inventory for components matching this recipe's requirements.
        /// </summary>
        /// <param name="player">The player to search.</param>
        private static void LoadComponents(uint player)
        {
            var device = OBJECT_SELF;
            var state  = Craft.GetPlayerCraftingState(player);
            var recipe = Craft.GetRecipe(state.SelectedRecipe);

            for (var item = GetFirstItemInInventory(player); GetIsObjectValid(item); item = GetNextItemInInventory(player))
            {
                var resref = GetResRef(item);

                if (recipe.Components.ContainsKey(resref))
                {
                    Item.ReturnItem(device, item);
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Retrieves all of the items found on a crafting device which match a recipe's component list.
        /// </summary>
        /// <param name="player">The player object</param>
        /// <param name="device">The crafting device</param>
        /// <returns>A list of item object Ids </returns>
        private static List <uint> GetComponents(uint player, uint device)
        {
            var playerComponents = new List <uint>();
            var model            = Craft.GetPlayerCraftingState(player);
            var recipe           = Craft.GetRecipe(model.SelectedRecipe);

            for (var item = GetFirstItemInInventory(device); GetIsObjectValid(item); item = GetNextItemInInventory(device))
            {
                var resref = GetResRef(item);
                if (recipe.Components.ContainsKey(resref))
                {
                    playerComponents.Add(item);
                }
            }

            return(playerComponents);
        }
예제 #7
0
        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);
            }
        }
예제 #8
0
        /// <summary>
        /// Determines if the player has all of the necessary components for this recipe.
        /// </summary>
        /// <param name="player">The player to check</param>
        /// <param name="device">The crafting device</param>
        /// <returns>true if player has all components, false otherwise</returns>
        private static bool HasAllComponents(uint player, uint device)
        {
            var state  = Craft.GetPlayerCraftingState(player);
            var recipe = Craft.GetRecipe(state.SelectedRecipe);
            var remainingComponents = recipe.Components.ToDictionary(x => x.Key, y => y.Value);
            var components          = GetComponents(player, device);

            for (var index = components.Count - 1; index >= 0; index--)
            {
                var component = components[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])
                {
                    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;
                }

                if (remainingComponents[resref] <= 0)
                {
                    remainingComponents.Remove(resref);
                }
            }

            return(remainingComponents.Count <= 0);
        }
예제 #9
0
        /// <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);
        }
예제 #10
0
        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);
                });
            }
        }