cable cars: extend order interface and let producer order more components at a time

master
Maikel de Vries 2018-04-14 18:01:50 +02:00
parent 75a82e172a
commit a4d20d79d5
6 changed files with 100 additions and 78 deletions

View File

@ -526,15 +526,14 @@ public func OnEnoughPower(int amount)
/*-- Delivery --*/
public func AddRequest(id requested_id, int amount, object target, object source)
public func AddRequest(proplist order, object target, object source)
{
//Log("[%d]AddRequest(car %v at station %v) %v->%v->%v", FrameCounter(), this, lib_ccar_rail, source, [requested_id, amount], target);
//Log("[%d]AddRequest(car %v at station %v) %v->%v->%v", FrameCounter(), this, lib_ccar_rail, source, order, target);
lib_ccar_delivery =
{
source = source,
target = target,
requested_id = requested_id,
amount = amount
target = target,
order = order
};
// First move to source if not already there.
if (lib_ccar_rail != lib_ccar_delivery.source)
@ -548,7 +547,7 @@ public func ContinueRequest()
{
if (!lib_ccar_delivery)
return;
//Log("[%d]ContinueRequest(car %v currently at station %v) %v", FrameCounter(), this, lib_ccar_rail, [lib_ccar_delivery.requested_id, lib_ccar_delivery.amount]);
//Log("[%d]ContinueRequest(car %v currently at station %v) %v", FrameCounter(), this, lib_ccar_rail, lib_ccar_delivery.order);
// Continue moving to source or target.
SetDestination(lib_ccar_delivery.source ?? lib_ccar_delivery.target);
}
@ -557,20 +556,20 @@ public func FinishedRequest(object station)
{
if (!lib_ccar_delivery)
return;
//Log("[%d]FinishedRequest(car %v at station %v) %v", FrameCounter(), this, station, [lib_ccar_delivery.requested_id, lib_ccar_delivery.amount]);
//Log("[%d]FinishedRequest(car %v at station %v) %v", FrameCounter(), this, station, lib_ccar_delivery.order);
// May have first arrived at the source station.
if (lib_ccar_delivery.source && station == lib_ccar_delivery.source)
{
// Load requested objects and move to target.
lib_ccar_delivery.source = nil;
station->RequestPickUp(this, lib_ccar_delivery.requested_id, lib_ccar_delivery.amount);
station->RequestPickUp(this, lib_ccar_delivery.order);
SetDestination(lib_ccar_delivery.target);
return;
}
// Arrived at delivery target station.
if (station == lib_ccar_delivery.target)
{
station->RequestArrived(this, lib_ccar_delivery.requested_id, lib_ccar_delivery.amount);
station->RequestArrived(this, lib_ccar_delivery.order);
lib_ccar_delivery = nil;
return;
}

View File

@ -42,14 +42,14 @@ public func OnCableCarDisengaged(object car) { }
public func OnCableCarDestruction(object car) { }
// Called when a cable car wants to pick up resources for a delivery
public func OnCableCarPickUp(object car, id requested, int amount) { }
public func OnCableCarPickUp(object car, proplist order) { }
// Called when a cable car with a requested delivery arrives
public func OnCableCarDelivery(object car, id requested, int amount) { }
public func OnCableCarDelivery(object car, proplist order) { }
// Called by other stations to check if a certain object and amount are available for delivery at this station.
// Return true if there are means to collect the required amount.
public func IsAvailable(id requested_id, int amount)
public func IsAvailable(proplist order)
{
return false;
}
@ -443,35 +443,40 @@ public func GetLengthToTarget(object end)
local request_queue;
// Add a new acquiring order
public func AddRequest(id requested_id, int amount)
// Add a new acquiring order, this order will be delivered to this station and is a proplist with information.
// { type = <id of the object>, min_amount = <minimal amount to be delivered>, max_amount = <maximal amount to be delivered>}.
public func AddRequest(proplist order)
{
if (!requested_id) return false;
if (!amount) amount = 1;
if (!order || !order.type)
return false;
if (!order.min_amount)
order.min_amount = 1;
// First of all check if a similar request already is on the line
// Similar requests will be dismissed, even if they are technically new
for (var request in request_queue)
if (request[0] == requested_id)
if (request[1] == amount)
if (request.type == order.type)
if (request.min_amount == order.min_amount)
return true; // The request is considered handled
var source = CheckAvailability(requested_id, amount);
// Find source station which has the order's items.
var source = CheckAvailability(order);
if (!source)
return false; // Items are not available
return false;
var car = source->GetAvailableCableCar(requested_id, amount, this);
// Find cable car that is at source station or closest to source station.
var car = source->GetAvailableCableCar(order, this);
if (!car)
return false; // No cable car is available for delivery
return false;
// Great. Start working immediately
PushBack(request_queue, [requested_id, amount]);
car->AddRequest(requested_id, amount, this, source);
PushBack(request_queue, order);
car->AddRequest(order, this, source);
return true;
}
// Check all connected stations for available objects.
public func CheckAvailability(id requested_id, int amount)
public func CheckAvailability(proplist order)
{
var nearest_station;
var length_to;
@ -482,7 +487,7 @@ public func CheckAvailability(id requested_id, int amount)
PushBack(network_stations, station[const_finaldestination]);
for (var station in network_stations)
{
if (station->IsAvailable(requested_id, amount))
if (station->IsAvailable(order))
{
if (!nearest_station)
{
@ -513,47 +518,42 @@ public func CheckAvailability(id requested_id, int amount)
}
// Check if there is a cable car ready for delivery
public func GetAvailableCableCar(id requested_id, int amount, object requesting_station)
public func GetAvailableCableCar(proplist order, object requesting_station)
{
}
// A delivery needs to be picked up at this station.
public func RequestPickUp(object car, id requested_id, int amount)
public func RequestPickUp(object car, proplist order)
{
OnCableCarPickUp(car, requested_id, amount);
OnCableCarPickUp(car, order);
}
// A delivery has arrived, remove it from the queue and handle the request
public func RequestArrived(object car, id requested_id, int amount)
public func RequestArrived(object car, proplist order)
{
if (!HasRequest(requested_id, amount))
if (!HasRequest(order))
return;
OnCableCarDelivery(car, requested_id, amount);
RemoveRequest(requested_id, amount);
OnCableCarDelivery(car, order);
RemoveRequest(order);
}
public func HasRequest(id requested_id, int amount)
public func HasRequest(proplist order)
{
for (var i = 0; i < GetLength(request_queue); i++)
{
if (request_queue[i][0] != requested_id)
continue;
if (request_queue[i][1] != amount)
continue;
return true;
}
for (var test_order in request_queue)
if (test_order.type == order.type && test_order.min_amount == order.min_amount)
return true;
return false;
}
public func RemoveRequest(id requested_id, int amount)
public func RemoveRequest(proplist order)
{
for (var i = 0; i < GetLength(request_queue); i++)
{
if (request_queue[i][0] != requested_id)
if (request_queue[i].type != order.type)
continue;
if (request_queue[i][1] != amount)
if (request_queue[i].min_amount != order.min_amount)
continue;
break;
}

View File

@ -68,17 +68,17 @@ public func DestinationsUpdated()
cable->OnRailNetworkUpdate();
}
public func IsAvailable(id requested_id, int amount)
public func IsAvailable(proplist order)
{
// Check resource chute for contents.
if (has_resource_chute && ContentsCount(requested_id) >= amount)
if (has_resource_chute && ContentsCount(order.type) >= order.min_amount)
return true;
// Check cable cars idling at this station.
if (GetLength(arrived_cars))
{
for (var car in arrived_cars)
{
if (car->~IsAvailable(requested_id, amount))
if (car->~IsAvailable(order))
return true;
}
}
@ -86,44 +86,52 @@ public func IsAvailable(id requested_id, int amount)
return false;
}
public func GetAvailableCableCar(id requested_id, int amount, object requesting_station)
public func GetAvailableCableCar(proplist order, object requesting_station)
{
// Check cars that are idling at this station
var best;
for (var car in arrived_cars)
{
if (!car->~IsReadyForDelivery(requested_id, amount, requesting_station))
if (!car->~IsReadyForDelivery(order, requesting_station))
continue;
if (!best)
best = car;
// A car might want to override the search for an available car, mainly because it holds the container
// which holds the requested items
else if (car->~OverridePriority(requested_id, amount, requesting_station, best))
else if (car->~OverridePriority(order, requesting_station, best))
best = car;
}
if (best)
return best;
// Check cars that are idling at the requesting station
// Check cars that are idling at other crossings in the network.
if (requesting_station != this)
{
var best = requesting_station->~GetAvailableCableCar(requested_id, amount, requesting_station);
if (best)
return best;
// Find closest cars first.
var destinations = GetDestinations();
SortArrayByArrayElement(destinations, this.const_distance, false);
for (dest in destinations)
{
var station = dest[this.const_finaldestination];
var best = station->~GetAvailableCableCar(order, station);
if (best)
return best;
}
}
return nil;
}
public func OnCableCarPickUp(object car, id requested, int amount)
public func OnCableCarPickUp(object car, proplist order)
{
car = car->~GetAttachedVehicle() ?? car;
// Take from resource chute if available.
if (has_resource_chute)
{
var amount = Max(order.min_amount, order.max_amount);
while (amount > 0)
{
var item = FindContents(requested);
var item = FindContents(order.type);
if (!item)
break;
item->Enter(car);
@ -135,26 +143,27 @@ public func OnCableCarPickUp(object car, id requested, int amount)
if (connected_building)
{
// TODO: Do we even want this?
}
return;
}
public func OnCableCarDelivery(object car, id requested, int amount)
public func OnCableCarDelivery(object car, proplist order)
{
// Transfer the requested material to the connected producer
if (!connected_building)
return;
car = car->~GetAttachedVehicle() ?? car;
for (var i = 0; i < amount; i++)
var amount = Max(order.min_amount, order.max_amount);
while (amount > 0)
{
var item = car->FindContents(requested);
var item = car->FindContents(order.type);
if (!item)
break;
item->Enter(connected_building);
amount--;
}
return;
}

View File

@ -212,17 +212,17 @@ public func DropContents(object station)
}
// Check for available contents
public func IsAvailable(id requested_id, int amount)
public func IsAvailable(proplist order)
{
// So far only do something if a lorry is connected, all other vehicles are considered off-limits
if (pickup && pickup->~IsLorry())
if (pickup->ContentsCount(requested_id) >= amount)
if (pickup->ContentsCount(order.type) >= order.min_amount)
return true;
return false;
}
// Called when a station has asked to make a delivery
public func IsReadyForDelivery(id requested_id, int amount, object requesting_station)
public func IsReadyForDelivery(proplist order, object requesting_station)
{
// Is already on a delivery.
if (lib_ccar_delivery)
@ -231,20 +231,20 @@ public func IsReadyForDelivery(id requested_id, int amount, object requesting_st
if (pickup && pickup->~IsLorry())
{
// Lorry must have enough space left...
if (pickup->ContentsCount() + amount <= pickup.MaxContentsCount)
if (pickup->ContentsCount() + order.min_amount <= pickup.MaxContentsCount)
return true;
// ...or contain the requested objects
if (pickup->ContentsCount(requested_id) >= amount)
if (pickup->ContentsCount(order.type) >= order.min_amount)
return true;
}
return false;
}
// Called when searching for a better option to deliver something
public func OverridePriority(id requested_id, int amount, object requesting_station, proplist best)
public func OverridePriority(proplist order, object requesting_station, object best_car)
{
// Check if the connected vehicle holds the requested objects and if yes, override the selection
if (pickup && pickup->ContentsCount(requested_id) >= amount)
if (pickup && pickup->ContentsCount(order.type) >= order.min_amount)
return true;
return false;
}

View File

@ -497,7 +497,7 @@ private func ProcessQueue()
if (!Produce(product_id, producing_player))
{
// No material available? request from cable network.
RequestAllMissingComponents(product_id);
RequestAllMissingComponents(queue[0]);
// In the meanwhile, just cycle the queue and try the next one.
CycleQueue();
return FX_OK;
@ -827,34 +827,47 @@ public func ConnectCableStation(object station)
/**
Requests the necessary material from the cable network if available.
*/
public func RequestAllMissingComponents(id item_id)
public func RequestAllMissingComponents(proplist product)
{
if (!cable_station)
return false;
var item_id = product.Product;
var amount = product.Amount;
// Take by batches of five for infinite production.
// TODO: Can we somehow make this smarter? Take all available from source container?
if (product.Infinite)
amount = 5;
// Request all currently unavailable components.
for (var item in ProductionCosts(item_id))
{
var mat_id = item[0];
var mat_cost = item[1];
// No way to request liquids currently, player must use pumps instead.
if (mat_id->~IsLiquid())
continue;
var available = GetAvailableComponentAmount(mat_id);
if (available < mat_cost)
RequestObject(mat_id, mat_cost - available);
RequestObject(mat_id, mat_cost - available, amount * mat_cost - available);
}
// Also check item fuel need.
var fuel_needed = FuelNeed(item_id);
if (fuel_needed > 0)
{
{
// For now just use coal as a fuel.
RequestObject(Coal, 1 + (fuel_needed - 1) / Coal->GetFuelAmount());
var coal_needed = 1 + (fuel_needed - 1) / Coal->GetFuelAmount();
RequestObject(Coal, coal_needed, amount * coal_needed);
}
return true;
}
public func RequestObject(id item_id, int amount)
public func RequestObject(id item_id, int min_amount, int max_amount)
{
if (cable_station)
cable_station->AddRequest(item_id, amount);
cable_station->AddRequest({type = item_id, min_amount = min_amount, max_amount = max_amount});
return;
}

View File

@ -277,7 +277,8 @@ public func RequestFuel()
{
// For now just request coal as it is the safest type of fuel, that is least needed by other structures.
if (cable_station)
cable_station->AddRequest(Coal, 1);
cable_station->AddRequest({type = Coal, min_amount = 1, max_amount = 5});
return;
}