1536 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains |
1540 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains |
1537 */ |
1541 */ |
1538 |
1542 |
1539 if (!CheckOwnership(v->owner)) return CMD_ERROR; |
1543 if (!CheckOwnership(v->owner)) return CMD_ERROR; |
1540 |
1544 |
1541 if (v->type == VEH_Train && v->subtype != TS_Front_Engine) return CMD_ERROR; |
1545 if (v->type == VEH_Train && !IsFrontEngine(v)) return CMD_ERROR; |
1542 |
1546 |
1543 // check that we can allocate enough vehicles |
1547 // check that we can allocate enough vehicles |
1544 if (!(flags & DC_EXEC)) { |
1548 if (!(flags & DC_EXEC)) { |
1545 int veh_counter = 0; |
1549 int veh_counter = 0; |
1546 do { |
1550 do { |
1568 if (v->cargo_type != w->cargo_type) { |
1578 if (v->cargo_type != w->cargo_type) { |
1569 DoCommand(x, y, w->index, v->cargo_type, flags, CMD_REFIT_VEH(v->type)); |
1579 DoCommand(x, y, w->index, v->cargo_type, flags, CMD_REFIT_VEH(v->type)); |
1570 } |
1580 } |
1571 } |
1581 } |
1572 |
1582 |
1573 if (v->type == VEH_Train && v->subtype != TS_Front_Engine) { |
1583 if (v->type == VEH_Train && !IsFrontEngine(v)) { |
1574 // this s a train car |
1584 // this s a train car |
1575 // add this unit to the end of the train |
1585 // add this unit to the end of the train |
1576 DoCommand(x, y, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE); |
1586 DoCommand(x, y, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE); |
1577 } else { |
1587 } else { |
1578 // this is a front engine or not a train. It need orders |
1588 // this is a front engine or not a train. It need orders |
1581 } |
1591 } |
1582 w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop |
1592 w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop |
1583 } |
1593 } |
1584 } while (v->type == VEH_Train && (v = GetNextVehicle(v)) != NULL); |
1594 } while (v->type == VEH_Train && (v = GetNextVehicle(v)) != NULL); |
1585 |
1595 |
1586 if (flags & DC_EXEC) { |
1596 if (flags & DC_EXEC && v_front->type == VEH_Train) { |
1587 v = v_front; |
1597 // _new_train_id needs to be the front engine due to the callback function |
1588 w = w_front; |
1598 _new_train_id = w_front->index; |
1589 if (v->type == VEH_Train) { |
|
1590 _new_train_id = w_front->index; // _new_train_id needs to be the front engine due to the callback function |
|
1591 |
|
1592 while (w != NULL && v != NULL) { // checking both just in case something went wrong |
|
1593 w->spritenum = v->spritenum; // makes sure that multiheaded engines are facing the correct way |
|
1594 w = w->next; |
|
1595 v = v->next; |
|
1596 } |
|
1597 } |
|
1598 } |
1599 } |
1599 return total_cost; |
1600 return total_cost; |
1600 } |
1601 } |
1601 |
1602 |
1602 /* |
1603 /* |
1663 } |
1664 } |
1664 } |
1665 } |
1665 |
1666 |
1666 MoveVehicleCargo(new_v, old_v); |
1667 MoveVehicleCargo(new_v, old_v); |
1667 |
1668 |
1668 if (old_v->type == VEH_Train && old_v->u.rail.first_engine != INVALID_VEHICLE) { |
1669 if (old_v->type == VEH_Train && !IsFrontEngine(old_v)) { |
1669 /* this is a railcar. We need to move the car into the train |
1670 /* this is a railcar. We need to move the car into the train |
1670 * We add the new engine after the old one instead of replacing it. It will give the same result anyway when we |
1671 * We add the new engine after the old one instead of replacing it. It will give the same result anyway when we |
1671 * sell the old engine in a moment |
1672 * sell the old engine in a moment |
1672 */ |
1673 */ |
1673 DoCommand(0, 0, (old_v->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
1674 DoCommand(0, 0, (GetPrevVehicleInChain(old_v)->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
1674 } else { |
1675 } else { |
1675 // copy/clone the orders |
1676 // copy/clone the orders |
1676 DoCommand(0, 0, (old_v->index << 16) | new_v->index, IsOrderListShared(old_v) ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER); |
1677 DoCommand(0, 0, (old_v->index << 16) | new_v->index, IsOrderListShared(old_v) ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER); |
1677 new_v->cur_order_index = old_v->cur_order_index; |
1678 new_v->cur_order_index = old_v->cur_order_index; |
1678 ChangeVehicleViewWindow(old_v, new_v); |
1679 ChangeVehicleViewWindow(old_v, new_v); |
1735 |
1736 |
1736 for (;;) { |
1737 for (;;) { |
1737 cost = 0; |
1738 cost = 0; |
1738 w = v; |
1739 w = v; |
1739 do { |
1740 do { |
|
1741 if (w->type == VEH_Train && IsMultiheaded(w) && !IsTrainEngine(w)) { |
|
1742 /* we build the rear ends of multiheaded trains with the front ones */ |
|
1743 continue; |
|
1744 } |
|
1745 |
1740 // check if the vehicle should be replaced |
1746 // check if the vehicle should be replaced |
1741 if (!p->engine_renew || |
1747 if (!p->engine_renew || |
1742 w->age - w->max_age < (p->engine_renew_months * 30) || // replace if engine is too old |
1748 w->age - w->max_age < (p->engine_renew_months * 30) || // replace if engine is too old |
1743 w->max_age == 0) { // rail cars got a max age of 0 |
1749 w->max_age == 0) { // rail cars got a max age of 0 |
1744 if (p->engine_replacement[w->engine_type] == INVALID_ENGINE) // updates to a new model |
1750 if (p->engine_replacement[w->engine_type] == INVALID_ENGINE) // updates to a new model |
1745 continue; |
|
1746 } |
|
1747 |
|
1748 /* if we are looking at the rear end of a multiheaded locomotive, skip it */ |
|
1749 if (w->type == VEH_Train) { |
|
1750 const RailVehicleInfo *rvi = RailVehInfo(w->engine_type); |
|
1751 if (rvi->flags & RVI_MULTIHEAD && rvi->image_index == w->spritenum - 1) |
|
1752 continue; |
1751 continue; |
1753 } |
1752 } |
1754 |
1753 |
1755 /* Now replace the vehicle */ |
1754 /* Now replace the vehicle */ |
1756 temp_cost = ReplaceVehicle(&w, flags); |
1755 temp_cost = ReplaceVehicle(&w, flags); |
2107 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_status), SLE_UINT8, 2, 255), |
2106 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_status), SLE_UINT8, 2, 255), |
2108 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_tile), SLE_UINT32, 2, 255), |
2107 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_tile), SLE_UINT32, 2, 255), |
2109 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_trackdir), SLE_UINT8, 2, 255), |
2108 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_trackdir), SLE_UINT8, 2, 255), |
2110 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,shortest_platform[0]), SLE_UINT8, 2, 255), // added with 16.1, but was blank since 2 |
2109 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,shortest_platform[0]), SLE_UINT8, 2, 255), // added with 16.1, but was blank since 2 |
2111 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,shortest_platform[1]), SLE_UINT8, 2, 255), // added with 16.1, but was blank since 2 |
2110 SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,shortest_platform[1]), SLE_UINT8, 2, 255), // added with 16.1, but was blank since 2 |
2112 // reserve extra space in savegame here. (currently 5 bytes) |
2111 SLE_CONDREFX(offsetof(Vehicle,u)+offsetof(VehicleRail,other_multiheaded_part), REF_VEHICLE, 2, 255), // added with 17.1, but was blank since 2 |
2113 SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 5, 2, 255), |
2112 // reserve extra space in savegame here. (currently 3 bytes) |
|
2113 SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 3, 2, 255), |
2114 |
2114 |
2115 SLE_END() |
2115 SLE_END() |
2116 }; |
2116 }; |
2117 |
2117 |
2118 static const SaveLoad _roadveh_desc[] = { |
2118 static const SaveLoad _roadveh_desc[] = { |
2260 SlObject(v, _veh_descs[v->type - 0x10]); |
2260 SlObject(v, _veh_descs[v->type - 0x10]); |
2261 } |
2261 } |
2262 } |
2262 } |
2263 } |
2263 } |
2264 |
2264 |
|
2265 /* |
|
2266 * Converts all trains to the new subtype format introduced in savegame 16.2 |
|
2267 * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found |
|
2268 */ |
|
2269 static inline void ConvertOldMultiheadToNew(void) |
|
2270 { |
|
2271 Vehicle *v; |
|
2272 FOR_ALL_VEHICLES(v) { |
|
2273 if (v->type == VEH_Train) { |
|
2274 v->u.rail.other_multiheaded_part = NULL; |
|
2275 SETBIT(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop |
|
2276 } |
|
2277 } |
|
2278 |
|
2279 FOR_ALL_VEHICLES(v) { |
|
2280 if (v->type == VEH_Train) { |
|
2281 if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) { |
|
2282 Vehicle *u = v; |
|
2283 |
|
2284 BEGIN_ENUM_WAGONS(u) |
|
2285 const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); |
|
2286 CLRBIT(u->subtype, 7); |
|
2287 switch (u->subtype) { |
|
2288 case 0: /* TS_Front_Engine */ |
|
2289 if (rvi->flags & RVI_MULTIHEAD) { |
|
2290 SetMultiheaded(u); |
|
2291 } |
|
2292 SetFrontEngine(u); |
|
2293 SetTrainEngine(u); |
|
2294 break; |
|
2295 case 1: /* TS_Artic_Part */ |
|
2296 u->subtype = 0; |
|
2297 SetArticulatedPart(u); |
|
2298 break; |
|
2299 case 2: /* TS_Not_First */ |
|
2300 u->subtype = 0; |
|
2301 if (rvi->flags & RVI_WAGON) { |
|
2302 // normal wagon |
|
2303 SetTrainWagon(u); |
|
2304 break; |
|
2305 } |
|
2306 if (rvi->flags & RVI_MULTIHEAD && rvi->image_index == u->spritenum - 1) { |
|
2307 // rear end of a multiheaded engine |
|
2308 SetMultiheaded(u); |
|
2309 break; |
|
2310 } |
|
2311 if (rvi->flags & RVI_MULTIHEAD) { |
|
2312 SetMultiheaded(u); |
|
2313 } |
|
2314 SetTrainEngine(u); |
|
2315 break; |
|
2316 case 4: /* TS_Free_Car */ |
|
2317 u->subtype = 0; |
|
2318 SetTrainWagon(u); |
|
2319 SetFreeWagon(u); |
|
2320 break; |
|
2321 default: NOT_REACHED(); break; |
|
2322 } |
|
2323 END_ENUM_WAGONS(u) |
|
2324 u = v; |
|
2325 BEGIN_ENUM_WAGONS(u) |
|
2326 const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); |
|
2327 |
|
2328 if (u->u.rail.other_multiheaded_part != NULL) continue; |
|
2329 |
|
2330 if (rvi->flags & RVI_MULTIHEAD) { |
|
2331 if (!IsTrainEngine(u)) { |
|
2332 /* we got a rear car without a front car. We will convert it to a front one */ |
|
2333 SetTrainEngine(u); |
|
2334 u->spritenum--; |
|
2335 } |
|
2336 |
|
2337 { |
|
2338 Vehicle *w; |
|
2339 |
|
2340 for(w = u->next; w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w)); |
|
2341 if (w != NULL) { |
|
2342 /* we found a car to partner with this engine. Now we will make sure it face the right way */ |
|
2343 if (IsTrainEngine(w)) { |
|
2344 ClearTrainEngine(w); |
|
2345 w->spritenum++; |
|
2346 } |
|
2347 } |
|
2348 |
|
2349 if (w != NULL) { |
|
2350 w->u.rail.other_multiheaded_part = u; |
|
2351 u->u.rail.other_multiheaded_part = w; |
|
2352 } else { |
|
2353 /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */ |
|
2354 ClearMultiheaded(u); |
|
2355 } |
|
2356 } |
|
2357 } |
|
2358 END_ENUM_WAGONS(u) |
|
2359 } |
|
2360 } |
|
2361 } |
|
2362 } |
|
2363 |
2265 // Will be called when vehicles need to be loaded. |
2364 // Will be called when vehicles need to be loaded. |
2266 static void Load_VEHS(void) |
2365 static void Load_VEHS(void) |
2267 { |
2366 { |
2268 int index; |
2367 int index; |
2269 Vehicle *v; |
2368 Vehicle *v; |