inline void  CprobeIGC::GetTarget(const ModelListIGC*  models,
                              IsideIGC*            pside,
                              const Vector&        myPosition,
                              float                dtUpdate,
                              float                accuracy,
                              float                speed,
                              float                lifespan,
                              ObjectType           type,
                              ImodelIGC**          ppmodelMin,
                              float*               pdistance2Min,
                              Vector*              pdirectionMin)
{
    for (ModelLinkIGC*   l = models->first(); (l != NULL); l = l->next())
    {
        ImodelIGC*   pmodel = l->data();

        assert (pmodel->GetObjectType() == type);

        ValidTarget(pmodel, 
                    pside,
                    myPosition,
                    dtUpdate,
                    accuracy,
                    speed,
                    lifespan,
                    type,
                    ppmodelMin,
                    pdistance2Min,
                    pdirectionMin);
    }
}
//This should only be called from the ChangeCluster() callback.
void CFSShip::SetCluster(IclusterIGC * pcluster, bool   bViewOnly)
{
    if (pcluster)
    {
        IshipIGC* pshipParent = m_pShip->GetParentShip();

        if ((pshipParent == NULL) && !bViewOnly)
        {
            //Everyone already in the sector now knows about the player's ship
            //(assuming the player is not in a turret)
            QueueLoadoutChange();

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

            m_pShip->ExportShipUpdate(&(pfmSSU->shipupdate));

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

            pfmSSU->bIsRipcording = m_pShip->fRipcordActive();

            g.fm.SendMessages(GetGroupSectorFlying(pcluster), FM_GUARANTEED, FM_FLUSH);

            SetDeviation(0.0f);
        }

        // if this is a drone that has arrived in a sector to which it was told
        // to go, clear its objective.
        if (!IsPlayer())
        {
            for (Command i = 0; i < c_cmdMax; i++)
            {
                ImodelIGC* ptarget = m_pShip->GetCommandTarget(i);
                
                // if this command has a cluster buoy in this cluster...
                if (ptarget && ptarget->GetObjectType() == OT_buoy 
                    && ((IbuoyIGC*)ptarget)->GetBuoyType() == c_buoyCluster
                    && ((IbuoyIGC*)ptarget)->GetCluster() == pcluster)
                {
                    // clear the command
                    m_pShip->SetCommand(i, NULL, c_cidNone);
                }
            }
        }
    }
}
bool CPigShip::OnNewChatMessage()
{

    ImodelIGC* pModel = GetIGC()->GetCommandTarget(c_cmdQueued);
    // Return if the chat message was not a command or no command is queued
    if (!pModel)
        return false;

    CommandID idCmd = GetIGC()->GetCommandID(c_cmdQueued);
    const char* pszVerb = (0 <= idCmd && idCmd < c_cidMax) ? c_cdAllCommands[idCmd].szVerb : "";
    debugf("...got a <%s> command to %s!!!\n",pszVerb,pModel->GetName());
    // Accept the queued command if auto accept is enabled
    return m_bAutoAcceptCommands ? SUCCEEDED(AcceptCommand(NULL)) : true;
}
ImodelIGC*  CclusterIGC::GetModel(const char* name) const
{
    assert (name);
    for (ModelLinkIGC*     l = m_models.first();
         (l != NULL);
         l = l->next())
    {
        ImodelIGC*  m = l->data();
        if (_stricmp(m->GetName(), name) == 0)
        {
            return m;
        }
    }

    return NULL;
}
 //------------------------------------------------------------------------------
 void        TurnToAction::Execute (void)
 {
     IshipIGC*   pShip = static_cast<IshipIGC*> (static_cast<ImodelIGC*> (*m_pObject));
     ImodelIGC*  pTarget = static_cast<ImodelIGC*> (*m_pTarget);
     if (pShip && pTarget)
     {
         Vector      delta = pTarget->GetPosition () - pShip->GetPosition ();
         turnToFace (delta, GetWindow ()->GetDeltaTime (), pShip, &g_setInputControls);
         g_setInputControls.jsValues[c_axisYaw] *= 0.5f;
         g_setInputControls.jsValues[c_axisPitch] *= 0.5f;
         g_setInputControls.jsValues[c_axisRoll] *= 0.5f;
     }
     else
     {
         g_setInputControls.jsValues[c_axisYaw] = NA;
         g_setInputControls.jsValues[c_axisPitch] = NA;
         g_setInputControls.jsValues[c_axisRoll] = NA;
     }
 }
//------------------------------------------------------------------------------
/* ImodelIGC* */    CurrentTarget::operator ImodelIGC* (void)
{
    // first, get the ship and its target
    IshipIGC*   pShip = static_cast<IshipIGC*> (static_cast<ImodelIGC*> (*m_pTarget));
    assert (pShip);
    ImodelIGC*  pTarget = pShip->GetCommandTarget (c_cmdCurrent);

    // there is an option to cache the target the first time this target is evaluated.
    // if that option is set...
    if (m_bLockOnFirstFetch)
    {

        // first check to see if we have done a fetch at all
        if (not m_pFetched)
        {
            // we haven't cached a target yet, so we need to get the target
            m_pFetched = new TypeIDTarget (pTarget ? pTarget->GetObjectType () : NA, pTarget ? pTarget->GetObjectID () : NA);
        }
        else
        {
            // we have cached a target, but the reason we want to cache the target is to
            // determine if a kill has happened, e.g. has the target been eliminated. The
            // problem is that the player may choose to change the target before
            // eliminating it, and then we are stuck waiting on the original target. Here
            // we check to see if the target has been changed w/o eliminating the
            // original target, and if so, adjust to compensate.
            ImodelIGC*  pFetched = *m_pFetched;
            if ((pFetched != pTarget) and pFetched and pTarget)
            {
                // there has been such a change, so set up a new abstract target
                delete m_pFetched;
                m_pFetched = new TypeIDTarget (pTarget ? pTarget->GetObjectType () : NA, pTarget ? pTarget->GetObjectID () : NA);
            }
        }
        return (*m_pFetched);
    }

    // that option wasn't requested, so we just return the actual found target
    return pTarget;
}
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;
    }
}
void        CclusterIGC::RecalculateCollisions(float        tOffset,
                                               ImodelIGC*   pModel1,
                                               ImodelIGC*   pModel2)
{
    //Update the stop positions for the hit tests (& update their bounding boxes)
    assert ((pModel1->GetAttributes() & c_mtStatic) == 0);
    HitTest*    pHitTest1 = pModel1->GetHitTest();
    if (pHitTest1)
    {
        if (pHitTest1->GetDeadF())
            pHitTest1 = NULL;
        else
            pHitTest1->SetStopPosition();
    }

    HitTest*    pHitTest2;
    if ((pModel2 == NULL) || (pModel2->GetAttributes() & c_mtStatic))
        pHitTest2 = NULL;
    else
    {
        pHitTest2 = pModel2->GetHitTest();
        if (pHitTest2)
        {
            if (pHitTest2->GetDeadF())
                pHitTest2 = NULL;
            else
                pHitTest2->SetStopPosition();
        }
    }

    if (pHitTest1 || pHitTest2)
    {
        m_tOffset += tOffset;

        //Don't bother recalculating collisions if we are already outside the window in which collisions can occur.
        if (m_tOffset <= m_tMax)
        {
            {
                //Move all objects to their positions at the time of the collision
                for (ModelLinkIGC*  l = m_models.first();
                     (l != NULL);
                     l = l->next())
                {
                    ImodelIGC*  m = l->data();

                    HitTest*    pht = m->GetHitTest();

                    //Move the models not involved in the collision
                    if ((m != pModel1) && (m != pModel2))
                        m->Move(tOffset);
                    else
                        pht->AdjustTimes(tOffset);

                    //Update the bounding boxes for everything
                    pht->UpdateBB();
                }
            }

            //Remove any collisions that involved either object involved in this collision
            m_collisions.flush(m_collisionID + 1, pHitTest1, pHitTest2);

            {
                //Check for any collisions between either ship and the rest of the stuff in the cluster
                for (ModelLinkIGC*     l = m_models.first();
                     (l != NULL);
                     l = l->next())
                {
                    ImodelIGC*  m = l->data();

                    if ((m != pModel1) && (m != pModel2) && (m->GetAttributes() & (c_mtCastRay | c_mtHitable)))
                    {
                        HitTest*    ht = m->GetHitTest();

                        if (!ht->GetDeadF())
                        {
                            if (ht->GetID() != c_htidStaticObject)
                            {
                                //ht is not a static object, so it can always go first (which also handles
                                //the problem that projectiles (which ht might be) go before ships).

                                //prevent collisions between projectiles and their launcher.
                                if (pHitTest1 &&
                                    (ht->GetNoHit() != pHitTest1) &&
                                    (pHitTest1->GetNoHit() != ht))
                                    ht->Collide(pHitTest1, &m_collisions);

                                if (pHitTest2 &&
                                    (ht->GetNoHit() != pHitTest2) &&
                                    (pHitTest2->GetNoHit() != ht))
                                    ht->Collide(pHitTest2, &m_collisions);
                            }
                            else
                            {
                                //in collisions between static objects and non-static objects, the
                                //non-static object is always first
                                if (pHitTest1 &&
                                    (ht->GetNoHit() != pHitTest1) &&
                                    (pHitTest1->GetNoHit() != ht))
                                    pHitTest1->Collide(ht, &m_collisions);

                                if (pHitTest2 &&
                                    (ht->GetNoHit() != pHitTest2) &&
                                    (pHitTest2->GetNoHit() != ht))
                                    pHitTest2->Collide(ht, &m_collisions);
                            }
                        }
                    }
                }
            }

            //Resort the collisions of the yet to be handled collisions
            m_collisions.sort(m_collisionID + 1);
        }
    }
}
void        CweaponIGC::FireWeapon(Time now)
{
	assert(m_mountID >= 0);
	assert(m_ship);

	bool    fFiredShot = false;

	if (m_fActive && (m_nextFire < now))
	{
		Time    lastUpdate = m_ship->GetLastUpdate();

		//Never fire retroactively.
		if (m_nextFire < lastUpdate)
			m_nextFire = lastUpdate;

		bool    fSelected = fIsWeaponSelected();

		float   energy = m_ship->GetEnergy();                   //the energy the ship would have at "now"
		if (energy >= m_typeData->energyPerShot)
		{
			//We'd be able to fire before now and would have enough energy at now to fire, so ...
			float   rechargeRate = m_ship->GetHullType()->GetRechargeRate();

			float   energyDeficit = (m_nextFire - now) *            //this is how much we are in the hole because we
				rechargeRate;                   //are shooting sooner than "now" (must be < 0)

			short     ammo = m_ship->GetAmmo();

			if ((ammo > 0) || (m_typeData->cAmmoPerShot == 0))
			{
				// we are firing at least once this frame
				fFiredShot = true;
				m_pMission->GetIgcSite()->PlayFFEffect(effectFire, m_pshipGunner ? m_pshipGunner : m_ship);

				//Get the stuff that won't change between shots
				IclusterIGC*    cluster = m_ship->GetCluster();
				assert(cluster);

				const Orientation&  shipOrientation = m_ship->GetOrientation();

				//Orientation         orientationBfr;
				const Orientation*  pMyOrientation;
				if (m_pshipGunner)
				{
					/*
					orientationBfr = m_pshipGunner->GetOrientation() * (*m_porientation * shipOrientation);
					pMyOrientation = &orientationBfr;
					*/
					pMyOrientation = &(m_pshipGunner->GetOrientation());
				}
				else
				{
					pMyOrientation = &shipOrientation;
				}

				//This is how much energy deficit recovers between shots
				float   dtimeBurst = GetDtBurst();

				float   recharge = rechargeRate * dtimeBurst;

				const Vector&       myVelocity = m_ship->GetVelocity();
				Vector              myPosition = m_ship->GetPosition() + *m_pposition * shipOrientation; //*pMyOrientation;


				/*
				m_ship->GetThingSite()->AddMuzzleFlare(
					m_emissionPt,
					min(dtimeBurst * 0.5f, 0.05f)
				);
				*/

				DataProjectileIGC   dataProjectile;
				dataProjectile.projectileTypeID = m_projectileType->GetObjectID();

				float   lifespan = GetLifespan();

				float   speed = m_projectileType->GetSpeed();
				if (m_typeData->cAmmoPerShot)
					speed *= m_ship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaSpeedAmmo);
				bool    absoluteF = m_projectileType->GetAbsoluteF();

				const Vector*   ppositionTarget;
				const Vector*   pvelocityTarget;
				ImodelIGC*  ptarget = NULL;
				if (m_projectileType->GetBlastPower() != 0.0f)
				{
					if (m_pshipGunner)
						ptarget = m_pshipGunner->GetCommandTarget(c_cmdCurrent);
					else
						ptarget = m_ship->GetCommandTarget(c_cmdCurrent);

					if (ptarget)
					{
						if ((ptarget->GetCluster() == cluster) && m_ship->CanSee(ptarget))
						{
							ppositionTarget = &(ptarget->GetPosition());
							pvelocityTarget = &(ptarget->GetVelocity());
						}
						else
							ptarget = NULL;
					}
				}

				int nShots = fSelected ? 10 : 0;    //Only allow a single shot if the weapon is no longer selected

				do
				{
					if (energy + energyDeficit < m_typeData->energyPerShot)
					{
						//We don't have enough energy to fire at our prefered time ... so wait until we do.
						m_nextFire += (m_typeData->energyPerShot - (energy + energyDeficit)) / rechargeRate;
					}

					//Permute the "forward" direction slightly by a random amount
					dataProjectile.forward = pMyOrientation->GetForward();
					if (m_typeData->dispersion != 0.0f)
					{
						float   r = random(0.0f, m_typeData->dispersion);
						float   a = random(0.0f, 2.0f * pi);
						dataProjectile.forward += (r * cos(a)) * pMyOrientation->GetRight();
						dataProjectile.forward += (r * sin(a)) * pMyOrientation->GetUp();

						dataProjectile.forward.SetNormalize();
					}

					dataProjectile.velocity = speed * dataProjectile.forward;
					if (!absoluteF)
						dataProjectile.velocity += myVelocity;

					Vector  position = myPosition + myVelocity * (m_nextFire - lastUpdate);
					dataProjectile.lifespan = lifespan;
					if (ptarget)
					{
						Vector      dV = *pvelocityTarget - dataProjectile.velocity;

						float       dV2 = dV.LengthSquared();
						if (dV2 != 0.0f)
						{
							Vector      dP = position - *ppositionTarget;  //reverse so time has right sense

							dataProjectile.lifespan = (dV * dP) / dV2;
							if (dataProjectile.lifespan > lifespan)
								dataProjectile.lifespan = lifespan;
							else if (dataProjectile.lifespan < 0.1f)
								dataProjectile.lifespan = 0.1f;     //Don't let it explode in our face
						}
					}

					IprojectileIGC*  p = (IprojectileIGC*)(m_pMission->CreateObject(m_nextFire, OT_projectile,
						&dataProjectile, sizeof(dataProjectile)));
					if (p)
					{
						if (m_pshipGunner)
							p->SetGunner(m_pshipGunner);
						else
							p->SetLauncher(m_ship);

						p->SetPosition(position);

						p->SetCluster(cluster);

						p->Release();
					}

					energyDeficit += rechargeRate * dtimeBurst;
					energy -= m_typeData->energyPerShot;
					ammo -= m_typeData->cAmmoPerShot;

					m_nextFire += dtimeBurst;
				} while ((nShots-- > 0) &&
					(m_nextFire < now) &&
					(energy + energyDeficit >= m_typeData->energyPerShot) &&
					(ammo > 0));

				m_ship->SetAmmo(ammo > 0 ? ammo : 0);

				if ((ammo == 0) && (m_typeData->cAmmoPerShot != 0))
					fSelected = false;

				m_ship->SetEnergy(energy);
			}
		}

		if (!fSelected)
			Deactivate();
	}

	// if we fired a shot, keep track of it (note - stored localy because the 
	// call to deactivate (above) clears the member variable).
	m_fFiringShot = fFiredShot;

	// if we are still firing and have the energy and ammo for the next shot,
	// assume we are firing a burst.
	if ((m_ship->GetEnergy() >= m_typeData->energyPerShot)
		&& (m_ship->GetAmmo() >= m_typeData->cAmmoPerShot)
		&& (m_fFiringBurst || (m_fActive && m_fFiringShot)) // a burst starts with a shot
		)
	{
		m_fFiringBurst = true;
	}
	else
	{
		m_fFiringBurst = false;
	}

}
Exemple #10
0
    //------------------------------------------------------------------------------
    Condition*  Mission6::CreateMission (void)
    {
        GoalList*   pGoalList = new GoalList;

        // play the introductory audio
        pGoalList->AddGoal (CreatePlaySoundGoal (salCommenceScanSound));

        // wait half  second
        pGoalList->AddGoal (new Goal (new ElapsedTimeCondition (0.5f)));

		// tm_6_01
		// Okay, Cadet, here's your Advanced Fighter. There's a base 
		// outpost here in case you need to replenish yourself.
        pGoalList->AddGoal (CreatePlaySoundGoal (tm_6_01Sound));

        // wait two more seconds
        pGoalList->AddGoal (new Goal (new ElapsedTimeCondition (2.0f)));

		// tm_6_02
		// Iron Coalition Intelligence reports inbound enemy craft. 
		// They're using an old code for their comms, so we can hear 
		// them. Watch your message stream to see what they're up to.
        {
            Goal*   pGoal = CreatePlaySoundGoal (tm_6_02Sound);
            pGoal->AddStartAction (new SetDisplayModeAction (TrekWindow::cmCockpit));
            pGoal->AddStartAction (new MessageAction ("Watch the chat to see what the enemy craft are after."));
            pGoalList->AddGoal (pGoal);
        }

        // wait half  second
        pGoalList->AddGoal (new Goal (new ElapsedTimeCondition (0.5f)));

		// tm_6_03
		// DEFEND THE MINERS! This simulation is over when you die.
        pGoalList->AddGoal (CreatePlaySoundGoal (tm_6_03Sound));

        // wait two more seconds
        pGoalList->AddGoal (new Goal (new ElapsedTimeCondition (2.0f)));

        // need this
        ImissionIGC*        pMission = trekClient.GetCore();
        ImodelIGC*          pStation = pMission->GetModel (OT_station, 1030);

        // wait for player to be dead
        {
            Goal*               pGoal = new Goal (new FalseCondition);

            // create enemy ships
            ShipID              enemyShipID = pMission->GenerateNewShipID ();
            CreateDroneAction*  pCreateDroneAction = new CreateDroneAction ("Enemy Support", enemyShipID, 310, 1, c_ptWingman);
            pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), Vector (3800.0f, 4275.0f, 855.0f));
            Condition*          pShipIsDestroyedcondition = new GetShipIsDestroyedCondition2 (OT_ship, static_cast<ObjectID> (enemyShipID));
            pGoal->AddConstraintCondition (new ConditionalAction (pShipIsDestroyedcondition, pCreateDroneAction));

            enemyShipID = pMission->GenerateNewShipID ();
            pCreateDroneAction = new CreateDroneAction ("Enemy Fighter", enemyShipID, 315, 1, c_ptWingman);
            pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), Vector (3800.0f, 4175.0f, 855.0f));
            pShipIsDestroyedcondition = new GetShipIsDestroyedCondition2 (OT_ship, static_cast<ObjectID> (enemyShipID));
            pGoal->AddConstraintCondition (new ConditionalAction (pShipIsDestroyedcondition, pCreateDroneAction));

            pGoalList->AddGoal (pGoal);
        }

        // build the goal that we'll return
        {
            Goal*   pGoal = new Goal (pGoalList);

            // create friendly miners
            Vector              pos = pStation->GetPosition ();
            pos.x += random(-1000.0f, 1000.0f);
            pos.y += random(-1000.0f, 1000.0f);
            pos.z += random(-1000.0f, 1000.0f);

            ShipID              minerShipID = pMission->GenerateNewShipID ();
            CreateDroneAction*  pCreateDroneAction = new CreateDroneAction ("Miner 01", minerShipID, 436, 0, c_ptMiner);
            pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), pos);
            Condition*          pShipIsDestroyedcondition = new GetShipIsDestroyedCondition2 (OT_ship, static_cast<ObjectID> (minerShipID));
            pGoal->AddConstraintCondition (new ConditionalAction (pShipIsDestroyedcondition, pCreateDroneAction));

            pos = pStation->GetPosition ();
            pos.x += random(-1000.0f, 1000.0f);
            pos.y += random(-1000.0f, 1000.0f);
            pos.z += random(-1000.0f, 1000.0f);

            minerShipID = pMission->GenerateNewShipID ();
            pCreateDroneAction = new CreateDroneAction ("Miner 02", minerShipID, 436, 0, c_ptMiner);
            pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), pos);
            pShipIsDestroyedcondition = new GetShipIsDestroyedCondition2 (OT_ship, static_cast<ObjectID> (minerShipID));
            pGoal->AddConstraintCondition (new ConditionalAction (pShipIsDestroyedcondition, pCreateDroneAction));

            pos = pStation->GetPosition ();
            pos.x += random(-1000.0f, 1000.0f);
            pos.y += random(-1000.0f, 1000.0f);
            pos.z += random(-1000.0f, 1000.0f);

            minerShipID = pMission->GenerateNewShipID ();
            pCreateDroneAction = new CreateDroneAction ("Miner 03", minerShipID, 436, 0, c_ptMiner);
            pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), pos);
            pShipIsDestroyedcondition = new GetShipIsDestroyedCondition2 (OT_ship, static_cast<ObjectID> (minerShipID));
            pGoal->AddConstraintCondition (new ConditionalAction (pShipIsDestroyedcondition, pCreateDroneAction));

            pos = pStation->GetPosition ();
            pos.x += random(-1000.0f, 1000.0f);
            pos.y += random(-1000.0f, 1000.0f);
            pos.z += random(-1000.0f, 1000.0f);

            minerShipID = pMission->GenerateNewShipID ();
            pCreateDroneAction = new CreateDroneAction ("Miner 04", minerShipID, 436, 0, c_ptMiner);
            pCreateDroneAction->SetCreatedLocation (GetStartSectorID (), pos);
            pShipIsDestroyedcondition = new GetShipIsDestroyedCondition2 (OT_ship, static_cast<ObjectID> (minerShipID));
            pGoal->AddConstraintCondition (new ConditionalAction (pShipIsDestroyedcondition, pCreateDroneAction));

            return pGoal;
        }
    }
Exemple #11
0
        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)
                    );
                }
            }
        }
Exemple #12
0
    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);
}