/* // Callback Clone Functions const int SQUARE_SIZE = 8; #include <algorithm> // Stolen directly from ALCallback.cpp struct SearchOffset { int dx,dy; int qdist; // dx*dx+dy*dy }; // Stolen directly from ALCallback.cpp bool SearchOffsetComparator (const SearchOffset& a, const SearchOffset& b) { return a.qdist < b.qdist; } // Stolen directly from ALCallback.cpp const vector<SearchOffset>& GetSearchOffsetTable (int radius) { static vector <SearchOffset> searchOffsets; int size = radius*radius*4; if (size > searchOffsets.size()) { searchOffsets.resize (size); for (int y=0;y<radius*2;y++) for (int x=0;x<radius*2;x++) { SearchOffset& i = searchOffsets[y*radius*2+x]; i.dx = x-radius; i.dy = y-radius; i.qdist = i.dx*i.dx+i.dy*i.dy; } sort (searchOffsets.begin(), searchOffsets.end(), SearchOffsetComparator); } return searchOffsets; } float3 cBuilderPlacement::ClosestBuildSite(const UnitDef* ud, float3 p, float sRadius, int facing) { if (!ud) return float3(-1.0f,0.0f,0.0f); int endr = (int)(sRadius/(SQUARE_SIZE*2)); const vector<SearchOffset>& ofs = GetSearchOffsetTable (endr); for(int so=0;so<endr*endr*4;so++) { float x = p.x+ofs[so].dx*SQUARE_SIZE*2; float z = p.z+ofs[so].dy*SQUARE_SIZE*2; if( cb->CanBuildAt(ud,float3(x,0,z),facing) ) { return float3(x,0,z); } } return float3(-1.0f,0.0f,0.0f); } */ bool cBuilderPlacement::FindWeaponPlacement(UnitInfo *U, float3& position) { if( U->BuildQ->creationUD->WeaponGuardRange == 0 ) return false; if( U->BuildQ->creationUD->ud->minWaterDepth < 0 && U->BuildQ->creationUD->WeaponSeaEff.BestRange > 0 ) { int iS = G->TM->GetSectorIndex(position); if( !G->TM->sector[iS].isWater ) position = G->TM->GetClosestSector(G->TM->waterSectorType,iS)->position; return true; } int BID = -1; float3 buildPosition; for(map<int,UnitInfo*>::iterator i=G->UImmobile.begin(); i!=G->UImmobile.end(); ++i ) { buildPosition = cb->GetUnitPos(i->first); if( i->second->udr->WeaponGuardRange == 0 && int(i->second->UDefences.size()) == 0 && CanBuildAt(U,position,buildPosition) && CanBeBuiltAt(U->BuildQ->creationUD,buildPosition,i->second->udr->WeaponGuardRange) ) if( BID == -1 || position.distance2D(buildPosition) < position.distance2D(cb->GetUnitPos(BID)) ) BID = i->first; } if( BID > 0 ) { position = cb->GetUnitPos(BID); return true; } return false; }
// this only verifies the existence, it does not check whether the building is currently // in a state that allows it to kick out units. however, it respects BuiltAt. bool HouseExt::FactoryForObjectExists(HouseClass *pHouse, TechnoTypeClass *pItem) { eAbstractType WhatAmI = pItem->WhatAmI(); auto pExt = TechnoTypeExt::ExtMap.Find(pItem); for(int i = 0; i < pHouse->Buildings.Count; ++i) { BuildingTypeClass *pType = pHouse->Buildings[i]->Type; if(pType->Factory == WhatAmI && pType->Naval == pItem->Naval && pExt->CanBeBuiltAt(pType)) { return true; } } return false; }
HouseExt::FactoryState HouseExt::HasFactory( HouseClass const* const pHouse, TechnoTypeClass const* const pItem, bool const requirePower) { auto const pExt = TechnoTypeExt::ExtMap.Find(pItem); auto const bitsOwners = pItem->GetOwners(); auto const isNaval = pItem->Naval; auto const abs = pItem->WhatAmI(); auto ret = FactoryState::NoFactory; for(auto const& pBld : pHouse->Buildings) { if(pBld->InLimbo || pBld->GetCurrentMission() == Mission::Selling || pBld->QueuedMission == Mission::Selling) { continue; } auto const pType = pBld->Type; if(pType->Factory != abs || (abs == AbstractType::UnitType && pType->Naval != isNaval) || !pExt->CanBeBuiltAt(pType) || !pType->InOwners(bitsOwners)) { continue; } if(!requirePower || pBld->HasPower) { return FactoryState::Available; } ret = FactoryState::Unpowered; } return ret; }
float3 cBuilderPlacement::FindBuildPosition(sBuildQuarry *BQ) { const UnitDef* bd = BQ->creationUD->ud; if( BQ->RS != 0 ) // Resource is set return cb->ClosestBuildSite(bd,BQ->RS->S->position,BQ->RS->searchRadius,BQ->RS->disApart); float3 cPosition = cb->GetUnitPos(BQ->builderID); // Construction Position if( NeedResourceSite(BQ->creationUD->ud) ) { cPosition.x = -2; cPosition.z = -1; cPosition.y = -1; return cPosition; } G->CorrectPosition(cPosition); float3 bPosition = cPosition; // Builder Position if( FindWeaponPlacement(BQ->builderUI,cPosition) ) { cPosition.x+=rand()%81-40; cPosition.z+=rand()%81-40; G->CorrectPosition(cPosition); } else if( BQ->builderUI->ud->speed == 0.0 ) { cPosition.x+=rand()%int(1.8*BQ->builderUI->ud->buildDistance)-0.9*BQ->builderUI->ud->buildDistance; cPosition.z+=rand()%int(1.8*BQ->builderUI->ud->buildDistance)-0.9*BQ->builderUI->ud->buildDistance; G->CorrectPosition(cPosition); } else { cPosition.x+=rand()%int(0.9*BQ->builderUI->ud->buildDistance)-0.45*BQ->builderUI->ud->buildDistance; cPosition.z+=rand()%int(0.9*BQ->builderUI->ud->buildDistance)-0.45*BQ->builderUI->ud->buildDistance; G->CorrectPosition(cPosition); } int iS; if( !CanBuildAt(BQ->builderUI,bPosition,cPosition) || !CanBeBuiltAt(BQ->creationUD,cPosition) ) { iS = G->TM->GetSectorIndex(cPosition); if( BQ->creationUD->mobileType != 0 ) // a factory or mobile unit { TerrainMapAreaSector *AS = G->TM->GetAlternativeSector(BQ->builderUI->area,iS,BQ->creationUD->mobileType); if( BQ->creationUD->immobileType != 0 ) // a factory { TerrainMapSector *S = G->TM->GetAlternativeSector(AS->area,iS,BQ->creationUD->immobileType); if( S != 0 ) cPosition = S->position; else { cPosition.x = -3; cPosition.z = -1; cPosition.y = -1; return cPosition; } } else cPosition = AS->S->position; } else if( BQ->creationUD->immobileType != 0 ) // buildings cPosition = G->TM->GetClosestSector(BQ->creationUD->immobileType,iS)->position; } if( BQ->builderUI->ud->speed == 0.0 ) { float3 cPosition2 = cb->ClosestBuildSite(bd,cPosition,BQ->builderUI->ud->buildDistance,5); if( cPosition2.x <= 0 && cPosition2.y <= 0 && cPosition2.z <= 0 ) cPosition2 = cb->ClosestBuildSite(bd,cPosition,BQ->builderUI->ud->buildDistance+25,1); return cPosition2; } iS = G->TM->GetSectorIndex(cPosition); float fSearchRadius=1000.0f; int iDisApart=10; if( G->TM->sector[iS].isWater ) iDisApart=15; else if( bd->speed > 0 ) iDisApart=5; else if( int(bd->buildOptions.size())>0 ) iDisApart=15; if( iDisApart < int(bd->kamikazeDist/8.0) ) iDisApart = int(bd->kamikazeDist/8.0); float3 cPosition2 = cb->ClosestBuildSite(bd,cPosition,fSearchRadius,iDisApart); if( cPosition2.x == -1 ) { cPosition2 = cb->ClosestBuildSite(bd,cPosition,2500.0f,iDisApart); if( cPosition2.x == -1 ) return bPosition; } return cPosition2; }