00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "command_func.h"
00014 #include "company_func.h"
00015 #include "date_func.h"
00016 #include "window_func.h"
00017 #include "vehicle_base.h"
00018
00019 #include "table/strings.h"
00020
00021 static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 time, bool is_journey)
00022 {
00023 Order *order = v->GetOrder(order_number);
00024 int delta;
00025
00026 if (is_journey) {
00027 delta = time - order->travel_time;
00028 order->travel_time = time;
00029 } else {
00030 delta = time - order->wait_time;
00031 order->wait_time = time;
00032 }
00033 v->orders.list->UpdateOrderTimetable(delta);
00034
00035 for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
00036 if (v->cur_real_order_index == order_number && v->current_order.Equals(*order)) {
00037 if (is_journey) {
00038 v->current_order.travel_time = time;
00039 } else {
00040 v->current_order.wait_time = time;
00041 }
00042 }
00043 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00044 }
00045 }
00046
00061 CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00062 {
00063 VehicleID veh = GB(p1, 0, 20);
00064
00065 Vehicle *v = Vehicle::GetIfValid(veh);
00066 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00067
00068 CommandCost ret = CheckOwnership(v->owner);
00069 if (ret.Failed()) return ret;
00070
00071 VehicleOrderID order_number = GB(p1, 20, 8);
00072 Order *order = v->GetOrder(order_number);
00073 if (order == NULL || order->IsType(OT_IMPLICIT)) return CMD_ERROR;
00074
00075 bool is_journey = HasBit(p1, 28);
00076
00077 int wait_time = order->wait_time;
00078 int travel_time = order->travel_time;
00079 if (is_journey) {
00080 travel_time = GB(p2, 0, 16);
00081 } else {
00082 wait_time = GB(p2, 0, 16);
00083 }
00084
00085 if (wait_time != order->wait_time) {
00086 switch (order->GetType()) {
00087 case OT_GOTO_STATION:
00088 if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return_cmd_error(STR_ERROR_TIMETABLE_NOT_STOPPING_HERE);
00089 break;
00090
00091 case OT_CONDITIONAL:
00092 break;
00093
00094 default: return_cmd_error(STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS);
00095 }
00096 }
00097
00098 if (travel_time != order->travel_time && order->IsType(OT_CONDITIONAL)) return CMD_ERROR;
00099
00100 if (flags & DC_EXEC) {
00101 if (wait_time != order->wait_time) ChangeTimetable(v, order_number, wait_time, false);
00102 if (travel_time != order->travel_time) ChangeTimetable(v, order_number, travel_time, true);
00103 }
00104
00105 return CommandCost();
00106 }
00107
00118 CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00119 {
00120 VehicleID veh = GB(p1, 0, 20);
00121
00122 Vehicle *v = Vehicle::GetIfValid(veh);
00123 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00124
00125 CommandCost ret = CheckOwnership(v->owner);
00126 if (ret.Failed()) return ret;
00127
00128 if (flags & DC_EXEC) {
00129 v->lateness_counter = 0;
00130 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00131 }
00132
00133 return CommandCost();
00134 }
00135
00145 CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00146 {
00147 Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));
00148 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00149
00150 CommandCost ret = CheckOwnership(v->owner);
00151 if (ret.Failed()) return ret;
00152
00153
00154 Date start_date = (Date)p2;
00155 if (start_date < 0 || start_date > MAX_DAY) return CMD_ERROR;
00156 if (start_date - _date > 15 * DAYS_IN_LEAP_YEAR) return CMD_ERROR;
00157 if (_date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR;
00158
00159 if (flags & DC_EXEC) {
00160 v->lateness_counter = 0;
00161 ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00162 v->timetable_start = start_date;
00163
00164 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00165 }
00166
00167 return CommandCost();
00168 }
00169
00170
00184 CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00185 {
00186 VehicleID veh = GB(p1, 0, 20);
00187
00188 Vehicle *v = Vehicle::GetIfValid(veh);
00189 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00190
00191 CommandCost ret = CheckOwnership(v->owner);
00192 if (ret.Failed()) return ret;
00193
00194 if (flags & DC_EXEC) {
00195 if (HasBit(p2, 0)) {
00196
00197
00198
00199 SetBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00200 ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00201
00202
00203 if (HasBit(p2, 1)) SetBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00204
00205 v->timetable_start = 0;
00206 v->lateness_counter = 0;
00207 } else {
00208 ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00209 ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00210 }
00211
00212 for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
00213 if (v2 != v) {
00214
00215 ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00216 ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00217 }
00218 SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index);
00219 }
00220 }
00221
00222 return CommandCost();
00223 }
00224
00225 void UpdateVehicleTimetable(Vehicle *v, bool travelling)
00226 {
00227 uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time;
00228 uint time_taken = v->current_order_time;
00229
00230 v->current_order_time = 0;
00231
00232 if (v->current_order.IsType(OT_IMPLICIT)) return;
00233
00234 VehicleOrderID first_manual_order = 0;
00235 for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_IMPLICIT); o = o->next) {
00236 ++first_manual_order;
00237 }
00238
00239 bool just_started = false;
00240
00241
00242 if (v->cur_real_order_index == first_manual_order && travelling) {
00243
00244
00245
00246
00247 just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00248
00249 if (v->timetable_start != 0) {
00250 v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract;
00251 v->timetable_start = 0;
00252 }
00253
00254 SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00255 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00256 }
00257
00258 if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return;
00259
00260 if (HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) {
00261 if (travelling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) {
00262
00263 v->current_order.wait_time = 0;
00264 }
00265
00266 if (just_started) return;
00267
00268
00269
00270 if (!v->current_order.IsType(OT_CONDITIONAL) && (travelling || time_taken > v->current_order.wait_time)) {
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 time_taken = CeilDiv(max(time_taken, 1U), DAY_TICKS) * DAY_TICKS;
00281
00282 ChangeTimetable(v, v->cur_real_order_index, time_taken, travelling);
00283 }
00284
00285 if (v->cur_real_order_index == first_manual_order && travelling) {
00286
00287
00288
00289 ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00290 ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00291 }
00292 return;
00293 }
00294
00295 if (just_started) return;
00296
00297
00298
00299
00300 if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return;
00301
00302 v->lateness_counter -= (timetabled - time_taken);
00303
00304
00305
00306
00307
00308
00309 if (v->lateness_counter > (int)timetabled) {
00310 Ticks cycle = v->orders.list->GetTimetableTotalDuration();
00311 if (cycle != INVALID_TICKS && v->lateness_counter > cycle) {
00312 v->lateness_counter %= cycle;
00313 }
00314 }
00315
00316 for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
00317 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00318 }
00319 }