bool CclusterIGC::IsFriendlyCluster(IsideIGC* pside, ClusterQuality cqlty) //Spunky #288
{
	int balanceOfPower = 0;
	//carrier or ASS in sector = not friendly - Spunky #290
	ShipLinkIGC* pshipl = GetShips()->first();
	if (pshipl)
	{
		do
		{
			IshipIGC* pship = pshipl->data();
			if (pship->GetParentShip() == NULL)
				if (pship->GetSide() != pside && pship->SeenBySide(pside) && !IsideIGC::AlliedSides(pside, pship->GetSide()))
				{
					if (pship->GetHullType()->HasCapability(c_habmIsRipcordTarget | c_habmIsLtRipcordTarget))
						return false;
					if (pship->GetBaseHullType()->GetScannerRange() > 800 && cqlty & cqNoEye)
						return false;
					balanceOfPower--;
				}
				else if (pship->GetSide() == pside || IsideIGC::AlliedSides(pside, pship->GetSide()))
					balanceOfPower++;
			pshipl = pshipl->next();
		} while (pshipl);
	}
	if (balanceOfPower < 0 && cqlty & cqPositiveBOP)
		return false;
		
	
	//Spunky #333
	StationLinkIGC* psl = GetStations()->first();
	bool ourBaseInCluster = false;
    if (psl)
	{
		do
		{
			IstationIGC*    ps = psl->data();
			if (!ps->GetStationType()->HasCapability(c_sabmPedestal) && ps->SeenBySide(pside))
			{
				if (pside != ps->GetSide() && !IsideIGC::AlliedSides(pside, ps->GetSide())) // #ALLY FIXED 7/10/09 imago
					return false;
				else 
					ourBaseInCluster = true;
			}
			psl = psl->next();
		}
		while (psl != NULL);
	}
	
	if (cqlty & cqIncludeNeutral || ourBaseInCluster)
		return true;
	else
		return false;
}
void CFSShip::ShipStatusSpotted(IsideIGC* pside)
{
    SideID  sideID = pside->GetObjectID();

    SectorID    sectorID;
    {
        IclusterIGC*    pcluster = GetIGCShip()->GetCluster();
        if (pcluster == NULL)
        {
            IstationIGC*    pstation = GetIGCShip()->GetStation();
            assert (pstation);
            pcluster = pstation->GetCluster();
        }

        sectorID = pcluster->GetObjectID();
    }

    ShipStatus* pss = &m_rgShipStatus[sideID];
	pss->SetStateTime(g.timeNow.clock());
    pss->SetState(c_ssFlying);
    pss->SetParentID(NA);
    pss->SetHullID(GetIGCShip()->GetHullType()->GetObjectID());
    pss->SetSectorID(sectorID);

    //Flag that we have been detected as well
    IsideIGC*   mySide = GetSide();
    SideID  mySideID = mySide->GetObjectID();
	if (mySide != pside && !mySide->AlliedSides(mySide, pside)) //#ALLY -was: mySide != pside (Imago fixed 7/8/09)
        m_rgShipStatus[mySideID].SetDetected(true);

    //Adjust the ship status for all of the children as well
    {
        for (ShipLinkIGC*   psl = GetIGCShip()->GetChildShips()->first();
             (psl != NULL);
             psl = psl->next())
        {
            IshipIGC*   pship = psl->data();
            CFSShip*    pfsship = ((CFSShip*)(pship->GetPrivateData()));
            ShipStatus* pss = pfsship->GetShipStatus(sideID);

            pss->SetState((pship->GetTurretID() == NA) ? c_ssObserver : c_ssTurret); 
            pss->SetHullID(NA);
            pss->SetSectorID(sectorID);
            pss->SetParentID(GetShipID());

			if (mySide != pside && !mySide->AlliedSides(mySide, pside)) //#ALLY -was != (Imago fixed 7/8/09)
                pfsship->GetShipStatus(mySideID)->SetDetected(true);
        }
    }
}
    static bool CanKeepCurrentShip(ImodelIGC* pmodel)
    {
        if (pmodel->GetObjectType() == OT_ship)
        {
            // they can keep their ship only if they don't have one or are in a lifepod
            return trekClient.GetShip()->GetParentShip() != NULL
                || trekClient.GetShip()->GetBaseHullType()->HasCapability(c_habmLifepod);
        }
        else
        {
            IstationIGC* pstation;
            CastTo(pstation, pmodel);
            IhullTypeIGC* pht = trekClient.GetShip()->GetBaseHullType();

            // they can keep their current ship if they are already in this station or 
            // if the station can build the hull which they currently have.  
            return trekClient.GetShip()->GetStation() == pstation 
                ||  pht && pstation->CanBuy(pht);
        }
    }
    void RebuildList(ImodelIGC* pmodelExclude = NULL)
    {
        TRef<TListListWrapper<ImodelIGC*> > plistNew = new TListListWrapper<ImodelIGC*>();

        IsideIGC* pside = trekClient.GetSide();

        if (pside && trekClient.GetSideID() != SIDE_TEAMLOBBY)
        {
            for (ShipLinkIGC*   pshiplink = pside->GetShips()->first();
                 (pshiplink != NULL);
                 pshiplink = pshiplink->next())
            {
                IshipIGC* pship = pshiplink->data();
            
                if (pship != pmodelExclude && CanBoard(pship))
                {
                    plistNew->PushEnd(pship);
                }
            }

            for (StationLinkIGC*   pstationlink = pside->GetStations()->first();
                 (pstationlink != NULL);
                 pstationlink = pstationlink->next())
            {
                IstationIGC* pstation = pstationlink->data();
            
                if (pstation != pmodelExclude 
                    && pstation->GetBaseStationType()->HasCapability(c_sabmRestart))
                {
                    plistNew->PushEnd(pstation);
                }
            }
        }

        m_plistDestinations = plistNew;
        m_plistPaneDestinations->SetList(m_plistDestinations);
    }
void        CclusterIGC::Update(Time now)
{
    if (now > m_lastUpdate)
    {
        float   dt = now - m_lastUpdate;

        bool    bStarted = m_pMission->GetMissionStage() == STAGE_STARTED;
        if (bStarted)
        {
            {
                //Have any stations launch docked drones
                for (StationLinkIGC*   l = m_stations.first();
                     (l != NULL);
                     l = l->next())
                {
                    IstationIGC*    pstation = l->data();

                    ShipLinkIGC*    pslNext;
                    for (ShipLinkIGC*   psl = pstation->GetShips()->first();
                         (psl != NULL);
                         psl = pslNext)
                    {
                        IshipIGC*   pship = psl->data();
                        pslNext = psl->next();             //Get the next link now since the ship may launch
                        // const MissionParams* pmp = m_pMission->GetMissionParams(); 04/08 commented out as not needed // mmf 10/07 added so we can get at bExperimental game type
                        if (pship->GetAutopilot() && (pship->GetPilotType() < c_ptPlayer))
                        {
                            //Docked non-players on autopilot never are observers/parents
                            assert (pship->GetParentShip() == NULL);
                            assert (pship->GetChildShips()->n() == 0);

							// mmf/yp 10/07 added this so drones launch when ordered to even if OkToLaunch might be false
							// intentionally left c_cidMine out of the list otherwise miners would launch with their AI
							// 'order' to mine
	
							if (pship->OkToLaunch(now) || (pship->GetCommandID(c_cmdAccepted) == c_cidGoto) ||
							   (pship->GetCommandID(c_cmdAccepted) == c_cidBuild) )
                                pship->SetStation(NULL);
							// if (pship->OkToLaunch(now))  // mmf orig code
							//	  pship->SetStation(NULL);
							
                        }
                    }
					
					//Are any ships buzzing around the stations that a side has yet to eye? #121 #120 Imago 8/10
					if (GetShips()->n() > 0 && pstation->GetRoidID() != NA) {
						Vector pos = pstation->GetRoidPos();
						float Sig = pstation->GetRoidSig();
						float Radius = pstation->GetRoidRadius();
						if (Sig != 0.0f && Radius != 0.0f) {
							//check if they have a ship eying where the rock would be
							for (ShipLinkIGC*   psl1 = GetShips()->first(); (psl1 != NULL); psl1 = psl1->next()) {
								IshipIGC*   pship = psl1->data();
								if (pship->GetParentShip() || pship->GetSide()->GetObjectID() == pstation->GetSide()->GetObjectID() || pstation->SeenBySide(pship->GetSide()) || !pstation->GetRoidSide(pship->GetSide()->GetObjectID()))
									continue;
								bool bEye = bSimpleEye(pship->GetHullType()->GetScannerRange(),GetMission()->GetModel(OT_ship,pship->GetObjectID()),Sig,pstation->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaSignature),Radius,pos);
								if (bEye) {
									//Turkey 3/13 #353: kill asteroids for all sides in that alliance.
									IsideIGC* pside1 = pship->GetSide();
									for (SideLinkIGC* sl = m_pMission->GetSides()->first(); sl != NULL; sl = sl->next())
									{
										IsideIGC* pside2 = sl->data();
										if (pside1->AlliedSides(pside1, pside2))
										{
											pstation->SetRoidSide(pside2->GetObjectID(),false);
											GetMission()->GetIgcSite()->KillAsteroidEvent(pstation->GetRoidID(),GetObjectID(),pside2);
										}
									}
								}
							}
						}
					}
                }
            }
            {
                m_fCost = m_pMission->GetFloatConstant(c_fcidBaseClusterCost);

                float   costLifepod = m_pMission->GetFloatConstant(c_fcidLifepodCost);
                float   costTurret = m_pMission->GetFloatConstant(c_fcidTurretCost);
                float   costPlayer = m_pMission->GetFloatConstant(c_fcidPlayerCost);
                float   costDrone = m_pMission->GetFloatConstant(c_fcidDroneCost);

                //Have miners and builders do any pre-plotted moves. Allow ships to suicide.
                ShipLinkIGC*        lNext;
                for (ShipLinkIGC*   l = m_ships.first();
                     (l != NULL);
                     l = lNext)
                {
                    IshipIGC*   s = l->data();
                    lNext = l->next();

                    if (s->GetPilotType() < c_ptPlayer)
                        m_fCost += costDrone;
                    else if (s->GetParentShip() != NULL)
                        m_fCost += costTurret;
                    else
                    {
                        IhullTypeIGC*   pht = s->GetBaseHullType();
                        assert (pht);
                        m_fCost += pht->HasCapability(c_habmLifepod)
                                  ? costLifepod
                                  : costPlayer;
                    }

                    s->PreplotShipMove(now);
                }

                if (m_fCost > 0.0f)
                {
                    m_fCost *= dt / m_pMission->GetFloatConstant(c_fcidClusterDivisor);
                }

                {
                    //Have all ships on autopilot plot their moves. Allow ships to suicide.
                    ShipLinkIGC*        lNext;
                    for (ShipLinkIGC*   l = m_ships.first();
                         (l != NULL);
                         l = lNext)
                    {
                        IshipIGC*   s = l->data();
                        lNext = l->next();

                        s->PlotShipMove(now);
                    }
                }
            }

            {
                //Have all ships execute their moves
                for (ShipLinkIGC*   l = m_ships.first();
                     (l != NULL);
                     l = l->next())
                {
                    IshipIGC*   s = l->data();

                    if (s->GetParentShip() == NULL)
                    {
                        s->ExecuteShipMove(now);
                    }
                }
            }
        }
        else
            m_fCost = 0.0f;

        {
            //Call the update method on all the contained models
            //models might self-terminate in the update and nuke earlier models in the update loop

            //NYI debugging variables
            //ObjectType  oldObjectType = NA;
            //ObjectType  newObjectType = NA;

            ModelLinkIGC*       lNext;
            for (ModelLinkIGC*     l = m_models.first();
                 (l != NULL);
                 l = lNext)
            {
                //oldObjectType = newObjectType;
                //newObjectType = l->data()->GetObjectType();

                lNext = l->next();

                l->data()->Update(now);
            }
        }

        if (m_data.activeF && bStarted)
        {
            {
                //Update the bounding boxes for all moving objects & projectiles
                for (ModelLinkIGC*     l = m_models.first();
                     (l != NULL);
                     l = l->next())
                {
                    l->data()->SetBB(m_lastUpdate, now, dt);
                }

                m_tMax = dt;
            }

            m_kdrStatic.update();
            m_kdrMoving.update();

            {
                //Cast rays through the KD tree for each object
                for (ModelLinkIGC*     l = m_modelsCastRay.first();
                     (l != NULL);
                     l = l->next())
                {
                    ImodelIGC*  m = l->data();

                    HitTest*    ht = m->GetHitTest();

                    if (!ht->GetDeadF())
                    {
                        m_kdrStatic.test(ht, &m_collisions);
                        m_kdrMoving.test(ht, &m_collisions);
                    }
                }
            }

            //Sort the collisions by the time they occur
            m_collisions.sort(0);

            //Process each collision (in order)
            {
                m_tOffset = 0.0f;
                for (m_collisionID = 0; (m_collisionID < m_collisions.n()); m_collisionID++)
                {
                    const CollisionEntry& entry = m_collisions[m_collisionID];

                    if (!(entry.m_pHitTest1->GetDeadF() || entry.m_pHitTest2->GetDeadF()))
                    {
                        Time    timeCollision = m_lastUpdate + (m_tOffset + entry.m_tCollision);

                        ImodelIGC*  pModelHitTest1 = (ImodelIGC*)(entry.m_pHitTest1->GetData());
                        assert (pModelHitTest1);

                        ImodelIGC*  pModelHitTest2 = (ImodelIGC*)(entry.m_pHitTest2->GetData());
                        assert (pModelHitTest2);

                        //Give each participant in the collision a chance to handle the collision
                        //but give the "1st" model first dibs.
                        if ((pModelHitTest1->GetCluster() == this) &&
                            (pModelHitTest2->GetCluster() == this))
                        {
                            pModelHitTest1->HandleCollision(timeCollision, entry.m_tCollision, entry, pModelHitTest2);
                        }
                    }
                }

                m_collisions.purge();
            }
            {
                //Apply any damage from mines
                //Kids always follow parents in the ship list, so go from back to front
                //so that the killing a parent doesn't mean hitting dead elements in the list
                ShipLinkIGC*        lTxen;
                for (ShipLinkIGC*   l = m_ships.last();
                     (l != NULL);
                     l = lTxen)
                {
                    IshipIGC*   s = l->data();
                    lTxen = l->txen();

                    s->ApplyMineDamage();
                }
            }

            //Move each object & projectile
            {
                for (ModelLinkIGC*  l = m_models.first();
                     (l != NULL);
                     l = l->next())
                {
                    l->data()->Move();
                }
            }

            if ((m_nPass++) % c_nPassesPerUpdate == 0)
            {
                for (ModelLinkIGC*  l = m_models.first();
                     (l != NULL);
                     l = l->next())
                {
                    l->data()->UpdateSeenBySide();
                }

                m_pMission->GetIgcSite()->ClusterUpdateEvent(this);
            }
        }


        //Draw and resolve any explosions
        if (m_nExplosions != 0)
        {
            const int c_maxDmgs = 500;
            IdamageIGC* pdmgs[c_maxDmgs];
            int         nDmgs = 0;

            //Copy the list of models in the sector that can be damaged into
            for (ModelLinkIGC*  l = m_modelsPickable.first();
                 (l != NULL);
                 l = l->next())
            {
                ImodelIGC*  pmodel = l->data();
                ObjectType  type = pmodel->GetObjectType();

                //Not everything that can take damage can be affected by an explosion.
                if ((type == OT_ship) || (type == OT_asteroid) ||
                    (type == OT_station) || (type == OT_missile) || (type == OT_probe))
                {
                    pmodel->AddRef();
                    pdmgs[nDmgs++] = (IdamageIGC*)pmodel;

                    if (nDmgs == c_maxDmgs)
                        break;
                }
            }

            ImineIGC*   pmines[c_maxDmgs];
            int         nMines = 0;
            {
                for (MineLinkIGC*   l = m_mines.first(); (l != NULL); l = l->next())
                {
                    ImineIGC*   pm = l->data();
                    pm->AddRef();
                    pmines[nMines++] = pm;

                    if (nMines == c_maxDmgs)
                        break;
                }
            }

            int i = 0;
            do
            {
                ExplosionData&  e = m_explosions[i];
                m_pClusterSite->AddExplosion(e.position, e.radius, e.explosionType);

                float   dt = (e.time - m_lastUpdate) - m_tOffset;

                //Now, the painful part: applying damage to everything in the sector that could be hit
                {
                    for (int j = 0; (j < nDmgs); j++)
                    {
                        IdamageIGC*  pTarget = pdmgs[j];
                        if (pTarget->GetCluster() == this)      //Make sure it wasn't already destroyed
                        {
                            //The target is still around
                            Vector  p = pTarget->GetPosition() + dt * pTarget->GetVelocity();
                            float   d = (e.position - p).Length() - pTarget->GetRadius();

                            if (d < e.radius)
                            {
                                float   amount = e.amount;
                                if (d > 0.0f)
                                {
                                    float   f = 1.0f - (d / e.radius);
                                    amount *= f * f;
                                }

                                pTarget->ReceiveDamage(e.damageType | c_dmgidNoWarn | c_dmgidNoDebris,
                                                       amount,
                                                       e.time,
                                                       p, e.position,
                                                       e.launcher);
                            }
                        }
                    }
                }
                {
                    for (int j = 0; (j < nMines); j++)
                    {
                        ImineIGC*  pTarget = pmines[j];
                        if (pTarget->GetCluster() == this)      //Make sure it wasn't already destroyed
                        {
                            //The target is still around
                            const Vector&   p = pTarget->GetPosition();
                            float           d = (e.position - p).Length() - pTarget->GetRadius();

                            if (d < e.radius)
                            {
                                float   amount = e.amount;
                                if (d > 0.0f)
                                {
                                    float   f = 1.0f - (d / e.radius);
                                    amount *= f * f;
                                }
                                pTarget->ReduceStrength(amount);
                            }
                        }
                    }
                }

                if (e.launcher)
                    e.launcher->Release();
            }
            while (++i < m_nExplosions);

            //Release all the cached pointers
            {
                while (--nDmgs >= 0)
                    pdmgs[nDmgs]->Release();
            }

            {
                while (--nMines >= 0)
                    pmines[nMines]->Release();
            }

            m_nExplosions = 0;
        }

        m_lastUpdate = now;
    }
}
Exemple #6
0
    //------------------------------------------------------------------------------
    Condition*  Mission5::CreateMission (void)
    {
        GoalList*           pGoalList = new GoalList;
        Goal*               pGoal = new Goal (pGoalList);
        ImissionIGC*        pMission = trekClient.GetCore ();
        IstationIGC*        pStationNeptune = pMission->GetStation (1050);
        IstationIGC*        pStationMars = pMission->GetStation (1052);
        IwarpIGC*           pAlephNeptune = pMission->GetWarp (1050);
        IwarpIGC*           pAlephMars = pMission->GetWarp (1052);

        // generate ship ids that we'll be using throughout the mission
        m_enemyScoutID = pMission->GenerateNewShipID ();
        m_miner1ID = pMission->GenerateNewShipID ();
        m_miner2ID = pMission->GenerateNewShipID ();
        m_miner3ID = pMission->GenerateNewShipID ();
        m_miner4ID = pMission->GenerateNewShipID ();
        m_scoutID = pMission->GenerateNewShipID ();
        m_builder1ID = pMission->GenerateNewShipID ();
        m_builder2ID = pMission->GenerateNewShipID ();
        m_builder3ID = pMission->GenerateNewShipID ();

        // add the goals to the list
        pGoalList->AddGoal (CreateGoal01 ());
        pGoalList->AddGoal (CreateGoal02 ());
        pGoalList->AddGoal (CreateGoal03 ());
        pGoalList->AddGoal (CreateGoal04 ());
        pGoalList->AddGoal (CreateGoal05 ());

        // create the tower builder drones
        Vector              pos = pStationNeptune->GetPosition () + Vector (random(-300.0f, 300.0f), random(-300.0f, 300.0f), random(-300.0f, 300.0f));
        CreateDroneAction*  pCreateDroneAction = new CreateDroneAction ("Tower Layer 01", m_builder1ID, 418, 0, c_ptLayer);
        pCreateDroneAction->SetExpendableType (431);
        pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), pos);
        pGoal->AddStartAction (pCreateDroneAction);

		pos = pStationNeptune->GetPosition () + Vector (random(-300.0f, 300.0f), random(-300.0f, 300.0f), random(-300.0f, 300.0f));
		pCreateDroneAction = new CreateDroneAction ("Tower Layer 02", m_builder2ID, 418, 0, c_ptLayer);
        pCreateDroneAction->SetExpendableType (431);
        pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), pos);
        pGoal->AddStartAction (pCreateDroneAction);

        pos = pStationNeptune->GetPosition () + Vector (random(-300.0f, 300.0f), random(-300.0f, 300.0f), random(-300.0f, 300.0f));
        pCreateDroneAction = new CreateDroneAction ("Tower Layer 03", m_builder3ID, 418, 0, c_ptLayer);
        pCreateDroneAction->SetExpendableType (431);
        pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), pos);
        pGoal->AddStartAction (pCreateDroneAction);

        // create the miners
        pos = pStationNeptune->GetPosition () + Vector (random(-600.0f, 600.0f), random(-600.0f, 600.0f), random(-300.0f, 300.0f));
        pCreateDroneAction = new CreateDroneAction ("Miner 01", m_miner1ID, 438, 0, c_ptMiner);
        pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), pos);
        pGoal->AddStartAction (pCreateDroneAction);

        pos = pStationMars->GetPosition () + Vector (random(-600.0f, 600.0f), random(-600.0f, 600.0f), random(-300.0f, 300.0f));
        pCreateDroneAction = new CreateDroneAction ("Miner 02", m_miner2ID, 438, 0, c_ptMiner);
        pCreateDroneAction->SetCreatedLocation (GetStartSectorID () + 1, pos);
        pGoal->AddStartAction (pCreateDroneAction);

        pos = pStationMars->GetPosition () + Vector (random(-600.0f, 600.0f), random(-600.0f, 600.0f), random(-300.0f, 300.0f));
        pCreateDroneAction = new CreateDroneAction ("Miner 03", m_miner3ID, 438, 0, c_ptMiner);
        pCreateDroneAction->SetCreatedLocation (GetStartSectorID () + 1, pos);
        pGoal->AddStartAction (pCreateDroneAction);

        pos = pStationMars->GetPosition () + Vector (random(-600.0f, 600.0f), random(-600.0f, 600.0f), random(-300.0f, 300.0f));
        pCreateDroneAction = new CreateDroneAction ("Miner 04", m_miner4ID, 438, 0, c_ptMiner);
        pCreateDroneAction->SetCreatedLocation (GetStartSectorID () + 1, pos);
        pGoal->AddStartAction (pCreateDroneAction);

        // create the scout
        pos = pStationMars->GetPosition () + ((pAlephMars->GetPosition () - pStationMars->GetPosition ()) * random (0.5f, 0.75f));
        pCreateDroneAction = new CreateDroneAction ("Stealth Fighter", m_scoutID, 411, 0, c_ptWingman);
        pCreateDroneAction->SetCreatedLocation (GetStartSectorID () + 1, pos);
        pGoal->AddStartAction (pCreateDroneAction);

        // tell all of these guys to do nothing
        pGoal->AddStartAction (new SetCommandAction (m_scoutID, c_cmdAccepted, NULL, c_cidDoNothing));
        pGoal->AddStartAction (new SetCommandAction (m_scoutID, c_cmdCurrent, NULL, c_cidDoNothing));

        pGoal->AddStartAction (new SetCommandAction (m_miner2ID, c_cmdAccepted, NULL, c_cidDoNothing));
        pGoal->AddStartAction (new SetCommandAction (m_miner2ID, c_cmdCurrent, NULL, c_cidDoNothing));

        pGoal->AddStartAction (new SetCommandAction (m_miner3ID, c_cmdAccepted, NULL, c_cidDoNothing));
        pGoal->AddStartAction (new SetCommandAction (m_miner3ID, c_cmdCurrent, NULL, c_cidDoNothing));

        pGoal->AddStartAction (new SetCommandAction (m_miner4ID, c_cmdAccepted, NULL, c_cidDoNothing));
        pGoal->AddStartAction (new SetCommandAction (m_miner4ID, c_cmdCurrent, NULL, c_cidDoNothing));

        pGoal->AddStartAction (new SetCommandAction (m_builder1ID, c_cmdAccepted, NULL, c_cidDoNothing));
        pGoal->AddStartAction (new SetCommandAction (m_builder1ID, c_cmdCurrent, NULL, c_cidDoNothing));

        pGoal->AddStartAction (new SetCommandAction (m_builder2ID, c_cmdAccepted, NULL, c_cidDoNothing));
        pGoal->AddStartAction (new SetCommandAction (m_builder2ID, c_cmdCurrent, NULL, c_cidDoNothing));

        pGoal->AddStartAction (new SetCommandAction (m_builder3ID, c_cmdAccepted, NULL, c_cidDoNothing));
        pGoal->AddStartAction (new SetCommandAction (m_builder3ID, c_cmdCurrent, NULL, c_cidDoNothing));

        return pGoal;
    }
        void Paint(ItemID pitemArg, Surface* psurface, bool bSelected, bool bFocus)
        {
            ImodelIGC* pDestination = (ImodelIGC*)pitemArg;
            IshipIGC* pship = NULL;
            IstationIGC* pstation = NULL;

            if (pDestination == NULL || trekClient.MyMission() == NULL)
                return;

            if (pDestination->GetObjectType() == OT_ship)
            {
                CastTo(pship, pDestination);
            }
            else
            {
                assert(pDestination->GetObjectType() == OT_station);
                CastTo(pstation, pDestination);
            }



            // draw the selection bar

            if (bSelected) {
                psurface->FillRect(
                    WinRect(0, 0, GetXSize(), GetYSize()),
                    Color::Red()
                );
            }

            TRef<IEngineFont> pfont;

            // show the place we currently are in bold
            if (pship && pship == trekClient.GetShip()->GetParentShip()
                || pstation && pstation == trekClient.GetShip()->GetStation())
            {
                pfont = TrekResources::SmallBoldFont();
            }
            else
            {
                pfont = TrekResources::SmallFont();
            }
         
            Color color;

            if (CanKeepCurrentShip(pDestination))
            {
                color = Color::White();
            }
            else
            {
                color = 0.75f * Color::White();
            }

            // draw the name

            psurface->DrawString(
                pfont, 
                color,
                WinPoint(0, 0),
                pship ? pship->GetName() : pstation->GetName()
            );


            // draw the ship type (if any)
            if (pship)
            {
                psurface->DrawString(
                    pfont, 
                    color,
                    WinPoint(m_viColumns[0], 0),
                    HullName(pDestination)
                );
            }
            
            // draw the cluster
            psurface->DrawString(
                pfont, 
                color,
                WinPoint(m_viColumns[1] + 2, 0),
                SectorName(pDestination)
            );

            // draw the total number of turrets (if appropriate)
            if (pship && NumTurrets(pship))
            {
                int nNumTurrets = NumTurrets(pship);

                if (nNumTurrets != 0)
                {
                    psurface->DrawString(
                        pfont,
                        color,
                        WinPoint(m_viColumns[2] + 2, 0), 
                        ZString((int)MannedTurrets(pship)) + ZString("/") + ZString(nNumTurrets)
                    );
                }
            }
        }
    bool OnButtonTeleport()
    {
        ImodelIGC* pDestination = (ImodelIGC*)(m_plistPaneDestinations->GetSelection());
        IstationIGC* pstation = NULL;

        if (pDestination == NULL || trekClient.MyMission() == NULL 
            || trekClient.GetShip()->GetCluster() != NULL)
            return true;


        if (pDestination->GetObjectType() == OT_ship)
        {
            // if this is a ship, try boarding it.
            IshipIGC* pship;
            CastTo(pship, pDestination);

            if (trekClient.GetShip()->GetParentShip() != NULL)
            {
                trekClient.DisembarkAndBoard(pship);
            }
            else
            {
                trekClient.BoardShip(pship);
            }
            trekClient.PlaySoundEffect(personalJumpSound);
        }
        else
        {
            // try teleporting to that station
            IstationIGC* pstation;
            CastTo(pstation, pDestination);

            if (trekClient.GetShip()->GetParentShip() != NULL)
            {
                // if they are already there, just get off of the ship
                if (pstation == trekClient.GetShip()->GetParentShip()->GetStation())
                {
                    trekClient.BoardShip(NULL);
                }
                else
                {
                    trekClient.DisembarkAndTeleport(pstation);
                }
            }
            else
            {
                if (pstation != trekClient.GetShip()->GetStation())
                {
                    trekClient.SetMessageType(BaseClient::c_mtGuaranteed);
                    BEGIN_PFM_CREATE(trekClient.m_fm, pfmDocked, C, DOCKED)
                    END_PFM_CREATE

                    pfmDocked->stationID = pstation->GetObjectID();

                    trekClient.StartLockDown(
                        "Teleporting to " + ZString(pstation->GetName()) + "....", 
                        BaseClient::lockdownTeleporting);
                }
            }
        }

        // dismiss the teleport pane.
        GetWindow()->TurnOffOverlayFlags(ofTeleportPane);

        return true;
    }
//This should only be called from the ChangeCluster() callback.
void CFSPlayer::SetCluster(IclusterIGC* pcluster, bool bViewOnly)
{
  CFSShip::SetCluster(pcluster, bViewOnly);

  if (pcluster)
  {
    SetDPGroup((CFSCluster*)(pcluster->GetPrivateData()), true);

    IshipIGC*   pshipParent = GetIGCShip()->GetParentShip();
    if ((pshipParent == NULL) || bViewOnly)
    {
        ShipID      shipID = GetIGCShip()->GetObjectID();
        assert(0 == g.fm.CbUsedSpaceInOutbox());
        if (!bViewOnly)
        {
            //Move the player to his destination
            BEGIN_PFM_CREATE(g.fm, pfmSetCluster, S, SET_CLUSTER)
            END_PFM_CREATE
            pfmSetCluster->sectorID = pcluster->GetObjectID();

            //Send the position of the parent ship if we are a child, otherwise our position
            IshipIGC*   pshipSource = pshipParent ? pshipParent : GetIGCShip();
            pshipSource->ExportShipUpdate(&(pfmSetCluster->shipupdate));
            pfmSetCluster->cookie = NewCookie();
        }

        {
            for (ShipLinkIGC*   pshiplink = pcluster->GetShips()->first(); pshiplink; pshiplink = pshiplink->next())
            {
                IshipIGC * pshipExist = pshiplink->data();
                if ((pshipExist != GetIGCShip()) && (pshipExist != pshipParent))
                {
                  IshipIGC*   pshipExistParent = pshipExist->GetParentShip();

                  //Tell the new player where the existing ship is/was
                  //provided the existing ship is not the child of some other ship
                  //and is not the parent of the new ship
                  if (pshipExistParent == NULL) 
                  {
                    CFSShip * pfsShipExist = (CFSShip *) pshipExist->GetPrivateData();

                    pfsShipExist->QueueLoadoutChange();

                    BEGIN_PFM_CREATE(g.fm, pfmSSU, S, SINGLE_SHIP_UPDATE)
                    END_PFM_CREATE

                    //Always use the ship update based on the server's current view of the universe
                    //(this shouldn't be a lot worse than anything the player sent and it is easier)
                    pshipExist->ExportShipUpdate(&(pfmSSU->shipupdate));

                    {
                        ImodelIGC*  pmodelTarget = pshipExist->GetCommandTarget(c_cmdCurrent);
                        if (pmodelTarget)
                        {
                            pfmSSU->otTarget = pmodelTarget->GetObjectType();
                            pfmSSU->oidTarget = pmodelTarget->GetObjectID();
                        }
                        else
                        {
                            pfmSSU->otTarget = NA;
                            pfmSSU->oidTarget = NA;
                        }                    
                    }
                    pfmSSU->bIsRipcording = pshipExist->fRipcordActive();
                  }
                }
            }
        }

        {
            // Let's build up a list of station updates so we can batch 'em down
            IsideIGC* pside = GetIGCShip()->GetSide();

            {
                const StationListIGC * pstnlist = pcluster->GetStations();
                int nStations = 0;
                {
                    //Count the number of visible stations
                    for (StationLinkIGC* pstnlink = pstnlist->first(); pstnlink; pstnlink = pstnlink->next())
                    {
                        IstationIGC*  pstation = pstnlink->data();
                        if (pstation->SeenBySide(pside))
                            nStations++;
                    }
                }

                if (nStations != 0)
                {
                    // tell the client what happened
                    BEGIN_PFM_CREATE(g.fm, pfmStationsUpdate, S, STATIONS_UPDATE)
                      FM_VAR_PARM(NULL, nStations * sizeof(StationState))
                    END_PFM_CREATE

                    StationState* pss = (StationState*)(FM_VAR_REF(pfmStationsUpdate, rgStationStates));
                    for (StationLinkIGC* pstnlink = pstnlist->first(); pstnlink; pstnlink = pstnlink->next())
                    {
                        IstationIGC * pstation = pstnlink->data();
                        if (pstation->SeenBySide(pside))
                        {
                            pss->stationID            = pstation->GetObjectID();
                            pss->bpHullFraction       = pstation->GetFraction();
                            (pss++)->bpShieldFraction = pstation->GetShieldFraction();
                        }
                    }
                }
            }

            {
                //Let's build up a list of probe updates and batch them on down (only damage & visible probes)
                const ProbeListIGC * pprblist = pcluster->GetProbes();
                int nProbes = 0;
                {
                    for (ProbeLinkIGC* pprblink = pprblist->first(); pprblink; pprblink = pprblink->next())
                    {
                        if (pprblink->data()->SeenBySide(pside))
                            nProbes++;
                    }
                }

                if (nProbes != 0)
                {
                    BEGIN_PFM_CREATE(g.fm, pfmProbesUpdate, S, PROBES_UPDATE)
                      FM_VAR_PARM(NULL, nProbes * sizeof(ProbeState))
                    END_PFM_CREATE

                    ProbeState* pps = (ProbeState*)(FM_VAR_REF(pfmProbesUpdate, rgProbeStates));
                    for (ProbeLinkIGC* pprblink = pprblist->first(); pprblink; pprblink = pprblink->next())
                    {
                        IprobeIGC * pprobe = pprblink->data();

                        if (pprobe->SeenBySide(pside))
                        {
                            pps->probeID        = pprobe->GetObjectID();
                            (pps++)->bpFraction = pprobe->GetFraction();
                        }
                    }
                }
            }

            {
                //Let's build up a list of asteroid updates and batch them on down
                const AsteroidListIGC * pastlist = pcluster->GetAsteroids();
                int nAsteroids = 0;
                {
                    for (AsteroidLinkIGC* pastlink = pastlist->first(); pastlink; pastlink = pastlink->next())
                    {
                        if (pastlink->data()->SeenBySide(pside))
                            nAsteroids++;
                    }
                }

                if (nAsteroids != 0)
                {
                    BEGIN_PFM_CREATE(g.fm, pfmAsteroidsUpdate, S, ASTEROIDS_UPDATE)
                      FM_VAR_PARM(NULL, nAsteroids * sizeof(AsteroidState))
                    END_PFM_CREATE

                    AsteroidState* pas = (AsteroidState*)(FM_VAR_REF(pfmAsteroidsUpdate, rgAsteroidStates));
                    for (AsteroidLinkIGC* pastlink = pastlist->first(); pastlink; pastlink = pastlink->next())
                    {
                        IasteroidIGC * pasteroid = pastlink->data();

                        if (pasteroid->SeenBySide(pside))
                        {
                            pas->asteroidID         = pasteroid->GetObjectID();
                            pas->ore                = short(pasteroid->GetOre());
                            pas->co.Set(pasteroid->GetOrientation());
                            (pas++)->bpFraction     = pasteroid->GetFraction();
                        }
                    }
                }
            }
        }
    
        //Also send the identical message to all of the ship's children]
		if (!bViewOnly) //TheRock 4-1-2010 fixed ships overlaying in f3 while on a turret
        {
            for (ShipLinkIGC*   psl = GetIGCShip()->GetChildShips()->first(); (psl != NULL); psl = psl->next())
            {
                CFSShip*    pfsShip = (CFSShip*)(psl->data()->GetPrivateData());
                assert (pfsShip->IsPlayer());
                pfsShip->GetPlayer()->ResetLastUpdate();
                g.fm.SendMessages(pfsShip->GetPlayer()->GetConnection(), FM_GUARANTEED, FM_DONT_FLUSH);
            }
        }
        g.fm.SendMessages(GetConnection(), FM_GUARANTEED, FM_FLUSH);
    }
  }
  else if (bViewOnly)
  {
    IstationIGC*    pstation = GetIGCShip()->GetStation();
    assert (pstation);

    CFSCluster*     pfsCluster = (CFSCluster*)(pstation->GetCluster()->GetPrivateData());
    SetDPGroup(pfsCluster, false);
  }
  else
    SetDPGroup(NULL, false);
}