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 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); }