Changeset - r15282:8e9c51163c93
[Not reviewed]
master
0 17 0
frosch - 14 years ago 2010-06-05 12:16:12
frosch@openttd.org
(svn r19931) -Fix (r19914): Convert assertion in Backup<> destructor into DEBUG() output. It was triggered on exceptions, especially when aborting world generation.
17 files changed with 62 insertions and 44 deletions:
0 comments (0 inline, 0 general)
src/ai/ai_core.cpp
Show inline comments
 
@@ -48,92 +48,92 @@
 
		config->ChangeAI(info->GetName(), -1, false, true);
 
	}
 

	
 
	_current_company = company;
 
	Company *c = Company::Get(company);
 

	
 
	c->ai_info = info;
 
	assert(c->ai_instance == NULL);
 
	c->ai_instance = new AIInstance(info);
 

	
 
	InvalidateWindowData(WC_AI_DEBUG, 0, -1);
 
	return;
 
}
 

	
 
/* static */ void AI::GameLoop()
 
{
 
	/* If we are in networking, only servers run this function, and that only if it is allowed */
 
	if (_networking && (!_network_server || !_settings_game.ai.ai_in_multiplayer)) return;
 

	
 
	/* The speed with which AIs go, is limited by the 'competitor_speed' */
 
	AI::frame_counter++;
 
	assert(_settings_game.difficulty.competitor_speed <= 4);
 
	if ((AI::frame_counter & ((1 << (4 - _settings_game.difficulty.competitor_speed)) - 1)) != 0) return;
 

	
 
	Backup<CompanyByte> cur_company(_current_company);
 
	Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
 
	const Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		if (c->is_ai) {
 
			cur_company.Change(c->index);
 
			c->ai_instance->GameLoop();
 
		}
 
	}
 
	cur_company.Restore();
 

	
 
	/* Occasionally collect garbage; every 255 ticks do one company.
 
	 * Effectively collecting garbage once every two months per AI. */
 
	if ((AI::frame_counter & 255) == 0) {
 
		CompanyID cid = (CompanyID)GB(AI::frame_counter, 8, 4);
 
		if (Company::IsValidAiID(cid)) Company::Get(cid)->ai_instance->CollectGarbage();
 
	}
 
}
 

	
 
/* static */ uint AI::GetTick()
 
{
 
	return AI::frame_counter;
 
}
 

	
 
/* static */ void AI::Stop(CompanyID company)
 
{
 
	if (_networking && !_network_server) return;
 

	
 
	Backup<CompanyByte> cur_company(_current_company, company);
 
	Backup<CompanyByte> cur_company(_current_company, company, FILE_LINE);
 
	Company *c = Company::Get(company);
 

	
 
	delete c->ai_instance;
 
	c->ai_instance = NULL;
 

	
 
	cur_company.Restore();
 

	
 
	InvalidateWindowData(WC_AI_DEBUG, 0, -1);
 
	DeleteWindowById(WC_AI_SETTINGS, company);
 
}
 

	
 
/* static */ void AI::Suspend(CompanyID company)
 
{
 
	if (_networking && !_network_server) return;
 

	
 
	Backup<CompanyByte> cur_company(_current_company, company);
 
	Backup<CompanyByte> cur_company(_current_company, company, FILE_LINE);
 
	Company::Get(company)->ai_instance->Suspend();
 

	
 
	cur_company.Restore();
 
}
 

	
 
/* static */ void AI::KillAll()
 
{
 
	/* It might happen there are no companies .. than we have nothing to loop */
 
	if (Company::GetPoolSize() == 0) return;
 

	
 
	const Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		if (c->is_ai) AI::Stop(c->index);
 
	}
 
}
 

	
 
/* static */ void AI::Initialize()
 
{
 
	if (AI::ai_scanner != NULL) AI::Uninitialize(true);
 

	
 
	AI::frame_counter = 0;
 
	if (AI::ai_scanner == NULL) AI::ai_scanner = new AIScanner();
 
}
 

	
 
@@ -180,109 +180,109 @@
 
				_settings_newgame.ai_config[c]->ChangeAI(NULL);
 
			}
 
		}
 
	}
 
}
 

	
 
/* static */ void AI::NewEvent(CompanyID company, AIEvent *event)
 
{
 
	/* AddRef() and Release() need to be called at least once, so do it here */
 
	event->AddRef();
 

	
 
	/* Clients should ignore events */
 
	if (_networking && !_network_server) {
 
		event->Release();
 
		return;
 
	}
 

	
 
	/* Only AIs can have an event-queue */
 
	if (!Company::IsValidAiID(company)) {
 
		event->Release();
 
		return;
 
	}
 

	
 
	/* Queue the event */
 
	Backup<CompanyByte> cur_company(_current_company, company);
 
	Backup<CompanyByte> cur_company(_current_company, company, FILE_LINE);
 
	AIEventController::InsertEvent(event);
 
	cur_company.Restore();
 

	
 
	event->Release();
 
}
 

	
 
/* static */ void AI::BroadcastNewEvent(AIEvent *event, CompanyID skip_company)
 
{
 
	/* AddRef() and Release() need to be called at least once, so do it here */
 
	event->AddRef();
 

	
 
	/* Clients should ignore events */
 
	if (_networking && !_network_server) {
 
		event->Release();
 
		return;
 
	}
 

	
 
	/* Try to send the event to all AIs */
 
	for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
 
		if (c != skip_company) AI::NewEvent(c, event);
 
	}
 

	
 
	event->Release();
 
}
 

	
 
void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	AIObject::SetLastCommandRes(result.Succeeded());
 

	
 
	if (result.Failed()) {
 
		AIObject::SetLastError(AIError::StringToError(result.GetErrorMessage()));
 
	} else {
 
		AIObject::IncreaseDoCommandCosts(result.GetCost());
 
		AIObject::SetLastCost(result.GetCost());
 
	}
 

	
 
	Company::Get(_current_company)->ai_instance->Continue();
 
}
 

	
 
/* static */ void AI::Save(CompanyID company)
 
{
 
	if (!_networking || _network_server) {
 
		Company *c = Company::GetIfValid(company);
 
		assert(c != NULL && c->ai_instance != NULL);
 

	
 
		Backup<CompanyByte> cur_company(_current_company, company);
 
		Backup<CompanyByte> cur_company(_current_company, company, FILE_LINE);
 
		c->ai_instance->Save();
 
		cur_company.Restore();
 
	} else {
 
		AIInstance::SaveEmpty();
 
	}
 
}
 

	
 
/* static */ void AI::Load(CompanyID company, int version)
 
{
 
	if (!_networking || _network_server) {
 
		Company *c = Company::GetIfValid(company);
 
		assert(c != NULL && c->ai_instance != NULL);
 

	
 
		Backup<CompanyByte> cur_company(_current_company, company);
 
		Backup<CompanyByte> cur_company(_current_company, company, FILE_LINE);
 
		c->ai_instance->Load(version);
 
		cur_company.Restore();
 
	} else {
 
		/* Read, but ignore, the load data */
 
		AIInstance::LoadEmpty();
 
	}
 
}
 

	
 
/* static */ int AI::GetStartNextTime()
 
{
 
	/* Find the first company which doesn't exist yet */
 
	for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
 
		if (!Company::IsValidID(c)) return AIConfig::GetConfig(c)->GetSetting("start_date");
 
	}
 

	
 
	/* Currently no AI can be started, check again in a year. */
 
	return DAYS_IN_YEAR;
 
}
 

	
 
/* static */ char *AI::GetConsoleList(char *p, const char *last)
 
{
 
	return AI::ai_scanner->GetAIConsoleList(p, last);
 
}
 

	
src/ai/ai_gui.cpp
Show inline comments
 
@@ -799,49 +799,49 @@ struct AIDebugWindow : public QueryStrin
 
			bool disabled = !valid;
 
			if (button->IsDisabled() != disabled) {
 
				/* Invalid/non-AI companies have button disabled */
 
				button->SetDisabled(disabled);
 
				dirty = true;
 
			}
 

	
 
			bool dead = valid && Company::Get(i)->ai_instance->IsDead();
 
			Colours colour = dead ? COLOUR_RED : COLOUR_GREY;
 
			if (button->colour != colour) {
 
				/* Mark dead AIs by red background */
 
				button->colour = colour;
 
				dirty = true;
 
			}
 

	
 
			/* Do we need a repaint? */
 
			if (dirty) this->SetDirty();
 
			/* Draw company icon only for valid AI companies */
 
			if (!valid) continue;
 

	
 
			byte offset = (i == ai_debug_company) ? 1 : 0;
 
			DrawCompanyIcon(i, button->pos_x + button->current_x / 2 - 7 + offset, this->GetWidget<NWidgetBase>(AID_WIDGET_COMPANY_BUTTON_START + i)->pos_y + 2 + offset);
 
		}
 

	
 
		Backup<CompanyByte> cur_company(_current_company, ai_debug_company);
 
		Backup<CompanyByte> cur_company(_current_company, ai_debug_company, FILE_LINE);
 
		AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
 
		cur_company.Restore();
 

	
 
		int scroll_count = (log == NULL) ? 0 : log->used;
 
		if (this->vscroll.GetCount() != scroll_count) {
 
			this->vscroll.SetCount(scroll_count);
 

	
 
			/* We need a repaint */
 
			this->SetWidgetDirty(AID_WIDGET_SCROLLBAR);
 
		}
 

	
 
		if (log == NULL) return;
 

	
 
		/* Detect when the user scrolls the window. Enable autoscroll when the
 
		 * bottom-most line becomes visible. */
 
		if (this->last_vscroll_pos != this->vscroll.GetPosition()) {
 
			this->autoscroll = this->vscroll.GetPosition() >= log->used - this->vscroll.GetCapacity();
 
		}
 
		if (this->autoscroll) {
 
			int scroll_pos = max(0, log->used - this->vscroll.GetCapacity());
 
			if (scroll_pos != this->vscroll.GetPosition()) {
 
				this->vscroll.SetPosition(scroll_pos);
 

	
 
				/* We need a repaint */
 
@@ -854,88 +854,88 @@ struct AIDebugWindow : public QueryStrin
 

	
 
	virtual void SetStringParameters(int widget) const
 
	{
 
		switch (widget) {
 
			case AID_WIDGET_NAME_TEXT:
 
				if (ai_debug_company == INVALID_COMPANY || !Company::IsValidAiID(ai_debug_company)) {
 
					SetDParam(0, STR_EMPTY);
 
				} else {
 
					const AIInfo *info = Company::Get(ai_debug_company)->ai_info;
 
					assert(info != NULL);
 
					SetDParam(0, STR_AI_DEBUG_NAME_AND_VERSION);
 
					SetDParamStr(1, info->GetName());
 
					SetDParam(2, info->GetVersion());
 
				}
 
				break;
 
		}
 
	}
 

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

	
 
		switch (widget) {
 
			case AID_WIDGET_LOG_PANEL: {
 
				Backup<CompanyByte> cur_company(_current_company, ai_debug_company);
 
				Backup<CompanyByte> cur_company(_current_company, ai_debug_company, FILE_LINE);
 
				AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
 
				cur_company.Restore();
 
				if (log == NULL) return;
 

	
 
				int y = this->top_offset;
 
				for (int i = this->vscroll.GetPosition(); this->vscroll.IsVisible(i) && i < log->used; i++) {
 
					int pos = (i + log->pos + 1 - log->used + log->count) % log->count;
 
					if (log->lines[pos] == NULL) break;
 

	
 
					TextColour colour;
 
					switch (log->type[pos]) {
 
						case AILog::LOG_SQ_INFO:  colour = TC_BLACK;  break;
 
						case AILog::LOG_SQ_ERROR: colour = TC_RED;    break;
 
						case AILog::LOG_INFO:     colour = TC_BLACK;  break;
 
						case AILog::LOG_WARNING:  colour = TC_YELLOW; break;
 
						case AILog::LOG_ERROR:    colour = TC_RED;    break;
 
						default:                  colour = TC_BLACK;  break;
 
					}
 

	
 
					/* Check if the current line should be highlighted */
 
					if (pos == this->highlight_row) {
 
						GfxFillRect(r.left + 1, r.top + y, r.right - 1, r.top + y + this->resize.step_height - WD_PAR_VSEP_NORMAL, 0);
 
						if (colour == TC_BLACK) colour = TC_WHITE; // Make black text readable by inverting it to white.
 
					}
 

	
 
					DrawString(r.left + 7, r.right - 7, r.top + y, log->lines[pos], colour, SA_LEFT | SA_FORCE);
 
					y += this->resize.step_height;
 
				}
 
				break;
 
			}
 
		}
 
	}
 

	
 
	void ChangeToAI(CompanyID show_ai)
 
	{
 
		this->RaiseWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
 
		ai_debug_company = show_ai;
 

	
 
		Backup<CompanyByte> cur_company(_current_company, ai_debug_company);
 
		Backup<CompanyByte> cur_company(_current_company, ai_debug_company, FILE_LINE);
 
		AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
 
		cur_company.Restore();
 
		this->vscroll.SetCount((log == NULL) ? 0 : log->used);
 

	
 
		this->LowerWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
 
		this->autoscroll = true;
 
		this->last_vscroll_pos = this->vscroll.GetPosition();
 
		this->SetDirty();
 
		/* Close AI settings window to prevent confusion */
 
		DeleteWindowByClass(WC_AI_SETTINGS);
 
	}
 

	
 
	virtual void OnClick(Point pt, int widget, int click_count)
 
	{
 
		/* Check which button is clicked */
 
		if (IsInsideMM(widget, AID_WIDGET_COMPANY_BUTTON_START, AID_WIDGET_COMPANY_BUTTON_END + 1)) {
 
			/* Is it no on disable? */
 
			if (!this->IsWidgetDisabled(widget)) {
 
				ChangeToAI((CompanyID)(widget - AID_WIDGET_COMPANY_BUTTON_START));
 
			}
 
		}
 

	
 
		switch (widget) {
 
			case AID_WIDGET_RELOAD_TOGGLE:
 
@@ -988,49 +988,49 @@ struct AIDebugWindow : public QueryStrin
 
			strecpy(this->break_string, this->edit_str_buf, lastof(this->break_string));
 
		}
 
		return state;
 
	}
 

	
 
	virtual void OnInvalidateData(int data = 0)
 
	{
 
		if (data == -1 || ai_debug_company == data) this->SetDirty();
 

	
 
		if (data == -2) {
 
			/* The continue button should be disabled when the game is unpaused and
 
			 * it was previously paused by the break string ( = a line in the log
 
			 * was highlighted )*/
 
			if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED && this->highlight_row != -1) {
 
				this->DisableWidget(AID_WIDGET_CONTINUE_BTN);
 
				this->SetWidgetDirty(AID_WIDGET_CONTINUE_BTN);
 
				this->SetWidgetDirty(AID_WIDGET_LOG_PANEL);
 
				this->highlight_row = -1;
 
			}
 
		}
 

	
 
		/* If the log message is related to the active company tab, check the break string */
 
		if (data == ai_debug_company && this->break_check_enabled && !StrEmpty(this->edit_str_buf)) {
 
			/* Get the log instance of the active company */
 
			Backup<CompanyByte> cur_company(_current_company, ai_debug_company);
 
			Backup<CompanyByte> cur_company(_current_company, ai_debug_company, FILE_LINE);
 
			AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
 

	
 
			if (log != NULL && case_sensitive_break_check?
 
					strstr(log->lines[log->pos], this->edit_str_buf) != 0 :
 
					strcasestr(log->lines[log->pos], this->edit_str_buf) != 0) {
 

	
 
				AI::Suspend(ai_debug_company);
 
				if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) {
 
					DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);
 
				}
 

	
 
				/* Make it possible to click on the continue button */
 
				this->EnableWidget(AID_WIDGET_CONTINUE_BTN);
 
				this->SetWidgetDirty(AID_WIDGET_CONTINUE_BTN);
 

	
 
				/* Highlight row that matched */
 
				this->highlight_row = log->pos;
 
			}
 

	
 
			cur_company.Restore();
 
		}
 
	}
 

	
 
	virtual void OnResize()
src/aircraft_cmd.cpp
Show inline comments
 
@@ -1183,49 +1183,49 @@ static void HandleAircraftSmoke(Aircraft
 
			EV_SMOKE
 
		);
 
	}
 
}
 

	
 
void HandleMissingAircraftOrders(Aircraft *v)
 
{
 
	/*
 
	 * We do not have an order. This can be divided into two cases:
 
	 * 1) we are heading to an invalid station. In this case we must
 
	 *    find another airport to go to. If there is nowhere to go,
 
	 *    we will destroy the aircraft as it otherwise will enter
 
	 *    the holding pattern for the first airport, which can cause
 
	 *    the plane to go into an undefined state when building an
 
	 *    airport with the same StationID.
 
	 * 2) we are (still) heading to a (still) valid airport, then we
 
	 *    can continue going there. This can happen when you are
 
	 *    changing the aircraft's orders while in-flight or in for
 
	 *    example a depot. However, when we have a current order to
 
	 *    go to a depot, we have to keep that order so the aircraft
 
	 *    actually stops.
 
	 */
 
	const Station *st = GetTargetAirportIfValid(v);
 
	if (st == NULL) {
 
		Backup<CompanyByte> cur_company(_current_company, v->owner);
 
		Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
 
		CommandCost ret = DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_SEND_AIRCRAFT_TO_HANGAR);
 
		cur_company.Restore();
 

	
 
		if (ret.Failed()) CrashAirplane(v);
 
	} else if (!v->current_order.IsType(OT_GOTO_DEPOT)) {
 
		v->current_order.Free();
 
	}
 
}
 

	
 

	
 
TileIndex Aircraft::GetOrderStationLocation(StationID station)
 
{
 
	/* Orders are changed in flight, ensure going to the right station. */
 
	if (this->state == FLYING) {
 
		AircraftNextAirportPos_and_Order(this);
 
	}
 

	
 
	/* Aircraft do not use dest-tile */
 
	return 0;
 
}
 

	
 
void Aircraft::MarkDirty()
 
{
 
	this->UpdateViewport(false, false);
 
@@ -1489,49 +1489,49 @@ static void AircraftEventHandler_TakeOff
 

	
 
static void AircraftEventHandler_StartTakeOff(Aircraft *v, const AirportFTAClass *apc)
 
{
 
	v->state = ENDTAKEOFF;
 
	v->UpdateDeltaXY(INVALID_DIR);
 
}
 

	
 
static void AircraftEventHandler_EndTakeOff(Aircraft *v, const AirportFTAClass *apc)
 
{
 
	v->state = FLYING;
 
	/* get the next position to go to, differs per airport */
 
	AircraftNextAirportPos_and_Order(v);
 
}
 

	
 
static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass *apc)
 
{
 
	v->state = FLYING;
 
	v->UpdateDeltaXY(INVALID_DIR);
 

	
 
	/* get the next position to go to, differs per airport */
 
	AircraftNextAirportPos_and_Order(v);
 

	
 
	/* Send the helicopter to a hangar if needed for replacement */
 
	if (v->NeedsAutomaticServicing()) {
 
		Backup<CompanyByte> cur_company(_current_company, v->owner);
 
		Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
 
		DoCommand(v->tile, v->index, DEPOT_SERVICE | DEPOT_LOCATE_HANGAR, DC_EXEC, CMD_SEND_AIRCRAFT_TO_HANGAR);
 
		cur_company.Restore();
 
	}
 
}
 

	
 
static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
 
{
 
	Station *st = Station::Get(v->targetairport);
 

	
 
	/* runway busy or not allowed to use this airstation, circle */
 
	if ((apc->flags & (v->subtype == AIR_HELICOPTER ? AirportFTAClass::HELICOPTERS : AirportFTAClass::AIRPLANES)) &&
 
			st->airport.tile != INVALID_TILE &&
 
			(st->owner == OWNER_NONE || st->owner == v->owner)) {
 
		/* {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41},
 
		 * if it is an airplane, look for LANDING, for helicopter HELILANDING
 
		 * it is possible to choose from multiple landing runways, so loop until a free one is found */
 
		byte landingtype = (v->subtype == AIR_HELICOPTER) ? HELILANDING : LANDING;
 
		const AirportFTA *current = apc->layout[v->pos].next;
 
		while (current != NULL) {
 
			if (current->heading == landingtype) {
 
				/* save speed before, since if AirportHasBlock is false, it resets them to 0
 
				 * we don't want that for plane in air
 
				 * hack for speed thingie */
 
				uint16 tcur_speed = v->cur_speed;
 
@@ -1541,49 +1541,49 @@ static void AircraftEventHandler_Flying(
 
					/* it's a bit dirty, but I need to set position to next position, otherwise
 
					 * if there are multiple runways, plane won't know which one it took (because
 
					 * they all have heading LANDING). And also occupy that block! */
 
					v->pos = current->next_position;
 
					SETBITS(st->airport.flags, apc->layout[v->pos].block);
 
					return;
 
				}
 
				v->cur_speed = tcur_speed;
 
				v->subspeed = tsubspeed;
 
			}
 
			current = current->next;
 
		}
 
	}
 
	v->state = FLYING;
 
	v->pos = apc->layout[v->pos].next_position;
 
}
 

	
 
static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *apc)
 
{
 
	v->state = ENDLANDING;
 
	AircraftLandAirplane(v);  // maybe crash airplane
 

	
 
	/* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */
 
	if (v->NeedsAutomaticServicing()) {
 
		Backup<CompanyByte> cur_company(_current_company, v->owner);
 
		Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
 
		DoCommand(v->tile, v->index, DEPOT_SERVICE, DC_EXEC, CMD_SEND_AIRCRAFT_TO_HANGAR);
 
		cur_company.Restore();
 
	}
 
}
 

	
 
static void AircraftEventHandler_HeliLanding(Aircraft *v, const AirportFTAClass *apc)
 
{
 
	v->state = HELIENDLANDING;
 
	v->UpdateDeltaXY(INVALID_DIR);
 
}
 

	
 
static void AircraftEventHandler_EndLanding(Aircraft *v, const AirportFTAClass *apc)
 
{
 
	/* next block busy, don't do a thing, just wait */
 
	if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return;
 

	
 
	/* if going to terminal (OT_GOTO_STATION) choose one
 
	 * 1. in case all terminals are busy AirportFindFreeTerminal() returns false or
 
	 * 2. not going for terminal (but depot, no order),
 
	 * --> get out of the way to the hangar. */
 
	if (v->current_order.IsType(OT_GOTO_STATION)) {
 
		if (AirportFindFreeTerminal(v, apc)) return;
 
	}
 
	v->state = HANGAR;
src/core/backup_type.hpp
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 backup_type.hpp Class for backupping variables and making sure they are restored later. */
 

	
 
#ifndef BACKUP_TYPE_HPP
 
#define BACKUP_TYPE_HPP
 

	
 
#include "../debug.h"
 

	
 
/**
 
 * Class to backup a specific variable and restore it later.
 
 * The variable is not restored automatically, but assertions make sure it is restored.
 
 * You have to call either Trash() or Restore() exactly once.
 
 */
 
template <typename T>
 
struct Backup {
 
	/**
 
	 * Backup variable.
 
	 * @param original Variable to backup.
 
	 * @param file Filename for debug output. Use FILE_LINE macro.
 
	 * @param line Linenumber for debug output. Use FILE_LINE macro.
 
	 */
 
	Backup(T &original) : original(original), valid(true), original_value(original) {}
 
	Backup(T &original, const char * const file, const int line) : original(original), valid(true), original_value(original), file(file), line(line) {}
 

	
 
	/**
 
	 * Backup variable and switch to new value.
 
	 * @param original Variable to backup.
 
	 * @param new_value New value for variable.
 
	 * @param file Filename for debug output. Use FILE_LINE macro.
 
	 * @param line Linenumber for debug output. Use FILE_LINE macro.
 
	 */
 
	template <typename U>
 
	Backup(T &original, const U &new_value) : original(original), valid(true), original_value(original)
 
	Backup(T &original, const U &new_value, const char * const file, const int line) : original(original), valid(true), original_value(original), file(file), line(line)
 
	{
 
		/* Note: We use a separate typename U, so type conversions are handled by assignment operator. */
 
		original = new_value;
 
	}
 

	
 
	/**
 
	 * Check whether the variable was restored on object destruction.
 
	 */
 
	~Backup()
 
	{
 
		/* Check whether restoration was done */
 
		assert(!this->valid);
 
		if (this->valid)
 
		{
 
			/* We cannot assert here, as missing restoration is 'normal' when exceptions are thrown.
 
			 * Exceptions are especially used to abort world generation. */
 
			DEBUG(misc, 0, "%s:%d: Backupped value was not restored!", this->file, this->line);
 
			this->Restore();
 
		}
 
	}
 

	
 
	/**
 
	 * Checks whether the variable was already restored.
 
	 * @return true if variable has already been restored.
 
	 */
 
	bool IsValid() const
 
	{
 
		return this->valid;
 
	}
 

	
 
	/**
 
	 * Returns the backupped value.
 
	 * @return value from the backup.
 
	 */
 
	const T &GetOriginalValue() const
 
	{
 
		assert(this->valid);
 
		return original_value;
 
	}
 

	
 
	/**
 
	 * Change the value of the variable.
 
	 * While this does not touch the backup at all, it ensures that the variable is only modified while backupped.
 
@@ -108,27 +120,30 @@ struct Backup {
 
	/**
 
	 * Update the backup.
 
	 * That is trash the old value and make the current value of the variable the value to be restored later.
 
	 */
 
	void Update()
 
	{
 
		assert(this->valid);
 
		this->original_value = this->original;
 
	}
 

	
 
	/**
 
	 * Check whether the variable is currently equals the backup.
 
	 * @return true if equal
 
	 */
 
	bool Verify() const
 
	{
 
		assert(this->valid);
 
		return this->original_value == this->original;
 
	}
 

	
 
private:
 
	T &original;
 
	bool valid;
 
	T original_value;
 

	
 
	const char * const file;
 
	const int line;
 
};
 

	
 
#endif /* BACKUP_TYPE_HPP */
src/debug.h
Show inline comments
 
@@ -32,48 +32,51 @@
 
	#define DEBUG(name, level, ...) if ((level) == 0 || _debug_ ## name ## _level >= (level)) debug(#name, __VA_ARGS__)
 

	
 
	extern int _debug_ai_level;
 
	extern int _debug_driver_level;
 
	extern int _debug_grf_level;
 
	extern int _debug_map_level;
 
	extern int _debug_misc_level;
 
	extern int _debug_net_level;
 
	extern int _debug_sprite_level;
 
	extern int _debug_oldloader_level;
 
	extern int _debug_npf_level;
 
	extern int _debug_yapf_level;
 
	extern int _debug_freetype_level;
 
	extern int _debug_sl_level;
 
	extern int _debug_gamelog_level;
 
	extern int _debug_desync_level;
 
	extern int _debug_console_level;
 

	
 
	void CDECL debug(const char *dbg, const char *format, ...) WARN_FORMAT(2, 3);
 
#endif /* NO_DEBUG_MESSAGES */
 

	
 
void SetDebugString(const char *s);
 
const char *GetDebugString();
 

	
 
/* Shorter form for passing filename and linenumber */
 
#define FILE_LINE __FILE__, __LINE__
 

	
 
/* Used for profiling
 
 *
 
 * Usage:
 
 * TIC();
 
 *   --Do your code--
 
 * TOC("A name", 1);
 
 *
 
 * When you run the TIC() / TOC() multiple times, you can increase the '1'
 
 *  to only display average stats every N values. Some things to know:
 
 *
 
 * for (int i = 0; i < 5; i++) {
 
 *   TIC();
 
 *     --Do yuor code--
 
 *   TOC("A name", 5);
 
 * }
 
 *
 
 * Is the correct usage for multiple TIC() / TOC() calls.
 
 *
 
 * TIC() / TOC() creates its own block, so make sure not the mangle
 
 *  it with another block.
 
 **/
 
#define TIC() {\
 
	extern uint64 ottd_rdtsc();\
 
	uint64 _xxx_ = ottd_rdtsc();\
src/disaster_cmd.cpp
Show inline comments
 
@@ -52,59 +52,59 @@ enum DisasterSubType {
 
	ST_ZEPPELINER,
 
	ST_ZEPPELINER_SHADOW,
 
	ST_SMALL_UFO,
 
	ST_SMALL_UFO_SHADOW,
 
	ST_AIRPLANE,
 
	ST_AIRPLANE_SHADOW,
 
	ST_HELICOPTER,
 
	ST_HELICOPTER_SHADOW,
 
	ST_HELICOPTER_ROTORS,
 
	ST_BIG_UFO,
 
	ST_BIG_UFO_SHADOW,
 
	ST_BIG_UFO_DESTROYER,
 
	ST_BIG_UFO_DESTROYER_SHADOW,
 
	ST_SMALL_SUBMARINE,
 
	ST_BIG_SUBMARINE,
 
};
 

	
 
static void DisasterClearSquare(TileIndex tile)
 
{
 
	if (EnsureNoVehicleOnGround(tile).Failed()) return;
 

	
 
	switch (GetTileType(tile)) {
 
		case MP_RAILWAY:
 
			if (Company::IsHumanID(GetTileOwner(tile))) {
 
				Backup<CompanyByte> cur_company(_current_company, OWNER_WATER);
 
				Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
 
				DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
				cur_company.Restore();
 

	
 
				/* update signals in buffer */
 
				UpdateSignalsInBuffer();
 
			}
 
			break;
 

	
 
		case MP_HOUSE: {
 
			Backup<CompanyByte> cur_company(_current_company, OWNER_NONE);
 
			Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
 
			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
			cur_company.Restore();
 
			break;
 
		}
 

	
 
		case MP_TREES:
 
		case MP_CLEAR:
 
			DoClearSquare(tile);
 
			break;
 

	
 
		default:
 
			break;
 
	}
 
}
 

	
 
static const SpriteID _disaster_images_1[] = {SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP};
 
static const SpriteID _disaster_images_2[] = {SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT};
 
static const SpriteID _disaster_images_3[] = {SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15};
 
static const SpriteID _disaster_images_4[] = {SPR_SUB_SMALL_NE, SPR_SUB_SMALL_NE, SPR_SUB_SMALL_SE, SPR_SUB_SMALL_SE, SPR_SUB_SMALL_SW, SPR_SUB_SMALL_SW, SPR_SUB_SMALL_NW, SPR_SUB_SMALL_NW};
 
static const SpriteID _disaster_images_5[] = {SPR_SUB_LARGE_NE, SPR_SUB_LARGE_NE, SPR_SUB_LARGE_SE, SPR_SUB_LARGE_SE, SPR_SUB_LARGE_SW, SPR_SUB_LARGE_SW, SPR_SUB_LARGE_NW, SPR_SUB_LARGE_NW};
 
static const SpriteID _disaster_images_6[] = {SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER};
 
static const SpriteID _disaster_images_7[] = {SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER};
 
static const SpriteID _disaster_images_8[] = {SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A};
 
static const SpriteID _disaster_images_9[] = {SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1};
src/economy.cpp
Show inline comments
 
@@ -284,71 +284,71 @@ int UpdateCompanyRatingAndValue(Company 
 

	
 
		/*  We always want the score scaled to SCORE_MAX (1000) */
 
		if (total_score != SCORE_MAX) score = score * SCORE_MAX / total_score;
 
	}
 

	
 
	if (update) {
 
		c->old_economy[0].performance_history = score;
 
		UpdateCompanyHQ(c, score);
 
		c->old_economy[0].company_value = CalculateCompanyValue(c);
 
	}
 

	
 
	SetWindowDirty(WC_PERFORMANCE_DETAIL, 0);
 
	return score;
 
}
 

	
 
/*  use INVALID_OWNER as new_owner to delete the company. */
 
void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
 
{
 
#ifdef ENABLE_NETWORK
 
	/* In all cases, make spectators of clients connected to that company */
 
	if (_networking) NetworkClientsToSpectators(old_owner);
 
#endif /* ENABLE_NETWORK */
 

	
 
	Town *t;
 
	Backup<CompanyByte> cur_company(_current_company, old_owner);
 
	Backup<CompanyByte> cur_company(_current_company, old_owner, FILE_LINE);
 

	
 
	assert(old_owner != new_owner);
 

	
 
	{
 
		Company *c;
 
		uint i;
 

	
 
		/* See if the old_owner had shares in other companies */
 
		FOR_ALL_COMPANIES(c) {
 
			for (i = 0; i < 4; i++) {
 
				if (c->share_owners[i] == old_owner) {
 
					/* Sell his shares */
 
					CommandCost res = DoCommand(0, c->index, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
 
					/* Because we are in a DoCommand, we can't just execute another one and
 
					 *  expect the money to be removed. We need to do it ourself! */
 
					SubtractMoneyFromCompany(res);
 
				}
 
			}
 
		}
 

	
 
		/* Sell all the shares that people have on this company */
 
		Backup<CompanyByte> cur_company2(_current_company);
 
		Backup<CompanyByte> cur_company2(_current_company, FILE_LINE);
 
		c = Company::Get(old_owner);
 
		for (i = 0; i < 4; i++) {
 
			cur_company2.Change(c->share_owners[i]);
 
			if (_current_company != INVALID_OWNER) {
 
				/* Sell the shares */
 
				CommandCost res = DoCommand(0, old_owner, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
 
				/* Because we are in a DoCommand, we can't just execute another one and
 
				 *  expect the money to be removed. We need to do it ourself! */
 
				SubtractMoneyFromCompany(res);
 
			}
 
		}
 
		cur_company2.Restore();
 
	}
 

	
 
	/* Temporarily increase the company's money, to be sure that
 
	 * removing his/her property doesn't fail because of lack of money.
 
	 * Not too drastically though, because it could overflow */
 
	if (new_owner == INVALID_OWNER) {
 
		Company::Get(old_owner)->money = UINT64_MAX >> 2; // jackpot ;p
 
	}
 

	
 
	Subsidy *s;
 
	FOR_ALL_SUBSIDIES(s) {
 
		if (s->awarded == old_owner) {
 
@@ -532,49 +532,49 @@ static void CompanyCheckBankrupt(Company
 
			/* Close everything the owner has open */
 
			DeleteCompanyWindows(c->index);
 

	
 
			/* Show bankrupt news */
 
			SetDParam(0, STR_NEWS_COMPANY_BANKRUPT_TITLE);
 
			SetDParam(1, STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION);
 
			SetDParamStr(2, cni->company_name);
 
			AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_BANKRUPT, cni);
 

	
 
			ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER);
 

	
 
			if (c->is_ai) AI::Stop(c->index);
 

	
 
			CompanyID c_index = c->index;
 
			delete c;
 
			AI::BroadcastNewEvent(new AIEventCompanyBankrupt(c_index));
 
	}
 
}
 

	
 
static void CompaniesGenStatistics()
 
{
 
	Station *st;
 
	Company *c;
 

	
 
	Backup<CompanyByte> cur_company(_current_company);
 
	Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
 
	FOR_ALL_STATIONS(st) {
 
		cur_company.Change(st->owner);
 
		CommandCost cost(EXPENSES_PROPERTY, _price[PR_STATION_VALUE] >> 1);
 
		SubtractMoneyFromCompany(cost);
 
	}
 
	cur_company.Restore();
 

	
 
	if (!HasBit(1 << 0 | 1 << 3 | 1 << 6 | 1 << 9, _cur_month))
 
		return;
 

	
 
	FOR_ALL_COMPANIES(c) {
 
		memmove(&c->old_economy[1], &c->old_economy[0], sizeof(c->old_economy) - sizeof(c->old_economy[0]));
 
		c->old_economy[0] = c->cur_economy;
 
		memset(&c->cur_economy, 0, sizeof(c->cur_economy));
 

	
 
		if (c->num_valid_stat_ent != MAX_HISTORY_MONTHS) c->num_valid_stat_ent++;
 

	
 
		UpdateCompanyRatingAndValue(c, true);
 
		if (c->block_preview != 0) c->block_preview--;
 
		CompanyCheckBankrupt(c);
 
	}
 

	
 
	SetWindowDirty(WC_INCOME_GRAPH, 0);
 
	SetWindowDirty(WC_OPERATING_PROFIT, 0);
 
@@ -667,49 +667,49 @@ void RecomputePrices()
 
			price = Clamp(_price_base_specs[i].start_price, -1, 1);
 
			/* No base price should be zero, but be sure. */
 
			assert(price != 0);
 
		}
 
		/* Store value */
 
		_price[i] = price;
 
	}
 

	
 
	/* Setup cargo payment */
 
	CargoSpec *cs;
 
	FOR_ALL_CARGOSPECS(cs) {
 
		cs->current_payment = ((int64)cs->initial_payment * _economy.inflation_payment) >> 16;
 
	}
 

	
 
	SetWindowClassesDirty(WC_BUILD_VEHICLE);
 
	SetWindowClassesDirty(WC_REPLACE_VEHICLE);
 
	SetWindowClassesDirty(WC_VEHICLE_DETAILS);
 
	SetWindowDirty(WC_PAYMENT_RATES, 0);
 
}
 

	
 
static void CompaniesPayInterest()
 
{
 
	const Company *c;
 

	
 
	Backup<CompanyByte> cur_company(_current_company);
 
	Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
 
	FOR_ALL_COMPANIES(c) {
 
		cur_company.Change(c->index);
 

	
 
		/* Over a year the paid interest should be "loan * interest percentage",
 
		 * but... as that number is likely not dividable by 12 (pay each month),
 
		 * one needs to account for that in the monthly fee calculations.
 
		 * To easily calculate what one should pay "this" month, you calculate
 
		 * what (total) should have been paid up to this month and you substract
 
		 * whatever has been paid in the previous months. This will mean one month
 
		 * it'll be a bit more and the other it'll be a bit less than the average
 
		 * monthly fee, but on average it will be exact. */
 
		Money yearly_fee = c->current_loan * _economy.interest_rate / 100;
 
		Money up_to_previous_month = yearly_fee * _cur_month / 12;
 
		Money up_to_this_month = yearly_fee * (_cur_month + 1) / 12;
 

	
 
		SubtractMoneyFromCompany(CommandCost(EXPENSES_LOAN_INT, up_to_this_month - up_to_previous_month));
 

	
 
		SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, _price[PR_STATION_VALUE] >> 2));
 
	}
 
	cur_company.Restore();
 
}
 

	
 
static void HandleEconomyFluctuations()
 
{
 
@@ -1006,49 +1006,49 @@ static void TriggerIndustryProduction(In
 
	}
 

	
 
	TriggerIndustry(i, INDUSTRY_TRIGGER_RECEIVED_CARGO);
 
	StartStopIndustryTileAnimation(i, IAT_INDUSTRY_RECEIVED_CARGO);
 
}
 

	
 
/**
 
 * Makes us a new cargo payment helper.
 
 * @param front The front of the train
 
 */
 
CargoPayment::CargoPayment(Vehicle *front) :
 
	front(front),
 
	current_station(front->last_station_visited)
 
{
 
}
 

	
 
CargoPayment::~CargoPayment()
 
{
 
	if (this->CleaningPool()) return;
 

	
 
	this->front->cargo_payment = NULL;
 

	
 
	if (this->visual_profit == 0) return;
 

	
 
	Backup<CompanyByte> cur_company(_current_company, this->front->owner);
 
	Backup<CompanyByte> cur_company(_current_company, this->front->owner, FILE_LINE);
 

	
 
	SubtractMoneyFromCompany(CommandCost(this->front->GetExpenseType(true), -this->route_profit));
 
	this->front->profit_this_year += this->visual_profit << 8;
 

	
 
	if (this->route_profit != 0) {
 
		if (IsLocalCompany() && !PlayVehicleSound(this->front, VSE_LOAD_UNLOAD)) {
 
			SndPlayVehicleFx(SND_14_CASHTILL, this->front);
 
		}
 

	
 
		ShowCostOrIncomeAnimation(this->front->x_pos, this->front->y_pos, this->front->z_pos, -this->visual_profit);
 
	} else {
 
		ShowFeederIncomeAnimation(this->front->x_pos, this->front->y_pos, this->front->z_pos, this->visual_profit);
 
	}
 

	
 
	cur_company.Restore();
 
}
 

	
 
/**
 
 * Handle payment for final delivery of the given cargo packet.
 
 * @param cp The cargo packet to pay for.
 
 * @param count The number of packets to pay for.
 
 */
 
void CargoPayment::PayFinalDelivery(const CargoPacket *cp, uint count)
 
{
 
@@ -1437,49 +1437,49 @@ static void DoAcquireCompany(Company *c)
 
	Company *owner;
 
	int i;
 
	Money value;
 
	CompanyID ci = c->index;
 

	
 
	CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
 
	cni->FillData(c, Company::Get(_current_company));
 

	
 
	SetDParam(0, STR_NEWS_COMPANY_MERGER_TITLE);
 
	SetDParam(1, c->bankrupt_value == 0 ? STR_NEWS_MERGER_TAKEOVER_TITLE : STR_NEWS_COMPANY_MERGER_DESCRIPTION);
 
	SetDParamStr(2, cni->company_name);
 
	SetDParamStr(3, cni->other_company_name);
 
	SetDParam(4, c->bankrupt_value);
 
	AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_MERGER, cni);
 
	AI::BroadcastNewEvent(new AIEventCompanyMerger(ci, _current_company));
 

	
 
	ChangeOwnershipOfCompanyItems(ci, _current_company);
 

	
 
	if (c->bankrupt_value == 0) {
 
		owner = Company::Get(_current_company);
 
		owner->current_loan += c->current_loan;
 
	}
 

	
 
	value = CalculateCompanyValue(c) >> 2;
 
	Backup<CompanyByte> cur_company(_current_company);
 
	Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
 
	for (i = 0; i != 4; i++) {
 
		if (c->share_owners[i] != COMPANY_SPECTATOR) {
 
			cur_company.Change(c->share_owners[i]);
 
			SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, -value));
 
		}
 
	}
 
	cur_company.Restore();
 

	
 
	if (c->is_ai) AI::Stop(c->index);
 

	
 
	DeleteCompanyWindows(ci);
 
	InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
	InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
 
	InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 
	InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
 

	
 
	delete c;
 
}
 

	
 
extern int GetAmountOwnedBy(const Company *c, Owner owner);
 

	
 
/** Acquire shares in an opposing company.
 
 * @param tile unused
 
 * @param flags type of operation
src/industry_cmd.cpp
Show inline comments
 
@@ -1022,49 +1022,49 @@ static void PlantFarmField(TileIndex til
 
	SetupFarmFieldFence(tile + TileDiffXY(0, size_y - 1), size_x, type, AXIS_X);
 
}
 

	
 
void PlantRandomFarmField(const Industry *i)
 
{
 
	int x = i->location.w / 2 + Random() % 31 - 16;
 
	int y = i->location.h / 2 + Random() % 31 - 16;
 

	
 
	TileIndex tile = TileAddWrap(i->location.tile, x, y);
 

	
 
	if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
 
}
 

	
 
/**
 
 * Search callback function for ChopLumberMillTrees
 
 * @param tile to test
 
 * @param user_data that is passed by the caller.  In this case, nothing
 
 * @return the result of the test
 
 */
 
static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
 
{
 
	if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) > 2) { ///< 3 and up means all fully grown trees
 
		/* found a tree */
 

	
 
		Backup<CompanyByte> cur_company(_current_company, OWNER_NONE);
 
		Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
 

	
 
		_industry_sound_ctr = 1;
 
		_industry_sound_tile = tile;
 
		SndPlayTileFx(SND_38_CHAINSAW, tile);
 

	
 
		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 

	
 
		cur_company.Restore();
 
		return true;
 
	}
 
	return false;
 
}
 

	
 
/**
 
 * Perform a circular search around the Lumber Mill in order to find trees to cut
 
 * @param i industry
 
 */
 
static void ChopLumberMillTrees(Industry *i)
 
{
 
	TileIndex tile = i->location.tile;
 

	
 
	if (!IsIndustryCompleted(tile)) return;  ///< Can't proceed if not completed
 

	
 
	if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) ///< 40x40 tiles  to search
 
@@ -1351,49 +1351,49 @@ static CommandCost CheckIfIndustryTilesA
 

	
 
			const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
 

	
 
			IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
 

	
 
			/* Perform land/water check if not disabled */
 
			if (!HasBit(its->slopes_refused, 5) && (IsWaterTile(cur_tile) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
 

	
 
			if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
 
				custom_shape = true;
 
				CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder);
 
				if (ret.Failed()) return ret;
 
			} else {
 
				Slope tileh = GetTileSlope(cur_tile, NULL);
 
				refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
 
			}
 

	
 
			if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
 
					((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house)
 
				if (!IsTileType(cur_tile, MP_HOUSE)) {
 
					return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
 
				}
 

	
 
				/* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
 
				Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN);
 
				Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
 
				CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
 
				cur_company.Restore();
 

	
 
				if (ret.Failed()) return ret;
 
			} else {
 
				/* Clear the tiles, but do not affect town ratings */
 
				CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
 

	
 
				if (ret.Failed()) return ret;
 
			}
 
		}
 
	} while ((++it)->ti.x != -0x80);
 

	
 
	if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
 

	
 
	/* It is almost impossible to have a fully flat land in TG, so what we
 
	 *  do is that we check if we can make the land flat later on. See
 
	 *  CheckIfCanLevelIndustryPlatform(). */
 
	if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
 
		return CommandCost();
 
	}
 
	return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
 
}
 

	
 
@@ -1463,49 +1463,49 @@ static bool CheckIfCanLevelIndustryPlatf
 
	uint h, curh;
 

	
 
	/* Finds dimensions of largest variant of this industry */
 
	do {
 
		if (it->gfx == 0xFF) continue;  //  FF been a marquer for a check on clear water, skip it
 
		if (it->ti.x > max_x) max_x = it->ti.x;
 
		if (it->ti.y > max_y) max_y = it->ti.y;
 
	} while ((++it)->ti.x != MKEND);
 

	
 
	/* Remember level height */
 
	h = TileHeight(tile);
 

	
 
	if (TileX(tile) <= 1 || TileY(tile) <= 1) return false;
 
	/* Check that all tiles in area and surrounding are clear
 
	 * this determines that there are no obstructing items */
 
	cur_tile = tile + TileDiffXY(-1, -1);
 
	size_x = max_x + 4;
 
	size_y = max_y + 4;
 

	
 
	/* Check if we don't leave the map */
 
	if (TileX(cur_tile) + size_x >= MapMaxX() || TileY(cur_tile) + size_y >= MapMaxY()) return false;
 

	
 
	/* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
 
	 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN);
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
 

	
 
	TILE_LOOP(tile_walk, size_x, size_y, cur_tile) {
 
		curh = TileHeight(tile_walk);
 
		if (curh != h) {
 
			/* This tile needs terraforming. Check if we can do that without
 
			 *  damaging the surroundings too much. */
 
			if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
 
				cur_company.Restore();
 
				return false;
 
			}
 
			/* This is not 100% correct check, but the best we can do without modifying the map.
 
			 *  What is missing, is if the difference in height is more than 1.. */
 
			if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) {
 
				cur_company.Restore();
 
				return false;
 
			}
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		/* Terraform the land under the industry */
 
		TILE_LOOP(tile_walk, size_x, size_y, cur_tile) {
 
			curh = TileHeight(tile_walk);
 
			while (curh != h) {
 
@@ -1767,49 +1767,49 @@ CommandCost CmdBuildIndustry(TileIndex t
 
	const IndustrySpec *indspec = GetIndustrySpec(it);
 

	
 
	/* Check if the to-be built/founded industry is available for this climate. */
 
	if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR;
 

	
 
	/* If the setting for raw-material industries is not on, you cannot build raw-material industries.
 
	 * Raw material industries are industries that do not accept cargo (at least for now) */
 
	if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
 
		return CMD_ERROR;
 
	}
 

	
 
	if (_game_mode != GM_EDITOR && !CheckIfCallBackAllowsAvailability(it, IACT_USERCREATION)) {
 
		return CMD_ERROR;
 
	}
 

	
 
	Randomizer randomizer;
 
	randomizer.SetSeed(p2);
 
	uint16 random_initial_bits = GB(p2, 0, 16);
 
	uint32 random_var8f = randomizer.Next();
 

	
 
	Industry *ind = NULL;
 
	if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry()) {
 
		if (flags & DC_EXEC) {
 
			/* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
 
			Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN);
 
			Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
 
			/* Prospecting has a chance to fail, however we cannot guarantee that something can
 
			 * be built on the map, so the chance gets lower when the map is fuller, but there
 
			 * is nothing we can really do about that. */
 
			if (Random() <= indspec->prospecting_chance) {
 
				for (int i = 0; i < 5000; i++) {
 
					/* We should not have more than one Random() in a function call
 
					 * because parameter evaluation order is not guaranteed in the c++ standard
 
					 */
 
					tile = RandomTile();
 
					CommandCost ret = CreateNewIndustryHelper(tile, it, flags, indspec, RandomRange(indspec->num_table), random_var8f, random_initial_bits, cur_company.GetOriginalValue(), &ind);
 
					if (ret.Succeeded()) break;
 
				}
 
			}
 
			cur_company.Restore();
 
		}
 
	} else {
 
		int count = indspec->num_table;
 
		const IndustryTileTable * const *itt = indspec->table;
 
		int num = GB(p1, 8, 8);
 
		if (num >= count) return CMD_ERROR;
 

	
 
		CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
 
		do {
 
			if (--count < 0) return ret;
 
@@ -1869,49 +1869,49 @@ static uint32 GetScaledIndustryProbabili
 
		 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
 
		chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(chance) : ScaleByMapSize(chance);
 

	
 
		*force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION);
 
		return chance;
 
	}
 
}
 

	
 
/** Number of industries on a 256x256 map */
 
static const byte _numof_industry_table[]= {
 
	0,    // none
 
	10,   // very low
 
	25,   // low
 
	55,   // normal
 
	80,   // high
 
};
 

	
 
/**
 
 * Try to build a industry on the map.
 
 * @param type IndustryType of the desired industry
 
 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type)
 
 */
 
static void PlaceInitialIndustry(IndustryType type, bool try_hard)
 
{
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_NONE);
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
 

	
 
	IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
 

	
 
	for (uint i = 0; i < (try_hard ? 10000u : 2000u); i++) {
 
		if (CreateNewIndustry(RandomTile(), type) != NULL) break;
 
	}
 

	
 
	cur_company.Restore();
 
}
 

	
 
/**
 
 * This function will create random industries during game creation.
 
 * It will scale the amount of industries by mapsize and difficulty level.
 
 */
 
void GenerateIndustries()
 
{
 
	assert(_settings_game.difficulty.number_industries < lengthof(_numof_industry_table));
 
	uint total_amount = ScaleByMapSize(_numof_industry_table[_settings_game.difficulty.number_industries]);
 

	
 
	/* Do not create any industries? */
 
	if (total_amount == 0) return;
 

	
 
	uint32 industry_probs[NUM_INDUSTRYTYPES];
 
	bool force_at_least_one[NUM_INDUSTRYTYPES];
 
@@ -2393,74 +2393,74 @@ static void ChangeIndustryProduction(Ind
 
	}
 
}
 

	
 
/** Daily handler for the industry changes
 
 * Taking the original map size of 256*256, the number of random changes was always of just one unit.
 
 * But it cannot be the same on smaller or bigger maps. That number has to be scaled up or down.
 
 * For small maps, it implies that less than one change per month is required, while on bigger maps,
 
 * it would be way more. The daily loop handles those changes. */
 
void IndustryDailyLoop()
 
{
 
	_economy.industry_daily_change_counter += _economy.industry_daily_increment;
 

	
 
	/* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
 
	 * the lower 16 bit are a fractional part that might accumulate over several days until it
 
	 * is sufficient for an industry. */
 
	uint16 change_loop = _economy.industry_daily_change_counter >> 16;
 

	
 
	/* Reset the active part of the counter, just keeping the "factional part" */
 
	_economy.industry_daily_change_counter &= 0xFFFF;
 

	
 
	if (change_loop == 0) {
 
		return;  // Nothing to do? get out
 
	}
 

	
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_NONE);
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
 

	
 
	/* perform the required industry changes for the day */
 
	for (uint16 j = 0; j < change_loop; j++) {
 
		/* 3% chance that we start a new industry */
 
		if (Chance16(3, 100)) {
 
			MaybeNewIndustry();
 
		} else {
 
			Industry *i = Industry::GetRandom();
 
			if (i != NULL) {
 
				ChangeIndustryProduction(i, false);
 
				SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
 
			}
 
		}
 
	}
 

	
 
	cur_company.Restore();
 

	
 
	/* production-change */
 
	InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
 
}
 

	
 
void IndustryMonthlyLoop()
 
{
 
	Industry *i;
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_NONE);
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
 

	
 
	FOR_ALL_INDUSTRIES(i) {
 
		UpdateIndustryStatistics(i);
 
		if (i->prod_level == PRODLEVEL_CLOSURE) {
 
			delete i;
 
		} else {
 
			ChangeIndustryProduction(i, true);
 
			SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
 
		}
 
	}
 

	
 
	cur_company.Restore();
 

	
 
	/* production-change */
 
	InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
 
}
 

	
 

	
 
void InitializeIndustries()
 
{
 
	_industry_pool.CleanPool();
 

	
 
	Industry::ResetIndustryCounts();
 
	_industry_sound_tile = 0;
src/industry_gui.cpp
Show inline comments
 
@@ -502,49 +502,49 @@ public:
 
	}
 

	
 
	virtual void OnResize()
 
	{
 
		/* Adjust the number of items in the matrix depending of the resize */
 
		this->vscroll.SetCapacityFromWidget(this, DPIW_MATRIX_WIDGET);
 
		this->GetWidget<NWidgetCore>(DPIW_MATRIX_WIDGET)->widget_data = (this->vscroll.GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
 
	}
 

	
 
	virtual void OnPlaceObject(Point pt, TileIndex tile)
 
	{
 
		bool success = true;
 
		/* We do not need to protect ourselves against "Random Many Industries" in this mode */
 
		const IndustrySpec *indsp = GetIndustrySpec(this->selected_type);
 
		uint32 seed = InteractiveRandom();
 

	
 
		if (_game_mode == GM_EDITOR) {
 
			/* Show error if no town exists at all */
 
			if (Town::GetNumItems() == 0) {
 
				SetDParam(0, indsp->name);
 
				ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO, pt.x, pt.y);
 
				return;
 
			}
 

	
 
			Backup<CompanyByte> cur_company(_current_company, OWNER_NONE);
 
			Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
 
			_generating_world = true;
 
			_ignore_restrictions = true;
 

	
 
			DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed,
 
					CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY), &CcBuildIndustry);
 

	
 
			cur_company.Restore();
 
			_ignore_restrictions = false;
 
			_generating_world = false;
 
		} else {
 
			success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY));
 
		}
 

	
 
		/* If an industry has been built, just reset the cursor and the system */
 
		if (success && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
 
	}
 

	
 
	virtual void OnTick()
 
	{
 
		if (_pause_mode != PM_UNPAUSED) return;
 
		if (!this->timer_enabled) return;
 
		if (--this->callback_timer == 0) {
 
			/* We have just passed another day.
 
			 * See if we need to update availability of currently selected industry */
src/misc_cmd.cpp
Show inline comments
 
@@ -209,32 +209,32 @@ CommandCost CmdMoneyCheat(TileIndex tile
 
 * To prevent abuse in multiplayer games you can only send money to other
 
 * companies if you have paid off your loan (either explicitely, or implicitely
 
 * given the fact that you have more money than loan).
 
 * @param tile unused
 
 * @param flags operation to perform
 
 * @param p1 the amount of money to transfer; max 20.000.000
 
 * @param p2 the company to transfer the money to
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdGiveMoney(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	if (!_settings_game.economy.give_money) return CMD_ERROR;
 

	
 
	const Company *c = Company::Get(_current_company);
 
	CommandCost amount(EXPENSES_OTHER, min((Money)p1, (Money)20000000LL));
 
	CompanyID dest_company = (CompanyID)p2;
 

	
 
	/* You can only transfer funds that is in excess of your loan */
 
	if (c->money - c->current_loan < amount.GetCost() || amount.GetCost() < 0) return CMD_ERROR;
 
	if (!_networking || !Company::IsValidID(dest_company)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		/* Add money to company */
 
		Backup<CompanyByte> cur_company(_current_company, dest_company);
 
		Backup<CompanyByte> cur_company(_current_company, dest_company, FILE_LINE);
 
		SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, -amount.GetCost()));
 
		cur_company.Restore();
 
	}
 

	
 
	/* Subtract money from local-company */
 
	return amount;
 
}
src/openttd.cpp
Show inline comments
 
@@ -1195,49 +1195,49 @@ void StateGameLoop()
 
	if (IsGeneratingWorld()) return;
 

	
 
	ClearStorageChanges(false);
 

	
 
	if (_game_mode == GM_EDITOR) {
 
		RunTileLoop();
 
		CallVehicleTicks();
 
		CallLandscapeTick();
 
		ClearStorageChanges(true);
 

	
 
		CallWindowTickEvent();
 
		NewsLoop();
 
	} else {
 
		if (_debug_desync_level > 2 && _date_fract == 0 && (_date & 0x1F) == 0) {
 
			/* Save the desync savegame if needed. */
 
			char name[MAX_PATH];
 
			snprintf(name, lengthof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
 
			SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR);
 
		}
 

	
 
		CheckCaches();
 

	
 
		/* All these actions has to be done from OWNER_NONE
 
		 *  for multiplayer compatibility */
 
		Backup<CompanyByte> cur_company(_current_company, OWNER_NONE);
 
		Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
 

	
 
		AnimateAnimatedTiles();
 
		IncreaseDate();
 
		RunTileLoop();
 
		CallVehicleTicks();
 
		CallLandscapeTick();
 
		ClearStorageChanges(true);
 

	
 
		AI::GameLoop();
 

	
 
		CallWindowTickEvent();
 
		NewsLoop();
 
		cur_company.Restore();
 
	}
 
}
 

	
 
/** Create an autosave. The default name is "autosave#.sav". However with
 
 * the setting 'keep_all_autosave' the name defaults to company-name + date */
 
static void DoAutosave()
 
{
 
	char buf[MAX_PATH];
 

	
 
#if defined(PSP)
 
	/* Autosaving in networking is too time expensive for the PSP */
src/rail_cmd.cpp
Show inline comments
 
@@ -621,49 +621,49 @@ CommandCost CmdRemoveSingleRail(TileInde
 

	
 

	
 
/**
 
 * Called from water_cmd if a non-flat rail-tile gets flooded and should be converted to shore.
 
 * The function floods the lower halftile, if the tile has a halftile foundation.
 
 *
 
 * @param t The tile to flood.
 
 * @return true if something was flooded.
 
 */
 
bool FloodHalftile(TileIndex t)
 
{
 
	assert(IsPlainRailTile(t));
 

	
 
	bool flooded = false;
 
	if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
 

	
 
	Slope tileh = GetTileSlope(t, NULL);
 
	TrackBits rail_bits = GetTrackBits(t);
 

	
 
	if (IsSlopeWithOneCornerRaised(tileh)) {
 
		TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
 

	
 
		TrackBits to_remove = lower_track & rail_bits;
 
		if (to_remove != 0) {
 
			Backup<CompanyByte> cur_company(_current_company, OWNER_WATER);
 
			Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
 
			flooded = DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Succeeded();
 
			cur_company.Restore();
 
			if (!flooded) return flooded; // not yet floodable
 
			rail_bits = rail_bits & ~to_remove;
 
			if (rail_bits == 0) {
 
				MakeShore(t);
 
				MarkTileDirtyByTile(t);
 
				return flooded;
 
			}
 
		}
 

	
 
		if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
 
			flooded = true;
 
			SetRailGroundType(t, RAIL_GROUND_WATER);
 
			MarkTileDirtyByTile(t);
 
		}
 
	} else {
 
		/* Make shore on steep slopes and 'three-corners-raised'-slopes. */
 
		if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
 
			if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
 
				flooded = true;
 
				SetRailGroundType(t, RAIL_GROUND_WATER);
 
				MarkTileDirtyByTile(t);
 
			}
src/roadveh_cmd.cpp
Show inline comments
 
@@ -1139,49 +1139,49 @@ static Trackdir FollowPreviousRoadVehicl
 
	/* Do some sanity checking. */
 
	static const RoadBits required_roadbits[] = {
 
		ROAD_X,            ROAD_Y,            ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE,
 
		ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X,            ROAD_Y
 
	};
 
	RoadBits required = required_roadbits[dir & 0x07];
 

	
 
	if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) {
 
		dir = INVALID_TRACKDIR;
 
	}
 

	
 
	return dir;
 
}
 

	
 
/**
 
 * Can a tram track build without destruction on the given tile?
 
 * @param c the company that would be building the tram tracks
 
 * @param t the tile to build on.
 
 * @param r the road bits needed.
 
 * @return true when a track track can be build on 't'
 
 */
 
static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r)
 
{
 
	/* The 'current' company is not necessarily the owner of the vehicle. */
 
	Backup<CompanyByte> cur_company(_current_company, c);
 
	Backup<CompanyByte> cur_company(_current_company, c, FILE_LINE);
 

	
 
	CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NONE, CMD_BUILD_ROAD);
 

	
 
	cur_company.Restore();
 
	return ret.Succeeded();
 
}
 

	
 
static bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
 
{
 
	if (v->overtaking != 0)  {
 
		if (IsTileType(v->tile, MP_STATION)) {
 
			/* Force us to be not overtaking! */
 
			v->overtaking = 0;
 
		} else if (++v->overtaking_ctr >= 35) {
 
			/* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
 
			 *  if the vehicle started a corner. To protect that, only allow an abort of
 
			 *  overtake if we are on straight roads */
 
			if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
 
				v->overtaking = 0;
 
			}
 
		}
 
	}
 

	
 
	/* If this vehicle is in a depot and we've reached this point it must be
src/saveload/afterload.cpp
Show inline comments
 
@@ -1550,49 +1550,49 @@ bool AfterLoadGame()
 
		/* Update locks, depots, docks and buoys to have a water class based
 
		 * on its neighbouring tiles. Done after river and canal updates to
 
		 * ensure neighbours are correct. */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (GetTileSlope(t, NULL) != SLOPE_FLAT) continue;
 

	
 
			if (IsTileType(t, MP_WATER) && IsLock(t)) SetWaterClassDependingOnSurroundings(t, false);
 
			if (IsTileType(t, MP_STATION) && (IsDock(t) || IsBuoy(t))) SetWaterClassDependingOnSurroundings(t, false);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(87)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* skip oil rigs at borders! */
 
			if ((IsTileType(t, MP_WATER) || IsBuoyTile(t)) &&
 
					(TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1)) {
 
				/* Some version 86 savegames have wrong water class at map borders (under buoy, or after removing buoy).
 
				 * This conversion has to be done before buoys with invalid owner are removed. */
 
				SetWaterClass(t, WATER_CLASS_SEA);
 
			}
 

	
 
			if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) {
 
				Owner o = GetTileOwner(t);
 
				if (o < MAX_COMPANIES && !Company::IsValidID(o)) {
 
					Backup<CompanyByte> cur_company(_current_company, o);
 
					Backup<CompanyByte> cur_company(_current_company, o, FILE_LINE);
 
					ChangeTileOwner(t, o, INVALID_OWNER);
 
					cur_company.Restore();
 
				}
 
				if (IsBuoyTile(t)) {
 
					/* reset buoy owner to OWNER_NONE in the station struct
 
					 * (even if it is owned by active company) */
 
					Waypoint::GetByTile(t)->owner = OWNER_NONE;
 
				}
 
			} else if (IsTileType(t, MP_ROAD)) {
 
				/* works for all RoadTileType */
 
				for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
 
					/* update even non-existing road types to update tile owner too */
 
					Owner o = GetRoadOwner(t, rt);
 
					if (o < MAX_COMPANIES && !Company::IsValidID(o)) SetRoadOwner(t, rt, OWNER_NONE);
 
				}
 
				if (IsLevelCrossing(t)) {
 
					if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t);
 
				}
 
			} else if (IsPlainRailTile(t)) {
 
				if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t);
 
			}
 
		}
 

	
 
		/* Convert old PF settings to new */
src/town_cmd.cpp
Show inline comments
 
@@ -495,49 +495,49 @@ static void TileLoop_Town(TileIndex tile
 
					break;
 

	
 
				default:
 
					break;
 
			}
 
		}
 
	} else {
 
		if (GB(r, 0, 8) < hs->population) {
 
			uint amt = GB(r, 0, 8) / 8 + 1;
 

	
 
			if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
 
			t->new_max_pass += amt;
 
			t->new_act_pass += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations());
 
		}
 

	
 
		if (GB(r, 8, 8) < hs->mail_generation) {
 
			uint amt = GB(r, 8, 8) / 8 + 1;
 

	
 
			if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
 
			t->new_max_mail += amt;
 
			t->new_act_mail += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations());
 
		}
 
	}
 

	
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN);
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
 

	
 
	if ((hs->building_flags & BUILDING_HAS_1_TILE) &&
 
			HasBit(t->flags, TOWN_IS_FUNDED) &&
 
			CanDeleteHouse(tile) &&
 
			GetHouseAge(tile) >= hs->minimum_life &&
 
			--t->time_until_rebuild == 0) {
 
		t->time_until_rebuild = GB(r, 16, 8) + 192;
 

	
 
		ClearTownHouse(t, tile);
 

	
 
		/* Rebuild with another house? */
 
		if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile);
 
	}
 

	
 
	cur_company.Restore();
 
}
 

	
 
static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags)
 
{
 
	if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
 
	if (!CanDeleteHouse(tile)) return CMD_ERROR;
 

	
 
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
 

	
 
@@ -1276,49 +1276,49 @@ static RoadBits GenRandomRoadBits()
 

	
 
/** Grow the town
 
 * @param t town to grow
 
 * @return true iff a house was built
 
 */
 
static bool GrowTown(Town *t)
 
{
 
	static const TileIndexDiffC _town_coord_mod[] = {
 
		{-1,  0},
 
		{ 1,  1},
 
		{ 1, -1},
 
		{-1, -1},
 
		{-1,  0},
 
		{ 0,  2},
 
		{ 2,  0},
 
		{ 0, -2},
 
		{-1, -1},
 
		{-2,  2},
 
		{ 2,  2},
 
		{ 2, -2},
 
		{ 0,  0}
 
	};
 

	
 
	/* Current "company" is a town */
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN);
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
 

	
 
	TileIndex tile = t->xy; // The tile we are working with ATM
 

	
 
	/* Find a road that we can base the construction on. */
 
	const TileIndexDiffC *ptr;
 
	for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
 
		if (GetTownRoadBits(tile) != ROAD_NONE) {
 
			int r = GrowTownAtRoad(t, tile);
 
			cur_company.Restore();
 
			return r != 0;
 
		}
 
		tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
 
	}
 

	
 
	/* No road available, try to build a random road block by
 
	 * clearing some land and then building a road there. */
 
	if (_settings_game.economy.allow_town_roads || _generating_world) {
 
		tile = t->xy;
 
		for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
 
			/* Only work with plain land that not already has a house */
 
			if (!IsTileType(tile, MP_HOUSE) && GetTileSlope(tile, NULL) == SLOPE_FLAT) {
 
				if (DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded()) {
 
					DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
 
					cur_company.Restore();
 
@@ -2362,49 +2362,49 @@ static void TownActionRoadRebuild(Town *
 
	char company_name[MAX_LENGTH_COMPANY_NAME_BYTES];
 
	SetDParam(0, _current_company);
 
	GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
 

	
 
	char *cn = strdup(company_name);
 
	SetDParam(0, t->index);
 
	SetDParamStr(1, cn);
 

	
 
	AddNewsItem(STR_NEWS_ROAD_REBUILDING, NS_GENERAL, NR_TOWN, t->index, NR_NONE, UINT32_MAX, cn);
 
}
 

	
 
static bool DoBuildStatueOfCompany(TileIndex tile, TownID town_id)
 
{
 
	/* Statues can be build on slopes, just like houses. Only the steep slopes is a no go. */
 
	if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
 
	/* Don't build statues under bridges. */
 
	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
 

	
 
	if (!IsTileType(tile, MP_HOUSE) &&
 
			!IsTileType(tile, MP_CLEAR) &&
 
			!IsTileType(tile, MP_TREES)) {
 
		return false;
 
	}
 

	
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_NONE);
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
 
	CommandCost r = DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
	cur_company.Restore();
 

	
 
	if (r.Failed()) return false;
 

	
 
	MakeStatue(tile, _current_company, town_id);
 
	MarkTileDirtyByTile(tile);
 

	
 
	return true;
 
}
 

	
 
/**
 
 * Search callback function for TownActionBuildStatue
 
 * @param tile on which to perform the search
 
 * @param user_data The town_id for which we want a statue
 
 * @return the result of the test
 
 */
 
static bool SearchTileForStatue(TileIndex tile, void *user_data)
 
{
 
	TownID *town_id = (TownID *)user_data;
 
	return DoBuildStatueOfCompany(tile, *town_id);
 
}
 

	
 
/**
src/vehicle.cpp
Show inline comments
 
@@ -752,49 +752,49 @@ void CallVehicleTicks()
 
		assert(Vehicle::Get(vehicle_index) == v);
 

	
 
		switch (v->type) {
 
			default: break;
 

	
 
			case VEH_TRAIN:
 
			case VEH_ROAD:
 
			case VEH_AIRCRAFT:
 
			case VEH_SHIP:
 
				if (_age_cargo_skip_counter == 0) v->cargo.AgeCargo();
 

	
 
				if (v->type == VEH_TRAIN && Train::From(v)->IsWagon()) continue;
 
				if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
 
				if (v->type == VEH_ROAD && !RoadVehicle::From(v)->IsRoadVehFront()) continue;
 

	
 
				v->motion_counter += v->cur_speed;
 
				/* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
 
				if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
 

	
 
				/* Play an alterate running sound every 16 ticks */
 
				if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
 
		}
 
	}
 

	
 
	Backup<CompanyByte> cur_company(_current_company);
 
	Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
 
	for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
 
		v = it->first;
 
		/* Autoreplace needs the current company set as the vehicle owner */
 
		cur_company.Change(v->owner);
 

	
 
		/* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
 
		 * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
 
		 * they are already leaving the depot again before being replaced. */
 
		if (it->second) v->vehstatus &= ~VS_STOPPED;
 

	
 
		/* Store the position of the effect as the vehicle pointer will become invalid later */
 
		int x = v->x_pos;
 
		int y = v->y_pos;
 
		int z = v->z_pos;
 

	
 
		const Company *c = Company::Get(_current_company);
 
		SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
 
		CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
 
		SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
 

	
 
		if (!IsLocalCompany()) continue;
 

	
 
		if (res.Succeeded()) {
 
			ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
 
@@ -1091,49 +1091,49 @@ void VehicleEnterDepot(Vehicle *v)
 
	v->vehstatus |= VS_HIDDEN;
 
	v->cur_speed = 0;
 

	
 
	VehicleServiceInDepot(v);
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.IsType(OT_GOTO_DEPOT)) {
 
		SetWindowDirty(WC_VEHICLE_VIEW, v->index);
 

	
 
		const Order *real_order = v->GetOrder(v->cur_order_index);
 
		Order t = v->current_order;
 
		v->current_order.MakeDummy();
 

	
 
		/* Test whether we are heading for this depot. If not, do nothing.
 
		 * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
 
		if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
 
				real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
 
				(v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
 
			/* We are heading for another depot, keep driving. */
 
			return;
 
		}
 

	
 
		if (t.IsRefit()) {
 
			Backup<CompanyByte> cur_company(_current_company, v->owner);
 
			Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
 
			CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
 
			cur_company.Restore();
 

	
 
			if (cost.Failed()) {
 
				_vehicles_to_autoreplace[v] = false;
 
				if (v->owner == _local_company) {
 
					/* Notify the user that we stopped the vehicle */
 
					SetDParam(0, v->index);
 
					AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
 
				}
 
			} else if (v->owner == _local_company && cost.GetCost() != 0) {
 
				ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
 
			}
 
		}
 

	
 
		if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
 
			/* Part of orders */
 
			UpdateVehicleTimetable(v, true);
 
			v->IncrementOrderIndex();
 
		}
 
		if (t.GetDepotActionType() & ODATFB_HALT) {
 
			/* Vehicles are always stopped on entering depots. Do not restart this one. */
 
			_vehicles_to_autoreplace[v] = false;
 
			if (v->owner == _local_company) {
src/water_cmd.cpp
Show inline comments
 
@@ -861,49 +861,49 @@ static FloodingBehaviour GetFloodingBeha
 

	
 
		case MP_STATION:
 
			if (IsBuoy(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsOilRig(tile)) {
 
				return (GetWaterClass(tile) == WATER_CLASS_SEA ? FLOOD_ACTIVE : FLOOD_NONE);
 
			}
 
			return FLOOD_NONE;
 

	
 
		case MP_INDUSTRY:
 
			return ((IsIndustryTileOnWater(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE);
 

	
 
		default:
 
			return FLOOD_NONE;
 
	}
 
}
 

	
 
/**
 
 * Floods a tile.
 
 */
 
void DoFloodTile(TileIndex target)
 
{
 
	assert(!IsTileType(target, MP_WATER));
 

	
 
	bool flooded = false; // Will be set to true if something is changed.
 

	
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_WATER);
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
 

	
 
	Slope tileh = GetTileSlope(target, NULL);
 
	if (tileh != SLOPE_FLAT) {
 
		/* make coast.. */
 
		switch (GetTileType(target)) {
 
			case MP_RAILWAY: {
 
				if (!IsPlainRail(target)) break;
 
				FloodVehicles(target);
 
				flooded = FloodHalftile(target);
 
				break;
 
			}
 

	
 
			case MP_TREES:
 
				if (!IsSlopeWithOneCornerRaised(tileh)) {
 
					SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
 
					MarkTileDirtyByTile(target);
 
					flooded = true;
 
					break;
 
				}
 
			/* FALL THROUGH */
 
			case MP_CLEAR:
 
				if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
 
					MakeShore(target);
 
					MarkTileDirtyByTile(target);
 
@@ -921,49 +921,49 @@ void DoFloodTile(TileIndex target)
 
		/* flood flat tile */
 
		if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
 
			MakeSea(target);
 
			MarkTileDirtyByTile(target);
 
			flooded = true;
 
		}
 
	}
 

	
 
	if (flooded) {
 
		/* Mark surrounding canal tiles dirty too to avoid glitches */
 
		MarkCanalsAndRiversAroundDirty(target);
 

	
 
		/* update signals if needed */
 
		UpdateSignalsInBuffer();
 
	}
 

	
 
	cur_company.Restore();
 
}
 

	
 
/**
 
 * Drys a tile up.
 
 */
 
static void DoDryUp(TileIndex tile)
 
{
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_WATER);
 
	Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
 

	
 
	switch (GetTileType(tile)) {
 
		case MP_RAILWAY:
 
			assert(IsPlainRail(tile));
 
			assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
 

	
 
			RailGroundType new_ground;
 
			switch (GetTrackBits(tile)) {
 
				case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
 
				case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
 
				case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
 
				case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
 
				default: NOT_REACHED();
 
			}
 
			SetRailGroundType(tile, new_ground);
 
			MarkTileDirtyByTile(tile);
 
			break;
 

	
 
		case MP_TREES:
 
			SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
 
			MarkTileDirtyByTile(tile);
 
			break;
 

	
 
		case MP_WATER:
0 comments (0 inline, 0 general)