// Prints information about all of the universes in the array // to a given player. void CHSUniverseDBDef::PrintInfo(int player) { if (m_mapUniverses.empty()) { hsInterface.Notify(player, "No universes currently loaded."); return; } hsInterface.Notify(player, "[Room#] Name Objects Active"); CSTLUniverseMap::iterator iter; for (iter = m_mapUniverses.begin(); iter != m_mapUniverses.end(); iter++) { CHSUniverse *pUniverse = iter->second; if (pUniverse) { hsInterface.Notify(player, hsInterface. HSPrintf("[%5d] %-32s%4d %4d", pUniverse->GetID(), pUniverse->GetName(), pUniverse->GetNumObjects(), pUniverse->GetNumActiveObjects())); } } }
HS_BOOL8 CHSUniverseDBDef::DeleteUniverse(HS_UINT32 uid) { CSTLUniverseMap::iterator iter; CHSUniverse *pUniverse = NULL; if ((iter = m_mapUniverses.find(uid)) != m_mapUniverses.end()) { pUniverse = (*iter).second; } if (!pUniverse) { return false; } // Check to see if the universe is empty if (!pUniverse->IsEmpty()) { return false; } // Delete it pUniverse->Release(); m_mapUniverses.erase(iter); return true; }
void CHSHandlerUniverse::HandleGetUniverseList(CHSPacket * pPacket) { hs_log("ADMIN SERVER: Handle packet GetUniverseList"); CHSPGetUniverseList *cmdGetList = static_cast < CHSPGetUniverseList * >(pPacket); // Create a class list packet as a response. CHSPUniverseList cmdList; cmdList.SetPacketAddress(cmdGetList->GetPacketAddress()); THSUniverseIterator tIter; HS_BOOL8 bContinue; for (bContinue = CHSUniverseDB::GetInstance().GetFirstUniverse(tIter); bContinue; bContinue = CHSUniverseDB::GetInstance().GetNextUniverse(tIter)) { if (tIter.pValue != NULL) { CHSUniverse *pUniverse = (CHSUniverse *) tIter.pValue; CHSPUniverseList::THSUniverse tEntry; tEntry.uiID = pUniverse->GetID(); tEntry.strName = pUniverse->GetName(); tEntry.uiNumObjects = pUniverse->GetNumObjects(); tEntry.uiNumActiveObjects = pUniverse->GetNumActiveObjects(); cmdList.AddUniverse(tEntry); } } HSNetwork.SendPacket(cmdList); }
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); }
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 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!!"); } } }
// Runs through the list of universes, telling them to // save to the specified file. void CHSUniverseDBDef::SaveToFile(const char *lpstrPath) { FILE *fp; char tbuf[256]; // Is the file path good? if (!lpstrPath || strlen(lpstrPath) == 0) { hs_log ("Attempt to save the universe database, but no path specified. Could be a config file problem."); return; } // Any universes to save? if (m_mapUniverses.size() == 0) { return; } // Open the database fopen_s(&fp, lpstrPath, "w"); if (!fp) { sprintf_s(tbuf, "ERROR: Unable to write universes to %s.", lpstrPath); hs_log(tbuf); return; } // Print dbversion fprintf(fp, "DBVERSION=4.0\n"); // Save all of the universes. CSTLUniverseMap::iterator iter; for (iter = m_mapUniverses.begin(); iter != m_mapUniverses.end(); iter++) { CHSUniverse *pUniverse; pUniverse = (*iter).second; if (pUniverse) { pUniverse->SaveToFile(fp); } } fprintf(fp, "*END*\n"); fclose(fp); }
CHSUniverseDBDef::~CHSUniverseDBDef() { CSTLUniverseMap::iterator iter; // Free up the universes we've loaded. for (iter = m_mapUniverses.begin(); iter != m_mapUniverses.end(); iter++) { CHSUniverse *pUniverse; pUniverse = (*iter).second; if (pUniverse) { pUniverse->Release(); } } }
void CHSWormHole::GateShip(CHSShip *cShip) { if (!cShip) return; BOOL succeed; if (getrandom(100) <= m_stability) succeed = TRUE; else succeed = FALSE; cShip->NotifyConsoles("The ship enters the wormhole and an infinite amount of colors can be seen.", MSG_SENSOR); cShip->NotifySrooms("The ship shakes slightly as it enters a wormhole."); CHSUniverse *uDest; uDest = uaUniverses.FindUniverse(cShip->GetUID()); if (uDest) { uDest->SendContactMessage("In the distance a ship gates a wormhole.", DETECTED, cShip); uDest->SendContactMessage( tprintf("In the distance the %s gates a wormhole.",cShip->GetName()), IDENTIFIED, cShip); } if (succeed) { if (m_destx) cShip->SetX(m_destx); if (m_desty) cShip->SetY(m_desty); if (m_destz) cShip->SetZ(m_destz); CHSUniverse *uSource; uDest = uaUniverses.FindUniverse(m_destuid); if (uDest) { // Grab the source universe uSource = uaUniverses.FindUniverse(cShip->GetUID()); // Now pull it from one, and put it in another uSource->RemoveObject(cShip); cShip->SetUID(m_destuid); uDest->AddObject(cShip); } cShip->NotifyConsoles("The ship safely emerges on the other side of the wormhole.", MSG_SENSOR); } else { cShip->NotifyConsoles("The wormhole collapses and the structural integrity is comprimised.", MSG_SENSOR); cShip->ExplodeMe(); if (!hsInterface.HasFlag(cShip->GetDbref(), TYPE_THING, THING_HSPACE_SIM)) cShip->KillShipCrew("The ship explodes as the structural integrity fails!"); } }
void CHSMissile::DoCycle() { // Do we need to delete ourselves? if (m_delete_me) { // Remove us from space CHSUniverse *cSource; cSource = GetUniverse(); if (cSource) { cSource->RemoveObject(this); } // Purge the object representing the missile prior to deallocating // memory if (hsInterface.ValidObject(GetDbref())) { hsInterface.DestroyObject(GetDbref()); } return; } // If we have no target or no parent, remove us from space. if (!m_target || !m_pData || !m_target->IsActive()) { hs_log("CHSMissile::DoCycle() Missile Data Invalid - Removing Object."); m_delete_me = true; return; } // Do we know how much time is left until we die? if (m_timeleft < 0) { CalculateTimeLeft(); } else { m_timeleft--; } // Missile depleted? if (0 == m_timeleft) { m_delete_me = true; return; } // Change the missile heading toward the target ChangeHeading(); // Move us closer to the target. MoveTowardTarget(); // The MoveTowardTarget() checks to see if the missile hits // so we just have to check our flag. if (m_target_hit) { // If we aren't designated to miss, apply damage if (m_specified_miss != true) { // BOOM! HitTarget(); } m_delete_me = true; // Delete next time around } }
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; }
// Loads universes from the universe db. It does this by // loading each line in the db and splitting it up into // a key/value pair. HS_BOOL8 CHSUniverseDBDef::LoadFromFile(const char *lpstrPath) { char tbuf[256]; char strKey[256]; char strValue[256]; FILE *fp; char *ptr; CHSUniverse *pNewUniverse = NULL; sprintf_s(tbuf, "LOADING: %s", lpstrPath); hs_log(tbuf); fopen_s(&fp, lpstrPath, "r"); if (!fp) { hs_log("ERROR: Unable to open object database for loading!"); return false; } // Load in the lines from the database, splitting the // line into key/value pairs. Each OBJNUM key specifies // the beginning of a new universe definition. while (fgets(tbuf, 256, fp)) { // Truncate newline chars if ((ptr = strchr(tbuf, '\n')) != NULL) *ptr = '\0'; if ((ptr = strchr(tbuf, '\r')) != NULL) *ptr = '\0'; // Check for end of DB if (!strcmp(tbuf, "*END*")) break; // Extract key and value extract(tbuf, strKey, 0, 1, '='); extract(tbuf, strValue, 1, 1, '='); // Determine key type, then do something. if (!strcmp(strKey, "DBVERSION")) { } else if (!strcmp(strKey, "OBJNUM")) { pNewUniverse = new CHSUniverse; HS_UINT32 uiID = atoi(strValue); if (hsInterface.ValidObject(uiID) == false) { return false; } pNewUniverse->SetID(uiID); hsInterface.SetToggle(uiID, ROOM_HSPACE_UNIVERSE); m_mapUniverses[uiID] = pNewUniverse; } else { // Just try to set the attribute on the universe. if (pNewUniverse && !pNewUniverse->SetAttributeValue(strKey, strValue)) { sprintf_s(tbuf, "WARNING: Key \"%s\" encountered but not handled.", strKey); hs_log(tbuf); } } } fclose(fp); sprintf_s(tbuf, "LOADING: %d universes loaded.", m_mapUniverses.size()); hs_log(tbuf); return true; }
// 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(); }