示例#1
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;
}
// 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();
}