TriggerSettingsRocket* FireworkFactory:: getBangerRocket(float intensity) { RocketSettings& rocketSettings = *new RocketSettings(); rocketSettings.startSpeedMin = 1000; rocketSettings.startSpeedMax = 1200; rocketSettings.directionVar = 4; rocketSettings.gravity.y = 200; rocketSettings.drag = 0.95; ParticleSystemSettings trails = getBangerTrails(); ParticleSystemSettings bang = getBangerBang(); ParticleSystemSettings laserBang = getBangerLaserBang(); ParticleSystemSettings bangCrackles = getBangerCrackles(intensity); ParticleSystemSettings smoke1 = getSmoke(); ParticleSystemSettings smoke2 = getSmoke(); smoke2.emitMode = PARTICLE_EMIT_CONTINUOUS; smoke2.emitCount = 200; smoke2.emitLifeTime = 0.2; smoke2.sizeStartMax = 30; smoke2.speedMax = 100; smoke2.brightnessStartMin = 10; smoke2.brightnessStartMax = 30; bang.emitDelay =laserBang.emitDelay = bangCrackles.emitDelay = trails.emitLifeTime = smoke1.emitLifeTime =smoke2.emitDelay = 2; rocketSettings.addParticleSystemSetting(trails); //rocketSettings.addParticleSystemSetting(smoke1); rocketSettings.addParticleSystemSetting(smoke2); rocketSettings.addParticleSystemSetting(bang); rocketSettings.addParticleSystemSetting(laserBang); rocketSettings.addParticleSystemSetting(bangCrackles); TriggerSettingsRocket* ts = new TriggerSettingsRocket(); ts->addRocketSettings(&rocketSettings); ts->rechargeSettings = TriggerRechargeSettings::slow; ts->radius *=1.3; return ts; }
RocketSettings SceneRealistic:: getBangerRocket() { RocketSettings rocketSettings; rocketSettings.startSpeedMin = 1000; rocketSettings.startSpeedMax = 1200; rocketSettings.directionVar = 4; rocketSettings.gravity.y = 200; rocketSettings.drag = 0.95; ParticleSystemSettings trails = getBangerTrails(); ParticleSystemSettings bang = getBangerBang(); ParticleSystemSettings bangCrackles = getBangerCrackles(); ParticleSystemSettings smoke1 = getSmoke(); ParticleSystemSettings smoke2 = getSmoke(); smoke2.emitMode = PARTICLE_EMIT_CONTINUOUS; smoke2.emitCount = 200; smoke2.emitLifeTime = 0.2; smoke2.sizeStartMax = 30; smoke2.speedMax = 100; smoke2.brightnessStartMin = 10; smoke2.brightnessStartMax = 30; bang.emitDelay = bangCrackles.emitDelay = trails.emitLifeTime = smoke1.emitLifeTime =smoke2.emitDelay = 2; rocketSettings.addParticleSystemSetting(trails); rocketSettings.addParticleSystemSetting(smoke1); rocketSettings.addParticleSystemSetting(smoke2); rocketSettings.addParticleSystemSetting(bang); rocketSettings.addParticleSystemSetting(bangCrackles); return rocketSettings; }
//------------------------------------------------------------------------------ // nib2PlayerState() -- // Called by our processInputList() to update the state of networked player. //------------------------------------------------------------------------------ void Nib::nib2PlayerState() { models::Player* player = getPlayer(); if (player != nullptr) { // Drive modes player->freeze( isFrozen() ); player->setMode( getMode() ); // Appearance player->setDamage( getDamage() ); player->setSmoke( getSmoke() ); player->setFlames( getFlames() ); player->setCamouflageType( getCamouflageType() ); // IPlayer's position and Euler angles are set by the player // during its dynamics phase and using our DR functions. } }
//------------------------------------------------------------------------------ // entityStateManager() -- (Output support) // -- Update the entity object for this NIB(Player) //------------------------------------------------------------------------------ bool Nib::entityStateManager(const LCreal curExecTime) { bool ok = false; // Get the player pointer const Simulation::Player* player = getPlayer(); if (player == nullptr) return ok; // Dummy weapon? const Simulation::Weapon* ww = dynamic_cast<const Simulation::Weapon*>( player ); if (ww != nullptr) { if (ww->isDummy()) return ok; } if (isPlayerStateUpdateRequired(curExecTime)) { // // Send an entity state PDU // 1) create buffer // 2) set state information // 3) send data // // Get our NetIO and the main simulation NetIO* disIO = static_cast<NetIO*>(getNetIO()); Simulation::Simulation* sim = disIO->getSimulation(); // Capture the player data, reset the dead reckoning and // mark the current time. playerState2Nib(); // --- // Create buffer and cast it as an entity state PDU // --- char pduBuffer[NetIO::MAX_PDU_SIZE]; EntityStatePDU* pdu = (EntityStatePDU*) &pduBuffer[0]; // // Entity state PDU structure // ========================================================= // PDUHeader header; // EntityIdentifierDIS entityID; // uint8_t forceID; // uint8_t numberOfArticulationParameters; // EntityType entityType; // EntityType alternativeType; // VectorDIS entityLinearVelocity; // WorldCoordinates entityLocation; // EulerAngles entityOrientation; // uint32_t appearance; // uint8_t deadReckoningAlgorithm; // uint8_t otherParameters[15]; // VectorDIS DRentityLinearAcceleration; // AngularVelocityVectorDIS DRentityAngularVelocity; // EntityMarking entityMarking; // uint32_t capabilities; // ========================================================= // // --- // Standard header (PDUHeader) // --- pdu->header.protocolVersion = disIO->getVersion(); pdu->header.exerciseIdentifier = disIO->getExerciseID(); pdu->header.PDUType = NetIO::PDU_ENTITY_STATE; pdu->header.protocolFamily = NetIO::PDU_FAMILY_ENTITY_INFO; // if (disIO->getTimeline() == Simulation::NetIO::UTC) pdu->header.timeStamp = disIO->makeTimeStamp( getTimeUtc(), true ); else pdu->header.timeStamp = disIO->makeTimeStamp( getTimeExec(), false ); // pdu->header.status = 0; pdu->header.padding = 0; // --- // Entity ID (EntityIdentifierID) // --- pdu->entityID.simulationID.siteIdentification = getSiteID(); pdu->entityID.simulationID.applicationIdentification = getApplicationID(); pdu->entityID.ID = getPlayerID(); // --- // Force ID: When mapping Player side to force IDs ... // --- if (getSide() == Simulation::Player::BLUE) { // blue's are friendly, ... pdu->forceID = NetIO::FRIENDLY_FORCE; } else if (getSide() == Simulation::Player::RED) { // red's are not, ... pdu->forceID = NetIO::OPPOSING_FORCE; } else if (getSide() == Simulation::Player::WHITE) { // white is neutral, ... pdu->forceID = NetIO::NEUTRAL_FORCE; } else { // and everyone else is type OTHER. pdu->forceID = NetIO::OTHER_FORCE; } // --- // Entity type (EntityType) // --- pdu->entityType.kind = getEntityKind(); pdu->entityType.domain = getEntityDomain(); pdu->entityType.country = getEntityCountry(); pdu->entityType.category = getEntityCategory(); pdu->entityType.subcategory = getEntitySubcategory(); pdu->entityType.specific = getEntitySpecific(); pdu->entityType.extra = getEntityExtra(); // --- // Alternative type (EntityType) // --- pdu->alternativeType.kind = getEntityKind(); pdu->alternativeType.domain = getEntityDomain(); pdu->alternativeType.country = getEntityCountry(); pdu->alternativeType.category = getEntityCategory(); pdu->alternativeType.subcategory = getEntitySubcategory(); pdu->alternativeType.specific = getEntitySpecific(); pdu->alternativeType.extra = getEntityExtra(); // --- // Player position and orientation state data data // 1) All data is geocentric (ECEF) // 2) The playerState2Nib() function, which was called above, captures // the state data and passed the state data to the dead reckoning // system, and we're using this DR captured data. // --- { // --- // Entity linear velocity (VectorDIS) // --- osg::Vec3d geocVel = getDrVelocity(); pdu->entityLinearVelocity.component[0] = static_cast<float>(geocVel[0]); pdu->entityLinearVelocity.component[1] = static_cast<float>(geocVel[1]); pdu->entityLinearVelocity.component[2] = static_cast<float>(geocVel[2]); // --- // Entity location (WorldCoordinates) // --- osg::Vec3d geocPos = getDrPosition(); pdu->entityLocation.X_coord = geocPos[Basic::Nav::IX]; pdu->entityLocation.Y_coord = geocPos[Basic::Nav::IY]; pdu->entityLocation.Z_coord = geocPos[Basic::Nav::IZ]; // --- // Entity orientation (EulerAngles) // --- osg::Vec3d geocAngles = getDrEulerAngles(); pdu->entityOrientation.phi = static_cast<float>(geocAngles[Basic::Nav::IPHI]); pdu->entityOrientation.theta = static_cast<float>(geocAngles[Basic::Nav::ITHETA]); pdu->entityOrientation.psi = static_cast<float>(geocAngles[Basic::Nav::IPSI]); } // --- // Appearance bits generic to all domains (except munitions) // --- { pdu->appearance = 0x0; // --- // Frozen? // --- if ( isFrozen() || sim->isFrozen() ) { pdu->appearance |= FROZEN_BIT; } // Deactive this entity? { if (isMode(Simulation::Player::DELETE_REQUEST) || player->isDead() ) pdu->appearance |= DEACTIVATE_BIT; } // Damage or health? (Bits 3-4) { unsigned int bits = 0; if (getDamage() > 0.9f) bits = 3; // Destroyed or Fatality else if (getDamage() > 0.5) bits = 2; // Moderate else if (getDamage() > 0.0) bits = 1; // Slight else bits = 0; // None pdu->appearance |= (bits << 3); } // Camouflage type // Note: air platform appearance bits 17 and 18 are not used, but we're using them the same as land platforms { unsigned int bits = getCamouflageType(); if (bits > 0 && bits <= 4) { pdu->appearance |= CAMOUFLAGE_BIT; // Land based camouflage bits if (player->isMajorType(Simulation::Player::GROUND_VEHICLE)) { // Subtract one to match DIS camouflage bits. // Our camouflage type for DIS is the camouflage appearance bits // plus one because our camouflage type of zero is no camouflage. bits--; pdu->appearance |= (bits << 17); } } } // Life forms appearance bits if (player->isMajorType(Simulation::Player::LIFE_FORM)) { const Simulation::LifeForm* lf = dynamic_cast<const Simulation::LifeForm*>(player); if (lf != nullptr) { // Health (aka damaged for other domains) same bits (3-4) - this is from the NIB, because it IS // updated // bits 5-8 compliance (not implemented) // bits 9 - 11 unused // bit 12 flashlight (not implemented) // bits 13-15 unused // bits 16 - 19 life form state // data is from the player, because NIB doesn't have actions associated with it { unsigned int bits = 1; // upright, standing still if (lf->getActionState() == Simulation::LifeForm::UPRIGHT_STANDING) bits = 1; // standing else if (lf->getActionState() == Simulation::LifeForm::UPRIGHT_WALKING) bits = 2; // walking else if (lf->getActionState() == Simulation::LifeForm::UPRIGHT_RUNNING) bits = 3; // running else if (lf->getActionState() == Simulation::LifeForm::KNEELING) bits = 4; // kneeling else if (lf->getActionState() == Simulation::LifeForm::PRONE) bits = 5; // prone else if (lf->getActionState() == Simulation::LifeForm::CRAWLING) bits = 6; // crawling else if (lf->getActionState() == Simulation::LifeForm::SWIMMING) bits = 7; // swimming else if (lf->getActionState() == Simulation::LifeForm::PARACHUTING) bits = 8; // parachuting else if (lf->getActionState() == Simulation::LifeForm::JUMPING) bits = 9; // jumping else if (lf->getActionState() == Simulation::LifeForm::SITTING) bits = 10; // sitting else if (lf->getActionState() == Simulation::LifeForm::SQUATTING) bits = 11; // squatting else if (lf->getActionState() == Simulation::LifeForm::CROUCHING) bits = 12; // crouching else if (lf->getActionState() == Simulation::LifeForm::WADING) bits = 13; // wading else if (lf->getActionState() == Simulation::LifeForm::SURRENDER) bits = 14; // surrender else if (lf->getActionState() == Simulation::LifeForm::DETAINED) bits = 15; // detained else bits = 1; pdu->appearance |= (bits << 16); } // bit 20 unused // bit 21 frozen status (taken care of above) // bits 24 - 25 weapon 1 (not implemented) // bits 26-27 weapon 2 (N/I) // bits 28-29 } } // Common Non-life form appearance bits else { // Smoking? (Bits 5-6) Standard (IST-CF-03-01, May 5, 2003) { unsigned int bits = 0; if (getSmoke() > 0.9f) bits = 3; else if (getSmoke() > 0.5) bits = 2; else if (getSmoke() > 0.0) bits = 1; else bits = 0; pdu->appearance |= (bits << 5); } // Flames? (Bit 15) Standard (IST-CF-03-01, May 5, 2003) { if (getFlames() > 0.5f) pdu->appearance |= FLAMES_BIT; } // Power plant status bit (just leave ON for now) pdu->appearance |= POWER_PLANT_BIT; } } // --- // Dead reckoning algorithm // --- pdu->deadReckoningAlgorithm = static_cast<unsigned char>(getDeadReckoning()); // --- // Other parameters // --- for (unsigned int i=0; i<15; i++) { pdu->otherParameters[i] = 0; } // --- // Dead reckoning information // --- { // --- // Dead reckoning linear acceleration (VectorDIS) // --- osg::Vec3d geocAcc = getDrAcceleration(); pdu->DRentityLinearAcceleration.component[0] = static_cast<float>(geocAcc[0]); pdu->DRentityLinearAcceleration.component[1] = static_cast<float>(geocAcc[1]); pdu->DRentityLinearAcceleration.component[2] = static_cast<float>(geocAcc[2]); // --- // Dead reckoning angular velocity (AngularVelocityVectorDIS) // --- osg::Vec3d geocAngVel = getDrAngularVelocities(); pdu->DRentityAngularVelocity.x_axis = static_cast<float>(geocAngVel[Basic::Nav::IX]); pdu->DRentityAngularVelocity.y_axis = static_cast<float>(geocAngVel[Basic::Nav::IY]); pdu->DRentityAngularVelocity.z_axis = static_cast<float>(geocAngVel[Basic::Nav::IZ]); } // --- // Entity marking (EntityMarking) // --- { const char* const pName = getPlayerName(); size_t nameLen = std::strlen(pName); for (unsigned int i = 0; i < EntityMarking::BUFF_SIZE; i++) { if (i < nameLen) { pdu->entityMarking.marking[i] = pName[i]; } else { pdu->entityMarking.marking[i] = '\0'; } } pdu->entityMarking.characterSet = 1; } // --- // Capabilities // --- pdu->capabilites = 0x0; // --- // Articulation parameters // --- pdu->numberOfArticulationParameters = manageArticulationParameters(pdu); // Size of the PDU package unsigned short length = sizeof(EntityStatePDU) + (pdu->numberOfArticulationParameters * sizeof(VpArticulatedPart)); pdu->header.length = length; if (Basic::NetHandler::isNotNetworkByteOrder()) pdu->swapBytes(); ok = disIO->sendData( reinterpret_cast<char*>(pdu), length ); } return ok; }
//------------------------------------------------------------------------------ // isPlayerStateUpdateRequired() -- check to see if an update is required //------------------------------------------------------------------------------ bool Nib::isPlayerStateUpdateRequired(const double curExecTime) { enum { NO, YES, UNSURE } result = UNSURE; // --- // 1) Make sure that we have a valid player and entity type // --- const models::Player* player = getPlayer(); if (player == nullptr || isEntityTypeInvalid()) result = NO; // --- // 2) Mode changes // --- if ( (result == UNSURE) && isNotMode( player->getMode()) ) result = YES; // 2-a) NIB is being deleted, send one more update to deactivate the entity if ( (result == UNSURE) && isMode( models::Player::DELETE_REQUEST ) ) result = YES; // --- // 3) When we're a local player, check for one of the following ... // --- if ( (result == UNSURE) && player->isLocalPlayer()) { //double drTime = curExecTime - getTimeExec(); models::SynchronizedState playerState = player->getSynchronizedState(); const double drTime = static_cast<double>(playerState.getTimeExec()) - getTimeExec(); // 3-a) Freeze flag has changed if ( (player->isFrozen() && isNotFrozen()) || (!player->isFrozen() && isFrozen()) ) { result = YES; } // 3-b) Max DR timeout if (result == UNSURE) { if ( drTime >= getNetIO()->getMaxTimeDR(this) ) { result = YES; } } // 3-c) Appearance has changed if (result == UNSURE && (player->getDamage() != getDamage() || player->getSmoke() != getSmoke() || player->getFlames() != getFlames() || player->getCamouflageType() != getCamouflageType() ) ) { result = YES; } // 3-d) Check dead reckoning errors if (result == UNSURE && isNotFrozen()) { // Compute our dead reckoned position and angles, which are // based on our last packet sent. base::Vec3d drPos; base::Vec3d drAngles; mainDeadReckoning(drTime, &drPos, &drAngles); // 3-d-1) Position error if (!player->isPositionFrozen() && !player->isAltitudeFrozen()) { // max position error (meters) const double maxPosErr = getNetIO()->getMaxPositionErr(this); const double maxPosErr2 = maxPosErr*maxPosErr; // squared // Check if the length of the position error (squared) is greater // than the max error (squared) //base::Vec3d ppos = player->getGeocPosition(); const base::Vec3d ppos = playerState.getGeocPosition(); const base::Vec3d errPos = drPos - ppos; if (errPos.length2() >= maxPosErr2) { result = YES; } } // 3-d-2) Orientation error if (result == UNSURE && !player->isAttitudeFrozen()) { // max angle error (radians) const double maxAngleErr = getNetIO()->getMaxOrientationErr(this); // Compute angular error //base::Vec3 errAngles = drAngles - player->getGeocEulerAngles(); base::Vec3d errAngles = drAngles - playerState.getGeocEulerAngles(); // Check if any angle error is greater than the max error errAngles[0] = std::fabs( base::angle::aepcdDeg(errAngles[0]) ); if (errAngles[0] >= maxAngleErr) result = YES; errAngles[1] = std::fabs( base::angle::aepcdDeg(errAngles[1]) ); if (errAngles[1] >= maxAngleErr) result = YES; errAngles[2] = std::fabs( base::angle::aepcdDeg(errAngles[2]) ); if (errAngles[2] >= maxAngleErr) result = YES; } } } // --- // 4) Check for air vehicle articulated and attached parts (always check this) // --- if ( player != nullptr && player->isMajorType(models::Player::AIR_VEHICLE) ) { const models::AirVehicle* av = static_cast<const models::AirVehicle*>(player); // (4-a) Check wing sweep angle. We only send out wing sweep as // an part if the position is greater than zero or if we've previously been // sending the wing sweep (count > 0). { const double angle = av->getWingSweepAngle(); // radians if (angle > 0 || apartWingSweepCnt > 0) { // Check if the angle has changed. if (angle != apartWingSweep) { apartWingSweep = angle; apartWingSweepCnt++; result = YES; } } } // (4-b) Check landing gear position. We only send out gear position as // an part if the gear is not up (pos != 0) or if we've previously been // sending the gear position (count > 0). { const double pos = av->getLandingGearPosition(); // (0% up; 100% down) if (pos > 0 || apartGearPosCnt > 0) { // Check if the pos has changed. if (pos != apartLandingGear) { apartLandingGear = pos; apartGearPosCnt++; result = YES; } } } // (4-c) Check bay door position. We only send out bay door posiiton as // an part if the door is not closed (pos != 0) or if we've previously been // sending the door position (count > 0). { const double pos = av->getWeaponBayDoorPosition(); // % (0% closed; 100% open) if (pos > 0 || apartBayDoorCnt > 0) { // Check if the pos has changed. if (pos != apartBayDoor) { apartBayDoor = pos; apartBayDoorCnt++; result = YES; } } } } // --- // 5) Check for ground vehicle articulated and attached parts (always check this) // --- if ( player != nullptr && player->isMajorType(models::Player::GROUND_VEHICLE) ) { const models::GroundVehicle* gv = static_cast<const models::GroundVehicle*>(player); // (5-a) Send launcher elevation angle and for an attached missile // (on SamVehicles and Artillery only) if ( gv->isClassType(typeid(models::SamVehicle)) || gv->isClassType(typeid(models::Artillery)) ) { const double angle = gv->getLauncherPosition(); // (radians) // First pass -- if (apartLnchrElevCnt == 0) { // find all missiles missiles const models::StoresMgr* sm = gv->getStoresManagement(); if (sm != nullptr) { const base::PairStream* stores = sm->getStores(); if (stores != nullptr) { const base::List::Item* item = stores->getFirstItem(); while (item != nullptr && apartNumMissiles < MAX_AMSL) { const auto pair = static_cast<const base::Pair*>(item->getValue()); if (pair != nullptr) { const auto msl = dynamic_cast<const models::Missile*>( pair->object() ); if (msl != nullptr) { // Save the pointer to the missile, set the missile's change count to 1, // and up the missile count msl->ref(); apartMsl[apartNumMissiles] = msl; apartMslAttached[apartNumMissiles] = !(msl->isMode(models::Player::LAUNCHED)); apartMslCnt[apartNumMissiles] = 1; apartNumMissiles++; } } item = item->getNext(); } stores->unref(); stores = nullptr; } } // If we have missile then set the launcher angle if (apartNumMissiles > 0) { apartLnchrElev = angle; apartLnchrElevCnt++; } } // If we have the launcher angle and missiles then check for changes if (apartLnchrElevCnt != 0) { // Check if the pos has changed if (angle != apartLnchrElev) { apartLnchrElev = angle; apartLnchrElevCnt++; result = YES; } // Check all missiles for change in launched status for (unsigned int i = 0; i < apartNumMissiles; i++) { bool attached = !(apartMsl[i]->isMode(models::Player::LAUNCHED)); if (attached != apartMslAttached[i]) { // There's been a change in status apartMslAttached[i] = attached; apartMslCnt[i]++; } } } } } // --- // 6) When we're a network player -- Update when the exec time of the // last input (player's NIB) is different that our exec time. // --- if ( (result == UNSURE) && player->isNetworkedPlayer() ) { const auto playerNib = dynamic_cast<const Nib*>(player->getNib()); if (playerNib->getTimeExec() != getTimeExec()) { result = YES; } } return (result == YES); }