1
0
Fork 0

Feature: Show servicing vehicles in extended depots on viewport and on vehicle window.

pull/8480/head
J0anJosep 2020-12-24 00:38:26 +01:00
parent 9869611ad8
commit 3715dcf2d7
9 changed files with 227 additions and 10 deletions

View File

@ -4441,6 +4441,7 @@ STR_VEHICLE_STATUS_STOPPED :{RED}Stopped
STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}{VELOCITY} - Stopping
STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}No power
STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Waiting for free path
STR_VEHICLE_STATUS_SERVICING :{LTBLUE}Servicing vehicle
STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Too far to next destination
STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}{1:VELOCITY} - Heading for {0:STATION}
@ -4928,6 +4929,8 @@ STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHI
STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW}
STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW}
STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW}
STR_SERVICING_INDICATOR_SMALL :{TINY_FONT}{LTBLUE}Servicing ({NUM}{NBSP}%)
STR_SERVICING_INDICATOR :{LTBLUE}Servicing ({NUM}{NBSP}%)
STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}%
STR_PERCENT_NONE :{WHITE}{NUM}%

View File

@ -485,11 +485,10 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
* to a depot (other vehicle types). */
if (::Vehicle::Get(vehicle_id)->type == VEH_AIRCRAFT) {
if (!::IsTileType(destination, MP_STATION)) return false;
order.MakeGoToDepot(::GetStationIndex(destination), odtf, onsf, odaf);
} else {
if (::IsTileType(destination, MP_STATION)) return false;
order.MakeGoToDepot(::GetDepotIndex(destination), odtf, onsf, odaf);
}
order.MakeGoToDepot(::GetDepotIndex(destination), odtf, onsf, odaf);
}
break;
}

View File

@ -60,7 +60,7 @@ ScriptVehicleList_Depot::ScriptVehicleList_Depot(TileIndex tile)
case MP_STATION: // Aircraft
if (!IsAirport(tile)) return;
type = VEH_AIRCRAFT;
dest = GetStationIndex(tile);
dest = GetDepotIndex(tile);
break;
case MP_RAILWAY:

View File

@ -374,6 +374,25 @@ static bool CheckReverseShip(const Ship *v, Trackdir *trackdir = nullptr)
return YapfShipCheckReverse(v, trackdir);
}
void HandleShipEnterDepot(Ship *v)
{
assert(IsShipDepotTile(v->tile));
if (IsExtendedDepot(v->tile)) {
v->state |= TRACK_BIT_DEPOT;
v->cur_speed = 0;
v->UpdateCache();
v->UpdateViewport(true, true);
SetWindowClassesDirty(WC_SHIPS_LIST);
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile));
v->StartService();
} else {
VehicleEnterDepot(v);
}
}
static bool CheckShipLeaveDepot(Ship *v)
{
if (!v->IsChainInDepot()) return false;

View File

@ -181,6 +181,117 @@ void VehicleServiceInDepot(Vehicle *v)
} while (v != nullptr && v->HasEngineType());
}
/**
* List of vehicles that should check for autoreplace this tick.
* Mapping of vehicle -> leave depot immediately after autoreplace.
*/
using AutoreplaceMap = std::map<VehicleID, bool>;
static AutoreplaceMap _vehicles_to_autoreplace;
void VehicleServiceInExtendedDepot(Vehicle *v)
{
/* Always work with the front of the vehicle */
assert(v == v->First());
assert(IsExtendedDepotTile(v->tile));
switch (v->type) {
case VEH_TRAIN: {
SetWindowClassesDirty(WC_TRAINS_LIST);
Train *t = Train::From(v);
t->ConsistChanged(CCF_ARRANGE);
t->UpdateViewport(true, true);
break;
}
case VEH_SHIP: {
SetWindowClassesDirty(WC_SHIPS_LIST);
Ship *ship = Ship::From(v);
ship->UpdateCache();
ship->UpdateViewport(true, true);
break;
}
case VEH_ROAD:
SetWindowClassesDirty(WC_ROADVEH_LIST);
break;
case VEH_AIRCRAFT:
SetWindowClassesDirty(WC_AIRCRAFT_LIST);
break;
default: NOT_REACHED();
}
DepotID depot_id = GetDepotIndex(v->tile);
SetWindowDirty(WC_VEHICLE_DEPOT, depot_id);
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
InvalidateWindowData(WC_VEHICLE_DEPOT, depot_id);
VehicleServiceInDepot(v);
/* After a vehicle trigger, the graphics and properties of the vehicle could change. */
TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
v->MarkDirty();
if (v->current_order.IsType(OT_GOTO_DEPOT)) {
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
const Order *real_order = v->GetOrder(v->cur_real_order_index);
Order t = v->current_order;
v->current_order.MakeDummy();
/* Test whether we are heading for this depot. If not, do nothing.
* Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
real_order != nullptr && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
t.GetDestination() != GetDepotIndex(v->tile)) {
/* We are heading for another depot, keep driving. */
return;
}
if (t.IsRefit()) {
Backup<CompanyID> cur_company(_current_company, v->owner);
CommandCost cost = std::get<0>(Command<CMD_REFIT_VEHICLE>::Do(DC_EXEC, v->index, t.GetRefitCargo(), 0xFF, false, false, 0));
cur_company.Restore();
if (cost.Failed()) {
_vehicles_to_autoreplace[v->index] = false;
if (v->owner == _local_company) {
/* Notify the user that we stopped the vehicle */
SetDParam(0, v->index);
AddVehicleAdviceNewsItem(STR_NEWS_ORDER_REFIT_FAILED, v->index);
}
} else if (cost.GetCost() != 0) {
v->profit_this_year -= cost.GetCost() << 8;
if (v->owner == _local_company) {
ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
}
}
}
if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
/* Part of orders */
v->DeleteUnreachedImplicitOrders();
UpdateVehicleTimetable(v, true);
v->IncrementImplicitOrderIndex();
}
if (t.GetDepotActionType() & ODATFB_HALT) {
/* Vehicles are always stopped on entering depots. Do not restart this one. */
_vehicles_to_autoreplace[v->index] = false;
/* Invalidate last_loading_station. As the link from the station
* before the stop to the station after the stop can't be predicted
* we shouldn't construct it when the vehicle visits the next stop. */
v->last_loading_station = INVALID_STATION;
if (v->owner == _local_company) {
SetDParam(0, v->index);
AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index);
}
AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
}
}
}
/**
* Check if the vehicle needs to go to a depot in near future (if a opportunity presents itself) for service or replacement.
*
@ -687,13 +798,6 @@ void ResetVehicleColourMap()
for (Vehicle *v : Vehicle::Iterate()) { v->colourmap = PAL_NONE; }
}
/**
* List of vehicles that should check for autoreplace this tick.
* Mapping of vehicle -> leave depot immediately after autoreplace.
*/
using AutoreplaceMap = std::map<VehicleID, bool>;
static AutoreplaceMap _vehicles_to_autoreplace;
void InitializeVehicles()
{
_vehicles_to_autoreplace.clear();

View File

@ -52,6 +52,7 @@ enum VehicleFlags {
VF_PATHFINDER_LOST, ///< Vehicle's pathfinder is lost.
VF_SERVINT_IS_CUSTOM, ///< Service interval is custom.
VF_SERVINT_IS_PERCENT, ///< Service interval is percent.
VF_IS_SERVICING, ///< Vehicle is servicing.
};
/** Bit numbers used to indicate which of the #NewGRFCache values are valid. */
@ -782,6 +783,12 @@ public:
bool HandleBreakdown();
bool IsServicing() const { return HasBit(this->vehicle_flags, VF_IS_SERVICING); }
void StartService();
bool ContinueServicing();
void StopServicing();
bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const;
bool NeedsServicing() const;

View File

@ -1131,3 +1131,85 @@ CommandCost CmdChangeServiceInt(DoCommandFlag flags, VehicleID veh_id, uint16_t
return CommandCost();
}
const uint16_t DEFAULT_SERVICE_TIME = 1 << 7;
const uint16_t TRAIN_SERVICE_TIME = 1 << 8;
/**
* A vehicle that entered an extended depot, starts servicing.
*/
void Vehicle::StartService()
{
assert(IsExtendedDepotTile(this->tile));
switch (this->type) {
case VEH_AIRCRAFT:
case VEH_ROAD:
case VEH_SHIP: {
this->wait_counter = DEFAULT_SERVICE_TIME;
break;
}
case VEH_TRAIN: {
this->wait_counter = TRAIN_SERVICE_TIME;
break;
}
default: NOT_REACHED();
}
this->cur_speed = 0;
this->subspeed = 0;
SetBit(this->vehicle_flags, VF_IS_SERVICING);
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
assert(this->fill_percent_te_id == INVALID_TE_ID);
this->fill_percent_te_id = ShowFillingPercent(this->x_pos, this->y_pos, this->z_pos + 20, 0, STR_SERVICING_INDICATOR);
}
/**
* Check if vehicle is servicing.
* If it is servicing, decrease time till finishing the servicing.
* It services the vehicle when servicing time ends.
* @return true if the vehicle is still servicing, false if it is not servicing.
*/
bool Vehicle::ContinueServicing()
{
if (!HasBit(this->vehicle_flags, VF_IS_SERVICING)) return false;
/* Update text effect every 16 ticks. */
if ((this->wait_counter & 15) == 0) {
uint8_t percent;
uint16_t max = this->type == VEH_TRAIN ? TRAIN_SERVICE_TIME : DEFAULT_SERVICE_TIME;
/* Return the percentage */
if ((max - this->wait_counter) * 2 < max) {
/* Less than 50%; round up, so that 0% means really empty. */
percent = (uint8_t)CeilDiv((max - this->wait_counter) * 100, max);
} else {
/* More than 50%; round down, so that 100% means really full. */
percent = (uint8_t)(((max - this->wait_counter) * 100) / max);
}
if (this->fill_percent_te_id == INVALID_TE_ID) {
this->fill_percent_te_id = ShowFillingPercent(this->x_pos, this->y_pos, this->z_pos + 20, percent, STR_SERVICING_INDICATOR);
} else {
UpdateFillingPercent(this->fill_percent_te_id, percent, STR_SERVICING_INDICATOR);
}
}
if (this->wait_counter--) return true;
VehicleServiceInExtendedDepot(this);
this->StopServicing();
return false;
}
void Vehicle::StopServicing()
{
this->wait_counter = 0;
/* End servicing. */
ClrBit(this->vehicle_flags, VF_IS_SERVICING);
HideFillingPercent(&this->fill_percent_te_id);
InvalidateWindowData(WC_VEHICLE_VIEW, this->index);
}

View File

@ -40,6 +40,7 @@ bool IsValidImageIndex(uint8_t image_index);
typedef Vehicle *VehicleFromPosProc(Vehicle *v, void *data);
void VehicleServiceInDepot(Vehicle *v);
void VehicleServiceInExtendedDepot(Vehicle *v);
uint CountVehiclesInChain(const Vehicle *v);
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc);

View File

@ -3111,6 +3111,8 @@ public:
} else { // no train
str = STR_VEHICLE_STATUS_STOPPED;
}
} else if (HasBit(v->vehicle_flags, VF_IS_SERVICING)) {
str = STR_VEHICLE_STATUS_SERVICING;
} else if (v->IsInDepot() && v->IsWaitingForUnbunching()) {
str = STR_VEHICLE_STATUS_WAITING_UNBUNCHING;
} else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) {