예제 #1
0
/**
 * Construct the iterator.
 * @param corner1 Tile from where to begin iterating.
 * @param corner2 Tile where to end the iterating.
 */
DiagonalTileIterator::DiagonalTileIterator(TileIndex corner1, TileIndex corner2) : TileIterator(corner2), base_x(TileX(corner2)), base_y(TileY(corner2)), a_cur(0), b_cur(0)
{
	assert(corner1 < MapSize());
	assert(corner2 < MapSize());

	int dist_x = TileX(corner1) - TileX(corner2);
	int dist_y = TileY(corner1) - TileY(corner2);
	this->a_max = dist_x + dist_y;
	this->b_max = dist_y - dist_x;

	/* Unfortunately we can't find a new base and make all a and b positive because
	 * the new base might be a "flattened" corner where there actually is no single
	 * tile. If we try anyway the result is either inaccurate ("one off" half of the
	 * time) or the code gets much more complex;
	 *
	 * We also need to increment here to have equality as marker for the end of a row or
	 * column. Like that it's shorter than having another if/else in operator++
	 */
	if (this->a_max > 0) {
		this->a_max++;
	} else {
		this->a_max--;
	}

	if (this->b_max > 0) {
		this->b_max++;
	} else {
		this->b_max--;
	}
}
예제 #2
0
void CPointer::Render()
{
    int		cell_x, cell_y;
    vec3	p;
    vec3	pos = CameraPosition();

    glPushAttrib( GL_POLYGON_BIT | GL_LIGHTING_BIT | GL_FOG_BIT );
    glDisable( GL_DEPTH_TEST );
    glEnable( GL_TEXTURE_2D );
    glDisable( GL_FOG );
    glEnable( GL_BLEND );
    glEnable( GL_ALPHA );
    glBindTexture( GL_TEXTURE_2D, m_texture );
    glDisable( GL_CULL_FACE );
    glBlendFunc( GL_ONE, GL_ONE );
    glLineWidth( 3.5f );
    glColor3f( 1.0f, 0.5f, 0.0f );
    cell_x = ( int )( pos.x - 0.5f ) + MapSize() / 2;
    cell_y = ( int )( pos.z - 0.5f ) + MapSize() / 2;
    cell_x = static_cast<int>(m_last_cell.x);
    cell_y = static_cast<int>(m_last_cell.y);
    glBegin( GL_QUADS );
    glTexCoord2f( 0.0f, 0.0f );
    p = MapPosition( cell_x - PT_HALF, cell_y - PT_HALF );
    p.x -= m_pulse;
    p.y += 2.0f;
    p.z -= m_pulse;
    glVertex3fv( &p.x );
    glTexCoord2f( 0.0f, 1.0f );
    p = MapPosition( cell_x - PT_HALF, cell_y + PT_HALF );
    p.x -= m_pulse;
    p.y += 2.0f;
    p.z += m_pulse;
    glVertex3fv( &p.x );
    glTexCoord2f( 1.0f, 1.0f );
    p = MapPosition( cell_x + PT_HALF, cell_y + PT_HALF );
    p.x += m_pulse;
    p.y += 2.0f;
    p.z += m_pulse;
    glVertex3fv( &p.x );
    glTexCoord2f( 1.0f, 0.0f );
    p = MapPosition( cell_x + PT_HALF, cell_y - PT_HALF );
    p.x += m_pulse;
    p.y += 2.0f;
    p.z -= m_pulse;
    glVertex3fv( &p.x );
    glEnd();
    glPopAttrib();
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    glEnable( GL_DEPTH_TEST );
    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
    glEnable( GL_CULL_FACE );
}
예제 #3
0
//--------------------------------------------------------------
ofVec2f ofxBingQuad::QuadKeyToPixelXY(string quadKey, int targetLevel){
    
    int newTargetLevel = targetLevel+levelOfDetail;
    ofVec2f tile = QuadKeyToTileXY(quadKey);
    ofVec2f px = TileXYToPixelXY(tile.x, tile.y);
    
    unsigned int targetSize = MapSize(newTargetLevel);
    unsigned int inputSize = MapSize(quadKey.length());
    int reqX = ofMap(px.x, 0, inputSize, 0, targetSize);
    int reqY = ofMap(px.y, 0, inputSize, 0, targetSize);

    return ofVec2f(reqX,reqY);
}
예제 #4
0
파일: town_sl.cpp 프로젝트: Johnnei/OpenTTD
/**
 * Check and update town and house values.
 *
 * Checked are the HouseIDs. Updated are the
 * town population the number of houses per
 * town, the town radius and the max passengers
 * of the town.
 */
void UpdateHousesAndTowns()
{
	for (TileIndex t = 0; t < MapSize(); t++) {
		if (!IsTileType(t, MP_HOUSE)) continue;

		HouseID house_id = GetCleanHouseType(t);
		if (!HouseSpec::Get(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) {
			/* The specs for this type of house are not available any more, so
			 * replace it with the substitute original house type. */
			house_id = _house_mngr.GetSubstituteID(house_id);
			SetHouseType(t, house_id);
		}
	}

	/* Check for cases when a NewGRF has set a wrong house substitute type. */
	for (TileIndex t = 0; t < MapSize(); t++) {
		if (!IsTileType(t, MP_HOUSE)) continue;

		HouseID house_type = GetCleanHouseType(t);
		TileIndex north_tile = t + GetHouseNorthPart(house_type); // modifies 'house_type'!
		if (t == north_tile) {
			const HouseSpec *hs = HouseSpec::Get(house_type);
			bool valid_house = true;
			if (hs->building_flags & TILE_SIZE_2x1) {
				TileIndex tile = t + TileDiffXY(1, 0);
				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false;
			} else if (hs->building_flags & TILE_SIZE_1x2) {
				TileIndex tile = t + TileDiffXY(0, 1);
				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false;
			} else if (hs->building_flags & TILE_SIZE_2x2) {
				TileIndex tile = t + TileDiffXY(0, 1);
				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false;
				tile = t + TileDiffXY(1, 0);
				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 2) valid_house = false;
				tile = t + TileDiffXY(1, 1);
				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 3) valid_house = false;
			}
			/* If not all tiles of this house are present remove the house.
			 * The other tiles will get removed later in this loop because
			 * their north tile is not the correct type anymore. */
			if (!valid_house) DoClearSquare(t);
		} else if (!IsTileType(north_tile, MP_HOUSE) || GetCleanHouseType(north_tile) != house_type) {
			/* This tile should be part of a multi-tile building but the
			 * north tile of this house isn't on the map. */
			DoClearSquare(t);
		}
	}

	RebuildTownCaches();
}
예제 #5
0
/**
 * Configure a ViewPort for rendering (a part of) the map into a screenshot.
 * @param t Screenshot type
 * @param [out] vp Result viewport
 */
void SetupScreenshotViewport(ScreenshotType t, ViewPort *vp)
{
	/* Determine world coordinates of screenshot */
	if (t == SC_WORLD) {
		vp->zoom = ZOOM_LVL_WORLD_SCREENSHOT;

		TileIndex north_tile = _settings_game.construction.freeform_edges ? TileXY(1, 1) : TileXY(0, 0);
		TileIndex south_tile = MapSize() - 1;

		/* We need to account for a hill or high building at tile 0,0. */
		int extra_height_top = TilePixelHeight(north_tile) + 150;
		/* If there is a hill at the bottom don't create a large black area. */
		int reclaim_height_bottom = TilePixelHeight(south_tile);

		vp->virtual_left   = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, 0).x;
		vp->virtual_top    = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, extra_height_top).y;
		vp->virtual_width  = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, 0).x                     - vp->virtual_left + 1;
		vp->virtual_height = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, reclaim_height_bottom).y - vp->virtual_top  + 1;
	} else {
		vp->zoom = (t == SC_ZOOMEDIN) ? _settings_client.gui.zoom_min : ZOOM_LVL_VIEWPORT;

		Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
		vp->virtual_left   = w->viewport->virtual_left;
		vp->virtual_top    = w->viewport->virtual_top;
		vp->virtual_width  = w->viewport->virtual_width;
		vp->virtual_height = w->viewport->virtual_height;
	}

	/* Compute pixel coordinates */
	vp->left = 0;
	vp->top = 0;
	vp->width  = UnScaleByZoom(vp->virtual_width,  vp->zoom);
	vp->height = UnScaleByZoom(vp->virtual_height, vp->zoom);
	vp->overlay = NULL;
}
예제 #6
0
파일: town_sl.cpp 프로젝트: Johnnei/OpenTTD
/**
 * Rebuild all the cached variables of towns.
 */
void RebuildTownCaches()
{
	Town *town;
	InitializeBuildingCounts();

	/* Reset town population and num_houses */
	FOR_ALL_TOWNS(town) {
		town->cache.population = 0;
		town->cache.num_houses = 0;
	}

	for (TileIndex t = 0; t < MapSize(); t++) {
		if (!IsTileType(t, MP_HOUSE)) continue;

		HouseID house_id = GetHouseType(t);
		town = Town::GetByTile(t);
		IncreaseBuildingCount(town, house_id);
		if (IsHouseCompleted(t)) town->cache.population += HouseSpec::Get(house_id)->population;

		/* Increase the number of houses for every house, but only once. */
		if (GetHouseNorthPart(house_id) == 0) town->cache.num_houses++;
	}

	/* Update the population and num_house dependent values */
	FOR_ALL_TOWNS(town) {
		UpdateTownRadius(town);
		UpdateTownCargoes(town);
	}
	UpdateTownCargoBitmap();
}
예제 #7
0
/**
 * Levels a selected (rectangle) area of land
 * @param tile end tile of area-drag
 * @param flags for this command type
 * @param p1 start tile of area drag
 * @param p2 various bitstuffed data.
 *  bit      0: Whether to use the Orthogonal (0) or Diagonal (1) iterator.
 *  bits 1 - 2: Mode of leveling \c LevelMode.
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdLevelLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
	if (p1 >= MapSize()) return CMD_ERROR;

	/* compute new height */
	int h = TileHeight(p1);
	switch ((LevelMode)GB(p2, 1, 2)) {
		case LM_LEVEL: break;
		case LM_RAISE: h++; break;
		case LM_LOWER: h--; break;
		default: return CMD_ERROR;
	}

	TerraformTilesResult ret;
	if (HasBit(p2, 0)) {
		DiagonalLandLevelingIterator iter(tile, p1, h);
		ret = TerraformTiles(&iter, flags);
	} else {
		OrthogonalLandLevelingIterator iter(TileArea(tile, p1), h);
		ret = TerraformTiles(&iter, flags);
	}

	/* If there were only errors then fail with the last one. */
	if (!ret.had_success && ret.last_error != STR_NULL) return_cmd_error(ret.last_error);
	/* Return overal cost. */
	return CommandCost(EXPENSES_CONSTRUCTION, ret.cost);
}
예제 #8
0
World::World(const QString & world_name) :
		timeStep(0),
		worldName(world_name),
		rwLock(new QReadWriteLock()),
		map(new WorldMap(&world_name)),
		toResetDir(UP)
{
	puts(qPrintable(tr("Loading world settings...")));
	world = this;
	QSettings game_settings("freg.ini", QSettings::IniFormat);
	numShreds = game_settings.value("number_of_shreds", MIN_WORLD_SIZE).
		toLongLong();
	if ( 1 != numShreds%2 ) {
		++numShreds;
		fprintf(stderr, "Invalid number of shreds. Set to %hu.\n",
			numShreds);
	}
	if ( numShreds < MIN_WORLD_SIZE ) {
		fprintf(stderr,
			"Number of shreds: to small: %hu. Set to %hu.\n",
			numShreds, MIN_WORLD_SIZE);
		numShreds = MIN_WORLD_SIZE;
	}
	SetNumActiveShreds(game_settings.value("number_of_active_shreds",
		numShreds).toUInt());
	game_settings.setValue("number_of_shreds", numShreds);
	game_settings.setValue("number_of_active_shreds", numActiveShreds);

	QDir::current().mkpath(worldName+"/texts");
	QSettings settings(worldName+"/settings.ini", QSettings::IniFormat);
	time = settings.value("time", END_OF_NIGHT).toLongLong();
	spawnLongi = settings.value( "spawn_longitude",
		int(qrand() % MapSize()) ).toLongLong();
	spawnLati  = settings.value( "spawn_latitude",
		int(qrand() % MapSize()) ).toLongLong();
	settings.setValue("spawn_longitude", qlonglong(spawnLongi));
	settings.setValue("spawn_latitude", qlonglong(spawnLati));
	longitude = settings.value("longitude", int(spawnLongi)).toLongLong();
	latitude  = settings.value("latitude",  int(spawnLati )).toLongLong();

	shredStorage = new ShredStorage(numShreds+2, longitude, latitude);
	puts(qPrintable(tr("Loading world...")));
	LoadAllShreds();
	emit UpdatedAll();
} // World::World(const QString & world_name)
예제 #9
0
static vec2 DrawGrid( void )
{
    int			x, y;
    int			block;
    int			hits;
    uint32_t	buffer[512];							// Set Up A Selection Buffer
    vec3		v1, v2, v3, v4;
    vec2		cell;

    memset( buffer, 0, sizeof( buffer ) );
    // Tell OpenGL To Use Our Array For Selection
    glSelectBuffer( 512, buffer );
    // Put OpenGL In Selection Mode.
    glRenderMode( GL_SELECT );
    glInitNames();
    glPushName( 0 );
    block = 0;
    glDisable( GL_CULL_FACE );
    for( y = 0; y < MapSize(); y += PT_SIZE ) {
        for( x = 0; x < MapSize(); x += PT_SIZE ) {
            block = x + y * MapSize();
            glLoadName( block );
            v1 = MapPosition( x, y );
            v2 = MapPosition( x, y + PT_SIZE );
            v3 = MapPosition( x + PT_SIZE, y + PT_SIZE );
            v4 = MapPosition( x + PT_SIZE, y );
            glBegin( GL_QUADS );
            glVertex3fv( &v1.x );
            glVertex3fv( &v2.x );
            glVertex3fv( &v3.x );
            glVertex3fv( &v4.x );
            glEnd();
        }
    }

    hits = glRenderMode( GL_RENDER );
    cell.x = cell.y = -1;
    if( hits > 0 ) {
        block = buffer[3];
        cell.x = static_cast<float>(block % MapSize() + PT_HALF);
        cell.y = static_cast<float>(( block - cell.x ) / MapSize() + PT_HALF);

    }
    return cell;
}
예제 #10
0
//--------------------------------------------------------------
string ofxBingQuad::getDeepestQuad(int pixelX, int pixelY, int requestedDepth, int maxDepth){
    
    // quad at requested zoom
    int reqDepth = requestedDepth + levelOfDetail;
    maxLevelOfDetail = maxDepth + levelOfDetail;
    unsigned int mapsize = MapSize(levelOfDetail);
    unsigned int reqMapsize = MapSize(reqDepth);
    int reqX = ofMap(pixelX, 0, mapsize, 0, reqMapsize);
    int reqY = ofMap(pixelY, 0, mapsize, 0, reqMapsize);
    ofVec2f reqTile = PixelXYToTileXY(reqX, reqY);
    string reqQuad = TileXYToQuadKey(reqTile.x, reqTile.y, reqDepth);
    
    // Check nobody on top
    bool found = false;
    bool full = false;
    string emptyQuad;
    while (reqQuad.length()>=levelOfDetail) {
        if (isQuadOccupied(reqQuad)){
            full = true;
            break;
        }
        else if (!found){
            emptyQuad = reqQuad;
            found = true;
        }
        reqQuad = reqQuad.substr(0,reqQuad.length()-1);
    }
    
    if (found){
        if (isQuadOccupiedBelow(emptyQuad)) {
            found = false;
        }
    }

    
    if (full || !found){
        if (reqDepth < maxLevelOfDetail) {
            return getDeepestQuad(pixelX, pixelY, maxDepth, maxDepth);
        } else {
        return "";
        }
    } else {
        return emptyQuad;
    }
}
예제 #11
0
static void Load_MAPH()
{
       SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
       TileIndex size = MapSize();

       for (TileIndex i = 0; i != size;) {
               SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
               for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _main_map.m[i++].height = buf[j];
       }
}
예제 #12
0
파일: command.cpp 프로젝트: Voxar/OpenTTD
/*!
 * This function executes a given command with the parameters from the #CommandProc parameter list.
 * Depending on the flags parameter it execute or test a command.
 *
 * @param tile The tile to apply the command on (for the #CommandProc)
 * @param p1 Additional data for the command (for the #CommandProc)
 * @param p2 Additional data for the command (for the #CommandProc)
 * @param flags Flags for the command and how to execute the command
 * @param cmd The command-id to execute (a value of the CMD_* enums)
 * @param text The text to pass
 * @see CommandProc
 * @return the cost
 */
CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text)
{
	CommandCost res;

	/* Do not even think about executing out-of-bounds tile-commands */
	if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (flags & DC_ALL_TILES) == 0))) return CMD_ERROR;

	/* Chop of any CMD_MSG or other flags; we don't need those here */
	CommandProc *proc = _command_proc_table[cmd & CMD_ID_MASK].proc;

	if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID;

	_docommand_recursive++;

	/* only execute the test call if it's toplevel, or we're not execing. */
	if (_docommand_recursive == 1 || !(flags & DC_EXEC) ) {
		SetTownRatingTestMode(true);
		res = proc(tile, flags & ~DC_EXEC, p1, p2, text);
		SetTownRatingTestMode(false);
		if (CmdFailed(res)) {
			res.SetGlobalErrorMessage();
			goto error;
		}

		if (_docommand_recursive == 1 &&
				!(flags & DC_QUERY_COST) &&
				!(flags & DC_BANKRUPT) &&
				res.GetCost() != 0 &&
				!CheckCompanyHasMoney(res)) {
			goto error;
		}

		if (!(flags & DC_EXEC)) {
			_docommand_recursive--;
			return res;
		}
	}

	/* Execute the command here. All cost-relevant functions set the expenses type
	 * themselves to the cost object at some point */
	res = proc(tile, flags, p1, p2, text);
	if (CmdFailed(res)) {
		res.SetGlobalErrorMessage();
error:
		_docommand_recursive--;
		return CMD_ERROR;
	}

	/* if toplevel, subtract the money. */
	if (--_docommand_recursive == 0 && !(flags & DC_BANKRUPT)) {
		SubtractMoneyFromCompany(res);
	}

	return res;
}
예제 #13
0
static void Save_MAP2()
{
	SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf;
	TileIndex size = MapSize();

	SlSetLength(size * sizeof(uint16));
	for (TileIndex i = 0; i != size;) {
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _main_map.m[i++].m2;
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16);
	}
}
예제 #14
0
static void Save_MAPH()
{
       SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
       TileIndex size = MapSize();

       SlSetLength(size);
       for (TileIndex i = 0; i != size;) {
               for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _main_map.m[i++].height;
                SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
        }
}
예제 #15
0
/**
 * Build a piece of canal.
 * @param tile end tile of stretch-dragging
 * @param flags type of operation
 * @param p1 start tile of stretch-dragging
 * @param p2 waterclass to build. sea and river can only be built in scenario editor
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
	WaterClass wc = Extract<WaterClass, 0, 2>(p2);
	if (p1 >= MapSize() || wc == WATER_CLASS_INVALID) return CMD_ERROR;

	/* Outside of the editor you can only build canals, not oceans */
	if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR;

	TileArea ta(tile, p1);

	/* Outside the editor you can only drag canals, and not areas */
	if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;

	CommandCost cost(EXPENSES_CONSTRUCTION);
	TILE_AREA_LOOP(tile, ta) {
		CommandCost ret;

		Slope slope = GetTileSlope(tile, NULL);
		if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) {
			return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
		}

		/* can't make water of water! */
		if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue;

		ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
		if (ret.Failed()) return ret;
		cost.AddCost(ret);

		if (flags & DC_EXEC) {
			switch (wc) {
				case WATER_CLASS_RIVER:
					MakeRiver(tile, Random());
					break;

				case WATER_CLASS_SEA:
					if (TileHeight(tile) == 0) {
						MakeSea(tile);
						break;
					}
					/* FALL THROUGH */

				default:
					MakeCanal(tile, _current_company, Random());
					break;
			}
			MarkTileDirtyByTile(tile);
			MarkCanalsAndRiversAroundDirty(tile);
		}

		cost.AddCost(_price[PR_BUILD_CANAL]);
	}
예제 #16
0
static void Load_MAP2()
{
	SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf;
	TileIndex size = MapSize();

	for (TileIndex i = 0; i != size;) {
		SlArray(buf, MAP_SL_BUF_SIZE,
			/* In those versions the m2 was 8 bits */
			IsSavegameVersionBefore(5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16
		);
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _main_map.m[i++].m2 = buf[j];
	}
}
예제 #17
0
void MercatorQuadtree::MercatorToPixel(double x, double y, int levelofdetail, int64& outPixelX, int64& outPixelY)
{
   int64 mapsize = MapSize(levelofdetail);

   double normX = (x + 1.0) / (2.0);
   double normY = (y + 1.0) / (2.0);

   outPixelX = (int64) math::Clip<int64>( int64(normX * (mapsize-1) + 0.5), 0, mapsize-1);
   outPixelY = (int64) math::Clip<int64>( int64(normY * (mapsize-1) + 0.5), 0, mapsize-1);

   // convert to pixel coord sys:
   outPixelY = mapsize-1-outPixelY;
}
예제 #18
0
/**
 * Move ourselves to the next tile in the rectange on the map.
 */
TileIterator &DiagonalTileIterator::operator++()
{
	assert(this->tile != INVALID_TILE);

	/* Determine the next tile, while clipping at map borders */
	bool new_line = false;
	do {
		/* Iterate using the rotated coordinates. */
		if (this->a_max == 1 || this->a_max == -1) {
			/* Special case: Every second column has zero length, skip them completely */
			this->a_cur = 0;
			if (this->b_max > 0) {
				this->b_cur = min(this->b_cur + 2, this->b_max);
			} else {
				this->b_cur = max(this->b_cur - 2, this->b_max);
			}
		} else {
			/* Every column has at least one tile to process */
			if (this->a_max > 0) {
				this->a_cur += 2;
				new_line = this->a_cur >= this->a_max;
			} else {
				this->a_cur -= 2;
				new_line = this->a_cur <= this->a_max;
			}
			if (new_line) {
				/* offset of initial a_cur: one tile in the same direction as a_max
				 * every second line.
				 */
				this->a_cur = abs(this->a_cur) % 2 ? 0 : (this->a_max > 0 ? 1 : -1);

				if (this->b_max > 0) {
					++this->b_cur;
				} else {
					--this->b_cur;
				}
			}
		}

		/* And convert the coordinates back once we've gone to the next tile. */
		uint x = this->base_x + (this->a_cur - this->b_cur) / 2;
		uint y = this->base_y + (this->b_cur + this->a_cur) / 2;
		/* Prevent wrapping around the map's borders. */
		this->tile = x >= MapSizeX() || y >= MapSizeY() ? INVALID_TILE : TileXY(x, y);
	} while (this->tile > MapSize() && this->b_max != this->b_cur);

	if (this->b_max == this->b_cur) this->tile = INVALID_TILE;
	return *this;
}
예제 #19
0
/**
 * Finds the distance for the closest tile with water/land given a tile
 * @param tile  the tile to find the distance too
 * @param water whether to find water or land
 * @return distance to nearest water (max 0x7F) / land (max 0x1FF; 0x200 if there is no land)
 */
uint GetClosestWaterDistance(TileIndex tile, bool water)
{
	if (HasTileWaterGround(tile) == water) return 0;

	uint max_dist = water ? 0x7F : 0x200;

	int x = TileX(tile);
	int y = TileY(tile);

	uint max_x = MapMaxX();
	uint max_y = MapMaxY();
	uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;

	/* go in a 'spiral' with increasing manhattan distance in each iteration */
	for (uint dist = 1; dist < max_dist; dist++) {
		/* next 'diameter' */
		y--;

		/* going counter-clockwise around this square */
		for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
			static const int8 ddx[DIAGDIR_END] = { -1,  1,  1, -1};
			static const int8 ddy[DIAGDIR_END] = {  1,  1, -1, -1};

			int dx = ddx[dir];
			int dy = ddy[dir];

			/* each side of this square has length 'dist' */
			for (uint a = 0; a < dist; a++) {
				/* MP_VOID tiles are not checked (interval is [min; max) for IsInsideMM())*/
				if (IsInsideMM(x, min_xy, max_x) && IsInsideMM(y, min_xy, max_y)) {
					TileIndex t = TileXY(x, y);
					if (HasTileWaterGround(t) == water) return dist;
				}
				x += dx;
				y += dy;
			}
		}
	}

	if (!water) {
		/* no land found - is this a water-only map? */
		for (TileIndex t = 0; t < MapSize(); t++) {
			if (!IsTileType(t, MP_VOID) && !IsTileType(t, MP_WATER)) return 0x1FF;
		}
	}

	return max_dist;
}
예제 #20
0
/**
 * Return the slope of a given tile inside the map.
 * @param tile Tile to compute slope of
 * @param h    If not \c NULL, pointer to storage of z height
 * @return Slope of the tile, except for the HALFTILE part
 */
Slope GetTileSlope(TileIndex tile, int *h)
{
	assert(tile < MapSize());

	if (!IsInnerTile(tile)) {
		if (h != NULL) *h = TileHeight(tile);
		return SLOPE_FLAT;
	}

	int hnorth = TileHeight(tile);                    // Height of the North corner.
	int hwest  = TileHeight(tile + TileDiffXY(1, 0)); // Height of the West corner.
	int heast  = TileHeight(tile + TileDiffXY(0, 1)); // Height of the East corner.
	int hsouth = TileHeight(tile + TileDiffXY(1, 1)); // Height of the South corner.

	return GetTileSlopeGivenHeight(hnorth, hwest, heast, hsouth, h);
}
예제 #21
0
/**
 * Check if a given tile is flat
 * @param tile Tile to check
 * @param h If not \c NULL, pointer to storage of z height (only if tile is flat)
 * @return Whether the tile is flat
 */
bool IsTileFlat(TileIndex tile, int *h)
{
	assert(tile < MapSize());

	if (!IsInnerTile(tile)) {
		if (h != NULL) *h = TileHeight(tile);
		return true;
	}

	uint z = TileHeight(tile);
	if (TileHeight(tile + TileDiffXY(1, 0)) != z) return false;
	if (TileHeight(tile + TileDiffXY(0, 1)) != z) return false;
	if (TileHeight(tile + TileDiffXY(1, 1)) != z) return false;

	if (h != NULL) *h = z;
	return true;
}
예제 #22
0
static void Load_MAPT()
{
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
	TileIndex size = MapSize();

	for (TileIndex i = 0; i != size;) {
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _main_map.m[i++].type = buf[j];
	}

       if (IsSavegameVersionBefore(MORE_HEIGHTLEVEL_SAVEGAME_VERSION)) {
               // In old savegame versions, the heightlevel was coded in bits 0..3 of the type field
               for (TileIndex tile = 0; tile != size; tile++) {
                       _main_map.m[tile].height = GB(_main_map.m[tile].type, 0, 4);
               }
        }
}
예제 #23
0
bool MapContainsSameKeys(const Map *map1, const Map *map2)
{
    assert(map1 != NULL);
    assert(map2 != NULL);

    MapIterator i = MapIteratorInit((Map *)map1);
    MapKeyValue *item;
    size_t count = 0;
    while ((item = MapIteratorNext(&i)))
    {
        count++;
        if (!MapHasKey(map2, item->key))
        {
            return false;
        }
    }
    return (count == MapSize(map2));
}
예제 #24
0
void AfterLoadLabelMaps()
{
	if (NeedRailTypeConversion()) {
		SmallVector<RailType, RAILTYPE_END> railtype_conversion_map;

		for (uint i = 0; i < _railtype_list.Length(); i++) {
			RailType r = GetRailTypeByLabel(_railtype_list[i]);
			if (r == INVALID_RAILTYPE) r = RAILTYPE_BEGIN;

			*railtype_conversion_map.Append() = r;
		}

		for (TileIndex t = 0; t < MapSize(); t++) {
			switch (GetTileType(t)) {
				case MP_RAILWAY:
					SetRailType(t, railtype_conversion_map[GetRailType(t)]);
					break;

				case MP_ROAD:
					if (IsLevelCrossing(t)) {
						SetRailType(t, railtype_conversion_map[GetRailType(t)]);
					}
					break;

				case MP_STATION:
					if (HasStationRail(t)) {
						SetRailType(t, railtype_conversion_map[GetRailType(t)]);
					}
					break;

				case MP_TUNNELBRIDGE:
					if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
						SetRailType(t, railtype_conversion_map[GetRailType(t)]);
					}
					break;

				default:
					break;
			}
		}
	}

	_railtype_list.Clear();
}
예제 #25
0
파일: water_cmd.cpp 프로젝트: Voxar/OpenTTD
/** Build a piece of canal.
 * @param tile end tile of stretch-dragging
 * @param flags type of operation
 * @param p1 start tile of stretch-dragging
 * @param p2 specifies canal (0), water (1) or river (2); last two can only be built in scenario editor
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
	CommandCost cost(EXPENSES_CONSTRUCTION);

	if (p1 >= MapSize()) return CMD_ERROR;

	/* Outside of the editor you can only build canals, not oceans */
	if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR;

	TileArea ta(tile, p1);

	/* Outside the editor you can only drag canals, and not areas */
	if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;

	TILE_AREA_LOOP(tile, ta) {
		CommandCost ret;

		Slope slope = GetTileSlope(tile, NULL);
		if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
			return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
		}

		/* can't make water of water! */
		if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue;

		ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
		if (CmdFailed(ret)) return ret;
		cost.AddCost(ret);

		if (flags & DC_EXEC) {
			if (TileHeight(tile) == 0 && p2 == 1) {
				MakeSea(tile);
			} else if (p2 == 2) {
				MakeRiver(tile, Random());
			} else {
				MakeCanal(tile, _current_company, Random());
			}
			MarkTileDirtyByTile(tile);
			MarkCanalsAndRiversAroundDirty(tile);
		}

		cost.AddCost(_price[PR_CLEAR_WATER]);
	}
예제 #26
0
파일: tile_map.cpp 프로젝트: Ayutac/OpenTTD
/**
 * Return the slope of a given tile
 * @param tile Tile to compute slope of
 * @param h    If not \c NULL, pointer to storage of z height
 * @return Slope of the tile, except for the HALFTILE part
 */
Slope GetTileSlope(TileIndex tile, int *h)
{
	assert(tile < MapSize());

	uint x = TileX(tile);
	uint y = TileY(tile);

	if (x == MapMaxX() || y == MapMaxY() ||
			((x == 0 || y == 0) && _settings_game.construction.freeform_edges)) {
		if (h != NULL) *h = TileHeight(tile);
		return SLOPE_FLAT;
	}

	int a = TileHeight(tile); // Height of the N corner
	int min = a; // Minimal height of all corners examined so far
	int b = TileHeight(tile + TileDiffXY(1, 0)); // Height of the W corner
	if (min > b) min = b;
	int c = TileHeight(tile + TileDiffXY(0, 1)); // Height of the E corner
	if (min > c) min = c;
	int d = TileHeight(tile + TileDiffXY(1, 1)); // Height of the S corner
	if (min > d) min = d;

	/* Due to the fact that tiles must connect with each other without leaving gaps, the
	 * biggest difference in height between any corner and 'min' is between 0, 1, or 2.
	 *
	 * Also, there is at most 1 corner with height difference of 2.
	 */

	uint r = SLOPE_FLAT; // Computed slope of the tile

	/* For each corner if not equal to minimum height:
	 *  - set the SLOPE_STEEP flag if the difference is 2
	 *  - add the corresponding SLOPE_X constant to the computed slope
	 */
	if ((a -= min) != 0) r += (--a << 4) + SLOPE_N;
	if ((c -= min) != 0) r += (--c << 4) + SLOPE_E;
	if ((d -= min) != 0) r += (--d << 4) + SLOPE_S;
	if ((b -= min) != 0) r += (--b << 4) + SLOPE_W;

	if (h != NULL) *h = min;

	return (Slope)r;
}
예제 #27
0
static void Load_MAP6()
{
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
	TileIndex size = MapSize();

	if (IsSavegameVersionBefore(42)) {
		for (TileIndex i = 0; i != size;) {
			/* 1024, otherwise we overflow on 64x64 maps! */
			SlArray(buf, 1024, SLE_UINT8);
			for (uint j = 0; j != 1024; j++) {
				_main_map.me[i++].m6 = GB(buf[j], 0, 2);
				_main_map.me[i++].m6 = GB(buf[j], 2, 2);
				_main_map.me[i++].m6 = GB(buf[j], 4, 2);
				_main_map.me[i++].m6 = GB(buf[j], 6, 2);
			}
		}
	} else {
		for (TileIndex i = 0; i != size;) {
			SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
			for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _main_map.me[i++].m6 = buf[j];
		}
	}
}
예제 #28
0
/** Make a screenshot of the whole map. */
static bool MakeWorldScreenshot()
{
	ViewPort vp;
	const ScreenshotFormat *sf;

	/* We need to account for a hill or high building at tile 0,0. */
	int extra_height_top = TilePixelHeight(0) + 150;
	/* If there is a hill at the bottom don't create a large black area. */
	int reclaim_height_bottom = TilePixelHeight(MapSize() - 1);

	vp.zoom = ZOOM_LVL_WORLD_SCREENSHOT;
	vp.left = 0;
	vp.top = 0;
	vp.virtual_left = -(int)MapMaxX() * TILE_PIXELS * ZOOM_LVL_BASE;
	vp.virtual_top = -extra_height_top * ZOOM_LVL_BASE;
	vp.virtual_width = (MapMaxX() + MapMaxY()) * TILE_PIXELS;
	vp.width = vp.virtual_width;
	vp.virtual_height = ((MapMaxX() + MapMaxY()) * TILE_PIXELS >> 1) + extra_height_top - reclaim_height_bottom;
	vp.height = vp.virtual_height;

	sf = _screenshot_formats + _cur_screenshot_format;
	return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), LargeWorldCallback, &vp, vp.width, vp.height,
			BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette);
}
예제 #29
0
파일: command.cpp 프로젝트: Voxar/OpenTTD
/*!
 * Toplevel network safe docommand function for the current company. Must not be called recursively.
 * The callback is called when the command succeeded or failed. The parameters
 * tile, p1 and p2 are from the #CommandProc function. The paramater cmd is the command to execute.
 * The parameter my_cmd is used to indicate if the command is from a company or the server.
 *
 * @param tile The tile to perform a command on (see #CommandProc)
 * @param p1 Additional data for the command (see #CommandProc)
 * @param p2 Additional data for the command (see #CommandProc)
 * @param cmd The command to execute (a CMD_* value)
 * @param callback A callback function to call after the command is finished
 * @param text The text to pass
 * @param my_cmd indicator if the command is from a company or server (to display error messages for a user)
 * @return true if the command succeeded, else false
 */
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd)
{
	assert(_docommand_recursive == 0);

	CommandCost res, res2;

	int x = TileX(tile) * TILE_SIZE;
	int y = TileY(tile) * TILE_SIZE;

	_error_message = INVALID_STRING_ID;
	StringID error_part1 = GB(cmd, 16, 16);
	_additional_cash_required = 0;

	/* get pointer to command handler */
	byte cmd_id = cmd & CMD_ID_MASK;
	assert(cmd_id < lengthof(_command_proc_table));

	CommandProc *proc = _command_proc_table[cmd_id].proc;
	if (proc == NULL) return false;

	/* Command flags are used internally */
	uint cmd_flags = GetCommandFlags(cmd);
	/* Flags get send to the DoCommand */
	DoCommandFlag flags = CommandFlagsToDCFlags(cmd_flags);

	/* Do not even think about executing out-of-bounds tile-commands */
	if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (cmd_flags & CMD_ALL_TILES) == 0))) return false;

	/* Always execute server and spectator commands as spectator */
	if (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) _current_company = COMPANY_SPECTATOR;

	CompanyID old_company = _current_company;

	/* If the company isn't valid it may only do server command or start a new company!
	 * The server will ditch any server commands a client sends to it, so effectively
	 * this guards the server from executing functions for an invalid company. */
	if (_game_mode == GM_NORMAL && (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) == 0 && !Company::IsValidID(_current_company)) {
		if (my_cmd) ShowErrorMessage(error_part1, _error_message, x, y);
		return false;
	}

	bool notest = (cmd_flags & CMD_NO_TEST) != 0;

	_docommand_recursive = 1;

	/* cost estimation only? */
	if (!IsGeneratingWorld() &&
			_shift_pressed &&
			IsLocalCompany() &&
			!(cmd & CMD_NETWORK_COMMAND) &&
			cmd_id != CMD_PAUSE) {
		/* estimate the cost. */
		SetTownRatingTestMode(true);
		res = proc(tile, flags, p1, p2, text);
		SetTownRatingTestMode(false);
		if (CmdFailed(res)) {
			res.SetGlobalErrorMessage();
			ShowErrorMessage(error_part1, _error_message, x, y);
		} else {
			ShowEstimatedCostOrIncome(res.GetCost(), x, y);
		}

		_docommand_recursive = 0;
		ClearStorageChanges(false);
		return false;
	}


	if (!((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
		/* first test if the command can be executed. */
		SetTownRatingTestMode(true);
		res = proc(tile, flags, p1, p2, text);
		SetTownRatingTestMode(false);
		assert(cmd_id == CMD_COMPANY_CTRL || old_company == _current_company);
		if (CmdFailed(res)) {
			res.SetGlobalErrorMessage();
			goto show_error;
		}
		/* no money? Only check if notest is off */
		if (!notest && res.GetCost() != 0 && !CheckCompanyHasMoney(res)) goto show_error;
	}

#ifdef ENABLE_NETWORK
	/*
	 * If we are in network, and the command is not from the network
	 * send it to the command-queue and abort execution
	 */
	if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
		NetworkSend_Command(tile, p1, p2, cmd & ~CMD_FLAGS_MASK, callback, text);
		_docommand_recursive = 0;
		ClearStorageChanges(false);
		return true;
	}
#endif /* ENABLE_NETWORK */
	DEBUG(desync, 1, "cmd: %08x; %08x; %1x; %06x; %08x; %08x; %04x; %s\n", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text);

	/* update last build coordinate of company. */
	if (tile != 0) {
		Company *c = Company::GetIfValid(_current_company);
		if (c != NULL) c->last_build_coordinate = tile;
	}

	/* Actually try and execute the command. If no cost-type is given
	 * use the construction one */
	res2 = proc(tile, flags | DC_EXEC, p1, p2, text);

	assert(cmd_id == CMD_COMPANY_CTRL || old_company == _current_company);

	/* If notest is on, it means the result of the test can be different than
	 *  the real command.. so ignore the test */
	if (!notest && !((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
		assert(res.GetCost() == res2.GetCost() && CmdFailed(res) == CmdFailed(res2)); // sanity check
	} else {
		if (CmdFailed(res2)) {
			res2.SetGlobalErrorMessage();
			goto show_error;
		}
	}

	SubtractMoneyFromCompany(res2);

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

	if (IsLocalCompany() && _game_mode != GM_EDITOR) {
		if (res2.GetCost() != 0 && tile != 0) ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2.GetCost());
		if (_additional_cash_required != 0) {
			SetDParam(0, _additional_cash_required);
			if (my_cmd) ShowErrorMessage(error_part1, STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY, x, y);
			if (res2.GetCost() == 0) goto callb_err;
		}
	}

	_docommand_recursive = 0;

	if (callback) callback(true, tile, p1, p2);
	ClearStorageChanges(true);
	return true;

show_error:
	/* show error message if the command fails? */
	if (IsLocalCompany() && error_part1 != 0 && my_cmd) {
		ShowErrorMessage(error_part1, _error_message, x, y);
	}

callb_err:
	_docommand_recursive = 0;

	if (callback) callback(false, tile, p1, p2);
	ClearStorageChanges(false);
	return false;
}
예제 #30
0
파일: set.c 프로젝트: lpefferkorn/core
size_t SetSize(const Set *set)
{
    return MapSize(set);
}