Beispiel #1
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 (GetAvailableBatteryPower() < 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.Equals("fireatwill", StringComparison.OrdinalIgnoreCase)))
            {
                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 (objective.SubObjectives.None())
                {
                    if (!AIDecontainEmptyItems(character, objective, equip: true, sourceContainer: container))
                    {
                        return(false);
                    }
                }
                if (objective.SubObjectives.None())
                {
                    var loadItemsObjective = AIContainItems <Turret>(container, character, objective, usableProjectileCount + 1, equip: true, removeEmpty: true);
                    loadItemsObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
                    character.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "loadturret", 30.0f);
                }
                return(false);
            }

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

            foreach (Character enemy in Character.CharacterList)
            {
                // Ignore dead, friendly, and those that are inside the same sub
                if (enemy.IsDead || !enemy.Enabled || enemy.Submarine == character.Submarine)
                {
                    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);
            }


            Vector2 start = ConvertUnits.ToSimUnits(item.WorldPosition);
            Vector2 end   = ConvertUnits.ToSimUnits(closestEnemy.WorldPosition);

            if (closestEnemy.Submarine != null)
            {
                start -= closestEnemy.Submarine.SimPosition;
                end   -= closestEnemy.Submarine.SimPosition;
            }
            var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel;
            var pickedBody          = Submarine.PickBody(start, end, null, collisionCategories, allowInsideFixture: true,
                                                         customPredicate: (Fixture f) => { return(!item.StaticFixtures.Contains(f)); });

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

            if (pickedBody.UserData is Character c)
            {
                targetCharacter = c;
            }
            else if (pickedBody.UserData is Limb limb)
            {
                targetCharacter = limb.character;
            }
            if (targetCharacter != null)
            {
                if (HumanAIController.IsFriendly(character, targetCharacter))
                {
                    // Don't shoot friendly characters
                    return(false);
                }
            }
            else
            {
                if (pickedBody.UserData is ISpatialEntity e)
                {
                    Submarine sub = e.Submarine;
                    if (sub == null)
                    {
                        return(false);
                    }
                    if (sub == Item.Submarine)
                    {
                        return(false);
                    }
                    // Don't shoot non-player submarines, i.e. wrecks or outposts.
                    if (!sub.Info.IsPlayer)
                    {
                        return(false);
                    }
                    // Don't shoot friendly submarines.
                    if (sub.TeamID == Item.Submarine.TeamID)
                    {
                        return(false);
                    }
                }
                else
                {
                    // Hit something else, probably a level wall
                    return(false);
                }
            }
            if (objective.Option.Equals("fireatwill", StringComparison.OrdinalIgnoreCase))
            {
                character?.Speak(TextManager.GetWithVariable("DialogFireTurret", "[itemname]", item.Name, true), null, 0.0f, "fireturret", 5.0f);
                character.SetInput(InputType.Shoot, true, true);
            }
            return(false);
        }
        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);
        }
Beispiel #3
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
            {
                return(false);
            }
            character.AIController.SteeringManager.Reset();
            bool shutDown = objective.Option.Equals("shutdown", StringComparison.OrdinalIgnoreCase);

            IsActive = true;

            if (!shutDown)
            {
                float degreeOfSuccess = DegreeOfSuccess(character);
                float refuelLimit     = 0.3f;
                //characters with insufficient skill levels don't refuel the reactor
                if (degreeOfSuccess > refuelLimit)
                {
                    if (aiUpdateTimer > 0.0f)
                    {
                        aiUpdateTimer -= deltaTime;
                        return(false);
                    }
                    aiUpdateTimer = AIUpdateInterval;
                    // load more fuel if the current maximum output is only 50% of the current load
                    // or if the fuel rod is (almost) deplenished
                    float minCondition = fuelConsumptionRate * MathUtils.Pow2((degreeOfSuccess - refuelLimit) * 2);
                    if (NeedMoreFuel(minimumOutputRatio: 0.5f, minCondition: minCondition))
                    {
                        bool outOfFuel = false;
                        var  container = item.GetComponent <ItemContainer>();
                        if (objective.SubObjectives.None())
                        {
                            var containObjective = AIContainItems <Reactor>(container, character, objective, itemCount: 1, equip: true, removeEmpty: true, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC, dropItemOnDeselected: true);
                            containObjective.Completed += ReportFuelRodCount;
                            containObjective.Abandoned += ReportFuelRodCount;
                            character.Speak(TextManager.Get("DialogReactorFuel"), null, 0.0f, "reactorfuel", 30.0f);

                            void ReportFuelRodCount()
                            {
                                if (!character.IsOnPlayerTeam)
                                {
                                    return;
                                }
                                if (character.Submarine != Submarine.MainSub)
                                {
                                    return;
                                }
                                int remainingFuelRods = Submarine.MainSub.GetItems(false).Count(i => i.HasTag("reactorfuel") && i.Condition > 1);

                                if (remainingFuelRods == 0)
                                {
                                    character.Speak(TextManager.Get("DialogOutOfFuelRods"), null, 0.0f, "outoffuelrods", 30.0f);
                                    outOfFuel = true;
                                }
                                else if (remainingFuelRods < 3)
                                {
                                    character.Speak(TextManager.Get("DialogLowOnFuelRods"), null, 0.0f, "lowonfuelrods", 30.0f);
                                }
                            }
                        }
                        return(outOfFuel);
                    }
                    else
                    {
                        if (Item.ConditionPercentage <= 0 && AIObjectiveRepairItems.IsValidTarget(Item, character))
                        {
                            if (Item.Repairables.Average(r => r.DegreeOfSuccess(character)) > 0.4f)
                            {
                                objective.AddSubObjective(new AIObjectiveRepairItem(character, Item, objective.objectiveManager, isPriority: true));
                                return(false);
                            }
                            else
                            {
                                character.Speak(TextManager.Get("DialogReactorIsBroken"), identifier: "reactorisbroken", minDurationBetweenSimilar: 30.0f);
                            }
                        }
                        if (TooMuchFuel())
                        {
                            DropFuel(minCondition: 0.1f, maxCondition: 100);
                        }
                        else
                        {
                            DropFuel(minCondition: 0, maxCondition: 0);
                        }
                    }
                }
            }

            if (objective.Override)
            {
                if (lastUser != null && lastUser != character && lastUser != LastAIUser)
                {
                    if (lastUser.SelectedConstruction == item && character.IsOnPlayerTeam)
                    {
                        character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f);
                    }
                }
            }
            else if (LastUserWasPlayer && lastUser != null && lastUser.TeamID == character.TeamID)
            {
                return(true);
            }

            LastUser = LastAIUser = character;

            bool  prevAutoTemp      = autoTemp;
            bool  prevPowerOn       = _powerOn;
            float prevFissionRate   = targetFissionRate;
            float prevTurbineOutput = targetTurbineOutput;

            if (shutDown)
            {
                PowerOn             = false;
                AutoTemp            = false;
                targetFissionRate   = 0.0f;
                targetTurbineOutput = 0.0f;
                unsentChanges       = true;
                return(true);
            }
            else
            {
                PowerOn = true;
                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
                FissionRateScrollBar.BarScroll   = FissionRate / 100.0f;
                TurbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f;
#endif
                if (autoTemp != prevAutoTemp ||
                    prevPowerOn != _powerOn ||
                    Math.Abs(prevFissionRate - targetFissionRate) > 1.0f ||
                    Math.Abs(prevTurbineOutput - targetTurbineOutput) > 1.0f)
                {
                    unsentChanges = true;
                }
                aiUpdateTimer = AIUpdateInterval;
                return(false);
            }


            void DropFuel(float minCondition, float maxCondition)
            {
                if (item.OwnInventory?.AllItems != null)
                {
                    var container = item.GetComponent <ItemContainer>();
                    foreach (Item item in item.OwnInventory.AllItemsMod)
                    {
                        if (item.ConditionPercentage <= maxCondition && item.ConditionPercentage >= minCondition)
                        {
                            item.Drop(character);
                            break;
                        }
                    }
                }
            }
        }
Beispiel #4
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);
        }
Beispiel #5
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);
        }
        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);
        }
Beispiel #7
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);
        }
Beispiel #8
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            character.AIController.SteeringManager.Reset();
            if (objective.Override)
            {
                if (user != character && user != null && user.SelectedConstruction == item && character.IsOnPlayerTeam)
                {
                    character.Speak(TextManager.Get("DialogSteeringTaken"), null, 0.0f, "steeringtaken", 10.0f);
                }
            }
            user = character;

            if (Item.ConditionPercentage <= 0 && AIObjectiveRepairItems.IsValidTarget(Item, character))
            {
                if (Item.Repairables.Average(r => r.DegreeOfSuccess(character)) > 0.4f)
                {
                    objective.AddSubObjective(new AIObjectiveRepairItem(character, Item, objective.objectiveManager, isPriority: true));
                    return(false);
                }
                else
                {
                    character.Speak(TextManager.Get("DialogNavTerminalIsBroken"), identifier: "navterminalisbroken", minDurationBetweenSimilar: 30.0f);
                }
            }

            if (!AutoPilot)
            {
                unsentChanges = true;
                AutoPilot     = true;
            }
            IncreaseSkillLevel(user, deltaTime);
            switch (objective.Option.ToLowerInvariant())
            {
            case "maintainposition":
                if (objective.Override)
                {
                    SetMaintainPosition();
                }
                break;

            case "navigateback":
                if (Level.IsLoadedOutpost)
                {
                    break;
                }
                if (DockingSources.Any(d => d.Docked))
                {
                    item.SendSignal("1", "toggle_docking");
                }
                if (objective.Override)
                {
                    if (MaintainPos || LevelEndSelected || !LevelStartSelected || navigateTactically)
                    {
                        unsentChanges = true;
                    }
                    SetDestinationLevelStart();
                }
                break;

            case "navigatetodestination":
                if (Level.IsLoadedOutpost)
                {
                    break;
                }
                if (DockingSources.Any(d => d.Docked))
                {
                    item.SendSignal("1", "toggle_docking");
                }
                if (objective.Override)
                {
                    if (MaintainPos || !LevelEndSelected || LevelStartSelected || navigateTactically)
                    {
                        unsentChanges = true;
                    }
                    SetDestinationLevelEnd();
                }
                break;

            case "navigatetactical":
                if (Level.IsLoadedOutpost)
                {
                    break;
                }
                if (DockingSources.Any(d => d.Docked))
                {
                    item.SendSignal("1", "toggle_docking");
                }
                if (objective.Override)
                {
                    if (MaintainPos || LevelEndSelected || LevelStartSelected || !navigateTactically)
                    {
                        unsentChanges = true;
                    }
                    SetDestinationTactical();
                }
                break;
            }
            sonar?.AIOperate(deltaTime, character, objective);
            if (!MaintainPos && showIceSpireWarning && character.IsOnPlayerTeam)
            {
                character.Speak(TextManager.Get("dialogicespirespottedsonar"), null, 0.0f, "icespirespottedsonar", 60.0f);
            }
            return(false);
        }