Ejemplo n.º 1
0
        private void CalculateClosest()
        {
            //int unitsUpdatedThisFrame = 0;
            _attackers = Units.Concat <IDealDamage>(TowerMgr.Towers).ToList();

            foreach (var attacker in _attackers)
            {
                if (attacker == null || attacker.GetHealth() <= 0)
                {
                    continue;
                }

                if (attacker.TimeTillNextMgrUpdate > 0)
                {
                    attacker.TimeTillNextMgrUpdate -= GameTime.DeltaTime;
                    continue;
                }

                //unitsUpdatedThisFrame++; //DEBUG

                attacker.TimeTillNextMgrUpdate = UNIT_UPDATE_PERIOD_DELAY; //reset

                //Find closest non-spawner enemy
                ITakeDamage closestEnemy = null;
                float       closestEnemyDistanceSquared = float.MaxValue;
                Vector3     ownPosition = attacker.transform.position;
                foreach (var other in Units)
                {
                    //reasons to skip: looking at itself, not a valid unit, or on same team
                    if (other == null || (IDealDamage)other == attacker || other.Team == attacker.Team ||
                        other.Health <= 0)
                    {
                        continue;
                    }

                    float testDistance = Vector3.SqrMagnitude(other.transform.position - ownPosition);
                    if (testDistance < closestEnemyDistanceSquared)
                    {
                        closestEnemyDistanceSquared = testDistance;
                        closestEnemy = other;

                        //push to unit for AI calculations
                        attacker.DistanceSquaredFromNearestEnemyUnit = closestEnemyDistanceSquared;
                    }
                }

                foreach (var other in TowerMgr.Towers)
                {
                    //reasons to skip: looking at itself, not a valid unit, or on same team
                    if (other == null || (IDealDamage)other == attacker || other.Team == attacker.Team ||
                        other.Health <= 0)
                    {
                        continue;
                    }

                    float testDistance = Vector3.SqrMagnitude(other.transform.position - ownPosition);
                    if (testDistance < closestEnemyDistanceSquared)
                    {
                        closestEnemyDistanceSquared = testDistance;
                        closestEnemy = other;

                        //push to unit for AI calculations
                        attacker.DistanceSquaredFromNearestEnemyUnit = closestEnemyDistanceSquared;
                    }
                }

                //get a more precise distance to current closest unit, taking into account its irregular/variable boundary
                if (closestEnemy != null &&
                    closestEnemyDistanceSquared < attacker.ReachSight * attacker.ReachSight * 2 * 2)
                {
                    closestEnemyDistanceSquared = Vector3.SqrMagnitude(
                        closestEnemy.transform.GetComponent <Collider>().ClosestPoint(ownPosition) - ownPosition);
                    //push to unit for AI calculations
                    attacker.DistanceSquaredFromNearestEnemyUnit = closestEnemyDistanceSquared;
                }

                //NOTE: null check when Unit goes to use
                attacker.ClosestNonSpawnerEnemy = closestEnemy;

                //Find closest spawners
                Spawner closestEnemySpawner = null;
                float   closestEnemySpawnerDistanceSquared = float.MaxValue;
                Spawner closestTeamSpawner = null;
                float   closestTeamSpawnerDistanceSquared = float.MaxValue;
                foreach (var s in LevelsMgr.CurrentLevel.Spawners)
                {
                    if (s == null || s.Health <= 0)
                    {
                        continue;                             //if not valid, skip
                    }
                    float testDistance = Vector3.SqrMagnitude(s.transform.position - ownPosition);
                    if (s.Team == attacker.Team)
                    {
                        if (testDistance < closestTeamSpawnerDistanceSquared)
                        {
                            closestTeamSpawnerDistanceSquared = testDistance;
                            closestTeamSpawner = s;
                        }
                    }
                    else
                    {
                        if (testDistance < closestEnemySpawnerDistanceSquared)
                        {
                            closestEnemySpawnerDistanceSquared = testDistance;
                            closestEnemySpawner = s;
                        }
                    }
                }

                //if unit close to an enemy spawner, get a more precise distance to its irregular/variable boundary
                if (closestEnemySpawner != null &&
                    closestEnemySpawnerDistanceSquared < attacker.ReachSight * attacker.ReachSight * 2 * 2)
                {
                    closestEnemySpawnerDistanceSquared = Vector3.SqrMagnitude(
                        closestEnemySpawner.GetComponent <Collider>().ClosestPoint(ownPosition) - ownPosition);
                }

                //push to unit for AI calculations
                //NOTE: null checks when Unit goes to use
                attacker.ClosestEnemySpawner = closestEnemySpawner;
                attacker.ClosestTeamSpawner  = closestTeamSpawner;
                attacker.DistanceSquaredFromNearestEnemySpawner = closestEnemySpawnerDistanceSquared;
                attacker.DistanceSquaredFromNearestVillage      = closestTeamSpawnerDistanceSquared;
            }
            //NumberOfUnitUpdatesThisFrame = unitsUpdatedThisFrame; //DEBUG
        }
Ejemplo n.º 2
0
 void Awake()
 {
     SampleHole            = SampleHoleInspector;
     SampleTown            = SampleTownInspector;
     LevelElementsInstance = GetComponent <LevelElements>();
 }
Ejemplo n.º 3
0
        void Update() //TODO: move this to user controls somewhere at some point, would really make more sense hah
        {
            //DEBUG
            if (Input.GetKeyDown(KeyCode.Plus) || Input.GetKeyDown(KeyCode.Equals)) //win
            {
                CurrentLevel.DebugKillOffSpawners(Teams.Baddies);
            }
            if (Input.GetKeyDown(KeyCode.Minus)) //lose
            {
                CurrentLevel.DebugKillOffSpawners(Teams.Townsfolk);
            }

            if (Input.GetKey("escape"))
            {
                Application.Quit();
            }

            if (Input.GetKeyDown(KeyCode.V))                           //Deselect All Units
            {
                UnitMgr.GatheredUnits.RemoveAll(item => item == null); //https://stackoverflow.com/questions/3069431/listobject-removeall-how-to-create-an-appropriate-predicate
                foreach (var u in UnitMgr.GatheredUnits)
                {
                    //if (u == null) continue;
                    u.SelectionRing?.gameObject.SetActive(false);
                }
                UnitMgr.GatheredUnits.Clear();
            }

            if (Input.GetKeyDown(KeyCode.C)) //Collect All Units
            {
                foreach (var u in UnitMgr.Units)
                {
                    if (u == null || u.Team != Teams.Townsfolk)
                    {
                        continue;
                    }
                    u.SelectionRing?.gameObject.SetActive(true);
                    UnitMgr.GatheredUnits.Add(u);
                }
            }

            if (Input.GetKeyDown(KeyCode.G)) //Gather Units
            {
                foreach (var u in UnitMgr.Units)
                {
                    if (u == null || u.Team != Teams.Townsfolk)
                    {
                        continue;
                    }
                    if (!((u.transform.position - PlayerUser.PlayerObject.transform.position).sqrMagnitude <
                          UnitMgr.UNIT_GATHER_RADIUS_SQUARED))
                    {
                        continue;
                    }
                    u.SelectionRing?.gameObject.SetActive(true);
                    UnitMgr.GatheredUnits.Add(u);
                }
            }

            if (Input.GetKeyDown(KeyCode.T)) //gathered villagers attack enemy Hole closest to you the user
            {
                //Find closest spawner to player
                Spawner closestHoleSpawner = null;
                float   closestBaddySpawnerDistanceSquared = float.MaxValue;
                foreach (var s in LevelsMgr.CurrentLevel.Spawners)
                {
                    if (s == null)
                    {
                        continue;
                    }
                    float testDistance =
                        Vector3.SqrMagnitude(s.transform.position - PlayerUser.PlayerObject.transform.position);
                    if (s.Team == Teams.Baddies &&
                        testDistance < closestBaddySpawnerDistanceSquared)
                    {
                        closestBaddySpawnerDistanceSquared = testDistance;
                        closestHoleSpawner = s;
                    }
                }

                UnitMgr.GatheredUnits.RemoveAll(item => item == null); //https://stackoverflow.com/questions/3069431/listobject-removeall-how-to-create-an-appropriate-predicate
                foreach (var u in UnitMgr.GatheredUnits)
                {
                    //if (u == null) continue;
                    if (u.Team == Teams.Townsfolk)
                    {
                        u.SelectionRing?.gameObject.SetActive(false);
                        u.SetAttack(closestHoleSpawner);
                    }
                }
                UnitMgr.GatheredUnits.Clear();

                if (closestHoleSpawner != null)
                {
                    PlayerUser.VisualUnitsTargetArrow.GetComponent <ObjectColor>()?.SetOriginalColor(Color.red);
                    PlayerUser.VisualUnitsTargetArrow.SetTarget(PlayerUser.PlayerObject.transform.position,
                                                                closestHoleSpawner.transform.position, 3f);
                }
            }

            if (Input.GetKeyDown(KeyCode.P)) //gathered villagers protect the rally point of your position
            {
                //TODO: make this dependent on mode to select the point (user might be top-down)

                UnitMgr.GatheredUnits.RemoveAll(item => item == null); //https://stackoverflow.com/questions/3069431/listobject-removeall-how-to-create-an-appropriate-predicate
                foreach (var u in UnitMgr.GatheredUnits)
                {
                    //if (u == null) continue;
                    if (u.Team == Teams.Townsfolk)
                    {
                        u.SelectionRing?.gameObject.SetActive(false);
                        u.SetRallyPoint(PlayerUser.PlayerObject.transform.position);
                    }
                }
                UnitMgr.GatheredUnits.Clear();
            }

            if (Input.GetKeyDown(KeyCode.M)) //show or hide menu
            {
                _menuActive = !_menuActive && CurrentLevel != Level.LobbyLevel;
                MenuInGameObject?.GetComponent <MenuInGame>().Show(_menuActive);
            }


            if (Input.GetKeyDown(KeyCode.Y)) //grab a tower for placement mode
            {
                if (!_towerPlacementMode)
                {
                    _towerToBePlaced = TowerMgr.PickATower(Teams.Townsfolk, TowerTypes.Round);
                }
                _towerPlacementMode = true;
            }

            if (Input.GetKeyUp(KeyCode.Y)) //place the tower
            {
                if (_towerPlacementMode)
                {
                    if (_towerPlacementOk)
                    {
                        _towerToBePlaced?.SetDownActivate();
                        PlayerUser.ResourceUnits -= TowerMgr.TOWER_RESOURCE_COST;
                    }
                    else
                    {
                        Destroy(_towerToBePlaced.gameObject);
                    }

                    _towerToBePlaced    = null; //release handle
                    _towerPlacementMode = false;
                    PlayerUser.VisualNewTowerDistanceArrow?.ClearTarget();
                    TowerMgr.ExplanationText.text = "";
                }
            }

            if (_towerPlacementMode)
            {
                _towerPlacementOk             = false;
                TowerMgr.ExplanationText.text = "";

                //raycast from cursor, get nearest grid spot on Level
                if (_cam == null)
                {
                    _cam = FindObjectOfType <Camera>();
                }

                Ray ray = _cam.ScreenPointToRay(Input.mousePosition);

                if (Physics.Raycast(ray, out RaycastHit hit))
                {
                    //check distances
                    bool closeEnoughToPlayer = (hit.point - _cam.transform.position).magnitude <
                                               TowerMgr.TOWER_PLACEMENT_DISTANCE;
                    Spawner nearestSpawner = GetClosestMatchingSpawner(hit.point);
                    if (nearestSpawner != null)
                    {
                        float distanceSquaredToNearestMatchingSpawner =
                            (nearestSpawner.transform.position - hit.point).sqrMagnitude;
                        bool closeEnoughToAVillage =
                            distanceSquaredToNearestMatchingSpawner <
                            (TowerMgr.TOWER_PLACEMENT_DISTANCE + _towerToBePlaced.Radius) *
                            (TowerMgr.TOWER_PLACEMENT_DISTANCE + _towerToBePlaced.Radius);
                        bool leavesEnoughGrowthRoomForAVillage =
                            distanceSquaredToNearestMatchingSpawner >
                            (Level.SPAWN_LAND_FIT_RADIUS + _towerToBePlaced.Radius) *
                            (Level.SPAWN_LAND_FIT_RADIUS + _towerToBePlaced.Radius);
                        bool enoughResources      = PlayerUser.ResourceUnits >= TowerMgr.TOWER_RESOURCE_COST;
                        bool accessibleViaNavMesh = Level.GetIfSpotOnNavMesh(hit.point, 0.25f);


                        if (closeEnoughToPlayer && closeEnoughToAVillage && leavesEnoughGrowthRoomForAVillage &&
                            enoughResources && accessibleViaNavMesh)
                        {
                            //sphere-cast to ensure clear for placement
                            if (Level.GetIfSpotFree(hit.point, _towerToBePlaced.Radius, out RaycastHit landHit))
                            {
                                //if clear, move to new temporary grid location
                                _towerToBePlaced.transform.position = landHit.point;
                                _towerPlacementOk = true;
                            }
                            else
                            {
                                TowerMgr.ExplanationText.text = "Spot not clear!\n";
                            }
                        }
                        else
                        {
                            TowerMgr.ExplanationText.text = (closeEnoughToPlayer ? "" : "Too far from you!\n") +
                                                            (closeEnoughToAVillage
                                                                ? ""
                                                                : "Too far from village!\n") +
                                                            (leavesEnoughGrowthRoomForAVillage
                                                                ? ""
                                                                : ("Too close to village!\n")) +
                                                            (enoughResources
                                                                ? ""
                                                                : "Need " + TowerMgr.TOWER_RESOURCE_COST +
                                                             " resources!\n") +
                                                            (accessibleViaNavMesh ? "" : "Units can't reach!\n");
                        }

                        //show distance reach visual (i.e. arrow)
                        PlayerUser.VisualNewTowerDistanceArrow?.SetTarget(hit.point, nearestSpawner.transform.position);
                        PlayerUser.VisualNewTowerDistanceArrow?.GetComponent <ObjectColor>()
                        ?.SetColor(_towerPlacementOk ? Color.white : Color.red);
                        TowerMgr.ExplanationText.transform.position = hit.point + Vector3.up * 2f;
                    }
                }

                //adjust temporary tower visuals
                if (_towerToBePlaced != null)
                {
                    _towerToBePlaced?.GetComponent <ObjectColor>()?.SetColor(_towerPlacementOk ? Color.white : Color.red);
                    _towerToBePlaced.GetComponent <Renderer>().enabled = _towerPlacementOk;
                }
            }
        }
Ejemplo n.º 4
0
 public void SetRallyPoint(Vector3 point)
 {
     _rallyPoint       = point;
     _rallyPointActive = true;
     TargetSpawner     = null;
 }
Ejemplo n.º 5
0
 public void SetAttack(Spawner enemy)
 {
     MentalState = MentalStates.Attacking;
     //SetUpWeapons(true, UnitWeapon.WeaponClasses.Ranged);
     TargetSpawner = enemy;
 }
Ejemplo n.º 6
0
        private void WanderingLogic()
        {
            _opponent       = null;
            _movementActive = true;

            _idleTimer -= GameTime.DeltaTime;
            if (_idleTimer > 0)
            {
                return;                 //skip logic till timer runs out
            }
            if (TEXT_DEBUG_ENABLED)
            {
                TestDebugOutput = "Idle | ";                     //DEBUG
            }
            //stow any weapons
            SetUpWeapon(false);

            if (ClosestTeamSpawner == null || ClosestTeamSpawner.Health <= 0)
            {
                return;                                                               //wander skip conditions
            }
            //if too far from home...
            float cutoffDistanceSquared =
                Mathf.Pow(Mathf.Sqrt(MAX_DIST_SQ_FROM_VILLAGE_DESIRED) + ClosestTeamSpawner.CurrentRadius, 2);

            if (_rallyPointActive)
            {
                if ((_rallyPoint - transform.position).sqrMagnitude <
                    ReachMelee * ReachMelee * 2 * 2) //if "close enough" already...
                {
                    _rallyPointActive = false;       //turn off rallying
                }
                else //still heading there, eyes wide open (since this in the Idle state)
                {
                    SpeedWalkReturnToBase = true;
                    SetDestinationData(_rallyPoint);
                }
            }
            else //...no rallying, normal wandering logic...
            {
                if (DistanceSquaredFromNearestVillage > cutoffDistanceSquared) //if far from home (and Idle)
                {
                    _idleTimer = 2; //check distance again in a little while

                    SpeedWalkReturnToBase = true;
                    SetDestinationData(ClosestTeamSpawner.transform.position);

                    if (TEXT_DEBUG_ENABLED)
                    {
                        TestDebugOutput += ClosestTeamSpawner.gameObject.name + "dist: " +
                                           DistanceSquaredFromNearestVillage +
                                           "/" + cutoffDistanceSquared; //DEBUG
                    }
                }
                else //...wander near home
                {
                    _idleTimer = Random.Range(0, IDLE_PERIOD_MAX); //reset
                    if (Spawner.FindASpot(transform.position, WANDER_RADIUS, Radius,
                                          out var wanderDestination))
                    {
                        SpeedWalkReturnToBase = false;
                        SetDestinationData(wanderDestination);
                        if (TEXT_DEBUG_ENABLED)
                        {
                            TestDebugOutput += "Random";                     //DEBUG
                        }
                    }
                }
            }
        }
Ejemplo n.º 7
0
        protected override void OnAttach()
        {
            base.OnAttach();

            window = ControlDeclarationManager.Instance.CreateControl("Gui\\TechLabUnitCustomizeWindow.gui");
            Controls.Add(window);

            if (spawner == null)
            {
                spawner = Entities.Instance.GetByName("TechlabMechSpawn") as Spawner;
            }
            else
            {
                spawner = Entities.Instance.GetByName("TechlabMechSpawn") as Spawner;
            }

            if (camera == null)
            {
                camera = Entities.Instance.GetByName("TechlabCam") as MapCamera;
            }
            else
            {
                camera = Entities.Instance.GetByName("TechlabCam") as MapCamera;
            }

            //declare controls
            btnMechs        = (Button)window.Controls["Mechs"];
            btnMechs.Click += new Button.ClickDelegate(btnMechs_Click);

            btnGroundUnits        = (Button)window.Controls["Gunit"];
            btnGroundUnits.Click += new Button.ClickDelegate(btnGroundUnits_Click);

            btnAirUnits        = (Button)window.Controls["Aunit"];
            btnAirUnits.Click += new Button.ClickDelegate(btnAirUnits_Click);

            btnJets        = (Button)window.Controls["Junit"];
            btnJets.Click += new Button.ClickDelegate(btnJets_Click);

            btnNext        = (Button)window.Controls["Next"];
            btnNext.Click += new Button.ClickDelegate(btnNext_Click);

            btnPrevious        = (Button)window.Controls["Previous"];
            btnPrevious.Click += new Button.ClickDelegate(btnPrevious_Click);

            btnRA        = (Button)window.Controls["RA"];
            btnRA.Click += new Button.ClickDelegate(btnRA_Click);

            btnRT        = (Button)window.Controls["RT"];
            btnRT.Click += new Button.ClickDelegate(btnRT_Click);

            btnCT        = (Button)window.Controls["CT"];
            btnCT.Click += new Button.ClickDelegate(btnCT_Click);

            btnLT        = (Button)window.Controls["LT"];
            btnLT.Click += new Button.ClickDelegate(btnLT_Click);

            btnLA        = (Button)window.Controls["LA"];
            btnLA.Click += new Button.ClickDelegate(btnLA_Click);
            //iNCIN -- SlotList
            cbxWeaponSlots = (ListBox)window.Controls["SlotList"];
            cbxWeaponSlots.SelectedIndexChange +=
                new ListBox.SelectedIndexChangeDelegate(cbxWeaponSlots_SelectedIndexChange);

            cbxVariantList = (ListBox)window.Controls["VariantList"];
            cbxVariantList.SelectedIndexChange +=
                new ListBox.SelectedIndexChangeDelegate(cbxVariantList_SelectedIndexChange);

            lstWeaponList = (ListBox)window.Controls["WeaponList"];
            lstWeaponList.SelectedIndexChange +=
                new ListBox.SelectedIndexChangeDelegate(lstWeaponList_SelectedIndexChange);

            btnAddWeapon        = (Button)window.Controls["AddWeapon"];
            btnAddWeapon.Click += new Button.ClickDelegate(btnAddWeapon_Click);

            txtWeaponInfo = (EditBox)window.Controls["WeaponInfo"];
            txtCash       = (TextBox)window.Controls["Cash"];

            btnSaveVariant        = (Button)window.Controls["SaveCustomUnit"];
            btnSaveVariant.Click += new Button.ClickDelegate(btnSaveVariant_Click);

            btnExit        = (Button)window.Controls["Quit"];
            btnExit.Click += new Button.ClickDelegate(btnExit_Click);

            txtUnitName = (TextBox)window.Controls["UnitName"];

            MechsPriceList = (PriceListC)Entities.Instance.Create("MechPriceList", Map.Instance);
            AunitPriceList = (PriceListC)Entities.Instance.Create("AunitPriceList", Map.Instance);
            GunitPriceList = (PriceListC)Entities.Instance.Create("GunitPriceList", Map.Instance);
            JunitPriceList = (PriceListC)Entities.Instance.Create("JunitPriceList", Map.Instance);

            GetListOfPlayerUnits();

            cash = GetPlayerCashSQL();

            if (MechDBUnits.Count == 0)
            {
                btnMechs.Enable = false;
            }

            if (ADBUnits.Count == 0)
            {
                btnAirUnits.Enable = false;
            }

            if (GDBUnits.Count == 0)
            {
                btnGroundUnits.Enable = false;
            }

            if (JDBUnits.Count == 0)
            {
                btnJets.Enable = false;
            }

            if (MechDBUnits.Count == 0 || ADBUnits.Count == 0 || GDBUnits.Count == 0 || JDBUnits.Count == 0)
            {
                //player has not bought any units
                Log.Info("No units purchased. TODO: ask user if they want to go to buy window");
            }

            InitCameraViewFromTarget();
            //positionY = maxout;

            spawner.UnitSpawned += new Spawner.OnUnitSpawned(spawner_UnitSpawned);
        }
Ejemplo n.º 8
0
        protected override void OnAttach()
        {
            window = ControlDeclarationManager.Instance.CreateControl("Gui\\TechLabUnitBuyWindow.gui");
            Controls.Add(window);

            if (spawner == null)
            {
                spawner = Entities.Instance.GetByName("TechlabMechSpawn") as Spawner;
            }
            else
            {
                spawner = Entities.Instance.GetByName("TechlabMechSpawn") as Spawner;
            }

            if (camera == null)
            {
                camera = Entities.Instance.GetByName("TechlabCam") as MapCamera;
            }
            else
            {
                camera = Entities.Instance.GetByName("TechlabCam") as MapCamera;
            }

            btnMechs        = (Button)window.Controls["Mechs"];
            btnMechs.Click += new Button.ClickDelegate(btnMechs_Click);

            btnGroundUnits        = (Button)window.Controls["Gunit"];
            btnGroundUnits.Click += new Button.ClickDelegate(btnGroundUnits_Click);

            btnAirUnits        = (Button)window.Controls["Aunit"];
            btnAirUnits.Click += new Button.ClickDelegate(btnAirUnits_Click);

            btnJets        = (Button)window.Controls["Junit"];
            btnJets.Click += new Button.ClickDelegate(btnJets_Click);

            btnExit        = (Button)window.Controls["Quit"];
            btnExit.Click += new Button.ClickDelegate(btnExit_Click);

            btnNext        = (Button)window.Controls["Next"];
            btnNext.Click += new Button.ClickDelegate(btnNext_Click);

            btnPrevious        = (Button)window.Controls["Previous"];
            btnPrevious.Click += new Button.ClickDelegate(btnPrevious_Click);

            btnBuy        = (Button)window.Controls["Buy"];
            btnBuy.Click += new Button.ClickDelegate(btnBuy_Click);

            txtUnitName = (TextBox)window.Controls["UnitName"];
            txtUnitCost = (TextBox)window.Controls["UnitCost"];
            txtCash     = (TextBox)window.Controls["Cash"];

            txtCash.Text = "Cash: " + cash.ToString();

            lstWeapons = (ListBox)window.Controls["Weapons"];

            spawner.UnitSpawned += new Spawner.OnUnitSpawned(spawner_UnitSpawned);

            InitCameraViewFromTarget();
            //positionY = maxout;

            MechsPriceList = (PriceListC)Entities.Instance.Create("MechPriceList", Map.Instance);
            AunitPriceList = (PriceListC)Entities.Instance.Create("AunitPriceList", Map.Instance);
            GunitPriceList = (PriceListC)Entities.Instance.Create("GunitPriceList", Map.Instance);
            JunitPriceList = (PriceListC)Entities.Instance.Create("JunitPriceList", Map.Instance);

            GetListOfPlayerUnits();

            cash = GetPlayerCashSQL();

            base.OnAttach();
        }