/**
 * Test if a given TileArea is valid.
 * @return \c true if the area is non-empty and fits inside the map, \c false otherwise.
 */
static CommandCost ValParamCopyPasteArea(const GenericTileArea &ta)
{
	if (!IsValidTile(ta.tile) ||
			!IsInsideBS(ta.w, 1, _settings_game.construction.clipboard_capacity) ||
			!IsInsideBS(ta.h, 1, _settings_game.construction.clipboard_capacity)) {
		return CMD_ERROR;
	}

	if (TileX(ta.tile) + ta.w > MapMaxX(MapOf(ta.tile)) ||
			TileY(ta.tile) + ta.h > MapMaxY(MapOf(ta.tile))) {
		return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB);
	}

	return CommandCost();
}
	virtual void OnClick(Point pt, int widget, int click_count)
	{
		if (widget >= WID_TT_BEGIN && widget < WID_TT_END) {
			if (_ctrl_pressed) {
				/* toggle the bit of the transparencies lock variable */
				ToggleTransparencyLock((TransparencyOption)(widget - WID_TT_BEGIN));
				this->SetDirty();
			} else {
				/* toggle the bit of the transparencies variable and play a sound */
				ToggleTransparency((TransparencyOption)(widget - WID_TT_BEGIN));
				if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
				MarkWholeScreenDirty();
			}
		} else if (widget == WID_TT_BUTTONS) {
			uint i;
			for (i = WID_TT_BEGIN; i < WID_TT_END; i++) {
				const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(i);
				if (IsInsideBS(pt.x, nwid->pos_x, nwid->current_x)) {
					break;
				}
			}
			if (i == WID_TT_LOADING || i == WID_TT_END) return;

			ToggleInvisibility((TransparencyOption)(i - WID_TT_BEGIN));
			if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);

			/* Redraw whole screen only if transparency is set */
			if (IsTransparencySet((TransparencyOption)(i - WID_TT_BEGIN))) {
				MarkWholeScreenDirty();
			} else {
				this->SetWidgetDirty(WID_TT_BUTTONS);
			}
		}
	}
Exemple #3
0
bool BuildConfirmationWindowProcessViewportClick()
{
	if (!BuildConfirmationWindow::shown) return false;

	Window *w = FindWindowById(WC_BUILD_CONFIRMATION, 0);
	if (w != NULL && IsInsideBS(_cursor.pos.x, w->left, w->width) && IsInsideBS(_cursor.pos.y, w->top, w->height)) {
		Point pt;
		pt.x = _cursor.pos.x - w->left;
		pt.y = _cursor.pos.y - w->top;
		w->OnClick(pt, WID_BC_OK, 1);
		return true;
	}

	HideBuildConfirmationWindow();
	return false;
}
void Blitter_32bppAnim::PaletteAnimate(uint start, uint count)
{
	assert(!_screen_disable_anim);

	/* Never repaint the transparency pixel */
	if (start == 0) {
		start++;
		count--;
	}

	const uint8 *anim = this->anim_buf;
	uint32 *dst = (uint32 *)_screen.dst_ptr;

	/* Let's walk the anim buffer and try to find the pixels */
	for (int y = this->anim_buf_height; y != 0 ; y--) {
		for (int x = this->anim_buf_width; x != 0 ; x--) {
			uint colour = *anim;
			if (IsInsideBS(colour, start, count)) {
				/* Update this pixel */
				*dst = LookupColourInPalette(colour);
			}
			dst++;
			anim++;
		}
		dst += _screen.pitch - this->anim_buf_width;
	}

	/* Make sure the backend redraws the whole screen */
	_video_driver->MakeDirty(0, 0, _screen.width, _screen.height);
}
Exemple #5
0
/**
 * Perform all steps to upgrade from the old station buoys to the new version
 * that uses waypoints. This includes some old saveload mechanics.
 */
void MoveBuoysToWaypoints()
{
	/* Buoy orders become waypoint orders */
	OrderList *ol;
	FOR_ALL_ORDER_LISTS(ol) {
		if (ol->GetFirstSharedVehicle()->type != VEH_SHIP) continue;

		for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o);
	}

	Vehicle *v;
	FOR_ALL_VEHICLES(v) {
		if (v->type != VEH_SHIP) continue;

		UpdateWaypointOrder(&v->current_order);
	}

	/* Now make the stations waypoints */
	Station *st;
	FOR_ALL_STATIONS(st) {
		if ((st->had_vehicle_of_type & HVOT_WAYPOINT) == 0) continue;

		StationID index    = st->index;
		TileIndex xy       = st->xy;
		Town *town         = st->town;
		StringID string_id = st->string_id;
		char *name         = st->name;
		Date build_date    = st->build_date;

		/* Delete the station, so we can make it a real waypoint. */
		delete st;

		Waypoint *wp = new (index) Waypoint(xy);
		wp->town       = town;
		wp->string_id  = STR_SV_STNAME_BUOY;
		wp->name       = name;
		wp->delete_ctr = 0; // Just reset delete counter for once.
		wp->build_date = build_date;
		wp->owner      = OWNER_NONE;

		if (IsInsideBS(string_id, STR_SV_STNAME_BUOY, 9)) wp->town_cn = string_id - STR_SV_STNAME_BUOY;

		if (IsBuoyTile(xy) && GetStationIndex(xy) == index) {
			wp->facilities |= FACIL_DOCK;
		}

		wp->rect.BeforeAddTile(xy, StationRect::ADD_FORCE);
	}
}
void Blitter_32bppAnim::CopyFromBuffer(void *video, const void *src, int width, int height)
{
	assert(!_screen_disable_anim);
	assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
	uint32 *dst = (uint32 *)video;
	uint32 *usrc = (uint32 *)src;
	uint8 *anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf;

	int count = (_use_palette == PAL_DOS) ? PALETTE_ANIM_SIZE_DOS : PALETTE_ANIM_SIZE_WIN;

	for (; height > 0; height--) {
		/* We need to keep those for palette animation. */
		uint32 *dst_pal = dst;
		uint8 *anim_pal = anim_line;

		memcpy(dst, usrc, width * sizeof(uint32));
		usrc += width;
		dst += _screen.pitch;
		/* Copy back the anim-buffer */
		memcpy(anim_line, usrc, width * sizeof(uint8));
		usrc = (uint32 *)((uint8 *)usrc + width);
		anim_line += this->anim_buf_width;

		/* Okay, it is *very* likely that the image we stored is using
		 * the wrong palette animated colours. There are two things we
		 * can do to fix this. The first is simply reviewing the whole
		 * screen after we copied the buffer, i.e. run PaletteAnimate,
		 * however that forces a full screen redraw which is expensive
		 * for just the cursor. This just copies the implementation of
		 * palette animation, much cheaper though slightly nastier. */
		for (int i = 0; i < width; i++) {
			uint colour = *anim_pal;
			if (IsInsideBS(colour, PALETTE_ANIM_SIZE_START, count)) {
				/* Update this pixel */
				*dst_pal = LookupColourInPalette(colour);
			}
			dst_pal++;
			anim_pal++;
		}
	}
}
	virtual void OnClick(Point pt, int widget, int click_count)
	{
		if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_END) {
			if (this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE) return;

			ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected);
			return;
		}

		switch (widget) {
			case WID_NCL_MATRIX: {
				uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX);
				if (id_v >= this->content.Length()) return; // click out of bounds

				this->selected = *this->content.Get(id_v);
				this->list_pos = id_v;

				const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
				if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
					_network_content_client.ToggleSelectedState(this->selected);
					this->content.ForceResort();
				}

				this->InvalidateData();
				break;
			}

			case WID_NCL_CHECKBOX:
			case WID_NCL_TYPE:
			case WID_NCL_NAME:
				if (this->content.SortType() == widget - WID_NCL_CHECKBOX) {
					this->content.ToggleSortOrder();
					this->list_pos = this->content.Length() - this->list_pos - 1;
				} else {
					this->content.SetSortType(widget - WID_NCL_CHECKBOX);
					this->content.ForceResort();
					this->SortContentList();
				}
				this->ScrollToSelected();
				this->InvalidateData();
				break;

			case WID_NCL_SELECT_ALL:
				_network_content_client.SelectAll();
				this->InvalidateData();
				break;

			case WID_NCL_SELECT_UPDATE:
				_network_content_client.SelectUpgrade();
				this->InvalidateData();
				break;

			case WID_NCL_UNSELECT:
				_network_content_client.UnselectAll();
				this->InvalidateData();
				break;

			case WID_NCL_CANCEL:
				delete this;
				break;

			case WID_NCL_OPEN_URL:
				if (this->selected != NULL) {
					extern void OpenBrowser(const char *url);
					OpenBrowser(this->selected->url);
				}
				break;

			case WID_NCL_DOWNLOAD:
				if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) == NULL) new NetworkContentDownloadStatusWindow();
				break;
		}
	}
Exemple #8
0
/**
 * Perform all steps to upgrade from the old station buoys to the new version
 * that uses waypoints. This includes some old saveload mechanics.
 */
void MoveBuoysToWaypoints()
{
	/* Buoy orders become waypoint orders */
	OrderList *ol;
	FOR_ALL_ORDER_LISTS(ol) {
		VehicleType vt = ol->GetFirstSharedVehicle()->type;
		if (vt != VEH_SHIP && vt != VEH_TRAIN) continue;

		for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o);
	}

	Vehicle *v;
	FOR_ALL_VEHICLES(v) {
		VehicleType vt = v->type;
		if (vt != VEH_SHIP && vt != VEH_TRAIN) continue;

		UpdateWaypointOrder(&v->current_order);
	}

	/* Now make the stations waypoints */
	Station *st;
	FOR_ALL_STATIONS(st) {
		if ((st->had_vehicle_of_type & HVOT_WAYPOINT) == 0) continue;

		StationID index    = st->index;
		TileIndex xy       = st->xy;
		Town *town         = st->town;
		StringID string_id = st->string_id;
		char *name         = st->name;
		st->name           = NULL;
		Date build_date    = st->build_date;
		/* TTDPatch could use "buoys with rail station" for rail waypoints */
		bool train         = st->train_station.tile != INVALID_TILE;
		TileArea train_st  = st->train_station;

		/* Delete the station, so we can make it a real waypoint. */
		delete st;

		/* Stations and waypoints are in the same pool, so if a station
		 * is deleted there must be place for a Waypoint. */
		assert(Waypoint::CanAllocateItem());
		Waypoint *wp   = new (index) Waypoint(xy);
		wp->town       = town;
		wp->string_id  = train ? STR_SV_STNAME_WAYPOINT : STR_SV_STNAME_BUOY;
		wp->name       = name;
		wp->delete_ctr = 0; // Just reset delete counter for once.
		wp->build_date = build_date;
		wp->owner      = train ? GetTileOwner(xy) : OWNER_NONE;

		if (IsInsideBS(string_id, STR_SV_STNAME_BUOY, 9)) wp->town_cn = string_id - STR_SV_STNAME_BUOY;

		if (train) {
			/* When we make a rail waypoint of the station, convert the map as well. */
			TILE_AREA_LOOP(t, train_st) {
				if (!IsTileType(t, MP_STATION) || GetStationIndex(t) != index) continue;

				SB(_me[t].m6, 3, 3, STATION_WAYPOINT);
				wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE);
			}

			wp->train_station = train_st;
			wp->facilities |= FACIL_TRAIN;
		} else if (IsBuoyTile(xy) && GetStationIndex(xy) == index) {
			wp->rect.BeforeAddTile(xy, StationRect::ADD_FORCE);
			wp->facilities |= FACIL_DOCK;
		}
	}
	virtual void OnClick(Point pt, int widget, int click_count)
	{
		switch (widget) {
			case NCLWW_MATRIX: {
				uint32 id_v = (pt.y - this->GetWidget<NWidgetBase>(NCLWW_MATRIX)->pos_y) / this->resize.step_height;

				if (id_v >= this->vscroll.GetCapacity()) return; // click out of bounds
				id_v += this->vscroll.GetPosition();

				if (id_v >= this->content.Length()) return; // click out of bounds

				this->selected = *this->content.Get(id_v);
				this->list_pos = id_v;

				const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(NCLWW_CHECKBOX);
				if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
					_network_content_client.ToggleSelectedState(this->selected);
					this->content.ForceResort();
				}

				this->InvalidateData();
			} break;

			case NCLWW_CHECKBOX:
			case NCLWW_TYPE:
			case NCLWW_NAME:
				if (this->content.SortType() == widget - NCLWW_CHECKBOX) {
					this->content.ToggleSortOrder();
					this->list_pos = this->content.Length() - this->list_pos - 1;
				} else {
					this->content.SetSortType(widget - NCLWW_CHECKBOX);
					this->content.ForceResort();
					this->SortContentList();
				}
				this->ScrollToSelected();
				this->InvalidateData();
				break;

			case NCLWW_SELECT_ALL:
				_network_content_client.SelectAll();
				this->InvalidateData();
				break;

			case NCLWW_SELECT_UPDATE:
				_network_content_client.SelectUpgrade();
				this->InvalidateData();
				break;

			case NCLWW_UNSELECT:
				_network_content_client.UnselectAll();
				this->InvalidateData();
				break;

			case NCLWW_CANCEL:
				delete this;
				break;

			case NCLWW_DOWNLOAD:
				if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, 0) == NULL) new NetworkContentDownloadStatusWindow();
				break;
		}
	}
/**
 * Plant a tree.
 * @param tile start tile of area-drag of tree plantation
 * @param flags type of operation
 * @param p1 tree type, TREE_INVALID means random.
 * @param p2 end tile of area-drag
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
	StringID msg = INVALID_STRING_ID;
	CommandCost cost(EXPENSES_OTHER);
	const byte tree_to_plant = GB(p1, 0, 8); // We cannot use Extract as min and max are climate specific.

	if (p2 >= MapSize()) return CMD_ERROR;
	/* Check the tree type within the current climate */
	if (tree_to_plant != TREE_INVALID && !IsInsideBS(tree_to_plant, _tree_base_by_landscape[_settings_game.game_creation.landscape], _tree_count_by_landscape[_settings_game.game_creation.landscape])) return CMD_ERROR;

	TileArea ta(tile, p2);
	TILE_AREA_LOOP(tile, ta) {
		switch (GetTileType(tile)) {
			case MP_TREES:
				/* no more space for trees? */
				if (_game_mode != GM_EDITOR && GetTreeCount(tile) == 4) {
					msg = STR_ERROR_TREE_ALREADY_HERE;
					continue;
				}

				if (flags & DC_EXEC) {
					AddTreeCount(tile, 1);
					MarkTileDirtyByTile(tile);
				}
				/* 2x as expensive to add more trees to an existing tile */
				cost.AddCost(_price[PR_BUILD_TREES] * 2);
				break;

			case MP_WATER:
				if (!IsCoast(tile) || IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL))) {
					msg = STR_ERROR_CAN_T_BUILD_ON_WATER;
					continue;
				}
				/* FALL THROUGH */
			case MP_CLEAR: {
				if (IsBridgeAbove(tile)) {
					msg = STR_ERROR_SITE_UNSUITABLE;
					continue;
				}

				TreeType treetype = (TreeType)tree_to_plant;
				/* Be a bit picky about which trees go where. */
				if (_settings_game.game_creation.landscape == LT_TROPIC && treetype != TREE_INVALID && (
						/* No cacti outside the desert */
						(treetype == TREE_CACTUS && GetTropicZone(tile) != TROPICZONE_DESERT) ||
						/* No rain forest trees outside the rain forest, except in the editor mode where it makes those tiles rain forest tile */
						(IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS) && GetTropicZone(tile) != TROPICZONE_RAINFOREST && _game_mode != GM_EDITOR) ||
						/* And no subtropical trees in the desert/rain forest */
						(IsInsideMM(treetype, TREE_SUB_TROPICAL, TREE_TOYLAND) && GetTropicZone(tile) != TROPICZONE_NORMAL))) {
					msg = STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE;
					continue;
				}

				if (IsTileType(tile, MP_CLEAR)) {
					/* Remove fields or rocks. Note that the ground will get barrened */
					switch (GetRawClearGround(tile)) {
						case CLEAR_FIELDS:
						case CLEAR_ROCKS: {
							CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
							if (ret.Failed()) return ret;
							cost.AddCost(ret);
							break;
						}

						default: break;
					}
				}

				if (_game_mode != GM_EDITOR && Company::IsValidID(_current_company)) {
					Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
					if (t != NULL) ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM, flags);
				}

				if (flags & DC_EXEC) {
					if (treetype == TREE_INVALID) {
						treetype = GetRandomTreeType(tile, GB(Random(), 24, 8));
						if (treetype == TREE_INVALID) treetype = TREE_CACTUS;
					}

					/* Plant full grown trees in scenario editor */
					PlantTreesOnTile(tile, treetype, 0, _game_mode == GM_EDITOR ? 3 : 0);
					MarkTileDirtyByTile(tile);

					/* When planting rainforest-trees, set tropiczone to rainforest in editor. */
					if (_game_mode == GM_EDITOR && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) {
						SetTropicZone(tile, TROPICZONE_RAINFOREST);
					}
				}
				cost.AddCost(_price[PR_BUILD_TREES]);
				break;
			}

			default:
				msg = STR_ERROR_SITE_UNSUITABLE;
				break;
		}
	}

	if (cost.GetCost() == 0) {
		return_cmd_error(msg);
	} else {
		return cost;
	}
}