diff --git a/train_cmd.c b/train_cmd.c --- a/train_cmd.c +++ b/train_cmd.c @@ -365,6 +365,35 @@ int32 EstimateTrainCost(const RailVehicl return (rvi->base_cost * (_price.build_railvehicle >> 3)) >> 5; } +void AddRearEngineToMultiheadedTrain(Vehicle *v, Vehicle *u, bool building) +{ + u->direction = v->direction; + u->owner = v->owner; + u->tile = v->tile; + u->x_pos = v->x_pos; + u->y_pos = v->y_pos; + u->z_pos = v->z_pos; + u->z_height = 6; + u->u.rail.track = 0x80; + v->u.rail.first_engine = 0xffff; + u->vehstatus = v->vehstatus & ~VS_STOPPED; + u->subtype = 2; + u->spritenum = v->spritenum + 1; + u->cargo_type = v->cargo_type; + u->cargo_cap = v->cargo_cap; + u->u.rail.railtype = v->u.rail.railtype; + if (building) v->next = u; + u->engine_type = v->engine_type; + u->build_year = v->build_year; + if (building) + v->value = u->value = v->value >> 1; + else + u->value = v->value; + u->type = VEH_Train; + u->cur_image = 0xAC2; + VehiclePositionChanged(u); +} + /* Build a railroad vehicle * p1 = vehicle type id */ @@ -442,32 +471,8 @@ int32 CmdBuildRailVehicle(int x, int y, VehiclePositionChanged(v); - if (rvi->flags&RVI_MULTIHEAD && (u=AllocateVehicle()) != NULL) { - u->direction = v->direction; - u->owner = v->owner; - u->tile = v->tile; - u->x_pos = v->x_pos; - u->y_pos = v->y_pos; - u->z_pos = v->z_pos; - u->z_height = 6; - u->u.rail.track = 0x80; - v->u.rail.first_engine = 0xffff; - u->vehstatus = VS_HIDDEN | VS_DEFPAL; - u->subtype = 2; - u->spritenum = v->spritenum + 1; - u->cargo_type = v->cargo_type; - u->cargo_cap = v->cargo_cap; - u->u.rail.railtype = v->u.rail.railtype; -// u->next_in_chain = 0xffff; - v->next = u; - u->engine_type = v->engine_type; - u->build_year = v->build_year; - v->value = u->value = v->value >> 1; -// u->day_counter = 0; - u->type = VEH_Train; - u->cur_image = 0xAC2; - VehiclePositionChanged(u); - } + if (rvi->flags&RVI_MULTIHEAD && (u = AllocateVehicle()) != NULL) + AddRearEngineToMultiheadedTrain(v, u, true); UpdateTrainAcceleration(v); NormalizeTrainVehInDepot(v); diff --git a/vehicle.c b/vehicle.c --- a/vehicle.c +++ b/vehicle.c @@ -1321,7 +1321,9 @@ int32 CmdReplaceVehicle(int x, int y, ui uint16 new_engine_type = (uint16)(p2 & 0xFFFF); uint32 autorefit_money = (p2 >> 16) * 100000; Vehicle *v = GetVehicle(p1); - int cost, build_cost; + int cost, build_cost, rear_engine_cost = 0; + Vehicle *u = v; + byte old_engine_type = v->engine_type; SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); @@ -1347,12 +1349,42 @@ int32 CmdReplaceVehicle(int x, int y, ui /* In a rare situation, when 2 clients are connected to 1 company and have the same settings, a vehicle can be replaced twice.. check if this is the situation here */ - if (v->engine_type == new_engine_type && v->age == 0) + if (old_engine_type == new_engine_type && v->age == 0) return CMD_ERROR; + + if ( v->type == VEH_Train ) { + u = GetLastVehicleInChain(v); + if ( RailVehInfo(new_engine_type)->flags & RVI_MULTIHEAD ) + build_cost = build_cost >> 1; //multiheaded engines have EstimateTrainCost() for both engines + + if ( old_engine_type != new_engine_type ) { + + // prevent that the rear engine can get replaced to something else than the front engine + if ( v->u.rail.first_engine != 0xffff && RailVehInfo(old_engine_type)->flags & RVI_MULTIHEAD && RailVehInfo(old_engine_type)->flags ) { + Vehicle *first = GetFirstVehicleInChain(v); + if ( first->engine_type != new_engine_type ) return CMD_ERROR; + } + + // checks if the engine is the first one + if ( v->u.rail.first_engine == 0xffff ) { + if ( RailVehInfo(new_engine_type)->flags & RVI_MULTIHEAD ) { + if ( u->engine_type == old_engine_type && v->next != NULL) { + rear_engine_cost = build_cost - u->value; + } else { + rear_engine_cost = build_cost; + } + } else { + if ( u->engine_type == old_engine_type && RailVehInfo(old_engine_type)->flags & RVI_MULTIHEAD) { + if (v->next != NULL) rear_engine_cost = -u->value; + } + } + } + } + } /* Check if there is money for the upgrade.. if not, give a nice news-item (that is needed, because this CMD is called automaticly) */ - if ( DEREF_PLAYER(v->owner)->money64 < (int32)(autorefit_money + build_cost - v->value)) { + if ( DEREF_PLAYER(v->owner)->money64 < (int32)(autorefit_money + build_cost + rear_engine_cost - v->value)) { if (( _local_player == v->owner ) && ( v->unitnumber != 0 )) { //v->unitnumber = 0 for train cars int message; SetDParam(0, v->unitnumber); @@ -1370,18 +1402,27 @@ int32 CmdReplaceVehicle(int x, int y, ui return CMD_ERROR; } - cost = build_cost - v->value; + cost = build_cost - v->value + rear_engine_cost; if (flags & DC_EXEC) { + /* We do not really buy a new vehicle, we upgrade the old one */ Engine *e; e = DEREF_ENGINE(new_engine_type); - // TODO make it check if refit is possible before actually doing it + v->reliability = e->reliability; + v->reliability_spd_dec = e->reliability_spd_dec; + v->age = 0; + + v->date_of_last_service = _date; + v->build_year = _cur_year; - /* We do not really buy a new vehicle, we upgrade the old one */ + v->value = build_cost; + + InvalidateWindow(WC_VEHICLE_DETAILS, v->index); + + if (v->engine_type != new_engine_type) { - byte old_engine = v->engine_type; byte sprite = v->spritenum; byte cargo_type = v->cargo_type; v->engine_type = new_engine_type; @@ -1390,11 +1431,11 @@ int32 CmdReplaceVehicle(int x, int y, ui /* Update limits of the vehicle (for when upgraded) */ switch (v->type) { case VEH_Train: - // using if (true) to declare the const { const RailVehicleInfo *rvi = RailVehInfo(new_engine_type); - const RailVehicleInfo *rvi2 = RailVehInfo(old_engine); + const RailVehicleInfo *rvi2 = RailVehInfo(old_engine_type); byte capacity = rvi->capacity; + Vehicle *first = GetFirstVehicleInChain(v); /* rvi->image_index is the new sprite for the engine. Adding +1 makes the engine head the other way if it is a multiheaded engine (rear engine) @@ -1402,7 +1443,7 @@ int32 CmdReplaceVehicle(int x, int y, ui v->spritenum = rvi->image_index + (( rvi->flags & RVI_MULTIHEAD && sprite - rvi2->image_index) ? 1 : 0); // turn the last engine in a multiheaded train if needed - if ( v->next == NULL && rvi->flags & RVI_MULTIHEAD && v->spritenum == rvi->image_index ) + if ( v->next == NULL && v->u.rail.first_engine != 0xffff && rvi->flags & RVI_MULTIHEAD && v->spritenum == rvi->image_index ) v->spritenum++; v->cargo_type = rvi->cargo_type; @@ -1420,11 +1461,34 @@ int32 CmdReplaceVehicle(int x, int y, ui } else { v->cargo_type = rvi->cargo_type; } + + if ( rvi2->flags & RVI_MULTIHEAD && !(rvi->flags & RVI_MULTIHEAD) && v->index == first->index) { + if (old_engine_type == u->engine_type ) { + u = GetLastVehicleInChain(v); + Vehicle *w = GetPrevVehicleInChain(u); + w->next = NULL; + DeleteVehicle(u); + } + } + + if ( rvi->flags & RVI_MULTIHEAD && rvi2->flags & RVI_MULTIHEAD && v->index == first->index ) { + CmdReplaceVehicle(x, y, flags, u->index, p2); + } + + if ( rvi->flags & RVI_MULTIHEAD && !(rvi2->flags & RVI_MULTIHEAD) && v->index == first->index ) { + if ( old_engine_type != u->engine_type ) { + Vehicle *w; + if ( (w=AllocateVehicle()) != NULL ) { + AddRearEngineToMultiheadedTrain(v,w, false); + u->next = w; + } + } + } + break; } case VEH_Road: - // using if (true) to declare the const - if (true) { + { const RoadVehicleInfo *rvi = RoadVehInfo(new_engine_type); v->spritenum = rvi->image_index; @@ -1434,8 +1498,7 @@ int32 CmdReplaceVehicle(int x, int y, ui break; } case VEH_Ship: - // using if (true) to declare the const - if (true) { + { const ShipVehicleInfo *svi = ShipVehInfo(new_engine_type); v->spritenum = svi->image_index; @@ -1450,8 +1513,7 @@ int32 CmdReplaceVehicle(int x, int y, ui break; } case VEH_Aircraft: - // using if (true) to declare the const - if (true) { + { const AircraftVehicleInfo *avi = AircraftVehInfo(new_engine_type); Vehicle *u; @@ -1480,17 +1542,6 @@ int32 CmdReplaceVehicle(int x, int y, ui v->cargo_count = v->cargo_cap; } } - - v->reliability = e->reliability; - v->reliability_spd_dec = e->reliability_spd_dec; - v->age = 0; - - v->date_of_last_service = _date; - v->build_year = _cur_year; - - v->value = build_cost; - - InvalidateWindow(WC_VEHICLE_DETAILS, v->index); } //needs to be down here because refitting will change SET_EXPENSES_TYPE if called SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); diff --git a/vehicle.h b/vehicle.h --- a/vehicle.h +++ b/vehicle.h @@ -284,6 +284,8 @@ void ViewportAddVehicles(DrawPixelInfo * void TrainEnterDepot(Vehicle *v, uint tile); +void AddRearEngineToMultiheadedTrain(Vehicle *v, Vehicle *u, bool building) ; + /* train_cmd.h */ int GetTrainImage(Vehicle *v, byte direction); int GetAircraftImage(Vehicle *v, byte direction);