1 /* 2 * This file is part of Dune Legacy. 3 * 4 * Dune Legacy is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * Dune Legacy is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with Dune Legacy. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifndef SCREENBORDER_H 19 #define SCREENBORDER_H 20 21 #include <DataTypes.h> 22 23 #include <misc/InputStream.h> 24 #include <misc/OutputStream.h> 25 #include <fixmath/FixPoint.h> 26 #include <mmath.h> 27 #include <globals.h> 28 29 #include <algorithm> 30 31 #define SCROLLBORDER 3 32 33 /// This class manages everything that is related to the current view onto the map. 34 class ScreenBorder 35 { 36 public: 37 /** 38 Constructor 39 \param gameBoardRect this SDL_Rect specifies the rectangle on the screen where the map is shown 40 */ ScreenBorder(const SDL_Rect & gameBoardRect)41 explicit ScreenBorder(const SDL_Rect& gameBoardRect) 42 : mapSizeX(0), mapSizeY(0) { 43 44 this->gameBoardRect = gameBoardRect; 45 46 bottomRightCorner.x = gameBoardRect.w; 47 bottomRightCorner.y = gameBoardRect.h; 48 topLeftCornerOnScreen.x = gameBoardRect.x; 49 topLeftCornerOnScreen.y = gameBoardRect.y; 50 bottomRightCornerOnScreen.x = gameBoardRect.x + gameBoardRect.w; 51 bottomRightCornerOnScreen.y = gameBoardRect.y + gameBoardRect.h; 52 53 numShakingCycles = 0; 54 }; 55 56 /** 57 Destructor 58 */ ~ScreenBorder()59 ~ScreenBorder() { } 60 61 /** 62 Loads the current position on the map from a stream 63 \param stream the stream to load from 64 */ load(InputStream & stream)65 void load(InputStream& stream) { 66 Coord center; 67 center.x = stream.readSint16(); 68 center.y = stream.readSint16(); 69 70 setNewScreenCenter(center); 71 } 72 73 /** 74 Saves the current map position to a stream 75 \param stream the stream to save to 76 */ save(OutputStream & stream)77 void save(OutputStream& stream) const 78 { 79 Coord center = getCurrentCenter(); 80 stream.writeSint16(center.x); 81 stream.writeSint16(center.y); 82 } 83 84 /** 85 Get the current center point of the view in world coordinates. 86 \return current center point in world coordinates. 87 */ getCurrentCenter()88 inline Coord getCurrentCenter() const 89 { 90 return topLeftCorner + shakingOffset + (bottomRightCorner - topLeftCorner)/2; 91 } 92 93 /** 94 Returns the top left corner of the view in world coordinates. 95 \return current top left corner in world coordinates. 96 */ getTopLeftCorner()97 inline Coord getTopLeftCorner() const 98 { 99 return topLeftCorner + shakingOffset; 100 } 101 102 /** 103 Returns the bottom right corner of the view in world coordinates. 104 \return current bottom right corner in world coordinates. 105 */ getBottomRightCorner()106 inline Coord getBottomRightCorner() const 107 { 108 return bottomRightCorner + shakingOffset; 109 } 110 111 /** 112 Returns the position of the left edge of the view in world coordinates. 113 \return current left edge in world coordinates. 114 */ getLeft()115 inline short getLeft() const 116 { 117 return topLeftCorner.x + shakingOffset.x; 118 } 119 120 /** 121 Returns the position of the top edge of the view in world coordinates. 122 \return current top edge in world coordinates. 123 */ getTop()124 inline short getTop() const 125 { 126 return topLeftCorner.y + shakingOffset.y; 127 } 128 129 /** 130 Returns the position of the right edge of the view in world coordinates. 131 \return current right edge in world coordinates. 132 */ getRight()133 inline short getRight() const 134 { 135 return bottomRightCorner.x + shakingOffset.x; 136 } 137 138 /** 139 Returns the position of the bottom edge of the view in world coordinates. 140 \return current bottom edge in world coordinates. 141 */ getBottom()142 inline short getBottom() const 143 { 144 return bottomRightCorner.y + shakingOffset.y; 145 } 146 147 /** 148 Returns the map coordinate of the top left corner of the current view. 149 \return map coordinate of the top left corner 150 */ getTopLeftTile()151 inline Coord getTopLeftTile() const 152 { 153 return (topLeftCorner + shakingOffset) / TILESIZE; 154 } 155 156 /** 157 Returns the map coordinate of the bottom right corner of the current view. 158 \return map coordinate of the bottom right corner 159 */ getBottomRightTile()160 inline Coord getBottomRightTile() const 161 { 162 return (bottomRightCorner + shakingOffset) / TILESIZE; 163 } 164 165 /** 166 There may be a part of the tile at the top left corner that is outside the screen. 167 This method returns how much is outside the screen (in world coordinates). 168 \return the part of the tile that lies outside the screen. 169 */ getCornerOffset()170 inline Coord getCornerOffset() const 171 { 172 return ((topLeftCorner + shakingOffset) / TILESIZE) * TILESIZE - (topLeftCorner + shakingOffset); 173 } 174 175 /** 176 This method checks if some object is (partly) inside or completely outside the current view. 177 \param objectPosition object position in world coordinates 178 \param objectSize the size of the object (in world coordinates) 179 \return true if (partly) inside, false if completly outside 180 */ isInsideScreen(const Coord & objectPosition,const Coord & objectSize)181 inline bool isInsideScreen(const Coord& objectPosition, const Coord& objectSize) const 182 { 183 return (((objectPosition.x + objectSize.x/2) >= topLeftCorner.x + shakingOffset.x) 184 && ((objectPosition.x - objectSize.x/2) <= bottomRightCorner.x + shakingOffset.x) 185 && ((objectPosition.y + objectSize.y/2) >= topLeftCorner.y + shakingOffset.y) 186 && ((objectPosition.y - objectSize.y/2) <= bottomRightCorner.y + shakingOffset.y) ); 187 } 188 189 /** 190 This method checks if a tile is (partly) inside the current view. 191 \param tileLocation the location of the tile in map coordinates 192 \return true if (partly) inside, false if completly outside 193 */ isTileInsideScreen(const Coord & tileLocation)194 inline bool isTileInsideScreen(const Coord& tileLocation) const 195 { 196 return isInsideScreen(tileLocation*TILESIZE + Coord(TILESIZE/2, TILESIZE/2), Coord(TILESIZE,TILESIZE)); 197 } 198 199 /** 200 Sets the current view to a new position. 201 \param newPosition the center of the new view in world coordinates 202 */ 203 void setNewScreenCenter(const Coord& newPosition); 204 205 /** 206 This method scrolls left 207 */ 208 bool scrollLeft(); 209 210 /** 211 This method scrolls right 212 */ 213 bool scrollRight(); 214 215 /** 216 This method scrolls up 217 */ 218 bool scrollUp(); 219 220 /** 221 This method scrolls down 222 */ 223 bool scrollDown(); 224 225 /** 226 This method converts from world to screen coordinates. 227 \param x the x position in world coordinates 228 \return the x-coordinate on the screen 229 */ world2screenX(int x)230 inline int world2screenX(int x) const 231 { 232 return world2zoomedWorld(x - topLeftCorner.x + shakingOffset.x + topLeftCornerOnScreen.x); 233 } 234 235 /** 236 This method converts from world to screen coordinates. 237 \param x the x position in world coordinates 238 \return the x-coordinate on the screen 239 */ world2screenX(float x)240 inline int world2screenX(float x) const 241 { 242 return world2zoomedWorld(x - (float) topLeftCorner.x + (float) shakingOffset.x + (float) topLeftCornerOnScreen.x); 243 } 244 245 /** 246 This method converts from world to screen coordinates. 247 \param x the x position in world coordinates 248 \return the x-coordinate on the screen 249 */ world2screenX(FixPoint x)250 inline int world2screenX(FixPoint x) const 251 { 252 return world2zoomedWorld(x.toFloat() - (float) topLeftCorner.x + (float) shakingOffset.x + (float) topLeftCornerOnScreen.x); 253 } 254 255 /** 256 This method converts from world to screen coordinates. 257 \param y the y position in world coordinates 258 \return the y-coordinate on the screen 259 */ world2screenY(int y)260 inline int world2screenY(int y) const 261 { 262 return world2zoomedWorld(y - topLeftCorner.y + shakingOffset.y + topLeftCornerOnScreen.y); 263 } 264 265 /** 266 This method converts from world to screen coordinates. 267 \param y the y position in world coordinates 268 \return the y-coordinate on the screen 269 */ world2screenY(float y)270 inline int world2screenY(float y) const 271 { 272 return world2zoomedWorld(y - (float) topLeftCorner.y + (float) shakingOffset.y + (float) topLeftCornerOnScreen.y); 273 } 274 275 /** 276 This method converts from world to screen coordinates. 277 \param y the y position in world coordinates 278 \return the y-coordinate on the screen 279 */ world2screenY(FixPoint y)280 inline int world2screenY(FixPoint y) const 281 { 282 return world2zoomedWorld(y.toFloat() - (float) topLeftCorner.y + (float) shakingOffset.y + (float) topLeftCornerOnScreen.y); 283 } 284 285 /** 286 This method converts from screen to world coordinates. 287 \param x the x coordinate on the screen 288 \return the x-position in world coordinates 289 */ screen2worldX(int x)290 inline int screen2worldX(int x) const 291 { 292 return zoomedWorld2world(x) - topLeftCornerOnScreen.x + topLeftCorner.x + shakingOffset.x; 293 } 294 295 /** 296 This method converts from screen to world coordinates. 297 \param y the y coordinate on the screen 298 \return the y-position in world coordinates 299 */ screen2worldY(int y)300 inline int screen2worldY(int y) const 301 { 302 return zoomedWorld2world(y) - topLeftCornerOnScreen.y + topLeftCorner.y + shakingOffset.y; 303 } 304 305 /** 306 This method converts from screen to map coordinates. 307 \param x the x coordinate on the screen 308 \return the x-coordinate of the tile at position x in map coordinates 309 */ screen2MapX(int x)310 inline int screen2MapX(int x) const 311 { 312 return screen2worldX(x)/TILESIZE; 313 }; 314 315 /** 316 This method converts from screen to map coordinates. 317 \param y the y coordinate on the screen 318 \return the y-coordinate of the tile at position y in map coordinates 319 */ screen2MapY(int y)320 inline int screen2MapY(int y) const 321 { 322 return screen2worldY(y)/TILESIZE; 323 }; 324 325 /** 326 This method checks if the specified x,y coordinate is within the map 327 \param x the x coordinate in screen coordinates 328 \param y the y coordinate in screen coordinates 329 \return true, if inside, false otherwise 330 */ isScreenCoordInsideMap(int x,int y)331 inline bool isScreenCoordInsideMap(int x, int y) const { 332 return (zoomedWorld2world(x) >= topLeftCornerOnScreen.x && zoomedWorld2world(x) < bottomRightCornerOnScreen.x 333 && zoomedWorld2world(y) >= topLeftCornerOnScreen.y && zoomedWorld2world(y) < bottomRightCornerOnScreen.y); 334 } 335 336 /** 337 This method adjusts the screen border to the current map size. 338 \param newMapSizeX the number of map tiles in x direction 339 \param newMapSizeY the number of map tiles in y direction 340 */ 341 void adjustScreenBorderToMapsize(int newMapSizeX, int newMapSizeY); 342 343 shakeScreen(int numShakingCycles)344 void shakeScreen(int numShakingCycles) { 345 this->numShakingCycles += numShakingCycles; 346 if(this->numShakingCycles > 2*numShakingCycles) { 347 this->numShakingCycles = 2*numShakingCycles; 348 } 349 } 350 update()351 void update() { 352 if(numShakingCycles > 0) { 353 int offsetMax = std::min(TILESIZE-1,numShakingCycles); 354 355 shakingOffset.x = (rand() % offsetMax) - offsetMax/2; 356 shakingOffset.y = (rand() % offsetMax) - offsetMax/2; 357 358 numShakingCycles--; 359 } 360 } 361 362 private: 363 SDL_Rect gameBoardRect; ///< the complete game board rectangle 364 365 int mapSizeX; ///< The number of tiles in x direction 366 int mapSizeY; ///< The number of tiles in y direction 367 368 Coord topLeftCorner; ///< the position of the top left corner in world coordinates 369 Coord bottomRightCorner; ///< the position of the bottom right corner in world coordinates 370 371 Coord shakingOffset; ///< this offset is added while shaking the screen (e.g. when a death hand explodes) 372 373 Coord topLeftCornerOnScreen; ///< the position of the top left corner in screen coordinates 374 Coord bottomRightCornerOnScreen;///< the position of the bottom right corner in screen coordinates 375 376 int numShakingCycles; ///< the number of cycles the screen will shake 377 }; 378 379 #endif //SCREENBORDER 380