Changeset - r2625:27ad3b929a5b
[Not reviewed]
master
0 8 2
peter1138 - 19 years ago 2005-11-12 00:19:34
peter1138@openttd.org
(svn r3167) - NewGRF: Start moving custom station code to separate files.
Rewrite handling of station classes.
Allow for more than 8 station tile layouts.
Start of code to unload custom stations.
10 files changed with 260 insertions and 180 deletions:
0 comments (0 inline, 0 general)
Makefile
Show inline comments
 
@@ -614,96 +614,97 @@ C_SOURCES += md5.c
 
C_SOURCES += mersenne.c
 
C_SOURCES += minilzo.c
 
C_SOURCES += misc.c
 
C_SOURCES += misc_cmd.c
 
C_SOURCES += misc_gui.c
 
C_SOURCES += mixer.c
 
C_SOURCES += music_gui.c
 
C_SOURCES += namegen.c
 
C_SOURCES += network.c
 
C_SOURCES += network_client.c
 
C_SOURCES += network_data.c
 
C_SOURCES += network_gamelist.c
 
C_SOURCES += network_gui.c
 
C_SOURCES += network_server.c
 
C_SOURCES += network_udp.c
 
C_SOURCES += news_gui.c
 
C_SOURCES += npf.c
 
C_SOURCES += oldloader.c
 
C_SOURCES += order_cmd.c
 
C_SOURCES += order_gui.c
 
C_SOURCES += openttd.c
 
C_SOURCES += pathfind.c
 
C_SOURCES += pbs.c
 
C_SOURCES += player_gui.c
 
C_SOURCES += players.c
 
C_SOURCES += pool.c
 
C_SOURCES += queue.c
 
C_SOURCES += rail.c
 
C_SOURCES += rail_cmd.c
 
C_SOURCES += rail_gui.c
 
C_SOURCES += rev.c
 
C_SOURCES += road_cmd.c
 
C_SOURCES += road_gui.c
 
C_SOURCES += roadveh_cmd.c
 
C_SOURCES += roadveh_gui.c
 
C_SOURCES += saveload.c
 
C_SOURCES += screenshot.c
 
C_SOURCES += settings.c
 
C_SOURCES += settings_gui.c
 
C_SOURCES += ship_cmd.c
 
C_SOURCES += ship_gui.c
 
C_SOURCES += signs.c
 
C_SOURCES += smallmap_gui.c
 
C_SOURCES += sound.c
 
C_SOURCES += sprite.c
 
C_SOURCES += spritecache.c
 
C_SOURCES += station_cmd.c
 
C_SOURCES += station_gui.c
 
C_SOURCES += station_newgrf.c
 
C_SOURCES += string.c
 
C_SOURCES += strings.c
 
C_SOURCES += subsidy_gui.c
 
C_SOURCES += terraform_gui.c
 
C_SOURCES += texteff.c
 
C_SOURCES += thread.c
 
C_SOURCES += tile.c
 
C_SOURCES += town_cmd.c
 
C_SOURCES += town_gui.c
 
C_SOURCES += train_cmd.c
 
C_SOURCES += train_gui.c
 
C_SOURCES += tree_cmd.c
 
C_SOURCES += tunnelbridge_cmd.c
 
C_SOURCES += unmovable_cmd.c
 
C_SOURCES += vehicle.c
 
C_SOURCES += vehicle_gui.c
 
C_SOURCES += viewport.c
 
C_SOURCES += water_cmd.c
 
C_SOURCES += waypoint.c
 
C_SOURCES += widget.c
 
C_SOURCES += window.c
 
C_SOURCES += music/null_m.c
 
C_SOURCES += sound/null_s.c
 
C_SOURCES += video/dedicated_v.c
 
C_SOURCES += video/null_v.c
 

	
 
# AI related files
 
C_SOURCES += ai/ai.c
 
C_SOURCES += ai/default/default.c
 
C_SOURCES += ai/trolly/trolly.c
 
C_SOURCES += ai/trolly/build.c
 
C_SOURCES += ai/trolly/pathfinder.c
 
C_SOURCES += ai/trolly/shared.c
 

	
 
CXX_SOURCES =
 

	
 
OBJC_SOURCES =
 

	
 
ifdef WITH_SDL
 
C_SOURCES += sdl.c
 
C_SOURCES += sound/sdl_s.c
 
C_SOURCES += video/sdl_v.c
 
endif
 

	
 
ifdef WIN32
 
C_SOURCES += win32.c
 
C_SOURCES += music/win32_m.c
 
C_SOURCES += sound/win32_s.c
newgrf.c
Show inline comments
 
@@ -755,169 +755,159 @@ static bool AircraftVehicleChangeInfo(ui
 
		} break;
 
		case 0x19: { /* Cargo classes disallowed */
 
			FOR_EACH_OBJECT {
 
				cargo_disallowed[AIRCRAFT_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
 
			}
 
		} break;
 
		case 0x14: /* Callback */
 
		case 0x15: /* Refit cost */
 
		case 0x16: /* Retire vehicle early */
 
		case 0x17: /* Miscellaneous flags */
 
		{
 
			/* TODO */
 
			FOR_EACH_OBJECT {
 
				grf_load_byte(&buf);
 
			}
 
			ret = true;
 
		}	break;
 
		default:
 
			ret = true;
 
	}
 

	
 
	*bufp = buf;
 
	return ret;
 
}
 

	
 
static bool StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int len)
 
{
 
	byte *buf = *bufp;
 
	int i;
 
	int ret = 0;
 

	
 
	/* This is one single huge TODO. It doesn't handle anything more than
 
	 * just waypoints for now. */
 

	
 
	//printf("sci %d %d [0x%02x]\n", stid, numinfo, prop);
 
	switch (prop) {
 
		case 0x08:
 
		{	/* Class ID */
 
			FOR_EACH_OBJECT {
 
				StationSpec *stat = &_cur_grffile->stations[stid + i];
 
				uint32 classid;
 

	
 
				/* classid, for a change, is always little-endian */
 
				classid = *(buf++) << 24;
 
				classid |= *(buf++) << 16;
 
				classid |= *(buf++) << 8;
 
				classid |= *(buf++);
 

	
 
				switch (classid) {
 
					case 'DFLT':
 
						stat->sclass = STAT_CLASS_DFLT;
 
						break;
 
					case 'WAYP':
 
						stat->sclass = STAT_CLASS_WAYP;
 
						break;
 
					default:
 
						/* TODO: No support for custom
 
						 * classes for now, so stuff
 
						 * everything to the single
 
						 * default one. --pasky */
 
						stat->sclass = STAT_CLASS_DFLT;
 
						//stat->sclass = STAT_CLASS_CUSTOM;
 
						break;
 
				}
 
				stat->sclass = AllocateStationClass(classid);
 
			}
 
			break;
 
		}
 
		case 0x09:
 
		{	/* Define sprite layout */
 
			FOR_EACH_OBJECT {
 
				StationSpec *stat = &_cur_grffile->stations[stid + i];
 
				int t;
 

	
 
				stat->tiles = grf_load_byte(&buf);
 
				stat->tiles = grf_load_extended(&buf);
 
				stat->renderdata = calloc(stat->tiles, sizeof(*stat->renderdata));
 
				for (t = 0; t < stat->tiles; t++) {
 
					DrawTileSprites *dts = &stat->renderdata[t];
 
					int seq_count = 0;
 

	
 
					if (t >= 8) {
 
						grfmsg(GMS_WARN, "StationChangeInfo: Sprite %d>=8, skipping.", t);
 
						grf_load_dword(&buf); // at least something
 
						continue;
 
					}
 

	
 
					dts->ground_sprite = grf_load_dword(&buf);
 
					if (!dts->ground_sprite) {
 
					PalSpriteID ground_sprite;
 

	
 
					ground_sprite = grf_load_dword(&buf);
 
					if (ground_sprite == 0) {
 
						static const DrawTileSeqStruct empty = {0x80, 0, 0, 0, 0, 0, 0};
 
						dts->seq = &empty;
 
						continue;
 
					}
 

	
 
					if (HASBIT(ground_sprite, 31)) {
 
						// Bit 31 indicates that we should use a custom sprite.
 
						dts->ground_sprite = GB(ground_sprite, 0, 15) - 0x42D;
 
						dts->ground_sprite += _cur_grffile->first_spriteset;
 
					} else {
 
						dts->ground_sprite = ground_sprite;
 
					}
 

	
 
					dts->seq = NULL;
 
					while (buf < *bufp + len) {
 
						DrawTileSeqStruct *dtss;
 

	
 
						// no relative bounding box support
 
						dts->seq = realloc((void*)dts->seq, ++seq_count * sizeof(DrawTileSeqStruct));
 
						dtss = (DrawTileSeqStruct*) &dts->seq[seq_count - 1];
 

	
 
						dtss->delta_x = grf_load_byte(&buf);
 
						if ((byte) dtss->delta_x == 0x80) break;
 
						dtss->delta_y = grf_load_byte(&buf);
 
						dtss->delta_z = grf_load_byte(&buf);
 
						dtss->width = grf_load_byte(&buf);
 
						dtss->height = grf_load_byte(&buf);
 
						dtss->unk = grf_load_byte(&buf);
 
						dtss->image = grf_load_dword(&buf) - 0x42d;
 
					}
 
				}
 
			}
 
			break;
 
		}
 
		case 0x0a:
 
		{	/* Copy sprite layout */
 
			FOR_EACH_OBJECT {
 
				StationSpec *stat = &_cur_grffile->stations[stid + i];
 
				byte srcid = grf_load_byte(&buf);
 
				const StationSpec *srcstat = &_cur_grffile->stations[srcid];
 
				int t;
 

	
 
				stat->tiles = srcstat->tiles;
 
				stat->renderdata = calloc(stat->tiles, sizeof(*stat->renderdata));
 
				for (t = 0; t < stat->tiles; t++) {
 
					DrawTileSprites *dts = &stat->renderdata[t];
 
					const DrawTileSprites *sdts = &srcstat->renderdata[t];
 
					DrawTileSeqStruct const *sdtss = sdts->seq;
 
					int seq_count = 0;
 

	
 
					dts->ground_sprite = sdts->ground_sprite;
 
					if (!dts->ground_sprite) {
 
						static const DrawTileSeqStruct empty = {0x80, 0, 0, 0, 0, 0, 0};
 
						dts->seq = &empty;
 
						continue;
 
					}
 

	
 
					dts->seq = NULL;
 
					while (1) {
 
						DrawTileSeqStruct *dtss;
 

	
 
						// no relative bounding box support
 
						dts->seq = realloc((void*)dts->seq, ++seq_count * sizeof(DrawTileSeqStruct));
 
						dtss = (DrawTileSeqStruct*) &dts->seq[seq_count - 1];
 
						*dtss = *sdtss;
 
						if ((byte) dtss->delta_x == 0x80) break;
 
						sdtss++;
 
					}
 
				}
 
			}
 
			break;
 
		}
 
		case 0x0b:
 
		{	/* Callback */
 
			/* TODO */
 
			FOR_EACH_OBJECT {
 
				grf_load_byte(&buf);
 
			}
 
			ret = 1;
 
			break;
 
		}
 
		case 0x0C:
 
		{	/* Platforms number */
 
			FOR_EACH_OBJECT {
 
				StationSpec *stat = &_cur_grffile->stations[stid + i];
 

	
 
				stat->allowed_platforms = ~grf_load_byte(&buf);
 
			}
 
			break;
 
		}
 
		case 0x0D:
 
		{	/* Platforms length */
 
@@ -1503,96 +1493,99 @@ static void NewSpriteGroup(byte *buf, in
 
		rg->var_scope = numloaded == 0x83 ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
 

	
 
		rg->triggers = grf_load_byte(&buf);
 
		rg->cmp_mode = rg->triggers & 0x80;
 
		rg->triggers &= 0x7F;
 

	
 
		rg->lowest_randbit = grf_load_byte(&buf);
 
		rg->num_groups = grf_load_byte(&buf);
 

	
 
		rg->groups = calloc(rg->num_groups, sizeof(*rg->groups));
 
		for (i = 0; i < rg->num_groups; i++) {
 
			uint16 groupid = grf_load_word(&buf);
 

	
 
			if (HASBIT(groupid, 15)) {
 
				rg->groups[i] = NewCallBackResultSpriteGroup(groupid);
 
				rg->groups[i]->ref_count++;
 
			} else if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
 
				grfmsg(GMS_WARN, "NewSpriteGroup(%02x:0x%x): Groupid %04x does not exist, leaving empty.", setid, numloaded, groupid);
 
				rg->groups[i] = NULL;
 
			} else {
 
				rg->groups[i] = _cur_grffile->spritegroups[groupid];
 
				rg->groups[i]->ref_count++;
 
			}
 
		}
 

	
 
		if (_cur_grffile->spritegroups[setid] != NULL)
 
			UnloadSpriteGroup(&_cur_grffile->spritegroups[setid]);
 
		_cur_grffile->spritegroups[setid] = group;
 
		group->ref_count++;
 
		return;
 
	}
 

	
 
	if (!_cur_grffile->spriteset_start) {
 
		grfmsg(GMS_ERROR, "NewSpriteGroup: No sprite set to work on! Skipping.");
 
		return;
 
	}
 

	
 
	if (_cur_grffile->spriteset_feature != feature) {
 
		grfmsg(GMS_ERROR, "NewSpriteGroup: Group feature %x doesn't match set feature %x! Playing it risky and trying to use it anyway.", feature, _cur_grffile->spriteset_feature);
 
		// return; // XXX: we can't because of MB's newstats.grf --pasky
 
	}
 

	
 
	check_length(bufend - buf, 5, "NewSpriteGroup");
 
	buf += 5;
 
	check_length(bufend - buf, 2 * numloaded, "NewSpriteGroup");
 
	loaded_ptr = buf;
 
	loading_ptr = buf + 2 * numloaded;
 

	
 
	if (_cur_grffile->first_spriteset == 0)
 
		_cur_grffile->first_spriteset = _cur_grffile->spriteset_start;
 

	
 
	if (numloaded > 16) {
 
		grfmsg(GMS_WARN, "NewSpriteGroup: More than 16 sprites in group %x, skipping the rest.", setid);
 
		numloaded = 16;
 
	}
 
	if (numloading > 16) {
 
		grfmsg(GMS_WARN, "NewSpriteGroup: More than 16 sprites in group %x, skipping the rest.", setid);
 
		numloading = 16;
 
	}
 

	
 
	group = calloc(1, sizeof(*group));
 
	group->type = SGT_REAL;
 
	rg = &group->g.real;
 

	
 
	rg->sprites_per_set = _cur_grffile->spriteset_numents;
 
	rg->loaded_count  = numloaded;
 
	rg->loading_count = numloading;
 

	
 
	DEBUG(grf, 6) ("NewSpriteGroup: New SpriteGroup 0x%02hhx, %u views, %u loaded, %u loading, sprites %u - %u",
 
			setid, rg->sprites_per_set, rg->loaded_count, rg->loading_count,
 
			_cur_grffile->spriteset_start - _cur_grffile->sprite_offset,
 
			_cur_grffile->spriteset_start + (_cur_grffile->spriteset_numents * (numloaded + numloading)) - _cur_grffile->sprite_offset);
 

	
 
	for (i = 0; i < numloaded; i++) {
 
		uint16 spriteset_id = grf_load_word(&loaded_ptr);
 
		if (HASBIT(spriteset_id, 15)) {
 
			rg->loaded[i] = NewCallBackResultSpriteGroup(spriteset_id);
 
		} else {
 
			rg->loaded[i] = NewResultSpriteGroup(_cur_grffile->spriteset_start + spriteset_id * _cur_grffile->spriteset_numents, rg->sprites_per_set);
 
		}
 
		rg->loaded[i]->ref_count++;
 
		DEBUG(grf, 8) ("NewSpriteGroup: + rg->loaded[%i]  = %u (subset %u)", i, rg->loaded[i]->g.result.result, spriteset_id);
 
	}
 

	
 
	for (i = 0; i < numloading; i++) {
 
		uint16 spriteset_id = grf_load_word(&loading_ptr);
 
		if (HASBIT(spriteset_id, 15)) {
 
			rg->loading[i] = NewCallBackResultSpriteGroup(spriteset_id);
 
		} else {
 
			rg->loading[i] = NewResultSpriteGroup(_cur_grffile->spriteset_start + spriteset_id * _cur_grffile->spriteset_numents, rg->sprites_per_set);
 
		}
 
		rg->loading[i]->ref_count++;
 
		DEBUG(grf, 8) ("NewSpriteGroup: + rg->loading[%i] = %u (subset %u)", i, rg->loading[i]->g.result.result, spriteset_id);
 
	}
 

	
 
	if (_cur_grffile->spritegroups[setid] != NULL)
 
		UnloadSpriteGroup(&_cur_grffile->spritegroups[setid]);
 
	_cur_grffile->spritegroups[setid] = group;
 
	group->ref_count++;
 
@@ -1643,98 +1636,98 @@ static void NewVehicle_SpriteGroupMappin
 
	}
 

	
 

	
 
	if (feature == GSF_STATION) {
 
		// We do things differently for stations.
 

	
 
		for (i = 0; i < idcount; i++) {
 
			uint8 stid = buf[3 + i];
 
			StationSpec *stat = &_cur_grffile->stations[stid];
 
			byte *bp = &buf[4 + idcount];
 

	
 
			for (c = 0; c < cidcount; c++) {
 
				uint8 ctype = grf_load_byte(&bp);
 
				uint16 groupid = grf_load_word(&bp);
 

	
 
				if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
 
					grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Spriteset %x out of range %x or empty, skipping.",
 
					       groupid, _cur_grffile->spritegroups_count);
 
					return;
 
				}
 

	
 
				if (ctype != 0xFF) {
 
					/* TODO: No support for any other cargo. */
 
					continue;
 
				}
 

	
 
				stat->spritegroup[1] = _cur_grffile->spritegroups[groupid];
 
				stat->spritegroup[1]->ref_count++;
 
			}
 
		}
 

	
 
		{
 
			byte *bp = buf + 4 + idcount + cidcount * 3;
 
			uint16 groupid = grf_load_word(&bp);
 

	
 
			if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
 
				grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Spriteset %x out of range %x or empty, skipping.",
 
				       groupid, _cur_grffile->spritegroups_count);
 
				return;
 
			}
 

	
 
			for (i = 0; i < idcount; i++) {
 
				uint8 stid = buf[3 + i];
 
				StationSpec *stat = &_cur_grffile->stations[stid];
 

	
 
				stat->spritegroup[0] = _cur_grffile->spritegroups[groupid];
 
				stat->spritegroup[0]->ref_count++;
 
				stat->grfid = _cur_grffile->grfid;
 
				SetCustomStation(stid, stat);
 
				stat->sclass = STAT_CLASS_NONE;
 
				stat->localidx = stid;
 
				SetCustomStation(stat);
 
			}
 
		}
 
		return;
 
	}
 

	
 

	
 
	/* If ``n-id'' (or ``idcount'') is zero, this is a ``feature
 
	 * callback''. I have no idea how this works, so we will ignore it for
 
	 * now.  --octo */
 
	if (idcount == 0) {
 
		grfmsg(GMS_NOTICE, "NewMapping: Feature callbacks not implemented yet.");
 
		return;
 
	}
 

	
 
	// FIXME: Tropicset contains things like:
 
	// 03 00 01 19 01 00 00 00 00 - this is missing one 00 at the end,
 
	// what should we exactly do with that? --pasky
 

	
 
	if (!_cur_grffile->spriteset_start || !_cur_grffile->spritegroups) {
 
		grfmsg(GMS_WARN, "VehicleMapSpriteGroup: No sprite set to work on! Skipping.");
 
		return;
 
	}
 

	
 
	if (!wagover && last_engines_count != idcount) {
 
		last_engines = realloc(last_engines, idcount);
 
		last_engines_count = idcount;
 
	}
 

	
 
	if (wagover) {
 
		if (last_engines_count == 0) {
 
			grfmsg(GMS_ERROR, "VehicleMapSpriteGroup: WagonOverride: No engine to do override with.");
 
			return;
 
		}
 
		DEBUG(grf, 6) ("VehicleMapSpriteGroup: WagonOverride: %u engines, %u wagons.",
 
				last_engines_count, idcount);
 
	}
 

	
 

	
 
	for (i = 0; i < idcount; i++) {
 
		uint8 engine_id = buf[3 + i];
 
		uint8 engine = engine_id + _vehshifts[feature];
 
		byte *bp = &buf[4 + idcount];
 

	
 
		if (engine_id > _vehcounts[feature]) {
 
			grfmsg(GMS_ERROR, "Id %u for feature %x is out of bounds.",
 
					engine_id, feature);
 
			return;
 
		}
 
@@ -2351,133 +2344,159 @@ static void InitializeGRFSpecial(void)
 
{
 
	/* FIXME: We should rather reflect reality in _ttdpatch_flags[]. */
 

	
 
	_ttdpatch_flags[0] = (1 << 0x1B); /* multihead */
 
	_ttdpatch_flags[1] = (1 << 0x08)  /* mammothtrains */
 
	                   | (1 << 0x0B)  /* subsidiaries */
 
	                   | (1 << 0x14)  /* bridgespeedlimits */
 
	                   | (1 << 0x16)  /* eternalgame */
 
	                   | (1 << 0x17)  /* newtrains */
 
	                   | (1 << 0x18)  /* newrvs */
 
	                   | (1 << 0x19)  /* newships */
 
	                   | (1 << 0x1A)  /* newplanes */
 
			               | (1 << 0x1B); /* signalsontrafficside */
 
	                   /* Uncomment following if you want to fool the GRF file.
 
	                    * Some GRF files will refuse to load without this
 
	                    * but you can still squeeze something from them even
 
	                    * without the support - i.e. USSet. --pasky */
 
			               //| (1 << 0x1C); /* electrifiedrailway */
 

	
 
	_ttdpatch_flags[2] = (1 << 0x0D)  /* buildonslopes */
 
	                   | (1 << 0x16)  /* canals */
 
	                   | (1 << 0x17)  /* newstartyear */
 
	                   | (_patches.wagon_speed_limits ? (1 << 0x1D) : 0); /* wagonspeedlimits */
 
}
 

	
 
/**
 
 * Unload unused sprite groups from the specified GRF file.
 
 * Called after loading each GRF file.
 
 * @param file GRF file
 
 */
 
static void ReleaseSpriteGroups(GRFFile *file)
 
{
 
	int i;
 

	
 
	// Bail out if no spritegroups were defined.
 
	if (file->spritegroups == NULL)
 
		return;
 

	
 
	DEBUG(grf, 6)("ReleaseSpriteGroups: Releasing for `%s'.", file->filename);
 
	for (i = 0; i < file->spritegroups_count; i++) {
 
		if (file->spritegroups[i] != NULL)
 
			UnloadSpriteGroup(&file->spritegroups[i]);
 
	}
 
	free(file->spritegroups);
 
	file->spritegroups = NULL;
 
	file->spritegroups_count = 0;
 
}
 

	
 
static void ResetCustomStations(void)
 
{
 
	GRFFile *file;
 
	int i;
 
	CargoID c;
 

	
 
	for (file = _first_grffile; file != NULL; file = file->next) {
 
		for (i = 0; i < 256; i++) {
 
			if (file->stations[i].grfid != file->grfid)
 
				continue;
 

	
 
			// TODO: Release renderdata, platforms and layouts
 

	
 
			// Release this stations sprite groups.
 
			for (c = 0; c < NUM_GLOBAL_CID; c++) {
 
				if (file->stations[i].spritegroup[c] != NULL)
 
					UnloadSpriteGroup(&file->stations[i].spritegroup[c]);
 
			}
 
		}
 
	}
 
}
 

	
 
/**
 
 * Reset all NewGRF loaded data
 
 * TODO
 
 */
 
static void ResetNewGRFData(void)
 
{
 
	int i;
 

	
 
	// Copy/reset original engine info data
 
	memcpy(&_engine_info, &orig_engine_info, sizeof(orig_engine_info));
 
	memcpy(&_rail_vehicle_info, &orig_rail_vehicle_info, sizeof(orig_rail_vehicle_info));
 
	memcpy(&_ship_vehicle_info, &orig_ship_vehicle_info, sizeof(orig_ship_vehicle_info));
 
	memcpy(&_aircraft_vehicle_info, &orig_aircraft_vehicle_info, sizeof(orig_aircraft_vehicle_info));
 
	memcpy(&_road_vehicle_info, &orig_road_vehicle_info, sizeof(orig_road_vehicle_info));
 

	
 
	// Copy/reset original bridge info data
 
	// First, free sprite table data
 
	for (i = 0; i < MAX_BRIDGES; i++) {
 
		if (_bridge[i].sprite_table != NULL) {
 
			byte j;
 
			for (j = 0; j < 7; j++)
 
				free(_bridge[i].sprite_table[j]);
 
			free(_bridge[i].sprite_table);
 
		}
 
	}
 
	memcpy(&_bridge, &orig_bridge, sizeof(_bridge));
 

	
 
	// Reset refit/cargo class data
 
	memset(&cargo_allowed, 0, sizeof(cargo_allowed));
 
	memset(&cargo_disallowed, 0, sizeof(cargo_disallowed));
 

	
 
	// Unload sprite group data
 
	UnloadWagonOverrides();
 
	UnloadCustomEngineSprites();
 

	
 
	// Reset price base data
 
	ResetPriceBaseMultipliers();
 

	
 
	// Reset station classes
 
	ResetStationClasses();
 
	ResetCustomStations();
 
}
 

	
 
static void InitNewGRFFile(const char* filename, int sprite_offset)
 
{
 
	GRFFile *newfile;
 

	
 
	newfile = GetFileByFilename(filename);
 
	if (newfile != NULL) {
 
		/* We already loaded it once. */
 
		newfile->sprite_offset = sprite_offset;
 
		_cur_grffile = newfile;
 
		return;
 
	}
 

	
 
	newfile = calloc(1, sizeof(*newfile));
 

	
 
	if (newfile == NULL)
 
		error ("Out of memory");
 

	
 
	newfile->filename = strdup(filename);
 
	newfile->sprite_offset = sprite_offset;
 

	
 
	if (_first_grffile == NULL) {
 
		_cur_grffile = newfile;
 
		_first_grffile = newfile;
 
	} else {
 
		_cur_grffile->next = newfile;
 
		_cur_grffile = newfile;
 
	}
 
}
 

	
 
/**
 
 * Precalculate refit masks from cargo classes for all vehicles.
 
 */
 
static void CalculateRefitMasks(void)
 
{
 
	EngineID engine;
 

	
 
	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
 
		uint32 mask = 0;
 
		uint32 not_mask = 0;
 
		uint32 xor_mask = _engine_info[engine].refit_mask;
 
		byte i;
 

	
 
		if (cargo_allowed[engine] != 0) {
 
			// Build up the list of cargo types from the set cargo classes.
 
			for (i = 0; i < lengthof(cargo_classes); i++) {
 
				if (HASBIT(cargo_allowed[engine], i))
newgrf.h
Show inline comments
 
/* $Id$ */
 

	
 
#ifndef NEWGRF_H
 
#define NEWGRF_H
 

	
 
#include "sprite.h"
 
#include "station.h"
 

	
 
typedef struct GRFFile GRFFile;
 
struct GRFFile {
 
	char *filename;
 
	uint32 grfid;
 
	uint16 flags;
 
	uint16 sprite_offset;
 
	SpriteID first_spriteset; ///< Holds the first spriteset's sprite offset.
 
	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. */
 

	
 
	int spriteset_start;
 
	int spriteset_numsets;
 
	int spriteset_numents;
 
	int spriteset_feature;
 

	
 
	int spritegroups_count;
 
	SpriteGroup **spritegroups;
 

	
 
	StationSpec stations[256];
 

	
 
	uint32 param[0x80];
 
	uint param_end; /// one more than the highest set parameter
 
};
 

	
 
extern int _grffile_count;
 
extern GRFFile *_first_grffile;
 

	
 

	
 
void LoadNewGRF(uint load_index, uint file_index);
 

	
 
#endif /* NEWGRF_H */
rail_gui.c
Show inline comments
 
@@ -82,97 +82,97 @@ static void PlaceRail_AutoRail(TileIndex
 
{
 
	VpStartPlaceSizing(tile, VPM_RAILDIRS);
 
}
 

	
 
static void PlaceExtraDepotRail(TileIndex tile, uint16 extra)
 
{
 
	byte b = _m[tile].m5;
 

	
 
	if (b & 0xC0 || !(b & (extra >> 8)))
 
		return;
 

	
 
	DoCommandP(tile, _cur_railtype, extra & 0xFF, NULL, CMD_BUILD_SINGLE_RAIL | CMD_AUTO | CMD_NO_WATER);
 
}
 

	
 
static const uint16 _place_depot_extra[12] = {
 
	0x604,		0x2102,		0x1202,		0x505,
 
	0x2400,		0x2801,		0x1800,		0x1401,
 
	0x2203,		0x904,		0x0A05,		0x1103,
 
};
 

	
 

	
 
void CcRailDepot(bool success, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	if (success) {
 
		int dir = p2;
 

	
 
		SndPlayTileFx(SND_20_SPLAT_2, tile);
 
		ResetObjectToPlace();
 

	
 
		tile += TileOffsByDir(dir);
 

	
 
		if (IsTileType(tile, MP_RAILWAY)) {
 
			PlaceExtraDepotRail(tile, _place_depot_extra[dir]);
 
			PlaceExtraDepotRail(tile, _place_depot_extra[dir + 4]);
 
			PlaceExtraDepotRail(tile, _place_depot_extra[dir + 8]);
 
		}
 
	}
 
}
 

	
 
static void PlaceRail_Depot(TileIndex tile)
 
{
 
	DoCommandP(tile, _cur_railtype, _build_depot_direction, CcRailDepot,
 
		CMD_BUILD_TRAIN_DEPOT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_100E_CAN_T_BUILD_TRAIN_DEPOT));
 
}
 

	
 
static void PlaceRail_Waypoint(TileIndex tile)
 
{
 
	if (!_remove_button_clicked) {
 
		DoCommandP(tile, (_waypoint_count > 0) ? (0x100 + _cur_waypoint_type) : 0, 0, CcPlaySound1E, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT));
 
		DoCommandP(tile, _cur_waypoint_type, 0, CcPlaySound1E, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT));
 
	} else {
 
		DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_REMOVE_TRAIN_WAYPOINT));
 
	}
 
}
 

	
 
void CcStation(bool success, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	if (success) {
 
		SndPlayTileFx(SND_20_SPLAT_2, tile);
 
		ResetObjectToPlace();
 
	}
 
}
 

	
 
static void PlaceRail_Station(TileIndex tile)
 
{
 
	if(_remove_button_clicked)
 
		DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_FROM_RAILROAD_STATION | CMD_MSG(STR_CANT_REMOVE_PART_OF_STATION));
 
	else if (_railstation.dragdrop) {
 
		VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED);
 
		VpSetPlaceSizingLimit(_patches.station_spread);
 
	} else {
 
		// TODO: Custom station selector GUI. Now we just try using first custom station
 
		// (and fall back to normal stations if it isn't available).
 
		DoCommandP(tile, _railstation.orientation | (_railstation.numtracks<<8) | (_railstation.platlength<<16),_cur_railtype|1<<4, CcStation,
 
				CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
 
	}
 
}
 

	
 
static void GenericPlaceSignals(TileIndex tile)
 
{
 
	uint trackstat;
 
	int i;
 

	
 
	trackstat = (byte)GetTileTrackStatus(tile, TRANSPORT_RAIL);
 

	
 
	if ((trackstat & 0x30)) // N-S direction
 
		trackstat = (_tile_fract_coords.x <= _tile_fract_coords.y) ? 0x20 : 0x10;
 

	
 
	if ((trackstat & 0x0C)) // E-W direction
 
		trackstat = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? 4 : 8;
 

	
 
	// Lookup the bit index
 
	i = 0;
 
	if (trackstat != 0) {	while (!(trackstat & 1)) { i++; trackstat >>= 1; }}
 

	
 
	if (!_remove_button_clicked) {
 
		DoCommandP(tile, i + (_ctrl_pressed ? 8 : 0), 0, CcPlaySound1E,
 
			CMD_BUILD_SIGNALS | CMD_AUTO | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE));
 
@@ -212,99 +212,99 @@ static void PlaceRail_ConvertRail(TileIn
 
{
 
	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_ConvertRailArea);
 
}
 

	
 
static void PlaceRail_AutoSignals(TileIndex tile)
 
{
 
	VpStartPlaceSizing(tile, VPM_SIGNALDIRS);
 
}
 

	
 
static void BuildRailClick_N(Window *w)
 
{
 
	HandlePlacePushButton(w, 4, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, 1, PlaceRail_N);
 
}
 

	
 
static void BuildRailClick_NE(Window *w)
 
{
 
	HandlePlacePushButton(w, 5, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, 1, PlaceRail_NE);
 
}
 

	
 
static void BuildRailClick_E(Window *w)
 
{
 
	HandlePlacePushButton(w, 6, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, 1, PlaceRail_E);
 
}
 

	
 
static void BuildRailClick_NW(Window *w)
 
{
 
	HandlePlacePushButton(w, 7, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, 1, PlaceRail_NW);
 
}
 

	
 
static void BuildRailClick_AutoRail(Window *w)
 
{
 
	HandlePlacePushButton(w, 8, GetRailTypeInfo(_cur_railtype)->cursor.autorail, VHM_RAIL, PlaceRail_AutoRail);
 
}
 

	
 
static void BuildRailClick_Demolish(Window *w)
 
{
 
	HandlePlacePushButton(w, 9, ANIMCURSOR_DEMOLISH, 1, PlaceProc_DemolishArea);
 
}
 

	
 
static void BuildRailClick_Depot(Window *w)
 
{
 
	if (HandlePlacePushButton(w, 10, GetRailTypeInfo(_cur_railtype)->cursor.depot, 1, PlaceRail_Depot)) {
 
		ShowBuildTrainDepotPicker();
 
	}
 
}
 

	
 
static void BuildRailClick_Waypoint(Window *w)
 
{
 
	_waypoint_count = GetCustomStationsCount(STAT_CLASS_WAYP);
 
	_waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP);
 
	if (HandlePlacePushButton(w, 11, SPR_CURSOR_WAYPOINT, 1, PlaceRail_Waypoint)
 
	    && _waypoint_count > 0)
 
			&& _waypoint_count > 1)
 
		ShowBuildWaypointPicker();
 
}
 

	
 
static void BuildRailClick_Station(Window *w)
 
{
 
	if (HandlePlacePushButton(w, 12, SPR_CURSOR_RAIL_STATION, 1, PlaceRail_Station)) ShowStationBuilder();
 
}
 

	
 
static void BuildRailClick_AutoSignals(Window *w)
 
{
 
	HandlePlacePushButton(w, 13, ANIMCURSOR_BUILDSIGNALS, VHM_RECT, PlaceRail_AutoSignals);
 
}
 

	
 
static void BuildRailClick_Bridge(Window *w)
 
{
 
	HandlePlacePushButton(w, 14, SPR_CURSOR_BRIDGE, 1, PlaceRail_Bridge);
 
}
 

	
 
static void BuildRailClick_Tunnel(Window *w)
 
{
 
	HandlePlacePushButton(w, 15, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, 3, PlaceRail_Tunnel);
 
}
 

	
 
static void BuildRailClick_Remove(Window *w)
 
{
 
	if (w->disabled_state & (1<<16))
 
		return;
 
	SetWindowDirty(w);
 
	SndPlayFx(SND_15_BEEP);
 

	
 
	w->click_state ^= (1 << 16);
 
	_remove_button_clicked = (w->click_state & (1 << 16)) != 0;
 
	SetSelectionRed((w->click_state & (1 << 16)) != 0);
 

	
 
	// handle station builder
 
	if( w->click_state & (1 << 16) )
 
	{
 
		if(_remove_button_clicked)
 
			SetTileSelectSize(1, 1);
 
		else
 
			BringWindowToFrontById(WC_BUILD_STATION, 0);
 
	}
 
}
 

	
 
static void BuildRailClick_Convert(Window *w)
 
{
 
	HandlePlacePushButton(w, 17, GetRailTypeInfo(_cur_railtype)->cursor.convert, 1, PlaceRail_ConvertRail);
 
}
 
@@ -784,119 +784,119 @@ static void BuildTrainDepotWndProc(Windo
 
			_build_depot_direction = e->click.widget - 3;
 
			SndPlayFx(SND_15_BEEP);
 
			SetWindowDirty(w);
 
			break;
 
		}
 
	} break;
 

	
 
	case WE_MOUSELOOP:
 
		if (WP(w,def_d).close)
 
			DeleteWindow(w);
 
		return;
 

	
 
	case WE_DESTROY:
 
		if (!WP(w,def_d).close)
 
			ResetObjectToPlace();
 
		break;
 
	}
 
}
 

	
 
static const Widget _build_depot_widgets[] = {
 
{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_1014_TRAIN_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   121, 0x0,			STR_NULL},
 
{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,			STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
 
{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,			STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
 
{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,			STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
 
{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,			STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
 
{   WIDGETS_END},
 
};
 

	
 
static const WindowDesc _build_depot_desc = {
 
	-1,-1, 140, 122,
 
	WC_BUILD_DEPOT,WC_BUILD_TOOLBAR,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 
	_build_depot_widgets,
 
	BuildTrainDepotWndProc
 
};
 

	
 
static void ShowBuildTrainDepotPicker(void)
 
{
 
	AllocateWindowDesc(&_build_depot_desc);
 
}
 

	
 

	
 
static void BuildWaypointWndProc(Window *w, WindowEvent *e)
 
{
 
	switch (e->event) {
 
	case WE_PAINT: {
 
		int i;
 
		w->click_state = (1 << 3) << (_cur_waypoint_type - w->hscroll.pos);
 
		DrawWindowWidgets(w);
 

	
 
		if(w->hscroll.pos + 0 <= _waypoint_count) DrawWaypointSprite(2,   25, w->hscroll.pos + 0, _cur_railtype);
 
		if(w->hscroll.pos + 1 <= _waypoint_count) DrawWaypointSprite(70,  25, w->hscroll.pos + 1, _cur_railtype);
 
		if(w->hscroll.pos + 2 <= _waypoint_count) DrawWaypointSprite(138, 25, w->hscroll.pos + 2, _cur_railtype);
 
		if(w->hscroll.pos + 3 <= _waypoint_count) DrawWaypointSprite(206, 25, w->hscroll.pos + 3, _cur_railtype);
 
		if(w->hscroll.pos + 4 <= _waypoint_count) DrawWaypointSprite(274, 25, w->hscroll.pos + 4, _cur_railtype);
 
		for (i = 0; i < 5; i++)
 
			if(w->hscroll.pos + i < _waypoint_count)
 
				DrawWaypointSprite(2 + i * 68, 25, w->hscroll.pos + i, _cur_railtype);
 

	
 
		break;
 
	}
 
	case WE_CLICK: {
 
		switch (e->click.widget) {
 
		case 3: case 4: case 5: case 6: case 7:
 
			_cur_waypoint_type = e->click.widget - 3 + w->hscroll.pos;
 
			SndPlayFx(SND_15_BEEP);
 
			SetWindowDirty(w);
 
			break;
 
		}
 
		break;
 
	}
 

	
 
	case WE_MOUSELOOP:
 
		if (WP(w,def_d).close)
 
			DeleteWindow(w);
 
		break;
 

	
 
	case WE_DESTROY:
 
		if (!WP(w,def_d).close)
 
			ResetObjectToPlace();
 
		break;
 
	}
 
}
 

	
 
static const Widget _build_waypoint_widgets[] = {
 
{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5, STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   343,     0,    13, STR_WAYPOINT,STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{      WWT_PANEL,   RESIZE_NONE,     7,     0,   343,    14,    91, 0x0, 0},
 

	
 
{      WWT_PANEL,   RESIZE_NONE,     7,     3,    68,    17,    76, 0x0, STR_WAYPOINT_GRAPHICS_TIP},
 
{      WWT_PANEL,   RESIZE_NONE,     7,    71,   136,    17,    76, 0x0, STR_WAYPOINT_GRAPHICS_TIP},
 
{      WWT_PANEL,   RESIZE_NONE,     7,   139,   204,    17,    76, 0x0, STR_WAYPOINT_GRAPHICS_TIP},
 
{      WWT_PANEL,   RESIZE_NONE,     7,   207,   272,    17,    76, 0x0, STR_WAYPOINT_GRAPHICS_TIP},
 
{      WWT_PANEL,   RESIZE_NONE,     7,   275,   340,    17,    76, 0x0, STR_WAYPOINT_GRAPHICS_TIP},
 

	
 
{ WWT_HSCROLLBAR,   RESIZE_NONE,    7,     1,   343,     80,    91, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{    WIDGETS_END},
 
};
 

	
 
static const WindowDesc _build_waypoint_desc = {
 
	-1,-1, 344, 92,
 
	WC_BUILD_DEPOT,WC_BUILD_TOOLBAR,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 
	_build_waypoint_widgets,
 
	BuildWaypointWndProc
 
};
 

	
 
static void ShowBuildWaypointPicker(void)
 
{
 
	Window *w = AllocateWindowDesc(&_build_waypoint_desc);
 
	w->hscroll.cap = 5;
 
	w->hscroll.count = _waypoint_count + 1;
 
	w->hscroll.count = _waypoint_count;
 
}
 

	
 

	
 
void InitializeRailGui(void)
 
{
 
	_build_depot_direction = 3;
 
	_railstation.numtracks = 1;
 
	_railstation.platlength = 1;
 
	_railstation.dragdrop = true;
 
}
station.h
Show inline comments
 
/* $Id$ */
 

	
 
#ifndef STATION_H
 
#define STATION_H
 

	
 
#include "player.h"
 
#include "pool.h"
 
#include "sprite.h"
 
#include "tile.h"
 
#include "vehicle.h"
 
#include "station_newgrf.h"
 

	
 
typedef struct GoodsEntry {
 
	uint16 waiting_acceptance;
 
	byte days_since_pickup;
 
	byte rating;
 
	uint16 enroute_from;
 
	byte enroute_time;
 
	byte last_speed;
 
	byte last_age;
 
	int32 feeder_profit;
 
} GoodsEntry;
 

	
 
typedef enum RoadStopType {
 
	RS_BUS,
 
	RS_TRUCK
 
} RoadStopType;
 

	
 
enum {
 
	INVALID_STATION = 0xFFFF,
 
	INVALID_SLOT = 0xFFFF,
 
	NUM_SLOTS = 2,
 
	ROAD_STOP_LIMIT = 8,
 
};
 

	
 
typedef uint16 StationID;
 

	
 
typedef struct RoadStop {
 
	TileIndex xy;
 
	bool used;
 
	byte status;
 
	uint32 index;
 
	uint16 slot[NUM_SLOTS];
 
	StationID station;
 
	uint8 type;
 
	struct RoadStop *next;
 
	struct RoadStop *prev;
 
} RoadStop;
 

	
 
struct Station {
 
	TileIndex xy;
 
	RoadStop *bus_stops;
 
	RoadStop *truck_stops;
 
	TileIndex train_tile;
 
	TileIndex airport_tile;
 
	TileIndex dock_tile;
 
	Town *town;
 
	uint16 string_id;
 

	
 
@@ -150,173 +151,100 @@ static inline uint16 GetStationPoolSize(
 
	return _station_pool.total_items;
 
}
 

	
 
static inline bool IsStationIndex(uint index)
 
{
 
	return index < GetStationPoolSize();
 
}
 

	
 
#define FOR_ALL_STATIONS_FROM(st, start) for (st = GetStation(start); st != NULL; st = (st->index + 1 < GetStationPoolSize()) ? GetStation(st->index + 1) : NULL)
 
#define FOR_ALL_STATIONS(st) FOR_ALL_STATIONS_FROM(st, 0)
 

	
 

	
 
/* Stuff for ROADSTOPS */
 

	
 
extern MemoryPool _roadstop_pool;
 

	
 
/**
 
 * Get the pointer to the roadstop with index 'index'
 
 */
 
static inline RoadStop *GetRoadStop(uint index)
 
{
 
	return (RoadStop*)GetItemFromPool(&_roadstop_pool, index);
 
}
 

	
 
/**
 
 * Get the current size of the RoadStoptPool
 
 */
 
static inline uint16 GetRoadStopPoolSize(void)
 
{
 
	return _roadstop_pool.total_items;
 
}
 

	
 
#define FOR_ALL_ROADSTOPS_FROM(rs, start) for (rs = GetRoadStop(start); rs != NULL; rs = (rs->index + 1 < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1) : NULL)
 
#define FOR_ALL_ROADSTOPS(rs) FOR_ALL_ROADSTOPS_FROM(rs, 0)
 

	
 
/* End of stuff for ROADSTOPS */
 

	
 

	
 
VARDEF bool _station_sort_dirty[MAX_PLAYERS];
 
VARDEF bool _global_station_sort_dirty;
 

	
 
void GetProductionAroundTiles(AcceptedCargo produced, TileIndex tile, int w, int h, int rad);
 
void GetAcceptanceAroundTiles(AcceptedCargo accepts, TileIndex tile, int w, int h, int rad);
 
uint GetStationPlatforms(const Station *st, TileIndex tile);
 

	
 

	
 
void StationPickerDrawSprite(int x, int y, RailType railtype, int image);
 

	
 

	
 
/* Station layout for given dimensions - it is a two-dimensional array
 
 * where index is computed as (x * platforms) + platform. */
 
typedef byte *StationLayout;
 

	
 
typedef enum StationClass {
 
	STAT_CLASS_NONE, // unused station slot or so
 
	STAT_CLASS_DFLT, // default station class
 
	STAT_CLASS_WAYP, // waypoints
 

	
 
	/* TODO: When we actually support custom classes, they are
 
	 * going to be allocated dynamically (with some classid->sclass
 
	 * mapping, there's a TTDPatch limit on 16 custom classes in
 
	 * the whole game at the same time) with base at
 
	 * STAT_CLASS_CUSTOM. --pasky */
 
	STAT_CLASS_CUSTOM, // some custom class
 
} StationClass;
 

	
 
typedef struct StationSpec {
 
	uint32 grfid;
 
	int localidx; // per-GRFFile station index + 1; SetCustomStation() takes care of this
 

	
 
	StationClass sclass;
 

	
 
	/* Bitmask of platform numbers/lengths available for the station.  Bits
 
	 * 0..6 correspond to 1..7, while bit 7 corresponds to >7 platforms or
 
	 * lenght. */
 
	byte allowed_platforms;
 
	byte allowed_lengths;
 

	
 
	/* Custom sprites */
 
	byte tiles;
 
	/* 00 = plain platform
 
	 * 02 = platform with building
 
	 * 04 = platform with roof, left side
 
	 * 06 = platform with roof, right side
 
	 *
 
	 * These numbers are used for stations in NE-SW direction, or these
 
	 * numbers plus one for stations in the NW-SE direction.  */
 
	DrawTileSprites renderdata[8];
 

	
 
	/* Custom layouts */
 
	/* The layout array is organized like [lenghts][platforms], both being
 
	 * dynamic arrays, the field itself is length*platforms array containing
 
	 * indexes to @renderdata (only even numbers allowed) for the given
 
	 * station tile. */
 
	/* @lengths is length of the @platforms and @layouts arrays, that is
 
	 * number of maximal length for which the layout is defined (since
 
	 * arrays are indexed from 0, the length itself is at [length - 1]). */
 
	byte lengths;
 
	/* @platforms is array of number of platforms defined for each length.
 
	 * Zero means no platforms defined. */
 
	byte *platforms;
 
	/* @layout is @layouts-sized array of @platforms-sized arrays,
 
	 * containing pointers to length*platforms-sized arrays or NULL if
 
	 * default OTTD station layout should be used for stations of these
 
	 * dimensions. */
 
	StationLayout **layouts;
 

	
 
	/* Sprite offsets for renderdata->seq->image. spritegroup[0] is default
 
	 * whilst spritegroup[1] is "GC_PURCHASE". */
 
	SpriteGroup *spritegroup[2];
 
} StationSpec;
 

	
 
/* Here, @stid is local per-GRFFile station index. If spec->localidx is not yet
 
 * set, it gets new dynamically allocated global index and spec->localidx is
 
 * set to @stid, otherwise we take it as that we are replacing it and try to
 
 * search for it first (that isn't much fast but we do it only very seldom). */
 
void SetCustomStation(byte stid, StationSpec *spec);
 
/* Here, @stid is global station index (in continous range 0..GetCustomStationsCount())
 
 * (lookup is therefore very fast as we do this very frequently). */
 
StationSpec *GetCustomStation(StationClass sclass, byte stid);
 
/* Get sprite offset for a given custom station and station structure (may be
 
 * NULL if ctype is set - that means we are in a build dialog). The station
 
 * structure is used for variational sprite groups. */
 
uint32 GetCustomStationRelocation(const StationSpec *spec, const Station *st, byte ctype);
 
int GetCustomStationsCount(StationClass sclass);
 

	
 
RoadStop * GetRoadStopByTile(TileIndex tile, RoadStopType type);
 
static inline int GetRoadStopType(TileIndex tile)
 
{
 
	return (_m[tile].m5 < 0x47) ? RS_TRUCK : RS_BUS;
 
}
 

	
 
uint GetNumRoadStops(const Station *st, RoadStopType type);
 
RoadStop * GetPrimaryRoadStop(const Station *st, RoadStopType type);
 
RoadStop * AllocateRoadStop( void );
 
void ClearSlot(Vehicle *v, RoadStop *rs);
 

	
 
static inline bool IsTrainStationTile(TileIndex tile)
 
{
 
	return IsTileType(tile, MP_STATION) && IS_BYTE_INSIDE(_m[tile].m5, 0, 8);
 
}
 

	
 
static inline bool IsCompatibleTrainStationTile(TileIndex tile, TileIndex ref)
 
{
 
	assert(IsTrainStationTile(ref));
 
	return
 
		IsTrainStationTile(tile) &&
 
		(_m[tile].m3 & 0x0F) == (_m[ref].m3 & 0x0F) && // same rail type?
 
		(_m[tile].m5 & 0x01) == (_m[ref].m5 & 0x01); // same direction?
 
}
 

	
 
static inline bool IsRoadStationTile(TileIndex tile) {
 
	return IsTileType(tile, MP_STATION) && IS_BYTE_INSIDE(_m[tile].m5, 0x43, 0x4B);
 
}
 

	
 
/**
 
 * Check if a station really exists.
 
 */
 
static inline bool IsValidStation(const Station *st)
 
{
 
	return st->xy != 0; /* XXX: Replace by INVALID_TILE someday */
 
}
 

	
 
static inline bool IsBuoy(const Station* st)
 
{
 
	return st->had_vehicle_of_type & HVOT_BUOY; /* XXX: We should really ditch this ugly coding and switch to something sane... */
 
}
 

	
 
static inline bool IsBuoyTile(TileIndex tile)
 
{
 
	return IsTileType(tile, MP_STATION) && _m[tile].m5 == 0x52;
 
}
 

	
station_cmd.c
Show inline comments
 
@@ -1154,150 +1154,96 @@ int32 CmdRemoveFromRailroadStation(int x
 
	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 

	
 
	// make sure the specified tile belongs to the current player, and that it is a railroad station.
 
	if (!IsTileType(tile, MP_STATION) || _m[tile].m5 >= 8 || !_patches.nonuniform_stations) return CMD_ERROR;
 
	st = GetStation(_m[tile].m2);
 
	if (_current_player != OWNER_WATER && (!CheckOwnership(st->owner) || !EnsureNoVehicle(tile))) return CMD_ERROR;
 

	
 
	// if we reached here, it means we can actually delete it. do that.
 
	if (flags & DC_EXEC) {
 
		DoClearSquare(tile);
 
		// now we need to make the "spanned" area of the railway station smaller if we deleted something at the edges.
 
		// we also need to adjust train_tile.
 
		MakeRailwayStationAreaSmaller(st);
 

	
 
		// if we deleted the whole station, delete the train facility.
 
		if (st->train_tile == 0) {
 
			st->facilities &= ~FACIL_TRAIN;
 
			UpdateStationVirtCoordDirty(st);
 
			DeleteStationIfEmpty(st);
 
		}
 
	}
 
	return _price.remove_rail_station;
 
}
 

	
 
// determine the number of platforms for the station
 
uint GetStationPlatforms(const Station *st, TileIndex tile)
 
{
 
	TileIndex t;
 
	TileIndexDiff delta;
 
	int dir;
 
	int len;
 
	assert(TileBelongsToRailStation(st, tile));
 

	
 
	len = 0;
 
	dir = _m[tile].m5&1;
 
	delta = dir ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
 

	
 
	// find starting tile..
 
	t = tile;
 
	do { t -= delta; len++; } while (TileBelongsToRailStation(st, t) && (_m[t].m5&1) == dir);
 

	
 
	// find ending tile
 
	t = tile;
 
	do { t += delta; len++; }while (TileBelongsToRailStation(st, t) && (_m[t].m5&1) == dir);
 

	
 
	return len - 1;
 
}
 

	
 

	
 
/* TODO: Custom classes! */
 
/* Indexed by class, just STAT_CLASS_DFLT and STAT_CLASS_WAYP supported. */
 
static int _statspec_highest_id[2] = {-1, -1};
 
static StationSpec _station_spec[2][256];
 

	
 
void SetCustomStation(byte local_stid, StationSpec *spec)
 
{
 
	StationClass sclass;
 
	int stid = -1;
 

	
 
	assert(spec->sclass == STAT_CLASS_DFLT || spec->sclass == STAT_CLASS_WAYP);
 
	sclass = spec->sclass - 1;
 

	
 
	if (spec->localidx != 0) {
 
		/* Already allocated, try to resolve to global stid */
 
		int i;
 

	
 
		for (i = 0; i <= _statspec_highest_id[sclass]; i++) {
 
			if (_station_spec[sclass][i].grfid == spec->grfid &&
 
					_station_spec[sclass][i].localidx == local_stid + 1) {
 
				stid = i;
 
				/* FIXME: Release original SpriteGroup to
 
				 * prevent leaks. But first we need to
 
				 * refcount the SpriteGroup. --pasky */
 
				break;
 
			}
 
		}
 
	}
 

	
 
	if (stid == -1) {
 
		/* Allocate new one. */
 
		if (_statspec_highest_id[sclass] >= 255) {
 
			error("Too many custom stations allocated.");
 
			return;
 
		}
 
		stid = ++_statspec_highest_id[sclass];
 
		spec->localidx = local_stid + 1;
 
	}
 

	
 
	//debug("Registering station #%d of class %d", stid, sclass);
 
	memcpy(&_station_spec[sclass][stid], spec, sizeof(*spec));
 
}
 

	
 
StationSpec *GetCustomStation(StationClass sclass, byte stid)
 
{
 
	assert(sclass == STAT_CLASS_DFLT || sclass == STAT_CLASS_WAYP);
 
	sclass--;
 
	//debug("Asking for station #%d of class %d", stid, sclass);
 
	if (stid > _statspec_highest_id[sclass])
 
		return NULL;
 
	return &_station_spec[sclass][stid];
 
}
 

	
 
static const RealSpriteGroup *ResolveStationSpriteGroup(const SpriteGroup *spg, const Station *st)
 
{
 
	switch (spg->type) {
 
		case SGT_REAL:
 
			return &spg->g.real;
 

	
 
		case SGT_DETERMINISTIC: {
 
			const DeterministicSpriteGroup *dsg = &spg->g.determ;
 
			SpriteGroup *target;
 
			int value = -1;
 

	
 
			if ((dsg->variable >> 6) == 0) {
 
				/* General property */
 
				value = GetDeterministicSpriteValue(dsg->variable);
 

	
 
			} else {
 
				if (st == NULL) {
 
					/* We are in a build dialog of something,
 
					 * and we are checking for something undefined.
 
					 * That means we should get the first target
 
					 * (NOT the default one). */
 
					if (dsg->num_ranges > 0) {
 
						target = dsg->ranges[0].group;
 
					} else {
 
						target = dsg->default_group;
 
					}
 
					return ResolveStationSpriteGroup(target, NULL);
 
				}
 

	
 
				/* Station-specific property. */
 
				if (dsg->var_scope == VSG_SCOPE_PARENT) {
 
					/* TODO: Town structure. */
 

	
 
				} else /* VSG_SELF */ {
 
					if (dsg->variable == 0x40 || dsg->variable == 0x41) {
 
						/* FIXME: This is ad hoc only
 
						 * for waypoints. */
 
						value = 0x01010000;
 
					} else {
 
						/* TODO: Only small fraction done. */
 
						// TTDPatch runs on little-endian arch;
 
						// Variable is 0x70 + offset in the TTD's station structure
 
						switch (dsg->variable - 0x70) {
 
							case 0x80:
 
								value = st->facilities;
 
								break;
 
							case 0x81:
 
								value = st->airport_type;
 
@@ -1306,104 +1252,96 @@ static const RealSpriteGroup *ResolveSta
 
								value = st->truck_stops->status;
 
								break;
 
							case 0x83:
 
								value = st->bus_stops->status;
 
								break;
 
							case 0x86:
 
								value = st->airport_flags & 0xFFFF;
 
								break;
 
							case 0x87:
 
								value = st->airport_flags & 0xFF;
 
								break;
 
							case 0x8A:
 
								value = st->build_date;
 
								break;
 
						}
 
					}
 
				}
 
			}
 

	
 
			target = value != -1 ? EvalDeterministicSpriteGroup(dsg, value) : dsg->default_group;
 
			return ResolveStationSpriteGroup(target, st);
 
		}
 

	
 
		default:
 
		case SGT_RANDOMIZED:
 
			error("I don't know how to handle random spritegroups yet!");
 
			return NULL;
 
	}
 
}
 

	
 
uint32 GetCustomStationRelocation(const StationSpec *spec, const Station *st, byte ctype)
 
{
 
	const RealSpriteGroup *rsg = ResolveStationSpriteGroup(spec->spritegroup[ctype], st);
 

	
 
	if (rsg->sprites_per_set != 0) {
 
		if (rsg->loading_count != 0) return rsg->loading[0]->g.result.result;
 

	
 
		if (rsg->loaded_count != 0) return rsg->loaded[0]->g.result.result;
 
	}
 

	
 
	error("Custom station 0x%08x::0x%02x has no sprites associated.",
 
		spec->grfid, spec->localidx);
 
	/* This is what gets subscribed of dtss->image in newgrf.c,
 
	 * so it's probably kinda "default offset". Try to use it as
 
	 * emergency measure. */
 
	return SPR_RAIL_PLATFORM_Y_FRONT;
 
}
 

	
 
int GetCustomStationsCount(StationClass sclass)
 
{
 
	assert(sclass == STAT_CLASS_DFLT || sclass == STAT_CLASS_WAYP);
 
	sclass--;
 
	return _statspec_highest_id[sclass] + 1;
 
}
 

	
 

	
 
static int32 RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags)
 
{
 
	int w,h;
 
	int32 cost;
 

	
 
	/* if there is flooding and non-uniform stations are enabled, remove platforms tile by tile */
 
	if (_current_player == OWNER_WATER && _patches.nonuniform_stations)
 
		return DoCommandByTile(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAILROAD_STATION);
 

	
 
	/* Current player owns the station? */
 
	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner))
 
		return CMD_ERROR;
 

	
 
	/* determine width and height of platforms */
 
	tile = st->train_tile;
 
	w = st->trainst_w;
 
	h = st->trainst_h;
 

	
 
	assert(w != 0 && h != 0);
 

	
 
	/* cost is area * constant */
 
	cost = w*h*_price.remove_rail_station;
 

	
 
	/* clear all areas of the station */
 
	do {
 
		int w_bak = w;
 
		do {
 
			// for nonuniform stations, only remove tiles that are actually train station tiles
 
			if (TileBelongsToRailStation(st, tile)) {
 
				if (!EnsureNoVehicle(tile))
 
					return CMD_ERROR;
 
				if (flags & DC_EXEC)
 
					DoClearSquare(tile);
 
			}
 
			tile += TileDiffXY(1, 0);
 
		} while (--w);
 
		w = w_bak;
 
		tile += TileDiffXY(-w, 1);
 
	} while (--h);
 

	
 
	if (flags & DC_EXEC) {
 
		st->train_tile = 0;
 
		st->facilities &= ~FACIL_TRAIN;
 

	
 
		UpdateStationVirtCoordDirty(st);
 
		DeleteStationIfEmpty(st);
 
	}
 

	
station_newgrf.c
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file station_newgrf.c Functions for dealing with station classes and custom stations. */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "debug.h"
 
#include "sprite.h"
 
#include "station_newgrf.h"
 

	
 
static StationClass station_classes[STAT_CLASS_MAX];
 

	
 
/**
 
 * Reset station classes to their default state.
 
 * This includes initialising the Default and Waypoint classes with an empty
 
 * entry, for standard stations and waypoints.
 
 */
 
void ResetStationClasses(void)
 
{
 
	StationClassID i;
 
	for (i = 0; i < STAT_CLASS_MAX; i++) {
 
		station_classes[i].id = 0;
 

	
 
		free(station_classes[i].name);
 
		station_classes[i].name = NULL;
 

	
 
		station_classes[i].stations = 0;
 

	
 
		free(station_classes[i].spec);
 
		station_classes[i].spec = NULL;
 
	}
 

	
 
	// Set up initial data
 
	station_classes[0].id = 'DFLT';
 
	station_classes[0].name = strdup("Default");
 
	station_classes[0].stations = 1;
 
	station_classes[0].spec = malloc(sizeof(*station_classes[0].spec));
 
	station_classes[0].spec[0] = NULL;
 

	
 
	station_classes[1].id = 'WAYP';
 
	station_classes[1].name = strdup("Waypoints");
 
	station_classes[1].stations = 1;
 
	station_classes[1].spec = malloc(sizeof(*station_classes[1].spec));
 
	station_classes[1].spec[0] = NULL;
 
}
 

	
 
/**
 
 * Allocate a station class for the given class id.
 
 * @param classid A 32 bit value identifying the class.
 
 * @return Index into station_classes of allocated class.
 
 */
 
StationClassID AllocateStationClass(uint32 class)
 
{
 
	StationClassID i;
 

	
 
	for (i = 0; i < STAT_CLASS_MAX; i++) {
 
		if (station_classes[i].id == class) {
 
			// ClassID is already allocated, so reuse it.
 
			return i;
 
		} else if (station_classes[i].id == 0) {
 
			// This class is empty, so allocate it to the ClassID.
 
			station_classes[i].id = class;
 
			return i;
 
		}
 
	}
 

	
 
	DEBUG(grf, 2)("StationClassAllocate: Already allocated %d classes, using default.", STAT_CLASS_MAX);
 
	return STAT_CLASS_DFLT;
 
}
 

	
 
/**
 
 * Return the number of stations for the given station class.
 
 * @param sclass Index of the station class.
 
 * @return Number of stations in the class.
 
 */
 
uint GetNumCustomStations(StationClassID sclass)
 
{
 
	assert(sclass < STAT_CLASS_MAX);
 
	return station_classes[sclass].stations;
 
}
 

	
 
/**
 
 * Tie a station spec to its station class.
 
 * @param spec The station spec.
 
 */
 
void SetCustomStation(StationSpec *spec)
 
{
 
	StationClass *station_class;
 
	int i;
 

	
 
	assert(spec->sclass < STAT_CLASS_MAX);
 
	station_class = &station_classes[spec->sclass];
 

	
 
	i = station_class->stations++;
 
	station_class->spec = realloc(station_class->spec, station_class->stations * sizeof(*station_class->spec));
 

	
 
	station_class->spec[i] = spec;
 
}
 

	
 
/**
 
 * Retrieve a station spec from a class.
 
 * @param sclass Index of the station class.
 
 * @param station The station index with the class.
 
 * @return The station spec.
 
 */
 
const StationSpec *GetCustomStation(StationClassID sclass, uint station)
 
{
 
	assert(sclass < STAT_CLASS_MAX);
 
	if (station < station_classes[sclass].stations)
 
		return station_classes[sclass].spec[station];
 

	
 
	// If the custom station isn't defined any more, then the GRF file
 
	// probably was not loaded.
 
	return NULL;
 
}
station_newgrf.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file station_newgrf.h Header file for NewGRF stations */
 

	
 
#ifndef STATION_NEWGRF_H
 
#define STATION_NEWGRF_H
 

	
 
#include "engine.h"
 

	
 
typedef enum {
 
	STAT_CLASS_DFLT,     ///< Default station class.
 
	STAT_CLASS_WAYP,     ///< Waypoint class.
 
	STAT_CLASS_MAX = 16, ///< Maximum number of classes.
 
} StationClassID;
 

	
 
/* Station layout for given dimensions - it is a two-dimensional array
 
 * where index is computed as (x * platforms) + platform. */
 
typedef byte *StationLayout;
 

	
 
typedef struct stationspec {
 
	uint32 grfid; ///< ID of GRF file station belongs to.
 
	int localidx; ///< Index within GRF file of station.
 

	
 
	StationClassID sclass; ///< The class to which this spec belongs.
 

	
 
	/**
 
	 * Bitmask of number of platforms available for the station.
 
	 * 0..6 correpsond to 1..7, while bit 7 corresponds to >7 platforms.
 
	 */
 
	byte allowed_platforms;
 
	/**
 
	 * Bitmask of platform lengths available for the station.
 
	 * 0..6 correpsond to 1..7, while bit 7 corresponds to >7 tiles long.
 
	 */
 
	byte allowed_lengths;
 

	
 
	/** Number of tile layouts.
 
	 * A minimum of 8 is required is required for stations.
 
	 * 0-1 = plain platform
 
	 * 2-3 = platform with building
 
	 * 4-5 = platform with roof, left side
 
	 * 6-7 = platform with roof, right side
 
	 */
 
	int tiles;
 
	DrawTileSprites *renderdata; ///< Array of tile layouts.
 

	
 
	byte lengths;
 
	byte *platforms;
 
	StationLayout **layouts;
 

	
 
	/**
 
	 * NUM_GLOBAL_CID sprite groups.
 
	 * Used for obtaining the sprite offset of custom sprites, and for
 
	 * evaluating callbacks.
 
	 */
 
	SpriteGroup *spritegroup[NUM_GLOBAL_CID];
 
} StationSpec;
 

	
 
/**
 
 * Struct containing information relating to station classes.
 
 */
 
typedef struct stationclass {
 
	uint32 id;          ///< ID of this class, e.g. 'DFLT', 'WAYP', etc.
 
	char *name;         ///< Name of this class.
 
	uint stations;      ///< Number of stations in this class.
 
	StationSpec **spec; ///< Array of station specifications.
 
} StationClass;
 

	
 
void ResetStationClasses(void);
 
StationClassID AllocateStationClass(uint32 class);
 
void SetStationClassName(StationClassID sclass, const char *name);
 
uint GetNumCustomStations(StationClassID sclass);
 

	
 
void SetCustomStation(StationSpec *spec);
 
const StationSpec *GetCustomStation(StationClassID sclass, uint station);
 

	
 
#endif /* STATION_NEWGRF_H */
waypoint.c
Show inline comments
 
@@ -109,146 +109,146 @@ void UpdateAllWaypointSigns(void)
 
void MakeDefaultWaypointName(Waypoint *wp)
 
{
 
	Waypoint *local_wp;
 
	bool used_waypoint[MAX_WAYPOINTS_PER_TOWN];
 
	int i;
 

	
 
	wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;
 

	
 
	memset(used_waypoint, 0, sizeof(used_waypoint));
 

	
 
	/* Find an unused waypoint number belonging to this town */
 
	FOR_ALL_WAYPOINTS(local_wp) {
 
		if (wp == local_wp)
 
			continue;
 

	
 
		if (local_wp->xy && local_wp->string == STR_NULL && local_wp->town_index == wp->town_index)
 
			used_waypoint[local_wp->town_cn] = true;
 
	}
 

	
 
	/* Find an empty spot */
 
	for (i = 0; used_waypoint[i] && i < MAX_WAYPOINTS_PER_TOWN; i++) {}
 

	
 
	wp->string = STR_NULL;
 
	wp->town_cn = i;
 
}
 

	
 
/* Find a deleted waypoint close to a tile. */
 
static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile)
 
{
 
	Waypoint *wp, *best = NULL;
 
	uint thres = 8, cur_dist;
 

	
 
	FOR_ALL_WAYPOINTS(wp) {
 
		if (wp->deleted && wp->xy) {
 
			cur_dist = DistanceManhattan(tile, wp->xy);
 
			if (cur_dist < thres) {
 
				thres = cur_dist;
 
				best = wp;
 
			}
 
		}
 
	}
 

	
 
	return best;
 
}
 

	
 
/** Convert existing rail to waypoint. Eg build a waypoint station over
 
 * piece of rail
 
 * @param x,y coordinates where waypoint will be built
 
 * @param p1 graphics for waypoint type, bit 8 signifies custom waypoint gfx (& 0x100)
 
 * @param p1 graphics for waypoint type, 0 indicates standard graphics
 
 * @param p2 unused
 
 *
 
 * @todo When checking for the tile slope,
 
 * distingush between "Flat land required" and "land sloped in wrong direction"
 
 */
 
int32 CmdBuildTrainWaypoint(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	TileIndex tile = TileVirtXY(x, y);
 
	Waypoint *wp;
 
	uint tileh;
 
	uint dir;
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 

	
 
	/* if custom gfx are used, make sure it is within bounds */
 
	if (p1 > 0x100 + (uint)GetCustomStationsCount(STAT_CLASS_WAYP)) return CMD_ERROR;
 
	if (p1 >= GetNumCustomStations(STAT_CLASS_WAYP)) return CMD_ERROR;
 

	
 
	if (!IsTileType(tile, MP_RAILWAY) || ((dir = 0, _m[tile].m5 != 1) && (dir = 1, _m[tile].m5 != 2)))
 
		return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
 

	
 
	if (!CheckTileOwnership(tile))
 
		return CMD_ERROR;
 

	
 
	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
 

	
 
	tileh = GetTileSlope(tile, NULL);
 
	if (tileh != 0) {
 
		if (!_patches.build_on_slopes || IsSteepTileh(tileh) || !(tileh & (0x3 << dir)) || !(tileh & ~(0x3 << dir)))
 
			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
 
	}
 

	
 
	/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
 
	wp = FindDeletedWaypointCloseTo(tile);
 
	if (wp == NULL) {
 
		wp = AllocateWaypoint();
 
		if (wp == NULL) return CMD_ERROR;
 

	
 
		wp->town_index = 0;
 
		wp->string = STR_NULL;
 
		wp->town_cn = 0;
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		bool reserved = PBSTileReserved(tile) != 0;
 
		ModifyTile(tile, MP_MAP5, RAIL_TYPE_WAYPOINT | dir);
 
		if (--p1 & 0x100) { // waypoint type 0 uses default graphics
 
		if (p1 > 0) { // waypoint type 0 uses default graphics
 
			// custom graphics
 
			_m[tile].m3 |= 16;
 
			_m[tile].m4 = p1 & 0xff;
 
			_m[tile].m4 = (p1 - 1) & 0xff;
 
		}
 
		if (reserved) {
 
			PBSReserveTrack(tile, dir);
 
		} else {
 
			PBSClearTrack(tile, dir);
 
		}
 

	
 
		wp->deleted = 0;
 
		wp->xy = tile;
 
		wp->build_date = _date;
 

	
 
		if (wp->town_index == STR_NULL)
 
			MakeDefaultWaypointName(wp);
 

	
 
		UpdateWaypointSign(wp);
 
		RedrawWaypointSign(wp);
 
	}
 

	
 
	return _price.build_train_depot;
 
}
 

	
 
/* Internal handler to delete a waypoint */
 
static void DoDeleteWaypoint(Waypoint *wp)
 
{
 
	Order order;
 

	
 
	wp->xy = 0;
 

	
 
	order.type = OT_GOTO_WAYPOINT;
 
	order.station = wp->index;
 
	DeleteDestinationFromVehicleOrder(order);
 

	
 
	if (wp->string != STR_NULL)
 
		DeleteName(wp->string);
 

	
 
	RedrawWaypointSign(wp);
 
}
 

	
 
/* Daily loop for waypoints */
 
void WaypointsDailyLoop(void)
 
{
 
	Waypoint *wp;
 

	
 
	/* Check if we need to delete a waypoint */
 
	FOR_ALL_WAYPOINTS(wp) {
 
		if (wp->deleted && !--wp->deleted) {
 
			DoDeleteWaypoint(wp);
 
		}
 
@@ -342,104 +342,104 @@ int32 CmdRenameWaypoint(int x, int y, ui
 
	} else {
 
		if (flags & DC_EXEC) {
 
			wp = GetWaypoint(p1);
 
			if (wp->string != STR_NULL)
 
				DeleteName(wp->string);
 

	
 
			MakeDefaultWaypointName(wp);
 
			UpdateWaypointSign(wp);
 
			MarkWholeScreenDirty();
 
		}
 
	}
 
	return 0;
 
}
 

	
 
/* This hacks together some dummy one-shot Station structure for a waypoint. */
 
Station *ComposeWaypointStation(TileIndex tile)
 
{
 
	Waypoint *wp = GetWaypointByTile(tile);
 
	static Station stat;
 

	
 
	stat.train_tile = stat.xy = wp->xy;
 
	stat.town = GetTown(wp->town_index);
 
	stat.string_id = wp->string == STR_NULL ? /* FIXME? */ 0 : wp->string;
 
	stat.build_date = wp->build_date;
 
	stat.class_id = 6;
 
	stat.stat_id = wp->stat_id;
 

	
 
	return &stat;
 
}
 

	
 
extern uint16 _custom_sprites_base;
 

	
 

	
 
/* Draw a waypoint */
 
void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype)
 
{
 
	const StationSpec *stat;
 
	uint32 relocation;
 
	const DrawTileSprites *cust;
 
	DrawTileSeqStruct const *seq;
 
	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
 
	uint32 ormod, img;
 

	
 
	ormod = SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player));
 

	
 
	x += 33;
 
	y += 17;
 

	
 
	/* draw default waypoint graphics of ID 0 */
 
	if (stat_id == 0) {
 
	stat = GetCustomStation(STAT_CLASS_WAYP, stat_id);
 
	if (stat == NULL) {
 
		// stat is NULL for default waypoints and when waypoint graphics are
 
		// not loaded.
 
		DrawDefaultWaypointSprite(x, y, railtype);
 
		return;
 
	}
 

	
 
	stat = GetCustomStation(STAT_CLASS_WAYP, stat_id - 1);
 
	assert(stat);
 
	relocation = GetCustomStationRelocation(stat, NULL, 1);
 
	// emulate station tile - open with building
 
	// add 1 to get the other direction
 
	cust = &stat->renderdata[2];
 

	
 
	img = cust->ground_sprite;
 
	img += (img < _custom_sprites_base) ? rti->total_offset : railtype;
 

	
 
	if (img & PALETTE_MODIFIER_COLOR) img = (img & SPRITE_MASK);
 
	DrawSprite(img, x, y);
 

	
 
	foreach_draw_tile_seq(seq, cust->seq) {
 
		Point pt = RemapCoords(seq->delta_x, seq->delta_y, seq->delta_z);
 
		uint32 image = seq->image + relocation;
 
		DrawSprite((image & SPRITE_MASK) | ormod, x + pt.x, y + pt.y);
 
	}
 
}
 

	
 
/* Fix savegames which stored waypoints in their old format */
 
void FixOldWaypoints(void)
 
{
 
	Waypoint *wp;
 

	
 
	/* Convert the old 'town_or_string', to 'string' / 'town' / 'town_cn' */
 
	FOR_ALL_WAYPOINTS(wp) {
 
		if (wp->xy == 0)
 
			continue;
 

	
 
		wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;
 
		wp->town_cn = 0;
 
		if (wp->string & 0xC000) {
 
			wp->town_cn = wp->string & 0x3F;
 
			wp->string = STR_NULL;
 
		}
 
	}
 
}
 

	
 
void InitializeWaypoints(void)
 
{
 
	CleanPool(&_waypoint_pool);
 
	AddBlockToPool(&_waypoint_pool);
 
}
 

	
 
static const SaveLoad _waypoint_desc[] = {
 
	SLE_CONDVAR(Waypoint, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(Waypoint, xy, SLE_UINT32, 6, 255),
 
	SLE_CONDVAR(Waypoint, town_index, SLE_UINT16, 12, 255),
 
	SLE_CONDVAR(Waypoint, town_cn, SLE_UINT8, 12, 255),
waypoint.h
Show inline comments
 
/* $Id$ */
 

	
 
#ifndef WAYPOINT_H
 
#define WAYPOINT_H
 

	
 
#include "pool.h"
 

	
 
struct Waypoint {
 
	TileIndex xy;
 
	uint16 index;
 

	
 
	uint16 town_index;
 
	byte town_cn;          // The Nth waypoint for this town (consecutive number)
 
	StringID string;       // If this is zero, town + town_cn is used for naming
 

	
 
	ViewportSign sign;
 
	uint16 build_date;
 
	byte stat_id;
 
	uint32 grfid;
 
	byte deleted;          // this is a delete counter. when it reaches 0, the waypoint struct is deleted.
 
};
 

	
 
enum {
 
	RAIL_TYPE_WAYPOINT = 0xC4,
 
	RAIL_WAYPOINT_TRACK_MASK = 1,
 
};
 

	
 
extern MemoryPool _waypoint_pool;
 

	
 
/**
 
 * Get the pointer to the waypoint with index 'index'
 
 */
 
static inline Waypoint *GetWaypoint(uint index)
 
{
 
	return (Waypoint*)GetItemFromPool(&_waypoint_pool, index);
 
}
 

	
 
/**
 
 * Get the current size of the WaypointPool
 
 */
 
static inline uint16 GetWaypointPoolSize(void)
 
{
 
	return _waypoint_pool.total_items;
 
}
 

	
 
static inline bool IsWaypointIndex(uint index)
 
{
 
	return index < GetWaypointPoolSize();
 
}
 

	
 
#define FOR_ALL_WAYPOINTS_FROM(wp, start) for (wp = GetWaypoint(start); wp != NULL; wp = (wp->index + 1 < GetWaypointPoolSize()) ? GetWaypoint(wp->index + 1) : NULL)
 
#define FOR_ALL_WAYPOINTS(wp) FOR_ALL_WAYPOINTS_FROM(wp, 0)
 

	
 
static inline bool IsRailWaypoint(byte m5)
 
{
 
	return (m5 & 0xFC) == 0xC4;
 
}
 

	
 
int32 RemoveTrainWaypoint(TileIndex tile, uint32 flags, bool justremove);
 
Station *ComposeWaypointStation(TileIndex tile);
 
Waypoint *GetWaypointByTile(TileIndex tile);
 
void ShowRenameWaypointWindow(const Waypoint *cp);
 
void DrawWaypointSprite(int x, int y, int image, RailType railtype);
 
void UpdateWaypointSign(Waypoint *cp);
 
void FixOldWaypoints(void);
 
void UpdateAllWaypointSigns(void);
 

	
0 comments (0 inline, 0 general)