Beispiel #1
0
// Gets the fuel system for the engines. Replaces the m_fuel_source variable.
CHSFuelSystem* CHSSysEngines::GetFuelSource(void)
{
      CHSShip *cShip = (CHSShip *) GetOwnerObject();
      if (!cShip)
              return NULL;
      return (CHSFuelSystem *)cShip->GetSystems().GetSystem(HSS_FUEL_SYSTEM);
}
Beispiel #2
0
void CHSSysEngines::CutPower(HS_INT32 level)
{
    if (level == 0)
    {
        if (GetOwnerObject() && GetOwnerObject()->GetType() == HST_SHIP)
        {
            CHSShip *cShip;

            cShip = (CHSShip *) GetOwnerObject();

            if (hsInterface.AtrGet(cShip->GetDbref(), "HSMSG_ENGINES_CUT"))
            {
                HS_DBREF idx = cShip->GetDbref();

                char *msg = hsInterface.EvalExpression(hsInterface.m_buffer,
                                                       idx, idx, idx);
                cShip->NotifySrooms(msg);
            }
            else
            {
                cShip->NotifySrooms(HSCONF.engines_cut);
            }
        }
    }
}
void CHSDamCon::UnassignCrew(HS_DBREF player, int iCrew)
{
    // Be certain this is a valid crew ID.
    if ((iCrew < 1) || (iCrew > (int) GetNumCrews()))
    {
        return;
    }
    
    // Grab this crew's structure from the vector.
    THSDamageCrew & rtCrew = m_vecCrews[iCrew];
    // Only one crew can be assigned to a system at any one time.
    HS_INT32 iNumCrews = GetNumCrews();

    for (int idx = 0; idx < iNumCrews; idx++)
    {
        // If this crew is the one we're assigning, ignore it.
        if (idx == iCrew)
        {
            rtCrew.pAssignedTo = NULL;
            rtCrew.iSecondsLeft = 0;
            if (GetOwnerObject()->GetType() == HST_SHIP)
            {
                CHSShip *pOwnerShip = static_cast <CHSShip * >
                    (GetOwnerObject());

                pOwnerShip->NotifyConsoles(hsInterface.
                        HSPrintf(
                            "%s%s-%s Damage Control crew %i now available.",
                            ANSI_HILITE, ANSI_GREEN, ANSI_NORMAL, iCrew), 
                        MSG_ENGINEERING);
            }
        }
    }
}
Beispiel #4
0
// Gets the fuel system for the engines. Replaces the m_fuel_source variable.
CHSFuelSystem* CHSJumpDrive::GetFuelSource(void)
{
	CHSShip *cShip = (CHSShip *) GetOwnerObject();
	if (!cShip)
    {
		return NULL;
    }
	return (CHSFuelSystem *)cShip->GetSystems().GetSystem(HSS_FUEL_SYSTEM);
}
void CHSHandlerClass::HandleDeleteClass(CHSPacket * pPacket)
{
    CHSPDeleteClass *pDelete = static_cast < CHSPDeleteClass * >(pPacket);
    CHSPDeleteClassResponse cmdResponse;

    cmdResponse.SetPacketAddress(pDelete->GetPacketAddress());
    cmdResponse.m_bDeleted = true;

    // Check to see if any ships remain with that class.
    // If so, don't allow it to be deleted.
    THSUniverseIterator tIter;
    HS_BOOL8 bIter;
    for (bIter = CHSUniverseDB::GetInstance().GetFirstUniverse(tIter); bIter;
         bIter = CHSUniverseDB::GetInstance().GetNextUniverse(tIter))
    {
        CHSUniverse *pUniverse = tIter.pValue;

        // Search ships in the universe
        THSObjectIterator tIterator;
        HS_BOOL8 bContinue;
        for (bContinue = pUniverse->GetFirstObject(tIterator, HST_SHIP);
             bContinue;
             bContinue = pUniverse->GetNextObject(tIterator, HST_SHIP))
        {
            if (tIterator.pValue)
            {
                CHSShip *pShip = static_cast < CHSShip * >(tIterator.pValue);
                if (pShip->ClassNum() == pDelete->m_uiClassID)
                {
                    // This class is still in use.
                    cmdResponse.m_bDeleted = false;
                    break;
                }
            }
        }

        if (bContinue)
        {
            // Inner loop exited prematurely.
            break;
        }
    }

    // Can we delete this class?
    if (cmdResponse.m_bDeleted)
    {
        cmdResponse.m_bDeleted =
            CHSClassDB::GetInstance().RemoveClass(pDelete->m_uiClassID);
    }

    HSNetwork.SendPacket(cmdResponse);
}
Beispiel #6
0
void CHSJumpDrive::DoCycle()
{
    float rate;

    // Do base stuff first
    CHSEngSystem::DoCycle();

    // Charge jumpers?
    if ((GetCurrentPower() > 0) && (m_fChargeLevel < 100))
    {
        rate = GetChargeRate(true);

        if (rate > 0)
        {
            m_fChargeLevel += rate;

            // Make sure we don't overcharge
            if (m_fChargeLevel > 100)
            {
                m_fChargeLevel = 100;
            }

            if (m_fChargeLevel == 100)
            {
                if (GetOwnerObject()
                    && GetOwnerObject()->GetType() == HST_SHIP)
                {
                    CHSShip *cShip;
                    cShip = (CHSShip *) GetOwnerObject();
                    if (cShip)
                    {
                        cShip->NotifyConsoles(hsInterface.
                                              HSPrintf
                                              ("%s%s-%s Jump Drive charged.",
                                               ANSI_HILITE, ANSI_GREEN,
                                               ANSI_NORMAL), MSG_ENGINEERING);
                    }
                }
            }

        }
    }

    // If engaged, consume fuel.
    if (m_bEngaged)
    {
        ConsumeFuelBySpeed(m_uiSublightSpeed * m_iJumpSpeedMultiplier);
    }
}
Beispiel #7
0
void CHSSysThrusters::PowerUp(int level)
{
    if (!GetOwnerObject())
    {
        return;
    }

    if (GetOwnerObject()->GetType() == HST_SHIP)
    {
        CHSShip *cShip;

        cShip = (CHSShip *) GetOwnerObject();

        if (hsInterface.
            AtrGet(cShip->GetDbref(), "HSMSG_THRUSTERS_ACTIVATING"))
        {
            char *msg = hsInterface.EvalExpression(hsInterface.m_buffer,
                                                   cShip->GetDbref(),
                                                   cShip->GetDbref(),
                                                   cShip->GetDbref());
            cShip->NotifySrooms(msg);
        }
        else
        {
            cShip->NotifySrooms(HSCONF.thrusters_activating);
        }
    }
}
void CHSBlackHole::DoCycle(void)
{
	CHSObject *cObj;
	CHSUniverse *uSrc;
	CHSShip *Target;
	int idx;
	double dDistance;

		
	  uSrc = uaUniverses.FindUniverse(GetUID());
	  if (!uSrc)
		  return;
	
	  // Grab all of the objects in the universe, and see if they're in the area.
	  for (idx = 0; idx < HS_MAX_OBJECTS; idx++)
	  {
		  cObj = uSrc->GetUnivObject(idx);
		  if (!cObj)
			  continue;
		  if (cObj->GetType() != HST_SHIP)
			  continue;

		  Target = (CHSShip *) cObj;
		  dDistance = Dist3D(GetX(),GetY(),GetZ(),Target->GetX(),Target->GetY(),Target->GetZ());
		  
		  if (dDistance > GetSize() * 100 - 0.01)
			  continue;

		  int strength;

		  strength = (GetSize() * 100) / dDistance * 100 - 100;

		  Target->MoveTowards(m_x, m_y, m_z, strength);

		  Target->m_hull_points -= strength;

		  Target->NotifySrooms("The hull buckles from the black hole's gravity.");

		  	// Is hull < 0?
			if (Target->m_hull_points < 0)
			{
				Target->ExplodeMe();
				if (!hsInterface.HasFlag(m_objnum, TYPE_THING, THING_HSPACE_SIM))
					Target->KillShipCrew("THE SHIP EXPLODES!!");
			} 

	  }

}
Beispiel #9
0
void CHSJumpDrive::CutPower(HS_INT32 level)
{
    if (level == 0)
    {
        if (GetOwnerObject() && (GetOwnerObject()->GetType() == HST_SHIP))
        {
            CHSShip *cShip;

            cShip = (CHSShip *) GetOwnerObject();

            if (hsInterface.AtrGet(cShip->GetDbref(), "HSMSG_JUMPERS_CUT"))
            {
                char *msg = hsInterface.EvalExpression(hsInterface.m_buffer,
                                                       cShip->GetDbref(),
                                                       cShip->GetDbref(),
                                                       cShip->GetDbref());
                cShip->NotifySrooms(msg);
            }
            else
            {
                cShip->NotifySrooms(HSCONF.jumpers_cut);
            }
        }

        // Set charge level to 0.
        m_fChargeLevel = 0;

        // If jumpers are engaged and power is set to 0, then
        // disengage.
        if (GetEngaged())
        {
            HS_INT8 tbuf[128];

            m_bEngaged = false;
            sprintf(tbuf, "%s%s-%s Jump drive disengaged.",
                    ANSI_HILITE, ANSI_GREEN, ANSI_NORMAL);
            if (GetOwnerObject())
            {
                GetOwnerObject()->HandleMessage(tbuf, MSG_ENGINEERING);
            }
        }

    }
}
Beispiel #10
0
void CHSMTube::AttackObject(CHS3DObject * cSource,
                            CHS3DObject * cTarget,
                            CHSConsole * cConsole,
                            HS_INT32 iSysType, HS_INT32 hit_flag)
{
    HS_DBREF dbUser;

    // Grab the user of the console.
    dbUser = hsInterface.ConsoleUser(cConsole->m_objnum);

    if (cSource->GetType() == HST_SHIP)
    {
        CHSSysCloak *cCloak;
        CHSShip *ptr;

        ptr = (CHSShip *) cSource;

        // Look for the cloaking device.
        cCloak = (CHSSysCloak *) ptr->GetEngSystem(HSS_CLOAK);
        if (cCloak)
            if (cCloak->GetEngaged())
            {
                if (dbUser != HSNOTHING)
                    hsStdError(dbUser, "You cannot fire while cloaked.");
                return;
            }
    }

    // Can we attack that object?
    if (!CanAttackObject(cTarget))
    {
        if (dbUser != HSNOTHING)
            hsStdError(dbUser,
                       "You cannot attack that target with that weapon.");
    }

    // Create a missile object, and put it in space
    CHSMissile *cMiss;
    cMiss = new CHSMissile;
    cMiss->SetUID(cSource->GetUID());

    if (hit_flag == 0)
    {
        cMiss->SetAutoMiss();
    }

    // Add it to the universe
    CHSUniverse *uDest;
    uDest = cMiss->GetUniverse();
    if (!uDest)
    {
        if (dbUser != HSNOTHING)
        {
            hsInterface.Notify(dbUser,
                               "Error finding a universe to put the missile in.");
        }
        delete cMiss;
        return;
    }
    uDest->AddObject(cMiss);

    // Set missile coords
    cMiss->SetX(cSource->GetX());
    cMiss->SetY(cSource->GetY());
    cMiss->SetZ(cSource->GetZ());

    // Set missile heading
    cMiss->SetHeading(cConsole->GetXYHeading(), cConsole->GetZHeading());

    // Set missile type
    cMiss->SetWeaponData(this);

    // Set source info
    cMiss->SetSourceConsole(cConsole);
    cMiss->SetSourceObject(cSource);
    cMiss->SetTargetObject(cTarget);


#ifdef PENNMUSH
    HS_DBREF obj_num = hsInterface.CreateNewGameObject();
#else
    HS_DBREF obj_num = hsInterface.CreateNewGameObject(TYPE_THING);
#endif

    if (hsInterface.ValidObject(obj_num))
    {
        cMiss->SetDbref(obj_num);

        // Try to set the name of the missile properly but default
        // just in case
        if (NULL == m_pWeaponData)
        {
            hsInterface.SetObjectName(obj_num, "Missile");
        }
        else
        {
            hsInterface.SetObjectName(obj_num,
                                      static_cast < CHSMissileData * >(m_pWeaponData)->Name());
        }

        hsInterface.MoveObject(obj_num, uDest->GetID());
        hsInterface.SetToggle(obj_num, THING_HSPACE_OBJECT);
        hsInterface.SetObjectOwner(obj_num, hsInterface.GetGodDbref());

        // Missile objects are temporary, clear them if the game
        // is restarted while the missile is still in existance
        hsInterface.AtrAdd(obj_num, "STARTUP", "@destroy me",
                           hsInterface.GetGodDbref());
    }
    else
    {
        // Set missile HS_DBREF to some very high number that's
        // probably not duplicated.
        cMiss->SetDbref(hsInterface.GetRandom(10000) + 28534);
        hs_log("CHSMTube::AttackObject() -- Deprecated fake dbref method \
                utilized.");
    }

    if (dbUser != HSNOTHING)
    {
        hsStdError(dbUser, "Missile launched.");
    }

    m_loaded = false;
}
void CHSAsteroid::DoCycle(void)
{
	CHSObject *cObj;
	CHSUniverse *uSrc;
	CHSShip *Target;
	int idx;
	double dDistance;

		
	  uSrc = uaUniverses.FindUniverse(GetUID());
	  if (!uSrc)
		  return;
	
	  // Grab all of the objects in the universe, and see if they're in the area.
	  for (idx = 0; idx < HS_MAX_OBJECTS; idx++)
	  {
		  cObj = uSrc->GetUnivObject(idx);
		  if (!cObj)
			  continue;
		  if (cObj->GetType() != HST_SHIP)
			  continue;

		  Target = (CHSShip *) cObj;
		  dDistance = Dist3D(GetX(),GetY(),GetZ(),Target->GetX(),Target->GetY(),Target->GetZ());
		  
		  if (dDistance > GetSize() * 100)
			  continue;

		  if (GetDensity() < getrandom(50 / Target->GetSize() * ((Target->GetSpeed() + 1) / 1000)))
			  continue;

		  int strength;

		  strength = getrandom(GetDensity() * Target->GetSize() * ((Target->GetSpeed() + 1) / 1000));

		  Target->m_hull_points -= strength;

		  Target->NotifySrooms("The ship shakes as asteroids impact on the hull");

		  	// Is hull < 0?
			if (Target->m_hull_points < 0)
			{
				Target->ExplodeMe();
				if (!hsInterface.HasFlag(m_objnum, TYPE_THING, THING_HSPACE_SIM))
					Target->KillShipCrew("THE SHIP EXPLODES!!");
			} 

	  }

}
void CHSDamCon::AssignCrew(HS_DBREF player, int iCrew, CHSEngSystem * pSystem)
{
    // Be certain this is a valid crew ID.
    if ((iCrew < 1) || (iCrew > (int) GetNumCrews()))
    {
        return;
    }

    // Grab this crew's structure from the vector.
    THSDamageCrew & rtCrew = m_vecCrews[iCrew];

    // If we're assigning to a valid system, try that.  
    // Otherwise, unassign this crew.
    if (pSystem)
    {
        // Only one crew can be assigned to a system at any one time.
        HS_INT32 iNumCrews = GetNumCrews();

        for (int idx = 0; idx < iNumCrews; idx++)
        {
            // If this crew is the one we're assigning, ignore it.
            if (idx == iCrew)
            {
                continue;
            }

            THSDamageCrew & rtAssignedCrew = m_vecCrews[idx];

            // Is this crew assigned to the system we want?
            if (rtAssignedCrew.pAssignedTo == pSystem)
            {
                hsStdError(player,
                           "A repair crew is already working on that system.");
                return;
            }
        }

        // This crew is now assigned.
        rtCrew.pAssignedTo = pSystem;
        rtCrew.iSecondsLeft = HSCONF.damage_repair_time;

        if (0 == rtCrew.iSecondsLeft)
        {
            rtCrew.iSecondsLeft = 1;
        }

        if (GetOwnerObject()->GetType() == HST_SHIP)
        {
            CHSShip *pOwnerShip = static_cast < CHSShip * >(GetOwnerObject());

            pOwnerShip->NotifyConsoles(hsInterface.
                                       HSPrintf
                                       ("%s%s-%s Damage Control crew %i assigned to %s.",
                                        ANSI_HILITE, ANSI_GREEN, ANSI_NORMAL,
                                        iCrew, pSystem->GetName()),
                                       MSG_ENGINEERING);
        }
    }
    else
    {
        // This crew is unassigned.
        rtCrew.pAssignedTo = NULL;
        rtCrew.iSecondsLeft = 0;

        if (GetOwnerObject()->GetType() == HST_SHIP)
        {
            CHSShip *pOwnerShip = static_cast < CHSShip * >(GetOwnerObject());

            pOwnerShip->NotifyConsoles(hsInterface.
                                       HSPrintf
                                       ("%s%s-%s Damage Control crew %i now idle.",
                                        ANSI_HILITE, ANSI_GREEN, ANSI_NORMAL,
                                        iCrew), MSG_ENGINEERING);
        }
    }
}
void CHSDamCon::DoCycle()
{
    // First we do the basic cycle, stress and such.
    CHSEngSystem::DoCycle();

    // Now we'll just go through our damage crews.
    HS_INT32 iEfficiency;
    HS_INT32 iRandNum;

    // Calculate percentage of power allocated to damage control.
    if (GetCurrentPower() != 0 && GetOptimalPower(false) != 0)
    {
        iEfficiency = (int) (100 * ((GetCurrentPower() * 1.00) /
                                    (GetOptimalPower(false) * 1.00)));
    }
    else
    {
        iEfficiency = 0;
    }

    iRandNum = hsInterface.GetRandom(99) + 1;

    // If we roll a random number greater than the power allocated to damage
    // control, then this round of damage control goes into the toilet.
    if (iRandNum > iEfficiency)
    {
        return;
    }

    // Insure that our number of crews matches the vector size.
    m_vecCrews.resize(GetNumCrews() + 1);

    // Run through all of our damage crews.
    // Those that are assigned get their time remaining reduced.
    unsigned int idx;
    for (idx = 1; idx <= GetNumCrews(); idx++)
    {
        THSDamageCrew & rtCrew = m_vecCrews[idx];

        // Is this crew working on anything?
        if (!rtCrew.pAssignedTo)
        {
            continue;
        }

        // This crew's time decreases.
        if (rtCrew.iSecondsLeft > 0)
        {
            rtCrew.iSecondsLeft--;
        }

        // If the crew is done working, reduce the damage on the system.
        if (rtCrew.iSecondsLeft <= 0)
        {
            rtCrew.pAssignedTo->ReduceDamage();

            // If this system is fully repaired, notify everyone, and pull this
            // crew off duty.
            if (rtCrew.pAssignedTo->GetDamageLevel() == DMG_NONE)
            {
                // If this system is part of a ship,
                // notify all consoles that repairs are complete.
                if (GetOwnerObject()->GetType() == HST_SHIP)
                {
                    CHSShip *pOwnerShip =
                        static_cast < CHSShip * >(GetOwnerObject());

                    pOwnerShip->NotifyConsoles(hsInterface.
                                               HSPrintf
                                               ("%s%s-%s %s repairs complete.",
                                                ANSI_HILITE, ANSI_GREEN,
                                                ANSI_NORMAL,
                                                rtCrew.pAssignedTo->
                                                GetName()), MSG_ENGINEERING);
                }

                // This crew is no longer assigned.
                rtCrew.pAssignedTo = NULL;
            }
            else
            {
                // This system is not repaired.  Reassign the crew to another
                // round of repairs.
                rtCrew.iSecondsLeft = HSCONF.damage_repair_time;

                if (0 == rtCrew.iSecondsLeft)
                {
                    rtCrew.iSecondsLeft = 1;
                }

                if (GetOwnerObject()->GetType() == HST_SHIP)
                {
                    CHSShip *pOwnerShip =
                        static_cast < CHSShip * >(GetOwnerObject());

                    pOwnerShip->NotifyConsoles(hsInterface.
                                               HSPrintf
                                               ("%s%s-%s %s repairs incomplete, continuing repairs.",
                                                ANSI_HILITE, ANSI_GREEN,
                                                ANSI_NORMAL,
                                                rtCrew.pAssignedTo->
                                                GetName()), MSG_ENGINEERING);
                }
            }
        }
    }
}
// Attacks a target object.
void CHSLaser::AttackObject(CHSObject *cSource,
							CHSObject *cTarget,
							CHSConsole *cConsole,
							int iSysType)
{
	dbref dbUser;
	int   iAttackRoll;
	int   iDefendRoll;
	int i;
	CHSObject *cCTarget;
	double sX, sY, sZ; // Source object coords
	double tX, tY, tZ; // Target object coords;

	// Grab the user of the console.
	dbUser = hsInterface.ConsoleUser(cConsole->m_objnum);

	// Can we attack that object?
	if (cSource->GetType() == HST_SHIP)
	{
		CHSSysCloak *cCloak;
		CHSShip *ptr;
		float rval;

		ptr = (CHSShip *)cSource;

		// Look for the cloaking device.
		cCloak = (CHSSysCloak *)ptr->GetEngSystem(HSS_CLOAK);
		if (cCloak)
			if (cCloak->GetEngaged())
			{
				if (dbUser != NOTHING)
					hsStdError(dbUser, "You cannot fire while cloaked.");
				return;
			}
	}

	if (!CanAttackObject(cTarget))
	{
		if (dbUser != NOTHING)
			hsStdError(dbUser,
			"You cannot attack that target with that weapon.");
	}

 	// Calculate distance to object
	sX = cSource->GetX();
	sY = cSource->GetY();
	sZ = cSource->GetZ();
	tX = cTarget->GetX();
	tY = cTarget->GetY();
	tZ = cTarget->GetZ();

	double dDistance;
	dDistance = Dist3D(sX, sY, sZ, tX, tY, tZ) + .00001;

	// Size of a target ship matters relative to distance.
	// The closer a target gets to the ship, the larger
	// it effectively is.  That is to say it takes up more
	// of the view angle.  When the target is right next
	// to the ship, in front of the gun, it is essentially
	// the broad side of a barn, which everyone can hit.
	// Thus, to handle this we'll calculate the size of
	// the target and the viewing angle it takes up.

	double dSize; // Size of the side of the target
	double dAngle; // Amount of viewing angle taken up by size

	dSize = cTarget->GetSize();
	dSize = (.7 * dSize) * (.7 * dSize);

	// Halve the size, and divide by distance.  This
	// gives us the tangent of the angle taken up by
	// the target.
	dSize = (dSize * .5) / dDistance;

	// Take the inverse tangent to get angle.
	dAngle = atan(dSize);

	// Double the angle because we used half of the size
	// to get the angle of a right triangle.
	dAngle *= 2;

	// We now have the viewing angle consumed by the 
	// target.  There's a maximum possible value of 180,
	// so divide by that to determine how much of the viewing
	// angle is taken up by the target.
	dSize = dAngle * .005555;

	// Subtract from 1 to get maximum values of 1 when the
	// angle is small.
	dSize = 1 - dSize;

	// Now multiply by 6 to get relative difficulty of hitting
	// target.
	iDefendRoll = (int) (6 * dSize) + getrandom(6);
    iAttackRoll = GetAccuracy() + getrandom(6);

	// Simulate difficulty when a target is moving.
	// If the target is moving toward or away from the
	// attacker, it's not very difficult.  Thus, we
	// calculate the change in angle for the target
	// during one cycle.  The maximum change is 180
	// degrees.
	CHSVector tVec;
	CHSVector aVec;
	tVec = cTarget->GetMotionVector();
	aVec = cSource->GetMotionVector();

	// Calculate vector to target now.
	double dx, dy, dz;
	dx = tX - sX;
	dy = tY - sY;
	dz = tZ - sZ;

	// Make a unit vector
	dx /= dDistance;
	dy /= dDistance;
	dz /= dDistance;

	CHSVector nowVec(dx, dy, dz);

	// Now calculate coordinate for source and target
	// in one cycle.
	double sX2, sY2, sZ2;
	double tX2, tY2, tZ2;
	double aSpeed, tSpeed;

	// Grab both object speeds, and bring them down
	// to per-second levels.
	aSpeed = cSource->GetSpeed() * .0002778;
	tSpeed = cTarget->GetSpeed() * .0002778;

	// Calculate coordinates for next cycle.
	sX2 = sX + (aVec.i() * aSpeed);
	sY2 = sY + (aVec.j() * aSpeed);
	sZ2 = sZ + (aVec.k() * aSpeed);
	tX2 = tX + (tVec.i() * tSpeed);
	tY2 = tY + (tVec.j() * tSpeed);
	tZ2 = tZ + (tVec.k() * tSpeed);

	// Calculate vector to target after next cycle
	dx = tX2 - sX2;
	dy = tY2 - sY2;
	dz = tZ2 - sZ2;

	// Divide by distance to make a unit vector
	double dDistance2;
	dDistance2 = Dist3D(sX2, sY2, sZ2, tX2, tY2, tZ2);
	dx /= dDistance2;
	dy /= dDistance2;
	dz /= dDistance2;

	CHSVector nextVec(dx, dy, dz);

	// Calculate the dot product between the previous
	// and the next cycle vectors.
	double dp;
	dp = nowVec.DotProduct(nextVec);

	// Calculate the angle change.  This is in radians.
	dAngle = acos(dp);

	// Now divide angle change by 2pi to get change in angle
	// from 0 to 1, where 1 is a huge change in angle and,
	// therefore, high difficulty.
	dAngle *= .15915;

	// Add up to 6 points of defense for "evasion" by angle
	// change.
	iDefendRoll += (int) (6 * dAngle);


	// If distance is farther than our range, the shot always
	// misses.

	double range;
	range = GetRange();
				
	CHSUniverse *uDest;
	char tbuf[256];
	char fstat1[128];
	char fstat2[128];

	if (dDistance >= range || iDefendRoll > iAttackRoll) {
		sprintf(fstat1, "%s%smisses%s",ANSI_HILITE,ANSI_GREEN,ANSI_NORMAL);
		sprintf(fstat2, "%s%smissed%s",ANSI_HILITE,ANSI_GREEN,ANSI_NORMAL);
	} else {
		sprintf(fstat1, "%s%shits%s",ANSI_HILITE,ANSI_RED,ANSI_NORMAL);
		sprintf(fstat2, "%s%shit%s",ANSI_HILITE,ANSI_RED,ANSI_NORMAL);
	}
		
	uDest = uaUniverses.FindUniverse(cSource->GetUID());

	CHSSysSensors *cSensors;
	SENSOR_CONTACT *cContactS;
	SENSOR_CONTACT *cContactD;
	for (i = 0; i < HS_MAX_ACTIVE_OBJECTS; i++)
	{
		cCTarget = uDest->GetActiveUnivObject(i);
		if (!cCTarget)
			continue;
		if (cCTarget == cSource || cCTarget == cTarget)
			continue;

		cSensors = (CHSSysSensors *)cCTarget->GetEngSystem(HSS_SENSORS);
		if (!cSensors)
			continue;

		cContactS = cSensors->GetContact(cSource);
		cContactD = cSensors->GetContact(cTarget);


		if (!cContactS && !cContactD)
			continue;

		if (!cContactS && cContactD) {
			if (cContactD->status == DETECTED) {
				sprintf(tbuf, "%s[%s%s%d%s%s]%s - Unknown contact is being fired upon and %s",cTarget->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactD->m_id,ANSI_NORMAL,cTarget->GetObjectColor(),ANSI_NORMAL, fstat2);
				cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget);
			} else if (cContactD->status == IDENTIFIED) {
				sprintf(tbuf, "%s[%s%s%d%s%s]%s - The %s is being fired upon and %s",cTarget->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactD->m_id,ANSI_NORMAL,cTarget->GetObjectColor(),ANSI_NORMAL, cSource->GetName(), fstat2);
				cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget);
			}
			continue;
		}
						
											
		if (cContactS && !cContactD) {
			if (cContactS->status == DETECTED) {
				sprintf(tbuf, "%s[%s%s%d%s%s]%s - Unknown contact is firing upon something",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL);
				cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget);
			} else if (cContactS->status == IDENTIFIED) {
				sprintf(tbuf, "%s[%s%s%d%s%s]%s - The %s is firing upon something",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, cSource->GetName());
				cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget);
			}
			continue;
		}

		if (cContactS && cContactD)
			if (cContactS->status == DETECTED && cContactD->status == DETECTED) {
				sprintf(tbuf, "%s[%s%s%d%s%s]%s - Unknown contact fires and %s unknown contact %s[%s%s%d%s%s]%s",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, fstat1,cTarget->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactD->m_id,ANSI_NORMAL,cTarget->GetObjectColor(),ANSI_NORMAL);
				cCTarget->HandleMessage(tbuf,MSG_SENSOR, (long *)cCTarget);
			} else if (cContactS->status == IDENTIFIED && cContactD->status == IDENTIFIED) {
				sprintf(tbuf, "%s[%s%s%d%s%s]%s - The %s fires and %s the %s",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, cSource->GetName(), fstat1, cTarget->GetName());
				cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget);
			} else if (cContactS->status == IDENTIFIED && cContactD->status == DETECTED) {
				sprintf(tbuf, "%s[%s%s%d%s%s]%s - The %s fires and %s unknown contact %s[%s%s%d%s%s]%s",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, cSource->GetName(), fstat1,cTarget->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactD->m_id,ANSI_NORMAL,cTarget->GetObjectColor(),ANSI_NORMAL);
				cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget);
			} else if (cContactS->status == DETECTED && cContactD->status == IDENTIFIED) {
				sprintf(tbuf, "%s[%s%s%d%s%s]%s - Unknown contact fires and %s the %s",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, fstat1, cTarget->GetName());
				cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget);
			}

	}
	
	
	
	
	
	if (dDistance >= range)
    {
		if (dbUser != NOTHING)
			hsStdError(
			dbUser,
			"Your shot dissipates short of its target.");

		strcpy(tbuf,
			"An incoming energy shot has missed us.");
		cTarget->HandleMessage(tbuf, MSG_COMBAT, (long *)cSource);
	}
    else if (iAttackRoll > iDefendRoll)
	{
		// The weapon hits!
		// Determine strength based on base weapon
		// strength and range to target.
		int strength;

		strength = GetStrength();
		if (dDistance > (range * .333))
		{
			strength = (int)(strength * 
				(.333 + (1 - (dDistance / (range + .0001)))));
		}

		// If iSysType is not HSS_NOTYPE, then do a roll
		// against the accuracy of the weapon to see if
		// the system gets hit.
		if (iSysType != HSS_NOTYPE)
		{
			UINT ARoll, SRoll;
		
			ARoll = getrandom(GetAccuracy());
			SRoll = getrandom(10);

			if (SRoll > ARoll)
				iSysType = HSS_NOTYPE; // Didn't succeed
		}

		// Tell the target to take damage
		cTarget->HandleDamage(cSource, this, strength,
			cConsole, iSysType);
	
	}
	else
	{
		// The weapon misses. :(
		if (dbUser != NOTHING)
			hsStdError(dbUser,
			"Your shot skims past your target and out into space.");

		strcpy(tbuf,
			"An incoming energy shot has missed us.");
		cTarget->HandleMessage(tbuf, MSG_COMBAT, (long *)cSource);
	}

	Regenerate();
}