{
SuperClass* pSource = NULL;
if(HouseExt::ExtData *pExt = HouseExt::ExtMap.Find(pThis->Owner)) {
if(pThis->Owner->Supers.ValidIndex(pExt->SWLastIndex)) {
pSource = pThis->Owner->Supers.GetItem(pExt->SWLastIndex);
}
}
if(pSource && (pSource->Type->Type == SuperWeaponType::ChronoSphere)) {
if(SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pSource->Type)) {
Debug::Log("[ChronoWarp::Launch] Launching %s with %s as source.\n", pThis->Type->ID, pSource->Type->ID);
if(pData->SW_RadarEvent.Get()) {
RadarEventClass::Create(RADAREVENT_SUPERWEAPONLAUNCHED, pSource->ChronoMapCoords);
RadarEventClass::Create(RADAREVENT_SUPERWEAPONLAUNCHED, *pCoords);
}
CellClass *pCellSource = MapClass::Instance->GetCellAt(&pSource->ChronoMapCoords);
CellClass *pCellTarget = MapClass::Instance->GetCellAt(pCoords);
CoordStruct coordsSource;
pCellSource->GetCoordsWithBridge(&coordsSource);
coordsSource.Z += pData->SW_AnimHeight;
CoordStruct coordsTarget;
pCellTarget->GetCoordsWithBridge(&coordsTarget);
coordsTarget.Z += pData->SW_AnimHeight;
SWTypeExt::ClearChronoAnim(pThis);
AnimClass *pAnim = NULL;
if(pData->Chronosphere_BlastSrc.Get()) {
GAME_ALLOC(AnimClass, pAnim, pData->Chronosphere_BlastSrc.Get(), &coordsSource);
}
if(pData->Chronosphere_BlastDest.Get()) {
GAME_ALLOC(AnimClass, pAnim, pData->Chronosphere_BlastDest.Get(), &coordsTarget);
}
DynamicVectorClass<ChronoWarpStateMachine::ChronoWarpContainer> RegisteredBuildings;
auto Chronoport = [&](ObjectClass* pObj) -> bool {
TechnoClass *pTechno = generic_cast<TechnoClass*>(pObj);
if(!pTechno) {
return true;
}
if(!pData->IsHouseAffected(pThis->Owner, pTechno->Owner)) {
return true;
}
if(!pData->IsTechnoAffected(pTechno)) {
return true;
}
TechnoTypeClass *pType = pTechno->GetTechnoType();
TechnoTypeExt::ExtData *pExt = TechnoTypeExt::ExtMap.Find(pType);
if(!pExt->Chronoshift_Allow) {
return true;
}
bool IsVehicle = false;
if(BuildingClass* pBld = specific_cast<BuildingClass*>(pObj)) {
if(pBld->Type->BridgeRepairHut) {
return true;
}
if(pData->Chronosphere_ReconsiderBuildings.Get()) {
IsVehicle = pExt->Chronoshift_IsVehicle.Get();
}
if(!pData->Chronosphere_AffectUndeployable || !pBld->Type->UndeploysInto) {
if(!IsVehicle && !pData->Chronosphere_AffectBuildings) {
return true;
}
if(IsVehicle && !(pData->SW_AffectsTarget & SuperWeaponTarget::Unit)) {
return true;
}
} else {
IsVehicle = true;
}
}
if(pTechno->IsImmobilized || pTechno->IsInAir()
|| pTechno->IsBeingWarpedOut() || pTechno->IsWarpingIn()) {
return true;
}
if(!pType->Warpable && !pData->Chronosphere_AffectUnwarpable.Get()) {
return true;
}
if(pTechno->IsIronCurtained() && !pData->Chronosphere_AffectIronCurtain.Get()) {
return true;
}
if(pTechno->WhatAmI() == abs_Unit) {
TechnoClass* pLink = pTechno->GetNthLink(0);
if(pLink) {
if(BuildingClass* pLinkBld = specific_cast<BuildingClass*>(pLink)) {
if(pLinkBld->Type->WeaponsFactory) {
if(MapClass::Instance->GetCellAt(&pTechno->Location)->GetBuilding() == pLinkBld) {
return true;
}
}
}
}
}
if(pType->Organic && pData->Chronosphere_KillOrganic.Get()) {
if(!pType->Teleporter || pData->Chronosphere_KillTeleporters.Get()) {
pTechno->ReceiveDamage(&pType->Strength, 0,
RulesClass::Instance->C4Warhead, NULL, true, false, pSource->Owner);
return true;
}
}
if(FootClass *pFoot = generic_cast<FootClass*>(pObj)) {
if(FootClass *pSquid = pFoot->ParasiteEatingMe) {
if(pType->Naval) {
if(ParasiteClass *pSquidParasite = pSquid->ParasiteImUsing) {
pSquidParasite->SuppressionTimer.Start(500);
pSquidParasite->ExitUnit();
}
}
}
}
if(pTechno->BunkerLinkedItem) {
if(BuildingClass *pBunkerLink = specific_cast<BuildingClass*>(pTechno->BunkerLinkedItem)) {
pBunkerLink->ClearBunker();
} else if(BuildingClass *pBunkerLink = specific_cast<BuildingClass*>(pTechno)) {
pBunkerLink->UnloadBunker();
pBunkerLink->EmptyBunker();
}
}
if(BuildingClass* pBld = specific_cast<BuildingClass*>(pObj)) {
pBld->SendToEachLink(rc_0D);
pBld->SendToEachLink(rc_Exit);
if(pBld->LightSource) {
pBld->LightSource->Deactivate();
GAME_DEALLOC(pBld->LightSource);
pBld->LightSource = NULL;
}
if(pBld->Type->CloakGenerator && pBld->CloakRadius) {
pBld->HasCloakingData = -1;
pBld->IsSensed = true;
pBld->CloakRadius = 1;
pBld->UpdateTimers();
}
}
CoordStruct coordsUnitSource;
pTechno->GetCoords(&coordsUnitSource);
CoordStruct coordsUnitTarget = coordsUnitSource;
CellStruct cellUnitTarget = pTechno->GetCell()->MapCoords - pSource->ChronoMapCoords + *pCoords;
CellClass* pCellUnitTarget = MapClass::Instance->GetCellAt(&cellUnitTarget);
coordsUnitTarget.X = coordsUnitSource.X + (pCoords->X - pSource->ChronoMapCoords.X) * 256;
coordsUnitTarget.Y = coordsUnitSource.Y + (pCoords->Y - pSource->ChronoMapCoords.Y) * 256;
pCellUnitTarget->FixHeight(&coordsUnitTarget);
if(FootClass *pFoot = generic_cast<FootClass*>(pObj)) {
pFoot->Locomotor->Mark_All_Occupation_Bits(0);
pFoot->Locomotor->Force_Track(-1, coordsUnitSource);
pFoot->MarkAllOccupationBits(&coordsUnitSource);
pFoot->FrozenStill = true;
LocomotionClass::ChangeLocomotorTo(pFoot, &LocomotionClass::CLSIDs::Teleport);
pFoot->IsImmobilized = true;
pFoot->ChronoDestCoords = coordsUnitTarget;
pFoot->SendToEachLink(rc_Exit);
pFoot->ChronoWarpedByHouse = pThis->Owner;
pFoot->SetDestination(pCellUnitTarget, true);
} else if (BuildingClass *pBld = generic_cast<BuildingClass*>(pObj)) {
pBld->BecomeUntargetable();
for(int i = 0; i<BulletClass::Array->Count; ++i) {
BulletClass* pBullet = BulletClass::Array->GetItem(i);
if(pBullet->Target == pBld) {
pBullet->LoseTarget();
}
}
pBld->BeingWarpedOut = true;
pBld->Owner->ShouldRecheckTechTree = true;
pBld->Owner->PowerBlackout = true;
pBld->DisableTemporal();
pBld->SetLayer(Layer::Ground);
BuildingExt::ExtData* pBldExt = BuildingExt::ExtMap.Find(pBld);
pBldExt->AboutToChronoshift = true;
ChronoWarpStateMachine::ChronoWarpContainer Container(pBld, cellUnitTarget, pBld->Location, IsVehicle);
RegisteredBuildings.AddItem(Container);
}
return true;
};
if(Helpers::Alex::DistinctCollector<ObjectClass*> *items = new Helpers::Alex::DistinctCollector<ObjectClass*>()) {
Helpers::Alex::forEachObjectInRange(&pSource->ChronoMapCoords, pData->SW_WidthOrRange, pData->SW_Height, items->getCollector());
items->forEach(Chronoport);
if(RegisteredBuildings.Count) {
this->newStateMachine(RulesClass::Instance->ChronoDelay + 1, *pCoords, pSource, this, &RegisteredBuildings);
}
delete items;
}
return true;
}
} else {
Debug::Log("ChronoWarp typed super weapon triggered as standalone. Use ChronoSphere instead.\n");
}
return false;
}