// Weapon Update void Weapon::Update(float aStep) { // get controller const Controller *controller = Database::controller.Get(mControlId); if (!controller) return; // advance fire timer mTimer += aStep; // get template data const WeaponTemplate &weapon = Database::weapontemplate.Get(mId); // get trigger value float fire = controller->mFire[mChannel]; bool trigger; switch (weapon.mTrigger) { default: case WeaponTemplate::TRIGGER_HOLD: trigger = fire != 0; break; case WeaponTemplate::TRIGGER_PRESS: trigger = fire != 0 && mPrevFire == 0; break; case WeaponTemplate::TRIGGER_RELEASE: trigger = fire == 0 && mPrevFire != 0; break; } mPrevFire = fire; // if triggered... if (trigger) { // if not busy if (mBurst <= 0 && mTimer > -0.001f && (!weapon.mTrack || mTrack < weapon.mTrack)) { // if firing on this phase... if (mPhase == 0) { Resource *resource = NULL; // if using ammo if (weapon.mCost) { // ammo resource (if any) resource = Database::resource.Get(mAmmo).Get(weapon.mType); } // if enough ammo... if (!resource || weapon.mCost <= resource->GetValue()) { // deduct ammo if (resource) resource->Add(mId, -weapon.mCost); // start a new burst mTimer -= weapon.mBurstStart; mBurst = weapon.mBurstLength; } else { // start "empty" sound cue PlaySoundCue(mId, 0x18a7beee /* "empty" */); } // wrap around mPhase = weapon.mCycle - 1; } else { // advance phase --mPhase; // wait for next phase mTimer -= weapon.mDelay / weapon.mCycle; } } } // if ready to fire... while (mBurst > 0 && mTimer > -0.001f && (!weapon.mTrack || mTrack < weapon.mTrack)) { // deduct a burst --mBurst; // get the entity Entity *entity = Database::entity.Get(mId); // start the "fire" sound cue PlaySoundCue(mId, 0x8eab16d9 /* "fire" */); // interpolated transform Transform2 basetransform(entity->GetInterpolatedTransform(mTimer / aStep)); for (int salvo = 0; salvo < weapon.mSalvoShots; ++salvo) { // get local position Transform2 position(weapon.mOffset); // apply transform offset Transform2 transform(position * basetransform); if (weapon.mRecoil) { // apply recoil force for (unsigned int id = mId; id != 0; id = Database::backlink.Get(id)) { if (Collidable *collidable = Database::collidable.Get(id)) { collidable->GetBody()->ApplyImpulse(transform.Rotate(Vector2(0, -weapon.mRecoil)), transform.p); break; } } } if (weapon.mFlash) { // instantiate a flash unsigned int flashId = Database::Instantiate(weapon.mFlash, Database::owner.Get(mId), mId, transform.Angle(), transform.p, entity->GetVelocity(), entity->GetOmega()); // set fractional turn if (Renderable *renderable = Database::renderable.Get(flashId)) renderable->SetFraction(mTimer / aStep); // link it (HACK) LinkTemplate linktemplate; linktemplate.mOffset = weapon.mOffset; linktemplate.mSub = flashId; linktemplate.mSecondary = flashId; Link *link = new Link(linktemplate, mId); Database::Typed<Link *> &links = Database::link.Open(mId); links.Put(flashId, link); Database::link.Close(mId); link->Activate(); } if (weapon.mOrdnance) { // TO DO: consolidate this with similar spawn patterns (Graze, Spawner) // apply position scatter position.a += Random::Value(0.0f, weapon.mScatter.a); position.p.x += Random::Value(0.0f, weapon.mScatter.p.x); position.p.y += Random::Value(0.0f, weapon.mScatter.p.y); // get world position position *= basetransform; // get local velocity Transform2 velocity(entity->GetOmega(), position.Unrotate(entity->GetVelocity())); // apply velocity inherit velocity.a *= weapon.mInherit.a; velocity.p.x *= weapon.mInherit.p.x; velocity.p.y *= weapon.mInherit.p.y; // apply velocity add velocity.a += weapon.mVelocity.a; velocity.p.x += weapon.mVelocity.p.x; velocity.p.y += weapon.mVelocity.p.y; // apply velocity variance velocity.a += Random::Value(0.0f, weapon.mVariance.a); velocity.p.x += Random::Value(0.0f, weapon.mVariance.p.x); velocity.p.y += Random::Value(0.0f, weapon.mVariance.p.y); // apply velocity aim velocity.p.x += controller->mAim.x * weapon.mAim.x; velocity.p.y += controller->mAim.y * weapon.mAim.y; // get world velocity velocity.p = position.Rotate(velocity.p); // instantiate a bullet unsigned int ordId = Database::Instantiate(weapon.mOrdnance, Database::owner.Get(mId), mId, position.a, position.p, velocity.p, velocity.a); #ifdef DEBUG_WEAPON_CREATE_ORDNANCE DebugPrint("ordnance=\"%s\" owner=\"%s\"\n", Database::name.Get(ordId).c_str(), Database::name.Get(Database::owner.Get(ordId)).c_str()); #endif // set fractional turn if (Renderable *renderable = Database::renderable.Get(ordId)) renderable->SetFraction(mTimer / aStep); // if tracking.... if (weapon.mTrack) { // add a tracker Database::weapontracker.Put(ordId, WeaponTracker(mId)); } } } // update weapon delay if (mBurst > 0) mTimer -= weapon.mBurstDelay; else mTimer -= (weapon.mDelay - weapon.mBurstStart - weapon.mBurstDelay * (weapon.mBurstLength - 1)) / weapon.mCycle; } if (mTimer > 0.0f) { // clamp fire delay mTimer = 0.0f; } }
// spawner update void Spawner::Update(float aStep) { // get the spawner template const SpawnerTemplate &spawner = Database::spawnertemplate.Get(mId); // skip if limit reached if (spawner.mTrack && mTrack >= spawner.mTrack) return; // advance the timer mTimer += aStep; // if the timer elapses... while (mTimer > 0.0f) { // get the spawner entity Entity *entity = Database::entity.Get(mId); if (!entity) return; // TO DO: consolidate this with similar spawn patterns (Graze, Weapon) // interpolated transform Transform2 transform(entity->GetInterpolatedTransform(mTimer / aStep)); // apply transform offset transform = spawner.mOffset * transform; // apply transform scatter if (spawner.mScatter.a) transform.a += Random::Value(0.0f, spawner.mScatter.a); if (spawner.mScatter.p.x) transform.p.x += Random::Value(0.0f, spawner.mScatter.p.x); if (spawner.mScatter.p.y) transform.p.y += Random::Value(0.0f, spawner.mScatter.p.y); // get local velocity Transform2 velocity(entity->GetOmega(), transform.Unrotate(entity->GetVelocity())); // apply velocity inherit velocity.a *= spawner.mInherit.a; velocity.p.x *= spawner.mInherit.p.x; velocity.p.y *= spawner.mInherit.p.y; // apply velocity add velocity.a += spawner.mVelocity.a; velocity.p.x += spawner.mVelocity.p.x; velocity.p.y += spawner.mVelocity.p.y; // apply velocity variance if (spawner.mVariance.a) velocity.a += Random::Value(0.0f, spawner.mVariance.a); if (spawner.mVariance.p.x) velocity.p.x += Random::Value(0.0f, spawner.mVariance.p.x); if (spawner.mVariance.p.y) velocity.p.y += Random::Value(0.0f, spawner.mVariance.p.y); // get world velocity velocity.p = transform.Rotate(velocity.p); // apply fractional turn (HACK) transform.a += velocity.a * (aStep - mTimer); transform.p += velocity.p * (aStep - mTimer); // instantiate the spawn entity if (unsigned int spawnId = Database::Instantiate(spawner.mSpawn, Database::owner.Get(mId), mId, transform.a, transform.p, velocity.p, velocity.a, false)) { // if the spawner has a team... unsigned int team = Database::team.Get(mId); if (team) { // propagate team to spawned item Database::team.Put(spawnId, team); } // activate Database::Activate(spawnId); // set fractional turn if (Renderable *renderable = Database::renderable.Get(spawnId)) renderable->SetFraction(mTimer / aStep); // if tracking.... if (spawner.mTrack) { // add a tracker Database::spawnertracker.Put(spawnId, SpawnerTracker(mId)); } } // set the timer mTimer -= spawner.mCycle; // if tracking.... if (spawner.mTrack) { // stop if out of slots if (mTrack >= spawner.mTrack) break; } } }