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!!"); } } }
// check collision. bool COGBonusPhysicalObject::CheckCollision (IOGPhysicalObject* _pObject) { if (!m_pListener) return false; if (!m_bActive) return false; const IOGObb& obb = _pObject->GetOBB(); if (Dist3D(m_vPosition, obb.m_vCenter) <= obb.m_Aabb.GetRadius()) { IOGCollision collision; collision.pActorMissile = m_pActor; collision.pActorBot = _pObject->GetActor(); if (m_pListener->OnCollision(collision)) { return _pObject->RespondOnCollision(collision); } } return false; }
// Moves the missile along the current trajectory. void CHSMissile::MoveTowardTarget() { if (!m_pData) { return; } // Calculate per second speed HS_FLOAT32 fSpeed; fSpeed = m_speed * (.0002778f * HSCONF.cyc_interval); static double tX = 0.0, tY = 0.0, tZ = 0.0; double dist; if(NULL != m_target && HST_SHIP == m_target->GetType()) { // get value from 0.0 - 1.0 where 1.0 is 100% visible float cloak_effect = static_cast<CHSShip* >(m_target)->CloakingEffect() * 100; // If the random value is less than the cloaking effect, // the missile still sees the ship and can update its // coordinates, otherwise, leave them at the previous // location if(hsInterface.GetRandom(100) <= (HS_UINT32) cloak_effect) { tX = m_target->GetX(); tY = m_target->GetY(); tZ = m_target->GetZ(); } } else { tX = m_target->GetX(); tY = m_target->GetY(); tZ = m_target->GetZ(); } dist = Dist3D(m_x, m_y, m_z, tX, tY, tZ); // Determine if speed is > distance, which might indicate // that the missile is within hitting range. If this is // true, move the missile just the distance to the target // and see if the coordinates are relatively close. It's // possible that the missile is close, but the target is // evading, in which case we just have to move the missile // it's regular distance. if (fSpeed > dist) { // Move just the distance double n_x, n_y, n_z; n_x = m_x + m_motion_vector.i() * dist; n_y = m_y + m_motion_vector.j() * dist; n_z = m_z + m_motion_vector.k() * dist; // Is new distance within 1 unit? dist = Dist3D(n_x, n_y, n_z, m_target->GetX(), m_target->GetY(), m_target->GetZ()); if (dist <= 1) { m_target_hit = true; return; } } // At this point we know we didn't hit, so just move regularly. m_x += m_motion_vector.i() * fSpeed; m_y += m_motion_vector.j() * fSpeed; m_z += m_motion_vector.k() * fSpeed; }
/* * This is called for all the polygons to delete them and replace them with * triangles around a centeral displaced point. The check for which ones * to process and which to skip is the same as above. */ static EDError Subdivide ( SpikeyData *dat, const EDPolygonInfo *pi) { MeshEditOp *op = dat->op; EDStateRef s = op->state; EDPointInfo *vi; double cen[3], norm[3], d; LWPntID cg; LWPntID vl[3]; int i; if (!( (pi->flags & EDDF_SELECT) && pi->numPnts >= 3 && (pi->type == LWPOLTYPE_FACE || pi->type == LWPOLTYPE_PTCH) )) return EDERR_NONE; /* * Count this polygon in the aggregate for the monitor. The * step function returns True if the user has requested an abort, * which we can propogate by returning the appropriate code. */ if (dat->mon && (*dat->mon->step) (dat->mon->data, 1)) return EDERR_USERABORT; /* * Compute the CG of the polygon vertices as `cen.' */ cen[0] = cen[1] = cen[2] = 0.0; for (i = 0; i < pi->numPnts; i++) { vi = (*op->pointInfo) (s, pi->points[i]); if (!vi) return EDERR_NOMEMORY; cen[0] += vi->position[0]; cen[1] += vi->position[1]; cen[2] += vi->position[2]; } cen[0] = cen[0] / pi->numPnts; cen[1] = cen[1] / pi->numPnts; cen[2] = cen[2] / pi->numPnts; /* * Compute the average distance from a polygon vertex to * the center point. */ d = 0.0; for (i = 0; i < pi->numPnts; i++) { vi = (*op->pointInfo) (s, pi->points[i]); if (!vi) return EDERR_NOMEMORY; d += Dist3D (vi->position, cen); } d = d / pi->numPnts; /* * Translate the center point out of the polygon's plane by this * average distance times the spikeyness factor. This translation * can only be done if the polygon has a valid normal. */ d *= dat->spike; if (d && (*op->polyNormal) (op->state, pi->pol, norm)) { cen[0] += norm[0] * d; cen[1] += norm[1] * d; cen[2] += norm[2] * d; } /* * Create a new point at the offset center position. VMAP vectors * will be an average of the values at the polygon vertices. */ cg = (*op->addIPnt) (s, cen, pi->numPnts, pi->points, NULL); if (!cg) return EDERR_NOMEMORY; /* * Loop over points in the polygon and create new triangles * from each pair to the center. We use `addPoly' rather than * `addTri' since we want to preserve the original polygon * tags and sidedness. Note the "modulo numPnts" to make * the point index wrap around the end of the point array. */ vl[0] = cg; for (i = 0; i < pi->numPnts; i++) { vl[1] = pi->points[i]; vl[2] = pi->points[(i + 1) % pi->numPnts]; if (!(*op->addPoly) (s, pi->type, pi->pol, NULL, 3, vl)) return EDERR_NOMEMORY; } /* * Delete the orginal and we're done. */ return ((*op->remPoly) (op->state, pi->pol)); }
// 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(); }