Ejemplo n.º 1
0
UFlareSimulatedSpacecraft*  SectorHelper::FindTradeStation(FlareTradeRequest Request)
{
	//FLOGV("FindTradeStation of %s for %s  (%d)", *Request.Resource->Acronym.ToString(), *Request.Client->GetImmatriculation().ToString(), (Request.Operation + 0));

	if(!Request.Client || !Request.Client->GetCurrentSector())
	{
		FLOG("Invalid find trade query");
		return NULL;
	}

	UFlareCompany* ClientCompany = Request.AllowUseNoTradeForMe ? Request.Client->GetCompany() : nullptr;


	UFlareSimulatedSector* Sector = Request.Client->GetCurrentSector();
	TArray<UFlareSimulatedSpacecraft*>& SectorStations = Sector->GetSectorStations();

	float UnloadQuantityScoreMultiplier = 0;
	float LoadQuantityScoreMultiplier = 0;
	float SellQuantityScoreMultiplier = 0;
	float BuyQuantityScoreMultiplier = 0;
	float FullRatioBonus = 0;
	float EmptyRatioBonus = 0;
	bool  NeedInput = false;
	bool  NeedOutput = false;

	switch(Request.Operation)
	{
		case EFlareTradeRouteOperation::Buy:
			BuyQuantityScoreMultiplier = 10.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::Sell:
			SellQuantityScoreMultiplier = 10.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
		case EFlareTradeRouteOperation::Load:
			LoadQuantityScoreMultiplier = 10.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::Unload:
			UnloadQuantityScoreMultiplier = 10.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
		case EFlareTradeRouteOperation::LoadOrBuy:
			LoadQuantityScoreMultiplier = 10.f;
			BuyQuantityScoreMultiplier = 1.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::UnloadOrSell:
			UnloadQuantityScoreMultiplier = 10.f;
			SellQuantityScoreMultiplier = 1.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
	}

	float BestScore = 0;
	UFlareSimulatedSpacecraft* BestStation = NULL;
	uint32 AvailableQuantity = Request.Client->GetActiveCargoBay()->GetResourceQuantity(Request.Resource, ClientCompany);
	uint32 FreeSpace = Request.Client->GetActiveCargoBay()->GetFreeSpaceForResource(Request.Resource, ClientCompany);

	for (int32 StationIndex = 0; StationIndex < SectorStations.Num(); StationIndex++)
	{
		UFlareSimulatedSpacecraft* Station = SectorStations[StationIndex];
		//FLOGV("   Check trade for %s", *Station->GetImmatriculation().ToString());


		FText Unused;
		if(!Request.Client->CanTradeWith(Station, Unused))
		{
			//FLOG(" cannot trade with");
			continue;
		}

		if(!Request.AllowStorage && Station->HasCapability(EFlareSpacecraftCapability::Storage))
		{
			continue;
		}

		FFlareResourceUsage StationResourceUsage = Station->GetResourceUseType(Request.Resource);


		if(NeedOutput && (!StationResourceUsage.HasUsage(EFlareResourcePriceContext::FactoryOutput) &&
						  !StationResourceUsage.HasUsage(EFlareResourcePriceContext::ConsumerConsumption) &&
						  !StationResourceUsage.HasUsage(EFlareResourcePriceContext::HubOutput)))
		{
			//FLOG(" need output but dont provide it");
			continue;
		}

		if(NeedInput && (!StationResourceUsage.HasUsage(EFlareResourcePriceContext::FactoryInput) &&
						 !StationResourceUsage.HasUsage(EFlareResourcePriceContext::ConsumerConsumption) &&
						 !StationResourceUsage.HasUsage(EFlareResourcePriceContext::MaintenanceConsumption) &&
						 !StationResourceUsage.HasUsage(EFlareResourcePriceContext::HubInput)))
		{
			//FLOG(" need input but dont provide it");
			continue;
		}

		int32 StationFreeSpace = Station->GetActiveCargoBay()->GetFreeSpaceForResource(Request.Resource, ClientCompany);
		int32 StationResourceQuantity = Station->GetActiveCargoBay()->GetResourceQuantity(Request.Resource, ClientCompany);

		if (!Station->IsUnderConstruction() && Station->IsComplex() && !Request.AllowFullStock)
		{
			if(Station->GetActiveCargoBay()->WantBuy(Request.Resource, ClientCompany) && Station->GetActiveCargoBay()->WantSell(Request.Resource, ClientCompany))
			{
				int32 TotalCapacity = Station->GetActiveCargoBay()->GetTotalCapacityForResource(Request.Resource, ClientCompany);
				StationFreeSpace = FMath::Max(0, StationFreeSpace - TotalCapacity / 2);
				StationResourceQuantity = FMath::Max(0, StationResourceQuantity - TotalCapacity / 2);
			}
		}

		if (StationFreeSpace == 0 && StationResourceQuantity == 0)
		{
			//FLOG(" need quantity or resource");
			continue;
		}

		float Score = 0;
		float FullRatio =  (float) StationResourceQuantity / (float) (StationResourceQuantity + StationFreeSpace);
		float EmptyRatio = 1 - FullRatio;
		uint32 UnloadMaxQuantity  = 0;
		uint32 LoadMaxQuantity  = 0;


		if(!Station->IsUnderConstruction())
		{
			// Check cargo limit
			if(NeedOutput && Request.CargoLimit != -1 && FullRatio < Request.CargoLimit / Station->GetLevel())
			{
				continue;
			}

			if(NeedInput && Request.CargoLimit != -1 && FullRatio > (1.f - (1.f - Request.CargoLimit) / Station->GetLevel()))
			{
				continue;
			}
		}
		else if (Station->HasCapability(EFlareSpacecraftCapability::Storage))
		{
			continue;
		}

		if(Station->GetActiveCargoBay()->WantBuy(Request.Resource, ClientCompany))
		{
			UnloadMaxQuantity = StationFreeSpace;
			UnloadMaxQuantity  = FMath::Min(UnloadMaxQuantity , AvailableQuantity);
		}

		if(Station->GetActiveCargoBay()->WantSell(Request.Resource, ClientCompany))
		{
			LoadMaxQuantity = StationResourceQuantity;
			LoadMaxQuantity = FMath::Min(LoadMaxQuantity , FreeSpace);
		}

		if(Station->GetCompany() == Request.Client->GetCompany())
		{
			Score += UnloadMaxQuantity * UnloadQuantityScoreMultiplier;
			Score += LoadMaxQuantity * LoadQuantityScoreMultiplier;
		}
		else
		{
			FFlareResourceUsage ResourceUsage = Station->GetResourceUseType(Request.Resource);

			int32 ResourcePrice = 0;
			if(NeedInput)
			{
				ResourcePrice = Sector->GetTransfertResourcePrice(NULL, Station, Request.Resource);
			}
			else
			{
				ResourcePrice = Sector->GetTransfertResourcePrice(Station, NULL, Request.Resource);
			}



			uint32 MaxBuyableQuantity = Request.Client->GetCompany()->GetMoney() / SectorHelper::GetBuyResourcePrice(Sector, Request.Resource, ResourceUsage);
			LoadMaxQuantity = FMath::Min(LoadMaxQuantity , MaxBuyableQuantity);

			uint32 MaxSellableQuantity = Station->GetCompany()->GetMoney() / SectorHelper::GetSellResourcePrice(Sector, Request.Resource, ResourceUsage);
			UnloadMaxQuantity = FMath::Min(UnloadMaxQuantity , MaxSellableQuantity);

			Score += UnloadMaxQuantity * SellQuantityScoreMultiplier;
			Score += LoadMaxQuantity * BuyQuantityScoreMultiplier;
		}

		Score *= 1 + (FullRatio * FullRatioBonus) + (EmptyRatio * EmptyRatioBonus);

		if(Station->IsUnderConstruction())
		{
			Score *= 10000;
			/*FLOGV("Station %s is under construction. Score %f, BestScore %f",
				  *Station->GetImmatriculation().ToString(),
				  Score,
				  BestScore)*/
		}
		else if(Station->HasCapability(EFlareSpacecraftCapability::Storage))
		{
			Score *= 0.01;
		}

		if(Score > 0 && Score > BestScore)
		{
			BestScore = Score;
			BestStation = Station;
		}
	}

	//FLOGV("FindTradeStation result %p", BestStation);

	return BestStation;
}