Changeset - r13718:936583604dd1
[Not reviewed]
master
0 2 0
frosch - 15 years ago 2009-11-23 13:14:45
frosch@openttd.org
(svn r18253) -Codechange: Convert the linked list of loaded GRFFiles into a SmallVector.
2 files changed with 65 insertions and 62 deletions:
0 comments (0 inline, 0 general)
src/newgrf.cpp
Show inline comments
 
@@ -55,26 +55,27 @@
 
 * (c) Petr Baudis 2004 (GPL'd)
 
 * Changes by Florian octo Forster are (c) by the OpenTTD development team.
 
 *
 
 * Contains portions of documentation by TTDPatch team.
 
 * Thanks especially to Josef Drexler for the documentation as well as a lot
 
 * of help at #tycoon. Also thanks to Michael Blunck for is GRF files which
 
 * served as subject to the initial testing of this codec. */
 

	
 

	
 
static int _skip_sprites; // XXX
 
static uint _file_index; // XXX
 

	
 
static SmallVector<GRFFile *, 16> _grf_files;
 

	
 
static GRFFile *_cur_grffile;
 
static GRFFile *_first_grffile;
 
static SpriteID _cur_spriteid;
 
static GrfLoadingStage _cur_stage;
 
static uint32 _nfo_line;
 

	
 
static GRFConfig *_cur_grfconfig;
 

	
 
/* Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E */
 
static byte _misc_grf_features = 0;
 

	
 
/* 32 * 8 = 256 flags. Apparently TTDPatch uses this many.. */
 
static uint32 _ttdpatch_flags[8];
 

	
 
@@ -209,40 +210,38 @@ static const char *grf_load_string(byte 
 
		grfmsg(7, "String was not terminated with a zero byte.");
 
	} else {
 
		/* Increase the string length to include the NUL byte. */
 
		string_length++;
 
	}
 
	*buf += string_length;
 

	
 
	return string;
 
}
 

	
 
static GRFFile *GetFileByGRFID(uint32 grfid)
 
{
 
	GRFFile *file;
 

	
 
	for (file = _first_grffile; file != NULL; file = file->next) {
 
		if (file->grfid == grfid) break;
 
	}
 
	return file;
 
	const GRFFile * const *end = _grf_files.End();
 
	for (GRFFile * const *file = _grf_files.Begin(); file != end; file++) {
 
		if ((*file)->grfid == grfid) return *file;
 
	}
 
	return NULL;
 
}
 

	
 
static GRFFile *GetFileByFilename(const char *filename)
 
{
 
	GRFFile *file;
 

	
 
	for (file = _first_grffile; file != NULL; file = file->next) {
 
		if (strcmp(file->filename, filename) == 0) break;
 
	}
 
	return file;
 
	const GRFFile * const *end = _grf_files.End();
 
	for (GRFFile * const *file = _grf_files.Begin(); file != end; file++) {
 
		if (strcmp((*file)->filename, filename) == 0) return *file;
 
	}
 
	return NULL;
 
}
 

	
 
/** Reset all NewGRFData that was used only while processing data */
 
static void ClearTemporaryNewGRFData(GRFFile *gf)
 
{
 
	/* Clear the GOTO labels used for GRF processing */
 
	for (GRFLabel *l = gf->label; l != NULL;) {
 
		GRFLabel *l2 = l->next;
 
		free(l);
 
		l = l2;
 
	}
 
	gf->label = NULL;
 
@@ -2717,26 +2716,27 @@ static void NewSpriteGroup(byte *buf, si
 

	
 
	if (!check_length(len, 5, "NewSpriteGroup")) return;
 
	buf++;
 

	
 
	uint8 feature = grf_load_byte(&buf);
 
	uint8 setid   = grf_load_byte(&buf);
 
	uint8 type    = grf_load_byte(&buf);
 

	
 
	if (setid >= _cur_grffile->spritegroups_count) {
 
		/* Allocate memory for new sprite group references. */
 
		_cur_grffile->spritegroups = ReallocT(_cur_grffile->spritegroups, setid + 1);
 
		/* Initialise new space to NULL */
 
		for (; _cur_grffile->spritegroups_count < (setid + 1); _cur_grffile->spritegroups_count++)
 
		for (; _cur_grffile->spritegroups_count < (setid + 1); _cur_grffile->spritegroups_count++) {
 
			_cur_grffile->spritegroups[_cur_grffile->spritegroups_count] = NULL;
 
		}
 
	}
 

	
 
	switch (type) {
 
		/* Deterministic Sprite Group */
 
		case 0x81: // Self scope, byte
 
		case 0x82: // Parent scope, byte
 
		case 0x85: // Self scope, word
 
		case 0x86: // Parent scope, word
 
		case 0x89: // Self scope, dword
 
		case 0x8A: // Parent scope, dword
 
		{
 
			byte varadjust;
 
@@ -5421,29 +5421,31 @@ static void InitializeGRFSpecial()
 
	                   |                                                      (0 << 0x13)  // followvehicle
 
	                   |                                                      (1 << 0x14)  // trams
 
	                   |                                                      (0 << 0x15)  // enhancetunnels
 
	                   |                                                      (1 << 0x16)  // shortrvs
 
	                   |                                                      (1 << 0x17)  // articulatedrvs
 
	                   |       ((_settings_game.vehicle.dynamic_engines ? 1 : 0) << 0x18)  // dynamic engines
 
	                   |                                                      (1 << 0x1E)  // variablerunningcosts
 
	                   |                                                      (1 << 0x1F); // any switch is on
 
}
 

	
 
static void ResetCustomStations()
 
{
 
	for (GRFFile *file = _first_grffile; file != NULL; file = file->next) {
 
		if (file->stations == NULL) continue;
 
	const GRFFile * const *end = _grf_files.End();
 
	for (GRFFile **file = _grf_files.Begin(); file != end; file++) {
 
		StationSpec **&stations = (*file)->stations;
 
		if (stations == NULL) continue;
 
		for (uint i = 0; i < MAX_STATIONS; i++) {
 
			if (file->stations[i] == NULL) continue;
 
			StationSpec *statspec = file->stations[i];
 
			if (stations[i] == NULL) continue;
 
			StationSpec *statspec = stations[i];
 

	
 
			/* Release renderdata, if it wasn't copied from another custom station spec  */
 
			if (!statspec->copied_renderdata) {
 
				for (uint t = 0; t < statspec->tiles; t++) {
 
					free((void*)statspec->renderdata[t].seq);
 
				}
 
				free(statspec->renderdata);
 
			}
 

	
 
			/* Release platforms and layouts */
 
			if (!statspec->copied_layouts) {
 
				for (uint l = 0; l < statspec->lengths; l++) {
 
@@ -5452,100 +5454,103 @@ static void ResetCustomStations()
 
					}
 
					free(statspec->layouts[l]);
 
				}
 
				free(statspec->layouts);
 
				free(statspec->platforms);
 
			}
 

	
 
			/* Release this station */
 
			free(statspec);
 
		}
 

	
 
		/* Free and reset the station data */
 
		free(file->stations);
 
		file->stations = NULL;
 
		free(stations);
 
		stations = NULL;
 
	}
 
}
 

	
 
static void ResetCustomHouses()
 
{
 
	for (GRFFile *file = _first_grffile; file != NULL; file = file->next) {
 
		if (file->housespec == NULL) continue;
 
	const GRFFile * const *end = _grf_files.End();
 
	for (GRFFile **file = _grf_files.Begin(); file != end; file++) {
 
		HouseSpec **&housespec = (*file)->housespec;
 
		if (housespec == NULL) continue;
 
		for (uint i = 0; i < HOUSE_MAX; i++) {
 
			free(file->housespec[i]);
 
			free(housespec[i]);
 
		}
 

	
 
		free(file->housespec);
 
		file->housespec = NULL;
 
		free(housespec);
 
		housespec = NULL;
 
	}
 
}
 

	
 
static void ResetCustomIndustries()
 
{
 
	for (GRFFile *file = _first_grffile; file != NULL; file = file->next) {
 
	const GRFFile * const *end = _grf_files.End();
 
	for (GRFFile **file = _grf_files.Begin(); file != end; file++) {
 
		IndustrySpec **&industryspec = (*file)->industryspec;
 
		IndustryTileSpec **&indtspec = (*file)->indtspec;
 

	
 
		/* We are verifiying both tiles and industries specs loaded from the grf file
 
		 * First, let's deal with industryspec */
 
		if (file->industryspec != NULL) {
 

	
 
		if (industryspec != NULL) {
 
			for (uint i = 0; i < NUM_INDUSTRYTYPES; i++) {
 
				IndustrySpec *ind = file->industryspec[i];
 
				IndustrySpec *ind = industryspec[i];
 
				if (ind == NULL) continue;
 

	
 
				/* We need to remove the sounds array */
 
				if (HasBit(ind->cleanup_flag, CLEAN_RANDOMSOUNDS)) {
 
					free((void*)ind->random_sounds);
 
				}
 

	
 
				/* We need to remove the tiles layouts */
 
				if (HasBit(ind->cleanup_flag, CLEAN_TILELSAYOUT) && ind->table != NULL) {
 
					for (int j = 0; j < ind->num_table; j++) {
 
						/* remove the individual layouts */
 
						free((void*)ind->table[j]);
 
					}
 
					/* remove the layouts pointers */
 
					free((void*)ind->table);
 
					ind->table = NULL;
 
				}
 

	
 
				free(ind);
 
			}
 

	
 
			free(file->industryspec);
 
			file->industryspec = NULL;
 
			free(industryspec);
 
			industryspec = NULL;
 
		}
 

	
 
		if (file->indtspec == NULL) continue;
 
		if (indtspec == NULL) continue;
 
		for (uint i = 0; i < NUM_INDUSTRYTILES; i++) {
 
			free(file->indtspec[i]);
 
			free(indtspec[i]);
 
		}
 

	
 
		free(file->indtspec);
 
		file->indtspec = NULL;
 
		free(indtspec);
 
		indtspec = NULL;
 
	}
 
}
 

	
 
static void ResetNewGRF()
 
{
 
	GRFFile *next;
 

	
 
	for (GRFFile *f = _first_grffile; f != NULL; f = next) {
 
		next = f->next;
 

	
 
	const GRFFile * const *end = _grf_files.End();
 
	for (GRFFile **file = _grf_files.Begin(); file != end; file++) {
 
		GRFFile *f = *file;
 
		free(f->filename);
 
		free(f->cargo_list);
 
		free(f->railtype_list);
 
		free(f);
 
	}
 

	
 
	_first_grffile = NULL;
 
	_grf_files.Clear();
 
	_cur_grffile   = NULL;
 
}
 

	
 
static void ResetNewGRFErrors()
 
{
 
	for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
 
		if (!HasBit(c->flags, GCF_COPY) && c->error != NULL) {
 
			free(c->error->custom_message);
 
			free(c->error->data);
 
			free(c->error);
 
			c->error = NULL;
 
		}
 
@@ -5668,31 +5673,25 @@ static void InitNewGRFFile(const GRFConf
 
	newfile->filename = strdup(config->filename);
 
	newfile->sprite_offset = sprite_offset;
 

	
 
	/* Initialise local settings to defaults */
 
	newfile->traininfo_vehicle_pitch = 0;
 
	newfile->traininfo_vehicle_width = TRAININFO_DEFAULT_VEHICLE_WIDTH;
 

	
 
	/* Copy the initial parameter list */
 
	assert_compile(lengthof(newfile->param) == lengthof(config->param) && lengthof(config->param) == 0x80);
 
	newfile->param_end = config->num_params;
 
	memcpy(newfile->param, config->param, sizeof(newfile->param));
 

	
 
	if (_first_grffile == NULL) {
 
		_cur_grffile = newfile;
 
		_first_grffile = newfile;
 
	} else {
 
		_cur_grffile->next = newfile;
 
		_cur_grffile = newfile;
 
	}
 
	*_grf_files.Append() = _cur_grffile = newfile;
 
}
 

	
 

	
 
/** List of what cargo labels are refittable for the given the vehicle-type.
 
 * Only currently active labels are applied. */
 
static const CargoLabel _default_refitmasks_rail[] = {
 
	'PASS', 'COAL', 'MAIL', 'LVST', 'GOOD', 'GRAI', 'WHEA', 'MAIZ', 'WOOD',
 
	'IORE', 'STEL', 'VALU', 'GOLD', 'DIAM', 'PAPR', 'FOOD', 'FRUT', 'CORE',
 
	'WATR', 'SUGR', 'TOYS', 'BATT', 'SWET', 'TOFF', 'COLA', 'CTCD', 'BUBL',
 
	'PLST', 'FZDR',
 
	0 };
 

	
 
@@ -5800,79 +5799,84 @@ static void FinaliseHouseArray()
 
{
 
	/* If there are no houses with start dates before 1930, then all houses
 
	 * with start dates of 1930 have them reset to 0. This is in order to be
 
	 * compatible with TTDPatch, where if no houses have start dates before
 
	 * 1930 and the date is before 1930, the game pretends that this is 1930.
 
	 * If there have been any houses defined with start dates before 1930 then
 
	 * the dates are left alone.
 
	 * On the other hand, why 1930? Just 'fix' the houses with the lowest
 
	 * minimum introduction date to 0.
 
	 */
 
	Year min_year = MAX_YEAR;
 

	
 
	for (GRFFile *file = _first_grffile; file != NULL; file = file->next) {
 
		if (file->housespec == NULL) continue;
 
	const GRFFile * const *end = _grf_files.End();
 
	for (GRFFile **file = _grf_files.Begin(); file != end; file++) {
 
		HouseSpec **&housespec = (*file)->housespec;
 
		if (housespec == NULL) continue;
 

	
 
		for (int i = 0; i < HOUSE_MAX; i++) {
 
			HouseSpec *hs = file->housespec[i];
 
			HouseSpec *hs = housespec[i];
 

	
 
			if (hs == NULL) continue;
 

	
 
			const HouseSpec *next1 = (i + 1 < HOUSE_MAX ? file->housespec[i + 1] : NULL);
 
			const HouseSpec *next2 = (i + 2 < HOUSE_MAX ? file->housespec[i + 2] : NULL);
 
			const HouseSpec *next3 = (i + 3 < HOUSE_MAX ? file->housespec[i + 3] : NULL);
 
			const HouseSpec *next1 = (i + 1 < HOUSE_MAX ? housespec[i + 1] : NULL);
 
			const HouseSpec *next2 = (i + 2 < HOUSE_MAX ? housespec[i + 2] : NULL);
 
			const HouseSpec *next3 = (i + 3 < HOUSE_MAX ? housespec[i + 3] : NULL);
 

	
 
			if (((hs->building_flags & BUILDING_HAS_2_TILES) != 0 &&
 
						(next1 == NULL || !next1->enabled || (next1->building_flags & BUILDING_HAS_1_TILE) != 0)) ||
 
					((hs->building_flags & BUILDING_HAS_4_TILES) != 0 &&
 
						(next2 == NULL || !next2->enabled || (next2->building_flags & BUILDING_HAS_1_TILE) != 0 ||
 
						next3 == NULL || !next3->enabled || (next3->building_flags & BUILDING_HAS_1_TILE) != 0))) {
 
				hs->enabled = false;
 
				DEBUG(grf, 1, "FinaliseHouseArray: %s defines house %d as multitile, but no suitable tiles follow. Disabling house.", file->filename, hs->local_id);
 
				DEBUG(grf, 1, "FinaliseHouseArray: %s defines house %d as multitile, but no suitable tiles follow. Disabling house.", (*file)->filename, hs->local_id);
 
				continue;
 
			}
 

	
 
			/* Some places sum population by only counting north tiles. Other places use all tiles causing desyncs.
 
			 * As the newgrf specs define population to be zero for non-north tiles, we just disable the offending house.
 
			 * If you want to allow non-zero populations somewhen, make sure to sum the population of all tiles in all places. */
 
			if (((hs->building_flags & BUILDING_HAS_2_TILES) != 0 && next1->population != 0) ||
 
					((hs->building_flags & BUILDING_HAS_4_TILES) != 0 && (next2->population != 0 || next3->population != 0))) {
 
				hs->enabled = false;
 
				DEBUG(grf, 1, "FinaliseHouseArray: %s defines multitile house %d with non-zero population on additional tiles. Disabling house.", file->filename, hs->local_id);
 
				DEBUG(grf, 1, "FinaliseHouseArray: %s defines multitile house %d with non-zero population on additional tiles. Disabling house.", (*file)->filename, hs->local_id);
 
				continue;
 
			}
 

	
 
			_house_mngr.SetEntitySpec(hs);
 
			if (hs->min_year < min_year) min_year = hs->min_year;
 
		}
 
	}
 

	
 
	if (min_year != 0) {
 
		for (int i = 0; i < HOUSE_MAX; i++) {
 
			HouseSpec *hs = HouseSpec::Get(i);
 

	
 
			if (hs->enabled && hs->min_year == min_year) hs->min_year = 0;
 
		}
 
	}
 
}
 

	
 
/** Add all new industries to the industry array. Industry properties can be set at any
 
 * time in the GRF file, so we can only add a industry spec to the industry array
 
 * after the file has finished loading. */
 
static void FinaliseIndustriesArray()
 
{
 
	for (GRFFile *file = _first_grffile; file != NULL; file = file->next) {
 
		if (file->industryspec != NULL) {
 
	const GRFFile * const *end = _grf_files.End();
 
	for (GRFFile **file = _grf_files.Begin(); file != end; file++) {
 
		IndustrySpec **&industryspec = (*file)->industryspec;
 
		IndustryTileSpec **&indtspec = (*file)->indtspec;
 
		if (industryspec != NULL) {
 
			for (int i = 0; i < NUM_INDUSTRYTYPES; i++) {
 
				IndustrySpec *indsp = file->industryspec[i];
 
				IndustrySpec *indsp = industryspec[i];
 

	
 
				if (indsp != NULL && indsp->enabled) {
 
					StringID strid;
 
					/* process the conversion of text at the end, so to be sure everything will be fine
 
					 * and available.  Check if it does not return undefind marker, which is a very good sign of a
 
					 * substitute industry who has not changed the string been examined, thus using it as such */
 
					strid = GetGRFStringID(indsp->grf_prop.grffile->grfid, indsp->name);
 
					if (strid != STR_UNDEFINED) indsp->name = strid;
 

	
 
					strid = GetGRFStringID(indsp->grf_prop.grffile->grfid, indsp->closure_text);
 
					if (strid != STR_UNDEFINED) indsp->closure_text = strid;
 

	
 
@@ -5889,27 +5893,27 @@ static void FinaliseIndustriesArray()
 
						/* STR_NULL (0) can be set by grf.  It has a meaning regarding assignation of the
 
						 * station's name. Don't want to lose the value, therefore, do not process. */
 
						strid = GetGRFStringID(indsp->grf_prop.grffile->grfid, indsp->station_name);
 
						if (strid != STR_UNDEFINED) indsp->station_name = strid;
 
					}
 

	
 
					_industry_mngr.SetEntitySpec(indsp);
 
					_loaded_newgrf_features.has_newindustries = true;
 
				}
 
			}
 
		}
 

	
 
		if (file->indtspec != NULL) {
 
		if (indtspec != NULL) {
 
			for (int i = 0; i < NUM_INDUSTRYTILES; i++) {
 
				IndustryTileSpec *indtsp = file->indtspec[i];
 
				IndustryTileSpec *indtsp = indtspec[i];
 
				if (indtsp != NULL) {
 
					_industile_mngr.SetEntitySpec(indtsp);
 
				}
 
			}
 
		}
 
	}
 

	
 
	for (uint j = 0; j < NUM_INDUSTRYTYPES; j++) {
 
		IndustrySpec *indsp = &_industry_specs[j];
 
		if (indsp->enabled && indsp->grf_prop.grffile != NULL) {
 
			for (uint i = 0; i < 3; i++) {
 
				indsp->conflicting[i] = MapNewGRFIndustryType(indsp->conflicting[i], indsp->grf_prop.grffile->grfid);
src/newgrf.h
Show inline comments
 
@@ -65,25 +65,24 @@ struct GRFLabel {
 
	uint32 nfo_line;
 
	size_t pos;
 
	struct GRFLabel *next;
 
};
 

	
 
/** Dynamic data of a loaded NewGRF */
 
struct GRFFile {
 
	char *filename;
 
	bool is_ottdfile;
 
	uint32 grfid;
 
	uint16 sprite_offset;
 
	byte grf_version;
 
	GRFFile *next;
 

	
 
	/* A sprite group contains all sprites of a given vehicle (or multiple
 
	 * vehicles) when carrying given cargo. It consists of several sprite
 
	 * sets.  Group ids are refered as "cargo id"s by TTDPatch
 
	 * documentation, contributing to the global confusion.
 
	 *
 
	 * A sprite set contains all sprites of a given vehicle carrying given
 
	 * cargo at a given *stage* - that is usually its load stage. Ie. you
 
	 * can have a spriteset for an empty wagon, wagon full of coal,
 
	 * half-filled wagon etc.  Each spriteset contains eight sprites (one
 
	 * per direction) or four sprites if the vehicle is symmetric. */
 

	
0 comments (0 inline, 0 general)