src/vehicle.cpp
branchnoai
changeset 9694 e72987579514
parent 9686 d3c195c226f9
child 9701 d1ac22c62f64
--- a/src/vehicle.cpp	Fri Aug 03 19:16:36 2007 +0000
+++ b/src/vehicle.cpp	Fri Aug 03 22:09:42 2007 +0000
@@ -78,27 +78,8 @@
 };
 
 
-enum {
-	BLOCKS_FOR_SPECIAL_VEHICLES   = 2, ///< Blocks needed for special vehicles
-};
-
-/**
- * Called if a new block is added to the vehicle-pool
- */
-static void VehiclePoolNewBlock(uint start_item)
-{
-	Vehicle *v;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (v = GetVehicle(start_item); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) {
-		v->index = start_item++;
-		v = new (v) InvalidVehicle();
-	}
-}
-
 /* Initialize the vehicle-pool */
-DEFINE_OLD_POOL(Vehicle, Vehicle, VehiclePoolNewBlock, NULL)
+DEFINE_OLD_POOL_GENERIC(Vehicle, Vehicle)
 
 void VehicleServiceInDepot(Vehicle *v)
 {
@@ -282,28 +263,12 @@
 	}
 }
 
-static Vehicle *InitializeVehicle(Vehicle *v)
+Vehicle::Vehicle()
 {
-	VehicleID index = v->index;
-	memset(v, 0, sizeof(Vehicle));
-	v->index = index;
-
-	assert(v->orders == NULL);
-
-	v = new (v) InvalidVehicle();
-	v->left_coord = INVALID_COORD;
-	v->first = NULL;
-	v->next = NULL;
-	v->next_hash = NULL;
-	v->string_id = 0;
-	v->next_shared = NULL;
-	v->prev_shared = NULL;
-	v->depot_list  = NULL;
-	v->random_bits = 0;
-	v->group_id = DEFAULT_GROUP;
-	v->fill_percent_te_id = INVALID_TE_ID;
-
-	return v;
+	this->type               = VEH_INVALID;
+	this->left_coord         = INVALID_COORD;
+	this->group_id           = DEFAULT_GROUP;
+	this->fill_percent_te_id = INVALID_TE_ID;
 }
 
 /**
@@ -315,87 +280,21 @@
 	return GB(Random(), 0, 8);
 }
 
-Vehicle *ForceAllocateSpecialVehicle()
-{
-	/* This stays a strange story.. there should always be room for special
-	 * vehicles (special effects all over the map), but with 65k of vehicles
-	 * is this realistic to double-check for that? For now we just reserve
-	 * BLOCKS_FOR_SPECIAL_VEHICLES times block_size vehicles that may only
-	 * be used for special vehicles.. should work nicely :) */
-
-	Vehicle *v;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (v = GetVehicle(0); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) {
-		/* No more room for the special vehicles, return NULL */
-		if (v->index >= (1 << Vehicle_POOL_BLOCK_SIZE_BITS) * BLOCKS_FOR_SPECIAL_VEHICLES)
-			return NULL;
-
-		if (!IsValidVehicle(v)) return InitializeVehicle(v);
-	}
-
-	return NULL;
-}
-
-/**
- * finds a free vehicle in the memory or allocates a new one
- * returns a pointer to the first free vehicle or NULL if all vehicles are in use
- * *skip_vehicles is an offset to where in the array we should begin looking
- * this is to avoid looping though the same vehicles more than once after we learned that they are not free
- * this feature is used by AllocateVehicles() since it need to allocate more than one and when
- * another block is added to _Vehicle_pool, since we only do that when we know it's already full
- */
-static Vehicle *AllocateSingleVehicle(VehicleID *skip_vehicles)
+
+/* static */ bool Vehicle::AllocateList(Vehicle **vl, int num)
 {
-	/* See note by ForceAllocateSpecialVehicle() why we skip the
-	 * first blocks */
-	Vehicle *v;
-	const int offset = (1 << Vehicle_POOL_BLOCK_SIZE_BITS) * BLOCKS_FOR_SPECIAL_VEHICLES;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * @todo - This is just a temporary stage, this will be removed. */
-	if (*skip_vehicles < (_Vehicle_pool.total_items - offset)) { // make sure the offset in the array is not larger than the array itself
-		for (v = GetVehicle(offset + *skip_vehicles); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) {
-			(*skip_vehicles)++;
-			if (!IsValidVehicle(v)) return InitializeVehicle(v);
-		}
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_Vehicle_pool))
-		return AllocateSingleVehicle(skip_vehicles);
-
-	return NULL;
-}
-
-
-Vehicle *AllocateVehicle()
-{
-	VehicleID counter = 0;
-	return AllocateSingleVehicle(&counter);
-}
-
-
-/** Allocates a lot of vehicles and frees them again
- * @param vl pointer to an array of vehicles to get allocated. Can be NULL if the vehicles aren't needed (makes it test only)
- * @param num number of vehicles to allocate room for
- * @return true if there is room to allocate all the vehicles
- */
-bool AllocateVehicles(Vehicle **vl, int num)
-{
-	int i;
-	Vehicle *v;
-	VehicleID counter = 0;
-
-	for (i = 0; i != num; i++) {
-		v = AllocateSingleVehicle(&counter);
-		if (v == NULL) {
-			return false;
-		}
+	uint counter = _Vehicle_pool.first_free_index;
+
+	for (int i = 0; i != num; i++) {
+		Vehicle *v = AllocateRaw(counter);
+
+		if (v == NULL) return false;
+		v = new (v) InvalidVehicle();
+
 		if (vl != NULL) {
 			vl[i] = v;
 		}
+		counter++;
 	}
 
 	return true;
@@ -471,8 +370,8 @@
 	if (remove) {
 		new_hash = NULL;
 	} else {
-		int x = GB(v->x_pos / TILE_SIZE, HASH_RES, HASH_BITS);
-		int y = GB(v->y_pos / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
+		int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
+		int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
 		new_hash = &_new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
 	}
 
@@ -555,16 +454,8 @@
 
 void InitializeVehicles()
 {
-	uint i;
-
-	/* Clean the vehicle pool, and reserve enough blocks
-	 *  for the special vehicles, plus one for all the other
-	 *  vehicles (which is increased on-the-fly) */
-	CleanPool(&_Vehicle_pool);
-	AddBlockToPool(&_Vehicle_pool);
-	for (i = 0; i < BLOCKS_FOR_SPECIAL_VEHICLES; i++) {
-		AddBlockToPool(&_Vehicle_pool);
-	}
+	_Vehicle_pool.CleanPool();
+	_Vehicle_pool.AddBlockToPool();
 
 	ResetVehiclePosHash();
 }
@@ -671,44 +562,51 @@
 	}
 }
 
-void DestroyVehicle(Vehicle *v)
+Vehicle::~Vehicle()
 {
-	if (IsValidStationID(v->last_station_visited)) {
-		GetStation(v->last_station_visited)->loading_vehicles.remove(v);
-
-		HideFillingPercent(v->fill_percent_te_id);
-		v->fill_percent_te_id = INVALID_TE_ID;
+	if (IsValidStationID(this->last_station_visited)) {
+		GetStation(this->last_station_visited)->loading_vehicles.remove(this);
+
+		HideFillingPercent(this->fill_percent_te_id);
+		this->fill_percent_te_id = INVALID_TE_ID;
 	}
 
-	if (IsEngineCountable(v)) {
-		GetPlayer(v->owner)->num_engines[v->engine_type]--;
-		if (v->owner == _local_player) InvalidateAutoreplaceWindow(v->engine_type, v->group_id);
-
-		if (IsValidGroupID(v->group_id)) GetGroup(v->group_id)->num_engines[v->engine_type]--;
-		if (v->IsPrimaryVehicle()) DecreaseGroupNumVehicle(v->group_id);
+	if (IsEngineCountable(this)) {
+		GetPlayer(this->owner)->num_engines[this->engine_type]--;
+		if (this->owner == _local_player) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
+
+		if (IsValidGroupID(this->group_id)) GetGroup(this->group_id)->num_engines[this->engine_type]--;
+		if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
 	}
 
-	DeleteVehicleNews(v->index, INVALID_STRING_ID);
-
-	DeleteName(v->string_id);
-	if (v->type == VEH_ROAD) ClearSlot(v);
-
-	if (v->type != VEH_TRAIN || (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v)))) {
-		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+	DeleteVehicleNews(this->index, INVALID_STRING_ID);
+
+	this->QuickFree();
+	if (this->type == VEH_ROAD) ClearSlot(this);
+
+	if (this->type != VEH_TRAIN || (this->type == VEH_TRAIN && (IsFrontEngine(this) || IsFreeWagon(this)))) {
+		InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
 	}
 
-	v->cargo.Truncate(0);
-	UpdateVehiclePosHash(v, INVALID_COORD, 0);
-	v->next_hash = NULL;
-	v->next_new_hash = NULL;
-	if (IsPlayerBuildableVehicleType(v)) DeleteVehicleOrders(v);
+	this->cargo.Truncate(0);
+	UpdateVehiclePosHash(this, INVALID_COORD, 0);
+	this->next_hash = NULL;
+	this->next_new_hash = NULL;
+	if (IsPlayerBuildableVehicleType(this)) DeleteVehicleOrders(this);
 
 	/* Now remove any artic part. This will trigger an other
 	 *  destroy vehicle, which on his turn can remove any
 	 *  other artic parts. */
-	if ((v->type == VEH_TRAIN && EngineHasArticPart(v)) || (v->type == VEH_ROAD && RoadVehHasArticPart(v))) {
-		DeleteVehicle(v->next);
+	if ((this->type == VEH_TRAIN && EngineHasArticPart(this)) || (this->type == VEH_ROAD && RoadVehHasArticPart(this))) {
+		delete this->next;
 	}
+
+	new (this) InvalidVehicle();
+}
+
+void Vehicle::QuickFree()
+{
+	DeleteName(this->string_id);
 }
 
 /**
@@ -725,7 +623,7 @@
 	do {
 		Vehicle *u = v;
 		v = v->next;
-		DeleteVehicle(u);
+		delete u;
 	} while (v != NULL);
 }
 
@@ -852,17 +750,14 @@
 	SpriteID image = v->cur_image;
 	SpriteID pal;
 
-	if (v->vehstatus & VS_SHADOW) {
-		SETBIT(image, PALETTE_MODIFIER_TRANSPARENT);
-		pal = PALETTE_TO_TRANSPARENT;
-	} else if (v->vehstatus & VS_DEFPAL) {
+	if (v->vehstatus & VS_DEFPAL) {
 		pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 	} else {
 		pal = PAL_NONE;
 	}
 
 	AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
-		v->sprite_width, v->sprite_height, v->z_height, v->z_pos);
+		v->sprite_width, v->sprite_height, v->z_height, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
 }
 
 void ViewportAddVehicles(DrawPixelInfo *dpi)
@@ -935,7 +830,7 @@
 		tile = TileVirtXY(v->x_pos, v->y_pos);
 		if (!IsTileType(tile, MP_INDUSTRY)) {
 			EndVehicleMove(v);
-			DeleteVehicle(v);
+			delete v;
 			return;
 		}
 
@@ -974,7 +869,7 @@
 			v->cur_image++;
 		} else {
 			EndVehicleMove(v);
-			DeleteVehicle(v);
+			delete v;
 			return;
 		}
 		moved = true;
@@ -1009,7 +904,7 @@
 			EndVehicleMove(v);
 		} else {
 			EndVehicleMove(v);
-			DeleteVehicle(v);
+			delete v;
 		}
 	}
 }
@@ -1033,7 +928,7 @@
 			EndVehicleMove(v);
 		} else {
 			EndVehicleMove(v);
-			DeleteVehicle(v);
+			delete v;
 		}
 	}
 }
@@ -1062,7 +957,7 @@
 			v->cur_image++;
 		} else {
 			EndVehicleMove(v);
-			DeleteVehicle(v);
+			delete v;
 			return;
 		}
 		moved = true;
@@ -1091,7 +986,7 @@
 			EndVehicleMove(v);
 		} else {
 			EndVehicleMove(v);
-			DeleteVehicle(v);
+			delete v;
 		}
 	}
 }
@@ -1116,11 +1011,11 @@
 		EndVehicleMove(v);
 	}
 
-	v->u.special.unk0--;
-	if (v->u.special.unk0 == 0) {
+	v->u.special.animation_state--;
+	if (v->u.special.animation_state == 0) {
 		BeginVehicleMove(v);
 		EndVehicleMove(v);
-		DeleteVehicle(v);
+		delete v;
 	}
 }
 
@@ -1141,7 +1036,7 @@
 			EndVehicleMove(v);
 		} else {
 			EndVehicleMove(v);
-			DeleteVehicle(v);
+			delete v;
 		}
 	}
 }
@@ -1150,8 +1045,8 @@
 {
 	v->cur_image = SPR_BULLDOZER_NE;
 	v->progress = 0;
-	v->u.special.unk0 = 0;
-	v->u.special.unk2 = 0;
+	v->u.special.animation_state = 0;
+	v->u.special.animation_substate = 0;
 }
 
 struct BulldozerMovement {
@@ -1197,7 +1092,7 @@
 {
 	v->progress++;
 	if ((v->progress & 7) == 0) {
-		const BulldozerMovement* b = &_bulldozer_movement[v->u.special.unk0];
+		const BulldozerMovement* b = &_bulldozer_movement[v->u.special.animation_state];
 
 		BeginVehicleMove(v);
 
@@ -1206,13 +1101,13 @@
 		v->x_pos += _inc_by_dir[b->direction].x;
 		v->y_pos += _inc_by_dir[b->direction].y;
 
-		v->u.special.unk2++;
-		if (v->u.special.unk2 >= b->duration) {
-			v->u.special.unk2 = 0;
-			v->u.special.unk0++;
-			if (v->u.special.unk0 == lengthof(_bulldozer_movement)) {
+		v->u.special.animation_substate++;
+		if (v->u.special.animation_substate >= b->duration) {
+			v->u.special.animation_substate = 0;
+			v->u.special.animation_state++;
+			if (v->u.special.animation_state == lengthof(_bulldozer_movement)) {
 				EndVehicleMove(v);
-				DeleteVehicle(v);
+				delete v;
 				return;
 			}
 		}
@@ -1402,7 +1297,7 @@
 			EndVehicleMove(v);
 			return;
 		}
-		if (v->u.special.unk2 != 0) {
+		if (v->u.special.animation_substate != 0) {
 			v->spritenum = GB(InteractiveRandom(), 0, 2) + 1;
 		} else {
 			v->spritenum = 6;
@@ -1416,7 +1311,7 @@
 
 	if (b->y == 4 && b->x == 0) {
 		EndVehicleMove(v);
-		DeleteVehicle(v);
+		delete v;
 		return;
 	}
 
@@ -1485,9 +1380,8 @@
 {
 	Vehicle *v;
 
-	v = ForceAllocateSpecialVehicle();
+	v = new SpecialVehicle();
 	if (v != NULL) {
-		v = new (v) SpecialVehicle();
 		v->subtype = type;
 		v->x_pos = x;
 		v->y_pos = y;
@@ -1881,7 +1775,7 @@
 			veh_counter++;
 		} while ((v = v->next) != NULL);
 
-		if (!AllocateVehicles(NULL, veh_counter)) {
+		if (!Vehicle::AllocateList(NULL, veh_counter)) {
 			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
 		}
 	}
@@ -2395,6 +2289,7 @@
 				break;
 
 			case VEH_ROAD:
+				if (!IsRoadVehFront(v)) continue;
 				break;
 
 			case VEH_AIRCRAFT:
@@ -2480,7 +2375,8 @@
 
 static Rect _old_vehicle_coords;
 
-void BeginVehicleMove(Vehicle *v) {
+void BeginVehicleMove(Vehicle *v)
+{
 	_old_vehicle_coords.left = v->left_coord;
 	_old_vehicle_coords.top = v->top_coord;
 	_old_vehicle_coords.right = v->right_coord;
@@ -3044,8 +2940,8 @@
 	    SLE_VAR(Vehicle, progress,      SLE_UINT8),
 	    SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
 
-	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, unk0), SLE_UINT16),
-	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, unk2), SLE_UINT8),
+	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_state),    SLE_UINT16),
+	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_substate), SLE_UINT8),
 
 	/* reserve extra space in savegame here. (currently 16 bytes) */
 	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
@@ -3082,8 +2978,8 @@
 	SLE_CONDVAR(Vehicle, age,           SLE_INT32,                  31, SL_MAX_VERSION),
 	    SLE_VAR(Vehicle, tick_counter,  SLE_UINT8),
 
-	   SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, image_override), SLE_UINT16),
-	   SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, unk2),           SLE_UINT16),
+	   SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, image_override),           SLE_UINT16),
+	   SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, big_ufo_destroyer_target), SLE_UINT16),
 
 	/* reserve extra space in savegame here. (currently 16 bytes) */
 	SLE_CONDNULL(16,                                                 2, SL_MAX_VERSION),
@@ -3092,7 +2988,7 @@
 };
 
 
-static const void *_veh_descs[] = {
+static const SaveLoad *_veh_descs[] = {
 	_train_desc,
 	_roadveh_desc,
 	_ship_desc,
@@ -3108,7 +3004,7 @@
 	/* Write the vehicles */
 	FOR_ALL_VEHICLES(v) {
 		SlSetArrayIndex(v->index);
-		SlObject(v, (SaveLoad*)_veh_descs[v->type]);
+		SlObject(v, _veh_descs[v->type]);
 	}
 }
 
@@ -3122,25 +3018,20 @@
 
 	while ((index = SlIterateArray()) != -1) {
 		Vehicle *v;
-
-		if (!AddBlockIfNeeded(&_Vehicle_pool, index))
-			error("Vehicles: failed loading savegame: too many vehicles");
-
-		v = GetVehicle(index);
 		VehicleType vtype = (VehicleType)SlReadByte();
 
 		switch (vtype) {
-			case VEH_TRAIN:    v = new (v) Train();           break;
-			case VEH_ROAD:     v = new (v) RoadVehicle();     break;
-			case VEH_SHIP:     v = new (v) Ship();            break;
-			case VEH_AIRCRAFT: v = new (v) Aircraft();        break;
-			case VEH_SPECIAL:  v = new (v) SpecialVehicle();  break;
-			case VEH_DISASTER: v = new (v) DisasterVehicle(); break;
-			case VEH_INVALID:  v = new (v) InvalidVehicle();  break;
+			case VEH_TRAIN:    v = new (index) Train();           break;
+			case VEH_ROAD:     v = new (index) RoadVehicle();     break;
+			case VEH_SHIP:     v = new (index) Ship();            break;
+			case VEH_AIRCRAFT: v = new (index) Aircraft();        break;
+			case VEH_SPECIAL:  v = new (index) SpecialVehicle();  break;
+			case VEH_DISASTER: v = new (index) DisasterVehicle(); break;
+			case VEH_INVALID:  v = new (index) InvalidVehicle();  break;
 			default: NOT_REACHED();
 		}
 
-		SlObject(v, (SaveLoad*)_veh_descs[vtype]);
+		SlObject(v, _veh_descs[vtype]);
 
 		if (_cargo_count != 0 && IsPlayerBuildableVehicleType(v)) {
 			/* Don't construct the packet with station here, because that'll fail with old savegames */