Exemplo n.º 1
0
        protected AIObjectiveContainItem AIContainItems <T>(ItemContainer container, Character character, AIObjective objective, int itemCount, bool equip, bool removeEmpty) where T : ItemComponent
        {
            var containObjective = new AIObjectiveContainItem(character, container.GetContainableItemIdentifiers.ToArray(), container, objective.objectiveManager)
            {
                targetItemCount = itemCount,
                Equip           = equip,
                RemoveEmpty     = removeEmpty,
                GetItemPriority = i =>
                {
                    if (i.ParentInventory?.Owner is Item)
                    {
                        //don't take items from other items of the same type
                        if (((Item)i.ParentInventory.Owner).GetComponent <T>() != null)
                        {
                            return(0.0f);
                        }
                    }
                    return(1.0f);
                }
            };

            // TODO: are we sure that we want to abandon the objective here?
            containObjective.Abandoned += () => objective.Abandon = true;
            objective.AddSubObjective(containObjective);
            return(containObjective);
        }
Exemplo n.º 2
0
        protected AIObjectiveContainItem AIContainItems <T>(ItemContainer container, Character character, AIObjective objective, int itemCount, bool equip, bool removeEmpty, bool spawnItemIfNotFound = false) where T : ItemComponent
        {
            AIObjectiveContainItem containObjective = null;

            if (character.AIController is HumanAIController aiController)
            {
                containObjective = new AIObjectiveContainItem(character, container.GetContainableItemIdentifiers.ToArray(), container, objective.objectiveManager, spawnItemIfNotFound: spawnItemIfNotFound)
                {
                    targetItemCount = itemCount,
                    Equip           = equip,
                    RemoveEmpty     = removeEmpty,
                    GetItemPriority = i =>
                    {
                        if (i.ParentInventory?.Owner is Item)
                        {
                            //don't take items from other items of the same type
                            if (((Item)i.ParentInventory.Owner).GetComponent <T>() != null)
                            {
                                return(0.0f);
                            }
                        }
                        return(1.0f);
                    }
                };
                containObjective.Abandoned += () =>
                {
                    aiController.IgnoredItems.Add(container.Item);
                };
                objective.AddSubObjective(containObjective);
            }
            return(containObjective);
        }
Exemplo n.º 3
0
        protected AIObjectiveContainItem AIContainItems <T>(ItemContainer container, Character character, AIObjective currentObjective, int itemCount, bool equip, bool removeEmpty, bool spawnItemIfNotFound = false, bool dropItemOnDeselected = false) where T : ItemComponent
        {
            AIObjectiveContainItem containObjective = null;

            if (character.AIController is HumanAIController aiController)
            {
                containObjective = new AIObjectiveContainItem(character, container.GetContainableItemIdentifiers.ToArray(), container, currentObjective.objectiveManager, spawnItemIfNotFound: spawnItemIfNotFound)
                {
                    targetItemCount = itemCount,
                    Equip           = equip,
                    RemoveEmpty     = removeEmpty,
                    GetItemPriority = i =>
                    {
                        if (i.ParentInventory?.Owner is Item)
                        {
                            //don't take items from other items of the same type
                            if (((Item)i.ParentInventory.Owner).GetComponent <T>() != null)
                            {
                                return(0.0f);
                            }
                        }
                        return(1.0f);
                    }
                };
                containObjective.Abandoned += () => aiController.IgnoredItems.Add(container.Item);
                if (dropItemOnDeselected)
                {
                    currentObjective.Deselected += () =>
                    {
                        if (containObjective == null)
                        {
                            return;
                        }
                        if (containObjective.IsCompleted)
                        {
                            return;
                        }
                        Item item = containObjective.ItemToContain;
                        if (item != null && character.CanInteractWith(item, checkLinked: false))
                        {
                            item.Drop(character);
                        }
                    };
                }
                currentObjective.AddSubObjective(containObjective);
            }
            return(containObjective);
        }
Exemplo n.º 4
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            var projectiles = GetLoadedProjectiles();

            if (projectiles.Count == 0 || (projectiles.Count == 1 && objective.Option.ToLowerInvariant() != "fire at will"))
            {
                ItemContainer container = null;
                foreach (MapEntity e in item.linkedTo)
                {
                    var containerItem = e as Item;
                    if (containerItem == null)
                    {
                        continue;
                    }

                    container = containerItem.GetComponent <ItemContainer>();
                    if (container != null)
                    {
                        break;
                    }
                }

                if (container == null || container.ContainableItems.Count == 0)
                {
                    return(true);
                }

                var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Names[0], container);
                containShellObjective.IgnoreAlreadyContainedItems = true;
                objective.AddSubObjective(containShellObjective);
                return(false);
            }
            else if (GetAvailablePower() < powerConsumption)
            {
                var batteries = item.GetConnectedComponents <PowerContainer>();

                float          lowestCharge  = 0.0f;
                PowerContainer batteryToLoad = null;
                foreach (PowerContainer battery in batteries)
                {
                    if (batteryToLoad == null || battery.Charge < lowestCharge)
                    {
                        batteryToLoad = battery;
                        lowestCharge  = battery.Charge;
                    }
                }

                if (batteryToLoad == null)
                {
                    return(true);
                }

                if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed * 0.4f)
                {
                    objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, "", false));
                    return(false);
                }
            }

            //enough shells and power
            Character closestEnemy = null;
            float     closestDist  = 3000.0f;

            foreach (Character enemy in Character.CharacterList)
            {
                //ignore humans and characters that are inside the sub
                if (enemy.IsDead || enemy.SpeciesName == "human" || enemy.AnimController.CurrentHull != null)
                {
                    continue;
                }

                float dist = Vector2.Distance(enemy.WorldPosition, item.WorldPosition);
                if (dist < closestDist)
                {
                    closestEnemy = enemy;
                    closestDist  = dist;
                }
            }

            if (closestEnemy == null)
            {
                return(false);
            }

            character.CursorPosition = closestEnemy.WorldPosition;
            if (item.Submarine != null)
            {
                character.CursorPosition -= item.Submarine.Position;
            }
            character.SetInput(InputType.Aim, false, true);

            float enemyAngle  = MathUtils.VectorToAngle(closestEnemy.WorldPosition - item.WorldPosition);
            float turretAngle = -rotation;

            if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.01f)
            {
                return(false);
            }

            var pickedBody = Submarine.PickBody(ConvertUnits.ToSimUnits(item.WorldPosition), closestEnemy.SimPosition, null);

            if (pickedBody != null && !(pickedBody.UserData is Limb))
            {
                return(false);
            }

            if (objective.Option.ToLowerInvariant() == "fire at will")
            {
                Use(deltaTime, character);
            }

            return(false);
        }
Exemplo n.º 5
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            if (character.AIController.SelectedAiTarget?.Entity is Character previousTarget &&
                previousTarget.IsDead)
            {
                character?.Speak(TextManager.Get("DialogTurretTargetDead"), null, 0.0f, "killedtarget" + previousTarget.ID, 30.0f);
                character.AIController.SelectTarget(null);
            }

            if (GetAvailablePower() < powerConsumption)
            {
                var batteries = item.GetConnectedComponents <PowerContainer>();

                float          lowestCharge  = 0.0f;
                PowerContainer batteryToLoad = null;
                foreach (PowerContainer battery in batteries)
                {
                    if (batteryToLoad == null || battery.Charge < lowestCharge)
                    {
                        batteryToLoad = battery;
                        lowestCharge  = battery.Charge;
                    }
                }

                if (batteryToLoad == null)
                {
                    return(true);
                }

                if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed * 0.4f)
                {
                    objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, objective.objectiveManager, option: "", requireEquip: false));
                    return(false);
                }
            }

            int usableProjectileCount = 0;
            int maxProjectileCount    = 0;

            foreach (MapEntity e in item.linkedTo)
            {
                if (!(e is Item projectileContainer))
                {
                    continue;
                }

                var containedItems = projectileContainer.ContainedItems;
                if (containedItems != null)
                {
                    var container = projectileContainer.GetComponent <ItemContainer>();
                    maxProjectileCount += container.Capacity;

                    int projectiles = containedItems.Count(it => it.Condition > 0.0f);
                    usableProjectileCount += projectiles;
                }
            }

            if (usableProjectileCount == 0 || (usableProjectileCount < maxProjectileCount && objective.Option.ToLowerInvariant() != "fireatwill"))
            {
                ItemContainer container     = null;
                Item          containerItem = null;
                foreach (MapEntity e in item.linkedTo)
                {
                    containerItem = e as Item;
                    if (containerItem == null)
                    {
                        continue;
                    }

                    container = containerItem.GetComponent <ItemContainer>();
                    if (container != null)
                    {
                        break;
                    }
                }

                if (container == null || container.ContainableItems.Count == 0)
                {
                    return(true);
                }

                if (container.Inventory.Items[0] != null && container.Inventory.Items[0].Condition <= 0.0f)
                {
                    var removeShellObjective = new AIObjectiveDecontainItem(character, container.Inventory.Items[0], container, objective.objectiveManager);
                    objective.AddSubObjective(removeShellObjective);
                }

                var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Identifiers[0], container, objective.objectiveManager);
                character?.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "loadturret", 30.0f);
                containShellObjective.targetItemCount             = usableProjectileCount + 1;
                containShellObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
                objective.AddSubObjective(containShellObjective);
                return(false);
            }

            //enough shells and power
            Character closestEnemy = null;
            float     closestDist  = 3000 * 3000;

            foreach (Character enemy in Character.CharacterList)
            {
                // Ignore friendly and those that are inside the sub
                if (enemy.IsDead || enemy.AnimController.CurrentHull != null || !enemy.Enabled)
                {
                    continue;
                }
                if (HumanAIController.IsFriendly(character, enemy))
                {
                    continue;
                }

                float dist = Vector2.DistanceSquared(enemy.WorldPosition, item.WorldPosition);
                if (dist > closestDist)
                {
                    continue;
                }

                float angle       = -MathUtils.VectorToAngle(enemy.WorldPosition - item.WorldPosition);
                float midRotation = (minRotation + maxRotation) / 2.0f;
                while (midRotation - angle < -MathHelper.Pi)
                {
                    angle -= MathHelper.TwoPi;
                }
                while (midRotation - angle > MathHelper.Pi)
                {
                    angle += MathHelper.TwoPi;
                }

                if (angle < minRotation || angle > maxRotation)
                {
                    continue;
                }

                closestEnemy = enemy;
                closestDist  = dist;
            }

            if (closestEnemy == null)
            {
                return(false);
            }

            character.AIController.SelectTarget(closestEnemy.AiTarget);

            character.CursorPosition = closestEnemy.WorldPosition;
            if (item.Submarine != null)
            {
                character.CursorPosition -= item.Submarine.Position;
            }

            float enemyAngle  = MathUtils.VectorToAngle(closestEnemy.WorldPosition - item.WorldPosition);
            float turretAngle = -rotation;

            if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.15f)
            {
                return(false);
            }

            var pickedBody = Submarine.PickBody(ConvertUnits.ToSimUnits(item.WorldPosition), closestEnemy.SimPosition);

            if (pickedBody == null)
            {
                return(false);
            }
            Character target = null;

            if (pickedBody.UserData is Character c)
            {
                target = c;
            }
            else if (pickedBody.UserData is Limb limb)
            {
                target = limb.character;
            }
            if (target == null || HumanAIController.IsFriendly(character, target))
            {
                return(false);
            }

            if (objective.Option.ToLowerInvariant() == "fireatwill")
            {
                character?.Speak(TextManager.GetWithVariable("DialogFireTurret", "[itemname]", item.Name, true), null, 0.0f, "fireturret", 5.0f);
                character.SetInput(InputType.Shoot, true, true);
            }

            return(false);
        }
Exemplo n.º 6
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
            {
                return(false);
            }

            IsActive = true;

            float degreeOfSuccess = DegreeOfSuccess(character);

            //characters with insufficient skill levels don't refuel the reactor
            if (degreeOfSuccess > 0.2f)
            {
                //remove used-up fuel from the reactor
                var containedItems = item.ContainedItems;
                foreach (Item item in containedItems)
                {
                    if (item != null && item.Condition <= 0.0f)
                    {
                        item.Drop(character);
                    }
                }

                if (aiUpdateTimer > 0.0f)
                {
                    aiUpdateTimer -= deltaTime;
                    return(false);
                }

                //load more fuel if the current maximum output is only 50% of the current load
                if (NeedMoreFuel(minimumOutputRatio: 0.5f))
                {
                    var containFuelObjective = new AIObjectiveContainItem(character, new string[] { "fuelrod", "reactorfuel" }, item.GetComponent <ItemContainer>(), objective.objectiveManager)
                    {
                        targetItemCount = item.ContainedItems.Count(i => i != null && i.Prefab.Identifier == "fuelrod" || i.HasTag("reactorfuel")) + 1,
                        GetItemPriority = (Item fuelItem) =>
                        {
                            if (fuelItem.ParentInventory?.Owner is Item)
                            {
                                //don't take fuel from other reactors
                                if (((Item)fuelItem.ParentInventory.Owner).GetComponent <Reactor>() != null)
                                {
                                    return(0.0f);
                                }
                            }
                            return(1.0f);
                        }
                    };
                    objective.AddSubObjective(containFuelObjective);

                    character?.Speak(TextManager.Get("DialogReactorFuel"), null, 0.0f, "reactorfuel", 30.0f);

                    aiUpdateTimer = AIUpdateInterval;
                    return(false);
                }
                else if (TooMuchFuel())
                {
                    foreach (Item item in item.ContainedItems)
                    {
                        if (item != null && item.HasTag("reactorfuel"))
                        {
                            if (!character.Inventory.TryPutItem(item, character, allowedSlots: item.AllowedSlots))
                            {
                                item.Drop(character);
                            }
                            break;
                        }
                    }
                }
            }

            if (lastUser != character && lastUser != null && lastUser.SelectedConstruction == item)
            {
                character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f);
            }

            LastUser = character;

            switch (objective.Option.ToLowerInvariant())
            {
            case "powerup":
                shutDown = false;
                //characters with insufficient skill levels simply set the autotemp on instead of trying to adjust the temperature manually
                if (degreeOfSuccess < 0.5f)
                {
                    if (!autoTemp)
                    {
                        unsentChanges = true;
                    }
                    AutoTemp = true;
                }
                else
                {
                    AutoTemp      = false;
                    unsentChanges = true;
                    UpdateAutoTemp(MathHelper.Lerp(0.5f, 2.0f, degreeOfSuccess), 1.0f);
                }
#if CLIENT
                onOffSwitch.BarScroll            = 0.0f;
                fissionRateScrollBar.BarScroll   = FissionRate / 100.0f;
                turbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f;
#endif
                break;

            case "shutdown":
#if CLIENT
                onOffSwitch.BarScroll = 1.0f;
#endif
                if (AutoTemp || !shutDown || targetFissionRate > 0.0f || targetTurbineOutput > 0.0f)
                {
                    unsentChanges = true;
                }

                AutoTemp            = false;
                shutDown            = true;
                targetFissionRate   = 0.0f;
                targetTurbineOutput = 0.0f;
                break;
            }

            aiUpdateTimer = AIUpdateInterval;

            return(false);
        }
Exemplo n.º 7
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            float degreeOfSuccess = DegreeOfSuccess(character);

            //characters with insufficient skill levels don't refuel the reactor
            if (degreeOfSuccess > 0.2f)
            {
                //remove used-up fuel from the reactor
                var containedItems = item.ContainedItems;
                foreach (Item item in containedItems)
                {
                    if (item != null && item.Condition <= 0.0f)
                    {
                        item.Drop();
                    }
                }

                //the temperature is too low and not increasing even though the fission rate is high and cooling low
                // -> we need more fuel
                if (temperature < load * 0.5f && temperatureChange <= 0.0f && fissionRate > 0.9f && coolingRate < 0.1f)
                {
                    var containFuelObjective = new AIObjectiveContainItem(character, new string[] { "Fuel Rod", "reactorfuel" }, item.GetComponent <ItemContainer>());
                    containFuelObjective.MinContainedAmount = containedItems.Count(i => i != null && i.Prefab.NameMatches("Fuel Rod") || i.HasTag("reactorfuel")) + 1;
                    containFuelObjective.GetItemPriority    = (Item fuelItem) =>
                    {
                        if (fuelItem.ParentInventory?.Owner is Item)
                        {
                            //don't take fuel from other reactors
                            if (((Item)fuelItem.ParentInventory.Owner).GetComponent <Reactor>() != null)
                            {
                                return(0.0f);
                            }
                        }
                        return(1.0f);
                    };
                    objective.AddSubObjective(containFuelObjective);

                    return(false);
                }
            }


            switch (objective.Option.ToLowerInvariant())
            {
            case "power up":
                float tempDiff = load - temperature;

                shutDownTemp = Math.Min(load + 1000.0f, 7500.0f);

                //characters with insufficient skill levels simply set the autotemp on instead of trying to adjust the temperature manually
                if (Math.Abs(tempDiff) < 500.0f || degreeOfSuccess < 0.5f)
                {
                    AutoTemp = true;
                }
                else
                {
                    AutoTemp = false;
                    //higher skill levels make the character adjust the temperature faster
                    FissionRate += deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess;
                    CoolingRate -= deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess;
                }
                break;

            case "shutdown":
                shutDownTemp = 0.0f;
                break;
            }

            return(false);
        }
Exemplo n.º 8
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
            {
                return(false);
            }

            IsActive = true;

            float degreeOfSuccess = DegreeOfSuccess(character);

            //characters with insufficient skill levels don't refuel the reactor
            if (degreeOfSuccess > 0.2f)
            {
                if (objective.SubObjectives.None())
                {
                    var containedItems = item.ContainedItems;
                    foreach (Item fuelRod in containedItems)
                    {
                        if (fuelRod != null && fuelRod.Condition <= 0.0f)
                        {
                            if (!FindSuitableContainer(character,
                                                       i =>
                            {
                                var container = i.GetComponent <ItemContainer>();
                                if (container == null)
                                {
                                    return(0);
                                }
                                if (container.Inventory.IsFull())
                                {
                                    return(0);
                                }
                                if (container.ShouldBeContained(fuelRod, out bool isRestrictionsDefined))
                                {
                                    if (isRestrictionsDefined)
                                    {
                                        return(3);
                                    }
                                    else
                                    {
                                        if (fuelRod.Prefab.IsContainerPreferred(container, out bool isPreferencesDefined))
                                        {
                                            return(isPreferencesDefined ? 2 : 1);
                                        }
                                        else
                                        {
                                            return(isPreferencesDefined ? 0 : 1);
                                        }
                                    }
                                }
                                else
                                {
                                    return(0);
                                }
                            }, out Item targetContainer))
                            {
                                return(false);
                            }
                            var decontainObjective = new AIObjectiveDecontainItem(character, fuelRod, item.GetComponent <ItemContainer>(), objective.objectiveManager, targetContainer?.GetComponent <ItemContainer>());
                            decontainObjective.Abandoned += () =>
                            {
                                itemIndex = 0;
                                if (targetContainer != null)
                                {
                                    ignoredContainers.Add(targetContainer);
                                }
                            };
                            objective.AddSubObjectiveInQueue(decontainObjective);
                        }
                    }
                }

                if (aiUpdateTimer > 0.0f)
                {
                    aiUpdateTimer -= deltaTime;
                    return(false);
                }

                //load more fuel if the current maximum output is only 50% of the current load
                if (NeedMoreFuel(minimumOutputRatio: 0.5f))
                {
                    aiUpdateTimer = AIUpdateInterval;
                    if (objective.SubObjectives.None())
                    {
                        var containFuelObjective = new AIObjectiveContainItem(character, fuelTags, item.GetComponent <ItemContainer>(), objective.objectiveManager)
                        {
                            targetItemCount = item.ContainedItems.Count(i => i != null && fuelTags.Any(t => i.Prefab.Identifier == t || i.HasTag(t))) + 1,
                            GetItemPriority = (Item fuelItem) =>
                            {
                                if (fuelItem.ParentInventory?.Owner is Item)
                                {
                                    //don't take fuel from other reactors
                                    if (((Item)fuelItem.ParentInventory.Owner).GetComponent <Reactor>() != null)
                                    {
                                        return(0.0f);
                                    }
                                }
                                return(1.0f);
                            }
                        };
                        containFuelObjective.Abandoned += () => objective.Abandon = true;
                        objective.AddSubObjective(containFuelObjective);
                        character?.Speak(TextManager.Get("DialogReactorFuel"), null, 0.0f, "reactorfuel", 30.0f);
                    }
                    return(false);
                }
                else if (TooMuchFuel())
                {
                    foreach (Item item in item.ContainedItems)
                    {
                        if (item != null && fuelTags.Any(t => item.Prefab.Identifier == t || item.HasTag(t)))
                        {
                            if (!character.Inventory.TryPutItem(item, character, allowedSlots: item.AllowedSlots))
                            {
                                item.Drop(character);
                            }
                            break;
                        }
                    }
                }
            }

            if (lastUser != character && lastUser != null && lastUser.SelectedConstruction == item)
            {
                character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f);
            }

            LastUser = lastAIUser = character;

            bool  prevAutoTemp      = autoTemp;
            bool  prevShutDown      = shutDown;
            float prevFissionRate   = targetFissionRate;
            float prevTurbineOutput = targetTurbineOutput;

            switch (objective.Option.ToLowerInvariant())
            {
            case "powerup":
                shutDown = false;
                if (objective.Override || !autoTemp)
                {
                    //characters with insufficient skill levels simply set the autotemp on instead of trying to adjust the temperature manually
                    if (degreeOfSuccess < 0.5f)
                    {
                        AutoTemp = true;
                    }
                    else
                    {
                        AutoTemp = false;
                        UpdateAutoTemp(MathHelper.Lerp(0.5f, 2.0f, degreeOfSuccess), 1.0f);
                    }
                }
#if CLIENT
                onOffSwitch.BarScroll            = 0.0f;
                fissionRateScrollBar.BarScroll   = FissionRate / 100.0f;
                turbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f;
#endif
                break;

            case "shutdown":
#if CLIENT
                onOffSwitch.BarScroll = 1.0f;
#endif
                AutoTemp            = false;
                shutDown            = true;
                targetFissionRate   = 0.0f;
                targetTurbineOutput = 0.0f;
                break;
            }

            if (autoTemp != prevAutoTemp ||
                prevShutDown != shutDown ||
                Math.Abs(prevFissionRate - targetFissionRate) > 1.0f ||
                Math.Abs(prevTurbineOutput - targetTurbineOutput) > 1.0f)
            {
                unsentChanges = true;
            }

            aiUpdateTimer = AIUpdateInterval;

            return(false);
        }