Changeset - r15175:66e0817dc450
[Not reviewed]
master
0 30 0
rubidium - 14 years ago 2010-05-13 10:14:29
rubidium@openttd.org
(svn r19814) -Codechange: give some more unnamed enums a name, in case they consisted of unrelated values use static const (u)int
30 files changed with 82 insertions and 125 deletions:
0 comments (0 inline, 0 general)
src/ai/ai_instance.cpp
Show inline comments
 
@@ -367,195 +367,193 @@ void AIInstance::GameLoop()
 
			this->engine->ResumeError();
 
			this->Died();
 
		}
 

	
 
		this->is_started = true;
 
		return;
 
	}
 
	if (this->is_save_data_on_stack) {
 
		sq_poptop(this->engine->GetVM());
 
		this->is_save_data_on_stack = false;
 
	}
 

	
 
	/* Continue the VM */
 
	try {
 
		if (!this->engine->Resume(_settings_game.ai.ai_max_opcode_till_suspend)) this->Died();
 
	} catch (AI_VMSuspend e) {
 
		this->suspend  = e.GetSuspendTime();
 
		this->callback = e.GetSuspendCallback();
 
	} catch (AI_FatalError e) {
 
		this->is_dead = true;
 
		this->engine->ThrowError(e.GetErrorMessage());
 
		this->engine->ResumeError();
 
		this->Died();
 
	}
 
}
 

	
 
void AIInstance::CollectGarbage() const
 
{
 
	if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
 
}
 

	
 
/* static */ void AIInstance::DoCommandReturn(AIInstance *instance)
 
{
 
	instance->engine->InsertResult(AIObject::GetLastCommandRes());
 
}
 

	
 
/* static */ void AIInstance::DoCommandReturnVehicleID(AIInstance *instance)
 
{
 
	instance->engine->InsertResult(AIObject::GetNewVehicleID());
 
}
 

	
 
/* static */ void AIInstance::DoCommandReturnSignID(AIInstance *instance)
 
{
 
	instance->engine->InsertResult(AIObject::GetNewSignID());
 
}
 

	
 
/* static */ void AIInstance::DoCommandReturnGroupID(AIInstance *instance)
 
{
 
	instance->engine->InsertResult(AIObject::GetNewGroupID());
 
}
 

	
 
/* static */ AIStorage *AIInstance::GetStorage()
 
{
 
	assert(Company::IsValidAiID(_current_company));
 
	return Company::Get(_current_company)->ai_instance->storage;
 
}
 

	
 
/*
 
 * All data is stored in the following format:
 
 * First 1 byte indicating if there is a data blob at all.
 
 * 1 byte indicating the type of data.
 
 * The data itself, this differs per type:
 
 *  - integer: a binary representation of the integer (int32).
 
 *  - string:  First one byte with the string length, then a 0-terminated char
 
 *             array. The string can't be longer than 255 bytes (including
 
 *             terminating '\0').
 
 *  - array:   All data-elements of the array are saved recursive in this
 
 *             format, and ended with an element of the type
 
 *             SQSL_ARRAY_TABLE_END.
 
 *  - table:   All key/value pairs are saved in this format (first key 1, then
 
 *             value 1, then key 2, etc.). All keys and values can have an
 
 *             arbitrary type (as long as it is supported by the save function
 
 *             of course). The table is ended with an element of the type
 
 *             SQSL_ARRAY_TABLE_END.
 
 *  - bool:    A single byte with value 1 representing true and 0 false.
 
 *  - null:    No data.
 
 */
 

	
 
/** The type of the data that follows in the savegame. */
 
enum SQSaveLoadType {
 
	SQSL_INT             = 0x00, ///< The following data is an integer.
 
	SQSL_STRING          = 0x01, ///< The following data is an string.
 
	SQSL_ARRAY           = 0x02, ///< The following data is an array.
 
	SQSL_TABLE           = 0x03, ///< The following data is an table.
 
	SQSL_BOOL            = 0x04, ///< The following data is a boolean.
 
	SQSL_NULL            = 0x05, ///< A null variable.
 
	SQSL_ARRAY_TABLE_END = 0xFF, ///< Marks the end of an array or table, no data follows.
 
};
 

	
 
static byte _ai_sl_byte;
 

	
 
static const SaveLoad _ai_byte[] = {
 
	SLEG_VAR(_ai_sl_byte, SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
enum {
 
	AISAVE_MAX_DEPTH = 25, ///< The maximum recursive depth for items stored in the savegame.
 
};
 
static const uint AISAVE_MAX_DEPTH = 25; ///< The maximum recursive depth for items stored in the savegame.
 

	
 
/* static */ bool AIInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
 
{
 
	if (max_depth == 0) {
 
		AILog::Error("Savedata can only be nested to 25 deep. No data saved.");
 
		return false;
 
	}
 

	
 
	switch (sq_gettype(vm, index)) {
 
		case OT_INTEGER: {
 
			if (!test) {
 
				_ai_sl_byte = SQSL_INT;
 
				SlObject(NULL, _ai_byte);
 
			}
 
			SQInteger res;
 
			sq_getinteger(vm, index, &res);
 
			if (!test) {
 
				int value = (int)res;
 
				SlArray(&value, 1, SLE_INT32);
 
			}
 
			return true;
 
		}
 

	
 
		case OT_STRING: {
 
			if (!test) {
 
				_ai_sl_byte = SQSL_STRING;
 
				SlObject(NULL, _ai_byte);
 
			}
 
			const SQChar *res;
 
			sq_getstring(vm, index, &res);
 
			/* @bug if a string longer than 512 characters is given to SQ2OTTD, the
 
			 *  internal buffer overflows. */
 
			const char *buf = SQ2OTTD(res);
 
			size_t len = strlen(buf) + 1;
 
			if (len >= 255) {
 
				AILog::Error("Maximum string length is 254 chars. No data saved.");
 
				return false;
 
			}
 
			if (!test) {
 
				_ai_sl_byte = (byte)len;
 
				SlObject(NULL, _ai_byte);
 
				SlArray((void*)buf, len, SLE_CHAR);
 
			}
 
			return true;
 
		}
 

	
 
		case OT_ARRAY: {
 
			if (!test) {
 
				_ai_sl_byte = SQSL_ARRAY;
 
				SlObject(NULL, _ai_byte);
 
			}
 
			sq_pushnull(vm);
 
			while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
 
				/* Store the value */
 
				bool res = SaveObject(vm, -1, max_depth - 1, test);
 
				sq_pop(vm, 2);
 
				if (!res) {
 
					sq_pop(vm, 1);
 
					return false;
 
				}
 
			}
 
			sq_pop(vm, 1);
 
			if (!test) {
 
				_ai_sl_byte = SQSL_ARRAY_TABLE_END;
 
				SlObject(NULL, _ai_byte);
 
			}
 
			return true;
 
		}
 

	
 
		case OT_TABLE: {
 
			if (!test) {
 
				_ai_sl_byte = SQSL_TABLE;
 
				SlObject(NULL, _ai_byte);
 
			}
 
			sq_pushnull(vm);
 
			while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
 
				/* Store the key + value */
 
				bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
 
				sq_pop(vm, 2);
 
				if (!res) {
 
					sq_pop(vm, 1);
 
					return false;
 
				}
 
			}
 
			sq_pop(vm, 1);
 
			if (!test) {
 
				_ai_sl_byte = SQSL_ARRAY_TABLE_END;
 
				SlObject(NULL, _ai_byte);
 
			}
 
			return true;
 
		}
 

	
 
		case OT_BOOL: {
 
			if (!test) {
 
				_ai_sl_byte = SQSL_BOOL;
 
				SlObject(NULL, _ai_byte);
src/airport.h
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file airport.h Various declarations for airports */
 

	
 
#ifndef AIRPORT_H
 
#define AIRPORT_H
 

	
 
#include "direction_type.h"
 
#include "tile_type.h"
 

	
 
/** Some airport-related constants */
 
enum {
 
	MAX_TERMINALS =  10,                    ///< maximum number of terminals per airport
 
	MAX_HELIPADS  =   4,                    ///< maximum number of helipads per airport
 
	MAX_ELEMENTS  = 255,                    ///< maximum number of aircraft positions at airport
 
	NUM_AIRPORTTILES = 256,                 ///< total number of airport tiles
 
	NEW_AIRPORTTILE_OFFSET = 74,            ///< offset of first newgrf airport tile
 
	INVALID_AIRPORTTILE = NUM_AIRPORTTILES, ///< id for an invalid airport tile
 
};
 
static const uint MAX_TERMINALS =  10;                       ///< maximum number of terminals per airport
 
static const uint MAX_HELIPADS  =   4;                       ///< maximum number of helipads per airport
 
static const uint MAX_ELEMENTS  = 255;                       ///< maximum number of aircraft positions at airport
 

	
 
static const uint NUM_AIRPORTTILES       = 256;              ///< total number of airport tiles
 
static const uint NEW_AIRPORTTILE_OFFSET = 74;               ///< offset of first newgrf airport tile
 
static const uint INVALID_AIRPORTTILE    = NUM_AIRPORTTILES; ///< id for an invalid airport tile
 

	
 
/** Airport types */
 
enum AirportTypes {
 
	AT_SMALL         =   0,
 
	AT_LARGE         =   1,
 
	AT_HELIPORT      =   2,
 
	AT_METROPOLITAN  =   3,
 
	AT_INTERNATIONAL =   4,
 
	AT_COMMUTER      =   5,
 
	AT_HELIDEPOT     =   6,
 
	AT_INTERCON      =   7,
 
	AT_HELISTATION   =   8,
 
	AT_OILRIG        =   9,
 
	NEW_AIRPORT_OFFSET = 10,
 
	NUM_AIRPORTS     =  128,
 
	AT_INVALID       = 254,
 
	AT_DUMMY         = 255
 
};
 

	
 
enum AirportMovingDataFlags {
 
	AMED_NOSPDCLAMP = 1 << 0,
 
	AMED_TAKEOFF    = 1 << 1,
 
	AMED_SLOWTURN   = 1 << 2,
 
	AMED_LAND       = 1 << 3,
 
	AMED_EXACTPOS   = 1 << 4,
 
	AMED_BRAKE      = 1 << 5,
 
	AMED_HELI_RAISE = 1 << 6,
 
	AMED_HELI_LOWER = 1 << 7,
 
	AMED_HOLD       = 1 << 8
 
};
 

	
 
/* Movement States on Airports (headings target) */
 
enum AirportMovementStates {
 
	TO_ALL         =  0,
 
	HANGAR         =  1,
 
	TERM1          =  2,
 
	TERM2          =  3,
 
	TERM3          =  4,
 
	TERM4          =  5,
 
	TERM5          =  6,
 
	TERM6          =  7,
 
	HELIPAD1       =  8,
 
	HELIPAD2       =  9,
 
	TAKEOFF        = 10,
 
	STARTTAKEOFF   = 11,
 
	ENDTAKEOFF     = 12,
 
	HELITAKEOFF    = 13,
 
	FLYING         = 14,
 
	LANDING        = 15,
 
	ENDLANDING     = 16,
 
	HELILANDING    = 17,
 
	HELIENDLANDING = 18,
 
	TERM7          = 19,
 
	TERM8          = 20,
 
	HELIPAD3       = 21,
 
	HELIPAD4       = 22,
 
	MAX_HEADINGS   = 22,
 
};
 

	
 
/* Movement Blocks on Airports
 
 * blocks (eg_airport_flags) */
 
static const uint64
 
	TERM1_block              = 1ULL <<  0,
 
	TERM2_block              = 1ULL <<  1,
 
	TERM3_block              = 1ULL <<  2,
 
	TERM4_block              = 1ULL <<  3,
 
	TERM5_block              = 1ULL <<  4,
 
	TERM6_block              = 1ULL <<  5,
 
	HELIPAD1_block           = 1ULL <<  6,
 
	HELIPAD2_block           = 1ULL <<  7,
 
	RUNWAY_IN_OUT_block      = 1ULL <<  8,
 
	RUNWAY_IN_block          = 1ULL <<  8,
 
	AIRPORT_BUSY_block       = 1ULL <<  8,
 
	RUNWAY_OUT_block         = 1ULL <<  9,
 
	TAXIWAY_BUSY_block       = 1ULL << 10,
 
	OUT_WAY_block            = 1ULL << 11,
 
	IN_WAY_block             = 1ULL << 12,
 
	AIRPORT_ENTRANCE_block   = 1ULL << 13,
 
	TERM_GROUP1_block        = 1ULL << 14,
 
	TERM_GROUP2_block        = 1ULL << 15,
 
	HANGAR2_AREA_block       = 1ULL << 16,
 
	TERM_GROUP2_ENTER1_block = 1ULL << 17,
 
	TERM_GROUP2_ENTER2_block = 1ULL << 18,
 
	TERM_GROUP2_EXIT1_block  = 1ULL << 19,
 
	TERM_GROUP2_EXIT2_block  = 1ULL << 20,
 
	PRE_HELIPAD_block        = 1ULL << 21,
 

	
 
	/* blocks for new airports */
 
	TERM7_block              = 1ULL << 22,
 
	TERM8_block              = 1ULL << 23,
 
	TERM9_block              = 1ULL << 24,
 
	HELIPAD3_block           = 1ULL << 24,
 
	TERM10_block             = 1ULL << 25,
 
	HELIPAD4_block           = 1ULL << 25,
 
	HANGAR1_AREA_block       = 1ULL << 26,
 
	OUT_WAY2_block           = 1ULL << 27,
src/airport_gui.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file airport_gui.cpp The GUI for airports. */
 

	
 
#include "stdafx.h"
 
#include "window_gui.h"
 
#include "station_gui.h"
 
#include "terraform_gui.h"
 
#include "airport.h"
 
#include "sound_func.h"
 
#include "window_func.h"
 
#include "strings_func.h"
 
#include "viewport_func.h"
 
#include "gfx_func.h"
 
#include "company_func.h"
 
#include "tilehighlight_func.h"
 
#include "company_base.h"
 
#include "station_type.h"
 
#include "newgrf_airport.h"
 
#include "widgets/dropdown_type.h"
 
#include "core/geometry_func.hpp"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
static AirportClassID _selected_airport_class; ///< the currently visible airport class
 
static int _selected_airport_index;            ///< the index of the selected airport in the current class or -1
 

	
 
static void ShowBuildAirportPicker(Window *parent);
 

	
 

	
 
void CcBuildAirport(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	if (result.Failed()) return;
 

	
 
	SndPlayTileFx(SND_1F_SPLAT, tile);
 
	if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
 
}
 

	
 
static void PlaceAirport(TileIndex tile)
 
{
 
	if (_selected_airport_index == -1) return;
 
	uint32 p2 = _ctrl_pressed;
 
	SB(p2, 16, 16, INVALID_STATION); // no station to join
 

	
 
	uint32 p1 = GetAirportSpecFromClass(_selected_airport_class, _selected_airport_index)->GetIndex();
 
	CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_AIRPORT | CMD_MSG(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE), CcBuildAirport, "" };
 
	ShowSelectStationIfNeeded(cmdcont, TileArea(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE));
 
}
 

	
 
/** Widget number of the airport build window. */
 
enum {
 
enum AirportToolbarWidgets {
 
	ATW_AIRPORT,
 
	ATW_DEMOLISH,
 
};
 

	
 

	
 
static void BuildAirClick_Airport(Window *w)
 
{
 
	if (HandlePlacePushButton(w, ATW_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT, PlaceAirport)) ShowBuildAirportPicker(w);
 
}
 

	
 
static void BuildAirClick_Demolish(Window *w)
 
{
 
	HandlePlacePushButton(w, ATW_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT, PlaceProc_DemolishArea);
 
}
 

	
 

	
 
typedef void OnButtonClick(Window *w);
 
static OnButtonClick * const _build_air_button_proc[] = {
 
	BuildAirClick_Airport,
 
	BuildAirClick_Demolish,
 
};
 

	
 
struct BuildAirToolbarWindow : Window {
 
	BuildAirToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
 
	{
 
		this->InitNested(desc, window_number);
 
		if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this);
 
	}
 

	
 
	~BuildAirToolbarWindow()
 
	{
 
		if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false);
 
	}
 

	
 
	virtual void OnPaint()
 
	{
 
		this->DrawWidgets();
 
	}
 

	
 
	virtual void OnClick(Point pt, int widget, int click_count)
 
	{
 
		if (!IsInsideBS(widget, ATW_AIRPORT, lengthof(_build_air_button_proc))) return;
 

	
 
		_build_air_button_proc[widget - ATW_AIRPORT](this);
 
	}
 

	
 

	
 
	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 
	{
 
		switch (keycode) {
 
			case '1': BuildAirClick_Airport(this); break;
 
			case '2': BuildAirClick_Demolish(this); break;
 
			default: return ES_NOT_HANDLED;
 
		}
 
		return ES_HANDLED;
 
	}
 

	
 
	virtual void OnPlaceObject(Point pt, TileIndex tile)
 
	{
 
		_place_proc(tile);
 
	}
 

	
 
	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
 
	{
 
		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
 
	}
 

	
 
	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
 
	{
 
		if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) {
 
			GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 
		}
 
	}
 

	
 
	virtual void OnPlaceObjectAbort()
 
	{
 
		this->RaiseButtons();
 

	
 
		DeleteWindowById(WC_BUILD_STATION, TRANSPORT_AIR);
 
		DeleteWindowById(WC_SELECT_STATION, 0);
 
	}
 
};
 

	
 
static const NWidgetPart _nested_air_toolbar_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
 
		NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 
		NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
 
	EndContainer(),
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, ATW_AIRPORT), SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_AIRPORT, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP),
 
		NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetFill(1, 1), EndContainer(),
 
		NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, ATW_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
 
	EndContainer(),
 
};
 

	
src/company_gui.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file company_gui.cpp Company related GUIs. */
 

	
 
#include "stdafx.h"
 
#include "gui.h"
 
#include "window_gui.h"
 
#include "textbuf_gui.h"
 
#include "viewport_func.h"
 
#include "company_func.h"
 
#include "command_func.h"
 
#include "network/network.h"
 
#include "network/network_gui.h"
 
#include "network/network_func.h"
 
#include "economy_func.h"
 
#include "vehicle_base.h"
 
#include "newgrf.h"
 
#include "company_manager_face.h"
 
#include "strings_func.h"
 
#include "date_func.h"
 
#include "widgets/dropdown_type.h"
 
#include "tilehighlight_func.h"
 
#include "sprite.h"
 
#include "company_base.h"
 
#include "core/geometry_func.hpp"
 

	
 
#include "table/strings.h"
 

	
 
/** Company GUI constants. */
 
enum {
 
	FIRST_GUI_CALL = INT_MAX,  ///< default value to specify this is the first call of the resizable gui
 
static const int FIRST_GUI_CALL = INT_MAX; ///< default value to specify this is the first call of the resizable gui
 

	
 
	EXP_LINESPACE  = 2,        ///< Amount of vertical space for a horizontal (sub-)total line.
 
	EXP_BLOCKSPACE = 10,       ///< Amount of vertical space between two blocks of numbers.
 
};
 
static const uint EXP_LINESPACE  = 2;      ///< Amount of vertical space for a horizontal (sub-)total line.
 
static const uint EXP_BLOCKSPACE = 10;     ///< Amount of vertical space between two blocks of numbers.
 

	
 
static void DoSelectCompanyManagerFace(Window *parent);
 

	
 
/** Standard unsorted list of expenses. */
 
static ExpensesType _expenses_list_1[] = {
 
	EXPENSES_CONSTRUCTION,
 
	EXPENSES_NEW_VEHICLES,
 
	EXPENSES_TRAIN_RUN,
 
	EXPENSES_ROADVEH_RUN,
 
	EXPENSES_AIRCRAFT_RUN,
 
	EXPENSES_SHIP_RUN,
 
	EXPENSES_PROPERTY,
 
	EXPENSES_TRAIN_INC,
 
	EXPENSES_ROADVEH_INC,
 
	EXPENSES_AIRCRAFT_INC,
 
	EXPENSES_SHIP_INC,
 
	EXPENSES_LOAN_INT,
 
	EXPENSES_OTHER,
 
};
 

	
 
/** Grouped list of expenses. */
 
static ExpensesType _expenses_list_2[] = {
 
	EXPENSES_TRAIN_INC,
 
	EXPENSES_ROADVEH_INC,
 
	EXPENSES_AIRCRAFT_INC,
 
	EXPENSES_SHIP_INC,
 
	INVALID_EXPENSES,
 
	EXPENSES_TRAIN_RUN,
 
	EXPENSES_ROADVEH_RUN,
 
	EXPENSES_AIRCRAFT_RUN,
 
	EXPENSES_SHIP_RUN,
 
	EXPENSES_PROPERTY,
 
	EXPENSES_LOAN_INT,
 
	INVALID_EXPENSES,
 
	EXPENSES_CONSTRUCTION,
 
	EXPENSES_NEW_VEHICLES,
 
	EXPENSES_OTHER,
 
	INVALID_EXPENSES,
 
};
 

	
 
/** Expense list container. */
 
struct ExpensesList {
 
	const ExpensesType *et;   ///< Expenses items.
 
	const uint length;        ///< Number of items in list.
 
	const uint num_subtotals; ///< Number of sub-totals in the list.
 

	
 
	ExpensesList(ExpensesType *et, int length, int num_subtotals) : et(et), length(length), num_subtotals(num_subtotals)
 
	{
 
	}
 

	
 
	uint GetHeight() const
 
	{
 
		/* heading + line + texts of expenses + sub-totals + total line + total text */
 
		return FONT_HEIGHT_NORMAL + EXP_LINESPACE + this->length * FONT_HEIGHT_NORMAL + num_subtotals * (EXP_BLOCKSPACE + EXP_LINESPACE) + EXP_LINESPACE + FONT_HEIGHT_NORMAL;
 
	}
 

	
 
	/** Compute width of the expenses categories in pixels. */
 
	uint GetCategoriesWidth() const
 
	{
 
		uint width = 0;
 
		bool invalid_expenses_measured = false; // Measure 'Total' width only once.
 
		for (uint i = 0; i < this->length; i++) {
 
			ExpensesType et = this->et[i];
 
			if (et == INVALID_EXPENSES) {
 
				if (!invalid_expenses_measured) {
 
					width = max(width, GetStringBoundingBox(STR_FINANCES_TOTAL_CAPTION).width);
 
					invalid_expenses_measured = true;
 
				}
 
			} else {
 
				width = max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width);
 
			}
 
		}
 
		return width;
 
	}
 
};
 

	
 
static const ExpensesList _expenses_list_types[] = {
 
	ExpensesList(_expenses_list_1, lengthof(_expenses_list_1), 0),
 
	ExpensesList(_expenses_list_2, lengthof(_expenses_list_2), 3),
 
};
 

	
 
/** Widgets of the company finances windows. */
 
enum CompanyFinancesWindowWidgets {
 
	CFW_CAPTION,       ///< Caption of the window
 
	CFW_TOGGLE_SIZE,   ///< Toggle windows size
 
	CFW_SEL_PANEL,     ///< Select panel or nothing
 
	CFW_EXPS_CATEGORY, ///< Column for expenses category strings
 
	CFW_EXPS_PRICE1,   ///< Column for year Y-2 expenses
 
	CFW_EXPS_PRICE2,   ///< Column for year Y-1 expenses
 
	CFW_EXPS_PRICE3,   ///< Column for year Y expenses
 
	CFW_TOTAL_PANEL,   ///< Panel for totals
 
	CFW_SEL_MAXLOAN,   ///< Selection of maxloan column
 
	CFW_BALANCE_VALUE, ///< Bank balance value
 
	CFW_LOAN_VALUE,    ///< Loan
 
	CFW_LOAN_LINE,     ///< Line for summing bank balance and loan
 
	CFW_TOTAL_VALUE,   ///< Total
src/console_gui.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file console_gui.cpp Handling the GUI of the in-game console. */
 

	
 
#include "stdafx.h"
 
#include "textbuf_gui.h"
 
#include "window_gui.h"
 
#include "console_gui.h"
 
#include "console_internal.h"
 
#include "window_func.h"
 
#include "string_func.h"
 
#include "gfx_func.h"
 
#include "settings_type.h"
 
#include "console_func.h"
 
#include "rev.h"
 

	
 

	
 
enum {
 
	ICON_HISTORY_SIZE       = 20,
 
	ICON_LINE_SPACING       =  2,
 
	ICON_RIGHT_BORDERWIDTH  = 10,
 
	ICON_BOTTOM_BORDERWIDTH = 12,
 
};
 
static const uint ICON_HISTORY_SIZE       = 20;
 
static const uint ICON_LINE_SPACING       =  2;
 
static const uint ICON_RIGHT_BORDERWIDTH  = 10;
 
static const uint ICON_BOTTOM_BORDERWIDTH = 12;
 

	
 
/**
 
 * Container for a single line of console output
 
 */
 
struct IConsoleLine {
 
	static IConsoleLine *front; ///< The front of the console backlog buffer
 
	static int size;            ///< The amount of items in the backlog
 

	
 
	IConsoleLine *previous; ///< The previous console message.
 
	char *buffer;           ///< The data to store.
 
	TextColour colour;      ///< The colour of the line.
 
	uint16 time;            ///< The amount of time the line is in the backlog.
 

	
 
	/**
 
	 * Initialize the console line.
 
	 * @param buffer the data to print.
 
	 * @param colour the colour of the line.
 
	 */
 
	IConsoleLine(char *buffer, TextColour colour) :
 
			previous(IConsoleLine::front),
 
			buffer(buffer),
 
			colour(colour),
 
			time(0)
 
	{
 
		IConsoleLine::front = this;
 
		IConsoleLine::size++;
 
	}
 

	
 
	/**
 
	 * Clear this console line and any further ones.
 
	 */
 
	~IConsoleLine()
 
	{
 
		IConsoleLine::size--;
 
		free(buffer);
 

	
 
		delete previous;
 
	}
 

	
 
	/**
 
	 * Get the index-ed item in the list.
 
	 */
 
	static const IConsoleLine *Get(uint index)
 
	{
 
		const IConsoleLine *item = IConsoleLine::front;
 
		while (index != 0 && item != NULL) {
 
			index--;
 
			item = item->previous;
 
		}
 

	
 
		return item;
 
	}
 

	
 
	/**
 
	 * Truncate the list removing everything older than/more than the amount
 
	 * as specified in the config file.
 
	 * As a side effect also increase the time the other lines have been in
 
	 * the list.
 
	 * @return true if and only if items got removed.
 
	 */
 
	static bool Truncate()
 
	{
 
		IConsoleLine *cur = IConsoleLine::front;
 
		if (cur == NULL) return false;
 

	
 
		int count = 1;
 
		for (IConsoleLine *item = cur->previous; item != NULL; count++, cur = item, item = item->previous) {
 
			if (item->time > _settings_client.gui.console_backlog_timeout &&
 
					count > _settings_client.gui.console_backlog_length) {
 
				delete item;
 
				cur->previous = NULL;
 
				return true;
 
			}
 

	
 
			if (item->time != MAX_UVALUE(uint16)) item->time++;
 
		}
 

	
 
		return false;
 
	}
 

	
 
	/**
 
	 * Reset the complete console line backlog.
 
	 */
 
	static void Reset()
 
	{
 
		delete IConsoleLine::front;
 
		IConsoleLine::front = NULL;
 
		IConsoleLine::size = 0;
 
	}
 
};
 

	
 
/* static */ IConsoleLine *IConsoleLine::front = NULL;
 
/* static */ int IConsoleLine::size  = 0;
 

	
 

	
 
/* ** main console cmd buffer ** */
 
@@ -353,128 +350,128 @@ void IConsoleGUIInit()
 

	
 
	IConsoleLine::Reset();
 
	memset(_iconsole_history, 0, sizeof(_iconsole_history));
 

	
 
	_iconsole_cmdline.buf = CallocT<char>(ICON_CMDLN_SIZE); // create buffer and zero it
 
	_iconsole_cmdline.maxsize = ICON_CMDLN_SIZE;
 

	
 
	IConsolePrintF(CC_WARNING, "OpenTTD Game Console Revision 7 - %s", _openttd_revision);
 
	IConsolePrint(CC_WHITE,  "------------------------------------");
 
	IConsolePrint(CC_WHITE,  "use \"help\" for more information");
 
	IConsolePrint(CC_WHITE,  "");
 
	IConsoleClearCommand();
 
}
 

	
 
void IConsoleClearBuffer()
 
{
 
	IConsoleLine::Reset();
 
}
 

	
 
void IConsoleGUIFree()
 
{
 
	free(_iconsole_cmdline.buf);
 
	IConsoleClearBuffer();
 
}
 

	
 
void IConsoleResize(Window *w)
 
{
 
	switch (_iconsole_mode) {
 
		case ICONSOLE_OPENED:
 
			w->height = _screen.height / 3;
 
			w->width = _screen.width;
 
			break;
 
		case ICONSOLE_FULL:
 
			w->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
 
			w->width = _screen.width;
 
			break;
 
		default: return;
 
	}
 

	
 
	MarkWholeScreenDirty();
 
}
 

	
 
void IConsoleSwitch()
 
{
 
	switch (_iconsole_mode) {
 
		case ICONSOLE_CLOSED:
 
			new IConsoleWindow();
 
			break;
 

	
 
		case ICONSOLE_OPENED: case ICONSOLE_FULL:
 
			DeleteWindowById(WC_CONSOLE, 0);
 
			break;
 
	}
 

	
 
	MarkWholeScreenDirty();
 
}
 

	
 
void IConsoleClose() {if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();}
 

	
 
/**
 
 * Add the entered line into the history so you can look it back
 
 * scroll, etc. Put it to the beginning as it is the latest text
 
 * @param cmd Text to be entered into the 'history'
 
 * @return the command to execute
 
 */
 
static const char *IConsoleHistoryAdd(const char *cmd)
 
{
 
	/* Strip all spaces at the begin */
 
	while (IsWhitespace(*cmd)) cmd++;
 

	
 
	/* Do not put empty command in history */
 
	if (StrEmpty(cmd)) return NULL;
 

	
 
	/* Do not put in history if command is same as previous */
 
	if (_iconsole_history[0] == NULL || strcmp(_iconsole_history[0], cmd) != 0) {
 
		free(_iconsole_history[ICON_HISTORY_SIZE - 1]);
 
		memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1));
 
		_iconsole_history[0] = strdup(cmd);
 
	}
 

	
 
	/* Reset the history position */
 
	IConsoleResetHistoryPos();
 
	return _iconsole_history[0];
 
}
 

	
 
/**
 
 * Navigate Up/Down in the history of typed commands
 
 * @param direction Go further back in history (+1), go to recently typed commands (-1)
 
 */
 
static void IConsoleHistoryNavigate(int direction)
 
{
 
	if (_iconsole_history[0] == NULL) return; // Empty history
 
	int i = _iconsole_historypos + direction;
 

	
 
	/* watch out for overflows, just wrap around */
 
	if (i < 0) i = ICON_HISTORY_SIZE - 1;
 
	if (i >= ICON_HISTORY_SIZE) i = 0;
 
	if ((uint)i >= ICON_HISTORY_SIZE) i = 0;
 

	
 
	if (direction > 0) {
 
		if (_iconsole_history[i] == NULL) i = 0;
 
	}
 

	
 
	if (direction < 0) {
 
		while (i > 0 && _iconsole_history[i] == NULL) i--;
 
	}
 

	
 
	_iconsole_historypos = i;
 
	IConsoleClearCommand();
 
	/* copy history to 'command prompt / bash' */
 
	assert(_iconsole_history[i] != NULL && IsInsideMM(i, 0, ICON_HISTORY_SIZE));
 
	ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_history[i], _iconsole_cmdline.maxsize);
 
	UpdateTextBufferSize(&_iconsole_cmdline);
 
}
 

	
 
/**
 
 * Handle the printing of text entered into the console or redirected there
 
 * by any other means. Text can be redirected to other clients in a network game
 
 * as well as to a logfile. If the network server is a dedicated server, all activities
 
 * are also logged. All lines to print are added to a temporary buffer which can be
 
 * used as a history to print them onscreen
 
 * @param colour_code the colour of the command. Red in case of errors, etc.
 
 * @param str the message entered or output on the console (notice, error, etc.)
 
 */
 
void IConsoleGUIPrint(ConsoleColour colour_code, char *str)
 
{
 
	new IConsoleLine(str, (TextColour)colour_code);
 
	SetWindowDirty(WC_CONSOLE, 0);
 
}
src/currency.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file currency.cpp Support for different currencies. */
 

	
 
#include "stdafx.h"
 
#include "currency.h"
 
#include "news_func.h"
 
#include "settings_type.h"
 
#include "date_func.h"
 

	
 
#include "table/strings.h"
 

	
 
	/*   exchange rate    prefix                      symbol_pos
 
	 *   |  separator        |           postfix          |
 
	 *   |   |   Euro year   |              |             | name
 
	 *   |   |    |          |              |             |  | */
 
static const CurrencySpec origin_currency_specs[NUM_CURRENCY] = {
 
	{    1, "", CF_NOEURO, "\xC2\xA3",     "",           0, STR_GAME_OPTIONS_CURRENCY_GBP    }, ///< british pounds
 
	{    2, "", CF_NOEURO, "$",            "",           0, STR_GAME_OPTIONS_CURRENCY_USD    }, ///< us dollars
 
	{    2, "", CF_ISEURO, "\xE2\x82\xAC", "",           0, STR_GAME_OPTIONS_CURRENCY_EUR    }, ///< Euro
 
	{  220, "", CF_NOEURO, "\xC2\xA5",     "",           0, STR_GAME_OPTIONS_CURRENCY_YEN    }, ///< yen
 
	{   20, "", 2002,      "",             " S.",        1, STR_GAME_OPTIONS_CURRENCY_ATS    }, ///< austrian schilling
 
	{   59, "", 2002,      "BEF ",         "",           0, STR_GAME_OPTIONS_CURRENCY_BEF    }, ///< belgian franc
 
	{    2, "", CF_NOEURO, "CHF ",         "",           0, STR_GAME_OPTIONS_CURRENCY_CHF    }, ///< swiss franc
 
	{   41, "", CF_NOEURO, "",             " K\xC4\x8D", 1, STR_GAME_OPTIONS_CURRENCY_CZK    }, ///< czech koruna
 
	{    3, "", 2002,      "DM ",          "",           0, STR_GAME_OPTIONS_CURRENCY_DEM    }, ///< deutsche mark
 
	{   11, "", CF_NOEURO, "",             " kr",        1, STR_GAME_OPTIONS_CURRENCY_DKK    }, ///< danish krone
 
	{  245, "", 2002,      "Pts ",         "",           0, STR_GAME_OPTIONS_CURRENCY_ESP    }, ///< spanish pesetas
 
	{    9, "", 2002,      "",             " mk",        1, STR_GAME_OPTIONS_CURRENCY_FIM    }, ///< finnish markka
 
	{   10, "", 2002,      "FF ",          "",           0, STR_GAME_OPTIONS_CURRENCY_FRF    }, ///< french francs
 
	{  500, "", 2002,      "",             "Dr.",        1, STR_GAME_OPTIONS_CURRENCY_GRD    }, ///< greek drachma
 
	{  378, "", CF_NOEURO, "",             " Ft",        1, STR_GAME_OPTIONS_CURRENCY_HUF    }, ///< hungarian forint
 
	{  130, "", CF_NOEURO, "",             " Kr",        1, STR_GAME_OPTIONS_CURRENCY_ISK    }, ///< icelandic krona
 
	{ 2850, "", 2002,      "",             " L.",        1, STR_GAME_OPTIONS_CURRENCY_ITL    }, ///< italian lira
 
	{    3, "", 2002,      "NLG ",         "",           0, STR_GAME_OPTIONS_CURRENCY_NLG    }, ///< dutch gulden
 
	{   12, "", CF_NOEURO, "",             " Kr",        1, STR_GAME_OPTIONS_CURRENCY_NOK    }, ///< norwegian krone
 
	{    6, "", CF_NOEURO, "",             " z\xC5\x82", 1, STR_GAME_OPTIONS_CURRENCY_PLN    }, ///< polish zloty
 
	{    5, "", CF_NOEURO, "",             " Lei",       1, STR_GAME_OPTIONS_CURRENCY_RON    }, ///< romanian Lei
 
	{   50, "", CF_NOEURO, "",             " p",         1, STR_GAME_OPTIONS_CURRENCY_RUR    }, ///< russian rouble
 
	{  352, "", 2007,      "",             " SIT",       1, STR_GAME_OPTIONS_CURRENCY_SIT    }, ///< slovenian tolar
 
	{   13, "", CF_NOEURO, "",             " Kr",        1, STR_GAME_OPTIONS_CURRENCY_SEK    }, ///< swedish krona
 
	{    3, "", CF_NOEURO, "",             " TL",        1, STR_GAME_OPTIONS_CURRENCY_TRY    }, ///< turkish lira
 
	{   52, "", 2009,      "",             " Sk",        1, STR_GAME_OPTIONS_CURRENCY_SKK    }, ///< slovak koruna
 
	{    4, "", CF_NOEURO, "R$ ",          "",           0, STR_GAME_OPTIONS_CURRENCY_BRL    }, ///< brazil real
 
	{   20, "", CF_NOEURO, "",             " EEK",       1, STR_GAME_OPTIONS_CURRENCY_EEK    }, ///< estonian krooni
 
	{    1, "", CF_NOEURO, "",             "",           2, STR_GAME_OPTIONS_CURRENCY_CUSTOM }, ///< custom currency
 
};
 

	
 
/* Array of currencies used by the system */
 
CurrencySpec _currency_specs[NUM_CURRENCY];
 

	
 
/**
 
 * These enums are only declared in order to make sens
 
 * out of the TTDPatch_To_OTTDIndex array that will follow
 
 * Every currency used by Ottd is there, just in case TTDPatch will
 
 * add those missing in its code
 
 **/
 
enum {
 
enum Currencies {
 
	CURR_GBP,
 
	CURR_USD,
 
	CURR_EUR,
 
	CURR_YEN,
 
	CURR_ATS,
 
	CURR_BEF,
 
	CURR_CHF,
 
	CURR_CZK,
 
	CURR_DEM,
 
	CURR_DKK,
 
	CURR_ESP,
 
	CURR_FIM,
 
	CURR_FRF,
 
	CURR_GRD,
 
	CURR_HUF,
 
	CURR_ISK,
 
	CURR_ITL,
 
	CURR_NLG,
 
	CURR_NOK,
 
	CURR_PLN,
 
	CURR_RON,
 
	CURR_RUR,
 
	CURR_SIT,
 
	CURR_SEK,
 
	CURR_YTL,
 
	CURR_SKK,
 
	CURR_BRL,
 
	CURR_EEK,
 
};
 

	
 
/**
 
 * This array represent the position of OpenTTD's currencies,
 
 * compared to TTDPatch's ones.
 
 * When a grf sends currencies, they are based on the order defined by TTDPatch.
 
 * So, we must reindex them to our own order.
 
 **/
 
const byte TTDPatch_To_OTTDIndex[] =
 
{
 
	CURR_GBP,
 
	CURR_USD,
 
	CURR_FRF,
 
	CURR_DEM,
 
	CURR_YEN,
 
	CURR_ESP,
 
	CURR_HUF,
 
	CURR_PLN,
 
	CURR_ATS,
 
	CURR_BEF,
 
	CURR_DKK,
 
	CURR_FIM,
 
	CURR_GRD,
 
	CURR_CHF,
 
	CURR_NLG,
 
	CURR_ITL,
 
	CURR_SEK,
 
	CURR_RUR,
 
	CURR_EUR,
 
};
 

	
 
/**
 
 * Will return the ottd's index correspondance to
 
 * the ttdpatch's id.  If the id is bigger than the array,
 
 * it is a grf written for ottd, thus returning the same id.
 
 * Only called from newgrf.cpp
 
 * @param grfcurr_id currency id coming from newgrf
 
 * @return the corrected index
 
 **/
 
byte GetNewgrfCurrencyIdConverted(byte grfcurr_id)
 
{
 
	return (grfcurr_id >= lengthof(TTDPatch_To_OTTDIndex)) ? grfcurr_id : TTDPatch_To_OTTDIndex[grfcurr_id];
 
}
 

	
 
/**
 
 * get a mask of the allowed currencies depending on the year
 
 * @return mask of currencies
 
 */
 
uint GetMaskOfAllowedCurrencies()
 
{
 
	uint mask = 0;
 
	uint i;
 

	
 
	for (i = 0; i < NUM_CURRENCY; i++) {
 
		Year to_euro = _currency_specs[i].to_euro;
 

	
 
		if (to_euro != CF_NOEURO && to_euro != CF_ISEURO && _cur_year >= to_euro) continue;
 
		if (to_euro == CF_ISEURO && _cur_year < 2000) continue;
 
		mask |= (1 << i);
 
	}
 
	mask |= (1 << CUSTOM_CURRENCY_ID); // always allow custom currency
 
	return mask;
 
}
 

	
 
/**
 
 * Verify if the currency chosen by the user is about to be converted to Euro
 
 **/
 
void CheckSwitchToEuro()
src/date.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file date.cpp Handling of dates in our native format and transforming them to something human readable. */
 

	
 
#include "stdafx.h"
 
#include "variables.h"
 
#include "network/network.h"
 
#include "network/network_func.h"
 
#include "currency.h"
 
#include "window_func.h"
 
#include "functions.h"
 
#include "date_func.h"
 
#include "vehicle_base.h"
 
#include "debug.h"
 
#include "rail_gui.h"
 
#include "saveload/saveload.h"
 

	
 
Year      _cur_year;   ///< Current year, starting at 0
 
Month     _cur_month;  ///< Current month (0..11)
 
Date      _date;       ///< Current date in days (day counter)
 
DateFract _date_fract;
 

	
 

	
 
void SetDate(Date date)
 
{
 
	YearMonthDay ymd;
 

	
 
	_date = date;
 
	ConvertDateToYMD(date, &ymd);
 
	_cur_year = ymd.year;
 
	_cur_month = ymd.month;
 
}
 

	
 
#define M(a, b) ((a << 5) | b)
 
static const uint16 _month_date_from_year_day[] = {
 
	M( 0, 1), M( 0, 2), M( 0, 3), M( 0, 4), M( 0, 5), M( 0, 6), M( 0, 7), M( 0, 8), M( 0, 9), M( 0, 10), M( 0, 11), M( 0, 12), M( 0, 13), M( 0, 14), M( 0, 15), M( 0, 16), M( 0, 17), M( 0, 18), M( 0, 19), M( 0, 20), M( 0, 21), M( 0, 22), M( 0, 23), M( 0, 24), M( 0, 25), M( 0, 26), M( 0, 27), M( 0, 28), M( 0, 29), M( 0, 30), M( 0, 31),
 
	M( 1, 1), M( 1, 2), M( 1, 3), M( 1, 4), M( 1, 5), M( 1, 6), M( 1, 7), M( 1, 8), M( 1, 9), M( 1, 10), M( 1, 11), M( 1, 12), M( 1, 13), M( 1, 14), M( 1, 15), M( 1, 16), M( 1, 17), M( 1, 18), M( 1, 19), M( 1, 20), M( 1, 21), M( 1, 22), M( 1, 23), M( 1, 24), M( 1, 25), M( 1, 26), M( 1, 27), M( 1, 28), M( 1, 29),
 
	M( 2, 1), M( 2, 2), M( 2, 3), M( 2, 4), M( 2, 5), M( 2, 6), M( 2, 7), M( 2, 8), M( 2, 9), M( 2, 10), M( 2, 11), M( 2, 12), M( 2, 13), M( 2, 14), M( 2, 15), M( 2, 16), M( 2, 17), M( 2, 18), M( 2, 19), M( 2, 20), M( 2, 21), M( 2, 22), M( 2, 23), M( 2, 24), M( 2, 25), M( 2, 26), M( 2, 27), M( 2, 28), M( 2, 29), M( 2, 30), M( 2, 31),
 
	M( 3, 1), M( 3, 2), M( 3, 3), M( 3, 4), M( 3, 5), M( 3, 6), M( 3, 7), M( 3, 8), M( 3, 9), M( 3, 10), M( 3, 11), M( 3, 12), M( 3, 13), M( 3, 14), M( 3, 15), M( 3, 16), M( 3, 17), M( 3, 18), M( 3, 19), M( 3, 20), M( 3, 21), M( 3, 22), M( 3, 23), M( 3, 24), M( 3, 25), M( 3, 26), M( 3, 27), M( 3, 28), M( 3, 29), M( 3, 30),
 
	M( 4, 1), M( 4, 2), M( 4, 3), M( 4, 4), M( 4, 5), M( 4, 6), M( 4, 7), M( 4, 8), M( 4, 9), M( 4, 10), M( 4, 11), M( 4, 12), M( 4, 13), M( 4, 14), M( 4, 15), M( 4, 16), M( 4, 17), M( 4, 18), M( 4, 19), M( 4, 20), M( 4, 21), M( 4, 22), M( 4, 23), M( 4, 24), M( 4, 25), M( 4, 26), M( 4, 27), M( 4, 28), M( 4, 29), M( 4, 30), M( 4, 31),
 
	M( 5, 1), M( 5, 2), M( 5, 3), M( 5, 4), M( 5, 5), M( 5, 6), M( 5, 7), M( 5, 8), M( 5, 9), M( 5, 10), M( 5, 11), M( 5, 12), M( 5, 13), M( 5, 14), M( 5, 15), M( 5, 16), M( 5, 17), M( 5, 18), M( 5, 19), M( 5, 20), M( 5, 21), M( 5, 22), M( 5, 23), M( 5, 24), M( 5, 25), M( 5, 26), M( 5, 27), M( 5, 28), M( 5, 29), M( 5, 30),
 
	M( 6, 1), M( 6, 2), M( 6, 3), M( 6, 4), M( 6, 5), M( 6, 6), M( 6, 7), M( 6, 8), M( 6, 9), M( 6, 10), M( 6, 11), M( 6, 12), M( 6, 13), M( 6, 14), M( 6, 15), M( 6, 16), M( 6, 17), M( 6, 18), M( 6, 19), M( 6, 20), M( 6, 21), M( 6, 22), M( 6, 23), M( 6, 24), M( 6, 25), M( 6, 26), M( 6, 27), M( 6, 28), M( 6, 29), M( 6, 30), M( 6, 31),
 
	M( 7, 1), M( 7, 2), M( 7, 3), M( 7, 4), M( 7, 5), M( 7, 6), M( 7, 7), M( 7, 8), M( 7, 9), M( 7, 10), M( 7, 11), M( 7, 12), M( 7, 13), M( 7, 14), M( 7, 15), M( 7, 16), M( 7, 17), M( 7, 18), M( 7, 19), M( 7, 20), M( 7, 21), M( 7, 22), M( 7, 23), M( 7, 24), M( 7, 25), M( 7, 26), M( 7, 27), M( 7, 28), M( 7, 29), M( 7, 30), M( 7, 31),
 
	M( 8, 1), M( 8, 2), M( 8, 3), M( 8, 4), M( 8, 5), M( 8, 6), M( 8, 7), M( 8, 8), M( 8, 9), M( 8, 10), M( 8, 11), M( 8, 12), M( 8, 13), M( 8, 14), M( 8, 15), M( 8, 16), M( 8, 17), M( 8, 18), M( 8, 19), M( 8, 20), M( 8, 21), M( 8, 22), M( 8, 23), M( 8, 24), M( 8, 25), M( 8, 26), M( 8, 27), M( 8, 28), M( 8, 29), M( 8, 30),
 
	M( 9, 1), M( 9, 2), M( 9, 3), M( 9, 4), M( 9, 5), M( 9, 6), M( 9, 7), M( 9, 8), M( 9, 9), M( 9, 10), M( 9, 11), M( 9, 12), M( 9, 13), M( 9, 14), M( 9, 15), M( 9, 16), M( 9, 17), M( 9, 18), M( 9, 19), M( 9, 20), M( 9, 21), M( 9, 22), M( 9, 23), M( 9, 24), M( 9, 25), M( 9, 26), M( 9, 27), M( 9, 28), M( 9, 29), M( 9, 30), M( 9, 31),
 
	M(10, 1), M(10, 2), M(10, 3), M(10, 4), M(10, 5), M(10, 6), M(10, 7), M(10, 8), M(10, 9), M(10, 10), M(10, 11), M(10, 12), M(10, 13), M(10, 14), M(10, 15), M(10, 16), M(10, 17), M(10, 18), M(10, 19), M(10, 20), M(10, 21), M(10, 22), M(10, 23), M(10, 24), M(10, 25), M(10, 26), M(10, 27), M(10, 28), M(10, 29), M(10, 30),
 
	M(11, 1), M(11, 2), M(11, 3), M(11, 4), M(11, 5), M(11, 6), M(11, 7), M(11, 8), M(11, 9), M(11, 10), M(11, 11), M(11, 12), M(11, 13), M(11, 14), M(11, 15), M(11, 16), M(11, 17), M(11, 18), M(11, 19), M(11, 20), M(11, 21), M(11, 22), M(11, 23), M(11, 24), M(11, 25), M(11, 26), M(11, 27), M(11, 28), M(11, 29), M(11, 30), M(11, 31),
 
};
 
#undef M
 

	
 
enum {
 
enum DaysTillMonth {
 
	ACCUM_JAN = 0,
 
	ACCUM_FEB = ACCUM_JAN + 31,
 
	ACCUM_MAR = ACCUM_FEB + 29,
 
	ACCUM_APR = ACCUM_MAR + 31,
 
	ACCUM_MAY = ACCUM_APR + 30,
 
	ACCUM_JUN = ACCUM_MAY + 31,
 
	ACCUM_JUL = ACCUM_JUN + 30,
 
	ACCUM_AUG = ACCUM_JUL + 31,
 
	ACCUM_SEP = ACCUM_AUG + 31,
 
	ACCUM_OCT = ACCUM_SEP + 30,
 
	ACCUM_NOV = ACCUM_OCT + 31,
 
	ACCUM_DEC = ACCUM_NOV + 30,
 
};
 

	
 
static const uint16 _accum_days_for_month[] = {
 
	ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
 
	ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
 
	ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
 
};
 

	
 
/**
 
 * Converts a Date to a Year, Month & Day.
 
 * @param date the date to convert from
 
 * @param ymd  the year, month and day to write to
 
 */
 
void ConvertDateToYMD(Date date, YearMonthDay *ymd)
 
{
 
	/*
 
	 * Year determination in multiple steps to account for leap
 
	 * years. First do the large steps, then the smaller ones.
 
	 */
 

	
 
	/* There are 97 leap years in 400 years */
 
	Year yr = 400 * (date / (DAYS_IN_YEAR * 400 + 97));
 
	int rem = date % (DAYS_IN_YEAR * 400 + 97);
 
	uint16 x;
 

	
 
	if (rem >= DAYS_IN_YEAR * 100 + 25) {
 
		/* There are 25 leap years in the first 100 years after
 
		 * every 400th year, as every 400th year is a leap year */
 
		yr  += 100;
 
		rem -= DAYS_IN_YEAR * 100 + 25;
 

	
 
		/* There are 24 leap years in the next couple of 100 years */
 
		yr += 100 * (rem / (DAYS_IN_YEAR * 100 + 24));
 
		rem = (rem % (DAYS_IN_YEAR * 100 + 24));
 
	}
 

	
 
	if (!IsLeapYear(yr) && rem >= DAYS_IN_YEAR * 4) {
 
		/* The first 4 year of the century are not always a leap year */
 
		yr  += 4;
 
		rem -= DAYS_IN_YEAR * 4;
 
	}
 

	
 
	/* There is 1 leap year every 4 years */
 
	yr += 4 * (rem / (DAYS_IN_YEAR * 4 + 1));
 
	rem = rem % (DAYS_IN_YEAR * 4 + 1);
 

	
 
	/* The last (max 3) years to account for; the first one
 
	 * can be, but is not necessarily a leap year */
 
	while (rem >= (IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR)) {
 
		rem -= IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
 
		yr++;
 
	}
 

	
 
	/* Skip the 29th of February in non-leap years */
 
	if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
 

	
 
	ymd->year = yr;
 

	
 
	x = _month_date_from_year_day[rem];
 
	ymd->month = x >> 5;
 
	ymd->day = x & 0x1F;
 
}
 

	
 
/**
 
 * Converts a tupe of Year, Month and Day to a Date.
 
 * @param year  is a number between 0..MAX_YEAR
 
 * @param month is a number between 0..11
 
 * @param day   is a number between 1..31
 
 */
 
Date ConvertYMDToDate(Year year, Month month, Day day)
 
{
 
	/* Day-offset in a leap year */
 
	int days = _accum_days_for_month[month] + day - 1;
 

	
 
	/* Account for the missing of the 29th of February in non-leap years */
 
	if (!IsLeapYear(year) && days >= ACCUM_MAR) days--;
 

	
 
	return DAYS_TILL(year) + days;
 
}
 

	
 
/** Functions used by the IncreaseDate function */
 

	
 
extern void EnginesDailyLoop();
 
extern void DisasterDailyLoop();
src/fontcache.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file fontcache.cpp Cache for characters from fonts. */
 

	
 
#include "stdafx.h"
 
#include "fontcache.h"
 
#include "blitter/factory.hpp"
 
#include "core/math_func.hpp"
 

	
 
#include "table/sprites.h"
 
#include "table/control_codes.h"
 

	
 
static const int ASCII_LETTERSTART = 32; ///< First printable ASCII letter.
 

	
 
/** Semi-constant for the height of the different sizes of fonts. */
 
int _font_height[FS_END];
 

	
 
#ifdef WITH_FREETYPE
 
#include <ft2build.h>
 
#include FT_FREETYPE_H
 
#include FT_GLYPH_H
 

	
 
#ifdef WITH_FONTCONFIG
 
#include <fontconfig/fontconfig.h>
 
#endif
 

	
 
static FT_Library _library = NULL;
 
static FT_Face _face_small = NULL;
 
static FT_Face _face_medium = NULL;
 
static FT_Face _face_large = NULL;
 
static int _ascender[FS_END];
 

	
 
FreeTypeSettings _freetype;
 

	
 
enum {
 
	FACE_COLOUR = 1,
 
	SHADOW_COLOUR = 2,
 
};
 
static const byte FACE_COLOUR   = 1;
 
static const byte SHADOW_COLOUR = 2;
 

	
 
/** Get the font loaded into a Freetype face by using a font-name.
 
 * If no appropiate font is found, the function returns an error */
 
#ifdef WIN32
 
#include <windows.h>
 
#include <shlobj.h> /* SHGetFolderPath */
 
#include "os/windows/win32.h"
 

	
 
/**
 
 * Get the short DOS 8.3 format for paths.
 
 * FreeType doesn't support Unicode filenames and Windows' fopen (as used
 
 * by FreeType) doesn't support UTF-8 filenames. So we have to convert the
 
 * filename into something that isn't UTF-8 but represents the Unicode file
 
 * name. This is the short DOS 8.3 format. This does not contain any
 
 * characters that fopen doesn't support.
 
 * @param long_path the path in UTF-8.
 
 * @return the short path in ANSI (ASCII).
 
 */
 
char *GetShortPath(const char *long_path)
 
{
 
	static char short_path[MAX_PATH];
 
#ifdef UNICODE
 
	/* The non-unicode GetShortPath doesn't support UTF-8...,
 
	 * so convert the path to wide chars, then get the short
 
	 * path and convert it back again. */
 
	wchar_t long_path_w[MAX_PATH];
 
	MultiByteToWideChar(CP_UTF8, 0, long_path, -1, long_path_w, MAX_PATH);
 

	
 
	wchar_t short_path_w[MAX_PATH];
 
	GetShortPathNameW(long_path_w, short_path_w, MAX_PATH);
 

	
 
	WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, MAX_PATH, NULL, NULL);
 
#else
 
	/* Technically not needed, but do it for consistency. */
 
	GetShortPathNameA(long_path, short_path, MAX_PATH);
 
#endif
 
	return short_path;
 
}
 

	
 
/* Get the font file to be loaded into Freetype by looping the registry
 
 * location where windows lists all installed fonts. Not very nice, will
 
 * surely break if the registry path changes, but it works. Much better
 
 * solution would be to use CreateFont, and extract the font data from it
 
 * by GetFontData. The problem with this is that the font file needs to be
 
 * kept in memory then until the font is no longer needed. This could mean
 
 * an additional memory usage of 30MB (just for fonts!) when using an eastern
 
 * font for all font sizes */
 
#define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
 
#define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
 
static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
 
{
 
	FT_Error err = FT_Err_Cannot_Open_Resource;
 
	HKEY hKey;
 
	LONG ret;
 
	TCHAR vbuffer[MAX_PATH], dbuffer[256];
 
	TCHAR *font_namep;
 
	char *font_path;
 
	uint index;
 

	
 
	/* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the
 
	 * "Windows NT" key, on Windows 9x in the Windows key. To save us having
 
	 * to retrieve the windows version, we'll just query both */
 
	ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
 
	if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
 

	
 
	if (ret != ERROR_SUCCESS) {
 
		DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
 
		return err;
 
	}
 

	
 
	/* For Unicode we need some conversion between widechar and
 
	 * normal char to match the data returned by RegEnumValue,
 
	 * otherwise just use parameter */
 
#if defined(UNICODE)
 
	font_namep = MallocT<TCHAR>(MAX_PATH);
 
	MB_TO_WIDE_BUFFER(font_name, font_namep, MAX_PATH * sizeof(TCHAR));
 
#else
 
	font_namep = const_cast<char *>(font_name); // only cast because in unicode pointer is not const
 
#endif
 

	
 
	for (index = 0;; index++) {
 
		TCHAR *s;
 
		DWORD vbuflen = lengthof(vbuffer);
 
		DWORD dbuflen = lengthof(dbuffer);
 

	
 
		ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
 
		if (ret != ERROR_SUCCESS) goto registry_no_font_found;
 

	
 
		/* The font names in the registry are of the following 3 forms:
 
		 * - ADMUI3.fon
 
		 * - Book Antiqua Bold (TrueType)
 
		 * - Batang & BatangChe & Gungsuh & GungsuhChe (TrueType)
 
		 * We will strip the font-type '()' if any and work with the font name
 
		 * itself, which must match exactly; if...
 
		 * TTC files, font files which contain more than one font are seperated
 
		 * byt '&'. Our best bet will be to do substr match for the fontname
src/gamelog.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file gamelog.cpp Definition of functions used for logging of important changes in the game */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "saveload/saveload.h"
 
#include "core/alloc_func.hpp"
 
#include "variables.h"
 
#include "string_func.h"
 
#include "settings_type.h"
 
#include "gamelog_internal.h"
 
#include "console_func.h"
 
#include "debug.h"
 
#include "rev.h"
 

	
 
#include <stdarg.h>
 

	
 
extern const uint16 SAVEGAME_VERSION;  ///< current savegame version
 

	
 
extern SavegameType _savegame_type; ///< type of savegame we are loading
 

	
 
extern uint32 _ttdp_version;     ///< version of TTDP savegame (if applicable)
 
extern uint16 _sl_version;       ///< the major savegame version identifier
 
extern byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
 

	
 

	
 
static GamelogActionType _gamelog_action_type = GLAT_NONE; ///< action to record if anything changes
 

	
 
LoggedAction *_gamelog_action = NULL;        ///< first logged action
 
uint _gamelog_actions         = 0;           ///< number of actions
 
static LoggedAction *_current_action = NULL; ///< current action we are logging, NULL when there is no action active
 

	
 

	
 
/** Stores information about new action, but doesn't allocate it
 
 * Action is allocated only when there is at least one change
 
 * @param at type of action
 
 */
 
void GamelogStartAction(GamelogActionType at)
 
{
 
	assert(_gamelog_action_type == GLAT_NONE); // do not allow starting new action without stopping the previous first
 
	_gamelog_action_type = at;
 
}
 

	
 
/** Stops logging of any changes
 
 */
 
void GamelogStopAction()
 
{
 
	assert(_gamelog_action_type != GLAT_NONE); // nobody should try to stop if there is no action in progress
 

	
 
	bool print = _current_action != NULL;
 

	
 
	_current_action = NULL;
 
	_gamelog_action_type = GLAT_NONE;
 

	
 
	if (print) GamelogPrintDebug(5);
 
}
 

	
 
/** Resets and frees all memory allocated - used before loading or starting a new game
 
 */
 
void GamelogReset()
 
{
 
	assert(_gamelog_action_type == GLAT_NONE);
 

	
 
	for (uint i = 0; i < _gamelog_actions; i++) {
 
		const LoggedAction *la = &_gamelog_action[i];
 
		for (uint j = 0; j < la->changes; j++) {
 
			const LoggedChange *lc = &la->change[j];
 
			if (lc->ct == GLCT_SETTING) free(lc->setting.name);
 
		}
 
		free(la->change);
 
	}
 

	
 
	free(_gamelog_action);
 

	
 
	_gamelog_action  = NULL;
 
	_gamelog_actions = 0;
 
	_current_action  = NULL;
 
}
 

	
 
enum {
 
	GAMELOG_BUF_LEN = 1024 ///< length of buffer for one line of text
 
};
 
static const uint GAMELOG_BUF_LEN = 1024; ///< length of buffer for one line of text
 

	
 
static int _dbgofs = 0; ///< offset in current output buffer
 
static uint _dbgofs = 0; ///< offset in current output buffer
 

	
 
static void AddDebugText(char *buf, const char *s, ...) WARN_FORMAT(2, 3);
 

	
 
static void AddDebugText(char *buf, const char *s, ...)
 
{
 
	if (GAMELOG_BUF_LEN <= _dbgofs) return;
 

	
 
	va_list va;
 

	
 
	va_start(va, s);
 
	_dbgofs += vsnprintf(buf + _dbgofs, GAMELOG_BUF_LEN - _dbgofs, s, va);
 
	va_end(va);
 
}
 

	
 

	
 
/** Prints GRF filename if found
 
 * @param buf The location in the _dbgofs buffer to draw
 
 * @param grfid GRF which filename to print
 
 */
 
static void PrintGrfFilename(char *buf, uint grfid)
 
{
 
	const GRFConfig *gc = FindGRFConfig(grfid);
 

	
 
	if (gc == NULL) return;
 

	
 
	AddDebugText(buf, ", filename: %s", gc->filename);
 
}
 

	
 
/** Prints GRF ID, checksum and filename if found
 
 * @param buf The location in the _dbgofs buffer to draw
 
 * @param grfid GRF ID
 
 * @param md5sum array of md5sum to print
 
 */
 
static void PrintGrfInfo(char *buf, uint grfid, const uint8 *md5sum)
 
{
 
	char txt[40];
 

	
 
	md5sumToString(txt, lastof(txt), md5sum);
 

	
 
	AddDebugText(buf, "GRF ID %08X, checksum %s", BSWAP32(grfid), txt);
 

	
 
	PrintGrfFilename(buf, grfid);
 

	
 
	return;
 
}
 

	
 

	
 
/** Text messages for various logged actions */
 
static const char * const la_text[] = {
 
	"new game started",
 
	"game loaded",
 
	"GRF config changed",
 
	"cheat was used",
 
	"settings changed",
 
	"GRF bug triggered",
 
	"emergency savegame",
 
};
 

	
 
assert_compile(lengthof(la_text) == GLAT_END);
 

	
 

	
 
/**
 
 * Prints active gamelog
 
 * @param proc the procedure to draw with
 
 */
 
void GamelogPrint(GamelogPrintProc *proc)
 
{
 
	char buf[GAMELOG_BUF_LEN];
 

	
 
	proc("---- gamelog start ----");
 

	
 
	const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
 

	
 
	for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
 
		assert((uint)la->at < GLAT_END);
 

	
 
		snprintf(buf, GAMELOG_BUF_LEN, "Tick %u: %s", (uint)la->tick, la_text[(uint)la->at]);
 
		proc(buf);
 

	
 
		const LoggedChange *lcend = &la->change[la->changes];
 

	
 
		for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
 
			_dbgofs = 0;
 
			AddDebugText(buf, "     ");
 

	
 
			switch (lc->ct) {
 
				default: NOT_REACHED();
 
				case GLCT_MODE:
 
					AddDebugText(buf, "New game mode: %u landscape: %u",
 
						(uint)lc->mode.mode, (uint)lc->mode.landscape);
 
					break;
 

	
 
				case GLCT_REVISION:
 
					AddDebugText(buf, "Revision text changed to %s, savegame version %u, ",
 
						lc->revision.text, lc->revision.slver);
 

	
src/gfx.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file gfx.cpp Handling of drawing text and other gfx related stuff. */
 

	
 
#include "stdafx.h"
 
#include "gfx_func.h"
 
#include "variables.h"
 
#include "fontcache.h"
 
#include "genworld.h"
 
#include "zoom_func.h"
 
#include "blitter/factory.hpp"
 
#include "video/video_driver.hpp"
 
#include "strings_func.h"
 
#include "settings_type.h"
 
#include "landscape_type.h"
 
#include "network/network.h"
 
#include "network/network_func.h"
 
#include "thread/thread.h"
 
#include "window_func.h"
 
#include "newgrf_debug.h"
 

	
 
#include "table/palettes.h"
 
#include "table/sprites.h"
 
#include "table/control_codes.h"
 

	
 
byte _dirkeys;        ///< 1 = left, 2 = up, 4 = right, 8 = down
 
bool _fullscreen;
 
CursorVars _cursor;
 
bool _ctrl_pressed;   ///< Is Ctrl pressed?
 
bool _shift_pressed;  ///< Is Shift pressed?
 
byte _fast_forward;
 
bool _left_button_down;     ///< Is left mouse button pressed?
 
bool _left_button_clicked;  ///< Is left mouse button clicked?
 
bool _right_button_down;    ///< Is right mouse button pressed?
 
bool _right_button_clicked; ///< Is right mouse button clicked?
 
DrawPixelInfo _screen;
 
bool _screen_disable_anim = false;   ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot)
 
bool _exit_game;
 
GameMode _game_mode;
 
SwitchMode _switch_mode;  ///< The next mainloop command.
 
PauseModeByte _pause_mode;
 
int _pal_first_dirty;
 
int _pal_count_dirty;
 

	
 
Colour _cur_palette[256];
 

	
 
static int _max_char_height; ///< Cache of the height of the largest font
 
static int _max_char_width;  ///< Cache of the width of the largest font
 
static byte _stringwidth_table[FS_END][224]; ///< Cache containing width of often used characters. @see GetCharacterWidth()
 
DrawPixelInfo *_cur_dpi;
 
byte _colour_gradient[COLOUR_END][8];
 

	
 
static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE);
 

	
 
FontSize _cur_fontsize;
 
static FontSize _last_fontsize;
 
static ReusableBuffer<uint8> _cursor_backup;
 

	
 
/**
 
 * The rect for repaint.
 
 *
 
 * This rectangle defines the area which should be repaint by the video driver.
 
 *
 
 * @ingroup dirty
 
 */
 
static Rect _invalid_rect;
 
static const byte *_colour_remap_ptr;
 
static byte _string_colourremap[3]; ///< Recoloursprite for stringdrawing. The grf loader ensures, that ST_FONT sprites only use colours 0 to 2.
 

	
 
enum {
 
	DIRTY_BLOCK_HEIGHT   = 8,
 
	DIRTY_BLOCK_WIDTH    = 64,
 
};
 
static const uint DIRTY_BLOCK_HEIGHT   = 8;
 
static const uint DIRTY_BLOCK_WIDTH    = 64;
 

	
 
static uint _dirty_bytes_per_line = 0;
 
static byte *_dirty_blocks = NULL;
 

	
 
void GfxScroll(int left, int top, int width, int height, int xo, int yo)
 
{
 
	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 

	
 
	if (xo == 0 && yo == 0) return;
 

	
 
	if (_cursor.visible) UndrawMouseCursor();
 

	
 
#ifdef ENABLE_NETWORK
 
	if (_networking) NetworkUndrawChatMessage();
 
#endif /* ENABLE_NETWORK */
 

	
 
	blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo);
 
	/* This part of the screen is now dirty. */
 
	_video_driver->MakeDirty(left, top, width, height);
 
}
 

	
 

	
 
/**
 
 * Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
 
 *
 
 * @pre dpi->zoom == ZOOM_LVL_NORMAL, right >= left, bottom >= top
 
 * @param left Minimum X (inclusive)
 
 * @param top Minimum Y (inclusive)
 
 * @param right Maximum X (inclusive)
 
 * @param bottom Maximum Y (inclusive)
 
 * @param colour A 8 bit palette index (FILLRECT_OPAQUE and FILLRECT_CHECKER) or a recolour spritenumber (FILLRECT_RECOLOUR)
 
 * @param mode
 
 *         FILLRECT_OPAQUE:   Fill the rectangle with the specified colour
 
 *         FILLRECT_CHECKER:  Like FILLRECT_OPAQUE, but only draw every second pixel (used to grey out things)
 
 *         FILLRECT_RECOLOUR:  Apply a recolour sprite to every pixel in the rectangle currently on screen
 
 */
 
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
 
{
 
	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 
	const DrawPixelInfo *dpi = _cur_dpi;
 
	void *dst;
 
	const int otop = top;
 
	const int oleft = left;
 

	
 
	if (dpi->zoom != ZOOM_LVL_NORMAL) return;
 
	if (left > right || top > bottom) return;
 
	if (right < dpi->left || left >= dpi->left + dpi->width) return;
 
	if (bottom < dpi->top || top >= dpi->top + dpi->height) return;
 

	
 
	if ( (left -= dpi->left) < 0) left = 0;
 
	right = right - dpi->left + 1;
 
	if (right > dpi->width) right = dpi->width;
 
	right -= left;
 
	assert(right > 0);
 

	
 
	if ( (top -= dpi->top) < 0) top = 0;
 
	bottom = bottom - dpi->top + 1;
 
	if (bottom > dpi->height) bottom = dpi->height;
 
	bottom -= top;
 
	assert(bottom > 0);
 

	
 
	dst = blitter->MoveTo(dpi->dst_ptr, left, top);
 

	
 
	switch (mode) {
 
		default: // FILLRECT_OPAQUE
 
			blitter->DrawRect(dst, right, bottom, (uint8)colour);
 
			break;
 

	
 
		case FILLRECT_RECOLOUR:
 
			blitter->DrawColourMappingRect(dst, right, bottom, GB(colour, 0, PALETTE_WIDTH));
 
			break;
 

	
 
		case FILLRECT_CHECKER: {
 
			byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
 
			do {
 
				for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)colour);
 
				dst = blitter->MoveTo(dst, 0, 1);
 
			} while (--bottom > 0);
 
			break;
 
		}
 
	}
 
}
 

	
 
void GfxDrawLine(int x, int y, int x2, int y2, int colour)
 
{
 
	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 
	DrawPixelInfo *dpi = _cur_dpi;
 

	
 
	x -= dpi->left;
 
	x2 -= dpi->left;
 
	y -= dpi->top;
 
	y2 -= dpi->top;
 

	
 
	/* Check clipping */
 
	if (x < 0 && x2 < 0) return;
 
	if (y < 0 && y2 < 0) return;
 
	if (x > dpi->width  && x2 > dpi->width)  return;
src/industry_cmd.cpp
Show inline comments
 
@@ -2094,196 +2094,194 @@ static void CanCargoServiceIndustry(Carg
 
		}
 
	}
 
}
 

	
 
/**
 
 * Compute who can service the industry.
 
 *
 
 * Here, 'can service' means that he/she has trains and stations close enough
 
 * to the industry with the right cargo type and the right orders (ie has the
 
 * technical means).
 
 *
 
 * @param ind: Industry being investigated.
 
 *
 
 * @return: 0 if nobody can service the industry, 2 if the local company can
 
 * service the industry, and 1 otherwise (only competitors can service the
 
 * industry)
 
 */
 
static int WhoCanServiceIndustry(Industry *ind)
 
{
 
	/* Find all stations within reach of the industry */
 
	StationList stations;
 
	FindStationsAroundTiles(ind->location, &stations);
 

	
 
	if (stations.Length() == 0) return 0; // No stations found at all => nobody services
 

	
 
	const Vehicle *v;
 
	int result = 0;
 
	FOR_ALL_VEHICLES(v) {
 
		/* Is it worthwhile to try this vehicle? */
 
		if (v->owner != _local_company && result != 0) continue;
 

	
 
		/* Check whether it accepts the right kind of cargo */
 
		bool c_accepts = false;
 
		bool c_produces = false;
 
		if (v->type == VEH_TRAIN && Train::From(v)->IsFrontEngine()) {
 
			for (const Vehicle *u = v; u != NULL; u = u->Next()) {
 
				CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
 
			}
 
		} else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
 
			CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
 
		} else {
 
			continue;
 
		}
 
		if (!c_accepts && !c_produces) continue; // Wrong cargo
 

	
 
		/* Check orders of the vehicle.
 
		 * We cannot check the first of shared orders only, since the first vehicle in such a chain
 
		 * may have a different cargo type.
 
		 */
 
		const Order *o;
 
		FOR_VEHICLE_ORDERS(v, o) {
 
			if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
 
				/* Vehicle visits a station to load or unload */
 
				Station *st = Station::Get(o->GetDestination());
 
				assert(st != NULL);
 

	
 
				/* Same cargo produced by industry is dropped here => not serviced by vehicle v */
 
				if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
 

	
 
				if (stations.Contains(st)) {
 
					if (v->owner == _local_company) return 2; // Company services industry
 
					result = 1; // Competitor services industry
 
				}
 
			}
 
		}
 
	}
 
	return result;
 
}
 

	
 
/**
 
 * Report news that industry production has changed significantly
 
 *
 
 * @param ind: Industry with changed production
 
 * @param type: Cargo type that has changed
 
 * @param percent: Percentage of change (>0 means increase, <0 means decrease)
 
 */
 
static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
 
{
 
	NewsSubtype ns;
 

	
 
	switch (WhoCanServiceIndustry(ind)) {
 
		case 0: ns = NS_INDUSTRY_NOBODY;  break;
 
		case 1: ns = NS_INDUSTRY_OTHER;   break;
 
		case 2: ns = NS_INDUSTRY_COMPANY; break;
 
		default: NOT_REACHED();
 
	}
 
	SetDParam(2, abs(percent));
 
	SetDParam(0, CargoSpec::Get(type)->name);
 
	SetDParam(1, ind->index);
 
	AddIndustryNewsItem(
 
		percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
 
		ns,
 
		ind->index
 
	);
 
}
 

	
 
enum {
 
	PERCENT_TRANSPORTED_60 = 153,
 
	PERCENT_TRANSPORTED_80 = 204,
 
};
 
static const uint PERCENT_TRANSPORTED_60 = 153;
 
static const uint PERCENT_TRANSPORTED_80 = 204;
 

	
 
/** Change industry production or do closure
 
 * @param i Industry for which changes are performed
 
 * @param monthly true if it's the monthly call, false if it's the random call
 
 */
 
static void ChangeIndustryProduction(Industry *i, bool monthly)
 
{
 
	StringID str = STR_NULL;
 
	bool closeit = false;
 
	const IndustrySpec *indspec = GetIndustrySpec(i->type);
 
	bool standard = false;
 
	bool suppress_message = false;
 
	bool recalculate_multipliers = false; ///< reinitialize production_rate to match prod_level
 
	/* don't use smooth economy for industries using production related callbacks */
 
	bool smooth_economy = _settings_game.economy.smooth_economy &&
 
	                      !(HasBit(indspec->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(indspec->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks
 
	                      !(HasBit(indspec->callback_mask, CBM_IND_MONTHLYPROD_CHANGE) || HasBit(indspec->callback_mask, CBM_IND_PRODUCTION_CHANGE));            // production change callbacks
 
	byte div = 0;
 
	byte mul = 0;
 
	int8 increment = 0;
 

	
 
	bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE);
 
	if (callback_enabled) {
 
		uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
 
		if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
 
			suppress_message = HasBit(res, 7);
 
			/* Get the custom message if any */
 
			if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
 
			res = GB(res, 0, 4);
 
			switch (res) {
 
				default: NOT_REACHED();
 
				case 0x0: break;                  // Do nothing, but show the custom message if any
 
				case 0x1: div = 1; break;         // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
 
				case 0x2: mul = 1; break;         // Double industry production if it hasn't reached eight times of the original yet.
 
				case 0x3: closeit = true; break;  // The industry announces imminent closure, and is physically removed from the map next month.
 
				case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
 
				case 0x5: case 0x6: case 0x7:     // Divide production by 4, 8, 16
 
				case 0x8: div = res - 0x3; break; // Divide production by 32
 
				case 0x9: case 0xA: case 0xB:     // Multiply production by 4, 8, 16
 
				case 0xC: mul = res - 0x7; break; // Multiply production by 32
 
				case 0xD:                         // decrement production
 
				case 0xE:                         // increment production
 
					increment = res == 0x0D ? -1 : 1;
 
					break;
 
				case 0xF:                         // Set production to third byte of register 0x100
 
					i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
 
					recalculate_multipliers = true;
 
					break;
 
			}
 
		}
 
	} else {
 
		if (monthly != smooth_economy) return;
 
		if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
 
	}
 

	
 
	if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) {
 
		/* decrease or increase */
 
		bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE;
 

	
 
		if (smooth_economy) {
 
			closeit = true;
 
			for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
 
				if (i->produced_cargo[j] == CT_INVALID) continue;
 
				uint32 r = Random();
 
				int old_prod, new_prod, percent;
 
				/* If over 60% is transported, mult is 1, else mult is -1. */
 
				int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
 

	
 
				new_prod = old_prod = i->production_rate[j];
 

	
 
				/* For industries with only_decrease flags (temperate terrain Oil Wells),
 
				 * the multiplier will always be -1 so they will only decrease. */
 
				if (only_decrease) {
 
					mult = -1;
 
				/* For normal industries, if over 60% is transported, 33% chance for decrease.
 
				 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
 
				} else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
 
					mult *= -1;
 
				}
 

	
 
				/* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
 
				 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
 
				if (Chance16I(1, 22, r >> 16)) {
 
					new_prod += mult * (max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
 
				}
 

	
 
				/* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
 
				new_prod = Clamp(new_prod, 1, 255);
 

	
 
				if (((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) && j == 1)
 
					new_prod = Clamp(new_prod, 0, 16);
 

	
 
				/* Do not stop closing the industry when it has the lowest possible production rate */
 
				if (new_prod == old_prod && old_prod > 1) {
 
					closeit = false;
 
					continue;
src/misc_gui.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file misc_gui.cpp GUIs for a number of misc windows. */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "landscape.h"
 
#include "newgrf_text.h"
 
#include "saveload/saveload.h"
 
#include "gui.h"
 
#include "viewport_func.h"
 
#include "gfx_func.h"
 
#include "command_func.h"
 
#include "company_func.h"
 
#include "town.h"
 
#include "network/network.h"
 
#include "network/network_content.h"
 
#include "company_base.h"
 
#include "texteff.hpp"
 
#include "cargotype.h"
 
#include "company_manager_face.h"
 
#include "strings_func.h"
 
#include "fileio_func.h"
 
#include "fios.h"
 
#include "zoom_func.h"
 
#include "window_func.h"
 
#include "tilehighlight_func.h"
 
#include "querystring_gui.h"
 
#include "console_func.h"
 
#include "core/geometry_func.hpp"
 
#include "newgrf_debug.h"
 

	
 
#include "table/strings.h"
 

	
 

	
 
/**
 
 * Try to retrive the current clipboard contents.
 
 *
 
 * @note OS-specific funtion.
 
 * @return True if some text could be retrived.
 
 */
 
bool GetClipboardContents(char *buffer, size_t buff_len);
 

	
 

	
 
/* Variables to display file lists */
 
SaveLoadDialogMode _saveload_mode;
 

	
 

	
 
static bool _fios_path_changed;
 
static bool _savegame_sort_dirty;
 
int _caret_timer;
 

	
 
/** Widgets for the land info window. */
 
enum LandInfoWidgets {
 
	LIW_BACKGROUND, ///< Background to draw on
 
};
 

	
 
static const NWidgetPart _nested_land_info_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
 
		NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_LAND_AREA_INFORMATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 
		NWidget(WWT_DEBUGBOX, COLOUR_GREY),
 
	EndContainer(),
 
	NWidget(WWT_PANEL, COLOUR_GREY, LIW_BACKGROUND), EndContainer(),
 
};
 

	
 
static const WindowDesc _land_info_desc(
 
	WDP_AUTO, 0, 0,
 
	WC_LAND_INFO, WC_NONE,
 
	0,
 
	_nested_land_info_widgets, lengthof(_nested_land_info_widgets)
 
);
 

	
 
class LandInfoWindow : public Window {
 
	enum {
 
	enum LandInfoLines {
 
		LAND_INFO_CENTERED_LINES   = 12,                       ///< Up to 12 centered lines
 
		LAND_INFO_MULTICENTER_LINE = LAND_INFO_CENTERED_LINES, ///< One multicenter line
 
		LAND_INFO_LINE_END,
 
	};
 

	
 
		LAND_INFO_LINE_BUFF_SIZE = 512,
 
	};
 
	static const uint LAND_INFO_LINE_BUFF_SIZE = 512;
 

	
 
public:
 
	char landinfo_data[LAND_INFO_LINE_END][LAND_INFO_LINE_BUFF_SIZE];
 
	TileIndex tile;
 

	
 
	virtual void OnPaint()
 
	{
 
		this->DrawWidgets();
 
	}
 

	
 
	virtual void DrawWidget(const Rect &r, int widget) const
 
	{
 
		if (widget != LIW_BACKGROUND) return;
 

	
 
		uint y = r.top + WD_TEXTPANEL_TOP;
 
		for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) {
 
			if (StrEmpty(this->landinfo_data[i])) break;
 

	
 
			DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, this->landinfo_data[i], i == 0 ? TC_LIGHT_BLUE : TC_FROMSTRING, SA_CENTER);
 
			y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
 
			if (i == 0) y += 4;
 
		}
 

	
 
		if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) {
 
			SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]);
 
			DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_TEXTPANEL_BOTTOM, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER);
 
		}
 
	}
 

	
 
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 
	{
 
		if (widget != LIW_BACKGROUND) return;
 

	
 
		size->height = WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM;
 
		for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) {
 
			if (StrEmpty(this->landinfo_data[i])) break;
 

	
 
			uint width = GetStringBoundingBox(this->landinfo_data[i]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT;
 
			size->width = max(size->width, width);
 

	
 
			size->height += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
 
			if (i == 0) size->height += 4;
 
		}
 

	
 
		if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) {
 
			uint width = GetStringBoundingBox(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT;
 
			size->width = max(size->width, min(300u, width));
 
			SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]);
 
			size->height += GetStringHeight(STR_JUST_RAW_STRING, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT);
 
		}
 
	}
 

	
 
	LandInfoWindow(TileIndex tile) : Window(), tile(tile) {
 
		Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
 

	
 
		/* Because build_date is not set yet in every TileDesc, we make sure it is empty */
 
		TileDesc td;
 

	
 
		td.build_date = INVALID_DATE;
 

	
 
		/* Most tiles have only one owner, but
 
		 *  - drivethrough roadstops can be build on town owned roads (up to 2 owners) and
 
		 *  - roads can have up to four owners (railroad, road, tram, 3rd-roadtype "highway").
 
		 */
 
		td.owner_type[0] = STR_LAND_AREA_INFORMATION_OWNER; // At least one owner is displayed, though it might be "N/A".
 
		td.owner_type[1] = STR_NULL;       // STR_NULL results in skipping the owner
 
		td.owner_type[2] = STR_NULL;
 
		td.owner_type[3] = STR_NULL;
 
		td.owner[0] = OWNER_NONE;
 
		td.owner[1] = OWNER_NONE;
 
		td.owner[2] = OWNER_NONE;
 
		td.owner[3] = OWNER_NONE;
 

	
 
		td.station_class = STR_NULL;
 
		td.station_name = STR_NULL;
 
		td.airport_tile_name = STR_NULL;
 
		td.rail_speed = 0;
 

	
 
		td.grf = NULL;
 

	
 
		CargoArray acceptance;
 
		AddAcceptedCargo(tile, acceptance, NULL);
 
		GetTileDesc(tile, &td);
 

	
 
		uint line_nr = 0;
 

	
 
		/* Tiletype */
 
		SetDParam(0, td.dparam[0]);
 
		GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr]));
 
		line_nr++;
 

	
 
		/* Up to four owners */
 
		for (uint i = 0; i < 4; i++) {
 
			if (td.owner_type[i] == STR_NULL) continue;
 

	
 
			SetDParam(0, STR_LAND_AREA_INFORMATION_OWNER_N_A);
src/music/qtmidi.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/**
 
 * @file qtmidi.cpp
 
 * @brief MIDI music player for MacOS X using QuickTime.
 
 *
 
 * This music player should work in all MacOS X releases starting from 10.0,
 
 * as QuickTime is an integral part of the system since the old days of the
 
 * Motorola 68k-based Macintoshes. The only extra dependency apart from
 
 * QuickTime itself is Carbon, which is included since 10.0 as well.
 
 *
 
 * QuickTime gets fooled with the MIDI files from Transport Tycoon Deluxe
 
 * because of the @c .gm suffix. To force QuickTime to load the MIDI files
 
 * without the need of dealing with the individual QuickTime components
 
 * needed to play music (data source, MIDI parser, note allocators,
 
 * synthesizers and the like) some Carbon functions are used to set the file
 
 * type as seen by QuickTime, using @c FSpSetFInfo() (which modifies the
 
 * file's resource fork).
 
 */
 

	
 

	
 
#ifndef NO_QUICKTIME
 

	
 
#include "../stdafx.h"
 
#include "qtmidi.h"
 
#include "../debug.h"
 

	
 
#define Rect  OTTDRect
 
#define Point OTTDPoint
 
#include <QuickTime/QuickTime.h>
 
#undef Rect
 
#undef Point
 

	
 
static FMusicDriver_QtMidi iFMusicDriver_QtMidi;
 

	
 

	
 
enum {
 
	midiType = 'Midi' ///< OSType code for MIDI songs.
 
};
 
static const uint MIDI_TYPE = 'Midi' ///< OSType code for MIDI songs.
 

	
 

	
 
/**
 
 * Sets the @c OSType of a given file to @c 'Midi', but only if it's not
 
 * already set.
 
 *
 
 * @param *ref A @c FSSpec structure referencing a file.
 
 */
 
static void SetMIDITypeIfNeeded(const FSRef *ref)
 
{
 
	FSCatalogInfo catalogInfo;
 

	
 
	assert(ref);
 

	
 
	if (noErr != FSGetCatalogInfo(ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL)) return;
 
	if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) {
 
		FileInfo * const info = (FileInfo *) catalogInfo.finderInfo;
 
		if (info->fileType != midiType && !(info->finderFlags & kIsAlias)) {
 
		if (info->fileType != MIDI_TYPE && !(info->finderFlags & kIsAlias)) {
 
			OSErr e;
 
			info->fileType = midiType;
 
			info->fileType = MIDI_TYPE;
 
			e = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
 
			if (e == noErr) {
 
				DEBUG(driver, 3, "qtmidi: changed filetype to 'Midi'");
 
			} else {
 
				DEBUG(driver, 0, "qtmidi: changing filetype to 'Midi' failed - error %d", e);
 
			}
 
		}
 
	}
 
}
 

	
 

	
 
/**
 
 * Loads a MIDI file and returns it as a QuickTime Movie structure.
 
 *
 
 * @param *path String with the path of an existing MIDI file.
 
 * @param *moov Pointer to a @c Movie where the result will be stored.
 
 * @return Wether the file was loaded and the @c Movie successfully created.
 
 */
 
static bool LoadMovieForMIDIFile(const char *path, Movie *moov)
 
{
 
	int fd;
 
	int ret;
 
	char magic[4];
 
	FSRef fsref;
 
	FSSpec fsspec;
 
	short refnum = 0;
 
	short resid  = 0;
 

	
 
	assert(path != NULL);
 
	assert(moov != NULL);
 

	
 
	DEBUG(driver, 2, "qtmidi: start loading '%s'...", path);
 

	
 
	/*
 
	 * XXX Manual check for MIDI header ('MThd'), as I don't know how to make
 
	 * QuickTime load MIDI files without a .mid suffix without knowing it's
 
	 * a MIDI file and setting the OSType of the file to the 'Midi' value.
 
	 * Perhahaps ugly, but it seems that it does the Right Thing(tm).
 
	 */
 
	fd = open(path, O_RDONLY, 0);
 
	if (fd == -1) return false;
 
	ret = read(fd, magic, 4);
 
	close(fd);
 
	if (ret < 4) return false;
 

	
 
	DEBUG(driver, 3, "qtmidi: header is '%.4s'", magic);
 
	if (magic[0] != 'M' || magic[1] != 'T' || magic[2] != 'h' || magic[3] != 'd') {
 
		return false;
 
	}
 

	
 
	if (noErr != FSPathMakeRef((const UInt8 *) path, &fsref, NULL)) return false;
 
	SetMIDITypeIfNeeded(&fsref);
 

	
 
	if (noErr != FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, &fsspec, NULL)) return false;
 
	if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false;
 
	DEBUG(driver, 3, "qtmidi: '%s' successfully opened", path);
 

	
 
	if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL,
 
				newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL)) {
 
		CloseMovieFile(refnum);
 
		return false;
 
	}
 
	DEBUG(driver, 3, "qtmidi: movie container created");
 

	
 
	CloseMovieFile(refnum);
 
	return true;
 
}
 

	
 

	
 
/**
 
 * Flag which has the @c true value when QuickTime is available and
 
 * initialized.
 
 */
 
static bool _quicktime_started = false;
 

	
 

	
 
/**
 
 * Initialize QuickTime if needed. This function sets the
 
 * #_quicktime_started flag to @c true if QuickTime is present in the system
 
 * and it was initialized properly.
 
 */
 
static void InitQuickTimeIfNeeded()
 
{
 
	OSStatus dummy;
 

	
 
	if (_quicktime_started) return;
 

	
 
	DEBUG(driver, 2, "qtmidi: initializing Quicktime");
 
	/* Be polite: check wether QuickTime is available and initialize it. */
 
	_quicktime_started =
 
		(noErr == Gestalt(gestaltQuickTime, &dummy)) &&
 
		(noErr == EnterMovies());
 
	if (!_quicktime_started) DEBUG(driver, 0, "qtmidi: Quicktime initialization failed!");
 
}
 

	
 

	
 
/** Possible states of the QuickTime music driver. */
 
enum {
 
enum QTStates {
 
	QT_STATE_IDLE, ///< No file loaded.
 
	QT_STATE_PLAY, ///< File loaded, playing.
 
	QT_STATE_STOP, ///< File loaded, stopped.
 
};
 

	
 

	
 
static Movie _quicktime_movie;                  ///< Current QuickTime @c Movie.
 
static byte  _quicktime_volume = 127;           ///< Current volume.
 
static int   _quicktime_state  = QT_STATE_IDLE; ///< Current player state.
 

	
 

	
 
/**
 
 * Maps OpenTTD volume to QuickTime notion of volume.
 
 */
 
#define VOLUME  ((short)((0x00FF & _quicktime_volume) << 1))
 

	
 

	
 
/**
 
 * Initialized the MIDI player, including QuickTime initialization.
 
 *
 
 * @todo Give better error messages by inspecting error codes returned by
 
 * @c Gestalt() and @c EnterMovies(). Needs changes in
 
 * #InitQuickTimeIfNeeded.
 
 */
 
const char *MusicDriver_QtMidi::Start(const char * const *parm)
 
{
 
	InitQuickTimeIfNeeded();
 
	return (_quicktime_started) ? NULL : "can't initialize QuickTime";
 
}
 

	
 

	
 
/**
 
 * Checks wether the player is active.
 
 *
 
 * This function is called at regular intervals from OpenTTD's main loop, so
 
 * we call @c MoviesTask() from here to let QuickTime do its work.
 
 */
 
bool MusicDriver_QtMidi::IsSongPlaying()
 
{
 
	if (!_quicktime_started) return true;
 

	
 
	switch (_quicktime_state) {
 
		case QT_STATE_IDLE:
 
		case QT_STATE_STOP:
 
			/* Do nothing. */
 
			break;
 

	
 
		case QT_STATE_PLAY:
 
			MoviesTask(_quicktime_movie, 0);
 
			/* Check wether movie ended. */
 
			if (IsMovieDone(_quicktime_movie) ||
 
					(GetMovieTime(_quicktime_movie, NULL) >=
 
					 GetMovieDuration(_quicktime_movie))) {
 
				_quicktime_state = QT_STATE_STOP;
 
			}
 
	}
 

	
 
	return _quicktime_state == QT_STATE_PLAY;
 
}
 

	
 

	
 
/**
 
 * Stops the MIDI player.
 
 *
 
 * Stops playing and frees any used resources before returning. As it
 
 * deinitilizes QuickTime, the #_quicktime_started flag is set to @c false.
 
 */
 
void MusicDriver_QtMidi::Stop()
 
{
 
	if (!_quicktime_started) return;
 

	
 
	DEBUG(driver, 2, "qtmidi: stopping driver...");
 
	switch (_quicktime_state) {
 
		case QT_STATE_IDLE:
 
			DEBUG(driver, 3, "qtmidi: stopping not needed, already idle");
 
			/* Do nothing. */
 
			break;
 

	
 
		case QT_STATE_PLAY:
 
			StopSong();
 
			/* Fall-through */
 

	
 
		case QT_STATE_STOP:
 
			DisposeMovie(_quicktime_movie);
 
	}
 

	
 
	ExitMovies();
 
	_quicktime_started = false;
 
}
 

	
 

	
 
/**
 
 * Starts playing a new song.
 
 *
 
 * @param filename Path to a MIDI file.
 
 */
src/network/network_chat_gui.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file network_chat_gui.cpp GUI for handling chat messages. */
 

	
 
#include <stdarg.h> /* va_list */
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
#include "../stdafx.h"
 
#include "../date_func.h"
 
#include "../gfx_func.h"
 
#include "../strings_func.h"
 
#include "../blitter/factory.hpp"
 
#include "../console_func.h"
 
#include "../video/video_driver.hpp"
 
#include "../table/sprites.h"
 
#include "../querystring_gui.h"
 
#include "../town.h"
 
#include "../window_func.h"
 
#include "../core/geometry_func.hpp"
 
#include "network.h"
 
#include "network_client.h"
 
#include "network_base.h"
 

	
 
#include "table/strings.h"
 

	
 
/* The draw buffer must be able to contain the chat message, client name and the "[All]" message,
 
 * some spaces and possible translations of [All] to other languages. */
 
assert_compile((int)DRAW_STRING_BUFFER >= (int)NETWORK_CHAT_LENGTH + NETWORK_NAME_LENGTH + 40);
 

	
 
enum {
 
	NETWORK_CHAT_LINE_SPACING = 3,
 
};
 
static const uint NETWORK_CHAT_LINE_SPACING = 3;
 

	
 
struct ChatMessage {
 
	char message[DRAW_STRING_BUFFER];
 
	TextColour colour;
 
	Date end_date;
 
};
 

	
 
/* used for chat window */
 
static ChatMessage *_chatmsg_list = NULL;
 
static bool _chatmessage_dirty = false;
 
static bool _chatmessage_visible = false;
 
static bool _chat_tab_completion_active;
 
static uint MAX_CHAT_MESSAGES = 0;
 

	
 
/* The chatbox grows from the bottom so the coordinates are pixels from
 
 * the left and pixels from the bottom. The height is the maximum height */
 
static PointDimension _chatmsg_box;
 
static uint8 *_chatmessage_backup = NULL;
 

	
 
static inline uint GetChatMessageCount()
 
{
 
	uint i = 0;
 
	for (; i < MAX_CHAT_MESSAGES; i++) {
 
		if (_chatmsg_list[i].message[0] == '\0') break;
 
	}
 

	
 
	return i;
 
}
 

	
 
/**
 
 * Add a text message to the 'chat window' to be shown
 
 * @param colour The colour this message is to be shown in
 
 * @param duration The duration of the chat message in game-days
 
 * @param message message itself in printf() style
 
 */
 
void CDECL NetworkAddChatMessage(TextColour colour, uint8 duration, const char *message, ...)
 
{
 
	char buf[DRAW_STRING_BUFFER];
 
	const char *bufp;
 
	va_list va;
 
	uint msg_count;
 
	uint16 lines;
 

	
 
	va_start(va, message);
 
	vsnprintf(buf, lengthof(buf), message, va);
 
	va_end(va);
 

	
 
	Utf8TrimString(buf, DRAW_STRING_BUFFER);
 

	
 
	/* Force linebreaks for strings that are too long */
 
	lines = GB(FormatStringLinebreaks(buf, lastof(buf), _chatmsg_box.width - 8), 0, 16) + 1;
 
	if (lines >= MAX_CHAT_MESSAGES) return;
 

	
 
	msg_count = GetChatMessageCount();
 
	/* We want to add more chat messages than there is free space for, remove 'old' */
 
	if (lines > MAX_CHAT_MESSAGES - msg_count) {
 
		int i = lines - (MAX_CHAT_MESSAGES - msg_count);
 
		memmove(&_chatmsg_list[0], &_chatmsg_list[i], sizeof(_chatmsg_list[0]) * (msg_count - i));
 
		msg_count = MAX_CHAT_MESSAGES - lines;
 
	}
 

	
 
	for (bufp = buf; lines != 0; lines--) {
 
		ChatMessage *cmsg = &_chatmsg_list[msg_count++];
 
		strecpy(cmsg->message, bufp, lastof(cmsg->message));
 

	
 
		/* The default colour for a message is company colour. Replace this with
 
		 * white for any additional lines */
 
		cmsg->colour = (bufp == buf && (colour & IS_PALETTE_COLOUR)) ? colour : TC_WHITE;
 
		cmsg->end_date = _date + duration;
 

	
 
		bufp += strlen(bufp) + 1; // jump to 'next line' in the formatted string
 
	}
 

	
 
	_chatmessage_dirty = true;
 
}
 

	
 
void NetworkInitChatMessage()
 
{
 
	MAX_CHAT_MESSAGES    = _settings_client.gui.network_chat_box_height;
 

	
 
	_chatmsg_list        = ReallocT(_chatmsg_list, _settings_client.gui.network_chat_box_height);
 
	_chatmsg_box.x       = 10;
 
	_chatmsg_box.y       = 3 * FONT_HEIGHT_NORMAL;
 
	_chatmsg_box.width   = _settings_client.gui.network_chat_box_width;
 
	_chatmsg_box.height  = _settings_client.gui.network_chat_box_height * (FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING) + 2;
 
	_chatmessage_backup  = ReallocT(_chatmessage_backup, _chatmsg_box.width * _chatmsg_box.height * BlitterFactoryBase::GetCurrentBlitter()->GetBytesPerPixel());
 
	_chatmessage_visible = false;
 

	
 
	for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) {
 
		_chatmsg_list[i].message[0] = '\0';
 
	}
 
}
 

	
 
/** Hide the chatbox */
 
void NetworkUndrawChatMessage()
 
{
src/network/network_content_gui.cpp
Show inline comments
 
@@ -132,196 +132,194 @@ public:
 

	
 
		/* Always invalidate the download window; tell it we are going to be gone */
 
		InvalidateWindowData(WC_NETWORK_WINDOW, 1, 2);
 
		_network_content_client.RemoveCallback(this);
 
	}
 

	
 
	virtual void OnPaint()
 
	{
 
		this->DrawWidgets();
 
	}
 

	
 
	virtual void DrawWidget(const Rect &r, int widget) const
 
	{
 
		if (widget != NCDSWW_BACKGROUND) return;
 

	
 
		/* Draw nice progress bar :) */
 
		DrawFrameRect(r.left + 20, r.top + 4, r.left + 20 + (int)((this->width - 40LL) * this->downloaded_bytes / this->total_bytes), r.top + 14, COLOUR_MAUVE, FR_NONE);
 

	
 
		int y = r.top + 20;
 
		SetDParam(0, this->downloaded_bytes);
 
		SetDParam(1, this->total_bytes);
 
		SetDParam(2, this->downloaded_bytes * 100LL / this->total_bytes);
 
		DrawString(r.left + 2, r.right - 2, y, STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, TC_FROMSTRING, SA_CENTER);
 

	
 
		StringID str;
 
		if (this->downloaded_bytes == this->total_bytes) {
 
			str = STR_CONTENT_DOWNLOAD_COMPLETE;
 
		} else if (!StrEmpty(this->name)) {
 
			SetDParamStr(0, this->name);
 
			SetDParam(1, this->downloaded_files);
 
			SetDParam(2, this->total_files);
 
			str = STR_CONTENT_DOWNLOAD_FILE;
 
		} else {
 
			str = STR_CONTENT_DOWNLOAD_INITIALISE;
 
		}
 

	
 
		y += FONT_HEIGHT_NORMAL + 5;
 
		DrawStringMultiLine(r.left + 2, r.right - 2, y, y + FONT_HEIGHT_NORMAL * 2, str, TC_FROMSTRING, SA_CENTER);
 
	}
 

	
 
	virtual void OnClick(Point pt, int widget, int click_count)
 
	{
 
		if (widget == NCDSWW_CANCELOK) {
 
			if (this->downloaded_bytes != this->total_bytes) _network_content_client.Close();
 
			delete this;
 
		}
 
	}
 

	
 
	virtual void OnDownloadProgress(const ContentInfo *ci, uint bytes)
 
	{
 
		if (ci->id != this->cur_id) {
 
			strecpy(this->name, ci->filename, lastof(this->name));
 
			this->cur_id = ci->id;
 
			this->downloaded_files++;
 
			this->receivedTypes.Include(ci->type);
 
		}
 
		this->downloaded_bytes += bytes;
 

	
 
		/* When downloading is finished change cancel in ok */
 
		if (this->downloaded_bytes == this->total_bytes) {
 
			this->GetWidget<NWidgetCore>(NCDSWW_CANCELOK)->widget_data = STR_BUTTON_OK;
 
		}
 

	
 
		this->SetDirty();
 
	}
 
};
 

	
 
/** Widgets of the content list window. */
 
enum NetworkContentListWindowWidgets {
 
	NCLWW_BACKGROUND,    ///< Resize button
 

	
 
	NCLWW_FILTER_CAPT,   ///< Caption for the filter editbox
 
	NCLWW_FILTER,        ///< Filter editbox
 

	
 
	NCLWW_CHECKBOX,      ///< Button above checkboxes
 
	NCLWW_TYPE,          ///< 'Type' button
 
	NCLWW_NAME,          ///< 'Name' button
 

	
 
	NCLWW_MATRIX,        ///< Panel with list of content
 
	NCLWW_SCROLLBAR,     ///< Scrollbar of matrix
 

	
 
	NCLWW_DETAILS,       ///< Panel with content details
 

	
 
	NCLWW_SELECT_ALL,    ///< 'Select all' button
 
	NCLWW_SELECT_UPDATE, ///< 'Select updates' button
 
	NCLWW_UNSELECT,      ///< 'Unselect all' button
 
	NCLWW_CANCEL,        ///< 'Cancel' button
 
	NCLWW_DOWNLOAD,      ///< 'Download' button
 

	
 
	NCLWW_SEL_ALL_UPDATE, ///< #NWID_SELECTION widget for select all/update buttons.
 
};
 

	
 
/** Window that lists the content that's at the content server */
 
class NetworkContentListWindow : public QueryStringBaseWindow, ContentCallback {
 
	typedef GUIList<const ContentInfo*> GUIContentList;
 

	
 
	enum {
 
		EDITBOX_MAX_SIZE = 50,
 
		EDITBOX_MAX_LENGTH = 300,
 
	};
 
	static const uint EDITBOX_MAX_SIZE   =  50;
 
	static const uint EDITBOX_MAX_LENGTH = 300;
 

	
 
	/** Runtime saved values */
 
	static Listing last_sorting;
 
	static Filtering last_filtering;
 
	/** The sorter functions */
 
	static GUIContentList::SortFunction * const sorter_funcs[];
 
	static GUIContentList::FilterFunction * const filter_funcs[];
 
	GUIContentList content;      ///< List with content
 

	
 
	const ContentInfo *selected; ///< The selected content info
 
	int list_pos;                ///< Our position in the list
 
	uint filesize_sum;           ///< The sum of all selected file sizes
 

	
 
	/**
 
	 * (Re)build the network game list as its amount has changed because
 
	 * an item has been added or deleted for example
 
	 */
 
	void BuildContentList()
 
	{
 
		if (!this->content.NeedRebuild()) return;
 

	
 
		/* Create temporary array of games to use for listing */
 
		this->content.Clear();
 

	
 
		for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) {
 
			*this->content.Append() = *iter;
 
		}
 

	
 
		this->FilterContentList();
 
		this->content.Compact();
 
		this->content.RebuildDone();
 
		this->SortContentList();
 

	
 
		this->vscroll.SetCount(this->content.Length()); // Update the scrollbar
 
		this->ScrollToSelected();
 
	}
 

	
 
	/** Sort content by name. */
 
	static int CDECL NameSorter(const ContentInfo * const *a, const ContentInfo * const *b)
 
	{
 
		return strcasecmp((*a)->name, (*b)->name);
 
	}
 

	
 
	/** Sort content by type. */
 
	static int CDECL TypeSorter(const ContentInfo * const *a, const ContentInfo * const *b)
 
	{
 
		int r = 0;
 
		if ((*a)->type != (*b)->type) {
 
			char a_str[64];
 
			char b_str[64];
 
			GetString(a_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*a)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(a_str));
 
			GetString(b_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*b)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(b_str));
 
			r = strcasecmp(a_str, b_str);
 
		}
 
		if (r == 0) r = NameSorter(a, b);
 
		return r;
 
	}
 

	
 
	/** Sort content by state. */
 
	static int CDECL StateSorter(const ContentInfo * const *a, const ContentInfo * const *b)
 
	{
 
		int r = (*a)->state - (*b)->state;
 
		if (r == 0) r = TypeSorter(a, b);
 
		return r;
 
	}
 

	
 
	/** Sort the content list */
 
	void SortContentList()
 
	{
 
		if (!this->content.Sort()) return;
 

	
 
		for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
 
			if (*iter == this->selected) {
 
				this->list_pos = iter - this->content.Begin();
 
				break;
 
			}
 
		}
 
	}
 

	
 
	/** Filter content by tags/name */
 
	static bool CDECL TagNameFilter(const ContentInfo * const *a, const char *filter_string)
 
	{
 
		for (int i = 0; i < (*a)->tag_count; i++) {
 
			if (strcasestr((*a)->tags[i], filter_string) != NULL) return true;
 
		}
 
		return strcasestr((*a)->name, filter_string) != NULL;
 
	}
 

	
 
	/** Filter the content list */
 
	void FilterContentList()
 
	{
 
		if (!this->content.Filter(this->edit_str_buf)) return;
 

	
 
		/* update list position */
 
		for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
 
			if (*iter == this->selected) {
src/network/network_gamelist.cpp
Show inline comments
 
@@ -39,157 +39,155 @@ void NetworkGameListAddItemDelayed(Netwo
 
}
 

	
 
/** Perform the delayed (thread safe) insertion into the game list */
 
static void NetworkGameListHandleDelayedInsert()
 
{
 
	_network_game_list_mutex->BeginCritical();
 
	while (_network_game_delayed_insertion_list != NULL) {
 
		NetworkGameList *ins_item = _network_game_delayed_insertion_list;
 
		_network_game_delayed_insertion_list = ins_item->next;
 

	
 
		NetworkGameList *item = NetworkGameListAddItem(ins_item->address);
 

	
 
		if (item != NULL) {
 
			if (StrEmpty(item->info.server_name)) {
 
				ClearGRFConfigList(&item->info.grfconfig);
 
				memset(&item->info, 0, sizeof(item->info));
 
				strecpy(item->info.server_name, ins_item->info.server_name, lastof(item->info.server_name));
 
				strecpy(item->info.hostname, ins_item->info.hostname, lastof(item->info.hostname));
 
				item->online = false;
 
			}
 
			item->manually |= ins_item->manually;
 
			if (item->manually) NetworkRebuildHostList();
 
			UpdateNetworkGameWindow(false);
 
		}
 
		free(ins_item);
 
	}
 
	_network_game_list_mutex->EndCritical();
 
}
 

	
 
/** Add a new item to the linked gamelist. If the IP and Port match
 
 * return the existing item instead of adding it again
 
 * @param address the address of the to-be added item
 
 * @param port the port the server is running on
 
 * @return a point to the newly added or already existing item */
 
NetworkGameList *NetworkGameListAddItem(NetworkAddress address)
 
{
 
	const char *hostname = address.GetHostname();
 

	
 
	/* Do not query the 'any' address. */
 
	if (StrEmpty(hostname) ||
 
			strcmp(hostname, "0.0.0.0") == 0 ||
 
			strcmp(hostname, "::") == 0) {
 
		return NULL;
 
	}
 

	
 
	NetworkGameList *item, *prev_item;
 

	
 
	prev_item = NULL;
 
	for (item = _network_game_list; item != NULL; item = item->next) {
 
		if (item->address == address) return item;
 
		prev_item = item;
 
	}
 

	
 
	item = CallocT<NetworkGameList>(1);
 
	item->next = NULL;
 
	item->address = address;
 

	
 
	if (prev_item == NULL) {
 
		_network_game_list = item;
 
	} else {
 
		prev_item->next = item;
 
	}
 
	DEBUG(net, 4, "[gamelist] added server to list");
 

	
 
	UpdateNetworkGameWindow(false);
 

	
 
	return item;
 
}
 

	
 
/** Remove an item from the gamelist linked list
 
 * @param remove pointer to the item to be removed */
 
void NetworkGameListRemoveItem(NetworkGameList *remove)
 
{
 
	NetworkGameList *prev_item = NULL;
 
	for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) {
 
		if (remove == item) {
 
			if (prev_item == NULL) {
 
				_network_game_list = remove->next;
 
			} else {
 
				prev_item->next = remove->next;
 
			}
 

	
 
			/* Remove GRFConfig information */
 
			ClearGRFConfigList(&remove->info.grfconfig);
 
			free(remove);
 
			remove = NULL;
 

	
 
			DEBUG(net, 4, "[gamelist] removed server from list");
 
			NetworkRebuildHostList();
 
			UpdateNetworkGameWindow(false);
 
			return;
 
		}
 
		prev_item = item;
 
	}
 
}
 

	
 
enum {
 
	MAX_GAME_LIST_REQUERY_COUNT  = 10, ///< How often do we requery in number of times per server?
 
	REQUERY_EVERY_X_GAMELOOPS    = 60, ///< How often do we requery in time?
 
	REFRESH_GAMEINFO_X_REQUERIES = 50, ///< Refresh the game info itself after REFRESH_GAMEINFO_X_REQUERIES * REQUERY_EVERY_X_GAMELOOPS game loops
 
};
 
static const uint MAX_GAME_LIST_REQUERY_COUNT  = 10; ///< How often do we requery in number of times per server?
 
static const uint REQUERY_EVERY_X_GAMELOOPS    = 60; ///< How often do we requery in time?
 
static const uint REFRESH_GAMEINFO_X_REQUERIES = 50; ///< Refresh the game info itself after REFRESH_GAMEINFO_X_REQUERIES * REQUERY_EVERY_X_GAMELOOPS game loops
 

	
 
/** Requeries the (game) servers we have not gotten a reply from */
 
void NetworkGameListRequery()
 
{
 
	NetworkGameListHandleDelayedInsert();
 

	
 
	static uint8 requery_cnt = 0;
 

	
 
	if (++requery_cnt < REQUERY_EVERY_X_GAMELOOPS) return;
 
	requery_cnt = 0;
 

	
 
	for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) {
 
		item->retries++;
 
		if (item->retries < REFRESH_GAMEINFO_X_REQUERIES && (item->online || item->retries >= MAX_GAME_LIST_REQUERY_COUNT)) continue;
 

	
 
		/* item gets mostly zeroed by NetworkUDPQueryServer */
 
		uint8 retries = item->retries;
 
		NetworkUDPQueryServer(NetworkAddress(item->address));
 
		item->retries = (retries >= REFRESH_GAMEINFO_X_REQUERIES) ? 0 : retries;
 
	}
 
}
 

	
 
/**
 
 * Rebuild the GRFConfig's of the servers in the game list as we did
 
 * a rescan and might have found new NewGRFs.
 
 */
 
void NetworkAfterNewGRFScan()
 
{
 
	for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) {
 
		/* Reset compatability state */
 
		item->info.compatible = item->info.version_compatible;
 

	
 
		for (GRFConfig *c = item->info.grfconfig; c != NULL; c = c->next) {
 
			assert(HasBit(c->flags, GCF_COPY));
 

	
 
			const GRFConfig *f = FindGRFConfig(c->ident.grfid, c->ident.md5sum);
 
			if (f == NULL) {
 
				/* Don't know the GRF, so mark game incompatible and the (possibly)
 
				 * already resolved name for this GRF (another server has sent the
 
				 * name of the GRF already */
 
				c->name   = FindUnknownGRFName(c->ident.grfid, c->ident.md5sum, true);
 
				c->status = GCS_NOT_FOUND;
 

	
 
				/* If we miss a file, we're obviously incompatible */
 
				item->info.compatible = false;
 
			} else {
 
				c->filename  = f->filename;
 
				c->name      = f->name;
 
				c->info      = f->info;
 
				c->status    = GCS_UNKNOWN;
 
			}
 
		}
 
	}
 
}
 

	
 
#endif /* ENABLE_NETWORK */
src/network/network_udp.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/**
 
 * @file network_udp.cpp This file handles the UDP related communication.
 
 *
 
 * This is the GameServer <-> MasterServer and GameServer <-> GameClient
 
 * communication before the game is being joined.
 
 */
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
#include "../stdafx.h"
 
#include "../date_func.h"
 
#include "../map_func.h"
 
#include "../debug.h"
 
#include "network_gamelist.h"
 
#include "network_internal.h"
 
#include "network_udp.h"
 
#include "network.h"
 
#include "../core/endian_func.hpp"
 
#include "../company_base.h"
 
#include "../thread/thread.h"
 
#include "../rev.h"
 

	
 
#include "core/udp.h"
 

	
 
static ThreadMutex *_network_udp_mutex = ThreadMutex::New();
 

	
 
/** Session key to register ourselves to the master server */
 
static uint64 _session_key = 0;
 

	
 
enum {
 
	ADVERTISE_NORMAL_INTERVAL = 30000, // interval between advertising in ticks (15 minutes)
 
	ADVERTISE_RETRY_INTERVAL  =   300, // readvertise when no response after this many ticks (9 seconds)
 
	ADVERTISE_RETRY_TIMES     =     3  // give up readvertising after this much failed retries
 
};
 
static const uint ADVERTISE_NORMAL_INTERVAL = 30000; ///< interval between advertising in ticks (15 minutes)
 
static const uint ADVERTISE_RETRY_INTERVAL  =   300; ///< readvertise when no response after this many ticks (9 seconds)
 
static const uint ADVERTISE_RETRY_TIMES     =     3; ///< give up readvertising after this much failed retries
 

	
 
NetworkUDPSocketHandler *_udp_client_socket = NULL; ///< udp client socket
 
NetworkUDPSocketHandler *_udp_server_socket = NULL; ///< udp server socket
 
NetworkUDPSocketHandler *_udp_master_socket = NULL; ///< udp master socket
 

	
 
///*** Communication with the masterserver ***/
 

	
 
class MasterNetworkUDPSocketHandler : public NetworkUDPSocketHandler {
 
protected:
 
	DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER);
 
	DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_SESSION_KEY);
 
public:
 
	MasterNetworkUDPSocketHandler(NetworkAddressList *addresses) : NetworkUDPSocketHandler(addresses) {}
 
	virtual ~MasterNetworkUDPSocketHandler() {}
 
};
 

	
 
DEF_UDP_RECEIVE_COMMAND(Master, PACKET_UDP_MASTER_ACK_REGISTER)
 
{
 
	_network_advertise_retries = 0;
 
	DEBUG(net, 2, "[udp] advertising on master server successful (%s)", NetworkAddress::AddressFamilyAsString(client_addr->GetAddress()->ss_family));
 

	
 
	/* We are advertised, but we don't want to! */
 
	if (!_settings_client.network.server_advertise) NetworkUDPRemoveAdvertise(false);
 
}
 

	
 
DEF_UDP_RECEIVE_COMMAND(Master, PACKET_UDP_MASTER_SESSION_KEY)
 
{
 
	_session_key = p->Recv_uint64();
 
	DEBUG(net, 2, "[udp] received new session key from master server (%s)", NetworkAddress::AddressFamilyAsString(client_addr->GetAddress()->ss_family));
 
}
 

	
 
///*** Communication with clients (we are server) ***/
 

	
 
class ServerNetworkUDPSocketHandler : public NetworkUDPSocketHandler {
 
protected:
 
	DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER);
 
	DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO);
 
	DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS);
 
public:
 
	ServerNetworkUDPSocketHandler(NetworkAddressList *addresses) : NetworkUDPSocketHandler(addresses) {}
 
	virtual ~ServerNetworkUDPSocketHandler() {}
 
};
 

	
 
DEF_UDP_RECEIVE_COMMAND(Server, PACKET_UDP_CLIENT_FIND_SERVER)
 
{
 
	/* Just a fail-safe.. should never happen */
 
	if (!_network_udp_server) {
 
		return;
 
	}
 

	
 
	NetworkGameInfo ngi;
 

	
 
	/* Update some game_info */
 
	ngi.clients_on     = _network_game_info.clients_on;
 
	ngi.start_date     = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
 

	
 
	ngi.server_lang    = _settings_client.network.server_lang;
 
	ngi.use_password   = !StrEmpty(_settings_client.network.server_password);
 
	ngi.clients_max    = _settings_client.network.max_clients;
 
	ngi.companies_on   = (byte)Company::GetNumItems();
 
	ngi.companies_max  = _settings_client.network.max_companies;
 
	ngi.spectators_on  = NetworkSpectatorCount();
 
	ngi.spectators_max = _settings_client.network.max_spectators;
 
	ngi.game_date      = _date;
 
	ngi.map_width      = MapSizeX();
 
	ngi.map_height     = MapSizeY();
 
	ngi.map_set        = _settings_game.game_creation.landscape;
 
	ngi.dedicated      = _network_dedicated;
 
	ngi.grfconfig      = _grfconfig;
 

	
 
	strecpy(ngi.map_name, _network_game_info.map_name, lastof(ngi.map_name));
 
	strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name));
 
	strecpy(ngi.server_revision, _openttd_revision, lastof(ngi.server_revision));
 

	
 
	Packet packet(PACKET_UDP_SERVER_RESPONSE);
 
	this->Send_NetworkGameInfo(&packet, &ngi);
 

	
 
	/* Let the client know that we are here */
 
	this->SendPacket(&packet, client_addr);
 

	
 
	DEBUG(net, 2, "[udp] queried from %s", client_addr->GetHostname());
 
}
 

	
 
DEF_UDP_RECEIVE_COMMAND(Server, PACKET_UDP_CLIENT_DETAIL_INFO)
 
{
 
	/* Just a fail-safe.. should never happen */
 
	if (!_network_udp_server) return;
 

	
 
	Packet packet(PACKET_UDP_SERVER_DETAIL_INFO);
 

	
 
	/* Send the amount of active companies */
 
	packet.Send_uint8 (NETWORK_COMPANY_INFO_VERSION);
 
	packet.Send_uint8 ((uint8)Company::GetNumItems());
 

	
 
	/* Fetch the latest version of the stats */
 
	NetworkCompanyStats company_stats[MAX_COMPANIES];
src/newgrf.cpp
Show inline comments
 
@@ -87,195 +87,193 @@ enum GrfDataType {
 
	GDT_SOUND,
 
};
 

	
 
static byte _grf_data_blocks;
 
static GrfDataType _grf_data_type;
 

	
 
class OTTDByteReaderSignal { };
 

	
 
class ByteReader {
 
protected:
 
	byte *data;
 
	byte *end;
 

	
 
public:
 
	ByteReader(byte *data, byte *end) : data(data), end(end) { }
 

	
 
	FORCEINLINE byte ReadByte()
 
	{
 
		if (data < end) return *(data)++;
 
		throw OTTDByteReaderSignal();
 
	}
 

	
 
	uint16 ReadWord()
 
	{
 
		uint16 val = ReadByte();
 
		return val | (ReadByte() << 8);
 
	}
 

	
 
	uint16 ReadExtendedByte()
 
	{
 
		uint16 val = ReadByte();
 
		return val == 0xFF ? ReadWord() : val;
 
	}
 

	
 
	uint32 ReadDWord()
 
	{
 
		uint32 val = ReadWord();
 
		return val | (ReadWord() << 16);
 
	}
 

	
 
	uint32 ReadVarSize(byte size)
 
	{
 
		switch (size) {
 
			case 1: return ReadByte();
 
			case 2: return ReadWord();
 
			case 4: return ReadDWord();
 
			default:
 
				NOT_REACHED();
 
				return 0;
 
		}
 
	}
 

	
 
	const char *ReadString()
 
	{
 
		char *string = reinterpret_cast<char *>(data);
 
		size_t string_length = ttd_strnlen(string, Remaining());
 

	
 
		if (string_length == Remaining()) {
 
			/* String was not NUL terminated, so make sure it is now. */
 
			string[string_length - 1] = '\0';
 
			grfmsg(7, "String was not terminated with a zero byte.");
 
		} else {
 
			/* Increase the string length to include the NUL byte. */
 
			string_length++;
 
		}
 
		Skip(string_length);
 

	
 
		return string;
 
	}
 

	
 
	FORCEINLINE size_t Remaining() const
 
	{
 
		return end - data;
 
	}
 

	
 
	FORCEINLINE bool HasData() const
 
	{
 
		return data < end;
 
	}
 

	
 
	FORCEINLINE byte *Data()
 
	{
 
		return data;
 
	}
 

	
 
	FORCEINLINE void Skip(size_t len)
 
	{
 
		data += len;
 
		/* It is valid to move the buffer to exactly the end of the data,
 
		 * as there may not be any more data read. */
 
		if (data > end) throw OTTDByteReaderSignal();
 
	}
 
};
 

	
 
typedef void (*SpecialSpriteHandler)(ByteReader *buf);
 

	
 
enum {
 
	MAX_STATIONS = 256,
 
};
 
static const uint MAX_STATIONS = 256;
 

	
 
/* Temporary data used when loading only */
 
struct GRFTempEngineData {
 
	uint16 cargo_allowed;
 
	uint16 cargo_disallowed;
 
	RailTypeLabel railtypelabel;
 
	bool refitmask_valid;    ///< Did the newgrf set any refittability property? If not, default refittability will be applied.
 
	uint8 rv_max_speed;      ///< Temporary storage of RV prop 15, maximum speed in mph/0.8
 
};
 

	
 
static GRFTempEngineData *_gted;
 

	
 
/* Contains the GRF ID of the owner of a vehicle if it has been reserved.
 
 * GRM for vehicles is only used if dynamic engine allocation is disabled,
 
 * so 256 is the number of original engines. */
 
static uint32 _grm_engines[256];
 

	
 
/* Contains the GRF ID of the owner of a cargo if it has been reserved */
 
static uint32 _grm_cargos[NUM_CARGO * 2];
 

	
 
struct GRFLocation {
 
	uint32 grfid;
 
	uint32 nfoline;
 

	
 
	GRFLocation(uint32 grfid, uint32 nfoline) : grfid(grfid), nfoline(nfoline) { }
 

	
 
	bool operator<(const GRFLocation &other) const
 
	{
 
		return this->grfid < other.grfid || (this->grfid == other.grfid && this->nfoline < other.nfoline);
 
	}
 

	
 
	bool operator == (const GRFLocation &other) const
 
	{
 
		return this->grfid == other.grfid && this->nfoline == other.nfoline;
 
	}
 
};
 

	
 
static std::map<GRFLocation, SpriteID> _grm_sprites;
 
typedef std::map<GRFLocation, byte*> GRFLineToSpriteOverride;
 
static GRFLineToSpriteOverride _grf_line_to_action6_sprite_override;
 

	
 
/** DEBUG() function dedicated to newGRF debugging messages
 
 * Function is essentialy the same as DEBUG(grf, severity, ...) with the
 
 * addition of file:line information when parsing grf files.
 
 * NOTE: for the above reason(s) grfmsg() should ONLY be used for
 
 * loading/parsing grf files, not for runtime debug messages as there
 
 * is no file information available during that time.
 
 * @param severity debugging severity level, see debug.h
 
 * @param str message in printf() format */
 
void CDECL grfmsg(int severity, const char *str, ...)
 
{
 
	char buf[1024];
 
	va_list va;
 

	
 
	va_start(va, str);
 
	vsnprintf(buf, sizeof(buf), str, va);
 
	va_end(va);
 

	
 
	DEBUG(grf, severity, "[%s:%d] %s", _cur_grfconfig->filename, _nfo_line, buf);
 
}
 

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

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

	
 
/** Reset all NewGRFData that was used only while processing data */
 
static void ClearTemporaryNewGRFData(GRFFile *gf)
 
{
 
	/* Clear the GOTO labels used for GRF processing */
 
	for (GRFLabel *l = gf->label; l != NULL;) {
 
		GRFLabel *l2 = l->next;
 
		free(l);
 
		l = l2;
 
	}
 
	gf->label = NULL;
 

	
 
	/* Clear the list of spritegroups */
 
	free(gf->spritegroups);
 
	gf->spritegroups = NULL;
 
	gf->spritegroups_count = 0;
 
}
 

	
 
@@ -6516,193 +6514,193 @@ static void FinaliseHouseArray()
 

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

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

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

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

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

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

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

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

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

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

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

	
 
	for (uint j = 0; j < NUM_INDUSTRYTYPES; j++) {
 
		IndustrySpec *indsp = &_industry_specs[j];
 
		if (indsp->enabled && indsp->grf_prop.grffile != NULL) {
 
			for (uint i = 0; i < 3; i++) {
 
				indsp->conflicting[i] = MapNewGRFIndustryType(indsp->conflicting[i], indsp->grf_prop.grffile->grfid);
 
			}
 
		}
 
	}
 
}
 

	
 
/**
 
 * Add all new airports to the airport array. Airport properties can be set at any
 
 * time in the GRF file, so we can only add a airport spec to the airport array
 
 * after the file has finished loading.
 
 */
 
static void FinaliseAirportsArray()
 
{
 
	const GRFFile * const *end = _grf_files.End();
 
	for (GRFFile **file = _grf_files.Begin(); file != end; file++) {
 
		AirportSpec **&airportspec = (*file)->airportspec;
 
		if (airportspec != NULL) {
 
			for (int i = 0; i < NUM_AIRPORTS; i++) {
 
				if (airportspec[i] != NULL && airportspec[i]->enabled) {
 
					_airport_mngr.SetEntitySpec(airportspec[i]);
 
				}
 
			}
 
		}
 

	
 
		AirportTileSpec **&airporttilespec = (*file)->airtspec;
 
		if (airporttilespec != NULL) {
 
			for (int i = 0; i < NUM_AIRPORTTILES; i++) {
 
			for (uint i = 0; i < NUM_AIRPORTTILES; i++) {
 
				if (airporttilespec[i] != NULL && airporttilespec[i]->enabled) {
 
					_airporttile_mngr.SetEntitySpec(airporttilespec[i]);
 
				}
 
			}
 
		}
 
	}
 
}
 

	
 
/* Here we perform initial decoding of some special sprites (as are they
 
 * described at http://www.ttdpatch.net/src/newgrf.txt, but this is only a very
 
 * partial implementation yet).
 
 * XXX: We consider GRF files trusted. It would be trivial to exploit OTTD by
 
 * a crafted invalid GRF file. We should tell that to the user somehow, or
 
 * better make this more robust in the future. */
 
static void DecodeSpecialSprite(byte *buf, uint num, GrfLoadingStage stage)
 
{
 
	/* XXX: There is a difference between staged loading in TTDPatch and
 
	 * here.  In TTDPatch, for some reason actions 1 and 2 are carried out
 
	 * during stage 1, whilst action 3 is carried out during stage 2 (to
 
	 * "resolve" cargo IDs... wtf). This is a little problem, because cargo
 
	 * IDs are valid only within a given set (action 1) block, and may be
 
	 * overwritten after action 3 associates them. But overwriting happens
 
	 * in an earlier stage than associating, so...  We just process actions
 
	 * 1 and 2 in stage 2 now, let's hope that won't get us into problems.
 
	 * --pasky
 
	 * We need a pre-stage to set up GOTO labels of Action 0x10 because the grf
 
	 * is not in memory and scanning the file every time would be too expensive.
 
	 * In other stages we skip action 0x10 since it's already dealt with. */
 
	static const SpecialSpriteHandler handlers[][GLS_END] = {
 
		/* 0x00 */ { NULL,     SafeChangeInfo, NULL,       NULL,           ReserveChangeInfo, FeatureChangeInfo, },
 
		/* 0x01 */ { SkipAct1, SkipAct1,  SkipAct1,        SkipAct1,       SkipAct1,          NewSpriteSet, },
 
		/* 0x02 */ { NULL,     NULL,      NULL,            NULL,           NULL,              NewSpriteGroup, },
 
		/* 0x03 */ { NULL,     GRFUnsafe, NULL,            NULL,           NULL,              FeatureMapSpriteGroup, },
 
		/* 0x04 */ { NULL,     NULL,      NULL,            NULL,           NULL,              FeatureNewName, },
 
		/* 0x05 */ { SkipAct5, SkipAct5,  SkipAct5,        SkipAct5,       SkipAct5,          GraphicsNew, },
 
		/* 0x06 */ { NULL,     NULL,      NULL,            CfgApply,       CfgApply,          CfgApply, },
 
		/* 0x07 */ { NULL,     NULL,      NULL,            NULL,           SkipIf,            SkipIf, },
 
		/* 0x08 */ { ScanInfo, NULL,      NULL,            GRFInfo,        GRFInfo,           GRFInfo, },
 
		/* 0x09 */ { NULL,     NULL,      NULL,            SkipIf,         SkipIf,            SkipIf, },
 
		/* 0x0A */ { SkipActA, SkipActA,  SkipActA,        SkipActA,       SkipActA,          SpriteReplace, },
 
		/* 0x0B */ { NULL,     NULL,      NULL,            GRFLoadError,   GRFLoadError,      GRFLoadError, },
 
		/* 0x0C */ { NULL,     NULL,      NULL,            GRFComment,     NULL,              GRFComment, },
 
		/* 0x0D */ { NULL,     SafeParamSet, NULL,         ParamSet,       ParamSet,          ParamSet, },
 
		/* 0x0E */ { NULL,     SafeGRFInhibit, NULL,       GRFInhibit,     GRFInhibit,        GRFInhibit, },
 
		/* 0x0F */ { NULL,     GRFUnsafe, NULL,            FeatureTownName, NULL,             NULL, },
 
		/* 0x10 */ { NULL,     NULL,      DefineGotoLabel, NULL,           NULL,              NULL, },
 
		/* 0x11 */ { SkipAct11,GRFUnsafe, SkipAct11,       SkipAct11,      SkipAct11,         GRFSound, },
 
		/* 0x12 */ { SkipAct12, SkipAct12, SkipAct12,      SkipAct12,      SkipAct12,         LoadFontGlyph, },
 
		/* 0x13 */ { NULL,     NULL,      NULL,            NULL,           NULL,              TranslateGRFStrings, },
 
	};
 

	
 
	GRFLocation location(_cur_grfconfig->ident.grfid, _nfo_line);
 

	
 
	GRFLineToSpriteOverride::iterator it = _grf_line_to_action6_sprite_override.find(location);
 
	if (it == _grf_line_to_action6_sprite_override.end()) {
 
		/* No preloaded sprite to work with; read the
 
		 * pseudo sprite content. */
 
		FioReadBlock(buf, num);
 
	} else {
 
		/* Use the preloaded sprite data. */
 
		buf = _grf_line_to_action6_sprite_override[location];
 
		grfmsg(7, "DecodeSpecialSprite: Using preloaded pseudo sprite data");
 

	
 
		/* Skip the real (original) content of this action. */
 
		FioSeekTo(num, SEEK_CUR);
 
	}
 

	
 
	ByteReader br(buf, buf + num);
 
	ByteReader *bufp = &br;
 

	
 
	try {
 
		byte action = bufp->ReadByte();
 

	
 
		if (action == 0xFF) {
 
			grfmsg(7, "DecodeSpecialSprite: Handling data block in stage %d", stage);
 
			GRFDataBlock(bufp);
 
		} else if (action == 0xFE) {
 
			grfmsg(7, "DecodeSpecialSprite: Handling import block in stage %d", stage);
 
			GRFImportBlock(bufp);
 
		} else if (action >= lengthof(handlers)) {
 
			grfmsg(7, "DecodeSpecialSprite: Skipping unknown action 0x%02X", action);
 
		} else if (handlers[action][stage] == NULL) {
 
			grfmsg(7, "DecodeSpecialSprite: Skipping action 0x%02X in stage %d", action, stage);
 
		} else {
 
			grfmsg(7, "DecodeSpecialSprite: Handling action 0x%02X in stage %d", action, stage);
 
			handlers[action][stage](bufp);
 
		}
 
	} catch (...) {
 
		grfmsg(1, "DecodeSpecialSprite: Tried to read past end of pseudo-sprite data");
 

	
 
		_skip_sprites = -1;
 
		_cur_grfconfig->status = GCS_DISABLED;
 
		delete _cur_grfconfig->error;
 
		_cur_grfconfig->error  = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_READ_BOUNDS);
 
	}
 
}
src/newgrf_engine.cpp
Show inline comments
 
@@ -61,329 +61,329 @@ const SpriteGroup *GetWagonOverrideSprit
 
	 * for O(1). Or O(logMlogN) and searching binary tree or smt. like
 
	 * that. --pasky */
 

	
 
	for (uint i = 0; i < e->overrides_count; i++) {
 
		const WagonOverride *wo = &e->overrides[i];
 

	
 
		if (wo->cargo != cargo && wo->cargo != CT_DEFAULT) continue;
 

	
 
		for (uint j = 0; j < wo->trains; j++) {
 
			if (wo->train_id[j] == overriding_engine) return wo->group;
 
		}
 
	}
 
	return NULL;
 
}
 

	
 
/**
 
 * Unload all wagon override sprite groups.
 
 */
 
void UnloadWagonOverrides(Engine *e)
 
{
 
	for (uint i = 0; i < e->overrides_count; i++) {
 
		WagonOverride *wo = &e->overrides[i];
 
		free(wo->train_id);
 
	}
 
	free(e->overrides);
 
	e->overrides_count = 0;
 
	e->overrides = NULL;
 
}
 

	
 

	
 
void SetCustomEngineSprites(EngineID engine, byte cargo, const SpriteGroup *group)
 
{
 
	Engine *e = Engine::Get(engine);
 
	assert(cargo < lengthof(e->group));
 

	
 
	if (e->group[cargo] != NULL) {
 
		grfmsg(6, "SetCustomEngineSprites: engine %d cargo %d already has group -- replacing", engine, cargo);
 
	}
 
	e->group[cargo] = group;
 
}
 

	
 

	
 
/**
 
 * Tie a GRFFile entry to an engine, to allow us to retrieve GRF parameters
 
 * etc during a game.
 
 * @param engine Engine ID to tie the GRFFile to.
 
 * @param file   Pointer of GRFFile to tie.
 
 */
 
void SetEngineGRF(EngineID engine, const GRFFile *file)
 
{
 
	Engine *e = Engine::Get(engine);
 
	e->grffile = file;
 
}
 

	
 

	
 
/**
 
 * Retrieve the GRFFile tied to an engine
 
 * @param engine Engine ID to retrieve.
 
 * @return Pointer to GRFFile.
 
 */
 
const GRFFile *GetEngineGRF(EngineID engine)
 
{
 
	return Engine::Get(engine)->grffile;
 
}
 

	
 

	
 
/**
 
 * Retrieve the GRF ID of the GRFFile tied to an engine
 
 * @param engine Engine ID to retrieve.
 
 * @return 32 bit GRFID value.
 
 */
 
uint32 GetEngineGRFID(EngineID engine)
 
{
 
	const GRFFile *file = GetEngineGRF(engine);
 
	return file == NULL ? 0 : file->grfid;
 
}
 

	
 

	
 
static int MapOldSubType(const Vehicle *v)
 
{
 
	switch (v->type) {
 
		case VEH_TRAIN:
 
			if (Train::From(v)->IsEngine()) return 0;
 
			if (Train::From(v)->IsFreeWagon()) return 4;
 
			return 2;
 
		case VEH_ROAD:
 
		case VEH_SHIP:     return 0;
 
		case VEH_AIRCRAFT:
 
		case VEH_DISASTER: return v->subtype;
 
		case VEH_EFFECT:   return v->subtype << 1;
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 

	
 
/* TTDP style aircraft movement states for GRF Action 2 Var 0xE2 */
 
enum {
 
enum TTDPAircraftMovementStates {
 
	AMS_TTDP_HANGAR,
 
	AMS_TTDP_TO_HANGAR,
 
	AMS_TTDP_TO_PAD1,
 
	AMS_TTDP_TO_PAD2,
 
	AMS_TTDP_TO_PAD3,
 
	AMS_TTDP_TO_ENTRY_2_AND_3,
 
	AMS_TTDP_TO_ENTRY_2_AND_3_AND_H,
 
	AMS_TTDP_TO_JUNCTION,
 
	AMS_TTDP_LEAVE_RUNWAY,
 
	AMS_TTDP_TO_INWAY,
 
	AMS_TTDP_TO_RUNWAY,
 
	AMS_TTDP_TO_OUTWAY,
 
	AMS_TTDP_WAITING,
 
	AMS_TTDP_TAKEOFF,
 
	AMS_TTDP_TO_TAKEOFF,
 
	AMS_TTDP_CLIMBING,
 
	AMS_TTDP_FLIGHT_APPROACH,
 
	AMS_TTDP_UNUSED_0x11,
 
	AMS_TTDP_FLIGHT_TO_TOWER,
 
	AMS_TTDP_UNUSED_0x13,
 
	AMS_TTDP_FLIGHT_FINAL,
 
	AMS_TTDP_FLIGHT_DESCENT,
 
	AMS_TTDP_BRAKING,
 
	AMS_TTDP_HELI_TAKEOFF_AIRPORT,
 
	AMS_TTDP_HELI_TO_TAKEOFF_AIRPORT,
 
	AMS_TTDP_HELI_LAND_AIRPORT,
 
	AMS_TTDP_HELI_TAKEOFF_HELIPORT,
 
	AMS_TTDP_HELI_TO_TAKEOFF_HELIPORT,
 
	AMS_TTDP_HELI_LAND_HELIPORT,
 
};
 

	
 

	
 
/**
 
 * Map OTTD aircraft movement states to TTDPatch style movement states
 
 * (VarAction 2 Variable 0xE2)
 
 */
 
static byte MapAircraftMovementState(const Aircraft *v)
 
{
 
	const Station *st = GetTargetAirportIfValid(v);
 
	if (st == NULL) return AMS_TTDP_FLIGHT_TO_TOWER;
 

	
 
	const AirportFTAClass *afc = st->airport.GetFTA();
 
	uint16 amdflag = afc->MovingData(v->pos)->flag;
 

	
 
	switch (v->state) {
 
		case HANGAR:
 
			/* The international airport is a special case as helicopters can land in
 
			 * front of the hanger. Helicopters also change their air.state to
 
			 * AMED_HELI_LOWER some time before actually descending. */
 

	
 
			/* This condition only occurs for helicopters, during descent,
 
			 * to a landing by the hanger of an international airport. */
 
			if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT;
 

	
 
			/* This condition only occurs for helicopters, before starting descent,
 
			 * to a landing by the hanger of an international airport. */
 
			if (amdflag & AMED_SLOWTURN) return AMS_TTDP_FLIGHT_TO_TOWER;
 

	
 
			/* The final two conditions apply to helicopters or aircraft.
 
			 * Has reached hanger? */
 
			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_HANGAR;
 

	
 
			/* Still moving towards hanger. */
 
			return AMS_TTDP_TO_HANGAR;
 

	
 
		case TERM1:
 
			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD1;
 
			return AMS_TTDP_TO_JUNCTION;
 

	
 
		case TERM2:
 
			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD2;
 
			return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
 

	
 
		case TERM3:
 
		case TERM4:
 
		case TERM5:
 
		case TERM6:
 
		case TERM7:
 
		case TERM8:
 
			/* TTDPatch only has 3 terminals, so treat these states the same */
 
			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD3;
 
			return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
 

	
 
		case HELIPAD1:
 
		case HELIPAD2:
 
		case HELIPAD3:
 
		case HELIPAD4: // Will only occur for helicopters.
 
			if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT; // Descending.
 
			if (amdflag & AMED_SLOWTURN)   return AMS_TTDP_FLIGHT_TO_TOWER;   // Still hasn't started descent.
 
			return AMS_TTDP_TO_JUNCTION; // On the ground.
 

	
 
		case TAKEOFF: // Moving to takeoff position.
 
			return AMS_TTDP_TO_OUTWAY;
 

	
 
		case STARTTAKEOFF: // Accelerating down runway.
 
			return AMS_TTDP_TAKEOFF;
 

	
 
		case ENDTAKEOFF: // Ascent
 
			return AMS_TTDP_CLIMBING;
 

	
 
		case HELITAKEOFF: // Helicopter is moving to take off position.
 
			if (afc->delta_z == 0) {
 
				return amdflag & AMED_HELI_RAISE ?
 
					AMS_TTDP_HELI_TAKEOFF_AIRPORT : AMS_TTDP_TO_JUNCTION;
 
			} else {
 
				return AMS_TTDP_HELI_TAKEOFF_HELIPORT;
 
			}
 

	
 
		case FLYING:
 
			return amdflag & AMED_HOLD ? AMS_TTDP_FLIGHT_APPROACH : AMS_TTDP_FLIGHT_TO_TOWER;
 

	
 
		case LANDING: // Descent
 
			return AMS_TTDP_FLIGHT_DESCENT;
 

	
 
		case ENDLANDING: // On the runway braking
 
			if (amdflag & AMED_BRAKE) return AMS_TTDP_BRAKING;
 
			/* Landed - moving off runway */
 
			return AMS_TTDP_TO_INWAY;
 

	
 
		case HELILANDING:
 
		case HELIENDLANDING: // Helicoptor is decending.
 
			if (amdflag & AMED_HELI_LOWER) {
 
				return afc->delta_z == 0 ?
 
					AMS_TTDP_HELI_LAND_AIRPORT : AMS_TTDP_HELI_LAND_HELIPORT;
 
			} else {
 
				return AMS_TTDP_FLIGHT_TO_TOWER;
 
			}
 

	
 
		default:
 
			return AMS_TTDP_HANGAR;
 
	}
 
}
 

	
 

	
 
/* TTDP style aircraft movement action for GRF Action 2 Var 0xE6 */
 
enum {
 
enum TTDPAircraftMovementActions {
 
	AMA_TTDP_IN_HANGAR,
 
	AMA_TTDP_ON_PAD1,
 
	AMA_TTDP_ON_PAD2,
 
	AMA_TTDP_ON_PAD3,
 
	AMA_TTDP_HANGAR_TO_PAD1,
 
	AMA_TTDP_HANGAR_TO_PAD2,
 
	AMA_TTDP_HANGAR_TO_PAD3,
 
	AMA_TTDP_LANDING_TO_PAD1,
 
	AMA_TTDP_LANDING_TO_PAD2,
 
	AMA_TTDP_LANDING_TO_PAD3,
 
	AMA_TTDP_PAD1_TO_HANGAR,
 
	AMA_TTDP_PAD2_TO_HANGAR,
 
	AMA_TTDP_PAD3_TO_HANGAR,
 
	AMA_TTDP_PAD1_TO_TAKEOFF,
 
	AMA_TTDP_PAD2_TO_TAKEOFF,
 
	AMA_TTDP_PAD3_TO_TAKEOFF,
 
	AMA_TTDP_HANGAR_TO_TAKOFF,
 
	AMA_TTDP_LANDING_TO_HANGAR,
 
	AMA_TTDP_IN_FLIGHT,
 
};
 

	
 

	
 
/**
 
 * Map OTTD aircraft movement states to TTDPatch style movement actions
 
 * (VarAction 2 Variable 0xE6)
 
 * This is not fully supported yet but it's enough for Planeset.
 
 */
 
static byte MapAircraftMovementAction(const Aircraft *v)
 
{
 
	switch (v->state) {
 
		case HANGAR:
 
			return (v->cur_speed > 0) ? AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_IN_HANGAR;
 

	
 
		case TERM1:
 
		case HELIPAD1:
 
			return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD1 : AMA_TTDP_LANDING_TO_PAD1;
 

	
 
		case TERM2:
 
		case HELIPAD2:
 
			return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD2 : AMA_TTDP_LANDING_TO_PAD2;
 

	
 
		case TERM3:
 
		case TERM4:
 
		case TERM5:
 
		case TERM6:
 
		case TERM7:
 
		case TERM8:
 
		case HELIPAD3:
 
		case HELIPAD4:
 
			return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD3 : AMA_TTDP_LANDING_TO_PAD3;
 

	
 
		case TAKEOFF:      // Moving to takeoff position
 
		case STARTTAKEOFF: // Accelerating down runway
 
		case ENDTAKEOFF:   // Ascent
 
		case HELITAKEOFF:
 
			/* @todo Need to find which terminal (or hanger) we've come from. How? */
 
			return AMA_TTDP_PAD1_TO_TAKEOFF;
 

	
 
		case FLYING:
 
			return AMA_TTDP_IN_FLIGHT;
 

	
 
		case LANDING:    // Descent
 
		case ENDLANDING: // On the runway braking
 
		case HELILANDING:
 
		case HELIENDLANDING:
 
			/* @todo Need to check terminal we're landing to. Is it known yet? */
 
			return (v->current_order.IsType(OT_GOTO_DEPOT)) ?
 
				AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_LANDING_TO_PAD1;
 

	
 
		default:
 
			return AMA_TTDP_IN_HANGAR;
 
	}
 
}
 

	
 

	
 
/* Vehicle Resolver Functions */
 
static inline const Vehicle *GRV(const ResolverObject *object)
 
{
 
	switch (object->scope) {
 
		default: NOT_REACHED();
 
		case VSG_SCOPE_SELF: return object->u.vehicle.self;
 
		case VSG_SCOPE_PARENT: return object->u.vehicle.parent;
 
		case VSG_SCOPE_RELATIVE: {
 
			if (object->u.vehicle.self == NULL) return NULL;
 
			const Vehicle *v = NULL;
 
			switch (GB(object->count, 6, 2)) {
 
				default: NOT_REACHED();
 
				case 0x00: // count back (away from the engine), starting at this vehicle
 
				case 0x01: // count forward (toward the engine), starting at this vehicle
 
					v = object->u.vehicle.self;
 
					break;
 
				case 0x02: // count back, starting at the engine
 
					v = object->u.vehicle.parent;
 
					break;
 
				case 0x03: { // count back, starting at the first vehicle in this chain of vehicles with the same ID, as for vehicle variable 41
 
					const Vehicle *self = object->u.vehicle.self;
src/newgrf_gui.cpp
Show inline comments
 
@@ -54,196 +54,194 @@ static void ShowNewGRFInfo(const GRFConf
 
	char buff[256];
 

	
 
	if (c->error != NULL) {
 
		char message[512];
 
		SetDParamStr(0, c->error->custom_message); // is skipped by built-in messages
 
		SetDParam   (1, STR_JUST_RAW_STRING);
 
		SetDParamStr(2, c->filename);
 
		SetDParam   (3, STR_JUST_RAW_STRING);
 
		SetDParamStr(4, c->error->data);
 
		for (uint i = 0; i < c->error->num_params; i++) {
 
			SetDParam(5 + i, c->error->param_value[i]);
 
		}
 
		GetString(message, c->error->custom_message == NULL ? c->error->message : STR_JUST_RAW_STRING, lastof(message));
 

	
 
		SetDParamStr(0, message);
 
		y = DrawStringMultiLine(x, right, y, bottom, c->error->severity);
 
	}
 

	
 
	/* Draw filename or not if it is not known (GRF sent over internet) */
 
	if (c->filename != NULL) {
 
		SetDParamStr(0, c->filename);
 
		y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_FILENAME);
 
	}
 

	
 
	/* Prepare and draw GRF ID */
 
	snprintf(buff, lengthof(buff), "%08X", BSWAP32(c->ident.grfid));
 
	SetDParamStr(0, buff);
 
	y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_GRF_ID);
 

	
 
	/* Prepare and draw MD5 sum */
 
	md5sumToString(buff, lastof(buff), c->ident.md5sum);
 
	SetDParamStr(0, buff);
 
	y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_MD5SUM);
 

	
 
	/* Show GRF parameter list */
 
	if (show_params) {
 
		if (c->num_params > 0) {
 
			GRFBuildParamList(buff, c, lastof(buff));
 
			SetDParam(0, STR_JUST_RAW_STRING);
 
			SetDParamStr(1, buff);
 
		} else {
 
			SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE);
 
		}
 
		y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_PARAMETER);
 

	
 
		/* Draw the palette of the NewGRF */
 
		SetDParamStr(0, c->windows_paletted ? "Windows" : "DOS");
 
		y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_PALETTE);
 
	}
 

	
 
	/* Show flags */
 
	if (c->status == GCS_NOT_FOUND)       y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_NOT_FOUND);
 
	if (c->status == GCS_DISABLED)        y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_DISABLED);
 
	if (HasBit(c->flags, GCF_COMPATIBLE)) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_COMPATIBLE_LOADED);
 

	
 
	/* Draw GRF info if it exists */
 
	if (!StrEmpty(c->GetDescription())) {
 
		SetDParam(0, STR_JUST_RAW_STRING);
 
		SetDParamStr(1, c->GetDescription());
 
		y = DrawStringMultiLine(x, right, y, bottom, STR_BLACK_STRING);
 
	} else {
 
		y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_NO_INFO);
 
	}
 
}
 

	
 

	
 
/** Names of the add a newgrf window widgets. */
 
enum AddNewGRFWindowWidgets {
 
	ANGRFW_FILTER,
 
	ANGRFW_GRF_LIST,
 
	ANGRFW_SCROLLBAR,
 
	ANGRFW_GRF_INFO,
 
	ANGRFW_ADD,
 
	ANGRFW_RESCAN,
 
};
 

	
 
/**
 
 * Window for adding NewGRF files
 
 */
 
struct NewGRFAddWindow : public QueryStringBaseWindow {
 
private:
 
	typedef GUIList<const GRFConfig *> GUIGRFConfigList;
 

	
 
	GRFConfig **list;
 

	
 
	/** Runtime saved values */
 
	static Listing last_sorting;
 
	static Filtering last_filtering;
 

	
 
	static GUIGRFConfigList::SortFunction * const sorter_funcs[];
 
	static GUIGRFConfigList::FilterFunction * const filter_funcs[];
 
	GUIGRFConfigList grfs;
 

	
 
	const GRFConfig *sel;
 
	int sel_pos;
 

	
 
	enum {
 
		EDITBOX_MAX_SIZE = 50,
 
		EDITBOX_MAX_LENGTH = 300,
 
	};
 
	static const uint EDITBOX_MAX_SIZE   =  50;
 
	static const uint EDITBOX_MAX_LENGTH = 300;
 

	
 
	/**
 
	 * (Re)build the grf as its amount has changed because
 
	 * an item has been added or deleted for example
 
	 */
 
	void BuildGrfList()
 
	{
 
		if (!this->grfs.NeedRebuild()) return;
 

	
 
		/* Create temporary array of grfs to use for listing */
 
		this->grfs.Clear();
 

	
 
		for (const GRFConfig *c = _all_grfs; c != NULL; c = c->next) {
 
			*this->grfs.Append() = c;
 
		}
 

	
 
		this->FilterGrfList();
 
		this->grfs.Compact();
 
		this->grfs.RebuildDone();
 
		this->SortGrfList();
 

	
 
		this->vscroll.SetCount(this->grfs.Length()); // Update the scrollbar
 
		this->ScrollToSelected();
 
	}
 

	
 
	/** Sort grfs by name. */
 
	static int CDECL NameSorter(const GRFConfig * const *a, const GRFConfig * const *b)
 
	{
 
		return strcasecmp((*a)->GetName(), (*b)->GetName());
 
	}
 

	
 
	/** Sort the grf list */
 
	void SortGrfList()
 
	{
 
		if (!this->grfs.Sort()) return;
 
		this->UpdateListPosition();
 
	}
 

	
 
	/** Update selection position. */
 
	void UpdateListPosition()
 
	{
 
		/* update list position */
 
		if (this->sel != NULL) {
 
			this->sel_pos = this->grfs.FindIndex(this->sel);
 
			if (this->sel_pos < 0) {
 
				this->sel = NULL;
 
			}
 
		}
 
	}
 

	
 
	/** Filter grfs by tags/name */
 
	static bool CDECL TagNameFilter(const GRFConfig * const *a, const char *filter_string)
 
	{
 
		if (strcasestr((*a)->GetName(), filter_string) != NULL) return true;
 
		if ((*a)->filename != NULL && strcasestr((*a)->filename, filter_string) != NULL) return true;
 
		if ((*a)->GetDescription() != NULL && strcasestr((*a)->GetDescription(), filter_string) != NULL) return true;
 
		return false;
 
	}
 

	
 
	/** Filter the grf list */
 
	void FilterGrfList()
 
	{
 
		if (!this->grfs.Filter(this->edit_str_buf)) return;
 
		this->UpdateListPosition();
 
	}
 

	
 
	/** Make sure that the currently selected grf is within the visible part of the list */
 
	void ScrollToSelected()
 
	{
 
		if (this->sel_pos >= 0) {
 
			this->vscroll.ScrollTowards(this->sel_pos);
 
		}
 
	}
 

	
 
public:
 
	NewGRFAddWindow(const WindowDesc *desc, Window *parent, GRFConfig **list) : QueryStringBaseWindow(EDITBOX_MAX_SIZE)
 
	{
 
		this->parent = parent;
 
		this->InitNested(desc, 0);
 

	
 
		InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, EDITBOX_MAX_LENGTH);
 
		this->SetFocusedWidget(ANGRFW_FILTER);
 

	
 
		this->list = list;
 
		this->grfs.SetListing(this->last_sorting);
 
		this->grfs.SetFiltering(this->last_filtering);
 
		this->grfs.SetSortFuncs(this->sorter_funcs);
 
		this->grfs.SetFilterFuncs(this->filter_funcs);
 

	
 
		this->OnInvalidateData(0);
 
	}
 

	
 
	virtual void OnInvalidateData(int data)
 
	{
 
		/* data == 0: NewGRFS were rescanned. All pointers to GrfConfigs are invalid.
 
		 * data == 1: User interaction with this window: Filter or selection change. */
src/newgrf_station.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file newgrf_station.cpp Functions for dealing with station classes and custom stations. */
 

	
 
#include "stdafx.h"
 
#include "variables.h"
 
#include "debug.h"
 
#include "station_base.h"
 
#include "waypoint_base.h"
 
#include "roadstop_base.h"
 
#include "newgrf_cargo.h"
 
#include "newgrf_commons.h"
 
#include "newgrf_station.h"
 
#include "newgrf_spritegroup.h"
 
#include "newgrf_sound.h"
 
#include "newgrf_railtype.h"
 
#include "town.h"
 
#include "newgrf_town.h"
 
#include "date_func.h"
 
#include "company_func.h"
 
#include "animated_tile_func.h"
 
#include "functions.h"
 
#include "tunnelbridge_map.h"
 
#include "newgrf.h"
 
#include "core/random_func.hpp"
 

	
 
#include "table/strings.h"
 

	
 
static StationClass _station_classes[STAT_CLASS_MAX];
 

	
 
enum {
 
	MAX_SPECLIST = 255,
 
};
 
static const uint MAX_SPECLIST = 255;
 

	
 
enum TriggerArea {
 
	TA_TILE,
 
	TA_PLATFORM,
 
	TA_WHOLE,
 
};
 

	
 
struct ETileArea : TileArea {
 
	ETileArea(const BaseStation *st, TileIndex tile, TriggerArea ta)
 
	{
 
		switch (ta) {
 
			default: NOT_REACHED();
 

	
 
			case TA_TILE:
 
				this->tile = tile;
 
				this->w    = 1;
 
				this->h    = 1;
 
				break;
 

	
 
			case TA_PLATFORM: {
 
				TileIndex start, end;
 
				Axis axis = GetRailStationAxis(tile);
 
				TileIndexDiff delta = TileOffsByDiagDir(AxisToDiagDir(axis));
 

	
 
				for (end = tile; IsRailStationTile(end + delta) && IsCompatibleTrainStationTile(tile, end + delta); end += delta) { /* Nothing */ }
 
				for (start = tile; IsRailStationTile(start - delta) && IsCompatibleTrainStationTile(tile, start - delta); start -= delta) { /* Nothing */ }
 

	
 
				this->tile = start;
 
				this->w = TileX(end) - TileX(start) + 1;
 
				this->h = TileY(end) - TileY(start) + 1;
 
				break;
 
			}
 

	
 
			case TA_WHOLE:
 
				st->GetTileArea(this, Station::IsExpected(st) ? STATION_RAIL : STATION_WAYPOINT);
 
				break;
 
		}
 
	}
 
};
 

	
 

	
 
/**
 
 * 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()
 
{
 
	for (StationClassID i = STAT_CLASS_BEGIN; i < STAT_CLASS_MAX; i++) {
 
		_station_classes[i].id = 0;
 
		_station_classes[i].name = STR_EMPTY;
 
		_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 = STR_STATION_CLASS_DFLT;
 
	_station_classes[0].stations = 1;
 
	_station_classes[0].spec = MallocT<StationSpec*>(1);
 
	_station_classes[0].spec[0] = NULL;
 

	
 
	_station_classes[1].id = 'WAYP';
 
	_station_classes[1].name = STR_STATION_CLASS_WAYP;
 
	_station_classes[1].stations = 1;
 
	_station_classes[1].spec = MallocT<StationSpec*>(1);
 
	_station_classes[1].spec[0] = NULL;
 
}
 

	
 
/**
 
 * Allocate a station class for the given class id.
 
 * @param cls A 32 bit value identifying the class.
 
 * @return Index into _station_classes of allocated class.
 
 */
 
StationClassID AllocateStationClass(uint32 cls)
 
{
 
	for (StationClassID i = STAT_CLASS_BEGIN; i < STAT_CLASS_MAX; i++) {
 
		if (_station_classes[i].id == cls) {
 
			/* 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 = cls;
 
			return i;
 
		}
 
	}
 

	
 
	grfmsg(2, "StationClassAllocate: already allocated %d classes, using default", STAT_CLASS_MAX);
 
	return STAT_CLASS_DFLT;
 
}
 

	
 
/** Set the name of a custom station class */
 
void SetStationClassName(StationClassID sclass, StringID name)
 
{
src/osk_gui.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file osk_gui.cpp The On Screen Keyboard GUI */
 

	
 
#include "stdafx.h"
 
#include "string_func.h"
 
#include "strings_func.h"
 
#include "debug.h"
 
#include "window_func.h"
 
#include "gfx_func.h"
 
#include "querystring_gui.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
/** Widget numbers of the on-screen keyboard (OSK) window. */
 
enum OskWidgets {
 
	OSK_WIDGET_CAPTION,         ///< Title bar.
 
	OSK_WIDGET_TEXT,            ///< Edit box.
 
	OSK_WIDGET_CANCEL,          ///< Cancel key.
 
	OSK_WIDGET_OK,              ///< Ok key.
 
	OSK_WIDGET_BACKSPACE,       ///< Backspace key.
 
	OSK_WIDGET_SPECIAL,         ///< Special key (at keyborads often used for tab key).
 
	OSK_WIDGET_CAPS,            ///< Capslock key.
 
	OSK_WIDGET_SHIFT,           ///< Shift(lock) key.
 
	OSK_WIDGET_SPACE,           ///< Space bar.
 
	OSK_WIDGET_LEFT,            ///< Cursor left key.
 
	OSK_WIDGET_RIGHT,           ///< Cursor right key.
 
	OSK_WIDGET_LETTERS,         ///< First widget of the 'normal' keys.
 

	
 
	OSK_WIDGET_NUMBERS_FIRST = OSK_WIDGET_LETTERS,           ///< First widget of the numbers row.
 
	OSK_WIDGET_NUMBERS_LAST = OSK_WIDGET_NUMBERS_FIRST + 13, ///< Last widget of the numbers row.
 

	
 
	OSK_WIDGET_QWERTY_FIRST,                                 ///< First widget of the qwerty row.
 
	OSK_WIDGET_QWERTY_LAST = OSK_WIDGET_QWERTY_FIRST + 11,   ///< Last widget of the qwerty row.
 

	
 
	OSK_WIDGET_ASDFG_FIRST,                                  ///< First widget of the asdfg row.
 
	OSK_WIDGET_ASDFG_LAST = OSK_WIDGET_ASDFG_FIRST + 11,     ///< Last widget of the asdfg row.
 

	
 
	OSK_WIDGET_ZXCVB_FIRST,                                  ///< First widget of the zxcvb row.
 
	OSK_WIDGET_ZXCVB_LAST = OSK_WIDGET_ZXCVB_FIRST + 11,     ///< Last widget of the zxcvb row.
 
};
 

	
 
char _keyboard_opt[2][OSK_KEYBOARD_ENTRIES * 4 + 1];
 
static WChar _keyboard[2][OSK_KEYBOARD_ENTRIES];
 

	
 
enum {
 
enum KeyStateBits {
 
	KEYS_NONE,
 
	KEYS_SHIFT,
 
	KEYS_CAPS
 
};
 
static byte _keystate = KEYS_NONE;
 

	
 
struct OskWindow : public Window {
 
	StringID caption;      ///< the caption for this window.
 
	QueryString *qs;       ///< text-input
 
	int text_btn;          ///< widget number of parent's text field
 
	int ok_btn;            ///< widget number of parent's ok button (=0 when ok shouldn't be passed on)
 
	int cancel_btn;        ///< widget number of parent's cancel button (=0 when cancel shouldn't be passed on; text will be reverted to original)
 
	Textbuf *text;         ///< pointer to parent's textbuffer (to update caret position)
 
	char *orig_str_buf;    ///< Original string.
 
	bool shift;            ///< Is the shift effectively pressed?
 

	
 
	OskWindow(const WindowDesc *desc, QueryStringBaseWindow *parent, int button, int cancel, int ok) : Window()
 
	{
 
		this->parent = parent;
 
		assert(parent != NULL);
 

	
 
		NWidgetCore *par_wid = parent->GetWidget<NWidgetCore>(button);
 
		assert(par_wid != NULL);
 
		this->caption = (par_wid->widget_data != STR_NULL) ? par_wid->widget_data : parent->caption;
 

	
 
		this->qs         = parent;
 
		this->text_btn   = button;
 
		this->cancel_btn = cancel;
 
		this->ok_btn     = ok;
 
		this->text       = &parent->text;
 

	
 
		/* make a copy in case we need to reset later */
 
		this->orig_str_buf = strdup(this->qs->text.buf);
 

	
 
		this->InitNested(desc, 0);
 

	
 
		/* Not needed by default. */
 
		this->DisableWidget(OSK_WIDGET_SPECIAL);
 

	
 
		this->UpdateOskState();
 
	}
 

	
 
	~OskWindow()
 
	{
 
		free(this->orig_str_buf);
 
	}
 

	
 
	/**
 
	 * Only show valid characters; do not show characters that would
 
	 * only insert a space when we have a spacebar to do that or
 
	 * characters that are not allowed to be entered.
 
	 */
 
	void UpdateOskState()
 
	{
 
		this->shift = HasBit(_keystate, KEYS_CAPS) ^ HasBit(_keystate, KEYS_SHIFT);
 

	
 
		for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) {
 
			this->SetWidgetDisabledState(OSK_WIDGET_LETTERS + i,
 
					!IsValidChar(_keyboard[this->shift][i], this->qs->afilter) || _keyboard[this->shift][i] == ' ');
 
		}
 
		this->SetWidgetDisabledState(OSK_WIDGET_SPACE, !IsValidChar(' ', this->qs->afilter));
 

	
 
		this->LowerWidget(OSK_WIDGET_TEXT);
 
		this->SetWidgetLoweredState(OSK_WIDGET_SHIFT, HasBit(_keystate, KEYS_SHIFT));
 
		this->SetWidgetLoweredState(OSK_WIDGET_CAPS, HasBit(_keystate, KEYS_CAPS));
 
	}
 

	
 
	virtual void SetStringParameters(int widget) const
 
	{
 
		if (widget == OSK_WIDGET_CAPTION) SetDParam(0, this->caption);
 
	}
 

	
 
	virtual void DrawWidget(const Rect &r, int widget) const
 
	{
 
		if (widget < OSK_WIDGET_LETTERS) return;
 

	
 
		widget -= OSK_WIDGET_LETTERS;
 
		DrawCharCentered(_keyboard[this->shift][widget],
 
			r.left + 8,
 
			r.top + 3,
 
			TC_BLACK);
 
	}
 

	
 
	virtual void OnPaint()
 
	{
 
		this->DrawWidgets();
 

	
 
		this->qs->DrawEditBox(this, OSK_WIDGET_TEXT);
 
	}
 

	
 
	virtual void OnClick(Point pt, int widget, int click_count)
 
	{
 
		/* clicked a letter */
 
		if (widget >= OSK_WIDGET_LETTERS) {
 
			WChar c = _keyboard[this->shift][widget - OSK_WIDGET_LETTERS];
 

	
src/pathfinder/npf/npf.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file npf.cpp Implementation of the NPF pathfinder. */
 

	
 
#include "../../stdafx.h"
 
#include "../../debug.h"
 
#include "../../landscape.h"
 
#include "../../network/network.h"
 
#include "../../functions.h"
 
#include "../../ship.h"
 
#include "../../roadstop_base.h"
 
#include "../pathfinder_func.h"
 
#include "../pathfinder_type.h"
 
#include "../follow_track.hpp"
 
#include "aystar.h"
 

	
 
enum {
 
	NPF_HASH_BITS = 12, ///< The size of the hash used in pathfinding. Just changing this value should be sufficient to change the hash size. Should be an even value.
 
	/* Do no change below values */
 
	NPF_HASH_SIZE = 1 << NPF_HASH_BITS,
 
	NPF_HASH_HALFBITS = NPF_HASH_BITS / 2,
 
	NPF_HASH_HALFMASK = (1 << NPF_HASH_HALFBITS) - 1
 
};
 
static const uint NPF_HASH_BITS = 12; ///< The size of the hash used in pathfinding. Just changing this value should be sufficient to change the hash size. Should be an even value.
 
/* Do no change below values */
 
static const uint NPF_HASH_SIZE = 1 << NPF_HASH_BITS;
 
static const uint NPF_HASH_HALFBITS = NPF_HASH_BITS / 2;
 
static const uint NPF_HASH_HALFMASK = (1 << NPF_HASH_HALFBITS) - 1;
 

	
 
/* Meant to be stored in AyStar.targetdata */
 
/** Meant to be stored in AyStar.targetdata */
 
struct NPFFindStationOrTileData {
 
	TileIndex dest_coords;    ///< An indication of where the station is, for heuristic purposes, or the target tile
 
	StationID station_index;  ///< station index we're heading for, or INVALID_STATION when we're heading for a tile
 
	bool reserve_path;        ///< Indicates whether the found path should be reserved
 
	StationType station_type; ///< The type of station we're heading for
 
	bool not_articulated;     ///< The (road) vehicle is not articulated
 
	const Vehicle *v;         ///< The vehicle we are pathfinding for
 
};
 

	
 
/* Indices into AyStar.userdata[] */
 
enum {
 
/** Indices into AyStar.userdata[] */
 
enum AyStarUserDataType {
 
	NPF_TYPE = 0,  ///< Contains a TransportTypes value
 
	NPF_SUB_TYPE,  ///< Contains the sub transport type
 
	NPF_OWNER,     ///< Contains an Owner value
 
	NPF_RAILTYPES, ///< Contains a bitmask the compatible RailTypes of the engine when NPF_TYPE == TRANSPORT_RAIL. Unused otherwise.
 
};
 

	
 
/* Indices into AyStarNode.userdata[] */
 
enum {
 
/** Indices into AyStarNode.userdata[] */
 
enum AyStarNodeUserDataType {
 
	NPF_TRACKDIR_CHOICE = 0, ///< The trackdir chosen to get here
 
	NPF_NODE_FLAGS,
 
};
 

	
 
/* Flags for AyStarNode.userdata[NPF_NODE_FLAGS]. Use NPFSetFlag() and NPFGetFlag() to use them. */
 
/** Flags for AyStarNode.userdata[NPF_NODE_FLAGS]. Use NPFSetFlag() and NPFGetFlag() to use them. */
 
enum NPFNodeFlag {
 
	NPF_FLAG_SEEN_SIGNAL,       ///< Used to mark that a signal was seen on the way, for rail only
 
	NPF_FLAG_2ND_SIGNAL,        ///< Used to mark that two signals were seen, rail only
 
	NPF_FLAG_3RD_SIGNAL,        ///< Used to mark that three signals were seen, rail only
 
	NPF_FLAG_REVERSE,           ///< Used to mark that this node was reached from the second start node, if applicable
 
	NPF_FLAG_LAST_SIGNAL_RED,   ///< Used to mark that the last signal on this path was red
 
	NPF_FLAG_LAST_SIGNAL_BLOCK, ///< Used to mark that the last signal on this path was a block signal
 
	NPF_FLAG_IGNORE_START_TILE, ///< Used to mark that the start tile is invalid, and searching should start from the second tile on
 
	NPF_FLAG_TARGET_RESERVED,   ///< Used to mark that the possible reservation target is already reserved
 
	NPF_FLAG_IGNORE_RESERVED,   ///< Used to mark that reserved tiles should be considered impassable
 
};
 

	
 
/* Meant to be stored in AyStar.userpath */
 
/** Meant to be stored in AyStar.userpath */
 
struct NPFFoundTargetData {
 
	uint best_bird_dist;    ///< The best heuristic found. Is 0 if the target was found
 
	uint best_path_dist;    ///< The shortest path. Is UINT_MAX if no path is found
 
	Trackdir best_trackdir; ///< The trackdir that leads to the shortest path/closest birds dist
 
	AyStarNode node;        ///< The node within the target the search led us to
 
	bool res_okay;          ///< True if a path reservation could be made
 
};
 

	
 
static AyStar _npf_aystar;
 

	
 
/* The cost of each trackdir. A diagonal piece is the full NPF_TILE_LENGTH,
 
 * the shorter piece is sqrt(2)/2*NPF_TILE_LENGTH =~ 0.7071
 
 */
 
#define NPF_STRAIGHT_LENGTH (uint)(NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH)
 
static const uint _trackdir_length[TRACKDIR_END] = {
 
	NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH,
 
	0, 0,
 
	NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH
 
};
 

	
 
/**
 
 * Returns the current value of the given flag on the given AyStarNode.
 
 */
 
static inline bool NPFGetFlag(const AyStarNode *node, NPFNodeFlag flag)
 
{
 
	return HasBit(node->user_data[NPF_NODE_FLAGS], flag);
 
}
 

	
 
/**
 
 * Sets the given flag on the given AyStarNode to the given value.
 
 */
 
static inline void NPFSetFlag(AyStarNode *node, NPFNodeFlag flag, bool value)
 
{
 
	SB(node->user_data[NPF_NODE_FLAGS], flag, 1, value);
 
}
 

	
 
/**
 
 * Calculates the minimum distance traveled to get from t0 to t1 when only
 
 * using tracks (ie, only making 45 degree turns). Returns the distance in the
 
 * NPF scale, ie the number of full tiles multiplied by NPF_TILE_LENGTH to
 
 * prevent rounding.
 
 */
 
static uint NPFDistanceTrack(TileIndex t0, TileIndex t1)
 
{
 
	const uint dx = Delta(TileX(t0), TileX(t1));
 
	const uint dy = Delta(TileY(t0), TileY(t1));
 

	
 
	const uint straightTracks = 2 * min(dx, dy); // The number of straight (not full length) tracks
 
	/* OPTIMISATION:
 
	 * Original: diagTracks = max(dx, dy) - min(dx,dy);
 
	 * Proof:
 
	 * (dx+dy) - straightTracks  == (min + max) - straightTracks = min + max - 2 * min = max - min */
 
	const uint diagTracks = dx + dy - straightTracks; // The number of diagonal (full tile length) tracks.
 

	
 
	/* Don't factor out NPF_TILE_LENGTH below, this will round values and lose
 
	 * precision */
 
	return diagTracks * NPF_TILE_LENGTH + straightTracks * NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH;
 
}
 

	
 

	
 
#if 0
 
static uint NTPHash(uint key1, uint key2)
 
{
 
	/* This function uses the old hash, which is fixed on 10 bits (1024 buckets) */
 
	return PATHFIND_HASH_TILE(key1);
 
}
 
#endif
 

	
 
/**
 
 * Calculates a hash value for use in the NPF.
 
 * @param key1 The TileIndex of the tile to hash
 
 * @param key2 The Trackdir of the track on the tile.
 
 *
 
 * @todo Think of a better hash.
 
 */
 
static uint NPFHash(uint key1, uint key2)
 
{
 
	/* TODO: think of a better hash? */
 
	uint part1 = TileX(key1) & NPF_HASH_HALFMASK;
 
	uint part2 = TileY(key1) & NPF_HASH_HALFMASK;
 

	
 
	assert(IsValidTrackdir((Trackdir)key2));
 
	assert(IsValidTile(key1));
 
	return ((part1 << NPF_HASH_HALFBITS | part2) + (NPF_HASH_SIZE * key2 / TRACKDIR_END)) % NPF_HASH_SIZE;
 
}
 

	
 
static int32 NPFCalcZero(AyStar *as, AyStarNode *current, OpenListNode *parent)
 
{
 
	return 0;
 
}
 

	
 
/* Calcs the heuristic to the target station or tile. For train stations, it
 
 * takes into account the direction of approach.
 
 */
 
static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, OpenListNode *parent)
 
{
src/rail_cmd.cpp
Show inline comments
 
@@ -2036,193 +2036,193 @@ static void DrawTrackBits(TileInfo *ti, 
 
			(image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
 
			(image++,                           track == TRACK_BIT_X) ||
 
			(image++,                           track == TRACK_BIT_UPPER) ||
 
			(image++,                           track == TRACK_BIT_LOWER) ||
 
			(image++,                           track == TRACK_BIT_RIGHT) ||
 
			(image++,                           track == TRACK_BIT_LEFT) ||
 
			(image++,                           track == TRACK_BIT_CROSS) ||
 

	
 
			(image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
 
			(image++,                            track == TRACK_BIT_VERT) ||
 

	
 
			(junction = true, false) ||
 
			(image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
 
			(image++,                          (track & TRACK_BIT_3WAY_SW) == 0) ||
 
			(image++,                          (track & TRACK_BIT_3WAY_NW) == 0) ||
 
			(image++,                          (track & TRACK_BIT_3WAY_SE) == 0) ||
 
			(image++, true);
 
		}
 

	
 
		switch (rgt) {
 
			case RAIL_GROUND_BARREN:     pal = PALETTE_TO_BARE_LAND; break;
 
			case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset;  break;
 
			case RAIL_GROUND_WATER: {
 
				/* three-corner-raised slope */
 
				DrawShoreTile(ti->tileh);
 
				Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
 
				sub = &(_halftile_sub_sprite[track_corner]);
 
				break;
 
			}
 
			default: break;
 
		}
 
	}
 

	
 
	if (image != 0) DrawGroundSprite(image, pal, sub);
 

	
 
	/* Draw track pieces individually for junction tiles */
 
	if (junction) {
 
		if (track & TRACK_BIT_X)     DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
 
		if (track & TRACK_BIT_Y)     DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
 
		if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
 
		if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
 
		if (track & TRACK_BIT_LEFT)  DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
 
		if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
 
	}
 

	
 
	/* PBS debugging, draw reserved tracks darker */
 
	if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
 
		/* Get reservation, but mask track on halftile slope */
 
		TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
 
		if (pbs & TRACK_BIT_X) {
 
			if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
 
				DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
 
			} else {
 
				DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
 
			}
 
		}
 
		if (pbs & TRACK_BIT_Y) {
 
			if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
 
				DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
 
			} else {
 
				DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
 
			}
 
		}
 
		if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -TILE_HEIGHT : 0);
 
		if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -TILE_HEIGHT : 0);
 
		if (pbs & TRACK_BIT_LEFT)  DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -TILE_HEIGHT : 0);
 
		if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -TILE_HEIGHT : 0);
 
	}
 

	
 
	if (IsValidCorner(halftile_corner)) {
 
		DrawFoundation(ti, HalftileFoundation(halftile_corner));
 

	
 
		/* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */
 
		Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
 
		image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
 
		pal = PAL_NONE;
 
		switch (rgt) {
 
			case RAIL_GROUND_BARREN:     pal = PALETTE_TO_BARE_LAND; break;
 
			case RAIL_GROUND_ICE_DESERT:
 
			case RAIL_GROUND_HALF_SNOW:  image += rti->snow_offset;  break; // higher part has snow in this case too
 
			default: break;
 
		}
 
		DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
 

	
 
		if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
 
			static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
 
			DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -TILE_HEIGHT);
 
		}
 
	}
 
}
 

	
 
/** Enums holding the offsets from base signal sprite,
 
 * according to the side it is representing.
 
 * The addtion of 2 per enum is necessary in order to "jump" over the
 
 * green state sprite, all signal sprites being in pair,
 
 * starting with the off-red state */
 
enum {
 
enum SignalOffsets {
 
	SIGNAL_TO_SOUTHWEST =  0,
 
	SIGNAL_TO_NORTHEAST =  2,
 
	SIGNAL_TO_SOUTHEAST =  4,
 
	SIGNAL_TO_NORTHWEST =  6,
 
	SIGNAL_TO_EAST      =  8,
 
	SIGNAL_TO_WEST      = 10,
 
	SIGNAL_TO_SOUTH     = 12,
 
	SIGNAL_TO_NORTH     = 14,
 
};
 

	
 
static void DrawSignals(TileIndex tile, TrackBits rails)
 
{
 
#define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
 

	
 
	if (!(rails & TRACK_BIT_Y)) {
 
		if (!(rails & TRACK_BIT_X)) {
 
			if (rails & TRACK_BIT_LEFT) {
 
				MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
 
				MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
 
			}
 
			if (rails & TRACK_BIT_RIGHT) {
 
				MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
 
				MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
 
			}
 
			if (rails & TRACK_BIT_UPPER) {
 
				MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
 
				MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
 
			}
 
			if (rails & TRACK_BIT_LOWER) {
 
				MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
 
				MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
 
			}
 
		} else {
 
			MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
 
			MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
 
		}
 
	} else {
 
		MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
 
		MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
 
	}
 
}
 

	
 
static void DrawTile_Track(TileInfo *ti)
 
{
 
	const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
 

	
 
	_drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
 

	
 
	if (IsPlainRail(ti->tile)) {
 
		TrackBits rails = GetTrackBits(ti->tile);
 

	
 
		DrawTrackBits(ti, rails);
 

	
 
		if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
 

	
 
		if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
 

	
 
		if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
 
	} else {
 
		/* draw depot */
 
		const DrawTileSprites *dts;
 
		PaletteID pal = PAL_NONE;
 
		SpriteID relocation;
 

	
 
		if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
 

	
 
		if (IsInvisibilitySet(TO_BUILDINGS)) {
 
			/* Draw rail instead of depot */
 
			dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
 
		} else {
 
			dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
 
		}
 

	
 
		SpriteID image;
 
		if (rti->UsesOverlay()) {
 
			image = SPR_FLAT_GRASS_TILE;
 
		} else {
 
			image = dts->ground.sprite;
 
			if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
 
		}
 

	
 
		/* adjust ground tile for desert
 
		 * don't adjust for snow, because snow in depots looks weird */
 
		if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
 
			if (image != SPR_FLAT_GRASS_TILE) {
 
				image += rti->snow_offset; // tile with tracks
 
			} else {
 
				image = SPR_FLAT_SNOW_DESERT_TILE; // flat ground
 
			}
 
		}
 

	
 
		DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
 

	
 
		if (rti->UsesOverlay()) {
 
			SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
 

	
src/signal.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file signal.cpp functions related to rail signals updating */
 

	
 
#include "stdafx.h"
 
#include "debug.h"
 
#include "station_map.h"
 
#include "tunnelbridge_map.h"
 
#include "vehicle_func.h"
 
#include "functions.h"
 
#include "train.h"
 
#include "company_base.h"
 

	
 

	
 
/** these are the maximums used for updating signal blocks */
 
enum {
 
	SIG_TBU_SIZE    =  64, ///< number of signals entering to block
 
	SIG_TBD_SIZE    = 256, ///< number of intersections - open nodes in current block
 
	SIG_GLOB_SIZE   = 128, ///< number of open blocks (block can be opened more times until detected)
 
	SIG_GLOB_UPDATE =  64, ///< how many items need to be in _globset to force update
 
};
 
static const uint SIG_TBU_SIZE    =  64; ///< number of signals entering to block
 
static const uint SIG_TBD_SIZE    = 256; ///< number of intersections - open nodes in current block
 
static const uint SIG_GLOB_SIZE   = 128; ///< number of open blocks (block can be opened more times until detected)
 
static const uint SIG_GLOB_UPDATE =  64; ///< how many items need to be in _globset to force update
 

	
 
assert_compile(SIG_GLOB_UPDATE <= SIG_GLOB_SIZE);
 

	
 
/** incidating trackbits with given enterdir */
 
static const TrackBits _enterdir_to_trackbits[DIAGDIR_END] = {
 
	TRACK_BIT_3WAY_NE,
 
	TRACK_BIT_3WAY_SE,
 
	TRACK_BIT_3WAY_SW,
 
	TRACK_BIT_3WAY_NW
 
};
 

	
 
/** incidating trackdirbits with given enterdir */
 
static const TrackdirBits _enterdir_to_trackdirbits[DIAGDIR_END] = {
 
	TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S,
 
	TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_RIGHT_N,
 
	TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N,
 
	TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LEFT_S
 
};
 

	
 
/**
 
 * Set containing 'items' items of 'tile and Tdir'
 
 * No tree structure is used because it would cause
 
 * slowdowns in most usual cases
 
 */
 
template <typename Tdir, uint items>
 
struct SmallSet {
 
private:
 
	uint n;           // actual number of units
 
	bool overflowed;  // did we try to oveflow the set?
 
	const char *name; // name, used for debugging purposes...
 

	
 
	/** Element of set */
 
	struct SSdata {
 
		TileIndex tile;
 
		Tdir dir;
 
	} data[items];
 

	
 
public:
 
	/** Constructor - just set default values and 'name' */
 
	SmallSet(const char *name) : n(0), overflowed(false), name(name) { }
 

	
 
	/** Reset variables to default values */
 
	void Reset()
 
	{
 
		this->n = 0;
 
		this->overflowed = false;
 
	}
 

	
 
	/**
 
	 * Returns value of 'oveflowed'
 
	 * @return did we try to overflow the set?
 
	 */
 
	bool Overflowed()
 
	{
 
		return this->overflowed;
 
	}
 

	
 
	/**
 
	 * Checks for empty set
 
	 * @return is the set empty?
 
	 */
 
	bool IsEmpty()
 
	{
 
		return this->n == 0;
 
	}
 

	
 
	/**
 
	 * Checks for full set
 
	 * @return is the set full?
 
	 */
 
	bool IsFull()
 
	{
 
		return this->n == lengthof(data);
 
	}
 

	
 
	/**
 
	 * Reads the number of items
 
	 * @return current number of items
 
	 */
 
	uint Items()
 
	{
 
		return this->n;
 
	}
 

	
 

	
 
	/**
 
	 * Tries to remove first instance of given tile and dir
 
	 * @param tile tile
 
	 * @param dir and dir to remove
 
	 * @return element was found and removed
 
	 */
 
	bool Remove(TileIndex tile, Tdir dir)
 
	{
 
		for (uint i = 0; i < this->n; i++) {
 
			if (this->data[i].tile == tile && this->data[i].dir == dir) {
 
				this->data[i] = this->data[--this->n];
src/statusbar_gui.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file statusbar_gui.cpp The GUI for the bottom status bar. */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "date_func.h"
 
#include "gfx_func.h"
 
#include "news_func.h"
 
#include "company_func.h"
 
#include "string_func.h"
 
#include "strings_func.h"
 
#include "company_base.h"
 
#include "tilehighlight_func.h"
 
#include "news_gui.h"
 
#include "company_gui.h"
 
#include "window_gui.h"
 
#include "variables.h"
 
#include "window_func.h"
 
#include "statusbar_gui.h"
 
#include "core/geometry_func.hpp"
 

	
 
#include "table/strings.h"
 
#include "table/sprites.h"
 

	
 
static bool DrawScrollingStatusText(const NewsItem *ni, int scroll_pos, int left, int right, int top, int bottom)
 
{
 
	CopyInDParam(0, ni->params, lengthof(ni->params));
 
	StringID str = ni->string_id;
 

	
 
	char buf[512];
 
	GetString(buf, str, lastof(buf));
 
	const char *s = buf;
 

	
 
	char buffer[256];
 
	char *d = buffer;
 
	const char *last = lastof(buffer);
 

	
 
	for (;;) {
 
		WChar c = Utf8Consume(&s);
 
		if (c == 0) {
 
			break;
 
		} else if (c == '\n') {
 
			if (d + 4 >= last) break;
 
			d[0] = d[1] = d[2] = d[3] = ' ';
 
			d += 4;
 
		} else if (IsPrintable(c)) {
 
			if (d + Utf8CharLen(c) >= last) break;
 
			d += Utf8Encode(d, c);
 
		}
 
	}
 
	*d = '\0';
 

	
 
	DrawPixelInfo tmp_dpi;
 
	if (!FillDrawPixelInfo(&tmp_dpi, left, top, right - left, bottom)) return true;
 

	
 
	int width = GetStringBoundingBox(buffer).width;
 
	int pos = (_dynlang.text_dir == TD_RTL) ? (scroll_pos - width) : (right - scroll_pos - left);
 

	
 
	DrawPixelInfo *old_dpi = _cur_dpi;
 
	_cur_dpi = &tmp_dpi;
 
	DrawString(pos, INT16_MAX, 0, buffer, TC_LIGHT_BLUE, SA_LEFT | SA_FORCE);
 
	_cur_dpi = old_dpi;
 

	
 
	return (_dynlang.text_dir == TD_RTL) ? (pos < right - left) : (pos + width > 0);
 
}
 

	
 
enum StatusbarWidget {
 
	SBW_LEFT,   ///< left part of the statusbar; date is shown there
 
	SBW_MIDDLE, ///< middle part; current news or company name or *** SAVING *** or *** PAUSED ***
 
	SBW_RIGHT,  ///< right part; bank balance
 
};
 

	
 
struct StatusBarWindow : Window {
 
	bool saving;
 
	int ticker_scroll;
 
	int reminder_timeout;
 

	
 
	enum {
 
		TICKER_STOP    = 1640, ///< scrolling is finished when counter reaches this value
 
		REMINDER_START =   91, ///< initial value of the reminder counter (right dot on the right)
 
		REMINDER_STOP  =    0, ///< reminder disappears when counter reaches this value
 
		COUNTER_STEP   =    2, ///< this is subtracted from active counters every tick
 
	};
 
	static const int TICKER_STOP    = 1640; ///< scrolling is finished when counter reaches this value
 
	static const int REMINDER_START =   91; ///< initial value of the reminder counter (right dot on the right)
 
	static const int REMINDER_STOP  =    0; ///< reminder disappears when counter reaches this value
 
	static const int COUNTER_STEP   =    2; ///< this is subtracted from active counters every tick
 

	
 
	StatusBarWindow(const WindowDesc *desc) : Window()
 
	{
 
		CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
 
		this->ticker_scroll    =   TICKER_STOP;
 
		this->reminder_timeout = REMINDER_STOP;
 

	
 
		this->InitNested(desc);
 
	}
 

	
 
	virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number)
 
	{
 
		Point pt = { (_screen.width - max(sm_width, desc->default_width)) / 2, _screen.height - sm_height };
 
		return pt;
 
	}
 

	
 
	virtual void OnPaint()
 
	{
 
		this->DrawWidgets();
 
	}
 

	
 
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 
	{
 
		Dimension d;
 
		switch (widget) {
 
			case SBW_LEFT:
 
				SetDParam(0, MAX_YEAR * DAYS_IN_YEAR);
 
				d = GetStringBoundingBox(STR_WHITE_DATE_LONG);
 
				break;
 

	
 
			case SBW_RIGHT: {
 
				int64 max_money = UINT32_MAX;
 
				const Company *c;
 
				FOR_ALL_COMPANIES(c) max_money = max<int64>(c->money, max_money);
 
				SetDParam(0, 100LL * max_money);
 
				d = GetStringBoundingBox(STR_COMPANY_MONEY);
 
			} break;
 

	
 
			default:
 
				return;
 
		}
 

	
 
		d.width += padding.width;
 
		d.height += padding.height;
 
		*size = maxdim(d, *size);
 
	}
 

	
 
	virtual void DrawWidget(const Rect &r, int widget) const
 
	{
 
		switch (widget) {
 
			case SBW_LEFT:
 
				/* Draw the date */
 
				SetDParam(0, _date);
 
				DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, (_pause_mode || _settings_client.gui.status_long_date) ? STR_WHITE_DATE_LONG : STR_WHITE_DATE_SHORT, TC_FROMSTRING, SA_CENTER);
 
				break;
 

	
 
			case SBW_RIGHT: {
 
				/* Draw company money, if any */
 
				const Company *c = Company::GetIfValid(_local_company);
 
				if (c != NULL) {
 
					SetDParam(0, c->money);
 
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_COMPANY_MONEY, TC_FROMSTRING, SA_CENTER);
 
				}
 
			} break;
 

	
 
			case SBW_MIDDLE:
 
				/* Draw status bar */
 
				if (this->saving) { // true when saving is active
 
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_SAVING_GAME, TC_FROMSTRING, SA_CENTER);
 
				} else if (_do_autosave) {
 
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_AUTOSAVE, TC_FROMSTRING, SA_CENTER);
 
				} else if (_pause_mode != PM_UNPAUSED) {
 
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_PAUSED, TC_FROMSTRING, SA_CENTER);
 
				} else if (this->ticker_scroll < TICKER_STOP && FindWindowById(WC_NEWS_WINDOW, 0) == NULL && _statusbar_news_item != NULL && _statusbar_news_item->string_id != 0) {
 
					/* Draw the scrolling news text */
 
					if (!DrawScrollingStatusText(_statusbar_news_item, this->ticker_scroll, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom)) {
 
						InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED);
 
						if (Company::IsValidID(_local_company)) {
 
							/* This is the default text */
 
							SetDParam(0, _local_company);
 
							DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_COMPANY_NAME, TC_FROMSTRING, SA_CENTER);
 
						}
 
					}
 
				} else {
 
					if (Company::IsValidID(_local_company)) {
 
						/* This is the default text */
 
						SetDParam(0, _local_company);
 
						DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_COMPANY_NAME, TC_FROMSTRING, SA_CENTER);
 
					}
 
				}
 

	
 
				if (this->reminder_timeout > 0) DrawSprite(SPR_BLOT, PALETTE_TO_RED, r.right - WD_FRAMERECT_RIGHT - 10, r.top + WD_FRAMERECT_TOP + 1);
 
				break;
 
		}
 
	}
 

	
src/toolbar_gui.cpp
Show inline comments
 
@@ -118,197 +118,195 @@ enum ToolbarScenEditorWidgets {
 
};
 

	
 
/**
 
 * Drop down list entry for showing a checked/unchecked toggle item.
 
 */
 
class DropDownListCheckedItem : public DropDownListStringItem {
 
	uint checkmark_width;
 
public:
 
	bool checked;
 

	
 
	DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked)
 
	{
 
		this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3;
 
	}
 

	
 
	virtual ~DropDownListCheckedItem() {}
 

	
 
	uint Width() const
 
	{
 
		return DropDownListStringItem::Width() + this->checkmark_width;
 
	}
 

	
 
	void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
 
	{
 
		bool rtl = _dynlang.text_dir == TD_RTL;
 
		if (this->checked) {
 
			DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK);
 
		}
 
		DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK);
 
	}
 
};
 

	
 
/**
 
 * Drop down list entry for showing a company entry, with companies 'blob'.
 
 */
 
class DropDownListCompanyItem : public DropDownListItem {
 
	uint icon_width;
 
public:
 
	bool greyed;
 

	
 
	DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed)
 
	{
 
		this->icon_width = GetSpriteSize(SPR_COMPANY_ICON).width;
 
	}
 

	
 
	virtual ~DropDownListCompanyItem() {}
 

	
 
	bool Selectable() const
 
	{
 
		return true;
 
	}
 

	
 
	uint Width() const
 
	{
 
		CompanyID company = (CompanyID)this->result;
 
		SetDParam(0, company);
 
		SetDParam(1, company);
 
		return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_width + 3;
 
	}
 

	
 
	void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
 
	{
 
		CompanyID company = (CompanyID)this->result;
 
		bool rtl = _dynlang.text_dir == TD_RTL;
 

	
 
		/* It's possible the company is deleted while the dropdown is open */
 
		if (!Company::IsValidID(company)) return;
 

	
 
		DrawCompanyIcon(company, rtl ? right - this->icon_width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + 1 + (FONT_HEIGHT_NORMAL - 10) / 2);
 

	
 
		SetDParam(0, company);
 
		SetDParam(1, company);
 
		TextColour col;
 
		if (this->greyed) {
 
			col = TC_GREY;
 
		} else {
 
			col = sel ? TC_WHITE : TC_BLACK;
 
		}
 
		DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : 3 + this->icon_width), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_width : 0), top, STR_COMPANY_NAME_COMPANY_NUM, col);
 
	}
 
};
 

	
 
/**
 
 * Pop up a generic text only menu.
 
 */
 
static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count)
 
{
 
	DropDownList *list = new DropDownList();
 
	for (int i = 0; i < count; i++) {
 
		list->push_back(new DropDownListStringItem(string + i, i, false));
 
	}
 
	ShowDropDownList(w, list, 0, widget, 140, true, true);
 
	SndPlayFx(SND_15_BEEP);
 
}
 

	
 
/** Enum for the Company Toolbar's network related buttons */
 
enum {
 
	CTMN_CLIENT_LIST = -1, ///< Show the client list
 
	CTMN_NEW_COMPANY = -2, ///< Create a new company
 
	CTMN_SPECTATE    = -3, ///< Become spectator
 
};
 
static const int CTMN_CLIENT_LIST = -1; ///< Show the client list
 
static const int CTMN_NEW_COMPANY = -2; ///< Create a new company
 
static const int CTMN_SPECTATE    = -3; ///< Become spectator
 

	
 
/**
 
 * Pop up a generic company list menu.
 
 */
 
static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0)
 
{
 
	DropDownList *list = new DropDownList();
 

	
 
#ifdef ENABLE_NETWORK
 
	if (widget == TBN_COMPANIES && _networking) {
 
		/* Add the client list button for the companies menu */
 
		list->push_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false));
 

	
 
		if (_local_company == COMPANY_SPECTATOR) {
 
			list->push_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached()));
 
		} else {
 
			list->push_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached()));
 
		}
 
	}
 
#endif /* ENABLE_NETWORK */
 

	
 
	for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
 
		if (!Company::IsValidID(c)) continue;
 
		list->push_back(new DropDownListCompanyItem(c, false, HasBit(grey, c)));
 
	}
 

	
 
	ShowDropDownList(w, list, _local_company == COMPANY_SPECTATOR ? CTMN_CLIENT_LIST : (int)_local_company, widget, 240, true, true);
 
	SndPlayFx(SND_15_BEEP);
 
}
 

	
 

	
 
static ToolbarMode _toolbar_mode;
 

	
 
static void SelectSignTool()
 
{
 
	if (_cursor.sprite == SPR_CURSOR_SIGN) {
 
		ResetObjectToPlace();
 
	} else {
 
		SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
 
		_place_proc = PlaceProc_Sign;
 
	}
 
}
 

	
 
/* --- Pausing --- */
 

	
 
static void ToolbarPauseClick(Window *w)
 
{
 
	if (_networking && !_network_server) return; // only server can pause the game
 

	
 
	if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) SndPlayFx(SND_15_BEEP);
 
}
 

	
 
/* --- Fast forwarding --- */
 

	
 
static void ToolbarFastForwardClick(Window *w)
 
{
 
	_fast_forward ^= true;
 
	SndPlayFx(SND_15_BEEP);
 
}
 

	
 
/* --- Options button menu --- */
 

	
 
enum OptionMenuEntries {
 
	OME_GAMEOPTIONS,
 
	OME_DIFFICULTIES,
 
	OME_SETTINGS,
 
	OME_NEWGRFSETTINGS,
 
	OME_TRANSPARENCIES,
 
	OME_SHOW_TOWNNAMES,
 
	OME_SHOW_STATIONNAMES,
 
	OME_SHOW_WAYPOINTNAMES,
 
	OME_SHOW_SIGNS,
 
	OME_FULL_ANIMATION,
 
	OME_FULL_DETAILS,
 
	OME_TRANSPARENTBUILDINGS,
 
	OME_SHOW_STATIONSIGNS,
 
};
 

	
 
static void ToolbarOptionsClick(Window *w)
 
{
 
	DropDownList *list = new DropDownList();
 
	list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS,             OME_GAMEOPTIONS, false));
 
	list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_DIFFICULTY_SETTINGS,      OME_DIFFICULTIES, false));
 
	list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS,          OME_SETTINGS, false));
 
	list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS,          OME_NEWGRFSETTINGS, false));
 
	list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS,     OME_TRANSPARENCIES, false));
 
	list->push_back(new DropDownListItem(-1, false));
 
	list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED,    OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES)));
 
	list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES)));
 
	list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED,     OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)));
 
	list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED,         OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS)));
 
	list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION,          OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION)));
 
	list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL,             OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL)));
 
	list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS,   OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES)));
 
	list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS,       OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS)));
 

	
src/train_gui.cpp
Show inline comments
 
@@ -33,365 +33,363 @@ void CcBuildWagon(const CommandCost &res
 
	const Train *t;
 
	FOR_ALL_TRAINS(t) {
 
		if (t->IsFrontEngine() && t->tile == tile &&
 
				t->track == TRACK_BIT_DEPOT) {
 
			if (found != NULL) return; // must be exactly one.
 
			found = t;
 
		}
 
	}
 

	
 
	/* if we found a loco, */
 
	if (found != NULL) {
 
		found = found->Last();
 
		/* put the new wagon at the end of the loco. */
 
		DoCommandP(0, _new_vehicle_id | (found->index << 16), 0, CMD_MOVE_RAIL_VEHICLE);
 
		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
	}
 
}
 

	
 
/**
 
 * Draws an image of a whole train
 
 * @param v         Front vehicle
 
 * @param left      The minimum horizontal position
 
 * @param right     The maximum horizontal position
 
 * @param y         Vertical position to draw at
 
 * @param selection Selected vehicle to draw a frame around
 
 * @param skip      Number of pixels to skip at the front (for scrolling)
 
 */
 
void DrawTrainImage(const Train *v, int left, int right, int y, VehicleID selection, int skip)
 
{
 
	bool rtl = _dynlang.text_dir == TD_RTL;
 
	Direction dir = rtl ? DIR_E : DIR_W;
 

	
 
	DrawPixelInfo tmp_dpi, *old_dpi;
 
	/* Position of highlight box */
 
	int highlight_l = 0;
 
	int highlight_r = 0;
 
	int max_width = right - left + 1;
 

	
 
	if (!FillDrawPixelInfo(&tmp_dpi, left, y, max_width, 14)) return;
 

	
 
	old_dpi = _cur_dpi;
 
	_cur_dpi = &tmp_dpi;
 

	
 
	int px = rtl ? max_width + skip : -skip;
 
	bool sel_articulated = false;
 
	for (; v != NULL && (rtl ? px > 0 : px < max_width); v = v->Next()) {
 
		Point offset;
 
		int width = Train::From(v)->GetDisplayImageWidth(&offset);
 

	
 
		if (rtl ? px + width > 0 : px - width < max_width) {
 
			PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 
			DrawSprite(v->GetImage(dir), pal, px + (rtl ? -offset.x : offset.x), 7 + offset.y);
 
		}
 

	
 
		if (!v->IsArticulatedPart()) sel_articulated = false;
 

	
 
		if (v->index == selection) {
 
			/* Set the highlight position */
 
			highlight_l = rtl ? px - width : px;
 
			highlight_r = rtl ? px - 1 : px + width - 1;
 
			sel_articulated = true;
 
		} else if ((_cursor.vehchain && highlight_r != 0) || sel_articulated) {
 
			if (rtl) {
 
				highlight_l -= width;
 
			} else {
 
				highlight_r += width;
 
			}
 
		}
 

	
 
		px += rtl ? -width : width;
 
	}
 

	
 
	if (highlight_l != highlight_r) {
 
		/* Draw the highlight. Now done after drawing all the engines, as
 
		 * the next engine after the highlight could overlap it. */
 
		DrawFrameRect(highlight_l, 0, highlight_r, 13, COLOUR_WHITE, FR_BORDERONLY);
 
	}
 

	
 
	_cur_dpi = old_dpi;
 
}
 

	
 
/** Helper struct for the cargo details information */
 
struct CargoSummaryItem {
 
	CargoID cargo;    ///< The cargo that is carried
 
	StringID subtype; ///< STR_EMPTY if none
 
	uint capacity;    ///< Amount that can be carried
 
	uint amount;      ///< Amount that is carried
 
	StationID source; ///< One of the source stations
 

	
 
	/** Used by CargoSummary::Find() and similiar functions */
 
	FORCEINLINE bool operator != (const CargoSummaryItem &other) const
 
	{
 
		return this->cargo != other.cargo || this->subtype != other.subtype;
 
	}
 
};
 

	
 
enum {
 
	TRAIN_DETAILS_MIN_INDENT = 32, ///< Minimum indent level in the train details window
 
	TRAIN_DETAILS_MAX_INDENT = 72, ///< Maximum indent level in the train details window; wider than this and we start on a new line
 
};
 
static const uint TRAIN_DETAILS_MIN_INDENT = 32; ///< Minimum indent level in the train details window
 
static const uint TRAIN_DETAILS_MAX_INDENT = 72; ///< Maximum indent level in the train details window; wider than this and we start on a new line
 

	
 
/** Container for the cargo summary information. */
 
typedef SmallVector<CargoSummaryItem, 2> CargoSummary;
 
/** Reused container of cargo details */
 
static CargoSummary _cargo_summary;
 

	
 
/**
 
 * Draw the details cargo tab for the given vehicle at the given position
 
 *
 
 * @param item  Data to draw
 
 * @param left  The left most coordinate to draw
 
 * @param right The right most coordinate to draw
 
 * @param y     The y coordinate
 
 */
 
static void TrainDetailsCargoTab(const CargoSummaryItem *item, int left, int right, int y)
 
{
 
	StringID str = STR_VEHICLE_DETAILS_CARGO_EMPTY;
 

	
 
	if (item->amount > 0) {
 
		SetDParam(0, item->cargo);
 
		SetDParam(1, item->amount);
 
		SetDParam(2, item->source);
 
		SetDParam(3, _settings_game.vehicle.freight_trains);
 
		str = FreightWagonMult(item->cargo) > 1 ? STR_VEHICLE_DETAILS_CARGO_FROM_MULT : STR_VEHICLE_DETAILS_CARGO_FROM;
 
	}
 

	
 
	DrawString(left, right, y, str);
 
}
 

	
 
/**
 
 * Draw the details info tab for the given vehicle at the given position
 
 *
 
 * @param v     current vehicle
 
 * @param left  The left most coordinate to draw
 
 * @param right The right most coordinate to draw
 
 * @param y     The y coordinate
 
 */
 
static void TrainDetailsInfoTab(const Vehicle *v, int left, int right, int y)
 
{
 
	if (RailVehInfo(v->engine_type)->railveh_type == RAILVEH_WAGON) {
 
		SetDParam(0, v->engine_type);
 
		SetDParam(1, v->value);
 
		DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE, TC_FROMSTRING, SA_LEFT | SA_STRIP);
 
	} else {
 
		SetDParam(0, v->engine_type);
 
		SetDParam(1, v->build_year);
 
		SetDParam(2, v->value);
 
		DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE, TC_FROMSTRING, SA_LEFT | SA_STRIP);
 
	}
 
}
 

	
 
/**
 
 * Draw the details capacity tab for the given vehicle at the given position
 
 *
 
 * @param item  Data to draw
 
 * @param left  The left most coordinate to draw
 
 * @param right The right most coordinate to draw
 
 * @param y     The y coordinate
 
 */
 
static void TrainDetailsCapacityTab(const CargoSummaryItem *item, int left, int right, int y)
 
{
 
	SetDParam(0, item->cargo);
 
	SetDParam(1, item->capacity);
 
	SetDParam(4, item->subtype);
 
	SetDParam(5, _settings_game.vehicle.freight_trains);
 
	DrawString(left, right, y, FreightWagonMult(item->cargo) > 1 ? STR_VEHICLE_INFO_CAPACITY_MULT : STR_VEHICLE_INFO_CAPACITY);
 
}
 

	
 
/**
 
 * Collects the cargo transportet
 
 * @param v Vehicle to process
 
 * @param summary Space for the result
 
 */
 
static void GetCargoSummaryOfArticulatedVehicle(const Train *v, CargoSummary *summary)
 
{
 
	summary->Clear();
 
	do {
 
		if (v->cargo_cap == 0) continue;
 

	
 
		CargoSummaryItem new_item;
 
		new_item.cargo = v->cargo_type;
 
		new_item.subtype = GetCargoSubtypeText(v);
 

	
 
		CargoSummaryItem *item = summary->Find(new_item);
 
		if (item == summary->End()) {
 
			item = summary->Append();
 
			item->cargo = new_item.cargo;
 
			item->subtype = new_item.subtype;
 
			item->capacity = 0;
 
			item->amount = 0;
 
			item->source = INVALID_STATION;
 
		}
 

	
 
		item->capacity += v->cargo_cap;
 
		item->amount += v->cargo.Count();
 
		if (item->source == INVALID_STATION) item->source = v->cargo.Source();
 
	} while ((v = v->Next()) != NULL && v->IsArticulatedPart());
 
}
 

	
 
/**
 
 * Get the length of an articulated vehicle.
 
 * @param v the vehicle to get the length of.
 
 * @return the length in pixels.
 
 */
 
static uint GetLengthOfArticulatedVehicle(const Train *v)
 
{
 
	uint length = 0;
 

	
 
	do {
 
		length += v->GetDisplayImageWidth();
 
	} while ((v = v->Next()) != NULL && v->IsArticulatedPart());
 

	
 
	return length;
 
}
 

	
 
/**
 
 * Determines the number of lines in the train details window
 
 * @param veh_id Train
 
 * @param det_tab Selected details tab
 
 * @return Number of line
 
 */
 
int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab)
 
{
 
	int num = 0;
 

	
 
	if (det_tab == TDW_TAB_TOTALS) { // Total cargo tab
 
		CargoArray act_cargo;
 
		CargoArray max_cargo;
 
		for (const Vehicle *v = Vehicle::Get(veh_id); v != NULL; v = v->Next()) {
 
			act_cargo[v->cargo_type] += v->cargo.Count();
 
			max_cargo[v->cargo_type] += v->cargo_cap;
 
		}
 

	
 
		/* Set scroll-amount seperately from counting, as to not compute num double
 
		 * for more carriages of the same type
 
		 */
 
		for (CargoID i = 0; i < NUM_CARGO; i++) {
 
			if (max_cargo[i] > 0) num++; // only count carriages that the train has
 
		}
 
		num++; // needs one more because first line is description string
 
	} else {
 
		for (const Train *v = Train::Get(veh_id); v != NULL; v = v->GetNextVehicle()) {
 
			GetCargoSummaryOfArticulatedVehicle(v, &_cargo_summary);
 
			num += max(1u, _cargo_summary.Length());
 

	
 
			uint length = GetLengthOfArticulatedVehicle(v);
 
			if (length > TRAIN_DETAILS_MAX_INDENT) num++;
 
		}
 
	}
 

	
 
	return num;
 
}
 

	
 
/**
 
 * Draw the details for the given vehicle at the given position
 
 *
 
 * @param v     current vehicle
 
 * @param left  The left most coordinate to draw
 
 * @param right The right most coordinate to draw
 
 * @param y     The y coordinate
 
 * @param vscroll_pos Position of scrollbar
 
 * @param vscroll_cap Number of lines currently displayed
 
 * @param det_tab Selected details tab
 
 */
 
void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_pos, uint16 vscroll_cap, TrainDetailsWindowTabs det_tab)
 
{
 
	/* draw the first 3 details tabs */
 
	if (det_tab != TDW_TAB_TOTALS) {
 
		bool rtl = _dynlang.text_dir == TD_RTL;
 
		Direction dir = rtl ? DIR_E : DIR_W;
 
		int x = rtl ? right : left;
 
		int sprite_y_offset = 4 + (FONT_HEIGHT_NORMAL - 10) / 2;
 
		int line_height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
 
		for (; v != NULL && vscroll_pos > -vscroll_cap; v = v->GetNextVehicle()) {
 
			GetCargoSummaryOfArticulatedVehicle(v, &_cargo_summary);
 

	
 
			/* Draw sprites */
 
			int dx = 0;
 
			uint dx = 0;
 
			int px = x;
 
			const Train *u = v;
 
			do {
 
				Point offset;
 
				int width = u->GetDisplayImageWidth(&offset);
 
				if (vscroll_pos <= 0 && vscroll_pos > -vscroll_cap) {
 
					PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 
					DrawSprite(u->GetImage(dir), pal, px + (rtl ? -offset.x : offset.x), y - line_height * vscroll_pos + sprite_y_offset + offset.y);
 
				}
 
				px += rtl ? -width : width;
 
				dx += width;
 
				u = u->Next();
 
			} while (u != NULL && u->IsArticulatedPart());
 

	
 
			bool separate_sprite_row = (dx > TRAIN_DETAILS_MAX_INDENT);
 
			if (separate_sprite_row) {
 
				vscroll_pos--;
 
				dx = 0;
 
			}
 

	
 
			uint num_lines = max(1u, _cargo_summary.Length());
 
			for (uint i = 0; i < num_lines; i++) {
 
				int sprite_width = max<int>(dx, TRAIN_DETAILS_MIN_INDENT) + 3;
 
				int data_left  = left + (rtl ? 0 : sprite_width);
 
				int data_right = right - (rtl ? sprite_width : 0);
 
				if (vscroll_pos <= 0 && vscroll_pos > -vscroll_cap) {
 
					int py = y - line_height * vscroll_pos;
 
					if (i > 0 || separate_sprite_row) {
 
						if (vscroll_pos != 0) GfxFillRect(left, py - WD_MATRIX_TOP - 1, right, py - WD_MATRIX_TOP, _colour_gradient[COLOUR_GREY][5]);
 
					}
 
					switch (det_tab) {
 
						case TDW_TAB_CARGO:
 
							if (i < _cargo_summary.Length()) {
 
								TrainDetailsCargoTab(&_cargo_summary[i], data_left, data_right, py);
 
							} else {
 
								DrawString(data_left, data_right, py, STR_QUANTITY_N_A, TC_LIGHT_BLUE);
 
							}
 
							break;
 

	
 
						case TDW_TAB_INFO:
 
							if (i == 0) TrainDetailsInfoTab(v, data_left, data_right, py);
 
							break;
 

	
 
						case TDW_TAB_CAPACITY:
 
							if (i < _cargo_summary.Length()) {
 
								TrainDetailsCapacityTab(&_cargo_summary[i], data_left, data_right, py);
 
							} else {
 
								DrawString(data_left, data_right, py, STR_VEHICLE_INFO_NO_CAPACITY);
 
							}
 
							break;
 

	
 
						default: NOT_REACHED();
 
					}
 
				}
 
				vscroll_pos--;
 
			}
 
		}
 
	} else {
 
		CargoArray act_cargo;
 
		CargoArray max_cargo;
 
		Money feeder_share = 0;
 

	
 
		for (const Vehicle *u = v; u != NULL; u = u->Next()) {
 
			act_cargo[u->cargo_type] += u->cargo.Count();
 
			max_cargo[u->cargo_type] += u->cargo_cap;
 
			feeder_share             += u->cargo.FeederShare();
 
		}
 

	
 
		/* draw total cargo tab */
 
		DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT);
 
		y += WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
 

	
 
		for (CargoID i = 0; i < NUM_CARGO; i++) {
 
			if (max_cargo[i] > 0 && --vscroll_pos < 0 && vscroll_pos > -vscroll_cap) {
 
				SetDParam(0, i);            // {CARGO} #1
 
				SetDParam(1, act_cargo[i]); // {CARGO} #2
 
				SetDParam(2, i);            // {SHORTCARGO} #1
 
				SetDParam(3, max_cargo[i]); // {SHORTCARGO} #2
 
				SetDParam(4, _settings_game.vehicle.freight_trains);
 
				DrawString(left, right, y, FreightWagonMult(i) > 1 ? STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT : STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY);
 
				y += WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
 
			}
 
		}
 
		SetDParam(0, feeder_share);
 
		DrawString(left, right, y, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE);
 
	}
 
}
src/video/allegro_v.cpp
Show inline comments
 
@@ -225,196 +225,194 @@ static bool CreateMainSurface(uint w, ui
 
	char caption[32];
 
	snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision);
 
	set_window_title(caption);
 

	
 
	GameSizeChanged();
 

	
 
	return true;
 
}
 

	
 
struct VkMapping {
 
	uint16 vk_from;
 
	byte vk_count;
 
	byte map_to;
 
};
 

	
 
#define AS(x, z) {x, 0, z}
 
#define AM(x, y, z, w) {x, y - x, z}
 

	
 
static const VkMapping _vk_mapping[] = {
 
	/* Pageup stuff + up/down */
 
	AM(KEY_PGUP, KEY_PGDN, WKC_PAGEUP, WKC_PAGEDOWN),
 
	AS(KEY_UP,     WKC_UP),
 
	AS(KEY_DOWN,   WKC_DOWN),
 
	AS(KEY_LEFT,   WKC_LEFT),
 
	AS(KEY_RIGHT,  WKC_RIGHT),
 

	
 
	AS(KEY_HOME,   WKC_HOME),
 
	AS(KEY_END,    WKC_END),
 

	
 
	AS(KEY_INSERT, WKC_INSERT),
 
	AS(KEY_DEL,    WKC_DELETE),
 

	
 
	/* Map letters & digits */
 
	AM(KEY_A, KEY_Z, 'A', 'Z'),
 
	AM(KEY_0, KEY_9, '0', '9'),
 

	
 
	AS(KEY_ESC,       WKC_ESC),
 
	AS(KEY_PAUSE,     WKC_PAUSE),
 
	AS(KEY_BACKSPACE, WKC_BACKSPACE),
 

	
 
	AS(KEY_SPACE,     WKC_SPACE),
 
	AS(KEY_ENTER,     WKC_RETURN),
 
	AS(KEY_TAB,       WKC_TAB),
 

	
 
	/* Function keys */
 
	AM(KEY_F1, KEY_F12, WKC_F1, WKC_F12),
 

	
 
	/* Numeric part. */
 
	AM(KEY_0_PAD, KEY_9_PAD, '0', '9'),
 
	AS(KEY_SLASH_PAD,   WKC_NUM_DIV),
 
	AS(KEY_ASTERISK,    WKC_NUM_MUL),
 
	AS(KEY_MINUS_PAD,   WKC_NUM_MINUS),
 
	AS(KEY_PLUS_PAD,    WKC_NUM_PLUS),
 
	AS(KEY_ENTER_PAD,   WKC_NUM_ENTER),
 
	AS(KEY_DEL_PAD,     WKC_DELETE),
 

	
 
	/* Other non-letter keys */
 
	AS(KEY_SLASH,        WKC_SLASH),
 
	AS(KEY_SEMICOLON,    WKC_SEMICOLON),
 
	AS(KEY_EQUALS,       WKC_EQUALS),
 
	AS(KEY_OPENBRACE,    WKC_L_BRACKET),
 
	AS(KEY_BACKSLASH,    WKC_BACKSLASH),
 
	AS(KEY_CLOSEBRACE,   WKC_R_BRACKET),
 

	
 
	AS(KEY_QUOTE,   WKC_SINGLEQUOTE),
 
	AS(KEY_COMMA,   WKC_COMMA),
 
	AS(KEY_MINUS,   WKC_MINUS),
 
	AS(KEY_STOP,    WKC_PERIOD),
 
	AS(KEY_TILDE,   WKC_BACKQUOTE),
 
};
 

	
 
static uint32 ConvertAllegroKeyIntoMy()
 
{
 
	int scancode;
 
	int unicode = ureadkey(&scancode);
 

	
 
	const VkMapping *map;
 
	uint key = 0;
 

	
 
	for (map = _vk_mapping; map != endof(_vk_mapping); ++map) {
 
		if ((uint)(scancode - map->vk_from) <= map->vk_count) {
 
			key = scancode - map->vk_from + map->map_to;
 
			break;
 
		}
 
	}
 

	
 
	if (key_shifts & KB_SHIFT_FLAG) key |= WKC_SHIFT;
 
	if (key_shifts & KB_CTRL_FLAG)  key |= WKC_CTRL;
 
	if (key_shifts & KB_ALT_FLAG)   key |= WKC_ALT;
 
#if 0
 
	DEBUG(driver, 0, "Scancode character pressed %u", scancode);
 
	DEBUG(driver, 0, "Unicode character pressed %u", unicode);
 
#endif
 
	return (key << 16) + unicode;
 
}
 

	
 
enum {
 
	LEFT_BUTTON,
 
	RIGHT_BUTTON,
 
};
 
static const uint LEFT_BUTTON  = 0;
 
static const uint RIGHT_BUTTON = 1;
 

	
 
static void PollEvent()
 
{
 
	poll_mouse();
 

	
 
	bool mouse_action = false;
 

	
 
	/* Mouse buttons */
 
	static int prev_button_state;
 
	if (prev_button_state != mouse_b) {
 
		uint diff = prev_button_state ^ mouse_b;
 
		while (diff != 0) {
 
			int button = FindFirstBit(diff);
 
			ClrBit(diff, button);
 
			if (HasBit(mouse_b, button)) {
 
				/* Pressed mouse button */
 
				if (_rightclick_emulate && (key_shifts & KB_CTRL_FLAG)) {
 
					button = RIGHT_BUTTON;
 
					ClrBit(diff, RIGHT_BUTTON);
 
				}
 
				switch (button) {
 
					case LEFT_BUTTON:
 
						_left_button_down = true;
 
						break;
 

	
 
					case RIGHT_BUTTON:
 
						_right_button_down = true;
 
						_right_button_clicked = true;
 
						break;
 

	
 
					default:
 
						/* ignore rest */
 
						break;
 
				}
 
			} else {
 
				/* Released mouse button */
 
				if (_rightclick_emulate) {
 
					_right_button_down = false;
 
					_left_button_down = false;
 
					_left_button_clicked = false;
 
				} else if (button == LEFT_BUTTON) {
 
					_left_button_down = false;
 
					_left_button_clicked = false;
 
				} else if (button == RIGHT_BUTTON) {
 
					_right_button_down = false;
 
				}
 
			}
 
		}
 
		prev_button_state = mouse_b;
 
		mouse_action = true;
 
	}
 

	
 
	/* Mouse movement */
 
	int dx = mouse_x - _cursor.pos.x;
 
	int dy = mouse_y - _cursor.pos.y;
 
	if (dx != 0 || dy != 0) {
 
		if (_cursor.fix_at) {
 
			_cursor.delta.x = dx;
 
			_cursor.delta.y = dy;
 
			position_mouse(_cursor.pos.x, _cursor.pos.y);
 
		} else {
 
			_cursor.delta.x = dx;
 
			_cursor.delta.y = dy;
 
			_cursor.pos.x = mouse_x;
 
			_cursor.pos.y = mouse_y;
 
			_cursor.dirty = true;
 
		}
 
		mouse_action = true;
 
	}
 

	
 
	static int prev_mouse_z = 0;
 
	if (prev_mouse_z != mouse_z) {
 
		_cursor.wheel = (prev_mouse_z - mouse_z) < 0 ? -1 : 1;
 
		prev_mouse_z = mouse_z;
 
		mouse_action = true;
 
	}
 

	
 
	if (mouse_action) HandleMouseEvents();
 

	
 
	poll_keyboard();
 
	if ((key_shifts & KB_ALT_FLAG) && (key[KEY_ENTER] || key[KEY_F])) {
 
		ToggleFullScreen(!_fullscreen);
 
	} else if (keypressed()) {
 
		HandleKeypress(ConvertAllegroKeyIntoMy());
 
	}
 
}
 

	
 
/** There are multiple modules that might be using Allegro and
 
 * Allegro can only be initiated once. */
 
int _allegro_instance_count = 0;
 

	
 
const char *VideoDriver_Allegro::Start(const char * const *parm)
 
{
 
	if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, NULL)) {
 
		DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error);
 
		return "Failed to set up Allegro";
src/video/cocoa/event.mm
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/******************************************************************************
 
 *                             Cocoa video driver                             *
 
 * Known things left to do:                                                   *
 
 *  Nothing at the moment.                                                    *
 
 ******************************************************************************/
 

	
 
#ifdef WITH_COCOA
 

	
 
#include "../../stdafx.h"
 

	
 
#define Rect  OTTDRect
 
#define Point OTTDPoint
 
#import <Cocoa/Cocoa.h>
 
#undef Rect
 
#undef Point
 

	
 
#include "../../openttd.h"
 
#include "../../debug.h"
 
#include "../../os/macosx/splash.h"
 
#include "../../variables.h"
 
#include "../../settings_type.h"
 
#include "../../core/geometry_type.hpp"
 
#include "cocoa_v.h"
 
#include "cocoa_keys.h"
 
#include "../../blitter/factory.hpp"
 
#include "../../gfx_func.h"
 
#include "../../network/network.h"
 
#include "../../core/random_func.hpp"
 
#include "../../texteff.hpp"
 

	
 
#import <sys/time.h> /* gettimeofday */
 

	
 
/**
 
 * Important notice regarding all modifications!!!!!!!
 
 * There are certain limitations because the file is objective C++.
 
 * gdb has limitations.
 
 * C++ and objective C code can't be joined in all cases (classes stuff).
 
 * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information.
 
 */
 

	
 

	
 
/* Right Mouse Button Emulation enum */
 
enum {
 
enum RightMouseButtonEmulationState {
 
	RMBE_COMMAND,
 
	RMBE_CONTROL,
 
	RMBE_OFF,
 
};
 

	
 

	
 
static bool _show_mouse = true;
 
static unsigned int _current_mods;
 
static bool _tab_is_down;
 
static bool _emulating_right_button;
 
#ifdef _DEBUG
 
static uint32 _tEvent;
 
#endif
 

	
 

	
 
static uint32 GetTick()
 
{
 
	struct timeval tim;
 

	
 
	gettimeofday(&tim, NULL);
 
	return tim.tv_usec / 1000 + tim.tv_sec * 1000;
 
}
 

	
 

	
 
void QZ_ShowMouse()
 
{
 
	if (!_show_mouse) {
 
		[ NSCursor unhide ];
 
		_show_mouse = true;
 

	
 
		/* Hide the openttd cursor when leaving the window */
 
		if (_cocoa_subdriver != NULL) UndrawMouseCursor();
 
		_cursor.in_window = false;
 
	}
 
}
 

	
 
void QZ_HideMouse()
 
{
 
	if (_show_mouse) {
 
		/* Don't hide the cursor when compiling in debug mode.
 
		 * Note: Not hiding the cursor will cause artefacts around it in 8bpp fullscreen mode. */
 
#ifndef _DEBUG
 
		[ NSCursor hide ];
 
#endif
 
		_show_mouse = false;
 

	
 
		/* Show the openttd cursor again */
 
		_cursor.in_window = true;
 
	}
 
}
 

	
 
static void QZ_WarpCursor(int x, int y)
 
{
 
	assert(_cocoa_subdriver != NULL);
 

	
 
	/* Only allow warping when in foreground */
 
	if (![ NSApp isActive ]) return;
 

	
 
	NSPoint p = NSMakePoint(x, y);
 
	CGPoint cgp = _cocoa_subdriver->PrivateLocalToCG(&p);
 

	
 
	/* this is the magic call that fixes cursor "freezing" after warp */
 
	CGSetLocalEventsSuppressionInterval(0.0);
 
	/* Do the actual warp */
 
	CGWarpMouseCursorPosition(cgp);
 
}
 

	
 

	
 
static void QZ_CheckPaletteAnim()
 
{
 
	if (_pal_count_dirty != 0) {
 
		Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 

	
 
		switch (blitter->UsePaletteAnimation()) {
 
			case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND:
 
				_cocoa_subdriver->UpdatePalette(_pal_first_dirty, _pal_count_dirty);
 
				break;
 

	
 
			case Blitter::PALETTE_ANIMATION_BLITTER:
 
				blitter->PaletteAnimate(_pal_first_dirty, _pal_count_dirty);
 
				break;
 

	
 
			case Blitter::PALETTE_ANIMATION_NONE:
 
				break;
 

	
 
			default:
 
				NOT_REACHED();
 
		}
 
		_pal_count_dirty = 0;
 
	}
 
}
 

	
 

	
 

	
 
struct VkMapping {
 
	unsigned short vk_from;
0 comments (0 inline, 0 general)