vehicle.c
changeset 2676 2ba71e034d97
parent 2666 94fc2b3967d7
child 2677 2c1fcffb304c
equal deleted inserted replaced
2675:269c38d892f9 2676:2ba71e034d97
    21 #include "vehicle_gui.h"
    21 #include "vehicle_gui.h"
    22 #include "depot.h"
    22 #include "depot.h"
    23 #include "station.h"
    23 #include "station.h"
    24 #include "gui.h"
    24 #include "gui.h"
    25 #include "rail.h"
    25 #include "rail.h"
       
    26 #include "train.h"
    26 
    27 
    27 #define INVALID_COORD (-0x8000)
    28 #define INVALID_COORD (-0x8000)
    28 #define GEN_HASH(x,y) (((x & 0x1F80)>>7) + ((y & 0xFC0)))
    29 #define GEN_HASH(x,y) (((x & 0x1F80)>>7) + ((y & 0xFC0)))
    29 
    30 
    30 /*
    31 /*
   236 			}
   237 			}
   237 
   238 
   238 			v->left_coord = INVALID_COORD;
   239 			v->left_coord = INVALID_COORD;
   239 			VehiclePositionChanged(v);
   240 			VehiclePositionChanged(v);
   240 
   241 
   241 			if (v->type == VEH_Train && (v->subtype == TS_Front_Engine || v->subtype == TS_Free_Car))
   242 			if (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v)))
   242 				TrainConsistChanged(v);
   243 				TrainConsistChanged(v);
   243 		}
   244 		}
   244 	}
   245 	}
   245 }
   246 }
   246 
   247 
   501 	Vehicle* u;
   502 	Vehicle* u;
   502 
   503 
   503 	assert(v != NULL);
   504 	assert(v != NULL);
   504 
   505 
   505 	if (v->first != NULL) {
   506 	if (v->first != NULL) {
   506 		if (v->first->subtype == TS_Front_Engine) return v->first;
   507 		if (IsFrontEngine(v->first)) return v->first;
   507 
   508 
   508 		DEBUG(misc, 0) ("v->first cache faulty. We shouldn't be here, rebuilding cache!");
   509 		DEBUG(misc, 0) ("v->first cache faulty. We shouldn't be here, rebuilding cache!");
   509 	}
   510 	}
   510 
   511 
   511 	/* It is the fact (currently) that newly built vehicles do not have
   512 	/* It is the fact (currently) that newly built vehicles do not have
   515 
   516 
   516 	/* Find the 'locomotive' or the first wagon in a chain */
   517 	/* Find the 'locomotive' or the first wagon in a chain */
   517 	while ((u = GetPrevVehicleInChain_bruteforce(v)) != NULL) v = u;
   518 	while ((u = GetPrevVehicleInChain_bruteforce(v)) != NULL) v = u;
   518 
   519 
   519 	/* Set the first pointer of all vehicles in that chain to the first wagon */
   520 	/* Set the first pointer of all vehicles in that chain to the first wagon */
   520 	if (v->subtype == TS_Front_Engine)
   521 	if (IsFrontEngine(v))
   521 		for (u = (Vehicle *)v; u != NULL; u = u->next) u->first = (Vehicle *)v;
   522 		for (u = (Vehicle *)v; u != NULL; u = u->next) u->first = (Vehicle *)v;
   522 
   523 
   523 	return (Vehicle*)v;
   524 	return (Vehicle*)v;
   524 }
   525 }
   525 
   526 
  1488  */
  1489  */
  1489 static Vehicle *GetNextEnginePart(Vehicle *v)
  1490 static Vehicle *GetNextEnginePart(Vehicle *v)
  1490 {
  1491 {
  1491 	switch (v->type) {
  1492 	switch (v->type) {
  1492 		case VEH_Train:
  1493 		case VEH_Train:
  1493 			if (RailVehInfo(v->engine_type)->flags & RVI_MULTIHEAD) {
  1494 			if (IsMultiheaded(v)) {
  1494 				return GetRearEngine(v);
  1495 				if (!IsTrainEngine(v))
       
  1496 					return v->u.rail.other_multiheaded_part;
       
  1497 				else
       
  1498 					return NULL;
  1495 			}
  1499 			}
  1496 			if (v->next != NULL && v->next->subtype == TS_Artic_Part) return v->next;
  1500 			if (v->next != NULL && IsArticulatedPart(v->next)) return v->next;
  1497 			break;
  1501 			break;
  1498 
  1502 
  1499 		case VEH_Aircraft:
  1503 		case VEH_Aircraft:
  1500 			return v->next;
  1504 			return v->next;
  1501 
  1505 
  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 {
  1553 	}
  1557 	}
  1554 
  1558 
  1555 	v = v_front;
  1559 	v = v_front;
  1556 
  1560 
  1557 	do {
  1561 	do {
  1558 		cost = DoCommand(x, y, v->engine_type, 3, flags, CMD_BUILD_VEH(v->type));
  1562 
       
  1563 		if (IsMultiheaded(v) && !IsTrainEngine(v)) {
       
  1564 			/* we build the rear ends of multiheaded trains with the front ones */
       
  1565 			continue;
       
  1566 		}
       
  1567 
       
  1568 		cost = DoCommand(x, y, v->engine_type, 2, flags, CMD_BUILD_VEH(v->type));
  1559 
  1569 
  1560 		if (CmdFailed(cost)) return cost;
  1570 		if (CmdFailed(cost)) return cost;
  1561 
  1571 
  1562 		total_cost += cost;
  1572 		total_cost += cost;
  1563 
  1573 
  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;
  2309 					break;
  2408 					break;
  2310 				}
  2409 				}
  2311 			}
  2410 			}
  2312 		}
  2411 		}
  2313 	}
  2412 	}
       
  2413 
       
  2414 	/* Connect front and rear engines of multiheaded trains and converts subtype to the new format */
       
  2415 	if (_sl_full_version < 0x1101) {
       
  2416 		ConvertOldMultiheadToNew();
       
  2417 	}
  2314 }
  2418 }
  2315 
  2419 
  2316 const ChunkHandler _veh_chunk_handlers[] = {
  2420 const ChunkHandler _veh_chunk_handlers[] = {
  2317 	{ 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
  2421 	{ 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
  2318 };
  2422 };