|
@@ -605,136 +605,128 @@ void ClearSnowLine()
|
|
|
* @param text unused
|
|
|
* @return the cost of this operation or an error
|
|
|
*/
|
|
|
CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
|
|
{
|
|
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
|
|
bool do_clear = false;
|
|
|
/* Test for stuff which results in water when cleared. Then add the cost to also clear the water. */
|
|
|
if ((flags & DC_FORCE_CLEAR_TILE) && HasTileWaterClass(tile) && IsTileOnWater(tile) && !IsWaterTile(tile) && !IsCoastTile(tile)) {
|
|
|
if ((flags & DC_AUTO) && GetWaterClass(tile) == WATER_CLASS_CANAL) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
|
|
|
do_clear = true;
|
|
|
cost.AddCost(GetWaterClass(tile) == WATER_CLASS_CANAL ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]);
|
|
|
}
|
|
|
|
|
|
const ClearedObjectArea *coa = FindClearedObject(tile);
|
|
|
|
|
|
/* If this tile was the first tile which caused object destruction, always
|
|
|
* pass it on to the tile_type_proc. That way multiple test runs and the exec run stay consistent. */
|
|
|
if (coa != NULL && coa->first_tile != tile) {
|
|
|
/* If this tile belongs to an object which was already cleared via another tile, pretend it has been
|
|
|
* already removed.
|
|
|
* However, we need to check stuff, which is not the same for all object tiles. (e.g. being on water or not) */
|
|
|
|
|
|
/* If a object is removed, it leaves either bare land or water. */
|
|
|
if ((flags & DC_NO_WATER) && HasTileWaterClass(tile) && IsTileOnWater(tile)) {
|
|
|
return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
|
|
|
}
|
|
|
if (do_clear && (flags & DC_EXEC)) DoClearSquare(tile);
|
|
|
return cost;
|
|
|
}
|
|
|
cost.AddCost(_tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags));
|
|
|
if (do_clear && (flags & DC_EXEC)) DoClearSquare(tile);
|
|
|
return cost;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Clear a big piece of landscape
|
|
|
* @param tile end tile of area dragging
|
|
|
* @param flags of operation to conduct
|
|
|
* @param p1 start tile of area dragging
|
|
|
* @param p2 unused
|
|
|
* @param text unused
|
|
|
* @return the cost of this operation or an error
|
|
|
*/
|
|
|
CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
|
|
{
|
|
|
if (p1 >= MapSize()) return CMD_ERROR;
|
|
|
|
|
|
/* make sure sx,sy are smaller than ex,ey */
|
|
|
int ex = TileX(tile);
|
|
|
int ey = TileY(tile);
|
|
|
int sx = TileX(p1);
|
|
|
int sy = TileY(p1);
|
|
|
if (ex < sx) Swap(ex, sx);
|
|
|
if (ey < sy) Swap(ey, sy);
|
|
|
|
|
|
Money money = GetAvailableMoneyForCommand();
|
|
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
|
|
CommandCost last_error = CMD_ERROR;
|
|
|
bool had_success = false;
|
|
|
|
|
|
for (int x = sx; x <= ex; ++x) {
|
|
|
for (int y = sy; y <= ey; ++y) {
|
|
|
CommandCost ret = DoCommand(TileXY(x, y), 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
|
|
|
if (ret.Failed()) {
|
|
|
last_error = ret;
|
|
|
continue;
|
|
|
}
|
|
|
TileArea ta(tile, p1);
|
|
|
TILE_AREA_LOOP(t, ta) {
|
|
|
CommandCost ret = DoCommand(t, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
|
|
|
if (ret.Failed()) {
|
|
|
last_error = ret;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
had_success = true;
|
|
|
if (flags & DC_EXEC) {
|
|
|
money -= ret.GetCost();
|
|
|
if (ret.GetCost() > 0 && money < 0) {
|
|
|
_additional_cash_required = ret.GetCost();
|
|
|
return cost;
|
|
|
}
|
|
|
DoCommand(TileXY(x, y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
|
|
had_success = true;
|
|
|
if (flags & DC_EXEC) {
|
|
|
money -= ret.GetCost();
|
|
|
if (ret.GetCost() > 0 && money < 0) {
|
|
|
_additional_cash_required = ret.GetCost();
|
|
|
return cost;
|
|
|
}
|
|
|
DoCommand(t, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
|
|
|
|
|
/* draw explosion animation... */
|
|
|
if ((x == sx || x == ex) && (y == sy || y == ey)) {
|
|
|
/* big explosion in each corner, or small explosion for single tiles */
|
|
|
CreateEffectVehicleAbove(x * TILE_SIZE + TILE_SIZE / 2, y * TILE_SIZE + TILE_SIZE / 2, 2,
|
|
|
sy == ey && sx == ex ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
|
|
|
);
|
|
|
}
|
|
|
/* draw explosion animation... */
|
|
|
TileIndex off = t - ta.tile;
|
|
|
if ((TileX(off) == 0 || TileX(off) == ta.w - 1U) && (TileY(off) == 0 || TileY(off) == ta.h - 1U)) {
|
|
|
/* big explosion in each corner, or small explosion for single tiles */
|
|
|
CreateEffectVehicleAbove(TileX(t) * TILE_SIZE + TILE_SIZE / 2, TileY(t) * TILE_SIZE + TILE_SIZE / 2, 2,
|
|
|
ta.w == 1 && ta.h == 1 ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
|
|
|
);
|
|
|
}
|
|
|
cost.AddCost(ret);
|
|
|
}
|
|
|
cost.AddCost(ret);
|
|
|
}
|
|
|
|
|
|
return had_success ? cost : last_error;
|
|
|
}
|
|
|
|
|
|
|
|
|
TileIndex _cur_tileloop_tile;
|
|
|
#define TILELOOP_BITS 4
|
|
|
#define TILELOOP_SIZE (1 << TILELOOP_BITS)
|
|
|
#define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
|
|
|
#define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
|
|
|
|
|
|
void RunTileLoop()
|
|
|
{
|
|
|
TileIndex tile = _cur_tileloop_tile;
|
|
|
|
|
|
assert((tile & ~TILELOOP_ASSERTMASK) == 0);
|
|
|
uint count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
|
|
|
do {
|
|
|
_tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
|
|
|
|
|
|
if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
|
|
|
tile += TILELOOP_SIZE; // no overflow
|
|
|
} else {
|
|
|
tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); // x would overflow, also increase y
|
|
|
}
|
|
|
} while (--count != 0);
|
|
|
assert((tile & ~TILELOOP_ASSERTMASK) == 0);
|
|
|
|
|
|
tile += 9;
|
|
|
if (tile & TILELOOP_CHKMASK) {
|
|
|
tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
|
|
|
}
|
|
|
_cur_tileloop_tile = tile;
|
|
|
}
|
|
|
|
|
|
void InitializeLandscape()
|
|
|
{
|
|
|
uint maxx = MapMaxX();
|
|
|
uint maxy = MapMaxY();
|
|
|
uint sizex = MapSizeX();
|
|
|
|
|
|
uint y;
|
|
|
for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
|
|
|
uint x;
|
|
|
for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
|
|
|
MakeClear(sizex * y + x, CLEAR_GRASS, 3);
|
|
|
SetTileHeight(sizex * y + x, 0);
|