118 } |
118 } |
119 |
119 |
120 bool VehicleNeedsService(const Vehicle *v) |
120 bool VehicleNeedsService(const Vehicle *v) |
121 { |
121 { |
122 if (v->vehstatus & (VS_STOPPED | VS_CRASHED)) return false; |
122 if (v->vehstatus & (VS_STOPPED | VS_CRASHED)) return false; |
123 if (v->current_order.type != OT_GOTO_DEPOT || !(v->current_order.flags & OFB_PART_OF_ORDERS)) { // Don't interfere with a depot visit by the order list |
123 if (!v->current_order.IsType(OT_GOTO_DEPOT) || !(v->current_order.GetDepotOrderType() & OFB_PART_OF_ORDERS)) { // Don't interfere with a depot visit by the order list |
124 if (_patches.gotodepot && VehicleHasDepotOrders(v)) return false; |
124 if (_patches.gotodepot && VehicleHasDepotOrders(v)) return false; |
125 if (v->current_order.type == OT_LOADING) return false; |
125 if (v->current_order.IsType(OT_LOADING)) return false; |
126 if (v->current_order.type == OT_GOTO_DEPOT && v->current_order.flags & OFB_HALT_IN_DEPOT) return false; |
126 if (v->current_order.IsType(OT_GOTO_DEPOT) && v->current_order.GetDepotActionType() & OFB_HALT_IN_DEPOT) return false; |
127 } |
127 } |
128 |
128 |
129 if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) { |
129 if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) { |
130 return EngineHasReplacementForPlayer(GetPlayer(v->owner), v->engine_type, v->group_id); /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off */ |
130 return EngineHasReplacementForPlayer(GetPlayer(v->owner), v->engine_type, v->group_id); /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off */ |
131 } |
131 } |
629 */ |
629 */ |
630 void VehicleEnteredDepotThisTick(Vehicle *v) |
630 void VehicleEnteredDepotThisTick(Vehicle *v) |
631 { |
631 { |
632 /* We need to set v->leave_depot_instantly as we have no control of it's contents at this time. |
632 /* We need to set v->leave_depot_instantly as we have no control of it's contents at this time. |
633 * Vehicle should stop in the depot if it was in 'stopping' state - train intered depot while slowing down. */ |
633 * Vehicle should stop in the depot if it was in 'stopping' state - train intered depot while slowing down. */ |
634 if ((HasBit(v->current_order.flags, OF_HALT_IN_DEPOT) && !HasBit(v->current_order.flags, OF_PART_OF_ORDERS) && v->current_order.type == OT_GOTO_DEPOT) || |
634 if ((HasBit(v->current_order.GetDepotActionType(), OF_HALT_IN_DEPOT) && !HasBit(v->current_order.GetDepotOrderType(), OF_PART_OF_ORDERS) && v->current_order.IsType(OT_GOTO_DEPOT)) || |
635 (v->vehstatus & VS_STOPPED)) { |
635 (v->vehstatus & VS_STOPPED)) { |
636 /* we keep the vehicle in the depot since the user ordered it to stay */ |
636 /* we keep the vehicle in the depot since the user ordered it to stay */ |
637 v->leave_depot_instantly = false; |
637 v->leave_depot_instantly = false; |
638 } else { |
638 } else { |
639 /* the vehicle do not plan on stopping in the depot, so we stop it to ensure that it will not reserve the path |
639 /* the vehicle do not plan on stopping in the depot, so we stop it to ensure that it will not reserve the path |
765 } else { |
765 } else { |
766 pal = PAL_NONE; |
766 pal = PAL_NONE; |
767 } |
767 } |
768 |
768 |
769 AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs, |
769 AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs, |
770 v->sprite_width, v->sprite_height, v->z_height, v->z_pos, (v->vehstatus & VS_SHADOW) != 0); |
770 v->x_extent, v->y_extent, v->z_extent, v->z_pos, (v->vehstatus & VS_SHADOW) != 0); |
771 } |
771 } |
772 |
772 |
773 void ViewportAddVehicles(DrawPixelInfo *dpi) |
773 void ViewportAddVehicles(DrawPixelInfo *dpi) |
774 { |
774 { |
775 /* The bounding rectangle */ |
775 /* The bounding rectangle */ |
2031 FOR_ALL_VEHICLES(v) { |
2031 FOR_ALL_VEHICLES(v) { |
2032 if (v->type == type && v->IsPrimaryVehicle()) { |
2032 if (v->type == type && v->IsPrimaryVehicle()) { |
2033 const Order *order; |
2033 const Order *order; |
2034 |
2034 |
2035 FOR_VEHICLE_ORDERS(v, order) { |
2035 FOR_VEHICLE_ORDERS(v, order) { |
2036 if (order->type == OT_GOTO_STATION && order->dest == index) { |
2036 if (order->IsType(OT_GOTO_STATION) && order->GetDestination() == index) { |
2037 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50); |
2037 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50); |
2038 (*sort_list)[n++] = v; |
2038 (*sort_list)[n++] = v; |
2039 break; |
2039 break; |
2040 } |
2040 } |
2041 } |
2041 } |
2075 FOR_ALL_VEHICLES(v) { |
2075 FOR_ALL_VEHICLES(v) { |
2076 if (v->type == type && v->IsPrimaryVehicle()) { |
2076 if (v->type == type && v->IsPrimaryVehicle()) { |
2077 const Order *order; |
2077 const Order *order; |
2078 |
2078 |
2079 FOR_VEHICLE_ORDERS(v, order) { |
2079 FOR_VEHICLE_ORDERS(v, order) { |
2080 if (order->type == OT_GOTO_DEPOT && order->dest == index) { |
2080 if (order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == index) { |
2081 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25); |
2081 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25); |
2082 (*sort_list)[n++] = v; |
2082 (*sort_list)[n++] = v; |
2083 break; |
2083 break; |
2084 } |
2084 } |
2085 } |
2085 } |
2172 for (; v != NULL; v = v->Next()) { |
2172 for (; v != NULL; v = v->Next()) { |
2173 count += v->cargo.Count(); |
2173 count += v->cargo.Count(); |
2174 max += v->cargo_cap; |
2174 max += v->cargo_cap; |
2175 if (v->cargo_cap != 0) { |
2175 if (v->cargo_cap != 0) { |
2176 unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0; |
2176 unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0; |
2177 loading |= (u->current_order.flags & OFB_UNLOAD) == 0 && st->goods[v->cargo_type].days_since_pickup != 255; |
2177 loading |= !HasBit(u->current_order.GetUnloadType(), OF_UNLOAD) && st->goods[v->cargo_type].days_since_pickup != 255; |
2178 cars++; |
2178 cars++; |
2179 } |
2179 } |
2180 } |
2180 } |
2181 |
2181 |
2182 if (unloading == 0 && loading) *color = STR_PERCENT_UP; |
2182 if (unloading == 0 && loading) *color = STR_PERCENT_UP; |
2233 |
2233 |
2234 VehicleServiceInDepot(v); |
2234 VehicleServiceInDepot(v); |
2235 |
2235 |
2236 TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); |
2236 TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); |
2237 |
2237 |
2238 if (v->current_order.type == OT_GOTO_DEPOT) { |
2238 if (v->current_order.IsType(OT_GOTO_DEPOT)) { |
2239 Order t; |
2239 Order t; |
2240 |
2240 |
2241 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
2241 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
2242 |
2242 |
2243 t = v->current_order; |
2243 t = v->current_order; |
2244 v->current_order.type = OT_DUMMY; |
2244 v->current_order.MakeDummy(); |
2245 v->current_order.flags = 0; |
2245 |
2246 |
2246 if (t.IsRefit()) { |
2247 if (t.refit_cargo < NUM_CARGO) { |
|
2248 CommandCost cost; |
2247 CommandCost cost; |
2249 |
2248 |
2250 _current_player = v->owner; |
2249 _current_player = v->owner; |
2251 cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, GetCmdRefitVeh(v)); |
2250 cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v)); |
2252 |
2251 |
2253 if (CmdFailed(cost)) { |
2252 if (CmdFailed(cost)) { |
2254 v->leave_depot_instantly = false; // We ensure that the vehicle stays in the depot |
2253 v->leave_depot_instantly = false; // We ensure that the vehicle stays in the depot |
2255 if (v->owner == _local_player) { |
2254 if (v->owner == _local_player) { |
2256 /* Notify the user that we stopped the vehicle */ |
2255 /* Notify the user that we stopped the vehicle */ |
2261 } else if (v->owner == _local_player && cost.GetCost() != 0) { |
2260 } else if (v->owner == _local_player && cost.GetCost() != 0) { |
2262 ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost()); |
2261 ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost()); |
2263 } |
2262 } |
2264 } |
2263 } |
2265 |
2264 |
2266 if (HasBit(t.flags, OF_PART_OF_ORDERS)) { |
2265 if (HasBit(t.GetDepotOrderType(), OF_PART_OF_ORDERS)) { |
2267 /* Part of orders */ |
2266 /* Part of orders */ |
2268 UpdateVehicleTimetable(v, true); |
2267 UpdateVehicleTimetable(v, true); |
2269 v->cur_order_index++; |
2268 v->cur_order_index++; |
2270 } else if (HasBit(t.flags, OF_HALT_IN_DEPOT)) { |
2269 } else if (HasBit(t.GetDepotActionType(), OF_HALT_IN_DEPOT)) { |
2271 /* Force depot visit */ |
2270 /* Force depot visit */ |
2272 v->vehstatus |= VS_STOPPED; |
2271 v->vehstatus |= VS_STOPPED; |
2273 if (v->owner == _local_player) { |
2272 if (v->owner == _local_player) { |
2274 StringID string; |
2273 StringID string; |
2275 |
2274 |
3095 v->last_station_visited = INVALID_STATION; |
3094 v->last_station_visited = INVALID_STATION; |
3096 |
3095 |
3097 if (CheckSavegameVersion(5)) { |
3096 if (CheckSavegameVersion(5)) { |
3098 /* Convert the current_order.type (which is a mix of type and flags, because |
3097 /* Convert the current_order.type (which is a mix of type and flags, because |
3099 * in those versions, they both were 4 bits big) to type and flags */ |
3098 * in those versions, they both were 4 bits big) to type and flags */ |
3100 v->current_order.flags = (v->current_order.type & 0xF0) >> 4; |
3099 v->current_order.flags = GB(v->current_order.type, 4, 4); |
3101 v->current_order.type.m_val &= 0x0F; |
3100 v->current_order.type.m_val &= 0x0F; |
3102 } |
3101 } |
3103 |
3102 |
3104 /* Advanced vehicle lists got added */ |
3103 /* Advanced vehicle lists got added */ |
3105 if (CheckSavegameVersion(60)) v->group_id = DEFAULT_GROUP; |
3104 if (CheckSavegameVersion(60)) v->group_id = DEFAULT_GROUP; |
3129 |
3128 |
3130 void Vehicle::BeginLoading() |
3129 void Vehicle::BeginLoading() |
3131 { |
3130 { |
3132 assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP); |
3131 assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP); |
3133 |
3132 |
3134 if (this->current_order.type == OT_GOTO_STATION && |
3133 if (this->current_order.IsType(OT_GOTO_STATION) && |
3135 this->current_order.dest == this->last_station_visited) { |
3134 this->current_order.GetDestination() == this->last_station_visited) { |
3136 /* Arriving at the ordered station. |
|
3137 * Keep the load/unload flags, as we (obviously) still need them. */ |
|
3138 this->current_order.flags &= OFB_FULL_LOAD | OFB_UNLOAD | OFB_TRANSFER; |
|
3139 |
|
3140 /* Furthermore add the Non Stop flag to mark that this station |
3135 /* Furthermore add the Non Stop flag to mark that this station |
3141 * is the actual destination of the vehicle, which is (for example) |
3136 * is the actual destination of the vehicle, which is (for example) |
3142 * necessary to be known for HandleTrainLoading to determine |
3137 * necessary to be known for HandleTrainLoading to determine |
3143 * whether the train is lost or not; not marking a train lost |
3138 * whether the train is lost or not; not marking a train lost |
3144 * that arrives at random stations is bad. */ |
3139 * that arrives at random stations is bad. */ |
3145 this->current_order.flags |= OFB_NON_STOP; |
3140 this->current_order.SetNonStopType(OFB_NON_STOP); |
|
3141 |
|
3142 current_order.MakeLoading(true); |
3146 UpdateVehicleTimetable(this, true); |
3143 UpdateVehicleTimetable(this, true); |
3147 } else { |
3144 } else { |
3148 /* This is just an unordered intermediate stop */ |
3145 this->current_order.SetNonStopType(OFB_NO_NON_STOP); |
3149 this->current_order.flags = 0; |
3146 current_order.MakeLoading(false); |
3150 } |
3147 } |
3151 |
3148 |
3152 current_order.type = OT_LOADING; |
|
3153 GetStation(this->last_station_visited)->loading_vehicles.push_back(this); |
3149 GetStation(this->last_station_visited)->loading_vehicles.push_back(this); |
3154 |
3150 |
3155 VehiclePayment(this); |
3151 VehiclePayment(this); |
3156 |
3152 |
3157 InvalidateWindow(this->GetVehicleListWindowClass(), this->owner); |
3153 InvalidateWindow(this->GetVehicleListWindowClass(), this->owner); |
3163 this->MarkDirty(); |
3159 this->MarkDirty(); |
3164 } |
3160 } |
3165 |
3161 |
3166 void Vehicle::LeaveStation() |
3162 void Vehicle::LeaveStation() |
3167 { |
3163 { |
3168 assert(current_order.type == OT_LOADING); |
3164 assert(current_order.IsType(OT_LOADING)); |
3169 |
3165 |
3170 /* Only update the timetable if the vehicle was supposed to stop here. */ |
3166 /* Only update the timetable if the vehicle was supposed to stop here. */ |
3171 if (current_order.flags & OFB_NON_STOP) UpdateVehicleTimetable(this, false); |
3167 if (current_order.GetNonStopType() != OFB_NO_NON_STOP) UpdateVehicleTimetable(this, false); |
3172 |
3168 |
3173 current_order.type = OT_LEAVESTATION; |
3169 current_order.MakeLeaveStation(); |
3174 current_order.flags = 0; |
|
3175 GetStation(this->last_station_visited)->loading_vehicles.remove(this); |
3170 GetStation(this->last_station_visited)->loading_vehicles.remove(this); |
3176 |
3171 |
3177 HideFillingPercent(this->fill_percent_te_id); |
3172 HideFillingPercent(this->fill_percent_te_id); |
3178 this->fill_percent_te_id = INVALID_TE_ID; |
3173 this->fill_percent_te_id = INVALID_TE_ID; |
3179 } |
3174 } |
3180 |
3175 |
3181 |
3176 |
3182 void Vehicle::HandleLoading(bool mode) |
3177 void Vehicle::HandleLoading(bool mode) |
3183 { |
3178 { |
3184 switch (this->current_order.type) { |
3179 switch (this->current_order.GetType()) { |
3185 case OT_LOADING: { |
3180 case OT_LOADING: { |
3186 uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0); |
3181 uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0); |
3187 |
3182 |
3188 /* Not the first call for this tick, or still loading */ |
3183 /* Not the first call for this tick, or still loading */ |
3189 if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || |
3184 if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || |
3193 |
3188 |
3194 Order b = this->current_order; |
3189 Order b = this->current_order; |
3195 this->LeaveStation(); |
3190 this->LeaveStation(); |
3196 |
3191 |
3197 /* If this was not the final order, don't remove it from the list. */ |
3192 /* If this was not the final order, don't remove it from the list. */ |
3198 if (!(b.flags & OFB_NON_STOP)) return; |
3193 if (!(b.GetNonStopType() & OFB_NON_STOP)) return; |
3199 break; |
3194 break; |
3200 } |
3195 } |
3201 |
3196 |
3202 case OT_DUMMY: break; |
3197 case OT_DUMMY: break; |
3203 |
3198 |