From d8736a56ac5133df65a9b3e97257b3122972e125 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 28 Jan 2018 12:47:36 +0100 Subject: [PATCH] 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. --- .../CableReel.ocd/CableLine.ocd/Script.c | 64 +++-- .../Items.ocd/CableReel.ocd/Script.c | 13 +- .../Libraries.ocd/CableCar.ocd/Script.c | 96 +++++-- .../Libraries.ocd/CableStation.ocd/Script.c | 260 +++++++++++------- .../Structures.ocd/Crossing.ocd/Script.c | 57 ++-- .../Crossing.ocd/StringTblDE.txt | 4 +- .../Vehicles.ocd/Hoist.ocd/Script.c | 57 ++-- .../Vehicles.ocd/Lorry.ocd/Script.c | 18 +- .../CableLorrys.ocs/Objects.c | 1 + .../Experimental.ocf/CableLorrys.ocs/Script.c | 4 + planet/Tests.ocf/CableCars.ocs/Script.c | 213 ++++++++++---- 11 files changed, 535 insertions(+), 252 deletions(-) diff --git a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Items.ocd/CableReel.ocd/CableLine.ocd/Script.c b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Items.ocd/CableReel.ocd/CableLine.ocd/Script.c index 89bceeb8a..13177d2e6 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Items.ocd/CableReel.ocd/CableLine.ocd/Script.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Items.ocd/CableReel.ocd/CableLine.ocd/Script.c @@ -1,6 +1,10 @@ -/*-- Cable line --*/ +/** + Cable line -func Initialize() + @author Clonkonaut +*/ + +public func Initialize() { SetAction("Connect"); SetVertexXY(0, GetX(), GetY()); @@ -37,28 +41,44 @@ public func GetConnectedObject(object obj) return GetActionTarget(0); } -/* Breaking */ -func LineBreak(bool no_msg) +/*-- Breaking --*/ + +public func OnLineBreak(bool no_msg) { Sound("Objects::Connect"); - if (GetActionTarget(0)) GetActionTarget(0)->~CableDeactivation(activations); - if (GetActionTarget(1)) GetActionTarget(1)->~CableDeactivation(activations); + var act1 = GetActionTarget(0); + 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) BreakMessage(); } -func BreakMessage() +public func BreakMessage() { var line_end = GetActionTarget(0); - if (line_end->GetID() != CableLorryReel) + if (!line_end || line_end->GetID() != CableLorryReel) line_end = GetActionTarget(1); - if (line_end->Contained()) line_end = line_end->Contained(); - - line_end->Message("$TxtLinebroke$"); + if (line_end && line_end->Contained()) + line_end = line_end->Contained(); + if (line_end) + line_end->Message("$TxtLinebroke$"); + return; } -/* Activation */ + +/*-- Activation --*/ local activations = 0; @@ -67,7 +87,8 @@ local activations = 0; public func Activation(int count) { // 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; if (GetActionTarget(0)) GetActionTarget(0)->~CableActivation(count); if (GetActionTarget(1)) GetActionTarget(1)->~CableActivation(count); @@ -78,22 +99,29 @@ public func Activation(int count) public func Deactivation(int count) { // 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; if (GetActionTarget(0)) GetActionTarget(0)->~CableDeactivation(count); if (GetActionTarget(1)) GetActionTarget(1)->~CableDeactivation(count); } -/* Saving */ + +/*-- Saving --*/ public func SaveScenarioObject(props) { - if (!inherited(props, ...)) return false; + if (!inherited(props, ...)) + return false; 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; } + +/*-- Properties --*/ + local ActMap = { Connect = { Prototype = Action, @@ -103,4 +131,4 @@ local ActMap = { } }; -local Name = "$Name$"; \ No newline at end of file +local Name = "$Name$"; diff --git a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Items.ocd/CableReel.ocd/Script.c b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Items.ocd/CableReel.ocd/Script.c index e8c0b5b36..dcb9af3e6 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Items.ocd/CableReel.ocd/Script.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Items.ocd/CableReel.ocd/Script.c @@ -1,4 +1,9 @@ -/*-- Cable reel --*/ +/** + Cable reel + Connects cable stations. + + @author Clonkonaut +*/ protected func Hit() { @@ -7,6 +12,7 @@ protected func Hit() public func IsToolProduct() { return true; } + /*-- Line connection --*/ protected func ControlUse(object clonk, int x, int y) @@ -32,7 +38,7 @@ protected func ControlUse(object clonk, int x, int y) else { // Connect existing power line to obj. - if(line->GetActionTarget(0) == this) + if (line->GetActionTarget(0) == this) line->SetActionTargets(obj, line->GetActionTarget(1)); else if(line->GetActionTarget(1) == this) line->SetActionTargets(line->GetActionTarget(0), obj); @@ -63,6 +69,9 @@ private func Find_CableLine(object obj) return [C4FO_Func, "IsConnectedTo", obj]; } + +/*-- Properties --*/ + local Name = "$Name$"; local Description = "$Description$"; local Collectible = 1; diff --git a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableCar.ocd/Script.c b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableCar.ocd/Script.c index f63281f44..b94a89c89 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableCar.ocd/Script.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableCar.ocd/Script.c @@ -24,7 +24,8 @@ local lib_ccar_destination; // Current delivery the car is on, array: [starting station, target station, requested objects, amount] local lib_ccar_delivery; -/*--- Overloads ---*/ + +/*-- Overloads --*/ // 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) func OnStop(bool failed) {} -/*--- Interface ---*/ + +/*-- Interface --*/ // Sets the speed of the cable car public func SetCableSpeed(int value) @@ -97,13 +99,14 @@ public func DoMovement() var origin = CreateArray(2), ending = CreateArray(2); lib_ccar_rail->GetActionTarget(start)->GetCablePosition(origin, 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[1] = origin[1] + (ending[1] - origin[1]) * 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; GetCableOffset(position, prec); SetPosition(position[0], position[1], 1, prec); } -/*--- Status ---*/ + +/*-- Status --*/ public func IsCableCar() { return true; } @@ -113,7 +116,8 @@ public func GetRailTarget() { return lib_ccar_rail; } public func IsTravelling() { return lib_ccar_destination; } -/* Interaction */ + +/*-- Interaction --*/ // Provides an own interaction menu. public func HasInteractionMenu() { return true; } @@ -185,7 +189,9 @@ public func GetCableCarMenuEntries(object clonk) }; PushBack(menu_entries, { symbol = this, extra_data = "NoStation", custom = search }); } - } else { + } + else + { // Start the trip 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); } -/*--- 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 public func EngageRail(object crossing, bool silent) { - if (! crossing->~IsCableCrossing()) return false; + if (!crossing->~IsCableCrossing()) + return false; var position = CreateArray(2); crossing->GetCablePosition(position); @@ -244,7 +260,8 @@ public func EngageRail(object crossing, bool silent) SetComDir(COMD_None); lib_ccar_rail = crossing; lib_ccar_direction = nil; - if (!silent) Sound("Objects::Connect"); + if (!silent) + Sound("Objects::Connect"); UpdateInteractionMenus(this.GetCableCarMenuEntries); Engaged(); @@ -262,21 +279,23 @@ public func DisengageRail() UpdateInteractionMenus(this.GetCableCarMenuEntries); 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 public func SetDestination(dest) { - if(GetType(dest) == C4V_Int) + if (GetType(dest) == C4V_Int) { dest = FindObjects(Find_Func("IsCableCrossing"))[dest]; - if (!dest) return; + if (!dest) + return; } lib_ccar_destination = dest; - if(lib_ccar_direction == nil) + if (lib_ccar_direction == nil) { OnStart(); 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 -func CrossingReached() +public func CrossingReached() { 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); else DestinationFailed(); } // Destination reached - else { + else + { DestinationReached(); } } // When the current destination is reached -func DestinationReached() +public func DestinationReached() { lib_ccar_destination = nil; lib_ccar_direction = nil; @@ -321,8 +341,11 @@ func DestinationReached() } // 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_direction = nil; lib_ccar_progress = 0; @@ -331,8 +354,14 @@ func DestinationFailed() OnStop(true); } +public func Destruction() +{ + if (lib_ccar_rail) + lib_ccar_rail->OnCableCarDestruction(this); +} + // Setup movement process -func MoveToIndex(int dest) +public func MoveToIndex(int dest) { var dest_obj = FindObjects(Find_Func("IsCableCrossing"))[dest]; if (dest_obj) return MoveTo(dest_obj); @@ -341,19 +370,19 @@ func MoveToIndex(int dest) public func MoveTo(object dest) { 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; break; } } - if(!rail) + if (!rail) return DestinationFailed(); // Shouldn't happen // Target the first or second action target? - if(rail->GetActionTarget(0) == dest) + if (rail->GetActionTarget(0) == dest) lib_ccar_direction = 0; else lib_ccar_direction = 1; @@ -366,14 +395,14 @@ public func MoveTo(object dest) lib_ccar_rail = rail; } -/* Destination selection */ + +/*-- Destination selection --*/ public func OpenDestinationSelection(object clonk) { if (!clonk) return; if (!GetRailTarget()) return; - var plr = clonk->GetOwner(); // Close interaction menu if (clonk->GetMenu()) if (!clonk->TryCancelMenu()) @@ -382,6 +411,7 @@ public func OpenDestinationSelection(object clonk) GUI_DestinationSelectionMenu->CreateFor(clonk, this, GetRailTarget()); } + /*-- Delivery --*/ 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); } -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) station->RequestArrived(this, lib_ccar_delivery[2], lib_ccar_delivery[3]); lib_ccar_delivery = nil; -} \ No newline at end of file +} diff --git a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableStation.ocd/Script.c b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableStation.ocd/Script.c index ec377bf9b..cb2324886 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableStation.ocd/Script.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableStation.ocd/Script.c @@ -26,6 +26,9 @@ public func CableDeactivation(int count) { } // Called by arriving cable cars if this station is the final stop 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 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 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 public func OnCableCarDelivery(object car, id requested, int amount) { } @@ -56,26 +62,10 @@ public func Construction() 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() { - 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->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); - } + // 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. 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. public func GetCablePosition(array coordinates, int prec) { - if (!prec) prec = 1; + if (!prec) + prec = 1; coordinates[0] = GetX(prec); coordinates[1] = GetY(prec); if (this.LineAttach) @@ -153,19 +144,23 @@ public func GetDestinationList(object middle) AddCableConnection(object cable) AddCableDestinations(array new_list, object crossing) AddCableDestination(object new_destination, object crossing, int distance_add) - ClearConnections(object crossing) - RenewConnections(object crossing) + ClearConnections() + RenewConnections() */ /** Returns the destination array so it can be used by other crossings. */ 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 -// Scheme (2D array): [Desired final point, Next waypoint to take, Distance (not airline!) until 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]. local destination_list; // Constants for easier script reading @@ -181,16 +176,25 @@ local const_distance = 2; public func AddCableConnection(object cable) { // Failsafe - if (!cable || ! cable->~IsCableLine()) + if (!cable || !cable->~IsCableLine()) return false; // Line setup finished? var other_crossing = cable->~GetConnectedObject(this); - if (! other_crossing->~IsCableCrossing()) + if (!other_crossing || !other_crossing->~IsCableCrossing()) return false; // Acquire destinations of the other crossing, all these are now in reach AddCableDestinations(other_crossing->GetDestinations(), other_crossing); // 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! DestinationsUpdated(); 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 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) - { - new_list[GetLength(new_list)] = [crossing, crossing]; - // This value is to be added to every distance - var distance_add = ObjectDistance(crossing); - } - else - return false; // Does not compute + if (!crossing) + return false; + // Append crossing itself to the list with zero distance. + new_list[GetLength(new_list)] = [crossing, crossing, 0]; + // This value is to be added to every distance + var distance_add = ObjectDistance(crossing); // Check every new destination for (var list_item in new_list) { - if (!list_item) continue; - // Destination is this - if (list_item[const_finaldestination] == this) continue; - // Check whether the destination is already in reach + if (!list_item) + continue; + // Destination may not be this crossing. + if (list_item[const_finaldestination] == this) + continue; + // Check whether the destination is already in already in the list. 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]; 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 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); } } } - // Destination is replaced or to be dismissed (because the new path would be longer), do nothing - if (handled) continue; - // Destination is a new one, add to the list - destination_list[GetLength(destination_list)] = [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) - list_item[const_finaldestination]->AddCableDestination(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 a new one, add to the list. + 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(); 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 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 - if (!new_destination || !crossing) return false; - if (new_destination == this) return false; - // Find the entry of crossing to get the next waypoint and the distance - var crossing_item; - for (var list_item in destination_list) - { - if (!list_item) continue; - if (list_item[const_finaldestination] == crossing) - { - 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]; + // Failsafes. + if (!new_destination || !crossing) + return; + if (new_destination == this) + return; + if (!IsDirectlyConnectToCrossing(crossing)) + return FatalError(Format("destination to %v for %v is not connected to crossing link %v.", new_destination, this, crossing)); + // Add to destination list. + PushBack(destination_list, [new_destination, crossing, distance]); DestinationsUpdated(); - return true; + return; } /** 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; for (var list_item in destination_list) { - if (!list_item) continue; + if (!list_item) + continue; if (list_item[const_finaldestination] == crossing) crossing_item = list_item; if (list_item[const_finaldestination] == known_destination) @@ -299,7 +332,8 @@ public func UpdateCableDestination(object known_destination, object crossing, in i++; } // Failsafe - if (!crossing_item || !destination_item) return false; + if (!crossing_item || !destination_item) + return false; // Save the updated path destination_list[destination_item][const_nextwaypoint] = crossing_item[const_nextwaypoint]; 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; -/* Called automatically by Destruction, see description there -* @param crossing The calling crossing -*/ -public func ClearConnections(object crossing) +// Updates the network for this crossing, this is called when a cable to this crossing has changed. +// It first clears every waypoint from the network and then renews the whole information. +public func UpdateConnections() { - 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; destination_list = []; for (var connection in FindObjects(Find_Func("IsConnectedTo", this))) { - if (!connection->~IsCableLine()) continue; + if (!connection->~IsCableLine()) + continue; var other_crossing = connection->~GetConnectedObject(this); - if (!other_crossing || !other_crossing->~IsCableCrossing()) continue; + if (!other_crossing || !other_crossing->~IsCableCrossing()) + continue; other_crossing->ClearConnections(); } } -/* Called automatically by Destruction, see description there -* @param crossing The calling crossing -*/ -public func RenewConnections(object crossing) +// Called automatically by UpdateConnections, see description there. +public func RenewConnections() { - if (!clearing) return; + if (!clearing) + return; 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); - if (!other_crossing || !other_crossing->~IsCableCrossing()) continue; - if (other_crossing == crossing) continue; - destination_list[GetLength(destination_list)] = [other_crossing, other_crossing, ObjectDistance(other_crossing)]; + if (!other_crossing || !other_crossing->~IsCableCrossing()) + continue; + PushBack(destination_list, [other_crossing, other_crossing, ObjectDistance(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: GetNextWaypoint(object end) @@ -356,10 +416,12 @@ public func RenewConnections(object crossing) */ public func GetNextWaypoint(object end) { - if (!destination_list) return nil; + if (!destination_list) + return nil; for (var item in destination_list) { - if (!item) continue; + if (!item) + continue; if (item[const_finaldestination] == end) return item[const_nextwaypoint]; } @@ -372,16 +434,19 @@ public func GetNextWaypoint(object end) */ public func GetLengthToTarget(object end) { - if (!destination_list) return nil; + if (!destination_list) + return nil; for (var item in destination_list) { - if (!item) continue; + if (!item) + continue; if (item[const_finaldestination] == end) return item[const_distance]; } return nil; } + /*-- Auto production --*/ local request_queue; @@ -410,12 +475,11 @@ public func AddRequest(proplist requested_id, int amount) // Great. Start working immediately PushBack(request_queue, [requested_id, amount]); car->AddRequest(requested_id, amount, this, source); - return true; } // Check all connected stations for available objects -func CheckAvailability(proplist requested, int amount) +public func CheckAvailability(proplist requested, int amount) { var nearest_station; var length_to; @@ -494,4 +558,4 @@ public func RemoveRequest(id requested, int amount) return false; RemoveArrayIndex(request_queue, i, true); return true; -} \ No newline at end of file +} diff --git a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/Script.c b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/Script.c index 8dd8937a1..091caf957 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/Script.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/Script.c @@ -1,11 +1,11 @@ -/*-- +/** Cable Crossing 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). But the crossing can also manually be set to function as a station. - Author: Clonkonaut ---*/ + @author Clonkonaut +*/ #include Library_CableStation @@ -32,7 +32,8 @@ func Initialize() // Prevents the automatic change of the station status when manually set to station mode local manual_setting = false; -/* Library functions: Cable Station */ + +/*-- Library functions: Cable Station --*/ public func DestinationsUpdated() { @@ -44,6 +45,11 @@ public func DestinationsUpdated() else SetCableStation(false); 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) @@ -107,7 +113,8 @@ public func OnCableCarDelivery(object car, id requested, int amount) } } -/* Construction */ + +/*-- Construction --*/ public func IsHammerBuildable() { return true; } @@ -124,7 +131,7 @@ public func ConstructionCombineOffset(proplist other) return; // 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; return ret; } @@ -238,7 +245,9 @@ public func ToggleDropOff(bool silent) if (!IsCableStation()) ToggleStation(true); setting_dropoff = true; - } else { + } + else + { setting_dropoff = false; } if (!silent) @@ -246,7 +255,8 @@ public func ToggleDropOff(bool silent) CheckStationStatus(); } -/* Cable Car Management */ + +/*-- Cable Car Management --*/ public func OnCableCarArrival(object car) { @@ -259,6 +269,11 @@ public func OnCableCarArrival(object car) PushBack(arrived_cars, car); } +public func OnCableCarStopped(object car) +{ + PushBack(arrived_cars, car); +} + public func OnCableCarDeparture(object car) { RemoveArrayValue(arrived_cars, car, true); @@ -274,19 +289,23 @@ public func OnCableCarDisengaged(object car) RemoveArrayValue(arrived_cars, car, true); } -/* Visuals */ +public func OnCableCarDestruction(object car) +{ + RemoveArrayValue(arrived_cars, car, true); +} -func CheckStationStatus() + +/*-- Visuals --*/ + +public func CheckStationStatus() { if (IsCableStation()) { // In order of priority if (setting_dropoff) - { SetMeshMaterial("CableCarStation_SignDropOff", 1); - } else { + else SetMeshMaterial("CableCarStation_SignStation", 1); - } } else SetMeshMaterial("CableCarStation_Sign", 1); @@ -294,14 +313,14 @@ func CheckStationStatus() local activations = 0; -func CableActivation(int count) +public func CableActivation(int count) { if (activations <= 0) SetAnimationPosition(turn_anim, Anim_Linear(GetAnimationPosition(turn_anim), 0, GetAnimationLength("Engine"), 175, ANIM_Loop)); activations += count; } -func CableDeactivation(int count) +public func CableDeactivation(int count) { activations -= count; if (activations <= 0) @@ -310,9 +329,10 @@ func CableDeactivation(int count) public func NoConstructionFlip() { return true; } -/* Saving */ -func SaveScenarioObject(props) +/*-- Saving --*/ + +public func SaveScenarioObject(props) { if (!inherited(props, ...)) return false; if (IsCableStation() && manual_setting) @@ -327,7 +347,8 @@ func SaveScenarioObject(props) public func SetManual() { manual_setting = true; return true; } -/* Properties */ + +/*-- Properties --*/ local Name = "$Name$"; local BlastIncinerate = 50; diff --git a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/StringTblDE.txt b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/StringTblDE.txt index 57ce696f6..b68eab1c6 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/StringTblDE.txt +++ b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/StringTblDE.txt @@ -3,5 +3,7 @@ Name=Seilbahnkreuzung StationSettings=Seilbahneinstellungen 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. \ No newline at end of file +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. \ No newline at end of file diff --git a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Hoist.ocd/Script.c b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Hoist.ocd/Script.c index 425fdb911..4fba57361 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Hoist.ocd/Script.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Hoist.ocd/Script.c @@ -1,20 +1,26 @@ -/*-- Cable Hoist --*/ +/** + Cable Hoist + + @author Clonkonaut +*/ #include Library_CableCar 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); } -/* Engine Callbacks */ -func Damage(int change, int cause) +/*-- Engine Callbacks --*/ + +public func Damage(int change, int cause) { if (cause == FX_Call_DmgBlast) { @@ -26,25 +32,28 @@ func Damage(int change, int cause) } } -/* Status */ + +/*-- Status --*/ 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; } -func Engaged() +public func Engaged() { this.Touchable = 0; SetAction("OnRail"); } -func Disengaged() +public func Disengaged() { this.Touchable = 1; SetAction("Idle"); @@ -52,9 +61,10 @@ func Disengaged() 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()) { @@ -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, ...); } -/* Picking up vehicles */ + +/*-- Picking up vehicles --*/ public func PickupVehicle(object vehicle) { @@ -155,9 +166,10 @@ local FxCableHoistPickup = new Effect } }; -/* Actions */ -func OnRail() +/*-- Actions --*/ + +public func OnRail() { DoMovement(); } @@ -180,7 +192,8 @@ local ActMap = { }, }; -/* Callbacks */ + +/*-- Callbacks --*/ 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 if (pickup && pickup->ContentsCount(requested) >= amount) return true; - 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$"; diff --git a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Lorry.ocd/Script.c b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Lorry.ocd/Script.c index d982819d3..7c607d6cc 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Lorry.ocd/Script.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Lorry.ocd/Script.c @@ -12,23 +12,23 @@ local empty_anim; /*-- Engine Callbacks --*/ -func Construction() +public func Construction() { 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)); empty_anim = PlayAnimation("Empty", 2, Anim_Const(0), Anim_Const(0)); } -func Hit3() +public func Hit3() { 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. if (!obj->Contained() && GetEffect("BlockCollectionByLorry", obj)) @@ -59,7 +59,7 @@ func RejectCollect(id object_id, object obj) } // Automatic unloading in buildings. -func Entrance(object container) +public func Entrance(object container) { // Only in buildings if (container->GetCategory() & (C4D_StaticBack | C4D_Structure)) @@ -69,19 +69,19 @@ func Entrance(object container) container->GrabContents(this); } -func ContactLeft() +public func ContactLeft() { if (Stuck() && !Random(5)) SetRDir(RandomX(-7, +7)); } -func ContactRight() +public func ContactRight() { if (Stuck() && !Random(5)) 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. if (cause != FX_Call_DmgBlast) @@ -144,7 +144,7 @@ public func DropContents(proplist station) ScheduleCall(this, "Empty", 35); } -func Empty() +public func Empty() { // Exit everything at once (as opposed to manual dumping below) while (Contents()) diff --git a/planet/Experimental.ocf/CableLorrys.ocs/Objects.c b/planet/Experimental.ocf/CableLorrys.ocs/Objects.c index e74ad78c0..00eece8d2 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/Objects.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/Objects.c @@ -144,6 +144,7 @@ func InitializeObjects() CableLine019->SetConnectedObjects(CableCrossing019, CableCrossing003); var ToolsWorkshop001 = CreateObjectAbove(ToolsWorkshop, 76, 388); + CableCrossing019->CombineWith(ToolsWorkshop001); var CableHoist001 = CreateObjectAbove(CableHoist, 560, 384); CableHoist001->SetComDir(COMD_None); diff --git a/planet/Experimental.ocf/CableLorrys.ocs/Script.c b/planet/Experimental.ocf/CableLorrys.ocs/Script.c index e38c140dc..5e9784005 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/Script.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/Script.c @@ -150,6 +150,10 @@ protected func InitializePlayer(int plr) // No FOW here. //SetFoW(false, plr); JoinPlayer(plr); + // Give all knowledge. + var index = 0, def; + while (def = GetDefinition(index++)) + SetPlrKnowledge(plr, def); return; } diff --git a/planet/Tests.ocf/CableCars.ocs/Script.c b/planet/Tests.ocf/CableCars.ocs/Script.c index cb9a03c3d..b472c6ead 100644 --- a/planet/Tests.ocf/CableCars.ocs/Script.c +++ b/planet/Tests.ocf/CableCars.ocs/Script.c @@ -56,10 +56,10 @@ protected func InitializePlayer(int plr) SetPlrKnowledge(plr, def); // Add test control effect. - var effect = AddEffect("IntTestControl", nil, 100, 2); - effect.testnr = 1; - effect.launched = false; - effect.plr = plr; + var fx = AddEffect("IntTestControl", nil, 100, 2); + fx.testnr = 7; + fx.launched = false; + fx.plr = plr; return; } @@ -191,7 +191,7 @@ global func Test1_OnStart(int plr) workshop->AddToQueue(Shovel, 2); // 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; } @@ -288,11 +288,13 @@ global func Test3_OnStart(int plr) var workshop = CreateObjectAbove(ToolsWorkshop, 40, 160, plr); crossing1->CombineWith(workshop); - workshop->AddToQueue(Shovel, 2); + workshop->AddToQueue(Shovel, 1); ScheduleCall(line_to_break, "OnLineBreak", 36, 0, true); ScheduleCall(line_to_break, "RemoveObject", 37, 0, true); + ScheduleCall(nil, "PrintCableCarNetwork", 38, 0); ScheduleCall(nil, "CreateCableCrossingsConnection", 240, 0, crossing2, crossing3); + ScheduleCall(nil, "PrintCableCarNetwork", 241, 0); // Log what the test is about. 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() { - if (ObjectCount(Find_ID(Shovel)) >= 2) + if (ObjectCount(Find_ID(Shovel)) >= 1) return true; return false; } @@ -319,26 +321,30 @@ global func Test4_OnStart(int plr) var crossing1 = CreateObjectAbove(CableCrossing, 70, 160, plr); var crossing2 = CreateObjectAbove(CableCrossing, 216, 64, plr); - var crossing3 = CreateObjectAbove(CableCrossing, 272, 64, plr); - var crossing4 = CreateObjectAbove(CableCrossing, 450, 104, 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 = crossing4->CreateObject(CableHoist); - hoist->EngageRail(crossing4); - var lorry = crossing4->CreateObject(CableLorry); + var hoist = crossing5->CreateObject(CableHoist); + hoist->EngageRail(crossing5); + var lorry = crossing5->CreateObject(CableLorry); hoist->PickupVehicle(lorry); lorry->CreateContents(Metal, 2); lorry->CreateContents(Wood, 2); var workshop = CreateObjectAbove(ToolsWorkshop, 40, 160, plr); crossing1->CombineWith(workshop); - workshop->AddToQueue(Shovel, 2); + workshop->AddToQueue(Shovel, 1); - ScheduleCall(crossing2, "RemoveObject", 36, 0, true); - ScheduleCall(nil, "CreateCableCrossingsConnection", 240, 0, crossing1, crossing3); + ScheduleCall(crossing3, "RemoveObject", 36, 0, true); + ScheduleCall(nil, "PrintCableCarNetwork", 37, 0); + ScheduleCall(nil, "CreateCableCrossingsConnection", 240, 0, crossing2, crossing4); + ScheduleCall(nil, "PrintCableCarNetwork", 241, 0); // Log what the test is about. 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() { - if (ObjectCount(Find_ID(Shovel)) >= 2) + if (ObjectCount(Find_ID(Shovel)) >= 1) return true; return false; } @@ -358,7 +364,6 @@ global func Test4_OnFinished() return; } - global func Test5_OnStart(int plr) { SetWindFixed(50); @@ -464,7 +469,7 @@ global func Test6_OnStart(int plr) var drain = CreateObjectAbove(Pipe, 80, 300, plr); 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("Test automated concrete production line."); @@ -539,6 +544,141 @@ global func Test7_OnFinished() 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("@%d", 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("@%d", 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 --*/ @@ -608,40 +748,3 @@ global func RemoveTestObjects() )); 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; -}