void Pickup::Kill(float aFraction) { const PickupTemplate &pickup = Database::pickuptemplate.Get(mId); // if spawning on pickup... if (pickup.mSpawnOnCollect) { // get the entity Entity *entity = Database::entity.Get(mId); if (entity) { // spawn template at entity location unsigned int spawnId = Database::Instantiate(pickup.mSpawnOnCollect, Database::owner.Get(mId), mId, entity->GetAngle(), entity->GetPosition(), entity->GetVelocity(), entity->GetOmega()); if (Renderable *renderable = Database::renderable.Get(spawnId)) renderable->SetFraction(aFraction); } } // if switching on pickup... if (pickup.mSwitchOnCollect) { // change dynamic type unsigned int aId = mId; Database::Switch(aId, pickup.mSwitchOnCollect); if (Renderable *renderable = Database::renderable.Get(aId)) renderable->SetFraction(aFraction); } else { // delete the entity Database::Delete(mId); } return; }
// 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; } }
// Gunner Update void Gunner::Update(float aStep) { // get the owner unsigned int aOwnerId = Database::backlink.Get(mId); // get the owner entity Entity *owner = Database::entity.Get(aOwnerId); // if the owner does not exist... if (!owner) { // self-destruct Database::Delete(mId); return; } // gunner template const GunnerTemplate &gunner = Database::gunnertemplate.Get(mId); // get owner movement const Vector2 &posP = owner->GetPosition(); #ifdef GUNNER_TRACK_DEQUE const Vector2 &posL0 = mTrackPos.back(); #else const Vector2 &posL0 = mTrackPos[mTrackLast]; #endif float movement = posP.DistSq(posL0); // if the owner has moved... if (movement > FLT_EPSILON) { #ifdef GUNNER_TRACK_DEQUE // get the last segment const Vector2 &posL1 = mTrackPos[mTrackPos.size()-2]; float lastsegment = posL0.Dist(posL1); // if the last segment isn't long enough... if (lastsegment < GUNNER_TRACK_GRANULARITY) { // replace the last segment mTrackPos.pop_back(); mTrackLength -= lastsegment; } // add new position mTrackPos.push_back(posP); mTrackLength += posP.Dist(mTrackPos[mTrackPos.size()-2]); #else // get the last segment size_t mTrackPrev = (mTrackLast > 0) ? (mTrackLast - 1) : (mTrackCount - 1); const Vector2 &posL1 = mTrackPos[mTrackPrev]; float lastsegment = posL0.Dist(posL1); // if the last segment is long enough... if (lastsegment >= GUNNER_TRACK_GRANULARITY) { // start a new segment mTrackPrev = mTrackLast; mTrackLast = (mTrackLast < mTrackCount - 1) ? (mTrackLast + 1) : 0; } else { // replace the last segment mTrackLength -= lastsegment; } // add new position mTrackPos[mTrackLast] = posP; mTrackLength += posP.Dist(mTrackPos[mTrackPrev]); #endif // while there is excess track length... while (mTrackLength > gunner.mFollowLength) { // get the excess length float excess = mTrackLength - gunner.mFollowLength; // get the first segment length #ifdef GUNNER_TRACK_DEQUE Vector2 &pos0 = mTrackPos[0]; const Vector2 &pos1 = mTrackPos[1]; #else size_t mTrackNext = (mTrackFirst < mTrackCount - 1) ? (mTrackFirst + 1) : 0; Vector2 &pos0 = mTrackPos[mTrackFirst]; const Vector2 &pos1 = mTrackPos[mTrackNext]; #endif float firstsegment = pos0.Dist(pos1); // if the segment is longer than the excess... if (firstsegment > excess) { // shorten the segment pos0 += excess / firstsegment * (pos1 - pos0); mTrackLength -= excess; break; } else { // remove the segment mTrackLength -= firstsegment; #ifdef GUNNER_TRACK_DEQUE mTrackPos.pop_front(); #else mTrackFirst = mTrackNext; #endif } } } // move to new position Entity *entity = Database::entity.Get(mId); entity->Step(); #ifdef GUNNER_TRACK_DEQUE entity->SetPosition(mTrackPos.front()); #else entity->SetPosition(mTrackPos[mTrackFirst]); #endif entity->SetAngle(owner->GetAngle()); entity->SetVelocity(owner->GetVelocity()); // <-- HACK! entity->SetOmega(owner->GetOmega()); }
// cancel void Cancelable::Cancel(unsigned int aId, unsigned int aSourceId) { const CancelableTemplate &cancelable = Database::cancelabletemplate.Get(mId); // set owner to source damage owner unsigned int aOwnerId = Database::owner.Get(aSourceId); Database::owner.Put(mId, aOwnerId); // bump the hit combo counter int &combo = Database::hitcombo.Open(mId); combo = std::max<int>(combo, Database::hitcombo.Get(aSourceId) + 1); Database::hitcombo.Close(mId); if (cancelable.mBacklash) { for (unsigned int creator = Database::creator.Get(aId); creator != 0; creator = Database::backlink.Get(creator)) { if (Damagable *damagable = Database::damagable.Get(creator)) { Damagable::DeathSignal &signal = Database::deathsignal.Open(creator); signal.Disconnect(this, &Cancelable::CreatorDeath); Database::deathsignal.Close(creator); // damagable->Damage(mId, cancelable.mBacklash); // burn tether from the cancelable to the creator new TetherBurn(creator, mId, aOwnerId, cancelable.mBacklash, combo); break; } } } // if spawning on cancelable... if (cancelable.mSpawn) { // get the entity Entity *entity = Database::entity.Get(mId); if (entity) { // spawn template at the entity location Database::Instantiate(cancelable.mSpawn, Database::owner.Get(mId), mId, entity->GetAngle(), entity->GetPosition(), entity->GetVelocity(), entity->GetOmega()); } } // if switching on cancelable... if (cancelable.mSwitch) { // get the entity Entity *entity = Database::entity.Get(mId); if (entity) { // change dynamic type Database::Switch(mId, cancelable.mSwitch); } } else { // delete the entity Database::Delete(mId); } }
// 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; } } }
void Capturable::Capture(void) { const CapturableTemplate &capturable = Database::capturabletemplate.Get(mId); // if spawning on capture... if (capturable.mSpawnOnCapture) { // get the entity Entity *entity = Database::entity.Get(mId); if (entity) { // instantiate the template Database::Instantiate(capturable.mSpawnOnCapture, Database::owner.Get(mId), mId, entity->GetAngle(), entity->GetPosition(), entity->GetVelocity(), entity->GetOmega()); } } // if switching on capture... if (capturable.mSwitchOnCapture) { // change dynamic type Database::Switch(mId, capturable.mSwitchOnCapture); } else { // delete the entity Database::Delete(mId); } }