/* $Id: copy_paste.c 6400 2006-09-05 20:32:58Z richk $ */ #include "stdafx.h" #include "openttd.h" #include "table/sprites.h" #include "table/strings.h" #include "functions.h" #include "player.h" #include "tile.h" #include "window.h" #include "gui.h" #include "viewport.h" #include "gfx.h" #include "sound.h" #include "command.h" #include "vehicle.h" #include "tunnel_map.h" #include "bridge_map.h" #include "npf.h" #include "waypoint.h" #include "variables.h" #include "debug.h" #include "depot.h" #include "network.h" #include "command_queue.h" //Internal vars static int32 _paste_costs = 0; /* Copy&Paste Variable setup functions */ bool IsSomethingCopied(void) { return !((_copy_width == 0) || (_copy_height == 0)); } void ClearCopyArrays(uint32 w, uint32 h) { uint32 index = 0; //Reset terrainmap for (index = 0; index < (w * h); index++) { _copy_heightmap[index] = 0; _copy_terrain_needed[index] = 0; } //Reset buildings for (index = 0; index < ((w - 1) * (h - 1)); index++) { _copy_rail[index] = 0; _copy_tunnel[index] = 0; _copy_signals[index] = 0; _copy_road[index] = 0; _copy_bridge[index] = 0; _copy_depot[index] = 0; } } /* Copy&Paste Helper functions. Mainly the same, just without sound */ static void CP_DoCommand(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd) { if (_shift_pressed) { int32 res = DoCommand(tile, p1, p2, DC_FORCETEST | DC_QUERY_COST, cmd & 0xFF); if (res != CMD_ERROR) _paste_costs += res; } else { #ifdef ENABLE_NETWORK if (_networking) { if (_paste_dryrun) _paste_command_estimate++; else QueueCommand(tile, p1, p2, callback, cmd); } else #endif /* ENABLE_NETWORK */ DoCommandP(tile, p1, p2, callback, cmd); } } static void CP_RaiseLowerLand(TileIndex tile, int mode) { if (mode) { CP_DoCommand(tile, 8, (uint32)mode, NULL, CMD_TERRAFORM_LAND | CMD_AUTO | CMD_MSG(STR_0808_CAN_T_RAISE_LAND_HERE)); } else { CP_DoCommand(tile, 8, (uint32)mode, NULL, CMD_TERRAFORM_LAND | CMD_AUTO | CMD_MSG(STR_0809_CAN_T_LOWER_LAND_HERE)); } } static void CP_PlaceRail(TileIndex tile, int cmd, uint32 railtype) { CP_DoCommand(tile, railtype, cmd, NULL, CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK) | CMD_AUTO | CMD_NO_WATER ); } static void CP_PlaceSignals(TileIndex tile, uint8 position, bool ctrl) { CP_DoCommand(tile, position + (ctrl ? 8 : 0), 0, NULL, CMD_BUILD_SIGNALS | CMD_AUTO | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE)); } static void CP_PlaceRoad(TileIndex tile, uint8 road_flag) { CP_DoCommand(tile, road_flag, 0, NULL, CMD_BUILD_ROAD | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1804_CAN_T_BUILD_ROAD_HERE)); } static void CP_PlaceRail_Tunnel(TileIndex tile, uint32 railtype) { CP_DoCommand(tile, railtype, 0, NULL, CMD_BUILD_TUNNEL | CMD_AUTO | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE)); } static void CP_PlaceRoad_Tunnel(TileIndex tile) { CP_DoCommand(tile, 0x200, 0, NULL, CMD_BUILD_TUNNEL | CMD_AUTO | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE)); } static void CP_Build_Bridge(TileIndex start, TileIndex end, uint8 bridgetype, uint8 transport_type, uint8 railtype) { //debug("bt: %u, tt: %u, rt: %u", bridgetype, transport_type, railtype); CP_DoCommand(end, start, bridgetype | (railtype << 8) | (transport_type << 15), NULL, CMD_BUILD_BRIDGE | CMD_AUTO | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE)); } static void CP_PlaceRail_Depot(TileIndex tile, uint8 railtype, uint8 direction) { CP_DoCommand(tile, railtype, direction, NULL, CMD_BUILD_TRAIN_DEPOT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_100E_CAN_T_BUILD_TRAIN_DEPOT)); } static void CP_PlaceRoad_Depot(TileIndex tile, uint8 directions) { CP_DoCommand(tile, directions, 0, NULL, CMD_BUILD_ROAD | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1804_CAN_T_BUILD_ROAD_HERE)); } static void CP_PlaceWaypoint(TileIndex tile, uint8 waypoint_type) { CP_DoCommand(tile, waypoint_type, 0, NULL, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT)); } static void CP_ClearTile(TileIndex start_tile, TileIndex end_tile) { CP_DoCommand(start_tile, end_tile, 0, NULL, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA)); } static int8 ClampToRight(TileIndex index, int8 baseh, int8 h_tile) { int8 h_right = baseh + _copy_heightmap[index - 1]; if (h_tile > (h_right + 1)) { h_tile = h_right + 1; } else if (h_tile < (h_right - 1)) { h_tile = h_right - 1; } return h_tile; } static int8 ClampToUp(TileIndex index, int8 baseh, int8 h_tile, int32 size_x) { int8 h_up = baseh + _copy_heightmap[index - size_x]; if (h_tile > (h_up + 1)) { h_tile = h_up + 1; } else if (h_tile < (h_up - 1)) { h_tile = h_up - 1; } return h_tile; } /** * Game command which pastes the copied content **/ static void PasteArea(TileIndex tile, bool pasteVacantTerrain, bool convertRail, bool clearBeforeBuild, bool toggleSignalDirection) { int8 baseh; TileIndex index = 0; int8 count, h_diff, h_tile; int32 size_x, size_y; bool success = true; bool bridge_error; TileIndex sx = TileX(tile); TileIndex sy = TileY(tile); TileIndex ex = sx + _copy_width; TileIndex ey = sy + _copy_height; uint8 storelocation; //tmp for loading signals TileIndex tmp_tile; //tmp for loading bridges uint16 tmpSignal; //tmp for signal direction TileIndex i; if (_shift_pressed) { _paste_costs = 0; } //Nothing copied? return if ((_copy_width <= 0) || (_copy_height <= 0)) return; //Copy out of map? return if ((ex >= MapSizeX()) || (ey >= MapSizeY())) return; size_x = _copy_width; size_y = _copy_height; //Base level is from first tile. baseh = (int8)TileHeight(tile); //bulldoze tiles which will be built on if (clearBeforeBuild) { index = 0; BEGIN_TILE_LOOP(tile, size_x - 1, size_y - 1, TileXY(sx, sy)) { if ((_copy_tunnel[index] & (1U << 7)) > 0) { CP_ClearTile(tile, tile); } index++; } END_TILE_LOOP(tile, size_x - 1, size_y - 1, 0); } //restore terrain index = 0; BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) { if (((_copy_terrain_needed[index] & 1U) > 0) || (pasteVacantTerrain)) { //Only do calculations if we are networking. #ifdef ENABLE_NETWORK if (_networking) { h_tile = (int8)TileHeight(tile); if ((h_cur != size_y) && (w_cur != size_x)) { //Look NE and NW... h_tile = ClampToRight(index, baseh, h_tile); h_tile = ClampToUp(index, baseh, h_tile, size_x); //use clamped height instead of actual height h_diff = baseh - h_tile + _copy_heightmap[index]; } else { if ((h_cur == size_y) && (w_cur == size_x)) { //First Tile is always at baseh... h_diff = baseh - ((int8)TileHeight(tile)) + _copy_heightmap[index]; } else if (w_cur == size_x) { //Right Border, clamp to upper tile h_tile = ClampToUp(index, baseh, h_tile, size_x); h_diff = baseh - h_tile + _copy_heightmap[index]; } else { //Upper Border, clamp to right h_tile = ClampToRight(index, baseh, h_tile); h_diff = baseh - h_tile + _copy_heightmap[index]; } } } else #endif /* ENABLE_NETWORK */ h_diff = baseh - ((int8)TileHeight(tile)) + _copy_heightmap[index]; if (h_diff > 0) { for (count = 0; count < h_diff; count++) CP_RaiseLowerLand(tile, 1); } else if (h_diff < 0) { for (count = h_diff; count < 0; count++) CP_RaiseLowerLand(tile, 0); } } index++; } END_TILE_LOOP(tile, size_x, size_y, 0); //Restore Rail, Depot, Tunnel, Road, Bridge: index = 0; BEGIN_TILE_LOOP(tile, size_x - 1, size_y - 1, TileXY(sx, sy)) { //Railway Tracks: if ((_copy_rail[index] & (1U << TRACK_X))>0) CP_PlaceRail(tile, TRACK_X, convertRail ? _cur_railtype : ((_copy_rail[index] >> 6) & 3U) ); if ((_copy_rail[index] & (1U << TRACK_Y))>0) CP_PlaceRail(tile, TRACK_Y, convertRail ? _cur_railtype : ((_copy_rail[index] >> 6) & 3U) ); if ((_copy_rail[index] & (1U << TRACK_UPPER))>0) CP_PlaceRail(tile, TRACK_UPPER, convertRail ? _cur_railtype : ((_copy_rail[index] >> 6) & 3U) ); if ((_copy_rail[index] & (1U << TRACK_LOWER))>0) CP_PlaceRail(tile, TRACK_LOWER, convertRail ? _cur_railtype : ((_copy_rail[index] >> 6) & 3U) ); if ((_copy_rail[index] & (1U << TRACK_LEFT))>0) CP_PlaceRail(tile, TRACK_LEFT, convertRail ? _cur_railtype : ((_copy_rail[index] >> 6) & 3U) ); if ((_copy_rail[index] & (1U << TRACK_RIGHT))>0) CP_PlaceRail(tile, TRACK_RIGHT, convertRail ? _cur_railtype : ((_copy_rail[index] >> 6) & 3U) ); //Depots: if ((_copy_depot[index] & 1U) > 0) { if ((_copy_depot[index] & (1U << 1)) > 0) CP_PlaceRoad_Depot(tile, ((_copy_depot[index] >> 2) & 3U)); else CP_PlaceRail_Depot(tile, convertRail ? _cur_railtype : ((_copy_rail[index] >> 6) & 3U), ((_copy_depot[index] >> 2) & 3U)); } //Tunnels: if ((_copy_tunnel[index] & 1U) > 0) { //TODO check if tunnel end will be at right place (=inside area) //Same check as bridge? move into tunneldir, until tunneltile reached if (((_copy_tunnel[index] >> 4) & 1U) > 0) { if (((_copy_tunnel[index] >> 3) & 1U) > 0) CP_PlaceRoad_Tunnel(tile); else CP_PlaceRail_Tunnel(tile, convertRail ? _cur_railtype : ((_copy_rail[index] >> 6) & 3U) ); } } //Road: if (_copy_road[index] > 0) CP_PlaceRoad(tile, _copy_road[index]); //Bridges: if (((_copy_bridge[index] >> 4) & 1U) > 0) { //There is a bridge start here, find the other side bridge_error = false; tmp_tile = tile; switch ((_copy_bridge[index] >> 1) & 3U) { case DIAGDIR_NE: //-X i=1; while (((_copy_bridge[index - i] & 1U) == 0) && ((TileX(tile) - i) >= sx)) i++; if ((TileX(tile) - i) < sx) bridge_error = true; else tmp_tile += TileDiffXY(0 - i, 0); break; case DIAGDIR_SW: //+X i=1; while (((_copy_bridge[index + i] & 1U) == 0) && ((TileX(tile) + i) < (sx + size_x - 1))) i++; if ((TileX(tile) + i) >= (sx + size_x - 1)) bridge_error = true; else tmp_tile += TileDiffXY(+i, 0); break; case DIAGDIR_SE: //+Y i=1; while (((_copy_bridge[index + (i * (size_x - 1))] & 1U) == 0) && ((TileY(tile) + i) < (sy + size_y - 1))) i++; if ((TileY(tile) + i) >= (sy + size_y - 1)) bridge_error = true; else tmp_tile += TileDiffXY(0, +i); break; case DIAGDIR_NW: //-Y i=1; while (((_copy_bridge[index - (i * (size_x - 1))] & 1U) == 0) && ((TileY(tile) - i) >= sy)) i++; if ((TileY(tile) - i) < sy) bridge_error = true; else tmp_tile += TileDiffXY(0, 0 - i); break; } if (!bridge_error) CP_Build_Bridge(tile, tmp_tile, (_copy_bridge[index] >> 8), ((_copy_bridge[index] >> 3) & 1U), convertRail ? _cur_railtype : ((_copy_rail[index] >> 6) & 3U) ); } index++; } END_TILE_LOOP(tile, size_x - 1, size_y - 1, 0); //Restore Signals and Waypoints (Seperated because they depend on underlying track) index = 0; BEGIN_TILE_LOOP(tile, size_x - 1, size_y - 1, TileXY(sx, sy)) { //Waypoint: if ((_copy_depot[index] & (1U << 7)) > 0) { CP_PlaceWaypoint(tile, ((_copy_depot[index] >> 1) & 63U)); } //Signals: tmpSignal = _copy_signals[index]; if (toggleSignalDirection) { if (((tmpSignal >> 6) & 3U) > 0) { TOGGLEBIT(tmpSignal, 6); TOGGLEBIT(tmpSignal, 7); } if (((tmpSignal >> 8) & 3U) > 0) { TOGGLEBIT(tmpSignal, 8); TOGGLEBIT(tmpSignal, 9); } } storelocation = 6; if ((tmpSignal & (1U << TRACK_X))>0) { //debug("Build Signal on TRACK_X"); //Restore Signal + semaphore CP_PlaceSignals(tile, TRACK_X, ((tmpSignal & (1U << 10))>0)); for (i = 0; i < ((tmpSignal >> storelocation) & 3U); i++) CP_PlaceSignals(tile, TRACK_X, false); //Restore signaltype, if not already restored... if (storelocation == 6) for (i = 0; i < ((tmpSignal >> 11) & 7U); i++) CP_PlaceSignals(tile, TRACK_X, true); storelocation = 8; } if ((tmpSignal & (1U << TRACK_Y))>0) { //debug("Build Signal on TRACK_Y"); //Restore Signal + semaphore CP_PlaceSignals(tile, TRACK_Y, ((tmpSignal & (1U << 10))>0)); for (i = 0; i < ((tmpSignal >> storelocation) & 3U); i++) CP_PlaceSignals(tile, TRACK_Y, false); //Restore signaltype if (storelocation == 6) for (i = 0; i < ((tmpSignal >> 11) & 7U); i++) CP_PlaceSignals(tile, TRACK_Y, true); storelocation = 8; } if ((tmpSignal & (1U << TRACK_UPPER))>0) { //debug("Build Signal on TRACK_UPPER"); //Restore Signal + semaphore CP_PlaceSignals(tile, TRACK_UPPER, ((tmpSignal & (1U << 10))>0)); for (i = 0; i < ((tmpSignal >> storelocation) & 3U); i++) CP_PlaceSignals(tile, TRACK_UPPER, false); //Restore signaltype if (storelocation == 6) for (i = 0; i < ((tmpSignal >> 11) & 7U); i++) CP_PlaceSignals(tile, TRACK_UPPER, true); storelocation = 8; } if ((tmpSignal & (1U << TRACK_LOWER))>0) { //debug("Build Signal on TRACK_LOWER"); //Restore Signal + semaphore CP_PlaceSignals(tile, TRACK_LOWER, ((tmpSignal & (1U << 10))>0)); for (i = 0; i < ((tmpSignal >> storelocation) & 3U); i++) CP_PlaceSignals(tile, TRACK_LOWER, false); //Restore signaltype if (storelocation == 6) for (i = 0; i < ((tmpSignal >> 11) & 7U); i++) CP_PlaceSignals(tile, TRACK_LOWER, true); storelocation = 8; } if ((tmpSignal & (1U << TRACK_LEFT))>0) { //debug("Build Signal on TRACK_LEFT"); //Restore Signal + semaphore CP_PlaceSignals(tile, TRACK_LEFT, ((tmpSignal & (1U << 10))>0)); for (i = 0; i < ((tmpSignal >> storelocation) & 3U); i++) CP_PlaceSignals(tile, TRACK_LEFT, false); //Restore signaltype if (storelocation == 6) for (i = 0; i < ((tmpSignal >> 11) & 7U); i++) CP_PlaceSignals(tile, TRACK_LEFT, true); storelocation = 8; } if ((tmpSignal & (1U << TRACK_RIGHT))>0) { //debug("Build Signal on TRACK_RIGHT"); //Restore Signal + semaphore CP_PlaceSignals(tile, TRACK_RIGHT, ((tmpSignal & (1U << 10))>0)); for (i = 0; i < ((tmpSignal >> storelocation) & 3U); i++) CP_PlaceSignals(tile, TRACK_RIGHT, false); //Restore signaltype if (storelocation == 6) for (i = 0; i < ((tmpSignal >> 11) & 7U); i++) CP_PlaceSignals(tile, TRACK_RIGHT, true); storelocation = 8; } index++; } END_TILE_LOOP(tile, size_x - 1, size_y - 1, 0); if (_shift_pressed) { ShowEstimatedCostOrIncome(_paste_costs, 100, 100); } else { if (success) SndPlayTileFx(SND_1F_SPLAT, tile); } } /** * Safe Paste Command. Checks CommandQueue in network games **/ void SafePasteArea(TileIndex tile, bool pasteVacantTerrain, bool convertRail, bool clearBeforeBuild, bool toggleSignalDirection) { #ifdef ENABLE_NETWORK if (_networking) { _paste_command_estimate = 0; _paste_dryrun = true; PasteArea(tile, pasteVacantTerrain, convertRail, clearBeforeBuild, toggleSignalDirection); _paste_dryrun = false; //debug("CQ_estimate: %u", _paste_command_estimate); //debug("CQ_remaining: %u", GetRemainingQueueSpace()); //CommandCount is stored in _command_queue_estimate, check queue space if (_paste_command_estimate <= GetRemainingQueueSpace()) { PasteArea(tile, pasteVacantTerrain, convertRail, clearBeforeBuild, toggleSignalDirection); //debug("CQ_size: %u", _command_queue_size); } else { //Warning message...CommandQueue full, command aborted debug("Command Queue full!"); } } else #endif /* ENABLE_NETWORK */ PasteArea(tile, pasteVacantTerrain, convertRail, clearBeforeBuild, toggleSignalDirection); } /** * Indicates this tile needs to be terraformed, in order to restore some building. * Bit 0 indicates this tile is needed for terraforming, * but is not directly build on. * Bit 1 indicates this tile is beeing built on. **/ static void TerrainNeededAroundTile(TileIndex tindex, TileIndex bindex) { //always restore terrain on this tiles _copy_terrain_needed[tindex] |= 1U; _copy_terrain_needed[tindex + 1] |= 1U; _copy_terrain_needed[tindex + _copy_width] |= 1U; _copy_terrain_needed[tindex + _copy_width + 1] |= 1U; //Bulldoze those tiles _copy_tunnel[bindex] |= (1U << 7); } /** * Game command which copies a selected area **/ void CopyArea(TileIndex end, TileIndex start, bool copyWithRail, bool copyWithRoad, bool copyWithOther) { int8 baseh; TileIndex tindex = 0; TileIndex bindex = 0; int size_x, size_y; bool success = false; TileIndex sx = TileX(start); TileIndex sy = TileY(start); TileIndex ex = TileX(end); TileIndex ey = TileY(end); uint8 storelocation; //tmp for storing signals bool tunnelbridge_error; int32 maxdiff, i; if (ex < sx) uintswap(ex, sx); if (ey < sy) uintswap(ey, sy); //add one tile, but just for heightmap ex++; ey++; size_x = (ex - sx) + 1; size_y = (ey - sy) + 1; if ((size_x * size_y) > COPY_MAX) return; _copy_width = size_x; _copy_height = size_y; ClearCopyArrays(size_x, size_y); //Create a command DIFF to a flat Area... //Base level is from first tile. baseh = (int8)TileHeight(TileXY(sx, sy)); tindex = 0; BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) { _copy_heightmap[tindex] = ((int8)TileHeight(tile)) - baseh; //debug("Index: %u, Height: %u", tindex, _copy_heightmap[tindex]); tindex++; //Dont Copy tracks/buildings on last x/y row if (!((h_cur == 1) || (w_cur == 1))) { //Copy building/track here switch (GetTileType(tile)) { case MP_RAILWAY: if (!copyWithRail) break; if (!(copyWithOther || IsTileOwner(tile, _current_player))) break; TerrainNeededAroundTile(tindex - 1, bindex); if (IsTileDepotType(tile, TRANSPORT_RAIL)) { //Store Depot //debug("Storing Depot"); //Depot here: bit 0 _copy_depot[bindex] |= 1U; //Transport type bit 1 (dont need to store, is zero) //Direction: bit 2+3 _copy_depot[bindex] |= (GetDepotDirection(tile, TRANSPORT_RAIL) << 2); //Store Railway type in bits 6+7 _copy_rail[bindex] |= (GetRailType(tile) << 6); //debug("Storing DepotRailtype: %u", _copy_rail[bindex]); } else { if (IsRailWaypoint(tile)) { //Store Waypoint in depot bit 7 debug("storing Waypoint"); _copy_depot[bindex] |= (1U << 7); //Store Waypoint custom gfx id in bits 1-6 _copy_depot[bindex] |= ((GetWaypointByTile(tile)->stat_id & 63U) << 1); //Store Rail track too. _copy_rail[bindex] |= (1U << GetWaypointAxis(tile)); //Store Railway type in bits 6+7 _copy_rail[bindex] |= (GetRailType(tile) << 6); } else { //debug("Storing Rail"); //Store Railway tracks in bits 0 to 5: if (HasTrack(tile, TRACK_X)) _copy_rail[bindex] |= (1U << TRACK_X); if (HasTrack(tile, TRACK_Y)) _copy_rail[bindex] |= (1U << TRACK_Y); if (HasTrack(tile, TRACK_UPPER)) _copy_rail[bindex] |= (1U << TRACK_UPPER); if (HasTrack(tile, TRACK_LOWER)) _copy_rail[bindex] |= (1U << TRACK_LOWER); if (HasTrack(tile, TRACK_LEFT)) _copy_rail[bindex] |= (1U << TRACK_LEFT); if (HasTrack(tile, TRACK_RIGHT)) _copy_rail[bindex] |= (1U << TRACK_RIGHT); //Store Railway type in bits 6+7 _copy_rail[bindex] |= (GetRailType(tile) << 6); //Signals: if (HasSignals(tile)) { //Store Signal: //0- 5 : Signal on trackdir //6- 7 : Direction S1 (Clicks to build) //8- 9 : Direction S2 (Clicks to build) storelocation = 6; if (HasTrack(tile, TRACK_X) && HasSignalOnTrack(tile, TRACK_X)) { //debug("Signal on TRACK_X"); _copy_signals[bindex] |= (1U << TRACK_X); if (!((HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_X)) && (HasSignalOnTrackdir(tile, ReverseTrackdir(TrackToTrackdir(TRACK_X))))))) { if (HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_X))) _copy_signals[bindex] |= (1U << storelocation); else _copy_signals[bindex] |= (2U << storelocation); } storelocation = 8; } if (HasTrack(tile, TRACK_Y) && HasSignalOnTrack(tile, TRACK_Y)) { //debug("Signal on TRACK_Y"); _copy_signals[bindex] |= (1U << TRACK_Y); if (!((HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_Y)) && (HasSignalOnTrackdir(tile, ReverseTrackdir(TrackToTrackdir(TRACK_Y))))))) { if (HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_Y))) _copy_signals[bindex] |= (1U << storelocation); else _copy_signals[bindex] |= (2U << storelocation); } storelocation = 8; } if (HasTrack(tile, TRACK_UPPER) && HasSignalOnTrack(tile, TRACK_UPPER)) { //debug("Signal on TRACK_UPPER"); _copy_signals[bindex] |= (1U << TRACK_UPPER); if (!((HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_UPPER)) && (HasSignalOnTrackdir(tile, ReverseTrackdir(TrackToTrackdir(TRACK_UPPER))))))) { if (HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_UPPER))) _copy_signals[bindex] |= (1U << storelocation); else _copy_signals[bindex] |= (2U << storelocation); } storelocation = 8; } if (HasTrack(tile, TRACK_LOWER) && HasSignalOnTrack(tile, TRACK_LOWER)) { //debug("Signal on TRACK_LOWER"); _copy_signals[bindex] |= (1U << TRACK_LOWER); if (!((HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_LOWER)) && (HasSignalOnTrackdir(tile, ReverseTrackdir(TrackToTrackdir(TRACK_LOWER))))))) { if (HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_LOWER))) _copy_signals[bindex] |= (1U << storelocation); else _copy_signals[bindex] |= (2U << storelocation); } storelocation = 8; } if (HasTrack(tile, TRACK_LEFT) && HasSignalOnTrack(tile, TRACK_LEFT)) { //debug("Signal on TRACK_LEFT"); _copy_signals[bindex] |= (1U << TRACK_LEFT); if (!((HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_LEFT)) && (HasSignalOnTrackdir(tile, ReverseTrackdir(TrackToTrackdir(TRACK_LEFT))))))) { if (HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_LEFT))) _copy_signals[bindex] |= (2U << storelocation); else _copy_signals[bindex] |= (1U << storelocation); } storelocation = 8; } if (HasTrack(tile, TRACK_RIGHT) && HasSignalOnTrack(tile, TRACK_RIGHT)) { //debug("Signal on TRACK_RIGHT"); _copy_signals[bindex] |= (1U << TRACK_RIGHT); if (!((HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_RIGHT)) && (HasSignalOnTrackdir(tile, ReverseTrackdir(TrackToTrackdir(TRACK_RIGHT))))))) { if (HasSignalOnTrackdir(tile, TrackToTrackdir(TRACK_RIGHT))) _copy_signals[bindex] |= (2U << storelocation); else _copy_signals[bindex] |= (1U << storelocation); } storelocation = 8; } //Semaphore? _copy_signals[bindex] |= (GetSignalVariant(tile) << 10); //10: Semaphore? //Store SignalType _copy_signals[bindex] |= (GetSignalType(tile) << 11); //11- 13: Signaltype (normal, pre, exit, combo, pbs) } } } break; case MP_STREET: if (IsLevelCrossingTile(tile)) { //Crossing: Get Axis, store rail too if (GetCrossingRoadAxis(tile) == AXIS_X) { if ((copyWithRail) && ((copyWithOther || IsTileOwner(tile, _current_player)))) { TerrainNeededAroundTile(tindex - 1, bindex); _copy_rail[bindex] = (1 << TRACK_Y); _copy_rail[bindex] |= (GetRailTypeCrossing(tile) << 6); } if ((copyWithRoad) && ((copyWithOther || (GetCrossingRoadOwner(tile) == _current_player)))) { TerrainNeededAroundTile(tindex - 1, bindex); _copy_road[bindex] = ROAD_X; } } else { if ((copyWithRail) && ((copyWithOther || IsTileOwner(tile, _current_player)))) { TerrainNeededAroundTile(tindex - 1, bindex); _copy_rail[bindex] = (1 << TRACK_X); _copy_rail[bindex] |= (GetRailTypeCrossing(tile) << 6); } if ((copyWithRoad) && ((copyWithOther || (GetCrossingRoadOwner(tile) == _current_player)))) { TerrainNeededAroundTile(tindex - 1, bindex); _copy_road[bindex] = ROAD_Y; } } } else { if (!copyWithRoad) break; if (!(copyWithOther || IsTileOwner(tile, _current_player))) break; TerrainNeededAroundTile(tindex - 1, bindex); //debug("Storing Road"); if (IsTileDepotType(tile, TRANSPORT_ROAD)) { _copy_depot[bindex] |= 1U; //Transport type bit 1 (dont need to store, is zero) _copy_depot[bindex] |= (1U << 1); //Direction: bit 2+3 _copy_depot[bindex] |= (GetDepotDirection(tile, TRANSPORT_ROAD) << 2); } else { //No Crossing, store road _copy_road[bindex] = GetRoadBits(tile); } } break; case MP_STATION: //Stations: //GetStationByTile(tile)); //debug("Storing Station"); break; case MP_TUNNELBRIDGE: //debug("Storing Tunnelbridge"); //Store tunnel in bit 0 if (IsTunnelTile(tile)) { if (!copyWithRail && (GetTunnelTransportType(tile) == TRANSPORT_RAIL)) break; if (!copyWithRoad && (GetTunnelTransportType(tile) == TRANSPORT_ROAD)) break; if (!(copyWithOther || IsTileOwner(tile, _current_player))) break; tunnelbridge_error = false; if ((GetTunnelDirection(tile) == DIAGDIR_SW) || (GetTunnelDirection(tile) == DIAGDIR_SE)) { int tilediff = 1; //debug("Storing Tunnel"); //Store existance of tunnel in bit 0 _copy_tunnel[bindex] |= 1U; //Store tunnel direction in bit 1-2 _copy_tunnel[bindex] |= GetTunnelDirection(tile) << 1; //Store tunnel transport type in bit 3 _copy_tunnel[bindex] |= (GetTunnelTransportType(tile) << 3); //Store tunnel start in bit 4 _copy_tunnel[bindex] |= (1U << 4); //Store rail type too, if railtunnel if (GetTunnelTransportType(tile) == TRANSPORT_RAIL) _copy_rail[bindex] = (GetRailType(tile) << 6); //Now mark all tiles between tunnel start and end as needed switch (GetTunnelDirection(tile)) { case DIAGDIR_SW: maxdiff = (size_x - 1) - (bindex % (size_x - 1)) - 1; if (maxdiff <= 0) { tunnelbridge_error = true; break; } while ((!IsTunnelTile(tile + TileDiffXY(tilediff, 0))) && (tilediff <= maxdiff)) { //InsideSelection, tunnelEndnotfound tilediff++; } if ((!IsTunnelTile(tile + TileDiffXY(tilediff, 0))) || (tilediff > maxdiff)) tunnelbridge_error = true; if (!tunnelbridge_error) { //Mark Tiles as needed: for (i = 0; i <= tilediff; i++) TerrainNeededAroundTile(tindex - 1 + i, bindex + i); //Set other TunnelEnd //Store existance of tunnel in bit 0 _copy_tunnel[bindex + tilediff] |= 1U; //Store tunnel direction in bit 1-2 _copy_tunnel[bindex + tilediff] |= GetTunnelDirection(tile + TileDiffXY(tilediff, 0)) << 1; //Store tunnel transport type in bit 3 _copy_tunnel[bindex + tilediff] |= (GetTunnelTransportType(tile + TileDiffXY(tilediff, 0)) << 3); //Store tunnel start in bit 4 (No, this is tunnel End) //Store rail type too, if railtunnel if (GetTunnelTransportType(tile + TileDiffXY(tilediff, 0)) == TRANSPORT_RAIL) _copy_rail[bindex + tilediff] = (GetRailType(tile + TileDiffXY(tilediff, 0)) << 6); } break; case DIAGDIR_SE: maxdiff = (size_y - 1) - (bindex / (size_x - 1)) - 1; if (maxdiff <= 0) { tunnelbridge_error = true; break; } while ((!IsTunnelTile(tile + TileDiffXY(0, tilediff))) && (tilediff <= maxdiff)) { //InsideSelection, tunnelEndnotfound tilediff++; } if ((!IsTunnelTile(tile + TileDiffXY(0, tilediff))) || (tilediff > maxdiff)) tunnelbridge_error = true; if (!tunnelbridge_error) { //Mark Tiles as needed: for (i = 0; i <= tilediff; i++) TerrainNeededAroundTile(tindex - 1 + (i * size_x), bindex + (i * (size_x - 1))); //Set other TunnelEnd //Store existance of tunnel in bit 0 _copy_tunnel[bindex + (tilediff * (size_x - 1))] |= 1U; //Store tunnel direction in bit 1-2 _copy_tunnel[bindex + (tilediff * (size_x - 1))] |= GetTunnelDirection(tile + TileDiffXY(0, tilediff)) << 1; //Store tunnel transport type in bit 3 _copy_tunnel[bindex + (tilediff * (size_x - 1))] |= (GetTunnelTransportType(tile + TileDiffXY(0, tilediff)) << 3); //Store tunnel start in bit 4 (No, this is tunnel End) //Store rail type too, if railtunnel if (GetTunnelTransportType(tile + TileDiffXY(0, tilediff)) == TRANSPORT_RAIL) _copy_rail[bindex + (tilediff * (size_x - 1))] = (GetRailType(tile + TileDiffXY(0, tilediff)) << 6); } break; default: break; } //NOTE: Bit 7 is used for bulldozing! if (tunnelbridge_error) { //ResetBridge on Error _copy_tunnel[bindex] = 0; _copy_rail[bindex] = 0; } } else { //Other direction, do nothing... } } else { /* Returns here when bridge branch is merged back into trunk //debug("Storing Bridge"); //BridgeRamp bit 0 _copy_bridge[bindex] |= (1U); //Direction bit 1-2 _copy_bridge[bindex] |= (GetBridgeRampDirection(tile) << 1); //TransportType bit 3 _copy_bridge[bindex] |= (GetBridgeTransportType(tile) << 3); //Store "IsBridge-Start" in Bit4 if ((GetBridgeRampDirection(tile) == DIAGDIR_SW) || (GetBridgeRampDirection(tile) == DIAGDIR_SE)) _copy_bridge[bindex] |= (1U << 4); //BridgeType bit 8-15 (max 255 bridges...) _copy_bridge[bindex] |= (GetBridgeType(tile) << 8); //Store Railtype if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) _copy_rail[bindex] |= (GetRailType(tile) << 6); */ //Store bridge (Has to be in "else", since Tunnel is a "BridgeRamp" too) if (IsBridgeRamp(tile)) { if (!copyWithRail && (GetBridgeTransportType(tile) == TRANSPORT_RAIL)) break; if (!copyWithRoad && (GetBridgeTransportType(tile) == TRANSPORT_ROAD)) break; if (!(copyWithOther || IsTileOwner(tile, _current_player))) break; tunnelbridge_error = false; if ((GetBridgeRampDirection(tile) == DIAGDIR_SW) || (GetBridgeRampDirection(tile) == DIAGDIR_SE)) { int tilediff = 1; //debug("Storing Bridge"); //BridgeRamp bit 0 _copy_bridge[bindex] |= (1U); //Direction bit 1-2 _copy_bridge[bindex] |= (GetBridgeRampDirection(tile) << 1); //TransportType bit 3 _copy_bridge[bindex] |= (GetBridgeTransportType(tile) << 3); //Store "IsBridge-Start" in Bit4 _copy_bridge[bindex] |= (1U << 4); //BridgeType bit 8-15 (max 255 bridges...) _copy_bridge[bindex] |= (GetBridgeType(tile) << 8); //Store Railtype if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) _copy_rail[bindex] |= (GetRailType(tile) << 6); //Now mark all tiles between tunnel start and end as needed switch (GetBridgeRampDirection(tile)) { case DIAGDIR_SW: maxdiff = (size_x - 1) - (bindex % (size_x - 1)) - 1; if (maxdiff <= 0) { tunnelbridge_error = true; break; } while ((!(IsTileType(tile + TileDiffXY(tilediff, 0), MP_TUNNELBRIDGE) && (!IsTunnelTile(tile + TileDiffXY(tilediff, 0))) && IsBridgeRamp(tile + TileDiffXY(tilediff, 0)))) && (tilediff <= maxdiff)) { tilediff++; } if ((!(IsTileType(tile + TileDiffXY(tilediff, 0), MP_TUNNELBRIDGE) && (!IsTunnelTile(tile + TileDiffXY(tilediff, 0))) && IsBridgeRamp(tile + TileDiffXY(tilediff, 0)))) || (tilediff > maxdiff)) tunnelbridge_error = true; if (!tunnelbridge_error) { //Mark Tiles as needed: for (i = 0; i <= tilediff; i++) TerrainNeededAroundTile(tindex - 1 + i, bindex + i); //Set other BridgeEnd //BridgeRamp bit 0 _copy_bridge[bindex + tilediff] |= (1U); //Direction bit 1-2 _copy_bridge[bindex + tilediff] |= (GetBridgeRampDirection(tile + TileDiffXY(tilediff, 0)) << 1); //TransportType bit 3 _copy_bridge[bindex + tilediff] |= (GetBridgeTransportType(tile + TileDiffXY(tilediff, 0)) << 3); //Store "IsBridge-Start" in Bit4 (Nope, this is the End) //BridgeType bit 8-15 (max 255 bridges...) _copy_bridge[bindex + tilediff] |= (GetBridgeType(tile + TileDiffXY(tilediff, 0)) << 8); //Store Railtype if (GetBridgeTransportType(tile + TileDiffXY(tilediff, 0)) == TRANSPORT_RAIL) _copy_rail[bindex + tilediff] |= (GetRailType(tile + TileDiffXY(tilediff, 0)) << 6); } break; case DIAGDIR_SE: maxdiff = (size_y - 1) - (bindex / (size_x - 1)) - 1; if (maxdiff <= 0) { tunnelbridge_error = true; break; } while ((!(IsTileType(tile + TileDiffXY(0, tilediff), MP_TUNNELBRIDGE) && (!IsTunnelTile(tile + TileDiffXY(0, tilediff))) && IsBridgeRamp(tile + TileDiffXY(0, tilediff)))) && (tilediff <= maxdiff)) { tilediff++; } if ((!(IsTileType(tile + TileDiffXY(0, tilediff), MP_TUNNELBRIDGE) && (!IsTunnelTile(tile + TileDiffXY(0, tilediff))) && IsBridgeRamp(tile + TileDiffXY(0, tilediff)))) || (tilediff > maxdiff)) tunnelbridge_error = true; if (!tunnelbridge_error) { //Mark Tiles as needed: for (i = 0; i <= tilediff; i++) TerrainNeededAroundTile(tindex - 1 + (i * size_x), bindex + (i * (size_x - 1))); //Set other BridgeEnd //BridgeRamp bit 0 _copy_bridge[bindex + (tilediff * (size_x - 1))] |= (1U); //Direction bit 1-2 _copy_bridge[bindex + (tilediff * (size_x - 1))] |= (GetBridgeRampDirection(tile + TileDiffXY(0, tilediff)) << 1); //TransportType bit 3 _copy_bridge[bindex + (tilediff * (size_x - 1))] |= (GetBridgeTransportType(tile + TileDiffXY(0, tilediff)) << 3); //Store "IsBridge-Start" in Bit4 (Nope, this is the End) //BridgeType bit 8-15 (max 255 bridges...) _copy_bridge[bindex + (tilediff * (size_x - 1))] |= (GetBridgeType(tile + TileDiffXY(0, tilediff)) << 8); //Store Railtype if (GetBridgeTransportType(tile + TileDiffXY(0, tilediff)) == TRANSPORT_RAIL) _copy_rail[bindex + (tilediff * (size_x - 1))] |= (GetRailType(tile + TileDiffXY(0, tilediff)) << 6); } break; default: break; } //NOTE: Bit 7 is used for bulldozing! if (tunnelbridge_error) { //ResetBridge on Error _copy_bridge[bindex] = 0; _copy_rail[bindex] = 0; } } else { //Other direction, do nothing... } } else { //rail/road below bridge if (IsTransportUnderBridge(tile)) { if (!(copyWithOther || IsTileOwner(tile, _current_player))) break; if (GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) { if (!copyWithRail) break; TerrainNeededAroundTile(tindex - 1, bindex); //debug("Storing Rail under Bridge"); _copy_rail[bindex] = (GetRailType(tile) << 6); if (GetBridgeAxis(tile) == AXIS_X) _copy_rail[bindex] |= (1U << TRACK_Y); else _copy_rail[bindex] |= (1U << TRACK_X); } else { if (!copyWithRoad) break; TerrainNeededAroundTile(tindex - 1, bindex); //debug("Storing Road under Bridge"); if (GetBridgeAxis(tile) == AXIS_X) _copy_road[bindex] = ROAD_Y; else _copy_road[bindex] = ROAD_X; } } } } break; default: //debug("Storing nothing"); //If this is above a tunnel, or under a bridge, we need this tile. /* Returns here when bridge branch is merged back into trunk if (MayHaveBridgeAbove(tile)) if (IsBridgeAbove(tile)) TerrainNeededAroundTile(tindex - 1, bindex); */ /* if (IsTunnelBelow(tile)) TerrainNeededAroundTile(tindex - 1, bindex); */ break; } bindex++; } success = true; } END_TILE_LOOP(tile, size_x, size_y, 0); if (success) SndPlayTileFx(SND_1F_SPLAT, end); } /** * Rotate array helper function **/ static void rotate1B(void* a, int w, int h, int dir) { uint8* tmp; uint8* b; int i, len, x, y, src, target; len = w * h; tmp = malloc(len); b = (uint8*) a; //TODO: Maybe a "in place" rotate would be nice... //Copy array to new allocated array: for (i = 0; i < len; i++) tmp[i] = b[i]; if (dir == 1) { //Copy rotated values back to original array for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { //X index is now the old Y index //Y index is w - x src = (y * w) + x; target = (((w - 1) - x) * h) + y; b[target] = tmp[src]; } } } else if (dir == -1) { //Copy rotated values back to original array for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { //X index is now the old Y index //Y index is w - x src = (y * w) + x; target = (x * h) + (h - 1 - y); b[target] = tmp[src]; } } } //Release temp array free(tmp); } /** * Rotate array helper function **/ static void rotate2B(void* a, int w, int h, int dir) { uint16* tmp; uint16* b; int i, len, x, y, src, target; len = w * h; tmp = malloc(len * 2); b = (uint16*) a; //Copy array to new allocated array: for (i = 0; i < len; i++) tmp[i] = b[i]; //Copy rotated values back to original array if (dir == 1) { for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { //X index is now the old Y index //Y index is w - x src = (y * w) + x; target = (((w - 1) - x) * h) + y; b[target] = tmp[src]; } } } else if (dir == -1) { //Copy rotated values back to original array for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { //X index is now the old Y index //Y index is w - x src = (y * w) + x; target = (x * h) + (h - 1 - y); b[target] = tmp[src]; } } } //Release temp array free(tmp); } /** * Mirror array helper function * axis: 0 = horizontal * axis: 1 = vertical **/ static void mirror1B(void* a, int w, int h, int axis) { uint8 tmp; uint8* b; int x, y, p1, p2; b = (uint8*) a; if (axis == 0) { //Mirror Horizontal (along horizontal axis. like photoshop.) //I'm getting confused everytime, because i think "horizontal" //describes the axis of the imaginary mirror... whatever =) for (y = 0; y < h; y++) { for (x = 0; x < (w / 2); x++) { p1 = x + (y * w); p2 = (w - x - 1) + (y * w); tmp = b[p1]; b[p1] = b[p2]; b[p2] = tmp; } } } else if (axis == 1) { //Mirror Vertical for (y = 0; y < (h / 2); y++) { for (x = 0; x < w; x++) { p1 = x + (y * w); p2 = x + ((h - y - 1) * w); tmp = b[p1]; b[p1] = b[p2]; b[p2] = tmp; } } } } /** * Mirror array helper function * axis: 0 = horizontal * axis: 1 = vertical **/ static void mirror2B(void* a, int w, int h, int axis) { uint16 tmp; uint16* b; int x, y, p1, p2; b = (uint16*) a; if (axis == 0) { //Mirror Horizontal for (y = 0; y < h; y++) { for (x = 0; x < (w / 2); x++) { p1 = x + (y * w); p2 = (w - x - 1) + (y * w); tmp = b[p1]; b[p1] = b[p2]; b[p2] = tmp; } } } else if (axis == 1) { //Mirror Vertical for (y = 0; y < (h / 2); y++) { for (x = 0; x < w; x++) { p1 = x + (y * w); p2 = x + ((h - y - 1) * w); tmp = b[p1]; b[p1] = b[p2]; b[p2] = tmp; } } } } /** * Rotates the copied content ClockWise **/ void RotateSelectionCW(void) { int tmp; int w = _copy_width - 1; int h = _copy_height - 1; uint8 storelocation; int index, len; uint8 tmp8; uint16 tmp16; //Rotate arrays rotate1B((void*) _copy_heightmap, _copy_width, _copy_height, 1); rotate1B((void*) _copy_terrain_needed, _copy_width, _copy_height, 1); rotate1B((void*) _copy_rail, w, h, 1); rotate1B((void*) _copy_tunnel, w, h, 1); rotate2B((void*) _copy_signals, w, h, 1); rotate1B((void*) _copy_road, w, h, 1); rotate2B((void*) _copy_bridge, w, h, 1); rotate1B((void*) _copy_depot, w, h, 1); //Rotate array content (tracks, depots etc..) len = w * h; for (index = 0; index < len; index++) { tmp8 = _copy_rail[index]; //Clear Tracks _copy_rail[index] &= ~63U; //Clear bits 0-5 //Copy back + rotate if ((tmp8 & (1U << TRACK_Y)) > 0) _copy_rail[index] |= (1U << TRACK_X); if ((tmp8 & (1U << TRACK_X)) > 0) _copy_rail[index] |= (1U << TRACK_Y); if ((tmp8 & (1U << TRACK_LEFT)) > 0) _copy_rail[index] |= (1U << TRACK_UPPER); if ((tmp8 & (1U << TRACK_RIGHT)) > 0) _copy_rail[index] |= (1U << TRACK_LOWER); if ((tmp8 & (1U << TRACK_LOWER)) > 0) _copy_rail[index] |= (1U << TRACK_LEFT); if ((tmp8 & (1U << TRACK_UPPER)) > 0) _copy_rail[index] |= (1U << TRACK_RIGHT); //Tunnel //Just rotate direction if ((_copy_tunnel[index] & 1U) > 0) { tmp8 = (_copy_tunnel[index] >> 1) & 3U; //Extract bit 1-2 _copy_tunnel[index] &= ~(3U << 1); //clear bit 1-2 tmp8++; //increase by 1 _copy_tunnel[index] |= (tmp8 & 3U) << 1;//clamp & set } //Signals //Rotate position tmp16 = _copy_signals[index]; //Clear Signals _copy_signals[index] &= ~63U; //Clear bits 0-5 //Copy back + rotate position storelocation = 6; if ((tmp16 & (1U << TRACK_X)) > 0) { _copy_signals[index] |= (1U << TRACK_Y); storelocation = 8; } if ((tmp16 & (1U << TRACK_Y)) > 0) { _copy_signals[index] |= (1U << TRACK_X); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } if ((tmp16 & (1U << TRACK_UPPER)) > 0) { _copy_signals[index] |= (1U << TRACK_RIGHT); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } if ((tmp16 & (1U << TRACK_LOWER)) > 0) { _copy_signals[index] |= (1U << TRACK_LEFT); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } if (storelocation == 8) { //Exchange Storelocations tmp8 = _copy_signals[index] >> 6; _copy_signals[index] &= ~(15U << 6); //Clear bit 6-9 _copy_signals[index] |= (((tmp8 >> 2) & 3U) << 6); //Set bit 6+7 to former 8+9 _copy_signals[index] |= (((tmp8 >> 0) & 3U) << 8); //Set bit 8+9 to former 6+7 } storelocation = 8; } if ((tmp16 & (1U << TRACK_LEFT)) > 0) { _copy_signals[index] |= (1U << TRACK_UPPER); storelocation = 8; } if ((tmp16 & (1U << TRACK_RIGHT)) > 0) { _copy_signals[index] |= (1U << TRACK_LOWER); storelocation = 8; } //Road: //store bit 0, shiftright, set bit 3 to bit 0 tmp8 = _copy_road[index]; _copy_road[index] >>= 1; _copy_road[index] |= ((tmp8 & 1U) << 3); //Bridge //Just rotate direction if ((_copy_bridge[index] & 1U) > 0) { tmp8 = (_copy_bridge[index] >> 1) & 3U; //Extract bit 1-2 _copy_bridge[index] &= ~(3U << 1); //clear bit 1-2 tmp8++; //increase by 1 _copy_bridge[index] |= (tmp8 & 3U) << 1;//clamp & set } //Depot, same as bridge if ((_copy_depot[index] & 1U) > 0) { tmp8 = (_copy_depot[index] >> 2) & 3U; //Extract bit 2-3 _copy_depot[index] &= ~(3U << 2); //clear bit 2-3 tmp8++; //increase by 1 _copy_depot[index] |= (tmp8 & 3U) << 2;//clamp & set } //Waypoint is rotated by its underlying track } tmp = _copy_height; _copy_height = _copy_width; _copy_width = tmp; } /** * Rotates the copied content CounterClockWise **/ void RotateSelectionCCW(void) { int tmp; int w = _copy_width - 1; int h = _copy_height - 1; uint8 storelocation; int index, len; uint8 tmp8; uint16 tmp16; //Rotate arrays rotate1B((void*) _copy_heightmap, _copy_width, _copy_height, -1); rotate1B((void*) _copy_terrain_needed, _copy_width, _copy_height, -1); rotate1B((void*) _copy_rail, w, h, -1); rotate1B((void*) _copy_tunnel, w, h, -1); rotate2B((void*) _copy_signals, w, h, -1); rotate1B((void*) _copy_road, w, h, -1); rotate2B((void*) _copy_bridge, w, h, -1); rotate1B((void*) _copy_depot, w, h, -1); //Rotate array content (tracks, depots etc..) len = w * h; for (index = 0; index < len; index++) { tmp8 = _copy_rail[index]; //Clear Tracks _copy_rail[index] &= ~63U; //Clear bits 0-5 //Copy back + rotate if ((tmp8 & (1U << TRACK_Y)) > 0) _copy_rail[index] |= (1U << TRACK_X); if ((tmp8 & (1U << TRACK_X)) > 0) _copy_rail[index] |= (1U << TRACK_Y); if ((tmp8 & (1U << TRACK_RIGHT)) > 0) _copy_rail[index] |= (1U << TRACK_UPPER); if ((tmp8 & (1U << TRACK_LEFT)) > 0) _copy_rail[index] |= (1U << TRACK_LOWER); if ((tmp8 & (1U << TRACK_UPPER)) > 0) _copy_rail[index] |= (1U << TRACK_LEFT); if ((tmp8 & (1U << TRACK_LOWER)) > 0) _copy_rail[index] |= (1U << TRACK_RIGHT); //Tunnel //Just rotate direction if ((_copy_tunnel[index] & 1U) > 0) { tmp8 = (_copy_tunnel[index] >> 1) & 3U; //Extract bit 1-2 _copy_tunnel[index] &= ~(3U << 1); //clear bit 1-2 tmp8--; //decrease by 1 (0 -> 255 (255 & 3) == 3) _copy_tunnel[index] |= (tmp8 & 3U) << 1;//clamp & set } //Signals //Rotate position tmp16 = _copy_signals[index]; //Clear Signals _copy_signals[index] &= ~63U; //Clear bits 0-5 //Copy back + rotate position storelocation = 6; if ((tmp16 & (1U << TRACK_X)) > 0) { _copy_signals[index] |= (1U << TRACK_Y); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } if ((tmp16 & (1U << TRACK_Y)) > 0) { _copy_signals[index] |= (1U << TRACK_X); storelocation = 8; } if ((tmp16 & (1U << TRACK_UPPER)) > 0) { _copy_signals[index] |= (1U << TRACK_LEFT); storelocation = 8; } if ((tmp16 & (1U << TRACK_LOWER)) > 0) { _copy_signals[index] |= (1U << TRACK_RIGHT); storelocation = 8; } if ((tmp16 & (1U << TRACK_LEFT)) > 0) { _copy_signals[index] |= (1U << TRACK_LOWER); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } if ((tmp16 & (1U << TRACK_RIGHT)) > 0) { _copy_signals[index] |= (1U << TRACK_UPPER); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } if (storelocation == 8) { //Exchange Storelocations tmp8 = _copy_signals[index] >> 6; _copy_signals[index] &= ~(15U << 6); //Clear bit 6-9 _copy_signals[index] |= (((tmp8 >> 2) & 3U) << 6); //Set bit 6+7 to former 8+9 _copy_signals[index] |= (((tmp8 >> 0) & 3U) << 8); //Set bit 8+9 to former 6+7 } storelocation = 8; } //Road: //store bit 3, shiftleft, set bit 0 to bit 3 tmp8 = _copy_road[index]; _copy_road[index] <<= 1; _copy_road[index] &= 15U; //Clear possible bit 4 _copy_road[index] |= (tmp8 >> 3); //Bridge //Just rotate direction if ((_copy_bridge[index] & 1U) > 0) { tmp8 = (_copy_bridge[index] >> 1) & 3U; //Extract bit 1-2 _copy_bridge[index] &= ~(3U << 1); //clear bit 1-2 tmp8--; //decrease by 1 (0 -> 255 (255 & 3) == 3) _copy_bridge[index] |= (tmp8 & 3U) << 1;//clamp & set } //Depot, same as bridge if ((_copy_depot[index] & 1U) > 0) { tmp8 = (_copy_depot[index] >> 2) & 3U; //Extract bit 2-3 _copy_depot[index] &= ~(3U << 2); //clear bit 2-3 tmp8--; //increase by 1 _copy_depot[index] |= (tmp8 & 3U) << 2;//clamp & set } //Waypoint is rotated by its underlying track } tmp = _copy_height; _copy_height = _copy_width; _copy_width = tmp; } void MirrorSelectionHorizontal(void) { int w = _copy_width - 1; int h = _copy_height - 1; uint8 storelocation; int index, len; uint8 tmp8; uint16 tmp16; //Mirror arrays mirror1B((void*) _copy_heightmap, _copy_width, _copy_height, 0); mirror1B((void*) _copy_terrain_needed, _copy_width, _copy_height, 0); mirror1B((void*) _copy_rail, w, h, 0); mirror1B((void*) _copy_tunnel, w, h, 0); mirror2B((void*) _copy_signals, w, h, 0); mirror1B((void*) _copy_road, w, h, 0); mirror2B((void*) _copy_bridge, w, h, 0); mirror1B((void*) _copy_depot, w, h, 0); //Mirror array content (left <-> right) len = w * h; for (index = 0; index < len; index++) { tmp8 = _copy_rail[index]; //Clear Tracks _copy_rail[index] &= ~63U; //Clear bits 0-5 //Copy back + mirror if ((tmp8 & (1U << TRACK_X)) > 0) _copy_rail[index] |= (1U << TRACK_X); if ((tmp8 & (1U << TRACK_Y)) > 0) _copy_rail[index] |= (1U << TRACK_Y); if ((tmp8 & (1U << TRACK_LEFT)) > 0) _copy_rail[index] |= (1U << TRACK_UPPER); if ((tmp8 & (1U << TRACK_RIGHT)) > 0) _copy_rail[index] |= (1U << TRACK_LOWER); if ((tmp8 & (1U << TRACK_UPPER)) > 0) _copy_rail[index] |= (1U << TRACK_LEFT); if ((tmp8 & (1U << TRACK_LOWER)) > 0) _copy_rail[index] |= (1U << TRACK_RIGHT); //Tunnel //Just mirror direction (flip horizontal dirs) if ((_copy_tunnel[index] & 1U) > 0) { tmp8 = (_copy_tunnel[index] >> 1) & 3U; //Extract bit 1-2 _copy_tunnel[index] &= ~(3U << 1); //clear bit 1-2 if (tmp8 == DIAGDIR_NE) tmp8 = DIAGDIR_SW; else if (tmp8 == DIAGDIR_SW) tmp8 = DIAGDIR_NE; _copy_tunnel[index] |= (tmp8 & 3U) << 1;//clamp & set } //Signals //Mirror position tmp16 = _copy_signals[index]; //Clear Signals _copy_signals[index] &= ~63U; //Clear bits 0-5 //Copy back + mirror position storelocation = 6; if ((tmp16 & (1U << TRACK_X)) > 0) { _copy_signals[index] |= (1U << TRACK_X); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } if ((tmp16 & (1U << TRACK_Y)) > 0) { _copy_signals[index] |= (1U << TRACK_Y); storelocation = 8; } if ((tmp16 & (1U << TRACK_UPPER)) > 0) { _copy_signals[index] |= (1U << TRACK_LEFT); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } if ((tmp16 & (1U << TRACK_LOWER)) > 0) { _copy_signals[index] |= (1U << TRACK_RIGHT); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } if ((tmp16 & (1U << TRACK_LEFT)) > 0) { _copy_signals[index] |= (1U << TRACK_UPPER); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } if ((tmp16 & (1U << TRACK_RIGHT)) > 0) { _copy_signals[index] |= (1U << TRACK_LOWER); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } //Road: //swap horizontal roadpieces tmp8 = _copy_road[index]; _copy_road[index] &= ~(ROAD_NE | ROAD_SW); //Clear specific road bits if ((tmp8 & ROAD_NE) > 0) _copy_road[index] |= ROAD_SW; if ((tmp8 & ROAD_SW) > 0) _copy_road[index] |= ROAD_NE; //Bridge //Just rotate direction if ((_copy_bridge[index] & 1U) > 0) { tmp8 = (_copy_bridge[index] >> 1) & 3U; //Extract bit 1-2 _copy_bridge[index] &= ~(3U << 1); //clear bit 1-2 if (tmp8 == DIAGDIR_NE) tmp8 = DIAGDIR_SW; else if (tmp8 == DIAGDIR_SW) tmp8 = DIAGDIR_NE; _copy_bridge[index] |= (tmp8 & 3U) << 1;//clamp & set } //Depot, same as bridge if ((_copy_depot[index] & 1U) > 0) { tmp8 = (_copy_depot[index] >> 2) & 3U; //Extract bit 2-3 _copy_depot[index] &= ~(3U << 2); //clear bit 2-3 if (tmp8 == DIAGDIR_NE) tmp8 = DIAGDIR_SW; else if (tmp8 == DIAGDIR_SW) tmp8 = DIAGDIR_NE; _copy_depot[index] |= (tmp8 & 3U) << 2;//clamp & set } //Waypoint is mirrored by its underlying track } } void MirrorSelectionVertical(void) { int w = _copy_width - 1; int h = _copy_height - 1; uint8 storelocation; int index, len; uint8 tmp8; uint16 tmp16; //Mirror arrays mirror1B((void*) _copy_heightmap, _copy_width, _copy_height, 1); mirror1B((void*) _copy_terrain_needed, _copy_width, _copy_height, 1); mirror1B((void*) _copy_rail, w, h, 1); mirror1B((void*) _copy_tunnel, w, h, 1); mirror2B((void*) _copy_signals, w, h, 1); mirror1B((void*) _copy_road, w, h, 1); mirror2B((void*) _copy_bridge, w, h, 1); mirror1B((void*) _copy_depot, w, h, 1); //Mirror array content (up <-> down) len = w * h; for (index = 0; index < len; index++) { tmp8 = _copy_rail[index]; //Clear Tracks _copy_rail[index] &= ~63U; //Clear bits 0-5 //Copy back + mirror if ((tmp8 & (1U << TRACK_X)) > 0) _copy_rail[index] |= (1U << TRACK_X); if ((tmp8 & (1U << TRACK_Y)) > 0) _copy_rail[index] |= (1U << TRACK_Y); if ((tmp8 & (1U << TRACK_RIGHT)) > 0) _copy_rail[index] |= (1U << TRACK_UPPER); if ((tmp8 & (1U << TRACK_LEFT)) > 0) _copy_rail[index] |= (1U << TRACK_LOWER); if ((tmp8 & (1U << TRACK_LOWER)) > 0) _copy_rail[index] |= (1U << TRACK_LEFT); if ((tmp8 & (1U << TRACK_UPPER)) > 0) _copy_rail[index] |= (1U << TRACK_RIGHT); //Tunnel //Just mirror direction (flip vertical dirs) if ((_copy_tunnel[index] & 1U) > 0) { tmp8 = (_copy_tunnel[index] >> 1) & 3U; //Extract bit 1-2 _copy_tunnel[index] &= ~(3U << 1); //clear bit 1-2 if (tmp8 == DIAGDIR_NW) tmp8 = DIAGDIR_SE; else if (tmp8 == DIAGDIR_SE) tmp8 = DIAGDIR_NW; _copy_tunnel[index] |= (tmp8 & 3U) << 1;//clamp & set } //Signals //Mirror position tmp16 = _copy_signals[index]; //Clear Signals _copy_signals[index] &= ~63U; //Clear bits 0-5 //Copy back + mirror position storelocation = 6; if ((tmp16 & (1U << TRACK_X)) > 0) { _copy_signals[index] |= (1U << TRACK_X); storelocation = 8; } if ((tmp16 & (1U << TRACK_Y)) > 0) { _copy_signals[index] |= (1U << TRACK_Y); if (((_copy_signals[index] >> storelocation) & 3U) > 0) { TOGGLEBIT(_copy_signals[index], storelocation); TOGGLEBIT(_copy_signals[index], storelocation + 1); } storelocation = 8; } if ((tmp16 & (1U << TRACK_UPPER)) > 0) { _copy_signals[index] |= (1U << TRACK_RIGHT); storelocation = 8; } if ((tmp16 & (1U << TRACK_LOWER)) > 0) { _copy_signals[index] |= (1U << TRACK_LEFT); if (storelocation == 8) { //Exchange Storelocations tmp8 = _copy_signals[index] >> 6; _copy_signals[index] &= ~(15U << 6); //Clear bit 6-9 _copy_signals[index] |= (((tmp8 >> 2) & 3U) << 6); //Set bit 6+7 to former 8+9 _copy_signals[index] |= (((tmp8 >> 0) & 3U) << 8); //Set bit 8+9 to former 6+7 } storelocation = 8; } if ((tmp16 & (1U << TRACK_LEFT)) > 0) { _copy_signals[index] |= (1U << TRACK_LOWER); storelocation = 8; } if ((tmp16 & (1U << TRACK_RIGHT)) > 0) { _copy_signals[index] |= (1U << TRACK_UPPER); if (storelocation == 8) { //Exchange Storelocations tmp8 = _copy_signals[index] >> 6; _copy_signals[index] &= ~(15U << 6); //Clear bit 6-9 _copy_signals[index] |= (((tmp8 >> 2) & 3U) << 6); //Set bit 6+7 to former 8+9 _copy_signals[index] |= (((tmp8 >> 0) & 3U) << 8); //Set bit 8+9 to former 6+7 } storelocation = 8; } //Road: //swap horizontal roadpieces tmp8 = _copy_road[index]; _copy_road[index] &= ~(ROAD_NW | ROAD_SE); //Clear specific road bits if ((tmp8 & ROAD_NW) > 0) _copy_road[index] |= ROAD_SE; if ((tmp8 & ROAD_SE) > 0) _copy_road[index] |= ROAD_NW; //Bridge //Just rotate direction if ((_copy_bridge[index] & 1U) > 0) { tmp8 = (_copy_bridge[index] >> 1) & 3U; //Extract bit 1-2 _copy_bridge[index] &= ~(3U << 1); //clear bit 1-2 if (tmp8 == DIAGDIR_NW) tmp8 = DIAGDIR_SE; else if (tmp8 == DIAGDIR_SE) tmp8 = DIAGDIR_NW; _copy_bridge[index] |= (tmp8 & 3U) << 1;//clamp & set } //Depot, same as bridge if ((_copy_depot[index] & 1U) > 0) { tmp8 = (_copy_depot[index] >> 2) & 3U; //Extract bit 2-3 _copy_depot[index] &= ~(3U << 2); //clear bit 2-3 if (tmp8 == DIAGDIR_NW) tmp8 = DIAGDIR_SE; else if (tmp8 == DIAGDIR_SE) tmp8 = DIAGDIR_NW; _copy_depot[index] |= (tmp8 & 3U) << 2;//clamp & set } //Waypoint is mirrored by its underlying track } }