Changeset - r1128:d0dd5c69c2e5
[Not reviewed]
master
0 7 0
bjarni - 20 years ago 2005-01-23 22:01:51
bjarni@openttd.org
(svn r1629) added a counter to tell how many engines you have of each type to the autoreplace vehicle windows and made them show only the vehicles you actually have in the left list.
this also fixes some window updates issues when autoreplacing
7 files changed with 101 insertions and 43 deletions:
0 comments (0 inline, 0 general)
aircraft_cmd.c
Show inline comments
 
@@ -266,12 +266,14 @@ int32 CmdBuildAircraft(int x, int y, uin
 

	
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		RebuildVehicleLists();
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
	}
 

	
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Aircraft); //updates the replace Aircraft window
 

	
 
	return value;
 
}
 

	
 
bool IsAircraftHangarTile(TileIndex tile)
 
{
 
	// 0x56 - hangar facing other way international airport (86)
 
@@ -319,12 +321,14 @@ int32 CmdSellAircraft(int x, int y, uint
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 

	
 
		DoDeleteAircraft(v);
 

	
 
	}
 

	
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Aircraft); // updates the replace Aircraft window
 

	
 
	return -(int32)v->value;
 
}
 

	
 
// p1 = vehicle
 
int32 CmdStartStopAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 
{
roadveh_cmd.c
Show inline comments
 
@@ -185,12 +185,14 @@ int32 CmdBuildRoadVeh(int x, int y, uint
 

	
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		RebuildVehicleLists();
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
	}
 

	
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Road); // updates the replace Road window
 

	
 
	return cost;
 
}
 

	
 
// p1 = vehicle
 
int32 CmdStartStopRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 
{
 
@@ -231,12 +233,13 @@ int32 CmdSellRoadVeh(int x, int y, uint3
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		RebuildVehicleLists();
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 
		DeleteVehicle(v);
 
	}
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Road); // updates the replace Road window
 

	
 
	return -(int32)v->value;
 
}
 

	
 
typedef struct RoadFindDepotData {
 
	uint best_length;
ship_cmd.c
Show inline comments
 
@@ -874,12 +874,13 @@ int32 CmdBuildShip(int x, int y, uint32 
 
		VehiclePositionChanged(v);
 

	
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		RebuildVehicleLists();
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
	}
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Ship); // updates the replace Ship window
 

	
 
	return value;
 
}
 

	
 
int32 CmdSellShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 
{
 
@@ -900,12 +901,14 @@ int32 CmdSellShip(int x, int y, uint32 f
 
		RebuildVehicleLists();
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 
		DeleteVehicle(v);
 
	}
 

	
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Ship); // updates the replace Ship window
 

	
 
	return -(int32)v->value;
 
}
 

	
 
// p1 = vehicle
 
int32 CmdStartStopShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 
{
train_cmd.c
Show inline comments
 
@@ -483,12 +483,15 @@ int32 CmdBuildRailVehicle(int x, int y, 
 
			RebuildVehicleLists();
 
			InvalidateWindow(WC_COMPANY, v->owner);
 
		}
 
	}
 
	_cmd_build_rail_veh_var1 = _railveh_unk1[p1];
 
	_cmd_build_rail_veh_score = _railveh_score[p1];
 

	
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train); // updates the replace Train window
 

	
 
	return value;
 
}
 

	
 

	
 
bool IsTrainDepotTile(TileIndex tile)
 
{
 
@@ -844,12 +847,13 @@ int32 CmdSellRailWagon(int x, int y, uin
 
				break;
 
			}
 
			if ( (v=v->next) == last || p2 != 1) break;
 
		}
 
		if (last) cost -= last->value;
 
	}
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train); // updates the replace Train window
 

	
 
	return cost;
 
}
 

	
 
static void UpdateTrainDeltaXY(Vehicle *v, int direction)
 
{
 
@@ -2396,14 +2400,16 @@ static void HandleCrashedTrain(Vehicle *
 
	}
 

	
 
	if (state <= 240 && !(v->tick_counter&3)) {
 
		ChangeTrainDirRandomly(v);
 
	}
 

	
 
	if (state >= 4440 && !(v->tick_counter&0x1F))
 
	if (state >= 4440 && !(v->tick_counter&0x1F)) {
 
		DeleteLastWagon(v);
 
		InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
 
	}
 
}
 

	
 
static void HandleBrokenTrain(Vehicle *v)
 
{
 
	if (v->breakdown_ctr != 1) {
 
		v->breakdown_ctr = 1;
variables.h
Show inline comments
 
@@ -428,13 +428,14 @@ VARDEF char _userstring[USERSTRING_LEN];
 
VARDEF byte _vehicle_design_names;
 

	
 
/* tunnelbridge */
 
#define MAX_BRIDGES 13
 

	
 
/* Autoreplace vehicle stuff*/
 
VARDEF byte _autoreplace_array[255];
 
VARDEF byte _autoreplace_array[256];
 
VARDEF uint16 _player_num_engines[256];
 

	
 
/* Debugging levels */
 
VARDEF int _debug_spritecache_level;
 
VARDEF int _debug_misc_level;
 
VARDEF int _debug_grf_level;
 
VARDEF int _debug_ai_level;
vehicle.c
Show inline comments
 
@@ -1446,12 +1446,13 @@ int32 CmdReplaceVehicle(int x, int y, ui
 
				{
 
				const RailVehicleInfo *rvi = RailVehInfo(new_engine_type);
 
				const RailVehicleInfo *rvi2 = RailVehInfo(old_engine_type);
 
				byte capacity = rvi->capacity;
 
				Vehicle *first = GetFirstVehicleInChain(v);
 

	
 
				//if (v->owner == _local_player) InvalidateWindowClasses(WC_TRAINS_LIST);
 
				/* 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)
 
				(rvi->flags & RVI_MULTIHEAD && sprite - rvi2->image_index) is true if the engine is heading the other way, otherwise 0*/
 
				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
 
@@ -1504,23 +1505,24 @@ int32 CmdReplaceVehicle(int x, int y, ui
 
				if ( v->u.rail.first_engine == 0xffff && v->next != NULL ) {
 
					Vehicle *veh = v->next;
 
					do {
 
						veh->u.rail.first_engine = new_engine_type;
 
					} while ( (veh=veh->next) != NULL );
 
				}
 

	
 
				InvalidateWindowClasses(WC_TRAINS_LIST);
 
				break;
 
				}
 
			case VEH_Road:
 
				{
 
				const RoadVehicleInfo *rvi = RoadVehInfo(new_engine_type);
 

	
 
				v->spritenum = rvi->image_index;
 
				v->cargo_type = rvi->cargo_type;
 
				v->cargo_cap = rvi->capacity;
 
				v->max_speed = rvi->max_speed;
 
				InvalidateWindowClasses(WC_ROADVEH_LIST);
 
				break;
 
				}
 
			case VEH_Ship:
 
				{
 
				const ShipVehicleInfo *svi = ShipVehInfo(new_engine_type);
 

	
 
@@ -1530,12 +1532,13 @@ int32 CmdReplaceVehicle(int x, int y, ui
 
				v->max_speed = svi->max_speed;
 

	
 
				// 0x0100 means that we skip the check for being stopped inside the depot
 
				// since we do not stop it for autorefitting
 
				if (v->cargo_type != cargo_type)
 
					CmdRefitShip(v->x_pos, v->y_pos, DC_EXEC, v->index , cargo_type + 0x0100 );
 
				InvalidateWindowClasses(WC_SHIPS_LIST);
 
				break;
 
				}
 
			case VEH_Aircraft:
 
				{
 
				const AircraftVehicleInfo *avi = AircraftVehInfo(new_engine_type);
 
				Vehicle *u;
 
@@ -1550,24 +1553,27 @@ int32 CmdReplaceVehicle(int x, int y, ui
 
						u->cargo_cap = avi->mail_capacity;
 
					} else {
 
						// 0x0100 means that we skip the check for being stopped inside the hangar
 
						// since we do not stop it for autorefitting
 
						CmdRefitAircraft(v->x_pos, v->y_pos, DC_EXEC, v->index , cargo_type + 0x0100 );
 
					}
 
				InvalidateWindowClasses(WC_AIRCRAFT_LIST);
 
				break;
 
				}
 
			default: return CMD_ERROR;
 
			}
 
			// makes sure that the cargo is still valid compared to new capacity
 
			if (v->cargo_count != 0) {
 
				if ( v->cargo_type != cargo_type )
 
					v->cargo_count = 0;
 
				else if ( v->cargo_count > v->cargo_cap )
 
					v->cargo_count = v->cargo_cap;
 
			}
 
		}
 
		InvalidateWindow(WC_REPLACE_VEHICLE, v->type);
 
		ResortVehicleLists();
 
	}
 
	//needs to be down here because refitting will change SET_EXPENSES_TYPE if called
 
	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
 

	
 
	return cost;
 
}
vehicle_gui.c
Show inline comments
 
@@ -321,12 +321,14 @@ static void train_engine_drawing_loop(in
 

	
 
	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
 
		const Engine *e = DEREF_ENGINE(i);
 
		const RailVehicleInfo *rvi = RailVehInfo(i);
 
		const EngineInfo *info = &_engine_info[i];
 

	
 
		if ( _player_num_engines[i] == 0 && show_outdated ) continue;
 

	
 
		if ( rvi->power == 0 && !(show_cars) )   // disables display of cars (works since they do not have power)
 
			continue;
 

	
 
		if (*sel == 0) *selected_id = i;
 

	
 

	
 
@@ -343,12 +345,16 @@ static void train_engine_drawing_loop(in
 

	
 
		if (IS_INT_INSIDE(--*pos, -lines_drawn, 0)) {
 
			DrawString(*x + 59, *y + 2, GetCustomEngineName(i),
 
				colour);
 
			DrawTrainEngine(*x + 29, *y + 6, i,
 
				SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
			if ( show_outdated ) {
 
				SetDParam(0, _player_num_engines[i]);
 
				DrawStringRightAligned(213, *y+5, STR_TINY_BLACK, 0);
 
			}
 
			*y += 14;
 
		}
 
		--*sel;
 
	}
 
}
 

	
 
@@ -371,35 +377,37 @@ static void SetupScrollStuffForReplaceWi
 
			w->widget[13].color = _player_colors[_local_player];	// sets the colour of that art thing
 
			w->widget[16].color = _player_colors[_local_player];	// sets the colour of that art thing
 
			for (engine_id = 0; engine_id < NUM_TRAIN_ENGINES; engine_id++) {
 
				const Engine *e = DEREF_ENGINE(engine_id);
 
				const EngineInfo *info = &_engine_info[engine_id];
 

	
 
				if (ENGINE_AVAILABLE && RailVehInfo(engine_id)->power && e->railtype == railtype) {
 
				if (ENGINE_AVAILABLE && RailVehInfo(engine_id)->power && e->railtype == railtype ) {
 
					count++;
 
					if (sel[0]==0)  selected_id[0] = engine_id;
 
					sel[0]--;
 
					if ( _player_num_engines[engine_id] ) {
 
						if (sel[0]==0)  selected_id[0] = engine_id;
 
						sel[0]--;
 
					}
 
					if (HASBIT(e->player_avail, _local_player)) {
 
						if (sel[1]==0)  selected_id[1] = engine_id;
 
							count2++;
 
							sel[1]--;
 
						}
 
						count2++;
 
						sel[1]--;
 
					}
 
				}
 
			}
 
			break;
 
			}
 
		}
 
		case VEH_Road: {
 
			int num = NUM_ROAD_ENGINES;
 
			Engine *e = DEREF_ENGINE(ROAD_ENGINES_INDEX);
 
			byte cargo;
 
			EngineInfo *info;
 
			engine_id = ROAD_ENGINES_INDEX;
 

	
 
			do {
 
				info = &_engine_info[engine_id];
 
				if (ENGINE_AVAILABLE) {
 
				if (_player_num_engines[engine_id] ) {
 
					if (sel[0]==0)  selected_id[0] = engine_id;
 
					count++;
 
					sel[0]--;
 
				}
 
			} while (++engine_id,++e,--num);
 

	
 
@@ -426,13 +434,13 @@ static void SetupScrollStuffForReplaceWi
 
			byte cargo, refittable;
 
			EngineInfo *info;
 
			engine_id = SHIP_ENGINES_INDEX;
 

	
 
			do {
 
				info = &_engine_info[engine_id];
 
				if (ENGINE_AVAILABLE) {
 
				if (_player_num_engines[engine_id] ) {
 
					if ( sel[0] == 0 )  selected_id[0] = engine_id;
 
					count++;
 
					sel[0]--;
 
				}
 
			} while (++engine_id,++e,--num);
 

	
 
@@ -462,13 +470,13 @@ static void SetupScrollStuffForReplaceWi
 
			Engine *e = DEREF_ENGINE(AIRCRAFT_ENGINES_INDEX);
 
			EngineInfo *info;
 
			engine_id = AIRCRAFT_ENGINES_INDEX;
 

	
 
			do {
 
				info = &_engine_info[engine_id];
 
				if (ENGINE_AVAILABLE) {
 
				if (_player_num_engines[engine_id]) {
 
					count++;
 
					if (sel[0]==0)  selected_id[0] = engine_id;
 
					sel[0]--;
 
				}
 
			} while (++engine_id,++e,--num);
 

	
 
@@ -540,28 +548,30 @@ static void DrawEngineArrayInReplaceWind
 

	
 
			if ( selected_id[0] >= ROAD_ENGINES_INDEX && selected_id[0] <= SHIP_ENGINES_INDEX ) {
 
				cargo = RoadVehInfo(selected_id[0])->cargo_type;
 

	
 
				do {
 
					info = &_engine_info[engine_id];
 
					if (ENGINE_AVAILABLE) {
 
					if (_player_num_engines[engine_id]) {
 
						if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
 
							DrawString(x+59, y+2, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
 
							DrawRoadVehEngine(x+29, y+6, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
							SetDParam(0, _player_num_engines[engine_id]);
 
							DrawStringRightAligned(213, y+5, STR_TINY_BLACK, 0);
 
							y += 14;
 
						}
 
					sel[0]--;
 
					}
 

	
 
						if ( RoadVehInfo(engine_id)->cargo_type == cargo && HASBIT(e->player_avail, _local_player) ) {
 
							if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0) && RoadVehInfo(engine_id)->cargo_type == cargo) {
 
								DrawString(x2+59, y2+2, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
 
								DrawRoadVehEngine(x2+29, y2+6, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
								y2 += 14;
 
							}
 
							sel[1]--;
 
					if ( RoadVehInfo(engine_id)->cargo_type == cargo && HASBIT(e->player_avail, _local_player) ) {
 
						if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0) && RoadVehInfo(engine_id)->cargo_type == cargo) {
 
							DrawString(x2+59, y2+2, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
 
							DrawRoadVehEngine(x2+29, y2+6, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
							y2 += 14;
 
						}
 
					sel[0]--;
 
						sel[1]--;
 
					}
 
				} while (++engine_id, ++e,--num);
 
			}
 
			break;
 
		}
 

	
 
@@ -575,29 +585,31 @@ static void DrawEngineArrayInReplaceWind
 
			if ( selected_id[0] != -1 ) {
 
				cargo = ShipVehInfo(selected_id[0])->cargo_type;
 
				refittable = ShipVehInfo(selected_id[0])->refittable;
 

	
 
				do {
 
					info = &_engine_info[engine_id];
 
					if (ENGINE_AVAILABLE) {
 
					if (_player_num_engines[engine_id]) {
 
						if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
 
							DrawString(x+75, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
 
							DrawShipEngine(x+35, y+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
							SetDParam(0, _player_num_engines[engine_id]);
 
							DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0);
 
							y += 24;
 
						}
 
						if ( selected_id[0] != -1 ) {
 
							if (HASBIT(e->player_avail, _local_player) && ( cargo == ShipVehInfo(engine_id)->cargo_type || refittable & ShipVehInfo(engine_id)->refittable)) {
 
								if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
 
									DrawString(x2+75, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
 
									DrawShipEngine(x2+35, y2+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
									y2 += 24;
 
								}
 
								sel[1]--;
 
						sel[0]--;
 
					}
 
					if ( selected_id[0] != -1 ) {
 
						if (HASBIT(e->player_avail, _local_player) && ( cargo == ShipVehInfo(engine_id)->cargo_type || refittable & ShipVehInfo(engine_id)->refittable)) {
 
							if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
 
								DrawString(x2+75, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
 
								DrawShipEngine(x2+35, y2+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
								y2 += 24;
 
							}
 
							sel[1]--;
 
						}
 
						sel[0]--;
 
					}
 
				} while (++engine_id, ++e,--num);
 
			}
 
			break;
 
		}   //end of ship
 

	
 
@@ -608,30 +620,32 @@ static void DrawEngineArrayInReplaceWind
 
				int engine_id = AIRCRAFT_ENGINES_INDEX;
 
				byte subtype = AircraftVehInfo(selected_id[0])->subtype;
 
				EngineInfo *info;
 

	
 
				do {
 
					info = &_engine_info[engine_id];
 
					if (ENGINE_AVAILABLE) {
 
					if (_player_num_engines[engine_id]) {
 
						if (sel[0]==0) selected_id[0] = engine_id;
 
						if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
 
							DrawString(x+62, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
 
							DrawAircraftEngine(x+29, y+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
							SetDParam(0, _player_num_engines[engine_id]);
 
							DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0);
 
							y += 24;
 
						}
 
						if ( ((subtype && AircraftVehInfo(engine_id)->subtype) || (!(subtype) && !AircraftVehInfo(engine_id)->subtype))
 
							&& HASBIT(e->player_avail, _local_player) ) {
 
							if (sel[1]==0) selected_id[1] = engine_id;
 
							if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
 
								DrawString(x2+62, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
 
								DrawAircraftEngine(x2+29, y2+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
								y2 += 24;
 
							}
 
						sel[0]--;
 
					}
 
					if ( ((subtype && AircraftVehInfo(engine_id)->subtype) || (!(subtype) && !AircraftVehInfo(engine_id)->subtype))
 
						&& HASBIT(e->player_avail, _local_player) ) {
 
						if (sel[1]==0) selected_id[1] = engine_id;
 
						if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
 
							DrawString(x2+62, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
 
							DrawAircraftEngine(x2+29, y2+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
 
							y2 += 24;
 
						}
 
						sel[1]--;
 
						}
 
					sel[0]--;
 
					}
 
				} while (++engine_id, ++e,--num);
 
			}
 
			break;
 
		}   // end of aircraft
 
	}
 
@@ -655,12 +669,33 @@ static void ReplaceVehicleWndProc(Window
 
				int x2 = 1 + 228;
 
				int y2 = 15;
 
				int sel[2];
 
				sel[0] = WP(w,replaceveh_d).sel_index[0];
 
				sel[1] = WP(w,replaceveh_d).sel_index[1];
 

	
 
				{
 
					uint i;
 
					const Vehicle *vehicle;
 

	
 
					for (i = 0; i < lengthof(_player_num_engines); i++) {
 
						_player_num_engines[i] = 0;
 
					}
 
					FOR_ALL_VEHICLES(vehicle) {
 
						if ( vehicle->owner == _local_player ) {
 
							if (vehicle->type == VEH_Aircraft && vehicle->subtype > 2) continue;
 

	
 
							// do not count the vehicles, that contains only 0 in all var
 
							if (vehicle->engine_type == 0 && vehicle->spritenum == 0 ) continue;
 

	
 
							if (vehicle->type != DEREF_ENGINE(vehicle->engine_type)->type) continue;
 

	
 
							_player_num_engines[vehicle->engine_type]++;
 
						}
 
					}
 
				}
 

	
 
				SetupScrollStuffForReplaceWindow(w);
 

	
 
				selected_id[0] = WP(w,replaceveh_d).sel_engine[0];
 
				selected_id[1] = WP(w,replaceveh_d).sel_engine[1];
 

	
 
			// sets the selected left item to the top one if it's greater than the number of vehicles in the left side
0 comments (0 inline, 0 general)