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
 
@@ -638,48 +638,49 @@ 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
newgrf.c
Show inline comments
 
@@ -779,121 +779,111 @@ static bool AircraftVehicleChangeInfo(ui
 

	
 
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++;
 
					}
 
@@ -1527,48 +1517,51 @@ static void NewSpriteGroup(byte *buf, in
 

	
 
		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);
 
@@ -1667,50 +1660,50 @@ static void NewVehicle_SpriteGroupMappin
 
				}
 

	
 
				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) {
 
@@ -2375,85 +2368,111 @@ static void InitializeGRFSpecial(void)
 

	
 
/**
 
 * 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;
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];
rail_gui.c
Show inline comments
 
@@ -106,49 +106,49 @@ void CcRailDepot(bool success, TileIndex
 
		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,
 
@@ -236,51 +236,51 @@ static void BuildRailClick_E(Window *w)
 
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)
 
@@ -808,56 +808,56 @@ static const Widget _build_depot_widgets
 
{      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;
 
	}
 
}
 
@@ -868,35 +868,35 @@ static const Widget _build_waypoint_widg
 
{      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,
 
};
 

	
 
@@ -174,125 +175,52 @@ static inline RoadStop *GetRoadStop(uint
 
/**
 
 * 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?
station_cmd.c
Show inline comments
 
@@ -1178,102 +1178,48 @@ int32 CmdRemoveFromRailroadStation(int x
 
// 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 {
 
@@ -1330,56 +1276,48 @@ static const RealSpriteGroup *ResolveSta
 
		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 */
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
 
@@ -133,98 +133,98 @@ void MakeDefaultWaypointName(Waypoint *w
 
}
 

	
 
/* 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)
 
{
 
@@ -366,56 +366,56 @@ Station *ComposeWaypointStation(TileInde
 
	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' */
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;
0 comments (0 inline, 0 general)