cable cars: improve network deletion and recreation + clean up

This is a rather chaotic commit and does not solve all problems of network creation yet, but is an improvement over the old system where deletion of a cable line would fail the network. However, we probably need a cleaner method to construct a network properly.
master
Maikel de Vries 2018-01-28 12:47:36 +01:00
parent 49d03e52c6
commit d8736a56ac
11 changed files with 535 additions and 252 deletions

View File

@ -1,6 +1,10 @@
/*-- Cable line --*/ /**
Cable line
func Initialize() @author Clonkonaut
*/
public func Initialize()
{ {
SetAction("Connect"); SetAction("Connect");
SetVertexXY(0, GetX(), GetY()); SetVertexXY(0, GetX(), GetY());
@ -37,28 +41,44 @@ public func GetConnectedObject(object obj)
return GetActionTarget(0); return GetActionTarget(0);
} }
/* Breaking */
func LineBreak(bool no_msg) /*-- Breaking --*/
public func OnLineBreak(bool no_msg)
{ {
Sound("Objects::Connect"); Sound("Objects::Connect");
if (GetActionTarget(0)) GetActionTarget(0)->~CableDeactivation(activations); var act1 = GetActionTarget(0);
if (GetActionTarget(1)) GetActionTarget(1)->~CableDeactivation(activations); var act2 = GetActionTarget(1);
SetAction("Idle");
if (act1)
{
act1->~CableDeactivation(activations);
act1->~RemoveCableConnection(this);
}
if (act2)
{
act2->~CableDeactivation(activations);
act2->~RemoveCableConnection(this);
}
if (!no_msg) if (!no_msg)
BreakMessage(); BreakMessage();
} }
func BreakMessage() public func BreakMessage()
{ {
var line_end = GetActionTarget(0); var line_end = GetActionTarget(0);
if (line_end->GetID() != CableLorryReel) if (!line_end || line_end->GetID() != CableLorryReel)
line_end = GetActionTarget(1); line_end = GetActionTarget(1);
if (line_end->Contained()) line_end = line_end->Contained(); if (line_end && line_end->Contained())
line_end = line_end->Contained();
line_end->Message("$TxtLinebroke$"); if (line_end)
line_end->Message("$TxtLinebroke$");
return;
} }
/* Activation */
/*-- Activation --*/
local activations = 0; local activations = 0;
@ -67,7 +87,8 @@ local activations = 0;
public func Activation(int count) public func Activation(int count)
{ {
// Count must be > 0 // Count must be > 0
if (count < 1) return FatalError("Cable Line: Activation() was called with count < 1."); if (count < 1)
return FatalError("Cable Line: Activation() was called with count < 1.");
activations += count; activations += count;
if (GetActionTarget(0)) GetActionTarget(0)->~CableActivation(count); if (GetActionTarget(0)) GetActionTarget(0)->~CableActivation(count);
if (GetActionTarget(1)) GetActionTarget(1)->~CableActivation(count); if (GetActionTarget(1)) GetActionTarget(1)->~CableActivation(count);
@ -78,22 +99,29 @@ public func Activation(int count)
public func Deactivation(int count) public func Deactivation(int count)
{ {
// Count must be > 0 // Count must be > 0
if (count < 1) return FatalError("Cable Line: Deactivation() was called with count < 1."); if (count < 1)
return FatalError("Cable Line: Deactivation() was called with count < 1.");
activations -= count; activations -= count;
if (GetActionTarget(0)) GetActionTarget(0)->~CableDeactivation(count); if (GetActionTarget(0)) GetActionTarget(0)->~CableDeactivation(count);
if (GetActionTarget(1)) GetActionTarget(1)->~CableDeactivation(count); if (GetActionTarget(1)) GetActionTarget(1)->~CableDeactivation(count);
} }
/* Saving */
/*-- Saving --*/
public func SaveScenarioObject(props) public func SaveScenarioObject(props)
{ {
if (!inherited(props, ...)) return false; if (!inherited(props, ...))
return false;
SaveScenarioObjectAction(props); SaveScenarioObjectAction(props);
if (IsCableLine()) props->AddCall("Connection", this, "SetConnectedObjects", GetActionTarget(0), GetActionTarget(1)); if (IsCableLine())
props->AddCall("Connection", this, "SetConnectedObjects", GetActionTarget(0), GetActionTarget(1));
return true; return true;
} }
/*-- Properties --*/
local ActMap = { local ActMap = {
Connect = { Connect = {
Prototype = Action, Prototype = Action,
@ -103,4 +131,4 @@ local ActMap = {
} }
}; };
local Name = "$Name$"; local Name = "$Name$";

View File

@ -1,4 +1,9 @@
/*-- Cable reel --*/ /**
Cable reel
Connects cable stations.
@author Clonkonaut
*/
protected func Hit() protected func Hit()
{ {
@ -7,6 +12,7 @@ protected func Hit()
public func IsToolProduct() { return true; } public func IsToolProduct() { return true; }
/*-- Line connection --*/ /*-- Line connection --*/
protected func ControlUse(object clonk, int x, int y) protected func ControlUse(object clonk, int x, int y)
@ -32,7 +38,7 @@ protected func ControlUse(object clonk, int x, int y)
else else
{ {
// Connect existing power line to obj. // Connect existing power line to obj.
if(line->GetActionTarget(0) == this) if (line->GetActionTarget(0) == this)
line->SetActionTargets(obj, line->GetActionTarget(1)); line->SetActionTargets(obj, line->GetActionTarget(1));
else if(line->GetActionTarget(1) == this) else if(line->GetActionTarget(1) == this)
line->SetActionTargets(line->GetActionTarget(0), obj); line->SetActionTargets(line->GetActionTarget(0), obj);
@ -63,6 +69,9 @@ private func Find_CableLine(object obj)
return [C4FO_Func, "IsConnectedTo", obj]; return [C4FO_Func, "IsConnectedTo", obj];
} }
/*-- Properties --*/
local Name = "$Name$"; local Name = "$Name$";
local Description = "$Description$"; local Description = "$Description$";
local Collectible = 1; local Collectible = 1;

View File

@ -24,7 +24,8 @@ local lib_ccar_destination;
// Current delivery the car is on, array: [starting station, target station, requested objects, amount] // Current delivery the car is on, array: [starting station, target station, requested objects, amount]
local lib_ccar_delivery; local lib_ccar_delivery;
/*--- Overloads ---*/
/*-- Overloads --*/
// Overload these functions as you feel fit // Overload these functions as you feel fit
@ -52,7 +53,8 @@ func OnStart() {}
// failed is true if the movement to a destination was cancelled (usually because the path broke in the meantime) // failed is true if the movement to a destination was cancelled (usually because the path broke in the meantime)
func OnStop(bool failed) {} func OnStop(bool failed) {}
/*--- Interface ---*/
/*-- Interface --*/
// Sets the speed of the cable car // Sets the speed of the cable car
public func SetCableSpeed(int value) public func SetCableSpeed(int value)
@ -97,13 +99,14 @@ public func DoMovement()
var origin = CreateArray(2), ending = CreateArray(2); var origin = CreateArray(2), ending = CreateArray(2);
lib_ccar_rail->GetActionTarget(start)->GetCablePosition(origin, prec); lib_ccar_rail->GetActionTarget(start)->GetCablePosition(origin, prec);
lib_ccar_rail->GetActionTarget(end)->GetCablePosition(ending, prec); lib_ccar_rail->GetActionTarget(end)->GetCablePosition(ending, prec);
position[0] = origin[0] + (ending[0] - origin[0]) * lib_ccar_progress/lib_ccar_max_progress; position[0] = origin[0] + (ending[0] - origin[0]) * lib_ccar_progress / lib_ccar_max_progress;
position[1] = origin[1] + (ending[1] - origin[1]) * lib_ccar_progress/lib_ccar_max_progress; position[1] = origin[1] + (ending[1] - origin[1]) * lib_ccar_progress / lib_ccar_max_progress;
GetCableOffset(position, prec); GetCableOffset(position, prec);
SetPosition(position[0], position[1], 1, prec); SetPosition(position[0], position[1], 1, prec);
} }
/*--- Status ---*/
/*-- Status --*/
public func IsCableCar() { return true; } public func IsCableCar() { return true; }
@ -113,7 +116,8 @@ public func GetRailTarget() { return lib_ccar_rail; }
public func IsTravelling() { return lib_ccar_destination; } public func IsTravelling() { return lib_ccar_destination; }
/* Interaction */
/*-- Interaction --*/
// Provides an own interaction menu. // Provides an own interaction menu.
public func HasInteractionMenu() { return true; } public func HasInteractionMenu() { return true; }
@ -185,7 +189,9 @@ public func GetCableCarMenuEntries(object clonk)
}; };
PushBack(menu_entries, { symbol = this, extra_data = "NoStation", custom = search }); PushBack(menu_entries, { symbol = this, extra_data = "NoStation", custom = search });
} }
} else { }
else
{
// Start the trip // Start the trip
if (!IsTravelling()) if (!IsTravelling())
{ {
@ -227,12 +233,22 @@ public func OnCableCarHover(symbol, extra_data, desc_menu_target, menu_id)
GuiUpdate({ Text = text }, menu_id, 1, desc_menu_target); GuiUpdate({ Text = text }, menu_id, 1, desc_menu_target);
} }
/*--- Travelling ---*/
/*-- Travelling --*/
// Called when the network is updated.
public func OnRailNetworkUpdate()
{
// The car may have been stuck on a request, continue it now.
ContinueRequest();
return;
}
// Attach the car onto a crossing // Attach the car onto a crossing
public func EngageRail(object crossing, bool silent) public func EngageRail(object crossing, bool silent)
{ {
if (! crossing->~IsCableCrossing()) return false; if (!crossing->~IsCableCrossing())
return false;
var position = CreateArray(2); var position = CreateArray(2);
crossing->GetCablePosition(position); crossing->GetCablePosition(position);
@ -244,7 +260,8 @@ public func EngageRail(object crossing, bool silent)
SetComDir(COMD_None); SetComDir(COMD_None);
lib_ccar_rail = crossing; lib_ccar_rail = crossing;
lib_ccar_direction = nil; lib_ccar_direction = nil;
if (!silent) Sound("Objects::Connect"); if (!silent)
Sound("Objects::Connect");
UpdateInteractionMenus(this.GetCableCarMenuEntries); UpdateInteractionMenus(this.GetCableCarMenuEntries);
Engaged(); Engaged();
@ -262,21 +279,23 @@ public func DisengageRail()
UpdateInteractionMenus(this.GetCableCarMenuEntries); UpdateInteractionMenus(this.GetCableCarMenuEntries);
Disengaged(); Disengaged();
if (lib_ccar_rail) lib_ccar_rail->OnCableCarDisengaged(this); if (lib_ccar_rail)
lib_ccar_rail->OnCableCarDisengaged(this);
} }
// Sets a target point for travelling and starts the movement process // Sets a target point for travelling and starts the movement process
public func SetDestination(dest) public func SetDestination(dest)
{ {
if(GetType(dest) == C4V_Int) if (GetType(dest) == C4V_Int)
{ {
dest = FindObjects(Find_Func("IsCableCrossing"))[dest]; dest = FindObjects(Find_Func("IsCableCrossing"))[dest];
if (!dest) return; if (!dest)
return;
} }
lib_ccar_destination = dest; lib_ccar_destination = dest;
if(lib_ccar_direction == nil) if (lib_ccar_direction == nil)
{ {
OnStart(); OnStart();
CrossingReached(); CrossingReached();
@ -286,24 +305,25 @@ public func SetDestination(dest)
} }
// Whenever a crossing is reached it must be queried for the next crossing to go to // Whenever a crossing is reached it must be queried for the next crossing to go to
func CrossingReached() public func CrossingReached()
{ {
var target; var target;
if(lib_ccar_destination != lib_ccar_rail) if (lib_ccar_destination != lib_ccar_rail)
{ {
if(target = lib_ccar_rail->GetNextWaypoint(lib_ccar_destination)) if (target = lib_ccar_rail->GetNextWaypoint(lib_ccar_destination))
MoveTo(target); MoveTo(target);
else else
DestinationFailed(); DestinationFailed();
} }
// Destination reached // Destination reached
else { else
{
DestinationReached(); DestinationReached();
} }
} }
// When the current destination is reached // When the current destination is reached
func DestinationReached() public func DestinationReached()
{ {
lib_ccar_destination = nil; lib_ccar_destination = nil;
lib_ccar_direction = nil; lib_ccar_direction = nil;
@ -321,8 +341,11 @@ func DestinationReached()
} }
// When the way to the current destination has vanished somehow // When the way to the current destination has vanished somehow
func DestinationFailed() public func DestinationFailed()
{ {
if (lib_ccar_rail)
lib_ccar_rail->OnCableCarStopped(this);
lib_ccar_destination = nil; lib_ccar_destination = nil;
lib_ccar_direction = nil; lib_ccar_direction = nil;
lib_ccar_progress = 0; lib_ccar_progress = 0;
@ -331,8 +354,14 @@ func DestinationFailed()
OnStop(true); OnStop(true);
} }
public func Destruction()
{
if (lib_ccar_rail)
lib_ccar_rail->OnCableCarDestruction(this);
}
// Setup movement process // Setup movement process
func MoveToIndex(int dest) public func MoveToIndex(int dest)
{ {
var dest_obj = FindObjects(Find_Func("IsCableCrossing"))[dest]; var dest_obj = FindObjects(Find_Func("IsCableCrossing"))[dest];
if (dest_obj) return MoveTo(dest_obj); if (dest_obj) return MoveTo(dest_obj);
@ -341,19 +370,19 @@ func MoveToIndex(int dest)
public func MoveTo(object dest) public func MoveTo(object dest)
{ {
var rail = 0; var rail = 0;
for(var test_rail in FindObjects(Find_Func("IsConnectedTo", lib_ccar_rail))) for (var test_rail in FindObjects(Find_Func("IsConnectedTo", lib_ccar_rail)))
{ {
if(test_rail->IsConnectedTo(dest)) if (test_rail->IsConnectedTo(dest))
{ {
rail = test_rail; rail = test_rail;
break; break;
} }
} }
if(!rail) if (!rail)
return DestinationFailed(); // Shouldn't happen return DestinationFailed(); // Shouldn't happen
// Target the first or second action target? // Target the first or second action target?
if(rail->GetActionTarget(0) == dest) if (rail->GetActionTarget(0) == dest)
lib_ccar_direction = 0; lib_ccar_direction = 0;
else else
lib_ccar_direction = 1; lib_ccar_direction = 1;
@ -366,14 +395,14 @@ public func MoveTo(object dest)
lib_ccar_rail = rail; lib_ccar_rail = rail;
} }
/* Destination selection */
/*-- Destination selection --*/
public func OpenDestinationSelection(object clonk) public func OpenDestinationSelection(object clonk)
{ {
if (!clonk) return; if (!clonk) return;
if (!GetRailTarget()) return; if (!GetRailTarget()) return;
var plr = clonk->GetOwner();
// Close interaction menu // Close interaction menu
if (clonk->GetMenu()) if (clonk->GetMenu())
if (!clonk->TryCancelMenu()) if (!clonk->TryCancelMenu())
@ -382,6 +411,7 @@ public func OpenDestinationSelection(object clonk)
GUI_DestinationSelectionMenu->CreateFor(clonk, this, GetRailTarget()); GUI_DestinationSelectionMenu->CreateFor(clonk, this, GetRailTarget());
} }
/*-- Delivery --*/ /*-- Delivery --*/
public func AddRequest(proplist requested, int amount, proplist target, proplist source) public func AddRequest(proplist requested, int amount, proplist target, proplist source)
@ -390,9 +420,17 @@ public func AddRequest(proplist requested, int amount, proplist target, proplist
SetDestination(target); SetDestination(target);
} }
func FinishedRequest(object station) public func ContinueRequest()
{
if (!lib_ccar_delivery)
return;
var target = lib_ccar_delivery[1];
SetDestination(target);
}
public func FinishedRequest(object station)
{ {
if (station && lib_ccar_delivery) if (station && lib_ccar_delivery)
station->RequestArrived(this, lib_ccar_delivery[2], lib_ccar_delivery[3]); station->RequestArrived(this, lib_ccar_delivery[2], lib_ccar_delivery[3]);
lib_ccar_delivery = nil; lib_ccar_delivery = nil;
} }

View File

@ -26,6 +26,9 @@ public func CableDeactivation(int count) { }
// Called by arriving cable cars if this station is the final stop // Called by arriving cable cars if this station is the final stop
public func OnCableCarArrival(object car) { } public func OnCableCarArrival(object car) { }
// Called by cable cars if it stopped at this station (usually because of a problem)
public func OnCableCarStopped(object car) { }
// Called by departing cable cars if it just starts a new journey // Called by departing cable cars if it just starts a new journey
public func OnCableCarDeparture(object car) { } public func OnCableCarDeparture(object car) { }
@ -35,6 +38,9 @@ public func OnCableCarEngaged(object car) { }
// Called by a cable car that has been taken off the rail at this station // Called by a cable car that has been taken off the rail at this station
public func OnCableCarDisengaged(object car) { } 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 with a requested delivery arrives // Called when a cable car with a requested delivery arrives
public func OnCableCarDelivery(object car, id requested, int amount) { } public func OnCableCarDelivery(object car, id requested, int amount) { }
@ -56,26 +62,10 @@ public func Construction()
return _inherited(...); return _inherited(...);
} }
/* Removes this crossing from the network
It first clears every waypoint from the network and then renews the whole information.
Optimisation welcome!
*/
public func Destruction() public func Destruction()
{ {
for (var connection in FindObjects(Find_Func("IsConnectedTo", this))) // The connection with other stations is broken via the cable and the network updating is handled there.
{ // So there is updating to be performed here.
if (!connection->~IsCableLine()) continue;
var other_crossing = connection->~GetConnectedObject(this);
if (!other_crossing || !other_crossing->~IsCableCrossing()) continue;
other_crossing->ClearConnections(this);
}
for (var connection in FindObjects(Find_Func("IsConnectedTo", this)))
{
if (!connection->~IsCableLine()) continue;
var other_crossing = connection->~GetConnectedObject(this);
if (!other_crossing || !other_crossing->~IsCableCrossing()) continue;
other_crossing->RenewConnections(this);
}
return _inherited(...); return _inherited(...);
} }
@ -106,7 +96,8 @@ public func SetCableStation(bool station)
// Returns the cable hookup position for proper positioning of a car along the line. // Returns the cable hookup position for proper positioning of a car along the line.
public func GetCablePosition(array coordinates, int prec) public func GetCablePosition(array coordinates, int prec)
{ {
if (!prec) prec = 1; if (!prec)
prec = 1;
coordinates[0] = GetX(prec); coordinates[0] = GetX(prec);
coordinates[1] = GetY(prec); coordinates[1] = GetY(prec);
if (this.LineAttach) if (this.LineAttach)
@ -153,19 +144,23 @@ public func GetDestinationList(object middle)
AddCableConnection(object cable) AddCableConnection(object cable)
AddCableDestinations(array new_list, object crossing) AddCableDestinations(array new_list, object crossing)
AddCableDestination(object new_destination, object crossing, int distance_add) AddCableDestination(object new_destination, object crossing, int distance_add)
ClearConnections(object crossing) ClearConnections()
RenewConnections(object crossing) RenewConnections()
*/ */
/** Returns the destination array so it can be used by other crossings. /** Returns the destination array so it can be used by other crossings.
*/ */
public func GetDestinations() public func GetDestinations()
{ {
return destination_list[:]; // This is a nested array, so ensure a proper deep copy is made.
var deep_copy = [];
for (var dest in destination_list)
PushBack(deep_copy, dest[:]);
return deep_copy;
} }
// Stores the next crossing (waypoint) to take when advancing to a certain final point // Stores the next crossing (waypoint) to take when advancing to a certain final point. The list may not contain the crossing itself.
// Scheme (2D array): [Desired final point, Next waypoint to take, Distance (not airline!) until final point] // Scheme (2D array): [Desired final point, Next waypoint to take, Distance (not airline!) until final point].
local destination_list; local destination_list;
// Constants for easier script reading // Constants for easier script reading
@ -181,16 +176,25 @@ local const_distance = 2;
public func AddCableConnection(object cable) public func AddCableConnection(object cable)
{ {
// Failsafe // Failsafe
if (!cable || ! cable->~IsCableLine()) if (!cable || !cable->~IsCableLine())
return false; return false;
// Line setup finished? // Line setup finished?
var other_crossing = cable->~GetConnectedObject(this); var other_crossing = cable->~GetConnectedObject(this);
if (! other_crossing->~IsCableCrossing()) if (!other_crossing || !other_crossing->~IsCableCrossing())
return false; return false;
// Acquire destinations of the other crossing, all these are now in reach // Acquire destinations of the other crossing, all these are now in reach
AddCableDestinations(other_crossing->GetDestinations(), other_crossing); AddCableDestinations(other_crossing->GetDestinations(), other_crossing);
// Send own destinations, now in reach for the other one // Send own destinations, now in reach for the other one
other_crossing->AddCableDestinations(destination_list[:], this); other_crossing->AddCableDestinations(GetDestinations(), this);
// Awesome, more power to the network!
DestinationsUpdated();
return true;
}
public func RemoveCableConnection(object cable)
{
// It is easiest to just update all connections.
UpdateConnections();
// Awesome, more power to the network! // Awesome, more power to the network!
DestinationsUpdated(); DestinationsUpdated();
return true; return true;
@ -200,28 +204,28 @@ public func AddCableConnection(object cable)
* @param new_list The new destination list, formated like a crossing's normal destination list * @param new_list The new destination list, formated like a crossing's normal destination list
* @param crossing The crossing where this list comes from * @param crossing The crossing where this list comes from
*/ */
public func AddCableDestinations(array new_list, object crossing) public func AddCableDestinations(array new_list, object crossing, bool has_reversed)
{ {
// Append crossing to the list if (!crossing)
if (crossing) return false;
{ // Append crossing itself to the list with zero distance.
new_list[GetLength(new_list)] = [crossing, crossing]; new_list[GetLength(new_list)] = [crossing, crossing, 0];
// This value is to be added to every distance // This value is to be added to every distance
var distance_add = ObjectDistance(crossing); var distance_add = ObjectDistance(crossing);
}
else
return false; // Does not compute
// Check every new destination // Check every new destination
for (var list_item in new_list) for (var list_item in new_list)
{ {
if (!list_item) continue; if (!list_item)
// Destination is this continue;
if (list_item[const_finaldestination] == this) continue; // Destination may not be this crossing.
// Check whether the destination is already in reach if (list_item[const_finaldestination] == this)
continue;
// Check whether the destination is already in already in the list.
var handled = false; var handled = false;
for (var i = 0, destination = false; i < GetLength(destination_list); i++) for (var i = 0, destination = nil; i < GetLength(destination_list); i++)
{ {
if (!destination_list[i]) continue; if (!destination_list[i])
continue;
destination = destination_list[i]; destination = destination_list[i];
if (destination[const_finaldestination] == list_item[const_finaldestination]) if (destination[const_finaldestination] == list_item[const_finaldestination])
{ {
@ -231,18 +235,55 @@ public func AddCableDestinations(array new_list, object crossing)
{ {
// It is shorter, replace, route through crossing // It is shorter, replace, route through crossing
destination_list[i] = [list_item[const_finaldestination], crossing, list_item[const_distance] + distance_add]; destination_list[i] = [list_item[const_finaldestination], crossing, list_item[const_distance] + distance_add];
// Inform the destination // Inform the destination.
list_item[const_finaldestination]->UpdateCableDestination(this, crossing, distance_add); list_item[const_finaldestination]->UpdateCableDestination(this, crossing, distance_add);
} }
} }
} }
// Destination is replaced or to be dismissed (because the new path would be longer), do nothing
if (handled) continue; // Destination is replaced or to be dismissed (because the new path would be longer), do nothing.
// Destination is a new one, add to the list if (handled)
destination_list[GetLength(destination_list)] = [list_item[const_finaldestination], crossing, list_item[const_distance] + distance_add]; continue;
// Add me to the new destination (the way to me is the same than to crossing)
if (list_item[const_finaldestination] != crossing) // Destination is a new one, add to the list.
list_item[const_finaldestination]->AddCableDestination(this, crossing, distance_add); AddCableDestination(list_item[const_finaldestination], crossing, list_item[const_distance] + distance_add);
// Add me to the new destination (the way to me is the same than to crossing).
if (list_item[const_finaldestination] != crossing && !has_reversed)
{
// This new crossing may have a bunch of other connections that need to be explored and potentially added.
// The new crossing is connected to this crossing via the crossing specified as the parameter to this function.
// So for the new destinations we want to add, we need to add the distance to the crossing.
var add_destinations = list_item[const_finaldestination]->GetDestinations();
var add_dest_distance = 0;
for (var dest in crossing->GetDestinations())
if (dest[const_finaldestination] == list_item[const_finaldestination])
add_dest_distance = dest[const_distance];
for (var dest in add_destinations)
dest[const_distance] += add_dest_distance;
this->AddCableDestinations(add_destinations, crossing, has_reversed);
// However, this crossing and its destinations must also be added in reverse to the new crossing found.
var reverse_destinations = this->GetDestinations();
PushBack(reverse_destinations, [this, crossing, 0]);
var reverse_crossing = nil;
for (var dest in list_item[const_finaldestination]->GetDestinations())
if (dest[const_finaldestination] == crossing)
reverse_crossing = dest[const_nextwaypoint];
if (reverse_crossing == nil)
return FatalError("AddCableDestinations(): reverse_crossing not found.");
var add_reverse_distance = distance_add;
if (reverse_crossing != crossing)
{
for (var dest in reverse_crossing->GetDestinations())
if (dest[const_finaldestination] == crossing)
add_reverse_distance += dest[const_distance];
if (add_reverse_distance == distance_add)
return FatalError("AddCableDestinations(): reverse_distance not correct.");
}
for (var dest in reverse_destinations)
dest[const_distance] += add_reverse_distance;
list_item[const_finaldestination]->AddCableDestinations(reverse_destinations, reverse_crossing, true);
}
} }
DestinationsUpdated(); DestinationsUpdated();
return true; return true;
@ -253,28 +294,19 @@ public func AddCableDestinations(array new_list, object crossing)
* @param crossing The crossing which links to the new destination * @param crossing The crossing which links to the new destination
* @param distance_add The distance between crossing and new_destination * @param distance_add The distance between crossing and new_destination
*/ */
public func AddCableDestination(object new_destination, object crossing, int distance_add) public func AddCableDestination(object new_destination, object crossing, int distance)
{ {
// Failsafe // Failsafes.
if (!new_destination || !crossing) return false; if (!new_destination || !crossing)
if (new_destination == this) return false; return;
// Find the entry of crossing to get the next waypoint and the distance if (new_destination == this)
var crossing_item; return;
for (var list_item in destination_list) if (!IsDirectlyConnectToCrossing(crossing))
{ return FatalError(Format("destination to %v for %v is not connected to crossing link %v.", new_destination, this, crossing));
if (!list_item) continue; // Add to destination list.
if (list_item[const_finaldestination] == crossing) PushBack(destination_list, [new_destination, crossing, distance]);
{
crossing_item = list_item;
break;
}
}
// Failsafe
if (!crossing_item) return false;
// Save the new destination
destination_list[GetLength(destination_list)] = [new_destination, crossing_item[const_nextwaypoint], crossing_item[const_distance] + distance_add];
DestinationsUpdated(); DestinationsUpdated();
return true; return;
} }
/** Updates the path to \a known_destination via \a crossing (e.g. because the path is shorter through \a crossing) /** Updates the path to \a known_destination via \a crossing (e.g. because the path is shorter through \a crossing)
@ -291,7 +323,8 @@ public func UpdateCableDestination(object known_destination, object crossing, in
var crossing_item, destination_item, i = 0; var crossing_item, destination_item, i = 0;
for (var list_item in destination_list) for (var list_item in destination_list)
{ {
if (!list_item) continue; if (!list_item)
continue;
if (list_item[const_finaldestination] == crossing) if (list_item[const_finaldestination] == crossing)
crossing_item = list_item; crossing_item = list_item;
if (list_item[const_finaldestination] == known_destination) if (list_item[const_finaldestination] == known_destination)
@ -299,7 +332,8 @@ public func UpdateCableDestination(object known_destination, object crossing, in
i++; i++;
} }
// Failsafe // Failsafe
if (!crossing_item || !destination_item) return false; if (!crossing_item || !destination_item)
return false;
// Save the updated path // Save the updated path
destination_list[destination_item][const_nextwaypoint] = crossing_item[const_nextwaypoint]; destination_list[destination_item][const_nextwaypoint] = crossing_item[const_nextwaypoint];
destination_list[destination_item][const_distance] = crossing_item[const_distance] + distance_add; destination_list[destination_item][const_distance] = crossing_item[const_distance] + distance_add;
@ -309,42 +343,68 @@ public func UpdateCableDestination(object known_destination, object crossing, in
local clearing; local clearing;
/* Called automatically by Destruction, see description there // Updates the network for this crossing, this is called when a cable to this crossing has changed.
* @param crossing The calling crossing // It first clears every waypoint from the network and then renews the whole information.
*/ public func UpdateConnections()
public func ClearConnections(object crossing)
{ {
if (clearing) return; // Clear this crossing and then other connected crossings.
ClearConnections();
RenewConnections();
return;
}
// Called automatically by UpdateConnections, see description there.
public func ClearConnections()
{
if (clearing)
return;
clearing = true; clearing = true;
destination_list = []; destination_list = [];
for (var connection in FindObjects(Find_Func("IsConnectedTo", this))) for (var connection in FindObjects(Find_Func("IsConnectedTo", this)))
{ {
if (!connection->~IsCableLine()) continue; if (!connection->~IsCableLine())
continue;
var other_crossing = connection->~GetConnectedObject(this); var other_crossing = connection->~GetConnectedObject(this);
if (!other_crossing || !other_crossing->~IsCableCrossing()) continue; if (!other_crossing || !other_crossing->~IsCableCrossing())
continue;
other_crossing->ClearConnections(); other_crossing->ClearConnections();
} }
} }
/* Called automatically by Destruction, see description there // Called automatically by UpdateConnections, see description there.
* @param crossing The calling crossing public func RenewConnections()
*/
public func RenewConnections(object crossing)
{ {
if (!clearing) return; if (!clearing)
return;
clearing = false; clearing = false;
for(var connection in FindObjects(Find_Func("IsConnectedTo", this))) for (var connection in FindObjects(Find_Func("IsConnectedTo", this)))
{ {
if (!connection->~IsCableLine()) continue; if (!connection->~IsCableLine())
continue;
var other_crossing = connection->~GetConnectedObject(this); var other_crossing = connection->~GetConnectedObject(this);
if (!other_crossing || !other_crossing->~IsCableCrossing()) continue; if (!other_crossing || !other_crossing->~IsCableCrossing())
if (other_crossing == crossing) continue; continue;
destination_list[GetLength(destination_list)] = [other_crossing, other_crossing, ObjectDistance(other_crossing)]; PushBack(destination_list, [other_crossing, other_crossing, ObjectDistance(other_crossing)]);
AddCableDestinations(other_crossing->GetDestinations(), other_crossing); AddCableDestinations(other_crossing->GetDestinations(), other_crossing);
other_crossing->RenewConnections();
} }
} }
/*--- Pathfinding ---*/ // Returns whether there is a direct conenctions between this and the other crossing.
public func IsDirectlyConnectToCrossing(object other_crossing)
{
for (var connection in FindObjects(Find_Func("IsConnectedTo", this)))
{
if (!connection->~IsCableLine())
continue;
if (other_crossing == connection->~GetConnectedObject(this))
return true;
}
return false;
}
/*-- Pathfinding --*/
/* Functions: /* Functions:
GetNextWaypoint(object end) GetNextWaypoint(object end)
@ -356,10 +416,12 @@ public func RenewConnections(object crossing)
*/ */
public func GetNextWaypoint(object end) public func GetNextWaypoint(object end)
{ {
if (!destination_list) return nil; if (!destination_list)
return nil;
for (var item in destination_list) for (var item in destination_list)
{ {
if (!item) continue; if (!item)
continue;
if (item[const_finaldestination] == end) if (item[const_finaldestination] == end)
return item[const_nextwaypoint]; return item[const_nextwaypoint];
} }
@ -372,16 +434,19 @@ public func GetNextWaypoint(object end)
*/ */
public func GetLengthToTarget(object end) public func GetLengthToTarget(object end)
{ {
if (!destination_list) return nil; if (!destination_list)
return nil;
for (var item in destination_list) for (var item in destination_list)
{ {
if (!item) continue; if (!item)
continue;
if (item[const_finaldestination] == end) if (item[const_finaldestination] == end)
return item[const_distance]; return item[const_distance];
} }
return nil; return nil;
} }
/*-- Auto production --*/ /*-- Auto production --*/
local request_queue; local request_queue;
@ -410,12 +475,11 @@ public func AddRequest(proplist requested_id, int amount)
// Great. Start working immediately // Great. Start working immediately
PushBack(request_queue, [requested_id, amount]); PushBack(request_queue, [requested_id, amount]);
car->AddRequest(requested_id, amount, this, source); car->AddRequest(requested_id, amount, this, source);
return true; return true;
} }
// Check all connected stations for available objects // Check all connected stations for available objects
func CheckAvailability(proplist requested, int amount) public func CheckAvailability(proplist requested, int amount)
{ {
var nearest_station; var nearest_station;
var length_to; var length_to;
@ -494,4 +558,4 @@ public func RemoveRequest(id requested, int amount)
return false; return false;
RemoveArrayIndex(request_queue, i, true); RemoveArrayIndex(request_queue, i, true);
return true; return true;
} }

View File

@ -1,11 +1,11 @@
/*-- /**
Cable Crossing Cable Crossing
The standard crossing for the cable network. The standard crossing for the cable network.
The crossing will automatically be a station if it is at the end of the cable line (i.e. only one cable connected). The crossing will automatically be a station if it is at the end of the cable line (i.e. only one cable connected).
But the crossing can also manually be set to function as a station. But the crossing can also manually be set to function as a station.
Author: Clonkonaut @author Clonkonaut
--*/ */
#include Library_CableStation #include Library_CableStation
@ -32,7 +32,8 @@ func Initialize()
// Prevents the automatic change of the station status when manually set to station mode // Prevents the automatic change of the station status when manually set to station mode
local manual_setting = false; local manual_setting = false;
/* Library functions: Cable Station */
/*-- Library functions: Cable Station --*/
public func DestinationsUpdated() public func DestinationsUpdated()
{ {
@ -44,6 +45,11 @@ public func DestinationsUpdated()
else else
SetCableStation(false); SetCableStation(false);
CheckStationStatus(); CheckStationStatus();
// Inform all cars at station about the update.
for (var car in arrived_cars)
if (car)
car->~OnRailNetworkUpdate();
} }
public func IsAvailable(proplist requested, int amount) public func IsAvailable(proplist requested, int amount)
@ -107,7 +113,8 @@ public func OnCableCarDelivery(object car, id requested, int amount)
} }
} }
/* Construction */
/*-- Construction --*/
public func IsHammerBuildable() { return true; } public func IsHammerBuildable() { return true; }
@ -124,7 +131,7 @@ public func ConstructionCombineOffset(proplist other)
return; return;
// Make sure the station preview is on the same ground level than the other building // Make sure the station preview is on the same ground level than the other building
var ret = [0,0]; var ret = [0, 0];
ret[1] = other->GetObjHeight()/2 - this->GetDefHeight()/2; ret[1] = other->GetObjHeight()/2 - this->GetDefHeight()/2;
return ret; return ret;
} }
@ -238,7 +245,9 @@ public func ToggleDropOff(bool silent)
if (!IsCableStation()) if (!IsCableStation())
ToggleStation(true); ToggleStation(true);
setting_dropoff = true; setting_dropoff = true;
} else { }
else
{
setting_dropoff = false; setting_dropoff = false;
} }
if (!silent) if (!silent)
@ -246,7 +255,8 @@ public func ToggleDropOff(bool silent)
CheckStationStatus(); CheckStationStatus();
} }
/* Cable Car Management */
/*-- Cable Car Management --*/
public func OnCableCarArrival(object car) public func OnCableCarArrival(object car)
{ {
@ -259,6 +269,11 @@ public func OnCableCarArrival(object car)
PushBack(arrived_cars, car); PushBack(arrived_cars, car);
} }
public func OnCableCarStopped(object car)
{
PushBack(arrived_cars, car);
}
public func OnCableCarDeparture(object car) public func OnCableCarDeparture(object car)
{ {
RemoveArrayValue(arrived_cars, car, true); RemoveArrayValue(arrived_cars, car, true);
@ -274,19 +289,23 @@ public func OnCableCarDisengaged(object car)
RemoveArrayValue(arrived_cars, car, true); RemoveArrayValue(arrived_cars, car, true);
} }
/* Visuals */ public func OnCableCarDestruction(object car)
{
RemoveArrayValue(arrived_cars, car, true);
}
func CheckStationStatus()
/*-- Visuals --*/
public func CheckStationStatus()
{ {
if (IsCableStation()) if (IsCableStation())
{ {
// In order of priority // In order of priority
if (setting_dropoff) if (setting_dropoff)
{
SetMeshMaterial("CableCarStation_SignDropOff", 1); SetMeshMaterial("CableCarStation_SignDropOff", 1);
} else { else
SetMeshMaterial("CableCarStation_SignStation", 1); SetMeshMaterial("CableCarStation_SignStation", 1);
}
} }
else else
SetMeshMaterial("CableCarStation_Sign", 1); SetMeshMaterial("CableCarStation_Sign", 1);
@ -294,14 +313,14 @@ func CheckStationStatus()
local activations = 0; local activations = 0;
func CableActivation(int count) public func CableActivation(int count)
{ {
if (activations <= 0) if (activations <= 0)
SetAnimationPosition(turn_anim, Anim_Linear(GetAnimationPosition(turn_anim), 0, GetAnimationLength("Engine"), 175, ANIM_Loop)); SetAnimationPosition(turn_anim, Anim_Linear(GetAnimationPosition(turn_anim), 0, GetAnimationLength("Engine"), 175, ANIM_Loop));
activations += count; activations += count;
} }
func CableDeactivation(int count) public func CableDeactivation(int count)
{ {
activations -= count; activations -= count;
if (activations <= 0) if (activations <= 0)
@ -310,9 +329,10 @@ func CableDeactivation(int count)
public func NoConstructionFlip() { return true; } public func NoConstructionFlip() { return true; }
/* Saving */
func SaveScenarioObject(props) /*-- Saving --*/
public func SaveScenarioObject(props)
{ {
if (!inherited(props, ...)) return false; if (!inherited(props, ...)) return false;
if (IsCableStation() && manual_setting) if (IsCableStation() && manual_setting)
@ -327,7 +347,8 @@ func SaveScenarioObject(props)
public func SetManual() { manual_setting = true; return true; } public func SetManual() { manual_setting = true; return true; }
/* Properties */
/*-- Properties --*/
local Name = "$Name$"; local Name = "$Name$";
local BlastIncinerate = 50; local BlastIncinerate = 50;

View File

@ -3,5 +3,7 @@ Name=Seilbahnkreuzung
StationSettings=Seilbahneinstellungen StationSettings=Seilbahneinstellungen
TooltipToggleStation=Bahnhofs-Status umstellen. TooltipToggleStation=Bahnhofs-Status umstellen.
TooltipToggleDropOff=Toggle item dropping status
DescToggleStation=Diese Kreuzung von Hand zu einem Bahnhof oder wieder zu einer Kreuzung umschalten. Nur Bahnhöfe sind als Ziel wählbar und nur am Bahnhöfen können Fahrzeuge aufgesetzt werden. DescToggleStation=Diese Kreuzung von Hand zu einem Bahnhof oder wieder zu einer Kreuzung umschalten. Nur Bahnhöfe sind als Ziel wählbar und nur am Bahnhöfen können Fahrzeuge aufgesetzt werden.
DescToggleDropOff=All arriving vehicle are emptied upon arrival at this station (giving it is the final stop). Will also be set as a cable station.

View File

@ -1,20 +1,26 @@
/*-- Cable Hoist --*/ /**
Cable Hoist
@author Clonkonaut
*/
#include Library_CableCar #include Library_CableCar
local pickup; local pickup;
/* Creation */
func Construction() /*-- Creation --*/
public func Construction()
{ {
SetProperty("MeshTransformation",Trans_Rotate(13,0,1,0)); this.MeshTransformation = Trans_Rotate(13, 0, 1, 0);
SetCableSpeed(1); SetCableSpeed(1);
} }
/* Engine Callbacks */
func Damage(int change, int cause) /*-- Engine Callbacks --*/
public func Damage(int change, int cause)
{ {
if (cause == FX_Call_DmgBlast) if (cause == FX_Call_DmgBlast)
{ {
@ -26,25 +32,28 @@ func Damage(int change, int cause)
} }
} }
/* Status */
/*-- Status --*/
public func IsToolProduct() { return true; } public func IsToolProduct() { return true; }
/* Cable Car Library */
func GetCableOffset(array position, int prec) /*-- Cable Car Library --*/
public func GetCableOffset(array position, int prec)
{ {
if (!prec) prec = 1; if (!prec)
prec = 1;
position[1] += 5 * prec; position[1] += 5 * prec;
} }
func Engaged() public func Engaged()
{ {
this.Touchable = 0; this.Touchable = 0;
SetAction("OnRail"); SetAction("OnRail");
} }
func Disengaged() public func Disengaged()
{ {
this.Touchable = 1; this.Touchable = 1;
SetAction("Idle"); SetAction("Idle");
@ -52,9 +61,10 @@ func Disengaged()
DropVehicle(); DropVehicle();
} }
func GetCableCarExtraMenuEntries(array menu_entries, proplist custom_entry, object clonk) public func GetCableCarExtraMenuEntries(array menu_entries, proplist custom_entry, object clonk)
{ {
if (IsTravelling()) return; if (IsTravelling())
return;
if (!pickup && GetRailTarget()) if (!pickup && GetRailTarget())
{ {
@ -103,7 +113,8 @@ public func OnCableCarHover(symbol, extra_data, desc_menu_target, menu_id)
return _inherited(symbol, extra_data, desc_menu_target, menu_id, ...); return _inherited(symbol, extra_data, desc_menu_target, menu_id, ...);
} }
/* Picking up vehicles */
/*-- Picking up vehicles --*/
public func PickupVehicle(object vehicle) public func PickupVehicle(object vehicle)
{ {
@ -155,9 +166,10 @@ local FxCableHoistPickup = new Effect
} }
}; };
/* Actions */
func OnRail() /*-- Actions --*/
public func OnRail()
{ {
DoMovement(); DoMovement();
} }
@ -180,7 +192,8 @@ local ActMap = {
}, },
}; };
/* Callbacks */
/*-- Callbacks --*/
public func GetAttachedVehicle() public func GetAttachedVehicle()
{ {
@ -230,15 +243,15 @@ public func OverridePriority(proplist requested, int amount, proplist requesting
// Check if the connected vehicle holds the requested objects and if yes, override the selection // 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) >= amount)
return true; return true;
return false; return false;
} }
/* Definition */
func Definition(def) /*-- Definition --*/
public func Definition(def)
{ {
SetProperty("PictureTransformation",Trans_Mul(Trans_Rotate(-25,1,0,0),Trans_Rotate(40,0,1,0)),def); def.PictureTransformation = Trans_Mul(Trans_Rotate(-25, 1, 0, 0), Trans_Rotate(40, 0, 1, 0));
} }
local Name = "$Name$"; local Name = "$Name$";

View File

@ -12,23 +12,23 @@ local empty_anim;
/*-- Engine Callbacks --*/ /*-- Engine Callbacks --*/
func Construction() public func Construction()
{ {
SetProperty("MeshTransformation", Trans_Rotate(13, 0, 1, 0)); SetProperty("MeshTransformation", Trans_Rotate(13, 0, 1, 0));
} }
func Initialize() public func Initialize()
{ {
drive_anim = PlayAnimation("Drive", 1, Anim_X(0,0, GetAnimationLength("Drive"), 30), Anim_Const(1000)); drive_anim = PlayAnimation("Drive", 1, Anim_X(0,0, GetAnimationLength("Drive"), 30), Anim_Const(1000));
empty_anim = PlayAnimation("Empty", 2, Anim_Const(0), Anim_Const(0)); empty_anim = PlayAnimation("Empty", 2, Anim_Const(0), Anim_Const(0));
} }
func Hit3() public func Hit3()
{ {
Sound("Hits::Materials::Metal::DullMetalHit?"); Sound("Hits::Materials::Metal::DullMetalHit?");
} }
func RejectCollect(id object_id, object obj) public func RejectCollect(id object_id, object obj)
{ {
// Collection maybe blocked if this object was just dumped. // Collection maybe blocked if this object was just dumped.
if (!obj->Contained() && GetEffect("BlockCollectionByLorry", obj)) if (!obj->Contained() && GetEffect("BlockCollectionByLorry", obj))
@ -59,7 +59,7 @@ func RejectCollect(id object_id, object obj)
} }
// Automatic unloading in buildings. // Automatic unloading in buildings.
func Entrance(object container) public func Entrance(object container)
{ {
// Only in buildings // Only in buildings
if (container->GetCategory() & (C4D_StaticBack | C4D_Structure)) if (container->GetCategory() & (C4D_StaticBack | C4D_Structure))
@ -69,19 +69,19 @@ func Entrance(object container)
container->GrabContents(this); container->GrabContents(this);
} }
func ContactLeft() public func ContactLeft()
{ {
if (Stuck() && !Random(5)) if (Stuck() && !Random(5))
SetRDir(RandomX(-7, +7)); SetRDir(RandomX(-7, +7));
} }
func ContactRight() public func ContactRight()
{ {
if (Stuck() && !Random(5)) if (Stuck() && !Random(5))
SetRDir(RandomX(-7, +7)); SetRDir(RandomX(-7, +7));
} }
func Damage(int change, int cause, int by_player) public func Damage(int change, int cause, int by_player)
{ {
// Only explode the lorry on blast damage. // Only explode the lorry on blast damage.
if (cause != FX_Call_DmgBlast) if (cause != FX_Call_DmgBlast)
@ -144,7 +144,7 @@ public func DropContents(proplist station)
ScheduleCall(this, "Empty", 35); ScheduleCall(this, "Empty", 35);
} }
func Empty() public func Empty()
{ {
// Exit everything at once (as opposed to manual dumping below) // Exit everything at once (as opposed to manual dumping below)
while (Contents()) while (Contents())

View File

@ -144,6 +144,7 @@ func InitializeObjects()
CableLine019->SetConnectedObjects(CableCrossing019, CableCrossing003); CableLine019->SetConnectedObjects(CableCrossing019, CableCrossing003);
var ToolsWorkshop001 = CreateObjectAbove(ToolsWorkshop, 76, 388); var ToolsWorkshop001 = CreateObjectAbove(ToolsWorkshop, 76, 388);
CableCrossing019->CombineWith(ToolsWorkshop001);
var CableHoist001 = CreateObjectAbove(CableHoist, 560, 384); var CableHoist001 = CreateObjectAbove(CableHoist, 560, 384);
CableHoist001->SetComDir(COMD_None); CableHoist001->SetComDir(COMD_None);

View File

@ -150,6 +150,10 @@ protected func InitializePlayer(int plr)
// No FOW here. // No FOW here.
//SetFoW(false, plr); //SetFoW(false, plr);
JoinPlayer(plr); JoinPlayer(plr);
// Give all knowledge.
var index = 0, def;
while (def = GetDefinition(index++))
SetPlrKnowledge(plr, def);
return; return;
} }

View File

@ -56,10 +56,10 @@ protected func InitializePlayer(int plr)
SetPlrKnowledge(plr, def); SetPlrKnowledge(plr, def);
// Add test control effect. // Add test control effect.
var effect = AddEffect("IntTestControl", nil, 100, 2); var fx = AddEffect("IntTestControl", nil, 100, 2);
effect.testnr = 1; fx.testnr = 7;
effect.launched = false; fx.launched = false;
effect.plr = plr; fx.plr = plr;
return; return;
} }
@ -191,7 +191,7 @@ global func Test1_OnStart(int plr)
workshop->AddToQueue(Shovel, 2); workshop->AddToQueue(Shovel, 2);
// Log what the test is about. // Log what the test is about.
Log("A workshop needs material to produce 2 shovels, lorry in system has materials."); Log("A workshop needs material to produce shovels, lorry in system has materials.");
return true; return true;
} }
@ -288,11 +288,13 @@ global func Test3_OnStart(int plr)
var workshop = CreateObjectAbove(ToolsWorkshop, 40, 160, plr); var workshop = CreateObjectAbove(ToolsWorkshop, 40, 160, plr);
crossing1->CombineWith(workshop); crossing1->CombineWith(workshop);
workshop->AddToQueue(Shovel, 2); workshop->AddToQueue(Shovel, 1);
ScheduleCall(line_to_break, "OnLineBreak", 36, 0, true); ScheduleCall(line_to_break, "OnLineBreak", 36, 0, true);
ScheduleCall(line_to_break, "RemoveObject", 37, 0, true); ScheduleCall(line_to_break, "RemoveObject", 37, 0, true);
ScheduleCall(nil, "PrintCableCarNetwork", 38, 0);
ScheduleCall(nil, "CreateCableCrossingsConnection", 240, 0, crossing2, crossing3); ScheduleCall(nil, "CreateCableCrossingsConnection", 240, 0, crossing2, crossing3);
ScheduleCall(nil, "PrintCableCarNetwork", 241, 0);
// Log what the test is about. // Log what the test is about.
Log("Check if a delivery is continued when a cable breaks and is repaired."); Log("Check if a delivery is continued when a cable breaks and is repaired.");
@ -301,7 +303,7 @@ global func Test3_OnStart(int plr)
global func Test3_Completed() global func Test3_Completed()
{ {
if (ObjectCount(Find_ID(Shovel)) >= 2) if (ObjectCount(Find_ID(Shovel)) >= 1)
return true; return true;
return false; return false;
} }
@ -319,26 +321,30 @@ global func Test4_OnStart(int plr)
var crossing1 = CreateObjectAbove(CableCrossing, 70, 160, plr); var crossing1 = CreateObjectAbove(CableCrossing, 70, 160, plr);
var crossing2 = CreateObjectAbove(CableCrossing, 216, 64, plr); var crossing2 = CreateObjectAbove(CableCrossing, 216, 64, plr);
var crossing3 = CreateObjectAbove(CableCrossing, 272, 64, plr); var crossing3 = CreateObjectAbove(CableCrossing, 244, 64, plr);
var crossing4 = CreateObjectAbove(CableCrossing, 450, 104, plr); var crossing4 = CreateObjectAbove(CableCrossing, 272, 64, plr);
var crossing5 = CreateObjectAbove(CableCrossing, 450, 104, plr);
CreateCableCrossingsConnection(crossing1, crossing2); CreateCableCrossingsConnection(crossing1, crossing2);
CreateCableCrossingsConnection(crossing2, crossing3); CreateCableCrossingsConnection(crossing2, crossing3);
CreateCableCrossingsConnection(crossing3, crossing4); CreateCableCrossingsConnection(crossing3, crossing4);
CreateCableCrossingsConnection(crossing4, crossing5);
var hoist = crossing4->CreateObject(CableHoist); var hoist = crossing5->CreateObject(CableHoist);
hoist->EngageRail(crossing4); hoist->EngageRail(crossing5);
var lorry = crossing4->CreateObject(CableLorry); var lorry = crossing5->CreateObject(CableLorry);
hoist->PickupVehicle(lorry); hoist->PickupVehicle(lorry);
lorry->CreateContents(Metal, 2); lorry->CreateContents(Metal, 2);
lorry->CreateContents(Wood, 2); lorry->CreateContents(Wood, 2);
var workshop = CreateObjectAbove(ToolsWorkshop, 40, 160, plr); var workshop = CreateObjectAbove(ToolsWorkshop, 40, 160, plr);
crossing1->CombineWith(workshop); crossing1->CombineWith(workshop);
workshop->AddToQueue(Shovel, 2); workshop->AddToQueue(Shovel, 1);
ScheduleCall(crossing2, "RemoveObject", 36, 0, true); ScheduleCall(crossing3, "RemoveObject", 36, 0, true);
ScheduleCall(nil, "CreateCableCrossingsConnection", 240, 0, crossing1, crossing3); ScheduleCall(nil, "PrintCableCarNetwork", 37, 0);
ScheduleCall(nil, "CreateCableCrossingsConnection", 240, 0, crossing2, crossing4);
ScheduleCall(nil, "PrintCableCarNetwork", 241, 0);
// Log what the test is about. // Log what the test is about.
Log("Check if a delivery is continued when a station is destroyed."); Log("Check if a delivery is continued when a station is destroyed.");
@ -347,7 +353,7 @@ global func Test4_OnStart(int plr)
global func Test4_Completed() global func Test4_Completed()
{ {
if (ObjectCount(Find_ID(Shovel)) >= 2) if (ObjectCount(Find_ID(Shovel)) >= 1)
return true; return true;
return false; return false;
} }
@ -358,7 +364,6 @@ global func Test4_OnFinished()
return; return;
} }
global func Test5_OnStart(int plr) global func Test5_OnStart(int plr)
{ {
SetWindFixed(50); SetWindFixed(50);
@ -464,7 +469,7 @@ global func Test6_OnStart(int plr)
var drain = CreateObjectAbove(Pipe, 80, 300, plr); var drain = CreateObjectAbove(Pipe, 80, 300, plr);
drain->ConnectPipeTo(pump, PIPE_STATE_Drain); drain->ConnectPipeTo(pump, PIPE_STATE_Drain);
Schedule(nil, "CreateObject(Dynamite, 482, 266)->Fuse()", 180, 10**6); Schedule(nil, "CreateObject(Rock, 480, 274)", 36, 10**6);
// Log what the test is about. // Log what the test is about.
Log("Test automated concrete production line."); Log("Test automated concrete production line.");
@ -539,6 +544,141 @@ global func Test7_OnFinished()
return; return;
} }
global func Test8_OnStart(int plr)
{
ClearFreeRect(0, 0, LandscapeWidth(), LandscapeHeight());
var nr_crossings = RandomX(6, 12);
var connect_chance = 20; // In percent.
var start_time = GetTime();
var crossings = [];
for (var cnt = 0; cnt < nr_crossings; cnt++)
PushBack(crossings, CreateObjectAbove(CableCrossing, RandomX(10, LandscapeWidth() - 10), RandomX(20, LandscapeHeight() - 20), plr));
var nr_connections = 0;
for (var c1 in crossings)
{
for (var c2 in crossings)
{
if (c1 != c2 && Random(100) < connect_chance)
{
CreateCableCrossingsConnection(c1, c2);
nr_connections++;
}
}
}
// Log what the test is about.
Log("Test a random network for symmetric distance measures.");
var time = GetTime() - start_time;
Log("It took %d ms to create %d stations with %d connections.", time, nr_crossings, nr_connections);
return true;
}
global func Test8_Completed()
{
if (IsSymmetricCableCarNetwork())
return true;
return false;
}
global func Test8_OnFinished()
{
RemoveTestObjects();
return;
}
/*-- Cable Network Functions --*/
global func CreateCableCrossingsConnection(object c1, object c2)
{
var cable = c1->CreateObject(CableLine);
cable->SetConnectedObjects(c1, c2);
// Log the distance the cable covers of the cable.
var dummy = CreateObject(Dummy, (c1->GetX() + c2->GetX()) / 2, (c1->GetY() + c2->GetY()) / 2);
dummy->SetCategory(C4D_StaticBack);
dummy.Visibility = VIS_All;
dummy->Message("@<c 141432>%d</c>", ObjectDistance(c1, c2));
cable->CreateEffect(FxRemoveWith, 1, 0, dummy);
return cable;
}
static const FxRemoveWith = new Effect
{
Construction = func(object to_remove)
{
this.to_remove = to_remove;
},
Destruction = func()
{
this.to_remove->RemoveObject();
}
};
global func CreateObjectAbove(id obj, ...)
{
var res = _inherited(obj, ...);
if (obj == CableCrossing)
res->Message("@<c aa0000>%d</c>", res->ObjectNumber());
return res;
}
global func PrintCableCarNetwork()
{
Log("Distances between all of the cable crossings:");
var cable_crossings = FindObjects(Find_Func("IsCableCrossing"));
var header = "Obj# |";
var line = "------";
for (var crossing in cable_crossings)
{
//Log("%v: %v", crossing, crossing->GetDestinations());
header = Format("%s %04d", header, crossing->ObjectNumber());
line = Format("%s-----", line);
}
Log(header);
Log(line);
for (var crossing1 in cable_crossings)
{
var msg = Format("%04d |", crossing1->ObjectNumber());
for (var crossing2 in cable_crossings)
{
var len = crossing1->GetLengthToTarget(crossing2);
msg = Format("%s %04d", msg, len);
}
Log(msg);
}
Log(line);
if (!IsSymmetricCableCarNetwork())
Log("WARNING: distance table is not symmetric.");
return;
}
global func IsSymmetricCableCarNetwork()
{
var cable_crossings = FindObjects(Find_Func("IsCableCrossing"));
var dist_table = [];
var index1 = 0;
for (var crossing1 in cable_crossings)
{
var index2 = 0;
dist_table[index1] = [];
for (var crossing2 in cable_crossings)
{
var len = crossing1->GetLengthToTarget(crossing2);
dist_table[index1][index2] = len;
index2++;
}
index1++;
}
var is_symmetric = true;
for (var index1 = 0; index1 < GetLength(dist_table); index1++)
for (var index2 = index1 + 1; index2 < GetLength(dist_table); index2++)
if (dist_table[index1][index2] != dist_table[index2][index1])
is_symmetric = false;
return is_symmetric;
}
/*-- Helper Functions --*/ /*-- Helper Functions --*/
@ -608,40 +748,3 @@ global func RemoveTestObjects()
)); ));
return; return;
} }
global func CreateCableCrossingsConnection(object c1, object c2)
{
var cable = c1->CreateObject(CableLine);
cable->SetConnectedObjects(c1, c2);
return cable;
}
global func PrintCableCarNetwork()
{
Log("Distances between all of the cable crossings:");
var cable_crossings = FindObjects(Find_Func("IsCableCrossing"));
var header = "Obj# |";
var line = "------";
for (var crossing in cable_crossings)
{
header = Format("%s %04d", header, crossing->ObjectNumber());
line = Format("%s-----", line);
}
Log(Format("%s tot", header));
Log(Format("%s-----", line));
for (var crossing1 in cable_crossings)
{
var msg = Format("%04d |", crossing1->ObjectNumber());
var sum = 0;
for (var crossing2 in cable_crossings)
{
var len = crossing1->GetLengthToTarget(crossing2);
sum += len;
msg = Format("%s %04d", msg, len);
}
msg = Format("%s %04d", msg, sum);
Log(msg);
}
return;
}