void WeaponItemSubSystem::OnShot( core::ShotEvent const& Evt )
{
    Opt<Actor> actor( mScene.GetActor( Evt.mActorGUID ) );
    if ( !actor.IsValid() )
    {
        return;
    }
    Opt<IInventoryComponent> inventoryC = actor->Get<IInventoryComponent>();
    if ( !inventoryC.IsValid() )
    {
        return;
    }
    Opt<Weapon> weapon = inventoryC->GetSelectedWeapon();
    if ( !weapon.IsValid() )
    {
        return;
    }
    weapon->GetScatter().Shot( Evt.mIsAlt );
    if ( Evt.mIsAlt )
    {
        weapon->SetCooldown( weapon->GetShootAltCooldown() );
        weapon->SetBullets( weapon->GetBullets() - weapon->GetShotCostAlt() );
    }
    else
    {
        weapon->SetCooldown( weapon->GetShootCooldown() );
        weapon->SetBullets( weapon->GetBullets() - weapon->GetShotCost() );
    }
}
void WeaponItemSubSystem::SetProjectilePosition(Actor& projectile, Actor& actor)
{
    Opt<IPositionComponent> projPositionC = projectile.Get<IPositionComponent>();
    Opt<IPositionComponent> actorPositionC = actor.Get<IPositionComponent>();
    glm::vec2 rvec(0.0, 0.0);
    Opt<IInventoryComponent> inventoryC = actor.Get<IInventoryComponent>();
    if (inventoryC.IsValid())
    {
        Opt<Weapon> weapon = inventoryC->GetSelectedWeapon();
        if (weapon.IsValid())
        {
            rvec.x += weapon->GetPositionX();
            rvec.y -= weapon->GetPositionY();
        }
    }
    rvec=glm::rotate(rvec, float(actorPositionC->GetOrientation()));
    projPositionC->SetX( projPositionC->GetX() + actorPositionC->GetX() + rvec.x );
    projPositionC->SetY( projPositionC->GetY() + actorPositionC->GetY() + rvec.y );
}
void GuardControllerSubSystem::Update(Actor& actor, double DeltaTime)
{
    Opt<GuardControllerComponent> guardCC=actor.Get<IControllerComponent>();
    if (!guardCC.IsValid()||!guardCC->IsEnabled())
    {
        return;
    }
    if (mProgramState.mMode == core::ProgramState::Client)
    {
        return;
    }
    auto targetHolderC = actor.Get<ITargetHolderComponent>();
    if (!targetHolderC.IsValid())
    {
        return;
    }
    auto healthC = actor.Get<IHealthComponent>();
    if (!healthC.IsValid() || !healthC->IsAlive())
    {
        return;
    }
    UpdateTarget( actor, targetHolderC );
    Opt<Actor> currentTarget( mScene.GetActor( targetHolderC->GetTargetGUID() ) );
    auto moveC( actor.Get<IMoveComponent>() );
    guardCC->SetNextMoveTimer( guardCC->GetNextMoveTimer() - DeltaTime );
    if (currentTarget.IsValid())
    {
        auto positionC( actor.Get<IPositionComponent>() );
        auto targetPositionC( currentTarget->Get<IPositionComponent>() );
        auto const distSqr = GetDistanceSqr( positionC, targetPositionC );
        glm::vec2 const distV( (targetPositionC->GetX() - positionC->GetX()), (targetPositionC->GetY() - positionC->GetY()) );
        double const Rot = atan2( distV.y, distV.x );
        positionC->SetOrientation( Rot );
        auto inventoryC = actor.Get<IInventoryComponent>();
        if (inventoryC.IsValid())
        {
            Opt<Weapon> weapon = inventoryC->GetSelectedWeapon();
            if (weapon.IsValid())
            {
                int32_t const aggroAltDistSqr = guardCC->GetAggroAltDist() * guardCC->GetAggroAltDist();
                if (distSqr < aggroAltDistSqr)
                {
                    weapon->SetShoot( false );
                    weapon->SetShootAlt( true );
                }
                else
                {
                    weapon->SetShoot( true );
                    weapon->SetShootAlt( false );
                }
            }
        }




        if (guardCC->GetNextMoveTimer() <= 0.0)
        {
            const int32_t ran = RandomGenerator::global()() % 3;
            if (ran == 0)
            {
                guardCC->SetMoveDirection( GuardControllerComponent::Left );
            }
            else if (ran == 1)
            {
                guardCC->SetMoveDirection( GuardControllerComponent::Right );
            }
            else
            {
                guardCC->SetMoveDirection( GuardControllerComponent::None );
            }
            guardCC->SetNextMoveTimer(guardCC->GetNextMoveTimerMax() 
                + (RandomGenerator::global()() % 100*0.02*- 1)*guardCC->GetNextMoveTimerVariance() );
        }
        int32_t const tooCloseDistSqr = guardCC->GetCloseDist() * guardCC->GetCloseDist();
        int32_t const walkAwayDistSqr = guardCC->GetWalkAwayDist() * guardCC->GetWalkAwayDist();
        double heading = 0.0;
        static const double pi = boost::math::constants::pi<double>();
        if (distSqr > tooCloseDistSqr)
        {
            heading = Rot;
            if (guardCC->GetMoveDirection() == GuardControllerComponent::Left)
            {
                heading -= pi / 4;
            }
            else if (guardCC->GetMoveDirection() == GuardControllerComponent::Right)
            {
                heading += pi / 4;
            }
            moveC->SetMoving( true );
        }
        else if (distSqr < walkAwayDistSqr)
        {
            heading = Rot-pi;
            if (guardCC->GetMoveDirection() == GuardControllerComponent::Left)
            {
                heading += pi / 4;
            }
            else if (guardCC->GetMoveDirection() == GuardControllerComponent::Right)
            {
                heading -= pi / 4;
            }
            moveC->SetMoving( true );
        }
        else
        {
            heading = Rot;
            if (guardCC->GetMoveDirection() == GuardControllerComponent::Left)
            {
                heading -= pi / 2;
                moveC->SetMoving( true );
            }
            else if (guardCC->GetMoveDirection() == GuardControllerComponent::Right)
            {
                heading += pi / 2;
                moveC->SetMoving( true );
            }
            else
            {
                moveC->SetMoving( false );
            }
        }
        moveC->SetHeading( heading );
    }
    else
    {
        moveC->SetMoving( false );
        Opt<IInventoryComponent> inventoryC = actor.Get<IInventoryComponent>();
        if (inventoryC.IsValid())
        {
            Opt<Weapon> weapon = inventoryC->GetSelectedWeapon();
            if (weapon.IsValid())
            {
                weapon->SetShoot( false );
                weapon->SetShootAlt( false );
            }
        }
    }
}
void WeaponItemSubSystem::Update( Actor& actor, double DeltaTime )
{
    Opt<IInventoryComponent> inventoryC = actor.Get<IInventoryComponent>();
    Opt<Weapon> weapon = inventoryC->GetSelectedWeapon();
    if ( !weapon.IsValid() )
    {
        return;
    }
    double cd = weapon->GetCooldown();
    cd -= DeltaTime;
    if( cd < 0 )
    {
        cd = 0;
    }
    weapon->SetCooldown( cd );
    //scatter updated on client
    Opt<IAccuracyComponent> accuracyC = actor.Get<IAccuracyComponent>();
    weapon->GetScatter().Update( DeltaTime, accuracyC.IsValid() ? accuracyC->GetAccuracy().Get() : 0 );

    if ( weapon->CanReload()
         //Not enough bullet for current shot  Need to see if the player wants to shoot alt:
         && ( weapon->GetShoot() && weapon->GetBullets() < weapon->GetShotCost()
              && weapon->GetCooldown() <= 0
              //Not enough bullet for current alt shot. Need to see if the player wants to shoot normal:
              || weapon->GetShootAlt() && weapon->GetBullets() < weapon->GetShotCostAlt()
              && weapon->GetCooldown() <= 0
              //Not enough bullet at all. This time the reload is a sure thing:
              || weapon->GetBullets() < weapon->GetShotCost()
              && weapon->GetBullets() < weapon->GetShotCostAlt() ) )
    {
        weapon->SetBullets( 0.0 );
        weapon->SetReloadTime( weapon->GetReloadTimeMax() );
        EventServer<ItemPropertiesChangedEvent>::Get().SendEvent( ItemPropertiesChangedEvent( *weapon ) );
    }

    weapon->SetReloadTime( weapon->GetReloadTime() - DeltaTime );

    if ( weapon->GetBullets() <= 0.0 )
    {
        if ( weapon->GetReloadTime() <= 0 && weapon->GetStaticReload() == 0.0 )
        {
            //todo: need to sync reloading with the server (-1 could occur, if a shot comes too fast, then it is reset by the end of the reload missing one bullet)
            weapon->SetBullets( weapon->GetBullets() + weapon->GetBulletsMax() );
            weapon->SetReloadTime( 0.0 );
        }
    }

    if ( weapon->GetReloadTime() <= 0 && weapon->GetStaticReload() > 0.0 )
    {
        weapon->SetBullets( std::min(
                                ( weapon->GetBullets() + weapon->GetStaticReload()/**DeltaTime*/ )
                                , weapon->GetBulletsMax() ) );
        weapon->SetReloadTime( weapon->GetReloadTimeMax() );
    }
    BindIds_t::iterator itemssIt = mSubSystems.get<SubSystemHolder::AllByBindId>().find( weapon->GetId() );
    if ( itemssIt != mSubSystems.get<SubSystemHolder::AllByBindId>().end() )
    {
        itemssIt->mSystem->Update( actor, DeltaTime );
    }

    if (mProgramState.mMode != core::ProgramState::Client)
    {
        if (weapon->GetCooldown() <= 0.0) //not synced to client
        {
            Opt<IPositionComponent> actorPositionC = actor.Get<IPositionComponent>();
            if (actorPositionC.IsValid())
            {
                if (weapon->IsShooting() && weapon->GetBullets() >= weapon->GetShotCost())
                {
                    if (weapon->GetMuzzleId() != -1)
                    {
                        std::auto_ptr<Actor> muzzle(mActorFactory(weapon->GetMuzzleId()));
                        SetProjectilePosition(*muzzle, actor);
                        BOOST_ASSERT(muzzle->Get<IPositionComponent>().IsValid());
                        muzzle->Get<IPositionComponent>()->SetOrientation(actorPositionC->GetOrientation());
                        mScene.AddActor(muzzle.release());
                    }
                    EventServer<core::ShotEvent>::Get().SendEvent(core::ShotEvent(actor.GetGUID(), glm::vec2(actorPositionC->GetX(), actorPositionC->GetY()), false));
                }
                else if (weapon->IsShootingAlt() && weapon->GetBullets() >= weapon->GetShotCostAlt())
                {
                    if (weapon->GetMuzzleAltId() != -1)
                    {
                        std::auto_ptr<Actor> muzzle(mActorFactory(weapon->GetMuzzleAltId()));
                        SetProjectilePosition(*muzzle, actor);
                        BOOST_ASSERT(muzzle->Get<IPositionComponent>().IsValid());
                        muzzle->Get<IPositionComponent>()->SetOrientation(actorPositionC->GetOrientation());
                        mScene.AddActor(muzzle.release());
                    }
                    EventServer<core::ShotEvent>::Get().SendEvent(core::ShotEvent(actor.GetGUID(), glm::vec2(actorPositionC->GetX(), actorPositionC->GetY()), true));
                }
            }
        }
    }
}