# timetable_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: timetable_cmd.cpp 15434 2009-02-09 21:20:05Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "command_func.h"
    00007 #include "functions.h"
    00008 #include "window_func.h"
    00009 #include "vehicle_base.h"
    00010 #include "settings_type.h"
    00011
    00012 #include "table/strings.h"
    00013
    00014 static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 time, bool is_journey)
    00015 {
    00016   Order *order = GetVehicleOrder(v, order_number);
    00017   int delta;
    00018
    00019   if (is_journey) {
    00020     delta = time - order->travel_time;
    00021     order->travel_time = time;
    00022   } else {
    00023     delta = time - order->wait_time;
    00024     order->wait_time = time;
    00025   }
    00026   v->orders.list->UpdateOrderTimetable(delta);
    00027
    00028   for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
    00029     if (v->cur_order_index == order_number && v->current_order.Equals(*order)) {
    00030       if (is_journey) {
    00031         v->current_order.travel_time = time;
    00032       } else {
    00033         v->current_order.wait_time = time;
    00034       }
    00035     }
    00036     InvalidateWindow(WC_VEHICLE_TIMETABLE, v->index);
    00037   }
    00038 }
    00039
    00055 CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00056 {
    00057   if (!_settings_game.order.timetabling) return CMD_ERROR;
    00058
    00059   VehicleID veh = GB(p1, 0, 16);
    00060   if (!IsValidVehicleID(veh)) return CMD_ERROR;
    00061
    00062   Vehicle *v = GetVehicle(veh);
    00063   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    00064
    00065   VehicleOrderID order_number = GB(p1, 16, 8);
    00066   Order *order = GetVehicleOrder(v, order_number);
    00067   if (order == NULL) return CMD_ERROR;
    00068
    00069   bool packed_time = HasBit(p1, 25);
    00070   bool is_journey = HasBit(p1, 24) || packed_time;
    00071
    00072   int wait_time   = order->wait_time;
    00073   int travel_time = order->travel_time;
    00074   if (packed_time) {
    00075     travel_time = GB(p2, 0, 16);
    00076     wait_time   = GB(p2, 16, 16);;
    00077   } else if (is_journey) {
    00078     travel_time = GB(p2, 0, 16);
    00079   } else {
    00080     wait_time   = GB(p2, 0, 16);
    00081   }
    00082
    00083   if (wait_time != order->wait_time) {
    00084     switch (order->GetType()) {
    00085       case OT_GOTO_STATION:
    00086         if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return_cmd_error(STR_TIMETABLE_NOT_STOPPING_HERE);
    00087         break;
    00088
    00089       case OT_CONDITIONAL:
    00090         break;
    00091
    00092       default: return_cmd_error(STR_TIMETABLE_ONLY_WAIT_AT_STATIONS);
    00093     }
    00094   }
    00095
    00096   if (travel_time != order->travel_time && order->IsType(OT_CONDITIONAL)) return CMD_ERROR;
    00097
    00098   if (flags & DC_EXEC) {
    00099     if (wait_time   != order->wait_time)   ChangeTimetable(v, order_number, wait_time,   false);
    00100     if (travel_time != order->travel_time) ChangeTimetable(v, order_number, travel_time, true);
    00101   }
    00102
    00103   return CommandCost();
    00104 }
    00105
    00113 CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00114 {
    00115   if (!_settings_game.order.timetabling) return CMD_ERROR;
    00116
    00117   VehicleID veh = GB(p1, 0, 16);
    00118   if (!IsValidVehicleID(veh)) return CMD_ERROR;
    00119
    00120   Vehicle *v = GetVehicle(veh);
    00121   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    00122
    00123   if (flags & DC_EXEC) {
    00124     v->lateness_counter = 0;
    00125   }
    00126
    00127   return CommandCost();
    00128 }
    00129
    00141 CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00142 {
    00143   if (!_settings_game.order.timetabling) return CMD_ERROR;
    00144
    00145   VehicleID veh = GB(p1, 0, 16);
    00146   if (!IsValidVehicleID(veh)) return CMD_ERROR;
    00147
    00148   Vehicle *v = GetVehicle(veh);
    00149   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    00150
    00151   if (flags & DC_EXEC) {
    00152     if (HasBit(p2, 0)) {
    00153       /* Start autofilling the timetable, which clears the
    00154        * "timetable has started" bit. Times are not cleared anymore, but are
    00155        * overwritten when the order is reached now. */
    00156       SetBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
    00157       ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
    00158
    00159       /* Overwrite waiting times only if they got longer */
    00160       if (HasBit(p2, 1)) SetBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
    00161
    00162       v->lateness_counter = 0;
    00163     } else {
    00164       ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
    00165       ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
    00166     }
    00167   }
    00168
    00169   for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
    00170     if (v2 != v) {
    00171       /* Stop autofilling; only one vehicle at a time can perform autofill */
    00172       ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE);
    00173       ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
    00174     }
    00175     InvalidateWindow(WC_VEHICLE_TIMETABLE, v2->index);
    00176   }
    00177
    00178   return CommandCost();
    00179 }
    00180
    00181 void UpdateVehicleTimetable(Vehicle *v, bool travelling)
    00182 {
    00183   uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time;
    00184   uint time_taken = v->current_order_time;
    00185
    00186   v->current_order_time = 0;
    00187
    00188   if (!_settings_game.order.timetabling) return;
    00189
    00190   bool just_started = false;
    00191
    00192   /* Make sure the timetable only starts when the vehicle reaches the first
    00193    * order, not when travelling from the depot to the first station. */
    00194   if (v->cur_order_index == 0 && !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) {
    00195     SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
    00196     just_started = true;
    00197   }
    00198
    00199   if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return;
    00200
    00201   if (HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) {
    00202     if (travelling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) {
    00203       /* Need to clear that now as otherwise we are not able to reduce the wait time */
    00204       v->current_order.wait_time = 0;
    00205     }
    00206
    00207     if (just_started) return;
    00208
    00209     /* Modify station waiting time only if our new value is larger (this is
    00210      * always the case when we cleared the timetable). */
    00211     if (!v->current_order.IsType(OT_CONDITIONAL) && (travelling || time_taken > v->current_order.wait_time)) {
    00212       /* Round the time taken up to the nearest day, as this will avoid
    00213        * confusion for people who are timetabling in days, and can be
    00214        * adjusted later by people who aren't. */
    00215       time_taken = (((time_taken - 1) / DAY_TICKS) + 1) * DAY_TICKS;
    00216
    00217       ChangeTimetable(v, v->cur_order_index, time_taken, travelling);
    00218     }
    00219
    00220     if (v->cur_order_index == 0 && travelling) {
    00221       /* If we just started we would have returned earlier and have not reached
    00222        * this code. So obviously, we have completed our round: So turn autofill
    00223        * off again. */
    00224       ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
    00225       ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
    00226     }
    00227     return;
    00228   }
    00229
    00230   if (just_started) return;
    00231
    00232   /* Vehicles will wait at stations if they arrive early even if they are not
    00233    * timetabled to wait there, so make sure the lateness counter is updated
    00234    * when this happens. */
    00235   if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return;
    00236
    00237   v->lateness_counter -= (timetabled - time_taken);
    00238
    00239   for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
    00240     InvalidateWindow(WC_VEHICLE_TIMETABLE, v->index);
    00241   }
    00242 }