示例#1
0
        protected bool HasOrder(Character character, string aiTag, string option = null)
        {
            if (character.CurrentOrder?.AITag == aiTag)
            {
                if (option == null)
                {
                    return(true);
                }
                else
                {
                    HumanAIController humanAI = character.AIController as HumanAIController;
                    return(humanAI.CurrentOrderOption == option);
                }
            }

            return(false);
        }
示例#2
0
        private bool HasOrder(string aiTag, string option = null)
        {
            for (int i = 0; i < crew.Count; i++)
            {
                if (crew[i].CurrentOrder?.AITag == aiTag)
                {
                    if (option == null)
                    {
                        return(true);
                    }
                    else
                    {
                        HumanAIController humanAI = crew[i].AIController as HumanAIController;
                        return(humanAI.CurrentOrderOption == option);
                    }
                }
            }

            return(false);
        }
示例#3
0
 protected void ApplyEffectSpecific(Character targetCharacter)
 {
     foreach (var statusEffect in statusEffects)
     {
         if (statusEffect.HasTargetType(StatusEffect.TargetType.UseTarget))
         {
             // currently used to spawn items on the targeted character
             statusEffect.SetUser(targetCharacter);
             statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targetCharacter);
         }
         else if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
         {
             targets.Clear();
             targets.AddRange(statusEffect.GetNearbyTargets(targetCharacter.WorldPosition, targets));
             if (!nearbyCharactersAppliesToSelf)
             {
                 targets.RemoveAll(c => c == Character);
             }
             if (!nearbyCharactersAppliesToAllies)
             {
                 targets.RemoveAll(c => c is Character otherCharacter && HumanAIController.IsFriendly(otherCharacter, Character));
             }
             statusEffect.SetUser(Character);
             statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targets);
         }
         else if (statusEffect.HasTargetType(StatusEffect.TargetType.Character))
         {
             statusEffect.SetUser(Character);
             statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, Character, targetCharacter);
         }
         else
         {
             statusEffect.SetUser(Character);
             statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, Character, Character);
         }
     }
 }
示例#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 (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 static void ServerRead(IReadMessage msg, Client c)
        {
            c.KickAFKTimer = 0.0f;

            UInt16          ID   = msg.ReadUInt16();
            ChatMessageType type = (ChatMessageType)msg.ReadByte();
            string          txt;

            Character        orderTargetCharacter = null;
            Entity           orderTargetEntity    = null;
            OrderChatMessage orderMsg             = null;
            OrderTarget      orderTargetPosition  = null;

            Order.OrderTargetType orderTargetType = Order.OrderTargetType.Entity;
            int?wallSectionIndex = null;

            if (type == ChatMessageType.Order)
            {
                var orderMessageInfo = OrderChatMessage.ReadOrder(msg);
                if (orderMessageInfo.OrderIndex < 0 || orderMessageInfo.OrderIndex >= Order.PrefabList.Count)
                {
                    DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderMessageInfo.OrderIndex}).");
                    if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
                    {
                        c.LastSentChatMsgID = ID;
                    }
                    return;
                }
                orderTargetCharacter = orderMessageInfo.TargetCharacter;
                orderTargetEntity    = orderMessageInfo.TargetEntity;
                orderTargetPosition  = orderMessageInfo.TargetPosition;
                orderTargetType      = orderMessageInfo.TargetType;
                wallSectionIndex     = orderMessageInfo.WallSectionIndex;
                var    orderPrefab = orderMessageInfo.OrderPrefab ?? Order.PrefabList[orderMessageInfo.OrderIndex];
                string orderOption = orderMessageInfo.OrderOption ??
                                     (orderMessageInfo.OrderOptionIndex == null || orderMessageInfo.OrderOptionIndex < 0 || orderMessageInfo.OrderOptionIndex >= orderPrefab.Options.Length ?
                                      "" : orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value]);
                orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderMessageInfo.Priority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character)
                {
                    WallSectionIndex = wallSectionIndex
                };
                txt = orderMsg.Text;
            }
            else
            {
                txt = msg.ReadString() ?? "";
            }

            if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
            {
                return;
            }

            c.LastSentChatMsgID = ID;

            if (txt.Length > MaxLength)
            {
                txt = txt.Substring(0, MaxLength);
            }

            c.LastSentChatMessages.Add(txt);
            if (c.LastSentChatMessages.Count > 10)
            {
                c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count - 10);
            }

            float similarity = 0.0f;

            for (int i = 0; i < c.LastSentChatMessages.Count; i++)
            {
                float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i);

                if (string.IsNullOrEmpty(txt))
                {
                    similarity += closeFactor;
                }
                else
                {
                    int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]);
                    similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f);
                }
            }
            //order/report messages can be sent a little faster than normal messages without triggering the spam filter
            if (orderMsg != null)
            {
                similarity *= 0.25f;
            }

            bool isOwner = GameMain.Server.OwnerConnection != null && c.Connection == GameMain.Server.OwnerConnection;

            if (similarity + c.ChatSpamSpeed > 5.0f && !isOwner)
            {
                GameMain.Server.KarmaManager.OnSpamFilterTriggered(c);

                c.ChatSpamCount++;
                if (c.ChatSpamCount > 3)
                {
                    //kick for spamming too much
                    GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked"));
                }
                else
                {
                    ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                    c.ChatSpamTimer = 10.0f;
                    GameMain.Server.SendDirectChatMessage(denyMsg, c);
                }
                return;
            }

            c.ChatSpamSpeed += similarity + 0.5f;

            if (c.ChatSpamTimer > 0.0f && !isOwner)
            {
                ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                c.ChatSpamTimer = 10.0f;
                GameMain.Server.SendDirectChatMessage(denyMsg, c);
                return;
            }

            var should = GameMain.Lua.hook.Call("chatMessage", new DynValue[] { DynValue.NewString(txt), UserData.Create(c) });


            if (should != null)
            {
                if (should.CastToBool())
                {
                    return;
                }
                else
                {
                }
            }

            if (type == ChatMessageType.Order)
            {
                if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead)
                {
                    return;
                }
                if (orderMsg.Order.IsReport)
                {
                    HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order);
                }
                Order order = orderTargetType switch
                {
                    Order.OrderTargetType.Entity =>
                    new Order(orderMsg.Order, orderTargetEntity, orderMsg.Order?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender),
                    Order.OrderTargetType.Position =>
                    new Order(orderMsg.Order, orderTargetPosition, orderGiver: orderMsg.Sender),
                    Order.OrderTargetType.WallSection when orderTargetEntity is Structure s && wallSectionIndex.HasValue =>
                    new Order(orderMsg.Order, s, wallSectionIndex, orderGiver: orderMsg.Sender),
                    _ => throw new NotImplementedException()
                };
                if (order != null)
                {
                    if (order.TargetAllCharacters)
                    {
                        if (order.IsIgnoreOrder)
                        {
                            switch (orderTargetType)
                            {
                            case Order.OrderTargetType.Entity:
                                if (!(orderTargetEntity is IIgnorable ignorableEntity))
                                {
                                    break;
                                }
                                ignorableEntity.OrderedToBeIgnored = order.Identifier == "ignorethis";
                                break;

                            case Order.OrderTargetType.Position:
                                throw new NotImplementedException();

                            case Order.OrderTargetType.WallSection:
                                if (!wallSectionIndex.HasValue)
                                {
                                    break;
                                }
                                if (!(orderTargetEntity is Structure s))
                                {
                                    break;
                                }
                                if (!(s.GetSection(wallSectionIndex.Value) is IIgnorable ignorableWall))
                                {
                                    break;
                                }
                                ignorableWall.OrderedToBeIgnored = order.Identifier == "ignorethis";
                                break;
                            }
                        }
                        GameMain.GameSession?.CrewManager?.AddOrder(order, order.IsIgnoreOrder ? (float?)null : order.FadeOutTime);
                    }
                    else if (orderTargetCharacter != null)
                    {
                        orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender);
                    }
                }
                GameMain.Server.SendOrderChatMessage(orderMsg);
            }
            else
            {
                GameMain.Server.SendChatMessage(txt, null, c);
            }
        }
示例#6
0
        public static void ServerRead(IReadMessage msg, Client c)
        {
            c.KickAFKTimer = 0.0f;

            UInt16          ID   = msg.ReadUInt16();
            ChatMessageType type = (ChatMessageType)msg.ReadByte();
            string          txt;

            Character        orderTargetCharacter = null;
            Entity           orderTargetEntity    = null;
            OrderChatMessage orderMsg             = null;
            OrderTarget      orderTargetPosition  = null;

            Order.OrderTargetType orderTargetType = Order.OrderTargetType.Entity;
            int?wallSectionIndex = null;

            if (type == ChatMessageType.Order)
            {
                int orderIndex = msg.ReadByte();
                orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
                orderTargetEntity    = Entity.FindEntityByID(msg.ReadUInt16()) as Entity;

                Order  orderPrefab      = null;
                int?   orderOptionIndex = null;
                string orderOption      = null;

                // The option of a Dismiss order is written differently so we know what order we target
                // now that the game supports multiple current orders simultaneously
                if (orderIndex >= 0 && orderIndex < Order.PrefabList.Count)
                {
                    orderPrefab = Order.PrefabList[orderIndex];
                    if (orderPrefab.Identifier != "dismissed")
                    {
                        orderOptionIndex = msg.ReadByte();
                    }
                    // Does the dismiss order have a specified target?
                    else if (msg.ReadBoolean())
                    {
                        int identifierCount = msg.ReadByte();
                        if (identifierCount > 0)
                        {
                            int   dismissedOrderIndex  = msg.ReadByte();
                            Order dismissedOrderPrefab = null;
                            if (dismissedOrderIndex >= 0 && dismissedOrderIndex < Order.PrefabList.Count)
                            {
                                dismissedOrderPrefab = Order.PrefabList[dismissedOrderIndex];
                                orderOption          = dismissedOrderPrefab.Identifier;
                            }
                            if (identifierCount > 1)
                            {
                                int dismissedOrderOptionIndex = msg.ReadByte();
                                if (dismissedOrderPrefab != null)
                                {
                                    var options = dismissedOrderPrefab.Options;
                                    if (options != null && dismissedOrderOptionIndex >= 0 && dismissedOrderOptionIndex < options.Length)
                                    {
                                        orderOption += $".{options[dismissedOrderOptionIndex]}";
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    orderOptionIndex = msg.ReadByte();
                }

                int orderPriority = msg.ReadByte();
                orderTargetType = (Order.OrderTargetType)msg.ReadByte();
                if (msg.ReadBoolean())
                {
                    var x    = msg.ReadSingle();
                    var y    = msg.ReadSingle();
                    var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull;
                    orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, true);
                }
                else if (orderTargetType == Order.OrderTargetType.WallSection)
                {
                    wallSectionIndex = msg.ReadByte();
                }

                if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
                {
                    DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex}).");
                    if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
                    {
                        c.LastSentChatMsgID = ID;
                    }
                    return;
                }

                orderPrefab ??= Order.PrefabList[orderIndex];
                orderOption ??= orderOptionIndex == null || orderOptionIndex < 0 || orderOptionIndex >= orderPrefab.Options.Length ? "" : orderPrefab.Options[orderOptionIndex.Value];
                orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderPriority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character)
                {
                    WallSectionIndex = wallSectionIndex
                };
                txt = orderMsg.Text;
            }
            else
            {
                txt = msg.ReadString() ?? "";
            }

            if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
            {
                return;
            }

            c.LastSentChatMsgID = ID;

            if (txt.Length > MaxLength)
            {
                txt = txt.Substring(0, MaxLength);
            }

            c.LastSentChatMessages.Add(txt);
            if (c.LastSentChatMessages.Count > 10)
            {
                c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count - 10);
            }

            float similarity = 0.0f;

            for (int i = 0; i < c.LastSentChatMessages.Count; i++)
            {
                float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i);

                if (string.IsNullOrEmpty(txt))
                {
                    similarity += closeFactor;
                }
                else
                {
                    int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]);
                    similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f);
                }
            }
            //order/report messages can be sent a little faster than normal messages without triggering the spam filter
            if (orderMsg != null)
            {
                similarity *= 0.25f;
            }

            bool isOwner = GameMain.Server.OwnerConnection != null && c.Connection == GameMain.Server.OwnerConnection;

            if (similarity + c.ChatSpamSpeed > 5.0f && !isOwner)
            {
                GameMain.Server.KarmaManager.OnSpamFilterTriggered(c);

                c.ChatSpamCount++;
                if (c.ChatSpamCount > 3)
                {
                    //kick for spamming too much
                    GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked"));
                }
                else
                {
                    ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                    c.ChatSpamTimer = 10.0f;
                    GameMain.Server.SendDirectChatMessage(denyMsg, c);
                }
                return;
            }

            c.ChatSpamSpeed += similarity + 0.5f;

            if (c.ChatSpamTimer > 0.0f && !isOwner)
            {
                ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                c.ChatSpamTimer = 10.0f;
                GameMain.Server.SendDirectChatMessage(denyMsg, c);
                return;
            }

            if (type == ChatMessageType.Order)
            {
                if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead)
                {
                    return;
                }
                Order order = null;
                if (orderMsg.Order.IsReport)
                {
                    HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order);
                }
                else if (orderTargetCharacter != null && !orderMsg.Order.TargetAllCharacters)
                {
                    switch (orderTargetType)
                    {
                    case Order.OrderTargetType.Entity:
                        order = new Order(orderMsg.Order.Prefab, orderTargetEntity, orderMsg.Order.Prefab?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender);
                        break;

                    case Order.OrderTargetType.Position:
                        order = new Order(orderMsg.Order.Prefab, orderTargetPosition, orderGiver: orderMsg.Sender);
                        break;
                    }
                    if (order != null)
                    {
                        orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender);
                    }
                }
                else if (orderMsg.Order.IsIgnoreOrder)
                {
                    switch (orderTargetType)
                    {
                    case Order.OrderTargetType.Entity:
                        if (orderTargetEntity is IIgnorable ignorableEntity)
                        {
                            ignorableEntity.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis";
                        }
                        break;

                    case Order.OrderTargetType.WallSection:
                        if (!wallSectionIndex.HasValue)
                        {
                            break;
                        }
                        if (orderTargetEntity is Structure s && s.GetSection(wallSectionIndex.Value) is IIgnorable ignorableWall)
                        {
                            ignorableWall.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis";
                        }
                        break;
                    }
                }
                GameMain.Server.SendOrderChatMessage(orderMsg);
            }
            else
            {
                GameMain.Server.SendChatMessage(txt, null, c);
            }
        }
示例#7
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            if (!(objective.OperateTarget is Gap leak))
            {
                return(true);
            }
            if (leak.Submarine == null)
            {
                return(true);
            }
            Vector2 fromCharacterToLeak = leak.WorldPosition - character.WorldPosition;
            float   dist  = fromCharacterToLeak.Length();
            float   reach = Range + ConvertUnits.ToDisplayUnits(((HumanoidAnimController)character.AnimController).ArmLength);

            //too far away -> consider this done and hope the AI is smart enough to move closer
            if (dist > reach * 2)
            {
                return(true);
            }
            character.AIController.SteeringManager.Reset();
            //steer closer if almost in range
            if (dist > reach)
            {
                if (character.AnimController.InWater)
                {
                    if (character.AIController.SteeringManager is IndoorsSteeringManager indoorSteering)
                    {
                        // Swimming inside the sub
                        if (indoorSteering.CurrentPath != null && !indoorSteering.IsPathDirty && indoorSteering.CurrentPath.Unreachable)
                        {
                            Vector2 dir = Vector2.Normalize(fromCharacterToLeak);
                            character.AIController.SteeringManager.SteeringManual(deltaTime, dir);
                        }
                        else
                        {
                            character.AIController.SteeringManager.SteeringSeek(character.GetRelativeSimPosition(leak));
                        }
                    }
                    else
                    {
                        // Swimming outside the sub
                        character.AIController.SteeringManager.SteeringSeek(character.GetRelativeSimPosition(leak));
                    }
                }
                else
                {
                    // TODO: use the collider size?
                    if (!character.AnimController.InWater && character.AnimController is HumanoidAnimController &&
                        Math.Abs(fromCharacterToLeak.X) < 100.0f && fromCharacterToLeak.Y < 0.0f && fromCharacterToLeak.Y > -150.0f)
                    {
                        ((HumanoidAnimController)character.AnimController).Crouching = true;
                    }
                    Vector2 standPos = new Vector2(Math.Sign(-fromCharacterToLeak.X), Math.Sign(-fromCharacterToLeak.Y)) / 2;
                    if (leak.IsHorizontal)
                    {
                        standPos.X *= 2;
                        standPos.Y  = 0;
                    }
                    else
                    {
                        standPos.X = 0;
                    }
                    character.AIController.SteeringManager.SteeringSeek(standPos);
                }
            }
            else
            {
                if (dist < reach / 2)
                {
                    // Too close -> steer away
                    character.AIController.SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(character.SimPosition - leak.SimPosition));
                }
                else if (dist <= reach)
                {
                    // In range
                    character.CursorPosition  = leak.Position;
                    character.CursorPosition += VectorExtensions.Forward(Item.body.TransformedRotation + (float)Math.Sin(sinTime) / 2, dist / 2);
                    if (character.AnimController.InWater)
                    {
                        var torso = character.AnimController.GetLimb(LimbType.Torso);
                        // Turn facing the target when not moving (handled in the animcontroller if not moving)
                        Vector2 mousePos    = ConvertUnits.ToSimUnits(character.CursorPosition);
                        Vector2 diff        = (mousePos - torso.SimPosition) * character.AnimController.Dir;
                        float   newRotation = MathUtils.VectorToAngle(diff);
                        character.AnimController.Collider.SmoothRotate(newRotation, 5.0f);

                        if (VectorExtensions.Angle(VectorExtensions.Forward(torso.body.TransformedRotation), fromCharacterToLeak) < MathHelper.PiOver4)
                        {
                            // Swim past
                            Vector2 moveDir = leak.IsHorizontal ? Vector2.UnitY : Vector2.UnitX;
                            moveDir *= character.AnimController.Dir;
                            character.AIController.SteeringManager.SteeringManual(deltaTime, moveDir);
                        }
                    }
                }
            }
            if (item.RequireAimToUse)
            {
                character.SetInput(InputType.Aim, false, true);
                sinTime += deltaTime * 5;
            }
            // Press the trigger only when the tool is approximately facing the target.
            Vector2 fromItemToLeak = leak.WorldPosition - item.WorldPosition;
            var     angle          = VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak);

            if (angle < MathHelper.PiOver4)
            {
                // Check that we don't hit any friendlies
                if (Submarine.PickBodies(item.SimPosition, leak.SimPosition, collisionCategory: Physics.CollisionCharacter).None(hit =>
                {
                    if (hit.UserData is Character c)
                    {
                        if (c == character)
                        {
                            return(false);
                        }
                        return(HumanAIController.IsFriendly(character, c));
                    }
                    return(false);
                }))
                {
                    character.SetInput(InputType.Shoot, false, true);
                    Use(deltaTime, character);
                }
            }

            bool leakFixed = (leak.Open <= 0.0f || leak.Removed) &&
                             (leak.ConnectedWall == null || leak.ConnectedWall.Sections.Average(s => s.damage) < 1);

            if (leakFixed && leak.FlowTargetHull != null)
            {
                if (!leak.FlowTargetHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f))
                {
                    character.Speak(TextManager.GetWithVariable("DialogLeaksFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leaksfixed", 10.0f);
                }
                else
                {
                    character.Speak(TextManager.GetWithVariable("DialogLeakFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leakfixed", 10.0f);
                }
            }

            return(leakFixed);
        }
示例#8
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);
        }
示例#9
0
        private void CheckActiveObjectives(TutorialSegment objective, float deltaTime)
        {
            switch (objective.Id)
            {
            case "ReactorCommand":     // Reactor commanded
                if (!IsReactorPoweredUp())
                {
                    if (!HasOrder("operatereactor"))
                    {
                        return;
                    }
                }
                break;

            case "NavConsole":     // traveled 50 meters
                if (Vector2.Distance(subStartingPosition, Submarine.MainSub.WorldPosition) < 4000f)
                {
                    return;
                }
                break;

            case "Flood":     // Hull breaches repaired
                if (IsFlooding())
                {
                    return;
                }
                break;

            case "Medical":
                if (injuredMember != null && !injuredMember.IsDead)
                {
                    if (injuredMember.CharacterHealth.DroppedItem == null)
                    {
                        return;
                    }
                }
                break;

            case "EnemyOnSonar":     // Enemy dispatched
                if (HasEnemyOnSonarForDuration(deltaTime))
                {
                    return;
                }
                break;

            case "Degrading":     // Fixed
                if (mechanic != null && !mechanic.IsDead)
                {
                    HumanAIController humanAI = mechanic.AIController as HumanAIController;
                    if (mechanic.CurrentOrder?.AITag != "repairsystems" || humanAI.CurrentOrderOption != "jobspecific")
                    {
                        return;
                    }
                }

                if (engineer != null && !engineer.IsDead)
                {
                    HumanAIController humanAI = engineer.AIController as HumanAIController;
                    if (engineer.CurrentOrder?.AITag != "repairsystems" || humanAI.CurrentOrderOption != "jobspecific")
                    {
                        return;
                    }
                }

                break;

            case "Approach1":     // Wait until docked
                if (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Count == 0)
                {
                    return;
                }
                break;
            }

            RemoveCompletedObjective(objective);
        }
示例#10
0
        public static void ServerRead(IReadMessage msg, Client c)
        {
            c.KickAFKTimer = 0.0f;

            UInt16          ID   = msg.ReadUInt16();
            ChatMessageType type = (ChatMessageType)msg.ReadByte();
            string          txt;

            Character        orderTargetCharacter = null;
            Entity           orderTargetEntity    = null;
            OrderChatMessage orderMsg             = null;
            OrderTarget      orderTargetPosition  = null;

            if (type == ChatMessageType.Order)
            {
                int orderIndex = msg.ReadByte();
                orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
                orderTargetEntity    = Entity.FindEntityByID(msg.ReadUInt16()) as Entity;
                int orderOptionIndex = msg.ReadByte();
                if (msg.ReadBoolean())
                {
                    var x    = msg.ReadSingle();
                    var y    = msg.ReadSingle();
                    var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull;
                    orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, true);
                }

                if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
                {
                    DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex}, {orderOptionIndex}).");
                    if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
                    {
                        c.LastSentChatMsgID = ID;
                    }
                    return;
                }

                Order  order       = Order.PrefabList[orderIndex];
                string orderOption = orderOptionIndex < 0 || orderOptionIndex >= order.Options.Length ? "" : order.Options[orderOptionIndex];
                orderMsg = new OrderChatMessage(order, orderOption, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character);
                txt      = orderMsg.Text;
            }
            else
            {
                txt = msg.ReadString() ?? "";
            }

            if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
            {
                return;
            }

            c.LastSentChatMsgID = ID;

            if (txt.Length > MaxLength)
            {
                txt = txt.Substring(0, MaxLength);
            }

            c.LastSentChatMessages.Add(txt);
            if (c.LastSentChatMessages.Count > 10)
            {
                c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count - 10);
            }

            float similarity = 0.0f;

            for (int i = 0; i < c.LastSentChatMessages.Count; i++)
            {
                float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i);

                if (string.IsNullOrEmpty(txt))
                {
                    similarity += closeFactor;
                }
                else
                {
                    int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]);
                    similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f);
                }
            }
            //order/report messages can be sent a little faster than normal messages without triggering the spam filter
            if (orderMsg != null)
            {
                similarity *= 0.25f;
            }

            bool isOwner = GameMain.Server.OwnerConnection != null && c.Connection == GameMain.Server.OwnerConnection;

            if (similarity + c.ChatSpamSpeed > 5.0f && !isOwner)
            {
                GameMain.Server.KarmaManager.OnSpamFilterTriggered(c);

                c.ChatSpamCount++;
                if (c.ChatSpamCount > 3)
                {
                    //kick for spamming too much
                    GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked"));
                }
                else
                {
                    ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                    c.ChatSpamTimer = 10.0f;
                    GameMain.Server.SendDirectChatMessage(denyMsg, c);
                }
                return;
            }

            c.ChatSpamSpeed += similarity + 0.5f;

            if (c.ChatSpamTimer > 0.0f && !isOwner)
            {
                ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                c.ChatSpamTimer = 10.0f;
                GameMain.Server.SendDirectChatMessage(denyMsg, c);
                return;
            }

            if (type == ChatMessageType.Order)
            {
                if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead)
                {
                    return;
                }
                if (orderMsg.Order.TargetAllCharacters)
                {
                    HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order);
                }
                else if (orderTargetCharacter != null)
                {
                    var order = orderTargetPosition == null ?
                                new Order(orderMsg.Order.Prefab, orderTargetEntity, orderMsg.Order.Prefab?.GetTargetItemComponent(orderTargetEntity as Item), orderMsg.Sender) :
                                new Order(orderMsg.Order.Prefab, orderTargetPosition, orderMsg.Sender);
                    orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.Sender);
                }
                GameMain.Server.SendOrderChatMessage(orderMsg);
            }
            else
            {
                GameMain.Server.SendChatMessage(txt, null, c);
            }
        }