timetable_cmd.cpp

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

Generated on Fri Jan 9 19:01:52 2009 for openttd by  doxygen 1.5.6