cable cars: improve deliveries and producer requests fuel

master
Maikel de Vries 2018-04-12 09:19:55 +02:00
parent 618b4039b3
commit 1e060d6124
7 changed files with 248 additions and 74 deletions

View File

@ -4,8 +4,11 @@
@author Clonkonaut
*/
local hanging_cars;
public func Initialize()
{
hanging_cars = [];
SetAction("Connect");
SetVertexXY(0, GetX(), GetY());
SetVertexXY(1, GetX(), GetY());
@ -21,7 +24,7 @@ public func IsConnectedTo(object obj)
}
/** Connects this cable to obj1 and obj2. */
public func SetConnectedObjects(obj1, obj2)
public func SetConnectedObjects(object obj1, object obj2)
{
if (GetActionTarget(0)) GetActionTarget(0)->~CableDeactivation(activations);
if (GetActionTarget(1)) GetActionTarget(1)->~CableDeactivation(activations);
@ -144,6 +147,28 @@ public func Deactivation(int count)
}
/*-- Cable Cars --*/
public func AddHangingCableCar(object car)
{
PushBack(hanging_cars, car);
return;
}
public func RemoveHangingCar(object car)
{
RemoveArrayValue(hanging_cars, car, true);
return;
}
public func OnRailNetworkUpdate()
{
for (var car in hanging_cars)
car->~OnRailNetworkUpdate();
return;
}
/*-- Saving --*/
public func SaveScenarioObject(proplist props)

View File

@ -108,6 +108,7 @@ public func DoMovement()
if (lib_ccar_progress >= lib_ccar_max_progress)
{
lib_ccar_rail->~Deactivation(1);
lib_ccar_rail->~RemoveHangingCableCar(this);
lib_ccar_rail = lib_ccar_rail->GetActionTarget(end);
lib_ccar_rail->GetCablePosition(position);
GetCableOffset(position);
@ -322,13 +323,10 @@ public func SetDestination(dest)
}
lib_ccar_destination = dest;
if (lib_ccar_direction == nil)
{
OnStart();
CrossingReached();
if (lib_ccar_rail)
lib_ccar_rail->~OnCableCarDeparture(this);
OnStart();
}
}
@ -388,27 +386,17 @@ public func Destruction()
lib_ccar_rail->~OnCableCarDestruction(this);
}
// Setup movement process
public func MoveToIndex(int dest)
{
var dest_obj = FindObjects(Find_Func("IsCableCrossing"))[dest];
if (dest_obj) return MoveTo(dest_obj);
}
public func MoveTo(object dest)
{
var rail = 0;
for (var test_rail in FindObjects(Find_Func("IsConnectedTo", lib_ccar_rail)))
{
if (test_rail->IsConnectedTo(dest))
{
rail = test_rail;
break;
}
}
// Find cable that is connected to both initial and final crossing.
var rail = FindObject(Find_Func("IsConnectedTo", lib_ccar_rail), Find_Func("IsConnectedTo", dest));
if (!rail)
return DestinationFailed(); // Shouldn't happen
// Notify crossing a cable car has left.
if (lib_ccar_rail)
lib_ccar_rail->~OnCableCarDeparture(this);
// Target the first or second action target?
if (rail->GetActionTarget(0) == dest)
lib_ccar_direction = 0;
@ -419,8 +407,10 @@ public func MoveTo(object dest)
rail->GetActionTarget(0)->GetCablePosition(origin);
rail->GetActionTarget(1)->GetCablePosition(ending);
rail->~Activation(1);
rail->~AddHangingCableCar(this);
lib_ccar_max_progress = Distance(origin[0], origin[1], ending[0], ending[1]);
lib_ccar_rail = rail;
return;
}
@ -536,25 +526,54 @@ public func OnEnoughPower(int amount)
/*-- Delivery --*/
public func AddRequest(proplist requested, int amount, proplist target, proplist source)
public func AddRequest(id requested_id, int amount, object target, object source)
{
lib_ccar_delivery = [source, target, requested, amount];
SetDestination(target);
//Log("[%d]AddRequest(car %v at station %v) %v->%v->%v", FrameCounter(), this, lib_ccar_rail, source, [requested_id, amount], target);
lib_ccar_delivery =
{
source = source,
target = target,
requested_id = requested_id,
amount = amount
};
// First move to source if not already there.
if (lib_ccar_rail != lib_ccar_delivery.source)
return SetDestination(lib_ccar_delivery.source);
// Was at source already so move to target directly.
lib_ccar_delivery.source = nil;
SetDestination(lib_ccar_delivery.target);
}
public func ContinueRequest()
{
if (!lib_ccar_delivery)
return;
var target = lib_ccar_delivery[1];
SetDestination(target);
//Log("[%d]ContinueRequest(car %v currently at station %v) %v", FrameCounter(), this, lib_ccar_rail, [lib_ccar_delivery.requested_id, lib_ccar_delivery.amount]);
// Continue moving to source or target.
SetDestination(lib_ccar_delivery.source ?? lib_ccar_delivery.target);
}
public func FinishedRequest(object station)
{
if (station && lib_ccar_delivery)
station->RequestArrived(this, lib_ccar_delivery[2], lib_ccar_delivery[3]);
lib_ccar_delivery = nil;
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]);
// 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);
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);
lib_ccar_delivery = nil;
return;
}
}

View File

@ -41,12 +41,15 @@ public func OnCableCarDisengaged(object car) { }
// Called by a cable car that has been destroyed at this station
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) { }
// Called when a cable car with a requested delivery arrives
public func OnCableCarDelivery(object car, id requested, int amount) { }
// 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(proplist requested, int amount)
public func IsAvailable(id requested_id, int amount)
{
return false;
}
@ -441,7 +444,7 @@ public func GetLengthToTarget(object end)
local request_queue;
// Add a new acquiring order
public func AddRequest(proplist requested_id, int amount)
public func AddRequest(id requested_id, int amount)
{
if (!requested_id) return false;
if (!amount) amount = 1;
@ -467,24 +470,29 @@ public func AddRequest(proplist requested_id, int amount)
return true;
}
// Check all connected stations for available objects
public func CheckAvailability(proplist requested, int amount)
// Check all connected stations for available objects.
public func CheckAvailability(id requested_id, int amount)
{
var nearest_station;
var length_to;
for (var destination in destination_list)
// Loop over all stations, including this one.
var network_stations = [this];
for (var station in GetDestinations())
if (station)
PushBack(network_stations, station[const_finaldestination]);
for (var station in network_stations)
{
if (destination[const_finaldestination]->IsAvailable(requested, amount))
if (station->IsAvailable(requested_id, amount))
{
var station = destination[const_finaldestination];
if (!nearest_station)
{
nearest_station = station;
length_to = GetLengthToTarget(nearest_station);
}
else {
else
{
// Storages (like chests) are always preferred over other producer because the items
// might be stored in another producer to produce something
// might be stored in another producer to produce something.
if (station->~IsStorage() && !nearest_station->~IsStorage())
{
nearest_station = station;
@ -492,7 +500,7 @@ public func CheckAvailability(proplist requested, int amount)
}
else if (nearest_station->~IsStorage() && !station->~IsStorage())
continue;
// Otherwise the shorter the path, the better
// Otherwise the shorter the path, the better.
else if (GetLengthToTarget(station) < length_to)
{
nearest_station = station;
@ -505,13 +513,19 @@ public func CheckAvailability(proplist requested, int amount)
}
// Check if there is a cable car ready for delivery
public func GetAvailableCableCar(proplist requested, int amount, proplist requesting_station)
public func GetAvailableCableCar(id requested_id, int amount, object requesting_station)
{
}
// A delivery needs to be picked up at this station.
public func RequestPickUp(object car, id requested_id, int amount)
{
OnCableCarPickUp(car, requested_id, amount);
}
// A delivery has arrived, remove it from the queue and handle the request
public func RequestArrived(proplist car, proplist requested_id, int amount)
public func RequestArrived(object car, id requested_id, int amount)
{
if (!HasRequest(requested_id, amount))
return;
@ -520,11 +534,11 @@ public func RequestArrived(proplist car, proplist requested_id, int amount)
RemoveRequest(requested_id, amount);
}
public func HasRequest(id requested, int amount)
public func HasRequest(id requested_id, int amount)
{
for (var i = 0; i < GetLength(request_queue); i++)
{
if (request_queue[i][0] != requested)
if (request_queue[i][0] != requested_id)
continue;
if (request_queue[i][1] != amount)
continue;
@ -533,11 +547,11 @@ public func HasRequest(id requested, int amount)
return false;
}
public func RemoveRequest(id requested, int amount)
public func RemoveRequest(id requested_id, int amount)
{
for (var i = 0; i < GetLength(request_queue); i++)
{
if (request_queue[i][0] != requested)
if (request_queue[i][0] != requested_id)
continue;
if (request_queue[i][1] != amount)
continue;

View File

@ -63,39 +63,42 @@ public func DestinationsUpdated()
for (var car in arrived_cars)
if (car)
car->~OnRailNetworkUpdate();
// Also inform all cars on adjacent cables.
for (var cable in FindObjects(Find_Func("IsConnectedTo", this)))
cable->OnRailNetworkUpdate();
}
public func IsAvailable(proplist requested, int amount)
public func IsAvailable(id requested_id, int amount)
{
// Check connected buildings for contents
if (connected_building)
if (connected_building->ContentsCount(requested) >= amount)
// Check resource chute for contents.
if (has_resource_chute && ContentsCount(requested_id) >= amount)
return true;
// Check cable cars idling at this station
// Check cable cars idling at this station.
if (GetLength(arrived_cars))
{
for (var car in arrived_cars)
{
if (car->~IsAvailable(requested, amount))
if (car->~IsAvailable(requested_id, amount))
return true;
}
}
// TODO: check connected building.
return false;
}
public func GetAvailableCableCar(proplist requested, int amount, proplist requesting_station)
public func GetAvailableCableCar(id requested_id, int amount, object requesting_station)
{
// Check cars that are idling at this station
var best;
for (var car in arrived_cars)
{
if (!car->~IsReadyForDelivery(requested, amount, requesting_station))
if (!car->~IsReadyForDelivery(requested_id, amount, 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, amount, requesting_station, best))
else if (car->~OverridePriority(requested_id, amount, requesting_station, best))
best = car;
}
if (best)
@ -103,12 +106,40 @@ public func GetAvailableCableCar(proplist requested, int amount, proplist reques
// Check cars that are idling at the requesting station
if (requesting_station != this)
if (best = requesting_station->~GetAvailableCableCar(requested, amount, requesting_station))
{
var best = requesting_station->~GetAvailableCableCar(requested_id, amount, requesting_station);
if (best)
return best;
}
return nil;
}
public func OnCableCarPickUp(object car, id requested, int amount)
{
car = car->~GetAttachedVehicle() ?? car;
// Take from resource chute if available.
if (has_resource_chute)
{
while (amount > 0)
{
var item = FindContents(requested);
if (!item)
break;
item->Enter(car);
amount--;
}
}
// Take from connected building alternatively.
if (connected_building)
{
// TODO: Do we even want this?
}
return;
}
public func OnCableCarDelivery(object car, id requested, int amount)
{
// Transfer the requested material to the connected producer
@ -346,6 +377,8 @@ public func Collection(object obj, bool put)
public func IsContainer() { return has_resource_chute; }
public func IsStorage() { return has_resource_chute; }
local MaxContentsCount = 100;
public func RejectCollect()

View File

@ -205,24 +205,24 @@ public func GetAttachedVehicle()
// Calls from the stations will mostly be forwarded to the attached vehicle
public func DropContents(proplist station)
public func DropContents(object station)
{
if (pickup)
pickup->DropContents(station);
}
// Check for available contents
public func IsAvailable(proplist requested, int amount)
public func IsAvailable(id requested_id, int amount)
{
// 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) >= amount)
if (pickup->ContentsCount(requested_id) >= amount)
return true;
return false;
}
// Called when a station has asked to make a delivery
public func IsReadyForDelivery(proplist requested, int amount, proplist requesting_station)
public func IsReadyForDelivery(id requested_id, int amount, object requesting_station)
{
// Is already on a delivery.
if (lib_ccar_delivery)
@ -234,17 +234,17 @@ public func IsReadyForDelivery(proplist requested, int amount, proplist requesti
if (pickup->ContentsCount() + amount <= pickup.MaxContentsCount)
return true;
// ...or contain the requested objects
if (pickup->ContentsCount(requested) >= amount)
if (pickup->ContentsCount(requested_id) >= amount)
return true;
}
return false;
}
// Called when searching for a better option to deliver something
public func OverridePriority(proplist requested, int amount, proplist requesting_station, proplist best)
public func OverridePriority(id requested_id, int amount, object requesting_station, proplist best)
{
// Check if the connected vehicle holds the requested objects and if yes, override the selection
if (pickup && pickup->ContentsCount(requested) >= amount)
if (pickup && pickup->ContentsCount(requested_id) >= amount)
return true;
return false;
}

View File

@ -827,7 +827,7 @@ public func ConnectCableStation(object station)
/**
Requests the necessary material from the cable network if available.
*/
func RequestAllMissingComponents(id item_id)
public func RequestAllMissingComponents(id item_id)
{
if (!cable_station)
return false;
@ -840,6 +840,14 @@ func RequestAllMissingComponents(id item_id)
if (available < mat_cost)
RequestObject(mat_id, 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());
}
return true;
}

View File

@ -57,7 +57,7 @@ protected func InitializePlayer(int plr)
// Add test control effect.
var fx = AddEffect("IntTestControl", nil, 100, 2);
fx.testnr = 9;
fx.testnr = 1;
fx.launched = false;
fx.plr = plr;
return;
@ -484,7 +484,8 @@ global func Test6_OnStart(int plr)
var drain = CreateObjectAbove(Pipe, 80, 300, plr);
drain->ConnectPipeTo(pump, PIPE_STATE_Drain);
Schedule(nil, "CreateObject(Rock, 480, 274)", 36, 10**6);
crossing13->AddResourceChute();
Schedule(nil, "CreateObject(Rock, 472, 274)", 36, 10**6);
// Log what the test is about.
Log("Test automated concrete production line.");
@ -493,7 +494,7 @@ global func Test6_OnStart(int plr)
global func Test6_Completed()
{
if (GetMaterial(80, 240) == Material("Granite"))
if (GetMaterial(80, 280) == Material("Granite"))
return true;
return false;
}
@ -609,7 +610,7 @@ global func Test9_OnStart(int plr)
var crossing1 = CreateObjectAbove(CableCrossing, 60, 160, plr);
var crossing2 = CreateObjectAbove(CableCrossing, 216, 64, plr);
var crossing3 = CreateObjectAbove(CableCrossing, 272, 64, plr);
var crossing4 = CreateObjectAbove(CableCrossing, 450, 104, plr);
var crossing4 = CreateObjectAbove(CableCrossing, 446, 104, plr);
var crossing5 = CreateObjectAbove(CableCrossing, 130, 160, plr);
var crossing6 = CreateObjectAbove(CableCrossing, 280, 160, plr);
var crossing7 = CreateObjectAbove(CableCrossing, 348, 104, plr);
@ -618,7 +619,7 @@ global func Test9_OnStart(int plr)
var crossing10 = CreateObjectAbove(CableCrossing, 288, 248, plr);
var crossing11 = CreateObjectAbove(CableCrossing, 254, 280, plr);
var crossing12 = CreateObjectAbove(CableCrossing, 312, 312, plr);
var crossing13 = CreateObjectAbove(CableCrossing, 476, 312, plr);
var crossing13 = CreateObjectAbove(CableCrossing, 420, 312, plr);
var crossing14 = CreateObjectAbove(CableCrossing, 440, 248, plr);
CreateCableCrossingsConnection(crossing1, crossing2);
@ -651,10 +652,13 @@ global func Test9_OnStart(int plr)
hoist->EngageRail(crossing1);
lorry = crossing1->CreateObject(CableLorry);
hoist->PickupVehicle(lorry);
lorry->CreateContents(Firestone, 10);
var foundry = CreateObjectAbove(Foundry, 100, 160, plr);
var foundry = CreateObjectAbove(Foundry, 110, 160, plr);
foundry->AddToQueue(Metal, nil, true);
foundry->SetDir(DIR_Right);
crossing5->CombineWith(foundry);
crossing5->AddResourceChute();
var workshop = CreateObjectAbove(ToolsWorkshop, 30, 160, plr);
crossing1->CombineWith(workshop);
@ -668,10 +672,18 @@ global func Test9_OnStart(int plr)
crossing14->CombineWith(steam_engine);
steam_engine->CreateContents(Coal);
var sawmill = CreateObjectAbove(Sawmill, 480, 104, plr);
var sawmill = CreateObjectAbove(Sawmill, 492, 104, plr);
sawmill->SetDir(DIR_Right);
for (var cnt = 0; cnt < 5; cnt++)
sawmill->CreateObjectAbove(Tree_Deciduous)->ChopDown();
crossing4->AddResourceChute();
crossing5->CreateObject(Hammer);
crossing5->CreateObject(Metal);
crossing13->AddResourceChute();
Schedule(crossing13, "CreateObject(Coal, -4, -5)", 36, 10**6);
Schedule(crossing13, "CreateObject(Ore, -4, -10)", 36, 10**6);
// Log what the test is about.
Log("Multiple producers and power supply which need resources from mines.");
@ -680,7 +692,8 @@ global func Test9_OnStart(int plr)
global func Test9_Completed()
{
if (ObjectCount(Find_ID(Shovel)) >= 10 && ObjectCount(Find_ID(Dynamite)) >= 10)
return true;
return false;
}
@ -752,10 +765,57 @@ global func Test10_OnFinished()
}
global func Test11_OnStart(int plr)
{
SetWindFixed(0);
CreateObjectAbove(WindGenerator, 90, 160, plr);
CreateObjectAbove(WindGenerator, 470, 104, plr);
var crossing1 = CreateObjectAbove(CableCrossing, 70, 160, plr);
var crossing2 = CreateObjectAbove(CableCrossing, 216, 64, plr);
var crossing3 = CreateObjectAbove(CableCrossing, 244, 64, plr);
var crossing4 = CreateObjectAbove(CableCrossing, 272, 64, plr);
var crossing5 = CreateObjectAbove(CableCrossing, 450, 104, plr);
CreateCableCrossingsConnection(crossing1, crossing2);
CreateCableCrossingsConnection(crossing2, crossing3);
CreateCableCrossingsConnection(crossing3, crossing4);
CreateCableCrossingsConnection(crossing4, crossing5);
var hoist = crossing1->CreateObject(CableHoist);
hoist->EngageRail(crossing1);
hoist->SetDestination(crossing5);
ScheduleCall(nil, "SetWindFixed", 20, 0, 50);
ScheduleCall(nil, "SetWindFixed", 40, 0, 0);
Schedule(nil, "DrawMaterialQuad(\"Rock\", 60, 80, 120, 80, 120, 140, 60, 140)", 60, 0);
ScheduleCall(nil, "SetWindFixed", 80, 0, 50);
// Log what the test is about.
Log("Specific network for which power supply fails.");
return true;
}
global func Test11_Completed()
{
return !!FindObject(Find_ID(CableHoist), Find_Distance(20, 450, 104));
}
global func Test11_OnFinished()
{
RemoveTestObjects();
ClearScheduleCall(nil, "SetWindFixed");
ClearFreeRect(60, 80, 60, 60);
return;
}
/*-- Cable Network Functions --*/
global func CreateCableCrossingsConnection(object c1, object c2)
{
if (!c1 || !c2)
return nil;
var cable = c1->CreateObject(CableLine);
cable->SetConnectedObjects(c1, c2);
// Log the distance the cable covers of the cable.
@ -787,6 +847,14 @@ global func CreateObjectAbove(id obj, ...)
return res;
}
global func CreateObject(id obj, ...)
{
var res = _inherited(obj, ...);
if (obj == CableHoist)
res->Message("@<c 00aaaa>%d</c>", res->ObjectNumber());
return res;
}
global func PrintCableCarNetwork()
{
Log("Distances between all of the cable crossings:");
@ -908,10 +976,17 @@ global func RemoveTestObjects()
Find_ID(CableLorry),
Find_ID(Flagpole),
Find_ID(ToolsWorkshop),
Find_ID(Rock)
Find_ID(Sawmill)
),
Find_Or(
Find_ID(Dynamite)
Find_ID(Dynamite),
Find_ID(Rock),
Find_ID(Coal),
Find_ID(Ore),
Find_ID(Compensator),
Find_ID(SteamEngine),
Find_ID(ChemicalLab),
Find_ID(Metal)
)
));
return;