Advertisement
Guest User

OpenTTD Autoseparation patch r25615 (Credit: Gathers)

a guest
Jul 18th, 2013
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.46 KB | None | 0 0
  1. Index: src/vehicle_base.h
  2. ===================================================================
  3. --- src/vehicle_base.h (revision 25615)
  4. +++ src/vehicle_base.h (working copy)
  5. @@ -44,6 +44,7 @@
  6. VF_TIMETABLE_STARTED, ///< Whether the vehicle has started running on the timetable yet.
  7. VF_AUTOFILL_TIMETABLE, ///< Whether the vehicle should fill in the timetable automatically.
  8. VF_AUTOFILL_PRES_WAIT_TIME, ///< Whether non-destructive auto-fill should preserve waiting times
  9. + VF_AUTOMATE_TIMETABLE, ///< Whether the vehicle should manage the timetable automatically.
  10. VF_STOP_LOADING, ///< Don't load anymore during the next load cycle.
  11. VF_PATHFINDER_LOST, ///< Vehicle's pathfinder is lost.
  12. VF_SERVINT_IS_CUSTOM, ///< Service interval is custom.
  13. @@ -133,6 +134,10 @@
  14.  
  15. Vehicle *next_shared; ///< pointer to the next vehicle that shares the order
  16. Vehicle *previous_shared; ///< NOSAVE: pointer to the previous vehicle in the shared order chain
  17. +
  18. + Vehicle *ahead_separation;
  19. + Vehicle *behind_separation;
  20. +
  21. public:
  22. friend const SaveLoad *GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code
  23. friend void FixOldVehicles();
  24. @@ -154,6 +159,12 @@
  25.  
  26. CargoPayment *cargo_payment; ///< The cargo payment we're currently in
  27.  
  28. + /* Used for timetabling. */
  29. + uint32 current_order_time; ///< How many ticks have passed since this order started.
  30. + uint32 current_loading_time; ///< How long loading took. Less than current_order_time if vehicle is early.
  31. + int32 lateness_counter; ///< How many ticks late (or early if negative) this vehicle is.
  32. + Date timetable_start; ///< When the vehicle is supposed to start the timetable.
  33. +
  34. Rect coord; ///< NOSAVE: Graphical bounding box of the vehicle, i.e. what to redraw on moves.
  35.  
  36. Vehicle *hash_viewport_next; ///< NOSAVE: Next vehicle in the visual location hash.
  37. @@ -565,6 +576,37 @@
  38. */
  39. inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
  40.  
  41. + /**
  42. + * Get the vehicle ahead on track.
  43. + * @return the vehicle ahead on track or NULL when there isn't one.
  44. + */
  45. + inline Vehicle *AheadSeparation() const { return this->ahead_separation; }
  46. +
  47. + /**
  48. + * Get the vehicle behind on track.
  49. + * @return the vehicle behind on track or NULL when there isn't one.
  50. + */
  51. + inline Vehicle *BehindSeparation() const { return this->behind_separation; }
  52. +
  53. + /**
  54. + * Clears a vehicle's separation status, removing it from any chain.
  55. + */
  56. + void ClearSeparation();
  57. +
  58. + /**
  59. + * Adds this vehicle to a shared vehicle separation chain.
  60. + * @param v_other a vehicle of the separation chain
  61. + * @pre !this->IsOrderListShared()
  62. + */
  63. + void InitSeparation();
  64. +
  65. + /**
  66. + * Adds this vehicle behind another in a separation chain.
  67. + * @param v_other a vehicle of the separation chain.
  68. + * @pre !this->IsOrderListShared()
  69. + */
  70. + void AddToSeparationBehind(Vehicle *v_other);
  71. +
  72. void AddToShared(Vehicle *shared_chain);
  73. void RemoveFromShared();
  74.  
  75. @@ -634,6 +676,18 @@
  76.  
  77. this->profit_this_year = src->profit_this_year;
  78. this->profit_last_year = src->profit_last_year;
  79. +
  80. + this->current_order_time = src->current_order_time;
  81. + this->current_loading_time = src->current_loading_time;
  82. + this->lateness_counter = src->lateness_counter;
  83. + this->timetable_start = src->timetable_start;
  84. +
  85. + if (HasBit(src->vehicle_flags, VF_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
  86. + if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE);
  87. + if (HasBit(src->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) SetBit(this->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
  88. +
  89. + this->service_interval = src->service_interval;
  90. +
  91. }
  92.  
  93.  
  94. Index: src/vehicle_cmd.cpp
  95. ===================================================================
  96. --- src/vehicle_cmd.cpp (revision 25615)
  97. +++ src/vehicle_cmd.cpp (working copy)
  98. @@ -572,6 +572,9 @@
  99. if (flags & DC_EXEC) {
  100. if (v->IsStoppedInDepot() && (flags & DC_AUTOREPLACE) == 0) DeleteVehicleNews(p1, STR_NEWS_TRAIN_IS_WAITING + v->type);
  101.  
  102. + if (_settings_game.order.timetable_separation) v->ClearSeparation();
  103. + if (_settings_game.order.timetable_separation) ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
  104. +
  105. v->vehstatus ^= VS_STOPPED;
  106. if (v->type != VEH_TRAIN) v->cur_speed = 0; // trains can stop 'slowly'
  107. v->MarkDirty();
  108. Index: src/table/settings.ini
  109. ===================================================================
  110. --- src/table/settings.ini (revision 25615)
  111. +++ src/table/settings.ini (working copy)
  112. @@ -1060,6 +1060,20 @@
  113. from = 67
  114. to = 158
  115.  
  116. +[SDT_BOOL]
  117. +base = GameSettings
  118. +var = order.timetable_automated
  119. +from = TIMESEP_SV
  120. +def = 1
  121. +str = STR_CONFIG_SETTING_TIMETABLE_AUTOMATED
  122. +
  123. +[SDT_BOOL]
  124. +base = GameSettings
  125. +var = order.timetable_separation
  126. +from = TIMESEP_SV
  127. +def = 1
  128. +str = STR_CONFIG_SETTING_TIMETABLE_SEPARATION
  129. +
  130. [SDT_VAR]
  131. base = GameSettings
  132. var = vehicle.plane_speed
  133. Index: src/settings_type.h
  134. ===================================================================
  135. --- src/settings_type.h (revision 25615)
  136. +++ src/settings_type.h (working copy)
  137. @@ -436,6 +436,8 @@
  138. bool gradual_loading; ///< load vehicles gradually
  139. bool selectgoods; ///< only send the goods to station if a train has been there
  140. bool no_servicing_if_no_breakdowns; ///< don't send vehicles to depot when breakdowns are disabled
  141. + bool timetable_automated; ///< whether to automatically manage timetables
  142. + bool timetable_separation; ///< whether to perform automatic separation based on timetable
  143. bool serviceathelipad; ///< service helicopters at helipads automatically (no need to send to depot)
  144. };
  145.  
  146. Index: src/lang/english.txt
  147. ===================================================================
  148. --- src/lang/english.txt (revision 25615)
  149. +++ src/lang/english.txt (working copy)
  150. @@ -1354,8 +1354,10 @@
  151. STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Enable usage of the advanced vehicle lists for grouping vehicles
  152. STR_CONFIG_SETTING_LOADING_INDICATORS :Use loading indicators: {STRING2}
  153. STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Select whether loading indicators are displayed above loading or unloading vehicles
  154. +STR_CONFIG_SETTING_TIMETABLE_AUTOMATED :Automatically manage timetables: {STRING2}
  155. STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Show timetable in ticks rather than days: {STRING2}
  156. STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Show travel times in time tables in game ticks instead of days
  157. +STR_CONFIG_SETTING_TIMETABLE_SEPARATION :Use timetable to ensure vehicle separation: {STRING2}
  158. STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Show arrival and departure in timetables: {STRING2}
  159. STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Display anticipated arrival and departure times in timetables
  160. STR_CONFIG_SETTING_QUICKGOTO :Quick creation of vehicle orders: {STRING2}
  161. @@ -3845,6 +3847,9 @@
  162. STR_TIMETABLE_AUTOFILL :{BLACK}Autofill
  163. STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey (Ctrl+Click to try to keep waiting times)
  164.  
  165. +STR_TIMETABLE_AUTOMATE :{BLACK}Automate
  166. +STR_TIMETABLE_AUTOMATE_TOOLTIP :{BLACK}Manage the timetables automatically by updating the values for each journey
  167. +
  168. STR_TIMETABLE_EXPECTED :{BLACK}Expected
  169. STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled
  170. STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Switch between expected and scheduled
  171. Index: src/timetable_cmd.cpp
  172. ===================================================================
  173. --- src/timetable_cmd.cpp (revision 25615)
  174. +++ src/timetable_cmd.cpp (working copy)
  175. @@ -15,6 +15,7 @@
  176. #include "date_func.h"
  177. #include "window_func.h"
  178. #include "vehicle_base.h"
  179. +#include "settings_type.h"
  180. #include "cmd_helper.h"
  181. #include "core/sort_func.hpp"
  182.  
  183. @@ -339,6 +340,164 @@
  184. }
  185.  
  186. /**
  187. + * Start or stop automatic management of timetables.
  188. + * @param tile Not used.
  189. + * @param flags Operation to perform.
  190. + * @param p1 Vehicle index.
  191. + * @param p2 Various bitstuffed elements
  192. + * - p2 = (bit 0) - Set to 1 to enable, 0 to disable automation.
  193. + * - p2 = (bit 1) - Ctrl was pressed. Used when disabling to keep times.
  194. + * @param text unused
  195. + * @return the cost of this operation or an error
  196. + */
  197. +
  198. +CommandCost CmdAutomateTimetable(TileIndex index, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
  199. +{
  200. + if (!_settings_game.order.timetable_automated) return CMD_ERROR;
  201. +
  202. + VehicleID veh = GB(p1, 0, 16);
  203. +
  204. + Vehicle *v = Vehicle::GetIfValid(veh);
  205. + if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
  206. +
  207. + CommandCost ret = CheckOwnership(v->owner);
  208. + if (ret.Failed()) return ret;
  209. +
  210. + if (flags & DC_EXEC) {
  211. + for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
  212. + if (HasBit(p2, 0)) {
  213. + /* Automated timetable. Set flags and clear current times. */
  214. + SetBit(v2->vehicle_flags, VF_AUTOMATE_TIMETABLE);
  215. + ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE);
  216. + ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
  217. + ClrBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
  218. + v2->timetable_start = 0;
  219. + v2->lateness_counter = 0;
  220. + v2->current_loading_time = 0;
  221. + v2->ClearSeparation();
  222. + } else {
  223. + /* De-automate timetable. Clear flags. */
  224. + ClrBit(v2->vehicle_flags, VF_AUTOMATE_TIMETABLE);
  225. + ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE);
  226. + ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
  227. + v2->ClearSeparation();
  228. + if (!HasBit(p2, 1)) {
  229. + /* Ctrl wasn't pressed, so clear all timetabled times. */
  230. + SetBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
  231. + v2->timetable_start = 0;
  232. + v2->lateness_counter = 0;
  233. + v2->current_loading_time = 0;
  234. + OrderList *orders = v2->orders.list;
  235. + if (orders != NULL) {
  236. + for (int i = 0; i < orders->GetNumOrders(); i++) {
  237. + ChangeTimetable(v2, i, 0, MTF_WAIT_TIME);
  238. + ChangeTimetable(v2, i, 0, MTF_TRAVEL_TIME);
  239. + }
  240. + }
  241. + }
  242. + }
  243. + SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index);
  244. + }
  245. + }
  246. +
  247. + return CommandCost();
  248. +}
  249. +
  250. +int TimeToFinishOrder(Vehicle *v, int n)
  251. +{
  252. + int left;
  253. + Order *order = v->GetOrder(n);
  254. + assert(order != NULL);
  255. + if ((v->cur_real_order_index == n) && (v->last_station_visited == order->GetDestination())) {
  256. + if (order->wait_time == 0) return -1;
  257. + if (v->current_loading_time > 0) {
  258. + left = order->wait_time - v->current_order_time;
  259. + } else {
  260. + left = order->wait_time;
  261. + }
  262. + if (left < 0) left = 0;
  263. + } else {
  264. + left = order->travel_time;
  265. + if (v->cur_real_order_index == n) left -= v->current_order_time;
  266. + if (order->travel_time == 0 || order->wait_time == 0) return -1;
  267. + if (left < 0) left = 0;
  268. + left += order->wait_time;
  269. + }
  270. + return left;
  271. +}
  272. +
  273. +int SeparationBetween(Vehicle *v1, Vehicle *v2)
  274. +{
  275. + if (v1 == v2) return -1;
  276. + int separation = 0;
  277. + int time;
  278. + int n = v1->cur_real_order_index;
  279. + while (n != v2->cur_real_order_index) {
  280. + time = TimeToFinishOrder(v1, n);
  281. + if (time == -1) return -1;
  282. + separation += time;
  283. + n++;
  284. + if (n >= v1->GetNumOrders()) n = 0;
  285. + }
  286. + int time1 = TimeToFinishOrder(v1, n);
  287. + int time2 = TimeToFinishOrder(v2, n);
  288. + if (time1 == -1 || time2 == -1) return -1;
  289. + time = time1 - time2;
  290. + if (time < 0) {
  291. + for (n = 0; n < v1->GetNumOrders(); n++) {
  292. + Order *order = v1->GetOrder(n);
  293. + if (order->travel_time == 0 || order->wait_time == 0) return -1;
  294. + time += order->travel_time + order->wait_time;
  295. + }
  296. + }
  297. + separation += time;
  298. + assert(separation >= 0);
  299. + if (separation == 0) return -1;
  300. + return separation;
  301. +}
  302. +
  303. +void UpdateSeparationOrder(Vehicle *v_start)
  304. +{
  305. + /* First check if we have a vehicle ahead, and if not search for one. */
  306. + if (v_start->AheadSeparation() == NULL) {
  307. + v_start->InitSeparation();
  308. + }
  309. + if (v_start->AheadSeparation() == NULL) {
  310. + return;
  311. + }
  312. + /* Switch positions if necessary. */
  313. + int swaps = 0;
  314. + bool done = false;
  315. + while (!done) {
  316. + done = true;
  317. + int min_sep = SeparationBetween(v_start, v_start->AheadSeparation());
  318. + Vehicle *v = v_start;
  319. + do {
  320. + if (v != v_start) {
  321. + int tmp_sep = SeparationBetween(v_start, v);
  322. + if (tmp_sep < min_sep && tmp_sep != -1) {
  323. + swaps++;
  324. + if (swaps >= 50) {
  325. + return;
  326. + }
  327. + done = false;
  328. + v_start->ClearSeparation();
  329. + v_start->AddToSeparationBehind(v);
  330. + break;
  331. + }
  332. + }
  333. + int separation_ahead = SeparationBetween(v, v->AheadSeparation());
  334. + int separation_behind = SeparationBetween(v->BehindSeparation(), v);
  335. + v->lateness_counter = (separation_ahead - separation_behind) / 2;
  336. + if (separation_ahead == -1 || separation_behind == -1) v->lateness_counter = 0;
  337. + v = v->AheadSeparation();
  338. + } while (v != v_start);
  339. + }
  340. +}
  341. +
  342. +
  343. +
  344. +/**
  345. * Update the timetable for the vehicle.
  346. * @param v The vehicle to update the timetable for.
  347. * @param travelling Whether we just travelled or waited at a station.
  348. @@ -346,9 +505,12 @@
  349. void UpdateVehicleTimetable(Vehicle *v, bool travelling)
  350. {
  351. uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time;
  352. + if (!travelling) v->current_loading_time++; // +1 because this time is one tick behind
  353. uint time_taken = v->current_order_time;
  354. + uint time_loading = v->current_loading_time;
  355.  
  356. v->current_order_time = 0;
  357. + v->current_loading_time = 0;
  358.  
  359. if (v->current_order.IsType(OT_IMPLICIT)) return; // no timetabling of auto orders
  360.  
  361. @@ -359,6 +521,18 @@
  362.  
  363. bool just_started = false;
  364.  
  365. + /* Start automated timetables at first opportunity */
  366. + if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED) && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
  367. + if (_settings_game.order.timetable_separation) v->ClearSeparation();
  368. + SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
  369. + v->lateness_counter = 0;
  370. + if (_settings_game.order.timetable_separation) UpdateSeparationOrder(v);
  371. + for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
  372. + SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
  373. + }
  374. + return;
  375. + }
  376. +
  377. /* This vehicle is arriving at the first destination in the timetable. */
  378. if (v->cur_real_order_index == first_manual_order && travelling) {
  379. /* If the start date hasn't been set, or it was set automatically when
  380. @@ -415,12 +589,60 @@
  381.  
  382. if (just_started) return;
  383.  
  384. + /* Update the timetable to gradually shift order times towards the actual travel times. */
  385. + if (timetabled != 0 && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
  386. + int32 new_time;
  387. + if (travelling) {
  388. + new_time = time_taken;
  389. + } else {
  390. + new_time = time_loading;
  391. + }
  392. +
  393. + /* Check for too large a difference from expected time, and if so don't average. */
  394. + if (!(new_time > (int32)timetabled * 2 || new_time < (int32)timetabled / 2)) {
  395. + int arrival_error = timetabled - new_time;
  396. + /* Compute running average, with sign conversion to avoid negative overflow. */
  397. + new_time = ((int32)timetabled * 4 + new_time + 2) / 5;
  398. + /* Use arrival_error to finetune order ticks. */
  399. + if (arrival_error < 0) new_time++;
  400. + if (arrival_error > 0) new_time--;
  401. + } else if (new_time > (int32)timetabled * 10 && travelling) {
  402. + /* Possible jam, clear time and restart timetable for all vehicles.
  403. + * Otherwise we risk trains blocking 1-lane stations for long times. */
  404. + ChangeTimetable(v, v->cur_real_order_index, 0, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME);
  405. + for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
  406. + if (_settings_game.order.timetable_separation) v2->ClearSeparation();
  407. + ClrBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
  408. + SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index);
  409. + }
  410. + return;
  411. + }
  412. +
  413. + if (new_time < 1) new_time = 1;
  414. + if (new_time != (int32)timetabled)
  415. + ChangeTimetable(v, v->cur_real_order_index, new_time, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME);
  416. + } else if (timetabled == 0 && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
  417. + /* Add times for orders that are not yet timetabled, even while not autofilling */
  418. + if (travelling)
  419. + ChangeTimetable(v, v->cur_real_order_index, time_taken, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME);
  420. + else
  421. + ChangeTimetable(v, v->cur_real_order_index, time_loading, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME);
  422. + }
  423. +
  424. /* Vehicles will wait at stations if they arrive early even if they are not
  425. * timetabled to wait there, so make sure the lateness counter is updated
  426. * when this happens. */
  427. if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return;
  428.  
  429. - v->lateness_counter -= (timetabled - time_taken);
  430. + if (_settings_game.order.timetable_separation && HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) {
  431. + v->current_order_time = time_taken;
  432. + v->current_loading_time = time_loading;
  433. + UpdateSeparationOrder(v);
  434. + v->current_order_time = 0;
  435. + v->current_loading_time = 0;
  436. + } else {
  437. + v->lateness_counter -= (timetabled - time_taken);
  438. + }
  439.  
  440. /* When we are more late than this timetabled bit takes we (somewhat expensively)
  441. * check how many ticks the (fully filled) timetable has. If a timetable cycle is
  442. Index: src/widgets/timetable_widget.h
  443. ===================================================================
  444. --- src/widgets/timetable_widget.h (revision 25615)
  445. +++ src/widgets/timetable_widget.h (working copy)
  446. @@ -25,9 +25,11 @@
  447. WID_VT_CLEAR_TIME, ///< Clear time button.
  448. WID_VT_RESET_LATENESS, ///< Reset lateness button.
  449. WID_VT_AUTOFILL, ///< Autofill button.
  450. + WID_VT_AUTOMATE, ///< Automate button.
  451. WID_VT_EXPECTED, ///< Toggle between expected and scheduled arrivals.
  452. WID_VT_SHARED_ORDER_LIST, ///< Show the shared order list.
  453. WID_VT_ARRIVAL_DEPARTURE_SELECTION, ///< Disable/hide the arrival departure panel.
  454. + WID_VT_AUTO_SELECTION, ///< Disable/hide the automate button.
  455. WID_VT_EXPECTED_SELECTION, ///< Disable/hide the expected selection button.
  456. WID_VT_CHANGE_SPEED, ///< Change speed limit button.
  457. WID_VT_CLEAR_SPEED, ///< Clear speed limit button.
  458. Index: src/command.cpp
  459. ===================================================================
  460. --- src/command.cpp (revision 25615)
  461. +++ src/command.cpp (working copy)
  462. @@ -188,6 +188,7 @@
  463. CommandProc CmdChangeTimetable;
  464. CommandProc CmdSetVehicleOnTime;
  465. CommandProc CmdAutofillTimetable;
  466. +CommandProc CmdAutomateTimetable;
  467. CommandProc CmdSetTimetableStart;
  468.  
  469. CommandProc CmdOpenCloseAirport;
  470. @@ -341,6 +342,7 @@
  471. DEF_CMD(CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CHANGE_TIMETABLE
  472. DEF_CMD(CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_VEHICLE_ON_TIME
  473. DEF_CMD(CmdAutofillTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOFILL_TIMETABLE
  474. + DEF_CMD(CmdAutomateTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOMATE_TIMETABLE]
  475. DEF_CMD(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START
  476.  
  477. DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT
  478. Index: src/settings_gui.cpp
  479. ===================================================================
  480. --- src/settings_gui.cpp (revision 25615)
  481. +++ src/settings_gui.cpp (working copy)
  482. @@ -1685,6 +1685,8 @@
  483. SettingEntry("vehicle.max_ships"),
  484. SettingEntry("vehicle.plane_speed"),
  485. SettingEntry("vehicle.plane_crashes"),
  486. + SettingEntry("order.timetable_automated"),
  487. + SettingEntry("order.timetable_separation"),
  488. SettingEntry("vehicle.dynamic_engines"),
  489. SettingEntry("vehicle.roadveh_acceleration_model"),
  490. SettingEntry("vehicle.roadveh_slope_steepness"),
  491. Index: src/command_type.h
  492. ===================================================================
  493. --- src/command_type.h (revision 25615)
  494. +++ src/command_type.h (working copy)
  495. @@ -309,6 +309,7 @@
  496. CMD_CHANGE_TIMETABLE, ///< change the timetable for a vehicle
  497. CMD_SET_VEHICLE_ON_TIME, ///< set the vehicle on time feature (timetable)
  498. CMD_AUTOFILL_TIMETABLE, ///< autofill the timetable
  499. + CMD_AUTOMATE_TIMETABLE, ///< automate the timetable
  500. CMD_SET_TIMETABLE_START, ///< set the date that a timetable should start
  501.  
  502. CMD_OPEN_CLOSE_AIRPORT, ///< open/close an airport to incoming aircraft
  503. Index: src/timetable_gui.cpp
  504. ===================================================================
  505. --- src/timetable_gui.cpp (revision 25615)
  506. +++ src/timetable_gui.cpp (working copy)
  507. @@ -331,6 +331,7 @@
  508. this->EnableWidget(WID_VT_START_DATE);
  509. this->EnableWidget(WID_VT_RESET_LATENESS);
  510. this->EnableWidget(WID_VT_AUTOFILL);
  511. + this->EnableWidget(WID_VT_AUTOMATE);
  512. } else {
  513. this->DisableWidget(WID_VT_START_DATE);
  514. this->DisableWidget(WID_VT_CHANGE_TIME);
  515. @@ -339,10 +340,17 @@
  516. this->DisableWidget(WID_VT_CLEAR_SPEED);
  517. this->DisableWidget(WID_VT_RESET_LATENESS);
  518. this->DisableWidget(WID_VT_AUTOFILL);
  519. + this->DisableWidget(WID_VT_AUTOMATE);
  520. this->DisableWidget(WID_VT_SHARED_ORDER_LIST);
  521. }
  522.  
  523. this->SetWidgetLoweredState(WID_VT_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE));
  524. + this->SetWidgetLoweredState(WID_VT_AUTOMATE, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE));
  525. + this->SetWidgetDisabledState(WID_VT_START_DATE, _settings_game.order.timetable_separation);
  526. + this->SetWidgetDisabledState(WID_VT_AUTOMATE, !_settings_game.order.timetable_automated);
  527. + this->SetWidgetDisabledState(WID_VT_CHANGE_TIME, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE));
  528. + this->SetWidgetDisabledState(WID_VT_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE));
  529. + this->SetWidgetDisabledState(WID_VT_CLEAR_TIME, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE));
  530.  
  531. this->DrawWidgets();
  532. }
  533. @@ -596,6 +604,14 @@
  534. break;
  535. }
  536.  
  537. + case WID_VT_AUTOMATE: {
  538. + uint32 p2 = 0;
  539. + if (!HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) SetBit(p2, 0);
  540. + if (!_ctrl_pressed) SetBit(p2, 1);
  541. + DoCommandP(0, v->index, p2, CMD_AUTOMATE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
  542. + break;
  543. + }
  544. +
  545. case WID_VT_EXPECTED:
  546. this->show_expected = !this->show_expected;
  547. break;
  548. @@ -640,6 +656,7 @@
  549. void UpdateSelectionStates()
  550. {
  551. this->GetWidget<NWidgetStacked>(WID_VT_ARRIVAL_DEPARTURE_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : SZSP_NONE);
  552. + // this->GetWidget<NWidgetStacked>(TTV_AUTO_SELECTION)->SetDisplayedPlane(!_settings_game.order.timetable_automated ? 0 : 1);
  553. this->GetWidget<NWidgetStacked>(WID_VT_EXPECTED_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : 1);
  554. }
  555. };
  556. @@ -677,6 +694,7 @@
  557. EndContainer(),
  558. NWidget(NWID_VERTICAL, NC_EQUALSIZE),
  559. NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_AUTOFILL), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_AUTOFILL, STR_TIMETABLE_AUTOFILL_TOOLTIP),
  560. + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_AUTOMATE), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_AUTOMATE, STR_TIMETABLE_AUTOMATE_TOOLTIP),
  561. NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VT_EXPECTED_SELECTION),
  562. NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_EXPECTED), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_BLACK_STRING, STR_TIMETABLE_EXPECTED_TOOLTIP),
  563. NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(),
  564. @@ -685,6 +703,7 @@
  565. EndContainer(),
  566. NWidget(NWID_VERTICAL, NC_EQUALSIZE),
  567. NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VT_SHARED_ORDER_LIST), SetFill(0, 1), SetDataTip(SPR_SHARED_ORDERS_ICON, STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP),
  568. + NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(),
  569. NWidget(WWT_RESIZEBOX, COLOUR_GREY), SetFill(0, 1),
  570. EndContainer(),
  571. EndContainer(),
  572. Index: src/saveload/saveload.h
  573. ===================================================================
  574. --- src/saveload/saveload.h (revision 25615)
  575. +++ src/saveload/saveload.h (working copy)
  576. @@ -545,6 +545,9 @@
  577.  
  578. bool SaveloadCrashWithMissingNewGRFs();
  579.  
  580. +/* Hack to change savegame version in only one place. Rmv and correct if trunk. */
  581. +const int TIMESEP_SV = 164;
  582. +
  583. extern char _savegame_format[8];
  584. extern bool _do_autosave;
  585.  
  586. Index: src/saveload/vehicle_sl.cpp
  587. ===================================================================
  588. --- src/saveload/vehicle_sl.cpp (revision 25615)
  589. +++ src/saveload/vehicle_sl.cpp (working copy)
  590. @@ -688,6 +688,9 @@
  591. SLE_CONDVAR(Vehicle, random_bits, SLE_UINT8, 2, SL_MAX_VERSION),
  592. SLE_CONDVAR(Vehicle, waiting_triggers, SLE_UINT8, 2, SL_MAX_VERSION),
  593.  
  594. + SLE_CONDREF(Vehicle, ahead_separation, REF_VEHICLE, TIMESEP_SV, SL_MAX_VERSION),
  595. + SLE_CONDREF(Vehicle, behind_separation, REF_VEHICLE, TIMESEP_SV, SL_MAX_VERSION),
  596. +
  597. SLE_CONDREF(Vehicle, next_shared, REF_VEHICLE, 2, SL_MAX_VERSION),
  598. SLE_CONDNULL(2, 2, 68),
  599. SLE_CONDNULL(4, 69, 100),
  600. @@ -695,6 +698,7 @@
  601. SLE_CONDVAR(Vehicle, group_id, SLE_UINT16, 60, SL_MAX_VERSION),
  602.  
  603. SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, 67, SL_MAX_VERSION),
  604. + SLE_CONDVAR(Vehicle, current_loading_time, SLE_UINT32, TIMESEP_SV, SL_MAX_VERSION),
  605. SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, 67, SL_MAX_VERSION),
  606.  
  607. SLE_CONDNULL(10, 2, 143), // old reserved space
  608. Index: src/order_cmd.cpp
  609. ===================================================================
  610. --- src/order_cmd.cpp (revision 25615)
  611. +++ src/order_cmd.cpp (working copy)
  612. @@ -1176,6 +1176,9 @@
  613. v->UpdateRealOrderIndex();
  614.  
  615. InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
  616. +
  617. + if (_settings_game.order.timetable_separation) v->ClearSeparation();
  618. + if (_settings_game.order.timetable_separation) ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
  619. }
  620.  
  621. /* We have an aircraft/ship, they have a mini-schedule, so update them all */
  622. @@ -1624,6 +1627,13 @@
  623. /* Link this vehicle in the shared-list */
  624. dst->AddToShared(src);
  625.  
  626. + /* Set automation bit if target has it. */
  627. + if (HasBit(src->vehicle_flags, VF_AUTOMATE_TIMETABLE))
  628. + SetBit(dst->vehicle_flags, VF_AUTOMATE_TIMETABLE);
  629. +
  630. + if (_settings_game.order.timetable_separation) dst->ClearSeparation();
  631. + if (_settings_game.order.timetable_separation) ClrBit(dst->vehicle_flags, VF_TIMETABLE_STARTED);
  632. +
  633. InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
  634. InvalidateVehicleOrder(src, VIWD_MODIFY_ORDERS);
  635.  
  636. Index: src/vehicle.cpp
  637. ===================================================================
  638. --- src/vehicle.cpp (revision 25615)
  639. +++ src/vehicle.cpp (working copy)
  640. @@ -205,6 +205,9 @@
  641. MarkSingleVehicleDirty(v);
  642. }
  643.  
  644. + if (_settings_game.order.timetable_separation) this->ClearSeparation();
  645. + if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
  646. +
  647. /* Dirty some windows */
  648. InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
  649. SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
  650. @@ -2268,6 +2271,10 @@
  651. case OT_LOADING: {
  652. uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
  653.  
  654. + /* Save time just loading took since that is what goes into the timetable */
  655. + if (!HasBit(this->vehicle_flags, VF_LOADING_FINISHED))
  656. + this->current_loading_time = this->current_order_time;
  657. +
  658. /* Not the first call for this tick, or still loading */
  659. if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
  660.  
  661. @@ -2344,6 +2351,8 @@
  662. if (flags & DC_EXEC) {
  663. this->current_order.SetDepotOrderType(ODTF_MANUAL);
  664. this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
  665. + if (_settings_game.order.timetable_separation) this->ClearSeparation();
  666. + if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
  667. SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
  668. }
  669. return CommandCost();
  670. @@ -2380,6 +2389,9 @@
  671. SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
  672. }
  673.  
  674. + if (_settings_game.order.timetable_separation) this->ClearSeparation();
  675. + if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
  676. +
  677. this->dest_tile = location;
  678. this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
  679. if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
  680. @@ -2632,6 +2644,55 @@
  681. }
  682. }
  683.  
  684. +void Vehicle::ClearSeparation()
  685. +{
  686. + if (this->ahead_separation == NULL && this->behind_separation == NULL) return;
  687. +
  688. + assert(this->ahead_separation != NULL);
  689. + assert(this->behind_separation != NULL);
  690. +
  691. + this->ahead_separation->behind_separation = this->behind_separation;
  692. + this->behind_separation->ahead_separation = this->ahead_separation;
  693. +
  694. + this->ahead_separation = NULL;
  695. + this->behind_separation = NULL;
  696. +
  697. + SetWindowDirty(WC_VEHICLE_TIMETABLE, this->index);
  698. +}
  699. +
  700. +void Vehicle::InitSeparation()
  701. +{
  702. + assert(this->ahead_separation == NULL && this->behind_separation == NULL);
  703. + Vehicle *best_match = this;
  704. + int lowest_separation;
  705. + for (Vehicle *v_other = this->FirstShared(); v_other != NULL; v_other = v_other->NextShared()) {
  706. + if ((HasBit(v_other->vehicle_flags, VF_TIMETABLE_STARTED)) && v_other != this) {
  707. + if (best_match == this) {
  708. + best_match = v_other;
  709. + lowest_separation = 0; // TODO call SeparationBetween() here
  710. + } else {
  711. + int temp_sep = 0; // TODO call SeparationBetween() here
  712. + if (temp_sep < lowest_separation && temp_sep != -1) {
  713. + best_match = v_other;
  714. + lowest_separation = temp_sep;
  715. + }
  716. + }
  717. + }
  718. + }
  719. + this->AddToSeparationBehind(best_match);
  720. +}
  721. +
  722. +void Vehicle::AddToSeparationBehind(Vehicle *v_other)
  723. +{
  724. + if (v_other->ahead_separation == NULL) v_other->ahead_separation = v_other;
  725. + if (v_other->behind_separation == NULL) v_other->behind_separation = v_other;
  726. +
  727. + this->ahead_separation = v_other;
  728. + v_other->behind_separation->ahead_separation = this;
  729. + this->behind_separation = v_other->behind_separation;
  730. + v_other->behind_separation = this;
  731. +}
  732. +
  733. /**
  734. * Adds this vehicle to a shared vehicle chain.
  735. * @param shared_chain a vehicle of the chain with shared vehicles.
  736. @@ -2689,6 +2750,9 @@
  737.  
  738. this->next_shared = NULL;
  739. this->previous_shared = NULL;
  740. +
  741. + if (_settings_game.order.timetable_separation) this->ClearSeparation();
  742. + if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
  743. }
  744.  
  745. void VehiclesYearlyLoop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement