void CGameHelper::Update() { std::list<WaitingDamage*>* wd = &waitingDamages[gs->frameNum & 127]; while (!wd->empty()) { WaitingDamage* w = wd->back(); wd->pop_back(); CUnit* attackee = unitHandler->units[w->target]; CUnit* attacker = (w->attacker == -1)? NULL: unitHandler->units[w->attacker]; if (attackee != NULL) attackee->DoDamage(w->damage, w->impulse, attacker, w->weaponID, w->projectileID); delete w; } }
void CTransportUnit::KillUnit(bool selfDestruct, bool reclaimed, CUnit* attacker, bool) { std::list<TransportedUnit>::iterator ti; for (ti = transported.begin(); ti != transported.end(); ++ti) { CUnit* u = ti->unit; u->transporter = 0; u->DeleteDeathDependence(this); // prevent a position teleport on the next movetype update if // the transport died in a place that the unit being carried // could not get to on its own if (!u->pos.IsInBounds()) { u->KillUnit(false, false, 0x0, false); continue; } else { const float gh = ground->GetHeight2(u->pos.x, u->pos.z); if (gh < -u->unitDef->maxWaterDepth || gh > -u->unitDef->minWaterDepth) { // note: should also check movedef restraints? u->KillUnit(false, false, 0x0, false); continue; } } if (!unitDef->releaseHeld) { if (!selfDestruct) { // we don't want it to leave a corpse u->DoDamage(DamageArray() * 1000000, 0, ZeroVector); } u->KillUnit(selfDestruct, reclaimed, attacker); } else { u->stunned = (u->paralyzeDamage > u->health); if (CGroundMoveType* mt = dynamic_cast<CGroundMoveType*>(u->moveType)) { mt->StartFlying(); } u->speed = speed; eventHandler.UnitUnloaded(u, this); } } CUnit::KillUnit(selfDestruct, reclaimed, attacker); }
void CRifle::FireImpl() { float3 dir = (targetPos - weaponMuzzlePos).Normalize(); dir += ((gs->randVector() * sprayAngle + salvoError) * (1.0f - owner->limExperience * weaponDef->ownerExpAccWeight)); dir.Normalize(); CUnit* hitUnit; CFeature* hitFeature; float length = TraceRay::TraceRay(weaponMuzzlePos, dir, range, 0, owner, hitUnit, hitFeature); if (hitUnit) { hitUnit->DoDamage(weaponDef->damages, owner, ZeroVector, weaponDef->id); new CHeatCloudProjectile(weaponMuzzlePos + dir*length, hitUnit->speed*0.9f, 30, 1, owner); } new CTracerProjectile(weaponMuzzlePos, dir*projectileSpeed, length, owner); new CSmokeProjectile(weaponMuzzlePos, float3(0,0,0), 70, 0.1f, 0.02f, owner, 0.6f); }
void CRifle::Fire(void) { float3 dir=targetPos-weaponMuzzlePos; dir.Normalize(); dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f); dir.Normalize(); #ifdef TRACE_SYNC tracefile << "Rifle fire: "; tracefile << owner->pos.x << " " << dir.x << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n"; #endif CUnit* hit; float length=helper->TraceRay(weaponMuzzlePos, dir, range, weaponDef->damages[0], owner, hit, collisionFlags); if(hit) { hit->DoDamage(weaponDef->damages, owner, ZeroVector, weaponDef->id); SAFE_NEW CHeatCloudProjectile(weaponMuzzlePos + dir * length, hit->speed*0.9f, 30, 1, owner); } SAFE_NEW CTracerProjectile(weaponMuzzlePos,dir*projectileSpeed,length,owner); SAFE_NEW CSmokeProjectile(weaponMuzzlePos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f); if(fireSoundId) sound->PlaySample(fireSoundId,owner,fireSoundVolume); }
void CTransportUnit::KillUnit(bool selfDestruct, bool reclaimed, CUnit* attacker, bool) { if (!isDead) { // guard against recursive invocation via // transportee->KillUnit // helper->Explosion // helper->DoExplosionDamage // unit->DoDamage // unit->KillUnit // in the case that unit == this isDead = true; // ::KillUnit might be called multiple times while !deathScriptFinished, // but it makes no sense to kill/detach our transportees more than once std::list<TransportedUnit>::iterator ti; for (ti = transportedUnits.begin(); ti != transportedUnits.end(); ++ti) { CUnit* transportee = ti->unit; assert(transportee != this); if (transportee->isDead) continue; const float gh = ground->GetHeightReal(transportee->pos.x, transportee->pos.z); transportee->transporter = NULL; transportee->DeleteDeathDependence(this, DEPENDENCE_TRANSPORTER); // prevent a position teleport on the next movetype update if // the transport died in a place that the unit being carried // could not get to on its own if (!transportee->pos.IsInBounds()) { transportee->KillUnit(false, false, NULL, false); continue; } else { // immobile units can still be transported // via script trickery, guard against this if (!transportee->unitDef->IsAllowedTerrainHeight(gh)) { transportee->KillUnit(false, false, NULL, false); continue; } } if (!unitDef->releaseHeld) { if (!selfDestruct) { // we don't want it to leave a corpse transportee->DoDamage(DamageArray(1e6f), ZeroVector, NULL, -DAMAGE_EXTSOURCE_KILLED); } transportee->KillUnit(selfDestruct, reclaimed, attacker); } else { // place unit near the place of death of the transport // if it's a ground transport and uses a piece-in-ground method // to hide units if (transportee->pos.y < gh) { const float k = (transportee->radius + radius) * std::max(unitDef->unloadSpread, 1.0f); // try to unload in a presently unoccupied spot // unload on a wreck if suitable position not found for (int i = 0; i < 10; ++i) { float3 pos = transportee->pos; pos.x += (gs->randFloat() * 2 * k - k); pos.z += (gs->randFloat() * 2 * k - k); pos.y = ground->GetHeightReal(transportee->pos.x, transportee->pos.z); if (qf->GetUnitsExact(pos, transportee->radius + 2).empty()) { transportee->Move3D(pos, false); break; } } } else if (CGroundMoveType* mt = dynamic_cast<CGroundMoveType*>(transportee->moveType)) { mt->StartFlying(); } transportee->moveType->SlowUpdate(); transportee->moveType->LeaveTransport(); // issue a move order so that unit won't try to return to pick-up pos in IdleCheck() if (unitDef->canfly && transportee->unitDef->canmove) { Command c(CMD_MOVE); c.params.push_back(transportee->pos.x); c.params.push_back(ground->GetHeightAboveWater(transportee->pos.x, transportee->pos.z)); c.params.push_back(transportee->pos.z); transportee->commandAI->GiveCommand(c); } transportee->stunned = (transportee->paralyzeDamage > (modInfo.paralyzeOnMaxHealth? transportee->maxHealth: transportee->health)); transportee->speed = speed * (0.5f + 0.5f * gs->randFloat()); if (CBuilding* building = dynamic_cast<CBuilding*>(transportee)) { // this building may end up in a strange position, so kill it building->KillUnit(selfDestruct, reclaimed, attacker); } eventHandler.UnitUnloaded(transportee, this); } } transportedUnits.clear(); // make sure CUnit::KillUnit does not return early isDead = false; } CUnit::KillUnit(selfDestruct, reclaimed, attacker); }
void CTransportUnit::KillUnit(bool selfDestruct, bool reclaimed, CUnit* attacker, bool) { std::list<TransportedUnit>::iterator ti; for (ti = transported.begin(); ti != transported.end(); ++ti) { CUnit* u = ti->unit; const float gh = ground->GetHeight2(u->pos.x, u->pos.z); u->transporter = 0; u->DeleteDeathDependence(this); // prevent a position teleport on the next movetype update if // the transport died in a place that the unit being carried // could not get to on its own if (!u->pos.IsInBounds()) { u->KillUnit(false, false, NULL, false); continue; } else { // immobile units can still be transported // via script trickery, guard against this if (u->unitDef->movedata != NULL && gh < -u->unitDef->movedata->depth) { // always treat depth as maxWaterDepth (fails if // the transportee is a ship, but so does using // UnitDef::{min, max}WaterDepth) u->KillUnit(false, false, NULL, false); continue; } } if (!unitDef->releaseHeld) { if (!selfDestruct) { // we don't want it to leave a corpse u->DoDamage(DamageArray() * 1000000, 0, ZeroVector); } u->KillUnit(selfDestruct, reclaimed, attacker); } else { // place unit near the place of death of the transport // if it's a ground transport and uses a piece-in-ground method // to hide units if (u->pos.y < gh) { const float k = (u->radius + radius)*std::max(unitDef->unloadSpread, 1.f); // try to unload in a presently unoccupied spot // unload on a wreck if suitable position not found for (int i = 0; i<10; ++i) { float3 pos = u->pos; pos.x += gs->randFloat()*2*k - k; pos.z += gs->randFloat()*2*k - k; pos.y = ground->GetHeight2(u->pos.x, u->pos.z); if (qf->GetUnitsExact(pos, u->radius + 2).empty()) { u->pos = pos; break; } } u->UpdateMidPos(); } else if (CGroundMoveType* mt = dynamic_cast<CGroundMoveType*>(u->moveType)) { mt->StartFlying(); } u->stunned = (u->paralyzeDamage > u->health); u->moveType->LeaveTransport(); u->speed = speed*(0.5f + 0.5f*gs->randFloat()); eventHandler.UnitUnloaded(u, this); } } CUnit::KillUnit(selfDestruct, reclaimed, attacker); }