private void Awake()
    {
        _characterJoint = GetComponent <CharacterJoint>();

        _initialPosition = GetComponent <InitialPosition>();

        _simpleAddTorque = GetComponent <SimpleAddTorque>();
    }
Exemple #2
0
            protected override Body CreateBody(object data)
            {
                var body = BodyFactory.CreateEdge(WorldContext.World, InitialPosition.ToSimUnits(), EndPosition.ToSimUnits());

                body.CollidesWith  = Category.All;
                body.BodyType      = BodyType.Static;
                body.IgnoreGravity = true;
                return(body);
            }
Exemple #3
0
 public void SaveToXml(XmlTextWriter xml)
 {
     xml.WriteAttributeString("id", Id);
     xml.WriteAttributeString("description", Description);
     xml.WriteAttributeString("index", Index.ToString());
     xml.WriteAttributeString("min", Min.ToString());
     xml.WriteAttributeString("max", Max.ToString());
     xml.WriteAttributeString("initialPosition", InitialPosition.ToString());
 }
Exemple #4
0
        public override string ToString()
        {
            var sb = new StringBuilder();

            sb.Append("Component type: ").Append(ComponentType.ToString()).Append("\n");
            sb.Append("Category: ").Append(Category.ToString()).Append("\n");
            sb.Append("Lexeme: ").Append(Lexeme.ToString()).Append("\n");
            sb.Append("Line number: ").Append(LineNumber.ToString()).Append("\n");
            sb.Append("Initial position: ").Append(InitialPosition.ToString()).Append("\n");
            sb.Append("Final position: ").Append(FinalPosition.ToString()).Append("\n");

            return(sb.ToString());
        }
Exemple #5
0
        public GameSetting Load()
        {
            //Get Grid Settings
            Grid grid = _gridService.GetGrid();

            //Get Mine Positions
            IEnumerable <Position> minePositions = _positionService.GetMinePositions();

            //Get Exit Point
            Position exit = _positionService.GetExit();

            //Get Turtle's initial position
            InitialPosition initialPosition = _positionService.GetInitialPosition();

            //Movements in Grid
            IEnumerable <IEnumerable <Move> > moves = _positionService.GetMovement();

            if (initialPosition.Position.X == exit.X && initialPosition.Position.Y == exit.Y)
            {
                throw new InvalidExitException();
            }

            foreach (var item in minePositions)
            {
                if (item.X == initialPosition.Position.X && item.Y == initialPosition.Position.Y)
                {
                    throw new InvalidMineException();
                }
            }

            return(new GameSetting()
            {
                Grid = grid,
                Mines = minePositions,
                Exit = exit,
                InitialPosition = initialPosition,
                Moves = moves
            });
        }
Exemple #6
0
        internal void SetRotation(Rotation[][] rotations)
        {
            //if (_dimensions.Length < 3)
            //    throw new IndexOutOfRangeException("dimensions.Length: " + _dimensions.Length);
            //if (rotations.Any(i => i.Any(j => j.Axis < 0 || (int)j.Axis >= _dimensions.Length)))
            //    throw new IndexOutOfRangeException("axis: " + rotations.Select(i => i.Select(j => j.IsNegative ? "-" : "+" + j.Axis).Join("")).Join(", "));

            for (int i = 0; i < NewPosition.Length; i++)
            {
                if (newVectorReady)
                {
                    InitialPosition[i] = NewPosition[i];
                }
                else
                {
                    NewPosition[i] = InitialPosition[i];
                }
            }

            if (rotations.Any(a => a.Length == 0))
            {
                return;
            }

            for (int i = 0; i < rotations.Length; i++)
            {
                bool temp = InitialPosition[(int)rotations[i][0].Axis];
                for (int j = 0; j < rotations[i].Length - 1; j++)
                {
                    NewPosition[(int)rotations[i][j].Axis] = rotations[i][j].IsNegative ^ InitialPosition[(int)rotations[i][j + 1].Axis];
                }
                NewPosition[(int)rotations[i][rotations[i].Length - 1].Axis] = rotations[i][rotations[i].Length - 1].IsNegative ^ temp;
            }

            _initialVector = InitialPosition.ToVector3(_dimensions.Length, _stretchToFit);
            _newVector     = NewPosition.ToVector3(_dimensions.Length, _stretchToFit);
            newVectorReady = true;
        }
 public Coordinate GetInitalCoordinte(InitialPosition pos)
 {
     if (pos.Equals(InitialPosition.UpLeft))
     {
         return(new Coordinate(1, 1));
     }
     else if (pos.Equals(InitialPosition.UpRight))
     {
         return(new Coordinate(width - 2, 1));
     }
     else if (pos.Equals(InitialPosition.DownLeft))
     {
         return(new Coordinate(1, height - 2));
     }
     else if (pos.Equals(InitialPosition.DownRight))
     {
         return(new Coordinate(width - 2, height - 2));
     }
     else
     {
         throw new ArgumentException($" Invalid initial position {pos.ToString()}");
     }
 }
 public static MoveDirection GetMoveDirection(InitialPosition pos)
 {
     if (pos.Equals(InitialPosition.UpLeft))
     {
         return(MoveDirection.Down);
     }
     else if (pos.Equals(InitialPosition.UpRight))
     {
         return(MoveDirection.Left);
     }
     else if (pos.Equals(InitialPosition.DownLeft))
     {
         return(MoveDirection.Right);
     }
     else if (pos.Equals(InitialPosition.DownRight))
     {
         return(MoveDirection.Up);
     }
     else
     {
         // log error
         return(MoveDirection.None);
     }
 }
Exemple #9
0
        private void UpdateState()
        {
            //forced death check
            if (CurrentAiState != ActorAiState.Dead)
            {
                if (Health <= 0)
                {
                    EnterState(ActorAiState.Dead);
                }
            }

            //hack to retrieve swizzled target after a load
            GetSwizzledTarget();

            switch (CurrentAiState)
            {
            case ActorAiState.Idle:
                if (Aggressive)
                {
                    //search for targets, select target
                    SelectTarget();
                    if (Target != null)
                    {
                        EnterState(ActorAiState.Chasing);
                    }
                }
                break;

            case ActorAiState.Wandering:
                //TODO aggression
                if (MovementComponent.DistToTarget <= WanderThreshold || TimeInState >= WanderTimeout)
                {
                    Vector2 newpos = VectorUtils.GetRandomVector2(InitialPosition.GetFlatVector(), WanderRadius);
                    MovementComponent.SetDestination(newpos.GetSpaceVector());
                    TimeInState = 0;
                }
                if (Aggressive)
                {
                    //search for targets, select target
                    SelectTarget();
                    if (Target != null)
                    {
                        EnterState(ActorAiState.Chasing);
                        AudioComponent.Ref()?.PlayAlertSound();
                    }
                }
                break;

            case ActorAiState.Chasing:
                if (!RpgWorldUtils.TargetIsAlive(Target))
                {
                    EnterState(BaseAiState);
                    break;
                }

                if ((MetaState.Instance.SessionFlags.Contains("NoTarget") || GameState.Instance.PlayerFlags.Contains(PlayerFlags.NoTarget)) && Target.GetComponent <PlayerController>())
                {
                    EnterState(BaseAiState);
                    break;
                }

                if (AttackComponent != null && AttackComponent.ReadyToAttack && AttackComponent.TargetInRange)
                {
                    EnterState(ActorAiState.Attacking);
                    return;
                }
                else
                {
                    //set target
                    var d = Target.position;
                    MovementComponent.SetDestination(d);
                }
                if (!Relentless)
                {
                    //break off if we are too far away or too badly hurt
                    if (Health <= (MaxHealth * 0.2f))
                    {
                        EnterState(ActorAiState.Fleeing);
                    }
                    else if ((Target.position - transform.position).magnitude > SearchRadius)
                    {
                        EnterState(BaseAiState);
                        Target = null;
                    }
                }
                break;

            case ActorAiState.ScriptedMoveTo:
                if (MovementComponent.AtTarget)     //we made it!
                {
                    EnterState(ActorAiState.Idle);  //don't wander off if you were sent there!
                }
                break;

            case ActorAiState.Attacking:
                //wait...
                if (!AttackComponent.DidAttack && AttackComponent.WarmupIsDone)
                {
                    AttackComponent.DoAttack();     //waaaaay too complicated to cram here
                }
                if (AttackComponent.AttackIsDone)
                {
                    //just return
                    if (!RpgWorldUtils.TargetIsAlive(Target))
                    {
                        EnterState(BaseAiState);
                    }
                    else
                    {
                        EnterState(ActorAiState.Chasing);
                    }
                }
                break;

            case ActorAiState.Hurting:
                if (TimeInState >= PainWaitTime)
                {
                    if (BeenHit && Target != null)
                    {
                        EnterState(ActorAiState.Chasing);
                    }
                    else
                    {
                        EnterState(LastAiState);
                    }
                }
                break;

            case ActorAiState.Fleeing:
                //stop running if far enough away, or target is gone
                if (!RpgWorldUtils.TargetIsAlive(Target) || (Target.position - transform.position).magnitude > SearchRadius)
                {
                    EnterState(BaseAiState);
                    Target = null;
                    break;
                }
                {
                    //set target
                    var d = transform.position + ((Target.position - transform.position).normalized * -(1 + Mathf.Abs(MovementComponent.TargetThreshold)));
                    MovementComponent.SetDestination(d);
                }
                break;
            }
        }
Exemple #10
0
 public Builder SetInitialPosition(InitialPosition value)
 {
     _subscribe.initialPosition = value;
     return(this);
 }
Exemple #11
0
    private void SetupPlayer(int playerIndex, Vector2 boardPosition, Vector2 panelPosition, InitialPosition initialPosition)
    {
        var worldPosition = BoardPositioner.ToWorldPosition(boardPosition * initialPosition.BoardQuarter);
        var corridor      = Spawner.SpawnLCorridor(worldPosition);

        corridor.Rotate(initialPosition.Rotation);

        var playerColor = GameSettings.PlayersSettings[playerIndex].Color;
        var pawn        = Spawner.SpawnPawn(playerColor, worldPosition);

        corridor.ContainedElements.Add(pawn.transform);

        var playerPanelPosition = panelPosition * initialPosition.BoardQuarter;
        var playerName          = GameSettings.PlayersSettings[playerIndex].Name;

        Spawner.SpawnPlayerPanel(playerColor, playerName, panelPosition, initialPosition.BoardQuarter);

        Spawner.SpawnGetActionToken(playerPanelPosition + new Vector2(-6.5f, 3.5f));
        Spawner.SpawnUseActionToken(playerPanelPosition + new Vector2(-1.5f, 3.5f));
        Spawner.SpawnControlActionToken(playerPanelPosition + new Vector2(3.5f, 3.5f));
    }
 public Consumer CreateConsumer(string tenant, string product, string component, string topic, string consumerName, SubscriptionType consumerType, InitialPosition initialPosition)
 {
     return(new Consumer()
     {
         Id = Guid.NewGuid(),
         Tenant = tenant,
         Product = product,
         Component = component,
         Topic = topic,
         ConsumerName = consumerName,
         SubscriptionType = consumerType,
         ConsumerSettings = new ConsumerSettings()
         {
             InitialPosition = initialPosition
         }
     });
 }
 public ConsumerSettings()
 {
     InitialPosition = InitialPosition.Latest;
 }
Exemple #14
0
            protected override Body CreateBody(object data)
            {
                var body = BodyFactory.CreateRectangle(WorldContext.World, 64, 64, 1f, InitialPosition.ToSimUnits(), data);

                body.Mass         = .001f;
                body.BodyType     = BodyType.Dynamic;
                body.CollidesWith = Category.All;
                body.Friction     = 1f;
                //body.IgnoreGravity = true;
                body.FixedRotation = true;
                return(body);
            }
Exemple #15
0
        public void EnterState(ActorAiState newState)
        {
            if (LockAiState)
            {
                return;
            }

            LastAiState = CurrentAiState;

            ExitState(CurrentAiState); //good place or no?

            TimeInState = 0;

            switch (newState)
            {
            case ActorAiState.Idle:
                Target = null;
                AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Idle);
                MovementComponent.AbortMove();
                break;

            case ActorAiState.Dead:
                if (CurrentAiState == ActorAiState.Dead)     //fix for glitchy looking behaviour
                {
                    break;
                }

                MovementComponent.AbortMove();
                MovementComponent.HandleDeath();
                if (DieImmediately)
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Dead);
                }
                else
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Dying);
                }

                AudioComponent.Ref()?.StopLivingSounds();
                AudioComponent.Ref()?.PlayDeathSound();

                if (InteractionComponent != null)
                {
                    InteractionComponent.InteractionDisabledByHit = false;
                }

                if (DestroyOnDeath)
                {
                    this.gameObject.SetActive(false);     //actually destroying the object breaks saving
                }
                if (OnDeathSpecial != null)
                {
                    OnDeathSpecial.Execute(new ActionInvokerData {
                        Activator = this
                    });
                }

                if (Target != null && Target.GetComponent <PlayerController>() && GrantXpOnDeath > 0)    //what the f**k
                {
                    GameState.Instance.PlayerRpgState.GrantXPScaled(GrantXpOnDeath);
                }
                break;

            case ActorAiState.Wandering:
                Target = null;
                AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Walking);
                //set initial destination
                Vector2 newpos = VectorUtils.GetRandomVector2(InitialPosition.GetFlatVector(), WanderRadius);
                MovementComponent.SetDestination(newpos.GetSpaceVector());
                AudioComponent.Ref()?.StartWalkSound();
                break;

            case ActorAiState.Chasing:
                if (RunOnChase)
                {
                    MovementComponent.IsRunning = true;
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Running);
                    AudioComponent.Ref()?.StartRunSound();
                }
                else
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Walking);
                    AudioComponent.Ref()?.StartWalkSound();
                }

                {
                    //set target

                    if (Target == null)
                    {
                        GetSwizzledTarget();     //fix for loading saves
                    }
                    var d = Target.position;     //FIXME what if Target is null?
                    MovementComponent.SetDestination(d);
                }
                break;

            case ActorAiState.ScriptedMoveTo:
                if (RunOnChase)
                {
                    MovementComponent.IsRunning = true;
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Running);
                    AudioComponent.Ref()?.StartRunSound();
                }
                else
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Walking);
                    AudioComponent.Ref()?.StartWalkSound();
                }
                MovementComponent.SetDestination(MovementComponent.MovementTarget);
                break;

            case ActorAiState.Attacking:
                if (AttackComponent == null)
                {
                    Debug.LogError($"{name} tried to attack, but has no attack component!");
                    EnterState(ActorAiState.Idle);
                    return;
                }

                if (Target == null)
                {
                    GetSwizzledTarget();     //fix for loading saves
                }
                //set animation, fire projectile, set timer
                AttackComponent.BeginAttack();
                break;

            case ActorAiState.Covering:
                break;

            case ActorAiState.Hurting:
                AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Hurting);
                AudioComponent.Ref()?.PlayPainSound();
                break;

            case ActorAiState.Fleeing:
                if (RunOnFlee)
                {
                    MovementComponent.IsRunning = true;
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Running);
                    AudioComponent.Ref()?.StartRunSound();
                }
                else
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Walking);
                    AudioComponent.Ref()?.StartWalkSound();
                }

                {
                    //set target
                    var d = transform.position + ((Target.position - transform.position).normalized * -(1 + Mathf.Abs(MovementComponent.TargetThreshold)));
                    MovementComponent.SetDestination(d);
                }
                break;

            default:
                break;
            }

            CurrentAiState = newState;
        }
Exemple #16
0
        public override Task OnConnectedAsync()
        {
            Consumer consumerToRegister;
            string   clientConnectionId = Context.ConnectionId;
            var      headers            = Context.GetHttpContext().Request.Headers;

            // authorization tokens
            // TODO: Implement token validation
            string tenantToken    = headers["x-andyx-tenant-authoriziation"];
            string componentToken = headers["x-andyx-component-authoriziation"];

            string tenant       = headers["x-andyx-tenant"].ToString();
            string product      = headers["x-andyx-product"].ToString();
            string component    = headers["x-andyx-component"].ToString();
            string topic        = headers["x-andyx-topic"].ToString();
            bool   isPersistent = bool.Parse(headers["x-andyx-topic-is-persistent"]);
            string consumerName = headers["x-andyx-consumer"].ToString();

            SubscriptionType subscriptionType = (SubscriptionType)Enum.Parse(typeof(SubscriptionType), headers["x-andyx-consumer-type"].ToString());
            InitialPosition  initialPosition  = (InitialPosition)Enum.Parse(typeof(InitialPosition), headers["x-andyx-consumer-initial-position"].ToString());

            logger.LogInformation($"Consumer '{consumerName}' and subscription type '{subscriptionType}' at {tenant}/{product}/{component}/{topic} requested connection");

            // check if the consumer is already connected
            var connectedTenant = tenantRepository.GetTenant(tenant);

            if (connectedTenant == null)
            {
                logger.LogInformation($"Consumer '{consumerName}' failed to connect, tenant '{tenant}' does not exists");
                return(OnDisconnectedAsync(new Exception($"There is no tenant registered with this name '{tenant}'")));
            }

            // check tenant token validation
            bool isTenantTokenValidated = tenantRepository.ValidateTenantToken(tenant, tenantToken);

            if (isTenantTokenValidated != true)
            {
                logger.LogInformation($"Consumer '{consumerName}' failed to connect, access is forbidden. Not authorized");
                return(OnDisconnectedAsync(new Exception($"Consumer '{consumerName}' failed to connect, access is forbidden")));
            }

            var connectedProduct = tenantRepository.GetProduct(tenant, product);

            if (connectedProduct == null)
            {
                if (connectedTenant.Settings.AllowProductCreation != true)
                {
                    logger.LogInformation($"Consumer '{consumerName}' failed to connect, tenant '{tenant}' does not allow to create new product");
                    return(OnDisconnectedAsync(new Exception($"There is no product registered with this name '{product}'. Tenant '{tenant}' does not allow to create new product")));
                }

                var productDetails = tenantFactory.CreateProduct(product);
                tenantRepository.AddProduct(tenant, product, productDetails);
                storageHubService.CreateProductAsync(tenant, productDetails);
            }
            else
            {
                storageHubService.UpdateProductAsync(tenant, connectedProduct);
            }

            var connectedComponent = tenantRepository.GetComponent(tenant, product, component);

            if (connectedComponent == null)
            {
                var componentDetails = tenantFactory.CreateComponent(component);
                tenantRepository.AddComponent(tenant, product, component, componentDetails);
                storageHubService.CreateComponentAsync(tenant, product, componentDetails);
            }
            else
            {
                // check component token validation
                bool isComponentTokenValidated = tenantRepository.ValidateComponentToken(tenant, product, component, componentToken, consumerName, true);
                if (isComponentTokenValidated != true)
                {
                    logger.LogInformation($"Consumer '{consumerName}' failed to connect, access is forbidden. Not authorized, check component token");
                    return(OnDisconnectedAsync(new Exception($"Consumer '{consumerName}' failed to connect, access is forbidden, check component token")));
                }

                storageHubService.UpdateComponentAsync(tenant, product, connectedComponent);
            }

            var connectedTopic = tenantRepository.GetTopic(tenant, product, component, topic);

            if (connectedTopic == null)
            {
                connectedComponent = tenantRepository.GetComponent(tenant, product, component);
                if (connectedComponent.Settings.AllowTopicCreation != true)
                {
                    logger.LogInformation($"Component '{component}' does not allow to create a new topic {topic} at '{tenant}/{product}/{component}'. To allow creating update property AllowTopicCreation at component.");
                    return(OnDisconnectedAsync(new Exception($"Component '{component}' does not allow to create a new topic {topic} at '{tenant}/{product}/{component}'. To allow creating update property AllowTopicCreation at component.")));
                }

                var topicDetails = tenantFactory.CreateTopic(topic, isPersistent);
                tenantRepository.AddTopic(tenant, product, component, topic, topicDetails);
                storageHubService.CreateTopicAsync(tenant, product, component, topicDetails);
            }
            else
            {
                storageHubService.UpdateTopicAsync(tenant, product, component, connectedTopic);
            }

            string consumerIdOnRepo  = $"{tenant}{product}{component}{topic}|{consumerName}";
            var    consumerConencted = consumerHubRepository.GetConsumerById(consumerIdOnRepo);

            if (consumerConencted != null)
            {
                if (subscriptionType == SubscriptionType.Exclusive)
                {
                    logger.LogWarning($"Consumer '{consumerName}' and subscription type '{subscriptionType}' at {tenant}/{product}/{component}/{topic} is already connected");
                    return(OnDisconnectedAsync(new Exception($"There is a consumer with name '{consumerName}' and with type 'EXCLUSIVE' is connected to this node")));
                }

                if (subscriptionType == SubscriptionType.Failover)
                {
                    if (consumerConencted.Connections.Count >= 2)
                    {
                        logger.LogWarning($"Consumer '{consumerName}' and subscription type '{subscriptionType}' at {tenant}/{product}/{component}/{topic} is already connected with 2 instances");

                        return(OnDisconnectedAsync(new Exception($"There are two consumers with name '{consumerName}' and with type 'Failover' are connected to this node")));
                    }
                }
            }

            consumerToRegister = consumerFactory.CreateConsumer(tenant, product, component, topic, consumerName, subscriptionType, initialPosition);
            consumerHubRepository.AddConsumer(consumerIdOnRepo, consumerToRegister);
            consumerHubRepository.AddConsumerConnection(consumerIdOnRepo, clientConnectionId);

            storageHubService.ConnectConsumerAsync(consumerToRegister);

            Clients.Caller.ConsumerConnected(new Model.Consumers.Events.ConsumerConnectedDetails()
            {
                Id               = consumerToRegister.Id,
                Tenant           = tenant,
                Product          = product,
                Component        = component,
                Topic            = topic,
                ConsumerName     = consumerName,
                SubscriptionType = subscriptionType,
                InitialPosition  = initialPosition
            });

            // if consumer is not persistent, do not store the message, just allow streaming
            if (isPersistent == true)
            {
                // Sent not acknoledged messages to this consumer (for exclusive and for the first shared/failover consumer connected)
                if (subscriptionType == SubscriptionType.Exclusive)
                {
                    storageHubService.RequestUnacknowledgedMessagesConsumer(consumerToRegister);
                }

                if (subscriptionType == SubscriptionType.Shared || subscriptionType == SubscriptionType.Failover)
                {
                    if (consumerConencted == null)
                    {
                        storageHubService.RequestUnacknowledgedMessagesConsumer(consumerToRegister);
                    }
                }
            }
            logger.LogInformation($"Consumer '{consumerName}' and subscription type '{subscriptionType}' at {tenant}/{product}/{component}/{topic} is connected");

            return(base.OnConnectedAsync());
        }
Exemple #17
0
        public void EnterState(ActorAiState newState)
        {
            if (LockAiState)
            {
                return;
            }

            if (newState != CurrentAiState)
            {
                LastAiState = CurrentAiState;
            }

            ExitState(CurrentAiState); //good place or no?

            TimeInState = 0;

            switch (newState)
            {
            case ActorAiState.Idle:
                Target = null;
                AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Idle);
                MovementComponent.AbortMove();
                break;

            case ActorAiState.Dead:
            {
                if (CurrentAiState == ActorAiState.Dead)         //fix for glitchy looking behaviour
                {
                    break;
                }

                MovementComponent.AbortMove();
                MovementComponent.HandleDeath();
                var deathStateArgs = new DeathStateActorAnimationArgs()
                {
                    DamageEffector = LastHit?.DamageEffector ?? 0, DamageType = LastHit?.DamageType ?? 0, ExtremeDeath = WasExtremeDeath, HitLocation = LastHit?.HitLocation ?? 0, HitMaterial = LastHit?.HitMaterial ?? 0
                };
                if (DieImmediately)
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Dead, deathStateArgs);
                }
                else
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Dying, deathStateArgs);
                }

                AudioComponent.Ref()?.StopLivingSounds();
                if (WasExtremeDeath)
                {
                    AudioComponent.Ref()?.PlayExtremeDeathSound();
                }
                else
                {
                    AudioComponent.Ref()?.PlayDeathSound();
                }

                if (InteractionComponent != null)
                {
                    InteractionComponent.InteractionDisabledByHit = false;
                }

                if (DestroyOnDeath)
                {
                    this.gameObject.SetActive(false);         //actually destroying the object breaks saving
                }
                if (OnDeathSpecial != null)
                {
                    OnDeathSpecial.Execute(new ActionInvokerData {
                            Activator = this
                        });
                }

                if (DisableHitboxesOnDeath)
                {
                    var hitboxComponents = GetComponentsInChildren <IHitboxComponent>(true);
                    foreach (var hitboxComponent in hitboxComponents)
                    {
                        if (hitboxComponent is MonoBehaviour mb)         //IHitboxComponent does not actually imply MonoBehaviour
                        {
                            mb.gameObject.SetActive(false);
                        }
                    }
                }

                if (DisableCollidersOnDeath)
                {
                    var colliders = GetComponentsInChildren <Collider>(true);
                    foreach (var collider in colliders)
                    {
                        collider.enabled = false;
                    }
                }

                if (
                    ((LastHit != null && LastHit.Value.Originator != null && LastHit.Value.Originator is PlayerController) ||
                     (Target != null && Target.GetComponent <PlayerController>())
                    ) &&
                    GrantXpOnDeath > 0
                    )
                {
                    GameState.Instance.PlayerRpgState.GrantXPScaled(GrantXpOnDeath);
                }
            }
            break;

            case ActorAiState.Wandering:
                Target = null;
                AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Walking);
                //set initial destination
                Vector2 newpos = VectorUtils.GetRandomVector2(InitialPosition.GetFlatVector(), WanderRadius);
                MovementComponent.SetDestination(newpos.GetSpaceVector());
                AudioComponent.Ref()?.StartWalkSound();
                break;

            case ActorAiState.Chasing:
                if (RunOnChase)
                {
                    MovementComponent.IsRunning = true;
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Running);
                    AudioComponent.Ref()?.StartRunSound();
                }
                else
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Walking);
                    AudioComponent.Ref()?.StartWalkSound();
                }

                {
                    //set target

                    if (Target == null)
                    {
                        GetSwizzledTarget();     //fix for loading saves
                    }
                    SetChaseDestination();
                }
                break;

            case ActorAiState.ScriptedMoveTo:
                if (RunOnChase)
                {
                    MovementComponent.IsRunning = true;
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Running);
                    AudioComponent.Ref()?.StartRunSound();
                }
                else
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Walking);
                    AudioComponent.Ref()?.StartWalkSound();
                }
                MovementComponent.SetDestination(MovementComponent.MovementTarget);
                break;

            case ActorAiState.Attacking:
                if (AttackComponent == null)
                {
                    Debug.LogError($"{name} tried to attack, but has no attack component!");
                    EnterState(ActorAiState.Idle);
                    return;
                }

                if (Target == null)
                {
                    GetSwizzledTarget();     //fix for loading saves
                }
                //set animation, fire projectile, set timer
                AttackComponent.BeginAttack();
                break;

            case ActorAiState.Covering:
                break;

            case ActorAiState.Hurting:
                AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Hurting);
                AudioComponent.Ref()?.PlayPainSound();
                break;

            case ActorAiState.Fleeing:
                if (RunOnFlee)
                {
                    MovementComponent.IsRunning = true;
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Running);
                    AudioComponent.Ref()?.StartRunSound();
                }
                else
                {
                    AnimationComponent.Ref()?.SetAnimation(ActorAnimState.Walking);
                    AudioComponent.Ref()?.StartWalkSound();
                }

                {
                    //set target
                    var d = transform.position + ((Target.position - transform.position).normalized * -(1 + Mathf.Abs(MovementComponent.TargetThreshold)));
                    MovementComponent.SetDestination(d);
                }
                break;

            case ActorAiState.ScriptedAction:
                //nop
                break;

            default:
                break;
            }

            CurrentAiState = newState;
        }