New upstream version 2.5.0
Markus Koschany
4 years ago
0 | #http://EditorConfig.org | |
1 | ||
2 | # top-most EditorConfig file | |
3 | root = true | |
4 | ||
5 | # Unix-style newlines with a newline ending every file | |
6 | [*] | |
7 | end_of_line = lf | |
8 | insert_final_newline = true | |
9 | ||
10 | [*.cpp,*.hpp,*.h,*.inc] | |
11 | indent_style = tab |
2 | 2 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${blockattack_SOURCE_DIR}/source/misc/cmake") |
3 | 3 | set(BIN_DIR ${blockattack_SOURCE_DIR}/Game) |
4 | 4 | |
5 | SET(CPACK_PACKAGE_VERSION "2.3.0") | |
5 | SET(CPACK_PACKAGE_VERSION "2.5.0") | |
6 | 6 | SET(CPACK_PACKAGE_VERSION_MAJOR "2") |
7 | SET(CPACK_PACKAGE_VERSION_MINOR "3") | |
7 | SET(CPACK_PACKAGE_VERSION_MINOR "5") | |
8 | 8 | SET(CPACK_PACKAGE_VERSION_PATCH "0") |
9 | 9 | SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Block Attack - Rise of the Blocks ${CPACK_PACKAGE_VERSION}") |
10 | 10 | SET(CPACK_PACKAGE_VENDOR "Poul Sander") |
17 | 17 | set(INSTALL_APPLICATIONS_DIR "share/applications" CACHE STRING "Install the .desktop file to this directory") |
18 | 18 | set(INSTALL_ICONS_DIR "share/icons/hicolor" CACHE STRING "Install the icon in a subfolder in this directory") |
19 | 19 | set(INSTALL_LOCALE_DIR "${INSTALL_DATA_DIR}/locale/" CACHE STRING "Install translation to this dir") |
20 | set(INSTALL_METAINFO_DIR "share/metainfo" CACHE STRING "Install appstream matedata to this directory") | |
20 | 21 | |
21 | 22 | # This sets up the exe icon for windows under mingw. |
22 | 23 | # Taken from https://hansonry.wordpress.com/2010/12/15/windows-application-icon-using-mingw-and-cmake/ |
30 | 31 | endif(MINGW) |
31 | 32 | |
32 | 33 | if (WIN32) |
33 | SET(GUI_TYPE WIN32) | |
34 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686") | |
34 | SET(GUI_TYPE WIN32) | |
35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686") | |
36 | if(NOT _WIN32_WINNT AND NOT WINVER) | |
37 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_WIN32_WINNT=0x0601 -DWINVER=0x0601") | |
38 | endif() | |
35 | 39 | endif() |
36 | 40 | |
37 | 41 | if (NOT WIN32 AND NOT STANDALONE) |
85 | 89 | install(FILES Game/blockattack.data DESTINATION ${INSTALL_DATA_DIR} ) |
86 | 90 | install(FILES man/blockattack.6.gz DESTINATION ${INSTALL_MAN_DIR} ) |
87 | 91 | install(FILES source/misc/blockattack.desktop DESTINATION ${INSTALL_APPLICATIONS_DIR} ) |
92 | install(FILES source/misc/net.blockattack.game.metainfo.xml DESTINATION ${INSTALL_METAINFO_DIR} ) | |
88 | 93 | install(FILES source/misc/icons/blockattack16.xpm DESTINATION "${INSTALL_ICONS_DIR}/16x16/apps" RENAME blockattack.xpm ) |
89 | 94 | install(FILES source/misc/icons/blockattack48.xpm DESTINATION "${INSTALL_ICONS_DIR}/48x48/apps" RENAME blockattack.xpm ) |
90 | 95 | install(FILES source/misc/icons/blockattack128.xpm DESTINATION "${INSTALL_ICONS_DIR}/128x128/apps" RENAME blockattack.xpm ) |
14 | 14 | "topy" : 0, |
15 | 15 | "height" : 768, |
16 | 16 | "width" : 1024, |
17 | "number_of_frames" : 1, | |
18 | "frame_time" : 1 | |
19 | }, | |
20 | "background_sixteen_nine" : { | |
21 | "texture" : "background_sixteen_nine", | |
22 | "topx" : 2, | |
23 | "topy" : 0, | |
24 | "height" : 768, | |
25 | "width" : 1364, | |
26 | "number_of_frames" : 1, | |
27 | "frame_time" : 1 | |
28 | }, | |
29 | "background_sun" : { | |
30 | "texture" : "background_sun", | |
31 | "topx" : 0, | |
32 | "topy" : 0, | |
33 | "height" : 1024, | |
34 | "width" : 1024, | |
35 | "number_of_frames" : 1, | |
36 | "frame_time" : 1 | |
37 | }, | |
38 | "background_cloud" : { | |
39 | "texture" : "background_cloud", | |
40 | "topx" : 0, | |
41 | "topy" : 0, | |
42 | "height" : 301, | |
43 | "width" : 511, | |
44 | "number_of_frames" : 1, | |
45 | "frame_time" : 1 | |
46 | }, | |
47 | "background_ground" : { | |
48 | "texture" : "background_ground", | |
49 | "topx" : 0, | |
50 | "topy" : 0, | |
51 | "height" : 511, | |
52 | "width" : 1920, | |
17 | 53 | "number_of_frames" : 1, |
18 | 54 | "frame_time" : 1 |
19 | 55 | }, |
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
1 | 1 | Block Attack - Rise of the Blocks - the game<br/> |
2 | 2 | A Tetris Attack Clone under the GPL. |
3 | 3 | |
4 | Homepage: http://www.blockattack.net<br/> | |
5 | Source: https://github.com/blockattack/blockattack-game | |
4 | Homepage: <https://blockattack.net><br/> | |
5 | Source: <https://github.com/blockattack/blockattack-game> | |
6 | 6 | |
7 | ##Screen shot | |
8 | ![Block Attack - Rise of the Blocks 2.0.0 snapshot](/source/misc/screenshots/screen_shot_2016_01_19.png?raw=true "Screen shot from 2016-01-19") | |
7 | ## Screen shot | |
8 | ![Block Attack - Rise of the Blocks](https://blockattack.github.io/images/screenshots/blockattack-2.3.0-3.png "Screen shot") | |
9 | 9 | |
10 | # Dependencies | |
11 | * A version of g++ with C++11 support. Tested on g++-4.9 | |
12 | * libSDL2 | |
13 | * libSDL2_image | |
14 | * libSDL2_mixer | |
15 | * libSDL2_ttf | |
16 | * libphysfs | |
17 | * libboost (only needed for compiling) | |
18 | * libboost-program-options | |
19 | * libutfcpp (only needed for compiling) | |
10 | ## Dependencies | |
11 | * A version of g++ with C++11 support. Tested on g++-4.9 | |
12 | * libSDL2 | |
13 | * libSDL2_image | |
14 | * libSDL2_mixer | |
15 | * libSDL2_ttf | |
16 | * libphysfs | |
17 | * libboost (only needed for compiling) | |
18 | * libboost-program-options | |
19 | * libutfcpp (only needed for compiling) | |
20 | 20 | |
21 | # Building | |
21 | ## Building | |
22 | 22 | The only supported build method is using the CMake<br/> |
23 | 23 | To build do: |
24 | 24 | ``` |
51 | 51 | i686-w64-mingw32.static-cmake -DCMAKE_BUILD_TYPE=Release . && make |
52 | 52 | ``` |
53 | 53 | |
54 | # Building using Docker | |
54 | ## Building using Docker | |
55 | 55 | |
56 | 56 | As getting a C++ project with many dependencies to compile can be a daunting task then I have provided a couple of Docker images that can perform a build. Both for Windows and Linux. |
57 | 57 | |
58 | 58 | On a fresh checkout you can use: |
59 | 59 | ``` |
60 | docker build -f source/misc/docker/Dockerfile.Ubuntu14.04build . -t blockattack_test | |
60 | docker build -f source/misc/docker/Dockerfile.Ubuntu16.04build . -t blockattack_test | |
61 | 61 | ``` |
62 | 62 | and |
63 | 63 | ``` |
64 | 64 | docker build -f source/misc/docker/Dockerfile.WindoesBuild . -t blockattack_test |
65 | 65 | ``` |
66 | 66 | |
67 | ||
68 | # Source Structure | |
67 | ## Source Structure | |
69 | 68 | This project is a bit unconversionel because I didn't know any better at the time. |
70 | 69 | |
71 | * Game - The output is placed here | |
72 | * man - The manual file and the script to generate it. May be moved to source/misc at some point | |
73 | * source/code/ - The source code | |
74 | * source/code/Libs - External libs that are compiled into the project because they are either header only (Cereal) or not designed for use as a shared library. | |
75 | * source/code/sago - Source code. Not designed to be specific to Block Attack - Rise of the Blocks | |
76 | * source/assets - Source for the assets if relevant. For instance svg source for the graphics. | |
77 | * source/misc - Misc stuff. Code related tool that are used for development but not part of the final product. | |
78 | * source/misc/astyle - Helper script that enforces code style using the "astyle"-program | |
79 | * source/misc/cmake - Files needed by CMake | |
80 | * source/misc/docker - Docker files used by Travis CI (but can just as well be used for local testing and release builds) | |
81 | * source/misc/icons - Icons for the installer | |
82 | * source/misc/screenshots - Screen shots like the one in this README file. | |
83 | * source/misc/translation - Translations and related tools and scripts | |
84 | * source/misc/travis_help - Helper files for Travis CI | |
85 | * windows installer - Information needed to Windows installer. May be moved to source/misc at some point | |
70 | * Game - The output is placed here | |
71 | * man - The manual file and the script to generate it. May be moved to source/misc at some point | |
72 | * source/code/ - The source code | |
73 | * source/code/Libs - External libs that are compiled into the project because they are either header only (Cereal) or not designed for use as a shared library. | |
74 | * source/code/sago - Source code. Not designed to be specific to Block Attack - Rise of the Blocks | |
75 | * source/assets - Source for the assets if relevant. For instance svg source for the graphics. | |
76 | * source/misc - Misc stuff. Code related tool that are used for development but not part of the final product. | |
77 | * source/misc/astyle - Helper script that enforces code style using the "astyle"-program | |
78 | * source/misc/cmake - Files needed by CMake | |
79 | * source/misc/docker - Docker files used by Travis CI (but can just as well be used for local testing and release builds) | |
80 | * source/misc/icons - Icons for the installer | |
81 | * source/misc/screenshots - Screen shots like the one in this README file. | |
82 | * source/misc/translation - Translations and related tools and scripts | |
83 | * source/misc/travis_help - Helper files for Travis CI | |
84 | * windows installer - Information needed to Windows installer. May be moved to source/misc at some point | |
86 | 85 | |
87 | # Reporting bugs | |
86 | ## Reporting bugs | |
88 | 87 | |
89 | Please report bugs on github: https://github.com/blockattack/blockattack-game/issues | |
88 | Please report bugs on github: <https://github.com/blockattack/blockattack-game/issues> | |
90 | 89 | If possible: Check if the bug is already fixed in master. But if you don't know how to check it then just report it. |
91 | 90 | |
92 | # Contributions | |
91 | ## Contributions | |
93 | 92 | Contributions are welcome. Both the current graphics and the original sharedir support was provided by kind individuals. |
94 | 93 | Patches can be attached to a github ticket or sent to poul@poulsander.com directly. You can also create pull requests on Github. |
0 | This is Block Attack - Rise of the Blocks - version 2.3.0 | |
1 | ||
2 | Changes since 2.2.0: | |
3 | Several keyboard keys are now translatable | |
4 | Window size is now restored on next startup | |
5 | The back-button on the gamepad now goes back in menus | |
6 | Gamepad L2 and R2 can now be used to push lines | |
7 | Game Over, Winner and Draw are now translatable | |
8 | ||
9 | Feedback can be given on https://blockattack.net or https://github.com/blockattack/blockattack-game |
0 | This is Block Attack - Rise of the Blocks - version 2.5.0 | |
1 | ||
2 | Changes since 2.4.0: | |
3 | Added option to always use the software renderer | |
4 | Automatically start in software render the first time after a crash | |
5 | Fixed the search order in archives | |
6 | Added widescreen support. Only used in fullscreen by default. | |
7 | Added appstream metadata | |
8 | Screenshot feature no longer crashes in hardware acceleration. Still only works in software mode | |
9 | ||
10 | Feedback can be given on https://blockattack.net or https://github.com/blockattack/blockattack-game |
0 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. | |
1 | .TH BLOCKATTACK "6" "July 2018" "blockattack 2.3.0" "Games" | |
0 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. | |
1 | .TH BLOCKATTACK "6" "May 2019" "blockattack 2.5.0" "Games" | |
2 | 2 | .SH NAME |
3 | 3 | blockattack \- a puzzle game inspired by Tetris Attack |
4 | 4 | .SH SYNOPSIS |
5 | 5 | .B blockattack |
6 | 6 | [\fI\,OPTION\/\fR]... |
7 | 7 | .SH DESCRIPTION |
8 | Block Attack \- Rise of the blocks 2.3.0 | |
8 | Block Attack \- Rise of the blocks 2.5.0 | |
9 | 9 | .PP |
10 | 10 | Block Attack \- Rise of the Blocks is a puzzle/blockfall game inspired by Tetris Attack for the SNES. |
11 | 11 | .PP |
42 | 42 | \fB\-\-no\-auto\-scale\fR |
43 | 43 | Do not automatically auto scale |
44 | 44 | .TP |
45 | \fB\-\-always\-sixteen\-nine\fR | |
46 | Use 16:9 format even in Window mode | |
47 | .TP | |
45 | 48 | \fB\-\-puzzle\-level\-file\fR arg |
46 | 49 | Sets the default puzzle file to load |
47 | 50 | .TP |
16 | 16 | /textures/ |
17 | 17 | back_board.png qubodup |
18 | 18 | background.png qubodup |
19 | background_sixteen_nine.png Poul Sander (based of qubodup's background.png) | |
19 | 20 | ball_blue.png qubodup |
20 | 21 | ball_gray.png qubodup |
21 | 22 | ball_green.png qubodup |
59 | 60 | garbage_tr.png qubodup |
60 | 61 | green.png qubodup |
61 | 62 | grey.png qubodup |
63 | gui_back_white.png Derived from UI pack by Kenney Vleugels (www.kenney.nl) (CC0 license) | |
64 | gui_back_yellow.png Derived from UI pack by Kenney Vleugels (www.kenney.nl) (CC0 license) | |
62 | 65 | help_controller.png nicefrog (https://opengameart.org/content/generic-gamepad-template) |
63 | 66 | i_check_box_area.png Poul Sander |
64 | 67 | icon.png Poul Sander |
0 | 0 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> |
1 | 1 | <!-- Created with Inkscape (http://www.inkscape.org/) --> |
2 | ||
2 | 3 | <svg |
3 | 4 | xmlns:dc="http://purl.org/dc/elements/1.1/" |
4 | 5 | xmlns:cc="http://creativecommons.org/ns#" |
9 | 10 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
10 | 11 | id="svg2" |
11 | 12 | sodipodi:version="0.32" |
12 | inkscape:version="0.46" | |
13 | inkscape:version="0.92.3 (2405546, 2018-03-11)" | |
13 | 14 | width="1024" |
14 | 15 | height="768" |
15 | 16 | version="1.0" |
52 | 53 | </filter> |
53 | 54 | </defs> |
54 | 55 | <sodipodi:namedview |
55 | inkscape:window-height="951" | |
56 | inkscape:window-width="1280" | |
56 | inkscape:window-height="1016" | |
57 | inkscape:window-width="927" | |
57 | 58 | inkscape:pageshadow="2" |
58 | 59 | inkscape:pageopacity="0.0" |
59 | 60 | guidetolerance="10.0" |
65 | 66 | id="base" |
66 | 67 | showgrid="false" |
67 | 68 | inkscape:zoom="0.5" |
68 | inkscape:cx="564.234" | |
69 | inkscape:cy="314.12607" | |
70 | inkscape:window-x="0" | |
71 | inkscape:window-y="25" | |
72 | inkscape:current-layer="svg2"> | |
69 | inkscape:cx="387.28966" | |
70 | inkscape:cy="362.22947" | |
71 | inkscape:window-x="67" | |
72 | inkscape:window-y="27" | |
73 | inkscape:current-layer="svg2" | |
74 | inkscape:window-maximized="0"> | |
73 | 75 | <inkscape:grid |
74 | 76 | type="xygrid" |
75 | 77 | id="grid3193" |
76 | 78 | visible="true" |
77 | 79 | enabled="true" |
78 | spacingx="128px" | |
79 | spacingy="128px" /> | |
80 | spacingx="128" | |
81 | spacingy="128" | |
82 | originx="0" | |
83 | originy="0" /> | |
80 | 84 | </sodipodi:namedview> |
81 | 85 | <rect |
82 | 86 | style="opacity:1;fill:#a1dbee;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" |
96 | 100 | sodipodi:cy="68.855171" |
97 | 101 | sodipodi:rx="180.08276" |
98 | 102 | sodipodi:ry="180.08276" |
99 | d="M 1084.0276,68.855171 A 180.08276,180.08276 0 1 1 723.86206,68.855171 A 180.08276,180.08276 0 1 1 1084.0276,68.855171 z" | |
100 | transform="matrix(1.5261598,0,0,1.5261598,-456.19872,25.564281)" /> | |
103 | d="M 1084.0276,68.855171 A 180.08276,180.08276 0 0 1 903.94482,248.93793 180.08276,180.08276 0 0 1 723.86206,68.855171 180.08276,180.08276 0 0 1 903.94482,-111.22759 180.08276,180.08276 0 0 1 1084.0276,68.855171 Z" | |
104 | transform="matrix(1.5261598,0,0,1.5261598,-456.19872,25.564281)" | |
105 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_sun.png" | |
106 | inkscape:export-xdpi="144.22725" | |
107 | inkscape:export-ydpi="144.22725" /> | |
101 | 108 | <path |
102 | 109 | transform="translate(19.42069,61.793103)" |
103 | d="M 1084.0276,68.855171 A 180.08276,180.08276 0 1 1 723.86206,68.855171 A 180.08276,180.08276 0 1 1 1084.0276,68.855171 z" | |
110 | d="M 1084.0276,68.855171 A 180.08276,180.08276 0 0 1 903.94482,248.93793 180.08276,180.08276 0 0 1 723.86206,68.855171 180.08276,180.08276 0 0 1 903.94482,-111.22759 180.08276,180.08276 0 0 1 1084.0276,68.855171 Z" | |
104 | 111 | sodipodi:ry="180.08276" |
105 | 112 | sodipodi:rx="180.08276" |
106 | 113 | sodipodi:cy="68.855171" |
115 | 122 | style="opacity:1;fill:#f77935;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> |
116 | 123 | <path |
117 | 124 | transform="matrix(0.9262219,0,0,1,33.836039,-13.732501)" |
118 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 1 1 813.96278,77.005501 A 23.719774,30.586025 0 1 1 861.40233,77.005501 z" | |
125 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 0 1 837.68256,107.59153 23.719774,30.586025 0 0 1 813.96278,77.005501 23.719774,30.586025 0 0 1 837.68256,46.419476 23.719774,30.586025 0 0 1 861.40233,77.005501 Z" | |
119 | 126 | sodipodi:ry="30.586025" |
120 | 127 | sodipodi:rx="23.719774" |
121 | 128 | sodipodi:cy="77.005501" |
131 | 138 | sodipodi:cy="77.005501" |
132 | 139 | sodipodi:rx="23.719774" |
133 | 140 | sodipodi:ry="30.586025" |
134 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 1 1 813.96278,77.005501 A 23.719774,30.586025 0 1 1 861.40233,77.005501 z" | |
141 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 0 1 837.68256,107.59153 23.719774,30.586025 0 0 1 813.96278,77.005501 23.719774,30.586025 0 0 1 837.68256,46.419476 23.719774,30.586025 0 0 1 861.40233,77.005501 Z" | |
135 | 142 | transform="matrix(0.9946296,0,0,1.1020408,71.785455,-0.9914533)" /> |
136 | 143 | <path |
137 | 144 | sodipodi:type="arc" |
141 | 148 | sodipodi:cy="77.005501" |
142 | 149 | sodipodi:rx="23.719774" |
143 | 150 | sodipodi:ry="30.586025" |
144 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 1 1 813.96278,77.005501 A 23.719774,30.586025 0 1 1 861.40233,77.005501 z" | |
151 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 0 1 837.68256,107.59153 23.719774,30.586025 0 0 1 813.96278,77.005501 23.719774,30.586025 0 0 1 837.68256,46.419476 23.719774,30.586025 0 0 1 861.40233,77.005501 Z" | |
145 | 152 | transform="matrix(0.5510204,0,0,0.5510204,345.51635,33.013387)" /> |
146 | 153 | <path |
147 | 154 | transform="matrix(0.5773697,0,0,0.5878019,415.69998,50.683724)" |
148 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 1 1 813.96278,77.005501 A 23.719774,30.586025 0 1 1 861.40233,77.005501 z" | |
155 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 0 1 837.68256,107.59153 23.719774,30.586025 0 0 1 813.96278,77.005501 23.719774,30.586025 0 0 1 837.68256,46.419476 23.719774,30.586025 0 0 1 861.40233,77.005501 Z" | |
149 | 156 | sodipodi:ry="30.586025" |
150 | 157 | sodipodi:rx="23.719774" |
151 | 158 | sodipodi:cy="77.005501" |
0 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
1 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | |
2 | ||
3 | <svg | |
4 | xmlns:dc="http://purl.org/dc/elements/1.1/" | |
5 | xmlns:cc="http://creativecommons.org/ns#" | |
6 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
7 | xmlns:svg="http://www.w3.org/2000/svg" | |
8 | xmlns="http://www.w3.org/2000/svg" | |
9 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
10 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
11 | width="210mm" | |
12 | height="297mm" | |
13 | viewBox="0 0 210 297" | |
14 | version="1.1" | |
15 | id="svg3990" | |
16 | inkscape:version="0.92.3 (2405546, 2018-03-11)" | |
17 | sodipodi:docname="background_cloud.svg"> | |
18 | <defs | |
19 | id="defs3984" /> | |
20 | <sodipodi:namedview | |
21 | id="base" | |
22 | pagecolor="#ffffff" | |
23 | bordercolor="#666666" | |
24 | borderopacity="1.0" | |
25 | inkscape:pageopacity="0.0" | |
26 | inkscape:pageshadow="2" | |
27 | inkscape:zoom="0.35" | |
28 | inkscape:cx="7.0210235" | |
29 | inkscape:cy="560" | |
30 | inkscape:document-units="mm" | |
31 | inkscape:current-layer="layer1" | |
32 | showgrid="false" | |
33 | inkscape:window-width="927" | |
34 | inkscape:window-height="1016" | |
35 | inkscape:window-x="993" | |
36 | inkscape:window-y="27" | |
37 | inkscape:window-maximized="0" /> | |
38 | <metadata | |
39 | id="metadata3987"> | |
40 | <rdf:RDF> | |
41 | <cc:Work | |
42 | rdf:about=""> | |
43 | <dc:format>image/svg+xml</dc:format> | |
44 | <dc:type | |
45 | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |
46 | <dc:title></dc:title> | |
47 | </cc:Work> | |
48 | </rdf:RDF> | |
49 | </metadata> | |
50 | <g | |
51 | inkscape:label="Layer 1" | |
52 | inkscape:groupmode="layer" | |
53 | id="layer1"> | |
54 | <circle | |
55 | r="7.9375" | |
56 | cy="54.603863" | |
57 | cx="89.136238" | |
58 | style="opacity:1;fill:#dbeff0;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
59 | id="path3241" | |
60 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_cloud.png" | |
61 | inkscape:export-xdpi="244.88148" | |
62 | inkscape:export-ydpi="244.88148" /> | |
63 | <circle | |
64 | r="6.2177081" | |
65 | cy="50.502834" | |
66 | cx="99.58728" | |
67 | style="opacity:1;fill:#c8e7ea;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
68 | id="path3243" | |
69 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_cloud.png" | |
70 | inkscape:export-xdpi="244.88148" | |
71 | inkscape:export-ydpi="244.88148" /> | |
72 | <circle | |
73 | r="5.1593752" | |
74 | cy="49.179913" | |
75 | cx="107.52478" | |
76 | style="opacity:1;fill:#e5fdff;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
77 | id="path3249" | |
78 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_cloud.png" | |
79 | inkscape:export-xdpi="244.88148" | |
80 | inkscape:export-ydpi="244.88148" /> | |
81 | <circle | |
82 | r="8.9296875" | |
83 | cy="54.273144" | |
84 | cx="125.31801" | |
85 | style="opacity:1;fill:#e5fdff;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
86 | id="path3257" | |
87 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_cloud.png" | |
88 | inkscape:export-xdpi="244.88148" | |
89 | inkscape:export-ydpi="244.88148" /> | |
90 | <circle | |
91 | r="10.451041" | |
92 | cy="60.424709" | |
93 | cx="103.29144" | |
94 | style="opacity:1;fill:#c9e9ef;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
95 | id="path3239" | |
96 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_cloud.png" | |
97 | inkscape:export-xdpi="244.88148" | |
98 | inkscape:export-ydpi="244.88148" /> | |
99 | <circle | |
100 | r="6.8791666" | |
101 | cy="66.245544" | |
102 | cx="94.295609" | |
103 | style="opacity:1;fill:#d7eef3;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
104 | id="path3247" | |
105 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_cloud.png" | |
106 | inkscape:export-xdpi="244.88148" | |
107 | inkscape:export-ydpi="244.88148" /> | |
108 | <circle | |
109 | r="7.8052082" | |
110 | cy="53.148663" | |
111 | cx="115.0654" | |
112 | style="opacity:1;fill:#ddf2f3;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
113 | id="path3237" | |
114 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_cloud.png" | |
115 | inkscape:export-xdpi="244.88148" | |
116 | inkscape:export-ydpi="244.88148" /> | |
117 | <circle | |
118 | r="7.4744792" | |
119 | cy="67.766891" | |
120 | cx="115.26384" | |
121 | style="opacity:1;fill:#dbeff3;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
122 | id="path3251" | |
123 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_cloud.png" | |
124 | inkscape:export-xdpi="244.88148" | |
125 | inkscape:export-ydpi="244.88148" /> | |
126 | <circle | |
127 | r="8.3343754" | |
128 | cy="62.673656" | |
129 | cx="120.88624" | |
130 | style="opacity:1;fill:#d3e8ec;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
131 | id="path3253" | |
132 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_cloud.png" | |
133 | inkscape:export-xdpi="244.88148" | |
134 | inkscape:export-ydpi="244.88148" /> | |
135 | </g> | |
136 | </svg> |
0 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
1 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | |
2 | ||
3 | <svg | |
4 | xmlns:dc="http://purl.org/dc/elements/1.1/" | |
5 | xmlns:cc="http://creativecommons.org/ns#" | |
6 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
7 | xmlns:svg="http://www.w3.org/2000/svg" | |
8 | xmlns="http://www.w3.org/2000/svg" | |
9 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
10 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
11 | width="210mm" | |
12 | height="297mm" | |
13 | viewBox="0 0 210 297" | |
14 | version="1.1" | |
15 | id="svg52" | |
16 | inkscape:version="0.92.3 (2405546, 2018-03-11)" | |
17 | sodipodi:docname="background_ground.svg"> | |
18 | <defs | |
19 | id="defs46" /> | |
20 | <sodipodi:namedview | |
21 | id="base" | |
22 | pagecolor="#ffffff" | |
23 | bordercolor="#666666" | |
24 | borderopacity="1.0" | |
25 | inkscape:pageopacity="0.0" | |
26 | inkscape:pageshadow="2" | |
27 | inkscape:zoom="0.35" | |
28 | inkscape:cx="-121.42857" | |
29 | inkscape:cy="560" | |
30 | inkscape:document-units="mm" | |
31 | inkscape:current-layer="layer1" | |
32 | showgrid="false" | |
33 | inkscape:window-width="927" | |
34 | inkscape:window-height="1016" | |
35 | inkscape:window-x="993" | |
36 | inkscape:window-y="27" | |
37 | inkscape:window-maximized="0" /> | |
38 | <metadata | |
39 | id="metadata49"> | |
40 | <rdf:RDF> | |
41 | <cc:Work | |
42 | rdf:about=""> | |
43 | <dc:format>image/svg+xml</dc:format> | |
44 | <dc:type | |
45 | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |
46 | <dc:title></dc:title> | |
47 | </cc:Work> | |
48 | </rdf:RDF> | |
49 | </metadata> | |
50 | <g | |
51 | inkscape:label="Layer 1" | |
52 | inkscape:groupmode="layer" | |
53 | id="layer1"> | |
54 | <path | |
55 | inkscape:connector-curvature="0" | |
56 | style="opacity:1;fill:#eeff39;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
57 | d="M -28.877379,153.8995 H 242.05595 V 86.166171 c -88.50674,22.518259 -171.413605,-17.010807 -270.933329,0 z" | |
58 | id="path3195" | |
59 | sodipodi:nodetypes="ccccc" | |
60 | inkscape:export-xdpi="180" | |
61 | inkscape:export-ydpi="180" /> | |
62 | <path | |
63 | inkscape:connector-curvature="0" | |
64 | sodipodi:nodetypes="ccccc" | |
65 | id="path3197" | |
66 | d="M -28.877379,153.8995 H 242.05595 v -47.52775 c -101.6,-8.912637 -162.059169,-3.9146 -270.933329,0 z" | |
67 | style="opacity:1;fill:#ffdc39;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" /> | |
68 | <path | |
69 | inkscape:connector-curvature="0" | |
70 | style="opacity:1;fill:#ffed39;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4.23333333, 4.23333333;stroke-dashoffset:0;stroke-opacity:1" | |
71 | d="M -28.877379,153.8995 H 242.05595 v -22.0837 c -101.6,8.67371 -162.059169,-3.91459 -270.933329,0 z" | |
72 | id="path3199" | |
73 | sodipodi:nodetypes="ccccc" /> | |
74 | <g | |
75 | id="g3226" | |
76 | transform="matrix(0.26458333,0,0,0.26458333,-40.821426,119.73046)" | |
77 | inkscape:export-xdpi="90" | |
78 | inkscape:export-ydpi="90"> | |
79 | <path | |
80 | inkscape:connector-curvature="0" | |
81 | id="path3207" | |
82 | d="m 479.10026,381.21815 -151.5226,135.76372 151.5226,81.29998 169.25958,-47.73819 z" | |
83 | style="opacity:1;fill:#e0a010;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
84 | <path | |
85 | inkscape:connector-curvature="0" | |
86 | sodipodi:nodetypes="cccc" | |
87 | id="path3201" | |
88 | d="M 640,547.38269 479.55512,386.86945 v 205.76807 z" | |
89 | style="opacity:1;fill:#ffed39;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
90 | <path | |
91 | inkscape:connector-curvature="0" | |
92 | style="opacity:1;fill:#ffdc39;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
93 | d="M 335.94408,515.56288 479.55512,386.86945 v 205.76807 z" | |
94 | id="path3205" | |
95 | sodipodi:nodetypes="cccc" /> | |
96 | <path | |
97 | inkscape:connector-curvature="0" | |
98 | style="opacity:1;fill:#e0a010;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
99 | d="m 546.63271,577.77289 28.88608,-8.14388 -17.01682,-33.38335 -24.82398,7.00499 z" | |
100 | id="path3224" | |
101 | sodipodi:nodetypes="ccccc" /> | |
102 | <path | |
103 | inkscape:connector-curvature="0" | |
104 | sodipodi:nodetypes="ccccc" | |
105 | id="path3219" | |
106 | d="m 549.75,572.82812 20.0625,-5.65624 -12.68701,-25.35645 -17.24121,4.86523 z" | |
107 | style="opacity:1;fill:#493c00;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
108 | </g> | |
109 | </g> | |
110 | </svg> |
0 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
1 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | |
2 | ||
3 | <svg | |
4 | xmlns:dc="http://purl.org/dc/elements/1.1/" | |
5 | xmlns:cc="http://creativecommons.org/ns#" | |
6 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
7 | xmlns:svg="http://www.w3.org/2000/svg" | |
8 | xmlns="http://www.w3.org/2000/svg" | |
9 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
10 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
11 | id="svg2" | |
12 | sodipodi:version="0.32" | |
13 | inkscape:version="0.92.3 (2405546, 2018-03-11)" | |
14 | width="1024" | |
15 | height="768" | |
16 | version="1.0" | |
17 | sodipodi:docname="background_sixteen_nine.svg" | |
18 | inkscape:export-filename="/home/qubodup/sf_games/blockattack-1.3.2/Game/gfx/background.png" | |
19 | inkscape:export-xdpi="90" | |
20 | inkscape:export-ydpi="90" | |
21 | inkscape:output_extension="org.inkscape.output.svg.inkscape"> | |
22 | <metadata | |
23 | id="metadata7"> | |
24 | <rdf:RDF> | |
25 | <cc:Work | |
26 | rdf:about=""> | |
27 | <dc:format>image/svg+xml</dc:format> | |
28 | <dc:type | |
29 | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |
30 | <dc:title></dc:title> | |
31 | </cc:Work> | |
32 | </rdf:RDF> | |
33 | </metadata> | |
34 | <defs | |
35 | id="defs5"> | |
36 | <inkscape:perspective | |
37 | sodipodi:type="inkscape:persp3d" | |
38 | inkscape:vp_x="0 : 526.18109 : 1" | |
39 | inkscape:vp_y="0 : 1000 : 0" | |
40 | inkscape:vp_z="744.09448 : 526.18109 : 1" | |
41 | inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |
42 | id="perspective9" /> | |
43 | <filter | |
44 | inkscape:collect="always" | |
45 | id="filter3189" | |
46 | x="-0.12" | |
47 | width="1.24" | |
48 | y="-0.12" | |
49 | height="1.24"> | |
50 | <feGaussianBlur | |
51 | inkscape:collect="always" | |
52 | stdDeviation="18.008276" | |
53 | id="feGaussianBlur3191" /> | |
54 | </filter> | |
55 | </defs> | |
56 | <sodipodi:namedview | |
57 | inkscape:window-height="1016" | |
58 | inkscape:window-width="1853" | |
59 | inkscape:pageshadow="2" | |
60 | inkscape:pageopacity="0.0" | |
61 | guidetolerance="10.0" | |
62 | gridtolerance="10.0" | |
63 | objecttolerance="10.0" | |
64 | borderopacity="1.0" | |
65 | bordercolor="#666666" | |
66 | pagecolor="#ffffff" | |
67 | id="base" | |
68 | showgrid="false" | |
69 | inkscape:zoom="0.5" | |
70 | inkscape:cx="22.28966" | |
71 | inkscape:cy="362.22947" | |
72 | inkscape:window-x="67" | |
73 | inkscape:window-y="27" | |
74 | inkscape:current-layer="svg2" | |
75 | inkscape:window-maximized="1"> | |
76 | <inkscape:grid | |
77 | type="xygrid" | |
78 | id="grid3193" | |
79 | visible="true" | |
80 | enabled="true" | |
81 | spacingx="128" | |
82 | spacingy="128" | |
83 | originx="0" | |
84 | originy="0" /> | |
85 | </sodipodi:namedview> | |
86 | <rect | |
87 | style="opacity:1;fill:#a1dbee;fill-opacity:1;stroke:none;stroke-width:18.47971916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:18.47971861, 18.47971861;stroke-dashoffset:0;stroke-opacity:1" | |
88 | id="rect3169" | |
89 | width="1366" | |
90 | height="768" | |
91 | x="-342" | |
92 | y="0" | |
93 | inkscape:export-xdpi="96" | |
94 | inkscape:export-ydpi="96" /> | |
95 | <g | |
96 | id="g3171" | |
97 | transform="translate(86,-52)"> | |
98 | <path | |
99 | sodipodi:type="arc" | |
100 | style="opacity:1;fill:#fff839;fill-opacity:0.65596331;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter3189)" | |
101 | id="path3179" | |
102 | sodipodi:cx="903.94482" | |
103 | sodipodi:cy="68.855171" | |
104 | sodipodi:rx="180.08276" | |
105 | sodipodi:ry="180.08276" | |
106 | d="M 1084.0276,68.855171 A 180.08276,180.08276 0 0 1 903.94482,248.93793 180.08276,180.08276 0 0 1 723.86206,68.855171 180.08276,180.08276 0 0 1 903.94482,-111.22759 180.08276,180.08276 0 0 1 1084.0276,68.855171 Z" | |
107 | transform="matrix(1.5261598,0,0,1.5261598,-456.19872,25.564281)" | |
108 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_sun.png" | |
109 | inkscape:export-xdpi="144.22725" | |
110 | inkscape:export-ydpi="144.22725" /> | |
111 | <path | |
112 | transform="translate(19.42069,61.793103)" | |
113 | d="M 1084.0276,68.855171 A 180.08276,180.08276 0 0 1 903.94482,248.93793 180.08276,180.08276 0 0 1 723.86206,68.855171 180.08276,180.08276 0 0 1 903.94482,-111.22759 180.08276,180.08276 0 0 1 1084.0276,68.855171 Z" | |
114 | sodipodi:ry="180.08276" | |
115 | sodipodi:rx="180.08276" | |
116 | sodipodi:cy="68.855171" | |
117 | sodipodi:cx="903.94482" | |
118 | id="path2384" | |
119 | style="opacity:1;fill:#ffec25;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
120 | sodipodi:type="arc" /> | |
121 | <path | |
122 | sodipodi:nodetypes="cscc" | |
123 | id="path2386" | |
124 | d="M 775.8067,156.28546 C 778.13701,224.70544 806.95117,280.78387 875.93545,280.78387 C 944.91971,280.78387 938.74719,255.91567 941.07749,187.49569 L 775.8067,156.28546 z" | |
125 | style="opacity:1;fill:#f77935;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
126 | <path | |
127 | transform="matrix(0.9262219,0,0,1,33.836039,-13.732501)" | |
128 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 0 1 837.68256,107.59153 23.719774,30.586025 0 0 1 813.96278,77.005501 23.719774,30.586025 0 0 1 837.68256,46.419476 23.719774,30.586025 0 0 1 861.40233,77.005501 Z" | |
129 | sodipodi:ry="30.586025" | |
130 | sodipodi:rx="23.719774" | |
131 | sodipodi:cy="77.005501" | |
132 | sodipodi:cx="837.68256" | |
133 | id="path3161" | |
134 | style="opacity:1;fill:#fffdb9;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
135 | sodipodi:type="arc" /> | |
136 | <path | |
137 | sodipodi:type="arc" | |
138 | style="opacity:1;fill:#fffdb9;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
139 | id="path3163" | |
140 | sodipodi:cx="837.68256" | |
141 | sodipodi:cy="77.005501" | |
142 | sodipodi:rx="23.719774" | |
143 | sodipodi:ry="30.586025" | |
144 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 0 1 837.68256,107.59153 23.719774,30.586025 0 0 1 813.96278,77.005501 23.719774,30.586025 0 0 1 837.68256,46.419476 23.719774,30.586025 0 0 1 861.40233,77.005501 Z" | |
145 | transform="matrix(0.9946296,0,0,1.1020408,71.785455,-0.9914533)" /> | |
146 | <path | |
147 | sodipodi:type="arc" | |
148 | style="opacity:1;fill:#132d6b;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
149 | id="path3165" | |
150 | sodipodi:cx="837.68256" | |
151 | sodipodi:cy="77.005501" | |
152 | sodipodi:rx="23.719774" | |
153 | sodipodi:ry="30.586025" | |
154 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 0 1 837.68256,107.59153 23.719774,30.586025 0 0 1 813.96278,77.005501 23.719774,30.586025 0 0 1 837.68256,46.419476 23.719774,30.586025 0 0 1 861.40233,77.005501 Z" | |
155 | transform="matrix(0.5510204,0,0,0.5510204,345.51635,33.013387)" /> | |
156 | <path | |
157 | transform="matrix(0.5773697,0,0,0.5878019,415.69998,50.683724)" | |
158 | d="M 861.40233,77.005501 A 23.719774,30.586025 0 0 1 837.68256,107.59153 23.719774,30.586025 0 0 1 813.96278,77.005501 23.719774,30.586025 0 0 1 837.68256,46.419476 23.719774,30.586025 0 0 1 861.40233,77.005501 Z" | |
159 | sodipodi:ry="30.586025" | |
160 | sodipodi:rx="23.719774" | |
161 | sodipodi:cy="77.005501" | |
162 | sodipodi:cx="837.68256" | |
163 | id="path3167" | |
164 | style="opacity:1;fill:#132d6b;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
165 | sodipodi:type="arc" /> | |
166 | </g> | |
167 | <path | |
168 | style="opacity:1;fill:#eeff39;fill-opacity:1;stroke:none;stroke-width:18.47971916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:18.47971861, 18.47971861;stroke-dashoffset:0;stroke-opacity:1" | |
169 | d="M -342,768 H 1024 V 512 c -446.23602,85.1084 -864.2384,-64.29281 -1366,0 z" | |
170 | id="path3195" | |
171 | sodipodi:nodetypes="ccccc" | |
172 | inkscape:connector-curvature="0" /> | |
173 | <path | |
174 | sodipodi:nodetypes="ccccc" | |
175 | id="path3197" | |
176 | d="M -342,768 H 1024 V 588.36753 c -512.25,-33.68554 -817.07493,-14.79533 -1366,0 z" | |
177 | style="opacity:1;fill:#ffdc39;fill-opacity:1;stroke:none;stroke-width:18.47971916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:18.47971861, 18.47971861;stroke-dashoffset:0;stroke-opacity:1" | |
178 | inkscape:connector-curvature="0" /> | |
179 | <path | |
180 | style="opacity:1;fill:#ffed39;fill-opacity:1;stroke:none;stroke-width:18.47971916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:18.47971861, 18.47971861;stroke-dashoffset:0;stroke-opacity:1" | |
181 | d="m -342,768 h 1366 v -83.46595 c -512.25,32.7825 -817.07493,-14.79533 -1366,0 z" | |
182 | id="path3199" | |
183 | sodipodi:nodetypes="ccccc" | |
184 | inkscape:connector-curvature="0" /> | |
185 | <g | |
186 | id="g3226" | |
187 | transform="translate(-562,120)" | |
188 | inkscape:export-xdpi="90" | |
189 | inkscape:export-ydpi="90"> | |
190 | <path | |
191 | id="path3207" | |
192 | d="m 479.10026,381.21815 -151.5226,135.76372 151.5226,81.29998 169.25958,-47.73819 z" | |
193 | style="opacity:1;fill:#e0a010;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
194 | inkscape:connector-curvature="0" /> | |
195 | <path | |
196 | sodipodi:nodetypes="cccc" | |
197 | id="path3201" | |
198 | d="M 640,547.38269 479.55512,386.86945 v 205.76807 z" | |
199 | style="opacity:1;fill:#ffed39;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
200 | inkscape:connector-curvature="0" /> | |
201 | <path | |
202 | style="opacity:1;fill:#ffdc39;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
203 | d="M 335.94408,515.56288 479.55512,386.86945 v 205.76807 z" | |
204 | id="path3205" | |
205 | sodipodi:nodetypes="cccc" | |
206 | inkscape:connector-curvature="0" /> | |
207 | <path | |
208 | style="opacity:1;fill:#e0a010;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
209 | d="m 546.63271,577.77289 28.88608,-8.14388 -17.01682,-33.38335 -24.82398,7.00499 z" | |
210 | id="path3224" | |
211 | sodipodi:nodetypes="ccccc" | |
212 | inkscape:connector-curvature="0" /> | |
213 | <path | |
214 | sodipodi:nodetypes="ccccc" | |
215 | id="path3219" | |
216 | d="m 549.75,572.82812 20.0625,-5.65624 -12.68701,-25.35645 -17.24121,4.86523 z" | |
217 | style="opacity:1;fill:#493c00;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
218 | inkscape:connector-curvature="0" /> | |
219 | </g> | |
220 | <path | |
221 | sodipodi:type="arc" | |
222 | style="opacity:1;fill:#dbeff0;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
223 | id="path3241" | |
224 | sodipodi:cx="164.5" | |
225 | sodipodi:cy="70" | |
226 | sodipodi:rx="30" | |
227 | sodipodi:ry="30" | |
228 | d="M 194.5,70 A 30,30 0 1 1 134.5,70 A 30,30 0 1 1 194.5,70 z" /> | |
229 | <path | |
230 | sodipodi:type="arc" | |
231 | style="opacity:1;fill:#c8e7ea;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
232 | id="path3243" | |
233 | sodipodi:cx="204" | |
234 | sodipodi:cy="54.5" | |
235 | sodipodi:rx="23.5" | |
236 | sodipodi:ry="23.5" | |
237 | d="M 227.5,54.5 A 23.5,23.5 0 1 1 180.5,54.5 A 23.5,23.5 0 1 1 227.5,54.5 z" /> | |
238 | <path | |
239 | sodipodi:type="arc" | |
240 | style="opacity:1;fill:#e5fdff;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
241 | id="path3249" | |
242 | sodipodi:cx="234" | |
243 | sodipodi:cy="49.5" | |
244 | sodipodi:rx="19.5" | |
245 | sodipodi:ry="19.5" | |
246 | d="M 253.5,49.5 A 19.5,19.5 0 1 1 214.5,49.5 A 19.5,19.5 0 1 1 253.5,49.5 z" /> | |
247 | <path | |
248 | sodipodi:type="arc" | |
249 | style="opacity:1;fill:#e5fdff;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
250 | id="path3257" | |
251 | sodipodi:cx="301.25" | |
252 | sodipodi:cy="68.75" | |
253 | sodipodi:rx="33.75" | |
254 | sodipodi:ry="33.75" | |
255 | d="M 335,68.75 A 33.75,33.75 0 1 1 267.5,68.75 A 33.75,33.75 0 1 1 335,68.75 z" /> | |
256 | <path | |
257 | sodipodi:type="arc" | |
258 | style="opacity:1;fill:#c9e9ef;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
259 | id="path3239" | |
260 | sodipodi:cx="218" | |
261 | sodipodi:cy="92" | |
262 | sodipodi:rx="39.5" | |
263 | sodipodi:ry="39.5" | |
264 | d="M 257.5,92 A 39.5,39.5 0 1 1 178.5,92 A 39.5,39.5 0 1 1 257.5,92 z" /> | |
265 | <path | |
266 | sodipodi:type="arc" | |
267 | style="opacity:1;fill:#d7eef3;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
268 | id="path3247" | |
269 | sodipodi:cx="184" | |
270 | sodipodi:cy="114" | |
271 | sodipodi:rx="26" | |
272 | sodipodi:ry="26" | |
273 | d="M 210,114 A 26,26 0 1 1 158,114 A 26,26 0 1 1 210,114 z" /> | |
274 | <path | |
275 | sodipodi:type="arc" | |
276 | style="opacity:1;fill:#ddf2f3;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
277 | id="path3237" | |
278 | sodipodi:cx="262.5" | |
279 | sodipodi:cy="64.5" | |
280 | sodipodi:rx="29.5" | |
281 | sodipodi:ry="29.5" | |
282 | d="M 292,64.5 A 29.5,29.5 0 1 1 233,64.5 A 29.5,29.5 0 1 1 292,64.5 z" /> | |
283 | <path | |
284 | sodipodi:type="arc" | |
285 | style="opacity:1;fill:#dbeff3;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
286 | id="path3251" | |
287 | sodipodi:cx="263.25" | |
288 | sodipodi:cy="119.75" | |
289 | sodipodi:rx="28.25" | |
290 | sodipodi:ry="28.25" | |
291 | d="M 291.5,119.75 A 28.25,28.25 0 1 1 235,119.75 A 28.25,28.25 0 1 1 291.5,119.75 z" /> | |
292 | <path | |
293 | sodipodi:type="arc" | |
294 | style="opacity:1;fill:#d3e8ec;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
295 | id="path3253" | |
296 | sodipodi:cx="284.5" | |
297 | sodipodi:cy="100.5" | |
298 | sodipodi:rx="31.5" | |
299 | sodipodi:ry="31.5" | |
300 | d="M 316,100.5 A 31.5,31.5 0 1 1 253,100.5 A 31.5,31.5 0 1 1 316,100.5 z" /> | |
301 | <g | |
302 | inkscape:export-ydpi="90" | |
303 | inkscape:export-xdpi="90" | |
304 | transform="translate(-244,60)" | |
305 | id="g88"> | |
306 | <path | |
307 | inkscape:connector-curvature="0" | |
308 | style="opacity:1;fill:#e0a010;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
309 | d="m 479.10026,381.21815 -151.5226,135.76372 151.5226,81.29998 169.25958,-47.73819 z" | |
310 | id="path78" /> | |
311 | <path | |
312 | inkscape:connector-curvature="0" | |
313 | style="opacity:1;fill:#ffed39;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
314 | d="M 640,547.38269 479.55512,386.86945 v 205.76807 z" | |
315 | id="path80" | |
316 | sodipodi:nodetypes="cccc" /> | |
317 | <path | |
318 | inkscape:connector-curvature="0" | |
319 | sodipodi:nodetypes="cccc" | |
320 | id="path82" | |
321 | d="M 335.94408,515.56288 479.55512,386.86945 v 205.76807 z" | |
322 | style="opacity:1;fill:#ffdc39;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
323 | <path | |
324 | inkscape:connector-curvature="0" | |
325 | sodipodi:nodetypes="ccccc" | |
326 | id="path84" | |
327 | d="m 546.63271,577.77289 28.88608,-8.14388 -17.01682,-33.38335 -24.82398,7.00499 z" | |
328 | style="opacity:1;fill:#e0a010;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
329 | <path | |
330 | inkscape:connector-curvature="0" | |
331 | style="opacity:1;fill:#493c00;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
332 | d="m 549.75,572.82812 20.0625,-5.65624 -12.68701,-25.35645 -17.24121,4.86523 z" | |
333 | id="path86" | |
334 | sodipodi:nodetypes="ccccc" /> | |
335 | </g> | |
336 | <circle | |
337 | id="path90" | |
338 | style="opacity:1;fill:#dbeff0;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
339 | cx="-163.5" | |
340 | cy="150" | |
341 | r="30" /> | |
342 | <circle | |
343 | id="path92" | |
344 | style="opacity:1;fill:#c8e7ea;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
345 | cx="-124" | |
346 | cy="134.5" | |
347 | r="23.5" /> | |
348 | <circle | |
349 | id="path94" | |
350 | style="opacity:1;fill:#e5fdff;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
351 | cx="-94" | |
352 | cy="129.5" | |
353 | r="19.5" /> | |
354 | <circle | |
355 | id="path96" | |
356 | style="opacity:1;fill:#e5fdff;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
357 | cx="-26.75" | |
358 | cy="148.75" | |
359 | r="33.75" /> | |
360 | <circle | |
361 | id="path98" | |
362 | style="opacity:1;fill:#c9e9ef;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
363 | cx="-110" | |
364 | cy="172" | |
365 | r="39.5" /> | |
366 | <circle | |
367 | id="path100" | |
368 | style="opacity:1;fill:#d7eef3;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
369 | cx="-144" | |
370 | cy="194" | |
371 | r="26" /> | |
372 | <circle | |
373 | id="path102" | |
374 | style="opacity:1;fill:#ddf2f3;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
375 | cx="-65.5" | |
376 | cy="144.5" | |
377 | r="29.5" /> | |
378 | <circle | |
379 | id="path104" | |
380 | style="opacity:1;fill:#dbeff3;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
381 | cx="-64.75" | |
382 | cy="199.75" | |
383 | r="28.25" /> | |
384 | <circle | |
385 | id="path106" | |
386 | style="opacity:1;fill:#d3e8ec;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
387 | cx="-43.5" | |
388 | cy="180.5" | |
389 | r="31.5" /> | |
390 | </svg> |
0 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
1 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | |
2 | ||
3 | <svg | |
4 | xmlns:dc="http://purl.org/dc/elements/1.1/" | |
5 | xmlns:cc="http://creativecommons.org/ns#" | |
6 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
7 | xmlns:svg="http://www.w3.org/2000/svg" | |
8 | xmlns="http://www.w3.org/2000/svg" | |
9 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
10 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
11 | width="210mm" | |
12 | height="297mm" | |
13 | viewBox="0 0 210 297" | |
14 | version="1.1" | |
15 | id="svg3885" | |
16 | inkscape:version="0.92.3 (2405546, 2018-03-11)" | |
17 | sodipodi:docname="sun.svg"> | |
18 | <defs | |
19 | id="defs3879"> | |
20 | <filter | |
21 | inkscape:collect="always" | |
22 | id="filter3189-3" | |
23 | x="-0.12" | |
24 | width="1.24" | |
25 | y="-0.12" | |
26 | height="1.24"> | |
27 | <feGaussianBlur | |
28 | inkscape:collect="always" | |
29 | stdDeviation="18.008276" | |
30 | id="feGaussianBlur3191-6" /> | |
31 | </filter> | |
32 | </defs> | |
33 | <sodipodi:namedview | |
34 | id="base" | |
35 | pagecolor="#ffffff" | |
36 | bordercolor="#666666" | |
37 | borderopacity="1.0" | |
38 | inkscape:pageopacity="0.0" | |
39 | inkscape:pageshadow="2" | |
40 | inkscape:zoom="0.35" | |
41 | inkscape:cx="289.38896" | |
42 | inkscape:cy="560" | |
43 | inkscape:document-units="mm" | |
44 | inkscape:current-layer="layer1" | |
45 | showgrid="false" | |
46 | inkscape:window-width="927" | |
47 | inkscape:window-height="1016" | |
48 | inkscape:window-x="993" | |
49 | inkscape:window-y="27" | |
50 | inkscape:window-maximized="0" /> | |
51 | <metadata | |
52 | id="metadata3882"> | |
53 | <rdf:RDF> | |
54 | <cc:Work | |
55 | rdf:about=""> | |
56 | <dc:format>image/svg+xml</dc:format> | |
57 | <dc:type | |
58 | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |
59 | <dc:title></dc:title> | |
60 | </cc:Work> | |
61 | </rdf:RDF> | |
62 | </metadata> | |
63 | <g | |
64 | inkscape:label="Layer 1" | |
65 | inkscape:groupmode="layer" | |
66 | id="layer1"> | |
67 | <g | |
68 | id="g3171" | |
69 | transform="matrix(0.26458333,0,0,0.26458333,-145.27737,57.569548)" | |
70 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_sun.png" | |
71 | inkscape:export-xdpi="144.23" | |
72 | inkscape:export-ydpi="144.23"> | |
73 | <circle | |
74 | r="180.08276" | |
75 | cy="68.855171" | |
76 | cx="903.94482" | |
77 | style="opacity:1;fill:#fff839;fill-opacity:0.65596331;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter3189-3)" | |
78 | id="path3179-7" | |
79 | transform="matrix(1.5261598,0,0,1.5261598,-456.19872,25.564281)" | |
80 | inkscape:export-filename="/home/poul/programmering/git/blockattack-game/Game/data/textures/background_sun.png" | |
81 | inkscape:export-xdpi="144.22725" | |
82 | inkscape:export-ydpi="144.22725" /> | |
83 | <circle | |
84 | r="180.08276" | |
85 | cy="68.855171" | |
86 | cx="903.94482" | |
87 | transform="translate(19.42069,61.793103)" | |
88 | id="path2384" | |
89 | style="opacity:1;fill:#ffec25;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
90 | <path | |
91 | inkscape:connector-curvature="0" | |
92 | sodipodi:nodetypes="cscc" | |
93 | id="path2386" | |
94 | d="m 775.8067,156.28546 c 2.33031,68.41998 31.14447,124.49841 100.12875,124.49841 68.98426,0 62.81174,-24.8682 65.14204,-93.28818 z" | |
95 | style="opacity:1;fill:#f77935;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
96 | <ellipse | |
97 | ry="30.586025" | |
98 | rx="23.719774" | |
99 | cy="77.005501" | |
100 | cx="837.68256" | |
101 | transform="matrix(0.9262219,0,0,1,33.836039,-13.732501)" | |
102 | id="path3161" | |
103 | style="opacity:1;fill:#fffdb9;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
104 | <ellipse | |
105 | ry="30.586025" | |
106 | rx="23.719774" | |
107 | cy="77.005501" | |
108 | cx="837.68256" | |
109 | style="opacity:1;fill:#fffdb9;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
110 | id="path3163" | |
111 | transform="matrix(0.9946296,0,0,1.1020408,71.785455,-0.9914533)" /> | |
112 | <ellipse | |
113 | ry="30.586025" | |
114 | rx="23.719774" | |
115 | cy="77.005501" | |
116 | cx="837.68256" | |
117 | style="opacity:1;fill:#132d6b;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" | |
118 | id="path3165" | |
119 | transform="matrix(0.5510204,0,0,0.5510204,345.51635,33.013387)" /> | |
120 | <ellipse | |
121 | ry="30.586025" | |
122 | rx="23.719774" | |
123 | cy="77.005501" | |
124 | cx="837.68256" | |
125 | transform="matrix(0.5773697,0,0,0.5878019,415.69998,50.683724)" | |
126 | id="path3167" | |
127 | style="opacity:1;fill:#132d6b;fill-opacity:1;stroke:none;stroke-width:16;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:16, 16;stroke-dashoffset:0;stroke-opacity:1" /> | |
128 | </g> | |
129 | </g> | |
130 | </svg> |
153 | 153 | baseSpeed=0.5; |
154 | 154 | break; |
155 | 155 | case 1: |
156 | baseSpeed=0.4; | |
156 | baseSpeed=0.1; | |
157 | 157 | break; |
158 | 158 | case 2: |
159 | baseSpeed=0.3; | |
159 | baseSpeed=0.07; | |
160 | 160 | break; |
161 | 161 | case 3: |
162 | baseSpeed=0.25; | |
162 | baseSpeed=0.04; | |
163 | 163 | break; |
164 | 164 | case 4: |
165 | baseSpeed=0.2; | |
165 | baseSpeed=0.015; | |
166 | 166 | break; |
167 | 167 | default: |
168 | baseSpeed=0.15; | |
168 | baseSpeed=0.005; | |
169 | 169 | break; |
170 | 170 | }; |
171 | 171 | } |
268 | 268 | if (s.AI) { |
269 | 269 | recordStats = false; |
270 | 270 | } |
271 | NewGame(s.ticks); | |
271 | NewGameInternal(s.ticks); | |
272 | 272 | if (s.timeTrial) { |
273 | 273 | timetrial = true; |
274 | 274 | putStartBlocks(); |
332 | 332 | } |
333 | 333 | if (s.gameSpeed > 0) { |
334 | 334 | setGameSpeed(s.gameSpeed); |
335 | speed = baseSpeed; | |
335 | 336 | } |
336 | 337 | } |
337 | 338 | |
338 | 339 | //Instead of creating new object new game is called, to prevent memory leaks |
339 | void BlockGame::NewGame( unsigned int ticks) { | |
340 | void BlockGame::NewGameInternal( unsigned int ticks) { | |
340 | 341 | this->ticks = ticks; |
341 | 342 | stageButtonStatus = SBdontShow; |
342 | 343 | nrFellDown = 0; |
1292 | 1293 | /////////////////////////////////////////////////////////////////////////// |
1293 | 1294 | //First the helpet functions: |
1294 | 1295 | int BlockGame::nrOfType(int line, int type) { |
1295 | // cout << "Start_ nrOfType" << "\n"; | |
1296 | 1296 | int counter = 0; |
1297 | 1297 | for (int i=0; i<6; i++) |
1298 | 1298 | if (board[i][line]==type) { |
1304 | 1304 | |
1305 | 1305 | //See if a combo can be made in this line |
1306 | 1306 | int BlockGame::horiInLine(int line) { |
1307 | //cout << "Start_ hori in line" << "\n"; | |
1308 | 1307 | int nrOfType[7] = {0, 0, 0, 0, 0, 0, 0}; |
1309 | 1308 | int max = 0; |
1310 | 1309 | for (int i=0; i<6; i++) { |
1323 | 1322 | } |
1324 | 1323 | |
1325 | 1324 | bool BlockGame::horiClearPossible() { |
1326 | //cout << "Start_ horiclear possible" << "\n"; | |
1327 | 1325 | int i=13; |
1328 | 1326 | bool solutionFound = false; |
1329 | 1327 | do { |
1350 | 1348 | |
1351 | 1349 | //Types 0..6 in line |
1352 | 1350 | int BlockGame::nrOfRealTypes(int line) { |
1353 | //cout << "Start_ nrOfReal" << "\n"; | |
1354 | 1351 | int counter = 0; |
1355 | 1352 | for (int i=0; i<6; i++) { |
1356 | 1353 | if ((board[i][line]>-1)&&(board[i][line]<7)) { |
1362 | 1359 | |
1363 | 1360 | //See if there is a tower |
1364 | 1361 | bool BlockGame::ThereIsATower() { |
1365 | //cout << "Start_ there is a tower" << "\n"; | |
1366 | 1362 | bool bThereIsATower = false; //Unless proven otherwise! |
1367 | 1363 | bool topReached = false; //If we have reached the top |
1368 | 1364 | int lineNumber = 0; |
1391 | 1387 | } |
1392 | 1388 | } |
1393 | 1389 | while ((!bThereIsATower)&&(!topReached)); |
1394 | //if(bThereIsATower) | |
1395 | //cout << "There is actually a tower" << "\n"; | |
1396 | 1390 | return bThereIsATower; |
1397 | 1391 | } |
1398 | 1392 | |
1439 | 1433 | |
1440 | 1434 | //The AI will remove a tower |
1441 | 1435 | void BlockGame::AI_ClearTower() { |
1442 | // cout << "AI: ClearTower, line: " << AIlineToClear << "\n"; | |
1443 | 1436 | int place = (int)firstInLine(AIlineToClear-1, -1); //Find an empty field to frop a brick into |
1444 | 1437 | int xplace = closestTo(AIlineToClear, place); //Find the brick to drop in it |
1445 | 1438 | if (cursory+1<AIlineToClear) { |
1464 | 1457 | |
1465 | 1458 | //The AI will try to clear block horisontally |
1466 | 1459 | void BlockGame::AI_ClearHori() { |
1467 | // cout << "AI: ClearHori"; | |
1468 | 1460 | int lowestLine = AIlineToClear; |
1469 | 1461 | for (int i=0; i<7; i++) { |
1470 | 1462 | if (nrOfType(lowestLine, i)>2) { |
1499 | 1491 | } |
1500 | 1492 | int xplace = 0; |
1501 | 1493 | if (left<right) { |
1502 | // cout << ", right>left"; | |
1503 | 1494 | int count=0; |
1504 | 1495 | for (int i=0; (i<4)&&(count<1); i++) { |
1505 | 1496 | if ((board[i][lowestLine]==AIcolorToClear)&&((i==0)||(board[i+1][lowestLine]!=AIcolorToClear))) { |
1509 | 1500 | } |
1510 | 1501 | } |
1511 | 1502 | else { |
1512 | // cout << ", left>=right"; | |
1513 | 1503 | int count=0; |
1514 | 1504 | for (int i=3; (i<=5)&&(count<1); i++) { |
1515 | 1505 | if ((board[i][lowestLine]==AIcolorToClear)&&(board[i-1][lowestLine]!=AIcolorToClear)) { |
1518 | 1508 | } |
1519 | 1509 | } |
1520 | 1510 | } |
1521 | //cout << ", xplace: " << xplace; | |
1522 | 1511 | if (cursorx<xplace) { |
1523 | 1512 | MoveCursor('E'); |
1524 | 1513 | } |
1535 | 1524 | else { |
1536 | 1525 | AIstatus = 0; |
1537 | 1526 | } |
1538 | //cout << "\n"; //for debugging | |
1539 | 1527 | } |
1540 | 1528 | |
1541 | 1529 | //Test if vertical clear is possible |
1575 | 1563 | |
1576 | 1564 | //The AI will try to clear blocks vertically |
1577 | 1565 | void BlockGame::AI_ClearVertical() { |
1578 | // cout << "AI: ClearVeri"; | |
1579 | 1566 | //First we find the place there we will align the bricks |
1580 | 1567 | int placeToCenter = (int)(firstInLine(AIlineToClear, AIcolorToClear)/3.0+firstInLine(AIlineToClear+1, AIcolorToClear)/3.0+firstInLine(AIlineToClear+2, AIcolorToClear)/3.0); |
1581 | 1568 | int unlimitedLoop=0; |
1587 | 1574 | cerr << "placeToCenter out of range: " << placeToCenter << "\n"; |
1588 | 1575 | return; |
1589 | 1576 | } |
1590 | //cout << "AI_ClearVertical: " << placeToCenter << ", " << AIlineToClear << "\n"; | |
1591 | 1577 | while (((board[placeToCenter][AIlineToClear]>1000000)||(board[placeToCenter][AIlineToClear+1]>1000000)||(board[placeToCenter][AIlineToClear+2]>1000000))&&(unlimitedLoop<10)) { |
1592 | 1578 | unlimitedLoop++; |
1593 | 1579 | placeToCenter++; |
1599 | 1585 | AIstatus = 0; |
1600 | 1586 | return; |
1601 | 1587 | } |
1602 | //cout << ", ptc: " << placeToCenter << ", line: " << AIlineToClear << ", cy: " << cursory; | |
1603 | 1588 | if (cursory+1>AIlineToClear+2) { |
1604 | // cout << ", cursory>line+2"; | |
1605 | 1589 | MoveCursor('S'); |
1606 | 1590 | } |
1607 | 1591 | if (cursory+1<AIlineToClear) { |
1617 | 1601 | if (board[placeToCenter][AIlineToClear+2]==AIcolorToClear) { |
1618 | 1602 | toAlign[2]=false; |
1619 | 1603 | } |
1620 | //cout << "status: " << toAlign[0] << " " << toAlign[1] << " " << toAlign[2]; | |
1621 | 1604 | if (cursory+1==AIlineToClear) { |
1622 | 1605 | if (toAlign[0]==false) { |
1623 | 1606 | MoveCursor('N'); |
1678 | 1661 | if ((nrOfType(AIlineToClear, AIcolorToClear)==0)||(nrOfType(AIlineToClear+1, AIcolorToClear)==0)||(nrOfType(AIlineToClear+2, AIcolorToClear)==0)) { |
1679 | 1662 | AIstatus = 0; |
1680 | 1663 | } |
1681 | //cout << "\n"; | |
1682 | 1664 | } |
1683 | 1665 | |
1684 | 1666 | |
1781 | 1763 | |
1782 | 1764 | //increse speed: |
1783 | 1765 | if ((nowTime>gameStartedAt+20000*speedLevel)&&(speedLevel <99)&&(!bGameOver)) { |
1784 | speed = (baseSpeed*0.9)/((double)speedLevel*0.5); | |
1766 | speed = (baseSpeed*0.9)/((double)speedLevel*0.8); | |
1785 | 1767 | speedLevel++; |
1786 | 1768 | nrPushedPixel=(int)((double)(nowTime-gameStartedAt)/(1000.0*speed)); |
1787 | 1769 | } |
57 | 57 | bool AI = false; |
58 | 58 | /** |
59 | 59 | * True means that stats will be recorded. |
60 | * If AI is true then this will be overruled to false | |
60 | * If AI is true then this will be overruled to false | |
61 | 61 | */ |
62 | 62 | bool recordStats = true; |
63 | 63 | bool vsMode = false; |
71 | 71 | template <class Archive> |
72 | 72 | void serialize( Archive & ar ) |
73 | 73 | { |
74 | ar( CEREAL_NVP(ticks), CEREAL_NVP(timeTrial), CEREAL_NVP(stageClear), CEREAL_NVP(puzzleMode), CEREAL_NVP(singlePuzzle), | |
75 | CEREAL_NVP(level), CEREAL_NVP(AI), CEREAL_NVP(recordStats), CEREAL_NVP(vsMode), CEREAL_NVP(vsAI), | |
74 | ar( CEREAL_NVP(ticks), CEREAL_NVP(timeTrial), CEREAL_NVP(stageClear), CEREAL_NVP(puzzleMode), CEREAL_NVP(singlePuzzle), | |
75 | CEREAL_NVP(level), CEREAL_NVP(AI), CEREAL_NVP(recordStats), CEREAL_NVP(vsMode), CEREAL_NVP(vsAI), | |
76 | 76 | CEREAL_NVP(startBlocks), CEREAL_NVP(handicap), CEREAL_NVP(gameSpeed) ); |
77 | 77 | } |
78 | 78 | }; |
158 | 158 | int Level = 0; //Only used in stageClear and puzzle (not implemented) |
159 | 159 | |
160 | 160 | BlockGameInfo replayInfo; |
161 | ||
161 | ||
162 | 162 | int rand2(); |
163 | 163 | int firstUnusedChain(); |
164 | 164 | |
165 | //public: | |
166 | 165 | protected: |
167 | 166 | int lastCounter = 0; |
168 | 167 | std::string strHolder; |
199 | 198 | bool vsAI = false; //Set to true for single player vs |
200 | 199 | |
201 | 200 | int handicap = 0; |
202 | ||
201 | ||
203 | 202 | std::vector<GarbageStruct> garbageSendQueue; |
204 | 203 | |
205 | 204 | int AIlineToClear = 0; |
217 | 216 | virtual ~BlockGame() = default; |
218 | 217 | |
219 | 218 | int getAIlevel() const; |
220 | ||
219 | ||
221 | 220 | virtual void AddText(int, int, unsigned int, int) const {} |
222 | 221 | virtual void AddBall(int, int, bool, int) const {} |
223 | 222 | virtual void AddExplosion(int, int) const {} |
227 | 226 | virtual void LongChainDoneEvent() const {} |
228 | 227 | virtual void TimeTrialEndEvent() const {} |
229 | 228 | virtual void EndlessHighscoreEvent() const {} |
230 | ||
229 | ||
231 | 230 | void NewGame(const BlockGameStartInfo &s); |
232 | 231 | void DoAction (const BlockGameAction& action); |
233 | 232 | /** |
237 | 236 | * @param poppedData |
238 | 237 | */ |
239 | 238 | void PopSendGarbage(std::vector<GarbageStruct>& poppedData); |
240 | ||
239 | ||
241 | 240 | int GetScore() const; |
242 | 241 | int GetHandicap() const; |
243 | 242 | bool isGameOver() const; |
261 | 260 | int getLevel() const; |
262 | 261 | bool GetAIenabled() const; |
263 | 262 | bool IsNearDeath() const; |
263 | double GetBaseSpeed() const { return baseSpeed; } | |
264 | 264 | const BlockGameInfo& GetBlockGameInfo() { |
265 | 265 | return replayInfo; |
266 | 266 | } |
267 | 267 | private: |
268 | void NewGame(unsigned int ticks); | |
268 | void NewGameInternal(unsigned int ticks); | |
269 | 269 | //Test if LineNr is an empty line, returns false otherwise. |
270 | 270 | bool LineEmpty(int lineNr) const; |
271 | 271 | //Test if the entire board is empty (used for Puzzles) |
307 | 307 | bool CreateGarbage(int wide, int height); |
308 | 308 | //Creates garbage using a given wide and height |
309 | 309 | bool CreateGreyGarbage(); |
310 | void MouseDown(int x, int y); //Send then the mouse is pressed | |
310 | void MouseDown(int x, int y); //Send then the mouse is pressed | |
311 | 311 | void MouseMove(int x); //Send then the mouse moves |
312 | 312 | void MouseUp(); //Send then the mouse goes up |
313 | 313 | void MoveCursorTo(int x, int y); |
34 | 34 | public: |
35 | 35 | DialogBox(int x, int y, const std::string& name, const std::string& header); |
36 | 36 | DialogBox(const DialogBox& orig) = delete; |
37 | DialogBox& operator=(const DialogBox& orig) = delete; | |
37 | 38 | virtual ~DialogBox(); |
38 | ||
39 | ||
39 | 40 | bool IsActive() override; |
40 | 41 | void Draw(SDL_Renderer* target) override; |
41 | 42 | void ProcessInput(const SDL_Event& event, bool &processed) override; |
45 | 46 | private: |
46 | 47 | bool isActive = true; |
47 | 48 | std::shared_ptr<ReadKeyboard> rk; |
48 | int x; | |
49 | int x; | |
49 | 50 | int y; |
50 | 51 | std::string name; |
51 | 52 | std::string header; |
26 | 26 | #include "MenuSystem.h" |
27 | 27 | #include "sstream" |
28 | 28 | #include "version.h" |
29 | #include "sago/SagoMisc.hpp" | |
29 | 30 | |
30 | const int xsize = 1024; | |
31 | const int ysize = 768; | |
32 | 31 | const int buttonOffset = 160; |
33 | 32 | extern sago::SagoSprite bExit; |
34 | 33 | |
53 | 52 | field.SetText(text); |
54 | 53 | } |
55 | 54 | |
56 | static SDL_RendererInfo renderInfo; | |
55 | ||
56 | ||
57 | 57 | |
58 | 58 | HelpAboutState::HelpAboutState() { |
59 | SDL_RendererInfo renderInfo; | |
60 | SDL_version compiled; | |
61 | SDL_version linked; | |
59 | 62 | SDL_GetRendererInfo(globalData.screen, &renderInfo); |
63 | SDL_VERSION(&compiled); | |
64 | SDL_GetVersion(&linked); | |
65 | const char* audio_driver_name = SDL_GetCurrentAudioDriver(); | |
66 | if (!audio_driver_name) { | |
67 | audio_driver_name = _("No audio driver"); | |
68 | } | |
60 | 69 | std::stringstream infoStream; |
61 | 70 | infoStream << _("Name:") << " " << _("Block Attack - Rise of the Blocks") << "\n"; |
62 | 71 | infoStream << _("Original name:") << " Block Attack - Rise of the Blocks" << "\n"; |
64 | 73 | infoStream << _("Homepage:") << " " << "https://blockattack.net\n"; |
65 | 74 | infoStream << _("Github page:") << " " << "https://github.com/blockattack/blockattack-game\n"; |
66 | 75 | infoStream << _("SDL render:") << " " << renderInfo.name << "\n"; |
76 | infoStream << _("SDL audio driver:") << " " << audio_driver_name << "\n"; | |
77 | infoStream << _("SDL compiled version:") << " " << (int)compiled.major << "." << (int)compiled.minor << "." << (int)compiled.patch << "\n"; | |
78 | infoStream << _("SDL linked version:") << " " << (int)linked.major << "." << (int)linked.minor << "." << (int)linked.patch << "\n"; | |
67 | 79 | infoStream << _("Save folder:") << " " << PHYSFS_getWriteDir() << "\n"; |
68 | 80 | infoStream << _("Locale:") << " " << setlocale( LC_CTYPE, nullptr ) << "\n"; |
69 | 81 | setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), titleField, _("About")); |
70 | 82 | setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), infoBox, infoStream.str().c_str()); |
83 | sago::WriteFileContent("about.txt", infoStream.str()); | |
71 | 84 | } |
72 | 85 | |
73 | 86 | HelpAboutState::~HelpAboutState() { |
95 | 108 | DrawRectYellow(target, 40, 90, 600, 900); |
96 | 109 | infoBox.SetMaxWidth(850); |
97 | 110 | infoBox.Draw(target, 50, 100); |
98 | bExit.Draw(globalData.screen, SDL_GetTicks(), xsize-buttonOffset, ysize-buttonOffset); | |
111 | bExit.Draw(globalData.screen, SDL_GetTicks(), globalData.xsize-buttonOffset, globalData.ysize-buttonOffset); | |
99 | 112 | #if DEBUG |
100 | 113 | static sago::SagoTextField mousePos; |
101 | 114 | mousePos.SetHolder(&globalData.spriteHolder->GetDataHolder()); |
116 | 129 | bMouseUp = false; |
117 | 130 | |
118 | 131 | //The Score button: |
119 | if ((globalData.mousex>xsize-buttonOffset) && (globalData.mousex<xsize-buttonOffset+bExit.GetWidth()) | |
120 | && (globalData.mousey>ysize-buttonOffset) && (globalData.mousey<ysize-buttonOffset+bExit.GetHeight())) { | |
132 | if ((globalData.mousex>globalData.xsize-buttonOffset) && (globalData.mousex<globalData.xsize-buttonOffset+bExit.GetWidth()) | |
133 | && (globalData.mousey>globalData.ysize-buttonOffset) && (globalData.mousey<globalData.ysize-buttonOffset+bExit.GetHeight())) { | |
121 | 134 | isActive = false; |
122 | 135 | } |
123 | 136 |
26 | 26 | #include "MenuSystem.h" |
27 | 27 | #include "gamecontroller.h" |
28 | 28 | |
29 | const int xsize = 1024; | |
30 | const int ysize = 768; | |
31 | 29 | const int buttonOffset = 160; |
32 | 30 | |
33 | 31 | static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) { |
84 | 82 | |
85 | 83 | extern sago::SagoSprite bExit; |
86 | 84 | |
85 | #define OFFSETX (-512+globalData.xsize/2) | |
86 | ||
87 | 87 | void HelpGamepadState::Draw(SDL_Renderer* target) { |
88 | 88 | DrawBackground(target); |
89 | 89 | const sago::SagoSprite& gamepad = globalData.spriteHolder->GetSprite("help_controller"); |
90 | 90 | gamepad.Draw(target, SDL_GetTicks(), globalData.xsize/2-480/2, 100); |
91 | SDL_RenderDrawLine(target, 100, 210, globalData.xsize/2-480/2+130, 210); | |
92 | SDL_RenderDrawLine(target, 100, 298, globalData.xsize/2-480/2+158, 298); | |
93 | SDL_RenderDrawLine(target, 100, 210, 100, 400); | |
94 | moveLabel.Draw(target, 100, 404, sago::SagoTextField::Alignment::center); | |
91 | SDL_RenderDrawLine(target, 100+OFFSETX, 210, globalData.xsize/2-480/2+130, 210); | |
92 | SDL_RenderDrawLine(target, 100+OFFSETX, 298, globalData.xsize/2-480/2+158, 298); | |
93 | SDL_RenderDrawLine(target, 100+OFFSETX, 210, 100+OFFSETX, 400); | |
94 | moveLabel.Draw(target, 100+OFFSETX, 404, sago::SagoTextField::Alignment::center); | |
95 | 95 | //Push lines |
96 | 96 | SDL_RenderDrawLine(target, globalData.xsize/2-480/2+140, 90, globalData.xsize/2-480/2+140, 105); |
97 | 97 | SDL_RenderDrawLine(target, globalData.xsize/2+480/2-140, 90, globalData.xsize/2+480/2-140, 105); |
101 | 101 | SDL_RenderDrawLine(target, globalData.xsize/2, 80, globalData.xsize/2, 90); |
102 | 102 | pushLabel.Draw(target, globalData.xsize/2, 80, sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::bottom); |
103 | 103 | //Back lines |
104 | SDL_RenderDrawLine(target, 625, 168, 800, 168); | |
105 | SDL_RenderDrawLine(target, 800, 158, 800, 195); | |
106 | SDL_RenderDrawLine(target, 490, 195, 800, 195); | |
107 | backLabel.Draw(target, 800, 156, sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::bottom); | |
108 | SDL_RenderDrawLine(target, 625, 241, 900, 241); | |
109 | SDL_RenderDrawLine(target, 663, 207, 900, 207); | |
110 | SDL_RenderDrawLine(target, 900, 207, 900, 400); | |
111 | switchLabel.Draw(target, 900, 404, sago::SagoTextField::Alignment::center); | |
112 | confirmLabel.Draw(target, 900, 404+30, sago::SagoTextField::Alignment::center); | |
113 | bExit.Draw(globalData.screen, SDL_GetTicks(), xsize-buttonOffset, ysize-buttonOffset); | |
104 | SDL_RenderDrawLine(target, 625+OFFSETX, 168, 800+OFFSETX, 168); | |
105 | SDL_RenderDrawLine(target, 800+OFFSETX, 158, 800+OFFSETX, 195); | |
106 | SDL_RenderDrawLine(target, 490+OFFSETX, 195, 800+OFFSETX, 195); | |
107 | backLabel.Draw(target, 800+OFFSETX, 156, sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::bottom); | |
108 | SDL_RenderDrawLine(target, 625+OFFSETX, 241, 900+OFFSETX, 241); | |
109 | SDL_RenderDrawLine(target, 663+OFFSETX, 207, 900+OFFSETX, 207); | |
110 | SDL_RenderDrawLine(target, 900+OFFSETX, 207, 900+OFFSETX, 400); | |
111 | switchLabel.Draw(target, 900+OFFSETX, 404, sago::SagoTextField::Alignment::center); | |
112 | confirmLabel.Draw(target, 900+OFFSETX, 404+30, sago::SagoTextField::Alignment::center); | |
113 | bExit.Draw(globalData.screen, SDL_GetTicks(), globalData.xsize-buttonOffset, globalData.ysize-buttonOffset); | |
114 | 114 | supportedControllers.Draw(target, 10, 600); |
115 | 115 | |
116 | 116 | #if DEBUG |
133 | 133 | bMouseUp = false; |
134 | 134 | |
135 | 135 | //The Score button: |
136 | if ((globalData.mousex>xsize-buttonOffset) && (globalData.mousex<xsize-buttonOffset+bExit.GetWidth()) | |
137 | && (globalData.mousey>ysize-buttonOffset) && (globalData.mousey<ysize-buttonOffset+bExit.GetHeight())) { | |
136 | if ((globalData.mousex>globalData.xsize-buttonOffset) && (globalData.mousex<globalData.xsize-buttonOffset+bExit.GetWidth()) | |
137 | && (globalData.mousey>globalData.ysize-buttonOffset) && (globalData.mousey<globalData.ysize-buttonOffset+bExit.GetHeight())) { | |
138 | 138 | isActive = false; |
139 | 139 | } |
140 | 140 |
26 | 26 | #include "MenuSystem.h" |
27 | 27 | #include <cmath> |
28 | 28 | |
29 | const int xsize = 1024; | |
30 | const int ysize = 768; | |
31 | 29 | const int buttonOffset = 160; |
32 | 30 | extern sago::SagoSprite bExit; |
33 | 31 | extern sago::SagoSprite bricks[7]; |
199 | 197 | DrawArrow(target, 600, 600, 650, 600); |
200 | 198 | DrawArrow(target, 525, 525, 525, 675); |
201 | 199 | chainField.Draw(target, 400, 710, sago::SagoTextField::Alignment::center); |
202 | bExit.Draw(globalData.screen, SDL_GetTicks(), xsize-buttonOffset, ysize-buttonOffset); | |
200 | bExit.Draw(globalData.screen, SDL_GetTicks(), globalData.xsize-buttonOffset, globalData.ysize-buttonOffset); | |
203 | 201 | #if DEBUG |
204 | 202 | static sago::SagoTextField mousePos; |
205 | 203 | mousePos.SetHolder(&globalData.spriteHolder->GetDataHolder()); |
220 | 218 | bMouseUp = false; |
221 | 219 | |
222 | 220 | //The Score button: |
223 | if ((globalData.mousex>xsize-buttonOffset) && (globalData.mousex<xsize-buttonOffset+bExit.GetWidth()) | |
224 | && (globalData.mousey>ysize-buttonOffset) && (globalData.mousey<ysize-buttonOffset+bExit.GetHeight())) { | |
221 | if ((globalData.mousex>globalData.xsize-buttonOffset) && (globalData.mousex<globalData.xsize-buttonOffset+bExit.GetWidth()) | |
222 | && (globalData.mousey>globalData.ysize-buttonOffset) && (globalData.mousey<globalData.ysize-buttonOffset+bExit.GetHeight())) { | |
225 | 223 | isActive = false; |
226 | 224 | } |
227 | 225 |
16 | 16 | along with this program. If not, see http://www.gnu.org/licenses/ |
17 | 17 | |
18 | 18 | Source information and contacts persons can be found at |
19 | http://www.blockattack.net | |
19 | https://blockattack.net | |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 | |
30 | 30 | static int oldmousex = 0; |
31 | 31 | static int oldmousey = 0; |
32 | 32 | |
33 | using std::string; | |
34 | using std::cerr; | |
35 | using std::cout; | |
36 | using std::vector; | |
37 | ||
38 | 33 | const char* const menu_marked = "menu_marked"; |
39 | 34 | const char* const menu_unmarked = "menu_unmarked"; |
40 | 35 | |
44 | 39 | this->xsize = globalData.spriteHolder->GetSprite(menu_marked).GetWidth(); |
45 | 40 | this->ysize = globalData.spriteHolder->GetSprite(menu_marked).GetHeight(); |
46 | 41 | if (globalData.verboseLevel) { |
47 | cout << "Surfaces set, size: " << this->xsize << " , " << this->ysize << "\n"; | |
42 | std::cout << "Surfaces set, size: " << this->xsize << " , " << this->ysize << "\n"; | |
48 | 43 | } |
49 | 44 | } |
50 | 45 | |
73 | 68 | Button::~Button() { |
74 | 69 | } |
75 | 70 | |
76 | Button::Button(const Button& b) { | |
77 | label = b.label; | |
78 | marked = b.marked; | |
79 | action = b.action; | |
80 | popOnRun = false; | |
81 | } | |
82 | ||
83 | void Button::setLabel(const string& text) { | |
71 | Button::Button(const Button& b) : action{b.action}, label{b.label}, marked{b.marked} { | |
72 | } | |
73 | ||
74 | Button& Button::operator=(const Button& other) { | |
75 | action = other.action; | |
76 | label = other.label; | |
77 | marked = other.marked; | |
78 | return *this; | |
79 | } | |
80 | ||
81 | void Button::setLabel(const std::string& text) { | |
84 | 82 | label = text; |
85 | 83 | } |
86 | 84 | |
93 | 91 | action(); |
94 | 92 | return; |
95 | 93 | } |
96 | cerr << "Warning: button \"" << label << "\" has no action assigned!"; | |
94 | std::cerr << "Warning: button \"" << label << "\" has no action assigned!"; | |
97 | 95 | } |
98 | 96 | |
99 | 97 | void Button::setPopOnRun(bool popOnRun) { |
114 | 112 | |
115 | 113 | standardButton.getLabel(b.label)->Draw(globalData.screen, b.x+standardButton.xsize/2,b.y+standardButton.ysize/2, |
116 | 114 | sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::center); |
117 | //standardButton.thefont->drawCenterAlsoHeight(globalData.screen, b.x+standardButton.xsize/2,b.y+standardButton.ysize/2, b.label); | |
118 | 115 | } |
119 | 116 | |
120 | 117 | |
156 | 153 | |
157 | 154 | Menu::Menu(SDL_Renderer* screen) { |
158 | 155 | this->screen = screen; |
159 | buttons = vector<Button*>(10); | |
156 | buttons = std::vector<Button*>(10); | |
160 | 157 | isSubmenu = true; |
161 | 158 | exit.setLabel( _("Back") ); |
162 | 159 | } |
163 | 160 | |
164 | 161 | Menu::Menu(SDL_Renderer* screen,bool submenu) { |
165 | 162 | this->screen = screen; |
166 | buttons = vector<Button*>(0); | |
163 | buttons = std::vector<Button*>(0); | |
167 | 164 | isSubmenu = submenu; |
168 | 165 | if (isSubmenu) { |
169 | 166 | exit.setLabel( _("Back") ); |
173 | 170 | } |
174 | 171 | } |
175 | 172 | |
176 | Menu::Menu(SDL_Renderer* screen, const string& title, bool submenu) { | |
173 | Menu::Menu(SDL_Renderer* screen, const std::string& title, bool submenu) : title{title} { | |
177 | 174 | this->screen = screen; |
178 | buttons = vector<Button*>(0); | |
175 | buttons = std::vector<Button*>(0); | |
179 | 176 | isSubmenu = submenu; |
180 | this->title = title; | |
181 | 177 | if (isSubmenu) { |
182 | 178 | exit.setLabel(_("Back") ); |
183 | 179 | } |
359 | 355 | } |
360 | 356 | |
361 | 357 | if (isConfirmEvent(event)) { |
358 | bMouseUp = false; | |
362 | 359 | if (marked < (int)buttons.size()) { |
363 | 360 | buttons.at(marked)->doAction(); |
364 | 361 | if (buttons.at(marked)->isPopOnRun()) { |
68 | 68 | |
69 | 69 | Button(); |
70 | 70 | Button(const Button& b); |
71 | Button& operator=(const Button& other); | |
71 | 72 | virtual ~Button(); |
72 | 73 | |
73 | 74 |
0 | 0 | /* |
1 | 1 | =========================================================================== |
2 | 2 | blockattack - Block Attack - Rise of the Blocks |
3 | Copyright (C) 2005-2012 Poul Sander | |
3 | Copyright (C) 2005-2018 Poul Sander | |
4 | 4 | |
5 | 5 | This program is free software: you can redistribute it and/or modify |
6 | 6 | it under the terms of the GNU General Public License as published by |
16 | 16 | along with this program. If not, see http://www.gnu.org/licenses/ |
17 | 17 | |
18 | 18 | Source information and contacts persons can be found at |
19 | http://blockattack.net | |
19 | https://blockattack.net | |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 | |
23 | 23 | #include "ReadKeyboard.h" |
24 | 24 | #include "utf8.h" |
25 | 25 | #include <iostream> |
26 | ||
27 | using std::string; | |
28 | using std::cerr; | |
29 | 26 | |
30 | 27 | ReadKeyboard::ReadKeyboard(void) { |
31 | 28 | maxLength = 16; |
39 | 36 | return std::distance(text_string.begin(), position); |
40 | 37 | } |
41 | 38 | |
42 | ReadKeyboard::ReadKeyboard(const char* oldName) { | |
43 | maxLength = 16; | |
44 | text_string = oldName; | |
39 | ReadKeyboard::ReadKeyboard(const char* oldName) : maxLength(16), text_string(oldName) { | |
45 | 40 | position = text_string.end(); |
46 | 41 | } |
47 | 42 | |
59 | 54 | |
60 | 55 | void ReadKeyboard::removeChar() { |
61 | 56 | if (position < text_string.end()) { |
62 | string::iterator endChar= position; | |
57 | std::string::iterator endChar= position; | |
63 | 58 | utf8::advance(endChar, 1, text_string.end()); |
64 | 59 | text_string.erase(position, endChar); |
65 | 60 | } |
29 | 29 | |
30 | 30 | |
31 | 31 | /*static void MoveBlockGameSdls( BlockGameSdl& game1, BlockGameSdl& game2 ) { |
32 | game1.SetTopXY(50, globalData.ysize/2-284); | |
33 | game2.SetTopXY(globalData.xsize-500, globalData.ysize/2-284); | |
32 | game1.SetTopXY(globalData.xsize/2-416, globalData.ysize/2-284); | |
33 | game2.SetTopXY(globalData.xsize/2+40, globalData.ysize/2-284); | |
34 | 34 | }*/ |
35 | 35 | |
36 | 36 |
26 | 26 | #include "stats.h" |
27 | 27 | #include "MenuSystem.h" |
28 | 28 | |
29 | using std::string; | |
30 | using std::cerr; | |
31 | using std::vector; | |
29 | const int buttonOffsetX = 140; | |
30 | const int buttonOffsetY = 180; | |
31 | extern sago::SagoSprite bExit; | |
32 | 32 | |
33 | 33 | static void setButtonFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) { |
34 | 34 | field.SetHolder(holder); |
54 | 54 | getCachedText(text)->Draw(target, x, y); |
55 | 55 | } |
56 | 56 | |
57 | const int numberOfPages = 3; | |
57 | const int numberOfPages = 7; | |
58 | 58 | |
59 | 59 | void ScoresDisplay::DrawBackgroundAndCalcPlacements() { |
60 | 60 | DrawBackground(globalData.screen); |
64 | 64 | } |
65 | 65 | |
66 | 66 | //Draws the highscores |
67 | void ScoresDisplay::DrawHighscores(int x, int y, bool endless) { | |
67 | void ScoresDisplay::DrawHighscores(int x, int y, bool endless, int level = 0) { | |
68 | 68 | DrawBackgroundAndCalcPlacements(); |
69 | 69 | if (endless) { |
70 | Write(globalData.screen, x+100,y+100, _("Endless:") ); | |
70 | std::string header; | |
71 | switch (level) { | |
72 | case 1: | |
73 | header = _("Endless (Fast):"); | |
74 | break; | |
75 | case 2: | |
76 | header = _("Endless (Faster):"); | |
77 | break; | |
78 | case 3: | |
79 | header = _("Endless (Even faster):"); | |
80 | break; | |
81 | case 4: | |
82 | header = _("Endless (Fastest):"); | |
83 | break; | |
84 | default: | |
85 | header = _("Endless:"); | |
86 | }; | |
87 | Write(globalData.screen, x+100,y+100, header.c_str() ); | |
71 | 88 | } |
72 | 89 | else { |
73 | 90 | Write(globalData.screen, x+100,y+100, _("Time Trial:") ); |
75 | 92 | for (int i =0; i<10; i++) { |
76 | 93 | record r; |
77 | 94 | if (endless) { |
78 | r = globalData.theTopScoresEndless.getScoreNumber(i); | |
95 | switch(level) { | |
96 | case 1: | |
97 | r = theTopScoresEndless1.getScoreNumber(i); | |
98 | break; | |
99 | case 2: | |
100 | r = theTopScoresEndless2.getScoreNumber(i); | |
101 | break; | |
102 | case 3: | |
103 | r = theTopScoresEndless3.getScoreNumber(i); | |
104 | break; | |
105 | case 4: | |
106 | r = theTopScoresEndless4.getScoreNumber(i); | |
107 | break; | |
108 | default: | |
109 | r = theTopScoresEndless0.getScoreNumber(i); | |
110 | } | |
79 | 111 | } |
80 | 112 | else { |
81 | r = globalData.theTopScoresTimeTrial.getScoreNumber(i); | |
113 | r = theTopScoresTimeTrial.getScoreNumber(i); | |
82 | 114 | } |
83 | 115 | char playerScore[32]; |
84 | 116 | char playerName[32]; |
99 | 131 | for (int i=2; i<13; i++) { |
100 | 132 | y+=y_spacing; |
101 | 133 | Write(globalData.screen, 10,y,(std::to_string(i)+"X").c_str()); |
102 | string numberAsString = std::to_string(Stats::getInstance()->getNumberOf("chainX"+std::to_string(i))); | |
134 | std::string numberAsString = std::to_string(Stats::getInstance()->getNumberOf("chainX"+std::to_string(i))); | |
103 | 135 | Write(globalData.screen, 300,y,numberAsString.c_str()); |
104 | 136 | } |
105 | 137 | y+=y_spacing*2; |
106 | 138 | Write(globalData.screen, 10,y,_("Lines Pushed: ") ); |
107 | string numberAsString = std::to_string(Stats::getInstance()->getNumberOf("linesPushed")); | |
139 | std::string numberAsString = std::to_string(Stats::getInstance()->getNumberOf("linesPushed")); | |
108 | 140 | Write(globalData.screen, 300,y,numberAsString.c_str()); |
109 | 141 | |
110 | 142 | y+=y_spacing; |
142 | 174 | Write(globalData.screen, x_offset,y, _("VS CPU (win/loss)") ); |
143 | 175 | for (int i=0; i<7; i++) { |
144 | 176 | y += y_spacing; |
145 | Write(globalData.screen, x_offset,y,string("AI "+std::to_string(i+1)).c_str()); | |
177 | Write(globalData.screen, x_offset,y,std::string("AI "+std::to_string(i+1)).c_str()); | |
146 | 178 | numberAsString = std::to_string(Stats::getInstance()->getNumberOf("defeatedAI"+std::to_string(i))); |
147 | string numberAsString2 = std::to_string(Stats::getInstance()->getNumberOf("defeatedByAI"+std::to_string(i))); | |
148 | string toPrint = numberAsString + "/" + numberAsString2; | |
179 | std::string numberAsString2 = std::to_string(Stats::getInstance()->getNumberOf("defeatedByAI"+std::to_string(i))); | |
180 | std::string toPrint = numberAsString + "/" + numberAsString2; | |
149 | 181 | Write(globalData.screen, x_offset+230,y,toPrint.c_str()); |
150 | 182 | } |
151 | 183 | } |
162 | 194 | |
163 | 195 | void ScoresDisplay::Draw(SDL_Renderer*) { |
164 | 196 | switch (page) { |
165 | case 0: | |
166 | //Highscores, endless | |
167 | DrawHighscores(100,100,true); | |
168 | break; | |
169 | case 1: | |
170 | //Highscores, Time Trial | |
171 | DrawHighscores(100,100,false); | |
172 | break; | |
173 | case 2: | |
174 | default: | |
175 | DrawStats(); | |
197 | case 0: | |
198 | case 1: | |
199 | case 2: | |
200 | case 3: | |
201 | case 4: | |
202 | //Highscores, endless | |
203 | DrawHighscores(100,100,true, page); | |
204 | break; | |
205 | case 5: | |
206 | //Highscores, Time Trial | |
207 | DrawHighscores(100,100,false); | |
208 | break; | |
209 | case 6: | |
210 | default: | |
211 | DrawStats(); | |
176 | 212 | }; |
177 | 213 | |
178 | 214 | const sago::SagoDataHolder* holder = &globalData.spriteHolder->GetDataHolder(); |
179 | 215 | //Draw buttons: |
180 | globalData.bHighScore.Draw(globalData.screen, 0, scoreX,scoreY); | |
216 | bExit.Draw(globalData.screen, SDL_GetTicks(), globalData.xsize-buttonOffsetX, globalData.ysize-buttonOffsetY); | |
181 | 217 | globalData.bBack.Draw(globalData.screen, 0, backX, backY); |
182 | 218 | static sago::SagoTextField backLabel; |
183 | 219 | setButtonFont(holder, backLabel, _("Back")); |
188 | 224 | nextLabel.Draw(globalData.screen, nextX+60, nextY+10, sago::SagoTextField::Alignment::center); |
189 | 225 | |
190 | 226 | //Draw page number |
191 | string pageXofY = SPrintStringF(_("Page %i of %i"), page+1, numberOfPages); | |
227 | std::string pageXofY = SPrintStringF(_("Page %i of %i"), page+1, numberOfPages); | |
192 | 228 | getCachedText(pageXofY)->Draw(globalData.screen, globalData.xsize/2, globalData.ysize-60, sago::SagoTextField::Alignment::center); |
193 | 229 | } |
194 | 230 | |
196 | 232 | |
197 | 233 | UpdateMouseCoordinates(event, globalData.mousex, globalData.mousey); |
198 | 234 | |
199 | if (isLeftEvent(event)) { | |
235 | if (isRightEvent(event)) { | |
200 | 236 | page++; |
201 | 237 | if (page>=numberOfPages) { |
202 | 238 | page = 0; |
204 | 240 | processed = true; |
205 | 241 | } |
206 | 242 | |
207 | if (isRightEvent(event)) { | |
243 | if (isLeftEvent(event)) { | |
208 | 244 | page--; |
209 | 245 | if (page<0) { |
210 | 246 | page = numberOfPages-1; |
227 | 263 | if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) { |
228 | 264 | bMouseUp = false; |
229 | 265 | |
230 | //The Score button: | |
231 | if ((globalData.mousex>scoreX) && (globalData.mousex<scoreX+buttonXsize) && (globalData.mousey>scoreY) && (globalData.mousey<scoreY+buttonYsize)) { | |
266 | //The Exit button: | |
267 | if ((globalData.mousex>globalData.xsize-buttonOffsetX) && (globalData.mousex<globalData.xsize-buttonOffsetX+bExit.GetWidth()) | |
268 | && (globalData.mousey>globalData.ysize-buttonOffsetY) && (globalData.mousey<globalData.ysize-buttonOffsetY+bExit.GetHeight())) { | |
232 | 269 | isActive = false; |
233 | 270 | } |
234 | 271 |
27 | 27 | #include "sago/SagoTextField.hpp" |
28 | 28 | #include <map> |
29 | 29 | #include <memory> |
30 | #include "highscore.h" | |
30 | 31 | |
31 | 32 | class ScoresDisplay : public sago::GameStateInterface { |
32 | 33 | public: |
45 | 46 | int scoreY = 0; |
46 | 47 | int buttonXsize = 0; |
47 | 48 | int buttonYsize = 0; |
49 | Highscore theTopScoresEndless0 = Highscore("endless", 0.5); //Stores highscores for endless | |
50 | Highscore theTopScoresEndless1 = Highscore("endless", 0.1); //Stores highscores for endless | |
51 | Highscore theTopScoresEndless2 = Highscore("endless", 0.07); //Stores highscores for endless | |
52 | Highscore theTopScoresEndless3 = Highscore("endless", 0.04); //Stores highscores for endless | |
53 | Highscore theTopScoresEndless4 = Highscore("endless", 0.015); //Stores highscores for endless | |
54 | Highscore theTopScoresTimeTrial = Highscore("timetrial", 0.5); //Stores highscores for timetrial | |
48 | 55 | private: |
49 | void DrawHighscores(int x, int y, bool endless); | |
56 | void DrawHighscores(int x, int y, bool endless, int speedLevel); | |
50 | 57 | void DrawStats(); |
51 | 58 | void DrawBackgroundAndCalcPlacements(); |
52 | 59 | void Write(SDL_Renderer* target, int x, int y, const char* text); |
21 | 21 | #include "common.h" |
22 | 22 | #include "MenuSystem.h" |
23 | 23 | |
24 | const int xsize = 1024; | |
25 | const int ysize = 768; | |
26 | 24 | const int buttonOffset = 160; |
27 | 25 | extern sago::SagoSprite bExit; |
28 | 26 | |
78 | 76 | infoBox.Draw(target, 50, 100); |
79 | 77 | DrawRectYellow(target, 40, 700, 50, 900); |
80 | 78 | filenameField.Draw(target, 50, 715); |
81 | bExit.Draw(globalData.screen, SDL_GetTicks(), xsize-buttonOffset, ysize-buttonOffset); | |
79 | bExit.Draw(globalData.screen, SDL_GetTicks(), globalData.xsize-buttonOffset, globalData.ysize-buttonOffset); | |
82 | 80 | #if DEBUG |
83 | 81 | static sago::SagoTextField mousePos; |
84 | 82 | mousePos.SetHolder(&globalData.spriteHolder->GetDataHolder()); |
99 | 97 | bMouseUp = false; |
100 | 98 | |
101 | 99 | //The Score button: |
102 | if ((globalData.mousex>xsize-buttonOffset) && (globalData.mousex<xsize-buttonOffset+bExit.GetWidth()) | |
103 | && (globalData.mousey>ysize-buttonOffset) && (globalData.mousey<ysize-buttonOffset+bExit.GetHeight())) { | |
100 | if ((globalData.mousex>globalData.xsize-buttonOffset) && (globalData.mousex<globalData.xsize-buttonOffset+bExit.GetWidth()) | |
101 | && (globalData.mousey>globalData.ysize-buttonOffset) && (globalData.mousey<globalData.ysize-buttonOffset+bExit.GetHeight())) { | |
104 | 102 | isActive = false; |
105 | 103 | } |
106 | 104 |
16 | 16 | along with this program. If not, see http://www.gnu.org/licenses/ |
17 | 17 | |
18 | 18 | Source information and contacts persons can be found at |
19 | http://www.blockattack.net | |
19 | https://blockattack.net | |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 | |
28 | 28 | #include "sago/SagoMisc.hpp" |
29 | 29 | #include <stdarg.h> |
30 | 30 | |
31 | using std::string; | |
32 | using std::stringstream; | |
33 | using std::cerr; | |
34 | using std::map; | |
35 | using std::vector; | |
36 | 31 | |
37 | 32 | bool strequals(const char* a, const char* b) { |
38 | 33 | return strcmp(a,b) == 0; |
44 | 39 | } |
45 | 40 | } |
46 | 41 | |
47 | double str2double(const string& str2parse) { | |
42 | double str2double(const std::string& str2parse) { | |
48 | 43 | try { |
49 | 44 | return std::stod(str2parse); |
50 | 45 | } |
73 | 68 | return buffer; |
74 | 69 | } |
75 | 70 | |
76 | int str2int(const string& str2parse) { | |
71 | int str2int(const std::string& str2parse) { | |
77 | 72 | try { |
78 | 73 | return std::stoi(str2parse); |
79 | 74 | } |
97 | 92 | return ct; |
98 | 93 | } |
99 | 94 | |
100 | commonTime TimeHandler::getTime(const string& name) { | |
95 | commonTime TimeHandler::getTime(const std::string& name) { | |
101 | 96 | commonTime ct; |
102 | 97 | ct.days = Config::getInstance()->getInt(name+"Days"); |
103 | 98 | ct.hours = Config::getInstance()->getInt(name+"Hours"); |
110 | 105 | * Returns the total runtime with toAdd added but without writing it to config file. |
111 | 106 | * Used for stats |
112 | 107 | */ |
113 | commonTime TimeHandler::peekTime(const string& name, const commonTime& toAdd) { | |
108 | commonTime TimeHandler::peekTime(const std::string& name, const commonTime& toAdd) { | |
114 | 109 | commonTime ct = getTime(name); |
115 | 110 | |
116 | 111 | ct.seconds +=toAdd.seconds; |
133 | 128 | * Same as peekTotalTime but writes the time to the config file. |
134 | 129 | * Should only be called only once! when the program shuts down |
135 | 130 | */ |
136 | commonTime TimeHandler::addTime(const string& name, const commonTime& toAdd) { | |
131 | commonTime TimeHandler::addTime(const std::string& name, const commonTime& toAdd) { | |
137 | 132 | commonTime ct = peekTime(name,toAdd); |
138 | 133 | |
139 | 134 | Config::getInstance()->setInt(name+"Days",ct.days); |
152 | 147 | } |
153 | 148 | |
154 | 149 | void Config::load() { |
155 | string filecontent = sago::GetFileContent("configFile"); | |
156 | stringstream inFile(filecontent); | |
157 | string key; | |
158 | string previuskey; | |
150 | std::string filecontent = sago::GetFileContent("configFile"); | |
151 | std::stringstream inFile(filecontent); | |
152 | std::string key; | |
153 | std::string previuskey; | |
159 | 154 | if (inFile) { |
160 | 155 | while (!inFile.eof()) { |
161 | 156 | inFile >> key; |
167 | 162 | std::string value; |
168 | 163 | std::getline(inFile, value); |
169 | 164 | #if DEBUG |
170 | cerr << "Config read: " << key << " with:\"" << value << "\"" << "\n"; | |
165 | std::cerr << "Config read: " << key << " with:\"" << value << "\"" << "\n"; | |
171 | 166 | #endif |
172 | 167 | configMap[key] = value; |
173 | 168 | } |
184 | 179 | |
185 | 180 | void Config::save() { |
186 | 181 | std::stringstream outFile; |
187 | map<string,string>::iterator iter; | |
182 | std::map<std::string,std::string>::iterator iter; | |
188 | 183 | for (iter = configMap.begin(); iter != configMap.end(); ++iter) { |
189 | 184 | outFile << iter->first << " " << iter->second << "\n"; |
190 | 185 | } |
193 | 188 | sago::WriteFileContent("configFile", outFile.str()); |
194 | 189 | } |
195 | 190 | |
196 | bool Config::exists(const string& varName) const { | |
191 | bool Config::exists(const std::string& varName) const { | |
197 | 192 | //Using that find returns an iterator to the end of the map if not found |
198 | 193 | return configMap.find(varName) != configMap.end(); |
199 | 194 | } |
200 | 195 | |
201 | void Config::setDefault(const string& varName,const string& content) { | |
196 | void Config::setDefault(const std::string& varName,const std::string& content) { | |
202 | 197 | if (exists(varName)) { |
203 | 198 | return; //Already exists do not change |
204 | 199 | } |
213 | 208 | return shuttingDown; |
214 | 209 | } |
215 | 210 | |
216 | void Config::setString(const string& varName, const string& content) { | |
211 | void Config::setString(const std::string& varName, const std::string& content) { | |
217 | 212 | configMap[varName] = content; |
218 | 213 | } |
219 | 214 | |
220 | void Config::setInt(const string& varName, int content) { | |
215 | void Config::setInt(const std::string& varName, int content) { | |
221 | 216 | configMap[varName] = std::to_string(content); |
222 | 217 | } |
223 | 218 | |
224 | void Config::setValue(const string& varName,double content) { | |
219 | void Config::setValue(const std::string& varName,double content) { | |
225 | 220 | configMap[varName] = std::to_string(content); |
226 | 221 | } |
227 | 222 | |
228 | string Config::getString(const string& varName) { | |
223 | std::string Config::getString(const std::string& varName) { | |
229 | 224 | if (exists(varName)) { |
230 | 225 | return configMap[varName]; |
231 | 226 | } |
234 | 229 | } |
235 | 230 | } |
236 | 231 | |
237 | int Config::getInt(const string& varName) { | |
232 | int Config::getInt(const std::string& varName) { | |
238 | 233 | if (exists(varName)) { |
239 | 234 | return str2int(configMap[varName]); |
240 | 235 | } |
243 | 238 | } |
244 | 239 | } |
245 | 240 | |
246 | double Config::getValue(const string& varName) { | |
241 | double Config::getValue(const std::string& varName) { | |
247 | 242 | if (exists(varName)) { |
248 | 243 | return str2double(configMap[varName]); |
249 | 244 | } |
16 | 16 | along with this program. If not, see http://www.gnu.org/licenses/ |
17 | 17 | |
18 | 18 | Source information and contacts persons can be found at |
19 | http://www.blockattack.net | |
19 | https://blockattack.net | |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 | |
23 | 23 | /* |
24 | 24 | *This is the common.h |
25 | *It contains some basic functions that nearly all multiplatform games are going | |
25 | *It contains some basic functions that nearly all multi platform games are going | |
26 | 26 | *to need. |
27 | 27 | */ |
28 | 28 | |
51 | 51 | |
52 | 52 | /** |
53 | 53 | * str2int parses a string and returns an int with the value of the string. |
54 | * if the string is not an int then 0 is returned instead of throing an error | |
55 | * in that way this function will always return a useable value. | |
54 | * if the string is not an int then 0 is returned instead of throwing an error | |
55 | * in that way this function will always return a usable value. | |
56 | 56 | */ |
57 | 57 | int str2int(const std::string &str2parse) __attribute__((const)); |
58 | 58 | |
60 | 60 | |
61 | 61 | /** |
62 | 62 | * str2double parses a string and returns a double with the value of the string. |
63 | * if the string is not a double then 0.0 is returned instead of throing an error | |
64 | * in that way this function will always return a useable value. | |
63 | * if the string is not a double then 0.0 is returned instead of throwing an error | |
64 | * in that way this function will always return a usable value. | |
65 | 65 | */ |
66 | 66 | double str2double(const std::string &str2parse) __attribute__((const)); |
67 | 67 | |
68 | 68 | /** |
69 | * Does the eqivilent to snprintf but returns a C++ string | |
69 | * Does the equivalent to snprintf but returns a C++ string | |
70 | 70 | * @param fmt The format string |
71 | * @param ... Additional paremeters for the place holders | |
71 | * @param ... Additional parameters for the place holders | |
72 | 72 | * @return A string with the result |
73 | 73 | */ |
74 | 74 | std::string SPrintStringF(const char* fmt, ...) __attribute__ ((format (printf, 1, 2))); |
77 | 77 | * Prints to an internal C-buffer |
78 | 78 | * Because it uses an internal buffer the returned buffer is only valid until the next call |
79 | 79 | * The String is cut at 1024 chars (including the 0 terminator) |
80 | * This is the larges string that can safely be parsed to NFont | |
81 | 80 | * @param fmt The format string |
82 | * @param ... Additional paremeters for the place holders | |
81 | * @param ... Additional parameters for the place holders | |
83 | 82 | * @return Pointer to an internal buffer |
84 | 83 | */ |
85 | 84 | const char* SPrintCF(const char* fmt, ...) __attribute__ ((format (printf, 1, 2))); |
115 | 114 | |
116 | 115 | /* tells if the user has requested a shutdown */ |
117 | 116 | long shuttingDown = 0; |
118 | protected: | |
119 | 117 | |
120 | 118 | Config(); |
121 | 119 | |
123 | 121 | public: |
124 | 122 | /*Config is a singleton. |
125 | 123 | *It is accessed like this: |
126 | *Config::getInstance()->method2call(paramters); | |
124 | *Config::getInstance()->method2call(parameters); | |
127 | 125 | */ |
128 | 126 | static Config* getInstance(); |
129 | 127 | |
173 | 171 | * starts so that it can see that it has to import configs from an earlier |
174 | 172 | * version. |
175 | 173 | * @param varName Name of the variable |
176 | * @return true if the varaible exists | |
174 | * @return true if the variable exists | |
177 | 175 | */ |
178 | 176 | bool exists(const std::string &varName) const; |
179 | 177 | |
196 | 194 | void setShuttingDown(long shuttingDown = 5); |
197 | 195 | |
198 | 196 | /** |
199 | * tells if the user wants to shutdown. This can be used if the exit button is pressed deaply in the program. | |
197 | * tells if the user wants to shutdown. This can be used if the exit button is pressed deeply in the program. | |
200 | 198 | * @return |
201 | 199 | */ |
202 | 200 | long isShuttingDown() const; |
74 | 74 | Config::getInstance()->setDefault(configName, "1"); |
75 | 75 | int player = Config::getInstance()->getInt(configName) + gamecontrollers_assigned[guidAsHex]; |
76 | 76 | gamecontrollers_assigned[guidAsHex]++; //Next controller with same guid should be assigned to different player. |
77 | //std::cout << "Guid: " << guidAsHex << "\n"; | |
78 | 77 | |
79 | 78 | if (player%2==0) { |
80 | 79 | return 2; //Even number means player 2 |
268 | 267 | } |
269 | 268 | } |
270 | 269 | return false; |
271 | }⏎ | |
270 | } |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 | |
23 | #ifndef GAMECONTROLLER_H | |
24 | #define GAMECONTROLLER_HPP | |
25 | ||
23 | 26 | #include "SDL.h" |
24 | 27 | #include <vector> |
25 | 28 | #include <string> |
41 | 44 | * Checks that the given event is in the dead zone. |
42 | 45 | * If it is in the dead zone. Then the dead zone variable for that axis will be set to true; |
43 | 46 | * Otherwise nothing is done |
44 | * @param event An SDL | |
47 | * @param event An SDL | |
45 | 48 | */ |
46 | 49 | void checkDeadZone(const SDL_Event& event); |
47 | 50 | |
54 | 57 | bool getDeadZone(SDL_JoystickID id, int axis); |
55 | 58 | |
56 | 59 | /** |
57 | * Sets dead zone status on a given axis on a given gamepad | |
60 | * Sets dead zone status on a given axis on a given gamepad | |
58 | 61 | * @param id The gamepad |
59 | 62 | * @param axis The axis on the gamepad |
60 | 63 | * @param value Value to set. Should normally be false as true will be set by checkDeadZone |
61 | 64 | */ |
62 | void setDeadZone(SDL_JoystickID id, int axis, bool value);⏎ | |
65 | void setDeadZone(SDL_JoystickID id, int axis, bool value); | |
66 | ||
67 | #endif //GAMECONTROLLER |
32 | 32 | #include "sago/SagoTextField.hpp" |
33 | 33 | |
34 | 34 | void MainMenu(); |
35 | void SafeModeMenu(); | |
35 | 36 | void ResetFullscreen(); |
36 | 37 | void RunGameState(sago::GameStateInterface& state ); |
37 | 38 | |
47 | 48 | void sagoTextSetHelpFont(sago::SagoTextField& field); |
48 | 49 | void sagoTextSetBlueFont(sago::SagoTextField& field); |
49 | 50 | |
51 | const int SIXTEEN_NINE_WIDTH = 1364; | |
52 | const int FOUR_THREE_WIDTH = 1024; | |
53 | const int SCREEN_HIGHT = 768; | |
54 | ||
50 | 55 | struct GlobalData { |
51 | 56 | sago::SagoSprite bHighScore; |
52 | 57 | sago::SagoSprite bBack; |
53 | 58 | sago::SagoSprite bNext; |
54 | sago::SagoSprite iLevelCheck; //To the level select screen | |
59 | sago::SagoSprite iLevelCheck; //To the level select screen | |
55 | 60 | sago::SagoSprite iLevelCheckBox; |
56 | 61 | sago::SagoSprite iLevelCheckBoxMarked; |
57 | 62 | sago::SagoSprite iCheckBoxArea; |
58 | bool MusicEnabled; //true if background music is enabled | |
59 | bool SoundEnabled; //true if sound effects is enabled | |
60 | bool bFullscreen; //true if game is running fullscreen | |
61 | std::string replayArgument; //Name of the replay to play (if given as a commandline argument) | |
63 | bool MusicEnabled; //true if background music is enabled | |
64 | bool SoundEnabled; //true if sound effects is enabled | |
65 | bool bFullscreen; //true if game is running fullscreen | |
66 | std::string replayArgument; //Name of the replay to play (if given as a commandline argument) | |
62 | 67 | std::string player1name; |
63 | 68 | std::string player2name; |
64 | SDL_Renderer *screen = nullptr; //The whole screen; | |
69 | SDL_Renderer *screen = nullptr; //The whole screen; | |
65 | 70 | sago::SoundHandler typingChunk; |
66 | 71 | sago::SagoSprite mouse; |
67 | 72 | bool highPriority = false; |
68 | bool NoSound = false; | |
73 | bool NoSound = false; | |
74 | bool alwaysSixteenNine = false; | |
69 | 75 | int verboseLevel = 0; |
70 | Highscore theTopScoresEndless; //Stores highscores for endless | |
71 | Highscore theTopScoresTimeTrial; //Stores highscores for timetrial | |
72 | 76 | std::unique_ptr<sago::SagoSpriteHolder> spriteHolder; |
73 | ||
77 | ||
74 | 78 | TextManager theTextManager; |
75 | 79 | |
76 | //The xsize and ysize are updated everytime the background is drawn | |
77 | int xsize = 1024; | |
78 | int ysize = 768; | |
80 | int xsize = FOUR_THREE_WIDTH; | |
81 | int ysize = SCREEN_HIGHT; | |
79 | 82 | int mousex = 0; |
80 | 83 | int mousey = 0; |
81 | 84 | }; |
27 | 27 | #include "cereal/archives/json.hpp" |
28 | 28 | #include "sago/SagoMisc.hpp" |
29 | 29 | #include <algorithm> |
30 | #include "common.h" | |
30 | 31 | |
31 | 32 | namespace cereal { |
32 | 33 | |
49 | 50 | return (i.score > j.score); |
50 | 51 | } |
51 | 52 | |
52 | Highscore::Highscore(const std::string& type) { | |
53 | this->type = type; | |
54 | filename = type+".json.dat"; | |
53 | Highscore::Highscore(const std::string& type, double speed) : filename(type+".json.dat"), type(type), speed(speed) { | |
54 | if (speed < 0.4) { | |
55 | std::string old_locale = setlocale (LC_NUMERIC, nullptr); | |
56 | setlocale (LC_NUMERIC, "C"); | |
57 | //Use special filenames for higher speeds (higher speed = lower number) | |
58 | filename = SPrintStringF("%s_%.4f.json.dat", type.c_str(), speed); | |
59 | setlocale(LC_NUMERIC, old_locale.c_str()); | |
60 | } | |
55 | 61 | std::string readFileContent = sago::GetFileContent(filename.c_str()); |
56 | 62 | if (readFileContent.length() > 0) { |
57 | 63 | try { |
45 | 45 | std::string filename; |
46 | 46 | std::string type; |
47 | 47 | void writeFile(); |
48 | double speed = 0.5; | |
48 | 49 | public: |
49 | ||
50 | Highscore() | |
51 | { | |
52 | } | |
53 | ||
54 | Highscore(const std::string& type); | |
50 | Highscore(const std::string& type, double speed); | |
55 | 51 | |
56 | 52 | bool isHighScore(int); |
57 | 53 | void addScore(const std::string& newName, int); |
28 | 28 | #include "stageclearhandler.hpp" |
29 | 29 | #include "MenuSystem.h" |
30 | 30 | |
31 | ||
32 | using std::string; | |
33 | using std::cerr; | |
34 | using std::cout; | |
35 | using std::exception; | |
36 | using std::vector; | |
37 | 31 | |
38 | 32 | static bool bMouseUp; //true if the mouse(1) is unpressed |
39 | 33 | |
197 | 191 | } |
198 | 192 | |
199 | 193 | if (Type == 1) { |
200 | string scoreString = SPrintStringF(_("Best score: %i"), GetStageScores(selected)) ; | |
201 | string timeString = SPrintStringF(_("Time used: %s"),"-- : --"); | |
194 | std::string scoreString = SPrintStringF(_("Best score: %i"), GetStageScores(selected)) ; | |
195 | std::string timeString = SPrintStringF(_("Time used: %s"),"-- : --"); | |
202 | 196 | |
203 | 197 | if (GetStageTime(selected)>0) { |
204 | 198 | timeString = SPrintStringF(_("Time used: %d : %02d"), GetStageTime(selected)/1000/60, (GetStageTime(selected)/1000)%60); |
206 | 200 | |
207 | 201 | Write(globalData.screen, 200,200,scoreString.c_str()); |
208 | 202 | Write(globalData.screen, 200,250,timeString.c_str()); |
209 | string totalString = SPrintStringF(_("Total score: %i in %i:%02i"), totalScore, totalTime/1000/60, ((totalTime/1000)%60) ); | |
203 | std::string totalString = SPrintStringF(_("Total score: %i in %i:%02i"), totalScore, totalTime/1000/60, ((totalTime/1000)%60) ); | |
210 | 204 | Write(globalData.screen, 200,600,totalString.c_str()); |
211 | 205 | } |
212 | 206 |
16 | 16 | along with this program. If not, see http://www.gnu.org/licenses/ |
17 | 17 | |
18 | 18 | Source information and contacts persons can be found at |
19 | http://www.blockattack.net | |
19 | https://blockattack.net | |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 | |
65 | 65 | |
66 | 66 | #include "highscore.h" //Stores highscores |
67 | 67 | #include "ReadKeyboard.h" //Reads text from keyboard |
68 | #include "stats.h" //Saves general stats | |
68 | #include "stats.h" //Saves general stats | |
69 | 69 | #include "replayhandler.hpp" |
70 | 70 | |
71 | 71 | #include "common.h" |
97 | 97 | |
98 | 98 | static void PhysFsSetSearchPath(const vector<string>& paths, const string& savepath) { |
99 | 99 | for (const string& path : paths) { |
100 | PHYSFS_addToSearchPath(path.c_str(),1); | |
101 | } | |
102 | PHYSFS_addToSearchPath(savepath.c_str(), 1); | |
100 | PHYSFS_mount(path.c_str(), "/", 0); | |
101 | } | |
102 | PHYSFS_mount(savepath.c_str(), "/", 0); | |
103 | 103 | PHYSFS_setWriteDir(savepath.c_str()); |
104 | 104 | } |
105 | 105 | |
106 | 106 | |
107 | 107 | static void PhysFsCreateFolders() { |
108 | PHYSFS_mkdir("screenshots"); | |
108 | //PHYSFS_mkdir("screenshots"); | |
109 | 109 | PHYSFS_mkdir("replays"); |
110 | 110 | PHYSFS_mkdir("puzzles"); |
111 | 111 | } |
131 | 131 | bricks[6] = holder.GetSprite("block_grey"); |
132 | 132 | bomb = holder.GetSprite("block_bomb"); |
133 | 133 | backgroundImage = holder.GetSprite("background"); |
134 | backgroundSixteenNineImage = holder.GetSprite("background_sixteen_nine"); | |
134 | 135 | globalData.bHighScore = holder.GetSprite("b_highscore"); |
135 | 136 | globalData.bBack = holder.GetSprite("b_blank"); |
136 | 137 | bForward = holder.GetSprite("b_forward"); |
246 | 247 | void ResetFullscreen() { |
247 | 248 | Mix_HaltMusic(); //We need to reload all data in case the screen type changes. Music must be stopped before unload. |
248 | 249 | if (globalData.bFullscreen) { |
250 | SDL_DisplayMode dm; | |
251 | globalData.xsize = SIXTEEN_NINE_WIDTH; | |
252 | globalData.ysize = SCREEN_HIGHT; | |
253 | if (SDL_GetDesktopDisplayMode(0, &dm) == 0) { | |
254 | globalData.xsize = globalData.ysize*dm.w/(double)dm.h; | |
255 | } | |
249 | 256 | SDL_SetWindowFullscreen(sdlWindow, SDL_WINDOW_FULLSCREEN_DESKTOP); |
250 | 257 | } |
251 | 258 | else { |
259 | globalData.xsize = FOUR_THREE_WIDTH; | |
260 | globalData.ysize = SCREEN_HIGHT; | |
252 | 261 | SDL_SetWindowFullscreen(sdlWindow, 0); |
253 | 262 | } |
263 | if (globalData.alwaysSixteenNine || globalData.xsize > SIXTEEN_NINE_WIDTH) { | |
264 | globalData.xsize = SIXTEEN_NINE_WIDTH; | |
265 | } | |
266 | if (globalData.xsize < FOUR_THREE_WIDTH) { | |
267 | globalData.xsize = FOUR_THREE_WIDTH; | |
268 | } | |
269 | SDL_RenderSetLogicalSize(globalData.screen, globalData.xsize, globalData.ysize); | |
254 | 270 | dataHolder.invalidateAll(globalData.screen); |
255 | 271 | globalData.spriteHolder.reset(new sago::SagoSpriteHolder( dataHolder ) ); |
256 | 272 | InitImages(*(globalData.spriteHolder.get()) ); |
261 | 277 | |
262 | 278 | void DrawBackground(SDL_Renderer* target) { |
263 | 279 | SDL_RenderClear(target); |
264 | if (logicalRenderer) { | |
265 | globalData.xsize = 1024; | |
266 | globalData.ysize = 768; | |
280 | if ( (double)globalData.xsize/globalData.ysize > 1.5) { | |
281 | backgroundSixteenNineImage.DrawScaled(target, SDL_GetTicks(), 0, 0, globalData.xsize, globalData.ysize); | |
267 | 282 | } |
268 | 283 | else { |
269 | SDL_GetWindowSize(sdlWindow, &globalData.xsize, &globalData.ysize); | |
270 | } | |
271 | backgroundImage.DrawScaled(target, SDL_GetTicks(), 0, 0, globalData.xsize, globalData.ysize); | |
284 | backgroundImage.DrawScaled(target, SDL_GetTicks(), 0, 0, globalData.xsize, globalData.ysize); | |
285 | } | |
272 | 286 | } |
273 | 287 | |
274 | 288 | /** |
308 | 322 | #include "BlockGameSdl.inc" |
309 | 323 | #include "sago/SagoMisc.hpp" |
310 | 324 | #include "ReplayPlayer.hpp" |
311 | ||
312 | ||
325 | #include "sago/platform_folders.h" | |
326 | ||
327 | std::string pathToScreenShots() { | |
328 | Config::getInstance()->setDefault("screenshot_dir", _("Block Attack - Rise of the Blocks")); | |
329 | std::string screenshot_dir = Config::getInstance()->getString("screenshot_dir"); | |
330 | if (OsPathIsRelative(screenshot_dir)) { | |
331 | return sago::getPicturesFolder() + "/" + screenshot_dir; | |
332 | } | |
333 | return screenshot_dir; | |
334 | } | |
313 | 335 | |
314 | 336 | //writeScreenShot saves the screen as a bmp file, it uses the time to get a unique filename |
315 | 337 | void writeScreenShot() { |
317 | 339 | cout << "Saving screenshot" << "\n"; |
318 | 340 | } |
319 | 341 | int rightNow = (int)time(nullptr); |
320 | string buf = getPathToSaveFiles() + "/screenshots/screenshot"+std::to_string(rightNow)+".bmp"; | |
321 | SDL_Surface* sreenshotSurface = SDL_CreateRGBSurface(0, 1024, 768, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); | |
322 | SDL_RenderReadPixels(globalData.screen, NULL, SDL_PIXELFORMAT_ARGB8888, sreenshotSurface->pixels, sreenshotSurface->pitch); | |
342 | SDL_Surface* infoSurface = SDL_GetWindowSurface(sdlWindow); | |
343 | if (!infoSurface) { | |
344 | std::cerr << "Could not get infoSurface. No screenshot written. Be aware that the screenshot feature only works with software render\n"; | |
345 | return; | |
346 | } | |
347 | std::vector<char> pixels(infoSurface->w * infoSurface->h * infoSurface->format->BytesPerPixel); | |
348 | int errorCode = SDL_RenderReadPixels(globalData.screen, &infoSurface->clip_rect, infoSurface->format->format, static_cast<void*>(pixels.data()), infoSurface->w * infoSurface->format->BytesPerPixel); | |
349 | if (errorCode) { | |
350 | SDL_FreeSurface(infoSurface); | |
351 | std::cerr << "Could not do SDL_RenderReadPixels. Error code: " << errorCode << ". No screenshot written\n"; | |
352 | return; | |
353 | } | |
354 | SDL_Surface* sreenshotSurface = SDL_CreateRGBSurfaceFrom(static_cast<void*>(pixels.data()), infoSurface->w, infoSurface->h, infoSurface->format->BitsPerPixel, infoSurface->w * infoSurface->format->BytesPerPixel, infoSurface->format->Rmask, infoSurface->format->Gmask, infoSurface->format->Bmask, infoSurface->format->Amask); | |
355 | SDL_FreeSurface(infoSurface); | |
356 | if (!sreenshotSurface) { | |
357 | std::cerr << "Could not get sreenshotSurface. No screenshot written\n"; | |
358 | return; | |
359 | } | |
360 | OsCreateFolder(pathToScreenShots()); | |
361 | std::string buf = pathToScreenShots() + "/screenshot"+std::to_string(rightNow)+".bmp"; | |
323 | 362 | SDL_SaveBMP(sreenshotSurface, buf.c_str()); |
324 | 363 | SDL_FreeSurface(sreenshotSurface); |
325 | 364 | if (!globalData.NoSound) { |
673 | 712 | static bool registerTTHighscorePlayer2 = false; |
674 | 713 | static bool saveReplay = false; |
675 | 714 | |
676 | static void StartSinglePlayerEndless() { | |
715 | /** | |
716 | * startSpeed is a value from 0 to 4 | |
717 | * */ | |
718 | static void StartSinglePlayerEndless(int startSpeed) { | |
677 | 719 | //1 player - endless |
678 | 720 | BlockGameStartInfo startInfo; |
679 | 721 | startInfo.ticks = SDL_GetTicks(); |
680 | 722 | startInfo.startBlocks = startInfo.ticks; |
723 | startInfo.gameSpeed = startSpeed; | |
681 | 724 | player1->NewGame(startInfo); |
682 | 725 | twoPlayers =false; |
683 | 726 | BlockGameAction a; |
721 | 764 | a.action = BlockGameAction::Action::SET_GAME_OVER; |
722 | 765 | a.tick = startInfo.ticks; |
723 | 766 | player2->DoAction(a); |
724 | //vsMode = true; | |
725 | 767 | player1->name = globalData.player1name; |
726 | 768 | player2->name = globalData.player2name; |
727 | 769 | return 0; |
777 | 819 | startInfo2.handicap = player2handicap; |
778 | 820 | player1->NewGame(startInfo); |
779 | 821 | player2->NewGame(startInfo2); |
780 | //vsMode = true; | |
781 | 822 | twoPlayers = true; |
782 | 823 | player1->name = globalData.player1name; |
783 | 824 | player2->name = globalData.player2name; |
784 | 825 | } |
785 | 826 | |
786 | 827 | static void MoveBlockGameSdls( BlockGameSdl& game1, BlockGameSdl& game2 ) { |
787 | game1.SetTopXY(50, globalData.ysize/2-284); | |
788 | game2.SetTopXY(globalData.xsize-500, globalData.ysize/2-284); | |
828 | game1.SetTopXY(globalData.xsize/2-440, globalData.ysize/2-284); | |
829 | game2.SetTopXY(globalData.xsize/2+40, globalData.ysize/2-284); | |
789 | 830 | } |
790 | 831 | |
791 | 832 | struct globalConfig { |
820 | 861 | ("verbose-game-controller", "Enables verbose messages regarding controllers") |
821 | 862 | ("print-search-path", "Prints the search path and quits") |
822 | 863 | ("no-auto-scale", "Do not automatically auto scale") |
864 | ("always-sixteen-nine", "Use 16:9 format even in Window mode") | |
823 | 865 | ("puzzle-level-file", boost::program_options::value<string>(), "Sets the default puzzle file to load") |
824 | 866 | ("puzzle-single-level", boost::program_options::value<int>(), "Start the specific puzzle level directly") |
825 | 867 | #ifdef REPLAY_IMPLEMENTED |
910 | 952 | } |
911 | 953 | if (vm.count("no-auto-scale")) { |
912 | 954 | conf.autoScale = false; |
955 | } | |
956 | if (vm.count("always-sixteen-nine")) { | |
957 | globalData.alwaysSixteenNine = true; | |
913 | 958 | } |
914 | 959 | if (vm.count("puzzle-level-file")) { |
915 | 960 | conf.puzzleName = vm["puzzle-level-file"].as<string>(); |
939 | 984 | ParseArguments(argc, argv, config); |
940 | 985 | OsCreateSaveFolder(); |
941 | 986 | PhysFsSetSearchPath(config.search_paths, config.savepath); |
942 | //Os create folders must be after the paramters because they can change the home folder | |
987 | //Os create folders must be after the parameters because they can change the home folder | |
943 | 988 | PhysFsCreateFolders(); |
989 | bool gameShutdownProperly = true; | |
990 | if (sago::FileExists("gameRunning")) { | |
991 | gameShutdownProperly = false; | |
992 | } | |
993 | sago::WriteFileContent("gameRunning", "Started"); | |
944 | 994 | globalData.SoundEnabled = true; |
945 | 995 | globalData.MusicEnabled = true; |
946 | 996 | twoPlayers = false; //true if two players splitscreen |
947 | globalData.theTopScoresEndless = Highscore("endless"); | |
948 | globalData.theTopScoresTimeTrial = Highscore("timetrial"); | |
949 | 997 | drawBalls = true; |
950 | 998 | puzzleLoaded = false; |
951 | 999 | theBallManager = BallManager(); |
997 | 1045 | keySettings[player2keys].change = SDLK_LCTRL; |
998 | 1046 | keySettings[player2keys].push = SDLK_LSHIFT; |
999 | 1047 | |
1000 | globalData.player1name = _("Player 1"); | |
1048 | globalData.player1name = defaultPlayerName(); | |
1001 | 1049 | globalData.player2name = _("Player 2"); |
1002 | 1050 | |
1003 | 1051 | Config* configSettings = Config::getInstance(); |
1070 | 1118 | cout << "Unable to load options file, using default values" << "\n"; |
1071 | 1119 | } |
1072 | 1120 | } |
1121 | if (configSettings->getInt("always-software")) { | |
1122 | config.softwareRenderer = true; | |
1123 | } | |
1124 | if (!gameShutdownProperly) { | |
1125 | std::cerr << "Game not shotdown. Using software renderer.\n"; | |
1126 | config.softwareRenderer = true; | |
1127 | } | |
1073 | 1128 | |
1074 | 1129 | // "Block Attack - Rise of the Blocks" |
1075 | 1130 | SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); |
1078 | 1133 | if (config.allowResize) { |
1079 | 1134 | createWindowParams |= SDL_WINDOW_RESIZABLE; |
1080 | 1135 | } |
1136 | globalData.xsize = FOUR_THREE_WIDTH; | |
1137 | if (globalData.alwaysSixteenNine) { | |
1138 | globalData.xsize = SIXTEEN_NINE_WIDTH; | |
1139 | } | |
1140 | globalData.ysize = SCREEN_HIGHT; | |
1081 | 1141 | sdlWindow = SDL_CreateWindow("Block Attack - Rise of the Blocks " VERSION_NUMBER, |
1082 | 1142 | SDL_WINDOWPOS_UNDEFINED, |
1083 | 1143 | SDL_WINDOWPOS_UNDEFINED, |
1084 | (screenHeight)*4/3, screenHeight, | |
1144 | (screenHeight)*globalData.xsize/globalData.ysize, screenHeight, | |
1085 | 1145 | createWindowParams ); |
1086 | 1146 | dieOnNullptr(sdlWindow, "Unable to create window"); |
1087 | 1147 | int rendererFlags = 0; |
1091 | 1151 | SDL_Renderer* renderer = SDL_CreateRenderer(sdlWindow, -1, rendererFlags); |
1092 | 1152 | dieOnNullptr(renderer, "Unable to create render"); |
1093 | 1153 | if (config.autoScale) { |
1094 | SDL_RenderSetLogicalSize(renderer, 1024, 768); | |
1154 | SDL_RenderSetLogicalSize(renderer, globalData.xsize, globalData.ysize); | |
1095 | 1155 | logicalRenderer = true; |
1096 | 1156 | } |
1097 | 1157 | if (globalData.verboseLevel) { |
1107 | 1167 | cout << "Images loaded" << "\n"; |
1108 | 1168 | } |
1109 | 1169 | |
1110 | BlockGameSdl theGame = BlockGameSdl(50, 100, &globalData.spriteHolder->GetDataHolder()); //creates game objects | |
1111 | BlockGameSdl theGame2 = BlockGameSdl(globalData.xsize-500, 100, &globalData.spriteHolder->GetDataHolder()); | |
1170 | BlockGameSdl theGame = BlockGameSdl(globalData.xsize/2-426, 100, &globalData.spriteHolder->GetDataHolder()); //creates game objects | |
1171 | BlockGameSdl theGame2 = BlockGameSdl(globalData.xsize/2+40, 100, &globalData.spriteHolder->GetDataHolder()); | |
1112 | 1172 | player1 = &theGame; |
1113 | 1173 | player2 = &theGame2; |
1114 | 1174 | |
1142 | 1202 | RunGameState(rp); |
1143 | 1203 | } |
1144 | 1204 | else { |
1205 | if (!gameShutdownProperly) { | |
1206 | SafeModeMenu(); | |
1207 | } | |
1145 | 1208 | //game loop |
1146 | 1209 | MainMenu(); |
1147 | 1210 | } |
1170 | 1233 | |
1171 | 1234 | configSettings->setString("player1name", globalData.player1name); |
1172 | 1235 | configSettings->setString("player2name", globalData.player2name); |
1173 | { | |
1236 | if (!globalData.bFullscreen){ | |
1174 | 1237 | //Store physical height of window |
1175 | 1238 | int height = 0; |
1176 | 1239 | SDL_GetWindowSize(sdlWindow, nullptr, &height); |
1198 | 1261 | catch (exception& e) { |
1199 | 1262 | sago::SagoFatalError(e.what()); |
1200 | 1263 | } |
1264 | PHYSFS_delete("gameRunning"); | |
1201 | 1265 | //Close file system Apstraction layer! |
1202 | 1266 | PHYSFS_deinit(); |
1203 | 1267 | return 0; |
1204 | 1268 | } |
1205 | 1269 | |
1206 | 1270 | int runGame(Gametype gametype, int level) { |
1207 | globalData.theTopScoresEndless = Highscore("endless"); | |
1208 | globalData.theTopScoresTimeTrial = Highscore("timetrial"); | |
1271 | Highscore theTopScoresTimeTrial = Highscore("timetrial", 0.5); | |
1209 | 1272 | drawBalls = true; |
1210 | 1273 | puzzleLoaded = false; |
1211 | 1274 | bool bNearDeath = false; //Play music faster or louder while tru |
1212 | 1275 | |
1213 | 1276 | theBallManager = BallManager(); |
1214 | 1277 | theExplosionManager = ExplosionManager(); |
1215 | BlockGameSdl theGame = BlockGameSdl(50, 100, &globalData.spriteHolder->GetDataHolder()); //creates game objects | |
1216 | BlockGameSdl theGame2 = BlockGameSdl(globalData.xsize-500, 100, &globalData.spriteHolder->GetDataHolder()); | |
1278 | BlockGameSdl theGame = BlockGameSdl(globalData.xsize/2-426, 100, &globalData.spriteHolder->GetDataHolder()); //creates game objects | |
1279 | BlockGameSdl theGame2 = BlockGameSdl(globalData.xsize/2+4, 100, &globalData.spriteHolder->GetDataHolder()); | |
1217 | 1280 | player1 = &theGame; |
1218 | 1281 | player2 = &theGame2; |
1219 | 1282 | theGame.DoPaintJob(); //Makes sure what there is something to paint |
1303 | 1366 | break; |
1304 | 1367 | case Gametype::SinglePlayerEndless: |
1305 | 1368 | default: |
1306 | StartSinglePlayerEndless(); | |
1369 | StartSinglePlayerEndless(level); | |
1307 | 1370 | }; |
1308 | 1371 | mustsetupgame = false; |
1309 | 1372 | DrawBackground(globalData.screen); |
1725 | 1788 | |
1726 | 1789 | if (theGame.isGameOver() && registerTTHighscorePlayer1) { |
1727 | 1790 | registerTTHighscorePlayer1 = false; |
1728 | globalData.theTopScoresTimeTrial.addScore(theGame.name, theGame.GetScore()); | |
1791 | theTopScoresTimeTrial.addScore(theGame.name, theGame.GetScore()); | |
1729 | 1792 | } |
1730 | 1793 | if (theGame2.isGameOver() && registerTTHighscorePlayer2) { |
1731 | 1794 | registerTTHighscorePlayer2 = false; |
1732 | globalData.theTopScoresTimeTrial.addScore(theGame2.name, theGame2.GetScore()); | |
1795 | theTopScoresTimeTrial.addScore(theGame2.name, theGame2.GetScore()); | |
1733 | 1796 | } |
1734 | 1797 | if (theGame.isGameOver() && registerEndlessHighscore) { |
1798 | Highscore theTopScoresEndless = Highscore("endless", theGame.GetBaseSpeed()); | |
1735 | 1799 | registerEndlessHighscore = false; |
1736 | globalData.theTopScoresEndless.addScore(theGame.name, theGame.GetScore()); | |
1800 | theTopScoresEndless.addScore(theGame.name, theGame.GetScore()); | |
1737 | 1801 | theGame.EndlessHighscoreEvent(); |
1738 | 1802 | } |
1739 | 1803 | #ifdef REPLAY_IMPLEMENTED |
46 | 46 | |
47 | 47 | //All graphic in the game: |
48 | 48 | sago::SagoSprite backgroundImage; //Stores the background image |
49 | sago::SagoSprite backgroundSixteenNineImage; // For 16:9 format | |
49 | 50 | sago::SagoSprite bExit; |
50 | 51 | static sago::SagoSprite backBoard; //Stores the background to the board |
51 | 52 | static sago::SagoSprite bForward; //The "forward" button |
137 | 137 | standardButton.setSurfaces(); |
138 | 138 | } |
139 | 139 | |
140 | static void runSinglePlayerEndless0() { | |
141 | runGame(Gametype::SinglePlayerEndless, 0); | |
142 | } | |
143 | ||
144 | static void runSinglePlayerEndless1() { | |
145 | runGame(Gametype::SinglePlayerEndless, 1); | |
146 | } | |
147 | ||
148 | static void runSinglePlayerEndless2() { | |
149 | runGame(Gametype::SinglePlayerEndless, 2); | |
150 | } | |
151 | ||
152 | static void runSinglePlayerEndless3() { | |
153 | runGame(Gametype::SinglePlayerEndless, 3); | |
154 | } | |
155 | ||
156 | static void runSinglePlayerEndless4() { | |
157 | runGame(Gametype::SinglePlayerEndless, 4); | |
158 | } | |
159 | ||
140 | 160 | static void runSinglePlayerEndless() { |
141 | runGame(Gametype::SinglePlayerEndless, 0); | |
161 | Menu sp(globalData.screen,_("Single Player Endless"),true); | |
162 | Button d0,d1,d2,d3,d4; | |
163 | d0.setPopOnRun(true); | |
164 | d1.setPopOnRun(true); | |
165 | d2.setPopOnRun(true); | |
166 | d3.setPopOnRun(true); | |
167 | d4.setPopOnRun(true); | |
168 | d0.setLabel(_("Slow")); | |
169 | d1.setLabel(_("Fast")); | |
170 | d2.setLabel(_("Faster")); | |
171 | d3.setLabel(_("Even faster")); | |
172 | d4.setLabel(_("Fastest")); | |
173 | d0.setAction(runSinglePlayerEndless0); | |
174 | d1.setAction(runSinglePlayerEndless1); | |
175 | d2.setAction(runSinglePlayerEndless2); | |
176 | d3.setAction(runSinglePlayerEndless3); | |
177 | d4.setAction(runSinglePlayerEndless4); | |
178 | sp.addButton(&d0); | |
179 | sp.addButton(&d1); | |
180 | sp.addButton(&d2); | |
181 | sp.addButton(&d3); | |
182 | sp.addButton(&d4); | |
183 | RunGameState(sp); | |
142 | 184 | } |
143 | 185 | |
144 | 186 | static void runSinglePlayerTimeTrial() { |
167 | 209 | runGame(Gametype::TwoPlayerVs, 0); |
168 | 210 | } |
169 | 211 | |
212 | static void SetAlwaysSoftwareLabel(Button* b) { | |
213 | b->setLabel(Config::getInstance()->getInt("always-software")? | |
214 | _("Always use software render: On") | |
215 | : _("Always use software render: Off")); | |
216 | } | |
217 | ||
218 | static void SetMusicLabel (Button* b) { | |
219 | b->setLabel(globalData.MusicEnabled? _("Music: On") : _("Music: Off") ); | |
220 | } | |
221 | ||
222 | static void SetSoundLabel (Button* b) { | |
223 | b->setLabel(globalData.SoundEnabled? _("Sound: On") : _("Sound: Off") ); | |
224 | } | |
225 | ||
226 | static void SetFullscreenLabel (Button* b) { | |
227 | b->setLabel(globalData.bFullscreen? _("Fullscreen: On") : _("Fullscreen: Off") ); | |
228 | } | |
229 | ||
230 | class AlwaysSoftwareRenderButton : public Button { | |
231 | virtual void doAction() override { | |
232 | Config::getInstance()->setInt("always-software", !Config::getInstance()->getInt("always-software")); | |
233 | SetAlwaysSoftwareLabel(this); | |
234 | } | |
235 | }; | |
236 | ||
170 | 237 | class MusicButton : public Button { |
171 | 238 | virtual void doAction() override { |
172 | 239 | globalData.MusicEnabled = !globalData.MusicEnabled; |
173 | setLabel(globalData.MusicEnabled? _("Music: On") : _("Music: Off")); | |
174 | } | |
175 | ||
240 | SetMusicLabel(this); | |
241 | } | |
176 | 242 | }; |
177 | 243 | |
178 | 244 | class SoundButton : public Button { |
179 | 245 | virtual void doAction() override { |
180 | 246 | globalData.SoundEnabled = !globalData.SoundEnabled; |
181 | setLabel(globalData.SoundEnabled? _("Sound: On") : _("Sound: Off") ); | |
247 | SetSoundLabel(this); | |
182 | 248 | } |
183 | 249 | }; |
184 | 250 | |
185 | 251 | class FullscreenButton : public Button { |
186 | 252 | virtual void doAction() override { |
187 | 253 | globalData.bFullscreen = !globalData.bFullscreen; |
188 | setLabel(globalData.bFullscreen? _("Fullscreen: On") : _("Fullscreen: Off") ); | |
254 | SetFullscreenLabel(this); | |
189 | 255 | ResetFullscreen(); |
190 | 256 | } |
191 | 257 | }; |
235 | 301 | Menu cm(globalData.screen,_("Configuration"),true); |
236 | 302 | Button bPlayer1Name,bPlayer2Name; |
237 | 303 | Button bPlayer1Keys, bPlayer2Keys; |
304 | AlwaysSoftwareRenderButton bSoftware; | |
238 | 305 | MusicButton bMusic; |
239 | 306 | SoundButton bSound; |
240 | 307 | FullscreenButton buttonFullscreen; |
241 | bMusic.setLabel(globalData.MusicEnabled? _("Music: On") : _("Music: Off") ); | |
242 | bSound.setLabel(globalData.SoundEnabled? _("Sound: On") : _("Sound: Off") ); | |
243 | buttonFullscreen.setLabel(globalData.bFullscreen? _("Fullscreen: On") : _("Fullscreen: Off") ); | |
308 | SetAlwaysSoftwareLabel(&bSoftware); | |
309 | SetMusicLabel(&bMusic); | |
310 | SetSoundLabel(&bSound); | |
311 | SetFullscreenLabel(&buttonFullscreen); | |
244 | 312 | bPlayer1Name.setAction(buttonActionPlayer1Name); |
245 | 313 | bPlayer1Name.setLabel(_("Change player 1's name") ); |
246 | 314 | bPlayer2Name.setAction(buttonActionPlayer2Name); |
251 | 319 | bPlayer2Keys.setLabel(_("Change player 2's keys") ); |
252 | 320 | cm.addButton(&bMusic); |
253 | 321 | cm.addButton(&bSound); |
322 | cm.addButton(&bSoftware); | |
254 | 323 | cm.addButton(&buttonFullscreen); |
255 | 324 | cm.addButton(&bPlayer1Name); |
256 | 325 | cm.addButton(&bPlayer2Name); |
368 | 437 | RunGameState(m); |
369 | 438 | } |
370 | 439 | |
440 | void SafeModeMenu() { | |
441 | if (Config::getInstance()->getInt("always-software")) { | |
442 | return; | |
443 | } | |
444 | InitMenues(); | |
445 | Menu safeMode(globalData.screen, _("Game did not shutdown as it should"), true); | |
446 | Button bOnce; | |
447 | Button bAlways; | |
448 | bOnce.setLabel(_("Use software renderer this time")); | |
449 | bAlways.setLabel(_("Always use software renderer")); | |
450 | bOnce.setPopOnRun(true); | |
451 | bAlways.setAction([]() {Config::getInstance()->setInt("always-software", 1); }); | |
452 | bAlways.setPopOnRun(true); | |
453 | safeMode.addButton(&bOnce); | |
454 | safeMode.addButton(&bAlways); | |
455 | RunGameState(safeMode); | |
456 | } | |
457 | ||
371 | 458 | void MainMenu() { |
372 | 459 | InitMenues(); |
373 | 460 | Menu m(globalData.screen,_("Block Attack - Rise of the blocks"),false); |
16 | 16 | along with this program. If not, see http://www.gnu.org/licenses/ |
17 | 17 | |
18 | 18 | Source information and contacts persons can be found at |
19 | http://blockattack.net | |
19 | https://blockattack.net | |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 | |
24 | 24 | #include <iostream> |
25 | 25 | #include <physfs.h> |
26 | 26 | #include "sago/platform_folders.h" |
27 | #include "version.h" | |
28 | #include "common.h" | |
29 | ||
30 | #if defined(__unix__) | |
31 | #include <pwd.h> | |
32 | #include <unistd.h> | |
33 | #endif | |
27 | 34 | |
28 | 35 | static sago::PlatformFolders pf; |
29 | ||
30 | ||
31 | /* | |
32 | *Files will be saved in: | |
33 | * HOME/.gamesaves/"+GAMENAME (unix) | |
34 | *or DOCUMENTS/My Games/GAMENAME (Windows) | |
35 | */ | |
36 | #define GAMENAME "blockattack" | |
37 | 36 | |
38 | 37 | static std::string overrideSavePath = ""; |
39 | 38 | |
40 | 39 | /** |
41 | 40 | * Returns the path to where all settings must be saved. |
42 | * On unix-like systems this is the home-folder under: ~/.gamesaves/GAMENAME | |
41 | * On unix-like systems this is the home-folder under: ~/.local/share/GAMENAME | |
43 | 42 | * In Windows it is My Documents/My Games |
44 | 43 | * Consider changing this for Vista that has a special save games folder |
45 | 44 | */ |
54 | 53 | overrideSavePath = path; |
55 | 54 | } |
56 | 55 | |
57 | void OsCreateSaveFolder() { | |
56 | #if defined(_WIN32) | |
57 | #include "shlwapi.h" | |
58 | ||
59 | static std::wstring win32_utf8_to_utf16(const char* str) { | |
60 | std::wstring res; | |
61 | // If the 6th parameter is 0 then WideCharToMultiByte returns the number of bytes needed to store the result. | |
62 | int actualSize = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0); | |
63 | if (actualSize > 0) { | |
64 | //If the converted UTF-8 string could not be in the initial buffer. Allocate one that can hold it. | |
65 | std::vector<wchar_t> buffer(actualSize); | |
66 | actualSize = MultiByteToWideChar(CP_UTF8, 0, str, -1, &buffer[0], buffer.size()); | |
67 | res = buffer.data(); | |
68 | } | |
69 | if (actualSize == 0) { | |
70 | // WideCharToMultiByte return 0 for errors. | |
71 | const std::string errorMsg = "UTF8 to UTF16 failed with error code: " + GetLastError(); | |
72 | throw std::runtime_error(errorMsg.c_str()); | |
73 | } | |
74 | return res; | |
75 | } | |
76 | #endif | |
77 | ||
78 | std::string defaultPlayerName() { | |
79 | std::string ret; | |
80 | #if defined(_WIN32) | |
81 | wchar_t win_buffer[50]; | |
82 | DWORD win_buffer_size = sizeof(win_buffer); | |
83 | bool success = GetUserNameW(win_buffer, &win_buffer_size); | |
84 | if (success) { | |
85 | ret = sago::internal::win32_utf16_to_utf8(win_buffer); | |
86 | } | |
87 | #endif | |
58 | 88 | #if defined(__unix__) |
59 | std::string cmd = "mkdir -p '"+getPathToSaveFiles()+"/'"; | |
89 | int uid = getuid(); | |
90 | struct passwd* pw = getpwuid(uid); | |
91 | if (pw && pw->pw_gecos) { | |
92 | ret = pw->pw_gecos; | |
93 | ret = ret.substr(0, ret.find_first_of(',',0)); | |
94 | } | |
95 | if (pw && pw->pw_name && ret.empty()) { | |
96 | ret = pw->pw_name; | |
97 | } | |
98 | #endif | |
99 | if (ret.empty()) { | |
100 | ret = _("Player 1"); | |
101 | } | |
102 | return ret; | |
103 | } | |
104 | ||
105 | bool OsPathIsRelative(const std::string& path) { | |
106 | #if defined(_WIN32) | |
107 | return PathIsRelativeW(win32_utf8_to_utf16(path.c_str()).c_str()); | |
108 | #else | |
109 | return path[0] != '/'; | |
110 | #endif | |
111 | } | |
112 | ||
113 | void OsCreateFolder(const std::string& path) { | |
114 | #if defined(__unix__) | |
115 | std::string cmd = "mkdir -p '"+path+"/'"; | |
60 | 116 | int retcode = system(cmd.c_str()); |
61 | 117 | if (retcode != 0) { |
62 | std::cerr << "Failed to create: " << getPathToSaveFiles()+"/" << "\n"; | |
118 | std::cerr << "Failed to create: " << path+"/" << "\n"; | |
63 | 119 | } |
64 | 120 | #elif defined(_WIN32) |
65 | 121 | //Now for Windows NT/2k/xp/2k3 etc. |
66 | CreateDirectory(pf.getSaveGamesFolder1().c_str(), nullptr); | |
67 | std::string tempA = getPathToSaveFiles(); | |
68 | CreateDirectory(tempA.c_str(),nullptr); | |
122 | CreateDirectoryW(win32_utf8_to_utf16(pf.getSaveGamesFolder1().c_str()).c_str(), nullptr); | |
123 | std::string tempA = path; | |
124 | CreateDirectoryW(win32_utf8_to_utf16(tempA.c_str()).c_str(), nullptr); | |
125 | #else | |
126 | std::cerr << "Failed to create: \"" << path << "\"\n"; | |
69 | 127 | #endif |
70 | 128 | } |
129 | ||
130 | void OsCreateSaveFolder() { | |
131 | std::string path = getPathToSaveFiles(); | |
132 | OsCreateFolder(path); | |
133 | } |
16 | 16 | along with this program. If not, see http://www.gnu.org/licenses/ |
17 | 17 | |
18 | 18 | Source information and contacts persons can be found at |
19 | http://blockattack.net | |
19 | https://blockattack.net | |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 | |
31 | 31 | std::string getMyDocumentsPath(); |
32 | 32 | #endif |
33 | 33 | |
34 | std::string defaultPlayerName(); | |
35 | ||
34 | 36 | void setPathToSaveFiles(const std::string& path); |
35 | 37 | |
36 | 38 | void OsCreateSaveFolder(); |
39 | ||
40 | bool OsPathIsRelative(const std::string& path); | |
41 | ||
42 | void OsCreateFolder(const std::string& path); |
31 | 31 | #include <SDL_mixer.h> |
32 | 32 | #include "SagoMiscSdl2.hpp" |
33 | 33 | |
34 | #if PHYSFS_VER_MAJOR < 3 | |
35 | #define PHYSFS_readBytes(X,Y,Z) PHYSFS_read(X,Y,1,Z) | |
36 | #define PHYSFS_writeBytes(X,Y,Z) PHYSFS_write(X,Y,1,Z) | |
37 | #endif | |
38 | ||
34 | 39 | namespace sago { |
35 | 40 | |
36 | 41 | struct SagoDataHolder::SagoDataHolderData { |
41 | 46 | std::vector<SDL_RWops*> rwOpsToFree; |
42 | 47 | std::vector<std::unique_ptr<char[]>> dataToFree; |
43 | 48 | bool verbose = false; |
44 | Uint64 version = 0; | |
49 | Uint64 version = 1; | |
45 | 50 | SDL_Renderer* renderer = nullptr; |
46 | 51 | }; |
47 | 52 | |
103 | 108 | return ret; |
104 | 109 | } |
105 | 110 | std::string path = "textures/"+textureName+".png"; |
106 | if (data->verbose) { | |
111 | if (data->verbose) { | |
107 | 112 | printFileWeLoad(path); |
108 | 113 | } |
109 | 114 | if (!PHYSFS_exists(path.c_str())) { |
112 | 117 | PHYSFS_file* myfile = PHYSFS_openRead(path.c_str()); |
113 | 118 | unsigned int m_size = PHYSFS_fileLength(myfile); |
114 | 119 | std::unique_ptr<char[]> m_data(new char[m_size]); |
115 | int length_read = PHYSFS_read (myfile, m_data.get(), 1, m_size); | |
120 | int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size); | |
116 | 121 | if (length_read != (int)m_size) { |
117 | 122 | PHYSFS_close(myfile); |
118 | std::cerr << "Error: Curropt data file: " << path << "\n"; | |
123 | std::cerr << "Error: Corrupt data file: " << path << "\n"; | |
119 | 124 | return ret; |
120 | 125 | } |
121 | 126 | PHYSFS_close(myfile); |
123 | 128 | //The above might fail an return null. |
124 | 129 | if (!rw) { |
125 | 130 | PHYSFS_close(myfile); |
126 | std::cerr << "Error. Curropt data file!\n"; | |
131 | std::cerr << "Error. Corrupt data file!\n"; | |
127 | 132 | return NULL; |
128 | 133 | } |
129 | 134 | SDL_Surface* surface = IMG_Load_RW(rw,true); |
144 | 149 | return ret; |
145 | 150 | } |
146 | 151 | std::string path = "fonts/"+fontName+".ttf"; |
147 | if (data->verbose) { | |
152 | if (data->verbose) { | |
148 | 153 | printFileWeLoad(path); |
149 | 154 | } |
150 | 155 | if (!PHYSFS_exists(path.c_str())) { |
154 | 159 | PHYSFS_file* myfile = PHYSFS_openRead(path.c_str()); |
155 | 160 | unsigned int m_size = PHYSFS_fileLength(myfile); |
156 | 161 | std::unique_ptr<char[]> m_data(new char[m_size]); |
157 | int length_read = PHYSFS_read (myfile, m_data.get(), 1, m_size); | |
162 | int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size); | |
158 | 163 | if (length_read != (int)m_size) { |
159 | 164 | PHYSFS_close(myfile); |
160 | std::cerr << "Error: Curropt data file: " << path << "\n"; | |
165 | std::cerr << "Error: Corrupt data file: " << path << "\n"; | |
161 | 166 | return ret; |
162 | 167 | } |
163 | 168 | PHYSFS_close(myfile); |
167 | 172 | //The above might fail an return null. |
168 | 173 | if (!rw) { |
169 | 174 | PHYSFS_close(myfile); |
170 | std::cerr << "Error: Curropt data file!\n"; | |
175 | std::cerr << "Error: Corrupt data file!\n"; | |
171 | 176 | return ret; |
172 | 177 | } |
173 | 178 | |
187 | 192 | return ret; |
188 | 193 | } |
189 | 194 | std::string path = "music/"+musicName+".ogg"; |
190 | if (data->verbose) { | |
195 | if (data->verbose) { | |
191 | 196 | printFileWeLoad(path); |
192 | 197 | } |
193 | 198 | if (!PHYSFS_exists(path.c_str())) { |
197 | 202 | PHYSFS_file* myfile = PHYSFS_openRead(path.c_str()); |
198 | 203 | unsigned int m_size = PHYSFS_fileLength(myfile); |
199 | 204 | std::unique_ptr<char[]> m_data(new char[m_size]); |
200 | int length_read = PHYSFS_read (myfile, m_data.get(), 1, m_size); | |
205 | int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size); | |
201 | 206 | if (length_read != (int)m_size) { |
202 | 207 | PHYSFS_close(myfile); |
203 | std::cerr << "Error: Curropt data file: " << path << "\n"; | |
208 | std::cerr << "Error: Corrupt data file: " << path << "\n"; | |
204 | 209 | return ret; |
205 | 210 | } |
206 | 211 | PHYSFS_close(myfile); |
209 | 214 | //The above might fail an return null. |
210 | 215 | if (!rw) { |
211 | 216 | PHYSFS_close(myfile); |
212 | std::cerr << "Error. Curropt data file!\n"; | |
217 | std::cerr << "Error. Corrupt data file!\n"; | |
213 | 218 | return NULL; |
214 | 219 | } |
215 | 220 | |
230 | 235 | return ret; |
231 | 236 | } |
232 | 237 | std::string path = "sounds/"+soundName+".ogg"; |
233 | if (data->verbose) { | |
238 | if (data->verbose) { | |
234 | 239 | printFileWeLoad(path); |
235 | 240 | } |
236 | 241 | if (!PHYSFS_exists(path.c_str())) { |
240 | 245 | PHYSFS_file* myfile = PHYSFS_openRead(path.c_str()); |
241 | 246 | unsigned int m_size = PHYSFS_fileLength(myfile); |
242 | 247 | std::unique_ptr<char[]> m_data(new char[m_size]); |
243 | int length_read = PHYSFS_read (myfile, m_data.get(), 1, m_size); | |
248 | int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size); | |
244 | 249 | if (length_read != (int)m_size) { |
245 | 250 | PHYSFS_close(myfile); |
246 | std::cerr << "Error: Curropt data file: " << path << "\n"; | |
251 | std::cerr << "Error: Corrupt data file: " << path << "\n"; | |
247 | 252 | return ret; |
248 | 253 | } |
249 | 254 | PHYSFS_close(myfile); |
252 | 257 | //The above might fail an return null. |
253 | 258 | if (!rw) { |
254 | 259 | PHYSFS_close(myfile); |
255 | std::cerr << "Error. Curropt data file!\n"; | |
260 | std::cerr << "Error. Corrupt data file!\n"; | |
256 | 261 | return NULL; |
257 | 262 | } |
258 | 263 | |
272 | 277 | |
273 | 278 | TextureHandler::TextureHandler(const SagoDataHolder* holder, const std::string &textureName) { |
274 | 279 | this->holder = holder; |
275 | this->version = this->holder->getVersion(); | |
280 | this->version = 0; | |
276 | 281 | this->textureName = textureName; |
277 | this->data = this->holder->getTexturePtr(this->textureName); | |
282 | this->data = nullptr; | |
278 | 283 | } |
279 | 284 | |
280 | 285 | SDL_Texture* TextureHandler::get() { |
288 | 293 | |
289 | 294 | MusicHandler::MusicHandler(const SagoDataHolder* holder, const std::string& musicName) { |
290 | 295 | this->holder = holder; |
291 | this->version = this->holder->getVersion(); | |
296 | this->version = 0; | |
292 | 297 | this->musicName = musicName; |
293 | this->data = this->holder->getMusicPtr(this->musicName); | |
298 | this->data = nullptr; | |
294 | 299 | } |
295 | 300 | |
296 | 301 | Mix_Music* MusicHandler::get() { |
303 | 308 | |
304 | 309 | SoundHandler::SoundHandler(const SagoDataHolder* holder, const std::string& soundName) { |
305 | 310 | this->holder = holder; |
306 | this->version = this->holder->getVersion(); | |
311 | this->version = 0; | |
307 | 312 | this->soundName = soundName; |
308 | this->data = this->holder->getSoundPtr(this->soundName); | |
313 | this->data = nullptr; | |
309 | 314 | } |
310 | 315 | |
311 | 316 | Mix_Chunk* SoundHandler::get() { |
28 | 28 | #include <string.h> |
29 | 29 | #include <memory> |
30 | 30 | |
31 | #if PHYSFS_VER_MAJOR < 3 | |
32 | #define PHYSFS_readBytes(X,Y,Z) PHYSFS_read(X,Y,1,Z) | |
33 | #define PHYSFS_writeBytes(X,Y,Z) PHYSFS_write(X,Y,1,Z) | |
34 | #endif | |
35 | ||
31 | 36 | using std::string; |
32 | 37 | using std::cerr; |
33 | 38 | using std::vector; |
58 | 63 | PHYSFS_file* myfile = PHYSFS_openRead(filename); |
59 | 64 | unsigned int m_size = PHYSFS_fileLength(myfile); |
60 | 65 | std::unique_ptr<char[]> m_data(new char[m_size]); |
61 | int length_read = PHYSFS_read (myfile, m_data.get(), 1, m_size); | |
66 | int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size); | |
62 | 67 | if (length_read != (int)m_size) { |
63 | 68 | PHYSFS_close(myfile); |
64 | 69 | cerr << "Error: Curropt data file: " << filename << "\n"; |
84 | 89 | CreatePathToFile(filename); |
85 | 90 | PHYSFS_file* myfile = PHYSFS_openWrite(filename); |
86 | 91 | if (!myfile) { |
87 | cerr << "Failed to open file for writing, " << PHYSFS_getLastError() << "\n"; | |
92 | #if PHYSFS_VER_MAJOR > 2 | |
93 | PHYSFS_ErrorCode code = PHYSFS_getLastErrorCode(); | |
94 | std::cerr << "Failed to open file for writing, " << PHYSFS_getErrorByCode(code) << " (" << code << ")\n"; | |
95 | #else | |
96 | std::cerr << "Failed to open file for writing, " << PHYSFS_getLastError() << "\n"; | |
97 | #endif | |
88 | 98 | return; |
89 | 99 | } |
90 | PHYSFS_write(myfile, content.c_str(), sizeof(char), content.length()); | |
100 | PHYSFS_writeBytes(myfile, content.c_str(), sizeof(char)*content.length()); | |
91 | 101 | PHYSFS_close(myfile); |
92 | 102 | } |
93 | 103 |
28 | 28 | #include <string> |
29 | 29 | |
30 | 30 | namespace sago { |
31 | ||
31 | ||
32 | 32 | /** |
33 | 33 | * Returns a vector with all filenames in a given directory. |
34 | 34 | * PHYSFS must be setup before hand. The directory is relative to the PHYSFS base |
36 | 36 | * @return A vector with the filenames in the given directory. If empty the directory was empty or did not exist |
37 | 37 | */ |
38 | 38 | std::vector<std::string> GetFileList(const char* dir); |
39 | ||
39 | ||
40 | 40 | /** |
41 | 41 | * Reads an entire file into memory. |
42 | 42 | * PHYSFS must be setup before hand |
44 | 44 | * @return The content of the file. If empty either the file was empty, did not exist or could not be opened |
45 | 45 | */ |
46 | 46 | std::string GetFileContent(const char* filename); |
47 | ||
47 | ||
48 | 48 | /** |
49 | 49 | * Reads an entire file into memory. |
50 | 50 | * PHYSFS must be setup before hand |
52 | 52 | * @return The content of the file. If empty either the file was empty, did not exist or could not be opened |
53 | 53 | */ |
54 | 54 | inline std::string GetFileContent(const std::string& filename) { return GetFileContent(filename.c_str()); }; |
55 | ||
55 | ||
56 | 56 | bool FileExists(const char* filename); |
57 | ||
57 | ||
58 | 58 | void WriteFileContent(const char* filename, const std::string& content); |
59 | ||
59 | ||
60 | 60 | /** |
61 | * This functions convers a string on a best effort basis | |
61 | * This functions converts a string on a best effort basis | |
62 | 62 | * Unlike atol this does NOT cause undefined behavior if out of range |
63 | 63 | * @param c_string A string that may contain a number |
64 | 64 | * @return A number between LONG_MIN and LONG_MAX (both inclusive) |
65 | 65 | */ |
66 | 66 | long int StrToLong(const char* c_string); |
67 | ||
67 | ||
68 | 68 | } //namespace sago |
69 | 69 | |
70 | 70 | #endif /* SAGOMISC_HPP */ |
208 | 208 | x -= texW/2; |
209 | 209 | } |
210 | 210 | if (alignment == Alignment::right) { |
211 | y -= texW; | |
211 | x -= texW; | |
212 | 212 | } |
213 | 213 | if (verticalAlignment == VerticalAlignment::center) { |
214 | 214 | y -= texH/2; |
28 | 28 | #include "platform_folders.h" |
29 | 29 | #include <iostream> |
30 | 30 | #include <stdexcept> |
31 | #include <string.h> | |
32 | 31 | #include <cstdio> |
33 | 32 | #include <cstdlib> |
34 | 33 | |
35 | #if defined(_WIN32) | |
36 | #include <windows.h> | |
37 | #include <shlobj.h> | |
38 | ||
39 | static std::string win32_utf16_to_utf8(const wchar_t* wstr) { | |
40 | std::string res; | |
41 | // If the 6th parameter is 0 then WideCharToMultiByte returns the number of bytes needed to store the result. | |
42 | int actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); | |
43 | if (actualSize > 0) { | |
44 | //If the converted UTF-8 string could not be in the initial buffer. Allocate one that can hold it. | |
45 | std::vector<char> buffer(actualSize); | |
46 | actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &buffer[0], buffer.size(), NULL, NULL); | |
47 | res = buffer.data(); | |
48 | } | |
49 | if (actualSize == 0) { | |
50 | // WideCharToMultiByte return 0 for errors. | |
51 | const std::string errorMsg = "UTF16 to UTF8 failed with error code: " + GetLastError(); | |
52 | throw std::runtime_error(errorMsg.c_str()); | |
53 | } | |
54 | return res; | |
55 | } | |
56 | ||
57 | static std::string GetWindowsFolder(int folderId, const char* errorMsg) { | |
58 | wchar_t szPath[MAX_PATH]; | |
59 | szPath[0] = 0; | |
60 | if ( !SUCCEEDED( SHGetFolderPathW( NULL, folderId, NULL, 0, szPath ) ) ) { | |
61 | throw std::runtime_error(errorMsg); | |
62 | } | |
63 | return win32_utf16_to_utf8(szPath); | |
64 | } | |
65 | ||
66 | static std::string GetAppData() { | |
67 | return GetWindowsFolder(CSIDL_APPDATA, "RoamingAppData could not be found"); | |
68 | } | |
69 | ||
70 | static std::string GetAppDataCommon() { | |
71 | return GetWindowsFolder(CSIDL_COMMON_APPDATA, "Common appdata could not be found"); | |
72 | } | |
73 | ||
74 | static std::string GetAppDataLocal() { | |
75 | return GetWindowsFolder(CSIDL_LOCAL_APPDATA, "LocalAppData could not be found"); | |
76 | } | |
77 | #elif defined(__APPLE__) | |
78 | #include <CoreServices/CoreServices.h> | |
79 | ||
80 | static std::string GetMacFolder(OSType folderType, const char* errorMsg) { | |
81 | std::string ret; | |
82 | FSRef ref; | |
83 | char path[PATH_MAX]; | |
84 | OSStatus err = FSFindFolder( kUserDomain, folderType, kCreateFolder, &ref ); | |
85 | if (err != noErr) { | |
86 | throw std::runtime_error(errorMsg); | |
87 | } | |
88 | FSRefMakePath( &ref, (UInt8*)&path, PATH_MAX ); | |
89 | ret = path; | |
90 | return ret; | |
91 | } | |
92 | ||
93 | #else | |
94 | #include <map> | |
95 | #include <fstream> | |
34 | #ifndef _WIN32 | |
35 | ||
96 | 36 | #include <pwd.h> |
97 | 37 | #include <unistd.h> |
98 | #include <sys/types.h> | |
99 | // For strlen and strtok | |
100 | #include <cstring> | |
101 | //Typically Linux. For easy reading the comments will just say Linux but should work with most *nixes | |
102 | ||
103 | static void throwOnRelative(const char* envName, const char* envValue) { | |
104 | if (envValue[0] != '/') { | |
105 | char buffer[200]; | |
106 | std::snprintf(buffer, sizeof(buffer), "Environment \"%s\" does not start with an '/'. XDG specifies that the value must be absolute. The current value is: \"%s\"", envName, envValue); | |
107 | throw std::runtime_error(buffer); | |
108 | } | |
109 | } | |
110 | 38 | |
111 | 39 | /** |
112 | 40 | * Retrives the effective user's home dir. |
123 | 51 | res = homeEnv; |
124 | 52 | return res; |
125 | 53 | } |
126 | struct passwd* pw = getpwuid(uid); | |
127 | if (!pw) { | |
54 | struct passwd* pw = nullptr; | |
55 | struct passwd pwd; | |
56 | long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); | |
57 | if (bufsize < 0) { | |
58 | bufsize = 16384; | |
59 | } | |
60 | std::vector<char> buffer; | |
61 | buffer.resize(bufsize); | |
62 | int error_code = getpwuid_r(uid, &pwd, buffer.data(), buffer.size(), &pw); | |
63 | if (error_code) { | |
128 | 64 | throw std::runtime_error("Unable to get passwd struct."); |
129 | 65 | } |
130 | 66 | const char* tempRes = pw->pw_dir; |
134 | 70 | res = tempRes; |
135 | 71 | return res; |
136 | 72 | } |
73 | ||
74 | #endif | |
75 | ||
76 | #ifdef _WIN32 | |
77 | // Make sure we don't bring in all the extra junk with windows.h | |
78 | #ifndef WIN32_LEAN_AND_MEAN | |
79 | #define WIN32_LEAN_AND_MEAN | |
80 | #endif | |
81 | // stringapiset.h depends on this | |
82 | #include <windows.h> | |
83 | // For SUCCEEDED macro | |
84 | #include <winerror.h> | |
85 | // For WideCharToMultiByte | |
86 | #include <stringapiset.h> | |
87 | // For SHGetFolderPathW and various CSIDL "magic numbers" | |
88 | #include <shlobj.h> | |
89 | ||
90 | namespace sago { | |
91 | namespace internal { | |
92 | ||
93 | std::string win32_utf16_to_utf8(const wchar_t* wstr) { | |
94 | std::string res; | |
95 | // If the 6th parameter is 0 then WideCharToMultiByte returns the number of bytes needed to store the result. | |
96 | int actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); | |
97 | if (actualSize > 0) { | |
98 | //If the converted UTF-8 string could not be in the initial buffer. Allocate one that can hold it. | |
99 | std::vector<char> buffer(actualSize); | |
100 | actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &buffer[0], static_cast<int>(buffer.size()), nullptr, nullptr); | |
101 | res = buffer.data(); | |
102 | } | |
103 | if (actualSize == 0) { | |
104 | // WideCharToMultiByte return 0 for errors. | |
105 | const std::string errorMsg = "UTF16 to UTF8 failed with error code: " + GetLastError(); | |
106 | throw std::runtime_error(errorMsg.c_str()); | |
107 | } | |
108 | return res; | |
109 | } | |
110 | ||
111 | } // namesapce internal | |
112 | } // namespace sago | |
113 | ||
114 | class FreeCoTaskMemory { | |
115 | LPWSTR pointer = NULL; | |
116 | public: | |
117 | explicit FreeCoTaskMemory(LPWSTR pointer) : pointer(pointer) {}; | |
118 | ~FreeCoTaskMemory() { | |
119 | CoTaskMemFree(pointer); | |
120 | } | |
121 | }; | |
122 | ||
123 | static std::string GetKnownWindowsFolder(REFKNOWNFOLDERID folderId, const char* errorMsg) { | |
124 | LPWSTR wszPath = NULL; | |
125 | HRESULT hr; | |
126 | hr = SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, NULL, &wszPath); | |
127 | FreeCoTaskMemory scopeBoundMemory(wszPath); | |
128 | ||
129 | if (!SUCCEEDED(hr)) { | |
130 | throw std::runtime_error(errorMsg); | |
131 | } | |
132 | return sago::internal::win32_utf16_to_utf8(wszPath); | |
133 | } | |
134 | ||
135 | static std::string GetAppData() { | |
136 | return GetKnownWindowsFolder(FOLDERID_RoamingAppData, "RoamingAppData could not be found"); | |
137 | } | |
138 | ||
139 | static std::string GetAppDataCommon() { | |
140 | return GetKnownWindowsFolder(FOLDERID_ProgramData, "ProgramData could not be found"); | |
141 | } | |
142 | ||
143 | static std::string GetAppDataLocal() { | |
144 | return GetKnownWindowsFolder(FOLDERID_LocalAppData, "LocalAppData could not be found"); | |
145 | } | |
146 | #elif defined(__APPLE__) | |
147 | #else | |
148 | #include <map> | |
149 | #include <fstream> | |
150 | #include <sys/types.h> | |
151 | // For strlen and strtok | |
152 | #include <cstring> | |
153 | #include <sstream> | |
154 | //Typically Linux. For easy reading the comments will just say Linux but should work with most *nixes | |
155 | ||
156 | static void throwOnRelative(const char* envName, const char* envValue) { | |
157 | if (envValue[0] != '/') { | |
158 | char buffer[200]; | |
159 | std::snprintf(buffer, sizeof(buffer), "Environment \"%s\" does not start with an '/'. XDG specifies that the value must be absolute. The current value is: \"%s\"", envName, envValue); | |
160 | throw std::runtime_error(buffer); | |
161 | } | |
162 | } | |
163 | ||
164 | ||
137 | 165 | |
138 | 166 | static std::string getLinuxFolderDefault(const char* envName, const char* defaultRelativePath) { |
139 | 167 | std::string res; |
147 | 175 | return res; |
148 | 176 | } |
149 | 177 | |
150 | static void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders) { | |
151 | std::vector<char> buffer(envValue, envValue + std::strlen(envValue) + 1); | |
152 | char* p = std::strtok ( &buffer[0], ":"); | |
153 | while (p != NULL) { | |
154 | if (p[0] == '/') { | |
155 | folders.push_back(p); | |
156 | } | |
157 | else { | |
158 | //Unless the system is wrongly configured this should never happen... But of course some systems will be incorectly configured. | |
159 | //The XDG documentation indicates that the folder should be ignored but that the program should continue. | |
160 | std::cerr << "Skipping path \"" << p << "\" in \"" << envName << "\" because it does not start with a \"/\"\n"; | |
161 | } | |
162 | p = std::strtok (NULL, ":"); | |
163 | } | |
164 | } | |
165 | ||
166 | 178 | static void appendExtraFolders(const char* envName, const char* defaultValue, std::vector<std::string>& folders) { |
167 | 179 | const char* envValue = std::getenv(envName); |
168 | 180 | if (!envValue) { |
169 | 181 | envValue = defaultValue; |
170 | 182 | } |
171 | appendExtraFoldersTokenizer(envName, envValue, folders); | |
183 | sago::internal::appendExtraFoldersTokenizer(envName, envValue, folders); | |
172 | 184 | } |
173 | 185 | |
174 | 186 | #endif |
176 | 188 | |
177 | 189 | namespace sago { |
178 | 190 | |
191 | #if !defined(_WIN32) && !defined(__APPLE__) | |
192 | namespace internal { | |
193 | void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders) { | |
194 | std::stringstream ss(envValue); | |
195 | std::string value; | |
196 | while (std::getline(ss, value, ':')) { | |
197 | if (value[0] == '/') { | |
198 | folders.push_back(value); | |
199 | } | |
200 | else { | |
201 | //Unless the system is wrongly configured this should never happen... But of course some systems will be incorectly configured. | |
202 | //The XDG documentation indicates that the folder should be ignored but that the program should continue. | |
203 | std::cerr << "Skipping path \"" << value << "\" in \"" << envName << "\" because it does not start with a \"/\"\n"; | |
204 | } | |
205 | } | |
206 | } | |
207 | } | |
208 | #endif | |
209 | ||
179 | 210 | std::string getDataHome() { |
180 | #if defined(_WIN32) | |
211 | #ifdef _WIN32 | |
181 | 212 | return GetAppData(); |
182 | 213 | #elif defined(__APPLE__) |
183 | return GetMacFolder(kApplicationSupportFolderType, "Failed to find the Application Support Folder"); | |
214 | return getHome()+"/Library/Application Support"; | |
184 | 215 | #else |
185 | 216 | return getLinuxFolderDefault("XDG_DATA_HOME", ".local/share"); |
186 | 217 | #endif |
187 | 218 | } |
188 | 219 | |
189 | 220 | std::string getConfigHome() { |
190 | #if defined(_WIN32) | |
221 | #ifdef _WIN32 | |
191 | 222 | return GetAppData(); |
192 | 223 | #elif defined(__APPLE__) |
193 | return GetMacFolder(kApplicationSupportFolderType, "Failed to find the Application Support Folder"); | |
224 | return getHome()+"/Library/Application Support"; | |
194 | 225 | #else |
195 | 226 | return getLinuxFolderDefault("XDG_CONFIG_HOME", ".config"); |
196 | 227 | #endif |
197 | 228 | } |
198 | 229 | |
199 | 230 | std::string getCacheDir() { |
200 | #if defined(_WIN32) | |
231 | #ifdef _WIN32 | |
201 | 232 | return GetAppDataLocal(); |
202 | 233 | #elif defined(__APPLE__) |
203 | return GetMacFolder(kCachedDataFolderType, "Failed to find the Application Support Folder"); | |
234 | return getHome()+"/Library/Caches"; | |
204 | 235 | #else |
205 | 236 | return getLinuxFolderDefault("XDG_CACHE_HOME", ".cache"); |
206 | 237 | #endif |
207 | 238 | } |
208 | 239 | |
209 | 240 | void appendAdditionalDataDirectories(std::vector<std::string>& homes) { |
210 | #if defined(_WIN32) | |
241 | #ifdef _WIN32 | |
211 | 242 | homes.push_back(GetAppDataCommon()); |
212 | #elif defined(__APPLE__) | |
213 | #else | |
243 | #elif !defined(__APPLE__) | |
214 | 244 | appendExtraFolders("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/", homes); |
215 | 245 | #endif |
216 | 246 | } |
217 | 247 | |
218 | 248 | void appendAdditionalConfigDirectories(std::vector<std::string>& homes) { |
219 | #if defined(_WIN32) | |
249 | #ifdef _WIN32 | |
220 | 250 | homes.push_back(GetAppDataCommon()); |
221 | #elif defined(__APPLE__) | |
222 | #else | |
251 | #elif !defined(__APPLE__) | |
223 | 252 | appendExtraFolders("XDG_CONFIG_DIRS", "/etc/xdg", homes); |
224 | 253 | #endif |
225 | 254 | } |
226 | 255 | |
227 | #if defined(_WIN32) | |
228 | #elif defined(__APPLE__) | |
229 | #else | |
256 | #if !defined(_WIN32) && !defined(__APPLE__) | |
230 | 257 | struct PlatformFolders::PlatformFoldersData { |
231 | 258 | std::map<std::string, std::string> folders; |
232 | 259 | }; |
245 | 272 | std::size_t valueEnd = line.find('"', valueStart+1); |
246 | 273 | std::string value = line.substr(valueStart+1, valueEnd - valueStart - 1); |
247 | 274 | folders[key] = value; |
248 | } catch (std::exception& e) { | |
275 | } | |
276 | catch (std::exception& e) { | |
249 | 277 | std::cerr << "WARNING: Failed to process \"" << line << "\" from \"" << filename << "\". Error: "<< e.what() << "\n"; |
250 | 278 | continue; |
251 | 279 | } |
272 | 300 | #endif |
273 | 301 | |
274 | 302 | PlatformFolders::PlatformFolders() { |
275 | #if defined(_WIN32) | |
276 | #elif defined(__APPLE__) | |
277 | #else | |
303 | #if !defined(_WIN32) && !defined(__APPLE__) | |
278 | 304 | this->data = new PlatformFolders::PlatformFoldersData(); |
279 | 305 | try { |
280 | 306 | PlatformFoldersFillData(data->folders); |
287 | 313 | } |
288 | 314 | |
289 | 315 | PlatformFolders::~PlatformFolders() { |
290 | #if defined(_WIN32) | |
291 | #elif defined(__APPLE__) | |
292 | #else | |
316 | #if !defined(_WIN32) && !defined(__APPLE__) | |
293 | 317 | delete this->data; |
294 | 318 | #endif |
295 | 319 | } |
296 | 320 | |
297 | 321 | std::string PlatformFolders::getDocumentsFolder() const { |
298 | #if defined(_WIN32) | |
299 | return GetWindowsFolder(CSIDL_PERSONAL, "Failed to find My Documents folder"); | |
300 | #elif defined(__APPLE__) | |
301 | return GetMacFolder(kDocumentsFolderType, "Failed to find Documents Folder"); | |
322 | #ifdef _WIN32 | |
323 | return GetKnownWindowsFolder(FOLDERID_Documents, "Failed to find My Documents folder"); | |
324 | #elif defined(__APPLE__) | |
325 | return getHome()+"/Documents"; | |
302 | 326 | #else |
303 | 327 | return data->folders["XDG_DOCUMENTS_DIR"]; |
304 | 328 | #endif |
305 | 329 | } |
306 | 330 | |
307 | 331 | std::string PlatformFolders::getDesktopFolder() const { |
308 | #if defined(_WIN32) | |
309 | return GetWindowsFolder(CSIDL_DESKTOP, "Failed to find Desktop folder"); | |
310 | #elif defined(__APPLE__) | |
311 | return GetMacFolder(kDesktopFolderType, "Failed to find Desktop folder"); | |
332 | #ifdef _WIN32 | |
333 | return GetKnownWindowsFolder(FOLDERID_Desktop, "Failed to find Desktop folder"); | |
334 | #elif defined(__APPLE__) | |
335 | return getHome()+"/Desktop"; | |
312 | 336 | #else |
313 | 337 | return data->folders["XDG_DESKTOP_DIR"]; |
314 | 338 | #endif |
315 | 339 | } |
316 | 340 | |
317 | 341 | std::string PlatformFolders::getPicturesFolder() const { |
318 | #if defined(_WIN32) | |
319 | return GetWindowsFolder(CSIDL_MYPICTURES, "Failed to find My Pictures folder"); | |
320 | #elif defined(__APPLE__) | |
321 | return GetMacFolder(kPictureDocumentsFolderType, "Failed to find Picture folder"); | |
342 | #ifdef _WIN32 | |
343 | return GetKnownWindowsFolder(FOLDERID_Pictures, "Failed to find My Pictures folder"); | |
344 | #elif defined(__APPLE__) | |
345 | return getHome()+"/Pictures"; | |
322 | 346 | #else |
323 | 347 | return data->folders["XDG_PICTURES_DIR"]; |
324 | 348 | #endif |
325 | 349 | } |
326 | 350 | |
351 | std::string PlatformFolders::getPublicFolder() const { | |
352 | #ifdef _WIN32 | |
353 | return GetKnownWindowsFolder(FOLDERID_Public, "Failed to find the Public folder"); | |
354 | #elif defined(__APPLE__) | |
355 | return getHome()+"/Public"; | |
356 | #else | |
357 | return data->folders["XDG_PUBLICSHARE_DIR"]; | |
358 | #endif | |
359 | } | |
360 | ||
327 | 361 | std::string PlatformFolders::getDownloadFolder1() const { |
328 | #if defined(_WIN32) | |
329 | //Pre Vista. Files was downloaded to the desktop | |
330 | return GetWindowsFolder(CSIDL_DESKTOP, "Failed to find My Downloads (Desktop) folder"); | |
331 | #elif defined(__APPLE__) | |
332 | return GetMacFolder(kDownloadsFolderType, "Failed to find Download folder"); | |
362 | #ifdef _WIN32 | |
363 | return GetKnownWindowsFolder(FOLDERID_Downloads, "Failed to find My Downloads folder"); | |
364 | #elif defined(__APPLE__) | |
365 | return getHome()+"/Downloads"; | |
333 | 366 | #else |
334 | 367 | return data->folders["XDG_DOWNLOAD_DIR"]; |
335 | 368 | #endif |
336 | 369 | } |
337 | 370 | |
338 | 371 | std::string PlatformFolders::getMusicFolder() const { |
339 | #if defined(_WIN32) | |
340 | return GetWindowsFolder(CSIDL_MYMUSIC, "Failed to find My Music folder"); | |
341 | #elif defined(__APPLE__) | |
342 | return GetMacFolder(kMusicDocumentsFolderType, "Failed to find Music folder"); | |
372 | #ifdef _WIN32 | |
373 | return GetKnownWindowsFolder(FOLDERID_Music, "Failed to find My Music folder"); | |
374 | #elif defined(__APPLE__) | |
375 | return getHome()+"/Music"; | |
343 | 376 | #else |
344 | 377 | return data->folders["XDG_MUSIC_DIR"]; |
345 | 378 | #endif |
346 | 379 | } |
347 | 380 | |
348 | 381 | std::string PlatformFolders::getVideoFolder() const { |
349 | #if defined(_WIN32) | |
350 | return GetWindowsFolder(CSIDL_MYVIDEO, "Failed to find My Video folder"); | |
351 | #elif defined(__APPLE__) | |
352 | return GetMacFolder(kMovieDocumentsFolderType, "Failed to find Movie folder"); | |
382 | #ifdef _WIN32 | |
383 | return GetKnownWindowsFolder(FOLDERID_Videos, "Failed to find My Video folder"); | |
384 | #elif defined(__APPLE__) | |
385 | return getHome()+"/Movies"; | |
353 | 386 | #else |
354 | 387 | return data->folders["XDG_VIDEOS_DIR"]; |
355 | 388 | #endif |
356 | 389 | } |
357 | 390 | |
358 | 391 | std::string PlatformFolders::getSaveGamesFolder1() const { |
359 | #if defined(_WIN32) | |
392 | #ifdef _WIN32 | |
360 | 393 | //A dedicated Save Games folder was not introduced until Vista. For XP and older save games are most often saved in a normal folder named "My Games". |
361 | 394 | //Data that should not be user accessible should be placed under GetDataHome() instead |
362 | return GetWindowsFolder(CSIDL_PERSONAL, "Failed to find My Documents folder")+"\\My Games"; | |
363 | #elif defined(__APPLE__) | |
364 | return GetMacFolder(kApplicationSupportFolderType, "Failed to find Application Support Folder"); | |
395 | return GetKnownWindowsFolder(FOLDERID_Documents, "Failed to find My Documents folder")+"\\My Games"; | |
396 | #elif defined(__APPLE__) | |
397 | return getHome()+"/Library/Application Support"; | |
365 | 398 | #else |
366 | 399 | return getDataHome(); |
367 | 400 | #endif |
375 | 408 | return PlatformFolders().getDocumentsFolder(); |
376 | 409 | } |
377 | 410 | |
411 | std::string getDownloadFolder() { | |
412 | return PlatformFolders().getDownloadFolder1(); | |
413 | } | |
414 | ||
378 | 415 | std::string getDownloadFolder1() { |
379 | return PlatformFolders().getDownloadFolder1(); | |
416 | return getDownloadFolder(); | |
380 | 417 | } |
381 | 418 | |
382 | 419 | std::string getPicturesFolder() { |
383 | 420 | return PlatformFolders().getPicturesFolder(); |
384 | 421 | } |
385 | 422 | |
423 | std::string getPublicFolder() { | |
424 | return PlatformFolders().getPublicFolder(); | |
425 | } | |
426 | ||
386 | 427 | std::string getMusicFolder() { |
387 | 428 | return PlatformFolders().getMusicFolder(); |
388 | 429 | } |
395 | 436 | return PlatformFolders().getSaveGamesFolder1(); |
396 | 437 | } |
397 | 438 | |
439 | std::string getSaveGamesFolder2() { | |
440 | #ifdef _WIN32 | |
441 | return GetKnownWindowsFolder(FOLDERID_SavedGames, "Failed to find Saved Games folder"); | |
442 | #else | |
443 | return PlatformFolders().getSaveGamesFolder1(); | |
444 | #endif | |
445 | } | |
398 | 446 | |
399 | 447 | } //namespace sago |
36 | 36 | */ |
37 | 37 | namespace sago { |
38 | 38 | |
39 | /** | |
40 | * Retrives the base folder for storring data files. | |
39 | #ifndef DOXYGEN_SHOULD_SKIP_THIS | |
40 | namespace internal { | |
41 | #if !defined(_WIN32) && !defined(__APPLE__) | |
42 | void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders); | |
43 | #endif | |
44 | #ifdef _WIN32 | |
45 | std::string win32_utf16_to_utf8(const wchar_t* wstr); | |
46 | #endif | |
47 | } | |
48 | #endif //DOXYGEN_SHOULD_SKIP_THIS | |
49 | ||
50 | /** | |
51 | * Retrives the base folder for storing data files. | |
41 | 52 | * You must add the program name yourself like this: |
42 | 53 | * @code{.cpp} |
43 | 54 | * string data_home = getDataHome()+"/My Program Name/"; |
44 | 55 | * @endcode |
45 | 56 | * On Windows this defaults to %APPDATA% (Roaming profile) |
46 | 57 | * On Linux this defaults to ~/.local/share but can be configured |
47 | * @return The base folder for storring program data. | |
58 | * @return The base folder for storing program data. | |
48 | 59 | */ |
49 | 60 | std::string getDataHome(); |
50 | 61 | |
51 | 62 | /** |
52 | * Retrives the base folder for storring config files. | |
63 | * Retrives the base folder for storing config files. | |
53 | 64 | * You must add the program name yourself like this: |
54 | 65 | * @code{.cpp} |
55 | 66 | * string data_home = getConfigHome()+"/My Program Name/"; |
56 | 67 | * @endcode |
57 | 68 | * On Windows this defaults to %APPDATA% (Roaming profile) |
58 | 69 | * On Linux this defaults to ~/.config but can be configured |
59 | * @return The base folder for storring config data. | |
70 | * @return The base folder for storing config data. | |
60 | 71 | */ |
61 | 72 | std::string getConfigHome(); |
62 | 73 | |
63 | 74 | /** |
64 | * Retrives the base folder for storring cache files. | |
75 | * Retrives the base folder for storing cache files. | |
65 | 76 | * You must add the program name yourself like this: |
66 | 77 | * @code{.cpp} |
67 | 78 | * string data_home = getCacheDir()+"/My Program Name/"; |
68 | 79 | * @endcode |
69 | 80 | * On Windows this defaults to %APPDATALOCAL% |
70 | 81 | * On Linux this defaults to ~/.cache but can be configured |
71 | * @return The base folder for storring data that do not need to be backed up. | |
82 | * @return The base folder for storing data that do not need to be backed up. | |
72 | 83 | */ |
73 | 84 | std::string getCacheDir(); |
74 | 85 | |
123 | 134 | |
124 | 135 | /** |
125 | 136 | * The folder where files are downloaded. |
126 | * @note Windows: This version is XP compatible and returns the Desktop. Vista and later has a dedicated folder. | |
127 | 137 | * @return Absolute path to the folder where files are downloaded to. |
128 | 138 | */ |
139 | std::string getDownloadFolder(); | |
140 | ||
141 | /** | |
142 | * The folder where files are downloaded. | |
143 | * @note This is provided for backward compatibility. Use getDownloadFolder instead. | |
144 | * @return Absolute path to the folder where files are downloaded to. | |
145 | */ | |
129 | 146 | std::string getDownloadFolder1(); |
130 | 147 | |
131 | 148 | /** |
132 | * The folder for storring the user's pictures. | |
149 | * The folder for storing the user's pictures. | |
133 | 150 | * @return Absolute path to the "Picture" folder |
134 | 151 | */ |
135 | 152 | std::string getPicturesFolder(); |
153 | ||
154 | /** | |
155 | * This returns the folder that can be used for sharing files with other users on the same system. | |
156 | * @return Absolute path to the "Public" folder | |
157 | */ | |
158 | std::string getPublicFolder(); | |
136 | 159 | |
137 | 160 | /** |
138 | 161 | * The folder where music is stored |
147 | 170 | std::string getVideoFolder(); |
148 | 171 | |
149 | 172 | /** |
150 | * The base folder for storring saved games. | |
173 | * A base folder for storing saved games. | |
151 | 174 | * You must add the program name to it like this: |
152 | 175 | * @code{.cpp} |
153 | 176 | * string saved_games_folder = sago::getSaveGamesFolder1()+"/My Program Name/"; |
154 | 177 | * @endcode |
155 | 178 | * @note Windows: This is an XP compatible version and returns the path to "My Games" in Documents. Vista and later has an official folder. |
156 | 179 | * @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome() |
157 | * @return The folder base folder for storring save games. | |
180 | * @return The folder base folder for storing save games. | |
158 | 181 | */ |
159 | 182 | std::string getSaveGamesFolder1(); |
183 | ||
184 | /** | |
185 | * A base folder for storing saved games. | |
186 | * You must add the program name to it like this: | |
187 | * @code{.cpp} | |
188 | * string saved_games_folder = sago::getSaveGamesFolder2()+"/My Program Name/"; | |
189 | * @endcode | |
190 | * @note PlatformFolders provide different folders to for saved games as not all operating systems has support for Saved Games yet. | |
191 | * It is recommended to pick the highest number (currently getSaveGamesFolder2) at the time your product enters production and stick with it | |
192 | * @note Windows: This returns the "Saved Games" folder. This folder exist in Vista and later | |
193 | * @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome() | |
194 | * @return The folder base folder for storing save games. | |
195 | */ | |
196 | std::string getSaveGamesFolder2(); | |
160 | 197 | |
161 | 198 | #ifndef DOXYGEN_SHOULD_SKIP_THIS |
162 | 199 | |
182 | 219 | */ |
183 | 220 | std::string getDocumentsFolder() const; |
184 | 221 | /** |
185 | * The folder for storring the user's pictures. | |
222 | * The folder for storing the user's pictures. | |
186 | 223 | * @return Absolute path to the "Picture" folder |
187 | 224 | */ |
188 | 225 | std::string getPicturesFolder() const; |
226 | /** | |
227 | * Use sago::getPublicFolder() instead! | |
228 | */ | |
229 | std::string getPublicFolder() const; | |
189 | 230 | /** |
190 | 231 | * The folder where files are downloaded. |
191 | 232 | * @note Windows: This version is XP compatible and returns the Desktop. Vista and later has a dedicated folder. |
203 | 244 | */ |
204 | 245 | std::string getVideoFolder() const; |
205 | 246 | /** |
206 | * The base folder for storring saved games. | |
247 | * The base folder for storing saved games. | |
207 | 248 | * You must add the program name to it like this: |
208 | 249 | * @code{.cpp} |
209 | 250 | * PlatformFolders pf; |
211 | 252 | * @endcode |
212 | 253 | * @note Windows: This is an XP compatible version and returns the path to "My Games" in Documents. Vista and later has an official folder. |
213 | 254 | * @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome() |
214 | * @return The folder base folder for storring save games. | |
255 | * @return The folder base folder for storing save games. | |
215 | 256 | */ |
216 | 257 | std::string getSaveGamesFolder1() const; |
217 | 258 | private: |
218 | 259 | PlatformFolders(const PlatformFolders&); |
219 | 260 | PlatformFolders& operator=(const PlatformFolders&); |
220 | #if defined(_WIN32) | |
221 | #elif defined(__APPLE__) | |
222 | #else | |
261 | #if !defined(_WIN32) && !defined(__APPLE__) | |
223 | 262 | struct PlatformFoldersData; |
224 | 263 | PlatformFoldersData* data; |
225 | 264 | #endif |
16 | 16 | along with this program. If not, see http://www.gnu.org/licenses/ |
17 | 17 | |
18 | 18 | Source information and contacts persons can be found at |
19 | http://www.blockattack.net | |
19 | https://blockattack.net | |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 |
57 | 57 | } |
58 | 58 | |
59 | 59 | Stats* Stats::getInstance() { |
60 | if (Stats::instance==nullptr) { | |
60 | if (!Stats::instance) { | |
61 | 61 | Stats::instance = new Stats(); |
62 | 62 | |
63 | 63 | } |
16 | 16 | along with this program. If not, see http://www.gnu.org/licenses/ |
17 | 17 | |
18 | 18 | Source information and contacts persons can be found at |
19 | http://www.blockattack.net | |
19 | https://blockattack.net | |
20 | 20 | =========================================================================== |
21 | 21 | */ |
22 | 22 | |
23 | ||
24 | /* | |
25 | *Files will be saved in: | |
26 | * HOME/.local/share/"+GAMENAME (unix) | |
27 | *or DOCUMENTS/My Games/GAMENAME (Windows) | |
28 | */ | |
29 | #define GAMENAME "blockattack" | |
30 | ||
23 | 31 | #ifndef VERSION_NUMBER |
24 | #define VERSION_NUMBER "2.3.0" | |
32 | #define VERSION_NUMBER "2.5.0" | |
25 | 33 | #endif |
14 | 14 | |
15 | 15 | COPY . /staging/blockattack-game |
16 | 16 | |
17 | ENV BLOCKATTACK_VERSION 2.3.0 | |
17 | ENV BLOCKATTACK_VERSION 2.5.0 | |
18 | 18 | |
19 | 19 | RUN cd /staging/blockattack-game && \ |
20 | 20 | ./packdata.sh && \ |
0 | FROM fedora:29 | |
1 | ||
2 | RUN dnf -y install cmake \ | |
3 | make \ | |
4 | gcc-c++ \ | |
5 | SDL2-devel \ | |
6 | boost-devel \ | |
7 | physfs-devel \ | |
8 | SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel \ | |
9 | utf8cpp-devel \ | |
10 | findutils \ | |
11 | gettext \ | |
12 | zip \ | |
13 | && dnf -y clean all | |
14 | ||
15 | COPY . /staging/blockattack-game | |
16 | ||
17 | ENV BLOCKATTACK_VERSION 2.5.0 | |
18 | ||
19 | RUN cd /staging/blockattack-game && \ | |
20 | ./packdata.sh && \ | |
21 | cmake . && \ | |
22 | make |
15 | 15 | |
16 | 16 | COPY . /staging/blockattack-game |
17 | 17 | |
18 | ENV BLOCKATTACK_VERSION 2.3.0 | |
18 | ENV BLOCKATTACK_VERSION 2.5.0 | |
19 | 19 | |
20 | 20 | RUN cd /staging/blockattack-game && \ |
21 | 21 | ./packdata.sh && \ |
5 | 5 | |
6 | 6 | COPY . /staging/blockattack-game |
7 | 7 | |
8 | ENV BLOCKATTACK_VERSION 2.3.0 | |
8 | ENV BLOCKATTACK_VERSION 2.5.0 | |
9 | 9 | |
10 | 10 | RUN cd /staging/blockattack-game && \ |
11 | 11 | ./packdata.sh && \ |
6 | 6 | |
7 | 7 | COPY . /staging/blockattack-game |
8 | 8 | |
9 | ENV BLOCKATTACK_VERSION 2.3.0 | |
9 | ENV BLOCKATTACK_VERSION 2.5.0 | |
10 | 10 | |
11 | 11 | RUN cd /staging/blockattack-game && \ |
12 | 12 | ./packdata.sh && \ |
6 | 6 | |
7 | 7 | COPY . /staging/blockattack-game |
8 | 8 | |
9 | ENV BLOCKATTACK_VERSION 2.3.0 | |
9 | ENV BLOCKATTACK_VERSION 2.5.0 | |
10 | 10 | |
11 | 11 | RUN cd /staging/blockattack-game && \ |
12 | 12 | ./packdata.sh && \ |
0 | FROM ubuntu:16.04 | |
1 | ||
2 | RUN apt-get update && apt-get install -yy build-essential libphysfs-dev libboost-dev cmake libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libboost-program-options-dev libutfcpp-dev zip gettext | |
3 | ||
4 | RUN mkdir -p /staging/blockattack-game | |
5 | ||
6 | COPY . /staging/blockattack-game | |
7 | ||
8 | ENV BLOCKATTACK_VERSION 2.5.0 | |
9 | ||
10 | RUN cd /staging/blockattack-game && \ | |
11 | ./packdata.sh && \ | |
12 | cmake . && \ | |
13 | make |
7 | 7 | |
8 | 8 | COPY . /staging/blockattack-game |
9 | 9 | |
10 | ENV BLOCKATTACK_VERSION 2.3.0 | |
10 | ENV BLOCKATTACK_VERSION 2.5.0 | |
11 | 11 | |
12 | 12 | RUN cd /staging/blockattack-game && \ |
13 | 13 | ./packdata.sh && \ |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <component type="desktop-application"> | |
2 | <id>net.blockattack.game</id> | |
3 | <metadata_license>MIT</metadata_license> | |
4 | <project_license>GPL-2.0+</project_license> | |
5 | <name>Block Attack - Rise of the Blocks</name> | |
6 | <summary>A fast paced match-3/blockfall game</summary> | |
7 | <description> | |
8 | <p>This a puzzle/blockfall game inspired by Nintendo’s Tetris Attack (or “Panel de Pon”) for the Super Nintendo. | |
9 | It might seem like any other match-3 style game but it is generally much faster. | |
10 | The game requires fast decisions compared to other puzzle games. | |
11 | While you can setup the perfect chain it is much more likely that you will construct chains while blocks are still dropping around you.</p> | |
12 | <p>In addition to traditional game types like endless, time trial and stage clear the game does also feature a VS-mode. | |
13 | The VS mode is a dual like you rarely see in a puzzle game.</p> | |
14 | <p>The game can be played with keyboard, gamepad or mouse. Keyboard or gamepad are strongly recommended.</p> | |
15 | <p>The game allows two players to compete on the same machine.</p> | |
16 | </description> | |
17 | <categories> | |
18 | <category>Game</category> | |
19 | <category>ArcadeGame</category> | |
20 | </categories> | |
21 | <screenshots> | |
22 | <screenshot type="default"> | |
23 | <image>https://files.poulsander.com/~poul19/public_files/blockattack/v2.5.0/blockattack_2.5.0_vs1.png</image> | |
24 | <caption>A VS game</caption> | |
25 | </screenshot> | |
26 | <screenshot> | |
27 | <image>https://files.poulsander.com/~poul19/public_files/blockattack/v2.5.0/blockattack_2.5.0_1.png</image> | |
28 | <caption>A time trial game</caption> | |
29 | </screenshot> | |
30 | <screenshot> | |
31 | <image>https://files.poulsander.com/~poul19/public_files/blockattack/v2.5.0/blockattack_2.5.0_vs2.png</image> | |
32 | <caption>A VS game with more action</caption> | |
33 | </screenshot> | |
34 | </screenshots> | |
35 | <launchable type="desktop-id">blockattack.desktop</launchable> | |
36 | <provides> | |
37 | <binary>blockattack</binary> | |
38 | </provides> | |
39 | <url type="homepage">https://blockattack.net</url> | |
40 | <url type="bugtracker">https://github.com/blockattack/blockattack-game/issues</url> | |
41 | <url type="faq">https://blockattack.net/instructions/</url> | |
42 | <update_contact>blockattack_AT_poulsander.com</update_contact> | |
43 | <translation type="gettext">blockattack_roftb</translation> | |
44 | </component> |
1 | 1 | set -e |
2 | 2 | set -x |
3 | 3 | |
4 | mkdir -p /staging/deps && cd /staging/deps && curl https://libsdl.org/release/SDL2-2.0.6.tar.gz | tar -zx && cd SDL2-2.0.6 && ls -lrt | |
5 | cd /staging/deps/SDL2-2.0.6 && ./configure --enable-shared --enable-static && make && make install | |
4 | mkdir -p /staging/deps && cd /staging/deps && curl https://libsdl.org/release/SDL2-2.0.9.tar.gz | tar -zx && cd SDL2-2.0.9 && ls -lrt | |
5 | cd /staging/deps/SDL2-2.0.9 && ./configure --enable-shared --enable-static && make && make install | |
6 | 6 | |
7 | #https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.1.tar.gz | |
8 | mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.1.tar.gz | tar -zx && cd SDL2_image-2.0.1 && ls -lrt | |
9 | cd /staging/deps/SDL2_image-2.0.1 && ./configure --enable-shared --enable-static && make && make install | |
7 | #https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.4.tar.gz | |
8 | mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.4.tar.gz | tar -zx && cd SDL2_image-2.0.4 && ls -lrt | |
9 | cd /staging/deps/SDL2_image-2.0.4 && ./configure --enable-shared --enable-static && make && make install | |
10 | 10 | |
11 | #https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.1.tar.gz | |
12 | mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.1.tar.gz | tar -zx && cd SDL2_mixer-2.0.1 && ls -lrt | |
13 | cd /staging/deps/SDL2_mixer-2.0.1 && ./configure --enable-shared --enable-static && make && make install | |
11 | #https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.4.tar.gz | |
12 | mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.4.tar.gz | tar -zx && cd SDL2_mixer-2.0.4 && ls -lrt | |
13 | cd /staging/deps/SDL2_mixer-2.0.4 && ./configure --enable-shared --enable-static && make && make install | |
14 | 14 | |
15 | 15 | #https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.14.tar.gz |
16 | 16 | mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.14.tar.gz | tar -zx && cd SDL2_ttf-2.0.14 && ls -lrt |
1 | 1 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER |
2 | 2 | # This file is distributed under the same license as the PACKAGE package. |
3 | 3 | # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. |
4 | # | |
4 | # Poul Sander <poul@poulsander.com>, 2019. #zanata | |
5 | 5 | msgid "" |
6 | 6 | msgstr "" |
7 | "Project-Id-Version: \n" | |
7 | "Project-Id-Version: PACKAGE VERSION\n" | |
8 | 8 | "Report-Msgid-Bugs-To: \n" |
9 | "POT-Creation-Date: 2018-06-30 14:36+0200\n" | |
10 | "PO-Revision-Date: 2018-06-30 14:37+0200\n" | |
11 | "Last-Translator: \n" | |
12 | "Language-Team: \n" | |
13 | "Language: da\n" | |
9 | "POT-Creation-Date: 2019-05-02 19:35+0200\n" | |
14 | 10 | "MIME-Version: 1.0\n" |
15 | 11 | "Content-Type: text/plain; charset=UTF-8\n" |
16 | 12 | "Content-Transfer-Encoding: 8bit\n" |
17 | "X-Generator: Poedit 2.0.6\n" | |
13 | "PO-Revision-Date: 2019-05-02 05:39+0000\n" | |
14 | "Last-Translator: Poul Sander <poul@poulsander.com>\n" | |
15 | "Language-Team: \n" | |
16 | "Language: da\n" | |
17 | "X-Generator: Zanata 4.6.2\n" | |
18 | 18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" |
19 | 19 | |
20 | 20 | #: ../../code/DialogBox.cpp:92 |
25 | 25 | msgid "Esc to cancel" |
26 | 26 | msgstr "Annuller med Esc" |
27 | 27 | |
28 | #: ../../code/HelpAboutState.cpp:62 | |
28 | #: ../../code/HelpAboutState.cpp:68 | |
29 | msgid "No audio driver" | |
30 | msgstr "Ingen lyd driver" | |
31 | ||
32 | #: ../../code/HelpAboutState.cpp:71 | |
29 | 33 | msgid "Name:" |
30 | 34 | msgstr "Navn:" |
31 | 35 | |
32 | #: ../../code/HelpAboutState.cpp:62 | |
36 | #: ../../code/HelpAboutState.cpp:71 | |
33 | 37 | msgid "Block Attack - Rise of the Blocks" |
34 | 38 | msgstr "Block Attack - Blokkenes opstand" |
35 | 39 | |
36 | #: ../../code/HelpAboutState.cpp:63 | |
40 | #: ../../code/HelpAboutState.cpp:72 | |
37 | 41 | msgid "Original name:" |
38 | 42 | msgstr "Originalt navn:" |
39 | 43 | |
40 | #: ../../code/HelpAboutState.cpp:64 | |
44 | #: ../../code/HelpAboutState.cpp:73 | |
41 | 45 | msgid "Version:" |
42 | 46 | msgstr "Version:" |
43 | 47 | |
44 | #: ../../code/HelpAboutState.cpp:65 | |
48 | #: ../../code/HelpAboutState.cpp:74 | |
45 | 49 | msgid "Homepage:" |
46 | 50 | msgstr "Hjemmeside:" |
47 | 51 | |
48 | #: ../../code/HelpAboutState.cpp:66 | |
52 | #: ../../code/HelpAboutState.cpp:75 | |
49 | 53 | msgid "Github page:" |
50 | 54 | msgstr "Github side:" |
51 | 55 | |
52 | #: ../../code/HelpAboutState.cpp:67 | |
56 | #: ../../code/HelpAboutState.cpp:76 | |
53 | 57 | msgid "SDL render:" |
54 | 58 | msgstr "SDL render:" |
55 | 59 | |
56 | #: ../../code/HelpAboutState.cpp:68 | |
60 | #: ../../code/HelpAboutState.cpp:77 | |
61 | msgid "SDL audio driver:" | |
62 | msgstr "SDL lyd driver:" | |
63 | ||
64 | #: ../../code/HelpAboutState.cpp:78 | |
65 | msgid "SDL compiled version:" | |
66 | msgstr "SDL kompileret version:" | |
67 | ||
68 | #: ../../code/HelpAboutState.cpp:79 | |
69 | msgid "SDL linked version:" | |
70 | msgstr "SDL lænket version:" | |
71 | ||
72 | #: ../../code/HelpAboutState.cpp:80 | |
57 | 73 | msgid "Save folder:" |
58 | 74 | msgstr "Mappe til gemte spil:" |
59 | 75 | |
60 | #: ../../code/HelpAboutState.cpp:69 | |
76 | #: ../../code/HelpAboutState.cpp:81 | |
61 | 77 | msgid "Locale:" |
62 | 78 | msgstr "Lokalitet:" |
63 | 79 | |
64 | #: ../../code/HelpAboutState.cpp:70 ../../code/menudef.cpp:345 | |
80 | #: ../../code/HelpAboutState.cpp:82 ../../code/menudef.cpp:414 | |
65 | 81 | msgid "About" |
66 | 82 | msgstr "Om" |
67 | 83 | |
68 | #: ../../code/HelpGamepadState.cpp:54 | |
84 | #: ../../code/HelpGamepadState.cpp:52 | |
69 | 85 | msgid "Move cursor" |
70 | 86 | msgstr "Flyt markøren" |
71 | 87 | |
72 | #: ../../code/HelpGamepadState.cpp:55 | |
88 | #: ../../code/HelpGamepadState.cpp:53 | |
73 | 89 | msgid "Push line" |
74 | 90 | msgstr "Skub linje" |
75 | 91 | |
76 | #: ../../code/HelpGamepadState.cpp:56 | |
92 | #: ../../code/HelpGamepadState.cpp:54 | |
77 | 93 | msgid "Back (Menu)" |
78 | 94 | msgstr "Tilbage (Menu)" |
79 | 95 | |
80 | #: ../../code/HelpGamepadState.cpp:57 | |
96 | #: ../../code/HelpGamepadState.cpp:55 | |
81 | 97 | msgid "Switch" |
82 | 98 | msgstr "Skift" |
83 | 99 | |
84 | #: ../../code/HelpGamepadState.cpp:58 | |
100 | #: ../../code/HelpGamepadState.cpp:56 | |
85 | 101 | msgid "Confirm" |
86 | 102 | msgstr "Bekræft" |
87 | 103 | |
88 | #: ../../code/HelpGamepadState.cpp:59 | |
104 | #: ../../code/HelpGamepadState.cpp:57 | |
89 | 105 | msgid "" |
90 | 106 | "Only SDL2 compatible controllers are supported!\n" |
91 | 107 | "Supported controllers: " |
93 | 109 | "Kun SDL2 kompatible kontrollere er understøttet!\n" |
94 | 110 | "Understøttede kontrollere: " |
95 | 111 | |
96 | #: ../../code/HelpHowtoState.cpp:127 | |
112 | #: ../../code/HelpHowtoState.cpp:125 | |
97 | 113 | msgid "Switch block horizontally" |
98 | 114 | msgstr "Skift blokke horisontalt" |
99 | 115 | |
100 | #: ../../code/HelpHowtoState.cpp:128 | |
116 | #: ../../code/HelpHowtoState.cpp:126 | |
101 | 117 | msgid "Match 3 to clear" |
102 | 118 | msgstr "Sammensæt 3 for at fjerne" |
103 | 119 | |
104 | #: ../../code/HelpHowtoState.cpp:129 | |
120 | #: ../../code/HelpHowtoState.cpp:127 | |
105 | 121 | msgid "Create combos!" |
106 | 122 | msgstr "Sammensæt mange!" |
107 | 123 | |
108 | #: ../../code/HelpHowtoState.cpp:130 | |
124 | #: ../../code/HelpHowtoState.cpp:128 | |
109 | 125 | msgid "Drop blocks!" |
110 | 126 | msgstr "Lad blokke falde!" |
111 | 127 | |
112 | #: ../../code/HelpHowtoState.cpp:131 | |
128 | #: ../../code/HelpHowtoState.cpp:129 | |
113 | 129 | msgid "Create a chain effect" |
114 | 130 | msgstr "Lav en kæde effekt" |
115 | 131 | |
116 | #: ../../code/levelselect.cpp:92 | |
132 | #: ../../code/levelselect.cpp:86 | |
117 | 133 | msgid "Select Puzzle" |
118 | 134 | msgstr "Vælg gåde" |
119 | 135 | |
120 | #: ../../code/levelselect.cpp:95 | |
136 | #: ../../code/levelselect.cpp:89 | |
121 | 137 | msgid "Stage Clear Level Select" |
122 | 138 | msgstr "Vælg Stage Clear-bane" |
123 | 139 | |
124 | #: ../../code/levelselect.cpp:201 | |
140 | #: ../../code/levelselect.cpp:195 | |
125 | 141 | #, c-format |
126 | 142 | msgid "Best score: %i" |
127 | 143 | msgstr "Bedste resultat: %i" |
128 | 144 | |
129 | #: ../../code/levelselect.cpp:202 | |
145 | #: ../../code/levelselect.cpp:196 | |
130 | 146 | #, c-format |
131 | 147 | msgid "Time used: %s" |
132 | 148 | msgstr "Tid brugt: %s" |
133 | 149 | |
134 | #: ../../code/levelselect.cpp:205 | |
150 | #: ../../code/levelselect.cpp:199 | |
135 | 151 | #, c-format |
136 | 152 | msgid "Time used: %d : %02d" |
137 | 153 | msgstr "Tid brugt: %d : %02d" |
138 | 154 | |
139 | #: ../../code/levelselect.cpp:210 | |
155 | #: ../../code/levelselect.cpp:204 | |
140 | 156 | #, c-format |
141 | 157 | msgid "Total score: %i in %i:%02i" |
142 | 158 | msgstr "Sammenlagt: %i på %i:%02i" |
143 | 159 | |
144 | #: ../../code/main.cpp:157 | |
160 | #: ../../code/main.cpp:158 | |
145 | 161 | msgid "GAME OVER" |
146 | 162 | msgstr "SPILLET ER SLUT" |
147 | 163 | |
148 | #: ../../code/main.cpp:158 | |
164 | #: ../../code/main.cpp:159 | |
149 | 165 | msgid "WINNER" |
150 | 166 | msgstr "VINDER" |
151 | 167 | |
152 | #: ../../code/main.cpp:159 | |
168 | #: ../../code/main.cpp:160 | |
153 | 169 | msgid "DRAW" |
154 | 170 | msgstr "UAFGJORT" |
155 | 171 | |
156 | #: ../../code/main.cpp:458 ../../code/main.cpp:589 | |
172 | #: ../../code/main.cpp:487 ../../code/main.cpp:618 | |
157 | 173 | msgid "AI" |
158 | 174 | msgstr "Computer" |
159 | 175 | |
160 | #: ../../code/main.cpp:461 | |
176 | #: ../../code/main.cpp:490 | |
161 | 177 | msgid "Playing field" |
162 | 178 | msgstr "Spilleflade" |
163 | 179 | |
164 | #: ../../code/main.cpp:535 | |
180 | #: ../../code/main.cpp:564 | |
165 | 181 | msgid "Time Trial" |
166 | 182 | msgstr "På tid" |
167 | 183 | |
168 | #: ../../code/main.cpp:536 | |
184 | #: ../../code/main.cpp:565 | |
169 | 185 | msgid "Score as much as possible in 2 minutes" |
170 | 186 | msgstr "Se hvor mange point du kan opnå på 2 minutter" |
171 | 187 | |
172 | #: ../../code/main.cpp:540 | |
188 | #: ../../code/main.cpp:569 | |
173 | 189 | msgid "Stage Clear" |
174 | 190 | msgstr "Stage Clear" |
175 | 191 | |
176 | #: ../../code/main.cpp:541 | |
192 | #: ../../code/main.cpp:570 | |
177 | 193 | msgid "You must clear a number of lines. Speed is rapidly increased." |
178 | 194 | msgstr "Fjern et specifik antal linjer. Hastigheden stiger hurtigt." |
179 | 195 | |
180 | #: ../../code/main.cpp:544 | |
196 | #: ../../code/main.cpp:573 | |
181 | 197 | msgid "Puzzle" |
182 | 198 | msgstr "Gåde" |
183 | 199 | |
184 | #: ../../code/main.cpp:545 | |
200 | #: ../../code/main.cpp:574 | |
185 | 201 | msgid "Clear the entire board with a limited number of moves." |
186 | 202 | msgstr "Fjern alle blokke med et begrænset antal flyt." |
187 | 203 | |
188 | #: ../../code/main.cpp:548 | |
204 | #: ../../code/main.cpp:577 | |
189 | 205 | msgid "Endless" |
190 | 206 | msgstr "Evighed" |
191 | 207 | |
192 | #: ../../code/main.cpp:549 | |
208 | #: ../../code/main.cpp:578 | |
193 | 209 | msgid "Score as much as possible. No time limit." |
194 | 210 | msgstr "Opnå så mange point som muligt. Ingen tidsbegrænsning." |
195 | 211 | |
196 | #: ../../code/main.cpp:559 | |
212 | #: ../../code/main.cpp:588 | |
197 | 213 | msgid "Objective:" |
198 | 214 | msgstr "Formål:" |
199 | 215 | |
200 | #: ../../code/main.cpp:569 | |
216 | #: ../../code/main.cpp:598 | |
201 | 217 | msgid "Movement keys:" |
202 | 218 | msgstr "Bevægelsestaster:" |
203 | 219 | |
204 | #: ../../code/main.cpp:571 | |
220 | #: ../../code/main.cpp:600 | |
205 | 221 | msgid "Switch: " |
206 | 222 | msgstr "Skift: " |
207 | 223 | |
208 | #: ../../code/main.cpp:573 | |
224 | #: ../../code/main.cpp:602 | |
209 | 225 | msgid "Restart: " |
210 | 226 | msgstr "Genstart: " |
211 | 227 | |
212 | #: ../../code/main.cpp:576 | |
228 | #: ../../code/main.cpp:605 | |
213 | 229 | msgid "Push line: " |
214 | 230 | msgstr "Skub linje: " |
215 | 231 | |
216 | #: ../../code/main.cpp:1001 | |
217 | msgid "Player 1" | |
218 | msgstr "Spiller 1" | |
219 | ||
220 | #: ../../code/main.cpp:1002 | |
232 | #: ../../code/main.cpp:1040 | |
221 | 233 | msgid "Player 2" |
222 | 234 | msgstr "Spiller 2" |
223 | 235 | |
267 | 279 | |
268 | 280 | #: ../../code/menudef.cpp:95 |
269 | 281 | msgid "Space" |
270 | msgstr "" | |
271 | ||
272 | #: ../../code/menudef.cpp:174 ../../code/menudef.cpp:242 | |
282 | msgstr "Mellemrum" | |
283 | ||
284 | #: ../../code/menudef.cpp:162 | |
285 | msgid "Single Player Endless" | |
286 | msgstr "En spiller - Evighed" | |
287 | ||
288 | #: ../../code/menudef.cpp:169 | |
289 | msgid "Slow" | |
290 | msgstr "Langsom" | |
291 | ||
292 | #: ../../code/menudef.cpp:170 | |
293 | msgid "Fast" | |
294 | msgstr "Hurtig" | |
295 | ||
296 | #: ../../code/menudef.cpp:171 | |
297 | msgid "Faster" | |
298 | msgstr "Hurtigere" | |
299 | ||
300 | #: ../../code/menudef.cpp:172 | |
301 | msgid "Even faster" | |
302 | msgstr "Endnu hurtigere" | |
303 | ||
304 | #: ../../code/menudef.cpp:173 | |
305 | msgid "Fastest" | |
306 | msgstr "Hurtigst" | |
307 | ||
308 | #: ../../code/menudef.cpp:215 | |
309 | msgid "Always use software render: On" | |
310 | msgstr "Brug altid software tilstand: Til" | |
311 | ||
312 | #: ../../code/menudef.cpp:216 | |
313 | msgid "Always use software render: Off" | |
314 | msgstr "Brug altid software tilstand: Fra" | |
315 | ||
316 | #: ../../code/menudef.cpp:220 | |
273 | 317 | msgid "Music: On" |
274 | 318 | msgstr "Musik: Til" |
275 | 319 | |
276 | #: ../../code/menudef.cpp:174 ../../code/menudef.cpp:242 | |
320 | #: ../../code/menudef.cpp:220 | |
277 | 321 | msgid "Music: Off" |
278 | 322 | msgstr "Musik: Fra" |
279 | 323 | |
280 | #: ../../code/menudef.cpp:182 ../../code/menudef.cpp:243 | |
324 | #: ../../code/menudef.cpp:224 | |
281 | 325 | msgid "Sound: On" |
282 | 326 | msgstr "Lyd: Til" |
283 | 327 | |
284 | #: ../../code/menudef.cpp:182 ../../code/menudef.cpp:243 | |
328 | #: ../../code/menudef.cpp:224 | |
285 | 329 | msgid "Sound: Off" |
286 | 330 | msgstr "Lyd: Fra" |
287 | 331 | |
288 | #: ../../code/menudef.cpp:189 ../../code/menudef.cpp:244 | |
332 | #: ../../code/menudef.cpp:228 | |
289 | 333 | msgid "Fullscreen: On" |
290 | 334 | msgstr "Fuldskærm: Til" |
291 | 335 | |
292 | #: ../../code/menudef.cpp:189 ../../code/menudef.cpp:244 | |
336 | #: ../../code/menudef.cpp:228 | |
293 | 337 | msgid "Fullscreen: Off" |
294 | 338 | msgstr "Fuldskærm: Fra" |
295 | 339 | |
296 | #: ../../code/menudef.cpp:195 | |
340 | #: ../../code/menudef.cpp:261 | |
297 | 341 | msgid "Enter player 1 name:" |
298 | 342 | msgstr "Indtast navnet på spiller 1:" |
299 | 343 | |
300 | #: ../../code/menudef.cpp:201 | |
344 | #: ../../code/menudef.cpp:267 | |
301 | 345 | msgid "Enter player 2 name:" |
302 | 346 | msgstr "Indtast navnet på spiller 2:" |
303 | 347 | |
304 | #: ../../code/menudef.cpp:211 | |
348 | #: ../../code/menudef.cpp:277 | |
305 | 349 | msgid "Change key bindings" |
306 | 350 | msgstr "Skift taster" |
307 | 351 | |
308 | #: ../../code/menudef.cpp:212 | |
352 | #: ../../code/menudef.cpp:278 | |
309 | 353 | msgid "Left" |
310 | 354 | msgstr "Venstre" |
311 | 355 | |
312 | #: ../../code/menudef.cpp:213 | |
356 | #: ../../code/menudef.cpp:279 | |
313 | 357 | msgid "Right" |
314 | 358 | msgstr "Højre" |
315 | 359 | |
316 | #: ../../code/menudef.cpp:214 | |
360 | #: ../../code/menudef.cpp:280 | |
317 | 361 | msgid "Up" |
318 | 362 | msgstr "Op" |
319 | 363 | |
320 | #: ../../code/menudef.cpp:215 | |
364 | #: ../../code/menudef.cpp:281 | |
321 | 365 | msgid "Down" |
322 | 366 | msgstr "Ned" |
323 | 367 | |
324 | #: ../../code/menudef.cpp:216 | |
368 | #: ../../code/menudef.cpp:282 | |
325 | 369 | msgid "Push" |
326 | 370 | msgstr "Skub" |
327 | 371 | |
328 | #: ../../code/menudef.cpp:217 | |
372 | #: ../../code/menudef.cpp:283 | |
329 | 373 | msgid "Change" |
330 | 374 | msgstr "Skift" |
331 | 375 | |
332 | #: ../../code/menudef.cpp:236 | |
376 | #: ../../code/menudef.cpp:302 | |
333 | 377 | msgid "Configuration" |
334 | 378 | msgstr "Konfiguration" |
335 | 379 | |
336 | #: ../../code/menudef.cpp:246 | |
380 | #: ../../code/menudef.cpp:314 | |
337 | 381 | msgid "Change player 1's name" |
338 | 382 | msgstr "Skift navn på spiller 1" |
339 | 383 | |
340 | #: ../../code/menudef.cpp:248 | |
384 | #: ../../code/menudef.cpp:316 | |
341 | 385 | msgid "Change player 2's name" |
342 | 386 | msgstr "Skift navn på spiller 2" |
343 | 387 | |
344 | #: ../../code/menudef.cpp:250 | |
388 | #: ../../code/menudef.cpp:318 | |
345 | 389 | msgid "Change player 1's keys" |
346 | 390 | msgstr "Tildel taster til spiller 1" |
347 | 391 | |
348 | #: ../../code/menudef.cpp:252 | |
392 | #: ../../code/menudef.cpp:320 | |
349 | 393 | msgid "Change player 2's keys" |
350 | 394 | msgstr "Tildel taster til spiller 2" |
351 | 395 | |
352 | #: ../../code/menudef.cpp:264 | |
396 | #: ../../code/menudef.cpp:333 | |
353 | 397 | msgid "Single player VS" |
354 | 398 | msgstr "En spiller - VS" |
355 | 399 | |
356 | #: ../../code/menudef.cpp:280 | |
400 | #: ../../code/menudef.cpp:349 | |
357 | 401 | msgid "Very easy" |
358 | 402 | msgstr "Meget let" |
359 | 403 | |
360 | #: ../../code/menudef.cpp:281 | |
404 | #: ../../code/menudef.cpp:350 | |
361 | 405 | msgid "Easy" |
362 | 406 | msgstr "Let" |
363 | 407 | |
364 | #: ../../code/menudef.cpp:282 | |
408 | #: ../../code/menudef.cpp:351 | |
365 | 409 | msgid "Below normal" |
366 | 410 | msgstr "Under normal" |
367 | 411 | |
368 | #: ../../code/menudef.cpp:283 | |
412 | #: ../../code/menudef.cpp:352 | |
369 | 413 | msgid "Normal" |
370 | 414 | msgstr "Normal" |
371 | 415 | |
372 | #: ../../code/menudef.cpp:284 | |
416 | #: ../../code/menudef.cpp:353 | |
373 | 417 | msgid "Above normal" |
374 | 418 | msgstr "Over normal" |
375 | 419 | |
376 | #: ../../code/menudef.cpp:285 | |
420 | #: ../../code/menudef.cpp:354 | |
377 | 421 | msgid "Hard" |
378 | 422 | msgstr "Svær" |
379 | 423 | |
380 | #: ../../code/menudef.cpp:286 | |
424 | #: ../../code/menudef.cpp:355 | |
381 | 425 | msgid "Hardest" |
382 | 426 | msgstr "Meget svær" |
383 | 427 | |
384 | #: ../../code/menudef.cpp:298 | |
428 | #: ../../code/menudef.cpp:367 | |
385 | 429 | msgid "Multiplayer" |
386 | 430 | msgstr "Flerspiller" |
387 | 431 | |
388 | #: ../../code/menudef.cpp:300 | |
432 | #: ../../code/menudef.cpp:369 | |
389 | 433 | msgid "Two player - time trial" |
390 | 434 | msgstr "To spillere - På tid" |
391 | 435 | |
392 | #: ../../code/menudef.cpp:302 | |
436 | #: ../../code/menudef.cpp:371 | |
393 | 437 | msgid "Two player - vs" |
394 | 438 | msgstr "To spillere - VS" |
395 | 439 | |
396 | #: ../../code/menudef.cpp:326 ../../code/menudef.cpp:341 | |
440 | #: ../../code/menudef.cpp:395 ../../code/menudef.cpp:410 | |
397 | 441 | msgid "Credits" |
398 | 442 | msgstr "Bidragydere" |
399 | 443 | |
400 | #: ../../code/menudef.cpp:331 ../../code/menudef.cpp:384 | |
444 | #: ../../code/menudef.cpp:400 ../../code/menudef.cpp:471 | |
401 | 445 | msgid "Help" |
402 | 446 | msgstr "Hjælp" |
403 | 447 | |
404 | #: ../../code/menudef.cpp:333 | |
448 | #: ../../code/menudef.cpp:402 | |
405 | 449 | msgid "How to" |
406 | 450 | msgstr "Guide" |
407 | 451 | |
408 | #: ../../code/menudef.cpp:337 | |
452 | #: ../../code/menudef.cpp:406 | |
409 | 453 | msgid "Gamepad" |
410 | 454 | msgstr "Spilkontroller" |
411 | 455 | |
412 | #: ../../code/menudef.cpp:352 ../../code/menudef.cpp:376 | |
456 | #: ../../code/menudef.cpp:421 ../../code/menudef.cpp:463 | |
413 | 457 | msgid "Single player" |
414 | 458 | msgstr "Enkeltspiller" |
415 | 459 | |
416 | #: ../../code/menudef.cpp:354 | |
460 | #: ../../code/menudef.cpp:423 | |
417 | 461 | msgid "Single player - endless" |
418 | 462 | msgstr "En spiller - Evighed" |
419 | 463 | |
420 | #: ../../code/menudef.cpp:356 | |
464 | #: ../../code/menudef.cpp:425 | |
421 | 465 | msgid "Single player - time trial" |
422 | 466 | msgstr "En spiller - På tid" |
423 | 467 | |
424 | #: ../../code/menudef.cpp:358 | |
468 | #: ../../code/menudef.cpp:427 | |
425 | 469 | msgid "Single player - stage clear" |
426 | 470 | msgstr "En spiller - Stage Clear" |
427 | 471 | |
428 | #: ../../code/menudef.cpp:360 | |
472 | #: ../../code/menudef.cpp:429 | |
429 | 473 | msgid "Single player - puzzle mode" |
430 | 474 | msgstr "En spiller - Gåde" |
431 | 475 | |
432 | #: ../../code/menudef.cpp:362 | |
476 | #: ../../code/menudef.cpp:431 | |
433 | 477 | msgid "Single player - vs" |
434 | 478 | msgstr "En spiller - VS" |
435 | 479 | |
436 | #: ../../code/menudef.cpp:374 | |
480 | #: ../../code/menudef.cpp:446 | |
481 | msgid "Game did not shutdown as it should" | |
482 | msgstr "Spillet blev ikke afsluttet korrekt" | |
483 | ||
484 | #: ../../code/menudef.cpp:449 | |
485 | msgid "Use software renderer this time" | |
486 | msgstr "Brug software tilstand denne gang" | |
487 | ||
488 | #: ../../code/menudef.cpp:450 | |
489 | msgid "Always use software renderer" | |
490 | msgstr "Start altid i software tilstand" | |
491 | ||
492 | #: ../../code/menudef.cpp:461 | |
437 | 493 | msgid "Block Attack - Rise of the blocks" |
438 | 494 | msgstr "Block Attack - Blokkenes opstand" |
439 | 495 | |
440 | #: ../../code/menudef.cpp:378 | |
496 | #: ../../code/menudef.cpp:465 | |
441 | 497 | msgid "Multi player" |
442 | 498 | msgstr "Flere spillere" |
443 | 499 | |
444 | #: ../../code/menudef.cpp:380 | |
500 | #: ../../code/menudef.cpp:467 | |
445 | 501 | msgid "Configure" |
446 | 502 | msgstr "Instillinger" |
447 | 503 | |
448 | #: ../../code/menudef.cpp:382 | |
504 | #: ../../code/menudef.cpp:469 | |
449 | 505 | msgid "Highscores" |
450 | 506 | msgstr "Bedste resultater" |
451 | 507 | |
452 | #: ../../code/MenuSystem.cpp:162 ../../code/MenuSystem.cpp:170 | |
453 | #: ../../code/MenuSystem.cpp:183 ../../code/ScoresDisplay.cpp:184 | |
508 | #: ../../code/MenuSystem.cpp:159 ../../code/MenuSystem.cpp:167 | |
509 | #: ../../code/MenuSystem.cpp:179 ../../code/ScoresDisplay.cpp:216 | |
454 | 510 | msgid "Back" |
455 | 511 | msgstr "Tilbage" |
456 | 512 | |
457 | #: ../../code/MenuSystem.cpp:173 ../../code/MenuSystem.cpp:186 | |
513 | #: ../../code/MenuSystem.cpp:170 ../../code/MenuSystem.cpp:182 | |
458 | 514 | msgid "Exit" |
459 | 515 | msgstr "Afslut" |
460 | 516 | |
461 | #: ../../code/ScoresDisplay.cpp:71 | |
517 | #: ../../code/os.cpp:99 | |
518 | msgid "Player 1" | |
519 | msgstr "Spiller 1" | |
520 | ||
521 | #: ../../code/ScoresDisplay.cpp:70 | |
522 | msgid "Endless (Fast):" | |
523 | msgstr "Evighed (Hurtig):" | |
524 | ||
525 | #: ../../code/ScoresDisplay.cpp:73 | |
526 | msgid "Endless (Faster):" | |
527 | msgstr "Evighed (Hurtigere):" | |
528 | ||
529 | #: ../../code/ScoresDisplay.cpp:76 | |
530 | msgid "Endless (Even faster):" | |
531 | msgstr "Evighed (Endnu hurtigere):" | |
532 | ||
533 | #: ../../code/ScoresDisplay.cpp:79 | |
534 | msgid "Endless (Fastest):" | |
535 | msgstr "Evighed (Hurtigst):" | |
536 | ||
537 | #: ../../code/ScoresDisplay.cpp:82 | |
462 | 538 | msgid "Endless:" |
463 | 539 | msgstr "Evighed:" |
464 | 540 | |
465 | #: ../../code/ScoresDisplay.cpp:74 | |
541 | #: ../../code/ScoresDisplay.cpp:87 | |
466 | 542 | msgid "Time Trial:" |
467 | 543 | msgstr "På tid:" |
468 | 544 | |
469 | #: ../../code/ScoresDisplay.cpp:97 | |
545 | #: ../../code/ScoresDisplay.cpp:125 | |
470 | 546 | msgid "Stats" |
471 | 547 | msgstr "Statistik" |
472 | 548 | |
473 | #: ../../code/ScoresDisplay.cpp:99 | |
549 | #: ../../code/ScoresDisplay.cpp:127 | |
474 | 550 | msgid "Chains" |
475 | 551 | msgstr "Kæder" |
476 | 552 | |
477 | #: ../../code/ScoresDisplay.cpp:107 | |
553 | #: ../../code/ScoresDisplay.cpp:135 | |
478 | 554 | msgid "Lines Pushed: " |
479 | 555 | msgstr "Linjer skubbet: " |
480 | 556 | |
481 | #: ../../code/ScoresDisplay.cpp:112 | |
557 | #: ../../code/ScoresDisplay.cpp:140 | |
482 | 558 | msgid "Puzzles solved: " |
483 | 559 | msgstr "Gåder løst: " |
484 | 560 | |
485 | #: ../../code/ScoresDisplay.cpp:117 | |
561 | #: ../../code/ScoresDisplay.cpp:145 | |
486 | 562 | msgid "Run time: " |
487 | 563 | msgstr "Kørselstid: " |
488 | 564 | |
489 | #: ../../code/ScoresDisplay.cpp:120 ../../code/ScoresDisplay.cpp:133 | |
565 | #: ../../code/ScoresDisplay.cpp:148 ../../code/ScoresDisplay.cpp:161 | |
490 | 566 | #, c-format |
491 | 567 | msgid "Days: %i" |
492 | 568 | msgstr "Dage: %i" |
493 | 569 | |
494 | #: ../../code/ScoresDisplay.cpp:122 ../../code/ScoresDisplay.cpp:135 | |
570 | #: ../../code/ScoresDisplay.cpp:150 ../../code/ScoresDisplay.cpp:163 | |
495 | 571 | #, c-format |
496 | 572 | msgid "Hours: %i" |
497 | 573 | msgstr "Timer: %i" |
498 | 574 | |
499 | #: ../../code/ScoresDisplay.cpp:124 ../../code/ScoresDisplay.cpp:137 | |
575 | #: ../../code/ScoresDisplay.cpp:152 ../../code/ScoresDisplay.cpp:165 | |
500 | 576 | #, c-format |
501 | 577 | msgid "Minutes: %i" |
502 | 578 | msgstr "Minutter: %i" |
503 | 579 | |
504 | #: ../../code/ScoresDisplay.cpp:126 ../../code/ScoresDisplay.cpp:139 | |
580 | #: ../../code/ScoresDisplay.cpp:154 ../../code/ScoresDisplay.cpp:167 | |
505 | 581 | #, c-format |
506 | 582 | msgid "Seconds: %i" |
507 | 583 | msgstr "Sekunder: %i" |
508 | 584 | |
509 | #: ../../code/ScoresDisplay.cpp:130 | |
585 | #: ../../code/ScoresDisplay.cpp:158 | |
510 | 586 | msgid "Play time: " |
511 | 587 | msgstr "Spilletid: " |
512 | 588 | |
513 | #: ../../code/ScoresDisplay.cpp:143 | |
589 | #: ../../code/ScoresDisplay.cpp:171 | |
514 | 590 | msgid "VS CPU (win/loss)" |
515 | 591 | msgstr "Mod computeren (vundet/tabt)" |
516 | 592 | |
517 | #: ../../code/ScoresDisplay.cpp:188 ../../code/BlockGameSdl.inc:55 | |
593 | #: ../../code/ScoresDisplay.cpp:220 ../../code/BlockGameSdl.inc:55 | |
518 | 594 | msgid "Next" |
519 | 595 | msgstr "Næste" |
520 | 596 | |
521 | #: ../../code/ScoresDisplay.cpp:192 | |
597 | #: ../../code/ScoresDisplay.cpp:224 | |
522 | 598 | #, c-format |
523 | 599 | msgid "Page %i of %i" |
524 | 600 | msgstr "Side %i af %i" |
564 | 640 | msgid "Showing content of: %s" |
565 | 641 | msgstr "Viser indhold af: %s" |
566 | 642 | |
567 | #~ msgid "Author:" | |
568 | #~ msgstr "Forfatter:" | |
569 | ||
570 | #~ msgid "Contributers:" | |
571 | #~ msgstr "Bidragydere:" | |
572 | ||
573 | #~ msgid "Other credits:" | |
574 | #~ msgstr "Andre bidrag:" | |
575 | ||
576 | #~ msgid "Total score: %1% in %2%:%3%" | |
577 | #~ msgstr "Sammenlagt resultat: %1% på %2%:%3%" | |
578 | ||
579 | #~ msgid "Page %1% of %2%" | |
580 | #~ msgstr "Side %1% af %2%" |
7 | 7 | msgstr "" |
8 | 8 | "Project-Id-Version: PACKAGE VERSION\n" |
9 | 9 | "Report-Msgid-Bugs-To: \n" |
10 | "POT-Creation-Date: 2018-06-30 14:36+0200\n" | |
10 | "POT-Creation-Date: 2019-05-02 19:35+0200\n" | |
11 | 11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
12 | 12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
13 | 13 | "Language-Team: LANGUAGE <LL@li.org>\n" |
24 | 24 | msgid "Esc to cancel" |
25 | 25 | msgstr "" |
26 | 26 | |
27 | #: ../../code/HelpAboutState.cpp:62 | |
27 | #: ../../code/HelpAboutState.cpp:68 | |
28 | msgid "No audio driver" | |
29 | msgstr "" | |
30 | ||
31 | #: ../../code/HelpAboutState.cpp:71 | |
28 | 32 | msgid "Name:" |
29 | 33 | msgstr "" |
30 | 34 | |
31 | #: ../../code/HelpAboutState.cpp:62 | |
35 | #: ../../code/HelpAboutState.cpp:71 | |
32 | 36 | msgid "Block Attack - Rise of the Blocks" |
33 | 37 | msgstr "" |
34 | 38 | |
35 | #: ../../code/HelpAboutState.cpp:63 | |
39 | #: ../../code/HelpAboutState.cpp:72 | |
36 | 40 | msgid "Original name:" |
37 | 41 | msgstr "" |
38 | 42 | |
39 | #: ../../code/HelpAboutState.cpp:64 | |
43 | #: ../../code/HelpAboutState.cpp:73 | |
40 | 44 | msgid "Version:" |
41 | 45 | msgstr "" |
42 | 46 | |
43 | #: ../../code/HelpAboutState.cpp:65 | |
47 | #: ../../code/HelpAboutState.cpp:74 | |
44 | 48 | msgid "Homepage:" |
45 | 49 | msgstr "" |
46 | 50 | |
47 | #: ../../code/HelpAboutState.cpp:66 | |
51 | #: ../../code/HelpAboutState.cpp:75 | |
48 | 52 | msgid "Github page:" |
49 | 53 | msgstr "" |
50 | 54 | |
51 | #: ../../code/HelpAboutState.cpp:67 | |
55 | #: ../../code/HelpAboutState.cpp:76 | |
52 | 56 | msgid "SDL render:" |
53 | 57 | msgstr "" |
54 | 58 | |
55 | #: ../../code/HelpAboutState.cpp:68 | |
59 | #: ../../code/HelpAboutState.cpp:77 | |
60 | msgid "SDL audio driver:" | |
61 | msgstr "" | |
62 | ||
63 | #: ../../code/HelpAboutState.cpp:78 | |
64 | msgid "SDL compiled version:" | |
65 | msgstr "" | |
66 | ||
67 | #: ../../code/HelpAboutState.cpp:79 | |
68 | msgid "SDL linked version:" | |
69 | msgstr "" | |
70 | ||
71 | #: ../../code/HelpAboutState.cpp:80 | |
56 | 72 | msgid "Save folder:" |
57 | 73 | msgstr "" |
58 | 74 | |
59 | #: ../../code/HelpAboutState.cpp:69 | |
75 | #: ../../code/HelpAboutState.cpp:81 | |
60 | 76 | msgid "Locale:" |
61 | 77 | msgstr "" |
62 | 78 | |
63 | #: ../../code/HelpAboutState.cpp:70 ../../code/menudef.cpp:345 | |
79 | #: ../../code/HelpAboutState.cpp:82 ../../code/menudef.cpp:414 | |
64 | 80 | msgid "About" |
65 | 81 | msgstr "" |
66 | 82 | |
83 | #: ../../code/HelpGamepadState.cpp:52 | |
84 | msgid "Move cursor" | |
85 | msgstr "" | |
86 | ||
87 | #: ../../code/HelpGamepadState.cpp:53 | |
88 | msgid "Push line" | |
89 | msgstr "" | |
90 | ||
67 | 91 | #: ../../code/HelpGamepadState.cpp:54 |
68 | msgid "Move cursor" | |
92 | msgid "Back (Menu)" | |
69 | 93 | msgstr "" |
70 | 94 | |
71 | 95 | #: ../../code/HelpGamepadState.cpp:55 |
72 | msgid "Push line" | |
96 | msgid "Switch" | |
73 | 97 | msgstr "" |
74 | 98 | |
75 | 99 | #: ../../code/HelpGamepadState.cpp:56 |
76 | msgid "Back (Menu)" | |
100 | msgid "Confirm" | |
77 | 101 | msgstr "" |
78 | 102 | |
79 | 103 | #: ../../code/HelpGamepadState.cpp:57 |
80 | msgid "Switch" | |
81 | msgstr "" | |
82 | ||
83 | #: ../../code/HelpGamepadState.cpp:58 | |
84 | msgid "Confirm" | |
85 | msgstr "" | |
86 | ||
87 | #: ../../code/HelpGamepadState.cpp:59 | |
88 | 104 | msgid "" |
89 | 105 | "Only SDL2 compatible controllers are supported!\n" |
90 | 106 | "Supported controllers: " |
91 | 107 | msgstr "" |
92 | 108 | |
109 | #: ../../code/HelpHowtoState.cpp:125 | |
110 | msgid "Switch block horizontally" | |
111 | msgstr "" | |
112 | ||
113 | #: ../../code/HelpHowtoState.cpp:126 | |
114 | msgid "Match 3 to clear" | |
115 | msgstr "" | |
116 | ||
93 | 117 | #: ../../code/HelpHowtoState.cpp:127 |
94 | msgid "Switch block horizontally" | |
118 | msgid "Create combos!" | |
95 | 119 | msgstr "" |
96 | 120 | |
97 | 121 | #: ../../code/HelpHowtoState.cpp:128 |
98 | msgid "Match 3 to clear" | |
122 | msgid "Drop blocks!" | |
99 | 123 | msgstr "" |
100 | 124 | |
101 | 125 | #: ../../code/HelpHowtoState.cpp:129 |
102 | msgid "Create combos!" | |
103 | msgstr "" | |
104 | ||
105 | #: ../../code/HelpHowtoState.cpp:130 | |
106 | msgid "Drop blocks!" | |
107 | msgstr "" | |
108 | ||
109 | #: ../../code/HelpHowtoState.cpp:131 | |
110 | 126 | msgid "Create a chain effect" |
111 | 127 | msgstr "" |
112 | 128 | |
113 | #: ../../code/levelselect.cpp:92 | |
129 | #: ../../code/levelselect.cpp:86 | |
114 | 130 | msgid "Select Puzzle" |
115 | 131 | msgstr "" |
116 | 132 | |
117 | #: ../../code/levelselect.cpp:95 | |
133 | #: ../../code/levelselect.cpp:89 | |
118 | 134 | msgid "Stage Clear Level Select" |
119 | 135 | msgstr "" |
120 | 136 | |
121 | #: ../../code/levelselect.cpp:201 | |
137 | #: ../../code/levelselect.cpp:195 | |
122 | 138 | #, c-format |
123 | 139 | msgid "Best score: %i" |
124 | 140 | msgstr "" |
125 | 141 | |
126 | #: ../../code/levelselect.cpp:202 | |
142 | #: ../../code/levelselect.cpp:196 | |
127 | 143 | #, c-format |
128 | 144 | msgid "Time used: %s" |
129 | 145 | msgstr "" |
130 | 146 | |
131 | #: ../../code/levelselect.cpp:205 | |
147 | #: ../../code/levelselect.cpp:199 | |
132 | 148 | #, c-format |
133 | 149 | msgid "Time used: %d : %02d" |
134 | 150 | msgstr "" |
135 | 151 | |
136 | #: ../../code/levelselect.cpp:210 | |
152 | #: ../../code/levelselect.cpp:204 | |
137 | 153 | #, c-format |
138 | 154 | msgid "Total score: %i in %i:%02i" |
139 | 155 | msgstr "" |
140 | 156 | |
141 | #: ../../code/main.cpp:157 | |
157 | #: ../../code/main.cpp:158 | |
142 | 158 | msgid "GAME OVER" |
143 | 159 | msgstr "" |
144 | 160 | |
145 | #: ../../code/main.cpp:158 | |
161 | #: ../../code/main.cpp:159 | |
146 | 162 | msgid "WINNER" |
147 | 163 | msgstr "" |
148 | 164 | |
149 | #: ../../code/main.cpp:159 | |
165 | #: ../../code/main.cpp:160 | |
150 | 166 | msgid "DRAW" |
151 | 167 | msgstr "" |
152 | 168 | |
153 | #: ../../code/main.cpp:458 ../../code/main.cpp:589 | |
169 | #: ../../code/main.cpp:487 ../../code/main.cpp:618 | |
154 | 170 | msgid "AI" |
155 | 171 | msgstr "" |
156 | 172 | |
157 | #: ../../code/main.cpp:461 | |
173 | #: ../../code/main.cpp:490 | |
158 | 174 | msgid "Playing field" |
159 | 175 | msgstr "" |
160 | 176 | |
161 | #: ../../code/main.cpp:535 | |
177 | #: ../../code/main.cpp:564 | |
162 | 178 | msgid "Time Trial" |
163 | 179 | msgstr "" |
164 | 180 | |
165 | #: ../../code/main.cpp:536 | |
181 | #: ../../code/main.cpp:565 | |
166 | 182 | msgid "Score as much as possible in 2 minutes" |
167 | 183 | msgstr "" |
168 | 184 | |
169 | #: ../../code/main.cpp:540 | |
185 | #: ../../code/main.cpp:569 | |
170 | 186 | msgid "Stage Clear" |
171 | 187 | msgstr "" |
172 | 188 | |
173 | #: ../../code/main.cpp:541 | |
189 | #: ../../code/main.cpp:570 | |
174 | 190 | msgid "You must clear a number of lines. Speed is rapidly increased." |
175 | 191 | msgstr "" |
176 | 192 | |
177 | #: ../../code/main.cpp:544 | |
193 | #: ../../code/main.cpp:573 | |
178 | 194 | msgid "Puzzle" |
179 | 195 | msgstr "" |
180 | 196 | |
181 | #: ../../code/main.cpp:545 | |
197 | #: ../../code/main.cpp:574 | |
182 | 198 | msgid "Clear the entire board with a limited number of moves." |
183 | 199 | msgstr "" |
184 | 200 | |
185 | #: ../../code/main.cpp:548 | |
201 | #: ../../code/main.cpp:577 | |
186 | 202 | msgid "Endless" |
187 | 203 | msgstr "" |
188 | 204 | |
189 | #: ../../code/main.cpp:549 | |
205 | #: ../../code/main.cpp:578 | |
190 | 206 | msgid "Score as much as possible. No time limit." |
191 | 207 | msgstr "" |
192 | 208 | |
193 | #: ../../code/main.cpp:559 | |
209 | #: ../../code/main.cpp:588 | |
194 | 210 | msgid "Objective:" |
195 | 211 | msgstr "" |
196 | 212 | |
197 | #: ../../code/main.cpp:569 | |
213 | #: ../../code/main.cpp:598 | |
198 | 214 | msgid "Movement keys:" |
199 | 215 | msgstr "" |
200 | 216 | |
201 | #: ../../code/main.cpp:571 | |
217 | #: ../../code/main.cpp:600 | |
202 | 218 | msgid "Switch: " |
203 | 219 | msgstr "" |
204 | 220 | |
205 | #: ../../code/main.cpp:573 | |
221 | #: ../../code/main.cpp:602 | |
206 | 222 | msgid "Restart: " |
207 | 223 | msgstr "" |
208 | 224 | |
209 | #: ../../code/main.cpp:576 | |
225 | #: ../../code/main.cpp:605 | |
210 | 226 | msgid "Push line: " |
211 | 227 | msgstr "" |
212 | 228 | |
213 | #: ../../code/main.cpp:1001 | |
214 | msgid "Player 1" | |
215 | msgstr "" | |
216 | ||
217 | #: ../../code/main.cpp:1002 | |
229 | #: ../../code/main.cpp:1040 | |
218 | 230 | msgid "Player 2" |
219 | 231 | msgstr "" |
220 | 232 | |
266 | 278 | msgid "Space" |
267 | 279 | msgstr "" |
268 | 280 | |
269 | #: ../../code/menudef.cpp:174 ../../code/menudef.cpp:242 | |
281 | #: ../../code/menudef.cpp:162 | |
282 | msgid "Single Player Endless" | |
283 | msgstr "" | |
284 | ||
285 | #: ../../code/menudef.cpp:169 | |
286 | msgid "Slow" | |
287 | msgstr "" | |
288 | ||
289 | #: ../../code/menudef.cpp:170 | |
290 | msgid "Fast" | |
291 | msgstr "" | |
292 | ||
293 | #: ../../code/menudef.cpp:171 | |
294 | msgid "Faster" | |
295 | msgstr "" | |
296 | ||
297 | #: ../../code/menudef.cpp:172 | |
298 | msgid "Even faster" | |
299 | msgstr "" | |
300 | ||
301 | #: ../../code/menudef.cpp:173 | |
302 | msgid "Fastest" | |
303 | msgstr "" | |
304 | ||
305 | #: ../../code/menudef.cpp:215 | |
306 | msgid "Always use software render: On" | |
307 | msgstr "" | |
308 | ||
309 | #: ../../code/menudef.cpp:216 | |
310 | msgid "Always use software render: Off" | |
311 | msgstr "" | |
312 | ||
313 | #: ../../code/menudef.cpp:220 | |
270 | 314 | msgid "Music: On" |
271 | 315 | msgstr "" |
272 | 316 | |
273 | #: ../../code/menudef.cpp:174 ../../code/menudef.cpp:242 | |
317 | #: ../../code/menudef.cpp:220 | |
274 | 318 | msgid "Music: Off" |
275 | 319 | msgstr "" |
276 | 320 | |
277 | #: ../../code/menudef.cpp:182 ../../code/menudef.cpp:243 | |
321 | #: ../../code/menudef.cpp:224 | |
278 | 322 | msgid "Sound: On" |
279 | 323 | msgstr "" |
280 | 324 | |
281 | #: ../../code/menudef.cpp:182 ../../code/menudef.cpp:243 | |
325 | #: ../../code/menudef.cpp:224 | |
282 | 326 | msgid "Sound: Off" |
283 | 327 | msgstr "" |
284 | 328 | |
285 | #: ../../code/menudef.cpp:189 ../../code/menudef.cpp:244 | |
329 | #: ../../code/menudef.cpp:228 | |
286 | 330 | msgid "Fullscreen: On" |
287 | 331 | msgstr "" |
288 | 332 | |
289 | #: ../../code/menudef.cpp:189 ../../code/menudef.cpp:244 | |
333 | #: ../../code/menudef.cpp:228 | |
290 | 334 | msgid "Fullscreen: Off" |
291 | 335 | msgstr "" |
292 | 336 | |
293 | #: ../../code/menudef.cpp:195 | |
337 | #: ../../code/menudef.cpp:261 | |
294 | 338 | msgid "Enter player 1 name:" |
295 | 339 | msgstr "" |
296 | 340 | |
297 | #: ../../code/menudef.cpp:201 | |
341 | #: ../../code/menudef.cpp:267 | |
298 | 342 | msgid "Enter player 2 name:" |
299 | 343 | msgstr "" |
300 | 344 | |
301 | #: ../../code/menudef.cpp:211 | |
345 | #: ../../code/menudef.cpp:277 | |
302 | 346 | msgid "Change key bindings" |
303 | 347 | msgstr "" |
304 | 348 | |
305 | #: ../../code/menudef.cpp:212 | |
349 | #: ../../code/menudef.cpp:278 | |
306 | 350 | msgid "Left" |
307 | 351 | msgstr "" |
308 | 352 | |
309 | #: ../../code/menudef.cpp:213 | |
353 | #: ../../code/menudef.cpp:279 | |
310 | 354 | msgid "Right" |
311 | 355 | msgstr "" |
312 | 356 | |
313 | #: ../../code/menudef.cpp:214 | |
357 | #: ../../code/menudef.cpp:280 | |
314 | 358 | msgid "Up" |
315 | 359 | msgstr "" |
316 | 360 | |
317 | #: ../../code/menudef.cpp:215 | |
361 | #: ../../code/menudef.cpp:281 | |
318 | 362 | msgid "Down" |
319 | 363 | msgstr "" |
320 | 364 | |
321 | #: ../../code/menudef.cpp:216 | |
365 | #: ../../code/menudef.cpp:282 | |
322 | 366 | msgid "Push" |
323 | 367 | msgstr "" |
324 | 368 | |
325 | #: ../../code/menudef.cpp:217 | |
369 | #: ../../code/menudef.cpp:283 | |
326 | 370 | msgid "Change" |
327 | 371 | msgstr "" |
328 | 372 | |
329 | #: ../../code/menudef.cpp:236 | |
373 | #: ../../code/menudef.cpp:302 | |
330 | 374 | msgid "Configuration" |
331 | 375 | msgstr "" |
332 | 376 | |
333 | #: ../../code/menudef.cpp:246 | |
377 | #: ../../code/menudef.cpp:314 | |
334 | 378 | msgid "Change player 1's name" |
335 | 379 | msgstr "" |
336 | 380 | |
337 | #: ../../code/menudef.cpp:248 | |
381 | #: ../../code/menudef.cpp:316 | |
338 | 382 | msgid "Change player 2's name" |
339 | 383 | msgstr "" |
340 | 384 | |
341 | #: ../../code/menudef.cpp:250 | |
385 | #: ../../code/menudef.cpp:318 | |
342 | 386 | msgid "Change player 1's keys" |
343 | 387 | msgstr "" |
344 | 388 | |
345 | #: ../../code/menudef.cpp:252 | |
389 | #: ../../code/menudef.cpp:320 | |
346 | 390 | msgid "Change player 2's keys" |
347 | 391 | msgstr "" |
348 | 392 | |
349 | #: ../../code/menudef.cpp:264 | |
393 | #: ../../code/menudef.cpp:333 | |
350 | 394 | msgid "Single player VS" |
351 | 395 | msgstr "" |
352 | 396 | |
353 | #: ../../code/menudef.cpp:280 | |
397 | #: ../../code/menudef.cpp:349 | |
354 | 398 | msgid "Very easy" |
355 | 399 | msgstr "" |
356 | 400 | |
357 | #: ../../code/menudef.cpp:281 | |
401 | #: ../../code/menudef.cpp:350 | |
358 | 402 | msgid "Easy" |
359 | 403 | msgstr "" |
360 | 404 | |
361 | #: ../../code/menudef.cpp:282 | |
405 | #: ../../code/menudef.cpp:351 | |
362 | 406 | msgid "Below normal" |
363 | 407 | msgstr "" |
364 | 408 | |
365 | #: ../../code/menudef.cpp:283 | |
409 | #: ../../code/menudef.cpp:352 | |
366 | 410 | msgid "Normal" |
367 | 411 | msgstr "" |
368 | 412 | |
369 | #: ../../code/menudef.cpp:284 | |
413 | #: ../../code/menudef.cpp:353 | |
370 | 414 | msgid "Above normal" |
371 | 415 | msgstr "" |
372 | 416 | |
373 | #: ../../code/menudef.cpp:285 | |
417 | #: ../../code/menudef.cpp:354 | |
374 | 418 | msgid "Hard" |
375 | 419 | msgstr "" |
376 | 420 | |
377 | #: ../../code/menudef.cpp:286 | |
421 | #: ../../code/menudef.cpp:355 | |
378 | 422 | msgid "Hardest" |
379 | 423 | msgstr "" |
380 | 424 | |
381 | #: ../../code/menudef.cpp:298 | |
425 | #: ../../code/menudef.cpp:367 | |
382 | 426 | msgid "Multiplayer" |
383 | 427 | msgstr "" |
384 | 428 | |
385 | #: ../../code/menudef.cpp:300 | |
429 | #: ../../code/menudef.cpp:369 | |
386 | 430 | msgid "Two player - time trial" |
387 | 431 | msgstr "" |
388 | 432 | |
389 | #: ../../code/menudef.cpp:302 | |
433 | #: ../../code/menudef.cpp:371 | |
390 | 434 | msgid "Two player - vs" |
391 | 435 | msgstr "" |
392 | 436 | |
393 | #: ../../code/menudef.cpp:326 ../../code/menudef.cpp:341 | |
437 | #: ../../code/menudef.cpp:395 ../../code/menudef.cpp:410 | |
394 | 438 | msgid "Credits" |
395 | 439 | msgstr "" |
396 | 440 | |
397 | #: ../../code/menudef.cpp:331 ../../code/menudef.cpp:384 | |
441 | #: ../../code/menudef.cpp:400 ../../code/menudef.cpp:471 | |
398 | 442 | msgid "Help" |
399 | 443 | msgstr "" |
400 | 444 | |
401 | #: ../../code/menudef.cpp:333 | |
445 | #: ../../code/menudef.cpp:402 | |
402 | 446 | msgid "How to" |
403 | 447 | msgstr "" |
404 | 448 | |
405 | #: ../../code/menudef.cpp:337 | |
449 | #: ../../code/menudef.cpp:406 | |
406 | 450 | msgid "Gamepad" |
407 | 451 | msgstr "" |
408 | 452 | |
409 | #: ../../code/menudef.cpp:352 ../../code/menudef.cpp:376 | |
453 | #: ../../code/menudef.cpp:421 ../../code/menudef.cpp:463 | |
410 | 454 | msgid "Single player" |
411 | 455 | msgstr "" |
412 | 456 | |
413 | #: ../../code/menudef.cpp:354 | |
457 | #: ../../code/menudef.cpp:423 | |
414 | 458 | msgid "Single player - endless" |
415 | 459 | msgstr "" |
416 | 460 | |
417 | #: ../../code/menudef.cpp:356 | |
461 | #: ../../code/menudef.cpp:425 | |
418 | 462 | msgid "Single player - time trial" |
419 | 463 | msgstr "" |
420 | 464 | |
421 | #: ../../code/menudef.cpp:358 | |
465 | #: ../../code/menudef.cpp:427 | |
422 | 466 | msgid "Single player - stage clear" |
423 | 467 | msgstr "" |
424 | 468 | |
425 | #: ../../code/menudef.cpp:360 | |
469 | #: ../../code/menudef.cpp:429 | |
426 | 470 | msgid "Single player - puzzle mode" |
427 | 471 | msgstr "" |
428 | 472 | |
429 | #: ../../code/menudef.cpp:362 | |
473 | #: ../../code/menudef.cpp:431 | |
430 | 474 | msgid "Single player - vs" |
431 | 475 | msgstr "" |
432 | 476 | |
433 | #: ../../code/menudef.cpp:374 | |
477 | #: ../../code/menudef.cpp:446 | |
478 | msgid "Game did not shutdown as it should" | |
479 | msgstr "" | |
480 | ||
481 | #: ../../code/menudef.cpp:449 | |
482 | msgid "Use software renderer this time" | |
483 | msgstr "" | |
484 | ||
485 | #: ../../code/menudef.cpp:450 | |
486 | msgid "Always use software renderer" | |
487 | msgstr "" | |
488 | ||
489 | #: ../../code/menudef.cpp:461 | |
434 | 490 | msgid "Block Attack - Rise of the blocks" |
435 | 491 | msgstr "" |
436 | 492 | |
437 | #: ../../code/menudef.cpp:378 | |
493 | #: ../../code/menudef.cpp:465 | |
438 | 494 | msgid "Multi player" |
439 | 495 | msgstr "" |
440 | 496 | |
441 | #: ../../code/menudef.cpp:380 | |
497 | #: ../../code/menudef.cpp:467 | |
442 | 498 | msgid "Configure" |
443 | 499 | msgstr "" |
444 | 500 | |
445 | #: ../../code/menudef.cpp:382 | |
501 | #: ../../code/menudef.cpp:469 | |
446 | 502 | msgid "Highscores" |
447 | 503 | msgstr "" |
448 | 504 | |
449 | #: ../../code/MenuSystem.cpp:162 ../../code/MenuSystem.cpp:170 | |
450 | #: ../../code/MenuSystem.cpp:183 ../../code/ScoresDisplay.cpp:184 | |
505 | #: ../../code/MenuSystem.cpp:159 ../../code/MenuSystem.cpp:167 | |
506 | #: ../../code/MenuSystem.cpp:179 ../../code/ScoresDisplay.cpp:216 | |
451 | 507 | msgid "Back" |
452 | 508 | msgstr "" |
453 | 509 | |
454 | #: ../../code/MenuSystem.cpp:173 ../../code/MenuSystem.cpp:186 | |
510 | #: ../../code/MenuSystem.cpp:170 ../../code/MenuSystem.cpp:182 | |
455 | 511 | msgid "Exit" |
456 | 512 | msgstr "" |
457 | 513 | |
458 | #: ../../code/ScoresDisplay.cpp:71 | |
514 | #: ../../code/os.cpp:99 | |
515 | msgid "Player 1" | |
516 | msgstr "" | |
517 | ||
518 | #: ../../code/ScoresDisplay.cpp:70 | |
519 | msgid "Endless (Fast):" | |
520 | msgstr "" | |
521 | ||
522 | #: ../../code/ScoresDisplay.cpp:73 | |
523 | msgid "Endless (Faster):" | |
524 | msgstr "" | |
525 | ||
526 | #: ../../code/ScoresDisplay.cpp:76 | |
527 | msgid "Endless (Even faster):" | |
528 | msgstr "" | |
529 | ||
530 | #: ../../code/ScoresDisplay.cpp:79 | |
531 | msgid "Endless (Fastest):" | |
532 | msgstr "" | |
533 | ||
534 | #: ../../code/ScoresDisplay.cpp:82 | |
459 | 535 | msgid "Endless:" |
460 | 536 | msgstr "" |
461 | 537 | |
462 | #: ../../code/ScoresDisplay.cpp:74 | |
538 | #: ../../code/ScoresDisplay.cpp:87 | |
463 | 539 | msgid "Time Trial:" |
464 | 540 | msgstr "" |
465 | 541 | |
466 | #: ../../code/ScoresDisplay.cpp:97 | |
542 | #: ../../code/ScoresDisplay.cpp:125 | |
467 | 543 | msgid "Stats" |
468 | 544 | msgstr "" |
469 | 545 | |
470 | #: ../../code/ScoresDisplay.cpp:99 | |
546 | #: ../../code/ScoresDisplay.cpp:127 | |
471 | 547 | msgid "Chains" |
472 | 548 | msgstr "" |
473 | 549 | |
474 | #: ../../code/ScoresDisplay.cpp:107 | |
550 | #: ../../code/ScoresDisplay.cpp:135 | |
475 | 551 | msgid "Lines Pushed: " |
476 | 552 | msgstr "" |
477 | 553 | |
478 | #: ../../code/ScoresDisplay.cpp:112 | |
554 | #: ../../code/ScoresDisplay.cpp:140 | |
479 | 555 | msgid "Puzzles solved: " |
480 | 556 | msgstr "" |
481 | 557 | |
482 | #: ../../code/ScoresDisplay.cpp:117 | |
558 | #: ../../code/ScoresDisplay.cpp:145 | |
483 | 559 | msgid "Run time: " |
484 | 560 | msgstr "" |
485 | 561 | |
486 | #: ../../code/ScoresDisplay.cpp:120 ../../code/ScoresDisplay.cpp:133 | |
562 | #: ../../code/ScoresDisplay.cpp:148 ../../code/ScoresDisplay.cpp:161 | |
487 | 563 | #, c-format |
488 | 564 | msgid "Days: %i" |
489 | 565 | msgstr "" |
490 | 566 | |
491 | #: ../../code/ScoresDisplay.cpp:122 ../../code/ScoresDisplay.cpp:135 | |
567 | #: ../../code/ScoresDisplay.cpp:150 ../../code/ScoresDisplay.cpp:163 | |
492 | 568 | #, c-format |
493 | 569 | msgid "Hours: %i" |
494 | 570 | msgstr "" |
495 | 571 | |
496 | #: ../../code/ScoresDisplay.cpp:124 ../../code/ScoresDisplay.cpp:137 | |
572 | #: ../../code/ScoresDisplay.cpp:152 ../../code/ScoresDisplay.cpp:165 | |
497 | 573 | #, c-format |
498 | 574 | msgid "Minutes: %i" |
499 | 575 | msgstr "" |
500 | 576 | |
501 | #: ../../code/ScoresDisplay.cpp:126 ../../code/ScoresDisplay.cpp:139 | |
577 | #: ../../code/ScoresDisplay.cpp:154 ../../code/ScoresDisplay.cpp:167 | |
502 | 578 | #, c-format |
503 | 579 | msgid "Seconds: %i" |
504 | 580 | msgstr "" |
505 | 581 | |
506 | #: ../../code/ScoresDisplay.cpp:130 | |
582 | #: ../../code/ScoresDisplay.cpp:158 | |
507 | 583 | msgid "Play time: " |
508 | 584 | msgstr "" |
509 | 585 | |
510 | #: ../../code/ScoresDisplay.cpp:143 | |
586 | #: ../../code/ScoresDisplay.cpp:171 | |
511 | 587 | msgid "VS CPU (win/loss)" |
512 | 588 | msgstr "" |
513 | 589 | |
514 | #: ../../code/ScoresDisplay.cpp:188 ../../code/BlockGameSdl.inc:55 | |
590 | #: ../../code/ScoresDisplay.cpp:220 ../../code/BlockGameSdl.inc:55 | |
515 | 591 | msgid "Next" |
516 | 592 | msgstr "" |
517 | 593 | |
518 | #: ../../code/ScoresDisplay.cpp:192 | |
594 | #: ../../code/ScoresDisplay.cpp:224 | |
519 | 595 | #, c-format |
520 | 596 | msgid "Page %i of %i" |
521 | 597 | msgstr "" |
1 | 1 | |
2 | 2 | ; HM NIS Edit Wizard helper defines |
3 | 3 | !define PRODUCT_NAME "Block Attack - Rise Of the Blocks" |
4 | !define PRODUCT_VERSION "2.3.0" | |
4 | !define PRODUCT_VERSION "2.5.0" | |
5 | 5 | !define PRODUCT_PUBLISHER "Poul Sander" |
6 | 6 | !define PRODUCT_WEB_SITE "http://www.blockattack.net" |
7 | 7 | !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\blockattack.exe" |