├── .gitmodules ├── .travis.yml ├── CMakeLists.txt ├── COPYING ├── README.md ├── artemispuzzle.cc ├── artemispuzzle.hh ├── cmake └── FindQuickTime.cmake ├── datamanager.cc ├── datamanager.hh ├── gameeventlistener.hh ├── gameinterface.cc ├── gameinterface.hh ├── hexagonspuzzle.cc ├── hexagonspuzzle.hh ├── hotfile.cc ├── hotfile.hh ├── interpreter.cc ├── interpreter.hh ├── logger.hh ├── main.cc ├── movplayer.cc ├── movplayer.hh ├── nodfile.cc ├── nodfile.hh ├── quicktime.cc ├── quicktime.hh ├── screen.cc ├── screen.hh ├── sunpuzzle.cc └── sunpuzzle.hh /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "extlibs/SDL2pp"] 2 | path = extlibs/SDL2pp 3 | url = git://github.com/AMDmi3/libSDL2pp.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: required 3 | dist: trusty 4 | compiler: 5 | - gcc 6 | - clang 7 | before_install: 8 | - sudo add-apt-repository --yes ppa:zoogie/sdl2-snapshots 9 | - sudo apt-get update -qq 10 | - sudo apt-get install -qq cmake libsdl2-dev libsdl2-image-dev libquicktime-dev 11 | script: 12 | - cmake -DCMAKE_CXX_FLAGS=-Werror . 13 | - make 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT(OpenDaed) 2 | 3 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 4 | 5 | # common depends and definitions 6 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -pedantic") 7 | 8 | OPTION(BUG2BUG "Enable bug-to-bug compatibility (useless really)" OFF) 9 | 10 | # depends 11 | IF(NOT EXISTS ${PROJECT_SOURCE_DIR}/extlibs/SDL2pp/CMakeLists.txt) 12 | MESSAGE(FATAL_ERROR "The source directory\n ${PROJECT_SOURCE_DIR}/extlibs/SDL2pp\ndoes not contain a CMakeLists.txt file.\nIt is likely that you forgot to run\n git submodule init && git submodule update") 13 | ENDIF(NOT EXISTS ${PROJECT_SOURCE_DIR}/extlibs/SDL2pp/CMakeLists.txt) 14 | 15 | SET(SDL2PP_WITH_IMAGE TRUE) 16 | ADD_SUBDIRECTORY(extlibs/SDL2pp) 17 | 18 | SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 19 | FIND_PACKAGE(QuickTime REQUIRED) 20 | 21 | # sources 22 | SET(OPENDAED_SOURCES 23 | artemispuzzle.cc 24 | datamanager.cc 25 | gameinterface.cc 26 | hexagonspuzzle.cc 27 | hotfile.cc 28 | interpreter.cc 29 | main.cc 30 | movplayer.cc 31 | nodfile.cc 32 | quicktime.cc 33 | screen.cc 34 | sunpuzzle.cc 35 | ) 36 | 37 | SET(OPENDAED_HEADERS 38 | artemispuzzle.hh 39 | datamanager.hh 40 | gameeventlistener.hh 41 | gameinterface.hh 42 | hexagonspuzzle.hh 43 | hotfile.hh 44 | interpreter.hh 45 | logger.hh 46 | movplayer.hh 47 | nodfile.hh 48 | quicktime.hh 49 | screen.hh 50 | sunpuzzle.hh 51 | ) 52 | 53 | # binary 54 | IF(BUG2BUG) 55 | ADD_DEFINITIONS(-DBUG2BUG) 56 | ENDIF(BUG2BUG) 57 | 58 | INCLUDE_DIRECTORIES(${SDL2PP_INCLUDE_DIRS} ${QUICKTIME_INCLUDE_DIR}) 59 | ADD_EXECUTABLE(opendaed ${OPENDAED_SOURCES} ${OPENDAED_HEADERS}) 60 | TARGET_LINK_LIBRARIES(opendaed ${SDL2PP_LIBRARIES} ${QUICKTIME_LIBRARY}) 61 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenDaed 2 | 3 | [![Build Status](https://travis-ci.org/AMDmi3/opendaed.svg?branch=master)](https://travis-ci.org/AMDmi3/opendaed) 4 | 5 | F/OSS reimplementation of Mechadeus 1995 "The Daedalus 6 | Encounter" interactive movie puzzle adventure game. 7 | 8 | ## Status 9 | 10 | The project is currently on the early stages of development, and 11 | is not yet playable, however you can already run through the very 12 | first scenes of the story (from beginning up to entering Vekkar 13 | freighter). 14 | 15 | ## Building 16 | 17 | Dependencies: 18 | 19 | * cmake 20 | * SDL2 21 | * SDL2_image 22 | 23 | The project also uses libSDL2pp, C++11 bindings library for SDL2. 24 | It's included into git repository as a submodule, so if you've 25 | obtained source through git, don't forget to run ```git submodule 26 | init && git submodule update```. 27 | 28 | To build the project, run: 29 | 30 | ``` 31 | cmake . && make 32 | ``` 33 | 34 | ## Running 35 | 36 | To run the game, you need original game data. Specify path to data 37 | directory (it may be either CD-ROM mount point or a directory 38 | containing contents of all game CDs; directory structure doesn't 39 | really matter in the latter case, game will find needed data in 40 | subdirectories automatically) with ```-d``` options: 41 | 42 | ``` 43 | opendaed -d 44 | ``` 45 | 46 | You may also specify name of game scenario (.nod) file and starting 47 | entry number with ```-n``` and ```-e``` options respectively - it's 48 | useful to jump to arbitrary part of the game for debugging purposes. 49 | 50 | For instance, 51 | ``` 52 | opendaed -d -n encountr.nod -e 2 53 | ``` 54 | is the start of the game story. 55 | 56 | You may also directly play puzzles which are already implemented. 57 | For that, run: 58 | ``` 59 | opendaed -d -p 60 | ``` 61 | 62 | Currently implemented puzzles are: 63 | 64 | * ```artemis``` - netwalk-style power connection puzzle 65 | * ```hexagons``` - yellow door puzzle 66 | * ```sun``` - sundial puzzle in engine room 67 | 68 | ## Author 69 | 70 | * [Dmitry Marakasov](https://github.com/AMDmi3) 71 | 72 | ## License 73 | 74 | GPLv3, see COPYING 75 | 76 | The project also bundles third party software under its own licenses: 77 | 78 | * extlibs/SDL2pp (C++11 SDL2 wrapper library) - zlib license 79 | -------------------------------------------------------------------------------- /artemispuzzle.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "artemispuzzle.hh" 26 | 27 | #include "datamanager.hh" 28 | #include "logger.hh" 29 | 30 | const std::array ArtemisPuzzle::initial_pieces_ = { { 31 | DR, UL, DR, VE, UL, DR, UL, HO, UL, 32 | DR, DL, DR, UR, VE, HO, DR, DR, UL, 33 | UL, DR, VE, DR, UR, DR, UL, VE, HO, 34 | DR, HO, DR, UL, DR, UR, HO, HO, DL, // central piece is not used 35 | UR, VE, UL, UR, DR, UL, VE, UR, DL, 36 | DR, UL, HO, UL, VE, DR, DR, DR, VE, 37 | DR, HO, DR, UR, UL, UL, HO, DR, UR, 38 | } }; 39 | 40 | // this is bug2bug compatibility, but actually alignment may be 41 | // improved; look at connection lines between pieces 42 | const std::array ArtemisPuzzle::col_offsets_ = { { 43 | 44 + 64 * 0, 44 | 44 + 64 * 1, 45 | 44 + 64 * 2, 46 | 44 + 64 * 3, 47 | 44 + 64 * 4, 48 | 44 + 64 * 5, 49 | 44 + 64 * 6, 50 | 44 + 64 * 7, 51 | 44 + 64 * 8, 52 | } }; 53 | 54 | const std::array ArtemisPuzzle::row_offsets_ = { { 55 | 36 + 61 * 0, 56 | 36 + 61 * 1, 57 | 36 + 61 * 2 + 1, 58 | 36 + 61 * 3 + 1, 59 | 36 + 61 * 4 + 1, 60 | 36 + 61 * 5 + 1, 61 | 36 + 61 * 6 + 2, 62 | } }; 63 | 64 | const std::array ArtemisPuzzle::light_locations_ = { { 65 | #ifdef BUG2BUG 66 | // original lights are a bit displaced 67 | { 10, 264 }, 68 | { 83, 195 }, 69 | { 84, 318 }, 70 | { 148, 257 }, 71 | { 212, 73 }, 72 | { 276, 379 }, 73 | { 339, 73 }, 74 | { 339, 135 }, 75 | { 404, 377 }, 76 | { 468, 195 }, 77 | { 519, 6 }, 78 | { 532, 134 }, 79 | { 531, 256 }, 80 | #else 81 | { 11, 265 }, 82 | { 84, 196 }, 83 | { 84, 318 }, 84 | { 148, 257 }, 85 | { 212, 73 }, 86 | { 275, 379 }, 87 | { 339, 73 }, 88 | { 339, 135 }, 89 | { 403, 379 }, 90 | { 468, 195 }, 91 | { 519, 6 }, 92 | { 531, 135 }, 93 | { 531, 257 }, 94 | #endif 95 | } }; 96 | 97 | ArtemisPuzzle::PieceType ArtemisPuzzle::RotatePiece(PieceType type, bool clockwise) { 98 | switch (type) { 99 | case DR: return clockwise ? DL : UR; 100 | case DL: return clockwise ? UL : DR; 101 | case UL: return clockwise ? UR : DL; 102 | case UR: return clockwise ? DR : UL; 103 | case HO: return VE; 104 | case VE: return HO; 105 | } 106 | return HO; // silence gcc warning 107 | } 108 | 109 | void ArtemisPuzzle::RecalculateActivePieces() { 110 | std::fill(active_.begin(), active_.end(), false); 111 | std::fill(horizontal_lines_.begin(), horizontal_lines_.end(), false); 112 | std::fill(vertical_lines_.begin(), vertical_lines_.end(), false); 113 | activated_systems_ = 0; 114 | 115 | PropagateActivity(CENTRAL_COLUMN, CENTRAL_ROW, LEFT); 116 | PropagateActivity(CENTRAL_COLUMN, CENTRAL_ROW, RIGHT); 117 | PropagateActivity(CENTRAL_COLUMN, CENTRAL_ROW, UP); 118 | PropagateActivity(CENTRAL_COLUMN, CENTRAL_ROW, DOWN); 119 | } 120 | 121 | void ArtemisPuzzle::PropagateActivity(int x, int y, Direction dir) { 122 | while (1) { 123 | switch (dir) { 124 | case LEFT: x--; break; 125 | case RIGHT: x++; break; 126 | case UP: y--; break; 127 | case DOWN: y++; break; 128 | } 129 | 130 | if (x == -1 && y == CENTRAL_ROW) 131 | activated_systems_ |= AUX_BIO_SYSTEMS; 132 | if (x == NUM_COLUMNS && y == CENTRAL_ROW) 133 | activated_systems_ |= AUX_CONTROL_SYSTEM; 134 | if (x == CENTRAL_COLUMN && y == -1) 135 | activated_systems_ |= AUX_AIR_REFILTRATION; 136 | if (x == CENTRAL_COLUMN && y == NUM_ROWS) 137 | activated_systems_ |= AUX_POWER_GRID; 138 | 139 | if (x < 0 || y < 0 || x >= NUM_COLUMNS || y >= NUM_ROWS) 140 | return; // out of bounds 141 | if (x == CENTRAL_COLUMN && y == CENTRAL_ROW) 142 | return; // back into center 143 | 144 | PieceType type = pieces_[y * NUM_COLUMNS + x]; 145 | 146 | Direction prev_dir = dir; 147 | 148 | switch (dir) { 149 | case LEFT: 150 | switch (type) { 151 | case DR: dir = DOWN; break; 152 | case UR: dir = UP; break; 153 | case HO: break; 154 | default: 155 | return; 156 | } 157 | break; 158 | case RIGHT: 159 | switch (type) { 160 | case DL: dir = DOWN; break; 161 | case UL: dir = UP; break; 162 | case HO: break; 163 | default: 164 | return; 165 | } 166 | break; 167 | case UP: 168 | switch (type) { 169 | case DR: dir = RIGHT; break; 170 | case DL: dir = LEFT; break; 171 | case VE: break; 172 | default: 173 | return; 174 | } 175 | break; 176 | case DOWN: 177 | switch (type) { 178 | case UL: dir = LEFT; break; 179 | case UR: dir = RIGHT; break; 180 | case VE: break; 181 | default: 182 | return; 183 | } 184 | break; 185 | } 186 | 187 | // activate piece 188 | active_[y * NUM_COLUMNS + x] = true; 189 | 190 | // activate line from prev piece 191 | switch (prev_dir) { 192 | case LEFT: horizontal_lines_[y * (NUM_COLUMNS - 1) + x] = true; break; 193 | case RIGHT: horizontal_lines_[y * (NUM_COLUMNS - 1) + x - 1] = true; break; 194 | case UP: vertical_lines_[y * NUM_COLUMNS + x] = true; break; 195 | case DOWN: vertical_lines_[(y - 1) * NUM_COLUMNS + x] = true; break; 196 | } 197 | } 198 | } 199 | 200 | ArtemisPuzzle::ArtemisPuzzle(SDL2pp::Renderer& renderer, const DataManager& datamanager) 201 | : renderer_(renderer), 202 | background_(renderer, datamanager.GetPath("images/party/backgrnd.rle")), 203 | pieces_inactive_(renderer, datamanager.GetPath("images/party/ctrw.rle")), 204 | pieces_active_(renderer, datamanager.GetPath("images/party/ctrr.rle")), 205 | line_horiz_(renderer, datamanager.GetPath("images/party/horz.rle")), 206 | line_vert_(renderer, datamanager.GetPath("images/party/vert.bmp")), 207 | core_(renderer, datamanager.GetPath("images/party/p1circ.bmp")), 208 | lights_(renderer, datamanager.GetPath("images/party/lights.bmp")), 209 | aux1_(renderer, datamanager.GetPath("images/party/aux1.rle")), 210 | aux2_(renderer, datamanager.GetPath("images/party/aux2.rle")), 211 | aux3_(renderer, datamanager.GetPath("images/party/aux3.rle")), 212 | aux4_(renderer, datamanager.GetPath("images/party/aux4.rle")), 213 | main1_(renderer, datamanager.GetPath("images/party/main1.rle")), 214 | main2_(renderer, datamanager.GetPath("images/party/main2.rle")), 215 | main3_(renderer, datamanager.GetPath("images/party/main3.rle")), 216 | main4_(renderer, datamanager.GetPath("images/party/main4.rle")), 217 | greyblit_(renderer, datamanager.GetPath("images/party/greyblit.bmp")), 218 | pieces_(initial_pieces_) { 219 | RecalculateActivePieces(); 220 | 221 | last_frame_time_ = SDL_GetTicks(); 222 | time_left_[0] = TIME_LIMIT_TICKS; 223 | time_left_[1] = TIME_LIMIT_TICKS; 224 | time_left_[2] = TIME_LIMIT_TICKS; 225 | time_left_[3] = TIME_LIMIT_TICKS; 226 | 227 | Log("puzzle") << "starting artemis puzzle"; 228 | } 229 | 230 | ArtemisPuzzle::~ArtemisPuzzle() { 231 | } 232 | 233 | bool ArtemisPuzzle::ProcessEvent(const SDL_Event& event) { 234 | if (event.type == SDL_MOUSEBUTTONDOWN) { 235 | // get closest next row/column 236 | auto col_offset = std::upper_bound(col_offsets_.begin(), col_offsets_.end(), event.button.x); 237 | auto row_offset = std::upper_bound(row_offsets_.begin(), row_offsets_.end(), event.button.y); 238 | 239 | // fix row/col and check we're in bounds 240 | if (col_offset-- == col_offsets_.begin() || event.button.x - *col_offset >= 32) 241 | return true; 242 | if (row_offset-- == row_offsets_.begin() || event.button.y - *row_offset >= 32) 243 | return true; 244 | 245 | // calculate piece number 246 | int column = col_offset - col_offsets_.begin(); 247 | int row = row_offset - row_offsets_.begin(); 248 | if (column >= NUM_COLUMNS || row >= NUM_ROWS) 249 | return true; 250 | int npiece = row * NUM_COLUMNS + column; 251 | 252 | // rotate piece 253 | #ifdef BUG2BUG 254 | bool clockwise = true; 255 | #else 256 | bool clockwise = event.button.button != SDL_BUTTON_RIGHT; 257 | #endif 258 | if (event.button.button == SDL_BUTTON_LEFT || event.button.button == SDL_BUTTON_RIGHT || event.button.button == SDL_BUTTON_MIDDLE) 259 | pieces_[npiece] = RotatePiece(pieces_[npiece], clockwise); 260 | 261 | RecalculateActivePieces(); 262 | } 263 | 264 | if (activated_systems_ == ALL_SYSTEMS) { 265 | Log("puzzle") << " all systems connected, congratulations!"; 266 | return false; 267 | } 268 | 269 | return true; 270 | } 271 | 272 | bool ArtemisPuzzle::Update() { 273 | unsigned int ticks = SDL_GetTicks(); 274 | unsigned int delta = ticks - last_frame_time_; 275 | last_frame_time_ = ticks; 276 | 277 | if (!(activated_systems_ & AUX_BIO_SYSTEMS)) 278 | time_left_[3] -= delta; 279 | if (!(activated_systems_ & AUX_POWER_GRID)) 280 | time_left_[2] -= delta; 281 | if (!(activated_systems_ & AUX_CONTROL_SYSTEM)) 282 | time_left_[1] -= delta; 283 | if (!(activated_systems_ & AUX_AIR_REFILTRATION)) 284 | time_left_[0] -= delta; 285 | 286 | for (int i = 0; i < 4; i++) { 287 | if (time_left_[i] <= 0) { 288 | Log("puzzle") << " your time is out, you're dead"; 289 | return false; 290 | } 291 | } 292 | 293 | return true; 294 | } 295 | 296 | void ArtemisPuzzle::Render() { 297 | // Background 298 | renderer_.Copy(background_, SDL2pp::NullOpt, SDL2pp::Rect(0, 0, 640, 480)); 299 | 300 | // Pieces 301 | int n = 0; 302 | for (int y = 0; y < NUM_ROWS; y++) { 303 | for (int x = 0; x < NUM_COLUMNS; x++, n++) { 304 | if (n == CENTRAL_PIECE_NUMBER) 305 | continue; 306 | 307 | // this is also bug2bug compatible; the thing is that ctrr.bmp 308 | // has vertical and horizontal lines misplaced a bit 309 | renderer_.Copy( 310 | active_[n] ? pieces_active_ : pieces_inactive_, 311 | SDL2pp::Rect(32 * (int)pieces_[n], 0, 32, 32), 312 | SDL2pp::Rect(col_offsets_[x], row_offsets_[y], 32, 32) 313 | ); 314 | } 315 | } 316 | 317 | // Vertical lines 318 | n = 0; 319 | for (int y = 0; y < NUM_ROWS - 1; y++) { 320 | for (int x = 0; x < NUM_COLUMNS; x++, n++) { 321 | if (n == NUM_VERTICAL_LINES / 2 || n == NUM_VERTICAL_LINES / 2 - 1) // central lines 322 | continue; 323 | if (vertical_lines_[n]) { 324 | renderer_.Copy( 325 | line_vert_, 326 | SDL2pp::Rect(6, 0, 6, row_offsets_[y + 1] - row_offsets_[y] - 32), 327 | SDL2pp::Rect(col_offsets_[x] + 13, row_offsets_[y] + 32, 6, row_offsets_[y + 1] - row_offsets_[y] - 32) 328 | ); 329 | } 330 | } 331 | } 332 | 333 | // Horizontal lines 334 | n = 0; 335 | for (int y = 0; y < NUM_ROWS; y++) { 336 | for (int x = 0; x < NUM_COLUMNS - 1; x++, n++) { 337 | if (n == NUM_HORIZONTAL_LINES / 2 || n == NUM_HORIZONTAL_LINES / 2 - 1) // central lines 338 | continue; 339 | if (horizontal_lines_[n]) { 340 | renderer_.Copy( 341 | line_horiz_, 342 | SDL2pp::Rect(0, 6, col_offsets_[x + 1] - col_offsets_[x] - 32, 6), 343 | SDL2pp::Rect(col_offsets_[x] + 32, row_offsets_[y] + 13, col_offsets_[y + 1] - col_offsets_[y] - 32, 6) 344 | ); 345 | } 346 | } 347 | } 348 | 349 | // connected systems indication 350 | if (activated_systems_ & AUX_BIO_SYSTEMS) 351 | renderer_.Copy(aux4_, SDL2pp::NullOpt, SDL2pp::Rect(38, 460, 120, 12)); 352 | if (activated_systems_ & AUX_POWER_GRID) 353 | renderer_.Copy(aux3_, SDL2pp::NullOpt, SDL2pp::Rect(177, 460, 120, 12)); 354 | if (activated_systems_ & AUX_CONTROL_SYSTEM) 355 | renderer_.Copy(aux2_, SDL2pp::NullOpt, SDL2pp::Rect(320, 460, 120, 12)); 356 | if (activated_systems_ & AUX_AIR_REFILTRATION) 357 | renderer_.Copy(aux1_, SDL2pp::NullOpt, SDL2pp::Rect(469, 460, 120, 12)); 358 | 359 | // animated stuff: core 360 | int seconds = SDL_GetTicks() / 1000; 361 | 362 | int corephase = seconds % 15; 363 | renderer_.Copy( 364 | core_, 365 | SDL2pp::Rect(96 * (corephase % 5), 92 * (corephase / 5), 96, 92), 366 | SDL2pp::Rect(270, 191, 96, 92) 367 | ); 368 | 369 | // animated stuff: blinking lighs 370 | // fun fact: if you use minstd_rand0 or minstd_rand PRNG here 371 | // you'll notice some lights not changing their color (or changing 372 | // with long period), likely because of poor quality of PRNG 373 | std::mt19937 rnd; 374 | rnd.seed(seconds); 375 | for (auto& coords : light_locations_) { 376 | renderer_.Copy( 377 | lights_, 378 | SDL2pp::Rect(18 * (rnd() % 3), 0, 18, 18), 379 | SDL2pp::Rect(coords.x, coords.y, 18, 18) 380 | ); 381 | } 382 | 383 | // animated stuff: useless messages 384 | if (activated_systems_ == ALL_SYSTEMS) { 385 | renderer_.Copy(main4_, SDL2pp::NullOpt, SDL2pp::Rect(40, 6, 250, 12)); 386 | } else { 387 | switch (seconds % 4) { 388 | case 0: break; 389 | case 1: renderer_.Copy(main1_, SDL2pp::NullOpt, SDL2pp::Rect(40, 6, 250, 12)); break; 390 | case 2: renderer_.Copy(main2_, SDL2pp::NullOpt, SDL2pp::Rect(40, 6, 250, 12)); break; 391 | case 3: renderer_.Copy(main3_, SDL2pp::NullOpt, SDL2pp::Rect(40, 6, 250, 12)); break; 392 | } 393 | } 394 | 395 | // time indication 396 | for (int sys = 0; sys < 4; sys++) { 397 | int numfills = std::min(34, 35 * (TIME_LIMIT_TICKS - time_left_[sys]) / TIME_LIMIT_TICKS); 398 | for (int fill = 0; fill < numfills; fill++) 399 | renderer_.Copy(greyblit_, SDL2pp::NullOpt, SDL2pp::Rect(7 + sys * 5, 11 + fill * 6, 5, 5)); 400 | } 401 | } 402 | -------------------------------------------------------------------------------- /artemispuzzle.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef ARTEMISPUZZLE_HH 21 | #define ARTEMISPUZZLE_HH 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include "screen.hh" 29 | 30 | class DataManager; 31 | 32 | class ArtemisPuzzle : public Screen { 33 | private: 34 | enum PieceType { 35 | DR = 0, 36 | DL = 1, 37 | UL = 2, 38 | UR = 3, 39 | HO = 4, 40 | VE = 5, 41 | }; 42 | 43 | enum Direction { 44 | LEFT, 45 | RIGHT, 46 | UP, 47 | DOWN, 48 | }; 49 | 50 | enum Systems { 51 | AUX_BIO_SYSTEMS = 1, 52 | AUX_CONTROL_SYSTEM = 2, 53 | AUX_AIR_REFILTRATION = 4, 54 | AUX_POWER_GRID = 8, 55 | 56 | ALL_SYSTEMS = AUX_BIO_SYSTEMS | AUX_CONTROL_SYSTEM | AUX_AIR_REFILTRATION | AUX_POWER_GRID, 57 | }; 58 | 59 | enum Constants { 60 | NUM_COLUMNS = 9, 61 | NUM_ROWS = 7, 62 | 63 | NUM_PIECES = NUM_COLUMNS * NUM_ROWS, 64 | CENTRAL_PIECE_NUMBER = NUM_PIECES / 2, 65 | 66 | NUM_HORIZONTAL_LINES = (NUM_COLUMNS - 1) * NUM_ROWS, 67 | NUM_VERTICAL_LINES = NUM_COLUMNS * (NUM_ROWS - 1), 68 | 69 | CENTRAL_COLUMN = NUM_COLUMNS / 2, 70 | CENTRAL_ROW = NUM_ROWS / 2, 71 | 72 | TIME_LIMIT_TICKS = 280 * 1000, 73 | }; 74 | 75 | private: 76 | static const std::array initial_pieces_; 77 | static const std::array col_offsets_; 78 | static const std::array row_offsets_; 79 | static const std::array light_locations_; 80 | 81 | private: 82 | SDL2pp::Renderer& renderer_; 83 | 84 | // Textures 85 | SDL2pp::Texture background_; 86 | SDL2pp::Texture pieces_inactive_; 87 | SDL2pp::Texture pieces_active_; 88 | SDL2pp::Texture line_horiz_; 89 | SDL2pp::Texture line_vert_; 90 | SDL2pp::Texture core_; 91 | SDL2pp::Texture lights_; 92 | SDL2pp::Texture aux1_; 93 | SDL2pp::Texture aux2_; 94 | SDL2pp::Texture aux3_; 95 | SDL2pp::Texture aux4_; 96 | SDL2pp::Texture main1_; 97 | SDL2pp::Texture main2_; 98 | SDL2pp::Texture main3_; 99 | SDL2pp::Texture main4_; 100 | SDL2pp::Texture greyblit_; 101 | 102 | private: 103 | std::array pieces_; 104 | std::array active_; 105 | 106 | std::array horizontal_lines_; 107 | std::array vertical_lines_; 108 | 109 | int activated_systems_; 110 | int time_left_[4]; 111 | unsigned int last_frame_time_; 112 | 113 | private: 114 | PieceType RotatePiece(PieceType type, bool clockwise = true); 115 | void RecalculateActivePieces(); 116 | void PropagateActivity(int x, int y, Direction dir); 117 | 118 | public: 119 | ArtemisPuzzle(SDL2pp::Renderer& renderer, const DataManager& datamanager); 120 | virtual ~ArtemisPuzzle(); 121 | 122 | bool ProcessEvent(const SDL_Event& event) override; 123 | bool Update() override; 124 | void Render() override; 125 | }; 126 | 127 | #endif // ARTEMISPUZZLE_HH 128 | -------------------------------------------------------------------------------- /cmake/FindQuickTime.cmake: -------------------------------------------------------------------------------- 1 | # - Try to locate QuickTime 2 | # This module defines: 3 | # 4 | # QUICKTIME_INCLUDE_DIR 5 | # QUICKTIME_LIBRARY 6 | # QUICKTIME_FOUND 7 | # 8 | 9 | FIND_PATH(QUICKTIME_INCLUDE_DIR NAMES lqt/lqt.h) 10 | 11 | FIND_LIBRARY(QUICKTIME_LIBRARY NAMES quicktime) 12 | 13 | IF(QUICKTIME_INCLUDE_DIR AND QUICKTIME_LIBRARY) 14 | SET(QUICKTIME_FOUND TRUE) 15 | ENDIF(QUICKTIME_INCLUDE_DIR AND QUICKTIME_LIBRARY) 16 | 17 | IF(QUICKTIME_FOUND) 18 | IF(NOT QUICKTIME_FIND_QUIETLY) 19 | MESSAGE(STATUS "Found libquicktime: -I${QUICKTIME_INCLUDE_DIR}, ${QUICKTIME_LIBRARY}") 20 | ENDIF(NOT QUICKTIME_FIND_QUIETLY) 21 | ELSE(QUICKTIME_FOUND) 22 | IF(QUICKTIME_FIND_REQUIRED) 23 | MESSAGE(FATAL_ERROR "Could not find libquicktime") 24 | ENDIF(QUICKTIME_FIND_REQUIRED) 25 | ENDIF(QUICKTIME_FOUND) 26 | 27 | MARK_AS_ADVANCED(QUICKTIME_INCLUDE_DIR QUICKTIME_LIBRARY QUICKTIME_FOUND) 28 | -------------------------------------------------------------------------------- /datamanager.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | 24 | #include "logger.hh" 25 | 26 | #include "datamanager.hh" 27 | 28 | void DataManager::ScanDir(const std::string& path, std::function processor) { 29 | DIR* dirp = opendir(path.c_str()); 30 | if (dirp == nullptr) 31 | throw std::runtime_error("cannot read data directory"); 32 | 33 | try { 34 | struct dirent* de; 35 | while ((de = readdir(dirp)) != nullptr) { 36 | if (de->d_name[0] == '.') 37 | continue; 38 | 39 | if (de->d_type == DT_DIR) { 40 | ScanDir(path + "/" + de->d_name, processor); 41 | } else if (de->d_type == DT_REG) { 42 | processor(path, de->d_name); 43 | } 44 | } 45 | } catch (...) { 46 | closedir(dirp); 47 | throw; 48 | } 49 | closedir(dirp); 50 | } 51 | 52 | DataManager::DataManager() { 53 | } 54 | 55 | DataManager::~DataManager() { 56 | } 57 | 58 | void DataManager::ScanDir(const std::string& datapath) { 59 | PathMap new_files; 60 | 61 | // Note: for the sake of simplicity, we assume that file 62 | // with specific name is only present on a single disk once 63 | // and if it's present on different disks, all copies are 64 | // identical 65 | ScanDir(datapath, [&new_files](const std::string& dir, const std::string& file){ 66 | std::string fullpath = dir + "/" + file; 67 | std::string lcfile = file; 68 | std::transform(lcfile.begin(), lcfile.end(), lcfile.begin(), ::tolower); 69 | new_files.insert(std::make_pair(lcfile, fullpath)); 70 | }); 71 | 72 | data_files_.swap(new_files); 73 | 74 | Log("datamgr") << "found data files in " << datapath << ":"; 75 | for (auto& file: data_files_) 76 | Log("datamgr") << " " << file.first << " -> " << file.second; 77 | } 78 | 79 | std::string DataManager::GetPath(const std::string& path) const { 80 | // Though full path may be provided (e.g. "images/intrface.bmp", 81 | // only file name matters, see assumption described in ScanDir() 82 | std::string name = path; 83 | size_t slashpos = name.rfind('/'); 84 | if (slashpos != std::string::npos) 85 | name = name.substr(slashpos + 1); 86 | std::transform(name.begin(), name.end(), name.begin(), ::tolower); 87 | 88 | PathMap::const_iterator file = data_files_.find(name); 89 | if (file == data_files_.end()) 90 | throw std::runtime_error("required data file not found"); 91 | 92 | Log("datamgr") << "returning " << file->second << " for " << path; 93 | return file->second; 94 | } 95 | 96 | bool DataManager::HasPath(const std::string& path) const { 97 | // Though full path may be provided (e.g. "images/intrface.bmp", 98 | // only file name matters, see assumption described in ScanDir() 99 | std::string name = path; 100 | size_t slashpos = name.rfind('/'); 101 | if (slashpos != std::string::npos) 102 | name = name.substr(slashpos + 1); 103 | std::transform(name.begin(), name.end(), name.begin(), ::tolower); 104 | 105 | PathMap::const_iterator file = data_files_.find(name); 106 | return file != data_files_.end(); 107 | } 108 | -------------------------------------------------------------------------------- /datamanager.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef DATAMANAGER_HH 21 | #define DATAMANAGER_HH 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | class DataManager { 28 | protected: 29 | typedef std::map PathMap; 30 | 31 | protected: 32 | PathMap data_files_; 33 | 34 | private: 35 | void ScanDir(const std::string& path, std::function processor); 36 | 37 | public: 38 | DataManager(); 39 | ~DataManager(); 40 | 41 | void ScanDir(const std::string& datapath); 42 | std::string GetPath(const std::string& path) const; 43 | bool HasPath(const std::string& path) const; 44 | }; 45 | 46 | #endif // DATAMANAGER_HH 47 | -------------------------------------------------------------------------------- /gameeventlistener.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef GAMEEVENTLISTENER_HH 21 | #define GAMEEVENTLISTENER_HH 22 | 23 | #include 24 | #include 25 | 26 | #include "movplayer.hh" 27 | #include "gameinterface.hh" 28 | 29 | class GameEventListener : public MovPlayer::EventListener, public GameInterface::EventListener { 30 | public: 31 | typedef std::function ControlEventHandler; 32 | typedef std::function PointEventHandler; 33 | typedef std::function EndOfClipEventHandler; 34 | 35 | private: 36 | std::list control_event_handlers_; 37 | std::list point_event_handlers_; 38 | std::list endofclip_event_handlers_; 39 | 40 | struct StackEntry { 41 | size_t control_events; 42 | size_t point_events; 43 | size_t endofclip_events; 44 | }; 45 | 46 | std::list handler_state_stack_; 47 | 48 | public: 49 | virtual ~GameEventListener() { 50 | } 51 | 52 | void AddControlEventHandler(ControlEventHandler&& handler) { 53 | control_event_handlers_.emplace_back(std::move(handler)); 54 | } 55 | 56 | void AddPointEventHandler(PointEventHandler&& handler) { 57 | point_event_handlers_.emplace_back(std::move(handler)); 58 | } 59 | 60 | void AddEndOfClipEventHandler(EndOfClipEventHandler&& handler) { 61 | endofclip_event_handlers_.emplace_back(std::move(handler)); 62 | } 63 | 64 | virtual void ProcessControlEvent(GameInterface::ControlEvent event) override { 65 | for (auto i = control_event_handlers_.begin(); i != control_event_handlers_.end(); i++) 66 | (*i)(event); 67 | } 68 | 69 | virtual void ProcessPointEvent(const SDL2pp::Point& point) override { 70 | for (auto i = point_event_handlers_.rbegin(); i != point_event_handlers_.rend(); i++) 71 | (*i)(point); 72 | } 73 | 74 | virtual void ProcessEndOfClipEvent() override { 75 | for (auto i = endofclip_event_handlers_.rbegin(); i != endofclip_event_handlers_.rend(); i++) 76 | (*i)(); 77 | } 78 | 79 | void PushHandlerState() { 80 | handler_state_stack_.push_back({ 81 | control_event_handlers_.size(), 82 | point_event_handlers_.size(), 83 | endofclip_event_handlers_.size() 84 | }); 85 | } 86 | 87 | void PopHandlerState() { 88 | if (handler_state_stack_.empty()) 89 | throw std::runtime_error("event handler stack underflow"); 90 | 91 | control_event_handlers_.resize(handler_state_stack_.back().control_events); 92 | point_event_handlers_.resize(handler_state_stack_.back().point_events); 93 | endofclip_event_handlers_.resize(handler_state_stack_.back().endofclip_events); 94 | 95 | handler_state_stack_.pop_back(); 96 | } 97 | 98 | void ResetHandlers() { 99 | control_event_handlers_.clear(); 100 | point_event_handlers_.clear(); 101 | endofclip_event_handlers_.clear(); 102 | } 103 | }; 104 | 105 | #endif // GAMEEVENTLISTENER_HH 106 | -------------------------------------------------------------------------------- /gameinterface.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "gameinterface.hh" 24 | 25 | constexpr unsigned int GameInterface::Constants::ControlDelayMs; 26 | 27 | const GameInterface::ControlMap GameInterface::controls_ = { 28 | { GameInterface::Control::ANALYSIS, { GameInterface::Texture::FNHILITE, { 10, 101, 90, 18 }, { 0, 0, 90, 18 } } }, 29 | { GameInterface::Control::DIAGNOSTICS, { GameInterface::Texture::FNHILITE, { 39, 141, 80, 18 }, { 0, 19, 80, 18 } } }, 30 | { GameInterface::Control::YES, { GameInterface::Texture::FNHILITE, { 26, 181, 36, 16 }, { 0, 38, 36, 16 } } }, 31 | { GameInterface::Control::NO, { GameInterface::Texture::FNHILITE, { 74, 181, 25, 16 }, { 48, 38, 25, 16 } } }, 32 | { GameInterface::Control::STATUS, { GameInterface::Texture::FNHILITE, { 49, 214, 53, 16 }, { 0, 55, 53, 16 } } }, 33 | 34 | { GameInterface::Control::STARTUP, { GameInterface::Texture::FNHILITE, { 37, 276, 69, 19 }, { 0, 72, 69, 19 } } }, 35 | { GameInterface::Control::DEPLOY, { GameInterface::Texture::FNHILITE, { 43, 314, 57, 17 }, { 0, 92, 57, 17 } } }, 36 | { GameInterface::Control::GRAPPLE_ARM, { GameInterface::Texture::FNHILITE, { 34, 345, 90, 20 }, { 0, 110, 90, 20 } } }, 37 | { GameInterface::Control::FLOODLIGHT, { GameInterface::Texture::FNHILITE, { 35, 383, 75, 20 }, { 0, 151, 75, 20 } } }, 38 | 39 | { GameInterface::Control::WOUND, { GameInterface::Texture::FNHILITE, { 170, 0, 90, 51 }, { 0, 217, 90, 51 } } }, 40 | 41 | { GameInterface::Control::PATTERN_PREV, { GameInterface::Texture::MLHILITE, { 171, 326, 38, 33 }, { 1, 90, 38, 33 } } }, 42 | { GameInterface::Control::PATTERN_SEND, { GameInterface::Texture::MLHILITE, { 209, 334, 48, 25 }, { 40, 90, 48, 25 } } }, 43 | { GameInterface::Control::PATTERN_NEXT, { GameInterface::Texture::MLHILITE, { 257, 340, 42, 33 }, { 89, 90, 42, 33 } } }, 44 | 45 | { GameInterface::Control::COLORS_IR, { GameInterface::Texture::MLHILITE, { 408, 288, 38, 17 }, { 81, 1, 38, 17 } } }, 46 | { GameInterface::Control::COLORS_VIS, { GameInterface::Texture::MLHILITE, { 470, 285, 38, 19 }, { 41, 1, 38, 19 } } }, 47 | { GameInterface::Control::COLORS_UV, { GameInterface::Texture::MLHILITE, { 531, 283, 38, 19 }, { 1, 1, 38, 19 } } }, 48 | 49 | { GameInterface::Control::COLORS_1, { GameInterface::Texture::MLHILITE, { 402, 312, 22, 23 }, { 1, 21, 22, 23 } } }, 50 | { GameInterface::Control::COLORS_2, { GameInterface::Texture::MLHILITE, { 434, 311, 21, 23 }, { 25, 21, 21, 23 } } }, 51 | { GameInterface::Control::COLORS_3, { GameInterface::Texture::MLHILITE, { 462, 309, 22, 25 }, { 48, 21, 22, 25 } } }, 52 | { GameInterface::Control::COLORS_4, { GameInterface::Texture::MLHILITE, { 492, 308, 23, 25 }, { 72, 21, 23, 25 } } }, 53 | { GameInterface::Control::COLORS_5, { GameInterface::Texture::MLHILITE, { 522, 307, 23, 25 }, { 97, 21, 23, 25 } } }, 54 | { GameInterface::Control::COLORS_6, { GameInterface::Texture::MLHILITE, { 553, 307, 23, 25 }, { 122, 21, 23, 25 } } }, 55 | }; 56 | 57 | GameInterface::GameInterface(SDL2pp::Renderer& renderer, const DataManager& datamanager) 58 | : renderer_(renderer), 59 | background_(renderer, datamanager.GetPath("images/intrface.bmp")), 60 | fnhighlights_(renderer, datamanager.GetPath("images/fnhilite.rle")), 61 | mlhighlights_(renderer, datamanager.GetPath("images/mlhilite.bmp")), 62 | patterns_(renderer, datamanager.GetPath("images/patterns.bmp")), 63 | currently_activated_control_(GameInterface::Control::NONE), 64 | ui_enabled_(true), 65 | fullscreen_video_(false), 66 | colors_mode_(ColorsMode::VIS), 67 | selected_pattern_(-1), 68 | laser_enabled_(false), 69 | navigation_mask_(0), 70 | listener_(nullptr) { 71 | } 72 | 73 | GameInterface::~GameInterface() { 74 | } 75 | 76 | void GameInterface::Render(SDL2pp::Texture* video) { 77 | if (fullscreen_video_) { 78 | // fullscreen video is enabled, we only need to render it 79 | if (video) 80 | renderer_.Copy(*video, SDL2pp::NullOpt, SDL2pp::Rect(0, 0, 640, 480)); 81 | return; 82 | } else if (!ui_enabled_) { 83 | // fullscreen video is not enabled, but there's no UI (start 84 | // of the game): only render video in the center 85 | if (video) 86 | renderer_.Copy(*video, SDL2pp::NullOpt, SDL2pp::Rect(160, 120, 320, 240)); 87 | return; 88 | } 89 | 90 | renderer_.Copy(background_, SDL2pp::NullOpt, SDL2pp::Rect(0, 0, 640, 480)); 91 | 92 | // render currently active control 93 | ControlMap::const_iterator active_control_info = controls_.find(currently_activated_control_); 94 | if (active_control_info != controls_.end()) 95 | renderer_.Copy( 96 | (active_control_info->second.texture == Texture::MLHILITE) ? mlhighlights_ : fnhighlights_, 97 | active_control_info->second.source_rect, 98 | active_control_info->second.rect 99 | ); 100 | 101 | // render ir/vis/vis color bar 102 | switch (colors_mode_) { 103 | case ColorsMode::IR: 104 | renderer_.Copy(mlhighlights_, SDL2pp::Rect(1, 48, 176, 19), SDL2pp::Rect(404, 335, 176, 19)); 105 | break; 106 | case ColorsMode::UV: 107 | renderer_.Copy(mlhighlights_, SDL2pp::Rect(1, 69, 176, 19), SDL2pp::Rect(404, 335, 176, 19)); 108 | break; 109 | default: 110 | break; 111 | } 112 | 113 | // laser indicator 114 | if (laser_enabled_) 115 | renderer_.Copy(fnhighlights_, SDL2pp::Rect(0, 173, 55, 43), SDL2pp::Rect(28, 18, 55, 43)); 116 | 117 | // pattern 118 | if (selected_pattern_ >= 0) 119 | renderer_.Copy(patterns_, SDL2pp::Rect(0, selected_pattern_ * 36, 105, 36), SDL2pp::Rect(162, 412, 105, 36)); 120 | 121 | // video 122 | if (video) 123 | renderer_.Copy(*video, SDL2pp::NullOpt, SDL2pp::Rect(295, 16, 320, 240)); 124 | 125 | // navigation marks 126 | renderer_.SetDrawColor(104, 191, 136); 127 | if (navigation_mask_ & (int)NavMode::LEFT) { 128 | renderer_.DrawLine(298, 120, 298, 151); 129 | renderer_.DrawLine(298, 136, 304, 136); 130 | } 131 | if (navigation_mask_ & (int)NavMode::RIGHT) { 132 | renderer_.DrawLine(611, 120, 611, 151); 133 | renderer_.DrawLine(605, 136, 611, 136); 134 | } 135 | // TODO: top 136 | // TODO: bottom 137 | } 138 | 139 | void GameInterface::TryActivateControl(Control control) { 140 | if (currently_activated_control_ != Control::NONE) 141 | return; 142 | 143 | currently_activated_control_ = control; 144 | control_activation_time_ = SDL_GetTicks(); 145 | } 146 | 147 | void GameInterface::ProcessControlAction(Control control) { 148 | switch (control) { 149 | // Left button mapping 150 | case Control::ANALYSIS: EmitControlEvent(ControlEvent::ANALYSIS); break; 151 | case Control::DIAGNOSTICS: EmitControlEvent(ControlEvent::DIAGNOSTICS); break; 152 | case Control::YES: EmitControlEvent(ControlEvent::YES); break; 153 | case Control::NO: EmitControlEvent(ControlEvent::NO); break; 154 | case Control::STATUS: EmitControlEvent(ControlEvent::STATUS); break; 155 | 156 | case Control::STARTUP: EmitControlEvent(ControlEvent::STARTUP); break; 157 | case Control::DEPLOY: EmitControlEvent(ControlEvent::DEPLOY); break; 158 | case Control::GRAPPLE_ARM: EmitControlEvent(ControlEvent::GRAPPLE_ARM); break; 159 | case Control::FLOODLIGHT: EmitControlEvent(ControlEvent::FLOODLIGHT); break; 160 | 161 | // Color mode selection 162 | case Control::COLORS_IR: 163 | colors_mode_ = ColorsMode::IR; 164 | break; 165 | case Control::COLORS_VIS: 166 | colors_mode_ = ColorsMode::VIS; 167 | break; 168 | case Control::COLORS_UV: 169 | colors_mode_ = ColorsMode::UV; 170 | break; 171 | 172 | // Color buttons processing 173 | case Control::COLORS_1: case Control::COLORS_2: case Control::COLORS_3: 174 | case Control::COLORS_4: case Control::COLORS_5: case Control::COLORS_6: 175 | if (colors_mode_ == ColorsMode::IR) { 176 | EmitControlEvent(ControlEvent::INFRARED); 177 | } else if (colors_mode_ == ColorsMode::UV) { 178 | EmitControlEvent(ControlEvent::ULTRAVIOLET); 179 | } else switch (control) { 180 | case Control::COLORS_1: EmitControlEvent(ControlEvent::RED); break; 181 | case Control::COLORS_2: EmitControlEvent(ControlEvent::ORANGE); break; 182 | case Control::COLORS_3: EmitControlEvent(ControlEvent::YELLOW); break; 183 | case Control::COLORS_4: EmitControlEvent(ControlEvent::GREEN); break; 184 | case Control::COLORS_5: EmitControlEvent(ControlEvent::BLUE); break; 185 | case Control::COLORS_6: EmitControlEvent(ControlEvent::PURPLE); break; 186 | default: break; 187 | } 188 | break; 189 | default: break; 190 | } 191 | } 192 | 193 | void GameInterface::EmitControlEvent(GameInterface::ControlEvent event) { 194 | if (listener_) 195 | listener_->ProcessControlEvent(event); 196 | } 197 | 198 | void GameInterface::EmitPointEvent(const SDL2pp::Point& point) { 199 | if (listener_) 200 | listener_->ProcessPointEvent(point); 201 | } 202 | 203 | void GameInterface::Update(unsigned int ticks) { 204 | if (ticks > control_activation_time_ + GameInterface::Constants::ControlDelayMs) { 205 | ProcessControlAction(currently_activated_control_); 206 | currently_activated_control_ = Control::NONE; 207 | } 208 | } 209 | 210 | void GameInterface::ProcessEvent(const SDL_Event& event) { 211 | if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT) 212 | ProcessMouseDown(event.button); 213 | else if (event.type == SDL_KEYUP) 214 | ProcessKeyUp(event.key); 215 | } 216 | 217 | void GameInterface::ProcessKeyUp(const SDL_KeyboardEvent& key) { 218 | if (!ui_enabled_) 219 | return; 220 | 221 | if (key.keysym.mod == KMOD_NONE) { 222 | switch (key.keysym.sym) { 223 | case SDLK_a: TryActivateControl(Control::ANALYSIS); break; 224 | case SDLK_d: TryActivateControl(Control::DIAGNOSTICS); break; 225 | case SDLK_y: TryActivateControl(Control::YES); break; 226 | case SDLK_n: TryActivateControl(Control::NO); break; 227 | case SDLK_t: TryActivateControl(Control::STATUS); break; 228 | case SDLK_s: TryActivateControl(Control::STARTUP); break; 229 | case SDLK_p: TryActivateControl(Control::DEPLOY); break; 230 | case SDLK_g: TryActivateControl(Control::GRAPPLE_ARM); break; 231 | case SDLK_f: TryActivateControl(Control::FLOODLIGHT); break; 232 | case SDLK_SPACE: fullscreen_video_ = !fullscreen_video_; break; 233 | default: break; 234 | } 235 | } else if (key.keysym.mod == KMOD_LCTRL || key.keysym.mod == KMOD_RCTRL) { 236 | switch (key.keysym.sym) { 237 | case SDLK_i: // TODO: infrared // XXX: not used in the game, may ignore 238 | case SDLK_r: // TODO: red 239 | case SDLK_o: // TODO: orange 240 | case SDLK_y: // TODO: yellow 241 | case SDLK_g: // TODO: green 242 | case SDLK_b: // TODO: blue 243 | case SDLK_p: // TODO: purple 244 | case SDLK_u: // TODO: ultraviolet // XXX: not used in the game, may ignore 245 | default: break; 246 | } 247 | } 248 | } 249 | 250 | void GameInterface::ProcessMouseDown(const SDL_MouseButtonEvent& button) { 251 | if (!ui_enabled_) 252 | return; 253 | 254 | if (!fullscreen_video_) 255 | for (auto& control : controls_) 256 | if (control.second.rect.Contains(SDL2pp::Point(button.x, button.y))) 257 | TryActivateControl(control.first); 258 | 259 | SDL2pp::Point target(0, 0); 260 | if (fullscreen_video_) { 261 | target.SetX(button.x / 2); 262 | target.SetY(button.y / 2); 263 | } else { 264 | target.SetX(button.x - 295); 265 | target.SetY(button.y - 16); 266 | } 267 | 268 | if (target.GetX() >= 0 && target.GetY() >= 0 && target.GetX() < 320 && target.GetY() < 240) 269 | EmitPointEvent(target); 270 | } 271 | 272 | void GameInterface::SetListener(GameInterface::EventListener* listener) { 273 | listener_ = listener; 274 | } 275 | 276 | void GameInterface::EnableLaserMode() { 277 | laser_enabled_ = true; 278 | } 279 | 280 | void GameInterface::EnableNavigationMode(int navigation_mask) { 281 | navigation_mask_ = navigation_mask; 282 | } 283 | 284 | void GameInterface::ResetMode() { 285 | laser_enabled_ = false; 286 | navigation_mask_ = 0; 287 | } 288 | -------------------------------------------------------------------------------- /gameinterface.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef GAMEINTERFACE_HH 21 | #define GAMEINTERFACE_HH 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include "datamanager.hh" 31 | 32 | class GameInterface { 33 | public: 34 | enum class ControlEvent { 35 | ANALYSIS, 36 | DIAGNOSTICS, 37 | YES, 38 | NO, 39 | STATUS, 40 | 41 | STARTUP, 42 | DEPLOY, 43 | GRAPPLE_ARM, 44 | FLOODLIGHT, 45 | 46 | INFRARED, 47 | 48 | RED, 49 | ORANGE, 50 | YELLOW, 51 | GREEN, 52 | BLUE, 53 | PURPLE, 54 | 55 | ULTRAVIOLET, 56 | }; 57 | 58 | class EventListener { 59 | public: 60 | virtual ~EventListener() { 61 | } 62 | 63 | virtual void ProcessControlEvent(ControlEvent) { 64 | } 65 | 66 | virtual void ProcessPointEvent(const SDL2pp::Point&) { 67 | } 68 | }; 69 | 70 | protected: 71 | enum class Control { 72 | NONE, 73 | 74 | ANALYSIS, 75 | DIAGNOSTICS, 76 | YES, 77 | NO, 78 | STATUS, 79 | 80 | STARTUP, 81 | DEPLOY, 82 | GRAPPLE_ARM, 83 | FLOODLIGHT, 84 | 85 | WOUND, 86 | 87 | PATTERN_PREV, 88 | PATTERN_SEND, 89 | PATTERN_NEXT, 90 | 91 | COLORS_IR, 92 | COLORS_VIS, 93 | COLORS_UV, 94 | 95 | COLORS_1, 96 | COLORS_2, 97 | COLORS_3, 98 | COLORS_4, 99 | COLORS_5, 100 | COLORS_6, 101 | }; 102 | 103 | protected: 104 | struct Constants { 105 | static constexpr unsigned int ControlDelayMs = 500; 106 | }; 107 | 108 | enum class Texture { 109 | FNHILITE, 110 | MLHILITE, 111 | }; 112 | 113 | enum class ColorsMode { 114 | IR, 115 | VIS, 116 | UV, 117 | }; 118 | 119 | enum class NavMode { 120 | LEFT = 0x1, 121 | RIGHT = 0x2, 122 | UP = 0x4, 123 | DOWN = 0x8, 124 | }; 125 | 126 | struct ControlInfo { 127 | Texture texture; 128 | SDL2pp::Rect rect; 129 | SDL2pp::Rect source_rect; 130 | }; 131 | 132 | typedef std::map ControlMap; 133 | 134 | typedef std::map> ControlHandlerMap; 135 | 136 | protected: 137 | static const ControlMap controls_; 138 | 139 | protected: 140 | SDL2pp::Renderer& renderer_; 141 | 142 | // Textures 143 | SDL2pp::Texture background_; 144 | SDL2pp::Texture fnhighlights_; 145 | SDL2pp::Texture mlhighlights_; 146 | SDL2pp::Texture patterns_; 147 | 148 | // Click processing 149 | Control currently_activated_control_; 150 | unsigned int control_activation_time_; 151 | 152 | bool ui_enabled_; 153 | bool fullscreen_video_; 154 | ColorsMode colors_mode_; 155 | int selected_pattern_; 156 | bool laser_enabled_; 157 | int navigation_mask_; 158 | 159 | EventListener* listener_; 160 | 161 | protected: 162 | void TryActivateControl(Control control); 163 | void ProcessControlAction(Control control); 164 | 165 | void EmitControlEvent(ControlEvent event); 166 | void EmitPointEvent(const SDL2pp::Point& point); 167 | 168 | public: 169 | GameInterface(SDL2pp::Renderer& renderer, const DataManager& datamanager); 170 | ~GameInterface(); 171 | 172 | void ProcessEvent(const SDL_Event& event); 173 | void ProcessMouseDown(const SDL_MouseButtonEvent& button); 174 | void ProcessKeyUp(const SDL_KeyboardEvent& key); 175 | void Update(unsigned int ticks); 176 | void Render(SDL2pp::Texture* video); 177 | 178 | void SetListener(EventListener* listener); 179 | 180 | void EnableLaserMode(); 181 | void EnableNavigationMode(int navmask); 182 | void ResetMode(); 183 | }; 184 | 185 | #endif // GAMEINTERFACE_HH 186 | -------------------------------------------------------------------------------- /hexagonspuzzle.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | 24 | #include "hexagonspuzzle.hh" 25 | 26 | #include "datamanager.hh" 27 | #include "logger.hh" 28 | 29 | // TODO: spinner lights around level indicators are missing 30 | // TODO: solve animation 31 | // TODO: sounds 32 | // TODO: difficilty levels 33 | 34 | // pieces are numbered clockwise from top right 35 | const std::array HexagonsPuzzle::piece_locations_ = { { 36 | { 328, 111 }, 37 | { 382, 202 }, 38 | // those two are not really a piece location (one from puz2piec.bmp) 39 | // but a tweak for lines, which are offset from hexagon by 2 pixels 40 | { 328, 293 + 2 }, 41 | { 229, 293 + 2 }, 42 | { 177, 202 }, 43 | { 229, 111 }, 44 | { 281, 202 }, 45 | } }; 46 | 47 | // vertices are numbered clockwise from top one 48 | const std::array HexagonsPuzzle::vertex_coords_ = { { 49 | { 39, 2 }, 50 | { 71, 20 }, 51 | { 71, 57 }, 52 | { 39, 75 }, 53 | { 7, 57 }, 54 | { 7, 20 }, 55 | } }; 56 | 57 | const std::array HexagonsPuzzle::level_locations_ = { { 58 | { 407, 16 }, 59 | { 521, 212 }, 60 | { 408, 409 }, 61 | { 180, 409 }, 62 | { 67, 214 }, 63 | { 179, 16 }, 64 | } }; 65 | 66 | // this is level data: 67 | // array of per-level 68 | // array of per-hexagon 69 | // vector of vertex number pairs 70 | // each pair represents one line on a hexagon 71 | const std::array, 6> HexagonsPuzzle::level_hex_lines_ = { { 72 | // level 0 73 | { { 74 | { }, 75 | { { 5, 0 } }, 76 | { { 5, 0 }, { 4, 0 } }, 77 | { { 5, 0 }, { 4, 0 }, { 3, 0 } }, 78 | { { 5, 0 }, { 4, 0 }, { 3, 0 }, { 2, 0 } }, 79 | { { 5, 0 }, { 4, 0 }, { 3, 0 }, { 2, 0 }, { 1, 0 } }, 80 | } }, 81 | // level 1 82 | { { 83 | { { 4, 5 }, { 5, 0 }, { 4, 0 }, { 3, 0 } }, 84 | { { 4, 5 }, { 5, 0 }, { 4, 0 }, { 2, 5 } }, 85 | { { 4, 5 }, { 5, 0 }, { 4, 0 }, { 1, 4 } }, 86 | { { 4, 5 }, { 5, 0 }, { 4, 0 } }, 87 | { { 4, 5 }, { 5, 0 }, { 4, 0 } }, 88 | { { 4, 5 }, { 5, 0 }, { 4, 0 } }, 89 | } }, 90 | // level 2 91 | { { 92 | { { 5, 1 }, { 1, 4 }, { 4, 5 } }, 93 | { { 5, 1 }, { 1, 4 }, { 4, 5 } }, 94 | { { 5, 1 }, { 1, 4 }, { 4, 5 } }, 95 | { { 5, 1 }, { 1, 4 }, { 4, 5 } }, 96 | { { 5, 1 }, { 1, 4 }, { 4, 5 } }, 97 | { { 5, 1 }, { 1, 4 }, { 4, 5 } }, 98 | } }, 99 | // level 3 100 | { { 101 | { { 0, 1 } }, 102 | { { 0, 1 }, { 1, 3 }, { 3, 5 }, { 5, 1 } }, 103 | { { 0, 1 } }, 104 | { { 0, 1 }, { 1, 3 }, { 3, 5 }, { 5, 1 } }, 105 | { { 0, 1 } }, 106 | { { 0, 1 }, { 0, 3 }, { 1, 4 }, { 2, 5 } }, 107 | } }, 108 | // level 4 109 | { { 110 | { { 0, 2 }, { 2, 4 }, { 4, 0 } }, 111 | { { 0, 3 }, { 2, 5 } }, 112 | { { 1, 2 }, { 4, 5 }, { 5, 0 } }, 113 | { { 0, 2 }, { 2, 4 }, { 4, 0 } }, 114 | { { 0, 3 } }, 115 | { { 2, 3 }, { 4, 5 }, { 5, 0 } }, 116 | } }, 117 | // level 5 118 | { { 119 | { { 5, 2 }, { 2, 4 }, { 4, 5 } }, 120 | { { 5, 2 }, { 2, 4 }, { 4, 5 } }, 121 | { { 5, 0 }, { 0, 1 }, { 1, 5 } }, 122 | { { 0, 2 }, { 2, 4 }, { 4, 0 } }, 123 | { { 1, 2 }, { 2, 4 }, { 4, 1 } }, 124 | { { 1, 2 }, { 2, 4 }, { 4, 1 } }, 125 | } }, 126 | } }; 127 | 128 | void HexagonsPuzzle::SetupLevel(int level) { 129 | level_ = level; 130 | last_touched_piece_ = -1; 131 | 132 | hex_lines_ = level_hex_lines_[level]; 133 | 134 | RecalculateSummary(); 135 | } 136 | 137 | void HexagonsPuzzle::ThickLine(const SDL2pp::Point& v1, const SDL2pp::Point& v2) { 138 | renderer_.DrawLine(v1, v2); 139 | renderer_.DrawLine(v1 + SDL2pp::Point(1, 0), v2 + SDL2pp::Point(1, 0)); 140 | renderer_.DrawLine(v1 + SDL2pp::Point(0, 1), v2 + SDL2pp::Point(0, 1)); 141 | renderer_.DrawLine(v1 + SDL2pp::Point(1, 1), v2 + SDL2pp::Point(1, 1)); 142 | } 143 | 144 | void HexagonsPuzzle::RecalculateSummary() { 145 | all_lines_.clear(); 146 | last_touched_lines_.clear(); 147 | 148 | for (int p = 0; p < 6; p++) { 149 | for (auto& line : hex_lines_[p]) { 150 | all_lines_.insert(std::make_pair(std::min(line.first, line.second), std::max(line.first, line.second))); 151 | if (last_touched_piece_ == p) 152 | last_touched_lines_.insert(std::make_pair(std::min(line.first, line.second), std::max(line.first, line.second))); 153 | } 154 | } 155 | } 156 | 157 | HexagonsPuzzle::HexagonsPuzzle(SDL2pp::Renderer& renderer, const DataManager& datamanager) 158 | : renderer_(renderer), 159 | background_(renderer, datamanager.GetPath("images/plaphex/puzz2bg.bmp")), 160 | levels_(renderer, datamanager.GetPath("images/plaphex/puz2goal.bmp")), 161 | levels_hl_(renderer, datamanager.GetPath("images/plaphex/puz2glhl.bmp")), 162 | pieces_(renderer, datamanager.GetPath("images/plaphex/puz2peic.bmp")), 163 | chaser_(renderer, datamanager.GetPath("images/plaphex/chaser.rle")) { 164 | Log("puzzle") << "starting hexagons puzzle"; 165 | 166 | SetupLevel(0); 167 | } 168 | 169 | HexagonsPuzzle::~HexagonsPuzzle() { 170 | } 171 | 172 | bool HexagonsPuzzle::ProcessEvent(const SDL_Event& event) { 173 | if (event.type == SDL_MOUSEBUTTONDOWN) { 174 | int npiece = -1; 175 | for (auto pieceloc = piece_locations_.begin(); pieceloc != piece_locations_.end(); pieceloc++) { 176 | if (!SDL2pp::Rect(pieceloc->x, pieceloc->y, 80, 80).Contains(SDL2pp::Point(event.button.x, event.button.y))) 177 | continue; 178 | 179 | npiece = pieceloc - piece_locations_.begin(); 180 | break; 181 | } 182 | 183 | if (npiece < 0 || npiece > 5) 184 | return true; 185 | 186 | for (auto& line : hex_lines_[npiece]) { 187 | line.first = (line.first + 1) % 6; 188 | line.second = (line.second + 1) % 6; 189 | } 190 | 191 | last_touched_piece_ = npiece; 192 | 193 | RecalculateSummary(); 194 | 195 | if (all_lines_.size() == 15) { // all lines filled in central hexagon 196 | // XXX: support difficulty levels here 197 | if (level_ == 5) { 198 | Log("puzzle") << " congrats, puzzle is solved"; 199 | return false; 200 | } else { 201 | Log("puzzle") << " congrats, level solved"; 202 | SetupLevel(level_ + 1); 203 | } 204 | } 205 | } 206 | 207 | return true; 208 | } 209 | 210 | bool HexagonsPuzzle::Update() { 211 | return true; 212 | } 213 | 214 | void HexagonsPuzzle::Render() { 215 | // background 216 | renderer_.Copy(background_, SDL2pp::NullOpt, SDL2pp::Rect(0, 0, 640, 480)); 217 | 218 | // level indicator 219 | for (int i = 0; i < level_; i++) { 220 | renderer_.Copy( 221 | levels_, 222 | SDL2pp::Rect(52 * i, 0, 52, 52), 223 | SDL2pp::Rect(level_locations_[i].x, level_locations_[i].y, 52, 52) 224 | ); 225 | } 226 | 227 | // pieces 228 | renderer_.SetDrawColor(0, 255, 0); 229 | for (int p = 0; p < 6; p++) { 230 | for (auto& line : hex_lines_[p]) { 231 | SDL2pp::Point v1 = piece_locations_[p] + vertex_coords_[line.first]; 232 | SDL2pp::Point v2 = piece_locations_[p] + vertex_coords_[line.second]; 233 | 234 | ThickLine(v1, v2); 235 | } 236 | } 237 | 238 | // central piece 239 | for (auto& line : all_lines_) { 240 | SDL2pp::Point v1 = piece_locations_[6] + vertex_coords_[line.first]; 241 | SDL2pp::Point v2 = piece_locations_[6] + vertex_coords_[line.second]; 242 | 243 | ThickLine(v1, v2); 244 | } 245 | 246 | // last touched piece, should overpaint other lines 247 | renderer_.SetDrawColor(255, 0, 0); 248 | 249 | for (auto& line : last_touched_lines_) { 250 | SDL2pp::Point v1 = piece_locations_[6] + vertex_coords_[line.first]; 251 | SDL2pp::Point v2 = piece_locations_[6] + vertex_coords_[line.second]; 252 | 253 | ThickLine(v1, v2); 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /hexagonspuzzle.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef HEXAGONSPUZZLE_HH 21 | #define HEXAGONSPUZZLE_HH 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include "screen.hh" 31 | 32 | class DataManager; 33 | 34 | class HexagonsPuzzle : public Screen { 35 | private: 36 | typedef std::pair LineDesc; 37 | typedef std::vector LineSet; 38 | 39 | private: 40 | static const std::array piece_locations_; 41 | static const std::array vertex_coords_; 42 | static const std::array level_locations_; 43 | 44 | static const std::array, 6> level_hex_lines_; 45 | 46 | private: 47 | SDL2pp::Renderer& renderer_; 48 | 49 | // Textures 50 | SDL2pp::Texture background_; 51 | SDL2pp::Texture levels_; 52 | SDL2pp::Texture levels_hl_; 53 | SDL2pp::Texture pieces_; 54 | SDL2pp::Texture chaser_; 55 | 56 | private: 57 | int level_; 58 | int last_touched_piece_; 59 | 60 | std::array hex_lines_; 61 | 62 | std::set last_touched_lines_; 63 | std::set all_lines_; 64 | 65 | private: 66 | void ThickLine(const SDL2pp::Point& v1, const SDL2pp::Point& v2); 67 | void SetupLevel(int level); 68 | void RecalculateSummary(); 69 | 70 | public: 71 | HexagonsPuzzle(SDL2pp::Renderer& renderer, const DataManager& datamanager); 72 | virtual ~HexagonsPuzzle(); 73 | 74 | bool ProcessEvent(const SDL_Event& event) override; 75 | bool Update() override; 76 | void Render() override; 77 | }; 78 | 79 | #endif // HEXAGONSPUZZLE_HH 80 | -------------------------------------------------------------------------------- /hotfile.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "hotfile.hh" 24 | 25 | HotFile::HotFile(const std::string& path) { 26 | std::ifstream stream(path, std::ios_base::in); 27 | stream.exceptions(std::ifstream::badbit); 28 | 29 | while (!stream.eof()) { 30 | int frameno; 31 | stream >> frameno; 32 | 33 | if (stream.fail()) 34 | break; 35 | 36 | RectVector rects; 37 | for (int i = 0; i < 8; i++) { 38 | int x1, y1, x2, y2; 39 | 40 | stream >> x1 >> y1 >> x2 >> y2; 41 | 42 | if (stream.fail()) 43 | break; 44 | 45 | if (x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0) 46 | rects.emplace_back(x1, y1, x2 - x1, y2 - y1); 47 | } 48 | 49 | entries_.emplace(std::make_pair(frameno, std::move(rects))); 50 | } 51 | } 52 | 53 | HotFile::~HotFile() { 54 | } 55 | 56 | const HotFile::RectVector& HotFile::GetRectsForFrame(int frame) const { 57 | EntryMap::const_iterator entry = entries_.find(frame); 58 | if (entry == entries_.end()) 59 | throw std::runtime_error("no hotspots for requested frame"); 60 | return entry->second; 61 | } 62 | -------------------------------------------------------------------------------- /hotfile.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef HOTFILE_HH 21 | #define HOTFILE_HH 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | class HotFile { 30 | public: 31 | typedef std::vector RectVector; 32 | 33 | protected: 34 | typedef std::map EntryMap; 35 | 36 | protected: 37 | EntryMap entries_; 38 | 39 | public: 40 | HotFile(const std::string& path); 41 | ~HotFile(); 42 | 43 | const RectVector& GetRectsForFrame(int frame) const; 44 | }; 45 | 46 | #endif // HOTFILE_HH 47 | -------------------------------------------------------------------------------- /interpreter.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "logger.hh" 24 | 25 | #include "datamanager.hh" 26 | #include "movplayer.hh" 27 | #include "gameinterface.hh" 28 | #include "hotfile.hh" 29 | 30 | #include "interpreter.hh" 31 | 32 | namespace { 33 | 34 | static GameInterface::ControlEvent ConditionToEvent(int cond) { 35 | switch (cond) { 36 | case (int)NodFile::Condition::YES: return GameInterface::ControlEvent::YES; 37 | case (int)NodFile::Condition::NO: return GameInterface::ControlEvent::NO; 38 | case (int)NodFile::Condition::STARTUP: return GameInterface::ControlEvent::STARTUP; 39 | case (int)NodFile::Condition::DIAGNOSTICS: return GameInterface::ControlEvent::DIAGNOSTICS; 40 | case (int)NodFile::Condition::DEPLOY: return GameInterface::ControlEvent::DEPLOY; 41 | case (int)NodFile::Condition::ANALYSIS: return GameInterface::ControlEvent::ANALYSIS; 42 | case (int)NodFile::Condition::FLOODLIGHT: return GameInterface::ControlEvent::FLOODLIGHT; 43 | default: 44 | throw std::logic_error("condition type not implemented"); 45 | } 46 | } 47 | 48 | } 49 | 50 | Interpreter::Interpreter(const DataManager& data_manager, GameInterface& interface, MovPlayer& player, const std::string& startnod, int startentry) : data_manager_(data_manager), interface_(interface), player_(player), awaiting_event_(false) { 51 | std::list loading_queue; 52 | loading_queue.push_back(startnod); 53 | 54 | while (!loading_queue.empty()) { 55 | Log("interp") << "loading script " << loading_queue.front(); 56 | NodFileMap::iterator just_added = nod_files_.emplace(loading_queue.front(), data_manager.GetPath(loading_queue.front())).first; 57 | 58 | // collect all .nod files referenced by recently 59 | // loaded one which were not yet visited 60 | just_added->second.ForEach([this, &loading_queue](const NodFile::Entry& e) { 61 | std::string file = e.GetName(); 62 | std::transform(file.begin(), file.end(), file.begin(), ::tolower); 63 | if (file.rfind(".nod") == file.length() - 4 && file != "gate.nod" && nod_files_.find(file) == nod_files_.end()) 64 | loading_queue.push_back(file); 65 | }); 66 | 67 | loading_queue.pop_front(); 68 | } 69 | 70 | current_node_ = std::make_pair(startnod, startentry); 71 | 72 | interface_.SetListener(this); 73 | player_.SetListener(this); 74 | } 75 | 76 | Interpreter::~Interpreter() { 77 | interface_.SetListener(nullptr); 78 | player_.SetListener(nullptr); 79 | } 80 | 81 | void Interpreter::InterruptAndGoto(int offset) { 82 | if (!awaiting_event_) 83 | return; 84 | 85 | Log("interp") << "interrupt received"; 86 | 87 | player_.Stop(); 88 | 89 | current_node_.second += offset; 90 | awaiting_event_ = false; 91 | } 92 | 93 | void Interpreter::Update() { 94 | if (awaiting_event_) 95 | return; 96 | 97 | while (1) { 98 | ResetHandlers(); 99 | interface_.ResetMode(); 100 | 101 | NodFileMap::const_iterator nodfile = nod_files_.find(current_node_.first); 102 | if (nodfile == nod_files_.end()) 103 | throw std::logic_error("nod file not found"); // shouldn't happend as all files are preloaded in constructor 104 | const NodFile::Entry* current_entry = &nodfile->second.GetEntry(current_node_.second); 105 | Log("interp") << "interpreting entry " << current_node_.second << " from " << current_node_.first << ": type=" << current_entry->GetType(); 106 | switch (current_entry->GetType()) { 107 | case 0: // death 108 | { 109 | Log("interp") << " death: should exit to menu here, but it's not implemented yet"; 110 | throw std::logic_error("death not implemented"); 111 | } 112 | case 1: // no-op, mostly used by "gate" entries 113 | { 114 | Log("interp") << " nop, skipping"; 115 | current_node_.second += current_entry->GetDefaultOffset(); 116 | break; 117 | } 118 | case 2: // simple "play movie" command 119 | case 61: // play movie with analysis as result? 120 | { 121 | // save frame limits on player actions 122 | // e.g. int a 20 second movie, the game will accept player 123 | // input only between 10 and 18 seconds 124 | int actionstartframe = current_entry->GetActionStartFrame(); 125 | int actionendframe = current_entry->GetActionEndFrame(); 126 | 127 | // install event handlers for this scene 128 | for (auto& condition : current_entry->GetConditions()) { 129 | Log("interp") << " installing interface control handler: condition=" << condition.first; 130 | AddControlEventHandler([=](GameInterface::ControlEvent event){ 131 | if (event == ConditionToEvent(condition.first) && 132 | player_.GetCurrentFrame() >= actionstartframe && 133 | player_.GetCurrentFrame() <= actionendframe) 134 | InterruptAndGoto(condition.second); 135 | }); 136 | } 137 | 138 | // install end of clip handler for this scene 139 | int offset = current_entry->GetDefaultOffset(); 140 | AddEndOfClipEventHandler([=](){ 141 | InterruptAndGoto(offset); 142 | }); 143 | 144 | // play movie 145 | Log("interp") << " playing a movie"; 146 | player_.Play( 147 | data_manager_.GetPath(current_entry->GetName()), 148 | current_entry->GetStartFrame(), 149 | current_entry->GetEndFrame() 150 | ); 151 | 152 | // yield 153 | awaiting_event_ = true; 154 | return; 155 | } 156 | case 3: 157 | { 158 | // install event handlers for this scene 159 | for (auto& condition : current_entry->GetConditions()) { 160 | Log("interp") << " installing interface control handler: condition=" << condition.first; 161 | AddControlEventHandler([=](GameInterface::ControlEvent event){ 162 | if (event == ConditionToEvent(condition.first)) 163 | InterruptAndGoto(condition.second); 164 | }); 165 | } 166 | 167 | // check if we have a hot zone (is this correct?) 168 | std::string hotname = current_entry->GetName(); 169 | hotname.replace(hotname.length() - 3, std::string::npos, "hot"); 170 | if (data_manager_.HasPath(hotname)) { 171 | Log("interp") << " found hotzone " << hotname; 172 | HotFile hot(data_manager_.GetPath(hotname)); 173 | 174 | std::vector offsets_for_rect; 175 | 176 | for (int i = 0; i < 8; i++) 177 | offsets_for_rect.push_back(current_entry->GetCondition(i).second); 178 | 179 | AddPointEventHandler([=](const SDL2pp::Point& point) { 180 | int nrect = 0; 181 | for (auto& rect: hot.GetRectsForFrame(player_.GetCurrentFrame())) { 182 | if (rect.Contains(point)) { 183 | InterruptAndGoto(offsets_for_rect[nrect]); 184 | return; 185 | } 186 | nrect++; 187 | } 188 | }); 189 | 190 | interface_.EnableLaserMode(); 191 | } 192 | 193 | // play our single frame 194 | Log("interp") << " playing a single frame: "; 195 | player_.PlaySingleFrame( 196 | data_manager_.GetPath(current_entry->GetName()), 197 | current_entry->GetStartFrame() 198 | ); 199 | 200 | // yield 201 | awaiting_event_ = true; 202 | return; 203 | } 204 | case 5: 205 | { 206 | Log("interp") << " enable user interface (not implemented yet)"; 207 | current_node_.second += current_entry->GetDefaultOffset(); 208 | break; 209 | } 210 | case 30: 211 | { 212 | Log("interp") << " something hotzone-related, skipping"; 213 | current_node_.second += current_entry->GetDefaultOffset(); 214 | break; 215 | } 216 | case 33: 217 | { 218 | Log("interp") << " unknown, skipping"; 219 | current_node_.second += current_entry->GetDefaultOffset(); 220 | break; 221 | } 222 | default: 223 | throw std::logic_error("node type processing not implemented"); 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /interpreter.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef INTERPRETER_HH 21 | #define INTERPRETER_HH 22 | 23 | #include 24 | 25 | #include "nodfile.hh" 26 | #include "gameeventlistener.hh" 27 | 28 | class DataManager; 29 | class GameInterface; 30 | class MovPlayer; 31 | 32 | class Interpreter : private GameEventListener { 33 | protected: 34 | typedef std::map NodFileMap; 35 | typedef std::pair NodPointer; 36 | 37 | protected: 38 | NodFileMap nod_files_; 39 | 40 | const DataManager& data_manager_; 41 | GameInterface& interface_; 42 | MovPlayer& player_; 43 | 44 | NodPointer current_node_; 45 | 46 | bool awaiting_event_; 47 | 48 | protected: 49 | void InterruptAndGoto(int offset); 50 | 51 | public: 52 | Interpreter(const DataManager& data_manager, GameInterface& interface, MovPlayer& player, const std::string& startnod, int numentry = 0); 53 | virtual ~Interpreter(); 54 | 55 | void Update(); 56 | }; 57 | 58 | #endif // INTERPRETER_HH 59 | -------------------------------------------------------------------------------- /logger.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef LOGGER_HH 21 | #define LOGGER_HH 22 | 23 | #ifdef NDEBUG 24 | 25 | class Log { 26 | public: 27 | Log(const char*) { 28 | } 29 | 30 | template 31 | Log& operator<<(const T& t) { 32 | return *this; 33 | } 34 | }; 35 | 36 | #else 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | class Log { 43 | private: 44 | const char* ident_; 45 | std::stringstream stream_; 46 | 47 | public: 48 | Log(const char* ident) : ident_(ident) { 49 | } 50 | 51 | ~Log() { 52 | try { 53 | std::cerr << "[" << std::setw(8) << ident_ << "] " << stream_.str() << std::endl; 54 | } catch (...) { 55 | } 56 | } 57 | 58 | template 59 | Log& operator<<(const T& t) { 60 | stream_ << t; 61 | return *this; 62 | } 63 | }; 64 | 65 | #endif 66 | 67 | #endif // LOGGER_HH 68 | -------------------------------------------------------------------------------- /main.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2015 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "datamanager.hh" 34 | #include "gameinterface.hh" 35 | #include "interpreter.hh" 36 | #include "movplayer.hh" 37 | #include "screen.hh" 38 | 39 | #include "artemispuzzle.hh" 40 | #include "hexagonspuzzle.hh" 41 | #include "sunpuzzle.hh" 42 | 43 | void usage(const char* progname) { 44 | std::cerr << "Usage: " << progname << " [ -n ] [ -e ] [ -p ] -d " << std::endl; 45 | } 46 | 47 | int realmain(int argc, char** argv) { 48 | const char* progname = argv[0]; 49 | 50 | const char* datapath = nullptr; 51 | const char* startnod = "encountr.nod"; 52 | int startentry = 2; 53 | 54 | std::string puzzle; 55 | 56 | int ch; 57 | while ((ch = getopt(argc, argv, "d:n:e:p:h")) != -1) { 58 | switch (ch) { 59 | case 'd': 60 | datapath = optarg; 61 | break; 62 | case 'n': 63 | startnod = optarg; 64 | startentry = 0; 65 | break; 66 | case 'e': 67 | startentry = std::stoi(optarg); 68 | break; 69 | case 'p': 70 | puzzle = optarg; 71 | break; 72 | case 'h': 73 | usage(progname); 74 | return 0; 75 | default: 76 | usage(progname); 77 | return 1; 78 | } 79 | } 80 | 81 | if (datapath == nullptr) { 82 | usage(progname); 83 | return 1; 84 | } 85 | 86 | // Data manager 87 | DataManager data_manager; 88 | data_manager.ScanDir(datapath); 89 | 90 | // SDL stuff 91 | SDL2pp::SDL sdl(SDL_INIT_VIDEO | SDL_INIT_AUDIO); 92 | SDL2pp::Window window("OpenDaed", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_RESIZABLE); 93 | SDL2pp::Renderer renderer(window, -1, SDL_RENDERER_ACCELERATED); 94 | 95 | GameInterface interface(renderer, data_manager); 96 | MovPlayer player; 97 | 98 | // Script interpreter 99 | Interpreter script(data_manager, interface, player, startnod, startentry); 100 | 101 | // Screens that replace interface such as puzzles 102 | std::unique_ptr screen; 103 | 104 | if (puzzle == "artemis") 105 | screen.reset(new ArtemisPuzzle(renderer, data_manager)); 106 | else if (puzzle == "hexagons") 107 | screen.reset(new HexagonsPuzzle(renderer, data_manager)); 108 | else if (puzzle == "sun") 109 | screen.reset(new SunPuzzle(renderer, data_manager)); 110 | 111 | while (1) { 112 | unsigned int frame_ticks = SDL_GetTicks(); 113 | 114 | // Process events 115 | SDL_Event event; 116 | while (SDL_PollEvent(&event)) { 117 | if (event.type == SDL_QUIT) { 118 | return 0; 119 | } else if (event.type == SDL_KEYDOWN) { 120 | switch (event.key.keysym.sym) { 121 | case SDLK_ESCAPE: case SDLK_q: 122 | return 0; 123 | } 124 | } 125 | 126 | if (screen) { 127 | if (!screen->ProcessEvent(event)) 128 | return 0; 129 | 130 | } else { 131 | interface.ProcessEvent(event); 132 | } 133 | } 134 | 135 | // Update logic 136 | if (screen) { 137 | if (!screen->Update()) 138 | return 0; 139 | } else { 140 | interface.Update(frame_ticks); 141 | script.Update(); 142 | player.UpdateFrame(renderer); 143 | } 144 | 145 | // Render 146 | renderer.SetDrawColor(0, 0, 0); 147 | renderer.Clear(); 148 | 149 | if (screen) 150 | screen->Render(); 151 | else 152 | interface.Render(player.GetTexture()); 153 | 154 | renderer.Present(); 155 | 156 | // Frame limiter 157 | SDL_Delay(1); 158 | } 159 | 160 | return 0; 161 | } 162 | 163 | int main(int argc, char** argv) { 164 | try { 165 | return realmain(argc, argv); 166 | } catch (SDL2pp::Exception& e) { 167 | std::cerr << "Error: " << e.what() << " (" << e.GetSDLError() << ")" << std::endl; 168 | } catch (std::exception& e) { 169 | std::cerr << "Error: " << e.what() << std::endl; 170 | } 171 | 172 | return 1; 173 | } 174 | 175 | -------------------------------------------------------------------------------- /movplayer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "logger.hh" 28 | 29 | #include "movplayer.hh" 30 | 31 | MovPlayer::MovPlayer() : state_(STOPPED), listener_(nullptr) { 32 | } 33 | 34 | MovPlayer::~MovPlayer() { 35 | } 36 | 37 | void MovPlayer::SetListener(MovPlayer::EventListener* listener) { 38 | listener_ = listener; 39 | } 40 | 41 | void MovPlayer::UpdateMovieFile(const std::string& filename, bool need_audio) { 42 | has_audio_ = false; 43 | if (filename != current_file_ || qt_.get() == nullptr) { 44 | // open new qt video 45 | qt_.reset(new QuickTime(filename)); 46 | 47 | if (!qt_->HasVideo()) 48 | throw std::runtime_error("no video track"); 49 | 50 | if (!qt_->SupportedVideo()) 51 | throw std::runtime_error("video track not supported"); 52 | 53 | if (need_audio && qt_->HasAudio()) { 54 | if (!qt_->SupportedAudio()) 55 | throw std::runtime_error("audio track not supported"); 56 | has_audio_ = true; 57 | } 58 | 59 | current_frame_ = -1; 60 | next_frame_ = 0; 61 | } 62 | } 63 | 64 | void MovPlayer::UpdateFrameTexture(SDL2pp::Renderer& renderer, int frame) { 65 | // we already have wanted frame loaded, do nothing 66 | if (current_frame_ == frame) 67 | return; 68 | 69 | // is seek required? 70 | if (next_frame_ != frame) { 71 | qt_->SetVideoPosition(frame); 72 | next_frame_ = frame; 73 | } 74 | 75 | int width = qt_->GetWidth(); 76 | int height = qt_->GetHeight(); 77 | 78 | // is texture rebuild required? 79 | if (texture_.get() == nullptr || 80 | texture_->GetFormat() != SDL_PIXELFORMAT_RGB24 || 81 | texture_->GetAccess() != SDL_TEXTUREACCESS_STREAMING || 82 | texture_->GetWidth() != width || 83 | texture_->GetHeight() != height) 84 | texture_.reset(new SDL2pp::Texture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, width, height)); 85 | 86 | // decode next frame 87 | { 88 | SDL2pp::Texture::LockHandle lock = texture_->Lock(SDL2pp::NullOpt); 89 | qt_->DecodeVideo(static_cast(lock.GetPixels()), lock.GetPitch()); 90 | } 91 | 92 | current_frame_ = next_frame_++; 93 | } 94 | 95 | void MovPlayer::ResetPlayback() { 96 | start_frame_ = end_frame_ = 0; 97 | start_frame_ticks_ = 0; 98 | state_ = STOPPED; 99 | audio_.reset(nullptr); 100 | } 101 | 102 | void MovPlayer::EmitEndOfClipEvent() { 103 | if (listener_) 104 | listener_->ProcessEndOfClipEvent(); 105 | } 106 | 107 | void MovPlayer::Play(const std::string& filename, int startframe, int endframe) { 108 | Log("player") << "playing " << filename << " at [" << startframe << ".." << endframe << "]"; 109 | 110 | ResetPlayback(); 111 | 112 | UpdateMovieFile(filename, true); 113 | 114 | // print some info 115 | Log("player") << " video:"; 116 | Log("player") << " dimensions: " << qt_->GetWidth() << "x" << qt_->GetHeight(); 117 | Log("player") << " time scale: " << qt_->GetTimeScale(); 118 | Log("player") << " frame dur.: " << qt_->GetFrameDuration(); 119 | Log("player") << " frame rate: " << (float)qt_->GetTimeScale() / (float)qt_->GetFrameDuration() << " fps"; 120 | Log("player") << " pts offset: " << qt_->GetVideoPtsOffset() << " (" << (float)qt_->GetVideoPtsOffset() / (float)qt_->GetFrameDuration() << " frames)"; 121 | 122 | if (has_audio_) { 123 | Log("player") << " audio:"; 124 | Log("player") << " sample rate: " << qt_->GetSampleRate(); 125 | std::string format = "unknown"; 126 | switch (qt_->GetSampleFormat()) { 127 | case LQT_SAMPLE_INT8: format = "s8"; break; 128 | case LQT_SAMPLE_UINT8: format = "u8"; break; 129 | case LQT_SAMPLE_INT16: format = "s16"; break; 130 | case LQT_SAMPLE_INT32: format = "s32"; break; 131 | case LQT_SAMPLE_FLOAT: format = "float"; break; 132 | case LQT_SAMPLE_DOUBLE: format = "double"; break; 133 | default: break; 134 | } 135 | Log("player") << " sample format: " << format; 136 | Log("player") << " audio bits: " << qt_->GetAudioBits(); 137 | Log("player") << " channels: " << qt_->GetTrackChannels(); 138 | Log("player") << " pts offset: " << qt_->GetAudioPtsOffset() << " samples"; 139 | } 140 | 141 | // setup video timing 142 | start_frame_ = startframe - qt_->GetVideoPtsOffset() / qt_->GetFrameDuration(); 143 | end_frame_ = endframe - qt_->GetVideoPtsOffset() / qt_->GetFrameDuration(); 144 | 145 | // setup audio 146 | if (has_audio_) { 147 | SDL2pp::AudioSpec spec(qt_->GetSampleRate(), AUDIO_U8, qt_->GetTrackChannels(), 16); 148 | audio_.reset(new SDL2pp::AudioDevice(SDL2pp::NullOpt, false, spec, 149 | [this](Uint8* stream, int len) { 150 | qt_->DecodeAudioRaw(stream, len / qt_->GetTrackChannels()); 151 | } 152 | )); 153 | 154 | int audiopos = (int)((float)start_frame_ * (float)qt_->GetFrameDuration() / (float)qt_->GetTimeScale() * qt_->GetSampleRate()); 155 | qt_->SetAudioPosition(audiopos); 156 | 157 | audio_->Pause(false); 158 | } 159 | 160 | start_frame_ticks_ = SDL_GetTicks(); 161 | 162 | state_ = PLAYING; 163 | } 164 | 165 | void MovPlayer::PlaySingleFrame(const std::string& filename, int frame) { 166 | Log("player") << "playing " << filename << " single frame " << frame; 167 | 168 | ResetPlayback(); 169 | 170 | UpdateMovieFile(filename, false); 171 | 172 | // print some info 173 | Log("player") << " video:"; 174 | Log("player") << " dimensions: " << qt_->GetWidth() << "x" << qt_->GetHeight(); 175 | 176 | start_frame_ = frame; 177 | 178 | state_ = SINGLE_FRAME; 179 | } 180 | 181 | void MovPlayer::Stop() { 182 | Log("player") << "stopping"; 183 | state_ = STOPPED; 184 | } 185 | 186 | bool MovPlayer::UpdateFrame(SDL2pp::Renderer& renderer) { 187 | // no movie loaded -> nothing to do 188 | if (!qt_.get()) 189 | return false; 190 | 191 | // ensure audio callback is not called while processing this frame 192 | SDL2pp::AudioDevice::LockHandle lock; 193 | if (has_audio_) 194 | lock = audio_->Lock(); 195 | 196 | // calculate wanted frame from given time 197 | int wanted_frame; 198 | switch (state_) { 199 | case STOPPED: 200 | wanted_frame = current_frame_; 201 | break; 202 | case PLAYING: 203 | wanted_frame = start_frame_ + 204 | (SDL_GetTicks() - start_frame_ticks_) * qt_->GetTimeScale() / (qt_->GetFrameDuration() * 1000) - 205 | qt_->GetVideoPtsOffset() / qt_->GetFrameDuration(); 206 | if (wanted_frame > end_frame_) 207 | wanted_frame = end_frame_; 208 | break; 209 | case SINGLE_FRAME: 210 | wanted_frame = start_frame_; 211 | break; 212 | } 213 | 214 | // don't go past end frame 215 | if (wanted_frame < 0) 216 | wanted_frame = 0; 217 | 218 | UpdateFrameTexture(renderer, wanted_frame); 219 | 220 | if (state_ == PLAYING) { 221 | if (current_frame_ >= end_frame_) { 222 | Log("player") << "movie finished"; 223 | if (audio_.get()) 224 | audio_->Pause(true); 225 | state_ = STOPPED; 226 | EmitEndOfClipEvent(); 227 | } 228 | } 229 | 230 | return true; 231 | } 232 | 233 | int MovPlayer::GetCurrentFrame() const { 234 | return current_frame_; 235 | } 236 | 237 | SDL2pp::Texture* MovPlayer::GetTexture() { 238 | return texture_.get(); 239 | } 240 | -------------------------------------------------------------------------------- /movplayer.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef MOVPLAYER_HH 21 | #define MOVPLAYER_HH 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "quicktime.hh" 32 | 33 | class MovPlayer { 34 | public: 35 | class EventListener { 36 | public: 37 | virtual ~EventListener() { 38 | } 39 | 40 | virtual void ProcessEndOfClipEvent() { 41 | } 42 | }; 43 | 44 | protected: 45 | enum State { 46 | PLAYING, 47 | STOPPED, 48 | SINGLE_FRAME, 49 | }; 50 | 51 | protected: 52 | std::unique_ptr qt_; 53 | 54 | std::unique_ptr texture_; 55 | std::unique_ptr audio_; 56 | 57 | // state of the currently loaded movie clip 58 | std::string current_file_; 59 | bool has_audio_; 60 | int current_frame_; 61 | int next_frame_; 62 | 63 | // state of the player 64 | State state_; 65 | unsigned int start_frame_ticks_; 66 | int start_frame_; 67 | int end_frame_; 68 | 69 | EventListener* listener_; 70 | 71 | protected: 72 | void UpdateMovieFile(const std::string& name, bool need_audio); 73 | void UpdateFrameTexture(SDL2pp::Renderer& renderer, int frame); 74 | 75 | void ResetPlayback(); 76 | 77 | void EmitEndOfClipEvent(); 78 | 79 | public: 80 | MovPlayer(); 81 | ~MovPlayer(); 82 | 83 | void SetListener(EventListener* listener); 84 | 85 | void Play(const std::string& filename, int startframe, int endframe); 86 | void PlaySingleFrame(const std::string& filename, int frame); 87 | void Stop(); 88 | 89 | int GetCurrentFrame() const; 90 | 91 | bool UpdateFrame(SDL2pp::Renderer& renderer); 92 | SDL2pp::Texture* GetTexture(); 93 | }; 94 | 95 | #endif // MOVPLAYER_HH 96 | -------------------------------------------------------------------------------- /nodfile.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | 24 | #include "nodfile.hh" 25 | 26 | NodFile::NodFile(const std::string& path) { 27 | std::ifstream stream(path, std::ios_base::in); 28 | stream.exceptions(std::ifstream::badbit); 29 | 30 | int index = 0; 31 | while (!stream.eof()) { 32 | Entry e; 33 | stream >> e.number >> e.name; 34 | 35 | for (int i = 0; i < 24; i++) 36 | stream >> e.fields[i]; 37 | 38 | if (stream.fail()) 39 | break; 40 | 41 | if (index != e.number) 42 | throw std::runtime_error("entry index in file != real index, this is unexpected"); 43 | 44 | entries_.push_back(std::move(e)); 45 | 46 | index++; 47 | } 48 | } 49 | 50 | NodFile::~NodFile() { 51 | } 52 | 53 | const NodFile::Entry& NodFile::GetEntry(int index) const { 54 | if (index < 0 || index >= (int)entries_.size()) 55 | throw std::runtime_error("entry does not exists in nod file"); 56 | return entries_[index]; 57 | } 58 | 59 | int NodFile::GetNumEntries() const { 60 | return entries_.size(); 61 | } 62 | -------------------------------------------------------------------------------- /nodfile.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef NODFILE_HH 21 | #define NODFILE_HH 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | class NodFile { 28 | public: 29 | enum class Condition { 30 | NO = 104, 31 | YES = 103, 32 | STARTUP = 111, 33 | DIAGNOSTICS = 102, 34 | DEPLOY = 114, 35 | ANALYSIS = 121, 36 | FLOODLIGHT = 113, 37 | }; 38 | 39 | struct Entry { 40 | typedef std::map ConditionMap; 41 | 42 | int number; 43 | std::string name; 44 | int fields[24]; 45 | 46 | int GetType() const { return fields[0]; } 47 | int GetStartFrame() const { return fields[1]; } 48 | int GetEndFrame() const { return fields[2]; } 49 | int GetActionStartFrame() const { return fields[3]; } 50 | int GetActionEndFrame() const { return fields[4]; } 51 | const std::string GetName() const { return name; } 52 | 53 | int GetDefaultOffset() const { return fields[5]; } 54 | 55 | ConditionMap GetConditions() const { 56 | ConditionMap conds; 57 | for (int i = 6; i <= 20; i += 2) 58 | if (fields[i+1] != 0) 59 | conds[fields[i+1]] = fields[i]; 60 | return conds; 61 | } 62 | 63 | std::pair GetCondition(int n) const { 64 | return std::make_pair(fields[6 + n * 2 + 7], fields[6 + n * 2]); 65 | } 66 | }; 67 | 68 | protected: 69 | typedef std::vector EntryVector; 70 | 71 | protected: 72 | EntryVector entries_; 73 | 74 | public: 75 | NodFile(const std::string& path); 76 | ~NodFile(); 77 | 78 | const Entry& GetEntry(int index) const; 79 | int GetNumEntries() const; 80 | 81 | template 82 | void ForEach(const F& processor) const { 83 | for (auto& e : entries_) 84 | processor(e); 85 | } 86 | }; 87 | 88 | #endif // NODFILE_HH 89 | -------------------------------------------------------------------------------- /quicktime.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "quicktime.hh" 24 | 25 | QuickTime::QuickTime(const std::string& path) { 26 | qt_ = quicktime_open(path.c_str(), 1, 0); 27 | if (qt_ == nullptr) 28 | throw std::runtime_error("quicktime_open failed"); 29 | } 30 | 31 | QuickTime::~QuickTime() { 32 | quicktime_close(qt_); 33 | } 34 | 35 | quicktime_t* QuickTime::Get() const { 36 | return qt_; 37 | } 38 | 39 | bool QuickTime::HasVideo() const { 40 | return quicktime_has_video(qt_); 41 | } 42 | 43 | bool QuickTime::SupportedVideo(int track) const { 44 | return quicktime_supported_video(qt_, track); 45 | } 46 | 47 | int QuickTime::GetWidth(int track) const { 48 | return quicktime_video_width(qt_, track); 49 | } 50 | 51 | int QuickTime::GetHeight(int track) const { 52 | return quicktime_video_height(qt_, track); 53 | } 54 | 55 | int QuickTime::GetTimeScale(int track) const { 56 | return lqt_video_time_scale(qt_, track); 57 | } 58 | 59 | int QuickTime::GetFrameDuration(int track) const { 60 | int constant; 61 | int duration = lqt_frame_duration(qt_, track, &constant); 62 | if (constant != 1) 63 | throw std::runtime_error("video with non-constant framerate detected, not supported"); 64 | return duration; 65 | } 66 | 67 | int64_t QuickTime::GetVideoPtsOffset(int track) const { 68 | return lqt_get_video_pts_offset(qt_, track); 69 | } 70 | 71 | lqt_sample_format_t QuickTime::GetSampleFormat(int track) const { 72 | return lqt_get_sample_format(qt_, track); 73 | } 74 | 75 | int QuickTime::SetVideoPosition(int64_t frame, int track) { 76 | return quicktime_set_video_position(qt_, frame, track); 77 | } 78 | 79 | int QuickTime::DecodeVideo(unsigned char** row_pointers, int track) { 80 | return quicktime_decode_video(qt_, row_pointers, track); 81 | } 82 | 83 | int QuickTime::DecodeVideo(unsigned char* pixels, int pitch, int track) { 84 | const int height = GetHeight(track); 85 | 86 | std::vector row_pointers(height); 87 | for (int i = 0; i < height; i++) 88 | row_pointers[i] = pixels + pitch * i; 89 | 90 | return quicktime_decode_video(qt_, row_pointers.data(), track); 91 | } 92 | 93 | bool QuickTime::HasAudio() const { 94 | return quicktime_has_audio(qt_); 95 | } 96 | 97 | bool QuickTime::SupportedAudio(int track) const { 98 | return quicktime_supported_audio(qt_, track); 99 | } 100 | 101 | long QuickTime::GetSampleRate(int track) const { 102 | return quicktime_sample_rate(qt_, track); 103 | } 104 | 105 | int QuickTime::GetAudioBits(int track) const { 106 | return quicktime_audio_bits(qt_, track); 107 | } 108 | 109 | int QuickTime::GetTrackChannels(int track) const { 110 | return quicktime_track_channels(qt_, track); 111 | } 112 | 113 | int64_t QuickTime::GetAudioPtsOffset(int track) const { 114 | return lqt_get_audio_pts_offset(qt_, track); 115 | } 116 | 117 | int QuickTime::SetAudioPosition(int64_t sample, int track) { 118 | return quicktime_set_audio_position(qt_, sample, track); 119 | } 120 | 121 | int64_t QuickTime::LastAudioPosition(int track) const { 122 | return lqt_last_audio_position(qt_, track); 123 | } 124 | 125 | int QuickTime::DecodeAudioTrack(int16_t** output_i, float** output_f, long samples, int track) { 126 | return lqt_decode_audio_track(qt_, output_i, output_f, samples, track); 127 | } 128 | 129 | int QuickTime::DecodeAudioTrackInterleaved(int16_t* output_i, float* output_f, long samples, int track) { 130 | std::vector temp_i(output_i ? GetTrackChannels(track) * samples : 0, 0); 131 | std::vector temp_f(output_f ? GetTrackChannels(track) * samples : 0, 0.0f); 132 | 133 | std::vector temp_p_i; 134 | if (output_i) 135 | for (int i = 0; i < GetTrackChannels(track); i++) 136 | temp_p_i.push_back(temp_i.data() + i * samples); 137 | std::vector temp_p_f; 138 | if (output_f) 139 | for (int i = 0; i < GetTrackChannels(track); i++) 140 | temp_p_f.push_back(temp_f.data() + i * samples); 141 | 142 | int retval = lqt_decode_audio_track(qt_, output_i ? temp_p_i.data() : nullptr, output_f ? temp_p_f.data() : nullptr, samples, track); 143 | 144 | if (output_i) 145 | for (int s = 0; s < samples; s++) 146 | for (int c = 0; c < GetTrackChannels(track); c++) 147 | *(output_i++) = temp_i[c * samples + s]; 148 | 149 | if (output_f) 150 | for (int s = 0; s < samples; s++) 151 | for (int c = 0; c < GetTrackChannels(track); c++) 152 | *(output_f++) = temp_f[c * samples + s]; 153 | 154 | return retval; 155 | } 156 | 157 | int QuickTime::DecodeAudioRaw(void* output, long samples, int track) { 158 | return lqt_decode_audio_raw(qt_, output, samples, track); 159 | } 160 | -------------------------------------------------------------------------------- /quicktime.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef QUICKTIME_HH 21 | #define QUICKTIME_HH 22 | 23 | #include 24 | 25 | #include 26 | 27 | class QuickTime { 28 | protected: 29 | quicktime_t* qt_; 30 | 31 | public: 32 | QuickTime(const std::string& path); 33 | ~QuickTime(); 34 | 35 | quicktime_t* Get() const; 36 | 37 | // video 38 | bool HasVideo() const; 39 | bool SupportedVideo(int track = 0) const; 40 | 41 | int GetWidth(int track = 0) const; 42 | int GetHeight(int track = 0) const; 43 | int GetTimeScale(int track = 0) const; 44 | int GetFrameDuration(int track = 0) const; 45 | int64_t GetVideoPtsOffset(int track = 0) const; 46 | 47 | int SetVideoPosition(int64_t frame, int track = 0); 48 | 49 | int DecodeVideo(unsigned char** row_pointers, int track = 0); 50 | int DecodeVideo(unsigned char* pixels, int pitch, int track = 0); 51 | 52 | // audio 53 | bool HasAudio() const; 54 | bool SupportedAudio(int track = 0) const; 55 | 56 | long GetSampleRate(int track = 0) const; 57 | int GetAudioBits(int track = 0) const; 58 | int GetTrackChannels(int track = 0) const; 59 | int64_t GetAudioPtsOffset(int track = 0) const; 60 | lqt_sample_format_t GetSampleFormat(int track = 0) const; 61 | 62 | int SetAudioPosition(int64_t sample, int track = 0); 63 | int64_t LastAudioPosition(int track = 0) const; 64 | 65 | int DecodeAudioTrack(int16_t** output_i, float** output_f, long samples, int track = 0); 66 | int DecodeAudioTrackInterleaved(int16_t* output_i, float* output_f, long samples, int track = 0); 67 | int DecodeAudioRaw(void* output, long samples, int track = 0); 68 | }; 69 | 70 | #endif // QUICKTIME_HH 71 | -------------------------------------------------------------------------------- /screen.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include "screen.hh" 21 | 22 | Screen::~Screen() { 23 | } 24 | 25 | bool Screen::ProcessEvent(const SDL_Event&) { 26 | return true; 27 | } 28 | 29 | bool Screen::Update() { 30 | return true; 31 | } 32 | 33 | void Screen::Render() { 34 | } 35 | -------------------------------------------------------------------------------- /screen.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef SCREEN_HH 21 | #define SCREEN_HH 22 | 23 | #include 24 | 25 | class Screen { 26 | public: 27 | virtual ~Screen(); 28 | 29 | virtual bool ProcessEvent(const SDL_Event& event); 30 | virtual bool Update(); 31 | virtual void Render(); 32 | }; 33 | 34 | #endif // SCREEN_HH 35 | -------------------------------------------------------------------------------- /sunpuzzle.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | 24 | #include "sunpuzzle.hh" 25 | 26 | #include "datamanager.hh" 27 | #include "logger.hh" 28 | 29 | // TODO: no sounds 30 | 31 | const std::array SunPuzzle::button_locations_ = { { 32 | { 360, 58 }, 33 | { 424, 144 }, 34 | { 404, 274 }, 35 | { 184, 274 }, 36 | { 166, 144 }, 37 | { 228, 58}, 38 | } }; 39 | 40 | SunPuzzle::SunPuzzle(SDL2pp::Renderer& renderer, const DataManager& datamanager) 41 | : renderer_(renderer), 42 | background_(renderer, datamanager.GetPath("images/psun/od_bg2.bmp")), 43 | buttons_(renderer, datamanager.GetPath("images/psun/od_buttb.rle")), 44 | temperature_(renderer, datamanager.GetPath("images/psun/bigtempa.bmp")) { 45 | Log("puzzle") << "starting sun puzzle"; 46 | 47 | std::fill(states_.begin(), states_.end(), 0); 48 | } 49 | 50 | SunPuzzle::~SunPuzzle() { 51 | } 52 | 53 | bool SunPuzzle::ProcessEvent(const SDL_Event& event) { 54 | if (event.type == SDL_MOUSEBUTTONDOWN) { 55 | int nbutton = -1; 56 | for (auto buttonloc = button_locations_.begin(); buttonloc != button_locations_.end(); buttonloc++) { 57 | if (!SDL2pp::Rect(buttonloc->x, buttonloc->y, 42, 42).Contains(SDL2pp::Point(event.button.x, event.button.y))) 58 | continue; 59 | 60 | nbutton = buttonloc - button_locations_.begin(); 61 | break; 62 | } 63 | 64 | if (nbutton < 0 || nbutton > 5) 65 | return true; 66 | 67 | // upgrade n'th and n+2'th buttons 68 | states_[nbutton] = (states_[nbutton] + 1) % 3; 69 | nbutton = (nbutton + 2) % 6; 70 | states_[nbutton] = (states_[nbutton] + 1) % 3; 71 | 72 | for (int i = 0; i < 6; i++) 73 | if (states_[i] != 2) 74 | return true; 75 | 76 | Log("puzzle") << " congrats, puzzle is solved"; 77 | return false; 78 | } 79 | 80 | return true; 81 | } 82 | 83 | bool SunPuzzle::Update() { 84 | return true; 85 | } 86 | 87 | void SunPuzzle::Render() { 88 | // background 89 | renderer_.Copy(background_, SDL2pp::NullOpt, SDL2pp::Rect(0, 0, 640, 480)); 90 | 91 | // buttons 92 | for (int i = 0; i < 6; i++) { 93 | renderer_.Copy( 94 | buttons_, 95 | SDL2pp::Rect(42 * i, 42 * states_[i], 42, 42), 96 | SDL2pp::Rect(button_locations_[i].x, button_locations_[i].y, 42, 42) 97 | ); 98 | } 99 | 100 | // temperature 101 | int temperature = 0; 102 | for (int i = 0; i < 6; i++) 103 | temperature += states_[i]; 104 | 105 | temperature = std::min(temperature * 5 / 12, 5); 106 | 107 | int phase = (SDL_GetTicks() / 1000) % 6; 108 | 109 | renderer_.Copy( 110 | temperature_, 111 | SDL2pp::Rect(100 * temperature, 120 * phase, 100, 120), 112 | SDL2pp::Rect(264, 192, 100, 120) 113 | ); 114 | } 115 | -------------------------------------------------------------------------------- /sunpuzzle.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Dmitry Marakasov 3 | * 4 | * This file is part of opendaed. 5 | * 6 | * opendaed is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * opendaed is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with opendaed. If not, see . 18 | */ 19 | 20 | #ifndef SUNPUZZLE_HH 21 | #define SUNPUZZLE_HH 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include "screen.hh" 29 | 30 | class DataManager; 31 | 32 | class SunPuzzle : public Screen { 33 | private: 34 | static const std::array button_locations_; 35 | 36 | private: 37 | SDL2pp::Renderer& renderer_; 38 | 39 | // Textures 40 | SDL2pp::Texture background_; 41 | SDL2pp::Texture buttons_; 42 | SDL2pp::Texture temperature_; 43 | 44 | private: 45 | std::array states_; 46 | 47 | public: 48 | SunPuzzle(SDL2pp::Renderer& renderer, const DataManager& datamanager); 49 | virtual ~SunPuzzle(); 50 | 51 | bool ProcessEvent(const SDL_Event& event) override; 52 | bool Update() override; 53 | void Render() override; 54 | }; 55 | 56 | #endif // SUNPUZZLE_HH 57 | --------------------------------------------------------------------------------