/** * 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--; } }
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 ); }
//-------------------------------------------------------------- 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); }
/** * 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(); }
/** * 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; }
/** * 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(); }
/** * 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); }
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)
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; }
//-------------------------------------------------------------- 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; } }
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]; } }
/*! * 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; }
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); } }
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); } }
/** * 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]); }
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]; } }
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; }
/** * 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; }
/** * 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; }
/** * 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); }
/** * 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; }
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); } } }
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)); }
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(); }
/** 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]); }
/** * 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; }
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]; } } }
/** 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); }
/*! * 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; }
size_t SetSize(const Set *set) { return MapSize(set); }