commit a547a31a378bbc8d4c01a60887030170347cc28e Author: brbarnesEA <161645603+brbarnesEA@users.noreply.github.com> Date: Tue Mar 5 11:56:45 2024 -0800 TS_RA2_Mission_Editor_sourcecode_23.02.2023_1 TS_RA2_Mission_Editor_sourcecode_23.02.2023_1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d07bc44 --- /dev/null +++ b/.gitignore @@ -0,0 +1,71 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# MSVC +[Dd]ebug*/ +[Rr]elease*/ +build/ +build_*/ +*.vs +*.user +*.spec +*.ncb +*.sdf +*.suo +*.sln +*.vcxproj +*.filters +*.aps + +# CMake +CMakeFiles/ +CMakeCache.txt +CMakeUserPresets.json +*.dir + +# Windows +thumbs.db +desktop.ini +*.log + +# Misc +*.tmp +*.bak +*.idb + +# FinalSun/FinalAlert specific +dist/ +intermediate/ +vcpkg_installed/ +vcpkg_downloads/ +[Tt]emplate/ diff --git a/3rdParty/xcc/.gitignore b/3rdParty/xcc/.gitignore new file mode 100644 index 0000000..962f2c9 --- /dev/null +++ b/3rdParty/xcc/.gitignore @@ -0,0 +1,3 @@ +.vs/ +Debug/ +Release/ diff --git a/3rdParty/xcc/COPYING b/3rdParty/xcc/COPYING new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/3rdParty/xcc/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/3rdParty/xcc/Library/StdAfx.cpp b/3rdParty/xcc/Library/StdAfx.cpp new file mode 100644 index 0000000..799dfed --- /dev/null +++ b/3rdParty/xcc/Library/StdAfx.cpp @@ -0,0 +1,19 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" diff --git a/3rdParty/xcc/Library/StdAfx.h b/3rdParty/xcc/Library/StdAfx.h new file mode 100644 index 0000000..ce37391 --- /dev/null +++ b/3rdParty/xcc/Library/StdAfx.h @@ -0,0 +1,45 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +// #define WIN32_LEAN_AND_MEAN + +#include <array> +#include <boost/algorithm/string.hpp> +#include <cassert> +#include <climits> +#include <cstdint> +#include <list> +#include <memory> +#include <map> +#include <set> +#include <span> +#include <string> +#include <vartypes.h> +#include <vector> +#include <xcc/data_ref.h> +#include <xcc/find_ptr.h> +#ifndef XCC_MINIMAL_BUILD +#include <xcc/string_view.h> +#endif + +using namespace std; +using boost::iequals; +using boost::to_lower_copy; +using boost::trim_copy; diff --git a/3rdParty/xcc/XCC.props b/3rdParty/xcc/XCC.props new file mode 100644 index 0000000..1e1a74b --- /dev/null +++ b/3rdParty/xcc/XCC.props @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalIncludeDirectories>..\misc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <DisableSpecificWarnings>4018;4201;4267;4554;4806;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <LanguageStandard>stdcpplatest</LanguageStandard> + <PreprocessorDefinitions>_HAS_STD_BYTE=0;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <AdditionalManifestDependencies>"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies> + <AdditionalDependencies>dsound.lib;gdiplus.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + +</Project> diff --git a/3rdParty/xcc/misc/blowfish.cpp b/3rdParty/xcc/misc/blowfish.cpp new file mode 100644 index 0000000..9e1833c --- /dev/null +++ b/3rdParty/xcc/misc/blowfish.cpp @@ -0,0 +1,427 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include <blowfish.h> + +#include <memory.h> + +const Cblowfish::t_bf_p g_p = +{ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b, +}; + +const Cblowfish::t_bf_s g_s = +{ + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, +}; + +void Cblowfish::set_key(data_ref key) +{ + memcpy(m_p, g_p, sizeof(t_bf_p)); + memcpy(m_s, g_s, sizeof(t_bf_s)); + + int j = 0; + for (int i = 0; i < 18; i++) + { + int a = key[j++]; j %= key.size(); + int b = key[j++]; j %= key.size(); + int c = key[j++]; j %= key.size(); + int d = key[j++]; j %= key.size(); + m_p[i] ^= a << 24 | b << 16 | c << 8 | d; + } + + uint32_t datal = 0; + uint32_t datar = 0; + + for (int i = 0; i < 18; ) + { + encipher(datal, datar); + + m_p[i++] = datal; + m_p[i++] = datar; + } + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 256; ) + { + encipher(datal, datar); + + m_s[i][j++] = datal; + m_s[i][j++] = datar; + } + } +} + +uint32_t Cblowfish::S(uint32_t x, int i) const +{ + return m_s[i][(x >> ((3 - i) << 3)) & 0xff]; +} + +uint32_t Cblowfish::bf_f(uint32_t x) const +{ + return ((S(x, 0) + S(x, 1)) ^ S(x, 2)) + S(x, 3); +} + +void Cblowfish::ROUND(uint32_t& a, uint32_t b, int n) const +{ + a ^= bf_f(b) ^ m_p[n]; +} + +void Cblowfish::encipher(uint32_t& xl, uint32_t& xr) const +{ + uint32_t Xl = xl; + uint32_t Xr = xr; + + Xl ^= m_p[0]; + ROUND (Xr, Xl, 1); ROUND (Xl, Xr, 2); + ROUND (Xr, Xl, 3); ROUND (Xl, Xr, 4); + ROUND (Xr, Xl, 5); ROUND (Xl, Xr, 6); + ROUND (Xr, Xl, 7); ROUND (Xl, Xr, 8); + ROUND (Xr, Xl, 9); ROUND (Xl, Xr, 10); + ROUND (Xr, Xl, 11); ROUND (Xl, Xr, 12); + ROUND (Xr, Xl, 13); ROUND (Xl, Xr, 14); + ROUND (Xr, Xl, 15); ROUND (Xl, Xr, 16); + Xr ^= m_p[17]; + + xr = Xl; + xl = Xr; +} + +void Cblowfish::decipher(uint32_t& xl, uint32_t& xr) const +{ + uint32_t Xl = xl; + uint32_t Xr = xr; + + Xl ^= m_p[17]; + ROUND (Xr, Xl, 16); ROUND (Xl, Xr, 15); + ROUND (Xr, Xl, 14); ROUND (Xl, Xr, 13); + ROUND (Xr, Xl, 12); ROUND (Xl, Xr, 11); + ROUND (Xr, Xl, 10); ROUND (Xl, Xr, 9); + ROUND (Xr, Xl, 8); ROUND (Xl, Xr, 7); + ROUND (Xr, Xl, 6); ROUND (Xl, Xr, 5); + ROUND (Xr, Xl, 4); ROUND (Xl, Xr, 3); + ROUND (Xr, Xl, 2); ROUND (Xl, Xr, 1); + Xr ^= m_p[0]; + + xl = Xr; + xr = Xl; +} + +static uint32_t reverse(uint32_t v) +{ + _asm + { + mov eax, v + xchg al, ah + rol eax, 16 + xchg al, ah + mov v, eax + } + return v; +} + +void Cblowfish::encipher(const void* s, void* d, int size) const +{ + const uint32_t* r = reinterpret_cast<const uint32_t*>(s); + uint32_t* w = reinterpret_cast<uint32_t*>(d); + size >>= 3; + while (size--) + { + uint32_t a = reverse(*r++); + uint32_t b = reverse(*r++); + encipher(a, b); + *w++ = reverse(a); + *w++ = reverse(b); + } +} + +void Cblowfish::decipher(const void* s, void* d, int size) const +{ + const uint32_t* r = reinterpret_cast<const uint32_t*>(s); + uint32_t* w = reinterpret_cast<uint32_t*>(d); + size >>= 3; + while (size--) + { + uint32_t a = reverse(*r++); + uint32_t b = reverse(*r++); + decipher(a, b); + *w++ = reverse(a); + *w++ = reverse(b); + } +} \ No newline at end of file diff --git a/3rdParty/xcc/misc/blowfish.h b/3rdParty/xcc/misc/blowfish.h new file mode 100644 index 0000000..72a3f3f --- /dev/null +++ b/3rdParty/xcc/misc/blowfish.h @@ -0,0 +1,41 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <vartypes.h> + +class Cblowfish +{ +public: + using t_bf_p = uint32_t[18]; + using t_bf_s = uint32_t[4][256]; + + void set_key(data_ref); + void encipher(const void* s, void* d, int size) const; + void decipher(const void* s, void* d, int size) const; +private: + void encipher(uint32_t& xl, uint32_t& xr) const; + void decipher(uint32_t& xl, uint32_t& xr) const; + uint32_t S(uint32_t x, int i) const; + uint32_t bf_f(uint32_t x) const; + void ROUND(uint32_t& a, uint32_t b, int n) const; + + t_bf_p m_p; + t_bf_s m_s; +}; diff --git a/3rdParty/xcc/misc/cc_file.cpp b/3rdParty/xcc/misc/cc_file.cpp new file mode 100644 index 0000000..d9e9e11 --- /dev/null +++ b/3rdParty/xcc/misc/cc_file.cpp @@ -0,0 +1,520 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "cc_file.h" + +#ifndef XCC_MINIMAL_BUILD +#include "aud_file.h" +#include "avi_file.h" +#include "big_file.h" +#include "bin_file.h" +#include "bink_file.h" +#include "bmp_file.h" +#include "csf_file.h" +#include "cps_file.h" +#include "dds_file.h" +#include "fnt_file.h" +#include "hva_file.h" +#include "id_log.h" +#include "jpeg_file.h" +#include "map_td_ini_reader.h" +#include "map_ra_ini_reader.h" +#include "map_ts_ini_reader.h" +#include "mix_file.h" +#include "mix_rg_file.h" +#include "mp3_file.h" +#include "null_ini_reader.h" +#include "ogg_file.h" +#include "pak_file.h" +#include "pal_file.h" +#include "pcx_file.h" +#include "png_file.h" +#include "pkt_ts_ini_reader.h" +#include "shp_dune2_file.h" +#include "shp_file.h" +#include "shp_ts_file.h" +#include "sound_ts_ini_reader.h" +#include "st_file.h" +#include "string_conversion.h" +#include "text_file.h" +#include "tga_file.h" +#include "theme_ts_ini_reader.h" +#include "tmp_file.h" +#include "tmp_ra_file.h" +#include "tmp_ts_file.h" +#include "virtual_tfile.h" +#include "voc_file.h" +#include "vqa_file.h" +#include "vqp_file.h" +#include "vxl_file.h" +#include "w3d_file.h" +#include "wav_file.h" +#include "wsa_dune2_file.h" +#include "wsa_file.h" +#include "xcc_dirs.h" +#include "xcc_file.h" +#include "xcc_lmd_file.h" +#include "xif_file.h" +#else +#include "mix_file.h" +#include "xcc_dirs.h" +#endif + + +const char* ft_name[] = +{ + "aud", + "avi", + "big", + "bin", + "bink", + "bmp", + "clipboard", + "csf", + "cps", + "csv", + "dds", + "dir", + "drive", + "fnt", + "html", + "hva", + "ini", + "jpeg", + "jpeg (single)", + "map (dune2)", + "map (td)", + "map (ra)", + "map (ts)", + "map (ts) preview", + "map (ra2)", + "mix", + "mix (rg)", + "mng", + "mp3", + "mrf", + "ogg", + "pak", + "pal", + "pal (jasc)", + "pcx (single)", + "pcx", + "png (single)", + "png", + "pkt (ts)", + "riff", + "rules ini (ts)", + "rules ini (ra2)", + "shp (dune2)", + "shp", + "shp (ts)", + "sound ini (ts)", + "sound ini (ra2)", + "string table", + "text", + "tga", + "tga (single)", + "theme ini (ts)", + "theme ini (ra2)", + "tmp", + "tmp (ra)", + "tmp (ts)", + "voc", + "vpl", + "vqa", + "vqp", + "vxl", + "w3d", + "wav", + "pcm wav", + "ima adpcm wav", + "wsa (dune2)", + "wsa", + "xcc lmd", + "xcc unknown", + "xif", + "zip", + "unknown" +}; + +Ccc_file::Ccc_file(bool read_on_open) : + m_read_on_open(read_on_open) +{ +} + +#define test_fail(res) { int v = res; if (v) { close(); return v; }} + +#ifndef NO_MIX_SUPPORT + int Ccc_file::open(unsigned int id, Cmix_file& mix_f) + { + if (mix_f.get_index(id) == -1) + return -1; + m_f = mix_f.m_f; + m_offset = mix_f.m_offset + mix_f.get_offset(id); + m_size = mix_f.get_size(id); + m_p = 0; + m_is_open = true; + if (m_read_on_open || mix_f.data()) + m_data = mix_f.get_vdata(id); + test_fail(post_open()) + return 0; + } + + int Ccc_file::open(const string& name, Cmix_file& mix_f) + { + return open(Cmix_file::get_id(mix_f.get_game(), name), mix_f); + } +#endif + + int Ccc_file::open(const string& name) + { + close(); + assert(!is_open()); +#ifdef NO_MIX_SUPPORT + test_fail(m_f.open_read(name)); +#else + test_fail(m_f.open_read(xcc_dirs::find_file(name))); +#endif + m_offset = 0; + m_size = m_f.size(); + m_p = 0; + m_is_open = true; + m_data = m_f.get_mm(); + if (m_read_on_open) + m_f.close(); +#ifndef NO_FT_SUPPORT + Cfname fname = to_lower_copy(name); + if (fname.get_fext() == ".mmx") + { + fname.set_ext(".map"); + mix_database::add_name(game_ra2, fname.get_fname(), "-"); + fname.set_ext(".pkt"); + mix_database::add_name(game_ra2, fname.get_fname(), "-"); + } +#endif + test_fail(post_open()) + return 0; + } + + const Cwin_handle& Ccc_file::h() + { + assert(is_open()); + return m_f.h(); + } + + int Ccc_file::open(const Cwin_handle& h) + { + assert(!is_open()); + m_f.open(h); + m_offset = 0; + m_size = m_f.size(); + m_p = 0; + m_is_open = true; + m_data = m_f.get_mm(); + if (m_read_on_open) + m_f.close(); + test_fail(post_open()) + return 0; + } + + void Ccc_file::load(const Cvirtual_binary& d, int size) + { + m_data = d; + m_offset = 0; + m_is_open = true; + m_p = 0; + m_size = size == -1 ? d.size() : size; + post_open(); + } + + void Ccc_file::load(const Ccc_file& f) + { + load(f.vdata()); + } + + int Ccc_file::read() + { + seek(0); + Cvirtual_binary d; + if (int error = read(d.write_start(get_size()), get_size())) + return error; + m_data = d; + return 0; + } + + int Ccc_file::read(void* data, int size) + { + if (get_p() < 0 || get_p() + size > get_size()) + return 1; + if (get_data()) + { + memcpy(data, m_data.data() + m_p, size); + skip(size); + return 0; + } + assert(is_open()); + m_f.seek(m_offset + m_p); + int res = m_f.read(data, size); + if (!res) + skip(size); + return res; + } + + int Ccc_file::extract(const string& name) + { + assert(is_open()); + if (data()) + return vdata().save(name); + seek(0); + Cfile32 f; + if (int error = f.open_write(name)) + return error; + Cvirtual_binary data; + for (int size = get_size(); size; ) + { + int cb_write = min(size, 1 << 20); + if (int error = read(data.write_start(cb_write), cb_write)) + return error; + if (int error = f.write(data.data(), cb_write)) + return error; + size -= cb_write; + } + return 0; + } + + void Ccc_file::close() + { + m_data.clear(); + m_f.close(); + m_is_open = false; + } + + +#ifndef NO_MIX_SUPPORT +#ifndef NO_FT_SUPPORT + t_file_type Ccc_file::get_file_type(bool fast) + { + Cvirtual_binary data; + int size; + if (m_data.data()) + { + data = m_data; + size = m_size; + } + else + { + size = min<int>(m_size, 64 << 10); + seek(0); + if (read(data.write_start(size), size)) + return ft_unknown; + seek(0); + } + Caud_file aud_f; + Cbin_file bin_f; + Cbink_file bink_f; + Cbig_file big_f; + Cbmp_file bmp_f; + Ccsf_file csf_f; + Ccps_file cps_f; + Cdds_file dds_f; + Cfnt_file fnt_f; + Chva_file hva_f; + Cmix_file mix_f; + Cmix_rg_file mix_rg_f; + Cmp3_file mp3_f; + Cjpeg_file jpeg_f; + Cogg_file ogg_f; + Cpak_file pak_f; + Cpal_file pal_f; + Cpcx_file pcx_f; + Cpng_file png_f; + Criff_file riff_f; + Cshp_dune2_file shp_dune2_f; + Cshp_file shp_f; + Cshp_ts_file shp_ts_f; + Cst_file st_f; + Ctext_file text_f; + Ctga_file tga_f; + Ctmp_file tmp_f; + Ctmp_ra_file tmp_ra_f; + Ctmp_ts_file tmp_ts_f; + Cvoc_file voc_f; + Cvqa_file vqa_f; + Cvqp_file vqp_f; + Cvxl_file vxl_f; + Cw3d_file w3d_f; + Cwsa_dune2_file wsa_dune2_f; + Cwsa_file wsa_f; + Cxcc_file xcc_f; + Cxif_file xif_f; + if (aud_f.load(data, m_size), aud_f.is_valid()) + return ft_aud; + if (big_f.load(data, m_size), big_f.is_valid()) + return ft_big; + if (bin_f.load(data, m_size), bin_f.is_valid()) + return ft_bin; + if (bink_f.load(data, m_size), bink_f.is_valid()) + return ft_bink; + if (bmp_f.load(data, m_size), bmp_f.is_valid()) + return ft_bmp; + if (csf_f.load(data, m_size), csf_f.is_valid()) + return ft_csf; + if (cps_f.load(data, m_size), cps_f.is_valid()) + return ft_cps; + if (dds_f.load(data, m_size), dds_f.is_valid()) + return ft_dds; + if (fnt_f.load(data, m_size), fnt_f.is_valid()) + return ft_fnt; + if (hva_f.load(data, m_size), hva_f.is_valid()) + return ft_hva; + if (mp3_f.load(data, m_size), mp3_f.is_valid()) + return ft_mp3; + if (jpeg_f.load(data, m_size), jpeg_f.is_valid()) + return ft_jpeg; + if (ogg_f.load(data, m_size), ogg_f.is_valid()) + return ft_ogg; + if (pal_f.load(data, m_size), pal_f.is_valid()) + return ft_pal; + if (pcx_f.load(data, m_size), pcx_f.is_valid()) + return ft_pcx; + if (png_f.load(data, m_size), png_f.is_valid()) + return ft_png; + if (riff_f.load(data, m_size), riff_f.is_valid()) + { + Cavi_file avi_f; + Cwav_file wav_f; + avi_f.load(data, m_size); + wav_f.load(data, m_size); + if (avi_f.is_valid()) + return ft_avi; + if (wav_f.is_valid()) + return ft_wav; + return ft_riff; + } + if (shp_dune2_f.load(data, m_size), shp_dune2_f.is_valid()) + return ft_shp_dune2; + if (shp_f.load(data, m_size), shp_f.is_valid()) + return ft_shp; + if (shp_ts_f.load(data, m_size), shp_ts_f.is_valid()) + return ft_shp_ts; + if (st_f.load(data, m_size), st_f.is_valid()) + return ft_st; + if (tga_f.load(data, m_size), tga_f.is_valid()) + return ft_tga; + if (tmp_f.load(data, m_size), tmp_f.is_valid()) + return ft_tmp; + if (tmp_ra_f.load(data, m_size), tmp_ra_f.is_valid()) + return ft_tmp_ra; + if (tmp_ts_f.load(data, m_size), tmp_ts_f.is_valid()) + return ft_tmp_ts; + if (voc_f.load(data, m_size), voc_f.is_valid()) + return ft_voc; + if (vqa_f.load(data, m_size), vqa_f.is_valid()) + return ft_vqa; + if (vqp_f.load(data, m_size), vqp_f.is_valid()) + return ft_vqp; + if (vxl_f.load(data, m_size), vxl_f.is_valid()) + return ft_vxl; + if (wsa_dune2_f.load(data, m_size), wsa_dune2_f.is_valid()) + return ft_wsa_dune2; + if (wsa_f.load(data, m_size), wsa_f.is_valid()) + return ft_wsa; + if (xcc_f.load(data, m_size), xcc_f.is_valid()) + { + switch (xcc_f.get_ft()) + { + case xcc_ft_lmd: + return ft_xcc_lmd; + } + return ft_xcc_unknown; + } + if (xif_f.load(data, m_size), xif_f.is_valid()) + return ft_xif; + if (mix_f.load(data, m_size), mix_f.is_valid()) + return ft_mix; + if (mix_rg_f.load(data, m_size), mix_rg_f.is_valid()) + return ft_mix_rg; + if (pak_f.load(data, m_size), pak_f.is_valid()) + return ft_pak; + if (w3d_f.load(data, m_size), w3d_f.is_valid()) + return ft_w3d; + if (text_f.load(data, m_size), text_f.is_valid()) + { + if (fast) + return ft_text; + Cvirtual_tfile tf; + tf.load_data(data); + Cnull_ini_reader ir; + int error = 0; + while (!error && !tf.eof()) + { + error = ir.process_line(tf.read_line()); + if (tf.eof()) + error = 0; + } + if (!error && ir.is_valid()) + { + if (!m_read_on_open && m_size != size) + { + size = m_size; + if (read(data.write_start(size), size)) + return ft_unknown; + seek(0); + } + { + Cmap_td_ini_reader ir; + if (!ir.process(data) && ir.is_valid()) + return ft_map_td; + } + { + Cmap_ra_ini_reader ir; + if (!ir.process(data) && ir.is_valid()) + return ft_map_ra; + } + { + Cmap_ts_ini_reader ir; + ir.fast(true); + if (!ir.process(data) && ir.is_valid()) + return ft_map_ts; + } + { + Cpkt_ts_ini_reader ir; + ir.fast(true); + if (!ir.process(data) && ir.is_valid()) + return ft_pkt_ts; + } + { + Csound_ts_ini_reader ir; + ir.fast(true); + if (!ir.process(data) && ir.is_valid()) + return ft_sound_ini_ts; + } + { + Ctheme_ts_ini_reader ir; + if (!ir.process(data) && ir.is_valid()) + return ft_theme_ini_ts; + } + return ft_ini; + } + return ft_text; + } + return ft_unknown; + } +#endif +#endif diff --git a/3rdParty/xcc/misc/cc_file.h b/3rdParty/xcc/misc/cc_file.h new file mode 100644 index 0000000..264e954 --- /dev/null +++ b/3rdParty/xcc/misc/cc_file.h @@ -0,0 +1,195 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "file32.h" +#include <virtual_binary.h> + +enum t_file_type +{ + ft_aud, + ft_avi, + ft_big, + ft_bin, + ft_bink, + ft_bmp, + ft_clipboard, + ft_csf, + ft_cps, + ft_csv, + ft_dds, + ft_dir, + ft_drive, + ft_fnt, + ft_html, + ft_hva, + ft_ini, + ft_jpeg, + ft_jpeg_single, + ft_map_dune2, + ft_map_td, + ft_map_ra, + ft_map_ts, + ft_map_ts_preview, + ft_map_ra2, + ft_mix, + ft_mix_rg, + ft_mng, + ft_mp3, + ft_mrf, + ft_ogg, + ft_pak, + ft_pal, + ft_pal_jasc, + ft_pcx_single, + ft_pcx, + ft_png_single, + ft_png, + ft_pkt_ts, + ft_riff, + ft_rules_ini_ts, + ft_rules_ini_ra2, + ft_shp_dune2, + ft_shp, + ft_shp_ts, + ft_sound_ini_ts, + ft_sound_ini_ra2, + ft_st, + ft_text, + ft_tga, + ft_tga_single, + ft_theme_ini_ts, + ft_theme_ini_ra2, + ft_tmp, + ft_tmp_ra, + ft_tmp_ts, + ft_voc, + ft_vpl, + ft_vqa, + ft_vqp, + ft_vxl, + ft_w3d, + ft_wav, + ft_wav_ima_adpcm, + ft_wav_pcm, + ft_wsa_dune2, + ft_wsa, + ft_xcc_lmd, + ft_xcc_unknown, + ft_xif, + ft_zip, + ft_unknown, + ft_count +}; + +const char* ft_name[]; + +class Cmix_file; + +class Ccc_file +{ +public: + const Cwin_handle& h(); + int open(const Cwin_handle& h); + int open(unsigned int id, Cmix_file& mix_f); + int open(const string& name, Cmix_file& mix_f); + int open(const string& name); + void load(const Cvirtual_binary& d, int size = -1); + void load(const Ccc_file& f); + t_file_type get_file_type(bool fast = true); + int read(); + int read(void* data, int size); + int extract(const string& name); + virtual void close(); + Ccc_file(bool read_on_open); + + const byte* begin() const + { + return m_data.begin(); + } + + const byte* end() const + { + return m_data.end(); + } + + const byte* data() const + { + return m_data.data(); + } + + long long size() const + { + return m_size; + } + + const byte* get_data() const + { + return m_data.data(); + } + + const byte* data_end() const + { + return m_data.data_end(); + } + + Cvirtual_binary vdata() const + { + return m_data; + } + + int get_p() const + { + return m_p; + } + + long long get_size() const + { + return m_size; + } + + bool is_open() const + { + return m_is_open; + } + + void seek(int p) + { + m_p = p; + } + + void skip(int p) + { + m_p += p; + } + + virtual int post_open() + { + return 0; + } +protected: + int m_offset; +private: + Cvirtual_binary m_data; + Cfile32 m_f; + bool m_is_open = false; + int m_p; + const bool m_read_on_open; + long long m_size; +}; diff --git a/3rdParty/xcc/misc/cc_file_sh.h b/3rdParty/xcc/misc/cc_file_sh.h new file mode 100644 index 0000000..a304dcf --- /dev/null +++ b/3rdParty/xcc/misc/cc_file_sh.h @@ -0,0 +1,31 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cc_file_small.h> + +template <class T> +class Ccc_file_sh : public Ccc_file_small +{ +public: + const T& header() const + { + return *reinterpret_cast<const T*>(data()); + } +}; diff --git a/3rdParty/xcc/misc/cc_file_small.h b/3rdParty/xcc/misc/cc_file_small.h new file mode 100644 index 0000000..3428d7f --- /dev/null +++ b/3rdParty/xcc/misc/cc_file_small.h @@ -0,0 +1,29 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cc_file.h> + +class Ccc_file_small : public Ccc_file +{ +public: + Ccc_file_small() : Ccc_file(true) + { + } +}; diff --git a/3rdParty/xcc/misc/cc_structures.cpp b/3rdParty/xcc/misc/cc_structures.cpp new file mode 100644 index 0000000..43fb582 --- /dev/null +++ b/3rdParty/xcc/misc/cc_structures.cpp @@ -0,0 +1,40 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "cc_structures.h" + +const char* game_name[] = +{ + "Tiberian Dawn", + "Red Alert", + "Tiberian Sun", + "Dune 2", + "Dune 2000", + "Red Alert 2", + "Red Alert 2 Yuri's Revenge", + "Renegade", + "Generals", + "Generals Zero Hour", + "Emperor Battle for Dune", + "Nox", + "Battle for Middle Earth", + "Battle for Middle Earth 2", + "Tiberium Wars", + "Tiberian Sun Firestorm", +}; diff --git a/3rdParty/xcc/misc/cc_structures.h b/3rdParty/xcc/misc/cc_structures.h new file mode 100644 index 0000000..2e93ff5 --- /dev/null +++ b/3rdParty/xcc/misc/cc_structures.h @@ -0,0 +1,566 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "palet.h" + +enum t_game +{ + game_td, + game_ra, + game_ts, + game_dune2, + game_dune2000, + game_ra2, + game_ra2_yr, + game_rg, + game_gr, + game_gr_zh, + game_ebfd, + game_nox, + game_bfme, + game_bfme2, + game_tw, + game_ts_fs, + game_unknown +}; + +const char* game_name[]; + +inline __int32 reverse(__int32 v) +{ + _asm + { + mov eax, v + xchg al, ah + rol eax, 16 + xchg al, ah + mov v, eax + } + return v; +} + +#pragma pack(push, 1) + +struct t_aud_header +{ + unsigned __int16 samplerate; + unsigned __int32 size_in; + unsigned __int32 size_out; + __int8 flags; + __int8 compression; +}; + +struct t_aud_chunk_header +{ + unsigned __int16 size_in; + unsigned __int16 size_out; + __int32 id; +}; + +const __int32 aud_chunk_id = 0x0000deaf; + +struct t_audio_idx_header +{ + __int32 id; + __int32 two; + __int32 c_sounds; +}; + +struct t_audio_idx_entry +{ + char fname[16]; + __int32 offset; + __int32 size; + __int32 samplerate; + __int32 flags; + __int32 chunk_size; +}; + +const __int32 audio_idx_id = *(__int32*)"GABA"; + +struct t_big_header +{ + __int32 id; + __int32 size; + __int32 mc_files; + __int32 mcb_header; + + int c_files() const + { + return reverse(mc_files); + } + + int cb_header() const + { + return reverse(mcb_header); + } +}; + +struct t_big_index_entry +{ + __int32 offset; + __int32 size; +}; + +const int big_id = 'FGIB'; +const int big4_id = '4GIB'; + +struct t_cps_header +{ + unsigned __int16 size; + __int16 unknown; + unsigned __int16 image_size; + __int16 zero; + __int16 palet_size; +}; + +struct t_csf_header +{ + __int32 id; + __int32 flags1; + __int32 count1; + __int32 count2; + __int32 zero; + __int32 flags2; +}; + +const __int32 csf_file_id = 'CSF '; +const __int32 csf_label_id = 'LBL '; +const __int32 csf_string_id = 'STR '; +const __int32 csf_string_w_id = 'STRW'; + +struct t_fnt_header +{ + unsigned __int16 size; + __int16 id1; + __int16 id2; + __int16 id3; + unsigned __int16 cx_ofs; + unsigned __int16 image_ofs; + unsigned __int16 cy_ofs; + __int16 id4; + __int8 zero; + unsigned __int8 c_chars; + __int8 cy; + __int8 cmax_x; +}; + +struct t_hva_header +{ + char id[16]; + __int32 c_frames; + __int32 c_sections; +}; + +using t_hva_transform_matrix = float[3][4]; + +struct t_jpeg_header +{ + __int8 unknown[6]; + __int8 id[4]; +}; + +const char jpeg_id[] = "JFIF"; + +union t_mix_header +{ + struct + { + __int16 c_files; + __int32 size; + }; + __int32 flags; +}; + +const int mix_checksum = 0x00010000; +const int mix_encrypted = 0x00020000; +const int cb_mix_key = 56; +const int cb_mix_key_source = 80; +const int cb_mix_checksum = 20; + +struct t_mix_index_entry +{ + t_mix_index_entry() = default; + + t_mix_index_entry(unsigned int id_, int offset_, int size_) + { + id = id_; + offset = offset_; + size = size_; + } + + unsigned __int32 id; + __int32 offset; + __int32 size; +}; + +struct t_mix_rg_header +{ + __int32 id; + __int32 index_offset; + __int32 tailer_offset; + __int32 zero; +}; + +struct t_mix_rg_index_entry +{ + __int32 id; + __int32 offset; + __int32 size; +}; + +const int mix_rg_id = '1XIM'; + +struct t_iso_map_pack_entry +{ + unsigned __int16 x; + unsigned __int16 y; + __int16 tile; + unsigned __int8 zero1; + unsigned __int8 zero2; + unsigned __int8 sub_tile; + unsigned __int8 z; + unsigned __int8 zero3; +}; + +struct t_ogg_header +{ + __int8 id[4]; +}; + +const char ogg_id[] = "OggS"; + +struct t_pack_section_header +{ + unsigned __int16 size_in; + unsigned __int16 size_out; +}; + +struct t_pcx_header +{ + __int8 manufacturer; + __int8 version; + __int8 encoding; + __int8 cbits_pixel; + __int16 xmin; + __int16 ymin; + __int16 xmax; + __int16 ymax; + __int16 cx_inch; + __int16 cy_inch; + __int8 colorpap[16][3]; + __int8 reserved; + __int8 c_planes; + __int16 cb_line; + __int8 filler[60]; +}; + +struct t_png_header +{ + __int8 id[8]; +}; + +const char png_id[] = "\x89PNG\r\n\x1A\n"; + +struct t_shp_dune2_header +{ + __int16 c_images; +}; + +struct t_shp_dune2_image_header +{ + __int16 compression; + unsigned __int8 cy; + unsigned __int16 cx; + unsigned __int8 cy2; + unsigned __int16 size_in; + unsigned __int16 size_out; +}; + +struct t_shp_header +{ + __int16 c_images; + __int16 unknown1; + __int16 unknown2; + __int16 cx; + __int16 cy; + __int32 unknown3; +}; + +struct t_shp_ts_header +{ + __int16 zero; + __int16 cx; + __int16 cy; + __int16 c_images; +}; + +struct t_shp_ts_image_header +{ + __int16 x; + __int16 y; + __int16 cx; + __int16 cy; + __int32 compression; + __int32 unknown; + __int32 zero; + __int32 offset; +}; + +struct t_tga_header +{ + byte id_size; + byte map_t; + byte image_t; + unsigned __int16 map_first; + unsigned __int16 map_size; + byte map_entry_size; + unsigned __int16 x; + unsigned __int16 y; + unsigned __int16 cx; + unsigned __int16 cy; + byte cb_pixel; + byte alpha:4; + byte horizontal:1; + byte vertical:1; +}; + +struct t_tmp_header +{ + __int16 cx; + __int16 cy; + __int16 c_tiles; + __int16 zero1; + __int32 size; + __int32 image_offset; + __int32 zero2; + __int32 id; + __int32 index2; + __int32 index1; +}; + +struct t_tmp_ra_header +{ + __int16 cx; + __int16 cy; + __int16 c_tiles; + __int16 zero1; + __int16 cblocks_x; + __int16 cblocks_y; + __int32 size; + __int32 image_offset; + __int32 zero2; + __int32 unknown1; + __int32 index2; + __int32 unknown2; + __int32 index1; +}; + +struct t_tmp_ts_header +{ + __int32 cblocks_x; + __int32 cblocks_y; + __int32 cx; + __int32 cy; +}; + +struct t_tmp_image_header +{ + __int32 x; + __int32 y; + __int32 extra_ofs; + __int32 z_ofs; + __int32 extra_z_ofs; + __int32 x_extra; + __int32 y_extra; + __int32 cx_extra; + __int32 cy_extra; + unsigned int has_extra_data: 1; + unsigned int has_z_data: 1; + unsigned int has_damaged_data: 1; + __int8 height; + __int8 terrain_type; + __int8 ramp_type; + unsigned __int8 radar_red_left; + unsigned __int8 radar_green_left; + unsigned __int8 radar_blue_left; + unsigned __int8 radar_red_right; + unsigned __int8 radar_green_right; + unsigned __int8 radar_blue_right; + __int8 pad[3]; +}; + +struct t_voc_header +{ + char id[20]; + __int16 offset; + __int32 version; +}; + +struct t_voc_sound_data_header +{ + unsigned __int8 samplerate; + __int8 compression; +}; + +const char voc_id[] = "Creative Voice File\x1a"; + +struct t_vqa_chunk_header +{ + __int32 id; + __int32 size; +}; + +struct t_vqa_header +{ + t_vqa_chunk_header file_header; + // 'FORM' + __int64 id; + // 'WVQAVQHD' + __int32 startpos; + __int16 version; + __int16 video_flags; + __int16 c_frames; + __int16 cx; + __int16 cy; + __int8 cx_block; + __int8 cy_block; + __int16 unknown3; + __int16 c_colors; + __int16 cb_max_cbp_chunk; + __int32 unknown4; + __int16 unknown5; + unsigned __int16 samplerate; + __int8 c_channels; + __int8 cbits_sample; + __int8 unknown6[14]; +}; + +const __int32 vqa_c_mask = 0xff000000; +const __int32 vqa_t_mask = 0x00ffffff; +const __int32 vqa_file_id = *(__int32*)"FORM"; +const __int64 vqa_form_id = {*(__int64*)"WVQAVQHD"}; +const __int32 vqa_cbf_id = *(__int32*)"CBF\0"; +const __int32 vqa_cbp_id = *(__int32*)"CBP\0"; +const __int32 vqa_cpl_id = *(__int32*)"CPL\0"; +const __int32 vqa_finf_id = *(__int32*)"FINF"; +const __int32 vqa_sn2j_id = *(__int32*)"SN2J"; +const __int32 vqa_snd_id = *(__int32*)"SND\0"; +const __int32 vqa_vpt_id = *(__int32*)"VPT\0"; +const __int32 vqa_vpr_id = *(__int32*)"VPR\0"; +const __int32 vqa_vqfl_id = *(__int32*)"VQFL"; +const __int32 vqa_vqfr_id = *(__int32*)"VQFR"; + +struct t_vqp_header +{ + unsigned __int32 c_tables; +}; + +struct t_vxl_header +{ + char id[16]; + __int32 one; + unsigned __int32 c_section_headers; + unsigned __int32 c_section_tailers; + unsigned __int32 size; + __int16 unknown; + t_palet palet; +}; + +struct t_vxl_section_header +{ + char id[16]; + __int32 section_i; + __int32 one; + __int32 zero; +}; + +struct t_vxl_section_tailer +{ + __int32 span_start_ofs; + __int32 span_end_ofs; + __int32 span_data_ofs; + float scale; + float transform[3][4]; + float x_min_scale; + float y_min_scale; + float z_min_scale; + float x_max_scale; + float y_max_scale; + float z_max_scale; + unsigned __int8 cx; + unsigned __int8 cy; + unsigned __int8 cz; + __int8 unknown; +}; + +const char vxl_id[] = "Voxel Animation"; + +struct t_w3d_header +{ + __int32 id; + __int32 m_size; + + bool container() const + { + return m_size & 0x80000000; + } + + int size() const + { + return m_size & ~0x80000000; + } +}; + +struct t_wsa_dune2_header +{ + __int16 c_frames; + __int16 cx; + __int16 cy; + __int16 delta; +}; + +struct t_wsa_header +{ + __int16 c_frames; + __int16 x; + __int16 y; + __int16 cx; + __int16 cy; + __int32 delta; +}; + +struct t_xcc_header +{ + char id[32]; + __int32 size; + __int32 type; + __int32 version; +}; + +const char xcc_id[] = "XCC by Olaf van der Spek\x1a\x04\x17\x27\x10\x19\x80"; + +struct t_xcc_lmd_header +{ + __int32 game; + __int32 c_fnames; +}; + +#pragma pack(pop) diff --git a/3rdParty/xcc/misc/crc.h b/3rdParty/xcc/misc/crc.h new file mode 100644 index 0000000..9a68d52 --- /dev/null +++ b/3rdParty/xcc/misc/crc.h @@ -0,0 +1,28 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <boost/crc.hpp> + +inline int compute_crc(const void* d, int cb_d) +{ + boost::crc_32_type crc; + crc.process_bytes(d, cb_d); + return crc(); +} diff --git a/3rdParty/xcc/misc/ddpf_conversion.cpp b/3rdParty/xcc/misc/ddpf_conversion.cpp new file mode 100644 index 0000000..6581bdc --- /dev/null +++ b/3rdParty/xcc/misc/ddpf_conversion.cpp @@ -0,0 +1,72 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "ddpf_conversion.h" + +static int get_shift(unsigned int v) +{ + if (!v) + return 0; + int r = 0; + while (~v & 1) + { + r++; + v >>= 1; + } + return r; +} + +static int get_size(unsigned int v) +{ + int r = 0; + while (v) + { + if (v & 1) + r++; + v >>= 1; + } + return r; +} + +void Cddpf_conversion::set_pf(const DDPIXELFORMAT& pf) +{ + a_shift = get_shift(pf.dwRGBAlphaBitMask); + r_shift = get_shift(pf.dwRBitMask); + g_shift = get_shift(pf.dwGBitMask); + b_shift = get_shift(pf.dwBBitMask); + a_size = get_size(pf.dwRGBAlphaBitMask); + r_size = get_size(pf.dwRBitMask); + g_size = get_size(pf.dwGBitMask); + b_size = get_size(pf.dwBBitMask); +} + +int Cddpf_conversion::get_color(int a, int r, int g, int b) +{ + return a >> (8 - a_size) << a_shift | r >> (8 - r_size) << r_shift | g >> (8 - g_size) << g_shift | b >> (8 - b_size) << b_shift; +} + +int Cddpf_conversion::get_color(int r, int g, int b) +{ + return get_color(0, r, g, b); +} + +int Cddpf_conversion::get_color(int v) +{ + return get_color(v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff); +} diff --git a/3rdParty/xcc/misc/ddpf_conversion.h b/3rdParty/xcc/misc/ddpf_conversion.h new file mode 100644 index 0000000..3aab406 --- /dev/null +++ b/3rdParty/xcc/misc/ddpf_conversion.h @@ -0,0 +1,33 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <ddraw.h> + +class Cddpf_conversion +{ +public: + int get_color(int a, int r, int g, int b); + int get_color(int r, int g, int b); + int get_color(int v); + void set_pf(const DDPIXELFORMAT& pf); +private: + int a_shift, r_shift, g_shift, b_shift; + int a_size, r_size, g_size, b_size; +}; \ No newline at end of file diff --git a/3rdParty/xcc/misc/file32.cpp b/3rdParty/xcc/misc/file32.cpp new file mode 100644 index 0000000..e895bfe --- /dev/null +++ b/3rdParty/xcc/misc/file32.cpp @@ -0,0 +1,153 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "file32.h" + +int Cfile32::open(const Cwin_handle& h) +{ + m_h = h; + m_p = 0; + return !is_open(); +} + +int Cfile32::open(const string& name, int access) +{ + return access & GENERIC_WRITE ? open(name, access, CREATE_ALWAYS, 0) : open(name, access, OPEN_EXISTING, FILE_SHARE_READ); +} + +int Cfile32::open(const string& name, int access, int creation, int share) +{ + m_h = Cwin_handle(CreateFileA(name.c_str(), access, share, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL)); + m_p = 0; + return !is_open(); +} + +FILETIME Cfile32::get_creation_time() const +{ + assert(is_open()); + FILETIME time; + int r = GetFileTime(h(), &time, NULL, NULL); + assert(r); + return time; +} + +FILETIME Cfile32::get_last_access_time() const +{ + assert(is_open()); + FILETIME time; + int r = GetFileTime(h(), NULL, &time, NULL); + assert(r); + return time; +} + +FILETIME Cfile32::get_last_write_time() const +{ + assert(is_open()); + FILETIME time; + int r = GetFileTime(h(), NULL, NULL, &time); + assert(r); + return time; +} + +int Cfile32::open_read(const string& name) +{ + return open(name, GENERIC_READ, OPEN_EXISTING, FILE_SHARE_READ); +} + +int Cfile32::open_edit(const string& name) +{ + return open(name, GENERIC_READ | GENERIC_WRITE, OPEN_ALWAYS, 0); +} + +int Cfile32::open_write(const string& name) +{ + return open(name, GENERIC_WRITE, CREATE_ALWAYS, 0); +} + +long long Cfile32::size() const +{ + assert(is_open()); + LARGE_INTEGER v; + return GetFileSizeEx(h(), &v) ? v.QuadPart : -1; +} + +int Cfile32::read(void* data, int size) +{ + assert(is_open()); + if (SetFilePointer(h(), m_p, 0, FILE_BEGIN) == -1) + return 1; + DWORD cb_read; + if (!ReadFile(h(), data, size, &cb_read, 0) || cb_read != size) + return 1; + m_p += size; + return 0; +} + +int Cfile32::write(const void* data, int size) +{ + assert(is_open()); + if (SetFilePointer(h(), m_p, 0, FILE_BEGIN) == -1) + return 1; + DWORD cb_write; + if (!WriteFile(h(), data, size, &cb_write, 0) || cb_write != size) + return 1; + m_p += size; + return 0; +} + +int Cfile32::write(data_ref v) +{ + return write(v.data(), v.size()); +}; + +int Cfile32::set_eof() +{ + assert(is_open()); + if (SetFilePointer(h(), m_p, 0, FILE_BEGIN) == -1) + return 1; + return !SetEndOfFile(h()); +} + +void Cfile32::close() +{ + m_h.clear(); +} + +Cvirtual_binary Cfile32::get_mm() +{ + if (!size()) + return Cvirtual_binary(); + Cwin_handle mh(CreateFileMapping(h(), NULL, PAGE_READONLY, 0, 0, NULL)); + void* d = mh ? MapViewOfFile(mh, FILE_MAP_READ, 0, 0, 0) : NULL; + return d ? Cvirtual_binary(d, size(), std::shared_ptr<void>(d, UnmapViewOfFile)) : Cvirtual_binary(); +} + +Cvirtual_binary file32_read(const string& name) +{ + Cfile32 f; + return f.open_read(name) ? Cvirtual_binary() : f.get_mm(); +} + +int file32_write(const string& name, const void* s, int cb_s) +{ + Cfile32 f; + if (int error = f.open_write(name)) + return error; + return f.write(s, cb_s); +} diff --git a/3rdParty/xcc/misc/file32.h b/3rdParty/xcc/misc/file32.h new file mode 100644 index 0000000..7e2cbfc --- /dev/null +++ b/3rdParty/xcc/misc/file32.h @@ -0,0 +1,83 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <string> +#include <vartypes.h> +#include <virtual_binary.h> +#include "win_handle.h" + +using namespace std; + +class Cfile32 +{ +public: + Cvirtual_binary get_mm(); + int open(const Cwin_handle& h); + int open(const string& name, int access); + int open(const string& name, int access, int creation, int share); + int open_read(const string& name); + int open_edit(const string& name); + int open_write(const string& name); + long long size() const; + FILETIME get_creation_time() const; + FILETIME get_last_access_time() const; + FILETIME get_last_write_time() const; + int read(void* data, int size); + int write(const void* data, int size); + int write(data_ref); + int set_eof(); + void close(); + + bool eof() const + { + return m_p >= size(); + } + + const Cwin_handle& h() const + { + return m_h; + } + + bool is_open() const + { + return h(); + } + + int get_p() const + { + return m_p; + } + + void seek(int p) + { + m_p = p; + } + + void skip(int p) + { + m_p += p; + } +private: + Cwin_handle m_h; + int m_p; +}; + +Cvirtual_binary file32_read(const string& name); +int file32_write(const string& name, const void* s, int cb_s); diff --git a/3rdParty/xcc/misc/fname.cpp b/3rdParty/xcc/misc/fname.cpp new file mode 100644 index 0000000..04654b5 --- /dev/null +++ b/3rdParty/xcc/misc/fname.cpp @@ -0,0 +1,217 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "fname.h" + +Cfname::Cfname(const string& s) +{ + *this = string_view(s); +} + +string Cfname::get_fname() const +{ + return title + ext; +} + +string Cfname::get_ftitle() const +{ + return title; +} + +string Cfname::get_fext() const +{ + return ext; +} + +string Cfname::get_path() const +{ + return path; +} + +string Cfname::get_all() const +{ + return path + title + ext; +} + +/* +void Cfname::expand() +{ + char t[MAX_PATH]; + _fullpath(t, get_all().c_str(), MAX_PATH); + Cfname(<string>(t)); +} +*/ + +Cfname GetModuleFileName(HMODULE hModule) +{ + char s[MAX_PATH]; + if (GetModuleFileNameA(hModule, s, MAX_PATH)) + return Cfname(s); + return {}; +} + +string get_temp_path() +{ + char temp_dir[MAX_PATH]; + return GetTempPathA(MAX_PATH, temp_dir) ? temp_dir : ".\\"; +} + +string get_temp_fname(string path) +{ + char temp_fname[MAX_PATH]; + return GetTempFileNameA(path.c_str(), "XCC", 0, temp_fname) ? temp_fname : ""; +} + +string get_temp_fname() +{ + return get_temp_fname(get_temp_path()); +} + +void Cfname::set_title(string_view s) +{ + title = s; +} + +void Cfname::set_ext(string_view s) +{ + ext = s; +} + +void Cfname::use_default_ext(string_view s) +{ + if (ext == "") + ext = s; +} + +void Cfname::set_path(string_view s) +{ + path = s; + if (!path.empty() && path[path.length() - 1] != '\\') + path += '\\'; +} + +void Cfname::use_default_path(string_view s) +{ + if (path.empty()) + set_path(s); +} + +void Cfname::make_path() +{ + if ((title + ext).empty()) + return; + path += title + ext + '\\'; + title = ext = ""; +} + +bool Cfname::exists() const +{ + HANDLE h; + WIN32_FIND_DATAA d; + h = FindFirstFileA(get_all().c_str(), &d); + if (h == INVALID_HANDLE_VALUE) + return false; + FindClose(h); + return true; +} + +const Cfname& Cfname::operator=(string_view s) +{ + long p1 = s.rfind('\\'); + long p2 = s.rfind('.'); + char t[MAX_PATH]; + if (p1 != string::npos) + { + //copy last \ also + t[s.copy(t, p1 + 1)] = 0; + path = t; + } + t[s.copy(t, p2 - p1 - 1, p1 + 1)] = 0; + title = t; + if (p2 != s.npos && p1 < p2) + { + t[s.copy(t, s.npos, p2)] = 0; + ext = t; + } + return *this; +} + +string operator+(const string& a, const Cfname& b) +{ + return a + static_cast<string>(b); +} + +int create_dir(const string& dir) +{ + return !CreateDirectoryA(dir.c_str(), NULL); +} + +void create_deep_dir(string dir, const string& name) +{ + int a = 0; + int b; + while ((b = name.find_first_of("/\\", a)) != string::npos) + { + dir += '/' + name.substr(a, b - a); + create_dir(dir); + a = b + 1; + } +} + +int copy_file(string s, string d) +{ + return !CopyFileA(s.c_str(), d.c_str(), false); +} + +int delete_file(string fname) +{ + return !DeleteFileA(fname.c_str()); +} + +int move_file(string s, string d) +{ + return !MoveFileA(s.c_str(), d.c_str()); +} + +bool fname_filter(const string& fname, const string& filter) +{ + size_t i; + for (i = 0; i < filter.size(); i++) + { + char c = filter[i]; + if (c == '*') + { + if (filter.find('*', i + 1) == string::npos) + { + int j = fname.length() - filter.length() + 1; + return j < 0 ? false : fname_filter(fname.substr(i + j), filter.substr(i + 1)); + } + // for (int j = 0; j < min(fname.length(), filter.length()) - i; j++) + for (size_t j = 0; j < fname.size(); j++) + { + if (fname_filter(fname.substr(i + j), filter.substr(i + 1))) + return true; + } + return false; + } + if (c != '?' && c != fname[i]) + return false; + } + return fname.length() == i; +} diff --git a/3rdParty/xcc/misc/fname.h b/3rdParty/xcc/misc/fname.h new file mode 100644 index 0000000..ded5594 --- /dev/null +++ b/3rdParty/xcc/misc/fname.h @@ -0,0 +1,66 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <string> +#include <windows.h> + +using namespace std; + +class Cfname +{ +private: + string path; + string title; + string ext; +public: + const Cfname& operator=(string_view); + bool exists() const; + void make_path(); + void use_default_ext(string_view); + void use_default_path(string_view); + void set_ext(string_view); + void set_path(string_view); + void set_title(string_view); + void expand(); + string get_all() const; + string get_path() const; + string get_fname() const; + string get_ftitle() const; + string get_fext() const; + Cfname() = default; + Cfname(const string&); + + operator string() const + { + return get_all(); + } +}; + +Cfname GetModuleFileName(HMODULE hModule = 0); +bool fname_filter(const string& fname, const string& filter); +int create_dir(const string& dir); +void create_deep_dir(string dir, const string& name); +int delete_file(string fname); +int copy_file(string s, string d); +int move_file(string s, string d); +string get_temp_fname(string path); +string get_temp_path(); +string get_temp_fname(); +string operator+(const string& a, const Cfname& b); diff --git a/3rdParty/xcc/misc/hva_file.cpp b/3rdParty/xcc/misc/hva_file.cpp new file mode 100644 index 0000000..fc3b675 --- /dev/null +++ b/3rdParty/xcc/misc/hva_file.cpp @@ -0,0 +1,115 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "hva_file.h" + +#include <fstream> +#include "multi_line.h" +#include "virtual_tfile.h" + +bool Chva_file::is_valid() const +{ + const t_hva_header& h = header(); + int size = get_size(); + return !(sizeof(t_hva_header) > size + || !h.c_frames + || !h.c_sections + || sizeof(t_hva_header) + (48 * h.c_frames + 16) * h.c_sections != size); +} + +int Chva_file::extract_as_csv(const string& name) const +{ + ofstream f(name.c_str()); + const int c_frames = get_c_frames(); + const int c_sections = get_c_sections(); + f << "Count frames;" << c_frames << endl + << "Count sections;" << c_sections << endl + << endl; + for (int i = 0; i < c_sections; i++) + f << get_section_id(i) << ";;;;;"; + for (int j = 0; j < c_frames; j++) + { + f << endl; + for (int y = 0; y < 3; y++) + { + for (int i = 0; i < c_sections; i++) + { + for (int x = 0; x < 4; x++) + { + f << get_transform_matrix(i, j)[x + 4 * y] << ';'; + } + f << ';'; + } + f << endl; + } + } + return f.fail(); +} + +Cvirtual_binary hva_file_write(const byte* s, int cb_s) +{ + Cvirtual_binary d; + const char sep = ';'; + Cvirtual_tfile f; + f.load_data(Cvirtual_binary(s, cb_s)); + Cmulti_line l; + l = f.read_line(); + l.get_next_line(sep); + int c_frames = atoi(l.get_next_line(sep).c_str()); + l = f.read_line(); + l.get_next_line(sep); + int c_sections = atoi(l.get_next_line(sep).c_str()); + f.read_line(); + byte* w = d.write_start(64 << 10); + t_hva_header& header = *reinterpret_cast<t_hva_header*>(w); + strcpy(header.id, "NONE"); + header.c_frames = c_frames; + header.c_sections = c_sections; + w += sizeof(t_hva_header); + l = f.read_line(); + for (int i = 0; i < c_sections; i++) + { + strcpy(reinterpret_cast<char*>(w), l.get_next_line(sep).c_str()); + w += 16; + l.get_next_line(sep); + l.get_next_line(sep); + l.get_next_line(sep); + l.get_next_line(sep); + } + float* transform_matrix = reinterpret_cast<float*>(w); + for (int j = 0; j < c_frames; j++) + { + for (int y = 0; y < 3; y++) + { + l = f.read_line(); + for (int i = 0; i < c_sections; i++) + { + for (int x = 0; x < 4; x++) + { + transform_matrix[12 * (c_frames * i + j) + x + 4 * y] = atof(l.get_next_line(sep).c_str()); + } + l.get_next_line(sep); + } + } + f.read_line(); + } + w += 4 * 12 * c_frames * c_sections; + d.set_size(w - d.data()); + return d; +} diff --git a/3rdParty/xcc/misc/hva_file.h b/3rdParty/xcc/misc/hva_file.h new file mode 100644 index 0000000..63b789d --- /dev/null +++ b/3rdParty/xcc/misc/hva_file.h @@ -0,0 +1,51 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cc_file_sh.h> +#include <cc_structures.h> + +class Chva_file : public Ccc_file_sh<t_hva_header> +{ +public: + int extract_as_csv(const string& name) const; + bool is_valid() const; + + int get_c_frames() const + { + return header().c_frames; + } + + int get_c_sections() const + { + return header().c_sections; + } + + const char* get_section_id(int i) const + { + return reinterpret_cast<const char*>(data() + sizeof(t_hva_header) + 16 * i); + } + + const float* get_transform_matrix(int i, int j) const + { + return reinterpret_cast<const float*>(data() + sizeof(t_hva_header) + 16 * get_c_sections() + (get_c_frames() * i + j) * sizeof(t_hva_transform_matrix)); + } +}; + +Cvirtual_binary hva_file_write(const byte* s, int cb_s); diff --git a/3rdParty/xcc/misc/id_log.cpp b/3rdParty/xcc/misc/id_log.cpp new file mode 100644 index 0000000..ff55fcd --- /dev/null +++ b/3rdParty/xcc/misc/id_log.cpp @@ -0,0 +1,137 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include <id_log.h> + +#include <fstream> +#include <mix_file.h> +#include <string_conversion.h> +#include <xcc_dirs.h> + +struct t_idinfo +{ + string name; + string description; +}; + +using t_id_list = map<int, t_idinfo>; + +t_id_list td_list, ra_list, ts_list, dune2_list, ra2_list; + +static t_id_list& get_list(t_game game) +{ + switch (game) + { + case game_ra: + return ra_list; + case game_ts: + return ts_list; + case game_dune2: + return dune2_list; + case game_ra2: + return ra2_list; + } + return td_list; +} + +static void read_list(t_game game, const char*& s) +{ + t_id_list& d = get_list(game); + int count = *reinterpret_cast<const int*>(s); + s += 4; + t_idinfo idinfo; + while (count--) + { + idinfo.name = s; + s += idinfo.name.length() + 1; + idinfo.description = s; + s += idinfo.description.length() + 1; + d[Cmix_file::get_id(game, idinfo.name)] = idinfo; + } +} + +int mix_database::load() +{ + if (!td_list.empty() || !ra_list.empty() || !ts_list.empty()) + return 0; + Cvirtual_binary f; + if (f.load(xcc_dirs::get_data_dir() + "global mix database.dat") || f.size() < 16) + return 1; + const char* data = reinterpret_cast<const char*>(f.data()); + read_list(game_td, data); + read_list(game_ra, data); + read_list(game_ts, data); + read_list(game_ra2, data); + if (0) + { + ofstream log_f("c:\\log.txt"); + for (auto& i : ts_list) + log_f << i.second.name << '\t' << i.second.description << endl; + } + return 0; + char name[12] = "scg00ea.bin"; + const char char1[] = "bgjm"; + const char char2[] = "ew"; + const char char3[] = "abc"; + for (int i = 0; i < 2; i++) + { + if (i) + strcpy(name + 8, "ini"); + for (int j = 0; j < 4; j++) + { + name[2] = char1[j]; + for (int k = 0; k < 100; k++) + { + memcpy(name + 3, nwzl(2, k).c_str(), 2); + for (int l = 0; l < 2; l++) + { + name[5] = char2[l]; + for (int m = 0; m < 3; m++) + { + name[6] = char3[m]; + mix_database::add_name(game_td, name, ""); + mix_database::add_name(game_ra, name, ""); + mix_database::add_name(game_ts, name, ""); + } + } + } + } + } + return 0; +} + +void mix_database::add_name(t_game game, const string& name, const string& description) +{ + t_idinfo idinfo; + idinfo.name = name; + idinfo.description = description; + get_list(game)[Cmix_file::get_id(game, name)] = idinfo; +} + +string mix_database::get_name(t_game game, int id) +{ + auto i = find_ptr(get_list(game), id); + return i ? i->name : ""; +} + +string mix_database::get_description(t_game game, int id) +{ + auto i = find_ptr(get_list(game), id); + return i ? i->description : ""; +} diff --git a/3rdParty/xcc/misc/id_log.h b/3rdParty/xcc/misc/id_log.h new file mode 100644 index 0000000..c866f86 --- /dev/null +++ b/3rdParty/xcc/misc/id_log.h @@ -0,0 +1,30 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cc_structures.h> +#include <string> + +namespace mix_database +{ + void add_name(t_game, const std::string& name, const std::string& description); + std::string get_name(t_game, int id); + std::string get_description(t_game, int id); + int load(); +}; diff --git a/3rdParty/xcc/misc/image_file.h b/3rdParty/xcc/misc/image_file.h new file mode 100644 index 0000000..b9e9fb5 --- /dev/null +++ b/3rdParty/xcc/misc/image_file.h @@ -0,0 +1,52 @@ +/* + XCC Utilities and Library + Copyright (C) 2001 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "cc_structures.h" +#include "palet.h" +#include "video_file.h" +#include "virtual_file.h" +#include "virtual_image.h" + +template <class T> +class Cimage_file : public Cvideo_file<T> +{ +public: + virtual void decode(void*) const = 0; + +#ifndef XCC_MINIMAL_BUILD + virtual Cvirtual_image vimage() const + { + Cvirtual_binary image; + decode(image.write_start(this->cb_image())); + return Cvirtual_image(image, this->cx(), this->cy(), this->cb_pixel(), this->palet()); + } +#endif + + int cf() const override + { + return 1; + } +}; + +#ifndef XCC_MINIMAL_BUILD +int image_file_write(Cvirtual_file&, t_file_type, const byte* image, const t_palet_entry*, int cx, int cy); +Cvirtual_file image_file_write(t_file_type, const byte* image, const t_palet_entry*, int cx, int cy); +int image_file_write(const string& name, t_file_type, const byte* image, const t_palet_entry*, int cx, int cy); +#endif diff --git a/3rdParty/xcc/misc/mix_decode.cpp b/3rdParty/xcc/misc/mix_decode.cpp new file mode 100644 index 0000000..5dbfc4e --- /dev/null +++ b/3rdParty/xcc/misc/mix_decode.cpp @@ -0,0 +1,439 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include <memory> +#include <mix_decode.h> + +const static char* pubkey_str = "AihRvNoIbTn85FZRYNZRcT+i6KpU+maCsEqr3Q5q+LDB5tH7Tz2qQ38V"; + +const static char char2num[] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +using word = unsigned short; +using bignum = uint32_t[64]; + +static struct +{ + bignum key1; + bignum key2; + uint32_t len; +} pubkey; + +static bignum glob1; +static uint32_t glob1_bitlen; +static uint32_t glob1_len_x2; +static uint32_t glob2[130]; +static uint32_t glob1_hi[4]; +static uint32_t glob1_hi_inv[4]; +static uint32_t glob1_hi_bitlen; +static uint32_t glob1_hi_inv_lo; +static uint32_t glob1_hi_inv_hi; + +static void init_bignum(bignum n, uint32_t val, uint32_t len) +{ + memset(n, 0, len * 4); + n[0] = val; +} + +static void move_key_to_big(bignum n, const char* key, uint32_t klen, uint32_t blen) +{ + uint32_t sign = key[0] & 0x80 ? 0xff : 0; + int i = blen * 4; + for (; i > klen; i--) + ((char *)n)[i - 1] = sign; + for (; i > 0; i--) + ((char *)n)[i - 1] = key[klen - i]; +} + +static void key_to_bignum(bignum n, char *key, uint32_t len) +{ + uint32_t keylen; + int i; + + if (key[0] != 2) + return; + key++; + + if (key[0] & 0x80) + { + keylen = 0; + for (i = 0; i < (key[0] & 0x7f); i++) keylen = (keylen << 8) | key[i+1]; + key += (key[0] & 0x7f) + 1; + } + else + { + keylen = key[0]; + key++; + } + if (keylen <= len * 4) + move_key_to_big(n, key, keylen, len); +} + +static uint32_t len_bignum(bignum n, uint32_t len) +{ + int i = len - 1; + while (i >= 0 && n[i] == 0) + i--; + return i + 1; +} + +static uint32_t bitlen_bignum(bignum n, uint32_t len) +{ + uint32_t ddlen = len_bignum(n, len); + if (ddlen == 0) + return 0; + uint32_t bitlen = ddlen * 32; + uint32_t mask = 0x80000000; + while ((mask & n[ddlen - 1]) == 0) + { + mask >>= 1; + bitlen--; + } + return bitlen; +} + +static void init_pubkey() +{ + init_bignum(pubkey.key2, 0x10001, 64); + char keytmp[256]; + uint32_t i2 = 0; + for (uint32_t i = 0; i < strlen(pubkey_str);) + { + uint32_t tmp = char2num[pubkey_str[i++]]; + tmp <<= 6; tmp |= char2num[pubkey_str[i++]]; + tmp <<= 6; tmp |= char2num[pubkey_str[i++]]; + tmp <<= 6; tmp |= char2num[pubkey_str[i++]]; + keytmp[i2++] = (tmp >> 16) & 0xff; + keytmp[i2++] = (tmp >> 8) & 0xff; + keytmp[i2++] = tmp & 0xff; + } + key_to_bignum(pubkey.key1, keytmp, 64); + pubkey.len = bitlen_bignum(pubkey.key1, 64) - 1; +} + +static uint32_t len_predata() +{ + uint32_t a = (pubkey.len - 1) / 8; + return (55 / a + 1) * (a + 1); +} + +static int cmp_bignum(bignum n1, bignum n2, uint32_t len) +{ + n1 += len - 1; + n2 += len - 1; + while (len > 0) + { + if (*n1 < *n2) return -1; + if (*n1 > *n2) return 1; + n1--; + n2--; + len--; + } + return 0; +} + +static void mov_bignum(bignum dest, bignum src, uint32_t len) +{ + memmove(dest, src, len * 4); +} + +static void shr_bignum(bignum n, uint32_t bits, long int len) +{ + uint32_t i; + if (uint32_t i2 = bits / 32) + { + for (i = 0; i < len - i2; i++) + n[i] = n[i + i2]; + for (; i < len; i++) + n[i] = 0; + bits %= 32; + } + if (!bits) + return; + for (i = 0; i < len - 1; i++) + n[i] = (n[i] >> bits) | (n[i + 1] << (32 - bits)); + n[i] >>= bits; +} + +static void shl_bignum(bignum n, uint32_t bits, uint32_t len) +{ + uint32_t i; + if (uint32_t i2 = bits / 32) + { + for (i = len - 1; i > i2; i--) + n[i] = n[i - i2]; + for (; i > 0; i--) + n[i] = 0; + bits %= 32; + } + if (!bits) + return; + for (i = len - 1; i > 0; i--) + n[i] = (n[i] << bits) | (n[i - 1] >> (32 - bits)); + n[0] <<= bits; +} + +static uint32_t sub_bignum(bignum dest, bignum src1, bignum src2, uint32_t carry, uint32_t len) +{ + len *= 2; + while (--len != -1) + { + uint32_t i1 = *(word *)src1; + uint32_t i2 = *(word *)src2; + *(word *)dest = i1 - i2 - carry; + src1 = (uint32_t *)(((word *)src1) + 1); + src2 = (uint32_t *)(((word *)src2) + 1); + dest = (uint32_t *)(((word *)dest) + 1); + carry = ((i1 - i2 - carry) & 0x10000) ? 1 : 0; + } + return carry; +} + +static void inv_bignum(bignum n1, bignum n2, uint32_t len) +{ + bignum n_tmp; + + init_bignum(n_tmp, 0, len); + init_bignum(n1, 0, len); + int n2_bitlen = bitlen_bignum(n2, len); + uint32_t bit = ((uint32_t)1) << (n2_bitlen % 32); + n1 += ((n2_bitlen + 32) / 32) - 1; + uint32_t n2_bytelen = ((n2_bitlen - 1) / 32) * 4; + n_tmp[n2_bytelen / 4] |= ((uint32_t)1) << ((n2_bitlen - 1) & 0x1f); + + while (n2_bitlen > 0) + { + n2_bitlen--; + shl_bignum(n_tmp, 1, len); + if (cmp_bignum(n_tmp, n2, len) != -1) + { + sub_bignum(n_tmp, n_tmp, n2, 0, len); + *n1 |= bit; + } + bit >>= 1; + if (bit == 0) + { + n1--; + bit = 0x80000000; + } + } + init_bignum(n_tmp, 0, len); +} + +static void inc_bignum(bignum n, uint32_t len) +{ + while ((++*n == 0) && (--len > 0)) + n++; +} + +static void init_two_dw(bignum n, uint32_t len) +{ + mov_bignum(glob1, n, len); + glob1_bitlen = bitlen_bignum(glob1, len); + glob1_len_x2 = (glob1_bitlen + 15) / 16; + mov_bignum(glob1_hi, glob1 + len_bignum(glob1, len) - 2, 2); + glob1_hi_bitlen = bitlen_bignum(glob1_hi, 2) - 32; + shr_bignum(glob1_hi, glob1_hi_bitlen, 2); + inv_bignum(glob1_hi_inv, glob1_hi, 2); + shr_bignum(glob1_hi_inv, 1, 2); + glob1_hi_bitlen = (glob1_hi_bitlen + 15) % 16 + 1; + inc_bignum(glob1_hi_inv, 2); + if (bitlen_bignum(glob1_hi_inv, 2) > 32) + { + shr_bignum(glob1_hi_inv, 1, 2); + glob1_hi_bitlen--; + } + glob1_hi_inv_lo = *(word *)glob1_hi_inv; + glob1_hi_inv_hi = *(((word *)glob1_hi_inv) + 1); +} + +static void mul_bignum_word(bignum n1, bignum n2, uint32_t mul, uint32_t len) +{ + uint32_t tmp = 0; + for (uint32_t i = 0; i < len; i++) + { + tmp = mul * (*(word *)n2) + *(word *)n1 + tmp; + *(word *)n1 = tmp; + n1 = (uint32_t *)(((word *)n1) + 1); + n2 = (uint32_t *)(((word *)n2) + 1); + tmp >>= 16; + } + *(word *)n1 += tmp; +} + +static void mul_bignum(bignum dest, bignum src1, bignum src2, uint32_t len) +{ + init_bignum(dest, 0, len * 2); + for (uint32_t i = 0; i < len * 2; i++) + { + mul_bignum_word(dest, src1, *(word *)src2, len * 2); + src2 = (uint32_t *)(((word *)src2) + 1); + dest = (uint32_t *)(((word *)dest) + 1); + } +} + +static void not_bignum(bignum n, uint32_t len) +{ + for (uint32_t i = 0; i < len; i++) + *(n++) = ~*n; +} + +static void neg_bignum(bignum n, uint32_t len) +{ + not_bignum(n, len); + inc_bignum(n, len); +} + +static uint32_t get_mulword(bignum n) +{ + word* wn = (word *)n; + uint32_t i = (((((((((*(wn - 1) ^ 0xffff) & 0xffff) * glob1_hi_inv_lo + 0x10000) >> 1) + + (((*(wn-2) ^ 0xffff) * glob1_hi_inv_hi + glob1_hi_inv_hi) >> 1) + 1) + >> 16) + ((((*(wn-1) ^ 0xffff) & 0xffff) * glob1_hi_inv_hi) >> 1) + + (((*wn ^ 0xffff) * glob1_hi_inv_lo) >> 1) + 1) >> 14) + glob1_hi_inv_hi + * (*wn ^ 0xffff) * 2) >> glob1_hi_bitlen; + if (i > 0xffff) + i = 0xffff; + return i & 0xffff; +} + +static void dec_bignum(bignum n, uint32_t len) +{ + while ((--*n == 0xffffffff) && (--len > 0)) + n++; +} + +static void calc_a_bignum(bignum n1, bignum n2, bignum n3, uint32_t len) +{ + mul_bignum(glob2, n2, n3, len); + glob2[len * 2] = 0; + uint32_t g2_len_x2 = len_bignum(glob2, len * 2 + 1) * 2; + if (g2_len_x2 >= glob1_len_x2) + { + inc_bignum(glob2, len * 2 + 1); + neg_bignum(glob2, len * 2 + 1); + uint32_t len_diff = g2_len_x2 + 1 - glob1_len_x2; + word* esi = ((word *)glob2) + (1 + g2_len_x2 - glob1_len_x2); + word* edi = ((word *)glob2) + (g2_len_x2 + 1); + for (; len_diff != 0; len_diff--) + { + edi--; + word tmp = get_mulword((uint32_t *)edi); + esi--; + if (tmp > 0) + { + mul_bignum_word((uint32_t *)esi, glob1, tmp, 2 * len); + if ((*edi & 0x8000) == 0) + { + if (sub_bignum((uint32_t *)esi, (uint32_t *)esi, glob1, 0, len)) + (*edi)--; + } + } + } + neg_bignum(glob2, len); + dec_bignum(glob2, len); + } + mov_bignum(n1, glob2, len); +} + +static void calc_a_key(bignum n1, bignum n2, bignum n3, bignum n4, uint32_t len) +{ + bignum n_tmp; + init_bignum(n1, 1, len); + uint32_t n4_len = len_bignum(n4, len); + init_two_dw(n4, n4_len); + uint32_t n3_bitlen = bitlen_bignum(n3, n4_len); + uint32_t n3_len = (n3_bitlen + 31) / 32; + uint32_t bit_mask = (((uint32_t)1) << ((n3_bitlen - 1) % 32)) >> 1; + n3 += n3_len - 1; + n3_bitlen--; + mov_bignum(n1, n2, n4_len); + while (--n3_bitlen != -1) + { + if (bit_mask == 0) + { + bit_mask = 0x80000000; + n3--; + } + calc_a_bignum(n_tmp, n1, n1, n4_len); + if (*n3 & bit_mask) + calc_a_bignum(n1, n_tmp, n2, n4_len); + else + mov_bignum(n1, n_tmp, n4_len); + bit_mask >>= 1; + } + init_bignum(n_tmp, 0, n4_len); + init_bignum(glob1, 0, len); + init_bignum(glob2, 0, len); + init_bignum(glob1_hi_inv, 0, 4); + init_bignum(glob1_hi, 0, 4); + glob1_bitlen = 0; + glob1_hi_bitlen = 0; + glob1_len_x2 = 0; + glob1_hi_inv_lo = 0; + glob1_hi_inv_hi = 0; +} + +static void process_predata(const byte* pre, uint32_t pre_len, byte *buf) +{ + bignum n2, n3; + const uint32_t a = (pubkey.len - 1) / 8; + while (a + 1 <= pre_len) + { + init_bignum(n2, 0, 64); + memmove(n2, pre, a + 1); + calc_a_key(n3, n2, pubkey.key2, pubkey.key1, 64); + + memmove(buf, n3, a); + + pre_len -= a + 1; + pre += a + 1; + buf += a; + } +} + +void get_blowfish_key(const byte* s, span<byte> d) +{ + static bool public_key_initialized = false; + if (!public_key_initialized) + { + init_pubkey(); + public_key_initialized = true; + } + byte key[256]; + process_predata(s, len_predata(), key); + memcpy(d.data(), key, 56); +} diff --git a/3rdParty/xcc/misc/mix_decode.h b/3rdParty/xcc/misc/mix_decode.h new file mode 100644 index 0000000..388f8ed --- /dev/null +++ b/3rdParty/xcc/misc/mix_decode.h @@ -0,0 +1,21 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +void get_blowfish_key(const byte* s, span<byte> d); diff --git a/3rdParty/xcc/misc/mix_file.cpp b/3rdParty/xcc/misc/mix_file.cpp new file mode 100644 index 0000000..874ff31 --- /dev/null +++ b/3rdParty/xcc/misc/mix_file.cpp @@ -0,0 +1,424 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include <stdafx.h> +#include "mix_file.h" + +#ifndef NO_FT_SUPPORT +#include "big_file.h" +#endif +#include "blowfish.h" +#include "crc.h" +#include "id_log.h" +#ifndef NO_FT_SUPPORT +#include "mix_cache.h" +#endif +#include "mix_decode.h" +#ifndef NO_FT_SUPPORT +#include "mix_rg_file.h" +#include "pak_file.h" +#endif +#include "string_conversion.h" +#include "xcc_lmd_file.h" + +bool Cmix_file::m_ft_support = false; + +Cmix_file::Cmix_file() : + Ccc_file(false) +{ +} + +bool Cmix_file::is_valid() +{ + const byte* data = get_data(); + if (!data) + return false; + const t_mix_header& header = *reinterpret_cast<const t_mix_header*>(data); + int size = get_size(); + if (sizeof(t_mix_header) > size) + return false; + if (header.c_files && sizeof(t_mix_header) + header.c_files * sizeof(t_mix_index_entry) + header.size == size) + return true; + if (header.flags & ~(mix_encrypted | mix_checksum)) + return false; + m_has_checksum = header.flags & mix_checksum; + m_is_encrypted = header.flags & mix_encrypted; + if (m_is_encrypted) + { + Cblowfish bf; + std::array<byte, cb_mix_key> key; + get_blowfish_key(data + 4, key); + bf.set_key(key); + byte e[8]; + bf.decipher(data + 84, e, 8); + t_mix_header* header = reinterpret_cast<t_mix_header*>(e); + if (!header->c_files || 84 + (sizeof(t_mix_header) + header->c_files * sizeof(t_mix_index_entry) + 7 & ~7) + header->size + (m_has_checksum ? 20 : 0) != size) + return false; + } + else + { + const t_mix_header* header = reinterpret_cast<const t_mix_header*>(data + 4); + if (!header->c_files || 4 + sizeof(t_mix_header) + header->c_files * sizeof(t_mix_index_entry) + header->size + (m_has_checksum ? 20 : 0) != size) + return false; + } + return true; +} + +#define test_fail(res) { int v = res; if (v) { close(); return v; }} + +int Cmix_file::post_open() +{ +#ifndef NO_FT_SUPPORT + bool index_read = false; + if (h()) + { + Cmix_rg_file f; + if (get_data()) + f.load(vdata()); + else + f.open(h()); + if (f.is_open() && f.is_valid()) + { + m_game = game_rg; + m_is_encrypted = m_has_checksum = false; + int c_files = f.get_c_files(); + m_index.resize(c_files); + for (int i = 0; i < c_files; i++) + { + string name = f.get_name(i); + mix_database::add_name(m_game, name, "-"); + m_index[i] = t_mix_index_entry(get_id(get_game(), name), f.get_offset(name), f.get_size(name)); + } + index_read = true; + } + else + { + Cbig_file f; + if (get_data()) + f.load(vdata()); + else + f.open(h()); + if (f.is_open() && f.is_valid()) + { + m_game = game_gr; + m_is_encrypted = m_has_checksum = false; + int c_files = f.get_c_files(); + m_index.resize(c_files); + for (int i = 0; i < c_files; i++) + { + string name = f.get_name(i); + mix_database::add_name(m_game, name, "-"); + m_index[i] = t_mix_index_entry(get_id(get_game(), name), f.get_offset(name), f.get_size(name)); + } + index_read = true; + } + } + } + if (!index_read) + { + Cpak_file f; + if (get_data()) + f.load(vdata()); + else + { + int size = min<int>(get_size(), 64 << 10); + Cvirtual_binary data; + test_fail(read(data.write_start(size), size)); + f.load(data, get_size()); + } + if (f.is_valid()) + { + m_game = game_dune2; + m_is_encrypted = m_has_checksum = false; + int c_files = f.get_c_files(); + if (c_files >> 12) + test_fail(1); + m_index.resize(c_files); + for (int i = 0; i < c_files; i++) + { + string name = f.get_name(i); + mix_database::add_name(m_game, name, "-"); + m_index[i] = t_mix_index_entry(get_id(get_game(), name), f.get_offset(name), f.get_size(name)); + } + index_read = true; + } + } + if (!index_read) +#endif + { + t_mix_header header; + seek(0); + test_fail(read(&header, sizeof(t_mix_header))); + if (header.c_files) + { + m_game = game_td; + m_is_encrypted = m_has_checksum = false; + int c_files = header.c_files; + int cb_index = c_files * sizeof(t_mix_index_entry); + if (header.c_files >> 12 || get_size() != 6 + cb_index + header.size) + test_fail(1); + m_index.resize(c_files); + test_fail(read(&m_index[0], cb_index)); + for (int i = 0; i < c_files; i++) + m_index[i].offset += 6 + cb_index; + } + else + { + m_has_checksum = header.flags & mix_checksum; + m_is_encrypted = header.flags & mix_encrypted; + bool aligned = true; + Cblowfish bf; + seek(4); + if (m_is_encrypted) + { + byte key_source[cb_mix_key_source]; + read(key_source, cb_mix_key_source); + std::array<byte, cb_mix_key> key; + get_blowfish_key(key_source, key); + bf.set_key(key); + byte e[8]; + read(e, 8); + bf.decipher(e, e, 8); + memcpy(&header, e, sizeof(t_mix_header)); + int c_files = header.c_files; + const int cb_index = c_files * sizeof(t_mix_index_entry); + const int cb_f = cb_index + 5 & ~7; + if (get_size() != 92 + cb_f + header.size + (m_has_checksum ? 20 : 0)) + test_fail(1); + if (c_files) + { + Cvirtual_binary f; + read(f.write_start(cb_f), cb_f); + bf.decipher(f.data_edit(), f.data_edit(), cb_f); + m_index.resize(c_files); + memcpy(&m_index[0], e + 6, 2); + memcpy(reinterpret_cast<byte*>(&m_index[0]) + 2, f.data(), cb_index - 2); + for (int i = 0; i < c_files; i++) + { + if (m_index[i].offset & 0xf) + aligned = false; + m_index[i].offset += 92 + cb_f; + } + } + } + else + { + read(&header, sizeof(header)); + int c_files = header.c_files; + const int cb_index = c_files * sizeof(t_mix_index_entry); + if (get_size() != 4 + sizeof(t_mix_header) + cb_index + header.size + (m_has_checksum ? 20 : 0)) + test_fail(1); + m_index.resize(c_files); + read(&m_index[0], cb_index); + for (int i = 0; i < c_files; i++) + { + if (m_index[i].offset & 0xf) + aligned = false; + m_index[i].offset += 4 + sizeof(t_mix_header) + cb_index; + } + } + m_game = is_encrypted() ? game_ra : game_ts; + for (int i = 0; i < get_c_files(); i++) + { + if (get_id(i) == 0x763c81dd) + { + m_game = game_ts; + break; + } + } + if (m_game == game_ra && aligned) + m_game = game_ts; + } + } + for (int i = 0; i < get_c_files(); i++) + m_id_index[get_id(i)] = i; +#ifndef NO_FT_SUPPORT + if (m_ft_support) + { + switch (m_game) + { + case game_dune2: + case game_rg: + break; + default: + int count[game_unknown] = {0}; + for (int i = 0; i < get_c_files(); i++) + { + int id = get_id(i); + for (int game = game_td; game < game_unknown; game++) + count[game] += mix_database::get_name(static_cast<t_game>(game), id).empty(); + } + int min = count[0]; + for (int game = 0; game < game_unknown; game++) + { + if (count[game] < min) + { + m_game = static_cast<t_game>(game); + min = count[game]; + } + } + } + if (vdata().size() == get_size()) + { + int crc = compute_crc(&m_index[0], get_c_files() * sizeof(t_mix_index_entry)); + Cvirtual_binary s = mix_cache::get_data(crc); + m_index_ft.resize(get_c_files()); + if (s.size() == get_c_files() * sizeof(t_file_type)) + memcpy(&m_index_ft[0], s.data(), get_c_files() * sizeof(t_file_type)); + else + { + using t_block_map = multimap<int, int>; + + t_block_map block_map; + for (int i = 0; i < get_c_files(); i++) + block_map.insert(t_block_map::value_type(get_offset(get_id(i)), i)); + for (auto& i : block_map) + { + Ccc_file f(false); + f.open(get_id(i.second), *this); + m_index_ft[i.second] = f.get_file_type(); + } + mix_cache::set_data(crc, Cvirtual_binary(&m_index_ft[0], get_c_files() * sizeof(t_file_type))); + } + for (int i = 0; i < get_c_files(); i++) + { + int id = get_id(i); + Cxcc_lmd_file f; + if (get_type(id) != ft_xcc_lmd || f.open(id, *this) || !f.is_valid()) + continue; + m_game = f.get_game(); + int count = f.get_c_fnames(); + const char* r = f.get_fnames(); + while (count--) + { + string name = r; + r += name.length() + 1; + mix_database::add_name(m_game, name, "-"); + } + } + } + } +#endif + if (m_mix_expansion) + { + int c_files = get_c_files(); + for (int i = 0; i < c_files; i++) + { + if (get_type(m_index[i].id) != ft_mix) + continue; + Cmix_file f; + f.open(m_index[i].id, *this); + int c_files = get_c_files(); + int new_c_files = f.get_c_files(); + m_index.resize(c_files + new_c_files); + for (int j = 0; j < new_c_files; j++) + { + int id = f.get_id(j); + m_index[c_files + j] = t_mix_index_entry(id, f.get_offset(id) + get_offset(m_index[i].id), f.get_size(id)); + m_id_index[id] = c_files + j; + } + m_index_ft.resize(c_files + new_c_files); + memcpy(&m_index_ft[c_files], &f.m_index_ft[0], new_c_files * sizeof(t_file_type)); + } + } + return 0; +} + +void Cmix_file::close() +{ + m_id_index.clear(); + m_index_ft.clear(); + m_index.clear(); + Ccc_file::close(); +} + +string Cmix_file::get_name(int id) +{ +#ifdef NO_FT_SUPPORT + return ""; +#else + return mix_database::get_name(get_game(), id); +#endif +} + +int Cmix_file::get_id(t_game game, string name) +{ + boost::to_upper(name); + std::replace(name.begin(), name.end(), '/', '\\'); + switch (game) + { + case game_ts: + case game_ra2: + case game_ra2_yr: + { + const int l = name.length(); + int a = l & ~3; + if (l & 3) + { + name += static_cast<char>(l - a); + name.append(3 - (l & 3), name[a]); + } + return compute_crc(name.c_str(), name.length()); + } + case game_rg: + case game_gr: + case game_gr_zh: + return compute_crc(name.c_str(), name.length()); + default: + int i = 0; + unsigned int id = 0; + int l = name.length(); + while (i < l) + { + unsigned int a = 0; + for (int j = 0; j < 4; j++) + { + a >>= 8; + if (i < l) + a |= static_cast<unsigned int>(name[i++]) << 24; + } + id = (id << 1 | id >> 31) + a; + } + return id; + } +} + +int Cmix_file::get_index(unsigned int id) const +{ + auto i = find_ptr(m_id_index, id); + return i ? *i : -1; +} + +Cvirtual_binary Cmix_file::get_vdata(int id) +{ + if (get_index(id) == -1) + return Cvirtual_binary(); + if (get_data()) + return vdata().sub_bin(get_offset(id), get_size(id)); + Cvirtual_binary d; + seek(get_offset(id)); + int size = get_size(id); + if (read(d.write_start(size), size)) + d.clear(); + return d; +} + +Cvirtual_binary Cmix_file::get_vdata(const string& name) +{ + return get_vdata(get_id(m_game, name)); +} diff --git a/3rdParty/xcc/misc/mix_file.h b/3rdParty/xcc/misc/mix_file.h new file mode 100644 index 0000000..fbf6681 --- /dev/null +++ b/3rdParty/xcc/misc/mix_file.h @@ -0,0 +1,115 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "cc_file.h" +#include "cc_structures.h" + +class Cmix_file : public Ccc_file +{ +public: + int post_open(); + string get_name(int id); + static int get_id(t_game game, string name); + int get_index(unsigned int id) const; + using Ccc_file::get_size; + using Ccc_file::vdata; + Cvirtual_binary get_vdata(int id); + Cvirtual_binary get_vdata(const string& name); + bool is_valid(); + void close(); + Cmix_file(); + + static void enable_ft_support() + { + assert(!m_ft_support); + m_ft_support = true; + } + + void enable_mix_expansion() + { + assert(!m_mix_expansion); + m_mix_expansion = true; + } + + int get_c_files() const + { + return m_index.size(); + } + + t_game get_game() const + { + return m_game; + } + + void set_game(t_game game) + { + m_game = game; + } + + t_file_type get_type(int id) + { + assert(get_index(id) != -1); + return m_index_ft[get_index(id)]; + } + + int get_id(int index) const + { + return m_index[index].id; + } + + int get_offset(unsigned int id) const + { + assert(get_index(id) != -1); + return m_index[get_index(id)].offset; + } + + int get_size(unsigned int id) const + { + assert(get_index(id) != -1); + return m_index[get_index(id)].size; + } + + bool has_checksum() const + { + return m_has_checksum; + } + + bool is_encrypted() const + { + return m_is_encrypted; + } + + const t_mix_index_entry* index() const + { + return &m_index[0]; + } +private: + using t_id_index = map<int, int>; + + static bool m_ft_support; + + t_game m_game; + bool m_mix_expansion = false; + bool m_is_encrypted; + bool m_has_checksum; + vector<t_mix_index_entry> m_index; + vector<t_file_type> m_index_ft; + t_id_index m_id_index; +}; diff --git a/3rdParty/xcc/misc/mix_file_write.cpp b/3rdParty/xcc/misc/mix_file_write.cpp new file mode 100644 index 0000000..85b750f --- /dev/null +++ b/3rdParty/xcc/misc/mix_file_write.cpp @@ -0,0 +1,83 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "mix_file_write.h" + +#include "mix_file.h" +#include "string_conversion.h" + +Cmix_file_write::Cmix_file_write(t_game game) +{ + m_game = game; +} + +void Cmix_file_write::add_file(int id, const Cvirtual_binary d) +{ + m_index[id] = d; +} + +void Cmix_file_write::add_file(string name, const Cvirtual_binary d) +{ + add_file(Cmix_file::get_id(m_game, name), d); + m_lmd_fw.add_fname(name); +} + +void Cmix_file_write::clear() +{ + m_index.clear(); +} + +int Cmix_file_write::write_start() +{ + add_file("local mix database.dat", m_lmd_fw.write(m_game)); + int r = 4 + sizeof(t_mix_header) + m_index.size() * sizeof(t_mix_index_entry); + for (auto& i : m_index) + r += i.second.size(); + return r; +} + +int Cmix_file_write::write(byte* d) const +{ + byte* w = d; + *reinterpret_cast<__int32*>(w) = 0; + w += 4; + t_mix_header& header = *reinterpret_cast<t_mix_header*>(w); + header.c_files = m_index.size(); + w += sizeof(t_mix_header); + t_mix_index_entry* index = reinterpret_cast<t_mix_index_entry*>(w); + w += m_index.size() * sizeof(t_mix_index_entry); + byte* body_start = w; + for (auto& i : m_index) + { + index->id = i.first; + index->offset = w - body_start; + index->size = i.second.size(); + index++; + w += i.second.read(w); + } + header.size = w - body_start; + return w - d; +} + +Cvirtual_binary Cmix_file_write::write() +{ + Cvirtual_binary d; + write(d.write_start(write_start())); + return d; +} diff --git a/3rdParty/xcc/misc/mix_file_write.h b/3rdParty/xcc/misc/mix_file_write.h new file mode 100644 index 0000000..c1b4fae --- /dev/null +++ b/3rdParty/xcc/misc/mix_file_write.h @@ -0,0 +1,42 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "cc_structures.h" +#include <virtual_binary.h> +#include "xcc_lmd_file_write.h" + +class Cmix_file_write +{ +public: + void add_file(int id, const Cvirtual_binary d); + void add_file(string name, const Cvirtual_binary d); + void clear(); + Cvirtual_binary write(); + Cmix_file_write(t_game game); +private: + using t_index = map<int, Cvirtual_binary>; + + int write_start(); + int write(byte* d) const; + + t_game m_game; + t_index m_index; + Cxcc_lmd_file_write m_lmd_fw; +}; diff --git a/3rdParty/xcc/misc/null_ini_reader.h b/3rdParty/xcc/misc/null_ini_reader.h new file mode 100644 index 0000000..846b270 --- /dev/null +++ b/3rdParty/xcc/misc/null_ini_reader.h @@ -0,0 +1,48 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "ini_reader.h" + +class Cnull_ini_reader : public Cini_reader +{ +public: + int process_section_start(string_view) override + { + mc_sections++; + return 0; + } + + bool process_section() const override + { + return true; + } + + int process_key(string_view, string_view) override + { + return 0; + } + + bool is_valid() const + { + return mc_sections; + } +private: + int mc_sections = 0; +}; diff --git a/3rdParty/xcc/misc/pal_file.cpp b/3rdParty/xcc/misc/pal_file.cpp new file mode 100644 index 0000000..801f245 --- /dev/null +++ b/3rdParty/xcc/misc/pal_file.cpp @@ -0,0 +1,50 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "pal_file.h" + +#include <fstream> + +bool Cpal_file::is_valid() const +{ + if (get_size() != sizeof(t_palet)) + return false; + const t_palet_entry* p = get_palet(); + for (int i = 0; i < 256; i++) + { + if ((p[i].r | p[i].g | p[i].b) & 0xc0) + return false; + } + return true; +} + +ostream& Cpal_file::extract_as_pal_jasc(ostream& os, bool shift_left) const +{ + os << "JASC-PAL" << endl + << "0100" << endl + << "256" << endl; + t_palet palet; + if (shift_left) + convert_palet_18_to_24(get_palet(), palet); + else + memcpy(palet, get_palet(), sizeof(t_palet)); + for (int i = 0; i < 256; i++) + os << static_cast<int>(palet[i].r) << ' ' << static_cast<int>(palet[i].g) << ' ' << static_cast<int>(palet[i].b) << endl; + return os; +} diff --git a/3rdParty/xcc/misc/pal_file.h b/3rdParty/xcc/misc/pal_file.h new file mode 100644 index 0000000..9d57687 --- /dev/null +++ b/3rdParty/xcc/misc/pal_file.h @@ -0,0 +1,39 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cc_file_small.h> +#include <palet.h> + +class Cpal_file : public Ccc_file_small +{ +public: + ostream& extract_as_pal_jasc(ostream&, bool shift_left = true) const; + bool is_valid() const; + + void decode(t_palet& palet) const + { + convert_palet_18_to_24(get_palet(), palet); + } + + const t_palet_entry* get_palet() const + { + return reinterpret_cast<const t_palet_entry*>(data()); + } +}; diff --git a/3rdParty/xcc/misc/palet.cpp b/3rdParty/xcc/misc/palet.cpp new file mode 100644 index 0000000..e24071b --- /dev/null +++ b/3rdParty/xcc/misc/palet.cpp @@ -0,0 +1,214 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include <climits> +#include "palet.h" + +void convert_image_8_to_24(const byte* s, byte* d, int cx, int cy, const t_palet palet) +{ + const byte* r = s; + byte* w = d; + int c = cx * cy; + while (c--) + { + const t_palet_entry* v = palet + *r++; + *w++ = v->r; + *w++ = v->g; + *w++ = v->b; + } +} + +void create_downsample_table(const t_palet palet, byte* rp) +{ + byte* rp_w = rp; + for (int b = 0; b < 0x40; b++) + { + for (int g = 0; g < 0x40; g++) + { + for (int r = 0; r < 0x40; r++) + *rp_w++ = find_color(r * 255 / 63, g * 255 / 63, b * 255 / 63, palet); + } + } +} + +void convert_image_24_to_8(const byte* s, byte* d, int cx, int cy, const byte* rp) +{ + const byte* r = s; + byte* w = d; + int c = cx * cy; + while (c--) + { + int red = *r++ >> 2 & 0x3f; + int green = *r++ >> 2 & 0x3f; + int blue = *r++ >> 2 & 0x3f; + *w++ = rp[red | green << 6 | blue << 12]; + } +} + +void convert_image_24_to_8(const byte* s, byte* d, int cx, int cy, const t_palet palet) +{ + const byte* r = s; + byte* w = d; + int c = cx * cy; + while (c--) + { + int red = *r++; + int green = *r++; + int blue = *r++; + *w++ = find_color(red, green, blue, palet); + } +} + +void downsample_image(const t_palet32entry* s, byte* d, int cx, int cy, const byte* rp) +{ + const t_palet32entry* r = s; + byte* w = d; + int c = cx * cy; + while (c--) + { + t_palet32entry e = *r++; + *w++ = e.a < 0x80 ? 0 : rp[e.r >> 2 | (e.g & 0xfc) << 4 | (e.b & 0xfc) << 10]; + } +} + +void downsample_image(const t_palet32entry* s, byte* d, int cx, int cy, const t_palet palet) +{ + const t_palet32entry* r = s; + byte* w = d; + int c = cx * cy; + while (c--) + { + t_palet32entry e = *r++; + if (e.a < 0x80) + *w++ = 0; + else + *w++ = find_color(e.r, e.g, e.b, palet); + } +} + +void upsample_image(const byte* s, t_palet32entry* d, int cx, int cy, const t_palet palet) +{ + const byte* r = s; + t_palet32entry* w = d; + int c = cx * cy; + while (c--) + { + t_palet32entry& e = *w++; + int z = *r++; + if (z) + { + const t_palet_entry* v = palet + z; + e.r = v->r; + e.g = v->g; + e.b = v->b; + e.a = 0xff; + } + else + { + e.r = 0x80; + e.g = 0x80; + e.b = 0x80; + e.a = 0; + } + } +} + +void convert_palet_18_to_24(const t_palet s, t_palet d) +{ + for (int i = 0; i < 256; i++) + { + d[i].r = (s[i].r & 63) * 255 / 63; + d[i].g = (s[i].g & 63) * 255 / 63; + d[i].b = (s[i].b & 63) * 255 / 63; + } +} + +void convert_palet_24_to_18(const t_palet s, t_palet d) +{ + for (int i = 0; i < 256; i++) + { + d[i].r = s[i].r >> 2; + d[i].g = s[i].g >> 2; + d[i].b = s[i].b >> 2; + } +} + +void convert_palet_18_to_24(t_palet palet) +{ + convert_palet_18_to_24(palet, palet); +} + +void convert_palet_24_to_18(t_palet palet) +{ + convert_palet_24_to_18(palet, palet); +} + +int find_color(int r, int g, int b, const t_palet p) +{ + int best_i; + int min_d = INT_MAX; + for (int i = 0; i < 256; i++) + { + int d_r = p[i].r - r; + int d_g = p[i].g - g; + int d_b = p[i].b - b; + int d = d_r * d_r + d_g * d_g + d_b * d_b; + if (d < min_d) + { + min_d = d; + best_i = i; + } + } + return best_i; +} + +int find_color_t(int r, int g, int b, const t_palet p) +{ + int best_i; + int min_d = INT_MAX; + for (int i = 1; i < 256; i++) + { + int d_r = p[i].r - r; + int d_g = p[i].g - g; + int d_b = p[i].b - b; + int d = d_r * d_r + d_g * d_g + d_b * d_b; + if (d < min_d) + { + min_d = d; + best_i = i; + } + } + return best_i; +} + +void create_rp(const t_palet s1, const t_palet s2, byte* d) +{ + d[0] = 0; + for (int i = 1; i < 256; i++) + d[i] = find_color(s1[i].r, s1[i].g, s1[i].b, s2); +} + +void apply_rp(byte* d, int cb_d, const byte* rp) +{ + while (cb_d--) + { + *d = rp[*d]; + d++; + } +} \ No newline at end of file diff --git a/3rdParty/xcc/misc/palet.h b/3rdParty/xcc/misc/palet.h new file mode 100644 index 0000000..539fbab --- /dev/null +++ b/3rdParty/xcc/misc/palet.h @@ -0,0 +1,76 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <vartypes.h> + +#pragma pack(push, 1) + +struct t_palet_entry +{ + byte r, g, b; +}; + +struct t_palet24rgb_entry +{ + byte r, g, b; +}; + +struct t_palet24bgr_entry +{ + byte b, g, r; +}; + +union t_palet32entry +{ + struct + { + byte r, g, b, a; + }; + unsigned __int32 v; +}; + +union t_palet32bgr_entry +{ + struct + { + byte b, g, r, a; + }; + unsigned __int32 v; +}; + +using t_palet = t_palet_entry[256]; + +void apply_rp(byte* d, int cb_d, const byte* rp); +void convert_image_8_to_24(const byte* s, byte* d, int cx, int cy, const t_palet palet); +void convert_image_24_to_8(const byte* s, byte* d, int cx, int cy, const byte* rp); +void convert_image_24_to_8(const byte* s, byte* d, int cx, int cy, const t_palet palet); +void convert_palet_18_to_24(const t_palet s, t_palet d); +void convert_palet_18_to_24(t_palet palet); +void convert_palet_24_to_18(const t_palet s, t_palet d); +void convert_palet_24_to_18(t_palet palet); +void create_downsample_table(const t_palet palet, byte* rp); +void create_rp(const t_palet s1, const t_palet s2, byte* d); +void downsample_image(const t_palet32entry* s, byte* d, int cx, int cy, const byte* rp); +void downsample_image(const t_palet32entry* s, byte* d, int cx, int cy, const t_palet palet); +void upsample_image(const byte* s, t_palet32entry* d, int cx, int cy, const t_palet palet); +int find_color(int r, int g, int b, const t_palet p); +int find_color_t(int r, int g, int b, const t_palet p); + +#pragma pack(pop) diff --git a/3rdParty/xcc/misc/reg_key.cpp b/3rdParty/xcc/misc/reg_key.cpp new file mode 100644 index 0000000..93401e9 --- /dev/null +++ b/3rdParty/xcc/misc/reg_key.cpp @@ -0,0 +1,105 @@ +/* + XCC Utilities and Library + Copyright (C) 2006 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "reg_key.h" + +#include <vector> + +using namespace std; + +Creg_key::Creg_key(HKEY key, const string& name, REGSAM sam_desired) +{ + m_h = NULL; + if (open(key, name, sam_desired) != ERROR_SUCCESS) + throw exception(); +} + +Creg_key::Creg_key(const Creg_key& key, const string& name, REGSAM sam_desired) +{ + m_h = NULL; + if (open(key.m_h, name, sam_desired) != ERROR_SUCCESS) + throw exception(); +} + +Creg_key::~Creg_key() +{ + close(); +} + +LONG Creg_key::create(HKEY key, const string& name) +{ + close(); + return RegCreateKeyExA(key, name.c_str(), 0, NULL, 0, KEY_ALL_ACCESS, NULL, &m_h, NULL); +} + +LONG Creg_key::open(HKEY key, const string& name, REGSAM sam_desired) +{ + close(); + return RegOpenKeyExA(key, name.c_str(), 0, sam_desired, &m_h); +}; + +LONG Creg_key::open(const Creg_key& key, const string& name, REGSAM sam_desired) +{ + return open(key.m_h, name, sam_desired); +}; + +LONG Creg_key::close() +{ + if (!m_h) + return ERROR_SUCCESS; + LONG result = RegCloseKey(m_h); + m_h = NULL; + return result; +} + +LONG Creg_key::query_value(const string& name, string& value) +{ + DWORD cb_d = 0; + LONG result = RegQueryValueExA(m_h, name.c_str(), NULL, NULL, NULL, &cb_d); + if (result != ERROR_SUCCESS) + return result; + if (!cb_d) + { + value.erase(); + return result; + } + vector<BYTE> d(cb_d); + result = RegQueryValueExA(m_h, name.c_str(), NULL, NULL, &d.front(), &cb_d); + if (result == ERROR_SUCCESS) + { + if (cb_d) + value.assign(reinterpret_cast<char*>(&d.front()), cb_d - 1); + else + value.erase(); + } + return result; +} + +string Creg_key::query_value(const string& name) +{ + string d; + if (query_value(name, d) != ERROR_SUCCESS) + throw exception(); + return d; +} + +LONG Creg_key::set_value(const string& name, const string& value) +{ + return RegSetValueExA(m_h, name.c_str(), 0, REG_SZ, reinterpret_cast<const BYTE*>(value.c_str()), value.size()); +} diff --git a/3rdParty/xcc/misc/reg_key.h b/3rdParty/xcc/misc/reg_key.h new file mode 100644 index 0000000..d087766 --- /dev/null +++ b/3rdParty/xcc/misc/reg_key.h @@ -0,0 +1,41 @@ +/* + XCC Utilities and Library + Copyright (C) 2006 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <boost/noncopyable.hpp> +#include <string> +#include <windows.h> + +class Creg_key : boost::noncopyable +{ +public: + Creg_key() = default; + Creg_key(HKEY, const std::string& name, REGSAM sam_desired); + Creg_key(const Creg_key&, const std::string& name, REGSAM sam_desired); + ~Creg_key(); + LONG create(HKEY key, const std::string& name); + LONG open(HKEY, const std::string& name, REGSAM sam_desired); + LONG open(const Creg_key&, const std::string& name, REGSAM sam_desired); + LONG close(); + LONG query_value(const std::string& name, std::string& value); + std::string query_value(const std::string& name); + LONG set_value(const std::string& name, const std::string& value); +private: + HKEY m_h = NULL; +}; diff --git a/3rdParty/xcc/misc/shp_decode.cpp b/3rdParty/xcc/misc/shp_decode.cpp new file mode 100644 index 0000000..e78be75 --- /dev/null +++ b/3rdParty/xcc/misc/shp_decode.cpp @@ -0,0 +1,1196 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "shp_decode.h" + +#include <lzo/lzo1x.h> +#include <virtual_binary.h> +#include "cc_structures.h" + +static const char* encode64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const int decode64_table[256] = +{ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 +}; + +static int read_w(const byte*& r) +{ + int v = *reinterpret_cast<const unsigned __int16*>(r); + r += 2; + return v; +} + +static void write_w(int v, byte*& w) +{ + *w++ = v & 0xff; + *w++ = v >> 8; +} + +static void write_v40(byte v, int count, byte*& d) +{ + while (count) + { + if (v) + { + if (count < 0x100) + { + *d++ = 0x00; + *d++ = count; + *d++ = v; + break; + } + int c_write = min(count, 0x3fff); + *d++ = 0x80; + write_w(0xc000 | c_write, d); + count -= c_write; + *d++ = v; + } + else if (count < 0x80) + { + *d++ = 0x80 | count; + count = 0; + } + else + { + int c_write = count < 0x8000 ? count : 0x7fff; + *d++ = 0x80; + write_w(c_write, d); + count -= c_write; + } + } +} + +int get_run_length(const byte* r, const byte* s_end) +{ + int count = 1; + int v = *r++; + while (r < s_end && *r++ == v) + count++; + return count; +} + +static void write40_c0(byte*& w, int count, int v) +{ + *w++ = 0; + *w++ = count; + *w++ = v; +} + +static void write40_c1(byte*& w, int count, const byte* r) +{ + *w++ = count; + memcpy(w, r, count); + w += count; +} + +static void write40_c2(byte*& w, int count) +{ + *w++ = 0x80; + write_w(count, w); +} + +static void write40_c3(byte*& w, int count, const byte* r) +{ + *w++ = 0x80; + write_w(0x8000 | count, w); + memcpy(w, r, count); + w += count; +} + +static void write40_c4(byte*& w, int count, int v) +{ + *w++ = 0x80; + write_w(0xc000 | count, w); + *w++ = v; +} + +static void write40_c5(byte*& w, int count) +{ + *w++ = 0x80 | count; +} + +static void write40_copy(byte*& w, int count, const byte* r) +{ + while (count) + { + if (count < 0x80) + { + write40_c1(w, count, r); + count = 0; + } + else + { + int c_write = count < 0x4000 ? count : 0x3fff; + write40_c3(w, c_write, r); + r += c_write; + count -= c_write; + } + } +} + +static void write40_fill(byte*& w, int count, int v) +{ + while (count) + { + if (count < 0x100) + { + write40_c0(w, count, v); + count = 0; + } + else + { + int c_write = count < 0x4000 ? count : 0x3fff; + write40_c4(w, c_write, v); + count -= c_write; + } + } +} + +static void write40_skip(byte*& w, int count) +{ + while (count) + { + if (count < 0x80) + { + write40_c5(w, count); + count = 0; + } + else + { + int c_write = count < 0x8000 ? count : 0x7fff; + write40_c2(w, c_write); + count -= c_write; + } + } +} + +static void flush_copy(byte*& w, const byte* r, const byte*& copy_from) +{ + if (copy_from) + { + write40_copy(w, r - copy_from, copy_from); + copy_from = NULL; + } +} + +int encode40(const byte* last_s, const byte* x, byte* d, int cb_s) +{ + // full compression + byte* s = new byte[cb_s]; + { + byte* a = s; + int size = cb_s; + while (size--) + *a++ = *last_s++ ^ *x++; + } + const byte* s_end = s + cb_s; + const byte* r = s; + byte* w = d; + const byte* copy_from = NULL; + while (r < s_end) + { + int v = *r; + int t = get_run_length(r, s_end); + if (!v) + { + flush_copy(w, r, copy_from); + write40_skip(w, t); + } + else if (t > 2) + { + flush_copy(w, r, copy_from); + write40_fill(w, t, v); + } + else + { + if (!copy_from) + copy_from = r; + } + r += t; + } + flush_copy(w, r, copy_from); + write40_c2(w, 0); + delete[] s; + return w - d; +} + +int encode40_y(const byte* last_r, const byte* r, byte* d, int cb_s) +{ + // run length encoding + byte* w = d; + int count = 0; + byte last = ~(*last_r ^ *r); + + while (cb_s--) + { + byte v = *last_r++ ^ *r++; + if (last == v) + count++; + else + { + write_v40(last, count, w); + count = 1; + last = v; + } + } + write_v40(last, count, w); + *w++ = 0x80; + write_w(0, w); + return w - d; +} + +int encode40_z(const byte* last_s, const byte* s, byte* d, int cb_s) +{ + // no compression + const byte* last_r = last_s; + const byte* r = s; + byte* w = d; + while (cb_s) + { + int c_write = cb_s > 0x3fff ? 0x3fff : cb_s; + cb_s -= c_write; + *w++ = 0x80; + *w++ = c_write & 0xff; + *w++ = 0x80 | c_write >> 8; + while (c_write--) + *w++ = *last_r++ ^ *r++; + } + *w++ = 0x80; + *w++ = 0x00; + *w++ = 0x00; + return w - d; +} + +int decode40(const byte* s, byte* d) +{ + /* + 0 fill 00000000 c v + 1 copy 0ccccccc + 2 skip 10000000 c 0ccccccc + 3 copy 10000000 c 10cccccc + 4 fill 10000000 c 11cccccc v + 5 skip 1ccccccc + */ + + const byte* r = s; + byte* w = d; + int count; + while (1) + { + int code = *r++; + if (code & 0x80) + { + if (count = code & 0x7f) + { + w += count; + } + else + { + count = *(uint16_t*)r; + r += 2; + code = count >> 8; + if (code & 0x80) + { + count &= 0x3fff; + if (code & 0x40) + { + code = *r++; + while (count--) + *w++ ^= code; + } + else + { + while (count--) + *w++ ^= *r++; + } + } + else + { + if (!count) + break; + w += count; + } + } + } + else if (code) + { + count = code; + while (count--) + *w++ ^= *r++; + } + else + { + count = *r++; + code = *r++; + while (count--) + *w++ ^= code; + } + } + return w - d; +} + +static void write_v80(byte v, int count, byte*& d) +{ + if (count > 3) + { + *d++ = 0xfe; + write_w(count, d); + *d++ = v; + } + else if (count) + { + *d++ = 0x80 | count; + while (count--) + *d++ = v; + } +} + +void get_same(const byte* s, const byte* r, const byte* s_end, byte*& p, int& cb_p) +{ + _asm + { + push esi + push edi + mov eax, s_end + mov ebx, s + xor ecx, ecx + mov edi, p + mov [edi], ecx + dec ebx +next_s: + inc ebx + xor edx, edx + mov esi, r + mov edi, ebx + cmp edi, esi + jnb end0 +next0: + inc edx + cmp esi, eax + jnb end_line + cmpsb + je next0 +end_line: + dec edx + cmp edx, ecx + jl next_s + mov ecx, edx + mov edi, p + mov [edi], ebx + jmp next_s +end0: + mov edi, cb_p + mov [edi], ecx + pop edi + pop esi + } +} + +static void write80_c0(byte*& w, int count, int p) +{ + *w++ = (count - 3) << 4 | p >> 8; + *w++ = p & 0xff; +} + +static void write80_c1(byte*& w, int count, const byte* r) +{ + do + { + int c_write = count < 0x40 ? count : 0x3f; + *w++ = 0x80 | c_write; + memcpy(w, r, c_write); + r += c_write; + w += c_write; + count -= c_write; + } + while (count); +} + +static void write80_c2(byte*& w, int count, int p) +{ + *w++ = 0xc0 | (count - 3); + write_w(p, w); +} + +static void write80_c3(byte*& w, int count, int v) +{ + *w++ = 0xfe; + write_w(count, w); + *w++ = v; +} + +static void write80_c4(byte*& w, int count, int p) +{ + *w++ = 0xff; + write_w(count, w); + write_w(p, w); +} + +static void flush_c1(byte*& w, const byte* r, const byte*& copy_from) +{ + if (copy_from) + { + write80_c1(w, r - copy_from, copy_from); + copy_from = NULL; + } +} + +int encode80(const byte* s, byte* d, int cb_s) +{ + // full compression + const byte* s_end = s + cb_s; + const byte* r = s; + byte* w = d; + const byte* copy_from = NULL; + while (r < s_end) + { + byte* p; + int cb_p; + int t = get_run_length(r, s_end); + get_same(s, r, s_end, p, cb_p); + if (t < cb_p && cb_p > 2) + { + flush_c1(w, r, copy_from); + if (cb_p - 3 < 8 && r - p < 0x1000) + write80_c0(w, cb_p, r - p); + else if (cb_p - 3 < 0x3e) + write80_c2(w, cb_p, p - s); + else + write80_c4(w, cb_p, p - s); + r += cb_p; + } + else + { + if (t < 3) + { + if (!copy_from) + copy_from = r; + } + else + { + flush_c1(w, r, copy_from); + write80_c3(w, t, *r); + } + r += t; + } + } + flush_c1(w, r, copy_from); + write80_c1(w, 0, NULL); + return w - d; +} + +int encode80_y(const byte* s, byte* d, int cb_s) +{ + // run length encoding + const byte* r = s; + byte* w = d; + int count = 0; + byte last = ~*r; + + while (cb_s--) + { + byte v = *r++; + if (last == v) + count++; + else + { + write_v80(last, count, w); + count = 1; + last = v; + } + + } + write_v80(last, count, w); + *w++ = 0x80; + return w - d; +} + +int decode80c(const byte image_in[], byte image_out[], int cb_in) +{ + /* + 0 copy 0cccpppp p + 1 copy 10cccccc + 2 copy 11cccccc p p + 3 fill 11111110 c c v + 4 copy 11111111 c c p p + */ + + const byte* copyp; + const byte* r = image_in; + byte* w = image_out; + int code; + int count; + while (1) + { + code = *r++; + if (~code & 0x80) + { + //bit 7 = 0 + //command 0 (0cccpppp p): copy + count = (code >> 4) + 3; + copyp = w - (((code & 0xf) << 8) + *r++); + while (count--) + *w++ = *copyp++; + } + else + { + //bit 7 = 1 + count = code & 0x3f; + if (~code & 0x40) + { + //bit 6 = 0 + if (!count) + //end of image + break; + //command 1 (10cccccc): copy + while (count--) + *w++ = *r++; + } + else + { + //bit 6 = 1 + if (count < 0x3e) + { + //command 2 (11cccccc p p): copy + count += 3; + copyp = &image_out[*(unsigned __int16*)r]; + r += 2; + while (count--) + *w++ = *copyp++; + } + else + if (count == 0x3e) + { + //command 3 (11111110 c c v): fill + count = *(unsigned __int16*)r; + r += 2; + code = *r++; + while (count--) + *w++ = byte(code); + } + else + { + //command 4 (copy 11111111 c c p p): copy + count = *(unsigned __int16*)r; + r += 2; + copyp = &image_out[*(unsigned __int16*)r]; + r += 2; + while (count--) + *w++ = *copyp++; + } + } + } + } + assert(cb_in == r - image_in); + return (w - image_out); +} + +int decode80(const byte image_in[], byte image_out[]) +{ + int cb_out; + /* + 0 copy 0cccpppp p + 1 copy 10cccccc + 2 copy 11cccccc p p + 3 fill 11111110 c c v + 4 copy 11111111 c c p p + */ + + _asm + { + push esi + push edi + mov ax, ds + mov es, ax + mov esi, image_in + mov edi, image_out +next0: + xor eax, eax + lodsb + mov ecx, eax + test eax, 0x80 + jnz c1c + shr ecx, 4 + add ecx, 3 + and eax, 0xf + shl eax, 8 + lodsb + mov edx, esi + mov esi, edi + sub esi, eax + jmp copy_from_destination +c1c: + and ecx, 0x3f + test eax, 0x40 + jnz c2c + or ecx, ecx + jz end0 + jmp copy_from_source +c2c: + xor eax, eax + lodsw + cmp ecx, 0x3e + je c3 + ja c4 + mov edx, esi + mov esi, image_out + add esi, eax + add ecx, 3 + jmp copy_from_destination +c3: + mov ecx, eax + lodsb + rep stosb + jmp next0 +c4: + mov ecx, eax + lodsw + mov edx, esi + mov esi, image_out + add esi, eax +copy_from_destination: + rep movsb + mov esi, edx + jmp next0 +copy_from_source: + rep movsb + jmp next0 +end0: + sub edi, image_out + mov cb_out, edi + pop edi + pop esi + } + return cb_out; +} + +int decode80r(const byte image_in[], byte image_out[]) +{ + int cb_out; + /* + 0 copy 0cccpppp p + 1 copy 10cccccc + 2 copy 11cccccc p p + 3 fill 11111110 c c v + 4 copy 11111111 c c p p + */ + + _asm + { + push esi + push edi + mov ax, ds + mov es, ax + mov esi, image_in + mov edi, image_out +next0: + xor eax, eax + lodsb + mov ecx, eax + test eax, 0x80 + jnz c1c + shr ecx, 4 + add ecx, 3 + and eax, 0xf + shl eax, 8 + lodsb + mov edx, esi + mov esi, edi + sub esi, eax + jmp copy_from_destination +c1c: + and ecx, 0x3f + test eax, 0x40 + jnz c2c + or ecx, ecx + jz end0 + jmp copy_from_source +c2c: + xor eax, eax + lodsw + cmp ecx, 0x3e + je c3 + ja c4 + mov edx, esi + mov esi, edi + sub esi, eax + add ecx, 3 + jmp copy_from_destination +c3: + mov ecx, eax + lodsb + rep stosb + jmp next0 +c4: + mov ecx, eax + lodsw + mov edx, esi + mov esi, edi + sub esi, eax +copy_from_destination: + rep movsb + mov esi, edx + jmp next0 +copy_from_source: + rep movsb + jmp next0 +end0: + sub edi, image_out + mov cb_out, edi + pop edi + pop esi + } + return cb_out; +} + +int decode2(const byte* s, byte* d, int cb_s, const byte* reference_palet) +{ + const byte* r = s; + const byte* r_end = s + cb_s; + byte* w = d; + while (r < r_end) + { + int v = *r++; + if (v) + *w++ = v; + else + { + v = *r++; + memset(w, 0, v); + w += v; + } + } + if (reference_palet) + apply_rp(d, w - d, reference_palet); + return w - d; +} + +int decode3(const byte* s, byte* d, int cx, int cy) +{ + const byte* r = s; + byte* w = d; + for (int y = 0; y < cy; y++) + { + int count = *reinterpret_cast<const unsigned __int16*>(r) - 2; + r += 2; + int x = 0; + while (count--) + { + int v = *r++; + if (v) + { + x++; + *w++ = v; + } + else + { + count--; + v = *r++; + if (x + v > cx) + v = cx - x; + x += v; + while (v--) + *w++ = 0; + } + } + } + return w - d; +} + +int encode3(const byte* s, byte* d, int cx, int cy) +{ + const byte* r = s; + byte* w = d; + for (int y = 0; y < cy; y++) + { + const byte* r_end = r + cx; + byte* w_line = w; + w += 2; + while (r < r_end) + { + + int v = *r; + *w++ = v; + if (v) + r++; + else + { + int c = get_run_length(r, r_end); + if (c > 0xff) + c = 0xff; + r += c; + *w++ = c; + } + } + *reinterpret_cast<unsigned __int16*>(w_line) = w - w_line; + } + return w - d; +} + +Cvirtual_binary encode64(data_ref s) +{ + Cvirtual_binary d; + const byte* r = s.data(); + int cb_s = s.size(); + byte* w = d.write_start(s.size() << 1); + while (cb_s) + { + int c1 = *r++; + *w++ = encode64_table[c1>>2]; + + int c2 = --cb_s == 0 ? 0 : *r++; + *w++ = encode64_table[((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4)]; + if (cb_s == 0) + { + *w++ = '='; + *w++ = '='; + break; + } + + int c3 = --cb_s == 0 ? 0 : *r++; + + *w++ = encode64_table[((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6)]; + if (cb_s == 0) + { + *w++ = '='; + break; + } + --cb_s; + *w++ = encode64_table[c3 & 0x3f]; + } + d.set_size(w - d.data()); + return d; +} + +Cvirtual_binary decode64(data_ref s) +{ + Cvirtual_binary d; + const byte* r = s.data(); + byte* w = d.write_start(s.size() << 1); + while (*r) + { + int c1 = *r++; + if (decode64_table[c1] == -1) + return Cvirtual_binary(); + int c2 = *r++; + if (decode64_table[c2] == -1) + return Cvirtual_binary(); + int c3 = *r++; + if (c3 != '=' && decode64_table[c3] == -1) + return Cvirtual_binary(); + int c4 = *r++; + if (c4 != '=' && decode64_table[c4] == -1) + return Cvirtual_binary(); + *w++ = (decode64_table[c1] << 2) | (decode64_table[c2] >> 4); + if (c3 == '=') + break; + *w++ = ((decode64_table[c2] << 4) & 0xf0) | (decode64_table[c3] >> 2); + if (c4 == '=') + break; + *w++ = ((decode64_table[c3] << 6) & 0xc0) | decode64_table[c4]; + } + d.set_size(w - d.data()); + return d; +} + +static void write5_count(byte*& w, int count) +{ + while (count > 255) + { + *w++ = 0; + count -= 255; + } + *w++ = count; +} + +static void write5_c0(byte*& w, int count, const byte* r, byte* small_copy) +{ + if (count < 4 && !small_copy) + count = count; + if ((count < 4 || count > 7) && small_copy) + { + int small_count = min(count, 3); + *small_copy |= small_count; + memcpy(w, r, small_count); + r += small_count; + w += small_count; + count -= small_count; + } + if (count) + { + assert(count > 3); + if (count > 18) + { + *w++ = 0; + write5_count(w, count - 18); + } + else + *w++ = count - 3; + memcpy(w, r, count); + w += count; + } +} + +static void write5_c1(byte*& w, int count, int p) +{ + assert(count > 2); + assert(p >= 0); + assert(p < 32768); + count -= 2; + if (count > 7) + { + *w++ = 0x10 | (p >> 11) & 8; + write5_count(w, count - 7); + } + else + *w++ = 0x10 | (p >> 11) & 8 | count; + write_w((p << 2) & 0xfffc, w); +} + +static void write5_c2(byte*& w, int count, int p) +{ + assert(count > 2); + assert(p > 0); + assert(p <= 16384); + count -= 2; + p--; + if (count > 31) + { + *w++ = 0x20; + write5_count(w, count - 31); + } + else + *w++ = 0x20 | count; + write_w(p << 2, w); +} + +static void write5_c3(byte*& w, int count, int p) +{ + assert(count > 1); + assert(count < 7); + assert(p > 0); + assert(p <= 2048); + count -= 2; + p--; + *w++ = (count + 1) << 5 | (p & 7) << 2; + *w++ = p >> 3; +} + +int get_count(const byte*& r) +{ + int count = -255; + int v; + do + { + count += 255; + v = *r++; + } + while (!v); + return count + v; +} + +static void flush_c0(byte*& w, const byte* r, const byte*& copy_from, byte* small_copy, bool start) +{ + if (copy_from) + { + int count = r - copy_from; + /* + if (start) + { + int small_count = count; + if (count > 241) + small_count = 238; + else if (count > 238) + small_count = count - 4; + *w++ = small_count + 17; + memcpy(w, copy_from, small_count); + copy_from += small_count; + w += small_count; + count -= small_count; + } + */ + if (count) + write5_c0(w, count, copy_from, small_copy); + copy_from = NULL; + } +} + +int encode5s(const byte* s, byte* d, int cb_s) +{ + lzo_init(); + static Cvirtual_binary t; + lzo_uint cb_d; + if (LZO_E_OK != lzo1x_1_compress(s, cb_s, d, &cb_d, t.write_start(LZO1X_1_MEM_COMPRESS))) + cb_d = 0; + return cb_d; +} + +int encode5s_z(const byte* s, byte* d, int cb_s) +{ + // no compression + const byte* r = s; + const byte* r_end = s + cb_s; + byte* w = d; + write5_c0(w, cb_s, r, NULL); + r += cb_s; + write5_c1(w, 3, 0); + assert(cb_s == r - s); + return w - d; +} + +int decode5s(const byte* s, byte* d, int cb_s) +{ + lzo_init(); + lzo_uint cb_d; + if (LZO_E_OK != lzo1x_decompress(s, cb_s, d, &cb_d, NULL)) + return 0; + return cb_d; + /* + 0 copy 0000cccc + 1 copy 0001pccc ppppppzz p + 2 copy 001ccccc ppppppzz p + 3 copy cccpppzz p + */ + + const byte* c; + const byte* r = s; + byte* w = d; + int code; + int count; + code = *r; + if (code > 17) + { + r++; + count = code - 17; + while (count--) + *w++ = *r++; + } + while (1) + { + code = *r++; + if (code & 0xf0) + { + if (code & 0xc0) + { + count = (code >> 5) - 1; + c = w - (code >> 2 & 7); + c -= *r++ << 3; + c--; + } + else if (code & 0x20) + { + count = code & 0x1f; + if (!count) + count = get_count(r) + 31; + c = w - (read_w(r) >> 2); + c--; + } + else + { + c = w - ((code & 8) << 11); + count = code & 7; + if (!count) + count = get_count(r) + 7; + c -= read_w(r) >> 2; + if (c == w) + break; + } + count += 2; + while (count--) + { + if (*w != *c) + *w = *c; + w++; + c++; + } + count = *(r - 2) & 3; + while (count--) + { + if (*w != *r) + *w = *r; + w++; + r++; + } + } + else + { + count = code ? code + 3: get_count(r) + 18; + while (count--) + { + if (*w != *r) + *w = *r; + w++; + r++; + } + } + } + assert(cb_s == r - s); + return w - d; +} + +int encode5(const byte* s, byte* d, int cb_s, int format) +{ + const byte* r = s; + const byte* r_end = s + cb_s; + byte* w = d; + while (r < r_end) + { + int cb_section = min(r_end - r, 8192); + t_pack_section_header& header = *reinterpret_cast<t_pack_section_header*>(w); + w += sizeof(t_pack_section_header); + w += header.size_in = format == 80 ? encode80(r, w, cb_section) : encode5s(r, w, cb_section); + r += header.size_out = cb_section; + } + return w - d; +} + +int decode5(const byte* s, byte* d, int cb_s, int format) +{ + const byte* r = s; + const byte* r_end = s + cb_s; + byte* w = d; + while (r < r_end) + { + const t_pack_section_header& header = *reinterpret_cast<const t_pack_section_header*>(r); + r += sizeof(t_pack_section_header); + if (format == 80) + decode80(r, w); + else + decode5s(r, w, header.size_in); + r += header.size_in; + w += header.size_out; + } + return w - d; +} diff --git a/3rdParty/xcc/misc/shp_decode.h b/3rdParty/xcc/misc/shp_decode.h new file mode 100644 index 0000000..df17b2e --- /dev/null +++ b/3rdParty/xcc/misc/shp_decode.h @@ -0,0 +1,39 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <virtual_binary.h> + +int decode2(const byte* s, byte* d, int cb_s, const byte* reference_palet); +int decode3(const byte* s, byte* d, int cx, int cy); +int encode3(const byte* s, byte* d, int cx, int cy); +int decode5(const byte* s, byte* d, int cb_s, int format); +int encode5(const byte* s, byte* d, int cb_s, int format); +int decode5s(const byte* s, byte* d, int cb_s); +int encode5s(const byte* s, byte* d, int cb_s); +int decode64(const byte* s, byte* d); +Cvirtual_binary decode64(data_ref); +Cvirtual_binary encode64(data_ref); +int decode40(const byte image_in[], byte image_out[]); +int decode80(const byte image_in[], byte image_out[]); +int decode80c(const byte image_in[], byte image_out[], int cb_in); +int decode80r(const byte image_in[], byte image_out[]); +int encode40(const byte* last_s, const byte* s, byte* d, int cb_s); +int encode80(const byte* s, byte* d, int cb_s); +int get_run_length(const byte* r, const byte* s_end); diff --git a/3rdParty/xcc/misc/shp_ts_file.cpp b/3rdParty/xcc/misc/shp_ts_file.cpp new file mode 100644 index 0000000..db60a92 --- /dev/null +++ b/3rdParty/xcc/misc/shp_ts_file.cpp @@ -0,0 +1,668 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "shp_ts_file.h" + +#include "image_file.h" +#include "shp_decode.h" +#include "string_conversion.h" +#ifndef XCC_MINIMAL_BUILD +#include "xcc_log.h" +#endif + +class Cshp_ts_decoder : public Cvideo_decoder +{ +public: + int cb_pixel() const + { + return m_f.cb_pixel(); + } + + int cf() const + { + return m_f.cf(); + } + + int cx() const + { + return m_f.cx(); + } + + int cy() const + { + return m_f.cy(); + } + + int decode(void* d0) + { + if (m_frame_i >= cf()) + return 1; + byte* d = reinterpret_cast<byte*>(d0); + Cvirtual_binary s; + const int cx = m_f.get_cx(m_frame_i); + const int cy = m_f.get_cy(m_frame_i); + const byte* r; + if (m_f.is_compressed(m_frame_i)) + { + decode3(m_f.get_image(m_frame_i), s.write_start(cx * cy), cx, cy); + r = s.data(); + } + else + r = m_f.get_image(m_frame_i); + memset(d, 0, cb_image()); + byte* w = d + m_f.get_x(m_frame_i) + Cshp_ts_decoder::cx() * m_f.get_y(m_frame_i); + for (int y = 0; y < cy; y++) + { + memcpy(w, r, cx); + r += cx; + w += Cshp_ts_decoder::cx(); + } + m_frame_i++; + return 0; + } + + const t_palet_entry* palet() const + { + return m_palet; + } + + int seek(int f) + { + m_frame_i = f; + return 0; + } + + Cshp_ts_decoder(const Cshp_ts_file& f, const t_palet_entry* palet) + { + m_f.load(f); + m_frame_i = 0; + memcpy(m_palet, palet, sizeof(t_palet)); + } +private: + Cshp_ts_file m_f; + int m_frame_i; + t_palet m_palet; +}; + +Cvideo_decoder* Cshp_ts_file::decoder(const t_palet_entry* palet) +{ + return new Cshp_ts_decoder(*this, palet); +} + +bool Cshp_ts_file::is_valid() const +{ + const t_shp_ts_header& h = header(); + int size = get_size(); + if (sizeof(t_shp_ts_header) > size || + h.zero || + h.c_images < 1 || h.c_images > 10000 || + sizeof(t_shp_ts_header) + get_cb_index() > size) + return false; + for (int i = 0; i < min(cf(), 1000); i++) + { + const t_shp_ts_image_header& image_header = *get_image_header(i); + if (!image_header.cx && !image_header.cy && !image_header.offset) + continue; + if (!image_header.cx || image_header.x + image_header.cx > h.cx || + !image_header.cy || image_header.y + image_header.cy > h.cy || + image_header.zero || + image_header.offset < sizeof(t_shp_ts_header) + get_cb_index()) + return false; + if (is_compressed(i)) + { + if (image_header.offset > size) + return false; + } + else + { + if (image_header.offset + image_header.cx * image_header.cy > size) + return false; + } + } + return true; +} + +int get_ofs(int x, int y, int cx, int cy) +{ + return x + cx * y; +} + +#ifndef XCC_MINIMAL_BUILD +int Cshp_ts_file::extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet _palet, bool combine_shadows) const +{ + t_palet palet; + convert_palet_18_to_24(_palet, palet); + int error = 0; + const int global_cx = cx(); + const int global_cy = cy(); + const int c_images = cf(); + if (combine_shadows && ~c_images & 1) + { + bool shadow = false; + byte* image = new byte[global_cx * global_cy]; + byte* d = new byte[global_cx * global_cy * c_images >> 1]; + byte* w = d; + for (int i = 0; i < c_images; i++) + { + const int cx = get_cx(i); + const int cy = get_cy(i); + const byte* r; + if (is_compressed(i)) + { + decode3(get_image(i), image, cx, cy); + r = image; + } + else + r = get_image(i); + if (!shadow) + { + if (i == c_images >> 1) + { + shadow = true; + w = d; + } + else + memset(w, 0, global_cx * global_cy); + } + byte* w_start = w; + w += get_x(i) + global_cx * get_y(i); + for (int y = 0; y < cy; y++) + { + if (shadow) + { + for (int x = 0; x < cx; x++) + { + if (*r++) + w[x] = 4; + } + } + else + { + memcpy(w, r, cx); + r += cx; + } + w += global_cx; + } + if (shadow) + { + Cfname t = name; + t.set_title(name.get_ftitle() + " " + nwzl(4, i - (c_images >> 1))); + error = image_file_write(t, ft, w_start, palet, global_cx, global_cy); + if (error) + break; + } + w = w_start + global_cx * global_cy; + } + delete[] d; + delete[] image; + } + else + { + byte* image = new byte[global_cx * global_cy]; + byte* s = new byte[global_cx * global_cy]; + for (int i = 0; i < c_images; i++) + { + const int cx = get_cx(i); + const int cy = get_cy(i); + const byte* r; + if (is_compressed(i)) + { + decode3(get_image(i), image, cx, cy); + r = image; + } + else + r = get_image(i); + memset(s, 0, global_cx * global_cy); + byte* w = s + get_x(i) + global_cx * get_y(i); + for (int y = 0; y < cy; y++) + { + memcpy(w, r, cx); + r += cx; + w += global_cx; + } + // xcc_log::write_line("<tr><td>" + name.get_ftitle() + "</td><td><img src=" + name.get_fname() + "></td></tr>"); + Cfname t = name; + t.set_title(name.get_ftitle() + " " + nwzl(4, i)); + error = image_file_write(t, ft, s, palet, global_cx, global_cy); + if (error) + break; + } + delete[] s; + delete[] image; + } + return error; +} + +Cvirtual_image Cshp_ts_file::extract_as_pcx_single(const t_palet _palet, bool combine_shadows) const +{ + t_palet palet; + convert_palet_18_to_24(_palet, palet); + const int global_cx = cx(); + const int global_cy = cy(); + int c_images = cf(); + combine_shadows &= ~c_images & 1; + if (combine_shadows) + c_images >>= 1; + const int cblocks_x = min(c_images, 1024 / global_cx); + const int cblocks_y = (c_images + cblocks_x - 1) / cblocks_x; + int cx_s = cblocks_x * global_cx; + int cy_s = cblocks_y * global_cy; + Cvirtual_binary image; + Cvirtual_binary s; + memset(s.write_start(cx_s * cy_s), 0, cx_s * cy_s); + if (combine_shadows) + { + c_images <<= 1; + bool shadow = false; + for (int i = 0; i < c_images; i++) + { + const int cx = get_cx(i); + const int cy = get_cy(i); + const byte* r; + if (is_compressed(i)) + { + decode3(get_image(i), image.write_start(global_cx * global_cy), cx, cy); + r = image.data(); + } + else + r = get_image(i); + if (!shadow && i == c_images >> 1) + shadow = true; + int j = i % (c_images >> 1); + byte* w = s.data_edit() + get_ofs(j % cblocks_x * global_cx + get_x(i), j / cblocks_x * global_cy + get_y(i), cx_s, cy_s); + for (int y = 0; y < cy; y++) + { + if (shadow) + { + for (int x = 0; x < cx; x++) + { + if (*r++) + w[x] = 4; + } + } + else + { + memcpy(w, r, cx); + r += cx; + } + w += cx_s; + } + } + } + else + { + for (int i = 0; i < c_images; i++) + { + const int cx = get_cx(i); + const int cy = get_cy(i); + const byte* r; + if (is_compressed(i)) + { + decode3(get_image(i), image.write_start(global_cx * global_cy), cx, cy); + r = image.data(); + } + else + r = get_image(i); + byte* w = s.data_edit() + get_ofs(i % cblocks_x * global_cx + get_x(i), i / cblocks_x * global_cy + get_y(i), cx_s, cy_s); + for (int y = 0; y < cy; y++) + { + memcpy(w, r, cx); + r += cx; + w += cx_s; + } + } + } + return Cvirtual_image(s, cx_s, cy_s, 1, palet); +} + +void shp_split_frames(Cvirtual_image& image, int cblocks_x, int cblocks_y) +{ + int cx = image.cx() / cblocks_x; + int cy = image.cy() / cblocks_y; + int cx_d = image.cx() / cblocks_x; + int cy_d = image.cy() * cblocks_x; + byte* d = new byte[cx_d * cy_d]; + byte* w = d; + const byte* r_line = image.image(); + for (int yb = 0; yb < cblocks_y; yb++) + { + for (int xb = 0; xb < cblocks_x; xb++) + { + const byte* r = r_line + cx * xb; + for (int y = 0; y < cy; y++) + { + memcpy(w, r, cx); + r += image.cx(); + w += cx_d; + } + } + r_line += image.cx() * cy; + } + image.load(d, cx_d, cy_d, image.cb_pixel(), image.palet()); + delete[] d; +} + +void shp_split_shadows(Cvirtual_image& image) +{ + int cx = image.cx(); + int cy = image.cy(); + int count = cx * cy; + byte* d = new byte[count << 1]; + memcpy(d, image.image(), count); + byte* r = d; + byte* w = d + count; + while (count--) + { + byte& v = *r++; + if (v == 4) + { + v = 0; + *w++ = 1; + } + else + *w++ = 0; + } + image.load(d, cx, cy << 1, image.cb_pixel(), image.palet()); + delete[] d; +} +#endif + +/* +void shp_xor_decode_frames(Cvirtual_image& image, int c_frames) +{ + int cx = image.cx(); + int cy = image.cy() / c_frames; + int count = cx * cy * (c_frames - 1); + const byte* r = image.image(); + byte* w = image.image_edit() + cx * cy; + while (count--) + { + *w++ ^= *r++; + } +} + +void shp_xor_encode_frames(Cvirtual_image& image, int c_frames) +{ + int cx = image.cx(); + int cy = image.cy() / c_frames; + int count = cx * cy * c_frames; + byte* w = image.image_edit() + count; + count -= cx * cy; + const byte* r = image.image() + count; + while (count--) + { + *--w ^= *--r; + } +} +*/ + +static int get_left_margin(const byte* r, int cx) +{ + int c = 0; + while (cx-- && !*r++) + c++; + return c; +} + +static int get_right_margin(const byte* r, int cx) +{ + int c = 0; + while (cx-- && !*--r) + c++; + return c; +} + +static int encode4_line(const byte* r, byte* d, int cx) +{ + const byte* s_end = r + cx; + byte* w = d; + while (r < s_end) + { + int v = *w++ = *r++; + if (!v) + { + int c = min(get_run_length(r - 1, s_end), 0xff); + r += c - 1; + *w++ = c; + } + } + return w - d; +} + +static int decode4_line_size(const byte*& r, int cx) +{ + int w = 0; + while (cx--) + { + w++; + if (!*r++) + { + cx -= *r++ - 1; + w++; + } + } + return w; +} + +static int decode4_line(const byte* s, byte*& w, int cx) +{ + const byte* r = s; + while (cx--) + { + if (!(*w++ = *r++)) + cx -= (*w++ = *r++) - 1; + } + return r - s; +} + +static int encode4(const byte* s, byte* d, int cx, int cy) +{ + const byte* s_end = s + cx * cy; + const byte* r = s; + byte* w = d; + for (int y = 0; y < cy; y++) + { + int lm = min(get_left_margin(r, cx), 0xff); + int rm = min(get_right_margin(r + cx, cx - lm), 0xff); + *w++ = lm; + *w++ = rm; + w += encode4_line(r + lm, w, cx - lm - rm); + r += cx; + } + return w - d; +} + +static int decode4_size(const byte*& r, int cx, int cy) +{ + int w = 0; + for (int y = 0; y < cy; y++) + { + int lm = *r++; + int rm = *r++; + w += 2; + if (lm) + w += 2; + w += decode4_line_size(r, cx - lm - rm); + if (rm) + w += 2; + } + return w; +} + +static int decode4(const byte* s, byte*& w, int cx, int cy) +{ + const byte* r = s; + for (int y = 0; y < cy; y++) + { + int lm = *r++; + int rm = *r++; + byte* w_line = w; + w += 2; + if (lm) + { + *w++ = 0; + *w++ = lm; + } + r += decode4_line(r, w, cx - lm - rm); + if (rm) + { + *w++ = 0; + *w++ = rm; + } + *reinterpret_cast<unsigned __int16*>(w_line) = w - w_line; + } + return r - s; +} + +struct t_shp4_header +{ + unsigned __int16 cx; + unsigned __int16 cy; + unsigned __int16 c_frames; +}; + +struct t_shp4_frame_header +{ + unsigned __int8 lm; + unsigned __int8 rm; + unsigned __int8 tm; + unsigned __int8 bm; +}; + +int shp_encode4(const Cshp_ts_file& f, byte* d) +{ + const int global_cx = f.cx(); + const int global_cy = f.cy(); + const int c_frames = f.cf(); + + byte* w = d; + t_shp4_header& header = *reinterpret_cast<t_shp4_header*>(w); + header.cx = global_cx; + header.cy = global_cy; + header.c_frames = c_frames; + w += sizeof(t_shp4_header); + + for (int i = 0; i < c_frames; i++) + { + const t_shp_ts_image_header& image_header = *f.get_image_header(i); + + const int cx = image_header.cx; + const int cy = image_header.cy; + + t_shp4_frame_header& frame_header = *reinterpret_cast<t_shp4_frame_header*>(w); + if (image_header.cx && image_header.cy) + { + frame_header.lm = image_header.x; + frame_header.tm = image_header.y; + } + else + { + frame_header.lm = min(global_cx, 0xff); + frame_header.tm = min(global_cy, 0xff); + } + if (global_cx - frame_header.lm - cx > 0xff + || global_cy - frame_header.tm - cy > 0xff) + return 0; + frame_header.rm = global_cx - frame_header.lm - cx; + frame_header.bm = global_cy - frame_header.tm - cy; + w += sizeof(t_shp4_frame_header); + + if (f.is_compressed(i)) + { + Cvirtual_binary image; + decode3(f.get_image(i), image.write_start(cx * cy), cx, cy); + w += encode4(image.data(), w, cx, cy); + } + else + w += encode4(f.get_image(i), w, cx, cy); + } + return w - d; +} + +int shp_decode4_size(const byte* s) +{ + Cvirtual_binary d; + const byte* r = s; + const t_shp4_header& s_header = *reinterpret_cast<const t_shp4_header*>(r); + const int global_cx = s_header.cx; + const int global_cy = s_header.cy; + const int c_frames = s_header.c_frames; + r += sizeof(t_shp4_header); + int w = 0; + for (int i = 0; i < c_frames; i++) + { + const t_shp4_frame_header& frame_header = *reinterpret_cast<const t_shp4_frame_header*>(r); + int x = frame_header.lm; + int y = frame_header.tm; + int cx = global_cx - x - frame_header.rm; + int cy = global_cy - y - frame_header.bm; + r += sizeof(t_shp4_frame_header); + if (cy) + w += decode4_size(r, cx, cy); + w = w + 7 & ~7; + } + return w + + sizeof(t_shp_ts_header) + + c_frames * sizeof(t_shp_ts_image_header); +} + +Cvirtual_binary shp_decode4(const byte* s, int cb_d) +{ + Cvirtual_binary d; + const byte* r = s; + const t_shp4_header& s_header = *reinterpret_cast<const t_shp4_header*>(r); + const int global_cx = s_header.cx; + const int global_cy = s_header.cy; + const int c_frames = s_header.c_frames; + r += sizeof(t_shp4_header); + byte* w = d.write_start(cb_d ? cb_d : Cshp_ts_file::get_max_size(global_cx, global_cy, c_frames)); + t_shp_ts_header& header = *reinterpret_cast<t_shp_ts_header*>(w); + header.zero = 0; + header.cx = global_cx; + header.cy = global_cy; + header.c_images = c_frames; + w += sizeof(t_shp_ts_header); + byte* w1 = w + c_frames * sizeof(t_shp_ts_image_header); + for (int i = 0; i < c_frames; i++) + { + const t_shp4_frame_header& frame_header = *reinterpret_cast<const t_shp4_frame_header*>(r); + int x = frame_header.lm; + int y = frame_header.tm; + int cx = global_cx - x - frame_header.rm; + int cy = global_cy - y - frame_header.bm; + r += sizeof(t_shp4_frame_header); + t_shp_ts_image_header& image_header = *reinterpret_cast<t_shp_ts_image_header*>(w); + image_header.x = x; + image_header.y = y; + image_header.cx = cx; + image_header.cy = cy; + image_header.compression = 3; + image_header.unknown = 0; + image_header.zero = 0; + image_header.offset = w1 - d.data(); + w += sizeof(t_shp_ts_image_header); + if (cy) + r += decode4(r, w1, cx, cy); + else + image_header.offset = 0; + w1 = d.data_edit() + (w1 - d.data() + 7 & ~7); + } + assert(!cb_d || d.size() == w1 - d.data()); + return cb_d ? d : Cvirtual_binary(d.data(), w1 - d.data()); +} diff --git a/3rdParty/xcc/misc/shp_ts_file.h b/3rdParty/xcc/misc/shp_ts_file.h new file mode 100644 index 0000000..76261cd --- /dev/null +++ b/3rdParty/xcc/misc/shp_ts_file.h @@ -0,0 +1,117 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "cc_structures.h" +#include "fname.h" +#include "palet.h" +#include "video_file.h" +#include "virtual_image.h" + +class Cshp_ts_file : public Cvideo_file<t_shp_ts_header> +{ +public: + Cvideo_decoder* decoder(const t_palet_entry*); +#ifndef XCC_MINIMAL_BUILD + int extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet palet, bool combine_shadows = false) const; + Cvirtual_image extract_as_pcx_single(const t_palet _palet, bool combine_shadows = false) const; +#endif + bool is_valid() const; + + int cb_pixel() const + { + return 1; + } + + int cf() const + { + return header().c_images; + } + + int cx() const + { + return header().cx; + } + + int cy() const + { + return header().cy; + } + + int get_x(int i) const + { + return get_image_header(i)->x; + } + + int get_y(int i) const + { + return get_image_header(i)->y; + } + + int get_cx(int i) const + { + return get_image_header(i)->cx; + } + + int get_cy(int i) const + { + return get_image_header(i)->cy; + } + + int get_cb_index() const + { + return sizeof(t_shp_ts_image_header) * cf(); + } + + bool is_compressed(int i) const + { + return get_image_header(i)->compression & 2; + } + + const t_shp_ts_image_header* get_image_header(int i) const + { + return reinterpret_cast<const t_shp_ts_image_header*>(data() + sizeof(t_shp_ts_header) + sizeof(t_shp_ts_image_header) * i); + } + + int get_offset(int i) const + { + return get_image_header(i)->offset; + } + + const byte* get_image(int i) const + { + return data() + get_offset(i); + } + + static int get_max_size(int cx, int cy, int c_images) + { + return sizeof(t_shp_ts_header) + (sizeof(t_shp_ts_image_header) + (2 * (cx + 1) * cy + 7 & ~7)) * c_images; + } +}; + +int shp_decode4_size(const byte* s); +Cvirtual_binary shp_decode4(const byte* s, int cb_d); +int shp_encode4(const Cshp_ts_file& f, byte* d); + +#ifndef XCC_MINIMAL_BUILD +void shp_split_frames(Cvirtual_image& image, int cblocks_x, int cblocks_y); +void shp_split_shadows(Cvirtual_image& image); +void shp_xor_decode_frames(Cvirtual_image& image, int c_frames); +void shp_xor_encode_frames(Cvirtual_image& image, int c_frames); +#endif diff --git a/3rdParty/xcc/misc/stdafx.h b/3rdParty/xcc/misc/stdafx.h new file mode 100644 index 0000000..de008af --- /dev/null +++ b/3rdParty/xcc/misc/stdafx.h @@ -0,0 +1,18 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + diff --git a/3rdParty/xcc/misc/string_conversion.cpp b/3rdParty/xcc/misc/string_conversion.cpp new file mode 100644 index 0000000..e1c1eff --- /dev/null +++ b/3rdParty/xcc/misc/string_conversion.cpp @@ -0,0 +1,266 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "string_conversion.h" + +#include <ctime> + +using namespace std; + +int a2ip(const string& s) +{ + int r = 0; + int l = 0; + for (int i = 0; i < 3; i++) + { + int c = s.find('.', l); + r = r << 8 | atoi(s.substr(l, c - l).c_str()); + l = c + 1; + } + r = r << 8 | atoi(s.substr(l).c_str()); + return r; +} + +string ip2a(int v) +{ + return n(v >> 24 & 0xff) + '.' + n(v >> 16 & 0xff) + '.' + n(v >> 8 & 0xff) + '.' + n(v & 0xff); +} + +int get_net_mask(int v) +{ + if (v & 0x80000000) + return 0xffffff00; + if (v & 0x40000000) + return 0xffff0000; + return 0xff000000; +} + +int get_net_part(int v) +{ + return v & get_net_mask(v); +} + +bool atob(string s) +{ + return s == "true" || s == "yes"; +} + +string btoa(bool v) +{ + return v ? "yes" : "no"; +} + +string n(unsigned int v) +{ + return to_string(v); +} + +string n(int v) +{ + return to_string(v); +} + +string n(long long v) +{ + return to_string(v); +} + +string n(unsigned long long v) +{ + return to_string(v); +} + +string swsl(int l, string s) +{ + while (s.size() < l) + s = ' ' + s; + return s; +} + +string swsr(int l, string s) +{ + while (s.size() < l) + s += ' '; + return s; +} + +string nwzl(int l, unsigned int v) +{ + string s = n(v); + while (s.size() < l) + s = '0' + s; + return s; +} + +string nwsl(int l, unsigned int v) +{ + return swsl(l, n(v)); +} + +string nh(int l, __int64 v) +{ + string s; + int w; + while (l) + { + w = v & 0xf; + if (w > 9) + w += 7; + s = char(w + 48) + s; + v >>= 4; + l--; + } + return s; +} + +string nwp(int l, unsigned int v) +{ + string r; + string s = n(v); + while (1) + { + int l = s.size(); + if (l > 3) + { + r = '.' + s.substr(l - 3, 3) + r; + s.erase(l - 3, 3); + } + else + { + r = s + r; + break; + } + + } + return swsl(l, r); +} + +void split_key(const string& key, string& name, string& value) +{ + size_t i = key.find('='); + if (i == string::npos) + { + name = key; + value.erase(); + } + else + { + name = key.substr(0, i); + value = key.substr(i + 1); + } +} + +string tabs2spaces(const string& v) +{ + string r; + for (size_t i = 0; i < v.size(); i++) + { + char c = v[i]; + if (c == '\t') + { + do + r += ' '; + while (r.size() & 3); + } + else + r += c; + } + return r; +} + +string time2a(time_t v) +{ + char b[20]; + const tm* date = gmtime(&v); + if (date) + sprintf(b, "%04d-%02d-%02d %02d:%02d:%02d", date->tm_year + 1900, date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec); + else + *b = 0; + return b; +} + +string js_encode(const string& v) +{ + string r; + for (size_t i = 0; i < v.size(); i++) + { + switch (v[i]) + { + case '<': + r += "<"; + break; + case '\"': + case '\'': + case '\\': + r += '\\'; + default: + r += v[i]; + } + } + return r; +} + +string trim_field(const string& v) +{ + string r; + bool copy_white = false; + for (size_t i = 0; i < v.size(); i++) + { + if (isspace(v[i])) + copy_white = true; + else + { + if (copy_white) + { + if (!r.empty()) + r += ' '; + copy_white = false; + } + r += v[i]; + } + } + return r; +} + +string trim_text(const string& v) +{ + string r; + bool copy_white = false; + for (size_t i = 0; i < v.size(); ) + { + int p = v.find('\n', i); + if (p == string::npos) + p = v.size(); + string line = trim_field(v.substr(i, p - i)); + if (line.empty()) + copy_white = true; + else + { + if (copy_white) + { + if (!r.empty()) + r += '\n'; + copy_white = false; + } + r += line + '\n'; + } + i = p + 1; + } + return r; +} diff --git a/3rdParty/xcc/misc/string_conversion.h b/3rdParty/xcc/misc/string_conversion.h new file mode 100644 index 0000000..8271255 --- /dev/null +++ b/3rdParty/xcc/misc/string_conversion.h @@ -0,0 +1,41 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <string> + +int a2ip(const std::string&); +std::string ip2a(int); +int get_net_mask(int); +int get_net_part(int); +bool atob(std::string); +std::string btoa(bool); +std::string js_encode(const std::string&); +std::string n(long long); +std::string swsl(int l, std::string); +std::string swsr(int l, std::string); +std::string nwp(int l, unsigned int); +std::string nwsl(int l, unsigned int); +std::string nwzl(int l, unsigned int); +std::string nh(int l, long long v); +void split_key(const std::string& key, std::string& name, std::string& value); +std::string tabs2spaces(const std::string&); +std::string time2a(time_t); +std::string trim_field(const std::string&); +std::string trim_text(const std::string&); diff --git a/3rdParty/xcc/misc/tmp_file.h b/3rdParty/xcc/misc/tmp_file.h new file mode 100644 index 0000000..da7334e --- /dev/null +++ b/3rdParty/xcc/misc/tmp_file.h @@ -0,0 +1,56 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cc_file_sh.h> +#include <cc_structures.h> + +class Ctmp_file : public Ccc_file_sh<t_tmp_header> +{ +public: + bool is_valid() const + { + const t_tmp_header& h = header(); + int size = get_size(); + return !(sizeof(t_tmp_header) > size || + h.cx != 24 || + h.cy != 24 || + h.c_tiles > 128 || + h.zero1 || + h.size != size || + h.image_offset > size || + h.zero2 || + h.id != 0x0d1affff); + } + + int get_c_tiles() const + { + return header().c_tiles; + } + + const byte* get_image(int i) const + { + return data() + header().image_offset + 576 * get_index1()[i]; + } + + const byte* get_index1() const + { + return data() + header().index1; + } +}; diff --git a/3rdParty/xcc/misc/tmp_ts_file.cpp b/3rdParty/xcc/misc/tmp_ts_file.cpp new file mode 100644 index 0000000..4347f86 --- /dev/null +++ b/3rdParty/xcc/misc/tmp_ts_file.cpp @@ -0,0 +1,185 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "tmp_ts_file.h" + +#include "image_file.h" + +void Ctmp_ts_file::get_rect(int& x, int& y, int& cx, int& cy) const +{ + x = INT_MAX; + y = INT_MAX; + cx = INT_MIN; + cy = INT_MIN; + int bigy = INT_MIN; + int bigyval = 0; + for (int i = 0; i < get_c_tiles(); i++) + { + if (get_index()[i]) + { + int height = get_height() - get_height(i); + int x_t = get_x(i); + int y_t = get_y(i) + (height * (get_cy() / 2)); + int x2_t = x_t + get_cx(); + int y2_t = y_t + get_cy(); + if (has_extra_graphics(i)) + { + int y_t_extra = get_y_extra(i) + (height * (get_cy() / 2)); + int y2_t_extra = y_t_extra + get_cy_extra(i); + if (y_t_extra < y) + y = y_t_extra; + if (y2_t_extra > cy) + cy = y2_t_extra; + } + if (x_t < x) + x = x_t; + if (x2_t > cx) + cx = x2_t; + if (y_t < y) + y = y_t; + if (y2_t > cy) + cy = y2_t; + if (bigy < get_y(i)) + { + bigy = get_y(i); + bigyval = get_y(i) + get_cy() + (get_height(i) * (get_cy() / 2)); + if (has_extra_graphics(i)) + bigyval -= get_y_extra(i); + } + } + } + cx -= x; + cy -= y; + if (cy < bigyval) + cy = bigyval; +} + +void Ctmp_ts_file::draw(byte* d) const +{ + int global_x, global_y, global_cx, global_cy; + get_rect(global_x, global_y, global_cx, global_cy); + memset(d, 0, global_cx * global_cy); + for (int i = 0; i < get_c_tiles(); i++) + { + if (get_index()[i]) + { + int height = get_height() - get_height(i); + const byte* r = get_image(i); + byte* w_line = d + get_x(i) - global_x + global_cx * (get_y(i) - global_y + (height * (get_cy() / 2))); + int x = get_cx() / 2; + int cx = 0; + int y = 0; + for (; y < get_cy() / 2; y++) + { + cx += 4; + x -= 2; + memcpy(w_line + x, r, cx); + r += cx; + w_line += global_cx; + } + for (; y < get_cy(); y++) + { + cx -= 4; + x += 2; + memcpy(w_line + x, r, cx); + r += cx; + w_line += global_cx; + } + if (has_extra_graphics(i)) + { + r += get_cx() * get_cy() / 2; + w_line = d + get_x_extra(i) - global_x + global_cx * (get_y_extra(i) - global_y + (height * (get_cy() / 2))); + int cx = get_cx_extra(i); + int cy = get_cy_extra(i); + for (y = 0; y < cy; y++) + { + byte* w = w_line; + for (int i = 0; i < cx; i++) + { + int v = *r++; + if (v) + *w = v; + w++; + } + w_line += global_cx; + } + } + } + } +} + +int decode_tile(const byte* s, byte* d, int cx_d) +{ + int cy = cx_d >> 1; + memset(d, 0, cx_d * cy); + const byte* r = s; + byte* w = d; + int x = cx_d / 2; + int cx = 0; + int y = 0; + for (; y < cy / 2; y++) + { + cx += 4; + x -= 2; + memcpy(w + x, r, cx); + r += cx; + w += cx_d; + } + for (; y < cy; y++) + { + cx -= 4; + x += 2; + memcpy(w + x, r, cx); + r += cx; + w += cx_d; + } + return w - d; +} + +int encode_tile(const byte* s, byte* d, int cx_s) +{ + int cy = cx_s >> 1; + const byte* r = s; + byte* w = d; + int x = cx_s / 2; + int cx = 0; + int y = 0; + for (; y < cy / 2; y++) + { + cx += 4; + x -= 2; + memcpy(w, r + x, cx); + r += cx_s; + w += cx; + } + for (; y < cy; y++) + { + cx -= 4; + x += 2; + memcpy(w, r + x, cx); + r += cx_s; + w += cx; + } + return w - d; +} + +void Ctmp_ts_file::decode(void* d) const +{ + draw(reinterpret_cast<byte*>(d)); +} diff --git a/3rdParty/xcc/misc/tmp_ts_file.h b/3rdParty/xcc/misc/tmp_ts_file.h new file mode 100644 index 0000000..43958bf --- /dev/null +++ b/3rdParty/xcc/misc/tmp_ts_file.h @@ -0,0 +1,210 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cc_file_sh.h> +#include <cc_structures.h> +#include "fname.h" +#include "image_file.h" +#include "palet.h" + +class Ctmp_ts_file : public Cimage_file<t_tmp_ts_header> +{ +public: + void decode(void*) const; + void draw(byte* d) const; + void get_rect(int& x, int& y, int& cx, int& cy) const; + + bool is_valid() const + { + const t_tmp_ts_header& h = header(); + int size = get_size(); + if (sizeof(t_tmp_ts_header) > size || + !h.cblocks_x || !h.cblocks_y || + h.cx != 48 && h.cx != 60 || + 2 * h.cy != h.cx || + sizeof(t_tmp_ts_header) + 4 * get_c_tiles() > size) + return false; + for (int i = 0; i < min(get_c_tiles(), 64); i++) + { + if (get_index()[i]) + { + const t_tmp_image_header& image_header = *get_image_header(i); + } + } + return true; + } + + int cb_pixel() const + { + return 1; + } + + int cx() const + { + int x, y, cx, cy; + get_rect(x, y, cx, cy); + return cx; + } + + int cy() const + { + int x, y, cx, cy; + get_rect(x, y, cx, cy); + return cy; + } + + int get_c_tiles() const + { + return get_cblocks_x() * get_cblocks_y(); + } + + int get_cblocks_x() const + { + return header().cblocks_x; + } + + int get_cblocks_y() const + { + return header().cblocks_y; + } + + const t_tmp_image_header* get_image_header(int i) const + { + return reinterpret_cast<const t_tmp_image_header*>(data() + get_index()[i]); + } + + int get_x(int i) const + { + return get_image_header(i)->x; + } + + int get_y(int i) const + { + return get_image_header(i)->y; + } + + int get_cx() const + { + return header().cx; + } + + int get_cy() const + { + return header().cy; + } + + int get_x_extra(int i) const + { + return get_image_header(i)->x_extra; + } + + int get_height() const + { + int height = 0; + for (int i = 0; i < get_c_tiles(); i++) + { + if (get_index()[i]) + { + if (get_height(i) > height) + height = get_height(i); + } + } + return height; + } + + int get_height(int i) const + { + return get_image_header(i)->height; + } + + /* + int get_ramp_type(int i) const + { + return get_image_header(i)->ramp_type; + } + + int get_terrain_type(int i) const + { + return get_image_header(i)->terrain_type; + } + */ + + int get_y_extra(int i) const + { + return get_image_header(i)->y_extra; + } + + int get_cx_extra(int i) const + { + return get_image_header(i)->cx_extra; + } + + int get_cy_extra(int i) const + { + return get_image_header(i)->cy_extra; + } + + bool has_extra_graphics(int i) const + { + return get_image_header(i)->has_extra_data; + } + + int get_cb_diamond() const + { + return get_cx() * get_cy() >> 1; + } + + int get_cb_extra_data(int i) const + { + return get_cx_extra(i) * get_cy_extra(i); + } + + const byte* get_image(int i) const + { + return reinterpret_cast<const byte*>(get_image_header(i) + 1); + } + + const byte* get_z_image(int i) const + { + int a = get_index()[i] + get_image_header(i)->z_ofs; + int b = get_image(i) + get_cb_diamond() - data(); + assert(a == b); + return data() + get_index()[i] + get_image_header(i)->z_ofs; + } + + const byte* get_extra_data(int i) const + { + return data() + get_index()[i] + get_image_header(i)->extra_ofs; + } + + const byte* get_extra_z_data(int i) const + { + return data() + get_index()[i] + get_image_header(i)->extra_z_ofs; + } + + const int* get_index() const + { + return reinterpret_cast<const int*>(data() + sizeof(t_tmp_ts_header)); + } +}; + +int decode_tile(const byte* s, byte* d, int cx_d); +int encode_tile(const byte* s, byte* d, int cx_s); +int tmp_ts_file_write(const byte* s, byte* d, int cx, int cy); diff --git a/3rdParty/xcc/misc/vartypes.h b/3rdParty/xcc/misc/vartypes.h new file mode 100644 index 0000000..9621128 --- /dev/null +++ b/3rdParty/xcc/misc/vartypes.h @@ -0,0 +1,22 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include <cstddef> + +using byte = unsigned char; +// using std::byte; diff --git a/3rdParty/xcc/misc/video_decoder.cpp b/3rdParty/xcc/misc/video_decoder.cpp new file mode 100644 index 0000000..8366838 --- /dev/null +++ b/3rdParty/xcc/misc/video_decoder.cpp @@ -0,0 +1,29 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "video_decoder.h" + +Cvideo_decoder::~Cvideo_decoder() +{ +} + +const t_palet_entry* Cvideo_decoder::palet() const +{ + return NULL; +} diff --git a/3rdParty/xcc/misc/video_decoder.h b/3rdParty/xcc/misc/video_decoder.h new file mode 100644 index 0000000..317f595 --- /dev/null +++ b/3rdParty/xcc/misc/video_decoder.h @@ -0,0 +1,44 @@ +/* + XCC Utilities and Library + Copyright (C) 2004 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "palet.h" + +class Cvideo_decoder +{ +public: + virtual int cb_pixel() const = 0; + virtual int cf() const = 0; + virtual int cx() const = 0; + virtual int cy() const = 0; + virtual int decode(void* d) = 0; + virtual const t_palet_entry* palet() const; + virtual int seek(int f) = 0; + virtual ~Cvideo_decoder(); + + int cb_image() const + { + return cb_pixel() * cx() * cy(); + } + + int cb_video() const + { + return cf() * cb_image(); + } +}; diff --git a/3rdParty/xcc/misc/video_file.cpp b/3rdParty/xcc/misc/video_file.cpp new file mode 100644 index 0000000..7f151e0 --- /dev/null +++ b/3rdParty/xcc/misc/video_file.cpp @@ -0,0 +1,20 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "video_file.h" diff --git a/3rdParty/xcc/misc/video_file.h b/3rdParty/xcc/misc/video_file.h new file mode 100644 index 0000000..a7c2872 --- /dev/null +++ b/3rdParty/xcc/misc/video_file.h @@ -0,0 +1,48 @@ +/* + XCC Utilities and Library + Copyright (C) 2004 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "cc_file_sh.h" +#include "palet.h" +#include "video_decoder.h" + +template <class T> +class Cvideo_file : public Ccc_file_sh<T> +{ +public: + virtual int cb_pixel() const = 0; + virtual int cf() const = 0; + virtual int cx() const = 0; + virtual int cy() const = 0; + + int cb_image() const + { + return cb_pixel() * cx() * cy(); + } + + int cb_video() const + { + return cf() * cb_image(); + } + + virtual const t_palet_entry* palet() const + { + return NULL; + } +}; diff --git a/3rdParty/xcc/misc/virtual_audio.cpp b/3rdParty/xcc/misc/virtual_audio.cpp new file mode 100644 index 0000000..410ae76 --- /dev/null +++ b/3rdParty/xcc/misc/virtual_audio.cpp @@ -0,0 +1,71 @@ +/* + XCC Utilities and Library + Copyright (C) 2001 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "virtual_audio.h" + +#include "aud_file_write.h" +#include "wav_file.h" + +Cvirtual_audio::Cvirtual_audio() +{ +} + +Cvirtual_audio::~Cvirtual_audio() +{ +} + +void Cvirtual_audio::load(Cvirtual_file f, int c_samples, int samplerate, int cb_sample, int c_channels) +{ + mc_samples = c_samples; + m_samplerate = samplerate; + mcb_sample = cb_sample; + mc_channels = c_channels; + m_f = f; + m_f.compact(); +} + +Cvirtual_file Cvirtual_audio::save_as_aud() const +{ + return aud_file_write(audio(), cb_audio(), c_samples(), samplerate(), c_channels()); +} + +int Cvirtual_audio::save_as_aud(string fname) const +{ + return aud_file_write(fname, audio(), cb_audio(), c_samples(), samplerate(), c_channels()); +} + +Cvirtual_file Cvirtual_audio::save_as_wav_ima_adpcm() const +{ + return wav_ima_adpcm_file_write(audio(), cb_audio(), c_samples(), samplerate(), c_channels()); +} + +int Cvirtual_audio::save_as_wav_ima_adpcm(string fname) const +{ + return wav_ima_adpcm_file_write(fname, audio(), cb_audio(), c_samples(), samplerate(), c_channels()); +} + +Cvirtual_file Cvirtual_audio::save_as_wav_pcm() const +{ + return wav_pcm_file_write(audio(), cb_audio(), samplerate(), cb_sample(), c_channels()); +} + +int Cvirtual_audio::save_as_wav_pcm(string fname) const +{ + return wav_pcm_file_write(fname, audio(), cb_audio(), samplerate(), cb_sample(), c_channels()); +} \ No newline at end of file diff --git a/3rdParty/xcc/misc/virtual_audio.h b/3rdParty/xcc/misc/virtual_audio.h new file mode 100644 index 0000000..6cc6de8 --- /dev/null +++ b/3rdParty/xcc/misc/virtual_audio.h @@ -0,0 +1,71 @@ +/* + XCC Utilities and Library + Copyright (C) 2001 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "virtual_file.h" + +class Cvirtual_audio +{ +public: + void load(Cvirtual_file f, int c_samples, int samplerate, int cb_sample, int c_channels); + Cvirtual_file save_as_aud() const; + int save_as_aud(string fname) const; + Cvirtual_file save_as_wav_ima_adpcm() const; + int save_as_wav_ima_adpcm(string fname) const; + Cvirtual_file save_as_wav_pcm() const; + int save_as_wav_pcm(string fname) const; + Cvirtual_audio(); + ~Cvirtual_audio(); + + const __int16* audio() const + { + return reinterpret_cast<const __int16*>(m_f.data()); + } + + int cb_audio() const + { + return mc_samples * mcb_sample * mc_channels; + } + + int c_samples() const + { + return mc_samples; + } + + int samplerate() const + { + return m_samplerate; + } + + int cb_sample() const + { + return mcb_sample; + } + + int c_channels() const + { + return mc_channels; + } +private: + Cvirtual_file m_f; + int mc_samples; + int m_samplerate; + int mcb_sample; + int mc_channels; +}; diff --git a/3rdParty/xcc/misc/virtual_binary.cpp b/3rdParty/xcc/misc/virtual_binary.cpp new file mode 100644 index 0000000..7d3ebcb --- /dev/null +++ b/3rdParty/xcc/misc/virtual_binary.cpp @@ -0,0 +1,165 @@ +/* + XCC Utilities and Library + Copyright (C) 2001 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include <virtual_binary.h> + +#include "file32.h" + +Cvirtual_binary_source::Cvirtual_binary_source(const void* d, size_t cb_d, const std::shared_ptr<const void>& source) +{ + if (source) + { + m_data = const_cast<byte*>(reinterpret_cast<const byte*>(d)); + m_size = cb_d; + m_source = source; + } + else + { + m_data = new byte[cb_d]; + m_size = cb_d; + if (d) + memcpy(m_data, d, cb_d); + } + mc_references = 1; +} + +Cvirtual_binary_source* Cvirtual_binary_source::attach() +{ + if (this) + mc_references++; + return this; +} + +void Cvirtual_binary_source::detach() +{ + if (!this || --mc_references) + return; + if (!m_source) + delete[] m_data; + delete this; +} + +Cvirtual_binary_source* Cvirtual_binary_source::pre_edit() +{ + if (mc_references == 1 && !m_source) + return this; + Cvirtual_binary_source* t = new Cvirtual_binary_source(m_data, m_size, NULL); + detach(); + return t; +} + +Cvirtual_binary::Cvirtual_binary() +{ + m_source = NULL; +} + +Cvirtual_binary::Cvirtual_binary(const Cvirtual_binary& v) +{ + m_source = v.m_source->attach(); +} + +Cvirtual_binary::Cvirtual_binary(const void* d, size_t cb_d) +{ + m_source = new Cvirtual_binary_source(d, cb_d); +} + +Cvirtual_binary::Cvirtual_binary(const void* d, size_t cb_d, const std::shared_ptr<void>& source) +{ + m_source = new Cvirtual_binary_source(d, cb_d, source); +} + +Cvirtual_binary::Cvirtual_binary(data_ref d) +{ + m_source = new Cvirtual_binary_source(d.data(), d.size()); +} + +Cvirtual_binary::Cvirtual_binary(const string& fname, bool use_mm) +{ + m_source = NULL; + load(fname, use_mm); +} + +Cvirtual_binary::~Cvirtual_binary() +{ + m_source->detach(); +} + +const Cvirtual_binary& Cvirtual_binary::operator=(const Cvirtual_binary& v) +{ + if (this != &v) + { + m_source->detach(); + m_source = v.m_source->attach(); + } + return *this; +} + +int Cvirtual_binary::save(const string& fname) const +{ + return data() ? file32_write(fname, data(), size()) : 1; +} + +int Cvirtual_binary::load(const string& fname, bool use_mm) +{ + if (use_mm) + *this = file32_read(fname); + else + { + Cvirtual_binary d = file32_read(fname); + *this = Cvirtual_binary(d.data(), d.size()); + } + return !data(); +} + +void Cvirtual_binary::clear() +{ + m_source->detach(); + m_source = NULL; +} + +void Cvirtual_binary::memset(int v) +{ + ::memset(data_edit(), v, size()); +} + +size_t Cvirtual_binary::read(void* d) const +{ + memcpy(d, data(), size()); + return size(); +} + +byte* Cvirtual_binary::write_start(size_t cb_d) +{ + if (data() && size() == cb_d) + return data_edit(); + m_source->detach(); + m_source = new Cvirtual_binary_source(NULL, cb_d); + return data_edit(); +} + +void Cvirtual_binary::write(const void* d, size_t cb_d) +{ + memcpy(write_start(cb_d), d, cb_d); +} + +Cvirtual_binary Cvirtual_binary::sub_bin(size_t offset, size_t size) const +{ + assert(offset >= 0 && offset + size <= Cvirtual_binary::size()); + return data() ? Cvirtual_binary(data() + offset, size, std::make_shared<Cvirtual_binary>(*this)) : *this; +} \ No newline at end of file diff --git a/3rdParty/xcc/misc/virtual_binary.h b/3rdParty/xcc/misc/virtual_binary.h new file mode 100644 index 0000000..9771175 --- /dev/null +++ b/3rdParty/xcc/misc/virtual_binary.h @@ -0,0 +1,140 @@ +/* + XCC Utilities and Library + Copyright (C) 2001 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cassert> +#include <memory> +#include <string> +#include <vartypes.h> +#include <xcc/data_ref.h> + +using namespace std; + +class Cvirtual_binary_source +{ +public: + Cvirtual_binary_source(const void* d, size_t cb_d, const std::shared_ptr<const void>& source = NULL); + Cvirtual_binary_source* attach(); + void detach(); + Cvirtual_binary_source* pre_edit(); + + const byte* data() const + { + return m_data; + } + + const byte* data_end() const + { + return data() + size(); + } + + byte* data_edit() + { + assert(mc_references == 1 && !m_source); + return m_data; + } + + size_t size() const + { + return m_size; + } + + void size(size_t v) + { + assert(mc_references == 1 && !m_source && v <= m_size); + m_size = v; + } + + bool unique() const + { + return mc_references == 1; + } +private: + byte* m_data; + size_t m_size; + int mc_references; + std::shared_ptr<const void> m_source; +}; + +class Cvirtual_binary +{ +public: + Cvirtual_binary sub_bin(size_t offset, size_t size) const; + int save(const string& fname) const; + int load(const string& fname, bool use_mm = true); + void clear(); + void memset(int v); + size_t read(void* d) const; + byte* write_start(size_t cb_d); + void write(const void* d, size_t cb_d); + const Cvirtual_binary& operator=(const Cvirtual_binary& v); + Cvirtual_binary(); + Cvirtual_binary(const Cvirtual_binary&); + Cvirtual_binary(data_ref); + Cvirtual_binary(const void*, size_t); + Cvirtual_binary(const void*, size_t, const std::shared_ptr<void>& source); + explicit Cvirtual_binary(const string& fname, bool use_mm = true); + ~Cvirtual_binary(); + + const byte* data() const + { + return m_source ? m_source->data() : NULL; + } + + const byte* data_end() const + { + return m_source ? m_source->data_end() : NULL; + } + + const byte* begin() const + { + return data(); + } + + const byte* end() const + { + return data_end(); + } + + byte* data_edit() + { + assert(m_source); + m_source = m_source->pre_edit(); + return m_source->data_edit(); + } + + byte* mutable_end() + { + return data_edit() + size(); + } + + size_t size() const + { + return m_source ? m_source->size() : 0; + } + + void set_size(size_t v) + { + assert(m_source); + m_source = m_source->pre_edit(); + m_source->size(v); + } +private: + Cvirtual_binary_source* m_source; +}; diff --git a/3rdParty/xcc/misc/virtual_file.cpp b/3rdParty/xcc/misc/virtual_file.cpp new file mode 100644 index 0000000..ba70183 --- /dev/null +++ b/3rdParty/xcc/misc/virtual_file.cpp @@ -0,0 +1,109 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "virtual_file.h" + +#include "file32.h" + +Cvirtual_file::Cvirtual_file() +{ +} + +Cvirtual_file::Cvirtual_file(const Cvirtual_binary& d) +{ + write(d); +} + +void Cvirtual_file::clear() +{ + m_data.clear(); +} + +void Cvirtual_file::compact() +{ + if (m_data.size() == 1) + return; + Cvirtual_binary t = read(); + clear(); + write(t); +} + +const byte* Cvirtual_file::data() const +{ + if (m_data.size() != 1) + return NULL; + return m_data.begin()->data(); +} + +int Cvirtual_file::size() const +{ + int r = 0; + for (auto& i : m_data) + r += i.size(); + return r; +} + +int Cvirtual_file::save(const string& fname) const +{ + Cfile32 f; + int error = f.open_write(fname); + if (!error) + { + for (auto& i : m_data) + error = f.write(i); + } + return error; +} + +int Cvirtual_file::load(const string& fname) +{ + clear(); + Cvirtual_binary t; + int error = t.load(fname); + if (!error) + write(t); + return error; +} + +Cvirtual_binary Cvirtual_file::read() const +{ + if (m_data.size() == 1) + return *m_data.begin(); + Cvirtual_binary r; + read(r.write_start(size())); + return r; +} + +int Cvirtual_file::read(void* d) const +{ + byte* w = reinterpret_cast<byte*>(d); + for (auto& i : m_data) + w += i.read(w); + return w - reinterpret_cast<byte*>(d); +} + +void Cvirtual_file::write(const Cvirtual_binary& d) +{ + m_data.push_back(d); +} + +void Cvirtual_file::write(const void* d, int cb_d) +{ + write(Cvirtual_binary(d, cb_d)); +} \ No newline at end of file diff --git a/3rdParty/xcc/misc/virtual_file.h b/3rdParty/xcc/misc/virtual_file.h new file mode 100644 index 0000000..2a4637e --- /dev/null +++ b/3rdParty/xcc/misc/virtual_file.h @@ -0,0 +1,44 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <list> +#include <virtual_binary.h> + +using namespace std; + +class Cvirtual_file +{ +public: + int save(const string& fname) const; + int load(const string& fname); + void clear(); + void compact(); + const byte* data() const; + int size() const; + Cvirtual_binary read() const; + int read(void* d) const; + void write(const Cvirtual_binary& d); + void write(const void* d, int cb_d); + Cvirtual_file(); + Cvirtual_file(const Cvirtual_binary& d); +private: + using t_data = list<Cvirtual_binary>; + t_data m_data; +}; diff --git a/3rdParty/xcc/misc/virtual_image.cpp b/3rdParty/xcc/misc/virtual_image.cpp new file mode 100644 index 0000000..456ea2d --- /dev/null +++ b/3rdParty/xcc/misc/virtual_image.cpp @@ -0,0 +1,332 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" + +#include <windows.h> +#include <gdiplus.h> +#include <shlwapi.h> + +#ifndef XCC_MINIMAL_BUILD +#include "dds_file.h" +#include "image_file.h" +#include "jpeg_file.h" +#include "pcx_file.h" +#include "pcx_file_write.h" +#include "png_file.h" +#include "tga_file.h" +#endif +#include "virtual_image.h" + +using namespace Gdiplus; + +Cvirtual_image::Cvirtual_image(const Cvirtual_binary& image, int cx, int cy, int cb_pixel, const t_palet_entry* palet, bool inflate) +{ + load(image, cx, cy, cb_pixel, palet, inflate); +} + +Cvirtual_image::Cvirtual_image(const void* image, int cx, int cy, int cb_pixel, const t_palet_entry* palet, bool inflate) +{ + load(image, cx, cy, cb_pixel, palet, inflate); +} + +const Cvirtual_image& Cvirtual_image::palet(const t_palet_entry* palet, bool inflate) +{ + if (palet) + { + memcpy(m_palet.write_start(sizeof(t_palet)), palet, sizeof(t_palet)); + if (inflate) + convert_palet_18_to_24(reinterpret_cast<t_palet_entry*>(m_palet.data_edit())); + } + else + m_palet.clear(); + return *this; +} + +void Cvirtual_image::load(const Cvirtual_binary& image, int cx, int cy, int cb_pixel, const t_palet_entry* p, bool inflate) +{ + assert(cb_pixel == 1 || cb_pixel == 3 || cb_pixel == 4); + m_cx = cx; + m_cy = cy; + mcb_pixel = cb_pixel; + if (image.size() == cb_image()) + m_image = image; + else + m_image.write_start(cb_image()); + palet(p, inflate); +} + +void Cvirtual_image::load(const void* image, int cx, int cy, int cb_pixel, const t_palet_entry* p, bool inflate) +{ + assert(cb_pixel == 1 || cb_pixel == 3 || cb_pixel == 4); + m_cx = cx; + m_cy = cy; + mcb_pixel = cb_pixel; + m_image.write_start(cb_image()); + if (image) + memcpy(m_image.data_edit(), image, cb_image()); + palet(p, inflate); +} + +#ifndef XCC_MINIMAL_BUILD + +int Cvirtual_image::load(const Cvirtual_binary& s) +{ + Cdds_file dds_f; + Cpcx_file pcx_f; + Cpng_file png_f; + Ctga_file tga_f; + if (dds_f.load(s), dds_f.is_valid()) + *this = dds_f.vimage(); + else if (pcx_f.load(s), pcx_f.is_valid()) + *this = pcx_f.vimage(); + else if (png_f.load(s), png_f.is_valid()) + return png_f.decode(*this); + else if (tga_f.load(s), tga_f.is_valid()) + return tga_f.decode(*this); + else + { + IStream* is = SHCreateMemStream(s.data(), s.size()); + Gdiplus::Bitmap bmp(is); + is->Release(); + if (bmp.GetLastStatus() != Ok) + return 1; + PixelFormat pf = bmp.GetPixelFormat(); + if (bmp.GetPixelFormat() & PixelFormatIndexed) + { + load(NULL, bmp.GetWidth(), bmp.GetHeight(), 1, NULL); + BitmapData d; + d.Stride = bmp.GetWidth(); + d.Scan0 = image_edit(); + bmp.LockBits(NULL, ImageLockModeRead | ImageLockModeUserInputBuf, PixelFormat8bppIndexed, &d); + bmp.UnlockBits(&d); + } + else + { + load(NULL, bmp.GetWidth(), bmp.GetHeight(), 3, NULL); + BitmapData d; + d.Stride = bmp.GetWidth() * 3; + d.Scan0 = image_edit(); + bmp.LockBits(NULL, ImageLockModeRead | ImageLockModeUserInputBuf, PixelFormat24bppRGB, &d); + bmp.UnlockBits(&d); + swap_rb(); + } + } + return 0; +} + +int Cvirtual_image::load(const Cvirtual_file& f) +{ + return load(f.read()); +} + +int Cvirtual_image::load(const string& fname) +{ + Cvirtual_binary s; + int error = s.load(fname); + if (!error) + error = load(s); + return error; +} + +int Cvirtual_image::save(Cvirtual_file& f, t_file_type ft) const +{ + return image_file_write(f, ft, image(), palet(), m_cx, m_cy); +} + +Cvirtual_file Cvirtual_image::save(t_file_type ft) const +{ + return image_file_write(ft, image(), palet(), m_cx, m_cy); +} + +int Cvirtual_image::save(const string& fname, t_file_type ft) const +{ + return image_file_write(fname, ft, image(), palet(), m_cx, m_cy); +} + +void Cvirtual_image::swap_rb() +{ + int count = m_cx * m_cy; + t_palet_entry* r = reinterpret_cast<t_palet_entry*>(m_image.data_edit()); + while (count--) + { + swap(r->r, r->b); + r++; + } +} + +static void flip_frame(const byte* s, byte* d, int cx, int cy, int cb_pixel) +{ + int cb_line = cx * cb_pixel; + const byte* r = s; + byte* w = d + cb_line * cy; + while (cy--) + { + w -= cb_line; + memcpy(w, r, cb_line); + r += cb_line; + } +} + +void Cvirtual_image::flip() +{ + Cvirtual_binary t = m_image; + flip_frame(t.data(), image_edit(), cx(), cy(), cb_pixel()); +} + + +void Cvirtual_image::cb_pixel(int cb_pixel, const t_palet_entry* palet) +{ + if (cb_pixel < mcb_pixel) + decrease_color_depth(cb_pixel, palet); + else if (cb_pixel > mcb_pixel) + increase_color_depth(cb_pixel); +} + +void Cvirtual_image::decrease_color_depth(int new_cb_pixel, const t_palet_entry* palet) +{ + if (new_cb_pixel == 3) + { + remove_alpha(); + return; + } + assert(new_cb_pixel == 1); + int old_cb_pixel = cb_pixel(); + Cvirtual_binary t = m_image; + load(NULL, cx(), cy(), new_cb_pixel, palet); + byte* w = image_edit(); + int count = m_cx * m_cy; + if (old_cb_pixel == 3) + { + const t_palet_entry* r = reinterpret_cast<const t_palet_entry*>(t.data()); + while (count--) + { + *w++ = find_color(r->r, r->g, r->b, palet); + r++; + } + } + else + { + assert(old_cb_pixel == 4); + const t_palet32entry* r = reinterpret_cast<const t_palet32entry*>(t.data()); + while (count--) + { + *w++ = r->a < 0x80 ? find_color(r->r, r->g, r->b, palet) : 0; + r++; + } + } +} + +static t_palet32entry p32e(int r, int g, int b, int a = 0) +{ + t_palet32entry e; + e.r = r; + e.g = g; + e.b = b; + e.a = a; + return e; +} + +static t_palet32entry p32e(t_palet_entry e) +{ + return p32e(e.r, e.g, e.b); +} + +static t_palet32entry p32e(const t_palet palet, int i) +{ + return i ? p32e(palet[i]) : p32e(0x80, 0x80, 0x80, 0xff); +} + +void Cvirtual_image::increase_color_depth(int new_cb_pixel) +{ + if (cb_pixel() == 3) + { + if (new_cb_pixel == 4) + add_alpha(); + return; + } + assert(cb_pixel() == 1); + Cvirtual_image t = *this; + const byte* r = t.image(); + load(NULL, cx(), cy(), new_cb_pixel, NULL); + int count = m_cx * m_cy; + if (cb_pixel() == 3) + { + t_palet_entry* w = reinterpret_cast<t_palet_entry*>(image_edit()); + while (count--) + *w++ = t.palet()[*r++]; + } + else + { + assert(cb_pixel() == 4); + t_palet32entry* w = reinterpret_cast<t_palet32entry*>(image_edit()); + while (count--) + *w++ = p32e(t.palet(), *r++); + } +} + +void Cvirtual_image::add_alpha() +{ + assert(cb_pixel() == 3); + Cvirtual_binary t = m_image; + load(NULL, cx(), cy(), 4, NULL); + int count = m_cx * m_cy; + const byte* r = t.data(); + byte* w = image_edit(); + while (count--) + { + *w++ = *r++; + *w++ = *r++; + *w++ = *r++; + *w++ = 0; + } +} + +void Cvirtual_image::remove_alpha() +{ + if (cb_pixel() != 4) + return; + Cvirtual_binary t = m_image; + load(NULL, cx(), cy(), 3, NULL); + int count = m_cx * m_cy; + const byte* r = t.data(); + byte* w = image_edit(); + while (count--) + { + *w++ = *r++; + *w++ = *r++; + *w++ = *r++; + r++; + } +} + +void Cvirtual_image::increase_palet_depth() +{ + assert(false); + Cvirtual_binary t = m_palet; + const t_palet_entry* s = reinterpret_cast<const t_palet_entry*>(t.data()); + t_palet_entry* d = reinterpret_cast<t_palet_entry*>(t.data_edit()); + for (int i = 0; i < 256; i++) + { + d[i].r = (s[i].r & 63) * 255 / 63; + d[i].g = (s[i].g & 63) * 255 / 63; + d[i].b = (s[i].b & 63) * 255 / 63; + } +} + +#endif diff --git a/3rdParty/xcc/misc/virtual_image.h b/3rdParty/xcc/misc/virtual_image.h new file mode 100644 index 0000000..0a2a2d6 --- /dev/null +++ b/3rdParty/xcc/misc/virtual_image.h @@ -0,0 +1,124 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "cc_file.h" +#include "palet.h" +#include "virtual_file.h" + +class Cvirtual_image +{ +public: + const Cvirtual_image& palet(const t_palet_entry* palet, bool inflate = false); + void remove_alpha(); + void add_alpha(); + void cb_pixel(int cb_pixel, const t_palet_entry* palet = NULL); + void decrease_color_depth(int cb_pixel, const t_palet_entry* palet = NULL); + void increase_color_depth(int cb_pixel); + void increase_palet_depth(); + void flip(); + int get_clipboard(); + int set_clipboard() const; + int load(); + int save() const; + void load(const Cvirtual_binary& image, int cx, int cy, int cb_pixel, const t_palet_entry* palet, bool inflate = false); + void load(const void* image, int cx, int cy, int cb_pixel, const t_palet_entry* palet, bool inflate = false); + int load(const Cvirtual_binary& s); + int load(const Cvirtual_file& f); + int load(const string& fname); + int save(Cvirtual_file& f, t_file_type ft) const; + Cvirtual_file save(t_file_type ft) const; + int save(const string& fname, t_file_type ft) const; + void swap_rb(); + Cvirtual_image() = default; + Cvirtual_image(const Cvirtual_binary& image, int cx, int cy, int cb_pixel, const t_palet_entry* palet = NULL, bool inflate = false); + Cvirtual_image(const void* image, int cx, int cy, int cb_pixel, const t_palet_entry* palet = NULL, bool inflate = false); + + const byte* image() const + { + return m_image.data(); + } + + byte* image_edit() + { + return m_image.data_edit(); + } + + int cx() const + { + return m_cx; + } + + int cy() const + { + return m_cy; + } + + int cb_pixel() const + { + return mcb_pixel; + } + + const t_palet_entry* palet() const + { + return reinterpret_cast<const t_palet_entry*>(m_palet.data()); + } + + int cb_image() const + { + return m_cx * m_cy * mcb_pixel; + } + + int ofs8(int x, int y) const + { + return x + m_cx * y; + } + + int ofs24(int x, int y) const + { + return ofs8(x, y) * 3; + } + + int pixel8(int x, int y) const + { + return m_image.data()[ofs8(x, y)]; + } + + void pixel8(int x, int y, int v) + { + m_image.data_edit()[ofs8(x, y)] = v; + } + + t_palet_entry pixel24(int x, int y) const + { + return reinterpret_cast<const t_palet_entry*>(m_image.data())[ofs8(x, y)]; + } + + void pixel24(int x, int y, t_palet_entry v) + { + reinterpret_cast<t_palet_entry*>(m_image.data_edit())[ofs8(x, y)] = v; + } +private: + Cvirtual_binary m_image; + Cvirtual_binary m_palet; + int m_cx = 0; + int m_cy = 0; + int mcb_pixel = 0; +}; + diff --git a/3rdParty/xcc/misc/virtual_tfile.cpp b/3rdParty/xcc/misc/virtual_tfile.cpp new file mode 100644 index 0000000..c1965f6 --- /dev/null +++ b/3rdParty/xcc/misc/virtual_tfile.cpp @@ -0,0 +1,93 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "virtual_tfile.h" + +void Cvirtual_tfile::load_data(const Cvirtual_binary s) +{ + m_data = s; + pos = 0; +} + +string Cvirtual_tfile::read_line() +{ + assert(data()); + const int first_non_ws = pos; + int last_non_ws; + while (pos < size()) + { + switch (data()[pos++]) + { + case '\r': + last_non_ws = pos - 2; + if (pos < size() && data()[pos] == '\n') + pos++; + return string(data() + first_non_ws, last_non_ws - first_non_ws + 1); + case '\n': + last_non_ws = pos - 2; + return string(data() + first_non_ws, last_non_ws - first_non_ws + 1); + } + } + last_non_ws = size() - 1; + return string(data() + first_non_ws, last_non_ws - first_non_ws + 1); +} + +string Cvirtual_tfile::read_line(bool remove_ws) +{ + if (!remove_ws) + return read_line(); + assert(data()); + int first_non_ws; + int last_non_ws; + while (pos < size()) + { + switch (data()[pos++]) + { + case '\r': + if (pos < size() && data()[pos] == '\n') + pos++; + case '\n': + return ""; + case '\t': + case ' ': + break; + default: + first_non_ws = pos - 1; + last_non_ws = pos - 2; + while (pos < size()) + { + switch (data()[pos++]) + { + case '\r': + if (pos < size() && data()[pos] == '\n') + pos++; + case '\n': + return string(data() + first_non_ws, last_non_ws - first_non_ws + 1); + case '\t': + case ' ': + break; + default: + last_non_ws = pos - 1; + } + } + return string(data() + first_non_ws, last_non_ws - first_non_ws + 1); + } + } + return ""; +} \ No newline at end of file diff --git a/3rdParty/xcc/misc/virtual_tfile.h b/3rdParty/xcc/misc/virtual_tfile.h new file mode 100644 index 0000000..418be44 --- /dev/null +++ b/3rdParty/xcc/misc/virtual_tfile.h @@ -0,0 +1,53 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <vartypes.h> +#include <virtual_binary.h> + +class Cvirtual_tfile +{ +private: + Cvirtual_binary m_data; + int pos; + + const char* data() const + { + return reinterpret_cast<const char*>(m_data.data()); + } + + int size() const + { + return m_data.size(); + } +public: + string read_line(); + string read_line(bool remove_ws); + void load_data(const Cvirtual_binary s); + + bool eof() const + { + return pos >= size(); + } + + void seek(int ipos) + { + pos = ipos; + } +}; diff --git a/3rdParty/xcc/misc/vxl_file.cpp b/3rdParty/xcc/misc/vxl_file.cpp new file mode 100644 index 0000000..a629aa1 --- /dev/null +++ b/3rdParty/xcc/misc/vxl_file.cpp @@ -0,0 +1,676 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "vxl_file.h" + +#include "file32.h" +#include "image_file.h" +#ifndef XCC_MINIMAL_BUILD +#include "multi_line.h" +#include "pcx_decode.h" +#include "pcx_file_write.h" +#endif +#include "string_conversion.h" + +bool Cvxl_file::is_valid() const +{ + int size = get_size(); + const t_vxl_header& h = header(); + if (sizeof(t_vxl_header) > size || + strcmp(h.id, vxl_id) || + h.one != 1 || + h.c_section_headers != h.c_section_tailers || + h.size != size - sizeof(t_vxl_header) - h.c_section_headers * sizeof(t_vxl_section_header) - h.c_section_tailers * sizeof(t_vxl_section_tailer) || + h.unknown != 0x1f10) + return false; + /* + for (int i = 0; i < header.c_section_headers; i++) + { + const t_vxl_section_header& section_header = *get_section_header(i); + const t_vxl_section_tailer& section_tailer = *get_section_tailer(i); + if (section_header.one != 1 || + section_header.zero || + section_tailer.span_end_ofs - section_tailer.span_start_ofs != section_tailer.span_data_ofs - section_tailer.span_end_ofs) + return false; + } + */ + return true; +} + +#ifndef XCC_MINIMAL_BUILD +int Cvxl_file::extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet _palet) const +{ + t_palet palet; + memcpy(palet, _palet, sizeof(t_palet)); + convert_palet_18_to_24(palet); + const t_vxl_section_tailer& section_tailer = *get_section_tailer(0); + const int cx = section_tailer.cx; + const int cy = section_tailer.cy; + const int cz = section_tailer.cz; + Cvirtual_binary s; + for (int i = 0; i < cz; i++) + { + memset(s.write_start(cx * cy), 0, cx * cy); + int j = 0; + for (int y = 0; y < cy; y++) + { + for (int x = 0; x < cx; x++) + { + const byte* r = get_span_data(0, j); + if (r) + { + int z = 0; + while (z < cz) + { + z += *r++; + int c = *r++; + while (c--) + { + if (i == z) + s.data_edit()[x + cx * y] = *r; + r += 2; + z++; + } + r++; + } + } + j++; + } + } + Cfname t = name; + t.set_title(name.get_ftitle() + " " + nwzl(4, i)); + int error = image_file_write(t, ft, s.data(), palet, cx, cy); + if (error) + return error; + } + return 0; +} +#endif + +ostream& Cvxl_file::extract_as_text(ostream& os) const +{ + for (int i = 0; i < get_c_section_headers(); i++) + { + const t_vxl_section_tailer& section_tailer = *get_section_tailer(i); + const int cx = section_tailer.cx; + const int cy = section_tailer.cy; + const int cz = section_tailer.cz; + int j = 0; + for (int y = 0; y < cy; y++) + { + for (int x = 0; x < cx; x++) + { + const byte* r = get_span_data(i, j); + if (r) + { + int z = 0; + while (z < cz) + { + z += *r++; + int c = *r++; + while (c--) + { + os << i << ',' << x << ',' << y << ',' << z << ',' << static_cast<int>(*r++) << ',' << static_cast<int>(*r++) << endl; + z++; + } + r++; + } + } + j++; + } + } + } + return os; +} + +enum +{ + vi_header, + vi_body, + vi_tailer, + vi_palet, + vi_color, + vi_surface_normal, + + vi_x, + vi_y, + vi_z, + vi_cx, + vi_cy, + vi_cz, + vi_id, + vi_red, + vi_green, + vi_blue, + vi_x_min, + vi_y_min, + vi_z_min, + vi_x_max, + vi_y_max, + vi_z_max +}; + +#ifndef XCC_MINIMAL_BUILD +int Cvxl_file::extract_as_xif(const string& name) const +{ + Cxif_key k; + Cxif_key& header = k.open_key_write(vi_header); + Cxif_key& palet = header.open_key_write(vi_palet); + int i; + for (i = 0; i < 256; i++) + { + Cxif_key& palet_entry = palet.open_key_write(i); + palet_entry.set_value_int(vi_red, get_palet()[i].r); + palet_entry.set_value_int(vi_green, get_palet()[i].g); + palet_entry.set_value_int(vi_blue, get_palet()[i].b); + } + Cxif_key& body = k.open_key_write(vi_body); + for (i = 0; i < get_c_section_headers(); i++) + { + const t_vxl_section_header& section_header = *get_section_header(i); + const t_vxl_section_tailer& section_tailer = *get_section_tailer(i); + const int cx = section_tailer.cx; + const int cy = section_tailer.cy; + const int cz = section_tailer.cz; + Cxif_key& section = body.open_key_write(i); + Cxif_key& header = section.open_key_write(vi_header); + header.set_value_string(vi_id, section_header.id); + Cxif_key& body = section.open_key_write(vi_body); + int j = 0; + for (int y = 0; y < cy; y++) + { + Cxif_key& yi = body.open_key_write(y); + for (int x = 0; x < cx; x++) + { + Cxif_key& xi = yi.open_key_write(x); + const byte* r = get_span_data(i, j); + if (r) + { + int z = 0; + while (z < cz) + { + z += *r++; + int c = *r++; + while (c--) + { + Cxif_key& zi = xi.open_key_write(z); + zi.set_value_int(vi_color, *r++); + zi.set_value_int(vi_surface_normal, *r++); + z++; + } + r++; + } + } + j++; + } + } + Cxif_key& tailer = section.open_key_write(vi_tailer); + tailer.set_value_int(vi_x_min, section_tailer.x_min_scale * 1000000); + tailer.set_value_int(vi_y_min, section_tailer.y_min_scale * 1000000); + tailer.set_value_int(vi_z_min, section_tailer.z_min_scale * 1000000); + tailer.set_value_int(vi_x_max, section_tailer.x_max_scale * 1000000); + tailer.set_value_int(vi_y_max, section_tailer.y_max_scale * 1000000); + tailer.set_value_int(vi_z_max, section_tailer.z_max_scale * 1000000); + tailer.set_value_int(vi_cx, cx); + tailer.set_value_int(vi_cy, cy); + tailer.set_value_int(vi_cz, cz); + } + return k.vdata().save(name); +} + +Cvirtual_binary vxl_file_write(const Cxif_key& s) +{ + Cvirtual_binary d; + byte* w = d.write_start(1 << 20); + const Cxif_key& header_key = s.open_key_read(vi_header); + const Cxif_key& body_key = s.open_key_read(vi_body); + int c_sections = body_key.c_keys(); + int* span_start_list_ofs = new int[c_sections]; + int* span_end_list_ofs = new int[c_sections]; + int* span_data_ofs = new int[c_sections]; + t_vxl_header& header = *reinterpret_cast<t_vxl_header*>(w); + strcpy(header.id, vxl_id); + header.one = 1; + header.c_section_headers = c_sections; + header.c_section_tailers = c_sections; + header.unknown = 0x1f10; + const Cxif_key& palet_key = header_key.open_key_read(vi_palet); + int i; + for (i = 0; i < 256; i++) + { + const Cxif_key& palet_entry_key = palet_key.open_key_read(i); + header.palet[i].r = palet_entry_key.get_value_int(vi_red); + header.palet[i].g = palet_entry_key.get_value_int(vi_green); + header.palet[i].b = palet_entry_key.get_value_int(vi_blue); + } + w += sizeof(t_vxl_header); + for (i = 0; i < c_sections; i++) + { + const Cxif_key& section_key = body_key.open_key_read(i); + const Cxif_key& section_header_key = section_key.open_key_read(vi_header); + t_vxl_section_header& section_header = *reinterpret_cast<t_vxl_section_header*>(w); + strcpy(section_header.id, section_header_key.get_value_string(vi_id).c_str()); + section_header.section_i = i; + section_header.one = 1; + section_header.zero = 0; + w += sizeof(t_vxl_section_header); + } + byte* body_start = w; + for (i = 0; i < c_sections; i++) + { + const Cxif_key& section_key = body_key.open_key_read(i); + const Cxif_key& section_body_key = section_key.open_key_read(vi_body); + const Cxif_key& section_tailer_key = section_key.open_key_read(vi_tailer); + const int cx = section_tailer_key.get_value_int(vi_cx); + const int cy = section_tailer_key.get_value_int(vi_cy); + const int cz = section_tailer_key.get_value_int(vi_cz); + __int32* span_start_list = reinterpret_cast<__int32*>(w); + span_start_list_ofs[i] = w - body_start; + w += 4 * cx * cy; + __int32* span_end_list = reinterpret_cast<__int32*>(w); + span_end_list_ofs[i] = w - body_start; + w += 4 * cx * cy; + byte* span_data_start = w; + span_data_ofs[i] = w - body_start; + int span_i = 0; + for (int y = 0; y < cy; y++) + { + const Cxif_key& yi = section_body_key.open_key_read(y); + for (int x = 0; x < cx; x++) + { + byte* span_start = w; + const Cxif_key& xi = yi.open_key_read(x); + int z = 0; + for (auto& i : xi.m_keys) + { + int z_inc = i.first - z; + z = i.first + 1; + *w++ = z_inc; + *w++ = 1; + *w++ = i.second.get_value_int(vi_color); + *w++ = i.second.get_value_int(vi_surface_normal); + *w++ = 1; + } + if (span_start == w) + { + span_start_list[span_i] = -1; + span_end_list[span_i] = -1; + } + else + { + if (z != cz) + { + *w++ = cz - z; + *w++ = 0; + *w++ = 0; + } + span_start_list[span_i] = span_start - span_data_start; + span_end_list[span_i] = w - span_data_start - 1; + } + span_i++; + } + } + } + header.size = w - body_start; + for (i = 0; i < c_sections; i++) + { + const Cxif_key& section_key = body_key.open_key_read(i); + const Cxif_key& section_tailer_key = section_key.open_key_read(vi_tailer); + t_vxl_section_tailer& section_tailer = *reinterpret_cast<t_vxl_section_tailer*>(w); + + section_tailer.span_start_ofs = span_start_list_ofs[i]; + section_tailer.span_end_ofs = span_end_list_ofs[i]; + section_tailer.span_data_ofs = span_data_ofs[i]; + section_tailer.scale = 0; + for (int ty = 0; ty < 3; ty++) + { + for (int tx = 0; tx < 4; tx++) + section_tailer.transform[ty][tx] = 0; + } + section_tailer.x_min_scale = section_tailer_key.get_value_int(vi_x_min) / 1000000.0; + section_tailer.y_min_scale = section_tailer_key.get_value_int(vi_y_min) / 1000000.0; + section_tailer.z_min_scale = section_tailer_key.get_value_int(vi_z_min) / 1000000.0; + section_tailer.x_max_scale = section_tailer_key.get_value_int(vi_x_max) / 1000000.0; + section_tailer.y_max_scale = section_tailer_key.get_value_int(vi_y_max) / 1000000.0; + section_tailer.z_max_scale = section_tailer_key.get_value_int(vi_z_max) / 1000000.0; + section_tailer.cx = section_tailer_key.get_value_int(vi_cx); + section_tailer.cy = section_tailer_key.get_value_int(vi_cy); + section_tailer.cz = section_tailer_key.get_value_int(vi_cz); + section_tailer.unknown = 2; + w += sizeof(t_vxl_section_tailer); + } + delete[] span_data_ofs; + delete[] span_end_list_ofs; + delete[] span_start_list_ofs; + d.set_size(w - d.data()); + return d; +} + +Cvirtual_binary vxl_file_write(const byte* s, const byte* s_normals, int cx, int cy, int cz) +{ + Cxif_key k; + Cxif_key& header = k.open_key_write(vi_header); + Cxif_key& palet = header.open_key_write(vi_palet); + for (int i = 0; i < 256; i++) + { + Cxif_key& palet_entry = palet.open_key_write(i); + palet_entry.set_value_int(vi_red, i); + palet_entry.set_value_int(vi_green, i); + palet_entry.set_value_int(vi_blue, i); + } + Cxif_key& body = k.open_key_write(vi_body); + { + Cxif_key& section = body.open_key_write(0); + Cxif_key& header = section.open_key_write(vi_header); + header.set_value_string(vi_id, "NONE"); + Cxif_key& body = section.open_key_write(vi_body); + for (int y = 0; y < cy; y++) + { + Cxif_key& yi = body.open_key_write(y); + for (int x = 0; x < cx; x++) + { + Cxif_key& xi = yi.open_key_write(x); + const byte* r = s + x + cx * y; + for (int z = 0; z < cz; z++) + { + int v = *r; + if (v) + { + Cxif_key& zi = xi.open_key_write(z); + zi.set_value_int(vi_color, v); + zi.set_value_int(vi_surface_normal, s_normals ? s_normals[r - s]: -1); + } + r += cx * cy; + } + } + } + Cxif_key& tailer = section.open_key_write(vi_tailer); + tailer.set_value_int(vi_x_min, cx * -1000000 / 2); + tailer.set_value_int(vi_y_min, cy * -1000000 / 2); + tailer.set_value_int(vi_z_min, cz * -1000000 / 2); + tailer.set_value_int(vi_x_max, cx * +1000000 / 2); + tailer.set_value_int(vi_y_max, cy * +1000000 / 2); + tailer.set_value_int(vi_z_max, cz * +1000000 / 2); + tailer.set_value_int(vi_cx, cx); + tailer.set_value_int(vi_cy, cy); + tailer.set_value_int(vi_cz, cz); + } + return vxl_file_write(k); +} + +struct t_voxel +{ + int x; + int y; + int z; + int color; + int normal; +}; + +Cvirtual_binary vxl_file_write(Cvirtual_tfile s) +{ + using t_list = list<t_voxel>; + + t_list list; + + int cs = 0; + int cx = 0; + int cy = 0; + int cz = 0; + while (!s.eof()) + { + Cmulti_line l = s.read_line(); + t_voxel e; + int s = l.get_next_int(','); + e.x = l.get_next_int(','); + e.y = l.get_next_int(','); + e.z = l.get_next_int(','); + e.normal = l.get_next_int(','); + e.color = l.get_next_int(','); + if (!s) + list.push_back(e); + cs = max(cs, s + 1); + cx = max(cx, e.x + 1); + cy = max(cy, e.y + 1); + cz = max(cz, e.z + 1); + } + Cvirtual_binary colors(NULL, cx * cy * cz); + Cvirtual_binary normals(NULL, cx * cy * cz); + colors.memset(0); + normals.memset(0); + for (auto& e : list) + { + int o = e.x + cx * (e.y + cy * e.z); + colors.data_edit()[o] = e.color; + normals.data_edit()[o] = e.normal; + } + return vxl_file_write(colors.data(), normals.data(), cx, cy, cz); +} + +#endif + +struct t_vxl4_header +{ + unsigned __int32 c_sections; +}; + +struct t_vxl4_section_header +{ + char id[16]; + __int32 section_i; + float scale; + float x_min_scale; + float y_min_scale; + float z_min_scale; + float x_max_scale; + float y_max_scale; + float z_max_scale; + unsigned __int8 cx; + unsigned __int8 cy; + unsigned __int8 cz; + __int8 unknown; +}; + +int vxl_encode4(const Cvxl_file& f, byte* d) +{ + const int c_sections = f.get_c_section_headers(); + + byte* w = d; + t_vxl4_header& header = *reinterpret_cast<t_vxl4_header*>(w); + header.c_sections = c_sections; + w += sizeof(t_vxl4_header); + + for (int i = 0; i < c_sections; i++) + { + const t_vxl_section_header& s_section_header = *f.get_section_header(i); + const t_vxl_section_tailer& section_tailer = *f.get_section_tailer(i); + const int cx = section_tailer.cx; + const int cy = section_tailer.cy; + const int cz = section_tailer.cz; + + t_vxl4_section_header& section_header = *reinterpret_cast<t_vxl4_section_header*>(w); + strcpy(section_header.id, s_section_header.id); + section_header.section_i = s_section_header.section_i; + assert(s_section_header.section_i == i); + section_header.scale = section_tailer.scale; + section_header.x_min_scale = section_tailer.x_min_scale; + section_header.y_min_scale = section_tailer.y_min_scale; + section_header.z_min_scale = section_tailer.z_min_scale; + section_header.x_max_scale = section_tailer.x_max_scale; + section_header.y_max_scale = section_tailer.y_max_scale; + section_header.z_max_scale = section_tailer.z_max_scale; + section_header.cx = section_tailer.cx; + section_header.cy = section_tailer.cy; + section_header.cz = section_tailer.cz; + section_header.unknown = section_tailer.unknown; + w += sizeof(t_vxl4_section_header); + for (int j = 0; j < f.get_c_spans(i); j++) + { + const byte* r = f.get_span_data(i, j); + if (r) + { + int z = 0; + while (z < cz) + { + int z_inc = *w++ = *r++; + if (z_inc == cz) + break; + z += z_inc; + int c = *w++ = *r++; + while (c--) + { + *w++ = *r++; + *w++ = *r++; + z++; + } + r++; + } + } + else + *w++ = cz; + } + } + return w - d; +} + +int vxl_decode4_size(const byte* s) +{ + const byte* r = s; + const t_vxl4_header& s_header = *reinterpret_cast<const t_vxl4_header*>(r); + const int c_sections = s_header.c_sections; + r += sizeof(t_vxl4_header); + int w = 0; + for (int i = 0; i < c_sections; i++) + { + const t_vxl4_section_header& section_header = *reinterpret_cast<const t_vxl4_section_header*>(r); + const int cx = section_header.cx; + const int cy = section_header.cy; + const int cz = section_header.cz; + w += 8 * cx * cy; + r += sizeof(t_vxl4_section_header); + for (int j = 0; j < cx * cy; j++) + { + int z = 0; + while (z < cz) + { + int z_inc = *r++; + if (z_inc == cz) + break; + z += z_inc; + int count = *r++; + r += 2 * count; + w += 2 * count + 3; + z += count; + } + } + } + return w + + sizeof(t_vxl_header) + + (sizeof(t_vxl_section_header) + sizeof(t_vxl_section_tailer)) * c_sections; +} + +Cvirtual_binary vxl_decode4(const byte* s, int cb_d) +{ + Cvirtual_binary d; + const byte* r = s; + const t_vxl4_header& s_header = *reinterpret_cast<const t_vxl4_header*>(r); + const int c_sections = s_header.c_sections; + r += sizeof(t_vxl4_header); + byte* w = d.write_start(cb_d ? cb_d : 1 << 20); + t_vxl_header& header = *reinterpret_cast<t_vxl_header*>(w); + strcpy(header.id, vxl_id); + header.one = 1; + header.c_section_headers = c_sections; + header.c_section_tailers = c_sections; + header.unknown = 0x1f10; + w += sizeof(t_vxl_header); + t_vxl_section_header* d_section_header = reinterpret_cast<t_vxl_section_header*>(w); + t_vxl_section_tailer* section_tailer = new t_vxl_section_tailer[c_sections]; + w += sizeof(t_vxl_section_header) * c_sections; + byte* body_start = w; + for (int i = 0; i < c_sections; i++) + { + const t_vxl4_section_header& section_header = *reinterpret_cast<const t_vxl4_section_header*>(r); + const int cx = section_header.cx; + const int cy = section_header.cy; + const int cz = section_header.cz; + strcpy(d_section_header->id, section_header.id); + d_section_header->section_i = section_header.section_i; + d_section_header->one = 1; + d_section_header->zero = 0; + d_section_header++; + __int32* span_start_list = reinterpret_cast<__int32*>(w); + section_tailer[i].span_start_ofs = w - body_start; + w += 4 * cx * cy; + __int32* span_end_list = reinterpret_cast<__int32*>(w); + section_tailer[i].span_end_ofs = w - body_start; + w += 4 * cx * cy; + section_tailer[i].span_data_ofs = w - body_start; + section_tailer[i].scale = section_header.scale; + section_tailer[i].x_min_scale = section_header.x_min_scale; + section_tailer[i].y_min_scale = section_header.y_min_scale; + section_tailer[i].z_min_scale = section_header.z_min_scale; + section_tailer[i].x_max_scale = section_header.x_max_scale; + section_tailer[i].y_max_scale = section_header.y_max_scale; + section_tailer[i].z_max_scale = section_header.z_max_scale; + section_tailer[i].cx = section_header.cx; + section_tailer[i].cy = section_header.cy; + section_tailer[i].cz = section_header.cz; + section_tailer[i].unknown = section_header.unknown; + r += sizeof(t_vxl4_section_header); + byte* span_data_start = w; + for (int j = 0; j < cx * cy; j++) + { + byte* span_start = w; + int z = 0; + while (z < cz) + { + int z_inc = *r++; + if (z_inc == cz) + break; + z += *w++ = z_inc; + int count = *w++ = *r++; + int c = count; + while (c--) + { + *w++ = *r++; + *w++ = *r++; + z++; + } + *w++ = count; + } + if (span_start == w) + { + span_start_list[j] = -1; + span_end_list[j] = -1; + } + else + { + span_start_list[j] = span_start - span_data_start; + span_end_list[j] = w - span_data_start - 1; + } + } + } + header.size = w - body_start; + memcpy(w, section_tailer, sizeof(t_vxl_section_tailer) * c_sections); + delete[] section_tailer; + w += sizeof(t_vxl_section_tailer) * c_sections; + assert(!cb_d || d.size() == w - d.data()); + return cb_d ? d : Cvirtual_binary(d.data(), w - d.data()); +} diff --git a/3rdParty/xcc/misc/vxl_file.h b/3rdParty/xcc/misc/vxl_file.h new file mode 100644 index 0000000..5dd1857 --- /dev/null +++ b/3rdParty/xcc/misc/vxl_file.h @@ -0,0 +1,106 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "cc_file_sh.h" +#include "cc_structures.h" +#include "fname.h" +#include "virtual_tfile.h" +#ifndef XCC_MINIMAL_BUILD +#include "xif_key.h" +#endif + +class Cvxl_file : public Ccc_file_sh<t_vxl_header> +{ +public: +#ifndef XCC_MINIMAL_BUILD + int extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet _palet) const; +#endif + ostream& extract_as_text(ostream& os) const; +#ifndef XCC_MINIMAL_BUILD + int extract_as_xif(const string& name) const; +#endif + bool is_valid() const; + + int get_c_section_headers() const + { + return header().c_section_headers; + } + + int get_c_spans(int i) const + { + return get_section_tailer(i)->span_end_ofs - get_section_tailer(i)->span_start_ofs >> 2; + } + + int get_c_section_tailers() const + { + return header().c_section_tailers; + } + + const t_palet_entry* get_palet() const + { + return header().palet; + } + + const byte* get_section_body() const + { + return data() + sizeof(t_vxl_header) + sizeof(t_vxl_section_header) * get_c_section_tailers(); + } + + const t_vxl_section_header* get_section_header(int i) const + { + return reinterpret_cast<const t_vxl_section_header*>(data() + sizeof(t_vxl_header) + sizeof(t_vxl_section_header) * i); + } + + const t_vxl_section_tailer* get_section_tailer(int i) const + { + return reinterpret_cast<const t_vxl_section_tailer*>(data() + get_size() + sizeof(t_vxl_section_tailer) * (i - get_c_section_tailers())); + } + + const byte* get_span_data(int i, int j) const + { + if (get_span_start_list(i)[j] == -1) + return NULL; + return get_section_body() + get_section_tailer(i)->span_data_ofs + get_span_start_list(i)[j]; + } + + int get_span_size(int i, int j) const + { + return get_span_end_list(i)[j] - get_span_start_list(i)[j] + 1; + } + + const int* get_span_start_list(int i) const + { + return reinterpret_cast<const int*>(get_section_body() + get_section_tailer(i)->span_start_ofs); + } + + const int* get_span_end_list(int i) const + { + return reinterpret_cast<const int*>(get_section_body() + get_section_tailer(i)->span_end_ofs); + } +}; + +int vxl_decode4_size(const byte* s); +Cvirtual_binary vxl_decode4(const byte* s, int cb_d); +int vxl_encode4(const Cvxl_file& f, byte* d); +#ifndef XCC_MINIMAL_BUILD +Cvirtual_binary vxl_file_write(const Cxif_key& s); +Cvirtual_binary vxl_file_write(const byte* s, const byte* s_normals, int cx, int cy, int cz); +Cvirtual_binary vxl_file_write(Cvirtual_tfile s); +#endif diff --git a/3rdParty/xcc/misc/win_handle.cpp b/3rdParty/xcc/misc/win_handle.cpp new file mode 100644 index 0000000..ce6f97d --- /dev/null +++ b/3rdParty/xcc/misc/win_handle.cpp @@ -0,0 +1,36 @@ +/* + XCC Utilities and Library + Copyright (C) 2002 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "win_handle.h" + +int create_process(const std::string& exe_name, const std::string& _cmd_line, bool wait) +{ + char cmd_line[256]; + strcpy(cmd_line, ("\"" + exe_name + "\" " + _cmd_line).c_str()); + STARTUPINFO si; + memset(&si, 0, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + PROCESS_INFORMATION pi; + int error = !CreateProcess(exe_name.c_str(), cmd_line, NULL, NULL, false, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi); + if (!error && wait) + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return error; +} diff --git a/3rdParty/xcc/misc/win_handle.h b/3rdParty/xcc/misc/win_handle.h new file mode 100644 index 0000000..9d49d92 --- /dev/null +++ b/3rdParty/xcc/misc/win_handle.h @@ -0,0 +1,50 @@ +/* + XCC Utilities and Library + Copyright (C) 2002 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <memory> +#include <string> +#include <windows.h> + +template<class T> +class Cwin_handle_base +{ +public: + Cwin_handle_base() = default; + + explicit Cwin_handle_base(T h) : m_source(h == INVALID_HANDLE_VALUE ? NULL : h, CloseHandle) + { + } + + void clear() + { + m_source.reset(); + } + + operator T() const + { + return static_cast<T>(m_source.get()); + } +private: + std::shared_ptr<void> m_source; +}; + +using Cwin_handle = Cwin_handle_base<HANDLE>; + +int create_process(const std::string& exe_name, const std::string& _cmd_line = "", bool wait = false); diff --git a/3rdParty/xcc/misc/xcc/data_ref.h b/3rdParty/xcc/misc/xcc/data_ref.h new file mode 100644 index 0000000..685d4b5 --- /dev/null +++ b/3rdParty/xcc/misc/xcc/data_ref.h @@ -0,0 +1,66 @@ +/* + XCC Utilities and Library + Copyright (C) 2021 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <span> + +template <class T, class U> +class data_ref_base : public std::span<T> +{ +private: + using base_t = std::span<T>; +public: + data_ref_base() = default; + + template<class V> + data_ref_base(const V& v, typename std::enable_if_t<std::is_class<V>::value>* = 0) + { + if (v.end() != v.begin()) + assign(&*v.begin(), v.end() - v.begin() + &*v.begin()); + } + + template<class V> + data_ref_base(V& v, typename std::enable_if<std::is_class<V>::value>* = 0) + { + if (v.end() != v.begin()) + assign(&*v.begin(), v.end() - v.begin() + &*v.begin()); + } + + data_ref_base(U begin, U end) + { + assign(begin, end); + } + + data_ref_base(U begin, size_t size) + { + assign(begin, size); + } + + void assign(U begin, U end) + { + static_cast<base_t&>(*this) = base_t(reinterpret_cast<T*>(begin), reinterpret_cast<T*>(end)); + } + + void assign(U begin, size_t size) + { + assign(begin, reinterpret_cast<T*>(begin) + size); + } +}; + +using data_ref = data_ref_base<const unsigned char, const void*>; diff --git a/3rdParty/xcc/misc/xcc/find_ptr.h b/3rdParty/xcc/misc/xcc/find_ptr.h new file mode 100644 index 0000000..0ec2a11 --- /dev/null +++ b/3rdParty/xcc/misc/xcc/find_ptr.h @@ -0,0 +1,86 @@ +/* + XCC Utilities and Library + Copyright (C) 2021 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +template <class T, class U> +const typename T::value_type::second_type* find_ptr(const T& c, const U& v) +{ + typename T::const_iterator i = c.find(v); + return i == c.end() ? NULL : &i->second; +} + +template <class T, class U> +typename T::value_type::second_type* find_ptr(T& c, const U& v) +{ + typename T::iterator i = c.find(v); + return i == c.end() ? NULL : &i->second; +} + +template <class T, class U> +const typename T::value_type::second_type& find_ptr2(const T& c, const U& v) +{ + static typename T::value_type::second_type z = typename T::value_type::second_type(); + typename T::const_iterator i = c.find(v); + return i == c.end() ? z : i->second; +} + +template <class T, class U> +typename T::value_type::second_type& find_ptr2(T& c, const U& v) +{ + static typename T::value_type::second_type z = typename T::value_type::second_type(); + typename T::iterator i = c.find(v); + return i == c.end() ? z : i->second; +} + +template <class T, class U> +const typename T::value_type* find_ptr0(const T& c, const U& v) +{ + typename T::const_iterator i = c.find(v); + return i == c.end() ? NULL : &*i; +} + +template <class T, class U> +typename T::value_type::second_type& find_ref(T& c, const U& v) +{ + typename T::iterator i = c.find(v); + assert(i != c.end()); + return i->second; +} + +template <class T, class U> +const typename T::value_type::second_type& find_ref(const T& c, const U& v) +{ + typename T::const_iterator i = c.find(v); + assert(i != c.end()); + return i->second; +} + +template <class T, class U> +const typename T::value_type::second_type& find_ref(const T& c, const U& v, const typename T::value_type::second_type& z) +{ + typename T::const_iterator i = c.find(v); + return i == c.end() ? z : i->second; +} + +template <class T, class U> +typename T::value_type::second_type& find_ref(T& c, const U& v, typename T::value_type::second_type& z) +{ + typename T::iterator i = c.find(v); + return i == c.end() ? z : i->second; +} diff --git a/3rdParty/xcc/misc/xcc/string_view.h b/3rdParty/xcc/misc/xcc/string_view.h new file mode 100644 index 0000000..6b6484f --- /dev/null +++ b/3rdParty/xcc/misc/xcc/string_view.h @@ -0,0 +1,68 @@ +/* + XCC Utilities and Library + Copyright (C) 2021 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <charconv> +#include <string> +#include <string_view> + +inline std::string& operator<<(std::string& a, std::string_view b) +{ + return a += b; +} + +template<class T> +inline std::enable_if_t<std::is_integral<T>::value, std::string&> operator<<(std::string& a, T b) +{ + return a += std::to_string(b); +} + +inline float to_float(std::string_view s) +{ + float v; + auto res = std::from_chars(s.data(), s.data() + s.size(), v); + return res.ec == std::errc() && res.ptr == s.data() + s.size() ? v : 0; +} + +inline long long to_int(std::string_view s) +{ + long long v; + auto res = std::from_chars(s.data(), s.data() + s.size(), v); + return res.ec == std::errc() && res.ptr == s.data() + s.size() ? v : 0; +} + +template<size_t N> +std::string_view to_string_view(const std::array<char, N>& v) +{ + return std::string_view(v.data(), v.size()); +} + +template<size_t N> +std::string_view to_string_view(const std::array<unsigned char, N>& v) +{ + return std::string_view(reinterpret_cast<const char*>(v.data()), v.size()); +} + +inline std::string_view read_until(std::string_view& v, char sep, bool keep_sep = false) +{ + size_t i = v.find(sep); + std::string_view ret = v.substr(0, i); + v.remove_prefix(i == std::string_view::npos ? v.size() : keep_sep ? i : i + 1); + return ret; +} diff --git a/3rdParty/xcc/misc/xcc_dirs.cpp b/3rdParty/xcc/misc/xcc_dirs.cpp new file mode 100644 index 0000000..a8cb29a --- /dev/null +++ b/3rdParty/xcc/misc/xcc_dirs.cpp @@ -0,0 +1,417 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "xcc_dirs.h" + +#include <boost/algorithm/string.hpp> +#include <cassert> +#include <windows.h> +#include "reg_key.h" +#include "string_conversion.h" +#include "xcc_registry.h" + +bool g_enable_log = false; +static string dune2_dir; +static string td_primary_dir; +static string td_secondary_dir; +static string cd_dir; +static string data_dir; +static string ra_dir; +static string dune2000_dir; +static string ts_dir; +static string ra2_dir; +static string nox_dir; +static string rg_dir; +static string gr_dir; +static string gr_zh_dir; +static string ebfd_dir; +static string bfme_dir; +static string tw_dir; + +bool xcc_dirs::enable_log() +{ + return g_enable_log; +} + +string xcc_dirs::get_dir(t_game game) +{ + switch (game) + { + case game_td: + return td_primary_dir; + case game_ra: + return ra_dir; + case game_ts: + case game_ts_fs: + return ts_dir; + case game_dune2: + return dune2_dir; + case game_dune2000: + return dune2000_dir; + case game_ra2: + case game_ra2_yr: + return ra2_dir; + case game_nox: + return nox_dir; + case game_rg: + return rg_dir; + case game_gr: + return gr_dir; + case game_gr_zh: + return gr_zh_dir; + case game_ebfd: + return ebfd_dir; + case game_bfme: + return bfme_dir; + case game_tw: + return tw_dir; + } + assert(false); + return ""; +} + +string xcc_dirs::get_exe(t_game game) +{ + switch (game) + { + case game_td: + return td_primary_dir + "c&c95.exe"; + case game_ra: + return ra_dir + "ra95.exe"; + case game_ts: + return ts_dir + "sun.exe"; + case game_dune2: + return dune2_dir + "dune2.exe"; + case game_dune2000: + return dune2000_dir + "dune2000.exe"; + case game_ra2: + return ra2_dir + "ra2.exe"; + case game_nox: + return nox_dir + "nox.exe"; + case game_ra2_yr: + return ra2_dir + "ra2md.exe"; + case game_gr: + return gr_dir + "generals.exe"; + case game_bfme: + return bfme_dir + "lotrbfme.exe"; + } + assert(false); + return ""; +} + +string xcc_dirs::get_audio_mix(t_game game) +{ + switch (game) + { + case game_ra2: + return "audio.mix"; + case game_ra2_yr: + return "audiomd.mix"; + } + assert(false); + return ""; +} + +string xcc_dirs::get_csf_fname(t_game game) +{ + switch (game) + { + case game_ra2: + return "ra2.csf"; + case game_ra2_yr: + return "ra2md.csf"; + case game_gr: + case game_gr_zh: + return "data/english/generals.csf"; + } + assert(false); + return ""; +} + +static string get_suffix(t_game game) +{ + return game == game_ra2_yr ? "md" : ""; +} + +string xcc_dirs::get_ecache_mix(t_game game, bool dir, int i) +{ + return get_ecache_mix(game, dir, nwzl(2, i)); +} + +string xcc_dirs::get_ecache_mix(t_game game, bool dir, const string& s) +{ + string r = "ecache" + get_suffix(game) + s + ".mix"; + if (dir) + r = get_dir(game) + r; + return r; +} + +string xcc_dirs::get_expand_mix(t_game game, int i) +{ + return get_expand_mix(game, nwzl(2, i)); +} + +string xcc_dirs::get_expand_mix(t_game game, const string& s) +{ + return get_dir(game) + "expand" + get_suffix(game) + s + ".mix"; +} + +string xcc_dirs::get_language_mix(t_game game) +{ + switch (game) + { + case game_ra2: + return ra2_dir + "language.mix"; + case game_ra2_yr: + return ra2_dir + "langmd.mix"; + case game_gr: + return gr_dir + "english.big"; + case game_gr_zh: + return gr_zh_dir + "englishzh.big"; + } + assert(false); + return ""; +} + +string xcc_dirs::get_local_mix(t_game game) +{ + switch (game) + { + case game_ts: + case game_ra2: + return "local.mix"; + case game_ra2_yr: + return "localmd.mix"; + } + assert(false); + return ""; +} + +string xcc_dirs::get_main_mix(t_game game) +{ + switch (game) + { + case game_ra: + return ra_dir + "redalert.mix"; + case game_ts: + return ts_dir + "tibsun.mix"; + case game_ra2: + return ra2_dir + "ra2.mix"; + case game_ra2_yr: + return ra2_dir + "ra2md.mix"; + } + assert(false); + return ""; +} + +static void set_path(string s, string& path) +{ + boost::to_lower(s); + if (!s.empty() && s.back() != '\\') + s += '\\'; + path = s; +} + +void xcc_dirs::set_dir(t_game game, const string &s) +{ + switch (game) + { + case game_td: + set_path(s, td_primary_dir); + break; + case game_ra: + set_path(s, ra_dir); + break; + case game_ts: + set_path(s, ts_dir); + break; + case game_dune2: + set_path(s, dune2_dir); + break; + case game_dune2000: + set_path(s, dune2000_dir); + break; + case game_ra2: + set_path(s, ra2_dir); + break; + case game_nox: + set_path(s, nox_dir); + break; + case game_rg: + set_path(s, rg_dir); + break; + case game_gr: + set_path(s, gr_dir); + break; + case game_gr_zh: + set_path(s, gr_zh_dir); + break; + case game_ebfd: + set_path(s, ebfd_dir); + break; + case game_bfme: + set_path(s, bfme_dir); + break; + case game_tw: + set_path(s, tw_dir); + break; + default: + assert(false); + } +} + +void xcc_dirs::set_td_secondary_dir(const string& s) +{ + set_path(s, td_secondary_dir); +} + +void xcc_dirs::set_cd_dir(const string& s) +{ + set_path(s, cd_dir); +} + +void xcc_dirs::set_data_dir(const string& s) +{ + set_path(s, data_dir); +} + +void xcc_dirs::reset_cd_dir() +{ + int drive_map = GetLogicalDrives(); + char drive_root[] = "a:\\"; + for (int i = 0; i < 26; i++) + { + if (drive_map >> i & 1 && GetDriveTypeA(drive_root) == DRIVE_CDROM) + { + set_cd_dir(drive_root); + break; + } + drive_root[0]++; + } +} + +void xcc_dirs::reset_data_dir() +{ + set_data_dir(GetModuleFileName().get_path()); +} + +static void read_dir(const string& key, const string& value, t_game game) +{ + Creg_key h; + string s; + if (xcc_dirs::get_dir(game).empty() + && ERROR_SUCCESS == h.open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE) + && ERROR_SUCCESS == h.query_value(value, s)) + xcc_dirs::set_dir(game, Cfname(s).get_path()); +} + +void xcc_dirs::load_from_registry() +{ + Creg_key kh_base; + if (!Cxcc_registry::get_base_key(kh_base)) + { + string s; + if (ERROR_SUCCESS == kh_base.query_value("dune2_dir", s)) + set_dir(game_dune2, s); + if (ERROR_SUCCESS == kh_base.query_value("dir1", s)) + set_dir(game_td, s); + if (ERROR_SUCCESS == kh_base.query_value("dir2", s)) + set_td_secondary_dir(s); + if (ERROR_SUCCESS == kh_base.query_value("ra_dir", s)) + set_dir(game_ra, s); + if (ERROR_SUCCESS == kh_base.query_value("cd_dir", s)) + set_cd_dir(s); + if (ERROR_SUCCESS == kh_base.query_value("data_dir", s)) + set_data_dir(s); + if (ERROR_SUCCESS == kh_base.query_value("enable_log", s)) + g_enable_log = true; + } + if (cd_dir.empty()) + reset_cd_dir(); + if (data_dir.empty()) + reset_data_dir(); + read_dir("Software\\Westwood\\Dune 2", "InstallPath", game_dune2); + read_dir("Software\\Westwood\\Command & Conquer Windows 95 Edition", "InstallPath", game_td); + read_dir("Software\\Westwood\\Red Alert Windows 95 Edition", "InstallPath", game_ra); + read_dir("Software\\Westwood\\Dune 2000", "InstallPath", game_dune2000); + read_dir("Software\\Westwood\\Tiberian Sun", "InstallPath", game_ts); + read_dir("Software\\Westwood\\Red Alert 2", "InstallPath", game_ra2); + read_dir("Software\\Westwood\\Nox", "InstallPath", game_nox); + read_dir("Software\\Westwood\\Renegade", "InstallPath", game_rg); + read_dir("Software\\Westwood\\Emperor", "InstallPath", game_ebfd); + /* + read_dir("Software\\Electronic Arts\\EA Games\\Generals", "InstallPath", game_gr); + read_dir("Software\\Electronic Arts\\EA Games\\Command and Conquer Generals Zero Hour", "InstallPath", game_gr_zh); + read_dir("Software\\Electronic Arts\\EA Games\\The Battle for Middle-earth", "InstallPath", game_bfme); + read_dir("Software\\Electronic Arts\\Electronic Arts\\Command and Conquer 3", "InstallPath", game_tw); + */ +} + +void xcc_dirs::save_to_registry() +{ + Creg_key kh_base; + if (Cxcc_registry::get_base_key(kh_base)) + return; + kh_base.set_value("dune2_dir", dune2_dir); + kh_base.set_value("dir1", td_primary_dir); + kh_base.set_value("dir2", td_secondary_dir); + kh_base.set_value("ra_dir", ra_dir); +}; + +string xcc_dirs::find_file(Cfname s) +{ + if (!s.get_path().empty() || s.exists()) + return s; + s.set_path(td_primary_dir); + if (s.exists()) + return s; + s.set_path(td_secondary_dir); + if (s.exists()) + return s; + s.set_path(ra_dir); + if (s.exists()) + return s; + s.set_path(ts_dir); + if (s.exists()) + return s; + s.set_path(ra2_dir); + if (s.exists()) + return s; + s.set_path(cd_dir); + return s; +} + +bool xcc_dirs::is_available(t_game game) +{ + return Cfname(get_exe(game)).exists(); +} + +const string& xcc_dirs::get_td_secondary_dir() +{ + return td_secondary_dir; +} + +const string& xcc_dirs::get_cd_dir() +{ + return cd_dir; +} + +const string& xcc_dirs::get_data_dir() +{ + return data_dir; +} diff --git a/3rdParty/xcc/misc/xcc_dirs.h b/3rdParty/xcc/misc/xcc_dirs.h new file mode 100644 index 0000000..8f374d1 --- /dev/null +++ b/3rdParty/xcc/misc/xcc_dirs.h @@ -0,0 +1,52 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "cc_structures.h" +#include "fname.h" + +class xcc_dirs +{ +public: + static bool enable_log(); + static void load_from_registry(); + static void save_to_registry(); + static string find_file(Cfname s); + static bool is_available(t_game game); + static string get_audio_mix(t_game game); + static string get_csf_fname(t_game game); + static string get_dir(t_game game); + static string get_exe(t_game game); + static string get_ecache_mix(t_game game, bool dir, int i); + static string get_ecache_mix(t_game game, bool dir, const string& s); + static string get_expand_mix(t_game game, int i); + static string get_expand_mix(t_game game, const string& s); + static string get_language_mix(t_game game); + static string get_local_mix(t_game game); + static string get_main_mix(t_game game); + static void set_td_secondary_dir(const string& s); + static void set_cd_dir(const string &s); + static void set_data_dir(const string &s); + static void set_dir(t_game game, const string& s); + static void reset_cd_dir(); + static void reset_data_dir(); + static const string& get_td_secondary_dir(); + static const string& get_cd_dir(); + static const string& get_data_dir(); +}; diff --git a/3rdParty/xcc/misc/xcc_file.h b/3rdParty/xcc/misc/xcc_file.h new file mode 100644 index 0000000..d063e38 --- /dev/null +++ b/3rdParty/xcc/misc/xcc_file.h @@ -0,0 +1,48 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cc_file_sh.h> +#include <cc_structures.h> + +enum t_xcc_ft +{ + xcc_ft_lmd, xcc_ft_xif, xcc_ft_unknown +}; + +const char* xcc_ft_name[]; + +class Cxcc_file : public Ccc_file_sh<t_xcc_header> +{ +public: + bool is_valid() const + { + const t_xcc_header& h = header(); + int size = get_size(); + return !(sizeof(t_xcc_header) > size || + strcmp(h.id, xcc_id) || + h.size != size || + h.version); + } + + t_xcc_ft get_ft() const + { + return static_cast<t_xcc_ft>(header().type); + } +}; diff --git a/3rdParty/xcc/misc/xcc_file_sh.h b/3rdParty/xcc/misc/xcc_file_sh.h new file mode 100644 index 0000000..f2fbf69 --- /dev/null +++ b/3rdParty/xcc/misc/xcc_file_sh.h @@ -0,0 +1,31 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "xcc_file.h" + +template <class T> +class Cxcc_file_sh : public Cxcc_file +{ +public: + const T& header() const + { + return *reinterpret_cast<const T*>(data() + sizeof(t_xcc_header)); + } +}; diff --git a/3rdParty/xcc/misc/xcc_lmd_file.h b/3rdParty/xcc/misc/xcc_lmd_file.h new file mode 100644 index 0000000..b5bde8f --- /dev/null +++ b/3rdParty/xcc/misc/xcc_lmd_file.h @@ -0,0 +1,45 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "xcc_file_sh.h" + +class Cxcc_lmd_file : public Cxcc_file_sh<t_xcc_lmd_header> +{ +public: + bool is_valid() const + { + return Cxcc_file_sh<t_xcc_lmd_header>::is_valid() && get_ft() == xcc_ft_lmd; + } + + t_game get_game() const + { + return static_cast<t_game>(header().game); + } + + int get_c_fnames() const + { + return header().c_fnames; + } + + const char* get_fnames() const + { + return reinterpret_cast<const char*>(data() + sizeof(t_xcc_header) + sizeof(t_xcc_lmd_header)); + } +}; diff --git a/3rdParty/xcc/misc/xcc_lmd_file_write.cpp b/3rdParty/xcc/misc/xcc_lmd_file_write.cpp new file mode 100644 index 0000000..23fda02 --- /dev/null +++ b/3rdParty/xcc/misc/xcc_lmd_file_write.cpp @@ -0,0 +1,53 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "xcc_lmd_file_write.h" + +#include "cc_structures.h" +#include "xcc_file.h" + +void Cxcc_lmd_file_write::add_fname(const string& fname) +{ + m_index.push_back(to_lower_copy(fname)); +} + +Cvirtual_binary Cxcc_lmd_file_write::write(t_game game) const +{ + int size = sizeof(t_xcc_header) + sizeof(t_xcc_lmd_header); + for (auto& i : m_index) + size += i.length() + 1; + Cvirtual_binary data; + byte* w = data.write_start(size); + t_xcc_header& header = *reinterpret_cast<t_xcc_header*>(w); + strcpy(header.id, xcc_id); + header.size = size; + header.type = xcc_ft_lmd; + header.version = 0; + w += sizeof(t_xcc_header); + t_xcc_lmd_header& lmd_header = *reinterpret_cast<t_xcc_lmd_header*>(w); + lmd_header.c_fnames = m_index.size(); + lmd_header.game = game; + w += sizeof(t_xcc_lmd_header); + for (auto& i : m_index) + { + strcpy(reinterpret_cast<char*>(w), i.c_str()); + w += i.length() + 1; + } + return data; +} \ No newline at end of file diff --git a/3rdParty/xcc/misc/xcc_lmd_file_write.h b/3rdParty/xcc/misc/xcc_lmd_file_write.h new file mode 100644 index 0000000..4e02a8e --- /dev/null +++ b/3rdParty/xcc/misc/xcc_lmd_file_write.h @@ -0,0 +1,35 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <vector> +#include "cc_structures.h" +#include <virtual_binary.h> + +using namespace std; + +class Cxcc_lmd_file_write +{ +public: + void add_fname(const string& fname); + Cvirtual_binary write(t_game game) const; +private: + using t_index = vector<string>; + t_index m_index; +}; diff --git a/3rdParty/xcc/misc/xcc_registry.cpp b/3rdParty/xcc/misc/xcc_registry.cpp new file mode 100644 index 0000000..e14c965 --- /dev/null +++ b/3rdParty/xcc/misc/xcc_registry.cpp @@ -0,0 +1,25 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "xcc_registry.h" + +int Cxcc_registry::get_base_key(Creg_key& kh_base) +{ + return ERROR_SUCCESS != kh_base.create(HKEY_CURRENT_USER, "Software\\XCC"); +} diff --git a/3rdParty/xcc/misc/xcc_registry.h b/3rdParty/xcc/misc/xcc_registry.h new file mode 100644 index 0000000..48890e6 --- /dev/null +++ b/3rdParty/xcc/misc/xcc_registry.h @@ -0,0 +1,27 @@ +/* + XCC Utilities and Library + Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "reg_key.h" + +class Cxcc_registry +{ +public: + static int get_base_key(Creg_key&); +}; diff --git a/3rdParty/xcc/patch.70358b46858973426c1ecf204485cb2a88716217.diff b/3rdParty/xcc/patch.70358b46858973426c1ecf204485cb2a88716217.diff new file mode 100644 index 0000000..497958a --- /dev/null +++ b/3rdParty/xcc/patch.70358b46858973426c1ecf204485cb2a88716217.diff @@ -0,0 +1,769 @@ +diff --git a/Library/StdAfx.h b/Library/StdAfx.h +index f688f65..ce37391 100644 +--- a/Library/StdAfx.h ++++ b/Library/StdAfx.h +@@ -35,7 +35,9 @@ + #include <vector> + #include <xcc/data_ref.h> + #include <xcc/find_ptr.h> ++#ifndef XCC_MINIMAL_BUILD + #include <xcc/string_view.h> ++#endif + + using namespace std; + using boost::iequals; +diff --git a/Library/XCC Library.vcxproj b/Library/XCC Library.vcxproj +index 0481daf..857d3f8 100644 +--- a/Library/XCC Library.vcxproj ++++ b/Library/XCC Library.vcxproj +@@ -1,10 +1,18 @@ + <?xml version="1.0" encoding="utf-8"?> + <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> ++ <ProjectConfiguration Include="DebugMinimal|Win32"> ++ <Configuration>DebugMinimal</Configuration> ++ <Platform>Win32</Platform> ++ </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> ++ <ProjectConfiguration Include="ReleaseMinimal|Win32"> ++ <Configuration>ReleaseMinimal</Configuration> ++ <Platform>Win32</Platform> ++ </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> +@@ -18,18 +26,59 @@ + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> ++ <OutDir>$(SolutionDir)\build\output\$(Configuration)-$(Platform)\lib\</OutDir> ++ <IntDir>$(SolutionDir)\build\intermediate\$(Configuration)-$(Platform)\$(ProjectName)\</IntDir> + <ConfigurationType>StaticLibrary</ConfigurationType> +- <UseOfMfc>Static</UseOfMfc> ++ <UseOfMfc>Dynamic</UseOfMfc> ++ <CharacterSet>MultiByte</CharacterSet> ++ <WholeProgramOptimization>true</WholeProgramOptimization> ++ <PlatformToolset>v143</PlatformToolset> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseMinimal|Win32'" Label="Configuration"> ++ <OutDir>$(SolutionDir)\build\output\$(Configuration)-$(Platform)\lib\</OutDir> ++ <IntDir>$(SolutionDir)\build\intermediate\$(Configuration)-$(Platform)\$(ProjectName)\</IntDir> ++ <ConfigurationType>StaticLibrary</ConfigurationType> ++ <UseOfMfc>Dynamic</UseOfMfc> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + <PlatformToolset>v143</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> ++ <OutDir>$(SolutionDir)\build\output\$(Configuration)-$(Platform)\lib\</OutDir> ++ <IntDir>$(SolutionDir)\build\intermediate\$(Configuration)-$(Platform)\$(ProjectName)\</IntDir> ++ <ConfigurationType>StaticLibrary</ConfigurationType> ++ <UseOfMfc>Dynamic</UseOfMfc> ++ <CharacterSet>MultiByte</CharacterSet> ++ <PlatformToolset>v143</PlatformToolset> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMinimal|Win32'" Label="Configuration"> ++ <OutDir>$(SolutionDir)\build\output\$(Configuration)-$(Platform)\lib\</OutDir> ++ <IntDir>$(SolutionDir)\build\intermediate\$(Configuration)-$(Platform)\$(ProjectName)\</IntDir> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseOfMfc>Dynamic</UseOfMfc> + <CharacterSet>MultiByte</CharacterSet> + <PlatformToolset>v143</PlatformToolset> + </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="XCC"> ++ <XCC_MINIMAL_BUILD> ++ </XCC_MINIMAL_BUILD> ++ <NO_FT_SUPPORT> ++ </NO_FT_SUPPORT> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)'=='ReleaseMinimal'" Label="XCC"> ++ <XCC_MINIMAL_BUILD>XCC_MINIMAL_BUILD</XCC_MINIMAL_BUILD> ++ <NO_FT_SUPPORT>NO_FT_SUPPORT</NO_FT_SUPPORT> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="XCC"> ++ <XCC_MINIMAL_BUILD> ++ </XCC_MINIMAL_BUILD> ++ <NO_FT_SUPPORT> ++ </NO_FT_SUPPORT> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)'=='DebugMinimal'" Label="XCC"> ++ <XCC_MINIMAL_BUILD>XCC_MINIMAL_BUILD</XCC_MINIMAL_BUILD> ++ <NO_FT_SUPPORT>NO_FT_SUPPORT</NO_FT_SUPPORT> ++ </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> +@@ -37,10 +86,18 @@ + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\XCC.props" /> + </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseMinimal|Win32'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="..\XCC.props" /> ++ </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\XCC.props" /> + </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugMinimal|Win32'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="..\XCC.props" /> ++ </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> +@@ -51,7 +108,22 @@ + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> +- <PreprocessorDefinitions>_DEBUG;WIN32;_LIB;JPEG_SUPPORT;OGG_SUPPORT;PNG_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <PreprocessorDefinitions>_DEBUG;WIN32;_LIB;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> ++ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> ++ <PrecompiledHeader>Use</PrecompiledHeader> ++ <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles> ++ <LanguageStandard>stdcpplatest</LanguageStandard> ++ </ClCompile> ++ <ResourceCompile> ++ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <Culture>0x0413</Culture> ++ </ResourceCompile> ++ </ItemDefinitionGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMinimal|Win32'"> ++ <ClCompile> ++ <Optimization>Disabled</Optimization> ++ <PreprocessorDefinitions>_DEBUG;WIN32;_LIB;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);%(PreprocessorDefinitions)</PreprocessorDefinitions> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <PrecompiledHeader>Use</PrecompiledHeader> +@@ -65,7 +137,7 @@ + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> +- <PreprocessorDefinitions>NDEBUG;WIN32;_LIB;JPEG_SUPPORT;OGG_SUPPORT;PNG_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <PreprocessorDefinitions>NDEBUG;WIN32;_LIB;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> +@@ -78,204 +150,293 @@ + <Culture>0x0413</Culture> + </ResourceCompile> + </ItemDefinitionGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseMinimal|Win32'"> ++ <ClCompile> ++ <PreprocessorDefinitions>NDEBUG;WIN32;_LIB;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <StringPooling>true</StringPooling> ++ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> ++ <FunctionLevelLinking>true</FunctionLevelLinking> ++ <PrecompiledHeader>Use</PrecompiledHeader> ++ <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles> ++ <LanguageStandard>stdcpplatest</LanguageStandard> ++ </ClCompile> ++ <ResourceCompile> ++ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <Culture>0x0413</Culture> ++ </ResourceCompile> ++ </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\misc\aud_decode.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\aud_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\aud_file_write.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\audio_idx_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\avi_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\big_edit.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\big_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\big_file_write.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\blowfish.cpp"> + </ClCompile> + <ClCompile Include="..\misc\bmp_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\cc_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">false</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\cc_structures.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">false</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\cps_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\csf_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\ddpf_conversion.cpp"> + </ClCompile> + <ClCompile Include="..\misc\dds_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\file32.cpp"> + </ClCompile> + <ClCompile Include="..\misc\fname.cpp"> + </ClCompile> + <ClCompile Include="..\misc\fs_ini_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\hva_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\id_log.cpp"> + </ClCompile> + <ClCompile Include="..\misc\ima_adpcm_wav_decode.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\ima_adpcm_wav_encode.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\image_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\image_tools.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\ini_reader.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> ++ </ClCompile> ++ <ClCompile Include="..\misc\jpeg_file.cpp"> ++ <ExcludedFromBuild Condition="'$(JPEG_SUPPORT)'==''">true</ExcludedFromBuild> + </ClCompile> +- <ClCompile Include="..\misc\jpeg_file.cpp" /> + <ClCompile Include="..\misc\map_ra_ini_reader.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\map_td_ini_reader.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\map_ts_encoder.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\map_ts_ini_reader.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\mix_cache.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\mix_decode.cpp"> + </ClCompile> + <ClCompile Include="..\misc\mix_edit.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\mix_file.cpp"> + </ClCompile> + <ClCompile Include="..\misc\mix_file_write.cpp"> + </ClCompile> + <ClCompile Include="..\misc\mix_rg_edit.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\mix_rg_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\mix_rg_file_write.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\mix_sfl.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\mp3_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\mp3_frame_header.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\multi_line.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\neat_ini_reader.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\neat_key_list.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\ogg_file.cpp"> ++ <ExcludedFromBuild Condition="'$(OGG_SUPPORT)'==''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\pak_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\pal_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\palet.cpp"> + </ClCompile> + <ClCompile Include="..\misc\pcx_decode.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\pcx_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\pcx_file_write.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\pkt_ts_ini_reader.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> +- <ClCompile Include="..\misc\png_file.cpp" /> +- <ClCompile Include="..\misc\reg_key.cpp"> ++ <ClCompile Include="..\misc\png_file.cpp"> ++ <ExcludedFromBuild Condition="'$(PNG_SUPPORT)'==''">true</ExcludedFromBuild> + </ClCompile> ++ <ClCompile Include="..\misc\reg_key.cpp" /> + <ClCompile Include="..\misc\riff_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\rules_ts_ini_reader.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\shp_decode.cpp"> + </ClCompile> + <ClCompile Include="..\misc\shp_dune2_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\shp_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\shp_images.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\shp_ts_file.cpp"> + </ClCompile> + <ClCompile Include="..\misc\shp_ts_file_write.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\sound_ts_ini_reader.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\st_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="StdAfx.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> ++ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugMinimal|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> ++ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseMinimal|Win32'">Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="..\misc\string_conversion.cpp"> + </ClCompile> + <ClCompile Include="..\misc\tga_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\theme_ts_ini_reader.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\timer.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\tmp_ra.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\tmp_ts_file.cpp"> + </ClCompile> + <ClCompile Include="..\misc\video_decoder.cpp"> + </ClCompile> + <ClCompile Include="..\misc\virtual_audio.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> +- <ClCompile Include="..\misc\virtual_binary.cpp"> +- </ClCompile> ++ <ClCompile Include="..\misc\virtual_binary.cpp" /> + <ClCompile Include="..\misc\virtual_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> +- <ClCompile Include="..\misc\virtual_image.cpp"> +- </ClCompile> ++ <ClCompile Include="..\misc\virtual_image.cpp" /> + <ClCompile Include="..\misc\virtual_tfile.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\voc_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\vqa_decode.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\vqa_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\vxl_file.cpp"> + </ClCompile> + <ClCompile Include="..\misc\wav_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\wav_header.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\win_handle.cpp"> + </ClCompile> + <ClCompile Include="..\misc\wsa_dune2_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\wsa_file.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\xcc_apps.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> +- <ClCompile Include="..\misc\xcc_dirs.cpp"> +- </ClCompile> ++ <ClCompile Include="..\misc\xcc_dirs.cpp" /> + <ClCompile Include="..\misc\xcc_draw.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> +- <ClCompile Include="..\misc\xcc_lmd_file_write.cpp"> +- </ClCompile> ++ <ClCompile Include="..\misc\xcc_lmd_file_write.cpp" /> + <ClCompile Include="..\misc\xcc_log.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\xcc_mixs.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> +- <ClCompile Include="..\misc\xcc_registry.cpp"> +- </ClCompile> ++ <ClCompile Include="..\misc\xcc_registry.cpp" /> + <ClCompile Include="..\misc\xif_key.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\xif_key_r.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\xif_value.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\xse.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="..\misc\XSTE.cpp"> ++ <ExcludedFromBuild Condition="'$(XCC_MINIMAL_BUILD)'!=''">true</ExcludedFromBuild> + </ClCompile> + </ItemGroup> + <ItemGroup> +@@ -301,7 +462,6 @@ + <ClInclude Include="..\misc\dd_window.h" /> + <ClInclude Include="..\misc\ddpf_conversion.h" /> + <ClInclude Include="..\misc\dds_file.h" /> +- <ClInclude Include="..\misc\ETSLayout.h" /> + <ClInclude Include="..\misc\extract_object.h" /> + <ClInclude Include="..\misc\file32.h" /> + <ClInclude Include="..\misc\fname.h" /> +@@ -413,4 +573,13 @@ + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> ++ <PropertyGroup> ++ <IntegratedVCPKG_ROOT>$(VcpkgRoot)</IntegratedVCPKG_ROOT> ++ </PropertyGroup> ++ <Import Project="$(VCINSTALLDIR)vcpkg\scripts\buildsystems\msbuild\vcpkg.props" Condition="'$(IntegratedVCPKG_ROOT)'=='' And Exists('$(VCINSTALLDIR)vcpkg\scripts\buildsystems\msbuild\vcpkg.props')" /> ++ <Import Project="$(VCINSTALLDIR)vcpkg\scripts\buildsystems\msbuild\vcpkg.targets" Condition="'$(IntegratedVCPKG_ROOT)'=='' And Exists('$(VCINSTALLDIR)vcpkg\scripts\buildsystems\msbuild\vcpkg.targets')" /> ++ <Target Name="CheckVCPKG" BeforeTargets="BeforeClCompile"> ++ <Error Text="You have neither installed VCPKG in your Visual C++ installation nor do you have VCPKG integrated into MSBuild. Please update your Visual Studio 2022 installation and after updating add the VCPKG single component. More details are available in the Readme.md file." Condition="'$(VcpkgRoot)' == ''" /> ++ <Warning Text="'$(VcpkgRoot)\.vcpkg-root' does not exist. Either VcpkgRoot is set to a invalid location or you may have to repair your VCPKG installation (e.g. using the Visual Studio installer)" Condition="!Exists('$(VcpkgRoot)\.vcpkg-root')" /> ++ </Target> + </Project> +\ No newline at end of file +diff --git a/XCC.props b/XCC.props +index f813cc4..5970828 100644 +--- a/XCC.props ++++ b/XCC.props +@@ -15,4 +15,5 @@ + <AdditionalDependencies>dsound.lib;gdiplus.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> ++ + </Project> +diff --git a/misc/cc_file.cpp b/misc/cc_file.cpp +index 13e4976..d9e9e11 100644 +--- a/misc/cc_file.cpp ++++ b/misc/cc_file.cpp +@@ -19,6 +19,7 @@ + #include "stdafx.h" + #include "cc_file.h" + ++#ifndef XCC_MINIMAL_BUILD + #include "aud_file.h" + #include "avi_file.h" + #include "big_file.h" +@@ -70,6 +71,11 @@ + #include "xcc_file.h" + #include "xcc_lmd_file.h" + #include "xif_file.h" ++#else ++#include "mix_file.h" ++#include "xcc_dirs.h" ++#endif ++ + + const char* ft_name[] = + { +diff --git a/misc/image_file.h b/misc/image_file.h +index e107843..b9e9fb5 100644 +--- a/misc/image_file.h ++++ b/misc/image_file.h +@@ -30,12 +30,14 @@ class Cimage_file : public Cvideo_file<T> + public: + virtual void decode(void*) const = 0; + ++#ifndef XCC_MINIMAL_BUILD + virtual Cvirtual_image vimage() const + { + Cvirtual_binary image; + decode(image.write_start(this->cb_image())); + return Cvirtual_image(image, this->cx(), this->cy(), this->cb_pixel(), this->palet()); + } ++#endif + + int cf() const override + { +@@ -43,6 +45,8 @@ public: + } + }; + ++#ifndef XCC_MINIMAL_BUILD + int image_file_write(Cvirtual_file&, t_file_type, const byte* image, const t_palet_entry*, int cx, int cy); + Cvirtual_file image_file_write(t_file_type, const byte* image, const t_palet_entry*, int cx, int cy); + int image_file_write(const string& name, t_file_type, const byte* image, const t_palet_entry*, int cx, int cy); ++#endif +diff --git a/misc/mix_file.cpp b/misc/mix_file.cpp +index 8354059..874ff31 100644 +--- a/misc/mix_file.cpp ++++ b/misc/mix_file.cpp +@@ -19,14 +19,20 @@ + #include <stdafx.h> + #include "mix_file.h" + ++#ifndef NO_FT_SUPPORT + #include "big_file.h" ++#endif + #include "blowfish.h" + #include "crc.h" + #include "id_log.h" ++#ifndef NO_FT_SUPPORT + #include "mix_cache.h" ++#endif + #include "mix_decode.h" ++#ifndef NO_FT_SUPPORT + #include "mix_rg_file.h" + #include "pak_file.h" ++#endif + #include "string_conversion.h" + #include "xcc_lmd_file.h" + +diff --git a/misc/shp_ts_file.cpp b/misc/shp_ts_file.cpp +index 4950213..db60a92 100644 +--- a/misc/shp_ts_file.cpp ++++ b/misc/shp_ts_file.cpp +@@ -22,7 +22,9 @@ + #include "image_file.h" + #include "shp_decode.h" + #include "string_conversion.h" ++#ifndef XCC_MINIMAL_BUILD + #include "xcc_log.h" ++#endif + + class Cshp_ts_decoder : public Cvideo_decoder + { +@@ -141,6 +143,7 @@ int get_ofs(int x, int y, int cx, int cy) + return x + cx * y; + } + ++#ifndef XCC_MINIMAL_BUILD + int Cshp_ts_file::extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet _palet, bool combine_shadows) const + { + t_palet palet; +@@ -378,6 +381,7 @@ void shp_split_shadows(Cvirtual_image& image) + image.load(d, cx, cy << 1, image.cb_pixel(), image.palet()); + delete[] d; + } ++#endif + + /* + void shp_xor_decode_frames(Cvirtual_image& image, int c_frames) +diff --git a/misc/shp_ts_file.h b/misc/shp_ts_file.h +index b38a053..76261cd 100644 +--- a/misc/shp_ts_file.h ++++ b/misc/shp_ts_file.h +@@ -28,8 +28,10 @@ class Cshp_ts_file : public Cvideo_file<t_shp_ts_header> + { + public: + Cvideo_decoder* decoder(const t_palet_entry*); ++#ifndef XCC_MINIMAL_BUILD + int extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet palet, bool combine_shadows = false) const; + Cvirtual_image extract_as_pcx_single(const t_palet _palet, bool combine_shadows = false) const; ++#endif + bool is_valid() const; + + int cb_pixel() const +@@ -106,7 +108,10 @@ public: + int shp_decode4_size(const byte* s); + Cvirtual_binary shp_decode4(const byte* s, int cb_d); + int shp_encode4(const Cshp_ts_file& f, byte* d); ++ ++#ifndef XCC_MINIMAL_BUILD + void shp_split_frames(Cvirtual_image& image, int cblocks_x, int cblocks_y); + void shp_split_shadows(Cvirtual_image& image); + void shp_xor_decode_frames(Cvirtual_image& image, int c_frames); + void shp_xor_encode_frames(Cvirtual_image& image, int c_frames); ++#endif +diff --git a/misc/virtual_image.cpp b/misc/virtual_image.cpp +index 5dfc3e2..456ea2d 100644 +--- a/misc/virtual_image.cpp ++++ b/misc/virtual_image.cpp +@@ -21,6 +21,8 @@ + #include <windows.h> + #include <gdiplus.h> + #include <shlwapi.h> ++ ++#ifndef XCC_MINIMAL_BUILD + #include "dds_file.h" + #include "image_file.h" + #include "jpeg_file.h" +@@ -28,6 +30,7 @@ + #include "pcx_file_write.h" + #include "png_file.h" + #include "tga_file.h" ++#endif + #include "virtual_image.h" + + using namespace Gdiplus; +@@ -80,6 +83,8 @@ void Cvirtual_image::load(const void* image, int cx, int cy, int cb_pixel, const + palet(p, inflate); + } + ++#ifndef XCC_MINIMAL_BUILD ++ + int Cvirtual_image::load(const Cvirtual_binary& s) + { + Cdds_file dds_f; +@@ -323,3 +328,5 @@ void Cvirtual_image::increase_palet_depth() + d[i].b = (s[i].b & 63) * 255 / 63; + } + } ++ ++#endif +diff --git a/misc/virtual_image.h b/misc/virtual_image.h +index 2396af8..0a2a2d6 100644 +--- a/misc/virtual_image.h ++++ b/misc/virtual_image.h +@@ -121,3 +121,4 @@ private: + int m_cy = 0; + int mcb_pixel = 0; + }; ++ +diff --git a/misc/vxl_file.cpp b/misc/vxl_file.cpp +index 3132cdf..a629aa1 100644 +--- a/misc/vxl_file.cpp ++++ b/misc/vxl_file.cpp +@@ -21,9 +21,11 @@ + + #include "file32.h" + #include "image_file.h" ++#ifndef XCC_MINIMAL_BUILD + #include "multi_line.h" + #include "pcx_decode.h" + #include "pcx_file_write.h" ++#endif + #include "string_conversion.h" + + bool Cvxl_file::is_valid() const +@@ -51,6 +53,7 @@ bool Cvxl_file::is_valid() const + return true; + } + ++#ifndef XCC_MINIMAL_BUILD + int Cvxl_file::extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet _palet) const + { + t_palet palet; +@@ -98,6 +101,7 @@ int Cvxl_file::extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet + } + return 0; + } ++#endif + + ostream& Cvxl_file::extract_as_text(ostream& os) const + { +@@ -162,6 +166,7 @@ enum + vi_z_max + }; + ++#ifndef XCC_MINIMAL_BUILD + int Cvxl_file::extract_as_xif(const string& name) const + { + Cxif_key k; +@@ -458,6 +463,8 @@ Cvirtual_binary vxl_file_write(Cvirtual_tfile s) + return vxl_file_write(colors.data(), normals.data(), cx, cy, cz); + } + ++#endif ++ + struct t_vxl4_header + { + unsigned __int32 c_sections; +diff --git a/misc/vxl_file.h b/misc/vxl_file.h +index 395f5ac..5dd1857 100644 +--- a/misc/vxl_file.h ++++ b/misc/vxl_file.h +@@ -22,14 +22,20 @@ + #include "cc_structures.h" + #include "fname.h" + #include "virtual_tfile.h" ++#ifndef XCC_MINIMAL_BUILD + #include "xif_key.h" ++#endif + + class Cvxl_file : public Ccc_file_sh<t_vxl_header> + { + public: ++#ifndef XCC_MINIMAL_BUILD + int extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet _palet) const; ++#endif + ostream& extract_as_text(ostream& os) const; ++#ifndef XCC_MINIMAL_BUILD + int extract_as_xif(const string& name) const; ++#endif + bool is_valid() const; + + int get_c_section_headers() const +@@ -93,6 +99,8 @@ public: + int vxl_decode4_size(const byte* s); + Cvirtual_binary vxl_decode4(const byte* s, int cb_d); + int vxl_encode4(const Cvxl_file& f, byte* d); ++#ifndef XCC_MINIMAL_BUILD + Cvirtual_binary vxl_file_write(const Cxif_key& s); + Cvirtual_binary vxl_file_write(const byte* s, const byte* s_normals, int cx, int cy, int cz); + Cvirtual_binary vxl_file_write(Cvirtual_tfile s); ++#endif +diff --git a/vcpkg.json b/vcpkg.json +index e0669e6..92d46dd 100644 +--- a/vcpkg.json ++++ b/vcpkg.json +@@ -5,9 +5,8 @@ + "boost-algorithm", + "boost-crc", + "bzip2", +- "libjpeg-turbo", +- "libpng", +- "libvorbis", +- "lzo" +- ] ++ "lzo", ++ "zlib" ++ ], ++ "builtin-baseline": "45c8b198b7647b6a68235353a00839082c910914" + } diff --git a/3rdParty/xcc/vcpkg.json b/3rdParty/xcc/vcpkg.json new file mode 100644 index 0000000..92d46dd --- /dev/null +++ b/3rdParty/xcc/vcpkg.json @@ -0,0 +1,12 @@ +{ + "name": "xcc", + "version-string": "0", + "dependencies": [ + "boost-algorithm", + "boost-crc", + "bzip2", + "lzo", + "zlib" + ], + "builtin-baseline": "45c8b198b7647b6a68235353a00839082c910914" +} diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/MissionEditor/AITriggerAddDlg.cpp b/MissionEditor/AITriggerAddDlg.cpp new file mode 100644 index 0000000..5f1b6e8 --- /dev/null +++ b/MissionEditor/AITriggerAddDlg.cpp @@ -0,0 +1,81 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// AITriggerAddDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "AITriggerAddDlg.h" +#include "Variables.h" +#include "inlines.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CAITriggerAddDlg + + +CAITriggerAddDlg::CAITriggerAddDlg(CWnd* pParent /*=NULL*/) + : CDialog(CAITriggerAddDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAITriggerAddDlg) + m_AITrigger = _T(""); + //}}AFX_DATA_INIT +} + + +void CAITriggerAddDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAITriggerAddDlg) + DDX_LBString(pDX, IDC_AITRIGGERS, m_AITrigger); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAITriggerAddDlg, CDialog) + //{{AFX_MSG_MAP(CAITriggerAddDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CAITriggerAddDlg + +BOOL CAITriggerAddDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CListBox* lb=(CListBox*)GetDlgItem(IDC_AITRIGGERS); + + int i; + for(i=0;i<ai.sections["AITriggerTypes"].values.size();i++) + { + lb->AddString(*ai.sections["AITriggerTypes"].GetValueName(i)+ (CString)" " +GetParam(*ai.sections["AITriggerTypes"].GetValue(i), 0)); + } + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} diff --git a/MissionEditor/AITriggerAddDlg.h b/MissionEditor/AITriggerAddDlg.h new file mode 100644 index 0000000..110e65f --- /dev/null +++ b/MissionEditor/AITriggerAddDlg.h @@ -0,0 +1,66 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_AITRIGGERADDDLG_H__19C60CA1_25D1_11D5_89B2_444553540000__INCLUDED_) +#define AFX_AITRIGGERADDDLG_H__19C60CA1_25D1_11D5_89B2_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AITriggerAddDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CAITriggerAddDlg + +class CAITriggerAddDlg : public CDialog +{ +// Konstruktion +public: + CAITriggerAddDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CAITriggerAddDlg) + enum { IDD = IDD_AITRIGGERADD }; + CString m_AITrigger; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CAITriggerAddDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CAITriggerAddDlg) + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_AITRIGGERADDDLG_H__19C60CA1_25D1_11D5_89B2_444553540000__INCLUDED_ diff --git a/MissionEditor/AITriggerTypes.cpp b/MissionEditor/AITriggerTypes.cpp new file mode 100644 index 0000000..27fc459 --- /dev/null +++ b/MissionEditor/AITriggerTypes.cpp @@ -0,0 +1,827 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// AITriggerTypes.cpp: implementation file +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "AITriggerTypes.h" +#include "Mapdata.h" +#include "structs.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + + +// AI trigger type enumeration +enum AITriggerEnum { + AIT_NONE = -1, + AIT_ENEMY_OWNS_X_COND_N = 0, + AIT_HOUSE_OWNS_X_COND_N, + AIT_POWER_YELLOW, + AIT_POWER_RED, + AIT_ENEMY_MONEY_COND_N, + AIT_CURTAIN_NEAR_READY, + AIT_SPHERE_NEAR_READY, + AIT_NEUTRAL_OWNS_X_COND_N, +}; + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// property page CAITriggerTypes + +IMPLEMENT_DYNCREATE(CAITriggerTypes, CDialog) + +CAITriggerTypes::CAITriggerTypes() : CDialog(CAITriggerTypes::IDD) +{ + //{{AFX_DATA_INIT(CAITriggerTypes) + m_Flag3 = _T(""); + m_Flag4 = _T(""); + m_Name = _T(""); + m_Flag6 = _T(""); + m_Flag7 = _T(""); + m_Flag8 = _T(""); + m_Flag9 = _T(""); + m_Enabled = FALSE; + m_Condition = -1; + m_Number = 0; + m_Easy = FALSE; + m_Medium = FALSE; + m_Hard = FALSE; + m_BaseDefense = FALSE; + m_Skirmish = FALSE; + m_Flag5 = _T(""); + m_MultiSide = _T(""); + //}}AFX_DATA_INIT +} + +CAITriggerTypes::~CAITriggerTypes() +{ +} + +void CAITriggerTypes::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAITriggerTypes) + DDX_Control(pDX, IDC_TEAMTYPE1, m_TeamType1); + DDX_Control(pDX, IDC_UNITTYPE, m_UnitType); + DDX_Control(pDX, IDC_TEAMTYPE2, m_TeamType2); + DDX_Control(pDX, IDC_FLAG2, m_Flag2); + DDX_Control(pDX, IDC_FLAG1, m_Flag1); + DDX_Control(pDX, IDC_DATA, m_Data); + DDX_Control(pDX, IDC_OWNER, m_Owner); + DDX_Control(pDX, IDC_FLOAT3, m_Float3); + DDX_Control(pDX, IDC_FLOAT2, m_Float2); + DDX_Control(pDX, IDC_FLOAT1, m_Float1); + DDX_Control(pDX, IDC_AITRIGGERTYPE, m_AITriggerType); + DDX_Text(pDX, IDC_FLAG4, m_Flag4); + DDX_Text(pDX, IDC_NAME, m_Name); + DDX_Check(pDX, IDC_ENABLED, m_Enabled); + DDX_CBIndex(pDX, IDC_CONDITION, m_Condition); + DDX_Text(pDX, IDC_NUMBER, m_Number); + DDV_MinMaxInt(pDX, m_Number, 0, 256); + DDX_Check(pDX, IDC_EASY, m_Easy); + DDX_Check(pDX, IDC_MEDIUM, m_Medium); + DDX_Check(pDX, IDC_HARD, m_Hard); + DDX_Check(pDX, IDC_BASEDEFENSE, m_BaseDefense); + DDX_Check(pDX, IDC_SKIRMISH, m_Skirmish); + DDX_CBString(pDX, IDC_MULTISIDE, m_MultiSide); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAITriggerTypes, CDialog) + //{{AFX_MSG_MAP(CAITriggerTypes) + ON_CBN_SELCHANGE(IDC_AITRIGGERTYPE, OnSelchangeAitriggertype) + ON_EN_CHANGE(IDC_NAME, OnChangeName) + ON_CBN_EDITCHANGE(IDC_OWNER, OnEditchangeOwner) + ON_CBN_EDITCHANGE(IDC_TEAMTYPE1, OnEditchangeTeamtype1) + ON_CBN_EDITCHANGE(IDC_TEAMTYPE2, OnEditchangeTeamtype2) + ON_CBN_EDITCHANGE(IDC_FLAG1, OnEditchangeFlag1) + ON_CBN_EDITCHANGE(IDC_FLAG2, OnEditchangeFlag2) + ON_CBN_EDITCHANGE(IDC_UNITTYPE, OnEditchangeUnittype) + ON_CBN_EDITCHANGE(IDC_DATA, OnEditchangeData) + ON_EN_CHANGE(IDC_FLOAT1, OnChangeFloat1) + ON_EN_CHANGE(IDC_FLOAT2, OnChangeFloat2) + ON_EN_CHANGE(IDC_FLOAT3, OnChangeFloat3) + ON_EN_CHANGE(IDC_FLAG4, OnChangeFlag4) + + ON_BN_CLICKED(IDC_ENABLED, OnEnabled) + ON_BN_CLICKED(IDC_ADD, OnAdd) + ON_BN_CLICKED(IDC_DELETE, OnDelete) + ON_CBN_EDITCHANGE(IDC_AITRIGGERTYPE, OnEditchangeAitriggertype) + ON_CBN_SELCHANGE(IDC_CONDITION, OnSelchangeCondition) + ON_EN_CHANGE(IDC_NUMBER, OnChangeNumber) + ON_BN_CLICKED(IDC_EASY, OnEasy) + ON_BN_CLICKED(IDC_MEDIUM, OnMedium) + ON_BN_CLICKED(IDC_HARD, OnHard) + ON_BN_CLICKED(IDC_BASEDEFENSE, OnBasedefense) + ON_BN_CLICKED(IDC_SKIRMISH, OnSkirmish) + ON_CBN_EDITCHANGE(IDC_MULTISIDE, OnEditchangeMultiside) + ON_CBN_SELCHANGE(IDC_MULTISIDE, OnSelchangeMultiside) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// message handlers CAITriggerTypes + +void ListObjects(CComboBox& cb) +{ + CComboBox& m_UnitType=cb; + CIniFile& ini=Map->GetIniFile(); + + int i; + + CString ss="InfantryTypes"; + for(i=0;i<rules.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*rules.sections[ss].GetValue(i); + s=type; + s+=" ("; + + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + for(i=0;i<ini.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*ini.sections[ss].GetValue(i); + s=type; + s+=" ("; + + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + + ss="VehicleTypes"; + for(i=0;i<rules.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*rules.sections[ss].GetValue(i); + s=type; + s+=" ("; + + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + for(i=0;i<ini.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*ini.sections[ss].GetValue(i); + s=type; + s+=" ("; + + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + + ss="AircraftTypes"; + for(i=0;i<rules.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*rules.sections[ss].GetValue(i); + s=type; + s+=" ("; + + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + for(i=0;i<ini.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*ini.sections[ss].GetValue(i); + s=type; + s+=" ("; + + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + + ss="BuildingTypes"; + for(i=0;i<rules.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*rules.sections[ss].GetValue(i); + s=type; + s+=" ("; + + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + for(i=0;i<ini.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*ini.sections[ss].GetValue(i); + s=type; + s+=" ("; + + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } +} + +void CAITriggerTypes::UpdateDialog() +{ + int sel=m_AITriggerType.GetCurSel(); + m_AITriggerType.SetRedraw(FALSE); + + while(m_AITriggerType.DeleteString(0)!=CB_ERR); + + ListHouses(m_Owner,FALSE,TRUE); + m_Owner.AddString("<all>"); + ListTeamTypes(m_TeamType1, TRUE); + ListTeamTypes(m_TeamType2, TRUE); + + int i; + for(i=0;i<Map->GetAITriggerTypeCount();i++) + { + AITRIGGERTYPE aitt; + Map->GetAITriggerType(i, &aitt); + CString s=aitt.ID; + s+=" ("; + s+=aitt.name; + s+=")"; + m_AITriggerType.AddString(s); + } + + m_AITriggerType.SetCurSel(0); + if(sel!=-1) + m_AITriggerType.SetCurSel(sel); + + + + + + + OnSelchangeAitriggertype(); + + m_AITriggerType.SetRedraw(TRUE); + m_AITriggerType.RedrawWindow(); +} + + +void CAITriggerTypes::OnSelchangeAitriggertype() +{ + int sel=m_AITriggerType.GetCurSel(); + if(sel<0) return; + + CString aitrigger; + m_AITriggerType.GetLBText(sel,aitrigger); + TruncSpace(aitrigger); + + + AITRIGGERTYPE aitt; + Map->GetAITriggerType(Map->GetAITriggerTypeIndex(aitrigger), &aitt); + + m_Name=aitt.name; + m_TeamType1.SetWindowText(aitt.teamtype1); + m_Owner.SetWindowText(TranslateHouse(aitt.owner, TRUE)); + m_Flag1.SetWindowText(aitt.techlevel); + //m_Flag2.SetWindowText(aitt.type); + int type=atoi(aitt.type)+1; + m_Flag2.SetCurSel(type); + m_UnitType.SetWindowText(aitt.unittype); + m_Data.SetWindowText(aitt.data); + m_Float1.SetWindowText(aitt.float1); + m_Float2.SetWindowText(aitt.float2); + m_Float3.SetWindowText(aitt.float3); + //m_Flag3=aitt.skirmish; + m_Skirmish=isTrue(aitt.skirmish); + m_Flag4=aitt.flag4; + //m_Flag5=aitt.multihouse; + m_MultiSide=aitt.multihouse; + m_BaseDefense=isTrue(aitt.basedefense); + m_TeamType2.SetWindowText(aitt.teamtype2); + m_Easy=isTrue(aitt.easy); + m_Medium=isTrue(aitt.medium); + m_Hard=isTrue(aitt.hard); + + m_Enabled=FALSE; + CIniFile& ini=Map->GetIniFile(); + if(ini.sections["AITriggerTypesEnable"].values.find((LPCTSTR)aitrigger)!=ini.sections["AITriggerTypesEnable"].values.end()) + if(stricmp(ini.sections["AITriggerTypesEnable"].values[(LPCTSTR)aitrigger], "yes")==NULL) + m_Enabled=TRUE; + + AITrigInfo info; + info=ConvertToAITrigInfoFromHex((char*)(LPCSTR)aitt.data); + m_Condition=info.Condition; + m_Number=info.Number; + + ListObjects(m_UnitType); + + UpdateData(FALSE); +} + +void CAITriggerTypes::OnChangeName() +{ + UpdateData(); + + CString value; + value=m_Name; + + if(value.GetLength()==0) value=" "; + + SetAITriggerParam(value, 0); + + UpdateDialog(); +} + +void CAITriggerTypes::OnEditchangeOwner() +{ + CString value; + m_Owner.GetWindowText(value); + + value=TranslateHouse(value); + + SetAITriggerParam(value, 2); +} + +void CAITriggerTypes::OnEditchangeTeamtype1() +{ + CString value; + m_TeamType1.GetWindowText(value); + TruncSpace(value); + + SetAITriggerParam(value, 1); +} + +void CAITriggerTypes::OnEditchangeTeamtype2() +{ + CString value; + m_TeamType2.GetWindowText(value); + TruncSpace(value); + + SetAITriggerParam(value, 14); +} + +void CAITriggerTypes::OnEditchangeFlag1() +{ + CString value; + m_Flag1.GetWindowText(value); + + SetAITriggerParam(value, 3); +} + +void CAITriggerTypes::OnEditchangeFlag2() +{ + CString value; + m_Flag2.GetWindowText(value); + + TruncSpace(value); + + SetAITriggerParam(value, 4); +} + +void CAITriggerTypes::OnEditchangeUnittype() +{ + CString value; + m_UnitType.GetWindowText(value); + TruncSpace(value); + + SetAITriggerParam(value, 5); +} + +void CAITriggerTypes::OnEditchangeData() +{ + /* + This function should also valid the data! + */ + + CString value; + m_Data.GetWindowText(value); + TruncSpace(value); + + // max 64 chars... min 64 chars too... + ((char*)(LPCTSTR)value)[64]=0; + + int ToInsert=64-value.GetLength(); + CString nulls('0',ToInsert); + + value.Insert(value.GetLength()-ToInsert, nulls); + + + SetAITriggerParam(value, 6); + + + int editsel=m_Data.GetEditSel(); + UpdateDialog(); + m_Data.SetEditSel(editsel,editsel+1); +} + +void CAITriggerTypes::OnChangeFloat1() +{ + CString value; + m_Float1.GetWindowText(value); + + SetAITriggerParam(value, 7); +} + +void CAITriggerTypes::OnChangeFloat2() +{ + CString value; + m_Float2.GetWindowText(value); + + SetAITriggerParam(value, 8); +} + +void CAITriggerTypes::OnChangeFloat3() +{ + CString value; + m_Float3.GetWindowText(value); + + SetAITriggerParam(value, 9); +} + +void CAITriggerTypes::OnChangeFlag3() +{ + + +} + +void CAITriggerTypes::OnChangeFlag4() +{ + UpdateData(); + + CString value; + value=m_Flag4; + + SetAITriggerParam(value, 11); + +} + +void CAITriggerTypes::OnChangeFlag5() +{ + + +} + +void CAITriggerTypes::OnChangeFlag6() +{ + +} + +void CAITriggerTypes::OnChangeFlag7() +{ + +} + +void CAITriggerTypes::OnChangeFlag8() +{ + UpdateData(); + + CString value; + value=m_Flag8; + + SetAITriggerParam(value, 16); +} + +void CAITriggerTypes::OnChangeFlag9() +{ + UpdateData(); + + CString value; + value=m_Flag9; + + SetAITriggerParam(value, 17); +} + +void CAITriggerTypes::OnEnabled() +{ + // enable or disable trigger + + UpdateData(); + + int sel=m_AITriggerType.GetCurSel(); + if(sel<0) return; + + CString aitrigger; + m_AITriggerType.GetLBText(sel,aitrigger); + TruncSpace(aitrigger); + + CIniFile& ini=Map->GetIniFile(); + + if(m_Enabled) + { + // enable it + ini.sections["AITriggerTypesEnable"].values[(LPCTSTR)aitrigger]="yes"; + } + else + ini.sections["AITriggerTypesEnable"].values.erase((LPCTSTR)aitrigger); +} + +void CAITriggerTypes::SetAITriggerParam(const char *value, int param) +{ + int sel=m_AITriggerType.GetCurSel(); + if(sel<0) return; + + CString aitrigger; + m_AITriggerType.GetLBText(sel,aitrigger); + TruncSpace(aitrigger); + + CIniFile& ini=Map->GetIniFile(); + ini.sections["AITriggerTypes"].values[aitrigger]=SetParam(ini.sections["AITriggerTypes"].values[aitrigger],param,value); +} + +void CAITriggerTypes::OnAdd() +{ + CString ID=GetFreeID(); + CIniFile& ini=Map->GetIniFile(); + CString data="New AI Trigger,"; + + // now try to set a teamtype + if(ini.sections["TeamTypes"].values.size()>0) + { + data+=*ini.sections["TeamTypes"].GetValue(0); + } + else + { + data+="<none>"; + } + + data+=",<all>,"; + + // the flag here... i first thought it´s an ID, but it more seems to be an value specifying the importance of the trigger + data+="1,"; + + // the flag 2 seems to be the type of the trigger. -1 seems to be pool + data+="0,"; + + // now stuff + data+="<none>,0000000000000000000000000000000000000000000000000000000000000000,50.000000,30.000000,50.000000,1,0,1,1,"; + + // a pool seems to need both teamtypes the same + if(ini.sections["TeamTypes"].values.size()>0) + { + data+="<none>";//*ini.sections["TeamTypes"].GetValue(0); + } + else + { + data+="<none>"; + } + + data+=",1,1,1"; + + ini.sections["AITriggerTypes"].values[ID]=data; + + UpdateDialog(); + + // now make current id visible + int i; + for(i=0;i<m_AITriggerType.GetCount();i++) + { + CString cuString; + m_AITriggerType.GetLBText(i, cuString); + TruncSpace(cuString); + + if(cuString==ID) + { + m_AITriggerType.SetCurSel(i); + OnSelchangeAitriggertype(); + } + } +} + +void CAITriggerTypes::OnDelete() +{ + int sel=m_AITriggerType.GetCurSel(); + if(sel<0) return; + + CString aitrigger; + m_AITriggerType.GetLBText(sel,aitrigger); + TruncSpace(aitrigger); + + CIniFile& ini=Map->GetIniFile(); + + ini.sections["AITriggerTypes"].values.erase(aitrigger); + ini.sections["AITriggerTypesEnable"].values.erase(aitrigger); + + UpdateDialog(); +} + +void CAITriggerTypes::OnEditchangeAitriggertype() +{ + OnSelchangeAitriggertype(); +} + +AITrigInfo CAITriggerTypes::ConvertToAITrigInfoFromHex(char *aitinfo) +{ + int index=0; + AITrigInfo info; + char* rawdata=(char*)&info; + char hexbuff[3]="00"; + char* dummy=NULL; + + while(*aitinfo!='\0') + { + while(isspace((int)*aitinfo)) aitinfo++; + + hexbuff[0]=*aitinfo++; + ASSERT(*aitinfo!='\0'); + if(*aitinfo!='\0'){ + hexbuff[1]=*aitinfo++; + } else { + hexbuff[1]='\0'; + } + + ASSERT(index<sizeof(AITrigInfo)); + if(index>=sizeof(AITrigInfo)) break; + + *rawdata++=strtol(hexbuff, &dummy, 16); + index++; + } + + return info; +} + +char* CAITriggerTypes::ConvertToHexFromAITrigInfo(AITrigInfo info, char* buffer) +{ + unsigned char* aitinfobuffer=(unsigned char*)buffer; + /* + ** Convert the AITrigInfo union data structure to ASCII format string + */ + { + + int index = 0; + unsigned char *rawdata = (unsigned char *)&info; + unsigned char *aitinfobuffptr = &aitinfobuffer[0]; + + for (; index < sizeof(AITrigInfo); index++, rawdata++, aitinfobuffptr += 2) { + sprintf((char *)aitinfobuffptr, "%02x", *rawdata); + } + + *aitinfobuffptr = '\0'; + } + + return (char*)aitinfobuffer; +} + +void CAITriggerTypes::OnSelchangeCondition() +{ + int sel=m_AITriggerType.GetCurSel(); + if(sel<0) return; + + UpdateData(TRUE); + + AITrigInfo info; + info.Condition=(ConditionEnum)m_Condition; + info.Number=m_Number; + + char buffer[65]; + ConvertToHexFromAITrigInfo(info, buffer); + + + SetAITriggerParam(buffer, 6); + + UpdateDialog(); +} + +void CAITriggerTypes::OnChangeNumber() +{ + int sel=m_AITriggerType.GetCurSel(); + if(sel<0) return; + + UpdateData(TRUE); + + AITrigInfo info; + memset(&info, 0, sizeof(AITrigInfo)); + info.Condition=(ConditionEnum)m_Condition; + info.Number=m_Number; + + char buffer[65]; + ConvertToHexFromAITrigInfo(info, buffer); + + //MessageBox(buffer); + + //m_Data.SetWindowText(buffer); + + SetAITriggerParam(buffer, 6); + + UpdateDialog(); + +} + +void CAITriggerTypes::OnEasy() +{ + UpdateData(); + + CString value; + value="1"; + if(!m_Easy) value="0"; + + SetAITriggerParam(value, 15); +} + +void CAITriggerTypes::OnMedium() +{ + UpdateData(); + + CString value; + value="1"; + if(!m_Medium) value="0"; + + SetAITriggerParam(value, 16); +} + +void CAITriggerTypes::OnHard() +{ + UpdateData(); + + CString value; + value="1"; + if(!m_Hard) value="0"; + + SetAITriggerParam(value, 17); +} + +void CAITriggerTypes::OnBasedefense() +{ + UpdateData(); + + CString value; + value="1"; + if(!m_BaseDefense) value="0"; + + SetAITriggerParam(value, 13); +} + +void CAITriggerTypes::OnSkirmish() +{ + UpdateData(); + + CString value; + value="1"; + if(!m_Skirmish) value="0"; + + SetAITriggerParam(value, 10); +} + +void CAITriggerTypes::OnEditchangeMultiside() +{ + UpdateData(); + + CString value; + value=m_MultiSide; + + TruncSpace(value); + + SetAITriggerParam(value, 12); +} + +void CAITriggerTypes::OnSelchangeMultiside() +{ + CString s; + CComboBox& box=*(CComboBox*)GetDlgItem(IDC_MULTISIDE); + box.GetLBText(box.GetCurSel(), s); + box.SetWindowText(s); + + OnEditchangeMultiside(); +} diff --git a/MissionEditor/AITriggerTypes.h b/MissionEditor/AITriggerTypes.h new file mode 100644 index 0000000..027a4ef --- /dev/null +++ b/MissionEditor/AITriggerTypes.h @@ -0,0 +1,132 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_AITRIGGERTYPES_H__47F0A0E0_A8DC_11D3_B63B_B4F5BEE55940__INCLUDED_) +#define AFX_AITRIGGERTYPES_H__47F0A0E0_A8DC_11D3_B63B_B4F5BEE55940__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AITriggerTypes.h : Header file +// + +#include "structs.h" + +///////////////////////////////////////////////////////////////////////////// +// dialog field CAITriggerTypes + +class CAITriggerTypes : public CDialog +{ + DECLARE_DYNCREATE(CAITriggerTypes) + +// construction +public: + char* ConvertToHexFromAITrigInfo(AITrigInfo info, char* buffer); + void SetAITriggerParam(const char* value, int param); + void UpdateDialog(); + CAITriggerTypes(); + ~CAITriggerTypes(); + +// dialog field data + //{{AFX_DATA(CAITriggerTypes) + enum { IDD = IDD_AITRIGGERTYPES }; + CMyComboBox m_TeamType1; + CMyComboBox m_UnitType; + CMyComboBox m_TeamType2; + CMyComboBox m_Flag2; + CMyComboBox m_Flag1; + CMyComboBox m_Data; + CMyComboBox m_Owner; + CFloatEdit m_Float3; + CFloatEdit m_Float2; + CFloatEdit m_Float1; + CMyComboBox m_AITriggerType; + CString m_Flag3; + CString m_Flag4; + CString m_Name; + CString m_Flag6; + CString m_Flag7; + CString m_Flag8; + CString m_Flag9; + BOOL m_Enabled; + int m_Condition; + int m_Number; + BOOL m_Easy; + BOOL m_Medium; + BOOL m_Hard; + BOOL m_BaseDefense; + BOOL m_Skirmish; + CString m_Flag5; + CString m_MultiSide; + //}}AFX_DATA + + +// overwriteables + // generated virtual overwriteables + //{{AFX_VIRTUAL(CAITriggerTypes) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// implementation +protected: + AITrigInfo ConvertToAITrigInfoFromHex(char* aitinfo); + // generated message maps + //{{AFX_MSG(CAITriggerTypes) + afx_msg void OnSelchangeAitriggertype(); + afx_msg void OnChangeName(); + afx_msg void OnEditchangeOwner(); + afx_msg void OnEditchangeTeamtype1(); + afx_msg void OnEditchangeTeamtype2(); + afx_msg void OnEditchangeFlag1(); + afx_msg void OnEditchangeFlag2(); + afx_msg void OnEditchangeUnittype(); + afx_msg void OnEditchangeData(); + afx_msg void OnChangeFloat1(); + afx_msg void OnChangeFloat2(); + afx_msg void OnChangeFloat3(); + afx_msg void OnChangeFlag3(); + afx_msg void OnChangeFlag4(); + afx_msg void OnChangeFlag5(); + afx_msg void OnChangeFlag6(); + afx_msg void OnChangeFlag7(); + afx_msg void OnChangeFlag8(); + afx_msg void OnChangeFlag9(); + afx_msg void OnEnabled(); + afx_msg void OnAdd(); + afx_msg void OnDelete(); + afx_msg void OnEditchangeAitriggertype(); + afx_msg void OnSelchangeCondition(); + afx_msg void OnChangeNumber(); + afx_msg void OnEasy(); + afx_msg void OnMedium(); + afx_msg void OnHard(); + afx_msg void OnBasedefense(); + afx_msg void OnSkirmish(); + afx_msg void OnEditchangeMultiside(); + afx_msg void OnSelchangeMultiside(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} + +#endif // AFX_AITRIGGERTYPES_H__47F0A0E0_A8DC_11D3_B63B_B4F5BEE55940__INCLUDED_ diff --git a/MissionEditor/AiTriggerTypesEnable.cpp b/MissionEditor/AiTriggerTypesEnable.cpp new file mode 100644 index 0000000..f534b8b --- /dev/null +++ b/MissionEditor/AiTriggerTypesEnable.cpp @@ -0,0 +1,170 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// AiTriggerTypesEnable.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "AiTriggerTypesEnable.h" +#include "mapdata.h" +#include "variables.h" +#include "inlines.h" +#include "aitriggeradddlg.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CAiTriggerTypesEnable + +IMPLEMENT_DYNCREATE(CAiTriggerTypesEnable, CDialog) + +CAiTriggerTypesEnable::CAiTriggerTypesEnable() : CDialog(CAiTriggerTypesEnable::IDD) +{ + //{{AFX_DATA_INIT(CAiTriggerTypesEnable) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + +CAiTriggerTypesEnable::~CAiTriggerTypesEnable() +{ +} + +void CAiTriggerTypesEnable::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAiTriggerTypesEnable) + DDX_Control(pDX, IDC_AITRIGGERTYPE, m_AITriggerType); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAiTriggerTypesEnable, CDialog) + //{{AFX_MSG_MAP(CAiTriggerTypesEnable) + ON_BN_CLICKED(IDC_ENABLEALL, OnEnableall) + ON_CBN_SELCHANGE(IDC_AITRIGGERTYPE, OnSelchangeAitriggertype) + ON_BN_CLICKED(IDC_DELETE, OnDelete) + ON_BN_CLICKED(IDC_ADD, OnAdd) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CAiTriggerTypesEnable + +void CAiTriggerTypesEnable::UpdateDialog() +{ + int sel=m_AITriggerType.GetCurSel(); + if(sel<0) sel=0; + + while(m_AITriggerType.DeleteString(0)!=CB_ERR); + + CIniFile& ini=Map->GetIniFile(); + + int i; + for(i=0;i<ini.sections["AITriggerTypesEnable"].values.size();i++) + { + CString aitrigger=*ini.sections["AITriggerTypesEnable"].GetValueName(i); + CString str=aitrigger; + str+=" ("; + + if(ai.sections["AITriggerTypes"].values.find(aitrigger)!=ai.sections["AITriggerTypes"].values.end()) + { + // standard ai trigger + str+=GetParam(ai.sections["AITriggerTypes"].values[aitrigger],0); + str+=" -> "; + str+=*ini.sections["AITriggerTypesEnable"].GetValue(i); + + + } + if(ini.sections["AITriggerTypes"].values.find(aitrigger)!=ini.sections["AITriggerTypes"].values.end()) + { + str+=GetParam(ini.sections["AITriggerTypes"].values[aitrigger],0); + str+=" -> "; + str+=*ini.sections["AITriggerTypesEnable"].GetValue(i); + } + + str+=")"; + + m_AITriggerType.AddString(str); + } + + if(m_AITriggerType.SetCurSel(sel)==CB_ERR) + m_AITriggerType.SetCurSel(0); + + OnSelchangeAitriggertype(); + +} + +void CAiTriggerTypesEnable::OnEnableall() +{ + // enable all standard ai triggers + CIniFile& ini=Map->GetIniFile(); + int i; + for(i=0;i<ai.sections["AITriggerTypes"].values.size();i++) + { + ini.sections["AITriggerTypesEnable"].values[*ai.sections["AITriggerTypes"].GetValueName(i)]="yes"; + } + + UpdateDialog(); +} + +void CAiTriggerTypesEnable::OnSelchangeAitriggertype() +{ + int sel=m_AITriggerType.GetCurSel(); + if(sel<0) return; + +} + +void CAiTriggerTypesEnable::OnDelete() +{ + int sel=m_AITriggerType.GetCurSel(); + if(sel<0) return; + CString aitrigger; + m_AITriggerType.GetLBText(sel,aitrigger); + if(aitrigger.Find(" ")>=0) aitrigger.SetAt(aitrigger.Find(" "), 0); + + CIniFile& ini=Map->GetIniFile(); + + ini.sections["AITriggerTypesEnable"].values.erase((LPCTSTR)aitrigger); + UpdateDialog(); +} + +void CAiTriggerTypesEnable::OnAdd() +{ + + + //CString p=InputBox("Please enter the ID of the AITriggerType (for a list of all AITriggerType-IDs use the All-Section)","Enable AITriggerType"); + CAITriggerAddDlg dlg; + if(dlg.DoModal()==IDCANCEL) return; + + CString p=dlg.m_AITrigger; + TruncSpace(p); + if(p.GetLength()==0) return; + + CIniFile& ini=Map->GetIniFile(); + + ini.sections["AITriggerTypesEnable"].values[p]="yes"; + UpdateDialog(); +} diff --git a/MissionEditor/AiTriggerTypesEnable.h b/MissionEditor/AiTriggerTypesEnable.h new file mode 100644 index 0000000..0cfcfb7 --- /dev/null +++ b/MissionEditor/AiTriggerTypesEnable.h @@ -0,0 +1,73 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_AITRIGGERTYPESENABLE_H__5CA6D080_A4D2_11D3_B63B_808EC7AC6440__INCLUDED_) +#define AFX_AITRIGGERTYPESENABLE_H__5CA6D080_A4D2_11D3_B63B_808EC7AC6440__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AiTriggerTypesEnable.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CAiTriggerTypesEnable + +class CAiTriggerTypesEnable : public CDialog +{ + DECLARE_DYNCREATE(CAiTriggerTypesEnable) + +// Konstruktion +public: + void UpdateDialog(); + CAiTriggerTypesEnable(); + ~CAiTriggerTypesEnable(); + +// Dialogfelddaten + //{{AFX_DATA(CAiTriggerTypesEnable) + enum { IDD = IDD_AITRIGGERTYPESENABLE }; + CComboBox m_AITriggerType; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CAiTriggerTypesEnable) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CAiTriggerTypesEnable) + afx_msg void OnEnableall(); + afx_msg void OnSelchangeAitriggertype(); + afx_msg void OnDelete(); + afx_msg void OnAdd(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_AITRIGGERTYPESENABLE_H__5CA6D080_A4D2_11D3_B63B_808EC7AC6440__INCLUDED_ diff --git a/MissionEditor/Aircraft.cpp b/MissionEditor/Aircraft.cpp new file mode 100644 index 0000000..7da02a8 --- /dev/null +++ b/MissionEditor/Aircraft.cpp @@ -0,0 +1,166 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Aircraft.cpp: implementation file +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Aircraft.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// dialog field CAircraft + + +CAircraft::CAircraft(CWnd* pParent /*=NULL*/) + : CDialog(CAircraft::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAircraft) + m_direction = _T(""); + m_house = _T(""); + m_flag1 = _T(""); + m_flag2 = _T(""); + m_flag3 = _T(""); + m_flag4 = _T(""); + m_action = _T(""); + m_tag = _T(""); + //}}AFX_DATA_INIT +} + + +void CAircraft::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAircraft) + DDX_Control(pDX, IDC_STRENGTH, m_strength_ctrl); + DDX_CBString(pDX, IDC_DIRECTION, m_direction); + DDX_CBString(pDX, IDC_HOUSE, m_house); + DDX_Text(pDX, IDC_P1, m_flag1); + DDX_Text(pDX, IDC_P2, m_flag2); + DDX_Text(pDX, IDC_P3, m_flag3); + DDX_Text(pDX, IDC_P4, m_flag4); + DDX_CBString(pDX, IDC_STATE, m_action); + DDX_CBString(pDX, IDC_TAG, m_tag); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAircraft, CDialog) + //{{AFX_MSG_MAP(CAircraft) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// handlers for messages CAircraft + +void CAircraft::Init(CString house, CString strength, CString direction, CString action, CString tag, CString flag1, CString flag2, CString flag3, CString flag4) +{ + if(house.GetLength()==0) + { + m_house=TranslateHouse(Map->GetHouseID(0), TRUE); + } + else + m_house=TranslateHouse(house, TRUE); + + + + m_flag1=flag1; + m_flag2=flag2; + m_flag3=flag3; + m_flag4=flag4; + + m_action=action; + m_strength=strength; + + m_tag=tag; + m_direction=direction; + +} + +BOOL CAircraft::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // init the common (!) dialog things + int i; + CComboBox* house, *tag; + + house=(CComboBox*)GetDlgItem(IDC_HOUSE); + + tag=(CComboBox*)GetDlgItem(IDC_TAG); + + ListHouses(*house, FALSE); + ListTags(*tag, TRUE); + + ListYesNo(*(CComboBox*)GetDlgItem(IDC_P3)); + + UpdateData(FALSE); + m_strength_ctrl.SetRange(0,256); + m_strength_ctrl.SetPos(atoi(m_strength)); + + UpdateStrings(); + + return TRUE; +} + +void CAircraft::OnOK() +{ + CDialog::OnOK(); + m_strength=GetText(&m_strength_ctrl); + + + + UpdateData(); + m_house=TranslateHouse(m_house, FALSE); + TruncSpace(m_tag); + TruncSpace(m_flag1); + TruncSpace(m_flag2); + TruncSpace(m_flag3); + TruncSpace(m_flag4); + +} + +void CAircraft::UpdateStrings() +{ + SetWindowText(GetLanguageStringACP("AirCap")); + GetDlgItem(IDC_LHOUSE)->SetWindowText(GetLanguageStringACP("AirHouse")); + GetDlgItem(IDC_LDESC)->SetWindowText(GetLanguageStringACP("AirDesc")); + GetDlgItem(IDC_LSTRENGTH)->SetWindowText(GetLanguageStringACP("AirStrength")); + GetDlgItem(IDC_LSTATE)->SetWindowText(GetLanguageStringACP("AirState")); + GetDlgItem(IDC_LDIRECTION)->SetWindowText(GetLanguageStringACP("AirDirection")); + GetDlgItem(IDC_LTAG)->SetWindowText(GetLanguageStringACP("AirTag")); + GetDlgItem(IDC_LP1)->SetWindowText(GetLanguageStringACP("AirP1")); + GetDlgItem(IDC_LP2)->SetWindowText(GetLanguageStringACP("AirP2")); + GetDlgItem(IDC_LP3)->SetWindowText(GetLanguageStringACP("AirP3")); + GetDlgItem(IDC_LP4)->SetWindowText(GetLanguageStringACP("AirP4")); + + SetDlgItemText(IDOK, GetLanguageStringACP("OK")); + SetDlgItemText(IDCANCEL, GetLanguageStringACP("Cancel")); +} diff --git a/MissionEditor/Aircraft.h b/MissionEditor/Aircraft.h new file mode 100644 index 0000000..48a9160 --- /dev/null +++ b/MissionEditor/Aircraft.h @@ -0,0 +1,75 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_AIRCRAFT_H__15BD6160_8953_11D3_B63B_A583BFBD8C41__INCLUDED_) +#define AFX_AIRCRAFT_H__15BD6160_8953_11D3_B63B_A583BFBD8C41__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Aircraft.h : Header-Datei +// + + +class CAircraft : public CDialog +{ +// construction +public: + void UpdateStrings(); + CString m_strength; + void Init(CString house="", CString strength="256", CString direction="64", CString action="Guard", CString tag="None", CString flag1="0", CString flag2="0", CString flag3="0", CString flag4="0"); + CAircraft(CWnd* pParent = NULL); // standard constructor + +// dialog field data + //{{AFX_DATA(CAircraft) + enum { IDD = IDD_AIRCRAFT }; + CSliderCtrl m_strength_ctrl; + CString m_direction; + CString m_house; + CString m_flag1; + CString m_flag2; + CString m_flag3; + CString m_flag4; + CString m_action; + CString m_tag; + //}}AFX_DATA + + +// overwriteables + // generated from class assistant + //{{AFX_VIRTUAL(CAircraft) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// implementation +protected: + + // generated message maps + //{{AFX_MSG(CAircraft) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} + +#endif // AFX_AIRCRAFT_H__15BD6160_8953_11D3_B63B_A583BFBD8C41__INCLUDED_ diff --git a/MissionEditor/All.cpp b/MissionEditor/All.cpp new file mode 100644 index 0000000..a95ce2c --- /dev/null +++ b/MissionEditor/All.cpp @@ -0,0 +1,285 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// All1.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "All.h" +#include "mapdata.h" +#include "variables.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +extern CFinalSunApp theApp; +#include "ImportIni.h" + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CAll + + +CAll::CAll(CWnd* pParent /*=NULL*/) + : CDialog(CAll::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAll) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + + +void CAll::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAll) + DDX_Control(pDX, IDC_VALUE, m_Value); + DDX_Control(pDX, IDC_KEYS, m_Keys); + DDX_Control(pDX, IDC_INISECTION, m_IniSection); + DDX_Control(pDX, IDC_DELETESECTION, m_DeleteSection); + DDX_Control(pDX, IDC_DELETEKEY, m_DeleteKey); + DDX_Control(pDX, IDC_ADDSECTION, m_AddSection); + DDX_Control(pDX, IDC_ADDKEY, m_AddKey); + DDX_Control(pDX, IDC_SECTIONS, m_Sections); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAll, CDialog) + //{{AFX_MSG_MAP(CAll) + ON_CBN_SELCHANGE(IDC_SECTIONS, OnSelchangeSections) + ON_EN_CHANGE(IDC_VALUE, OnChangeValue) + ON_LBN_SELCHANGE(IDC_KEYS, OnSelchangeKeys) + ON_EN_UPDATE(IDC_VALUE, OnUpdateValue) + ON_BN_CLICKED(IDC_ADDSECTION, OnAddsection) + ON_BN_CLICKED(IDC_DELETESECTION, OnDeletesection) + ON_BN_CLICKED(IDC_DELETEKEY, OnDeletekey) + ON_BN_CLICKED(IDC_ADDKEY, OnAddkey) + ON_BN_CLICKED(IDC_INISECTION, OnInisection) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CAll + +void CAll::UpdateDialog() +{ + //m_Sections.Clear(); + + while(m_Sections.DeleteString(0)!=-1); + while(m_Keys.DeleteString(0)!=-1); + CIniFile& ini=Map->GetIniFile(); + + + m_Value.SetWindowText(""); + + int i; + for(i=ini.sections.size()-1;i>=0;i--) + { + const CString* name=ini.GetSectionName(i); + if(!Map->IsMapSection(*name)) + m_Sections.InsertString(0, *name); + } + + m_Sections.SetCurSel(1); + OnSelchangeSections(); +} + +void CAll::OnSelchangeSections() +{ + while(m_Keys.DeleteString(0)!=CB_ERR); + CIniFile& ini=Map->GetIniFile(); + + CString cuSection; + m_Sections.GetWindowText(cuSection); + + if(cuSection.GetLength()) + { + int i; + m_Keys.SetRedraw(FALSE); + SetCursor(LoadCursor(0,IDC_WAIT)); + for(i=0;i<ini.sections[cuSection].values.size();i++) + { + const CString* name=ini.sections[cuSection].GetValueName(i); + m_Keys.InsertString(-1, *name); + + } + SetCursor(m_hArrowCursor); + m_Keys.SetRedraw(TRUE); + m_Keys.RedrawWindow(); + } +} + + +void CAll::OnChangeValue() +{ + CIniFile& ini=Map->GetIniFile(); + + CString t; + m_Value.GetWindowText(t); + + CString cuSection; + m_Sections.GetWindowText(cuSection); + + + CString cuKey; + if(m_Keys.GetCurSel()>=0)m_Keys.GetText(m_Keys.GetCurSel(), cuKey) ; + + + + ini.sections[cuSection].values[cuKey]=t; + +} + +void CAll::OnSelchangeKeys() +{ + CIniFile& ini=Map->GetIniFile(); + + CString cuSection; + m_Sections.GetWindowText(cuSection); + + CString cuKey; + m_Keys.GetText(m_Keys.GetCurSel(), cuKey) ; + + m_Value.SetWindowText(ini.sections[cuSection].values[cuKey]); +} + +void CAll::OnUpdateValue() +{ + +} + +void CAll::OnAddsection() +{ + CString name=InputBox("Please set the name of the new section (the section may already exist)", "Insert Section"); + + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection stub=ini.sections[(LPCTSTR)name]; + + UpdateDialog(); +} + +void CAll::OnDeletesection() +{ + CIniFile& ini=Map->GetIniFile(); + + int cusection; + cusection=m_Sections.GetCurSel(); + if(cusection==-1) { + MessageBox("You cannot delete a section without choosing one."); + return; + } + + CString str; + m_Sections.GetLBText(cusection, str); + + if(MessageBox(CString((CString)"Are you sure you want to delete " + str + "? You should be really careful, you may not be able to use the map afterwards."), "Delete section", MB_YESNO)==IDNO) return; + + ini.sections.erase(str); + + UpdateDialog(); +} + +void CAll::OnDeletekey() +{ + CIniFile& ini=Map->GetIniFile(); + + int cukey; + if(m_Sections.GetCurSel()<0) return; + cukey=m_Keys.GetCurSel(); + if(cukey==-1) { + MessageBox("You cannot delete a key without choosing one."); + return; + } + + CString str; + CString sec; + int cuSection=m_Sections.GetCurSel(); + m_Sections.GetLBText(cuSection, sec); + m_Keys.GetText(cukey, str); + + if(MessageBox(CString((CString)"Are you sure you want to delete " + str + "? You should be really careful, you may not be able to use the map afterwards."), "Delete key", MB_YESNO)==IDNO) return; + + ini.sections[sec].values.erase(str); + + UpdateDialog(); + + m_Sections.SetCurSel(cuSection); + OnSelchangeSections(); +} + +void CAll::OnAddkey() +{ + CIniFile& ini=Map->GetIniFile(); + int cusection; + cusection=m_Sections.GetCurSel(); + if(cusection==-1) { + MessageBox("You need to specify a section first."); + return; + } + + CString sec; + m_Sections.GetLBText(cusection, sec); + + CString key, value; + key=InputBox("Please set the name and value for the current key here: (for example, setting a new key ""Strength"" with the value 200 can be written as ""Strength=200"". You don´t need to specify a value.)", "Create key"); + + if(key.Find("=")!=-1) + { + // value specified + // MW BUGFIX + value=key.Right(key.GetLength()-key.Find("=")-1); + key=key.Left(key.Find("=")); + } + + ini.sections[sec].values[key]=value; + + UpdateDialog(); + m_Sections.SetCurSel(cusection); + OnSelchangeSections(); +} + +void CAll::OnInisection() +{ + CFileDialog dlg(FALSE, ".ini", "*.ini", OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, "INI files|*.ini|"); + + char cuPath[MAX_PATH]; + BOOL hidePreview=FALSE; + BOOL previewPrinted=FALSE; + GetCurrentDirectory(MAX_PATH, cuPath); + dlg.m_ofn.lpstrInitialDir=cuPath; + + if(theApp.m_Options.TSExe.GetLength()) dlg.m_ofn.lpstrInitialDir=(char*)(LPCTSTR)theApp.m_Options.TSExe; + + if(dlg.DoModal()!=IDCANCEL) + { + CImportINI impini; + impini.m_FileName=dlg.GetPathName(); + if(impini.DoModal()!=IDCANCEL) + { + UpdateDialog(); + } + } +} diff --git a/MissionEditor/All.h b/MissionEditor/All.h new file mode 100644 index 0000000..e5b43e9 --- /dev/null +++ b/MissionEditor/All.h @@ -0,0 +1,82 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_ALL1_H__B5D522E4_69CE_11D3_99E1_C138647F2A00__INCLUDED_) +#define AFX_ALL1_H__B5D522E4_69CE_11D3_99E1_C138647F2A00__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// All1.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CAll + +class CAll : public CDialog +{ +// Konstruktion +public: + void UpdateDialog(); + CAll(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CAll) + enum { IDD = IDD_ALL }; + CEdit m_Value; + CListBox m_Keys; + CButton m_IniSection; + CButton m_DeleteSection; + CButton m_DeleteKey; + CButton m_AddSection; + CButton m_AddKey; + CComboBox m_Sections; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CAll) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CAll) + afx_msg void OnSelchangeSections(); + afx_msg void OnChangeValue(); + afx_msg void OnSelchangeKeys(); + afx_msg void OnUpdateValue(); + afx_msg void OnAddsection(); + afx_msg void OnDeletesection(); + afx_msg void OnDeletekey(); + afx_msg void OnAddkey(); + afx_msg void OnInisection(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_ALL1_H__B5D522E4_69CE_11D3_99E1_C138647F2A00__INCLUDED_ diff --git a/MissionEditor/BackCliffModifier.cpp b/MissionEditor/BackCliffModifier.cpp new file mode 100644 index 0000000..f9a1499 --- /dev/null +++ b/MissionEditor/BackCliffModifier.cpp @@ -0,0 +1,100 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// BackCliffModifier.cpp: Implementierung der Klasse CBackCliffModifier. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "stdafx.h" +#include "BackCliffModifier.h" +#include <vector> +#include "variables.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Konstruktion/Destruktion +////////////////////////////////////////////////////////////////////// + +CBackCliffModifier::CBackCliffModifier() +{ + +} + +CBackCliffModifier::~CBackCliffModifier() +{ + +} + + + +void CBackCliffModifier::ModifyCurrentPos(DWORD *dwPos, BOOL bBeforePlacing, BOOL bSmall) +{ + if(!bBeforePlacing) + { + if(m_direction==cd_verticdiag_top) (*dwPos)+=2+0*Map->GetIsoSize(); + if(m_direction==cd_verticdiag_bottom) (*dwPos)+=-2+0*Map->GetIsoSize(); + } +} + +void CBackCliffModifier::ModifyStartPos(DWORD *dwPos, BOOL bSmall) +{ + if(m_direction==cd_verticdiag_top) (*dwPos)+=1+1*Map->GetIsoSize(); + if(m_direction==cd_verticdiag_bottom) (*dwPos)+=-1+0*Map->GetIsoSize(); + + if(m_direction==cd_horiz_right) (*dwPos)+=0+0*Map->GetIsoSize(); + if(m_direction==cd_horiz_left) + { + + int ground=Map->GetFielddataAt(*dwPos)->wGround; + (*dwPos)+=0+Map->GetIsoSize(); + if(ground==0xFFFF) ground=0; + if((*tiledata)[ground].wTileSet==cliffset) + { + (*dwPos)-=Map->GetIsoSize(); + //ModifyStartPos(dwPos, bSmall); + } + } + + if(m_direction==cd_vertic_top) + { + int ground=Map->GetFielddataAt(*dwPos)->wGround; + + (*dwPos)+=1; + if(ground==0xFFFF) ground=0; + if((*tiledata)[ground].wTileSet==cliffset) + { + (*dwPos)-=1; + //ModifyStartPos(dwPos, bSmall); + } + } + +} + +CString CBackCliffModifier::GetDataSection() +{ + if(m_bAlternative) return ("CliffBackDataAlt"); + return("CliffBackData"); +} diff --git a/MissionEditor/BackCliffModifier.h b/MissionEditor/BackCliffModifier.h new file mode 100644 index 0000000..114c95b --- /dev/null +++ b/MissionEditor/BackCliffModifier.h @@ -0,0 +1,46 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// BackCliffModifier.h: Schnittstelle fĂ¼r die Klasse CBackCliffModifier. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_BACKCLIFFMODIFIER_H__3853D325_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) +#define AFX_BACKCLIFFMODIFIER_H__3853D325_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "CliffModifier.h" + +class CBackCliffModifier : public CCliffModifier +{ +public: + CBackCliffModifier(); + virtual ~CBackCliffModifier(); + +protected: + virtual CString GetDataSection(); + virtual void ModifyStartPos(DWORD* dwPos, BOOL bSmall); + virtual void ModifyCurrentPos(DWORD* dwPos, BOOL bBeforePlacing, BOOL bSmall); +}; + +#endif // !defined(AFX_BACKCLIFFMODIFIER_H__3853D325_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) diff --git a/MissionEditor/Basic.cpp b/MissionEditor/Basic.cpp new file mode 100644 index 0000000..a9e84e9 --- /dev/null +++ b/MissionEditor/Basic.cpp @@ -0,0 +1,346 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Basic.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Basic.h" +#include "resource.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CBasic + +IMPLEMENT_DYNCREATE(CBasic, CPropertyPage) + +CBasic::CBasic() : CDialog(CBasic::IDD) +{ + //{{AFX_DATA_INIT(CBasic) + //}}AFX_DATA_INIT +} + +CBasic::~CBasic() +{ +} + +void CBasic::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CBasic) + DDX_Control(pDX, IDC_REQUIREDADDON, m_RequiredAddOn); + DDX_Control(pDX, IDC_VEINGROWTHENABLED, m_VeinGrowthEnabled); + DDX_Control(pDX, IDC_TRUCKCRATE, m_TruckCrate); + DDX_Control(pDX, IDC_TRAINCRATE, m_TrainCrate); + DDX_Control(pDX, IDC_TIBERIUMGROWTHENABLED, m_TiberiumGrowthEnabled); + DDX_Control(pDX, IDC_TIBERIUMDEATHTOVISCEROID, m_TiberiumDeathToVisceroid); + DDX_Control(pDX, IDC_SKIPSCORE, m_SkipScore); + DDX_Control(pDX, IDC_SKIPMAPSELECT, m_SkipMapSelect); + DDX_Control(pDX, IDC_ONETIMEONLY, m_OneTimeOnly); + DDX_Control(pDX, IDC_OFFICIAL, m_Official); + DDX_Control(pDX, IDC_NEXTSCENARIO, m_NextScenario); + DDX_Control(pDX, IDC_PERCENT, m_Percent); + DDX_Control(pDX, IDC_NEWINIFORMAT, m_NewINIFormat); + DDX_Control(pDX, IDC_NAME, m_Name); + DDX_Control(pDX, IDC_MULTIPLAYERONLY, m_MultiplayerOnly); + DDX_Control(pDX, IDC_INITTIME, m_InitTime); + DDX_Control(pDX, IDC_IGNOREGLOBALAITRIGGERS, m_IgnoreGlobalAITriggers); + DDX_Control(pDX, IDC_ICEGROWTHENABLED, m_IceGrowthEnabled); + DDX_Control(pDX, IDC_FREERADAR, m_FreeRadar); + DDX_Control(pDX, IDC_ENDOFGAME, m_EndOfGame); + DDX_Control(pDX, IDC_CARRYOVERCAP, m_CarryOverCap); + DDX_Control(pDX, IDC_ALTNEXTSCENARIO, m_AltNextScenario); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CBasic, CDialog) + //{{AFX_MSG_MAP(CBasic) + ON_EN_CHANGE(IDC_NAME, OnChangeName) + ON_CBN_EDITCHANGE(IDC_NEXTSCENARIO, OnEditchangeNextscenario) + ON_CBN_EDITCHANGE(IDC_ALTNEXTSCENARIO, OnEditchangeAltnextscenario) + ON_EN_CHANGE(IDC_NEWINIFORMAT, OnChangeNewiniformat) + ON_EN_CHANGE(IDC_CARRYOVERCAP, OnChangeCarryovercap) + ON_CBN_EDITCHANGE(IDC_ENDOFGAME, OnEditchangeEndofgame) + ON_CBN_EDITCHANGE(IDC_SKIPSCORE, OnEditchangeSkipscore) + ON_CBN_EDITCHANGE(IDC_ONETIMEONLY, OnEditchangeOnetimeonly) + ON_CBN_EDITCHANGE(IDC_SKIPMAPSELECT, OnEditchangeSkipmapselect) + ON_CBN_EDITCHANGE(IDC_OFFICIAL, OnEditchangeOfficial) + ON_CBN_EDITCHANGE(IDC_IGNOREGLOBALAITRIGGERS, OnEditchangeIgnoreglobalaitriggers) + ON_CBN_EDITCHANGE(IDC_TRUCKCRATE, OnEditchangeTruckcrate) + ON_CBN_EDITCHANGE(IDC_TRAINCRATE, OnEditchangeTraincrate) + ON_EN_CHANGE(IDC_PERCENT, OnChangePercent) + ON_EN_CHANGE(IDC_MULTIPLAYERONLY, OnChangeMultiplayeronly) + ON_CBN_EDITCHANGE(IDC_TIBERIUMGROWTHENABLED, OnEditchangeTiberiumgrowthenabled) + ON_CBN_EDITCHANGE(IDC_VEINGROWTHENABLED, OnEditchangeVeingrowthenabled) + ON_CBN_EDITCHANGE(IDC_ICEGROWTHENABLED, OnEditchangeIcegrowthenabled) + ON_CBN_EDITCHANGE(IDC_TIBERIUMDEATHTOVISCEROID, OnEditchangeTiberiumdeathtovisceroid) + ON_CBN_EDITCHANGE(IDC_FREERADAR, OnEditchangeFreeradar) + ON_EN_CHANGE(IDC_INITTIME, OnChangeInittime) + ON_CBN_EDITCHANGE(IDC_REQUIREDADDON, OnEditchangeRequiredaddon) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CBasic + +//DEL void CBasic::OnOK() +//DEL { +//DEL // TODO: Zusätzliche PrĂ¼fung hier einfĂ¼gen +//DEL +//DEL CPropertyPage::OnOK(); +//DEL } + +void CBasic::UpdateDialog() +{ + CIniFile& ini=Map->GetIniFile(); + + m_AltNextScenario.SetWindowText(ini.sections["Basic"].values["AltNextScenario"]); + m_Name.SetWindowText(ini.sections["Basic"].values["Name"]); + m_CarryOverCap.SetWindowText(ini.sections["Basic"].values["CarryOverCap"]); + m_EndOfGame.SetWindowText(ini.sections["Basic"].values["EndOfGame"]); + m_FreeRadar.SetWindowText(ini.sections["Basic"].values["FreeRadar"]); + m_IceGrowthEnabled.SetWindowText(ini.sections["Basic"].values["IceGrowthEnabled"]); + m_IgnoreGlobalAITriggers.SetWindowText(ini.sections["Basic"].values["IgnoreGlobalAITriggers"]); + m_InitTime.SetWindowText(ini.sections["Basic"].values["InitTime"]); + m_MultiplayerOnly.SetWindowText(ini.sections["Basic"].values["MultiplayerOnly"]); + m_NewINIFormat.SetWindowText(ini.sections["Basic"].values["NewINIFormat"]); + m_NextScenario.SetWindowText(ini.sections["Basic"].values["NextScenario"]); + m_Official.SetWindowText(ini.sections["Basic"].values["Official"]); + m_OneTimeOnly.SetWindowText(ini.sections["Basic"].values["OneTimeOnly"]); + m_Percent.SetWindowText(ini.sections["Basic"].values["Percent"]); + m_SkipMapSelect.SetWindowText(ini.sections["Basic"].values["SkipMapSelect"]); + m_SkipScore.SetWindowText(ini.sections["Basic"].values["SkipScore"]); + m_TiberiumDeathToVisceroid.SetWindowText(ini.sections["Basic"].values["TiberiumDeathToVisceroid"]); + m_TiberiumGrowthEnabled.SetWindowText(ini.sections["Basic"].values["TiberiumGrowthEnabled"]); + m_TrainCrate.SetWindowText(ini.sections["Basic"].values["TrainCrate"]); + m_TruckCrate.SetWindowText(ini.sections["Basic"].values["TruckCrate"]); + m_VeinGrowthEnabled.SetWindowText(ini.sections["Basic"].values["VeinGrowthEnabled"]); + + if(ini.sections["Basic"].values.find("RequiredAddOn")!=ini.sections["Basic"].values.end()) + { + m_RequiredAddOn.SetWindowText(ini.sections["Basic"].values["RequiredAddOn"]); + } + else + m_RequiredAddOn.SetWindowText("0"); + +} + +void CBasic::OnChangeName() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["Name"]=GetText(&m_Name); +} + +void CBasic::UpdateData() +{ + // MessageBox("This function ( UpdateData() ) should not be called here... please report to the author."); + errstream << "CBasic::UpdateData() called - should not be called" << endl; + errstream.flush(); +} + + +void CBasic::OnEditchangeNextscenario() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["NextScenario"]=GetText(&m_NextScenario); +} + +void CBasic::OnEditchangeAltnextscenario() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["AltNextScenario"]=GetText(&m_AltNextScenario); +} + +void CBasic::OnChangeNewiniformat() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["NewINIFormat"]=GetText(&m_NewINIFormat); +} + +void CBasic::OnChangeCarryovercap() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["CarryOverCap"]=GetText(&m_CarryOverCap); +} + +void CBasic::OnEditchangeEndofgame() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["EndOfGame"]=GetText(&m_EndOfGame); +} + +void CBasic::OnEditchangeSkipscore() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["SkipScore"]=GetText(&m_SkipScore); +} + +void CBasic::OnEditchangeOnetimeonly() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["OneTimeOnly"]=GetText(&m_OneTimeOnly); +} + +void CBasic::OnEditchangeSkipmapselect() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["SkipMapSelect"]=GetText(&m_SkipMapSelect); +} + +void CBasic::OnEditchangeOfficial() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["Official"]=GetText(&m_Official); +} + +void CBasic::OnEditchangeIgnoreglobalaitriggers() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["IgnoreGlobalAITriggers"]=GetText(&m_IgnoreGlobalAITriggers); +} + +void CBasic::OnEditchangeTruckcrate() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["TruckCrate"]=GetText(&m_TruckCrate); +} + +void CBasic::OnEditchangeTraincrate() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["TrainCrate"]=GetText(&m_TrainCrate); +} + +void CBasic::OnChangePercent() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["Percent"]=GetText(&m_Percent); +} + +void CBasic::OnChangeMultiplayeronly() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["MultiplayerOnly"]=GetText(&m_MultiplayerOnly); +} + +void CBasic::OnEditchangeTiberiumgrowthenabled() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["TiberiumGrowthEnabled"]=GetText(&m_TiberiumGrowthEnabled); +} + +void CBasic::OnEditchangeVeingrowthenabled() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["VeinGrowthEnabled"]=GetText(&m_VeinGrowthEnabled); +} + +void CBasic::OnEditchangeIcegrowthenabled() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["IceGrowthEnabled"]=GetText(&m_IceGrowthEnabled); +} + +void CBasic::OnEditchangeTiberiumdeathtovisceroid() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["TiberiumDeathToVisceroid"]=GetText(&m_TiberiumDeathToVisceroid); +} + +void CBasic::OnEditchangeFreeradar() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["FreeRadar"]=GetText(&m_FreeRadar); +} + +void CBasic::OnChangeInittime() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["InitTime"]=GetText(&m_InitTime); +} + +void CBasic::UpdateStrings() +{ + SetDlgItemText(IDC_LDESC, GetLanguageStringACP("BasicDesc")); + SetDlgItemText(IDC_LNAME, GetLanguageStringACP("BasicName")); + SetDlgItemText(IDC_LNEXTSCENARIO, GetLanguageStringACP("BasicNextScenario")); + SetDlgItemText(IDC_LALTNEXTSCENARIO, GetLanguageStringACP("BasicAltNextScenario")); + SetDlgItemText(IDC_LNEWINIFORMAT, GetLanguageStringACP("BasicNewIniFormat")); + SetDlgItemText(IDC_LCARRYOVERCAP, GetLanguageStringACP("BasicCarryOverCap")); + SetDlgItemText(IDC_LENDOFGAME, GetLanguageStringACP("BasicEndOfGame")); + SetDlgItemText(IDC_LSKIPSCORE, GetLanguageStringACP("BasicSkipScore")); + SetDlgItemText(IDC_LONETIMEONLY, GetLanguageStringACP("BasicOneTimeOnly")); + SetDlgItemText(IDC_LSKIPMAPSELECT, GetLanguageStringACP("BasicSkipMapSelect")); + SetDlgItemText(IDC_LOFFICIAL, GetLanguageStringACP("BasicOfficial")); + SetDlgItemText(IDC_LIGNOREGLOBALAITRIGGERS, GetLanguageStringACP("BasicIgnoreGlobalAITriggers")); + SetDlgItemText(IDC_LTRUCKCRATE, GetLanguageStringACP("BasicTruckCrate")); + SetDlgItemText(IDC_LTRAINCRATE, GetLanguageStringACP("BasicTrainCrate")); + SetDlgItemText(IDC_LPERCENT, GetLanguageStringACP("BasicPercent")); + SetDlgItemText(IDC_LMULTIPLAYERONLY, GetLanguageStringACP("BasicMultiplayerOnly")); + SetDlgItemText(IDC_LTIBERIUMGROWTHENABLED, GetLanguageStringACP("BasicTiberiumGrowthEnabled")); + SetDlgItemText(IDC_LVEINGROWTHENABLED, GetLanguageStringACP("BasicVeinGrowthEnabled")); + SetDlgItemText(IDC_LICEGROWTHENABLED, GetLanguageStringACP("BasicIceGrowthEnabled")); + SetDlgItemText(IDC_LTIBERIUMDEATHTOVISCEROID, GetLanguageStringACP("BasicTiberiumDeathToVisceroid")); + SetDlgItemText(IDC_LFREERADAR, GetLanguageStringACP("BasicFreeRadar")); + SetDlgItemText(IDC_LINITIME, GetLanguageStringACP("BasicInitTime")); + SetDlgItemText(IDC_LADDONNEEDED, GetLanguageStringACP("BasicAddOnNeeded")); + + + +#ifdef RA2_MODE + GetDlgItem(IDC_LVEINGROWTHENABLED)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_VEINGROWTHENABLED)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_LTRAINCRATE)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_TRAINCRATE)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_ICEGROWTHENABLED)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_LICEGROWTHENABLED)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_TIBERIUMDEATHTOVISCEROID)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_LTIBERIUMDEATHTOVISCEROID)->ShowWindow(SW_HIDE); + + +#endif + + SetWindowText(TranslateStringACP("Basic")); +} + +void CBasic::OnEditchangeRequiredaddon() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["RequiredAddOn"]=GetText(&m_RequiredAddOn); + if(ini.sections["Basic"].values["RequiredAddOn"]=="0") ini.sections["Basic"].values.erase("RequiredAddOn"); + +} + +void CBasic::PostNcDestroy() +{ + // do not call PostNcDestroy as this is a member of FinalSunDlg + //CPropertyPage::PostNcDestroy(); +} diff --git a/MissionEditor/Basic.h b/MissionEditor/Basic.h new file mode 100644 index 0000000..7687b58 --- /dev/null +++ b/MissionEditor/Basic.h @@ -0,0 +1,115 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_BASIC_H__C350C7AC_63C3_11D3_99E0_C30F10710B17__INCLUDED_) +#define AFX_BASIC_H__C350C7AC_63C3_11D3_99E0_C30F10710B17__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Basic.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CBasic + +class CBasic : public CDialog +{ + DECLARE_DYNCREATE(CBasic) + +// Konstruktion +public: + void UpdateStrings(); + void UpdateData(); + void UpdateDialog(); + CBasic(); + ~CBasic(); + +// Dialogfelddaten + //{{AFX_DATA(CBasic) + enum { IDD = IDD_BASIC }; + CMyComboBox m_RequiredAddOn; + CMyComboBox m_VeinGrowthEnabled; + CMyComboBox m_TruckCrate; + CMyComboBox m_TrainCrate; + CMyComboBox m_TiberiumGrowthEnabled; + CMyComboBox m_TiberiumDeathToVisceroid; + CMyComboBox m_SkipScore; + CMyComboBox m_SkipMapSelect; + CMyComboBox m_OneTimeOnly; + CMyComboBox m_Official; + CMyComboBox m_NextScenario; + CEdit m_Percent; + CEdit m_NewINIFormat; + CEdit m_Name; + CEdit m_MultiplayerOnly; + CEdit m_InitTime; + CMyComboBox m_IgnoreGlobalAITriggers; + CMyComboBox m_IceGrowthEnabled; + CMyComboBox m_FreeRadar; + CMyComboBox m_EndOfGame; + CEdit m_CarryOverCap; + CMyComboBox m_AltNextScenario; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CBasic) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CBasic) + afx_msg void OnChangeName(); + afx_msg void OnEditchangeNextscenario(); + afx_msg void OnEditchangeAltnextscenario(); + afx_msg void OnChangeNewiniformat(); + afx_msg void OnChangeCarryovercap(); + afx_msg void OnEditchangeEndofgame(); + afx_msg void OnEditchangeSkipscore(); + afx_msg void OnEditchangeOnetimeonly(); + afx_msg void OnEditchangeSkipmapselect(); + afx_msg void OnEditchangeOfficial(); + afx_msg void OnEditchangeIgnoreglobalaitriggers(); + afx_msg void OnEditchangeTruckcrate(); + afx_msg void OnEditchangeTraincrate(); + afx_msg void OnChangePercent(); + afx_msg void OnChangeMultiplayeronly(); + afx_msg void OnEditchangeTiberiumgrowthenabled(); + afx_msg void OnEditchangeVeingrowthenabled(); + afx_msg void OnEditchangeIcegrowthenabled(); + afx_msg void OnEditchangeTiberiumdeathtovisceroid(); + afx_msg void OnEditchangeFreeradar(); + afx_msg void OnChangeInittime(); + afx_msg void OnEditchangeRequiredaddon(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_BASIC_H__C350C7AC_63C3_11D3_99E0_C30F10710B17__INCLUDED_ diff --git a/MissionEditor/Bitmap2MapConverter.cpp b/MissionEditor/Bitmap2MapConverter.cpp new file mode 100644 index 0000000..6dfa91b --- /dev/null +++ b/MissionEditor/Bitmap2MapConverter.cpp @@ -0,0 +1,206 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Bitmap2MapConverter.cpp: Implementierung der Klasse CBitmap2MapConverter. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "stdafx.h" +#include "Bitmap2MapConverter.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Konstruktion/Destruktion +////////////////////////////////////////////////////////////////////// + +CBitmap2MapConverter::CBitmap2MapConverter() +{ + +} + +CBitmap2MapConverter::~CBitmap2MapConverter() +{ + +} + +/* +I originally intended this tool to support different theaters, +but currently it does only support temperate. People can use +copy/paste to convert those maps though! +*/ +BOOL CBitmap2MapConverter::Convert(HBITMAP hBitmap, CMapData & mapdata) +{ + BITMAP bm; + + GetObject(hBitmap, sizeof(BITMAP), &bm); + + HBITMAP hUsed=hBitmap; + + + if(bm.bmWidth+bm.bmHeight>255) + { + float scalex=(float)bm.bmWidth/(float)bm.bmHeight; + int neededheight, neededwidth; + neededheight=255.0f/(scalex+1.0f); + neededwidth=255-neededheight; + + hUsed=CreateCompatibleBitmap(GetDC(NULL), neededwidth, neededheight); + HDC hDC=CreateCompatibleDC(GetDC(NULL)); + SelectObject(hDC, hUsed); + HDC hSrcDC=CreateCompatibleDC(GetDC(NULL)); + SelectObject(hSrcDC, hBitmap); + + StretchBlt(hDC, 0,0,neededwidth,neededheight, hSrcDC, 0,0,bm.bmWidth, bm.bmHeight, SRCCOPY); + + DeleteDC(hDC); + DeleteDC(hSrcDC); + + GetObject(hUsed, sizeof(BITMAP), &bm); + } + + HDC hDC; + hDC=CreateCompatibleDC(GetDC(NULL)); + SelectObject(hDC, hUsed); + + + srand(GetTickCount()); + + int i; + int e; + int theater=0; + mapdata.CreateMap(bm.bmWidth, bm.bmHeight, "TEMPERATE", 0); + + int isosize=mapdata.GetIsoSize(); + + + for(i=0;i<(*tiledata_count);i++) + if((*tiledata)[i].wTileSet==waterset) break; + + int water_start=i+8; // to 12 + + + int sandset=atoi((*tiles).sections["General"].values["SandTile"]); + int greenset=atoi((*tiles).sections["General"].values["GreenTile"]); + +#ifdef RA2_MODE + sandset=atoi((*tiles).sections["General"].values["GreenTile"]); + greenset=atoi((*tiles).sections["General"].values["RoughTile"]); +#endif + + for(i=0;i<(*tiledata_count);i++) + if((*tiledata)[i].wTileSet==sandset) break; + + int sand_start=i; + + for(i=0;i<(*tiledata_count);i++) + if((*tiledata)[i].wTileSet==greenset) break; + + int green_start=i; + + + for(i=0;i<bm.bmWidth;i++) + { + for(e=0;e<bm.bmHeight;e++) + { + COLORREF col=GetPixel(hDC, i, bm.bmHeight-e); + + int x=(i)+mapdata.GetHeight()+1; + int y=(e)+mapdata.GetWidth(); + + int xiso; + int yiso; + + yiso=mapdata.GetIsoSize()-(y - x); + xiso=mapdata.GetIsoSize()-(x + y); + yiso-=mapdata.GetHeight(); + + + for(x=-1;x<2;x++) + { + for(y=-1;y<2;y++) + { + DWORD dwPos=xiso+x+(yiso+y)*isosize; + + if(dwPos>isosize*isosize) continue; + + FIELDDATA* fd=mapdata.GetFielddataAt(dwPos); + + int r=GetRValue(col); + int g=GetGValue(col); + int b=GetBValue(col); + + if(g>r && g>b) + { + if(theater!=1) + { + fd->wGround=0; + fd->bSubTile=0; + } + } + if(b>g && b>r) + { + int p=rand()*4/RAND_MAX; + fd->wGround=water_start+p; + fd->bSubTile=0; + } + if(g>b+25 && r>b+25 && g>120 && r>120) + { + if(theater!=1) + { + fd->wGround=sand_start; + fd->bSubTile=0; + } + } + if(b<20 && r<20 && g>20) + { +#ifdef RA2_MODE + if(g<140) // dark only +#endif + { + fd->wGround=green_start; + fd->bSubTile=0; + } + + } + + } + } + } + } + + mapdata.CreateShore(0,0,isosize, isosize); + + for(i=0;i<isosize*isosize;i++) + { + mapdata.SmoothAllAt(i); + } + + DeleteDC(hDC); + + if(hUsed!=hBitmap) DeleteObject(hUsed); + + return TRUE; +} diff --git a/MissionEditor/Bitmap2MapConverter.h b/MissionEditor/Bitmap2MapConverter.h new file mode 100644 index 0000000..4715abf --- /dev/null +++ b/MissionEditor/Bitmap2MapConverter.h @@ -0,0 +1,43 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Bitmap2MapConverter.h: Schnittstelle fĂ¼r die Klasse CBitmap2MapConverter. +// +////////////////////////////////////////////////////////////////////// + +#include "mapdata.h" + +#if !defined(AFX_BITMAP2MAPCONVERTER_H__42E61B61_E18A_11D4_9C88_816E6DEF4C47__INCLUDED_) +#define AFX_BITMAP2MAPCONVERTER_H__42E61B61_E18A_11D4_9C88_816E6DEF4C47__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class CBitmap2MapConverter +{ +public: + BOOL Convert(HBITMAP hBitmap, CMapData& mapdata); + CBitmap2MapConverter(); + virtual ~CBitmap2MapConverter(); + +}; + +#endif // !defined(AFX_BITMAP2MAPCONVERTER_H__42E61B61_E18A_11D4_9C88_816E6DEF4C47__INCLUDED_) diff --git a/MissionEditor/Building.cpp b/MissionEditor/Building.cpp new file mode 100644 index 0000000..63e72a2 --- /dev/null +++ b/MissionEditor/Building.cpp @@ -0,0 +1,317 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Building.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Building.h" +#include "mapdata.h" +#include "variables.h" +#include "inlines.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CBuilding + + +CBuilding::CBuilding(CWnd* pParent /*=NULL*/) + : CDialog(CBuilding::IDD, pParent) +{ + //{{AFX_DATA_INIT(CBuilding) + m_direction = _T(""); + m_house = _T(""); + m_flag1 = _T(""); + m_flag2 = _T(""); + m_energy = _T(""); + m_upgradecount = _T(""); + m_spotlight = _T(""); + m_upgrade1 = _T(""); + m_upgrade2 = _T(""); + m_upgrade3 = _T(""); + m_flag3 = _T(""); + m_flag4 = _T(""); + m_tag = _T(""); + //}}AFX_DATA_INIT + Init(); +} + + +void CBuilding::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CBuilding) + DDX_Control(pDX, IDC_STRENGTH, m_strength_ctrl); + DDX_CBString(pDX, IDC_DIRECTION, m_direction); + DDX_CBString(pDX, IDC_HOUSE, m_house); + DDX_Text(pDX, IDC_P1, m_flag1); + DDX_Text(pDX, IDC_P2, m_flag2); + DDX_Text(pDX, IDC_P3, m_energy); + DDX_Text(pDX, IDC_P4, m_upgradecount); + DDX_Text(pDX, IDC_P5, m_spotlight); + DDX_CBString(pDX, IDC_P6, m_upgrade1); + DDX_CBString(pDX, IDC_P7, m_upgrade2); + DDX_CBString(pDX, IDC_P8, m_upgrade3); + DDX_Text(pDX, IDC_P9, m_flag3); + DDX_Text(pDX, IDC_P10, m_flag4); + DDX_CBString(pDX, IDC_TAG, m_tag); + //}}AFX_DATA_MAP + + +} + + +BEGIN_MESSAGE_MAP(CBuilding, CDialog) + //{{AFX_MSG_MAP(CBuilding) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CBuilding + +CString GetName(CString id) +{ + CIniFile& ini=Map->GetIniFile(); + if(ini.sections.find(id)!=ini.sections.end()) + { + if(ini.sections[id].values.find("Name")!=ini.sections[id].values.end()) + return ini.sections[id].values["Name"]; + + } + return rules.sections[id].values["Name"]; +} + +void CBuilding::OnOK() +{ + CDialog::OnOK(); + + m_strength=GetText(&m_strength_ctrl); + UpdateData(); + + char d[50]; + TruncSpace(m_spotlight); + itoa(atoi(m_spotlight), d, 10); + m_spotlight=d; + + m_house=TranslateHouse(m_house); + TruncSpace(m_upgrade1); + TruncSpace(m_upgrade2); + TruncSpace(m_upgrade3); + TruncSpace(m_tag); + TruncSpace(m_flag1); + TruncSpace(m_flag2); + TruncSpace(m_flag3); + TruncSpace(m_flag4); + + // +} + +BOOL CBuilding::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CIniFile& ini=Map->GetIniFile(); + + int i; + CComboBox* chouse, *ctag; + chouse=(CComboBox*)GetDlgItem(IDC_HOUSE); + ctag=(CComboBox*)GetDlgItem(IDC_TAG); + + ListHouses(*chouse, FALSE); + ListTags(*ctag, TRUE); + + + + m_strength_ctrl.SetRange(0,256); + m_strength_ctrl.SetPos(atoi(m_strength)); + + UpdateData(FALSE); + + int upgradecount=0; + if(strcmp(m_type,"GACTWR")==NULL) + upgradecount=1; + + + if(ini.sections.find(m_type)!=ini.sections.end()) + { + if(ini.sections[m_type].values.find("Upgrades")!=ini.sections[m_type].values.end()) + { + // ok we have our upgrade + upgradecount=atoi(ini.sections[m_type].values["Upgrades"]); + } + else + { + if(rules.sections[m_type].values.find("Upgrades")!=rules.sections[m_type].values.end()) + upgradecount=atoi(rules.sections[m_type].values["Upgrades"]); + } + } + else + { + if(rules.sections[m_type].values.find("Upgrades")!=rules.sections[m_type].values.end()) + upgradecount=atoi(rules.sections[m_type].values["Upgrades"]); + } + + + GetDlgItem(IDC_P5)->SendMessage(CB_SETCURSEL, atoi(m_spotlight), 0); + + if(upgradecount>0) + { + for(i=0;i<rules.sections["BuildingTypes"].values.size();i++) + { + const char* unitname=*rules.sections["BuildingTypes"].GetValue(i); + + // okay, first all the old units + if(ini.sections.find(unitname)!=ini.sections.end()) + { + // new thing specified + if(ini.sections[unitname].values.find("PowersUpBuilding")!=ini.sections[unitname].values.end()) + { + + // ini file specified new PowersUpBuilding + if(_stricmp(ini.sections[unitname].values["PowersUpBuilding"], m_type)==NULL) + { + ((CComboBox*)GetDlgItem(IDC_P6))->AddString(((CString)unitname+" ("+GetName(unitname)+")")); + ((CComboBox*)GetDlgItem(IDC_P7))->AddString(((CString)unitname+" ("+GetName(unitname)+")")); + ((CComboBox*)GetDlgItem(IDC_P8))->AddString(((CString)unitname+" ("+GetName(unitname)+")")); + } + } + } + else + { + // ini did not specify thing specified + if(rules.sections[unitname].values.find("PowersUpBuilding")!=rules.sections[unitname].values.end()) + { + // rules file specified new PowersUpBuilding + if(_stricmp(rules.sections[unitname].values["PowersUpBuilding"], m_type)==NULL) + { + ((CComboBox*)GetDlgItem(IDC_P6))->AddString(((CString)unitname+" ("+GetName(unitname)+")")); + ((CComboBox*)GetDlgItem(IDC_P7))->AddString(((CString)unitname+" ("+GetName(unitname)+")")); + ((CComboBox*)GetDlgItem(IDC_P8))->AddString(((CString)unitname+" ("+GetName(unitname)+")")); + } + } + } + } + if(ini.sections.find("BuildingTypes")!=ini.sections.end()) + { + for(i=0;i<ini.sections["BuildingTypes"].values.size();i++) + { + const char* unitname=*ini.sections["BuildingTypes"].GetValue(i); + + // okay, first all the old units + if(ini.sections.find(unitname)!=ini.sections.end()) + { + // new thing specified + if(ini.sections[unitname].values.find("PowersUpBuilding")!=ini.sections[unitname].values.end()) + { + // ini file specified new PowersUpBuilding + if(_stricmp(ini.sections[unitname].values["PowersUpBuilding"], m_type)==NULL) + { + ((CComboBox*)GetDlgItem(IDC_P6))->AddString(((CString)unitname+" ("+GetName(unitname)+")")); + ((CComboBox*)GetDlgItem(IDC_P7))->AddString(((CString)unitname+" ("+GetName(unitname)+")")); + ((CComboBox*)GetDlgItem(IDC_P8))->AddString(((CString)unitname+" ("+GetName(unitname)+")")); + } + } + } + + } + } + } + + GetDlgItem(IDC_P8)->EnableWindow(TRUE); + GetDlgItem(IDC_P7)->EnableWindow(TRUE); + GetDlgItem(IDC_P6)->EnableWindow(TRUE); + GetDlgItem(IDC_P4)->EnableWindow(TRUE); + + if(upgradecount<3) + GetDlgItem(IDC_P8)->EnableWindow(FALSE); + if(upgradecount<2) + GetDlgItem(IDC_P7)->EnableWindow(FALSE); + if(upgradecount<1) + { + GetDlgItem(IDC_P6)->EnableWindow(FALSE); + GetDlgItem(IDC_P4)->EnableWindow(FALSE); + } + + + UpdateStrings(); + + return TRUE; +} + +void CBuilding::Init(CString house, CString strength, CString direction, CString tag, CString flag1, CString flag2, CString energy, CString upgradecount, CString spotlight, CString upgrade1, CString upgrade2, CString upgrade3, CString flag3, CString flag4) +{ + CIniFile& ini=Map->GetIniFile(); + + if(house=="") + { + house=TranslateHouse(Map->GetHouseID(0), TRUE); + } + else + m_house=TranslateHouse(house, TRUE); + + + + + m_house=TranslateHouse(house, TRUE); + m_flag1=flag1; + m_flag2=flag2; + m_flag3=flag3; + m_flag4=flag4; + m_spotlight=spotlight; + m_energy=energy; + m_upgrade1=upgrade1; + m_upgrade2=upgrade2; + m_upgrade3=upgrade3; + m_upgradecount=upgradecount; + m_strength=strength; + m_tag=tag; + m_direction=direction; + +} + +void CBuilding::UpdateStrings() +{ + SetWindowText(GetLanguageStringACP("StructCap")); + GetDlgItem(IDC_LHOUSE)->SetWindowText(GetLanguageStringACP("StructHouse")); + GetDlgItem(IDC_LDESC)->SetWindowText(GetLanguageStringACP("StructDesc")); + GetDlgItem(IDC_LSTRENGTH)->SetWindowText(GetLanguageStringACP("StructStrength")); + GetDlgItem(IDC_LDIRECTION)->SetWindowText(GetLanguageStringACP("StructDirection")); + GetDlgItem(IDC_LTAG)->SetWindowText(GetLanguageStringACP("StructTag")); + GetDlgItem(IDC_LAIREPAIRS)->SetWindowText(GetLanguageStringACP("StructAIRepairs")); + GetDlgItem(IDC_LENERGY)->SetWindowText(GetLanguageStringACP("StructEnergy")); + GetDlgItem(IDC_LUPGRADECOUNT)->SetWindowText(GetLanguageStringACP("StructUpgradeCount")); + GetDlgItem(IDC_LSPOTLIGHT)->SetWindowText(GetLanguageStringACP("StructSpotlight")); + GetDlgItem(IDC_LUPGRADE1)->SetWindowText(GetLanguageStringACP("StructUpgrade1")); + GetDlgItem(IDC_LUPGRADE2)->SetWindowText(GetLanguageStringACP("StructUpgrade2")); + GetDlgItem(IDC_LUPGRADE3)->SetWindowText(GetLanguageStringACP("StructUpgrade3")); + GetDlgItem(IDC_LP1)->SetWindowText(GetLanguageStringACP("StructP1")); + GetDlgItem(IDC_LP2)->SetWindowText(GetLanguageStringACP("StructP2")); + GetDlgItem(IDC_LP3)->SetWindowText(GetLanguageStringACP("StructP3")); + + SetDlgItemText(IDOK, GetLanguageStringACP("OK")); + SetDlgItemText(IDCANCEL, GetLanguageStringACP("Cancel")); +} diff --git a/MissionEditor/Building.h b/MissionEditor/Building.h new file mode 100644 index 0000000..739450d --- /dev/null +++ b/MissionEditor/Building.h @@ -0,0 +1,84 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_BUILDING_H__44A11CC0_84B6_11D3_B63B_F881F458F743__INCLUDED_) +#define AFX_BUILDING_H__44A11CC0_84B6_11D3_B63B_F881F458F743__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Building.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CBuilding + +class CBuilding : public CDialog +{ +// Konstruktion +public: + void UpdateStrings(); + CString m_type; + CString m_strength; + void Init(CString house="", CString strength="256", CString direction="0", CString tag="None", CString flag1="0", CString flag2="0", CString energy="1", CString upgradecount="0", CString spotlight="0", CString upgrade1="None", CString upgrade2="None", CString upgrade3="None", CString flag3="0", CString flag4="0"); + CBuilding(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CBuilding) + enum { IDD = IDD_BUILDING }; + CSliderCtrl m_strength_ctrl; + CString m_direction; + CString m_house; + CString m_flag1; + CString m_flag2; + CString m_energy; + CString m_upgradecount; + CString m_spotlight; + CString m_upgrade1; + CString m_upgrade2; + CString m_upgrade3; + CString m_flag3; + CString m_flag4; + CString m_tag; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CBuilding) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CBuilding) + virtual void OnOK(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_BUILDING_H__44A11CC0_84B6_11D3_B63B_F881F458F743__INCLUDED_ diff --git a/MissionEditor/CellTag.cpp b/MissionEditor/CellTag.cpp new file mode 100644 index 0000000..c310168 --- /dev/null +++ b/MissionEditor/CellTag.cpp @@ -0,0 +1,108 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// CellTag.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "CellTag.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CCellTag + + +CCellTag::CCellTag(CWnd* pParent /*=NULL*/) + : CDialog(CCellTag::IDD, pParent) +{ + //{{AFX_DATA_INIT(CCellTag) + m_tag = _T(""); + //}}AFX_DATA_INIT +} + + +void CCellTag::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CCellTag) + DDX_CBString(pDX, IDC_TAG, m_tag); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CCellTag, CDialog) + //{{AFX_MSG_MAP(CCellTag) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CCellTag + +string GetParam(string data, int pos); + +BOOL CCellTag::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CIniFile& ini=Map->GetIniFile(); + + CComboBox& m_Tag=*((CComboBox*)GetDlgItem(IDC_TAG)); + + if(ini.sections.find("Tags")==ini.sections.end()) + { + MessageBox("No tags are specified."); + OnCancel(); + } + else + { + ListTags(m_Tag, FALSE); + if(m_tag=="") m_Tag.SetCurSel(0); + } + + UpdateStrings(); + + return TRUE; +} + +void CCellTag::OnOK() +{ + UpdateData(); + + CDialog::OnOK(); + + TruncSpace(m_tag); +} + +void CCellTag::UpdateStrings() +{ + SetWindowText(GetLanguageStringACP("CellTagCap")); + GetDlgItem(IDC_LTAG)->SetWindowText(GetLanguageStringACP("CellTagTag")); + GetDlgItem(IDC_LDESC)->SetWindowText(GetLanguageStringACP("CellTagDesc")); + +} diff --git a/MissionEditor/CellTag.h b/MissionEditor/CellTag.h new file mode 100644 index 0000000..7b54107 --- /dev/null +++ b/MissionEditor/CellTag.h @@ -0,0 +1,68 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_CELLTAG_H__F41D5900_9133_11D3_B63B_D010F279DC93__INCLUDED_) +#define AFX_CELLTAG_H__F41D5900_9133_11D3_B63B_D010F279DC93__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// CellTag.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CCellTag + +class CCellTag : public CDialog +{ +// Konstruktion +public: + void UpdateStrings(); + CCellTag(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CCellTag) + enum { IDD = IDD_CELLTAG }; + CString m_tag; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CCellTag) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CCellTag) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_CELLTAG_H__F41D5900_9133_11D3_B63B_D010F279DC93__INCLUDED_ diff --git a/MissionEditor/ChangeSizeDlg.cpp b/MissionEditor/ChangeSizeDlg.cpp new file mode 100644 index 0000000..bbcd9da --- /dev/null +++ b/MissionEditor/ChangeSizeDlg.cpp @@ -0,0 +1,93 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// ChangeSizeDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "ChangeSizeDlg.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CChangeSizeDlg + + +CChangeSizeDlg::CChangeSizeDlg(CWnd* pParent /*=NULL*/) + : CDialog(CChangeSizeDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CChangeSizeDlg) + m_Left = 0; + m_Height = 0; + m_Top = 0; + m_Width = 0; + //}}AFX_DATA_INIT + m_Width=Map->GetWidth(); + m_Height=Map->GetHeight(); +} + + +void CChangeSizeDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CChangeSizeDlg) + DDX_Text(pDX, IDC_LEFT, m_Left); + DDX_Text(pDX, IDC_HEIGHT, m_Height); + DDV_MinMaxInt(pDX, m_Height, 0, 400); + DDX_Text(pDX, IDC_TOP, m_Top); + DDX_Text(pDX, IDC_WIDTH, m_Width); + DDV_MinMaxInt(pDX, m_Width, 0, 400); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CChangeSizeDlg, CDialog) + //{{AFX_MSG_MAP(CChangeSizeDlg) + ON_EN_CHANGE(IDC_WIDTH, OnChangeWidth) + ON_EN_CHANGE(IDC_HEIGHT, OnChangeHeight) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CChangeSizeDlg + +void CChangeSizeDlg::OnChangeWidth() +{ + if(UpdateData(TRUE)) + { + m_Left=(m_Width-Map->GetWidth())/2; + UpdateData(FALSE); + } +} + +void CChangeSizeDlg::OnChangeHeight() +{ + if(UpdateData(TRUE)) + { + m_Top=(m_Height-Map->GetHeight())/2; + UpdateData(FALSE); + } +} diff --git a/MissionEditor/ChangeSizeDlg.h b/MissionEditor/ChangeSizeDlg.h new file mode 100644 index 0000000..51f254d --- /dev/null +++ b/MissionEditor/ChangeSizeDlg.h @@ -0,0 +1,70 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_CHANGESIZEDLG_H__60391D80_1E15_11D5_89B2_444553540000__INCLUDED_) +#define AFX_CHANGESIZEDLG_H__60391D80_1E15_11D5_89B2_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ChangeSizeDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CChangeSizeDlg + +class CChangeSizeDlg : public CDialog +{ +// Konstruktion +public: + CChangeSizeDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CChangeSizeDlg) + enum { IDD = IDD_CHANGESIZE }; + int m_Left; + int m_Height; + int m_Top; + int m_Width; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CChangeSizeDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CChangeSizeDlg) + afx_msg void OnChangeWidth(); + afx_msg void OnChangeHeight(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_CHANGESIZEDLG_H__60391D80_1E15_11D5_89B2_444553540000__INCLUDED_ diff --git a/MissionEditor/CliffModifier.cpp b/MissionEditor/CliffModifier.cpp new file mode 100644 index 0000000..bfa86d8 --- /dev/null +++ b/MissionEditor/CliffModifier.cpp @@ -0,0 +1,488 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// CliffModifier.cpp: Implementierung der Klasse CCliffModifier. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "stdafx.h" +#include "CliffModifier.h" +#include "variables.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Konstruktion/Destruktion +////////////////////////////////////////////////////////////////////// + +CCliffModifier::CCliffModifier() +{ + +} + +CCliffModifier::~CCliffModifier() +{ + +} + +BOOL CCliffModifier::PlaceCliff(DWORD dwXFrom, DWORD dwYFrom, DWORD dwXDest, DWORD dwYDest, BOOL bAlternative) +{ + m_bAlternative=bAlternative; + + int x_diff, y_diff; + + x_diff=dwXDest-dwXFrom; + y_diff=dwYDest-dwYFrom; + + if(x_diff>0 && y_diff>0 && ((float)y_diff)/((float)x_diff) > 1.33f) + { + x_diff=0; + dwXDest=dwXFrom; + } + if(x_diff<0 && y_diff>0 && ((float)y_diff)/(-(float)x_diff) > 1.33f) + { + x_diff=0; + dwXDest=dwXFrom; + } + if(x_diff>0 && y_diff<0 && ((float)-y_diff)/((float)x_diff) > 1.33f) + { + x_diff=0; + dwXDest=dwXFrom; + } + if(x_diff<0 && y_diff<0 && (-(float)y_diff)/(-(float)x_diff) > 1.33f) + { + x_diff=0; + dwXDest=dwXFrom; + } + if(y_diff>0 && x_diff>0 && ((float)x_diff)/((float)y_diff) > 2) + { + y_diff=0; + dwYDest=dwYFrom; + } + if(y_diff<0 && x_diff>0 && ((float)x_diff)/(-(float)y_diff) > 2) + { + y_diff=0; + dwYDest=dwYFrom; + } + if(y_diff>0 && x_diff<0 && ((float)-x_diff)/((float)y_diff) > 2) + { + y_diff=0; + dwYDest=dwYFrom; + } + if(y_diff<0 && x_diff<0 && (-(float)x_diff)/(-(float)y_diff) > 2) + { + y_diff=0; + dwYDest=dwYFrom; + } + + m_dwFrom=dwXFrom + dwYFrom*Map->GetIsoSize(); + m_dwTo=dwXDest + dwYDest*Map->GetIsoSize(); + + if(!x_diff && !y_diff) return FALSE; + + if(x_diff && y_diff) + { + if((x_diff>0 && y_diff>0)) + { + m_direction=cd_verticdiag_bottom; + } + else if((x_diff<0 && y_diff<0)) + { + m_direction=cd_verticdiag_top; + } + else if((x_diff<0 && y_diff>0) ) + { + m_direction=cd_horizdiag_right; + } + else if(x_diff>0 && y_diff<0) + { + m_direction=cd_horizdiag_left; + } + + } + else if(y_diff<0) + { + m_direction=cd_horiz_left; + } + else if(y_diff>0) + { + m_direction=cd_horiz_right; + } + else if(x_diff<0) + { + m_direction=cd_vertic_top; + } + else if(x_diff>0) + { + m_direction=cd_vertic_bottom; + } + + switch(m_direction) + { + case cd_horiz_left: + m_addx=0; + m_addy=-1; + break; + case cd_horiz_right: + m_addx=0; + m_addy=1; + break; + case cd_horizdiag_left: + m_addx=1; + m_addy=-1; + break; + case cd_horizdiag_right: + m_addx=-1; + m_addy=1; + break; + case cd_vertic_top: + m_addx=-1; + m_addy=0; + break; + case cd_vertic_bottom: + m_addx=1; + m_addy=0; + break; + case cd_verticdiag_top: + m_addx=-1; + m_addy=-1; + break; + case cd_verticdiag_bottom: + m_addx=1; + m_addy=1; + break; + } + + int i,e; + DWORD dwCurPos=m_dwFrom; + int startheight=Map->GetHeightAt(dwCurPos); + + + + DWORD dwLastTile=-1; + + FIELDDATA* fd=Map->GetFielddataAt(dwCurPos); + int ground=fd->wGround; + int subtile=fd->bSubTile; + if(ground==0xFFFF) ground=0; + startheight-=(*tiledata)[ground].tiles[subtile].bZHeight; + + ModifyStartPos(&dwCurPos, FALSE); + + BOOL bSmall=FALSE; + DWORD dwFirstStartPos=dwCurPos; + DWORD dwTile=GetTileToPlace(dwCurPos, &bSmall); + + + + BOOL bFirstPos=TRUE; + + while(dwCurPos!=m_dwTo) + { + ModifyCurrentPos(&dwCurPos, TRUE, bSmall); + + if(!bFirstPos) + { + dwTile=GetTileToPlace(dwCurPos, &bSmall); + dwLastTile=dwTile; + } + else + bFirstPos=FALSE; + if(dwTile==-1) break; + + TILEDATA* t=&(*tiledata)[dwTile]; + + if(m_addx<0) dwCurPos+=t->cx*m_addx; + if(m_addy<0) dwCurPos+=t->cy*m_addy*Map->GetIsoSize(); + + + int o=0; + DWORD dwTmpTile=dwTile; + while(dwFirstStartPos!=dwCurPos && dwTile==dwLastTile) + { + o++; + if(o==10) break; + dwTmpTile=GetTileToPlace(dwCurPos, &bSmall); + + if((*tiledata)[dwTmpTile].cx==(*tiledata)[dwTile].cx && (*tiledata)[dwTile].cy==(*tiledata)[dwTmpTile].cy) + dwTile=dwTmpTile; + } + + + + t=&(*tiledata)[dwTile]; + + + + + + + + int p=0; + for(i=0;i<t->cx;i++) + { + for(e=0;e<t->cy;e++) + { + + if(t->tiles[p].pic!=NULL) + { + + + Map->SetHeightAt(dwCurPos+i+e*Map->GetIsoSize(), startheight+t->tiles[p].bZHeight); + Map->SetTileAt(dwCurPos+i+e*Map->GetIsoSize(), dwTile, p); + + } + p++; + } + } + + if(m_addx>0) dwCurPos+=t->cx*m_addx; + if(m_addy>0) dwCurPos+=t->cy*m_addy*Map->GetIsoSize(); + + ModifyCurrentPos(&dwCurPos, FALSE, bSmall); + + dwLastTile=dwTile; + } + + return TRUE; +} + +void CCliffModifier::ModifyStartPos(DWORD *dwStartPos, BOOL bSmall) +{ + +} + +void CCliffModifier::ModifyCurrentPos(DWORD *dwPos, BOOL bBeforePlacing, BOOL bSmall) +{ + +} + +DWORD CCliffModifier::GetTileToPlace(DWORD dwPos, BOOL* bSmall) +{ + vector<DWORD> careables; + vector<DWORD> useables; + map<DWORD, BOOL> notusedascliff; + + CString type; + int count=0; + + + switch(m_direction) + { + case cd_horiz_left: + case cd_horiz_right: + type="horiz_"; + break; + case cd_horizdiag_left: + case cd_horizdiag_right: + type="horiz_diag_"; + break; + case cd_vertic_top: + case cd_vertic_bottom: + type="vertic_"; + break; + case cd_verticdiag_top: + case cd_verticdiag_bottom: + type="vertic_diag_"; + break; + } + + + CString sec=GetDataSection(); + CIniFile& ini=Map->GetIniFile(); + if(g_data.sections.find(sec+ini.sections["Map"].values["Theater"])!=g_data.sections.end()) + sec=sec+ini.sections["Map"].values["Theater"]; + + count=atoi(g_data.sections[sec].values[type+"c"]); + + + + int i; + DWORD dwStartSet=0; + /*for(i=0;i<(*tiledata_count);i++) + { + if( (!m_bAlternative && (*tiledata)[i].wTileSet==cliffset) || (m_bAlternative && (*tiledata)[i].wTileSet==cliff2set)) + { + dwStartSet=i; + break; + } + }*/ + // a bit faster: + if(m_bAlternative) dwStartSet=cliff2set_start; + else dwStartSet=cliffset_start; + + for(i=0;i<count;i++) + { + char c[50]; + itoa(i, c, 10); + CString cur=type; + cur+=c; + notusedascliff[dwStartSet+atoi(g_data.sections[sec].values[cur])]=TRUE; + } + + CString corner_searched=""; + DWORD dwCurPos=dwPos; + int isosize=Map->GetIsoSize(); + ModifyStartPos(&dwCurPos, FALSE); + int e; + for(i=-1;i<2;i++) + { + for(e=-1;e<2;e++) + { + FIELDDATA* fd=Map->GetFielddataAt(dwCurPos+i+e*isosize); + int ground=fd->wGround; + if(ground==0xFFFF) ground=0; + + if( (*tiledata)[ground].wTileSet==cliffset && notusedascliff.find(ground)==notusedascliff.end()) + { + + + if(i==0 && e==-1) {corner_searched="cornerleft_";break;} + if(i==0 && e==1) {corner_searched="cornerright_";break;} + if(i==-1 && e==0) {corner_searched="cornertop_";break;} + if(i==1 && e==0) {corner_searched="cornerbottom_";break;} + /*if(e==-1) {corner_searched="cornerleft_";break;} + if(e==1) {corner_searched="cornerright_";break;} + if(i==-1) {corner_searched="cornertop_";break;} + if(i==1) {corner_searched="cornerbottom_";break;}*/ + } + + } + if(corner_searched.GetLength()>0) break; + } + + BOOL bCornerFound=FALSE; + if(g_data.sections[sec].FindName(type+corner_searched+"c")>=0) + { + int icount=atoi(g_data.sections[sec].values[type+corner_searched+"c"]); + if(icount) + { + bCornerFound=TRUE; + count=icount; + } + } + + if(!bCornerFound) corner_searched=""; + + if(count==0) return -1; + + + DWORD dwX=dwPos%Map->GetIsoSize(); + DWORD dwY=dwPos/Map->GetIsoSize(); + DWORD dwDX=m_dwTo%Map->GetIsoSize(); + DWORD dwDY=m_dwTo/Map->GetIsoSize(); + + + for(i=0;i<count;i++) + { + char c[50]; + itoa(i,c,10); + careables.push_back(dwStartSet+atoi(g_data.sections[sec].values[type+corner_searched+c])); + } + + for(i=0;i<careables.size();i++) + { + TILEDATA& t=(*tiledata)[careables[i]]; + + if(m_addx>0 && dwX+m_addx*t.cx>dwDX) continue; + if(m_addy>0 && dwY+m_addy*t.cy>dwDY) continue; + if(m_addx<0 && dwX+m_addx*t.cx<dwDX) continue; + if(m_addy<0 && dwY+m_addy*t.cy<dwDY) continue; + + useables.push_back(careables[i]); + } + + if(useables.size()<1) return -1; + + + *bSmall=FALSE; + + int k; + k=rand()%(useables.size()); + + TILEDATA& t1=(*tiledata)[useables[k]]; + for(i=0;i<careables.size();i++) + { + TILEDATA& t=(*tiledata)[careables[i]]; + if(t.cx>t1.cx || t.cy>t1.cy) {*bSmall=TRUE; break;} + } + + // check for water + BOOL bWater=FALSE; + for(i=0;i<t1.cx;i++) + { + for(e=0;e<t1.cy;e++) + { + + FIELDDATA* fd=Map->GetFielddataAt(dwPos+i+e*Map->GetIsoSize()); + int ground=fd->wGround; + if(ground==0xFFFF) ground=0; + if((i==t1.cx-1 || e==t1.cy-1) && (*tiledata)[ground].tiles[fd->bSubTile].bHackedTerrainType==TERRAINTYPE_WATER) + { + bWater=TRUE; + break; + } + } + if(bWater) break; + } + + + if(bWater && useables[k]-dwStartSet<22) + { + CString tset; + char c[50]; + int watercliffs=atoi(tiles->sections["General"].values["WaterCliffs"]); + if(m_bAlternative) watercliffs=cliffwater2set; + itoa(watercliffs, c, 10); + int e; + for(e=0;e<4-strlen(c);e++) + tset+="0"; + tset+=c; + CString sec="TileSet"; + sec+=tset; + + if(tiles->sections.find(sec)==tiles->sections.end()) return useables[k]; + + + if(atoi(tiles->sections[sec].values["TilesInSet"])>useables[k]-dwStartSet) + { + DWORD dwStartWaterSet=0; + for(i=0;i<(*tiledata_count);i++) + { + if((*tiledata)[i].wTileSet==watercliffs) + { + dwStartWaterSet=i; + return dwStartWaterSet+(useables[k]-dwStartSet); + } + } + + + } + } + + return useables[k]; +} + + diff --git a/MissionEditor/CliffModifier.h b/MissionEditor/CliffModifier.h new file mode 100644 index 0000000..0f12e03 --- /dev/null +++ b/MissionEditor/CliffModifier.h @@ -0,0 +1,62 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// CliffModifier.h: Schnittstelle fĂ¼r die Klasse CCliffModifier. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_CLIFFMODIFIER_H__3853D323_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) +#define AFX_CLIFFMODIFIER_H__3853D323_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "TerrainModifier.h" + + + +class CCliffModifier : public CTerrainModifier +{ + +public: + virtual BOOL PlaceCliff(DWORD dwXFrom, DWORD dwYFrom, DWORD dwXDest, DWORD dwYDest, BOOL bAlternative=FALSE); + CCliffModifier(); + virtual ~CCliffModifier(); + +protected: + virtual CString GetDataSection()=0; + virtual void ModifyCurrentPos(DWORD* dwPos, BOOL bBeforePlacing, BOOL bSmall); + virtual void ModifyStartPos(DWORD* dwStartPos, BOOL bSmall); + + enum e_cliffdirections {cd_horiz_left, cd_horiz_right, cd_horizdiag_left, + cd_horizdiag_right, cd_vertic_top, cd_vertic_bottom, cd_verticdiag_top, cd_verticdiag_bottom }; + + DWORD m_dwTo; + DWORD m_dwFrom; + e_cliffdirections m_direction; + + int m_addx; + int m_addy; + BOOL m_bAlternative; + virtual DWORD GetTileToPlace(DWORD dwPos, BOOL* bSmall) ; +}; + +#endif // !defined(AFX_CLIFFMODIFIER_H__3853D323_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) diff --git a/MissionEditor/ComboUInputDlg.cpp b/MissionEditor/ComboUInputDlg.cpp new file mode 100644 index 0000000..d0bfff4 --- /dev/null +++ b/MissionEditor/ComboUInputDlg.cpp @@ -0,0 +1,135 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "finalsun.h" +#include "ComboUInputDlg.h" +#include "functions.h" +#include "inlines.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CComboUInputDlg + + +CComboUInputDlg::CComboUInputDlg(CWnd* pParent /*=NULL*/) + : CDialog(CComboUInputDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CComboUInputDlg) + m_Caption = _T(""); + m_Combo = _T(""); + //}}AFX_DATA_INIT + + m_type=0; + bTruncateStrings=FALSE; +} + + +void CComboUInputDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CComboUInputDlg) + DDX_Text(pDX, IDC_CAPTION, m_Caption); + DDX_CBString(pDX, IDC_COMBO1, m_Combo); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CComboUInputDlg, CDialog) + //{{AFX_MSG_MAP(CComboUInputDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CComboUInputDlg + +BOOL CComboUInputDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CComboBox* box=(CComboBox*)GetDlgItem(IDC_COMBO1); + + switch(m_type) + { + case COMBOUINPUT_HOUSES: + { + ListHouses(*box, FALSE, FALSE); + break; + } + case COMBOUINPUT_COUNTRIES: + ListHouses(*box, FALSE, TRUE); + break; + case COMBOUINPUT_TRIGGERS: + ListTriggers(*box); + break; + case COMBOUINPUT_TAGS: + ListTags(*box, FALSE); + break; + case COMBOUINPUT_HOUSES_N: + { + ListHouses(*box, TRUE, FALSE); + break; + } + case COMBOUINPUT_COUNTRIES_N: + ListHouses(*box, TRUE, TRUE); + break; + case COMBOUINPUT_MANUAL: + int i; + for(i=0;i<m_ManualStrings.size();i++) + box->AddString(m_ManualStrings[i]); + } + + box->SetCurSel(0); + + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CComboUInputDlg::OnOK() +{ + UpdateData(TRUE); + + if(m_type==COMBOUINPUT_TRIGGERS || m_type==COMBOUINPUT_TAGS || m_type==COMBOUINPUT_HOUSES_N || m_type==COMBOUINPUT_COUNTRIES_N) TruncSpace(m_Combo); + else if(m_type==COMBOUINPUT_MANUAL) + { + if(bTruncateStrings) TruncSpace(m_Combo); + } + else + { + m_Combo=TranslateHouse(m_Combo, FALSE); + } + + EndDialog(0); + + //CDialog::OnOK(); +} + +void CComboUInputDlg::OnCancel() +{ + // TODO: Zusätzlichen Bereinigungscode hier einfĂ¼gen + + //CDialog::OnCancel(); +} diff --git a/MissionEditor/ComboUInputDlg.h b/MissionEditor/ComboUInputDlg.h new file mode 100644 index 0000000..f6e472e --- /dev/null +++ b/MissionEditor/ComboUInputDlg.h @@ -0,0 +1,84 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_COMBOUINPUTDLG_H__2EEED280_9A8C_11D5_89B3_00E07D97C331__INCLUDED_) +#define AFX_COMBOUINPUTDLG_H__2EEED280_9A8C_11D5_89B3_00E07D97C331__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ComboUInputDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CComboUInputDlg + +#include <vector> + +using namespace std; + +#define COMBOUINPUT_HOUSES 0 +#define COMBOUINPUT_COUNTRIES 1 +#define COMBOUINPUT_TRIGGERS 2 +#define COMBOUINPUT_TAGS 3 +#define COMBOUINPUT_HOUSES_N 4 +#define COMBOUINPUT_COUNTRIES_N 5 +#define COMBOUINPUT_MANUAL 6 + +class CComboUInputDlg : public CDialog +{ +// Konstruktion +public: + int m_type; + vector<CString> m_ManualStrings; + BOOL bTruncateStrings; + CComboUInputDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CComboUInputDlg) + enum { IDD = IDD_COMBO_UINPUT }; + CString m_Caption; + CString m_Combo; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CComboUInputDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CComboUInputDlg) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + virtual void OnCancel(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_COMBOUINPUTDLG_H__2EEED280_9A8C_11D5_89B3_00E07D97C331__INCLUDED_ diff --git a/MissionEditor/Defines.h b/MissionEditor/Defines.h new file mode 100644 index 0000000..52c6937 --- /dev/null +++ b/MissionEditor/Defines.h @@ -0,0 +1,200 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +/************************** + Defines.h + Place any definitions here +**************************/ + +// set NOSURFACES to use palettized tile drawing - probably slower, but using less memory +#define NOSURFACES +#define NOSURFACES_EXTRACT // this will cause tiles to be extracted +// #undef NOSURFACES // enable this if display is too slow + +// set NOSURFACES_OBJECTS to use palettized object & overlay drawing - slower, but better display +#define NOSURFACES_OBJECTS +// #undef NOSURFACES_OBJECTS + +// MW 08/07/01: define SMUDGE_SUPP if you want to support smudges +// added this as switch because if there are problems with this new feature we can just disable it +#define SMUDGE_SUPP + +// tiberium / ore +#ifdef RA2_MODE +#define RIPARIUS_BEGIN 102 +#define RIPARIUS_END 121 +#define CRUENTUS_BEGIN 27 +#define CRUENTUS_END 38 +#define VINIFERA_BEGIN 127 +#define VINIFERA_END 146 +#define ABOREUS_BEGIN 147 +#define ABOREUS_END 166 +#else +#define RIPARIUS_BEGIN 102 +#define RIPARIUS_END 121 +#define CRUENTUS_BEGIN 27 +#define CRUENTUS_END 38 +#define VINIFERA_BEGIN 127 +#define VINIFERA_END 146 +#define ABOREUS_BEGIN 147 +#define ABOREUS_END 166 +#endif + +// picdata type +#define PICDATA_TYPE_BMP 0 +#define PICDATA_TYPE_SHP 1 +#define PICDATA_TYPE_VXL 2 + +#define SUBPOS_COUNT 3 +#define REAL_SUBPOS_COUNT 3 + +#define SOUND_NONE 0 +#define SOUND_POSITIVE 1 +#define SOUND_NEGATIVE 2 +#define SOUND_LAYDOWNTILE 3 +#define SOUND_DELETETILE 4 + +// actiondata modes (isoview user interface) +#define ACTIONMODE_PLACE 1 // place any unit, building, tree or overlay +#define ACTIONMODE_ERASEFIELD 2 // delete any unit, building, or tree +#define ACTIONMODE_WAYPOINT 3 // any waypoint editing +#define ACTIONMODE_CELLTAG 4 // any celltag editing +#define ACTIONMODE_NODE 5 // any node editing +#define ACTIONMODE_MAPTOOL 6 +#define ACTIONMODE_SETTILE 10 // setting ground tiles +#define ACTIONMODE_HEIGHTEN 11 // heighten ground +#define ACTIONMODE_LOWER 12 // lower ground +#define ACTIONMODE_LOWERTILE 13 +#define ACTIONMODE_HEIGHTENTILE 14 +#define ACTIONMODE_FLATTENGROUND 15 +#define ACTIONMODE_HIDETILESET 16 // make specific tileset invisible +#define ACTIONMODE_HIDEFIELD 17 // make specific field invisible +#define ACTIONMODE_CLIFFFRONT 18 // add front cliff +#define ACTIONMODE_CLIFFBACK 19 // add back cliff +#define ACTIONMODE_COPY 20 +#define ACTIONMODE_PASTE 21 +#define ACTIONMODE_RANDOMTERRAIN 22 +#define ACTIONMODE_SMUDGE 23 + +// paramtype list types +#define PARAMTYPE_NOTHING 0 +#define PARAMTYPE_HOUSES 1 +#define PARAMTYPE_TEAMTYPES 2 +#define PARAMTYPE_UNITTYPES 3 +#define PARAMTYPE_INFANTRYTYPES 4 +#define PARAMTYPE_AIRCRAFTTYPES 5 +#define PARAMTYPE_BUILDINGTYPES 6 +#define PARAMTYPE_VIDEOS 7 +#define PARAMTYPE_TUTORIALTEXTS 8 +#define PARAMTYPE_TRIGGERS 9 +#define PARAMTYPE_YESNO 10 +#define PARAMTYPE_SOUNDS 11 +#define PARAMTYPE_THEMES 12 +#define PARAMTYPE_SPEECHES 13 +#define PARAMTYPE_SPECIALWEAPONS 14 +#define PARAMTYPE_ANIMATIONS 15 +#define PARAMTYPE_PARTICLES 16 +#define PARAMTYPE_WAYPOINTS 17 +#define PARAMTYPE_CRATETYPES 18 +#define PARAMTYPE_SPEECHBUBBLETYPES 19 +#define PARAMTYPE_GLOBALS 20 +#define PARAMTYPE_RULESGLOBALS 27 +#define PARAMTYPE_BUILDINGTYPESINI 28 +#define PARAMTYPE_TECHTYPES 29 + +#define THEATER0 "TEMPERATE" +#define THEATER1 "SNOW" +#define THEATER2 "URBAN" +#define THEATER3 "NEWURBAN" +#define THEATER4 "LUNAR" +#define THEATER5 "DESERT" + + +#define ra2_mode 1 +#define ts_mode 0 + + +#ifndef RA2_MODE + +#define NO_URBAN +#define MAXHEIGHT 14 + +#define f_y 24 +#define f_x 48 + +#define TERRAINTYPE_GROUND 0x0d +#define TERRAINTYPE_WATER 0x09 +#define TERRAINTYPE_IMPASSABLE 0x0f +#define TERRAINTYPE_ROUGH 0x0e +#define TERRAINTYPE_PAVED 0x0b +#define TERRAINTYPE_BUILDING 0x07 +#define TERRAINTYPE_DIRT_ROAD 0x0c +#define TERRAINTYPE_ICE 0x01 + +#define MAINMIX "TIBSUN.MIX" +#define HOUSES "Houses" +#define MAPHOUSES "Houses" + +#endif +#ifdef RA2_MODE + +#define MAINMIX "RA2.MIX" +#define HOUSES "Countries" +#define MAPHOUSES "Houses" + +#define MAXHEIGHT 14 + +#define f_y 30 +#define f_x 60 + +#define TERRAINTYPE_GROUND 0x0d +#define TERRAINTYPE_WATER 0x09 +#define TERRAINTYPE_IMPASSABLE 0x0f +#define TERRAINTYPE_ROUGH 0x0e +#define TERRAINTYPE_PAVED 0x0b +#define TERRAINTYPE_BUILDING 0x07 +#define TERRAINTYPE_DIRT_ROAD 0x0c +#define TERRAINTYPE_ICE 0x01 + +#endif + +#define SLOPE_UP_RIGHT 1 +#define SLOPE_UP_BOTTOM 2 +#define SLOPE_UP_LEFT 3 +#define SLOPE_UP_TOP 4 +#define SLOPE_UP_RIGHTBOTTOM 5 +#define SLOPE_UP_LEFTBOTTOM 6 +#define SLOPE_UP_LEFTTOP 7 +#define SLOPE_UP_RIGHTTOP 8 +#define SLOPE_DOWN_LEFTTOP 9 +#define SLOPE_DOWN_RIGHTTOP 10 +#define SLOPE_DOWN_RIGHTBOTTOM 11 +#define SLOPE_DOWN_LEFTBOTTOM 12 +#define SLOPE_DOWN_TOP 13 // z difference of x-1/y-1 to x+1/y+1 is -2, to x+1/y 1, to x/y+1 1 +#define SLOPE_DOWN_RIGHT 14 +#define SLOPE_DOWN_BOTTOM 15 +#define SLOPE_DOWN_LEFT 16 +#define SLOPE_UP_LEFTBOTTOM_AND_RIGHTTOP 17 +#define SLOPE_UP_LEFTTOP_AND_RIGHTBOTTOM 18 +#define SLOPE_UP_LEFTBOTTOM_AND_RIGHTTOP2 19 +#define SLOPE_UP_LEFTTOP_AND_RIGHTBOTTOM2 20 + +// max images loaded from one overlay graphic file (SHP) +#define max_ovrl_img 60 \ No newline at end of file diff --git a/MissionEditor/DownloadSession.cpp b/MissionEditor/DownloadSession.cpp new file mode 100644 index 0000000..a487644 --- /dev/null +++ b/MissionEditor/DownloadSession.cpp @@ -0,0 +1,49 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "stdafx.h" +#include "DownloadSession.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Konstruktion/Destruktion +////////////////////////////////////////////////////////////////////// + +CDownloadSession::CDownloadSession():CInternetSession("FinalAlert Download", 1, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC | INTERNET_FLAG_DONT_CACHE) +{ + +} + +CDownloadSession::~CDownloadSession() +{ + +} + + +void CDownloadSession::OnStatusCallback(DWORD dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength ) +{ + +} \ No newline at end of file diff --git a/MissionEditor/DownloadSession.h b/MissionEditor/DownloadSession.h new file mode 100644 index 0000000..3f6ed90 --- /dev/null +++ b/MissionEditor/DownloadSession.h @@ -0,0 +1,40 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include <afxinet.h> + +#if !defined(AFX_DOWNLOADSESSION_H__944482A1_E98F_11D4_9C88_82B0A7E03C49__INCLUDED_) +#define AFX_DOWNLOADSESSION_H__944482A1_E98F_11D4_9C88_82B0A7E03C49__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class CDownloadSession : public CInternetSession +{ +public: + CDownloadSession(); + virtual ~CDownloadSession(); +protected: + virtual void OnStatusCallback( DWORD dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength ); + +}; + +#endif // !defined(AFX_DOWNLOADSESSION_H__944482A1_E98F_11D4_9C88_82B0A7E03C49__INCLUDED_) diff --git a/MissionEditor/DynamicGraphDlg.cpp b/MissionEditor/DynamicGraphDlg.cpp new file mode 100644 index 0000000..6cad11d --- /dev/null +++ b/MissionEditor/DynamicGraphDlg.cpp @@ -0,0 +1,67 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "finalsun.h" +#include "DynamicGraphDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CDynamicGraphDlg + + +CDynamicGraphDlg::CDynamicGraphDlg(CWnd* pParent /*=NULL*/) + : CDialog(CDynamicGraphDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CDynamicGraphDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT + + Create(CDynamicGraphDlg::IDD, pParent); +} + + +void CDynamicGraphDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CDynamicGraphDlg) + DDX_Control(pDX, IDC_PROGRESS, m_Progress); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CDynamicGraphDlg, CDialog) + //{{AFX_MSG_MAP(CDynamicGraphDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros fĂ¼r Nachrichten ein + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CDynamicGraphDlg + +void CDynamicGraphDlg::PostNcDestroy() +{ + // delete this; +} diff --git a/MissionEditor/DynamicGraphDlg.h b/MissionEditor/DynamicGraphDlg.h new file mode 100644 index 0000000..8cf4286 --- /dev/null +++ b/MissionEditor/DynamicGraphDlg.h @@ -0,0 +1,69 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_DYNAMICGRAPHDLG_H__ED5FED21_83F5_11D4_9C87_86ADAD0FBC4A__INCLUDED_) +#define AFX_DYNAMICGRAPHDLG_H__ED5FED21_83F5_11D4_9C87_86ADAD0FBC4A__INCLUDED_ + +#include "resource.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// DynamicGraphDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CDynamicGraphDlg + +class CDynamicGraphDlg : public CDialog +{ +// Konstruktion +public: + CDynamicGraphDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CDynamicGraphDlg) + enum { IDD = IDD_DYNAMICLOAD }; + CProgressCtrl m_Progress; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CDynamicGraphDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CDynamicGraphDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_DYNAMICGRAPHDLG_H__ED5FED21_83F5_11D4_9C87_86ADAD0FBC4A__INCLUDED_ diff --git a/MissionEditor/FinalSun.cpp b/MissionEditor/FinalSun.cpp new file mode 100644 index 0000000..b65e21c --- /dev/null +++ b/MissionEditor/FinalSun.cpp @@ -0,0 +1,628 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// +// This is the application code. Mainly shows the main dialog and initializes some application global stuff +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "FinalSunDlg.h" +#include "structs.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" +#include <ShlObj.h> + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#define APPID "FinalSun App" + +extern char AppPath[]; + +extern ACTIONDATA AD; + +///////////////////////////////////////////////////////////////////////////// +// CFinalSunApp + +BEGIN_MESSAGE_MAP(CFinalSunApp, CWinApp) + //{{AFX_MSG_MAP(CFinalSunApp) + //}}AFX_MSG_MAP + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CFinalSunApp construction + +void __cdecl term_func() +{ + if (MessageBox(0, "Fatal error. Exit FinalSun?", "Fatal error", MB_YESNO) == IDCANCEL) return; + + exit(-1); +} + + +CFinalSunApp::CFinalSunApp() +{ + m_cf = RegisterClipboardFormat("FINAL*FORMAT"); + + if (!m_cf) MessageBox(0, "Failed to register clipboard format, clipboard functions not available", "", 0); + + tiledata_count = &t_tiledata_count; + tiledata = &t_tiledata; + + // first: set up global variable AppPath + // [02/16/2000] using GetModuleFileName() instead of GetCurrentDirectory(): always the correct path + wchar_t AppPathUtf16[MAX_PATH] = { 0 }; + GetModuleFileNameW(NULL, AppPathUtf16, MAX_PATH); + strcpy_s(AppPath, utf16ToUtf8(AppPathUtf16).c_str()); + *(strrchr(AppPath, '\\') + 1) = 0; + + // Initialize AppData + const std::wstring AppDataPathFolder = utf8ToUtf16(u8AppDataPath.substr(0, u8AppDataPath.size() - 1)); + auto create_dir_res = SHCreateDirectoryExW(NULL, AppDataPathFolder.c_str(), nullptr); + if (ERROR_SUCCESS != create_dir_res && ERROR_ALREADY_EXISTS != create_dir_res) + { + wchar_t err_msg[1025] = { 0 }; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, create_dir_res, 0, err_msg, 1024, NULL); + MessageBoxW(NULL, err_msg, (std::wstring(L"Failed to open ") + AppDataPathFolder).c_str(), 0); + exit(1); + } + + if ((GetFileAttributesW(AppDataPathFolder.c_str()) & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) + { + MessageBoxW(NULL, (AppDataPathFolder + L" must be a directory, not a file").c_str(), (std::wstring(L"Failed to open ") + AppDataPathFolder).c_str(), 0); + exit(1); + } + + /*memset(t_tilepics, 0, sizeof(TILEPICDATA)*10000); + memset(s_tilepics, 0, sizeof(TILEPICDATA)*10000);*/ + + m_Options.LanguageName = "English"; + m_Options.bFlat = FALSE; + m_Options.bEasy = FALSE; + m_Options.bSupportMarbleMadness = FALSE; + m_Options.bMarbleMadness = FALSE; + + auto log = u8AppDataPath; +#ifdef TS_MODE + log += "finalsunlog.txt"; +#else + log += "finalalert2log.txt"; +#endif + m_u8LogFileName = log; + errstream.open(m_u8LogFileName, ios_base::trunc); + errstream << "\uFEFF"; // BOM + +#ifdef TS_MODE + errstream << "FinalSun log file" << std::endl << "----------------------" << std::endl << std::endl; +#else + errstream << "FinalAlert 2 log file" << std::endl << "----------------------" << std::endl << std::endl; +#endif + errstream << "CFinalSunApp::CFinalSunApp() called" << std::endl; + + errstream << "App Path: " << AppPath << std::endl; + errstream << "AppData Path: " << u8AppDataPath << std::endl; + errstream << "Locale: " << setlocale(LC_ALL, nullptr) << std::endl; + errstream << "Windows ACP: " << GetACP() << std::endl; + + + INITCOMMONCONTROLSEX ctr; + ctr.dwSize = sizeof(INITCOMMONCONTROLSEX); + ctr.dwICC = ICC_STANDARD_CLASSES; + if (!InitCommonControlsEx(&ctr)) + { + errstream << "Error: Common controls could not be initialized" << std::endl; + MessageBox(0, "Common controls could not be initialized.", "Error", 0); + } + + errstream << std::endl << std::endl << std::endl; + + errstream.flush(); + +} + + +///////////////////////////////////////////////////////////////////////////// +// CFinalSunApp initialization + +BOOL CFinalSunApp::InitInstance() +{ + m_hAccel = LoadAccelerators(this->m_hInstance, MAKEINTRESOURCE(IDR_MAIN)); + +#ifndef NOSURFACES + if (GetDeviceCaps(GetDC(GetDesktopWindow()), BITSPIXEL) <= 8) + { + MessageBox(0, "You currently only have 8 bit color mode enabled. This is not recommended. You can continue, but this will cause a significant slowdown while loading graphics, and result in poor graphics quality", "Error", 0); + //exit(0); + } +#else + if (GetDeviceCaps(GetDC(GetDesktopWindow()), BITSPIXEL) <= 8) + { + MessageBox(0, "You currently only have 8 bit color mode enabled. FinalSun/FinalAlert 2 will not work in 8 bit color mode. See readme.txt for further information!", "Error", 0); + exit(0); + } +#endif + + ParseCommandLine(); + + // Load application data + std::string datafile = AppPath; +#ifdef TS_MODE + datafile += "\\FSData.ini"; +#else + datafile += "\\FAData.ini"; +#endif + + g_data.LoadFile(datafile); + + // Load language data + std::string languagefile = AppPath; +#ifndef RA2_MODE + languagefile += "\\FSLanguage.ini"; +#else + languagefile += "\\FALanguage.ini"; +#endif + language.LoadFile(languagefile); + + if (language.sections.size() == 0) + { + MessageBox(0, "FALanguage.ini does not exist or is not valid (download corrupt?)", "", 0); + exit(0); + } + +#ifndef RA2_MODE + const std::string iniName = "FinalSun.ini"; + const std::string defaultIniName = "FinalSunDefaults.ini"; +#else + const std::string iniName = "FinalAlert.ini"; + const std::string defaultIniName = "FinalAlertDefaults.ini"; +#endif + + // ok lets get some options + CIniFile optini; + std::string iniFile = u8AppDataPath + iniName; + std::string templateIniFile = std::string(AppPath) + defaultIniName; + + bool copiedDefaultFile = false; + if (!DoesFileExist(iniFile.c_str())) + { + if (CopyFileW(utf8ToUtf16(templateIniFile).c_str(), utf8ToUtf16(iniFile).c_str(), TRUE)) + copiedDefaultFile = true; + } + + optini.LoadFile(iniFile); + +#ifdef RA2_MODE + CString game = "RA2"; + CString app = "FinalAlert"; +#else + CString game = "TS"; + CString app = "FinalSun"; +#endif + + std::wstring key; +#ifdef RA2_MODE + key = L"Software\\Westwood\\Red Alert 2"; +#else + key = L"Software\\Westwood\\Tiberian Sun"; +#endif + + auto& opts = m_Options; + + HKEY hKey = 0; + int res; + res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_EXECUTE/*KEY_ALL_ACCESS*/, &hKey); + if (res != ERROR_SUCCESS) + { + std::wstring s = L"Failed to access registry. Using manual setting. Error was:\n"; + wchar_t c[1024] = { 0 }; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, res, 0, c, 1023, NULL); + MessageBoxW(0, (s + c).c_str(), L"Error", 0); + opts.TSExe = optini.sections[game].values["Exe"]; + } + else + { + // key opened + wchar_t path[MAX_PATH + 1] = { 0 }; + DWORD pathsize = MAX_PATH; + DWORD type = REG_SZ; + if ((res = RegQueryValueExW(hKey, L"InstallPath", 0, &type, (unsigned char*)path, &pathsize)) != ERROR_SUCCESS) + { + std::wstring s = L"Failed to access registry. Using manual setting. Error was:\n"; + wchar_t c[1024] = { 0 }; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, res, 0, c, 1023, NULL); + MessageBoxW(0, (s + c).c_str(), L"Error", 0); + opts.TSExe = optini.sections[game].values["Exe"]; + } + else + opts.TSExe = path; + } + + + if (copiedDefaultFile || + optini.sections.size() == 0 || + opts.TSExe.GetLength() == 0 || + optini.sections[app].values["Language"].GetLength() == 0 || + optini.sections[app].values.find("FileSearchLikeGame") == optini.sections[app].values.end() || + optini.sections[app].values.find("PreferLocalTheaterFiles") == optini.sections[app].values.end()) + { + opts.bSearchLikeTS = TRUE; + + bOptionsStartup = TRUE; + ShowOptionsDialog(); + bOptionsStartup = FALSE; + + } + else + { + opts.LanguageName = optini.sections[app].values["Language"]; + if (optini.sections[app].values["FileSearchLikeGame"] != "no") + opts.bSearchLikeTS = TRUE; + else opts.bSearchLikeTS = FALSE; + } + opts.bPreferLocalTheaterFiles = optini.sections[app].values.emplace("PreferLocalTheaterFiles", opts.bPreferLocalTheaterFiles ? "1" : "0").first->second == "1"; + + opts.bDoNotLoadAircraftGraphics = optini.sections["Graphics"].values["NoAircraftGraphics"] == "1"; + opts.bDoNotLoadVehicleGraphics = optini.sections["Graphics"].values["NoVehicleGraphics"] == "1"; + opts.bDoNotLoadBuildingGraphics = optini.sections["Graphics"].values["NoBuildingGraphics"] == "1"; + opts.bDoNotLoadInfantryGraphics = optini.sections["Graphics"].values["NoInfantryGraphics"] == "1"; + opts.bDoNotLoadTreeGraphics = optini.sections["Graphics"].values["NoTreeGraphics"] == "1"; + opts.bDoNotLoadSnowGraphics = optini.sections["Graphics"].values["NoSnowGraphics"] == "1"; + opts.bDoNotLoadTemperateGraphics = optini.sections["Graphics"].values["NoTemperateGraphics"] == "1"; + opts.bDoNotLoadBMPs = optini.sections["Graphics"].values["NoBMPs"] == "1"; + opts.bDoNotLoadOverlayGraphics = optini.sections["Graphics"].values["NoOverlayGraphics"] == "1"; + opts.bVSync = optini.sections["Graphics"].values.emplace("VSync", opts.bVSync ? "1" : "0").first->second == "1"; + + opts.bDisableAutoShore = optini.sections["UserInterface"].values["DisableAutoShore"] == "1"; + opts.bDisableAutoLat = optini.sections["UserInterface"].values["DisableAutoLat"] == "1"; + opts.bNoSounds = optini.sections["UserInterface"].values["Sounds"] != "1"; + opts.bDisableSlopeCorrection = optini.sections["UserInterface"].values["DisableSlopeCorrection"] == "1"; + opts.fLoadScreenDelayInSeconds = static_cast<float>(atof(optini.sections["UserInterface"].values.emplace("LoadScreenDelay", std::to_string(opts.fLoadScreenDelayInSeconds).c_str()).first->second)); + opts.bShowStats = optini.sections["UserInterface"].values.emplace("ShowStats", opts.bShowStats ? "1" : "0").first->second == "1"; + opts.bHighResUI = optini.sections["UserInterface"].values.emplace("HighRes", opts.bHighResUI ? "1" : "0").first->second == "1"; + opts.useDefaultMouseCursor = optini.sections["UserInterface"].values.emplace("UseDefaultMouseCursor", opts.useDefaultMouseCursor ? "1" : "0").first->second == "1"; + + opts.fMiniMapScale = static_cast<float>(atof(optini.sections["MiniMap"].values.emplace("Scale", std::to_string(opts.fMiniMapScale).c_str()).first->second)); + + auto defaultViewSteps = CString(Join(",", opts.viewScaleSteps | std::views::transform([](auto v) {return std::to_string(v); })).c_str()); + auto viewScaleStepsRange = SplitParams(optini.sections["UserInterface"].values.emplace("ViewScaleSteps", defaultViewSteps).first->second) | std::views::transform([](auto v) { return static_cast<float>(std::atof(v)); }); + opts.viewScaleSteps.assign(viewScaleStepsRange.begin(), viewScaleStepsRange.end()); + opts.viewScaleUseSteps = optini.sections["UserInterface"].values.emplace("ViewScaleUseSteps", opts.viewScaleUseSteps ? "1" : "0").first->second == "1"; + opts.viewScaleSpeed = static_cast<float>(atof(optini.sections["UserInterface"].values.emplace("ViewScaleSpeed", std::to_string(opts.viewScaleSpeed).c_str()).first->second)); + + // MW 07/19/01 + opts.bShowCells = optini.sections["UserInterface"].values["ShowBuildingCells"] == "1"; + + optini.SaveFile(iniFile); + + // MW 07/20/01: Load file list + int i; + for (i = 0;i < 4;i++) + { + char c[50]; + itoa(i, c, 10); + opts.prev_maps[i] = optini.sections["Files"].values[c]; + } + + if (opts.bDoNotLoadTemperateGraphics && opts.bDoNotLoadSnowGraphics) + { + MessageBox(0, "You have turned off loading of both snow and temperate terrain in 'FinalAlert.ini'. At least one of these must be loaded. The application will now quit.", "Error", 0); + exit(-982); + } + + int EasyView; + if (optini.sections["UserInterface"].FindName("EasyView") < 0) + { + MessageBox(0, GetLanguageStringACP("ExplainEasyView"), GetLanguageStringACP("ExplainEasyViewCap"), 0); + EasyView = 1; + + optini.LoadFile(iniFile); + optini.sections["UserInterface"].values["EasyView"] = "1"; + optini.SaveFile(iniFile); + } + else + { + EasyView = atoi(optini.sections["UserInterface"].values["EasyView"]); + } + if (EasyView != 0) theApp.m_Options.bEasy = TRUE; + + + + + CString cTSPath = theApp.m_Options.TSExe; + auto lastSlash = cTSPath.ReverseFind('\\'); + if (lastSlash >= 0) + cTSPath.SetAt(lastSlash + 1, 0); + strcpy(TSPath, cTSPath); + + // MW 01/23/2013: changed the global CMapData Map to a global CMapData* to get rid of static initialization/shutdown problems + { + std::unique_ptr<CMapData> mapData(new CMapData()); + Map = mapData.get(); + + CLoading loading(NULL); + m_loading = &loading; + + CFinalSunDlg dlg; + m_pMainWnd = &dlg; + + dlg.DoModal(); + } + + // Map and dialog closed, do further work if required + + return FALSE; +} + +void CFinalSunApp::ParseCommandLine() +{ +#ifdef 0 // Removed as it can conflict with Steam game arguments! -LF 23.02.2024 + char data[MAX_PATH + 30]; + + strcpy(data, theApp.m_lpCmdLine); + if (strlen(data) == 0) + { + strcpy(currentMapFile, ""); + return; + } + + strcpy(currentMapFile, data); +#endif +} + +void CFinalSunApp::ShowTipAtStartup(void) +{ + CTipDlg dlg; + if (dlg.m_bStartup) + dlg.DoModal(); + + +} + +void CFinalSunApp::ShowTipOfTheDay(void) +{ + CTipDlg dlg; + dlg.DoModal(); + +} + +int CFinalSunApp::Run() +{ + return CWinApp::Run(); + +} + +BOOL CFinalSunApp::ProcessMessageFilter(int code, LPMSG lpMsg) +{ + if (lpMsg->message == WM_KEYDOWN) + { + /*if(lpMsg->wParam==VK_F1) + { + if(ShellExecute(0, NULL, (CString)AppPath+"/help/index.htm", NULL, NULL, SW_NORMAL)==0) + { + MessageBox(0,(CString)"Could not open manual! Try opening "+(CString)AppPath+(CString)"/help/index.htm manually","Error",0); + } + return TRUE; + }*/ + + // check AD mode + + if (lpMsg->wParam == VK_PRIOR || lpMsg->wParam == VK_NEXT) + { + if (lpMsg->wParam == VK_PRIOR) + { + AD.z_data += 1; + } + if (lpMsg->wParam == VK_NEXT) + { + AD.z_data -= 1; + } + + if (AD.mode == ACTIONMODE_SETTILE || AD.mode == ACTIONMODE_PASTE) + { + CIsoView* v = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + CTerrainDlg& tdlg = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_browser->m_bar; + WORD isox, isoy; + RECT r; + POINT p; + v->GetWindowRect(&r); + GetCursorPos(&p); + isox = p.x - r.left; + isoy = p.y - r.top; + + if (isox > r.right - r.left || isoy > r.bottom - r.top) + { + + } + else + { + LPARAM lParam; + memcpy(&lParam, &isox, 2); + memcpy((BYTE*)&lParam + 2, &isoy, 2); + v->SendMessage(WM_MOUSEMOVE, 0, lParam); + } + + } + } + + + + + + if (AD.mode == ACTIONMODE_SETTILE) + { + CIsoView* v = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + CTerrainDlg& tdlg = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_browser->m_bar; + WORD isox, isoy; + RECT r; + POINT p; + v->GetWindowRect(&r); + GetCursorPos(&p); + isox = p.x - r.left; + isoy = p.y - r.top; + if (isox > r.right - r.left || isoy > r.bottom - r.top) + { + + } + else + { + LPARAM lParam; + memcpy(&lParam, &isox, 2); + memcpy((BYTE*)&lParam + 2, &isoy, 2); + + int searchedTileSet; + int z; + switch (lpMsg->wParam) + { + + case VK_LEFT: + if (AD.type > 0 && (*tiledata)[AD.type].wTileSet == (*tiledata)[AD.type - 1].wTileSet) { AD.type -= 1; AD.z_data = 0; } + v->SendMessage(WM_MOUSEMOVE, 0, lParam); + return 0; + break; + case VK_RIGHT: + if (AD.type < (*tiledata_count) - 1 && (*tiledata)[AD.type].wTileSet == (*tiledata)[AD.type + 1].wTileSet) { AD.type += 1; AD.z_data = 0; } + v->SendMessage(WM_MOUSEMOVE, 0, lParam); + return 0; + break; + case VK_UP: + searchedTileSet = (*tiledata)[AD.type].wTileSet - 1; + case VK_DOWN: + if (lpMsg->wParam == VK_DOWN) + searchedTileSet = (*tiledata)[AD.type].wTileSet + 1; + + if (searchedTileSet >= 0 && searchedTileSet < tilesets_start.size()) + { + int i; + int s = 1; + int start = 0; + int count = tilesets_start.size() - searchedTileSet; + + if (searchedTileSet < (*tiledata)[AD.type].wTileSet) + { + s = -1; + start = 0; + count = searchedTileSet + 1; + } + + + + + for (i = start;i < count;i += 1) + { + if (searchedTileSet + i * s < 0 || searchedTileSet + i * s >= tilesets_start.size()) continue; + + int pos = tilesets_start[searchedTileSet + i * s]; + + + + + int e; + CComboBox* cb = ((CComboBox*)tdlg.GetDlgItem(IDC_TILESET)); + BOOL bFound = FALSE; + for (e = 0;e < cb->GetCount();e++) + { + if (cb->GetItemData(e) == searchedTileSet + i * s) + { + cb->SendMessage(CB_SETCURSEL, e, 0); + bFound = TRUE; + break; + } + } + + if (bFound) + { + AD.type = tilesets_start[searchedTileSet + i * s]; + AD.data = 0; + AD.data2 = 0; + AD.data3 = 0; + AD.data_s = ""; + v->SendMessage(WM_MOUSEMOVE, 0, lParam); + + return 0; + } + + + } + + + return 0; + break; + + + } + + return 0; + break; + + + } + } + + } + + } + + return CWinApp::ProcessMessageFilter(code, lpMsg); +} + +LRESULT CFinalSunApp::ProcessWndProcException(CException* e, const MSG* pMsg) +{ + // TODO: Speziellen Code hier einfĂ¼gen und/oder Basisklasse aufrufen + e->ReportError(MB_YESNO); + + return TRUE; + //return CWinApp::ProcessWndProcException(e, pMsg); +} + +BOOL CFinalSunApp::PreTranslateMessage(MSG* pMsg) +{ + + if (!TranslateAccelerator( + *this->m_pMainWnd, // handle to receiving window + m_hAccel, // handle to active accelerator table + pMsg)) // message data + + return CWinApp::PreTranslateMessage(pMsg); + + return FALSE; +} + + + +BOOL CFinalSunApp::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) +{ + + return CWinApp::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); +} + +BOOL CFinalSunApp::OnIdle(LONG lCount) +{ + ((CFinalSunDlg*)m_pMainWnd)->m_view.m_isoview->UpdateWindow(); + //MessageBox(0,"Idled","",0); + return CWinApp::OnIdle(lCount); +} diff --git a/MissionEditor/FinalSun.h b/MissionEditor/FinalSun.h new file mode 100644 index 0000000..e3dc5c4 --- /dev/null +++ b/MissionEditor/FinalSun.h @@ -0,0 +1,132 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// +// Main header file +// + +#if !defined(AFX_TIBERIANSUNMISSIONEDITOR_H__9F773422_63BB_11D3_99E0_C30F10710B17__INCLUDED_) +#define AFX_TIBERIANSUNMISSIONEDITOR_H__9F773422_63BB_11D3_99E0_C30F10710B17__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols +#include "ddeml.h" +#include "loading.h" + +struct OPTIONS{ + CString TSExe; + CString LanguageName; + CString prev_maps[4]; + bool bPreferLocalTheaterFiles = true; + BOOL bFlat; + BOOL bEasy; + BOOL bMarbleMadness; + BOOL bSupportMarbleMadness; + BOOL bShowCells; + BOOL bDoNotLoadBuildingGraphics; + BOOL bDoNotLoadInfantryGraphics; + BOOL bDoNotLoadAircraftGraphics; + BOOL bDoNotLoadTreeGraphics; + BOOL bDoNotLoadSnowGraphics; + BOOL bDoNotLoadTemperateGraphics; + BOOL bDoNotLoadVehicleGraphics; + BOOL bDoNotLoadBMPs; + BOOL bDoNotLoadOverlayGraphics; + BOOL bDisableAutoShore; + BOOL bDisableAutoLat; + BOOL bNoSounds; + BOOL bDisableSlopeCorrection; + float fMiniMapScale = 2.0f; + float fLoadScreenDelayInSeconds = 3.5f; + bool bShowStats = false; + bool bHighResUI = true; + bool bVSync = false; + std::vector<float> viewScaleSteps = { 0.75f, 0.5f, 0.25f }; + bool viewScaleUseSteps = true; + float viewScaleSpeed = 15.0f; + bool useDefaultMouseCursor = false; + +public: + BOOL bSearchLikeTS; +}; + + +///////////////////////////////////////////////////////////////////////////// +// CFinalSunApp: +// Look at FinalSun.cpp for the implementation of this class +// + +class CFinalSunApp : public CWinApp +{ +public: + DWORD pidInst; + OPTIONS m_Options; + CLoading* m_loading; + CFinalSunApp(); + + const std::string& getLogFileName() const + { + return m_u8LogFileName; + } + + +// Ăœberladungen + // Vom Klassenassistenten generierte Ăœberladungen virtueller Funktionen + //{{AFX_VIRTUAL(CFinalSunApp) + public: + virtual BOOL InitInstance(); + virtual int Run(); + virtual BOOL ProcessMessageFilter(int code, LPMSG lpMsg); + virtual LRESULT ProcessWndProcException(CException* e, const MSG* pMsg); + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo); + virtual BOOL OnIdle(LONG lCount); + //}}AFX_VIRTUAL + +// Implementierung + + //{{AFX_MSG(CFinalSunApp) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + public: + UINT m_cf; + HACCEL m_hAccel; + void ParseCommandLine(); + void ShowTipAtStartup(void); + void ShowTipOfTheDay(void); + +private: + std::string m_u8LogFileName; +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // !defined(AFX_TIBERIANSUNMISSIONEDITOR_H__9F773422_63BB_11D3_99E0_C30F10710B17__INCLUDED_) diff --git a/MissionEditor/FinalSunDlg.cpp b/MissionEditor/FinalSunDlg.cpp new file mode 100644 index 0000000..355c661 --- /dev/null +++ b/MissionEditor/FinalSunDlg.cpp @@ -0,0 +1,4135 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// +// Main dialog implementation +// + +#include "stdafx.h" +#include "structs.h" +#include "FinalSun.h" +#include "FinalSunDlg.h" +#include "tsoptions.h" +#include "info.h" +#include "loading.h" +#include "MapOpenDialog.h" +//#include "NewMap->h" +#include "newmapcreatedlg.h" +#include "newmapcreatenewdlg.h" +#include "newmapimportdlg.h" +#include "newmapspdlg.h" +#include "newmaptypedlg.h" +#include "MapValidator.h" +#include "ShutDownDlg.h" +#include "SavingDlg.h" +#include "functions.h" +#include "mapdata.h" +#include "variables.h" +#include "GlobalsDlg.h" +#include "savemapoptionsdlg.h" +#include "MissionEditorPackLib.h" +#include "bitmap2mapconverter.h" +#include "multisaveoptionsdlg.h" +#include "mmxsavingoptionsdlg.h" +#include <afxinet.h> +#include "inlines.h" +#include "MapCode.h" +#include "SearchWaypointDlg.h" +#include "userscriptsdlg.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <io.h> +#include <stdio.h> + +extern ACTIONDATA AD; +extern BOOL bNoDraw; + +extern char AppPath[MAX_PATH + 1]; +extern const std::string u8AppDataPath; +extern BOOL bMiniMapClosedByUser; + +HCURSOR m_hArrowCursor = NULL; + +static UINT indicators[] = +{ + ID_SEPARATOR, // Sstatus bar + ID_INDICATOR_CAPS, + ID_INDICATOR_NUM, + ID_INDICATOR_SCRL, +}; + + + +#define ID_STATBAR 26111 + +///////////////////////////////////////////////////////////////////////////// +// CFinalSunDlg Dialogfeld + +CFinalSunDlg::CFinalSunDlg(CWnd* pParent /*=NULL*/) + : CDialog(CFinalSunDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CFinalSunDlg) + // HINWEIS: Der Klassenassistent fĂ¼gt hier Member-Initialisierung ein + //}}AFX_DATA_INIT + // Beachten Sie, dass LoadIcon unter Win32 keinen nachfolgenden DestroyIcon-Aufruf benötigt + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + m_hGameCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_EDITOR_ARROW)); + m_hArrowCursor = m_hGameCursor; + +} + +void CFinalSunDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CFinalSunDlg) + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CFinalSunDlg, CDialog) + //{{AFX_MSG_MAP(CFinalSunDlg) + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_COMMAND(ID_FILE_QUIT, OnFileQuit) + ON_WM_SYSCOMMAND() + ON_COMMAND(ID_OPTIONS_TIBERIANSUNOPTIONS, OnOptionsTiberiansunoptions) + ON_COMMAND(ID_FILE_OPENMAP, OnFileOpenmap) + ON_COMMAND(ID_FILE_SAVEAS, OnFileSaveas) + ON_COMMAND(ID_OPTIONS_EXPORTRULESINI, OnOptionsExportrulesini) + ON_COMMAND(ID_HELP_INFO, OnHelpInfo) + ON_WM_SHOWWINDOW() + ON_COMMAND(ID_FILE_SAVE, OnFileSave) + ON_WM_MENUSELECT() + ON_COMMAND(ID_FILE_RUNTIBERIANSUN, OnFileRuntiberiansun) + ON_COMMAND(ID_FILE_IMPORTMOD, OnFileImportmod) + ON_COMMAND(ID_DEBUG_EXPORTMAPPACKNOSECTIONS, OnDebugExportmappacknosections) + ON_COMMAND(ID_DEBUG_EXPORTMAPPACK, OnDebugExportmappack) + ON_COMMAND(ID_FILE_NEW, OnFileNew) + ON_COMMAND(ID_HELP_TIPOFTHEDAY, OnHelpTipoftheday) + ON_COMMAND(ID_OPTIONS_SIMPLEVIEW, OnOptionsSimpleview) + ON_COMMAND(ID_OPTIONS_SHOWMINIMAP, OnOptionsShowminimap) + ON_COMMAND(ID_FILE_VALIDATEMAP, OnFileValidatemap) + ON_WM_ENTERIDLE() + ON_COMMAND(ID_EDIT_BASICSETTINGS, OnEditBasicsettings) + ON_COMMAND(ID_EDIT_SINGLEPLAYERSETTINGS, OnEditSingleplayersettings) + ON_WM_SIZING() + ON_WM_SIZE() + ON_COMMAND(ID_EDIT_HOUSES, OnEditHouses) + ON_COMMAND(ID_EDIT_AITRIGGERS, OnEditAitriggers) + ON_COMMAND(ID_EDIT_AITRIGGERENABLING, OnEditAitriggerenabling) + ON_COMMAND(ID_EDIT_INIEDITING, OnEditIniediting) + ON_COMMAND(ID_EDIT_LIGHTING, OnEditLighting) + ON_COMMAND(ID_EDIT_MAP, OnEditMap) + ON_COMMAND(ID_EDIT_SCRIPTS, OnEditScripts) + ON_COMMAND(ID_EDIT_SPECIALFLAGS, OnEditSpecialflags) + ON_COMMAND(ID_EDIT_TAGS, OnEditTags) + ON_COMMAND(ID_EDIT_TASKFORCES, OnEditTaskforces) + ON_COMMAND(ID_EDIT_TEAMS, OnEditTeams) + ON_COMMAND(ID_EDIT_TRIGGERS, OnEditTriggers) + ON_WM_SETFOCUS() + ON_COMMAND(ID_TERRAIN_HEIGHTENGROUND, OnTerrainHeightenground) + ON_COMMAND(ID_TERRAIN_LOWERGROUND, OnTerrainLowerground) + ON_COMMAND(ID_TERRAIN_LOWERTILE, OnTerrainLowertile) + ON_COMMAND(ID_TERRAIN_RAISETILE, OnTerrainRaisetile) + ON_COMMAND(ID_TERRAIN_FLATTEN, OnTerrainFlatten) + ON_COMMAND(ID_TERRAIN_CLOAK, OnTerrainCloak) + ON_COMMAND(ID_TERRAIN_SHOWEVERYTILE, OnTerrainShoweverytile) + ON_COMMAND(ID_TERRAIN_SHOWALLFIELDS, OnTerrainShowallfields) + ON_COMMAND(ID_TERRAIN_HIDEFIELD, OnTerrainHidefield) + ON_COMMAND(ID_EDIT_TRIGGEREDITOR, OnEditTriggereditor) + ON_WM_KEYDOWN() + ON_COMMAND(ID_MAPTOOLS_CHANGEMAPHEIGHT, OnMaptoolsChangemapheight) + ON_COMMAND(ID_EDIT_GLOBALVARIABLES, OnEditGlobalvariables) + ON_COMMAND(ID_EDIT_UNDO, OnEditUndo) + ON_COMMAND(ID_HELP, OnHelpManual) + ON_COMMAND(ID_HELP_SHOWLOGS, &CFinalSunDlg::OnHelpShowlogs) + ON_COMMAND(ID_MAPTOOLS_AUTOLEVEL, OnMaptoolsAutolevel) + ON_UPDATE_COMMAND_UI(ID_EDIT_AITRIGGERENABLING, OnUpdateEditAitriggerenabling) + ON_UPDATE_COMMAND_UI(ID_EDIT_AITRIGGERS, OnUpdateEditAitriggers) + ON_UPDATE_COMMAND_UI(ID_EDIT_BASICSETTINGS, OnUpdateEditBasicsettings) + ON_UPDATE_COMMAND_UI(ID_EDIT_GLOBALVARIABLES, OnUpdateEditGlobalvariables) + ON_UPDATE_COMMAND_UI(ID_EDIT_HOUSES, OnUpdateEditHouses) + ON_UPDATE_COMMAND_UI(ID_EDIT_INIEDITING, OnUpdateEditIniediting) + ON_UPDATE_COMMAND_UI(ID_EDIT_LIGHTING, OnUpdateEditLighting) + ON_UPDATE_COMMAND_UI(ID_EDIT_MAP, OnUpdateEditMap) + ON_UPDATE_COMMAND_UI(ID_EDIT_SCRIPTS, OnUpdateEditScripts) + ON_UPDATE_COMMAND_UI(ID_EDIT_SINGLEPLAYERSETTINGS, OnUpdateEditSingleplayersettings) + ON_UPDATE_COMMAND_UI(ID_EDIT_SPECIALFLAGS, OnUpdateEditSpecialflags) + ON_UPDATE_COMMAND_UI(ID_EDIT_TAGS, OnUpdateEditTags) + ON_UPDATE_COMMAND_UI(ID_EDIT_TASKFORCES, OnUpdateEditTaskforces) + ON_UPDATE_COMMAND_UI(ID_EDIT_TEAMS, OnUpdateEditTeams) + ON_UPDATE_COMMAND_UI(ID_EDIT_TRIGGEREDITOR, OnUpdateEditTriggereditor) + ON_UPDATE_COMMAND_UI(ID_EDIT_TRIGGERS, OnUpdateEditTriggers) + ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVEAS, OnUpdateFileSaveas) + ON_UPDATE_COMMAND_UI(ID_FILE_VALIDATEMAP, OnUpdateFileValidatemap) + ON_UPDATE_COMMAND_UI(ID_MAPTOOLS_AUTOLEVEL, OnUpdateMaptoolsAutolevel) + ON_UPDATE_COMMAND_UI(ID_MAPTOOLS_CHANGEMAPHEIGHT, OnUpdateMaptoolsChangemapheight) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SHOWMINIMAP, OnUpdateOptionsShowminimap) + ON_UPDATE_COMMAND_UI(ID_TERRAIN_CLOAK, OnUpdateTerrainCloak) + ON_UPDATE_COMMAND_UI(ID_TERRAIN_FLATTEN, OnUpdateTerrainFlatten) + ON_UPDATE_COMMAND_UI(ID_TERRAIN_HEIGHTENGROUND, OnUpdateTerrainHeightenground) + ON_UPDATE_COMMAND_UI(ID_TERRAIN_HIDEFIELD, OnUpdateTerrainHidefield) + ON_UPDATE_COMMAND_UI(ID_TERRAIN_LOWERGROUND, OnUpdateTerrainLowerground) + ON_UPDATE_COMMAND_UI(ID_TERRAIN_LOWERTILE, OnUpdateTerrainLowertile) + ON_UPDATE_COMMAND_UI(ID_TERRAIN_RAISETILE, OnUpdateTerrainRaisetile) + ON_UPDATE_COMMAND_UI(ID_TERRAIN_SHOWALLFIELDS, OnUpdateTerrainShowallfields) + ON_UPDATE_COMMAND_UI(ID_TERRAIN_SHOWEVERYTILE, OnUpdateTerrainShoweverytile) + ON_COMMAND(ID_MAPTOOLS_FRONTCLIFF, OnMaptoolsFrontcliff) + ON_COMMAND(ID_MAPTOOLS_BACKCLIFF, OnMaptoolsBackcliff) + ON_COMMAND(ID_EDIT_REDO, OnEditRedo) + ON_COMMAND(ID_MAPTOOLS_AUTOCREATESHORES, OnMaptoolsAutocreateshores) + ON_COMMAND(ID_OPTIONS_DISABLEAUTOSHORE, OnOptionsDisableautoshore) + ON_COMMAND(ID_OPTIONS_DISABLEAUTOLAT, OnOptionsDisableautolat) + ON_COMMAND(ID_EDIT_PASTE, OnEditPaste) + ON_COMMAND(ID_EDIT_COPY, OnEditCopy) + ON_COMMAND(ID_EDIT_COPYWHOLEMAP, OnEditCopywholemap) + ON_COMMAND(ID_EDIT_PASTEWHOLEMAP, OnEditPastewholemap) + ON_COMMAND(ID_MARBLEMADNESS, OnMarblemadness) + ON_COMMAND(ID_OPTIONS_SOUNDS, OnOptionsSounds) + ON_UPDATE_COMMAND_UI(ID_OPTIONS_SOUNDS, OnUpdateOptionsSounds) + ON_COMMAND(ID_OPTIONS_DISABLESLOPECORRECTION, OnOptionsDisableslopecorrection) + ON_COMMAND(ID_OPTIONS_SHOWBUILDINGOUTLINE, OnOptionsShowbuildingoutline) + ON_COMMAND(ID_FILE_FILE1, OnFileFile1) + ON_COMMAND(ID_FILE_FILE2, OnFileFile2) + ON_COMMAND(ID_FILE_FILE3, OnFileFile3) + ON_COMMAND(ID_FILE_FILE4, OnFileFile4) + ON_COMMAND(ID_MAPTOOLS_SEARCHWAYPOINT, OnMaptoolsSearchwaypoint) + ON_COMMAND(ID_MAPTOOLS_TOOLSCRIPTS, OnMaptoolsToolscripts) + //}}AFX_MSG_MAP + ON_COMMAND(ID_OPTIONS_SMOOTHZOOM, &CFinalSunDlg::OnOptionsSmoothzoom) + ON_WM_SETCURSOR() + ON_COMMAND(ID_OPTIONS_USEDEFAULTMOUSECURSOR, &CFinalSunDlg::OnOptionsUsedefaultmousecursor) + END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CFinalSunDlg message handler + +BOOL CFinalSunDlg::OnInitDialog() +{ + + CDialog::OnInitDialog(); + + m_hArrowCursor = theApp.m_Options.useDefaultMouseCursor ? LoadCursor(NULL, IDC_ARROW) : m_hGameCursor; + + errstream << "CFinalSunDlg::OnInitDialog() called" << endl; + errstream.flush(); + + ShowWindow(SW_HIDE); + SetWindowPos(NULL, 0, 0, GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN), 0); + + SetIcon(m_hIcon, TRUE); // use big symbol + SetIcon(m_hIcon, FALSE); // use small symbol + + CString cap; +#ifndef RA2_MODE + cap= GetLanguageStringACP("MainDialogCaption"); +#else + cap=GetLanguageStringACP("MainDialogCaptionRA2"); +#endif + + cap+=" ("; + cap+=GetLanguageStringACP("NoMapLoaded"); + cap+=")"; + SetWindowText(cap); + + + // Matze: + // July 9th: + // Added toolbars + + BOOL success=true; + RECT r; + SIZE size_mainbar; + SIZE size_terrainbar; + GetClientRect(&r); + r.top+=32; + success = success && m_view.Create(NULL, GetLanguageStringACP("IsoCaption"), WS_CHILD, r, this); + + r.top=0; + r.bottom=32; + success = success && m_bar.Create(RBS_AUTOSIZE, r, this, 5000); + success = success && m_maintoolbar.Create(this); + success = success && m_maintoolbar.LoadToolBar(IDR_MAINFRAME); + m_maintoolbar.GetToolBarCtrl().SetStyle(m_maintoolbar.GetToolBarCtrl().GetStyle() | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS); + success = success && m_maintoolbar.GetToolBarCtrl().GetMaxSize(&size_mainbar); + success = success && m_terraintoolbar.Create(this); + success = success && m_terraintoolbar.LoadToolBar(IDR_TERRAINBAR); + m_terraintoolbar.GetToolBarCtrl().SetStyle(m_terraintoolbar.GetToolBarCtrl().GetStyle() | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS ); + success = success && m_terraintoolbar.GetToolBarCtrl().GetMaxSize(&size_terrainbar); + m_terraintoolbar.SetBarStyle(m_terraintoolbar.GetBarStyle()); + success = success && m_clifftoolbar.Create(this); + success = success && m_clifftoolbar.LoadToolBar(IDR_CLIFFBAR); + m_clifftoolbar.GetToolBarCtrl().SetStyle(m_clifftoolbar.GetToolBarCtrl().GetStyle() | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS ); + m_clifftoolbar.SetBarStyle(m_terraintoolbar.GetBarStyle()); + + success = success && m_settingsbar.Create(this, IDD_TOOLSETTINGS, CBRS_TOP, 6000); + + REBARBANDINFO rbi = { 0 }; + rbi.cbSize= sizeof(REBARBANDINFO); + rbi.fMask= RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_TEXT /*| RBBIM_SIZE*/ | RBBIM_IDEALSIZE; + rbi.fStyle= RBBS_GRIPPERALWAYS; + rbi.cxMinChild= size_mainbar.cx+30; + rbi.cyMinChild= 30; + rbi.cch= 0; + rbi.cx= size_mainbar.cx+30; + rbi.cxIdeal=size_mainbar.cx+30; + rbi.hbmBack= NULL; + rbi.hwndChild= (HWND)m_maintoolbar; + success = success && m_bar.InsertBand(0, &rbi); + rbi.hwndChild= (HWND)m_terraintoolbar; + rbi.cx=size_terrainbar.cx+30; + rbi.cxIdeal=size_terrainbar.cx+30; + rbi.cxMinChild= size_terrainbar.cx+30; + success = success && m_bar.InsertBand(1, &rbi); + rbi.hwndChild = (HWND)m_clifftoolbar; + rbi.cx = 560; + rbi.cxMinChild = 170; + rbi.cxIdeal = 560; + success = success && m_bar.InsertBand(2, &rbi); + rbi.hwndChild= (HWND)m_settingsbar; + rbi.cxMinChild= 170; + rbi.cx=170; + rbi.cxIdeal=170; + success = success && m_bar.InsertBand(3, &rbi); + + + m_bar.ShowWindow(SW_SHOW); + m_maintoolbar.ShowWindow(SW_SHOW); + m_terraintoolbar.ShowWindow(SW_SHOW); + m_settingsbar.ShowWindow(SW_SHOW); + + m_bar.MinimizeBand(0); + m_bar.MaximizeBand(3); + + + + if(!success) + { + // sometimes, insufficient resources are available. + // this is a very rare case - but it happened on Win9x + // especially when running the developer studio and IE5, this happens often + // 04/02/2000: Should not anymore occur. + MessageBox(GetLanguageStringACP("Err_InsufficientResources")); + exit(-5); + } + + + errstream << "Updating menu" << endl; + errstream.flush(); + + if(theApp.m_Options.bEasy && GetMenu()) GetMenu()->CheckMenuItem(ID_OPTIONS_SIMPLEVIEW, MF_BYCOMMAND | MF_CHECKED); + + UpdateStrings(); + + + + + // Matze: + // June 21, CLoading now non-modal. + // CLoading will free itself + // September 6th, CLoading will not free itself as it is a member of CFinalSunApp + if(theApp.m_loading->m_hWnd ==NULL) + { + MessageBox("Loading dialog could not be created. Please close any programs and start again."); + exit(-99); + } + theApp.m_loading->ShowWindow(SW_SHOW); + theApp.m_loading->UpdateWindow(); + theApp.m_loading->Load(); + + if(!theApp.m_Options.bSupportMarbleMadness) + { + TBBUTTON b; + m_terraintoolbar.GetToolBarCtrl().GetButton(9, &b); + + m_terraintoolbar.GetToolBarCtrl().HideButton(b.idCommand); + m_terraintoolbar.GetToolBarCtrl().HideButton(ID_MARBLEMADNESS); + } + + ShowWindow(SW_SHOWMAXIMIZED); + CDialog::BringWindowToTop(); + + if(strlen(currentMapFile)==0) // no map file specified + { + // ok, let the user choose a map! + // hmm... no, don´t let him. we already have our tips dialog. + // OnFileOpenmap(); + + theApp.ShowTipAtStartup(); + } + else // yah, map file specified + { + CString str = GetLanguageStringACP("MainDialogCaption"); + str+=" ("; + str+=currentMapFile; + str+=")"; + + this->SetWindowText(str); + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + Map->LoadMap(currentMapFile); + + SetCursor(m_hArrowCursor); + + } + + UpdateDialogs(); + +#ifndef RA2_MODE + CTime t=t.GetCurrentTime(); + + if(t.GetDay()>=24 && t.GetDay()<=26 && t.GetMonth()==12) + { + CString str; + GetWindowText(str); + + SetWindowText(str+" Merry Christmas! Fröhliche Weihnachten!"); + + } +#endif + + + return TRUE; +} + +void CFinalSunDlg::OnPaint() +{ + + if (IsIconic()) + { + CPaintDC dc(this); // DC for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // center symbol + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // draw symbol + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } + + +} + +HCURSOR CFinalSunDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +void CFinalSunDlg::OnFileQuit() +{ + UnloadAll(); +} + + +void CFinalSunDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if(nID==SC_CLOSE) + { + UnloadAll(); + return; + } + CDialog::OnSysCommand(nID, lParam); +} + + + +void CFinalSunDlg::OnOK() +{ + //just do nothing... + // this is a stub +} + +void CFinalSunDlg::OnCancel() +{ + //do nothing... + // stub +} + +void CFinalSunDlg::OnOptionsTiberiansunoptions() +{ + + ShowOptionsDialog(); + +} + +void CFinalSunDlg::OnFileOpenmap() +{ + + //CMapOpenDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST, "TS maps|*.mpr;*.map|TS multi maps|*.mpr|TS single maps|*.map|"); + CString r=GetLanguageStringACP("SAVEDLG_FILETYPES"); + if(yuri_mode) + { + r=GetLanguageStringACP("SAVEDLG_FILETYPES_YR"); + } + r=TranslateStringVariables(8, r, ";"); + + if(!yuri_mode) r.Replace(".yrm",".mpr"); + + CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST, r); + + char cuPath[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, cuPath); + dlg.m_ofn.lpstrInitialDir=cuPath; + + if(theApp.m_Options.TSExe.GetLength()) dlg.m_ofn.lpstrInitialDir=(char*)(LPCTSTR)theApp.m_Options.TSExe; + + + if(dlg.DoModal()==IDCANCEL) return; + + m_PKTHeader.Clear(); + + CString fileToOpen=dlg.GetPathName(); + fileToOpen.MakeLower(); + CString ext=dlg.GetFileExt(); + ext.MakeLower(); + BOOL bLoadedFromMMX=FALSE; + if(ext=="mmx") + { + HMIXFILE hMix=FSunPackLib::XCC_OpenMix(fileToOpen, NULL); + fileToOpen.Replace(".mmx", ".map"); + + if(fileToOpen.ReverseFind('\\')>=0) fileToOpen=fileToOpen.Right(fileToOpen.GetLength()-fileToOpen.ReverseFind('\\')-1); + + CString extractFile=u8AppDataPath.c_str(); + CString pktFile=fileToOpen; + pktFile.Replace(".map", ".pkt"); + extractFile+="\\mmx_tmp.pkt"; + + FSunPackLib::XCC_ExtractFile(pktFile, extractFile, hMix); + m_PKTHeader.LoadFile(extractFile, TRUE); + fileToOpen=m_PKTHeader.sections["MultiMaps"].values["1"]+".map"; + + + + extractFile=u8AppDataPath.c_str(); + extractFile+="\\mmx_tmp.map"; + FSunPackLib::XCC_ExtractFile(fileToOpen, extractFile, hMix); + fileToOpen=extractFile; + + + + FSunPackLib::XCC_CloseMix(hMix); + bLoadedFromMMX=TRUE; + } + + CIniFile f; + f.InsertFile(fileToOpen, "Map"); + if((f.sections["Map"].values["Theater"]==THEATER0 && theApp.m_Options.bDoNotLoadTemperateGraphics) || (f.sections["Map"].values["Theater"]==THEATER1 && theApp.m_Options.bDoNotLoadSnowGraphics)) + { + MessageBox("You have selected to don´t show temperate or snow theater, but this map uses this theater. You cannot load it without restarting FinalSun/FinalAlert 2 with this theater enabled.", "Error"); + return; + } + + bNoDraw=TRUE; + + CString str; + str = GetLanguageStringACP("MainDialogCaption"); + str+=" ("; + str+=(char*)(LPCTSTR)dlg.GetPathName(); + str+=")"; + + // MW 07/20/01: Update prev. files + InsertPrevFile(dlg.GetPathName()); + + this->SetWindowText(str); + + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + errstream << "Map->LoadMap() will be called" << endl; + errstream.flush(); + + + + Map->LoadMap((char*)(LPCTSTR)fileToOpen); + + + BOOL bNoMapFile=FALSE; + if(!Map->CheckMapPackData()) + { + int res=MessageBox("This map seems to be corrupt. Do you want to try repairing it? If you click cancel, a empty map will be created, if you click no, it will load the map as it is","Corrupt", MB_YESNOCANCEL); + if(res==IDCANCEL) + { + Map->CreateMap(32,32,THEATER0,0); + bNoMapFile=TRUE; + } + else + { + if(res==IDYES) // try repair + { + int fielddata_size=Map->GetIsoSize()*Map->GetIsoSize(); + + int i; + for(i=0;i<fielddata_size;i++) + { + int gr=Map->GetFielddataAt(i)->wGround; + if(gr==0xFFFF) gr=0; + + if(gr>=(*tiledata_count)) + { + Map->SetTileAt(i, 0, 0); + } + else + { + if((*tiledata)[gr].wTileCount<=Map->GetFielddataAt(i)->bSubTile) + { + Map->SetTileAt(i, 0, 0); + } + } + } + + } + } + } + + if(!bNoMapFile) + { + if(bLoadedFromMMX) + { + //currentMapFile[0]=0; + strcpy(currentMapFile, dlg.GetPathName()); + } + else + strcpy(currentMapFile, fileToOpen); + } + + Sleep(200); + + SetCursor(m_hArrowCursor); + + + bNoDraw=FALSE; + + m_view.m_isoview->UpdateDialog(TRUE); + UpdateDialogs(); +} + +void CFinalSunDlg::UpdateDialogs(BOOL bOnlyMissionControl, BOOL bNoRepos) +{ + RepairRulesHouses(); + + OutputDebugString("Dialogs updated\n"); + + if(m_basic.m_hWnd) m_basic.UpdateDialog(); + if(m_all.m_hWnd) m_all.UpdateDialog(); + if(m_map.m_hWnd) m_map.UpdateDialog(); + if(m_lighting.m_hWnd) m_lighting.UpdateDialog(); + if(m_specialflags.m_hWnd) m_specialflags.UpdateDialog(); + if(m_teamtypes.m_hWnd) m_teamtypes.UpdateDialog(); + if(m_houses.m_hWnd) m_houses.UpdateDialog(); + if(m_taskforces.m_hWnd) m_taskforces.UpdateDialog(); + if(m_Scripttypes.m_hWnd) m_Scripttypes.UpdateDialog(); + if(m_triggers.m_hWnd) m_triggers.UpdateDialog(); + if(m_triggereditor.m_hWnd) m_triggereditor.UpdateDialog(); + if(m_tags.m_hWnd) m_tags.UpdateDialog(); + if(m_aitriggertypesenable.m_hWnd) m_aitriggertypesenable.UpdateDialog(); + if(m_aitriggertypes.m_hWnd) m_aitriggertypes.UpdateDialog(); + if(m_singleplayersettings.m_hWnd) m_singleplayersettings.UpdateDialog(); + + CIniFile& ini=Map->GetIniFile(); + if(ini.sections.find(MAPHOUSES)!=ini.sections.end() && ini.sections[MAPHOUSES].values.size()>0) + { + if(ini.sections[MAPHOUSES].FindValue("Neutral")>=0) + currentOwner="Neutral"; + else + currentOwner=*ini.sections[MAPHOUSES].GetValue(0); + } + else + currentOwner="Neutral";//*rules.sections[HOUSES].GetValue(0); + + if(!bOnlyMissionControl) + { + UpdateWindow(); + UpdateStrings(); + + + + m_view.m_isoview->UpdateDialog(!bNoRepos); + m_view.m_objectview->UpdateDialog(); + m_view.m_minimap.UpdateView(); + + if(tiles!=NULL && tiledata!=NULL && tiledata_count!=NULL) + m_view.m_browser->m_bar.Update(); + } + + AD.reset(); +} + +void CFinalSunDlg::OnFileSaveas() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + CMapValidator validator; + int iCancel=validator.DoModal(); + if(iCancel==IDCANCEL) return; + CString r=GetLanguageStringACP("SAVEDLG_FILETYPES"); + if(yuri_mode) + { + r=GetLanguageStringACP("SAVEDLG_FILETYPES_YR"); + } + r=TranslateStringVariables(8, r, ";"); + + CString ext, fname; + if(Map->IsMultiplayer()) + { + ext=".mpr"; + fname="noname.mpr"; + + // MW 07/27/01: YRM support + //if(Map->IsYRMap()) + // MW Fix: Usually always YRM in Yuri Mode, + // because YR does NOT read MPR + if(yuri_mode) + { + ext=".yrm"; + fname="noname.yrm"; + } + } + else{ + ext=".map"; + fname="noname.map"; + } + + CFileDialog dlg(FALSE, ext, /*fname*/ NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, r); + char cuPath[MAX_PATH]; + + GetCurrentDirectory(MAX_PATH, cuPath); + dlg.m_ofn.lpstrInitialDir=cuPath; + + + + if(theApp.m_Options.TSExe.GetLength()) dlg.m_ofn.lpstrInitialDir=(char*)(LPCTSTR)theApp.m_Options.TSExe; + + if(dlg.DoModal()!=IDCANCEL) + { + strcpy(currentMapFile, dlg.GetPathName()); + + CString str=GetLanguageStringACP("MainDialogCaption"); + str+=" ("; + str+=(char*)(LPCTSTR)dlg.GetPathName(); + str+=")"; + + this->SetWindowText(str); + + SaveMap(dlg.GetPathName()); + } + + + + SetCursor(m_hArrowCursor); + +} + +void CFinalSunDlg::OnOptionsExportrulesini() +{ + int res=MessageBox("This will export the Rules.Ini of Tiberian Sun V1.13 MMX. ou should not modify this rules.ini because you won´t be able to play online then and ecause this could cause compatibility problems.\nIf you want to modify the rules.ini, you need to rename it before you play online.", "Export Rules.INI", MB_OK); + + CFileDialog dlg(FALSE, ".ini", "rules.ini", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Rules.INI|rules.ini|"); + + char cuPath[MAX_PATH]; + BOOL hidePreview=FALSE; + BOOL previewPrinted=FALSE; + GetCurrentDirectory(MAX_PATH, cuPath); + dlg.m_ofn.lpstrInitialDir=cuPath; + + if(theApp.m_Options.TSExe.GetLength()) dlg.m_ofn.lpstrInitialDir=(char*)(LPCTSTR)theApp.m_Options.TSExe; + + if(dlg.DoModal()!=IDCANCEL) + { + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + HRSRC r; + r=FindResource(NULL, MAKEINTRESOURCE(IDR_RULES) ,"TEXTFILE"); + + if(r==0) {MessageBox("FindResource() failed to find IDR_RULES", "DEBUG");return;} + + HGLOBAL hres=LoadResource(NULL, r); + + if(hres==0) {MessageBox("LoadResource() failed to load IDR_RULES", "DEBUG");return;} + + char* data=(char*)LockResource(hres); + + int hfile=_open((char*)(LPCTSTR)dlg.GetPathName(),_O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE); + + if(hfile==-1) { MessageBox("File could not be opened","DEBUG"); return; } + + _write(hfile, (void*) data, strlen(data)); + + _close(hfile); + + SetCursor(m_hArrowCursor); + + } +} + +void CFinalSunDlg::OnHelpInfo() +{ + // handle the help dialog + CInfo info; + info.DoModal(); +} + + +void CFinalSunDlg::OnShowWindow(BOOL bShow, UINT nStatus) +{ + CDialog::OnShowWindow(bShow, nStatus); + + m_view.ShowWindow(SW_SHOW); + + if(!bShow) return; + + + +} + + + + +void CFinalSunDlg::OnFileSave() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + if(strlen(currentMapFile)==0) { OnFileSaveas(); return; } + + CMapValidator validator; + int iCancel=validator.DoModal(); + if(iCancel==IDCANCEL) return; + + SaveMap(currentMapFile); +} + + + + +void CFinalSunDlg::SaveMap(CString FileName_) +{ + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + errstream << "SaveMap() called" << endl; + errstream.flush(); + + BOOL bSaveAsMMX=FALSE; + BOOL hidePreview=FALSE; + BOOL previewPrinted=FALSE; + + + + FileName_.MakeLower(); + FileName_=(LPCSTR)FileName_; // GetLength() needs to return proper size + + + CString CoreName=FileName_; + CString Description; + int minplayers; + int maxplayers; + BOOL standard; + BOOL meatgrind; + BOOL navalwar; + BOOL nukewar; + BOOL airwar; + BOOL megawealth; + BOOL duel; + BOOL cooperative; + // MW Apr 17th, 2002: Added Teamgame! + BOOL teamgame; + + if(CoreName.ReverseFind('\\')>=0) CoreName=CoreName.Right(CoreName.GetLength()-CoreName.ReverseFind('\\')-1); + if(CoreName.Find(".")>=0) CoreName=CoreName.Left(CoreName.Find(".")); + + + + +#ifdef RA2_MODE + if(Map->IsMultiplayer()) + { + if(FileName_.Find(".mmx")>=0) bSaveAsMMX=TRUE; else bSaveAsMMX=FALSE; + if(FileName_.Find(".map")>=0) FileName_.Replace(".map",".mpr"); + + // MW 07/27/01: Check for YRM + if(FileName_.Find(".mpr")>=0 && Map->IsYRMap()) FileName_.Replace(".mpr",".yrm"); + + + // MW 07/28/01: Create [Header] + int i; + int wp_count=0; + int xw[8]={0,0,0,0,0,0,0,0}; + int yw[8]={0,0,0,0,0,0,0,0}; + for(i=0;i<Map->GetWaypointCount();i++) + { + CString id; + DWORD pos; + Map->GetWaypointData(i, &id, &pos); + int idi; + idi=atoi(id); + if(idi!=i) break; + if(idi>=0 && idi<8) + { + int x,y; + x=pos/Map->GetIsoSize(); + y=pos%Map->GetIsoSize(); + //PosToXY(pos, x,y); + xw[wp_count]=calcXPos(x,y); + yw[wp_count]=calcYPos(x,y); + wp_count++; + } + + } + char c[50]; + CIniFile& ini=Map->GetIniFile(); + CIniFileSection& sec=ini.sections["Header"]; + itoa(wp_count, c, 10); + sec.values["NumberStartingPoints"]=c; + for(i=0;i<8;i++) + { + CString s="Waypoint"; + itoa(i+1, c, 10); + s+=c; + itoa(xw[i], c, 10); + CString val=c; + val+=","; + itoa(yw[i], c, 10); + val+=c; + sec.values[s]=val; + } + + int startx, starty, width, height; + MC_GetHeaderRect(startx, starty, width, height); + + itoa(height, c, 10); + sec.values["Height"]=c; + itoa(width, c, 10); + sec.values["Width"]=c; + + //CIniFile& ini=Map->GetIniFile(); + + CString left=GetParam(ini.sections["Map"].values["LocalSize"], 0); + CString top=GetParam(ini.sections["Map"].values["LocalSize"], 1); + + //startx=1;//Map->GetHeight()/2;//atoi(left);//Map->GetIsoSize()/2-Map->GetWidth()/2;//198/2-50;//Map->GetIsoSize()/2-Map->GetHeight()/2;//Map->GetWidth()/2-50; + //starty=Map->GetWidth();//Map->GetIsoSize()/2-Map->GetWidth()/2;//198/2-50;//Map->GetIsoSize()/2-Map->GetWidth()/2;//Map->GetHeight()/2-50; + itoa(startx, c, 10); + sec.values["StartX"]=c; + itoa(starty, c, 10); + sec.values["StartY"]=c; + + /*CMultiSaveOptionsDlg mso; + + if(FileName.Find(".mmx")>=0) mso.m_mmx=0; else mso.m_mmx=1; + + if(mso.DoModal()==IDCANCEL) return; + + if(mso.m_mmx==0) + { + FileName.Replace(".mpr", ".map"); + //FileName.Replace(" ", ""); + if(CoreName.GetLength()>8) + { + CoreName=CoreName.Left(8); + FileName=CoreName+".map"; + + CString s="The maximum filename length for MMX files is 8 chars, do you want to save the map as "; + s+=CoreName; + s+=".mmx?"; + int res=MessageBox(s,"Error", MB_YESNO); + if(res!=IDYES) return; + } + + bSaveAsMMX=TRUE; + + } + else + { + FileName.Replace(".mmx", ".mpr"); + bSaveAsMMX=FALSE; + }*/ + } +#endif + + CString MMXFileName=CoreName; + MMXFileName+=".mmx"; + + CString PKTFileName=CoreName; + PKTFileName+=".pkt"; + + CString MAPFileName=CoreName; + MAPFileName+=".map"; + + DWORD dwFlags=MAPDATA_UPDATE_TO_INI_ALL; + + if(!bSaveAsMMX) + { + CSaveMapOptionsDlg opt; + + + CString gm=Map->GetIniFile().sections["Basic"].values["GameMode"]; + gm.MakeLower(); + if(gm.GetLength()) + { + opt.m_Standard=gm.Find("standard")>=0; + opt.m_AirWar=gm.Find("airwar")>=0; + opt.m_Cooperative=gm.Find("cooperative")>=0; + opt.m_Duel=gm.Find("duel")>=0; + opt.m_Navalwar=gm.Find("navalwar")>=0; + opt.m_Nukewar=gm.Find("nukewar")>=0; + opt.m_Meatgrind=gm.Find("meatgrind")>=0; + opt.m_Megawealth=gm.Find("megawealth")>=0; + opt.m_TeamGame=gm.Find("teamgame")>=0; + } + else + opt.m_Standard=TRUE; + + + if(opt.DoModal()==IDCANCEL) return; + + gm=""; + if(opt.m_Standard) gm+="standard, "; + if(opt.m_Meatgrind) gm+="meatgrind, "; + if(opt.m_Navalwar) gm+="navalwar, "; + if(opt.m_Nukewar) gm+="nukewar, "; + if(opt.m_AirWar) gm+="airwar, "; + if(opt.m_Megawealth) gm+="megawealth, "; + if(opt.m_Duel) gm+="duel, "; + if(opt.m_Cooperative) gm+="cooperative, "; + if(opt.m_TeamGame) gm+="teamgame, "; + + if(gm.ReverseFind(',')>=0) gm=gm.Left(gm.ReverseFind(',')); + + if(gm.GetLength()==0) gm="standard"; + + + Map->GetIniFile().sections["Basic"].values["Name"]=opt.m_MapName; + Map->GetIniFile().sections["Basic"].values["GameMode"]=gm; + + int i; + int count=0; + for(i=0;i<Map->GetWaypointCount();i++) + { + CString id; + DWORD pos; + Map->GetWaypointData(i, &id, &pos); + int idi; + idi=atoi(id); + if(idi!=i) break; + if(idi>=0 && idi<8) count++; + } + + if(count<2) count=2; + + Map->GetIniFile().sections["Basic"].values["MinPlayer"]="2"; + char c[50]; + itoa(count, c, 10); + Map->GetIniFile().sections["Basic"].values["MaxPlayer"]=c; + + if(opt.m_Compress==0) dwFlags|=MAPDATA_UPDATE_TO_INI_ALL_COMPRESSED; + if(opt.m_PreviewMode==0) dwFlags|=MAPDATA_UPDATE_TO_INI_ALL_PREVIEW; + if(opt.m_PreviewMode==2) hidePreview=TRUE; + } + else + { + CMMXSavingOptionsDlg opt; + + if(m_PKTHeader.sections.size()>0) // old pkt header exists + { + CIniFileSection& sec=m_PKTHeader.sections[m_PKTHeader.sections["MultiMaps"].values["1"]]; + if(sec.values["Description"].GetLength()>0) opt.m_Description=sec.values["Description"]; + opt.m_MinPlayers=atoi(sec.values["MinPlayers"])-2; + opt.m_Maxplayers=atoi(sec.values["MaxPlayers"])-2; + CString gm=sec.values["GameMode"]; + gm.MakeLower(); + opt.m_Standard=gm.Find("standard")>=0; + opt.m_AirWar=gm.Find("airwar")>=0; + opt.m_Cooperative=gm.Find("cooperative")>=0; + opt.m_Duel=gm.Find("duel")>=0; + opt.m_NavalWar=gm.Find("navalwar")>=0; + opt.m_NukeWar=gm.Find("nukewar")>=0; + opt.m_Meatgrind=gm.Find("meatgrind")>=0; + opt.m_MegaWealth=gm.Find("megawealth")>=0; + } + + if(opt.DoModal()==IDCANCEL) return; + + Description=opt.m_Description; + standard=opt.m_Standard; + airwar=opt.m_AirWar; + cooperative=opt.m_Cooperative; + duel=opt.m_Duel; + navalwar=opt.m_NavalWar; + nukewar=opt.m_NukeWar; + meatgrind=opt.m_Meatgrind; + megawealth=opt.m_MegaWealth; + + maxplayers=opt.m_Maxplayers+2; + minplayers=opt.m_MinPlayers+2; + + dwFlags|=MAPDATA_UPDATE_TO_INI_ALL_PREVIEW; + + Map->GetIniFile().sections["Basic"].values["Official"]="Yes"; + + // Map->GetIniFile().sections["Basic"].values["Name"]=opt.m_Description; + } + + SetText("Packing data..."); + UpdateWindow(); + errstream << "Calling UpdateIniFile()"<<endl; + + + + CSavingDlg dlg; + dlg.ShowWindow(SW_SHOW); + dlg.BringWindowToTop(); + dlg.UpdateWindow(); + Map->UpdateIniFile(dwFlags); + + + + CIniFile& ini=Map->GetIniFile(); + + + int i; + + for(i=0;i<ini.sections.size();i++) + { + if(ini.GetSection(i)->values.size()==0 || ini.GetSectionName(i)->GetLength()==0) + { + ini.sections.erase(*ini.GetSectionName(i)); + } + } + + for(i=0;i<ini.sections.size();i++) + { + CIniFileSection& sec=*ini.GetSection(i); + int e; + if(*ini.GetSectionName(i)!="IsoMapPack5") + for(e=0;e<sec.values.size();e++) + { + sec.GetValue(e)->TrimLeft(); + { + CString value=*sec.GetValue(e); + CString name=*sec.GetValueName(e); + + sec.values.erase(name); + name.TrimLeft(); + sec.values[name]=value; + } + } + } + + for(i=0;i<ini.sections.size();i++) + { + CIniFileSection& sec=*ini.GetSection(i); + int e; + if(*ini.GetSectionName(i)!="IsoMapPack5") + for(e=0;e<sec.values.size();e++) + { + sec.GetValue(e)->TrimRight(); + { + CString value=*sec.GetValue(e); + CString name=*sec.GetValueName(e); + + sec.values.erase(name); + name.TrimRight(); + sec.values[name]=value; + } + } + } + + + + SetText("Saving..."); + UpdateWindow(); + + + + + std::wstring FileName = utf8ToUtf16(FileName_.GetString()); + + map<CString, BOOL> rulessections; + + std::string tempfile=u8AppDataPath; + tempfile+="\\TmpMap.map"; + std::wstring u16tempfile = utf8ToUtf16(tempfile); + + CString fi; + + deleteFile(tempfile); + HANDLE hFile=CreateFileW(u16tempfile.c_str(), GENERIC_WRITE, 0, NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + CloseHandle(hFile); + hFile=CreateFileW(u16tempfile.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + + DWORD bwr; + +#ifdef TS_MODE + fi= "; Map created with FinalSun Mission Editor"; + fi+="\n"; + fi+= "; note that all comments were truncated" ; + fi+= "\n"; + fi+="\n"; +#else + fi= "; Map created with FinalAlert 2 Mission Editor"; + fi+="\n"; + fi+= "; note that all comments were truncated" ; + fi+= "\n"; + fi+="\n"; +#endif + + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + fi=""; + + // MW 07/28/01: Header saving at top + for(i=0;i<ini.sections.size();i++) + { + if(*ini.GetSectionName(i)=="Header") + { + rulessections[*ini.GetSectionName(i)]=TRUE; + + fi= "[" ; + fi+= *ini.GetSectionName(i); + fi+= "]" ; + fi+= "\n"; + + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + int e; + CIniFileSection& sec=*ini.GetSection(i); + CString d; + + + char c[50]; + for(e=0;e<sec.values.size();e++) + { + fi= *sec.GetValueName(e); + fi+= "=" ; + fi+= *sec.GetValue(e) ; + fi+= "\n"; + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + + if(e%500==0) + { + int percent=e*100/sec.values.size(); + d=*ini.GetSectionName(i); + itoa(percent,c ,10); + SetText((CString)"Saving... "+d+"( "+c+"% )"); + UpdateWindow(); + } + + } + + fi= "\n"; + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + } + + } + + for(i=0;i<ini.sections.size();i++) + { + if(Map->IsRulesSection(*ini.GetSectionName(i))) + { + rulessections[*ini.GetSectionName(i)]=TRUE; + + fi= "[" ; + fi+= *ini.GetSectionName(i); + fi+= "]" ; + fi+= "\n"; + + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + int e; + CIniFileSection& sec=*ini.GetSection(i); + CString d; + + + char c[50]; + for(e=0;e<sec.values.size();e++) + { + fi= *sec.GetValueName(e); + fi+= "=" ; + fi+= *sec.GetValue(e) ; + fi+= "\n"; + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + + if(e%500==0) + { + int percent=e*100/sec.values.size(); + d=*ini.GetSectionName(i); + itoa(percent,c ,10); + SetText((CString)"Saving... "+d+"( "+c+"% )"); + UpdateWindow(); + } + + } + + fi= "\n"; + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + } + + } + + // the preview must be before map data... + if(hidePreview) + { + fi+= "; this is a hidden preview";fi+= "\n"; + fi+= "[Preview]" ;fi+= "\n" ; + fi+= "Size=0,0,106,61" ;fi+= "\n" ;fi+= "\n"; + fi+= "[PreviewPack]" ;fi+= "\n"; + fi+= "2=BIACcgAEwBtAMnRABAAaQCSANMAVQASAAnIABMAbQDJ0QAQAGkAkgDTAFUAEgAJyAATAG0" ;fi+= "\n"; + fi+= "1=yAsAIAXQ5PDQ5PDQ6JQATAEE6PDQ4PDI4JgBTAFEAkgAJyAATAG0AydEAEABpAJIA0wBVA" ;fi+= "\n" ;fi+= "\n"; + } + else{ + fi+= "[Preview]" ;fi+= "\n"; + int e; + for(e=0;e<ini.sections["Preview"].values.size();e++) + { + fi+= *ini.sections["Preview"].GetValueName(e) ;fi+= "=" ; + fi+= *ini.sections["Preview"].GetValue(e); + fi+= "\n"; + } + fi+= "\n"; + fi+= "[PreviewPack]" ;fi+= "\n"; + for(e=0;e<ini.sections["PreviewPack"].values.size();e++) + { + fi+= *ini.sections["PreviewPack"].GetValueName(e) ;fi+= "=" ; + fi+= *ini.sections["PreviewPack"].GetValue(e) ; + fi+= "\n"; + } + fi+= "\n"; + } + + + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + for(i=0;i<ini.sections.size();i++) + { + if(rulessections.find(*ini.GetSectionName(i))!=rulessections.end() || (*ini.GetSectionName(i)=="Digest" || *ini.GetSectionName(i)=="PreviewPack" || *ini.GetSectionName(i)=="Preview" || *ini.GetSectionName(i)=="Header")) + { + + + + + } + else if(*ini.GetSectionName(i)!="") + { + //MessageBox(ini.GetSectionName(i)->data()); + + + //its a standard section: + fi= "[" ; + fi+= *ini.GetSectionName(i); + fi+= "]" ; + fi+= "\n"; + + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + int e; + CIniFileSection& sec=*ini.GetSection(i); + CString d; + + + char c[50]; + for(e=0;e<sec.values.size();e++) + { + fi= *sec.GetValueName(e); + fi+= "=" ; + fi+= *sec.GetValue(e) ; + fi+= "\n"; + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + + + + if(e%500==0) + { + int percent=e*100/sec.values.size(); + d=*ini.GetSectionName(i); + itoa(percent,c ,10); + SetText((CString)"Saving... "+d+"( "+c+"% )"); + UpdateWindow(); + } + + } + + fi= "\n"; + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + } + } + + + fi+= "\n"; + fi+= "[Digest]" ;fi+= "\n"; + int e; + for(e=0;e<ini.sections["Digest"].values.size();e++) + { + fi+= *ini.sections["Digest"].GetValueName(e) ;fi+= "=" ; + fi+= *ini.sections["Digest"].GetValue(e) ; + fi+= "\n"; + } + fi+= "\n"; + WriteFile(hFile, fi, fi.GetLength(), &bwr, NULL); + + + CloseHandle(hFile); + + dlg.DestroyWindow(); + + auto DestName=FileName; + if(bSaveAsMMX) + { + MAPFileName.Replace(" ", ""); + MMXFileName.Replace(" ", ""); + PKTFileName.Replace(" ", ""); + CoreName.Replace(" ", ""); + } + if (bSaveAsMMX) + FileName = utf8ToUtf16(MAPFileName.GetString()); + + const auto u8FileName = utf16ToUtf8(FileName); + + if(!CopyFileW(u16tempfile.c_str(), FileName.c_str(), FALSE)) + { + MessageBox("Error: file cannot be saved. Make sure the file is not read only","Error",MB_OK); + } + else + { + SetText(TranslateStringVariables(1,GetLanguageStringACP("FileSaved"), u8FileName.c_str())); + if(bSaveAsMMX) + { + SetText(TranslateStringVariables(1,GetLanguageStringACP("FileSaved"), MMXFileName)); + + // MW 07/20/01: + InsertPrevFile(MMXFileName); + + CIniFile f; + //CoreName.Replace(" ", ""); + //Description.Replace(" ",""); + + f.sections["MultiMaps"].values["1"]=CoreName; + f.sections[CoreName].values["Description"]=Description; + CString gm; + if(standard) gm+="standard, "; + if(meatgrind) gm+="meatgrind, "; + if(navalwar) gm+="navalwar, "; + if(nukewar) gm+="nukewar, "; + if(airwar) gm+="airwar, "; + if(megawealth) gm+="megawealth, "; + if(duel) gm+="duel, "; + if(cooperative) gm+="cooperative, "; + + if(gm.ReverseFind(',')>=0) gm=gm.Left(gm.ReverseFind(',')); + + f.sections[CoreName].values["GameMode"]=gm; + + char c[50]; + itoa(maxplayers, c, 10); + f.sections[CoreName].values["MaxPlayers"]=c; + itoa(minplayers,c,10); + f.sections[CoreName].values["MinPlayers"]=c; + + f.sections[CoreName].values["CD"]="0,1"; + + + f.SaveFile(PKTFileName); + + LPCSTR files[2]; + files[0]=(LPCSTR)PKTFileName; + files[1]=(LPCSTR)MAPFileName; + +#ifdef RA2_MODE + auto game = yuri_mode ? FSunPackLib::Game::RA2_YR : FSunPackLib::Game::RA2; +#else + auto game = FSunPackLib::Game::TS; +#endif + FSunPackLib::WriteMixFile(MMXFileName, files, 2, game); + + DeleteFile(PKTFileName); + DeleteFile(MAPFileName); + } + else + { + // MW 07/20/01: + InsertPrevFile(u8FileName.c_str()); + } + } + + deleteFile(tempfile); + + SetCursor(m_hArrowCursor); + //SetReady(); + + } + +void CFinalSunDlg::SetReady() +{ + m_view.m_statbar.GetStatusBarCtrl().SetText(TranslateStringACP("Ready"), 0,0); +} + +void CFinalSunDlg::SetText(const char *text) +{ + m_view.m_statbar.GetStatusBarCtrl().SetText(text,0,0); +} + +void CFinalSunDlg::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu) +{ + + + CDialog::OnMenuSelect(nItemID, nFlags, hSysMenu); + + switch(nItemID) + { + case ID_FILE_OPENMAP: + SetText(GetLanguageStringACP("FileOpenHelp")); + break; + case ID_FILE_SAVE: + SetText(GetLanguageStringACP("FileSaveHelp")); + break; + case ID_FILE_SAVEAS: + SetText(GetLanguageStringACP("FileSaveAsHelp")); + break; + case ID_FILE_IMPORTMOD: + SetText(GetLanguageStringACP("FileImportModHelp")); + break; + case ID_FILE_QUIT: + SetText(GetLanguageStringACP("FileQuitHelp")); + break; + case ID_FILE_VALIDATEMAP: + SetText(GetLanguageStringACP("FileCheckMapHelp")); + break; + case ID_FILE_RUNTIBERIANSUN: + SetText(GetLanguageStringACP("FileRunTiberianSunHelp")); + break; + case ID_FILE_NEW: + SetText(GetLanguageStringACP("FileNewHelp")); + break; + case ID_MAPVIEW: + SetText(GetLanguageStringACP("OptionsShowMapViewHelp")); + break; + case ID_HELP_INFO: + SetText(GetLanguageStringACP("HelpInfoHelp")); + break; + case ID_HELP_TIPOFTHEDAY: + SetText(GetLanguageStringACP("HelpTipOfTheDayHelp")); + break; + case ID_OPTIONS_EXPORTRULESINI: + SetText("Export the file rules.ini"); + break; + default: + SetReady(); + } +} + + +void se_translator(unsigned int e, _EXCEPTION_POINTERS* p) +{ + throw(unsigned int)(e); +} + + + + +void CFinalSunDlg::OnFileRuntiberiansun() // or RA2 +{ + PROCESS_INFORMATION pi; + STARTUPINFO si; + memset(&si, 0, sizeof(STARTUPINFO)); + si.cb=sizeof(STARTUPINFO); + + CString exe=theApp.m_Options.TSExe; + exe.MakeLower(); + if(yuri_mode) + { + exe.Replace("ra2.exe","ra2md.exe"); + } + + + BOOL success=CreateProcess(exe, + NULL, + NULL, + NULL, + FALSE, + NORMAL_PRIORITY_CLASS, + NULL, + NULL, + &si, + &pi); + +} + + + + +void CFinalSunDlg::OnFileImportmod() +{ + /*CImportModDlg dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST, "TS maps|*.mpr;*.map|TS multi maps|*.mpr|TS single maps|*.map|"); + + + + char cuPath[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, cuPath); + dlg.m_ofn.lpstrInitialDir=cuPath; + + //if(theApp.m_Options.TSExe.GetLength()) dlg.m_ofn.lpstrInitialDir=(char*)(LPCTSTR)theApp.m_Options.TSExe; + + if(dlg.DoModal()==IDCANCEL) return; */ + + +} + +void CFinalSunDlg::OnDebugExportmappacknosections() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ovrl; + int i; + + + ovrl=""; + + for(i=0;i<ini.sections["IsoMapPack5"].values.size();i++) + { + ovrl+=*ini.sections["IsoMapPack5"].GetValue(i); + } + + + BYTE hex[400000]; + BYTE values[400000]; + + //int hexlen=ConvertToHex((BYTE*)(LPCTSTR)ovrl, hex); + + + + + //ExtractIsoMapPack5(hex,hexlen, values); + + HANDLE hFile=CreateFile("c:\\MAPPACKNOSECTIONS.BIN", GENERIC_WRITE, 0, NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + CloseHandle(hFile); + hFile=CreateFile("c:\\MAPPACKNOSECTIONS.BIN", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + DWORD dw; + WriteFile(hFile, values, 400000, &dw, NULL); + + CloseHandle(hFile); + +} + +void CFinalSunDlg::OnDebugExportmappack() +{ + +} + +void DeleteTypeList(CString SectionType) +{ + CIniFile& ini=Map->GetIniFile(); + + int i; + for(i=0;i<ini.sections[SectionType].values.size();i++) + { + ini.sections.erase(*ini.sections[SectionType].GetValue(i)); + } + ini.sections.erase(SectionType); +} + +void CFinalSunDlg::OnFileNew() +{ + + CNewMapTypeDlg typedlg; + if(typedlg.DoModal()==IDCANCEL) return; + + BOOL bSingleplayer=!typedlg.m_Singleplayer; + + CNewMapCreateDlg createdlg; + if(createdlg.DoModal()==IDCANCEL) return; + + BOOL bCreateNew=!createdlg.m_CreateType; + + int width, height, theater, stdheight; + CString importmap; + BOOL bImportTrees, bImportUnits, bImportOverlay; + if(bCreateNew) + { + CNewMapCreateNewDlg createnewdlg; + if(createnewdlg.DoModal()==IDCANCEL) return; + width=createnewdlg.m_Width; + height=createnewdlg.m_Height; + stdheight=createnewdlg.m_StartingHeight; + theater=createnewdlg.m_Theater; + } + else + { + while(!DoesFileExist(importmap)) + { + CNewMapImportDlg impdlg; + if(impdlg.DoModal()==IDCANCEL) return; + importmap=impdlg.m_ImportFile; + bImportTrees=impdlg.m_ImportTrees; + bImportUnits=impdlg.m_ImportUnits; + bImportOverlay=impdlg.m_ImportOverlay; + } + } + + CString plhouse; + BOOL bPrepareHouses=FALSE; + BOOL bAutoProd=FALSE; + if(bSingleplayer) + { + CNewMapSpDlg spdlg; + if(spdlg.DoModal()==IDCANCEL) return; + bPrepareHouses=spdlg.m_PrepareHouses; + bAutoProd=spdlg.m_AutoProd; + plhouse=*rules.sections[HOUSES].GetValue(spdlg.m_House); + } + + bNoDraw=TRUE; + + m_PKTHeader.Clear(); + + // first hide the terrain browser window + m_TerrainDlg.DestroyWindow(); + + // set currentMapFile to nothing and update window caption + strcpy(currentMapFile,""); + CString cap; + cap=GetLanguageStringACP("MainDialogCaption"); + cap+=" ("; + cap+=GetLanguageStringACP("NewMap"); + cap+=")"; + SetWindowText(cap); + + // set cursor to wait + SetCursor(LoadCursor(NULL,IDC_WAIT)); + + if(!bCreateNew) + { + CString file=importmap; + file.MakeLower(); + if(file.Find(".bmp")>=0) + { + CBitmap2MapConverter conv; + HBITMAP hBitmap=(HBITMAP)LoadImageW(NULL, utf8ToUtf16(file.GetString()).c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + + conv.Convert(hBitmap, *Map); + + DeleteObject(hBitmap); + } + else + { + Map->LoadMap(file.GetString()); + + if(!bImportOverlay) { + Map->ClearOverlay(); + Map->ClearOverlayData(); + } + + CIniFile& ini=Map->GetIniFile(); + + int i; + int count=Map->GetTerrainCount(); + if(!bImportTrees) + { + for(i=0;i<count;i++) + Map->DeleteTerrain(0); + } + + if(!bImportUnits) + { + count=Map->GetInfantryCount(); + for(i=0;i<count;i++) + Map->DeleteInfantry(0); + count=Map->GetUnitCount(); + for(i=0;i<count;i++) + Map->DeleteUnit(0); + count=Map->GetStructureCount(); + for(i=0;i<count;i++) + Map->DeleteStructure(0); + count=Map->GetAircraftCount(); + for(i=0;i<count;i++) + Map->DeleteAircraft(0); + } + + ini.sections["Basic"].values["Name"]="Noname"; + + for(i=0;i<ini.sections[MAPHOUSES].values.size();i++) + { + ini.sections.erase(*ini.sections[MAPHOUSES].GetValue(i)); + } + ini.sections.erase(MAPHOUSES); + + for(i=0;i<ini.sections[HOUSES].values.size();i++) + { + ini.sections.erase(*ini.sections[HOUSES].GetValue(i)); + } + ini.sections.erase(HOUSES); + + if(TRUE) + { + ini.sections.erase("Tags"); + ini.sections.erase("Triggers"); + ini.sections.erase("Actions"); + ini.sections.erase("Events"); + DeleteTypeList("TeamTypes"); + DeleteTypeList("TaskForces"); + DeleteTypeList("ScriptTypes"); + ini.sections.erase("CellTags"); + + // ini.sections.erase("AITriggerTypesEnable"); + // ini.sections.erase("AITriggerTypes"); + } + } + + } + else + { + // ok, create a new map + CString theater_s; + if(theater==0) theater_s=THEATER0; else if(theater==1) theater_s=THEATER1; + else if(theater==2) theater_s=THEATER2; else if(theater==3) theater_s=THEATER3; + else if(theater==4) theater_s=THEATER4; else if(theater==5) theater_s=THEATER5; + + Map->CreateMap(width, height, theater_s, stdheight); + + if(!bSingleplayer) + { + last_succeeded_operation=11003; + + // create map function was created for SP. Fix it here; + Map->DeleteWaypoint(0); + Map->DeleteWaypoint(0); + int midx=Map->GetIsoSize()/2; + int midy=Map->GetIsoSize()/2; + Map->AddWaypoint("0", midx+midy*Map->GetIsoSize()); + Map->AddWaypoint("1", midx+1+midy*Map->GetIsoSize()); + Map->AddWaypoint("2", midx+2+midy*Map->GetIsoSize()); + Map->AddWaypoint("3", midx+3+midy*Map->GetIsoSize()); + Map->AddWaypoint("4", midx+(midy+1)*Map->GetIsoSize()); + Map->AddWaypoint("5", midx+1+(midy+1)*Map->GetIsoSize()); + Map->AddWaypoint("6", midx+2+(midy+1)*Map->GetIsoSize()); + Map->AddWaypoint("7", midx+3+(midy+1)*Map->GetIsoSize()); + + } + + } + + + last_succeeded_operation=11004; + + + CIniFile& ini=Map->GetIniFile(); + + if(!bSingleplayer) ini.sections["Basic"].values["MultiplayerOnly"]="1"; + + if(bSingleplayer) + { + ini.sections["Basic"].values["MultiplayerOnly"]="0"; + + ini.sections.erase("Preview"); + ini.sections.erase("PreviewPack"); + + + + + if(bPrepareHouses) + { + //CString plhouse; + //plhouse=GetHouseSectionName(dlg.m_House); + plhouse+=" House"; + ini.sections["Basic"].values["Player"]=plhouse; + + int i; + for (i=0;i<rules.sections[HOUSES].values.size();i++) + { +#ifdef RA2_MODE + CString j=*rules.sections[HOUSES].GetValue(i); + j.MakeLower(); + if(j=="nod" || j=="gdi") continue; +#endif + + char c[50]; + int k=i; + itoa(k,c,10); + CString country=*rules.sections[HOUSES].GetValue(i); + CString house=GetHouseSectionName(country); + ini.sections[MAPHOUSES].values[c]=house; +#ifdef RA2_MODE + ini.sections[HOUSES].values[c]=country; +#endif + + // is it a player house or a ai house? + if(house!=(LPCTSTR)plhouse) + { + ini.sections[house].values["IQ"]="5"; + + ini.sections[house].values["PlayerControl"]="no"; + + // now, if the user wants to, check if this house is a passive or active house + if(stricmp(rules.sections[house].values["MultiplayPassive"],"true")!=NULL && bAutoProd) + { + CString id=GetFreeID(); + + char c[50]; + k=i; + itoa(i,c,10); +#ifdef RA2_MODE + //k=i+rules.sections[HOUSES].values.size(); + //itoa(k,c,10); +#endif + + ini.sections["Triggers"].values[id]=country; + ini.sections["Triggers"].values[id]+=",<none>,AI Auto Production "; + ini.sections["Triggers"].values[id]+=TranslateHouse(country, TRUE); + ini.sections["Triggers"].values[id]+=",0,1,1,1,0"; + + ini.sections["Events"].values[id]="1,13,0,10"; // after 10 secs, start prod. + + ini.sections["Actions"].values[id]="3,3,0,"; + ini.sections["Actions"].values[id]+=c; + ini.sections["Actions"].values[id]+=",0,0,0,0,A,13,0,"; + ini.sections["Actions"].values[id]+=c; + ini.sections["Actions"].values[id]+=",0,0,0,0,A,74,0,"; + ini.sections["Actions"].values[id]+=c; + ini.sections["Actions"].values[id]+=",0,0,0,0,A"; + + + + CString ID_TAG=GetFreeID(); + ini.sections["Tags"].values[ID_TAG]="0,AI Auto Production "; + ini.sections["Tags"].values[ID_TAG]+=TranslateHouse(house, TRUE); + ini.sections["Tags"].values[ID_TAG]+=","; + ini.sections["Tags"].values[ID_TAG]+=id; + } + + } + else + { + ini.sections[house].values["IQ"]="0"; + + ini.sections[house].values["PlayerControl"]="yes"; + } + +#ifndef RA2_MODE + ini.sections[house].values["ActsLike"]=c; + ini.sections[house].values["Side"]=house; +#else + ini.sections[house].values["Country"]=*rules.sections[HOUSES].GetValue(i); +#endif + ini.sections[house].values["Edge"]="North"; + + ini.sections[house].values["Color"]=rules.sections[*rules.sections[HOUSES].GetValue(i)].values["Color"]; + ini.sections[house].values["Allies"]=house; + ini.sections[house].values["Credits"]="0"; + ini.sections[house].values["NodeCount"]="0"; + ini.sections[house].values["TechLevel"]="10"; + ini.sections[house].values["PercentBuilt"]="100"; + +#ifdef RA2_MODE + ini.sections[country].values["ParentCountry"]=country; + ini.sections[country].values["Name"]=country; + ini.sections[country].values["Suffix"]=rules.sections[country].values["Suffix"]; + ini.sections[country].values["Prefix"]=rules.sections[country].values["Prefix"]; + ini.sections[country].values["Color"]=rules.sections[country].values["Color"]; + ini.sections[country].values["Side"]=rules.sections[country].values["Side"]; + ini.sections[country].values["SmartAI"]=rules.sections[country].values["SmartAI"]; + ini.sections[country].values["CostUnitsMult"]="1"; +#endif + + + } + } + + } + else + { + // for RA2, we create standard houses +#ifdef RA2_MODE + int i; + for (i=0;i<rules.sections[HOUSES].values.size();i++) + { + char c[50]; + int k=i; + itoa(k,c,10); + CString country=*rules.sections[HOUSES].GetValue(i); + + if(country.GetLength()==0) continue; // make sure we don´t have an empty entry + + // we now create a HOUSE with the same name as the current rules house + ini.sections[MAPHOUSES].values[c]=country; + + ini.sections[country].values["IQ"]="0"; + ini.sections[country].values["Edge"]="North"; + ini.sections[country].values["Color"]=rules.sections[country].values["Color"]; + ini.sections[country].values["Allies"]=country; + ini.sections[country].values["Country"]=country; + ini.sections[country].values["Credits"]="0"; + ini.sections[country].values["NodeCount"]="0"; + ini.sections[country].values["TechLevel"]="1"; + ini.sections[country].values["PercentBuilt"]="0"; + ini.sections[country].values["PlayerControl"]="no"; + + } +#endif + + } + + // MW: added March 31st + // now allow automatic ai trigger enabling + if(createdlg.m_AITriggers) + { + int i; + for(i=0;i<ai.sections["AITriggerTypes"].values.size();i++) + { + ini.sections["AITriggerTypesEnable"].values[*ai.sections["AITriggerTypes"].GetValueName(i)]="yes"; + } + } + + last_succeeded_operation=11000; + + Map->UpdateIniFile(MAPDATA_UPDATE_FROM_INI); + + last_succeeded_operation=11001; + + Sleep(200); + + SetCursor(m_hArrowCursor); + + bNoDraw=FALSE; + + //if(RepairRulesHouses()) + // MessageBox("Repaired houses"); + + m_view.m_isoview->UpdateDialog(TRUE); + m_view.m_minimap.RedrawWindow(); + UpdateDialogs(); + + last_succeeded_operation=11002; +} + + +/* + UpdateStrings(); + Updates all dialog CStrings, and the CStrings from the isoview object list and the child dialogs +*/ +void CFinalSunDlg::UpdateStrings() +{ + last_succeeded_operation=20; + + CString str; + + // update the menu + CMenu* menu=GetMenu(); + + + // destroy the old menu + if(menu) menu->DestroyMenu(); + // if(menu) delete menu; + + CMenu* my_menu=new(CMenu); + // first, we load the original menu (we can´t translate from for example german!) + my_menu->LoadMenu(IDR_MAIN); + + int i,e; + for(i=0;i<my_menu->GetMenuItemCount();i++) + { + MENUITEMINFO mii; + ZeroMemory(&mii, sizeof(MENUITEMINFO)); + mii.cbSize=sizeof(MENUITEMINFO); + mii.fMask=MIIM_ID | MIIM_STATE | MIIM_TYPE; + + my_menu->GetMenuItemInfo(i, &mii, TRUE); + my_menu->GetMenuString(i, str, MF_BYPOSITION); + my_menu->ModifyMenu(i,mii.fState | mii.fType | MF_BYPOSITION | MF_STRING, mii.wID, TranslateStringACP((LPCTSTR)str)); + for(e=0;e<my_menu->GetSubMenu(i)->GetMenuItemCount();e++) + { + int id=my_menu->GetSubMenu(i)->GetMenuItemID(e); + + ZeroMemory(&mii, sizeof(MENUITEMINFO)); + mii.cbSize=sizeof(MENUITEMINFO); + mii.fMask=MIIM_ID | MIIM_STATE | MIIM_TYPE; + my_menu->GetSubMenu(i)->GetMenuItemInfo(e, &mii, TRUE); + my_menu->GetSubMenu(i)->GetMenuString(e, str, MF_BYPOSITION); + my_menu->GetSubMenu(i)->ModifyMenu(e,mii.fState | mii.fType | MF_BYPOSITION | MF_STRING, mii.wID, TranslateStringACP((LPCTSTR)str)); + + } + } + + + if(theApp.m_Options.bEasy) my_menu->CheckMenuItem(ID_OPTIONS_SIMPLEVIEW, MF_BYCOMMAND | MF_CHECKED); + if(theApp.m_Options.bDisableAutoShore) my_menu->CheckMenuItem(ID_OPTIONS_DISABLEAUTOSHORE, MF_BYCOMMAND | MF_CHECKED); + if(theApp.m_Options.bDisableAutoLat) my_menu->CheckMenuItem(ID_OPTIONS_DISABLEAUTOLAT, MF_BYCOMMAND | MF_CHECKED); + if(theApp.m_Options.bDisableSlopeCorrection) my_menu->CheckMenuItem(ID_OPTIONS_DISABLESLOPECORRECTION, MF_BYCOMMAND | MF_CHECKED); + if(theApp.m_Options.bShowCells) my_menu->CheckMenuItem(ID_OPTIONS_SHOWBUILDINGOUTLINE, MF_BYCOMMAND | MF_CHECKED); + if(theApp.m_Options.useDefaultMouseCursor) my_menu->CheckMenuItem(ID_OPTIONS_USEDEFAULTMOUSECURSOR, MF_BYCOMMAND | MF_CHECKED); + if(!theApp.m_Options.viewScaleUseSteps) my_menu->CheckMenuItem(ID_OPTIONS_SMOOTHZOOM, MF_BYCOMMAND | MF_CHECKED); + + + // MW 07/20/01: Show prev. opened files + int prev_maps_count=0; + for(i=0;i<4;i++) + { + if(theApp.m_Options.prev_maps[i].GetLength()>0) + { + prev_maps_count++; + + int id=0; + CString str="bla"; + str=theApp.m_Options.prev_maps[i]; + + if(i==0) id=ID_FILE_FILE1; + else if(i==1) id=ID_FILE_FILE2; + else if(i==2) id=ID_FILE_FILE3; + else if(i==3) id=ID_FILE_FILE4; + + my_menu->GetSubMenu(0)->InsertMenu(10+prev_maps_count, MF_BYPOSITION | MF_STRING, id, str); + } + } + + +#ifdef RA2_MODE + // my_menu->DeleteMenu(4, MF_BYPOSITION); +#endif + + if(theApp.m_Options.bEasy) my_menu->GetSubMenu(3)->DeleteMenu(0, MF_BYPOSITION); + + if(theApp.m_Options.bEasy) + { + CMenu* edit_my_menu=my_menu->GetSubMenu(1); + for(i=edit_my_menu->GetMenuItemCount()-1;i>=11;i--) // MW 07/17/2001: i>=9 changed to i>=10 so Basic dialog is always available + { + edit_my_menu->DeleteMenu(i, MF_BYPOSITION); + } + CMenu* terrain_my_menu=my_menu->GetSubMenu(2); + for(i=terrain_my_menu->GetMenuItemCount()-1;i>=8;i--) + { + terrain_my_menu->DeleteMenu(i, MF_BYPOSITION); + } + } + +#ifndef SCRIPT_SUPPORT + my_menu->GetSubMenu(3)->DeleteMenu(ID_MAPTOOLS_TOOLSCRIPTS, MF_BYCOMMAND); +#endif + + // now attach this my_menu to the window + SetMenu(my_menu); + + + // update the tabs + /*TCITEM tci; + memset(&tci, 0, sizeof(TCITEM)); + tci.mask=TCIF_TEXT; + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabBasic"); + m_TabCtrl.SetItem(TAB_BASIC, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabSingleplayerSettings"); + m_TabCtrl.SetItem(TAB_SINGLEPLAYERSETTINGS, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabMap"); + m_TabCtrl.SetItem(TAB_MAP, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabLighting"); + m_TabCtrl.SetItem(TAB_LIGHTNING, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabSpecial"); + m_TabCtrl.SetItem(TAB_SPECIALFLAGS, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabHouses"); + m_TabCtrl.SetItem(TAB_HOUSES, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabTaskForces"); + m_TabCtrl.SetItem(TAB_TASKFORCES, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabScriptTypes"); + m_TabCtrl.SetItem(TAB_SCRIPTTYPES, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabTeamTypes"); + m_TabCtrl.SetItem(TAB_TEAMTYPES, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabTriggers"); + m_TabCtrl.SetItem(TAB_TRIGGERS, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabTags"); + m_TabCtrl.SetItem(TAB_TAGS, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabAITriggers"); + m_TabCtrl.SetItem(TAB_AITRIGGERTYPES, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabAITriggerEnable"); + m_TabCtrl.SetItem(TAB_AITRIGGERTYPESENABLE, &tci); + tci.pszText=(char*)(LPCTSTR)GetLanguageStringACP("TabOther"); + m_TabCtrl.SetItem(TAB_OTHER, &tci); + */ + + // now the child windows and the iso view + m_view.m_objectview->UpdateDialog(); + m_view.m_browser->m_bar.Update(); + if(m_basic.m_hWnd) m_basic.UpdateStrings(); + if(m_houses.m_hWnd) m_houses.UpdateStrings(); + if(m_map.m_hWnd) m_map.UpdateStrings(); + if(m_singleplayersettings.m_hWnd) m_singleplayersettings.UpdateStrings(); + + // we need to check SimpleView if using easy view + if(theApp.m_Options.bEasy) GetMenu()->CheckMenuItem(ID_OPTIONS_SIMPLEVIEW, MF_BYCOMMAND | MF_CHECKED); + if(!theApp.m_Options.bNoSounds) GetMenu()->CheckMenuItem(ID_OPTIONS_SOUNDS, MF_BYCOMMAND | MF_CHECKED); + + + + RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); +} + +void CFinalSunDlg::OnHelpTipoftheday() +{ + CTipDlg tip; + tip.DoModal(); + +} + +void CFinalSunDlg::UnloadAll() +{ + int iQuit=MessageBox(GetLanguageStringACP("MainDialogExitQuestion"), GetLanguageStringACP("MainDialogExitQuestionCap"), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2); + if(iQuit==IDNO) return; + else{ + try + { + + CShutDownDlg dlg(this); + dlg.ShowWindow(SW_SHOW); + dlg.UpdateWindow(); + + tiledata=0; + + theApp.m_loading->FreeAll(); + + rules.Clear(); + ai.Clear(); + art.Clear(); + tiles_t.Clear(); + tiles_s.Clear(); + tiles_u.Clear(); + Map->GetIniFile().Clear(); + sound.Clear(); + tutorial.Clear(); + g_data.Clear(); + language.Clear(); + + + + DestroyWindow(); + } + catch(...) + { + DestroyWindow(); + } + } + + +} + +void CFinalSunDlg::OnOptionsSimpleview() +{ + CIniFile Options; + Options.LoadFile(u8AppDataPath+"\\FinalSun.ini"); +#ifdef RA2_MODE + Options.LoadFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif + + if(GetMenu()->GetMenuState(ID_OPTIONS_SIMPLEVIEW, MF_BYCOMMAND) & MF_CHECKED) + { + GetMenu()->CheckMenuItem(ID_OPTIONS_SIMPLEVIEW, MF_BYCOMMAND | MF_UNCHECKED); + theApp.m_Options.bEasy=FALSE; + Options.sections["UserInterface"].values["EasyView"]="0"; + + // hide all dialogs: + HideAllDialogs(); + } + else + { + GetMenu()->CheckMenuItem(ID_OPTIONS_SIMPLEVIEW, MF_BYCOMMAND | MF_CHECKED); + theApp.m_Options.bEasy=TRUE; + Options.sections["UserInterface"].values["EasyView"]="1"; + } + + UpdateStrings(); + +#ifndef RA2_MODE + Options.SaveFile(u8AppDataPath+"\\FinalSun.ini"); +#else + Options.SaveFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif + + UpdateDialogs(); +} + + +void CFinalSunDlg::OnOptionsShowminimap() +{ + bMiniMapClosedByUser=FALSE; + this->m_view.m_minimap.UpdateView(); +} + +void CFinalSunDlg::HideAllDialogs() +{ + if (m_aitriggertypes) + m_aitriggertypes.ShowWindow(SW_HIDE); + if (m_aitriggertypesenable) + m_aitriggertypesenable.ShowWindow(SW_HIDE); + if (m_all) + m_all.ShowWindow(SW_HIDE); + if (m_basic) + m_basic.ShowWindow(SW_HIDE); + if (m_houses) + m_houses.ShowWindow(SW_HIDE); + if (m_lighting) + m_lighting.ShowWindow(SW_HIDE); + if (m_map) + m_map.ShowWindow(SW_HIDE); + if (m_Scripttypes) + m_Scripttypes.ShowWindow(SW_HIDE); + if (m_singleplayersettings) + m_singleplayersettings.ShowWindow(SW_HIDE); + if (m_specialflags) + m_specialflags.ShowWindow(SW_HIDE); + if (m_tags) + m_tags.ShowWindow(SW_HIDE); + if (m_taskforces) + m_taskforces.ShowWindow(SW_HIDE); + if (m_teamtypes) + m_teamtypes.ShowWindow(SW_HIDE); + if (m_triggers) + m_triggers.ShowWindow(SW_HIDE); +} + +void CFinalSunDlg::OnFileValidatemap() +{ + CMapValidator validator; + int iCancel=validator.DoModal(); + if(iCancel==IDCANCEL) return; +} + + + + +void CFinalSunDlg::OnEnterIdle(UINT nWhy, CWnd* pWho) +{ + CDialog::OnEnterIdle(nWhy, pWho); + + +} + + + +void CFinalSunDlg::OnEditBasicsettings() +{ + if(m_basic.m_hWnd==NULL) + { + if(!m_basic.Create(CBasic::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + + } + + if(m_basic.m_hWnd!=NULL) + { + m_basic.UpdateStrings(); + m_basic.UpdateDialog(); + m_basic.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnEditSingleplayersettings() +{ + if(m_singleplayersettings.m_hWnd==NULL) + { + if(!m_singleplayersettings.Create(CSingleplayerSettings::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_singleplayersettings.m_hWnd!=NULL) + { + m_singleplayersettings.UpdateStrings(); + m_singleplayersettings.UpdateDialog(); + m_singleplayersettings.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnSizing(UINT fwSide, LPRECT pRect) +{ + CDialog::OnSizing(fwSide, pRect); + + +} + +void CFinalSunDlg::OnSize(UINT nType, int cx, int cy) +{ + CDialog::OnSize(nType, cx, cy); + + if(nType==SIZE_MINIMIZED) + { + if(!bMiniMapClosedByUser) m_view.m_minimap.ShowWindow(SW_MINIMIZE); + } + else if(nType==SIZE_MAXIMIZED) + { + if(!bMiniMapClosedByUser) m_view.m_minimap.ShowWindow(SW_RESTORE); + } + + RecalcLayout(); +} + +void CFinalSunDlg::OnEditHouses() +{ + if(m_houses.m_hWnd==NULL) + { + if(!m_houses.Create(CHouses::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_houses.m_hWnd!=NULL) + { + m_houses.UpdateStrings(); + m_houses.UpdateDialog(); + m_houses.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnEditAitriggers() +{ + if(m_aitriggertypes.m_hWnd==NULL) + { + if(!m_aitriggertypes.Create(CAITriggerTypes::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_aitriggertypes.m_hWnd!=NULL) + { + //m_aitriggertypes.UpdateStrings(); + m_aitriggertypes.UpdateDialog(); + m_aitriggertypes.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + + } + +} + +void CFinalSunDlg::OnEditAitriggerenabling() +{ + if(m_aitriggertypesenable.m_hWnd==NULL) + { + if(!m_aitriggertypesenable.Create(CAiTriggerTypesEnable::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_aitriggertypesenable.m_hWnd!=NULL) + { + //m_aitriggertypesenable.UpdateStrings(); + m_aitriggertypesenable.UpdateDialog(); + m_aitriggertypesenable.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + + } +} + +void CFinalSunDlg::OnEditIniediting() +{ + if(m_all.m_hWnd==NULL) + { + if(!m_all.Create(CAll::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_all.m_hWnd!=NULL) + { + //m_all.UpdateStrings(); + m_all.UpdateDialog(); + m_all.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnEditLighting() +{ + if(m_lighting.m_hWnd==NULL) + { + if(!m_lighting.Create(CLighting::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_lighting.m_hWnd!=NULL) + { + //m_lighting.UpdateStrings(); + m_lighting.UpdateDialog(); + m_lighting.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } + +} + +void CFinalSunDlg::OnEditMap() +{ + if(m_map.m_hWnd==NULL) + { + if(!m_map.Create(CMapD::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_map.m_hWnd!=NULL) + { + m_map.UpdateStrings(); + m_map.UpdateDialog(); + m_map.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnEditScripts() +{ + if(m_Scripttypes.m_hWnd==NULL) + { + if(!m_Scripttypes.Create(CScriptTypes::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_Scripttypes.m_hWnd!=NULL) + { + //m_Scripttypes.UpdateStrings(); + m_Scripttypes.UpdateDialog(); + m_Scripttypes.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnEditSpecialflags() +{ + if(m_specialflags.m_hWnd==NULL) + { + if(!m_specialflags.Create(CSpecialFlags::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_specialflags.m_hWnd!=NULL) + { + //m_specialflags.UpdateStrings(); + m_specialflags.UpdateDialog(); + m_specialflags.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnEditTags() +{ + if(m_tags.m_hWnd==NULL) + { + if(!m_tags.Create(CTags::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_tags.m_hWnd!=NULL) + { + //m_tags.UpdateStrings(); + m_tags.UpdateDialog(); + m_tags.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnEditTaskforces() +{ + if(m_taskforces.m_hWnd==NULL) + { + if(!m_taskforces.Create(CTaskForce::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_taskforces.m_hWnd!=NULL) + { + //m_taskforces.UpdateStrings(); + m_taskforces.UpdateDialog(); + m_taskforces.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnEditTeams() +{ + if(m_teamtypes.m_hWnd==NULL) + { + if(!m_teamtypes.Create(CTeamTypes::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_teamtypes.m_hWnd!=NULL) + { + //m_teamtypes.UpdateStrings(); + m_teamtypes.UpdateDialog(); + m_teamtypes.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnEditTriggers() +{ + if(m_triggers.m_hWnd==NULL) + { + if(!m_triggers.Create(CTriggers::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_triggers.m_hWnd!=NULL) + { + //m_triggers.UpdateStrings(); + m_triggers.UpdateDialog(); + m_triggers.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnSetFocus(CWnd* pOldWnd) +{ + CDialog::OnSetFocus(pOldWnd); + + SetForegroundWindow(); +} + +BOOL CFinalSunDlg::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult) +{ + // + + + + return CDialog::OnChildNotify(message, wParam, lParam, pLResult); +} + +void CFinalSunDlg::RecalcLayout() +{ + if(m_bar.m_hWnd==NULL) return; + + RECT r,rr; + GetClientRect(&r); + m_bar.GetWindowRect(&rr); + int h=rr.bottom-rr.top+2; + m_bar.GetClientRect(&rr); + rr.right=r.right; + m_view.SetWindowPos(NULL, 0, h, r.right, r.bottom-h, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); + m_bar.SetWindowPos(NULL, 0,0, rr.right, rr.bottom, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); + m_bar.ShowBand(0, TRUE); + m_bar.ShowBand(1, TRUE); +} + +BOOL CFinalSunDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) +{ + NMHDR* pHead=(NMHDR*)lParam; + + if(pHead->hwndFrom==m_bar.m_hWnd && pHead->code==RBN_HEIGHTCHANGE) + { + RecalcLayout(); + } + + if(pHead->code==TTN_NEEDTEXT) + { + TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pHead; + UINT nID =pHead->idFrom; + if (pTTT->uFlags & TTF_IDISHWND) + { + // idFrom ist der HWND des Tools + nID = ::GetDlgCtrlID((HWND)nID); + } + + if(nID) + { + CString s; + char c[50]; + itoa(nID, c, 10); + + s.LoadString(nID); + s=TranslateStringACP(s); + //pTTT->lpszText = s; + if(s.GetLength()>80) s.SetAt(80, 0); + strcpy(pTTT->szText, s); + pTTT->hinst = NULL; + return(TRUE); + } + + } + + return CDialog::OnNotify(wParam, lParam, pResult); +} + +void CFinalSunDlg::OnTerrainHeightenground() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + if(AD.mode!=ACTIONMODE_HEIGHTEN) + { + m_settingsbar.m_BrushSize=1; + m_settingsbar.UpdateData(FALSE); + m_view.m_isoview->m_BrushSize_x=2; + m_view.m_isoview->m_BrushSize_y=2; + } + + Sound(SOUND_POSITIVE); + + AD.mode=ACTIONMODE_HEIGHTEN; + +} + +void CFinalSunDlg::OnTerrainLowerground() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + if(AD.mode!=ACTIONMODE_LOWER) + { + m_settingsbar.m_BrushSize=1; + m_settingsbar.UpdateData(FALSE); + m_view.m_isoview->m_BrushSize_x=2; + m_view.m_isoview->m_BrushSize_y=2; + } + + Sound(SOUND_POSITIVE); + + AD.mode=ACTIONMODE_LOWER; +} + +//DEL void CFinalSunDlg::OnTerrainPaint() +//DEL { +//DEL if(m_TerrainDlg.m_hWnd==NULL) +//DEL { +//DEL if(!m_TerrainDlg.Create(NULL, "Terrain-Browser", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL, NULL, 0)) +//DEL { +//DEL MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); +//DEL } +//DEL } +//DEL +//DEL if(m_TerrainDlg.m_hWnd!=NULL) +//DEL { +//DEL m_TerrainDlg.ShowWindow(SW_SHOW); +//DEL m_TerrainDlg.ActivateFrame(SW_SHOW); +//DEL m_TerrainDlg.m_bar.Update(); +//DEL } +//DEL } + +void CFinalSunDlg::OnTerrainLowertile() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + if(AD.mode!=ACTIONMODE_LOWERTILE) + { + m_settingsbar.m_BrushSize=0; + m_settingsbar.UpdateData(FALSE); + m_view.m_isoview->m_BrushSize_x=1; + m_view.m_isoview->m_BrushSize_y=1; + + } + Sound(SOUND_POSITIVE); + + AD.mode=ACTIONMODE_LOWERTILE; + +} + +void CFinalSunDlg::OnTerrainRaisetile() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + if(AD.mode!=ACTIONMODE_HEIGHTENTILE) + { + m_settingsbar.m_BrushSize=0; + m_settingsbar.UpdateData(FALSE); + m_view.m_isoview->m_BrushSize_x=1; + m_view.m_isoview->m_BrushSize_y=1; + } + Sound(SOUND_POSITIVE); + AD.mode=ACTIONMODE_HEIGHTENTILE; + +} + +void CFinalSunDlg::OnTerrainFlatten() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + if(AD.mode!=ACTIONMODE_FLATTENGROUND) + { + m_settingsbar.m_BrushSize=1; + m_settingsbar.UpdateData(FALSE); + m_view.m_isoview->m_BrushSize_x=2; + m_view.m_isoview->m_BrushSize_y=2; + } + Sound(SOUND_POSITIVE); + + AD.mode=ACTIONMODE_FLATTENGROUND; +} + +void CFinalSunDlg::OnTerrainCloak() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + AD.mode=ACTIONMODE_HIDETILESET; + Sound(SOUND_POSITIVE); +} + +void CFinalSunDlg::OnTerrainShoweverytile() +{ + if(!Map->GetIsoSize()) { + Sound(SOUND_NEGATIVE); + return; + } + + m_view.m_isoview->ShowAllTileSets(); + m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + Sound(SOUND_POSITIVE); +} + +void CFinalSunDlg::OnTerrainShowallfields() +{ + if(!Map->GetIsoSize()) { + Sound(SOUND_NEGATIVE); + return; + } + + int i; + for(i=0;i<Map->GetIsoSize()*Map->GetIsoSize();i++) + { + Map->HideField(i, FALSE); + } + + m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + Sound(SOUND_POSITIVE); +} + +void CFinalSunDlg::OnTerrainHidefield() +{ + if(!Map->GetIsoSize()) { + Sound(SOUND_NEGATIVE); + return; + } + + AD.mode=ACTIONMODE_HIDEFIELD; + Sound(SOUND_POSITIVE); +} + +void CFinalSunDlg::OnEditTriggereditor() +{ + + + if(m_triggereditor.m_hWnd==NULL) + { + if(!m_triggereditor.Create(CTriggerEditorDlg::IDD, NULL)) + { + MessageBox(GetLanguageStringACP("Err_CreateErr"), "Error"); + } + } + + if(m_triggereditor.m_hWnd!=NULL) + { + //m_all.UpdateStrings(); + m_triggereditor.UpdateDialog(); + m_triggereditor.ShowWindow(SW_SHOW); + Sound(SOUND_POSITIVE); + } +} + +void CFinalSunDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + + CDialog::OnKeyDown(nChar, nRepCnt, nFlags); +} + +void CFinalSunDlg::OnMaptoolsChangemapheight() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + Sound(SOUND_POSITIVE); + + int vmin=-MAXHEIGHT; + int vmax=MAXHEIGHT; + + int isosize=Map->GetIsoSize(); + int mapsize=isosize*isosize; + int mapwidth=Map->GetWidth(); + int mapheight=Map->GetHeight(); + int max=Map->GetIsoSize()*Map->GetIsoSize(); + int i; + for(i=0;i<max;i++) + { + int dwX=i%isosize; + int dwY=i/isosize; + + //if(dwX==0 || dwY==0 || dwX+dwY<mapwidth+1 || dwX+dwY+1>mapwidth+mapheight*2 || (dwY+1>mapwidth && dwX<dwY-mapwidth+1) || (dwX+1>mapwidth && dwY+mapwidth<dwX+1)) + //if( dwX<2|| dwY<2 || dwX+dwY<mapwidth+2 || dwX+dwY+2>mapwidth+mapheight*2 || (dwY+2>mapwidth && dwX-2<dwY-mapwidth) || (dwX+2>mapwidth && dwY+mapwidth-2<dwX)) + if( dwX<1|| dwY<1 || dwX+dwY<mapwidth+1 || dwX+dwY>mapwidth+mapheight*2 || (dwY+1>mapwidth && dwX-1<dwY-mapwidth) || (dwX+1>mapwidth && dwY+mapwidth-1<dwX)) + { + + } + else + { + int v=Map->GetHeightAt(i); + if(v+vmin <0) + { + vmin=-v; + } + if(v+vmax>MAXHEIGHT) + { + vmax=MAXHEIGHT-v; + } + } + } + + CString p=GetLanguageStringACP("StrChangeHeight"); + char c[50]; + itoa(vmin, c, 10); + p=TranslateStringVariables(1, p, c); + itoa(vmax, c, 10); + p=TranslateStringVariables(2, p, c); + + CString res=InputBox(p, + GetLanguageStringACP("StrChangeHeightCap")); + + if(res.GetLength()<0) return; + + int a=atoi(res); + if(a==0) return; + + + + + + for(i=0;i<max;i++) + { + int dwX=i%isosize; + int dwY=i/isosize; + + //if(dwX==0 || dwY==0 || dwX+dwY<mapwidth+1 || dwX+dwY+1>mapwidth+mapheight*2 || (dwY+1>mapwidth && dwX<dwY-mapwidth+1) || (dwX+1>mapwidth && dwY+mapwidth<dwX+1)) + //if( dwX<2|| dwY<2 || dwX+dwY<mapwidth+2 || dwX+dwY+2>mapwidth+mapheight*2 || (dwY+2>mapwidth && dwX-2<dwY-mapwidth) || (dwX+2>mapwidth && dwY+mapwidth-2<dwX)) + if( dwX<1|| dwY<1 || dwX+dwY<mapwidth+1 || dwX+dwY>mapwidth+mapheight*2 || (dwY+1>mapwidth && dwX-1<dwY-mapwidth) || (dwX+1>mapwidth && dwY+mapwidth-1<dwX)) + { + + } + else + { + int v=Map->GetHeightAt(i); + if(v+a <0 || v+a>MAXHEIGHT) + { + MessageBox(GetLanguageStringACP("StrChangeHeightErr"), GetLanguageStringACP("StrChangeHeightErrCap"), MB_ICONSTOP); + return; + } + } + } + + for(i=0;i<max;i++) + { + int v=Map->GetHeightAt(i); + Map->SetHeightAt(i, v+a); + } + + this->m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + +void CFinalSunDlg::OnEditGlobalvariables() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + Sound(SOUND_POSITIVE); + CGlobalsDlg dlg; + dlg.DoModal(); + UpdateDialogs(TRUE); +} + +BOOL CFinalSunDlg::PreTranslateMessage(MSG* pMsg) +{ + // CG: Der folgende Block wurde von der Komponente "QuickInfo" hinzugefĂ¼gt. + { + // Diese Nachricht von QuickInfo verarbeiten lassen. + //m_tooltip.RelayEvent(pMsg); + } + return CDialog::PreTranslateMessage(pMsg); // CG: Dies wurde von der Komponente "QuickInfo" hinzugefĂ¼gt. +} + +void CFinalSunDlg::OnEditUndo() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + //int a=0; + //int b=2/a; + //memcpy( (void*)0xddffeedd,&a, 1); + Sound(SOUND_POSITIVE); + Map->Undo(); + //UpdateDialogs(FALSE); + m_view.m_isoview->SendMessage(WM_RBUTTONUP); + m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + +void CFinalSunDlg::OnHelpManual() +{ + Sound(SOUND_POSITIVE); + if(ShellExecuteW(0, NULL, (utf8ToUtf16(AppPath)+L"\\HelpManual.pdf").c_str(), NULL, NULL, SW_NORMAL) == 0) + { + MessageBox((CString)"Could not open HelpManual.pdf! Try opening "+(CString)AppPath+(CString)"\\HelpManual manually."); + } +} + + +LONG __stdcall ExceptionHandler( + _EXCEPTION_POINTERS *ExceptionInfo // address of + // exception info +) +{ + CString s; + CString s2; + CString s_add; + char adress[50]; + char c[50]; + itoa((int)ExceptionInfo->ExceptionRecord->ExceptionAddress, adress, 16); + s="Unknown exception"; + switch(ExceptionInfo->ExceptionRecord->ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + s="EXCEPTION_ACCESS_VIOLATION"; + s2="Thread did not have read or write access to the virtual address."; + if(ExceptionInfo->ExceptionRecord->ExceptionInformation[0]) + { + s_add="\nAdditional information: Write access to 0x"; + } + else + s_add="\nAdditional information: Read access from 0x"; + + itoa(ExceptionInfo->ExceptionRecord->ExceptionInformation[1], c, 16); + + s_add+=c; + + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + s="EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; + s2="Thread tried to access an array out of bounds."; + break; + case EXCEPTION_BREAKPOINT : + s="EXCEPTION_BREAKPOINT"; + s2="Encountered breakpoint."; + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + s="EXCEPTION_DATATYPE_MISALIGNMENT"; + s2="Access to memory was misaligned for the given datatype."; + break; + case EXCEPTION_FLT_DENORMAL_OPERAND: + s="EXCEPTION_FLT_DENORMAL_OPERAND"; + s2="Denormal operand in floating point operation."; + break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + s="EXCEPTION_FLT_DIVIDE_BY_ZERO"; + s2="Thread divided by zero in a floating point operation."; + break; + case EXCEPTION_FLT_INEXACT_RESULT : + s="EXCEPTION_FLT_INEXACT_RESULT"; + s2="Floating point operation result not representable with exact decimal fraction."; + break; + case EXCEPTION_FLT_INVALID_OPERATION: + s="EXCEPTION_FLT_INVALID_OPERATION"; + s2="Invalid floating point operation."; + break; + case EXCEPTION_FLT_OVERFLOW : + s="EXCEPTION_FLT_OVERFLOW"; + s2="Floating point overflow error."; + break; + case EXCEPTION_FLT_STACK_CHECK : + s="EXCEPTION_FLT_STACK_CHECK"; + s2="Floating point operation caused stack overflow or underflow."; + break; + case EXCEPTION_FLT_UNDERFLOW: + s="EXCEPTION_FLT_UNDERFLOW"; + s2="Floating point underflow error."; + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + s="EXCEPTION_ILLEGAL_INSTRUCTION"; + s2="Thread executed illegal instruction."; + break; + case EXCEPTION_IN_PAGE_ERROR: + s="EXCEPTION_IN_PAGE_ERROR"; + s2="Thread tried to access a page that could not be retrieved by the system."; + break; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + s="EXCEPTION_INT_DIVIDE_BY_ZERO"; + s2="Thread divided by zero in an integer operation."; + break; + case EXCEPTION_INT_OVERFLOW: + s="EXCEPTION_INT_OVERFLOW"; + s2="Integer operation caused overflow."; + break; + case EXCEPTION_INVALID_DISPOSITION: + s="EXCEPTION_INVALID_DISPOSITION"; + s2="Exception handler returned invalid disposition."; + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + s="EXCEPTION_NONCONTINUABLE_EXCEPTION"; + s2="Cannot continue execution after a noncontinuable exception."; + break; + case EXCEPTION_PRIV_INSTRUCTION : + s="EXCEPTION_PRIV_INSTRUCTION"; + s2="Instruction not valid in the current machine mode."; + break; + case EXCEPTION_SINGLE_STEP: + s="EXCEPTION_SINGLE_STEP"; + s2="Instruction step has been executed."; + break; + case EXCEPTION_STACK_OVERFLOW: + s="EXCEPTION_STACK_OVERFLOW"; + s2="Stack overflow."; + + } + + CString s3; +#ifdef TS_MODE + s3="INTERNAL APPLICATION ERROR\n\nApplication will now try to free memory, save the current map as \"fcrash_backup.map\" in the FinalSun directory and quit.\n\n\n"; +#else // RA2_MODE + s3="INTERNAL APPLICATION ERROR\n\nApplication will now try to free memory, save the current map as \"fcrash_backup.map\" in the FinalAlert 2 directory and quit.\n\n\n"; +#endif + + s3+="Important: If this error has occured while loading graphics, it can very often be fixed by using another system color resolution (16, 24 or 32 bit)."; + + s3+="\n\nThe following information is available, please note every line below:\n\n"; + s3+="Last succeeded operation: "; + itoa(last_succeeded_operation,c,10); + s3+=c; + s3+=""; + s3+="\nLast library operation: "; + itoa(FSunPackLib::last_succeeded_operation,c,10); + s3+=c; + s3+="\n"; + s3+="\nException data:\n"; + s3+=s; + s3+="\n"; + s3+=s2; + s3+="\nAt address: "; + s3+=adress; + s3+=s_add; + + + errstream << "Exception occured. Current data:" << endl; + errstream << "Last succeeded operation:" << last_succeeded_operation << endl; + errstream << "Last succeeded library operation:" << FSunPackLib::last_succeeded_operation << endl; + errstream << "Trying to save current map" << endl; + errstream.flush(); + + + + if(MessageBox(0,s3,"Fatal error",MB_OKCANCEL)==IDOK) + { + return EXCEPTION_CONTINUE_EXECUTION; + } + + std::string file=u8AppDataPath; + file+="\\fcrash_backup.map"; + ((CFinalSunDlg*)theApp.m_pMainWnd)->SaveMap(file.c_str()); + + theApp.m_loading->FreeAll(); + + rules.Clear(); + ai.Clear(); + art.Clear(); + tiles_t.Clear(); + tiles_s.Clear(); + tiles_u.Clear(); + Map->GetIniFile().Clear(); + sound.Clear(); + tutorial.Clear(); + g_data.Clear(); + language.Clear(); + +#ifdef _DEBUG + return EXCEPTION_CONTINUE_SEARCH; +#endif + + return EXCEPTION_EXECUTE_HANDLER;//EXCEPTION_CONTINUE_SEARCH;//EXCEPTION_EXECUTE_HANDLER; +} + +int CFinalSunDlg::DoModal() +{ + int res=0; + SetUnhandledExceptionFilter(ExceptionHandler); + + res=CDialog::DoModal(); + + return res; +} + +void CFinalSunDlg::OnMaptoolsAutolevel() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + Sound(SOUND_POSITIVE); + MessageBox("This tool will try to automatically raise the terrain using the cliffs.\nIt may take some seconds to execute, as there are masses of data to handle.\nAfter this, you should check your map if everything looks fine. If not, you should use the different height tools, especially flatten ground, to fix any errors. You can use Edit->Undo to undo anything that has been done by using this function.", "Auto Leveler"); + + m_view.m_isoview->AutoLevel(); +} + +void CFinalSunDlg::OnUpdateEditAitriggerenabling(CCmdUI* pCmdUI) +{ + + /*if(Map->GetIsoSize()==0) pCmdUI->Enable(FALSE); + else pCmdUI->Enable(TRUE);*/ + +} + +void CFinalSunDlg::OnUpdateEditAitriggers(CCmdUI* pCmdUI) +{ + /*if(Map->GetIsoSize()==0) pCmdUI->Enable(FALSE); + else pCmdUI->Enable(TRUE);*/ +} + +void CFinalSunDlg::OnUpdateEditBasicsettings(CCmdUI* pCmdUI) +{ + /*if(Map->GetIsoSize()==0) pCmdUI->Enable(FALSE); + else pCmdUI->Enable(TRUE);*/ +} + +void CFinalSunDlg::OnUpdateEditGlobalvariables(CCmdUI* pCmdUI) +{ + /*if(Map->GetIsoSize()==0) pCmdUI->Enable(FALSE); + else pCmdUI->Enable(TRUE);*/ +} + +void CFinalSunDlg::OnUpdateEditHouses(CCmdUI* pCmdUI) +{ + CheckAvail(pCmdUI); +} + +void CFinalSunDlg::OnUpdateEditIniediting(CCmdUI* pCmdUI) +{ + + CheckAvail(pCmdUI); + +} + +void CFinalSunDlg::OnUpdateEditLighting(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditMap(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditScripts(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditSingleplayersettings(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditSpecialflags(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditTags(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditTaskforces(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditTeams(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditTriggereditor(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditTriggers(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateEditUndo(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateFileSave(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateFileSaveas(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateFileValidatemap(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateMaptoolsAutolevel(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateMaptoolsChangemapheight(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateOptionsShowminimap(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateTerrainCloak(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateTerrainFlatten(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateTerrainHeightenground(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateTerrainHidefield(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateTerrainLowerground(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateTerrainLowertile(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateTerrainRaisetile(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateTerrainShowallfields(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnUpdateTerrainShoweverytile(CCmdUI* pCmdUI) +{ + // TODO: Code fĂ¼r die Befehlsbehandlungsroutine zum Aktualisieren der Benutzeroberfläche hier einfĂ¼gen + +} + +void CFinalSunDlg::OnMaptoolsFrontcliff() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + if(Map->GetTheater()==THEATER4) + { + MessageBox("There are no cliffs in the Lunar theater"); + return; + } + + Sound(SOUND_POSITIVE); + AD.mode=ACTIONMODE_CLIFFFRONT; +} + +void CFinalSunDlg::OnMaptoolsBackcliff() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + if(Map->GetTheater()==THEATER4) + { + MessageBox("There are no cliffs in the Lunar theater"); + return; + } + + Sound(SOUND_POSITIVE); + AD.mode=ACTIONMODE_CLIFFBACK; +} + +void CFinalSunDlg::OnEditRedo() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + Sound(SOUND_POSITIVE); + Map->Redo(); + + m_view.m_isoview->SendMessage(WM_RBUTTONUP); + m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + +void CFinalSunDlg::OnMaptoolsAutocreateshores() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + Sound(SOUND_POSITIVE); + + Map->TakeSnapshot(); + + Map->CreateShore(0,0,Map->GetIsoSize(), Map->GetIsoSize()); + m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + Map->TakeSnapshot(); + Map->Undo(); + +} + +void CFinalSunDlg::OnOptionsDisableautoshore() +{ + + CIniFile Options; + Options.LoadFile(u8AppDataPath+"\\FinalSun.ini"); +#ifdef RA2_MODE + Options.LoadFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif + + if(GetMenu()->GetMenuState(ID_OPTIONS_DISABLEAUTOSHORE, MF_BYCOMMAND) & MF_CHECKED) + { + GetMenu()->CheckMenuItem(ID_OPTIONS_DISABLEAUTOSHORE, MF_BYCOMMAND | MF_UNCHECKED); + theApp.m_Options.bDisableAutoShore=FALSE; + Options.sections["UserInterface"].values["DisableAutoShore"]="0"; + } + else + { + GetMenu()->CheckMenuItem(ID_OPTIONS_DISABLEAUTOSHORE, MF_BYCOMMAND | MF_CHECKED); + theApp.m_Options.bDisableAutoShore=TRUE; + Options.sections["UserInterface"].values["DisableAutoShore"]="1"; + } + + +#ifndef RA2_MODE + Options.SaveFile(u8AppDataPath+"\\FinalSun.ini"); +#else + Options.SaveFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif + +} + + + + + +//DEL void CFinalSunDlg::OnNcPaint() +//DEL { +//DEL CBitmap b; +//DEL b.LoadBitmap(IDB_TEXTURE1); +//DEL CDC dc; +//DEL +//DEL +//DEL CDC* target=GetWindowDC(); +//DEL dc.CreateCompatibleDC(target); +//DEL dc.SelectObject(b); +//DEL +//DEL BITMAP bd; +//DEL b.GetBitmap(&bd); +//DEL +//DEL RECT r; +//DEL GetWindowRect(&r); +//DEL +//DEL int count=(r.right-r.left)/bd.bmWidth+1; +//DEL int i; +//DEL for(i=0;i<count;i++) +//DEL { +//DEL target->BitBlt(i*bd.bmWidth,0,bd.bmWidth, bd.bmHeight-1, &dc, 0, 0, SRCCOPY); +//DEL } +//DEL +//DEL ReleaseDC(target); +//DEL +//DEL CMenu* m=GetMenu(); +//DEL if(m) +//DEL { +//DEL count=m->GetMenuItemCount(); +//DEL for(i=0;i<count;i++) +//DEL { +//DEL DRAWITEMSTRUCT t; +//DEL t.CtlType=ODT_MENU; +//DEL t.itemID=m->GetMenuItemID(i); +//DEL t.itemAction=ODA_DRAWENTIRE; +//DEL t.itemState=ODS_DEFAULT; +//DEL t.hwndItem=(HWND)m->m_hMenu; +//DEL t.rcItem=r; +//DEL CString text; +//DEL m->GetMenuString(t.itemID, text, MF_BYCOMMAND); +//DEL t.itemData=(int)(LPCSTR)text; +//DEL +//DEL m->DrawItem(&t); +//DEL } +//DEL } +//DEL +//DEL +//DEL +//DEL dc.DeleteDC(); +//DEL b.DeleteObject(); +//DEL +//DEL // Kein Aufruf von CDialog::OnNcPaint() fĂ¼r Zeichnungsnachrichten +//DEL } + +void CFinalSunDlg::OnOptionsDisableautolat() +{ + CIniFile Options; + Options.LoadFile(u8AppDataPath+"\\FinalSun.ini"); +#ifdef RA2_MODE + Options.LoadFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif + + if(GetMenu()->GetMenuState(ID_OPTIONS_DISABLEAUTOLAT, MF_BYCOMMAND) & MF_CHECKED) + { + GetMenu()->CheckMenuItem(ID_OPTIONS_DISABLEAUTOLAT, MF_BYCOMMAND | MF_UNCHECKED); + theApp.m_Options.bDisableAutoLat=FALSE; + Options.sections["UserInterface"].values["DisableAutoLat"]="0"; + } + else + { + GetMenu()->CheckMenuItem(ID_OPTIONS_DISABLEAUTOLAT, MF_BYCOMMAND | MF_CHECKED); + theApp.m_Options.bDisableAutoLat=TRUE; + Options.sections["UserInterface"].values["DisableAutoLat"]="1"; + } + + +#ifndef RA2_MODE + Options.SaveFile(u8AppDataPath+"\\FinalSun.ini"); +#else + Options.SaveFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif +} + +void CFinalSunDlg::OnEditPaste() +{ + Sound(SOUND_POSITIVE); + AD.mode=ACTIONMODE_PASTE; + AD.z_data=0; +} + +void CFinalSunDlg::OnEditCopy() +{ + Sound(SOUND_POSITIVE); + AD.mode=ACTIONMODE_COPY; +} + +void CFinalSunDlg::OnEditCopywholemap() +{ + Sound(SOUND_POSITIVE); + Map->Copy(); +} + +void CFinalSunDlg::OnEditPastewholemap() +{ + Sound(SOUND_POSITIVE); + Map->Paste(Map->GetIsoSize()/2,Map->GetIsoSize()/2,0); + m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + +void CFinalSunDlg::OnMarblemadness() +{ + if(Map->GetIsoSize()==0) + { + Sound(SOUND_NEGATIVE); + return; + } + + Sound(SOUND_POSITIVE); + + theApp.m_Options.bMarbleMadness=! theApp.m_Options.bMarbleMadness; + + m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + m_view.m_browser->m_view.SetTileSet(m_view.m_browser->m_view.m_currentTileSet, TRUE); +} + +void CFinalSunDlg::CheckAvail(CCmdUI *pCmdUI) +{ + /*if(Map->GetIsoSize()==0) + { + pCmdUI->Enable(FALSE); + + if(pCmdUI->m_pMenu) + { + pCmdUI->m_pMenu->DeleteMenu(pCmdUI->m_nIndex, MF_BYPOSITION); + } + } + else + { + pCmdUI->Enable(TRUE); + + + if(pCmdUI->m_pMenu) + { + pCmdUI->m_pMenu->ModifyMenu(pCmdUI->m_nID, MF_BYCOMMAND | MF_ENABLED); + } + }*/ +} + +void CFinalSunDlg::OnOptionsSounds() +{ + CIniFile Options; + Options.LoadFile(u8AppDataPath+"\\FinalSun.ini"); +#ifdef RA2_MODE + Options.LoadFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif + + if(GetMenu()->GetMenuState(ID_OPTIONS_SOUNDS, MF_BYCOMMAND) & MF_CHECKED) + { + GetMenu()->CheckMenuItem(ID_OPTIONS_SOUNDS, MF_BYCOMMAND | MF_UNCHECKED); + theApp.m_Options.bNoSounds=TRUE; + Options.sections["UserInterface"].values["Sounds"]="0"; + } + else + { + GetMenu()->CheckMenuItem(ID_OPTIONS_SOUNDS, MF_BYCOMMAND | MF_CHECKED); + theApp.m_Options.bNoSounds=FALSE; + Options.sections["UserInterface"].values["Sounds"]="1"; + } + + +#ifndef RA2_MODE + Options.SaveFile(u8AppDataPath+"\\FinalSun.ini"); +#else + Options.SaveFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif +} + +void CFinalSunDlg::OnUpdateOptionsSounds(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(theApp.m_Options.bNoSounds ? 0 : 1); +} + +void CFinalSunDlg::OnOptionsDisableslopecorrection() +{ + CIniFile Options; + Options.LoadFile(u8AppDataPath +"\\FinalSun.ini"); +#ifdef RA2_MODE + Options.LoadFile(u8AppDataPath +"\\FinalAlert.ini"); +#endif + + if(GetMenu()->GetMenuState(ID_OPTIONS_DISABLESLOPECORRECTION, MF_BYCOMMAND) & MF_CHECKED) + { + GetMenu()->CheckMenuItem(ID_OPTIONS_DISABLESLOPECORRECTION, MF_BYCOMMAND | MF_UNCHECKED); + theApp.m_Options.bDisableSlopeCorrection=FALSE; + Options.sections["UserInterface"].values["DisableSlopeCorrection"]="0"; + } + else + { + GetMenu()->CheckMenuItem(ID_OPTIONS_DISABLESLOPECORRECTION, MF_BYCOMMAND | MF_CHECKED); + theApp.m_Options.bDisableSlopeCorrection=TRUE; + Options.sections["UserInterface"].values["DisableSlopeCorrection"]="1"; + } + +#ifndef RA2_MODE + Options.SaveFile(u8AppDataPath+"\\FinalSun.ini"); +#else + Options.SaveFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif +} + +void CFinalSunDlg::OnOptionsShowbuildingoutline() +{ + + + CIniFile Options; + Options.LoadFile(u8AppDataPath+"\\FinalSun.ini"); +#ifdef RA2_MODE + Options.LoadFile(u8AppDataPath+"\\FinalAlert.ini"); +#endif + + if(GetMenu()->GetMenuState(ID_OPTIONS_SHOWBUILDINGOUTLINE, MF_BYCOMMAND) & MF_CHECKED) + { + GetMenu()->CheckMenuItem(ID_OPTIONS_SHOWBUILDINGOUTLINE, MF_BYCOMMAND | MF_UNCHECKED); + theApp.m_Options.bShowCells=FALSE; + Options.sections["UserInterface"].values["ShowBuildingCells"]="0"; + } + else + { + GetMenu()->CheckMenuItem(ID_OPTIONS_SHOWBUILDINGOUTLINE, MF_BYCOMMAND | MF_CHECKED); + theApp.m_Options.bShowCells=TRUE; + Options.sections["UserInterface"].values["ShowBuildingCells"]="1"; + } + + m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + +#ifndef RA2_MODE + Options.SaveFile(u8AppDataPath +"\\FinalSun.ini"); +#else + Options.SaveFile(u8AppDataPath +"\\FinalAlert.ini"); +#endif +} + + +void CFinalSunDlg::OnFileFile1() +{ + if(DoesFileExist(theApp.m_Options.prev_maps[0])) OpenMap(theApp.m_Options.prev_maps[0]); + +} + +void CFinalSunDlg::OnFileFile2() +{ + if(DoesFileExist(theApp.m_Options.prev_maps[1])) OpenMap(theApp.m_Options.prev_maps[1]); + +} + +void CFinalSunDlg::OnFileFile3() +{ + if(DoesFileExist(theApp.m_Options.prev_maps[2])) OpenMap(theApp.m_Options.prev_maps[2]); + +} + +void CFinalSunDlg::OnFileFile4() +{ + if(DoesFileExist(theApp.m_Options.prev_maps[3])) OpenMap(theApp.m_Options.prev_maps[3]); + +} + +// MW 07/20/01: Checks if file already exists in prev. files list. If not, adds it (may delete old ones) +void CFinalSunDlg::InsertPrevFile(CString lpFilename) +{ + int i; + + //int free_at=-1; + for(i=0;i<4;i++) + { + CString f=theApp.m_Options.prev_maps[i]; + CString f2=lpFilename; + f2.MakeLower(); + f.MakeLower(); + + if(f==f2) + { + return; + } + + /*if(free_at<0) + { + if(theApp.m_Options.prev_maps[i].GetLength()==0) + { + free_at=i; + } + }*/ + } + + CIniFile Options; + Options.LoadFile(u8AppDataPath +"\\FinalSun.ini"); +#ifdef RA2_MODE + Options.LoadFile(u8AppDataPath +"\\FinalAlert.ini"); +#endif + + + + + + + for(i=3;i>0;i--) + { + theApp.m_Options.prev_maps[i]=theApp.m_Options.prev_maps[i-1]; + char e[10]; + itoa(i, e, 10); + + Options.sections["Files"].values[e]=theApp.m_Options.prev_maps[i]; + } + + theApp.m_Options.prev_maps[0]=lpFilename; + Options.sections["Files"].values["0"]=theApp.m_Options.prev_maps[0]; + + + +#ifndef RA2_MODE + Options.SaveFile(u8AppDataPath +"\\FinalSun.ini"); +#else + Options.SaveFile(u8AppDataPath +"\\FinalAlert.ini"); +#endif + + UpdateStrings(); +} + +// MW 07/20/01: New: for files clicked in the file list... copied from OnFileOpenmap(); +void CFinalSunDlg::OpenMap(LPCSTR lpFilename) +{ + CString r=GetLanguageStringACP("SAVEDLG_FILETYPES"); + r=TranslateStringVariables(8, r, ";"); + //CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST, r); + + char cuPath[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, cuPath); + //dlg.m_ofn.lpstrInitialDir=cuPath; + + //if(theApp.m_Options.TSExe.GetLength()) dlg.m_ofn.lpstrInitialDir=(char*)(LPCTSTR)theApp.m_Options.TSExe; + + + //if(dlg.DoModal()==IDCANCEL) return; + + + m_PKTHeader.Clear(); + + CString fileToOpen=lpFilename;//dlg.GetPathName(); + fileToOpen.MakeLower(); + CString ext=fileToOpen.Right(fileToOpen.GetLength()-fileToOpen.ReverseFind('.')-1); //dlg.GetFileExt(); + + ext.MakeLower(); + BOOL bLoadedFromMMX=FALSE; + if(ext=="mmx") + { + HMIXFILE hMix=FSunPackLib::XCC_OpenMix(fileToOpen, NULL); + fileToOpen.Replace(".mmx", ".map"); + + if(fileToOpen.ReverseFind('\\')>=0) fileToOpen=fileToOpen.Right(fileToOpen.GetLength()-fileToOpen.ReverseFind('\\')-1); + + CString extractFile=u8AppDataPath.c_str(); + CString pktFile=fileToOpen; + pktFile.Replace(".map", ".pkt"); + extractFile+="\\mmx_tmp.pkt"; + + FSunPackLib::XCC_ExtractFile(pktFile, extractFile, hMix); + m_PKTHeader.LoadFile(extractFile, TRUE); + fileToOpen=m_PKTHeader.sections["MultiMaps"].values["1"]+".map"; + + + + extractFile=u8AppDataPath.c_str(); + extractFile+="\\mmx_tmp.map"; + FSunPackLib::XCC_ExtractFile(fileToOpen, extractFile, hMix); + fileToOpen=extractFile; + + + + FSunPackLib::XCC_CloseMix(hMix); + bLoadedFromMMX=TRUE; + } + + CIniFile f; + f.InsertFile(fileToOpen, "Map"); + if((f.sections["Map"].values["Theater"]==THEATER0 && theApp.m_Options.bDoNotLoadTemperateGraphics) || (f.sections["Map"].values["Theater"]==THEATER1 && theApp.m_Options.bDoNotLoadSnowGraphics)) + { + MessageBox("You have selected to don´t show temperate or snow theater, but this map uses this theater. You cannot load it without restarting FinalSun/FinalAlert 2 with this theater enabled.", "Error"); + return; + } + + bNoDraw=TRUE; + + CString str = GetLanguageStringACP("MainDialogCaption"); + str+=" ("; + str+=(char*)(LPCTSTR)lpFilename; + str+=")"; + + // MW 07/20/01: Update prev. files + InsertPrevFile(lpFilename); + + this->SetWindowText(str); + + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + errstream << "Map->LoadMap() will be called" << endl; + errstream.flush(); + + + + Map->LoadMap((char*)(LPCTSTR)fileToOpen); + + + BOOL bNoMapFile=FALSE; + if(!Map->CheckMapPackData()) + { + int res=MessageBox("This map seems to be corrupt. Do you want to try repairing it? If you click cancel, a empty map will be created, if you click no, it will load the map as it is","Corrupt", MB_YESNOCANCEL); + if(res==IDCANCEL) + { + Map->CreateMap(32,32,THEATER0,0); + bNoMapFile=TRUE; + } + else + { + if(res==IDYES) // try repair + { + int fielddata_size=Map->GetIsoSize()*Map->GetIsoSize(); + + int i; + for(i=0;i<fielddata_size;i++) + { + int gr=Map->GetFielddataAt(i)->wGround; + if(gr==0xFFFF) gr=0; + + if(gr>=(*tiledata_count)) + { + Map->SetTileAt(i, 0, 0); + } + else + { + if((*tiledata)[gr].wTileCount<=Map->GetFielddataAt(i)->bSubTile) + { + Map->SetTileAt(i, 0, 0); + } + } + } + + } + } + } + + if(!bNoMapFile) + { + if(bLoadedFromMMX) + { + //currentMapFile[0]=0; + strcpy(currentMapFile, lpFilename); + } + else + strcpy(currentMapFile, fileToOpen); + } + + Sleep(200); + + SetCursor(m_hArrowCursor); + + + bNoDraw=FALSE; + + m_view.m_isoview->UpdateDialog(TRUE); + UpdateDialogs(); + +} + +void CFinalSunDlg::OnMaptoolsSearchwaypoint() +{ + if(Map->GetIsoSize()==0) return; + + CSearchWaypointDlg dlg; + if(dlg.DoModal()==IDCANCEL) return; + if(dlg.m_WaypointIndex<0) return; + + m_view.m_isoview->FocusWaypoint(dlg.m_WaypointIndex); +} + +void CFinalSunDlg::OnMaptoolsToolscripts() +{ + if(Map->GetIsoSize()==0) return; + + CUserScriptsDlg dlg; + dlg.DoModal(); + +} + + +void CFinalSunDlg::OnHelpShowlogs() +{ + // TODO: FĂ¼gen Sie hier Ihren Befehlshandlercode ein. + + Sound(SOUND_POSITIVE); + errstream.flush(); + auto f = utf8ToUtf16(theApp.getLogFileName()); + if (ShellExecuteW(0, NULL, f.c_str(), NULL, NULL, SW_NORMAL) == 0) + { + MessageBoxW(nullptr, (std::wstring(L"Could not open log! Try opening ") + f + L" manually").c_str(), L"Cannot open log", MB_ICONEXCLAMATION); + } +} + + +void CFinalSunDlg::OnOptionsSmoothzoom() +{ + CIniFile Options; + Options.LoadFile(u8AppDataPath + "\\FinalSun.ini"); +#ifdef RA2_MODE + Options.LoadFile(u8AppDataPath + "\\FinalAlert.ini"); +#endif + + if (GetMenu()->GetMenuState(ID_OPTIONS_SMOOTHZOOM, MF_BYCOMMAND) & MF_CHECKED) + { + GetMenu()->CheckMenuItem(ID_OPTIONS_SMOOTHZOOM, MF_BYCOMMAND | MF_UNCHECKED); + theApp.m_Options.viewScaleUseSteps = true; + } + else + { + GetMenu()->CheckMenuItem(ID_OPTIONS_SMOOTHZOOM, MF_BYCOMMAND | MF_CHECKED); + theApp.m_Options.viewScaleUseSteps = false; + } + + Options.sections["UserInterface"].values["ViewScaleUseSteps"] = theApp.m_Options.viewScaleUseSteps ? "1" : "0"; + +#ifndef RA2_MODE + Options.SaveFile(u8AppDataPath + "\\FinalSun.ini"); +#else + Options.SaveFile(u8AppDataPath + "\\FinalAlert.ini"); +#endif +} + + +BOOL CFinalSunDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + if (!CDialog::OnSetCursor(pWnd, nHitTest, message)) + SetCursor(m_hArrowCursor); + return TRUE; +} + + + +void CFinalSunDlg::OnOptionsUsedefaultmousecursor() +{ + CIniFile Options; + Options.LoadFile(u8AppDataPath + "\\FinalSun.ini"); +#ifdef RA2_MODE + Options.LoadFile(u8AppDataPath + "\\FinalAlert.ini"); +#endif + + if (GetMenu()->GetMenuState(ID_OPTIONS_USEDEFAULTMOUSECURSOR, MF_BYCOMMAND) & MF_CHECKED) + { + GetMenu()->CheckMenuItem(ID_OPTIONS_USEDEFAULTMOUSECURSOR, MF_BYCOMMAND | MF_UNCHECKED); + theApp.m_Options.useDefaultMouseCursor = false; + m_hArrowCursor = m_hGameCursor; + } + else + { + GetMenu()->CheckMenuItem(ID_OPTIONS_USEDEFAULTMOUSECURSOR, MF_BYCOMMAND | MF_CHECKED); + theApp.m_Options.useDefaultMouseCursor = true; + m_hArrowCursor = LoadCursor(NULL, IDC_ARROW); + } + + Options.sections["UserInterface"].values["UseDefaultMouseCursor"] = theApp.m_Options.useDefaultMouseCursor ? "1" : "0"; + +#ifndef RA2_MODE + Options.SaveFile(u8AppDataPath + "\\FinalSun.ini"); +#else + Options.SaveFile(u8AppDataPath + "\\FinalAlert.ini"); +#endif +} diff --git a/MissionEditor/FinalSunDlg.h b/MissionEditor/FinalSunDlg.h new file mode 100644 index 0000000..20081c1 --- /dev/null +++ b/MissionEditor/FinalSunDlg.h @@ -0,0 +1,254 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// +// Header-Datei +// + +#if !defined(AFX_TIBERIANSUNMISSIONEDITORDLG_H__9F773424_63BB_11D3_99E0_C30F10710B17__INCLUDED_) +#define AFX_TIBERIANSUNMISSIONEDITORDLG_H__9F773424_63BB_11D3_99E0_C30F10710B17__INCLUDED_ + +#include "ScriptTypes.h" +#include "Triggers.h" +#include "Houses.h" +#include "Basic.h" +#include "all.h" +#include "mapd.h" +#include "Lighting.h" +#include "SpecialFlags.h" +#include "IsoView.h" +#include "TeamTypes.h" +#include "TaskForce.h" +#include "tags.h" +#include "myviewframe.h" +#include "AiTriggerTypesEnable.h" +#include "AITriggerTypes.h" +#include "resource.h" +#include "SingleplayerSettings.h" // HinzugefĂ¼gt von der Klassenansicht +#include "loading.h" +#include "TileSetBrowserFrame.h" // HinzugefĂ¼gt von der Klassenansicht +#include "ToolSettingsBar.h" +#include "TriggerEditorDlg.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class CLoading; + +///////////////////////////////////////////////////////////////////////////// +// CFinalSunDlg Dialogfeld + +class CFinalSunDlg : public CDialog +{ +// Konstruktion +public: + void OpenMap(LPCSTR lpFilename); + void InsertPrevFile(CString lpFilename); + void CheckAvail(CCmdUI* pCmdUI); + virtual BOOL PreTranslateMessage(MSG* pMsg); + CTileSetBrowserFrame m_TerrainDlg; + void RecalcLayout(); + CToolBar m_clifftoolbar; + CToolBar m_terraintoolbar; + CToolBar m_maintoolbar; + CToolSettingsBar m_settingsbar; + CReBarCtrl m_bar; + void HideAllDialogs(); + CSingleplayerSettings m_singleplayersettings; + void UpdateStrings(); + CAITriggerTypes m_aitriggertypes; + CAiTriggerTypesEnable m_aitriggertypesenable; + void SetText(const char* text); + void SaveMap(CString FileName); + void SetReady(); + CScriptTypes m_Scripttypes; + CTriggers m_triggers; + CTriggerEditorDlg m_triggereditor; + CTags m_tags; + CTaskForce m_taskforces; + CTeamTypes m_teamtypes; + + CHouses m_houses; + + CSplitterWnd m_splitter_view; + CMyViewFrame m_view; + CSpecialFlags m_specialflags; + CLighting m_lighting; + void UpdateDialogs(BOOL bOnlyMissionControl=FALSE, BOOL bNoRepos=FALSE); + CAll m_all; + CBasic m_basic; + CMapD m_map; + CIniFile m_PKTHeader; + CFinalSunDlg(CWnd* pParent = NULL); // Standard-Konstruktor + +// Dialogfelddaten + //{{AFX_DATA(CFinalSunDlg) + enum { IDD = IDD_FINALSUN_DIALOG }; + CTabCtrl m_TabCtrl; + //}}AFX_DATA + + // Vom Klassenassistenten generierte Ăœberladungen virtueller Funktionen + //{{AFX_VIRTUAL(CFinalSunDlg) + public: + virtual BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult); + virtual int DoModal(); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); + //}}AFX_VIRTUAL + +// Implementierung +protected: + HICON m_hIcon; + + // Generierte Message-Map-Funktionen + //{{AFX_MSG(CFinalSunDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnFileQuit(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + virtual void OnOK(); + virtual void OnCancel(); + afx_msg void OnOptionsTiberiansunoptions(); + afx_msg void OnFileOpenmap(); + afx_msg void OnFileSaveas(); + afx_msg void OnOptionsExportrulesini(); + afx_msg void OnHelpInfo(); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + afx_msg void OnFileSave(); + afx_msg void OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu); + afx_msg void OnFileRuntiberiansun(); + afx_msg void OnFileImportmod(); + afx_msg void OnDebugExportmappacknosections(); + afx_msg void OnDebugExportmappack(); + afx_msg void OnFileNew(); + afx_msg void OnHelpTipoftheday(); + afx_msg void OnOptionsSimpleview(); + afx_msg void OnOptionsShowminimap(); + afx_msg void OnFileValidatemap(); + afx_msg void OnEnterIdle(UINT nWhy, CWnd* pWho); + afx_msg void OnEditBasicsettings(); + afx_msg void OnEditSingleplayersettings(); + afx_msg void OnSizing(UINT fwSide, LPRECT pRect); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnEditHouses(); + afx_msg void OnEditAitriggers(); + afx_msg void OnEditAitriggerenabling(); + afx_msg void OnEditIniediting(); + afx_msg void OnEditLighting(); + afx_msg void OnEditMap(); + afx_msg void OnEditScripts(); + afx_msg void OnEditSpecialflags(); + afx_msg void OnEditTags(); + afx_msg void OnEditTaskforces(); + afx_msg void OnEditTeams(); + afx_msg void OnEditTriggers(); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnTerrainHeightenground(); + afx_msg void OnTerrainLowerground(); + afx_msg void OnTerrainLowertile(); + afx_msg void OnTerrainRaisetile(); + afx_msg void OnTerrainFlatten(); + afx_msg void OnTerrainCloak(); + afx_msg void OnTerrainShoweverytile(); + afx_msg void OnTerrainShowallfields(); + afx_msg void OnTerrainHidefield(); + afx_msg void OnEditTriggereditor(); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnMaptoolsChangemapheight(); + afx_msg void OnEditGlobalvariables(); + afx_msg void OnEditUndo(); + afx_msg void OnHelpManual(); + afx_msg void OnMaptoolsAutolevel(); + afx_msg void OnUpdateEditAitriggerenabling(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditAitriggers(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditBasicsettings(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditGlobalvariables(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditHouses(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditIniediting(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditLighting(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditMap(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditScripts(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditSingleplayersettings(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditSpecialflags(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditTags(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditTaskforces(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditTeams(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditTriggereditor(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditTriggers(CCmdUI* pCmdUI); + afx_msg void OnUpdateEditUndo(CCmdUI* pCmdUI); + afx_msg void OnUpdateFileSave(CCmdUI* pCmdUI); + afx_msg void OnUpdateFileSaveas(CCmdUI* pCmdUI); + afx_msg void OnUpdateFileValidatemap(CCmdUI* pCmdUI); + afx_msg void OnUpdateMaptoolsAutolevel(CCmdUI* pCmdUI); + afx_msg void OnUpdateMaptoolsChangemapheight(CCmdUI* pCmdUI); + afx_msg void OnUpdateOptionsShowminimap(CCmdUI* pCmdUI); + afx_msg void OnUpdateTerrainCloak(CCmdUI* pCmdUI); + afx_msg void OnUpdateTerrainFlatten(CCmdUI* pCmdUI); + afx_msg void OnUpdateTerrainHeightenground(CCmdUI* pCmdUI); + afx_msg void OnUpdateTerrainHidefield(CCmdUI* pCmdUI); + afx_msg void OnUpdateTerrainLowerground(CCmdUI* pCmdUI); + afx_msg void OnUpdateTerrainLowertile(CCmdUI* pCmdUI); + afx_msg void OnUpdateTerrainRaisetile(CCmdUI* pCmdUI); + afx_msg void OnUpdateTerrainShowallfields(CCmdUI* pCmdUI); + afx_msg void OnUpdateTerrainShoweverytile(CCmdUI* pCmdUI); + afx_msg void OnMaptoolsFrontcliff(); + afx_msg void OnMaptoolsBackcliff(); + afx_msg void OnEditRedo(); + afx_msg void OnMaptoolsAutocreateshores(); + afx_msg void OnOptionsDisableautoshore(); + afx_msg void OnOptionsDisableautolat(); + afx_msg void OnEditPaste(); + afx_msg void OnEditCopy(); + afx_msg void OnEditCopywholemap(); + afx_msg void OnEditPastewholemap(); + afx_msg void OnMarblemadness(); + afx_msg void OnOptionsSounds(); + afx_msg void OnUpdateOptionsSounds(CCmdUI* pCmdUI); + afx_msg void OnOptionsDisableslopecorrection(); + afx_msg void OnOptionsShowbuildingoutline(); + afx_msg void OnFileFile1(); + afx_msg void OnFileFile2(); + afx_msg void OnFileFile3(); + afx_msg void OnFileFile4(); + afx_msg void OnMaptoolsSearchwaypoint(); + afx_msg void OnMaptoolsToolscripts(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + void UnloadAll(); + + HCURSOR m_hGameCursor; + +public: + afx_msg void OnHelpShowlogs(); + afx_msg void OnOptionsSmoothzoom(); + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); + afx_msg void OnOptionsUsedefaultmousecursor(); +}; + +extern HCURSOR m_hArrowCursor; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // !defined(AFX_TIBERIANSUNMISSIONEDITORDLG_H__9F773424_63BB_11D3_99E0_C30F10710B17__INCLUDED_) diff --git a/MissionEditor/FloatEdit.cpp b/MissionEditor/FloatEdit.cpp new file mode 100644 index 0000000..e722aaf --- /dev/null +++ b/MissionEditor/FloatEdit.cpp @@ -0,0 +1,102 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// +// FloatEdit.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "FloatEdit.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CFloatEdit + +CFloatEdit::CFloatEdit() +{ +} + +CFloatEdit::~CFloatEdit() +{ +} + + +BEGIN_MESSAGE_MAP(CFloatEdit, CEdit) + //{{AFX_MSG_MAP(CFloatEdit) + ON_WM_ACTIVATE() + ON_CONTROL_REFLECT(EN_KILLFOCUS, OnKillfocus) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CFloatEdit + + + + + + +void CFloatEdit::OnKillfocus() +{ + + // okay, we need to convert it to a float + CString text, originaltext; + GetWindowText(text); + originaltext=text; + + if(strlen(text)<1) + { + //SetWindowText("0.000000"); + return; + } + + double res=atof(text); + int c,d; + char* j=_fcvt(res, 6, &c, &d); + + int i, slen=strlen(j); + char j2[50]; + + for(i=0;i<6-slen;i++) + { + strcpy(j2, j+i); + j[i]=0; + strcat(j, "0"); + strcat(j,j2); + } + + if(j==NULL) return; + //MessageBox(j,text); + text=j; + text.Insert(c, "."); + + //MessageBox(text); + if(strchr(text, '.')==text) text.Insert(0, "0"); + //delete[](j); + if(originaltext==text) return; + SetWindowText(text); + +} diff --git a/MissionEditor/FloatEdit.h b/MissionEditor/FloatEdit.h new file mode 100644 index 0000000..ef315bf --- /dev/null +++ b/MissionEditor/FloatEdit.h @@ -0,0 +1,68 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_FLOATEDIT_H__D0F98066_6E8E_11D3_99E1_D18E6230AA05__INCLUDED_) +#define AFX_FLOATEDIT_H__D0F98066_6E8E_11D3_99E1_D18E6230AA05__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// FloatEdit.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Fenster CFloatEdit + +class CFloatEdit : public CEdit +{ +// Konstruktion +public: + CFloatEdit(); + +// Attribute +public: + +// Operationen +public: + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CFloatEdit) + //}}AFX_VIRTUAL + +// Implementierung +public: + virtual ~CFloatEdit(); + + // Generierte Nachrichtenzuordnungsfunktionen +protected: + //{{AFX_MSG(CFloatEdit) + afx_msg void OnKillfocus(); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_FLOATEDIT_H__D0F98066_6E8E_11D3_99E1_D18E6230AA05__INCLUDED_ diff --git a/MissionEditor/FrontCliffModifier.cpp b/MissionEditor/FrontCliffModifier.cpp new file mode 100644 index 0000000..b195d88 --- /dev/null +++ b/MissionEditor/FrontCliffModifier.cpp @@ -0,0 +1,103 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// FrontCliffModifier.cpp: Implementierung der Klasse CFrontCliffModifier. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "stdafx.h" +#include "FrontCliffModifier.h" +#include <vector> +#include "variables.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Konstruktion/Destruktion +////////////////////////////////////////////////////////////////////// + +CFrontCliffModifier::CFrontCliffModifier() +{ + +} + +CFrontCliffModifier::~CFrontCliffModifier() +{ + +} + + + + + +void CFrontCliffModifier::ModifyStartPos(DWORD *dwStartPos, BOOL bSmall) +{ + + if(m_direction==cd_horiz_right) (*dwStartPos)-=1+0*Map->GetIsoSize(); + if(m_direction==cd_horiz_left) (*dwStartPos)+=-(1)+Map->GetIsoSize(); + if(m_direction==cd_vertic_top) (*dwStartPos)-=-1+0*Map->GetIsoSize(); + if(m_direction==cd_vertic_bottom) (*dwStartPos)-=0*Map->GetIsoSize(); + + if(m_direction==cd_verticdiag_top) (*dwStartPos)+=1+Map->GetIsoSize(); + if(m_direction==cd_verticdiag_bottom) (*dwStartPos)+=0-Map->GetIsoSize(); + + + if(m_direction==cd_horizdiag_right) (*dwStartPos)+=1+0*Map->GetIsoSize(); + if(m_direction==cd_horizdiag_left) (*dwStartPos)+=0+1*Map->GetIsoSize(); +} + +void CFrontCliffModifier::ModifyCurrentPos(DWORD *dwPos, BOOL bBeforePlacing, BOOL bSmall) +{ + if(!bBeforePlacing) + { + if(!bSmall) + { + if(m_direction==cd_verticdiag_top) (*dwPos)+=0+2*Map->GetIsoSize(); + if(m_direction==cd_verticdiag_bottom) (*dwPos)+=0-2*Map->GetIsoSize(); + } + else + { + if(m_direction==cd_verticdiag_top) (*dwPos)+=0+2*Map->GetIsoSize(); + if(m_direction==cd_verticdiag_bottom) (*dwPos)+=0-2*Map->GetIsoSize(); + } + } + else + { + if(bSmall) + { + if(m_direction==cd_verticdiag_top) (*dwPos)+=0-1*Map->GetIsoSize(); + if(m_direction==cd_verticdiag_bottom) (*dwPos)+=0+1*Map->GetIsoSize(); + + + } + + } +} + +CString CFrontCliffModifier::GetDataSection() +{ + if(m_bAlternative) return ("CliffFrontDataAlt"); + return("CliffFrontData"); +} diff --git a/MissionEditor/FrontCliffModifier.h b/MissionEditor/FrontCliffModifier.h new file mode 100644 index 0000000..7bf45dc --- /dev/null +++ b/MissionEditor/FrontCliffModifier.h @@ -0,0 +1,46 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// FrontCliffModifier.h: Schnittstelle fĂ¼r die Klasse CFrontCliffModifier. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_FRONTCLIFFMODIFIER_H__3853D324_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) +#define AFX_FRONTCLIFFMODIFIER_H__3853D324_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "CliffModifier.h" + +class CFrontCliffModifier : public CCliffModifier +{ +public: + CFrontCliffModifier(); + virtual ~CFrontCliffModifier(); + +protected: + virtual CString GetDataSection(); + virtual void ModifyCurrentPos(DWORD* dwPos, BOOL bBeforePlacing, BOOL bSmall); + virtual void ModifyStartPos(DWORD* dwStartPos, BOOL bSmall); +}; + +#endif // !defined(AFX_FRONTCLIFFMODIFIER_H__3853D324_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) diff --git a/MissionEditor/GlobalsDlg.cpp b/MissionEditor/GlobalsDlg.cpp new file mode 100644 index 0000000..8c07264 --- /dev/null +++ b/MissionEditor/GlobalsDlg.cpp @@ -0,0 +1,210 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// GlobalsDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "GlobalsDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "inlines.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CGlobalsDlg + + +CGlobalsDlg::CGlobalsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CGlobalsDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CGlobalsDlg) + m_Description = _T(""); + //}}AFX_DATA_INIT +} + + +void CGlobalsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CGlobalsDlg) + DDX_Control(pDX, IDC_VALUE, m_Value); + DDX_Control(pDX, IDC_GLOBAL, m_Global); + DDX_Text(pDX, IDC_DESCRIPTION, m_Description); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CGlobalsDlg, CDialog) + //{{AFX_MSG_MAP(CGlobalsDlg) + ON_EN_CHANGE(IDC_DESCRIPTION, OnChangeDescription) + ON_CBN_SELCHANGE(IDC_GLOBAL, OnSelchangeGlobal) + ON_CBN_SELCHANGE(IDC_VALUE, OnSelchangeValue) + ON_CBN_EDITCHANGE(IDC_VALUE, OnEditchangeValue) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CGlobalsDlg + +void CGlobalsDlg::OnOK() +{ + + // CDialog::OnOK(); +} + +void CGlobalsDlg::OnCancel() +{ + // TODO: Zusätzlichen Bereinigungscode hier einfĂ¼gen + + CDialog::OnCancel(); +} + +void CGlobalsDlg::UpdateDialog() +{ + int oldsel=m_Global.GetCurSel(); + if(oldsel<0) oldsel=0; + + while(m_Global.DeleteString(0)!=CB_ERR); + + int i; + BOOL bFailFind=FALSE; + CIniFile& ini=Map->GetIniFile(); + for(i=0;i<100;i++) + { + char c[50]; + itoa(i,c,10); + CString added=c; + added+=" "; + + if(ini.sections["VariableNames"].FindName(c)>=0) + { + added+=ini.sections["VariableNames"].values[c]; + } + else + { + bFailFind=TRUE; + added+=" No name"; + } + + m_Global.SetItemData(m_Global.AddString(added),i); + + if(bFailFind) break; + } + + m_Global.SetCurSel(oldsel); + OnSelchangeGlobal(); +} + +void CGlobalsDlg::OnChangeDescription() +{ + CIniFile& ini=Map->GetIniFile(); + + int cursel=m_Global.GetCurSel(); + if(cursel<0) return; + int curglob=m_Global.GetItemData(cursel); + + + + char c[50]; + itoa(curglob, c, 10); + + UpdateData(TRUE); + + if(m_Description.Find(",")>=0) m_Description.SetAt(m_Description.Find(","), 0); + + if(ini.sections["VariableNames"].values[c].GetLength()==0) ini.sections["VariableNames"].values[c]="text,0"; + ini.sections["VariableNames"].values[c]=SetParam(ini.sections["VariableNames"].values[c], 0, m_Description); + + // do not remove, Tiberian Sun seems to don´t like probably unused global numbers + //if(m_Description.GetLength()==0) + // ini.sections["VariableNames"].values.erase(c); + + UpdateDialog(); + +} + +void CGlobalsDlg::OnSelchangeGlobal() +{ + CIniFile& ini=Map->GetIniFile(); + + int cursel=m_Global.GetCurSel(); + if(cursel<0) return; + int curglob=m_Global.GetItemData(cursel); + + char c[50]; + itoa(curglob, c, 10); + + if(ini.sections["VariableNames"].FindName(c)>=0) + { + m_Description=GetParam(ini.sections["VariableNames"].values[c],0); + m_Value.SetWindowText(GetParam(ini.sections["VariableNames"].values[c],1)); + } + else + m_Description=""; + + UpdateData(FALSE); +} + +BOOL CGlobalsDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + UpdateDialog(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CGlobalsDlg::OnSelchangeValue() +{ + +} + +void CGlobalsDlg::OnEditchangeValue() +{ + CIniFile& ini=Map->GetIniFile(); + CString str; + m_Value.GetWindowText(str); + if(str.GetLength()==0) return; + int cursel=m_Global.GetCurSel(); + if(cursel<0) return; + int curglob=m_Global.GetItemData(cursel); + + char c[50]; + itoa(curglob, c, 10); + + if(ini.sections["VariableNames"].FindName(c)<0) return; + + + UpdateData(TRUE); + + str=GetParam(str, 0); + TruncSpace(str); + ini.sections["VariableNames"].values[c]=SetParam(ini.sections["VariableNames"].values[c], 1, str); + + UpdateDialog(); +} diff --git a/MissionEditor/GlobalsDlg.h b/MissionEditor/GlobalsDlg.h new file mode 100644 index 0000000..0aaff16 --- /dev/null +++ b/MissionEditor/GlobalsDlg.h @@ -0,0 +1,75 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_GLOBALSDLG_H__A8AAF461_9DE3_11D4_9C87_A7C4798A5242__INCLUDED_) +#define AFX_GLOBALSDLG_H__A8AAF461_9DE3_11D4_9C87_A7C4798A5242__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// GlobalsDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CGlobalsDlg + +class CGlobalsDlg : public CDialog +{ +// Konstruktion +public: + void UpdateDialog(); + CGlobalsDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CGlobalsDlg) + enum { IDD = IDD_GLOBALS }; + CMyComboBox m_Value; + CComboBox m_Global; + CString m_Description; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CGlobalsDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CGlobalsDlg) + virtual void OnOK(); + virtual void OnCancel(); + afx_msg void OnChangeDescription(); + afx_msg void OnSelchangeGlobal(); + virtual BOOL OnInitDialog(); + afx_msg void OnSelchangeValue(); + afx_msg void OnEditchangeValue(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_GLOBALSDLG_H__A8AAF461_9DE3_11D4_9C87_A7C4798A5242__INCLUDED_ diff --git a/MissionEditor/Houses.cpp b/MissionEditor/Houses.cpp new file mode 100644 index 0000000..d7dd396 --- /dev/null +++ b/MissionEditor/Houses.cpp @@ -0,0 +1,826 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Houses.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Houses.h" +#include "resource.h" +#include "finalsundlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "newra2housedlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CHouses + +IMPLEMENT_DYNCREATE(CHouses, CDialog) + +CHouses::CHouses() : CDialog(CHouses::IDD) +{ + //{{AFX_DATA_INIT(CHouses) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + +CHouses::~CHouses() +{ +} + +void CHouses::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CHouses) + DDX_Control(pDX, IDC_HUMANPLAYER, m_HumanPlayer); + DDX_Control(pDX, IDC_TECHLEVEL, m_TechLevel); + DDX_Control(pDX, IDC_SIDE, m_Side); + DDX_Control(pDX, IDC_PLAYERCONTROL, m_PlayerControl); + DDX_Control(pDX, IDC_PERCENTBUILT, m_PercentBuilt); + DDX_Control(pDX, IDC_NODECOUNT, m_Nodecount); + DDX_Control(pDX, IDC_IQ, m_IQ); + DDX_Control(pDX, IDC_EDGE, m_Edge); + DDX_Control(pDX, IDC_CREDITS, m_Credits); + DDX_Control(pDX, IDC_COLOR, m_Color); + DDX_Control(pDX, IDC_ALLIES, m_Allies); + DDX_Control(pDX, IDC_ACTSLIKE, m_ActsLike); + DDX_Control(pDX, IDC_HOUSES, m_houses); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CHouses, CDialog) + //{{AFX_MSG_MAP(CHouses) + ON_CBN_SELCHANGE(IDC_HOUSES, OnSelchangeHouses) + ON_BN_CLICKED(IDC_PREPAREHOUSES, OnPreparehouses) + ON_WM_SHOWWINDOW() + ON_BN_CLICKED(IDC_ADDHOUSE, OnAddhouse) + ON_BN_CLICKED(IDC_DELETEHOUSE, OnDeletehouse) + ON_CBN_KILLFOCUS(IDC_IQ, OnKillfocusIq) + ON_CBN_KILLFOCUS(IDC_EDGE, OnKillfocusEdge) + ON_CBN_KILLFOCUS(IDC_SIDE, OnKillfocusSide) + ON_CBN_KILLFOCUS(IDC_COLOR, OnKillfocusColor) + ON_EN_KILLFOCUS(IDC_ALLIES, OnKillfocusAllies) + ON_EN_KILLFOCUS(IDC_CREDITS, OnKillfocusCredits) + ON_CBN_EDITCHANGE(IDC_ACTSLIKE, OnEditchangeActslike) + ON_CBN_KILLFOCUS(IDC_NODECOUNT, OnKillfocusNodecount) + ON_CBN_KILLFOCUS(IDC_TECHLEVEL, OnKillfocusTechlevel) + ON_CBN_KILLFOCUS(IDC_PERCENTBUILT, OnKillfocusPercentbuilt) + ON_CBN_KILLFOCUS(IDC_PLAYERCONTROL, OnKillfocusPlayercontrol) + ON_CBN_SELCHANGE(IDC_HUMANPLAYER, OnSelchangeHumanplayer) + ON_CBN_SELCHANGE(IDC_ACTSLIKE, OnSelchangeActslike) + ON_EN_SETFOCUS(IDC_ALLIES, OnSetfocusAllies) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CHouses + +void CHouses::UpdateDialog() +{ + while(this->m_houses.DeleteString(0)!=CB_ERR); + while(this->m_HumanPlayer.DeleteString(0)!=CB_ERR); + while(this->m_Color.DeleteString(0)!=CB_ERR); + while(this->m_ActsLike.DeleteString(0)!=CB_ERR); + + ListHouses(m_Side, FALSE, TRUE); + + int i; + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { +#ifdef RA2_MODE + CString j=*rules.sections[HOUSES].GetValue(i); + j.MakeLower(); + if(j=="nod" || j=="gdi") continue; +#endif + + char house_id[5]; + CString houseCString; + itoa(i,house_id,10); + houseCString=house_id; + houseCString+=" "; + houseCString+=TranslateHouse(*rules.sections[HOUSES].GetValue(i), TRUE); + m_ActsLike.AddString(houseCString); + } + + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections.find(MAPHOUSES)==ini.sections.end() && ini.sections.size()>0) + { + // MessageBox("No houses do exist, if you want to use houses, you should use ""Prepare houses"" before doing anything else."); + } + else + { + m_HumanPlayer.AddString("None"); + m_HumanPlayer.SetCurSel(0); + for(i=0;i<ini.sections[MAPHOUSES].values.size();i++) + { +#ifdef RA2_MODE + CString j=*ini.sections[MAPHOUSES].GetValue(i); + j.MakeLower(); + if(j=="nod" || j=="gdi") continue; +#endif + m_houses.AddString(TranslateHouse(*ini.sections[MAPHOUSES].GetValue(i), TRUE)); + m_HumanPlayer.AddString(TranslateHouse(*ini.sections[MAPHOUSES].GetValue(i), TRUE)); + + } + + + if(ini.sections["Basic"].values.find("Player")!=ini.sections["Basic"].values.end()) + { + m_HumanPlayer.SetCurSel(m_HumanPlayer.FindStringExact(0, TranslateHouse(ini.sections["Basic"].values["Player"], TRUE))); + + } + + m_houses.SetCurSel(0); + + m_ActsLike.SetWindowText(""); + m_Allies.SetWindowText(""); + m_Color.SetWindowText(""); + m_Credits.SetWindowText(""); + m_Edge.SetWindowText(""); + m_IQ.SetWindowText(""); + m_Nodecount.SetWindowText(""); + m_PercentBuilt.SetWindowText(""); + m_PlayerControl.SetWindowText(""); + m_Side.SetWindowText(""); + m_TechLevel.SetWindowText(""); + + + + OnSelchangeHouses(); + } + + // houses list done + + + // ok now color list + const auto& rulesColors = rules.sections["Colors"]; + for(i=0;i< rulesColors.values.size();i++) + { + m_Color.AddString(*rulesColors.GetValueName(i)); + } + for (i = 0;i < ini.sections["Colors"].values.size();i++) + { + auto col = *ini.sections["Colors"].GetValueName(i); + if(rulesColors.values.find(col) == rulesColors.values.end()) + m_Color.AddString(*ini.sections["Colors"].GetValueName(i)); + } +} + +BOOL CHouses::OnInitDialog() +{ + CDialog::OnInitDialog(); + + UpdateStrings(); + UpdateDialog(); + +#ifdef RA2_MODE + m_ActsLike.ShowWindow(SW_HIDE); + //m_Edge.ShowWindow(SW_HIDE); +#endif + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CHouses::OnSelchangeHouses() +{ + CIniFile& ini=Map->GetIniFile(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + // ListHouses(m_ActsLike, TRUE); + +#ifndef RA2_MODE + m_ActsLike.SetWindowText(s.values["ActsLike"]); +#endif + m_Allies.SetWindowText(TranslateHouse(s.values["Allies"], TRUE)); + m_Color.SetWindowText(s.values["Color"]); + m_Credits.SetWindowText(s.values["Credits"]); + m_Edge.SetWindowText(s.values["Edge"]); + m_IQ.SetWindowText(s.values["IQ"]); + m_Nodecount.SetWindowText(s.values["NodeCount"]); + m_PercentBuilt.SetWindowText(s.values["PercentBuilt"]); + m_PlayerControl.SetWindowText(s.values["PlayerControl"]); +#ifndef RA2_MODE + m_Side.SetWindowText(s.values["Side"]); +#else + m_Side.SetWindowText(TranslateHouse(s.values["Country"], TRUE)); +#endif + m_TechLevel.SetWindowText(s.values["TechLevel"]); + +} + +void CHouses::OnPreparehouses() +{ + CIniFile& ini=Map->GetIniFile(); + +#ifdef RA2_MODE + if(Map->IsMultiplayer()) + { + ini.sections["Basic"].values["MultiplayerOnly"]="1"; + + int i; + for (i=0;i<rules.sections[HOUSES].values.size();i++) + { + char c[50]; + int k=i; + itoa(k,c,10); + CString country=*rules.sections[HOUSES].GetValue(i); + + // we now create a MAPHOUSE with the same name as the current rules house + ini.sections[MAPHOUSES].values[c]=country; + + ini.sections[country].values["IQ"]="0"; + ini.sections[country].values["Edge"]="North"; + ini.sections[country].values["Color"]=rules.sections[country].values["Color"]; + ini.sections[country].values["Allies"]=country; + ini.sections[country].values["Country"]=country; + ini.sections[country].values["Credits"]="0"; + ini.sections[country].values["NodeCount"]="0"; + ini.sections[country].values["TechLevel"]="1"; + ini.sections[country].values["PercentBuilt"]="0"; + ini.sections[country].values["PlayerControl"]="no"; + + } + + UpdateDialog(); + return; + } +#endif + + // import the rules.ini houses + if(ini.sections.find(MAPHOUSES)!=ini.sections.end()) + { + if(ini.sections[MAPHOUSES].values.size()>0) + { + MessageBox("There are already houses in your map. You need to delete these first."); + return; + } + } + + int i; + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + AddHouse(GetHouseSectionName(*rules.sections[HOUSES].GetValue(i))); + } +} + +void CHouses::AddHouse(const char *name) +{ + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections.find(name)!=ini.sections.end()) + { + MessageBox(((CString)"Sorry this name is not available. " + name + (CString)" is already used in the map file. You need to use another name.")); + return; + } + if(ini.sections.find(TranslateHouse(name))!=ini.sections.end()) + { + MessageBox(((CString)"Sorry this name is not available. " + name + (CString)" is already used in the map file. You need to use another name.")); + return; + } +#ifdef RA2_MODE + CNewRA2HouseDlg dlg; + if(dlg.DoModal()==IDCANCEL) return; +#endif + + int c; + + //okay, get a free slot + int pos=-1; +#ifdef RA2_MODE + int pos2=-1; +#endif + for(c=0;c>-1;c++) + { + char k[50]; + itoa(c,k,10); + if(ini.sections[MAPHOUSES].values.find(k)==ini.sections[MAPHOUSES].values.end()) + pos=c; + if(pos!=-1) break; + } +#ifdef RA2_MODE + for(c=0;c>-1;c++) + { + char k[50]; + itoa(c,k,10); + if(ini.sections[HOUSES].values.find(k)==ini.sections[HOUSES].values.end()) + pos2=c; + if(pos2!=-1) break; + } +#endif + + char k[50]; + itoa(pos,k,10); + + ini.sections[MAPHOUSES].values[k]=TranslateHouse(name); + + CString country; + country=name; + country.Replace(" House", ""); + country.Replace("House",""); + if(country.Find(" ")>=0) country.Replace(" ", "_"); //=country.Left(country.Find(" ")); + +#ifdef RA2_MODE + itoa(pos2, k, 10); + ini.sections[HOUSES].values[k]=country; +#endif + + ini.sections[TranslateHouse(name)].values["IQ"]="0"; + ini.sections[TranslateHouse(name)].values["Edge"]="West"; + ini.sections[TranslateHouse(name)].values["Allies"]=TranslateHouse(name); + + CString side=name; +#ifdef RA2_MODE + side=rules.sections[TranslateHouse(dlg.m_Country)].values["Side"]; +#endif + + if(strstr(name, "Nod")!=NULL) + { +#ifndef RA2_MODE + ini.sections[TranslateHouse(name)].values["Side"]="Nod"; +#endif + ini.sections[TranslateHouse(name)].values["Color"]="DarkRed"; + if(name!="Nod") ini.sections[name].values["Allies"]+=",Nod"; + } + else + { +#ifndef RA2_MODE + ini.sections[TranslateHouse(name)].values["Side"]="GDI"; +#endif + ini.sections[TranslateHouse(name)].values["Color"]="Gold"; + if(name!="GDI") ini.sections[TranslateHouse(name)].values["Allies"]+=",GDI"; + } + ini.sections[TranslateHouse(name)].values["Credits"]="0"; +#ifndef RA2_MODE + ini.sections[TranslateHouse(name)].values["ActsLike"]="0"; +#else + ini.sections[TranslateHouse(name)].values["Country"]=TranslateHouse(country); +#endif + ini.sections[TranslateHouse(name)].values["NodeCount"]="0"; + ini.sections[TranslateHouse(name)].values["TechLevel"]="10"; + ini.sections[TranslateHouse(name)].values["PercentBuilt"]="100"; + ini.sections[TranslateHouse(name)].values["PlayerControl"]="no"; + +#ifdef RA2_MODE + dlg.m_Country=TranslateHouse(dlg.m_Country); // just to make sure... + country=TranslateHouse(country); + ini.sections[country].values["ParentCountry"]=dlg.m_Country; + ini.sections[country].values["Name"]=country; + ini.sections[country].values["Suffix"]=rules.sections[dlg.m_Country].values["Suffix"]; + ini.sections[country].values["Prefix"]=rules.sections[dlg.m_Country].values["Prefix"]; + ini.sections[country].values["Color"]=rules.sections[dlg.m_Country].values["Color"]; + ini.sections[country].values["Side"]=rules.sections[dlg.m_Country].values["Side"]; + ini.sections[country].values["SmartAI"]=rules.sections[dlg.m_Country].values["SmartAI"]; + ini.sections[country].values["CostUnitsMult"]="1"; +#endif + + int cusel=m_houses.GetCurSel(); + UpdateDialog(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(); + if(cusel!=-1)m_houses.SetCurSel(cusel); +} + +void CHouses::OnShowWindow(BOOL bShow, UINT nStatus) +{ + CDialog::OnShowWindow(bShow, nStatus); + + CIniFile& ini=Map->GetIniFile(); + + if(bShow) + { + if(ini.sections.find(MAPHOUSES)==ini.sections.end() && ini.sections.size()>0) + { +#ifndef RA2_MODE + MessageBox("No houses do exist, if you want to use houses, you should use ""Prepare houses"" before doing anything else. Note that in a multiplayer map independent computer players cannot be created by using the names GDI and Nod for the house. Just use something like GDI_AI."); +#else + MessageBox("No houses do exist, if you want to use houses, you should use ""Prepare houses"" before doing anything else."); + +#endif + } + } + else + { + // call all KillFocus ! + OnKillfocusIq(); + OnEditchangeActslike(); + OnKillfocusAllies(); + OnKillfocusColor(); + OnKillfocusCredits(); + OnKillfocusEdge(); + OnKillfocusNodecount(); + OnKillfocusPercentbuilt(); + OnKillfocusPlayercontrol(); + OnKillfocusSide(); + OnKillfocusTechlevel(); + } + +} + +void CHouses::OnAddhouse() +{ + CString name=InputBox(GetLanguageStringACP("AddHouse"),GetLanguageStringACP("AddHouseCap")); + if(name.GetLength()==0) return; + + name=GetHouseSectionName(name); + //name=TranslateHouse(name); + AddHouse(name); +} + +void CHouses::OnDeletehouse() +{ + CIniFile& ini=Map->GetIniFile(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + CString uiname; + m_houses.GetLBText(cusel, name); + + uiname=name; + name=TranslateHouse(name); + + CString str=GetLanguageStringACP("DeleteHouse"); + str=TranslateStringVariables(1, str, uiname); + if(MessageBox(str,GetLanguageStringACP("DeleteHouseCap"),MB_YESNO)==IDNO) return; + + ini.sections.erase((LPCTSTR)name); + + int i; + for(i=0;i<ini.sections[MAPHOUSES].values.size();i++) + { + if(*ini.sections[MAPHOUSES].GetValue(i)==name) + { + ini.sections[MAPHOUSES].values.erase(*ini.sections[MAPHOUSES].GetValueName(i)); + } + } + + if(ini.sections[MAPHOUSES].values.size()==0) + ini.sections.erase(MAPHOUSES); + + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(); + UpdateDialog(); +} + +void CHouses::OnKillfocusIq() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_IQ.GetWindowText(t); + s.values["IQ"]=t; +} + +void CHouses::OnKillfocusEdge() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_Edge.GetWindowText(t); + s.values["Edge"]=t; +} + +void CHouses::OnKillfocusSide() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_Side.GetWindowText(t); + t=TranslateHouse(t); +#ifndef RA2_MODE + s.values["Side"]=t; +#else + s.values["Country"]=t; +#endif +} + +void CHouses::OnKillfocusColor() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_Color.GetWindowText(t); + s.values["Color"]=t; + + //Map->UpdateIniFile(MAPDATA_UPDATE_FROM_INI); + // MW fix: Only update structures + // this recalculates the colors + Map->UpdateStructures(FALSE); + // and minimap + Map->RedrawMinimap(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->RedrawWindow(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_minimap.RedrawWindow(); +} + +void CHouses::OnKillfocusAllies() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_Allies.GetWindowText(t); + t=TranslateHouse(t); + s.values["Allies"]=t; +} + +void CHouses::OnKillfocusCredits() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_Credits.GetWindowText(t); + s.values["Credits"]=t; +} + +void CHouses::OnEditchangeActslike() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_ActsLike.GetWindowText(t); + TruncSpace(t); + t=TranslateHouse(t); + s.values["ActsLike"]=t; +} + +void CHouses::OnKillfocusNodecount() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_Nodecount.GetWindowText(t); + s.values["NodeCount"]=t; +} + +void CHouses::OnKillfocusTechlevel() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_TechLevel.GetWindowText(t); + s.values["TechLevel"]=t; +} + +void CHouses::OnKillfocusPercentbuilt() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_PercentBuilt.GetWindowText(t); + s.values["PercentBuilt"]=t; +} + +void CHouses::OnKillfocusPlayercontrol() +{ + CIniFile& ini=Map->GetIniFile(); + + SetMainStatusBarReady(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_PlayerControl.GetWindowText(t); + s.values["PlayerControl"]=t; +} + +void CHouses::OnSelchangeHumanplayer() +{ + CIniFile& ini=Map->GetIniFile(); + + CString pl; + m_HumanPlayer.GetLBText(m_HumanPlayer.GetCurSel(),pl); + pl=TranslateHouse(pl); + + if(pl.GetLength()==0 || pl=="None") + { + ini.sections["Basic"].values.erase("Player"); + } + else + { + ini.sections["Basic"].values["Player"]=(LPCTSTR)pl; + } +} + +void CHouses::OnSelchangeActslike() +{ + CIniFile& ini=Map->GetIniFile(); + + int cusel; + cusel=m_houses.GetCurSel(); + if(cusel==-1) return; + + CString name; + m_houses.GetLBText(cusel, name); + name=TranslateHouse(name); + + + + CIniFileSection& s=ini.sections[(LPCTSTR)name]; + + CString t; + m_ActsLike.GetLBText(m_ActsLike.GetCurSel(),t); + TruncSpace(t); + t=TranslateHouse(t); + s.values["ActsLike"]=t; +} + +void CHouses::UpdateStrings() +{ + SetDlgItemText(IDC_DESC, GetLanguageStringACP("HousesDesc")); + SetDlgItemText(IDC_LPLAYER, GetLanguageStringACP("HousesPlayerHouse")); + SetDlgItemText(IDC_LHOUSE, GetLanguageStringACP("HousesHouse")); + SetDlgItemText(IDC_LIQ, GetLanguageStringACP("HousesIQ")); + SetDlgItemText(IDC_LEDGE, GetLanguageStringACP("HousesEdge")); + SetDlgItemText(IDC_LSIDE, GetLanguageStringACP("HousesSide")); + SetDlgItemText(IDC_LCOLOR, GetLanguageStringACP("HousesColor")); + SetDlgItemText(IDC_LALLIES, GetLanguageStringACP("HousesAllies")); + SetDlgItemText(IDC_LCREDITS, GetLanguageStringACP("HousesCredits")); + SetDlgItemText(IDC_LACTSLIKE, GetLanguageStringACP("HousesActsLike")); + SetDlgItemText(IDC_LNODECOUNT, GetLanguageStringACP("HousesNodeCount")); + SetDlgItemText(IDC_LTECHLEVEL, GetLanguageStringACP("HousesTechlevel")); + SetDlgItemText(IDC_LBUILDACTIVITY, GetLanguageStringACP("HousesBuildActivity")); + SetDlgItemText(IDC_LPLAYERCONTROL, GetLanguageStringACP("HousesPlayerControl")); + + SetDlgItemText(IDC_PREPAREHOUSES, GetLanguageStringACP("HousesPrepareHouses")); + SetDlgItemText(IDC_ADDHOUSE, GetLanguageStringACP("HousesAddHouse")); + SetDlgItemText(IDC_DELETEHOUSE, GetLanguageStringACP("HousesDeleteHouse")); + + SetWindowText(TranslateStringACP(HOUSES)); +} + +void CHouses::OnSetfocusAllies() +{ + SetMainStatusBar(GetLanguageStringACP("HousesAlliesHelp")); +} + +void CHouses::PostNcDestroy() +{ + CDialog::PostNcDestroy(); +} diff --git a/MissionEditor/Houses.h b/MissionEditor/Houses.h new file mode 100644 index 0000000..98ffd5e --- /dev/null +++ b/MissionEditor/Houses.h @@ -0,0 +1,104 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_HOUSES_H__80D09600_8932_11D3_B63B_A583BFBD8C41__INCLUDED_) +#define AFX_HOUSES_H__80D09600_8932_11D3_B63B_A583BFBD8C41__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Houses.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CHouses + +class CHouses : public CDialog +{ + DECLARE_DYNCREATE(CHouses) + +// Konstruktion +public: + void UpdateStrings(); + void AddHouse(const char* name); + void UpdateDialog(); + CHouses(); + ~CHouses(); + +// Dialogfelddaten + //{{AFX_DATA(CHouses) + enum { IDD = IDD_HOUSES }; + CComboBox m_HumanPlayer; + CComboBox m_TechLevel; + CComboBox m_Side; + CComboBox m_PlayerControl; + CComboBox m_PercentBuilt; + CComboBox m_Nodecount; + CComboBox m_IQ; + CComboBox m_Edge; + CEdit m_Credits; + CComboBox m_Color; + CEdit m_Allies; + CComboBox m_ActsLike; + CComboBox m_houses; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CHouses) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CHouses) + virtual BOOL OnInitDialog(); + afx_msg void OnSelchangeHouses(); + afx_msg void OnPreparehouses(); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + afx_msg void OnAddhouse(); + afx_msg void OnDeletehouse(); + afx_msg void OnKillfocusIq(); + afx_msg void OnKillfocusEdge(); + afx_msg void OnKillfocusSide(); + afx_msg void OnKillfocusColor(); + afx_msg void OnKillfocusAllies(); + afx_msg void OnKillfocusCredits(); + afx_msg void OnEditchangeActslike(); + afx_msg void OnKillfocusNodecount(); + afx_msg void OnKillfocusTechlevel(); + afx_msg void OnKillfocusPercentbuilt(); + afx_msg void OnKillfocusPlayercontrol(); + afx_msg void OnSelchangeHumanplayer(); + afx_msg void OnSelchangeActslike(); + afx_msg void OnSetfocusAllies(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_HOUSES_H__80D09600_8932_11D3_B63B_A583BFBD8C41__INCLUDED_ diff --git a/MissionEditor/ImportINI.cpp b/MissionEditor/ImportINI.cpp new file mode 100644 index 0000000..d42f3e9 --- /dev/null +++ b/MissionEditor/ImportINI.cpp @@ -0,0 +1,139 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// ImportINI.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "ImportINI.h" +#include "mapdata.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CImportINI + + +CImportINI::CImportINI(CWnd* pParent /*=NULL*/) + : CDialog(CImportINI::IDD, pParent) +{ + //{{AFX_DATA_INIT(CImportINI) + //}}AFX_DATA_INIT + m_inicount=0; +} + + +void CImportINI::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CImportINI) + DDX_Control(pDX, IDC_AVAILABLE, m_Available); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CImportINI, CDialog) + //{{AFX_MSG_MAP(CImportINI) + ON_BN_CLICKED(IDC_ALLSECTIONS, OnAllsections) + ON_BN_CLICKED(IDC_SPECIFYSECTIONS, OnSpecifysections) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CImportINI + +void CImportINI::OnAllsections() +{ + this->m_Available.EnableWindow(FALSE); + //this->m_Sections.EnableWindow(FALSE); +} + +void CImportINI::OnSpecifysections() +{ + this->m_Available.EnableWindow(); + //this->m_Sections.EnableWindow(); +} + +BOOL CImportINI::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CButton* all; + all=(CButton*)GetDlgItem(IDC_ALLSECTIONS); + all->SetCheck(1); + + this->OnAllsections(); + + CIniFile inifile; + inifile.LoadFile(this->m_FileName); + + if(inifile.sections.size()<1){MessageBox("File does not have any ini content, abort.","Error");EndDialog(IDCANCEL);return TRUE;} + + m_inicount=inifile.sections.size(); + + int i; + for(i=0;i<inifile.sections.size();i++) + { + if(!Map->IsMapSection(*inifile.GetSectionName(i))) + m_Available.InsertString(-1, *inifile.GetSectionName(i)); + } + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CImportINI::OnOK() +{ + CIniFile& ini=Map->GetIniFile(); + + CButton* all; + all=(CButton*)GetDlgItem(IDC_ALLSECTIONS); + + if(all->GetCheck()) + { + // all... + ini.InsertFile(m_FileName, NULL); + } + else + { + // only the chosen sections + + int i; + for(i=0;i<m_Available.GetCount();i++) + { + if(m_Available.GetSel(i)>0) + { + // ok the user wants to add that section! + CString name; + m_Available.GetText(i, name); + + ini.InsertFile(m_FileName, (char*)(LPCTSTR)name); + } + } + } + + CDialog::OnOK(); +} diff --git a/MissionEditor/ImportINI.h b/MissionEditor/ImportINI.h new file mode 100644 index 0000000..1987406 --- /dev/null +++ b/MissionEditor/ImportINI.h @@ -0,0 +1,72 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_IMPORTINI_H__9DC7B324_6DF2_11D3_99E1_D14A1D4DCF07__INCLUDED_) +#define AFX_IMPORTINI_H__9DC7B324_6DF2_11D3_99E1_D14A1D4DCF07__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ImportINI.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CImportINI + +class CImportINI : public CDialog +{ +// Konstruktion +public: + CString m_FileName; + CImportINI(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CImportINI) + enum { IDD = IDD_IMPORTINI }; + CListBox m_Available; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CImportINI) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CImportINI) + afx_msg void OnAllsections(); + afx_msg void OnSpecifysections(); + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + WORD m_inicount; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_IMPORTINI_H__9DC7B324_6DF2_11D3_99E1_D14A1D4DCF07__INCLUDED_ diff --git a/MissionEditor/Infantry.cpp b/MissionEditor/Infantry.cpp new file mode 100644 index 0000000..7b6f971 --- /dev/null +++ b/MissionEditor/Infantry.cpp @@ -0,0 +1,173 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Infantrie.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Infantry.h" +#include "functions.h" +#include "mapdata.h" +#include "variables.h" + + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CInfantrie + + +CInfantrie::CInfantrie(CWnd* pParent /*=NULL*/) + : CDialog(CInfantrie::IDD, pParent) +{ + //{{AFX_DATA_INIT(CInfantrie) + m_direction = _T(""); + m_house = _T(""); + m_flag1 = _T(""); + m_flag2 = _T(""); + m_flag3 = _T(""); + m_flag4 = _T(""); + m_action = _T(""); + m_tag = _T(""); + m_flag5 = _T(""); + //}}AFX_DATA_INIT + Init(); +} + + +void CInfantrie::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CInfantrie) + DDX_Control(pDX, IDC_STRENGTH, m_strength_ctrl); + DDX_CBString(pDX, IDC_DIRECTION, m_direction); + DDX_CBString(pDX, IDC_HOUSE, m_house); + DDX_Text(pDX, IDC_P1, m_flag1); + DDX_Text(pDX, IDC_P2, m_flag2); + DDX_Text(pDX, IDC_P3, m_flag3); + DDX_Text(pDX, IDC_P4, m_flag4); + DDX_CBString(pDX, IDC_STATE, m_action); + DDX_CBString(pDX, IDC_TAG, m_tag); + DDX_Text(pDX, IDC_P5, m_flag5); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CInfantrie, CDialog) + //{{AFX_MSG_MAP(CInfantrie) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CInfantrie + +BOOL CInfantrie::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // init the common (!) dialog things + int i; + CComboBox* house, *tag; + house=(CComboBox*)GetDlgItem(IDC_HOUSE); + tag=(CComboBox*)GetDlgItem(IDC_TAG); + + ListHouses(*house, FALSE); + ListTags(*tag, TRUE); + + + UpdateData(FALSE); + m_strength_ctrl.SetRange(0,256); + m_strength_ctrl.SetPos(atoi(m_strength)); + + + UpdateStrings(); + + return TRUE; +} + +void CInfantrie::OnOK() +{ + CDialog::OnOK(); + m_strength=GetText(&m_strength_ctrl); + + UpdateData(); + TruncSpace(m_tag); + m_house=TranslateHouse(m_house); + + + +} + +void CInfantrie::Init(CString house, CString strength, CString action, CString direction, CString tag, CString flag1, CString flag2, CString flag3, CString flag4, CString flag5) +{ + CIniFile& ini=Map->GetIniFile(); + + if(house=="") + { + /*m_house=*rules.sections[HOUSES].GetValue(0); + if(ini.sections.find(HOUSES)!=ini.sections.end()) + if(ini.sections[HOUSES].values.size()>0) + m_house=*ini.sections[HOUSES].GetValue(0);*/ + m_house=TranslateHouse(Map->GetHouseID(0), TRUE); + } + else + m_house=TranslateHouse(house, TRUE); + + + + m_flag1=flag1; + m_flag2=flag2; + m_flag3=flag3; + m_flag4=flag4; + m_flag5=flag5; + // m_pos=pos; + m_action=action; + m_strength=strength; + + m_tag=tag; + m_direction=direction; + +} + +void CInfantrie::UpdateStrings() +{ + SetWindowText(GetLanguageStringACP("InfCap")); + GetDlgItem(IDC_LHOUSE)->SetWindowText(GetLanguageStringACP("InfHouse")); + GetDlgItem(IDC_LDESC)->SetWindowText(GetLanguageStringACP("InfDesc")); + GetDlgItem(IDC_LSTRENGTH)->SetWindowText(GetLanguageStringACP("InfStrength")); + // GetDlgItem(IDC_LPOS)->SetWindowText(GetLanguageStringACP("InfPos")); + GetDlgItem(IDC_LSTATE)->SetWindowText(GetLanguageStringACP("InfState")); + GetDlgItem(IDC_LDIRECTION)->SetWindowText(GetLanguageStringACP("InfDirection")); + GetDlgItem(IDC_LTAG)->SetWindowText(GetLanguageStringACP("InfTag")); + GetDlgItem(IDC_LP1)->SetWindowText(GetLanguageStringACP("InfP1")); + GetDlgItem(IDC_LP2)->SetWindowText(GetLanguageStringACP("InfP2")); + GetDlgItem(IDC_LP3)->SetWindowText(GetLanguageStringACP("InfP3")); + GetDlgItem(IDC_LP4)->SetWindowText(GetLanguageStringACP("InfP4")); + GetDlgItem(IDC_LP5)->SetWindowText(GetLanguageStringACP("InfP5")); + + SetDlgItemText(IDOK, GetLanguageStringACP("OK")); + SetDlgItemText(IDCANCEL, GetLanguageStringACP("Cancel")); +} diff --git a/MissionEditor/Infantry.h b/MissionEditor/Infantry.h new file mode 100644 index 0000000..14ae9a8 --- /dev/null +++ b/MissionEditor/Infantry.h @@ -0,0 +1,79 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_INFANTRIE_H__F5A248C4_84A5_11D3_B63B_F881F458F743__INCLUDED_) +#define AFX_INFANTRIE_H__F5A248C4_84A5_11D3_B63B_F881F458F743__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Infantrie.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CInfantrie + +class CInfantrie : public CDialog +{ +// Konstruktion +public: + void UpdateStrings(); + CString m_strength; + void Init(CString house="", CString strength="256", CString action="Guard", CString direction="64", CString tag="None", CString p1="0", CString p2="-1", CString p3="0", CString p4="0", CString p5="0"); + CInfantrie(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CInfantrie) + enum { IDD = IDD_INFANTRY }; + CSliderCtrl m_strength_ctrl; + CString m_direction; + CString m_house; + CString m_flag1; + CString m_flag2; + CString m_flag3; + CString m_flag4; + CString m_action; + CString m_tag; + CString m_flag5; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CInfantrie) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CInfantrie) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_INFANTRIE_H__F5A248C4_84A5_11D3_B63B_F881F458F743__INCLUDED_ diff --git a/MissionEditor/Info.cpp b/MissionEditor/Info.cpp new file mode 100644 index 0000000..c8e19e1 --- /dev/null +++ b/MissionEditor/Info.cpp @@ -0,0 +1,129 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Info.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Info.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CInfo + + +CInfo::CInfo(CWnd* pParent /*=NULL*/) + : CDialog(CInfo::IDD, pParent) +{ + //{{AFX_DATA_INIT(CInfo) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + + +void CInfo::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CInfo) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier DDX- und DDV-Aufrufe ein + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CInfo, CDialog) + //{{AFX_MSG_MAP(CInfo) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros fĂ¼r Nachrichten ein + //}}AFX_MSG_MAP +// ON_EN_CHANGE(IDC_EDIT1, &CInfo::OnEnChangeEdit1) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CInfo + + + +BOOL CInfo::OnInitDialog() +{ + CDialog::OnInitDialog(); + +#ifdef YR_MODE + CStringA license = R"(FinalAlert 2: Yuri's Revenge Mission Editor +Copyright (C) 1999-2024 Electronic Arts, Inc. +Authored by Matthias Wagner + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>.)"; +#elif RA2_MODE + CStringA license = R"(FinalAlert 2 Mission Editor +Copyright (C) 1999-2024 Electronic Arts, Inc. +Authored by Matthias Wagner + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>.)"; +#else // TS_MODE + CStringA license = R"(FinalSun Mission Editor +Copyright (C) 1999-2024 Electronic Arts, Inc. +Authored by Matthias Wagner + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>.)"; +#endif + + license.Replace("\n", "\r\n"); + GetDlgItem(IDC_LICENSE_AND_COPYRIGHT)->SetWindowTextA(license); + + return TRUE; +} diff --git a/MissionEditor/Info.h b/MissionEditor/Info.h new file mode 100644 index 0000000..5d057ce --- /dev/null +++ b/MissionEditor/Info.h @@ -0,0 +1,68 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_INFO_H__3F820D60_6EB5_11D3_99E1_444553540000__INCLUDED_) +#define AFX_INFO_H__3F820D60_6EB5_11D3_99E1_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Info.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CInfo + +class CInfo : public CDialog +{ +// Konstruktion +public: + CInfo(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CInfo) + enum { IDD = IDD_INFO }; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CInfo) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CInfo) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +public: +// afx_msg void OnEnChangeEdit1(); + virtual BOOL OnInitDialog(); +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_INFO_H__3F820D60_6EB5_11D3_99E1_444553540000__INCLUDED_ diff --git a/MissionEditor/IniFile.cpp b/MissionEditor/IniFile.cpp new file mode 100644 index 0000000..b1b1e66 --- /dev/null +++ b/MissionEditor/IniFile.cpp @@ -0,0 +1,405 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// IniFile.cpp: Implementierung der Klasse CIniFile. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "IniFile.h" +#include <string> +#include <algorithm> +#include <stdexcept> + + + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#define new DEBUG_NEW +#endif + +using namespace std; + +bool SortDummy::operator()(const CString& x, const CString& y) const +{ + // the length is more important than spelling (numbers!!!)... + if (x.GetLength() < y.GetLength()) return true; + if (x.GetLength() == y.GetLength()) + { + if (x < y) return true; + } + + return false; + +} + +typedef map<CString, CIniFileSection>::iterator CIniI; +typedef map<CString, CString, SortDummy>::iterator SI; +typedef map<CString, int, SortDummy>::iterator SII; + + +////////////////////////////////////////////////////////////////////// +// Konstruktion/Destruktion +////////////////////////////////////////////////////////////////////// + +CIniFile::CIniFile() +{ + Clear(); +} + +CIniFile::~CIniFile() +{ + sections.clear(); +} + +WORD CIniFile::LoadFile(const CString& filename, BOOL bNoSpaces) +{ + return LoadFile(std::string(filename.GetString()), bNoSpaces); +} + +WORD CIniFile::LoadFile(const std::string& filename, BOOL bNoSpaces) +{ + Clear(); + + if (filename.size() == NULL) return 1; + m_filename = filename; + + return(InsertFile(filename, NULL, bNoSpaces)); + +} + + +void CIniFile::Clear() +{ + + sections.clear(); +} + +CIniFileSection::CIniFileSection() +{ + values.clear(); + value_orig_pos.clear(); +}; + +CIniFileSection::~CIniFileSection() +{ + values.clear(); + value_orig_pos.clear(); +}; + +WORD CIniFile::InsertFile(const CString& filename, const char* Section, BOOL bNoSpaces) +{ + return InsertFile(std::string(filename.GetString()), Section, bNoSpaces); +} + +WORD CIniFile::InsertFile(const std::string& filename, const char* Section, BOOL bNoSpaces) +{ + if (filename.size() == 0) + return 1; + + fstream file; + + file.open(filename, ios::in); + if (!file.good()) + return 2; + + + //char cSec[256]; + //char cLine[4096]; + + //memset(cSec, 0, 256); + //memset(cLine, 0, 4096); + CString cSec; + std::string cLine; + + const auto npos = std::string::npos; + + while (!file.eof()) + { + std::getline(file, cLine); + + // strip to left side of newline or comment + cLine.erase(std::find_if(cLine.begin(), cLine.end(), [](const char c) { return c == '\r' || c == '\n' || c == ';'; }), cLine.end()); + + const auto openBracket = cLine.find('['); + const auto closeBracket = cLine.find(']'); + const auto equals = cLine.find('='); + + if (openBracket != npos && closeBracket != npos && openBracket < closeBracket && (equals == npos || equals > openBracket)) + { + if ((Section != nullptr) && cSec == Section) + return 0; // the section we want to insert is finished + + cSec = cLine.substr(openBracket + 1, closeBracket - openBracket - 1).c_str(); + } + else if (equals != npos && !cSec.IsEmpty()) + { + if (Section == NULL || cSec == Section) + { + // a value is set and we have a valid current section! + CString name = cLine.substr(0, equals).c_str(); + CString value = cLine.substr(equals + 1, cLine.size() - equals - 1).c_str(); + + int cuValueIndex = sections[cSec].values.size(); + + if (bNoSpaces) + { + name.Trim(); + value.Trim(); + } + + sections[cSec].values[name] = value; + sections[cSec].value_orig_pos[name] = cuValueIndex; + } + } + + } + + + + file.close(); + + return 0; +} + +const CIniFileSection* CIniFile::GetSection(std::size_t index) const +{ + if (index > sections.size() - 1) + return NULL; + + auto i = sections.cbegin(); + for (auto e = 0;e < index;e++) + i++; + + return &i->second; +} + +CIniFileSection* CIniFile::GetSection(std::size_t index) +{ + if (index > sections.size() - 1) + return NULL; + + CIniI i = sections.begin(); + for (auto e = 0;e < index;e++) + i++; + + return &i->second; +} + +const CIniFileSection* CIniFile::GetSection(const CString& section) const +{ + auto it = sections.find(section); + if (it == sections.end()) + return nullptr; + return &it->second; +} + +CIniFileSection* CIniFile::GetSection(const CString& section) +{ + auto it = sections.find(section); + if (it == sections.end()) + return nullptr; + return &it->second; +} + +const CString* CIniFileSection::GetValue(std::size_t index) const noexcept +{ + if (index > values.size() - 1) + return NULL; + + auto i = values.begin(); + for (auto e = 0;e < index;e++) + i++; + + return &i->second; +} + +CString* CIniFileSection::GetValue(std::size_t index) noexcept +{ + if (index > values.size() - 1) + return NULL; + + auto i = values.begin(); + for (auto e = 0;e < index;e++) + i++; + + return &i->second; +} + +CString CIniFileSection::GetValueByName(const CString& valueName, const CString& defaultValue) const +{ + auto it = values.find(valueName); + return (it == values.end()) ? defaultValue : it->second; +} + +const CString* CIniFile::GetSectionName(std::size_t index) const noexcept +{ + if (index > sections.size() - 1) + return NULL; + + auto i = sections.cbegin(); + for (auto e = 0; e < index; ++e) + i++; + + return &(i->first); +} + +CString& CIniFileSection::AccessValueByName(const CString& valueName) +{ + return values[valueName]; +} + +const CString* CIniFileSection::GetValueName(std::size_t index) const noexcept +{ + if (index > values.size() - 1) + return NULL; + + auto i = values.begin(); + for (auto e = 0; e < index; ++e) + i++; + + + return &(i->first); +} + +BOOL CIniFile::SaveFile(const CString& filename) const +{ + return SaveFile(std::string(filename.GetString())); +} + +BOOL CIniFile::SaveFile(const std::string& Filename) const +{ + fstream file; + + file.open(Filename, ios::out | ios::trunc); + + int i; + for (i = 0;i < sections.size();i++) + { + file << "[" << (LPCTSTR)*GetSectionName(i) << "]" << endl; + int e; + for (e = 0;e < GetSection(i)->values.size();e++) + { + file << (LPCTSTR) * (GetSection(i)->GetValueName(e)) << "=" << (LPCTSTR)*GetSection(i)->GetValue(e) << endl; + } + file << endl; + } + + file << endl; + + return TRUE; +} + + +int CIniFileSection::FindValue(CString sval) const noexcept +{ + int i; + auto it = values.cbegin(); + for (i = 0;i < values.size();i++) + { + if (sval == it->second) + return i; + it++; + } + return -1; +} + +int CIniFileSection::FindName(CString sval) const noexcept +{ + int i; + auto it = values.cbegin(); + for (i = 0;i < values.size();i++) + { + if (sval == it->first) + return i; + it++; + } + return -1; +} + +void CIniFile::DeleteLeadingSpaces(BOOL bValueNames, BOOL bValues) +{ + int i; + for (i = 0;i < sections.size();i++) + { + CIniFileSection& sec = *GetSection(i); + int e; + for (e = 0;e < sec.values.size();e++) + { + if (bValues) sec.GetValue(e)->TrimLeft(); + if (bValueNames) + { + CString value = *sec.GetValue(e); + CString name = *sec.GetValueName(e); + + sec.values.erase(name); + name.TrimLeft(); + sec.values[name] = value; + } + } + } +} + +void CIniFile::DeleteEndingSpaces(BOOL bValueNames, BOOL bValues) +{ + int i; + for (i = 0;i < sections.size();i++) + { + CIniFileSection& sec = *GetSection(i); + int e; + for (e = 0;e < sec.values.size();e++) + { + if (bValues) sec.GetValue(e)->TrimRight(); + if (bValueNames) + { + //CString& name=(CString&)*sec.GetValueName(e); + //name.TrimRight(); + CString value = *sec.GetValue(e); + CString name = *sec.GetValueName(e); + + sec.values.erase(name); + name.TrimRight(); + sec.values[name] = value; + } + } + } +} + +CString CIniFile::GetValueByName(const CString& sectionName, const CString& valueName, const CString& defaultValue) const +{ + auto section = GetSection(sectionName); + if (!section) + return defaultValue; + return section->GetValueByName(valueName, defaultValue); +} + +int CIniFileSection::GetValueOrigPos(int index) const noexcept +{ + if (index > value_orig_pos.size() - 1) + return -1; + + auto i = value_orig_pos.cbegin(); + for (int e = 0;e < index;e++) + i++; + + return i->second; +} + diff --git a/MissionEditor/IniFile.h b/MissionEditor/IniFile.h new file mode 100644 index 0000000..bc0b8b6 --- /dev/null +++ b/MissionEditor/IniFile.h @@ -0,0 +1,150 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// IniFile.h: Schnittstelle fĂ¼r die Klasse CIniFile. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_INIFILE_H__96455620_6528_11D3_99E0_DB2A1EF71411__INCLUDED_) +#define AFX_INIFILE_H__96455620_6528_11D3_99E0_DB2A1EF71411__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#include <map> +#include <CString> +#include <fstream> +#include <ios> + + +using namespace std; + +class SortDummy +{ +public: + bool operator() (const CString&, const CString&) const; +}; + + + +class CIniFileSection +{ +public: + CIniFileSection(); + virtual ~CIniFileSection(); + + CString GetValueByName(const CString& name, const CString& defaultValue = CString()) const; + CString& AccessValueByName(const CString& name); + + auto begin() noexcept + { + return values.begin(); + } + + auto begin() const noexcept + { + return values.begin(); + } + + auto end() noexcept + { + return values.end(); + } + + auto end() const noexcept + { + return values.end(); + } + + [[deprecated("instead use iterators or for_each")]] + int GetValueOrigPos(int index) const noexcept; + + [[deprecated("instead use iterators or for_each")]] + int FindName(CString sval) const noexcept; + + [[deprecated("instead use iterators or for_each")]] + int FindValue(CString sval) const noexcept; + + [[deprecated("instead use iterators or for_each")]] + const CString* GetValueName(std::size_t index) const noexcept; + + [[deprecated("instead use iterators or for_each")]] + const CString* GetValue(std::size_t index) const noexcept; + + [[deprecated("instead use iterators or for_each")]] + CString* GetValue(std::size_t index) noexcept; + +public: + map<CString, CString, SortDummy> values; + map<CString, int, SortDummy> value_orig_pos; +}; + +class CIniFile +{ +public: + void DeleteEndingSpaces(BOOL bValueNames, BOOL bValues); + void DeleteLeadingSpaces(BOOL bValueNames, BOOL bValues); + + const CString* GetSectionName(std::size_t Index) const noexcept; + const CIniFileSection* GetSection(std::size_t index) const; + CIniFileSection* GetSection(std::size_t index); + const CIniFileSection* GetSection(const CString& section) const; + CIniFileSection* GetSection(const CString& section); + CString GetValueByName(const CString& sectionName, const CString& valueName, const CString& defaultValue) const; + void Clear(); + WORD InsertFile(const CString& filename, const char* Section, BOOL bNoSpaces = FALSE); + WORD InsertFile(const std::string& filename, const char* Section, BOOL bNoSpaces = FALSE); + BOOL SaveFile(const CString& Filename) const; + BOOL SaveFile(const std::string& Filename) const; + WORD LoadFile(const CString& filename, BOOL bNoSpaces = FALSE); + WORD LoadFile(const std::string& filename, BOOL bNoSpaces = FALSE); + + + auto begin() noexcept + { + return sections.begin(); + } + + auto begin() const noexcept + { + return sections.begin(); + } + + auto end() noexcept + { + return sections.end(); + } + + auto end() const noexcept + { + return sections.end(); + } + + map<CString, CIniFileSection> sections; + CIniFile(); + virtual ~CIniFile(); + +private: + std::string m_filename; +}; + +#endif // !defined(AFX_INIFILE_H__96455620_6528_11D3_99E0_DB2A1EF71411__INCLUDED_) diff --git a/MissionEditor/InputBox.cpp b/MissionEditor/InputBox.cpp new file mode 100644 index 0000000..6ebbf6c --- /dev/null +++ b/MissionEditor/InputBox.cpp @@ -0,0 +1,119 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// InputBox.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "InputBox.h" +#include "functions.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + +/* +InputBox(); + +Shows a inputbox with specified caption and text. +Returns the user input. If the user cancels, the user input is "". +*/ +CString InputBox(const char* Sentence, const char* Caption) +{ + CInputBox inp; + inp.SetCaption(Caption); + inp.SetSentence(Sentence); + char* res=(char*) inp.DoModal(); + CString cstr=res; + + return cstr; +} + +CInputBox::CInputBox(CWnd* pParent /*=NULL*/) + : CDialog(CInputBox::IDD, pParent) +{ + //{{AFX_DATA_INIT(CInputBox) + + //}}AFX_DATA_INIT +} + + +void CInputBox::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CInputBox) + + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CInputBox, CDialog) + //{{AFX_MSG_MAP(CInputBox) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + + +void CInputBox::OnOK() +{ + CString text; + GetDlgItem(IDC_VAL)->GetWindowText(text); + + if(text.GetLength()==0){EndDialog(NULL);}; + + char* str; + str=new(char[text.GetLength()]); + strcpy(str, (LPCTSTR)text); + EndDialog((int)str); +} + +void CInputBox::OnCancel() +{ + EndDialog(NULL); +} + +void CInputBox::SetCaption(CString Caption) +{ + m_Caption=Caption; +} + +void CInputBox::SetSentence(CString Sentence) +{ + m_Text=Sentence; +} + +BOOL CInputBox::OnInitDialog() +{ + CDialog::OnInitDialog(); + + SetWindowText(m_Caption); + SetDlgItemText(IDC_SENTENCE, m_Text); + + SetDlgItemText(IDOK, GetLanguageStringACP("OK")); + SetDlgItemText(IDCANCEL, GetLanguageStringACP("Cancel")); + + GetDlgItem(IDC_VAL)->SetFocus(); + + return FALSE; +} diff --git a/MissionEditor/InputBox.h b/MissionEditor/InputBox.h new file mode 100644 index 0000000..ddb6bb0 --- /dev/null +++ b/MissionEditor/InputBox.h @@ -0,0 +1,76 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_INPUTBOX_H__90BA0F00_6AD4_11D3_99E1_FA6209BA1804__INCLUDED_) +#define AFX_INPUTBOX_H__90BA0F00_6AD4_11D3_99E1_FA6209BA1804__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// InputBox.h : Header-Datei +// + +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CInputBox + +CString InputBox(const char* Sentence, const char* Caption); + +class CInputBox : public CDialog +{ +// Konstruktion +public: + void SetSentence(CString Sentence); + void SetCaption(CString Caption); + CInputBox(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CInputBox) + enum { IDD = IDD_INPUTBOX }; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CInputBox) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CInputBox) + virtual void OnOK(); + virtual void OnCancel(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + CString m_Text; + CString m_Caption; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_INPUTBOX_H__90BA0F00_6AD4_11D3_99E1_FA6209BA1804__INCLUDED_ diff --git a/MissionEditor/IsoPaintThread.cpp b/MissionEditor/IsoPaintThread.cpp new file mode 100644 index 0000000..3527a21 --- /dev/null +++ b/MissionEditor/IsoPaintThread.cpp @@ -0,0 +1,74 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// IsoPaintThread.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "IsoPaintThread.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CIsoPaintThread + +IMPLEMENT_DYNCREATE(CIsoPaintThread, CWinThread) + +CIsoPaintThread::CIsoPaintThread() +{ +} + +CIsoPaintThread::~CIsoPaintThread() +{ +} + +BOOL CIsoPaintThread::InitInstance() +{ + // ZU ERLEDIGEN: Initialisierungen fĂ¼r jeden Thread hier durchfĂ¼hren + + while(TRUE) + { + // this worker thread just updates the main window + ((CFinalSunDlg*)theApp.GetMainWnd())->m_view.m_isoview->UpdateWindow(); + } + + return TRUE; +} + +int CIsoPaintThread::ExitInstance() +{ + // ZU ERLEDIGEN: Bereinigungen fĂ¼r jeden Thread hier durchfĂ¼hren + return CWinThread::ExitInstance(); +} + +BEGIN_MESSAGE_MAP(CIsoPaintThread, CWinThread) + //{{AFX_MSG_MAP(CIsoPaintThread) + // HINWEIS - Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros ein und entfernt diese. + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CIsoPaintThread diff --git a/MissionEditor/IsoPaintThread.h b/MissionEditor/IsoPaintThread.h new file mode 100644 index 0000000..69abef7 --- /dev/null +++ b/MissionEditor/IsoPaintThread.h @@ -0,0 +1,72 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_ISOPAINTTHREAD_H__13F04541_01CB_11D5_9C88_FB4495B57649__INCLUDED_) +#define AFX_ISOPAINTTHREAD_H__13F04541_01CB_11D5_9C88_FB4495B57649__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// IsoPaintThread.h : Header-Datei +// + + + +///////////////////////////////////////////////////////////////////////////// +// Thread CIsoPaintThread + +class CIsoPaintThread : public CWinThread +{ + DECLARE_DYNCREATE(CIsoPaintThread) +protected: + CIsoPaintThread(); // Dynamische Erstellung verwendet geschĂ¼tzten Konstruktor + +// Attribute +public: + +// Operationen +public: + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CIsoPaintThread) + public: + virtual BOOL InitInstance(); + virtual int ExitInstance(); + //}}AFX_VIRTUAL + +// Implementierung +protected: + virtual ~CIsoPaintThread(); + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CIsoPaintThread) + // HINWEIS - Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein und entfernt diese. + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_ISOPAINTTHREAD_H__13F04541_01CB_11D5_9C88_FB4495B57649__INCLUDED_ diff --git a/MissionEditor/IsoView.cpp b/MissionEditor/IsoView.cpp new file mode 100644 index 0000000..3e2830a --- /dev/null +++ b/MissionEditor/IsoView.cpp @@ -0,0 +1,6824 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +/* +ISOVIEW.CPP +Implementation of the isometric view. +*/ + +#include "stdafx.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +/* Includes */ +#include "FinalSun.h" +#include "IsoView.h" +#include "DynamicGraphDlg.h" +#include "infantry.h" +#include "building.h" +#include "unit.h" +#include "aircraft.h" +#include "waypointid.h" +#include "celltag.h" +#include "MyViewframe.h" +#include "inlines.h" +#include "macros.h" +#include "FinalSunDlg.h" +#include "loading.h" +#include "Structs.h" +#include "frontcliffmodifier.h" +#include "backcliffmodifier.h" +#include "LineDrawer.h" +#include "MapTool.h" +#include <format> +#include <chrono> +#include <algorithm> +#include "TextDrawer.h" + +/* -------- */ + +/* Externals */ +extern ACTIONDATA AD; +void GetNodeName(CString& name, int n); +/* --------- */ + +/* Overlay picture table (maximum overlay count=0xFF) */ +PICDATA* ovrlpics[0xFF][max_ovrl_img]; + +// cancel draw flag +BOOL bCancelDraw = FALSE; +BOOL bNoDraw = FALSE; + + +// this variable will be set to TRUE when the window has lost focus +// once the mouse is moved in the isoview again WITHOUT pressed button, it is set to FALSE again +BOOL bDoNotAllowScroll = FALSE; + + + +///////////////////////////////////////////////////////////////////////////// +// CIsoView + +IMPLEMENT_DYNCREATE(CIsoView, CScrollView) + +BOOL bNoThreadDraw = FALSE; +BOOL bDrawStats = TRUE; + +/*UINT PaintThreadProc( LPVOID pParam ) +{ + while(!bNoThreadDraw) + { + if(((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview!=NULL) ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->UpdateWindow(); + } + + return 0; // Thread erfolgreich ausgefĂ¼hrt +} +*/ + +class SurfaceLocker +{ +public: + SurfaceLocker(IDirectDrawSurface4* pDDS, LPRECT rect = nullptr) : + SurfaceLocker() + { + m_hasRect = rect != nullptr; + if (rect) + m_rect = *rect; + m_pDDS = pDDS; + m_ddsd.dwSize = sizeof(DDSURFACEDESC2); + m_ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + } + + DDSURFACEDESC2* ensure_locked() + { + if (m_locked) + return &m_ddsd; + + if (m_pDDS->GetSurfaceDesc(&m_ddsd) != DD_OK) + return nullptr; + + if (m_pDDS->Lock(m_hasRect ? &m_rect : nullptr, &m_ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL) != DD_OK) + return nullptr; + + m_locked = true; + + if (!m_ddsd.lpSurface) + return nullptr; // probably does not happen in reality + + return &m_ddsd; + } + + void ensure_unlocked() + { + if (m_locked) + { + m_pDDS->Unlock(m_hasRect ? &m_rect : nullptr); + } + m_locked = false; + } + + ~SurfaceLocker() + { + ensure_unlocked(); + } + + SurfaceLocker(const SurfaceLocker& other) = delete; + SurfaceLocker& operator=(const SurfaceLocker& other) = delete; + +private: + SurfaceLocker() = default; + +private: + IDirectDrawSurface4* m_pDDS = nullptr; + DDSURFACEDESC2 m_ddsd = { 0 }; + RECT m_rect = { 0 }; + bool m_hasRect = false; + bool m_locked = false; +}; + + +CIsoView::CIsoView() +{ + srand(GetTickCount()); + m_bAltCliff = FALSE; + m_NoMove = FALSE; + b_IsLoading = FALSE; + m_viewOffset = ProjectedVec(0, 0); + dd = NULL; + dd_1 = NULL; + lpds = NULL; + lpdsBack = NULL; + lpdsBackHighRes = nullptr; + lpdsTemp = NULL; + pf = DDPIXELFORMAT{ 0 }; + line.left = 0; + line.top = 0; + line.right = 0; + line.bottom = 0; + m_menu.LoadMenu(IDR_MAPVIEW); + m_drag = FALSE; + // _map=NULL; + AD.reset(); + m_BrushSize_x = 1; + m_BrushSize_y = 1; + rscroll = FALSE; + m_zooming = false; + bThreadPainting = TRUE; + m_viewScale = Vec2<CSProjected, float>(1.0f, 1.0f); + m_viewScaleControl = 1.0f; + updateFontScaled(); + //m_paintthread=new(CIsoPaintThread); + //m_paintthread->CreateThread(); + +} + +CIsoView::~CIsoView() +{ + // if(_map!=NULL) delete[] _map; + // _map=NULL; + //delete m_paintthread; + bNoThreadDraw = TRUE; +} + + +BEGIN_MESSAGE_MAP(CIsoView, CView) + //{{AFX_MSG_MAP(CIsoView) + ON_WM_SYSCOMMAND() + ON_WM_VSCROLL() + ON_WM_HSCROLL() + ON_WM_MOUSEMOVE() + ON_WM_RBUTTONUP() + ON_WM_LBUTTONDBLCLK() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_MOVE() + ON_WM_SIZE() + ON_WM_CHAR() + ON_WM_DEADCHAR() + ON_WM_KEYDOWN() + ON_WM_KEYUP() + ON_WM_TIMER() + ON_WM_RBUTTONDOWN() + ON_WM_KILLFOCUS() + ON_WM_MOUSEWHEEL() + //}}AFX_MSG_MAP + ON_WM_MBUTTONDOWN() + ON_WM_MBUTTONUP() +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Zeichnung CIsoView + +void CIsoView::OnInitialUpdate() +{ + CView::OnInitialUpdate(); +} + + +struct CHANGEHEIGHTDATA +{ + int pos; + BOOL bNonMorpheable; + DWORD toHeight; +}; + + +DWORD WINAPI ChangeHeightThread( + LPVOID lpParameter // thread data +) +{ + CHANGEHEIGHTDATA* p = (CHANGEHEIGHTDATA*)lpParameter; + + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->ChangeTileHeight(p->pos, p->toHeight, p->bNonMorpheable); + + return 0; +} + +/* +dst must be surface data, src must be a 8 bit palette image +*/ +#ifdef NOSURFACES + +struct BlitRect +{ + short left; + short top; + short right; + short bottom; +}; + +__forceinline void BlitTerrain(void* dst, int x, int y, int dleft, int dtop, int dpitch, int dright, int dbottom, const SUBTILE& st)//BYTE* src, int swidth, int sheight) +{ + BYTE* src = st.pic; + const unsigned short swidth = st.wWidth; + const unsigned short sheight = st.wHeight; + + + if (src == NULL || dst == NULL) return; + + //x += 1; + //y += 1; + //y -= f_y; + + if (x + swidth < dleft || y + sheight < dtop) return; + if (x >= dright || y >= dbottom) return; + + + BlitRect blrect; + BlitRect srcRect; + srcRect.left = 0; + srcRect.top = 0; + srcRect.right = swidth; + srcRect.bottom = sheight; + blrect.left = x; + + + if (blrect.left < 0) + { + srcRect.left = 1 - blrect.left; + blrect.left = 1; + } + blrect.top = y; + if (blrect.top < 0) + { + srcRect.top = 1 - blrect.top; + blrect.top = 1; + } + blrect.right = (x + swidth); + if (x + swidth > dright) + { + srcRect.right = dright - x;//swidth-((x+swidth)-dright); + blrect.right = dright; + } + blrect.bottom = (y + sheight); + if (y + sheight > dbottom) + { + srcRect.bottom = dbottom - y;//sheight-((y+sheight)-dbottom); + blrect.bottom = dbottom; + } + + + short i, e; + + +#ifdef NOSURFACES_EXTRACT + int pos = 0; + if (!st.bNotExtracted) + { + for (e = srcRect.top;e < srcRect.bottom;e++) + { + short left = st.vborder[e].left; + short right = st.vborder[e].right; + + short realright = right; + //short realleft=left; + //short addx_s=0; + + if (right >= srcRect.right) right = srcRect.right - 1; + if (srcRect.left > 0) + { + pos += (realright - left + 1) * bpp; + continue; // just cancel. this area is used by object browser. saves some performance + //addx_s=srcRect.left; + //left=max(left, srcRect.left); + //left=//addx=left-srcRect.left; + } + + if (realright >= left) + { + if (/*left<srcRect.left ||*/ left >= srcRect.right) + { + pos += (realright - left + 1) * bpp; + continue; + } + + + void* dest = ((BYTE*)dst + (blrect.left + left) * bpp + (blrect.top + e) * dpitch); + + memcpy(dest, &st.pic[pos], bpp * (right - left + 1)); + pos += (realright - left + 1) * bpp; + } + } + } + else + +#endif + for (e = srcRect.top;e < srcRect.bottom;e++) + { + short& left = st.vborder[e].left; + short& right = st.vborder[e].right; + + auto l = max(left, srcRect.left); + auto r = min(right, static_cast<short>(srcRect.right - 1)); + for (i = l;i <= r;i++) + { + //if (i < srcRect.left || i >= srcRect.right) + { + //dest+=bpp; + } + //else + { + + BYTE& val = src[i + e * swidth]; + if (val) + { + void* dest = ((BYTE*)dst + (blrect.left + i) * bpp + (blrect.top + e) * dpitch); + + memcpy(dest, &iPalIso[val], bpp); + } + } + } + + } + +} + + +__forceinline void BlitTerrainHalfTransp(void* dst, int x, int y, int dleft, int dtop, int dpitch, int dright, int dbottom, const SUBTILE& st)//BYTE* src, int swidth, int sheight) +{ + BYTE* src = st.pic; + const unsigned short swidth = st.wWidth; + const unsigned short sheight = st.wHeight; + + + if (src == NULL || dst == NULL) return; + + //x += 1; + //y += 1; + //y -= f_y; + + if (x + swidth < dleft || y + sheight < dtop) return; + if (x >= dright || y >= dbottom) return; + + + BlitRect blrect; + BlitRect srcRect; + srcRect.left = 0; + srcRect.top = 0; + srcRect.right = swidth; + srcRect.bottom = sheight; + blrect.left = x; + + + if (blrect.left < 0) + { + srcRect.left = 1 - blrect.left; + blrect.left = 1; + } + blrect.top = y; + if (blrect.top < 0) + { + srcRect.top = 1 - blrect.top; + blrect.top = 1; + } + blrect.right = (x + swidth); + if (x + swidth > dright) + { + srcRect.right = dright - x;//swidth-((x+swidth)-dright); + blrect.right = dright; + } + blrect.bottom = (y + sheight); + if (y + sheight > dbottom) + { + srcRect.bottom = dbottom - y;//sheight-((y+sheight)-dbottom); + blrect.bottom = dbottom; + } + + + short i, e; + + +#ifdef NOSURFACES_EXTRACT + int pos = 0; + if (!st.bNotExtracted) + { + int a = 0; + for (e = srcRect.top;e < srcRect.bottom;e += 1) + { + short left = st.vborder[e].left; + short right = st.vborder[e].right; + + short realright = right; + + if (right >= srcRect.right) right = srcRect.right - 1; + if (srcRect.left > 0) + { + pos += (realright - left + 1) * bpp; + continue; // just cancel. this area is used by object browser. saves some performance + } + + a++; + + if (realright >= left) + { + if (/*left<srcRect.left ||*/ left >= srcRect.right) + { + pos += (realright - left + 1) * bpp; + continue; + } + + + void* dest = ((BYTE*)dst + (blrect.left + left) * bpp + (blrect.top + e) * dpitch); + + //memcpy(dest, &st.pic[pos], bpp*(right-left+1)); + //pos+=(right-left+1)*bpp; + + for (i = left + a % 2;i <= right;i += 2) + { + if (i < srcRect.left || i >= srcRect.right) + { + //dest+=bpp; + } + else + { + + //BYTE& val=st.pic[pos+i*bpp]; + //if(val) + { + void* dest2 = (BYTE*)dest + (i - left) * bpp; //((BYTE*)dst+(blrect.left+i)*bpp+(blrect.top+e)*dpitch); + + memcpy(dest2, &st.pic[pos + (i - left) * bpp], bpp); + } + } + } + + pos += (realright - left + 1) * bpp; + } + } + } + else + +#endif + { + int a = 0; + for (e = srcRect.top;e < srcRect.bottom;e++) + { + short& left = st.vborder[e].left; + short& right = st.vborder[e].right; + + + a++; + + for (i = left + a % 2;i <= right;i += 2) + { + if (i < srcRect.left || i >= srcRect.right) + { + //dest+=bpp; + } + else + { + + BYTE& val = src[i + e * swidth]; + if (val) + { + void* dest = ((BYTE*)dst + (blrect.left + i) * bpp + (blrect.top + e) * dpitch); + + memcpy(dest, &iPalIso[val], bpp); + } + } + } + + + } + } + +} + + +const int houseColorMin = 0x10; +const int houseColorMax = 0x1f; +const int houseColorRelMax = houseColorMax - houseColorMin; + +inline void CalculateHouseColorPalette(int house_pal[houseColorRelMax + 1], const int* default_pal, const int* color = NULL) +{ + if (color) + { + if (bpp == 4) + { + for (int n = 0; n <= houseColorRelMax; ++n) + { + const int v = (houseColorRelMax - n); + auto src = reinterpret_cast<const BYTE*>(color); + auto bdest = reinterpret_cast<BYTE*>(&house_pal[n]); + bdest[0] = src[0] * v / houseColorRelMax; + bdest[1] = src[1] * v / houseColorRelMax; + bdest[2] = src[2] * v / houseColorRelMax; + bdest[3] = src[3]; + } + } + else + { + // nowadays only 32 bit rendering should be used, so we take a shortcut here + for (int n = 0; n <= houseColorRelMax; ++n) + { + house_pal[n] = *color; + } + } + } + else + { + for (int n = 0; n <= houseColorRelMax; ++n) + { + house_pal[n] = default_pal[n + houseColorMin]; + } + } +} + + +/* +There is no need for newpal +*/ +__forceinline void BlitPic(void* dst, int x, int y, int dleft, int dtop, int dpitch, int dright, int dbottom, PICDATA& pd, int* color = NULL, int* newPal = NULL)//BYTE* src, int swidth, int sheight) +{ + ASSERT(pd.bType != PICDATA_TYPE_BMP); + + if (newPal == NULL) newPal = pd.pal; + + BYTE* src = (BYTE*)pd.pic; + int swidth = pd.wMaxWidth; + int sheight = pd.wMaxHeight; + + if (src == NULL || dst == NULL) return; + + //x += 1; + //y += 1; + //y -= f_y; + + if (x + swidth < dleft || y + sheight < dtop) return; + if (x >= dright || y >= dbottom) return; + + + RECT blrect; + RECT srcRect; + srcRect.left = 0; + srcRect.top = 0; + srcRect.right = swidth; + srcRect.bottom = sheight; + blrect.left = x; + if (blrect.left < 0) + { + srcRect.left = 1 - blrect.left; + //blrect.left=1; + } + blrect.top = y; + if (blrect.top < 0) + { + srcRect.top = 1 - blrect.top; + //blrect.top=1; + } + blrect.right = (x + swidth); + if (x + swidth > dright) + { + srcRect.right = swidth - ((x + swidth) - dright); + blrect.right = dright; + } + blrect.bottom = (y + sheight); + if (y + sheight > dbottom) + { + srcRect.bottom = sheight - ((y + sheight) - dbottom); + blrect.bottom = dbottom; + } + + + int i, e; + + // calculate a palette for given color for values 0x10 to 0x1f - we might move this outside + const int houseColorMin = 0x10; + const int houseColorMax = 0x1f; + const int houseColorRelMax = houseColorMax - houseColorMin; + int houseColors[houseColorRelMax + 1] = { 0 }; + CalculateHouseColorPalette(houseColors, newPal, color); + const BYTE* const pLighting = (bpp == 4 && pd.lighting && !pd.lighting->empty()) ? pd.lighting->data() : nullptr; + + for (e = srcRect.top;e < srcRect.bottom;e++) + { + int left = pd.vborder[e].left; + int right = pd.vborder[e].right; + + if (left < srcRect.left) + left = srcRect.left; + if (right >= srcRect.right) + right = srcRect.right - 1; + + for (i = left;i <= right;i++) + { + if (blrect.left + i < 0) + continue; + + const int spos = i + e * swidth; + BYTE val = src[spos]; + + if (val) + { + void* dest = ((BYTE*)dst + (blrect.left + i) * bpp + (blrect.top + e) * dpitch); + + if (dest >= dst) + { + int c; + if (!color || newPal != iPalUnit || val < houseColorMin || val > houseColorMax) + { + c = newPal[val]; + } + else + { + // Replace the original palette color with the house color + ASSERT(val >= houseColorMin && val <= houseColorMax); + const int v = (val - houseColorMin); + c = houseColors[v]; + } + if (pLighting) + { + // bpp == 4 + ASSERT(bpp == 4); + int l = pLighting[spos]; + BYTE* bc = reinterpret_cast<BYTE*>(&c); + for (int i = 0; i < 4; ++i) + bc[i] = min(255, bc[i] * (200 + l * 300 / 255) / 255); // game seems to overbrighten and have a lot of ambient - if you change this, also change Loading.cpp shp lighting value so that shp light stays at 1.0 + //bc[i] = min(255, bc[i] * (0 + l * (255 - 0) / 255) / 255); + } + memcpy(dest, &c, bpp); + } + } + } + } +} + +__forceinline void BlitPicHalfTransp(void* dst, int x, int y, int dleft, int dtop, int dpitch, int dright, int dbottom, PICDATA& pd, int* color = NULL, int* newPal = NULL)//BYTE* src, int swidth, int sheight) +{ + ASSERT(pd.bType != PICDATA_TYPE_BMP); + + if (newPal == NULL) newPal = pd.pal; + + BYTE* src = (BYTE*)pd.pic; + int swidth = pd.wMaxWidth; + int sheight = pd.wMaxHeight; + + if (src == NULL || dst == NULL) return; + + //x += 1; + //y += 1; + //y -= f_y; + + if (x + swidth < dleft || y + sheight < dtop) return; + if (x >= dright || y >= dbottom) return; + + + RECT blrect; + RECT srcRect; + srcRect.left = 0; + srcRect.top = 0; + srcRect.right = swidth; + srcRect.bottom = sheight; + blrect.left = x; + if (blrect.left < 0) + { + srcRect.left = 1 - blrect.left; + //blrect.left=1; + } + blrect.top = y; + if (blrect.top < 0) + { + srcRect.top = 1 - blrect.top; + //blrect.top=1; + } + blrect.right = (x + swidth); + if (x + swidth > dright) + { + srcRect.right = swidth - ((x + swidth) - dright); + blrect.right = dright; + } + blrect.bottom = (y + sheight); + if (y + sheight > dbottom) + { + srcRect.bottom = sheight - ((y + sheight) - dbottom); + blrect.bottom = dbottom; + } + + + int i, e; + + + + + for (e = srcRect.top;e < srcRect.bottom;e++) + { + + + int left = pd.vborder[e].left; + int right = pd.vborder[e].right; + if (left < srcRect.left) left = srcRect.left; + if (right >= srcRect.right) right = srcRect.right - 1; + + int a = e % 2 + left % 2; + + for (i = left + a;i <= right;i += 2) + { + //a++; + + if (blrect.left + i < 0) continue; + //if(a%2) continue; + + BYTE& val = src[i + e * swidth]; + //0x10-0x1f, + if (val) + { + void* dest = ((BYTE*)dst + (blrect.left + i) * bpp + (blrect.top + e) * dpitch); + //*dest=newPal[val]; + if (dest >= dst) + { + if (!color || newPal != iPalUnit || val < 0x10 || val>0x1f) + { + memcpy(dest, &newPal[val], bpp); + } + else + { + //int col=0; + memcpy(dest, color, bpp); + } + } + } + } + } +} +#endif + + + + +///////////////////////////////////////////////////////////////////////////// +// Diagnose CIsoView + +#ifdef _DEBUG +void CIsoView::AssertValid() const +{ + CView::AssertValid(); +} + +void CIsoView::Dump(CDumpContext& dc) const +{ + CView::Dump(dc); +} +#endif //_DEBUG + +/////////////updateFontScaled//////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CIsoView + +void CIsoView::updateFontScaled() +{ + auto dc = CDC::FromHandle(::GetDC(NULL)); + m_fontDefaultHeight = -MulDiv(12, dc->GetDeviceCaps(LOGPIXELSY), 72); + m_Font9Height = -MulDiv(9, dc->GetDeviceCaps(LOGPIXELSY), 72); + + if (dd) + { + m_textDefault.reset(new TextDrawer(dd, m_fontDefaultHeight, RGB(0,0,0), RGB(255, 255, 255))); + m_text9.reset(new TextDrawer(dd, m_Font9Height, RGB(0, 0, 0), RGB(255, 255, 255))); + m_textScaled.reset(new TextDrawer(dd, m_fontDefaultHeight / m_viewScale.y, RGB(0, 0, 0), RGB(255, 255, 255))); + m_text9Scaled.reset(new TextDrawer(dd, m_Font9Height / m_viewScale.y, RGB(0, 0, 0), RGB(255, 255, 255))); + m_textBlue.reset(new TextDrawer(dd, m_fontDefaultHeight, RGB(0, 0, 255), RGB(255, 255, 255))); + m_textBlueScaled.reset(new TextDrawer(dd, m_fontDefaultHeight / m_viewScale.y, RGB(0, 0, 255), RGB(255, 255, 255))); + m_textBlue9.reset(new TextDrawer(dd, m_Font9Height, RGB(0, 0, 255), RGB(255, 255, 255))); + m_textBlue9Scaled.reset(new TextDrawer(dd, m_Font9Height / m_viewScale.y, RGB(0, 0, 255), RGB(255, 255, 255))); + } +} + +BOOL CIsoView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) +{ + + BOOL r = CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext); + + this->SetScrollRange(SB_HORZ, 0, 1, TRUE); + this->SetScrollRange(SB_VERT, 0, 1, TRUE); + + // AfxBeginThread(PaintThreadProc, 0, 0, 0xFFFF); + + return r; +} + +void CIsoView::OnSysCommand(UINT nID, LPARAM lParam) +{ + // TODO: Code fĂ¼r die Behandlungsroutine fĂ¼r Nachrichten hier einfĂ¼gen und/oder Standard aufrufen + if (nID == SC_CLOSE) + { + // ok now just hide the window + ShowWindow(SW_HIDE); + return; + } + + CView::OnSysCommand(nID, lParam); +} + +inline int GetScrPos(CWnd* pOwner, UINT nSB, UINT nSBCode, UINT& nPos) +{ + SCROLLINFO scr; + scr.cbSize = sizeof(SCROLLINFO); + scr.fMask = SIF_ALL; + + pOwner->GetScrollInfo(nSB, &scr); + + switch (nSBCode) + { + case SB_LEFT: + { + nPos = scr.nMin; + break; + } + case SB_RIGHT: + { + nPos = scr.nMax; + break; + } + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + { + break; + } + case SB_LINELEFT: + { + nPos = scr.nPos - 1; + break; + } + case SB_LINERIGHT: + { + nPos = scr.nPos + 1; + break; + } + case SB_PAGELEFT: + { + nPos = scr.nPos - 5; + break; + } + case SB_PAGERIGHT: + { + nPos = scr.nPos + 5; + break; + } + } + + return nPos; + +} + +void CIsoView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + if (nSBCode == SB_ENDSCROLL || nSBCode == SB_THUMBTRACK) return; + + + nPos = GetScrPos(this, SB_VERT, nSBCode, nPos); + + this->SetScrollPos(SB_VERT, nPos, TRUE); + + m_viewOffset.y = (nPos + Map->GetWidth() / 2 - 4) * f_y; + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + CMyViewFrame& dlg = *(CMyViewFrame*)owner; + dlg.m_minimap.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + +void CIsoView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + if (nSBCode == SB_ENDSCROLL || nSBCode == SB_THUMBTRACK) return; + + + + nPos = GetScrPos(this, SB_HORZ, nSBCode, nPos); + + RECT r; + GetWindowRect(&r); + m_viewOffset.x = (nPos + Map->GetHeight() / 2 - 1) * f_x; + + this->SetScrollPos(SB_HORZ, nPos, TRUE); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + CMyViewFrame& dlg = *(CMyViewFrame*)owner; + dlg.m_minimap.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + +/* +This function is called when any data has been changed in another dialog. +It is used to initialize and update the dialog. +*/ +void CIsoView::UpdateDialog(BOOL bRepos) +{ + OutputDebugString("Isoview updated\n"); + + UpdateOverlayPictures(); + + + if (bRepos && Map->GetIsoSize() != 0) + { + m_viewScale = Vec2<CSProjected, float>(1.0f, 1.0f); + m_viewScaleControl = 1.0f; + auto r = GetScaledDisplayRect(); + UpdateScrollRanges(); + SetScroll((Map->GetIsoSize() / 2 - r.right / f_x / 2) * f_x, (Map->GetIsoSize() / 2 - r.bottom / f_y / 2) * f_y); + } + + RedrawWindow(NULL, NULL, RDW_INVALIDATE); + +} + +void CIsoView::UpdateScrollRanges() +{ + auto r = GetScaledDisplayRect(); + SetScrollRange(SB_HORZ, 0, Map->GetWidth() - r.right / f_x + 4, TRUE); + SetScrollRange(SB_VERT, 0, Map->GetHeight() - r.bottom / f_y + 6, TRUE); +} + +BOOL CIsoView::PreCreateWindow(CREATESTRUCT& cs) +{ + // we overwrite that, because in debug version its necessary that a view is a child window! + + // save the old style and let CView::PreCreateWindow() think we are using a child window, then restore old style. + int ostyle = cs.style; + cs.style |= WS_CHILD | WS_VSCROLL | WS_HSCROLL; + + BOOL bres = CView::PreCreateWindow(cs); + cs.style = ostyle; + + return bres; + +} + + +void CIsoView::OnMouseMove(UINT nFlags, CPoint point) +{ + if (b_IsLoading) return; + + static BOOL isMoving = FALSE; + + CIniFile& ini = Map->GetIniFile(); + + cur_x_mouse = point.x; + cur_y_mouse = point.y; + + if (!(nFlags & MK_RBUTTON)) bDoNotAllowScroll = FALSE; + + if (rscroll) + { + if (!(nFlags & MK_RBUTTON)) + { + ReleaseCapture(); + KillTimer(11); + rscroll = FALSE; + ShowCursor(TRUE); + + CMyViewFrame& dlg = *(CMyViewFrame*)owner; + dlg.m_minimap.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + } + else + { + + isMoving = FALSE; + return; + } + } + + if (!bDoNotAllowScroll && (nFlags & MK_RBUTTON) && !rscroll) // check if scroll should start + { + if (abs(point.x - rclick_x) > 2 || abs(point.y - rclick_y) > 2) + { + // yes, begin scrolling! + + rscroll = TRUE; + SetTimer(11, 25, NULL); + SetCapture(); + //while(ShowCursor(FALSE)>0); + isMoving = FALSE; + return; + } + } + + if ((nFlags & MK_MBUTTON) == 0) + m_zooming = false; + + if (!bDoNotAllowScroll && m_zooming) + { + if ((nFlags & MK_MBUTTON) == MK_MBUTTON) + { + auto diff = point - m_MButtonMoveZooming; + m_MButtonMoveZooming = point; + Zoom(m_MButtonDown, -diff.cy / 1000.0f); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + return; + } + } + + m_moved = TRUE; + + if (b_IsLoading == TRUE) return; + if (Map->GetIsoSize() == 0 || isMoving == TRUE || m_zooming) return; + + isMoving = TRUE; + + // SetError(TranslateStringACP("Ready")); + + RECT r; + //GetClientRect(&r); + //ClientToScreen(&r); + GetWindowRect(&r); + + const auto viewOffsetWR = m_viewOffset + ProjectedVec(r.left, r.top); + const auto projCoords = GetProjectedCoordinatesFromClientCoordinates(point); + const MapCoords mapCoords = GetMapCoordinatesFromClientCoordinates(point, (nFlags & MK_CONTROL) == MK_CONTROL); + m_cellCursor = MapCoords(-1, -1); + const int x = mapCoords.x; // compat + const int y = mapCoords.y; + + int mapwidth = Map->GetWidth(); + int mapheight = Map->GetHeight(); + + BOOL bOutside = FALSE; + + if (AD.mode != ACTIONMODE_COPY && AD.mode != ACTIONMODE_PASTE) + { + if (x < 1 || y < 1 || x + y<mapwidth + 1 || x + y>mapwidth + mapheight * 2 || (y + 1 > mapwidth && x - 1 < y - mapwidth) || (x + 1 > mapwidth && y + mapwidth - 1 < x)) + { + isMoving = FALSE; + return; + } + } + else + { + if (x < 1 || y < 1 || x >= mapwidth + mapheight - 1 || y >= mapwidth + mapheight - 1) + { + bOutside = TRUE; + if (AD.mode == ACTIONMODE_COPY || AD.mode == ACTIONMODE_PASTE) + { + isMoving = FALSE; + return; + } + } + } + + + + if (lpdsBack) + // reset back buffer to last DrawMap() + lpdsBack->BltFast(0, 0, lpdsTemp, NULL, DDBLTFAST_WAIT); + //lpdsBack->Blt(NULL, lpdsTemp, NULL, 0, 0); + + //int cell_x = x; + //int cell_y = y; + + { + // Preview rendering + if (AD.mode == ACTIONMODE_SETTILE && !((nFlags & MK_LBUTTON) && !(nFlags & MK_CONTROL) && (nFlags & MK_SHIFT))) + { + // No placement, just preview + + bCancelDraw = TRUE; + + int i, e, f, n; + int p = 0; + //FIELDDATA oldData[36][36][10][10]; + int width = (*tiledata)[AD.type].cx; + int height = (*tiledata)[AD.type].cy; + int pos = x - width + 1 + (y - height + 1) * Map->GetIsoSize(); + int startheight = Map->GetHeightAt(x + y * Map->GetIsoSize()) + AD.z_data; + int ground = (Map->GetFielddataAt(x + y * Map->GetIsoSize()))->wGround; + if (ground == 0xFFFF) ground = 0; + startheight -= (*tiledata)[ground].tiles[Map->GetFielddataAt(x + y * Map->GetIsoSize())->bSubTile].bZHeight; + TILEDATA td = (*tiledata)[AD.type]; + + Map->TakeSnapshot(TRUE, x - width - 4, y - height - 4, x - width + m_BrushSize_x * width + 7, y - height + m_BrushSize_y * height + 7); + int cur_pos = pos; + int isosize = Map->GetIsoSize(); + int height_add = height * isosize; + char c[50]; + itoa(AD.data, c, 10); + for (f = 0;f < m_BrushSize_x;f++) + { + for (n = 0;n < m_BrushSize_y;n++) + { + + int tile = AD.type; + + if (AD.data == 1) + { + int n = rand() * 5 / RAND_MAX; + tile += n; + } + + + + cur_pos = pos + f * width + n * height_add; + p = 0; + for (i = 0;i < td.cx;i++) + { + for (e = 0;e < td.cy;e++) + { + if (x - width + 1 + f * width + i >= Map->GetIsoSize() || + y - height + 1 + n * height + e >= Map->GetIsoSize()) + { + } + else + if (td.tiles[p].pic != NULL) + { + int mypos = cur_pos + i + e * isosize; + + Map->SetHeightAt(mypos, startheight + td.tiles[p].bZHeight); + Map->SetTileAt(mypos, tile, p); + + + + } + p++; + + } + } + + + } + } + + if (!((nFlags & MK_CONTROL) && (nFlags & MK_SHIFT))) + { + if (!theApp.m_Options.bDisableAutoShore) Map->CreateShore(x - width - 2, y - height - 2, x - width + td.cx * m_BrushSize_x + 5, y - height + td.cy * m_BrushSize_y + 5, FALSE); + + for (f = 0;f < m_BrushSize_x;f++) + { + for (n = 0;n < m_BrushSize_y;n++) + { + cur_pos = pos + f * width + n * height_add; + p = 0; + for (i = -1;i < td.cx + 1;i++) + { + for (e = -1;e < td.cy + 1;e++) + { + Map->SmoothAllAt(cur_pos + i + (e)*isosize); + } + } + + + } + } + } + + + + bCancelDraw = FALSE; + DrawMap(); + + + Map->Undo(); + + m_drag = FALSE; + + } + else if (m_drag && AD.mode == ACTIONMODE_CLIFFFRONT) + { + RECT affect; + if (m_mapx < x) affect.left = m_mapx - 2; else affect.left = x - 2; + if (m_mapx < x) affect.right = x + 2; else affect.right = m_mapx + 2; + if (m_mapy < y) affect.top = m_mapy - 2; else affect.top = y - 2; + if (m_mapy < y) affect.bottom = y + 2; else affect.bottom = m_mapy + 2; + + //Map->TakeSnapshot(); + Map->TakeSnapshot(TRUE, affect.left, affect.top, affect.right, affect.bottom); + CFrontCliffModifier f; + BOOL bAlt = FALSE; + if (Map->GetTheater() == THEATER3 && m_bAltCliff) + bAlt = TRUE; + f.PlaceCliff(m_mapx, m_mapy, x, y, bAlt); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + //Map->TakeSnapshot(); + Map->TakeSnapshot(TRUE, affect.left, affect.top, affect.right, affect.bottom); + Map->Undo(); + Map->Undo(); + } + else if (m_drag && AD.mode == ACTIONMODE_CLIFFBACK) + { + RECT affect; + if (m_mapx < x) affect.left = m_mapx - 2; else affect.left = x - 2; + if (m_mapx < x) affect.right = x + 2; else affect.right = m_mapx + 2; + if (m_mapy < y) affect.top = m_mapy - 2; else affect.top = y - 2; + if (m_mapy < y) affect.bottom = y + 2; else affect.bottom = m_mapy + 2; + + //Map->TakeSnapshot(); + Map->TakeSnapshot(TRUE, affect.left, affect.top, affect.right, affect.bottom); + CBackCliffModifier f; + BOOL bAlt = FALSE; + if (Map->GetTheater() == THEATER3 && m_bAltCliff) + bAlt = TRUE; + f.PlaceCliff(m_mapx, m_mapy, x, y); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + //Map->TakeSnapshot(); + Map->TakeSnapshot(TRUE, affect.left, affect.top, affect.right, affect.bottom); + Map->Undo(); + Map->Undo(); + } + else if (AD.mode == ACTIONMODE_COPY && m_drag) + { + last_succeeded_operation = 80301; //bugtracing once more + + int x1, x2, y1, y2; + if (m_mapx < x) + { + x1 = m_mapx; + x2 = x; + } + else + { + x1 = x; + x2 = m_mapx; + } + if (m_mapy < y) + { + y1 = m_mapy; + y2 = y; + } + else + { + y1 = y; + y2 = m_mapy; + } + + DDSURFACEDESC2 ddsd; + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + + lpdsBack->GetSurfaceDesc(&ddsd); + + + lpdsBack->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL); + + int i, e; + int isosize = Map->GetIsoSize(); + for (i = 0;i < x2 - x1 + 1;i++) + { + for (e = 0;e < y2 - y1 + 1;e++) + { + last_succeeded_operation = 80302; + int x_s = x1 + i; + int y_s = y1 + e; + + if (x_s < 0 || y_s < 0 || x_s >= isosize || y_s >= isosize) continue; + + if (theApp.m_Options.bFlat) ToPhys(&x_s, &y_s); else ToPhys3d(&x_s, &y_s); + x_s -= m_viewOffset.x; + y_s -= m_viewOffset.y; + + last_succeeded_operation = 80305; + DrawCell(ddsd.lpSurface, ddsd.dwWidth, ddsd.dwHeight, ddsd.lPitch, x_s, y_s, 1, 1, m_color_converter->GetColor(255, 0, 0)); + last_succeeded_operation = 80303; + } + } + + lpdsBack->Unlock(NULL); + + BlitBackbufferToHighRes(); + RenderUIOverlay(); + FlipHighResBuffer(); + last_succeeded_operation = 80304; + } + else if (AD.mode == ACTIONMODE_PASTE) + { + Map->TakeSnapshot(); + Map->Paste(x, y, AD.z_data); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + Map->Undo(); + } + else if ((AD.mode == ACTIONMODE_PLACE || AD.mode == ACTIONMODE_RANDOMTERRAIN) && (nFlags & ~MK_CONTROL) == 0 && AD.type != 7 && (AD.type != 6 || (AD.type == 6 && ((AD.data >= 30 && AD.data <= 33) || AD.data == 2 || AD.data == 3)))) // everything placing but not overlay! + { + FIELDDATA oldData[32][32]; + INFANTRY infData[SUBPOS_COUNT][32][32]; + int i, e; + + //if(AD.type!=1 || Map->GetInfantryCountAt(x+y*Map->GetIsoSize())==0) + { + for (i = 0;i < 32;i++) + { + for (e = 0;e < 32;e++) + { + oldData[i][e] = *Map->GetFielddataAt(i + x + (e + y) * Map->GetIsoSize()); + int z; + for (z = 0;z < SUBPOS_COUNT;z++) + if (oldData[i][e].infantry[z] > -1) + Map->GetInfantryData(oldData[i][e].infantry[z], &infData[z][i][e]); + } + } + + PlaceCurrentObjectAt(x, y); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + for (i = 0;i < 32;i++) + { + for (e = 0;e < 32;e++) + { + DWORD dwPos = i + x + (e + y) * Map->GetIsoSize(); + FIELDDATA cur_field; + cur_field = *Map->GetFielddataAt(dwPos); + + if (cur_field.aircraft != oldData[i][e].aircraft) + Map->DeleteAircraft(cur_field.aircraft); + int z; + for (z = 0;z < SUBPOS_COUNT;z++) + if (cur_field.infantry[z] != oldData[i][e].infantry[z]) + { + Map->DeleteInfantry(cur_field.infantry[z]); + } + + if (cur_field.node.index != oldData[i][e].node.index) + { + CString house; + int id = Map->GetNodeAt(dwPos, house); + Map->DeleteNode(house, id); + } + if (cur_field.structure != oldData[i][e].structure) + Map->DeleteStructure(cur_field.structure); + if (cur_field.terrain != oldData[i][e].terrain) + Map->DeleteTerrain(cur_field.terrain); +#ifdef SMUDGE_SUPP + if (cur_field.smudge != oldData[i][e].smudge) + Map->DeleteSmudge(cur_field.smudge); +#endif + if (cur_field.unit != oldData[i][e].unit) + Map->DeleteUnit(cur_field.unit); + + if (cur_field.overlay != oldData[i][e].overlay) + Map->SetOverlayAt(dwPos, oldData[i][e].overlay); + if (cur_field.overlaydata != oldData[i][e].overlaydata) + Map->SetOverlayDataAt(dwPos, oldData[i][e].overlaydata); + + Map->SetFielddataAt(dwPos, &oldData[i][e]); + } + } + } + //else + // RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + } + else + { + + SurfaceLocker locker(lpdsBack); + auto desc = locker.ensure_locked(); + if (desc) + DrawCellCursor(mapCoords, *desc); + m_cellCursor = mapCoords; + //RedrawWindow(NULL, NULL, RDW_INVALIDATE); + locker.ensure_unlocked(); + + BlitBackbufferToHighRes(); + RenderUIOverlay(); + FlipHighResBuffer(); + } + } + + + + + + + // display the coordinates + char c[50]; + CString cap; + itoa(x, c, 10); + cap += c; + cap += " / "; + itoa(y, c, 10); + cap += c; + cap += " - "; + itoa(Map->GetHeightAt(x + y * Map->GetIsoSize()), c, 10); + cap += c; + + CStatusBarCtrl& stat = ((CMyViewFrame*)owner)->m_statbar.GetStatusBarCtrl(); + stat.SetText(cap, 1, 0); + + + // drag + if (m_drag && AD.mode == 0) + { + RedrawWindow(NULL, NULL, RDW_INVALIDATE); + + CPaintDC dc(this); + dc.SetROP2(R2_NOT); + + const auto renderOffset = CPoint(f_x / 2 / m_viewScale.x, f_y / 2 / m_viewScale.y); + const auto from = GetClientCoordinates(MapCoords(m_mapx, m_mapy)) + renderOffset; + const auto to = GetClientCoordinates(mapCoords) + renderOffset; + + dc.MoveTo(from.x, from.y); + dc.LineTo(to.x, to.y); + } + else if (AD.mode == ACTIONMODE_SETTILE && (nFlags & MK_LBUTTON) && ((nFlags & MK_SHIFT) || Map->hasLat(AD.type)) && !(nFlags & MK_CONTROL)) + { + // Sound(SOUND_LAYDOWNTILE); // too many sounds + + PlaceTile(x, y, nFlags); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + isMoving = FALSE; + return; + } + else if ((nFlags & MK_LBUTTON) && (nFlags & MK_SHIFT) && AD.mode == ACTIONMODE_HEIGHTEN) + { + OnLButtonDown(nFlags, point); + isMoving = FALSE; + return; + } + else if ((nFlags & MK_LBUTTON) && (nFlags & MK_SHIFT) && AD.mode == ACTIONMODE_LOWER) + { + OnLButtonDown(nFlags, point); + isMoving = FALSE; + return; + } + + else if ((nFlags == MK_LBUTTON) && AD.mode == ACTIONMODE_FLATTENGROUND) + { + m_TileChangeCount = 0; + + // if(abs(m_FlattenLastX-x)<2 && abs(m_FlattenLastY-y)<2) //ReachableFrom(x+y*Map->GetIsoSize(), m_mapx+m_mapy*Map->GetIsoSize())) + int ground = Map->GetFielddataAt(x + (y)*Map->GetIsoSize())->wGround; + if (ground == 0xFFFF) ground = 0; + + //if((*tiledata)[ground].bMorphable) + { + + int left = -m_BrushSize_x / 2; + int right = m_BrushSize_x / 2 + 1; + int top = -m_BrushSize_y / 2; + int bottom = m_BrushSize_y / 2 + 1; + + BOOL doNotSave = FALSE; + int n, m; + int isosize = Map->GetIsoSize(); + + for (m = left;m < right;m++) + { + for (n = top;n < bottom;n++) + { + int pos = x + m + (y + n) * isosize; + + int ground = Map->GetFielddataAt(pos)->wGround; + if (ground == 0xFFFF) ground = 0; + /*int ground1=Map->GetFielddataAt(pos-m)->wGround; + if(ground1==0xFFFF) ground=0; + int ground2=Map->GetFielddataAt(pos-n*isosize)->wGround; + if(ground2==0xFFFF) ground=0;*/ + + + + if (!(*tiledata)[ground].bMorphable) + { + + { + if (n <= 0 /*&& !(*tiledata)[ground1].bMorphable*/) top = n + 1; + if (m <= 0 /*&& !(*tiledata)[ground2].bMorphable*/) left = m + 1; + if (n > 0 /*&& !(*tiledata)[ground1].bMorphable*/) bottom = n; + if (m > 0 /*&& !(*tiledata)[ground2].bMorphable*/) right = m; + } + + } + + if (n < top) + { + m = left; + n = top; + } + if (m < left) + { + n = top; + m = left; + } + } + } + + m_funcRect.left = x; + m_funcRect.top = y; + m_funcRect.bottom = y; + m_funcRect.right = x; + + for (m = left;m < right;m++) + { + for (n = top;n < bottom;n++) + { + int ground = Map->GetFielddataAt(x + m + (y + n) * Map->GetIsoSize())->wGround; + if (ground == 0xFFFF) ground = 0; + + + + if ((*tiledata)[ground].bMorphable) + { + int i; + int max = isosize * isosize; + for (i = 0;i < max;i++) + Map->SetReserved(i, 0); + + + // do not make any slopes yet, we do this once we´re finished with the whole area! + // helps to speed up performance! + ChangeTileHeight(x + m + (y + n) * isosize, m_FlattenHeight, FALSE, FALSE, TRUE); + + + + } + else + { + if (n == 0 && m == 0) + doNotSave = TRUE; + + + } + + } + + } + + /* + Some trick for improving performance is using the m_funcRect parameter to get + the area that any ChangeTileHeight() calls affected. + */ + ASSERT(m_funcRect.left <= m_funcRect.right); + ASSERT(m_funcRect.top <= m_funcRect.bottom); + for (m = m_funcRect.left - 1;m <= m_funcRect.right + 1;m++) + for (n = m_funcRect.top - 1;n <= m_funcRect.bottom + 1;n++) + Map->CreateSlopesAt(m + n * isosize); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + if (!doNotSave) + { + m_FlattenLastX = x; + m_FlattenLastY = y; + } + } + } + else if ((nFlags & MK_LBUTTON) && (nFlags & MK_SHIFT) && AD.mode == ACTIONMODE_HEIGHTENTILE) + { + OnLButtonDown(nFlags, point); + } + else if ((nFlags & MK_LBUTTON) && (nFlags & MK_SHIFT) && AD.mode == ACTIONMODE_LOWERTILE) + { + OnLButtonDown(nFlags, point); + } + else if ((nFlags == MK_LBUTTON) && AD.mode == ACTIONMODE_WAYPOINT) // waypoints + { + if (AD.type == 1) + { + //delete waypoint + int w = Map->GetWaypointAt(x + y * Map->GetIsoSize()); + if (w < 0) + { + isMoving = FALSE; + return; + } + + Map->DeleteWaypoint(w); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.type == 0) + { + int n = Map->GetWaypointAt(x + y * Map->GetIsoSize()); + if (n >= 0) + { + isMoving = FALSE; + return; + } + + Map->AddWaypoint("", x + y * Map->GetIsoSize()); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.type >= 3) + { + int n = Map->GetWaypointAt(x + y * Map->GetIsoSize()); + if (n >= 0) + { + isMoving = FALSE; + return; + } + + char c[50]; + int max = AD.type - 3; + + // MW April 8th: place waypoints before selected one if they are not there! + // makes the user aware that he is doing something he should not do. + // he should not skip starting locations + // this logic is here to make sure there are no random starting points. + // I do not want to change this when saving the map, as triggers may rely on the + // actual starting position! + int i; + int e; + int notfound = -1; + for (e = 0;e < max;e++) + { + BOOL bFound = FALSE; + + for (i = 0;i < Map->GetWaypointCount();i++) + { + CString id; + DWORD pos; + Map->GetWaypointData(i, &id, &pos); + if (atoi(id) == e) bFound = TRUE; + if (bFound) break; + } + if (!bFound) + { + notfound = e; + break; + } + } + + if (notfound >= 0) max = notfound; + + AD.type = 3 + max; + + itoa(max, c, 10); + + if (!Map->IsMultiplayer()) + { + Map->AddWaypoint("99", x + (y + 1) * Map->GetIsoSize()); + Map->AddWaypoint("98", x + (y)*Map->GetIsoSize()); + } + else + { + Map->AddWaypoint(c, x + y * Map->GetIsoSize()); + } + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + + } + else if ((nFlags == MK_LBUTTON) && AD.mode == ACTIONMODE_CELLTAG) // celltags + { + if (AD.type == 1) + { + int n = Map->GetCelltagAt(x + y * Map->GetIsoSize()); + if (n < 0) + { + isMoving = FALSE; + return; + } + Map->DeleteCelltag(n); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.type == 4) + { + Map->AddCelltag(AD.data_s, x + y * Map->GetIsoSize()); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + } + else if ((nFlags == MK_LBUTTON) && AD.mode == ACTIONMODE_NODE) // nodes + { + if (AD.type == 1) // create node, delete building + { + int n = Map->GetStructureAt(x + y * Map->GetIsoSize()); + if (n < 0) + { + isMoving = FALSE; + return; + } + + STDOBJECTDATA sod; + Map->GetStdStructureData(n, &sod); + + CString tmp; + if (Map->GetNodeAt(atoi(sod.x) + atoi(sod.y) * Map->GetIsoSize(), tmp) >= 0) + { + SetError("You cannot place a node on another node"); + { + isMoving = FALSE; + return; + }; + } + + Map->DeleteStructure(n); + + NODE node; + node.x = sod.x; + node.y = sod.y; + node.house = sod.house; + node.type = sod.type; + + Map->AddNode(&node, 0); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + } + else if (AD.type == 0) // create node, don´t delete building + { + int n = Map->GetStructureAt(x + y * Map->GetIsoSize()); + if (n < 0) + { + isMoving = FALSE; + return; + } + + STDOBJECTDATA sod; + Map->GetStdStructureData(n, &sod); + + CString tmp; + if (Map->GetNodeAt(atoi(sod.x) + atoi(sod.y) * Map->GetIsoSize(), tmp) >= 0) + { + SetError("You cannot place a node on another node"); + { + isMoving = FALSE; + return; + }; + } + + NODE node; + node.x = sod.x; + node.y = sod.y; + node.type = sod.type; + node.house = sod.house; + + Map->AddNode(&node, 0); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + } + else if (AD.type == 2) // delete node + { + CString owner; + int n = Map->GetNodeAt(x + y * Map->GetIsoSize(), owner); + if (n < 0) + { + isMoving = FALSE; + return; + } + Map->DeleteNode(owner, n); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + } + } + else if ((nFlags == MK_LBUTTON) && AD.mode == ACTIONMODE_ERASEFIELD) + { + int h; + DWORD dwPos = x + y * Map->GetIsoSize(); + h = Map->GetInfantryAt(dwPos); + if (h > -1) + { + Map->DeleteInfantry(h); + } + + h = Map->GetUnitAt(dwPos); + if (h > -1) + { + Map->DeleteUnit(h); + } + + h = Map->GetStructureAt(dwPos); + if (h > -1) + { + Map->DeleteStructure(h); + } + + h = Map->GetAirAt(dwPos); + if (h > -1) + { + Map->DeleteAircraft(h); + } + + h = Map->GetTerrainAt(dwPos); + if (h > -1) + { + Map->DeleteTerrain(h); + } + +#ifdef SMUDGE_SUPP + const FIELDDATA& fd = *Map->GetFielddataAt(dwPos); + h = fd.smudge; + if (h > -1) + { + Map->DeleteSmudge(h); + } +#endif + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + } + else if (AD.mode == ACTIONMODE_MAPTOOL) + { + if (AD.tool) + AD.tool->onMouseMove(projCoords, mapCoords, MapToolMouseFlagsFromWin32(nFlags)); + } + else if ((nFlags & MK_LBUTTON) == MK_LBUTTON && (AD.mode == ACTIONMODE_PLACE || AD.mode == ACTIONMODE_RANDOMTERRAIN)) + { + // ADD OBJECTS + + if (AD.mode == ACTIONMODE_PLACE && AD.type == 6) Map->TakeSnapshot(); + + if (AD.mode == ACTIONMODE_PLACE && AD.type == 6 && AD.data == 5) // bridges + { + + + // calculate the x and y value... + int x = mapCoords.x; + int y = mapCoords.y; + + if (abs(x - m_mapx) >= abs(y - m_mapy)) + { + // it´s from bottom left to top right + y = m_mapy; + } + else + { + // from bottom right to top left + x = m_mapx; + } + + // draw a line + + int px1, py1, px2, py2; + px1 = m_mapx; + py1 = m_mapy; + px2 = x; + py2 = y; + if (theApp.m_Options.bFlat) + ToPhys(&px1, &py1); + else + ToPhys3d(&px1, &py1); + if (theApp.m_Options.bFlat) + ToPhys(&px2, &py2); + else + ToPhys3d(&px2, &py2); + px1 += f_x / 2 - m_viewOffset.x - r.left; + py1 += f_y / 2 - m_viewOffset.y - r.top; + px2 += f_x / 2 - m_viewOffset.x - r.left; + py2 += f_y / 2 - m_viewOffset.y - r.top; + + CRect r; + GetWindowRect(r); + px1 += r.left; + px2 += r.left; + py1 += r.top; + py2 += r.top; + + + HDC dc; + lpdsBack->GetDC(&dc); + + POINT p; + MoveToEx(dc, px1, py1, &p); + LineTo(dc, px2, py2); + + lpdsBack->ReleaseDC(dc); + + BlitBackbufferToHighRes(); + RenderUIOverlay(); + FlipHighResBuffer(); + //lpds->Blt(NULL, lpdsBack, NULL, 0, 0); + + } + else + { + PlaceCurrentObjectAt(x, y); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + + + if (AD.mode == ACTIONMODE_PLACE && AD.type == 6) + { + Map->TakeSnapshot(); + Map->Undo(); + } + + + } + + UpdateStatusBar(x, y); + + + isMoving = FALSE; + + + + CView::OnMouseMove(nFlags, point); +} + + + +void CIsoView::DrawCellCursor(const MapCoords& mapCoords, const DDSURFACEDESC2& desc) +{ + ProjectedVec drawOffset(0*4, 0*3); + ProjectedCoords drawCoords2d = GetRenderTargetCoordinates(mapCoords, 0) + drawOffset; + ProjectedCoords drawCoords = GetRenderTargetCoordinates(mapCoords) + drawOffset; + + static const COLORREF _cell_hilight_colors[16] = { + RGB(255, 255, 255), // level 0 + RGB( 170, 0, 170), // level 1 + RGB(0, 170, 170), // level 2 + RGB(0, 170, 0), // level 3 + RGB(90, 255, 90), // level 4 + RGB(255, 255, 90), // level 5 + RGB(255, 50, 50), // level 6 + RGB(170, 85, 0), // level 7 + RGB(170, 0, 0), // level 8 + RGB(85, 255, 255), // level 9 + RGB(80, 80, 255), // level 10 + RGB(0, 0, 170), // level 11 + RGB(0, 0, 0), // level 12 + RGB(85,85 ,85), // level 13 + RGB(170, 170, 170), // level 14 + RGB(255, 255, 255) // level 15 + }; + + const FIELDDATA& m = *Map->GetFielddataAt(mapCoords.x + mapCoords.y * Map->GetIsoSize()); + int tileheight = m.bHeight; + int new_tileheight = std::clamp(tileheight, 0, 16); + + DrawCell(desc.lpSurface, desc.dwWidth, desc.dwHeight, desc.lPitch, drawCoords.x, drawCoords.y, 1, 1, m_color_converter->GetColor(_cell_hilight_colors[new_tileheight]), false, true, m_color_converter->GetColor(60, 60, 255)); + + LineDrawer l(desc.lpSurface, bpp, desc.dwWidth, desc.dwHeight, desc.lPitch); + + POINT p1, p2, p3, p4; + p2.x = drawCoords2d.x + 1 * f_x / 2 + f_x / 2; + p2.y = drawCoords2d.y + 1 * f_y / 2; + p3.x = drawCoords2d.x + 1 * f_x / 2 - 1 * f_x / 2 + f_x / 2 - 1; + p3.y = drawCoords2d.y + 1 * f_y / 2 + 1 * f_y / 2 - 1; + p4.x = drawCoords2d.x - 1 * f_x / 2 + f_x / 2 - 1; + p4.y = drawCoords2d.y + 1 * f_y / 2 - 1; + + POINT p5, p6, p7, p8; + p6.x = drawCoords.x + 1 * f_x / 2 + f_x / 2; + p6.y = drawCoords.y + 1 * f_y / 2; + p7.x = drawCoords.x + 1 * f_x / 2 - 1 * f_x / 2 + f_x / 2 - 1; + p7.y = drawCoords.y + 1 * f_y / 2 + 1 * f_y / 2 - 1; + p8.x = drawCoords.x - 1 * f_x / 2 + f_x / 2 - 1; + p8.y = drawCoords.y + 1 * f_y / 2 - 1; + + auto col = m_color_converter->GetColor(60, 60, 60); + if (drawCoords2d != drawCoords) + { + for (int y = 0; y < 2; ++y) + { + l.MoveTo(p2.x + 1, p2.y + y); + l.LineTo(p6.x + 1, p6.y + y, col, LineStyle::Dotted_4); + l.MoveTo(p3.x, p3.y + 1 + y); + l.LineTo(p7.x, p7.y + 1 + y, col, LineStyle::Dotted_4); + l.MoveTo(p4.x - 1, p4.y + y); + l.LineTo(p8.x - 1, p8.y + y, col, LineStyle::Dotted_4); + + l.MoveTo(p2.x, p2.y + y); + l.LineTo(p6.x, p6.y + y, col, LineStyle::Dotted_4); + l.MoveTo(p3.x + 1, p3.y + 1 + y); + l.LineTo(p7.x + 1, p7.y + 1 + y, col, LineStyle::Dotted_4); + l.MoveTo(p4.x, p4.y + y); + l.LineTo(p8.x, p8.y + y, col, LineStyle::Dotted_4); + } + } +} + +const int valadded = 10000; + + +void CIsoView::OnRButtonUp(UINT nFlags, CPoint point) +{ + if (rscroll) + { + if (b_IsLoading) return; + + ReleaseCapture(); + KillTimer(11); + ShowCursor(TRUE); + CMyViewFrame& dlg = *(CMyViewFrame*)owner; + dlg.m_minimap.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + } + + + if (nFlags == 0 && point.x == 0 && point.y == 0) + { + m_drag = FALSE; return; + } + + CIniFile& ini = Map->GetIniFile(); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + if (!rscroll) m_drag = FALSE; + + const auto projCoords = GetProjectedCoordinatesFromClientCoordinates(point); + const MapCoords mapCoords = GetMapCoordinatesFromClientCoordinates(point, (nFlags & MK_CONTROL) == MK_CONTROL); + + const int x = mapCoords.x; // compat + const int y = mapCoords.y; + + // context menu + if (AD.mode != 0 && !rscroll) + { + bool ignoreClick = false; + if (AD.mode == ACTIONMODE_MAPTOOL) + { + if (AD.tool) + ignoreClick = AD.tool->onRButtonUp(projCoords, mapCoords, MapToolMouseFlagsFromWin32(nFlags)); + } + + if (!ignoreClick) + { + AD.reset(); + + CMyViewFrame& frame = *((CMyViewFrame*)owner); + frame.m_objectview->GetTreeCtrl().Select(frame.m_objectview->GetTreeCtrl().GetRootItem(), TVGN_CARET); + } + return; + } + + rscroll = FALSE; + + return; + + + + + CView::OnRButtonUp(nFlags, point); +} + +// from old (popup menu) interface, taken over and used by OnLButtonDblClick +BOOL CIsoView::OnCommand(WPARAM wParam, LPARAM lParam) +{ + int wNotifyCode = HIWORD(wParam); // notification code + int wID = LOWORD(wParam); // item, control, or accelerator identifier + HWND hwndCtl = (HWND)lParam; // handle of control + + CIniFile& ini = Map->GetIniFile(); + + + if (wID < valadded) + { + // a standard menu, no popup! + + switch (wID) + { + case 4: + { + last_succeeded_operation = 54310; + //get the number + if (Map->GetAirAt(m_mapx + m_mapy * Map->GetIsoSize()) != -1) + { + HandleProperties(Map->GetAirAt(m_mapx + m_mapy * Map->GetIsoSize()), 2); + } + else if (Map->GetInfantryAt(m_mapx + m_mapy * Map->GetIsoSize()) != -1) + { + last_succeeded_operation = 54311; + int z; + for (z = 0;z < SUBPOS_COUNT;z++) + if (Map->GetInfantryAt(m_mapx + m_mapy * Map->GetIsoSize(), z) != -1) HandleProperties(Map->GetInfantryAt(m_mapx + m_mapy * Map->GetIsoSize(), z), 0); + } + else if (Map->GetUnitAt(m_mapx + m_mapy * Map->GetIsoSize()) != -1) + { + HandleProperties(Map->GetUnitAt(m_mapx + m_mapy * Map->GetIsoSize()), 3); + } + else if (Map->GetStructureAt(m_mapx + m_mapy * Map->GetIsoSize()) != -1) + { + HandleProperties(Map->GetStructureAt(m_mapx + m_mapy * Map->GetIsoSize()), 1); + } + + + break; + } + + } + + return 0; + } + + + + + + return CView::OnCommand(wParam, lParam); +} + +void CIsoView::HandleProperties(int n, int type) +{ + CIniFile& ini = Map->GetIniFile(); + + if (n < 0) return; + switch (type) + { + case 0: + { + last_succeeded_operation = 54312; + + // infantry + + INFANTRY data; + + Map->GetInfantryData(n, &data); + + last_succeeded_operation = 54313; + + + CInfantrie dlg(this); + char tmp[255]; + dlg.Init((LPCTSTR)data.house, (LPCTSTR)data.strength, (LPCTSTR)data.action, + (LPCTSTR)data.direction, (LPCTSTR)data.tag, (LPCTSTR)data.flag1, + (LPCTSTR)data.flag2, (LPCTSTR)data.flag3, (LPCTSTR)data.flag4, (LPCTSTR)data.flag5); + + int res = dlg.DoModal(); + if (res == IDCANCEL) return; + + data.action = dlg.m_action; + data.strength = dlg.m_strength; + data.tag = dlg.m_tag; + data.direction = dlg.m_direction; + data.house = dlg.m_house; + data.flag1 = dlg.m_flag1; + data.flag2 = dlg.m_flag2; + data.flag3 = dlg.m_flag3; + data.flag4 = dlg.m_flag4; + data.flag5 = dlg.m_flag5; + + + Map->DeleteInfantry(n); + Map->AddInfantry(&data); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + break; + } + case 1: + { + // building + + STRUCTURE data; + Map->GetStructureData(n, &data); + + + CBuilding dlg(this); + char tmp[255]; + dlg.Init((LPCTSTR)data.house, (LPCTSTR)data.strength, (LPCTSTR)data.direction, (LPCTSTR)data.tag, + (LPCTSTR)data.flag1, (LPCTSTR)data.flag2, (LPCTSTR)data.energy, + (LPCTSTR)data.upgradecount, (LPCTSTR)data.spotlight, (LPCTSTR)data.upgrade1, (LPCTSTR)data.upgrade2, + (LPCTSTR)data.upgrade3, (LPCTSTR)data.flag3, (LPCTSTR)data.flag4); + dlg.m_type = data.type; + + int res = dlg.DoModal(); + if (res == IDCANCEL) return; + + data.strength = dlg.m_strength; + data.tag = dlg.m_tag; + data.direction = dlg.m_direction; + data.house = dlg.m_house; + data.spotlight = dlg.m_spotlight; + data.flag1 = dlg.m_flag1; + data.flag2 = dlg.m_flag2; + data.flag3 = dlg.m_flag3; + data.flag4 = dlg.m_flag4; + data.energy = dlg.m_energy; + data.upgradecount = dlg.m_upgradecount; + data.upgrade1 = dlg.m_upgrade1; + data.upgrade2 = dlg.m_upgrade2; + data.upgrade3 = dlg.m_upgrade3; + + + + Map->DeleteStructure(n); + Map->AddStructure(&data); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + break; + + } + case 2: + { + // aircraft + + AIRCRAFT data; + Map->GetAircraftData(n, &data); + + + CAircraft dlg(this); + char tmp[255]; + dlg.Init(data.house, data.strength, data.direction, data.action, + data.tag, data.flag1, data.flag2, data.flag3, data.flag4); + + int res = dlg.DoModal(); + if (res == IDCANCEL) return; + + data.action = dlg.m_action; + data.strength = dlg.m_strength; + data.tag = dlg.m_tag; + data.direction = dlg.m_direction; + data.house = dlg.m_house; + data.flag1 = dlg.m_flag1; + data.flag2 = dlg.m_flag2; + data.flag3 = dlg.m_flag3; + data.flag4 = dlg.m_flag4; + + + Map->DeleteAircraft(n); + Map->AddAircraft(&data); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + break; + } + case 3: + { + // vehicle + + UNIT data; + Map->GetUnitData(n, &data); + + + CUnit dlg(this); + char tmp[255]; + dlg.Init(data.house, data.strength, data.direction, data.action, + data.tag, data.flag1, data.flag2, data.flag3, data.flag4, data.flag5, data.flag6); + + int res = dlg.DoModal(); + if (res == IDCANCEL) return; + + data.action = dlg.m_action; + data.strength = dlg.m_strength; + data.tag = dlg.m_tag; + data.direction = dlg.m_direction; + data.house = dlg.m_house; + data.flag1 = dlg.m_flag1; + data.flag2 = dlg.m_flag2; + data.flag3 = dlg.m_flag3; + data.flag4 = dlg.m_flag4; + data.flag5 = dlg.m_flag5; + data.flag6 = dlg.m_flag6; + + Map->DeleteUnit(n); + Map->AddUnit(&data); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + break; + + + } + } +} + +void CIsoView::OnLButtonDblClk(UINT nFlags, CPoint point) +{ + + + if (b_IsLoading == TRUE) return; + + m_NoMove = TRUE; + m_drag = FALSE; + + const auto projCoords = GetProjectedCoordinatesFromClientCoordinates(point); + const MapCoords mapCoords = GetMapCoordinatesFromClientCoordinates(point, (nFlags & MK_CONTROL) == MK_CONTROL); + + if (AD.mode == ACTIONMODE_MAPTOOL) + { + if (AD.tool) + AD.tool->onLButtonDblClick(projCoords, mapCoords, MapToolMouseFlagsFromWin32(nFlags)); + } + else + { + if (!Map->isInside(mapCoords)) + return; + + m_mapx = mapCoords.x; + m_mapy = mapCoords.y; + + int pos = m_mapx + m_mapy * Map->GetIsoSize(); + if (Map->GetCelltagAt(pos) < 0) + { + OnCommand(4, 0); + } + else + OnCommand(9, 0); + } + + m_NoMove = FALSE; + + CView::OnLButtonDblClk(nFlags, point); +} + +void CIsoView::OnLButtonDown(UINT nFlags, CPoint point) +{ + if (Map->GetIsoSize() == 0) return; + if (b_IsLoading == TRUE) return; + + + CIniFile& ini = Map->GetIniFile(); + + const auto projCoords = GetProjectedCoordinatesFromClientCoordinates(point); + const MapCoords mapCoords = GetMapCoordinatesFromClientCoordinates(point, (nFlags & MK_CONTROL) == MK_CONTROL); + + + + const int x = mapCoords.x; // compat + const int y = mapCoords.y; + + + int mapwidth = Map->GetWidth(); + int mapheight = Map->GetHeight(); + //if(x>=Map->GetIsoSize() || y>=Map->GetIsoSize() || x<0 || y<0) return; + if (AD.mode != ACTIONMODE_COPY && AD.mode != ACTIONMODE_PASTE && AD.mode != ACTIONMODE_MAPTOOL) + { + if (!Map->isInside(mapCoords)) + return; + if (x < 1 || y < 1 || x + y<mapwidth + 1 || x + y>mapwidth + mapheight * 2 || (y + 1 > mapwidth && x - 1 < y - mapwidth) || (x + 1 > mapwidth && y + mapwidth - 1 < x)) + return; + } + + int px = m_mapx; + int py = m_mapy; + + m_mapx = x; + m_mapy = y; + + CStatusBarCtrl& stat = ((CMyViewFrame*)owner)->m_statbar.GetStatusBarCtrl(); + + if (AD.mode == ACTIONMODE_CLIFFFRONT || AD.mode == ACTIONMODE_CLIFFBACK) + { + m_drag = TRUE; + } + else if (AD.mode == ACTIONMODE_PASTE) + { + Map->TakeSnapshot(); + Map->Paste(m_mapx, m_mapy, AD.z_data); + Map->TakeSnapshot(); + Map->Undo(); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.mode == ACTIONMODE_COPY) + { + if (!m_drag) + { + m_drag = TRUE; + } + else // 2nd click + { + int x1, x2, y1, y2; + if (px < x) + { + x1 = px; + x2 = x; + } + else + { + x1 = x; + x2 = px; + } + if (py < y) + { + y1 = py; + y2 = y; + } + else + { + y1 = y; + y2 = py; + } + + + Map->Copy(x1, y1, x2 + 1, y2 + 1); + + m_drag = FALSE; + } + } + else if (Map->IsGroundObjectAt(m_mapx + m_mapy * Map->GetIsoSize()) && AD.mode == 0 && m_NoMove == FALSE) + { + m_drag = TRUE; + m_moved = FALSE; + m_id = Map->GetInfantryAt(m_mapx + m_mapy * Map->GetIsoSize()); + m_type = 0; + if (m_id < 0) + { + m_id = Map->GetUnitAt(m_mapx + m_mapy * Map->GetIsoSize()); + m_type = 3; + } + if (m_id < 0) + { + m_id = Map->GetAirAt(m_mapx + m_mapy * Map->GetIsoSize()); + m_type = 2; + } + if (m_id < 0) + { + m_id = Map->GetTerrainAt(m_mapx + m_mapy * Map->GetIsoSize()); + m_type = 4; + } + if (m_id < 0) + { + m_id = Map->GetStructureAt(m_mapx + m_mapy * Map->GetIsoSize()); + + STDOBJECTDATA sod; + Map->GetStdStructureData(m_id, &sod); + m_mapx = atoi(sod.x); + m_mapy = atoi(sod.y); + + m_type = 1; + } + + } + else if (AD.mode == ACTIONMODE_SETTILE) + { + + + if ((nFlags & MK_CONTROL) && !(nFlags & MK_SHIFT)) + { + // Fill the whole area + Sound(SOUND_LAYDOWNTILE); + + Map->TakeSnapshot(); + int i; + for (i = 0;i < Map->GetIsoSize() * Map->GetIsoSize();i++) + Map->SetReserved(i, 0); + + FillArea(x, y, AD.type, 0); + Map->TakeSnapshot(); + Map->Undo(); + } + else + { + // just place a single tile + + if (!(nFlags & MK_SHIFT)) + { + Sound(SOUND_LAYDOWNTILE); + } + + PlaceTile(x, y, nFlags); + } + + + + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.mode == ACTIONMODE_HIDETILESET) + { + int ground = Map->GetFielddataAt(x + (y)*Map->GetIsoSize())->wGround; + if (ground == 0xFFFF) ground = 0; + + //if(ground!=0) + HideTileSet((*tiledata)[ground].wTileSet); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.mode == ACTIONMODE_HIDEFIELD) + { + Map->HideField(x + y * Map->GetIsoSize(), TRUE); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.mode == ACTIONMODE_HEIGHTEN) + { + Map->TakeSnapshot(); + + m_TileChangeCount = 0; + //if(x==m_mapx && y==m_mapy) + //try + { + int ground = Map->GetFielddataAt(x + (y)*Map->GetIsoSize())->wGround; + if (ground == 0xFFFF) ground = 0; + + if ((nFlags & MK_CONTROL) && !(*tiledata)[ground].bMorphable) + { + SetError("Applying non-morphable terrain height change, please wait..."); + stat.RedrawWindow(); + stat.UpdateWindow(); + } + + m_funcRect.left = x; + m_funcRect.top = y; + m_funcRect.bottom = y; + m_funcRect.right = x; + + if ((*tiledata)[ground].bMorphable) + { + int f, n; + int oheight = Map->GetHeightAt(x + y * Map->GetIsoSize()); + for (f = -m_BrushSize_x / 2;f < m_BrushSize_x / 2 + 1;f++) + { + for (n = -m_BrushSize_y / 2;n < m_BrushSize_y / 2 + 1;n++) + { + int pos = x + f + (y + n) * Map->GetIsoSize(); + int ground = Map->GetFielddataAt(pos)->wGround; + if (ground == 0xFFFF) ground = 0; + + if ((*tiledata)[ground].bMorphable && Map->GetHeightAt(pos) == oheight) + { + Map->SetHeightAt(pos, oheight + 1); + } + } + } + for (f = -m_BrushSize_x / 2;f < m_BrushSize_x / 2 + 1;f++) + { + for (n = -m_BrushSize_y / 2;n < m_BrushSize_y / 2 + 1;n++) + { + int pos = x + f + (y + n) * Map->GetIsoSize(); + int ground = Map->GetFielddataAt(pos)->wGround; + if (ground == 0xFFFF) ground = 0; + + if ((*tiledata)[ground].bMorphable && Map->GetHeightAt(x + f + (y + n) * Map->GetIsoSize()) == oheight + 1) + { + int i; + for (i = 0;i < Map->GetIsoSize() * Map->GetIsoSize();i++) + Map->SetReserved(i, 0); + + ChangeTileHeight(x + f + (y + n) * Map->GetIsoSize(), oheight + 1, FALSE, (nFlags & MK_CONTROL), TRUE); + } + } + } + } + else + { + int i; + for (i = 0;i < Map->GetIsoSize() * Map->GetIsoSize();i++) + Map->SetReserved(i, 0); + + // TODO: replace recursion, otherwise be aware of stack issues! + try + { + ChangeTileHeight(x + (y)*Map->GetIsoSize(), Map->GetHeightAt(x + y * Map->GetIsoSize()) + 1, FALSE, !(nFlags & MK_CONTROL)); + } + catch (...) + { + MessageBox("Stack is too small to complete operation!", "Error"); + } + } + + int f, n; + for (f = m_funcRect.left - 1;f <= m_funcRect.right + 1;f++) + { + for (n = m_funcRect.top - 1;n <= m_funcRect.bottom + 1;n++) + { + int pos = f + (n)*Map->GetIsoSize(); + Map->CreateSlopesAt(pos); + } + } + + + /*CHANGEHEIGHTDATA d; + d.pos=x+y*Map->GetIsoSize(); + d.bNonMorpheable=FALSE; + d.toHeight=Map->GetHeightAt(x+y*Map->GetIsoSize())+1; + DWORD id; + HANDLE hThread=CreateThread(NULL, 4000000, ChangeHeightThread, &d, NULL, &id); + SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); + WaitForSingleObjectEx(hThread, INFINITE, FALSE);*/ + + + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + Map->TakeSnapshot(); + Map->Undo(); + } + //catch(...) + { + // MessageBox("Error occured","Error"); + } + } + else if (AD.mode == ACTIONMODE_LOWER) + { + Map->TakeSnapshot(); + + m_TileChangeCount = 0; + //if(x==m_mapx && y==m_mapy) + //try + { + int ground = Map->GetFielddataAt(x + (y)*Map->GetIsoSize())->wGround; + if (ground == 0xFFFF) ground = 0; + + if ((nFlags & MK_CONTROL) && !(*tiledata)[ground].bMorphable) + { + SetError("Applying non-morphable terrain height change, please wait..."); + stat.RedrawWindow(); + stat.UpdateWindow(); + } + + int i; + + m_funcRect.left = x; + m_funcRect.top = y; + m_funcRect.bottom = y; + m_funcRect.right = x; + + if ((*tiledata)[ground].bMorphable) + { + int f, n; + int oheight = Map->GetHeightAt(x + y * Map->GetIsoSize()); + for (f = -m_BrushSize_x / 2;f < m_BrushSize_x / 2 + 1;f++) + { + for (n = -m_BrushSize_y / 2;n < m_BrushSize_y / 2 + 1;n++) + { + int pos = x + f + (y + n) * Map->GetIsoSize(); + int ground = Map->GetFielddataAt(pos)->wGround; + if (ground == 0xFFFF) ground = 0; + + if ((*tiledata)[ground].bMorphable && Map->GetHeightAt(pos) == oheight) + { + Map->SetHeightAt(pos, oheight - 1); + } + } + } + for (f = -m_BrushSize_x / 2;f < m_BrushSize_x / 2 + 1;f++) + { + for (n = -m_BrushSize_y / 2;n < m_BrushSize_y / 2 + 1;n++) + { + int pos = x + f + (y + n) * Map->GetIsoSize(); + int ground = Map->GetFielddataAt(pos)->wGround; + if (ground == 0xFFFF) ground = 0; + + if ((*tiledata)[ground].bMorphable && Map->GetHeightAt(x + f + (y + n) * Map->GetIsoSize()) == oheight - 1) + { + for (i = 0;i < Map->GetIsoSize() * Map->GetIsoSize();i++) + Map->SetReserved(i, 0); + + ChangeTileHeight(x + f + (y + n) * Map->GetIsoSize(), oheight - 1, FALSE, (nFlags & MK_CONTROL), TRUE); + } + } + } + } + else + { + for (i = 0;i < Map->GetIsoSize() * Map->GetIsoSize();i++) + Map->SetReserved(i, 0); + + try + { + ChangeTileHeight(x + (y)*Map->GetIsoSize(), Map->GetHeightAt(x + y * Map->GetIsoSize()) - 1, FALSE, !(nFlags & MK_CONTROL)); + } + catch (...) + { + MessageBox("Stack is too small to complete operation!", "Error"); + } + } + + int f, n; + for (f = m_funcRect.left - 1;f <= m_funcRect.right + 1;f++) + { + for (n = m_funcRect.top - 1;n <= m_funcRect.bottom + 1;n++) + { + int pos = f + (n)*Map->GetIsoSize(); + Map->CreateSlopesAt(pos); + } + } + + /*CHANGEHEIGHTDATA d; + d.pos=x+y*Map->GetIsoSize(); + d.bNonMorpheable=FALSE; + d.toHeight=Map->GetHeightAt(x+y*Map->GetIsoSize())-1; + DWORD id; + HANDLE hThread=CreateThread(NULL, 4000000, ChangeHeightThread, &d, NULL, &id); + SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); + WaitForSingleObjectEx(hThread, INFINITE, FALSE);*/ + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + //catch(...) + { + // MessageBox("Error occured","Error"); + } + + Map->TakeSnapshot(); + Map->Undo(); + } + else if (AD.mode == ACTIONMODE_HEIGHTENTILE) + { + Map->TakeSnapshot(); + + int n, m; + for (m = -m_BrushSize_x / 2;m < m_BrushSize_x / 2 + 1;m++) + { + for (n = -m_BrushSize_y / 2;n < m_BrushSize_y / 2 + 1;n++) + { + Map->SetHeightAt(x + m + (y + n) * Map->GetIsoSize(), Map->GetHeightAt(x + m + (y + n) * Map->GetIsoSize()) + 1); + } + } + + if (nFlags & MK_CONTROL) + for (m = -m_BrushSize_x / 2 - 1;m < m_BrushSize_x / 2 + 2;m++) + { + for (n = -m_BrushSize_y / 2 - 1;n < m_BrushSize_y / 2 + 2;n++) + { + Map->CreateSlopesAt(x + m + (y + n) * Map->GetIsoSize()); + } + } + + Map->TakeSnapshot(); + Map->Undo(); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.mode == ACTIONMODE_LOWERTILE) + { + Map->TakeSnapshot(); + + int n, m; + for (m = -m_BrushSize_x / 2;m < m_BrushSize_x / 2 + 1;m++) + { + for (n = -m_BrushSize_y / 2;n < m_BrushSize_y / 2 + 1;n++) + { + Map->SetHeightAt(x + m + (y + n) * Map->GetIsoSize(), Map->GetHeightAt(x + m + (y + n) * Map->GetIsoSize()) - 1); + } + } + + if (nFlags & MK_CONTROL) + for (m = -m_BrushSize_x / 2 - 1;m < m_BrushSize_x / 2 + 2;m++) + { + for (n = -m_BrushSize_y / 2 - 1;n < m_BrushSize_y / 2 + 2;n++) + { + Map->CreateSlopesAt(x + m + (y + n) * Map->GetIsoSize()); + } + } + + Map->TakeSnapshot(); + Map->Undo(); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.mode == ACTIONMODE_FLATTENGROUND) + { + Map->TakeSnapshot(); + + m_FlattenHeight = Map->GetHeightAt(x + y * Map->GetIsoSize()); + m_FlattenLastX = x; + m_FlattenLastY = y; + + Map->TakeSnapshot(); + Map->Undo(); + } + else if (Map->GetWaypointAt(m_mapx + m_mapy * Map->GetIsoSize()) >= 0 && AD.mode == 0) + { + m_drag = TRUE; + m_id = Map->GetWaypointAt(m_mapx + m_mapy * Map->GetIsoSize()); + m_type = 6; + } + else if (Map->GetCelltagAt(m_mapx + m_mapy * Map->GetIsoSize()) >= 0 && AD.mode == 0) + { + m_drag = TRUE; + m_id = Map->GetCelltagAt(m_mapx + m_mapy * Map->GetIsoSize()); + m_type = 5; + } + else if ((AD.mode < 3 || AD.mode>4) || (AD.mode == 3 && AD.type == 0) || (AD.mode >= 3 && AD.mode <= 4 && AD.type == 1)) + { + OnMouseMove(nFlags, point); + } + else if (AD.mode == 3) + { + if (AD.type == 2) + { + // create waypoint + CWaypointID w(this); + if (w.DoModal() != IDCANCEL) + { + int n = w.m_value; + + char id[50]; + itoa(n, id, 10); + Map->AddWaypoint(id, x + y * Map->GetIsoSize()); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + } + if (AD.type >= 3) OnMouseMove(nFlags, point); + + } + + else if (AD.mode == 4) + { + if (AD.type == 0) + { + // create celltag + CCellTag w(this); + if (w.DoModal() != IDCANCEL) + { + Map->AddCelltag(w.m_tag, x + y * Map->GetIsoSize()); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + } + if (AD.type == 2) + { + // change celltag properties + int n = Map->GetCelltagAt(x + y * Map->GetIsoSize()); + if (n < 0) return; + + DWORD dwPos; + CString tag; + + Map->GetCelltagData(n, &tag, &dwPos); + + + + CCellTag dlg(this); + + dlg.m_tag = tag; + dlg.m_tag += " ("; + dlg.m_tag += GetParam(Map->GetIniFile().sections["Tags"].values[(LPCTSTR)tag], 1); + dlg.m_tag += ")"; + + if (dlg.DoModal() == IDCANCEL) return; + + Map->DeleteCelltag(n); + + Map->AddCelltag(dlg.m_tag, dwPos); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + + } + + + + CView::OnLButtonDown(nFlags, point); +} + +void CIsoView::PlaceTile(const int x, const int y, const UINT nMouseFlags) +{ + Map->TakeSnapshot(TRUE, x - 6, y - 6, x + (*tiledata)[AD.type].cx * m_BrushSize_x + 7, y + (*tiledata)[AD.type].cy * m_BrushSize_y + 7); + int i, e, f, n; + int p = 0; + int width = (*tiledata)[AD.type].cx; + int height = (*tiledata)[AD.type].cy; + int pos = x - width + 1 + (y - height + 1) * Map->GetIsoSize(); + int startheight = Map->GetHeightAt(x + y * Map->GetIsoSize()) + AD.z_data; + int ground = Map->GetFielddataAt(x + y * Map->GetIsoSize())->wGround; + if (ground == 0xFFFF) ground = 0; + startheight -= (*tiledata)[ground].tiles[Map->GetFielddataAt(x + y * Map->GetIsoSize())->bSubTile].bZHeight; + for (f = 0;f < m_BrushSize_x;f++) + { + for (n = 0;n < m_BrushSize_y;n++) + { + int tile = AD.type; + if (AD.data == 1) + { + int n = rand() * 5 / RAND_MAX; + tile += n; + + } + p = 0; + for (i = 0;i < (*tiledata)[AD.type].cx;i++) + { + for (e = 0;e < (*tiledata)[AD.type].cy;e++) + { + + if (x - width + 1 + f * width + i >= Map->GetIsoSize() || + y - height + 1 + n * height + e >= Map->GetIsoSize()) + { + + } + else + if ((*tiledata)[AD.type].tiles[p].pic != NULL) + { + Map->SetHeightAt(pos + i + f * width + (e + n * height) * Map->GetIsoSize(), startheight + (*tiledata)[AD.type].tiles[p].bZHeight); + Map->SetTileAt(pos + i + f * width + (e + n * height) * Map->GetIsoSize(), tile, p); + + } + p++; + } + } + + } + } + + if (!((nMouseFlags & MK_CONTROL) && (nMouseFlags & MK_SHIFT))) + { + if (!theApp.m_Options.bDisableAutoShore) Map->CreateShore(x - 5, y - 5, x + (*tiledata)[AD.type].cx * m_BrushSize_x + 5, y + (*tiledata)[AD.type].cy * m_BrushSize_y + 5, FALSE); + //Map->CreateShore(0,0,Map->GetIsoSize(), Map->GetIsoSize()); + + for (f = 0;f < m_BrushSize_x;f++) + { + for (n = 0;n < m_BrushSize_y;n++) + { + p = 0; + for (i = -1;i < (*tiledata)[AD.type].cx + 1;i++) + { + for (e = -1;e < (*tiledata)[AD.type].cy + 1;e++) + { + + Map->SmoothAllAt(pos + i + f * width + (e + n * height) * Map->GetIsoSize()); + + p++; + } + } + + } + } + } + + // now make current tiles available for redo + Map->TakeSnapshot(TRUE, x - 6, y - 6, x + (*tiledata)[AD.type].cx * m_BrushSize_x + 6, y + (*tiledata)[AD.type].cy * m_BrushSize_y + 6); + Map->Undo(); +} + + + + + +void CIsoView::OnLButtonUp(UINT nFlags, CPoint point) +{ + if (b_IsLoading == TRUE) return; + + CIniFile& ini = Map->GetIniFile(); + + const auto projCoords = GetProjectedCoordinatesFromClientCoordinates(point); + const MapCoords mapCoords = GetMapCoordinatesFromClientCoordinates(point, (nFlags & MK_CONTROL) == MK_CONTROL); + + const int dx = mapCoords.x; // compat + const int dy = mapCoords.y; + + + //if(dx>=Map->GetIsoSize() || dy>=Map->GetIsoSize() || dx<0 || dy<0) return; + int mapwidth = Map->GetWidth(); + int mapheight = Map->GetHeight(); + if (AD.mode != ACTIONMODE_COPY && AD.mode != ACTIONMODE_PASTE && AD.mode != ACTIONMODE_MAPTOOL) + { + if (!Map->isInside(mapCoords)) + return; + if (dx < 1 || dy < 1 || dx + dy<mapwidth + 1 || dx + dy>mapwidth + mapheight * 2 || (dy + 1 > mapwidth && dx - 1 < dy - mapwidth) || (dx + 1 > mapwidth && dy + mapwidth - 1 < dx)) + return; + } + + + char fx[50], fy[50]; + itoa(dx, fx, 10); + itoa(dy, fy, 10); + + int x, y; + x = dx; + y = dy; + + // check if user did select something else than 0 in object browser + if (AD.mode != 0 && AD.mode != ACTIONMODE_COPY) + { + if (m_moved) + m_drag = FALSE; + m_moved = FALSE; + } + + if (AD.mode == ACTIONMODE_FLATTENGROUND) + { + Map->TakeSnapshot(); + Map->Undo(); + } + if (AD.mode == ACTIONMODE_CLIFFFRONT || AD.mode == ACTIONMODE_CLIFFBACK) + { + m_drag = FALSE; + Map->Redo(); + /*Map->TakeSnapshot(); + + if(AD.mode==ACTIONMODE_CLIFFFRONT) + { + CFrontCliffModifier f; + f.PlaceCliff(m_mapx, m_mapy, x, y); + } + else if(AD.mode==ACTIONMODE_CLIFFBACK) + { + CBackCliffModifier f; + f.PlaceCliff(m_mapx, m_mapy, x, y); + }*/ + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + + if (AD.mode == ACTIONMODE_COPY && m_drag) + { + /*m_drag=FALSE; + + int x1, x2, y1, y2; + if(m_mapx<x) { x1=m_mapx; x2=x; } else { x1=x; x2=m_mapx; } + if(m_mapy<y) { y1=m_mapy; y2=y; } else { y1=y; y2=m_mapy; } + + + Map->Copy(x1, y1, x2+1, y2+1);*/ + m_moved = FALSE; + } + + if (m_drag && m_moved) + { + m_moved = FALSE; + + // ok, drag the object at m_mapx/m_mapy to x/y + int x = dx, y = dy; + char strX[15], strY[15]; + itoa(x, strX, 10); + itoa(y, strY, 10); + switch (m_type) + { + case 0: // drag infantry + { + INFANTRY infantry; + Map->GetInfantryData(m_id, &infantry); + infantry.x = strX; + infantry.y = strY; + infantry.pos = "-1"; + + if ((nFlags != MK_SHIFT)) + { + Map->DeleteInfantry(m_id); + } + + Map->AddInfantry(&infantry); + + break; + } + case 1: // drag structure + { + STRUCTURE structure; + Map->GetStructureData(m_id, &structure); + structure.x = strX; + structure.y = strY; + + if ((nFlags != MK_SHIFT)) + { + Map->DeleteStructure(m_id); + } + + Map->AddStructure(&structure); + + break; + } + case 2: // drag aircraft + { + AIRCRAFT aircraft; + Map->GetAircraftData(m_id, &aircraft); + aircraft.x = strX; + aircraft.y = strY; + + + if ((nFlags != MK_SHIFT)) + { + Map->DeleteAircraft(m_id); + } + + Map->AddAircraft(&aircraft); + + break; + } + case 3: // drag vehicles + { + UNIT unit; + Map->GetUnitData(m_id, &unit); + unit.x = strX; + unit.y = strY; + + if (!(nFlags == MK_SHIFT)) + { + Map->DeleteUnit(m_id); + } + + Map->AddUnit(&unit); + + break; + } + case 4: // drag terrain + { + CString type; + + Map->GetTerrainData(m_id, &type); + + if ((nFlags != MK_SHIFT)) + { + Map->DeleteTerrain(m_id); + } + + Map->AddTerrain(type, x + y * Map->GetIsoSize()); + break; + } + + case 5: // drag celltag + { + CString tag; + DWORD dwPos; + Map->GetCelltagData(m_id, &tag, &dwPos); + + if ((nFlags != MK_SHIFT)) + { + Map->DeleteCelltag(m_id); + } + + Map->AddCelltag(tag, x + y * Map->GetIsoSize()); + break; + } + case 6: // drag waypoint + { + CString ID; + DWORD dwPos; + + Map->GetWaypointData(m_id, &ID, &dwPos); + + if (!(nFlags == MK_SHIFT)) + { + Map->DeleteWaypoint(m_id); + } + + Map->AddWaypoint(ID, x + y * Map->GetIsoSize()); + break; + } + + } + + + + m_drag = FALSE; + line.left = 0; + line.top = 0; + line.right = 0; + line.bottom = 0; + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.mode == ACTIONMODE_MAPTOOL) + { + if (AD.tool) + AD.tool->onLButtonUp(projCoords, mapCoords, MapToolMouseFlagsFromWin32(nFlags)); + } + else if (AD.mode == ACTIONMODE_PLACE) // painting stuff + { + m_moved = FALSE; + if (AD.type == 6) // Overlay + { + if (AD.data == 5) // birdges + { + if (x == m_mapx && y == m_mapy) return; + + int ovrltype = 0x18; + if (abs(x - m_mapx) >= abs(y - m_mapy)) + { + // it´s from bottom left to top right + y = m_mapy; + ovrltype = 0x19; + } + else + { + // from bottom right to top left + x = m_mapx; + ovrltype = 0x18; + } + + int tmp; + + if (x < m_mapx) + { + tmp = m_mapx; + m_mapx = x; + x = tmp; + } + if (y < m_mapy) + { + tmp = m_mapy; + m_mapy = y; + y = tmp; + } + + // okay, now we can do it... + int i; + if (AD.data2 == 0) // big bridge + { + int startheight = Map->GetFielddataAt(m_mapx + m_mapy * Map->GetIsoSize())->bHeight; + + if (y == m_mapy) + { + for (i = m_mapx;i <= x;i++) + { + if (Map->GetFielddataAt(i + m_mapy * Map->GetIsoSize())->bHeight == startheight - 4) + { + startheight = Map->GetFielddataAt(i + m_mapy * Map->GetIsoSize())->bHeight; + break; + } + } + } + else + { + for (i = m_mapy;i <= y;i++) + { + if (Map->GetFielddataAt(m_mapx + i * Map->GetIsoSize())->bHeight == startheight - 4) + { + startheight = Map->GetFielddataAt(m_mapx + i * Map->GetIsoSize())->bHeight; + break; + } + } + } + + if (y == m_mapy) + { + for (i = m_mapx;i <= x;i++) + { + if (Map->GetFielddataAt(i + m_mapy * Map->GetIsoSize())->bHeight == startheight) + { + Map->SetOverlayAt(i + m_mapy * Map->GetIsoSize(), ovrltype); + Map->SetOverlayDataAt(i + m_mapy * Map->GetIsoSize(), 0x9); + } + } + } + else + { + for (i = m_mapy;i <= y;i++) + { + if (Map->GetFielddataAt(m_mapx + i * Map->GetIsoSize())->bHeight == startheight) + { + Map->SetOverlayAt(m_mapx + i * Map->GetIsoSize(), ovrltype); + Map->SetOverlayDataAt(m_mapx + i * Map->GetIsoSize(), 0x0); + } + } + } + } + if (AD.data2 == 2) // big track bridge + { + int startheight = Map->GetFielddataAt(m_mapx + m_mapy * Map->GetIsoSize())->bHeight; + + if (y == m_mapy) + { + for (i = m_mapx;i <= x;i++) + { + if (Map->GetFielddataAt(i + m_mapy * Map->GetIsoSize())->bHeight == startheight - 4) + { + startheight = Map->GetFielddataAt(i + m_mapy * Map->GetIsoSize())->bHeight; + break; + } + } + } + else + { + for (i = m_mapy;i <= y;i++) + { + if (Map->GetFielddataAt(m_mapx + i * Map->GetIsoSize())->bHeight == startheight - 4) + { + startheight = Map->GetFielddataAt(m_mapx + i * Map->GetIsoSize())->bHeight; + break; + } + } + } + + if (y == m_mapy) + { + for (i = m_mapx;i <= x;i++) + { + if (Map->GetFielddataAt(i + m_mapy * Map->GetIsoSize())->bHeight == startheight) + { + + Map->SetOverlayAt(i + m_mapy * Map->GetIsoSize(), 0x3c); +#ifdef RA2_MODE + Map->SetOverlayAt(i + m_mapy * Map->GetIsoSize(), 0xee); +#endif + Map->SetOverlayDataAt(i + m_mapy * Map->GetIsoSize(), 0x9); + } + } + } + else + { + for (i = m_mapy;i <= y;i++) + { + if (Map->GetFielddataAt(m_mapx + i * Map->GetIsoSize())->bHeight == startheight) + { + Map->SetOverlayAt(m_mapx + i * Map->GetIsoSize(), 0x3b); +#ifdef RA2_MODE + Map->SetOverlayAt(m_mapx + i * Map->GetIsoSize(), 0xed); +#endif + Map->SetOverlayDataAt(m_mapx + i * Map->GetIsoSize(), 0x0); + } + } + } + + /*if(y==m_mapy) + { + for(i=m_mapx;i<=x;i++) + { + Map->SetOverlayAt(i+m_mapy*Map->GetIsoSize(), 0x3b); + Map->SetOverlayDataAt(i+m_mapy*Map->GetIsoSize(), 0x9); + } + } + else + { + for(i=m_mapy;i<=y;i++) + { + Map->SetOverlayAt(m_mapx+i*Map->GetIsoSize(), 0x3b); + Map->SetOverlayDataAt(m_mapx+i*Map->GetIsoSize(), 0x0); + } + }*/ + } + else if (AD.data2 == 1 || AD.data2 == 3) // small bridge + { + int start = 0x4a; + if (AD.data2 == 3) start = 0xcd; + + if (y == m_mapy) + { + srand((unsigned)time(NULL)); + for (i = m_mapx + 1;i <= x - 1;i++) + { + + int v2 = ((float)rand() / (float)RAND_MAX) * 4; + + Map->SetOverlayAt(i + (m_mapy - 1) * Map->GetIsoSize(), start + 9 + v2); + Map->SetOverlayDataAt(i + (m_mapy - 1) * Map->GetIsoSize(), 0x0); + Map->SetOverlayAt(i + (m_mapy + 0) * Map->GetIsoSize(), start + 9 + v2); + Map->SetOverlayDataAt(i + (m_mapy + 0) * Map->GetIsoSize(), 0x1); + Map->SetOverlayAt(i + (m_mapy + 1) * Map->GetIsoSize(), start + 9 + v2); + Map->SetOverlayDataAt(i + (m_mapy + 1) * Map->GetIsoSize(), 0x2); + } + Map->SetOverlayAt(m_mapx + (m_mapy - 1) * Map->GetIsoSize(), start + 22); + Map->SetOverlayAt(m_mapx + (m_mapy - 0) * Map->GetIsoSize(), start + 22); + Map->SetOverlayAt(m_mapx + (m_mapy + 1) * Map->GetIsoSize(), start + 22); + Map->SetOverlayDataAt(m_mapx + (m_mapy - 1) * Map->GetIsoSize(), 0x0); + Map->SetOverlayDataAt(m_mapx + (m_mapy - 0) * Map->GetIsoSize(), 0x1); + Map->SetOverlayDataAt(m_mapx + (m_mapy + 1) * Map->GetIsoSize(), 0x2); + + Map->SetOverlayAt(x + (m_mapy - 1) * Map->GetIsoSize(), start + 24); + Map->SetOverlayAt(x + (m_mapy - 0) * Map->GetIsoSize(), start + 24); + Map->SetOverlayAt(x + (m_mapy + 1) * Map->GetIsoSize(), start + 24); + Map->SetOverlayDataAt(x + (m_mapy - 1) * Map->GetIsoSize(), 0x0); + Map->SetOverlayDataAt(x + (m_mapy - 0) * Map->GetIsoSize(), 0x1); + Map->SetOverlayDataAt(x + (m_mapy + 1) * Map->GetIsoSize(), 0x2); + + + } + else + { + srand((unsigned)time(NULL)); + + for (i = m_mapy + 1;i <= y - 1;i++) + { + + int v2 = ((float)rand() / (float)RAND_MAX) * 4; + + Map->SetOverlayAt((m_mapx - 1) + i * Map->GetIsoSize(), start + v2); + Map->SetOverlayDataAt((m_mapx - 1) + i * Map->GetIsoSize(), 0x0); + Map->SetOverlayAt((m_mapx - 0) + i * Map->GetIsoSize(), start + v2); + Map->SetOverlayDataAt((m_mapx - 0) + i * Map->GetIsoSize(), 0x1); + Map->SetOverlayAt((m_mapx + 1) + i * Map->GetIsoSize(), start + v2); + Map->SetOverlayDataAt((m_mapx + 1) + i * Map->GetIsoSize(), 0x2); + } + Map->SetOverlayAt((m_mapx - 1) + m_mapy * Map->GetIsoSize(), start + 20); + Map->SetOverlayAt((m_mapx - 0) + m_mapy * Map->GetIsoSize(), start + 20); + Map->SetOverlayAt((m_mapx + 1) + m_mapy * Map->GetIsoSize(), start + 20); + Map->SetOverlayDataAt((m_mapx - 1) + m_mapy * Map->GetIsoSize(), 0x0); + Map->SetOverlayDataAt((m_mapx - 0) + m_mapy * Map->GetIsoSize(), 0x1); + Map->SetOverlayDataAt((m_mapx + 1) + m_mapy * Map->GetIsoSize(), 0x2); + + Map->SetOverlayAt((m_mapx - 1) + y * Map->GetIsoSize(), start + 18); + Map->SetOverlayAt((m_mapx - 0) + y * Map->GetIsoSize(), start + 18); + Map->SetOverlayAt((m_mapx + 1) + y * Map->GetIsoSize(), start + 18); + Map->SetOverlayDataAt((m_mapx - 1) + y * Map->GetIsoSize(), 0x0); + Map->SetOverlayDataAt((m_mapx + 0) + y * Map->GetIsoSize(), 0x1); + Map->SetOverlayDataAt((m_mapx + 1) + y * Map->GetIsoSize(), 0x2); + + + } + } + + + + + //UpdateMap(); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + } + } + + CFinalSunDlg& dlg = *(CFinalSunDlg*)theApp.m_pMainWnd; + dlg.m_view.m_minimap.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + m_moved = FALSE; + + CView::OnLButtonUp(nFlags, point); +} + + + + +void CIsoView::TextOut(int x, int y, const char* text, COLORREF col) +{ + HDC hdc; + lpdsBack->GetDC(&hdc); + + SetTextColor(hdc, col); + SetBkMode(hdc, TRANSPARENT); + ::TextOut(hdc, x, y, text, strlen(text)); + + + lpdsBack->ReleaseDC(hdc); +} + +void CIsoView::TextOut(HDC hDC, int x, int y, const char* text, COLORREF col) +{ + SetTextColor(hDC, col); + SetBkMode(hDC, TRANSPARENT); + ::TextOut(hDC, x, y, text, strlen(text)); +} + + + +void CIsoView::OnMove(int x, int y) +{ + CView::OnMove(x, y); + + if (lpds == NULL) return; + LPDIRECTDRAWCLIPPER ddc; + + lpds->GetClipper(&ddc); + ddc->SetHWnd(0, m_hWnd); + updateFontScaled(); + + RedrawWindow(); +} + +void CIsoView::OnSize(UINT nType, int cx, int cy) +{ + // CView::OnSize(nType, cx, cy); + if (lpds == NULL) return; + + LPDIRECTDRAWCLIPPER ddc; + + lpds->GetClipper(&ddc); + ddc->SetHWnd(0, m_hWnd); + updateFontScaled(); + + CMyViewFrame& dlg = *(CMyViewFrame*)owner; + dlg.m_minimap.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + UpdateScrollRanges(); + + GetWindowRect(&m_myRect); +} + +COLORREF CIsoView::GetColor(const char* house, const char* vcolor) +{ + + COLORREF neutral = RGB(120, 120, 120); + COLORREF GDI = RGB(170, 170, 0); + COLORREF Nod = RGB(255, 0, 0); + COLORREF other = RGB(255, 255, 0); + + CString color; + CIniFile& ini = Map->GetIniFile(); + if (house && strlen(house)) + { + if (ini.sections.find(house) != ini.sections.end()) + { + color = ini.sections[house].values["Color"]; + } + else + color = rules.sections[house].values["Color"]; + } + + if (vcolor) + color = vcolor; + + if (color) + { + CString colorValues; + if (ini.sections.contains("Colors")) + { + colorValues = ini.sections["Colors"].GetValueByName(color); + } + if (colorValues.IsEmpty() && rules.sections.contains("Colors")) + { + colorValues = rules.sections["Colors"].GetValueByName(color); + } + auto colorArray = SplitParams(colorValues); + if (colorArray.size() == 3) + { + unsigned char hsv[3] = { static_cast<unsigned char>(std::atoi(colorArray[0])), static_cast<unsigned char>(std::atoi(colorArray[1])), static_cast<unsigned char>(std::atoi(colorArray[2])) }; + unsigned char rgb[3]; + HSVToRGB(hsv, rgb); + return RGB(rgb[0], rgb[1], rgb[2]); + } + } + +#ifndef RA2_MODE + if (strstr(house, houses[0].name) != NULL) + { + return GDI; + } + else if (strstr(house, houses[1].name) != NULL) + { + return Nod; + } + else if (strstr(house, houses[2].name) != NULL) + { + return neutral; + } + else + { + if (isIncluded(color, "darkred") != NULL) + { + return Nod; + } + if (isIncluded(color, "grey") != NULL) + { + return RGB(120, 120, 120); + } + if (isIncluded(color, "gold") != NULL) + { + return GDI; + } + + + return other; + } +#else + if (isIncluded(color, "darkred") != NULL) + { + return RGB(130, 20, 20); + } + if (isIncluded(color, "grey") != NULL) + { + return RGB(120, 120, 120); + } + if (isIncluded(color, "red") != NULL) + { + return RGB(240, 20, 20); + } + if (isIncluded(color, "lightgold") != NULL) + { + return RGB(220, 220, 150); + } + if (isIncluded(color, "yellow") != NULL) + { + return RGB(240, 240, 0); + } + if (isIncluded(color, "gold") != NULL) + { + return RGB(230, 200, 0); + } + if (isIncluded(color, "darkgreen") != NULL) + { + return RGB(50, 160, 70); + } + if (isIncluded(color, "neongreen") != NULL) + { + return RGB(10, 255, 10); + } + if (isIncluded(color, "green") != NULL) + { + return RGB(50, 200, 70); + } + if (isIncluded(color, "darkblue") != NULL) + { + return RGB(30, 30, 150); + } + if (isIncluded(color, "lightblue") != NULL) + { + return RGB(100, 100, 200); + } + if (isIncluded(color, "neonblue") != NULL) + { + return RGB(35, 205, 255); + } + + { + return other; + } + +#endif + + +} + + + + +/* +GetOverlayPic(BYTE ovrl, BYTE ovrldata); + +Returns the picture that should be used to draw the overlay tile. +First checks if a explicite bitmap exists for this tile, if not +checks if it can be displayed by a standard bitmap. +For bridges, it also needs the overlaydata. +*/ +inline PICDATA* GetOverlayPic(BYTE ovrl, BYTE ovrldata) +{ + + char c[50]; + char d[50]; + itoa(ovrl, c, 10); + itoa(ovrldata, d, 10); + + CString fname = (CString)"OVRL" + c + "_" + d; + + // MessageBox(0,fname,"",0); + + if (pics.find(fname) != pics.end()) return &pics[fname]; + + //errstream << "pic " << (LPCSTR)fname << " not found" << endl; + + + return NULL; +} + + + + +void CIsoView::OnDraw(CDC* pDC) +{ + DrawMap(); +} + + +void CIsoView::ReInitializeDDraw() +{ + b_IsLoading = TRUE; + ReleaseCapture(); + KillTimer(11); + // rscroll=FALSE; + + + +#ifdef NOSURFACES + while ((GetDeviceCaps(::GetDC(::GetDesktopWindow()), BITSPIXEL) <= 8)) + { + if (MessageBox("You currently only have 8 bit color mode enabled. FinalAlert 2 does not work in 8 bit color mode. Please change the color mode and then click on OK. Click Cancel to quit (and save the map as backup.map).", "Error", MB_OKCANCEL) == IDCANCEL) + { + ((CFinalSunDlg*)theApp.m_pMainWnd)->SaveMap((u8AppDataPath + "\\backup.map").c_str()); + PostQuitMessage(0); + return; + } + } +#endif + + + CDynamicGraphDlg dlg; + + dlg.ShowWindow(SW_SHOW); + dlg.UpdateWindow(); + + dd->RestoreAllSurfaces(); + + updateFontScaled(); + + + missingimages.clear(); + + theApp.m_loading->FreeAll(); + theApp.m_loading->InitDirectDraw(); + theApp.m_loading->InitPics(); + theApp.m_loading->InitTMPs(&dlg.m_Progress); + + memset(ovrlpics, 0, max_ovrl_img * 0xFF * sizeof(LPDIRECTDRAWSURFACE4)); + //UpdateOverlayPictures(-1); + //Map->UpdateIniFile(MAPDATA_UPDATE_FROM_INI); + Map->UpdateBuildingInfo(); + Map->UpdateTreeInfo(); +#ifdef SMUDGE_SUPP + Map->UpdateSmudgeInfo(); +#endif + + + + b_IsLoading = FALSE; + + //Sleep(2500); + + + + dlg.DestroyWindow(); + + + + + + RedrawWindow(); + + + + /* + + CString CommandLine; + + if(res==IDYES) + { + CFileDialog dlg(FALSE, ".mpr", "noname.mpr", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "TS maps|*.mpr;*.map|TS multi maps|*.mpr|TS single maps|*.map|"); + do + { + + + char cuPath[MAX_PATH]; + + GetCurrentDirectory(MAX_PATH, cuPath); + dlg.m_ofn.lpstrInitialDir=cuPath; + + if(theApp.m_Options.TSExe.GetLength()) dlg.m_ofn.lpstrInitialDir=(char*)(LPCTSTR)theApp.m_Options.TSExe; + + }while(dlg.DoModal()==IDCANCEL) ; + + CommandLine=dlg.GetPathName(); + + ((CFinalSunDlg*)theApp.m_pMainWnd)->SaveMap(dlg.GetPathName()); + } + + if(res==IDNO || res==IDYES) + { + PROCESS_INFORMATION pi; + STARTUPINFO si; + memset(&si, 0, sizeof(STARTUPINFO)); + si.cb=sizeof(STARTUPINFO); + + char myExe[MAX_PATH]; + GetModuleFileName(NULL, myExe, MAX_PATH); + + BOOL success=CreateProcess(myExe, + (LPTSTR)(LPCTSTR)CommandLine, + NULL, + NULL, + FALSE, + NORMAL_PRIORITY_CLASS, + NULL, + AppPath, + &si, + &pi); + } + + theApp.m_pMainWnd->DestroyWindow();*/ + + + + + + /*CLoading load; + load.InitDirectDraw(); + load.InitMixFiles(); + load.InitPics(); + + + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + b_IsLoading=FALSE;*/ + + +} + +void CIsoView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + + + CView::OnChar(nChar, nRepCnt, nFlags); +} + +void CIsoView::OnDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + + CView::OnDeadChar(nChar, nRepCnt, nFlags); +} + +void CIsoView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + int nPos; + + + + if (nChar == 68) // D key + { + theApp.m_Options.bFlat = !theApp.m_Options.bFlat; + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + if (nChar == 65) + m_bAltCliff = !m_bAltCliff; + + CView::OnKeyDown(nChar, nRepCnt, nFlags); +} + +void CIsoView::SetError(const char* text) +{ + CMyViewFrame& v = *((CMyViewFrame*)owner); + v.m_statbar.GetStatusBarCtrl().SetText(text, 0, 0); +} + + + + +int CIsoView::GetOverlayDirection(int x, int y) +{ + DWORD dwIsoSize = Map->GetIsoSize(); + int p = -1; + int type = Map->GetOverlayAt(x + y * dwIsoSize); + + BOOL isTrail = FALSE; + int i; + for (i = 0;i < overlay_count;i++) + if (overlay_number[i] == type) + if (overlay_trail[i]) isTrail = TRUE; + + if (isTrack(type)) // handling a train track + { + + + if (isTrack(Map->GetOverlayAt((x - 1) + (y - 1) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x + 1) + (y + 1) * dwIsoSize))) + return 0; + if (isTrack(Map->GetOverlayAt((x + 1) + (y - 1) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x - 1) + (y + 1) * dwIsoSize))) + return 1; + if (isTrack(Map->GetOverlayAt((x - 1) + (y - 0) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x + 1) + (y + 0) * dwIsoSize))) + return 2; + if (isTrack(Map->GetOverlayAt((x - 0) + (y - 1) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x + 0) + (y + 1) * dwIsoSize))) + return 3; + if (isTrack(Map->GetOverlayAt((x - 1) + (y - 0) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x + 1) + (y + 1) * dwIsoSize))) + return 4; + if (isTrack(Map->GetOverlayAt((x - 0) + (y - 1) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x + 1) + (y + 1) * dwIsoSize))) + return 5; + if (isTrack(Map->GetOverlayAt((x - 1) + (y - 1) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x - 0) + (y + 1) * dwIsoSize))) + return 6; + if (isTrack(Map->GetOverlayAt((x - 1) + (y - 1) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x + 1) + (y + 0) * dwIsoSize))) + return 7; + if (isTrack(Map->GetOverlayAt((x - 1) + (y - 0) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x + 1) + (y - 1) * dwIsoSize))) + return 8; + if (isTrack(Map->GetOverlayAt((x + 0) + (y + 1) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x + 1) + (y - 1) * dwIsoSize))) + return 9; + if (isTrack(Map->GetOverlayAt((x - 0) + (y - 1) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x - 1) + (y + 1) * dwIsoSize))) + return 10; + if (isTrack(Map->GetOverlayAt((x - 1) + (y + 1) * dwIsoSize)) && isTrack(Map->GetOverlayAt((x + 1) + (y + 0) * dwIsoSize))) + return 11; + if (isTrack(Map->GetOverlayAt((x - 1) + (y - 1) * dwIsoSize))) + return 0; + if (isTrack(Map->GetOverlayAt((x - 1) + (y + 1) * dwIsoSize))) + return 1; + if (isTrack(Map->GetOverlayAt((x - 1) + (y - 0) * dwIsoSize))) + return 2; + if (isTrack(Map->GetOverlayAt((x - 0) + (y - 1) * dwIsoSize))) + return 3; + if (isTrack(Map->GetOverlayAt((x + 1) + (y + 1) * dwIsoSize))) + return 0; + if (isTrack(Map->GetOverlayAt((x + 1) + (y - 1) * dwIsoSize))) + return 1; + if (isTrack(Map->GetOverlayAt((x + 1) + (y + 0) * dwIsoSize))) + return 2; + if (isTrack(Map->GetOverlayAt((x + 0) + (y + 1) * dwIsoSize))) + return 3; + + return 0; + } + else if (isTrail) // handling something like a sandbag + { + p = 0; + if (Map->GetOverlayAt(x - 1 + (y - 0) * dwIsoSize) == type) p |= 0x1; + if (Map->GetOverlayAt(x + (y + 1) * dwIsoSize) == type) p |= 0x2; + if (Map->GetOverlayAt(x + 1 + (y + 0) * dwIsoSize) == type) p |= 0x4; + if (Map->GetOverlayAt(x + (y - 1) * dwIsoSize) == type) p |= 0x8; + } + + return p; + +} + +void CIsoView::HandleTrail(int x, int y) +{ + int i, e; + int type = Map->GetOverlayAt(x + y * Map->GetIsoSize()); + + if (isTrack(type)) // is a track (overlay must be changed) + { + + for (i = x - 2;i <= x + 2;i++) + { + for (e = y - 1;e <= y + 1;e++) + { + if (isTrack(Map->GetOverlayAt(i + e * Map->GetIsoSize()))) + Map->SetOverlayAt(i + e * Map->GetIsoSize(), 0x27 + GetOverlayDirection(i, e)); + } + } + } + else // something like a sandbag (overlaydata must be changed) + { + + for (i = x - 2;i <= x + 2;i++) + { + for (e = y - 1;e <= y + 1;e++) + { + if (Map->GetOverlayAt(i + e * Map->GetIsoSize()) == type) + { + int dir = GetOverlayDirection(i, e); + if (dir >= 0) Map->SetOverlayDataAt(i + e * Map->GetIsoSize(), dir); + } + } + } + } + +} + + +/* +DrawCell(int x, int y, int w, int h, COLORREF col) + +Draws a frame around one or more cells. +w is the width, h is the height (in cells). +x and y are pixel coordinates. +col specifies the color. +*/ +void CIsoView::DrawCell(int x, int y, int w, int h, COLORREF col, BOOL dotted, HDC hDC_) +{ + + + // correct the y value: + //y -= f_y; + + POINT p1, p2, p3, p4; + p1.x = x + f_x / 2; + p1.y = y; + p2.x = x + w * f_x / 2 + f_x / 2; + p2.y = y + w * f_y / 2; + p3.x = x + w * f_x / 2 - h * f_x / 2 + f_x / 2 - 1; + p3.y = y + h * f_y / 2 + w * f_y / 2 - 1; + p4.x = x - h * f_x / 2 + f_x / 2 - 1; + p4.y = y + h * f_y / 2 - 1; + + HDC hDC = hDC_; + if (!hDC) + while (lpdsBack->GetDC(&hDC) == DDERR_WASSTILLDRAWING); + + HPEN p; + int width = 1; +#ifdef RA2_MODE + width = 2; +#endif + if (!dotted) p = CreatePen(PS_SOLID, width, col); + else p = CreatePen(PS_DOT, 0, col); + + SelectObject(hDC, p); + + if (dotted) + { + SetBkMode(hDC, TRANSPARENT); + MoveToEx(hDC, p1.x, p1.y - 1, NULL); + LineTo(hDC, p2.x + 1, p2.y); + LineTo(hDC, p3.x, p3.y + 1); + LineTo(hDC, p4.x - 1, p4.y); + LineTo(hDC, p1.x, p1.y - 1); + } + + if (!dotted) + { + MoveToEx(hDC, p1.x, p1.y, NULL); + LineTo(hDC, p2.x, p2.y); + LineTo(hDC, p3.x, p3.y); + LineTo(hDC, p4.x, p4.y); + LineTo(hDC, p1.x, p1.y); + } + + + + + + if (!hDC_) + lpdsBack->ReleaseDC(hDC); + + DeleteObject(p); +} + +void CIsoView::DrawCell(void* dest, int dest_width, int dest_height, int dest_pitch, int drawx, int drawy, int w, int h, int col, bool dotted, bool touchNeighbours, int colNeighbour) const +{ + if (colNeighbour == CLR_INVALID) + colNeighbour = col; + + // correct the y value: + //y -= f_y; + + POINT p1, p2, p3, p4; + p1.x = drawx + f_x / 2; + p1.y = drawy; + p2.x = drawx + w * f_x / 2 + f_x / 2; + p2.y = drawy + w * f_y / 2; + p3.x = drawx + w * f_x / 2 - h * f_x / 2 + f_x / 2; + p3.y = drawy + h * f_y / 2 + w * f_y / 2; + p4.x = drawx - h * f_x / 2 + f_x / 2; + p4.y = drawy + h * f_y / 2; + + LineDrawer drawer(dest, bpp, dest_width, dest_height, dest_pitch); + + const LineStyle style = dotted ? LineStyle::Dotted_4 : LineStyle::Standard; + + for (int x = 0; x < 1; ++x) // you could use this loop for more thickness + { + for (int y = 0; y < 1; ++y) + { + // inside the MM tile + drawer.MoveTo(p1.x + x + 1, p1.y + y + 1); + drawer.LineTo(p2.x + x - 2, p2.y + y - 1, col, style); + drawer.LineTo(p3.x + x + 1, p3.y + y - 3, col, style); + drawer.LineTo(p3.x + x, p3.y + y - 3, col, style); + drawer.LineTo(p4.x + x + 3, p4.y + y - 1, col, style); + drawer.LineTo(p4.x + x + 2, p4.y + y - 1, col, style); + drawer.MoveTo(p4.x + x + 3, p4.y + y - 1); + drawer.LineTo(p1.x + x, p1.y + y + 1, col, style); + drawer.LineTo(p1.x + x + 1, p1.y + y + 1, col, style); + + // on inner pixels of MM tile boundary + drawer.MoveTo(p1.x + x + 1, p1.y + y); + drawer.LineTo(p2.x + x, p2.y + y - 1, col, style); + drawer.LineTo(p3.x + x + 1, p3.y + y - 2, col, style); + drawer.LineTo(p3.x + x, p3.y + y - 2, col, style); + drawer.LineTo(p4.x + x + 1, p4.y + y - 1, col, style); + drawer.LineTo(p1.x + x, p1.y + y, col, style); + drawer.LineTo(p1.x + x + 1, p1.y + y, col, style); + } + } + + // pixels of neighboured MM tiles boundary + if (touchNeighbours) + { + for (int x = 0; x < 1; ++x) // you could use this loop for more thickness + { + for (int y = 0; y < 1; ++y) + { + drawer.MoveTo(p1.x + x + 1, p1.y + y - 1); + drawer.LineTo(p2.x + x - 2, p2.y + y - 3, colNeighbour, style); + drawer.MoveTo(p2.x + x - 2, p2.y + y - 2); + drawer.LineTo(p2.x + x - 1, p2.y + y, colNeighbour, style); + drawer.LineTo(p2.x + x, p2.y + y, colNeighbour, style); + drawer.LineTo(p3.x + x + 1, p3.y + y - 1, colNeighbour, style); + drawer.LineTo(p3.x + x, p3.y + y - 1, colNeighbour, style); + drawer.LineTo(p4.x + x + 1, p4.y + y, colNeighbour, style); + drawer.LineTo(p4.x + x, p4.y + y - 1, colNeighbour, style); + drawer.LineTo(p1.x + x, p1.y + y - 1, colNeighbour, style); + drawer.LineTo(p1.x + x + 1, p1.y + y - 1, colNeighbour, style); + } + } + } +} + +void CIsoView::DrawTube(const CTube& tube, const DDSURFACEDESC2* lockedDDSD, const COLORREF* color) const +{ + SurfaceLocker locker(lpdsBack); + + if (!lockedDDSD || !lockedDDSD->lpSurface) + { + lockedDDSD = locker.ensure_locked(); + } + if (!lockedDDSD) + return; + + // TODO: culling if required + + // find out if we are tube #1 or #2 for bidirectional tubes + bool type0 = tube.getStartX() == tube.getEndX() ? (tube.getStartY() < tube.getEndY()) : (tube.getStartX() < tube.getEndX()); + const auto col = color ? m_color_converter->GetColor(*color) : (type0 ? m_color_converter->GetColor(255, 0, 0) : m_color_converter->GetColor(0, 0, 255)); + ProjectedVec lineOffset = type0 ? ProjectedVec() : ProjectedVec(1, 1); + + int lowestHeight = min(Map->GetHeightAt(tube.getStartCoords()), Map->GetHeightAt(tube.getEndCoords())); + LineDrawer ld(lockedDDSD->lpSurface, bpp, lockedDDSD->dwWidth, lockedDDSD->dwHeight, lockedDDSD->lPitch); + auto startDraw = GetRenderTargetCoordinates(tube.getStartCoords(), lowestHeight); + ld.MoveTo(startDraw.x + f_x / 2 + lineOffset.x, startDraw.y + f_y / 2 + lineOffset.y); + + + tube.walk([this, &tube, lockedDDSD, &ld, lowestHeight, col, lineOffset](const auto& wi) { + auto draw = GetRenderTargetCoordinates(wi.pos, lowestHeight); + if (wi.pos == tube.getEndCoords()) + { + // end coordinates are drawn as cross + LineDrawer startLD(lockedDDSD->lpSurface, bpp, lockedDDSD->dwWidth, lockedDDSD->dwHeight, lockedDDSD->lPitch); + ProjectedVec off(7, 4); + startLD.DrawLine(draw.x + off.x, draw.y + f_y / 2, draw.x + f_x - off.x, draw.y + f_y / 2, col); + startLD.DrawLine(draw.x + f_x / 2 - 1, draw.y + off.y, draw.x + f_x / 2 - 1, draw.y + f_y - off.y, col); + } + if (wi.pos == tube.getStartCoords()) + { + // Start coordinates are drawn as cell + DrawCell(lockedDDSD->lpSurface, lockedDDSD->dwWidth, lockedDDSD->dwHeight, lockedDDSD->lPitch, draw.x, draw.y, 1, 1, col, true); + } + ld.LineTo(draw.x + f_x / 2 + lineOffset.x, draw.y + f_y / 2 + lineOffset.y, col); + return true; + }); +} + +MapCoords CIsoView::GetMapCoordinates(const ProjectedCoords& projCoords, bool bAllowAccessBehindCliffs, bool ignoreHideFlagsAndOutside) const +{ + return theApp.m_Options.bFlat ? Map->ToMapCoords(projCoords) : Map->ToMapCoords3d(projCoords, bAllowAccessBehindCliffs, ignoreHideFlagsAndOutside); +} + +MapCoords CIsoView::GetMapCoordinatesFromRenderTargetCoordinates(const ProjectedCoords& projCoords, bool bAllowAccessBehindCliffs, bool ignoreHideFlagsAndOutside) const +{ + return GetMapCoordinates(projCoords + m_viewOffset, bAllowAccessBehindCliffs, ignoreHideFlagsAndOutside); +} + +MapCoords CIsoView::GetMapCoordinatesFromClientCoordinates(const CPoint& clientPt, bool bAllowAccessBehindCliffs, bool ignoreHideFlagsAndOutside) const +{ + return GetMapCoordinates(GetProjectedCoordinatesFromClientCoordinates(clientPt), bAllowAccessBehindCliffs, ignoreHideFlagsAndOutside); +} + +ProjectedCoords CIsoView::GetProjectedCoordinatesFromClientCoordinates(const CPoint& clientPt) const +{ + RECT r; + GetWindowRect(&r); + const auto viewOffsetWR = m_viewOffset + ProjectedVec(r.left, r.top); + const auto projCoords = ProjectedCoords(clientPt.x * m_viewScale.x, clientPt.y * m_viewScale.y) + viewOffsetWR; + return projCoords; +} + +ProjectedCoords CIsoView::GetProjectedCoordinates(const MapCoords& mapCoords) const +{ + return theApp.m_Options.bFlat ? Map->ProjectCoords(mapCoords) : Map->ProjectCoords3d(mapCoords); +} + +ProjectedCoords CIsoView::GetProjectedCoordinates(const MapCoords& mapCoords, int mapZ) const +{ + return Map->ProjectCoords3d(mapCoords, mapZ); +} + +ProjectedCoords CIsoView::GetRenderTargetCoordinates(const MapCoords& mapCoords) const +{ + // Draw coordinates are display coordinates + return GetProjectedCoordinates(mapCoords) - m_viewOffset; +} + +ProjectedCoords CIsoView::GetRenderTargetCoordinates(const MapCoords& mapCoords, int mapZ) const +{ + return GetProjectedCoordinates(mapCoords, mapZ) - m_viewOffset; +} + +CPoint CIsoView::GetClientCoordinates(const MapCoords& mapCoords) const +{ + RECT r; + GetWindowRect(&r); + const auto windowPos = ProjectedVec(r.left, r.top); + //const auto p = ScaleBackToFrontBuffer(GetRenderTargetCoordinates(mapCoords)) - windowPos; + const auto rtc = GetRenderTargetCoordinates(mapCoords); + const auto p = ((ProjectedCoords(rtc.x, rtc.y) - windowPos) / m_viewScale).convertT<std::int32_t>(); + return CPoint(p.x, p.y); +} + +CPoint CIsoView::GetClientCoordinatesFromWorld(const ProjectedCoords& projectedCoords) const +{ + RECT r; + GetWindowRect(&r); + const auto windowPos = ProjectedVec(r.left, r.top); + //const auto p = ScaleBackToFrontBuffer(GetRenderTargetCoordinates(mapCoords)) - windowPos; + const auto rtc = projectedCoords - m_viewOffset; + const auto p = ((ProjectedCoords(rtc.x, rtc.y)) / m_viewScale).convertT<std::int32_t>(); + return CPoint(p.x, p.y); +} + +ProjectedCoords CIsoView::ScaleBackToFrontBuffer(const ProjectedCoords& backBufferCoords) const +{ + RECT r; + GetWindowRect(&r); + const auto windowPos = ProjectedVec(r.left, r.top); + return ((ProjectedCoords(backBufferCoords.x, backBufferCoords.y) - windowPos) / m_viewScale).convertT<std::int32_t>() + windowPos; +} + + +void CIsoView::UpdateStatusBar(int x, int y) +{ + CString statusbar;//=TranslateStringACP("Ready"); + + FIELDDATA m = *Map->GetFielddataAt(x + y * Map->GetIsoSize()); + if (m.wGround == 0xFFFF) m.wGround = 0; + + if (m.wGround < (*tiledata_count) && m.bSubTile < (*tiledata)[m.wGround].wTileCount) + { + statusbar = "Terrain type: 0x"; + char c[50]; + itoa((*tiledata)[m.wGround].tiles[m.bSubTile].bTerrainType, c, 16); + statusbar += c; + statusbar += ", height: "; + itoa(m.bHeight, c, 10); + statusbar += c; + statusbar += " / "; + } + + + if (Map->GetOverlayAt(x + y * Map->GetIsoSize()) != 0xFF) + { + char ov[50]; + itoa(Map->GetOverlayAt(x + y * Map->GetIsoSize()), ov, 16); + + int i; + CString name; + name = "0x"; + name += ov; + for (i = 0;i < overlay_count;i++) + { + if (overlay_number[i] == Map->GetOverlayAt(x + y * Map->GetIsoSize())) + name = overlay_name[i]; + } + + + itoa(Map->GetOverlayDataAt(x + y * Map->GetIsoSize()), ov, 16); + + statusbar += GetLanguageStringACP("OvrlStatus"); + statusbar += TranslateStringACP(name); + statusbar += ", OverlayData: 0x"; + statusbar += ov; + } + + STDOBJECTDATA sod; + sod.type = ""; + + int n = Map->GetStructureAt(x + y * Map->GetIsoSize()); + int on = -1; + if (n >= 0) + { + + Map->GetStdStructureData(n, &sod); + statusbar = GetLanguageStringACP("StructStatus"); + on = n; + } + + n = Map->GetUnitAt(x + y * Map->GetIsoSize()); + if (n >= 0) + { + + Map->GetStdUnitData(n, &sod); + statusbar = GetLanguageStringACP("UnitStatus"); + on = n; + + } + + n = Map->GetAirAt(x + y * Map->GetIsoSize()); + if (n >= 0) + { + + Map->GetStdAircraftData(n, &sod); + statusbar = GetLanguageStringACP("AirStatus"); + on = n; + } + + n = Map->GetInfantryAt(x + y * Map->GetIsoSize()); + if (n >= 0) + { + Map->GetStdInfantryData(n, &sod); + statusbar = GetLanguageStringACP("InfStatus"); + on = n; + } + + if (sod.type.GetLength() > 0) + { + char c[50]; + itoa(on, c, 10); + statusbar += "ID "; + statusbar += c; + statusbar += ", "; + + statusbar += TranslateStringACP(Map->GetUnitName(sod.type)); + statusbar += " ("; + + statusbar += TranslateHouse(sod.house, TRUE); + statusbar += ", "; + statusbar += sod.type; + statusbar += ")"; + } + + /* + // activate this code to display information about the mappack! + + statusbar="MAPPACK: "; + int i; + FIELDDATA td=Map->GetFielddataAt(x+y*Map->GetIsoSize()); + char c[50]; + itoa(td.wGround, c, 10); + statusbar+="tile: "; + statusbar+=c; + statusbar+=" "; + for(i=0;i<3;i++) + { + itoa(td.bMapData[i], c, 10); + statusbar+=c; + statusbar+=" "; + } + + statusbar+=" height: "; + itoa(td.bHeight, c, 10); + statusbar+=c; + statusbar+=" "; + itoa(td.bMapData2[0],c,10); + statusbar+=c;*/ + + + n = Map->GetCelltagAt(x + y * Map->GetIsoSize()); + if (n >= 0) + { + CString type; + CString name; + DWORD pos; + Map->GetCelltagData(n, &type, &pos); + CIniFile& ini = Map->GetIniFile(); + if (ini.sections["Tags"].values.find(type) != ini.sections["Tags"].values.end()) + name = GetParam(ini.sections["Tags"].values[type], 1); + + statusbar += GetLanguageStringACP("CellTagStatus"); + statusbar += name; + statusbar += " ("; + statusbar += type; + statusbar += ")"; + } + + if (AD.mode == ACTIONMODE_SETTILE) + { + statusbar = GetLanguageStringACP("TilePlaceStatus"); + } + + if (AD.mode == ACTIONMODE_COPY) + statusbar = GetLanguageStringACP("CopyHelp"); + + if (statusbar.GetLength() > 0) + SetError(statusbar); + +} + +void CIsoView::UpdateOverlayPictures(int id) +{ + if (id < 0) + { + memset(ovrlpics, 0, max_ovrl_img * 0xFF * sizeof(LPDIRECTDRAWSURFACE4)); + + int i, e; + for (i = 0;i < 0xFF;i++) + { + for (e = 0;e < max_ovrl_img;e++) + { + /*PICDATA& p=GetOverlayPic(i, e); + if(p.pic!=NULL) ovrlpics[i][e]=&p; + else + ovrlpics[i][e]=NULL;*/ + ovrlpics[i][e] = GetOverlayPic(i, e); + } + } + } + else + { + int e; + for (e = 0;e < max_ovrl_img;e++) + { + ovrlpics[id][e] = GetOverlayPic(id, e); + } + } +} + + +__forceinline void FixTileHeight(DWORD dwPos, int x, int y) +{ + return; // we use CMapData::CreateSlopes() to fix slopes now + + int oheight = Map->GetHeightAt(dwPos); + int isosize = Map->GetIsoSize(); + + char bHeightDiff[9]; + + int i, e; + for (i = -1;i < 2;i++) + { + for (e = -1;e < 2;e++) + { + if (x + i < 0 || y + e < 0 || x + i >= isosize || y + e >= isosize) bHeightDiff[i + 1 + (e + 1) * 3] = 0; + else + bHeightDiff[i + 1 + (e + 1) * 3] = oheight - Map->GetHeightAt(dwPos + i + e * isosize); + } + } + + if (bHeightDiff[1] < 0 && bHeightDiff[7] < 0) + { + Map->SetHeightAt(dwPos, oheight + 1); + return; + } + if (bHeightDiff[3] < 0 && bHeightDiff[5] < 0) + { + Map->SetHeightAt(dwPos, oheight + 1); + return; + } + + if ( + (bHeightDiff[1] < 0 && bHeightDiff[6] < 0) || + (bHeightDiff[1] < 0 && bHeightDiff[8] < 0) /*|| + (bHeightDiff[3]<0 && bHeightDiff[2]<0) || + (bHeightDiff[3]<0 && bHeightDiff[8]<0) || + (bHeightDiff[5]<0 && bHeightDiff[0]<0) || + (bHeightDiff[5]<0 && bHeightDiff[6]<0) || + (bHeightDiff[7]<0 && bHeightDiff[0]<0) || + (bHeightDiff[7]<0 && bHeightDiff[2]<0) */ + ) + { + Map->SetHeightAt(dwPos, oheight + 1); + return; + } +} + + +/* +ChangeTileHeight(); + +General routine for changing the height of a tile. +Warning: This routine calls itself if necessary, and therefore may be quite performance hungry! +*/ +void __fastcall CIsoView::ChangeTileHeight(DWORD dwPos, DWORD dwNewHeight, BOOL bNonMorpheableMove, BOOL bOnlyThisTile, BOOL bNoSlopes) +{ + int isosize = Map->GetIsoSize(); + int mapsize = isosize * isosize; + int mapwidth = Map->GetWidth(); + int mapheight = Map->GetHeight(); + + int dwX = dwPos % isosize; + int dwY = dwPos / isosize; + + //if(dwX==0 || dwY==0 || dwX+dwY<mapwidth || dwX+dwY>mapwidth+mapheight*2 || (dwY>mapwidth && dwX<dwY-mapwidth) || (dwX>mapwidth && dwY+mapwidth<dwX)) return; + //if( dwX<2|| dwY<2 || dwX+dwY<mapwidth+2 || dwX+dwY+2>mapwidth+mapheight*2 || (dwY+2>mapwidth && dwX-2<dwY-mapwidth) || (dwX+2>mapwidth && dwY+mapwidth-2<dwX)) return; + if (dwX < 1 || dwY < 1 || dwX + dwY<mapwidth + 1 || dwX + dwY>mapwidth + mapheight * 2 || (dwY + 1 > mapwidth && dwX - 1 < dwY - mapwidth) || (dwX + 1 > mapwidth && dwY + mapwidth - 1 < dwX)) return; + + + + FIELDDATA orig_fd = *Map->GetFielddataAt(dwPos); + + //if(bOnlyHeighten && dwNewHeight<orig_fd.bHeight) return; + + if (orig_fd.wGround == 0xFFFF) orig_fd.wGround = 0; + int orig_ground = orig_fd.wGround; + + if (orig_fd.bReserved) return; + + if (dwX < m_funcRect.left) m_funcRect.left = dwX; + if (dwY < m_funcRect.top) m_funcRect.top = dwY; + if (dwX > m_funcRect.right) m_funcRect.right = dwX; + if (dwY > m_funcRect.bottom) m_funcRect.bottom = dwY; + + BOOL bCliffNext = FALSE; + /*if(bOnlyHeighten) + { + bCliffNext=FALSE; + /*int i; + int e; + for(i=-1;i<2;i++) + { + for(e=-1;e<2;e++) + { + int pos=dwPos+i+(e)*isosize; + + FIELDDATA fd=*Map->GetFielddataAt(pos); + if(fd.wGround==0xFFFF) fd.wGround=0; + + if((*tiledata)[fd.wGround].wTileSet==cliffset || fd.bCliffHack) + { + bCliffNext=TRUE; + break; + } + } + if(bCliffNext) break; + }*//* + + }*/ + + Map->SetReserved(dwPos, 1); + + + if (!(*tiledata)[orig_ground].bMorphable) bNonMorpheableMove = TRUE; + + Map->SetHeightAt(dwPos, dwNewHeight); + + + int i, e; + for (i = -1;i < 2;i++) + { + for (e = -1;e < 2;e++) + { + + int pos = dwPos + i + (e)*isosize; + + FIELDDATA fd = *Map->GetFielddataAt(pos); + if (fd.wGround == 0xFFFF) fd.wGround = 0; + + BOOL bAllowed = TRUE; + + if (dwX == 0 && i == -1) bAllowed = FALSE; + else if (dwY == 0 && e == -1) bAllowed = FALSE; + else if (dwX == isosize - 1 && i == 1) bAllowed = FALSE; + else if (dwY == isosize - 1 && e == 1) bAllowed = FALSE; + + + if (bOnlyThisTile) + { + if (fd.wGround != orig_fd.wGround) bAllowed = FALSE; // was another tile + + else + { + // we now need to check if it is really the same tile or just the same tile type (!) + int of = orig_fd.bSubTile; + int f = fd.bSubTile; + int width = (*tiledata)[orig_ground].cy; + int height = (*tiledata)[orig_ground].cx; + int ox = of / width; + int oy = of % width; + int x = f / width; + int y = f % width; + + if (x - ox != i || y - oy != e) bAllowed = FALSE; + } + } + + + int ground = fd.wGround; + + + if (bAllowed && !fd.bReserved && pos > 0 && pos < mapsize) + { + + + + + BOOL bDestMorphable = (*tiledata)[fd.wGround].bMorphable; + TILEDATA destTile = (*tiledata)[fd.wGround]; + TILEDATA sourceTile = (*tiledata)[orig_fd.wGround]; + + if (bAllowed && (!bNonMorpheableMove || bDestMorphable)) + { + if (e == 1 && i == 1) + { + int leftGround = Map->GetFielddataAt(dwPos + 1)->wGround; + int rightGround = Map->GetFielddataAt(dwPos + isosize)->wGround; + if (leftGround == 0xFFFF) leftGround = 0; + if (rightGround == 0xFFFF) rightGround = 0; + if (!(*tiledata)[leftGround].bMorphable && !(*tiledata)[rightGround].bMorphable) + bAllowed = FALSE; + } + if (e == -1 && i == -1) + { + int leftGround = Map->GetFielddataAt(dwPos - 1)->wGround; + int rightGround = Map->GetFielddataAt(dwPos - isosize)->wGround; + if (leftGround == 0xFFFF) leftGround = 0; + if (rightGround == 0xFFFF) rightGround = 0; + if (!(*tiledata)[leftGround].bMorphable && !(*tiledata)[rightGround].bMorphable) + bAllowed = FALSE; + } + if (e == -1 && i == 1) + { + int leftGround = Map->GetFielddataAt(dwPos - 1)->wGround; + int rightGround = Map->GetFielddataAt(dwPos + isosize)->wGround; + if (leftGround == 0xFFFF) leftGround = 0; + if (rightGround == 0xFFFF) rightGround = 0; + if (!(*tiledata)[leftGround].bMorphable && !(*tiledata)[rightGround].bMorphable) + bAllowed = FALSE; + } + if (e == 1 && i == -1) + { + int leftGround = Map->GetFielddataAt(dwPos + 1)->wGround; + int rightGround = Map->GetFielddataAt(dwPos - isosize)->wGround; + if (leftGround == 0xFFFF) leftGround = 0; + if (rightGround == 0xFFFF) rightGround = 0; + if (!(*tiledata)[leftGround].bMorphable && !(*tiledata)[rightGround].bMorphable) + bAllowed = FALSE; + } + } + + + + + + + if (/*(*tiledata)[ground].bMorphable &&*/ bAllowed) + { + int need_diff = (*tiledata)[ground].tiles[fd.bSubTile].bZHeight - (*tiledata)[orig_ground].tiles[orig_fd.bSubTile].bZHeight; + + + //if(Map->GetHeightAt(pos)-dwNewHeight!=need_diff || !bNonMorpheableMove) + { + int diff = fd.bHeight - dwNewHeight; + + /* + Activate this code to use the huge slopes + Removed because it did look worse than the normal slopes + */ + /* + if(i && abs(i)==abs(e)) + { + if(diff<-1) diff++; + if(diff>1) diff--; + }*/ + + + if (!bNonMorpheableMove && bDestMorphable) + { + //if(!bOnlyHeighten)//!bCliffNext) + { + if (diff < -1) + ChangeTileHeight(pos, dwNewHeight - 1, bNonMorpheableMove, bOnlyThisTile, bNoSlopes); + if (diff > 1) + ChangeTileHeight(pos, dwNewHeight + 1, bNonMorpheableMove, bOnlyThisTile, bNoSlopes); + } + /*else + { + ChangeTileHeight(pos, dwNewHeight, bNonMorpheableMove, bOnlyThisTile, bOnlyHeighten); + }*/ + } + else if (bNonMorpheableMove) + { + if (!bDestMorphable /*&& (*tiledata)[fd.wGround].wTileSet==(*tiledata)[orig_fd.wGround].wTileSet*/ /*&& need_diff!=fd.bHeight-orig_fd.bHeight*/) + { + if (destTile.tiles[fd.bSubTile].bTerrainType == sourceTile.tiles[orig_fd.bSubTile].bTerrainType || destTile.wTileSet == sourceTile.wTileSet) + { + ChangeTileHeight(pos, dwNewHeight + need_diff, TRUE, bOnlyThisTile, bNoSlopes); + } + } + else if (bDestMorphable /*&& need_diff!=fd.bHeight-orig_fd.bHeight*/) + { + //diff-=need_diff; + + if ((sourceTile.cx > 1 && sourceTile.cy > 1 && (e < 0 && i < 0)) || ((sourceTile.cx < 2 || sourceTile.cy < 2) && (e > 0 && i > 0))) + { + ChangeTileHeight(pos, dwNewHeight, FALSE, bOnlyThisTile, bNoSlopes); + } + else + { + if (diff - need_diff > 0) + ChangeTileHeight(pos, dwNewHeight + need_diff, FALSE, bOnlyThisTile, bNoSlopes); + else if (diff - need_diff < 0) + ChangeTileHeight(pos, dwNewHeight + need_diff, FALSE, bOnlyThisTile, bNoSlopes); + } + + } + } + + } + } + } + } + } + + /*for(i=-1;i<2;i++) + { + for(e=-1;e<2;e++) + { + FixTileHeight(dwPos+i+e*isosize, dwX+i, dwY+e); + } + }*/ + + if (!bNoSlopes) + { + for (i = -1;i < 2;i++) + { + for (e = -1;e < 2;e++) + { + int pos = dwPos + i + (e)*isosize; + if (pos > 0 && pos < mapsize) + Map->CreateSlopesAt(pos); + } + } + } + +} + +BOOL CIsoView::ReachableFrom(DWORD dwStart, DWORD dwEnd) +{ + FIELDDATA orig_fd = *Map->GetFielddataAt(dwStart); + if (orig_fd.wGround == 0xFF) orig_fd.wGround = 0; + int orig_ground = orig_fd.wGround; + + if (orig_fd.bReserved) return FALSE; + orig_fd.bReserved = 1; + + if (dwStart == dwEnd) return TRUE; + + + int i, e; + for (i = -1;i < 2;i++) + { + for (e = -1;e < 2;e++) + { + int new_ground = orig_fd.wGround; + if (new_ground == 0xFFFF) new_ground = 0; + + if (!(*tiledata)[new_ground].bMorphable && ReachableFrom(dwStart + i + e * Map->GetIsoSize(), dwEnd)) + return TRUE; + } + } + + return FALSE; +} + +void CIsoView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + CView::OnKeyUp(nChar, nRepCnt, nFlags); +} + +void CIsoView::HideTileSet(DWORD dwTileSet) +{ + int i; + for (i = 0;i < *tiledata_count;i++) + { + if ((*tiledata)[i].wTileSet == dwTileSet) (*tiledata)[i].bHide = TRUE; + } +} + +void CIsoView::BlitBackbufferToHighRes() +{ + // MW: + // the primary buffer and the (optional) high-res buffer cover the whole screen (Windows automatic high DPI scaling does not change this) + // the backbuffer also has the size of the whole screen, however we don't render to the whole screen + // we only render to the visible window rectangle (which IS affected by Windows' automatic DPI scaling features) + // Additionally, we have a user-controlled scale factor. + // If the user zooms in, we only render to a smaller part of the backbuffer and stretch it to the window rectangle (which may then again be stretched by Windows DPI if enabled in the Windows settings). + // the rectangle we render to has the same left/top border but a lower value for right/bottom. + // + // This is a simple scaling and also scales any text that has already been rendered to the backbuffer (which is why we're usually rendering text afterwards to the HighRes backbuffer). + // Altogether it'd probably be best to move from DirectDraw to Direct3D, support high DPI awareness and do the scaling right when initially drawing the map. + + + if (m_viewScale != Vec2<CSProjected, float>(1.0f, 1.0f) && lpdsBackHighRes) + { + // copy scene backbuffer to the high-res buffer that will receive text rendering + RECT dr; + GetWindowRect(&dr); + auto cr = GetScaledDisplayRect(); + lpdsBackHighRes->Blt(&dr, lpdsBack, &cr, DDBLT_WAIT, 0); + } + else + { + // do nothing, backbuffer will receive additional text rendering as text doesn't have to be scaled + } +} + +void CIsoView::FlipHighResBuffer() +{ + if (m_viewScale != Vec2<CSProjected, float>(1.0f, 1.0f) && lpdsBackHighRes) + { + // This flip copies the high-res backbuffer to the front buffer + RECT dr; + GetWindowRect(&dr); + lpds->Blt(&dr, lpdsBackHighRes, &dr, DDBLT_WAIT, 0); + } + else + { + // copy scene backbuffer to the front buffer that will receive text/gdi rendering + RECT dr; + GetWindowRect(&dr); + auto cr = GetScaledDisplayRect(); + lpds->Blt(&dr, lpdsBack, &cr, DDBLT_WAIT, 0); + } +} + +void CIsoView::ShowAllTileSets() +{ + int i; + for (i = 0;i < *tiledata_count;i++) + { + (*tiledata)[i].bHide = FALSE; + } +} + + + +void CIsoView::PlaceCurrentObjectAt(int x, int y) +{ + if (AD.mode == ACTIONMODE_RANDOMTERRAIN) + { + if (Map->GetTerrainAt(x + y * Map->GetIsoSize()) >= 0) + { + return; + } + + CString s; + + int n = rand() * rndterrainsrc.size() / RAND_MAX; + + // safety checks... + if (n >= rndterrainsrc.size()) n = rndterrainsrc.size() - 1; + if (n < 0) n = 0; + + s = rndterrainsrc[n]; + + Map->AddTerrain(s, x + y * Map->GetIsoSize()); + + return; + } + + if (AD.type == 1) // ADD INFANTRY + { + if (Map->GetInfantryCountAt(x + y * Map->GetIsoSize()) >= SUBPOS_COUNT) + { + return; + } + + Map->AddInfantry(NULL, AD.data_s, currentOwner, x + y * Map->GetIsoSize()); + //RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.type == 2) // add structure + { + int n = Map->GetStructureAt(x + y * Map->GetIsoSize()); + if (n >= 0) + { + STDOBJECTDATA sod; + Map->GetStdStructureData(n, &sod); + if (strcmp(sod.type, "GAPAVE") != NULL) + { + //isMoving=FALSE; + return; + } + } + + + Map->AddStructure(NULL, AD.data_s, currentOwner, x + y * Map->GetIsoSize()); + //RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.type == 3) // add aircraft + { + + if (Map->GetAirAt(x + y * Map->GetIsoSize()) >= 0) + { + return; + } + + Map->AddAircraft(NULL, AD.data_s, currentOwner, x + y * Map->GetIsoSize()); + + //RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.type == 4) // add vehicle + { + if (Map->GetUnitAt(x + y * Map->GetIsoSize()) >= 0) + { + return; + } + + Map->AddUnit(NULL, AD.data_s, currentOwner, x + y * Map->GetIsoSize()); + + //RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.type == 5) // add terrain + { + if (Map->GetTerrainAt(x + y * Map->GetIsoSize()) >= 0) + { + return; + } + + Map->AddTerrain(AD.data_s, x + y * Map->GetIsoSize()); + + //RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.type == 6) + { + // Overlay + + + + DWORD dwPos = x + y * Map->GetIsoSize(); + + FIELDDATA m = *Map->GetFielddataAt(dwPos); + if (m.wGround == 0xFFFF) m.wGround = 0; + + BYTE oldOverlay = Map->GetOverlayAt(dwPos); + BYTE oldOverlayData = Map->GetOverlayDataAt(dwPos); + + if (AD.data == 1) // delete overlay + { + int gx, gy; + for (gx = x - AD.data2;gx <= x + AD.data2;gx++) + { + for (gy = y - AD.data2;gy <= y + AD.data2;gy++) + { + Map->SetOverlayDataAt(gx + gy * Map->GetIsoSize(), 0xFF); + Map->SetOverlayAt(gx + gy * Map->GetIsoSize(), 0xFF); + + + HandleTrail(gx - 1, gy - 1); + HandleTrail(gx + 1, gy - 1); + HandleTrail(gx - 1, gy + 1); + HandleTrail(gx + 1, gy + 1); + HandleTrail(gx - 0, gy - 1); + HandleTrail(gx + 0, gy + 1); + HandleTrail(gx - 1, gy + 0); + HandleTrail(gx + 1, gy + 0); + } + } + + + } + else if (AD.data == 2) // green tiberium mode + { + + { + if (AD.data2 == 0) + { + int i, e; + for (i = 0;i < m_BrushSize_x;i++) + { + for (e = 0;e < m_BrushSize_y;e++) + { + int curground = Map->GetFielddataAt(dwPos + i + e * Map->GetIsoSize())->wGround; + if (curground == 0xFFFF) curground = 0; + + if ((*tiledata)[curground].bAllowTiberium) + { + //srand( GetTickCount()+i+e*5 ); + int v1 = ((float)rand() / (float)RAND_MAX) * 8.0f + 0x68; + int v2 = ((float)rand() / (float)RAND_MAX) * 8.0f + 1; + Map->SetOverlayAt(dwPos + i + e * Map->GetIsoSize(), v1); + Map->SetOverlayDataAt(dwPos + i + e * Map->GetIsoSize(), v2); + } + } + } + } + else if (AD.data2 == 10) + { + int i, e; + for (i = 0;i < m_BrushSize_x;i++) + { + for (e = 0;e < m_BrushSize_y;e++) + { + int curground = Map->GetFielddataAt(dwPos + i + e * Map->GetIsoSize())->wGround; + if (curground == 0xFFFF) curground = 0; + + if ((*tiledata)[curground].bAllowTiberium) + { + Map->SetOverlayAt(dwPos + i + e * Map->GetIsoSize(), 0x70); + Map->SetOverlayDataAt(dwPos + i + e * Map->GetIsoSize(), 0x5); + } + } + } + } + else if (AD.data2 == 20) + { + int i, e; + for (i = 0;i < m_BrushSize_x;i++) + { + for (e = 0;e < m_BrushSize_y;e++) + { + int ovrl = Map->GetOverlayAt(dwPos + i + e * Map->GetIsoSize()); + if (ovrl > 0x65 && ovrl < 0x72) + { + if (Map->GetOverlayDataAt(i + e * Map->GetIsoSize() + dwPos) < 9) Map->SetOverlayDataAt(dwPos + i + e * Map->GetIsoSize(), Map->GetOverlayDataAt(dwPos + i + e * Map->GetIsoSize()) + 1); + } + } + } + } + else if (AD.data2 == 21) + { + + int i, e; + for (i = 0;i < m_BrushSize_x;i++) + { + for (e = 0;e < m_BrushSize_y;e++) + { + int ovrl = Map->GetOverlayAt(dwPos + i + e * Map->GetIsoSize()); + if (ovrl > 0x65 && ovrl < 0x72) + { + if (Map->GetOverlayDataAt(dwPos + i + e * Map->GetIsoSize()) > 0) Map->SetOverlayDataAt(dwPos + i + e * Map->GetIsoSize(), Map->GetOverlayDataAt(dwPos + i + e * Map->GetIsoSize()) - 1); + } + } + } + } + } + + } + else if (AD.data == 3) // blue tiberium mode + { + int o = 0x7f; +#ifdef RA2_MODE + o = 0x1e; +#endif + //if((*tiledata)[m.wGround].bAllowTiberium) + { + if (AD.data2 == 0) + { + + int i, e; + for (i = 0;i < m_BrushSize_x;i++) + { + for (e = 0;e < m_BrushSize_y;e++) + { + int curground = Map->GetFielddataAt(dwPos + i + e * Map->GetIsoSize())->wGround; + if (curground == 0xFFFF) curground = 0; + + if ((*tiledata)[curground].bAllowTiberium) + { + + int v2 = ((float)rand() / (float)RAND_MAX) * 8 + 1; + Map->SetOverlayAt(dwPos + i + e * Map->GetIsoSize(), o); + Map->SetOverlayDataAt(dwPos + i + e * Map->GetIsoSize(), v2); + } + } + } + + } + else if (AD.data2 == 10) + { + int i, e; + for (i = 0;i < m_BrushSize_x;i++) + { + for (e = 0;e < m_BrushSize_y;e++) + { + int curground = Map->GetFielddataAt(dwPos + i + e * Map->GetIsoSize())->wGround; + if (curground == 0xFFFF) curground = 0; + + if ((*tiledata)[curground].bAllowTiberium) + { + Map->SetOverlayAt(dwPos + i + e * Map->GetIsoSize(), o); + Map->SetOverlayDataAt(dwPos + i + e * Map->GetIsoSize(), 0x5); + } + } + } + } + else if (AD.data2 == 20) + { + int i, e; + for (i = 0;i < m_BrushSize_x;i++) + { + for (e = 0;e < m_BrushSize_y;e++) + { + int ovrl = Map->GetOverlayAt(dwPos + i + e * Map->GetIsoSize()); + if (ovrl == o) + { + if (Map->GetOverlayDataAt(dwPos + i + e * Map->GetIsoSize()) < 9) Map->SetOverlayDataAt(dwPos + i + e * Map->GetIsoSize(), Map->GetOverlayDataAt(dwPos + i + e * Map->GetIsoSize()) + 1); + } + } + } + } + else if (AD.data2 == 21) + { + int i, e; + for (i = 0;i < m_BrushSize_x;i++) + { + for (e = 0;e < m_BrushSize_y;e++) + { + int ovrl = Map->GetOverlayAt(dwPos + i + e * Map->GetIsoSize()); + if (ovrl == o) + { + if (Map->GetOverlayDataAt(dwPos + i + e * Map->GetIsoSize()) > 0) Map->SetOverlayDataAt(dwPos + i + e * Map->GetIsoSize(), Map->GetOverlayDataAt(dwPos + i + e * Map->GetIsoSize()) - 1); + } + } + } + } + } + + } + else if (AD.data == 4) // veinhole stuff mode + { + if (AD.data2 == 0) // Set veinhole! + { + int gx, gy; + for (gx = x - 1;gx <= x + 1;gx++) + { + for (gy = y - 1;gy <= y + 1;gy++) + { + Map->SetOverlayAt(gx + gy * Map->GetIsoSize(), OVRL_VEINHOLEBORDER); + Map->SetOverlayDataAt(gx + gy * Map->GetIsoSize(), 0x0); + } + } + Map->SetOverlayAt(dwPos, OVRL_VEINHOLE); + Map->SetOverlayDataAt(dwPos, 0x0); + Map->SetHeightAt(dwPos, Map->GetHeightAt(dwPos) - 1); + } + else if (AD.data2 == 1) // set veins + { + Map->SetOverlayAt(dwPos, OVRL_VEINS); + Map->SetOverlayDataAt(dwPos, 0x30); + } + + } + else if (AD.data == 30) // any overlay + { + Map->SetOverlayAt(dwPos, AD.data2); + Map->SetOverlayDataAt(dwPos, 0); + int i; + for (i = 0;i < overlay_count;i++) + { + if (overlay_number[i] == AD.data2) + { + if (overlay_trail[i]) + { + // handle trail stuff! + HandleTrail(x, y); + } + } + } + } + else if (AD.data == 33) + { + int i, e; + for (i = 0;i < m_BrushSize_x;i++) + { + for (e = 0;e < m_BrushSize_y;e++) + { + Map->SetOverlayAt(dwPos + i + e * Map->GetIsoSize(), AD.data2); + Map->SetOverlayDataAt(dwPos + i + e * Map->GetIsoSize(), AD.data3); + } + } + } + + else if (AD.data == 31) + { + Map->SetOverlayAt(dwPos, AD.data2); + } + else if (AD.data == 32) + { + Map->SetOverlayDataAt(dwPos, AD.data2); + } + + // RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (AD.type == 7) + { + // set owner! + BOOL bchanged = FALSE; + + int t = Map->GetStructureAt(x + y * Map->GetIsoSize()); + if (t >= 0) + { + STRUCTURE structure; + Map->GetStructureData(t, &structure); + Map->DeleteStructure(t); + structure.house = AD.data_s; + Map->AddStructure(&structure); + bchanged = TRUE; + } + t = Map->GetUnitAt(x + y * Map->GetIsoSize()); + if (t >= 0) + { + UNIT unit; + Map->GetUnitData(t, &unit); + Map->DeleteUnit(t); + unit.house = AD.data_s; + Map->AddUnit(&unit); + bchanged = TRUE; + } + t = Map->GetAirAt(x + y * Map->GetIsoSize()); + if (t >= 0) + { + AIRCRAFT aircraft; + Map->GetAircraftData(t, &aircraft); + Map->DeleteAircraft(t); + aircraft.house = AD.data_s; + Map->AddAircraft(&aircraft); + bchanged = TRUE; + } + int z; + for (z = 0;z < SUBPOS_COUNT;z++) + { + t = Map->GetInfantryAt(x + y * Map->GetIsoSize(), z); + if (t >= 0) + { + INFANTRY infantry; + Map->GetInfantryData(t, &infantry); + Map->DeleteInfantry(t); + infantry.house = AD.data_s; + Map->AddInfantry(&infantry); + bchanged = TRUE; + } + } + + if (bchanged) + { + //RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW); + } + + + } +#ifdef SMUDGE_SUPP + else if (AD.type == 8) // add smudge + { + + if (Map->GetFielddataAt(x + y * Map->GetIsoSize())->smudge >= 0) + { + return; + } + + SMUDGE s; + s.type = AD.data_s; + s.x = x; + s.y = y; + s.deleted = 0; + Map->AddSmudge(&s); + + //RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } +#endif + +} + +void CIsoView::OnTimer(UINT nIDEvent) +{ + // theApp.m_loading->FreeAll(); + // theApp.m_loading->InitPics(); + + last_succeeded_operation = 1000000; + + + if (nIDEvent == 11) + { + // BUGSEARCH + //if(b_IsLoading) return; + // + m_viewOffset += ProjectedVec((cur_x_mouse - rclick_x) / 2, (cur_y_mouse - rclick_y) / 2); + + SetScroll(m_viewOffset.x, m_viewOffset.y); + + InvalidateRect(NULL, FALSE); + } + else + { + errstream << "Timer calls InitTMPs()" << endl; + errstream.flush(); + + theApp.m_loading->InitTMPs(); + + CView::OnTimer(nIDEvent); + + KillTimer(nIDEvent); + + b_IsLoading = FALSE; + RedrawWindow(); + } +} + +void CIsoView::FillArea(DWORD dwX, DWORD dwY, DWORD dwID, BYTE bSubTile) +{ + if ((*tiledata)[dwID].cx != 1 || (*tiledata)[dwID].cy != 1) + { + MessageBox("You can only use 1x1 tiles to fill areas."); + return; + } + + FIELDDATA* f = Map->GetFielddataAt(dwX + dwY * Map->GetIsoSize()); + f->bReserved = TRUE; + + int mapwidth, mapheight; + mapwidth = Map->GetWidth(); + mapheight = Map->GetHeight(); + + int i, e; + for (i = -1;i < 2;i++) + { + for (e = -1;e < 2;e++) + { + if (abs(i) == abs(e)) continue; + int cur_x, cur_y; + cur_x = dwX + i; + cur_y = dwY + e; + if (cur_x < 1 || cur_y < 1 || cur_x + cur_y<mapwidth + 1 || cur_x + cur_y>mapwidth + mapheight * 2 || (cur_y + 1 > mapwidth && cur_x - 1 < cur_y - mapwidth) || (cur_x + 1 > mapwidth && cur_y + mapwidth - 1 < cur_x)) continue; + + FIELDDATA* f2 = Map->GetFielddataAt(cur_x + cur_y * Map->GetIsoSize()); + + if (f2->bReserved) continue; + + + + if (f2->wGround != dwID && f2->wGround == f->wGround && f2->bSubTile == f->bSubTile) + { + FillArea(cur_x, cur_y, dwID, bSubTile); + } + + } + } + f->wGround = dwID; + f->bSubTile = bSubTile; +} + +void CIsoView::AutoLevel() +{ + Map->TakeSnapshot(); + + + + int mapsize = Map->GetIsoSize() * Map->GetIsoSize(); + int mapedge = Map->GetIsoSize(); + + if (mapsize == 0) return; + + BOOL* bChanged; + bChanged = new(BOOL[mapsize]); + memset(bChanged, 0, mapsize); + + int iCliffStart = -1; //, iSlopeSetStart = -1; + + int i; + + for (i = 0;i < *tiledata_count;i++) + { + if ((*tiledata)[i].wTileSet == cliffset) + { + iCliffStart = i; + break; + + } + } + + if (iCliffStart < 0) + return; + + /*for (i = 0;i<*tiledata_count;i++) + { + if((*tiledata)[i].wTileSet==slopesetpiecesset) + { + iSlopeSetStart=i; + break; + } + }*/ + + /*int count=atoi(g_data.sections["SlopeSetPiecesDirections"].values["Count"]); + BYTE* bXLeftSearch=new(BYTE[count]); + BYTE* bXRightSearch=new(BYTE[count]); + BYTE* bYTopSearch=new(BYTE[count]); + BYTE* bYBottomSearch=new(BYTE[count]); + + for(i=0;i<count;i++) + { + char c[50]; + itoa(i,c,10); + CString s=*g_data.sections["SlopeSetPiecesDirections"].GetValue(i); + if(s=="Right_1") { bXLeftSearch=0; bXRightSearch=1; b + else if(s=="Left_1") bDirections[i]=1; + else if(s=="Bottom_1") bDirections[i]=2; + else if(s=="Top_1") bDirections[i]=3; + else if(s=="Right_2") bDirections[i]=4; + else if(s=="Left_2") bDirections[i]=5; + else if(s=="Bottom_2") bDirections[i]=6; + else if(s=="Top_2") bDirections[i]=7; + }*/ + + for (i = 0;i < mapsize;i++) + { + FIELDDATA* f1 = Map->GetFielddataAt(i); + int o_ground = f1->wGround; + if (o_ground == 0xFFFF) o_ground = 0; + int o_width = (*tiledata)[o_ground].cx; + int o_height = (*tiledata)[o_ground].cy; + + int ox, oy; + ox = i % mapedge; + oy = i / mapedge; + + + int x, y; + for (x = -1;x < 2;x++) + { + for (y = -1;y < 2;y++) + { + if (x == -1 && y == -1) continue; + if (x == 1 && y == 1) continue; + if (x == 1 && y == -1) continue; + if (x == -1 && y == 1) continue; + + int count = 0; + int p, k; + int heights[32][32]; + memset(heights, 0, 32 * 32 * sizeof(int)); + + for (p = 0;p < o_width;p++) + { + for (k = 0;k < o_height;k++) + { + count++; + heights[p][k] = (*tiledata)[o_ground].tiles[p + k * o_width].bZHeight; + } + } + + + + if (o_ground < 8 + iCliffStart || o_ground>13 + iCliffStart) + { + if (count < 4 || count>4) + { + if (x < 0 || y < 0) continue; + } + + + + + if (heights[0][0] && !heights[1][1]) + { + if (heights[1][0] && heights[0][1]) + { + + if (x < 0 || y < 0) continue; + + } + } + + if (heights[0][0] && heights[1][1]) + { + if (x < 0 || y>0) continue; + } + + if (!heights[0][0] && heights[1][0] && heights[0][1] && heights[1][1]) + { + if (x < 0 || y < 0) continue; + } + } + else + { + if (x > 0 || y > 0) continue; + } + + if (x + ox > mapedge || x + ox<0 || y + oy>mapedge || y + oy < 0) + continue; + + FIELDDATA* cur_f = Map->GetFielddataAt(i + x + y * mapedge); + + int cur_ground = cur_f->wGround; + if (cur_ground == 0xFFFF) cur_ground = 0; + int cur_set; + if ((*tiledata)[cur_ground].wTileSet != (*tiledata)[o_ground].wTileSet) + { + + if (((*tiledata)[o_ground].wTileSet == cliffset || (*tiledata)[o_ground].wTileSet == slopesetpiecesset) && (*tiledata)[cur_ground].bMorphable) + { + int height_diff = f1->bHeight - cur_f->bHeight; + if (o_ground >= 8 + iCliffStart && o_ground <= 13 + iCliffStart && (*tiledata)[o_ground].tiles[cur_f->bSubTile].bZHeight == 0) height_diff += 4; + int need_diff = height_diff;//(*tiledata)[o_ground].tiles[f1->bSubTile].bZHeight-(*tiledata)[cur_ground].tiles[cur_f->bSubTile].bZHeight; + //if((*tiledata)[o_ground].tiles[f1->bSubTile].bZ + if (abs(height_diff) > 1) + { + //ChangeTileHeight(i+x+y*mapedge,f1->bHeight,FALSE, FALSE); + int height = f1->bHeight; + if (o_ground >= 8 + iCliffStart && o_ground <= 13 + iCliffStart && (*tiledata)[o_ground].tiles[cur_f->bSubTile].bZHeight == 0) height = f1->bHeight + 4; + Map->SetHeightAt(i + x + y * mapedge, height); + bChanged[i + x + y * mapedge] = TRUE; + } + else if (height_diff) + Map->CreateSlopesAt(i + x + y * mapedge); + //bChanged[i+x+y*mapedge]=TRUE; + } + } + } + } + } + + for (i = 0;i < mapsize;i++) + { + + if (bChanged[i]) + { + int e; + for (e = 0;e < Map->GetIsoSize() * Map->GetIsoSize();e++) + Map->SetReserved(e, 0); + ChangeTileHeight(i, Map->GetHeightAt(i), FALSE, FALSE); + } + + } + + /* delete[] bXSearch; + delete[] bYSearch;*/ + + if (bChanged) delete[] bChanged; + + RedrawWindow(); + + Map->TakeSnapshot(); + Map->Undo(); +} + +inline void ToIso3d_NoAccessCheck(int* x, int* y) +{ + int cx = *x, cy = *y; + + ToIso(&cx, &cy); + + int i, e = 0; + + + for (i = 15;i >= 0;i--) + { + for (e = 0;e < 3;e++) + { + int a; + + + int m, n; + int px, py; + m = cx + i; + n = cy + i; + + if (e == 1) m -= 1; + if (e == 2) n -= 1; + + px = m; + py = n; + + if (m >= 0 && n >= 0 && m < Map->GetIsoSize() && n < Map->GetIsoSize()) + { + FIELDDATA mfd = *Map->GetFielddataAt(px + py * Map->GetIsoSize()); + int ground = mfd.wGround; + if (ground == 0xFFFF) ground = 0; + //if(mfd.bHide==FALSE && !(*tiledata)[ground].bHide) + { + + ToPhys3d(&m, &n); + + // now m and n hold the pixel coordinates for the current field... + // we now need to check if cx and cy are in this field + //if(*x >= m && *x<= m+f_x && *y>=n && *y<=n+f_y) + { + int dx = *x - m; + int dy = *y - n - f_y / 2;//-f_y/2; + int dx1 = dx; + int dy1 = dy; + + dx = ((float)dy1) / ((float)f_y) - ((float)dx1) / ((float)f_x) + 1.0f;//+ 1 + (float)0.5 +1; + dy = ((float)dx1) / ((float)f_x) + ((float)dy1) / ((float)f_y) + 0.0f;//- 1-(float)0.5 +1; + + if (((dx == 0 && dy == 0) || (!bAllowAccessBehindCliffs && *y - n > f_y))) + { + *x = px - 0; + *y = py + 0; + return; + } + } + } + } + } + } + + /* +for(i=15;i>=0;i--) + { + for(e=0;e<3;e++) + { + int a; + + + int m,n; + int px,py; + m=cx+i; + n=cy+i; + + if(e==1) m-=1; + if(e==2) n-=1; + + px=m; + py=n; + + if(m>=0 && n>=0 && m< Map->GetIsoSize() && n<Map->GetIsoSize()) + { + + ToPhys3d(&m, &n); + + // just find at least one tile if possible... + + if(*x>m && *y>n) + { + *x=px; + *y=py; + return; + } + } + } + }*/ + + + *x = cx;//-1; + *y = cy;//-1; +} + + + +void CIsoView::DrawMap() +{ + const CMapData* const Map = ::Map; + + if (bNoDraw) return; + + if (bCancelDraw) + { + bCancelDraw = FALSE; + return; + } + + last_succeeded_operation = 100; + + if (lpds == NULL || b_IsLoading || tiledata == NULL || (*tiledata) == NULL || (*tiledata_count == 0)) return; // just to make sure... + + if (lpds->IsLost() != DD_OK) + { + // we lost our surfaces, we need to reinitialize directdraw and all associated objects + ReInitializeDDraw(); + return; + } + + + + if (Map->GetIsoSize() == 0) return; + + auto startTime = std::chrono::steady_clock::now(); + + // draw a white background + DDBLTFX fx; + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize = sizeof(DDBLTFX); + fx.dwFillColor = RGB(255, 255, 255); + lpdsBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &fx); + + + // get the window rect + + RECT r = GetScaledDisplayRect(); + + // the code here draws the coordinate system + int i; + + + // now, we draw all the objects + + + int left, right, top, bottom; + + { + RECT cr; + GetClientRect(&cr); + auto topLeft = GetMapCoordinatesFromClientCoordinates(CPoint(0, 0), false, true); + auto topRight = GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, 0), false, true); + auto bottomLeft = GetMapCoordinatesFromClientCoordinates(CPoint(0, cr.bottom), false, true); + auto bottomRight = GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, cr.bottom), false, true); + left = min(topLeft.x, topRight.x); + top = min(topLeft.y, topRight.y); + right = max(bottomLeft.x, bottomRight.x); + bottom = max(bottomLeft.y, bottomRight.y); + } + + // some large buildings may be out of reach: + left -= 2; + top -= 2; + right += 7; + bottom += 7; + + + + // validate the coordinates + if (left < 0) left = 0; + if (bottom >= Map->GetIsoSize() || bottom < top) bottom = Map->GetIsoSize(); + if (right >= Map->GetIsoSize() || right < left) right = Map->GetIsoSize(); + if (top < 0) top = 0; + + + BOOL bMarbleHeight = TRUE; + //if(Map->GetTheater()==THEATER4 || Map->GetTheater()==THEATER3) bMarbleHeight=FALSE; + + // Now left, right, top & bottom contain the needed values + + DWORD MM_heightstart = tilesets_start[atoi((*tiles).sections["General"].values["HeightBase"])]; + + // now draw everything + int u, v, z; + int mapwidth, mapheight; + mapwidth = Map->GetWidth(); + mapheight = Map->GetHeight(); + + DDSURFACEDESC2 ddsd; + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + + lpdsBack->GetSurfaceDesc(&ddsd); + + +#ifdef NOSURFACES + lpdsBack->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL); +#endif + + // we render texts and waypoints last as they should be always visible anyway and because text rendering is currently done using GDI -> getting a DC for every text is too slow nowadays + m_texts_to_render.clear(); + m_waypoints_to_render.clear(); + + for (u = left;u < right;u++) + { + for (v = top;v < bottom;v++) + { + const MapCoords mapCoords(u, v); + if (bCancelDraw) + { + bCancelDraw = FALSE; + } + + if (u < 1 || v < 1 || u + v<mapwidth + 1 || u + v>mapwidth + mapheight * 2 || (v + 1 > mapwidth && u - 1 < v - mapwidth) || (u + 1 > mapwidth && v + mapwidth - 1 < u)) + continue; + + + FIELDDATA m = *Map->GetFielddataAt(mapCoords); + const auto drawCoords = GetRenderTargetCoordinates(mapCoords); + + // draw terrain + if (m.wGround >= (*tiledata_count)) + m.wGround = 0; + + DWORD dwOrigGround = m.wGround; + + if (theApp.m_Options.bMarbleMadness) + { + if ((*tiledata)[m.wGround].wMarbleGround != 0xFFFF) + { + + m.wGround = (*tiledata)[m.wGround].wMarbleGround; + } + else if (bMarbleHeight) + { + //drawy+=f_y*m.bHeight; + + m.wGround = MM_heightstart + m.bHeight; + m.bSubTile = 0; + } + } + + if (!m.bRedrawTerrain) + { + + TILEDATA* td = &(*tiledata)[m.wGround]; + if (td->bReplacementCount) + { + if (m.bRNDImage > 0) + { + m.bRNDImage <= td->bReplacementCount ? td = &td->lpReplacements[m.bRNDImage - 1] : td = &td->lpReplacements[td->bReplacementCount - 1]; + } + } + + if (m.bSubTile < td->wTileCount && td->tiles[m.bSubTile].pic != NULL) + { + const SUBTILE& st = td->tiles[m.bSubTile]; + const auto stDrawCoords = drawCoords + st.drawOffset(); + + + if (!m.bHide && (*tiledata)[dwOrigGround].bHide == FALSE) + { +#ifndef NOSURFACES + Blit(st.pic, stDrawCoords.x, stDrawCoords.y, st.wWidth, st.wHeight); +#else + BlitTerrain(ddsd.lpSurface, stDrawCoords.x, stDrawCoords.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, st); +#endif + } + else // draw soemthing representing the tile + { +#ifndef NOSURFACES + DrawCell(stDrawCoords.x, stDrawCoords.y, 1, 1, RGB(0, 140, 0), FALSE, FALSE); +#else + BlitTerrainHalfTransp(ddsd.lpSurface, stDrawCoords.x, stDrawCoords.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, st); +#endif + + } + } + + } + + } + } + + + for (u = left;u < right;u++) + { + for (v = top;v < bottom;v++) + { + const MapCoords mapCoords(u, v); + if (bCancelDraw) + { + bCancelDraw = FALSE; + } + + if (u < 1 || v < 1 || u + v<mapwidth + 1 || u + v>mapwidth + mapheight * 2 || (v + 1 > mapwidth && u - 1 < v - mapwidth) || (u + 1 > mapwidth && v + mapwidth - 1 < u)) + continue; + + FIELDDATA m = *Map->GetFielddataAt(mapCoords); // copy + const auto drawCoords = GetRenderTargetCoordinates(mapCoords); + + if (m.wGround == 0xFFFF) + m.wGround = 0; + + DWORD dwOrigGround = m.wGround; + + if (theApp.m_Options.bMarbleMadness) + { + if ((*tiledata)[m.wGround].wMarbleGround != 0xFFFF) + { + m.wGround = (*tiledata)[m.wGround].wMarbleGround; + } + else if (bMarbleHeight) + { + //y+=f_y*m.bHeight; + m.wGround = MM_heightstart + m.bHeight; + m.bSubTile = 0; + } + } + + if (m.bRedrawTerrain) + { + // draw cliff again to hide buildings behind + + if (m.wGround < *tiledata_count) + { + TILEDATA* td = &(*tiledata)[m.wGround]; + if (td->bReplacementCount) + { + if (m.bRNDImage > 0) + { + m.bRNDImage <= td->bReplacementCount ? td = &td->lpReplacements[m.bRNDImage - 1] : td = &td->lpReplacements[td->bReplacementCount - 1]; + } + } + + if (m.bSubTile < td->wTileCount && td->tiles[m.bSubTile].pic != NULL) + { + const SUBTILE& st = td->tiles[m.bSubTile]; + const auto stDrawCoords = drawCoords + st.drawOffset(); + + + if (!m.bHide && (*tiledata)[dwOrigGround].bHide == FALSE) + { +#ifndef NOSURFACES + Blit(st.pic, stDrawCoords.x, stDrawCoords.y, st.wWidth, st.wHeight); +#else + BlitTerrain(ddsd.lpSurface, stDrawCoords.x, stDrawCoords.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, st); + if (st.anim) + { + const auto animDrawCoords = drawCoords + ProjectedVec(f_x / 2 - st.anim->wMaxWidth / 2, f_y / 2 - st.anim->wMaxHeight / 2) + st.anim->drawOffset(); + BlitPic(ddsd.lpSurface, animDrawCoords.x, animDrawCoords.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, *st.anim); + } +#endif + + } + else // draw soemthing representing the tile + { +#ifndef NOSURFACES + DrawCell(stDrawCoords.x, stDrawCoords.y, 1, 1, RGB(0, 140, 0), FALSE, FALSE); +#else + BlitTerrainHalfTransp(ddsd.lpSurface, stDrawCoords.x, stDrawCoords.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, st); +#endif + + } + } + + } + } + + // draw terrain animation (tunnel tops, waterfalls) + // tunnel tops might be repainted later so that units do not appear on top - this probably could be done in CLoading so that instead of a back tile a front tile is responsible for drawing the animation + { + if (m.wGround < *tiledata_count) + { + TILEDATA* td = &(*tiledata)[m.wGround]; + + if (m.bSubTile < td->wTileCount) + { + const SUBTILE& st = td->tiles[m.bSubTile]; + + if (!m.bHide && (*tiledata)[dwOrigGround].bHide == FALSE && st.anim) + { +#ifndef NOSURFACES +#else + const auto animDrawCoords = drawCoords + ProjectedVec(f_x / 2 - st.anim->wMaxWidth / 2, f_y / 2 - st.anim->wMaxHeight / 2) + st.anim->drawOffset(); + BlitPic(ddsd.lpSurface, animDrawCoords.x, animDrawCoords.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, *st.anim); +#endif + } + + } + } + } + + // draw overlay + if (m.overlay != 0xFF) + { + PICDATA pic; + pic.pic = NULL; + + if (ovrlpics[m.overlay][m.overlaydata] != NULL) + { + pic = *ovrlpics[m.overlay][m.overlaydata]; + } + + + if (pic.pic == NULL) + { + if (!pic.bTried) + { + SetError("Loading graphics"); + theApp.m_loading->LoadOverlayGraphic(*rules.sections["OverlayTypes"].GetValue(m.overlay), m.overlay); + UpdateOverlayPictures(m.overlay); + if (ovrlpics[m.overlay][m.overlaydata] != NULL) + pic = *ovrlpics[m.overlay][m.overlaydata]; + } + + if (pic.pic == NULL) + { + if (!(m.overlay >= 0x4a && m.overlay <= 0x65) && !(m.overlay >= 0xcd && m.overlay <= 0xec)) + { + char cd[50]; + cd[0] = '0'; + cd[1] = 'x'; + itoa(m.overlay, cd + 2, 16); + + m_texts_to_render.push_back({ cd, drawCoords.x + f_x / 2, drawCoords.y + f_y / 2, RGB(0,0,0), false, true, true}); + // TextOut(drawx,drawy, cd, RGB(0,0,0)); + } + } + } + + if (pic.pic != NULL) + { + ProjectedVec offset(f_x / 2 - pic.wMaxWidth / 2, -pic.wMaxHeight / 2); + + if (m.overlay == OVRL_VEINHOLE) // veinhole, big, special case + { + offset.y -= f_y * 3 / 2; + } + else if (isBigBridge(m.overlay)) // bridge special case + { + // drawy-=f_y; + if (m.overlaydata >= 0x09 && m.overlaydata <= 0x11) + { + offset.y -= f_y / 2; + } + + offset.x -= 1; // hmm... strange, but this is needed + + } + else if (isTrack(m.overlay)) + offset.y += f_y / 2; + + if (m.overlay >= 0x4a && m.overlay <= 0x65) offset.y += f_y / 2; + if (m.overlay >= 0xcd && m.overlay <= 0xec) offset.y += f_y / 2; + + + const auto drawCoordsOvrl = drawCoords + offset; + +#ifndef NOSURFACES + Blit(pic.pic, drawCoordsOvrl.x, drawCoordsOvrl.y); +#else + +#ifdef RA2_MODE + BlitPic(ddsd.lpSurface, drawCoordsOvrl.x, drawCoordsOvrl.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, pic); +#endif +#ifdef TS_MODE + if (!isGreenTiberium(m.overlay) && !(m.overlay == 0x7f)) // no tib + BlitPic(ddsd.lpSurface, drawCoordsOvrl.x, drawCoordsOvrl.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, pic); + else if (m.overlay == 0x7f) // blue tib + { + int n = RGB(200, 0, 0); + BlitPic(ddsd.lpSurface, drawCoordsOvrl.x, drawCoordsOvrl.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, pic, &n); + } + else + { + int n = RGB(0, 200, 0); + BlitPic(ddsd.lpSurface, drawCoordsOvrl.x, drawCoordsOvrl.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, pic, &n); + } +#endif + +#endif + + } + } + + if (m.structure != -1) + { + last_succeeded_operation = 10101; + + // for structures we need to check if they weren´t drawn earlier + // (every field that this building achieves has this building as .structure) + if (Map->GetStructureAt(mapCoords - MapVec(-1, 0)) != m.structure && Map->GetStructureAt(mapCoords - MapVec(0, -1)) != m.structure) + { + + STRUCTUREPAINT objp; + Map->GetStructurePaint(m.structure, &objp); + + const auto drawCoordsBld = GetRenderTargetCoordinates(MapCoords(objp.x, objp.y)); + int id = m.structuretype; + + + int w = 1, h = 1; + PICDATA pic; + if (id > -1 && id < 0x0F00) + { + w = buildinginfo[id].w; + h = buildinginfo[id].h; + int dir = objp.direction / 32; + + // MW April 13th 2001: fix for building direction + dir = (7 - dir) % 8; + + pic = buildinginfo[id].pic[dir]; + if (pic.pic == NULL) pic = buildinginfo[id].pic[0]; + + } + +#ifndef NOSURFACES + DrawCell(drawCoordsBld.x, drawCoordsBld.y, w, h, colorref_conv[objp.col]); +#else + // MW 07/19/01: Paint cell if user chose so... + if (theApp.m_Options.bShowCells) + { + DrawCell(ddsd.lpSurface, ddsd.dwWidth, ddsd.dwHeight, ddsd.lPitch, drawCoordsBld.x, drawCoordsBld.y, w, h, colorref_conv[objp.col]); + } +#endif + + + if (pic.pic == NULL) + { + if (!missingimages[objp.type]) + { + SetError("Loading graphics"); + theApp.m_loading->LoadUnitGraphic(objp.type); + ::Map->UpdateBuildingInfo(objp.type); + int dir = (7 - objp.direction / 32) % 8; + pic = buildinginfo[id].pic[dir]; + if (pic.pic == NULL) pic = buildinginfo[id].pic[0]; + } + if (pic.pic == NULL) + { +#ifndef NOSURFACES + Blit(pics["HOUSE"].pic, drawCoordsBld.x, drawCoordsBld.y - 19); // draw a ugly house +#endif + missingimages[objp.type] = TRUE; + } + } + + if (pic.pic) // picture + { + + // it was that easy! just center on top end!!! + const auto drawCoordsBldShp = drawCoordsBld + ProjectedVec(f_x / 2 - pic.wMaxWidth / 2, -pic.wMaxHeight / 2); + +#ifndef NOSURFACES + Blit(pic.pic, drawCoordsBldShp.x, drawCoordsBldShp.y, pic.wMaxWidth, pic.wMaxHeight); +#else + + BlitPic(ddsd.lpSurface, drawCoordsBldShp.x, drawCoordsBldShp.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, pic, &colorref_conv[objp.col]); +#endif + + for (int upgrade = 0; upgrade < objp.upradecount; ++upgrade) + { + const auto& upg = upgrade == 0 ? objp.upgrade1 : (upgrade == 1 ? objp.upgrade2 : objp.upgrade3); + if (upg.GetLength() == 0) + continue; + + PICDATA pic; + int dir = (7 - objp.direction / 32) % 8; + pic = pics[GetUnitPictureFilename(upg, dir)]; + if (!missingimages[upg] && pic.pic == NULL) + { + SetError("Loading graphics"); + theApp.m_loading->LoadUnitGraphic(upg); + ::Map->UpdateBuildingInfo(upg); + pic = pics[GetUnitPictureFilename(upg, dir)]; + if (pic.pic == NULL) missingimages[upg] = TRUE; + } + + if (pic.pic != NULL) + { + static const CString LocLookup[3][2] = { {"PowerUp1LocXX", "PowerUp1LocYY"}, {"PowerUp2LocXX", "PowerUp2LocYY"}, {"PowerUp3LocXX", "PowerUp3LocYY"} }; + const auto drawCoordsPowerUp = drawCoordsBldShp + ProjectedVec( + atoi(art.sections[objp.type].values[LocLookup[upgrade][0]]), + atoi(art.sections[objp.type].values[LocLookup[upgrade][1]]) + ); + // py-=atoi(art.sections[obj.type].values["PowerUp1LocZZ"]); +#ifndef NOSURFACES + Blit(pic.pic, drawCoordsPowerUp.x, drawCoordsPowerUp.y); +#else + BlitPic(ddsd.lpSurface, drawCoordsPowerUp.x, drawCoordsPowerUp.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, pic, &colorref_conv[objp.col]); +#endif + + } + + } + + } + } + + } + + + if (m.node.type > -1) + { + last_succeeded_operation = 10102; + + CString house = m.node.house; + CString tmp; + + if (Map->GetNodeAt(mapCoords + MapVec(1, 0), tmp) != m.node.index && Map->GetNodeAt(mapCoords + MapVec(0, 1), tmp) != m.node.index) + { + const auto drawCoordsBld = GetRenderTargetCoordinates(mapCoords - MapVec(buildinginfo[m.node.type].h - 1, buildinginfo[m.node.type].w - 1)); + + COLORREF c; + c = GetColor(house); + + + int id = m.node.type; + int w = 1, h = 1; + PICDATA pic; + if (id > -1 && id < 0x0F00) + { + w = buildinginfo[id].w; + h = buildinginfo[id].h; + pic = buildinginfo[id].pic[0]; + } + + + //#ifndef NOSURFACES +#ifdef NOSURFACES + if (m.structure >= 0) // only paint cell if we have a structure preplaced, as we have a half transparent image + { +#endif + // place it 2 pixels lower so that user can see the dotted lines even if the building itself has the cells drawn + DrawCell(ddsd.lpSurface, ddsd.dwWidth, ddsd.dwHeight, ddsd.lPitch, drawCoordsBld.x, drawCoordsBld.y + 3, w, h, colorref_conv[c], true); + +#ifdef NOSURFACES + } +#endif + //#endif + + if (pic.pic == NULL) + { + if (!missingimages[*rules.sections["BuildingTypes"].GetValue(m.node.type)]) + { + SetError("Loading graphics"); + theApp.m_loading->LoadUnitGraphic(*rules.sections["BuildingTypes"].GetValue(m.node.type)); + ::Map->UpdateBuildingInfo(*rules.sections["BuildingTypes"].GetValue(m.node.type)); + pic = buildinginfo[id].pic[0]; + } + if (pic.pic == NULL); + { +#ifndef NOSURFACES + Blit(pics["HOUSE"].pic, drawCoordsBld.x, drawCoordsBld.y - 19); +#endif + missingimages[*rules.sections["BuildingTypes"].GetValue(m.node.type)] = TRUE; + } + } + + + if (pic.pic) // picture + { + const auto drawCoordsBldShp = drawCoordsBld + ProjectedVec(f_x / 2 - pic.wMaxWidth / 2, -pic.wMaxHeight / 2); + +#ifndef NOSURFACES + Blit(pic.pic, drawCoordsBldShp.x, drawCoordsBldShp.y); +#else + BlitPicHalfTransp(ddsd.lpSurface, drawCoordsBldShp.x, drawCoordsBldShp.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, pic, &colorref_conv[c]); +#endif + } + } + + } + if (m.unit != -1) + { + + UNIT obj; + Map->GetUnitData(m.unit, &obj); + + COLORREF c = GetColor(obj.house); + + + CString lpPicFile = GetUnitPictureFilename(obj.type, atoi(obj.direction) / 32); + +#ifndef NOSURFACES + DrawCell(drawCoords.x, drawCoords.y, 1, 1, c); +#endif + + PICDATA p = pics[lpPicFile]; + + if (p.pic == NULL || lpPicFile.GetLength() == 0) + { + if (!missingimages[obj.type]) + { + SetError("Loading graphics"); + theApp.m_loading->LoadUnitGraphic(obj.type); + lpPicFile = GetUnitPictureFilename(obj.type, atoi(obj.direction) / 32); + p = pics[lpPicFile]; + } + + if (p.pic == NULL) + { +#ifndef NOSURFACES + Blit(pics["TANK"].pic, drawCoords.x, drawCoords.y); + // TextOut(drawx+f_x/4,drawy+f_y/4, obj.type,c); + m_texts_to_render.push_back({ obj.type, drawCoords.x + f_x / 4, drawCoords.y + f_y / 4, m_color_converter->GetColor(c)}); +#endif + missingimages[obj.type] = TRUE; + } + } + + if (p.pic)// we have a picture! + { + const auto drawCoordsOffset = (p.bType == PICDATA_TYPE_BMP) ? ProjectedVec((f_y / 4) + p.x, (f_y - p.wHeight) + p.y) - p.drawOffset() : + (p.bType == PICDATA_TYPE_SHP) ? ProjectedVec(f_x / 2 - (p.wMaxWidth / 2), f_y / 2 - (p.wMaxHeight / 2)) : ProjectedVec(f_x / 2, f_y / 2) + p.drawOffset(); + auto drawCoordsUnit = drawCoords + drawCoordsOffset; + +#ifndef NOSURFACES + Blit(p.pic, drawCoordsUnit.x, drawCoordsUnit.y); +#else + BlitPic(ddsd.lpSurface, drawCoordsUnit.x, drawCoordsUnit.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, p, &colorref_conv[c]); +#endif + } + } + if (m.aircraft != -1) + { + last_succeeded_operation = 10102; + + AIRCRAFT obj; + Map->GetAircraftData(m.aircraft, &obj); + + COLORREF c = GetColor(obj.house); + + + CString lpPicFile = GetUnitPictureFilename(obj.type, atoi(obj.direction) / 32); + +#ifndef NOSURFACES + DrawCell(drawCoords.x, drawCoords.y, 1, 1, c); +#endif + + PICDATA p = pics[lpPicFile]; + + if (p.pic == NULL) + { + if (!missingimages[obj.type]) + { + SetError("Loading graphics"); + theApp.m_loading->LoadUnitGraphic(obj.type); + p = pics[lpPicFile]; + } + + if (p.pic == NULL) + { +#ifndef NOSURFACES + Blit(pics["TANK"].pic, drawCoords.x, drawCoords.y); + //TextOut(drawx+f_x/4,drawy+f_y/4, obj.type,c); + m_texts_to_render.push_back({ obj.type, drawCoords.x + f_x / 4, drawCoords.y + f_y / 4, m_color_converter->GetColor(c) }); +#endif + missingimages[obj.type] = TRUE; + } + } + + if (p.pic)// we have a picture! + { + const auto drawCoordsOffset = (p.bType == PICDATA_TYPE_BMP) ? ProjectedVec(f_x / 2 - p.wWidth / 2, f_y - p.wHeight) - p.drawOffset() : + (p.bType == PICDATA_TYPE_SHP) ? ProjectedVec(f_x / 2 - (p.wMaxWidth / 2), f_y / 2 - (p.wMaxHeight / 2)) : ProjectedVec(f_x / 2, f_y / 2) + p.drawOffset(); + auto drawCoordsAir = drawCoords + drawCoordsOffset; + +#ifndef NOSURFACES + Blit(p.pic, drawCoordsAir.x, drawCoordsAir.y); +#else + BlitPic(ddsd.lpSurface, drawCoordsAir.x, drawCoordsAir.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, p, &colorref_conv[c]); +#endif + } + } + int ic; + for (ic = 0;ic < SUBPOS_COUNT;ic++) + if (m.infantry[ic] != -1) + { + last_succeeded_operation = 10103; + + //errstream << "GetInfantryData()" << endl; + //errstream.flush(); + + INFANTRY obj; + Map->GetInfantryData(m.infantry[ic], &obj); + + //errstream << "Done " << (LPCSTR)obj.type << endl; + //errstream.flush(); + + + COLORREF c = GetColor(obj.house); + + + int dir = (7 - atoi(obj.direction) / 32) % 8; + CString lpPicFile = GetUnitPictureFilename(obj.type, dir); + +#ifndef NOSURFACES + DrawCell(drawCoords.x, drawCoords.y, 1, 1, c); +#endif + + static const ProjectedVec subPosLookup[5] = { ProjectedVec(0, -f_y / 4), ProjectedVec(f_x / 4 , 0), ProjectedVec(-f_x / 4, 0), ProjectedVec(0, f_y / 4), ProjectedVec()}; + auto drawCoordsInf = drawCoords + subPosLookup[ic > 4 ? 4 : ic]; + + PICDATA p = pics[lpPicFile]; + + if (p.pic == NULL) + { + if (!missingimages[obj.type]) + { + SetError("Loading graphics"); + theApp.m_loading->LoadUnitGraphic(obj.type); + p = pics[lpPicFile]; + } + + if (p.pic == NULL) + { +#ifndef NOSURFACES + Blit(pics["MAN"].pic, drawCoordsInf.x, drawCoordsInf.y); + // TextOut(drawx+f_x/4,drawy+f_y/4, obj.type,c); + m_texts_to_render.push_back({ obj.type, drawCoordsInf.x + f_x / 4, drawCoordsInf.y + f_y / 4, RGB(0,0,0) }); +#endif + missingimages[obj.type] = TRUE; + } + } + + + + if (p.pic)// we have a picture! + { + auto drawCoordsInfShp = drawCoordsInf + ProjectedVec(f_x / 2 - (p.wMaxWidth / 2), f_y / 2 - (p.wMaxHeight / 2)); + +#ifndef NOSURFACES + Blit(p.pic, drawCoordsInfShp.x, drawCoordsInfShp.y, p.wWidth, p.wHeight); +#else + BlitPic(ddsd.lpSurface, drawCoordsInfShp.x, drawCoordsInfShp.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, p, &colorref_conv[c]); +#endif + + } + + } + if (m.terrain != -1) + { + last_succeeded_operation = 10104; + + + int id = m.terraintype; + int w = 1, h = 1; + PICDATA pic; + if (id > -1 && id < 0x0F00) + { + w = treeinfo[id].w; + h = treeinfo[id].h; + pic = treeinfo[id].pic; + } + + //CString lpPicFile=GetUnitPictureFilename(type, 0); + + if (pic.pic == NULL) + { + CString type; + Map->GetTerrainData(m.terrain, &type); + + if (missingimages.find(type) == missingimages.end()) + { + SetError("Loading graphics"); + theApp.m_loading->LoadUnitGraphic(type); + ::Map->UpdateTreeInfo(type); + pic = treeinfo[id].pic; + } + if (pic.pic == NULL) + { +#ifndef NOSURFACES + Blit(pics["TREE"].pic, drawCoords.x, drawCoords.y - 19); +#endif + missingimages[type] = TRUE; + } + } + + if (pic.pic); + { + + auto drawCoordsTerrain = drawCoords + ProjectedVec(f_x / 2 - (pic.wMaxWidth / 2), f_y / 2 - 3 - (pic.wMaxHeight / 2)); + +#ifndef NOSURFACES + Blit(pic.pic, drawCoordsTerrain.x, drawCoordsTerrain.y); +#else + BlitPic(ddsd.lpSurface, drawCoordsTerrain.x, drawCoordsTerrain.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, pic); + +#endif + + + } + + } + + +#ifdef SMUDGE_SUPP + if (m.smudge != -1) + { + last_succeeded_operation = 10104; + + + int id = m.smudgetype; + + PICDATA pic; + if (id > -1 && id < 0x0F00) + { + pic = smudgeinfo[id].pic; + } + + if (pic.pic == NULL) + { + SMUDGE data; + CString& type = data.type; + Map->GetSmudgeData(m.smudge, &data); + + if (missingimages.find(type) == missingimages.end()) + { + SetError("Loading graphics"); + theApp.m_loading->LoadUnitGraphic(type); + ::Map->UpdateSmudgeInfo(type); + pic = smudgeinfo[id].pic; + } + if (pic.pic == NULL) + { +#ifndef NOSURFACES + // Blit(pics["TREE"].pic,drawCoords.x,drawCoords.y-19); +#endif + missingimages[type] = TRUE; + } + } + + if (pic.pic) + { + auto drawCoordsSmudge = drawCoords + ProjectedVec(f_x / 2 - (pic.wMaxWidth / 2), /*f_y / 2 - 3*/ - (pic.wMaxHeight / 2)); + +#ifndef NOSURFACES + Blit(pic.pic, drawCoordsSmudge.x, drawCoordsSmudge.y); +#else + BlitPic(ddsd.lpSurface, drawCoordsSmudge.x, drawCoordsSmudge.y, r.left, r.top, ddsd.lPitch, r.right, r.bottom, pic); + +#endif + + + } + + } +#endif + + + if (m.celltag != -1) + { + +#ifdef NOSURFACES + lpdsBack->Unlock(NULL); +#endif + Blit((LPDIRECTDRAWSURFACE4)pics["CELLTAG"].pic, drawCoords.x - 1, drawCoords.y - 1); + +#ifdef NOSURFACES + lpdsBack->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL); +#endif + } + + if (m.waypoint != -1) + { + + DWORD dwPos; + CString ID; + Map->GetWaypointData(m.waypoint, &ID, &dwPos); + + +#ifdef NOSURFACES + lpdsBack->Unlock(NULL); +#endif + + // move the graphic and text into place +#ifdef RA2_MODE + int image_fudge_x = 4; + int image_fudge_y = -20; + int text_fudge_x = 12; + int text_fudge_y = -24; +#else + int image_fudge_x = 4; + int image_fudge_y = -15; + int text_fudge_x = 9; + int text_fudge_y = -17; +#endif + + const ProjectedVec waypointImageOffset(image_fudge_x, image_fudge_y); + const ProjectedVec waypointTextOffset((f_x / 2) + text_fudge_x, (f_y / 2) + text_fudge_y); +#ifdef RA2_MODE + bool useFont9 = false; +#else + bool useFont9 = true; +#endif + const auto waypointImageCoords = ProjectedCoords({ drawCoords.x, drawCoords.y }) + waypointImageOffset; + const auto waypointTextCoords = ProjectedCoords({ drawCoords.x, drawCoords.y }) + waypointTextOffset; + m_waypoints_to_render.push_back({ waypointImageCoords.x, waypointImageCoords.y }); + m_texts_to_render.push_back({ ID.GetString(), waypointTextCoords.x, waypointTextCoords.y, RGB(0,0,255), false, useFont9, true}); +#ifdef NOSURFACES + lpdsBack->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL); +#endif + } + + } + + } + + for (const auto& tube : Map->GetTubes()) + { + DrawTube(*tube, &ddsd); + } + +#ifdef NOSURFACES + lpdsBack->Unlock(NULL); +#endif + + // delayed waypoint rendering + for (const auto& wp : m_waypoints_to_render) + { + Blit((LPDIRECTDRAWSURFACE4)pics["FLAG"].pic, wp.drawx, wp.drawy); + } + + // map tool rendering + if (AD.mode == ACTIONMODE_MAPTOOL) + { + if (AD.tool) + AD.tool->render(); + } + + lpdsTemp->Blt(NULL, lpdsBack, NULL, 0, 0); // lpdsTemp always holds the scene drawn above, unscaled to the window + + if (m_cellCursor != MapCoords(-1, -1)) + { + SurfaceLocker locker(lpdsBack); + auto desc = locker.ensure_locked(); + if (desc) + DrawCellCursor(m_cellCursor, *desc); + } + + auto renderDuration = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - startTime); // not including text output, ReleaseDC, waitForVerticalBlank etc below + + if (bDrawStats) + { + if (theApp.m_Options.bShowStats) + { + auto systemStats = std::format("ms: {0} Left: {1} Top: {2} Right: {3} Bottom: {4}", renderDuration.count(), left, top, right, bottom); + m_texts_to_render.push_back({ systemStats.c_str(), r.left + 10, r.top + 10 + (-m_fontDefaultHeight) * 3 / 2, RGB(0,0,0), true }); + } + + auto moneyStr = std::format("Credits on map: {0}", Map->GetMoneyOnMap()); + m_texts_to_render.push_back({ moneyStr.c_str(), r.left + 10, r.top + 10, RGB(0,0,0), true }); + } + + if (rscroll) + { + const auto& sc = pics["SCROLLCURSOR"]; + Blit((LPDIRECTDRAWSURFACE4)sc.pic, rclick_x * m_viewScale.x + r.left - sc.wWidth / 2, rclick_y * m_viewScale.y + r.top - sc.wHeight / 2); + } + + BlitBackbufferToHighRes(); // lpdsBackHighRes contains the same graphic, but scaled to the whole window + + RenderUIOverlay(); + if (theApp.m_Options.bVSync) + dd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); + FlipHighResBuffer(); + last_succeeded_operation = 10100; + +} + +void CIsoView::RenderUIOverlay() +{ + if (!m_textDefault) + updateFontScaled(); + + LPDIRECTDRAWSURFACE4 dds = lpdsBack; + bool useHighRes = false; + if (m_viewScale != Vec2<CSProjected, float>(1.0f, 1.0f) && lpdsBackHighRes) + { + dds = lpdsBackHighRes; + useHighRes = true; + } + + DDSURFACEDESC2 ddsd; + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + + dds->GetSurfaceDesc(&ddsd); + + dds->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL); + LineDrawer d(ddsd.lpSurface, bpp, ddsd.dwWidth, ddsd.dwHeight, ddsd.lPitch); + + int lr, lt, ll, lb; + + ll = Map->GetWidth(); + lt = 1; + lr = Map->GetHeight(); + lb = Map->GetIsoSize() - 1; + + int h_lefttop = 0;//Map->GetHeightAt(ll+lt*Map->GetIsoSize()); + int h_leftbottom = 0;//Map->GetHeightAt(lr+lb*Map->GetIsoSize()); + + ToPhys((int*)&ll, (int*)<); + ToPhys((int*)&lr, (int*)&lb); + ll -= m_viewOffset.x - f_x / 2; + lt -= m_viewOffset.y - f_y / 2; + lr -= m_viewOffset.x - f_x / 2; + lb -= m_viewOffset.y - f_y / 2; + + lt -= h_lefttop * f_y / 2; + lb -= h_leftbottom * f_y / 2; + + auto sllt = useHighRes ? ScaleBackToFrontBuffer(ProjectedCoords(ll, lt)) : ProjectedCoords(ll, lt); + auto slbr = useHighRes ? ScaleBackToFrontBuffer(ProjectedCoords(lr, lb)) : ProjectedCoords(lr, lb); + + RECT ls; + Map->GetLocalSize(&ls); + ProjectedCoords l_lt( + ll + ls.left * f_x - f_x / 2, + lt + (ls.top - 4) * f_y + ); + ProjectedCoords l_br( + ll + ls.left * f_x + ls.right * f_x - f_x / 2, + lt + (ls.top - 4 + 4) * f_y + ls.bottom * f_y + ); + auto ls_lt = useHighRes ? ScaleBackToFrontBuffer(l_lt) : l_lt; + auto ls_br = useHighRes ? ScaleBackToFrontBuffer(l_br) : l_br; + + auto red = m_color_converter->GetColor(255, 0, 0); + auto blue = m_color_converter->GetColor(0, 0, 255); + d.Rectangle(sllt.x, sllt.y, slbr.x, slbr.y, red); + d.Rectangle(sllt.x-1, sllt.y-1, slbr.x+1, slbr.y+1, red); + d.Rectangle(ls_lt.x, ls_lt.y, ls_br.x, ls_br.y, blue); + d.Rectangle(ls_lt.x+1, ls_lt.y+1, ls_br.x-1, ls_br.y-1, blue); + + dds->Unlock(NULL); + + RECT r; + GetWindowRect(&r); + + for (const auto& s : m_texts_to_render) + { + const bool blue = s.color == RGB(0, 0, 255); // TODO: TextRenderer should support setting the color at render time + if (s.fixedScreenPos || !useHighRes) + { + auto textRenderer = s.useFont9 ? (blue ? *m_textBlue9 : *m_text9) : (blue ? *m_textBlue : *m_textDefault); + textRenderer.RenderText(dds, s.drawx, s.drawy, s.text, s.centered); + } + else + { + auto textRenderer = s.useFont9 ? (blue ? *m_textBlue9Scaled : *m_text9Scaled) : (blue ? *m_textBlueScaled : *m_textScaled); + textRenderer.RenderText(dds, r.left + (s.drawx - r.left) / m_viewScale.x, r.top + (s.drawy - r.top) / m_viewScale.y, s.text, s.centered); + } + } +} + + +void CIsoView::OnRButtonDown(UINT nFlags, CPoint point) +{ + rclick_x = point.x; + rclick_y = point.y; + rscroll = FALSE; + + CView::OnRButtonDown(nFlags, point); +} + +void CIsoView::SetScroll(int xscroll, int yscroll) +{ + RECT r; + GetWindowRect(&r); + + m_viewOffset = ProjectedVec(xscroll, yscroll); + + + if (m_viewOffset.x < (Map->GetHeight() / 2 - 14 - r.left / f_x) * f_x) + m_viewOffset.x = (Map->GetHeight() / 2 - 14 - r.left / f_x) * f_x; + if (m_viewOffset.x + r.right * m_viewScale.x > (Map->GetHeight() / 2 + Map->GetWidth() + 14) * f_x) + m_viewOffset.x = (Map->GetHeight() / 2 + Map->GetWidth() + 14) * f_x - r.right * m_viewScale.x; + if (m_viewOffset.y < (Map->GetWidth() / 2 - 14 - r.top / f_y) * f_y) + m_viewOffset.y = (Map->GetWidth() / 2 - 14 - r.top / f_y) * f_y; + if (m_viewOffset.y + r.bottom * m_viewScale.y > (Map->GetWidth() / 2 + Map->GetHeight() + 4) * f_y) + m_viewOffset.y = (Map->GetWidth() / 2 + Map->GetHeight() + 4) * f_y - r.bottom * m_viewScale.y; + + SetScrollPos(SB_VERT, (m_viewOffset.y / f_y - Map->GetWidth() / 2 + 4), TRUE); + SetScrollPos(SB_HORZ, (m_viewOffset.x / f_x - Map->GetHeight() / 2 + 1), TRUE); + +} + +RECT CIsoView::GetScaledDisplayRect() const +{ + RECT r; + GetWindowRect(&r); + r.right = r.right - (r.right - r.left) * (1.0f - m_viewScale.x); + r.bottom = r.bottom - (r.bottom - r.top) * (1.0f - m_viewScale.y); + return r; // RVO +} + +void CIsoView::GetScroll(int& xscroll, int& yscroll) const +{ + xscroll = m_viewOffset.x; + yscroll = m_viewOffset.y; +} + +void CIsoView::OnKillFocus(CWnd* pNewWnd) +{ + CView::OnKillFocus(pNewWnd); + + if (rscroll) + { + errstream << "Killing scroll" << endl; + errstream.flush(); + + ReleaseCapture(); + KillTimer(11); + ShowCursor(TRUE); + rscroll = FALSE; + bDoNotAllowScroll = TRUE; + } + +} + +// takes an index, not an waypoint id! +void CIsoView::FocusWaypoint(int index) +{ + int x, y; + + DWORD dwPos; + + Map->GetWaypointData(index, NULL, &dwPos); + + x = dwPos % Map->GetIsoSize(); + y = dwPos / Map->GetIsoSize(); + + ToPhys3d(&x, &y); + + RECT r; + GetWindowRect(&r); + + auto pos = ProjectedVec((x - (r.right - r.left) / 2 * m_viewScale.x) - r.left, (y - (r.bottom - r.top) / 2 * m_viewScale.y) - r.top); + SetScroll(pos.x, pos.y); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + + +BOOL CIsoView::OnMouseWheel(UINT nFlags, short zDelta, CPoint ptScreen) +{ + CPoint pt = ptScreen; + ScreenToClient(&pt); // Attention: MouseWheel event has screen coordinates in contrast to e.g. MouseMove + + float smoothF = float(zDelta) / std::numeric_limits<short>::max(); + float fixedF = zDelta > 0 ? std::numeric_limits<short>::max() : std::numeric_limits<short>::min(); + + Zoom(pt, theApp.m_Options.viewScaleUseSteps ? fixedF : smoothF); + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + CMyViewFrame& dlg = *(CMyViewFrame*)owner; + dlg.m_minimap.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + return CView::OnMouseWheel(nFlags, zDelta, pt); +} + +void CIsoView::Zoom(CPoint& pt, float f) +{ + auto oldScaledMPos = GetProjectedCoordinatesFromClientCoordinates(pt); + + auto oldScale = m_viewScale; + + auto oldViewScaleControl = m_viewScaleControl; + m_viewScaleControl *= (1.0f - f * theApp.m_Options.viewScaleSpeed); + if (m_viewScaleControl > 1.0f) + m_viewScaleControl = 1.0f; + if (m_viewScaleControl < 0.1f) + m_viewScaleControl = 0.1f; + + if (!theApp.m_Options.viewScaleUseSteps) + m_viewScale.set(m_viewScaleControl, m_viewScaleControl); + else + { + // find previous step + auto prevStepIt = std::find_if(theApp.m_Options.viewScaleSteps.rbegin(), theApp.m_Options.viewScaleSteps.rend(), [oldScale](auto f) {return f >= oldScale.x;}); + auto stepIt = std::find_if(theApp.m_Options.viewScaleSteps.rbegin(), theApp.m_Options.viewScaleSteps.rend(), [this](auto f) {return f >= m_viewScaleControl;}); + if (stepIt > prevStepIt) + stepIt = prevStepIt + 1; + if (stepIt < prevStepIt) + stepIt = prevStepIt - 1; + auto nextScale = stepIt == theApp.m_Options.viewScaleSteps.rend() ? 1.0f : *stepIt; + m_viewScale.set(nextScale, nextScale); + } + + auto newScaledMPos = GetProjectedCoordinatesFromClientCoordinates(pt); + + m_viewOffset = m_viewOffset + ((oldScaledMPos - newScaledMPos)).convertT<std::int32_t>(); // this lets the mouse cursor pixel stay constant + + UpdateScrollRanges(); + SetScroll(m_viewOffset.x, m_viewOffset.y); + updateFontScaled(); +} + + +void CIsoView::OnMButtonDown(UINT nFlags, CPoint point) +{ + // TODO: FĂ¼gen Sie hier Ihren Meldungshandlercode ein, und/oder benutzen Sie den Standard. + m_MButtonDown = point; + m_MButtonMoveZooming = point; + m_zooming = true; + CView::OnMButtonDown(nFlags, point); +} + + +void CIsoView::OnMButtonUp(UINT nFlags, CPoint point) +{ + // TODO: FĂ¼gen Sie hier Ihren Meldungshandlercode ein, und/oder benutzen Sie den Standard. + m_zooming = false; + CView::OnMButtonUp(nFlags, point); +} diff --git a/MissionEditor/IsoView.h b/MissionEditor/IsoView.h new file mode 100644 index 0000000..41b3e8d --- /dev/null +++ b/MissionEditor/IsoView.h @@ -0,0 +1,392 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_ISOVIEW_H__7FB6D6A0_7B52_11D3_99E1_DA6DFD21E706__INCLUDED_) +#define AFX_ISOVIEW_H__7FB6D6A0_7B52_11D3_99E1_DA6DFD21E706__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// IsoView.h : header file +// + + + +///////////////////////////////////////////////////////////////////////////// +// View CIsoView + +#include <vector> +#include <memory> +#include "MissionEditorPackLib.h" +#include "Structs.h" + + + +struct TextToRender +{ + std::string text; + int drawx; + int drawy; + int color; + bool fixedScreenPos = false; + bool useFont9 = false; + bool centered = false; +}; + +struct WaypointToRender +{ + int drawx; + int drawy; +}; + +class TextDrawer; +class CTube; + + +class CIsoView : public CView +{ +protected: + DECLARE_DYNCREATE(CIsoView) + +// attributes +public: + INT m_mapx; + INT m_mapy; + int m_FlattenHeight; // for flatten ground + int m_FlattenLastX; + int m_FlattenLastY; + int m_TileChangeCount; + BOOL bThreadPainting; + +private: + ProjectedVec m_viewOffset; + Vec2<CSProjected, float> m_viewScale; // this is used for display and may e.g. be locked to zoom steps + float m_viewScaleControl; // you control these with your mouse + CPoint m_MButtonDown; + CPoint m_MButtonMoveZooming; + + int rclick_x; // scroll pixel coordinates + int rclick_y; + int cur_x_mouse; + int cur_y_mouse; + BOOL rscroll; + BOOL m_bAltCliff; + bool m_zooming; + + std::vector<TextToRender> m_texts_to_render; + std::vector<WaypointToRender> m_waypoints_to_render; + + + +// operations +public: + CIsoView(); + virtual ~CIsoView(); + +// overwriteables + //{{AFX_VIRTUAL(CIsoView) + public: + virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); + protected: + virtual void OnDraw(CDC* pDC); // Ăœberschrieben zum Zeichnen dieser Ansicht + virtual void OnInitialUpdate(); // Zum ersten Mal nach der Konstruktion + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); + //}}AFX_VIRTUAL + +// implementation +protected: + +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + + + // generated message maps + //{{AFX_MSG(CIsoView) + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnRButtonUp(UINT nFlags, CPoint point); + afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMove(int x, int y); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnKillFocus(CWnd* pNewWnd); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +public: + void FocusWaypoint(int index); + RECT m_funcRect; + Vec2<CSProjected, float> GetViewScale() const + { + return m_viewScale; + } + ProjectedVec GetViewOffset() const + { + return m_viewOffset; + } + RECT GetScaledDisplayRect() const; + void GetScroll(int& xscroll, int& yscroll) const; + void SetScroll(int xscroll, int yscroll); + void DrawMap(); + void AutoLevel(); + void FillArea(DWORD dwX, DWORD dwY, DWORD dwID, BYTE bSubTile); + BOOL m_NoMove; + void PlaceCurrentObjectAt(int x, int y); + void PlaceTile(const int x, const int y, const UINT nMouseFlags); + void ShowAllTileSets(); + void HideTileSet(DWORD dwTileSet); + void FlipHighResBuffer(); + void BlitBackbufferToHighRes(); + void RenderUIOverlay(); + int m_BrushSize_x; + int m_BrushSize_y; + BOOL ReachableFrom(DWORD dwStart, DWORD dwEnd); + void __fastcall ChangeTileHeight(DWORD dwPos, DWORD dwNewHeight, BOOL bNonMorphableMove, BOOL bOnlyThisTile=FALSE, BOOL bNoSlopes=FALSE); + void UpdateOverlayPictures(int id=-1); + void UpdateStatusBar(int x, int y); + void DrawCell(int x, int y, int w, int h, COLORREF col, BOOL dotted=FALSE, HDC hDC=nullptr); + void DrawCell(void* dest, int dest_width, int dest_height, int dest_pitch, int x, int y, int w, int h, int col, bool dotted=false, bool touchNeighbours=false, int colNeighbour=CLR_INVALID) const; + void DrawCellCursor(const MapCoords& mapCoords, const DDSURFACEDESC2& desc); + void DrawTube(const CTube& tube, const DDSURFACEDESC2* ddsd=nullptr, const COLORREF* color=nullptr) const; + + /// <summary> + /// Converts from (world) pixel coordinates to logical map coordinates + /// </summary> + /// <param name="projCoords">World pixel coordinates</param> + /// <returns>Logical map coordinates</returns> + MapCoords GetMapCoordinates(const ProjectedCoords& projCoords, bool bAllowAccessBehindCliffs=false, bool ignoreHideFlags = false) const; + + /// <summary> + /// Converts from view / render target pixel coordinates (0/0 is top left corner of screen) to logical map coordinates + /// If you use mouse-move coordinates you need to + /// </summary> + /// <param name="projCoords">Texel coordinates of the backbuffer render target</param> + /// <returns>Logical map coordinates</returns> + MapCoords GetMapCoordinatesFromRenderTargetCoordinates(const ProjectedCoords& screenViewCoords, bool bAllowAccessBehindCliffs = false, bool ignoreHideFlags = false) const; + + /// <summary> + /// Converts from Win32 window client coordinates (0/0 at the top left corner of the view window) to logical map coordinates + /// </summary> + /// <param name="clientPt">Client coordinates as given e.g. by window messages</param> + /// <returns>Logical map coordinates</returns> + MapCoords GetMapCoordinatesFromClientCoordinates(const CPoint& clientPt, bool bAllowAccessBehindCliffs = false, bool ignoreHideFlags = false) const; + + /// <summary> + /// Converts from Win32 window client coordinates (0/0 at the top left corner of the view window) to (world) pixel coordinates + /// </summary> + /// <param name="clientPt">Client coordinates as given e.g. by window messages</param> + /// <returns>World pixel coordinates</returns> + ProjectedCoords GetProjectedCoordinatesFromClientCoordinates(const CPoint& clientPt) const; + + /// <summary> + /// Converts from logical map coordinates to (world) pixel coordinates + /// </summary> + /// <param name="mapCoords">Logical map coordinates</param> + /// <returns>World pixel coordinates</returns> + ProjectedCoords GetProjectedCoordinates(const MapCoords& mapCoords) const; + + /// <summary> + /// Converts from logical map coordinates to (world) pixel coordinates + /// </summary> + /// <param name="mapCoords">Logical map coordinates</param> + /// <param name="mapZ">Fixed logical height</param> + /// <returns>World pixel coordinates</returns> + ProjectedCoords GetProjectedCoordinates(const MapCoords& mapCoords, int mapZ) const; + + /// <summary> + /// Converts from logical map coordinates to view / render target pixel coordinates (screen backbuffer, e.g. currently not yet scaled by view zoom) + /// </summary> + /// <param name="mapCoords">Logical map coordinates</param> + /// <returns>Texel coordinates of the screen backbuffer</returns> + ProjectedCoords GetRenderTargetCoordinates(const MapCoords& mapCoords) const; + + /// <summary> + /// Converts from logical map coordinates to view / render target pixel coordinates (screen backbuffer, e.g. currently not yet scaled by view zoom) + /// </summary> + /// <param name="mapCoords">Logical map coordinates</param> + /// <param name="mapZ">Fixed logical height</param> + /// <returns>Texel coordinates of the screen backbuffer</returns> + ProjectedCoords GetRenderTargetCoordinates(const MapCoords& mapCoords, int mapZ) const; + + /// <summary> + /// Converts from logical map coordinates to Win32 window client coordinates (0/0 at the top left corner of the view window) + /// </summary> + /// <param name="projCoords">Logical map coordinates</param> + /// <returns>Texel coordinates of the backbuffer render target</returns> + CPoint GetClientCoordinates(const MapCoords& mapCoords) const; + + /// <summary> + /// Converts from (world) pixel coordinates to Win32 window client coordinates (0/0 at the top left corner of the view window) + /// </summary> + /// <param name="projCoords">World pixel coordinates</param> + /// <returns>Client coordinates as given e.g. by window messages</returns> + CPoint GetClientCoordinatesFromWorld(const ProjectedCoords& projectedCoords) const; + + /// <summary> + /// Applies the scaling as it is being done when blitting from back to frontbuffer, required e.g. for drawing calls directly to the frontbuffer + /// If you use mouse-move coordinates you need to + /// </summary> + /// <param name="projCoords">Texel coordinates of the backbuffer render target</param> + /// <returns>Texel coordinates of the frontbuffer render target</returns> + ProjectedCoords ScaleBackToFrontBuffer(const ProjectedCoords& backBufferCoords) const; + + void HandleTrail(int x, int y); + int GetOverlayDirection(int x, int y); + void SetError(const char* text); + CWnd* owner; + void ReInitializeDDraw(); + COLORREF GetColor(const char* house, const char* color=NULL); + void Blit(LPDIRECTDRAWSURFACE4 pic, int x, int y, int width=-1, int height=-1) + { + if(pic==NULL) return; + + x+=1; + y+=1; + //y-=f_y; + + RECT r; + GetDesktopWindow()->GetWindowRect(&r); + //GetWindowRect(&r); + + if(width==-1 || height==-1) + { + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize=sizeof(DDSURFACEDESC2); + ddsd.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + pic->GetSurfaceDesc(&ddsd); + width=ddsd.dwWidth; + height=ddsd.dwHeight; + } + + if(x+width<0 || y+height<0) return; + if(x>r.right || y>r.bottom) return; + + if(x<0 || y<0 || x+width>=r.right || y+height>=r.bottom) + { + + + RECT blrect; + RECT srcRect; + srcRect.left=0; + srcRect.top=0; + srcRect.right=width; + srcRect.bottom=height; + blrect.left=x; + if(blrect.left<0) + { + srcRect.left=r.left+1-blrect.left; + blrect.left=r.left+1; + } + blrect.top=y; + if(blrect.top<0) + { + + //errstream << "BlRect.top=" << blrect.top << endl; + srcRect.top=(r.top+1)-blrect.top; //(r.top-blrect.top); + blrect.top=r.top+1;//r.top; + // errstream << blrect.top << " " << srcRect.top << endl; + } + blrect.right=(x+width); + if(x+width>r.right) + { + srcRect.right=width-((x+width)-r.right);// -(-blrect.right+r.right); + blrect.right=r.right; + } + blrect.bottom=(y+height); + if(y+height>r.bottom) + { + srcRect.bottom=height-((y+height)-r.bottom); // -(-blrect.bottom+r.bottom); + blrect.bottom=r.bottom; + } + DDBLTFX fx; + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + lpdsBack->Blt(&blrect, pic, &srcRect, DDBLT_KEYSRC, &fx); + } + else + lpdsBack->BltFast(x,y, pic, NULL, DDBLTFAST_SRCCOLORKEY); + } + void updateFontScaled(); + void TextOut(int x, int y, const char* text, COLORREF col); + void TextOut(HDC hDC, int x, int y, const char* text, COLORREF col); + LPDIRECTDRAWSURFACE4 lpdsBack; + LPDIRECTDRAWSURFACE4 lpdsTemp; // used for saving the isoview when drawing current tile + LPDIRECTDRAWSURFACE4 lpdsBackHighRes; // used for rendering text and some lines in high-res + LPDIRECTDRAWSURFACE4 lpds; + DDPIXELFORMAT pf; + std::unique_ptr<FSunPackLib::ColorConverter> m_color_converter; + LPDIRECTDRAW4 dd; + LPDIRECTDRAW dd_1; + HGLRC m_hglrc; + void HandleProperties(int n, int type); + void UpdateDialog(BOOL bRepos=TRUE); + CMenu m_menu; + BOOL b_IsLoading; + int m_fontDefaultHeight; + int m_Font9Height; + std::unique_ptr<TextDrawer> m_textDefault; + std::unique_ptr<TextDrawer> m_textScaled; + std::unique_ptr<TextDrawer> m_text9; + std::unique_ptr<TextDrawer> m_text9Scaled; + std::unique_ptr<TextDrawer> m_textBlue; + std::unique_ptr<TextDrawer> m_textBlue9; + std::unique_ptr<TextDrawer> m_textBlueScaled; + std::unique_ptr<TextDrawer> m_textBlue9Scaled; + +private: + void UpdateScrollRanges(); + +private: + RECT m_myRect; + + + // mapdata* _map; + COLORREF m_linecolor; + RECT line; + int m_type; + int m_id; + BOOL m_drag; + BOOL m_moved; + MapCoords m_cellCursor; +public: + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + void Zoom(CPoint& pt, float f); + afx_msg void OnMButtonDown(UINT nFlags, CPoint point); + afx_msg void OnMButtonUp(UINT nFlags, CPoint point); +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} + +#endif // AFX_ISOVIEW_H__7FB6D6A0_7B52_11D3_99E1_DA6DFD21E706__INCLUDED_ diff --git a/MissionEditor/Lighting.cpp b/MissionEditor/Lighting.cpp new file mode 100644 index 0000000..5470b06 --- /dev/null +++ b/MissionEditor/Lighting.cpp @@ -0,0 +1,226 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Lighting.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Lighting.h" +#include "mapdata.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CLighting + +IMPLEMENT_DYNCREATE(CLighting, CDialog) + +CLighting::CLighting() : CDialog(CLighting::IDD) +{ + //{{AFX_DATA_INIT(CLighting) + //}}AFX_DATA_INIT +} + +CLighting::~CLighting() +{ +} + +void CLighting::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLighting) + DDX_Control(pDX, IDC_RED2, m_Red2); + DDX_Control(pDX, IDC_RED, m_Red); + DDX_Control(pDX, IDC_LEVEL2, m_Level2); + DDX_Control(pDX, IDC_LEVEL, m_Level); + DDX_Control(pDX, IDC_GREEN2, m_Green2); + DDX_Control(pDX, IDC_GREEN, m_Green); + DDX_Control(pDX, IDC_BLUE2, m_Blue2); + DDX_Control(pDX, IDC_BLUE, m_Blue); + DDX_Control(pDX, IDC_AMBIENT2, m_Ambient2); + DDX_Control(pDX, IDC_AMBIENT, m_Ambient); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLighting, CDialog) + //{{AFX_MSG_MAP(CLighting) + ON_EN_CHANGE(IDC_AMBIENT, OnChangeAmbient) + ON_EN_CHANGE(IDC_LEVEL, OnChangeLevel) + ON_EN_KILLFOCUS(IDC_AMBIENT, OnKillfocusAmbient) + ON_EN_CHANGE(IDC_RED, OnChangeRed) + ON_EN_CHANGE(IDC_GREEN, OnChangeGreen) + ON_EN_CHANGE(IDC_BLUE, OnChangeBlue) + ON_EN_CHANGE(IDC_AMBIENT2, OnChangeAmbient2) + ON_EN_CHANGE(IDC_LEVEL2, OnChangeLevel2) + ON_EN_CHANGE(IDC_RED2, OnChangeRed2) + ON_EN_CHANGE(IDC_GREEN2, OnChangeGreen2) + ON_EN_CHANGE(IDC_BLUE2, OnChangeBlue2) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CLighting + +void CLighting::UpdateDialog() +{ + CIniFile& ini=Map->GetIniFile(); + + m_Ambient.SetWindowText(ini.sections["Lighting"].values["Ambient"]); + m_Ambient2.SetWindowText(ini.sections["Lighting"].values["IonAmbient"]); + m_Level.SetWindowText(ini.sections["Lighting"].values["Level"]); + m_Level2.SetWindowText(ini.sections["Lighting"].values["IonLevel"]); + m_Red.SetWindowText(ini.sections["Lighting"].values["Red"]); + m_Red2.SetWindowText(ini.sections["Lighting"].values["IonRed"]); + m_Green.SetWindowText(ini.sections["Lighting"].values["Green"]); + m_Green2.SetWindowText(ini.sections["Lighting"].values["IonGreen"]); + m_Blue.SetWindowText(ini.sections["Lighting"].values["Blue"]); + m_Blue2.SetWindowText(ini.sections["Lighting"].values["IonBlue"]); + //MessageBox(ini.sections["Lightning"].values["Ambient"]); +} + +BOOL CLighting::OnInitDialog() +{ + CDialog::OnInitDialog(); + +#ifdef RA2_MODE + SetDlgItemText(IDC_LIONSTORM, "Weather Storm Settings"); +#endif + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + + + + + +void CLighting::OnChangeAmbient() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Ambient.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["Ambient"]=text; + +} + +void CLighting::OnChangeLevel() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Level.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["Level"]=text; + +} + +void CLighting::OnKillfocusAmbient() +{ + +} + +void CLighting::OnChangeRed() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Red.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["Red"]=text; +} + +void CLighting::OnChangeGreen() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Green.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["Green"]=text; +} + +void CLighting::OnChangeBlue() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Blue.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["Blue"]=text; +} + +void CLighting::OnChangeAmbient2() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Ambient2.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["IonAmbient"]=text; +} + +void CLighting::OnChangeLevel2() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Level2.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["IonLevel"]=text; +} + +void CLighting::OnChangeRed2() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Red2.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["IonRed"]=text; +} + +void CLighting::OnChangeGreen2() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Green2.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["IonGreen"]=text; +} + +void CLighting::OnChangeBlue2() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ctext; + m_Blue2.GetWindowText(ctext); + CString text=(char*)(LPCTSTR)ctext; + ini.sections["Lighting"].values["IonBlue"]=text; +} diff --git a/MissionEditor/Lighting.h b/MissionEditor/Lighting.h new file mode 100644 index 0000000..a371a1d --- /dev/null +++ b/MissionEditor/Lighting.h @@ -0,0 +1,92 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_LIGHTNING_H__9DC7B326_6DF2_11D3_99E1_D14A1D4DCF07__INCLUDED_) +#define AFX_LIGHTNING_H__9DC7B326_6DF2_11D3_99E1_D14A1D4DCF07__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Lightning.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CLighting + + + +class CLighting : public CDialog +{ + DECLARE_DYNCREATE(CLighting) + +// Konstruktion +public: + void UpdateDialog(); + CLighting(); + ~CLighting(); + +// Dialogfelddaten + //{{AFX_DATA(CLighting) + enum { IDD = IDD_LIGHTING }; + CFloatEdit m_Red2; + CFloatEdit m_Red; + CFloatEdit m_Level2; + CFloatEdit m_Level; + CFloatEdit m_Green2; + CFloatEdit m_Green; + CFloatEdit m_Blue2; + CFloatEdit m_Blue; + CFloatEdit m_Ambient2; + CFloatEdit m_Ambient; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CLighting) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CLighting) + virtual BOOL OnInitDialog(); + afx_msg void OnChangeAmbient(); + afx_msg void OnChangeLevel(); + afx_msg void OnKillfocusAmbient(); + afx_msg void OnChangeRed(); + afx_msg void OnChangeGreen(); + afx_msg void OnChangeBlue(); + afx_msg void OnChangeAmbient2(); + afx_msg void OnChangeLevel2(); + afx_msg void OnChangeRed2(); + afx_msg void OnChangeGreen2(); + afx_msg void OnChangeBlue2(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_LIGHTNING_H__9DC7B326_6DF2_11D3_99E1_D14A1D4DCF07__INCLUDED_ diff --git a/MissionEditor/LineDrawer.cpp b/MissionEditor/LineDrawer.cpp new file mode 100644 index 0000000..a7d9ce5 --- /dev/null +++ b/MissionEditor/LineDrawer.cpp @@ -0,0 +1,148 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "StdAfx.h" +#include "LineDrawer.h" +#include <cassert> +#include <memory> + +static int ModLookup[] = { + 1, + 2, + 3, + 4 +}; + +LineDrawer::LineDrawer(void* dest, int bytes_per_pixel, int width, int height, int pitch): + m_dest(dest), + m_bytes_per_pixel(bytes_per_pixel), + m_width(width), + m_height(height), + m_pitch(pitch), + m_last_x(0), + m_last_y(0) +{ +} + +void LineDrawer::MoveTo(int to_x, int to_y) +{ + m_last_x = to_x; + m_last_y = to_y; +} + +void LineDrawer::LineTo(int to_x, int to_y, int color, LineStyle style) +{ + DrawLine(m_last_x, m_last_y, to_x, to_y, color, style); +} + +void LineDrawer::DrawLine(int from_x, int from_y, int to_x, int to_y, int color, LineStyle style) +{ + const int w = to_x - from_x; + const int h = to_y - from_y; + m_last_x = to_x; + m_last_y = to_y; + if (abs(w) >= abs(h)) { + return w >= 0 ? DrawLineImplX(from_x, from_y, to_x, to_y, color, style) : DrawLineImplX(to_x, to_y, from_x, from_y, color, style); + } + else { + return h >= 0 ? DrawLineImplY(from_x, from_y, to_x, to_y, color, style) : DrawLineImplY(to_x, to_y, from_x, from_y, color, style); + } +} + +void LineDrawer::Rectangle(int from_x, int from_y, int to_x, int to_y, int color, LineStyle style) +{ + MoveTo(from_x, from_y); + LineTo(to_x, from_y, color, style); + LineTo(to_x, to_y, color, style); + LineTo(from_x, to_y, color, style); + LineTo(from_x, from_y, color, style); +} + +void LineDrawer::SetPixel(char* const dest, const int cur_x, const int cur_y, const int color) +{ + if (cur_x >= 0 && cur_y >= 0 && cur_x < m_width && cur_y < m_height) + memcpy(&dest[cur_x * m_bytes_per_pixel + cur_y * m_pitch], &color, m_bytes_per_pixel); +} + +void LineDrawer::DrawLineImplX(const int from_x, const int from_y, const int to_x, const int to_y, const int color, const LineStyle style) +{ + // X major line drawing + + assert (from_x <= to_x); + const int w = to_x - from_x; + const int h = abs(to_y - from_y); + assert (w >= h); + const int increment_e = 2 * h; + const int increment_ne = 2 * (h - w); + const int y_inc = (to_y - from_y) < 0 ? -1 : 1; + int d = 2 * h - w; + int cur_x = from_x; + int cur_y = from_y; + const int mod = ModLookup[static_cast<int>(style)]; + + char* dest = reinterpret_cast<char*>(m_dest); + SetPixel(dest, cur_x, cur_y, color); + + for(; cur_x < to_x; ++cur_x) + { + if (d < 0) { + d += increment_e; + } + else { + d += increment_ne; + cur_y += y_inc; + } + if (mod == 1 || (cur_x - from_x) % mod == 0) + SetPixel(dest, cur_x, cur_y, color); + } +} + +void LineDrawer::DrawLineImplY(const int from_x, const int from_y, const int to_x, const int to_y, const int color, LineStyle style) +{ + // Y major line drawing + + assert(from_y <= to_y); + const int w = abs(to_x - from_x); + const int h = to_y - from_y; + assert(h >= w); + const int increment_e = 2 * w; + const int increment_ne = 2 * (w - h); + const int x_inc = (to_x - from_x) < 0 ? -1 : 1; + int d = 2 * w - h; + int cur_x = from_x; + int cur_y = from_y; + const int mod = ModLookup[static_cast<int>(style)]; + + char* dest = reinterpret_cast<char*>(m_dest); + SetPixel(dest, cur_x, cur_y, color); + + for (; cur_y < to_y; ++cur_y) + { + if (d < 0) { + d += increment_e; + } + else { + d += increment_ne; + cur_x += x_inc; + } + if (mod == 1 || (cur_y - from_y) % mod == 0) + SetPixel(dest, cur_x, cur_y, color); + } +} diff --git a/MissionEditor/LineDrawer.h b/MissionEditor/LineDrawer.h new file mode 100644 index 0000000..550b24c --- /dev/null +++ b/MissionEditor/LineDrawer.h @@ -0,0 +1,56 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cinttypes> + +enum class LineStyle: int +{ + Standard, + Dotted_2, + Dotted_3, + Dotted_4, +}; + +class LineDrawer +{ +public: + LineDrawer(void* dest, int bytes_per_pixel, int width, int height, int pitch); + + void MoveTo(int to_x, int to_y); + void LineTo(int to_x, int to_y, int color, LineStyle style = LineStyle::Standard); + void DrawLine(int from_x, int from_y, int to_x, int to_y, int color, LineStyle style = LineStyle::Standard); + void Rectangle(int from_x, int from_y, int to_x, int to_y, int color, LineStyle style = LineStyle::Standard); + +private: + void SetPixel(char* dest, int cur_x, int cur_y, int color); + void DrawLineImplX(int from_x, int from_y, int to_x, int to_y, int color, LineStyle style); + void DrawLineImplY(int from_x, int from_y, int to_x, int to_y, int color, LineStyle style); + +private: + void* m_dest; + int m_bytes_per_pixel; + int m_width; + int m_height; + int m_pitch; + int m_last_x; + int m_last_y; +}; \ No newline at end of file diff --git a/MissionEditor/Loading.cpp b/MissionEditor/Loading.cpp new file mode 100644 index 0000000..f41bd9b --- /dev/null +++ b/MissionEditor/Loading.cpp @@ -0,0 +1,6972 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Loading.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Loading.h" +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <io.h> +#include <stdio.h> +#include "resource.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" +#include "MissionEditorPackLib.h" +#include <chrono> +#include <thread> +#include "VoxelNormals.h" +#include <format> + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CLoading + + +CLoading::CLoading(CWnd* pParent /*=NULL*/) + : CDialog(CLoading::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLoading) + //}}AFX_DATA_INIT + + Create(CLoading::IDD, pParent); + + loaded=FALSE; + cur_theat='T'; + + + + m_hCache=NULL; + m_hConquer=NULL; + m_hIsoSnow=NULL; + m_hIsoTemp=NULL; + m_hLocal=NULL; + m_hTemperat=NULL; + m_hTibSun=NULL; + m_hLangMD=NULL; + m_pic_count=0; + + s_tiledata=NULL; + t_tiledata=NULL; + u_tiledata=NULL; + s_tiledata_count=0; + t_tiledata_count=0; + u_tiledata_count=0; + tiledata=NULL; + tiledata_count=0; + + int i=0; + for(i=0;i<101; i++) + { + + m_hExpand[i].hExpand=NULL; + } + for(i=0;i<100; i++) + { + + m_hECache[i]=NULL; + } + + errstream << "CLoading::CLoading() called" << endl; + errstream.flush(); +} + + +void CLoading::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLoading) + DDX_Control(pDX, IDC_VERSION, m_Version); + DDX_Control(pDX, IDC_BUILTBY, m_BuiltBy); + DDX_Control(pDX, IDC_CAP, m_cap); + DDX_Control(pDX, IDC_PROGRESS1, m_progress); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLoading, CDialog) + //{{AFX_MSG_MAP(CLoading) + ON_WM_DESTROY() + ON_WM_PAINT() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// message handlers CLoading + +BOOL bUseFirestorm=TRUE; + +void CLoading::Load() +{ + auto startTime = std::chrono::steady_clock::now(); + + + CString artFile; + + + + + // show a wait cursor + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + // write a log + errstream << "CLoading::Load() called" << std::endl << std::endl; + errstream.flush(); + + + // initialize the FSunPackLib::XCC + errstream << "Initializing FSunPackLib::XCC" << std::endl; + errstream.flush(); + FSunPackLib::XCC_Initialize(TRUE); + m_cap.SetWindowText(GetLanguageStringACP("LoadExtractStdMixFiles")); + + errstream << "Initializing mix files" << std::endl; + errstream.flush(); + MEMORYSTATUS ms; + ms.dwLength=sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&ms); + int cs=ms.dwAvailPhys+ms.dwAvailPageFile; + InitMixFiles(); + errstream << "Loading palettes" << std::endl << std::endl; + errstream.flush(); + InitPalettes(); + + // Load voxel normal tables + InitVoxelNormalTables(); + + + // create a ini file containing some info XCC Mixer needs + CreateINI(); + + // set progress bar range to 0-2 + m_progress.SetRange(0,2); + + // rules.ini + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadRules")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("Rules.ini", &rules, FALSE); + +#ifdef TS_MODE + if(bUseFirestorm) + { + // very special case, the types list don´t have any order according to the original rules! + CIniFile fstorm; + LoadTSIni("firestrm.ini", &fstorm, TRUE); + + int i; + CString cuSection; + cuSection="InfantryTypes"; + for(i=0;i<fstorm.sections[cuSection].values.size();i++) + { + // we simply add a FS to the index + char c[50]; + itoa(i, c, 10); + strcat(c, "FS"); + rules.sections[cuSection].values[c]=*fstorm.sections[cuSection].GetValue(i); + rules.sections[cuSection].value_orig_pos[c]=rules.sections[cuSection].values.size()-1; + } + cuSection="VehicleTypes"; + for(i=0;i<fstorm.sections[cuSection].values.size();i++) + { + // we simply add a FS to the index + char c[50]; + itoa(i, c, 10); + strcat(c, "FS"); + rules.sections[cuSection].values[c]=*fstorm.sections[cuSection].GetValue(i); + rules.sections[cuSection].value_orig_pos[c]=rules.sections[cuSection].values.size()-1; + } + cuSection="AircraftTypes"; + for(i=0;i<fstorm.sections[cuSection].values.size();i++) + { + // we simply add a FS to the index + char c[50]; + itoa(i, c, 10); + strcat(c, "FS"); + rules.sections[cuSection].values[c]=*fstorm.sections[cuSection].GetValue(i); + rules.sections[cuSection].value_orig_pos[c]=rules.sections[cuSection].values.size()-1; + } + cuSection="BuildingTypes"; + for(i=0;i<fstorm.sections[cuSection].values.size();i++) + { + // we simply add a FS to the index + char c[50]; + itoa(i, c, 10); + strcat(c, "FS"); + rules.sections[cuSection].values[c]=*fstorm.sections[cuSection].GetValue(i); + rules.sections[cuSection].value_orig_pos[c]=rules.sections[cuSection].values.size()-1; + } + cuSection="SuperWeaponTypes"; + for(i=0;i<fstorm.sections[cuSection].values.size();i++) + { + // we simply add a FS to the index + char c[50]; + itoa(i, c, 10); + strcat(c, "FS"); + rules.sections[cuSection].values[c]=*fstorm.sections[cuSection].GetValue(i); + rules.sections[cuSection].value_orig_pos[c]=rules.sections[cuSection].values.size()-1; + } + + for(i=0;i<fstorm.sections.size(); i++) + { + cuSection=*fstorm.GetSectionName(i); + if(cuSection!="SuperWeaponTypes" && cuSection!="InfantryTypes" && cuSection!="VehicleTypes" && cuSection!="AircraftTypes" && cuSection!="BuildingTypes") + { + int e; + for(e=0;e<fstorm.sections[cuSection].values.size();e++) + { + CString cuValue=*fstorm.sections[cuSection].GetValueName(e); + rules.sections[cuSection].values[cuValue]=*fstorm.sections[cuSection].GetValue(e); + } + } + } + } +#else + if(bUseFirestorm && yuri_mode) // MW actually this is Yuri's Revenge + { + CIniFile rulesmd; + LoadTSIni("rulesmd.ini", &rulesmd, TRUE); + if(rulesmd.sections.size()>0) + { + rules=rulesmd; + } + } +#endif + + m_progress.SetPos(2); + //rules.DeleteLeadingSpaces(TRUE, TRUE); + //rules.DeleteEndingSpaces(TRUE, TRUE); + + PrepareHouses(); + HackRules(); + + UpdateWindow(); + + + // art.ini + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadArt")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("Art.ini", &art, FALSE); +#ifdef TS_MODE + if(bUseFirestorm) // LoadTSIni("ArtFs.ini", &art, TRUE); + { + CIniFile artfs; + LoadTSIni("artfs.ini", &artfs, TRUE); + + // MW April 8th: bugfix... we erased Movies even if there was no new data!!! + if(artfs.sections.size()) + { + + int i; + CString cuSection; + cuSection="Movies"; + art.sections.erase(cuSection); + /*for(i=0;i<artfs.sections[cuSection].values.size();i++) + { + // we simply add a FS to the index + char c[50]; + itoa(i, c, 10); + strcat(c, "FS"); + art.sections[cuSection].values[c]=*artfs.sections[cuSection].GetValue(i); + art.sections[cuSection].value_orig_pos[c]=art.sections[cuSection].values.size()-1; + }*/ + + for(i=0;i<artfs.sections.size(); i++) + { + cuSection=*artfs.GetSectionName(i); + //if(cuSection!="Movies") + { + int e; + for(e=0;e<artfs.sections[cuSection].values.size();e++) + { + CString cuValue=*artfs.sections[cuSection].GetValueName(e); + art.sections[cuSection].values[cuValue]=*artfs.sections[cuSection].GetValue(e); + if(cuSection=="Movies") art.sections[cuSection].value_orig_pos[cuValue]=artfs.sections[cuSection].GetValueOrigPos(e); + } + } + } + } + + } +#else + if(bUseFirestorm && yuri_mode) // Yuri's Revenge + { + CIniFile artmd; + LoadTSIni("artmd.ini", &artmd, TRUE); + if(artmd.sections.size()>0) + { + art.Clear(); + art=artmd; + } + } +#endif + + + + m_progress.SetPos(2); + //art.DeleteLeadingSpaces(TRUE, TRUE); + //art.DeleteEndingSpaces(TRUE, TRUE); + UpdateWindow(); + + // tutorial.ini + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadTutorial")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("Tutorial.ini", &tutorial, FALSE); + + // sound.ini + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadSound")); + m_progress.SetPos(1); + UpdateWindow(); + + + if(bUseFirestorm) + { + int b; + for(b=99;b>0;b--) + { + char p[50]; + itoa(b, p, 10); + CString name="Sound"; + if(strlen(p)<2) name+="0"; + name+=p; + name+=".ini"; + + LoadTSIni(name, &sound, FALSE); + if(sound.sections.size()>0) break; + } + + } else LoadTSIni("Sound01.ini", &sound, FALSE); + if(sound.sections.size()==0) LoadTSIni("Sound.ini", &sound, FALSE); + + m_progress.SetPos(2); + UpdateWindow(); + + // eva.INI + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadEva")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("eva.ini", &eva, FALSE); + m_progress.SetPos(2); + UpdateWindow(); + + // theme.INI + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadTheme")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("theme.ini", &theme, FALSE); + m_progress.SetPos(2); + UpdateWindow(); + + + // AI.INI + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadAI")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("Ai.ini", &ai, FALSE); +#ifdef TS_MODE + if(bUseFirestorm) LoadTSIni("aifs.ini", &ai, TRUE);; +#else + if(bUseFirestorm && yuri_mode) LoadTSIni("aimd.ini", &ai, TRUE); // YR +#endif + m_progress.SetPos(2); + UpdateWindow(); + + + const BOOL preferLocalTheater = theApp.m_Options.bPreferLocalTheaterFiles ? TRUE : FALSE; + + // Temperat.INI + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadTemperat")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("Temperat.ini", &tiles_t, FALSE, preferLocalTheater); + if(yuri_mode) LoadTSIni("TemperatMD.ini", &tiles_t, TRUE, preferLocalTheater); + m_progress.SetPos(2); + UpdateWindow(); + + // Snow.INI + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadSnow")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("Snow.ini", &tiles_s, FALSE, preferLocalTheater); + if(yuri_mode) LoadTSIni("SnowMD.ini", &tiles_s, TRUE, preferLocalTheater); + m_progress.SetPos(2); + UpdateWindow(); + + // Urban.INI + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadUrban")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("Urban.ini", &tiles_u, FALSE, preferLocalTheater); + if(yuri_mode) LoadTSIni("UrbanMD.ini", &tiles_u, TRUE, preferLocalTheater); + m_progress.SetPos(2); + UpdateWindow(); + + if(yuri_mode) + { + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadUrbanN")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("UrbanNMD.ini", &tiles_un, FALSE, preferLocalTheater); + m_progress.SetPos(2); + UpdateWindow(); + + // MW FIX: MAKE URBAN RAMPS MORPHABLE: + if(tiles_un.sections["TileSet0117"].FindName("Morphable")<0) + tiles_un.sections["TileSet0117"].values["Morphable"]="true"; + + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadLunar")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("LunarMD.ini", &tiles_l, FALSE, preferLocalTheater); + m_progress.SetPos(2); + UpdateWindow(); + + m_cap.SetWindowText(GetLanguageStringACP("LoadLoadDesert")); + m_progress.SetPos(1); + UpdateWindow(); + LoadTSIni("DesertMD.ini", &tiles_d, FALSE, preferLocalTheater); + m_progress.SetPos(2); + UpdateWindow(); + } + + + + // load Command & Conquer Rules.ini section names + LoadStrings(); + + + // ok now directdraw + m_cap.SetWindowText(GetLanguageStringACP("LoadInitDDraw")); + m_progress.SetRange(0,4); + + InitDirectDraw(); + + m_progress.SetPos(3); + UpdateWindow(); + + /*errstream << "Now calling InitPics()\n"; + errstream.flush(); + m_cap.SetWindowText(GetLanguageStringACP("LoadInitPics")); + InitPics(); + errstream << "InitPics() finished\n\n\n"; + errstream.flush();*/ + + auto delay = std::chrono::duration<double>(theApp.m_Options.fLoadScreenDelayInSeconds); + if ((std::chrono::steady_clock::now() - startTime) < delay) + { + std::this_thread::sleep_until(startTime + delay); + } + + DestroyWindow(); + +} + + + +// +// InitPics loads all graphics except terrain graphics! +void CLoading::InitPics(CProgressCtrl* prog) +{ + MEMORYSTATUS ms; + ms.dwLength=sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&ms); + int cs=ms.dwAvailPhys+ms.dwAvailPageFile; + + errstream << "InitPics() called. Available memory: " << cs << endl; + errstream.flush(); + + + + + CalcPicCount(); + + if(m_progress.m_hWnd!=NULL) m_progress.SetRange(0,m_pic_count/15+1); + + if(!theApp.m_Options.bDoNotLoadBMPs) + { + int k; + CFileFind ff; + CString bmps=(CString)AppPath+"\\pics2\\*.bmp"; + if(ff.FindFile(bmps)) + { + + BOOL lastFile=FALSE; + + for(k=0;k<m_bmp_count+1;k++) + { + + if(ff.FindNextFile()==0) + { + if(lastFile) // we already were at last file, so that´s an error here! + break; + lastFile=TRUE; + } + + try + { + pics[(LPCTSTR)ff.GetFileName()].pic = BitmapToSurface(((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->dd, *BitmapFromFile(ff.GetFilePath())).Detach(); + + DDSURFACEDESC2 desc; + memset(&desc, 0, sizeof(DDSURFACEDESC2)); + desc.dwSize = sizeof(DDSURFACEDESC2); + desc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; + ((LPDIRECTDRAWSURFACE4)pics[(LPCTSTR)ff.GetFileName()].pic)->GetSurfaceDesc(&desc); + pics[(LPCTSTR)ff.GetFileName()].wHeight = desc.dwHeight; + pics[(LPCTSTR)ff.GetFileName()].wWidth = desc.dwWidth; + pics[(LPCTSTR)ff.GetFileName()].wMaxWidth = desc.dwWidth; + pics[(LPCTSTR)ff.GetFileName()].wMaxHeight = desc.dwHeight; + pics[(LPCTSTR)ff.GetFileName()].bType = PICDATA_TYPE_BMP; + + FSunPackLib::SetColorKey(((LPDIRECTDRAWSURFACE4)(pics[(LPCTSTR)ff.GetFileName()].pic)), -1); + } + catch (const BitmapNotFound&) + { + } + + if(m_progress.m_hWnd!=NULL && k%15==0) + { + m_progress.SetPos(m_progress.GetPos()+1); + UpdateWindow(); + } + } + } + } + + DDSURFACEDESC2 desc; + + try { + pics["SCROLLCURSOR"].pic = BitmapToSurface(((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->dd, *BitmapFromResource(IDB_SCROLLCURSOR)).Detach(); + FSunPackLib::SetColorKey((LPDIRECTDRAWSURFACE4)pics["SCROLLCURSOR"].pic, -1); + memset(&desc, 0, sizeof(DDSURFACEDESC2)); + desc.dwSize = sizeof(DDSURFACEDESC2); + desc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; + ((LPDIRECTDRAWSURFACE4)pics["SCROLLCURSOR"].pic)->GetSurfaceDesc(&desc); + pics["SCROLLCURSOR"].wHeight = desc.dwHeight; + pics["SCROLLCURSOR"].wWidth = desc.dwWidth; + pics["SCROLLCURSOR"].bType = PICDATA_TYPE_BMP; + } + catch (const BitmapNotFound&) + { + } + + try { + pics["CELLTAG"].pic = BitmapToSurface(((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->dd, *BitmapFromResource(IDB_CELLTAG)).Detach(); + FSunPackLib::SetColorKey((LPDIRECTDRAWSURFACE4)pics["CELLTAG"].pic, CLR_INVALID); + memset(&desc, 0, sizeof(DDSURFACEDESC2)); + desc.dwSize = sizeof(DDSURFACEDESC2); + desc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; + ((LPDIRECTDRAWSURFACE4)pics["CELLTAG"].pic)->GetSurfaceDesc(&desc); + pics["CELLTAG"].wHeight = desc.dwHeight; + pics["CELLTAG"].wWidth = desc.dwWidth; +#ifdef RA2_MODE + pics["CELLTAG"].x = -1; + pics["CELLTAG"].y = 0; +#else + pics["CELLTAG"].x = -1; + pics["CELLTAG"].y = -1; +#endif + pics["CELLTAG"].bType = PICDATA_TYPE_BMP; + } + catch (const BitmapNotFound&) + { + } + + try + { + pics["FLAG"].pic = BitmapToSurface(((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->dd, *BitmapFromResource(IDB_FLAG)).Detach(); + FSunPackLib::SetColorKey((LPDIRECTDRAWSURFACE4)pics["FLAG"].pic, -1); + memset(&desc, 0, sizeof(DDSURFACEDESC2)); + desc.dwSize = sizeof(DDSURFACEDESC2); + desc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; + ((LPDIRECTDRAWSURFACE4)pics["FLAG"].pic)->GetSurfaceDesc(&desc); + pics["FLAG"].wHeight = desc.dwHeight; + pics["FLAG"].wWidth = desc.dwWidth; + pics["FLAG"].bType = PICDATA_TYPE_BMP; + } + catch (const BitmapNotFound&) + { + } + + + + // MW April 2nd, 2001 + // prepare 1x1 hidden tile replacement + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize=sizeof(DDSURFACEDESC2); + ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN; + ddsd.dwFlags=DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.dwWidth=f_x; + ddsd.dwHeight=f_y; + + LPDIRECTDRAWSURFACE4 srf=NULL; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->dd->CreateSurface(&ddsd, &srf, 0); + + pics["HTILE"].pic=srf; + pics["HTILE"].wHeight=ddsd.dwHeight; + pics["HTILE"].wWidth=ddsd.dwWidth; + pics["HTILE"].bType=PICDATA_TYPE_BMP; + + HDC hDC; + srf->GetDC(&hDC); + + HPEN p; + int width=1; + p=CreatePen(PS_DOT, 0, RGB(0,120,0)); + + SelectObject(hDC,p); + + POINT p1, p2, p3, p4; + p1.x=f_x/2; + p1.y=0; + p2.x=f_x/2+f_x/2; + p2.y=f_y/2; + p3.x=f_x/2-f_x/2+f_x/2-1; + p3.y=f_y/2+f_y/2-1; + p4.x=f_x/2+f_x/2-1; + p4.y=f_y/2-1; + + + SetBkMode(hDC, TRANSPARENT); + MoveToEx(hDC, p1.x,p1.y-1,NULL); + LineTo(hDC, p2.x+1,p2.y); + LineTo(hDC, p3.x,p3.y+1); + LineTo(hDC, p4.x-1, p4.y); + LineTo(hDC, p1.x, p1.y-1); + + srf->ReleaseDC(hDC); + + DeleteObject(p); + + + // new: Prepare building terrain information: + int i; + for(i=0;i<rules.sections["BuildingTypes"].values.size();i++) + { + PrepareUnitGraphic(*rules.sections["BuildingTypes"].GetValue(i)); + + } + ms.dwLength=sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&ms); + cs=ms.dwAvailPhys+ms.dwAvailPageFile; + + int piccount=pics.size(); + + errstream << "InitPics() finished and loaded " << piccount << " pictures. Available memory: " << cs << endl; + errstream.flush(); + + return; +} + +BOOL CLoading::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CString version; + version.LoadString(IDS_VERSIONTEXT); +#ifdef TS_MODE + version.LoadString(IDS_VERSIONTEXTTS); +#endif + + m_Version.SetWindowText(version); + + CString builder; + builder.LoadString(IDS_BUILTBY); + m_BuiltBy.SetWindowText(builder); + + SetDlgItemText(IDC_LBUILTBY, GetLanguageStringACP("LoadBuiltBy")); + SetDlgItemText(IDC_LVERSION, GetLanguageStringACP("LoadVersion")); + SetDlgItemText(IDC_CAP, GetLanguageStringACP("LoadLoading")); + + + + UpdateWindow(); + + return TRUE; +} + +// write a small ini file containing the FinalSun path and version (XCC needs this) +// TODO: this was made for Win9x. It does not work anymore on modern operating systems if you don't run the editor as administrator (which you should not do) +void CLoading::CreateINI() +{ + + + wchar_t iniFile_[MAX_PATH]; + CIniFile path; + CString version; + + GetWindowsDirectoryW(iniFile_, MAX_PATH); + std::string iniFile = utf16ToUtf8(iniFile_); +#ifdef RA2_MODE + iniFile += "\\FinalAlert2.ini"; +#else + iniFile += "\\FinalSun.ini"; +#endif + +#ifdef RA2_MODE + CString app = "FinalAlert"; +#else + CString app = "FinalSun"; +#endif + + version.LoadString(IDS_VERSION); + path.sections[app].values["Path"]=AppPath; + path.sections[app].values["Version"]=version; + + path.SaveFile(iniFile); +} + + + + + + + + + + +void CLoading::LoadTSIni(LPCTSTR lpFilename, CIniFile *lpIniFile, BOOL bIsExpansion, BOOL bCheckEditorDir) +{ + errstream << "LoadTSIni(" << lpFilename << "," << lpIniFile << "," << bIsExpansion << ") called" << endl; + errstream.flush(); + + if (bCheckEditorDir) { + // check if file is available in the editors application data folder + if (DoesFileExist((u8AppDataPath + lpFilename).c_str())) + { + errstream << "File found in mission editor AppData directory (" << u8AppDataPath << ")" << endl; + errstream.flush(); + if (!bIsExpansion) + lpIniFile->LoadFile(u8AppDataPath + lpFilename, TRUE); + else + lpIniFile->InsertFile(u8AppDataPath + lpFilename, NULL, TRUE); + return; + } + + // check if file is available in the editors root folder + if(DoesFileExist(CString(AppPath) + lpFilename)) + { + errstream << "File found in Mission Editor directory (" << AppPath << ")" << endl; + errstream.flush(); + if(!bIsExpansion) + lpIniFile->LoadFile((CString)AppPath+lpFilename, TRUE); + else + lpIniFile->InsertFile((CString)AppPath+lpFilename, NULL, TRUE); + return; + } + } + + if(theApp.m_Options.bSearchLikeTS) + { + + + // check if Rules.ini is available + if(DoesFileExist((CString)TSPath+lpFilename)) + { + errstream << "File found in TS directory (" << TSPath << ")" << endl; + errstream.flush(); + if(!bIsExpansion) + lpIniFile->LoadFile((CString)TSPath+lpFilename, TRUE); + else + lpIniFile->InsertFile((CString)TSPath+lpFilename, NULL, TRUE); + return; + } + + + BOOL bExpandFound=FALSE; + + + + /*int i; + for(i=1;i<101;i++) + { + if(m_hExpand[i].hExpand!=NULL) + { + if(FSunPackLib::XCC_ExtractFile(lpFilename, (CString)TSPath+(CString)"FinalSun"+lpFilename, m_hExpand[i].hExpand)) + { + + errstream << lpFilename << " found in expansion #" << i << endl; + errstream.flush(); + + //if(!bIsExpansion) + // lpIniFile->InsertFile((CString)TSPath+(CString)"FinalSun"+lpFilename, NULL); + //else + lpIniFile->InsertFile((CString)TSPath+(CString)"FinalSun"+lpFilename, NULL, TRUE); + + DeleteFile((CString)TSPath+(CString)"FinalSun"+lpFilename); + + bExpandFound=TRUE; + } + + } + }*/ + + HMIXFILE hMix=FindFileInMix(lpFilename); + if(hMix) + { + if(FSunPackLib::XCC_ExtractFile(lpFilename, (CString)TSPath+(CString)"FinalSun"+lpFilename, hMix)) + { + + errstream << lpFilename << " found " << endl; + errstream.flush(); + + //if(!bIsExpansion) + // lpIniFile->InsertFile((CString)TSPath+(CString)"FinalSun"+lpFilename, NULL); + //else + lpIniFile->InsertFile((CString)TSPath+(CString)"FinalSun"+lpFilename, NULL, TRUE); + + DeleteFile((CString)TSPath+(CString)"FinalSun"+lpFilename); + + bExpandFound=TRUE; + } + } + + if(!bIsExpansion && !bExpandFound) + { + // not found, go ahead if this is not a expansion only file... + FSunPackLib::XCC_ExtractFile(lpFilename,(CString)TSPath+(CString)"FinalSun"+lpFilename, m_hLocal); + + lpIniFile->LoadFile((CString)TSPath+(CString)"FinalSun"+lpFilename, TRUE); + + DeleteFile((CString)TSPath+(CString)"FinalSun"+lpFilename); + } + + + } + else if(bIsExpansion==FALSE) + { + FSunPackLib::XCC_ExtractFile(lpFilename,(CString)TSPath+(CString)"FinalSun"+lpFilename, m_hLocal); + + lpIniFile->LoadFile((CString)TSPath+(CString)"FinalSun"+lpFilename, TRUE); + DeleteFile((CString)TSPath+(CString)"FinalSun"+lpFilename); + return; + } +} + + +void CLoading::InitSHPs(CProgressCtrl* prog) +{ + MEMORYSTATUS ms; + ms.dwLength=sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&ms); + int cs=ms.dwAvailPhys+ms.dwAvailPageFile; + + errstream << "InitSHPs() called. Available memory: " << cs << endl; + errstream.flush(); + + int i; + + // overlay: + if(!theApp.m_Options.bDoNotLoadOverlayGraphics) + for(i=0;i<rules.sections["OverlayTypes"].values.size();i++) + { + LoadOverlayGraphic(*rules.sections["OverlayTypes"].GetValue(i), i); + if(m_progress.m_hWnd!=NULL && i%15==0) { + m_progress.SetPos(m_progress.GetPos()+1); + UpdateWindow(); + } + } + + if(!theApp.m_Options.bDoNotLoadVehicleGraphics) + for(i=0;i<rules.sections["VehicleTypes"].values.size();i++) + { + LoadUnitGraphic(*rules.sections["VehicleTypes"].GetValue(i)); + if(m_progress.m_hWnd!=NULL && i%15==0) { + m_progress.SetPos(m_progress.GetPos()+1); + UpdateWindow(); + } + } + + if(!theApp.m_Options.bDoNotLoadInfantryGraphics) + for(i=0;i<rules.sections["InfantryTypes"].values.size();i++) + { + LoadUnitGraphic(*rules.sections["InfantryTypes"].GetValue(i)); + if(m_progress.m_hWnd!=NULL && i%15==0){ + m_progress.SetPos(m_progress.GetPos()+1); + UpdateWindow(); + } + } + + if(!theApp.m_Options.bDoNotLoadBuildingGraphics) + for(i=0;i<rules.sections["BuildingTypes"].values.size();i++) + { + LoadUnitGraphic(*rules.sections["BuildingTypes"].GetValue(i)); + if(m_progress.m_hWnd!=NULL && i%15==0) { + m_progress.SetPos(m_progress.GetPos()+1); + UpdateWindow(); + } + } + + if(!theApp.m_Options.bDoNotLoadAircraftGraphics) + for(i=0;i<rules.sections["AircraftTypes"].values.size();i++) + { + LoadUnitGraphic(*rules.sections["AircraftTypes"].GetValue(i)); + if(m_progress.m_hWnd!=NULL && i%15==0) { + m_progress.SetPos(m_progress.GetPos()+1); + UpdateWindow(); + } + } + + if(!theApp.m_Options.bDoNotLoadTreeGraphics) + for(i=0;i<rules.sections["TerrainTypes"].values.size();i++) + { + LoadUnitGraphic(*rules.sections["TerrainTypes"].GetValue(i)); + if(m_progress.m_hWnd!=NULL && i%15==0) + { + m_progress.SetPos(m_progress.GetPos()+1); + UpdateWindow(); + } + } + +#ifdef SMUDGE_SUPP + for(i=0;i<rules.sections["SmudgeTypes"].values.size();i++) + { + LoadUnitGraphic(*rules.sections["SmudgeTypes"].GetValue(i)); + /*if(m_progress.m_hWnd!=NULL && i%15==0) + { + m_progress.SetPos(m_progress.GetPos()+1); + UpdateWindow(); + }*/ + } +#endif + +} + +/* +CLoading::LoadUnitGraphic(); + +Matze: +June 15th: +- Added bib support, works fine. +*/ + +#ifdef NOSURFACES_OBJECTS // palettized + +// blit util +__forceinline void Blit_Pal(BYTE* dst, int x, int y, int dwidth, int dheight, BYTE* src, int swidth, int sheight) +{ + + if(src==NULL || dst==NULL) return; + + + + if(x+swidth<0 || y+sheight<0) return; + if(x>=dwidth || y>=dheight) return; + + + RECT blrect; + RECT srcRect; + srcRect.left=0; + srcRect.top=0; + srcRect.right=swidth; + srcRect.bottom=sheight; + blrect.left=x; + if(blrect.left<0) + { + srcRect.left=1-blrect.left; + blrect.left=1; + } + blrect.top=y; + if(blrect.top<0) + { + srcRect.top=1-blrect.top; + blrect.top=1; + } + blrect.right=(x+swidth); + if(x+swidth>dwidth) + { + srcRect.right=swidth-((x+swidth)-dwidth); + blrect.right=dwidth; + } + blrect.bottom=(y+sheight); + if(y+sheight>dheight) + { + srcRect.bottom=sheight-((y+sheight)-dheight); + blrect.bottom=dheight; + } + + + int i,e; + for(i=srcRect.left;i<srcRect.right;i++) + { + for(e=srcRect.top;e<srcRect.bottom;e++) + { + BYTE& val=src[i+e*swidth]; + if(val) + { + BYTE* dest=dst+(blrect.left+i)+(blrect.top+e)*dwidth; + *dest=val; + } + } + } + +} + +__forceinline void Blit_PalD(BYTE* dst, RECT blrect, const BYTE* src, RECT srcRect, int swidth, int dwidth, int sheight, int dheight, const BYTE* const srcMask=nullptr) +{ + + if(src==NULL || dst==NULL) return; + + if(blrect.left+swidth<0 || blrect.top+sheight<0) return; + if(blrect.left>=dwidth || blrect.top>=dheight) return; + + int x=blrect.left; + int y=blrect.top; + + int i,e; + for(i=srcRect.left;i<srcRect.right;i++) + { + for(e=srcRect.top;e<srcRect.bottom;e++) + { + auto pos = i + e * swidth; + const BYTE& val=src[pos]; + if(blrect.left+i>0 && blrect.top+e>0 && blrect.left+i<dwidth && blrect.top+e<dheight) + { + if (srcMask) + { + if (srcMask[pos] == 0) + continue; + } + else + { + if (val == 0) + continue; + } + + BYTE* dest=dst+(blrect.left+i)+(blrect.top+e)*dwidth; + *dest=val; + } + } + } + +} + +#ifdef TS_MODE +const Vec3f lightDirection = Vec3f(1.0f, 0.0f, -1.0f).normalize(); +#else +const Vec3f lightDirection = Vec3f(1.0f, 0.0f, -1.0f).normalize(); +#endif + + +HTSPALETTE CLoading::GetIsoPalette(char theat) +{ + HTSPALETTE isoPalette = m_hPalIsoTemp; + switch (theat) + { + case 'T': + case 'G': + isoPalette = m_hPalIsoTemp; + break; + case 'A': + isoPalette = m_hPalIsoSnow; + break; + case 'U': + isoPalette = m_hPalIsoUrb; + break; + case 'N': + isoPalette = m_hPalIsoUbn; + break; + case 'D': + isoPalette = m_hPalIsoDes; + break; + case 'L': + isoPalette = m_hPalIsoLun; + break; + } + return isoPalette; +} + +HTSPALETTE CLoading::GetUnitPalette(char theat) +{ + HTSPALETTE isoPalette = m_hPalUnitTemp; + switch (theat) + { + case 'T': + case 'G': + isoPalette = m_hPalUnitTemp; + break; + case 'A': + isoPalette = m_hPalUnitSnow; + break; + case 'U': + isoPalette = m_hPalUnitUrb; + break; + case 'N': + isoPalette = m_hPalUnitUbn; + break; + case 'D': + isoPalette = m_hPalUnitDes; + break; + case 'L': + isoPalette = m_hPalUnitLun; + break; + } + return isoPalette; +} + +CString theatToSuffix(char theat) +{ + if (theat == 'T') return ".tem"; + else if (theat == 'A') return ".sno"; + else if (theat == 'U') return ".urb"; + else if (theat == 'L') return ".lun"; + else if (theat == 'D') return ".des"; + else if (theat == 'N') return ".ubn"; + return ".tem"; +} + +char suffixToTheat(const CString& suffix) +{ + if (suffix == ".tem") + return 'T'; + else if (suffix == ".sno") + return 'A'; + else if (suffix == ".urb") + return 'U'; + else if (suffix == ".lun") + return 'L'; + else if (suffix == ".des") + return 'D'; + else if (suffix == ".ubn") + return 'N'; + return 'T'; +} + +std::optional<FindShpResult> CLoading::FindUnitShp(const CString& image, char preferred_theat, const CIniFileSection& artSection) +{ + if (image.IsEmpty()) + return std::nullopt; + + const char kTheatersToTry[] = { preferred_theat, 'G', 'T', 'A', 'U', 'N', 'D', 'L', 0}; + const CString kSuffixesToTry[] = { theatToSuffix(preferred_theat), ".tem", ".sno", ".urb", ".lun", ".des", ".ubn", ""}; + + const char first = image.GetAt(0); + const bool firstCharSupportsTheater = first == 'G' || first == 'N' || first == 'C' || first == 'Y'; + + HTSPALETTE forcedPalette = 0; + const auto& unitPalettePrefixes = g_data.sections["ForceUnitPalettePrefix"]; + if (unitPalettePrefixes.end() != std::find_if(unitPalettePrefixes.begin(), unitPalettePrefixes.end(), [&image](const auto& pair) {return image.Find(pair.second) == 0;})) + { + forcedPalette = GetUnitPalette(preferred_theat); + } + + const auto& isoPalettePrefixes = g_data.sections["ForceIsoPalettePrefix"]; + if (isoPalettePrefixes.end() != std::find_if(isoPalettePrefixes.begin(), isoPalettePrefixes.end(), [&image](const auto& pair) {return image.Find(pair.second) == 0;})) + { + forcedPalette = GetIsoPalette(preferred_theat); + } + + const bool isTheater = isTrue(artSection.GetValueByName("Theater")); + const bool isNewTheater = isTrue(artSection.GetValueByName("NewTheater")); + const bool terrainPalette = isTrue(artSection.GetValueByName("TerrainPalette")); + + auto unitOrIsoPalette = terrainPalette ? GetIsoPalette(preferred_theat) : GetUnitPalette(preferred_theat); + + HMIXFILE curMixFile = 0; + CString curFilename = image + ".shp"; + TheaterChar curMixTheater = TheaterChar::None; + char curTheater = 'G'; + CString curSuffix; + + // Phase 0: theater with .tem, .sno etc + if (isTheater) + { + for (int t = 0; !(curSuffix = kSuffixesToTry[t]).IsEmpty(); ++t) + { + curFilename = image + curSuffix; + curFilename.MakeLower(); + curMixFile = FindFileInMix(curFilename, &curMixTheater); + if (curMixFile) + return FindShpResult(curMixFile, curMixTheater, curFilename, toTheaterChar(suffixToTheat(curSuffix)), forcedPalette ? forcedPalette : GetIsoPalette(suffixToTheat(curSuffix))); + } + } + // Phase 1: if NewTheater is enabled and first character indicates support, try with real theater, then in order of kTheatersToTry + // Otherwise, + if (isNewTheater) + { + if (firstCharSupportsTheater) + { + /*curFilename.SetAt(1, preferred_theat); + curMixFile = FindFileInMix(curFilename, &curMixTheater); + if (curMixFile) + return FindShpResult(curMixFile, curMixTheater, curFilename, toTheaterChar(preferred_theat), GetUnitPalette(preferred_theat));*/ + for (int t = 0; curTheater=kTheatersToTry[t]; ++t) + { + curFilename.SetAt(1, curTheater); + curMixFile = FindFileInMix(curFilename, &curMixTheater); + if (curMixFile) + return FindShpResult(curMixFile, curMixTheater, curFilename, toTheaterChar(curTheater), forcedPalette ? forcedPalette : unitOrIsoPalette); + } + } + } + // Phase 2: try again even if isNewTheater is not true but the first char signals it should support theaters + if (firstCharSupportsTheater) + { + /*curFilename.SetAt(1, preferred_theat); + curMixFile = FindFileInMix(curFilename, &curMixTheater); + if (curMixFile) + return FindShpResult(curMixFile, curMixTheater, curFilename, toTheaterChar(preferred_theat), GetUnitPalette(preferred_theat));*/ + for (int t = 0; curTheater = kTheatersToTry[t]; ++t) + { + curFilename.SetAt(1, curTheater); + curMixFile = FindFileInMix(curFilename, &curMixTheater); + if (curMixFile) + return FindShpResult(curMixFile, curMixTheater, curFilename, toTheaterChar(curTheater), forcedPalette ? forcedPalette : unitOrIsoPalette); + } + } + // Phase 3: try unchanged filename + curFilename = image + ".shp"; + curMixFile = FindFileInMix(curFilename, &curMixTheater); + if (curMixFile) + return FindShpResult(curMixFile, curMixTheater, curFilename, toTheaterChar(preferred_theat), forcedPalette ? forcedPalette : unitOrIsoPalette); + // Phase 4: try lowercase and otherwise unchanged filename + curFilename = image + ".shp"; + curFilename.MakeLower(); + curMixFile = FindFileInMix(curFilename, &curMixTheater); + if (curMixFile) + return FindShpResult(curMixFile, curMixTheater, curFilename, toTheaterChar(preferred_theat), forcedPalette ? forcedPalette : unitOrIsoPalette); + // Phase 5: try with .tem, .sno etc endings with preferred theater + for (int t = 0; !(curSuffix = kSuffixesToTry[t]).IsEmpty(); ++t) + { + curFilename = image + curSuffix; + curFilename.MakeLower(); + curMixFile = FindFileInMix(curFilename, &curMixTheater); + if (curMixFile) + return FindShpResult(curMixFile, curMixTheater, curFilename, toTheaterChar(suffixToTheat(curSuffix)), forcedPalette ? forcedPalette : GetIsoPalette(suffixToTheat(curSuffix))); + } + // Phase 6: try with theater in 2nd char even if first char does not indicate support + curFilename = image + ".shp"; + for (int t = 0; curTheater = kTheatersToTry[t]; ++t) + { + curFilename.SetAt(1, curTheater); + curMixFile = FindFileInMix(curFilename, &curMixTheater); + if (curMixFile) + return FindShpResult(curMixFile, curMixTheater, curFilename, toTheaterChar(curTheater), forcedPalette ? forcedPalette : GetIsoPalette(curTheater)); + } + + return std::nullopt; +} + +int lepton_to_screen_y(int leptons) +{ + return leptons * f_y / 256; +} + +BOOL CLoading::LoadUnitGraphic(LPCTSTR lpUnittype) +{ + errstream << "Loading: " << lpUnittype << endl; + errstream.flush(); + + last_succeeded_operation=10; + + CString _rules_image; // the image used + CString filename; // filename of the image + char theat=cur_theat; // standard theater char is t (Temperat). a is snow. + + BOOL bAlwaysSetChar=FALSE; // second char is always theater, even if NewTheater not specified! + WORD wStep=1; // step is 1 for infantry, buildings, etc, and for shp vehicles it specifies the step rate between every direction + WORD wStartWalkFrame=0; // for examply cyborg reaper has another walk starting frame + int iTurretOffset=0; // used for centering y pos of turret (if existing) (for vehicles) + const BOOL bStructure=rules.sections["BuildingTypes"].FindValue(lpUnittype)>=0; // is this a structure? + const BOOL bVehicle = rules.sections["VehicleTypes"].FindValue(lpUnittype) >= 0; // is this a structure? + + BOOL bPowerUp=rules.sections[lpUnittype].values["PowersUpBuilding"]!=""; + + + CIsoView& v=*((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + + _rules_image=lpUnittype; + if(rules.sections[lpUnittype].values.find("Image")!=rules.sections[lpUnittype].values.end()) + _rules_image=rules.sections[lpUnittype].values["Image"]; + + CString _art_image = _rules_image; + if(art.sections[_rules_image].values.find("Image")!=art.sections[_rules_image].values.end()) + { + if(!isTrue(g_data.sections["IgnoreArtImage"].values[_rules_image])) + _art_image=art.sections[_rules_image].values["Image"]; + } + + const CString& image = _art_image; + const auto& rulesSection = rules.sections[lpUnittype]; + const auto& artSection = art.sections[image]; + + if(!isTrue(art.sections[image].values["Voxel"])) // is it a shp graphic? + { + try + { + + auto shp = FindUnitShp(image, cur_theat, artSection); + if (!shp) + { + errstream << "Building SHP in theater " << cur_theat << " not found: " << image << endl; + errstream.flush(); + missingimages[lpUnittype] = TRUE; + return FALSE; + } + + filename = shp->filename; + HTSPALETTE hPalette = shp->palette; + const auto hShpMix = shp->mixfile; + theat = static_cast<char>(shp->theat); + auto limited_to_theater = isTrue(artSection.GetValueByName("TerrainPalette")) ? shp->mixfile_theater : TheaterChar::None; + + + SHPHEADER head; + int superanim_1_zadjust=0; + int superanim_2_zadjust=0; + int superanim_3_zadjust=0; + int superanim_4_zadjust=0; + + CString turretanim_name; + CString turretanim_filename; + CString barrelanim_filename; + BYTE* bib=NULL; + SHPHEADER bib_h; + BYTE* activeanim=NULL; + SHPHEADER activeanim_h; + BYTE* idleanim=NULL; + SHPHEADER idleanim_h; + BYTE* activeanim2=NULL; + SHPHEADER activeanim2_h; + BYTE* activeanim3=NULL; + SHPHEADER activeanim3_h; + BYTE* superanim1=NULL; + SHPHEADER superanim1_h; + BYTE* superanim2=NULL; + SHPHEADER superanim2_h; + BYTE* superanim3=NULL; + SHPHEADER superanim3_h; + BYTE* superanim4=NULL; + SHPHEADER superanim4_h; + BYTE* specialanim1=NULL; + SHPHEADER specialanim1_h; + BYTE* specialanim2=NULL; + SHPHEADER specialanim2_h; + BYTE* specialanim3=NULL; + SHPHEADER specialanim3_h; + BYTE* specialanim4=NULL; + SHPHEADER specialanim4_h; + BYTE** lpT=NULL; + SHPHEADER* lpT_h=NULL; + std::vector<BYTE> turretColors[8]; + std::vector<BYTE> turretLighting[8]; + std::vector<BYTE> vxlBarrelColors[8]; + std::vector<BYTE> vxlBarrelLighting[8]; + SHPHEADER turrets_h[8]; + SHPIMAGEHEADER turretinfo[8]; + SHPHEADER barrels_h[8]; + SHPIMAGEHEADER barrelinfo[8]; + + + if(hShpMix>0) + { + + std::string shp_mixfile; + if (FSunPackLib::XCC_GetMixName(hShpMix, shp_mixfile)) + { + errstream << (LPCTSTR)filename << " found "; + errstream << " in " << shp_mixfile << endl; + errstream.flush(); + } + //hShpMix=20; + + + if(rules.sections[lpUnittype].values["Bib"]!="no") // seems to be ignored by TS, art.ini overwrites??? + { + LoadBuildingSubGraphic("BibShape", artSection, bAlwaysSetChar, theat, hShpMix, bib_h, bib); + } + + LoadBuildingSubGraphic("ActiveAnim", artSection, bAlwaysSetChar, theat, hShpMix, activeanim_h, activeanim); + LoadBuildingSubGraphic("IdleAnim", artSection, bAlwaysSetChar, theat, hShpMix, idleanim_h, idleanim); + LoadBuildingSubGraphic("ActiveAnim2", artSection, bAlwaysSetChar, theat, hShpMix, activeanim2_h, activeanim2); + LoadBuildingSubGraphic("ActiveAnim3", artSection, bAlwaysSetChar, theat, hShpMix, activeanim3_h, activeanim3); + if (!isTrue(g_data.sections["IgnoreSuperAnim1"].values[image])) + LoadBuildingSubGraphic("SuperAnim", artSection, bAlwaysSetChar, theat, hShpMix, superanim1_h, superanim1); + if (!isTrue(g_data.sections["IgnoreSuperAnim2"].values[image])) + LoadBuildingSubGraphic("SuperAnimTwo", artSection, bAlwaysSetChar, theat, hShpMix, superanim2_h, superanim2); + if (!isTrue(g_data.sections["IgnoreSuperAnim3"].values[image])) + LoadBuildingSubGraphic("SuperAnimThree", artSection, bAlwaysSetChar, theat, hShpMix, superanim3_h, superanim3); + if (!isTrue(g_data.sections["IgnoreSuperAnim4"].values[image])) + LoadBuildingSubGraphic("SuperAnimFour", artSection, bAlwaysSetChar, theat, hShpMix, superanim4_h, superanim4); + LoadBuildingSubGraphic("SpecialAnim", artSection, bAlwaysSetChar, theat, hShpMix, specialanim1_h, specialanim1); + LoadBuildingSubGraphic("SpecialAnimTwo", artSection, bAlwaysSetChar, theat, hShpMix, specialanim2_h, specialanim2); + LoadBuildingSubGraphic("SpecialAnimThree", artSection, bAlwaysSetChar, theat, hShpMix, specialanim3_h, specialanim3); + LoadBuildingSubGraphic("SpecialAnimFour", artSection, bAlwaysSetChar, theat, hShpMix, specialanim4_h, specialanim4); + + BOOL bVoxelTurret = FALSE; + BOOL bVoxelBarrel = FALSE; + + FSunPackLib::VoxelNormalClass vnc = FSunPackLib::VoxelNormalClass::Unknown; + + if (isTrue(rules.sections[image].values["Turret"])) + { + turretanim_name = rules.sections[image].values["TurretAnim"]; + auto vxl_turretanim_filename = turretanim_name.IsEmpty() ? image + "tur.vxl" : turretanim_name + ".vxl"; + auto vxl_barrelanim_filename = image + "barl.vxl"; + if (art.sections[turretanim_name].values.find("Image") != art.sections[turretanim_name].values.end()) + vxl_turretanim_filename = art.sections[turretanim_name].values["Image"] + ".vxl"; + + if (bStructure && turretanim_name.GetLength() > 0 && isFalse(rules.sections[image].values["TurretAnimIsVoxel"])) + { + turretanim_filename = turretanim_name + ".shp"; + if (art.sections[turretanim_name].values.find("Image") != art.sections[turretanim_name].values.end()) turretanim_filename = art.sections[turretanim_name].values["Image"] + ".shp"; + + if (isTrue(artSection.GetValueByName("NewTheater"))) + { + auto tmp = turretanim_filename; + tmp.SetAt(1, theat); + if (FSunPackLib::XCC_DoesFileExist(tmp, hShpMix)) + turretanim_filename = tmp; + } + + + FSunPackLib::SetCurrentSHP(turretanim_filename, hShpMix); + FSunPackLib::XCC_GetSHPHeader(&head); + + int iStartTurret = 0; + const WORD wAnimCount = 4; // anims between each "normal" direction, seems to be hardcoded + + int i; + + for (i = 0;i < 8;i++) + { + if (iStartTurret + i * wAnimCount < head.c_images) + { + FSunPackLib::XCC_GetSHPImageHeader(iStartTurret + i * wAnimCount, &turretinfo[i]); + FSunPackLib::XCC_GetSHPHeader(&turrets_h[i]); + FSunPackLib::LoadSHPImage(iStartTurret + i * wAnimCount, turretColors[i]); + turretLighting[i].clear(); + } + + } + } + else if ( + (bStructure && turretanim_name.GetLength() > 0 && isTrue(rules.sections[image].values["TurretAnimIsVoxel"])) + || (!bStructure && (FindFileInMix(vxl_turretanim_filename) || FindFileInMix(vxl_barrelanim_filename))) + ) + { + turretanim_filename = vxl_turretanim_filename; + barrelanim_filename = vxl_barrelanim_filename; + + HMIXFILE hVXL = FindFileInMix(vxl_turretanim_filename); + HMIXFILE hBarl = FindFileInMix(vxl_barrelanim_filename); + + if (artSection.values.find("TurretOffset") != art.sections[image].values.end()) + iTurretOffset = atoi(art.sections[image].values["TurretOffset"]); + Vec3f turretModelOffset(iTurretOffset / 6.0f, 0.0f, 0.0f); + + + if (hVXL) + { + bVoxelTurret = TRUE; + + if ( + FSunPackLib::SetCurrentVXL(turretanim_filename, hVXL) + ) + { + // we assume the voxel normal class is always the same for the combined voxels + FSunPackLib::GetVXLSectionInfo(0, vnc); + + int i; + + for (i = 0;i < 8;i++) + { + float r_x, r_y, r_z; + + + const int dir = bVehicle ? ((i + 1) % 8) : i; + r_x = 300; + r_y = 0; + r_z = 45 * dir + 90; + + // convert + const double pi = 3.141592654; + const Vec3f rotation(r_x / 180.0f * pi, r_y / 180.0f * pi, r_z / 180.0f * pi); + + + RECT r; + int center_x, center_y; + if (! + FSunPackLib::LoadVXLImage(*m_voxelNormalTables, lightDirection, rotation, turretModelOffset, turretColors[i], turretLighting[i], ¢er_x, ¢er_y, 0, 0, 0, 0, 0, &r) + ) + { + + } + else + { + turrets_h[i].cx = r.right - r.left; + turrets_h[i].cy = r.bottom - r.top; + + turretinfo[i].x = center_x; + turretinfo[i].y = center_y; + turretinfo[i].cx = r.right - r.left; + turretinfo[i].cy = r.bottom - r.top; + + } + + } + } + } + if (hBarl) + { + bVoxelBarrel = TRUE; + + if ( + FSunPackLib::SetCurrentVXL(barrelanim_filename, hBarl) + ) + { + // we assume the voxel normal class is always the same for the combined voxels + FSunPackLib::GetVXLSectionInfo(0, vnc); + + int i; + + for (i = 0;i < 8;i++) + { + float r_x, r_y, r_z; + + + const int dir = bVehicle ? ((i + 1) % 8) : i; + r_x = 300; + r_y = 0; + r_z = 45 * dir + 90; + + // convert + const double pi = 3.141592654; + const Vec3f rotation(r_x / 180.0f * pi, r_y / 180.0f * pi, r_z / 180.0f * pi); + + + RECT r; + int center_x, center_y; + if (! + FSunPackLib::LoadVXLImage(*m_voxelNormalTables, lightDirection, rotation, turretModelOffset, vxlBarrelColors[i], vxlBarrelLighting[i], ¢er_x, ¢er_y, atoi(rules.sections[image].values["TurretAnimZAdjust"]), 0, 0, 0, 0, &r) + ) + { + + } + else + { + barrels_h[i].cx = r.right - r.left; + barrels_h[i].cy = r.bottom - r.top; + + barrelinfo[i].x = center_x; + barrelinfo[i].y = center_y; + barrelinfo[i].cx = r.right - r.left; + barrelinfo[i].cy = r.bottom - r.top; + + } + + } + } + } + } + } + + + if(art.sections[image].values.find("WalkFrames")!=art.sections[image].values.end()) + wStep=atoi(art.sections[image].values["WalkFrames"]); + if(art.sections[image].values.find("StartWalkFrame")!=art.sections[image].values.end()) + wStartWalkFrame=atoi(art.sections[image].values["StartWalkFrame"]); + + if(art.sections[image].values["Palette"]=="lib") + hPalette=m_hPalLib; + + BOOL bSuccess=FSunPackLib::SetCurrentSHP(filename, hShpMix); + if( + !bSuccess + ) + { + filename=image+".sno"; + if(cur_theat=='T' || cur_theat=='U' /* || cur_theat=='N' ? */) hPalette=m_hPalIsoTemp; + HMIXFILE hShpMix=FindFileInMix(filename); + bSuccess=FSunPackLib::SetCurrentSHP(filename, hShpMix); + + if(!bSuccess) + { + missingimages[lpUnittype]=TRUE; + } + } + + if(bSuccess) + { + + FSunPackLib::XCC_GetSHPHeader(&head); + int i; + int maxPics=head.c_images; + if(maxPics>8) maxPics=8; // we only need 8 pictures for every direction! + if(bStructure && !bPowerUp && !isTrue(rules.sections[image].values["Turret"])) maxPics=1; + if(bVoxelTurret) maxPics=8; + + + + if(!bStructure && rules.sections[image].values["Turret"]=="yes") + { + int iStartTurret=wStartWalkFrame+8*wStep; + const WORD wAnimCount=4; // anims between each "normal" direction, seems to be hardcoded + + int i; + + for(i=0;i<8;i++) + { + if(iStartTurret+i*wAnimCount<head.c_images) + { + FSunPackLib::XCC_GetSHPImageHeader(iStartTurret+i*wAnimCount, &turretinfo[i]); + FSunPackLib::XCC_GetSHPHeader(&turrets_h[i]); + FSunPackLib::LoadSHPImage(iStartTurret+i*wAnimCount, turretColors[i]); + } + + } + } + + + + // create an array of pointers to directdraw surfaces + lpT=new(BYTE*[maxPics]); + memset(lpT, 0, sizeof(BYTE)*maxPics); + std::vector<std::vector<BYTE>> lighting(maxPics); + std::vector<SHPIMAGEHEADER> shp_image_headers(maxPics); + + if(bVoxelTurret && bStructure) + { + for(i=0;i<maxPics; i++) + { + FSunPackLib::LoadSHPImage(0, 1, &lpT[i]); + FSunPackLib::XCC_GetSHPImageHeader(0, &shp_image_headers[i]); + } + } + else if(wStep==1 && (rules.sections[lpUnittype].values["PowersUpBuilding"].GetLength()==0 || !isTrue(rules.sections[lpUnittype].values["Turret"]))) + { // standard case... + + FSunPackLib::LoadSHPImage(wStartWalkFrame, maxPics, lpT); + for (int i = 0; i < maxPics; ++i) + FSunPackLib::XCC_GetSHPImageHeader(wStartWalkFrame + i, &shp_image_headers[i]); + + } + else if(rules.sections[lpUnittype].values["PowersUpBuilding"].GetLength()!=0 && isTrue(rules.sections[lpUnittype].values["Turret"])) + { // a "real" turret (vulcan cannon, etc...) + for(i=0;i<maxPics; i++) + { + FSunPackLib::LoadSHPImage(i*4, 1, &lpT[i]); + FSunPackLib::XCC_GetSHPImageHeader(i*4, &shp_image_headers[i]); + } + } + else + { + // walk frames used + for(i=0;i<maxPics; i++) + { + const int dir = bVehicle ? ((i + 1) % 8) : i; + const int pic_in_file = dir * wStep + wStartWalkFrame; + FSunPackLib::LoadSHPImage(pic_in_file, 1, &lpT[i]); + FSunPackLib::XCC_GetSHPImageHeader(pic_in_file, &shp_image_headers[i]); + } + } + + for(i=0; i<maxPics; i++) + { + int pic_in_file=i; + if(bStructure && bVoxelTurret) pic_in_file=0; + SHPIMAGEHEADER imghead = shp_image_headers[i]; + //FSunPackLib::XCC_GetSHPImageHeader(pic_in_file, &imghead); + + if(bib!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, bib, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, 0, head.cx, head.cy, bib, bib_h.cx, bib_h.cy); + + imghead.cx=head.cx-imghead.x; // update size of main graphic + imghead.cy=head.cy-imghead.y; + + } + + if(activeanim!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, activeanim, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, 0, head.cx, head.cy, activeanim, activeanim_h.cx, activeanim_h.cy); + + + } + + if(idleanim!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, idleanim, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, 0, head.cx, head.cy, idleanim, idleanim_h.cx, idleanim_h.cy); + + + } + + if(activeanim2!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, activeanim2, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, 0, head.cx, head.cy, activeanim2, activeanim2_h.cx, activeanim2_h.cy); + + } + + if(activeanim3!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, activeanim3, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, 0, head.cx, head.cy, activeanim3, activeanim3_h.cx, activeanim3_h.cy); + + } + + if(superanim1!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, superanim1, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, superanim_1_zadjust, head.cx, head.cy, superanim1, superanim1_h.cx, superanim1_h.cy); + + + } + + if(superanim2!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, superanim2, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, superanim_2_zadjust, head.cx, head.cy, superanim2, superanim2_h.cx, superanim2_h.cy); + + + } + + if(superanim3!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, superanim3, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, superanim_3_zadjust, head.cx, head.cy, superanim3, superanim3_h.cx, superanim3_h.cy); + + + } + + if(superanim4!=NULL && strcmp(lpUnittype, "YAGNTC")!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, superanim4, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, superanim_4_zadjust, head.cx, head.cy, superanim4, superanim4_h.cx, superanim4_h.cy); + + + } + + if(specialanim1!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, specialanim1, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, 0, head.cx, head.cy, specialanim1, specialanim1_h.cx, specialanim1_h.cy); + + + } + + if(specialanim2!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, specialanim2, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, 0, head.cx, head.cy, specialanim2, specialanim2_h.cx, specialanim2_h.cy); + + } + + if(specialanim3!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, specialanim3, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, 0, head.cx, head.cy, specialanim3, specialanim3_h.cx, specialanim3_h.cy); + + + } + + if(specialanim4!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + //lpT[i]->Blt(NULL, specialanim4, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + Blit_Pal(lpT[i], 0, 0, head.cx, head.cy, specialanim4, specialanim4_h.cx, specialanim4_h.cy); + + } + + if (!vxlBarrelLighting[i].empty() || !turretLighting[i].empty()) + lighting[i].resize(head.cx * head.cy, 46); // value needs to lead to 1.0 lighting + + // barrels hidden behind turret: + if(!vxlBarrelColors[i].empty() && (i == 1 || i == 0 || i == 7)) + { + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = barrels_h[i].cx; + ddsd.dwHeight = barrels_h[i].cy; + + int XMover, YMover; + char c[50]; + itoa(i, c, 10); +#ifdef RA2_MODE + XMover = atoi(g_data.sections["BuildingVoxelBarrelsRA2"].values[(CString)lpUnittype + "X"]); + YMover = atoi(g_data.sections["BuildingVoxelBarrelsRA2"].values[(CString)lpUnittype + "Y"]); + XMover += atoi(g_data.sections["BuildingVoxelBarrelsRA2"].values[(CString)lpUnittype + (CString)"X" + c]); + YMover += atoi(g_data.sections["BuildingVoxelBarrelsRA2"].values[(CString)lpUnittype + (CString)"Y" + c]); +#else + XMover = atoi(g_data.sections["BuildingVoxelBarrels"].values[(CString)lpUnittype + "X"]); + YMover = atoi(g_data.sections["BuildingVoxelBarrels"].values[(CString)lpUnittype + "Y"]); +#endif + + RECT srcRect, destRect; + + int mx = head.cx / 2 + atoi(rules.sections[image].values["TurretAnimX"]) - barrelinfo[i].x; + int my = head.cy / 2 + atoi(rules.sections[image].values["TurretAnimY"]) - barrelinfo[i].y; + + srcRect.top = 0; + srcRect.left = 0; + srcRect.right = ddsd.dwWidth; + srcRect.bottom = ddsd.dwHeight; + destRect.top = YMover + my; + destRect.left = XMover + mx; + destRect.right = destRect.left + ddsd.dwWidth; + destRect.bottom = destRect.top + ddsd.dwHeight; + + + errstream << "vxl barrel: " << i << " size: " << ddsd.dwWidth << " " << ddsd.dwHeight << " at " << destRect.left << " " << destRect.top << endl; + errstream.flush(); + Blit_PalD(lpT[i], destRect, vxlBarrelColors[i].data(), srcRect, ddsd.dwWidth, head.cx, ddsd.dwHeight, head.cy); + Blit_PalD(lighting[i].data(), destRect, vxlBarrelLighting[i].data(), srcRect, ddsd.dwWidth, head.cx, ddsd.dwHeight, head.cy, vxlBarrelColors[i].data()); + + } + + + if(!turretColors[i].empty()) + { + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize=sizeof(DDSURFACEDESC2); + ddsd.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + //turrets[i]->GetSurfaceDesc(&ddsd); + // replace DX code: + ddsd.dwWidth=turrets_h[i].cx; + ddsd.dwHeight=turrets_h[i].cy; + + int XMover, YMover; + char c[50]; + itoa(i, c, 10); +#ifdef RA2_MODE + XMover = atoi(g_data.sections["BuildingVoxelTurretsRA2"].values[(CString)lpUnittype + "X"]); + YMover = atoi(g_data.sections["BuildingVoxelTurretsRA2"].values[(CString)lpUnittype + "Y"]); + XMover += atoi(g_data.sections["BuildingVoxelTurretsRA2"].values[(CString)lpUnittype + (CString)"X" + c]); + YMover += atoi(g_data.sections["BuildingVoxelTurretsRA2"].values[(CString)lpUnittype + (CString)"Y" + c]); +#else + XMover = atoi(g_data.sections["BuildingVoxelTurrets"].values[(CString)lpUnittype + "X"]); + YMover = atoi(g_data.sections["BuildingVoxelTurrets"].values[(CString)lpUnittype + "Y"]); +#endif + + RECT srcRect, destRect; + + if (bVoxelTurret) + { + int mx = head.cx / 2 + atoi(rules.sections[image].values["TurretAnimX"]) - turretinfo[i].x; + int my = head.cy / 2 + atoi(rules.sections[image].values["TurretAnimY"]) - turretinfo[i].y; + + srcRect.top=0; + srcRect.left=0; + srcRect.right=ddsd.dwWidth; + srcRect.bottom=ddsd.dwHeight; + destRect.top=YMover+my; + destRect.left=XMover+mx; + destRect.right=destRect.left+ddsd.dwWidth;; + destRect.bottom=destRect.top+ddsd.dwHeight; + + } + else // !bVoxelTurret + { + + int mx = atoi(rules.sections[image].values["TurretAnimX"]); + int my = atoi(rules.sections[image].values["TurretAnimY"]);//+atoi(rules.sections[image].values["barrelAnimZAdjust"]); + + + + srcRect.top = 0; + srcRect.left = 0; + srcRect.right = turrets_h[i].cx; + srcRect.bottom = turrets_h[i].cy; + destRect.top = YMover + my; + destRect.left = XMover + mx; + destRect.right = destRect.left + srcRect.right; + destRect.bottom = destRect.top + srcRect.bottom; + } + + errstream << "vxl turret: " << i << " size: " << ddsd.dwWidth << " " << ddsd.dwHeight << " at " << destRect.left << " " << destRect.top << endl; + errstream.flush(); + Blit_PalD(lpT[i], destRect, turretColors[i].data(), srcRect, ddsd.dwWidth, head.cx, ddsd.dwHeight, head.cy); + Blit_PalD(lighting[i].data(), destRect, turretLighting[i].data(), srcRect, ddsd.dwWidth, head.cx, ddsd.dwHeight, head.cy, turretColors[i].data()); + + } + + // barrels in front of turret + if(!vxlBarrelColors[i].empty() && i!=1 && i!=0 && i!=7) + { + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = barrels_h[i].cx; + ddsd.dwHeight = barrels_h[i].cy; + + int XMover, YMover; + char c[50]; + itoa(i, c, 10); +#ifdef RA2_MODE + XMover = atoi(g_data.sections["BuildingVoxelBarrelsRA2"].values[(CString)lpUnittype + "X"]); + YMover = atoi(g_data.sections["BuildingVoxelBarrelsRA2"].values[(CString)lpUnittype + "Y"]); + XMover += atoi(g_data.sections["BuildingVoxelBarrelsRA2"].values[(CString)lpUnittype + (CString)"X" + c]); + YMover += atoi(g_data.sections["BuildingVoxelBarrelsRA2"].values[(CString)lpUnittype + (CString)"Y" + c]); +#else + XMover = atoi(g_data.sections["BuildingVoxelBarrels"].values[(CString)lpUnittype + "X"]); + YMover = atoi(g_data.sections["BuildingVoxelBarrels"].values[(CString)lpUnittype + "Y"]); +#endif + + RECT srcRect, destRect; + + int mx = head.cx / 2 + atoi(rules.sections[image].values["TurretAnimX"]) - barrelinfo[i].x; + int my = head.cy / 2 + atoi(rules.sections[image].values["TurretAnimY"]) - barrelinfo[i].y; + + srcRect.top = 0; + srcRect.left = 0; + srcRect.right = ddsd.dwWidth; + srcRect.bottom = ddsd.dwHeight; + destRect.top = YMover + my; + destRect.left = XMover + mx; + destRect.right = destRect.left + ddsd.dwWidth; + destRect.bottom = destRect.top + ddsd.dwHeight; + + + errstream << "vxl barrel: " << i << " size: " << ddsd.dwWidth << " " << ddsd.dwHeight << " at " << destRect.left << " " << destRect.top << endl; + errstream.flush(); + Blit_PalD(lpT[i], destRect, vxlBarrelColors[i].data(), srcRect, ddsd.dwWidth, head.cx, ddsd.dwHeight, head.cy); + Blit_PalD(lighting[i].data(), destRect, vxlBarrelLighting[i].data(), srcRect, ddsd.dwWidth, head.cx, ddsd.dwHeight, head.cy, vxlBarrelColors[i].data()); + + + } + + if(!bPowerUp && i!=0 && (imghead.unknown==0 && !isTrue(g_data.sections["Debug"].values["IgnoreSHPImageHeadUnused"])) && bStructure) + { + if(lpT[i]) delete[] lpT[i]; + lpT[i]=NULL; + } + else + { + char ic[50]; + itoa(i, ic, 10); + + PICDATA p; + p.pic=lpT[i]; + if (std::find_if(lighting[i].begin(), lighting[i].end(), [](const BYTE b) { return b != 255; }) != lighting[i].end()) + p.lighting = std::shared_ptr<std::vector<BYTE>>(new std::vector<BYTE>(std::move(lighting[i]))); + else + lighting[i].clear(); + p.vborder=new(VBORDER[head.cy]); + int k; + for(k=0;k<head.cy;k++) + { + int l,r; + GetDrawBorder(lpT[i], head.cx, k, l, r, 0); + p.vborder[k].left=l; + p.vborder[k].right=r; + } + + if(hPalette==m_hPalIsoTemp || hPalette==m_hPalIsoUrb || hPalette==m_hPalIsoSnow || hPalette==m_hPalIsoUbn || hPalette==m_hPalIsoDes || hPalette==m_hPalIsoLun) p.pal=iPalIso; + if(hPalette==m_hPalTemp || hPalette==m_hPalUrb || hPalette==m_hPalSnow || hPalette==m_hPalUbn || hPalette==m_hPalLun || hPalette==m_hPalDes) p.pal=iPalTheater; + if(hPalette==m_hPalUnitTemp || hPalette==m_hPalUnitUrb || hPalette==m_hPalUnitSnow || hPalette==m_hPalUnitDes || hPalette==m_hPalUnitLun || hPalette==m_hPalUnitUbn) p.pal=iPalUnit; + if(hPalette==m_hPalLib) p.pal=iPalLib; + + p.x=imghead.x; + p.y=imghead.y; + p.wHeight=imghead.cy; + p.wWidth=imghead.cx; + p.wMaxWidth=head.cx; + p.wMaxHeight=head.cy; + p.bType=PICDATA_TYPE_SHP; + p.bTerrain=limited_to_theater; + + pics[image+ic]=p; + + //errstream << " --> finished as " << (LPCSTR)(image+ic) << endl; + //errstream.flush(); + } + + + } + + delete[] lpT; + + + if(bib) delete[] bib; + if(activeanim) delete[] activeanim; + if(idleanim) delete[] idleanim; + if(activeanim2) delete[] activeanim2; + if(activeanim3) delete[] activeanim3; + if(superanim1) delete[] superanim1; + if(superanim2) delete[] superanim2; + if(superanim3) delete[] superanim3; + if(superanim4) delete[] superanim4; + if(specialanim1) delete[] specialanim1; + if(specialanim2) delete[] specialanim2; + if(specialanim3) delete[] specialanim3; + if(specialanim4) delete[] specialanim4; + + //for(i=0;i<8;i++) + // if(turrets[i]) delete[] turrets[i]; + + } + + //errstream << " --> Finished" << endl; + //errstream.flush(); + } + + else + { + errstream << "File in theater " << cur_theat << " not found: " << (LPCTSTR)filename << endl; + errstream.flush(); + + missingimages[lpUnittype]=TRUE; + } + + } + catch(...) + { + errstream << " exception " << endl; + errstream.flush(); + } + + + } + else + { + filename=image+".vxl"; + + HMIXFILE hMix=FindFileInMix(filename); + if(hMix==FALSE) + { + missingimages[lpUnittype]=TRUE; + return FALSE; + } + + int XMover, YMover; +#ifdef RA2_MODE + XMover=atoi(g_data.sections["VehicleVoxelTurretsRA2"].values[(CString)lpUnittype+"X"]); + YMover=atoi(g_data.sections["VehicleVoxelTurretsRA2"].values[(CString)lpUnittype+"Y"]); +#else + XMover=atoi(g_data.sections["VehicleVoxelTurrets"].values[(CString)lpUnittype+"X"]); + YMover=atoi(g_data.sections["VehicleVoxelTurrets"].values[(CString)lpUnittype+"Y"]); +#endif + + if (artSection.values.find("TurretOffset") != art.sections[image].values.end()) + iTurretOffset = atoi(art.sections[image].values["TurretOffset"]); + + int i; + + for(i=0;i<8;i++) + { + float r_x,r_y,r_z; + + + r_x = 300; + r_y=0; + r_z=45*i+90; + + //r_x = 0; + //r_y = 0; + //r_z = 0; + + // convert + const double pi = 3.141592654; + Vec3f rotation(r_x / 180.0f * pi, r_y / 180.0f * pi, r_z / 180.0f * pi); + Vec3f turretModelOffset(iTurretOffset / 6.0f, 0.0f, 0.0f); + + + std::vector<BYTE> colors; + std::shared_ptr<std::vector<BYTE>> pLighting(new std::vector<BYTE>); + auto& lighting = *pLighting; + std::vector<BYTE> turretColors; + std::vector<BYTE> turretNormals; + std::vector<BYTE> barrelColors; + std::vector<BYTE> barrelNormals; + RECT lprT; + RECT lprB; + int turret_x,turret_y,turret_x_zmax,turret_y_zmax,barrel_x,barrel_y; + + if(isTrue(rules.sections[lpUnittype].values["Turret"])) + { + if(FSunPackLib::SetCurrentVXL(image+"tur.vxl", hMix)) + { + FSunPackLib::LoadVXLImage(*m_voxelNormalTables, lightDirection, rotation, turretModelOffset, turretColors, turretNormals, &turret_x,&turret_y, 0, &turret_x_zmax, &turret_y_zmax,-1,-1,&lprT); + } + if(FSunPackLib::SetCurrentVXL(image+"barl.vxl", hMix)) + { + FSunPackLib::LoadVXLImage(*m_voxelNormalTables, lightDirection, rotation, turretModelOffset, barrelColors, barrelNormals, &barrel_x,&barrel_y, 0, NULL, NULL, 0, 0, &lprB); + } + } + + + if(!FSunPackLib::SetCurrentVXL(filename, hMix)) + { + return FALSE; + } + + + + int xcenter,ycenter,xcenter_zmax,ycenter_zmax; + + RECT r; + + if(! + FSunPackLib::LoadVXLImage(*m_voxelNormalTables, lightDirection, rotation, Vec3f(), colors, lighting, &xcenter, &ycenter,0, &xcenter_zmax, &ycenter_zmax,-1,-1,&r) + ) + { + return FALSE; + } + + FSunPackLib::VoxelNormalClass vnc = FSunPackLib::VoxelNormalClass::Unknown; + FSunPackLib::GetVXLSectionInfo(0, vnc); // we assume the normal class for all voxels sections and turrets or barrels is the same + + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize=sizeof(DDSURFACEDESC2); + ddsd.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth=r.right-r.left; + ddsd.dwHeight=r.bottom-r.top; + + //lpT->GetSurfaceDesc(&ddsd); + + // turret + if(turretColors.size()) + { + DDSURFACEDESC2 ddsdT; + memset(&ddsdT, 0, sizeof(DDSURFACEDESC2)); + ddsdT.dwSize=sizeof(DDSURFACEDESC2); + ddsdT.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + ddsdT.dwWidth=lprT.right-lprT.left; + ddsdT.dwHeight=lprT.bottom-lprT.top; + //lpTurret->GetSurfaceDesc(&ddsdT); + + DDBLTFX fx; + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + + RECT srcRect, destRect; + srcRect.left=0; + srcRect.right=ddsdT.dwWidth; + destRect.left=xcenter - turret_x + XMover; + destRect.right=destRect.left+ddsdT.dwWidth; + srcRect.top=0; + srcRect.bottom=ddsdT.dwHeight; + destRect.top=ycenter - turret_y + YMover; + destRect.bottom=destRect.top+ddsdT.dwHeight; + + errstream << destRect.left << " " << destRect.top << endl; + errstream.flush(); + + Blit_PalD(colors.data(), destRect, turretColors.data(), srcRect, ddsdT.dwWidth, ddsd.dwWidth, ddsdT.dwHeight, ddsd.dwHeight); + Blit_PalD(lighting.data(), destRect, turretNormals.data(), srcRect, ddsdT.dwWidth, ddsd.dwWidth, ddsdT.dwHeight, ddsd.dwHeight, turretColors.data()); + //AssertNormals(turretColors, turretNormals); + + } + + // barrel + if(barrelColors.size()) + { + DDSURFACEDESC2 ddsdB; + memset(&ddsdB, 0, sizeof(DDSURFACEDESC2)); + ddsdB.dwSize=sizeof(DDSURFACEDESC2); + ddsdB.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + ddsdB.dwWidth=lprB.right-lprB.left; + ddsdB.dwHeight=lprB.bottom-lprB.top; + //lpBarrel->GetSurfaceDesc(&ddsdB); + + DDSURFACEDESC2 ddsdT; + memset(&ddsdT, 0, sizeof(DDSURFACEDESC2)); + ddsdT.dwSize=sizeof(DDSURFACEDESC2); + ddsdT.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + + if(turretColors.size()) + { + ddsdT.dwWidth=lprT.right-lprT.left; + ddsdT.dwHeight=lprT.bottom-lprT.top; + //lpTurret->GetSurfaceDesc(&ddsdT); + } + + + DDBLTFX fx; + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + RECT srcRect, destRect; + srcRect.left=0; + srcRect.right=ddsdB.dwWidth; + destRect.left=xcenter-barrel_x+XMover; + destRect.right=destRect.left+ddsdB.dwWidth; + srcRect.top=0; + srcRect.bottom=ddsdB.dwHeight; + destRect.top=ycenter-barrel_y+YMover; + destRect.bottom=destRect.top+ddsdB.dwHeight; + + Blit_PalD(colors.data(), destRect, barrelColors.data(), srcRect, ddsdB.dwWidth, ddsd.dwWidth, ddsdB.dwHeight, ddsd.dwHeight); + Blit_PalD(lighting.data(), destRect, barrelNormals.data(), srcRect, ddsdB.dwWidth, ddsd.dwWidth, ddsdB.dwHeight, ddsd.dwHeight, barrelColors.data()); + //AssertNormals(vxlBarrelColors, barrelNormals); + + } + + // all VXL, so every non-transparent area should have a normal + //AssertNormals(colors, lighting); + + char ic[50]; + itoa(7-i, ic, 10); + + errstream << ddsd.dwWidth << " " << ddsd.dwHeight << "\n"; + PICDATA p; + p.pic = new(BYTE[colors.size()]); + memcpy(p.pic, colors.data(), colors.size()); + p.lighting = pLighting; + p.normalClass = vnc; + + p.vborder=new(VBORDER[ddsd.dwHeight]); + int k; + for(k=0;k<ddsd.dwHeight;k++) + { + int l,r; + GetDrawBorder(colors.data(), ddsd.dwWidth, k, l, r, 0); + p.vborder[k].left=l; + p.vborder[k].right=r; + } + + //if(hPalette==m_hPalIsoTemp || hPalette==m_hPalIsoUrb || hPalette==m_hPalIsoSnow) p.pal=iPalIso; + //if(hPalette==m_hPalTemp || hPalette==m_hPalUrb || hPalette==m_hPalSnow) p.pal=iPalTheater; + //if(hPalette==m_hPalUnitTemp || hPalette==m_hPalUnitUrb || hPalette==m_hPalUnitSnow) p.pal=iPalUnit; + //if(hPalette==m_hPalLib) p.pal=iPalLib; + p.pal=iPalUnit; + + p.x=-xcenter; + p.y=-ycenter; + p.wHeight=ddsd.dwHeight; + p.wWidth=ddsd.dwWidth; + p.wMaxWidth=ddsd.dwWidth; + p.wMaxHeight=ddsd.dwHeight; + p.bType=PICDATA_TYPE_VXL; + p.bTerrain=TheaterChar::None; + + pics[image+ic]=p; + + errstream << "vxl saved as " << (LPCSTR)image << (LPCSTR)ic << endl; + errstream.flush(); + + //delete[] lpT; + + } + + + + } + + + + return FALSE; +} +void CLoading::LoadBuildingSubGraphic(const CString& subkey, const CIniFileSection& artSection, BOOL bAlwaysSetChar, char theat, HMIXFILE hShpMix, SHPHEADER& shp_h, BYTE*& shp) +{ + CString subname = artSection.GetValueByName(subkey); + if (subname.GetLength() > 0) + { + auto res = FindUnitShp(subname, theat, artSection); + /*CString subfilename = subname + ".shp"; + + if (isTrue(artSection.GetValueByName("NewTheater")) || bAlwaysSetChar || subfilename.GetAt(0) == 'G' || subfilename.GetAt(0) == 'N' || subfilename.GetAt(0) == 'Y' || subfilename.GetAt(0) == 'C') + { + auto subfilename_theat = subfilename; + subfilename_theat.SetAt(1, theat); + if (FSunPackLib::XCC_DoesFileExist(subfilename_theat, hShpMix)) + subfilename = subfilename_theat; + }*/ + + if (res && FSunPackLib::XCC_DoesFileExist(res->filename, res->mixfile)) + { + FSunPackLib::SetCurrentSHP(res->filename, res->mixfile); + FSunPackLib::XCC_GetSHPHeader(&shp_h); + FSunPackLib::LoadSHPImage(0, 1, &shp); + + } + } +} +#else // surfaces +BOOL CLoading::LoadUnitGraphic(LPCTSTR lpUnittype) +{ + last_succeeded_operation=10; + + CString _rules_image; // the image used + CString filename; // filename of the image + char theat=cur_theat; // standard theater char is t (Temperat). a is snow. + + BOOL bAlwaysSetChar; // second char is always theater, even if NewTheater not specified! + WORD wStep=1; // step is 1 for infantry, buildings, etc, and for shp vehicles it specifies the step rate between every direction + WORD wStartWalkFrame=0; // for examply cyborg reaper has another walk starting frame + int iTurretOffset=0; // used for centering y pos of turret (if existing) + BOOL bStructure=rules.sections["BuildingTypes"].FindValue(lpUnittype)>=0; // is this a structure? + + BOOL bPowerUp=rules.sections[lpUnittype].values["PowersUpBuilding"]!=""; + + HTSPALETTE hPalette; + if(theat=='T') hPalette=m_hPalIsoTemp; + if(theat=='A') hPalette=m_hPalIsoSnow; + if(theat=='U') hPalette=m_hPalIsoUrb; + + CIsoView& v=*((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + + _rules_image = lpUnittype; + if (rules.sections[lpUnittype].values.find("Image") != rules.sections[lpUnittype].values.end()) + _rules_image = rules.sections[lpUnittype].values["Image"]; + + CString _art_image = _rules_image; + if (art.sections[_rules_image].values.find("Image") != art.sections[_rules_image].values.end()) + { + if (!isTrue(g_data.sections["IgnoreArtImage"].values[_rules_image])) + _art_image = art.sections[_rules_image].values["Image"]; + } + + const CString& image = _art_image; + const auto& rulesSection = rules.sections[lpUnittype]; + const auto& artSection = art.sections[image]; + + if(!isTrue(art.sections[image].values["Voxel"])) // is it a shp graphic? + { + try + { + + filename=image+".shp"; + + + BYTE bTerrain=0; + + + + BOOL isNewTerrain=FALSE; + if(isTrue(art.sections[image].values["NewTheater"]))//&& isTrue(artSection.GetValueByName("TerrainPalette")))//(filename.GetAt(0)=='G' || filename.GetAt(0)=='N' || filename.GetAt(0)=='C') && filename.GetAt(1)=='A') + { + hPalette=m_hPalUnitTemp; + if(theat=='A') hPalette=m_hPalUnitSnow; + if(theat=='U') hPalette=m_hPalUnitUrb; + filename.SetAt(1, theat); + isNewTerrain=TRUE; + } + + + HMIXFILE hShpMix=FindFileInMix(filename, &bTerrain); + + BYTE bIgnoreTerrain=TRUE; + + if(hShpMix==NULL && isNewTerrain) + { + filename.SetAt(1, 'G'); + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix) theat='G'; + + } + + + + if(hShpMix==NULL && isNewTerrain) + { + filename.SetAt(1, 'A'); + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix) theat='A'; + } + + if(hShpMix==NULL && isNewTerrain) + { + filename.SetAt(1, 'T'); + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix){ + theat='T'; + hPalette=m_hIsoTemp; + } + } + + + if(isTrue(artSection.GetValueByName("TerrainPalette"))) + { + bIgnoreTerrain=FALSE; + + if(cur_theat=='T') + hPalette=m_hPalIsoTemp; + else if(cur_theat=='A') + hPalette=m_hPalIsoSnow; + else if (cur_theat=='U') + hPalette=m_hPalIsoUrb; + + + + } + + + + if(hShpMix==0) + { + filename=image; + filename+=".shp"; + hShpMix=FindFileInMix(filename, &bTerrain); + + + + if(hShpMix==NULL) + { + filename=image; + if(theat=='T') filename+=".tem"; + if(theat=='A') filename+=".sno"; + if(theat=='U') filename+=".urb"; + filename.MakeLower(); + hShpMix=FindFileInMix(filename, &bTerrain); + + if(hShpMix==NULL) + { + filename=image; + filename+=".tem"; + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix) + { + hPalette=m_hPalIsoTemp; + } + } + + if(hShpMix!=NULL) + { + + + + } + else + { + filename=image+".shp"; + + filename.SetAt(1, 'A'); + + hShpMix=FindFileInMix(filename); + + if(hShpMix!=NULL) + { + bAlwaysSetChar=TRUE; + } + else + { + filename.SetAt(1, 'A'); + hShpMix=FindFileInMix(filename); + + if(hShpMix!=NULL) + { + theat='A'; + bAlwaysSetChar=TRUE; + } + else + { + filename.SetAt(1, 'U'); + hShpMix=FindFileInMix(filename); + if(hShpMix) theat='U'; + else + { + filename.SetAt(1, 'T'); + hShpMix=FindFileInMix(filename); + if(hShpMix) theat='T'; + } + } + } + } + } + else + { + theat='T'; + } + + } + else + { + + // now we need to find out the palette + + if(isTrue(artSection.GetValueByName("TerrainPalette"))) // it´s a file in isotemp.mix/isosno.mix + { + + } + else // it´s a file in temperat.mix/snow.mix + { + if(cur_theat=='T') hPalette=m_hPalUnitTemp; + if(cur_theat=='A') hPalette=m_hPalUnitSnow; + if(cur_theat=='U') hPalette=m_hPalUnitUrb; + } + + } + + + + if(filename=="tibtre01.tem" || filename=="tibtre02.tem" || filename=="tibtre03.tem" || filename=="veinhole.tem") + { + hPalette=m_hPalUnitTemp; + } + + + SHPHEADER head; + CString bibname; + CString bibfilename; + CString activeanim_name; + CString activeanim_filename; + CString idleanim_name; + CString idleanim_filename; + CString activeanim2_name; + CString activeanim2_filename; + CString activeanim3_name; + CString activeanim3_filename; + CString superanim1_name,superanim1_filename; + CString superanim2_name,superanim2_filename; + CString superanim3_name,superanim3_filename; + CString superanim4_name,superanim4_filename; + CString specialanim1_name,specialanim1_filename; + CString specialanim2_name,specialanim2_filename; + CString specialanim3_name,specialanim3_filename; + CString specialanim4_name,specialanim4_filename; + + CString turretanim_name; + CString turretanim_filename; + LPDIRECTDRAWSURFACE4 bib=NULL; + LPDIRECTDRAWSURFACE4 activeanim=NULL; + LPDIRECTDRAWSURFACE4 idleanim=NULL; + LPDIRECTDRAWSURFACE4 activeanim2=NULL; + LPDIRECTDRAWSURFACE4 activeanim3=NULL; + LPDIRECTDRAWSURFACE4 superanim1=NULL; + LPDIRECTDRAWSURFACE4 superanim2=NULL; + LPDIRECTDRAWSURFACE4 superanim3=NULL; + LPDIRECTDRAWSURFACE4 superanim4=NULL; + LPDIRECTDRAWSURFACE4 specialanim1=NULL; + LPDIRECTDRAWSURFACE4 specialanim2=NULL; + LPDIRECTDRAWSURFACE4 specialanim3=NULL; + LPDIRECTDRAWSURFACE4 specialanim4=NULL; + LPDIRECTDRAWSURFACE4* lpT=NULL; + LPDIRECTDRAWSURFACE4 turrets[8] = { 0 }; + SHPIMAGEHEADER turretinfo[8]; + + if(hShpMix>0) + { + + + //errstream << (LPCTSTR)filename << " found " ; + //errstream.flush(); + + + if(rules.sections[lpUnittype].values["Bib"]!="no") // seems to be ignored by TS, art.ini overwrites??? + { + + bibname=art.sections[image].values["BibShape"]; + if(bibname.GetLength()>0) + { + bibfilename=bibname+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + bibfilename.SetAt(1, theat); + + if(bAlwaysSetChar) bibfilename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(bibfilename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(bibfilename, hShpMix); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &bib); + + } + } + } + + activeanim_name=art.sections[image].values["ActiveAnim"]; + if(activeanim_name.GetLength()>0) + { + activeanim_filename=activeanim_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + activeanim_filename.SetAt(1, theat); + + if(bAlwaysSetChar) activeanim_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(activeanim_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(activeanim_filename, hShpMix); + + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &activeanim); + + + } + } + + idleanim_name=art.sections[image].values["IdleAnim"]; + if(idleanim_name.GetLength()>0) + { + idleanim_filename=idleanim_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + idleanim_filename.SetAt(1, theat); + + if(bAlwaysSetChar) idleanim_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(idleanim_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(idleanim_filename, hShpMix); + + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &idleanim); + } + } + + + activeanim2_name=art.sections[image].values["ActiveAnimTwo"]; + if(activeanim2_name.GetLength()>0) + { + activeanim2_filename=activeanim2_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + activeanim2_filename.SetAt(1, theat); + + if(bAlwaysSetChar) activeanim2_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(activeanim2_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(activeanim2_filename, hShpMix); + + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &activeanim2); + + } + } + + activeanim3_name=art.sections[image].values["ActiveAnimThree"]; + if(activeanim3_name.GetLength()>0) + { + activeanim3_filename=activeanim3_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + activeanim3_filename.SetAt(1, theat); + + if(bAlwaysSetChar) activeanim3_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(activeanim3_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(activeanim3_filename, hShpMix); + + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &activeanim3); + + } + } + + superanim1_name=art.sections[image].values["SuperAnim"]; + if(superanim1_name.GetLength()>0) + { + superanim1_filename=superanim1_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + superanim1_filename.SetAt(1, theat); + + if(bAlwaysSetChar) superanim1_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(superanim1_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(superanim1_filename, hShpMix); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &superanim1); + } + } + + superanim2_name=art.sections[image].values["SuperAnimTwo"]; + if(superanim2_name.GetLength()>0) + { + superanim2_filename=superanim2_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + superanim2_filename.SetAt(1, theat); + + if(bAlwaysSetChar) superanim2_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(superanim2_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(superanim2_filename, hShpMix); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &superanim2); + } + } + + superanim3_name=art.sections[image].values["SuperAnimThree"]; + if(superanim3_name.GetLength()>0) + { + superanim3_filename=superanim3_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + superanim3_filename.SetAt(1, theat); + + if(bAlwaysSetChar) superanim3_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(superanim3_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(superanim3_filename, hShpMix); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &superanim3); + } + } + + superanim4_name=art.sections[image].values["SuperAnimFour"]; + if(superanim4_name.GetLength()>0) + { + superanim4_filename=superanim4_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + superanim4_filename.SetAt(1, theat); + + if(bAlwaysSetChar) superanim4_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(superanim4_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(superanim4_filename, hShpMix); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &superanim4); + } + } + + specialanim1_name=art.sections[image].values["SpecialAnim"]; + if(specialanim1_name.GetLength()>0) + { + specialanim1_filename=specialanim1_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + specialanim1_filename.SetAt(1, theat); + + if(bAlwaysSetChar) specialanim1_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(specialanim1_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(specialanim1_filename, hShpMix); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &specialanim1); + } + } + + specialanim2_name=art.sections[image].values["SpecialAnimTwo"]; + if(specialanim2_name.GetLength()>0) + { + specialanim2_filename=specialanim2_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + specialanim2_filename.SetAt(1, theat); + + if(bAlwaysSetChar) specialanim2_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(specialanim2_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(specialanim2_filename, hShpMix); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &specialanim2); + } + } + + specialanim3_name=art.sections[image].values["SpecialAnimThree"]; + if(specialanim3_name.GetLength()>0) + { + specialanim3_filename=specialanim3_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + specialanim3_filename.SetAt(1, theat); + + if(bAlwaysSetChar) specialanim3_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(specialanim3_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(specialanim3_filename, hShpMix); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &specialanim3); + } + } + + specialanim4_name=art.sections[image].values["SpecialAnimFour"]; + if(specialanim4_name.GetLength()>0) + { + specialanim4_filename=specialanim4_name+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + specialanim4_filename.SetAt(1, theat); + + if(bAlwaysSetChar) specialanim4_filename.SetAt(1, theat); + + if(FSunPackLib::XCC_DoesFileExist(specialanim4_filename, hShpMix)) + { + FSunPackLib::SetCurrentSHP(specialanim4_filename, hShpMix); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &specialanim4); + } + } + + BOOL bVoxelTurret=FALSE; + + turretanim_name=rules.sections[image].values["TurretAnim"]; + if(bStructure && rules.sections[image].values["Turret"]=="yes" && turretanim_name.GetLength()>0 && rules.sections[image].values["TurretAnimIsVoxel"]!="true") + { + turretanim_filename=turretanim_name+".shp"; + if(art.sections[turretanim_name].values.find("Image")!=art.sections[turretanim_name].values.end()) turretanim_filename=art.sections[turretanim_name].values["Image"]+".shp"; + + if(isTrue(art.sections[image].values["NewTheater"])) + turretanim_filename.SetAt(1, theat); + + + FSunPackLib::SetCurrentSHP(turretanim_filename, hShpMix); + FSunPackLib::XCC_GetSHPHeader(&head); + + int iStartTurret=0; + const WORD wAnimCount=4; // anims between each "normal" direction, seems to be hardcoded + + int i; + + for(i=0;i<8;i++) + { + if(iStartTurret+i*wAnimCount<head.c_images) + { + FSunPackLib::XCC_GetSHPImageHeader(iStartTurret+i*wAnimCount, &turretinfo[i]); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, iStartTurret+i*wAnimCount, 1, &turrets[i]); + } + + } + } + else if(bStructure && rules.sections[image].values["Turret"]=="yes" && turretanim_name.GetLength()>0 && rules.sections[image].values["TurretAnimIsVoxel"]=="true") + { + turretanim_filename=turretanim_name+".vxl"; + if(art.sections[turretanim_name].values.find("Image")!=art.sections[turretanim_name].values.end()) turretanim_filename=art.sections[turretanim_name].values["Image"]+".vxl"; + + //if(isTrue(art.sections[image].values["NewTheater"])) + // turretanim_filename.SetAt(1, theat); + + HMIXFILE hVXL=FindFileInMix(turretanim_filename); + + if(hVXL) + { + bVoxelTurret=TRUE; + + if( + FSunPackLib::SetCurrentVXL(turretanim_filename, hVXL) + ) + { + int i; + + for(i=0;i<8;i++) + { + float r_x,r_y,r_z; + + + r_x=300; + r_y=0; + r_z=45*i+90; + + // convert + const double pi = 3.141592654; + r_x=r_x/180.0f*pi; + r_y=r_y/180.0f*pi; + r_z=r_z/180.0f*pi; + + int center_x, center_y; + if(! + FSunPackLib::LoadVXLImageInSurface(*m_voxelNormalTables, lightDirection, v.dd, 0, 1, r_x, r_y, r_z, &turrets[i], hPalette,¢er_x, ¢er_y,atoi(rules.sections[image].values["TurretAnimZAdjust"])) + ) + { + + } + else + { + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize=sizeof(DDSURFACEDESC2); + ddsd.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + turrets[i]->GetSurfaceDesc(&ddsd); + turretinfo[i].x=-center_x; + turretinfo[i].y=-center_y; + turretinfo[i].cx=ddsd.dwWidth; + turretinfo[i].cy=ddsd.dwHeight; + } + + } + } + } + } + + + if(art.sections[image].values.find("WalkFrames")!=art.sections[image].values.end()) + wStep=atoi(art.sections[image].values["WalkFrames"]); + if(art.sections[image].values.find("StartWalkFrame")!=art.sections[image].values.end()) + wStartWalkFrame=atoi(art.sections[image].values["StartWalkFrame"]); + if(art.sections[image].values.find("TurretOffset")!=art.sections[image].values.end()) + iTurretOffset=atoi(art.sections[image].values["TurretOffset"]); + + + if(art.sections[image].values["Palette"]=="lib") + hPalette=m_hPalLib; + + BOOL bSuccess=FSunPackLib::SetCurrentSHP(filename, hShpMix); + if( + !bSuccess + ) + { + filename=image+=".sno"; + if(cur_theat=='T' || cur_theat=='U') hPalette=m_hPalIsoTemp; + hShpMix=FindFileInMix(filename, &bTerrain); + bSuccess=FSunPackLib::SetCurrentSHP(filename, hShpMix); + + if(!bSuccess) + { + missingimages[lpUnittype]=TRUE; + } + } + + if(bSuccess) + { + + FSunPackLib::XCC_GetSHPHeader(&head); + int i; + int maxPics=head.c_images; + if(maxPics>8) maxPics=8; // we only need 8 pictures for every direction! + if(bStructure && !bPowerUp) maxPics=1; + if(bVoxelTurret) maxPics=8; + + + if(!bStructure && rules.sections[image].values["Turret"]=="yes") + { + int iStartTurret=wStartWalkFrame+8*wStep; + const WORD wAnimCount=4; // anims between each "normal" direction, seems to be hardcoded + + int i; + + for(i=0;i<8;i++) + { + if(!bStructure && iStartTurret+i*wAnimCount<head.c_images) + { + FSunPackLib::XCC_GetSHPImageHeader(iStartTurret+i*wAnimCount, &turretinfo[i]); + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, iStartTurret+i*wAnimCount, 1, &turrets[i]); + } + + } + } + + + + // create an array of pointers to directdraw surfaces + lpT=new(LPDIRECTDRAWSURFACE4[maxPics]); + memset(lpT, 0, sizeof(LPDIRECTDRAWSURFACE4)*maxPics); + + if(bVoxelTurret) + { + for(i=0;i<maxPics; i++) + { + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, 1, &lpT[i]); + } + } + else if(wStep==1 && (rules.sections[lpUnittype].values["PowersUpBuilding"].GetLength()==0 || !isTrue(rules.sections[lpUnittype].values["Turret"]))) + { // standard case... + + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, wStartWalkFrame, maxPics, lpT); + + } + else if(rules.sections[lpUnittype].values["PowersUpBuilding"].GetLength()!=0 && isTrue(rules.sections[lpUnittype].values["Turret"])) + { // a "real" turret (vulcan cannon, etc...) + for(i=0;i<maxPics; i++) + { + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, i*4, 1, &lpT[i]); + } + } + else + { // walk frames used + for(i=0;i<maxPics; i++) + { + int pic_in_file=i; + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, i*wStep+wStartWalkFrame, 1, &lpT[i]); + } + } + + for(i=0; i<maxPics; i++) + { + int pic_in_file=i; + if(bStructure && bVoxelTurret) pic_in_file=0; + SHPIMAGEHEADER imghead; + FSunPackLib::XCC_GetSHPImageHeader(pic_in_file, &imghead); + + if(bib!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, bib, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + imghead.cx=head.cx-imghead.x; // update size of main graphic + imghead.cy=head.cy-imghead.y; + + } + + if(activeanim!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, activeanim, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(idleanim!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, idleanim, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(activeanim2!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, activeanim2, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(activeanim3!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, activeanim3, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(superanim1!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, superanim1, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(superanim2!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, superanim2, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(superanim3!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, superanim3, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(superanim4!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, superanim4, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(specialanim1!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, specialanim1, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(specialanim2!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, specialanim2, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(specialanim3!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, specialanim3, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + if(specialanim4!=NULL) + { + DDBLTFX fx; + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + lpT[i]->Blt(NULL, specialanim4, NULL, DDBLT_KEYSRC | DDBLT_WAIT , &fx); + + + } + + + + if(turrets[i]!=NULL) + { + DDBLTFX fx; + int iMove=0; + + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize=sizeof(DDSURFACEDESC2); + ddsd.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + turrets[i]->GetSurfaceDesc(&ddsd); + + + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + RECT srcRect, destRect; + srcRect.left=0; + srcRect.right=ddsd.dwWidth; + destRect.left=(head.cx-ddsd.dwWidth)/2; + destRect.right=head.cx-destRect.left; + + if(iMove<0) + { + srcRect.top=-iMove; + srcRect.bottom=ddsd.dwHeight; + destRect.top=0; + destRect.bottom=head.cy+iMove-(head.cy-ddsd.dwHeight); + } + else + { + int mx=imghead.x/2+imghead.cx/2+(-turretinfo[i].x/2-turretinfo[i].cx)+ atoi(rules.sections[image].values["TurretAnimX"]); + int my=imghead.y/2+imghead.cy/2+(-turretinfo[i].y/2-turretinfo[i].cy) + atoi(rules.sections[image].values["TurretAnimY"]);//+atoi(rules.sections[image].values["TurretAnimZAdjust"]); + + if(ddsd.dwWidth!=head.cx || ddsd.dwHeight!=head.cy) + { + // voxel turret + //mx=head.cx/2-ddsd.dwWidth/2;//+atoi(rules.sections[image].values["TurretAnimX"]); + //my=head.cy/2-ddsd.dwHeight/2+atoi(rules.sections[image].values["TurretAnimY"])+atoi(rules.sections[image].values["TurretAnimZAdjust"])/2; + mx=imghead.x+imghead.cx/2+turretinfo[i].x+atoi(rules.sections[image].values["TurretAnimX"]); + my=imghead.y+imghead.cy/2+turretinfo[i].y+atoi(rules.sections[image].values["TurretAnimY"]);//+atoi(rules.sections[image].values["TurretAnimZAdjust"])/2; + + errstream << turretinfo[i].x << " y:" << turretinfo[i].y << " mx:" << mx << " my:" << my << endl; + errstream.flush(); + + int XMover, YMover; +#ifdef RA2_MODE + XMover=atoi(g_data.sections["BuildingVoxelTurretsRA2"].values[(CString)lpUnittype+"X"]); + YMover=atoi(g_data.sections["BuildingVoxelTurretsRA2"].values[(CString)lpUnittype+"Y"]); +#else + XMover=atoi(g_data.sections["BuildingVoxelTurrets"].values[(CString)lpUnittype+"X"]); + YMover=atoi(g_data.sections["BuildingVoxelTurrets"].values[(CString)lpUnittype+"Y"]); +#endif + + mx+=XMover; + my+=YMover; + + srcRect.top=0; + srcRect.left=0; + srcRect.right=ddsd.dwWidth; + srcRect.bottom=ddsd.dwHeight; + destRect.top=my; + destRect.left=mx; + destRect.right=destRect.left+ddsd.dwWidth; + destRect.bottom=destRect.top+ddsd.dwHeight; + if(destRect.top<0) + { + int old=destRect.top; + destRect.top=0; + srcRect.top-=old-destRect.top; + + } + if(destRect.right>=head.cx) + { + int old=destRect.right; + destRect.right=head.cx; + srcRect.right-=old-destRect.right; + } + if(destRect.bottom>=head.cy) + { + int old=destRect.bottom; + destRect.bottom=head.cy; + srcRect.bottom-=old-destRect.bottom; + } + } + else + { + + if(mx<0)mx=0; + if(my<0)my=0; + srcRect.top=0; + srcRect.right=ddsd.dwWidth-mx; + srcRect.bottom=ddsd.dwHeight-my; + destRect.top=my; + destRect.left=mx+(head.cx-ddsd.dwWidth)/2; + destRect.right=destRect.left+ddsd.dwWidth;; + destRect.bottom=destRect.top+ddsd.dwHeight; + } + } + + + + + if(lpT[i]->Blt(&destRect, turrets[i], &srcRect, DDBLT_KEYSRC | DDBLT_WAIT, &fx)!=DD_OK) + { + + errstream << "vxl turret: " << i << " size: " << ddsd.dwWidth << " " << ddsd.dwHeight << " failed" << endl; + errstream.flush(); + //exit(-99); + } + + + } + + if(!bPowerUp && i!=0 && imghead.unknown==0 && bStructure) + { + if(lpT[i]) lpT[i]->Release(); + } + else + { + char ic[50]; + itoa(i, ic, 10); + + PICDATA p; + p.pic=lpT[i]; + p.x=imghead.x; + p.y=imghead.y; + p.wHeight=imghead.cy; + p.wWidth=imghead.cx; + p.wMaxWidth=head.cx; + p.wMaxHeight=head.cy; + p.bType=PICDATA_TYPE_SHP; + p.bTerrain=bTerrain; + if(bIgnoreTerrain) p.bTerrain=0; + + + pics[image+ic]=p; + + //errstream << " --> finished as " << (LPCSTR)(image+ic) << endl; + //errstream.flush(); + } + + + } + + delete[] lpT; + + + if(bib) bib->Release(); + if(activeanim)activeanim->Release(); + if(idleanim)idleanim->Release(); + if(activeanim2)activeanim2->Release(); + if(activeanim3)activeanim3->Release(); + if(superanim1)superanim1->Release(); + if(superanim2)superanim2->Release(); + if(superanim3)superanim3->Release(); + if(superanim4)superanim4->Release(); + if(specialanim1)specialanim1->Release(); + if(specialanim2)specialanim2->Release(); + if(specialanim3)specialanim3->Release(); + if(specialanim4)specialanim4->Release(); + + for(i=0;i<8;i++) + if(turrets[i])turrets[i]->Release(); + + } + + //errstream << " --> Finished" << endl; + //errstream.flush(); + } + + else + { + errstream << "File in theater " << cur_theat << " not found: " << (LPCTSTR)filename << endl; + errstream.flush(); + + missingimages[lpUnittype]=TRUE; + } + + } + catch(...) + { + errstream << " exception " << endl; + errstream.flush(); + } + + + } + else + { + filename=image+".vxl"; + + HMIXFILE hMix=FindFileInMix(filename); + if(hMix==FALSE) + { + missingimages[lpUnittype]=TRUE; + return FALSE; + } + + + int i; + + try + { + + for(i=0;i<8;i++) + { + float r_x,r_y,r_z; + + + r_x=300; + r_y=0; + r_z=45*i+90; + + // convert + const double pi = 3.141592654; + r_x=r_x/180.0f*pi; + r_y=r_y/180.0f*pi; + r_z=r_z/180.0f*pi; + + + + LPDIRECTDRAWSURFACE4 lpT;//=new(LPDIRECTDRAWSURFACE4[1]); + LPDIRECTDRAWSURFACE4 lpTurret=NULL; + LPDIRECTDRAWSURFACE4 lpBarrel=NULL; + int turret_x,turret_y,turret_x_zmax,turret_y_zmax,barrel_x,barrel_y; + + if(isTrue(rules.sections[lpUnittype].values["Turret"])) + { + if(FSunPackLib::SetCurrentVXL(image+"tur.vxl", hMix)) + { + FSunPackLib::LoadVXLImageInSurface(*m_voxelNormalTables, lightDirection, v.dd, 0, 1, r_x, r_y, r_z, &lpTurret, m_hPalUnitTemp,&turret_x,&turret_y,0,&turret_x_zmax, &turret_y_zmax,-1,-1); + } + if(FSunPackLib::SetCurrentVXL(image+"barl.vxl", hMix)) + { + FSunPackLib::LoadVXLImageInSurface(*m_voxelNormalTables, lightDirection, v.dd, 0, 1, r_x, r_y, r_z, &lpBarrel, m_hPalUnitTemp,&barrel_x,&barrel_y,0,NULL,NULL,0,0); + } + } + + + if(!FSunPackLib::SetCurrentVXL(filename, hMix)) + { + return FALSE; + } + + + + int xcenter,ycenter,xcenter_zmax,ycenter_zmax; + + if(! + FSunPackLib::LoadVXLImageInSurface(*m_voxelNormalTables, lightDirection, v.dd, 0, 1, r_x, r_y, r_z, &lpT, m_hPalUnitTemp,&xcenter, &ycenter,0,&xcenter_zmax,&ycenter_zmax) + ) + { + return FALSE; + } + + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize=sizeof(DDSURFACEDESC2); + ddsd.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + lpT->GetSurfaceDesc(&ddsd); + + // turret + if(lpTurret) + { + DDSURFACEDESC2 ddsdT; + memset(&ddsdT, 0, sizeof(DDSURFACEDESC2)); + ddsdT.dwSize=sizeof(DDSURFACEDESC2); + ddsdT.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + lpTurret->GetSurfaceDesc(&ddsdT); + + DDBLTFX fx; + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + RECT srcRect, destRect; + srcRect.left=0; + srcRect.right=ddsdT.dwWidth; + destRect.left=xcenter_zmax-turret_x; + destRect.right=destRect.left+ddsdT.dwWidth; + srcRect.top=0; + srcRect.bottom=ddsdT.dwHeight; + destRect.top=ycenter_zmax-turret_y; + destRect.bottom=destRect.top+ddsdT.dwHeight; + + lpT->Blt(&destRect, lpTurret, &srcRect, DDBLT_KEYSRC | DDBLT_WAIT, &fx); + + } + + // barrel + if(lpBarrel) + { + DDSURFACEDESC2 ddsdB; + memset(&ddsdB, 0, sizeof(DDSURFACEDESC2)); + ddsdB.dwSize=sizeof(DDSURFACEDESC2); + ddsdB.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + lpBarrel->GetSurfaceDesc(&ddsdB); + + DDSURFACEDESC2 ddsdT; + memset(&ddsdT, 0, sizeof(DDSURFACEDESC2)); + ddsdT.dwSize=sizeof(DDSURFACEDESC2); + ddsdT.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + + if(lpTurret) lpTurret->GetSurfaceDesc(&ddsdT); + + + DDBLTFX fx; + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + + RECT srcRect, destRect; + srcRect.left=0; + srcRect.right=ddsdB.dwWidth; + destRect.left=xcenter_zmax-barrel_x+(turret_x_zmax-turret_x); + destRect.right=destRect.left+ddsdB.dwWidth; + srcRect.top=0; + srcRect.bottom=ddsdB.dwHeight; + destRect.top=ycenter_zmax-barrel_y+(turret_y_zmax-turret_y); + destRect.bottom=destRect.top+ddsdB.dwHeight; + + lpT->Blt(&destRect, lpBarrel, &srcRect, DDBLT_KEYSRC | DDBLT_WAIT, &fx); + + } + + char ic[50]; + itoa(7-i, ic, 10); + + errstream << ddsd.dwWidth << " " << ddsd.dwHeight << "\n"; + PICDATA p; + p.pic=lpT; + p.x=-xcenter; + p.y=-ycenter; + p.wHeight=ddsd.dwHeight; + p.wWidth=ddsd.dwWidth; + p.wMaxWidth=ddsd.dwWidth; + p.wMaxHeight=ddsd.dwHeight; + p.bType=PICDATA_TYPE_VXL; + p.bTerrain=0; + + pics[image+ic]=p; + + errstream << "vxl saved as " << (LPCSTR)image << (LPCSTR)ic << endl; + errstream.flush(); + + if(lpBarrel) lpBarrel->Release(); + if(lpTurret) lpTurret->Release(); + + //delete[] lpT; + + } + } + catch(...) + { + + } + + } + + + + return FALSE; +} +#endif + + +BOOL CLoading::InitMixFiles() +{ + last_succeeded_operation=8; + + MEMORYSTATUS ms; + ms.dwLength=sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&ms); + int cs=ms.dwAvailPhys+ms.dwAvailPageFile; + + errstream << "InitMixFiles() called. Available memory: " << cs << endl; + errstream.flush(); + + + // load tibsun.mix and local.mix + if(DoesFileExist((CString)TSPath+(CString)"\\"+MAINMIX)) + { + errstream << "Loading " MAINMIX ".mix" ; + errstream.flush(); + m_hTibSun=FSunPackLib::XCC_OpenMix((CString)TSPath+(CString)"\\"+MAINMIX, NULL); + if(m_hTibSun!=NULL) + { + errstream << " success" << endl; + errstream.flush(); + } + else + { + ShowWindow(SW_HIDE); + MessageBox(GetLanguageStringACP("Err_TSNotInstalled")); + exit(200); + } + + m_hLanguage=FSunPackLib::XCC_OpenMix((CString)TSPath+(CString)"\\Language.mix", NULL); + m_hLangMD=FSunPackLib::XCC_OpenMix((CString)TSPath+(CString)"\\Langmd.mix", NULL); + m_hMarble=FSunPackLib::XCC_OpenMix((CString)TSPath+(CString)"\\marble.mix", NULL); + + //if(!m_hLanguage) MessageBox("No language file found"); + + if(!m_hMarble) + { + m_hMarble=FSunPackLib::XCC_OpenMix((CString)AppPath+(CString)"\\marble.mix", NULL); + } + } + else + { + ShowWindow(SW_HIDE); + MessageBox(GetLanguageStringACP("Err_TSNotInstalled")); + exit(199); + } + + errstream << "Loading local.mix"; + errstream.flush(); + if(DoesFileExist((CString)TSPath+"\\Local.mix")==FALSE || theApp.m_Options.bSearchLikeTS==FALSE) + { + m_hLocal=FSunPackLib::XCC_OpenMix("Local.mix", m_hTibSun); + } + else + m_hLocal=FSunPackLib::XCC_OpenMix((CString)TSPath+"\\Local.mix", NULL); + errstream << " successful" << endl; + errstream.flush(); + + + + errstream << "Loading conquer.mix, temperat.mix, isotemp.mix, isosnow.mix, isourb.mix and cache.mix"; + errstream.flush(); + m_hConquer=FSunPackLib::XCC_OpenMix("conquer.mix", m_hTibSun); + m_hTemperat=FSunPackLib::XCC_OpenMix("temperat.mix", m_hTibSun); + m_hUrban=FSunPackLib::XCC_OpenMix("urban.mix", m_hTibSun); + m_hSnow=FSunPackLib::XCC_OpenMix("snow.mix", m_hTibSun); + m_hUrbanN=FSunPackLib::XCC_OpenMix("urbann.mix", m_hTibSun); + m_hLunar=FSunPackLib::XCC_OpenMix("lunar.mix", m_hTibSun); + m_hDesert=FSunPackLib::XCC_OpenMix("desert.mix", m_hTibSun); + m_hIsoTemp=FSunPackLib::XCC_OpenMix("isotemp.mix", m_hTibSun); + m_hIsoSnow=FSunPackLib::XCC_OpenMix("isosnow.mix", m_hTibSun); + m_hIsoUrb=FSunPackLib::XCC_OpenMix("isourb.mix", m_hTibSun); + m_hIsoUbn=FSunPackLib::XCC_OpenMix("isoubn.mix", m_hTibSun); + m_hIsoLun=FSunPackLib::XCC_OpenMix("isolun.mix", m_hTibSun); + m_hIsoDes=FSunPackLib::XCC_OpenMix("isodes.mix", m_hTibSun); + m_hIsoGen=FSunPackLib::XCC_OpenMix("isogen.mix", m_hTibSun); + //m_hBuildings=FSunPackLib::XCC_OpenMix("_ID1085587737", m_hTibSun); + m_hBuildings=FSunPackLib::XCC_OpenMix("Generic.mix", m_hTibSun); + m_hCache=FSunPackLib::XCC_OpenMix("cache.mix", m_hTibSun); + m_hTem=FSunPackLib::XCC_OpenMix("tem.mix", m_hTibSun); + m_hSno=FSunPackLib::XCC_OpenMix("sno.mix", m_hTibSun); + m_hUrb=FSunPackLib::XCC_OpenMix("urb.mix", m_hTibSun); + m_hUbn=FSunPackLib::XCC_OpenMix("ubn.mix", m_hTibSun); + m_hLun=FSunPackLib::XCC_OpenMix("lun.mix", m_hTibSun); + m_hDes=FSunPackLib::XCC_OpenMix("des.mix", m_hTibSun); + if(!m_hMarble) FSunPackLib::XCC_OpenMix("marble.mix", m_hTibSun); + + if(m_hMarble) theApp.m_Options.bSupportMarbleMadness=TRUE; + + errstream << " successful" << endl; + errstream.flush(); + + int i; + + yuri_mode=FALSE; + + + if(!theApp.m_Options.bSearchLikeTS) return TRUE; + + if(DoesFileExist((CString)TSPath+"\\ra2md.mix")) + yuri_mode=TRUE; // MW Apr 17th, make it available right here! + + // load expansion mix files + for(i=0;i<101;i++) + { + CString expand; + char n[50]; + + // MW April 17th, 2002: + // read expandxxmd.mix files in yurimode + + itoa(i, n, 10); + expand=TSPath; + expand+="\\Expand"; + if(yuri_mode) expand+="md"; + if(i<10) expand+="0"; + expand+=n; + expand+=".mix"; + + CString nappend=".mix"; + + CString append=".mix"; + if(i==100) append="md.mix"; + + + if(yuri_mode) append="md.mix"; + + + if(i==100) expand=(CString)TSPath+"\\ra2md.mix"; // support the mission disk!!! + + errstream << "Searching " << (LPCTSTR)expand << endl; + errstream.flush(); + + if(DoesFileExist(expand)) + { + + OutputDebugString(expand); + OutputDebugString(": "); + + + m_hExpand[i].hExpand=FSunPackLib::XCC_OpenMix(expand, NULL); + +#ifdef YR_MODE + if(i==100 && m_hExpand[i].hExpand) yuri_mode=TRUE; +#endif + + errstream << (LPCTSTR)expand << " found: loading "; + errstream.flush(); + + CString conquer="conquer"; + if(i==100) conquer="conq"; + if(FSunPackLib::XCC_DoesFileExist(conquer+append, m_hExpand[i].hExpand)) + { + OutputDebugString(conquer+append); + OutputDebugString(": "); + m_hExpand[i].hConquer=FSunPackLib::XCC_OpenMix((CString)conquer+append, m_hExpand[i].hExpand); + errstream << "conquer.mix, "; + } + if(FSunPackLib::XCC_DoesFileExist((CString)"local"+append, m_hExpand[i].hExpand)) + { + OutputDebugString((CString)"local"+append); + OutputDebugString(": "); + m_hExpand[i].hLocal=FSunPackLib::XCC_OpenMix((CString)"local"+append, m_hExpand[i].hExpand); + errstream << "local.mix, "; + } + //if(FSunPackLib::XCC_DoesFileExist("_ID1085587737", m_hExpand[i].hExpand)) + { + //m_hExpand[i].hConquer=FSunPackLib::XCC_OpenMix("_ID1085587737", m_hExpand[i].hExpand); + //errstream << "1085587737, "; + } + if(FSunPackLib::XCC_DoesFileExist((CString)"temperat"+append, m_hExpand[i].hExpand)) + { + OutputDebugString((CString)"temperat"+append); + OutputDebugString(": "); + m_hExpand[i].hTemperat=FSunPackLib::XCC_OpenMix((CString)"temperat"+append, m_hExpand[i].hExpand); + errstream << "temperat.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"urban"+append, m_hExpand[i].hExpand)) + { + OutputDebugString((CString)"urban"+append); + OutputDebugString(": "); + m_hExpand[i].hUrban=FSunPackLib::XCC_OpenMix((CString)"urban"+append, m_hExpand[i].hExpand); + errstream << "urban.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"snow"+append, m_hExpand[i].hExpand)) + { + OutputDebugString((CString)"snow"+append); + OutputDebugString(": "); + + FSunPackLib::_DEBUG_EnableLogs=true; + + HMIXFILE hM=FSunPackLib::XCC_OpenMix((CString)"snow"+append, m_hExpand[i].hExpand); + m_hExpand[i].hSnow=hM; + errstream << "snow.mix, "; + errstream.flush(); + + FSunPackLib::_DEBUG_EnableLogs=false; + } + + CString generic="generic"; + if(i==100) generic="gener"; + if(FSunPackLib::XCC_DoesFileExist((CString)generic+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hGeneric=FSunPackLib::XCC_OpenMix((CString)generic+append, m_hExpand[i].hExpand); + errstream << "generic.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"urbann"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hUrbanN=FSunPackLib::XCC_OpenMix((CString)"urbann"+nappend, m_hExpand[i].hExpand); + errstream << "urbann.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"lunar"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hLunar=FSunPackLib::XCC_OpenMix((CString)"lunar"+nappend, m_hExpand[i].hExpand); + errstream << "lunar.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"desert"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hDesert=FSunPackLib::XCC_OpenMix((CString)"desert"+nappend, m_hExpand[i].hExpand); + errstream << "desert.mix, "; + errstream.flush(); + } + CString isotemp="isotemp"; + if(i==100) isotemp="isotem"; + if(FSunPackLib::XCC_DoesFileExist(isotemp+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoTemp=FSunPackLib::XCC_OpenMix((CString)isotemp+append, m_hExpand[i].hExpand); + errstream << "isotemp.mix, "; + errstream.flush(); + } + CString isosnow="isosnow"; + if(i==100) isosnow="isosno"; + if(FSunPackLib::XCC_DoesFileExist((CString)isosnow+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoSnow=FSunPackLib::XCC_OpenMix((CString)isosnow+append, m_hExpand[i].hExpand); + errstream << "isosnow.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"isourb"+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoUrb=FSunPackLib::XCC_OpenMix((CString)"isourb"+append, m_hExpand[i].hExpand); + errstream << "isourb.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"isoubn"+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoUbnMd=FSunPackLib::XCC_OpenMix((CString)"isoubn"+append, m_hExpand[i].hExpand); + errstream << "isoubn.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"isolun"+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoLunMd=FSunPackLib::XCC_OpenMix((CString)"isolun"+append, m_hExpand[i].hExpand); + errstream << "isolun.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"isodes"+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoDesMd=FSunPackLib::XCC_OpenMix((CString)"isodes"+append, m_hExpand[i].hExpand); + errstream << "isodes.mix, "; + errstream.flush(); + } + + if(FSunPackLib::XCC_DoesFileExist((CString)"isoubn"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoUbn=FSunPackLib::XCC_OpenMix((CString)"isoubn"+nappend, m_hExpand[i].hExpand); + errstream << "isoubn.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"isolun"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoLun=FSunPackLib::XCC_OpenMix((CString)"isolun"+nappend, m_hExpand[i].hExpand); + errstream << "isolun.mix, "; + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"isodes"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoDes=FSunPackLib::XCC_OpenMix((CString)"isodes"+nappend, m_hExpand[i].hExpand); + errstream << "isodes.mix, "; + errstream.flush(); + } + + if(FSunPackLib::XCC_DoesFileExist((CString)"isogen"+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoGenMd=FSunPackLib::XCC_OpenMix((CString)"isogen"+append, m_hExpand[i].hExpand); + errstream << "isogen.mix, "; + errstream.flush(); + } + + if(FSunPackLib::XCC_DoesFileExist((CString)"isogen"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hIsoGen=FSunPackLib::XCC_OpenMix((CString)"isogen"+nappend, m_hExpand[i].hExpand); + errstream << "isogen.mix, "; + errstream.flush(); + } + + CString cache="ecache01"; + if(i==100) cache="cache"; + if(FSunPackLib::XCC_DoesFileExist((CString)cache+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hECache=FSunPackLib::XCC_OpenMix((CString)cache+append, m_hExpand[i].hExpand); + errstream << LPCSTR("ecache01"+append+", "); + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"tem"+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hTem=FSunPackLib::XCC_OpenMix((CString)"tem"+append, m_hExpand[i].hExpand); + errstream << LPCSTR("tem"+append+", "); + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"sno"+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hSno=FSunPackLib::XCC_OpenMix((CString)"sno"+append, m_hExpand[i].hExpand); + errstream << LPCSTR("sno"+append+", "); + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"urb"+append, m_hExpand[i].hExpand)) + { + m_hExpand[i].hUrb=FSunPackLib::XCC_OpenMix((CString)"urb"+append, m_hExpand[i].hExpand); + errstream << LPCSTR("urb"+append+", "); + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"ubn"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hUbn=FSunPackLib::XCC_OpenMix((CString)"ubn"+nappend, m_hExpand[i].hExpand); + errstream << LPCSTR("ubn"+nappend+", "); + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"lun"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hLun=FSunPackLib::XCC_OpenMix((CString)"lun"+nappend, m_hExpand[i].hExpand); + errstream << LPCSTR("lun"+nappend+", "); + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"des"+nappend, m_hExpand[i].hExpand)) + { + m_hExpand[i].hDes=FSunPackLib::XCC_OpenMix((CString)"des"+nappend, m_hExpand[i].hExpand); + errstream << LPCSTR("des"+nappend+", "); + errstream.flush(); + } + if(FSunPackLib::XCC_DoesFileExist((CString)"marble"+append, m_hExpand[i].hExpand)) + { + theApp.m_Options.bSupportMarbleMadness=TRUE; + + m_hExpand[i].hMarble=FSunPackLib::XCC_OpenMix((CString)"marble"+append, m_hExpand[i].hExpand); + errstream << LPCSTR("marble"+append+", "); + errstream.flush(); + } + + errstream << endl; + errstream.flush(); + } + else + { + m_hExpand[i].hExpand=NULL; + } + } + + // load expansion ecache mix files + for(i=0;i<100;i++) + { + CString expand; + char n[50]; + + itoa(i, n, 10); + expand=TSPath; + if(!yuri_mode) expand+="\\ECache"; + else expand+="\\ecachemd"; + + if(i<10) expand+="0"; + expand+=n; + expand+=".mix"; + + + if(DoesFileExist(expand)) + { + m_hECache[i]=FSunPackLib::XCC_OpenMix(expand, NULL); + errstream << (LPCTSTR)expand << " found and loaded" << endl; + errstream.flush(); + } + else + { + m_hECache[i]=NULL; + } + } + + ms.dwLength=sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&ms); + cs=ms.dwAvailPhys+ms.dwAvailPageFile; + + errstream << "InitMixFiles() finished. Available memory: " << cs << endl; + errstream.flush(); + + return TRUE; +} + +CLoading::~CLoading() +{ + Unload(); +} + +void CLoading::Unload() +{ + FSunPackLib::XCC_CloseMix(m_hCache); + FSunPackLib::XCC_CloseMix(m_hConquer); + FSunPackLib::XCC_CloseMix(m_hIsoSnow); + FSunPackLib::XCC_CloseMix(m_hIsoTemp); + FSunPackLib::XCC_CloseMix(m_hIsoUrb); + FSunPackLib::XCC_CloseMix(m_hIsoGen); + FSunPackLib::XCC_CloseMix(m_hLocal); + FSunPackLib::XCC_CloseMix(m_hTemperat); + FSunPackLib::XCC_CloseMix(m_hSnow); + FSunPackLib::XCC_CloseMix(m_hUrban); + FSunPackLib::XCC_CloseMix(m_hTibSun); + FSunPackLib::XCC_CloseMix(m_hSno); + FSunPackLib::XCC_CloseMix(m_hTem); + FSunPackLib::XCC_CloseMix(m_hUrb); + FSunPackLib::XCC_CloseMix(m_hBuildings); + + + m_hCache = NULL; + m_hConquer = NULL; + m_hIsoSnow = NULL; + m_hIsoTemp = NULL; + m_hIsoUrb = NULL; + m_hLocal = NULL; + m_hTemperat = NULL; + m_hSnow = NULL; + m_hUrban = NULL; + m_hTibSun = NULL; + m_hBuildings = NULL; + m_hIsoGen = NULL; + + + int i = 0; + for (i = 0;i < 100; i++) + { + FSunPackLib::XCC_CloseMix(m_hExpand[i].hExpand); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hConquer); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hECache); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hIsoSnow); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hIsoTemp); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hIsoUrb); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hIsoGen); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hTemperat); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hSnow); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hUrban); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hSno); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hTem); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hUrb); + FSunPackLib::XCC_CloseMix(m_hExpand[i].hBuildings); + m_hExpand[i].hExpand = NULL; + } + + for (i = 0;i < 100; i++) + { + FSunPackLib::XCC_CloseMix(m_hECache[i]); + } + + MEMORYSTATUS ms; + ms.dwLength = sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&ms); + int cs = ms.dwAvailPhys + ms.dwAvailPageFile; + + errstream << "CLoading::Unload finished. Available memory: " << cs << endl; + errstream.flush(); +} + + +HMIXFILE CLoading::FindFileInMix(LPCTSTR lpFilename, TheaterChar* pTheaterChar) +{ + if(pTheaterChar) + *pTheaterChar = TheaterChar::None; + + int i; + // MW: added ecache support + for(i=100;i>=0; i--) + { + HMIXFILE cuExp=m_hECache[i]; + + if(cuExp!=NULL) + { + if(FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp)) + return cuExp; + } + } + + for(i=100;i>=0; i--) + { + EXPANDMIX cuExp=m_hExpand[i]; + + if(cuExp.hExpand!=NULL) + { + if(FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hExpand)) + return cuExp.hExpand; + if(cuExp.hECache!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hECache)) + return cuExp.hECache; + if(cuExp.hConquer!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hConquer)) + return cuExp.hConquer; + if(cuExp.hLocal!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hLocal)) + return cuExp.hLocal; + if(cuExp.hTemperat!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hTemperat)) + return cuExp.hTemperat; + if(strcmp(lpFilename,"yayard.shp")==NULL) + FSunPackLib::_DEBUG_EnableLogs=true; + if(cuExp.hSnow!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hSnow)) + return cuExp.hSnow; + FSunPackLib::_DEBUG_EnableLogs=false; + if(cuExp.hGeneric!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hGeneric)) + return cuExp.hGeneric; + if(cuExp.hUrban!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hUrban)) + return cuExp.hUrban; + if(cuExp.hUrbanN!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hUrbanN)) + return cuExp.hUrbanN; + if(cuExp.hLunar!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hLunar)) + return cuExp.hLunar; + if(cuExp.hDesert!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hDesert)) + return cuExp.hDesert; + if(cuExp.hBuildings!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hBuildings)) + return cuExp.hBuildings; + if(cuExp.hIsoGen!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoGen)) + return cuExp.hIsoGen; + if(cuExp.hIsoGenMd!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoGenMd)) + return cuExp.hIsoGenMd; + if(cuExp.hIsoTemp!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoTemp)) + { + if(pTheaterChar) *pTheaterChar=TheaterChar::T; + return cuExp.hIsoTemp; + } + if(cuExp.hIsoSnow!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoSnow)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::A; + return cuExp.hIsoSnow; + } + if(cuExp.hIsoUrb!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoUrb)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::U; + return cuExp.hIsoUrb; + } + if(cuExp.hIsoUbn!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoUbn)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::N; + return cuExp.hIsoUbn; + } + if(cuExp.hIsoDes!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoDes)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::D; + return cuExp.hIsoDes; + } + if(cuExp.hIsoLun!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoLun)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::L; + return cuExp.hIsoLun; + } + if(cuExp.hIsoUbnMd!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoUbnMd)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::N; + return cuExp.hIsoUbnMd; + } + if(cuExp.hIsoDesMd!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoDesMd)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::D; + return cuExp.hIsoDesMd; + } + if(cuExp.hIsoLunMd!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hIsoLunMd)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::L; + return cuExp.hIsoLunMd; + } + if(cuExp.hSno!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hSno)) + return cuExp.hSno; + if(cuExp.hTem!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hTem)) + return cuExp.hTem; + if(cuExp.hUrb!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hUrb)) + return cuExp.hUrb; + if(cuExp.hUbn!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hUbn)) + return cuExp.hUbn; + if(cuExp.hLun!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hLun)) + return cuExp.hLun; + if(cuExp.hDes!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hDes)) + return cuExp.hDes; + if(cuExp.hMarble!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, cuExp.hMarble)) + return cuExp.hMarble; + } + } + + if(m_hTibSun!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hTibSun)) + return m_hTibSun; + if(m_hLanguage!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hLanguage)) + return m_hLanguage; + if(m_hLangMD!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hLangMD)) + return m_hLangMD; + if(m_hLocal!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hLocal)) + return m_hLocal; + if(m_hBuildings!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hBuildings)) + return m_hBuildings; + if(m_hCache!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hCache)) + return m_hCache; + if(m_hConquer!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hConquer)) + return m_hConquer; + if(m_hTemperat!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hTemperat)) + return m_hTemperat; + if(m_hSnow!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hSnow)) + return m_hSnow; + if(m_hUrban!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hUrban)) + return m_hUrban; + if(m_hUrbanN!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hUrbanN)) + return m_hUrbanN; + if(m_hLunar!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hLunar)) + return m_hLunar; + if(m_hDesert!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hDesert)) + return m_hDesert; + if(m_hIsoGen!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hIsoGen)) + { + return m_hIsoGen; + } + if(m_hIsoTemp!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hIsoTemp)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::T; + return m_hIsoTemp; + } + if(m_hIsoSnow!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hIsoSnow)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::A; + return m_hIsoSnow; + } + if(m_hIsoUrb!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hIsoUrb)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::U; + return m_hIsoUrb; + } + if(m_hIsoUbn!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hIsoUbn)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::N; + return m_hIsoUbn; + } + if(m_hIsoLun!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hIsoLun)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::L; + return m_hIsoLun; + } + if(m_hIsoDes!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hIsoDes)) + { + if(pTheaterChar) *pTheaterChar = TheaterChar::D; + return m_hIsoDes; + } + if(m_hTem!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hTem)) + return m_hTem; + if(m_hSno!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hSno)) + return m_hSno; + if(m_hUrb!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hUrb)) + return m_hUrb; + if(m_hUbn!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hUbn)) + return m_hUbn; + if(m_hLun!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hLun)) + return m_hLun; + if(m_hDes!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hDes)) + return m_hDes; + + if(m_hMarble!=NULL && FSunPackLib::XCC_DoesFileExist(lpFilename, m_hMarble)) + return m_hMarble; + + + + return NULL; +} + + + +void CLoading::InitPalettes() +{ + errstream << "InitPalettes() called\n"; + if(!FSunPackLib::XCC_ExtractFile("isotem.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "IsoTem.pal failed\n"; + m_hPalIsoTemp=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("isosno.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "IsoSno.pal failed\n"; + m_hPalIsoSnow=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("isourb.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "IsoUrb.pal failed\n"; + m_hPalIsoUrb=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + HMIXFILE m_hCache2=m_hExpand[100].hECache; + if(!FSunPackLib::XCC_ExtractFile("isolun.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache2)) + errstream << "IsoLun.pal failed\n"; + m_hPalIsoLun=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("isodes.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache2)) + errstream << "IsoDes.pal failed\n"; + m_hPalIsoDes=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("isoubn.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache2)) + errstream << "IsoUbn.pal failed\n"; + m_hPalIsoUbn=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + + if(!FSunPackLib::XCC_ExtractFile("unittem.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "UnitTem.pal failed"; + m_hPalUnitTemp=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("unitsno.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "UnitSno.pal failed\n"; + m_hPalUnitSnow=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("uniturb.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "UnitUrb.pal failed\n"; + m_hPalUnitUrb=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + + if(!FSunPackLib::XCC_ExtractFile("unitlun.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache2)) + errstream << "UnitLun.pal failed\n"; + m_hPalUnitLun=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("unitdes.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache2)) + errstream << "UnitDes.pal failed\n"; + m_hPalUnitDes=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("unitubn.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache2)) + errstream << "UnitUbn.pal failed\n"; + m_hPalUnitUbn=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + + if(!FSunPackLib::XCC_ExtractFile("snow.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "Snow.pal failed\n"; + m_hPalSnow=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("temperat.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "Temperat.pal failed\n"; + m_hPalTemp=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("urban.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "Urban.pal failed\n"; + m_hPalUrb=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + + if(!FSunPackLib::XCC_ExtractFile("lunar.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache2)) + errstream << "lunar.pal failed\n"; + m_hPalLun=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("desert.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache2)) + errstream << "desert.pal failed\n"; + m_hPalDes=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + if(!FSunPackLib::XCC_ExtractFile("urbann.pal", u8AppDataPath+"\\TmpPalette.pal", m_hCache2)) + errstream << "urbann.pal failed\n"; + m_hPalUbn=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + + if(!FSunPackLib::XCC_ExtractFile("_ID2124019542", u8AppDataPath+"\\TmpPalette.pal", m_hCache)) + errstream << "lib.pal failed\n"; + m_hPalLib=FSunPackLib::LoadTSPalette(u8AppDataPath+"\\TmpPalette.pal", NULL); + deleteFile(u8AppDataPath +"\\TmpPalette.pal"); + + + errstream << "\n"; + errstream.flush(); + + +} + +void CLoading::InitTMPs(CProgressCtrl* prog) +{ + FetchPalettes(); + + + MEMORYSTATUS ms; + ms.dwLength=sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&ms); + int cs=ms.dwAvailPhys+ms.dwAvailPageFile; + + errstream << "InitTMPs() called. Available memory: " << cs << endl; + errstream.flush(); + + // we need to have that here, CMapData::UpdateIniFile() is too late for the shore hack + shoreset=atoi((*tiles).sections["General"].values["ShorePieces"]); + waterset=atoi((*tiles).sections["General"].values["WaterSet"]); + + + + + + + int i, tcount=0; + + for(i=0;i<10000;i++) + { + CString tset; + char c[50]; + itoa(i, c, 10); + int e; + for(e=0;e<4-strlen(c);e++) + tset+="0"; + tset+=c; + CString sec="TileSet"; + sec+=tset; + + if(tiles->sections.find(sec)==tiles->sections.end()) break; + + for(e=0;e<atoi(tiles->sections[sec].values["TilesInSet"]);e++) + { + tcount++; + } + + + } + + if(prog) prog->SetRange(0, tcount); + if(prog) prog->SetPos(0); + + if(*tiledata!=NULL) delete[] *tiledata; + *tiledata=new(TILEDATA[tcount]); + *tiledata_count=tcount; + + DWORD tilecount=0; + for(i=0;i<10000;i++) + { + CString tset; + char c[50]; + itoa(i, c, 10); + int e; + for(e=0;e<4-strlen(c);e++) + tset+="0"; + tset+=c; + CString sec="TileSet"; + sec+=tset; + + if(tiles->sections.find(sec)==tiles->sections.end()) break; + + BOOL bTib, bMorph, bPlace, bMadness; + bPlace=TRUE; + bTib=FALSE; + bMorph=FALSE; + bMadness=FALSE; + tiles->sections[sec].values["AllowTiberium"].MakeLower(); + if(tiles->sections[sec].values["AllowTiberium"]=="true") + bTib=TRUE; + tiles->sections[sec].values["Morphable"].MakeLower(); + if(tiles->sections[sec].values["Morphable"]=="true") + bMorph=TRUE; + tiles->sections[sec].values["AllowToPlace"].MakeLower(); + if(tiles->sections[sec].values["AllowToPlace"]=="no") + bPlace=FALSE; + tiles->sections[sec].values["NonMarbleMadness"].MakeLower(); + if(tiles->sections[sec].values["NonMarbleMadness"].GetLength()>0) + bMadness=TRUE; + auto tilesetAnimSection = tiles->GetSection(tiles->sections[sec].GetValueByName("SetName")); + + tilesets_start[i]=tilecount; + + + for(e=0;e<atoi(tiles->sections[sec].values["TilesInSet"]);e++) + { + std::string sId = std::format("{:02}", e + 1); + CString filename=tiles->sections[sec].values["FileName"]; + filename+=sId.c_str(); + + CString bas_f=filename; + + CString suffix; + + if(tiles==&tiles_t) suffix =".tem"; + if(tiles==&tiles_s) suffix =".sno"; + if(tiles==&tiles_u) suffix =".urb"; + if(tiles==&tiles_un) suffix =".ubn"; + if(tiles==&tiles_l) suffix =".lun"; + if(tiles==&tiles_d) suffix =".des"; + + filename += suffix; + HTSPALETTE hPalette=m_hPalIsoTemp; + if(tiles==&tiles_s) hPalette=m_hPalIsoSnow; + if(tiles==&tiles_u) hPalette=m_hPalIsoUrb; + if(tiles==&tiles_t) hPalette=m_hPalIsoTemp; + if(tiles==&tiles_un) hPalette=m_hPalIsoUbn; + if(tiles==&tiles_d) hPalette=m_hPalIsoDes; + if(tiles==&tiles_l) hPalette=m_hPalIsoLun; + + // MW add: use other... + if(FindFileInMix(filename)==NULL && tiles==&tiles_un) { filename=bas_f+".urb"; hPalette=m_hPalIsoUrb; } + if(FindFileInMix(filename)==NULL) { filename=bas_f+".tem"; hPalette=m_hPalIsoTemp; } + + (*tiledata)[tilecount].bAllowTiberium=bTib; + (*tiledata)[tilecount].bAllowToPlace=bPlace; + (*tiledata)[tilecount].bMorphable=bMorph; + (*tiledata)[tilecount].bMarbleMadness=bMadness; + (*tiledata)[tilecount].wTileSet=i; + + int reps; + for(reps=0;reps<5;reps++) + { + CString r_filename=filename; + + if(reps>0) + { + char c[3]; + c[0]='a'+reps-1; + c[1]='.'; + c[2]=0; + + r_filename.Replace(".", c); + + if(!LoadTile(r_filename, FindFileInMix(filename), hPalette, tilecount, TRUE)) + break; + } + else + { + LoadTile(filename, FindFileInMix(filename), hPalette, tilecount, FALSE); + } + } + + if (tilesetAnimSection) + { + auto anim = tilesetAnimSection->GetValueByName(std::format("Tile{}Anim", sId).c_str()); + auto offsetX = std::atoi(tilesetAnimSection->GetValueByName(std::format("Tile{}XOffset", sId).c_str())); + auto offsetY = std::atoi(tilesetAnimSection->GetValueByName(std::format("Tile{}YOffset", sId).c_str())); + auto attachesTo = std::atoi(tilesetAnimSection->GetValueByName(std::format("Tile{}AttachesTo", sId).c_str())); + auto animFileName = anim + suffix; + HMIXFILE hAnimMix = FindFileInMix(animFileName); + if (hAnimMix) + { + auto& tile = (*tiledata)[tilecount]; + if (tile.wTileCount <= attachesTo) + { + ASSERT(tile.wTileCount > attachesTo); + } + else + { + auto& subtile = tile.tiles[attachesTo]; + SHPHEADER shp_h; + SHPIMAGEHEADER shpi_h; + auto animPic = std::make_shared<PICDATA>(); + auto rawPic = std::make_shared<std::vector<BYTE>>(); + animPic->rawPic = rawPic; + FSunPackLib::SetCurrentSHP(animFileName, hAnimMix); + FSunPackLib::XCC_GetSHPHeader(&shp_h); + int imageNum = 1; + FSunPackLib::XCC_GetSHPImageHeader(1, &shpi_h); + if (shpi_h.unknown == 0) + { + // shadow + imageNum = 0; + } + FSunPackLib::XCC_GetSHPImageHeader(imageNum, &shpi_h); + if (FSunPackLib::LoadSHPImage(imageNum, *rawPic)) + { + subtile.anim = animPic; + animPic->pic = animPic->rawPic->data(); + animPic->bType = PICDATA_TYPE_SHP; + animPic->pal = iPalIso; + animPic->wWidth = animPic->wMaxWidth = shp_h.cx; + animPic->wHeight = animPic->wMaxHeight = shp_h.cy; + animPic->x = offsetX; + animPic->y = offsetY; + animPic->createVBorder(); + } + } + } + } + + tilecount++; + if(prog!=NULL /*&& tilecount%15==0*/) + { + prog->SetPos(tilecount); + prog->UpdateWindow(); + } + } + + + } + + tilecount=0; + for(i=0;i<10000;i++) + { + CString tset; + char c[50]; + itoa(i, c, 10); + int e; + for(e=0;e<4-strlen(c);e++) + tset+="0"; + tset+=c; + CString sec="TileSet"; + sec+=tset; + + if(tiles->sections.find(sec)==tiles->sections.end()) break; + + + int madnessid=atoi(tiles->sections[sec].values["MarbleMadness"]); + + for(e=0;e<atoi(tiles->sections[sec].values["TilesInSet"]);e++) + { + if(madnessid) + { + (*tiledata)[tilecount].wMarbleGround=tilesets_start[madnessid]+(tilecount-tilesets_start[i]); + } + else + (*tiledata)[tilecount].wMarbleGround=0xFFFF; + + tilecount++; + + } + + + } + +} + +#ifdef NOSURFACES // first version, using palettized (or extracted) data +BOOL CLoading::LoadTile(LPCSTR lpFilename, HMIXFILE hOwner, HTSPALETTE hPalette, DWORD dwID, BOOL bReplacement) +{ + last_succeeded_operation=12; + + + int tileCount; + + if(FSunPackLib::XCC_DoesFileExist(lpFilename, hOwner)) + { + FSunPackLib::SetCurrentTMP(lpFilename, hOwner); + { + + //FSunPackLib::SetCurrentTMP((CString)AppPath+"\\TmpTmp.tmp"/* lpFilename*/, NULL/*hOwner*/); + int tileWidth, tileHeight; + RECT rect; + FSunPackLib::XCC_GetTMPInfo(&rect, &tileCount, &tileWidth, &tileHeight); + + + BYTE** pics=new(BYTE*[tileCount]); + + if(FSunPackLib::LoadTMPImage(0, tileCount, pics)) // be aware this allocates memory! + //if(FSunPackLib::LoadTMPImageInSurface(v.dd,lpFilename, 0, tileCount, pics, hPalette, hOwner)) + { + TILEDATA* td; + if(!bReplacement) td=&(*tiledata)[dwID]; + else + { + + TILEDATA* lpTmp=NULL; + if((*tiledata)[dwID].bReplacementCount) + { + lpTmp=new(TILEDATA[(*tiledata)[dwID].bReplacementCount]); + memcpy(lpTmp, (*tiledata)[dwID].lpReplacements, sizeof(TILEDATA)* (*tiledata)[dwID].bReplacementCount); + } + + (*tiledata)[dwID].lpReplacements=new(TILEDATA[(*tiledata)[dwID].bReplacementCount+1]); + + if((*tiledata)[dwID].bReplacementCount) + { + memcpy((*tiledata)[dwID].lpReplacements, lpTmp, sizeof(TILEDATA)*(*tiledata)[dwID].bReplacementCount); + delete[] lpTmp; + } + + td=&(*tiledata)[dwID].lpReplacements[(*tiledata)[dwID].bReplacementCount]; + (*tiledata)[dwID].bReplacementCount++; + } + + + td->tiles=new(SUBTILE[tileCount]); + td->wTileCount=tileCount; + td->cx=tileWidth; + td->cy=tileHeight; + td->rect=rect; + + int i; + for(i=0;i<tileCount;i++) + { + if(pics[i]!=NULL) + { + + int cx,cy; + BYTE height,terraintype,direction; + POINT p; + FSunPackLib::XCC_GetTMPTileInfo(i, &p, &cx, &cy, &direction, &height, &terraintype, &td->tiles[i].rgbLeft, &td->tiles[i].rgbRight); + + td->tiles[i].pic=pics[i]; + td->tiles[i].sX=p.x; + td->tiles[i].sY=p.y; + td->tiles[i].wWidth=cx; + td->tiles[i].wHeight=cy; + td->tiles[i].bZHeight=height; + td->tiles[i].bTerrainType=terraintype; + td->tiles[i].bHackedTerrainType=terraintype; + td->tiles[i].bDirection=direction; + + td->tiles[i].vborder=new(VBORDER[cy]); + + int k; + int size=0; + BOOL TranspInside=FALSE; + for(k=0;k<cy;k++) + { + int l,r; + BOOL* ti=NULL; + if(!TranspInside) ti=&TranspInside; + GetDrawBorder(pics[i], cx, k, l, r, 0, ti); + td->tiles[i].vborder[k].left=l; + td->tiles[i].vborder[k].right=r; + + if(r>=l) + size+=r-l+1; + } + +#ifdef NOSURFACES_EXTRACT + + if(!TranspInside) + { + // extract the palette data! + td->tiles[i].bNotExtracted=FALSE; + td->tiles[i].pic=new(BYTE[size*bpp]); + int l; + int pos=0; + for(k=0;k<cy;k++) + { + int left, right; + left=td->tiles[i].vborder[k].left; + right=td->tiles[i].vborder[k].right; + for(l=left;l<=right;l++) + { + memcpy(&td->tiles[i].pic[pos], &iPalIso[pics[i][l+k*cx]], bpp); + pos+=bpp; + } + } + delete[] pics[i]; + } + else + td->tiles[i].bNotExtracted=TRUE; +#endif + + + if(terraintype==0xa) + { +#ifdef RA2_MODE + td->tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; +#else + td->tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; +#endif + } + if(terraintype==TERRAINTYPE_ROUGH) td->tiles[i].bHackedTerrainType=TERRAINTYPE_GROUND; + + //if((*tiledata)[dwID].wTileSet==waterset) (*tiledata)[dwID].tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; + + // shore hack: check fsdata.ini for new shore terrain + if(td->wTileSet==shoreset) + { + int h; + for(h=0;h<(*tiledata_count);h++) + { + if((*tiledata)[h].wTileSet==shoreset) break; + } + + int pos=dwID-h; + char c[50]; + itoa(pos,c,10); + CString hack=c; + hack+="_"; + itoa(i, c, 10); + hack+=c;/* + hack+="_"; + itoa(i/tileWidth, c, 10); + hack+=c;*/ + + CString section="ShoreTerrainTS"; +#ifdef RA2_MODE + section="ShoreTerrainRA2"; +#endif + + if(g_data.sections[section].FindName(hack)>=0) + { + int t=atoi(g_data.sections[section].values[hack]); + if(t) td->tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; + else + td->tiles[i].bHackedTerrainType=0xe; + } + } + if((*tiledata)[dwID].wTileSet==waterset) (*tiledata)[dwID].tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; + } + else + { + td->tiles[i].pic=NULL; + td->tiles[i].sX=0; + td->tiles[i].sY=0; + td->tiles[i].wWidth=0; + td->tiles[i].wHeight=0; + td->tiles[i].bZHeight=0; + td->tiles[i].bTerrainType=0; + td->tiles[i].bDirection=0; + td->tiles[i].vborder=NULL; + + } + } + } + + if(tileCount>0) delete[] pics; + } + } + else + { + errstream << lpFilename << " not found" << endl; + return FALSE; + } + + + + + + return TRUE; + + +} +#else // now standard version, with surfaces +BOOL CLoading::LoadTile(LPCSTR lpFilename, HMIXFILE hOwner, HTSPALETTE hPalette, DWORD dwID, BOOL bReplacement) +{ + last_succeeded_operation=12; + + //errstream << "Loading " << lpFilename << " owned by " << hOwner << ", palette " << hPalette ; + //errstream << lpFilename << endl; + //errstream.flush(); + + CIsoView& v=*((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + + + //DeleteFile((CString)AppPath+(CString)"\\TmpTmp.tmp"); + //FSunPackLib::XCC_ExtractFile(lpFilename, (CString)AppPath+(CString)"\\TmpTmp.tmp" /*lpFilename*//*, hOwner); + + int tileCount; + try{ + if(FSunPackLib::XCC_DoesFileExist(lpFilename, hOwner)) + //if(DoesFileExist((CString)AppPath+(CString)"\\TmpTmp.tmp")) + { + //if( + FSunPackLib::SetCurrentTMP(lpFilename, hOwner); + //) + { + + //FSunPackLib::SetCurrentTMP((CString)AppPath+"\\TmpTmp.tmp"/* lpFilename*//*, NULL/*hOwner*//*); + int tileWidth, tileHeight; + RECT rect; + FSunPackLib::XCC_GetTMPInfo(&rect, &tileCount, &tileWidth, &tileHeight); + + + LPDIRECTDRAWSURFACE4* pics=new(LPDIRECTDRAWSURFACE4[tileCount]); + if(FSunPackLib::LoadTMPImageInSurface(v.dd,0, tileCount, pics, hPalette)) + //if(FSunPackLib::LoadTMPImageInSurface(v.dd,lpFilename, 0, tileCount, pics, hPalette, hOwner)) + { + TILEDATA* td; + if(!bReplacement) td=&(*tiledata)[dwID]; + else + { + + TILEDATA* lpTmp=NULL; + if((*tiledata)[dwID].bReplacementCount) + { + lpTmp=new(TILEDATA[(*tiledata)[dwID].bReplacementCount]); + memcpy(lpTmp, (*tiledata)[dwID].lpReplacements, sizeof(TILEDATA)* (*tiledata)[dwID].bReplacementCount); + } + + (*tiledata)[dwID].lpReplacements=new(TILEDATA[(*tiledata)[dwID].bReplacementCount+1]); + + if((*tiledata)[dwID].bReplacementCount) + { + memcpy((*tiledata)[dwID].lpReplacements, lpTmp, sizeof(TILEDATA)*(*tiledata)[dwID].bReplacementCount); + delete[] lpTmp; + } + + td=&(*tiledata)[dwID].lpReplacements[(*tiledata)[dwID].bReplacementCount]; + (*tiledata)[dwID].bReplacementCount++; + } + + + td->tiles=new(SUBTILE[tileCount]); + td->wTileCount=tileCount; + td->cx=tileWidth; + td->cy=tileHeight; + td->rect=rect; + + int i; + for(i=0;i<tileCount;i++) + { + if(pics[i]!=NULL) + { + + int cx,cy; + BYTE height,terraintype,direction; + POINT p; + FSunPackLib::XCC_GetTMPTileInfo(i, &p, &cx, &cy, &direction, &height, &terraintype, &td->tiles[i].rgbLeft, &td->tiles[i].rgbRight); + td->tiles[i].pic=pics[i]; + td->tiles[i].sX=p.x; + td->tiles[i].sY=p.y; + td->tiles[i].wWidth=cx; + td->tiles[i].wHeight=cy; + td->tiles[i].bZHeight=height; + td->tiles[i].bTerrainType=terraintype; + td->tiles[i].bHackedTerrainType=terraintype; + td->tiles[i].bDirection=direction; + + if(terraintype==0xa) + { +#ifdef RA2_MODE + td->tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; +#else + td->tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; +#endif + } + if(terraintype==TERRAINTYPE_ROUGH) td->tiles[i].bHackedTerrainType=TERRAINTYPE_GROUND; + + //if((*tiledata)[dwID].wTileSet==waterset) (*tiledata)[dwID].tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; + + // shore hack: check fsdata.ini for new shore terrain + if(td->wTileSet==shoreset) + { + int h; + for(h=0;h<(*tiledata_count);h++) + { + if((*tiledata)[h].wTileSet==shoreset) break; + } + + int pos=dwID-h; + char c[50]; + itoa(pos,c,10); + CString hack=c; + hack+="_"; + itoa(i, c, 10); + hack+=c;/* + hack+="_"; + itoa(i/tileWidth, c, 10); + hack+=c;*/ + + CString section="ShoreTerrainTS"; +#ifdef RA2_MODE + section="ShoreTerrainRA2"; +#endif + + if(g_data.sections[section].FindName(hack)>=0) + { + int t=atoi(g_data.sections[section].values[hack]); + if(t) td->tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; + else + td->tiles[i].bHackedTerrainType=0xe; + } + } + if((*tiledata)[dwID].wTileSet==waterset) (*tiledata)[dwID].tiles[i].bHackedTerrainType=TERRAINTYPE_WATER; + } + else + { + td->tiles[i].pic=NULL; + td->tiles[i].sX=0; + td->tiles[i].sY=0; + td->tiles[i].wWidth=0; + td->tiles[i].wHeight=0; + td->tiles[i].bZHeight=0; + td->tiles[i].bTerrainType=0; + td->tiles[i].bDirection=0; + } + } + } + + if(tileCount>0) delete[] pics; + } + } + else + { + //errstream << " not found" << endl; + return FALSE; + } + } + catch(...) + { + + } + + if((*tiledata)[dwID].wTileCount==0 || (*tiledata)[dwID].tiles[0].pic==NULL) + { + //errstream << " failed" << endl; + //errstream.flush(); + + return FALSE; + } + else + { + //errstream << " succeeded" << endl; + //errstream.flush(); + } + + return TRUE; + + +} +#endif + +#ifdef NOSURFACES_OBJECTS // palettized +void CLoading::LoadOverlayGraphic(LPCTSTR lpOvrlName_, int iOvrlNum) +{ + last_succeeded_operation=11; + + CString image; // the image used + CString filename; // filename of the image + SHPHEADER head; + char theat=cur_theat; + BYTE** lpT=NULL; + + char OvrlID[50]; + itoa(iOvrlNum, OvrlID, 10); + + HTSPALETTE hPalette = m_hPalIsoTemp; + if(cur_theat=='T') + { + hPalette=m_hPalIsoTemp; + #ifdef RA2_MODE + hPalette=m_hPalIsoTemp; + #endif + } + if(cur_theat=='A') + { + hPalette=m_hPalIsoSnow; + #ifdef RA2_MODE + hPalette=m_hPalIsoSnow; + #endif + } + if(cur_theat=='U' && m_hPalIsoUrb) + { + hPalette=m_hPalIsoUrb; + #ifdef RA2_MODE + hPalette=m_hPalIsoUrb; + #endif + } + if(cur_theat=='N' && m_hPalIsoUbn) + { + hPalette=m_hPalIsoUbn; + #ifdef RA2_MODE + hPalette=m_hPalIsoUbn; + #endif + } + if(cur_theat=='L' && m_hPalIsoLun) + { + hPalette=m_hPalIsoLun; + #ifdef RA2_MODE + hPalette=m_hPalIsoLun; + #endif + } + if(cur_theat=='D' && m_hPalIsoDes) + { + hPalette=m_hPalIsoDes; + #ifdef RA2_MODE + hPalette=m_hPalIsoDes; + #endif + } + + HTSPALETTE forcedPalette = 0; + const auto& isoPalettePrefixes = g_data.sections["ForceOvrlIsoPalettePrefix"]; + const auto& unitPalettePrefixes = g_data.sections["ForceOvrlUnitPalettePrefix"]; + const CString sOvrlName(lpOvrlName_); + if (unitPalettePrefixes.end() != std::find_if(unitPalettePrefixes.begin(), unitPalettePrefixes.end(), [&sOvrlName](const auto& pair) {return sOvrlName.Find(pair.second) == 0;})) + { + forcedPalette = GetUnitPalette(cur_theat); + } + if (isoPalettePrefixes.end() != std::find_if(isoPalettePrefixes.begin(), isoPalettePrefixes.end(), [&sOvrlName](const auto& pair) {return sOvrlName.Find(pair.second) == 0;})) + { + forcedPalette = GetIsoPalette(cur_theat); + } + + HMIXFILE hMix; + + CString lpOvrlName = lpOvrlName_; + if(lpOvrlName.Find(' ')>=0) lpOvrlName = lpOvrlName.Left(lpOvrlName.Find(' ')); + //if(strchr(lpOvrlName, ' ')!=NULL) strchr(lpOvrlName, ' ')[0]=0; + //if(lpOvrlName + + CString isveinhole_t=rules.sections[lpOvrlName].values["IsVeinholeMonster"]; + CString istiberium_t=rules.sections[lpOvrlName].values["Tiberium"]; + CString isveins_t=rules.sections[lpOvrlName].values["IsVeins"]; + isveinhole_t.MakeLower(); + istiberium_t.MakeLower(); + isveins_t.MakeLower(); + BOOL isveinhole=FALSE, istiberium=FALSE, isveins=FALSE; + if(isTrue(isveinhole_t)) isveinhole=TRUE; + if(isTrue(istiberium_t)) istiberium=TRUE; + if(isTrue(isveins_t)) isveins=TRUE; + + + + + + image=lpOvrlName; + if(rules.sections[lpOvrlName].values.find("Image")!=rules.sections[lpOvrlName].values.end()) + image=rules.sections[lpOvrlName].values["Image"]; + + TruncSpace(image); + + CString imagerules=image; + if(art.sections[image].values.find("Image")!=art.sections[image].values.end()) + image=art.sections[image].values["Image"]; + + TruncSpace(image); + + if(cur_theat=='T') filename=image+".tem"; + if(cur_theat=='A') filename=image+".sno"; + if(cur_theat=='U') filename=image+".urb"; + if(cur_theat=='N') filename=image+".ubn"; + if(cur_theat=='L') filename=image+".lun"; + if(cur_theat=='D') filename=image+".des"; + + + hMix=FindFileInMix(filename); + + const auto& artSection = art.sections[image]; + + if(hMix==NULL) + { + filename=image+".shp"; + if(isTrue(artSection.GetValueByName("NewTheater"))) + filename.SetAt(1, theat); + + if(cur_theat=='U' && m_hPalUnitUrb) hPalette=m_hPalUnitUrb; + if(cur_theat=='T') hPalette=m_hPalUnitTemp; + if(cur_theat=='A') hPalette=m_hPalUnitSnow; + if(cur_theat=='N') hPalette=m_hPalUnitUbn; + if(cur_theat=='L') hPalette=m_hPalUnitLun; + if(cur_theat=='D') hPalette=m_hPalUnitDes; + + hMix=FindFileInMix(filename); + + //errstream << (LPCSTR)filename << " " << endl; + //errstream.flush(); + + if(hMix==NULL) + { + filename.SetAt(1, 'T'); + hMix=FindFileInMix(filename); + } + if(hMix==NULL) + { + filename.SetAt(1, 'A'); + hMix=FindFileInMix(filename); + } + if(hMix==NULL) + { + filename.SetAt(1, 'U'); + hMix=FindFileInMix(filename); + } + if(hMix==NULL) + { + filename.SetAt(1, 'N'); + hMix=FindFileInMix(filename); + } + if(hMix==NULL) + { + filename.SetAt(1, 'L'); + hMix=FindFileInMix(filename); + } + if(hMix==NULL) + { + filename.SetAt(1, 'D'); + hMix=FindFileInMix(filename); + } + + if(cur_theat=='T' || cur_theat=='U') + { + hPalette=m_hPalUnitTemp; + } + else + hPalette=m_hPalUnitSnow; + + } + + if(hMix==NULL) + { + filename=image+".tem"; + hMix=FindFileInMix(filename); + if(hMix) hPalette=m_hPalIsoTemp; + } + if(hMix==NULL) + { + filename=image+".sno"; + hMix=FindFileInMix(filename); + if(hMix) hPalette=m_hPalIsoSnow; + } + if(hMix==NULL) + { + filename=image+".urb"; + hMix=FindFileInMix(filename); + if(hMix && m_hPalIsoUrb) hPalette=m_hPalIsoUrb; + } + if(hMix==NULL) + { + filename=image+".ubn"; + hMix=FindFileInMix(filename); + if(hMix && m_hPalIsoUbn) hPalette=m_hPalIsoUbn; + } + if(hMix==NULL) + { + filename=image+".lun"; + hMix=FindFileInMix(filename); + if(hMix && m_hPalIsoLun) hPalette=m_hPalIsoLun; + } + if(hMix==NULL) + { + filename=image+".des"; + hMix=FindFileInMix(filename); + if(hMix && m_hPalIsoDes) hPalette=m_hPalIsoDes; + } + + if(isveinhole==TRUE || isveins==TRUE || istiberium==TRUE) + { + hPalette=m_hPalTemp; +#ifndef RA2_MODE + hPalette=m_hPalUnitTemp; +#endif + } + + hPalette = forcedPalette ? forcedPalette : hPalette; + + + if(hMix!=NULL) + { + + errstream << "Overlay: " << (LPCSTR) filename << endl; + errstream.flush(); + + FSunPackLib::SetCurrentSHP(filename, hMix); + { + + FSunPackLib::XCC_GetSHPHeader(&head); + + int i; + int maxPics=head.c_images; + if(maxPics>max_ovrl_img) maxPics=max_ovrl_img; + + + // create an array of pointers to directdraw surfaces + lpT=new(BYTE*[maxPics]); + memset(lpT, 0, sizeof(BYTE)*maxPics); + + // if tiberium, change color + BOOL bIsBlueTib=FALSE; + BOOL bIsGreenTib=FALSE; + RGBTRIPLE rgbOld[16], rgbNew; + #ifndef RA2_MODE + if(istiberium) + { + if(lpOvrlName[4]=='_') // other than green! + bIsBlueTib=TRUE; + else + bIsGreenTib=TRUE; + + + + int i; + for(i=0;i<16;i++) + { + if(bIsGreenTib) + { + rgbNew.rgbtBlue=0; + if(i!=0) + rgbNew.rgbtGreen=255-i*16+1; + else + rgbNew.rgbtGreen=255; + rgbNew.rgbtRed=0; + } + else if(bIsBlueTib) + { + if(i!=0) + rgbNew.rgbtBlue=255-i*16+1; + else + rgbNew.rgbtBlue=255; + rgbNew.rgbtGreen=0; + rgbNew.rgbtRed=0; // change green/blue (not RGB but BGR) + } + + int rb=rgbNew.rgbtBlue; + int rr=rgbNew.rgbtRed; + + FSunPackLib::SetTSPaletteEntry(hPalette, 0x10+i, &rgbNew, &rgbOld[i]); + } + } + #endif + + FSunPackLib::LoadSHPImage(0, maxPics, lpT); + + #ifndef RA2_MODE + if(istiberium) + for(i=0;i<16;i++) + FSunPackLib::SetTSPaletteEntry(hPalette, 0x10+i, &rgbOld[i], NULL); + #endif + + for(i=0; i<maxPics; i++) + { + SHPIMAGEHEADER imghead; + FSunPackLib::XCC_GetSHPImageHeader(i, &imghead); + + // MW: fixed april 20th, 2002 + if(imghead.unknown==0 && !isTrue(g_data.sections["Debug"].values["IgnoreSHPImageHeadUnused"])) // is it a shadow or not used image? + if(lpT[i]) + { + delete[] lpT[i]; + lpT[i]=NULL; + } + + if(/*imghead.unknown &&*/ lpT[i]) + { + char ic[50]; + itoa(i, ic, 10); + + PICDATA p; + p.pic=lpT[i]; + + if(hPalette==m_hPalIsoTemp || hPalette==m_hPalIsoUrb || hPalette==m_hPalIsoSnow || hPalette==m_hPalIsoDes || hPalette==m_hPalIsoLun || hPalette==m_hPalIsoUbn) p.pal=iPalIso; + if(hPalette==m_hPalTemp || hPalette==m_hPalUrb || hPalette==m_hPalSnow || hPalette==m_hPalDes || hPalette==m_hPalLun || hPalette==m_hPalUbn) p.pal=iPalTheater; + if(hPalette==m_hPalUnitTemp || hPalette==m_hPalUnitUrb || hPalette==m_hPalUnitSnow || hPalette==m_hPalUnitDes || hPalette==m_hPalUnitLun || hPalette==m_hPalUnitUbn) p.pal=iPalUnit; + + p.vborder=new(VBORDER[head.cy]); + int k; + for(k=0;k<head.cy;k++) + { + int l,r; + GetDrawBorder(lpT[i], head.cx, k, l, r, 0); + p.vborder[k].left=l; + p.vborder[k].right=r; + } + + p.x=imghead.x; + p.y=imghead.y; + + p.wHeight=imghead.cy; + p.wWidth=imghead.cx; + p.wMaxWidth=head.cx; + p.wMaxHeight=head.cy; + p.bType=PICDATA_TYPE_SHP; + + + pics[(CString)"OVRL"+ OvrlID + "_" + ic]=p; + } + } + + + delete[] lpT; + } + + } + + int i; + for(i=0; i<0xFF; i++) + { + char ic[50]; + itoa(i, ic, 10); + + pics[(CString)"OVRL"+ OvrlID + "_" + ic].bTried=TRUE; + } + + +} + +#else // surfaces +void CLoading::LoadOverlayGraphic(LPCTSTR lpOvrlName_, int iOvrlNum) +{ + last_succeeded_operation=11; + + CString image; // the image used + CString filename; // filename of the image + SHPHEADER head; + char theat=cur_theat; + LPDIRECTDRAWSURFACE4* lpT=NULL; + + char OvrlID[50]; + itoa(iOvrlNum, OvrlID, 10); + + HTSPALETTE hPalette; + if(cur_theat=='T') + { + hPalette=m_hPalIsoTemp; + #ifdef RA2_MODE + hPalette=m_hPalIsoTemp; + #endif + } + if(cur_theat=='A') + { + hPalette=m_hPalIsoSnow; + #ifdef RA2_MODE + hPalette=m_hPalIsoSnow; + #endif + } + if(cur_theat=='U' && m_hPalIsoUrb) + { + hPalette=m_hPalIsoUrb; + #ifdef RA2_MODE + hPalette=m_hPalIsoUrb; + #endif + } + + HMIXFILE hMix; + + CIsoView& v=*((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + + CString lpOvrlName = lpOvrlName_; + if (lpOvrlName.Find(' ') >= 0) lpOvrlName = lpOvrlName.Left(lpOvrlName.Find(' ')); + + CString isveinhole_t=rules.sections[lpOvrlName].values["IsVeinholeMonster"]; + CString istiberium_t=rules.sections[lpOvrlName].values["Tiberium"]; + CString isveins_t=rules.sections[lpOvrlName].values["IsVeins"]; + isveinhole_t.MakeLower(); + istiberium_t.MakeLower(); + isveins_t.MakeLower(); + BOOL isveinhole=FALSE, istiberium=FALSE, isveins=FALSE; + if(isTrue(isveinhole_t)) isveinhole=TRUE; + if(isTrue(istiberium_t)) istiberium=TRUE; + if(isTrue(isveins_t)) isveins=TRUE; + + + + + + image=lpOvrlName; + if(rules.sections[lpOvrlName].values.find("Image")!=rules.sections[lpOvrlName].values.end()) + image=rules.sections[lpOvrlName].values["Image"]; + + TruncSpace(image); + + CString imagerules=image; + if(art.sections[image].values.find("Image")!=art.sections[image].values.end()) + image=art.sections[image].values["Image"]; + + TruncSpace(image); + + if(cur_theat=='T') filename=image+".tem"; + if(cur_theat=='A') filename=image+".sno"; + if(cur_theat=='U') filename=image+".urb"; + + + hMix=FindFileInMix(filename); + + + if(hMix==NULL) + { + filename=image+".shp"; + if(isTrue(art.sections[image].values["NewTheater"])) + filename.SetAt(1, theat); + + if(cur_theat=='U' && m_hPalUnitUrb) hPalette=m_hPalUnitUrb; + if(cur_theat=='T') hPalette=m_hPalUnitTemp; + if(cur_theat=='A') hPalette=m_hPalUnitSnow; + + hMix=FindFileInMix(filename); + + // errstream << (LPCSTR)filename << " " << hMix; + + if(hMix==NULL) + { + filename.SetAt(1, 'T'); + hMix=FindFileInMix(filename); + } + if(hMix==NULL) + { + filename.SetAt(1, 'A'); + hMix=FindFileInMix(filename); + } + if(hMix==NULL) + { + filename.SetAt(1, 'U'); + hMix=FindFileInMix(filename); + } + + if(cur_theat=='T' || cur_theat=='U') + { + hPalette=m_hPalUnitTemp; + } + else + hPalette=m_hPalUnitSnow; + + } + + if(hMix==NULL) + { + filename=image+".tem"; + hMix=FindFileInMix(filename); + if(hMix) hPalette=m_hPalIsoTemp; + } + if(hMix==NULL) + { + filename=image+".sno"; + hMix=FindFileInMix(filename); + if(hMix) hPalette=m_hPalIsoSnow; + } + if(hMix==NULL) + { + filename=image+".urb"; + hMix=FindFileInMix(filename); + if(hMix && m_hPalIsoUrb) hPalette=m_hPalIsoUrb; + } + + if(isveinhole==TRUE || isveins==TRUE || istiberium==TRUE) + { + hPalette=m_hPalTemp; +#ifndef RA2_MODE + hPalette=m_hPalUnitTemp; +#endif + } + + if(hMix!=NULL) + { + + FSunPackLib::SetCurrentSHP(filename, hMix); + { + + FSunPackLib::XCC_GetSHPHeader(&head); + + int i; + int maxPics=head.c_images; + if(maxPics>max_ovrl_img) maxPics=max_ovrl_img; // max may_ovrl_img pictures (memory usage!) + //errstream << ", loading " << maxPics << " of " << head.c_images << " pictures. "; + //errstream.flush(); + + + // create an array of pointers to directdraw surfaces + lpT=new(LPDIRECTDRAWSURFACE4[maxPics]); + memset(lpT, 0, sizeof(LPDIRECTDRAWSURFACE4)*maxPics); + + // if tiberium, change color + BOOL bIsBlueTib=FALSE; + BOOL bIsGreenTib=FALSE; + RGBTRIPLE rgbOld[16], rgbNew; + #ifndef RA2_MODE + if(istiberium) + { + if(lpOvrlName[4]=='_') // other than green! + bIsBlueTib=TRUE; + else + bIsGreenTib=TRUE; + + + + int i; + for(i=0;i<16;i++) + { + if(bIsGreenTib) + { + rgbNew.rgbtBlue=0; + if(i!=0) + rgbNew.rgbtGreen=255-i*16+1; + else + rgbNew.rgbtGreen=255; + rgbNew.rgbtRed=0; + } + else if(bIsBlueTib) + { + if(i!=0) + rgbNew.rgbtBlue=255-i*16+1; + else + rgbNew.rgbtBlue=255; + rgbNew.rgbtGreen=0; + rgbNew.rgbtRed=0; + } + + FSunPackLib::SetTSPaletteEntry(hPalette, 0x10+i, &rgbNew, &rgbOld[i]); + } + } + #endif + + FSunPackLib::LoadSHPImageInSurface(v.dd, hPalette, 0, maxPics, lpT); + + #ifndef RA2_MODE + if(istiberium) + for(i=0;i<16;i++) + FSunPackLib::SetTSPaletteEntry(hPalette, 0x10+i, &rgbOld[i], NULL); + #endif + + for(i=0; i<maxPics; i++) + { + SHPIMAGEHEADER imghead; + FSunPackLib::XCC_GetSHPImageHeader(i, &imghead); + + if(imghead.unknown==0) // is it a shadow or not used image? + if(lpT[i]) lpT[i]->Release(); + + if(imghead.unknown && lpT[i]) + { + char ic[50]; + itoa(i, ic, 10); + + PICDATA p; + p.pic=lpT[i]; + p.x=imghead.x; + p.y=imghead.y; + + p.wHeight=imghead.cy; + p.wWidth=imghead.cx; + p.wMaxWidth=head.cx; + p.wMaxHeight=head.cy; + p.bType=PICDATA_TYPE_SHP; + + + + pics[(CString)"OVRL"+ OvrlID + "_" + ic]=p; + } + } + + + delete[] lpT; + + //errstream << " --> Finished" << endl; + //errstream.flush(); + } + /*else + { + errstream << " failed"; + errstream.flush(); + }*/ + } + + else + { + //errstream << "File not found: " << (LPCTSTR)filename << endl; + //errstream.flush(); + } + + int i; + for(i=0; i<0xFF; i++) + { + char ic[50]; + itoa(i, ic, 10); + + pics[(CString)"OVRL"+ OvrlID + "_" + ic].bTried=TRUE; + } + + +} +#endif + +void CLoading::OnDestroy() +{ + CDialog::OnDestroy(); +} + +void CLoading::InitVoxelNormalTables() +{ + try + { + std::ifstream f(std::string(AppPath) + "\\voxel_normal_tables.bin", std::ios::binary); + m_voxelNormalTables.reset(new VoxelNormalTables(f)); + } + catch (const std::runtime_error& e) + { + errstream << e.what() << std::endl; + m_voxelNormalTables.reset(new VoxelNormalTables()); + } +} + +void CLoading::CalcPicCount() +{ + m_pic_count=0; + + CString bmps=(CString)AppPath+"\\pics\\*.bmp"; + if(!theApp.m_Options.bDoNotLoadBMPs) + { + CFileFind ff; + if(ff.FindFile(bmps)) + { + // found bmp + m_pic_count++; + while(ff.FindNextFile()) m_pic_count++; + } + } + + m_bmp_count=m_pic_count; + + if(!theApp.m_Options.bDoNotLoadVehicleGraphics) m_pic_count+=rules.sections["VehicleTypes"].values.size(); + if(!theApp.m_Options.bDoNotLoadOverlayGraphics) m_pic_count+=rules.sections["OverlayTypes"].values.size(); + if(!theApp.m_Options.bDoNotLoadInfantryGraphics) m_pic_count+=rules.sections["InfantryTypes"].values.size(); + if(!theApp.m_Options.bDoNotLoadBuildingGraphics) m_pic_count+=rules.sections["BuildingTypes"].values.size(); + if(!theApp.m_Options.bDoNotLoadAircraftGraphics) m_pic_count+=rules.sections["AircraftTypes"].values.size(); + if(!theApp.m_Options.bDoNotLoadTreeGraphics) m_pic_count+=rules.sections["TerrainTypes"].values.size(); + + int i; +/* + if(!theApp.m_Options.bDoNotLoadSnowGraphics) + { + tiledata=&s_tiledata; + tiles=&tiles_s; + tiledata_count=&s_tiledata_count; + for(i=0;i<10000;i++) + { + CString tset; + char c[50]; + itoa(i, c, 10); + int e; + for(e=0;e<4-strlen(c);e++) + tset+="0"; + tset+=c; + CString sec="TileSet"; + sec+=tset; + + if(tiles->sections.find(sec)==tiles->sections.end()) break; + + for(e=0;e<atoi(tiles->sections[sec].values["TilesInSet"]);e++) + { + m_pic_count++; + } + + } + } + + if(!theApp.m_Options.bDoNotLoadTemperateGraphics) + { + tiledata=&t_tiledata; + tiles=&tiles_t; + tiledata_count=&t_tiledata_count; + for(i=0;i<10000;i++) + { + CString tset; + char c[50]; + itoa(i, c, 10); + int e; + for(e=0;e<4-strlen(c);e++) + tset+="0"; + tset+=c; + CString sec="TileSet"; + sec+=tset; + + if(tiles->sections.find(sec)==tiles->sections.end()) break; + + for(e=0;e<atoi(tiles->sections[sec].values["TilesInSet"]);e++) + { + m_pic_count++; + } + + } + }*/ +} + + +BOOL CLoading::InitDirectDraw() +{ + last_succeeded_operation=7; + + errstream << "\n\nDirectDrawCreate() will be called now\n"; + errstream.flush(); + + CIsoView& v=*((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + if(DirectDrawCreate(NULL, &v.dd_1, NULL)!=DD_OK) + { + errstream << "DirectDrawCreate() failed\n"; + errstream.flush(); + ShowWindow(SW_HIDE); + MessageBox("DirectDraw could not be initialized! Quitting..."); + exit(-1); + + return FALSE; + } + + errstream << "DirectDrawCreate() successful\n\n"; + errstream.flush(); + + if(m_progress.m_hWnd) m_progress.SetPos(1); + if(m_hWnd) UpdateWindow(); + + errstream << "Now querying the DirectX 7 or 6 interface\n"; + errstream.flush(); + + if(v.dd_1->QueryInterface(IID_IDirectDraw7, (void**)&v.dd)!=DD_OK) + { + errstream << "QueryInterface() failed -> Using DirectX 6.0\n"; + errstream.flush(); + //ShowWindow(SW_HIDE); + //MessageBox("You don´t have DirectX 6.0 but an older version. Quitting..."); + //exit(-1); + + //return FALSE; + + if(v.dd_1->QueryInterface(IID_IDirectDraw4, (void**)&v.dd)!=DD_OK) + { + MessageBox("You need at least DirectX 6.0 to run this program", "Error"); + exit(-1); + return FALSE; + } + } + + errstream << "QueryInterface() successful\n\nNow setting cooperative level\n"; + errstream.flush(); + + if(v.dd->SetCooperativeLevel(v.m_hWnd, DDSCL_NORMAL | DDSCL_NOWINDOWCHANGES )!=DD_OK) + { + errstream << "SetCooperativeLevel() failed\n"; + errstream.flush(); + ShowWindow(SW_HIDE); + MessageBox("Cooperative Level could not be set! Quitting..."); + v.dd->Release(); + v.dd=NULL; + exit(-2); + + return FALSE; + } + + errstream << "SetCooperativeLevel() successful\n\nCreating primary surface\n"; + errstream.flush(); + + + if(m_progress.m_hWnd) m_progress.SetPos(2); + if(m_hWnd) UpdateWindow(); + + DDSURFACEDESC2 ddsd; + + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize=sizeof(DDSURFACEDESC2); + ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE ; + ddsd.dwFlags=DDSD_CAPS ; + + + + int res=0; + int trycount=0; + do + { + res=v.dd->CreateSurface(&ddsd, &v.lpds, NULL); + errstream << "Return code: " << res << endl; + errstream.flush(); + + //if(res!=DD_OK && (res!=DDERR_PRIMARYSURFACEALREADYEXISTS || trycount>100)) + if(res!=DD_OK && trycount>=300) + { + + errstream << "CreateSurface() failed\n"; + + errstream.flush(); + ShowWindow(SW_HIDE); + MessageBox("Primary surface could not be initialized! Quitting..."); + v.dd->Release(); + v.dd=NULL; + exit(-3); + + return FALSE; + } + trycount++; + if(res!=DD_OK) + { + Sleep(50); + } + + + }while(res!=DD_OK); + +#ifdef NOSURFACES + DDPIXELFORMAT pf; + memset(&pf, 0, sizeof(DDPIXELFORMAT)); + pf.dwSize=sizeof(DDPIXELFORMAT); + + v.lpds->GetPixelFormat(&pf); + + if(!pf.dwBBitMask || !pf.dwRBitMask || !pf.dwGBitMask) + { + ShowWindow(SW_HIDE); + MessageBox("You must not use a palette color mode like 8 bit in order to run FinalSun/FinalAlert 2. Please check readme.txt","Error",MB_OK); + + v.lpds->Release(); + v.lpds=NULL; + v.dd->Release(); + v.dd=NULL; + exit(-3); + return FALSE; + } + bpp=(pf.dwRGBBitCount+7)/8; +#endif + + + errstream << "CreateSurface() successful\n\nCreating backbuffer surface\n"; + errstream.flush(); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize=sizeof(DDSURFACEDESC2); + ddsd.dwFlags=DDSD_WIDTH | DDSD_HEIGHT; + v.lpds->GetSurfaceDesc(&ddsd); + ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN; + + + ddsd.dwFlags=DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + + + if(v.dd->CreateSurface(&ddsd, &v.lpdsBack, NULL)!=DD_OK) + { + errstream << "CreateSurface() failed\n"; + errstream.flush(); + ShowWindow(SW_HIDE); + MessageBox("Backbuffer surface could not be initialized! Quitting..."); + v.lpds->Release(); + v.lpds=NULL; + v.dd->Release(); + v.dd=NULL; + exit(-4); + + return FALSE; + } + if (theApp.m_Options.bHighResUI && v.dd->CreateSurface(&ddsd, &v.lpdsBackHighRes, NULL) != DD_OK) + { + errstream << "CreateSurface() failed\n"; + errstream.flush(); + ShowWindow(SW_HIDE); + MessageBox("Highres Backbuffer surface could not be initialized! Quitting..."); + v.lpdsBack->Release(); + v.lpdsBack = NULL; + v.lpds->Release(); + v.lpds = NULL; + v.dd->Release(); + v.dd = NULL; + exit(-4); + + return FALSE; + } + if(v.dd->CreateSurface(&ddsd, &v.lpdsTemp, NULL)!=DD_OK) + { + errstream << "CreateSurface() failed\n"; + errstream.flush(); + ShowWindow(SW_HIDE); + MessageBox("Tempbuffer surface could not be initialized! Quitting..."); + v.lpdsBack->Release(); + v.lpdsBack=NULL; + if (v.lpdsBackHighRes) + v.lpdsBackHighRes->Release(); + v.lpdsBackHighRes = nullptr; + v.lpds->Release(); + v.lpds=NULL; + v.dd->Release(); + v.dd=NULL; + exit(-4); + + return FALSE; + } + + errstream << "CreateSurface() successful\n\nNow creating clipper\n"; + errstream.flush(); + + LPDIRECTDRAWCLIPPER ddc; + if(v.dd->CreateClipper(0, &ddc, NULL)!=DD_OK) + { + errstream << "CreateClipper() failed\n"; + errstream.flush(); + ShowWindow(SW_HIDE); + MessageBox("Clipper could not be created! Quitting..."); + v.lpdsTemp->Release(); + v.lpdsTemp=NULL; + v.lpdsBack->Release(); + v.lpdsBack=NULL; + if (v.lpdsBackHighRes) + v.lpdsBackHighRes->Release(); + v.lpdsBackHighRes = nullptr; + v.lpds->Release(); + v.lpds=NULL; + v.dd->Release(); + v.dd=NULL; + exit(-6); + } + + errstream << "CreateClipper() successful\n\n"; + errstream.flush(); + + v.lpds->SetClipper(ddc); + + ddc->SetHWnd(0, v.m_hWnd); + + return TRUE; +} + +void CLoading::OnPaint() +{ + CPaintDC dc(this); // device context for painting + + CWnd* poswindow=GetDlgItem(IDC_SAVEOFTEN); + + if(!poswindow) return; + + RECT r1,r2; + poswindow->GetWindowRect(&r1); + GetWindowRect(&r2); + + dc.SetTextColor(RGB(255, 0, 0)); + dc.SetBkMode(TRANSPARENT); + + RECT dest; + dest.top=r1.bottom-r2.top-45; + dest.bottom=r1.bottom-r2.top+10; + dest.left=10; + dest.right=r1.right-r1.left+10; + + CFont f; + f.CreatePointFont(90, "Tahoma"); + dc.SelectObject(&f); + +} + +void CLoading::FreeTileSet() +{ + // free the current tileset + + int i; + for(i=0;i<(*tiledata_count);i++) + { + int e; + int z; + + // delete replacements. Replacements themself MUST NOT have replacements + for(z=0;z<(*tiledata)[i].bReplacementCount;z++) + { + TILEDATA& rept=(*tiledata)[i].lpReplacements[z]; + + for(e=0;e<rept.wTileCount;e++) + { +#ifdef NOSURFACES + BYTE* curSur=rept.tiles[e].pic; + if(curSur) delete[] curSur; + if(rept.tiles[e].vborder) delete[] rept.tiles[e].vborder; +#else + LPDIRECTDRAWSURFACE4 curSur=rept.tiles[e].pic; + if(curSur) curSur->Release(); +#endif + } + + delete[] rept.tiles; + rept.tiles=NULL; + rept.wTileCount=0; + rept.bReplacementCount=0; + + ASSERT(!rept.lpReplacements); // make sure we don´t have replacements for this replacement + } + + for(e=0;e<(*tiledata)[i].wTileCount;e++) + { +#ifdef NOSURFACES + BYTE* curSur=(*tiledata)[i].tiles[e].pic; + if(curSur) delete[] curSur; + if((*tiledata)[i].tiles[e].vborder) delete[] (*tiledata)[i].tiles[e].vborder; +#else + LPDIRECTDRAWSURFACE4 curSur=(*tiledata)[i].tiles[e].pic; + if(curSur) curSur->Release(); +#endif + } + + delete[] ((*tiledata)[i].tiles); + (*tiledata)[i].tiles=NULL; + (*tiledata)[i].wTileCount=0; + (*tiledata)[i].bReplacementCount=0; + if((*tiledata)[i].lpReplacements) delete[] (*tiledata)[i].lpReplacements; + (*tiledata)[i].lpReplacements=NULL; + } + if(*tiledata) delete[] (*tiledata); + (*tiledata)=NULL; + (*tiledata_count)=0; +} + +void CLoading::FreeAll() +{ + last_succeeded_operation=14; + + // MW fix: We need to set tiledata and tiledata_count to the old pointers again + int t=0; + if(tiledata==&t_tiledata) t=0; + if(tiledata==&s_tiledata) t=1; + if(tiledata==&u_tiledata) t=2; + if(tiledata==&un_tiledata) t=3; + if(tiledata==&l_tiledata) t=4; + if(tiledata==&d_tiledata) t=4; + + //try{ + tiledata=&t_tiledata; + tiledata_count=&t_tiledata_count; + FreeTileSet(); + tiledata=&s_tiledata; + tiledata_count=&s_tiledata_count; + FreeTileSet(); + tiledata=&u_tiledata; + tiledata_count=&u_tiledata_count; + FreeTileSet(); + + // MW New tilesets: + tiledata=&un_tiledata; + tiledata_count=&un_tiledata_count; + FreeTileSet(); + tiledata=&l_tiledata; + tiledata_count=&l_tiledata_count; + FreeTileSet(); + tiledata=&d_tiledata; + tiledata_count=&d_tiledata_count; + FreeTileSet(); + /* } + catch(...) + { + errstream << "Exception in FreeTileSet()" << endl; + }*/ + + // MW Reset tiledata & tiledata_count + if(t==0) { tiledata=&t_tiledata; tiledata_count=&t_tiledata_count; } + if(t==1) { tiledata=&s_tiledata; tiledata_count=&s_tiledata_count; } + if(t==2) { tiledata=&u_tiledata; tiledata_count=&u_tiledata_count; } + if(t==3) { tiledata=&un_tiledata; tiledata_count=&un_tiledata_count; } + if(t==4) { tiledata=&l_tiledata; tiledata_count=&l_tiledata_count; } + if(t==5) { tiledata=&d_tiledata; tiledata_count=&d_tiledata_count; } + + map<CString, PICDATA>::iterator i=pics.begin(); + for (int e=0;e<pics.size();e++) + { + try{ +#ifdef NOSURFACES_OBJECTS + if(i->second.bType==PICDATA_TYPE_BMP) + { + if(i->second.pic!=NULL) + { + ((LPDIRECTDRAWSURFACE4)i->second.pic)->Release(); + } + } + else + { + if(i->second.pic!=NULL) + { + delete[] i->second.pic; + } + if(i->second.vborder) delete[] i->second.vborder; + } +#else + if(i->second.pic!=NULL) i->second.pic->Release(); +#endif + + i->second.pic=NULL; + } + catch(...) + { + CString err; + err="Access violation while trying to release surface "; + char c[6]; + itoa(e,c,10); + err+=c; + + err+="\n"; + OutputDebugString(err); + continue; + } + + i++; + } + + + + try{ + CFinalSunDlg* dlg=((CFinalSunDlg*)theApp.m_pMainWnd); + if(dlg->m_view.m_isoview->lpds!=NULL) dlg->m_view.m_isoview->lpds->Release(); + dlg->m_view.m_isoview->lpds=NULL; + if(dlg->m_view.m_isoview->lpdsBack!=NULL) dlg->m_view.m_isoview->lpdsBack->Release(); + dlg->m_view.m_isoview->lpdsBack=NULL; + if (dlg->m_view.m_isoview->lpdsBackHighRes != NULL) dlg->m_view.m_isoview->lpdsBackHighRes->Release(); + dlg->m_view.m_isoview->lpdsBackHighRes = NULL; + if(dlg->m_view.m_isoview->lpdsTemp!=NULL) dlg->m_view.m_isoview->lpdsTemp->Release(); + dlg->m_view.m_isoview->lpdsTemp=NULL; + if(dlg->m_view.m_isoview->dd!=NULL) dlg->m_view.m_isoview->dd->Release(); + dlg->m_view.m_isoview->dd=NULL; + if(dlg->m_view.m_isoview->dd_1!=NULL) dlg->m_view.m_isoview->dd_1->Release(); + dlg->m_view.m_isoview->dd_1=NULL; + } + catch(...) + { + errstream << "Exception while freeing DirectDraw" << endl; + } +} + +void CLoading::PostNcDestroy() +{ + +// delete this; // on stack! +// CDialog::PostNcDestroy(); +} + +void CLoading::PrepareHouses() +{ + int i; + int p=0 ; + for(i=0;i<rules.sections["Sides"].values.size();i++) + { + int t=0; + while(GetParam(*rules.sections["Sides"].GetValue(i), t).GetLength()>0) + { + sides[p].name=GetParam(*rules.sections["Sides"].GetValue(i), t); + sides[p].orig_n=rules.sections["Sides"].GetValueOrigPos(i); // mw fix instead of =i + t++; + p++; + } + } + + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + if(rules.sections[HOUSES].GetValueOrigPos(i)<0) continue; + + HOUSEINFO& house=houses[rules.sections[HOUSES].GetValueOrigPos(i)]; + house.name=*rules.sections[HOUSES].GetValue(i); + house.bPlayable=isTrue(rules.sections[house.name].values["Multiplay"]); + memset(&house.color, 0, sizeof(RGBTRIPLE)); + int e; + for(e=0;e<sides.size();e++) + { + house.side=NULL; + if(sides[e].name==rules.sections[house.name].values["Side"]) + house.side=&sides[e]; + } + + } +} + + +BYTE* Search(BYTE** lpData, BYTE* lpSearched) +{ + BYTE* lpDat=*lpData; + + lpDat=(BYTE*)strstr((LPCSTR)lpDat, (LPCSTR)lpSearched)+strlen((LPCSTR)lpSearched); + + return lpDat; +} + +class SortDummy2{ +public: + bool operator() (const CString& x, const CString& y) const + { + // the length is more important than spelling (numbers!!!)... + if(x.GetLength()<y.GetLength()) return true; + if(x.GetLength()==y.GetLength()) + { + CString x2=x; + CString y2=y; + x2.MakeLower(); + y2.MakeLower(); + if(x2<y2) return true; + } + + return false; + + } +}; + +extern map<CString, XCString> AllStrings; +void CLoading::LoadStrings() +{ + last_succeeded_operation=9; + +#ifdef RA2_MODE + + // MW April 17th, 2002: + // ra2md.csf supported! + std::string file="RA2.CSF"; + if(yuri_mode) + file="RA2MD.CSF"; + + errstream << "LoadStrings() executing" << endl; + errstream.flush(); + + BYTE *lpData=NULL; + DWORD dwSize; + if(DoesFileExist((std::string(TSPath) + "\\" + file).c_str())) + { + std::ifstream f(std::string(TSPath) + "\\" + file, ios::binary); + if (f.good()) + { + f.seekg(0, std::ios::end); + auto size = f.tellg(); + if (size > 0) + { + lpData = new(BYTE[size]); + dwSize = size; + f.seekg(0, std::ios::beg); + f.read(reinterpret_cast<char*>(lpData), dwSize); + } + } + } + errstream << "LoadStrings() loading from mix" << endl; + errstream.flush(); + + if(!lpData) + { + HMIXFILE hMix=FindFileInMix(file.c_str()); + //HMIXFILE hMix=m_hLanguage; + if(hMix) + { + if (FSunPackLib::XCC_ExtractFile(file, u8AppDataPath + "\\RA2Tmp.csf", hMix)) + { + std::ifstream f(u8AppDataPath + "\\RA2Tmp.csf", ios::binary); + if (f.good()) + { + f.seekg(0, std::ios::end); + auto size = f.tellg(); + if (size > 0) + { + lpData = new(BYTE[size]); + dwSize = size; + f.seekg(0, std::ios::beg); + f.read(reinterpret_cast<char*>(lpData), dwSize); + } + } + } + + if (!lpData) + { + MessageBox("String file not found, using rules.ini names","Error"); + return; + } + } + else + { + MessageBox("String file not found, using rules.ini names","Error"); + return; + } + + } + + BYTE* orig=static_cast<BYTE*>(lpData); + + if(!(lpData=Search(&lpData, (BYTE*)" FSC"))) return; + + RA2STRFILEHEAD head; + memcpy(&head, lpData, RA2STRFILEHEADSIZE); + + + lpData+=RA2STRFILEHEADSIZE; + + map<CString, XCString, SortDummy2> strings; + + int i; + //try{ + for(i=0;i<head.dwCount1;i++) + { + ASSERT(orig+dwSize>lpData); + + if(!(lpData=lpData+4))//Search(&lpData, (BYTE*)" LBL"))) + { + + return; + } + + RA2STRINGENTRY entry; + memcpy(&entry.dwFlag, lpData, 4); + lpData+=4; + + DWORD dwCharCount; + memcpy(&dwCharCount, lpData, 4); + lpData+=4; + + BYTE* lpID=new(BYTE[dwCharCount+1]); + memcpy(lpID, lpData, dwCharCount); + lpData+=dwCharCount; + lpID[dwCharCount]=0; + entry.id=(CHAR*)new(BYTE[dwCharCount+1]); + strcpy(entry.id, (LPCSTR)lpID); + entry.id[dwCharCount]=0; + entry.id_size=dwCharCount; + // enable this to show the string ID + delete[](lpID); + + + BOOL b2Strings=FALSE; + + if(lpData[0]=='W') + b2Strings=TRUE; + + if(!(lpData=lpData+4))//Search(&lpData, (BYTE*)" RTS"))) + { + return; + } + + memcpy(&dwCharCount, lpData, 4); + lpData+=4; + + WCHAR* lpwID=new(WCHAR[dwCharCount+1]); + int e; + for(e=0;e<dwCharCount;e++) + { + WCHAR w; + memcpy(&w, lpData, 2); + lpData+=2; + lpwID[e]=~w; + } + lpwID[dwCharCount]=0; + entry.value=lpwID; + entry.value_size=dwCharCount; + + if(b2Strings) + { + + memcpy(&dwCharCount, lpData, 4); + lpData+=4; + + + + CHAR* lpwID2=new(CHAR[dwCharCount+1]); + int e; + for(e=0;e<dwCharCount;e++) + { + WCHAR w; + memcpy(&w, lpData, 1); + lpData+=1; + lpwID2[e]=w; + } + lpwID2[dwCharCount]=0; + entry.value_asc=lpwID2; + entry.value_asc_size=dwCharCount; + } + + /*BYTE* bByte=new(BYTE[entry.value_size+1]); + wcstombs((LPSTR)bByte, entry.value, entry.value_size+1); + bByte[entry.value_size]=0;*/ + strings[entry.id].SetString(entry.value, entry.value_size); + AllStrings[entry.id].SetString(entry.value, entry.value_size); + + + //delete[] bByte; + } + + + + for(i=0;i<rules.sections.size();i++) + { + if(rules.GetSection(i)->FindName("UIName")>=0) + { + int e; + + if(strings.find(rules.GetSection(i)->values["UIName"])!=strings.end()) + { + //MessageBox(strings[rules.GetSection(i)->values["UIName"]].cString); + if(!strings[rules.GetSection(i)->values["UIName"]].bUsedDefault) + { + //CCStrings[*rules.GetSectionName(i)].cString=strings[rules.GetSection(i)->values["UIName"]].cString; //.SetString(strings[rules.GetSection(i)->values["UIName"]].wString, strings[rules.GetSection(i)->values["UIName"]].len); + CCStrings[*rules.GetSectionName(i)].SetString(strings[rules.GetSection(i)->values["UIName"]].wString, strings[rules.GetSection(i)->values["UIName"]].len); + } + else + { + CCStrings[*rules.GetSectionName(i)].SetString(strings[rules.GetSection(i)->values["UIName"]].wString, strings[rules.GetSection(i)->values["UIName"]].len); + CCStrings[*rules.GetSectionName(i)].cString=rules.GetSection(i)->GetValueByName("Name"); + } + } + else + { + //MessageBox((LPSTR)(LPCSTR)rules.GetSection(i)->values["Name"], *rules.GetSectionName(i)); + CCStrings[*rules.GetSectionName(i)].SetString((LPSTR)(LPCSTR)rules.GetSection(i)->GetValueByName("Name")); + } + } + else CCStrings[*rules.GetSectionName(i)].SetString((LPSTR)(LPCSTR)rules.GetSection(i)->GetValueByName("Name")); + + } + + +#else + int i; + for(i=0;i<rules.sections.size();i++) + { + if(rules.GetSection(i)->FindName("Name")>=0) + { + //CCStrings[*rules.GetSectionName(i)].cString=rules.GetSection(i)->values["Name"]; + //CCStrings[*rules.GetSectionName(i)].SetString=rul + CCStrings[*rules.GetSectionName(i)].SetString((LPSTR)(LPCSTR)rules.GetSection(i)->values["Name"]); + } + } +#endif + + +} + +void CLoading::HackRules() +{ + if(editor_mode==ra2_mode) + { + int i; + int max_c=0; + for(i=0;i<rules.sections["BuildingTypes"].values.size();i++) + { + int p=atoi(*rules.sections["BuildingTypes"].GetValueName(i)); + if(p>max_c) max_c=p; + } + + char c[50]; + itoa(max_c+1,c,10); + + rules.sections["BuildingTypes"].values[c]=rules.sections["General"].values["GDIGateOne"]; + +#ifdef RA2_MODE + // RULES(MD).INI has the incorrect colors set for the following houses, let's remap them to the expected values. + // Fixup YuriCountry colour + if (rules.sections["YuriCountry"].GetValueByName("Color") == "DarkRed") { + rules.sections["YuriCountry"].values["Color"] = "Purple"; + } + // Fixup Allied colors + std::list<CString> allied_houses; + allied_houses.push_back("British"); + allied_houses.push_back("French"); + allied_houses.push_back("Germans"); + allied_houses.push_back("Americans"); + allied_houses.push_back("Alliance"); + for (std::list<CString>::iterator it = allied_houses.begin(); it != allied_houses.end(); ++it) { + if (rules.sections[*it].GetValueByName("Color") == "Gold") { + rules.sections[*it].values["Color"] = "DarkBlue"; + } + } + // Fixup Nod color + if (rules.sections["Nod"].GetValueByName("Color") == "Gold") { + rules.sections["Nod"].values["Color"] = "DarkRed"; + } +#endif + + } + +} + +void CLoading::PrepareBuildingTheaters() +{ + // stub + +} + +/* +This actually just checks what palette the unit (only buildings make sense) +uses. Used for the ObjectBrowser (so it only shows those buildings that really exist +in the specific terrain) + +Added: MW March 20th 2001 +*/ +void CLoading::PrepareUnitGraphic(LPCSTR lpUnittype) +{ + CString _rules_image; // the image used + CString filename; // filename of the image + char theat=cur_theat; // standard theater char is t (Temperat). a is snow. + + BOOL bAlwaysSetChar; // second char is always theater, even if NewTheater not specified! + WORD wStep=1; // step is 1 for infantry, buildings, etc, and for shp vehicles it specifies the step rate between every direction + WORD wStartWalkFrame=0; // for examply cyborg reaper has another walk starting frame + int iTurretOffset=0; // used for centering y pos of turret (if existing) + BOOL bStructure=rules.sections["BuildingTypes"].FindValue(lpUnittype)>=0; // is this a structure? + + if(!bStructure) return; // make sure we only use it for buildings now + + BOOL bPowerUp=rules.sections[lpUnittype].values["PowersUpBuilding"]!=""; + + HTSPALETTE hPalette; + if(theat=='T') hPalette=m_hPalIsoTemp; + if(theat=='A') hPalette=m_hPalIsoSnow; + if(theat=='U') hPalette=m_hPalIsoUrb; + if(theat=='L') hPalette=m_hPalIsoLun; + if(theat=='D') hPalette=m_hPalIsoDes; + if(theat=='N') hPalette=m_hPalIsoUbn; + + CIsoView& v=*((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + + _rules_image=lpUnittype; + if(rules.sections[lpUnittype].values.find("Image")!=rules.sections[lpUnittype].values.end()) + _rules_image=rules.sections[lpUnittype].values["Image"]; + + CString _art_image = _rules_image; + if(art.sections[_rules_image].values.find("Image")!=art.sections[_rules_image].values.end()) + { + if(!isTrue(g_data.sections["IgnoreArtImage"].values[_rules_image])) + _art_image=art.sections[_rules_image].values["Image"]; + } + + const CString& image = _art_image; + const auto& rulesSection = rules.sections[lpUnittype]; + const auto& artSection = art.sections[image]; + + if(!isTrue(art.sections[image].values["Voxel"])) // is it a shp graphic? + { + try + { + + /*filename = image + ".shp"; + + + BYTE bTerrain=0; + + + + BOOL isNewTerrain=FALSE; + if(isTrue(artSection.GetValueByName("NewTheater")))//&& isTrue(artSection.GetValueByName("TerrainPalette")))//(filename.GetAt(0)=='G' || filename.GetAt(0)=='N' || filename.GetAt(0)=='C') && filename.GetAt(1)=='A') + { + hPalette=m_hPalUnitTemp; + if(theat=='A') hPalette=m_hPalUnitSnow; + if(theat=='U') hPalette=m_hPalUnitUrb; + if(theat=='L') hPalette=m_hPalUnitLun; + if(theat=='D') hPalette=m_hPalUnitDes; + if(theat=='N') hPalette=m_hPalUnitUbn; + filename.SetAt(1, theat); + isNewTerrain=TRUE; + } + + + HMIXFILE hShpMix=FindFileInMix(filename, &bTerrain); + + BYTE bIgnoreTerrain=TRUE; + + if(hShpMix==NULL && isNewTerrain) + { + filename.SetAt(1, 'G'); + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix) theat='G'; + + } + + + if(hShpMix==NULL && isNewTerrain) + { + filename.SetAt(1, 'N'); + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix) theat='N'; + } + + if(hShpMix==NULL && isNewTerrain) + { + filename.SetAt(1, 'D'); + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix) theat='D'; + } + + if(hShpMix==NULL && isNewTerrain) + { + filename.SetAt(1, 'L'); + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix) theat='L'; + } + + if(hShpMix==NULL && isNewTerrain) + { + filename.SetAt(1, 'A'); + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix) theat='A'; + } + + if(hShpMix==NULL && isNewTerrain) + { + filename.SetAt(1, 'T'); + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix){ + theat='T'; + hPalette=m_hIsoTemp; + } + } + + + if(isTrue(artSection.GetValueByName("TerrainPalette"))) + { + bIgnoreTerrain=FALSE; + + if(cur_theat=='T') + hPalette=m_hPalIsoTemp; + else if(cur_theat=='A') + hPalette=m_hPalIsoSnow; + else if (cur_theat=='U') + hPalette=m_hPalIsoUrb; + else if(cur_theat=='L') + hPalette=m_hPalIsoLun; + else if(cur_theat=='D') + hPalette=m_hPalIsoDes; + else if(cur_theat=='N') + hPalette=m_hPalIsoUbn; + + + + } + + + + if(hShpMix==0) + { + filename=image; + filename+=".shp"; + hShpMix=FindFileInMix(filename, &bTerrain); + + + + if(hShpMix==NULL) + { + filename=image; + if(theat=='T') filename+=".tem"; + if(theat=='A') filename+=".sno"; + if(theat=='U') filename+=".urb"; + if(theat=='L') filename+=".lun"; + if(theat=='D') filename+=".des"; + if(theat=='N') filename+=".ubn"; + filename.MakeLower(); + hShpMix=FindFileInMix(filename, &bTerrain); + + if(hShpMix==NULL) + { + filename=image; + filename+=".tem"; + hShpMix=FindFileInMix(filename, &bTerrain); + if(hShpMix) + { + hPalette=m_hPalIsoTemp; + } + } + + if(hShpMix!=NULL) + { + + + + } + else + { + filename=image+".shp"; + + filename.SetAt(1, 'A'); + + hShpMix=FindFileInMix(filename); + + if(hShpMix!=NULL) + { + bAlwaysSetChar=TRUE; + } + else + { + filename.SetAt(1, 'A'); + hShpMix=FindFileInMix(filename); + + if(hShpMix!=NULL) + { + theat='A'; + bAlwaysSetChar=TRUE; + } + else + { + filename.SetAt(1, 'U'); + hShpMix=FindFileInMix(filename); + if(hShpMix) theat='U'; + else + { + filename.SetAt(1, 'L'); + hShpMix=FindFileInMix(filename); + if(hShpMix) theat='L'; + else + { + filename.SetAt(1, 'D'); + hShpMix=FindFileInMix(filename); + if(hShpMix) theat='D'; + else + { + filename.SetAt(1, 'N'); + hShpMix=FindFileInMix(filename); + if(hShpMix) theat='N'; + else + { + filename.SetAt(1, 'T'); + hShpMix=FindFileInMix(filename); + if(hShpMix) theat='T'; + } + } + } + } + } + } + } + } + else + { + theat='T'; + } + + } + else + { + + // now we need to find out the palette + + if(isTrue(artSection.GetValueByName("TerrainPalette"))) // it´s a file in isotemp.mix/isosno.mix + { + + } + else // it´s a file in temperat.mix/snow.mix + { + if(cur_theat=='T') hPalette=m_hPalUnitTemp; + if(cur_theat=='A') hPalette=m_hPalUnitSnow; + if(cur_theat=='U') hPalette=m_hPalUnitUrb; + if(cur_theat=='L') hPalette=m_hPalUnitLun; + if(cur_theat=='D') hPalette=m_hPalUnitDes; + if(cur_theat=='N') hPalette=m_hPalUnitUbn; + } + + }*/ + + auto shp = FindUnitShp(image, cur_theat, artSection); + if (!shp) + return; + + filename = shp->filename; + hPalette = shp->palette; + + auto limited_to_theater = isTrue(artSection.GetValueByName("TerrainPalette")) ? shp->mixfile_theater : TheaterChar::None; + + if(filename=="tibtre01.tem" || filename=="tibtre02.tem" || filename=="tibtre03.tem" || filename=="veinhole.tem") + { + hPalette=m_hPalUnitTemp; + } + + + if(shp->mixfile>0) + { + + BOOL bSuccess=FSunPackLib::SetCurrentSHP(filename, shp->mixfile); + if( + !bSuccess + ) + { + filename=image+".sno"; + if(cur_theat=='T' || cur_theat=='U') hPalette=m_hPalIsoTemp; + HMIXFILE hShpMix=FindFileInMix(filename); + bSuccess=FSunPackLib::SetCurrentSHP(filename, hShpMix); + + if(!bSuccess) + { + return; + } + } + + if(bSuccess) + { + + + char ic[50]; + int i=0; + itoa(i, ic, 10); + + // just fill in a stub entry - Final* will automatically retry loading once the graphic really must be loaded + PICDATA p; + p.pic=NULL; + p.x=0; + p.y=0; + p.wHeight=0; + p.wWidth=0; + p.wMaxWidth=0; + p.wMaxHeight=0; + p.bType=PICDATA_TYPE_SHP; + p.bTerrain=limited_to_theater; + + + pics[image+ic]=p; + + + } + + } + + } + catch(...) + { + errstream << " exception " << endl; + errstream.flush(); + } + + + } + +} + +/* +Helper function that fetches the palette data from FsunPackLib +FSunPackLib doesn´t provide any special function to retrieve a color table entry, +so we have to build it ourself +Also builds color_conv +*/ +void CLoading::FetchPalettes() +{ + // SetTSPaletteEntry(HTSPALETTE hPalette, BYTE bIndex, RGBTRIPLE* rgb, RGBTRIPLE* orig); + // SetTSPaletteEntry can retrieve the current color table entry without modifying it! + + + // iso palette + HTSPALETTE hCur=0; + if(Map->GetTheater()==THEATER0) hCur=m_hPalIsoTemp; + if(Map->GetTheater()==THEATER1) hCur=m_hPalIsoSnow; + if(Map->GetTheater()==THEATER2) hCur=m_hPalIsoUrb; + if(Map->GetTheater()==THEATER3) hCur=m_hPalIsoUbn; + if(Map->GetTheater()==THEATER4) hCur=m_hPalIsoLun; + if(Map->GetTheater()==THEATER5) hCur=m_hPalIsoDes; + + int i; + + for(i=0;i<256;i++) + { + FSunPackLib::SetTSPaletteEntry(hCur, i, NULL /* don´t modify it!*/, &palIso[i] /*but retrieve it!*/); + } + + + // unit palette + if(Map->GetTheater()==THEATER0) hCur=m_hPalUnitTemp; + if(Map->GetTheater()==THEATER1) hCur=m_hPalUnitSnow; + if(Map->GetTheater()==THEATER2) hCur=m_hPalUnitUrb; + if(Map->GetTheater()==THEATER3) hCur=m_hPalUnitUbn; + if(Map->GetTheater()==THEATER4) hCur=m_hPalUnitLun; + if(Map->GetTheater()==THEATER5) hCur=m_hPalUnitDes; + + + for(i=0;i<256;i++) + { + FSunPackLib::SetTSPaletteEntry(hCur, i, NULL /* don´t modify it!*/, &palUnit[i] /*but retrieve it!*/); + } + + + // theater palette + if(Map->GetTheater()==THEATER0) hCur=m_hPalTemp; + if(Map->GetTheater()==THEATER1) hCur=m_hPalSnow; + if(Map->GetTheater()==THEATER2) hCur=m_hPalUrb; + if(Map->GetTheater()==THEATER3) hCur=m_hPalUbn; + if(Map->GetTheater()==THEATER4) hCur=m_hPalLun; + if(Map->GetTheater()==THEATER5) hCur=m_hPalDes; + + + + for(i=0;i<256;i++) + { + FSunPackLib::SetTSPaletteEntry(hCur, i, NULL /* don´t modify it!*/, &palTheater[i] /*but retrieve it!*/); + } + + + // lib palette + hCur=m_hPalLib; + + + for(i=0;i<256;i++) + { + FSunPackLib::SetTSPaletteEntry(hCur, i, NULL /* don´t modify it!*/, &palLib[i] /*but retrieve it!*/); + } + + CreateConvTable(palIso, iPalIso); + CreateConvTable(palLib, iPalLib); + CreateConvTable(palUnit, iPalUnit); + CreateConvTable(palTheater, iPalTheater); + + CIsoView& v=*((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + + DDPIXELFORMAT pf; + memset(&pf, 0, sizeof(DDPIXELFORMAT)); + pf.dwSize=sizeof(DDPIXELFORMAT); + + v.lpds->GetPixelFormat(&pf); + v.pf = pf; + v.m_color_converter.reset(new FSunPackLib::ColorConverter(v.pf)); + + FSunPackLib::ColorConverter conf(pf); + + const auto& rulesColors = rules.sections["Colors"]; + for(i=0;i< rulesColors.values.size();i++) + { + CString col=*rulesColors.GetValueName(i); + COLORREF cref=v.GetColor("", col); + + color_conv[col]=conf.GetColor(GetRValue(cref), GetGValue(cref), GetBValue(cref)); + colorref_conv[cref]=color_conv[col]; + } +} + +void CLoading::CreateConvTable(RGBTRIPLE *pal, int *iPal) +{ + CIsoView& v=*((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview; + + DDPIXELFORMAT pf; + memset(&pf, 0, sizeof(DDPIXELFORMAT)); + pf.dwSize=sizeof(DDPIXELFORMAT); + + v.lpds->GetPixelFormat(&pf); + + FSunPackLib::ColorConverter conf(pf); + + int i; + for(i=0;i<256;i++) + { + iPal[i]=conf.GetColor(pal[i].rgbtRed, pal[i].rgbtGreen, pal[i].rgbtBlue); + } +} diff --git a/MissionEditor/Loading.h b/MissionEditor/Loading.h new file mode 100644 index 0000000..eb07890 --- /dev/null +++ b/MissionEditor/Loading.h @@ -0,0 +1,221 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_LOADING_H__5D5C3284_8962_11D3_B63B_AAA51FD322E3__INCLUDED_) +#define AFX_LOADING_H__5D5C3284_8962_11D3_B63B_AAA51FD322E3__INCLUDED_ + +#include "FinalSunDlg.h" +#include "MissionEditorPackLib.h" +#include <memory> +#include <optional> + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Loading.h : header file +// + +class VoxelNormalTables; + +struct EXPANDMIX +{ + HMIXFILE hExpand; // NULL if expansion mix does not exist + HMIXFILE hECache; // NULL if no ECache + HMIXFILE hConquer; // NULL if no Conquer + HMIXFILE hLocal; + HMIXFILE hIsoSnow; // NULL if no IsoSnow + HMIXFILE hIsoTemp; // NULL if no IsoTemp + HMIXFILE hIsoUrb; + HMIXFILE hIsoGen; + HMIXFILE hIsoLun; + HMIXFILE hIsoDes; + HMIXFILE hIsoUbn; + HMIXFILE hIsoGenMd; + HMIXFILE hIsoLunMd; + HMIXFILE hIsoDesMd; + HMIXFILE hIsoUbnMd; + HMIXFILE hTemperat; // NULL if no Temperat + HMIXFILE hSnow; + HMIXFILE hUrban; + HMIXFILE hLunar; + HMIXFILE hUrbanN; + HMIXFILE hDesert; + HMIXFILE hGeneric; + HMIXFILE hTem; + HMIXFILE hSno; + HMIXFILE hUrb; + HMIXFILE hLun; + HMIXFILE hDes; + HMIXFILE hUbn; + HMIXFILE hBuildings; + HMIXFILE hMarble; + EXPANDMIX() {memset(this, 0, sizeof(EXPANDMIX));}; +}; + +class CFinalSunDlg; + + +///////////////////////////////////////////////////////////////////////////// +// dialog field CLoading + + +struct FindShpResult +{ + FindShpResult(HMIXFILE mixfile_, TheaterChar mixfile_theater_, CString filename_, TheaterChar theat_, HTSPALETTE palette_): mixfile(mixfile_), mixfile_theater(mixfile_theater_), filename(filename_), theat(theat_), palette(palette_) { } + HMIXFILE mixfile; + TheaterChar mixfile_theater; + CString filename; + TheaterChar theat; + HTSPALETTE palette; +}; + +class CLoading : public CDialog +{ +// Construction +public: + void CreateConvTable(RGBTRIPLE* pal, int* iPal); + void FetchPalettes(); + void PrepareUnitGraphic(LPCSTR lpUnittype); + void LoadStrings(); + void FreeAll(); + void FreeTileSet(); + BOOL InitDirectDraw(); + + void InitTMPs(CProgressCtrl* prog=NULL); + void InitPalettes(); + + ~CLoading(); + void Unload(); + BOOL InitMixFiles(); + void InitSHPs(CProgressCtrl* prog=NULL); + void LoadTSIni(LPCTSTR lpFilename, CIniFile* lpIniFile, BOOL bIsExpansion, BOOL bCheckEditorDir = FALSE); + void CreateINI(); + CLoading(CWnd* pParent = NULL); // Standardconstructor + void InitPics(CProgressCtrl* prog=NULL); + void Load(); + BOOL LoadUnitGraphic(LPCTSTR lpUnittype); + void LoadBuildingSubGraphic(const CString& subkey, const CIniFileSection& artSection, BOOL bAlwaysSetChar, char theat, HMIXFILE hShpMix, SHPHEADER& shp_h, BYTE*& shp); + void LoadOverlayGraphic(LPCTSTR lpOvrlName, int iOvrlNum); + void InitVoxelNormalTables(); + HTSPALETTE GetIsoPalette(char theat); + HTSPALETTE GetUnitPalette(char theat); + std::optional<FindShpResult> FindUnitShp(const CString& image, char preferred_theat, const CIniFileSection& artSection); + char cur_theat; + + +// Dialog data + //{{AFX_DATA(CLoading) + enum { IDD = IDD_LOADING }; + CStatic m_Version; + CStatic m_BuiltBy; + CStatic m_cap; + CProgressCtrl m_progress; + //}}AFX_DATA + + +// Overwriteables + // class wizard generated overwriteables + //{{AFX_VIRTUAL(CLoading) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-support + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementation +protected: + void PrepareBuildingTheaters(); + + // generated message handlers + //{{AFX_MSG(CLoading) + virtual BOOL OnInitDialog(); + afx_msg void OnDestroy(); + afx_msg void OnPaint(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + void HackRules(); + void PrepareHouses(void); + void CalcPicCount(); + int m_pic_count; + int m_bmp_count; + BOOL LoadTile(LPCSTR lpFilename, HMIXFILE hOwner, HTSPALETTE hPalette, DWORD dwID, BOOL bReplacement); + HTSPALETTE m_hPalIsoTemp; + HTSPALETTE m_hPalIsoSnow; + HTSPALETTE m_hPalIsoUrb; + + HTSPALETTE m_hPalUnitTemp; + HTSPALETTE m_hPalUnitSnow; + HTSPALETTE m_hPalUnitUrb; + HTSPALETTE m_hPalTemp; + HTSPALETTE m_hPalSnow; + HTSPALETTE m_hPalUrb; + HTSPALETTE m_hPalLib; + // YR pals: + HTSPALETTE m_hPalLun; + HTSPALETTE m_hPalDes; + HTSPALETTE m_hPalUbn; + HTSPALETTE m_hPalIsoLun; + HTSPALETTE m_hPalIsoDes; + HTSPALETTE m_hPalIsoUbn; + HTSPALETTE m_hPalUnitLun; + HTSPALETTE m_hPalUnitDes; + HTSPALETTE m_hPalUnitUbn; + + HMIXFILE FindFileInMix(LPCTSTR lpFilename, TheaterChar* pTheaterChar=NULL); + HMIXFILE m_hLocal; + HMIXFILE m_hSno; + HMIXFILE m_hTem; + HMIXFILE m_hUrb; + HMIXFILE m_hLun; + HMIXFILE m_hDes; + HMIXFILE m_hUbn; + HMIXFILE m_hTibSun; + HMIXFILE m_hBuildings; + EXPANDMIX m_hExpand[101]; // 1 added for ra2md.mix + HMIXFILE m_hECache[100]; + HMIXFILE m_hIsoSnow; + HMIXFILE m_hIsoTemp; + HMIXFILE m_hIsoUrb; + HMIXFILE m_hIsoGen; + HMIXFILE m_hIsoLun; + HMIXFILE m_hIsoDes; + HMIXFILE m_hIsoUbn; + HMIXFILE m_hTemperat; + HMIXFILE m_hSnow; + HMIXFILE m_hUrban; + HMIXFILE m_hUrbanN; + HMIXFILE m_hLunar; + HMIXFILE m_hDesert; + HMIXFILE m_hCache; + HMIXFILE m_hConquer; + HMIXFILE m_hLanguage; + HMIXFILE m_hLangMD; + HMIXFILE m_hMarble; + BOOL loaded; + + std::unique_ptr<VoxelNormalTables> m_voxelNormalTables; + + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_LOADING_H__5D5C3284_8962_11D3_B63B_AAA51FD322E3__INCLUDED_ diff --git a/MissionEditor/MMXSavingOptionsDlg.cpp b/MissionEditor/MMXSavingOptionsDlg.cpp new file mode 100644 index 0000000..80af27f --- /dev/null +++ b/MissionEditor/MMXSavingOptionsDlg.cpp @@ -0,0 +1,86 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MMXSavingOptionsDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "MMXSavingOptionsDlg.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CMMXSavingOptionsDlg + + +CMMXSavingOptionsDlg::CMMXSavingOptionsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CMMXSavingOptionsDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CMMXSavingOptionsDlg) + m_Description = _T(""); + m_AirWar = FALSE; + m_Cooperative = FALSE; + m_Duel = FALSE; + m_Maxplayers = 0; + m_Meatgrind = FALSE; + m_MegaWealth = FALSE; + m_MinPlayers = 0; + m_NavalWar = FALSE; + m_NukeWar = FALSE; + m_Standard = TRUE; + //}}AFX_DATA_INIT + + m_Description=Map->GetIniFile().sections["Basic"].values["Name"]; +} + + +void CMMXSavingOptionsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CMMXSavingOptionsDlg) + DDX_Text(pDX, IDC_DESCRIPTION, m_Description); + DDX_Check(pDX, IDC_AIRWAR, m_AirWar); + DDX_Check(pDX, IDC_COOPERATIVE, m_Cooperative); + DDX_Check(pDX, IDC_DUEL, m_Duel); + DDX_CBIndex(pDX, IDC_MAXPLAYERS, m_Maxplayers); + DDX_Check(pDX, IDC_MEATGRIND, m_Meatgrind); + DDX_Check(pDX, IDC_MEGAWEALTH, m_MegaWealth); + DDX_CBIndex(pDX, IDC_MINPLAYERS, m_MinPlayers); + DDX_Check(pDX, IDC_NAVALWAR, m_NavalWar); + DDX_Check(pDX, IDC_NUKEWAR, m_NukeWar); + DDX_Check(pDX, IDC_STANDARD, m_Standard); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CMMXSavingOptionsDlg, CDialog) + //{{AFX_MSG_MAP(CMMXSavingOptionsDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros fĂ¼r Nachrichten ein + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CMMXSavingOptionsDlg diff --git a/MissionEditor/MMXSavingOptionsDlg.h b/MissionEditor/MMXSavingOptionsDlg.h new file mode 100644 index 0000000..783b5a2 --- /dev/null +++ b/MissionEditor/MMXSavingOptionsDlg.h @@ -0,0 +1,76 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_MMXSAVINGOPTIONSDLG_H__1A62AFE1_E8CA_11D4_9C88_444553540000__INCLUDED_) +#define AFX_MMXSAVINGOPTIONSDLG_H__1A62AFE1_E8CA_11D4_9C88_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// MMXSavingOptionsDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CMMXSavingOptionsDlg + +class CMMXSavingOptionsDlg : public CDialog +{ +// Konstruktion +public: + CMMXSavingOptionsDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CMMXSavingOptionsDlg) + enum { IDD = IDD_MMXOPTIONS }; + CString m_Description; + BOOL m_AirWar; + BOOL m_Cooperative; + BOOL m_Duel; + int m_Maxplayers; + BOOL m_Meatgrind; + BOOL m_MegaWealth; + int m_MinPlayers; + BOOL m_NavalWar; + BOOL m_NukeWar; + BOOL m_Standard; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CMMXSavingOptionsDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CMMXSavingOptionsDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_MMXSAVINGOPTIONSDLG_H__1A62AFE1_E8CA_11D4_9C88_444553540000__INCLUDED_ diff --git a/MissionEditor/Macros.h b/MissionEditor/Macros.h new file mode 100644 index 0000000..e1215e9 --- /dev/null +++ b/MissionEditor/Macros.h @@ -0,0 +1,38 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +/* + macros.h + + FinalSun Macros (mainly constant variables) +*/ + +#ifndef FINALSUN_MACROS_INCLUDED +#define FINALSUN_MACROS_INCLUDED + +/* Overlay types */ +#define OVRL_VEINS 0x7e +#define OVRL_VEINHOLE 0xa7 +#define OVRL_VEINHOLEBORDER 0xb2 + +#define OVRL_TRACK_BEGIN 0x27 +#define OVRL_TRACK_END 0x36 // 0x32 was old end [changed on 2/13/2000] + +#endif \ No newline at end of file diff --git a/MissionEditor/MapCode.cpp b/MissionEditor/MapCode.cpp new file mode 100644 index 0000000..aad82c0 --- /dev/null +++ b/MissionEditor/MapCode.cpp @@ -0,0 +1,152 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// This code determines the cell values for +// StartX, StartY, Width & Height for the [Header] section + +#include "stdafx.h" +#include "MapCode.h" +#include "mapdata.h" +#include "defines.h" + + + + +int calcXPos(int x, int y) +{ + int x1=x*256+128; + + int y1 = y*256 + 128; + + int x2 = (x1 - y1) * 30; + + int y2 = (x1 + y1) * 15; + + int x3 = (x2/256 + 512*30) / 60; + + int y3 = (y2/256) / 30; + + return x3; +} + +int calcYPos(int x, int y) +{ + int x1=x*256+128; + + int y1 = y*256 + 128; + + int x2 = (x1 - y1) * 30; + + int y2 = (x1 + y1) * 15; + + int x3 = (x2/256 + 512*30) / 60; + + int y3 = (y2/256) / 30; + + return y3; +} + +struct MRECT +{ + int X; + int Y; + int Width; + int Height; +}; + + +void MC_GetHeaderRect(int& startx, int& starty, int& width, int& height) +{ + int leastx=10000; + int leasty=10000; + int mostx=0; + int mosty=0; + + MRECT LocalRect, PlayRect; + + RECT r; + Map->GetLocalSize(&r); + LocalRect.X=r.left; + LocalRect.Y=r.top; + LocalRect.Width=r.right; + LocalRect.Height=r.bottom; + + CIniFile& ini=Map->GetIniFile(); + PlayRect.X=0; + PlayRect.Y=0; + PlayRect.Width=Map->GetWidth(); + PlayRect.Height=Map->GetHeight(); + + char c[50]; + char d[50]; + itoa(LocalRect.Width, c, 10); + + int x,y; + int max=Map->GetIsoSize(); + for(x=0;x<max;x++) + { + for(y=0;y<max;y++) + { + int height=0; + + if (TRUE) { + + height = Map->GetHeightAt(y+x*max); // remember: x/y switched here, WS coordinate system + + // fudge ramps at the top of the map so that they end up considered not in the local rect + //if (cell->ramp && x + y < PlayRect.Width + 2*LocalRect.Y + 4 + height) { + //height++; + //} + } + + + if ((x + y > PlayRect.Width + 2*LocalRect.Y + height) && + (x + y <= PlayRect.Width + 2*(LocalRect.Y + LocalRect.Height + 1) + height) && + (x - y < 2*(LocalRect.X + LocalRect.Width) - PlayRect.Width) && + (y - x < PlayRect.Width - 2*LocalRect.X)) + //if ((x + y > PlayRect.Width) && (x - y < PlayRect.Width) && (y - x < PlayRect.Width) && (x + y <= PlayRect.Width + 2 * PlayRect.Height)) + { + int rx=calcXPos(x,y); + int ry=calcYPos(x,y); + + if (rx < leastx) + leastx = rx; + + if (rx > mostx) + mostx = rx; + + if (ry < leasty) + leasty = ry; + + if (ry > mosty) + mosty = ry; + } + + } + } + + startx=leastx; + starty=leasty; + width=mostx-leastx; + height=mosty-leasty; +} + + + \ No newline at end of file diff --git a/MissionEditor/MapCode.h b/MissionEditor/MapCode.h new file mode 100644 index 0000000..ab017d4 --- /dev/null +++ b/MissionEditor/MapCode.h @@ -0,0 +1,28 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#ifndef MAPCODE_INCLUDED +#define MAPCODE_INCLUDED + +void MC_GetHeaderRect(int& startx, int& starty, int& width, int& height); +int calcXPos(int x, int y); +int calcYPos(int x, int y); + +#endif \ No newline at end of file diff --git a/MissionEditor/MapD.cpp b/MissionEditor/MapD.cpp new file mode 100644 index 0000000..238fa46 --- /dev/null +++ b/MissionEditor/MapD.cpp @@ -0,0 +1,169 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MapD.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "MapD.h" +#include "resource.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "changesizedlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CMapD + +IMPLEMENT_DYNCREATE(CMapD, CDialog) + +CMapD::CMapD() : CDialog(CMapD::IDD) +{ + //{{AFX_DATA_INIT(CMapD) + m_Width = _T(""); + m_Height = _T(""); + //}}AFX_DATA_INIT +} + +CMapD::~CMapD() +{ +} + +void CMapD::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CMapD) + DDX_Control(pDX, IDC_USESIZE, m_LocalSize); + DDX_Control(pDX, IDC_THEATER, m_Theater); + DDX_Text(pDX, IDC__SIZEX, m_Width); + DDX_Text(pDX, IDC__SIZEY, m_Height); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CMapD, CDialog) + //{{AFX_MSG_MAP(CMapD) + ON_EN_CHANGE(IDC_USESIZE, OnChangeUsesize) + ON_CBN_EDITCHANGE(IDC_THEATER, OnEditchangeTheater) + ON_BN_CLICKED(IDC_CHANGELOCAL, OnChangelocal) + ON_CBN_SELCHANGE(IDC_THEATER, OnEditchangeTheater) + ON_BN_CLICKED(IDC_CHANGE, OnChange) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CMapD + +void CMapD::UpdateDialog() +{ + CIniFile& ini=Map->GetIniFile(); + + m_LocalSize.SetWindowText( ini.sections["Map"].values["LocalSize"] ); + //m_Size.SetWindowText( ini.sections["Map"].values["Size"] ); + m_Theater.SetWindowText( ini.sections["Map"].values["Theater"] ); + + char c[50]; + itoa(Map->GetWidth(), c, 10); + m_Width=c; + itoa(Map->GetHeight(), c, 10); + m_Height=c; + + CDialog::UpdateData(FALSE); +} + +void CMapD::UpdateData() +{ + //MessageBox("This function ( UpdateData() ) should not be called, please contact the author."); +} + +void CMapD::OnChangeUsesize() +{ + +} + +void CMapD::OnEditchangeTheater() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Map"].values["Theater"]=GetText(&m_Theater); +} + +void CMapD::UpdateStrings() +{ + + GetDlgItem(IDC_DESC)->SetWindowText(GetLanguageStringACP("MapDesc")); + GetDlgItem(IDC_SIZEFRAME)->SetWindowText(GetLanguageStringACP("MapSizeFrame")); + GetDlgItem(IDC_LSIZE)->SetWindowText(GetLanguageStringACP("MapSize")); + GetDlgItem(IDC_USEABLEFRAME)->SetWindowText(GetLanguageStringACP("MapVisibleSizeFrame")); + GetDlgItem(IDC_LUSEABLE)->SetWindowText(GetLanguageStringACP("MapVisibleSize")); + GetDlgItem(IDC_LTHEATER)->SetWindowText(GetLanguageStringACP("MapTheater")); +} + +void CMapD::OnChangelocal() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Map"].values["LocalSize"]=GetText(&m_LocalSize); + + Map->CalcMapRect(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + +void CMapD::OnChange() +{ + /* + CDialog::UpdateData(TRUE); + + int width, height; + width=atoi(m_Width); + height=atoi(m_Height); + + Map->ResizeMap(width, height); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + */ + + CChangeSizeDlg dlg; + if(dlg.DoModal()==IDCANCEL) return; + + if(dlg.m_Width<16 || dlg.m_Width>400 || dlg.m_Height<16 || dlg.m_Height>400 || (dlg.m_Width + dlg.m_Height) > 512) + { + MessageBox("Width and Height must both be between 16 and 400 and both added must be less than 512.", "Error"); + return; + } + + Map->ResizeMap(dlg.m_Left, dlg.m_Top, dlg.m_Width, dlg.m_Height); + + + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_minimap.UpdateView(); + + char c[50]; + itoa(dlg.m_Width, c, 10); + + m_Width=c; + itoa(dlg.m_Height, c, 10); + m_Height=c; + CDialog::UpdateData(FALSE); +} diff --git a/MissionEditor/MapD.h b/MissionEditor/MapD.h new file mode 100644 index 0000000..334cb3d --- /dev/null +++ b/MissionEditor/MapD.h @@ -0,0 +1,78 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_MAPD_H__B5D522E9_69CE_11D3_99E1_C138647F2A00__INCLUDED_) +#define AFX_MAPD_H__B5D522E9_69CE_11D3_99E1_C138647F2A00__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// MapD.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CMapD + +class CMapD : public CDialog +{ + DECLARE_DYNCREATE(CMapD) + +// Konstruktion +public: + void UpdateStrings(); + void UpdateData(); + void UpdateDialog(); + CMapD(); + ~CMapD(); + +// Dialogfelddaten + //{{AFX_DATA(CMapD) + enum { IDD = IDD_MAP }; + CEdit m_LocalSize; + CComboBox m_Theater; + CString m_Width; + CString m_Height; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CMapD) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CMapD) + afx_msg void OnChangeUsesize(); + afx_msg void OnEditchangeTheater(); + afx_msg void OnChangelocal(); + afx_msg void OnChange(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_MAPD_H__B5D522E9_69CE_11D3_99E1_C138647F2A00__INCLUDED_ diff --git a/MissionEditor/MapData.cpp b/MissionEditor/MapData.cpp new file mode 100644 index 0000000..1faee3e --- /dev/null +++ b/MissionEditor/MapData.cpp @@ -0,0 +1,7461 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Map->cpp: Implementierung der Klasse CMap. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "MapData.h" +#include "DynamicGraphDlg.h" +#include "MissionEditorPackLib.h" +#include "inlines.h" +#include "variables.h" +#include "maploadingdlg.h" +#include "progressdlg.h" +#include "Structs.h" +#include "Tube.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#define new DEBUG_NEW +#endif + +typedef map<CString, CString, SortDummy> OURMAP; + + + +void DoEvents() +{ + /*MSG msg; + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + }*/ +} + + +void GetNodeName(CString& name, int n); + + +CString GetFree(const char* section) +{ + CIniFile& ini = Map->GetIniFile(); + + int i = 0; + char l[50]; + itoa(i, l, 10); + + while (ini.sections[section].values.find(l) != ini.sections[section].values.end()) + { + i++; + itoa(i, l, 10); + } + + return l; +} + + +/* +This function calculates a number for the specified building type. +Because this function is slow, you should only use it to fill the +buildingid map +*/ +inline int GetBuildingNumber(LPCTSTR name) +{ + CIniFile& ini = Map->GetIniFile(); + + int v = rules.sections["BuildingTypes"].FindValue(name); + + if (v > -1) + { + + return v; + } + + v = ini.sections["BuildingTypes"].FindValue(name); + if (v > -1) + { + return v + 0x0C00; + } + return -1; +} + +inline int GetTerrainNumber(LPCTSTR name) +{ + CIniFile& ini = Map->GetIniFile(); + + int v = rules.sections["TerrainTypes"].FindValue(name); + + if (v > -1) + { + + return v; + } + + v = ini.sections["TerrainTypes"].FindValue(name); + if (v > -1) + { + return v + 0x0C00; + } + return -1; +} + +#ifdef SMUDGE_SUPP +inline int GetSmudgeNumber(LPCTSTR name) +{ + CIniFile& ini = Map->GetIniFile(); + + int v = rules.sections["SmudgeTypes"].FindValue(name); + + if (v > -1) + { + + return v; + } + + v = ini.sections["SmudgeTypes"].FindValue(name); + if (v > -1) + { + return v + 0x0C00; + } + return -1; +} +#endif + +SNAPSHOTDATA::SNAPSHOTDATA() +{ + memset(this, 0, sizeof(SNAPSHOTDATA)); +} + + +NODEDATA::NODEDATA() +{ + type = -1; + house = ""; + index = -1; +} + +FIELDDATA::FIELDDATA() +{ +#ifdef SMUDGE_SUPP + smudge = -1; + smudgetype = -1; +#endif + unit = -1; + int i; + for (i = 0;i < SUBPOS_COUNT;i++) + infantry[i] = -1; + aircraft = -1; + structure = -1; + structuretype = -1; + terrain = -1; + waypoint = -1; + overlay = 0xFF; + overlaydata = 0x0; + bMapData = 0x0; + bSubTile = 0; + bMapData2 = 0x0; + wGround = 0xFFFF; + bHeight = 0; + celltag = -1; + bReserved = 0; + bCliffHack = 0; + bRedrawTerrain = 0; + terraintype = -1; + bHide = FALSE; + //sTube = 0xFFFF; + //cTubePart = -1; + + if (tiledata_count && (*tiledata_count)) // only if initialized + { + // algorithm taken from UpdateMapFieldData + int replacement = 0; + int ground = wGround; + if (ground == 0xFFFF) ground = 0; + ASSERT(ground == 0); + + // we assume ground 0 will never be a bridge set, so don't do this check here in contrast to UpdateMapFieldData + if ((*tiledata)[ground].bReplacementCount) //&& atoi((*tiles).sections["General"].values["BridgeSet"]) != (*tiledata)[ground].wTileSet) + { + replacement = rand() * (1 + (*tiledata)[ground].bReplacementCount) / RAND_MAX; + } + + bRNDImage = replacement; + } + +}; + +CMapData::CMapData() +{ + m_noAutoObjectUpdate = FALSE; + m_money = 0; + m_cursnapshot = -1; + fielddata = NULL; + fielddata_size = 0; + m_IsoSize = 0; + isInitialized = FALSE; + tiledata = NULL; + m_mfd = NULL; + dwIsoMapSize = 0; + m_snapshots = NULL; + dwSnapShotCount = 0; + + memset(&m_mini_biinfo, 0, sizeof(BITMAPINFO)); + m_mini_biinfo.bmiHeader.biBitCount = 24; + m_mini_biinfo.bmiHeader.biWidth = 0; + m_mini_biinfo.bmiHeader.biHeight = 0; + m_mini_biinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + m_mini_biinfo.bmiHeader.biClrUsed = 0; + m_mini_biinfo.bmiHeader.biPlanes = 1; + m_mini_biinfo.bmiHeader.biCompression = BI_RGB; + m_mini_biinfo.bmiHeader.biClrImportant = 0; +} + +CMapData::~CMapData() +{ + errstream << "CMapData::~CMapData()\n"; + errstream.flush(); + + // MW : Do not delete tiledata here! + //if(*tiledata!=NULL) delete[] *tiledata; + tiledata = NULL; + if (m_mfd != NULL) delete[] m_mfd; + m_mfd = NULL; + if (fielddata != NULL) delete[] fielddata; + fielddata = NULL; + fielddata_size = 0; + + int i; + + for (i = 0;i < dwSnapShotCount;i++) + { + delete[] m_snapshots[i].bHeight; + delete[] m_snapshots[i].bMapData; + delete[] m_snapshots[i].bSubTile; + delete[] m_snapshots[i].bMapData2; + delete[] m_snapshots[i].wGround; + delete[] m_snapshots[i].bRedrawTerrain; + delete[] m_snapshots[i].overlay; + delete[] m_snapshots[i].overlaydata; + // m_snapshots[i].mapfile.Clear(); + } + if (m_snapshots) delete[] m_snapshots; + m_snapshots = NULL; + dwSnapShotCount = 0; +} + +void CMapData::CalcMapRect() +{ + CIniFileSection& sec = m_mapfile.sections["Map"]; + char msize[50]; + strcpy_s(msize, sec.values["Size"]); + + + int cupos = 0; + static const int custr_size = 20; + char custr[custr_size]; + char* cucomma; + + cucomma = strchr(&msize[cupos], ','); + if (cucomma == NULL) return; + memcpy_s(custr, custr_size, &msize[cupos], (cucomma - msize) - cupos + 1); + custr[(cucomma - msize) - cupos] = 0; + cupos = cucomma - msize + 1; + + m_maprect.left = atoi(custr); + + + cucomma = strchr(&msize[cupos], ','); + if (cucomma == NULL) return; + memcpy_s(custr, custr_size, &msize[cupos], (cucomma - msize) - cupos + 1); + custr[((cucomma - msize)) - cupos] = 0; + cupos = cucomma - msize + 1; + + m_maprect.top = atoi(custr); + + + cucomma = strchr(&msize[cupos], ','); + if (cucomma == NULL) return; + memcpy_s(custr, custr_size, &msize[cupos], (cucomma - msize) - cupos + 1); + custr[((cucomma - msize)) - cupos] = 0; + cupos = cucomma - msize + 1; + + m_maprect.right = atoi(custr); + + cucomma = strchr(&msize[cupos], ','); // we check again... could be there is a new ini format + if (cucomma == NULL) cucomma = (char*)((int)msize + strlen(msize)); + memcpy_s(custr, custr_size, &msize[cupos], (cucomma - msize) - cupos + 1); + custr[((cucomma - msize)) - cupos] = 0; + cupos = cucomma - msize + 1; + + m_maprect.bottom = atoi(custr); + + m_IsoSize = m_maprect.right + m_maprect.bottom; + + // local size + + strcpy_s(msize, sec.values["LocalSize"]); + cupos = 0; + + + cucomma = strchr(&msize[cupos], ','); + if (cucomma == NULL) return; + memcpy_s(custr, custr_size, &msize[cupos], (cucomma - msize) - cupos + 1); + custr[(cucomma - msize) - cupos] = 0; + cupos = cucomma - msize + 1; + + m_vismaprect.left = atoi(custr); + + + cucomma = strchr(&msize[cupos], ','); + if (cucomma == NULL) return; + memcpy_s(custr, custr_size, &msize[cupos], (cucomma - msize) - cupos + 1); + custr[((cucomma - msize)) - cupos] = 0; + cupos = cucomma - msize + 1; + + m_vismaprect.top = atoi(custr); + + + cucomma = strchr(&msize[cupos], ','); + if (cucomma == NULL) return; + memcpy_s(custr, custr_size, &msize[cupos], (cucomma - msize) - cupos + 1); + custr[((cucomma - msize)) - cupos] = 0; + cupos = cucomma - msize + 1; + + m_vismaprect.right = atoi(custr); + + + cucomma = strchr(&msize[cupos], ','); // we check again... could be there is a new ini format + if (cucomma == NULL) cucomma = (char*)((int)msize + strlen(msize)); + memcpy_s(custr, custr_size, &msize[cupos], (cucomma - msize) - cupos + 1); + custr[((cucomma - msize)) - cupos] = 0; + cupos = cucomma - msize + 1; + + m_vismaprect.bottom = atoi(custr); + + +} + + + + + +WORD CMapData::GetHousesCount(BOOL bCountries) +{ +#ifndef RA2_MODE + bCountries = FALSE; +#endif + + CString sSection = MAPHOUSES; + if (bCountries) sSection = HOUSES; + + if (m_mapfile.sections.find(sSection) != m_mapfile.sections.end()) + if (m_mapfile.sections[sSection].values.size() > 0) return m_mapfile.sections[sSection].values.size(); + + return(rules.sections[HOUSES].values.size()); +} + +CString CMapData::GetHouseID(WORD wHouse, BOOL bCountry) +{ + if (wHouse >= GetHousesCount()) + return CString(""); + +#ifndef RA2_MODE + bCountry = FALSE; +#endif + + CString sSection = MAPHOUSES; + if (bCountry) sSection = HOUSES; + + + if (m_mapfile.sections.find(sSection) != m_mapfile.sections.end()) + if (m_mapfile.sections[sSection].values.size() > 0) return *m_mapfile.sections[sSection].GetValue(wHouse); + + return(*rules.sections[HOUSES].GetValue(wHouse)); +} + +DWORD CMapData::GetAITriggerTypeCount() +{ + if (m_mapfile.sections.find("AITriggerTypes") != m_mapfile.sections.end()) + return(m_mapfile.sections["AITriggerTypes"].values.size()); + + return 0; +} + +void CMapData::GetAITriggerType(DWORD dwAITriggerType, AITRIGGERTYPE* pAITrg) +{ + CString data; + + if (dwAITriggerType >= GetAITriggerTypeCount()) + return; + + data = *m_mapfile.sections["AITriggerTypes"].GetValue(dwAITriggerType); + + pAITrg->ID = *m_mapfile.sections["AITriggerTypes"].GetValueName(dwAITriggerType); + pAITrg->name = GetParam(data, 0); + pAITrg->teamtype1 = GetParam(data, 1); + pAITrg->owner = GetParam(data, 2); + pAITrg->techlevel = GetParam(data, 3); + pAITrg->type = GetParam(data, 4); + pAITrg->unittype = GetParam(data, 5); + pAITrg->data = GetParam(data, 6); + pAITrg->float1 = GetParam(data, 7); + pAITrg->float2 = GetParam(data, 8); + pAITrg->float3 = GetParam(data, 9); + pAITrg->skirmish = GetParam(data, 10); + pAITrg->flag4 = GetParam(data, 11); + pAITrg->multihouse = GetParam(data, 12); + pAITrg->basedefense = GetParam(data, 13); + pAITrg->teamtype2 = GetParam(data, 14); + pAITrg->easy = GetParam(data, 15); + pAITrg->medium = GetParam(data, 16); + pAITrg->hard = GetParam(data, 17); + + +} + +WORD CMapData::GetHouseIndex(LPCTSTR lpHouse) +{ + if (m_mapfile.sections.find(HOUSES) != m_mapfile.sections.end()) + if (m_mapfile.sections[HOUSES].values.size() > 0) + return m_mapfile.sections[HOUSES].FindValue(lpHouse); + + + return rules.sections[HOUSES].FindValue(lpHouse); +} + +DWORD CMapData::GetAITriggerTypeIndex(LPCTSTR lpID) +{ + if (GetAITriggerTypeCount() == 0) return 0; + + return m_mapfile.sections["AITriggerTypes"].FindName(lpID); +} + +CString CMapData::GetAITriggerTypeID(DWORD dwAITriggerType) +{ + if (dwAITriggerType >= GetAITriggerTypeCount()) return CString(""); + + return *m_mapfile.sections["AITriggerTypes"].GetValueName(dwAITriggerType); +} + +CIniFile& CMapData::GetIniFile() +{ + UpdateIniFile(); + return m_mapfile; +} + +/* +UpdateIniFile(); + +This will update the mapfile member if bSave==TRUE, +else the other data will be updated according to the info in mapfile. + +This sections will NOT be updated during loading from ini, +because of perfomance issues. They will not be updated not +during saving to ini if MAPDATA_UPDATE_TO_INI_ALL is not specified: + - IsoMapPack5 + - OverlayPack + - OverlayDataPack +If you want to load these sections, the caller needs to call Unpack(); +in order to do this. +*/ +void CMapData::UpdateIniFile(DWORD dwFlags) +{ + BOOL bSave = TRUE; + if (dwFlags == MAPDATA_UPDATE_FROM_INI) + bSave = FALSE; + + if (dwFlags == MAPDATA_UPDATE_FROM_INI) + { + CalcMapRect(); + InitMinimap(); + + slopesetpiecesset = atoi((*tiles).sections["General"].values["SlopeSetPieces"]); + rampset = atoi((*tiles).sections["General"].values["RampBase"]); + rampsmoothset = atoi((*tiles).sections["General"].values["RampSmooth"]); + cliffset = atoi((*tiles).sections["General"].values["CliffSet"]); + cliffset_start = GetTileID(cliffset, 0); + waterset = atoi((*tiles).sections["General"].values["WaterSet"]); + shoreset = atoi((*tiles).sections["General"].values["ShorePieces"]); + rampset_start = GetTileID(atoi((*tiles).sections["General"].values["RampBase"]), 0); + ramp2set = atoi(g_data.sections["NewUrbanInfo"].values["Ramps2"]); + ramp2set_start = GetTileID(ramp2set, 0); + pave2set = atoi(g_data.sections["NewUrbanInfo"].values["Morphable2"]); + pave2set_start = GetTileID(pave2set, 0); + cliff2set = atoi(g_data.sections["NewUrbanInfo"].values["Cliffs2"]); + cliff2set_start = GetTileID(cliff2set, 0); + cliffwater2set = atoi(g_data.sections["NewUrbanInfo"].values["CliffsWater2"]); + + InitializeUnitTypes(); + UpdateBuildingInfo(); + UpdateTreeInfo(); +#ifdef SMUDGE_SUPP + UpdateSmudgeInfo(); +#endif + UpdateMapFieldData(bSave); + + + } + else if (dwFlags & MAPDATA_UPDATE_TO_INI_ALL) + { + UpdateAircraft(bSave); + UpdateCelltags(bSave); + UpdateInfantry(bSave); + UpdateNodes(bSave); + UpdateOverlay(bSave); + UpdateStructures(bSave); + UpdateTerrain(bSave); +#ifdef SMUDGE_SUPP + UpdateSmudges(bSave); +#endif + UpdateUnits(bSave); + UpdateWaypoints(bSave); + UpdateTubes(bSave); + errstream << "UpdateMapFieldData() called" << endl; + errstream.flush(); + UpdateMapFieldData(bSave); + errstream << "About to call Pack()" << endl; + errstream.flush(); + Pack(dwFlags & MAPDATA_UPDATE_TO_INI_ALL_PREVIEW, dwFlags & MAPDATA_UPDATE_TO_INI_ALL_COMPRESSED); + return; + } + + if (!bSave) UpdateAircraft(bSave); + UpdateCelltags(bSave); + if (!bSave) UpdateInfantry(bSave); + UpdateNodes(bSave); + if (!bSave) UpdateOverlay(bSave); + if (!bSave) UpdateStructures(bSave); + if (!bSave) UpdateTerrain(bSave); +#ifdef SMUDGE_SUPP + if (!bSave) UpdateSmudges(bSave); +#endif + if (!bSave) UpdateUnits(bSave); + UpdateWaypoints(bSave); + UpdateTubes(bSave); + +} + +void CMapData::LoadMap(const std::string& file) +{ + errstream << "LoadMap() frees memory\n"; + errstream.flush(); + + if (fielddata != NULL) delete[] fielddata; + int i; + for (i = 0;i < dwSnapShotCount;i++) + { + delete[] m_snapshots[i].bHeight; + delete[] m_snapshots[i].bMapData; + delete[] m_snapshots[i].bSubTile; + delete[] m_snapshots[i].bMapData2; + delete[] m_snapshots[i].wGround; + delete[] m_snapshots[i].bRedrawTerrain; + delete[] m_snapshots[i].overlay; + delete[] m_snapshots[i].overlaydata; + // m_snapshots[i].mapfile.Clear(); + } + if (m_snapshots != NULL) delete[] m_snapshots; + + + + fielddata = NULL; + fielddata_size = 0; + m_snapshots = NULL; + dwSnapShotCount = 0; + m_cursnapshot = -1; + + m_tubes.clear(); + m_tubes.reserve(32); + + m_infantry.clear(); + m_terrain.clear(); + m_units.clear(); + m_structures.clear(); +#ifdef SMUDGE_SUPP + m_smudges.clear(); +#endif + + errstream << "LoadMap() loads map file\n"; + errstream.flush(); + + m_mapfile.Clear(); + m_mapfile.LoadFile(file, TRUE); + + // any .mpr is a multi map. Previous FinalAlert/FinalSun versions did not set this value correctly-> + char lowc[MAX_PATH] = { 0 }; + strcpy_s(lowc, file.c_str()); + _strlwr(lowc); + if (strstr(lowc, ".mpr")) + { + m_mapfile.sections["Basic"].values["MultiplayerOnly"] = "1"; + if (m_mapfile.sections["Basic"].FindName("Player") >= 0) m_mapfile.sections["Basic"].values.erase("Player"); + } + + + + errstream << "LoadMap() repairs Taskforces (if needed)\n"; + errstream.flush(); + + // repair taskforces (bug in earlier 0.95 versions) + for (i = 0;i < m_mapfile.sections["TaskForces"].values.size();i++) + { + vector<CString> toDelete; + toDelete.reserve(5); + + CIniFileSection& sec = m_mapfile.sections[*m_mapfile.sections["TaskForces"].GetValue(i)]; + int e; + for (e = 0;e < sec.values.size();e++) + { + if (sec.GetValue(e)->GetLength() == 0) + { + toDelete.push_back(*sec.GetValueName(e)); + } + + + } + for (e = 0;e < toDelete.size();e++) + { + sec.values.erase(toDelete[e]); + } + } + + errstream << "LoadMap() loads graphics\n"; + errstream.flush(); + + CDynamicGraphDlg dlg(theApp.m_pMainWnd); + dlg.ShowWindow(SW_SHOW); + dlg.UpdateWindow(); + + theApp.m_loading->Unload(); + theApp.m_loading->InitMixFiles(); + + map<CString, PICDATA>::iterator it = pics.begin(); + for (int e = 0;e < pics.size();e++) + { + try + { +#ifdef NOSURFACES_OBJECTS + if (it->second.bType == PICDATA_TYPE_BMP) + { + if (it->second.pic != NULL) + { + ((LPDIRECTDRAWSURFACE4)it->second.pic)->Release(); + } + } + else + { + if (it->second.pic != NULL) + { + delete[] it->second.pic; + } + if (it->second.vborder) delete[] it->second.vborder; + } +#else + if (it->second.pic != NULL) it->second.pic->Release(); +#endif + + it->second.pic = NULL; + } + catch (...) + { + CString err; + err = "Access violation while trying to release surface "; + char c[6]; + itoa(e, c, 10); + err += c; + + err += "\n"; + OutputDebugString(err); + continue; + } + + it++; + } + + pics.clear(); + missingimages.clear(); + + theApp.m_loading->InitPics(); + + UpdateBuildingInfo(); + UpdateTreeInfo(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->UpdateOverlayPictures(); + + + if (m_mapfile.sections["Map"].values["Theater"] == THEATER0) + { + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + theApp.m_loading->InitTMPs(&dlg.m_Progress); + theApp.m_loading->cur_theat = 'T'; + + } + else if (m_mapfile.sections["Map"].values["Theater"] == THEATER1) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + theApp.m_loading->InitTMPs(&dlg.m_Progress); + theApp.m_loading->cur_theat = 'A'; + } + else if (m_mapfile.sections["Map"].values["Theater"] == THEATER2) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + theApp.m_loading->InitTMPs(&dlg.m_Progress); + theApp.m_loading->cur_theat = 'U'; + } + else if (yuri_mode && m_mapfile.sections["Map"].values["Theater"] == THEATER3) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + + theApp.m_loading->InitTMPs(&dlg.m_Progress); + theApp.m_loading->cur_theat = 'N'; + } + else if (yuri_mode && m_mapfile.sections["Map"].values["Theater"] == THEATER4) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + + + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + theApp.m_loading->InitTMPs(&dlg.m_Progress); + theApp.m_loading->cur_theat = 'L'; + } + else if (m_mapfile.sections["Map"].values["Theater"] == THEATER5) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + + theApp.m_loading->InitTMPs(&dlg.m_Progress); + theApp.m_loading->cur_theat = 'D'; + } + else + { + theApp.m_loading->FreeAll(); + CString s = "Fatal error! %9 doesn´t support the theater of this map!"; + s = TranslateStringACP(s); + MessageBox(0, s, "Error", 0); + exit(0); + } + dlg.DestroyWindow(); + + + + CalcMapRect(); + + isInitialized = TRUE; + + errstream << "LoadMap() allocates fielddata\n"; + errstream.flush(); + + fielddata = new(FIELDDATA[(GetIsoSize() + 1) * (GetIsoSize() + 1)]); + fielddata_size = (GetIsoSize() + 1) * (GetIsoSize() + 1); + + errstream << "LoadMap() unpacks data\n"; + errstream.flush(); + + + + Unpack(); + + errstream << "LoadMap() updates from ini\n"; + errstream.flush(); + + + UpdateIniFile(MAPDATA_UPDATE_FROM_INI); + +} + + + + +void CMapData::Unpack() +{ + if (!isInitialized) return; + + CMapLoadingDlg d; + d.ShowWindow(SW_SHOW); + d.UpdateWindow(); + + CString ovrl; + int i; + + + ovrl = ""; + + for (i = 0;i < m_mapfile.sections["OverlayPack"].values.size();i++) + { + ovrl += *m_mapfile.sections["OverlayPack"].GetValue(i); + } + + //BYTE values[262144]; + const size_t VALUESIZE = 262144; + std::vector<BYTE> values(VALUESIZE, 0xFF); + int hexlen; + + + if (ovrl.GetLength() > 0) + { + std::vector<BYTE> hex; + hexlen = FSunPackLib::DecodeBase64(ovrl, hex); + FSunPackLib::DecodeF80(hex.data(), hexlen, values, VALUESIZE); + values.resize(VALUESIZE, 0xFF); // fill rest + } + + memcpy(m_Overlay, values.data(), std::min(VALUESIZE, values.size())); + + ovrl = ""; + + for (i = 0;i < m_mapfile.sections["OverlayDataPack"].values.size();i++) + { + ovrl += *m_mapfile.sections["OverlayDataPack"].GetValue(i); + } + + values.assign(VALUESIZE, 0); + if (ovrl.GetLength() > 0) + { + std::vector<BYTE> hex; + + hexlen = FSunPackLib::DecodeBase64(ovrl, hex); + FSunPackLib::DecodeF80(hex.data(), hexlen, values, VALUESIZE); + values.resize(VALUESIZE, 0xFF); // fill rest + } + + memcpy(m_OverlayData, values.data(), std::min(VALUESIZE, values.size())); + + + CString IsoMapPck; + int len_needed = 0; + + CIniFileSection& sec = m_mapfile.sections["IsoMapPack5"]; + int lines = sec.values.size(); + + /*char c[50]; + itoa(m_mapfile.sections["IsoMapPack5"].values.size(), c, 10); + MessageBox(0,c,"",0);*/ + + for (i = 0;i < lines;i++) + { + len_needed += sec.GetValue(i)->GetLength(); + } + + LPSTR lpMapPack = new(char[len_needed + 1]); + memset(lpMapPack, 0, len_needed + 1); + + int cur_pos = 0; + for (i = 0;i < lines;i++) + { + memcpy(lpMapPack + cur_pos, (LPCSTR)*sec.GetValue(i), sec.GetValue(i)->GetLength()); + cur_pos += sec.GetValue(i)->GetLength(); + DoEvents(); + + //IsoMapPck+=*sec.GetValue(i); + } + + IsoMapPck = lpMapPack; + + delete[] lpMapPack; + + + if (m_mfd != NULL) delete[] m_mfd; + m_mfd = NULL; + dwIsoMapSize = 0; + + if (IsoMapPck.GetLength() > 0) + { + std::vector<BYTE> hexC; + + //DoEvents(); + + hexlen = FSunPackLib::DecodeBase64(IsoMapPck, hexC); + + // first let´s find out the size of the mappack data + const auto hex = hexC.data(); + int SP = 0; + int MapSizeBytes = 0; + int sec = 0; + while (SP < hexlen) + { + WORD wSrcSize; + WORD wDestSize; + memcpy(&wSrcSize, hex + SP, 2); + SP += 2; + memcpy(&wDestSize, hex + SP, 2); + SP += 2; + + MapSizeBytes += wDestSize; + SP += wSrcSize; + + sec++; + } + + m_mfd = new(BYTE[MapSizeBytes]); + dwIsoMapSize = MapSizeBytes / MAPFIELDDATA_SIZE; + + FSunPackLib::DecodeIsoMapPack5(hex, hexlen, (BYTE*)m_mfd, d.m_Progress.m_hWnd, TRUE); + + int k; + /*fstream f; + f.open("C:\\isomappack5.txt",ios_base::in | ios_base::out | ios_base::trunc); + for(k=0;k<150;k++) + { + f << "Byte " << k << ": " << (int)m_mfd[k] << endl; + } + f.flush();*/ + } + + d.DestroyWindow(); + +} + + + + + + +void CMapData::Pack(BOOL bCreatePreview, BOOL bCompression) +{ + if (!isInitialized) return; + + errstream << "Erasing sections" << endl; + errstream.flush(); + + int i; + BYTE* base64 = NULL; // must be freed! + + m_mapfile.sections.erase("OverlayPack"); + m_mapfile.sections.erase("OverlayDataPack"); + m_mapfile.sections.erase("IsoMapPack5"); // only activate when packing isomappack is supported + + DWORD pos; + + errstream << "Creating Digest" << endl; + errstream.flush(); + + if (m_mapfile.sections["Digest"].values.size() == 0) + { + srand(GetTickCount()); + unsigned short vals[10]; + for (i = 0;i < 10;i++) + vals[i] = rand() * 65536 / RAND_MAX; + + base64 = FSunPackLib::EncodeBase64((BYTE*)vals, 20); + + i = 0; + pos = 0; + while (TRUE) + { + i++; + char cLine[50]; + itoa(i, cLine, 10); + char str[200]; + memset(str, 0, 200); + WORD cpysize = 70; + if (pos + cpysize > strlen((char*)base64)) cpysize = strlen((char*)base64) - pos; + memcpy(str, &base64[pos], cpysize); + if (strlen(str) > 0) + m_mapfile.sections["Digest"].values[cLine] = str; + if (cpysize < 70) break; + pos += 70; + } + + delete[] base64; + base64 = NULL; + } + + + BYTE* values = new(BYTE[262144]); + BYTE* hexpacked = NULL; // must be freed! + + + errstream << "Values allocated. Pointer: " << (int)values << endl; + errstream.flush(); + + + errstream << "Packing overlay" << endl; + errstream.flush(); + + for (i = 0;i < 262144;i++) + { + values[i] = m_Overlay[i]; + } + + int hexpackedLen = FSunPackLib::EncodeF80(values, 262144, 32, &hexpacked); + base64 = FSunPackLib::EncodeBase64(hexpacked, hexpackedLen); + + + errstream << "Saving overlay" << endl; + + i = 0; + pos = 0; + while (TRUE) + { + i++; + char cLine[50]; + itoa(i, cLine, 10); + char str[200]; + memset(str, 0, 200); + WORD cpysize = 70; + if (pos + cpysize > strlen((char*)base64)) cpysize = strlen((char*)base64) - pos; + memcpy(str, &base64[pos], cpysize); + if (strlen(str) > 0) + m_mapfile.sections["OverlayPack"].values[cLine] = str; + if (cpysize < 70) break; + pos += 70; + } + + + +#ifndef _DEBUG__ + delete[] hexpacked; + delete[] base64; +#endif + + errstream << "Pack overlaydata" << endl; + errstream.flush(); + + for (i = 0;i < 262144;i++) + { + values[i] = m_OverlayData[i]; + } + + hexpacked = NULL; + + errstream << "Format80" << endl; + errstream.flush(); + + hexpackedLen = FSunPackLib::EncodeF80(values, 262144, 32, &hexpacked); + + + errstream << "Base64" << endl; + errstream.flush(); + + base64 = FSunPackLib::EncodeBase64(hexpacked, hexpackedLen); + + + errstream << "Overlaydata done" << endl; + errstream.flush(); + + i = 0; + pos = 0; + while (TRUE) + { + i++; + char cLine[50]; + itoa(i, cLine, 10); + char str[200]; + memset(str, 0, 200); + WORD cpysize = 70; + if (pos + cpysize > strlen((char*)base64)) cpysize = strlen((char*)base64) - pos; + memcpy(str, &base64[pos], cpysize); + if (strlen(str) > 0) + m_mapfile.sections["OverlayDataPack"].values[cLine] = str; + if (cpysize < 70) break; + pos += 70; + } + + +#ifndef _DEBUG__ + delete[] hexpacked; + delete[] base64; +#endif + + hexpacked = NULL; + + errstream << "Pack isomappack" << endl; + errstream.flush(); + + + hexpackedLen = FSunPackLib::EncodeIsoMapPack5(m_mfd, dwIsoMapSize * MAPFIELDDATA_SIZE, &hexpacked); + + + errstream << "done" << endl; + errstream.flush(); + + errstream << "hexdata size: " << hexpackedLen; + errstream << endl << "Now converting to base64"; + errstream.flush(); + base64 = FSunPackLib::EncodeBase64(hexpacked, hexpackedLen); + errstream << "done" << endl; + errstream.flush(); + + i = 0; + pos = 0; + int base64len = strlen((char*)base64); + while (TRUE) + { + i++; + char cLine[50]; + itoa(i, cLine, 10); + char str[200]; + memset(str, 0, 200); + int cpysize = 70; + if (pos + cpysize > base64len) cpysize = base64len - pos; + memcpy(str, &base64[pos], cpysize); + if (cpysize) + m_mapfile.sections["IsoMapPack5"].values[cLine] = str; + + if (cpysize < 70) break; + pos += 70; + } + + errstream << "finished copying into inifile" << endl; + errstream.flush(); + + +#ifndef _DEBUG__ + delete[] hexpacked; + delete[] base64; +#endif + + + // create minimap + if (bCreatePreview) + { + BITMAPINFO biinfo; + BYTE* lpDibData; + int pitch; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_minimap.DrawMinimap(&lpDibData, biinfo, pitch); + + m_mapfile.sections.erase("PreviewPack"); + m_mapfile.sections["Preview"].values["Size"] = m_mapfile.sections["Map"].values["Size"]; + char c[50]; + itoa(biinfo.bmiHeader.biWidth, c, 10); + m_mapfile.sections["Preview"].values["Size"] = SetParam(m_mapfile.sections["Preview"].values["Size"], 2, c); + itoa(biinfo.bmiHeader.biHeight, c, 10); + m_mapfile.sections["Preview"].values["Size"] = SetParam(m_mapfile.sections["Preview"].values["Size"], 3, c); + + BYTE* lpRAW = new(BYTE[biinfo.bmiHeader.biWidth * biinfo.bmiHeader.biHeight * 3]); + + int mapwidth = GetWidth(); + int mapheight = GetHeight(); + int e; + for (i = 0;i < biinfo.bmiHeader.biWidth;i++) + { + for (e = 0;e < biinfo.bmiHeader.biHeight;e++) + { + int dest = i * 3 + e * biinfo.bmiHeader.biWidth * 3; + int src = i * 3 + (biinfo.bmiHeader.biHeight - e - 1) * pitch; + memcpy(&lpRAW[dest + 2], &lpDibData[src + 0], 1); + memcpy(&lpRAW[dest + 1], &lpDibData[src + 1], 1); + memcpy(&lpRAW[dest + 0], &lpDibData[src + 2], 1); + } + } + + + hexpacked = NULL; + hexpackedLen = FSunPackLib::EncodeIsoMapPack5(lpRAW, biinfo.bmiHeader.biWidth * biinfo.bmiHeader.biHeight * 3, &hexpacked); + + base64 = FSunPackLib::EncodeBase64(hexpacked, hexpackedLen); + + // uses IsoMapPack5 encoding routine + + + errstream << "Saving minimap" << endl; + + i = 0; + pos = 0; + while (TRUE) + { + i++; + char cLine[50]; + itoa(i, cLine, 10); + char str[200]; + memset(str, 0, 200); + WORD cpysize = 70; + if (pos + cpysize > strlen((char*)base64)) cpysize = strlen((char*)base64) - pos; + memcpy(str, &base64[pos], cpysize); + if (strlen(str) > 0) + m_mapfile.sections["PreviewPack"].values[cLine] = str; + if (cpysize < 70) break; + pos += 70; + } + + + + //#ifndef _DEBUG__ + delete[] base64; + delete[] hexpacked; + //#endif + + + delete[] lpRAW; + //delete[] lpDibData; + } + + delete[] values; +} + +void CMapData::ClearOverlayData() +{ + memset(m_OverlayData, 0x0, 262144); + // Pack(); +} + +void CMapData::ClearOverlay() +{ + memset(m_Overlay, 0xFF, 262144); + // Pack(); +} + +void CMapData::SetOverlayAt(DWORD dwPos, BYTE bValue) +{ + int y = dwPos / m_IsoSize; + int x = dwPos % m_IsoSize; + + if (y + x * 512 > 262144 || dwPos > m_IsoSize * m_IsoSize) return; + + BYTE& ovrl = m_Overlay[y + x * 512]; + BYTE& ovrld = m_OverlayData[y + x * 512]; + + + RemoveOvrlMoney(ovrl, ovrld); + + + m_Overlay[y + x * 512] = bValue; + m_OverlayData[y + x * 512] = 0; + fielddata[dwPos].overlay = bValue; + fielddata[dwPos].overlaydata = 0; + + BYTE& ovrl2 = m_Overlay[y + x * 512]; + BYTE& ovrld2 = m_OverlayData[y + x * 512]; + AddOvrlMoney(ovrl2, ovrld2); + + int i, e; + for (i = -1;i < 2;i++) + for (e = -1;e < 2;e++) + if (i + x > 0 && i + x < m_IsoSize && y + e >= 0 && y + e < m_IsoSize) + SmoothTiberium(dwPos + i + e * m_IsoSize); + + + + + + + + Mini_UpdatePos(x, y, IsMultiplayer()); + +} + +BYTE CMapData::GetOverlayAt(DWORD dwPos) +{ + if (dwPos > fielddata_size) return 0; + return fielddata[dwPos].overlay; +} + +void CMapData::SetOverlayDataAt(DWORD dwPos, BYTE bValue) +{ + + int y = dwPos / m_IsoSize; + int x = dwPos % m_IsoSize; + + if (y + x * 512 > 262144 || dwPos > m_IsoSize * m_IsoSize) return; + + BYTE& ovrl = m_Overlay[y + x * 512]; + BYTE& ovrld = m_OverlayData[y + x * 512]; + + if (ovrl >= RIPARIUS_BEGIN && ovrl <= RIPARIUS_END) + { + //m_money-=(ovrld+1)*(atoi(rules.sections["Riparius"].values["Value"])); + return; + } + + if (ovrl >= CRUENTUS_BEGIN && ovrl <= CRUENTUS_END) + { + //m_money-=(ovrld+1)*(atoi(rules.sections["Cruentus"].values["Value"])); + return; + } + + if (ovrl >= VINIFERA_BEGIN && ovrl <= VINIFERA_END) + { + //m_money-=(ovrld+1)*(atoi(rules.sections["Vinifera"].values["Value"])); + return; + } + + if (ovrl >= ABOREUS_BEGIN && ovrl <= ABOREUS_END) + { + //m_money-=(ovrld+1)*(atoi(rules.sections["Aboreus"].values["Value"])); + return; + } + + m_OverlayData[y + x * 512] = bValue; + fielddata[dwPos].overlaydata = bValue; + + BYTE& ovrl2 = m_Overlay[y + x * 512]; + BYTE& ovrld2 = m_OverlayData[y + x * 512]; + + + /*if(ovrl2>=RIPARIUS_BEGIN && ovrl2<=RIPARIUS_END) + { + m_money+=(ovrld2+1)*(atoi(rules.sections["Riparius"].values["Value"])); + } + + if(ovrl2>=CRUENTUS_BEGIN && ovrl2<=CRUENTUS_END) + { + m_money+=(ovrld2+1)*(atoi(rules.sections["Cruentus"].values["Value"])); + } + + if(ovrl2>=VINIFERA_BEGIN && ovrl2<=VINIFERA_END) + { + m_money+=(ovrld2+1)*(atoi(rules.sections["Vinifera"].values["Value"])); + } + + if(ovrl2>=ABOREUS_BEGIN && ovrl2<=ABOREUS_END) + { + m_money+=(ovrld2+1)*(atoi(rules.sections["Aboreus"].values["Value"])); + }*/ + + +} + +BYTE CMapData::GetOverlayDataAt(DWORD dwPos) +{ + return fielddata[dwPos].overlaydata; +} + +/* +UpdateInfantry(); + +Updates the tiledata if bSave==FALSE (standard) according to the mapfile. +If bSave==TRUE, nothing is done at the moment (would be for updating the mapfile, but not needed yet, + because the mapfile is modified directly) +*/ +void CMapData::UpdateInfantry(BOOL bSave) +{ + vector<INFANTRY>& iv = m_infantry; + + if (bSave == FALSE) + { + iv.clear(); + iv.reserve(100); + + int i; + for (i = 0;i < GetIsoSize() * GetIsoSize();i++) + { + int e; + for (e = 0;e < SUBPOS_COUNT;e++) + fielddata[i].infantry[e] = -1; + } + + + if (m_mapfile.sections.find("Infantry") != m_mapfile.sections.end()) + { + CIniFileSection& sec = m_mapfile.sections["Infantry"]; + + for (i = 0;i < sec.values.size();i++) + { + CString data = *sec.GetValue(i); + + int x = atoi(GetParam(data, 4)); + int y = atoi(GetParam(data, 3)); + int sp = atoi(GetParam(data, 5)); + int pos = x + y * GetIsoSize(); + + INFANTRY id; + id.deleted = 0; + id.house = GetParam(data, 0); + id.type = GetParam(data, 1); + id.strength = GetParam(data, 2); + id.y = GetParam(data, 3); + id.x = GetParam(data, 4); + id.pos = GetParam(data, 5); + id.action = GetParam(data, 6); + id.direction = GetParam(data, 7); + id.tag = GetParam(data, 8); + id.flag1 = GetParam(data, 9); + id.flag2 = GetParam(data, 10); + id.flag3 = GetParam(data, 11); + id.flag4 = GetParam(data, 12); + id.flag5 = GetParam(data, 13); + + iv.push_back(id); + + int spp = sp - 1; + if (spp < 0) spp = 0; + + if (spp < SUBPOS_COUNT) + if (pos < fielddata_size) + fielddata[pos].infantry[spp] = iv.size() - 1; + + Mini_UpdatePos(x, y, IsMultiplayer()); + + + + /*else + { + int e; + for(e=0;e<SUBPOS_COUNT;e++) + { + if(fielddata[pos].infantry[e]<0) + { + fielddata[pos].infantry[e]=i; + break; + } + } + }*/ + } + } + } + else + { + m_mapfile.sections.erase("Infantry"); + int i; + + int count = 0; + for (i = 0;i < iv.size();i++) + { + INFANTRY& id = iv[i]; + if (!id.deleted) + { + INFANTRY& infantry = id; + + CString value; + value = infantry.house + "," + infantry.type + "," + infantry.strength + "," + infantry.y + + "," + infantry.x + "," + infantry.pos + "," + infantry.action + "," + infantry.direction + "," + + infantry.tag + "," + infantry.flag1 + "," + infantry.flag2 + "," + infantry.flag3 + "," + + infantry.flag4 + "," + infantry.flag5; + + char c[50]; + itoa(count, c, 10); + + m_mapfile.sections["Infantry"].values[c] = value; + + count++; + } + } + + } +} + +void CMapData::UpdateAircraft(BOOL bSave) +{ + if (bSave == FALSE) + { + int i; + for (i = 0;i < GetIsoSize() * GetIsoSize();i++) + { + fielddata[i].aircraft = -1; + } + + + if (m_mapfile.sections.find("Aircraft") != m_mapfile.sections.end()) + { + CIniFileSection& sec = m_mapfile.sections["Aircraft"]; + + for (i = 0;i < sec.values.size();i++) + { + int x = atoi(GetParam(*sec.GetValue(i), 4)); + int y = atoi(GetParam(*sec.GetValue(i), 3)); + int pos = x + y * GetIsoSize(); + if (pos < fielddata_size) fielddata[pos].aircraft = i; + + Mini_UpdatePos(x, y, IsMultiplayer()); + } + } + } +} + +void CMapData::UpdateStructures(BOOL bSave) +{ + if (bSave == FALSE) + { + int i; + for (i = 0;i < GetIsoSize() * GetIsoSize();i++) + { + fielddata[i].structure = -1; + fielddata[i].structuretype = -1; + } + + m_structurepaint.clear(); + + if (m_mapfile.sections.find("Structures") != m_mapfile.sections.end()) + { + CIniFileSection& sec = m_mapfile.sections["Structures"]; + + for (i = 0;i < sec.values.size();i++) + { + STRUCTUREPAINT sp; + sp.col = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->GetColor(GetParam(*sec.GetValue(i), 0)); + sp.strength = atoi(GetParam(*sec.GetValue(i), 2)); + sp.upgrade1 = GetParam(*sec.GetValue(i), 12); + sp.upgrade2 = GetParam(*sec.GetValue(i), 13); + sp.upgrade3 = GetParam(*sec.GetValue(i), 14); + sp.upradecount = atoi(GetParam(*sec.GetValue(i), 10)); + sp.x = atoi(GetParam(*sec.GetValue(i), 4)); + sp.y = atoi(GetParam(*sec.GetValue(i), 3)); + sp.direction = atoi(GetParam(*sec.GetValue(i), 5)); + sp.type = GetParam(*sec.GetValue(i), 1); + + TruncSpace(sp.upgrade1); + TruncSpace(sp.upgrade2); + TruncSpace(sp.upgrade3); + + m_structurepaint.push_back(sp); + + int x = atoi(GetParam(*sec.GetValue(i), 4)); + int y = atoi(GetParam(*sec.GetValue(i), 3)); + int d, e; + int bid = buildingid[GetParam(*sec.GetValue(i), 1)]; + for (d = 0;d < buildinginfo[bid].h;d++) + { + for (e = 0;e < buildinginfo[bid].w;e++) + { + int pos = (x + d) + (y + e) * GetIsoSize(); + if (pos < fielddata_size) + { + fielddata[pos].structure = i; + fielddata[pos].structuretype = bid; + } + + Mini_UpdatePos(x + d, y + e, IsMultiplayer()); + } + } + + + } + } + } +} + +void CMapData::UpdateTerrain(BOOL bSave, int num) +{ + vector<TERRAIN>& t = m_terrain; + + if (bSave == FALSE) + { + if (m_mapfile.sections.find("Terrain") == m_mapfile.sections.end() || m_mapfile.sections["Terrain"].values.size() <= 0) + return; + + if (num < 0) + { + t.clear(); + t.reserve(100); + + int i; + for (i = 0;i < GetIsoSize() * GetIsoSize();i++) + { + fielddata[i].terrain = -1; + } + + + + CIniFileSection& sec = m_mapfile.sections["Terrain"]; + + for (i = 0;i < sec.values.size();i++) + { + int x, y; + PosToXY(*sec.GetValueName(i), &x, &y); + + // check for valid coordinates ; MW May 17th 2001 + ASSERT(x >= 0 && x < GetIsoSize()); + ASSERT(y >= 0 && y < GetIsoSize()); + if (x < 0 || x >= GetIsoSize() || y < 0 || y >= GetIsoSize()) + { + // invalid coordinates - ignore in release + } + else + { + TERRAIN td; + td.deleted = 0; + td.type = *sec.GetValue(i); + td.x = x; + td.y = y; + + t.push_back(td); + + int pos = x + y * GetIsoSize(); + fielddata[pos].terrain = i; + fielddata[pos].terraintype = terrainid[td.type]; + } + } + + m_mapfile.sections.erase("Terrain"); + + } + + } + else + { + + //if(num<0) + { + //if(m_mapfile.sections.find("Terrain")!=m_mapfile.sections.end()) MessageBox(0,"Reupdate!","",0); + m_mapfile.sections.erase("Terrain"); + int i; + + for (i = 0;i < t.size();i++) + { + TERRAIN& td = t[i]; + if (!td.deleted) + { + char j1[15]; + char k1[15]; + + int x, y; + x = td.x; + y = td.y; + + itoa(y, j1, 10); + if (strlen(j1) < 3) + { + strcpy_safe(j1 + 1, j1); + j1[0] = '0'; + } + if (strlen(j1) < 3) + { + strcpy_safe(j1 + 1, j1); + j1[0] = '0'; + } + itoa(x, k1, 10); + strcat(k1, j1); + + + m_mapfile.sections["Terrain"].values[k1] = td.type; + } + } + } + + } +} + +void CMapData::UpdateUnits(BOOL bSave) +{ + if (bSave == FALSE) + { + int i; + for (i = 0;i < GetIsoSize() * GetIsoSize();i++) + { + fielddata[i].unit = -1; + } + + + if (m_mapfile.sections.find("Units") != m_mapfile.sections.end()) + { + CIniFileSection& sec = m_mapfile.sections["Units"]; + + for (i = 0;i < sec.values.size();i++) + { + int x = atoi(GetParam(*sec.GetValue(i), 4)); + int y = atoi(GetParam(*sec.GetValue(i), 3)); + int pos = x + y * GetIsoSize(); + if (pos < fielddata_size) fielddata[pos].unit = i; + + Mini_UpdatePos(x, y, IsMultiplayer()); + } + } + } + +} + +void CMapData::UpdateWaypoints(BOOL bSave) +{ + if (bSave == FALSE) + { + int i; + for (i = 0;i < GetIsoSize() * GetIsoSize();i++) + { + fielddata[i].waypoint = -1; + } + + + if (m_mapfile.sections.find("Waypoints") != m_mapfile.sections.end()) + { + CIniFileSection& sec = m_mapfile.sections["Waypoints"]; + + for (i = 0;i < sec.values.size();i++) + { + int x, y; + PosToXY(*sec.GetValue(i), &x, &y); + + int pos = x + y * GetIsoSize(); + if (pos < 0 || pos >= fielddata_size) continue; + fielddata[pos].waypoint = i; + + int k, l; + for (k = -1;k < 2;k++) + for (l = -1;l < 2;l++) + Mini_UpdatePos(x + k, y + l, IsMultiplayer()); + } + } + } + +} + +void CMapData::UpdateNodes(BOOL bSave) +{ + if (bSave == FALSE) + { + int i; + + for (i = 0;i < GetIsoSize() * GetIsoSize();i++) + { + fielddata[i].node.index = -1; + fielddata[i].node.type = -1; + fielddata[i].node.house = ""; + } + + if (m_mapfile.sections.find(MAPHOUSES) != m_mapfile.sections.end()) + { + + for (i = 0;i < m_mapfile.sections[MAPHOUSES].values.size();i++) + { + CIniFileSection& sec = m_mapfile.sections[*m_mapfile.sections[MAPHOUSES].GetValue(i)]; + int c = atoi(sec.values["NodeCount"]); + + int e; + for (e = 0;e < c;e++) + { + CString p; + GetNodeName(p, e); + + CString type, sx, sy; + type = GetParam(sec.values[p], 0); + sy = GetParam(sec.values[p], 1); + sx = GetParam(sec.values[p], 2); + + int x = atoi(sx); + int y = atoi(sy); + int bid = buildingid[type]; + int d, f; + for (d = 0;d < buildinginfo[bid].h;d++) + { + for (f = 0;f < buildinginfo[bid].w;f++) + { + int pos = x + d + (y + f) * GetIsoSize(); + fielddata[pos].node.type = buildingid[type]; + fielddata[pos].node.house = *m_mapfile.sections[MAPHOUSES].GetValue(i); + fielddata[pos].node.index = e; + } + } + } + } + } + } + +} + +void CMapData::UpdateOverlay(BOOL bSave) +{ + if (bSave == FALSE) + { + int u, v; + const bool mp = IsMultiplayer(); + for (u = 0;u < GetIsoSize();u++) + { + for (v = 0;v < GetIsoSize();v++) + { + fielddata[u + v * GetIsoSize()].overlay = m_Overlay[v + u * 512]; + fielddata[u + v * GetIsoSize()].overlaydata = m_OverlayData[v + u * 512]; + + Mini_UpdatePos(u, v, mp); + + } + } + } + else + { + int u, v; + for (u = 0;u < GetIsoSize();u++) + { + for (v = 0;v < GetIsoSize();v++) + { + m_Overlay[v + u * 512] = fielddata[u + v * GetIsoSize()].overlay; + m_OverlayData[v + u * 512] = fielddata[u + v * GetIsoSize()].overlaydata; + } + } + } + + m_money = CalcMoneyOnMap(); + +} + + +void CMapData::UpdateCelltags(BOOL bSave) +{ + if (bSave == FALSE) + { + int i; + for (i = 0;i < GetIsoSize() * GetIsoSize();i++) + { + fielddata[i].celltag = -1; + } + + + if (m_mapfile.sections.find("CellTags") != m_mapfile.sections.end()) + { + CIniFileSection& sec = m_mapfile.sections["CellTags"]; + + for (i = 0;i < sec.values.size();i++) + { + int x, y; + PosToXY(*sec.GetValueName(i), &x, &y); + + int pos = x + y * GetIsoSize(); + if (pos < fielddata_size) fielddata[pos].celltag = i; + } + } + } +} + + +INT CMapData::GetNodeAt(DWORD dwPos, CString& lpHouse) const +{ + lpHouse = fielddata[dwPos].node.house; + return fielddata[dwPos].node.index; +} + + + +void CMapData::DeleteInfantry(DWORD dwIndex) +{ + //if(dwIndex>=m_infantry.size()) MessageBox(0,"CMapData::DeleteInfantry(): Out of range error", "Error", 0); + + if (dwIndex >= m_infantry.size()) return; + + // BUG TRACING HERE, FOR THE COPY INSTEAD MOVE INFANTRY BUG! + // SOLUTION WAS IN ADDINFANTRY(); + if (m_infantry[dwIndex].deleted) + { + //MessageBox(0,"CMapData::DeleteInfantry() called for infantry that already got deleted!", "Error",0); + errstream << "CMapData::DeleteInfantry() called for infantry that already got deleted! Index: " << dwIndex << endl; + errstream.flush(); + } + + if (m_infantry[dwIndex].deleted) return; + + + + m_infantry[dwIndex].deleted = 1; + + int x = atoi(m_infantry[dwIndex].x); + int y = atoi(m_infantry[dwIndex].y); + int pos = atoi(m_infantry[dwIndex].pos); + + if (pos > 0) pos--; + + if (x + y * m_IsoSize < fielddata_size) fielddata[x + y * m_IsoSize].infantry[pos] = -1; + + Mini_UpdatePos(x, y, IsMultiplayer()); + + /*if(dwIndex>=m_mapfile.sections["Infantry"].values.size()) return; + + CIniFileSection& sec=m_mapfile.sections["Infantry"]; + int x=atoi(GetParam(*sec.GetValue(dwIndex),4)); + int y=atoi(GetParam(*sec.GetValue(dwIndex),3)); + + + m_mapfile.sections["Infantry"].values.erase(*m_mapfile.sections["Infantry"].GetValueName(dwIndex)); + UpdateInfantry(FALSE);*/ + + +} + +void CMapData::DeleteWaypoint(DWORD dwIndex) +{ + if (dwIndex >= GetWaypointCount()) return; + + CString id; + DWORD pos; + Map->GetWaypointData(dwIndex, &id, &pos); + + int x = pos % m_IsoSize; + int y = pos / m_IsoSize; + + + + m_mapfile.sections["Waypoints"].values.erase(*m_mapfile.sections["Waypoints"].GetValueName(dwIndex)); + if (!m_noAutoObjectUpdate) UpdateWaypoints(FALSE); + + int k, l; + for (k = -1;k < 2;k++) + for (l = -1;l < 2;l++) + Mini_UpdatePos(x + k, y + l, IsMultiplayer()); +} + +void CMapData::DeleteCelltag(DWORD dwIndex) +{ + if (dwIndex >= GetCelltagCount()) return; + + m_mapfile.sections["CellTags"].values.erase(*m_mapfile.sections["CellTags"].GetValueName(dwIndex)); + if (!m_noAutoObjectUpdate) UpdateCelltags(FALSE); +} + +void CMapData::DeleteUnit(DWORD dwIndex) +{ + if (dwIndex >= GetUnitCount()) return; + + CIniFileSection& sec = m_mapfile.sections["Units"]; + int x = atoi(GetParam(*sec.GetValue(dwIndex), 4)); + int y = atoi(GetParam(*sec.GetValue(dwIndex), 3)); + + + m_mapfile.sections["Units"].values.erase(*m_mapfile.sections["Units"].GetValueName(dwIndex)); + if (!m_noAutoObjectUpdate) UpdateUnits(FALSE); + + Mini_UpdatePos(x, y, IsMultiplayer()); +} + +void CMapData::DeleteStructure(DWORD dwIndex) +{ + if (dwIndex >= GetStructureCount()) return; + + CIniFileSection& sec = m_mapfile.sections["Structures"]; + int x = atoi(GetParam(*sec.GetValue(dwIndex), 4)); + int y = atoi(GetParam(*sec.GetValue(dwIndex), 3)); + CString type = GetParam(*sec.GetValue(dwIndex), 1); + + m_mapfile.sections["Structures"].values.erase(*m_mapfile.sections["Structures"].GetValueName(dwIndex)); + if (!m_noAutoObjectUpdate) UpdateStructures(FALSE); + + int d, e; + int bid = buildingid[type]; + for (d = 0;d < buildinginfo[bid].h;d++) + { + for (e = 0;e < buildinginfo[bid].w;e++) + { + int pos = (x + d) + (y + e) * GetIsoSize(); + + Mini_UpdatePos(x + d, y + e, IsMultiplayer()); + } + } +} + +void CMapData::DeleteAircraft(DWORD dwIndex) +{ + if (dwIndex >= GetAircraftCount()) return; + + CIniFileSection& sec = m_mapfile.sections["Aircraft"]; + int x = atoi(GetParam(*sec.GetValue(dwIndex), 4)); + int y = atoi(GetParam(*sec.GetValue(dwIndex), 3)); + + + m_mapfile.sections["Aircraft"].values.erase(*m_mapfile.sections["Aircraft"].GetValueName(dwIndex)); + if (!m_noAutoObjectUpdate) UpdateAircraft(FALSE); + + Mini_UpdatePos(x, y, IsMultiplayer()); +} + +void CMapData::DeleteTerrain(DWORD dwIndex) +{ + /* March 23th 2001: MW: Rewrote code, much faster */ + if (dwIndex >= GetTerrainCount()) return; + if (m_terrain[dwIndex].deleted) return; + + //UpdateTerrain(FALSE); + // replacement of slow UpdateTerrain(): + + //CString valuename=*m_mapfile.sections["Terrain"].GetValueName(dwIndex); + + int x, y; + //PosToXY(valuename, &x, &y); + //m_mapfile.sections["Terrain"].values.erase(valuename); + x = m_terrain[dwIndex].x; + y = m_terrain[dwIndex].y; + m_terrain[dwIndex].deleted = 1; + + int pos = x + y * GetIsoSize(); + if (x + y * m_IsoSize < fielddata_size) + { + fielddata[pos].terrain = -1; + fielddata[pos].terraintype = -1; + } + +} + +void CMapData::DeleteNode(LPCTSTR lpHouse, DWORD dwIndex) +{ + CString p; // p is last node + GetNodeName(p, atoi(m_mapfile.sections[lpHouse].values["NodeCount"]) - 1); + + char c[50]; + itoa(atoi(m_mapfile.sections[lpHouse].values["NodeCount"]) - 1, c, 10); + + int i; + for (i = dwIndex;i < atoi(m_mapfile.sections[lpHouse].values["NodeCount"]) - 1;i++) + { + CString d1, d2; + GetNodeName(d1, i); + GetNodeName(d2, i + 1); + m_mapfile.sections[lpHouse].values[d1] = m_mapfile.sections[lpHouse].values[d2]; + } + + m_mapfile.sections[lpHouse].values.erase(p); + m_mapfile.sections[lpHouse].values["NodeCount"] = c; + + UpdateNodes(FALSE); +} + +BOOL CMapData::AddWaypoint(CString lpID, DWORD dwPos) +{ + // create waypoint, auto number + CString id = lpID; + + + if (lpID.GetLength() == 0) id = GetFree("Waypoints"); + + + char j[15]; + char k[15]; + memset(j, 0, 15); + memset(k, 0, 15); + itoa(dwPos / GetIsoSize(), j, 10); + if (strlen(j) < 3) + { + strcpy_safe(j + 1, j); + j[0] = '0'; + } + if (strlen(j) < 3) + { + strcpy_safe(j + 1, j); + j[0] = '0'; + } + itoa(dwPos % GetIsoSize(), k, 10); + strcat(k, j); + + //MessageBox(0,k,"",0); + + + m_mapfile.sections["Waypoints"].values[id] = k; + if (!m_noAutoObjectUpdate) UpdateWaypoints(FALSE); + + return TRUE; +} + + + +void CMapData::GetStructureData(DWORD dwIndex, STRUCTURE* lpStructure) const +{ + const auto section = m_mapfile.GetSection("Structures"); + if (!section || dwIndex >= section->values.size()) + return; + + CString data = *section->GetValue(dwIndex); + + lpStructure->house = GetParam(data, 0); + lpStructure->type = GetParam(data, 1); + lpStructure->strength = GetParam(data, 2); + lpStructure->y = GetParam(data, 3); + lpStructure->x = GetParam(data, 4); + lpStructure->direction = GetParam(data, 5); + lpStructure->tag = GetParam(data, 6); + lpStructure->flag1 = GetParam(data, 7); + lpStructure->flag2 = GetParam(data, 8); + lpStructure->energy = GetParam(data, 9); + lpStructure->upgradecount = GetParam(data, 10); + lpStructure->spotlight = GetParam(data, 11); + lpStructure->upgrade1 = GetParam(data, 12); + lpStructure->upgrade2 = GetParam(data, 13); + lpStructure->upgrade3 = GetParam(data, 14); + lpStructure->flag3 = GetParam(data, 15); + lpStructure->flag4 = GetParam(data, 16); + +} + +void CMapData::GetStdStructureData(DWORD dwIndex, STDOBJECTDATA* lpStdStructure) const +{ + const auto section = m_mapfile.GetSection("Structures"); + if (!section || dwIndex >= section->values.size()) + return; + + CString data = *section->GetValue(dwIndex); + + lpStdStructure->house = GetParam(data, 0); + lpStdStructure->type = GetParam(data, 1); + lpStdStructure->strength = GetParam(data, 2); + lpStdStructure->y = GetParam(data, 3); + lpStdStructure->x = GetParam(data, 4); +} + +BOOL CMapData::AddNode(NODE* lpNode, WORD dwPos) +{ + NODE node; + if (lpNode != NULL) + { + node = *lpNode; + } + else + { + node.x.Format("%d", dwPos % Map->GetIsoSize()); + node.y.Format("%d", dwPos / Map->GetIsoSize()); + node.house = GetHouseID(0); + node.type = *rules.sections["BuildingTypes"].GetValue(0); + } + + if (m_mapfile.sections.find(HOUSES) == m_mapfile.sections.end() || m_mapfile.sections[HOUSES].values.size() == 0) + { + return FALSE; + } + + + int c = atoi(m_mapfile.sections[(LPCTSTR)node.house].values["NodeCount"]); + + c++; + char sc[50]; + itoa(c, sc, 10); + m_mapfile.sections[(LPCTSTR)node.house].values["NodeCount"] = sc; + + c--; + CString p; + GetNodeName(p, c); + + + m_mapfile.sections[(LPCTSTR)node.house].values[p] = node.type; + m_mapfile.sections[(LPCTSTR)node.house].values[p] += ","; + m_mapfile.sections[(LPCTSTR)node.house].values[p] += node.y; + m_mapfile.sections[(LPCTSTR)node.house].values[p] += ","; + m_mapfile.sections[(LPCTSTR)node.house].values[p] += node.x; + + UpdateNodes(FALSE); + + return TRUE; +} + +BOOL CMapData::AddInfantry(INFANTRY* lpInfantry, LPCTSTR lpType, LPCTSTR lpHouse, DWORD dwPos, int suggestedIndex) +{ + + INFANTRY infantry; + if (lpInfantry != NULL) + { + infantry = *lpInfantry; + dwPos = atoi(infantry.x) + atoi(infantry.y) * Map->GetIsoSize(); + + // MW Bugfix: not checking if infantry.pos does already exist caused crashes with user scripts! + if (GetInfantryAt(dwPos, atoi(infantry.pos)) >= 0) + infantry.pos = "-1"; + } + else + { + char cx[10], cy[10]; + itoa(dwPos % Map->GetIsoSize(), cx, 10); + itoa(dwPos / Map->GetIsoSize(), cy, 10); + + + + infantry.action = "Guard"; + infantry.tag = "None"; + infantry.direction = "64"; + infantry.flag1 = "0"; + infantry.flag2 = "-1"; + infantry.flag3 = "0"; + infantry.flag4 = "1"; + infantry.flag5 = "0"; + infantry.strength = "256"; + infantry.house = lpHouse; + infantry.pos = "-1"; + infantry.type = lpType; + infantry.x = cx; + infantry.y = cy; + + + } + + if (infantry.pos == "-1") + { + int subpos = -1; + int i; + + if (GetInfantryCountAt(dwPos) == 0) + subpos = 0; + else + { + int oldInf = GetInfantryAt(dwPos, 0); + if (oldInf > -1) + { + INFANTRY inf; + GetInfantryData(oldInf, &inf); + + if (inf.pos == "0") + for (i = 1;i < SUBPOS_COUNT;i++) + { + if (GetInfantryAt(dwPos, i) == -1) + { + //subpos=i+1; + + char c[50]; + itoa(i, c, 10); + inf.pos = c; + DeleteInfantry(oldInf); + AddInfantry(&inf); + break; + } + + } + } + + // if(GetInfantryAt(dwPos, 0)==oldInf) return FALSE; + + for (i = 0;i < SUBPOS_COUNT;i++) + { + if (GetInfantryAt(dwPos, i) == -1) + { + subpos = i + 1; + break; + } + } + } + + if (subpos < 0) return FALSE; + char c[50]; + itoa(subpos, c, 10); + + infantry.pos = c; + } + + + + /* + CString id=GetFree("Infantry"); + + CString value; + value=infantry.house+","+infantry.type+","+infantry.strength+","+infantry.y+ + ","+infantry.x+","+infantry.pos+","+infantry.action+","+infantry.direction+","+ + infantry.tag+","+infantry.flag1+","+infantry.flag2+","+infantry.flag3+","+ + infantry.flag4+","+infantry.flag5; + + m_mapfile.sections["Infantry"].values[id]=(LPCTSTR)value; + + UpdateInfantry(FALSE); + */ + + infantry.deleted = 0; + + /* This code just pushed it back to the end, caused some trouble (and used memory) + m_infantry.push_back(infantry); + + int sp=atoi(infantry.pos); + if(sp>0) sp--; + + int pos=dwPos; + fielddata[pos].infantry[sp]=m_infantry.size()-1; + */ + + // below code should be much more compatible to the very old code (the direct ini one) + + int sp = atoi(infantry.pos); + if (sp > 0) sp--; + + int i; + BOOL bFound = FALSE; + if (suggestedIndex >= 0 && suggestedIndex < m_infantry.size()) + { + if (m_infantry[suggestedIndex].deleted) + { + m_infantry[suggestedIndex] = infantry; + if (dwPos < fielddata_size) fielddata[dwPos].infantry[sp] = suggestedIndex; + bFound = TRUE; + + } + } + + if (!bFound) + for (i = 0;i < m_infantry.size();i++) + { + if (m_infantry[i].deleted) // yep, found one, replace it + { + m_infantry[i] = infantry; + if (dwPos < fielddata_size) fielddata[dwPos].infantry[sp] = i; + bFound = TRUE; + break; + } + } + + if (!bFound) + { + m_infantry.push_back(infantry); + if (dwPos < fielddata_size) fielddata[dwPos].infantry[sp] = m_infantry.size() - 1; + } + + + return TRUE; +} + +BOOL CMapData::AddStructure(STRUCTURE* lpStructure, LPCTSTR lpType, LPCTSTR lpHouse, DWORD dwPos, CString suggestedID) +{ + STRUCTURE structure; + if (lpStructure != NULL) + { + structure = *lpStructure; + } + else + { + char cx[10], cy[10]; + itoa(dwPos % Map->GetIsoSize(), cx, 10); + itoa(dwPos / Map->GetIsoSize(), cy, 10); + + structure.tag = "None"; + structure.direction = "64"; + structure.flag1 = "1"; + structure.flag2 = "0"; + structure.spotlight = "0"; + structure.flag3 = "0"; + structure.flag4 = "0"; + structure.energy = "1"; + structure.upgrade1 = "None"; + structure.upgrade2 = "None"; + structure.upgrade3 = "None"; + structure.upgradecount = "0"; + structure.strength = "256"; + structure.house = lpHouse; + structure.type = lpType; + structure.x = cx; + structure.y = cy; + + + } + + + CString id = GetFree("Structures"); + + if (suggestedID.GetLength() > 0) + { + if (m_mapfile.sections["Structures"].values.find(suggestedID) == m_mapfile.sections["Structures"].values.end()) + id = suggestedID; + } + + CString value; + value = structure.house + "," + structure.type + "," + structure.strength + "," + structure.y + + "," + structure.x + "," + structure.direction + "," + structure.tag + "," + structure.flag1 + "," + + structure.flag2 + "," + structure.energy + "," + structure.upgradecount + "," + structure.spotlight + "," + + structure.upgrade1 + "," + structure.upgrade2 + "," + structure.upgrade3 + "," + structure.flag3 + "," + structure.flag4; + + m_mapfile.sections["Structures"].values[id] = (LPCTSTR)value; + + if (!m_noAutoObjectUpdate) UpdateStructures(FALSE); + + return TRUE; +} + + + +void CMapData::InitializeUnitTypes() +{ + buildingid.clear(); + terrainid.clear(); + + int i; + m_overlayCredits[OverlayCredits_Riparius] = atoi(m_mapfile.GetValueByName("Riparius", "Value", rules.sections["Riparius"].AccessValueByName("Value"))); + m_overlayCredits[OverlayCredits_Cruentus] = atoi(m_mapfile.GetValueByName("Cruentus", "Value", rules.sections["Cruentus"].AccessValueByName("Value"))); + m_overlayCredits[OverlayCredits_Vinifera] = atoi(m_mapfile.GetValueByName("Vinifera", "Value", rules.sections["Vinifera"].AccessValueByName("Value"))); + m_overlayCredits[OverlayCredits_Aboreus] = atoi(m_mapfile.GetValueByName("Aboreus", "Value", rules.sections["Aboreus"].AccessValueByName("Value"))); + for (i = 0;i < rules.sections["BuildingTypes"].values.size();i++) + { + CString type = *rules.sections["BuildingTypes"].GetValue(i); + + int n = GetBuildingNumber(type); + buildingid[type] = n; + } + + for (i = 0;i < m_mapfile.sections["BuildingTypes"].values.size();i++) + { + CString type = *m_mapfile.sections["BuildingTypes"].GetValue(i); + + int n = GetBuildingNumber(type); + buildingid[type] = n; + } + + for (i = 0;i < rules.sections["TerrainTypes"].values.size();i++) + { + CString type = *rules.sections["TerrainTypes"].GetValue(i); + + int n = GetTerrainNumber(type); + terrainid[type] = n; + } + + for (i = 0;i < m_mapfile.sections["TerrainTypes"].values.size();i++) + { + CString type = *m_mapfile.sections["TerrainTypes"].GetValue(i); + + int n = GetTerrainNumber(type); + terrainid[type] = n; + } + +#ifdef SMUDGE_SUPP + + for (i = 0;i < rules.sections["SmudgeTypes"].values.size();i++) + { + CString type = *rules.sections["SmudgeTypes"].GetValue(i); + + int n = GetSmudgeNumber(type); + smudgeid[type] = n; + } + + for (i = 0;i < m_mapfile.sections["SmudgeTypes"].values.size();i++) + { + CString type = *m_mapfile.sections["SmudgeTypes"].GetValue(i); + + int n = GetSmudgeNumber(type); + smudgeid[type] = n; + } + +#endif + + +} + +INT CMapData::GetUnitTypeID(LPCTSTR lpType) +{ + // we only support building types, terrain types and smudge types at the moment + if (buildingid.find(lpType) != buildingid.end()) return buildingid[lpType]; + if (terrainid.find(lpType) != terrainid.end()) return terrainid[lpType]; +#ifdef SMUDGE_SUPP + if (smudgeid.find(lpType) != smudgeid.end()) return smudgeid[lpType]; +#endif + return 0; +} + +void CMapData::GetStdInfantryData(DWORD dwIndex, STDOBJECTDATA* lpStdInfantry) const +{ + /*CString data=*m_mapfile.sections["Infantry"].GetValue(dwIndex); + + lpStdInfantry->house=GetParam(data, 0); + lpStdInfantry->type=GetParam(data, 1); + lpStdInfantry->strength=atoi(GetParam(data, 2)); + lpStdInfantry->y=GetParam(data, 3); + lpStdInfantry->x=atoi(GetParam(data, 4));*/ + + lpStdInfantry->house = m_infantry[dwIndex].house; + lpStdInfantry->type = m_infantry[dwIndex].type; + lpStdInfantry->strength = m_infantry[dwIndex].strength; + lpStdInfantry->y = m_infantry[dwIndex].y; + lpStdInfantry->x = m_infantry[dwIndex].x; + +} + +void CMapData::GetInfantryData(DWORD dwIndex, INFANTRY* lpInfantry) const +{ + ASSERT(dwIndex < m_infantry.size()); + + if (dwIndex >= m_infantry.size()) return; + + /*lpInfantry->house=m_infantry.house; + lpInfantry->type=m_infantry.; + lpInfantry->strength=m_infantry.; + lpInfantry->y=m_infantry.; + lpInfantry->x=m_infantry.; + lpInfantry->pos=m_infantry.; + lpInfantry->action=m_infantry.; + lpInfantry->direction=m_infantry.; + lpInfantry->tag=m_infantry.; + lpInfantry->flag1=m_infantry.; + lpInfantry->flag2=m_infantry.; + lpInfantry->flag3=m_infantry.; + lpInfantry->flag4=m_infantry.; + lpInfantry->flag5=m_infantry.;*/ + *lpInfantry = m_infantry[dwIndex]; + + //memcpy(lpInfantry, &m_infantry[dwIndex], sizeof(INFANTRY)); + + //ASSERT(dwIndex>=0 && dwIndex<m_mapfile.sections["Infantry"].values.size()); + + + + /*if(dwIndex>=m_mapfile.sections["Infantry"].values.size()) return; + + CString data=*m_mapfile.sections["Infantry"].GetValue(dwIndex); + + lpInfantry->house=GetParam(data, 0); + lpInfantry->type=GetParam(data, 1); + lpInfantry->strength=GetParam(data, 2); + lpInfantry->y=GetParam(data, 3); + lpInfantry->x=GetParam(data, 4); + lpInfantry->pos=GetParam(data, 5); + lpInfantry->action=GetParam(data, 6); + lpInfantry->direction=GetParam(data, 7); + lpInfantry->tag=GetParam(data, 8); + lpInfantry->flag1=GetParam(data, 9); + lpInfantry->flag2=GetParam(data, 10); + lpInfantry->flag3=GetParam(data, 11); + lpInfantry->flag4=GetParam(data, 12); + lpInfantry->flag5=GetParam(data, 13);*/ + +} + +void CMapData::GetUnitData(DWORD dwIndex, UNIT* lpUnit) const +{ + const auto section = m_mapfile.GetSection("Units"); + if (!section || dwIndex >= section->values.size()) + return; + + CString data = *section->GetValue(dwIndex); + + lpUnit->house = GetParam(data, 0); + lpUnit->type = GetParam(data, 1); + lpUnit->strength = GetParam(data, 2); + lpUnit->y = GetParam(data, 3); + lpUnit->x = GetParam(data, 4); + lpUnit->direction = GetParam(data, 5); + lpUnit->action = GetParam(data, 6); + lpUnit->tag = GetParam(data, 7); + lpUnit->flag1 = GetParam(data, 8); + lpUnit->flag2 = GetParam(data, 9); + lpUnit->flag3 = GetParam(data, 10); + lpUnit->flag4 = GetParam(data, 11); + lpUnit->flag5 = GetParam(data, 12); + lpUnit->flag6 = GetParam(data, 13); +} + +void CMapData::GetAircraftData(DWORD dwIndex, AIRCRAFT* lpAircraft) const +{ + const auto section = m_mapfile.GetSection("Aircraft"); + if (!section || dwIndex >= section->values.size()) + return; + + CString data = *section->GetValue(dwIndex); + + lpAircraft->house = GetParam(data, 0); + lpAircraft->type = GetParam(data, 1); + lpAircraft->strength = GetParam(data, 2); + lpAircraft->y = GetParam(data, 3); + lpAircraft->x = GetParam(data, 4); + lpAircraft->direction = GetParam(data, 5); + lpAircraft->action = GetParam(data, 6); + lpAircraft->tag = GetParam(data, 7); + lpAircraft->flag1 = GetParam(data, 8); + lpAircraft->flag2 = GetParam(data, 9); + lpAircraft->flag3 = GetParam(data, 10); + lpAircraft->flag4 = GetParam(data, 11); +} + +BOOL CMapData::AddCelltag(LPCTSTR lpTag, DWORD dwPos) +{ + char j[15]; + char k[15]; + memset(j, 0, 15); + memset(k, 0, 15); + itoa(dwPos / GetIsoSize(), j, 10); + if (strlen(j) < 3) + { + strcpy_safe(j + 1, j); + j[0] = '0'; + } + if (strlen(j) < 3) + { + strcpy_safe(j + 1, j); + j[0] = '0'; + } + itoa(dwPos % GetIsoSize(), k, 10); + strcat(k, j); + + m_mapfile.sections["CellTags"].values[k] = lpTag; + + if (!m_noAutoObjectUpdate) UpdateCelltags(FALSE); + return TRUE; +} + +void CMapData::GetCelltagData(DWORD dwIndex, CString* lpTag, DWORD* lpdwPos) const +{ + const auto section = m_mapfile.GetSection("CellTags"); + if (!section || dwIndex >= section->values.size()) + return; + + int x, y; + CString pos; + + pos = *section->GetValueName(dwIndex); + PosToXY(pos, &x, &y); + + const auto tag = section->GetValueByName(pos); + *lpTag = tag; + *lpdwPos = x + y * GetIsoSize(); +} + +BOOL CMapData::AddAircraft(AIRCRAFT* lpAircraft, LPCTSTR lpType, LPCTSTR lpHouse, DWORD dwPos, CString suggestedID) +{ + AIRCRAFT aircraft; + + if (lpAircraft != NULL) + { + aircraft = *lpAircraft; + } + else + { + char sx[15], sy[15]; + itoa(dwPos % GetIsoSize(), sx, 10); + itoa(dwPos / GetIsoSize(), sy, 10); + + aircraft.type = lpType; + aircraft.house = lpHouse; + aircraft.action = "Guard"; + aircraft.tag = "None"; + aircraft.direction = "64"; + aircraft.strength = "256"; + aircraft.x = sx; + aircraft.y = sy; + aircraft.flag1 = "0"; + aircraft.flag2 = "0"; + aircraft.flag3 = "1"; + aircraft.flag4 = "0"; + } + + CString id = GetFree("Aircraft"); + + if (suggestedID.GetLength() > 0) + { + if (m_mapfile.sections["Aircraft"].values.find(suggestedID) == m_mapfile.sections["Aircraft"].values.end()) + id = suggestedID; + } + + CString value; + value = aircraft.house + "," + aircraft.type + "," + aircraft.strength + "," + aircraft.y + "," + + aircraft.x + "," + aircraft.direction + "," + aircraft.action + "," + aircraft.tag + "," + + aircraft.flag1 + "," + aircraft.flag2 + "," + aircraft.flag3 + "," + aircraft.flag4; + + m_mapfile.sections["Aircraft"].values[id] = value; + + if (!m_noAutoObjectUpdate) UpdateAircraft(FALSE); + + return TRUE; +} + +BOOL CMapData::AddUnit(UNIT* lpUnit, LPCTSTR lpType, LPCTSTR lpHouse, DWORD dwPos, CString suggestedID) +{ + UNIT unit; + + if (lpUnit != NULL) + { + unit = *lpUnit; + } + else + { + char sx[15], sy[15]; + itoa(dwPos % GetIsoSize(), sx, 10); + itoa(dwPos / GetIsoSize(), sy, 10); + + unit.type = lpType; + unit.house = lpHouse; + unit.action = "Guard"; + unit.tag = "None"; + unit.direction = "64"; + unit.strength = "256"; + unit.x = sx; + unit.y = sy; + unit.flag1 = "0"; + unit.flag2 = "-1"; + unit.flag3 = "0"; + unit.flag4 = "-1"; + unit.flag5 = "1"; + unit.flag6 = "0"; + + } + + CString id = GetFree("Units"); + + if (suggestedID.GetLength() > 0) + { + if (m_mapfile.sections["Units"].values.find(suggestedID) == m_mapfile.sections["Units"].values.end()) + id = suggestedID; + } + + CString value; + value = unit.house + "," + unit.type + "," + unit.strength + "," + unit.y + "," + + unit.x + "," + unit.direction + "," + unit.action + "," + unit.tag + "," + + unit.flag1 + "," + unit.flag2 + "," + unit.flag3 + "," + unit.flag4 + "," + unit.flag5 + "," + unit.flag6; + + m_mapfile.sections["Units"].values[id] = value; + + if (!m_noAutoObjectUpdate) UpdateUnits(FALSE); + return TRUE; +} + +void CMapData::GetTerrainData(DWORD dwIndex, CString* lpType) const +{ + ASSERT(m_terrain.size() > dwIndex); + + /* if(m_mapfile.sections["Terrain"].values.size()<=dwIndex) + { + errstream << "GetTerrainData() fails..." << endl; + errstream.flush(); + *lpType=""; + return; + }*/ + *lpType = m_terrain[dwIndex].type;//*m_mapfile.sections["Terrain"].GetValue(dwIndex); +} + +// MW New for script interpreter: +void CMapData::GetTerrainData(DWORD dwIndex, TERRAIN* lpType) const +{ + ASSERT(m_terrain.size() > dwIndex); + + *lpType = m_terrain[dwIndex]; +} + +BOOL CMapData::AddTerrain(LPCTSTR lpType, DWORD dwPos, int suggestedIndex) +{ + /*char j1[15]; + char k1[15];*/ + + int x, y; + x = dwPos % GetIsoSize(); + y = dwPos / GetIsoSize(); + + /*itoa(y, j1, 10); + if(strlen(j1)<3) + { + strcpy_safe(j1+1, j1); + j1[0]='0'; + } + if(strlen(j1)<3) + { + strcpy_safe(j1+1, j1); + j1[0]='0'; + } + itoa(x, k1, 10); + strcat(k1, j1);*/ + + + + /* + March 23th, 2001: Replaced slow UpdateTerrain() call with direct modification: + */ + + TERRAIN td; + td.deleted = 0; + td.type = lpType; + td.x = x; + td.y = y; + + if (terrainid.find(td.type) == terrainid.end()) return FALSE; + + BOOL bFound = FALSE; + + if (suggestedIndex >= 0 && suggestedIndex < m_terrain.size()) + { + if (m_terrain[suggestedIndex].deleted) + { + m_terrain[suggestedIndex] = td; + if (dwPos < fielddata_size) + { + fielddata[dwPos].terrain = suggestedIndex; + fielddata[dwPos].terraintype = terrainid[lpType]; + } + bFound = TRUE; + + } + } + + int i; + if (!bFound) + for (i = 0;i < m_terrain.size();i++) + { + if (m_terrain[i].deleted) // yep, found one, replace it + { + m_terrain[i] = td; + if (dwPos < fielddata_size) + { + fielddata[dwPos].terrain = i; + fielddata[dwPos].terraintype = terrainid[lpType]; + } + bFound = TRUE; + break; + } + } + + if (!bFound) + { + m_terrain.push_back(td); + int pos = x + y * GetIsoSize(); + if (pos < fielddata_size) + { + fielddata[pos].terrain = m_terrain.size() - 1; + fielddata[pos].terraintype = terrainid[lpType]; + } + } + + //UpdateTerrain(); + + return TRUE; + +} + +BOOL CMapData::IsGroundObjectAt(DWORD dwPos) const +{ + int m_id = 0; + + m_id = GetInfantryAt(dwPos); + if (m_id < 0) + m_id = GetUnitAt(dwPos); + if (m_id < 0) + m_id = GetAirAt(dwPos); + if (m_id < 0) + m_id = GetStructureAt(dwPos); + if (m_id < 0) + m_id = GetTerrainAt(dwPos); + + if (m_id < 0) return FALSE; + + return TRUE; + +} + +void CMapData::GetWaypointData(DWORD dwIndex, CString* lpID, DWORD* lpdwPos) const +{ + if (lpID) *lpID = ""; + if (lpdwPos) *lpdwPos = 0; + + const auto section = m_mapfile.GetSection("Waypoints"); + if (!section || dwIndex >= section->values.size()) + return; + + CString data = *section->GetValue(dwIndex); + + int x, y; + PosToXY(data, &x, &y); + + if (lpID) *lpID = *section->GetValueName(dwIndex); + if (lpdwPos) *lpdwPos = x + y * GetIsoSize(); + +} + +void CMapData::GetStdAircraftData(DWORD dwIndex, STDOBJECTDATA* lpStdAircraft) const +{ + const auto section = m_mapfile.GetSection("Aircraft"); + if (!section || dwIndex >= section->values.size()) + return; + + CString data = *section->GetValue(dwIndex); + + lpStdAircraft->house = GetParam(data, 0); + lpStdAircraft->type = GetParam(data, 1); + lpStdAircraft->strength.Format("%d", atoi(GetParam(data, 2))); + lpStdAircraft->y = GetParam(data, 3); + lpStdAircraft->x.Format("%d", atoi(GetParam(data, 4))); +} + +void CMapData::GetStdUnitData(DWORD dwIndex, STDOBJECTDATA* lpStdUnit) const +{ + const auto section = m_mapfile.GetSection("Units"); + if (!section || dwIndex >= section->values.size()) + return; + + CString data = *section->GetValue(dwIndex); + + lpStdUnit->house = GetParam(data, 0); + lpStdUnit->type = GetParam(data, 1); + lpStdUnit->strength.Format("%d", atoi(GetParam(data, 2))); + lpStdUnit->y = GetParam(data, 3); + lpStdUnit->x.Format("%d", atoi(GetParam(data, 4))); +} + +DWORD CMapData::GetInfantryCount() const +{ + return m_infantry.size();//m_mapfile.sections["Infantry"].values.size(); +} + +DWORD CMapData::GetUnitCount() const +{ + const auto section = m_mapfile.GetSection("Units"); + return section ? section->values.size() : 0; +} + +DWORD CMapData::GetStructureCount() const +{ + const auto section = m_mapfile.GetSection("Structures"); + return section ? section->values.size() : 0; +} + +DWORD CMapData::GetAircraftCount() const +{ + const auto section = m_mapfile.GetSection("Aircraft"); + return section ? section->values.size() : 0; +} + +DWORD CMapData::GetTerrainCount() const +{ + return m_terrain.size();//m_mapfile.sections["Terrain"].values.size(); +} + +/* +CString CMapData::GetUnitName(LPCTSTR lpID); + +Returns the name of the unit identified with the ID lpID. +Note: takes care of the current mapfile settings +*/ +WCHAR unknown[] = L"MISSING"; +WCHAR* CMapData::GetUnitName(LPCTSTR lpID) const +{ + WCHAR* res = NULL; + + if (g_data.sections["Rename"].FindName(lpID) >= 0) + { + CCStrings[lpID].SetString((LPSTR)(LPCSTR)GetLanguageStringACP(g_data.sections["Rename"].values[(LPCSTR)lpID])); + res = CCStrings[lpID].wString; + return res; + } + + if (CCStrings.find(lpID) != CCStrings.end() && CCStrings[lpID].len > 0) res = CCStrings[lpID].wString; + + if (!res && m_mapfile.sections.find(lpID) != m_mapfile.sections.end()) + { + const auto section = m_mapfile.GetSection(lpID); + if (section && section->values.find("Name") != section->values.end()) + { + CCStrings[lpID].SetString(section->values.at("Name")); + + res = CCStrings[lpID].wString; + } + } + + if (!res && rules.sections.find(lpID) != rules.sections.end()) + { + const auto section = rules.GetSection(lpID); + if (section && section->values.find("Name") != section->values.end()) + { + CCStrings[lpID].SetString(section->values.at("Name")); + res = CCStrings[lpID].wString; + } + } + + if (!res) + { + CCStrings[lpID].SetString(L"MISSING", 7); + res = CCStrings[lpID].wString; + } + + + return res; + + //return CString(""); +} + +DWORD CMapData::GetCelltagCount() const +{ + const auto section = m_mapfile.GetSection("CellTags"); + return section ? section->values.size() : 0; +} + +DWORD CMapData::GetWaypointCount() const +{ + const auto section = m_mapfile.GetSection("Waypoints"); + return section ? section->values.size() : 0; +} + +void CMapData::DeleteRulesSections() +{ + int i; + + // delete any rules sections except the types lists (we need those to get the data of new units in the map)... + for (i = 0; i < m_mapfile.sections.size(); i++) + { + CString name = *m_mapfile.GetSectionName(i); + + if (IsRulesSection(name) && name.Find("Types") < 0) + { + m_mapfile.sections.erase(name); + } + } + + // now delete these types lists... + for (i = 0; i < m_mapfile.sections.size(); i++) + { + CString name = *m_mapfile.GetSectionName(i); + + if (IsRulesSection(name)) + { + m_mapfile.sections.erase(name); + } + } +} + +BOOL CMapData::IsRulesSection(LPCTSTR lpSection) +{ + int i; + for (i = 0;i < GetHousesCount();i++) + if (GetHouseID(i) == lpSection) return FALSE; + + if (strcmp(lpSection, HOUSES) == NULL) return FALSE; + if (strcmp(lpSection, "VariableNames") == NULL) return FALSE; + + if (rules.sections.find(lpSection) != rules.sections.end()) return TRUE; + + + if (m_mapfile.sections.find("InfantryTypes") != m_mapfile.sections.end()) + if (m_mapfile.sections["InfantryTypes"].FindValue(lpSection) >= 0) + return TRUE; + + if (m_mapfile.sections.find("VehicleTypes") != m_mapfile.sections.end()) + if (m_mapfile.sections["VehicleTypes"].FindValue(lpSection) >= 0) + return TRUE; + + if (m_mapfile.sections.find("AircraftTypes") != m_mapfile.sections.end()) + if (m_mapfile.sections["AircraftTypes"].FindValue(lpSection) >= 0) + return TRUE; + + if (m_mapfile.sections.find("BuildingTypes") != m_mapfile.sections.end()) + if (m_mapfile.sections["BuildingTypes"].FindValue(lpSection) >= 0) + return TRUE; + + if (m_mapfile.sections.find("TerrainTypes") != m_mapfile.sections.end()) + if (m_mapfile.sections["TerrainTypes"].FindValue(lpSection) >= 0) + return TRUE; + + if ((CString)"IsoMapPack5" != lpSection && (CString)"OverlayPack" != lpSection && (CString)"OverlayDataPack" != lpSection && m_mapfile.sections.find(lpSection) != m_mapfile.sections.end()) + { + CIniFileSection& sec = m_mapfile.sections[lpSection]; + if (sec.FindName("ROF") > -1 && sec.FindName("Range") > -1 && + sec.FindName("Damage") > -1 && sec.FindName("Warhead") > -1) + return TRUE; // a weapon + + if (sec.FindName("Spread") > -1 && sec.FindName("Range") > -1 && + sec.FindName("Damage") > -1 && sec.FindName("Warhead") > -1) + return TRUE; // a warhead + + // check for projectile/warhead + for (i = 0;i < m_mapfile.sections.size();i++) + { + CString name = *m_mapfile.GetSectionName(i); + if ((CString)"IsoMapPack5" != name && (CString)"OverlayPack" != name && (CString)"OverlayDataPack" != name && (m_mapfile.GetSection(i)->FindName("Projectile") > -1 || m_mapfile.GetSection(i)->FindName("Warhead") > -1)) + { + // MW Bugfix: Check if is found in Projectile first... + // This may have caused several crashes while saving + if (m_mapfile.GetSection(i)->FindName("Projectile") >= 0) + if (*m_mapfile.GetSection(i)->GetValue(m_mapfile.GetSection(i)->FindName("Projectile")) == lpSection) + return TRUE; + } + } + } + + + + return FALSE; + +} + +void CMapData::ExportRulesChanges(const char* filename) +{ + CIniFile rul; + + int i; + for (i = 0;i < m_mapfile.sections.size();i++) + { + + CString name = *m_mapfile.GetSectionName(i); + + if (IsRulesSection(name)) + { + + rul.sections[name] = *m_mapfile.GetSection(i); + + } + } + + rul.SaveFile(std::string(filename)); +} + +void CMapData::ImportRUL(LPCTSTR lpFilename) +{ + m_mapfile.InsertFile(std::string(lpFilename), NULL); + m_mapfile.sections.erase("Editor"); + UpdateBuildingInfo(); + UpdateTreeInfo(); +} + +void CMapData::UpdateMapFieldData(BOOL bSave) +{ + if (bSave == FALSE) + { + int i; + int e; + /*for(i=0;i<GetIsoSize()*GetIsoSize();i++) + { + int dwX=i%m_IsoSize; + int dwY=i/m_IsoSize; + int mapwidth=Map->GetWidth(); + int mapheight=Map->GetHeight(); + int k=1; + + if( dwX<1|| dwY<1 || dwX+dwY<mapwidth+k || dwX+dwY>mapwidth+mapheight*2 || (dwY+k>mapwidth && dwX-k<dwY-mapwidth) || (dwX+k>mapwidth && dwY+mapwidth-k<dwX)) + { + + } + else + { + BOOL bFound=FALSE; + for(e=0;e<dwIsoMapSize;e++) + { + MAPFIELDDATA* mfd=(MAPFIELDDATA*)&m_mfd[e*MAPFIELDDATA_SIZE]; + if(mfd->wY==dwX && mfd->wX==dwY) + { + bFound=TRUE; + break; + } + } + + if(!bFound) + { + errstream << dwX << " " << dwY << " not found"; + errstream.flush(); + } + } + }*/ + + /* int count=0; + int max_count=0; + BYTE b; + b=m_mfd[0]; + for (i=0;i<dwIsoMapSize*MAPFIELDDATA_SIZE;i++) + { + if(m_mfd[i]!=b) { b=m_mfd[i]; count=0; } + if(m_mfd[i]==b) count++; + if(max_count<count) max_count=count; + if(count>10) MessageBox(0,"uh","",0); + } + + char c[50]; + itoa(max_count,c,10); + MessageBox(0,c,"",0);*/ + + const bool mp = IsMultiplayer(); + for (i = 0;i < dwIsoMapSize;i++) + { + MAPFIELDDATA* mfd = (MAPFIELDDATA*)&m_mfd[i * MAPFIELDDATA_SIZE]; + int pos = mfd->wY + mfd->wX * GetIsoSize(); + if (dwIsoMapSize - i < 50) errstream << mfd->wY << " " << mfd->wX << endl; + if (pos < (GetIsoSize() + 1) * (GetIsoSize() + 1)) + { + fielddata[pos].wGround = mfd->wGround; + fielddata[pos].bHeight = mfd->bHeight; + memcpy(&fielddata[pos].bMapData, mfd->bData, 3); + memcpy(&fielddata[pos].bMapData2, mfd->bData2, 1); + + int replacement = 0; + int ground = mfd->wGround; + if (ground == 0xFFFF) ground = 0; + + if ((*tiledata)[ground].bReplacementCount && atoi((*tiles).sections["General"].values["BridgeSet"]) != (*tiledata)[ground].wTileSet) + { + replacement = rand() * (1 + (*tiledata)[ground].bReplacementCount) / RAND_MAX; + } + + fielddata[pos].bRNDImage = replacement; + + Mini_UpdatePos(i % GetIsoSize(), i / GetIsoSize(), mp); + + /*int dwX=mfd->wY; + int dwY=mfd->wX; + int mapwidth=Map->GetWidth(); + int mapheight=Map->GetHeight(); + const int k=1; + if( dwX<1|| dwY<1 || dwX+dwY<mapwidth+k || dwX+dwY>mapwidth+mapheight*2 || (dwY+k>mapwidth && dwX-k<dwY-mapwidth) || (dwX+k>mapwidth && dwY+mapwidth-k<dwX)) + { + errstream << "Outside " << dwX << " " << dwY << endl; + errstream.flush(); + }*/ + + } + else // if(mfd->wY==0xFFFE && mfd->wX==0xFFFE) + { + char c[2]; + c[0] = mfd->bHeight; + c[1] = 0; + OutputDebugString(c); + } + + /*if(mfd->bData[0] || mfd->bData[1] || mfd->bData2[0]) + { + char c[50]; + itoa(mfd->wY, c, 10); + OutputDebugString("Data at "); + OutputDebugString(c); + OutputDebugString(" "); + itoa(mfd->wX,c,10); + OutputDebugString(c); + OutputDebugString(": "); + itoa(mfd->bData[0], c, 10); + OutputDebugString(c); + OutputDebugString(" "); + itoa(mfd->bData[1], c, 10); + OutputDebugString(c); + OutputDebugString(" "); + itoa(mfd->bData[2], c, 10); + OutputDebugString(c); + OutputDebugString(" "); + itoa(mfd->bData2[0], c, 10); + OutputDebugString(c); + OutputDebugString("\n"); + }*/ + + } + + for (i = 0;i < m_IsoSize;i++) + { + for (e = 0;e < m_IsoSize;e++) + { + int pos = i + e * m_IsoSize; + int xx, yy; + fielddata[pos].bRedrawTerrain = FALSE; + for (xx = -2;xx < 0;xx++) + { + for (yy = -2;yy < 0;yy++) + { + int npos = pos + xx + yy * m_IsoSize; + if (npos > 0 && fielddata[pos].bHeight - fielddata[npos].bHeight >= 4) + { + fielddata[pos].bRedrawTerrain = TRUE; + break; + } + } + if (fielddata[pos].bRedrawTerrain) break; + } + } + } + } + else + { + int x, y, n = 0; + + // this code here must be improved to produce smaller maps. Just ignore the data outside the visible rect! + + if (m_mfd) delete[] m_mfd; + dwIsoMapSize = m_IsoSize * m_IsoSize + 15; + m_mfd = new(BYTE[(dwIsoMapSize + m_IsoSize * m_IsoSize) * MAPFIELDDATA_SIZE]); + memset(m_mfd, 0, dwIsoMapSize * MAPFIELDDATA_SIZE); + + + + int p = 0; + const int width = m_maprect.right; + const int height = m_maprect.bottom; + + errstream << "Memory allocated for mappack, saving fielddata into mapfields" << endl; + errstream.flush(); + + int i; + int mapwidth = m_maprect.right; + int mapheight = m_maprect.bottom; + + //#ifdef UNUSED + int dwX, dwY; + for (dwX = 0;dwX <= m_IsoSize;dwX++) + { + for (dwY = 0;dwY <= m_IsoSize;dwY++) + { + /*for(i=0;i<fielddata_size;i++) + {*/ + //int dwX=i%m_IsoSize; + //int dwY=i/m_IsoSize; + i = dwX + dwY * m_IsoSize; + + //if( dwX<2|| dwY<2 || dwX+dwY<mapwidth+2 || dwX+dwY+2>mapwidth+mapheight*2 || (dwY+2>mapwidth && dwX-2<dwY-mapwidth) || (dwX+2>mapwidth && dwY+mapwidth-2<dwX)) continue; + if (dwX < 1 || dwY < 1 || dwX + dwY<mapwidth + 1 || dwX + dwY>mapwidth + mapheight * 2 || (dwY + 1 > mapwidth && dwX - 1 < dwY - mapwidth) || (dwX + 1 > mapwidth && dwY + mapwidth - 1 < dwX)) continue; + + + MAPFIELDDATA* mfd = (MAPFIELDDATA*)&m_mfd[p * MAPFIELDDATA_SIZE]; + mfd->wGround = fielddata[i].wGround; + mfd->wX = dwY; + mfd->wY = dwX; + mfd->bHeight = fielddata[i].bHeight; + memcpy(&mfd->bData, &fielddata[i].bMapData, 3); // includes fielddata[i].bSubTile! + memcpy(&mfd->bData2, &fielddata[i].bMapData2, 1); + + p++; + } + + } + //#endif + + /* + + + if(width>height) + { + int add_bottom=1; + int add_top=-1; + int n_bottom, n_top; + n_bottom=n_top=width; + for(x=0;x<width+height+1;x++) + { + + for(y=n_top;y<=n_bottom;y++) + { + if(y<width+height+1 && y>=0) + { + if( x<1|| y<1 || x+y<mapwidth+1 || x+y>mapwidth+mapheight*2 || (y+1>mapwidth && x-1<y-mapwidth) || (x+1>mapwidth && y+mapwidth-1<x)) continue; + + + int pos=y+x*GetIsoSize(); + + MAPFIELDDATA* mfd=(MAPFIELDDATA*)&m_mfd[p*MAPFIELDDATA_SIZE]; + mfd->wGround=fielddata[pos].wGround; + mfd->wX=x; + mfd->wY=y; + mfd->bHeight=fielddata[pos].bHeight; + memcpy(&mfd->bData, &fielddata[pos].bMapData, 3); + memcpy(&mfd->bData2, &fielddata[pos].bMapData2, 1); + + p++; + } + } + + if(x==height) add_bottom=-1; + if(x==width) add_top=1; + + n_top+=add_top; + n_bottom+=add_bottom; + } + } + else + { + int add_right=1; + int add_left=-1; + int n_right, n_left; + n_right=n_left=height; + for(y=width+height;y>=0;y--) + { + + for(x=n_left;x<=n_right;x++) + { + if(x<width+height && x>=0) + { + if( x<1|| y<1 || x+y<mapwidth+1 || x+y>mapwidth+mapheight*2 || (y+1>mapwidth && x-1<y-mapwidth) || (x+1>mapwidth && y+mapwidth-1<x)) continue; + + int pos=y+x*GetIsoSize(); + + //if(pos>0 && pos<= + MAPFIELDDATA* mfd=(MAPFIELDDATA*)&m_mfd[p*MAPFIELDDATA_SIZE]; + mfd->wGround=fielddata[pos].wGround; + mfd->wX=x; + mfd->wY=y; + mfd->bHeight=fielddata[pos].bHeight; + memcpy(&mfd->bData, &fielddata[pos].bMapData, 3); + memcpy(&mfd->bData2, &fielddata[pos].bMapData2, 1); + + p++; + } + } + + if(y==height) add_right=-1; + if(y==width) add_left=1; + + n_left+=add_left; + n_right+=add_right; + } + }*/ + + /* + else + { + for(y=height;y>=0;y--) + { + for(x=0;x<=n;x++) + { + int pos=y+x*GetIsoSize(); + + MAPFIELDDATA* mfd=(MAPFIELDDATA*)&m_mfd[p*MAPFIELDDATA_SIZE]; + mfd->wGround=fielddata[pos].wGround; + mfd->wX=x; + mfd->wY=y; + mfd->bHeight=fielddata[pos].bHeight; + memcpy(&mfd->bData, &fielddata[pos].bMapData, 3); + memcpy(&mfd->bData2, &fielddata[pos].bMapData2, 1); + char c[50]; + itoa(x,c,10); + OutputDebugString(c); + OutputDebugString(" "); + itoa(y,c,10); + OutputDebugString(c); + OutputDebugString(" "); + itoa(p,c,10); + OutputDebugString(c); + OutputDebugString(" "); + OutputDebugString("\n"); + p++; + } + if(height-y<width) + n++; + else if(y<=width) + n--; + + + } + }*/ + + dwIsoMapSize = p;//+14; // dwIsoMapSize is smaller than whole iso map! + + + + int startpos = (p)*MAPFIELDDATA_SIZE; + /*for(i=0;i<14;i++) + { + MAPFIELDDATA* mfd=(MAPFIELDDATA*)&m_mfd[startpos+i*MAPFIELDDATA_SIZE]; + mfd->wX=0xFFFE; + mfd->wY=0xFFFE; + int c; + switch(i) + { + case 0: + c='F'; + break; + case 1: + c='I'; + break; + case 2: + c='N'; + break; + case 3: + c='A'; + break; + case 4: + c='L'; + break; + case 5: + c='S'; + break; + case 6: + c='U'; + break; + case 7: + c='N'; + break; + case 8: + c='/'; + break; + case 9: + c='A'; + break; + case 10: + c='L'; + break; + case 11: + c='E'; + break; + case 12: + c='R'; + break; + case 13: + c='T'; + break; + } + mfd->bHeight=c; + + }*/ + /*for(i=0;i<m_IsoSize;i++) + { + for(e=0;e<m_IsoSize;e++) + { + int pos=e+i*GetIsoSize(); + + MAPFIELDDATA* mfd=(MAPFIELDDATA*)&m_mfd[n*MAPFIELDDATA_SIZE]; + mfd->wGround=fielddata[pos].wGround; + mfd->wX=i; + mfd->wY=e; + mfd->bHeight=fielddata[pos].bHeight; + memcpy(&mfd->bData, &fielddata[pos].bMapData, 3); + memcpy(&mfd->bData2, &fielddata[pos].bMapData2, 1); + n++; + } + }*/ + + + } +} + +void CMapData::UpdateBuildingInfo(LPCSTR lpUnitType) +{ + CIniFile& ini = GetIniFile(); + + if (!lpUnitType) + { + memset(buildinginfo, 0, 0x0F00 * sizeof(BUILDING_INFO)); + + int i; + for (i = 0;i < rules.sections["BuildingTypes"].values.size();i++) + { + + + CString type = *rules.sections["BuildingTypes"].GetValue(i); + CString artname = type; + + + if (rules.sections[type].values.find("Image") != rules.sections[type].values.end()) + { + artname = rules.sections[type].values["Image"]; + } + if (ini.sections.find(type) != ini.sections.end()) + { + if (ini.sections[type].values.find("Image") != ini.sections[type].values.end()) + { + artname = ini.sections[type].values["Image"]; + } + } + + int w, h; + char d[6]; + memcpy(d, art.sections[artname].values["Foundation"], 1); + d[1] = 0; + w = atoi(d); + if (w == 0) w = 1; + memcpy(d, (LPCTSTR)art.sections[artname].values["Foundation"] + 2, 1); + d[1] = 0; + h = atoi(d); + if (h == 0) h = 1; + + int n = Map->GetUnitTypeID(type); + + if (n >= 0 && n < 0x0F00) + { + buildinginfo[n].w = w; + buildinginfo[n].h = h; + + buildinginfo[n].bSnow = FALSE; + buildinginfo[n].bTemp = FALSE; + buildinginfo[n].bUrban = FALSE; + + + CString lpPicFile = GetUnitPictureFilename(type, 0); + + if (pics.find(lpPicFile) != pics.end()) + { + if (pics[lpPicFile].bTerrain == TheaterChar::None) + { + buildinginfo[n].bSnow = TRUE; + buildinginfo[n].bTemp = TRUE; + buildinginfo[n].bUrban = TRUE; + } + else if (pics[lpPicFile].bTerrain == TheaterChar::T) buildinginfo[n].bTemp = TRUE; + else if (pics[lpPicFile].bTerrain == TheaterChar::A) buildinginfo[n].bSnow = TRUE; + else if (pics[lpPicFile].bTerrain == TheaterChar::U) buildinginfo[n].bUrban = TRUE; + } + else + { + buildinginfo[n].bSnow = TRUE; + buildinginfo[n].bTemp = TRUE; + buildinginfo[n].bUrban = TRUE; + } + + buildinginfo[n].pic_count = 8; + int k; + for (k = 0;k < 8;k++) + { + lpPicFile = GetUnitPictureFilename(type, k); + + if (pics.find(lpPicFile) != pics.end()) + { + buildinginfo[n].pic[k] = pics[lpPicFile]; + } + else + { + buildinginfo[n].pic[k].pic = NULL; + } + + } + + + } + else + { + errstream << "Building not found " << endl; + errstream.flush(); + } + + } + + for (i = 0;i < ini.sections["BuildingTypes"].values.size();i++) + { + + + CString type = *ini.sections["BuildingTypes"].GetValue(i); + CString artname = type; + + + if (ini.sections.find(type) != ini.sections.end()) + { + if (ini.sections[type].values.find("Image") != ini.sections[type].values.end()) + { + artname = ini.sections[type].values["Image"]; + } + } + + int w, h; + char d[6]; + memcpy(d, art.sections[artname].values["Foundation"], 1); + d[1] = 0; + w = atoi(d); + if (w == 0) w = 1; + memcpy(d, (LPCTSTR)art.sections[artname].values["Foundation"] + 2, 1); + d[1] = 0; + h = atoi(d); + if (h == 0) h = 1; + + int n = Map->GetUnitTypeID(type); + + if (n >= 0 && n < 0x0F00) + { + buildinginfo[n].w = w; + buildinginfo[n].h = h; + buildinginfo[n].bSnow = TRUE; + buildinginfo[n].bTemp = TRUE; + buildinginfo[n].bUrban = TRUE; + + CString lpPicFile = GetUnitPictureFilename(type, 0); + + int k; + for (k = 0;k < 8;k++) + { + lpPicFile = GetUnitPictureFilename(type, k); + + if (pics.find(lpPicFile) != pics.end()) + { + buildinginfo[n].pic[k] = pics[lpPicFile]; + } + else + { + buildinginfo[n].pic[k].pic = NULL; + } + } + + } + + } + } + else + { + // only for specific building -> faster + CString type = lpUnitType; + CString artname = type; + + + if (rules.sections[type].values.find("Image") != rules.sections[type].values.end()) + { + artname = rules.sections[type].values["Image"]; + } + if (ini.sections.find(type) != ini.sections.end()) + { + if (ini.sections[type].values.find("Image") != ini.sections[type].values.end()) + { + artname = ini.sections[type].values["Image"]; + } + } + + int w, h; + char d[6]; + memcpy(d, art.sections[artname].values["Foundation"], 1); + d[1] = 0; + w = atoi(d); + if (w == 0) w = 1; + memcpy(d, (LPCTSTR)art.sections[artname].values["Foundation"] + 2, 1); + d[1] = 0; + h = atoi(d); + if (h == 0) h = 1; + + int n = Map->GetUnitTypeID(type); + + if (n >= 0 && n < 0x0F00) + { + buildinginfo[n].w = w; + buildinginfo[n].h = h; + CString lpPicFile = GetUnitPictureFilename(type, 0); + buildinginfo[n].pic_count = 8; + + int k; + for (k = 0;k < 8;k++) + { + lpPicFile = GetUnitPictureFilename(type, k); + + if (pics.find(lpPicFile) != pics.end()) + { + buildinginfo[n].pic[k] = pics[lpPicFile]; + } + else + { + buildinginfo[n].pic[k].pic = NULL; + } + } + + } + } + +} + +void CMapData::UpdateTreeInfo(LPCSTR lpTreeType) +{ + CIniFile& ini = GetIniFile(); + + if (!lpTreeType) + { + memset(treeinfo, 0, 0x0F00 * sizeof(TREE_INFO)); + + int i; + for (i = 0;i < rules.sections["TerrainTypes"].values.size();i++) + { + + + CString type = *rules.sections["TerrainTypes"].GetValue(i); + CString artname = type; + + + if (rules.sections[type].values.find("Image") != rules.sections[type].values.end()) + { + artname = rules.sections[type].values["Image"]; + } + if (ini.sections.find(type) != ini.sections.end()) + { + if (ini.sections[type].values.find("Image") != ini.sections[type].values.end()) + { + artname = ini.sections[type].values["Image"]; + } + } + + int w, h; + char d[6]; + memcpy(d, art.sections[artname].values["Foundation"], 1); + d[1] = 0; + w = atoi(d); + if (w == 0) w = 1; + memcpy(d, (LPCTSTR)art.sections[artname].values["Foundation"] + 2, 1); + d[1] = 0; + h = atoi(d); + if (h == 0) h = 1; + + int n = GetUnitTypeID(type); + + if (n >= 0 && n < 0x0F00) + { + treeinfo[n].w = w; + treeinfo[n].h = h; + + CString lpPicFile = GetUnitPictureFilename(type, 0); + + if (pics.find(lpPicFile) != pics.end()) + { + + treeinfo[n].pic = pics[lpPicFile]; + } + else + treeinfo[n].pic.pic = NULL; + } + + } + + for (i = 0;i < ini.sections["TerrainTypes"].values.size();i++) + { + + + CString type = *ini.sections["TerrainTypes"].GetValue(i); + CString artname = type; + + + if (ini.sections.find(type) != ini.sections.end()) + { + if (ini.sections[type].values.find("Image") != ini.sections[type].values.end()) + { + artname = ini.sections[type].values["Image"]; + } + } + + int w, h; + char d[6]; + memcpy(d, art.sections[artname].values["Foundation"], 1); + d[1] = 0; + w = atoi(d); + if (w == 0) w = 1; + memcpy(d, (LPCTSTR)art.sections[artname].values["Foundation"] + 2, 1); + d[1] = 0; + h = atoi(d); + if (h == 0) h = 1; + + int n = Map->GetUnitTypeID(type); + + if (n >= 0 && n < 0x0F00) + { + treeinfo[n].w = w; + treeinfo[n].h = h; + + CString lpPicFile = GetUnitPictureFilename(type, 0); + + if (pics.find(lpPicFile) != pics.end()) + { + treeinfo[n].pic = pics[lpPicFile]; + } + else + treeinfo[n].pic.pic = NULL; + } + + } + } + else + { + CString type = lpTreeType; + CString artname = type; + + + if (rules.sections[type].values.find("Image") != rules.sections[type].values.end()) + { + artname = rules.sections[type].values["Image"]; + } + if (ini.sections.find(type) != ini.sections.end()) + { + if (ini.sections[type].values.find("Image") != ini.sections[type].values.end()) + { + artname = ini.sections[type].values["Image"]; + } + } + + int w, h; + char d[6]; + memcpy(d, art.sections[artname].values["Foundation"], 1); + d[1] = 0; + w = atoi(d); + if (w == 0) w = 1; + memcpy(d, (LPCTSTR)art.sections[artname].values["Foundation"] + 2, 1); + d[1] = 0; + h = atoi(d); + if (h == 0) h = 1; + int n = Map->GetUnitTypeID(type); + + if (n >= 0 && n < 0x0F00) + { + treeinfo[n].w = w; + treeinfo[n].h = h; + + CString lpPicFile = GetUnitPictureFilename(type, 0); + if (pics.find(lpPicFile) != pics.end()) + { + + treeinfo[n].pic = pics[lpPicFile]; + } + else + treeinfo[n].pic.pic = NULL; + } + + } + +} + +int CMapData::GetBuildingID(LPCSTR lpBuildingName) +{ + if (buildingid.find(lpBuildingName) == buildingid.end()) return -1; + return buildingid[lpBuildingName]; +} + + + +MAPFIELDDATA* CMapData::GetMappackPointer(DWORD dwPos) +{ + int x = dwPos % GetIsoSize(); // note that x=y and y=x in the mappack (according to our struct)! + int y = dwPos / GetIsoSize(); + + int i = 0; + for (i = 0;i < dwIsoMapSize;i++) + { + MAPFIELDDATA* cur = (MAPFIELDDATA*)&m_mfd[i * MAPFIELDDATA_SIZE]; + if (cur->wX == y && cur->wY == x) + return cur; + } + + return NULL; +} + + +void CMapData::CreateMap(DWORD dwWidth, DWORD dwHeight, LPCTSTR lpTerrainType, DWORD dwGroundHeight) +{ + if (fielddata != NULL) delete[] fielddata; + int i; + for (i = 0;i < dwSnapShotCount;i++) + { + delete[] m_snapshots[i].bHeight; + delete[] m_snapshots[i].bMapData; + delete[] m_snapshots[i].bSubTile; + delete[] m_snapshots[i].bMapData2; + delete[] m_snapshots[i].wGround; + delete[] m_snapshots[i].bRedrawTerrain; + delete[] m_snapshots[i].overlay; + delete[] m_snapshots[i].overlaydata; + // m_snapshots[i].mapfile.Clear(); + } + if (m_snapshots != NULL) delete[] m_snapshots; + + + + + + fielddata = NULL; + fielddata_size = 0; + m_snapshots = NULL; + dwSnapShotCount = 0; + m_cursnapshot = -1; + + + m_tubes.clear(); + m_tubes.reserve(32); + + m_infantry.clear(); + m_terrain.clear(); + m_units.clear(); + m_structures.clear(); +#ifdef SMUDGE_SUPP + m_smudges.clear(); +#endif + + + m_mapfile.Clear(); + + CString stdMap; + stdMap = AppPath; +#ifdef TS_MODE + stdMap += "\\StdMapTS.ini"; +#endif +#ifdef RA2_MODE + stdMap += "\\StdMapRA2.ini"; +#endif + + m_mapfile.InsertFile(stdMap, NULL); + + char c[50]; + CString mapsize; + itoa(dwWidth, c, 10); + mapsize = "0,0,"; + mapsize += c; + itoa(dwHeight, c, 10); + mapsize += ","; + mapsize += c; + + m_mapfile.sections["Map"].values["Size"] = mapsize; + + itoa(dwWidth - 4, c, 10); + mapsize = "2,4,"; + mapsize += c; + itoa(dwHeight - 6, c, 10); + mapsize += ","; + mapsize += c; + + m_mapfile.sections["Map"].values["Theater"] = lpTerrainType; + m_mapfile.sections["Map"].values["LocalSize"] = mapsize; + + map<CString, PICDATA>::iterator it = pics.begin(); + for (int e = 0;e < pics.size();e++) + { + try + { +#ifdef NOSURFACES_OBJECTS + if (it->second.bType == PICDATA_TYPE_BMP) + { + if (it->second.pic != NULL) + { + ((LPDIRECTDRAWSURFACE4)it->second.pic)->Release(); + } + } + else + { + if (it->second.pic != NULL) + { + delete[] it->second.pic; + } + if (it->second.vborder) delete[] it->second.vborder; + } +#else + if (it->second.pic != NULL) it->second.pic->Release(); +#endif + + it->second.pic = NULL; + } + catch (...) + { + CString err; + err = "Access violation while trying to release surface "; + char c[6]; + itoa(e, c, 10); + err += c; + + err += "\n"; + OutputDebugString(err); + continue; + } + + it++; + } + + std::unique_ptr<CDynamicGraphDlg> dlg; + if (theApp.m_pMainWnd) + { + dlg.reset(new CDynamicGraphDlg(theApp.m_pMainWnd)); + dlg->ShowWindow(SW_SHOW); + dlg->UpdateWindow(); + } + + pics.clear(); + missingimages.clear(); + + UpdateBuildingInfo(); + UpdateTreeInfo(); + + if (theApp.m_loading) + { + theApp.m_loading->Unload(); + theApp.m_loading->InitMixFiles(); + + if (theApp.m_pMainWnd) + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->UpdateOverlayPictures(); + + theApp.m_loading->InitPics(); + + if (m_mapfile.sections["Map"].values["Theater"] == THEATER0) + { + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + if (dlg) + theApp.m_loading->InitTMPs(&dlg->m_Progress); + theApp.m_loading->cur_theat = 'T'; + + } + else if (m_mapfile.sections["Map"].values["Theater"] == THEATER1) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + if (dlg) + theApp.m_loading->InitTMPs(&dlg->m_Progress); + theApp.m_loading->cur_theat = 'A'; + } + else if (m_mapfile.sections["Map"].values["Theater"] == THEATER2) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + if (dlg) + theApp.m_loading->InitTMPs(&dlg->m_Progress); + theApp.m_loading->cur_theat = 'U'; + } + else if (yuri_mode && m_mapfile.sections["Map"].values["Theater"] == THEATER3) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + + if (dlg) + theApp.m_loading->InitTMPs(&dlg->m_Progress); + theApp.m_loading->cur_theat = 'N'; + } + else if (yuri_mode && m_mapfile.sections["Map"].values["Theater"] == THEATER4) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + + + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + if (dlg) + { + theApp.m_loading->InitTMPs(&dlg->m_Progress); + } + theApp.m_loading->cur_theat = 'L'; + } + else if (m_mapfile.sections["Map"].values["Theater"] == THEATER5) + { + tiledata = &t_tiledata; + tiledata_count = &t_tiledata_count; + tiles = &tiles_t; + theApp.m_loading->FreeTileSet(); + tiledata = &s_tiledata; + tiledata_count = &s_tiledata_count; + tiles = &tiles_s; + theApp.m_loading->FreeTileSet(); + + // MW new tilesets + tiledata = &un_tiledata; + tiledata_count = &un_tiledata_count; + tiles = &tiles_un; + theApp.m_loading->FreeTileSet(); + + tiledata = &l_tiledata; + tiledata_count = &l_tiledata_count; + tiles = &tiles_l; + theApp.m_loading->FreeTileSet(); + + + tiledata = &u_tiledata; + tiledata_count = &u_tiledata_count; + tiles = &tiles_u; + theApp.m_loading->FreeTileSet(); + + tiledata = &d_tiledata; + tiledata_count = &d_tiledata_count; + tiles = &tiles_d; + theApp.m_loading->FreeTileSet(); + + if (dlg) + theApp.m_loading->InitTMPs(&dlg->m_Progress); + theApp.m_loading->cur_theat = 'D'; + } + else + { + theApp.m_loading->FreeAll(); + CString s = "Fatal error! %9 doesn´t support the theater of this map!"; + s = TranslateStringACP(s); + MessageBox(0, s, "Error", 0); + exit(0); + } + } + else + { + // e.g. unittests + tiles = &tiles_t; + } + + + errstream << "CreateMap() clears data\n"; + errstream.flush(); + + CalcMapRect(); + ClearOverlay(); + ClearOverlayData(); + + isInitialized = TRUE; + if (fielddata != NULL) delete[] fielddata; + + errstream << "CreateMap() allocates memory\n"; + errstream.flush(); + fielddata = new(FIELDDATA[(GetIsoSize() + 1) * (GetIsoSize() + 1)]); // +1 because of some unpacking problems + fielddata_size = (GetIsoSize() + 1) * (GetIsoSize() + 1); + dwIsoMapSize = 0; + + errstream << "CreateMap() frees m_mfd\n"; + errstream.flush(); + if (m_mfd != NULL) delete[] m_mfd; + m_mfd = NULL; + + errstream << "CreateMap() loads from ini\n"; + errstream.flush(); + UpdateIniFile(MAPDATA_UPDATE_FROM_INI); + + AddWaypoint("98", (dwWidth + dwHeight) / 2 + (dwWidth + dwHeight) * (dwWidth + dwHeight) / 2); + AddWaypoint("99", (dwWidth + dwHeight) / 2 + (dwWidth + dwHeight) * (dwWidth + dwHeight) / 2 - 1); + + errstream << "CreateMap() sets terrain height\n"; + errstream.flush(); + + + for (i = 0;i < fielddata_size;i++) + { + fielddata[i].bHeight = dwGroundHeight; + } + + errstream << "CreateMap() finished\n"; + errstream.flush(); + +} + +/*void CMapData::CreateSlopesAt(DWORD dwPos) +{ + //OutputDebugString("CreateSlopes()\n"); + + FIELDDATA m=*GetFielddataAt(dwPos); + if(m.wGround==0xFFFF) m.wGround=0; + + TILEDATA& d=(*tiledata)[m.wGround]; + + int ns=-1; + int i,e,p=0; + int h[3][3]; + for(i=0;i<3; i++) + { + for(e=0;e<3;e++) + { + int pos=dwPos+(i-1)+(e-1)*m_IsoSize; + if(pos<0 || pos>=m_IsoSize*m_IsoSize) + { + h[i][e]=0; + } + else + { + FIELDDATA m2=*GetFielddataAt(pos); + + h[i][e]=m.bHeight-m2.bHeight; + } + + + } + } + + // hmm... check if the current tile must be heightened anyway + if(!theApp.m_Options.bDisableSlopeCorrection && d.bMorphable) + { + if((h[0][1]<0 && h[2][1]<0) || (h[1][0]<0 && h[1][2]<0) + + || (h[1][0]<0 && h[0][2]<0 && h[0][1]>=0) + || (h[1][0]<0 && h[2][2]<0 && h[2][1]>=0) + + || (h[0][1]<0 && h[2][0]<0 && h[1][0]>=0) + || (h[0][1]<0 && h[2][2]<0 && h[1][2]>=0) + + || (h[1][2]<0 && h[0][0]<0 && h[0][1]>=0) + || (h[1][2]<0 && h[2][0]<0 && h[2][1]>=0) + + || (h[2][1]<0 && h[0][0]<0 && h[1][0]>=0) + || (h[2][1]<0 && h[0][2]<0 && h[1][2]>=0) + + || (h[1][0]<0 && h[0][1]<0 && h[0][0]>=0) + || (h[0][1]<0 && h[1][2]<0 && h[0][2]>=0) + || (h[1][2]<0 && h[2][1]<0 && h[2][2]>=0) + || (h[2][1]<0 && h[1][0]<0 && h[2][0]>=0) + + ) + { + SetHeightAt(dwPos, m.bHeight+1); + for(i=-1;i<2;i++) + for(e=-1;e<2;e++) + CreateSlopesAt(dwPos+i+e*m_IsoSize); + + return; + } + } + + //OutputDebugString("Running check\n"); + + BOOL checkOtherSlopes=FALSE; + /*if(h[0][0] && h[0][1] && h[0][2] && h[1][0] && h[1][2] && h[2][0] && h[2][1] && h[2][2]) + { + ns=-1; + checkOtherSlopes=TRUE; + }*//* + + if(h[0][0]==-1 && h[2][2]==-1 && h[2][0]>=0 && h[0][2]>=0 && h[1][0]>=0 && h[1][2]>=0 && h[0][1]>=0 && h[2][1]>=0) ns=SLOPE_UP_LEFTTOP_AND_RIGHTBOTTOM; + if(h[0][2]==-1 && h[2][0]==-1 && h[0][0]>=0 && h[2][2]>=0 && h[0][1]>=0 && h[1][0]>=0 && h[1][2]>=0 && h[2][1]>=0) ns=SLOPE_UP_LEFTBOTTOM_AND_RIGHTTOP; + + // that would just be another solution: + // if(h[0][0]==-1 && h[2][2]==-1 && h[2][0]>=0 && h[0][2]>=0 && h[1][0]>=0 && h[1][2]>=0 && h[0][1]>=0 && h[2][1]>=0) ns=SLOPE_UP_LEFTTOP_AND_RIGHTBOTTOM2; + // if(h[0][2]==-1 && h[2][0]==-1 && h[0][0]>=0 && h[2][2]>=0 && h[0][1]>=0 && h[1][0]>=0 && h[1][2]>=0 && h[2][1]>=0) ns=SLOPE_UP_LEFTBOTTOM_AND_RIGHTTOP2; + + + + if(ns==-1) + if(h[1][0]==-1 && h[0][1]!=-1 && h[1][2]!=-1 && h[2][1]!=-1) + { + ns=SLOPE_UP_LEFT; + } + else if(h[0][1]==-1 && h[1][0]!=-1 && h[2][1]!=-1 && h[1][2]!=-1) + { + ns=SLOPE_UP_TOP; + } + else if(h[1][2]==-1 && h[0][1]!=-1 && h[1][0]!=-1 && h[2][1]!=-1) + { + ns=SLOPE_UP_RIGHT; + } + else if(h[2][1]==-1 && h[0][1]!=-1 && h[1][0]!=-1 && h[1][2]!=-1) + { + ns=SLOPE_UP_BOTTOM; + } + + if(ns==-1) + { + if(h[0][0]==-2) ns=SLOPE_DOWN_BOTTOM; + if(h[2][0]==-2) ns=SLOPE_DOWN_RIGHT; + if(h[0][2]==-2) ns=SLOPE_DOWN_LEFT; + if(h[2][2]==-2) ns=SLOPE_DOWN_TOP; + } + + if(ns==-1 && h[0][0]==-1) + { + if(h[1][0]==-1 && h[0][1]==-1 ) ns=SLOPE_DOWN_RIGHTBOTTOM; + else if(h[1][0]==0 && h[0][1]==0) ns=SLOPE_UP_LEFTTOP; + //else if(h[2][2]==1) ns=SLOPE_DOWN_BOTTOM; + } + + if( ns==-1 && h[2][0]==-1) + { + if(h[1][0]==-1 && h[2][1]==-1 ) ns=SLOPE_DOWN_RIGHTTOP; + else if(h[1][0]==0 && h[2][1]==0) ns=SLOPE_UP_LEFTBOTTOM; + //else if(h[0][2]==1) ns=SLOPE_DOWN_RIGHT; + } + if( ns==-1 && h[0][2]==-1) + { + if(h[1][2]==-1 && h[0][1]==-1 ) ns=SLOPE_DOWN_LEFTBOTTOM; + else if(h[1][2]==0 && h[0][1]==0) ns=SLOPE_UP_RIGHTTOP; + //else if(h[2][0]==1) ns=SLOPE_DOWN_LEFT; + } + if( ns==-1 && h[2][2]==-1) + { + if(h[1][2]==-1 && h[2][1]==-1 ) ns=SLOPE_DOWN_LEFTTOP; + else if(h[1][2]==0 && h[2][1]==0) ns=SLOPE_UP_RIGHTBOTTOM; + //else if(h[0][0]==1) ns=SLOPE_DOWN_TOP; + } + + if(ns==-1 && h[1][0]==-1 && h[2][1]==-1 ) ns=SLOPE_DOWN_RIGHTTOP; + if(ns==-1 && h[1][2]==-1 && h[2][1]==-1 ) ns=SLOPE_DOWN_LEFTTOP; + if(ns==-1 && h[1][0]==-1 && h[0][1]==-1 ) ns=SLOPE_DOWN_RIGHTBOTTOM; + if(ns==-1 && h[1][2]==-1 && h[0][1]==-1 ) ns=SLOPE_DOWN_LEFTBOTTOM; + + + //OutputDebugString("Applying changes()\n"); + + + + int rampbase=atoi((*tiles).sections["General"].values["RampBase"]); + int rampsmooth=atoi((*tiles).sections["General"].values["RampSmooth"]); + + //if((rampbase==d.wTileSet || rampsmooth==d.wTileSet) && m.bSubTile==ns) + // return; + + if(ns==-1 && (d.wTileSet==rampbase || d.wTileSet==rampsmooth) && d.bMorphable) + { + SetTileAt(dwPos, 0, 0); + } + if(d.bMorphable && ns!=-1) + { + SetTileAt(dwPos, GetTileID(rampbase, ns-1), 0); + + } + + + + /*if(ns!=-1 || checkOtherSlopes) + { + for(i=-1;i<2;i++) + { + for(e=-1;e<2;e++) + { + int pos=dwPos+(i)+(e)*m_IsoSize; + if(pos>0 && pos<m_IsoSize*m_IsoSize) + { + CreateSlopesAt(pos); + } + } + } + }*//* + +}*/ + +int CMapData::GetNecessarySlope(DWORD dwPos) +{ + + + return 0; +} + +DWORD CMapData::GetTileID(DWORD dwTileSet, int iTile) +{ + int i, e; + DWORD tilecount = 0; + for (i = 0;i < 10000;i++) + { + CString tset; + char c[50]; + itoa(i, c, 10); + int e; + for (e = 0;e < 4 - strlen(c);e++) + tset += "0"; + tset += c; + CString sec = "TileSet"; + sec += tset; + + if (tiles->sections.find(sec) == tiles->sections.end()) return 0xFFFFFFFF; + + + for (e = 0;e < atoi(tiles->sections[sec].values["TilesInSet"]);e++) + { + if (i == dwTileSet && e == iTile) return tilecount; + tilecount++; + + } + + + } + + return tilecount; + +} + +void CMapData::SetReserved(DWORD dwPos, BYTE val) +{ + fielddata[dwPos].bReserved = val; +} + + + +void CMapData::HideField(DWORD dwPos, BOOL bHide) +{ + fielddata[dwPos].bHide = bHide; +} + + + +void CMapData::UpdateTubes(BOOL bSave) +{ + if (!bSave) + { + m_tubes.clear(); + if (m_mapfile.sections.find("Tubes") == m_mapfile.sections.end()) + return; + + auto& tubeSection = m_mapfile.sections["Tubes"]; + + std::uint16_t secSize = tubeSection.values.size(); + m_tubes.reserve(secSize + 10); + + for (auto& [sTubeId, value] : tubeSection) + { + const auto tubeId = std::atoi(sTubeId); + if (tubeId < 0 || tubeId >= std::numeric_limits<std::uint16_t>::max()) + continue; + m_tubes.push_back(std::make_unique<CTube>(static_cast<std::uint16_t>(tubeId), value.GetString())); + } + } + else + { + + } + +} + + + +void CMapData::SetTube(CTube* lpTI) +{ + CString sTubeId; + if (lpTI->hasId()) + sTubeId = std::to_string(lpTI->getId()).c_str(); + else + { + for (std::uint16_t i = 0;i < 10000;i++) + { + sTubeId = std::to_string(i).c_str(); + if (m_mapfile.sections["Tubes"].values.find(sTubeId) == m_mapfile.sections["Tubes"].values.end()) + { + lpTI->setId(i); + break; + } + } + } + + if (!lpTI->hasId()) + return; + + m_mapfile.sections["Tubes"].values[sTubeId] = lpTI->toString().c_str(); + UpdateTubes(FALSE); +} + +CTube* CMapData::GetTube(std::uint16_t wID) +{ + auto it = std::find_if(m_tubes.begin(), m_tubes.end(), [wID](const auto& el) {return el->getId() == wID;}); + if (it == m_tubes.end()) + return nullptr; + + return it->get(); +} + + +void CMapData::DeleteTube(std::uint16_t wID) +{ + if (m_mapfile.sections.find("Tubes") == m_mapfile.sections.end()) + return; + + auto& tubeSection = m_mapfile.sections["Tubes"]; + const CString sTubeId = std::to_string(wID).c_str(); + + std::erase_if(tubeSection.values, [&sTubeId](const auto& el) {return el.first == sTubeId;}); + + //CString id1 = *m_mapfile.sections["Tubes"].GetValueName(wID); + + /*CTube i1 = m_tubes[wID]; + + vector<CString> toErase; + toErase.reserve(10); + + // we delete every tube with same starting coordinates or when starting coordinate of i1 is ending of curi + int i; + for (i = 0;i < m_tubes.size();i++) + { + CTube& curi = m_tubes[i]; + if ((curi.getEndX() == i1.getStartX() && curi.getEndY() == i1.getStartY()) || (curi.getStartX() == i1.getStartX() && curi.getStartY() == i1.getStartY())) + { + toErase.push_back(*m_mapfile.sections["Tubes"].GetValueName(i)); + } + } + + for (i = 0;i < toErase.size();i++) + { + m_mapfile.sections["Tubes"].values.erase(toErase[i]); + }*/ + + UpdateTubes(FALSE); +} + +int CMapData::GetInfantryCountAt(DWORD dwPos) +{ + int i; + int sc = 0; + for (i = 0;i < SUBPOS_COUNT;i++) + { + if (fielddata[dwPos].infantry[i] > -1) sc++; + } + + return sc; +} + +/* +Checks if the map data is valid +May fail if the user changed the tileset manually, +or if loading maps made with modified tilesets +*/ +BOOL CMapData::CheckMapPackData() +{ + int i; + for (i = 0;i < fielddata_size;i++) + { + int gr = fielddata[i].wGround; + if (gr != 0xFFFF && gr >= (*tiledata_count)) + return FALSE; + if (gr == 0xFFFF) gr = 0; + if ((*tiledata)[gr].wTileCount <= fielddata[i].bSubTile) return FALSE; + } + + return TRUE; +} + +/* +Takes a snapshot of the map at a certain location. +Be aware that this won´t make a copy of any units etc. + +This is used for undo and similar things (like displaying and immediatly removing tiles when moving +the mouse on the map before placing a tile). +This method is very fast, as long as you don´t copy the whole map all the time. +*/ +void CMapData::TakeSnapshot(BOOL bEraseFollowing, int left, int top, int right, int bottom) +{ + DWORD dwOldSnapShotCount = dwSnapShotCount; + + if (left < 0) left = 0; + if (top < 0) top = 0; + if (right > m_IsoSize) right = m_IsoSize; + if (bottom > m_IsoSize) bottom = m_IsoSize; + + if (right == 0) right = m_IsoSize; + if (bottom == 0) bottom = m_IsoSize; + + int e; + if (bEraseFollowing) + { + for (e = dwSnapShotCount - 1;e > m_cursnapshot;e--) + { + delete[] m_snapshots[e].bHeight; + delete[] m_snapshots[e].bMapData; + delete[] m_snapshots[e].bSubTile; + delete[] m_snapshots[e].bMapData2; + delete[] m_snapshots[e].overlay; + delete[] m_snapshots[e].overlaydata; + delete[] m_snapshots[e].wGround; + delete[] m_snapshots[e].bRedrawTerrain; + delete[] m_snapshots[e].bRNDData; + // m_snapshots[0].mapfile.Clear(); + } + dwSnapShotCount = m_cursnapshot + 1; + } + + + dwSnapShotCount += 1; + m_cursnapshot++; + + if (dwSnapShotCount > 64) + { + dwSnapShotCount = 64; + m_cursnapshot = 63; + int i; + delete[] m_snapshots[0].bHeight; + delete[] m_snapshots[0].bMapData; + delete[] m_snapshots[0].bSubTile; + delete[] m_snapshots[0].bMapData2; + delete[] m_snapshots[0].overlay; + delete[] m_snapshots[0].overlaydata; + delete[] m_snapshots[0].wGround; + delete[] m_snapshots[0].bRedrawTerrain; + delete[] m_snapshots[0].bRNDData; + // m_snapshots[0].mapfile.Clear(); + for (i = 1;i < dwSnapShotCount;i++) + { + m_snapshots[i - 1] = m_snapshots[i]; + } + + } + else + { + SNAPSHOTDATA* b = new(SNAPSHOTDATA[dwSnapShotCount]); + + if (m_snapshots) + { + memcpy(b, m_snapshots, sizeof(SNAPSHOTDATA) * (dwSnapShotCount - 1)); + delete[] m_snapshots; + } + + m_snapshots = b; + } + + + m_cursnapshot = dwSnapShotCount - 1; + + + SNAPSHOTDATA ss = m_snapshots[dwSnapShotCount - 1]; + // ss.mapfile=m_mapfile; + int width, height; + width = right - left; + height = bottom - top; + + int size = width * height; + ss.left = left; + ss.top = top; + ss.right = right; + ss.bottom = bottom; + ss.bHeight = new(BYTE[size]); + ss.bMapData = new(WORD[size]); + ss.bSubTile = new(BYTE[size]); + ss.bMapData2 = new(BYTE[size]); + ss.wGround = new(WORD[size]); + ss.overlay = new(BYTE[size]); + ss.overlaydata = new(BYTE[size]); + ss.bRedrawTerrain = new(BOOL[size]); + ss.bRNDData = new(BYTE[size]); + int i; + for (i = 0;i < width;i++) + { + for (e = 0;e < height;e++) + { + int pos_w, pos_r; + pos_w = i + e * width; + pos_r = left + i + (top + e) * m_IsoSize; + ss.bHeight[pos_w] = fielddata[pos_r].bHeight; + ss.bMapData[pos_w] = fielddata[pos_r].bMapData; + ss.bSubTile[pos_w] = fielddata[pos_r].bSubTile; + ss.bMapData2[pos_w] = fielddata[pos_r].bMapData2; + ss.wGround[pos_w] = fielddata[pos_r].wGround; + ss.overlay[pos_w] = fielddata[pos_r].overlay; + ss.overlaydata[pos_w] = fielddata[pos_r].overlaydata; + ss.bRedrawTerrain[pos_w] = fielddata[pos_r].bRedrawTerrain; + ss.bRNDData[pos_w] = fielddata[pos_r].bRNDImage; + } + } + + m_snapshots[dwSnapShotCount - 1] = ss; + +} + +/* +Just uses the last SnapShot to reverse changes on the map. +Very fast +*/ +void CMapData::Undo() +{ + if (dwSnapShotCount == 0) return; + if (m_cursnapshot < 0) return; + + + //dwSnapShotCount--; + m_cursnapshot -= 1; + + int left, top, width, height; + left = m_snapshots[m_cursnapshot + 1].left; + top = m_snapshots[m_cursnapshot + 1].top; + width = m_snapshots[m_cursnapshot + 1].right - left; + height = m_snapshots[m_cursnapshot + 1].bottom - top; + + const bool mp = IsMultiplayer(); + int i, e; + for (i = 0;i < width;i++) + { + for (e = 0;e < height;e++) + { + int pos_w, pos_r; + pos_r = i + e * width; + pos_w = left + i + (top + e) * m_IsoSize; + fielddata[pos_w].bHeight = m_snapshots[m_cursnapshot + 1].bHeight[pos_r]; + fielddata[pos_w].bMapData = m_snapshots[m_cursnapshot + 1].bMapData[pos_r]; + fielddata[pos_w].bSubTile = m_snapshots[m_cursnapshot + 1].bSubTile[pos_r]; + fielddata[pos_w].bMapData2 = m_snapshots[m_cursnapshot + 1].bMapData2[pos_r]; + fielddata[pos_w].wGround = m_snapshots[m_cursnapshot + 1].wGround[pos_r]; + + RemoveOvrlMoney(fielddata[pos_w].overlay, fielddata[pos_w].overlaydata); + fielddata[pos_w].overlay = m_snapshots[m_cursnapshot + 1].overlay[pos_r]; + fielddata[pos_w].overlaydata = m_snapshots[m_cursnapshot + 1].overlaydata[pos_r]; + AddOvrlMoney(fielddata[pos_w].overlay, fielddata[pos_w].overlaydata); + + + + fielddata[pos_w].bRedrawTerrain = m_snapshots[m_cursnapshot + 1].bRedrawTerrain[pos_r]; + fielddata[pos_w].bRNDImage = m_snapshots[m_cursnapshot + 1].bRNDData[pos_r]; + + + Mini_UpdatePos(left + i, top + e, mp); + } + } + + // no need for SmoothTiberium: handled externally, because we undo more than just the very needed area + // when changing overlay! + + + +} + +BOOL CMapData::GetLocalSize(RECT* rect) const +{ + if (!isInitialized) return FALSE; + + *rect = m_vismaprect; + + return TRUE; +} + + + +/* +Opposite of Undo(). If possible, redoes the changes. +Very fast. +*/ +void CMapData::Redo() +{ + if (dwSnapShotCount <= m_cursnapshot + 1 || !dwSnapShotCount) return; + + m_cursnapshot += 1; // dwSnapShotCount-1; + + if (m_cursnapshot + 1 >= dwSnapShotCount) m_cursnapshot = dwSnapShotCount - 2; + + int left, top, width, height; + left = m_snapshots[m_cursnapshot + 1].left; + top = m_snapshots[m_cursnapshot + 1].top; + width = m_snapshots[m_cursnapshot + 1].right - left; + height = m_snapshots[m_cursnapshot + 1].bottom - top; + + int i, e; + const bool mp = IsMultiplayer(); + for (i = 0;i < width;i++) + { + for (e = 0;e < height;e++) + { + int pos_w, pos_r; + pos_r = i + e * width; + pos_w = left + i + (top + e) * m_IsoSize; + fielddata[pos_w].bHeight = m_snapshots[m_cursnapshot + 1].bHeight[pos_r]; + fielddata[pos_w].bMapData = m_snapshots[m_cursnapshot + 1].bMapData[pos_r]; + fielddata[pos_w].bSubTile = m_snapshots[m_cursnapshot + 1].bSubTile[pos_r]; + fielddata[pos_w].bMapData2 = m_snapshots[m_cursnapshot + 1].bMapData2[pos_r]; + fielddata[pos_w].wGround = m_snapshots[m_cursnapshot + 1].wGround[pos_r]; + RemoveOvrlMoney(fielddata[pos_w].overlay, fielddata[pos_w].overlaydata); + fielddata[pos_w].overlay = m_snapshots[m_cursnapshot + 1].overlay[pos_r]; + fielddata[pos_w].overlaydata = m_snapshots[m_cursnapshot + 1].overlaydata[pos_r]; + AddOvrlMoney(fielddata[pos_w].overlay, fielddata[pos_w].overlaydata); + fielddata[pos_w].bRedrawTerrain = m_snapshots[m_cursnapshot + 1].bRedrawTerrain[pos_r]; + fielddata[pos_w].bRNDImage = m_snapshots[m_cursnapshot + 1].bRNDData[pos_r]; + + Mini_UpdatePos(left + i, top + e, mp); + } + } + + /* + int i; + for(i=0;i<fielddata_size;i++) + { + fielddata[i].bHeight=m_snapshots[m_cursnapshot+1].bHeight[i]; + fielddata[i].bMapData=m_snapshots[m_cursnapshot+1].bMapData[i]; + fielddata[i].bSubTile=m_snapshots[m_cursnapshot+1].bSubTile[i]; + fielddata[i].bMapData2=m_snapshots[m_cursnapshot+1].bMapData2[i]; + fielddata[i].wGround=m_snapshots[m_cursnapshot+1].wGround[i]; + fielddata[i].overlay=m_snapshots[m_cursnapshot+1].overlay[i]; + fielddata[i].overlaydata=m_snapshots[m_cursnapshot+1].overlaydata[i]; + fielddata[i].bRedrawTerrain=m_snapshots[m_cursnapshot+1].bRedrawTerrain[i]; + } + */ + +} + +static const int tile_to_lat_count = 7; +static const CString tile_to_lat[tile_to_lat_count][3] = { + {"SandTile", "ClearToSandLat", "ClearTile"}, + {"GreenTile", "ClearToGreenLat", "ClearTile"}, + {"RoughTile", "ClearToRoughLat", "ClearTile"}, + {"PaveTile", "ClearToPaveLat", "ClearTile"}, + {"BlueMoldTile", "ClearToBlueMoldLat", ""}, //"ClearTile"}, // TODO: fix + {"CrystalTile", "ClearToCrystalLat", "ClearTile"}, + {"SwampTile", "WaterToSwampLat", "WaterSet"} +}; + +bool CMapData::hasLat(WORD wGround) const +{ + if (wGround >= *tiledata_count) + return false; + const auto set = (*tiledata)[wGround].wTileSet; + + const auto& sec = tiles->sections["General"]; + const CString empty; + + for (int i = 0; i < tile_to_lat_count; ++i) + { + const int tile = atoi(sec.GetValueByName(tile_to_lat[i][0], empty)); + const int lat = atoi(sec.GetValueByName(tile_to_lat[i][1], empty)); + const int target_tile = atoi(sec.GetValueByName(tile_to_lat[i][2], empty)); + if (lat && + (set == tile || + set == lat || + set == target_tile)) + return true; + } + + return false; +} + +void CMapData::SmoothAllAt(DWORD dwPos) +{ + if (theApp.m_Options.bDisableAutoLat) return; + + if (dwPos > fielddata_size) return; + + int set = 0, ground = fielddata[dwPos].wGround; + + if (ground == 0xFFFF) ground = 0; + set = (*tiledata)[ground].wTileSet; + + const auto& sec = tiles->sections["General"]; + const CString empty; + + for (int i = 0; i < tile_to_lat_count; ++i) + { + const int tile = atoi(sec.GetValueByName(tile_to_lat[i][0], empty)); + const int lat = atoi(sec.GetValueByName(tile_to_lat[i][1], empty)); + const int target_tile = atoi(sec.GetValueByName(tile_to_lat[i][2], empty)); + if (strlen(tile_to_lat[i][2]) && + lat && + (set == tile || + set == lat)) + SmoothAt(dwPos, tile, lat, target_tile); + } +} + +void CMapData::CreateShore(int left, int top, int right, int bottom, BOOL bRemoveUseless) +{ + + + int i; + int isosize = Map->GetIsoSize(); + int mapsize = isosize * isosize; + int mapwidth = Map->GetWidth(); + int mapheight = Map->GetHeight(); + // int shoreset=atoi((*tiles).sections["General"].values["ShorePieces"]); + + short* tsets = new(short[mapsize]); + BYTE* terrain = new(BYTE[mapsize]); + int* tile = new(int[mapsize]); + BOOL* hasChanged = new(BOOL[isosize * isosize]); + BOOL* noChange = new(BOOL[isosize * isosize]); + //BOOL* replaced=new(BOOL[isosize*isosize]); // replaced by water<->ground + + memset(hasChanged, 0, sizeof(BOOL) * isosize * isosize); + memset(noChange, 0, sizeof(BOOL) * isosize * isosize); + //memset(replaced, 0, sizeof(BOOL)*isosize*isosize); + + int watercliffset = atoi((*tiles).sections["General"].values["WaterCliffs"]); + int xx, yy; + + for (i = 0;i < *tiledata_count;i++) + { + if ((*tiledata)[i].wTileSet == waterset && (*tiledata)[i].cx == 1 && (*tiledata)[i].cy == 1) break; + } + + int smallwater = i; + + + + + last_succeeded_operation = 7002; + + + map<int, int> softsets; + CString sec = "SoftTileSets"; + + for (i = 0;i < g_data.sections[sec].values.size();i++) + { + CString tset = *g_data.sections[sec].GetValueName(i); + TruncSpace(tset); + int p = (*tiles).sections["General"].FindName(tset); + if (p < 0) continue; + + int set = atoi(*(*tiles).sections["General"].GetValue(p)); + if (atoi(*g_data.sections[sec].GetValue(i))) softsets[set] = 1; + + + } + + + + + last_succeeded_operation = 7001; + + // remove partial shore pieces (wrong ones) + for (xx = left - 2;xx < right + 2;xx++) + { + for (yy = top - 2;yy < bottom + 2;yy++) + { + + if (xx < 1 || yy < 1 || xx + yy<mapwidth + 1 || xx + yy>mapwidth + mapheight * 2 || (yy + 1 > mapwidth && xx - 1 < yy - mapwidth) || (xx + 1 > mapwidth && yy + mapwidth - 1 < xx)) continue; + + int pos = xx + yy * isosize; + if (noChange[pos]) continue; + + FIELDDATA* fd = Map->GetFielddataAt(pos); + int ground = fd->wGround; + if (ground == 0xFFFF) ground = 0; + TILEDATA& td = (*tiledata)[ground]; + if (td.wTileSet != shoreset) continue; + + // we have a shore piece here. check if it is set correct + BOOL bCorrect = TRUE; + + int of = fd->bSubTile; + + int ox = of / td.cy; + int oy = of % td.cy; + + + int xxx, yyy; + int p = 0; + for (xxx = xx - ox;xxx < xx + td.cx - ox;xxx++) + { + for (yyy = yy - oy;yyy < yy + td.cy - oy;yyy++) + { + int pos = xxx + yyy * isosize; + if (td.tiles[p].pic != NULL) + { + FIELDDATA* curf = Map->GetFielddataAt(pos); + int curg = curf->wGround; + if (curg == 0xFFFF) curg = 0; + + if (curg != ground || curf->bSubTile != p) + { + bCorrect = FALSE; + break; + } + } + p++; + } + if (!bCorrect) break; + } + + if (!bCorrect) + { + int iWaterFound = 0; + /*for(xxx=xx-1;xxx<=xx+1;xxx++) + { + for(yyy=yy-1;yyy<=yy+1;yyy++) + { + if(xxx==xx && yyy==yy) continue; + + int pos=xxx+yyy*isosize; + FIELDDATA* curf=Map->GetFielddataAt(pos); + int curg=curf->wGround; + if(curg==0xFFFF) curg=0; + + if((*tiledata)[curg].tiles[curf->bSubTile].bHackedTerrainType==TERRAINTYPE_WATER) + iWaterFound++; + + } + }*/ + + int pos = xx + yy * isosize; + FIELDDATA* curf = Map->GetFielddataAt(pos); + int curg = curf->wGround; + if (curg == 0xFFFF) curg = 0; + + if ((*tiledata)[curg].tiles[curf->bSubTile].bHackedTerrainType == TERRAINTYPE_WATER) iWaterFound = 8; + + if (iWaterFound > 7) + { + for (i = 0;i < *tiledata_count;i++) + { + if ((*tiledata)[i].wTileSet == waterset && (*tiledata)[i].cx == 1 && (*tiledata)[i].cy == 1) break; + } + SetTileAt(xx + yy * isosize, i, 0); + noChange[xx + yy * isosize] = FALSE; + //replaced[xx+yy*isosize]=TRUE; + } + else + { + SetTileAt(xx + yy * isosize, 0, 0); + noChange[xx + yy * isosize] = FALSE; + //replaced[xx+yy*isosize]=TRUE; + + } + } + + } + } + + + // remove too small water and ground pieces (NEW) + if (bRemoveUseless) + { + for (xx = left;xx < right;xx++) + { + for (yy = top;yy < bottom;yy++) + { + + if (xx < 1 || yy < 1 || xx + yy<mapwidth + 1 || xx + yy>mapwidth + mapheight * 2 || (yy + 1 > mapwidth && xx - 1 < yy - mapwidth) || (xx + 1 > mapwidth && yy + mapwidth - 1 < xx)) continue; + + int dwPos = xx + yy * isosize; + + //if(noChange[dwPos]) continue; + + FIELDDATA* fd = Map->GetFielddataAt(dwPos); + int ground = fd->wGround; + if (ground == 0xFFFF) ground = 0; + TILEDATA& td = (*tiledata)[ground]; + + if (softsets.find(td.wTileSet) == softsets.end()) continue; + + if (td.tiles[fd->bSubTile].bHackedTerrainType != TERRAINTYPE_WATER && td.tiles[fd->bSubTile].bHackedTerrainType != TERRAINTYPE_GROUND) continue; + + int ts[3][3]; // terrain info + int i, e; + for (i = 0;i < 3; i++) + { + for (e = 0;e < 3;e++) + { + int pos = dwPos + (i - 1) + (e - 1) * m_IsoSize; + if (pos < 0 || pos >= fielddata_size) + { + ts[i][e] = 0; + } + else + { + FIELDDATA m2 = *GetFielddataAt(pos); + if (m2.wGround == 0xFFFF) m2.wGround = 0; + + ts[i][e] = (*tiledata)[m2.wGround].tiles[m2.bSubTile].bHackedTerrainType; + } + } + } + + + if ((ts[1][0] != ts[1][1] && ts[1][2] != ts[1][1]) || + (ts[0][1] != ts[1][1] && ts[2][1] != ts[1][1])) + { + if (ts[1][1] == TERRAINTYPE_WATER) + { + SetTileAt(dwPos, 0, 0); + //replaced[dwPos]=TRUE; + } + else if (ts[1][1] == TERRAINTYPE_GROUND) + { + if ((ts[1][0] == TERRAINTYPE_WATER && ts[1][2] == TERRAINTYPE_WATER) || (ts[0][1] == TERRAINTYPE_WATER && ts[2][1] == TERRAINTYPE_WATER)) + { + SetTileAt(dwPos, smallwater, 0); + //replaced[dwPos]=TRUE; + } + } + } + + } + } + } + + + last_succeeded_operation = 7003; + + // retrieve non-changeable fields + for (xx = left;xx < right;xx++) + { + for (yy = top;yy < bottom;yy++) + { + if (xx < 1 || yy < 1 || xx + yy<mapwidth + 1 || xx + yy>mapwidth + mapheight * 2 || (yy + 1 > mapwidth && xx - 1 < yy - mapwidth) || (xx + 1 > mapwidth && yy + mapwidth - 1 < xx)) continue; + + int pos = xx + yy * isosize; + FIELDDATA* fd = GetFielddataAt(pos); + int ground = fd->wGround; + if (ground == 0xFFFF) ground = 0; + + tsets[pos] = (*tiledata)[ground].wTileSet; + terrain[pos] = (*tiledata)[ground].tiles[fd->bSubTile].bHackedTerrainType; + tile[pos] = ground; + + if (xx >= left && xx < right && yy >= top && yy < bottom) + { + + if (softsets.find((*tiledata)[ground].wTileSet) == softsets.end()/*(*tiledata)[ground].wTileSet==cliffset || (*tiledata)[ground].wTileSet==watercliffset*/) + { + noChange[pos] = TRUE; continue; + } + + + + TILEDATA& td = (*tiledata)[ground]; + + if (td.wTileSet == shoreset) + { + int of = fd->bSubTile; + + int ox = of / td.cy; + int oy = of % td.cy; + + if (xx - ox < left || yy - oy < top || xx - ox + td.cx >= right || yy - oy + td.cy >= bottom) + { + /*if(!replaced[pos])*/ noChange[pos] = TRUE; + } + } + } + } + } + + + + + /*CProgressCtrl pc; + RECT r,rw; + GetWindowRect(&r); + rw.left=r.left+(r.right-r.left)/2-80; + rw.top=r.top+(r.bottom-r.top)/2-15; + rw.right=rw.left+160; + rw.bottom=rw.top+30; + pc.Create(WS_POPUPWINDOW | PBS_SMOOTH, rw, m_view.m_isoview, 0);*/ + + int tStart, tEnd; + tStart = -1; + tEnd = 0; + for (i = 0;i < *tiledata_count;i++) + { + if ((*tiledata)[i].wTileSet == shoreset) + { + if (tStart < 0) tStart = i; + if (i > tEnd) tEnd = i; + } + } + + /*pc.SetRange(0, (tEnd-tStart)*2); + pc.ShowWindow(SW_SHOW); + pc.RedrawWindow();*/ + + + last_succeeded_operation = 7004; + + for (i = tStart;i <= tEnd;i++) + { + /*pc.SetPos(i-tStart); + pc.UpdateWindow();*/ + TILEDATA& td = (*tiledata)[i]; + + if (td.wTileSet == shoreset) + { + int pos = i - tStart; + if (pos != 4 && pos != 5 && pos != 12 && pos != 13 && pos != 20 && pos != 21 && pos != 28 && pos != 29 + && pos != 6 && pos != 7 && pos != 14 && pos != 15 && pos != 22 && pos != 23 && pos != 30 && pos != 31 && (pos < 32 || pos>39)) + continue; + + int x, y; + int water_count = 0; + int p = 0; + for (x = 0;x < td.cx;x++) + { + for (y = 0;y < td.cy;y++) + { + if (td.tiles[p].bHackedTerrainType == TERRAINTYPE_WATER) + water_count++; + p++; + } + } + + // tsets now has the tileset of every single field in range (x+16, y+16) + // terrain has the terrain type of every single field + int max_x = td.cx < 16 ? td.cx : 16; + int max_y = td.cy < 16 ? td.cy : 16; + + for (x = left;x < right;x++) + { + for (y = top;y < bottom;y++) + { + last_succeeded_operation = 7010; + + int xx, yy; + + //if(!replaced[x+y*isosize] && (x<left || y<top || x>=right || y>=bottom)) continue; + if (x < 1 || y < 1 || x + y<mapwidth + 1 || x + y>mapwidth + mapheight * 2 || (y + 1 > mapwidth && x - 1 < y - mapwidth) || (x + 1 > mapwidth && y + mapwidth - 1 < x)) continue; + + + /*BOOL wat_ex=FALSE; + for(xx=x;xx<x+max_x;xx++) + { + for(yy=y;yy<y+max_y;yy++) + { + FIELDDATA* fd=Map->GetFielddataAt(xx+yy*isosize); + int ground=fd->wGround; + if(ground==0xFFFF) ground=0; + int tile_t=(*tiledata)[ground].tiles[fd->bSubTile].bHackedTerrainType; + if(tile_t==TERRAINTYPE_WATER || tile_t==0xa) + wat_ex=TRUE; + if(wat_ex) break; + } + if(wat_ex) break; + } + if(!wat_ex) continue;*/ + + BOOL bFits = TRUE; + int p = 0; + for (xx = x;xx < x + max_x;xx++) + { + for (yy = y;yy < y + max_y;yy++) + { + if (xx >= isosize || yy >= isosize) continue; + + + int tpos = i - tStart; + int xadd = 0, yadd = 0; + + /* + if(tpos>=0 && tpos<=7) xadd=1; + if(tpos>=6 && tpos<=15) yadd=1; + if(tpos>=14 && tpos<=23) xadd=-1; + if(tpos>=22 && tpos<=31) yadd=-1; + if(tpos>=30 && tpos<=31) xadd=1; + + if(tpos>=32 && tpos<=33) + { + xadd=1; yadd=1; + + } + + if(tpos>=34 && tpos<=35) + { + xadd=-1; yadd=1; + + } + + if(tpos>=36 && tpos<=37) + { + xadd=-1; yadd=-1; + + } + + if(tpos>=38 && tpos<=39) + { + xadd=1; yadd=-1; + + }*/ + + /*if(tpos>=32 && tpos<=33) + { + xadd=1; yadd=1; + if( + terrain[xx+1+yy*isosize]==TERRAINTYPE_WATER || terrain[xx+(yy+1)*isosize]==TERRAINTYPE_WATER + ) + {bFits=FALSE; break;} + } + + if(tpos>=34 && tpos<=35) + { + xadd=-1; yadd=1; + if( + terrain[xx-1+yy*isosize]==TERRAINTYPE_WATER || terrain[xx+(yy+1)*isosize]==TERRAINTYPE_WATER + ) + {bFits=FALSE; break;} + } + + if(tpos>=36 && tpos<=37) + { + xadd=-1; yadd=-1; + if( + terrain[xx-1+yy*isosize]==TERRAINTYPE_WATER || terrain[xx+(yy-1)*isosize]==TERRAINTYPE_WATER + ) + {bFits=FALSE; break;} + } + + if(tpos>=38 && tpos<=39) + { + xadd=1; yadd=-1; + if( + terrain[xx+1+yy*isosize]==TERRAINTYPE_WATER || terrain[xx+(yy-1)*isosize]==TERRAINTYPE_WATER + ) + {bFits=FALSE; break;} + }*/ + + last_succeeded_operation = 7011; + + if (xadd && yadd) + { + if (tsets[xx + xadd + yy * isosize] == waterset || tsets[xx + (yy + yadd) * isosize] == waterset) + { + bFits = FALSE; + break; + } + } + + + int pos_water = xx + xadd + (yy + yadd) * isosize; + int pos_data = xx + yy * isosize; + + + + BYTE& tile_t = td.tiles[p].bHackedTerrainType; + + if (tsets[pos_data] == shoreset) + { + if (hasChanged[pos_data]) // only cancel if this routine set the shore + { + // curves are preferred + if ((max_x != 2 || max_y != 2 || water_count != 3)) + { + if (!((max_x == 3 && max_y == 2) || (max_x == 2 && max_y == 3))) + { + bFits = FALSE; + break; + } + + } + + } + } + + last_succeeded_operation = 7012; + + // one step curves + if (noChange[pos_data]) + { + bFits = FALSE; + break; + } + + + // 2 big shore pieces need special treatment + if (tile[pos_data] <= tEnd && tile[pos_data] >= tEnd - 2) + bFits = FALSE; + + if (tile_t == TERRAINTYPE_WATER) + { + if (terrain[pos_water] != TERRAINTYPE_WATER) + { + bFits = FALSE; + } + } + else + { + if (terrain[pos_water] != TERRAINTYPE_GROUND) + //if(tsets[pos_water]==waterset) + { + bFits = FALSE; + } + } + + + if (!bFits) break; + p++; + } + if (!bFits) break; + } + + last_succeeded_operation = 7012; + + if (bFits) // ok, place shore (later we need to do random choose of the different tiles here + { + // find similar shore piece (randomness) + int count = 0; + int pieces[16]; + int k; + TILEDATA& t_orig = (*tiledata)[i]; + for (k = 0;k < *tiledata_count;k++) + { + TILEDATA& t = (*tiledata)[k]; + + if (t.bMarbleMadness) continue; + + if (t.cx != t_orig.cx || t.cy != t_orig.cy) continue; + + if (k != 4 && k != 5 && k != 12 && k != 13 && k != 20 && k != 21 && k != 28 && k != 29 + && (k < 32 || k>39)) + { + } + else continue; + + int xx, yy; + BOOL bSame = TRUE; + int p = 0; + for (xx = 0;xx < t.cx;xx++) + { + for (yy = 0;yy < t.cy;yy++) + { + if (t.tiles[p].bHackedTerrainType != t_orig.tiles[p].bHackedTerrainType) + bSame = FALSE; + p++; + if (!bSame) break; + } + if (!bSame) break; + } + + if (bSame && count < 16) + { + pieces[count] = k; + count++; + } + } + + last_succeeded_operation = 7013; + + k = ((float)rand() * count) / (float)RAND_MAX; + if (k >= count) k = count - 1; + k = pieces[k]; + + TILEDATA& t = (*tiledata)[k]; + int p = 0; + int xx, yy; + int startheight = GetHeightAt(x + y * isosize); + for (xx = 0;xx < t.cx;xx++) + { + for (yy = 0;yy < t.cy;yy++) + { + if (x + xx >= isosize || y + yy >= isosize) continue; + + int pos = x + xx + (y + yy) * isosize; + last_succeeded_operation = 7014; + + if (t.tiles[p].pic != NULL) + { + SetHeightAt(pos, startheight + t.tiles[p].bZHeight); + SetTileAt(pos, k, p); + last_succeeded_operation = 7015; + tile[pos] = i; + tsets[pos] = (*tiledata)[k].wTileSet; + terrain[pos] = (*tiledata)[k].tiles[p].bHackedTerrainType; + hasChanged[pos] = TRUE; + if ((t.cx == 3 && t.cy == 2) || (t.cx == 2 && t.cy == 3)) noChange[pos] = TRUE; + } + p++; + } + } + + + } + + } + } + } + } + + last_succeeded_operation = 7005; + + + for (i = tStart;i <= tEnd;i++) + { + /*pc.SetPos(i-tStart+(tEnd-tStart)); + pc.UpdateWindow();*/ + TILEDATA& td = (*tiledata)[i]; + + if ((*tiledata)[i].wTileSet == shoreset) + { + int pos = i - tStart; + if (pos != 4 && pos != 5 && pos != 12 && pos != 13 && pos != 20 && pos != 21 && pos != 28 && pos != 29 + && pos != 6 && pos != 7 && pos != 14 && pos != 15 && pos != 22 && pos != 23 && pos != 30 && pos != 31 && (pos < 32 || pos>39)) + + { + } + else continue; + + int x, y; + int water_count = 0; + int p = 0; + for (x = 0;x < td.cx;x++) + { + for (y = 0;y < td.cy;y++) + { + if (td.tiles[p].bHackedTerrainType == TERRAINTYPE_WATER) + water_count++; + p++; + } + } + + + // tsets now has the tileset of every single field in range (x+16, y+16) + // terrain has the terrain type of every single field + int max_x = td.cx < 16 ? td.cx : 16; + int max_y = td.cy < 16 ? td.cy : 16; + + for (x = left;x < right;x++) + { + for (y = top;y < bottom;y++) + { + int xx, yy; + + //if(!replaced[x+y*isosize] && (x<left || y<top || x>=right || y>=bottom)) continue; + if (x < 1 || y < 1 || x + y<mapwidth + 1 || x + y>mapwidth + mapheight * 2 || (y + 1 > mapwidth && x - 1 < y - mapwidth) || (x + 1 > mapwidth && y + mapwidth - 1 < x)) continue; + + + + + + /*BOOL wat_ex=FALSE; + for(xx=x;xx<x+max_x;xx++) + { + for(yy=y;yy<y+max_y;yy++) + { + FIELDDATA* fd=Map->GetFielddataAt(xx+yy*isosize); + int ground=fd->wGround; + if(ground==0xFFFF) ground=0; + int tile_t=(*tiledata)[ground].tiles[fd->bSubTile].bHackedTerrainType; + if(tile_t==TERRAINTYPE_WATER || tile_t==0xa) + wat_ex=TRUE; + if(wat_ex) break; + } + if(wat_ex) break; + } + if(!wat_ex) continue;*/ + + + BOOL bFits = TRUE; + int p = 0; + for (xx = x;xx < x + max_x;xx++) + { + for (yy = y;yy < y + max_y;yy++) + { + if (xx >= isosize || yy >= isosize) continue; + + int tpos = i - tStart; + int xadd = 0, yadd = 0; + + /*if(tpos>=0 && tpos<=7) xadd=1; + if(tpos>=6 && tpos<=15) yadd=1; + if(tpos>=14 && tpos<=23) xadd=-1; + if(tpos>=22 && tpos<=31) yadd=-1; + if(tpos>=30 && tpos<=31) xadd=1; + + if(tpos>=32 && tpos<=33) + { + xadd=1; yadd=1; + + } + + if(tpos>=34 && tpos<=35) + { + xadd=-1; yadd=1; + + } + + if(tpos>=36 && tpos<=37) + { + xadd=-1; yadd=-1; + + } + + if(tpos>=38 && tpos<=39) + { + xadd=1; yadd=-1; + + } + + + if(xadd && yadd) + { + if(tsets[xx+xadd+yy*isosize]==waterset || tsets[xx+(yy+yadd)*isosize]==waterset) + { + bFits=FALSE; + break; + } + }*/ + + + + + int pos_water = xx + xadd + (yy + yadd) * isosize; + int pos_data = xx + yy * isosize; + + BYTE& tile_t = td.tiles[p].bHackedTerrainType; + + if (tsets[pos_data] == shoreset) + { + if (hasChanged[pos_data]) // only cancel if this routine set the shore + { + // curves are preferred + if ((max_x != 2 || max_y != 2 || water_count != 3)) + { + if (!((max_x == 3 && max_y == 2) || (max_x == 2 && max_y == 3))) + { + bFits = FALSE; + break; + } + } + + } + } + + // one step curves + if (noChange[pos_data]) + { + bFits = FALSE; + break; + } + + + if (tile[pos_data] <= tEnd && tile[pos_data] >= tEnd - 2) + bFits = FALSE; + + if (tile_t == TERRAINTYPE_WATER) + { + if (terrain[pos_water] != TERRAINTYPE_WATER) + { + bFits = FALSE; + } + } + else + { + if (terrain[pos_water] != TERRAINTYPE_GROUND) + //if(tsets[pos_water]==waterset) + { + bFits = FALSE; + } + } + + + if (!bFits) break; + p++; + } + if (!bFits) break; + } + + last_succeeded_operation = 7031; + if (bFits) // ok, place shore + { + // find similar shore piece (randomness) + int count = 0; + int pieces[16]; + int k; + TILEDATA& t_orig = (*tiledata)[i]; + for (k = 0;k < *tiledata_count;k++) + { + TILEDATA& t = (*tiledata)[k]; + if (t.cx != t_orig.cx || t.cy != t_orig.cy) continue; + + if (t.bMarbleMadness) continue; + + if (k != 4 && k != 5 && k != 12 && k != 13 && k != 20 && k != 21 && k != 28 && k != 29 + && (k < 32 || k>39)) + { + } + else continue; + + int xx, yy; + BOOL bSame = TRUE; + int p = 0; + for (xx = 0;xx < t.cx;xx++) + { + for (yy = 0;yy < t.cy;yy++) + { + if (t.tiles[p].bHackedTerrainType != t_orig.tiles[p].bHackedTerrainType) + bSame = FALSE; + p++; + if (!bSame) break; + } + if (!bSame) break; + } + + if (bSame && count < 16) + { + pieces[count] = k; + count++; + } + } + + last_succeeded_operation = 7032; + + k = ((float)rand() * count) / (float)RAND_MAX; + if (k >= count) k = count - 1; + k = pieces[k]; + + TILEDATA& t = (*tiledata)[k]; + int p = 0; + int xx, yy; + int startheight = GetHeightAt(x + y * isosize); + for (xx = 0;xx < t.cx;xx++) + { + for (yy = 0;yy < t.cy;yy++) + { + if (x + xx >= isosize || y + yy >= isosize) continue; + + int pos = x + xx + (y + yy) * isosize; + + if (t.tiles[p].pic != NULL) + { + SetHeightAt(pos, startheight + t.tiles[p].bZHeight); + SetTileAt(pos, k, p); + tile[pos] = i; + tsets[pos] = (*tiledata)[k].wTileSet; + terrain[pos] = (*tiledata)[k].tiles[p].bHackedTerrainType; + hasChanged[pos] = TRUE; + if ((t.cx == 3 && t.cy == 2) || (t.cx == 2 && t.cy == 3)) noChange[pos] = TRUE; + } + p++; + } + } + } + + } + } + } + } + + last_succeeded_operation = 7006; + + memset(hasChanged, 0, sizeof(BOOL) * isosize * isosize); + + // now make LAT (RA2 only) + +#ifdef RA2_MODE + int x, y; + for (x = left;x < right;x++) + { + for (y = top;y < bottom;y++) + { + int xx, yy; + if (x < 1 || y < 1 || x + y<mapwidth + 1 || x + y>mapwidth + mapheight * 2 || (y + 1 > mapwidth && x - 1 < y - mapwidth) || (x + 1 > mapwidth && y + mapwidth - 1 < x)) continue; + + int pos = x + y * isosize; + + if (noChange[pos]) continue; + if (terrain[pos] == TERRAINTYPE_GROUND && tsets[pos] != shoreset && tsets[pos] != cliffset && tsets[pos] != watercliffset) + { + int i, e; + BOOL bShoreFound = FALSE; + for (i = x - 1;i <= x + 1;i++) + { + for (e = y - 1;e <= y + 1;e++) + { + if (tsets[i + e * isosize] == shoreset) bShoreFound = TRUE; + if (bShoreFound) break; + } + if (bShoreFound) break; + } + + if (bShoreFound) + { + int sandtile = atoi(tiles->sections["General"].values["GreenTile"]); + int sandlat = atoi(tiles->sections["General"].values["ClearToGreenLat"]); + + int i; + for (i = 0;i < *tiledata_count;i++) + if ((*tiledata)[i].wTileSet == sandtile) break; + Map->SetTileAt(pos, i, 0); + hasChanged[pos] = TRUE; + + } + + } + } + } + + for (x = left - 1;x < right + 1;x++) + { + for (y = top - 1;y < bottom + 1;y++) + { + int xx, yy; + if (x < 1 || y < 1 || x + y<mapwidth + 1 || x + y>mapwidth + mapheight * 2 || (y + 1 > mapwidth && x - 1 < y - mapwidth) || (x + 1 > mapwidth && y + mapwidth - 1 < x)) continue; + + int pos = x + y * isosize; + if (noChange[pos]) continue; + + if (terrain[pos] == TERRAINTYPE_GROUND && tsets[pos] != shoreset && tsets[pos] != cliffset && tsets[pos] != watercliffset) + { + int i, e; + BOOL bShoreFound = FALSE; + BOOL bSomethingChanged = FALSE; + for (i = x - 1;i <= x + 1;i++) + { + for (e = y - 1;e <= y + 1;e++) + { + if (tsets[i + e * isosize] == shoreset) bShoreFound = TRUE; + if (hasChanged[i + e * isosize]) bSomethingChanged = TRUE; + if (bShoreFound && hasChanged[i + e * isosize]) break; + } + if (bShoreFound && hasChanged[i + e * isosize]) break; + } + + + + if (bShoreFound && hasChanged) + { + int sandtile = atoi(tiles->sections["General"].values["GreenTile"]); + int sandlat = atoi(tiles->sections["General"].values["ClearToGreenLat"]); + + + SmoothAt(pos, sandtile, sandlat, atoi(tiles->sections["General"].values["ClearTile"])); + } + + } + } + } +#endif + + + + //delete[] replaced; + delete[] hasChanged; + delete[] noChange; + delete[] tsets; + delete[] terrain; + delete[] tile; + + //pc.DestroyWindow(); + + + +} + +BOOL CMapData::IsMultiplayer() +{ + if (m_mapfile.sections["Basic"].FindName("Player") >= 0) return FALSE; + if (isTrue(m_mapfile.sections["Basic"].values["MultiplayerOnly"])) return TRUE; + if (m_mapfile.sections.find(MAPHOUSES) == m_mapfile.sections.end()) return TRUE; + + return FALSE; +} + +CString CMapData::GetTheater() +{ + return m_mapfile.sections["Map"].values["Theater"]; +} + +void CMapData::Copy(int left, int top, int right, int bottom) +{ + if (left < 0) left = 0; + if (top < 0) top = 0; + if (right > m_IsoSize) right = m_IsoSize; + if (bottom > m_IsoSize) bottom = m_IsoSize; + + if (right == 0) right = m_IsoSize; + if (bottom == 0) bottom = m_IsoSize; + + if (left >= right) return; + if (top >= bottom) return; + + + CLIPBOARD_DATA cd; + cd.dwType = 1; + cd.iWidth = right - left; + cd.iHeight = bottom - top; + cd.dwVersion = 0; + cd.dwReserved = 0; + if (editor_mode == ra2_mode) cd.bGame = 1; else cd.bGame = 0; + + HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(CLIPBOARD_DATA) + cd.iWidth * cd.iHeight * sizeof(CLIPBOARD_MAPCOPY_ENTRY)); + + last_succeeded_operation = 80200; + + void* lpVoid = GlobalLock(hGlob); + + if (!lpVoid) + { + MessageBox(0, "Failed to lock memory", "Error", 0); + return; + } + + memcpy(lpVoid, &cd, sizeof(CLIPBOARD_DATA)); + + CLIPBOARD_MAPCOPY_ENTRY* data = (CLIPBOARD_MAPCOPY_ENTRY*)(((BYTE*)lpVoid) + sizeof(CLIPBOARD_DATA)); + + int i; + int e; + + int lowestheight = 255; + for (i = 0;i < cd.iWidth;i++) + { + for (e = 0;e < cd.iHeight;e++) + { + if (i + left < 0 || e + top < 0 || i + left >= m_IsoSize || e + top >= m_IsoSize) continue; + + int pos_r; + pos_r = left + i + (top + e) * m_IsoSize; + + int ground = fielddata[pos_r].wGround; + if (ground == 0xFFFF) ground = 0; + + if (fielddata[pos_r].bHeight - (*tiledata)[ground].tiles[fielddata[pos_r].bSubTile].bZHeight < lowestheight) lowestheight = fielddata[pos_r].bHeight - (*tiledata)[ground].tiles[fielddata[pos_r].bSubTile].bZHeight; + } + } + + last_succeeded_operation = 80201; + + for (i = 0;i < cd.iWidth;i++) + { + for (e = 0;e < cd.iHeight;e++) + { + if (i + left < 0 || e + top < 0 || i + left >= m_IsoSize || e + top >= m_IsoSize) continue; + + int pos_w, pos_r; + pos_w = i + e * cd.iWidth; + pos_r = left + i + (top + e) * m_IsoSize; + + data[pos_w].bHeight = fielddata[pos_r].bHeight - lowestheight; + data[pos_w].bMapData = fielddata[pos_r].bMapData; + data[pos_w].bSubTile = fielddata[pos_r].bSubTile; + data[pos_w].bMapData2 = fielddata[pos_r].bMapData2; + data[pos_w].wGround = fielddata[pos_r].wGround; + data[pos_w].overlay = fielddata[pos_r].overlay; + data[pos_w].overlaydata = fielddata[pos_r].overlaydata; + data[pos_w].bRedrawTerrain = fielddata[pos_r].bRedrawTerrain; + + int ground = fielddata[pos_r].wGround; + if (ground == 0xFFFF) ground = 0; + int tset = (*tiledata)[ground].wTileSet; + + int k; + for (k = 0;k < *tiledata_count;k++) + { + if ((*tiledata)[k].wTileSet == tset) break; + } + + data[pos_w].wTileSet = tset; + data[pos_w].bTile = ground - k; + } + } + + last_succeeded_operation = 80202; + + while (GlobalUnlock(hGlob)); + + OpenClipboard(theApp.m_pMainWnd->m_hWnd); + EmptyClipboard(); + + if (!SetClipboardData(theApp.m_cf, hGlob)) + { + MessageBox(0, "Failed to set clipboard data", "Error", 0); + + } + + CloseClipboard(); + +} + +void CMapData::Paste(int x, int y, int z_mod) +{ + OpenClipboard(theApp.m_pMainWnd->m_hWnd); + HANDLE handle = GetClipboardData(theApp.m_cf); + + void* lpVoid = GlobalLock(handle); + + if (!lpVoid) + { + CloseClipboard(); + return; + } + + last_succeeded_operation = 3001; + + CLIPBOARD_DATA cd; + memcpy(&cd, lpVoid, sizeof(CLIPBOARD_DATA)); + + + x -= cd.iWidth / 2; + y -= cd.iHeight / 2; + + CLIPBOARD_MAPCOPY_ENTRY* data = (CLIPBOARD_MAPCOPY_ENTRY*)(((BYTE*)lpVoid) + sizeof(CLIPBOARD_DATA)); + + last_succeeded_operation = 3002; + + int lowestheight = 255; + int mapwidth, mapheight; + mapwidth = GetWidth(); + mapheight = GetHeight(); + + int i; + int e; + for (i = 0;i < cd.iWidth;i++) + { + for (e = 0;e < cd.iHeight;e++) + { + if (x + i < 0 || y + e < 0 || x + i >= m_IsoSize || y + e >= m_IsoSize) continue; + + FIELDDATA* fd = Map->GetFielddataAt(i + x + (y + e) * m_IsoSize); + int ground = fd->wGround; + if (ground = 0xFFFF) ground = 0; + + + int height = fd->bHeight;//-(*tiledata)[ground].tiles[fd->bSubTile].bZHeight; + + if (height < lowestheight) lowestheight = height; + + + } + } + + int ground = GetFielddataAt(x + y * m_IsoSize)->wGround; + if (ground == 0xFFFF) ground = 0; + int startheight = lowestheight + z_mod;//-(*tiledata)[ground].tiles[GetFielddataAt(x+y*m_IsoSize)->bSubTile].bZHeight; + + //char c[50]; + //itoa(startheight, c, 10); + //MessageBox(0,c,"",0); + + last_succeeded_operation = 3003; + + const bool mp = IsMultiplayer(); + for (i = 0;i < cd.iWidth;i++) + { + for (e = 0;e < cd.iHeight;e++) + { + int pos_w, pos_r; + pos_r = i + e * cd.iWidth; + pos_w = x + i + (y + e) * m_IsoSize; + + if (x + i < 0 || y + e < 0 || x + i >= m_IsoSize || y + e >= m_IsoSize) continue; + + RemoveOvrlMoney(fielddata[pos_w].overlay, fielddata[pos_w].overlaydata); + + fielddata[pos_w].overlay = data[pos_r].overlay; + fielddata[pos_w].overlaydata = data[pos_r].overlaydata; + + AddOvrlMoney(fielddata[pos_w].overlay, fielddata[pos_w].overlaydata); + + SetHeightAt(pos_w, startheight + data[pos_r].bHeight); + + int tset = data[pos_r].wTileSet; + int tile = data[pos_r].bTile; + int k; + int found = -1; + for (k = 0;k < *tiledata_count;k++) + { + if ((*tiledata)[k].wTileSet == tset) + { + found = k; + break; + } + } + + if (found < 0) continue; + if ((*tiledata)[found + tile].wTileSet != tset) + { + continue; + } + if ((*tiledata)[found + tile].wTileCount <= data[pos_r].bSubTile) continue; + + + fielddata[pos_w].bSubTile = data[pos_r].bSubTile; + fielddata[pos_w].bRedrawTerrain = data[pos_r].bRedrawTerrain; + fielddata[pos_w].wGround = found + tile; + + + + fielddata[pos_w].bMapData = data[pos_r].bMapData; + fielddata[pos_w].bMapData2 = data[pos_r].bMapData2; + + Mini_UpdatePos(x + i, y + e, mp); + } + } + + last_succeeded_operation = 3005; + GlobalUnlock(handle); + + CloseClipboard(); +} + +void CMapData::GetStructurePaint(int index, STRUCTUREPAINT* lpStructurePaint) const +{ + if (index < 0 || index >= m_structurepaint.size()) return; + + *lpStructurePaint = m_structurepaint[index]; +} + +void CMapData::InitMinimap() +{ + + int pwidth = GetWidth() * 2; + int pheight = GetHeight(); + + memset(&m_mini_biinfo, 0, sizeof(BITMAPINFO)); + m_mini_biinfo.bmiHeader.biBitCount = 24; + m_mini_biinfo.bmiHeader.biWidth = pwidth; + m_mini_biinfo.bmiHeader.biHeight = pheight; + m_mini_biinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + m_mini_biinfo.bmiHeader.biClrUsed = 0; + m_mini_biinfo.bmiHeader.biPlanes = 1; + m_mini_biinfo.bmiHeader.biCompression = BI_RGB; + m_mini_biinfo.bmiHeader.biClrImportant = 0; + + int pitch = pwidth * 3; + if (pitch == 0) return; + + if (pitch % sizeof(DWORD)) + { + pitch += sizeof(DWORD) - (pwidth * 3) % sizeof(DWORD); + } + + m_mini_pitch = pitch; + + //m_mini_colors=new(BYTE[pitch*pheight]); + m_mini_colors.resize(pitch * pheight); + + + memset(m_mini_colors.data(), 255, pitch * (pheight)); + + + /*DWORD dwIsoSize=GetIsoSize(); + + int mapwidth=GetWidth(); + int mapheight=GetHeight(); + int i,e; + + int size=pitch*pheight; + + for(i=0;i<dwIsoSize;i++) + { + for(e=0;e<dwIsoSize;e++) + { + Mini_UpdatePos(i,e); + } + }*/ + +} + +void CMapData::GetMinimap(BYTE** lpData, BITMAPINFO* lpBI, int* pitch) +{ + *lpData = m_mini_colors.data(); + *pitch = m_mini_pitch; + memcpy(lpBI, &m_mini_biinfo, sizeof(BITMAPINFO)); +} + +int CMapData::CalcMoneyOnMap() +{ + int i; + int money = 0; + for (i = 0;i < fielddata_size;i++) + { + FIELDDATA& fd = fielddata[i]; + + BYTE& ovrl = fd.overlay; + BYTE& ovrld = fd.overlaydata; + + + if (ovrl >= RIPARIUS_BEGIN && ovrl <= RIPARIUS_END) + { + money += (ovrld + 1) * (atoi(rules.sections["Riparius"].values["Value"])); + } + + if (ovrl >= CRUENTUS_BEGIN && ovrl <= CRUENTUS_END) + { + money += (ovrld + 1) * (atoi(rules.sections["Cruentus"].values["Value"])); + } + + if (ovrl >= VINIFERA_BEGIN && ovrl <= VINIFERA_END) + { + money += (ovrld + 1) * (atoi(rules.sections["Vinifera"].values["Value"])); + } + + if (ovrl >= ABOREUS_BEGIN && ovrl <= ABOREUS_END) + { + money += (ovrld + 1) * (atoi(rules.sections["Aboreus"].values["Value"])); + } + } + + return money; +} + +int CMapData::GetMoneyOnMap() const +{ + return m_money; +} + +int CMapData::GetPowerOfHouse(LPCTSTR lpHouse) +{ + // stub + return 0; +} + +void CMapData::SmoothTiberium(DWORD dwPos) +{ + static int _adj[9] = { 0,1,3,4,6,7,8,10,11 }; + + BYTE& ovrl = fielddata[dwPos].overlay; + + if (!(ovrl >= RIPARIUS_BEGIN && ovrl <= RIPARIUS_END) && + !(ovrl >= CRUENTUS_BEGIN && ovrl <= CRUENTUS_END) && + !(ovrl >= VINIFERA_BEGIN && ovrl <= VINIFERA_END) && + !(ovrl >= ABOREUS_BEGIN && ovrl <= ABOREUS_END)) + return; + + RemoveOvrlMoney(ovrl, fielddata[dwPos].overlaydata); + + int i, e; + int x, y; + x = dwPos % m_IsoSize; + y = dwPos / m_IsoSize; + int count = 0; + + for (i = -1;i < 2;i++) + { + for (e = -1;e < 2;e++) + { + int xx = x + i; + int yy = y + e; + + if (xx < 0 || xx >= m_IsoSize || yy < 0 || yy >= m_IsoSize) continue; + + FIELDDATA& fd = fielddata[xx + yy * m_IsoSize]; + + BYTE& ovrl = fd.overlay; + BYTE& ovrld = fd.overlaydata; + + + if (ovrl >= RIPARIUS_BEGIN && ovrl <= RIPARIUS_END) + { + count++; + } + + if (ovrl >= CRUENTUS_BEGIN && ovrl <= CRUENTUS_END) + { + count++; + } + + if (ovrl >= VINIFERA_BEGIN && ovrl <= VINIFERA_END) + { + count++; + } + + if (ovrl >= ABOREUS_BEGIN && ovrl <= ABOREUS_END) + { + count++; + } + + } + } + + ASSERT(count); + + fielddata[dwPos].overlaydata = _adj[count - 1]; + m_OverlayData[y + x * 512] = _adj[count - 1]; + + AddOvrlMoney(ovrl, fielddata[dwPos].overlaydata); + +} + +void CMapData::ResizeMap(int iLeft, int iTop, DWORD dwNewWidth, DWORD dwNewHeight) +{ +#ifndef RA2_MODE + if (MessageBox(0, "Tunnels may be damaged after changing the map size. Continue?", "Warning", MB_YESNO) == IDNO) return; +#endif + + // MW: New object replacing code to fix crashes + INFANTRY* inf = new(INFANTRY[GetInfantryCount()]); + int inf_count = GetInfantryCount(); + STRUCTURE* str = new(STRUCTURE[GetStructureCount()]); + int str_count = GetStructureCount(); + UNIT* unit = new(UNIT[GetUnitCount()]); + int unit_count = GetUnitCount(); + AIRCRAFT* air = new(AIRCRAFT[GetAircraftCount()]); + int air_count = GetAircraftCount(); + TERRAIN* terrain = new(TERRAIN[GetTerrainCount()]); + int terrain_count = GetTerrainCount(); + CString* wp_id = new(CString[GetWaypointCount()]); + int wp_count = GetWaypointCount(); + DWORD* wp_pos = new(DWORD[GetWaypointCount()]); + CString* ct_tag = new(CString[GetCelltagCount()]); + int ct_count = GetCelltagCount(); + DWORD* ct_pos = new(DWORD[GetCelltagCount()]); + + int i; + + // Now copy the objects into above arrays and delete them from map + for (i = 0;i < inf_count;i++) + { + INFANTRY obj; + GetInfantryData(i, &obj); + inf[i] = obj; + } + for (i = inf_count - 1;i >= 0;i--) + DeleteInfantry(i); + + for (i = 0;i < air_count;i++) + { + AIRCRAFT obj; + GetAircraftData(i, &obj); + + air[i] = obj; + } + for (i = air_count - 1;i >= 0;i--) + DeleteAircraft(i); + + for (i = 0;i < str_count;i++) + { + STRUCTURE obj; + GetStructureData(i, &obj); + + str[i] = obj; + } + for (i = str_count - 1;i >= 0;i--) + DeleteStructure(i); + + for (i = 0;i < unit_count;i++) + { + UNIT obj; + GetUnitData(i, &obj); + + unit[i] = obj; + } + for (i = unit_count - 1;i >= 0;i--) + DeleteUnit(i); + + for (i = 0;i < terrain_count;i++) + { + terrain[i] = m_terrain[i]; + } + for (i = 0;i < terrain_count;i++) + DeleteTerrain(i); + + + for (i = 0;i < wp_count;i++) + { + DWORD pos; + CString id; + + GetWaypointData(i, &id, &pos); + + wp_id[i] = id; + wp_pos[i] = pos; + } + + // for(i=0;i<wp_count;i++) DeleteWaypoint(0); + + + for (i = 0;i < ct_count;i++) + { + DWORD pos; + CString tag; + + GetCelltagData(i, &tag, &pos); + + ct_tag[i] = tag; + ct_pos[i] = pos; + } + + for (i = 0;i < ct_count;i++) DeleteCelltag(0); + + + FIELDDATA* old_fd = fielddata; + int ow = GetWidth(); + int oh = GetHeight(); + int os = GetIsoSize(); + int old_fds = fielddata_size; + + int left = iLeft; + int top = iTop; + + + // hmm, erase any snapshots... we probably can remove this and do coordinate conversion instead + // but for now we just delete them... + for (i = 0;i < dwSnapShotCount;i++) + { + delete[] m_snapshots[i].bHeight; + delete[] m_snapshots[i].bMapData; + delete[] m_snapshots[i].bSubTile; + delete[] m_snapshots[i].bMapData2; + delete[] m_snapshots[i].wGround; + delete[] m_snapshots[i].bRedrawTerrain; + delete[] m_snapshots[i].overlay; + delete[] m_snapshots[i].overlaydata; + // m_snapshots[i].mapfile.Clear(); + } + if (m_snapshots != NULL) delete[] m_snapshots; + + + fielddata = NULL; + fielddata_size = 0; + m_snapshots = NULL; + dwSnapShotCount = 0; + m_cursnapshot = -1; + + + char c[50]; + CString mapsize; + itoa(dwNewWidth, c, 10); + mapsize = "0,0,"; + mapsize += c; + itoa(dwNewHeight, c, 10); + mapsize += ","; + mapsize += c; + + m_mapfile.sections["Map"].values["Size"] = mapsize; + + itoa(dwNewWidth - 4, c, 10); + mapsize = "2,4,"; + mapsize += c; + itoa(dwNewHeight - 6, c, 10); + mapsize += ","; + mapsize += c; + + m_mapfile.sections["Map"].values["LocalSize"] = mapsize; + + + CalcMapRect(); + ClearOverlay(); + ClearOverlayData(); + + + + errstream << "ResizeMap() allocates memory\n"; + errstream.flush(); + fielddata = new(FIELDDATA[(GetIsoSize() + 1) * (GetIsoSize() + 1)]); // +1 because of some unpacking problems + fielddata_size = (GetIsoSize() + 1) * (GetIsoSize() + 1); + dwIsoMapSize = 0; // our iso mappack is empty now, as we didn´t load from a file + + errstream << "ResizeMap() frees m_mfd\n"; + errstream.flush(); + if (m_mfd != NULL) delete[] m_mfd; + m_mfd = NULL; + + + // x_move and y_move specify the movement for each field, related to the old position + int x_move = 0; + int y_move = 0; + + x_move += (dwNewWidth - ow); + + + // x_move and y_move now take care of the map sizing. This means, + // all new or removed tiles will now be added/deleted to/from the bottom right + // but we want to consider left and right, as the user selected it. + // so, do some coordinate conversion: + + x_move += top; + y_move += top; + + x_move += -left; + y_move += left; + + //char c[50]; + /*char d[50]; + itoa(y_move, d, 10); + itoa(x_move, c, 10); + MessageBox(0, c, d,0);*/ + + + // copy tiles now + int e; + for (i = 0;i < os;i++) + { + for (e = 0;e < os;e++) + { + int x, y; + x = i + x_move; + y = e + y_move; + + if (x < 0 || y < 0 || x >= m_IsoSize || y >= m_IsoSize) continue; + + FIELDDATA& fdd = fielddata[x + y * m_IsoSize]; + FIELDDATA& fdo = old_fd[i + e * os]; + + fdd.bCliffHack = fdo.bCliffHack; + fdd.bHeight = fdo.bHeight; + fdd.bHide = fdo.bHide; + fdd.bMapData = fdo.bMapData; + fdd.bMapData2 = fdo.bMapData2; + fdd.bRedrawTerrain = fdo.bRedrawTerrain; + fdd.bRNDImage = fdo.bRNDImage; + fdd.bSubTile = fdo.bSubTile; + fdd.overlay = fdo.overlay; + fdd.overlaydata = fdo.overlaydata; + fdd.wGround = fdo.wGround; + } + } + + // MW 07/22/01: Added Progress dialog - it just was slow, and did not crash... + int allcount = GetInfantryCount() + GetAircraftCount() + GetUnitCount() + GetStructureCount() + GetTerrainCount() + GetWaypointCount() + GetCelltagCount(); + int curcount = 0; + CProgressDlg* dlg = new(CProgressDlg)("Updating objects, please wait"); + dlg->SetRange(0, allcount - 1); + dlg->ShowWindow(SW_SHOW); + + //m_noAutoObjectUpdate=TRUE; // deactivate Update*()... faster + + int count = inf_count; // this temp variable is *needed* (infinite loop)!!! + for (i = 0;i < count;i++) + { + if (inf[i].deleted) + { + dlg->SetPosition(i + curcount); + dlg->UpdateWindow(); + + continue; // MW June 12 01 + } + + INFANTRY obj; + obj = inf[i]; + + char c[50]; + obj.x = itoa(atoi(obj.x) + x_move, c, 10); + obj.y = itoa(atoi(obj.y) + y_move, c, 10); + + int x = atoi(obj.x); + int y = atoi(obj.y); + + + if (x < 0 || y < 0 || x >= m_IsoSize || y >= m_IsoSize) continue; + + AddInfantry(&obj); + + dlg->SetPosition(i + curcount); + dlg->UpdateWindow(); + + } + + curcount += count; + + count = air_count; + for (i = 0;i < count;i++) + { + // if(air[i].deleted) continue; + + AIRCRAFT obj; + obj = air[i]; + + char c[50]; + obj.x = itoa(atoi(obj.x) + x_move, c, 10); + obj.y = itoa(atoi(obj.y) + y_move, c, 10); + + int x = atoi(obj.x); + int y = atoi(obj.y); + + + if (x < 0 || y < 0 || x >= m_IsoSize || y >= m_IsoSize) continue; + + AddAircraft(&obj); + + dlg->SetPosition(i + curcount); + dlg->UpdateWindow(); + } + + UpdateAircraft(FALSE); + + curcount += count; + + count = str_count; + for (i = 0;i < count;i++) + { + // if(str[i].deleted) continue; + + STRUCTURE obj; + obj = str[i]; + + char c[50]; + obj.x = itoa(atoi(obj.x) + x_move, c, 10); + obj.y = itoa(atoi(obj.y) + y_move, c, 10); + + int x = atoi(obj.x); + int y = atoi(obj.y); + + + if (x < 0 || y < 0 || x >= m_IsoSize || y >= m_IsoSize) continue; + + AddStructure(&obj); + + dlg->SetPosition(i + curcount); + dlg->UpdateWindow(); + } + + UpdateStructures(FALSE); + + curcount += count; + + count = unit_count; + for (i = 0;i < count;i++) + { + // if(units[i].deleted) continue; + + UNIT obj; + obj = unit[i]; + + char c[50]; + obj.x = itoa(atoi(obj.x) + x_move, c, 10); + obj.y = itoa(atoi(obj.y) + y_move, c, 10); + + int x = atoi(obj.x); + int y = atoi(obj.y); + + + if (x < 0 || y < 0 || x >= m_IsoSize || y >= m_IsoSize) continue; + + AddUnit(&obj); + + dlg->SetPosition(i + curcount); + dlg->UpdateWindow(); + } + + UpdateUnits(FALSE); + + curcount += count; + + count = terrain_count; + for (i = 0;i < count;i++) + { + if (terrain[i].deleted) + { + dlg->SetPosition(i + curcount); + dlg->UpdateWindow(); + continue; // MW June 12 01 + } + + CString obj; + int x = terrain[i].x; + int y = terrain[i].y; + obj = terrain[i].type; + + + char c[50]; + x = x + x_move; + y = y + y_move; + + + if (x < 0 || y < 0 || x >= m_IsoSize || y >= m_IsoSize) continue; + + AddTerrain(obj, x + y * m_IsoSize); + + dlg->SetPosition(i + curcount); + dlg->UpdateWindow(); + } + + //UpdateTerrain(TRUE); + //UpdateTerrain(FALSE); + + curcount += count; + + count = wp_count; + for (i = 0;i < count;i++) + { + DWORD pos; + CString id; + + pos = wp_pos[i]; + id = wp_id[i]; + + int x = pos % os + x_move; + int y = pos / os + y_move; + + if (x < 0 || y < 0 || x >= m_IsoSize || y >= m_IsoSize) continue; + + AddWaypoint(id, x + y * m_IsoSize); + + dlg->SetPosition(i + curcount); + dlg->UpdateWindow(); + } + + UpdateWaypoints(FALSE); + + curcount += count; + + + for (i = 0;i < ct_count;i++) + { + DWORD pos = ct_pos[i]; + CString tag = ct_tag[i]; + + int x = pos % os + x_move; + int y = pos / os + y_move; + + if (x < 0 || y < 0 || x >= m_IsoSize || y >= m_IsoSize) continue; + + AddCelltag(tag, x + y * m_IsoSize); + + dlg->SetPosition(i + curcount); + dlg->UpdateWindow(); + } + + UpdateCelltags(FALSE); + + m_noAutoObjectUpdate = FALSE; + + errstream << "Delete old_fd" << endl; + errstream.flush(); + + dlg->DestroyWindow(); + dlg = new(CProgressDlg)("Updating Minimap, please wait"); + count = 0; + dlg->SetRange(0, m_IsoSize * m_IsoSize); + dlg->ShowWindow(SW_SHOW); + + if (old_fd) delete[] old_fd; + + errstream << "Init minimap" << endl; + errstream.flush(); + + InitMinimap(); + + errstream << "Fill minimap" << endl; + errstream.flush(); + + const bool mp = IsMultiplayer(); + for (i = 0;i < m_IsoSize;i++) + { + for (e = 0;e < m_IsoSize;e++) + { + Mini_UpdatePos(i, e, mp); + + count++; + + } + dlg->SetPosition(count); + dlg->UpdateWindow(); + } + + errstream << "Finished" << endl; + errstream.flush(); + + if (inf) delete[] inf; + if (str) delete[] str; + if (unit) delete[] unit; + if (air) delete[] air; + if (terrain) delete[] terrain; + if (wp_id) delete[] wp_id; + if (wp_pos) delete[] wp_pos; + if (ct_tag) delete[] ct_tag; + if (ct_pos) delete[] ct_pos; + + dlg->DestroyWindow(); + + +} + +/* +Returns TRUE for all sections that should not be modified using the INI editor, +because they become modified whenever the map is saved by the editor itself. +*/ +BOOL CMapData::IsMapSection(LPCSTR lpSectionName) +{ + CString str; + str = lpSectionName; + + if (str == "IsoMapPack5" || str == "OverlayPack" || str == "OverlayDataPack" || + str == "Preview" || str == "PreviewPack" || str == "Map" || + str == "Structures" || str == "Terrain" || str == "Units" || str == "Aircraft" || str == "Infantry" + || str == "Variables") + return TRUE; + + return FALSE; +} + +int GetEventParamStart(CString& EventData, int param); + +BOOL CMapData::IsYRMap() +{ +#ifdef TS_MODE + return FALSE; +#else + + //if(yuri_mode) // always check for this + { + if (Map->GetTheater() == THEATER3 || Map->GetTheater() == THEATER4 || Map->GetTheater() == THEATER5) + return TRUE; + + int i; + int max = 0; + if (tiledata == &u_tiledata) + { + max = atoi(g_data.sections["RA2TileMax"].values["Urban"]); + } + else if (tiledata == &s_tiledata) max = atoi(g_data.sections["RA2TileMax"].values["Snow"]); + else if (tiledata == &t_tiledata) max = atoi(g_data.sections["RA2TileMax"].values["Temperat"]); + + int yroverlay = atoi(g_data.sections["YROverlay"].values["Begin"]); + + for (i = 0;i < fielddata_size;i++) + { + if (fielddata[i].wGround != 0xFFFF && fielddata[i].wGround >= max) + { + return TRUE; + } + if (fielddata[i].overlay >= yroverlay && fielddata[i].overlay != 0xFF) + return TRUE; + } + + int count; + + count = GetInfantryCount(); + for (i = 0;i < count;i++) + { + INFANTRY inf; + GetInfantryData(i, &inf); + + if (inf.deleted) continue; + + CIniFileSection& sec = g_data.sections["YRInfantry"]; + + if (sec.values.find(inf.type) != sec.values.end()) + { + return TRUE; + } + } + + count = GetStructureCount(); + for (i = 0;i < count;i++) + { + STRUCTURE str; + GetStructureData(i, &str); + + if (str.deleted) continue; + + CIniFileSection& sec = g_data.sections["YRBuildings"]; + + if (sec.values.find(str.type) != sec.values.end()) + { + return TRUE; + } + } + + count = GetUnitCount(); + for (i = 0;i < count;i++) + { + UNIT unit; + GetUnitData(i, &unit); + + if (unit.deleted) continue; + + CIniFileSection& sec = g_data.sections["YRUnits"]; + + if (sec.values.find(unit.type) != sec.values.end()) + { + return TRUE; + } + } + + count = GetAircraftCount(); + for (i = 0;i < count;i++) + { + AIRCRAFT air; + GetAircraftData(i, &air); + + if (air.deleted) continue; + + CIniFileSection& sec = g_data.sections["YRAircraft"]; + + if (sec.values.find(air.type) != sec.values.end()) + { + return TRUE; + } + } + + count = GetTerrainCount(); + for (i = 0;i < count;i++) + { + TERRAIN& tr = m_terrain[i]; + + + if (tr.deleted) continue; + + CIniFileSection& sec = g_data.sections["YRTerrain"]; + + if (sec.values.find(tr.type) != sec.values.end()) + { + return TRUE; + } + } + + count = m_mapfile.sections["Triggers"].values.size(); + for (i = 0;i < count;i++) + { + CString event; + CString action; + CString id; + + id = *m_mapfile.sections["Triggers"].GetValueName(i); + + event = m_mapfile.sections["Events"].values[id]; + action = m_mapfile.sections["Actions"].values[id]; + + int eventcount, actioncount; + eventcount = atoi(GetParam(event, 0)); + actioncount = atoi(GetParam(action, 0)); + + int e; + + for (e = 0;e < eventcount;e++) + { + CString type = GetParam(event, GetEventParamStart(event, e)); + if (g_data.sections["EventsRA2"].values.find(type) != g_data.sections["EventsRA2"].values.end()) + { + if (isTrue(GetParam(g_data.sections["EventsRA2"].values[type], 9))) + return TRUE; + } + } + + for (e = 0;e < actioncount;e++) + { + CString type = GetParam(action, 1 + e * 8); + if (g_data.sections["ActionsRA2"].values.find(type) != g_data.sections["ActionsRA2"].values.end()) + { + if (isTrue(GetParam(g_data.sections["ActionsRA2"].values[type], 14))) + return TRUE; + } + } + } + } + + return FALSE; +#endif +} + +#ifdef SMUDGE_SUPP +BOOL CMapData::AddSmudge(SMUDGE* lpSmudge) +{ + + + SMUDGE td; + td = *lpSmudge; + int pos = td.x + td.y * GetIsoSize(); + + if (smudgeid.find(td.type) == smudgeid.end()) return FALSE; + + BOOL bFound = FALSE; + + int i; + for (i = 0;i < m_smudges.size();i++) + { + if (m_smudges[i].deleted) // yep, found one, replace it + { + m_smudges[i] = td; + if (pos < fielddata_size) + { + fielddata[pos].smudge = i; + fielddata[pos].smudgetype = smudgeid[td.type]; + } + + bFound = TRUE; + break; + } + } + + if (!bFound) + { + m_smudges.push_back(td); + + if (pos < fielddata_size) + { + fielddata[pos].smudge = m_smudges.size() - 1; + fielddata[pos].smudgetype = smudgeid[td.type]; + } + } + + + return TRUE; +} + +void CMapData::DeleteSmudge(DWORD dwIndex) +{ + if (m_smudges[dwIndex].deleted) return; + + int x, y; + + x = m_smudges[dwIndex].x; + y = m_smudges[dwIndex].y; + m_smudges[dwIndex].deleted = 1; + + int pos = x + y * GetIsoSize(); + if (x + y * m_IsoSize < fielddata_size) + { + fielddata[pos].smudge = -1; + fielddata[pos].smudgetype = -1; + } +} + +void CMapData::UpdateSmudges(BOOL bSave, int num) +{ + vector<SMUDGE>& t = m_smudges; + + if (bSave == FALSE) + { + if (m_mapfile.sections.find("Smudge") == m_mapfile.sections.end() || m_mapfile.sections["Smudge"].values.size() <= 0) + return; + + if (num < 0) + { + t.clear(); + t.reserve(100); + + int i; + for (i = 0;i < GetIsoSize() * GetIsoSize();i++) + { + fielddata[i].smudge = -1; + } + + + + CIniFileSection& sec = m_mapfile.sections["Smudge"]; + + for (i = 0;i < sec.values.size();i++) + { + int x, y; + x = atoi(GetParam(*sec.GetValue(i), 2)); + y = atoi(GetParam(*sec.GetValue(i), 1)); + + // check for valid coordinates ; MW May 17th 2001 + ASSERT(x >= 0 && x < GetIsoSize()); + ASSERT(y >= 0 && y < GetIsoSize()); + if (x < 0 || x >= GetIsoSize() || y < 0 || y >= GetIsoSize()) + { + // invalid coordinates - ignore in release + } + else + { + SMUDGE td; + td.deleted = 0; + td.type = GetParam(*sec.GetValue(i), 0); + td.x = x; + td.y = y; + + t.push_back(td); + + int pos = x + y * GetIsoSize(); + fielddata[pos].smudge = i; + fielddata[pos].smudgetype = smudgeid[td.type]; + } + } + + m_mapfile.sections.erase("Smudge"); + + } + + } + else + { + + //if(num<0) + { + //if(m_mapfile.sections.find("Smudge")!=m_mapfile.sections.end()) MessageBox(0,"Reupdate!","",0); + m_mapfile.sections.erase("Smudge"); + int i; + + for (i = 0;i < t.size();i++) + { + SMUDGE& td = t[i]; + if (!td.deleted) + { + char c[50]; + CString val = td.type; + val += ","; + itoa(td.y, c, 10); + val += c; + val += ","; + itoa(td.x, c, 10); + val += c; + val += ",0"; + + itoa(i, c, 10); + + m_mapfile.sections["Smudge"].values[c] = val; + } + } + } + + } + +} + +void CMapData::UpdateSmudgeInfo(LPCSTR lpSmudgeType) +{ + CIniFile& ini = GetIniFile(); + + if (!lpSmudgeType) + { + memset(smudgeinfo, 0, 0x0F00 * sizeof(SMUDGE_INFO)); + + int i; + for (i = 0;i < rules.sections["SmudgeTypes"].values.size();i++) + { + + + CString type = *rules.sections["SmudgeTypes"].GetValue(i); + CString artname = type; + + + int n = GetUnitTypeID(type); + + if (n >= 0 && n < 0x0F00) + { + + CString lpPicFile = GetUnitPictureFilename(type, 0); + + if (pics.find(lpPicFile) != pics.end()) + { + + smudgeinfo[n].pic = pics[lpPicFile]; + } + else + smudgeinfo[n].pic.pic = NULL; + } + + } + + for (i = 0;i < ini.sections["SmudgeTypes"].values.size();i++) + { + + + CString type = *ini.sections["SmudgeTypes"].GetValue(i); + CString artname = type; + + + + int n = Map->GetUnitTypeID(type); + + if (n >= 0 && n < 0x0F00) + { + //smudgeinfo[n].w=w; + //smudgeinfo[n].h=h; + + CString lpPicFile = GetUnitPictureFilename(type, 0); + + if (pics.find(lpPicFile) != pics.end()) + { + smudgeinfo[n].pic = pics[lpPicFile]; + } + else + smudgeinfo[n].pic.pic = NULL; + } + + } + } + else + { + CString type = lpSmudgeType; + CString artname = type; + + + + int n = Map->GetUnitTypeID(type); + + if (n >= 0 && n < 0x0F00) + { + + CString lpPicFile = GetUnitPictureFilename(type, 0); + if (pics.find(lpPicFile) != pics.end()) + { + + smudgeinfo[n].pic = pics[lpPicFile]; + } + else + smudgeinfo[n].pic.pic = NULL; + } + + } + + +} + +void CMapData::GetSmudgeData(DWORD dwIndex, SMUDGE* lpData) const +{ + ASSERT(m_smudges.size() > dwIndex); + + + *lpData = m_smudges[dwIndex];//*m_mapfile.sections["Terrain"].GetValue(dwIndex); +} +#endif + + + + +BOOL CMapData::GetInfantryINIData(int index, CString* lpINI) +{ + ASSERT(index < m_infantry.size()); + + if (index >= m_infantry.size() || index < 0) return FALSE; + + INFANTRY& infantry = m_infantry[index]; + CString value; + value = infantry.house + "," + infantry.type + "," + infantry.strength + "," + infantry.y + + "," + infantry.x + "," + infantry.pos + "," + infantry.action + "," + infantry.direction + "," + + infantry.tag + "," + infantry.flag1 + "," + infantry.flag2 + "," + infantry.flag3 + "," + + infantry.flag4 + "," + infantry.flag5; + + *lpINI = value; + + return TRUE; + +} + +void CMapData::RedrawMinimap() +{ + const bool mp = IsMultiplayer(); + int i, e; + for (i = 0; i < m_IsoSize; i++) + for (e = 0; e < m_IsoSize; e++) + Mini_UpdatePos(i, e, mp); +} diff --git a/MissionEditor/MapData.h b/MissionEditor/MapData.h new file mode 100644 index 0000000..2ae8f86 --- /dev/null +++ b/MissionEditor/MapData.h @@ -0,0 +1,1306 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Map->h: Interface for the class CMap. +// +// CMap holds all information for the current map +// +////////////////////////////////////////////////////////////////////// + +#include "structs.h" +#include <vector> +#include "variables.h" +#include "macros.h" +#include "ovrlinline.h" +#include "Tube.h" + + +extern TILEDATA** tiledata; +extern DWORD* tiledata_count; +extern ofstream errstream; +extern map<int, int> tilesets_start; +extern CIniFile* tiles; +extern CFinalSunApp theApp; +extern int shoreset; + +extern CIniFile rules; + +extern TILEDATA* un_tiledata; +extern CIniFile g_data; + +extern int ramp2set; +extern int pave2set; +extern int ramp2set_start; +extern int pave2set_start; +extern int rampset_start; +extern int rampset; + + + +#if !defined(AFX_MAP_H__9278CAC0_D4E7_11D3_B63B_444553540001__INCLUDED_) +#define AFX_MAP_H__9278CAC0_D4E7_11D3_B63B_444553540001__INCLUDED_ + +#include "IniFile.h" // HinzugefĂ¼gt von der Klassenansicht +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +#include <array> + +#define MAPDATA_UPDATE_FROM_INI 0 +#define MAPDATA_UPDATE_TO_INI 1 +#define MAPDATA_UPDATE_TO_INI_ALL 2 +#define MAPDATA_UPDATE_TO_INI_ALL_PREVIEW 4 +#define MAPDATA_UPDATE_TO_INI_ALL_COMPRESSED 8 + +struct NODEDATA +{ + NODEDATA(); + int type; + int index; + CString house; +}; + +// mapfielddata is the data of every field in an extracted isomappack! +struct MAPFIELDDATA +{ + unsigned short wX; + unsigned short wY; + WORD wGround; + BYTE bData[3]; + BYTE bHeight; + BYTE bData2[1]; +}; +#define MAPFIELDDATA_SIZE 11 + +/* +struct TILEDATA{}; + +contains the information needed for one field of the map. +*/ +struct FIELDDATA +{ + FIELDDATA(); + short unit; // unit number + short infantry[SUBPOS_COUNT]; // infantry number + short aircraft; // aircraft number + short structure; // structure number + short structuretype; // structure type id + short terrain; // terrain number + int terraintype; // terrain type id +#ifdef SMUDGE_SUPP + short smudge; + int smudgetype; +#endif + short waypoint; // waypoint number + + NODEDATA node; // node info + BYTE overlay; // overlay number + BYTE overlaydata; // overlay data info + WORD wGround; // ground type (tile) + WORD bMapData; // add. data + BYTE bSubTile; + BYTE bHeight; // height of tile + BYTE bMapData2; // add. data2 + short celltag; // celltag uses + + //std::uint16_t wTubeId; // tube ID + //char cTubePart; // 0 is start, 1 is exit, and 2-101 are tube parts + unsigned bReserved : 1; // for program usage + unsigned bHide : 1; + unsigned bRedrawTerrain : 1; // force redraw + unsigned bCliffHack : 1; + unsigned bRNDImage : 4; // for using a,b,c of tmp tiles +}; + +struct SNAPSHOTDATA +{ + SNAPSHOTDATA(); + int left; + int top; + int bottom; + int right; + + BOOL* bRedrawTerrain; + BYTE* overlay; + BYTE* overlaydata; + WORD* wGround; + WORD* bMapData; + BYTE* bSubTile; + BYTE* bHeight; + BYTE* bMapData2; + BYTE* bRNDData; + //CIniFile mapfile; +}; + + + +class CMapData +{ +public: + + BOOL m_noAutoObjectUpdate; + + void SetFielddataAt(DWORD dwPos, FIELDDATA* lpFd) + { + if (dwPos >= fielddata_size) return; + + RemoveOvrlMoney(fielddata[dwPos].overlay, fielddata[dwPos].overlaydata); + fielddata[dwPos] = (*lpFd); + AddOvrlMoney(fielddata[dwPos].overlay, fielddata[dwPos].overlaydata); + }; + + DWORD GetMapPos(int mapX, int mapY) const + { + return mapX + mapY * m_IsoSize; + } + DWORD GetMapPos(const MapCoords& coords) const + { + return coords.x + coords.y * m_IsoSize; + } + + bool hasLat(WORD wTileSet) const; + + void HideField(DWORD dwPos, BOOL bHide); + void SetReserved(DWORD dwPos, BYTE val); + DWORD GetTileID(DWORD dwTileSet, int iTile); + int GetNecessarySlope(DWORD dwPos); + void CreateSlopesAt(DWORD dwPos) + { + //OutputDebugString("CreateSlopes()\n"); + + FIELDDATA m = *GetFielddataAt(dwPos); + if (m.wGround == 0xFFFF) m.wGround = 0; + + TILEDATA& d = (*tiledata)[m.wGround]; + + int ns = -1; + int i, e, p = 0; + int h[3][3]; + for (i = 0;i < 3; i++) + { + for (e = 0;e < 3;e++) + { + int pos = dwPos + (i - 1) + (e - 1) * m_IsoSize; + if (pos < 0 || pos >= m_IsoSize * m_IsoSize) + { + h[i][e] = 0; + } + else + { + FIELDDATA m2 = *GetFielddataAt(pos); + + h[i][e] = m.bHeight - m2.bHeight; + } + + + } + } + + // check if the current tile must be heightened anyway + if (!theApp.m_Options.bDisableSlopeCorrection && d.bMorphable) + { + if ((h[0][1] < 0 && h[2][1] < 0) || (h[1][0] < 0 && h[1][2] < 0) + + || (h[1][0] < 0 && h[0][2] < 0 && h[0][1] >= 0) + || (h[1][0] < 0 && h[2][2] < 0 && h[2][1] >= 0) + + || (h[0][1] < 0 && h[2][0] < 0 && h[1][0] >= 0) + || (h[0][1] < 0 && h[2][2] < 0 && h[1][2] >= 0) + + || (h[1][2] < 0 && h[0][0] < 0 && h[0][1] >= 0) + || (h[1][2] < 0 && h[2][0] < 0 && h[2][1] >= 0) + + || (h[2][1] < 0 && h[0][0] < 0 && h[1][0] >= 0) + || (h[2][1] < 0 && h[0][2] < 0 && h[1][2] >= 0) + + || (h[1][0] < 0 && h[0][1] < 0 && h[0][0] >= 0) + || (h[0][1] < 0 && h[1][2] < 0 && h[0][2] >= 0) + || (h[1][2] < 0 && h[2][1] < 0 && h[2][2] >= 0) + || (h[2][1] < 0 && h[1][0] < 0 && h[2][0] >= 0) + + ) + { + SetHeightAt(dwPos, m.bHeight + 1); + for (i = -1;i < 2;i++) + for (e = -1;e < 2;e++) + CreateSlopesAt(dwPos + i + e * m_IsoSize); + + return; + } + } + + + + BOOL checkOtherSlopes = FALSE; + + + if (h[0][0] == -1 && h[2][2] == -1 && h[2][0] >= 0 && h[0][2] >= 0 && h[1][0] >= 0 && h[1][2] >= 0 && h[0][1] >= 0 && h[2][1] >= 0) ns = SLOPE_UP_LEFTTOP_AND_RIGHTBOTTOM; + if (h[0][2] == -1 && h[2][0] == -1 && h[0][0] >= 0 && h[2][2] >= 0 && h[0][1] >= 0 && h[1][0] >= 0 && h[1][2] >= 0 && h[2][1] >= 0) ns = SLOPE_UP_LEFTBOTTOM_AND_RIGHTTOP; + + + + + if (ns == -1) + if (h[1][0] == -1 && h[0][1] != -1 && h[1][2] != -1 && h[2][1] != -1) + { + ns = SLOPE_UP_LEFT; + } + else if (h[0][1] == -1 && h[1][0] != -1 && h[2][1] != -1 && h[1][2] != -1) + { + ns = SLOPE_UP_TOP; + } + else if (h[1][2] == -1 && h[0][1] != -1 && h[1][0] != -1 && h[2][1] != -1) + { + ns = SLOPE_UP_RIGHT; + } + else if (h[2][1] == -1 && h[0][1] != -1 && h[1][0] != -1 && h[1][2] != -1) + { + ns = SLOPE_UP_BOTTOM; + } + + if (ns == -1) + { + if (h[0][0] == -2) ns = SLOPE_DOWN_BOTTOM; + if (h[2][0] == -2) ns = SLOPE_DOWN_RIGHT; + if (h[0][2] == -2) ns = SLOPE_DOWN_LEFT; + if (h[2][2] == -2) ns = SLOPE_DOWN_TOP; + } + + if (ns == -1 && h[0][0] == -1) + { + if (h[1][0] == -1 && h[0][1] == -1) ns = SLOPE_DOWN_RIGHTBOTTOM; + else if (h[1][0] == 0 && h[0][1] == 0) ns = SLOPE_UP_LEFTTOP; + //else if(h[2][2]==1) ns=SLOPE_DOWN_BOTTOM; + } + + if (ns == -1 && h[2][0] == -1) + { + if (h[1][0] == -1 && h[2][1] == -1) ns = SLOPE_DOWN_RIGHTTOP; + else if (h[1][0] == 0 && h[2][1] == 0) ns = SLOPE_UP_LEFTBOTTOM; + //else if(h[0][2]==1) ns=SLOPE_DOWN_RIGHT; + } + if (ns == -1 && h[0][2] == -1) + { + if (h[1][2] == -1 && h[0][1] == -1) ns = SLOPE_DOWN_LEFTBOTTOM; + else if (h[1][2] == 0 && h[0][1] == 0) ns = SLOPE_UP_RIGHTTOP; + //else if(h[2][0]==1) ns=SLOPE_DOWN_LEFT; + } + if (ns == -1 && h[2][2] == -1) + { + if (h[1][2] == -1 && h[2][1] == -1) ns = SLOPE_DOWN_LEFTTOP; + else if (h[1][2] == 0 && h[2][1] == 0) ns = SLOPE_UP_RIGHTBOTTOM; + //else if(h[0][0]==1) ns=SLOPE_DOWN_TOP; + } + + if (ns == -1 && h[1][0] == -1 && h[2][1] == -1) ns = SLOPE_DOWN_RIGHTTOP; + if (ns == -1 && h[1][2] == -1 && h[2][1] == -1) ns = SLOPE_DOWN_LEFTTOP; + if (ns == -1 && h[1][0] == -1 && h[0][1] == -1) ns = SLOPE_DOWN_RIGHTBOTTOM; + if (ns == -1 && h[1][2] == -1 && h[0][1] == -1) ns = SLOPE_DOWN_LEFTBOTTOM; + + + int rampbase = rampset_start;//atoi((*tiles).sections["General"].values["RampBase"]); + int rampsmooth = atoi((*tiles).sections["General"].AccessValueByName("RampSmooth")); + + if (ns == -1 && (d.wTileSet == rampset || d.wTileSet == rampsmooth) && d.bMorphable) + { + SetTileAt(dwPos, 0, 0); + } + if (tiledata == &un_tiledata) + { + int r = ramp2set; + int m = pave2set; + + if (ns == -1 && (d.wTileSet == r || d.wTileSet == m) && d.bMorphable) + { + SetTileAt(dwPos, pave2set_start/*GetTileID(m,0)*/, 0); + } + } + if (d.bMorphable && ns != -1) + { + if (tiledata == &un_tiledata) // NEW URBAN FIX FOR URBAN PAVEMENT + { + + //[NewUrbanInfo] + //Morphable2=114 + //Ramps2=117 + int r = ramp2set; + int m = pave2set; + if (d.wTileSet == r || d.wTileSet == m) + rampbase = ramp2set_start; + + + } + + SetTileAt(dwPos, rampbase + ns - 1, 0); + + } + + + } + void CreateMap(DWORD dwWidth, DWORD dwHeight, LPCTSTR lpTerrainType, DWORD dwGroundHeight); + BOOL SetTileAt(DWORD dwPos, DWORD dwID, DWORD dwTile) + { + if (dwPos > fielddata_size) return FALSE; + + int replacement = 0; // MW fix: ignore for bridges + if ((*tiledata)[dwID].bReplacementCount && atoi((*tiles).sections["General"].AccessValueByName("BridgeSet")) != (*tiledata)[dwID].wTileSet) + { + replacement = rand() * (1 + (*tiledata)[dwID].bReplacementCount) / RAND_MAX; + } + + fielddata[dwPos].wGround = dwID; + fielddata[dwPos].bSubTile = dwTile; + fielddata[dwPos].bRNDImage = replacement; + + int e; + fielddata[dwPos].bRedrawTerrain = FALSE; + int xx, yy; + for (xx = -2;xx < 0;xx++) + { + for (yy = -2;yy < 0;yy++) + { + int npos = dwPos + xx + yy * m_IsoSize; + if (npos > 0 && fielddata[dwPos].bHeight - fielddata[npos].bHeight >= 4) + { + fielddata[dwPos].bRedrawTerrain = TRUE; + break; + } + } + if (fielddata[dwPos].bRedrawTerrain) break; + } + + Mini_UpdatePos(dwPos % m_IsoSize, dwPos / m_IsoSize, IsMultiplayer()); + + return TRUE; + } + + void SetHeightAt(DWORD dwPos, BYTE bHeight) + { + int height = (char)bHeight; + if (height > MAXHEIGHT) height = MAXHEIGHT; // too high else + if (height < 0) height = 0; + if (dwPos < fielddata_size) fielddata[dwPos].bHeight = height; + } + + + int GetBuildingID(LPCSTR lpBuildingName); + void ImportRUL(LPCTSTR lpFilename); + void ExportRulesChanges(const char* filename); + void DeleteRulesSections(); + DWORD GetWaypointCount() const; + DWORD GetCelltagCount() const; + WCHAR* GetUnitName(LPCTSTR lpID) const; + DWORD GetTerrainCount() const; + DWORD GetAircraftCount() const; + DWORD GetStructureCount() const; + DWORD GetUnitCount() const; + DWORD GetInfantryCount() const; + void GetStdUnitData(DWORD dwIndex, STDOBJECTDATA* lpStdUnit) const; + void GetStdAircraftData(DWORD dwIndex, STDOBJECTDATA* lpStdAircraft) const; + void GetWaypointData(DWORD dwIndex, CString* lpID, DWORD* lpdwPos) const; + BOOL IsGroundObjectAt(DWORD dwPos) const; + BOOL AddTerrain(LPCTSTR lpType, DWORD dwPos, int suggestedIndex = -1); + void GetTerrainData(DWORD dwIndex, CString* lpType) const; + void GetTerrainData(DWORD dwIndex, TERRAIN* lpTerrain) const; + BOOL AddUnit(UNIT* lpUnit, LPCTSTR lpType = NULL, LPCTSTR lpHouse = NULL, DWORD dwPos = 0, CString suggestedID = ""); + BOOL AddAircraft(AIRCRAFT* lpAircraft, LPCTSTR lpType = NULL, LPCTSTR lpHouse = NULL, DWORD dwPos = 0, CString suggestedID = ""); + void GetCelltagData(DWORD dwIndex, CString* lpTag, DWORD* lpdwPos) const; + BOOL AddCelltag(LPCTSTR lpTag, DWORD dwPos); + void GetAircraftData(DWORD dwIndex, AIRCRAFT* lpAircraft) const; + void GetUnitData(DWORD dwIndex, UNIT* lpUnit) const; + void GetInfantryData(DWORD dwIndex, INFANTRY* lpInfantry) const; + void GetStdInfantryData(DWORD dwIndex, STDOBJECTDATA* lpStdInfantry) const; + INT GetUnitTypeID(LPCTSTR lpType); + void InitializeUnitTypes(); + BOOL AddStructure(STRUCTURE* lpStructure, LPCTSTR lpType = NULL, LPCTSTR lpHouse = NULL, DWORD dwPos = 0, CString suggestedID = ""); + BOOL AddInfantry(INFANTRY* lpInfantry, LPCTSTR lpType = NULL, LPCTSTR lpHouse = NULL, DWORD dwPos = 0, int suggestedIndex = -1); + BOOL AddNode(NODE* lpNode, WORD dwPos); + void GetStdStructureData(DWORD dwIndex, STDOBJECTDATA* lpStdStructure) const; + void GetStructureData(DWORD dwIndex, STRUCTURE* lpStructure) const; + BOOL AddWaypoint(CString lpID, DWORD dwPos); + + void DeleteNode(LPCTSTR lpHouse, DWORD dwIndex); + void DeleteTerrain(DWORD dwIndex); + void DeleteAircraft(DWORD dwIndex); + void DeleteStructure(DWORD dwIndex); + void DeleteUnit(DWORD dwIndex); + void DeleteCelltag(DWORD dwIndex); + void DeleteWaypoint(DWORD dwIndex); + void DeleteInfantry(DWORD dwIndex); + + INT GetCelltagAt(DWORD dwPos) const + { + return fielddata[dwPos].celltag; + } + INT GetCelltagAt(MapCoords pos) const + { + return GetCelltagAt(GetMapPos(pos)); + } + INT GetWaypointAt(DWORD dwPos) const + { + return fielddata[dwPos].waypoint; + } + INT GetWaypointAt(MapCoords pos) const + { + return GetWaypointAt(GetMapPos(pos)); + } + INT GetTerrainAt(DWORD dwPos) const + { + return fielddata[dwPos].terrain; + } + INT GetTerrainAt(MapCoords pos) const + { + return GetTerrainAt(GetMapPos(pos)); + } + INT GetAirAt(DWORD dwPos) const + { + return fielddata[dwPos].aircraft; + } + INT GetAirAt(MapCoords pos) const + { + return GetAirAt(GetMapPos(pos)); + } + INT GetStructureAt(DWORD dwPos) const + { + if (fielddata[dwPos].structure > -1) return fielddata[dwPos].structure; return -1; + } + INT GetStructureAt(MapCoords pos) const + { + return GetStructureAt(GetMapPos(pos)); + } + INT GetUnitAt(DWORD dwPos) const + { + return fielddata[dwPos].unit; + } + INT GetUnitAt(MapCoords pos) const + { + return GetUnitAt(GetMapPos(pos)); + } + INT GetInfantryAt(DWORD dwPos, DWORD dwSubPos = 0xFFFFFFFF) const + { + if (dwSubPos == 0xFFFFFFFF) + { + int i; + for (i = 0;i < SUBPOS_COUNT;i++) + if (fielddata[dwPos].infantry[i] != -1) + return fielddata[dwPos].infantry[i]; + return -1; + } + return fielddata[dwPos].infantry[dwSubPos]; + } + INT GetInfantryAt(MapCoords pos, DWORD dwSubPos = 0xFFFFFFFF) + { + return GetInfantryAt(GetMapPos(pos), dwSubPos); + } + INT GetNodeAt(DWORD dwPos, CString& lpHouse) const; + INT GetNodeAt(MapCoords pos, CString& lpHouse) const + { + return GetNodeAt(GetMapPos(pos), lpHouse); + } + INT GetHeightAt(DWORD dwPos) const + { + return fielddata[dwPos].bHeight; + } + INT GetHeightAt(const MapCoords& coords) const + { + return GetHeightAt(GetMapPos(coords)); + } + + const FIELDDATA* GetFielddataAt(DWORD dwPos) const + { + if (dwPos >= fielddata_size) + { + outside_f.bReserved = 1; + return &outside_f; + } + + return &fielddata[dwPos]; + }; + + FIELDDATA* GetFielddataAt(DWORD dwPos) + { + if (dwPos >= fielddata_size) + { + outside_f.bReserved = 1; + return &outside_f; + } + + return &fielddata[dwPos]; + }; + + const FIELDDATA* GetFielddataAt(const MapCoords& pos) const + { + auto dwPos = GetMapPos(pos); + if (dwPos >= fielddata_size) + { + outside_f.bReserved = 1; + return &outside_f; + } + + return &fielddata[dwPos]; + }; + + FIELDDATA* GetFielddataAt(const MapCoords& pos) + { + auto dwPos = GetMapPos(pos); + if (dwPos >= fielddata_size) + { + outside_f.bReserved = 1; + return &outside_f; + } + + return &fielddata[dwPos]; + }; + + BYTE GetOverlayDataAt(DWORD dwPos); + void SetOverlayDataAt(DWORD dwPos, BYTE bValue); + BYTE GetOverlayAt(DWORD dwPos); + void SetOverlayAt(DWORD dwPos, BYTE bValue); + void ClearOverlay(); + void ClearOverlayData(); + + const std::vector<std::unique_ptr<CTube>>& GetTubes() const + { + return m_tubes; + } + + DWORD GetIsoSize() const + { + return m_IsoSize; + } + void LoadMap(const std::string& file); + void UpdateIniFile(DWORD dwFlags = MAPDATA_UPDATE_TO_INI); + CIniFile& GetIniFile(); + CString GetAITriggerTypeID(DWORD dwAITriggerType); + DWORD GetAITriggerTypeIndex(LPCTSTR lpID); + WORD GetHouseIndex(LPCTSTR lpHouse); + void GetAITriggerType(DWORD dwAITriggerType, AITRIGGERTYPE* pAITrg); + DWORD GetAITriggerTypeCount(); + CString GetHouseID(WORD wHouse, BOOL bCountry = FALSE); + WORD GetHousesCount(BOOL bCountries = FALSE); + WORD GetHeight() const + { + return m_maprect.bottom; + }; + WORD GetWidth() const + { + return m_maprect.right; + }; + BOOL IsRulesSection(LPCTSTR lpSection); + + CMapData(); + virtual ~CMapData(); + void Pack(BOOL bCreatePreview = FALSE, BOOL bCompression = FALSE); + void Unpack(); + void UpdateTreeInfo(LPCSTR lpTreeType = NULL); + void UpdateBuildingInfo(LPCSTR lpUnitType = NULL); + void CalcMapRect(); + + // MW change: UpdateStructures() public, so that houses dialog can access it + void UpdateStructures(BOOL bSave = FALSE); + + MapCoords ToMapCoords(ProjectedCoords xy) const; + MapCoords ToMapCoords3d(ProjectedCoords xy, int mapZ) const; + MapCoords ToMapCoords3d(ProjectedCoords xy, bool bAllowAccessBehindCliffs=false, bool ignoreHideFlagsAndOutside=false) const; + ProjectedCoords ProjectCoords(MapCoords xy) const; + ProjectedCoords ProjectCoords3d(MapCoords xy) const; + ProjectedCoords ProjectCoords3d(MapCoords xy, int z) const; + bool isInside(MapCoords xy) const; + + __forceinline CPoint GetMiniMapPos(MapCoords mapCoords) + { + int x, y; + GetMiniMapPos(mapCoords.x, mapCoords.y, x, y); + return CPoint(static_cast<LONG>(x), static_cast<LONG>(y)); + } + +private: + void UpdateTubes(BOOL bSave); + MAPFIELDDATA* GetMappackPointer(DWORD dwPos); + + void UpdateMapFieldData(BOOL bSave = FALSE); + + DWORD m_IsoSize; + mutable FIELDDATA outside_f; + BOOL isInitialized; + void UpdateCelltags(BOOL bSave = FALSE); + void UpdateOverlay(BOOL bSave = FALSE); + void UpdateNodes(BOOL bSave = FALSE); + void UpdateWaypoints(BOOL bSave = FALSE); + void UpdateUnits(BOOL bSave = FALSE); + void UpdateTerrain(BOOL bSave = FALSE, int num = -1); + void UpdateInfantry(BOOL bSave = FALSE); + void UpdateAircraft(BOOL bSave = FALSE); + + + + + + map<CString, int> buildingid; + map<CString, int> terrainid; +#ifdef SMUDGE_SUPP + map<CString, int> smudgeid; +#endif + BYTE m_Overlay[262144]; // overlay byte values (extracted) + BYTE m_OverlayData[262144]; // overlay data byte values (extracted) + BYTE* m_mfd; // map field data buffer + DWORD dwIsoMapSize; + CIniFile m_mapfile; + RECT m_maprect; + RECT m_vismaprect; + FIELDDATA* fielddata; + int fielddata_size; + SNAPSHOTDATA* m_snapshots; + DWORD dwSnapShotCount; + int m_cursnapshot; + int m_money; + + vector<STRUCTUREPAINT> m_structurepaint; + + +protected: + + void InitMinimap(); + vector<std::unique_ptr<CTube>> m_tubes; + + // vectors for terrain, infantry, structures and units, as those need to be displayed very fast. + // we don´t need them for aircraft right now, as there won´t be many aircrafts on the map anyway. +#ifdef SMUDGE_SUPP + vector<SMUDGE> m_smudges; +#endif + vector<TERRAIN> m_terrain; + vector<INFANTRY> m_infantry; + vector<UNIT> m_units; + vector<STRUCTURE> m_structures; + + // we use a dib to draw the minimap + std::vector<BYTE> m_mini_colors; + BITMAPINFO m_mini_biinfo; + int m_mini_pitch; + + enum OverlayCreditsType + { + OverlayCredits_Riparius = 0, + OverlayCredits_Cruentus = 1, + OverlayCredits_Vinifera = 2, + OverlayCredits_Aboreus = 3, + OverlayCredits_NumOf + }; + + std::array<int, OverlayCredits_NumOf> m_overlayCredits; + + + __forceinline void RemoveOvrlMoney(unsigned char ovrl, unsigned char ovrld) + { + if (ovrl >= RIPARIUS_BEGIN && ovrl <= RIPARIUS_END) + { + m_money -= (ovrld + 1) * m_overlayCredits[OverlayCredits_Riparius]; + } + + if (ovrl >= CRUENTUS_BEGIN && ovrl <= CRUENTUS_END) + { + m_money -= (ovrld + 1) * m_overlayCredits[OverlayCredits_Cruentus]; + } + + if (ovrl >= VINIFERA_BEGIN && ovrl <= VINIFERA_END) + { + m_money -= (ovrld + 1) * m_overlayCredits[OverlayCredits_Vinifera]; + } + + if (ovrl >= ABOREUS_BEGIN && ovrl <= ABOREUS_END) + { + m_money -= (ovrld + 1) * m_overlayCredits[OverlayCredits_Aboreus]; + } + } + + __forceinline void AddOvrlMoney(unsigned char ovrl, unsigned char ovrld) + { + if (ovrl >= RIPARIUS_BEGIN && ovrl <= RIPARIUS_END) + { + m_money += (ovrld + 1) * m_overlayCredits[OverlayCredits_Riparius]; + } + + if (ovrl >= CRUENTUS_BEGIN && ovrl <= CRUENTUS_END) + { + m_money += (ovrld + 1) * m_overlayCredits[OverlayCredits_Cruentus]; + } + + if (ovrl >= VINIFERA_BEGIN && ovrl <= VINIFERA_END) + { + m_money += (ovrld + 1) * m_overlayCredits[OverlayCredits_Vinifera]; + } + + if (ovrl >= ABOREUS_BEGIN && ovrl <= ABOREUS_END) + { + m_money += (ovrld + 1) * m_overlayCredits[OverlayCredits_Aboreus]; + } + } + + __forceinline void GetMiniMapPos(int i, int e, int& x, int& y) + { + const int pheight = m_mini_biinfo.bmiHeader.biHeight; + + const DWORD dwIsoSize = m_IsoSize; + y = e / 2 + i / 2; + x = dwIsoSize - i + e; + + int tx, ty; + tx = GetWidth(); + ty = GetHeight(); + + ty = ty / 2 + tx / 2; + tx = dwIsoSize - GetWidth() + GetHeight(); + + x -= tx; + y -= ty; + + x += pheight; + y += pheight / 2; + } + + + __forceinline void Mini_UpdatePos(const int i, const int e, bool isMultiplayer) + { + const int pwidth = m_mini_biinfo.bmiHeader.biWidth; + const int pheight = m_mini_biinfo.bmiHeader.biHeight; + + if (m_mini_colors.empty() || !tiledata) + return; + + + const DWORD dwIsoSize = m_IsoSize; + const int pitch = m_mini_pitch; + + int x = 0; + int y = 0; + GetMiniMapPos(i, e, x, y); + y = pheight - y - 1; + + int xiso = i; + int yiso = e; + + if (xiso >= m_IsoSize) + xiso = m_IsoSize - 1; + if (yiso >= m_IsoSize) + yiso = m_IsoSize - 1; + if (xiso < 0) + xiso = 0; + if (yiso < 0) + yiso = 0; + + DWORD dwPos = xiso + yiso * dwIsoSize; + + int dwDrawPos = (x * 3 + y * pitch); + + int size = pitch * pheight; + + if (dwDrawPos >= size || x >= pwidth || y >= pheight || x < 0 || y < 0) return; + if (dwPos >= m_IsoSize * m_IsoSize) return; + if (dwDrawPos + 3 >= m_mini_colors.size()) return; + + RGBTRIPLE& col = (RGBTRIPLE&)m_mini_colors[dwDrawPos]; + RGBTRIPLE& col_r = (RGBTRIPLE&)m_mini_colors[(dwDrawPos + sizeof(RGBTRIPLE)) < size ? dwDrawPos + sizeof(RGBTRIPLE) : dwDrawPos]; + + + FIELDDATA td; + td = *GetFielddataAt(dwPos); + + + + STDOBJECTDATA sod; + sod.house = ""; + int ic; + for (ic = 0;ic < SUBPOS_COUNT;ic++) + { + if (td.infantry[ic] >= 0) + { + GetStdInfantryData(td.infantry[ic], &sod); + } + } + if (td.structure >= 0) + { + GetStdStructureData(td.structure, &sod); + } + if (td.aircraft >= 0) + { + GetStdAircraftData(td.aircraft, &sod); + } + if (td.unit >= 0) + { + GetStdUnitData(td.unit, &sod); + } + + + int ground = (td.wGround >= (*tiledata_count)) ? 0 : td.wGround; + int subt = td.bSubTile; + int ttype = 0; + if (subt < (*tiledata)[ground].wTileCount) ttype = (*tiledata)[ground].tiles[subt].bTerrainType; + + + // mw added check: + if (subt >= (*tiledata)[ground].wTileCount) return; + + RGBTRIPLE& l = (*tiledata)[ground].tiles[subt].rgbLeft; + RGBTRIPLE& r = (*tiledata)[ground].tiles[subt].rgbRight; + + int pos = GetHeightAt(dwPos); + + col.rgbtBlue = l.rgbtBlue; + col.rgbtGreen = l.rgbtGreen; + col.rgbtRed = l.rgbtRed; + col_r.rgbtBlue = r.rgbtBlue; + col_r.rgbtGreen = r.rgbtGreen; + col_r.rgbtRed = r.rgbtRed; + + if (isGreenTiberium(td.overlay)) + { +#ifndef RA2_MODE + col.rgbtBlue = 0; + col.rgbtGreen = 200; + col.rgbtRed = 0; + col_r = col; +#else + col.rgbtBlue = 0; + col.rgbtGreen = 250; + col.rgbtRed = 250; + col_r = col; +#endif + } + else if (td.overlay == OVRL_VEINS) + { + col.rgbtBlue = 120; + col.rgbtGreen = 180; + col.rgbtRed = 190; + col_r = col; + } + else if (td.overlay == OVRL_VEINHOLE || td.overlay == OVRL_VEINHOLEBORDER) + { + col.rgbtBlue = 120; + col.rgbtGreen = 160; + col.rgbtRed = 165; + col_r = col; + } + else if (td.overlay != 0xFF) + { + col.rgbtBlue = 20; + col.rgbtGreen = 20; + col.rgbtRed = 20; + col_r = col; + } + + + if (sod.house.GetLength() > 0) + { + /* + if(strstr(sod.house, houses[1].name)) + { + col.rgbtRed=255; + col.rgbtGreen=0; + col.rgbtBlue=0; + } + else if(strstr(sod.house,houses[0].name)) + { + col.rgbtRed=180; + col.rgbtGreen=180; + col.rgbtBlue=0; + } + else + { + col.rgbtRed=200; + col.rgbtGreen=200; + col.rgbtBlue=200; + }*/ + COLORREF c = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->GetColor(sod.house); + + col.rgbtRed = GetRValue(c); + col.rgbtBlue = GetBValue(c); + col.rgbtGreen = GetGValue(c); + col_r = col; + } + + // MW: ADD: make red start pos dots + if (isMultiplayer) + { + CString id; + DWORD p; + int wp = td.waypoint; + BOOL startpos = FALSE; + int i, e; + for (i = -1;i < 2;i++) + { + for (e = -1;e < 2;e++) + { + if (dwPos + i + e * m_IsoSize < fielddata_size) + { + int w = GetWaypointAt(dwPos + i + e * m_IsoSize); + if (w >= 0) + { + GetWaypointData(w, &id, &p); + if (atoi(id) < 8) + { + startpos = TRUE; + break; + } + } + + + } + } + if (startpos) break; + } + if (startpos) + { + col.rgbtBlue = 0; + col.rgbtGreen = 0; + col.rgbtRed = 255; + col_r = col; + + } + } + } + + + // helper function. Is val==iSet1 or val=iSet2? + __forceinline BOOL st(int val, int iSet) + { + + if (val == iSet) return TRUE; + return FALSE; + } + + +public: + void RedrawMinimap(); + BOOL GetInfantryINIData(int index, CString* lpINI); + + +#ifdef SMUDGE_SUPP + void UpdateSmudges(BOOL bSave = FALSE, int num = -1); + void DeleteSmudge(DWORD dwIndex); + BOOL AddSmudge(SMUDGE* lpSmudge); + void GetSmudgeData(DWORD dwIndex, SMUDGE* lpData) const; + void UpdateSmudgeInfo(LPCSTR lpSmudgeType = NULL); +#endif + + BOOL IsYRMap(); + BOOL IsMapSection(LPCSTR lpSectionName); + void ResizeMap(int iLeft, int iTop, DWORD dwNewWidth, DWORD dwNewHeight); + void SmoothTiberium(DWORD dwPos); + int GetPowerOfHouse(LPCTSTR lpHouse); + int GetMoneyOnMap() const; + int CalcMoneyOnMap(); + void GetMinimap(BYTE** lpData, BITMAPINFO* lpBI, int* pitch); + void GetStructurePaint(int index, STRUCTUREPAINT* lpStructurePaint) const; + void Paste(int x, int y, int z_mod); + void Copy(int left = 0, int top = 0, int right = 0, int bottom = 0); + CString GetTheater(); + BOOL IsMultiplayer(); + void CreateShore(int left, int top, int right, int bottom, BOOL bRemoveUseless = TRUE); + void Redo(); + void SmoothAllAt(DWORD dwPos); + + __forceinline void SmoothAt(DWORD dwPos, int iSmoothSet, int iLatSet, int iTargetSet, BOOL bIgnoreShore = TRUE) + { + int i; + int its, iss, ils; + int iLatGround = tilesets_start[iLatSet]; + int iSmoothGround = tilesets_start[iSmoothSet]; + its = (*tiledata)[tilesets_start[iTargetSet]].tiles[0].bTerrainType; + iss = (*tiledata)[iSmoothGround].tiles[0].bTerrainType; + ils = (*tiledata)[iLatGround].tiles[0].bTerrainType; + + + + FIELDDATA m = *GetFielddataAt(dwPos); + if (m.wGround == 0xFFFF) m.wGround = 0; + + // do we have that certain LAT tile here? + if ((*tiledata)[m.wGround].wTileSet != iSmoothSet && (*tiledata)[m.wGround].wTileSet != iLatSet) return; + + //if(m.wGround==iLatGround) m.wGround=iSmoothGround; + + if (its == iss && (*tiledata)[m.wGround].wTileSet == iSmoothSet) m.wGround = iLatGround; + + if (its == iss) ils += 1; + + BOOL bOnlyLat = TRUE; + //BOOL bNoLat=TRUE; + int ns = -1; + int e, p = 0; + int ts[3][3]; // terrain info + + int set = (*tiledata)[m.wGround].wTileSet; + + for (i = 0;i < 3; i++) + { + for (e = 0;e < 3;e++) + { + int pos = dwPos + (i - 1) + (e - 1) * m_IsoSize; + if (pos < 0 || pos >= fielddata_size) + { + ts[i][e] = 0; + } + else + { + FIELDDATA m2 = *GetFielddataAt(pos); + if (m2.wGround == 0xFFFF) m2.wGround = 0; + + int cur_set = (*tiledata)[m2.wGround].wTileSet; + + //if(cur_set==iSmoothSet) bNoLat=FALSE; + // + + if (its == iss && cur_set == iSmoothSet) + { + m2.wGround = iLatGround; cur_set = iLatSet; + } + + if (cur_set == iSmoothSet || cur_set == iTargetSet) bOnlyLat = FALSE; + + /*if(cur_set != iSmoothSet && cur_set!= iLatSet && cur_set!=iTargetSet) + { + ts[i][e]=(*tiledata)[m2.wGround].tiles[m2.bSubTile].bTerrainType; + if((*tiledata)[m2.wGround].wTileSet!=shoreset) + { + ts[i][e]=0;//ts[i][e]+1; // make sure you don´t smooth at it except it´s shore + } + //if(bIgnoreShore && (*tiledata)[m2.wGround].wTileSet==shoreset) + // ts[i][e]=0;//ts[i][e]+1; + } + else*/ if (its == iss && cur_set != set) + { + if (cur_set == shoreset && !bIgnoreShore) + ts[i][e] = its; + else if (cur_set != iSmoothSet && cur_set != iTargetSet && cur_set != iLatSet) + ts[i][e] = 0; + else + ts[i][e] = its; + } + else if (its == iss && cur_set == set) + ts[i][e] = ils; + else + { + ts[i][e] = (*tiledata)[m2.wGround].tiles[m2.bSubTile].bTerrainType; + + if (cur_set != shoreset && cur_set != iLatSet && cur_set != iSmoothSet) + { + ts[i][e] = 0;//ts[i][e]+1; // make sure you don´t smooth at it except it´s shore + } + + } + } + } + } + + //if(bOnlyLat) return; + + + int needed = -1; + + // 1/1 is smoothed tile + + if (ts[1][1] == ils) + { + // single lat + if (ts[0][1] != ils && ts[1][0] != ils + && ts[1][2] != ils && ts[2][1] != ils) + needed = 16; + else if (ts[0][1] == ils && ts[1][0] == ils + && ts[1][2] == ils && ts[2][1] == ils) + needed = 0; + else if (ts[0][1] == ils && ts[2][1] == ils && + ts[1][0] != ils && ts[1][2] != ils) + needed = 11; + else if (ts[1][0] == ils && ts[1][2] == ils && + ts[0][1] != ils && ts[2][1] != ils) + needed = 6; + else if (ts[1][0] != ils && ts[0][1] == ils && + ts[2][1] == ils) + needed = 9; + else if (ts[2][1] != ils && ts[1][0] == ils && + ts[1][2] == ils) + needed = 5; + else if (ts[1][2] != ils && ts[0][1] == ils && + ts[2][1] == ils) + needed = 3; + else if (ts[0][1] != ils && ts[1][0] == ils && + ts[1][2] == ils) + needed = 2; + else if (ts[0][1] == ils && ts[1][0] != ils && + ts[1][2] != ils && ts[2][1] != ils) + needed = 15; + else if (ts[1][2] == ils && ts[1][0] != ils && + ts[0][1] != ils && ts[2][1] != ils) + needed = 14; + else if (ts[2][1] == ils && ts[1][0] != ils && + ts[0][1] != ils && ts[1][2] != ils) + needed = 12; + else if (ts[1][0] == ils && ts[0][1] != ils && + ts[1][2] != ils && ts[2][1] != ils) + needed = 8; + else if (ts[1][0] != ils && ts[2][1] != ils) + needed = 13; + else if (ts[1][0] != ils && ts[0][1] != ils) + needed = 10; + else if (ts[2][1] != ils && ts[1][2] != ils) + needed = 7; + else if (ts[0][1] != ils && ts[1][2] != ils) + needed = 4; + + + } + else if (ts[1][1] == its) + { + // replace target set instead of smooth set + //if(st(ts[0][0], && ts[0][1] + } + + + needed -= 1; + if (needed >= 0) + { + /*for(i=0;i<*tiledata_count;i++) + { + if((*tiledata)[i].wTileSet==iLatSet) + { + break; + } + }*/ + i = tilesets_start[iLatSet]; + + // i is first lat tile + int e; + for (e = 0;e < needed;e++) + { + i += (*tiledata)[i].wTileCount; + } + + SetTileAt(dwPos, i, 0); + } + else if (needed == -1) + { + /*for(i=0;i<*tiledata_count;i++) + { + if((*tiledata)[i].wTileSet==iSmoothSet) + { + break; + } + }*/ + i = tilesets_start[iSmoothSet]; + + // i is first lat tile + SetTileAt(dwPos, i, 0); + } + } + + BOOL GetLocalSize(RECT* rect) const; + void Undo(); + void TakeSnapshot(BOOL bEraseFollowing = TRUE, int left = 0, int top = 0, int right = 0, int bottom = 0); + BOOL CheckMapPackData(); + int GetInfantryCountAt(DWORD dwPos); + void DeleteTube(std::uint16_t wID); + // void SetTube(WORD wID, CTube *lpTI); + void SetTube(CTube* lpTI); + CTube* GetTube(std::uint16_t wID); +}; + +inline bool CMapData::isInside(MapCoords xy) const +{ + return xy.x >= 0 && xy.y >= 0 && xy.x < m_IsoSize && xy.y < m_IsoSize; +} + +inline MapCoords CMapData::ToMapCoords(ProjectedCoords xy) const +{ + return ToMapCoords3d(xy, 0); +} + +inline MapCoords CMapData::ToMapCoords3d(ProjectedCoords xy, int mapZ) const +{ + float cx = xy.x, cy = xy.y + mapZ * f_y / 2; + return MapCoords( + cy / (float)f_y - cx / (float)f_x + (float)(m_IsoSize - 2) / 2 + (float)0.5, + cy / (float)f_y + cx / (float)f_x - (float)(m_IsoSize - 2) / 2.0f - (float)0.5 + ); +} + +inline MapCoords CMapData::ToMapCoords3d(const ProjectedCoords xy, bool bAllowAccessBehindCliffs, bool ignoreHideFlagsAndOutside) const +{ + auto xy2d = ToMapCoords(xy); + static const auto fxy = ProjectedVec(f_x, f_y).convertT<float>(); + auto ret = ignoreHideFlagsAndOutside ? xy2d : MapCoords(-1, -1); + + for (int i = 15; i >= 0; i--) + { + for (int e = 0; e < 3; e++) + { + const MapVec off(i, i); // this is a vertical line starting from the bottom + const MapVec off2(e == 1 ? -1 : 0, e == 2 ? -1 : 0); // increase x or y or neither in map coordinates by one so that we have a broader area to check + const MapCoords cur = xy2d + off + off2; + + if (isInside(cur)) + { + const auto& mfd = *GetFielddataAt(GetMapPos(cur)); + const int ground = mfd.wGround == 0xFFFF ? 0 : mfd.wGround; + if (ignoreHideFlagsAndOutside || (!mfd.bHide && !(tiledata && (*tiledata)[ground].bHide))) + { + const auto curProj = ProjectCoords3d(cur); + + // now projCoords hold the logical pixel coordinates for the current field... + // we now need to check if cx and cy are in this field + //if(*x >= m && *x<= m+f_x && *y>=n && *y<=n+f_y) + { + auto df1 = (xy - curProj).convertT<float>(); + auto dfScaled = df1 / fxy; + auto d = Vec2<CSProjected, float>(dfScaled.y - dfScaled.x + 0.5f, dfScaled.y + dfScaled.x - 0.5f); + if (d.x >= 0.0f && d.y >= 0.0f && d.x <= 1.0f && d.y <= 1.0f)// || (!bAllowAccessBehindCliffs && xy.y >= curProj.y))) + //if (d == MapCoords(0, 0)) + { + if (bAllowAccessBehindCliffs) + ret = cur; + else + return cur; + } + } + } + } + } + } + return ret; +} + +inline ProjectedCoords CMapData::ProjectCoords(MapCoords xy) const +{ + return ProjectCoords3d(xy, 0); +} + +inline ProjectedCoords CMapData::ProjectCoords3d(MapCoords xy, int z) const +{ + return ProjectedCoords( + (m_IsoSize - 2 - xy.x + xy.y) * f_x / 2, + (xy.y + xy.x - z) * f_y / 2 + ); +} + +inline ProjectedCoords CMapData::ProjectCoords3d(MapCoords xy) const +{ + return ProjectCoords3d(xy, isInside(xy) ? GetHeightAt(xy) : 0); +} + +#endif // !defined(AFX_MAP_H__9278CAC0_D4E7_11D3_B63B_444553540001__INCLUDED_) diff --git a/MissionEditor/MapLoadingDlg.cpp b/MissionEditor/MapLoadingDlg.cpp new file mode 100644 index 0000000..dad0c42 --- /dev/null +++ b/MissionEditor/MapLoadingDlg.cpp @@ -0,0 +1,65 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MapLoadingDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "MapLoadingDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CMapLoadingDlg + + +CMapLoadingDlg::CMapLoadingDlg(CWnd* pParent /*=NULL*/) + : CDialog(CMapLoadingDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CMapLoadingDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT + + Create(CMapLoadingDlg::IDD); +} + + +void CMapLoadingDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CMapLoadingDlg) + DDX_Control(pDX, IDC_PROGRESS, m_Progress); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CMapLoadingDlg, CDialog) + //{{AFX_MSG_MAP(CMapLoadingDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros fĂ¼r Nachrichten ein + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CMapLoadingDlg diff --git a/MissionEditor/MapLoadingDlg.h b/MissionEditor/MapLoadingDlg.h new file mode 100644 index 0000000..ff99f14 --- /dev/null +++ b/MissionEditor/MapLoadingDlg.h @@ -0,0 +1,66 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_MAPLOADINGDLG_H__19690341_CE13_11D4_9C87_444553540000__INCLUDED_) +#define AFX_MAPLOADINGDLG_H__19690341_CE13_11D4_9C87_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// MapLoadingDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CMapLoadingDlg + +class CMapLoadingDlg : public CDialog +{ +// Konstruktion +public: + CMapLoadingDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CMapLoadingDlg) + enum { IDD = IDD_MAPLOAD }; + CProgressCtrl m_Progress; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CMapLoadingDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CMapLoadingDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_MAPLOADINGDLG_H__19690341_CE13_11D4_9C87_444553540000__INCLUDED_ diff --git a/MissionEditor/MapModifier.cpp b/MissionEditor/MapModifier.cpp new file mode 100644 index 0000000..57fe456 --- /dev/null +++ b/MissionEditor/MapModifier.cpp @@ -0,0 +1,47 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MapModifier.cpp: Implementierung der Klasse CMapModifier. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "stdafx.h" +#include "MapModifier.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Konstruktion/Destruktion +////////////////////////////////////////////////////////////////////// + +CMapModifier::CMapModifier() +{ + +} + +CMapModifier::~CMapModifier() +{ + +} diff --git a/MissionEditor/MapModifier.h b/MissionEditor/MapModifier.h new file mode 100644 index 0000000..06cb7b4 --- /dev/null +++ b/MissionEditor/MapModifier.h @@ -0,0 +1,40 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MapModifier.h: Schnittstelle fĂ¼r die Klasse CMapModifier. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_MAPMODIFIER_H__3853D321_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) +#define AFX_MAPMODIFIER_H__3853D321_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class CMapModifier +{ +public: + CMapModifier(); + virtual ~CMapModifier(); + +}; + +#endif // !defined(AFX_MAPMODIFIER_H__3853D321_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) diff --git a/MissionEditor/MapOpenDialog.cpp b/MissionEditor/MapOpenDialog.cpp new file mode 100644 index 0000000..25eca84 --- /dev/null +++ b/MissionEditor/MapOpenDialog.cpp @@ -0,0 +1,88 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MapOpenDialog.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "MapOpenDialog.h" +#include "inlines.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CMapOpenDialog + +UINT CALLBACK OFNHookProc( + HWND hdlg, // handle to child dialog window + UINT uiMsg, // message identifier + WPARAM wParam, // message parameter + LPARAM lParam // message parameter +) +{ + if(uiMsg==WM_NOTIFY) + { + OFNOTIFY ofn; + ofn=*((OFNOTIFY*)lParam); + if(ofn.hdr.code==CDN_SELCHANGE) + { + // user selected another file + wchar_t psz[MAX_PATH] = { 0 }; // filename + CommDlg_OpenSave_GetFilePathW(GetParent(hdlg), psz, MAX_PATH); + + // lets parse the file. Only load Basic section + CIniFile CurMap; + CurMap.InsertFile(utf16ToUtf8(psz),"Basic"); + + SetDlgItemText(hdlg, IDC_MAPNAME, CurMap.sections["Basic"].values["Name"]); + + + } + else if (ofn.hdr.code==CDN_FOLDERCHANGE) + RedrawWindow(GetParent(hdlg),NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE ); + } + + return 0; +} + + +IMPLEMENT_DYNAMIC(CMapOpenDialog, CFileDialog) + +CMapOpenDialog::CMapOpenDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName, + DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) : + CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd) +{ + m_ofn.Flags|=OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK; + m_ofn.lpTemplateName=MAKEINTRESOURCE(IDD_MYOPENDIALOG); + m_ofn.lpfnHook=OFNHookProc; +} + + +BEGIN_MESSAGE_MAP(CMapOpenDialog, CFileDialog) + //{{AFX_MSG_MAP(CMapOpenDialog) + // HINWEIS - Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros ein und entfernt diese. + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + diff --git a/MissionEditor/MapOpenDialog.h b/MissionEditor/MapOpenDialog.h new file mode 100644 index 0000000..f478162 --- /dev/null +++ b/MissionEditor/MapOpenDialog.h @@ -0,0 +1,55 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_MAPOPENDIALOG_H__BA196F80_ACBA_11D3_B63B_8A39ED4C0940__INCLUDED_) +#define AFX_MAPOPENDIALOG_H__BA196F80_ACBA_11D3_B63B_8A39ED4C0940__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// MapOpenDialog.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CMapOpenDialog + +class CMapOpenDialog : public CFileDialog +{ + DECLARE_DYNAMIC(CMapOpenDialog) + +public: + CMapOpenDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + LPCTSTR lpszFilter = NULL, + CWnd* pParentWnd = NULL); + +protected: + //{{AFX_MSG(CMapOpenDialog) + // HINWEIS - Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein und entfernt diese. + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_MAPOPENDIALOG_H__BA196F80_ACBA_11D3_B63B_8A39ED4C0940__INCLUDED_ diff --git a/MissionEditor/MapTool.h b/MissionEditor/MapTool.h new file mode 100644 index 0000000..60bab55 --- /dev/null +++ b/MissionEditor/MapTool.h @@ -0,0 +1,87 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cstdint> +#include "structs.h" +#include <winnt.h> + +class CMapData; +class CIsoView; + +enum class MapToolMouseFlags +{ + DEFAULT = 0, + LBUTTON = 1, + MBUTTON = 2, + RBUTTON = 4, + SHIFT = 8 +}; +DEFINE_ENUM_FLAG_OPERATORS(MapToolMouseFlags); + +inline MapToolMouseFlags MapToolMouseFlagsFromWin32(UINT nFlags) { + + MapToolMouseFlags flags = MapToolMouseFlags::DEFAULT; + + if ((nFlags & MK_LBUTTON) == MK_LBUTTON) + flags |= MapToolMouseFlags::LBUTTON; + + if ((nFlags & MK_MBUTTON) == MK_MBUTTON) + flags |= MapToolMouseFlags::MBUTTON; + + if ((nFlags & MK_RBUTTON) == MK_RBUTTON) + flags |= MapToolMouseFlags::RBUTTON; + + if ((nFlags & MK_SHIFT) == MK_SHIFT) + flags |= MapToolMouseFlags::SHIFT; + + return flags; +} + +class MapTool +{ +public: + virtual ~MapTool() = default; + + // return false if tool has not handled this call (or doesn't want to override any caller behavior) + virtual bool onRButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) + { + return false; + }; + + virtual void onLButtonDblClick(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) {}; + virtual void onLButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) {}; + virtual void onMouseMove(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) {}; + virtual void render() {}; + +protected: + MapTool(CMapData& map, CIsoView& view) : m_map(map), m_view(view) {}; + MapTool& operator=(const MapTool& other) = delete; + + CMapData& getMap() { return m_map; } + const CMapData& getMap() const { return m_map; } + CIsoView& getView() { return m_view; } + const CIsoView& getView() const { return m_view; } + +private: + CMapData& m_map; + CIsoView& m_view; +}; \ No newline at end of file diff --git a/MissionEditor/MapValidator.cpp b/MissionEditor/MapValidator.cpp new file mode 100644 index 0000000..fbf4ec2 --- /dev/null +++ b/MissionEditor/MapValidator.cpp @@ -0,0 +1,387 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MapValidator.cpp: implementation file +// + +#include "stdafx.h" +#include "finalsun.h" +#include "MapValidator.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" +#include <algorithm> +#include <string> + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// dialog field CMapValidator + + +CMapValidator::CMapValidator(CWnd* pParent /*=NULL*/) + : CDialog(CMapValidator::IDD, pParent) +{ + //{{AFX_DATA_INIT(CMapValidator) + + //}}AFX_DATA_INIT +} + + +void CMapValidator::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CMapValidator) + DDX_Control(pDX, IDC_MAPPROBLEMS, m_MapProblemList); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CMapValidator, CDialog) + //{{AFX_MSG_MAP(CMapValidator) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// message handlers CMapValidator + +void CMapValidator::UpdateStrings() +{ + SetWindowText(GetLanguageStringACP("MapValidatorCap")); + SetDlgItemText(IDC_LPROBLEMSFOUND, GetLanguageStringACP("MapValidatorProblemsFound")); + SetDlgItemText(IDOK, GetLanguageStringACP("OK")); + SetDlgItemText(IDCANCEL, GetLanguageStringACP("Cancel")); +} + +BOOL CMapValidator::OnInitDialog() +{ + CDialog::OnInitDialog(); + + UpdateStrings(); + + m_ProblemImages.Create(16,16,ILC_COLOR8 | ILC_MASK,0, 50 ); + + CBitmap bmpIcons; + bmpIcons.LoadBitmap(IDB_MV_ICONS); + + m_ProblemImages.Add(&bmpIcons, RGB(255,255,255)); + m_MapProblemList.SetImageList(&m_ProblemImages,LVSIL_SMALL); + m_MapProblemList.SetImageList(&m_ProblemImages,LVSIL_NORMAL); + + auto col = m_MapProblemList.InsertColumn(0, ""); + //RECT r; + //m_MapProblemList.GetClientRect(&r); + + + + BOOL bSaveAble=CheckMap(); + + m_MapProblemList.SetColumnWidth(col, LVSCW_AUTOSIZE); + + + if(bSaveAble==FALSE) GetDlgItem(IDOK)->EnableWindow(FALSE); + + return TRUE; +} + +void AddItemWithNewLine(CListCtrl& ctrl, CString s, int image) +{ + s.Replace("\\n", "\n"); + int n = ctrl.GetItemCount(); + for (const auto& line : Split(s, '\n')) + { + ctrl.InsertItem(n++, line, image); + image = 2; + } +} + +/* +CMapValidator::CheckMap(); + +Returns TRUE, when the map is saveable, but may not work. +If FALSE is returned, you should not anymore allow to save the map. +*/ +BOOL CMapValidator::CheckMap() +{ + BOOL bAllow=TRUE; + + // now check the map + + Map->UpdateIniFile(MAPDATA_UPDATE_TO_INI); + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections.find("Map")==ini.sections.end() ) + { + bAllow=FALSE; + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("MV_NoMap"), 0); + } + if(ini.sections.find("Basic")==ini.sections.end() || ini.sections["Basic"].values.size()==0) + { + bAllow=FALSE; + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("MV_NoBasic"), 0); + + } + else + { + if(ini.sections["Basic"].values["Name"].GetLength()==0) + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("MV_NoName"), 1); + + if(ini.sections["Basic"].values.find("Player")==ini.sections["Basic"].values.end()) + { +#ifdef TS_MODE + if(ini.sections.find(MAPHOUSES)!=ini.sections.end() && ini.sections["Houses"].values.size()>0) + { + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("MV_HousesButNoPlayer"), 1); + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("MV_HousesInMultiplayer"), 1); + } +#endif + } + + if(ini.sections.find(MAPHOUSES)==ini.sections.end()) + { + int d=Map->GetWaypointCount(); + int below8found=0; + int i; + for(i=0;i<d;i++) + { + DWORD pos; + CString id; + Map->GetWaypointData(i, &id, &pos); + if(atoi(id)<8) + { + below8found++; + } + } + + if(below8found<8) + { + if(isFalse(ini.sections["Basic"].values["Official"])) + { + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("MV_Not8Waypoints"), 1); + } + + if(below8found<2) + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("MV_HousesNoWaypoints"), 1); + } + +#ifdef RA2_MODE + if(isTrue(ini.sections["Basic"].values["Official"])) + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("MV_OfficialYes"), 1); +#endif + + } + + int i; + for(i=0;i<ini.sections["Tags"].values.size();i++) + { + CString trigger=GetParam(*ini.sections["Tags"].GetValue(i),2); + if(ini.sections["Triggers"].FindName(trigger)<0) + { + CString error; + error=GetLanguageStringACP("MV_TriggerMissing"); + error=TranslateStringVariables(1, error, trigger); + error=TranslateStringVariables(2, error, "Tag"); + error=TranslateStringVariables(3, error, *ini.sections["Tags"].GetValueName(i)); + AddItemWithNewLine(m_MapProblemList, error, 1); + } + } + // repair triggers + for(i=0;i<ini.sections["Triggers"].values.size();i++) + { + RepairTrigger(ini.sections["Triggers"].values[*ini.sections["Triggers"].GetValueName(i)]); + } + for(i=0;i<ini.sections["Triggers"].values.size();i++) + { + CString trigger=GetParam(*ini.sections["Triggers"].GetValue(i),1); + if(ini.sections["Triggers"].FindName(trigger)<0 && trigger!="<none>") + { + CString error; + error=GetLanguageStringACP("MV_TriggerMissing"); + error=TranslateStringVariables(1, error, trigger); + error=TranslateStringVariables(2, error, "Trigger"); + error=TranslateStringVariables(3, error, *ini.sections["Triggers"].GetValueName(i)); + AddItemWithNewLine(m_MapProblemList, error, 1); + } + } + + for(i=0;i<ini.sections["TeamTypes"].values.size();i++) + { + CIniFileSection& sec=ini.sections[*ini.sections["TeamTypes"].GetValue(i)]; + CString taskforce=sec.values["TaskForce"]; + if(taskforce.GetLength()>0 && ini.sections["TaskForces"].FindValue(taskforce)<0) + { + CString error; + error=GetLanguageStringACP("MV_TaskForceMissing"); + error=TranslateStringVariables(1, error, taskforce); + error=TranslateStringVariables(2, error, *ini.sections["TeamTypes"].GetValue(i)); + AddItemWithNewLine(m_MapProblemList, error, 1); + } + } + for(i=0;i<ini.sections["TeamTypes"].values.size();i++) + { + CIniFileSection& sec=ini.sections[*ini.sections["TeamTypes"].GetValue(i)]; + CString scripttype=sec.values["Script"]; + if(scripttype.GetLength()>0 && ini.sections["ScriptTypes"].FindValue(scripttype)<0) + { + CString error; + error=GetLanguageStringACP("MV_ScripttypeMissing"); + error=TranslateStringVariables(1, error, scripttype); + error=TranslateStringVariables(2, error, *ini.sections["TeamTypes"].GetValue(i)); + AddItemWithNewLine(m_MapProblemList, error, 1); + } + } + for(i=0;i<ini.sections["TeamTypes"].values.size();i++) + { + CIniFileSection& sec=ini.sections[*ini.sections["TeamTypes"].GetValue(i)]; + if(sec.FindName("Tag")>=0) + { + CString tag=sec.values["Tag"]; + if(ini.sections["Tags"].FindName(tag)<0) + { + CString error; + error=GetLanguageStringACP("MV_TagMissing"); + error=TranslateStringVariables(1, error, tag); + error=TranslateStringVariables(2, error, "Teamtype"); + error=TranslateStringVariables(3, error, *ini.sections["TeamTypes"].GetValue(i)); + AddItemWithNewLine(m_MapProblemList, error, 1); + } + } + } + for(i=0;i<Map->GetCelltagCount();i++) + { + CString tag; + DWORD pos; + Map->GetCelltagData(i, &tag, &pos); + int x=pos%Map->GetIsoSize(); + int y=pos/Map->GetIsoSize(); + char cx[50]; + char cy[50]; + itoa(x, cx, 10); + itoa(y, cy, 10); + CString p=cx; + p+="/"; + p+=cy; + if(ini.sections["Tags"].FindName(tag)<0) + { + CString error; + error=GetLanguageStringACP("MV_TagMissing"); + error=TranslateStringVariables(1, error, tag); + error=TranslateStringVariables(2, error, "Celltag"); + error=TranslateStringVariables(3, error, p); + AddItemWithNewLine(m_MapProblemList, error, 1); + } + } + + } + + const auto& tubes = Map->GetTubes(); + for (auto& tube : tubes) + { + auto n_reverse = std::count_if(tubes.begin(), tubes.end(), [&tube](const auto& other) { return tube->isCounterpart(*other); }); + if (n_reverse == 0) + { + CString error = TranslateTubeString( + GetLanguageStringACP("MV_TubeCounterpartMissing"), + *tube, + n_reverse + ); + AddItemWithNewLine(m_MapProblemList, error, 0); + } + auto n_same_start = std::count_if(tubes.begin(), tubes.end(), [&tube](const auto& other) { return tube->getStartCoords() == other->getStartCoords() && *tube != *other; }); + if (n_same_start) + { + CString error = TranslateTubeString( + GetLanguageStringACP("MV_TubeStartNotUnique"), + *tube, + n_same_start + ); + AddItemWithNewLine(m_MapProblemList, error, 0); + } + auto n_same_end = std::count_if(tubes.begin(), tubes.end(), [&tube](const auto& other) { return tube->getEndCoords() == other->getEndCoords() && *tube != *other; }); + if (n_same_end) + { + CString error = TranslateTubeString( + GetLanguageStringACP("MV_TubeEndNotUnique"), + *tube, + n_same_end + ); + AddItemWithNewLine(m_MapProblemList, error, 0); + } + auto n_invalid_counterpart_end = std::count_if(tubes.begin(), tubes.end(), [&tube](const auto& other) { return tube->getEndCoords() == other->getStartCoords() && tube->getStartCoords() != other->getEndCoords(); }); + if (n_invalid_counterpart_end) + { + CString error = TranslateTubeString( + GetLanguageStringACP("MV_TubeInvalidCounterpartEnd"), + *tube, + n_invalid_counterpart_end + ); + AddItemWithNewLine(m_MapProblemList, error, 0); + } + auto n_invalid_counterpart_start = std::count_if(tubes.begin(), tubes.end(), [&tube](const auto& other) { return tube->getStartCoords() == other->getEndCoords() && tube->getEndCoords() != other->getStartCoords(); }); + if (n_invalid_counterpart_start) + { + CString error = TranslateTubeString( + GetLanguageStringACP("MV_TubeInvalidCounterpartStart"), + *tube, + n_invalid_counterpart_start + ); + AddItemWithNewLine(m_MapProblemList, error, 0); + } + } + + int i; + BOOL bWaypBig=FALSE; + for(i=0;i<Map->GetWaypointCount();i++) + { + DWORD pos; + CString id; + + Map->GetWaypointData(i, &id, &pos); + + if(atoi(id)>99) bWaypBig=TRUE; + } + + if(bWaypBig) + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("MV_>100Waypoint"), 1); + + if(Map->IsYRMap()) + { + AddItemWithNewLine(m_MapProblemList, GetLanguageStringACP("NeedsYR"), 1); + } + + return bAllow; +} + +CString TranslateTubeString(const char* error_, const CTube& tube, int count) +{ + CString error = error_; + error = TranslateStringVariables(1, error, std::to_string(tube.getStartX()).c_str()); + error = TranslateStringVariables(2, error, std::to_string(tube.getStartY()).c_str()); + error = TranslateStringVariables(3, error, std::to_string(tube.getEndX()).c_str()); + error = TranslateStringVariables(4, error, std::to_string(tube.getEndY()).c_str()); + error = TranslateStringVariables(5, error, std::to_string(tube.getId()).c_str()); + error = TranslateStringVariables(6, error, std::to_string(count).c_str()); + return error; +} diff --git a/MissionEditor/MapValidator.h b/MissionEditor/MapValidator.h new file mode 100644 index 0000000..7097b27 --- /dev/null +++ b/MissionEditor/MapValidator.h @@ -0,0 +1,73 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_MAPVALIDATOR_H__B290D180_F761_11D3_B63B_00485453E8BA__INCLUDED_) +#define AFX_MAPVALIDATOR_H__B290D180_F761_11D3_B63B_00485453E8BA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// MapValidator.h : Header file +// + +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +// dialog field CMapValidator + +class CMapValidator : public CDialog +{ +// construction +public: + CMapValidator(CWnd* pParent = NULL); // standard constructor + +// dialog field data + //{{AFX_DATA(CMapValidator) + enum { IDD = IDD_MAPVALIDATOR }; + + //}}AFX_DATA + + +// overwriteables + //{{AFX_VIRTUAL(CMapValidator) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// implementation +protected: + + // generated message maps + //{{AFX_MSG(CMapValidator) + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + CImageList m_ProblemImages; + CListCtrl m_MapProblemList; + void UpdateStrings(); + BOOL CheckMap(); +}; + +//{{AFX_INSERT_LOCATION}} + +#endif // AFX_MAPVALIDATOR_H__B290D180_F761_11D3_B63B_00485453E8BA__INCLUDED_ + +CString TranslateTubeString(const char* error_, const CTube& tube, int count); diff --git a/MissionEditor/MiniMap.cpp b/MissionEditor/MiniMap.cpp new file mode 100644 index 0000000..69f5b01 --- /dev/null +++ b/MissionEditor/MiniMap.cpp @@ -0,0 +1,302 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MiniMap.cpp: implementaion file +// + +#include "stdafx.h" +#include "finalsun.h" +#include "MiniMap.h" +#include "finalsundlg.h" +#include "macros.h" +#include "mapdata.h" +#include "variables.h" +#include "inlines.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CMiniMap + +IMPLEMENT_DYNCREATE(CMiniMap, CView) + +CMiniMap::CMiniMap(): m_scale(theApp.m_Options.fMiniMapScale) +{ +} + +CMiniMap::~CMiniMap() +{ +} + + +BEGIN_MESSAGE_MAP(CMiniMap, CView) + //{{AFX_MSG_MAP(CMiniMap) + ON_WM_SYSCOMMAND() + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONDOWN() + //}}AFX_MSG_MAP + ON_WM_SIZING() + ON_WM_SETCURSOR() +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// draw CMiniMap + +void CMiniMap::OnDraw(CDC* pDC) +{ + + BYTE* colors; + BITMAPINFO biinfo; + int pitch; + DrawMinimap(&colors, biinfo, pitch); + + if(!colors) return; + + // set the bits + //SetDIBitsToDevice(pDC->m_hDC, 0, 0, Map->GetWidth()*2, Map->GetHeight(),0,0,0, Map->GetHeight(), colors, &biinfo, DIB_RGB_COLORS); + RECT r; + GetClientRect(&r); + StretchDIBits(pDC->m_hDC, 0, 0, r.right, r.bottom, 0, 0, Map->GetWidth() * 2, Map->GetHeight(), colors, &biinfo, DIB_RGB_COLORS, SRCCOPY); + + + // now draw the current position + CFinalSunDlg& dlg=*(CFinalSunDlg*)theApp.GetMainWnd(); + CIsoView& isoview=*dlg.m_view.m_isoview; + RECT selRect; + auto isoRect = isoview.GetScaledDisplayRect(); + + int mapwidth=Map->GetWidth(); + int mapheight=Map->GetHeight(); + + + // Get iso view display rectangle + RECT cr; + isoview.GetClientRect(&cr); + auto topLeft = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(0, 0), false, true)); + auto topRight = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, 0), false, true)); + auto bottomLeft = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(0, cr.bottom), false, true)); + auto bottomRight = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, cr.bottom), false, true)); + auto left = min(topLeft.x, topRight.x); + auto top = min(topLeft.y, topRight.y); + auto right = max(bottomLeft.x, bottomRight.x); + auto bottom = max(bottomLeft.y, bottomRight.y); + + CPoint center(r.right / 2, r.bottom / 2); + selRect.left = left * m_scale; + selRect.top = top * m_scale; + selRect.right = right * m_scale; + selRect.bottom = bottom * m_scale; + + + pDC->Draw3dRect(&selRect, RGB(200,0,0), RGB(120,0,0)); + +} + +///////////////////////////////////////////////////////////////////////////// +// diagnose CMiniMap + +#ifdef _DEBUG +void CMiniMap::AssertValid() const +{ + CView::AssertValid(); +} + +void CMiniMap::Dump(CDumpContext& dc) const +{ + CView::Dump(dc); +} +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// handlers + +BOOL CMiniMap::PreCreateWindow(CREATESTRUCT& cs) +{ + // MW 07/17/2001: Style changed + + cs.style = WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU;// | WS_CHILD; + cs.cx=0; + cs.cy=0; + + CFinalSunDlg& dlg=*(CFinalSunDlg*)theApp.GetMainWnd(); + //CIsoView& isoview=*dlg.m_view.m_isoview; + RECT r; + dlg.GetWindowRect(&r); + + cs.x=0;//r.right-250 ; + cs.y=r.bottom-250; + if(cs.y<0) cs.y=0; + //cs.dwExStyle=WS_EX_TOOLWINDOW; + //cs.dwExStyle=WS_EX_PALETTEWINDOW; + + // this here will cause an assert in debug mode, ignore it (window must be a child window) + int res=CWnd::PreCreateWindow(cs); + + cs.style=WS_POPUPWINDOW | WS_CAPTION /*| WS_DLGFRAME */ | WS_THICKFRAME | WS_OVERLAPPED | DS_3DLOOK | WS_MINIMIZEBOX; //WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX; + + return res; + +} + +void CMiniMap::UpdateView() +{ + CRect r; + GetWindowRect(r); + + if(Map->GetIsoSize()==0) + { + ShowWindow(SW_HIDE); + } + else + { + // calculate the needed width=height + int axissizex=Map->GetWidth()*2; + int axissizey=Map->GetHeight(); + + SetIcon(theApp.m_pMainWnd->GetIcon(FALSE), FALSE); + SetIcon(theApp.m_pMainWnd->GetIcon(TRUE), TRUE); + SetWindowPos(&wndTopMost, r.left, r.top, axissizex * m_scale + 2 * (GetSystemMetrics(SM_CXFIXEDFRAME)), axissizey * m_scale + 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION), SWP_SHOWWINDOW); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + + +} + + +BOOL bMiniMapClosedByUser=FALSE; + +void CMiniMap::OnSysCommand(UINT nID, LPARAM lParam) +{ + + if(nID==SC_CLOSE) + { + bMiniMapClosedByUser=TRUE; + ShowWindow(SW_HIDE); + return; + } + + CWnd::OnSysCommand(nID, lParam); +} + + +void CMiniMap::OnMouseMove(UINT nFlags, CPoint point) +{ + if(nFlags==MK_LBUTTON) + { + int x,y; + int xiso; + int yiso; + + //y=Map->GetIsoSize()-(point.y - point.x+ /*(float)Map->GetIsoSize()/2.0f*/+1); + //x=Map->GetIsoSize()-(point.x + point.y- /*(float)Map->GetIsoSize()/2.0f*/+1); + //y-=Map->GetHeight(); + + RECT cr; + GetClientRect(&cr); + float defaultXSize = (Map->GetWidth() * 2 * m_scale); + float defaultYSize = (Map->GetHeight() * m_scale); + float resizedXScale = cr.right / defaultXSize; + float resizedYScale = cr.bottom / defaultYSize; + + CFinalSunDlg& dlg = *(CFinalSunDlg*)theApp.GetMainWnd(); + CIsoView& isoview = *dlg.m_view.m_isoview; + + auto viewScale = isoview.GetViewScale(); + auto viewOffset = isoview.GetViewOffset(); + + x = (point.x / m_scale / resizedXScale) / 2 +Map->GetHeight() / 2; + y = (point.y / m_scale / resizedYScale) + Map->GetWidth() / 2; + + + RECT r = isoview.GetScaledDisplayRect(); + + + isoview.SetScroll((x-r.right/f_x/2)*f_x, (y-r.bottom/f_y/2)*f_y); + + + isoview.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } +} + +void CMiniMap::OnLButtonDown(UINT nFlags, CPoint point) +{ + + OnMouseMove(nFlags, point); +} + +void CMiniMap::DrawMinimap(BYTE **lpData, BITMAPINFO &biinfo, int& Pitch) +{ + Map->GetMinimap(lpData, &biinfo, &Pitch); + + // fix straw pixels + auto* data = *lpData; + if (data) + { + // fix bottom left and right top pixels in the bottom-up bitmap + memcpy(&data[0], &data[sizeof(RGBTRIPLE)], sizeof(RGBTRIPLE)); + auto firstLine = (biinfo.bmiHeader.biHeight - 1) * Pitch; + memcpy(&data[firstLine + (biinfo.bmiHeader.biWidth - 1) * sizeof(RGBTRIPLE)], &data[firstLine + (biinfo.bmiHeader.biWidth - 2) * sizeof(RGBTRIPLE)], sizeof(RGBTRIPLE)); + } +} + + + +void CMiniMap::OnSizing(UINT fwSide, LPRECT pRect) +{ + CView::OnSizing(fwSide, pRect); + + int axissizex = Map->GetWidth() * 2; + int axissizey = Map->GetHeight(); + float ratio = float(axissizex) / float(axissizey); + + if (pRect) + { + int heightAdd = 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION); + int widthAdd = 2 * GetSystemMetrics(SM_CXFIXEDFRAME); + if (fwSide == WMSZ_LEFT || fwSide == WMSZ_TOPLEFT || fwSide == WMSZ_BOTTOMLEFT || + fwSide == WMSZ_RIGHT || fwSide == WMSZ_BOTTOMRIGHT) + { + pRect->bottom = pRect->top + (pRect->right - pRect->left - widthAdd) / ratio + heightAdd; + } + else + { + pRect->right = pRect->left + (pRect->bottom - pRect->top - heightAdd) * ratio + widthAdd; + } + } + + //width = axissizex* m_scale + 2 * (GetSystemMetrics(SM_CXFIXEDFRAME)) + + m_scale = ((pRect->right - pRect->left) - 2 * GetSystemMetrics(SM_CXFIXEDFRAME)) / (float)axissizex; + + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + + +BOOL CMiniMap::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + if (!CView::OnSetCursor(pWnd, nHitTest, message)) + SetCursor(m_hArrowCursor); + return TRUE; +} diff --git a/MissionEditor/MiniMap.h b/MissionEditor/MiniMap.h new file mode 100644 index 0000000..5893261 --- /dev/null +++ b/MissionEditor/MiniMap.h @@ -0,0 +1,84 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_MINIMAP_H__43F7CCE0_CC11_11D3_B63B_00485453E8BA__INCLUDED_) +#define AFX_MINIMAP_H__43F7CCE0_CC11_11D3_B63B_00485453E8BA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// MiniMap.h : Header file +// + +///////////////////////////////////////////////////////////////////////////// +// View CMiniMap + +class CMiniMap : public CView +{ +public: + CMiniMap(); + virtual ~CMiniMap(); + DECLARE_DYNCREATE(CMiniMap) + +// attributes +public: + +// operations +public: + void DrawMinimap(BYTE** lpData, BITMAPINFO& biinfo, int& Pitch); + + void UpdateView(); + +// overwriteables + //{{AFX_VIRTUAL(CMiniMap) + protected: + virtual void OnDraw(CDC* pDC); + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + //}}AFX_VIRTUAL + +// Implementierung +protected: +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + + + // generated message maps +protected: + //{{AFX_MSG(CMiniMap) + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +private: + float m_scale; +public: + afx_msg void OnSizing(UINT fwSide, LPRECT pRect); + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} + +#endif // AFX_MINIMAP_H__43F7CCE0_CC11_11D3_B63B_00485453E8BA__INCLUDED_ diff --git a/MissionEditor/MissionEditor.rc b/MissionEditor/MissionEditor.rc new file mode 100644 index 0000000..457be9a --- /dev/null +++ b/MissionEditor/MissionEditor.rc @@ -0,0 +1,3614 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Deutsch (Deutschland) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(65001)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\FinalSun.rc2"" // Nicht mit Microsoft Visual C++ bearbeitete Ressourcen\r\n" + "#include ""afxres.rc"" // Standardkomponenten\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Deutsch (Deutschland) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Englisch (USA) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +///////////////////////////////////////////////////////////////////////////// +// +// Cursor +// + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDC_EDITOR_ARROW$(TS_MODE) CURSOR "res\\ts_arrow.cur" + +#else +IDC_EDITOR_ARROW CURSOR "res\\ts_arrow.cur" + +#endif +#endif +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDC_EDITOR_ARROW$(RA2_MODE) CURSOR "res\\ra2_arrow.cur" + +#else +IDC_EDITOR_ARROW CURSOR "res\\ra2_arrow.cur" + +#endif +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDB_FLAG$(TS_MODE) BITMAP "res\\wp_ts.bmp" + +#else +IDB_FLAG BITMAP "res\\wp_ts.bmp" + +#endif +#endif +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDB_CELLTAG$(TS_MODE) BITMAP "res\\celltag_ts.bmp" + +#else +IDB_CELLTAG BITMAP "res\\celltag_ts.bmp" + +#endif +#endif +IDB_LIGHTBULB BITMAP "res\\litebulb.bmp" + +IDB_MV_ICONS BITMAP "res\\bmp00005.bmp" + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDB_SCROLLCURSOR$(TS_MODE) BITMAP "res\\scrollcursor_ts.bmp" + +#else +IDB_SCROLLCURSOR BITMAP "res\\scrollcursor_ts.bmp" + +#endif +#endif +IDR_MAINFRAME BITMAP "res\\Toolbar.bmp" + +IDR_TERRAINBAR BITMAP "res\\terrainb.bmp" + +IDR_CLIFFBAR BITMAP "res\\clifftoo.bmp" + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDB_CELLTAG$(RA2_MODE) BITMAP "res\\celltag_ra2.bmp" + +#else +IDB_CELLTAG BITMAP "res\\celltag_ra2.bmp" + +#endif +#endif +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDB_FLAG$(RA2_MODE) BITMAP "res\\wp_ra2.bmp" + +#else +IDB_FLAG BITMAP "res\\wp_ra2.bmp" + +#endif +#endif +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDB_SCROLLCURSOR$(RA2_MODE) BITMAP "res\\scrollcursor_ra2.bmp" + +#else +IDB_SCROLLCURSOR BITMAP "res\\scrollcursor_ra2.bmp" + +#endif +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NEWRA2HOUSE DIALOG 0, 0, 186, 52 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Create new house" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + LTEXT "Choose parent country:",IDC_STATIC,7,7,98,12 + COMBOBOX IDC_COUNTRY,7,20,112,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_SAVEOPTIONS$(TS_MODE) DIALOG 0, 0, 233, 125 +#else +IDD_SAVEOPTIONS DIALOG 0, 0, 233, 125 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Save options" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,176,104,50,14 + PUSHBUTTON "Cancel",IDCANCEL,117,104,50,14 + CONTROL "Compress map",IDC_COMPRESS,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE | WS_GROUP,19,42,118,12 + CONTROL "Don't compress map (use this if any problems with the map occur in RA2/TS)",IDC_NOCOMPRESSION, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE | NOT WS_VISIBLE,19,52,192,21 + CONTROL "Create new preview using minimap",IDC_PREVIEWMODE, + "Button",BS_AUTORADIOBUTTON | WS_GROUP,19,40,150,13 + CONTROL "Use existing preview (if possible)",IDC_EXISTINGPREVIEW, + "Button",BS_AUTORADIOBUTTON,19,53,141,12 + CONTROL "Don't save any preview",IDC_NOPREVIEW,"Button",BS_AUTORADIOBUTTON,19,66,141,12 + GROUPBOX "Compression",IDC_STATIC,7,28,219,52,NOT WS_VISIBLE + GROUPBOX "Preview",IDC_STATIC,7,29,219,56 + LTEXT "If you want to play the map online, you should try to make the file size as low as possible. This includes turning off the preview. You should also try using compression.",IDC_STATIC,7,90,219,27,NOT WS_VISIBLE + LTEXT "Map name:",IDC_STATIC,7,7,63,13 + EDITTEXT IDC_MAPNAME,73,7,153,12,ES_AUTOHSCROLL +END +#endif + +IDD_MULTISAVEOPT DIALOG 0, 0, 281, 105 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Specify file type" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,224,84,50,14 + PUSHBUTTON "Cancel",IDCANCEL,161,84,50,14 + LTEXT "Please specify if you want to save your multiplayer map as *.mmx map or as *.mpr map. While *.mmx maps are the recommended method, as they are fully supported and do not slow down RA2 when loading, they are never transferred automatically to other players!",IDC_STATIC,7,7,267,38 + CONTROL "Save as *.mmx (no automatic map transfer)",IDC_MMX, + "Button",BS_AUTORADIOBUTTON | WS_GROUP,7,47,267,15 + CONTROL "Save as *.mpr (many mprs slow down RA2 while loading)",IDC_MMX2, + "Button",BS_AUTORADIOBUTTON,7,59,267,15 +END + +IDD_MMXOPTIONS DIALOG 0, 0, 268, 172 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "MMX options" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,211,151,50,14 + PUSHBUTTON "Cancel",IDCANCEL,141,151,50,14 + LTEXT "If description tag does not exist, RA2 will place MISSING: in front of the map name, this does not affect the game!",IDC_STATIC,7,7,254,21 + LTEXT "Description tag:",IDC_STATIC,7,37,80,12 + EDITTEXT IDC_DESCRIPTION,90,37,171,15,ES_AUTOHSCROLL + CONTROL "Standard",IDC_STANDARD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,89,80,14 + CONTROL "Meatgrind",IDC_MEATGRIND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,92,90,80,14 + CONTROL "Naval War",IDC_NAVALWAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,174,90,80,14 + CONTROL "Nuke War",IDC_NUKEWAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,105,80,14 + CONTROL "Air War",IDC_AIRWAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,92,105,80,14 + CONTROL "Mega Wealth",IDC_MEGAWEALTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,174,105,80,14 + CONTROL "Duel",IDC_DUEL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,121,80,14 + CONTROL "Cooperative",IDC_COOPERATIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,92,121,80,14 + LTEXT "Min players:",IDC_STATIC,7,63,54,12 + COMBOBOX IDC_MINPLAYERS,89,62,40,103,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Max players:",IDC_STATIC,148,63,54,12 + COMBOBOX IDC_MAXPLAYERS,221,61,40,104,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP +END + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_SAVEOPTIONS$(RA2_MODE) DIALOG 0, 0, 233, 186 +#else +IDD_SAVEOPTIONS DIALOG 0, 0, 233, 186 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Save options" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,176,165,50,14 + PUSHBUTTON "Cancel",IDCANCEL,117,165,50,14 + CONTROL "Compress map",IDC_COMPRESS,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE | WS_GROUP,201,46,25,8 + CONTROL "Don't compress map (use this if any problems with the map occur in RA2/TS)",IDC_NOCOMPRESSION, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE | NOT WS_VISIBLE,184,62,42,13 + CONTROL "Create new preview using minimap",IDC_PREVIEWMODE, + "Button",BS_AUTORADIOBUTTON | WS_GROUP,19,40,150,13 + CONTROL "Use existing preview (if possible)",IDC_EXISTINGPREVIEW, + "Button",BS_AUTORADIOBUTTON,19,53,141,12 + CONTROL "Don't save any preview",IDC_NOPREVIEW,"Button",BS_AUTORADIOBUTTON,19,66,141,12 + GROUPBOX "Compression",IDC_STATIC,119,52,107,15,NOT WS_VISIBLE + GROUPBOX "Preview",IDC_STATIC,7,29,219,56 + LTEXT "If you want to play the map online, you should try to make the file size as low as possible. This includes turning off the preview.",IDC_STATIC,7,143,219,21 + LTEXT "Map name:",IDC_STATIC,7,7,63,13 + EDITTEXT IDC_MAPNAME,73,7,153,12,ES_AUTOHSCROLL + CONTROL "Standard",IDC_STANDARD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,89,67,14 + CONTROL "Meatgrind",IDC_MEATGRIND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,83,90,65,14 + CONTROL "Naval War",IDC_NAVALWAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,161,90,65,14 + CONTROL "Nuke War",IDC_NUKEWAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,105,66,14 + CONTROL "Air War",IDC_AIRWAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,83,105,65,14 + CONTROL "Mega Wealth",IDC_MEGAWEALTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,161,105,80,14 + CONTROL "Land Rush",IDC_DUEL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,121,59,14 + CONTROL "Cooperative",IDC_COOPERATIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,83,121,70,14 + CONTROL "Team Alliance",IDC_TEAMGAME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,161,121,65,14 +END +#endif + +IDD_CHANGESIZE DIALOG 0, 0, 212, 194 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Change Map Size" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,155,173,50,14 + PUSHBUTTON "Cancel",IDCANCEL,97,173,50,14 + LTEXT "Please specify the new width and height of the map. Left and top will automatically be set so that the old area of the map is centered. You can change left and top to modify the left-top position (you may use negative numbers for left/top).",IDC_STATIC,7,7,198,36 + LTEXT "Width:",IDC_STATIC,7,54,71,13 + EDITTEXT IDC_WIDTH,86,52,62,15,ES_AUTOHSCROLL + LTEXT "Note: If there are any units, buildings, waypoints etc. outside of the new map area, they will be deleted.",IDC_STATIC,7,132,198,19 + LTEXT "Height:",IDC_STATIC,7,72,71,13 + EDITTEXT IDC_HEIGHT,86,70,62,15,ES_AUTOHSCROLL + LTEXT "Left:",IDC_STATIC,7,90,71,13 + EDITTEXT IDC_LEFT,86,88,62,15,ES_AUTOHSCROLL + LTEXT "Top:",IDC_STATIC,7,108,71,13 + EDITTEXT IDC_TOP,86,106,62,15,ES_AUTOHSCROLL + LTEXT "UNDO IS NOT AVAILABLE!",IDC_STATIC,7,152,198,16 +END + +IDD_AITRIGGERADD DIALOG 0, 0, 222, 97 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enable AI Trigger" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,165,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,165,24,50,14 + LTEXT "Select AI Trigger that should be enabled:",IDC_STATIC,7,7,136,21 + LISTBOX IDC_AITRIGGERS,7,48,208,42,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP +END + +IDD_MYOPENDIALOG DIALOGEX 0, 0, 222, 30 +STYLE DS_LOCALEDIT | DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_TRANSPARENT +FONT 8, "Tahoma", 0, 0, 0x1 +BEGIN + LTEXT "Map name:",IDC_STATIC,5,4,41,14 + EDITTEXT IDC_MAPNAME,54,4,155,14,ES_AUTOHSCROLL +END + +IDD_TIP DIALOGEX 0, 0, 275, 174 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Tip of the day" +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + LTEXT "TIP",IDC_TIPSTRING,28,63,177,60 + CONTROL "&Show tips at program start",IDC_STARTUP,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,13,152,134,10 + PUSHBUTTON "&Next tip",IDC_NEXTTIP,157,152,52,14,WS_GROUP + DEFPUSHBUTTON "&Close",IDOK,216,152,50,14,WS_GROUP + CONTROL "",IDC_TOOLTIPCENTER,"Static",SS_BLACKFRAME,12,11,251,134 +END + +IDD_FINALSUN_DIALOG DIALOGEX 0, 0, 414, 287 +STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR | WS_EX_APPWINDOW +CAPTION "FinalAlert 2" +MENU IDR_MAIN +FONT 8, "Tahoma", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "just to prohibite enter to quit.",IDOK,0,124,21,12,NOT WS_VISIBLE + PUSHBUTTON "and that one to prevent cancelling",IDCANCEL,5,191,18,8,NOT WS_VISIBLE + LTEXT "As FinalAlert was dialog based in earlier versions, we need to have this.",IDC_STATIC,7,156,26,26 +END + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_TSOPTIONS$(RA2_MODE) DIALOGEX 0, 0, 197, 183 +#else +IDD_TSOPTIONS DIALOGEX 0, 0, 197, 183 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_NOFAILCREATE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Options" +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,140,159,50,14 + PUSHBUTTON "Cancel",IDCANCEL,85,159,50,14 + LTEXT "Red Alert 2 EXE (make sure its in the correct path)",IDC_STATIC,5,5,130,20 + EDITTEXT IDC_EDIT1,5,25,130,15,ES_AUTOHSCROLL + PUSHBUTTON "Browse",IDC_CHOOSE,140,25,50,15 + LTEXT "Language / Sprache:",IDC_STATIC,7,51,128,11 + COMBOBOX IDC_LANGUAGE,7,63,183,94,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Support settings",IDC_STATIC,7,81,183,71 + CONTROL "Support mission disks and mods (recommended)",IDC_RULESLIKETS, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE | WS_GROUP,14,92,170,16 + CONTROL "Only support original Red Alert 2",IDC_ONLYORIGINAL, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,14,108,168,16 + CONTROL "Prefer FinalAlert 2 theater INI files",IDC_PREFER_LOCAL_THEATER_FILES, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,131,164,12 +END +#endif + +IDD_ALL DIALOG 0, 0, 303, 204 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "INI Editor" +FONT 8, "Tahoma" +BEGIN + LTEXT "We highly recommend not to use this editor except you really know what you are doing.",IDC_STATIC,6,5,290,15 + LTEXT "Sections:",IDC_STATIC,5,25,55,10 + COMBOBOX IDC_SECTIONS,61,25,235,85,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Keys:",IDC_STATIC,15,80,40,10 + PUSHBUTTON "Add",IDC_ADDSECTION,60,40,55,15 + PUSHBUTTON "Delete",IDC_DELETESECTION,120,40,55,15 + GROUPBOX "Section content",IDC_STATIC,6,67,290,130 + LISTBOX IDC_KEYS,60,80,225,90,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Value:",IDC_STATIC,15,175,40,15 + EDITTEXT IDC_VALUE,60,175,225,12,ES_AUTOHSCROLL + PUSHBUTTON "Add",IDC_ADDKEY,15,95,40,15 + PUSHBUTTON "Delete",IDC_DELETEKEY,15,115,40,15 + PUSHBUTTON "Insert another INI file content",IDC_INISECTION,181,40,115,15 +END + +IDD_MAP DIALOG 0, 0, 303, 204 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Map Properties" +FONT 8, "Tahoma" +BEGIN + LTEXT "Except useable size just for information.",IDC_DESC,7,7,289,18 + GROUPBOX "Size of map data",IDC_SIZEFRAME,6,28,290,62 + GROUPBOX """Useable"" size",IDC_USEABLEFRAME,6,95,290,55 + LTEXT "The ""physical"" size of the map. Format: 0,0,Width,Height.",IDC_LSIZE,10,39,275,13 + EDITTEXT IDC__SIZEX,11,67,90,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "The ""useable"" size of the map. This specifies where you can place buildings etc. Has the following format: Left,Top,Right,Bottom",IDC_LUSEABLE,10,110,275,20 + EDITTEXT IDC_USESIZE,10,131,90,12,ES_AUTOHSCROLL + LTEXT "Theater:",IDC_LTHEATER,12,159,284,11 + COMBOBOX IDC_THEATER,10,170,90,45,CBS_DROPDOWN | CBS_SORT | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Change",IDC_CHANGELOCAL,111,131,70,13 + PUSHBUTTON "Change",IDC_CHANGE,212,67,70,13 + LTEXT "Width:",IDC_STATIC,12,56,93,9 + EDITTEXT IDC__SIZEY,106,67,90,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Height:",IDC_STATIC,107,56,93,9 +END + +IDD_INPUTBOX DIALOG 0, 0, 214, 70 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,160,5,50,14 + PUSHBUTTON "Cancel",IDCANCEL,160,25,50,14 + LTEXT "Static",IDC_SENTENCE,5,5,150,35 + EDITTEXT IDC_VAL,5,50,205,12,ES_AUTOHSCROLL +END + +IDD_IMPORTINI DIALOG 0, 0, 229, 150 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Insert INI file section" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,170,5,50,14 + PUSHBUTTON "Cancel",IDCANCEL,170,25,50,14 + LTEXT "Choose the sections you want to import in the map. Be careful! If you import a section that already exists, keys of the already existing section may be overwritten!",IDC_STATIC,5,5,155,35 + LISTBOX IDC_AVAILABLE,5,75,215,55,LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP + LTEXT "Available sections:",IDC_STATIC,5,65,100,10 + CONTROL "Import all sections",IDC_ALLSECTIONS,"Button",BS_AUTORADIOBUTTON,5,40,155,10 + CONTROL "Specify sections to be imported",IDC_SPECIFYSECTIONS, + "Button",BS_AUTORADIOBUTTON,5,50,150,10 + LTEXT "Select the sections you wish to import.",IDC_STATIC,5,135,215,10 +END + +IDD_LIGHTING DIALOG 0, 0, 303, 204 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Lighting Settings" +FONT 8, "Tahoma" +BEGIN + LTEXT "Lighting settings define the color of the terrain in the game, and you can specify a very dark or very bright map. Be careful, using wrong settings may cause the player to be unable to see his units.",IDC_DESC,6,5,290,25 + GROUPBOX "Normal",IDC_LNORMAL,6,35,290,65 + GROUPBOX "Ion storm settings",IDC_LIONSTORM,6,110,290,65 + LTEXT "Ambient:",IDC_LAMBIENT1,15,50,50,10 + EDITTEXT IDC_AMBIENT,65,50,75,12,ES_AUTOHSCROLL + LTEXT "Green:",IDC_LGREEN1,160,65,50,10 + EDITTEXT IDC_GREEN,210,65,75,12,ES_AUTOHSCROLL + LTEXT "Red:",IDC_LRED1,160,50,50,10 + EDITTEXT IDC_RED,210,50,75,12,ES_AUTOHSCROLL + LTEXT "Blue:",IDC_LBLUE1,160,80,50,10 + EDITTEXT IDC_BLUE,210,80,75,12,ES_AUTOHSCROLL + LTEXT "Level:",IDC_LLEVEL1,15,65,50,10 + EDITTEXT IDC_LEVEL,65,65,75,12,ES_AUTOHSCROLL + LTEXT "Ambient:",IDC_LAMBIENT2,15,125,50,10 + EDITTEXT IDC_AMBIENT2,65,125,75,12,ES_AUTOHSCROLL + LTEXT "Green:",IDC_LGREEN2,160,140,50,10 + EDITTEXT IDC_GREEN2,210,140,75,12,ES_AUTOHSCROLL + LTEXT "Red:",IDC_LRED2,160,125,50,10 + EDITTEXT IDC_RED2,210,125,75,12,ES_AUTOHSCROLL + LTEXT "Blue:",IDC_LBLUE2,160,155,50,10 + EDITTEXT IDC_BLUE2,210,155,75,12,ES_AUTOHSCROLL + LTEXT "Level:",IDC_LLEVEL2,15,140,50,10 + EDITTEXT IDC_LEVEL2,65,140,75,12,ES_AUTOHSCROLL +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_INFO$(TS_MODE) DIALOGEX 0, 0, 349, 250 +#else +IDD_INFO DIALOGEX 0, 0, 349, 250 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Info" +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,292,8,50,14 + LTEXT "© 1999-2024 ELECTRONIC ARTS INC. ALL RIGHTS RESERVED\nWestwood Studios(tm) is an Electronic Arts(tm) brand.",IDC_STATIC,7,189,334,18 + LTEXT "© 1999-2024 Electronic Arts Inc. Westwood Studios and Electronic Arts are trademarks or registered trademarks of Electronic Arts Inc. in the U.S. and/or other countries. All rights reserved.",IDC_STATIC,7,214,335,28 + EDITTEXT IDC_LICENSE_AND_COPYRIGHT,6,29,336,148,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL +END +#endif + +IDD_SPECIALFLAGS DIALOG 0, 0, 303, 137 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Special Flags" +FONT 8, "Tahoma" +BEGIN + LTEXT "Tiberium grows:",IDC_LTIBERIUMGROWS,5,22,75,10 + COMBOBOX IDC_TIBERIUMGROWS,85,22,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Tiberium spreads:",IDC_LTIBERIUMSPREADS,5,37,75,10 + COMBOBOX IDC_TIBERIUMSPREADS,85,37,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Tiberium explosive:",IDC_LTIBERIUMEXPLOSIVE,5,52,75,10 + COMBOBOX IDC_TIBERIUMEXPLOSIVE,85,52,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Destroyable bridges:",IDC_LDESTROYABLEBRIDGES,5,67,75,10 + COMBOBOX IDC_DESTROYABLEBRIDGES,85,67,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "MCV deploy:",IDC_LMCVDEPLOY,5,82,75,10 + COMBOBOX IDC_MCVDEPLOY,85,82,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Initial veteran: (initial troops have veteran status)",IDC_LINITIALVETERAN,5,97,75,25 + COMBOBOX IDC_INITIALVETERAN,85,97,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Fixed alliance:",IDC_LFIXEDALLIANCE,165,22,75,10 + COMBOBOX IDC_FIXEDALLIANCE,245,22,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Harvester immune:",IDC_LHARVESTERIMMUNE,165,37,75,10 + COMBOBOX IDC_HARVESTERIMMUNE,245,37,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Fog of war:",IDC_LFOGOFWAR,165,52,75,10 + COMBOBOX IDC_FOGOFWAR,245,52,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Inert:",IDC_LINERT,165,67,75,10 + COMBOBOX IDC_INERT,245,67,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Ion storms:",IDC_LIONSTORMS,165,82,75,10 + COMBOBOX IDC_IONSTORMS,245,82,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Meteorites:",IDC_LMETEORITES,165,97,75,10 + COMBOBOX IDC_METEORITES,245,97,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Visceroids:",IDC_LVISCEROIDS,165,112,75,10 + COMBOBOX IDC_VISCEROIDS,245,112,45,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Some settings only work under certain circumstances.",IDC_DESC,5,5,285,16 +END + +IDD_INFANTRY DIALOG 0, 0, 232, 142 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Infantry options" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,175,121,50,14 + PUSHBUTTON "Cancel",IDCANCEL,117,121,50,14 + LTEXT "House:",IDC_LHOUSE,7,6,33,11 + COMBOBOX IDC_HOUSE,47,6,65,45,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Strength:",IDC_LSTRENGTH,7,24,29,10 + CONTROL "Slider1",IDC_STRENGTH,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,47,24,70,11 + LTEXT "State:",IDC_LSTATE,7,42,40,13 + COMBOBOX IDC_STATE,47,42,65,90,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Tag:",IDC_LTAG,7,100,68,19 + COMBOBOX IDC_TAG,79,102,142,69,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Param1:",IDC_LP1,120,6,35,15 + EDITTEXT IDC_P1,155,6,65,12,ES_AUTOHSCROLL + LTEXT "Param2:",IDC_LP2,120,24,32,16 + LTEXT "Param3:",IDC_LP3,120,42,32,16 + LTEXT "Param4:",IDC_LP4,120,60,36,17 + EDITTEXT IDC_P2,155,24,65,12,ES_AUTOHSCROLL + EDITTEXT IDC_P3,155,42,65,12,ES_AUTOHSCROLL + EDITTEXT IDC_P4,155,60,65,12,ES_AUTOHSCROLL + LTEXT "",IDC_LDESC,0,133,38,8 + LTEXT "Direction:",IDC_LDIRECTION,7,60,40,10 + COMBOBOX IDC_DIRECTION,47,60,65,69,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Param5:",IDC_LP5,120,78,34,19 + EDITTEXT IDC_P5,155,78,65,12,ES_AUTOHSCROLL +END + +IDD_HOUSES DIALOG 0, 0, 303, 207 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Houses" +FONT 8, "Tahoma" +BEGIN + LTEXT "DESC [quite long]",IDC_DESC,7,5,290,43 + COMBOBOX IDC_HOUSES,77,65,220,125,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "House:",IDC_LHOUSE,7,65,64,22 + PUSHBUTTON "Add house",IDC_ADDHOUSE,227,82,70,15 + PUSHBUTTON "Standard houses",IDC_PREPAREHOUSES,75,82,70,15 + PUSHBUTTON "Delete house",IDC_DELETEHOUSE,150,82,70,15 + LTEXT "IQ:",IDC_LIQ,10,105,40,10 + COMBOBOX IDC_IQ,55,105,70,70,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Edge:",IDC_LEDGE,10,120,40,10 + COMBOBOX IDC_EDGE,55,120,70,65,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Side",IDC_LSIDE,10,135,40,10 + COMBOBOX IDC_SIDE,55,135,70,65,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Color",IDC_LCOLOR,10,150,40,10 + COMBOBOX IDC_COLOR,55,150,70,150,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Allies:",IDC_LALLIES,10,165,40,10 + EDITTEXT IDC_ALLIES,55,165,70,12,ES_AUTOHSCROLL + LTEXT "Credits (x100):",IDC_LCREDITS,10,181,40,17 + EDITTEXT IDC_CREDITS,55,179,70,12,ES_AUTOHSCROLL + LTEXT "Acts like:",IDC_LACTSLIKE,150,105,69,14 + COMBOBOX IDC_ACTSLIKE,227,105,70,50,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Nodecount:",IDC_LNODECOUNT,150,119,68,15 + COMBOBOX IDC_NODECOUNT,227,120,70,50,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Techlevel:",IDC_LTECHLEVEL,150,134,63,10 + COMBOBOX IDC_TECHLEVEL,227,135,70,135,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Build activity (%):",IDC_LBUILDACTIVITY,150,150,66,17 + COMBOBOX IDC_PERCENTBUILT,227,150,70,50,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Player control:",IDC_LPLAYERCONTROL,150,166,70,20 + COMBOBOX IDC_PLAYERCONTROL,227,166,70,50,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Human Player:",IDC_LPLAYER,7,48,65,16 + COMBOBOX IDC_HUMANPLAYER,77,49,220,70,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "",IDC_STATIC,6,98,293,102 +END + +IDD_AIRCRAFT DIALOG 0, 0, 232, 130 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Aircraft Options" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,170,110,50,14 + PUSHBUTTON "Cancel",IDCANCEL,110,110,50,14 + CONTROL "House:",IDC_LHOUSE,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,5,7,33,11 + COMBOBOX IDC_HOUSE,45,7,65,45,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Strength:",IDC_LSTRENGTH,5,25,29,10 + CONTROL "Slider1",IDC_STRENGTH,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,45,25,70,11 + LTEXT "State:",IDC_LSTATE,5,62,40,10 + COMBOBOX IDC_STATE,45,62,65,90,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Tag:",IDC_LTAG,5,90,66,14 + COMBOBOX IDC_TAG,77,90,144,69,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Param1:",IDC_LP1,116,7,40,17 + EDITTEXT IDC_P1,155,7,65,12,ES_AUTOHSCROLL + LTEXT "Param2:",IDC_LP2,116,25,37,12 + LTEXT "Recruitable:",IDC_LP3,116,43,39,15 + LTEXT "Param4:",IDC_LP4,116,62,39,18 + EDITTEXT IDC_P2,155,25,65,12,ES_AUTOHSCROLL + EDITTEXT IDC_P4,155,62,65,12,ES_AUTOHSCROLL + LTEXT "Params are unknown (integers?).",IDC_LDESC,5,120,19,10 + LTEXT "Direction:",IDC_LDIRECTION,5,43,40,10 + COMBOBOX IDC_DIRECTION,45,43,65,63,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_P3,155,43,66,62,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP +END + +IDD_BUILDING DIALOG 0, 0, 247, 190 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_CAPTION | WS_SYSMENU +CAPTION "Building options" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,190,170,50,14 + PUSHBUTTON "Cancel",IDCANCEL,131,170,50,14 + LTEXT "House:",IDC_LHOUSE,7,41,33,11 + COMBOBOX IDC_HOUSE,47,41,65,45,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Strength:",IDC_LSTRENGTH,7,57,29,10 + CONTROL "Slider1",IDC_STRENGTH,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,47,56,69,11 + LTEXT "Tag:",IDC_LTAG,7,149,39,15 + COMBOBOX IDC_TAG,47,149,193,69,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Param1:",IDC_LP1,7,87,35,13 + EDITTEXT IDC_P1,47,87,65,12,ES_AUTOHSCROLL + LTEXT "AI repairs:",IDC_LAIREPAIRS,7,102,40,14 + LTEXT "Energy:",IDC_LENERGY,7,117,38,18 + LTEXT "Upgrade count:",IDC_LUPGRADECOUNT,119,40,30,17 + LTEXT "Params are unknown (some integers, some strings?). Note: 0 means no, 1 means yes",IDC_LDESC,5,5,235,36 + LTEXT "Direction:",IDC_LDIRECTION,7,71,40,14 + COMBOBOX IDC_DIRECTION,47,71,65,58,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Spotlight:",IDC_LSPOTLIGHT,119,57,39,15 + LTEXT "Upgrade 1:",IDC_LUPGRADE1,119,72,40,14 + COMBOBOX IDC_P6,164,71,77,71,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Upgrade 2:",IDC_LUPGRADE2,119,87,40,16 + COMBOBOX IDC_P7,164,86,77,84,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Upgrade 3:",IDC_LUPGRADE3,119,102,38,15 + COMBOBOX IDC_P8,164,101,77,89,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Param 2:",IDC_LP2,120,117,35,10 + LTEXT "Show name:",IDC_LP3,120,132,40,10 + COMBOBOX IDC_P3,47,118,65,69,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_P2,47,102,65,41,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_P4,164,41,77,53,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_P5,164,56,77,79,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_P9,164,116,77,41,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_P10,164,132,77,41,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_LOADING$(TS_MODE) DIALOGEX 0, 0, 235, 165 +#else +IDD_LOADING DIALOGEX 0, 0, 235, 165 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP +FONT 8, "Tahoma", 0, 0, 0x1 +BEGIN + LTEXT "Loading...",IDC_CAP,7,7,221,9 + CONTROL "",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH,7,18,221,13,WS_EX_DLGMODALFRAME + LTEXT "Homepage: http://www.ea.com",IDC_STATIC,7,78,221,11,WS_BORDER + CTEXT "",IDC_VERSION,74,37,154,13,SS_CENTERIMAGE | SS_SUNKEN + LTEXT "Version:",IDC_LVERSION,7,37,61,9 + CTEXT "",IDC_BUILTBY,74,52,154,13,SS_CENTERIMAGE | SS_SUNKEN + LTEXT "Built by:",IDC_LBUILTBY,7,52,61,9 + LTEXT "© 1999-2024 ELECTRONIC ARTS INC. ALL RIGHTS RESERVED\nAuthored by Matthias Wagner\nWestwood Studios(tm) is an Electronic Arts(tm) brand.",IDC_STATIC,7,97,221,33 + LTEXT "This software comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it.\nFor details open Help->Info",IDC_STATIC,6,129,221,26 +END +#endif + +IDD_WAYPOINT DIALOG 0, 0, 186, 93 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Create waypoint" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,72,50,14 + PUSHBUTTON "Cancel",IDCANCEL,70,72,50,14 + LTEXT "Enter the waypoint number (note that it may already exist and be overwritten!). Or use ""Get free number"".",IDC_DESC,7,7,172,27 + EDITTEXT IDC_ID,7,45,67,16,ES_AUTOHSCROLL + LTEXT "ID:",IDC_LID,7,34,78,10 + PUSHBUTTON "Get first free number",IDC_FREE,86,45,93,16 +END + +IDD_CELLTAG DIALOG 0, 0, 212, 77 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Cell-Tag" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,155,56,50,14 + PUSHBUTTON "Cancel",IDCANCEL,95,56,50,14 + LTEXT "Tag:",IDC_LTAG,7,29,82,8 + COMBOBOX IDC_TAG,7,37,198,114,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Associate a tag with a specific cell.",IDC_LDESC,7,7,198,19 +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_TEAMTYPES$(TS_MODE) DIALOG 0, 0, 303, 206 +#else +IDD_TEAMTYPES DIALOG 0, 0, 303, 206 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Teamtypes" +FONT 8, "Tahoma" +BEGIN + LTEXT "Team types connect a trigger with task forces",IDC_STATIC,6,5,290,10 + LTEXT "Team types:",IDC_STATIC,5,20,50,10 + COMBOBOX IDC_TEAMTYPES,55,20,155,174,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "New",IDC_NEWTEAMTYPE,261,20,35,15 + PUSHBUTTON "Delete",IDC_DELETETEAMTYPE,220,20,35,15 + LTEXT "Name:",IDC_STATIC,10,51,30,10 + EDITTEXT IDC_NAME,56,51,90,12,ES_AUTOHSCROLL + LTEXT "Veteran level:",IDC_STATIC,10,66,45,15 + CONTROL "Loadable",IDC_LOADABLE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,145,55,8 + CONTROL "Full",IDC_FULL,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,155,55,8 + CONTROL "Annoyance",IDC_ANNOYANCE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,164,55,10 + CONTROL "Guard slower",IDC_GUARDSLOWER,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,175,55,8 + CONTROL "Recruiter",IDC_RECRUITER,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,185,55,8 + LTEXT "House:",IDC_STATIC,10,81,35,10 + COMBOBOX IDC_HOUSE,56,81,90,62,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Autocreate",IDC_AUTOCREATE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,145,55,8 + CONTROL "Prebuild",IDC_PREBUILD,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,155,55,8 + CONTROL "Reinforce",IDC_REINFORCE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,165,55,8 + CONTROL "Droppod",IDC_DROPPOD,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,145,55,8 + CONTROL "Whiner",IDC_WHINER,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,155,55,8 + CONTROL "Loose recruit",IDC_LOOSERECRUIT,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,165,55,8 + CONTROL "Aggressive",IDC_AGGRESSIVE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,175,55,8 + CONTROL "Suicide",IDC_SUICIDE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,185,55,8 + CONTROL "OnTransOnly",IDC_ONTRANSONLY,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,175,55,8 + CONTROL "AvoidThreats",IDC_AVOIDTHREATS,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,185,55,8 + CONTROL "Ion immune",IDC_IONIMMUNE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,185,145,60,8 + CONTROL "TransportsReturnOnUnload",IDC_TRANSPORTRETURNSONUNLOAD, + "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,185,155,100,8 + CONTROL "AreTeamMembersRecruitable",IDC_ARETEAMMEMBERSRECRUITABLE, + "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,185,165,105,8 + CONTROL "IsBaseDefense",IDC_ISBASEDEFENSE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,185,175,80,8 + CONTROL "OnlyTargetHouseEnemy",IDC_ONLYTARGETHOUSEENEMY,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,185,185,100,8 + LTEXT "Priority:",IDC_STATIC,10,96,40,10 + EDITTEXT IDC_PRIORITY,56,96,90,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Max:",IDC_STATIC,10,111,30,10 + EDITTEXT IDC_MAX,56,111,90,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Techlevel:",IDC_STATIC,10,125,40,10 + COMBOBOX IDC_TECHLEVEL,56,125,91,72,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Group:",IDC_STATIC,156,51,30,10 + GROUPBOX "Selected team type",IDC_STATIC,6,37,290,161 + COMBOBOX IDC_GROUP,200,51,90,78,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Waypoint:",IDC_STATIC,156,66,40,10 + COMBOBOX IDC_WAYPOINT,200,66,90,80,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Script:",IDC_STATIC,156,81,40,10 + COMBOBOX IDC_SCRIPT,200,81,90,205,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Task force:",IDC_STATIC,156,96,40,10 + COMBOBOX IDC_TASKFORCE,200,96,90,205,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_VETERANLEVEL,56,66,90,60,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Tag:",IDC_STATIC,156,111,40,13 + COMBOBOX IDC_TAG,200,111,90,186,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "",IDC_LTRANSPORTWAYPOINT,156,126,40,17 + COMBOBOX IDC_TRANSPORTWAYPOINT,200,126,90,80,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Mind Control Decision:",IDC_STATIC,164,4,43,16,NOT WS_VISIBLE + COMBOBOX IDC_MINDCONTROLDECISION,209,6,92,205,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + LTEXT "Mind Control Decision:",IDC_MCD_L,10,139,43,16,NOT WS_VISIBLE +END +#endif + +IDD_TASKFORCES DIALOG 0, 0, 303, 205 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Taskforces" +FONT 8, "Tahoma" +BEGIN + LTEXT "Task forces:",IDC_STATIC,7,7,71,10 + COMBOBOX IDC_TASKFORCES,87,7,199,130,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Units in task force:",IDC_STATIC,17,88,61,13 + LISTBOX IDC_UNITS,87,88,199,68,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add",IDC_ADDUNIT,17,102,61,14 + PUSHBUTTON "Delete",IDC_DELETEUNIT,17,121,61,15 + LTEXT "Group:",IDC_STATIC,17,69,61,13 + EDITTEXT IDC_GROUP,87,69,199,13,ES_AUTOHSCROLL + LTEXT "Number of units:",IDC_STATIC,16,160,62,12 + EDITTEXT IDC_NUMBERUNITS,87,160,199,14,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Unit type:",IDC_STATIC,17,179,62,12 + COMBOBOX IDC_UNITTYPE,87,179,199,183,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Selected task force",IDC_STATIC,7,45,290,153 + PUSHBUTTON "Delete",IDC_DELETETASKFORCE,222,23,64,15 + PUSHBUTTON "Add",IDC_ADDTASKFORCE,153,23,64,15 + LTEXT "Name:",IDC_STATIC,17,56,61,12 + EDITTEXT IDC_NAME,87,54,199,13,ES_AUTOHSCROLL +END + +IDD_TAGS DIALOG 0, 0, 303, 204 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Tags" +FONT 8, "Tahoma" +BEGIN + LTEXT "Tags make Triggers work. Without a tag, a trigger is usually useless, because it won't be executed (except if another triggers fires it directly).",IDC_STATIC,7,7,290,20 + LTEXT "Tag:",IDC_STATIC,7,36,54,12 + COMBOBOX IDC_TAG,61,37,236,196,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add",IDC_ADD,169,53,59,14 + PUSHBUTTON "Delete",IDC_DELETE,238,53,59,14 + LTEXT "Name:",IDC_STATIC,7,90,54,12 + EDITTEXT IDC_NAME,61,89,236,13,ES_AUTOHSCROLL + LTEXT "Repeat:",IDC_STATIC,7,110,54,13 + COMBOBOX IDC_REPEAT,61,110,236,59,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Trigger:",IDC_STATIC,7,131,54,13 + COMBOBOX IDC_TRIGGER,61,131,236,135,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "For every trigger you create, you should create a tag to make the trigger work. A trigger consists of some general properties, an event and an action, which can all be defined in the ""trigger"" section.",IDC_STATIC,7,167,290,30 +END + +IDD_TRIGGERS DIALOG 0, 0, 303, 204 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Old Trigger Editor - UNUSED" +FONT 8, "Tahoma" +BEGIN + LTEXT "Trigger:",IDC_STATIC,7,7,26,11 + COMBOBOX IDC_TRIGGER,37,7,120,122,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "House:",IDC_STATIC,7,25,28,12 + COMBOBOX IDC_HOUSE,38,25,60,100,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "New trigger",IDC_ADDTRIGGER,165,7,61,14 + PUSHBUTTON "Delete trigger",IDC_DELETETRIGGER,234,7,63,14 + LTEXT "Name:",IDC_STATIC,109,26,24,12 + EDITTEXT IDC_NAME,135,25,162,13,ES_AUTOHSCROLL + LTEXT "Flags:",IDC_STATIC,7,41,19,13 + EDITTEXT IDC_FLAG1,37,41,24,13,ES_AUTOHSCROLL + EDITTEXT IDC_FLAG2,65,41,23,13,ES_AUTOHSCROLL + EDITTEXT IDC_FLAG3,92,41,23,13,ES_AUTOHSCROLL + EDITTEXT IDC_FLAG4,119,41,23,13,ES_AUTOHSCROLL + EDITTEXT IDC_FLAG5,146,41,23,13,ES_AUTOHSCROLL + GROUPBOX "Events which let the trigger start",IDC_STATIC,7,56,290,59 + GROUPBOX "Actions - What the trigger will do",IDC_STATIC,7,120,290,77 + LTEXT "Event:",IDC_STATIC,13,65,29,11 + COMBOBOX IDC_EVENT,57,66,123,68,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add",IDC_ADDEVENT,185,65,49,15 + PUSHBUTTON "Delete",IDC_DELETEEVENT,239,65,49,15 + LTEXT "Parameter 1:",IDC_LABEL_E1,13,97,44,16 + COMBOBOX IDC_EVENTPARAM1,57,97,86,160,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Parameter 2:",IDC_LABEL_E2,149,97,44,16 + COMBOBOX IDC_EVENTPARAM2,198,98,90,172,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_ACTION,45,131,134,68,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add",IDC_ADDACTION,185,130,49,15 + PUSHBUTTON "Delete",IDC_DELETEACTION,239,130,49,15 + LTEXT "Action:",IDC_STATIC,14,131,24,13 + LTEXT "Type:",IDC_STATIC,13,82,44,12 + COMBOBOX IDC_EVENTTYPE,57,82,230,98,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Param1:",IDC_LABEL_A1,13,163,30,14 + COMBOBOX IDC_ACTIONPARAM1,45,163,48,219,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",IDC_STATIC,13,148,23,12 + COMBOBOX IDC_ACTIONTYPE,45,148,172,133,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Param2:",IDC_LABEL_A2,96,163,30,15 + COMBOBOX IDC_ACTIONPARAM2,127,163,74,289,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Param3:",IDC_LABEL_A3,203,162,30,14 + COMBOBOX IDC_ACTIONPARAM3,234,163,56,243,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Param4:",IDC_LABEL_A4,13,177,30,15 + COMBOBOX IDC_ACTIONPARAM4,45,176,48,204,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Param5:",IDC_LABEL_A5,96,178,30,14 + COMBOBOX IDC_ACTIONPARAM5,127,176,74,221,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Param6:",IDC_LABEL_A6,203,176,30,16 + COMBOBOX IDC_ACTIONPARAM6,234,176,56,239,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Waypoint:",IDC_WAYPOINT,221,148,33,11 + COMBOBOX IDC_ACTIONWAYPOINT,257,148,32,133,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Trigger??? :",IDC_STATIC,177,42,37,12 + COMBOBOX IDC_TRIGGER2,221,42,76,152,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP +END + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_AITRIGGERTYPES$(RA2_MODE) DIALOG 0, 0, 303, 234 +#else +IDD_AITRIGGERTYPES DIALOG 0, 0, 303, 234 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "AI Trigger Types" +FONT 8, "Tahoma" +BEGIN + LTEXT "AI Trigger:",IDC_STATIC,7,7,43,11 + COMBOBOX IDC_AITRIGGERTYPE,60,7,236,307,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Name:",IDC_STATIC,7,63,43,11 + EDITTEXT IDC_NAME,60,64,94,13,ES_AUTOHSCROLL + LTEXT "Teamtype #1:",IDC_STATIC,7,80,43,17 + COMBOBOX IDC_TEAMTYPE1,60,81,236,81,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "House:",IDC_STATIC,165,64,50,16 + COMBOBOX IDC_OWNER,220,64,76,207,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Teamtype #2:",IDC_STATIC,7,98,43,17 + COMBOBOX IDC_TEAMTYPE2,60,98,235,81,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Techlevel:",IDC_STATIC,280,206,8,11,NOT WS_VISIBLE + COMBOBOX IDC_FLAG1,288,222,16,56,CBS_DROPDOWN | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",IDC_STATIC,6,44,53,17 + COMBOBOX IDC_FLAG2,60,45,235,71,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Data:",IDC_DATALABEL,265,204,8,13,NOT WS_VISIBLE + COMBOBOX IDC_DATA,287,222,16,128,CBS_DROPDOWN | CBS_AUTOHSCROLL | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + LTEXT "Weight:",IDC_STATIC,6,150,33,11 + EDITTEXT IDC_FLOAT1,59,148,56,13,ES_AUTOHSCROLL + LTEXT "MinWeight:",IDC_STATIC,6,165,38,11 + EDITTEXT IDC_FLOAT2,59,164,56,13,ES_AUTOHSCROLL + LTEXT "MaxWeight:",IDC_STATIC,125,165,40,11 + EDITTEXT IDC_FLOAT3,180,164,54,13,ES_AUTOHSCROLL + LTEXT "MinDiff:",IDC_STATIC,279,222,8,12,NOT WS_VISIBLE + EDITTEXT IDC_FLAG4,291,222,8,12,ES_AUTOHSCROLL | NOT WS_VISIBLE + LTEXT "Multi-Side:",IDC_STATIC,7,115,33,12 + PUSHBUTTON "Delete",IDC_DELETE,220,23,76,13 + PUSHBUTTON "Add",IDC_ADD,140,23,74,13 + CONTROL "Enabled",IDC_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,60,23,76,11 + CONTROL "Easy",IDC_EASY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,133,42,13 + CONTROL "Medium",IDC_MEDIUM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,124,132,42,13 + CONTROL "Hard",IDC_HARD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,199,132,42,13 + CONTROL "Base defense",IDC_BASEDEFENSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,124,116,67,13 + CONTROL "Available in Skirmish",IDC_SKIRMISH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,199,116,85,14 + COMBOBOX IDC_MULTISIDE,60,116,56,63,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Unittype (X):",IDC_STATIC,171,200,51,10 + COMBOBOX IDC_UNITTYPE,171,212,125,255,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Condition:",IDC_STATIC,8,200,50,11 + COMBOBOX IDC_CONDITION,8,212,95,82,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_NUMBER,109,212,54,13,ES_AUTOHSCROLL + LTEXT "Number (N):",IDC_STATIC,110,200,56,11 + LTEXT "Additional parameters for the appropiate AI Trigger Types:",IDC_STATIC,6,188,295,12 +END +#endif + +IDD_NEWMAP DIALOG 0, 0, 248, 226 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "New map assistant" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,191,205,50,14 + PUSHBUTTON "Cancel",IDCANCEL,134,205,50,14 + PUSHBUTTON "Browse",IDC_BROWSE,189,106,44,12 + GROUPBOX "Import options",IDC_LIMPORTOPTIONS,7,93,234,64 + CONTROL "Import Trees",IDC_IMPORTTREES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,125,91,12 + CONTROL "Import Overlay",IDC_IMPORTOVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,138,103,13 + CONTROL "Import Units/Buildings",IDC_IMPORTUNITS,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,128,122,94,19 + CONTROL "Multiplayer",IDC_MULTIPLAYER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,167,85,12 + COMBOBOX IDC_IMPORTFILE,15,106,161,206,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Prepare standard houses",IDC_PREPAREHOUSES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,120,167,113,13 + COMBOBOX IDC_HOUSE,177,183,56,99,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Player house:",IDC_LPLAYERHOUSE,119,183,52,15 + CONTROL "Set Auto-Production triggers",IDC_AUTOPROD,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,178,102,19 + CONTROL "Import existing map",IDC_IMPORT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7,81,234,11 + CONTROL "Create new map",IDC_NEW,"Button",BS_AUTORADIOBUTTON,7,8,234,15 + GROUPBOX "New map options",IDC_STATIC,7,21,234,51 + EDITTEXT IDC_WIDTH,51,31,51,14,ES_AUTOHSCROLL + LTEXT "Width:",IDC_STATIC,13,31,33,14 + EDITTEXT IDC_HEIGHT,178,31,51,14,ES_AUTOHSCROLL + LTEXT "Height:",IDC_STATIC,130,31,41,14 + LTEXT "Theater:",IDC_STATIC,13,49,38,12 + COMBOBOX IDC_THEATER,51,49,68,71,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Ground height:",IDC_STATIC,130,50,47,16 + COMBOBOX IDC_GROUNDHEIGHT,178,50,52,71,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +IDD_BASIC DIALOG 0, 0, 303, 208 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Basic Settings" +FONT 8, "Tahoma" +BEGIN + LTEXT "Note: some of the settings are probably just ignored",IDC_LDESC,5,7,290,10 + LTEXT "Next scenario:",IDC_LNEXTSCENARIO,5,35,60,15 + LTEXT "Alt. next scenario:",IDC_LALTNEXTSCENARIO,5,51,60,15 + LTEXT "Name:",IDC_LNAME,5,20,60,15 + EDITTEXT IDC_NAME,70,20,70,12,ES_AUTOHSCROLL + LTEXT "New INI format:",IDC_LNEWINIFORMAT,5,67,60,15 + EDITTEXT IDC_NEWINIFORMAT,70,67,70,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "CarryOverCap:",IDC_LCARRYOVERCAP,5,83,60,15 + EDITTEXT IDC_CARRYOVERCAP,70,83,70,12,ES_AUTOHSCROLL + LTEXT "EndOfGame",IDC_LENDOFGAME,5,100,60,15 + COMBOBOX IDC_ENDOFGAME,70,99,70,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_NEXTSCENARIO,70,35,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_ALTNEXTSCENARIO,70,51,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Skip Score:",IDC_LSKIPSCORE,5,115,60,15 + COMBOBOX IDC_SKIPSCORE,70,115,70,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "One Time Only:",IDC_LONETIMEONLY,5,130,60,15 + COMBOBOX IDC_ONETIMEONLY,70,131,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Skip map select:",IDC_LSKIPMAPSELECT,5,146,60,15 + COMBOBOX IDC_SKIPMAPSELECT,70,147,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Official",IDC_LOFFICIAL,5,163,60,15 + COMBOBOX IDC_OFFICIAL,70,163,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Ignore global AI triggers",IDC_LIGNOREGLOBALAITRIGGERS,6,178,60,19 + COMBOBOX IDC_IGNOREGLOBALAITRIGGERS,70,179,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Truck crate:",IDC_LTRUCKCRATE,150,20,70,17 + COMBOBOX IDC_TRUCKCRATE,226,20,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Train crate:",IDC_LTRAINCRATE,150,35,70,16 + COMBOBOX IDC_TRAINCRATE,226,36,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Percent: (?)",IDC_LPERCENT,150,52,70,16 + EDITTEXT IDC_PERCENT,226,52,70,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Multiplayer Only:",IDC_LMULTIPLAYERONLY,150,67,70,16 + EDITTEXT IDC_MULTIPLAYERONLY,226,68,70,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Tiberium growth enabled:",IDC_LTIBERIUMGROWTHENABLED,150,83,70,15 + COMBOBOX IDC_TIBERIUMGROWTHENABLED,226,84,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Vein growth enabled:",IDC_LVEINGROWTHENABLED,150,99,70,15 + COMBOBOX IDC_VEINGROWTHENABLED,226,100,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Ice growth enabled:",IDC_LICEGROWTHENABLED,150,115,70,15 + COMBOBOX IDC_ICEGROWTHENABLED,226,116,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Tiberium death to visceroid:",IDC_LTIBERIUMDEATHTOVISCEROID,150,131,70,15 + COMBOBOX IDC_TIBERIUMDEATHTOVISCEROID,226,132,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Free radar:",IDC_LFREERADAR,150,147,70,10 + COMBOBOX IDC_FREERADAR,226,148,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Init time:",IDC_LINITIME,150,164,70,10 + EDITTEXT IDC_INITTIME,226,164,70,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Required add on:",IDC_LADDONNEEDED,150,179,68,20 + COMBOBOX IDC_REQUIREDADDON,226,179,70,40,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP +END + +IDD_SINGLEPLAYER DIALOG 0, 0, 303, 207 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Singleplayer Map Settings" +FONT 8, "Tahoma" +BEGIN + LTEXT "Movies && other singleplayer stuff.",IDC_DESC,7,7,289,16 + GROUPBOX "Movies",IDC_LMOVIES,7,117,289,81 + LTEXT "Intro:",IDC_LINTRO,15,128,59,18 + COMBOBOX IDC_INTRO,75,128,68,161,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Brief:",IDC_LBRIEF,15,144,59,18 + COMBOBOX IDC_BRIEF,75,144,68,202,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Win:",IDC_LWIN,15,160,59,18 + COMBOBOX IDC_WIN,75,160,68,185,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Lose:",IDC_LLOSE,14,177,59,15 + COMBOBOX IDC_LOSE,75,176,68,203,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Action:",IDC_LACTION,154,128,59,18 + COMBOBOX IDC_ACTION,216,128,68,160,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "PostScore:",IDC_LPOSTSCORE,153,144,59,18 + COMBOBOX IDC_POSTSCORE,216,144,68,196,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "PreMapSelect:",IDC_LPREMAPSELECT,153,160,59,18 + COMBOBOX IDC_PREMAPSELECT,216,160,68,225,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Starting dropships:",IDC_LSTARTINGDROPSHIPS,7,23,67,16 + COMBOBOX IDC_STARTINGDROPSHIPS,75,23,68,161,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Carry over money (percent):",IDC_LCARRYOVERMONEY,7,40,67,16 + EDITTEXT IDC_CARRYOVERMONEY,75,41,67,14,ES_AUTOHSCROLL + LTEXT "Inherit timer:",IDC_LINHERITTIMER,7,61,67,16 + COMBOBOX IDC_TIMERINHERIT,75,61,68,161,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Fill silos:",IDC_LFILLSILOS,7,79,67,16 + COMBOBOX IDC_FILLSILOS,75,79,68,161,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP +END + +IDD_MAPVALIDATOR DIALOGEX 0, 0, 440, 225 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Map-Validator" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,383,205,50,14 + PUSHBUTTON "Cancel",IDCANCEL,322,205,50,14 + LTEXT "These possible problems were found:",IDC_LPROBLEMSFOUND,7,7,225,14 + CONTROL "List1",IDC_MAPPROBLEMS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,6,21,427,144 +END + +IDD_SCRIPTTYPES DIALOG 0, 0, 302, 230 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Scripts" +FONT 8, "Tahoma" +BEGIN + LTEXT "Scripttypes let you, for example, define that a team moves from one point to another. A scripttype is attached to a TeamType (not a TaskForce!)",IDC_STATIC,7,7,288,20 + LTEXT "Scripttype",IDC_STATIC,7,31,65,12 + COMBOBOX IDC_SCRIPTTYPE,72,32,223,196,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add",IDC_ADD,169,49,59,14 + PUSHBUTTON "Delete",IDC_DELETE,236,49,59,14 + LTEXT "Name:",IDC_STATIC,7,74,65,12 + EDITTEXT IDC_NAME,72,74,223,13,ES_AUTOHSCROLL + LTEXT "Actions:",IDC_STATIC,7,92,65,11 + LISTBOX IDC_ACTION,72,92,223,45,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Type of action:",IDC_STATIC,7,160,65,12 + LTEXT "Parameter of action:",IDC_PDESC,7,180,65,17 + COMBOBOX IDC_TYPE,72,161,223,192,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_PARAM,72,180,223,111,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Delete",IDC_DELETEACTION,235,140,60,14 + PUSHBUTTON "Add",IDC_ADDACTION,168,140,60,14 + LTEXT "Description:",IDC_STATIC,7,201,62,13 + EDITTEXT IDC_DESCRIPTION,72,201,221,24,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL +END + +IDD_AITRIGGERTYPESENABLE DIALOG 0, 0, 303, 204 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "AI Trigger Types Enable" +FONT 8, "Tahoma" +BEGIN + LTEXT "This allows the AI for example to create teams automatically. You simply specify which AITriggerTypes are enabled.",IDC_STATIC,7,7,287,23 + LTEXT "AITriggerType:",IDC_STATIC,7,62,60,13 + COMBOBOX IDC_AITRIGGERTYPE,71,62,223,281,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Enable all standard AI triggers (recommended)",IDC_ENABLEALL,7,30,160,14 + PUSHBUTTON "Delete = Disable AITrigger",IDC_DELETE,192,81,102,15 + PUSHBUTTON "Add = Enable AITrigger",IDC_ADD,85,81,102,15 +END + +IDD_TERRAINBAR DIALOG 0, 0, 387, 29 +STYLE DS_SETFONT | WS_CHILD +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Terrain / Ground:",IDC_STATIC,7,7,32,20 + COMBOBOX IDC_TILESET,42,7,141,169,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Overlay && Special:",IDC_STATIC,204,7,32,20 + COMBOBOX IDC_OVERLAY,239,7,141,169,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP +END + +IDD_TOOLSETTINGS DIALOGEX 0, 0, 116, 17 +STYLE DS_SETFONT | WS_CHILD +EXSTYLE WS_EX_TRANSPARENT +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "Brush size:",IDC_STATIC,7,3,46,11,SS_CENTERIMAGE,WS_EX_TRANSPARENT + COMBOBOX IDC_BRUSHSIZE,58,1,51,79,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +IDD_SHUTDOWN DIALOG 0, 0, 186, 35 +STYLE DS_SETFONT | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "Shutdown" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Shutting down, please wait a few seconds",IDC_STATIC,7,14,172,13 +END + +IDD_DYNAMICLOAD DIALOG 0, 0, 220, 44 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "Loading" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Loading graphics, please wait a few seconds.",IDC_STATIC,7,7,206,15 + CONTROL "Progress4",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | WS_BORDER,7,22,206,15 +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_SAVING$(TS_MODE) DIALOG 0, 0, 263, 46 +#else +IDD_SAVING DIALOG 0, 0, 263, 46 +#endif +STYLE DS_SETFONT | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "Saving" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Please wait a few seconds while FinalSun is saving. On very large maps this may even take some minutes, please do not cancel! More information is available in the status bar, most time will be needed for packing.",IDC_STATIC,7,7,249,32 +END +#endif + +IDD_TRIGGEREDITOR DIALOGEX 0, 0, 389, 263 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Trigger editor" +FONT 8, "Tahoma", 0, 0, 0x1 +BEGIN + LTEXT "Select current trigger:",IDC_STATIC,7,7,80,10 + PUSHBUTTON "New trigger",IDC_NEWTRIGGER,180,7,60,14 + PUSHBUTTON "Delete trigger",IDC_DELETETRIGGER,254,7,60,14 + COMBOBOX IDC_TRIGGER,7,26,307,165,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Tab3",IDC_TRIGGERTAB,"SysTabControl32",TCS_HOTTRACK | TCS_TOOLTIPS,7,44,377,214,WS_EX_TRANSPARENT + PUSHBUTTON "Place on map",IDC_PLACEONMAP,324,7,60,14 + PUSHBUTTON "Clone trigger",IDC_CLONE,324,24,60,14 +END + +IDD_TRIGGEROPTIONS DIALOGEX 0, 0, 365, 204 +STYLE DS_SETFONT | WS_CHILD +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + LTEXT "Type (modifies all attached Tags!):",IDC_STATIC,231,30,125,9 + COMBOBOX IDC_TRIGGERTYPE,231,41,125,71,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Name",IDC_STATIC,7,2,264,10 + EDITTEXT IDC_NAME,6,12,350,13,ES_AUTOHSCROLL + LTEXT "House:",IDC_STATIC,4,31,125,9 + COMBOBOX IDC_HOUSE,4,41,186,78,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Attached trigger:",IDC_STATIC,4,59,125,8 + COMBOBOX IDC_ATTACHEDTRIGGER,4,68,352,133,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Disabled",IDC_DISABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,90,124,9 + LTEXT "Disabled triggers must be enabled using other triggers before they fire.",IDC_STATIC,4,102,260,9 + CONTROL "Easy",IDC_EASY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,115,58,13 + CONTROL "Medium",IDC_MEDIUM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,68,115,58,13 + CONTROL "Hard",IDC_HARD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,140,115,58,13 +END + +IDD_TRIGGEREVENTS DIALOGEX 0, 0, 365, 204 +STYLE DS_SETFONT | WS_CHILD +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + LTEXT "Current event:",IDC_STATIC,6,6,64,11 + COMBOBOX IDC_EVENT,72,6,150,79,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "New event",IDC_NEWEVENT,233,6,61,14 + PUSHBUTTON "Delete event",IDC_DELETEEVENT,300,6,61,14 + GROUPBOX "Event options",IDC_STATIC,6,19,355,178 + LTEXT "Event type:",IDC_STATIC,14,32,57,12 + COMBOBOX IDC_EVENTTYPE,72,30,282,184,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_EVENTDESCRIPTION,14,48,340,26,ES_MULTILINE | ES_READONLY | WS_VSCROLL + LTEXT "Event parameters:",IDC_STATIC,14,79,74,10 + LISTBOX IDC_PARAMETER,14,93,159,96,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + LTEXT "Parameter value:",IDC_STATIC,185,79,118,10 + COMBOBOX IDC_PARAMVALUE,185,93,169,125,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_NOINTEGRALHEIGHT | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Select the event type first, then set all parameters.",IDC_STATIC,185,110,169,25 +END + +IDD_TRIGGERACTIONS DIALOGEX 0, 0, 365, 202 +STYLE DS_SETFONT | WS_CHILD +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + LTEXT "Current action:",IDC_STATIC,6,6,58,11 + COMBOBOX IDC_ACTION,72,6,149,79,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "New action",IDC_NEWACTION,233,6,60,14 + PUSHBUTTON "Delete action",IDC_DELETEACTION,301,6,59,14 + GROUPBOX "Action options",IDC_STATIC,6,20,354,174 + LTEXT "Action type:",IDC_STATIC,14,32,57,12 + COMBOBOX IDC_ACTIONTYPE,72,30,282,184,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_ACTIONDESCRIPTION,14,48,340,26,ES_MULTILINE | ES_READONLY | WS_VSCROLL + LTEXT "Action parameters:",IDC_STATIC,14,79,74,10 + LISTBOX IDC_PARAMETER,14,93,160,94,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + LTEXT "Parameter value:",IDC_STATIC,186,79,118,10 + COMBOBOX IDC_PARAMVALUE,186,92,168,125,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_NOINTEGRALHEIGHT | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Select the event type first, then set all parameters.",IDC_STATIC,186,110,168,25 +END + +IDD_GLOBALS DIALOG 0, 0, 186, 79 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Local Variables" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Select variable:",IDC_STATIC,7,7,60,12 + COMBOBOX IDC_GLOBAL,7,19,172,92,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Description:",IDC_STATIC,7,41,44,12 + EDITTEXT IDC_DESCRIPTION,56,41,123,13,ES_AUTOHSCROLL + LTEXT "Preset value:",IDC_STATIC,7,60,45,11 + COMBOBOX IDC_VALUE,57,59,122,55,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_TSOPTIONS$(TS_MODE) DIALOGEX 0, 0, 197, 183 +#else +IDD_TSOPTIONS DIALOGEX 0, 0, 197, 183 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_NOFAILCREATE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Options" +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,140,160,50,14 + PUSHBUTTON "Cancel",IDCANCEL,85,160,50,14 + LTEXT "Tiberian Sun EXE (make sure its in the correct path)",IDC_STATIC,5,5,130,20 + EDITTEXT IDC_EDIT1,5,25,130,15,ES_AUTOHSCROLL + PUSHBUTTON "Browse",IDC_CHOOSE,140,25,50,15 + LTEXT "Language / Sprache:",IDC_STATIC,7,51,128,11 + COMBOBOX IDC_LANGUAGE,7,63,183,94,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Rules, Art && AI ini files",IDC_STATIC,7,81,183,71 + CONTROL "Act like Tiberian Sun when searching for files (recommended)",IDC_RULESLIKETS, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE | WS_GROUP,14,92,170,16 + CONTROL "Only use the files inside tibsun.mix (do not use Firestorm or any mods)",IDC_ONLYORIGINAL, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE,14,110,168,16 + CONTROL "Prefer FinalSun theater INI files",IDC_PREFER_LOCAL_THEATER_FILES, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,131,164,12 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_INFO$(RA2_MODE) DIALOGEX 0, 0, 349, 250 +#else +IDD_INFO DIALOGEX 0, 0, 349, 250 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Info" +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,292,8,50,14 + LTEXT "© 1999-2024 ELECTRONIC ARTS INC. ALL RIGHTS RESERVED\nWestwood Studios(tm) is an Electronic Arts(tm) brand.",IDC_STATIC,7,189,334,18 + LTEXT "© 1999-2024 Electronic Arts Inc. Westwood Studios and Electronic Arts are trademarks or registered trademarks of Electronic Arts Inc. in the U.S. and/or other countries. All rights reserved.",IDC_STATIC,7,214,335,28 + EDITTEXT IDC_LICENSE_AND_COPYRIGHT,6,29,336,148,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_LOADING$(RA2_MODE) DIALOGEX 0, 0, 235, 165 +#else +IDD_LOADING DIALOGEX 0, 0, 235, 165 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP +FONT 8, "Tahoma", 0, 0, 0x1 +BEGIN + LTEXT "Loading...",IDC_CAP,7,7,221,9 + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH,7,18,221,13,WS_EX_DLGMODALFRAME + LTEXT "Homepage: http://www.ea.com",IDC_STATIC,7,78,221,11,WS_BORDER + CTEXT "",IDC_VERSION,74,37,154,13,SS_CENTERIMAGE | SS_SUNKEN + LTEXT "Version:",IDC_LVERSION,7,37,61,9 + CTEXT "",IDC_BUILTBY,74,52,154,13,SS_CENTERIMAGE | SS_SUNKEN + LTEXT "Built by:",IDC_LBUILTBY,7,52,61,9 + LTEXT "© 1999-2024 ELECTRONIC ARTS INC. ALL RIGHTS RESERVED\nAuthored by Matthias Wagner\nWestwood Studios(tm) is an Electronic Arts(tm) brand.",IDC_STATIC,7,97,221,33 + LTEXT "This software comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it.\nFor details open Help->Info",IDC_STATIC,6,129,221,26 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_TEAMTYPES$(RA2_MODE) DIALOG 0, 0, 303, 215 +#else +IDD_TEAMTYPES DIALOG 0, 0, 303, 215 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Teams" +FONT 8, "Tahoma" +BEGIN + LTEXT "Team types connect a trigger with task forces",IDC_STATIC,6,5,290,10 + LTEXT "Team types:",IDC_STATIC,5,20,50,10 + COMBOBOX IDC_TEAMTYPES,55,20,155,174,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "New",IDC_NEWTEAMTYPE,261,20,35,15 + PUSHBUTTON "Delete",IDC_DELETETEAMTYPE,220,20,35,15 + LTEXT "Name:",IDC_STATIC,10,51,30,10 + EDITTEXT IDC_NAME,56,51,90,12,ES_AUTOHSCROLL + LTEXT "Veteran level:",IDC_STATIC,10,66,45,15 + CONTROL "Loadable",IDC_LOADABLE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,157,55,8 + CONTROL "Full",IDC_FULL,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,167,55,8 + CONTROL "Annoyance",IDC_ANNOYANCE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,176,55,10 + CONTROL "Guard slower",IDC_GUARDSLOWER,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,187,55,8 + CONTROL "Recruiter",IDC_RECRUITER,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,10,197,55,8 + LTEXT "House:",IDC_STATIC,10,81,35,10 + COMBOBOX IDC_HOUSE,56,81,90,62,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Autocreate",IDC_AUTOCREATE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,157,55,8 + CONTROL "Prebuild",IDC_PREBUILD,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,167,55,8 + CONTROL "Reinforce",IDC_REINFORCE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,177,55,8 + CONTROL "Cargo plane",IDC_DROPPOD,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,157,55,8 + CONTROL "Whiner",IDC_WHINER,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,167,55,8 + CONTROL "Loose recruit",IDC_LOOSERECRUIT,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,177,55,8 + CONTROL "Aggressive",IDC_AGGRESSIVE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,187,55,8 + CONTROL "Suicide",IDC_SUICIDE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,65,197,55,8 + CONTROL "OnTransOnly",IDC_ONTRANSONLY,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,187,55,8 + CONTROL "AvoidThreats",IDC_AVOIDTHREATS,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,125,197,55,8 + CONTROL "Ion immune",IDC_IONIMMUNE,"Button",BS_AUTOCHECKBOX | BS_LEFT | NOT WS_VISIBLE | WS_TABSTOP,185,157,60,8 + CONTROL "TransportsReturnOnUnload",IDC_TRANSPORTRETURNSONUNLOAD, + "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,185,177,100,8 + CONTROL "AreTeamMembersRecruitable",IDC_ARETEAMMEMBERSRECRUITABLE, + "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,185,167,105,8 + CONTROL "IsBaseDefense",IDC_ISBASEDEFENSE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,185,187,80,8 + CONTROL "OnlyTargetHouseEnemy",IDC_ONLYTARGETHOUSEENEMY,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,185,197,100,8 + LTEXT "Priority:",IDC_STATIC,10,96,40,10 + EDITTEXT IDC_PRIORITY,56,96,90,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Max:",IDC_STATIC,10,111,30,10 + EDITTEXT IDC_MAX,56,111,90,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Techlevel:",IDC_STATIC,10,125,40,10 + COMBOBOX IDC_TECHLEVEL,56,125,91,72,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Group:",IDC_STATIC,156,51,30,10 + GROUPBOX "Selected team type",IDC_STATIC,6,37,290,173 + COMBOBOX IDC_GROUP,200,51,90,78,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Waypoint:",IDC_STATIC,156,66,40,10 + COMBOBOX IDC_WAYPOINT,200,66,90,80,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Script:",IDC_STATIC,156,81,40,10 + COMBOBOX IDC_SCRIPT,200,81,90,205,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Task force:",IDC_STATIC,156,96,40,10 + COMBOBOX IDC_TASKFORCE,200,96,90,205,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_VETERANLEVEL,56,66,90,60,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Tag:",IDC_STATIC,156,111,40,13 + COMBOBOX IDC_TAG,200,111,90,186,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Transport waypoint:",IDC_LTRANSPORTWAYPOINT,156,126,40,17 + COMBOBOX IDC_TRANSPORTWAYPOINT,200,126,90,80,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Mind Control Decision:",IDC_MCD_L,10,139,43,16 + COMBOBOX IDC_MINDCONTROLDECISION,55,140,92,205,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP +END +#endif + +IDD_NEWMAPTYPE DIALOG 0, 0, 222, 129 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Create new map - Step 1" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "Next",IDOK,165,108,50,14 + PUSHBUTTON "Cancel",IDCANCEL,7,108,50,14 + LTEXT "Please select if you want to create a new singleplayer map or multiplayer map. Multiplayer maps are maps used in both skirmish and multiplayer games.",IDC_STATIC,7,7,208,33 + CONTROL "Singleplayer map (only for experienced users that can handle advanced mode)",IDC_SINGLE, + "Button",BS_AUTORADIOBUTTON | BS_MULTILINE | WS_GROUP,7,55,208,20 + CONTROL "Multiplayer map",IDC_MULTI,"Button",BS_AUTORADIOBUTTON,7,76,208,11 +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_NEWMAPCREATE$(TS_MODE) DIALOG 0, 0, 222, 129 +#else +IDD_NEWMAPCREATE DIALOG 0, 0, 222, 129 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Create new map - Step 2" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "Next",IDOK,165,108,50,14 + PUSHBUTTON "Cancel",IDCANCEL,7,108,50,14 + LTEXT "Please select here if you want to create a completely new map from scratch or if you want to import an already existing map (Note: You cannot import maps created by the random map generator of RA2 or of TS version 1.15 or higher)",IDC_STATIC,7,7,208,37 + CONTROL "Create a completely new map",IDC_CREATE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7,55,208,11 + CONTROL "Import an existing map or bitmap (BMP)",IDC_IMPORT, + "Button",BS_AUTORADIOBUTTON,7,67,208,11 + CONTROL "Activate AI Triggers (results in better AI)",IDC_AITRIGGERS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,83,208,14 +END +#endif + +IDD_NEWMAPSPOPTIONS DIALOG 0, 0, 222, 129 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Create new map - Step 4" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "Next",IDOK,165,108,50,14 + PUSHBUTTON "Cancel",IDCANCEL,7,108,50,14 + CONTROL "Prepare standard houses (recommended)",IDC_PREPAREHOUSES, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,39,159,13 + COMBOBOX IDC_HOUSE,87,63,115,99,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Player house:",IDC_LPLAYERHOUSE,15,63,52,15 + CONTROL "Set Auto-Production triggers",IDC_AUTOPROD,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,14,78,192,14 + LTEXT "Please select the human player. It is recommended to leave the other options as they are.",IDC_STATIC,7,7,208,26 + GROUPBOX "",IDC_STATIC,7,52,208,46 +END + +IDD_NEWMAPCREATENEW DIALOG 0, 0, 222, 129 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Create new map - Step 3" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "Next",IDOK,165,108,50,14 + PUSHBUTTON "Cancel",IDCANCEL,7,108,50,14 + LTEXT "Please select size, theater and starting height here. The size should be below 100x100 for best results.",IDC_STATIC,7,7,208,32 + LTEXT "Width:",IDC_STATIC,7,39,35,11 + EDITTEXT IDC_WIDTH,130,39,85,13,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Height:",IDC_STATIC,7,55,35,11 + EDITTEXT IDC_HEIGHT,130,55,85,13,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Theater:",IDC_STATIC,7,71,53,12 + COMBOBOX IDC_THEATER,130,71,85,58,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Starting height:",IDC_STATIC,7,87,64,12 + COMBOBOX IDC_STARTINGHEIGHT,130,87,85,93,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +IDD_NEWMAPIMPORT DIALOG 0, 0, 222, 129 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Create new map - Step 3" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "Next",IDOK,165,108,50,14 + PUSHBUTTON "Cancel",IDCANCEL,7,108,50,14 + PUSHBUTTON "Browse",IDC_BROWSE,155,51,60,12 + CONTROL "Import Trees",IDC_IMPORTTREES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,69,91,12 + CONTROL "Import Overlay",IDC_IMPORTOVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,82,103,13 + CONTROL "Import Units/Buildings",IDC_IMPORTUNITS,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,120,66,94,19 + COMBOBOX IDC_IMPORTFILE,7,51,131,206,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Please select the map you want to import. No triggers or houses will be imported. Bitmaps will be scaled down to appropiate size. Currently bitmaps will always be converted to temperate theater maps.",IDC_STATIC,7,7,208,43 +END + +IDD_MAPLOAD DIALOG 0, 0, 220, 50 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "Loading" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Loading map, please wait. This may take several minutes on big maps.",IDC_STATIC,7,7,206,18 + CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | WS_BORDER,7,29,206,14 +END + +IDD_NEWMAPBITMAP DIALOG 0, 0, 222, 129 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Create new map - Step 3" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "Next",IDOK,165,108,50,14 + PUSHBUTTON "Cancel",IDCANCEL,7,108,50,14 + LTEXT "Please select size, theater and starting height here. The size should be below 150x150.",IDC_STATIC,7,7,208,32 + LTEXT "Width:",IDC_STATIC,7,39,35,11 + EDITTEXT IDC_WIDTH,130,39,85,13,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Height:",IDC_STATIC,7,55,35,11 + EDITTEXT IDC_HEIGHT,130,55,85,13,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Theater:",IDC_STATIC,7,71,53,12 + COMBOBOX IDC_THEATER,130,71,85,58,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Starting height:",IDC_STATIC,7,87,64,12 + COMBOBOX IDC_STARTINGHEIGHT,130,87,85,93,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +IDD_PROGRESS DIALOG 0, 0, 208, 89 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Progress" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,67,68,50,14 + LTEXT "Progress:",IDC_LABEL,7,7,194,22 + CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | WS_BORDER,7,47,194,13 + LTEXT "Progress: ",IDC_PROGLABEL,7,31,194,13 +END + +IDD_AUTOUPDATE DIALOG 0, 0, 290, 177 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Auto Update" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Download",IDOK,223,156,60,14 + PUSHBUTTON "Cancel",IDCANCEL,152,156,60,14 + LTEXT "Updates available:",IDC_STATIC,7,7,184,16 + LISTBOX IDC_UPDATELIST,7,23,276,36,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Description:",IDC_STATIC,7,66,80,14 + EDITTEXT IDC_DESCRIPTION,92,66,191,42,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL + LTEXT "Download locations:",IDC_STATIC,7,118,69,14 + LISTBOX IDC_DOWNLOADLIST,91,117,192,29,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP +END + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_NEWMAPCREATE$(RA2_MODE) DIALOG 0, 0, 222, 129 +#else +IDD_NEWMAPCREATE DIALOG 0, 0, 222, 129 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Create new map - Step 2" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "Next",IDOK,165,108,50,14 + PUSHBUTTON "Cancel",IDCANCEL,7,108,50,14 + LTEXT "Please select here if you want to create a completely new map from scratch or if you want to import an already existing map (Note: You cannot import maps created by the random map generator of RA2)",IDC_STATIC,7,7,208,37 + CONTROL "Create a completely new map",IDC_CREATE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7,55,208,11 + CONTROL "Import an existing map or bitmap (BMP)",IDC_IMPORT, + "Button",BS_AUTORADIOBUTTON,7,67,208,11 + CONTROL "Activate AI Triggers (results in better AI)",IDC_AITRIGGERS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,83,208,14 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_SAVING$(RA2_MODE) DIALOG 0, 0, 263, 46 +#else +IDD_SAVING DIALOG 0, 0, 263, 46 +#endif +STYLE DS_SETFONT | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "Saving" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Please wait a few seconds while FinalAlert 2 is saving. On very large maps this may even take some minutes, please do not cancel! More information is available in the status bar, most time will be needed for packing.",IDC_STATIC,7,7,249,32 +END +#endif + +IDD_UNIT DIALOG 0, 0, 232, 145 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Unit Options" +FONT 8, "Tahoma" +BEGIN + DEFPUSHBUTTON "OK",IDOK,170,124,50,14 + PUSHBUTTON "Cancel",IDCANCEL,110,124,50,14 + LTEXT "House:",IDC_LHOUSE,5,8,33,11 + COMBOBOX IDC_HOUSE,45,8,65,45,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Strength:",IDC_LSTRENGTH,5,26,29,10 + CONTROL "Slider1",IDC_STRENGTH,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,45,26,70,11 + LTEXT "State:",IDC_LSTATE,5,43,40,10 + COMBOBOX IDC_STATE,45,43,65,90,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Tag:",IDC_LTAG,6,105,63,14 + COMBOBOX IDC_TAG,74,106,153,69,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Param1:",IDC_LP1,5,80,37,17 + EDITTEXT IDC_P1,45,80,65,12,ES_AUTOHSCROLL + LTEXT "Param2:",IDC_LP2,125,8,30,16 + LTEXT "Param3:",IDC_LP3,125,25,30,16 + LTEXT "Param4:",IDC_LP4,125,43,30,16 + EDITTEXT IDC_P2,161,8,65,12,ES_AUTOHSCROLL + EDITTEXT IDC_P3,161,25,65,12,ES_AUTOHSCROLL + EDITTEXT IDC_P4,161,43,65,12,ES_AUTOHSCROLL + LTEXT "Params are unknown (integers?).",IDC_DESC,4,137,53,8 + LTEXT "Direction:",IDC_LDIRECTION,5,61,40,10 + COMBOBOX IDC_DIRECTION,45,61,65,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Param5:",IDC_LP5,125,61,34,17 + EDITTEXT IDC_P6,161,79,65,12,ES_AUTOHSCROLL + LTEXT "Param6:",IDC_LP6,125,79,35,16 + EDITTEXT IDC_P5,161,61,65,12,ES_AUTOHSCROLL +END + +IDD_TERRAINPLACING DIALOG 0, 0, 193, 234 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Random Tree Placing" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,136,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,136,24,50,14 + LTEXT "Please select the trees that shall be placed",IDC_STATIC,7,7,104,22 + LISTBOX IDC_AVAIL,7,58,73,77,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Available:",IDC_STATIC,7,45,86,11 + LISTBOX IDC_USED,113,58,73,77,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Used:",IDC_STATIC,114,45,74,11 + PUSHBUTTON "<-",IDC_REMOVE,87,75,20,11 + PUSHBUTTON "->",IDC_ADD,87,58,20,11 + GROUPBOX "Preview",IDC_PREVIEW,7,140,179,86 +END + +IDD_SEARCHWAYPOINT DIALOG 0, 0, 186, 95 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Search Waypoint" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Search",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + LTEXT "Waypoints:",IDC_STATIC,7,7,96,12 + LISTBOX IDC_WAYPOINTS,7,21,97,67,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_AITRIGGERTYPES$(TS_MODE) DIALOG 0, 0, 303, 234 +#else +IDD_AITRIGGERTYPES DIALOG 0, 0, 303, 234 +#endif +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "AI Trigger Types" +FONT 8, "Tahoma" +BEGIN + LTEXT "AI Trigger:",IDC_STATIC,7,7,43,11 + COMBOBOX IDC_AITRIGGERTYPE,60,7,236,307,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Name:",IDC_STATIC,7,63,43,11 + EDITTEXT IDC_NAME,60,64,94,13,ES_AUTOHSCROLL + LTEXT "Teamtype #1:",IDC_STATIC,7,80,43,17 + COMBOBOX IDC_TEAMTYPE1,60,81,236,81,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "House:",IDC_STATIC,165,64,50,16 + COMBOBOX IDC_OWNER,220,64,76,207,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Teamtype #2:",IDC_STATIC,7,98,43,17 + COMBOBOX IDC_TEAMTYPE2,60,98,235,81,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Techlevel:",IDC_STATIC,280,206,8,11,NOT WS_VISIBLE + COMBOBOX IDC_FLAG1,288,222,16,56,CBS_DROPDOWN | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",IDC_STATIC,6,44,53,17 + COMBOBOX IDC_FLAG2,60,45,235,71,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Data:",IDC_DATALABEL,265,204,8,13,NOT WS_VISIBLE + COMBOBOX IDC_DATA,287,222,16,128,CBS_DROPDOWN | CBS_AUTOHSCROLL | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + LTEXT "Weight:",IDC_STATIC,6,150,33,11 + EDITTEXT IDC_FLOAT1,59,148,56,13,ES_AUTOHSCROLL + LTEXT "MinWeight:",IDC_STATIC,6,165,38,11 + EDITTEXT IDC_FLOAT2,59,164,56,13,ES_AUTOHSCROLL + LTEXT "MaxWeight:",IDC_STATIC,125,165,40,11 + EDITTEXT IDC_FLOAT3,180,164,54,13,ES_AUTOHSCROLL + LTEXT "MinDiff:",IDC_STATIC,279,222,8,12,NOT WS_VISIBLE + EDITTEXT IDC_FLAG4,291,222,8,12,ES_AUTOHSCROLL | NOT WS_VISIBLE + LTEXT "Multi-Side:",IDC_STATIC,7,115,33,12 + PUSHBUTTON "Delete",IDC_DELETE,220,23,76,13 + PUSHBUTTON "Add",IDC_ADD,140,23,74,13 + CONTROL "Enabled",IDC_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,60,23,76,11 + CONTROL "Easy",IDC_EASY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,133,42,13 + CONTROL "Medium",IDC_MEDIUM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,124,132,42,13 + CONTROL "Hard",IDC_HARD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,199,132,42,13 + CONTROL "Base defense",IDC_BASEDEFENSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,124,116,67,13 + CONTROL "Available in Skirmish",IDC_SKIRMISH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,199,116,85,14 + COMBOBOX IDC_MULTISIDE,60,116,56,63,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Unittype (X):",IDC_STATIC,171,200,51,10 + COMBOBOX IDC_UNITTYPE,171,212,125,255,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Condition:",IDC_STATIC,8,200,50,11 + COMBOBOX IDC_CONDITION,8,212,95,82,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_NUMBER,109,212,54,13,ES_AUTOHSCROLL + LTEXT "Number (N):",IDC_STATIC,110,200,56,11 + LTEXT "Additional parameters for the appropiate AI Trigger Types:",IDC_STATIC,6,188,295,12 +END +#endif + +IDD_USERSCRIPTS DIALOG 0, 0, 301, 193 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Map Scripts" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Run",IDOK,244,40,50,14 + PUSHBUTTON "Quit",IDCANCEL,244,57,50,14 + LTEXT "Scripts available:",IDC_STATIC,7,24,109,12 + LISTBOX IDC_SCRIPTS,7,39,230,74,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Report:",IDC_STATIC,7,124,117,15 + EDITTEXT IDC_REPORT,7,145,287,41,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL + LTEXT "For safety reasons, you should save your map before running scripts. Undo is not available.",IDC_STATIC,7,7,287,17 +END + +IDD_COMBO_UINPUT DIALOG 0, 0, 238, 63 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Please select" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,181,42,50,14 + PUSHBUTTON "Cancel",IDCANCEL,124,42,50,14,NOT WS_VISIBLE + LTEXT "CAPTION",IDC_CAPTION,7,7,224,12 + COMBOBOX IDC_COMBO1,7,23,224,160,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NEWRA2HOUSE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 45 + END + + "IDD_SAVEOPTIONS$(TS_MODE)", DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 226 + TOPMARGIN, 7 + BOTTOMMARGIN, 118 + END + + IDD_MULTISAVEOPT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 274 + TOPMARGIN, 7 + BOTTOMMARGIN, 98 + END + + IDD_MMXOPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 261 + TOPMARGIN, 7 + BOTTOMMARGIN, 165 + END + + "IDD_SAVEOPTIONS$(RA2_MODE)", DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 226 + TOPMARGIN, 7 + BOTTOMMARGIN, 179 + END + + IDD_CHANGESIZE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 187 + END + + IDD_AITRIGGERADD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 215 + TOPMARGIN, 7 + BOTTOMMARGIN, 90 + END + + IDD_MYOPENDIALOG, DIALOG + BEGIN + END + + IDD_TIP, DIALOG + BEGIN + RIGHTMARGIN, 274 + END + + IDD_FINALSUN_DIALOG, DIALOG + BEGIN + END + + "IDD_TSOPTIONS$(RA2_MODE)", DIALOG + BEGIN + BOTTOMMARGIN, 165 + END + + IDD_ALL, DIALOG + BEGIN + END + + IDD_MAP, DIALOG + BEGIN + END + + IDD_INPUTBOX, DIALOG + BEGIN + END + + IDD_IMPORTINI, DIALOG + BEGIN + END + + IDD_LIGHTING, DIALOG + BEGIN + END + + "IDD_INFO$(TS_MODE)", DIALOG + BEGIN + RIGHTMARGIN, 343 + BOTTOMMARGIN, 243 + END + + IDD_SPECIALFLAGS, DIALOG + BEGIN + END + + IDD_INFANTRY, DIALOG + BEGIN + END + + IDD_HOUSES, DIALOG + BEGIN + END + + IDD_AIRCRAFT, DIALOG + BEGIN + END + + IDD_BUILDING, DIALOG + BEGIN + END + + "IDD_LOADING$(TS_MODE)", DIALOG + BEGIN + BOTTOMMARGIN, 159 + END + + IDD_WAYPOINT, DIALOG + BEGIN + END + + IDD_CELLTAG, DIALOG + BEGIN + END + + "IDD_TEAMTYPES$(TS_MODE)", DIALOG + BEGIN + END + + IDD_TASKFORCES, DIALOG + BEGIN + END + + IDD_TAGS, DIALOG + BEGIN + END + + IDD_TRIGGERS, DIALOG + BEGIN + END + + "IDD_AITRIGGERTYPES$(RA2_MODE)", DIALOG + BEGIN + END + + IDD_NEWMAP, DIALOG + BEGIN + END + + IDD_BASIC, DIALOG + BEGIN + END + + IDD_SINGLEPLAYER, DIALOG + BEGIN + END + + IDD_MAPVALIDATOR, DIALOG + BEGIN + RIGHTMARGIN, 433 + VERTGUIDE, 6 + VERTGUIDE, 372 + BOTTOMMARGIN, 219 + HORZGUIDE, 165 + END + + IDD_SCRIPTTYPES, DIALOG + BEGIN + END + + IDD_TERRAINBAR, DIALOG + BEGIN + END + + IDD_TOOLSETTINGS, DIALOG + BEGIN + END + + IDD_SHUTDOWN, DIALOG + BEGIN + END + + IDD_DYNAMICLOAD, DIALOG + BEGIN + END + + "IDD_SAVING$(TS_MODE)", DIALOG + BEGIN + END + + IDD_TRIGGEREDITOR, DIALOG + BEGIN + RIGHTMARGIN, 384 + VERTGUIDE, 228 + BOTTOMMARGIN, 258 + END + + IDD_TRIGGEROPTIONS, DIALOG + BEGIN + VERTGUIDE, 4 + VERTGUIDE, 356 + END + + IDD_TRIGGEREVENTS, DIALOG + BEGIN + RIGHTMARGIN, 361 + VERTGUIDE, 6 + VERTGUIDE, 14 + VERTGUIDE, 72 + VERTGUIDE, 173 + VERTGUIDE, 185 + VERTGUIDE, 222 + VERTGUIDE, 233 + VERTGUIDE, 294 + VERTGUIDE, 300 + VERTGUIDE, 354 + HORZGUIDE, 6 + HORZGUIDE, 79 + END + + IDD_TRIGGERACTIONS, DIALOG + BEGIN + RIGHTMARGIN, 360 + VERTGUIDE, 6 + VERTGUIDE, 14 + VERTGUIDE, 72 + VERTGUIDE, 174 + VERTGUIDE, 186 + VERTGUIDE, 221 + VERTGUIDE, 233 + VERTGUIDE, 293 + VERTGUIDE, 301 + VERTGUIDE, 354 + BOTTOMMARGIN, 194 + HORZGUIDE, 6 + HORZGUIDE, 74 + HORZGUIDE, 79 + END + + "IDD_TSOPTIONS$(TS_MODE)", DIALOG + BEGIN + BOTTOMMARGIN, 165 + END + + "IDD_INFO$(RA2_MODE)", DIALOG + BEGIN + RIGHTMARGIN, 342 + TOPMARGIN, 8 + BOTTOMMARGIN, 242 + END + + "IDD_LOADING$(RA2_MODE)", DIALOG + BEGIN + BOTTOMMARGIN, 159 + END + + "IDD_TEAMTYPES$(RA2_MODE)", DIALOG + BEGIN + END + + IDD_NEWMAPTYPE, DIALOG + BEGIN + END + + "IDD_NEWMAPCREATE$(TS_MODE)", DIALOG + BEGIN + END + + IDD_NEWMAPSPOPTIONS, DIALOG + BEGIN + END + + IDD_NEWMAPCREATENEW, DIALOG + BEGIN + END + + IDD_NEWMAPIMPORT, DIALOG + BEGIN + END + + IDD_MAPLOAD, DIALOG + BEGIN + END + + IDD_NEWMAPBITMAP, DIALOG + BEGIN + END + + IDD_PROGRESS, DIALOG + BEGIN + END + + IDD_AUTOUPDATE, DIALOG + BEGIN + END + + "IDD_NEWMAPCREATE$(RA2_MODE)", DIALOG + BEGIN + END + + "IDD_SAVING$(RA2_MODE)", DIALOG + BEGIN + END + + IDD_UNIT, DIALOG + BEGIN + END + + IDD_TERRAINPLACING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 186 + TOPMARGIN, 7 + BOTTOMMARGIN, 226 + END + + IDD_SEARCHWAYPOINT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END + + "IDD_AITRIGGERTYPES$(TS_MODE)", DIALOG + BEGIN + END + + IDD_USERSCRIPTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 294 + TOPMARGIN, 7 + BOTTOMMARGIN, 186 + END + + IDD_COMBO_UINPUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 231 + TOPMARGIN, 7 + BOTTOMMARGIN, 56 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_MMXOPTIONS DLGINIT +BEGIN + IDC_MINPLAYERS, 0x403, 2, 0 +0x0032, + IDC_MINPLAYERS, 0x403, 2, 0 +0x0033, + IDC_MINPLAYERS, 0x403, 2, 0 +0x0034, + IDC_MINPLAYERS, 0x403, 2, 0 +0x0035, + IDC_MINPLAYERS, 0x403, 2, 0 +0x0036, + IDC_MINPLAYERS, 0x403, 2, 0 +0x0037, + IDC_MINPLAYERS, 0x403, 2, 0 +0x0038, + IDC_MAXPLAYERS, 0x403, 2, 0 +0x0032, + IDC_MAXPLAYERS, 0x403, 2, 0 +0x0033, + IDC_MAXPLAYERS, 0x403, 2, 0 +0x0034, + IDC_MAXPLAYERS, 0x403, 2, 0 +0x0035, + IDC_MAXPLAYERS, 0x403, 2, 0 +0x0036, + IDC_MAXPLAYERS, 0x403, 2, 0 +0x0037, + IDC_MAXPLAYERS, 0x403, 2, 0 +0x0038, + 0 +END + +IDD_MAP DLGINIT +BEGIN + IDC_THEATER, 0x403, 5, 0 +0x4e53, 0x574f, "\000" + IDC_THEATER, 0x403, 10, 0 +0x4554, 0x504d, 0x5245, 0x5441, 0x0045, + 0 +END + +IDD_SPECIALFLAGS DLGINIT +BEGIN + IDC_TIBERIUMGROWS, 0x403, 4, 0 +0x6579, 0x0073, + IDC_TIBERIUMGROWS, 0x403, 3, 0 +0x6f6e, "\000" + IDC_TIBERIUMSPREADS, 0x403, 4, 0 +0x6579, 0x0073, + IDC_TIBERIUMSPREADS, 0x403, 3, 0 +0x6f6e, "\000" + IDC_TIBERIUMEXPLOSIVE, 0x403, 4, 0 +0x6579, 0x0073, + IDC_TIBERIUMEXPLOSIVE, 0x403, 3, 0 +0x6f6e, "\000" + IDC_DESTROYABLEBRIDGES, 0x403, 4, 0 +0x6579, 0x0073, + IDC_DESTROYABLEBRIDGES, 0x403, 3, 0 +0x6f6e, "\000" + IDC_MCVDEPLOY, 0x403, 4, 0 +0x6579, 0x0073, + IDC_MCVDEPLOY, 0x403, 3, 0 +0x6f6e, "\000" + IDC_INITIALVETERAN, 0x403, 4, 0 +0x6579, 0x0073, + IDC_INITIALVETERAN, 0x403, 3, 0 +0x6f6e, "\000" + IDC_FIXEDALLIANCE, 0x403, 4, 0 +0x6579, 0x0073, + IDC_FIXEDALLIANCE, 0x403, 3, 0 +0x6f6e, "\000" + IDC_HARVESTERIMMUNE, 0x403, 4, 0 +0x6579, 0x0073, + IDC_HARVESTERIMMUNE, 0x403, 3, 0 +0x6f6e, "\000" + IDC_FOGOFWAR, 0x403, 4, 0 +0x6579, 0x0073, + IDC_FOGOFWAR, 0x403, 3, 0 +0x6f6e, "\000" + IDC_INERT, 0x403, 4, 0 +0x6579, 0x0073, + IDC_INERT, 0x403, 3, 0 +0x6f6e, "\000" + IDC_IONSTORMS, 0x403, 4, 0 +0x6579, 0x0073, + IDC_IONSTORMS, 0x403, 3, 0 +0x6f6e, "\000" + IDC_METEORITES, 0x403, 4, 0 +0x6579, 0x0073, + IDC_METEORITES, 0x403, 3, 0 +0x6f6e, "\000" + IDC_VISCEROIDS, 0x403, 4, 0 +0x6579, 0x0073, + IDC_VISCEROIDS, 0x403, 3, 0 +0x6f6e, "\000" + 0 +END + +IDD_INFANTRY DLGINIT +BEGIN + IDC_STATE, 0x403, 6, 0 +0x6c53, 0x6565, 0x0070, + IDC_STATE, 0x403, 9, 0 +0x6148, 0x6d72, 0x656c, 0x7373, "\000" + IDC_STATE, 0x403, 7, 0 +0x7453, 0x6369, 0x796b, "\000" + IDC_STATE, 0x403, 7, 0 +0x7441, 0x6174, 0x6b63, "\000" + IDC_STATE, 0x403, 5, 0 +0x6f4d, 0x6576, "\000" + IDC_STATE, 0x403, 7, 0 +0x6150, 0x7274, 0x6c6f, "\000" + IDC_STATE, 0x403, 6, 0 +0x4d51, 0x766f, 0x0065, + IDC_STATE, 0x403, 8, 0 +0x6552, 0x7274, 0x6165, 0x0074, + IDC_STATE, 0x403, 6, 0 +0x7547, 0x7261, 0x0064, + IDC_STATE, 0x403, 6, 0 +0x6e45, 0x6574, 0x0072, + IDC_STATE, 0x403, 8, 0 +0x6143, 0x7470, 0x7275, 0x0065, + IDC_STATE, 0x403, 8, 0 +0x6148, 0x7672, 0x7365, 0x0074, + IDC_STATE, 0x403, 11, 0 +0x7241, 0x6165, 0x4720, 0x6175, 0x6472, "\000" + IDC_STATE, 0x403, 17, 0 +0x6552, 0x7574, 0x6e72, 0x3c20, 0x6e75, 0x7375, 0x6465, 0x3e21, "\000" + IDC_STATE, 0x403, 5, 0 +0x7453, 0x706f, "\000" + IDC_STATE, 0x403, 17, 0 +0x6d41, 0x7562, 0x6873, 0x3c20, 0x6e75, 0x7375, 0x6465, 0x3e21, "\000" + IDC_STATE, 0x403, 5, 0 +0x7548, 0x746e, "\000" + IDC_STATE, 0x403, 7, 0 +0x6e55, 0x6f6c, 0x6461, "\000" + IDC_STATE, 0x403, 9, 0 +0x6153, 0x6f62, 0x6174, 0x6567, "\000" + IDC_STATE, 0x403, 13, 0 +0x6f43, 0x736e, 0x7274, 0x6375, 0x6974, 0x6e6f, "\000" + IDC_STATE, 0x403, 8, 0 +0x6553, 0x6c6c, 0x6e69, 0x0067, + IDC_STATE, 0x403, 7, 0 +0x6552, 0x6170, 0x7269, "\000" + IDC_STATE, 0x403, 7, 0 +0x6552, 0x6373, 0x6575, "\000" + IDC_STATE, 0x403, 8, 0 +0x694d, 0x7373, 0x6c69, 0x0065, + IDC_STATE, 0x403, 5, 0 +0x704f, 0x6e65, "\000" + IDC_TAG, 0x403, 5, 0 +0x6f4e, 0x656e, "\000" + IDC_DIRECTION, 0x403, 2, 0 +0x0030, + IDC_DIRECTION, 0x403, 3, 0 +0x3233, "\000" + IDC_DIRECTION, 0x403, 3, 0 +0x3436, "\000" + IDC_DIRECTION, 0x403, 3, 0 +0x3639, "\000" + IDC_DIRECTION, 0x403, 4, 0 +0x3231, 0x0038, + IDC_DIRECTION, 0x403, 4, 0 +0x3631, 0x0030, + IDC_DIRECTION, 0x403, 4, 0 +0x3931, 0x0032, + IDC_DIRECTION, 0x403, 4, 0 +0x3232, 0x0034, + 0 +END + +IDD_HOUSES DLGINIT +BEGIN + IDC_IQ, 0x403, 2, 0 +0x0030, + IDC_IQ, 0x403, 2, 0 +0x0031, + IDC_IQ, 0x403, 2, 0 +0x0032, + IDC_IQ, 0x403, 2, 0 +0x0033, + IDC_IQ, 0x403, 2, 0 +0x0034, + IDC_IQ, 0x403, 2, 0 +0x0035, + IDC_EDGE, 0x403, 5, 0 +0x6557, 0x7473, "\000" + IDC_EDGE, 0x403, 5, 0 +0x6145, 0x7473, "\000" + IDC_EDGE, 0x403, 6, 0 +0x6f4e, 0x7472, 0x0068, + IDC_EDGE, 0x403, 6, 0 +0x6f53, 0x7475, 0x0068, + IDC_SIDE, 0x403, 4, 0 +0x4447, 0x0049, + IDC_SIDE, 0x403, 4, 0 +0x6f4e, 0x0064, + IDC_SIDE, 0x403, 9, 0 +0x6943, 0x6976, 0x696c, 0x6e61, "\000" + IDC_SIDE, 0x403, 7, 0 +0x754d, 0x6174, 0x746e, "\000" + IDC_ACTSLIKE, 0x403, 6, 0 +0x2030, 0x4447, 0x0049, + IDC_ACTSLIKE, 0x403, 6, 0 +0x2031, 0x6f4e, 0x0064, + IDC_NODECOUNT, 0x403, 2, 0 +0x0030, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0030, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0031, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0032, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0033, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0034, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0035, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0036, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0037, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0038, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0039, + IDC_TECHLEVEL, 0x403, 3, 0 +0x3031, "\000" + IDC_PERCENTBUILT, 0x403, 2, 0 +0x0030, + IDC_PERCENTBUILT, 0x403, 3, 0 +0x3035, "\000" + IDC_PERCENTBUILT, 0x403, 4, 0 +0x3031, 0x0030, + IDC_PLAYERCONTROL, 0x403, 3, 0 +0x6f6e, "\000" + IDC_PLAYERCONTROL, 0x403, 4, 0 +0x6579, 0x0073, + 0 +END + +IDD_AIRCRAFT DLGINIT +BEGIN + IDC_STATE, 0x403, 6, 0 +0x6c53, 0x6565, 0x0070, + IDC_STATE, 0x403, 9, 0 +0x6148, 0x6d72, 0x656c, 0x7373, "\000" + IDC_STATE, 0x403, 7, 0 +0x7453, 0x6369, 0x796b, "\000" + IDC_STATE, 0x403, 7, 0 +0x7441, 0x6174, 0x6b63, "\000" + IDC_STATE, 0x403, 5, 0 +0x6f4d, 0x6576, "\000" + IDC_STATE, 0x403, 7, 0 +0x6150, 0x7274, 0x6c6f, "\000" + IDC_STATE, 0x403, 6, 0 +0x4d51, 0x766f, 0x0065, + IDC_STATE, 0x403, 8, 0 +0x6552, 0x7274, 0x6165, 0x0074, + IDC_STATE, 0x403, 6, 0 +0x7547, 0x7261, 0x0064, + IDC_STATE, 0x403, 6, 0 +0x6e45, 0x6574, 0x0072, + IDC_STATE, 0x403, 8, 0 +0x6143, 0x7470, 0x7275, 0x0065, + IDC_STATE, 0x403, 8, 0 +0x6148, 0x7672, 0x7365, 0x0074, + IDC_STATE, 0x403, 11, 0 +0x7241, 0x6165, 0x4720, 0x6175, 0x6472, "\000" + IDC_STATE, 0x403, 17, 0 +0x6552, 0x7574, 0x6e72, 0x3c20, 0x6e75, 0x7375, 0x6465, 0x3e21, "\000" + IDC_STATE, 0x403, 5, 0 +0x7453, 0x706f, "\000" + IDC_STATE, 0x403, 17, 0 +0x6d41, 0x7562, 0x6873, 0x3c20, 0x6e75, 0x7375, 0x6465, 0x3e21, "\000" + IDC_STATE, 0x403, 5, 0 +0x7548, 0x746e, "\000" + IDC_STATE, 0x403, 7, 0 +0x6e55, 0x6f6c, 0x6461, "\000" + IDC_STATE, 0x403, 9, 0 +0x6153, 0x6f62, 0x6174, 0x6567, "\000" + IDC_STATE, 0x403, 13, 0 +0x6f43, 0x736e, 0x7274, 0x6375, 0x6974, 0x6e6f, "\000" + IDC_STATE, 0x403, 8, 0 +0x6553, 0x6c6c, 0x6e69, 0x0067, + IDC_STATE, 0x403, 7, 0 +0x6552, 0x6170, 0x7269, "\000" + IDC_STATE, 0x403, 7, 0 +0x6552, 0x6373, 0x6575, "\000" + IDC_STATE, 0x403, 8, 0 +0x694d, 0x7373, 0x6c69, 0x0065, + IDC_STATE, 0x403, 5, 0 +0x704f, 0x6e65, "\000" + IDC_TAG, 0x403, 5, 0 +0x6f4e, 0x656e, "\000" + IDC_DIRECTION, 0x403, 2, 0 +0x0030, + IDC_DIRECTION, 0x403, 3, 0 +0x3233, "\000" + IDC_DIRECTION, 0x403, 3, 0 +0x3436, "\000" + IDC_DIRECTION, 0x403, 3, 0 +0x3639, "\000" + IDC_DIRECTION, 0x403, 4, 0 +0x3231, 0x0038, + IDC_DIRECTION, 0x403, 4, 0 +0x3631, 0x0030, + IDC_DIRECTION, 0x403, 4, 0 +0x3931, 0x0032, + IDC_DIRECTION, 0x403, 4, 0 +0x3232, 0x0034, + 0 +END + +IDD_BUILDING DLGINIT +BEGIN + IDC_TAG, 0x403, 5, 0 +0x6f4e, 0x656e, "\000" + IDC_DIRECTION, 0x403, 2, 0 +0x0030, + IDC_DIRECTION, 0x403, 3, 0 +0x3233, "\000" + IDC_DIRECTION, 0x403, 3, 0 +0x3436, "\000" + IDC_DIRECTION, 0x403, 3, 0 +0x3639, "\000" + IDC_DIRECTION, 0x403, 4, 0 +0x3231, 0x0038, + IDC_DIRECTION, 0x403, 4, 0 +0x3631, 0x0030, + IDC_DIRECTION, 0x403, 4, 0 +0x3931, 0x0032, + IDC_DIRECTION, 0x403, 4, 0 +0x3232, 0x0034, + IDC_P6, 0x403, 5, 0 +0x6f4e, 0x656e, "\000" + IDC_P7, 0x403, 5, 0 +0x6f4e, 0x656e, "\000" + IDC_P8, 0x403, 5, 0 +0x6f4e, 0x656e, "\000" + IDC_P3, 0x403, 2, 0 +0x0030, + IDC_P3, 0x403, 2, 0 +0x0031, + IDC_P2, 0x403, 2, 0 +0x0030, + IDC_P2, 0x403, 2, 0 +0x0031, + IDC_P4, 0x403, 2, 0 +0x0030, + IDC_P4, 0x403, 2, 0 +0x0031, + IDC_P4, 0x403, 2, 0 +0x0032, + IDC_P4, 0x403, 2, 0 +0x0033, + IDC_P5, 0x403, 17, 0 +0x2030, 0x202d, 0x6f4e, 0x7320, 0x6f70, 0x6c74, 0x6769, 0x7468, "\000" + IDC_P5, 0x403, 22, 0 +0x2031, 0x202d, 0x7552, 0x656c, 0x2e73, 0x6e49, 0x2069, 0x6573, 0x7474, +0x6e69, 0x0067, + IDC_P5, 0x403, 23, 0 +0x2032, 0x202d, 0x6943, 0x6372, 0x656c, 0x2f20, 0x4420, 0x7269, 0x6365, +0x6974, 0x6e6f, "\000" + IDC_P9, 0x403, 2, 0 +0x0030, + IDC_P9, 0x403, 2, 0 +0x0031, + IDC_P10, 0x403, 2, 0 +0x0030, + IDC_P10, 0x403, 2, 0 +0x0031, + 0 +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_TEAMTYPES$(TS_MODE) DLGINIT +#else +IDD_TEAMTYPES DLGINIT +#endif +BEGIN + IDC_TECHLEVEL, 0x403, 2, 0 +0x0030, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0031, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0032, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0033, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0034, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0035, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0036, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0037, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0038, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0039, + IDC_TECHLEVEL, 0x403, 3, 0 +0x3031, "\000" + IDC_GROUP, 0x403, 3, 0 +0x312d, "\000" + IDC_VETERANLEVEL, 0x403, 2, 0 +0x0031, + IDC_VETERANLEVEL, 0x403, 2, 0 +0x0032, + IDC_VETERANLEVEL, 0x403, 2, 0 +0x0033, + IDC_MINDCONTROLDECISION, 0x403, 17, 0 +0x2030, 0x202d, 0x443c, 0x6e6f, 0x7427, 0x6320, 0x7261, 0x3e65, "\000" + IDC_MINDCONTROLDECISION, 0x403, 16, 0 +0x2031, 0x202d, 0x6441, 0x2064, 0x6f54, 0x5420, 0x6165, 0x006d, + IDC_MINDCONTROLDECISION, 0x403, 19, 0 +0x2032, 0x202d, 0x7550, 0x2074, 0x6e69, 0x4720, 0x6972, 0x646e, 0x7265, +"\000" + IDC_MINDCONTROLDECISION, 0x403, 23, 0 +0x2033, 0x202d, 0x7550, 0x2074, 0x6e69, 0x4220, 0x6f69, 0x5220, 0x6165, +0x7463, 0x726f, "\000" + IDC_MINDCONTROLDECISION, 0x403, 15, 0 +0x2034, 0x202d, 0x6f47, 0x7420, 0x206f, 0x7548, 0x746e, "\000" + IDC_MINDCONTROLDECISION, 0x403, 15, 0 +0x2035, 0x202d, 0x6f44, 0x4e20, 0x746f, 0x6968, 0x676e, "\000" + 0 +END +#endif + +IDD_TAGS DLGINIT +BEGIN + IDC_REPEAT, 0x403, 36, 0 +0x2030, 0x202d, 0x614d, 0x656b, 0x7420, 0x6568, 0x7420, 0x6972, 0x6767, +0x7265, 0x7720, 0x726f, 0x206b, 0x6e6f, 0x796c, 0x6f20, 0x636e, 0x0065, + + IDC_REPEAT, 0x403, 12, 0 +0x2031, 0x202d, 0x6e55, 0x6e6b, 0x776f, 0x006e, + IDC_REPEAT, 0x403, 32, 0 +0x2032, 0x202d, 0x614d, 0x656b, 0x7420, 0x6568, 0x7420, 0x6972, 0x6767, +0x7265, 0x7220, 0x7065, 0x6165, 0x6974, 0x676e, 0x0020, + 0 +END + +IDD_TRIGGERS DLGINIT +BEGIN + IDC_TRIGGER2, 0x403, 7, 0 +0x6e3c, 0x6e6f, 0x3e65, "\000" + 0 +END + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_AITRIGGERTYPES$(RA2_MODE) DLGINIT +#else +IDD_AITRIGGERTYPES DLGINIT +#endif +BEGIN + IDC_FLAG2, 0x403, 8, 0 +0x312d, 0x4e20, 0x6e6f, 0x0065, + IDC_FLAG2, 0x403, 37, 0 +0x2030, 0x6e45, 0x6d65, 0x2079, 0x776f, 0x736e, 0x2820, 0x4f43, 0x444e, +0x5449, 0x4f49, 0x294e, 0x4e20, 0x6f20, 0x2066, 0x7974, 0x6570, 0x5820, +"\000" + IDC_FLAG2, 0x403, 37, 0 +0x2031, 0x6f48, 0x7375, 0x2065, 0x776f, 0x736e, 0x2820, 0x4f43, 0x444e, +0x5449, 0x4f49, 0x294e, 0x4e20, 0x6f20, 0x2066, 0x7974, 0x6570, 0x5820, +"\000" + IDC_FLAG2, 0x403, 22, 0 +0x2032, 0x6e45, 0x6d65, 0x3a79, 0x5920, 0x6c65, 0x6f6c, 0x2077, 0x6f70, +0x6577, 0x0072, + IDC_FLAG2, 0x403, 19, 0 +0x2033, 0x6e45, 0x6d65, 0x3a79, 0x5220, 0x6465, 0x7020, 0x776f, 0x7265, +"\000" + IDC_FLAG2, 0x403, 33, 0 +0x2034, 0x6e45, 0x6d65, 0x2079, 0x776f, 0x736e, 0x2820, 0x4f43, 0x444e, +0x5449, 0x4f49, 0x294e, 0x4e20, 0x6d20, 0x6e6f, 0x7965, "\000" + IDC_FLAG2, 0x403, 26, 0 +0x2035, 0x7249, 0x6e6f, 0x6320, 0x7275, 0x6174, 0x6e69, 0x6e20, 0x6165, +0x2072, 0x6572, 0x6461, 0x0079, + IDC_FLAG2, 0x403, 26, 0 +0x2036, 0x6843, 0x6f72, 0x6f6e, 0x7073, 0x6568, 0x6572, 0x6e20, 0x6165, +0x2072, 0x6572, 0x6461, 0x0079, + IDC_FLAG2, 0x403, 39, 0 +0x2037, 0x654e, 0x7475, 0x6172, 0x206c, 0x776f, 0x736e, 0x2820, 0x4f43, +0x444e, 0x5449, 0x4f49, 0x294e, 0x4e20, 0x6f20, 0x2066, 0x7974, 0x6570, +0x5820, "\000" + IDC_DATA, 0x403, 65, 0 +0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, +0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, +0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, +0x3030, 0x3030, 0x3030, 0x3030, 0x3030, "\000" + IDC_MULTISIDE, 0x403, 7, 0 +0x2030, 0x6f4e, 0x656e, "\000" + IDC_MULTISIDE, 0x403, 9, 0 +0x2031, 0x6c41, 0x696c, 0x6465, "\000" + IDC_MULTISIDE, 0x403, 9, 0 +0x2032, 0x6f53, 0x6976, 0x7465, "\000" + IDC_MULTISIDE, 0x403, 8, 0 +0x2033, 0x6854, 0x7269, 0x0064, + IDC_CONDITION, 0x403, 10, 0 +0x656c, 0x7373, 0x7420, 0x6168, 0x006e, + IDC_CONDITION, 0x403, 22, 0 +0x656c, 0x7373, 0x7420, 0x6168, 0x206e, 0x726f, 0x6520, 0x7571, 0x6c61, +0x7420, 0x006f, + IDC_CONDITION, 0x403, 9, 0 +0x7165, 0x6175, 0x206c, 0x6f74, "\000" + IDC_CONDITION, 0x403, 25, 0 +0x7267, 0x6165, 0x6574, 0x2072, 0x6874, 0x6e61, 0x6f20, 0x2072, 0x7165, +0x6175, 0x206c, 0x6f74, "\000" + IDC_CONDITION, 0x403, 13, 0 +0x7267, 0x6165, 0x6574, 0x2072, 0x6874, 0x6e61, "\000" + IDC_CONDITION, 0x403, 13, 0 +0x6f6e, 0x2074, 0x7165, 0x6175, 0x206c, 0x6f74, "\000" + 0 +END +#endif + +IDD_BASIC DLGINIT +BEGIN + IDC_ENDOFGAME, 0x403, 3, 0 +0x6f6e, "\000" + IDC_ENDOFGAME, 0x403, 4, 0 +0x6579, 0x0073, + IDC_SKIPSCORE, 0x403, 3, 0 +0x6f6e, "\000" + IDC_SKIPSCORE, 0x403, 4, 0 +0x6579, 0x0073, + IDC_ONETIMEONLY, 0x403, 3, 0 +0x6f6e, "\000" + IDC_ONETIMEONLY, 0x403, 4, 0 +0x6579, 0x0073, + IDC_SKIPMAPSELECT, 0x403, 3, 0 +0x6f6e, "\000" + IDC_SKIPMAPSELECT, 0x403, 4, 0 +0x6579, 0x0073, + IDC_OFFICIAL, 0x403, 3, 0 +0x6f6e, "\000" + IDC_OFFICIAL, 0x403, 4, 0 +0x6579, 0x0073, + IDC_IGNOREGLOBALAITRIGGERS, 0x403, 3, 0 +0x6f6e, "\000" + IDC_IGNOREGLOBALAITRIGGERS, 0x403, 4, 0 +0x6579, 0x0073, + IDC_TRUCKCRATE, 0x403, 3, 0 +0x6f6e, "\000" + IDC_TRUCKCRATE, 0x403, 4, 0 +0x6579, 0x0073, + IDC_TRAINCRATE, 0x403, 3, 0 +0x6f6e, "\000" + IDC_TRAINCRATE, 0x403, 4, 0 +0x6579, 0x0073, + IDC_TIBERIUMGROWTHENABLED, 0x403, 3, 0 +0x6f6e, "\000" + IDC_TIBERIUMGROWTHENABLED, 0x403, 4, 0 +0x6579, 0x0073, + IDC_VEINGROWTHENABLED, 0x403, 3, 0 +0x6f6e, "\000" + IDC_VEINGROWTHENABLED, 0x403, 4, 0 +0x6579, 0x0073, + IDC_ICEGROWTHENABLED, 0x403, 3, 0 +0x6f6e, "\000" + IDC_ICEGROWTHENABLED, 0x403, 4, 0 +0x6579, 0x0073, + IDC_TIBERIUMDEATHTOVISCEROID, 0x403, 3, 0 +0x6f6e, "\000" + IDC_TIBERIUMDEATHTOVISCEROID, 0x403, 4, 0 +0x6579, 0x0073, + IDC_FREERADAR, 0x403, 3, 0 +0x6f6e, "\000" + IDC_FREERADAR, 0x403, 4, 0 +0x6579, 0x0073, + IDC_REQUIREDADDON, 0x403, 2, 0 +0x0030, + IDC_REQUIREDADDON, 0x403, 2, 0 +0x0031, + 0 +END + +IDD_SINGLEPLAYER DLGINIT +BEGIN + IDC_STARTINGDROPSHIPS, 0x403, 2, 0 +0x0030, + IDC_STARTINGDROPSHIPS, 0x403, 2, 0 +0x0031, + IDC_TIMERINHERIT, 0x403, 4, 0 +0x6579, 0x0073, + IDC_TIMERINHERIT, 0x403, 3, 0 +0x6f6e, "\000" + IDC_FILLSILOS, 0x403, 4, 0 +0x6579, 0x0073, + IDC_FILLSILOS, 0x403, 3, 0 +0x6f6e, "\000" + 0 +END + +IDD_SCRIPTTYPES DLGINIT +BEGIN + IDC_TYPE, 0x403, 32, 0 +0x2030, 0x202d, 0x7441, 0x6174, 0x6b63, 0x7420, 0x7261, 0x6567, 0x2074, +0x7428, 0x7261, 0x6567, 0x2074, 0x7974, 0x6570, 0x0029, + IDC_TYPE, 0x403, 38, 0 +0x2031, 0x202d, 0x7441, 0x6174, 0x6b63, 0x7720, 0x7961, 0x6f70, 0x6e69, +0x2074, 0x7728, 0x7961, 0x6f70, 0x6e69, 0x2074, 0x756e, 0x626d, 0x7265, +0x0029, + IDC_TYPE, 0x403, 39, 0 +0x2033, 0x202d, 0x6f4d, 0x6576, 0x7420, 0x206f, 0x6177, 0x7079, 0x696f, +0x746e, 0x2820, 0x6177, 0x7079, 0x696f, 0x746e, 0x6e20, 0x6d75, 0x6562, +0x2972, "\000" + IDC_TYPE, 0x403, 58, 0 +0x2034, 0x202d, 0x6f4d, 0x6576, 0x7420, 0x206f, 0x6563, 0x6c6c, 0x2820, +0x6177, 0x7079, 0x696f, 0x746e, 0x7620, 0x6c61, 0x6575, 0x2820, 0x5820, +0x5858, 0x5959, 0x2c59, 0x6120, 0x2074, 0x656c, 0x7361, 0x2074, 0x5958, +0x5959, 0x0029, + IDC_TYPE, 0x403, 37, 0 +0x2035, 0x202d, 0x7547, 0x7261, 0x2064, 0x7261, 0x6165, 0x2820, 0x6974, +0x656d, 0x7520, 0x696e, 0x7374, 0x7420, 0x206f, 0x7567, 0x7261, 0x2964, +"\000" + IDC_TYPE, 0x403, 36, 0 +0x2036, 0x202d, 0x754a, 0x706d, 0x7420, 0x206f, 0x6361, 0x6974, 0x6e6f, +0x2320, 0x2820, 0x6361, 0x6974, 0x6e6f, 0x7420, 0x206f, 0x6f67, 0x0029, + + IDC_TYPE, 0x403, 18, 0 +0x2037, 0x202d, 0x7441, 0x6174, 0x6b63, 0x7420, 0x7261, 0x6f63, 0x006d, + + IDC_TYPE, 0x403, 46, 0 +0x2038, 0x202d, 0x6e55, 0x6f6c, 0x6461, 0x6320, 0x7261, 0x6f67, 0x2820, +0x7073, 0x696c, 0x2074, 0x7274, 0x6e61, 0x7073, 0x726f, 0x2074, 0x6e61, +0x2064, 0x7274, 0x6f6f, 0x7370, 0x0029, + IDC_TYPE, 0x403, 24, 0 +0x2039, 0x202d, 0x6544, 0x6c70, 0x796f, 0x2820, 0x6170, 0x6172, 0x206d, +0x7369, 0x3020, 0x0029, + IDC_TYPE, 0x403, 30, 0 +0x3131, 0x2d20, 0x4420, 0x206f, 0x6562, 0x6168, 0x6976, 0x756f, 0x2072, +0x6228, 0x6865, 0x7661, 0x6f69, 0x7275, 0x0029, + IDC_TYPE, 0x403, 32, 0 +0x3431, 0x2d20, 0x4c20, 0x616f, 0x2064, 0x6e6f, 0x7420, 0x6172, 0x736e, +0x6f70, 0x7472, 0x2073, 0x7528, 0x6573, 0x3020, 0x0029, + IDC_TYPE, 0x403, 42, 0 +0x3631, 0x2d20, 0x5020, 0x7461, 0x6f72, 0x206c, 0x6f74, 0x7720, 0x7961, +0x6f70, 0x6e69, 0x2074, 0x7728, 0x7961, 0x6f70, 0x6e69, 0x2074, 0x756e, +0x626d, 0x7265, 0x0029, + IDC_TYPE, 0x403, 46, 0 +0x3032, 0x2d20, 0x4320, 0x6168, 0x676e, 0x2065, 0x6f68, 0x7375, 0x2065, +0x6e28, 0x6d75, 0x6562, 0x2072, 0x666f, 0x6e20, 0x7765, 0x6f20, 0x6e77, +0x7265, 0x6820, 0x756f, 0x6573, 0x0029, + IDC_TYPE, 0x403, 23, 0 +0x3733, 0x2d20, 0x4c20, 0x6165, 0x6576, 0x6d20, 0x7061, 0x2820, 0x7375, +0x2065, 0x2930, "\000" + IDC_TYPE, 0x403, 25, 0 +0x3933, 0x2d20, 0x5320, 0x7465, 0x6720, 0x6f6c, 0x6162, 0x206c, 0x6728, +0x6f6c, 0x6162, 0x296c, "\000" + IDC_TYPE, 0x403, 19, 0 +0x3034, 0x2d20, 0x4320, 0x656c, 0x7261, 0x6720, 0x6f6c, 0x6162, 0x3f6c, +"\000" + IDC_TYPE, 0x403, 25, 0 +0x3234, 0x2d20, 0x5420, 0x7275, 0x206e, 0x6e69, 0x6f74, 0x6420, 0x7269, +0x6365, 0x6974, 0x6e6f, "\000" + IDC_TYPE, 0x403, 16, 0 +0x3434, 0x2d20, 0x4c20, 0x616f, 0x2064, 0x6163, 0x6772, 0x006f, + IDC_TYPE, 0x403, 18, 0 +0x3534, 0x2d20, 0x5520, 0x6c6e, 0x616f, 0x2064, 0x6163, 0x6772, 0x006f, + + IDC_TYPE, 0x403, 29, 0 +0x3634, 0x2d20, 0x4120, 0x7474, 0x6361, 0x206b, 0x6174, 0x6772, 0x7465, +0x7320, 0x7274, 0x6375, 0x7574, 0x6572, "\000" + IDC_TYPE, 0x403, 30, 0 +0x3734, 0x2d20, 0x4d20, 0x766f, 0x2065, 0x6f74, 0x7420, 0x7261, 0x6567, +0x2074, 0x7473, 0x7572, 0x7463, 0x7275, 0x0065, + 0 +END + +IDD_NEWMAP DLGINIT +BEGIN + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0030, + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0031, + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0032, + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0033, + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0034, + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0035, + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0036, + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0037, + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0038, + IDC_GROUNDHEIGHT, 0x403, 2, 0 +0x0039, + IDC_GROUNDHEIGHT, 0x403, 3, 0 +0x3031, "\000" + 0 +END + +IDD_TOOLSETTINGS DLGINIT +BEGIN + IDC_BRUSHSIZE, 0x403, 4, 0 +0x7831, 0x0031, + IDC_BRUSHSIZE, 0x403, 4, 0 +0x7832, 0x0032, + IDC_BRUSHSIZE, 0x403, 4, 0 +0x7833, 0x0033, + IDC_BRUSHSIZE, 0x403, 4, 0 +0x7834, 0x0034, + IDC_BRUSHSIZE, 0x403, 4, 0 +0x7835, 0x0035, + IDC_BRUSHSIZE, 0x403, 6, 0 +0x3031, 0x3178, 0x0030, + IDC_BRUSHSIZE, 0x403, 4, 0 +0x7831, 0x0032, + IDC_BRUSHSIZE, 0x403, 4, 0 +0x7832, 0x0031, + IDC_BRUSHSIZE, 0x403, 4, 0 +0x7831, 0x0033, + IDC_BRUSHSIZE, 0x403, 4, 0 +0x7833, 0x0031, + 0 +END + +IDD_TRIGGEROPTIONS DLGINIT +BEGIN + IDC_TRIGGERTYPE, 0x403, 13, 0 +0x2030, 0x202d, 0x7453, 0x6e61, 0x6164, 0x6472, "\000" + IDC_TRIGGERTYPE, 0x403, 14, 0 +0x2032, 0x202d, 0x6552, 0x6570, 0x7461, 0x6e69, 0x0067, + IDC_HOUSE, 0x403, 13, 0 +0x2030, 0x202d, 0x7453, 0x6e61, 0x6164, 0x6472, "\000" + IDC_HOUSE, 0x403, 14, 0 +0x2032, 0x202d, 0x6552, 0x6570, 0x7461, 0x6e69, 0x0067, + 0 +END + +IDD_GLOBALS DLGINIT +BEGIN + IDC_VALUE, 0x403, 10, 0 +0x2030, 0x202d, 0x6c43, 0x6165, 0x0072, + IDC_VALUE, 0x403, 8, 0 +0x2031, 0x202d, 0x6553, 0x0074, + 0 +END + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_TEAMTYPES$(RA2_MODE) DLGINIT +#else +IDD_TEAMTYPES DLGINIT +#endif +BEGIN + IDC_TECHLEVEL, 0x403, 2, 0 +0x0030, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0031, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0032, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0033, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0034, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0035, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0036, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0037, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0038, + IDC_TECHLEVEL, 0x403, 2, 0 +0x0039, + IDC_TECHLEVEL, 0x403, 3, 0 +0x3031, "\000" + IDC_GROUP, 0x403, 3, 0 +0x312d, "\000" + IDC_VETERANLEVEL, 0x403, 2, 0 +0x0031, + IDC_VETERANLEVEL, 0x403, 2, 0 +0x0032, + IDC_VETERANLEVEL, 0x403, 2, 0 +0x0033, + IDC_MINDCONTROLDECISION, 0x403, 17, 0 +0x2030, 0x202d, 0x443c, 0x6e6f, 0x7427, 0x6320, 0x7261, 0x3e65, "\000" + IDC_MINDCONTROLDECISION, 0x403, 16, 0 +0x2031, 0x202d, 0x6441, 0x2064, 0x6f54, 0x5420, 0x6165, 0x006d, + IDC_MINDCONTROLDECISION, 0x403, 19, 0 +0x2032, 0x202d, 0x7550, 0x2074, 0x6e69, 0x4720, 0x6972, 0x646e, 0x7265, +"\000" + IDC_MINDCONTROLDECISION, 0x403, 23, 0 +0x2033, 0x202d, 0x7550, 0x2074, 0x6e69, 0x4220, 0x6f69, 0x5220, 0x6165, +0x7463, 0x726f, "\000" + IDC_MINDCONTROLDECISION, 0x403, 15, 0 +0x2034, 0x202d, 0x6f47, 0x7420, 0x206f, 0x7548, 0x746e, "\000" + IDC_MINDCONTROLDECISION, 0x403, 15, 0 +0x2035, 0x202d, 0x6f44, 0x4e20, 0x746f, 0x6968, 0x676e, "\000" + 0 +END +#endif + +IDD_NEWMAPCREATENEW DLGINIT +BEGIN + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0030, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0031, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0032, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0033, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0034, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0035, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0036, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0037, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0038, + 0 +END + +IDD_NEWMAPBITMAP DLGINIT +BEGIN + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0030, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0031, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0032, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0033, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0034, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0035, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0036, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0037, + IDC_STARTINGHEIGHT, 0x403, 2, 0 +0x0038, + 0 +END + +IDD_UNIT DLGINIT +BEGIN + IDC_STATE, 0x403, 6, 0 +0x6c53, 0x6565, 0x0070, + IDC_STATE, 0x403, 9, 0 +0x6148, 0x6d72, 0x656c, 0x7373, "\000" + IDC_STATE, 0x403, 7, 0 +0x7453, 0x6369, 0x796b, "\000" + IDC_STATE, 0x403, 7, 0 +0x7441, 0x6174, 0x6b63, "\000" + IDC_STATE, 0x403, 5, 0 +0x6f4d, 0x6576, "\000" + IDC_STATE, 0x403, 7, 0 +0x6150, 0x7274, 0x6c6f, "\000" + IDC_STATE, 0x403, 6, 0 +0x4d51, 0x766f, 0x0065, + IDC_STATE, 0x403, 8, 0 +0x6552, 0x7274, 0x6165, 0x0074, + IDC_STATE, 0x403, 6, 0 +0x7547, 0x7261, 0x0064, + IDC_STATE, 0x403, 6, 0 +0x6e45, 0x6574, 0x0072, + IDC_STATE, 0x403, 8, 0 +0x6143, 0x7470, 0x7275, 0x0065, + IDC_STATE, 0x403, 8, 0 +0x6148, 0x7672, 0x7365, 0x0074, + IDC_STATE, 0x403, 11, 0 +0x7241, 0x6165, 0x4720, 0x6175, 0x6472, "\000" + IDC_STATE, 0x403, 17, 0 +0x6552, 0x7574, 0x6e72, 0x3c20, 0x6e75, 0x7375, 0x6465, 0x3e21, "\000" + IDC_STATE, 0x403, 5, 0 +0x7453, 0x706f, "\000" + IDC_STATE, 0x403, 17, 0 +0x6d41, 0x7562, 0x6873, 0x3c20, 0x6e75, 0x7375, 0x6465, 0x3e21, "\000" + IDC_STATE, 0x403, 5, 0 +0x7548, 0x746e, "\000" + IDC_STATE, 0x403, 7, 0 +0x6e55, 0x6f6c, 0x6461, "\000" + IDC_STATE, 0x403, 9, 0 +0x6153, 0x6f62, 0x6174, 0x6567, "\000" + IDC_STATE, 0x403, 13, 0 +0x6f43, 0x736e, 0x7274, 0x6375, 0x6974, 0x6e6f, "\000" + IDC_STATE, 0x403, 8, 0 +0x6553, 0x6c6c, 0x6e69, 0x0067, + IDC_STATE, 0x403, 7, 0 +0x6552, 0x6170, 0x7269, "\000" + IDC_STATE, 0x403, 7, 0 +0x6552, 0x6373, 0x6575, "\000" + IDC_STATE, 0x403, 8, 0 +0x694d, 0x7373, 0x6c69, 0x0065, + IDC_STATE, 0x403, 5, 0 +0x704f, 0x6e65, "\000" + IDC_TAG, 0x403, 5, 0 +0x6f4e, 0x656e, "\000" + IDC_DIRECTION, 0x403, 2, 0 +0x0030, + IDC_DIRECTION, 0x403, 3, 0 +0x3233, "\000" + IDC_DIRECTION, 0x403, 3, 0 +0x3436, "\000" + IDC_DIRECTION, 0x403, 3, 0 +0x3639, "\000" + IDC_DIRECTION, 0x403, 4, 0 +0x3231, 0x0038, + IDC_DIRECTION, 0x403, 4, 0 +0x3631, 0x0030, + IDC_DIRECTION, 0x403, 4, 0 +0x3931, 0x0032, + IDC_DIRECTION, 0x403, 4, 0 +0x3232, 0x0034, + 0 +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_AITRIGGERTYPES$(TS_MODE) DLGINIT +#else +IDD_AITRIGGERTYPES DLGINIT +#endif +BEGIN + IDC_FLAG2, 0x403, 8, 0 +0x312d, 0x4e20, 0x6e6f, 0x0065, + IDC_FLAG2, 0x403, 37, 0 +0x2030, 0x6e45, 0x6d65, 0x2079, 0x776f, 0x736e, 0x2820, 0x4f43, 0x444e, +0x5449, 0x4f49, 0x294e, 0x4e20, 0x6f20, 0x2066, 0x7974, 0x6570, 0x5820, +"\000" + IDC_FLAG2, 0x403, 37, 0 +0x2031, 0x6f48, 0x7375, 0x2065, 0x776f, 0x736e, 0x2820, 0x4f43, 0x444e, +0x5449, 0x4f49, 0x294e, 0x4e20, 0x6f20, 0x2066, 0x7974, 0x6570, 0x5820, +"\000" + IDC_FLAG2, 0x403, 22, 0 +0x2032, 0x6e45, 0x6d65, 0x3a79, 0x5920, 0x6c65, 0x6f6c, 0x2077, 0x6f70, +0x6577, 0x0072, + IDC_FLAG2, 0x403, 19, 0 +0x2033, 0x6e45, 0x6d65, 0x3a79, 0x5220, 0x6465, 0x7020, 0x776f, 0x7265, +"\000" + IDC_FLAG2, 0x403, 33, 0 +0x2034, 0x6e45, 0x6d65, 0x2079, 0x776f, 0x736e, 0x2820, 0x4f43, 0x444e, +0x5449, 0x4f49, 0x294e, 0x4e20, 0x6d20, 0x6e6f, 0x7965, "\000" + IDC_DATA, 0x403, 65, 0 +0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, +0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, +0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, +0x3030, 0x3030, 0x3030, 0x3030, 0x3030, "\000" + IDC_MULTISIDE, 0x403, 7, 0 +0x2030, 0x6f4e, 0x656e, "\000" + IDC_MULTISIDE, 0x403, 6, 0 +0x2031, 0x4447, 0x0049, + IDC_MULTISIDE, 0x403, 6, 0 +0x2032, 0x6f4e, 0x0064, + IDC_CONDITION, 0x403, 10, 0 +0x656c, 0x7373, 0x7420, 0x6168, 0x006e, + IDC_CONDITION, 0x403, 22, 0 +0x656c, 0x7373, 0x7420, 0x6168, 0x206e, 0x726f, 0x6520, 0x7571, 0x6c61, +0x7420, 0x006f, + IDC_CONDITION, 0x403, 9, 0 +0x7165, 0x6175, 0x206c, 0x6f74, "\000" + IDC_CONDITION, 0x403, 25, 0 +0x7267, 0x6165, 0x6574, 0x2072, 0x6874, 0x6e61, 0x6f20, 0x2072, 0x7165, +0x6175, 0x206c, 0x6f74, "\000" + IDC_CONDITION, 0x403, 13, 0 +0x7267, 0x6165, 0x6574, 0x2072, 0x6874, 0x6e61, "\000" + IDC_CONDITION, 0x403, 13, 0 +0x6f6e, 0x2074, 0x7165, 0x6175, 0x206c, 0x6f74, "\000" + 0 +END +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +#if defined(APSTUDIO_INVOKED) || defined(YR_MODE) +#if defined(APSTUDIO_INVOKED) +IDR_MAINFRAME$(YR_MODE) ICON "res\\FinalAlert2YR.ico" + +#else +IDR_MAINFRAME ICON "res\\FinalAlert2YR.ico" + +#endif +#endif +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE_ICON) +#if defined(APSTUDIO_INVOKED) +IDR_MAINFRAME$(RA2_MODE_ICON) ICON "res\\FinalAlert2.ico" + +#else +IDR_MAINFRAME ICON "res\\FinalAlert2.ico" + +#endif +#endif +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDR_MAINFRAME$(TS_MODE) ICON "res\\FinalSun.ico" + +#else +IDR_MAINFRAME ICON "res\\FinalSun.ico" + +#endif +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// WAVE +// + +IDR_WAVE1 WAVE "RES\\uacbopen.wav" + +IDR_WAVE2 WAVE "RES\\ugamclos.wav" + +IDR_WAVE3 WAVE "RES\\umenscol.wav" + +IDR_WAVE4 WAVE "RES\\uqeue.wav" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +VS_VERSION_INFO$(RA2_MODE) VERSIONINFO +#else +VS_VERSION_INFO VERSIONINFO +#endif + FILEVERSION 1,0,0,2 + PRODUCTVERSION 1,0,0,2 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x2bL +#else + FILEFLAGS 0x2aL +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "FinalAlert 2: Yuri's Revenge Mission Editor" + VALUE "CompanyName", "Electronic Arts, Inc." + VALUE "FileDescription", "FinalAlert 2: Yuri's Revenge" + VALUE "FileVersion", "2.00" + VALUE "InternalName", "FinalAlert 2: Yuri's Revenge Mission Editor" + VALUE "LegalCopyright", "Copyright (C) 1999-2024 Electronic Arts, Inc." + VALUE "LegalTrademarks", "FinalAlert 2: Yuri's Revenge" + VALUE "OriginalFilename", "FinalAlert2YR.EXE" + VALUE "ProductName", "FinalAlert 2: Yuri's Revenge" + VALUE "ProductVersion", "2.00" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +VS_VERSION_INFO$(TS_MODE) VERSIONINFO +#else +VS_VERSION_INFO VERSIONINFO +#endif + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x23L +#else + FILEFLAGS 0x22L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "FinalSun Mission Editor" + VALUE "CompanyName", "Electronic Arts, Inc." + VALUE "FileDescription", "FinalSun" + VALUE "FileVersion", "2.00" + VALUE "InternalName", "FinalSun Mission Editor" + VALUE "LegalCopyright", "Copyright (C) 1999-2024 Electronic Arts, Inc." + VALUE "LegalTrademarks", "FinalSun" + VALUE "OriginalFilename", "FinalSun.EXE" + VALUE "ProductName", "FinalSun" + VALUE "ProductVersion", "2.00" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDR_MAIN$(TS_MODE) MENU +#else +IDR_MAIN MENU +#endif +BEGIN + POPUP "File" + BEGIN + MENUITEM "New", ID_FILE_NEW + MENUITEM SEPARATOR + MENUITEM "Open", ID_FILE_OPENMAP + MENUITEM SEPARATOR + MENUITEM "Save", ID_FILE_SAVE + MENUITEM "Save as", ID_FILE_SAVEAS + MENUITEM SEPARATOR + MENUITEM "Check map", ID_FILE_VALIDATEMAP + MENUITEM SEPARATOR + MENUITEM "Quit", ID_FILE_QUIT + END + POPUP "Edit" + BEGIN + MENUITEM "Undo\tCtrl+Z", ID_EDIT_UNDO + MENUITEM "Redo\tCtrl+Y", ID_EDIT_REDO + MENUITEM SEPARATOR + MENUITEM "Copy\tCtrl+C", ID_EDIT_COPY + MENUITEM "Copy whole map", ID_EDIT_COPYWHOLEMAP + MENUITEM "Paste\tCtrl+V", ID_EDIT_PASTE + MENUITEM "Paste centered", ID_EDIT_PASTEWHOLEMAP + MENUITEM SEPARATOR + MENUITEM "Map", ID_EDIT_MAP + MENUITEM "Basic", ID_EDIT_BASICSETTINGS + MENUITEM "Special flags", ID_EDIT_SPECIALFLAGS + MENUITEM "Lighting", ID_EDIT_LIGHTING + MENUITEM SEPARATOR + MENUITEM "Singleplayer settings", ID_EDIT_SINGLEPLAYERSETTINGS + MENUITEM SEPARATOR + MENUITEM "Houses", ID_EDIT_HOUSES + MENUITEM SEPARATOR + MENUITEM "Local variables (Locals)", ID_EDIT_GLOBALVARIABLES + MENUITEM SEPARATOR + MENUITEM "Trigger editor", ID_EDIT_TRIGGEREDITOR + MENUITEM "Tag editor", ID_EDIT_TAGS + MENUITEM SEPARATOR + MENUITEM "Scripts", ID_EDIT_SCRIPTS + MENUITEM SEPARATOR + MENUITEM "Taskforces", ID_EDIT_TASKFORCES + MENUITEM "Teams", ID_EDIT_TEAMS + MENUITEM SEPARATOR + MENUITEM "AI Triggers", ID_EDIT_AITRIGGERS + MENUITEM "AI Trigger enabling", ID_EDIT_AITRIGGERENABLING + MENUITEM SEPARATOR + MENUITEM "INI editing", ID_EDIT_INIEDITING + END + POPUP "Terrain" + BEGIN + MENUITEM "Raise ground", ID_TERRAIN_HEIGHTENGROUND + MENUITEM "Lower ground", ID_TERRAIN_LOWERGROUND + MENUITEM "Flatten ground", ID_TERRAIN_FLATTEN + MENUITEM SEPARATOR + MENUITEM "Hide tileset", ID_TERRAIN_CLOAK + MENUITEM "Show every tileset", ID_TERRAIN_SHOWEVERYTILE + MENUITEM "Hide single field", ID_TERRAIN_HIDEFIELD + MENUITEM "Show all fields", ID_TERRAIN_SHOWALLFIELDS + MENUITEM SEPARATOR + MENUITEM "Raise single tile (Be careful!)", ID_TERRAIN_RAISETILE + MENUITEM "Lower single tile (Be careful!)", ID_TERRAIN_LOWERTILE + END + POPUP "Map tools" + BEGIN + MENUITEM "Change map height", ID_MAPTOOLS_CHANGEMAPHEIGHT + MENUITEM SEPARATOR + MENUITEM "Autocreate shores", ID_MAPTOOLS_AUTOCREATESHORES + MENUITEM "Auto level using cliffs", ID_MAPTOOLS_AUTOLEVEL + MENUITEM SEPARATOR + MENUITEM "Paint cliff front", ID_MAPTOOLS_FRONTCLIFF + MENUITEM "Paint cliff back", ID_MAPTOOLS_BACKCLIFF + MENUITEM SEPARATOR + MENUITEM "Search Waypoint", ID_MAPTOOLS_SEARCHWAYPOINT + MENUITEM SEPARATOR + MENUITEM "Tool Scripts", ID_MAPTOOLS_TOOLSCRIPTS + END + POPUP "Options" + BEGIN + MENUITEM "Settings", ID_OPTIONS_TIBERIANSUNOPTIONS + MENUITEM "Show minimap", ID_OPTIONS_SHOWMINIMAP + MENUITEM "Easy mode", ID_OPTIONS_SIMPLEVIEW + MENUITEM "Sounds", ID_OPTIONS_SOUNDS + MENUITEM "Show Building Outline", ID_OPTIONS_SHOWBUILDINGOUTLINE + MENUITEM "Disable AutoShore\tCTRL-A", ID_OPTIONS_DISABLEAUTOSHORE + MENUITEM "Disable AutoLat\tCTRL-L", ID_OPTIONS_DISABLEAUTOLAT + MENUITEM "Disable Slope Correction", ID_OPTIONS_DISABLESLOPECORRECTION + MENUITEM "Smooth zoom", ID_OPTIONS_SMOOTHZOOM + MENUITEM "Use default mouse cursor", ID_OPTIONS_USEDEFAULTMOUSECURSOR + END + POPUP "Help" + BEGIN + MENUITEM "Manual\tF1", ID_HELP + MENUITEM SEPARATOR + MENUITEM "Info", ID_HELP_INFO + MENUITEM "Tip of the day", ID_HELP_TIPOFTHEDAY + MENUITEM SEPARATOR + MENUITEM "Show logs", ID_HELP_SHOWLOGS + END +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDR_MAIN$(RA2_MODE) MENU +#else +IDR_MAIN MENU +#endif +BEGIN + POPUP "File" + BEGIN + MENUITEM "New", ID_FILE_NEW + MENUITEM SEPARATOR + MENUITEM "Open", ID_FILE_OPENMAP + MENUITEM SEPARATOR + MENUITEM "Save", ID_FILE_SAVE + MENUITEM "Save as", ID_FILE_SAVEAS + MENUITEM SEPARATOR + MENUITEM "Check map", ID_FILE_VALIDATEMAP + MENUITEM SEPARATOR + MENUITEM "Quit", ID_FILE_QUIT + END + POPUP "Edit" + BEGIN + MENUITEM "Undo\tCtrl+Z", ID_EDIT_UNDO + MENUITEM "Redo\tCtrl+Y", ID_EDIT_REDO + MENUITEM SEPARATOR + MENUITEM "Copy\tCtrl+C", ID_EDIT_COPY + MENUITEM "Copy whole map", ID_EDIT_COPYWHOLEMAP + MENUITEM "Paste\tCtrl+V", ID_EDIT_PASTE + MENUITEM "Paste centered", ID_EDIT_PASTEWHOLEMAP + MENUITEM SEPARATOR + MENUITEM "Map", ID_EDIT_MAP + MENUITEM "Basic", ID_EDIT_BASICSETTINGS + MENUITEM "Special flags", ID_EDIT_SPECIALFLAGS + MENUITEM "Lighting", ID_EDIT_LIGHTING + MENUITEM SEPARATOR + MENUITEM "Singleplayer settings", ID_EDIT_SINGLEPLAYERSETTINGS + MENUITEM SEPARATOR + MENUITEM "Houses", ID_EDIT_HOUSES + MENUITEM SEPARATOR + MENUITEM "Local variables (Locals)", ID_EDIT_GLOBALVARIABLES + MENUITEM SEPARATOR + MENUITEM "Trigger editor", ID_EDIT_TRIGGEREDITOR + MENUITEM "Tag editor", ID_EDIT_TAGS + MENUITEM SEPARATOR + MENUITEM "Scripts", ID_EDIT_SCRIPTS + MENUITEM SEPARATOR + MENUITEM "Taskforces", ID_EDIT_TASKFORCES + MENUITEM "Teams", ID_EDIT_TEAMS + MENUITEM SEPARATOR + MENUITEM "AI Triggers", ID_EDIT_AITRIGGERS + MENUITEM "AI Trigger enabling", ID_EDIT_AITRIGGERENABLING + MENUITEM SEPARATOR + MENUITEM "INI editing", ID_EDIT_INIEDITING + END + POPUP "Terrain" + BEGIN + MENUITEM "Raise ground", ID_TERRAIN_HEIGHTENGROUND + MENUITEM "Lower ground", ID_TERRAIN_LOWERGROUND + MENUITEM "Flatten ground", ID_TERRAIN_FLATTEN + MENUITEM SEPARATOR + MENUITEM "Hide tileset", ID_TERRAIN_CLOAK + MENUITEM "Show every tileset", ID_TERRAIN_SHOWEVERYTILE + MENUITEM "Hide single field", ID_TERRAIN_HIDEFIELD + MENUITEM "Show all fields", ID_TERRAIN_SHOWALLFIELDS + MENUITEM SEPARATOR + MENUITEM "Raise single tile (Be careful!)", ID_TERRAIN_RAISETILE + MENUITEM "Lower single tile (Be careful!)", ID_TERRAIN_LOWERTILE + END + POPUP "Map tools" + BEGIN + MENUITEM "Change map height", ID_MAPTOOLS_CHANGEMAPHEIGHT + MENUITEM SEPARATOR + MENUITEM "Autocreate shores", ID_MAPTOOLS_AUTOCREATESHORES + MENUITEM "Auto level using cliffs", ID_MAPTOOLS_AUTOLEVEL + MENUITEM SEPARATOR + MENUITEM "Paint cliff front", ID_MAPTOOLS_FRONTCLIFF + MENUITEM "Paint cliff back", ID_MAPTOOLS_BACKCLIFF + MENUITEM SEPARATOR + MENUITEM "Search Waypoint", ID_MAPTOOLS_SEARCHWAYPOINT + MENUITEM SEPARATOR + MENUITEM "Tool Scripts", ID_MAPTOOLS_TOOLSCRIPTS + END + POPUP "Options" + BEGIN + MENUITEM "Settings", ID_OPTIONS_TIBERIANSUNOPTIONS + MENUITEM "Show minimap", ID_OPTIONS_SHOWMINIMAP + MENUITEM "Easy mode", ID_OPTIONS_SIMPLEVIEW + MENUITEM "Sounds", ID_OPTIONS_SOUNDS + MENUITEM "Show Building Outline", ID_OPTIONS_SHOWBUILDINGOUTLINE + MENUITEM "Disable AutoShore\tCTRL-A", ID_OPTIONS_DISABLEAUTOSHORE + MENUITEM "Disable AutoLat\tCTRL-L", ID_OPTIONS_DISABLEAUTOLAT + MENUITEM "Disable Slope Correction", ID_OPTIONS_DISABLESLOPECORRECTION + MENUITEM "Smooth zoom", ID_OPTIONS_SMOOTHZOOM + MENUITEM "Use default mouse cursor", ID_OPTIONS_USEDEFAULTMOUSECURSOR + END + POPUP "Help" + BEGIN + MENUITEM "Manual\tF1", ID_HELP + MENUITEM SEPARATOR + MENUITEM "Info", ID_HELP_INFO + MENUITEM "Tip of the day", ID_HELP_TIPOFTHEDAY + MENUITEM SEPARATOR + MENUITEM "Show logs", ID_HELP_SHOWLOGS + END +END +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// Toolbar +// + +IDR_MAINFRAME TOOLBAR 16, 15 +BEGIN + BUTTON ID_FILE_NEW + BUTTON ID_FILE_OPENMAP + BUTTON ID_FILE_SAVE +END + +IDR_TERRAINBAR TOOLBAR 16, 15 +BEGIN + BUTTON ID_TERRAIN_HEIGHTENGROUND + BUTTON ID_TERRAIN_LOWERGROUND + BUTTON ID_TERRAIN_FLATTEN + BUTTON ID_TERRAIN_CLOAK + BUTTON ID_TERRAIN_SHOWEVERYTILE + BUTTON ID_TERRAIN_HIDEFIELD + BUTTON ID_TERRAIN_SHOWALLFIELDS + BUTTON ID_TERRAIN_RAISETILE + BUTTON ID_TERRAIN_LOWERTILE + SEPARATOR + BUTTON ID_MARBLEMADNESS +END + +IDR_CLIFFBAR TOOLBAR 16, 15 +BEGIN + BUTTON ID_MAPTOOLS_FRONTCLIFF + BUTTON ID_MAPTOOLS_BACKCLIFF + SEPARATOR + BUTTON ID_MAPTOOLS_AUTOLEVEL + BUTTON ID_MAPTOOLS_AUTOCREATESHORES +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MAIN ACCELERATORS +BEGIN + "A", ID_OPTIONS_DISABLEAUTOSHORE, VIRTKEY, CONTROL, NOINVERT + "C", ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT + "F", ID_MARBLEMADNESS, VIRTKEY, CONTROL, NOINVERT + "L", ID_OPTIONS_DISABLEAUTOLAT, VIRTKEY, CONTROL, NOINVERT + "V", ID_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT + "Y", ID_EDIT_REDO, VIRTKEY, CONTROL, NOINVERT + "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_INFO$(RA2_MODE) AFX_DIALOG_LAYOUT +#else +IDD_INFO AFX_DIALOG_LAYOUT +#endif +BEGIN + 0 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_INFO$(TS_MODE) AFX_DIALOG_LAYOUT +#else +IDD_INFO AFX_DIALOG_LAYOUT +#endif +BEGIN + 0 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_LOADING$(RA2_MODE) AFX_DIALOG_LAYOUT +#else +IDD_LOADING AFX_DIALOG_LAYOUT +#endif +BEGIN + 0 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_LOADING$(TS_MODE) AFX_DIALOG_LAYOUT +#else +IDD_LOADING AFX_DIALOG_LAYOUT +#endif +BEGIN + 0 +END +#endif + +IDD_FINALSUN_DIALOG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_TIP AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#if defined(APSTUDIO_INVOKED) || defined(TS_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_TSOPTIONS$(TS_MODE) AFX_DIALOG_LAYOUT +#else +IDD_TSOPTIONS AFX_DIALOG_LAYOUT +#endif +BEGIN + 0 +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(RA2_MODE) +#if defined(APSTUDIO_INVOKED) +IDD_TSOPTIONS$(RA2_MODE) AFX_DIALOG_LAYOUT +#else +IDD_TSOPTIONS AFX_DIALOG_LAYOUT +#endif +BEGIN + 0 +END +#endif + +IDD_TRIGGEREDITOR AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_TRIGGERACTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_TRIGGEREVENTS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_TRIGGEROPTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_MAPVALIDATOR AFX_DIALOG_LAYOUT +BEGIN + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_BUILTBY "Matthias Wagner" + IDS_VERSIONTEXT "Version 2.00" + IDS_VERSION "2.00" + IDS_VERSIONTEXTTS "Version 2.00" +END + +STRINGTABLE +BEGIN + ID_TERRAIN_HEIGHTENGROUND "Heighten ground (slope logic)" + ID_TERRAIN_LOWERGROUND "Lower ground (slope logic)" + ID_TERRAIN_PAINT "Paint terrain types" + ID_TERRAIN_RISETILE "Raise a single tile" + ID_TERRAIN_RAISETILE "Raise a single tile" + ID_TERRAIN_LOWERTILE "Lower a single tile" +END + +STRINGTABLE +BEGIN + ID_TERRAIN_FLATTEN "Make terrain flat" + ID_TERRAIN_CLOAK "Hide tileset" + ID_TERRAIN_SHOWEVERYTILE "Show all tilesets" + ID_TERRAIN_SHOWALLFIELDS "Show all fields" + ID_TERRAIN_HIDEFIELD "Hide single field" +END + +STRINGTABLE +BEGIN + ID_FILE_NEW "New map" + ID_FILE_SAVE "Save map" + IDS_LINEARVERSION "3" +END + +STRINGTABLE +BEGIN + ID_FILE_OPENMAP "Open map" +END + +STRINGTABLE +BEGIN + ID_MAPTOOLS_AUTOLEVEL "AutoLevel terrain height using cliffs" + ID_MAPTOOLS_FRONTCLIFF "Paint cliff front" + ID_MAPTOOLS_BACKCLIFF "Paint cliff back" +END + +STRINGTABLE +BEGIN + ID_MAPTOOLS_AUTOCREATESHORES "AutoCreate shores" +END + +STRINGTABLE +BEGIN + ID_MARBLEMADNESS "Switch Framework Mode" +END + +#endif // Englisch (USA) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(65001) +#endif //_WIN32 +#include "res\FinalSun.rc2" // Nicht mit Microsoft Visual C++ bearbeitete Ressourcen +#include "afxres.rc" // Standardkomponenten +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/MissionEditor/MultiSaveOptionsDlg.cpp b/MissionEditor/MultiSaveOptionsDlg.cpp new file mode 100644 index 0000000..dc9d3bb --- /dev/null +++ b/MissionEditor/MultiSaveOptionsDlg.cpp @@ -0,0 +1,63 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MultiSaveOptionsDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "MultiSaveOptionsDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CMultiSaveOptionsDlg + + +CMultiSaveOptionsDlg::CMultiSaveOptionsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CMultiSaveOptionsDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CMultiSaveOptionsDlg) + m_mmx = 0; + //}}AFX_DATA_INIT +} + + +void CMultiSaveOptionsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CMultiSaveOptionsDlg) + DDX_Radio(pDX, IDC_MMX, m_mmx); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CMultiSaveOptionsDlg, CDialog) + //{{AFX_MSG_MAP(CMultiSaveOptionsDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros fĂ¼r Nachrichten ein + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CMultiSaveOptionsDlg diff --git a/MissionEditor/MultiSaveOptionsDlg.h b/MissionEditor/MultiSaveOptionsDlg.h new file mode 100644 index 0000000..0e0bcd4 --- /dev/null +++ b/MissionEditor/MultiSaveOptionsDlg.h @@ -0,0 +1,66 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_MULTISAVEOPTIONSDLG_H__72E7BEC1_E8B2_11D4_9C88_444553540000__INCLUDED_) +#define AFX_MULTISAVEOPTIONSDLG_H__72E7BEC1_E8B2_11D4_9C88_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// MultiSaveOptionsDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CMultiSaveOptionsDlg + +class CMultiSaveOptionsDlg : public CDialog +{ +// Konstruktion +public: + CMultiSaveOptionsDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CMultiSaveOptionsDlg) + enum { IDD = IDD_MULTISAVEOPT }; + int m_mmx; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CMultiSaveOptionsDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CMultiSaveOptionsDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_MULTISAVEOPTIONSDLG_H__72E7BEC1_E8B2_11D4_9C88_444553540000__INCLUDED_ diff --git a/MissionEditor/MyComboBox.cpp b/MissionEditor/MyComboBox.cpp new file mode 100644 index 0000000..a3efe6e --- /dev/null +++ b/MissionEditor/MyComboBox.cpp @@ -0,0 +1,75 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MyComboBox.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "MyComboBox.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CMyComboBox + +CMyComboBox::CMyComboBox() +{ +} + +CMyComboBox::~CMyComboBox() +{ +} + + +BEGIN_MESSAGE_MAP(CMyComboBox, CComboBox) + //{{AFX_MSG_MAP(CMyComboBox) + ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelchange) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CMyComboBox + + +/* +This will automatically send a CBN_EDITCHANGE command. +Also it will set the window text to the selected item +*/ +void CMyComboBox::OnSelchange() +{ + CString SelectedItem; + GetLBText(GetCurSel(),SelectedItem); + + + SetWindowText(SelectedItem); + + WPARAM wparam; + int ctrlid=GetDlgCtrlID(); + WORD command=CBN_EDITCHANGE; + memcpy((BYTE*)&wparam+2, &command, 2); + memcpy((BYTE*)&wparam, &ctrlid, 2); + GetOwner()->SendMessage(WM_COMMAND,wparam,(LPARAM)m_hWnd); + +} diff --git a/MissionEditor/MyComboBox.h b/MissionEditor/MyComboBox.h new file mode 100644 index 0000000..500e3db --- /dev/null +++ b/MissionEditor/MyComboBox.h @@ -0,0 +1,68 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_MYCOMBOBOX_H__6B1D6F02_A9A7_11D3_B63B_B4DF98412640__INCLUDED_) +#define AFX_MYCOMBOBOX_H__6B1D6F02_A9A7_11D3_B63B_B4DF98412640__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// MyComboBox.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Fenster CMyComboBox + +class CMyComboBox : public CComboBox +{ +// Konstruktion +public: + CMyComboBox(); + +// Attribute +public: + +// Operationen +public: + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CMyComboBox) + //}}AFX_VIRTUAL + +// Implementierung +public: + virtual ~CMyComboBox(); + + // Generierte Nachrichtenzuordnungsfunktionen +protected: + //{{AFX_MSG(CMyComboBox) + afx_msg void OnSelchange(); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_MYCOMBOBOX_H__6B1D6F02_A9A7_11D3_B63B_B4DF98412640__INCLUDED_ diff --git a/MissionEditor/MyViewFrame.cpp b/MissionEditor/MyViewFrame.cpp new file mode 100644 index 0000000..7f7cbbd --- /dev/null +++ b/MissionEditor/MyViewFrame.cpp @@ -0,0 +1,177 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// MyViewFrame.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "MyViewFrame.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CMyViewFrame + +IMPLEMENT_DYNCREATE(CMyViewFrame, CFrameWnd) + +CMyViewFrame::CMyViewFrame() +{ + m_isoview=0; +} + +CMyViewFrame::~CMyViewFrame() +{ +} + + +BEGIN_MESSAGE_MAP(CMyViewFrame, CFrameWnd) + //{{AFX_MSG_MAP(CMyViewFrame) + ON_WM_SYSCOMMAND() + ON_WM_SIZE() + ON_WM_GETMINMAXINFO() + ON_WM_KEYDOWN() + ON_WM_KEYUP() + ON_WM_CHAR() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CMyViewFrame + +BOOL CMyViewFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) +{ + SIZE z; + z.cx=200; + z.cy=200; + + CRect r; + r.right=200; + r.bottom=200; + + + + if(!m_Splitter.CreateStatic(this,1,2)) return FALSE; + + + if(!m_Splitter.CreateView(0,0, + RUNTIME_CLASS(CViewObjects), + z, + pContext)) return FALSE; + + if(!m_Splitter.CreateView(0,1, + RUNTIME_CLASS(CRightFrame), + z, + pContext)) return FALSE; + + OutputDebugString("CMyViewFrame::OnCreateClient(): windows created\n"); + + m_rightFrame=(CRightFrame*)m_Splitter.GetPane(0,1); + + m_isoview=(CIsoView*)m_rightFrame->m_Splitter.GetPane(0,0); + m_isoview->owner=this; + m_browser=(CTileSetBrowserFrame*)m_rightFrame->m_Splitter.GetPane(1,0); + m_objectview=(CViewObjects*)m_Splitter.GetPane(0,0); + + // the minimap is not a child window right now, but it is created here though + auto miniMapClass = AfxRegisterWndClass(0, m_hArrowCursor, static_cast<HBRUSH>(::GetStockObject(GRAY_BRUSH))); + m_minimap.CreateEx(0, miniMapClass, "Minimap", WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE, r, NULL, 0); + //m_minimap.Create(NULL, "Minimap", WS_OVERLAPPED) + m_minimap.UpdateView(); + + if(!m_statbar.CreateEx(this,SBARS_SIZEGRIP | SBT_TOOLTIPS)) return FALSE; + + return CFrameWnd::OnCreateClient(lpcs, pContext); +} + +void CMyViewFrame::OnSysCommand(UINT nID, LPARAM lParam) +{ +if(nID==SC_CLOSE) + { + // ok now just hide the window + ShowWindow(SW_HIDE); + return; + } + CFrameWnd::OnSysCommand(nID, lParam); +} + +void CMyViewFrame::OnSize(UINT nType, int cx, int cy) +{ + // we now check if our frame window has already created its child windows + // this is true at the second OnSize + // TODO: replace static + static BOOL wasHere=FALSE; + if(wasHere==FALSE) + { + wasHere=TRUE; + return; + } + + CFrameWnd::OnSize(nType, cx, cy); + CStatusBarCtrl& stat=m_statbar.GetStatusBarCtrl(); + + m_statbar.ShowWindow(SW_SHOW); + CRect sr; + GetWindowRect(sr); + //int Widths[]={sr.right-80,80,-1}; + int Widths[]={sr.right-sr.left-130,-1}; + stat.SetParts(2, Widths); + stat.SetSimple(FALSE); + m_statbar.ShowWindow(SW_SHOW); +} + +void CMyViewFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + lpMMI->ptMinTrackSize.x=260; + lpMMI->ptMinTrackSize.y=150; + CFrameWnd::OnGetMinMaxInfo(lpMMI); +} + +void CMyViewFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + m_isoview->SendMessage(WM_KEYDOWN, nChar, nFlags); + // CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags); +} + + + +void CMyViewFrame::PostNcDestroy() +{ + // do not call CFrameWnd::PostNcDestroy(), as long as MyViewFrame is not on the heap! + // CFrameWnd::PostNcDestroy(); +} + +void CMyViewFrame::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + // TODO: Code fĂ¼r die Behandlungsroutine fĂ¼r Nachrichten hier einfĂ¼gen und/oder Standard aufrufen + + // CFrameWnd::OnKeyUp(nChar, nRepCnt, nFlags); +} + +void CMyViewFrame::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + // TODO: Code fĂ¼r die Behandlungsroutine fĂ¼r Nachrichten hier einfĂ¼gen und/oder Standard aufrufen + + // CFrameWnd::OnChar(nChar, nRepCnt, nFlags); +} diff --git a/MissionEditor/MyViewFrame.h b/MissionEditor/MyViewFrame.h new file mode 100644 index 0000000..462a194 --- /dev/null +++ b/MissionEditor/MyViewFrame.h @@ -0,0 +1,90 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_MYVIEWFRAME_H__98929AE1_9B75_11D3_B63B_D046A7216340__INCLUDED_) +#define AFX_MYVIEWFRAME_H__98929AE1_9B75_11D3_B63B_D046A7216340__INCLUDED_ + +#include "IsoView.h" + +#if _MSC_VER > 1000 +#pragma once +#endif + +// MyViewFrame.h : Header file +// + +#include "isoview.h" +#include "viewobjects.h" +#include "MiniMap.h" +#include "RightFrame.h" +#include "TileSetBrowserFrame.h" + +///////////////////////////////////////////////////////////////////////////// +// Frame CMyViewFrame + +class CMyViewFrame : public CFrameWnd +{ + DECLARE_DYNCREATE(CMyViewFrame) +protected: + + +// attributes +public: + CMiniMap m_minimap; + CStatusBar m_statbar; + CViewObjects* m_objectview; + CIsoView* m_isoview; + CSplitterWnd m_Splitter; + +// operations +public: + CTileSetBrowserFrame* m_browser; + CRightFrame* m_rightFrame; + CMyViewFrame(); + ~CMyViewFrame(); + +// overwriteables + + //{{AFX_VIRTUAL(CMyViewFrame) + protected: + virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext); + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// implementation +protected: + + // generated message maps + //{{AFX_MSG(CMyViewFrame) + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} + +#endif // AFX_MYVIEWFRAME_H__98929AE1_9B75_11D3_B63B_D046A7216340__INCLUDED_ diff --git a/MissionEditor/NewMap.cpp b/MissionEditor/NewMap.cpp new file mode 100644 index 0000000..c7b9e2d --- /dev/null +++ b/MissionEditor/NewMap.cpp @@ -0,0 +1,287 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// NewMap.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "NewMap.h" +#include "MapOpenDialog.h" +#include "resource.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + +extern CFinalSunApp theApp; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMap + + +CNewMap::CNewMap(CWnd* pParent /*=NULL*/) + : CDialog(CNewMap::IDD, pParent) +{ + //{{AFX_DATA_INIT(CNewMap) + m_ImportOverlay = FALSE; + m_ImportTrees = FALSE; + m_ImportUnits = FALSE; + m_Multiplayer = FALSE; + m_House = _T(""); + m_PrepareHouses = FALSE; + m_AutoProduction = FALSE; + m_Height = 0; + m_Width = 0; + m_Import = -1; + m_Theater = 0; + m_GroundHeight = 2; + //}}AFX_DATA_INIT +} + + +void CNewMap::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CNewMap) + DDX_Control(pDX, IDOK, m_OK); + DDX_Check(pDX, IDC_IMPORTOVERLAY, m_ImportOverlay); + DDX_Check(pDX, IDC_IMPORTTREES, m_ImportTrees); + DDX_Check(pDX, IDC_IMPORTUNITS, m_ImportUnits); + DDX_Check(pDX, IDC_MULTIPLAYER, m_Multiplayer); + DDX_CBString(pDX, IDC_HOUSE, m_House); + DDX_Check(pDX, IDC_PREPAREHOUSES, m_PrepareHouses); + DDX_Check(pDX, IDC_AUTOPROD, m_AutoProduction); + DDX_Text(pDX, IDC_HEIGHT, m_Height); + DDV_MinMaxUInt(pDX, m_Height, 8, 255); + DDX_Text(pDX, IDC_WIDTH, m_Width); + DDV_MinMaxUInt(pDX, m_Width, 8, 255); + DDX_Radio(pDX, IDC_IMPORT, m_Import); + DDX_CBIndex(pDX, IDC_THEATER, m_Theater); + DDX_CBIndex(pDX, IDC_GROUNDHEIGHT, m_GroundHeight); + DDX_Control(pDX, IDC_IMPORTFILE, m_ImportFile); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CNewMap, CDialog) + //{{AFX_MSG_MAP(CNewMap) + ON_BN_CLICKED(IDC_BROWSE, OnBrowse) + ON_BN_CLICKED(IDC_MULTIPLAYER, OnMultiplayer) + ON_CBN_EDITCHANGE(IDC_IMPORTFILE, OnEditchangeImportfile) + ON_BN_CLICKED(IDC_IMPORT, OnImport) + ON_BN_CLICKED(IDC_NEW, OnNew) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CNewMap + +BOOL CNewMap::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // preset some stuff + m_ImportOverlay=TRUE; + m_ImportUnits=TRUE; + m_OK.EnableWindow(FALSE); + m_ImportTrees=TRUE; + m_PrepareHouses=TRUE; + m_AutoProduction=TRUE; + m_Theater=0; + m_Import=1; + m_Width=64; + m_Height=64; + + + CComboBox& house=*((CComboBox*)(GetDlgItem(IDC_HOUSE))); + int i; + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + house.AddString(*rules.sections[HOUSES].GetValue(i)); + } + + m_House=rules.sections[HOUSES].values["0"]; + + CComboBox& theater=*((CComboBox*)GetDlgItem(IDC_THEATER)); + theater.AddString(THEATER0); + theater.AddString(THEATER1); +#ifdef RA2_MODE + theater.AddString(THEATER2); +#endif + + m_Theater=0; + + UpdateData(FALSE); + + UpdateStrings(); + + + + + + + // set cursor to wait + SetCursor(LoadCursor(NULL,IDC_WAIT)); + + CString maps=CString(u8AppDataPath.c_str())+"\\stdmaps\\*.mpr"; + CFileFind ff; + + if(ff.FindFile(maps)) + { + BOOL bFileAvailable=TRUE; + while(bFileAvailable) { + bFileAvailable=ff.FindNextFile(); + + CString file=ff.GetFileName(); + m_ImportFile.AddString(file); + } + + m_ImportFile.SetCurSel(0); + OnEditchangeImportfile(); + } + + m_OK.EnableWindow(TRUE); + + // set cursor to ready + SetCursor(m_hArrowCursor); + + return TRUE; +} + +void CNewMap::OnBrowse() +{ + UpdateData(); + + CMapOpenDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST, "TS maps|*.mpr;*.map|TS multi maps|*.mpr|TS single maps|*.map|"); + + char cuPath[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, cuPath); + dlg.m_ofn.lpstrInitialDir=cuPath; + + if(theApp.m_Options.TSExe.GetLength()) dlg.m_ofn.lpstrInitialDir=(char*)(LPCTSTR)theApp.m_Options.TSExe; + + + if(dlg.DoModal()==IDCANCEL) return; + + m_ImportFile.SetWindowText(dlg.GetPathName()); + + UpdateData(FALSE); + OnEditchangeImportfile(); +} + + + +void CNewMap::OnOK() +{ + UpdateData(); + + CDialog::OnOK(); +} + +void CNewMap::OnMultiplayer() +{ + UpdateData(); + + CButton& ph=*((CButton*)(GetDlgItem(IDC_PREPAREHOUSES))); + CButton& autoprod=*((CButton*)(GetDlgItem(IDC_AUTOPROD))); + CComboBox& house=*((CComboBox*)(GetDlgItem(IDC_HOUSE))); + + if(m_Multiplayer) + { + ph.EnableWindow(FALSE); + autoprod.EnableWindow(FALSE); + m_AutoProduction=FALSE; + house.EnableWindow(FALSE); + m_PrepareHouses=FALSE; + } + else + { + autoprod.EnableWindow(TRUE); + m_AutoProduction=TRUE; + ph.EnableWindow(TRUE); + house.EnableWindow(TRUE); + m_PrepareHouses=TRUE; + } + + UpdateData(FALSE); +} + +void CNewMap::UpdateStrings() +{ + SetDlgItemText(IDC_LDESC, GetLanguageStringACP("NewMapDesc")); + SetDlgItemText(IDC_BROWSE, GetLanguageStringACP("NewMapBrowse")); + SetDlgItemText(IDC_MULTIPLAYER, GetLanguageStringACP("NewMapMultiplayer")); + SetDlgItemText(IDC_PREPAREHOUSES, GetLanguageStringACP("NewMapPrepareStandardHouses")); + SetDlgItemText(IDC_AUTOPROD, GetLanguageStringACP("NewMapSetAutoProduction")); + SetDlgItemText(IDC_LPLAYERHOUSE, GetLanguageStringACP("NewMapPlayerHouse")); + SetDlgItemText(IDC_LIMPORTOPTIONS, GetLanguageStringACP("NewMapImportOptions")); + SetDlgItemText(IDC_IMPORTTREES, GetLanguageStringACP("NewMapImportTrees")); + SetDlgItemText(IDC_IMPORTOVERLAY, GetLanguageStringACP("NewMapImportOverlay")); + SetDlgItemText(IDC_IMPORTUNITS, GetLanguageStringACP("NewMapImportUnits")); + SetDlgItemText(IDOK, GetLanguageStringACP("OK")); + SetDlgItemText(IDCANCEL, GetLanguageStringACP("Cancel")); + + SetWindowText(GetLanguageStringACP("NewMapCap")); +} + +void CNewMap::OnEditchangeImportfile() +{ + UpdateData(); + + CIniFile cmap; + CString file; + m_ImportFile.GetWindowText(file); + + m_MapToImport=file; + + if(file.Find(":")<0) + { + m_MapToImport=CString(u8AppDataPath.c_str())+"\\stdmaps\\"; + m_MapToImport+=file; + } + + cmap.InsertFile(m_MapToImport,"Map"); + + if(cmap.sections.find("Map")==cmap.sections.end()) + { + m_OK.EnableWindow(FALSE); + return; + } + + m_OK.EnableWindow(TRUE); +} + + +void CNewMap::OnImport() +{ + m_OK.EnableWindow(FALSE); + OnEditchangeImportfile(); +} + +void CNewMap::OnNew() +{ + m_OK.EnableWindow(TRUE); +} diff --git a/MissionEditor/NewMap.h b/MissionEditor/NewMap.h new file mode 100644 index 0000000..a65147e --- /dev/null +++ b/MissionEditor/NewMap.h @@ -0,0 +1,88 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_NEWMAP_H__868C3FC0_AF27_11D3_B63B_BE68077E9F41__INCLUDED_) +#define AFX_NEWMAP_H__868C3FC0_AF27_11D3_B63B_BE68077E9F41__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// NewMap.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMap + +class CNewMap : public CDialog +{ +// Konstruktion +public: + CString m_MapToImport; + void UpdateStrings(); + CNewMap(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CNewMap) + enum { IDD = IDD_NEWMAP }; + CButton m_OK; + BOOL m_ImportOverlay; + BOOL m_ImportTrees; + BOOL m_ImportUnits; + BOOL m_Multiplayer; + CString m_House; + BOOL m_PrepareHouses; + BOOL m_AutoProduction; + UINT m_Height; + UINT m_Width; + int m_Import; + int m_Theater; + int m_GroundHeight; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CNewMap) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CNewMap) + virtual BOOL OnInitDialog(); + afx_msg void OnBrowse(); + virtual void OnOK(); + afx_msg void OnMultiplayer(); + afx_msg void OnEditchangeImportfile(); + afx_msg void OnImport(); + afx_msg void OnNew(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + CMyComboBox m_ImportFile; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_NEWMAP_H__868C3FC0_AF27_11D3_B63B_BE68077E9F41__INCLUDED_ diff --git a/MissionEditor/NewMapCreateDlg.cpp b/MissionEditor/NewMapCreateDlg.cpp new file mode 100644 index 0000000..2da20b7 --- /dev/null +++ b/MissionEditor/NewMapCreateDlg.cpp @@ -0,0 +1,75 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// NewMapCreateDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "NewMapCreateDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapCreateDlg + + +CNewMapCreateDlg::CNewMapCreateDlg(CWnd* pParent /*=NULL*/) + : CDialog(CNewMapCreateDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CNewMapCreateDlg) + m_CreateType = -1; + m_AITriggers = TRUE; + //}}AFX_DATA_INIT +} + + +void CNewMapCreateDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CNewMapCreateDlg) + DDX_Radio(pDX, IDC_CREATE, m_CreateType); + DDX_Check(pDX, IDC_AITRIGGERS, m_AITriggers); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CNewMapCreateDlg, CDialog) + //{{AFX_MSG_MAP(CNewMapCreateDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CNewMapCreateDlg + +BOOL CNewMapCreateDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_CreateType=0; + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} diff --git a/MissionEditor/NewMapCreateDlg.h b/MissionEditor/NewMapCreateDlg.h new file mode 100644 index 0000000..6c42f3e --- /dev/null +++ b/MissionEditor/NewMapCreateDlg.h @@ -0,0 +1,67 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_NEWMAPCREATEDLG_H__F7D62442_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_) +#define AFX_NEWMAPCREATEDLG_H__F7D62442_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// NewMapCreateDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapCreateDlg + +class CNewMapCreateDlg : public CDialog +{ +// Konstruktion +public: + CNewMapCreateDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CNewMapCreateDlg) + enum { IDD = IDD_NEWMAPCREATE }; + int m_CreateType; + BOOL m_AITriggers; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CNewMapCreateDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CNewMapCreateDlg) + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_NEWMAPCREATEDLG_H__F7D62442_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ diff --git a/MissionEditor/NewMapCreateNewDlg.cpp b/MissionEditor/NewMapCreateNewDlg.cpp new file mode 100644 index 0000000..c78eec8 --- /dev/null +++ b/MissionEditor/NewMapCreateNewDlg.cpp @@ -0,0 +1,122 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// NewMapCreateNewDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "NewMapCreateNewDlg.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapCreateNewDlg + + +CNewMapCreateNewDlg::CNewMapCreateNewDlg(CWnd* pParent /*=NULL*/) + : CDialog(CNewMapCreateNewDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CNewMapCreateNewDlg) + m_Height = 0; + m_Width = 0; + m_StartingHeight = -1; + m_Theater = -1; + //}}AFX_DATA_INIT +} + + +void CNewMapCreateNewDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CNewMapCreateNewDlg) + DDX_Text(pDX, IDC_HEIGHT, m_Height); + DDX_Text(pDX, IDC_WIDTH, m_Width); + DDX_CBIndex(pDX, IDC_STARTINGHEIGHT, m_StartingHeight); + DDX_CBIndex(pDX, IDC_THEATER, m_Theater); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CNewMapCreateNewDlg, CDialog) + //{{AFX_MSG_MAP(CNewMapCreateNewDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CNewMapCreateNewDlg + +BOOL CNewMapCreateNewDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CComboBox& theater=*((CComboBox*)GetDlgItem(IDC_THEATER)); + theater.AddString(THEATER0); + theater.AddString(THEATER1); +#ifdef RA2_MODE + theater.AddString(THEATER2); + if(yuri_mode) // MW YR support + { + theater.AddString(THEATER3); + theater.AddString(THEATER4); + theater.AddString(THEATER5); + } + +#endif + + m_Theater=0; + m_Width=50; + m_Height=50; + m_StartingHeight=0; + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CNewMapCreateNewDlg::OnOK() +{ + + UpdateData(TRUE); + + if(m_Width>400 || m_Height>400 || m_Width<16 || m_Height<16 || (m_Width + m_Height) > 512) + { + MessageBox("Width and Height must both be between 16 and 400 and both added must be less than 512.","Error"); + return; + } + + if(m_Width+m_Height>256) + { +#ifdef RA2_MODE + int res=MessageBox("Width + height is bigger than 256, this may cause problems in RA2. Continue?","Warning",MB_YESNO); +#else + int res=MessageBox("Width + height is bigger than 256, this may cause problems in TS. Continue?","Warning",MB_YESNO); +#endif + if(res==IDNO) return; + } + + CDialog::OnOK(); +} diff --git a/MissionEditor/NewMapCreateNewDlg.h b/MissionEditor/NewMapCreateNewDlg.h new file mode 100644 index 0000000..0951e0c --- /dev/null +++ b/MissionEditor/NewMapCreateNewDlg.h @@ -0,0 +1,70 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_NEWMAPCREATENEWDLG_H__F7D62443_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_) +#define AFX_NEWMAPCREATENEWDLG_H__F7D62443_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// NewMapCreateNewDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapCreateNewDlg + +class CNewMapCreateNewDlg : public CDialog +{ +// Konstruktion +public: + CNewMapCreateNewDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CNewMapCreateNewDlg) + enum { IDD = IDD_NEWMAPCREATENEW }; + int m_Height; + int m_Width; + int m_StartingHeight; + int m_Theater; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CNewMapCreateNewDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CNewMapCreateNewDlg) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_NEWMAPCREATENEWDLG_H__F7D62443_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ diff --git a/MissionEditor/NewMapImportDlg.cpp b/MissionEditor/NewMapImportDlg.cpp new file mode 100644 index 0000000..de615a9 --- /dev/null +++ b/MissionEditor/NewMapImportDlg.cpp @@ -0,0 +1,118 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// NewMapImportDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "NewMapImportDlg.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapImportDlg + + +CNewMapImportDlg::CNewMapImportDlg(CWnd* pParent /*=NULL*/) + : CDialog(CNewMapImportDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CNewMapImportDlg) + m_ImportFile = _T(""); + m_ImportOverlay = FALSE; + m_ImportTrees = FALSE; + m_ImportUnits = FALSE; + //}}AFX_DATA_INIT +} + + +void CNewMapImportDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CNewMapImportDlg) + DDX_CBString(pDX, IDC_IMPORTFILE, m_ImportFile); + DDX_Check(pDX, IDC_IMPORTOVERLAY, m_ImportOverlay); + DDX_Check(pDX, IDC_IMPORTTREES, m_ImportTrees); + DDX_Check(pDX, IDC_IMPORTUNITS, m_ImportUnits); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CNewMapImportDlg, CDialog) + //{{AFX_MSG_MAP(CNewMapImportDlg) + ON_BN_CLICKED(IDC_BROWSE, OnBrowse) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CNewMapImportDlg + +void CNewMapImportDlg::OnBrowse() +{ + UpdateData(); + + //CComboBox* m_ImportFile=(CComboBox*)GetDlgItem(IDC_IMPORTFILE); + + CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST, "All files|*.mpr;*.map;*.bmp|TS/RA2 multi maps|*.mpr|TS/RA2 single maps|*.map|Windows bitmaps|*.bmp|"); + + char cuPath[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, cuPath); + dlg.m_ofn.lpstrInitialDir=cuPath; + + if(theApp.m_Options.TSExe.GetLength()) dlg.m_ofn.lpstrInitialDir=(char*)(LPCTSTR)theApp.m_Options.TSExe; + + + if(dlg.DoModal()==IDCANCEL) return; + + m_ImportFile=dlg.GetPathName(); + + UpdateData(FALSE); +} + +BOOL CNewMapImportDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CComboBox* m_ImportFile=(CComboBox*)GetDlgItem(IDC_IMPORTFILE); + + CString maps = CString(u8AppDataPath.c_str()) + "\\stdmaps\\*.mpr"; + CFileFind ff; + + if(ff.FindFile(maps)) + { + BOOL bFileAvailable=TRUE; + while(bFileAvailable) { + bFileAvailable=ff.FindNextFile(); + + CString file=ff.GetFileName(); + m_ImportFile->AddString(file); + } + + m_ImportFile->SetCurSel(0); + } + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} diff --git a/MissionEditor/NewMapImportDlg.h b/MissionEditor/NewMapImportDlg.h new file mode 100644 index 0000000..2d0228c --- /dev/null +++ b/MissionEditor/NewMapImportDlg.h @@ -0,0 +1,70 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_NEWMAPIMPORTDLG_H__F7D62444_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_) +#define AFX_NEWMAPIMPORTDLG_H__F7D62444_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// NewMapImportDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapImportDlg + +class CNewMapImportDlg : public CDialog +{ +// Konstruktion +public: + CNewMapImportDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CNewMapImportDlg) + enum { IDD = IDD_NEWMAPIMPORT }; + CString m_ImportFile; + BOOL m_ImportOverlay; + BOOL m_ImportTrees; + BOOL m_ImportUnits; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CNewMapImportDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CNewMapImportDlg) + afx_msg void OnBrowse(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_NEWMAPIMPORTDLG_H__F7D62444_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ diff --git a/MissionEditor/NewMapSpDlg.cpp b/MissionEditor/NewMapSpDlg.cpp new file mode 100644 index 0000000..379ac17 --- /dev/null +++ b/MissionEditor/NewMapSpDlg.cpp @@ -0,0 +1,105 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// NewMapSpDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "NewMapSpDlg.h" +#include "variables.h" +#include "functions.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapSpDlg + + +CNewMapSpDlg::CNewMapSpDlg(CWnd* pParent /*=NULL*/) + : CDialog(CNewMapSpDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CNewMapSpDlg) + m_AutoProd = FALSE; + m_House = -1; + m_PrepareHouses = FALSE; + //}}AFX_DATA_INIT +} + + +void CNewMapSpDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CNewMapSpDlg) + DDX_Check(pDX, IDC_AUTOPROD, m_AutoProd); + DDX_CBIndex(pDX, IDC_HOUSE, m_House); + DDX_Check(pDX, IDC_PREPAREHOUSES, m_PrepareHouses); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CNewMapSpDlg, CDialog) + //{{AFX_MSG_MAP(CNewMapSpDlg) + ON_BN_CLICKED(IDC_PREPAREHOUSES, OnPreparehouses) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CNewMapSpDlg + +void CNewMapSpDlg::OnPreparehouses() +{ + UpdateData(TRUE); + BOOL bEnable=m_PrepareHouses; + + GetDlgItem(IDC_AUTOPROD)->EnableWindow(bEnable); + GetDlgItem(IDC_HOUSE)->EnableWindow(bEnable); + +} + +BOOL CNewMapSpDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CComboBox& house=*((CComboBox*)(GetDlgItem(IDC_HOUSE))); + int i; + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + house.AddString(TranslateHouse(*rules.sections[HOUSES].GetValue(i), TRUE)); + } + + m_PrepareHouses=TRUE; + m_AutoProd=TRUE; + m_House=0; + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CNewMapSpDlg::OnOK() +{ + CDialog::OnOK(); + //m_House=TranslateHouse(m_House); +} diff --git a/MissionEditor/NewMapSpDlg.h b/MissionEditor/NewMapSpDlg.h new file mode 100644 index 0000000..90c4206 --- /dev/null +++ b/MissionEditor/NewMapSpDlg.h @@ -0,0 +1,70 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_NEWMAPSPDLG_H__F7D62445_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_) +#define AFX_NEWMAPSPDLG_H__F7D62445_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// NewMapSpDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapSpDlg + +class CNewMapSpDlg : public CDialog +{ +// Konstruktion +public: + CNewMapSpDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CNewMapSpDlg) + enum { IDD = IDD_NEWMAPSPOPTIONS }; + BOOL m_AutoProd; + int m_House; + BOOL m_PrepareHouses; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CNewMapSpDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CNewMapSpDlg) + afx_msg void OnPreparehouses(); + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_NEWMAPSPDLG_H__F7D62445_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ diff --git a/MissionEditor/NewMapTypeDlg.cpp b/MissionEditor/NewMapTypeDlg.cpp new file mode 100644 index 0000000..5e27156 --- /dev/null +++ b/MissionEditor/NewMapTypeDlg.cpp @@ -0,0 +1,73 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// NewMapTypeDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "NewMapTypeDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapTypeDlg + + +CNewMapTypeDlg::CNewMapTypeDlg(CWnd* pParent /*=NULL*/) + : CDialog(CNewMapTypeDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CNewMapTypeDlg) + m_Singleplayer = -1; + //}}AFX_DATA_INIT +} + + +void CNewMapTypeDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CNewMapTypeDlg) + DDX_Radio(pDX, IDC_SINGLE, m_Singleplayer); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CNewMapTypeDlg, CDialog) + //{{AFX_MSG_MAP(CNewMapTypeDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CNewMapTypeDlg + +BOOL CNewMapTypeDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_Singleplayer=1; + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} diff --git a/MissionEditor/NewMapTypeDlg.h b/MissionEditor/NewMapTypeDlg.h new file mode 100644 index 0000000..7467169 --- /dev/null +++ b/MissionEditor/NewMapTypeDlg.h @@ -0,0 +1,66 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_NEWMAPTYPEDLG_H__F7D62441_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_) +#define AFX_NEWMAPTYPEDLG_H__F7D62441_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// NewMapTypeDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewMapTypeDlg + +class CNewMapTypeDlg : public CDialog +{ +// Konstruktion +public: + CNewMapTypeDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CNewMapTypeDlg) + enum { IDD = IDD_NEWMAPTYPE }; + int m_Singleplayer; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CNewMapTypeDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CNewMapTypeDlg) + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_NEWMAPTYPEDLG_H__F7D62441_C6DF_11D4_9C87_E63AC3E34349__INCLUDED_ diff --git a/MissionEditor/NewRA2HouseDlg.cpp b/MissionEditor/NewRA2HouseDlg.cpp new file mode 100644 index 0000000..394e60a --- /dev/null +++ b/MissionEditor/NewRA2HouseDlg.cpp @@ -0,0 +1,83 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// NewRA2HouseDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "NewRA2HouseDlg.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewRA2HouseDlg + + +CNewRA2HouseDlg::CNewRA2HouseDlg(CWnd* pParent /*=NULL*/) + : CDialog(CNewRA2HouseDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CNewRA2HouseDlg) + m_Country = _T(""); + //}}AFX_DATA_INIT +} + + +void CNewRA2HouseDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CNewRA2HouseDlg) + DDX_CBString(pDX, IDC_COUNTRY, m_Country); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CNewRA2HouseDlg, CDialog) + //{{AFX_MSG_MAP(CNewRA2HouseDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CNewRA2HouseDlg + +#include "functions.h" + +BOOL CNewRA2HouseDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CComboBox* country=(CComboBox*)GetDlgItem(IDC_COUNTRY); + + int i; + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + country->AddString(TranslateHouse(*rules.sections[HOUSES].GetValue(i), TRUE)); + } + + country->SetCurSel(0); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} diff --git a/MissionEditor/NewRA2HouseDlg.h b/MissionEditor/NewRA2HouseDlg.h new file mode 100644 index 0000000..0673a1b --- /dev/null +++ b/MissionEditor/NewRA2HouseDlg.h @@ -0,0 +1,66 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_NEWRA2HOUSEDLG_H__142D23E1_ADDC_11D4_9C87_A435A7B6044F__INCLUDED_) +#define AFX_NEWRA2HOUSEDLG_H__142D23E1_ADDC_11D4_9C87_A435A7B6044F__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// NewRA2HouseDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CNewRA2HouseDlg + +class CNewRA2HouseDlg : public CDialog +{ +// Konstruktion +public: + CNewRA2HouseDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CNewRA2HouseDlg) + enum { IDD = IDD_NEWRA2HOUSE }; + CString m_Country; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CNewRA2HouseDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CNewRA2HouseDlg) + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_NEWRA2HOUSEDLG_H__142D23E1_ADDC_11D4_9C87_A435A7B6044F__INCLUDED_ diff --git a/MissionEditor/OpenMapDialog.cpp b/MissionEditor/OpenMapDialog.cpp new file mode 100644 index 0000000..83787ba --- /dev/null +++ b/MissionEditor/OpenMapDialog.cpp @@ -0,0 +1,51 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// OpenMapDialog.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "TiberianSun Mission Editor.h" +#include "OpenMapDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// COpenMapDialog + +IMPLEMENT_DYNAMIC(COpenMapDialog, CFileDialog) + +COpenMapDialog::COpenMapDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName, + DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) : + CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd) +{ +} + + +BEGIN_MESSAGE_MAP(COpenMapDialog, CFileDialog) + //{{AFX_MSG_MAP(COpenMapDialog) + // HINWEIS - Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros ein und entfernt diese. + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + diff --git a/MissionEditor/OpenMapDialog.h b/MissionEditor/OpenMapDialog.h new file mode 100644 index 0000000..1ad98aa --- /dev/null +++ b/MissionEditor/OpenMapDialog.h @@ -0,0 +1,55 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_OPENMAPDIALOG_H__914D68A0_ACAF_11D3_B63B_F360681B1940__INCLUDED_) +#define AFX_OPENMAPDIALOG_H__914D68A0_ACAF_11D3_B63B_F360681B1940__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// OpenMapDialog.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld COpenMapDialog + +class COpenMapDialog : public CFileDialog +{ + DECLARE_DYNAMIC(COpenMapDialog) + +public: + COpenMapDialog(BOOL bOpenFileDialog, // TRUE fĂ¼r FileOpen, FALSE fĂ¼r FileSaveAs + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + LPCTSTR lpszFilter = NULL, + CWnd* pParentWnd = NULL); + +protected: + //{{AFX_MSG(COpenMapDialog) + // HINWEIS - Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein und entfernt diese. + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_OPENMAPDIALOG_H__914D68A0_ACAF_11D3_B63B_F360681B1940__INCLUDED_ diff --git a/MissionEditor/ProgressDlg.cpp b/MissionEditor/ProgressDlg.cpp new file mode 100644 index 0000000..0b83171 --- /dev/null +++ b/MissionEditor/ProgressDlg.cpp @@ -0,0 +1,111 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// ProgressDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "ProgressDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CProgressDlg + + +CProgressDlg::CProgressDlg(CString lpDescription, CWnd* pParent /*=NULL*/) + : CDialog(CProgressDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CProgressDlg) + m_Label = lpDescription; + m_ProgLabel = _T(""); + //}}AFX_DATA_INIT + + m_bCancel=FALSE; + + Create(CProgressDlg::IDD, pParent); +} + + +void CProgressDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CProgressDlg) + DDX_Control(pDX, IDC_PROGRESS, m_Progress); + DDX_Text(pDX, IDC_LABEL, m_Label); + DDX_Text(pDX, IDC_PROGLABEL, m_ProgLabel); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CProgressDlg, CDialog) + //{{AFX_MSG_MAP(CProgressDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CProgressDlg + +void CProgressDlg::SetRange(int min, int max) +{ + m_Progress.SetRange32(min, max); +} + +void CProgressDlg::SetPosition(int nPos) +{ + m_Progress.SetPos(nPos); + m_Progress.UpdateWindow(); + m_ProgLabel="Progress: "; + + + + float p=m_Progress.GetPos(); + int min,max; + m_Progress.GetRange(min,max); + + if(max-min==0) return; + + float f=p/((float)(max-min)); + char c[50]; + itoa(f*100, c, 10); + m_ProgLabel+=c; + m_ProgLabel+=" %"; + + UpdateData(FALSE); +} + +void CProgressDlg::PostNcDestroy() +{ + delete this; + + //CDialog::PostNcDestroy(); +} + +void CProgressDlg::OnCancel() +{ + m_bCancel=TRUE; + + CDialog::OnCancel(); +} diff --git a/MissionEditor/ProgressDlg.h b/MissionEditor/ProgressDlg.h new file mode 100644 index 0000000..1456db5 --- /dev/null +++ b/MissionEditor/ProgressDlg.h @@ -0,0 +1,72 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_PROGRESSDLG_H__6FA29A01_EA1F_11D4_9C88_F09F67B34649__INCLUDED_) +#define AFX_PROGRESSDLG_H__6FA29A01_EA1F_11D4_9C88_F09F67B34649__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ProgressDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CProgressDlg + +class CProgressDlg : public CDialog +{ +// Konstruktion +public: + BOOL m_bCancel; + void SetPosition(int nPos); + void SetRange(int min, int max); + CProgressDlg(CString lpDescription, CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CProgressDlg) + enum { IDD = IDD_PROGRESS }; + CProgressCtrl m_Progress; + CString m_Label; + CString m_ProgLabel; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CProgressDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CProgressDlg) + virtual void OnCancel(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_PROGRESSDLG_H__6FA29A01_EA1F_11D4_9C88_F09F67B34649__INCLUDED_ diff --git a/MissionEditor/PropertySheets/Common.props b/MissionEditor/PropertySheets/Common.props new file mode 100644 index 0000000..cc6956b --- /dev/null +++ b/MissionEditor/PropertySheets/Common.props @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets" /> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <IntDir>$(SolutionDir)\build\intermediate\$(Configuration)-$(Platform)\$(ProjectName)\</IntDir> + <DisableFastUpToDateCheck>True</DisableFastUpToDateCheck> + </PropertyGroup> + <PropertyGroup> + <XccDir>$(MSBuildThisFileDirectory)..\..\3rdParty\xcc</XccDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <SuppressStartupBanner>true</SuppressStartupBanner> + <PreprocessorDefinitions>WIN32;_WINDOWS;SCRIPT_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile> + <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)\..\..\MissionEditorPackLib</AdditionalIncludeDirectories> + <LanguageStandard>stdcpp20</LanguageStandard> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <SuppressStartupBanner>true</SuppressStartupBanner> + <MkTypLibCompatible>true</MkTypLibCompatible> + <TargetEnvironment>Win32</TargetEnvironment> + </Midl> + <ResourceCompile> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <SuppressStartupBanner>true</SuppressStartupBanner> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(XccVcpkgDir)\lib</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + <StackReserveSize>11194304</StackReserveSize> + <StackCommitSize>11194304</StackCommitSize> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalManifestDependencies>"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'";%(AdditionalManifestDependencies)</AdditionalManifestDependencies> + </Link> + <Manifest> + <EnableDpiAwareness>false</EnableDpiAwareness> + <AdditionalManifestFiles>$(MSBuildThisFileDirectory)force_utf8.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + </ItemDefinitionGroup> +</Project> \ No newline at end of file diff --git a/MissionEditor/PropertySheets/Debug.props b/MissionEditor/PropertySheets/Debug.props new file mode 100644 index 0000000..fac5737 --- /dev/null +++ b/MissionEditor/PropertySheets/Debug.props @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets"> + <Import Project="$(MSBuildThisFileDirectory)/Common.props" /> + </ImportGroup> + <PropertyGroup> + <XccVcpkgDirTriplet>$(XccDir)\vcpkg_installed\x86-windows\x86-windows</XccVcpkgDirTriplet> + <XccVcpkgDir>$(XccVcpkgDirTriplet)\debug</XccVcpkgDir> + </PropertyGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup> + <ClCompile> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <InlineFunctionExpansion>Default</InlineFunctionExpansion> + <Optimization>Disabled</Optimization> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + </ClCompile> + <Midl> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>ddraw.lib;dxguid.lib;winmm.lib;gdiplus.lib;lzo2.lib;bz2d.lib;zlibd.lib;%(AdditionalDependencies)</AdditionalDependencies> + <IgnoreSpecificDefaultLibraries>libcmt.lib</IgnoreSpecificDefaultLibraries> + </Link> + </ItemDefinitionGroup> + <ItemGroup /> +</Project> \ No newline at end of file diff --git a/MissionEditor/PropertySheets/Distribution.props b/MissionEditor/PropertySheets/Distribution.props new file mode 100644 index 0000000..65a9f22 --- /dev/null +++ b/MissionEditor/PropertySheets/Distribution.props @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets" /> + <PropertyGroup Label="UserMacros"> + </PropertyGroup> + <PropertyGroup> + <DistributionFolder>$(MSBuildThisFileDirectory)\..\..\dist\$(DistributionName)</DistributionFolder> + <OutDir>$(DistributionFolder)\</OutDir> + </PropertyGroup> + <ItemGroup> + <!--<XccVcpkgLic Include="$(XccVcpkgDirTriplet)\share\boost-config\copyright"><Dest>boost\license.txt</Dest></XccVcpkgLic>--> + <XccVcpkgLic Include="$(XccVcpkgDirTriplet)\share\*\copyright"> + <Dest>%(RecursiveDir)\COPYING</Dest> + </XccVcpkgLic> + <XccVcpkgBin Include="$(XccVcpkgDir)\bin\bz2*.dll" /> + <XccVcpkgBin Include="$(XccVcpkgDir)\bin\lzo2.dll" /> + <XccVcpkgBin Include="$(XccVcpkgDir)\bin\zlib*1.dll" /> + <InstallData Include="$(MSBuildThisFileDirectory)\..\data\shared\**\*" /> + <InstallData Include="$(MSBuildThisFileDirectory)\..\..\LICENSE.md" /> + <LicDir Include="$(XccDir)\COPYING" DestDir="xcc" /> + </ItemGroup> + <Target Name="CopyLicenseFiles" AfterTargets="Build" BeforeTargets="BuildAndZipDistribution"> + <Copy SourceFiles="@(XccVcpkgLic)" DestinationFiles="$(OutDir)\3rdParty\licenses\%(Dest)" /> + </Target> + <Target Name="CopyLicenseFilesToDir" AfterTargets="Build" BeforeTargets="BuildAndZipDistribution"> + <Copy SourceFiles="@(XccVcpkgLicDir)" DestinationFolder="$(OutDir)\3rdParty\licenses\%(DestDir)" /> + <Copy SourceFiles="@(LicDir)" DestinationFolder="$(OutDir)\3rdParty\licenses\%(DestDir)" /> + </Target> + <Target Name="CopyDllFiles" AfterTargets="Build" BeforeTargets="BuildAndZipDistribution"> + <Copy SourceFiles="@(XccVcpkgBin)" DestinationFolder="$(OutDir)" /> + </Target> + <Target Name="CopyDataFiles" AfterTargets="Build" BeforeTargets="BuildAndZipDistribution"> + <Copy SourceFiles="@(InstallData)" DestinationFolder="$(OutDir)\%(RecursiveDir)" /> + </Target> + <Target Name="CleanDistribution" BeforeTargets="Clean"> + <RemoveDir Directories="$(DistributionFolder)" /> + </Target> + <Target Name="BuildAndZipDistribution" AfterTargets="Build" Condition="'$(DistributeMissionEditor)'=='true'"> + <ZipDirectory + Overwrite="True" + SourceDirectory="$(DistributionFolder)" + DestinationFile="$(DistributionFolder)\..\$(DistributionName).zip" /> + </Target> +</Project> diff --git a/MissionEditor/PropertySheets/FinalAlert2.props b/MissionEditor/PropertySheets/FinalAlert2.props new file mode 100644 index 0000000..5ea42f5 --- /dev/null +++ b/MissionEditor/PropertySheets/FinalAlert2.props @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets" /> + <ItemGroup> + <InstallData Include="$(MSBuildThisFileDirectory)\..\data\FinalAlert2\**\*" /> + </ItemGroup> + <PropertyGroup> + <DistributionName>FinalAlert2</DistributionName> + </PropertyGroup> +</Project> \ No newline at end of file diff --git a/MissionEditor/PropertySheets/FinalAlert2YR.props b/MissionEditor/PropertySheets/FinalAlert2YR.props new file mode 100644 index 0000000..33d68f2 --- /dev/null +++ b/MissionEditor/PropertySheets/FinalAlert2YR.props @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets" /> + <ItemGroup> + <InstallData Include="$(MSBuildThisFileDirectory)\..\data\FinalAlert2\**\*" /> + </ItemGroup> + <PropertyGroup> + <DistributionName>FinalAlert2YR</DistributionName> + </PropertyGroup> +</Project> \ No newline at end of file diff --git a/MissionEditor/PropertySheets/FinalSun.props b/MissionEditor/PropertySheets/FinalSun.props new file mode 100644 index 0000000..69068da --- /dev/null +++ b/MissionEditor/PropertySheets/FinalSun.props @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets" /> + <ItemGroup> + <InstallData Include="$(MSBuildThisFileDirectory)\..\data\FinalSun\**\*" /> + </ItemGroup> + <PropertyGroup> + <DistributionName>FinalSun</DistributionName> + </PropertyGroup> +</Project> \ No newline at end of file diff --git a/MissionEditor/PropertySheets/Release.props b/MissionEditor/PropertySheets/Release.props new file mode 100644 index 0000000..0e155dc --- /dev/null +++ b/MissionEditor/PropertySheets/Release.props @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets"> + <Import Project="$(MSBuildThisFileDirectory)/Common.props" /> + </ImportGroup> + <PropertyGroup> + <XccVcpkgDirTriplet>$(XccDir)\vcpkg_installed\x86-windows\x86-windows</XccVcpkgDirTriplet> + <XccVcpkgDir>$(XccVcpkgDirTriplet)</XccVcpkgDir> + </PropertyGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup> + <ClCompile> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> + <StringPooling>true</StringPooling> + <Optimization>MaxSpeed</Optimization> + <SuppressStartupBanner>true</SuppressStartupBanner> + <PreprocessorDefinitions>NDEBUG;_AFXDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;_AFXDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>ddraw.lib;dxguid.lib;winmm.lib;gdiplus.lib;lzo2.lib;bz2.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies> + <IgnoreSpecificDefaultLibraries>libcmt.lib; libcmtd.lib; msvcrtd.lib</IgnoreSpecificDefaultLibraries> + </Link> + </ItemDefinitionGroup> + <ItemGroup /> +</Project> \ No newline at end of file diff --git a/MissionEditor/PropertySheets/Tests.props b/MissionEditor/PropertySheets/Tests.props new file mode 100644 index 0000000..a96b067 --- /dev/null +++ b/MissionEditor/PropertySheets/Tests.props @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets" /> + <PropertyGroup> + <IS_UNITTEST>True</IS_UNITTEST> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <PreprocessorDefinitions>TESTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EntryPointSymbol>mainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> +</Project> \ No newline at end of file diff --git a/MissionEditor/PropertySheets/force_utf8.manifest b/MissionEditor/PropertySheets/force_utf8.manifest new file mode 100644 index 0000000..ceeb4d0 --- /dev/null +++ b/MissionEditor/PropertySheets/force_utf8.manifest @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asm3="urn:schemas-microsoft-com:asm.v3" xmlns:ws="http://schemas.microsoft.com/SMI/2019/WindowsSettings"> + <asm3:application> + <asm3:windowsSettings> + <ws:activeCodePage>UTF-8</ws:activeCodePage> + </asm3:windowsSettings> + </asm3:application> +</assembly> diff --git a/MissionEditor/RTPDlg.cpp b/MissionEditor/RTPDlg.cpp new file mode 100644 index 0000000..84dbf0b --- /dev/null +++ b/MissionEditor/RTPDlg.cpp @@ -0,0 +1,314 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// RTPDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "RTPDlg.h" +#include "variables.h" +#include "functions.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CRTPDlg + + +CRTPDlg::CRTPDlg(CWnd* pParent /*=NULL*/) + : CDialog(CRTPDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CRTPDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + + +void CRTPDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CRTPDlg) + DDX_Control(pDX, IDC_PREVIEW, m_Preview); + DDX_Control(pDX, IDC_USED, m_Used); + DDX_Control(pDX, IDC_AVAIL, m_Available); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CRTPDlg, CDialog) + //{{AFX_MSG_MAP(CRTPDlg) + ON_BN_CLICKED(IDC_ADD, OnAdd) + ON_BN_CLICKED(IDC_REMOVE, OnRemove) + ON_LBN_SELCHANGE(IDC_AVAIL, OnSelchangeAvail) + ON_LBN_DBLCLK(IDC_AVAIL, OnDblclkAvail) + ON_LBN_SELCHANGE(IDC_USED, OnSelchangeUsed) + ON_LBN_DBLCLK(IDC_USED, OnDblclkUsed) + ON_WM_PAINT() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CRTPDlg + +BOOL CRTPDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + int i; + for(i=0;i<rules.sections["TerrainTypes"].values.size();i++) + { + CString unitname=*rules.sections["TerrainTypes"].GetValue(i); + CString addedString=unitname; + + if(g_data.sections["IgnoreRA2"].FindValue(unitname)>=0) continue; + + addedString=TranslateStringACP(addedString); + + + if(unitname.Find("TREE")>=0) + { + + + if(unitname.GetLength()>0 && unitname!="VEINTREE") // out with it :-) + { + int TreeMin=atoi(g_data.sections[Map->GetTheater()+"Limits"].values["TreeMin"]); + int TreeMax=atoi(g_data.sections[Map->GetTheater()+"Limits"].values["TreeMax"]); + + CString id=unitname; + id.Delete(0, 4); + int n=atoi(id); + + + if(n<TreeMin || n>TreeMax) continue; + + m_Available.AddString(unitname); + } + } + } + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CRTPDlg::OnAdd() +{ + int sel=m_Available.GetCurSel(); + if(sel<0) return; + + CString currentname; + m_Available.GetText(sel, currentname); + + m_Available.DeleteString(sel); + m_Used.AddString(currentname); +} + +void CRTPDlg::OnRemove() +{ + int sel=m_Used.GetCurSel(); + if(sel<0) return; + + CString currentname; + m_Used.GetText(sel, currentname); + + m_Used.DeleteString(sel); + m_Available.AddString(currentname); +} + +void CRTPDlg::OnOK() +{ + if(m_Used.GetCount()<=0) + { + //AfxMessageBox("Please select at least one tree","Error", MB_OK); + return; + } + + rndterrainsrc.clear(); + + int i; + for(i=0;i<m_Used.GetCount();i++) + { + CString str; + m_Used.GetText(i, str); + rndterrainsrc.push_back(str); + } + + CDialog::OnOK(); +} + +void CRTPDlg::OnSelchangeAvail() +{ + int sel=m_Available.GetCurSel(); + + if(sel<0) + { + m_LastSelected=""; + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + return; + } + + CString s; + m_Available.GetText(sel, s); + m_LastSelected=s; + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + +} + +void CRTPDlg::OnDblclkAvail() +{ + int sel=m_Available.GetCurSel(); + if(sel<0) return; + + CString currentname; + m_Available.GetText(sel, currentname); + + m_Available.DeleteString(sel); + m_Used.AddString(currentname); +} + +void CRTPDlg::OnSelchangeUsed() +{ + int sel=m_Used.GetCurSel(); + + if(sel<0) + { + m_LastSelected=""; + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + return; + } + + CString s; + m_Used.GetText(sel, s); + m_LastSelected=s; + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + +} + +void CRTPDlg::OnDblclkUsed() +{ + int sel=m_Used.GetCurSel(); + if(sel<0) return; + + CString currentname; + m_Used.GetText(sel, currentname); + + m_Used.DeleteString(sel); + m_Available.AddString(currentname); +} + +void CRTPDlg::OnPaint() +{ + + if(m_LastSelected=="") return; + + CPaintDC dc(this); // device context for painting + + int id=Map->GetUnitTypeID(m_LastSelected); + + PICDATA* p=&treeinfo[id].pic; //ovrlpics[m_currentOverlay][i]; + + + if(p->pic==NULL) + { + CString type; + type=m_LastSelected; + + if(missingimages.find(type)==missingimages.end()) + { + theApp.m_loading->LoadUnitGraphic(type); + Map->UpdateTreeInfo(type); + p=&treeinfo[id].pic; + } + if(p->pic==NULL) + { + missingimages[type]=TRUE; + } + } + + int curwidth=p->wMaxWidth; + int curheight=p->wMaxHeight; + + BITMAPINFO biinfo; + memset(&biinfo, 0, sizeof(BITMAPINFO)); + biinfo.bmiHeader.biBitCount=24; + biinfo.bmiHeader.biWidth=curwidth; + biinfo.bmiHeader.biHeight=curheight; + biinfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + biinfo.bmiHeader.biClrUsed=0; + biinfo.bmiHeader.biPlanes=1; + biinfo.bmiHeader.biCompression=BI_RGB; + biinfo.bmiHeader.biClrImportant=0; + + + int pitch=curwidth*3; + if(pitch==0) return; + + if(pitch%sizeof(DWORD)) + { + pitch+=sizeof(DWORD)-(curwidth*3)%sizeof(DWORD); + } + + BYTE* colors=new(BYTE[pitch*curheight]); + memset(colors, 255, pitch*(curheight)); + + RGBTRIPLE* pal=palIso; +#ifdef NOSURFACES + if(p->pal==iPalTheater) pal=palTheater; + if(p->pal==iPalUnit) pal=palUnit; +#endif + + int k,l; + for(k=0;k<curheight;k++) + { + for(l=0;l<curwidth;l++) + { + if(((BYTE*)p->pic)[l+k*curwidth]) + { + memcpy(&colors[l*3+(curheight-k-1)*pitch], &pal[((BYTE*)p->pic)[l+k*curwidth]], 3); + } + } + } + + RECT pr; + m_Preview.GetWindowRect(&pr); + this->ScreenToClient(&pr); + + pr.top += 15; + pr.bottom -= 5; + pr.left += 5; + pr.right -= 5; + + CBrush f; + f.Attach(GetStockObject(WHITE_BRUSH)); + dc.FillRect(&pr,&f); + f.Detach(); + + auto clientDC = m_Preview.GetWindowDC(); + StretchDIBits(clientDC->GetSafeHdc(), 20, 30,curwidth, curheight, + 0, 0, curwidth, curheight, colors, &biinfo, DIB_RGB_COLORS, SRCCOPY); + + delete[] colors; + + // Kein Aufruf von CDialog::OnPaint() fĂ¼r Zeichnungsnachrichten +} diff --git a/MissionEditor/RTPDlg.h b/MissionEditor/RTPDlg.h new file mode 100644 index 0000000..18a6a6c --- /dev/null +++ b/MissionEditor/RTPDlg.h @@ -0,0 +1,77 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_RTPDLG_H__8E65AA00_2C54_11D5_89B2_444553540000__INCLUDED_) +#define AFX_RTPDLG_H__8E65AA00_2C54_11D5_89B2_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// RTPDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CRTPDlg + +class CRTPDlg : public CDialog +{ +// Konstruktion +public: + CRTPDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CRTPDlg) + enum { IDD = IDD_TERRAINPLACING }; + CButton m_Preview; + CListBox m_Used; + CListBox m_Available; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CRTPDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + CString m_LastSelected; + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CRTPDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnAdd(); + afx_msg void OnRemove(); + virtual void OnOK(); + afx_msg void OnSelchangeAvail(); + afx_msg void OnDblclkAvail(); + afx_msg void OnSelchangeUsed(); + afx_msg void OnDblclkUsed(); + afx_msg void OnPaint(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_RTPDLG_H__8E65AA00_2C54_11D5_89B2_444553540000__INCLUDED_ diff --git a/MissionEditor/RightFrame.cpp b/MissionEditor/RightFrame.cpp new file mode 100644 index 0000000..2f3e14c --- /dev/null +++ b/MissionEditor/RightFrame.cpp @@ -0,0 +1,123 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// RightFrame.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "RightFrame.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CRightFrame + +IMPLEMENT_DYNCREATE(CRightFrame, CFrameWnd) + +CRightFrame::CRightFrame() +{ +} + +CRightFrame::~CRightFrame() +{ +} + + +BEGIN_MESSAGE_MAP(CRightFrame, CFrameWnd) + //{{AFX_MSG_MAP(CRightFrame) + ON_WM_SIZE() + ON_WM_CHAR() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CRightFrame + +BOOL CRightFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) +{ + + SIZE z; + z.cx=200; + z.cy=700; + //if(z.cy<100) z.cy=100; + + CRect r; + r.right=200; + r.bottom=200; + + + if(!m_Splitter.CreateStatic(this,2,1)) return FALSE; + + + if(!m_Splitter.CreateView(0,0, + RUNTIME_CLASS(CIsoView), + z, + pContext)) return FALSE; + + z.cy=100; + + if(!m_Splitter.CreateView(1,0, + RUNTIME_CLASS(CTileSetBrowserFrame), + z, + pContext)) return FALSE; + + GetClientRect(&r); + + m_Splitter.SetRowInfo(0, GetSystemMetrics(SM_CYFULLSCREEN)/2, 20); + m_Splitter.SetRowInfo(1, GetSystemMetrics(SM_CYFULLSCREEN)/2, 10); + + //SetWindowLong(m_Splitter->m_hWnd, GWL_STYLE, m_rightFrame->GetStyle() ! WS_THICKFRAME); + + OutputDebugString("CRightFrame::OnCreateClient(): windows created\n"); + + return CFrameWnd::OnCreateClient(lpcs, pContext); +} + +BOOL CRightFrame::PreCreateWindow(CREATESTRUCT& cs) +{ + // cs.style=WS_OVERLAPPED && WS_CAPTION && WS_SYSMENU && WS_MINIMIZEBOX && WS_MAXIMIZEBOX; + + return CFrameWnd::PreCreateWindow(cs); +} + +void CRightFrame::OnSize(UINT nType, int cx, int cy) +{ + CFrameWnd::OnSize(nType, cx, cy); + + +} + +void CRightFrame::RecalcLayout(BOOL bNotify) +{ + // TODO: Speziellen Code hier einfĂ¼gen und/oder Basisklasse aufrufen + + CFrameWnd::RecalcLayout(bNotify); +} + +void CRightFrame::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + + CFrameWnd::OnChar(nChar, nRepCnt, nFlags); +} diff --git a/MissionEditor/RightFrame.h b/MissionEditor/RightFrame.h new file mode 100644 index 0000000..76e1a0b --- /dev/null +++ b/MissionEditor/RightFrame.h @@ -0,0 +1,73 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_RIGHTFRAME_H__22553762_8405_11D4_9C87_EE62BC46B24A__INCLUDED_) +#define AFX_RIGHTFRAME_H__22553762_8405_11D4_9C87_EE62BC46B24A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// RightFrame.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Rahmen CRightFrame + +class CRightFrame : public CFrameWnd +{ + DECLARE_DYNCREATE(CRightFrame) +protected: + CRightFrame(); // Dynamische Erstellung verwendet geschĂ¼tzten Konstruktor + +// Attribute +public: + +// Operationen +public: + CSplitterWnd m_Splitter; + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CRightFrame) + public: + virtual void RecalcLayout(BOOL bNotify = TRUE); + protected: + virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext); + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + //}}AFX_VIRTUAL + +// Implementierung +protected: + virtual ~CRightFrame(); + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CRightFrame) + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_RIGHTFRAME_H__22553762_8405_11D4_9C87_EE62BC46B24A__INCLUDED_ diff --git a/MissionEditor/SaveMapOptionsDlg.cpp b/MissionEditor/SaveMapOptionsDlg.cpp new file mode 100644 index 0000000..c420601 --- /dev/null +++ b/MissionEditor/SaveMapOptionsDlg.cpp @@ -0,0 +1,122 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// SaveMapOptionsDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "SaveMapOptionsDlg.h" +#include "variables.h" +#include "inifile.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CSaveMapOptionsDlg + + +CSaveMapOptionsDlg::CSaveMapOptionsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSaveMapOptionsDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSaveMapOptionsDlg) + m_Compress = 1; + m_PreviewMode = 0; + m_MapName = _T(""); + m_AirWar = FALSE; + m_Cooperative = FALSE; + m_Duel = FALSE; + m_Meatgrind = FALSE; + m_Megawealth = FALSE; + m_Navalwar = FALSE; + m_Nukewar = FALSE; + m_Standard = FALSE; + m_TeamGame = FALSE; + //}}AFX_DATA_INIT + + CIniFile& ini=Map->GetIniFile(); + if(!Map->IsMultiplayer()) + m_PreviewMode=1; + + m_MapName=ini.sections["Basic"].values["Name"]; +} + + +void CSaveMapOptionsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSaveMapOptionsDlg) + DDX_Radio(pDX, IDC_COMPRESS, m_Compress); + DDX_Radio(pDX, IDC_PREVIEWMODE, m_PreviewMode); + DDX_Text(pDX, IDC_MAPNAME, m_MapName); + #ifdef RA2_MODE + DDX_Check(pDX, IDC_AIRWAR, m_AirWar); + DDX_Check(pDX, IDC_COOPERATIVE, m_Cooperative); + DDX_Check(pDX, IDC_DUEL, m_Duel); + DDX_Check(pDX, IDC_MEATGRIND, m_Meatgrind); + DDX_Check(pDX, IDC_MEGAWEALTH, m_Megawealth); + DDX_Check(pDX, IDC_NAVALWAR, m_Navalwar); + DDX_Check(pDX, IDC_NUKEWAR, m_Nukewar); + DDX_Check(pDX, IDC_STANDARD, m_Standard); + DDX_Check(pDX, IDC_TEAMGAME, m_TeamGame); + #endif + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSaveMapOptionsDlg, CDialog) + //{{AFX_MSG_MAP(CSaveMapOptionsDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CSaveMapOptionsDlg + +BOOL CSaveMapOptionsDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CIniFile& ini=Map->GetIniFile(); + if(!Map->IsMultiplayer()) + { + GetDlgItem(IDC_PREVIEWMODE)->EnableWindow(FALSE); + GetDlgItem(IDC_NOPREVIEW)->EnableWindow(FALSE); + GetDlgItem(IDC_EXISTINGPREVIEW)->EnableWindow(FALSE); + +#ifndef TS_MODE + GetDlgItem(IDC_AIRWAR)->EnableWindow(FALSE); + GetDlgItem(IDC_COOPERATIVE)->EnableWindow(FALSE); + GetDlgItem(IDC_DUEL)->EnableWindow(FALSE); + GetDlgItem(IDC_MEATGRIND)->EnableWindow(FALSE); + GetDlgItem(IDC_MEGAWEALTH)->EnableWindow(FALSE); + GetDlgItem(IDC_NAVALWAR)->EnableWindow(FALSE); + GetDlgItem(IDC_NUKEWAR)->EnableWindow(FALSE); + GetDlgItem(IDC_STANDARD)->EnableWindow(FALSE); + GetDlgItem(IDC_TEAMGAME)->EnableWindow(FALSE); +#endif + } + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} diff --git a/MissionEditor/SaveMapOptionsDlg.h b/MissionEditor/SaveMapOptionsDlg.h new file mode 100644 index 0000000..a90f1d6 --- /dev/null +++ b/MissionEditor/SaveMapOptionsDlg.h @@ -0,0 +1,77 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_SAVEMAPOPTIONSDLG_H__DD7874E1_CED2_11D4_9C87_444553540000__INCLUDED_) +#define AFX_SAVEMAPOPTIONSDLG_H__DD7874E1_CED2_11D4_9C87_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SaveMapOptionsDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CSaveMapOptionsDlg + +class CSaveMapOptionsDlg : public CDialog +{ +// Konstruktion +public: + CSaveMapOptionsDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CSaveMapOptionsDlg) + enum { IDD = IDD_SAVEOPTIONS }; + int m_Compress; + int m_PreviewMode; + CString m_MapName; + BOOL m_AirWar; + BOOL m_Cooperative; + BOOL m_Duel; + BOOL m_Meatgrind; + BOOL m_Megawealth; + BOOL m_Navalwar; + BOOL m_Nukewar; + BOOL m_Standard; + BOOL m_TeamGame; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CSaveMapOptionsDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CSaveMapOptionsDlg) + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_SAVEMAPOPTIONSDLG_H__DD7874E1_CED2_11D4_9C87_444553540000__INCLUDED_ diff --git a/MissionEditor/SavingDlg.cpp b/MissionEditor/SavingDlg.cpp new file mode 100644 index 0000000..2f1684f --- /dev/null +++ b/MissionEditor/SavingDlg.cpp @@ -0,0 +1,71 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// SavingDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "SavingDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CSavingDlg + + +CSavingDlg::CSavingDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSavingDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSavingDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT + + Create(CSavingDlg::IDD, pParent); +} + + +void CSavingDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSavingDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier DDX- und DDV-Aufrufe ein + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSavingDlg, CDialog) + //{{AFX_MSG_MAP(CSavingDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros fĂ¼r Nachrichten ein + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CSavingDlg + +void CSavingDlg::PostNcDestroy() +{ + + // CDialog::PostNcDestroy(); +} diff --git a/MissionEditor/SavingDlg.h b/MissionEditor/SavingDlg.h new file mode 100644 index 0000000..9820494 --- /dev/null +++ b/MissionEditor/SavingDlg.h @@ -0,0 +1,69 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_SAVINGDLG_H__9E604CC1_850C_11D4_9C87_BC8AE639B54A__INCLUDED_) +#define AFX_SAVINGDLG_H__9E604CC1_850C_11D4_9C87_BC8AE639B54A__INCLUDED_ + +#include "resource.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SavingDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CSavingDlg + +class CSavingDlg : public CDialog +{ +// Konstruktion +public: + CSavingDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CSavingDlg) + enum { IDD = IDD_SAVING }; + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Datenelemente ein + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CSavingDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CSavingDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_SAVINGDLG_H__9E604CC1_850C_11D4_9C87_BC8AE639B54A__INCLUDED_ diff --git a/MissionEditor/ScriptTypes.cpp b/MissionEditor/ScriptTypes.cpp new file mode 100644 index 0000000..a341e00 --- /dev/null +++ b/MissionEditor/ScriptTypes.cpp @@ -0,0 +1,751 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// ScriptTypes.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "ScriptTypes.h" +#include "FinalSunDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + +#define TMISSION_COUNT 59 +#define TPROPERTY_COUNT 4 +#define UNLOAD_COUNT 4 + + +// The various missions that a team can have. +enum TeamMissionType { + TMISSION_ATTACK, + TMISSION_ATT_WAYPT, + TMISSION_BERZERK, + TMISSION_MOVE, + TMISSION_MOVECELL, + TMISSION_GUARD, + TMISSION_LOOP, + TMISSION_WIN, + TMISSION_UNLOAD, + TMISSION_DEPLOY, + TMISSION_HOUND_DOG, + TMISSION_DO, + TMISSION_SET_GLOBAL, + TMISSION_IDLE_ANIM, + TMISSION_LOAD, + TMISSION_SPY, + TMISSION_PATROL, + TMISSION_SCRIPT, + TMISSION_TEAMCHANGE, + TMISSION_PANIC, + TMISSION_CHANGE_HOUSE, + TMISSION_SCATTER, + TMISSION_GOTO_SHROUD, + TMISSION_LOSE, + TMISSION_PLAY_SPEECH, + TMISSION_PLAY_SOUND, + TMISSION_PLAY_MOVIE, + TMISSION_PLAY_MUSIC, + TMISSION_REDUCE_TIBERIUM, + TMISSION_BEGIN_PRODUCTION, + TMISSION_FIRE_SALE, + TMISSION_SELF_DESTRUCT, + TMISSION_ION_STORM_START, + TMISSION_ION_STORM_END, + TMISSION_CENTER_VIEWPOINT, + TMISSION_RESHROUD, + TMISSION_REVEAL, + TMISSION_DESTROY_MEMBERS, + TMISSION_CLEAR_GLOBAL, + TMISSION_SET_LOCAL, + TMISSION_CLEAR_LOCAL, + TMISSION_UNPANIC, + TMISSION_FORCE_FACING, + TMISSION_FULLY_LOADED, + TMISSION_UNLOAD_TRUCK, + TMISSION_LOAD_TRUCK, + TMISSION_ATTACK_BUILDING_WITH_PROPERTY, + TMISSION_MOVETO_BUILDING_WITH_PROPERTY, + TMISSION_SCOUT, + TMISSION_SUCCESS, + TMISSION_FLASH, + TMISSION_PLAY_ANIM, + TMISSION_TALK_BUBBLE, + TMISSION_GATHER_FAR, + TMISSION_GATHER_NEAR, + TMISSION_ACTIVATE_CURTAIN, + TMISSION_CHRONO_ATTACK_BUILDING_WITH_PROPERTY, + TMISSION_CHRONO_ATTACK, + TMISSION_MOVETO_OWN_BUILDING_WITH_PROPERTY, +}; + +char const * TMissions[TMISSION_COUNT] = { + "Attack...", + "Attack Waypoint...", + "Go Berzerk", + "Move to waypoint...", + "Move to Cell...", + "Guard area (timer ticks)...", + "Jump to line #...", + "Player wins", + "Unload...", + "Deploy", + "Follow friendlies", + "Do this...", + "Set global...", + "Idle Anim...", + "Load onto Transport", + "Spy on bldg @ waypt...", + "Patrol to waypoint...", + "Change script...", + "Change team...", + "Panic", + "Change house...", + "Scatter", + "Goto nearby shroud", + "Player loses", + "Play speech...", + "Play sound...", + "Play movie...", + "Play music...", + "Reduce tiberium", + "Begin production", + "Fire sale", + "Self destruct", + "Ion storm start in...", + "Ion storn end", + "Center view on team (speed)...", + "Reshroud map", + "Reveal map", + "Delete team members", + "Clear global...", + "Set local...", + "Clear local...", + "Unpanic", + "Force facing...", + "Wait till fully loaded", + "Truck unload", + "Truck load", + "Attack enemy building", + "Moveto enemy building", + "Scout", + "Success", + "Flash", + "Play Anim", + "Talk Bubble", + "Gather at Enemy", + "Gather at Base", + "Iron Curtain Me", + "Chrono Prep for ABwP", + "Chrono Prep for AQ", + "Move to own building", +}; + +char const * TMissionsHelp[TMISSION_COUNT] = { + "Attack some general target", + "Attack anything nearby the specified waypoint", + "Cyborg members of the team will go berzerk.", + "Orders the team to move to a waypoint on the map", + "Orders the team to move to a specific cell on the map", + "Guard an area for a specified amount of time", + "Move to a new line number in the script. Used for loops.", + "Duh", + "Unloads all loaded units. The command parameter specifies which units should stay a part of the team, and which should be severed from the team.", + "Causes all deployable units in the team to deploy", + "Causes the team to follow the nearest friendly unit", + "Give all team members the specified mission", + "Sets a global variable", + "Causes team members to enter their idle animation", + "Causes all units to load into transports, if able", + "**OBSOLETE**", + "Move to a waypoint while scanning for enemies", + "Causes the team to start using a new script", + "Causes the team to switch team types", + "Causes all units in the team to panic", + "All units in the team switch houses", + "Tells all units to scatter", + "Causes units to flee to a shrouded cell", + "Causes the player to lose", + "Plays the specified voice file", + "Plays the specified sound file", + "Plays the specified movie file", + "Plays the specified theme", + "Reduces the amount of tiberium around team members", + "Signals the owning house to begin production", + "Causes an AI house to sell all of its buildings and do a Braveheart", + "Causes all team members to self destruct", + "Causes an ion storm to begin at the specified time", + "Causes an ion storm to end", + "Center view on team (speed)...", + "Reshrouds the map", + "Reveals the map", + "Delete all members from the team", + "Clears the specified global variable", + "Sets the specified local variable", + "Clears the specified local variable", + "Causes all team members to stop panicking", + "Forces team members to face a certain direction", + "Waits until all transports are full", + "Causes all trucks to unload their crates (ie, change imagery)", + "Causes all trucks to load crates (ie, change imagery)", + "Attack a specific type of building with the specified property", + "Move to a specific type of building with the specified property", + "The team will scout the bases of the players that have not been scouted", + "Record a team as having successfully accomplished its mission. Used for AI trigger weighting. Put this at the end of every AITrigger script.", + "Flashes a team for a period of team.", + "Plays an anim over every unit in the team.", + "Displays talk bubble over first unit in the team.", + "Uses AISafeDistance to find a spot close to enemy's base to gather close.", + "Gathers outside own base perimeter.", + "Calls (and waits if nearly ready) for House to deliver Iron Curtain to Team.", + "Teleports team to Building With Property, but needs similar attack order as next mission.", + "Teleports team to Attack Quarry, but needs similar attack order as next mission.", + "A BwP move that will only search through buildings owned by this house.", +}; + + +char const *TargetProperties[TPROPERTY_COUNT] = { + "Least Threat", + "Greatest Threat", + "Nearest", + "Farthest", +}; + +char const *UnloadTypeNames[UNLOAD_COUNT] = { + "Keep Transports, Keep Units", + "Keep Transports, Lose Units", + "Lose Transports, Keep Units", + "Lose Transports, Lose Units", +}; + + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CScriptTypes + +IMPLEMENT_DYNCREATE(CScriptTypes, CDialog) + +CScriptTypes::CScriptTypes() : CDialog(CScriptTypes::IDD) +{ + //{{AFX_DATA_INIT(CScriptTypes) + m_Name = _T(""); + //}}AFX_DATA_INIT +} + +CScriptTypes::~CScriptTypes() +{ +} + +void CScriptTypes::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CScriptTypes) + DDX_Control(pDX, IDC_DESCRIPTION, m_DescriptionEx); + DDX_Control(pDX, IDC_PDESC, m_Desc); + DDX_Control(pDX, IDC_TYPE, m_Type); + DDX_Control(pDX, IDC_SCRIPTTYPE, m_ScriptType); + DDX_Control(pDX, IDC_PARAM, m_Param); + DDX_Control(pDX, IDC_ACTION, m_Action); + DDX_Text(pDX, IDC_NAME, m_Name); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CScriptTypes, CDialog) + //{{AFX_MSG_MAP(CScriptTypes) + ON_CBN_EDITCHANGE(IDC_SCRIPTTYPE, OnEditchangeScripttype) + ON_CBN_SELCHANGE(IDC_SCRIPTTYPE, OnSelchangeScripttype) + ON_LBN_SELCHANGE(IDC_ACTION, OnSelchangeAction) + ON_EN_CHANGE(IDC_NAME, OnChangeName) + ON_CBN_EDITCHANGE(IDC_TYPE, OnEditchangeType) + ON_CBN_SELCHANGE(IDC_TYPE, OnSelchangeType) + ON_CBN_EDITCHANGE(IDC_PARAM, OnEditchangeParam) + ON_CBN_SELCHANGE(IDC_PARAM, OnSelchangeParam) + ON_BN_CLICKED(IDC_ADDACTION, OnAddaction) + ON_BN_CLICKED(IDC_DELETEACTION, OnDeleteaction) + ON_BN_CLICKED(IDC_ADD, OnAdd) + ON_BN_CLICKED(IDC_DELETE, OnDelete) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CScriptTypes + +void CScriptTypes::UpdateDialog() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_ScriptType.GetCurSel(); + + + while(m_ScriptType.DeleteString(0)!=CB_ERR); + + + // MW 07/24/01: clear dialog + m_DescriptionEx.SetWindowText(""); + m_Name=""; + m_Param.SetWindowText(""); + m_Action.SetWindowText(""); + m_Type.SetCurSel(-1); + + UpdateData(FALSE); + + + int i; + for(i=0;i<ini.sections["ScriptTypes"].values.size();i++) + { + CString type,s; + type=*ini.sections["ScriptTypes"].GetValue(i); + s=type; + s+=" ("; + s+=ini.sections[(LPCTSTR)type].values["Name"]; + s+=")"; + m_ScriptType.AddString(s); + } + + m_ScriptType.SetCurSel(0); + if(sel>=0) m_ScriptType.SetCurSel(sel); + OnSelchangeScripttype(); + + +} + +void CScriptTypes::OnEditchangeScripttype() +{ + +} + +void CScriptTypes::OnSelchangeScripttype() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Action.GetCurSel(); + while(m_Action.DeleteString(0)!=CB_ERR); + + CString Scripttype; + if(m_ScriptType.GetCurSel()<0) return; + m_ScriptType.GetLBText(m_ScriptType.GetCurSel(), Scripttype); + TruncSpace(Scripttype); + + m_Name=ini.sections[(LPCTSTR)Scripttype].values["Name"]; + + int count=ini.sections[(LPCTSTR)Scripttype].values.size()-1; + int i; + for(i=0;i<count;i++) + { + char c[50]; + itoa(i,c,10); + m_Action.AddString(c); + } + + + m_Action.SetCurSel(0); + if(sel>=0) m_Action.SetCurSel(sel); + OnSelchangeAction(); + + UpdateData(FALSE); +} + +void CScriptTypes::OnSelchangeAction() +{ + CIniFile& ini=Map->GetIniFile(); + + CString Scripttype; + char action[50]; + if(m_ScriptType.GetCurSel()<0) return; + if(m_Action.GetCurSel()<0) return; + m_ScriptType.GetLBText(m_ScriptType.GetCurSel(), Scripttype); + TruncSpace(Scripttype); + + itoa(m_Action.GetCurSel(), action, 10); + //m_Type.SetWindowText(GetParam(ini.sections[(LPCTSTR)Scripttype].values[action],0)); + m_Type.SetCurSel(atoi(GetParam(ini.sections[(LPCTSTR)Scripttype].values[action], 0))); + + OnSelchangeType(); + + m_Param.SetWindowText(GetParam(ini.sections[(LPCTSTR)Scripttype].values[action],1)); + + +} + +void CScriptTypes::OnChangeName() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + CEdit* n=(CEdit*)GetDlgItem(IDC_NAME); + + DWORD pos=n->GetSel(); + CString Scripttype; + if(m_ScriptType.GetCurSel()<0) return; + m_ScriptType.GetLBText(m_ScriptType.GetCurSel(), Scripttype); + TruncSpace(Scripttype); + + + + ini.sections[(LPCTSTR)Scripttype].values["Name"]=m_Name; + + UpdateDialog(); + n->SetSel(pos); +} + +void CScriptTypes::OnEditchangeType() +{ + CIniFile& ini=Map->GetIniFile(); + + while(m_Param.DeleteString(0)!=CB_ERR); + CString Scripttype; + char action[50]; + if(m_Action.GetCurSel()<0) return; + if(m_ScriptType.GetCurSel()<0) return; + m_ScriptType.GetLBText(m_ScriptType.GetCurSel(), Scripttype); + TruncSpace(Scripttype); + + //CString type; + //m_Type.GetWindowText(type); + //TruncSpace(type); + //MessageBox("beep"); + int type=m_Type.GetCurSel(); + + int i; + char tmp[50]; + + switch(type) + { + case 0: + ListTargets(m_Param); + m_Desc.SetWindowText("Target:"); + break; + case 39: + case 40: + ListGlobals(m_Param); + break; + + case 11: + ListBehaviours(m_Param); + break; + case 1: + case 3: + case 16: + ListWaypoints(m_Param); + m_Desc.SetWindowText("Waypoint:"); + break; + case 4: + m_Desc.SetWindowText("Cell:"); + break; + case 5: + m_Desc.SetWindowText("Time units to guard:"); + break; + case 6: + m_Desc.SetWindowText("Script action #:"); + while(m_Param.DeleteString(0)!=CB_ERR); + for(i=1;i<=ini.sections[(LPCTSTR)Scripttype].values.size()-1;i++) + m_Param.AddString(itoa(i,tmp,10)); + break; + case 8: + m_Desc.SetWindowText("Split groups:"); + while(m_Param.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<UNLOAD_COUNT;i++) + { + CString p; + char c[50]; + itoa(i,c,10); + p=c; + p+=" - "; + p+=UnloadTypeNames[i]; + + m_Param.AddString(p); + } + break; + case 9: + case 14: + case 37: + m_Desc.SetWindowText("Use 0:"); + break; + case 12: + m_Desc.SetWindowText("Global:"); + break; + case 20: + ListHouses(m_Param, TRUE); + m_Desc.SetWindowText("House:"); + break; + case 46: + case 47: + { + m_Desc.SetWindowText("Type to move/attack:"); + + for(i=0;i<rules.sections["BuildingTypes"].values.size();i++) + { + char c[50]; + itoa(i,c,10); + CString s=c; + + s+=" "; + //s+=rules.sections[*rules.sections["BuildingTypes"].GetValue(i)].values["Name"]; + s+=Map->GetUnitName(*rules.sections["BuildingTypes"].GetValue(i)); + m_Param.AddString(s); + } + + break; + } + + default: + m_Desc.SetWindowText("Parameter of action:"); + } + + itoa(m_Action.GetCurSel(), action, 10); + + char types[50]; + itoa(type, types, 10); + ini.sections[(LPCTSTR)Scripttype].values[action]=SetParam(ini.sections[(LPCTSTR)Scripttype].values[action], 0, (LPCTSTR)types); + + + +} + +void CScriptTypes::OnSelchangeType() +{ + CString str; + if(m_Type.GetCurSel()>-1) + { + //m_Type.GetLBText(m_Type.GetCurSel(), str); + //m_Type.SetWindowText(str); + + m_DescriptionEx.SetWindowText(TMissionsHelp[m_Type.GetCurSel()]); + } + + + + OnEditchangeType(); +} + +void CScriptTypes::OnEditchangeParam() +{ + CIniFile& ini=Map->GetIniFile(); + + CString Scripttype; + char action[50]; + if(m_Action.GetCurSel()<0) return; + if(m_ScriptType.GetCurSel()<0) return; + m_ScriptType.GetLBText(m_ScriptType.GetCurSel(), Scripttype); + TruncSpace(Scripttype); + + CString param; + m_Param.GetWindowText(param); + TruncSpace(param); + + param=TranslateHouse(param); + + itoa(m_Action.GetCurSel(), action, 10); + ini.sections[(LPCTSTR)Scripttype].values[action]=SetParam(ini.sections[(LPCTSTR)Scripttype].values[action], 1, (LPCTSTR)param); + + +} + +void CScriptTypes::OnSelchangeParam() +{ + m_Param.SetWindowText(GetText(&m_Param)); + OnEditchangeParam(); +} + +void CScriptTypes::OnAddaction() +{ + CIniFile& ini=Map->GetIniFile(); + + CString Scripttype; + if(m_ScriptType.GetCurSel()<0) return; + m_ScriptType.GetLBText(m_ScriptType.GetCurSel(), Scripttype); + TruncSpace(Scripttype); + + + char action[20]; + int count=ini.sections[(LPCTSTR)Scripttype].values.size()-1; + itoa(count,action,10); + ini.sections[(LPCTSTR)Scripttype].values[action]="0,0"; + + UpdateDialog(); +} + +void CScriptTypes::OnDeleteaction() +{ + CIniFile& ini=Map->GetIniFile(); + + CString Scripttype; + if(m_Action.GetCurSel()<0) return; + if(m_ScriptType.GetCurSel()<0) return; + m_ScriptType.GetLBText(m_ScriptType.GetCurSel(), Scripttype); + TruncSpace(Scripttype); + + + // okay, action is now the deleted one... + int i; + for(i=m_Action.GetCurSel(); i<m_Action.GetCount()-1;i++) + { + // okay, now move every action one number up. + char current[50]; + char next[50]; + + itoa(i, current, 10); + itoa(i+1, next, 10); + + ini.sections[(LPCTSTR)Scripttype].values[current]=ini.sections[(LPCTSTR)Scripttype].values[next]; + } + char last[50]; + itoa(m_Action.GetCount()-1, last, 10); + ini.sections[(LPCTSTR)Scripttype].values.erase(last); + + UpdateDialog(); +} + +CString GetFree(const char* section); + +void CScriptTypes::OnAdd() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ID=GetFreeID(); + + CString p=GetFree("ScriptTypes"); + ini.sections["ScriptTypes"].values[p]=ID; + ini.sections[ID].values["Name"]="New script"; + + + + int i; + for(i=0;i<m_ScriptType.GetCount();i++) + { + CString data; + m_ScriptType.GetLBText(i, data); + TruncSpace(data); + + if(data==ID) + { + m_ScriptType.SetCurSel(i); + OnSelchangeScripttype(); // MW bugfix + break; + } + } + + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); + //UpdateDialog(); +} + +void CScriptTypes::OnDelete() +{ + CIniFile& ini=Map->GetIniFile(); + + CString Scripttype; + if(m_ScriptType.GetCurSel()<0) return; + m_ScriptType.GetLBText(m_ScriptType.GetCurSel(), Scripttype); + TruncSpace(Scripttype); + + int res=MessageBox("Are you sure to delete this ScriptType? Don´t forget to delete any references to this ScriptType","Delete ScriptType", MB_YESNO | MB_ICONQUESTION); + if(res!=IDYES) return; + + ini.sections.erase((LPCTSTR)Scripttype); + ini.sections["ScriptTypes"].values.erase(*ini.sections["ScriptTypes"].GetValueName(ini.sections["ScriptTypes"].FindValue((LPCTSTR)Scripttype))); + //UpdateDialog(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); +} + + + +void CScriptTypes::ListBehaviours(CComboBox &cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + + cb.AddString("0 - Sleep"); + cb.AddString("1 - Attack nearest enemy"); + cb.AddString("2 - Move"); + cb.AddString("3 - QMove"); + cb.AddString("4 - Retreat home for R&R"); + cb.AddString("5 - Guard"); + cb.AddString("6 - Sticky (never recruit)"); + cb.AddString("7 - Enter object"); + cb.AddString("8 - Capture object"); + cb.AddString("9 - Move into & get eaten"); + cb.AddString("10 - Harvest"); + cb.AddString("11 - Area Guard"); + cb.AddString("12 - Return (to refinery)"); + cb.AddString("13 - Stop"); + cb.AddString("14 - Ambush (wait until discovered)"); + cb.AddString("15 - Hunt"); + cb.AddString("16 - Unload"); + cb.AddString("17 - Sabotage (move in & destroy)"); + cb.AddString("18 - Construction"); + cb.AddString("19 - Deconstruction"); + cb.AddString("20 - Repair"); + cb.AddString("21 - Rescue"); + cb.AddString("22 - Missile"); + cb.AddString("23 - Harmless"); + cb.AddString("24 - Open"); + cb.AddString("25 - Patrol"); + cb.AddString("26 - Paradrop approach drop zone"); + cb.AddString("27 - Paradrop overlay drop zone"); + cb.AddString("28 - Wait"); + cb.AddString("29 - Attack move"); + if(yuri_mode) + { + // cb.AddString("30 - Spyplane approach"); + // cb.AddString("31 - Spyplane retreat"); + } +} + +BOOL CScriptTypes::OnInitDialog() +{ + CDialog::OnInitDialog(); + + while(m_Type.DeleteString(0)!=CB_ERR); + + + int i; + for(i=0;i<TMISSION_COUNT;i++) + { + CString p; + char c[50]; + itoa(i,c,10); + + //p=c; + + + //p+=" - "; + p+=TMissions[i]; + + if(strlen(TMissions[i])>0) + { + m_Type.AddString(p); + } + } + + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} diff --git a/MissionEditor/ScriptTypes.h b/MissionEditor/ScriptTypes.h new file mode 100644 index 0000000..632d1e2 --- /dev/null +++ b/MissionEditor/ScriptTypes.h @@ -0,0 +1,89 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_SCRIPTTYPES_H__981EF700_951E_11D3_B63B_BCCF9C98B341__INCLUDED_) +#define AFX_SCRIPTTYPES_H__981EF700_951E_11D3_B63B_BCCF9C98B341__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ScriptTypes.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CScriptTypes + +class CScriptTypes : public CDialog +{ + DECLARE_DYNCREATE(CScriptTypes) + +// Konstruktion +public: + void UpdateDialog(); + CScriptTypes(); + ~CScriptTypes(); + +// Dialogfelddaten + //{{AFX_DATA(CScriptTypes) + enum { IDD = IDD_SCRIPTTYPES }; + CEdit m_DescriptionEx; + CStatic m_Desc; + CComboBox m_Type; + CComboBox m_ScriptType; + CComboBox m_Param; + CListBox m_Action; + CString m_Name; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CScriptTypes) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + void ListBehaviours(CComboBox& cb); + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CScriptTypes) + afx_msg void OnEditchangeScripttype(); + afx_msg void OnSelchangeScripttype(); + afx_msg void OnSelchangeAction(); + afx_msg void OnChangeName(); + afx_msg void OnEditchangeType(); + afx_msg void OnSelchangeType(); + afx_msg void OnEditchangeParam(); + afx_msg void OnSelchangeParam(); + afx_msg void OnAddaction(); + afx_msg void OnDeleteaction(); + afx_msg void OnAdd(); + afx_msg void OnDelete(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_SCRIPTTYPES_H__981EF700_951E_11D3_B63B_BCCF9C98B341__INCLUDED_ diff --git a/MissionEditor/SearchWaypointDlg.cpp b/MissionEditor/SearchWaypointDlg.cpp new file mode 100644 index 0000000..a344356 --- /dev/null +++ b/MissionEditor/SearchWaypointDlg.cpp @@ -0,0 +1,102 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// SearchWaypointDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "SearchWaypointDlg.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CSearchWaypointDlg + + +CSearchWaypointDlg::CSearchWaypointDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSearchWaypointDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSearchWaypointDlg) + m_Waypoints = _T(""); + //}}AFX_DATA_INIT +} + + +void CSearchWaypointDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSearchWaypointDlg) + DDX_LBString(pDX, IDC_WAYPOINTS, m_Waypoints); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSearchWaypointDlg, CDialog) + //{{AFX_MSG_MAP(CSearchWaypointDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CSearchWaypointDlg + +BOOL CSearchWaypointDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + CListBox& ctrl=*(CListBox*)GetDlgItem(IDC_WAYPOINTS); + + while(ctrl.DeleteString(0)!=LB_ERR); + + int i; + int count=Map->GetWaypointCount(); + + for(i=0;i<count;i++) + { + CString id; + DWORD pos; + Map->GetWaypointData(i, &id, &pos); + + ctrl.SetItemData(ctrl.InsertString(i, id), i); + } + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CSearchWaypointDlg::OnOK() +{ + CListBox& ctrl=*(CListBox*)GetDlgItem(IDC_WAYPOINTS); + + int sel=ctrl.GetCurSel(); + + if(sel<0) m_WaypointIndex=-1; + else + { + m_WaypointIndex=ctrl.GetItemData(sel); + } + + CDialog::OnOK(); +} diff --git a/MissionEditor/SearchWaypointDlg.h b/MissionEditor/SearchWaypointDlg.h new file mode 100644 index 0000000..6cb34b5 --- /dev/null +++ b/MissionEditor/SearchWaypointDlg.h @@ -0,0 +1,68 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_SEARCHWAYPOINTDLG_H__28D1CCC0_874C_11D5_89B3_00E07D97C331__INCLUDED_) +#define AFX_SEARCHWAYPOINTDLG_H__28D1CCC0_874C_11D5_89B3_00E07D97C331__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SearchWaypointDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CSearchWaypointDlg + +class CSearchWaypointDlg : public CDialog +{ +// Konstruktion +public: + int m_WaypointIndex; + CSearchWaypointDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CSearchWaypointDlg) + enum { IDD = IDD_SEARCHWAYPOINT }; + CString m_Waypoints; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CSearchWaypointDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CSearchWaypointDlg) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_SEARCHWAYPOINTDLG_H__28D1CCC0_874C_11D5_89B3_00E07D97C331__INCLUDED_ diff --git a/MissionEditor/ShutDownDlg.cpp b/MissionEditor/ShutDownDlg.cpp new file mode 100644 index 0000000..56f98d1 --- /dev/null +++ b/MissionEditor/ShutDownDlg.cpp @@ -0,0 +1,71 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// ShutDownDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "ShutDownDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CShutDownDlg + + +CShutDownDlg::CShutDownDlg(CWnd* pParent /*=NULL*/) + : CDialog(CShutDownDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CShutDownDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT + + Create(CShutDownDlg::IDD, pParent); +} + + +void CShutDownDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CShutDownDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier DDX- und DDV-Aufrufe ein + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CShutDownDlg, CDialog) + //{{AFX_MSG_MAP(CShutDownDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Zuordnungsmakros fĂ¼r Nachrichten ein + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CShutDownDlg + + +void CShutDownDlg::PostNcDestroy() +{ + // delete this; +} diff --git a/MissionEditor/ShutDownDlg.h b/MissionEditor/ShutDownDlg.h new file mode 100644 index 0000000..24a019d --- /dev/null +++ b/MissionEditor/ShutDownDlg.h @@ -0,0 +1,69 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_SHUTDOWNDLG_H__28D9E061_8340_11D4_9C87_A1B9E12BB04A__INCLUDED_) +#define AFX_SHUTDOWNDLG_H__28D9E061_8340_11D4_9C87_A1B9E12BB04A__INCLUDED_ + +#include "resource.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ShutDownDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CShutDownDlg + +class CShutDownDlg : public CDialog +{ +// Konstruktion +public: + CShutDownDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CShutDownDlg) + enum { IDD = IDD_SHUTDOWN }; + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Datenelemente ein + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CShutDownDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CShutDownDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Member-Funktionen ein + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_SHUTDOWNDLG_H__28D9E061_8340_11D4_9C87_A1B9E12BB04A__INCLUDED_ diff --git a/MissionEditor/SingleplayerSettings.cpp b/MissionEditor/SingleplayerSettings.cpp new file mode 100644 index 0000000..9a1c67c --- /dev/null +++ b/MissionEditor/SingleplayerSettings.cpp @@ -0,0 +1,227 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// SingleplayerSettings.cpp: implementation file +// + +#include "stdafx.h" +#include "finalsun.h" +#include "SingleplayerSettings.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// property page CSingleplayerSettings + +IMPLEMENT_DYNCREATE(CSingleplayerSettings, CDialog) + +CSingleplayerSettings::CSingleplayerSettings() : CDialog(IDD) +{ + //{{AFX_DATA_INIT(CSingleplayerSettings) + + //}}AFX_DATA_INIT +} + +CSingleplayerSettings::~CSingleplayerSettings() +{ +} + +void CSingleplayerSettings::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSingleplayerSettings) + DDX_Control(pDX, IDC_TIMERINHERIT, m_TimerInherit); + DDX_Control(pDX, IDC_STARTINGDROPSHIPS, m_StartingDropships); + DDX_Control(pDX, IDC_FILLSILOS, m_FillSilos); + DDX_Control(pDX, IDC_CARRYOVERMONEY, m_CarryOverMoney); + DDX_Control(pDX, IDC_WIN, m_Win); + DDX_Control(pDX, IDC_PREMAPSELECT, m_PreMapSelect); + DDX_Control(pDX, IDC_POSTSCORE, m_PostScore); + DDX_Control(pDX, IDC_LOSE, m_Lose); + DDX_Control(pDX, IDC_INTRO, m_Intro); + DDX_Control(pDX, IDC_BRIEF, m_Brief); + DDX_Control(pDX, IDC_ACTION, m_Action); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSingleplayerSettings, CDialog) + //{{AFX_MSG_MAP(CSingleplayerSettings) + ON_CBN_EDITCHANGE(IDC_INTRO, OnEditchangeIntro) + ON_CBN_EDITCHANGE(IDC_BRIEF, OnEditchangeBrief) + ON_CBN_EDITCHANGE(IDC_WIN, OnEditchangeWin) + ON_CBN_EDITCHANGE(IDC_LOSE, OnEditchangeLose) + ON_CBN_EDITCHANGE(IDC_ACTION, OnEditchangeAction) + ON_CBN_EDITCHANGE(IDC_POSTSCORE, OnEditchangePostscore) + ON_CBN_EDITCHANGE(IDC_PREMAPSELECT, OnEditchangePremapselect) + ON_CBN_EDITCHANGE(IDC_STARTINGDROPSHIPS, OnEditchangeStartingdropships) + ON_EN_CHANGE(IDC_CARRYOVERMONEY, OnChangeCarryovermoney) + ON_CBN_EDITCHANGE(IDC_TIMERINHERIT, OnEditchangeTimerinherit) + ON_CBN_EDITCHANGE(IDC_FILLSILOS, OnEditchangeFillsilos) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// message handlers + +void CSingleplayerSettings::UpdateDialog() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection& sec=ini.sections["Basic"]; + + if(sec.values.find("Intro")!=sec.values.end()) + m_Intro.SetWindowText(sec.values["Intro"]); + if(sec.values.find("Brief")!=sec.values.end()) + m_Brief.SetWindowText(sec.values["Brief"]); + if(sec.values.find("Win")!=sec.values.end()) + m_Win.SetWindowText(sec.values["Win"]); + if(sec.values.find("Lose")!=sec.values.end()) + m_Lose.SetWindowText(sec.values["Lose"]); + if(sec.values.find("Action")!=sec.values.end()) + m_Action.SetWindowText(sec.values["Action"]); + if(sec.values.find("PostScore")!=sec.values.end()) + m_PostScore.SetWindowText(sec.values["PostScore"]); + if(sec.values.find("PreMapSelect")!=sec.values.end()) + m_PreMapSelect.SetWindowText(sec.values["PreMapSelect"]); + + if(sec.values.find("StartingDropships")!=sec.values.end()) + m_StartingDropships.SetWindowText(sec.values["StartingDropships"]); + if(sec.values.find("CarryOverMoney")!=sec.values.end()) + m_CarryOverMoney.SetWindowText(sec.values["CarryOverMoney"]); + if(sec.values.find("TimerInherit")!=sec.values.end()) + m_TimerInherit.SetWindowText(sec.values["TimerInherit"]); + if(sec.values.find("FillSilos")!=sec.values.end()) + m_FillSilos.SetWindowText(sec.values["FillSilos"]); + + ListMovies(m_Intro, TRUE); + ListMovies(m_Brief, TRUE); + ListMovies(m_Win, TRUE); + ListMovies(m_Lose, TRUE); + ListMovies(m_Action, TRUE); + ListMovies(m_PostScore, TRUE); + ListMovies(m_PreMapSelect, TRUE); + + + UpdateStrings(); +} + +void CSingleplayerSettings::OnEditchangeIntro() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["Intro"]=GetText(&m_Intro); +} + +void CSingleplayerSettings::OnEditchangeBrief() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["Brief"]=GetText(&m_Brief); +} + +void CSingleplayerSettings::OnEditchangeWin() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["Win"]=GetText(&m_Win); +} + +void CSingleplayerSettings::OnEditchangeLose() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["Lose"]=GetText(&m_Lose); +} + +void CSingleplayerSettings::OnEditchangeAction() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["Action"]=GetText(&m_Action); +} + +void CSingleplayerSettings::OnEditchangePostscore() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["PostScore"]=GetText(&m_PostScore); +} + +void CSingleplayerSettings::OnEditchangePremapselect() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["PreMapSelect"]=GetText(&m_PreMapSelect); +} + +void CSingleplayerSettings::OnEditchangeStartingdropships() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["StartingDropships"]=GetText(&m_StartingDropships); +} + +void CSingleplayerSettings::OnChangeCarryovermoney() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["CarryOverMoney"]=GetText(&m_CarryOverMoney); +} + +void CSingleplayerSettings::OnEditchangeTimerinherit() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["TimerInherit"]=GetText(&m_TimerInherit); +} + +void CSingleplayerSettings::OnEditchangeFillsilos() +{ + CIniFile& ini=Map->GetIniFile(); + ini.sections["Basic"].values["FillSilos"]=GetText(&m_FillSilos); +} + +void CSingleplayerSettings::UpdateStrings() +{ + SetDlgItemText(IDC_LSTARTINGDROPSHIPS, GetLanguageStringACP("SingleplayerStartingDropships")); + SetDlgItemText(IDC_LCARRYOVERMONEY, GetLanguageStringACP("SingleplayerCarryOverMoney")); + SetDlgItemText(IDC_LINHERITTIMER, GetLanguageStringACP("SingleplayerTimerInherit")); + SetDlgItemText(IDC_LFILLSILOS, GetLanguageStringACP("SingleplayerFillSilos")); + SetDlgItemText(IDC_LMOVIES, GetLanguageStringACP("SingleplayerMovies")); + SetDlgItemText(IDC_LINTRO, GetLanguageStringACP("SingleplayerIntro")); + SetDlgItemText(IDC_LBRIEF, GetLanguageStringACP("SingleplayerBrief")); + SetDlgItemText(IDC_LWIN, GetLanguageStringACP("SingleplayerWin")); + SetDlgItemText(IDC_LLOSE, GetLanguageStringACP("SingleplayerLose")); + SetDlgItemText(IDC_LACTION, GetLanguageStringACP("SingleplayerAction")); + SetDlgItemText(IDC_LPOSTSCORE, GetLanguageStringACP("SingleplayerPostScore")); + SetDlgItemText(IDC_LPREMAPSELECT, GetLanguageStringACP("SingleplayerPreMapSelect")); + SetDlgItemText(IDC_DESC, GetLanguageStringACP("SingleplayerDesc")); + + SetWindowText(TranslateStringACP("Singleplayer settings")); + +#ifdef RA2_MODE + GetDlgItem(IDC_LSTARTINGDROPSHIPS)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_STARTINGDROPSHIPS)->ShowWindow(SW_HIDE); +#endif +} + +void CSingleplayerSettings::PostNcDestroy() +{ + // do not call CDialog::PostNcDestroy(); + // CDialog::PostNcDestroy(); +} diff --git a/MissionEditor/SingleplayerSettings.h b/MissionEditor/SingleplayerSettings.h new file mode 100644 index 0000000..835e23f --- /dev/null +++ b/MissionEditor/SingleplayerSettings.h @@ -0,0 +1,92 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_SINGLEPLAYERSETTINGS_H__082D6780_CA89_11D3_B63B_00485453E8BA__INCLUDED_) +#define AFX_SINGLEPLAYERSETTINGS_H__082D6780_CA89_11D3_B63B_00485453E8BA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SingleplayerSettings.h : Header file +// + +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +// dialog field CSingleplayerSettings + +class CSingleplayerSettings : public CDialog +{ + DECLARE_DYNCREATE(CSingleplayerSettings) + +// construction +public: + void UpdateStrings(); + void UpdateDialog(); + CSingleplayerSettings(); + ~CSingleplayerSettings(); + +// dialog field data + //{{AFX_DATA(CSingleplayerSettings) + enum { IDD = IDD_SINGLEPLAYER }; + CMyComboBox m_TimerInherit; + CMyComboBox m_StartingDropships; + CMyComboBox m_FillSilos; + CFloatEdit m_CarryOverMoney; + CMyComboBox m_Win; + CMyComboBox m_PreMapSelect; + CMyComboBox m_PostScore; + CMyComboBox m_Lose; + CMyComboBox m_Intro; + CMyComboBox m_Brief; + CMyComboBox m_Action; + //}}AFX_DATA + + +// overwriteables + //{{AFX_VIRTUAL(CSingleplayerSettings) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // ddx/ddv support + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// implementation +protected: + // generated message maps + //{{AFX_MSG(CSingleplayerSettings) + afx_msg void OnEditchangeIntro(); + afx_msg void OnEditchangeBrief(); + afx_msg void OnEditchangeWin(); + afx_msg void OnEditchangeLose(); + afx_msg void OnEditchangeAction(); + afx_msg void OnEditchangePostscore(); + afx_msg void OnEditchangePremapselect(); + afx_msg void OnEditchangeStartingdropships(); + afx_msg void OnChangeCarryovermoney(); + afx_msg void OnEditchangeTimerinherit(); + afx_msg void OnEditchangeFillsilos(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} + +#endif // AFX_SINGLEPLAYERSETTINGS_H__082D6780_CA89_11D3_B63B_00485453E8BA__INCLUDED_ diff --git a/MissionEditor/SpecialFlags.cpp b/MissionEditor/SpecialFlags.cpp new file mode 100644 index 0000000..20027c1 --- /dev/null +++ b/MissionEditor/SpecialFlags.cpp @@ -0,0 +1,311 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// SpecialFlags.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "SpecialFlags.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CSpecialFlags + + +CSpecialFlags::CSpecialFlags(CWnd* pParent /*=NULL*/) + : CDialog(CSpecialFlags::IDD, 0) +{ + //{{AFX_DATA_INIT(CSpecialFlags) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + + +void CSpecialFlags::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSpecialFlags) + DDX_Control(pDX, IDC_VISCEROIDS, m_Visceroids); + DDX_Control(pDX, IDC_TIBERIUMSPREADS, m_TiberiumSpreads); + DDX_Control(pDX, IDC_TIBERIUMGROWS, m_TiberiumGrows); + DDX_Control(pDX, IDC_TIBERIUMEXPLOSIVE, m_TiberiumExplosive); + DDX_Control(pDX, IDC_METEORITES, m_Meteorites); + DDX_Control(pDX, IDC_MCVDEPLOY, m_MCVDeploy); + DDX_Control(pDX, IDC_IONSTORMS, m_IonStorms); + DDX_Control(pDX, IDC_INITIALVETERAN, m_InitialVeteran); + DDX_Control(pDX, IDC_INERT, m_Inert); + DDX_Control(pDX, IDC_HARVESTERIMMUNE, m_HarvesterImmune); + DDX_Control(pDX, IDC_FOGOFWAR, m_FogOfWar); + DDX_Control(pDX, IDC_FIXEDALLIANCE, m_FixedAlliance); + DDX_Control(pDX, IDC_DESTROYABLEBRIDGES, m_DestroyableBridges); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSpecialFlags, CDialog) + //{{AFX_MSG_MAP(CSpecialFlags) + ON_CBN_EDITCHANGE(IDC_TIBERIUMGROWS, OnEditchangeTiberiumgrows) + ON_CBN_EDITCHANGE(IDC_TIBERIUMSPREADS, OnEditchangeTiberiumspreads) + ON_CBN_EDITCHANGE(IDC_TIBERIUMEXPLOSIVE, OnEditchangeTiberiumexplosive) + ON_CBN_EDITCHANGE(IDC_DESTROYABLEBRIDGES, OnEditchangeDestroyablebridges) + ON_CBN_EDITCHANGE(IDC_MCVDEPLOY, OnEditchangeMcvdeploy) + ON_CBN_EDITCHANGE(IDC_INITIALVETERAN, OnEditchangeInitialveteran) + ON_CBN_EDITCHANGE(IDC_FIXEDALLIANCE, OnEditchangeFixedalliance) + ON_CBN_EDITCHANGE(IDC_HARVESTERIMMUNE, OnEditchangeHarvesterimmune) + ON_CBN_EDITCHANGE(IDC_FOGOFWAR, OnEditchangeFogofwar) + ON_CBN_EDITCHANGE(IDC_INERT, OnEditchangeInert) + ON_CBN_EDITCHANGE(IDC_IONSTORMS, OnEditchangeIonstorms) + ON_CBN_EDITCHANGE(IDC_METEORITES, OnEditchangeMeteorites) + ON_CBN_EDITCHANGE(IDC_VISCEROIDS, OnEditchangeVisceroids) + + ON_CBN_SELCHANGE(IDC_TIBERIUMGROWS, OnEditchangeTiberiumgrows) + ON_CBN_SELCHANGE(IDC_TIBERIUMSPREADS, OnEditchangeTiberiumspreads) + ON_CBN_SELCHANGE(IDC_TIBERIUMEXPLOSIVE, OnEditchangeTiberiumexplosive) + ON_CBN_SELCHANGE(IDC_DESTROYABLEBRIDGES, OnEditchangeDestroyablebridges) + ON_CBN_SELCHANGE(IDC_MCVDEPLOY, OnEditchangeMcvdeploy) + ON_CBN_SELCHANGE(IDC_INITIALVETERAN, OnEditchangeInitialveteran) + ON_CBN_SELCHANGE(IDC_FIXEDALLIANCE, OnEditchangeFixedalliance) + ON_CBN_SELCHANGE(IDC_HARVESTERIMMUNE, OnEditchangeHarvesterimmune) + ON_CBN_SELCHANGE(IDC_FOGOFWAR, OnEditchangeFogofwar) + ON_CBN_SELCHANGE(IDC_INERT, OnEditchangeInert) + ON_CBN_SELCHANGE(IDC_IONSTORMS, OnEditchangeIonstorms) + ON_CBN_SELCHANGE(IDC_METEORITES, OnEditchangeMeteorites) + ON_CBN_SELCHANGE(IDC_VISCEROIDS, OnEditchangeVisceroids) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +void CSpecialFlags::UpdateDialog() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + m_DestroyableBridges.SetWindowText(sec->values["DestroyableBridges"]); + m_FixedAlliance.SetWindowText(sec->values["FixedAlliance"]); + m_FogOfWar.SetWindowText(sec->values["FogOfWar"]); + m_HarvesterImmune.SetWindowText(sec->values["HarvesterImmune"]); + m_Inert.SetWindowText(sec->values["Inert"]); + m_InitialVeteran.SetWindowText(sec->values["InitialVeteran"]); + m_IonStorms.SetWindowText(sec->values["IonStorms"]); + m_MCVDeploy.SetWindowText(sec->values["MCVDeploy"]); + m_Meteorites.SetWindowText(sec->values["Meteorites"]); + m_TiberiumExplosive.SetWindowText(sec->values["TiberiumExplosive"]); + m_TiberiumGrows.SetWindowText(sec->values["TiberiumGrows"]); + m_TiberiumSpreads.SetWindowText(sec->values["TiberiumSpreads"]); + m_Visceroids.SetWindowText(sec->values["Visceroids"]); + +#ifdef RA2_MODE + SetDlgItemText(IDC_LTIBERIUMGROWS,"Ore grows:"); + SetDlgItemText(IDC_LTIBERIUMSPREADS,"Ore spreads:"); + GetDlgItem(IDC_LTIBERIUMEXPLOSIVE)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_TIBERIUMEXPLOSIVE)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_HARVESTERIMMUNE)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_LHARVESTERIMMUNE)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_METEORITES)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_LMETEORITES)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_VISCEROIDS)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_LVISCEROIDS)->ShowWindow(SW_HIDE); + + SetDlgItemText(IDC_LFOGOFWAR, "Shroud:"); + SetDlgItemText(IDC_LIONSTORMS, "Weather Storms:"); +#endif + +}; +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CSpecialFlags + +void CSpecialFlags::OnEditchangeTiberiumgrows() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_TiberiumGrows); + sec->values["TiberiumGrows"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeTiberiumspreads() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_TiberiumSpreads); + sec->values["TiberiumSpreads"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeTiberiumexplosive() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_TiberiumExplosive); + sec->values["TiberiumExplosive"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeDestroyablebridges() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_DestroyableBridges); + sec->values["DestroyableBridges"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeMcvdeploy() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_MCVDeploy); + sec->values["MCVDeploy"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeInitialveteran() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_InitialVeteran); + sec->values["InitialVeteran"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeFixedalliance() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_FixedAlliance); + sec->values["FixedAlliance"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeHarvesterimmune() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_HarvesterImmune); + sec->values["HarvesterImmune"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeFogofwar() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_FogOfWar); + sec->values["FogOfWar"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeInert() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_Inert); + sec->values["Inert"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeIonstorms() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_IonStorms); + sec->values["IonStorms"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeMeteorites() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_Meteorites); + sec->values["Meteorites"]=(LPCTSTR)str; +} + +void CSpecialFlags::OnEditchangeVisceroids() +{ + CIniFile& ini=Map->GetIniFile(); + + CIniFileSection *sec; + sec=&ini.sections["SpecialFlags"]; + CString str; + + + str=GetText(&m_Visceroids); + sec->values["Visceroids"]=(LPCTSTR)str; +} diff --git a/MissionEditor/SpecialFlags.h b/MissionEditor/SpecialFlags.h new file mode 100644 index 0000000..e02146e --- /dev/null +++ b/MissionEditor/SpecialFlags.h @@ -0,0 +1,91 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_SPECIALFLAGS_H__500DF000_7058_11D3_99E1_97DB32807805__INCLUDED_) +#define AFX_SPECIALFLAGS_H__500DF000_7058_11D3_99E1_97DB32807805__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SpecialFlags.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CSpecialFlags + +class CSpecialFlags : public CDialog +{ +// Konstruktion +public: + void UpdateDialog(); + CSpecialFlags(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CSpecialFlags) + enum { IDD = IDD_SPECIALFLAGS }; + CMyComboBox m_Visceroids; + CMyComboBox m_TiberiumSpreads; + CMyComboBox m_TiberiumGrows; + CMyComboBox m_TiberiumExplosive; + CMyComboBox m_Meteorites; + CMyComboBox m_MCVDeploy; + CMyComboBox m_IonStorms; + CMyComboBox m_InitialVeteran; + CMyComboBox m_Inert; + CMyComboBox m_HarvesterImmune; + CMyComboBox m_FogOfWar; + CMyComboBox m_FixedAlliance; + CMyComboBox m_DestroyableBridges; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CSpecialFlags) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CSpecialFlags) + afx_msg void OnEditchangeTiberiumgrows(); + afx_msg void OnEditchangeTiberiumspreads(); + afx_msg void OnEditchangeTiberiumexplosive(); + afx_msg void OnEditchangeDestroyablebridges(); + afx_msg void OnEditchangeMcvdeploy(); + afx_msg void OnEditchangeInitialveteran(); + afx_msg void OnEditchangeFixedalliance(); + afx_msg void OnEditchangeHarvesterimmune(); + afx_msg void OnEditchangeFogofwar(); + afx_msg void OnEditchangeInert(); + afx_msg void OnEditchangeIonstorms(); + afx_msg void OnEditchangeMeteorites(); + afx_msg void OnEditchangeVisceroids(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_SPECIALFLAGS_H__500DF000_7058_11D3_99E1_97DB32807805__INCLUDED_ diff --git a/MissionEditor/StdAfx.cpp b/MissionEditor/StdAfx.cpp new file mode 100644 index 0000000..e687021 --- /dev/null +++ b/MissionEditor/StdAfx.cpp @@ -0,0 +1,36 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// stdafx.cpp : Quelltextdatei, die nur die Standard-Includes einbindet +// TiberianSun Mission Editor.pch ist die vorcompilierte Header-Datei +// stdafx.obj enthält die vorcompilierte Typinformation + +#include "stdafx.h" + +#include "structs.h" + + + +TILEDATA::~TILEDATA() +{ + memset(this,0, sizeof(TILEDATA)); +} + + diff --git a/MissionEditor/StdAfx.h b/MissionEditor/StdAfx.h new file mode 100644 index 0000000..456a46f --- /dev/null +++ b/MissionEditor/StdAfx.h @@ -0,0 +1,64 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// stdafx.h : include everything that should be available everywhere in the code +// + +#if !defined(AFX_STDAFX_H__9F773426_63BB_11D3_99E0_C30F10710B17__INCLUDED_) +#define AFX_STDAFX_H__9F773426_63BB_11D3_99E0_C30F10710B17__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#define VC_EXTRALEAN +#define NOMINMAX + +#pragma warning(disable: 4503) +#pragma warning(disable: 4786) +#pragma warning(disable: 4800) + + +#include <afxwin.h> +#include <afxext.h> +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include <afxcmn.h> +#endif + +#include "defines.h" +#include "IniFile.h" +#include "InputBox.h" +#include "floatedit.h" +#include "MyComboBox.h" +#include <ddraw.h> +// #include "structs.h" +// #include "variables.h" +// #include "functions.h" +// #include "inlines.h" +// #include "MapData.h" +#include "resource.h" +#include "TipDlg.h" + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ inserts additional declarations exactly above this line. + +#endif // !defined(AFX_STDAFX_H__9F773426_63BB_11D3_99E0_C30F10710B17__INCLUDED_) + diff --git a/MissionEditor/Structs.h b/MissionEditor/Structs.h new file mode 100644 index 0000000..d536611 --- /dev/null +++ b/MissionEditor/Structs.h @@ -0,0 +1,658 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +/************************************** + Global structs here +**************************************/ + +#ifndef GLOBALSTRUCTS_H_INCLUDED +#define GLOBALSTRUCTS_H_INCLUDED + +#include "defines.h" +#include <vector> +#include <memory> +#include <cstdint> +#include "MissionEditorPackLib.h" +#include "Vec2.h" + +class MapTool; + + +enum class TheaterChar : char +{ + T = 'T', + A = 'A', + U = 'U', + N = 'N', + D = 'D', + L = 'L', + Generic = 'G', + None = 0 +}; + +inline TheaterChar toTheaterChar(char c) +{ + switch (c) + { + case 'T': + return TheaterChar::T; + case 'A': + return TheaterChar::A; + case 'U': + return TheaterChar::U; + case 'N': + return TheaterChar::N; + case 'D': + return TheaterChar::D; + case 'L': + return TheaterChar::L; + case 'G': + return TheaterChar::Generic; + default: + return TheaterChar::None; + } +} + +struct CLIPBOARD_MAPCOPY_ENTRY +{ + BOOL bRedrawTerrain; + BYTE overlay; + BYTE overlaydata; + WORD wGround; + WORD bMapData; + BYTE bSubTile; + BYTE bHeight; + BYTE bMapData2; + + // for RA2<->TS conversion: + WORD wTileSet; + BYTE bTile; +}; + +struct CLIPBOARD_DATA +{ + DWORD dwType; + DWORD dwVersion; + DWORD dwReserved; + BYTE bGame; // 0 TS, 1 RA2 + UINT iWidth; + UINT iHeight; +}; + +struct VBORDER +{ + short left; + short right; +}; + +/* +picdata + +Holds information for every picture: +a directdraw surface, and additional data +*/ +struct PICDATA{ + PICDATA() = default; + PICDATA(const PICDATA& c) = default; + PICDATA& operator=(const PICDATA& c) = default; + ~PICDATA() = default; + +#ifndef NOSURFACES_OBJECTS + LPDIRECTDRAWSURFACE4 pic; +#else + void* pic = nullptr; // BYTE* to image, exception: if bType==PICDATA_TYPE_BMP then this is a LPDIRECTDRAWSURFACE! + VBORDER* vborder = nullptr; + int* pal = nullptr; + std::shared_ptr<std::vector<BYTE>> lighting; + std::shared_ptr<std::vector<BYTE>> rawPic; + std::shared_ptr<std::vector<VBORDER>> _vBorder; +#endif + + FSunPackLib::VoxelNormalClass normalClass = FSunPackLib::VoxelNormalClass::Unknown; + short x = 0; // for SHPs (starting point of main graphic inside surface) + short y = 0; // for SHPs (starting point of main graphic inside surface) + WORD wWidth = 0; // for non-shps: size of whole surface, else size of main graphic + WORD wHeight = 0; // for non-shps: size of whole surface, else size of main graphic + WORD wMaxWidth = 0; // for SHPs (size of whole surface) + WORD wMaxHeight = 0; // for SHPs (size of whole surface) + BYTE bType = 0; // is loaded from voxel, shp, bmp, etc... (for drawing logic) + TheaterChar bTerrain = TheaterChar::None; + BOOL bTried = 0; // already tried to load this? - superseded by global array missingimages + + inline ProjectedVec drawOffset() const + { + return ProjectedVec(x, y); + } + +#ifdef NOSURFACES_OBJECTS + void createVBorder(); +#endif + +}; + +/* +TILEPIC / TILEDATA + +Holds information for every tile/subtile in TS. +*/ +struct SUBTILE{ +#ifndef NOSURFACES + LPDIRECTDRAWSURFACE4 pic; +#else +#ifdef NOSURFACES_EXTRACT + BOOL bNotExtracted; // pic is not extracted, even if NOSURFACES_EXTRACT is specifed. Probably there is inner transparency! +#endif + BYTE* pic; // optionally use direct blitting? This is either a palette index array or non-palette data (if NOSURFACES_EXTRACT is specified) + VBORDER * vborder; +#endif + + WORD wWidth; // width of tile + WORD wHeight; // height " + short sX; // x starting pos + short sY; // y starting pos + BYTE bZHeight; // z difference from tile ground surface (1unit == f_y/2pixel == 12pixel) + BYTE bDirection; // for ramps for example + BYTE bTerrainType; // water, etc... + RGBTRIPLE rgbLeft; + RGBTRIPLE rgbRight; + BYTE bHackedTerrainType; // same like bTerrainType, except some shore pieces that were hacked in fsdata.ini + + std::shared_ptr<PICDATA> anim; + + inline ProjectedVec drawOffset() const + { + return ProjectedVec(sX, sY); + } +}; +struct TILEDATA{ + TILEDATA() = default; + ~TILEDATA(); + WORD wTileSet = 0; + SUBTILE* tiles = nullptr; // the different tiles + WORD wTileCount = 0; // number of tiles + WORD cx = 0; + WORD cy = 0; + BOOL bAllowTiberium = 0; + BOOL bAllowToPlace = TRUE; + BOOL bMorphable = FALSE; // morphable using lower/raise ground function? + BOOL bHide = FALSE; // for user interface only + BOOL bMarbleMadness = FALSE; + WORD wMarbleGround = 0xFFFF; + +public: + RECT rect = { 0 }; + + TILEDATA* lpReplacements = nullptr; + BYTE bReplacementCount = 0; +}; + +/* +actiondata + +CViewObjects sets this data struct, +and CIsoView uses it to interact with the user´s CViewObjects and terrain editing choice +*/ +struct ACTIONDATA{ + DWORD mode; + DWORD type; + DWORD data; + DWORD data2; + DWORD data3; + int z_data; + CString data_s; + std::unique_ptr<MapTool> tool; + + ~ACTIONDATA(); + + void reset(); +}; + +struct SIDEINFO{ + CString name; + int orig_n; +}; + +struct HOUSEINFO{ + CString name; + SIDEINFO* side; // side is used for rules.ini owner= settings + RGBTRIPLE color; + BOOL bPlayable; +}; + +/********************** + Unittype infos +**********************/ + +/* +building infos +*/ +struct BUILDING_INFO +{ + PICDATA pic[8]; + int pic_count; + BYTE w; + BYTE h; + BOOL bTemp; + BOOL bSnow; + BOOL bUrban; +}; + +struct TREE_INFO +{ + PICDATA pic; + BYTE w; + BYTE h; +}; + +#ifdef SMUDGE_SUPP +struct SMUDGE_INFO +{ + PICDATA pic; + //BYTE w; + //BYTE h; +}; +#endif + +/* +** Condition enumeration +*/ +enum ConditionEnum { + COND_LT = 0, // less than + COND_LE, // less than or equal to + COND_EQ, // equal to + COND_GE, // greater than or equal to + COND_GT, // greater than + COND_NE, // not equal to + COND_COUNT +}; + +struct AITrigInfo +{ + union{ + struct{ + int Number; + ConditionEnum Condition; + }; + char Padding[32]; + }; +}; + + +/* +Struct for string items +*/ +struct XCString +{ + XCString() + { + //wString=new(WCHAR[2]); + //memset(wString, 0, 4); + wString=NULL; + bUsedDefault=FALSE; + len=0; + } + ~XCString() + { + if(wString) delete[] wString; + len=0; + wString=NULL; + } + void SetString(const CHAR* cString) + { + len=strlen(cString); + + this->cString=cString; + + if(wString) delete[] wString; + + bUsedDefault=FALSE; + wString=new(WCHAR[len+1]); + memset(wString, 0, (len+1)*2); + + //MultiByteToWideChar(CP_ACP, WC_COMPOSITECHECK, cString, len, wString, len+1); + mbstowcs(wString, cString, len); + + } + void SetString(const WCHAR* wString, int len) + { + this->len=len; + + if(this->wString) delete[] this->wString; + + bUsedDefault=FALSE; + + this->wString=new(WCHAR[len+1]); + memset(this->wString, 0, (len+1)*2); + memcpy(this->wString, wString, len*2); + + auto bufferSize = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, this->wString, len + 1, nullptr, 0, NULL, &bUsedDefault); + if (bufferSize == 0) + { + cString = ""; + return; // failed + } + + std::vector<BYTE> bByte(bufferSize + 4, 0); + if (WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, this->wString, len + 1, (LPSTR)bByte.data(), bufferSize, NULL, &bUsedDefault) == 0) + { + cString = ""; + return; // failed + } + cString = bByte.data(); + + } + CString cString; + WCHAR* wString; + BOOL bUsedDefault; + int len; +}; + + +/********************** + Map stuff structs +***********************/ + +/* +AITRIGGERTYPE{}; + +Data for ai trigger types +*/ +struct AITRIGGERTYPE{ + CString ID; // ai trigger id + CString name; // param 1 + CString teamtype1; // param 2 + CString owner; // param 3 + CString techlevel; // flag 1/ param 4 + CString type; // param 5 + CString unittype; // param 6 + CString data; // param 7 + CString float1; // param 8 + CString float2; // param 9 + CString float3; // param 10 + CString skirmish; // param 11 + CString flag4; // param 12 + CString multihouse; // param 13 + CString basedefense; // param 14 + CString teamtype2; // param 15 + CString easy; // param 16 + CString medium; // param 17 + CString hard; // param 18 +}; + +/* +STDOBJECTDATA + +Data for Trees, Units, Infantry, Aircraft & Structures +This should be used for painting procedure... +except if you want to draw the upgrades on buildings +*/ +struct STDOBJECTDATA +{ + CString house; // 1 + CString type; // 2 + CString strength; // 3 + CString y; // 4 + CString x; // 5 +}; + +/* +STRUCTURE + +Data for a structure +*/ +struct STRUCTURE{ + CString house; // 1 + CString type; // 2 + CString strength; // 3 + CString y; // 4 + CString x; // 5 + CString direction; // 6 + CString tag; // 7 + CString flag1; // 8 + CString flag2; // 9 + CString energy; // 10 + CString upgradecount; // 11 + CString spotlight; // 12 + CString upgrade1; // 13 + CString upgrade2; // 14 + CString upgrade3; // 15 + CString flag3; // 16 + CString flag4; // 17 + unsigned deleted:1; +}; + +// structure data especially for painting +struct STRUCTUREPAINT{ + COLORREF col; + CString type; + short x; + short y; + short direction; + BYTE strength; + BYTE upradecount; + CString upgrade1; + CString upgrade2; + CString upgrade3; +}; + + +/* +struct INFANTRY{}; + +Data for an infantry unit +*/ +struct INFANTRY{ + CString house; // 1 + CString type; // 2 + CString strength; // 3 + CString y; // 4 + CString x; // 5 + CString pos; // 6 + CString action; // 7 + CString direction; // 8 + CString tag; // 9 + CString flag1; // 10 + CString flag2; // 11 + CString flag3; // 12 + CString flag4; // 13 + CString flag5; // 14 + unsigned deleted:1; +}; + +struct UNIT{ + CString house; // 1 + CString type; // 2 + CString strength; // 3 + CString y; // 4 + CString x; // 5 + CString direction; // 6 + CString action; // 7 + CString tag; // 8 + CString flag1; // 9 + CString flag2; // 10 + CString flag3; // 11 + CString flag4; // 12 + CString flag5; // 13 + CString flag6; // 14 + unsigned deleted:1; +}; + + + +struct AIRCRAFT{ + CString house; // 1 + CString type; // 2 + CString strength; // 3 + CString y; // 4 + CString x; // 5 + CString direction; // 6 + CString action; // 7 + CString tag; // 8 + CString flag1; // 9 + CString flag2; // 10 + CString flag3; // 11 + CString flag4; // 12 + unsigned deleted:1; +}; + +struct TERRAIN{ + CString type; + int x; + int y; + unsigned deleted:1; +}; + +// MW 08/07/01: Smudge +#ifdef SMUDGE_SUPP +struct SMUDGE{ + CString type; + int x; + int y; + unsigned deleted:1; +}; +#endif + +/* +NODE + +Data for a node +*/ +struct NODE{ + CString house; + CString type; + CString x; + CString y; +}; + + +struct RA2STRFILEHEAD +{ + DWORD dwFlag1; + DWORD dwCount1; + DWORD dwCount2; + DWORD dwUnused; + DWORD dwFlag2; +}; + +#define RA2STRFILEHEADSIZE 20 + +struct RA2STRINGENTRY +{ + RA2STRINGENTRY(){ + //memset(this, 0, sizeof(RA2STRINGENTRY)); + id=NULL; + value=NULL; + value_asc=0; + value_asc_size=0; + dwFlag = 0; + id_size = 0; + value_size = 0; + } + ~RA2STRINGENTRY(){ + if(value) delete[] value; + if(id) delete[] id; + if(value_asc) delete[] value_asc; + value=NULL; + value_size=0; + id=NULL; + id_size=0; + value_asc=0; + value_asc_size=0; + } + RA2STRINGENTRY(RA2STRINGENTRY& ref) + { + value=NULL; + value_size=0; + id=NULL; + id_size = 0; + value_asc=0; + value_asc_size=0; + + if(ref.value_size && ref.value) + { + value_size=ref.value_size; + value=new(WCHAR[value_size+1]); + memcpy(value, ref.value, value_size*sizeof(WCHAR)); + value[value_size]=0; + } + if(ref.id_size && ref.id) + { + id_size=ref.id_size; + id=new(CHAR[id_size+1]); + memcpy(id, ref.id, id_size*sizeof(CHAR)); + id[id_size]=0; + } + if(ref.value_asc_size && ref.value_asc) + { + value_asc_size=ref.value_asc_size; + value_asc=new(CHAR[value_asc_size+1]); + memcpy(value_asc, ref.value_asc, value_asc_size*sizeof(CHAR)); + value_asc[value_asc_size]=0; + } + dwFlag=ref.dwFlag; + } + RA2STRINGENTRY& operator=(RA2STRINGENTRY& ref) + { + if(value) delete[] value; + if(id) delete[] id; + value=NULL; + value_size=0; + id=NULL; + value_asc=0; + value_asc_size=0; + + if(ref.value_size) + { + value_size=ref.value_size; + value=new(WCHAR[value_size+1]); + memcpy(value, ref.value, value_size*sizeof(WCHAR)); + value[value_size]=0; + } + if(ref.id_size) + { + id_size=ref.id_size; + id=new(CHAR[id_size+1]); + memcpy(id, ref.id, id_size*sizeof(CHAR)); + id[id_size]=0; + } + if(ref.value_asc_size) + { + value_asc_size=ref.value_asc_size; + value_asc=new(CHAR[value_asc_size+1]); + memcpy(value_asc, ref.value_asc, value_asc_size*sizeof(CHAR)); + value_asc[value_asc_size]=0; + } + dwFlag=ref.dwFlag; + + return *this; + } + + DWORD dwFlag; + CHAR* id; + DWORD id_size; + DWORD value_size; + WCHAR* value; + CHAR* value_asc; + DWORD value_asc_size; +}; + + + +#endif \ No newline at end of file diff --git a/MissionEditor/TSOptions.cpp b/MissionEditor/TSOptions.cpp new file mode 100644 index 0000000..e939af7 --- /dev/null +++ b/MissionEditor/TSOptions.cpp @@ -0,0 +1,128 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TSOptions.cpp: implementation +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "TSOptions.h" +#include "resource.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + +extern CFinalSunApp theApp; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTSOptions + + +CTSOptions::CTSOptions(CWnd* pParent /*=NULL*/) + : CDialog(CTSOptions::IDD, pParent) + , m_PreferLocalTheaterFiles(FALSE) +{ + //{{AFX_DATA_INIT(CTSOptions) + m_LikeTS = -1; + //}}AFX_DATA_INIT +} + + +void CTSOptions::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTSOptions) + DDX_Control(pDX, IDC_LANGUAGE, m_Language); + DDX_Control(pDX, IDC_EDIT1, m_TSExe); + DDX_Radio(pDX, IDC_RULESLIKETS, m_LikeTS); + DDX_Check(pDX, IDC_PREFER_LOCAL_THEATER_FILES, m_PreferLocalTheaterFiles); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTSOptions, CDialog) + //{{AFX_MSG_MAP(CTSOptions) + ON_BN_CLICKED(IDC_CHOOSE, OnChoose) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTSOptions + +void CTSOptions::OnChoose() +{ +#ifndef RA2_MODE + CFileDialog fd(TRUE, NULL, "Sun.exe", OFN_FILEMUSTEXIST, "Tiberian Sun EXE|Sun.exe|"); +#else + CFileDialog fd(TRUE, NULL, "ra2.exe", OFN_FILEMUSTEXIST, "Red Alert 2 EXE|ra2.exe|"); +#endif + + fd.DoModal(); + + this->GetDlgItem(IDC_EDIT1)->SetWindowText((LPCTSTR)fd.GetPathName()); + + delete fd; +} + +void CTSOptions::OnOK() +{ + this->GetDlgItem(IDC_EDIT1)->GetWindowText(m_TSEXE); + int n=m_Language.GetItemData(m_Language.GetCurSel()); + + m_LanguageName=*language.sections["Languages"].GetValue(n); + + CDialog::OnOK(); +} + +BOOL CTSOptions::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_TSExe.SetWindowText((LPCTSTR)theApp.m_Options.TSExe); + + if(theApp.m_Options.bSearchLikeTS) m_LikeTS=0; + else m_LikeTS=1; + + m_PreferLocalTheaterFiles = theApp.m_Options.bPreferLocalTheaterFiles ? TRUE : FALSE; + + UpdateData(FALSE); + + int i; + for(i=0;i<language.sections["Languages"].values.size();i++) + { + CString lang=*language.sections["Languages"].GetValue(i); + lang=language.sections[lang+"Header"].values["Name"]; + + + + m_Language.SetItemData(m_Language.AddString(lang),i); + if (lang=="English") + m_Language.SetCurSel(i); + } + + + return TRUE; +} diff --git a/MissionEditor/TSOptions.h b/MissionEditor/TSOptions.h new file mode 100644 index 0000000..329cfd7 --- /dev/null +++ b/MissionEditor/TSOptions.h @@ -0,0 +1,74 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TSOPTIONS_H__AFDC93E0_651A_11D3_99E0_B9A145C86B12__INCLUDED_) +#define AFX_TSOPTIONS_H__AFDC93E0_651A_11D3_99E0_B9A145C86B12__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TSOptions.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTSOptions + +class CTSOptions : public CDialog +{ +// Konstruktion +public: + BOOL m_PreferLocalTheaterFiles; + CString m_LanguageName; + CString m_TSEXE; + CTSOptions(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CTSOptions) + enum { IDD = IDD_TSOPTIONS }; + CComboBox m_Language; + CEdit m_TSExe; + int m_LikeTS; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTSOptions) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTSOptions) + afx_msg void OnChoose(); + virtual void OnOK(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TSOPTIONS_H__AFDC93E0_651A_11D3_99E0_B9A145C86B12__INCLUDED_ diff --git a/MissionEditor/Tags.cpp b/MissionEditor/Tags.cpp new file mode 100644 index 0000000..36a7328 --- /dev/null +++ b/MissionEditor/Tags.cpp @@ -0,0 +1,353 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Tags.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Tags.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CTags + +IMPLEMENT_DYNCREATE(CTags, CDialog) + +CTags::CTags() : CDialog(CTags::IDD) +{ + //{{AFX_DATA_INIT(CTags) + m_Name = _T(""); + //}}AFX_DATA_INIT +} + +CTags::~CTags() +{ +} + +void CTags::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTags) + DDX_Control(pDX, IDC_REPEAT, m_Repeat); + DDX_Control(pDX, IDC_TAG, m_Tag); + DDX_Control(pDX, IDC_TRIGGER, m_Trigger); + DDX_Text(pDX, IDC_NAME, m_Name); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTags, CDialog) + //{{AFX_MSG_MAP(CTags) + ON_CBN_SELCHANGE(IDC_TAG, OnSelchangeTag) + ON_EN_CHANGE(IDC_NAME, OnChangeName) + ON_CBN_EDITCHANGE(IDC_REPEAT, OnEditchangeRepeat) + ON_CBN_SELCHANGE(IDC_REPEAT, OnSelchangeRepeat) + ON_CBN_EDITCHANGE(IDC_TRIGGER, OnEditchangeTrigger) + ON_CBN_SELCHANGE(IDC_TRIGGER, OnSelchangeTrigger) + ON_BN_CLICKED(IDC_DELETE, OnDelete) + ON_BN_CLICKED(IDC_ADD, OnAdd) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTags + +void CTags::UpdateDialog() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Tag.GetCurSel(); + + while(m_Tag.DeleteString(0)!=CB_ERR); + while(m_Trigger.DeleteString(0)!=CB_ERR); + + int i; + for(i=0;i<ini.sections["Tags"].values.size();i++) + { + CString type=*ini.sections["Tags"].GetValueName(i); + CString s; + s=type; + s+=" ("; + s+=GetParam(*ini.sections["Tags"].GetValue(i), 1); + s+=")"; + m_Tag.AddString(s); + } + + for(i=0;i<ini.sections["Triggers"].values.size();i++) + { + CString type=*ini.sections["Triggers"].GetValueName(i); + CString s; + s=type; + s+=" ("; + s+=GetParam(ini.sections["Triggers"].values[type], 2); + s+=")"; + m_Trigger.AddString(s); + } + + if(m_Tag.SetCurSel(0)!=CB_ERR) + OnSelchangeTag(); + + if(sel!=-1) + { + if(m_Tag.SetCurSel(sel)!=CB_ERR) + { + OnSelchangeTag(); + } + } + +} + +void CTags::OnSelchangeTag() +{ + CIniFile& ini=Map->GetIniFile(); + + int index=m_Tag.GetCurSel(); + if(index<0) return; + CString type; + m_Tag.GetLBText(index, type); + if(type.Find(" ")>=0) type.SetAt(type.Find(" "),0); + + CString data=ini.sections["Tags"].values[(LPCTSTR)type]; + m_Name=GetParam(data,1); + CString trigger=GetParam(data,2); + CString typ=trigger; + + trigger+=" ("; + if(ini.sections["Triggers"].values.find(typ)!=ini.sections["Triggers"].values.end()) + trigger+=GetParam(ini.sections["Triggers"].values[typ],2); + trigger+=")"; + + m_Trigger.SetWindowText(trigger); + + + m_Repeat.SetWindowText(GetParam(data,0)); + + + + UpdateData(FALSE); +} + +void CTags::OnChangeName() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + CEdit& name=*(CEdit*)GetDlgItem(IDC_NAME); + int sel2=name.GetSel(); + + int index=m_Tag.GetCurSel(); + if(index<0) return; + CString type; + m_Tag.GetLBText(index, type); + if(type.Find(" ")>=0) type.SetAt(type.Find(" "),0); + + CString data=ini.sections["Tags"].values[(LPCTSTR)type]; + + CString tag, repeat; + tag=GetParam(data,2); + repeat=GetParam(data,0); + data=repeat+","+(LPCTSTR)m_Name+","+tag; + ini.sections["Tags"].values[(LPCTSTR)type]=data; + + UpdateDialog(); + name.SetSel(sel2); +} + +void CTags::OnEditchangeRepeat() +{ + CIniFile& ini=Map->GetIniFile(); + + int index=m_Tag.GetCurSel(); + if(index<0) return; + + CString str; + m_Repeat.GetWindowText(str); + + CString type; + m_Tag.GetLBText(index, type); + if(type.Find(" ")>=0) type.SetAt(type.Find(" "),0); + + CString data=ini.sections["Tags"].values[(LPCTSTR)type]; + + CString trigger, name; + trigger=GetParam(data,2); + name=GetParam(data,1); + data=(CString)(LPCTSTR)str+","+name+","+trigger; + ini.sections["Tags"].values[(LPCTSTR)type]=data; + + + UpdateDialog(); + +} + +void CTags::OnSelchangeRepeat() +{ + CIniFile& ini=Map->GetIniFile(); + + int index=m_Tag.GetCurSel(); + if(index<0) return; + + int v=m_Repeat.GetCurSel(); + CString str; + + + m_Repeat.GetLBText(v,str); + + + CString type; + m_Tag.GetLBText(index, type); + TruncSpace(type); + + TruncSpace(str); + + CString data=ini.sections["Tags"].values[(LPCTSTR)type]; + + CString trigger, name; + trigger=GetParam(data,2); + name=GetParam(data,1); + data=(CString)(LPCTSTR)str+","+name+","+trigger; + ini.sections["Tags"].values[(LPCTSTR)type]=data; + + + UpdateDialog(); +} + +void CTags::OnEditchangeTrigger() +{ + CIniFile& ini=Map->GetIniFile(); + + int index=m_Tag.GetCurSel(); + if(index<0) return; + + CString str; + m_Trigger.GetWindowText(str); + if(str.Find(" ")>=0) str.SetAt(str.Find(" "),0); + + CString type; + m_Tag.GetLBText(index, type); + if(type.Find(" ")>=0) type.SetAt(type.Find(" "),0); + + CString data=ini.sections["Tags"].values[(LPCTSTR)type]; + + CString repeat, name; + repeat=GetParam(data,0); + name=GetParam(data,1); + data=repeat+","+name+","+(LPCTSTR)str; + ini.sections["Tags"].values[(LPCTSTR)type]=data; + + + //UpdateDialog(); + +} + +void CTags::OnSelchangeTrigger() +{ + CIniFile& ini=Map->GetIniFile(); + + int index=m_Tag.GetCurSel(); + if(index<0) return; + + int v=m_Trigger.GetCurSel(); + CString str; + + + m_Trigger.GetLBText(v,str); + + if(str.Find(" ")>=0) str.SetAt(str.Find(" "),0); + + CString type; + m_Tag.GetLBText(index, type); + if(type.Find(" ")>=0) type.SetAt(type.Find(" "),0); + + CString data=ini.sections["Tags"].values[(LPCTSTR)type]; + + CString repeat, name; + repeat=GetParam(data,0); + name=GetParam(data,1); + data=repeat+","+name+","+(LPCTSTR)str; + ini.sections["Tags"].values[(LPCTSTR)type]=data; + + + //UpdateDialog(); +} + +void CTags::OnDelete() +{ + CIniFile& ini=Map->GetIniFile(); + + int index=m_Tag.GetCurSel(); + if(index<0) return; + + CString type; + m_Tag.GetLBText(index, type); + if(type.Find(" ")>=0) type.SetAt(type.Find(" "),0); + + int res=MessageBox("Are you sure to delete the selected tag? This may cause the attached trigger to don´t work anymore, if no other tag has the trigger attached.","Delete tag", MB_YESNO); + if(res==IDNO) return; + + ini.sections["Tags"].values.erase((LPCTSTR)type); + UpdateDialog(); +} + +void CTags::OnAdd() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ID=GetFreeID(); + + if(ini.sections["Triggers"].values.size()<1) + { + MessageBox("Before creating tags, you need at least one trigger.","Error"); + return; + }; + + CString data; + data="0,New Tag,"; + data+=*ini.sections["Triggers"].GetValueName(0); + ini.sections["Tags"].values[ID]=data; + + + UpdateDialog(); + + int i; + for(i=0;i<m_Tag.GetCount();i++) + { + CString j; + m_Tag.GetLBText(i,j); + if(j.Find(" ")>=0) j.SetAt(j.Find(" "),0); + + if(j==ID) + { + m_Tag.SetCurSel(i); + break; + } + } +} diff --git a/MissionEditor/Tags.h b/MissionEditor/Tags.h new file mode 100644 index 0000000..2371db6 --- /dev/null +++ b/MissionEditor/Tags.h @@ -0,0 +1,80 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TAGS_H__103BF600_9378_11D3_B63B_8867017BB441__INCLUDED_) +#define AFX_TAGS_H__103BF600_9378_11D3_B63B_8867017BB441__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Tags.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTags + +class CTags : public CDialog +{ + DECLARE_DYNCREATE(CTags) + +// Konstruktion +public: + void UpdateDialog(); + CTags(); + ~CTags(); + +// Dialogfelddaten + //{{AFX_DATA(CTags) + enum { IDD = IDD_TAGS }; + CComboBox m_Repeat; + CComboBox m_Tag; + CComboBox m_Trigger; + CString m_Name; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTags) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTags) + afx_msg void OnSelchangeTag(); + afx_msg void OnChangeName(); + afx_msg void OnEditchangeRepeat(); + afx_msg void OnSelchangeRepeat(); + afx_msg void OnEditchangeTrigger(); + afx_msg void OnSelchangeTrigger(); + afx_msg void OnDelete(); + afx_msg void OnAdd(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TAGS_H__103BF600_9378_11D3_B63B_8867017BB441__INCLUDED_ diff --git a/MissionEditor/TaskForce.cpp b/MissionEditor/TaskForce.cpp new file mode 100644 index 0000000..16a1a48 --- /dev/null +++ b/MissionEditor/TaskForce.cpp @@ -0,0 +1,567 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TaskForce.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "TaskForce.h" +#include "FinalSunDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CTaskForce + +IMPLEMENT_DYNCREATE(CTaskForce, CDialog) + +CTaskForce::CTaskForce() : CDialog(CTaskForce::IDD) +{ + //{{AFX_DATA_INIT(CTaskForce) + m_Group = _T(""); + m_Name = _T(""); + m_NumberOfUnits = 0; + //}}AFX_DATA_INIT +} + +CTaskForce::~CTaskForce() +{ +} + +void CTaskForce::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTaskForce) + DDX_Control(pDX, IDC_UNITTYPE, m_UnitType); + DDX_Control(pDX, IDC_UNITS, m_Units); + DDX_Control(pDX, IDC_TASKFORCES, m_TaskForces); + DDX_Text(pDX, IDC_GROUP, m_Group); + DDX_Text(pDX, IDC_NAME, m_Name); + DDX_Text(pDX, IDC_NUMBERUNITS, m_NumberOfUnits); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTaskForce, CDialog) + //{{AFX_MSG_MAP(CTaskForce) + ON_CBN_EDITCHANGE(IDC_TASKFORCES, OnEditchangeTaskforces) + ON_CBN_SELCHANGE(IDC_TASKFORCES, OnSelchangeTaskforces) + ON_LBN_SELCHANGE(IDC_UNITS, OnSelchangeUnits) + ON_BN_CLICKED(IDC_DELETEUNIT, OnDeleteunit) + ON_EN_CHANGE(IDC_NUMBERUNITS, OnChangeNumberunits) + ON_EN_CHANGE(IDC_NAME, OnChangeName) + ON_CBN_EDITCHANGE(IDC_UNITTYPE, OnEditchangeUnittype) + ON_CBN_SELCHANGE(IDC_UNITTYPE, OnSelchangeUnittype) + ON_BN_CLICKED(IDC_ADDUNIT, OnAddunit) + ON_BN_CLICKED(IDC_DELETETASKFORCE, OnDeletetaskforce) + ON_BN_CLICKED(IDC_ADDTASKFORCE, OnAddtaskforce) + ON_EN_CHANGE(IDC_GROUP, OnChangeGroup) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTaskForce + +void CTaskForce::UpdateDialog() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_TaskForces.GetCurSel(); + int sel2=m_Units.GetCurSel(); + + while(m_TaskForces.DeleteString(0)!=CB_ERR); + while(m_Units.DeleteString(0)!=LB_ERR); + while(m_UnitType.DeleteString(0)!=CB_ERR); + + // MW 07/24/01: Clear + m_Group=""; + m_Name=""; + m_NumberOfUnits=0; + UpdateData(FALSE); + + int i; + CIniFileSection& sec=ini.sections["TaskForces"]; + for(i=0;i<sec.values.size();i++) + { + CString s; + s=*sec.GetValue(i); + s+=" ("; + s+=ini.sections[*sec.GetValue(i)].values["Name"]; + s+=")"; + m_TaskForces.AddString(s); + } + + CString ss="InfantryTypes"; + for(i=0;i<rules.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*rules.sections[ss].GetValue(i); + s=type; + s+=" ("; + /*if(ini.sections.find((char*)(LPCTSTR)type)!=ini.sections.end() && ini.sections[(char*)(LPCTSTR)type].values.find("Name")!=ini.sections[(char*)(LPCTSTR)type].values.end()) + s+=ini.sections[(char*)(LPCTSTR)type].values["Name"]; + else + s+=rules.sections[(char*)(LPCTSTR)type].values["Name"]; + */ + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + for(i=0;i<ini.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*ini.sections[ss].GetValue(i); + s=type; + s+=" ("; + /*if(ini.sections.find((char*)(LPCTSTR)type)!=ini.sections.end() && ini.sections[(char*)(LPCTSTR)type].values.find("Name")!=ini.sections[(char*)(LPCTSTR)type].values.end()) + s+=ini.sections[(char*)(LPCTSTR)type].values["Name"]; + else + s+=rules.sections[(char*)(LPCTSTR)type].values["Name"]; +*/ + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + + ss="VehicleTypes"; + for(i=0;i<rules.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*rules.sections[ss].GetValue(i); + s=type; + s+=" ("; + /*if(ini.sections.find((char*)(LPCTSTR)type)!=ini.sections.end() && ini.sections[(char*)(LPCTSTR)type].values.find("Name")!=ini.sections[(char*)(LPCTSTR)type].values.end()) + s+=ini.sections[(char*)(LPCTSTR)type].values["Name"]; + else + s+=rules.sections[(char*)(LPCTSTR)type].values["Name"]; +*/ + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + for(i=0;i<ini.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*ini.sections[ss].GetValue(i); + s=type; + s+=" ("; + /*if(ini.sections.find((char*)(LPCTSTR)type)!=ini.sections.end() && ini.sections[(char*)(LPCTSTR)type].values.find("Name")!=ini.sections[(char*)(LPCTSTR)type].values.end()) + s+=ini.sections[(char*)(LPCTSTR)type].values["Name"]; + else + s+=rules.sections[(char*)(LPCTSTR)type].values["Name"]; +*/ + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + + ss="AircraftTypes"; + for(i=0;i<rules.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*rules.sections[ss].GetValue(i); + s=type; + s+=" ("; + /*if(ini.sections.find((char*)(LPCTSTR)type)!=ini.sections.end() && ini.sections[(char*)(LPCTSTR)type].values.find("Name")!=ini.sections[(char*)(LPCTSTR)type].values.end()) + s+=ini.sections[(char*)(LPCTSTR)type].values["Name"]; + else + s+=rules.sections[(char*)(LPCTSTR)type].values["Name"]; +*/ + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + for(i=0;i<ini.sections[ss].values.size();i++) + { + CString type; + CString s; + type=*ini.sections[ss].GetValue(i); + s=type; + s+=" ("; + /*if(ini.sections.find((char*)(LPCTSTR)type)!=ini.sections.end() && ini.sections[(char*)(LPCTSTR)type].values.find("Name")!=ini.sections[(char*)(LPCTSTR)type].values.end()) + s+=ini.sections[(char*)(LPCTSTR)type].values["Name"]; + else + s+=rules.sections[(char*)(LPCTSTR)type].values["Name"]; +*/ + s+=Map->GetUnitName((char*)(LPCTSTR)type); + + s+=")"; + m_UnitType.AddString(s); + } + + + if(sel<0) + { + if(m_TaskForces.SetCurSel(0)!=CB_ERR) + OnSelchangeTaskforces(); + } + else + { + if(m_TaskForces.SetCurSel(sel)!=CB_ERR) + OnSelchangeTaskforces(); + } + + + + + + if(!(sel2<0)) + { + if(m_Units.SetCurSel(sel2)!=LB_ERR) + OnSelchangeUnits(); + } + + +} + +void CTaskForce::OnEditchangeTaskforces() +{ + // TODO: Code fĂ¼r die Behandlungsroutine der Steuerelement-Benachrichtigung hier einfĂ¼gen + +} + +void CTaskForce::OnSelchangeTaskforces() +{ + CIniFile& ini=Map->GetIniFile(); + + CString tf; + tf=GetText(&m_TaskForces); + + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + m_Name=sec.values["Name"]; + m_Group=sec.values["Group"]; + + int i; + while(m_Units.DeleteString(0)!=LB_ERR); + for(i=0;i<sec.values.size()-2;i++) + { + char p[50]; + itoa(i, p, 10); + CString data=sec.values[p]; + CString type=GetParam(data, 1); + CString s=GetParam(data, 0); + s+=" "; + /*if(ini.sections.find((char*)(LPCTSTR)type)!=ini.sections.end() && ini.sections[(char*)(LPCTSTR)type].values.find("Name")!=ini.sections[(char*)(LPCTSTR)type].values.end()) + s+=ini.sections[(char*)(LPCTSTR)type].values["Name"]; + else + s+=rules.sections[(char*)(LPCTSTR)type].values["Name"];*/ + s+=Map->GetUnitName(type); + //s+=")"; + + m_Units.SetItemData(m_Units.AddString(s), i); + + + } + UpdateData(FALSE); + + if(m_Units.SetCurSel(0)!=LB_ERR) OnSelchangeUnits(); + + +} + +void CTaskForce::OnSelchangeUnits() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Units.GetCurSel(); + int u=m_Units.GetItemData(sel); + CString tf; + tf=GetText(&m_TaskForces); + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + + char k[50]; + itoa(u, k, 10); + CString data=sec.values[k]; + CString c=GetParam(data, 0); + + CString s; + CString type=GetParam(data,1); + /*if(ini.sections.find((char*)(LPCTSTR)type)!=ini.sections.end() && ini.sections[(char*)(LPCTSTR)type].values.find("Name")!=ini.sections[(char*)(LPCTSTR)type].values.end()) + s=ini.sections[(char*)(LPCTSTR)type].values["Name"]; + else + s=rules.sections[(char*)(LPCTSTR)type].values["Name"];*/ + s=Map->GetUnitName(type); + + m_UnitType.SetWindowText(((CString)(LPCTSTR)type + (CString)" (" + s + (CString)")")); + m_NumberOfUnits=atoi(c); + + UpdateData(FALSE); +} + +void CTaskForce::OnDeleteunit() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Units.GetCurSel(); + if(sel<0) return; + int u=m_Units.GetItemData(sel); + CString tf; + tf=GetText(&m_TaskForces); + + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + + char k[50]; + itoa(u, k, 10); + if(sec.values.size()<4) { + sec.values.erase(k); + m_Units.DeleteString(sel); + m_UnitType.SetWindowText(""); + m_NumberOfUnits=atoi("0"); + UpdateDialog(); + + return; + } + + int lastpos=sec.values.size()-3; + char l[50]; + itoa(lastpos, l, 10); + sec.values[k]=sec.values[l]; + sec.values.erase(l); + m_Units.DeleteString(sel); + + + UpdateDialog(); + return; +} + +void CTaskForce::OnChangeNumberunits() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + int sel=m_Units.GetCurSel(); + if(sel<0) return; + int u=m_Units.GetItemData(sel); + CString tf; + tf=GetText(&m_TaskForces); + + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + + char k[50], n[50];; + itoa(u, k, 10); + itoa(m_NumberOfUnits, n, 10); + CString data=sec.values[k]; + CString c=GetParam(data, 1); + sec.values[k]=n+(CString)","+c; + UpdateDialog(); +} + +void CTaskForce::OnChangeName() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + CEdit& n=*(CEdit*)GetDlgItem(IDC_NAME); + DWORD pos=n.GetSel(); + + if(m_TaskForces.GetCurSel()<0) return; + CString tf; + tf=GetText(&m_TaskForces); + + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + + sec.values["Name"]=m_Name; + + UpdateDialog(); + n.SetSel(pos); +} + +void CTaskForce::OnEditchangeUnittype() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Units.GetCurSel(); + if(sel<0) return; + int u=m_Units.GetItemData(sel); + CString tf; + tf=GetText(&m_TaskForces); + + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + + char k[50]; + itoa(u, k, 10); + + CString count=GetParam(sec.values[k],0); + CString type=GetText(&m_UnitType); + TruncSpace(type); + + sec.values[k]=count+","+(char*)(LPCTSTR)type; + + CString ut; + m_UnitType.GetWindowText(ut); + UpdateDialog(); + m_UnitType.SetWindowText(ut); + + +} + +void CTaskForce::OnSelchangeUnittype() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Units.GetCurSel(); + if(sel<0) return; + int u=m_Units.GetItemData(sel); + CString tf; + tf=GetText(&m_TaskForces); + + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + + char k[50]; + itoa(u, k, 10); + + CString count=GetParam(sec.values[k],0); + CString type=GetText(&m_UnitType); + + TruncSpace(type); + + sec.values[k]=count+","+(char*)(LPCTSTR)type; + + UpdateDialog(); + //m_UnitType.SetWindowText("H"); +} + +void CTaskForce::OnAddunit() +{ + CIniFile& ini=Map->GetIniFile(); + + CString tf; + if(m_TaskForces.GetCurSel()<0) return; + tf=GetText(&m_TaskForces); + + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + + char k[50]; + int c=m_Units.GetCount(); + if(c==LB_ERR) c=0; + itoa(c, k, 10); + + sec.values[k]="1"+(CString)","+*rules.sections["InfantryTypes"].GetValue(0); + + UpdateDialog(); +} + +void CTaskForce::OnDeletetaskforce() +{ + CIniFile& ini=Map->GetIniFile(); + + CString tf; + if(m_TaskForces.GetCurSel()<0) return; + tf=GetText(&m_TaskForces); + + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + + int res; + res=MessageBox("Are you sure to delete the selected task force? If you delete it, make sure to eliminate ANY references to this task force in team-types.","Delete task force",MB_YESNO); + if(res==IDNO) return; + + int v=ini.sections["TaskForces"].FindValue((char*)(LPCTSTR)tf); + if(v==-1) return; // SHOULD NEVER BE!!!! AND CANNOT BE!!! BUT MAYBE A BUG... + + ini.sections["TaskForces"].values.erase(*ini.sections["TaskForces"].GetValueName(v)); + ini.sections.erase((char*)(LPCTSTR)tf); + while(m_Units.DeleteString(0)!=LB_ERR); + //UpdateDialog(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); +} + +CString GetFree(const char* section); +void CTaskForce::OnAddtaskforce() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ID=GetFreeID(); + CString tf=GetFree("TaskForces"); + ini.sections["TaskForces"].values[tf]=ID; + + ini.sections[ID].values["Name"]="New task force"; + ini.sections[ID].values["Group"]="-1"; + + //UpdateDialog(); + + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); + + int i; + for(i=0;i<m_TaskForces.GetCount();i++) + { + CString tf2; + m_TaskForces.GetLBText(i,tf2); + + TruncSpace(tf2); + + if(strcmp(ID, tf2)==NULL) + { + m_TaskForces.SetCurSel(i); + OnSelchangeTaskforces(); // MW bugfix + break; + } + } + + +} + +void CTaskForce::OnChangeGroup() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + CString tf; + if(m_TaskForces.GetCurSel()<0) return; + tf=GetText(&m_TaskForces); + + TruncSpace(tf); + CIniFileSection & sec=ini.sections[(char*)(LPCTSTR)tf]; + + sec.values["Group"]=m_Group; + + UpdateDialog(); + +} diff --git a/MissionEditor/TaskForce.h b/MissionEditor/TaskForce.h new file mode 100644 index 0000000..e84716a --- /dev/null +++ b/MissionEditor/TaskForce.h @@ -0,0 +1,86 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TASKFORCE_H__58AF6EC0_92E3_11D3_B63B_85DE97E7FB41__INCLUDED_) +#define AFX_TASKFORCE_H__58AF6EC0_92E3_11D3_B63B_85DE97E7FB41__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TaskForce.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTaskForce + +class CTaskForce : public CDialog +{ + DECLARE_DYNCREATE(CTaskForce) + +// Konstruktion +public: + void UpdateDialog(); + CTaskForce(); + ~CTaskForce(); + +// Dialogfelddaten + //{{AFX_DATA(CTaskForce) + enum { IDD = IDD_TASKFORCES }; + CComboBox m_UnitType; + CListBox m_Units; + CComboBox m_TaskForces; + CString m_Group; + CString m_Name; + int m_NumberOfUnits; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTaskForce) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTaskForce) + afx_msg void OnEditchangeTaskforces(); + afx_msg void OnSelchangeTaskforces(); + afx_msg void OnSelchangeUnits(); + afx_msg void OnDeleteunit(); + afx_msg void OnChangeNumberunits(); + afx_msg void OnChangeName(); + afx_msg void OnEditchangeUnittype(); + afx_msg void OnSelchangeUnittype(); + afx_msg void OnAddunit(); + afx_msg void OnDeletetaskforce(); + afx_msg void OnAddtaskforce(); + afx_msg void OnChangeGroup(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TASKFORCE_H__58AF6EC0_92E3_11D3_B63B_85DE97E7FB41__INCLUDED_ diff --git a/MissionEditor/TeamTypes.cpp b/MissionEditor/TeamTypes.cpp new file mode 100644 index 0000000..4d9955f --- /dev/null +++ b/MissionEditor/TeamTypes.cpp @@ -0,0 +1,1288 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TeamTypes.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "TeamTypes.h" +#include "FinalSunDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CTeamTypes + +IMPLEMENT_DYNCREATE(CTeamTypes, CDialog) + +CTeamTypes::CTeamTypes() : CDialog(CTeamTypes::IDD) +{ + //{{AFX_DATA_INIT(CTeamTypes) + m_Aggressive = FALSE; + m_Annoyance = FALSE; + m_AreTeamMembersRecruitable = FALSE; + m_Autocreate = FALSE; + m_AvoidThreats = FALSE; + m_Droppod = FALSE; + m_Full = FALSE; + m_Group = _T(""); + m_GuardSlower = FALSE; + m_House = _T(""); + m_IonImmune = FALSE; + m_IsBaseDefense = FALSE; + m_Loadable = FALSE; + m_LooseRecruit = FALSE; + m_Max = _T(""); + m_Name = _T(""); + m_OnlyTargetHouseEnemy = FALSE; + m_OnTransOnly = FALSE; + m_Prebuild = FALSE; + m_Priority = _T(""); + m_Recruiter = FALSE; + m_Reinforce = FALSE; + m_Script = _T(""); + m_Suicide = FALSE; + m_TaskForce = _T(""); + m_TechLevel = _T(""); + m_TransportReturnsOnUnload = FALSE; + m_Waypoint = _T(""); + m_Whiner = FALSE; + m_VeteranLevel = _T(""); + m_Tag = _T(""); + m_TransportWaypoint = _T(""); + m_MindControlDecision = _T(""); + //}}AFX_DATA_INIT +} + +CTeamTypes::~CTeamTypes() +{ +} + +void CTeamTypes::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTeamTypes) + DDX_Control(pDX, IDC_MCD_L, m_MCD_L); + DDX_Control(pDX, IDC_TEAMTYPES, m_TeamTypes); + DDX_Check(pDX, IDC_AGGRESSIVE, m_Aggressive); + DDX_Check(pDX, IDC_ANNOYANCE, m_Annoyance); + DDX_Check(pDX, IDC_ARETEAMMEMBERSRECRUITABLE, m_AreTeamMembersRecruitable); + DDX_Check(pDX, IDC_AUTOCREATE, m_Autocreate); + DDX_Check(pDX, IDC_AVOIDTHREATS, m_AvoidThreats); + DDX_Check(pDX, IDC_DROPPOD, m_Droppod); + DDX_Check(pDX, IDC_FULL, m_Full); + DDX_CBString(pDX, IDC_GROUP, m_Group); + DDX_Check(pDX, IDC_GUARDSLOWER, m_GuardSlower); + DDX_CBString(pDX, IDC_HOUSE, m_House); + DDX_Check(pDX, IDC_IONIMMUNE, m_IonImmune); + DDX_Check(pDX, IDC_ISBASEDEFENSE, m_IsBaseDefense); + DDX_Check(pDX, IDC_LOADABLE, m_Loadable); + DDX_Check(pDX, IDC_LOOSERECRUIT, m_LooseRecruit); + DDX_Text(pDX, IDC_MAX, m_Max); + DDX_Text(pDX, IDC_NAME, m_Name); + DDX_Check(pDX, IDC_ONLYTARGETHOUSEENEMY, m_OnlyTargetHouseEnemy); + DDX_Check(pDX, IDC_ONTRANSONLY, m_OnTransOnly); + DDX_Check(pDX, IDC_PREBUILD, m_Prebuild); + DDX_Text(pDX, IDC_PRIORITY, m_Priority); + DDX_Check(pDX, IDC_RECRUITER, m_Recruiter); + DDX_Check(pDX, IDC_REINFORCE, m_Reinforce); + DDX_CBString(pDX, IDC_SCRIPT, m_Script); + DDX_Check(pDX, IDC_SUICIDE, m_Suicide); + DDX_CBString(pDX, IDC_TASKFORCE, m_TaskForce); + DDX_CBString(pDX, IDC_TECHLEVEL, m_TechLevel); + DDX_Check(pDX, IDC_TRANSPORTRETURNSONUNLOAD, m_TransportReturnsOnUnload); + DDX_CBString(pDX, IDC_WAYPOINT, m_Waypoint); + DDX_Check(pDX, IDC_WHINER, m_Whiner); + DDX_CBString(pDX, IDC_VETERANLEVEL, m_VeteranLevel); + DDX_CBString(pDX, IDC_TAG, m_Tag); + DDX_CBString(pDX, IDC_TRANSPORTWAYPOINT, m_TransportWaypoint); + DDX_CBString(pDX, IDC_MINDCONTROLDECISION, m_MindControlDecision); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTeamTypes, CDialog) + //{{AFX_MSG_MAP(CTeamTypes) + ON_CBN_SELCHANGE(IDC_TEAMTYPES, OnSelchangeTeamtypes) + ON_EN_CHANGE(IDC_NAME, OnChangeName) + ON_BN_CLICKED(IDC_DELETETEAMTYPE, OnDeleteteamtype) + ON_CBN_EDITCHANGE(IDC_VETERANLEVEL, OnEditchangeVeteranlevel) + ON_CBN_EDITCHANGE(IDC_HOUSE, OnEditchangeHouse) + ON_EN_CHANGE(IDC_PRIORITY, OnChangePriority) + ON_EN_CHANGE(IDC_MAX, OnChangeMax) + ON_CBN_EDITCHANGE(IDC_TECHLEVEL, OnEditchangeTechlevel) + ON_CBN_EDITCHANGE(IDC_GROUP, OnEditchangeGroup) + ON_CBN_EDITCHANGE(IDC_WAYPOINT, OnEditchangeWaypoint) + ON_CBN_EDITCHANGE(IDC_SCRIPT, OnEditchangeScript) + ON_CBN_EDITCHANGE(IDC_TASKFORCE, OnEditchangeTaskforce) + ON_CBN_KILLFOCUS(IDC_VETERANLEVEL, OnKillfocusVeteranlevel) + ON_CBN_KILLFOCUS(IDC_HOUSE, OnKillfocusHouse) + ON_CBN_KILLFOCUS(IDC_TECHLEVEL, OnKillfocusTechlevel) + ON_CBN_KILLFOCUS(IDC_GROUP, OnKillfocusGroup) + ON_CBN_KILLFOCUS(IDC_WAYPOINT, OnKillfocusWaypoint) + ON_CBN_KILLFOCUS(IDC_SCRIPT, OnKillfocusScript) + ON_CBN_KILLFOCUS(IDC_TASKFORCE, OnKillfocusTaskforce) + ON_WM_SHOWWINDOW() + ON_BN_CLICKED(IDC_LOADABLE, OnLoadable) + ON_BN_CLICKED(IDC_FULL, OnFull) + ON_BN_CLICKED(IDC_ANNOYANCE, OnAnnoyance) + ON_BN_CLICKED(IDC_GUARDSLOWER, OnGuardslower) + ON_BN_CLICKED(IDC_RECRUITER, OnRecruiter) + ON_BN_CLICKED(IDC_DROPPOD, OnDroppod) + ON_BN_CLICKED(IDC_WHINER, OnWhiner) + ON_BN_CLICKED(IDC_LOOSERECRUIT, OnLooserecruit) + ON_BN_CLICKED(IDC_AGGRESSIVE, OnAggressive) + ON_BN_CLICKED(IDC_SUICIDE, OnSuicide) + ON_BN_CLICKED(IDC_AUTOCREATE, OnAutocreate) + ON_BN_CLICKED(IDC_PREBUILD, OnPrebuild) + ON_BN_CLICKED(IDC_ONTRANSONLY, OnOntransonly) + ON_BN_CLICKED(IDC_REINFORCE, OnReinforce) + ON_BN_CLICKED(IDC_AVOIDTHREATS, OnAvoidthreats) + ON_BN_CLICKED(IDC_IONIMMUNE, OnIonimmune) + ON_BN_CLICKED(IDC_TRANSPORTRETURNSONUNLOAD, OnTransportreturnsonunload) + ON_BN_CLICKED(IDC_ARETEAMMEMBERSRECRUITABLE, OnAreteammembersrecruitable) + ON_BN_CLICKED(IDC_ISBASEDEFENSE, OnIsbasedefense) + ON_BN_CLICKED(IDC_ONLYTARGETHOUSEENEMY, OnOnlytargethouseenemy) + ON_BN_CLICKED(IDC_NEWTEAMTYPE, OnNewteamtype) + ON_CBN_EDITCHANGE(IDC_TAG, OnEditchangeTag) + ON_CBN_KILLFOCUS(IDC_TAG, OnKillfocusTag) + ON_CBN_EDITCHANGE(IDC_TRANSPORTWAYPOINT, OnEditchangeTransportwaypoint) + ON_CBN_KILLFOCUS(IDC_TRANSPORTWAYPOINT, OnKillfocusTransportwaypoint) + ON_CBN_EDITCHANGE(IDC_MINDCONTROLDECISION, OnEditchangeMindcontroldecision) + ON_CBN_KILLFOCUS(IDC_MINDCONTROLDECISION, OnKillfocusMindcontroldecision) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +BOOL stob(const char* s) +{ + if(_stricmp(s,"no")==NULL) + { + return FALSE; + } + return TRUE; +} + +CString btos(BOOL b) +{ + CString s="no"; + if(b==TRUE) s="yes"; + return s; +} + +int letter2number(char let){ + int reply=let-'A'; + /*if(let=='A')reply=0; + if(let=='B')reply=1; + if(let=='C')reply=2; + if(let=='D')reply=3; + if(let=='E')reply=4; + if(let=='F')reply=5; + if(let=='G')reply=6; + if(let=='H')reply=7; + if(let=='I')reply=8; + if(let=='J')reply=9; + if(let=='K')reply=10; + if(let=='L')reply=11; + if(let=='M')reply=12; + if(let=='N')reply=13; + if(let=='O')reply=14; + if(let=='P')reply=15; + if(let=='Q')reply=16; + if(let=='R')reply=17; + if(let=='S')reply=18; + if(let=='T')reply=19; + if(let=='U')reply=20; + if(let=='V')reply=21; + if(let=='W')reply=22; + if(let=='X')reply=23; + if(let=='Y')reply=24; + if(let=='Z')reply=25;*/ + return reply; + +} + +char number2letter(int let){ + int reply=let+'A'; + /*if(let==0)reply='A'; + if(let==1)reply='B'; + if(let==2)reply='C'; + if(let==3)reply='D'; + if(let==4)reply='E'; + if(let==5)reply='F'; + if(let==6)reply='G'; + if(let==7)reply='H'; + if(let==8)reply='I'; + if(let==9)reply='J'; + if(let==10)reply='K'; + if(let==11)reply='L'; + if(let==12)reply='M'; + if(let==13)reply='N'; + if(let==14)reply='O'; + if(let==15)reply='P'; + if(let==16)reply='Q'; + if(let==17)reply='R'; + if(let==18)reply='S'; + if(let==19)reply='T'; + if(let==20)reply='U'; + if(let==21)reply='V'; + if(let==22)reply='W'; + if(let==23)reply='X'; + if(let==24)reply='Y'; + if(let==25)reply='Z';*/ + + return reply; + +} + +int GetWaypoint(const char* c) +{ + if(strlen(c)==0) return -1; + int i; + int res=0; + for(i=0;i<strlen(c);i++) + { + int addval=letter2number(c[i]); + res+=addval+(res+1)*(i*25)+i; + } + return res; +} + +CString GetWaypoint(int n) +{ + if(n==-1) return (CString)(""); + int i,e; + for(i=-1;i<26;i++) + { + for(e=0;e<26;e++) + { + char c[50]; + CString p; + if(i==-1) + { + c[0]=number2letter(e); + c[1]=0; + if(GetWaypoint(c)==n) return c; + } + else + { + c[0]=number2letter(i); + c[1]=number2letter(e); + c[2]=0; + if(GetWaypoint(c)==n) return c; + } + + } + } + return (CString)(""); +} + + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTeamTypes +void CTeamTypes::UpdateDialog() +{ + if(!yuri_mode) + { + GetDlgItem(IDC_MINDCONTROLDECISION)->ShowWindow(SW_HIDE); + m_MCD_L.ShowWindow(SW_HIDE); + } + + CIniFile& ini=Map->GetIniFile(); + + CComboBox& taskforces=*(CComboBox*)GetDlgItem(IDC_TASKFORCE); + CComboBox& scripts=*(CComboBox*)GetDlgItem(IDC_SCRIPT); + CComboBox& houses=*(CComboBox*)GetDlgItem(IDC_HOUSE); + + int sel=m_TeamTypes.GetCurSel(); + + while(m_TeamTypes.DeleteString(0)!=CB_ERR); + while(taskforces.DeleteString(0)!=CB_ERR); + while(scripts.DeleteString(0)!=CB_ERR); + + // MW 07/24/01: Clear: + m_Aggressive=0; + m_Annoyance=0; + m_AreTeamMembersRecruitable=0; + m_Autocreate=0; + m_AvoidThreats=0; + m_Droppod=0; + m_Full=0; + m_Group=""; + m_GuardSlower=0; + m_House=""; + m_IonImmune=0; + m_IsBaseDefense=0; + m_Loadable=0; + m_LooseRecruit=0; + m_Max=""; + m_Name=""; + m_OnlyTargetHouseEnemy=0; + m_OnTransOnly=0; + m_Prebuild=0; + m_Priority=""; + m_Recruiter=0; + m_Reinforce=0; + m_Script=""; + m_Suicide=0; + m_Tag=""; + m_TaskForce=""; + m_TechLevel=""; + m_TransportReturnsOnUnload=0; + m_TransportWaypoint=""; + m_VeteranLevel=""; + m_MindControlDecision=""; + + UpdateData(FALSE); + + int i; + for(i=0;i<ini.sections["TeamTypes"].values.size();i++) + { + CString tt; + tt=*ini.sections["TeamTypes"].GetValue(i); + + CString str; + str=tt; + str+=" ("; + str+=ini.sections[tt].values["Name"]; + str+=")"; + + m_TeamTypes.AddString(str); + } + + for(i=0;i<ini.sections["TaskForces"].values.size();i++) + { + + CString tt; + tt=*ini.sections["TaskForces"].GetValue(i); + + CString str; + str=tt; + str+=" ("; + if(ini.sections.find(tt)!=ini.sections.end()) + { + str+=ini.sections[tt].values["Name"]; + } + str+=")"; + + taskforces.AddString(str); + } + + for(i=0;i<ini.sections["ScriptTypes"].values.size();i++) + { + + CString tt; + tt=*ini.sections["ScriptTypes"].GetValue(i); + + CString str; + str=tt; + str+=" ("; + if(ini.sections.find((char*)(LPCTSTR)tt)!=ini.sections.end()) + { + str+=ini.sections[(char*)(LPCTSTR)tt].values["Name"]; + } + str+=")"; + + scripts.AddString(str); + } + + + // now list all tags, but not "None", because we want the correct language, + // and ListTags uses (for compatibility) always the english one + ListTags(*(CComboBox*)GetDlgItem(IDC_TAG), FALSE); + (*(CComboBox*)GetDlgItem(IDC_TAG)).InsertString(0, GetLanguageStringACP("None")); + + + CComboBox* house; + house=(CComboBox*)GetDlgItem(IDC_HOUSE); + + /*while(house->DeleteString(0)!=CB_ERR); + // houses: rules.ini + map definitions! + if(ini.sections.find("Houses")!=ini.sections.end()) + { + if(ini.sections["Houses"].values.size()==0) goto wasnohouse; + // we use the map definitions! + for(i=0;i<ini.sections["Houses"].values.size();i++) + { + house->AddString(*ini.sections["Houses"].GetValue(i)); + } + } + else + { + wasnohouse: + for(i=0;i<rules.sections["Houses"].values.size();i++) + { + house->AddString(*rules.sections["Houses"].GetValue(i)); + } + }*/ + ListHouses(*house, FALSE, TRUE, TRUE); + + CComboBox* wayp; + wayp=(CComboBox*)GetDlgItem(IDC_WAYPOINT); + + while(wayp->DeleteString(0)!=CB_ERR); + // houses: rules.ini + map definitions! + if(ini.sections.find("Waypoints")!=ini.sections.end()) + { + for(i=0;i<ini.sections["Waypoints"].values.size();i++) + { + wayp->AddString(*ini.sections["Waypoints"].GetValueName(i)); + } + } + + wayp=(CComboBox*)GetDlgItem(IDC_TRANSPORTWAYPOINT); + + while(wayp->DeleteString(0)!=CB_ERR); + // houses: rules.ini + map definitions! + wayp->SetItemData(wayp->InsertString(0,TranslateStringACP("None")),0); + + if(ini.sections.find("Waypoints")!=ini.sections.end()) + { + for(i=0;i<ini.sections["Waypoints"].values.size();i++) + { + wayp->SetItemData(wayp->AddString(*ini.sections["Waypoints"].GetValueName(i)),1); + } + } + +#ifdef TS_MODE + wayp->ShowWindow(SW_HIDE); +#endif + + m_TeamTypes.SetCurSel(0); + if(sel>=0) m_TeamTypes.SetCurSel(sel); + OnSelchangeTeamtypes(); + + +} + +void CTeamTypes::OnSelchangeTeamtypes() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_TeamTypes.GetCurSel()<0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + m_Aggressive=stob(sec.values["Aggressive"]); + m_Annoyance=stob(sec.values["Annoyance"]); + m_AreTeamMembersRecruitable=stob(sec.values["AreTeamMembersRecruitable"]); + m_Autocreate=stob(sec.values["Autocreate"]); + m_AvoidThreats=stob(sec.values["AvoidThreats"]); + m_Droppod=stob(sec.values["Droppod"]); + m_Full=stob(sec.values["Full"]); + m_Group=sec.values["Group"]; + m_GuardSlower=stob(sec.values["GuardSlower"]); + m_House=TranslateHouse(sec.values["House"], TRUE); + m_IonImmune=stob(sec.values["IonImmune"]); + m_IsBaseDefense=stob(sec.values["IsBaseDefense"]); + m_Loadable=stob(sec.values["Loadable"]); + m_LooseRecruit=stob(sec.values["LooseRecruit"]); + m_Max=sec.values["Max"]; + m_Name=sec.values["Name"]; + m_OnlyTargetHouseEnemy=stob(sec.values["OnlyTargetHouseEnemy"]); + m_OnTransOnly=stob(sec.values["OnTransOnly"]); + m_Prebuild=stob(sec.values["Prebuild"]); + m_Priority=sec.values["Priority"]; + m_Recruiter=stob(sec.values["Recruiter"]); + m_Reinforce=stob(sec.values["Reinforce"]); + m_Script=(sec.values["Script"]); + if(ini.sections.find(sec.values["Script"])!=ini.sections.end()) + m_Script+=(" ("+ini.sections[sec.values["Script"]].values["Name"]+")"); + m_Suicide=stob(sec.values["Suicide"]); + if(sec.values.find("Tag")!=sec.values.end()) + { + m_Tag=sec.values["Tag"]; + if(ini.sections["Tags"].values.find((LPCTSTR)m_Tag)!=ini.sections["Tags"].values.end()) + { + CString tag=m_Tag; + m_Tag+=" "; + m_Tag+=GetParam(ini.sections["Tags"].values[(LPCTSTR)tag], 1); + } + } + else + { + m_Tag=GetLanguageStringACP("None"); + } + m_TaskForce=(sec.values["TaskForce"]); + if(ini.sections.find(sec.values["TaskForce"])!=ini.sections.end()) + m_TaskForce+=(" ("+ini.sections[sec.values["TaskForce"]].values["Name"]+")"); + m_TechLevel=sec.values["TechLevel"]; + m_TransportReturnsOnUnload=stob(sec.values["TransportsReturnOnUnload"]); + m_VeteranLevel=sec.values["VeteranLevel"]; + + if(yuri_mode) + m_MindControlDecision=sec.values["MindControlDecision"]; + + + int w=GetWaypoint(sec.values["Waypoint"]); + char c[50]; + itoa(w,c,10); + if(w!=-1) + m_Waypoint=c; + else + m_Waypoint=""; + +#ifdef RA2_MODE + if(isTrue(sec.values["UseTransportOrigin"])) + { + int w=GetWaypoint(sec.values["TransportWaypoint"]); + char c[50]; + itoa(w,c,10); + if(w!=-1) + m_TransportWaypoint=c; + else + m_TransportWaypoint=""; + + } + else + m_TransportWaypoint=TranslateStringACP("None"); +#endif + + m_Whiner=stob(sec.values["Whiner"]); + + UpdateData(FALSE); +} + +void CTeamTypes::OnChangeName() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CEdit& n=*(CEdit*)GetDlgItem(IDC_NAME); + DWORD pos=n.GetSel(); + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Name"]=m_Name; + + UpdateDialog(); + + n.SetSel(pos); +} + +void CTeamTypes::OnDeleteteamtype() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_TeamTypes.GetCurSel()!=-1) + { + int res=MessageBox("Are you sure that you want to delete the selected team-type? If you delete it, don´t forget to delete any reference to the team-type.","Delete team-type",MB_YESNO); + if(res==IDNO) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + + int i; + CIniFile& ini=Map->GetIniFile(); + for(i=0;i<ini.sections["TeamTypes"].values.size();i++) + { + if(strcmp(str, *ini.sections["TeamTypes"].GetValue(i))==NULL) + { + ini.sections["TeamTypes"].values.erase(*ini.sections["TeamTypes"].GetValueName(i)); + } + } + ini.sections.erase((char*)(LPCTSTR)str); + } + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); + //UpdateDialog(); +} + +void CTeamTypes::OnEditchangeVeteranlevel() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["VeteranLevel"]=m_VeteranLevel; +} + +void CTeamTypes::OnEditchangeHouse() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["House"]=TranslateHouse(m_House); +} + +void CTeamTypes::OnChangePriority() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Priority"]=m_Priority; +} + +void CTeamTypes::OnChangeMax() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Max"]=m_Max; +} + +void CTeamTypes::OnEditchangeTechlevel() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["TechLevel"]=m_TechLevel; +} + +void CTeamTypes::OnEditchangeGroup() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + //MessageBox(str); + + sec.values["Group"]=m_Group; +} + +void CTeamTypes::OnEditchangeWaypoint() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + if(strlen(m_Waypoint)==0) sec.values["Waypoint"]=""; + else + sec.values["Waypoint"]=GetWaypoint(atoi(m_Waypoint)); +} + +void CTeamTypes::OnEditchangeScript() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + CString tmp=m_Script; + TruncSpace(tmp); + sec.values["Script"]=tmp; + +} + +void CTeamTypes::OnEditchangeTaskforce() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + CString tmp=m_TaskForce; + TruncSpace(tmp); + sec.values["TaskForce"]=tmp; +} + + + +void CTeamTypes::OnKillfocusVeteranlevel() +{ + OnEditchangeVeteranlevel(); +} + +void CTeamTypes::OnKillfocusHouse() +{ + OnEditchangeHouse(); +} + +void CTeamTypes::OnKillfocusTechlevel() +{ + OnEditchangeTechlevel(); +} + +void CTeamTypes::OnKillfocusGroup() +{ + OnEditchangeGroup(); +} + +void CTeamTypes::OnKillfocusWaypoint() +{ + OnEditchangeWaypoint(); +} + +void CTeamTypes::OnKillfocusScript() +{ + OnEditchangeScript(); +} + +void CTeamTypes::OnKillfocusTaskforce() +{ + OnEditchangeTaskforce(); +} + +void CTeamTypes::OnShowWindow(BOOL bShow, UINT nStatus) +{ + CDialog::OnShowWindow(bShow, nStatus); + + if(!bShow) + { + OnKillfocusGroup(); + OnKillfocusHouse(); + OnKillfocusScript(); + OnKillfocusTaskforce(); + OnKillfocusTechlevel(); + OnKillfocusVeteranlevel(); + OnKillfocusWaypoint(); + OnKillfocusTag(); +#ifdef RA2_MODE + OnKillfocusTransportwaypoint(); + if(yuri_mode) OnKillfocusMindcontroldecision(); +#endif + } +} + + + +void CTeamTypes::OnLoadable() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Loadable"]=btos(m_Loadable); +} + +void CTeamTypes::OnFull() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Full"]=btos(m_Full); +} + +void CTeamTypes::OnAnnoyance() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Annoyance"]=btos(m_Annoyance); +} + +void CTeamTypes::OnGuardslower() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["GuardSlower"]=btos(m_GuardSlower); +} + +void CTeamTypes::OnRecruiter() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Recruiter"]=btos(m_Recruiter); +} + +void CTeamTypes::OnDroppod() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Droppod"]=btos(m_Droppod); +} + +void CTeamTypes::OnWhiner() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Whiner"]=btos(m_Whiner); +} + +void CTeamTypes::OnLooserecruit() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["LooseRecruit"]=btos(m_LooseRecruit); +} + +void CTeamTypes::OnAggressive() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Aggressive"]=btos(m_Aggressive); +} + +void CTeamTypes::OnSuicide() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Suicide"]=btos(m_Suicide); +} + +void CTeamTypes::OnAutocreate() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Autocreate"]=btos(m_Autocreate); +} + +void CTeamTypes::OnPrebuild() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Prebuild"]=btos(m_Prebuild); +} + +void CTeamTypes::OnOntransonly() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["OnTransOnly"]=btos(m_OnTransOnly); +} + +void CTeamTypes::OnReinforce() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["Reinforce"]=btos(m_Reinforce); +} + +void CTeamTypes::OnAvoidthreats() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["AvoidThreats"]=btos(m_AvoidThreats); +} + +void CTeamTypes::OnIonimmune() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["IonImmune"]=btos(m_IonImmune); +} + +void CTeamTypes::OnTransportreturnsonunload() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["TransportsReturnOnUnload"]=btos(m_TransportReturnsOnUnload); +} + +void CTeamTypes::OnAreteammembersrecruitable() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["AreTeamMembersRecruitable"]=btos(m_AreTeamMembersRecruitable); +} + +void CTeamTypes::OnIsbasedefense() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["IsBaseDefense"]=btos(m_IsBaseDefense); +} + +void CTeamTypes::OnOnlytargethouseenemy() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + sec.values["OnlyTargetHouseEnemy"]=btos(m_OnlyTargetHouseEnemy); +} + +CString GetFree(const char* section); + +void CTeamTypes::OnNewteamtype() +{ + CIniFile& ini=Map->GetIniFile(); + + CString id=GetFreeID() ; + CString p; + p=GetFree("TeamTypes"); + + + ini.sections["TeamTypes"].values[p]=id; + CIniFileSection& s=ini.sections[id]; + s.values["Name"]="New teamtype"; + s.values["VeteranLevel"]="1"; + s.values["Loadable"]="no"; + s.values["Full"]="yes"; + s.values["Annoyance"]="no"; + s.values["GuardSlower"]="no"; + s.values["Recruiter"]="no"; + s.values["Autocreate"]="yes"; + s.values["Prebuild"]="no"; + s.values["Reinforce"]="no"; + s.values["Droppod"]="no"; + s.values["Whiner"]="no"; + s.values["LooseRecruit"]="no"; + s.values["Aggressive"]="no"; + s.values["Suicide"]="no"; + s.values["Priority"]="5"; + s.values["Max"]="5"; + s.values["TechLevel"]="0"; + s.values["Group"]="-1"; + s.values["OnTransOnly"]="no"; + s.values["AvoidThreats"]="no"; + s.values["IonImmune"]="no"; + s.values["TransportsReturnOnUnload"]="no"; + s.values["AreTeamMembersRecruitable"]="no"; + s.values["IsBaseDefense"]="no"; + s.values["OnlyTargetHouseEnemy"]="no"; + +#ifdef RA2_MODE + s.values["UseTransportOrigin"]="no"; + if(yuri_mode) s.values["MindControlDecision"]="0"; + +#endif + + + //UpdateDialog(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); + + int i; + for(i=0;i<m_TeamTypes.GetCount();i++) + { + CString k; + m_TeamTypes.GetLBText(i, k); + TruncSpace(k); + if(strcmp(k, id)==NULL) + { + m_TeamTypes.SetCurSel(i); + OnSelchangeTeamtypes(); + } + } + + CComboBox& houses=*(CComboBox*)GetDlgItem(IDC_HOUSE); + houses.SetCurSel(0); + OnEditchangeHouse(); + CComboBox& waypoints=*(CComboBox*)GetDlgItem(IDC_WAYPOINT); + waypoints.SetCurSel(0); + CComboBox& script=*(CComboBox*)GetDlgItem(IDC_SCRIPT); + script.SetCurSel(0); + CComboBox& taskforce=*(CComboBox*)GetDlgItem(IDC_TASKFORCE); + taskforce.SetCurSel(0); + OnKillfocusHouse(); + OnKillfocusWaypoint(); + OnKillfocusScript(); + OnKillfocusTaskforce(); +} + +void CTeamTypes::OnEditchangeTag() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + TruncSpace(m_Tag); + + sec.values["Tag"]=m_Tag; + if(m_Tag==GetLanguageStringACP("None") || m_Tag.GetLength()==0) + { + sec.values.erase("Tag"); + } +} + +void CTeamTypes::OnKillfocusTag() +{ + OnEditchangeTag(); +} + +void CTeamTypes::OnEditchangeTransportwaypoint() +{ +#ifndef RA2_MODE + return; +#endif + + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + if(strlen(m_TransportWaypoint)==0 || isSame(m_TransportWaypoint, TranslateStringACP("None"))) + { + sec.values.erase("TransportWaypoint"); + sec.values["UseTransportOrigin"]="no"; + } + else + { + sec.values["TransportWaypoint"]=GetWaypoint(atoi(m_TransportWaypoint)); + sec.values["UseTransportOrigin"]="yes"; + } + +} + +void CTeamTypes::OnKillfocusTransportwaypoint() +{ + OnEditchangeTransportwaypoint(); +} + +void CTeamTypes::OnEditchangeMindcontroldecision() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(TRUE); + if(m_TeamTypes.GetCount()==0) return; + + CString str; + str=GetText(&m_TeamTypes); + TruncSpace(str); + CIniFileSection& sec=ini.sections[(char*)(LPCTSTR)str]; + + CString tmp=m_MindControlDecision; + TruncSpace(tmp); + sec.values["MindControlDecision"]=tmp; +} + +void CTeamTypes::OnKillfocusMindcontroldecision() +{ + OnEditchangeMindcontroldecision(); +} diff --git a/MissionEditor/TeamTypes.h b/MissionEditor/TeamTypes.h new file mode 100644 index 0000000..f697372 --- /dev/null +++ b/MissionEditor/TeamTypes.h @@ -0,0 +1,154 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +//{{AFX_INCLUDES() + +//}}AFX_INCLUDES +#if !defined(AFX_TEAMTYPES_H__EE440E20_929B_11D3_B63B_F2ECCFA7A541__INCLUDED_) +#define AFX_TEAMTYPES_H__EE440E20_929B_11D3_B63B_F2ECCFA7A541__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TeamTypes.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTeamTypes + + +class CTeamTypes : public CDialog +{ + DECLARE_DYNCREATE(CTeamTypes) + +// Konstruktion +public: + void UpdateDialog(); + CTeamTypes(); + ~CTeamTypes(); + +// Dialogfelddaten + //{{AFX_DATA(CTeamTypes) + enum { IDD = IDD_TEAMTYPES }; + CStatic m_MCD_L; + CComboBox m_TeamTypes; + BOOL m_Aggressive; + BOOL m_Annoyance; + BOOL m_AreTeamMembersRecruitable; + BOOL m_Autocreate; + BOOL m_AvoidThreats; + BOOL m_Droppod; + BOOL m_Full; + CString m_Group; + BOOL m_GuardSlower; + CString m_House; + BOOL m_IonImmune; + BOOL m_IsBaseDefense; + BOOL m_Loadable; + BOOL m_LooseRecruit; + CString m_Max; + CString m_Name; + BOOL m_OnlyTargetHouseEnemy; + BOOL m_OnTransOnly; + BOOL m_Prebuild; + CString m_Priority; + BOOL m_Recruiter; + BOOL m_Reinforce; + CString m_Script; + BOOL m_Suicide; + CString m_TaskForce; + CString m_TechLevel; + BOOL m_TransportReturnsOnUnload; + CString m_Waypoint; + BOOL m_Whiner; + CString m_VeteranLevel; + CString m_Tag; + CString m_TransportWaypoint; + CString m_MindControlDecision; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTeamTypes) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTeamTypes) + afx_msg void OnSelchangeTeamtypes(); + afx_msg void OnChangeName(); + afx_msg void OnDeleteteamtype(); + afx_msg void OnEditchangeVeteranlevel(); + afx_msg void OnEditchangeHouse(); + afx_msg void OnChangePriority(); + afx_msg void OnChangeMax(); + afx_msg void OnEditchangeTechlevel(); + afx_msg void OnEditchangeGroup(); + afx_msg void OnEditchangeWaypoint(); + afx_msg void OnEditchangeScript(); + afx_msg void OnEditchangeTaskforce(); + afx_msg void OnKillfocusVeteranlevel(); + afx_msg void OnKillfocusHouse(); + afx_msg void OnKillfocusTechlevel(); + afx_msg void OnKillfocusGroup(); + afx_msg void OnKillfocusWaypoint(); + afx_msg void OnKillfocusScript(); + afx_msg void OnKillfocusTaskforce(); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + afx_msg void OnLoadable(); + afx_msg void OnFull(); + afx_msg void OnAnnoyance(); + afx_msg void OnGuardslower(); + afx_msg void OnRecruiter(); + afx_msg void OnDroppod(); + afx_msg void OnWhiner(); + afx_msg void OnLooserecruit(); + afx_msg void OnAggressive(); + afx_msg void OnSuicide(); + afx_msg void OnAutocreate(); + afx_msg void OnPrebuild(); + afx_msg void OnOntransonly(); + afx_msg void OnReinforce(); + afx_msg void OnAvoidthreats(); + afx_msg void OnIonimmune(); + afx_msg void OnTransportreturnsonunload(); + afx_msg void OnAreteammembersrecruitable(); + afx_msg void OnIsbasedefense(); + afx_msg void OnOnlytargethouseenemy(); + afx_msg void OnNewteamtype(); + afx_msg void OnEditchangeTag(); + afx_msg void OnKillfocusTag(); + afx_msg void OnEditchangeTransportwaypoint(); + afx_msg void OnKillfocusTransportwaypoint(); + afx_msg void OnEditchangeMindcontroldecision(); + afx_msg void OnKillfocusMindcontroldecision(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TEAMTYPES_H__EE440E20_929B_11D3_B63B_F2ECCFA7A541__INCLUDED_ diff --git a/MissionEditor/TerrainDlg.cpp b/MissionEditor/TerrainDlg.cpp new file mode 100644 index 0000000..8e557f1 --- /dev/null +++ b/MissionEditor/TerrainDlg.cpp @@ -0,0 +1,275 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TerrainDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "TerrainDlg.h" +#include "TileSetBrowserFrame.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" +#include <string> + +extern ACTIONDATA AD; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTerrainDlg + + +CTerrainDlg::CTerrainDlg(CWnd* pParent /*=NULL*/) + : CDialogBar() +{ + //{{AFX_DATA_INIT(CTerrainDlg) + //}}AFX_DATA_INIT +} + + +void CTerrainDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialogBar::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTerrainDlg) + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTerrainDlg, CDialogBar) + //{{AFX_MSG_MAP(CTerrainDlg) + ON_CBN_SELCHANGE(IDC_TILESET, OnSelchangeTileset) + ON_CBN_SELCHANGE(IDC_OVERLAY, OnSelchangeOverlay) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTerrainDlg + +void CTerrainDlg::OnOK() +{ + // stub +} + +void CTerrainDlg::OnCancel() +{ + DestroyWindow(); +} + +BOOL CTerrainDlg::OnInitDialog() +{ + //CDialogBar::OnInitDialog(); + + return FALSE; +} + +void CTerrainDlg::PostNcDestroy() +{ + //delete this; + //CDialog::PostNcDestroy(); +} + +void CTerrainDlg::OnSelchangeTileset() +{ + //while(m_Type.DeleteString(0)!=CB_ERR); + + CString currentTileSet; + CComboBox* TileSet; + TileSet = (CComboBox*)GetDlgItem(IDC_TILESET); + TileSet->GetLBText(TileSet->GetCurSel(), currentTileSet); + + TruncSpace(currentTileSet); + + ((CTileSetBrowserFrame*)GetParentFrame())->m_view.SetTileSet(atoi(currentTileSet)); +} + + + +BOOL CTerrainDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) +{ + + return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext); + + +} + +// needed to find out if pic exists +extern PICDATA* ovrlpics[0xFF][max_ovrl_img]; + +void CTerrainDlg::Update() +{ + CComboBox* TileSet; + TileSet = (CComboBox*)GetDlgItem(IDC_TILESET); + + while (TileSet->DeleteString(0) != CB_ERR); + + if (tiles) + { + int i; + int tilecount = 0; + for (i = 0;i < 10000;i++) + { + CString tset; + char c[50]; + itoa(i, c, 10); + int e; + for (e = 0;e < 4 - strlen(c);e++) + tset += "0"; + tset += c; + CString sec = "TileSet"; + sec += tset; + + if (tiles->sections.find(sec) == tiles->sections.end()) + break; + if (atoi(tiles->sections[sec].values["TilesInSet"]) == 0) + continue; + + CString string; + string = tset; + string += " ("; + string += TranslateStringACP(tiles->sections[sec].values["SetName"]); + string += ")"; + + BOOL bForced = FALSE; + BOOL bForcedNot = FALSE; + + + // force yes + CString datsec = (CString)"UseSet" + Map->GetTheater(); + auto tsetc = CString(std::to_string(atoi(tset)).c_str()); + + if (g_data.sections[datsec].FindValue(tsetc) >= 0) + bForced = TRUE; + + // force no + datsec = (CString)"IgnoreSet" + Map->GetTheater(); + if (g_data.sections[datsec].FindValue(tsetc) >= 0) + bForcedNot = TRUE; + + + if (bForced || (!bForcedNot && (*tiledata)[tilecount].bAllowToPlace && !(*tiledata)[tilecount].bMarbleMadness)) + TileSet->SetItemData(TileSet->AddString(string), i); + + tilecount += atoi(tiles->sections[sec].values["TilesInSet"]); + } + + TileSet->SetCurSel(0); + OnSelchangeTileset(); + } + + CComboBox* Overlays; + Overlays = (CComboBox*)GetDlgItem(IDC_OVERLAY); + + while (Overlays->DeleteString(0) != CB_ERR); + + int i; + + int e = 0; + for (i = 0;i < rules.sections["OverlayTypes"].values.size();i++) + { + CString id = *rules.sections["OverlayTypes"].GetValue(i); + id.TrimLeft(); + id.TrimRight(); + + if (id.GetLength() > 0) + { + + if (rules.sections.find(id) != rules.sections.end() && rules.sections[id].FindName("Name") >= 0) + { + int p; + BOOL bListIt = TRUE; + for (p = 0;p < max_ovrl_img;p++) + if (ovrlpics[i][p] != NULL && ovrlpics[i][p]->pic != NULL) + bListIt = TRUE; + +#ifdef RA2_MODE + if ((i >= 39 && i <= 60) || (i >= 180 && i <= 201) || i == 239 || i == 178 || i == 167 || i == 126 + || (i >= 122 && i <= 125)) + bListIt = FALSE; +#endif + + if (bListIt) + { + CString str; + str = TranslateStringACP(rules.sections[(*rules.sections["OverlayTypes"].GetValue(i))].values["Name"]); + Overlays->SetItemData(Overlays->AddString(str), e); + } + } + e++; + } + } +} + + +DWORD CTerrainDlg::GetTileID(DWORD dwTileSet, int iTile) +{ + int i, e; + DWORD tilecount = 0; + for (i = 0;i < 10000;i++) + { + CString tset; + char c[50]; + itoa(i, c, 10); + int e; + for (e = 0;e < 4 - strlen(c);e++) + tset += "0"; + tset += c; + CString sec = "TileSet"; + sec += tset; + + if (tiles->sections.find(sec) == tiles->sections.end()) + return 0xFFFFFFFF; + + + for (e = 0;e < atoi(tiles->sections[sec].values["TilesInSet"]);e++) + { + if (i == dwTileSet && e == iTile) + return tilecount; + tilecount++; + + } + + + } + + return tilecount; + +} + + +void CTerrainDlg::OnSelchangeOverlay() +{ + CComboBox* Overlay; + Overlay = (CComboBox*)GetDlgItem(IDC_OVERLAY); + //TileSet->GetLBText(TileSet->GetCurSel(), currentTileSet); + int n = Overlay->GetCurSel(); + + if (n < 0) return; + + int sel = Overlay->GetItemData(n); + + ((CTileSetBrowserFrame*)GetParentFrame())->m_view.SetOverlay(sel); +} diff --git a/MissionEditor/TerrainDlg.h b/MissionEditor/TerrainDlg.h new file mode 100644 index 0000000..5b2206d --- /dev/null +++ b/MissionEditor/TerrainDlg.h @@ -0,0 +1,74 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TERRAINDLG_H__9746CA41_703A_11D4_9C87_EB588B546B1A__INCLUDED_) +#define AFX_TERRAINDLG_H__9746CA41_703A_11D4_9C87_EB588B546B1A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TerrainDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTerrainDlg + +class CTerrainDlg : public CDialogBar +{ +// Konstruktion +public: + DWORD GetTileID(DWORD dwTileSet, int iTile); + void Update(); + CTerrainDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CTerrainDlg) + enum { IDD = IDD_TERRAINBAR }; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTerrainDlg) + public: + virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTerrainDlg) + virtual void OnOK(); + virtual void OnCancel(); + virtual BOOL OnInitDialog(); + afx_msg void OnSelchangeTileset(); + afx_msg void OnSelchangeOverlay(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TERRAINDLG_H__9746CA41_703A_11D4_9C87_EB588B546B1A__INCLUDED_ diff --git a/MissionEditor/TerrainModifier.cpp b/MissionEditor/TerrainModifier.cpp new file mode 100644 index 0000000..38574b2 --- /dev/null +++ b/MissionEditor/TerrainModifier.cpp @@ -0,0 +1,47 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TerrainModifier.cpp: Implementierung der Klasse CTerrainModifier. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "stdafx.h" +#include "TerrainModifier.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Konstruktion/Destruktion +////////////////////////////////////////////////////////////////////// + +CTerrainModifier::CTerrainModifier() +{ + +} + +CTerrainModifier::~CTerrainModifier() +{ + +} diff --git a/MissionEditor/TerrainModifier.h b/MissionEditor/TerrainModifier.h new file mode 100644 index 0000000..ef2a9d1 --- /dev/null +++ b/MissionEditor/TerrainModifier.h @@ -0,0 +1,42 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TerrainModifier.h: Schnittstelle fĂ¼r die Klasse CTerrainModifier. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TERRAINMODIFIER_H__3853D322_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) +#define AFX_TERRAINMODIFIER_H__3853D322_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "MapModifier.h" + +class CTerrainModifier : public CMapModifier +{ +public: + CTerrainModifier(); + virtual ~CTerrainModifier(); + +}; + +#endif // !defined(AFX_TERRAINMODIFIER_H__3853D322_CD37_11D4_9C87_F2DC6A2E6849__INCLUDED_) diff --git a/MissionEditor/TextDrawer.cpp b/MissionEditor/TextDrawer.cpp new file mode 100644 index 0000000..c878715 --- /dev/null +++ b/MissionEditor/TextDrawer.cpp @@ -0,0 +1,186 @@ +#include "TextDrawer.h" +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "TextDrawer.h" +#include <afxwin.h> +#include "Vec2.h" +#include "MissionEditorPackLib.h" + +TextDrawer::TextDrawer(IDirectDraw4* pDirectDraw, int fontSizeInPoints, COLORREF col, COLORREF shadowCol): m_fontSizeInPoints(fontSizeInPoints), m_col(col), m_shadowCol(shadowCol) +{ + auto dc = CDC::FromHandle(::GetDC(NULL)); + auto fontSizeInPixels = -MulDiv(fontSizeInPoints, dc->GetDeviceCaps(LOGPIXELSY), 72); + m_fontSizeInPixels = fontSizeInPixels; + + CFont f; + f.CreateFont(fontSizeInPixels, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, NONANTIALIASED_QUALITY, VARIABLE_PITCH, "COURIER NEW"); + + // Build a string that contains all required characters in order + std::string s; + for (char c = 32; c <= 126; ++c) + s.push_back(c); + + // get the extent in pixels of all characters + dc->SelectObject(f); + const auto extent = dc->GetTextExtent(s.c_str(), s.size()); + + // Now create the DirectDraw surface + DDSURFACEDESC2 desc = { 0 }; + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + desc.dwWidth = extent.cx; + desc.dwHeight = extent.cy * 2; + + m_charExtent.set(extent.cx / s.size(), extent.cy); + + auto bkcol = col == RGB(10, 10, 10) ? RGB(11, 11, 11) : RGB(10, 10, 10); + + auto pSurface = CComPtr<IDirectDrawSurface4>(); + if (pDirectDraw->CreateSurface(&desc, &pSurface, nullptr) != DD_OK) + return; + + desc.dwFlags |= DDSD_PIXELFORMAT; + pSurface->GetSurfaceDesc(&desc); + if (pSurface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL) == DD_OK) + { + FSunPackLib::ColorConverter c(desc.ddpfPixelFormat); + std::int32_t backcolor = c.GetColor(bkcol); + auto bytes_per_pixel = (desc.ddpfPixelFormat.dwRGBBitCount + 7) / 8; + BYTE* const pImage = static_cast<BYTE*>(desc.lpSurface); + for (int i=0; i < desc.dwWidth; ++i) + { + for (int e = 0; e < desc.dwHeight; ++e) + { + memcpy(&pImage[e * desc.lPitch + i * bytes_per_pixel], &backcolor, bytes_per_pixel); + } + } + pSurface->Unlock(NULL); + } + + + + + HDC hDC; + if (pSurface->GetDC(&hDC) != DD_OK) + return; + + // Draw the string with all characters onto the surface + SelectObject(hDC, f); + SetBkMode(hDC, TRANSPARENT); + if (shadowCol != CLR_INVALID) + { + SetTextColor(hDC, shadowCol); + if (!TextOutA(hDC, 0, extent.cy, s.c_str(), s.size())) + return; + } + SetTextColor(hDC, col); + if (!TextOutA(hDC, 0, 0, s.c_str(), s.size())) + return; + + if (pSurface->ReleaseDC(hDC) != DD_OK) + return; + + // set transparency key to top left + FSunPackLib::SetColorKey(pSurface, CLR_INVALID); + + // Everything fine, pass ownership of surface to m_fontSurface + m_fontSurface.Attach(pSurface.Detach()); +} + +bool TextDrawer::isValid() const +{ + return m_fontSurface != nullptr; +} + +void TextDrawer::RenderText(IDirectDrawSurface4* target, int x, int y, const std::string& text, bool centered) const +{ + if (!isValid()) + return; + + auto shadowOffset = 1 + m_fontSizeInPixels / 32; + + const int lineOffset = m_charExtent.y / 4; + ProjectedVec cur(x, y); + const int cw = m_charExtent.x; + const int ch = m_charExtent.y; + + if (centered) + { + cur -= GetExtent(text) / 2; + } + + for (const auto c: text) + { + if (c == '\n') + { + cur.set(x, cur.y + ch + lineOffset); + } + else if (c >= 32 && c <= 126) + { + auto i = c - 32; + + + if (m_shadowCol != CLR_INVALID) + { + RECT s_shadow{ i * cw, ch, i * cw + cw, ch + ch }; + + target->BltFast(cur.x + 0 * shadowOffset, cur.y + 1 * shadowOffset, m_fontSurface, &s_shadow, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + target->BltFast(cur.x + 0 * shadowOffset, cur.y - 1 * shadowOffset, m_fontSurface, &s_shadow, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + target->BltFast(cur.x + 1 * shadowOffset, cur.y + 0 * shadowOffset, m_fontSurface, &s_shadow, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + target->BltFast(cur.x - 1 * shadowOffset, cur.y + 0 * shadowOffset, m_fontSurface, &s_shadow, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + + target->BltFast(cur.x + 1 * shadowOffset, cur.y + 1 * shadowOffset, m_fontSurface, &s_shadow, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + target->BltFast(cur.x - 1 * shadowOffset, cur.y + 1 * shadowOffset, m_fontSurface, &s_shadow, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + target->BltFast(cur.x + 1 * shadowOffset, cur.y - 1 * shadowOffset, m_fontSurface, &s_shadow, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + target->BltFast(cur.x - 1 * shadowOffset, cur.y - 1 * shadowOffset, m_fontSurface, &s_shadow, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + } + + RECT s{ i * cw, 0, i * cw + cw, ch }; + target->BltFast(cur.x, cur.y, m_fontSurface, &s, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + cur.x += cw; + } + } +} + +ProjectedVec TextDrawer::GetExtent(const std::string& text) const +{ + ProjectedVec cur(0, 0); + const int lineOffset = m_charExtent.y / 4; + const int cw = m_charExtent.x; + const int ch = m_charExtent.y; + ProjectedVec maxpos(0, 0); + for (const auto c : text) + { + if (c == '\n') + { + cur.set(0, cur.y + ch + lineOffset); + } + else if (c >= 32 && c <= 126) + { + cur.x += cw; + maxpos.set(max(maxpos.x, cur.x), max(maxpos.y, cur.y + ch)); + } + + } + return maxpos; +} diff --git a/MissionEditor/TextDrawer.h b/MissionEditor/TextDrawer.h new file mode 100644 index 0000000..99fdc86 --- /dev/null +++ b/MissionEditor/TextDrawer.h @@ -0,0 +1,47 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include <ddraw.h> +#include <afx.h> +#include <string> +#include "Vec2.h" + +// Very simple class that renders text through a prepared DirectDraw surface +// Only supports ASCII chars 32 to 126, only supports monospace font +// This is for rendering waypoint ids or credits on map without using GDI during rendering, nothing fancy +class TextDrawer +{ +public: + TextDrawer(IDirectDraw4* pDirectDraw, int fontSizeInPoints, COLORREF col, COLORREF shadowCol=CLR_INVALID); + + bool isValid() const; + + void RenderText(IDirectDrawSurface4* target, int x, int y, const std::string& text, bool centered=false) const; + + ProjectedVec GetExtent(const std::string& text) const; + +private: + CComPtr<IDirectDrawSurface4> m_fontSurface; + ProjectedVec m_charExtent; + int m_fontSizeInPoints; + int m_fontSizeInPixels; + COLORREF m_col; + COLORREF m_shadowCol; +}; \ No newline at end of file diff --git a/MissionEditor/TileSetBrowserFrame.cpp b/MissionEditor/TileSetBrowserFrame.cpp new file mode 100644 index 0000000..fcdf219 --- /dev/null +++ b/MissionEditor/TileSetBrowserFrame.cpp @@ -0,0 +1,115 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TileSetBrowserFrame.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "TileSetBrowserFrame.h" +#include "resource.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTileSetBrowserFrame + +IMPLEMENT_DYNCREATE(CTileSetBrowserFrame, CFrameWnd) + +CTileSetBrowserFrame::CTileSetBrowserFrame() +{ +} + +CTileSetBrowserFrame::~CTileSetBrowserFrame() +{ +} + + +BEGIN_MESSAGE_MAP(CTileSetBrowserFrame, CFrameWnd) + //{{AFX_MSG_MAP(CTileSetBrowserFrame) + ON_WM_SIZE() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTileSetBrowserFrame + +void CTileSetBrowserFrame::PostNcDestroy() +{ + // TODO: Speziellen Code hier einfĂ¼gen und/oder Basisklasse aufrufen + delete this; + // CFrameWnd::PostNcDestroy(); +} + +BOOL CTileSetBrowserFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) +{ + ((CDialogBar*)&m_bar)->Create(this, IDD_TERRAINBAR, CBRS_TOP, 5); + m_bar.ShowWindow(SW_SHOW); + CRect r; + GetClientRect(r); + m_view.Create(NULL, NULL, WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE, r, this, 1, NULL); + + + RecalcLayout(TRUE); + + CSize sizeTotal; + GetClientRect(&r); + sizeTotal.cx = r.right; + sizeTotal.cy = m_view.m_bottom_needed; + m_view.SetScrollSizes(MM_TEXT, sizeTotal); + + m_view.ShowWindow(SW_SHOW); + + return CFrameWnd::OnCreateClient(lpcs, pContext); +} + +void CTileSetBrowserFrame::RecalcLayout(BOOL bNotify) +{ + + RECT r; + RECT rm; + GetClientRect(&rm); + m_bar.GetClientRect(&r); + + m_view.SetWindowPos(NULL, 0, r.bottom, rm.right, rm.bottom - r.bottom, SWP_NOZORDER); + + m_view.GetClientRect(&r); + CSize sizeTotal; + sizeTotal.cx = r.right; + sizeTotal.cy = m_view.m_bottom_needed; + m_view.SetScrollSizes(MM_TEXT, sizeTotal); + + CFrameWnd::RecalcLayout(bNotify); + + +} + +void CTileSetBrowserFrame::OnSize(UINT nType, int cx, int cy) +{ + CFrameWnd::OnSize(nType, cx, cy); + + RecalcLayout(); + +} + diff --git a/MissionEditor/TileSetBrowserFrame.h b/MissionEditor/TileSetBrowserFrame.h new file mode 100644 index 0000000..7b36572 --- /dev/null +++ b/MissionEditor/TileSetBrowserFrame.h @@ -0,0 +1,76 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TILESETBROWSERFRAME_H__1FD3DBE1_7D2F_11D4_9C87_444553540000__INCLUDED_) +#define AFX_TILESETBROWSERFRAME_H__1FD3DBE1_7D2F_11D4_9C87_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TileSetBrowserFrame.h : Header-Datei +// + +#include "TerrainDlg.h" +#include "TileSetBrowserView.h" // HinzugefĂ¼gt von der Klassenansicht + +///////////////////////////////////////////////////////////////////////////// +// Rahmen CTileSetBrowserFrame + +class CTileSetBrowserFrame : public CFrameWnd +{ + DECLARE_DYNCREATE(CTileSetBrowserFrame) +public: + CTileSetBrowserFrame(); // Dynamische Erstellung verwendet geschĂ¼tzten Konstruktor + +// Attribute +public: + +// Operationen +public: + CTerrainDlg m_bar; + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTileSetBrowserFrame) + public: + virtual void RecalcLayout(BOOL bNotify = TRUE); + protected: + virtual void PostNcDestroy(); + virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext); + //}}AFX_VIRTUAL + +// Implementierung +public: + CTileSetBrowserView m_view; + virtual ~CTileSetBrowserFrame(); + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTileSetBrowserFrame) + afx_msg void OnSize(UINT nType, int cx, int cy); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TILESETBROWSERFRAME_H__1FD3DBE1_7D2F_11D4_9C87_444553540000__INCLUDED_ diff --git a/MissionEditor/TileSetBrowserView.cpp b/MissionEditor/TileSetBrowserView.cpp new file mode 100644 index 0000000..6b794d2 --- /dev/null +++ b/MissionEditor/TileSetBrowserView.cpp @@ -0,0 +1,1086 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TileSetBrowserView.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "TileSetBrowserView.h" +#include "FinalSunDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + +extern ACTIONDATA AD; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTileSetBrowserView + +IMPLEMENT_DYNCREATE(CTileSetBrowserView, CScrollView) + +CTileSetBrowserView::CTileSetBrowserView() +{ + m_lpDDS = NULL; + m_bottom_needed = 1000; + m_CurrentMode = 0; +} + +CTileSetBrowserView::~CTileSetBrowserView() +{ + if (m_lpDDS) + { + int i; + for (i = 0;i < m_tilecount;i++) + { + if (m_lpDDS[i]) m_lpDDS[i]->Release(); + } + delete[] m_lpDDS; + } + m_lpDDS = NULL; + +} + + +BEGIN_MESSAGE_MAP(CTileSetBrowserView, CScrollView) + //{{AFX_MSG_MAP(CTileSetBrowserView) + ON_WM_LBUTTONDOWN() + ON_WM_VSCROLL() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Zeichnung CTileSetBrowserView + +void CTileSetBrowserView::OnInitialUpdate() +{ + CScrollView::OnInitialUpdate(); + + +} + +// for fast overlay drawing use IsoView´s overlay table +extern PICDATA* ovrlpics[0xFF][max_ovrl_img]; + + + +void CTileSetBrowserView::OnDraw(CDC* pDC) +{ + //ReleaseDC(pDC); + + + + if (((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->b_IsLoading || ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->lpds == NULL || ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->lpds->IsLost() != DD_OK) + return; + + + RECT r; + GetClientRect(&r); + + if (tiledata == NULL || (*tiledata) == NULL) + return; + + if (m_tilecount == 0) + return; + + if (m_tile_width == 0) + return; // just to make sure I never divide through 0 here... + + int max_r = r.right / m_tile_width; + + int cur_y = 0; + int cur_x = 0; + + if (m_CurrentMode == 1) + { + DWORD dwID = GetTileID(m_currentTileSet, 0); + + int i; + for (i = 0;i < m_tilecount;i++) + { + char c[50]; + itoa(i, c, 10); + + int curwidth = (*tiledata)[dwID].rect.right - (*tiledata)[dwID].rect.left; + int curheight = GetAddedHeight(dwID) + (*tiledata)[dwID].rect.bottom - (*tiledata)[dwID].rect.top; + //pDC.TextOut(cur_x, cur_y, c); + +#ifdef RA2_MODE + if ((m_currentTileSet == 80 && Map->GetTheater() == "TEMPERATE") || (m_currentTileSet == 73 && Map->GetTheater() == "SNOW") || (m_currentTileSet == 101 && Map->GetTheater() == "URBAN")) + { + if (i == 10 || i == 15) + { + dwID++; // don´t forget this here, too + continue; + } + } +#endif + + if (!m_lpDDS[i]) continue; + + RECT r; + GetClientRect(&r); + if (cur_y + curheight + (m_tile_height - curheight) / 2 >= this->GetScrollPos(SB_VERT) && cur_y <= GetScrollPos(SB_VERT) + r.bottom) + { + + HDC hDC = NULL; + m_lpDDS[i]->GetDC(&hDC); + + + HDC hTmpDC = CreateCompatibleDC(hDC); + HBITMAP hBitmap = CreateCompatibleBitmap(hDC, curwidth, curheight); + SelectObject(hTmpDC, hBitmap); + + BitBlt(hTmpDC, 0, 0, curwidth, curheight, hDC, 0, 0, SRCCOPY); + + m_lpDDS[i]->ReleaseDC(hDC); + + + BitBlt(pDC->GetSafeHdc(), cur_x + (m_tile_width - curwidth) / 2, cur_y + (m_tile_height - curheight) / 2, curwidth, curheight, hTmpDC, 0, 0, SRCCOPY); + + + DeleteDC(hTmpDC); + DeleteObject(hBitmap); + + if (AD.mode == ACTIONMODE_SETTILE && AD.type == dwID) + { + CPen p; + CBrush b; + p.CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); + b.CreateStockObject(NULL_BRUSH); + + CPen* old = pDC->SelectObject(&p); + + pDC->SetBkMode(TRANSPARENT); + pDC->SelectObject(&b); + pDC->Rectangle(cur_x + 2, cur_y + 2, cur_x + m_tile_width - 2, cur_y + m_tile_height - 2); + + pDC->SelectObject(old); + } + } + + cur_x += m_tile_width; + if (max_r == 0) max_r = 1; + if (i % max_r == max_r - 1) + { + cur_y += m_tile_height; + cur_x = 0; + } + + + + dwID++; + } + } +#ifndef NOSURFACES + else if (m_CurrentMode == 2) + { + int i; + + for (i = 0;i < max_ovrl_img;i++) + { + PICDATA* p = ovrlpics[m_currentOverlay][i]; + if (p != NULL && p->pic != NULL) + { + + DDSURFACEDESC2 desc; + memset(&desc, 0, sizeof(DDSURFACEDESC2)); + desc.dwSize = sizeof(DDSURFACEDESC2); + desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + p->pic->GetSurfaceDesc(&desc); + + int curwidth = desc.dwWidth; + int curheight = desc.dwHeight; + + HDC hDC = NULL; + p->pic->GetDC(&hDC); + + + HDC hTmpDC = CreateCompatibleDC(hDC); + HBITMAP hBitmap = CreateCompatibleBitmap(hDC, curwidth, curheight); + SelectObject(hTmpDC, hBitmap); + + BitBlt(hTmpDC, 0, 0, curwidth, curheight, hDC, 0, 0, SRCCOPY); + + p->pic->ReleaseDC(hDC); + + + BitBlt(pDC->GetSafeHdc(), cur_x + (m_tile_width - curwidth) / 2, cur_y + (m_tile_height - curheight) / 2, curwidth, curheight, hTmpDC, 0, 0, SRCCOPY); + + + DeleteDC(hTmpDC); + DeleteObject(hBitmap); + + if (AD.mode == ACTIONMODE_PLACE && AD.data2 == m_currentOverlay && AD.data3 == i && AD.data == 33 && AD.type == 6) + { + CPen p; + CBrush b; + p.CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); + b.CreateStockObject(NULL_BRUSH); + + CPen* old = pDC->SelectObject(&p); + + pDC->SetBkMode(TRANSPARENT); + pDC->SelectObject(&b); + pDC->Rectangle(cur_x + 2, cur_y + 2, cur_x + m_tile_width - 2, cur_y + m_tile_height - 2); + + pDC->SelectObject(old); + } + + cur_x += m_tile_width; + if (max_r == 0) max_r = 1; + if (i % max_r == max_r - 1) + { + cur_y += m_tile_height; + cur_x = 0; + } + } + } + } +#else + else if (m_CurrentMode == 2) + { + int i; + + for (i = 0;i < max_ovrl_img;i++) + { + PICDATA* p = ovrlpics[m_currentOverlay][i]; + if (p != NULL && p->pic != NULL) + { + + int curwidth = p->wMaxWidth; + int curheight = p->wMaxHeight; + + BITMAPINFO biinfo; + memset(&biinfo, 0, sizeof(BITMAPINFO)); + biinfo.bmiHeader.biBitCount = 24; + biinfo.bmiHeader.biWidth = curwidth; + biinfo.bmiHeader.biHeight = curheight; + biinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + biinfo.bmiHeader.biClrUsed = 0; + biinfo.bmiHeader.biPlanes = 1; + biinfo.bmiHeader.biCompression = BI_RGB; + biinfo.bmiHeader.biClrImportant = 0; + + int pitch = curwidth * 3; + if (pitch == 0) + continue; + + if (pitch % sizeof(DWORD)) + { + pitch += sizeof(DWORD) - (curwidth * 3) % sizeof(DWORD); + } + + BYTE* colors = new(BYTE[pitch * curheight]); + memset(colors, 255, pitch * (curheight)); + + RGBTRIPLE* pal = palIso; + if (p->pal == iPalTheater) + pal = palTheater; + if (p->pal == iPalUnit) + pal = palUnit; + + int k, l; + for (k = 0;k < curheight;k++) + { + for (l = 0;l < curwidth;l++) + { + if (((BYTE*)p->pic)[l + k * curwidth]) + { + memcpy(&colors[l * 3 + (curheight - k - 1) * pitch], &pal[((BYTE*)p->pic)[l + k * curwidth]], 3); + } + } + } + + StretchDIBits(pDC->GetSafeHdc(), cur_x + (m_tile_width - curwidth) / 2, cur_y + (m_tile_height - curheight) / 2, curwidth, curheight, + 0, 0, curwidth, curheight, colors, &biinfo, DIB_RGB_COLORS, SRCCOPY); + + delete[] colors; + + if (AD.mode == ACTIONMODE_PLACE && AD.data2 == m_currentOverlay && AD.data3 == i && AD.data == 33 && AD.type == 6) + { + CPen p; + CBrush b; + p.CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); + b.CreateStockObject(NULL_BRUSH); + + CPen* old = pDC->SelectObject(&p); + + pDC->SetBkMode(TRANSPARENT); + pDC->SelectObject(&b); + pDC->Rectangle(cur_x + 2, cur_y + 2, cur_x + m_tile_width - 2, cur_y + m_tile_height - 2); + + pDC->SelectObject(old); + } + + cur_x += m_tile_width; + if (max_r == 0) + max_r = 1; + if (i % max_r == max_r - 1) + { + cur_y += m_tile_height; + cur_x = 0; + } + } + } + } +#endif + + +} + +///////////////////////////////////////////////////////////////////////////// +// Diagnose CTileSetBrowserView + +#ifdef _DEBUG +void CTileSetBrowserView::AssertValid() const +{ + CScrollView::AssertValid(); +} + +void CTileSetBrowserView::Dump(CDumpContext& dc) const +{ + CScrollView::Dump(dc); +} +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTileSetBrowserView + +void CTileSetBrowserView::PostNcDestroy() +{ + // TODO: Speziellen Code hier einfĂ¼gen und/oder Basisklasse aufrufen + + // CScrollView::PostNcDestroy(); +} + +DWORD CTileSetBrowserView::GetTileID(DWORD dwTileSet, DWORD dwType) +{ + int i, e; + DWORD tilecount = 0; + for (i = 0;i < 10000;i++) + { + CString tset; + char c[50]; + itoa(i, c, 10); + int e; + for (e = 0;e < 4 - strlen(c);e++) + tset += "0"; + tset += c; + CString sec = "TileSet"; + sec += tset; + + if (tiles->sections.find(sec) == tiles->sections.end()) + return 0xFFFFFFFF; + + + for (e = 0;e < atoi(tiles->sections[sec].values["TilesInSet"]);e++) + { + if (i == dwTileSet && e == dwType) + return tilecount; + tilecount++; + + } + + + } + + return tilecount; +} + +void CTileSetBrowserView::SetTileSet(DWORD dwTileSet, BOOL bOnlyRedraw) +{ + m_currentTileSet = dwTileSet; + m_CurrentMode = 1; + + char currentTileSet[50]; + itoa(m_currentTileSet, currentTileSet, 10); + CString tset; + + int e; + for (e = 0;e < 4 - strlen(currentTileSet);e++) + tset += "0"; + + tset += currentTileSet; + + m_tile_width = 0; + m_tile_height = 0; + + int i; + int max = atoi(tiles->sections[(CString)"TileSet" + tset].values["TilesInSet"]); + DWORD dwStartID = GetTileID(dwTileSet, 0); + if ((*tiledata)[dwStartID].wTileCount && (*tiledata)[dwStartID].tiles[0].pic) + { + if (!bOnlyRedraw) + { + AD.mode = ACTIONMODE_SETTILE; + AD.type = dwStartID; + AD.data = 0; + AD.data2 = 0; + AD.z_data = 0; + + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.m_BrushSize = 0; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.UpdateData(FALSE); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_x = 1; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_y = 1; + + int i; + for (i = 0;i < g_data.sections["StdBrushSize"].values.size();i++) + { + CString n = *g_data.sections["StdBrushSize"].GetValueName(i); + if ((*tiles).sections["General"].FindName(n) >= 0) + { + int tset = atoi((*tiles).sections["General"].values[n]); + if (tset == m_currentTileSet) + { + int bs = atoi(*g_data.sections["StdBrushSize"].GetValue(i)); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.m_BrushSize = bs - 1; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.UpdateData(FALSE); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_x = bs; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_y = bs; + } + } + } + } + } + DWORD dwID; + for (i = 0;i < max;i++) + { + CString str; + char c[50]; + itoa(i, c, 10); + for (e = 0;e < 2 - strlen(c);e++) + str += "0"; + str += c; + + dwID = dwStartID + i; // just faster than always calling GetTileID() + if (dwID < *tiledata_count) + { + if ((*tiledata)[dwID].rect.right - (*tiledata)[dwID].rect.left > m_tile_width) m_tile_width = (*tiledata)[dwID].rect.right - (*tiledata)[dwID].rect.left; + if (GetAddedHeight(dwID) + (*tiledata)[dwID].rect.bottom - (*tiledata)[dwID].rect.top > m_tile_height) m_tile_height = GetAddedHeight(dwID) + (*tiledata)[dwID].rect.bottom - (*tiledata)[dwID].rect.top; + } + } + + m_tile_width += 6; + m_tile_height += 6; + + if (m_lpDDS) + { + int i; + for (i = 0;i < m_tilecount;i++) + { + if (m_lpDDS[i]) m_lpDDS[i]->Release(); + } + delete[] m_lpDDS; + } + + m_tilecount = max; + + m_lpDDS = new(LPDIRECTDRAWSURFACE4[m_tilecount]); + for (i = 0;i < m_tilecount;i++) + { + m_lpDDS[i] = RenderTile(dwStartID + i); + } + + RECT r; + GetClientRect(&r); + int max_r = r.right / m_tile_width; + if (max_r <= 0) max_r = 1; + m_bottom_needed = m_tile_height * (1 + m_tilecount / max_r); + GetParentFrame()->RecalcLayout(TRUE); + + + RedrawWindow(); + + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->SetForegroundWindow(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->SetFocus(); + + //DrawIt(); +} + + +#ifdef NOSURFACES + +struct BlitRect +{ + short left; + short top; + short right; + short bottom; +}; + +__forceinline void BlitTerrainTSB(void* dst, int x, int y, int dleft, int dtop, int dpitch, int dright, int dbottom, SUBTILE& st)//BYTE* src, int swidth, int sheight) +{ + BYTE* src = st.pic; + unsigned short& swidth = st.wWidth; + unsigned short& sheight = st.wHeight; + + + if (src == NULL || dst == NULL) + return; + + if (x + swidth < dleft || y + sheight < dtop) + return; + if (x >= dright || y >= dbottom) + return; + + + BlitRect blrect; + BlitRect srcRect; + srcRect.left = 0; + srcRect.top = 0; + srcRect.right = swidth; + srcRect.bottom = sheight; + blrect.left = x; + if (blrect.left < 0) + { + srcRect.left = 1 - blrect.left; + blrect.left = 1; + } + blrect.top = y; + if (blrect.top < 0) + { + srcRect.top = 1 - blrect.top; + blrect.top = 1; + } + blrect.right = (x + swidth); + if (x + swidth > dright) + { + srcRect.right = dright - x;//swidth-((x+swidth)-dright); + blrect.right = dright; + } + blrect.bottom = (y + sheight); + if (y + sheight > dbottom) + { + srcRect.bottom = dbottom - y;//sheight-((y+sheight)-dbottom); + blrect.bottom = dbottom; + } + + + short i, e; + + + +#ifdef NOSURFACES_EXTRACT + int pos = 0; + if (!st.bNotExtracted) + { + for (e = srcRect.top;e < srcRect.bottom;e++) + { + short& left = st.vborder[e].left; + short& right = st.vborder[e].right; + + if (right >= left) + { + void* dest = ((BYTE*)dst + (blrect.left + left) * bpp + (blrect.top + e) * dpitch); + + memcpy(dest, &st.pic[pos], bpp * (right - left + 1)); + pos += (right - left + 1) * bpp; + } + } + } + else + +#endif + + for (e = srcRect.top;e < srcRect.bottom;e++) + { + short& left = st.vborder[e].left; + short& right = st.vborder[e].right; + + for (i = left;i <= right;i++) + { + if (i < srcRect.left || i >= srcRect.right) + { + //dest+=bpp; + } + else + { + + BYTE& val = src[i + e * swidth]; + if (val) + { + void* dest = ((BYTE*)dst + (blrect.left + i) * bpp + (blrect.top + e) * dpitch); + + memcpy(dest, &iPalIso[val], bpp); + } + } + } + + } + + +} +#endif + + +LPDIRECTDRAWSURFACE4 CTileSetBrowserView::RenderTile(DWORD dwID) +{ + if (theApp.m_Options.bMarbleMadness) + { + if ((*tiledata)[dwID].wMarbleGround != 0xFFFF) + { + dwID = (*tiledata)[dwID].wMarbleGround; + } + } + + LPDIRECTDRAWSURFACE4 lpdds = NULL; + LPDIRECTDRAW4 lpdd = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->dd; + + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + int added_height = GetAddedHeight(dwID); + ddsd.dwHeight = (*tiledata)[dwID].rect.bottom - (*tiledata)[dwID].rect.top + added_height; + ddsd.dwWidth = (*tiledata)[dwID].rect.right - (*tiledata)[dwID].rect.left; + if (lpdd->CreateSurface(&ddsd, &lpdds, NULL) != DD_OK) + { + return NULL; + } + + DDBLTFX ddfx; + memset(&ddfx, 0, sizeof(DDBLTFX)); + ddfx.dwSize = sizeof(DDBLTFX); + lpdds->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &ddfx); + + + int y_added = ddsd.dwHeight - ((*tiledata)[dwID].cx * f_y / 2 + (*tiledata)[dwID].cy * f_y / 2); + + int i, e, p = 0;; + for (i = 0;i < (*tiledata)[dwID].cx;i++) + { + for (e = 0;e < (*tiledata)[dwID].cy;e++) + { + int drawx = e * f_x / 2 - i * f_x / 2 - (*tiledata)[dwID].rect.left; + int drawy = e * f_y / 2 + i * f_y / 2 - (*tiledata)[dwID].rect.top; + + drawx += (*tiledata)[dwID].tiles[p].sX; + drawy += added_height + (*tiledata)[dwID].tiles[p].sY - (*tiledata)[dwID].tiles[p].bZHeight * f_y / 2; + //drawy+=y_added; + + if ((*tiledata)[dwID].tiles[p].pic) + { + RECT dest; + dest.left = drawx; + dest.top = drawy; + dest.right = drawx + (*tiledata)[dwID].tiles[p].wWidth; + dest.bottom = drawy + (*tiledata)[dwID].tiles[p].wHeight; + DDBLTFX fx; + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize = sizeof(DDBLTFX); + +#ifndef NOSURFACES + if (lpdds->Blt(&dest, (*tiledata)[dwID].tiles[p].pic, NULL, DDBLT_KEYSRC, &fx) != DD_OK) + TRACE("Blit failed\n"); +#else + DDSURFACEDESC2 ddsd; + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + + lpdds->GetSurfaceDesc(&ddsd); + + lpdds->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL); + + BlitTerrainTSB(ddsd.lpSurface, drawx, drawy, 0, 0, ddsd.lPitch, ddsd.dwWidth, ddsd.dwHeight, (*tiledata)[dwID].tiles[p]); + lpdds->Unlock(NULL); +#endif + + } + + p++; + } + } + + FSunPackLib::SetColorKey(lpdds, -1); + + return lpdds; +} + +void CTileSetBrowserView::DrawIt() +{ + CPaintDC myDC(this); + + +} + +void CTileSetBrowserView::OnLButtonDown(UINT nFlags, CPoint point) +{ + RECT r; + GetClientRect(&r); + + if (m_tilecount == 0) + return; + + SCROLLINFO scrinfo; + scrinfo.cbSize = sizeof(SCROLLINFO); + scrinfo.fMask = SIF_ALL; + GetScrollInfo(SB_HORZ, &scrinfo); + point.x += scrinfo.nPos; + GetScrollInfo(SB_VERT, &scrinfo); + point.y += scrinfo.nPos; + + + int max_r = r.right / m_tile_width; + + if (max_r == 0) max_r = 1; + + int cur_y = 0; + int cur_x = 0; + + int tile_width = m_tile_width; + int tile_height = m_tile_height; + + if (m_CurrentMode == 1) + { + DWORD dwID = GetTileID(m_currentTileSet, 0); + + + + int i; + for (i = 0;i < m_tilecount;i++) + { + int curwidth = (*tiledata)[dwID].rect.right - (*tiledata)[dwID].rect.left; + int curheight = (*tiledata)[dwID].rect.bottom - (*tiledata)[dwID].rect.top; + curwidth = m_tile_width; + curheight = m_tile_height; + +#ifdef RA2_MODE + if ((m_currentTileSet == 80 && Map->GetTheater() == "TEMPERATE") || (m_currentTileSet == 73 && Map->GetTheater() == "SNOW") || (m_currentTileSet == 101 && Map->GetTheater() == "URBAN")) + { + + if (i == 10 || i == 15) + { + dwID++; // don´t forget this + continue; + } + } +#endif + + int posaddedx = (m_tile_width - curwidth) / 2; + int posaddedy = (m_tile_height - curheight) / 2; + + if (point.x > cur_x + posaddedx && point.y > cur_y + posaddedy && point.x < cur_x + tile_width - posaddedx && point.y < cur_y + tile_height - posaddedy) + { + char c[50]; + itoa(GetAddedHeight(dwID), c, 10); + OutputDebugString(c); + + int oldmode = AD.mode; + int oldid = AD.type; + + AD.mode = ACTIONMODE_SETTILE; + AD.type = dwID; + AD.data = 0; + AD.data2 = 0; + AD.data3 = 0; + AD.z_data = 0; + + if (oldid > *tiledata_count) oldid = 0; + + if (oldmode != ACTIONMODE_SETTILE || (*tiledata)[oldid].wTileSet != m_currentTileSet) + { + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.m_BrushSize = 0; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.UpdateData(FALSE); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_x = 1; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_y = 1; + + int i; + for (i = 0;i < g_data.sections["StdBrushSize"].values.size();i++) + { + CString n = *g_data.sections["StdBrushSize"].GetValueName(i); + if ((*tiles).sections["General"].FindName(n) >= 0) + { + int tset = atoi((*tiles).sections["General"].values[n]); + if (tset == m_currentTileSet) + { + int bs = atoi(*g_data.sections["StdBrushSize"].GetValue(i)); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.m_BrushSize = bs - 1; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.UpdateData(FALSE); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_x = bs; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_y = bs; + } + } + } + } + + RedrawWindow(); + return; + } + + cur_x += tile_width; + if (i % max_r == max_r - 1) + { + cur_y += tile_height; + cur_x = 0; + } + + + + dwID++; + } + } + else if (m_CurrentMode == 2) + { + int i; + for (i = 0;i < max_ovrl_img;i++) + { + PICDATA* p = ovrlpics[m_currentOverlay][i]; + if (p != NULL && p->pic != NULL) + { + int curwidth = m_tile_width; + int curheight = m_tile_height; + + int posaddedx = (m_tile_width - curwidth) / 2; + int posaddedy = (m_tile_height - curheight) / 2; + + if (point.x > cur_x + posaddedx && point.y > cur_y + posaddedy && point.x < cur_x + tile_width - posaddedx && point.y < cur_y + tile_height - posaddedy) + { + AD.mode = ACTIONMODE_PLACE; + AD.type = 6; + AD.data = 33; + AD.data2 = m_currentOverlay; + AD.data3 = i; + RedrawWindow(); + return; + } + + cur_x += tile_width; + if (i % max_r == max_r - 1) + { + cur_y += tile_height; + cur_x = 0; + } + } + + } + } + + + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->SetForegroundWindow(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->SetFocus(); + + CScrollView::OnLButtonDown(nFlags, point); +} + +// calculates additional height added to the top of a tile if needed +int CTileSetBrowserView::GetAddedHeight(DWORD dwID) +{ + + //int i; + int cur_added = 0; + //for(i=0;i<(*tiledata)[dwID].wTileCount;i++) + { + int i, e, p = 0;; + for (i = 0;i < (*tiledata)[dwID].cx;i++) + { + for (e = 0;e < (*tiledata)[dwID].cy;e++) + { + int drawy = e * f_y / 2 + i * f_y / 2 - (*tiledata)[dwID].rect.top; + + drawy += (*tiledata)[dwID].tiles[p].sY - (*tiledata)[dwID].tiles[p].bZHeight * f_y / 2; + + if (drawy < cur_added) cur_added = drawy; + + p++; + } + } + + + } + + + + return -cur_added; +} + +void CTileSetBrowserView::SetOverlay(DWORD dwID) +{ + int k; + int need_pos = -1; + int need_width = 0; + int need_height = 0; + // m_tilecount=0; + int iovrlcount = 0; + BOOL bFound = FALSE; + for (k = 0;k < max_ovrl_img;k++) + { + PICDATA* p = ovrlpics[dwID][k]; + if (p != NULL && p->pic != NULL) + { + bFound = TRUE; + } + } + if (!bFound) + { + theApp.m_loading->LoadOverlayGraphic(*rules.sections["OverlayTypes"].GetValue(dwID), dwID); + ((CFinalSunDlg*)(theApp.m_pMainWnd))->m_view.m_isoview->UpdateOverlayPictures(); + //p=ovrlpics[dwID][k]; + } + for (k = 0;k < max_ovrl_img;k++) + { + PICDATA* p = ovrlpics[dwID][k]; + if (p == NULL || p->pic == NULL) + { + //if(!p->bTried) + { + + } + } + if (p != NULL && p->pic != NULL) + { + iovrlcount++; + } + } + for (k = 0;k < max_ovrl_img;k++) + { + PICDATA* p = ovrlpics[dwID][k]; + if (p != NULL && p->pic != NULL) + { + need_pos = k; + need_width = p->wMaxWidth; + need_height = p->wMaxHeight; + break; + } + } + + if (need_pos < 0) + return; + + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.m_BrushSize = 0; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.UpdateData(FALSE); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_x = 1; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_y = 1; + + + + m_CurrentMode = 2; + m_tile_width = 0; + m_tile_height = 0; + m_currentOverlay = dwID; + + + + m_tile_width = need_width + 6; + m_tile_height = need_height + 6; + + + + RECT r; + GetClientRect(&r); + int max_r = r.right / m_tile_width; + if (max_r <= 0) max_r = 1; + m_bottom_needed = m_tile_height * (1 + (iovrlcount) / max_r); + GetParentFrame()->RecalcLayout(TRUE); + RedrawWindow(); + + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->SetForegroundWindow(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->SetFocus(); + +} + +#ifdef IGNORETHIS +LPDIRECTDRAWSURFACE4 CTileSetBrowserView::RenderOverlay(DWORD dwType, DWORD dwData) +{ + LPDIRECTDRAWSURFACE4 lpdds = NULL; + LPDIRECTDRAW4 lpdd = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->dd; + + DDSURFACEDESC2 ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + int added_height = GetAddedHeight(dwID); + ddsd.dwHeight =//(*tiledata)[dwID].rect.bottom-(*tiledata)[dwID].rect.top+added_height; + ddsd.dwWidth = (*tiledata)[dwID].rect.right - (*tiledata)[dwID].rect.left; + if (lpdd->CreateSurface(&ddsd, &lpdds, NULL) != DD_OK) + { + return NULL; + } + + DDBLTFX ddfx; + memset(&ddfx, 0, sizeof(DDBLTFX)); + ddfx.dwSize = sizeof(DDBLTFX); + lpdds->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &ddfx); + + + int y_added = ddsd.dwHeight - ((*tiledata)[dwID].cx * f_y / 2 + (*tiledata)[dwID].cy * f_y / 2); + + int i, e, p = 0;; + for (i = 0;i < (*tiledata)[dwID].cx;i++) + { + for (e = 0;e < (*tiledata)[dwID].cy;e++) + { + int drawx = e * f_x / 2 - i * f_x / 2 - (*tiledata)[dwID].rect.left; + int drawy = e * f_y / 2 + i * f_y / 2 - (*tiledata)[dwID].rect.top; + + drawx += (*tiledata)[dwID].tiles[p].sX; + drawy += added_height + (*tiledata)[dwID].tiles[p].sY - (*tiledata)[dwID].tiles[p].bZHeight * f_y / 2; + //drawy+=y_added; + + if ((*tiledata)[dwID].tiles[p].pic) + { + RECT dest; + dest.left = drawx; + dest.top = drawy; + dest.right = drawx + (*tiledata)[dwID].tiles[p].wWidth; + dest.bottom = drawy + (*tiledata)[dwID].tiles[p].wHeight; + DDBLTFX fx; + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize = sizeof(DDBLTFX); + + + DDSURFACEDESC2 ddsd; + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + + lpdds->GetSurfaceDesc(&ddsd); + + lpdds->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL); + + BlitTerrainTSB(ddsd.lpSurface, drawx, drawy, 0, 0, ddsd.lPitch, ddsd.dwWidth, ddsd.dwHeight, (*tiledata)[dwID].tiles[p]); + lpdds->Unlock(NULL); + + + } + + p++; + } + } + + SetSurfaceColorKey(lpdds, -1); +} + +#endif + +void CTileSetBrowserView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + //RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + CScrollView::OnVScroll(nSBCode, nPos, pScrollBar); +} diff --git a/MissionEditor/TileSetBrowserView.h b/MissionEditor/TileSetBrowserView.h new file mode 100644 index 0000000..a641223 --- /dev/null +++ b/MissionEditor/TileSetBrowserView.h @@ -0,0 +1,90 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TILESETBROWSERVIEW_H__3DD92021_7D37_11D4_9C87_97337B61A44A__INCLUDED_) +#define AFX_TILESETBROWSERVIEW_H__3DD92021_7D37_11D4_9C87_97337B61A44A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TileSetBrowserView.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Ansicht CTileSetBrowserView + +class CTileSetBrowserView : public CScrollView +{ +public: + CTileSetBrowserView(); // Dynamische Erstellung verwendet geschĂ¼tzten Konstruktor + DECLARE_DYNCREATE(CTileSetBrowserView) + +// Attribute +public: + +// Operationen +public: + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTileSetBrowserView) + protected: + virtual void OnDraw(CDC* pDC); // Ăœberschrieben zum Zeichnen dieser Ansicht + virtual void OnInitialUpdate(); // Zum ersten Mal nach der Konstruktion + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementierung +public: + void SetOverlay(DWORD dwID); + int m_currentOverlay; + int GetAddedHeight(DWORD dwID); + int m_bottom_needed; + void DrawIt(); + LPDIRECTDRAWSURFACE4* m_lpDDS; + void SetTileSet(DWORD dwTileSet, BOOL bOnlyRedraw=FALSE); + DWORD GetTileID(DWORD dwTileSet, DWORD dwType); + int m_currentTileSet; + virtual ~CTileSetBrowserView(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTileSetBrowserView) + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +protected: + int m_CurrentMode; + LPDIRECTDRAWSURFACE4 RenderTile(DWORD dwID); + int m_tilecount; + int m_tile_height; + int m_tile_width; +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TILESETBROWSERVIEW_H__3DD92021_7D37_11D4_9C87_97337B61A44A__INCLUDED_ diff --git a/MissionEditor/TipDlg.cpp b/MissionEditor/TipDlg.cpp new file mode 100644 index 0000000..164d433 --- /dev/null +++ b/MissionEditor/TipDlg.cpp @@ -0,0 +1,266 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "resource.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + +#include <winreg.h> +#include <sys\stat.h> +#include <sys\types.h> + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTipDlg dialog field + +#define MAX_BUFLEN 1000 + +static const TCHAR szSection[] = _T("Tip"); +static const TCHAR szIntFilePos[] = _T("FilePos"); +static const TCHAR szTimeStamp[] = _T("TimeStamp"); +static const TCHAR szIntStartup[] = _T("StartUp"); + +extern char AppPath[]; + +CTipDlg::CTipDlg(CWnd* pParent /*=NULL*/) + : CDialog(IDD_TIP, pParent) +{ + //{{AFX_DATA_INIT(CTipDlg) + m_bStartup = TRUE; + //}}AFX_DATA_INIT + + CIniFile optini; + CString iniFile; + + iniFile=AppPath; +#ifndef RA2_MODE + iniFile+="\\FinalSun.ini"; +#else + iniFile+="\\FinalAlert.ini"; +#endif + optini.LoadFile(iniFile); + + CWinApp* pApp = AfxGetApp(); + m_bStartup = !atoi(optini.sections[szSection].values[szIntStartup]); + UINT iFilePos = atoi(optini.sections[szSection].values[szIntFilePos]); + + // try top open the tips file + CString tipsfile=AppPath; + tipsfile+="\\tips."; + tipsfile+=language.sections[theApp.m_Options.LanguageName+"Header"].values["ExtensionName"]; + + m_pStream = fopen(tipsfile, "r"); + if (m_pStream == NULL) + { + m_strTip=GetLanguageStringACP("CG_IDS_FILE_ABSENT"); + return; + } + + //now check if the tips file is changed! (check the date the tips file was created) + struct _stat buf; + _fstat(_fileno(m_pStream), &buf); + CString strCurrentTime = ctime(&buf.st_ctime); + strCurrentTime.TrimRight(); + CString strStoredTime = optini.sections[szSection].values[szTimeStamp]; + if (strCurrentTime != strStoredTime) + { + iFilePos = 0; + optini.sections[szSection].values[szTimeStamp]=(LPCTSTR)strCurrentTime; + + } + + if (fseek(m_pStream, iFilePos, SEEK_SET) != 0) + { + AfxMessageBox(GetLanguageStringACP("CG_IDP_FILE_CORRUPT")); + } + else + { + GetNextTipString(m_strTip); + } + + optini.SaveFile(iniFile); +} + +CTipDlg::~CTipDlg() +{ + if (m_pStream != NULL) + { + + CIniFile optini; + CString iniFile; + + iniFile=AppPath; +#ifndef RA2_MODE + iniFile+="\\FinalSun.ini"; +#else + iniFile+="\\FinalAlert.ini"; +#endif + optini.LoadFile(iniFile); + + char val[50]; + itoa(ftell(m_pStream),val, 10); + optini.sections[szSection].values[szIntFilePos]=val; + optini.SaveFile(iniFile); + fclose(m_pStream); + } +} + +void CTipDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTipDlg) + DDX_Check(pDX, IDC_STARTUP, m_bStartup); + DDX_Text(pDX, IDC_TIPSTRING, m_strTip); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CTipDlg, CDialog) + //{{AFX_MSG_MAP(CTipDlg) + ON_BN_CLICKED(IDC_NEXTTIP, OnNextTip) + ON_WM_CTLCOLOR() + ON_WM_PAINT() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CTipDlg - handlers + +void CTipDlg::OnNextTip() +{ + GetNextTipString(m_strTip); + UpdateData(FALSE); +} + +void CTipDlg::GetNextTipString(CString& strNext) +{ + LPTSTR lpsz = strNext.GetBuffer(MAX_BUFLEN); + + BOOL bStop = FALSE; + while (!bStop) + { + if (_fgetts(lpsz, MAX_BUFLEN, m_pStream) == NULL) + { + if (fseek(m_pStream, 0, SEEK_SET) != 0) + AfxMessageBox(GetLanguageStringACP("CG_IDP_FILE_CORRUPT")); + } + else + { + if (*lpsz != ' ' && *lpsz != '\t' && + *lpsz != '\n' && *lpsz != ';') + { + bStop = TRUE; + } + } + } + strNext.ReleaseBuffer(); +} + +HBRUSH CTipDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (pWnd->GetDlgCtrlID() == IDC_TIPSTRING) + return (HBRUSH)GetStockObject(WHITE_BRUSH); + + return CDialog::OnCtlColor(pDC, pWnd, nCtlColor); +} + +void CTipDlg::OnOK() +{ + CDialog::OnOK(); + + // actualize startup + CIniFile optini; + CString iniFile; + + iniFile=AppPath; +#ifndef RA2_MODE + iniFile+="\\FinalSun.ini"; +#else + iniFile+="\\FinalAlert.ini"; +#endif + + optini.LoadFile(iniFile); + + char val[50]; + itoa(!m_bStartup,val, 10); + optini.sections[szSection].values[szIntStartup]=val; + optini.SaveFile(iniFile); +} + +BOOL CTipDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // deactivate next tip if no tips are present + if (m_pStream == NULL) + GetDlgItem(IDC_NEXTTIP)->EnableWindow(FALSE); + + SetDlgItemText(IDC_STARTUP, GetLanguageStringACP("TipDialogShowAtStartup")); + SetDlgItemText(IDC_NEXTTIP, GetLanguageStringACP("TipDialogNext")); + SetDlgItemText(IDOK, GetLanguageStringACP("TipDialogClose")); + SetWindowText(GetLanguageStringACP("TipDialogCaption")); + + return TRUE; +} + +void CTipDlg::OnPaint() +{ + CPaintDC dc(this); + + // prepare draw area for the big static rectangle + CWnd* pStatic = GetDlgItem(IDC_TOOLTIPCENTER); + CRect rect; + pStatic->GetWindowRect(&rect); + ScreenToClient(&rect); + + // draw white background + CBrush brush; + brush.CreateStockObject(WHITE_BRUSH); + dc.FillRect(rect, &brush); + + // load bitmap + CBitmap bmp; + bmp.LoadBitmap(IDB_LIGHTBULB); + BITMAP bmpInfo; + bmp.GetBitmap(&bmpInfo); + + // draw bitmap in the left corner + CDC dcTmp; + dcTmp.CreateCompatibleDC(&dc); + dcTmp.SelectObject(&bmp); + rect.bottom = bmpInfo.bmHeight + rect.top; + dc.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), + &dcTmp, 0, 0, SRCCOPY); + + // draw "Did you know" in the correct language + CString strMessage; + strMessage=GetLanguageStringACP("CG_IDS_DIDYOUKNOW"); + rect.left += bmpInfo.bmWidth; + dc.DrawText(strMessage, rect, DT_VCENTER | DT_SINGLELINE); + + +} + diff --git a/MissionEditor/TipDlg.h b/MissionEditor/TipDlg.h new file mode 100644 index 0000000..bccf4a4 --- /dev/null +++ b/MissionEditor/TipDlg.h @@ -0,0 +1,69 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(TIPDLG_H_INCLUDED_) +#define TIPDLG_H_INCLUDED_ + +// CG: Diese Datei wurde von der Komponente "Tipps und Tricks" hinzugefĂ¼gt + +///////////////////////////////////////////////////////////////////////////// +// CTipDlg Dialogfeld + +class CTipDlg : public CDialog +{ +// Konstruktion +public: + CTipDlg(CWnd* pParent = NULL); // Standard-Konstruktor + +// Dialogfelddaten + //{{AFX_DATA(CTipDlg) + enum { IDD = IDD_TIP }; + BOOL m_bStartup; + CString m_strTip; + //}}AFX_DATA + + FILE* m_pStream; + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte Ăœberschreibungen virtueller Funktionen + //{{AFX_VIRTUAL(CTipDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +public: + virtual ~CTipDlg(); + +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTipDlg) + afx_msg void OnNextTip(); + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + virtual void OnOK(); + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + void GetNextTipString(CString& strNext); +}; + +#endif // !defined(TIPDLG_H_INCLUDED_) diff --git a/MissionEditor/ToolSettingsBar.cpp b/MissionEditor/ToolSettingsBar.cpp new file mode 100644 index 0000000..d6a65e3 --- /dev/null +++ b/MissionEditor/ToolSettingsBar.cpp @@ -0,0 +1,142 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// ToolSettingsBar.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "ToolSettingsBar.h" +#include "FinalSunDlg.h" +#include "mapdata.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CToolSettingsBar + + +CToolSettingsBar::CToolSettingsBar(CWnd* pParent /*=NULL*/) + : CDialogBar() +{ + //{{AFX_DATA_INIT(CToolSettingsBar) + m_BrushSize = 0; + //}}AFX_DATA_INIT +} + + +void CToolSettingsBar::DoDataExchange(CDataExchange* pDX) +{ + CDialogBar::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CToolSettingsBar) + DDX_CBIndex(pDX, IDC_BRUSHSIZE, m_BrushSize); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CToolSettingsBar, CDialogBar) + //{{AFX_MSG_MAP(CToolSettingsBar) + ON_CBN_SELCHANGE(IDC_BRUSHSIZE, OnSelchangeBrushsize) + ON_WM_SHOWWINDOW() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CToolSettingsBar + + + +void CToolSettingsBar::OnSelchangeBrushsize() +{ + + UpdateData(TRUE); + + int bx,by; + + switch(m_BrushSize) + { + case 0: + bx=1; + by=1; + break; + case 1: + bx=2; + by=2; + break; + case 2: + bx=3; + by=3; + break; + case 3: + bx=4; + by=4; + break; + case 4: + bx=5; + by=5; + break; + case 5: + bx=10; + by=10; + break; + case 6: + bx=1; + by=2; + break; + case 7: + bx=2; + by=1; + break; + case 8: + bx=1; + by=3; + break; + case 9: + bx=3; + by=1; + break; + } + + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_x=bx; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_y=by; +} + +BOOL CToolSettingsBar::OnInitDialog() +{ + m_BrushSize=0; + UpdateData(FALSE); + + ((CComboBox*)GetDlgItem(IDC_BRUSHSIZE))->SetCurSel(0); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CToolSettingsBar::OnShowWindow(BOOL bShow, UINT nStatus) +{ + CDialogBar::OnShowWindow(bShow, nStatus); + + UpdateData(FALSE); +} diff --git a/MissionEditor/ToolSettingsBar.h b/MissionEditor/ToolSettingsBar.h new file mode 100644 index 0000000..81daa98 --- /dev/null +++ b/MissionEditor/ToolSettingsBar.h @@ -0,0 +1,68 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TOOLSETTINGSBAR_H__582DFEA1_7F44_11D4_9C87_F809D2CDBE4A__INCLUDED_) +#define AFX_TOOLSETTINGSBAR_H__582DFEA1_7F44_11D4_9C87_F809D2CDBE4A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ToolSettingsBar.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CToolSettingsBar + +class CToolSettingsBar : public CDialogBar +{ +// Konstruktion +public: + CToolSettingsBar(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CToolSettingsBar) + enum { IDD = IDD_TOOLSETTINGS }; + int m_BrushSize; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CToolSettingsBar) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CToolSettingsBar) + afx_msg void OnSelchangeBrushsize(); + virtual BOOL OnInitDialog(); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TOOLSETTINGSBAR_H__582DFEA1_7F44_11D4_9C87_F809D2CDBE4A__INCLUDED_ diff --git a/MissionEditor/Trees.cpp b/MissionEditor/Trees.cpp new file mode 100644 index 0000000..d27c7c5 --- /dev/null +++ b/MissionEditor/Trees.cpp @@ -0,0 +1,275 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Trees.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "TiberianSun Mission Editor.h" +#include "Trees.h" +#include "pos.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CTrees + +IMPLEMENT_DYNCREATE(CTrees, CPropertyPage) + +CTrees::CTrees() : CPropertyPage(CTrees::IDD) +{ + //{{AFX_DATA_INIT(CTrees) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + +CTrees::~CTrees() +{ +} + +void CTrees::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTrees) + DDX_Control(pDX, IDC_POS, m_Pos); + DDX_Control(pDX, IDC_TYPE, m_Type); + DDX_Control(pDX, IDC_TREELIST, m_TreeList); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTrees, CPropertyPage) + //{{AFX_MSG_MAP(CTrees) + ON_LBN_SELCHANGE(IDC_TREELIST, OnSelchangeTreelist) + ON_CBN_EDITCHANGE(IDC_TYPE, OnEditchangeType) + ON_CBN_KILLFOCUS(IDC_TYPE, OnKillfocusType) + ON_WM_KILLFOCUS() + ON_WM_SHOWWINDOW() + ON_BN_CLICKED(IDC_DELETE, OnDelete) + ON_CBN_SELCHANGE(IDC_TYPE, OnEditchangeType) + ON_BN_CLICKED(IDC_NEW, OnNew) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTrees + +void CTrees::UpdateDialog() +{ + m_TreeList.SetRedraw(FALSE); + + // first clear the list + while(m_TreeList.DeleteString(0)!=LB_ERR); + + // okay add all trees + + int i; + CIniFileSection& sec=ini.sections["Terrain"]; + + + for(i=0;i<sec.values.size();i++) + { + CString str; + str=sec.GetValueName(i)->data(); + + int pos=atoi(str); + + str+=(CString)" "+ sec.GetValue(i)->data(); + int x,y,z; + GetXYPos((char*)sec.GetValueName(i)->data(), &x, &y); + char c[50]; + itoa(x, c, 10); + str+=" ("; + str+=c; + str+="/"; + itoa(y, c, 10); + str+=c; + + z=GetPos(x,y,0); + + itoa(z, c, 10); + str+="/"; + str+=c; + str+=")"; + + m_TreeList.InsertString(-1, str); + + } + + m_TreeList.SetRedraw(TRUE); + m_TreeList.RedrawWindow(); +} + +BOOL CTrees::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + + // TODO: Zusätzliche Initialisierung hier einfĂ¼gen + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CTrees::OnSelchangeTreelist() +{ + int i=m_TreeList.GetCurSel(); + + CString str; + m_TreeList.GetText(i, str); + + str.SetAt(str.Find(" ", 0),0); + + m_Type.SetWindowText( ini.sections["Terrain"].values[ (char*)(LPCTSTR)str ].data() ); + + string pos; + int x,y,z; + GetXYPos((char*)ini.sections["Terrain"].GetValueName(i)->data(), &x, &y); + + char c[50]; + itoa(x, c, 10); + pos=c; + pos+="/"; + itoa(y, c, 10); + pos+=c; + pos+="/"; + itoa(z, c, 10); + pos+=c; + + m_Pos.SetWindowText(pos.data()); + +} + +void CTrees::OnEditchangeType() +{ + + + +} + +void CTrees::OnKillfocusType() +{ + int i=m_TreeList.GetCurSel(); + + if(i==-1) return; + + m_TreeList.SetRedraw(FALSE); + + CString str; + m_TreeList.GetText(i, str); + + str.SetAt(str.Find(" ", 0),0); + + + CString type; + m_Type.GetWindowText(type); + + if(ini.sections["Terrain"].values[(char*)(LPCTSTR)str]==(char*)(LPCTSTR)type) return; + + ini.sections["Terrain"].values[(char*)(LPCTSTR)str]=type; + + UpdateDialog(); + + m_TreeList.SetCurSel(i); + CTrees::OnSelchangeTreelist(); + + /*String str_=str; + //str_=ini.sections["Terrain"].GetValueName(i)->data(); + + //int pos=atoi(str_); + + str_+=(CString)" "+ ini.sections["Terrain"].values[(char*)(LPCTSTR)str].data(); + int x,y; + GetXYPos(atoi(str), x, y); + char c[50]; + itoa(x, c, 10); + str_+=" ("; + str_+=c; + str_+="/"; + itoa(y, c, 10); + str_+=c; + str_+=")"; + + m_TreeList.DeleteString(i); + m_TreeList.InsertString(i, str_);*/ + + + + m_TreeList.SetRedraw(TRUE); + m_TreeList.RedrawWindow(); + m_TreeList.SetCurSel(i); +} + +void CTrees::OnKillFocus(CWnd* pNewWnd) +{ + CPropertyPage::OnKillFocus(pNewWnd); + + + + +} + +void CTrees::OnShowWindow(BOOL bShow, UINT nStatus) +{ + CPropertyPage::OnShowWindow(bShow, nStatus); + + OnKillfocusType(); +} + +void CTrees::OnDelete() +{ + int pos=m_TreeList.GetCurSel(); + if(pos==-1) return; + + CString cutree; + //m_TreeList.GetText(pos, cutree); + cutree=ini.sections["Terrain"].GetValueName(pos)->data(); + + ini.sections["Terrain"].values.erase((string)(char*)(LPCTSTR) cutree); + + //m_TreeList.SetRedraw(FALSE); + UpdateDialog(); + m_TreeList.SetCurSel(pos); + //m_TreeList.SetRedraw(TRUE); + + +} + +void CTrees::OnNew() +{ + int pos=m_TreeList.GetCurSel(); + + CPos p; + if(p.DoModal()==IDCANCEL) return; + + int h=GetPos(atoi(p.m_x), atoi(p.m_y), 0); + + char k[50]; + itoa(h, k, 10); + + ini.sections["Terrain"].values[k]="TREE01"; + + UpdateDialog(); + m_TreeList.SetCurSel(pos); + +} diff --git a/MissionEditor/Trees.h b/MissionEditor/Trees.h new file mode 100644 index 0000000..2c35dad --- /dev/null +++ b/MissionEditor/Trees.h @@ -0,0 +1,79 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TREES_H__8ACDE600_72AB_11D3_99E1_95E76FDD1C05__INCLUDED_) +#define AFX_TREES_H__8ACDE600_72AB_11D3_99E1_95E76FDD1C05__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Trees.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTrees + +class CTrees : public CPropertyPage +{ + DECLARE_DYNCREATE(CTrees) + +// Konstruktion +public: + void UpdateDialog(); + CTrees(); + ~CTrees(); + +// Dialogfelddaten + //{{AFX_DATA(CTrees) + enum { IDD = IDD_TREES }; + CEdit m_Pos; + CComboBox m_Type; + CListBox m_TreeList; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTrees) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTrees) + virtual BOOL OnInitDialog(); + afx_msg void OnSelchangeTreelist(); + afx_msg void OnEditchangeType(); + afx_msg void OnKillfocusType(); + afx_msg void OnKillFocus(CWnd* pNewWnd); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + afx_msg void OnDelete(); + afx_msg void OnNew(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TREES_H__8ACDE600_72AB_11D3_99E1_95E76FDD1C05__INCLUDED_ diff --git a/MissionEditor/TriggerActionsDlg.cpp b/MissionEditor/TriggerActionsDlg.cpp new file mode 100644 index 0000000..c1f2e20 --- /dev/null +++ b/MissionEditor/TriggerActionsDlg.cpp @@ -0,0 +1,567 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TriggerActionsDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "TriggerActionsDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + +CString GetWaypoint(int n); +int GetWaypoint(const char* c); + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + +BOOL IsWaypointFormat(CString s) +{ + if(s.GetLength()==0) return TRUE; + + if(s[0]>='A' && s[0]<='Z') + return TRUE; + + return FALSE; + +} + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTriggerActionsDlg + + +CTriggerActionsDlg::CTriggerActionsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CTriggerActionsDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTriggerActionsDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + + +void CTriggerActionsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTriggerActionsDlg) + DDX_Control(pDX, IDC_PARAMVALUE, m_ParamValue); + DDX_Control(pDX, IDC_PARAMETER, m_Parameter); + DDX_Control(pDX, IDC_ACTIONTYPE, m_ActionType); + DDX_Control(pDX, IDC_ACTIONDESCRIPTION, m_ActionDescription); + DDX_Control(pDX, IDC_ACTION, m_Action); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTriggerActionsDlg, CDialog) + //{{AFX_MSG_MAP(CTriggerActionsDlg) + ON_CBN_SELCHANGE(IDC_ACTION, OnSelchangeAction) + ON_CBN_EDITCHANGE(IDC_ACTIONTYPE, OnEditchangeActiontype) + ON_LBN_SELCHANGE(IDC_PARAMETER, OnSelchangeParameter) + ON_CBN_EDITCHANGE(IDC_PARAMVALUE, OnEditchangeParamvalue) + ON_BN_CLICKED(IDC_NEWACTION, OnNewaction) + ON_BN_CLICKED(IDC_DELETEACTION, OnDeleteaction) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTriggerActionsDlg + +void CTriggerActionsDlg::OnSelchangeAction() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + int selev=m_Action.GetCurSel(); + if(selev<0) return; + int curev=m_Action.GetItemData(selev); + + + int i; + + CString ActionData; + ActionData=ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]; + + int startpos=1+curev*8; + CString ActionType=GetParam(ActionData,startpos); + m_ActionType.SetWindowText(ActionType); + for(i=0;i<m_ActionType.GetCount();i++) + { + CString tmp; + m_ActionType.GetLBText(i,tmp); + TruncSpace(tmp); + if(tmp==ActionType) + m_ActionType.SetCurSel(i); + } + + OnEditchangeActiontype(); + +} + +void CTriggerActionsDlg::OnEditchangeActiontype() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + int selev=m_Action.GetCurSel(); + if(selev<0) return; + int curev=m_Action.GetItemData(selev); + + CString e1,e2; + while(m_Parameter.DeleteString(0)!=CB_ERR); + + + CString eventtype,eventdata; + m_ActionType.GetWindowText(eventtype); + TruncSpace(eventtype); + + if(eventtype.GetLength()==0) + { + eventtype="0"; + m_ActionType.SetWindowText(eventtype); + } + + + CString acsec="Actions"; +#ifdef RA2_MODE + acsec="ActionsRA2"; +#endif + + + int pos=1+8*curev; + + ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos, (LPCTSTR)eventtype); + + if(g_data.sections[acsec].FindName(eventtype)<0) return; + + eventdata=g_data.sections[acsec].values[eventtype]; + +#ifdef RA2_MODE + if(g_data.sections["ActionsRA2"].FindName(eventtype)>=0) + eventdata=g_data.sections["ActionsRA2"].values[eventtype]; +#endif + + CString desc=GetParam(eventdata,10); + desc.Replace("%1",","); + m_ActionDescription.SetWindowText(desc); + + CString ptype[6]; + ptype[0]=GetParam(eventdata,1); + ptype[1]=GetParam(eventdata,2); + ptype[2]=GetParam(eventdata,3); + ptype[3]=GetParam(eventdata,4); + ptype[4]=GetParam(eventdata,5); + ptype[5]=GetParam(eventdata,6); + + int pListType[6]; + memset(pListType, 0, 6*sizeof(int)); + + if(atoi(ptype[0])>=0) pListType[0]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[0]], 1)); + if(atoi(ptype[1])>=0) pListType[1]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[1]], 1)); + if(atoi(ptype[2])>=0) pListType[2]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[2]], 1)); + if(atoi(ptype[3])>=0) pListType[3]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[3]], 1)); + if(atoi(ptype[4])>=0) pListType[4]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[4]], 1)); + if(atoi(ptype[5])>=0) pListType[5]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[5]], 1)); + + int i; + for(i=0;i<6;i++) + { + + if(atoi(ptype[i])>0) + { + CString paramname=GetParam(g_data.sections["ParamTypes"].values[ptype[i]], 0); + + m_Parameter.SetItemData(m_Parameter.AddString(paramname), i); + } + else if(atoi(ptype[i])<0) + { + char c[50]; + itoa(-atoi(ptype[i]),c,10); + ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos+i+1,c ); + } + else + { + ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos+i+1, "0"); + } + + } + + // MW fix for waypoint/number issue + CString code; + BOOL bNoWP=FALSE; + code=GetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos+1); + if(g_data.sections["DontSaveAsWP"].FindValue(code)>=0) bNoWP=TRUE; + + // conversion below: + if(IsWaypointFormat(GetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos+1+6)) && bNoWP) + { + int number=GetWaypoint(GetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos+1+6)); + char c[50]; + itoa(number, c, 10); + ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos+1+6, c); + } + else if(!IsWaypointFormat(GetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos+1+6)) && !bNoWP) + { + int wp=atoi(GetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos+1+6)); + CString s=GetWaypoint(wp); + ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos+1+6, s); + + } + + + if(atoi(GetParam(eventdata, 7))==1) + { + if(bNoWP) + m_Parameter.SetItemData(m_Parameter.AddString(TranslateStringACP("Number")), -1); + else + m_Parameter.SetItemData(m_Parameter.AddString(TranslateStringACP("Waypoint")), -1); + } + + m_ParamValue.SetWindowText(""); + if(m_Parameter.GetCount()>0) { + m_Parameter.SetCurSel(0); + OnSelchangeParameter(); + } +} + +void CTriggerActionsDlg::OnSelchangeParameter() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + int selev=m_Action.GetCurSel(); + if(selev<0) return; + int curev=m_Action.GetItemData(selev); + + int curselparam=m_Parameter.GetCurSel(); + if(curselparam<0) + { + m_ParamValue.SetWindowText(""); + return; + } + + + + int curparam=m_Parameter.GetItemData(curselparam); + + + + CString ActionData; + ActionData=ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]; + + + int startpos=1+curev*8; + + CString code; + BOOL bNoWP=FALSE; + code=GetParam(ActionData, startpos+1); + if(g_data.sections["DontSaveAsWP"].FindValue(code)>=0) bNoWP=TRUE; + + if(curparam>=0 && curparam<6) + { + CString ParamType=GetParam(g_data.sections["Actions"].values[GetParam(ActionData,startpos)],1+curparam); +#ifdef RA2_MODE + if(g_data.sections["ActionsRA2"].FindName(GetParam(ActionData, startpos))>=0) + { + ParamType=GetParam(g_data.sections["ActionsRA2"].values[GetParam(ActionData,startpos)],1+curparam); + } +#endif + if(atoi(ParamType)<0) + { + } + else + { + CString ListType=GetParam(g_data.sections["ParamTypes"].values[ParamType],1); + HandleParamList(m_ParamValue, atoi(ListType)); + m_ParamValue.SetWindowText(GetParam(ActionData,startpos+1+curparam)); + + int i; + BOOL bFound=FALSE; + for(i=0;i<m_ParamValue.GetCount();i++) + { + CString tmp; + m_ParamValue.GetLBText(i,tmp); + TruncSpace(tmp); + if(tmp==GetParam(ActionData,startpos+1+curparam)) + { + m_ParamValue.SetCurSel(i); + bFound=TRUE; + break; + } + } + + /*if(!bFound) + { + // not found, change it... + + if(m_ParamValue.GetCount()) { + m_ParamValue.SetCurSel(0); + OnEditchangeParamvalue(); + } + else + { + // not numeric value? + + CString p=GetParam(ActionData,startpos+1+curparam); + char c[50]; + itoa(atoi(p), c, 10); + if(c!=p) { + m_ParamValue.SetWindowText("0"); + OnEditchangeParamvalue(); + } + } + }*/ + } + } + else if(curparam==-1) + { + char wayp[50]; + if(!bNoWP) + { + ListWaypoints(m_ParamValue); + int iWayp=GetWaypoint(GetParam(ActionData,startpos+1+6)); + + itoa(iWayp, wayp, 10); + } + else + { + strcpy(wayp, GetParam(ActionData, startpos+1+6)); + HandleParamList(m_ParamValue, 0); + } + + + m_ParamValue.SetWindowText(wayp); + } +} + +void CTriggerActionsDlg::OnEditchangeParamvalue() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + int selev=m_Action.GetCurSel(); + if(selev<0) return; + int curev=m_Action.GetItemData(selev); + + int curselparam=m_Parameter.GetCurSel(); + if(curselparam<0) + { + m_ParamValue.SetWindowText(""); + return; + } + + int curparam=m_Parameter.GetItemData(curselparam); + + CString ActionData; + ActionData=ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]; + + int startpos=1+curev*8; + + + CString code; + BOOL bNoWP=FALSE; + code=GetParam(ActionData, startpos+1); + if(g_data.sections["DontSaveAsWP"].FindValue(code)>=0) bNoWP=TRUE; + + CString newVal; + m_ParamValue.GetWindowText(newVal); + TruncSpace(newVal); + newVal.TrimLeft(); + + if(newVal.Find(",",0)>=0) newVal.SetAt(newVal.Find(",",0), 0); + + if(curparam>=0) + { + ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]=SetParam(ActionData, startpos+1+curparam, newVal); + } + else if(curparam==-1) // waypoint FIX MW: OR NUMBER!!! + { + int pos=1+8*curev+7; + + + CString waypoint=newVal; + + if(!bNoWP) waypoint=GetWaypoint(atoi(newVal)); + + ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)m_currentTrigger], pos, (LPCTSTR)waypoint); + } + +} + +void CTriggerActionsDlg::OnNewaction() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + + + CIniFileSection& sec=ini.sections["Actions"]; + + int cval=atoi(GetParam(sec.values[(LPCTSTR)m_currentTrigger],0)); + cval++; + char c[50]; + itoa(cval,c,10); + + sec.values[(LPCTSTR)m_currentTrigger]=SetParam(sec.values[(LPCTSTR)m_currentTrigger],0,c); + sec.values[(LPCTSTR)m_currentTrigger]+=",0,0,0,0,0,0,0,A"; + + + UpdateDialog(); + + m_Action.SetCurSel(cval-1); + OnSelchangeAction(); +} + +void CTriggerActionsDlg::OnDeleteaction() +{ + CIniFile& ini=Map->GetIniFile(); + if(m_currentTrigger.GetLength()==0) return; + + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + int curev=m_Action.GetItemData(sel2); + if(MessageBox("Do you really want to delete this action?","Delete action", MB_YESNO)==IDNO) return; + + + CIniFileSection& sec=ini.sections["Actions"]; + + CString data; + data=sec.values[(LPCTSTR)m_currentTrigger]; + + int v=atoi(GetParam(data,0)); + char c[50]; + v--; + itoa(v,c,10); + data=SetParam(data,0, c); + + int pos=1+curev*8; + int posc=1+v*8; + int i; + for(i=0;i<8;i++) + data=SetParam(data,pos+i, GetParam(data,posc+i)); + + // MW April 17th, 2002: + // fixed: (char*)(LPCTSTR)data should not be modified directly, + // Instead, moving to a buffer + char* str_act=new(char[data.GetLength()+1]); + strcpy(str_act, (LPCSTR) data); + char* cupos=str_act;//(char*)(LPCTSTR)data; + for(i=0;i<posc;i++) + { + cupos=strchr(cupos+1, ','); + if(i==posc-1) + { + cupos[0]=0; + break; + } + } + //MessageBox(str_act); + + sec.values[(LPCTSTR)m_currentTrigger]=str_act; + delete[] str_act; + UpdateDialog(); + +} + +void CTriggerActionsDlg::UpdateDialog() +{ + // MW 07/20/01 + Clear(); + + if(m_currentTrigger.GetLength()==0) + { + while(m_Action.DeleteString(0)!=CB_ERR); + return; + } + + CIniFile& ini=Map->GetIniFile(); + + // 9.3.2001: Only support specified section +#ifndef RA2_MODE + CString sec="Actions"; +#else + CString sec="ActionsRA2"; +#endif + + while(m_ActionType.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<g_data.sections[sec].values.size();i++) + { + CString eventid=*g_data.sections[sec].GetValueName(i); //GetParam(*g_data.sections["Actions"].GetValue(i),13); + CString eventdata=*g_data.sections[sec].GetValue(i); +/*#ifdef RA2_MODE + if(g_data.sections["ActionsRA2"].FindName(eventid)>=0) + eventdata=g_data.sections["ActionsRA2"].values[eventid]; +#endif*/ + CString text=eventid+" "+GetParam(eventdata,0); + text.Replace("%1",","); + +#ifdef RA2_MODE + if(GetParam(eventdata,12)=="1" && (yuri_mode || !isTrue(GetParam(eventdata, 14)))) + { +#else + if(GetParam(eventdata,11)=="1") + { +#endif + m_ActionType.AddString(text); + } + } + + int cur_sel=m_Action.GetCurSel(); + while(m_Action.DeleteString(0)!=CB_ERR); + + CString Data=ini.sections["Actions"].values[m_currentTrigger]; + int count=atoi(GetParam(Data,0)); + + for(i=0;i<count;i++) + { + char c[50]; + itoa(i,c,10); + + CString s=TranslateStringACP("Action"); + s+=" "; + s+=c; + + m_Action.SetItemData(m_Action.AddString(s), i); + } + + if(cur_sel<0) cur_sel=0; + if(cur_sel>=count) cur_sel=count-1; + + m_Action.SetCurSel(cur_sel); + + + OnSelchangeAction(); +} + +// MW 07/20/01 +void CTriggerActionsDlg::Clear() +{ + m_ActionType.SetWindowText(""); + while(m_Parameter.DeleteString(0)!=LB_ERR); + m_ParamValue.SetWindowText(""); + m_ActionDescription.SetWindowText(""); +} diff --git a/MissionEditor/TriggerActionsDlg.h b/MissionEditor/TriggerActionsDlg.h new file mode 100644 index 0000000..ad213b8 --- /dev/null +++ b/MissionEditor/TriggerActionsDlg.h @@ -0,0 +1,78 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TRIGGERACTIONSDLG_H__234BEB21_96D7_11D4_9C87_E6A6DF12E04A__INCLUDED_) +#define AFX_TRIGGERACTIONSDLG_H__234BEB21_96D7_11D4_9C87_E6A6DF12E04A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TriggerActionsDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTriggerActionsDlg + +class CTriggerActionsDlg : public CDialog +{ +// Konstruktion +public: + void Clear(); + void UpdateDialog(); + CString m_currentTrigger; + CTriggerActionsDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CTriggerActionsDlg) + enum { IDD = IDD_TRIGGERACTIONS }; + CMyComboBox m_ParamValue; + CListBox m_Parameter; + CMyComboBox m_ActionType; + CEdit m_ActionDescription; + CComboBox m_Action; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTriggerActionsDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTriggerActionsDlg) + afx_msg void OnSelchangeAction(); + afx_msg void OnEditchangeActiontype(); + afx_msg void OnSelchangeParameter(); + afx_msg void OnEditchangeParamvalue(); + afx_msg void OnNewaction(); + afx_msg void OnDeleteaction(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TRIGGERACTIONSDLG_H__234BEB21_96D7_11D4_9C87_E6A6DF12E04A__INCLUDED_ diff --git a/MissionEditor/TriggerEditorDlg.cpp b/MissionEditor/TriggerEditorDlg.cpp new file mode 100644 index 0000000..e50af2e --- /dev/null +++ b/MissionEditor/TriggerEditorDlg.cpp @@ -0,0 +1,355 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TriggerEditorDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "TriggerEditorDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + +extern ACTIONDATA AD; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTriggerEditorDlg + + +CTriggerEditorDlg::CTriggerEditorDlg(CWnd* pParent /*=NULL*/) + : CDialog(CTriggerEditorDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTriggerEditorDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + + +void CTriggerEditorDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTriggerEditorDlg) + DDX_Control(pDX, IDC_TRIGGER, m_Trigger); + DDX_Control(pDX, IDC_TRIGGERTAB, m_tab); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTriggerEditorDlg, CDialog) + //{{AFX_MSG_MAP(CTriggerEditorDlg) + ON_BN_CLICKED(IDC_NEWTRIGGER, OnNewtrigger) + ON_BN_CLICKED(IDC_DELETETRIGGER, OnDeletetrigger) + ON_CBN_SELCHANGE(IDC_TRIGGER, OnSelchangeTrigger) + ON_CBN_EDITCHANGE(IDC_TRIGGER, OnEditchangeTrigger) + ON_NOTIFY(TCN_SELCHANGE, IDC_TRIGGERTAB, OnSelchangeTriggertab) + ON_BN_CLICKED(IDC_PLACEONMAP, OnPlaceonmap) + ON_BN_CLICKED(IDC_CLONE, OnClone) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTriggerEditorDlg + +void CTriggerEditorDlg::OnOK() +{ + +} + +void CTriggerEditorDlg::OnCancel() +{ + // TODO: Zusätzlichen Bereinigungscode hier einfĂ¼gen + + CDialog::OnCancel(); +} + +BOOL CTriggerEditorDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_tab.InsertItem(0, TranslateStringACP("Trigger options")); + m_tab.InsertItem(1, TranslateStringACP("Events")); + m_tab.InsertItem(2, TranslateStringACP("Actions")); + + m_TriggerOptions.Create(CTriggerOptionsDlg::IDD, &m_tab); + RECT r; + m_tab.GetItemRect(0, &r); + int top=m_tab.GetRowCount()*r.bottom+5; + m_tab.GetClientRect(&r); + int bottom=r.bottom-top-3; + m_TriggerOptions.SetWindowPos(NULL, 10, top, r.right-20, bottom, SWP_NOZORDER); + m_TriggerOptions.ShowWindow(SW_SHOW); + + m_TriggerEvents.Create(CTriggerEventsDlg::IDD, &m_tab); + m_TriggerEvents.SetWindowPos(NULL, 10, top, r.right-20, bottom, SWP_NOZORDER); + + m_TriggerActions.Create(CTriggerActionsDlg::IDD, &m_tab); + m_TriggerActions.SetWindowPos(NULL, 10, top, r.right-20, bottom, SWP_NOZORDER); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CTriggerEditorDlg::UpdateDialog() +{ + int i; + CIniFile& ini=Map->GetIniFile(); + + int curSel=m_Trigger.GetCurSel(); + int curData=-1; + if(curSel!=-1) + curData=m_Trigger.GetItemData(curSel); + + + while(m_Trigger.DeleteString(0)!=CB_ERR); + m_Trigger.SetWindowText(""); + + for(i=0;i<ini.sections["Triggers"].values.size();i++) + { + CString type; + CString s; + type=*ini.sections["Triggers"].GetValueName(i); + + s=GetParam(ini.sections["Triggers"].values[type], 2); + + if(ini.sections["Triggers"].values[type].GetLength()==0) continue; + + int id=m_Trigger.AddString(s); + m_Trigger.SetItemData(id, i); + } + + if(curData<0) curData=0; + if(curData>=m_Trigger.GetCount()) curData=m_Trigger.GetCount()-1; + + if(ini.sections["Triggers"].values.size()) m_Trigger.SetCurSel(0); + + for(i=0;i<m_Trigger.GetCount();i++) + if(m_Trigger.GetItemData(i)==curData) + { + m_Trigger.SetCurSel(i); + break; + } + + OnSelchangeTrigger(); +} + +void CTriggerEditorDlg::OnNewtrigger() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ID_T=GetFreeID(); + ini.sections["Triggers"].values[ID_T]=Map->GetHouseID(0, TRUE)+",<none>,New trigger,0,1,1,1,0"; + ini.sections["Events"].values[ID_T]="0"; + ini.sections["Actions"].values[ID_T]="0"; + + //if(MessageBox("Trigger created. If you want to create a simple tag now, press Yes. The tag will be called ""New tag"", you should name it like the trigger (after you have set up the trigger).","Trigger created",MB_YESNO)) + { + CString ID_TAG=GetFreeID(); + ini.sections["Tags"].values[ID_TAG]="0,New tag,"; + ini.sections["Tags"].values[ID_TAG]+=ID_T; + } + + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); + + int i; + for(i=0;i<m_Trigger.GetCount();i++) + { + if(m_Trigger.GetItemData(i)==ini.sections["Triggers"].FindName(ID_T)) + m_Trigger.SetCurSel(i); + } + OnSelchangeTrigger(); + +} + +void CTriggerEditorDlg::OnDeletetrigger() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int curtrig=m_Trigger.GetItemData(sel); + + int res=MessageBox("If you want to delete all attached tags, too, press 'Yes'.\nIf you don´t want to delete these tags, press 'No'.\nIf you want to cancel deletion of the trigger, press 'Cancel'.\n\nNote: CellTags will never be deleted using this function","Delete trigger", MB_YESNOCANCEL); + if(res==IDCANCEL) return; + + CString trigger=*ini.sections["Triggers"].GetValueName(curtrig); + + if(res==IDYES) + { + int i; + for(i=0;i<ini.sections["Tags"].values.size();i++) + { + CString type=*ini.sections["Tags"].GetValueName(i); + + CString attTrigg=GetParam(ini.sections["Tags"].values[type], 2); + + if(trigger==attTrigg) + { + ini.sections["Tags"].values.erase(type); + } + } + + } + + ini.sections["Triggers"].values.erase((LPCTSTR)trigger); + ini.sections["Events"].values.erase((LPCTSTR)trigger); + ini.sections["Actions"].values.erase((LPCTSTR)trigger); + + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); + +} + + + +void CTriggerEditorDlg::OnSelchangeTrigger() +{ + OnEditchangeTrigger(); +} + +void CTriggerEditorDlg::OnEditchangeTrigger() +{ + CIniFile& ini=Map->GetIniFile(); + + int curSel=m_Trigger.GetCurSel(); + if(curSel<0) + { + m_TriggerOptions.m_currentTrigger=""; + if(m_TriggerOptions.m_hWnd) m_TriggerOptions.UpdateDialog(); + m_TriggerEvents.m_currentTrigger=""; + if(m_TriggerEvents.m_hWnd) m_TriggerEvents.UpdateDialog(); + m_TriggerActions.m_currentTrigger=""; + if(m_TriggerActions.m_hWnd) m_TriggerActions.UpdateDialog(); + return; + } + + int curInd=m_Trigger.GetItemData(curSel); + + CString Trigger=*ini.sections["Triggers"].GetValueName(curInd); + + m_TriggerOptions.m_currentTrigger=Trigger; + if(m_TriggerOptions.m_hWnd) m_TriggerOptions.UpdateDialog(); + m_TriggerEvents.m_currentTrigger=Trigger; + if(m_TriggerEvents.m_hWnd) m_TriggerEvents.UpdateDialog(); + m_TriggerActions.m_currentTrigger=Trigger; + if(m_TriggerActions.m_hWnd) m_TriggerActions.UpdateDialog(); +} + +void CTriggerEditorDlg::OnSelchangeTriggertab(NMHDR* pNMHDR, LRESULT* pResult) +{ + m_TriggerEvents.ShowWindow(SW_HIDE); + m_TriggerOptions.ShowWindow(SW_HIDE); + m_TriggerActions.ShowWindow(SW_HIDE); + + switch(m_tab.GetCurSel()) + { + case 0: + m_TriggerOptions.ShowWindow(SW_SHOW); + m_TriggerOptions.UpdateDialog(); + break; + case 1: + m_TriggerEvents.ShowWindow(SW_SHOW); + m_TriggerEvents.UpdateDialog(); + break; + case 2: + m_TriggerActions.ShowWindow(SW_SHOW); + m_TriggerActions.UpdateData(); + break; + } + + *pResult = 0; +} + +void CTriggerEditorDlg::OnPlaceonmap() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int curtrig=m_Trigger.GetItemData(sel); + + CString trigger=*ini.sections["Triggers"].GetValueName(curtrig); + + int i; + CString tag; + for(i=0;i<ini.sections["Tags"].values.size();i++) + { + CString type=*ini.sections["Tags"].GetValueName(i); + + CString attTrigg=GetParam(ini.sections["Tags"].values[type], 2); + + if(trigger==attTrigg) + { + tag=type; + break; + } + } + + + AD.mode=ACTIONMODE_CELLTAG; + AD.type=4; + AD.data_s=tag; +} + +void CTriggerEditorDlg::OnClone() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int curtrig=m_Trigger.GetItemData(sel); + + CString trigger=*ini.sections["Triggers"].GetValueName(curtrig); + + CString ID_T=GetFreeID(); + ini.sections["Triggers"].values[ID_T]=ini.sections["Triggers"].values[trigger]; + ini.sections["Events"].values[ID_T]=ini.sections["Events"].values[trigger]; + ini.sections["Actions"].values[ID_T]=ini.sections["Actions"].values[trigger]; + + ini.sections["Triggers"].values[ID_T]=SetParam(ini.sections["Triggers"].values[ID_T], 2, GetParam(ini.sections["Triggers"].values[ID_T], 2) + " Clone"); + + { + CString ID_TAG=GetFreeID(); + ini.sections["Tags"].values[ID_TAG]=(CString)"0,"+GetParam(ini.sections["Triggers"].values[ID_T], 2)+","; + ini.sections["Tags"].values[ID_TAG]+=ID_T; + } + + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); + + int i; + for(i=0;i<m_Trigger.GetCount();i++) + { + if(m_Trigger.GetItemData(i)==ini.sections["Triggers"].FindName(ID_T)) + m_Trigger.SetCurSel(i); + } + OnSelchangeTrigger(); + +} + +void CTriggerEditorDlg::Clear() +{ + +} diff --git a/MissionEditor/TriggerEditorDlg.h b/MissionEditor/TriggerEditorDlg.h new file mode 100644 index 0000000..ae333e1 --- /dev/null +++ b/MissionEditor/TriggerEditorDlg.h @@ -0,0 +1,86 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TRIGGEREDITORDLG_H__E9CA56E1_93E6_11D4_9C87_F3E3AC59A04A__INCLUDED_) +#define AFX_TRIGGEREDITORDLG_H__E9CA56E1_93E6_11D4_9C87_F3E3AC59A04A__INCLUDED_ + +#include "TriggerOptionsDlg.h" // HinzugefĂ¼gt von der Klassenansicht +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TriggerEditorDlg.h : Header-Datei +// + +#include "MyComboBox.h" +#include "TriggerEventsDlg.h" // HinzugefĂ¼gt von der Klassenansicht +#include "TriggerActionsDlg.h" // HinzugefĂ¼gt von der Klassenansicht + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTriggerEditorDlg + +class CTriggerEditorDlg : public CDialog +{ +// Konstruktion +public: + void Clear(); + CTriggerActionsDlg m_TriggerActions; + CTriggerEventsDlg m_TriggerEvents; + CTriggerOptionsDlg m_TriggerOptions; + void UpdateDialog(); + CTriggerEditorDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CTriggerEditorDlg) + enum { IDD = IDD_TRIGGEREDITOR }; + CMyComboBox m_Trigger; + CTabCtrl m_tab; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTriggerEditorDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTriggerEditorDlg) + virtual void OnOK(); + virtual void OnCancel(); + virtual BOOL OnInitDialog(); + afx_msg void OnNewtrigger(); + afx_msg void OnDeletetrigger(); + afx_msg void OnSelchangeTrigger(); + afx_msg void OnEditchangeTrigger(); + afx_msg void OnSelchangeTriggertab(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnPlaceonmap(); + afx_msg void OnClone(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TRIGGEREDITORDLG_H__E9CA56E1_93E6_11D4_9C87_F3E3AC59A04A__INCLUDED_ diff --git a/MissionEditor/TriggerEventsDlg.cpp b/MissionEditor/TriggerEventsDlg.cpp new file mode 100644 index 0000000..79a51c9 --- /dev/null +++ b/MissionEditor/TriggerEventsDlg.cpp @@ -0,0 +1,588 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TriggerEventsDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "TriggerEventsDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTriggerEventsDlg + + +CTriggerEventsDlg::CTriggerEventsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CTriggerEventsDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTriggerEventsDlg) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + + +void CTriggerEventsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTriggerEventsDlg) + DDX_Control(pDX, IDC_PARAMVALUE, m_ParamValue); + DDX_Control(pDX, IDC_PARAMETER, m_Parameter); + DDX_Control(pDX, IDC_EVENTTYPE, m_EventType); + DDX_Control(pDX, IDC_EVENTDESCRIPTION, m_EventDescription); + DDX_Control(pDX, IDC_EVENT, m_Event); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTriggerEventsDlg, CDialog) + //{{AFX_MSG_MAP(CTriggerEventsDlg) + ON_BN_CLICKED(IDC_NEWEVENT, OnNewevent) + ON_BN_CLICKED(IDC_DELETEEVENT, OnDeleteevent) + ON_CBN_SELCHANGE(IDC_EVENT, OnSelchangeEvent) + ON_CBN_EDITCHANGE(IDC_EVENTTYPE, OnEditchangeEventtype) + ON_LBN_SELCHANGE(IDC_PARAMETER, OnSelchangeParameter) + ON_CBN_EDITCHANGE(IDC_PARAMVALUE, OnEditchangeParamvalue) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTriggerEventsDlg + +// MW 07/23/01: Added this because startpos=1+curev*3 isn´t anymore valid for calculating the next event +int GetEventParamStart(CString& EventData, int param) +{ + int count=atoi(GetParam(EventData, 0)); + if(param>=count) return -1; + + int pos=1; + int i; + for(i=0;i<param;i++) + { + pos+=1; // jump to first eventtype param + int needs=atoi(GetParam(EventData, pos)); + + pos+=2; // jump to next usual eventtype + if(needs==2) // if needs of last eventtype is 2, we need to add 1 + { + pos+=1; + } + } + + return pos; +} + +void CTriggerEventsDlg::OnNewevent() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + + + CIniFileSection& sec=ini.sections["Events"]; + + int cval=atoi(GetParam(sec.values[(LPCTSTR)m_currentTrigger],0)); + cval++; + char c[50]; + itoa(cval,c,10); + + sec.values[(LPCTSTR)m_currentTrigger]=SetParam(sec.values[(LPCTSTR)m_currentTrigger],0,c); + sec.values[(LPCTSTR)m_currentTrigger]+=",0,0,0"; + + + UpdateDialog(); + + m_Event.SetCurSel(cval-1); + OnSelchangeEvent(); +} + +int FindTokenX(CString data, char token, int n) +{ + if(n<=0) return -1; + + int found=0; + int pos=0; + while(found<n) + { + if(!pos) + pos=data.Find(token, 0); + else + pos=data.Find(token, pos+1); + if(pos<0) + { + return -1; + } + + found++; + } + + return pos; +} + +void CTriggerEventsDlg::OnDeleteevent() +{ + char d[50]; + //itoa(FindTokenX("0,1,2,3,4", ',', 3),d,10); + //MessageBox(d); + + CIniFile& ini=Map->GetIniFile(); + if(m_currentTrigger.GetLength()==0) return; + + int sel2=m_Event.GetCurSel(); + if(sel2<0) return; + int curev=m_Event.GetItemData(sel2); + if(MessageBox("Do you really want to delete this event?","Delete event", MB_YESNO)==IDNO) return; + + + CIniFileSection& sec=ini.sections["Events"]; + + CString data; + data=sec.values[(LPCTSTR)m_currentTrigger]; + + CString orig_data=data; + + int v=atoi(GetParam(data,0)); + char c[50]; + v--; + itoa(v,c,10); + data=SetParam(data,0, c); + + int pos=GetEventParamStart(orig_data, curev);//1+curev*3; + //int posc=GetEventParamStart(orig_data, v);//1+v*3; + + // MW 07/23/01: + // NEW DELETE EVENT CODE... + + // Now check for those 2 param + code events... + BOOL bEvent1Needs4=FALSE; + + + if(GetParam(data, pos+1)=="2") bEvent1Needs4=TRUE; + + int count=3; + if(bEvent1Needs4) count=4; + + int del_start=FindTokenX(data, ',', pos); + int del_end=FindTokenX(data, ',', pos+count); + if(del_end<0) + { + // beyond end, so delete all... + del_end=data.GetLength(); + + } + data.Delete(del_start, del_end-del_start); + + /* + old delete event code, that used replacement. Not possible anymore because of 4 values/event sometimes now + + int i; + for(i=0;i<3;i++) + data=SetParam(data,pos+i, GetParam(data,posc+i)); + + char* cupos=(char*)(LPCTSTR)data; + for(i=0;i<posc;i++) + { + cupos=strchr(cupos+1, ','); + if(i==posc-1) + { + cupos[0]=0; + break; + } + }*/ + + sec.values[(LPCTSTR)m_currentTrigger]=data; + UpdateDialog(); + +} + +void CTriggerEventsDlg::OnSelchangeEvent() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + int selev=m_Event.GetCurSel(); + if(selev<0) return; + int curev=m_Event.GetItemData(selev); + + + int i; + + CString EventData; + EventData=ini.sections["Events"].values[(LPCTSTR)m_currentTrigger]; + + int startpos=GetEventParamStart(EventData, curev); //1+curev*3; + CString EventType=GetParam(EventData,startpos); + m_EventType.SetWindowText(EventType); + for(i=0;i<m_EventType.GetCount();i++) + { + CString tmp; + m_EventType.GetLBText(i,tmp); + TruncSpace(tmp); + if(tmp==EventType) + m_EventType.SetCurSel(i); + } + + OnEditchangeEventtype(); +} + +void CTriggerEventsDlg::OnEditchangeEventtype() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + int selev=m_Event.GetCurSel(); + if(selev<0) return; + int curev=m_Event.GetItemData(selev); + + CString e1,e2; + while(m_Parameter.DeleteString(0)!=CB_ERR); + + + CString eventtype,eventdata; + m_EventType.GetWindowText(eventtype); + TruncSpace(eventtype); + + if(eventtype.GetLength()==0) + { + eventtype="0"; + m_EventType.SetWindowText(eventtype); + } + + int pos=GetEventParamStart(ini.sections["Events"].values[(LPCTSTR)m_currentTrigger], curev); //1+3*curev; + + BOOL bAlready4=FALSE; + if(atoi(GetParam(ini.sections["Events"].values[(LPCTSTR)m_currentTrigger], pos+1))==2) + bAlready4=TRUE; + + ini.sections["Events"].values[(LPCTSTR)m_currentTrigger]=SetParam(ini.sections["Events"].values[(LPCTSTR)m_currentTrigger], pos, (LPCTSTR)eventtype); + + + CString evsec="Events"; +#ifdef RA2_MODE + evsec="EventsRA2"; +#endif + + + if(g_data.sections[evsec].FindName(eventtype)<0) return; + eventdata=g_data.sections[evsec].values[eventtype]; + +#ifdef RA2_MODE + if(g_data.sections["EventsRA2"].FindName(eventtype)>=0) + eventdata=g_data.sections["EventsRA2"].values[eventtype]; +#endif + + CString desc=GetParam(eventdata,5); + desc.Replace("%1",","); + m_EventDescription.SetWindowText(desc); + + CString ptype[2]; + ptype[0]=GetParam(eventdata,1); + ptype[1]=GetParam(eventdata,2); + + + int pListType[2]; + pListType[0]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[0]], 1)); + pListType[1]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[1]], 1)); + + int code=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[0]], 2)); // usually 0 + + // ************************************** + // MW ADD SUPPORT FOR 2 PARAMS+CODE + if(code==2) + { + // add code + event 0 ONLY IF THEY DO NOT ALREADY EXIST + if(!bAlready4) ini.sections["Events"].values[(LPCTSTR)m_currentTrigger]=SetParam(ini.sections["Events"].values[(LPCTSTR)m_currentTrigger], pos+1, "2,0"); + + } + else + { + // remove code + event 0 + char c[50]; + itoa(code, c, 10); + ini.sections["Events"].values[(LPCTSTR)m_currentTrigger]=SetParam(ini.sections["Events"].values[(LPCTSTR)m_currentTrigger], pos+1, c); + + if(bAlready4) + { + + CString& data=ini.sections["Events"].values[(LPCTSTR)m_currentTrigger]; + + int del_start=FindTokenX(data, ',', pos+2); + int del_end=FindTokenX(data, ',', pos+3); + if(del_end<0) + { + // beyond end, so delete all... + del_end=data.GetLength(); + + } + data.Delete(del_start, del_end-del_start); + } + + } + // ************************************** + + int i; + for(i=0;i<2;i++) + { + int add=0; + if(code==2) add=1; + + if(atoi(ptype[i])!=0 && atoi(ptype[i])>0 && atoi(ptype[i])!=47) + { + CString paramname=GetParam(g_data.sections["ParamTypes"].values[ptype[i]], 0); + + m_Parameter.SetItemData(m_Parameter.AddString(paramname), i+add); + } + + + } + + m_ParamValue.SetWindowText(""); + if(m_Parameter.GetCount()>0) { + m_Parameter.SetCurSel(0); + OnSelchangeParameter(); + } + + + + RepairTrigger(ini.sections["Triggers"].values[m_currentTrigger]); + +} + + + +void CTriggerEventsDlg::OnSelchangeParameter() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + int selev=m_Event.GetCurSel(); + if(selev<0) return; + int curev=m_Event.GetItemData(selev); + + int curselparam=m_Parameter.GetCurSel(); + if(curselparam<0) + { + m_ParamValue.SetWindowText(""); + return; + } + + + + int curparam=m_Parameter.GetItemData(curselparam); + + + CString EventData; + EventData=ini.sections["Events"].values[(LPCTSTR)m_currentTrigger]; + + int startpos=GetEventParamStart(EventData, curev);//1+curev*3; + + + // MW FIX FOR CODE!=0 + int original_cuparam=curparam; +#ifdef RA2_MODE + CString Param1=GetParam(g_data.sections["EventsRA2"].values[GetParam(EventData,startpos)],1); + CString Code=GetParam(g_data.sections["ParamTypes"].values[Param1],2); + //MessageBox(Param1, Code); + if(atoi(Code)!=0) curparam--; +#endif + // END FIx + + CString ParamType=GetParam(g_data.sections["Events"].values[GetParam(EventData,startpos)],1+curparam); +#ifdef RA2_MODE + if(g_data.sections["EventsRA2"].FindName(GetParam(EventData, startpos))>=0) ParamType=GetParam(g_data.sections["EventsRA2"].values[GetParam(EventData,startpos)],1+curparam); +#endif + + if(atoi(ParamType)<0) + { + } + else + { + CString ListType=GetParam(g_data.sections["ParamTypes"].values[ParamType],1); + + HandleParamList(m_ParamValue, atoi(ListType)); + m_ParamValue.SetWindowText(GetParam(EventData,startpos+1+original_cuparam)); + + int i; + BOOL bFound=FALSE; + for(i=0;i<m_ParamValue.GetCount();i++) + { + CString tmp; + m_ParamValue.GetLBText(i,tmp); + TruncSpace(tmp); + if(tmp==GetParam(EventData,startpos+1+original_cuparam)) + { + m_ParamValue.SetCurSel(i); + bFound=TRUE; + break; + } + } + + /*if(!bFound) + { + // not found, change it... + + if(m_ParamValue.GetCount()) { + m_ParamValue.SetCurSel(0); + OnEditchangeParamvalue(); + } + else + { + // not numeric value? + + CString p=GetParam(EventData,startpos+1+original_cuparam); + char c[50]; + itoa(atoi(p), c, 10); + if(c!=p) { + m_ParamValue.SetWindowText("0"); + OnEditchangeParamvalue(); + } + } + }*/ + } +} + +void CTriggerEventsDlg::OnEditchangeParamvalue() +{ + CIniFile& ini=Map->GetIniFile(); + + if(m_currentTrigger.GetLength()==0) return; + int selev=m_Event.GetCurSel(); + if(selev<0) return; + int curev=m_Event.GetItemData(selev); + + int curselparam=m_Parameter.GetCurSel(); + if(curselparam<0) + { + m_ParamValue.SetWindowText(""); + return; + } + + int curparam=m_Parameter.GetItemData(curselparam); + + CString EventData; + EventData=ini.sections["Events"].values[(LPCTSTR)m_currentTrigger]; + + int startpos=GetEventParamStart(EventData, curev);// 1+curev*3; + + + CString newVal; + m_ParamValue.GetWindowText(newVal); + TruncSpace(newVal); + newVal.TrimLeft(); + + if(newVal.Find(",",0)>=0) newVal.SetAt(newVal.Find(",",0), 0); + + ini.sections["Events"].values[(LPCTSTR)m_currentTrigger]=SetParam(EventData, startpos+1+curparam, newVal); +} + +void CTriggerEventsDlg::UpdateDialog() +{ + // MW 07/20/01 + Clear(); + + if(m_currentTrigger.GetLength()==0) + { + while(m_Event.DeleteString(0)!=CB_ERR); + return; + } + CIniFile& ini=Map->GetIniFile(); + + while(m_EventType.DeleteString(0)!=CB_ERR); + int i; + + //9.3.2001: Only use specified section, do not merge +#ifndef RA2_MODE + CString sec="Events"; +#else + CString sec="EventsRA2"; +#endif + + for(i=0;i<g_data.sections[sec].values.size();i++) + { + CString eventid = *g_data.sections[sec].GetValueName(i); //GetParam(*g_data.sections["Events"].GetValue(i),8); + CString eventdata=*g_data.sections[sec].GetValue(i); +/*#ifdef RA2_MODE + if(g_data.sections["EventsRA2"].FindName(eventid)>=0) + eventdata=g_data.sections["EventsRA2"].values[eventid]; +#endif*/ + + CString text=eventid+" "+GetParam(eventdata,0); + text.Replace("%1",","); +#ifdef RA2_MODE + // MW 07/18/01 + // for yuri mode, only check if it´s for RA2, else support it only if YR isnt´needed... + if(GetParam(eventdata, 7)=="1" && ( yuri_mode || !atoi(GetParam(eventdata,9)) ) ) + { + + +#else + if(GetParam(eventdata, 6)=="1") + { +#endif + m_EventType.AddString(text); + } + } + + + + int cur_sel=m_Event.GetCurSel(); + while(m_Event.DeleteString(0)!=CB_ERR); + + CString Data=ini.sections["Events"].values[m_currentTrigger]; + int count=atoi(GetParam(Data,0)); + + for(i=0;i<count;i++) + { + char c[50]; + itoa(i,c,10); + + CString s=TranslateStringACP("Event"); + s+=" "; + s+=c; + + m_Event.SetItemData(m_Event.AddString(s), i); + } + + if(cur_sel<0) cur_sel=0; + if(cur_sel>=count) cur_sel=count-1; + + m_Event.SetCurSel(cur_sel); + + + OnSelchangeEvent(); +} + +// MW 07/20/01 +void CTriggerEventsDlg::Clear() +{ + m_EventType.SetWindowText(""); + while(m_Parameter.DeleteString(0)!=LB_ERR); + m_ParamValue.SetWindowText(""); + m_EventDescription.SetWindowText(""); +} diff --git a/MissionEditor/TriggerEventsDlg.h b/MissionEditor/TriggerEventsDlg.h new file mode 100644 index 0000000..5345a04 --- /dev/null +++ b/MissionEditor/TriggerEventsDlg.h @@ -0,0 +1,80 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TRIGGEREVENTSDLG_H__13CDEBA1_961C_11D4_9C87_BD9803B9B54A__INCLUDED_) +#define AFX_TRIGGEREVENTSDLG_H__13CDEBA1_961C_11D4_9C87_BD9803B9B54A__INCLUDED_ + +#include "resource.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TriggerEventsDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTriggerEventsDlg + +class CTriggerEventsDlg : public CDialog +{ +// Konstruktion +public: + void Clear(); + CString m_currentTrigger; + void UpdateDialog(); + CTriggerEventsDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CTriggerEventsDlg) + enum { IDD = IDD_TRIGGEREVENTS }; + CMyComboBox m_ParamValue; + CListBox m_Parameter; + CMyComboBox m_EventType; + CEdit m_EventDescription; + CComboBox m_Event; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTriggerEventsDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTriggerEventsDlg) + afx_msg void OnNewevent(); + afx_msg void OnDeleteevent(); + afx_msg void OnSelchangeEvent(); + afx_msg void OnEditchangeEventtype(); + afx_msg void OnSelchangeParameter(); + afx_msg void OnEditchangeParamvalue(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TRIGGEREVENTSDLG_H__13CDEBA1_961C_11D4_9C87_BD9803B9B54A__INCLUDED_ diff --git a/MissionEditor/TriggerOptionsDlg.cpp b/MissionEditor/TriggerOptionsDlg.cpp new file mode 100644 index 0000000..3c40214 --- /dev/null +++ b/MissionEditor/TriggerOptionsDlg.cpp @@ -0,0 +1,357 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// TriggerOptionsDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "TriggerOptionsDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTriggerOptionsDlg + + +CTriggerOptionsDlg::CTriggerOptionsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CTriggerOptionsDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTriggerOptionsDlg) + //}}AFX_DATA_INIT +} + + +void CTriggerOptionsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTriggerOptionsDlg) + DDX_Control(pDX, IDC_MEDIUM, m_Medium); + DDX_Control(pDX, IDC_HARD, m_Hard); + DDX_Control(pDX, IDC_EASY, m_Easy); + DDX_Control(pDX, IDC_DISABLED, m_Disabled); + DDX_Control(pDX, IDC_TRIGGERTYPE, m_TriggerType); + DDX_Control(pDX, IDC_NAME, m_Name); + DDX_Control(pDX, IDC_HOUSE, m_House); + DDX_Control(pDX, IDC_ATTACHEDTRIGGER, m_AttachedTrigger); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTriggerOptionsDlg, CDialog) + //{{AFX_MSG_MAP(CTriggerOptionsDlg) + ON_EN_CHANGE(IDC_NAME, OnChangeName) + ON_CBN_EDITCHANGE(IDC_HOUSE, OnEditchangeHouse) + ON_CBN_EDITCHANGE(IDC_ATTACHEDTRIGGER, OnEditchangeAttachedtrigger) + ON_EN_KILLFOCUS(IDC_NAME, OnKillfocusName) + ON_WM_KILLFOCUS() + ON_CBN_EDITCHANGE(IDC_TRIGGERTYPE, OnEditchangeTriggertype) + ON_BN_CLICKED(IDC_DISABLED, OnDisabled) + ON_BN_CLICKED(IDC_EASY, OnEasy) + ON_BN_CLICKED(IDC_MEDIUM, OnMedium) + ON_BN_CLICKED(IDC_HARD, OnHard) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTriggerOptionsDlg + +void CTriggerOptionsDlg::UpdateDialog() +{ + // MW 07/20/01 + + CIniFile& ini=Map->GetIniFile(); + if(m_currentTrigger.GetLength()==0) return; + + ListHouses(m_House, FALSE, TRUE, FALSE); + ListTriggers(m_AttachedTrigger); + m_AttachedTrigger.InsertString(0, "<none>"); + + RepairTrigger(ini.sections["Triggers"].values[m_currentTrigger]); + + m_Name.SetWindowText(GetParam(ini.sections["Triggers"].values[m_currentTrigger],2)); + m_House.SetWindowText(TranslateHouse(GetParam(ini.sections["Triggers"].values[m_currentTrigger],0), TRUE)); + CString attachedTrigger=GetParam(ini.sections["Triggers"].values[m_currentTrigger],1); + m_AttachedTrigger.SetWindowText(attachedTrigger); + + m_Disabled.SetCheck((atoi(GetParam(ini.sections["Triggers"].values[m_currentTrigger],3)))); + m_Easy.SetCheck((atoi(GetParam(ini.sections["Triggers"].values[m_currentTrigger],4)))); + m_Medium.SetCheck((atoi(GetParam(ini.sections["Triggers"].values[m_currentTrigger],5)))); + m_Hard.SetCheck((atoi(GetParam(ini.sections["Triggers"].values[m_currentTrigger],6)))); + + int i; + for(i=0;i<m_AttachedTrigger.GetCount();i++) + { + CString tmp; + m_AttachedTrigger.GetLBText(i,tmp); + TruncSpace(tmp); + if(tmp==attachedTrigger) + m_AttachedTrigger.SetCurSel(i); + } + + for(i=0;i<ini.sections["Tags"].values.size();i++) + { + CString type=*ini.sections["Tags"].GetValueName(i); + + CString attTrigg=GetParam(ini.sections["Tags"].values[type], 2); + if(attTrigg==m_currentTrigger) + { + m_TriggerType.SetWindowText(GetParam(ini.sections["Tags"].values[type], 0)); + break; + } + } +} + +void CTriggerOptionsDlg::OnChangeName() +{ + if(m_currentTrigger.GetLength()==0) return; + + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections["Triggers"].FindName(m_currentTrigger)<0 || m_currentTrigger.GetLength()==0) return; + + CString newName; + m_Name.GetWindowText(newName); + + if(newName.GetLength()==0) newName=" "; + + if(newName.Find(",",0)>=0) + {//newName.SetAt(newName.Find(",",0), 0); + newName=newName.Left(newName.Find(",",0)); + + m_Name.SetWindowText(newName);} + + + + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 2, newName); + + int i; + int p=0; + for(i=0;i<ini.sections["Tags"].values.size();i++) + { + CString type=*ini.sections["Tags"].GetValueName(i); + + CString attTrigg=GetParam(ini.sections["Tags"].values[type], 2); + if(attTrigg==m_currentTrigger) + { + p++; + char c[50]; + itoa(p,c,10); + CString newVal=newName+" "; + newVal+=c; + ini.sections["Tags"].values[type]=SetParam(ini.sections["Tags"].values[type], 1, newVal); + + } + } + //MessageBox(ini.sections["Triggers"].values[m_currentTrigger],newName); + RepairTrigger(ini.sections["Triggers"].values[m_currentTrigger]); + +} + +void CTriggerOptionsDlg::OnEditchangeHouse() +{ + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections["Triggers"].FindName(m_currentTrigger)<0 || m_currentTrigger.GetLength()==0) return; + + CString newHouse; + m_House.GetWindowText(newHouse); + + + + newHouse=TranslateHouse(newHouse); + + newHouse.TrimLeft(); + TruncSpace(newHouse); + if(newHouse.Find(",",0)>=0) newHouse.SetAt(newHouse.Find(",",0), 0); + + + + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 0, newHouse); + + RepairTrigger(ini.sections["Triggers"].values[m_currentTrigger]); + +} + +void CTriggerOptionsDlg::OnEditchangeAttachedtrigger() +{ + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections["Triggers"].FindName(m_currentTrigger)<0 || m_currentTrigger.GetLength()==0) return; + + CString newTrigger; + m_AttachedTrigger.GetWindowText(newTrigger); + newTrigger.TrimLeft(); + TruncSpace(newTrigger); + + if(newTrigger.Find(",",0)>=0) newTrigger.SetAt(newTrigger.Find(",",0), 0); + + + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 1, newTrigger); + + + +} + +void CTriggerOptionsDlg::OnKillfocusName() +{ + ((CTriggerEditorDlg*)(this->GetOwner()->GetOwner()))->UpdateDialog(); +} + +void CTriggerOptionsDlg::OnKillFocus(CWnd* pNewWnd) +{ + CDialog::OnKillFocus(pNewWnd); + + ((CTriggerEditorDlg*)(this->GetOwner()->GetOwner()))->UpdateDialog(); +} + +void CTriggerOptionsDlg::OnEditchangeTriggertype() +{ + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections["Triggers"].FindName(m_currentTrigger)<0 || m_currentTrigger.GetLength()==0) return; + + + CString newType; + m_TriggerType.GetWindowText(newType); + TruncSpace(newType); + + int i; + for(i=0;i<ini.sections["Tags"].values.size();i++) + { + CString type=*ini.sections["Tags"].GetValueName(i); + + CString attTrigg=GetParam(ini.sections["Tags"].values[type], 2); + if(attTrigg==m_currentTrigger) + { + ini.sections["Tags"].values[type]=SetParam(ini.sections["Tags"].values[type], 0, newType); + } + } + + RepairTrigger(ini.sections["Triggers"].values[m_currentTrigger]); +} + +BOOL CTriggerOptionsDlg::PreTranslateMessage(MSG* pMsg) +{ + { + m_tooltip.RelayEvent(pMsg); + } + return CDialog::PreTranslateMessage(pMsg); +} + +BOOL CTriggerOptionsDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + { + m_tooltip.Create(this); + m_tooltip.Activate(TRUE); + m_tooltip.AddTool(GetDlgItem(IDC_HOUSE), GetLanguageStringACP("TT_TriggerHouse")); + } + return TRUE; +} + +void CTriggerOptionsDlg::OnDisabled() +{ + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections["Triggers"].FindName(m_currentTrigger)<0 || m_currentTrigger.GetLength()==0) return; + + BOOL bDisabled=FALSE; + if(m_Disabled.GetCheck()==0) bDisabled=FALSE; + else + bDisabled=TRUE; + + if(bDisabled) + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 3, "1"); + else + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 3, "0"); + + + +} + +void CTriggerOptionsDlg::OnEasy() +{ + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections["Triggers"].FindName(m_currentTrigger)<0 || m_currentTrigger.GetLength()==0) return; + + BOOL bEasy=FALSE; + if(m_Easy.GetCheck()==0) bEasy=FALSE; + else + bEasy=TRUE; + + if(bEasy) + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 4, "1"); + else + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 4, "0"); + + +} + +void CTriggerOptionsDlg::OnMedium() +{ + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections["Triggers"].FindName(m_currentTrigger)<0 || m_currentTrigger.GetLength()==0) return; + + BOOL bMedium=FALSE; + if(m_Medium.GetCheck()==0) bMedium=FALSE; + else + bMedium=TRUE; + + if(bMedium) + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 5, "1"); + else + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 5, "0"); + +} + +void CTriggerOptionsDlg::OnHard() +{ + CIniFile& ini=Map->GetIniFile(); + + if(ini.sections["Triggers"].FindName(m_currentTrigger)<0 || m_currentTrigger.GetLength()==0) return; + + BOOL bHard=FALSE; + if(m_Hard.GetCheck()==0) bHard=FALSE; + else + bHard=TRUE; + + if(bHard) + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 6, "1"); + else + ini.sections["Triggers"].values[m_currentTrigger]=SetParam(ini.sections["Triggers"].values[m_currentTrigger], 6, "0"); + +} + +//MW 07/20/01 +void CTriggerOptionsDlg::Clear() +{ + +} diff --git a/MissionEditor/TriggerOptionsDlg.h b/MissionEditor/TriggerOptionsDlg.h new file mode 100644 index 0000000..b9641fd --- /dev/null +++ b/MissionEditor/TriggerOptionsDlg.h @@ -0,0 +1,88 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TRIGGEROPTIONSDLG_H__FA26A541_949D_11D4_9C87_CBD54CC4BF4A__INCLUDED_) +#define AFX_TRIGGEROPTIONSDLG_H__FA26A541_949D_11D4_9C87_CBD54CC4BF4A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TriggerOptionsDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTriggerOptionsDlg + +class CTriggerOptionsDlg : public CDialog +{ +// Konstruktion +public: + void Clear(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + void UpdateDialog(); + CString m_currentTrigger; + CTriggerOptionsDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CTriggerOptionsDlg) + enum { IDD = IDD_TRIGGEROPTIONS }; + CButton m_Medium; + CButton m_Hard; + CButton m_Easy; + CButton m_Disabled; + CMyComboBox m_TriggerType; + CEdit m_Name; + CMyComboBox m_House; + CMyComboBox m_AttachedTrigger; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTriggerOptionsDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + CToolTipCtrl m_tooltip; + virtual BOOL OnInitDialog(); + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTriggerOptionsDlg) + afx_msg void OnChangeName(); + afx_msg void OnEditchangeHouse(); + afx_msg void OnEditchangeAttachedtrigger(); + afx_msg void OnKillfocusName(); + afx_msg void OnKillFocus(CWnd* pNewWnd); + afx_msg void OnEditchangeTriggertype(); + afx_msg void OnDisabled(); + afx_msg void OnEasy(); + afx_msg void OnMedium(); + afx_msg void OnHard(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TRIGGEROPTIONSDLG_H__FA26A541_949D_11D4_9C87_CBD54CC4BF4A__INCLUDED_ diff --git a/MissionEditor/Triggers.cpp b/MissionEditor/Triggers.cpp new file mode 100644 index 0000000..bd8137d --- /dev/null +++ b/MissionEditor/Triggers.cpp @@ -0,0 +1,1458 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Triggers.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Triggers.h" +#include "FinalSunDlg.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" + +CString GetWaypoint(int n); +int GetWaypoint(const char* c); + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CTriggers + +IMPLEMENT_DYNCREATE(CTriggers, CDialog) + + +CTriggers::CTriggers() : CDialog(CTriggers::IDD) +{ + //{{AFX_DATA_INIT(CTriggers) + m_F1 = _T(""); + m_F2 = _T(""); + m_F3 = _T(""); + m_F4 = _T(""); + m_F5 = _T(""); + m_LA1 = _T(""); + m_LA2 = _T(""); + m_LA3 = _T(""); + m_LA4 = _T(""); + m_LA5 = _T(""); + m_LA6 = _T(""); + m_LE1 = _T(""); + m_LE2 = _T(""); + m_Name = _T(""); + m_LAW = _T(""); + //}}AFX_DATA_INIT +} + +CTriggers::~CTriggers() +{ +} + +void CTriggers::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTriggers) + DDX_Control(pDX, IDC_EVENTPARAM2, m_E2); + DDX_Control(pDX, IDC_EVENTPARAM1, m_E1); + DDX_Control(pDX, IDC_ACTIONPARAM6, m_A6); + DDX_Control(pDX, IDC_ACTIONPARAM5, m_A5); + DDX_Control(pDX, IDC_ACTIONPARAM4, m_A4); + DDX_Control(pDX, IDC_ACTIONPARAM3, m_A3); + DDX_Control(pDX, IDC_ACTIONPARAM2, m_A2); + DDX_Control(pDX, IDC_ACTIONPARAM1, m_A1); + DDX_Control(pDX, IDC_HOUSE, m_House); + DDX_Control(pDX, IDC_TRIGGER2, m_Trigger2); + DDX_Control(pDX, IDC_TRIGGER, m_Trigger); + DDX_Control(pDX, IDC_EVENTTYPE, m_EventType); + DDX_Control(pDX, IDC_EVENT, m_Event); + DDX_Control(pDX, IDC_ACTIONWAYPOINT, m_ActionWaypoint); + DDX_Control(pDX, IDC_ACTIONTYPE, m_ActionType); + DDX_Control(pDX, IDC_ACTION, m_Action); + DDX_Text(pDX, IDC_FLAG1, m_F1); + DDX_Text(pDX, IDC_FLAG2, m_F2); + DDX_Text(pDX, IDC_FLAG3, m_F3); + DDX_Text(pDX, IDC_FLAG4, m_F4); + DDX_Text(pDX, IDC_FLAG5, m_F5); + DDX_Text(pDX, IDC_LABEL_A1, m_LA1); + DDX_Text(pDX, IDC_LABEL_A2, m_LA2); + DDX_Text(pDX, IDC_LABEL_A3, m_LA3); + DDX_Text(pDX, IDC_LABEL_A4, m_LA4); + DDX_Text(pDX, IDC_LABEL_A5, m_LA5); + DDX_Text(pDX, IDC_LABEL_A6, m_LA6); + DDX_Text(pDX, IDC_LABEL_E1, m_LE1); + DDX_Text(pDX, IDC_LABEL_E2, m_LE2); + DDX_Text(pDX, IDC_NAME, m_Name); + DDX_Text(pDX, IDC_WAYPOINT, m_LAW); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTriggers, CDialog) + //{{AFX_MSG_MAP(CTriggers) + ON_CBN_SELCHANGE(IDC_TRIGGER, OnSelchangeTrigger) + ON_CBN_SELCHANGE(IDC_EVENT, OnSelchangeEvent) + ON_CBN_SELCHANGE(IDC_ACTION, OnSelchangeAction) + ON_CBN_EDITCHANGE(IDC_HOUSE, OnEditchangeHouse) + ON_CBN_SELCHANGE(IDC_HOUSE, OnSelchangeHouse) + ON_EN_CHANGE(IDC_NAME, OnChangeName) + ON_EN_CHANGE(IDC_FLAG1, OnChangeFlag1) + ON_EN_CHANGE(IDC_FLAG2, OnChangeFlag2) + ON_EN_CHANGE(IDC_FLAG3, OnChangeFlag3) + ON_EN_CHANGE(IDC_FLAG4, OnChangeFlag4) + ON_EN_CHANGE(IDC_FLAG5, OnChangeFlag5) + ON_CBN_EDITCHANGE(IDC_TRIGGER2, OnEditchangeTrigger2) + ON_CBN_SELCHANGE(IDC_TRIGGER2, OnSelchangeTrigger2) + ON_CBN_EDITCHANGE(IDC_EVENTTYPE, OnEditchangeEventtype) + ON_CBN_SELCHANGE(IDC_EVENTTYPE, OnSelchangeEventtype) + ON_CBN_EDITCHANGE(IDC_EVENTPARAM1, OnEditchangeEventparam1) + ON_CBN_SELCHANGE(IDC_EVENTPARAM1, OnSelchangeEventparam1) + ON_CBN_EDITCHANGE(IDC_EVENTPARAM2, OnEditchangeEventparam2) + ON_CBN_SELCHANGE(IDC_EVENTPARAM2, OnSelchangeEventparam2) + ON_CBN_EDITCHANGE(IDC_ACTIONTYPE, OnEditchangeActiontype) + ON_CBN_SELCHANGE(IDC_ACTIONTYPE, OnSelchangeActiontype) + ON_CBN_EDITCHANGE(IDC_ACTIONWAYPOINT, OnEditchangeActionwaypoint) + ON_CBN_SELCHANGE(IDC_ACTIONWAYPOINT, OnSelchangeActionwaypoint) + ON_CBN_EDITCHANGE(IDC_ACTIONPARAM1, OnEditchangeActionparam1) + ON_CBN_SELCHANGE(IDC_ACTIONPARAM1, OnSelchangeActionparam1) + ON_CBN_EDITCHANGE(IDC_ACTIONPARAM2, OnEditchangeActionparam2) + ON_CBN_SELCHANGE(IDC_ACTIONPARAM2, OnSelchangeActionparam2) + ON_CBN_EDITCHANGE(IDC_ACTIONPARAM3, OnEditchangeActionparam3) + ON_CBN_SELCHANGE(IDC_ACTIONPARAM3, OnSelchangeActionparam3) + ON_CBN_EDITCHANGE(IDC_ACTIONPARAM4, OnEditchangeActionparam4) + ON_CBN_SELCHANGE(IDC_ACTIONPARAM4, OnSelchangeActionparam4) + ON_CBN_EDITCHANGE(IDC_ACTIONPARAM5, OnEditchangeActionparam5) + ON_CBN_SELCHANGE(IDC_ACTIONPARAM5, OnSelchangeActionparam5) + ON_CBN_EDITCHANGE(IDC_ACTIONPARAM6, OnEditchangeActionparam6) + ON_CBN_SELCHANGE(IDC_ACTIONPARAM6, OnSelchangeActionparam6) + ON_BN_CLICKED(IDC_ADDEVENT, OnAddevent) + ON_BN_CLICKED(IDC_DELETEEVENT, OnDeleteevent) + ON_BN_CLICKED(IDC_ADDACTION, OnAddaction) + ON_BN_CLICKED(IDC_DELETEACTION, OnDeleteaction) + ON_BN_CLICKED(IDC_DELETETRIGGER, OnDeletetrigger) + ON_BN_CLICKED(IDC_ADDTRIGGER, OnAddtrigger) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CTriggers + + +void CTriggers::UpdateDialog() +{ + CIniFile& ini=Map->GetIniFile(); + + + int sel=m_Trigger.GetCurSel(); + int selat=m_Action.GetCurSel(); + int selev=m_Event.GetCurSel(); + + while(m_Trigger.DeleteString(0)!=CB_ERR); + while(m_Trigger2.DeleteString(0)!=CB_ERR); + while(m_Action.DeleteString(0)!=CB_ERR); + while(m_Event.DeleteString(0)!=CB_ERR); + while(m_ActionWaypoint.DeleteString(0)!=CB_ERR); + while(m_House.DeleteString(0)!=CB_ERR); + while(m_ActionType.DeleteString(0)!=CB_ERR); + while(m_EventType.DeleteString(0)!=CB_ERR); + + m_LE1="Parameter 1"; + m_LE2="Parameter 2"; + m_LA1="Param1"; + m_LA2="Param2"; + m_LA3="Param3"; + m_LA4="Param4"; + m_LA5="Param5"; + m_LA6="Param6"; + + int i; + + m_Trigger2.AddString("<none>"); + for(i=0;i<ini.sections["Triggers"].values.size();i++) + { + CString type; + CString s; + type=*ini.sections["Triggers"].GetValueName(i); + + s=type; + s+=" ("; + s+=GetParam(ini.sections["Triggers"].values[type], 2); + s+=")"; + + m_Trigger.AddString(s); + m_Trigger2.AddString(s); + + } + + for(i=0;i<g_data.sections["Events"].values.size();i++) + { + CString eventid=*g_data.sections["Events"].GetValueName(i); + CString eventdata=*g_data.sections["Events"].GetValue(i); + CString text=eventid+" "+GetParam(eventdata,0); + m_EventType.AddString(text); + } + + for(i=0;i<g_data.sections["Actions"].values.size();i++) + { + CString actionid=*g_data.sections["Actions"].GetValueName(i); + CString actiondata=*g_data.sections["Actions"].GetValue(i); + CString text=actionid+" "+GetParam(actiondata,0); + m_ActionType.AddString(text); + } + + + ListHouses(m_House, FALSE); + + CComboBox* wayp; + wayp=(CComboBox*)GetDlgItem(IDC_ACTIONWAYPOINT); + while(wayp->DeleteString(0)!=CB_ERR); + if(ini.sections.find("Waypoints")!=ini.sections.end()) + { + for(i=0;i<ini.sections["Waypoints"].values.size();i++) + { + wayp->AddString(*ini.sections["Waypoints"].GetValueName(i)); + } + } + + + if(sel==-1 || m_Trigger.SetCurSel(sel)==FALSE) + { + m_Trigger.SetCurSel(0); + } + if(selat==-1 || m_Trigger.SetCurSel(selat)==FALSE) + { + m_Action.SetCurSel(0); + } + if(selev==-1 || m_Trigger.SetCurSel(selev)==FALSE) + { + m_Event.SetCurSel(0); + } + + OnSelchangeTrigger(); + +} + +void CTriggers::OnSelchangeTrigger() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + while(m_Action.DeleteString(0)!=CB_ERR); + while(m_Event.DeleteString(0)!=CB_ERR); + + CString TriggerData, EventData, ActionData; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + TriggerData=ini.sections["Triggers"].values[CurrentTrigger]; + EventData=ini.sections["Events"].values[CurrentTrigger]; + ActionData=ini.sections["Actions"].values[CurrentTrigger]; + + m_Name=GetParam(TriggerData, 2); + m_House.SetWindowText(TranslateHouse(GetParam(TriggerData,0), TRUE)); + + + CString trig2=GetParam(TriggerData,1); + if(ini.sections["Triggers"].values.find(trig2)!=ini.sections["Triggers"].values.end()) + { + trig2+=" ("; + trig2+=GetParam( ini.sections["Triggers"].values[GetParam(TriggerData,1)],2); + trig2+=")"; + } + m_Trigger2.SetWindowText(trig2); + + m_F1=GetParam(TriggerData,3); + m_F2=GetParam(TriggerData,4); + m_F3=GetParam(TriggerData,5); + m_F4=GetParam(TriggerData,6); + m_F5=GetParam(TriggerData,7); + + + // okay, now list all events and actions + // ------------------------------------- + int i; + + // events + for(i=0;i<atoi(GetParam(EventData, 0));i++) + { + char c[10]; + itoa(i,c,10); + m_Event.AddString(c); + } + if(m_Event.SetCurSel(0)!=CB_ERR) + OnSelchangeEvent(); + + + + // actions + for(i=0;i<atoi(GetParam(ActionData, 0));i++) + { + char c[10]; + itoa(i,c,10); + m_Action.AddString(c); + } + if(m_Action.SetCurSel(0)!=CB_ERR) + OnSelchangeAction(); + + UpdateData(FALSE); +} + +void CTriggers::OnSelchangeEvent() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int selev=m_Event.GetCurSel(); + if(selev<0) return; + + + int i; + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + + CString EventData; + EventData=ini.sections["Events"].values[(LPCTSTR)CurrentTrigger]; + + int startpos=1+selev*3; + CString EventType=GetParam(EventData,startpos); + m_EventType.SetWindowText(EventType); + for(i=0;i<m_EventType.GetCount();i++) + { + CString tmp; + m_EventType.GetLBText(i,tmp); + TruncSpace(tmp); + if(tmp==EventType) + m_EventType.SetCurSel(i); + } + m_E1.SetWindowText(GetParam(EventData,startpos+1)); + + m_E2.SetWindowText(GetParam(EventData,startpos+2)); + + OnEditchangeEventtype(); +} + +void CTriggers::OnSelchangeAction() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int selac=m_Action.GetCurSel(); + if(selac<0) return; + + int i; + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString ActionData; + ActionData=ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger]; + + int startpos=1+selac*8; + CString ActionType=GetParam(ActionData,startpos); + m_ActionType.SetWindowText(ActionType); + for(i=0;i<m_ActionType.GetCount();i++) + { + CString tmp; + m_ActionType.GetLBText(i,tmp); + TruncSpace(tmp); + if(tmp==ActionType) + m_ActionType.SetCurSel(i); + } + m_A1.SetWindowText(GetParam(ActionData,startpos+1)); + m_A2.SetWindowText(GetParam(ActionData,startpos+2)); + m_A3.SetWindowText(GetParam(ActionData,startpos+3)); + m_A4.SetWindowText(GetParam(ActionData,startpos+4)); + m_A5.SetWindowText(GetParam(ActionData,startpos+5)); + m_A6.SetWindowText(GetParam(ActionData,startpos+6)); + + OnEditchangeActiontype(); + + char wayp[50]; + itoa(GetWaypoint(GetParam(ActionData,startpos+7)), wayp, 10); + m_ActionWaypoint.SetWindowText(wayp); +} + +void CTriggers::OnEditchangeHouse() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString house; + m_House.GetWindowText(house); + + house=TranslateHouse(house); + + ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger], 0, (LPCTSTR)house); +} + +void CTriggers::OnSelchangeHouse() +{ + CIniFile& ini=Map->GetIniFile(); + + int csel=m_House.GetCurSel(); + CString house; + m_House.GetLBText(csel,house); + m_House.SetWindowText(house); + + OnEditchangeHouse(); +} + +void CTriggers::OnChangeName() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + CEdit& name=*(CEdit*)GetDlgItem(IDC_NAME); + + int esel=name.GetSel(); + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + + ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger], 2, (LPCTSTR)m_Name); + + UpdateDialog(); + + m_Trigger.SetCurSel(sel); + OnSelchangeTrigger(); + name.SetSel(esel); +} + +void CTriggers::OnChangeFlag1() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + + ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger], 3, (LPCTSTR)m_F1); + +} + +void CTriggers::OnChangeFlag2() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + + ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger], 4, (LPCTSTR)m_F2); + +} + +void CTriggers::OnChangeFlag3() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + + ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger], 5, (LPCTSTR)m_F3); + + +} + +void CTriggers::OnChangeFlag4() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + + ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger], 6, (LPCTSTR)m_F4); + +} + +void CTriggers::OnChangeFlag5() +{ + CIniFile& ini=Map->GetIniFile(); + + UpdateData(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + + ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger], 7, (LPCTSTR)m_F5); + +} + +void CTriggers::OnEditchangeTrigger2() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString trg; + m_Trigger2.GetWindowText(trg); + TruncSpace(trg); + + ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Triggers"].values[(LPCTSTR)CurrentTrigger], 1, (LPCTSTR)trg); +} + +void CTriggers::OnSelchangeTrigger2() +{ + CIniFile& ini=Map->GetIniFile(); + + int csel=m_Trigger2.GetCurSel(); + CString trg; + m_Trigger2.GetLBText(csel,trg); + m_Trigger2.SetWindowText(trg); + OnEditchangeTrigger2(); +} + +void CTriggers::OnEditchangeEventtype() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Event.GetCurSel(); + if(sel2<0) return; + + CString e1,e2; + m_E1.GetWindowText(e1); + m_E2.GetWindowText(e2); + while(m_E2.DeleteString(0)!=CB_ERR); + while(m_E1.DeleteString(0)!=CB_ERR); + m_E1.SetWindowText(e1); + m_E2.SetWindowText(e2); + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString eventtype; + m_EventType.GetWindowText(eventtype); + TruncSpace(eventtype); + + int pos=1+3*sel2; + + ini.sections["Events"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Events"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)eventtype); + + if(g_data.sections["Events"].FindName(eventtype)<0) return; + + + CString ptype[2]; + ptype[0]=GetParam(g_data.sections["Events"].values[eventtype],1); + ptype[1]=GetParam(g_data.sections["Events"].values[eventtype],2); + + int pListType[2]; + pListType[0]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[0]], 1)); + pListType[1]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[1]], 1)); + + int i; + for(i=0;i<2;i++) + { + CString* label; + if(i==0) label=&m_LE1; + if(i==1) label=&m_LE2; + CComboBox* cb; + if(i==0) cb=&m_E1; + if(i==1) cb=&m_E2; + + CString old_sel; + cb->GetWindowText(old_sel); + TruncSpace(old_sel); + + if(atoi(ptype[i])<0) + { + char c[50]; + itoa(abs(atoi(ptype[i])), c, 10); + cb->SetWindowText(c); + *label="Static"; + continue; + } + + *label=GetParam(g_data.sections["ParamTypes"].values[ptype[i]], 0); + + + + HandleParamList(*cb, pListType[i]); + + cb->SetWindowText(old_sel); + + int e; + for(e=0;e<cb->GetCount();e++) + { + CString tmp; + cb->GetLBText(e,tmp); + TruncSpace(tmp); + if(tmp==old_sel) + cb->SetCurSel(e); + } + + } + + + + + UpdateData(FALSE); + +} + + + +void CTriggers::OnSelchangeEventtype() +{ + int csel=m_EventType.GetCurSel(); + CString trg; + m_EventType.GetLBText(csel,trg); + m_EventType.SetWindowText(trg); + OnEditchangeEventtype(); + + +} + +void CTriggers::OnEditchangeEventparam1() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Event.GetCurSel(); + if(sel2<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString param1; + m_E1.GetWindowText(param1); + TruncSpace(param1); + + int pos=1+3*sel2+1; + + ini.sections["Events"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Events"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)param1); + +} + +void CTriggers::OnSelchangeEventparam1() +{ + int csel=m_E1.GetCurSel(); + CString trg; + m_E1.GetLBText(csel,trg); + m_E1.SetWindowText(trg); + OnEditchangeEventparam1(); +} + +void CTriggers::OnEditchangeEventparam2() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Event.GetCurSel(); + if(sel2<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString param2; + m_E2.GetWindowText(param2); + TruncSpace(param2); + + int pos=1+3*sel2+2; + + ini.sections["Events"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Events"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)param2); + +} + +void CTriggers::OnSelchangeEventparam2() +{ + int csel=m_E2.GetCurSel(); + CString trg; + m_E2.GetLBText(csel,trg); + m_E2.SetWindowText(trg); + OnEditchangeEventparam2(); +} + +void CTriggers::OnEditchangeActiontype() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + + CString a; + m_A1.GetWindowText(a); + while(m_A1.DeleteString(0)!=CB_ERR); + m_A1.SetWindowText(a); + m_A2.GetWindowText(a); + while(m_A2.DeleteString(0)!=CB_ERR); + m_A2.SetWindowText(a); + m_A3.GetWindowText(a); + while(m_A3.DeleteString(0)!=CB_ERR); + m_A3.SetWindowText(a); + m_A4.GetWindowText(a); + while(m_A4.DeleteString(0)!=CB_ERR); + m_A4.SetWindowText(a); + m_A5.GetWindowText(a); + while(m_A5.DeleteString(0)!=CB_ERR); + m_A5.SetWindowText(a); + m_A6.GetWindowText(a); + while(m_A6.DeleteString(0)!=CB_ERR); + m_A6.SetWindowText(a); + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString actiontype; + m_ActionType.GetWindowText(actiontype); + TruncSpace(actiontype); + + int pos=1+8*sel2; + + ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)actiontype); + + if(g_data.sections["Actions"].FindName(actiontype)<0) return; + + + CString ptype[6]; + ptype[0]=GetParam(g_data.sections["Actions"].values[actiontype],1); + ptype[1]=GetParam(g_data.sections["Actions"].values[actiontype],2); + ptype[2]=GetParam(g_data.sections["Actions"].values[actiontype],3); + ptype[3]=GetParam(g_data.sections["Actions"].values[actiontype],4); + ptype[4]=GetParam(g_data.sections["Actions"].values[actiontype],5); + ptype[5]=GetParam(g_data.sections["Actions"].values[actiontype],6); + + if(GetParam(g_data.sections["Actions"].values[actiontype],7)=="0") + m_LAW="Unused"; + else + m_LAW="Waypoint:"; + + int pListType[6]; + pListType[0]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[0]], 1)); + pListType[1]=atoi(GetParam(g_data.sections["ParamTypes"].values[ptype[1]], 1)); + + + + int i; + for(i=0;i<6;i++) + { + CString* label; + if(i==0) label=&m_LA1; + if(i==1) label=&m_LA2; + if(i==2) label=&m_LA3; + if(i==3) label=&m_LA4; + if(i==4) label=&m_LA5; + if(i==5) label=&m_LA6; + CComboBox* cb; + if(i==0) cb=&m_A1; + if(i==1) cb=&m_A2; + if(i==2) cb=&m_A3; + if(i==3) cb=&m_A4; + if(i==4) cb=&m_A5; + if(i==5) cb=&m_A6; + + CString old_sel; + cb->GetWindowText(old_sel); + TruncSpace(old_sel); + + if(atoi(ptype[i])<0) + { + char c[50]; + itoa(abs(atoi(ptype[i])), c, 10); + cb->SetWindowText(c); + *label="Static"; + continue; + } + + *label = GetParam(g_data.sections["ParamTypes"].values[ptype[i]], 0); + + + + HandleParamList(*cb, pListType[i]); + + cb->SetWindowText(old_sel); + + int e; + for(e=0;e<cb->GetCount();e++) + { + CString tmp; + cb->GetLBText(e,tmp); + TruncSpace(tmp); + if(tmp==old_sel) + cb->SetCurSel(e); + } + + } +/* + + switch(atoi(actiontype)) + { + case 0: + case 23: + case 24: + case 46: + case 47: + m_LA1="Unused:"; + m_LA2="Unused:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + break; + case 1: + case 2: + case 3: + case 6: + case 36: + case 74: + m_LA1="Unused:"; + m_LA2="House:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + ListHouses(m_A2); + break; + + case 4: + m_LA1="Unknown =1:"; + m_LA2="TeamType:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + m_A1.SetWindowText("1"); + OnEditchangeActionparam1(); + ListTeamTypes(m_A2); + break; + case 5: + m_LA1="Unused?:"; + m_LA2="TeamType:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + ListTeamTypes(m_A2); + break; + + case 7: + m_LA1="Unknown =1:"; + m_LA2="TeamType:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + m_A1.SetWindowText("1"); + OnEditchangeActionparam1(); + ListTeamTypes(m_A2); + break; + case 8: + case 17: + case 18: + m_LA1="Unused:"; + m_LA2="Waypoint:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + ListWaypoints(m_A2); + break; + + case 27: + m_LA1="Unused:"; + m_LA2="Duration:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + break; + case 43: + m_LA1="Unused:"; + m_LA2="Unknown:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + m_A2.SetWindowText("7"); + OnEditchangeActionparam2(); + break; + case 44: + m_LA1="Unused:"; + m_LA2="Duration:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + break; + case 48: + m_LA1="Unused:"; + m_LA2="Speed:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + break; + case 55: + m_LA1="Unused:"; + m_LA2="Unknown:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + m_A2.SetWindowText("1"); + OnEditchangeActionparam2(); + break; + case 56: + m_LA1="Unused:"; + m_LA2="Global:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + break; + case 58: + m_LA1="Unused:"; + m_LA2="Size:"; + m_LA3="Unused:"; + m_LA4="Unused:"; + m_LA5="Unused:"; + m_LA6="Unused:"; + break; + default: + m_LA1="Param1:"; + m_LA2="Param2:"; + m_LA3="Param3:"; + m_LA4="Param4:"; + m_LA5="Param5:"; + m_LA6="Param6:"; + } +*/ + + UpdateData(FALSE); + +} + +void CTriggers::OnSelchangeActiontype() +{ + int csel=m_ActionType.GetCurSel(); + CString trg; + m_ActionType.GetLBText(csel,trg); + m_ActionType.SetWindowText(trg); + OnEditchangeActiontype(); +} + +void CTriggers::OnEditchangeActionwaypoint() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString waypoint; + m_ActionWaypoint.GetWindowText(waypoint); + TruncSpace(waypoint); + + waypoint=GetWaypoint(atoi(waypoint)); + + int pos=1+8*sel2+7; + + ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)waypoint); + +} + +void CTriggers::OnSelchangeActionwaypoint() +{ + int csel=m_ActionWaypoint.GetCurSel(); + CString trg; + m_ActionWaypoint.GetLBText(csel,trg); + m_ActionWaypoint.SetWindowText(trg); + OnEditchangeActionwaypoint(); +} + +void CTriggers::OnEditchangeActionparam1() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString p1; + m_A1.GetWindowText(p1); + TruncSpace(p1); + + int pos=1+8*sel2+1; + + ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)p1); + +} + +void CTriggers::OnSelchangeActionparam1() +{ + int csel=m_A1.GetCurSel(); + CString trg; + m_A1.GetLBText(csel,trg); + m_A1.SetWindowText(trg); + OnEditchangeActionparam1(); +} + +void CTriggers::OnEditchangeActionparam2() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString p2; + m_A2.GetWindowText(p2); + TruncSpace(p2); + + int pos=1+8*sel2+2; + + ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)p2); + +} + +void CTriggers::OnSelchangeActionparam2() +{ + int csel=m_A2.GetCurSel(); + CString trg; + m_A2.GetLBText(csel,trg); + m_A2.SetWindowText(trg); + OnEditchangeActionparam2(); +} + +void CTriggers::OnEditchangeActionparam3() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString p3; + m_A3.GetWindowText(p3); + TruncSpace(p3); + + int pos=1+8*sel2+3; + + ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)p3); + +} + +void CTriggers::OnSelchangeActionparam3() +{ + int csel=m_A3.GetCurSel(); + CString trg; + m_A3.GetLBText(csel,trg); + m_A3.SetWindowText(trg); + OnEditchangeActionparam3(); +} + +void CTriggers::OnEditchangeActionparam4() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString p4; + m_A4.GetWindowText(p4); + TruncSpace(p4); + + int pos=1+8*sel2+4; + + ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)p4); + +} + +void CTriggers::OnSelchangeActionparam4() +{ + int csel=m_A4.GetCurSel(); + CString trg; + m_A4.GetLBText(csel,trg); + m_A4.SetWindowText(trg); + OnEditchangeActionparam4(); +} + +void CTriggers::OnEditchangeActionparam5() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString p5; + m_A5.GetWindowText(p5); + TruncSpace(p5); + + int pos=1+8*sel2+5; + + ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)p5); + +} + +void CTriggers::OnSelchangeActionparam5() +{ + int csel=m_A5.GetCurSel(); + CString trg; + m_A5.GetLBText(csel,trg); + m_A5.SetWindowText(trg); + OnEditchangeActionparam5(); +} + +void CTriggers::OnEditchangeActionparam6() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CString p6; + m_A6.GetWindowText(p6); + TruncSpace(p6); + + int pos=1+8*sel2+6; + + ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger]=SetParam(ini.sections["Actions"].values[(LPCTSTR)CurrentTrigger], pos, (LPCTSTR)p6); + +} + +void CTriggers::OnSelchangeActionparam6() +{ + int csel=m_A6.GetCurSel(); + CString trg; + m_A6.GetLBText(csel,trg); + m_A6.SetWindowText(trg); + OnEditchangeActionparam6(); +} + +void CTriggers::OnAddevent() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CIniFileSection& sec=ini.sections["Events"]; + + int cval=atoi(GetParam(sec.values[(LPCTSTR)CurrentTrigger],0)); + cval++; + char c[50]; + itoa(cval,c,10); + + sec.values[(LPCTSTR)CurrentTrigger]=SetParam(sec.values[(LPCTSTR)CurrentTrigger],0,c); + sec.values[(LPCTSTR)CurrentTrigger]+=",13,0,0"; + + + UpdateDialog(); + + m_Trigger.SetCurSel(sel); + OnSelchangeTrigger(); + m_Event.SetCurSel(cval-1); + OnSelchangeEvent(); + +} + +void CTriggers::OnDeleteevent() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Event.GetCurSel(); + if(sel2<0) return; + if(MessageBox("Do you really want to delete this event?","Delete event", MB_YESNO)==IDNO) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CIniFileSection& sec=ini.sections["Events"]; + + CString data; + data=sec.values[(LPCTSTR)CurrentTrigger]; + + int v=atoi(GetParam(data,0)); + char c[50]; + v--; + itoa(v,c,10); + data=SetParam(data,0, c); + + int pos=1+sel2*3; + int posc=1+v*3; + int i; + for(i=0;i<3;i++) + data=SetParam(data,pos+i, GetParam(data,posc+i)); + + char* cupos=(char*)(LPCTSTR)data; + for(i=0;i<posc;i++) + { + cupos=strchr(cupos+1, ','); + if(i==posc-1) + { + cupos[0]=0; + break; + } + } + + sec.values[(LPCTSTR)CurrentTrigger]=data; + UpdateDialog(); + m_Trigger.SetCurSel(sel); + OnSelchangeTrigger(); +} + +void CTriggers::OnAddaction() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CIniFileSection& sec=ini.sections["Actions"]; + + int cval=atoi(GetParam(sec.values[(LPCTSTR)CurrentTrigger],0)); + cval++; + char c[50]; + itoa(cval,c,10); + + sec.values[(LPCTSTR)CurrentTrigger]=SetParam(sec.values[(LPCTSTR)CurrentTrigger],0,c); + sec.values[(LPCTSTR)CurrentTrigger]+=",0,0,0,0,0,0,0,A"; + + + UpdateDialog(); + + m_Trigger.SetCurSel(sel); + OnSelchangeTrigger(); + m_Action.SetCurSel(cval-1); + OnSelchangeAction(); +} + +void CTriggers::OnDeleteaction() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + int sel2=m_Action.GetCurSel(); + if(sel2<0) return; + if(MessageBox("Do you really want to delete this action?","Delete action", MB_YESNO)==IDNO) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + CIniFileSection& sec=ini.sections["Actions"]; + + CString data; + data=sec.values[(LPCTSTR)CurrentTrigger]; + + int v=atoi(GetParam(data,0)); + char c[50]; + v--; + itoa(v,c,10); + data=SetParam(data,0, c); + + int pos=1+sel2*8; + int posc=1+v*8; + int i; + for(i=0;i<3;i++) + data=SetParam(data,pos+i, GetParam(data,posc+i)); + + char* cupos=(char*)(LPCTSTR)data; + for(i=0;i<posc;i++) + { + cupos=strchr(cupos+1, ','); + if(i==posc-1) + { + cupos[0]=0; + break; + } + } + + sec.values[(LPCTSTR)CurrentTrigger]=data; + UpdateDialog(); + + m_Trigger.SetCurSel(sel); + OnSelchangeTrigger(); +} + + +void CTriggers::OnDeletetrigger() +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=m_Trigger.GetCurSel(); + if(sel<0) return; + + if(MessageBox("Do you really want to delete this trigger? Don´t forget to delete the attached tag (important!)","Delete trigger", MB_YESNO)==IDNO) return; + + CString CurrentTrigger; + m_Trigger.GetLBText(sel, CurrentTrigger); + TruncSpace(CurrentTrigger); + + ini.sections["Triggers"].values.erase((LPCTSTR)CurrentTrigger); + ini.sections["Events"].values.erase((LPCTSTR)CurrentTrigger); + ini.sections["Actions"].values.erase((LPCTSTR)CurrentTrigger); + + //UpdateDialog(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); +} + +void CTriggers::OnAddtrigger() +{ + CIniFile& ini=Map->GetIniFile(); + + CString ID_T=GetFreeID(); + ini.sections["Triggers"].values[ID_T]="GDI,<none>,New trigger,0,1,1,1,0"; + ini.sections["Events"].values[ID_T]="0"; + ini.sections["Actions"].values[ID_T]="0"; + + if(MessageBox("Trigger created. If you want to create a simple tag now, press Yes. The tag will be called ""New tag"", you should name it like the trigger (after you have set up the trigger).","Trigger created",MB_YESNO)) + { + CString ID_TAG=GetFreeID(); + ini.sections["Tags"].values[ID_TAG]="0,New tag,"; + ini.sections["Tags"].values[ID_TAG]+=ID_T; + } + + //UpdateDialog(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); + +} + + diff --git a/MissionEditor/Triggers.h b/MissionEditor/Triggers.h new file mode 100644 index 0000000..451e6dd --- /dev/null +++ b/MissionEditor/Triggers.h @@ -0,0 +1,140 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_TRIGGERS_H__1E811180_939D_11D3_B63B_F94AB129C441__INCLUDED_) +#define AFX_TRIGGERS_H__1E811180_939D_11D3_B63B_F94AB129C441__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Triggers.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CTriggers + +class CTriggers : public CDialog +{ + DECLARE_DYNCREATE(CTriggers) + +// Konstruktion +public: + void UpdateDialog(); + CTriggers(); + ~CTriggers(); + +// Dialogfelddaten + //{{AFX_DATA(CTriggers) + enum { IDD = IDD_TRIGGERS }; + CComboBox m_E2; + CComboBox m_E1; + CComboBox m_A6; + CComboBox m_A5; + CComboBox m_A4; + CComboBox m_A3; + CComboBox m_A2; + CComboBox m_A1; + CComboBox m_House; + CComboBox m_Trigger2; + CComboBox m_Trigger; + CComboBox m_EventType; + CComboBox m_Event; + CComboBox m_ActionWaypoint; + CComboBox m_ActionType; + CComboBox m_Action; + CString m_F1; + CString m_F2; + CString m_F3; + CString m_F4; + CString m_F5; + CString m_LA1; + CString m_LA2; + CString m_LA3; + CString m_LA4; + CString m_LA5; + CString m_LA6; + CString m_LE1; + CString m_LE2; + CString m_Name; + CString m_LAW; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CTriggers) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CTriggers) + afx_msg void OnSelchangeTrigger(); + afx_msg void OnSelchangeEvent(); + afx_msg void OnSelchangeAction(); + afx_msg void OnEditchangeHouse(); + afx_msg void OnSelchangeHouse(); + afx_msg void OnChangeName(); + afx_msg void OnChangeFlag1(); + afx_msg void OnChangeFlag2(); + afx_msg void OnChangeFlag3(); + afx_msg void OnChangeFlag4(); + afx_msg void OnChangeFlag5(); + afx_msg void OnEditchangeTrigger2(); + afx_msg void OnSelchangeTrigger2(); + afx_msg void OnEditchangeEventtype(); + afx_msg void OnSelchangeEventtype(); + afx_msg void OnEditchangeEventparam1(); + afx_msg void OnSelchangeEventparam1(); + afx_msg void OnEditchangeEventparam2(); + afx_msg void OnSelchangeEventparam2(); + afx_msg void OnEditchangeActiontype(); + afx_msg void OnSelchangeActiontype(); + afx_msg void OnEditchangeActionwaypoint(); + afx_msg void OnSelchangeActionwaypoint(); + afx_msg void OnEditchangeActionparam1(); + afx_msg void OnSelchangeActionparam1(); + afx_msg void OnEditchangeActionparam2(); + afx_msg void OnSelchangeActionparam2(); + afx_msg void OnEditchangeActionparam3(); + afx_msg void OnSelchangeActionparam3(); + afx_msg void OnEditchangeActionparam4(); + afx_msg void OnSelchangeActionparam4(); + afx_msg void OnEditchangeActionparam5(); + afx_msg void OnSelchangeActionparam5(); + afx_msg void OnEditchangeActionparam6(); + afx_msg void OnSelchangeActionparam6(); + afx_msg void OnAddevent(); + afx_msg void OnDeleteevent(); + afx_msg void OnAddaction(); + afx_msg void OnDeleteaction(); + afx_msg void OnDeletetrigger(); + afx_msg void OnAddtrigger(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_TRIGGERS_H__1E811180_939D_11D3_B63B_F94AB129C441__INCLUDED_ diff --git a/MissionEditor/Tube.cpp b/MissionEditor/Tube.cpp new file mode 100644 index 0000000..dfa5a40 --- /dev/null +++ b/MissionEditor/Tube.cpp @@ -0,0 +1,363 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "StdAfx.h" +#include "Tube.h" +#include <ranges> + +#include "inlines.h" + +#ifndef __INTELLISENSE__ +// This file had problems with Intellisense. Until this is fixed, deactivate intellisense parsing here. + +int sgn(int v) +{ + if (v < 0) return -1; + return v > 0 ? 1 : 0; +} + +CTube::CTube(std::uint16_t tubeID, std::uint16_t startX, std::uint16_t startY, ETubeDirection direction, std::uint16_t endX, std::uint16_t endY, const std::vector<ETubeDirection>& tubeParts): + CTube(startX, startY, direction, endX, endY, tubeParts) +{ + m_tubeId = tubeID; +} + +CTube::CTube(const std::uint16_t startX, const std::uint16_t startY, const ETubeDirection direction, const std::uint16_t endX, const std::uint16_t endY, const std::vector<ETubeDirection>& tubeParts): + CTube() +{ + m_startX = startX; + m_startY = startY; + m_direction = direction; + m_endX = endX; + m_endY = endY; + m_tubeParts = tubeParts; +} + +CTube::CTube(std::uint16_t tubeId, const std::string& value): + m_tubeId(tubeId) +{ + m_startY = stoi(GetParam(value, 0)); + m_startX = stoi(GetParam(value, 1)); + m_direction = ToTubeDirection(stoi(GetParam(value, 2))); + m_endY = stoi(GetParam(value, 3)); + m_endX = stoi(GetParam(value, 4)); + + std::string readDirS; + for (std::size_t e = 5; !(readDirS = GetParam(value, e)).empty(); ++e) + { + const auto readDir = stoi(readDirS); + m_tubeParts.push_back(ToTubeDirection(readDir)); + } + if (m_tubeParts.empty() || m_tubeParts.back() != ETubeDirection::Undefined) + m_tubeParts.push_back(ETubeDirection::Undefined); +} + +bool CTube::isValid() const +{ + return m_direction != ETubeDirection::Undefined && m_tubeParts.size() > 1; +} + +CTube CTube::reverse(std::uint16_t newTubeID) const +{ + CTube ti2; + + ti2.m_tubeId = newTubeID; + + ti2.m_startX = m_endX; + ti2.m_startY = m_endY; + ti2.m_endX = m_startX; + ti2.m_endY = m_startY; + + const auto last_d = getLastDirection(); + ti2.m_direction = opposite_dir(last_d); + + auto x = m_startX; + auto y = m_startY; + + // reverse direction tube parts + auto reversed = m_tubeParts | + std::views::reverse | + std::views::transform([](auto dir) {return opposite_dir(dir);}) | + std::views::common; + + // find the first defined direction in the reversed list + auto reversedFirst = std::find_if(reversed.begin(), reversed.end(), [](ETubeDirection dir) { return dir != ETubeDirection::Undefined; }); + auto reversedSize = reversed.end() - reversedFirst; + ti2.m_tubeParts.reserve(reversed.size() + 2); + ti2.m_tubeParts.assign(reversedFirst, reversed.end()); + ti2.m_tubeParts.push_back(ETubeDirection::Undefined); + + return ti2; +} + +static const ETubeDirection kDiffToDir[3][3] = { + {ETubeDirection::TopLeft, ETubeDirection::Top, ETubeDirection::TopRight}, // xadd == -1 + {ETubeDirection::Left, ETubeDirection::Undefined, ETubeDirection::Right}, // xadd == 0 + {ETubeDirection::BottomLeft, ETubeDirection::Bottom, ETubeDirection::BottomRight} // xadd == 1 +}; + +bool CTube::isEqual(const CTube& r, bool ignoreId) const +{ + if (!ignoreId) + return *this == r; + + const auto& largerTubeParts = r.m_tubeParts.size() >= m_tubeParts.size() ? r.m_tubeParts : m_tubeParts; + const auto& smallerTubeParts = r.m_tubeParts.size() < m_tubeParts.size() ? r.m_tubeParts : m_tubeParts; + for (auto i = 0; i < smallerTubeParts.size(); ++i) + { + if (largerTubeParts[i] != smallerTubeParts[i]) + return false; + } + for (auto i = smallerTubeParts.size(); i < largerTubeParts.size(); ++i) + { + if (largerTubeParts[i] != ETubeDirection::Undefined) + return false; + } + + return m_direction == r.m_direction && m_startX == r.m_startX && m_startY == r.m_startY && r.m_endX == r.m_endX && r.m_endY == r.m_endY; +} + +CTube CTube::autocreate(std::uint16_t startX, std::uint16_t startY, std::uint16_t endX, std::uint16_t endY, int straightStartParts) +{ + CTube ti; + ti.m_startX = startX; + ti.m_startY = startY; + ti.m_endX = startX; + ti.m_endY = startY; + ti.append(endX, endY, straightStartParts); + return ti; + + /* + int curx = startX; + int cury = startY; + + CTube ti; + ti.m_startX = startX; + ti.m_startY = startY; + ti.m_endX = endX; + ti.m_endY = endY; + + + + int xadd = sgn(endX - curx); + int yadd = sgn(endY - cury); + if (straightStartTiles > 0) + { + const bool xMajor = abs(endX - startX) > abs(endY - startY); + xadd = xMajor ? xadd : 0; + yadd = xMajor ? 0 : yadd; + } + + curx += xadd; + cury += yadd; + ti.m_direction = kDiffToDir[xadd + 1][yadd + 1]; + + int n = 1; + while (endX != curx || endY != cury) + { + xadd = n < straightStartTiles ? xadd : sgn(endX - curx); // keep initial direction for straightStartTiles + yadd = n < straightStartTiles ? yadd : sgn(endY - cury); + n++; + curx += xadd; + cury += yadd; + ti.m_tubeParts.push_back(kDiffToDir[xadd + 1][yadd + 1]); + } + + ti.m_tubeParts.push_back(ETubeDirection::Undefined); + return ti; + */ +} + +ETubeDirection opposite_dir(const ETubeDirection dir) +{ + static const ETubeDirection opposite_dir_tbl[8] = { + ETubeDirection::Bottom, + ETubeDirection::BottomLeft, + ETubeDirection::Left, + ETubeDirection::TopLeft, + ETubeDirection::Top, + ETubeDirection::TopRight, + ETubeDirection::Right, + ETubeDirection::BottomRight + }; + const auto iDir = to_int(dir); + if (iDir < 0 || iDir > 7) + return ETubeDirection::Undefined; + return opposite_dir_tbl[iDir]; +} + + +bool dir_to_xy(ETubeDirection dir, MapVec& vec) +{ + static int dir_to_xy_table[8][2] = { + {0, -1}, // 0 + {1, -1}, // 1 + {1, 0}, // 2 + {1, 1}, // 3 + {0, 1}, // 4 + {-1, 1}, // 5 + {-1, 0}, // 6 + {-1, -1}, // 7 + }; + const auto iDir = to_int(dir); + if (iDir < 0 || iDir > 7) + { + vec.x = 0; + vec.y = 0; + return false; + } + vec.x = dir_to_xy_table[iDir][1]; // swap x/y + vec.y = dir_to_xy_table[iDir][0]; + return true; +} + +ETubeDirection CTube::getLastDirection() const +{ + if (m_tubeParts.empty()) + return m_direction; + auto last = std::find_if(m_tubeParts.crbegin(), m_tubeParts.crend(), [](ETubeDirection dir) { return dir != ETubeDirection::Undefined; }); + return last == m_tubeParts.crend() ? m_direction : *last; +} + +bool CTube::touches(const MapCoords& mc) const +{ + bool touches = false; + walk([this, &mc, &touches](const auto& wi) { + if (wi.pos == mc) + { + touches = true; + return false; + } + return true; + }); + return touches; +} + +std::string CTube::toString() const +{ + auto partsAsInt = m_tubeParts | std::views::transform([](auto dir) {return to_int(dir); }) | std::views::common; + + std::vector<int> values; + values.reserve(5 + m_tubeParts.size()); + values.assign({ m_startY, m_startX, to_int(m_direction), m_endY, m_endX }); + values.insert(values.end(), partsAsInt.begin(), partsAsInt.end()); + + std::string res = Join(",", values | std::views::transform([](auto v) {return std::to_string(v); })); + if (m_tubeParts.empty() || m_tubeParts.back() != ETubeDirection::Undefined) + res += ",-1"; // TS/RA2 crash when no delimiter exists + return res; +} + +bool CTube::append(std::uint16_t endX, std::uint16_t endY, int forceStraightParts) +{ + auto newTubeParts = m_tubeParts; + MapCoords end(endX, endY); + + // remove delimiters + auto oldLast = std::find(newTubeParts.begin(), newTubeParts.end(), ETubeDirection::Undefined); + newTubeParts.resize(oldLast - newTubeParts.begin()); + + // now find current x/y + MapCoords cur = getStartCoords(); + std::vector<MapCoords> existingPositions; + if(!walk([&cur, &existingPositions](const WalkInfo& wi) { + cur = wi.pos; + existingPositions.push_back(wi.pos); + return true; + })) + return false; + + // if no enter direction was given, set it now - this should only be true if there are no existingPositions + if (m_direction == ETubeDirection::Undefined) + { + const bool xMajor = abs(end.x - m_startX) > abs(end.y - m_startY); + MapVec add(sgn(end.x - m_startX), sgn(end.y - m_startY)); + add.x = xMajor ? add.x : 0; + add.y = xMajor ? 0 : add.y; + m_direction = kDiffToDir[add.x + 1][add.y + 1]; + } + + auto endOnExistingIt = std::find(existingPositions.begin(), existingPositions.end(), end); + if (endOnExistingIt != existingPositions.end()) + { + if (endOnExistingIt == existingPositions.begin()) + return false; // zero length remaining + + // shorten + auto remaining = endOnExistingIt - existingPositions.begin(); + newTubeParts.resize(remaining); + newTubeParts.push_back(ETubeDirection::Undefined); + m_endX = end.x; + m_endY = end.y; + m_tubeParts = std::move(newTubeParts); + return true; + } + + int n = 0; + while (end != cur) + { + MapVec add(sgn(end.x - cur.x), sgn(end.y - cur.y)); + if (newTubeParts.size() < 1 && forceStraightParts < 0) + { + // the first tube part should be in the same direction as the enter direction + dir_to_xy(m_direction, add); + } + if (n++ < forceStraightParts) + { + const bool xMajorPart = abs(end.x - m_endX) > abs(end.y - m_endY); + add.x = xMajorPart ? add.x : 0; + add.y = xMajorPart ? 0 : add.y; + } + cur += add; + //if (std::find(existingPositions.begin(), existingPositions.end(), std::make_pair(curX, curY)) != existingPositions.end()) + // return false; // intersection - maybe shorten? maybe we can even allow it if TS accepts it? + newTubeParts.push_back(kDiffToDir[add.x + 1][add.y + 1]); + } + + newTubeParts.push_back(ETubeDirection::Undefined); + m_endX = cur.x; + m_endY = cur.y; + m_tubeParts = std::move(newTubeParts); + + return true; +} + +bool CTube::walk(const std::function<bool(const WalkInfo&)>& walker) const +{ + MapVec diff; + WalkInfo wi; + wi.pos = MapCoords(m_startX, m_startY); + + for (auto dir : m_tubeParts) + { + wi.direction = dir; + dir_to_xy(wi.direction, diff); + wi.next_pos = (wi.direction == ETubeDirection::Undefined) ? MapCoords(-1, -1) : wi.pos + diff; + if (!walker(wi)) + return false; + if (wi.direction == ETubeDirection::Undefined) + break; + wi.pos = wi.next_pos; + } + return true; +} + + +#endif \ No newline at end of file diff --git a/MissionEditor/Tube.h b/MissionEditor/Tube.h new file mode 100644 index 0000000..dfdcbc6 --- /dev/null +++ b/MissionEditor/Tube.h @@ -0,0 +1,144 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <vector> +#include <string> +#include <functional> +#include "Structs.h" + +enum class ETubeDirection : char +{ + Undefined = -1, + Top=0, + TopRight=1, + Right=2, + BottomRight=3, + Bottom=4, + BottomLeft=5, + Left=6, + TopLeft=7, +}; + +inline ETubeDirection ToTubeDirection(const std::underlying_type_t<ETubeDirection> dir) +{ + if (dir > 7 || dir < -1) + return ETubeDirection::Undefined; + return static_cast<ETubeDirection>(dir); +} + +inline auto to_int(const ETubeDirection dir) +{ + return static_cast<std::underlying_type_t<ETubeDirection>>(dir); +} + +ETubeDirection opposite_dir(ETubeDirection dir); +bool dir_to_xy(ETubeDirection dir, MapVec& y); + +class CTube +{ +public: + struct WalkInfo + { + MapCoords pos; + ETubeDirection direction = ETubeDirection::Undefined; + MapCoords next_pos; + }; + +public: + CTube() = default; + CTube(std::uint16_t tubeId, const std::string& s); + CTube( + std::uint16_t tubeID, + std::uint16_t startX, + std::uint16_t startY, + ETubeDirection direction, + std::uint16_t endX, + std::uint16_t endY, + const std::vector<ETubeDirection>& tubeParts + ); + CTube( + std::uint16_t startX, + std::uint16_t startY, + ETubeDirection direction, + std::uint16_t endX, + std::uint16_t endY, + const std::vector<ETubeDirection>& tubeParts + ); + + CTube reverse(std::uint16_t newTubeID=0xFFFF) const; + + // full equivalency including id + bool operator==(const CTube& r) const = default; + + bool isEqual(const CTube& r, bool ignoreId) const; + + // Create tube with simple algorithm + static CTube autocreate(std::uint16_t startX, std::uint16_t startY, std::uint16_t endX, std::uint16_t endY, int straightStartParts=1); + + + const std::vector<ETubeDirection>& GetTubeParts() const + { + return m_tubeParts; + } + + void setId(std::uint16_t id) + { + m_tubeId = id; + } + + bool isCounterpart(const CTube& other) const + { + return getStartCoords() == other.getEndCoords() && getEndCoords() == other.getStartCoords(); + } + + bool hasId() const + { + return m_tubeId != 0xFFFF; + } + auto getId() const { return m_tubeId; } + auto getStartX() const { return m_startX; } + auto getStartY() const { return m_startY; } + MapCoords getStartCoords() const { return MapCoords(m_startX, m_startY); } + auto getInitialDirection() const { return m_direction; } + ETubeDirection getLastDirection() const; + auto getEndX() const { return m_endX; } + auto getEndY() const { return m_endY; } + MapCoords getEndCoords() const { return MapCoords(m_endX, m_endY); } + + bool touches(const MapCoords& mc) const; + + std::string toString() const; + + bool append(std::uint16_t endX, std::uint16_t endY, int forceStraightParts=-1); + + bool walk(const std::function<bool(const WalkInfo&)>& walker) const; + + bool isValid() const; + +private: + std::uint16_t m_tubeId = 0xFFFF; // ID of tube + std::uint16_t m_startX = 0; + std::uint16_t m_startY = 0; + ETubeDirection m_direction = ETubeDirection::Undefined; + std::uint16_t m_endX = 0; + std::uint16_t m_endY = 0; + std::vector<ETubeDirection> m_tubeParts; +}; \ No newline at end of file diff --git a/MissionEditor/TubeTool.cpp b/MissionEditor/TubeTool.cpp new file mode 100644 index 0000000..5c9c8ff --- /dev/null +++ b/MissionEditor/TubeTool.cpp @@ -0,0 +1,251 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "StdAfx.h" +#include "TubeTool.h" +#include "MapData.h" +#include "IsoView.h" +#include "Structs.h" +#include "inlines.h" +#include <memory> +#include <algorithm> + +std::unique_ptr<CTube> findTubeEndAt(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, const CMapData& map) +{ + const auto& tubes = map.GetTubes(); + auto it = std::find_if(tubes.begin(), tubes.end(), [mapCoords3d](const auto& tube) { return tube->getEndCoords() == mapCoords3d; }); + if (it != tubes.end()) + return std::make_unique<CTube>(**it); + // if not found, also try with z - 4 (e.g. behind cliffs) + auto backMapCoords = map.ToMapCoords3d(projCoords, map.GetHeightAt(mapCoords3d) - 4); + it = std::find_if(tubes.begin(), tubes.end(), [backMapCoords](const auto& tube) { return tube->getEndCoords() == backMapCoords; }); + if (it != tubes.end()) + return std::make_unique<CTube>(**it); + return nullptr; +} + +std::vector<std::uint16_t> findTubesAt(const ProjectedCoords& projCoords, const CMapData& map) +{ + std::vector<std::uint16_t> foundTubes; + for (auto& t : map.GetTubes()) + { + auto coords = map.ToMapCoords3d(projCoords, map.GetHeightAt(t->getStartCoords())); + if (t->touches(coords)) + foundTubes.push_back(t->getId()); + } + return foundTubes; +} + +AddTubeTool::AddTubeTool(CMapData& map, CIsoView& view, bool bidirectional): MapTool(map, view), + m_bidirectional(bidirectional) +{ + +} + +void AddTubeTool::finish() +{ + if (m_tube) { + if (m_tube->isValid()) + { + getMap().SetTube(m_tube.get()); + if (m_bidirectional) + { + auto t2 = m_tube->reverse(); + getMap().SetTube(&t2); + } + } + getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + m_mm_tube.reset(); + m_tube.reset(); + m_modified_tubes.clear(); +} + +bool AddTubeTool::onRButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) +{ + if (!m_modified_tubes.empty()) + { + // reset modified tubes to original state + for (auto& tube : m_modified_tubes) + { + getMap().SetTube(tube.get()); + } + } + bool ret = m_tube != nullptr; + m_mm_tube.reset(); + m_tube.reset(); + m_modified_tubes.clear(); + getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + return ret; // if we were adding or modifying a tube, a right click should just cancel this current tube, not the whole tool +} + +void AddTubeTool::onLButtonDblClick(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) +{ +} + +void AddTubeTool::onLButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) +{ + if (!m_tube) { + // first check if there is already a tube at the given location and take ownership if existing + auto tube = getTubeToModify(mapCoords3d, projCoords, flags); + if (tube) { + m_tube = std::move(tube); + + // also find reverse direction + if (m_bidirectional) + { + const auto& tubes = getMap().GetTubes(); + auto reversed = m_tube->reverse(); + auto reverseIt = std::find_if(tubes.begin(), tubes.end(), [&reversed](const auto& tube) { return tube->isEqual(reversed, true); }); + if (reverseIt != tubes.end()) + { + m_modified_tubes.push_back(std::make_unique<CTube>(**reverseIt)); + getMap().DeleteTube((*reverseIt)->getId()); + } + } + m_modified_tubes.push_back(std::make_unique<CTube>(*m_tube)); + getMap().DeleteTube(m_tube->getId()); + } + + if (!m_tube) { + // create a new tube, first click + m_tube = std::move(createNewTube(mapCoords3d)); + } + } + else + { + int z = getMap().GetHeightAt(m_tube->getStartCoords()); + auto mc = getMap().ToMapCoords3d(projCoords, z); + if (m_tube->getEndCoords() == MapCoords(mc.x, mc.y)) + { + finish(); + } + else + { + m_tube->append(mc.x, mc.y, m_tube->GetTubeParts().empty() ? 2 : 0); + } + + } + + getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + +std::unique_ptr<CTube> AddTubeTool::createNewTube(const MapCoords& mapCoords3d) const +{ + return std::make_unique<CTube>(mapCoords3d.x, mapCoords3d.y, ETubeDirection::Undefined, mapCoords3d.x, mapCoords3d.y, std::vector<ETubeDirection>()); +} + +std::unique_ptr<CTube> AddTubeTool::getTubeToModify(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, MapToolMouseFlags flags) const +{ + if ((flags & MapToolMouseFlags::SHIFT) == MapToolMouseFlags::SHIFT) + return findTubeEndAt(mapCoords3d, projCoords, getMap()); + return nullptr; +} + +void AddTubeTool::onMouseMove(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) +{ + if (m_tube) { + m_mm_tube.reset(new CTube(*m_tube)); + int z = getMap().GetHeightAt(m_tube->getStartCoords()); + auto mc = getMap().ToMapCoords3d(projCoords, z); + m_mm_tube->append(mc.x, mc.y, m_tube->GetTubeParts().empty() ? 2 : 0); + getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else + { + auto tube = getTubeToModify(mapCoords3d, projCoords, flags); + if (tube) + { + m_hover_tube = std::move(tube); + getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + else if (m_hover_tube) + { + m_hover_tube.reset(); + getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + } +} + +void AddTubeTool::render() +{ + if (m_mm_tube) + { + // mouse-move tube + getView().DrawTube(*m_mm_tube); + } + else if (m_tube) { + getView().DrawTube(*m_tube); + } + else if (m_hover_tube) + { + COLORREF col = RGB(0, 255, 0); + getView().DrawTube(*m_hover_tube, nullptr, &col); + } + +} + +RemoveTubeTool::RemoveTubeTool(CMapData& map, CIsoView& view) : MapTool(map, view) +{ +} + +void RemoveTubeTool::onMouseMove(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) +{ + auto& m = getMap(); + std::vector<std::uint16_t> tubes = findTubesAt(projCoords, getMap()); + + if ((flags & MapToolMouseFlags::LBUTTON) == MapToolMouseFlags::LBUTTON) + { + for (auto& id : tubes) + { + m.DeleteTube(id); + } + } + else + { + m_hover_tubes.reserve(tubes.size()); + std::transform(tubes.begin(), tubes.end(), std::back_inserter(m_hover_tubes), [this](std::uint16_t tubeId) { return std::make_unique<CTube>(*getMap().GetTube(tubeId)); }); + } + getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + m_hover_tubes.clear(); +} + +void RemoveTubeTool::render() +{ + for(auto& tube: m_hover_tubes) + { + COLORREF col = RGB(0, 255, 0); + getView().DrawTube(*tube, nullptr, &col); + } +} + +ModifyTubeTool::ModifyTubeTool(CMapData& map, CIsoView& view, bool bidirectional): AddTubeTool(map, view, bidirectional) +{ +} + +std::unique_ptr<CTube> ModifyTubeTool::getTubeToModify(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, MapToolMouseFlags flags) const +{ + return findTubeEndAt(mapCoords3d, projCoords, getMap()); +} + +std::unique_ptr<CTube> ModifyTubeTool::createNewTube(const MapCoords& mapCoords3d) const +{ + return nullptr; +} diff --git a/MissionEditor/TubeTool.h b/MissionEditor/TubeTool.h new file mode 100644 index 0000000..bb11779 --- /dev/null +++ b/MissionEditor/TubeTool.h @@ -0,0 +1,85 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "MapTool.h" +#include <vector> +class CTube; + +class AddTubeTool: public MapTool +{ +public: + AddTubeTool(CMapData& map, CIsoView& view, bool bidirectional); + virtual ~AddTubeTool() = default; + + void finish(); + + virtual bool onRButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags); + virtual void onLButtonDblClick(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags); + virtual void onLButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags); + virtual void onMouseMove(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags); + virtual void render(); + +protected: + AddTubeTool& operator=(const AddTubeTool& other) = delete; + + virtual std::unique_ptr<CTube> getTubeToModify(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, MapToolMouseFlags flags) const; + virtual std::unique_ptr<CTube> createNewTube(const MapCoords& mapCoords3d) const; + +private: + std::unique_ptr<CTube> m_tube; + std::unique_ptr<CTube> m_mm_tube; + std::unique_ptr<CTube> m_hover_tube; + std::vector<std::unique_ptr<CTube>> m_modified_tubes; + bool m_bidirectional; +}; + +class ModifyTubeTool : public AddTubeTool +{ +public: + ModifyTubeTool(CMapData& map, CIsoView& view, bool bidirectional); + virtual ~ModifyTubeTool() = default; + +protected: + ModifyTubeTool& operator=(const AddTubeTool& other) = delete; + + virtual std::unique_ptr<CTube> getTubeToModify(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, MapToolMouseFlags flags) const; + virtual std::unique_ptr<CTube> createNewTube(const MapCoords& mapCoords3d) const; + +private: +}; + +class RemoveTubeTool : public MapTool +{ +public: + RemoveTubeTool(CMapData& map, CIsoView& view); + virtual ~RemoveTubeTool() = default; + + virtual void onMouseMove(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags); + virtual void render(); + +protected: + RemoveTubeTool& operator=(const RemoveTubeTool& other) = delete; + +private: + std::vector<std::unique_ptr<CTube>> m_hover_tubes; +}; + diff --git a/MissionEditor/Unit.cpp b/MissionEditor/Unit.cpp new file mode 100644 index 0000000..42b716b --- /dev/null +++ b/MissionEditor/Unit.cpp @@ -0,0 +1,169 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Unit.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "Unit.h" +#include "resource.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CUnit + + +CUnit::CUnit(CWnd* pParent /*=NULL*/) + : CDialog(CUnit::IDD, pParent) +{ + //{{AFX_DATA_INIT(CUnit) + m_direction = _T(""); + m_flag1 = _T(""); + m_flag2 = _T(""); + m_house = _T(""); + m_flag3 = _T(""); + m_flag4 = _T(""); + m_flag5 = _T(""); + m_flag6 = _T(""); + m_action = _T(""); + m_tag = _T(""); + //}}AFX_DATA_INIT +} + + +void CUnit::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CUnit) + DDX_Control(pDX, IDC_STRENGTH, m_strength_ctrl); + DDX_CBString(pDX, IDC_DIRECTION, m_direction); + DDX_Text(pDX, IDC_P1, m_flag1); + DDX_Text(pDX, IDC_P2, m_flag2); + DDX_CBString(pDX, IDC_HOUSE, m_house); + DDX_Text(pDX, IDC_P3, m_flag3); + DDX_Text(pDX, IDC_P4, m_flag4); + DDX_Text(pDX, IDC_P5, m_flag5); + DDX_Text(pDX, IDC_P6, m_flag6); + DDX_CBString(pDX, IDC_STATE, m_action); + DDX_CBString(pDX, IDC_TAG, m_tag); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CUnit, CDialog) + //{{AFX_MSG_MAP(CUnit) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CUnit + +void CUnit::Init(CString house, CString strength, CString direction, CString action, CString tag, CString flag1, CString flag2, CString flag3, CString flag4, CString flag5, CString flag6) +{ + CIniFile& ini=Map->GetIniFile(); + + if(house=="") + { + m_house=*rules.sections["Houses"].GetValue(0); + if(ini.sections.find("Houses")!=ini.sections.end()) + if(ini.sections["Houses"].values.size()>0) + m_house=TranslateHouse(*ini.sections["Houses"].GetValue(0), TRUE); + } + else + m_house=TranslateHouse(house, TRUE); + + m_flag1=flag1; + m_flag2=flag2; + m_flag3=flag3; + m_flag4=flag4; + m_flag5=flag5; + m_flag6=flag6; + m_action=action; + m_strength=strength; + m_tag=tag; + m_direction=direction; +} + +BOOL CUnit::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // init the common (!) dialog things + int i; + CComboBox* house, *tag; + house=(CComboBox*)GetDlgItem(IDC_HOUSE); + tag=(CComboBox*)GetDlgItem(IDC_TAG); + + ListHouses(*house, FALSE); + ListTags(*tag,TRUE); + + + + UpdateData(FALSE); + m_strength_ctrl.SetRange(0,256); + m_strength_ctrl.SetPos(atoi(m_strength)); + + UpdateStrings(); + + return TRUE; +} + +void CUnit::OnOK() +{ + CDialog::OnOK(); + m_strength=GetText(&m_strength_ctrl); + UpdateData(); + TruncSpace(m_tag); + m_house=TranslateHouse(m_house); + + + +} + +void CUnit::UpdateStrings() +{ + + + SetWindowText(GetLanguageStringACP("UnitCap")); + SetDlgItemText(IDC_DESC, GetLanguageStringACP("UnitDesc")); + SetDlgItemText(IDC_LHOUSE, GetLanguageStringACP("UnitHouse")); + SetDlgItemText(IDC_LSTRENGTH, GetLanguageStringACP("UnitStrength")); + SetDlgItemText(IDC_LSTATE, GetLanguageStringACP("UnitState")); + SetDlgItemText(IDC_LDIRECTION, GetLanguageStringACP("UnitDirection")); + SetDlgItemText(IDC_LTAG, GetLanguageStringACP("UnitTag")); + SetDlgItemText(IDC_LP1, GetLanguageStringACP("UnitP1")); + SetDlgItemText(IDC_LP2, GetLanguageStringACP("UnitP2")); + SetDlgItemText(IDC_LP3, GetLanguageStringACP("UnitP3")); + SetDlgItemText(IDC_LP4, GetLanguageStringACP("UnitP4")); + SetDlgItemText(IDC_LP5, GetLanguageStringACP("UnitP5")); + SetDlgItemText(IDC_LP6, GetLanguageStringACP("UnitP6")); + + SetDlgItemText(IDOK, GetLanguageStringACP("OK")); + SetDlgItemText(IDCANCEL, GetLanguageStringACP("Cancel")); +} diff --git a/MissionEditor/Unit.h b/MissionEditor/Unit.h new file mode 100644 index 0000000..e191286 --- /dev/null +++ b/MissionEditor/Unit.h @@ -0,0 +1,80 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_UNIT_H__44A11CC3_84B6_11D3_B63B_F881F458F743__INCLUDED_) +#define AFX_UNIT_H__44A11CC3_84B6_11D3_B63B_F881F458F743__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Unit.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CUnit + +class CUnit : public CDialog +{ +// Konstruktion +public: + void UpdateStrings(); + CString m_strength; + void Init(CString house="", CString strength="256", CString direction="64", CString action="Guard", CString tag="None", CString flag1="0", CString flag2="0", CString flag3="0", CString flag4="0", CString flag5="0", CString flag6="0"); + CUnit(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CUnit) + enum { IDD = IDD_UNIT }; + CSliderCtrl m_strength_ctrl; + CString m_direction; + CString m_flag1; + CString m_flag2; + CString m_house; + CString m_flag3; + CString m_flag4; + CString m_flag5; + CString m_flag6; + CString m_action; + CString m_tag; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CUnit) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CUnit) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_UNIT_H__44A11CC3_84B6_11D3_B63B_F881F458F743__INCLUDED_ diff --git a/MissionEditor/UserScriptsDlg.cpp b/MissionEditor/UserScriptsDlg.cpp new file mode 100644 index 0000000..a932135 --- /dev/null +++ b/MissionEditor/UserScriptsDlg.cpp @@ -0,0 +1,3292 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// UserScriptsDlg.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "finalsun.h" +#include "UserScriptsDlg.h" +#include <io.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "variables.h" +#include "functions.h" +#include "inlines.h" +#include "combouinputdlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + +using namespace std; + +struct FunctionData +{ + CString* name; + CString* param; +public: + void Init(); + FunctionData(); + int paramcount; + void AddParam(); + ~FunctionData(); +}; + +struct JumpLineData +{ + CString name; + int line; +}; + +class CUserScript +{ +public: + void RaiseErr(int n, const char* str); + char errortext[250]; + int error; + int functioncount; + int GetFunction(int index, CString* name, CString *params[], int* paramcount); + int FindJumpLine(CString name); + int LoadFile(const char* filename); + CUserScript(); + virtual ~CUserScript(); + +private: + int AllocateFunction(); + FunctionData* functiondata; + map<CString, int> jumplinedata; + + + CString filename; +}; + +CUserScript::CUserScript() +{ + functioncount=0; + functiondata=NULL; + +} + +CUserScript::~CUserScript() +{ + if(functiondata!=NULL) free( functiondata); +} + +int CUserScript::FindJumpLine(CString name) +{ + if(jumplinedata.find(name)==jumplinedata.end()) return -1; + return jumplinedata[name]; +} + +int CUserScript::LoadFile(const char *setupfile) +{ + filename=setupfile; + + int file=_open(setupfile, _O_RDONLY); + if(file==-1) + { + MessageBox(0, "Error opening script file", "Error", MB_ICONERROR); + return -1; + } + + int parsepos=0, filesize=0; + BOOL inFunction=FALSE; + BOOL inParam=FALSE; + BOOL inComment=FALSE; + BOOL inFunctionHead=FALSE; + BOOL inNewOrder=TRUE; + BOOL inJumpLine=FALSE; + + + + while(!(_eof(file))) + { + unsigned char c; + int res=_read(file,(void*) &c, 1); + if(res>0) filesize++; + } + + _lseek(file, 0, SEEK_SET); + unsigned char *data=new(unsigned char[filesize+5]); + data[filesize]=0; + for (parsepos=0;parsepos<filesize;parsepos++) + { + _read(file, data+parsepos, 1); + } + _close(file); + + //MessageBox(0,(char*)data,"DEBUG: SETUPSCRIPT:/",0); + + BYTE jumplinename[512]; + memset(jumplinename, 512, 0); + + //// MAIN STUFF HERE //// + for(parsepos=0;parsepos<filesize;parsepos++) + { + + + if(inComment==TRUE || inNewOrder==FALSE) + { + + + + if(data[parsepos]=='\n') + { + //MessageBox(0, "NEWLINE", (char*)&data[parsepos+1], 0); + inNewOrder=TRUE; + inComment=FALSE; + inJumpLine=FALSE; + memset(jumplinename, 0, 512); + + } + } + + else if(inFunction==FALSE && inComment==FALSE && inFunctionHead==FALSE && inJumpLine==FALSE) + { + // easy here, just seek for new position + + if(data[parsepos]=='/' && data[parsepos+1]=='/') + { + inComment=TRUE; + } + else if(data[parsepos]==';') + { + inNewOrder=TRUE; + } + else if(data[parsepos]==':') + { + inJumpLine=TRUE; + } + else if(IsCharAlphaNumeric(data[parsepos])!=0 && inNewOrder==TRUE && inJumpLine==FALSE) + { + inFunction=TRUE; + int pos=AllocateFunction(); + //*functiondata[pos-1].name.append(data[parsepos]); + *functiondata[pos-1].name = (char)data[parsepos]; + } + + } + else if(data[parsepos]=='(' && inComment==FALSE && inParam==FALSE) + { + //MessageBox(0, "InHead","",0); + inFunctionHead=TRUE; + } + else if(inFunctionHead==TRUE && inParam==TRUE) + { + if(data[parsepos]=='\\') + { + if(data[parsepos+1]=='n' || data[parsepos+1]=='N') + { + data[parsepos]='\n'; + functiondata[functioncount-1].param[functiondata[functioncount-1].paramcount-1]+=data[parsepos]; + parsepos++; + } + if(data[parsepos+1]=='r' || data[parsepos+1]=='R') + { + data[parsepos]='\r'; + functiondata[functioncount-1].param[functiondata[functioncount-1].paramcount-1]+=data[parsepos]; + parsepos++; + } + } + + else if(data[parsepos]=='"' && data[parsepos+1]!='"') + { + inParam=FALSE; + //MessageBox(0, functiondata[functioncount-1].param[functiondata[functioncount-1].paramcount-1].data(), functiondata[functioncount-1].name->data(), 0); + + + } + else + { + + // add character to param + functiondata[functioncount-1].param[functiondata[functioncount-1].paramcount-1]+=data[parsepos]; + if(data[parsepos]=='"' && data[parsepos+1]=='"') parsepos++; // ignore the next " + + + } + } + else if(inFunction==TRUE && inParam==FALSE && inFunctionHead==FALSE) + { + if(IsCharAlphaNumeric(data[parsepos])!=0) + { + *functiondata[functioncount-1].name+=data[parsepos]; + } + else + { + inFunction=FALSE; + //MessageBox(0, functiondata[functioncount-1].name->data(), "FUNCTIONAME", 0); + } + } + + else if(inFunctionHead==TRUE && inParam==FALSE) + { + if(data[parsepos]=='"') + { + // add a param! + inParam=TRUE; + functiondata[functioncount-1].AddParam(); + functiondata[functioncount-1].param[functiondata[functioncount-1].paramcount-1]=""; + } + if(data[parsepos]==')') + { + inFunctionHead=FALSE; + //MessageBox(0, (char*)&data[parsepos], "", 0); + } + } + + else if(inJumpLine==TRUE) + { + if(data[parsepos]!=':') + { + char d[2]; + d[0]=data[parsepos]; + d[1]=0; + strcat((char*)jumplinename, d); + } + else + { + jumplinedata[jumplinename]=functioncount; + //MessageBox(0,(char*)jumplinename,"",0); + memset(jumplinename, 0, 512); + inJumpLine=FALSE; + inNewOrder=TRUE; + } + } + + + + + } + ///////////////////////// + + + + + delete[] (data); + return 0; +} + +int CUserScript::GetFunction(int index, CString *name, CString * params[], int* paramcount) +{ + if(index<0 || index>=functioncount) return -1; + + *name=*functiondata[index].name; + *paramcount=functiondata[index].paramcount; + + //if(params==NULL) return 0; + if (*paramcount>0) + { + *params=new(CString[*paramcount]); + } + else *params=0; + + + int i; + for(i=0;i<*paramcount;i++) + { + //params[i]=new(CString); + CString* str=*params; + str[i]=functiondata[index].param[i]; + //memcpy((void*)params[i], (void*) &functiondata[index].param[i], &function + //MessageBox(0,functiondata[index].param[i].data(),"",0); + } + + + return 0; +} + +void FunctionData::AddParam() +{ + //CString* tmp=NULL; + //if(paramcount>0) + //{ + + //tmp=new(CString[paramcount]); + //memcpy((void*)tmp, param, sizeof(CString)*paramcount); + + //delete[] (functiondata); //delete is bad-> CStrings would be deallocated! + //delete[](param); + //param=NULL; + //} + //param=(CString*)realloc(param, (paramcount+1)*sizeof(CString)); + //param[paramcount]=CString(); + //CString hack; + //memset(¶m[paramcount], 0, sizeof(CString)); + //memcpy(¶m[paramcount], &hack, sizeof(CString)); + //param[paramcount]=""; + //param=new(CString[paramcount+1]); + // + //memcpy((void*) param, (void*) tmp, sizeof(CString)*paramcount); + + //name=""; + + CString* newparam=new(CString[paramcount+1]); + int i; + for(i=0;i<paramcount;i++) + { + newparam[i]=param[i]; + } + newparam[paramcount]=""; + + delete[] param; + + param=newparam; + + paramcount++; + //delete[](tmp); + +} + + +FunctionData::FunctionData() +{ + paramcount=0; + param=NULL; + name=new(CString); +} + +FunctionData::~FunctionData() +{ + if (param!=NULL) delete[] param; + paramcount=0; + delete (name); +} + +int CUserScript::AllocateFunction() +{ + /*FunctionData* tmp=NULL; + if(functioncount>0) + { + + tmp=new(FunctionData[functioncount]); + memcpy((void*)tmp, functiondata, sizeof(FunctionData)*functioncount); + delete[] functiondata; + functiondata=NULL; + } + + functiondata=new(FunctionData[functioncount+1]); + + memcpy((void*) functiondata, (void*) tmp, sizeof(FunctionData)*functioncount); + + functiondata[functioncount].name="";*/ + functiondata=(FunctionData*)realloc(functiondata, sizeof(FunctionData)*(functioncount+1)); + + functiondata[functioncount].Init(); + + *functiondata[functioncount].name="HUHU"; + + functioncount++; + //delete[] (tmp); + return functioncount; +} + +void CUserScript::RaiseErr(int n, const char *str) +{ + +} + +void FunctionData::Init() +{ + paramcount=0; + param=NULL; + name=new(CString); +} + + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CUserScriptsDlg + + +CUserScriptsDlg::CUserScriptsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CUserScriptsDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CUserScriptsDlg) + m_Script = _T(""); + m_Report = _T(""); + //}}AFX_DATA_INIT +} + + +void CUserScriptsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CUserScriptsDlg) + DDX_LBString(pDX, IDC_SCRIPTS, m_Script); + DDX_Text(pDX, IDC_REPORT, m_Report); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CUserScriptsDlg, CDialog) + //{{AFX_MSG_MAP(CUserScriptsDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CUserScriptsDlg + +#define ASK_CONTINUE "AskContinue" +#define ADD_TRIGGER "AddTrigger" +#define MESSAGE "Message" +#define SET_INI_KEY "SetIniKey" +#define SET_SAFE_MODE "SetSafeMode" +#define SET_VARIABLE "SetVariable" +#define SET_VARIABLE_IF "SetVariableIf" +#define ADD "Add" +#define MULTI "Multi" +#define SUBSTRACT "Substract" +#define DIVIDE "Divide" +#define SET_WAYPOINT "SetWaypoint" +#define REQUIRES_MP "RequiresMP" +#define REQUIRES_SP "RequiresSP" +#define ADD_AI_TRIGGER "AddAITrigger" +#define ADD_TAG "AddTag" +#define RESIZE "Resize" +#define IS "Is" +#define CANCEL "Cancel" +#define PRINT "Print" +#define TOLOWER "LowerCase" +#define TOUPPER "UpperCase" +#define GET_FREE_WAYPOINT "GetFreeWaypoint" +#define UINPUT_GET_INTEGER "UInputGetInteger" +#define UINPUT_GET_STRING "UInputGetString" +#define JUMP_TO_LINE "JumpTo" +#define SET_AUTO_UPDATE "SetAutoUpdate" +#define GET_RANDOM "GetRandom" +#define ADD_TERRAIN "AddTerrain" +#define GET_INI_KEY "GetIniKey" +#define MODULO "Mod" +#ifdef SMUDGE_SUPP +#define ADD_SMUDGE "AddSmudge" +#endif +#define INSERT "Insert" +#define LENGTH "Length" +#define TRIM "Trim" +#define GETCHAR "GetChar" +#define REPLACE "Replace" +#define REMOVE "Remove" +#define GET_WAYPOINT_POS "GetWaypointPos" +#define GET_PARAM "GetParam" +#define SET_PARAM "SetParam" +#define GET_PARAM_COUNT "GetParamCount" +#define ALLOW_DELETE "AllowDelete" +#define DELETE_TERRAIN "DeleteTerrain" +#define DELETE_INFANTRY "DeleteInfantry" +#define DELETE_AIRCRAFT "DeleteAircraft" +#define DELETE_STRUCTURE "DeleteStructure" +#define DELETE_VEHICLE "DeleteVehicle" +#define IS_INFANTRY_DELETED "IsInfantryDeleted" +#define IS_TERRAIN_DELETED "IsTerrainDeleted" +#define ADD_INFANTRY "AddInfantry" +#define ALLOW_ADD "AllowAdd" +#define ADD_VEHICLE "AddVehicle" +#define ADD_AIRCRAFT "AddAircraft" +#define ADD_STRUCTURE "AddStructure" +#define GET_INFANTRY "GetInfantry" +#define GET_AIRCRAFT "GetAircraft" +#define GET_STRUCTURE "GetStructure" +#define GET_VEHICLE "GetVehicle" +#define UINPUT_GET_HOUSE "UInputGetHouse" +#define UINPUT_GET_COUNTRY "UInputGetCountry" +#define UINPUT_GET_TRIGGER "UInputGetTrigger" +#define UINPUT_GET_TAG "UInputGetTag" +#define MESSAGE_YES_NO "Ask" +#define GET_HOUSE "GetHouse" +#define GET_COUNTRY "GetCountry" +#define GET_HOUSE_INDEX "GetHouseIndex" +#define OR "Or" +#define AND "And" +#define NOT "Not" +#define UINPUT_GET_MANUAL "UInputSelect" + +#define ID_ASK_CONTINUE 0 +#define ID_ADD_TRIGGER 1 +#define ID_MESSAGE 2 +#define ID_SET_INI_KEY 3 +#define ID_SET_SAFE_MODE 4 +#define ID_SET_VARIABLE 5 +#define ID_SET_VARIABLE_IF 6 +#define ID_ADD 7 +#define ID_MULTI 8 +#define ID_SUBSTRACT 9 +#define ID_DIVIDE 10 +#define ID_SET_WAYPOINT 11 +#define ID_REQUIRES_MP 12 +#define ID_REQUIRES_SP 13 +#define ID_ADD_AI_TRIGGER 14 +#define ID_ADD_TAG 15 +#define ID_RESIZE 16 +#define ID_IS 17 +#define ID_CANCEL 18 +#define ID_PRINT 19 +#define ID_TOLOWER 20 +#define ID_TOUPPER 21 +#define ID_GET_FREE_WAYPOINT 22 +#define ID_UINPUT_GET_INTEGER 23 +#define ID_UINPUT_GET_STRING 24 +#define ID_JUMP_TO_LINE 25 +#define ID_SET_AUTO_UPDATE 26 +#define ID_GET_RANDOM 27 +#define ID_ADD_TERRAIN 28 +#define ID_GET_INI_KEY 29 +#define ID_MODULO 30 +#ifdef SMUDGE_SUPP +#define ID_ADD_SMUDGE 31 +#endif +#define ID_INSERT 32 +#define ID_LENGTH 33 +#define ID_TRIM 34 +#define ID_GETCHAR 35 +#define ID_REPLACE 36 +#define ID_REMOVE 37 +#define ID_GET_WAYPOINT_POS 38 +#define ID_GET_PARAM 39 +#define ID_SET_PARAM 40 +#define ID_GET_PARAM_COUNT 41 +#define ID_ALLOW_DELETE 42 +#define ID_DELETE_TERRAIN 43 +#define ID_DELETE_INFANTRY 44 +#define ID_DELETE_STRUCTURE 45 +#define ID_DELETE_AIRCRAFT 46 +#define ID_DELETE_VEHICLE 47 +#define ID_IS_INFANTRY_DELETED 48 +#define ID_IS_TERRAIN_DELETED 49 +#define ID_ADD_INFANTRY 50 +#define ID_ALLOW_ADD 51 +#define ID_ADD_VEHICLE 52 +#define ID_ADD_AIRCRAFT 53 +#define ID_ADD_STRUCTURE 54 +#define ID_GET_INFANTRY 55 +#define ID_GET_AIRCRAFT 56 +#define ID_GET_STRUCTURE 57 +#define ID_GET_VEHICLE 58 +#define ID_UINPUT_GET_HOUSE 59 +#define ID_UINPUT_GET_COUNTRY 60 +#define ID_UINPUT_GET_TRIGGER 61 +#define ID_UINPUT_GET_TAG 62 +#define ID_MESSAGE_YES_NO 63 +#define ID_GET_HOUSE 64 +#define ID_GET_COUNTRY 65 +#define ID_GET_HOUSE_INDEX 66 +#define ID_OR 67 +#define ID_AND 68 +#define ID_NOT 69 +#define ID_UINPUT_GET_MANUAL 70 + + +extern CString GetFree(const char* section); + +BOOL IsValSet(CString val) +{ + val.MakeLower(); + if(val=="false" || val=="no") return FALSE; // val is not set + if(val=="true" || val=="yes") return TRUE; + if(atoi(val)) return TRUE; + return FALSE; +} + +int get_player_count() +{ + if(Map->IsMultiplayer()==FALSE) return 1; + + int i; + int wp_count=0; + for(i=0;i<Map->GetWaypointCount();i++) + { + CString id; + DWORD pos; + Map->GetWaypointData(i, &id, &pos); + int idi; + idi=atoi(id); + if(idi!=i) break; + if(idi>=0 && idi<8) + { + wp_count++; + } + } + + return wp_count; +} + +struct FUNC_INFO +{ + int type; + CString name; + CString* params; + int paramcount; +}; + +void CUserScriptsDlg::OnOK() +{ + UpdateData(TRUE); + + //srand((unsigned)time(NULL)); + + if(m_Script.GetLength()==0) return; + + CUserScript s; + s.LoadFile((CString)AppPath+(CString)"\\Scripts\\"+m_Script); + + CIniFile& ini=Map->GetIniFile(); + + BOOL bUpdate=FALSE; + BOOL bUpdateOnlyMission=TRUE; + BOOL bNoRepos=TRUE; + BOOL bSafeMode=TRUE; + + map<CString, CString> variables; + char c[50]; + + + CString report=m_Script+" Report:\r\n\r\n"; + + BOOL bAutoUpdate=TRUE; + BOOL bAllowLoop=TRUE; // for now we enable this, as we´ve introduced a loop counter + + // stuff for faster CMapData processing: + BOOL bUpdateWaypoints=FALSE; + BOOL bOldUpdate=Map->m_noAutoObjectUpdate; + + BOOL bDeleteAllowed=FALSE; // shall the script be able to delete stuff? + BOOL bAddAllowed=FALSE; // " delete stuff + + + + + + // for delete/add stuff: + int lastInfantryDeleted=-1; + CString lastStructureDeleted=""; + int lastTerrainDeleted=-1; + CString lastUnitDeleted=""; + CString lastAircraftDeleted=""; + + + BOOL bIgnoreLoopCounts=FALSE; + int loop_count=0; + + + map<int, FUNC_INFO> functions; + + // get function ids + int i; + for(i=0;i<s.functioncount;i++) + { + FUNC_INFO info; + CString& name=info.name; + + s.GetFunction(i, &info.name, &info.params, &info.paramcount); + + + + if(name==ASK_CONTINUE) + { + info.type=ID_ASK_CONTINUE; + } + else if(name==MESSAGE) + { + info.type=ID_MESSAGE; + } + else if(name==ADD_TRIGGER) + { + info.type=ID_ADD_TRIGGER; + } + else if(name==SET_INI_KEY) + { + info.type=ID_SET_INI_KEY; + } + else if(name==SET_SAFE_MODE) + { + info.type=ID_SET_SAFE_MODE; + } + else if(name==SET_VARIABLE) + { + info.type=ID_SET_VARIABLE; + } + else if(name==ADD) + { + info.type=ID_ADD; + } + else if(name==SUBSTRACT) + { + info.type=ID_SUBSTRACT; + } + else if(name==MULTI) + { + info.type=ID_MULTI; + } + else if(name==DIVIDE) + { + info.type=ID_DIVIDE; + } + else if(name==SET_WAYPOINT) + { + info.type=ID_SET_WAYPOINT; + } + else if(name==REQUIRES_MP) + { + info.type=ID_REQUIRES_MP; + } + else if(name==REQUIRES_SP) + { + info.type=ID_REQUIRES_SP; + } + else if(name==ADD_AI_TRIGGER) + { + info.type=ID_ADD_AI_TRIGGER; + } + else if(name==ADD_TAG) + { + info.type=ID_ADD_TAG; + } + else if(name==RESIZE) + { + info.type=ID_RESIZE; + } + else if(name==IS) + { + info.type=ID_IS; + } + else if(name==CANCEL) + { + info.type=ID_CANCEL; + } + else if(name==PRINT) + { + info.type=ID_PRINT; + } + else if(name==TOLOWER) + { + info.type=ID_TOLOWER; + } + else if(name==TOUPPER) + { + info.type=ID_TOUPPER; + } + else if(name==GET_FREE_WAYPOINT) + { + info.type=ID_GET_FREE_WAYPOINT; + } + else if(name==UINPUT_GET_INTEGER) + { + info.type=ID_UINPUT_GET_INTEGER; + } + else if(name== UINPUT_GET_STRING ) + { + info.type=ID_UINPUT_GET_STRING; + } + else if(name==JUMP_TO_LINE) + { + info.type=ID_JUMP_TO_LINE; + } + else if(name==SET_AUTO_UPDATE) + { + info.type=ID_SET_AUTO_UPDATE; + } + else if(name==GET_RANDOM) + { + info.type=ID_GET_RANDOM; + } + else if(name==ADD_TERRAIN) + { + info.type=ID_ADD_TERRAIN; + } + else if(name==GET_INI_KEY) + { + info.type=ID_GET_INI_KEY; + } + else if(name==MODULO) + { + info.type=ID_MODULO; + } +#ifdef SMUDGE_SUPP + else if(name==ADD_SMUDGE) + { + info.type=ID_ADD_SMUDGE; + } +#endif + else if(name==INSERT) + { + info.type=ID_INSERT; + } + else if(name==LENGTH) + { + info.type=ID_LENGTH; + } + else if(name==TRIM) + { + info.type=ID_TRIM; + } + else if(name==GETCHAR) + { + info.type=ID_GETCHAR; + } + else if(name==REPLACE) + { + info.type=ID_REPLACE; + } + else if(name==REMOVE) + { + info.type=ID_REMOVE; + } + else if(name==GET_WAYPOINT_POS) + { + info.type=ID_GET_WAYPOINT_POS; + } + else if(name==GET_PARAM) + { + info.type=ID_GET_PARAM; + } + else if(name==SET_PARAM) + { + info.type=ID_SET_PARAM; + } + else if(name==GET_PARAM_COUNT) + { + info.type=ID_GET_PARAM_COUNT; + } + else if(name==ALLOW_DELETE) + { + info.type=ID_ALLOW_DELETE; + } + else if(name==DELETE_TERRAIN) + { + info.type=ID_DELETE_TERRAIN; + } + else if(name==DELETE_INFANTRY) + { + info.type=ID_DELETE_INFANTRY; + } + else if(name==DELETE_STRUCTURE) + { + info.type=ID_DELETE_STRUCTURE; + } + else if(name==DELETE_AIRCRAFT) + { + info.type=ID_DELETE_AIRCRAFT; + } + else if(name==DELETE_VEHICLE) + { + info.type=ID_DELETE_VEHICLE; + } + else if(name==IS_INFANTRY_DELETED) + { + info.type=ID_IS_INFANTRY_DELETED; + } + else if(name==IS_TERRAIN_DELETED) + { + info.type=ID_IS_TERRAIN_DELETED; + } + else if(name==ADD_INFANTRY) + { + info.type=ID_ADD_INFANTRY; + } + else if(name==ALLOW_ADD) + { + info.type=ID_ALLOW_ADD; + } + else if(name==ADD_VEHICLE) info.type=ID_ADD_VEHICLE; + else if(name==ADD_AIRCRAFT) info.type=ID_ADD_AIRCRAFT; + else if(name==ADD_STRUCTURE) info.type=ID_ADD_STRUCTURE; + else if(name==GET_INFANTRY) info.type=ID_GET_INFANTRY; + else if(name==GET_AIRCRAFT) info.type=ID_GET_AIRCRAFT; + else if(name==GET_STRUCTURE) info.type=ID_GET_STRUCTURE; + else if(name==GET_VEHICLE) info.type=ID_GET_VEHICLE; + else if(name==UINPUT_GET_HOUSE) info.type=ID_UINPUT_GET_HOUSE; + else if(name==UINPUT_GET_COUNTRY) info.type=ID_UINPUT_GET_COUNTRY; + else if(name==UINPUT_GET_TRIGGER) info.type=ID_UINPUT_GET_TRIGGER; + else if(name==UINPUT_GET_TAG) info.type=ID_UINPUT_GET_TAG; + else if(name==MESSAGE_YES_NO) info.type=ID_MESSAGE_YES_NO; + else if(name==GET_HOUSE) info.type=ID_GET_HOUSE; + else if(name==GET_COUNTRY) info.type=ID_GET_COUNTRY; + else if(name==GET_HOUSE_INDEX) info.type=ID_GET_HOUSE_INDEX; + else if(name==OR) info.type=ID_OR; + else if(name==AND) info.type=ID_AND; + else if(name==NOT) info.type=ID_NOT; + else if(name==UINPUT_GET_MANUAL) info.type=ID_UINPUT_GET_MANUAL; + + else info.type=-1; + + + + + functions[i]=info; + } + + + for(i=0;i<s.functioncount;i++) + { + // initialize global variables here so they can´t be overwritten! + itoa(Map->GetWidth(), c, 10); + variables["%Width%"]=c; + itoa(Map->GetHeight(), c, 10); + variables["%Height%"]=c; + itoa(Map->GetIsoSize(), c, 10); + variables["%IsoSize%"]=c; + itoa(Map->GetWaypointCount(), c, 10); + variables["%WaypointCount%"]=c; + itoa(Map->GetUnitCount(), c, 10); + variables["%UnitCount%"]=c; + itoa(Map->GetInfantryCount(), c, 10); + variables["%InfantryCount%"]=c; + itoa(Map->GetStructureCount(), c, 10); + variables["%StructureCount%"]=c; + itoa(Map->GetAircraftCount(), c, 10); + variables["%AircraftCount%"]=c; + itoa(Map->GetTerrainCount(), c, 10); + variables["%TerrainCount%"]=c; + variables["%Theater%"]=Map->GetTheater(); + itoa(get_player_count(), c, 10); + variables["%PlayerCount%"]=c; + itoa(Map->GetHousesCount(FALSE), c, 10); + variables["%HousesCount%"]=c; + itoa(Map->GetHousesCount(TRUE), c, 10); + variables["%CountriesCount%"]=c; + + if(bDeleteAllowed) + { + variables["%DeleteAllowed%"]="1"; + } + else + variables["%DeleteAllowed%"]="0"; + + if(bAddAllowed) + { + variables["%AddAllowed%"]="1"; + } + else + variables["%AddAllowed%"]="0"; + + if(bSafeMode) + variables["%SafeMode%"]="1"; + else + variables["%SafeMode%"]="0"; + + //CString name; + int name=functions[i].type; + + int paramcount=functions[i].paramcount; + + CString* params=NULL; + + if(paramcount) + { + params=new(CString[paramcount]); + int e; + for(e=0;e<paramcount;e++) + params[e]=functions[i].params[e]; + } + + //s.GetFunction(i, &name, ¶ms, ¶mcount); + + + BOOL * replaceVariables=new(BOOL[paramcount+4]); // make sure at least room for 4 variables + + int h; + for(h=0;h<paramcount;h++) replaceVariables[h]=TRUE; + + if(name==ID_SET_VARIABLE || name==ID_ADD || name==ID_SUBSTRACT || name==ID_MULTI || name==ID_DIVIDE + || name==ID_TOLOWER || name==ID_TOUPPER || name==ID_GET_FREE_WAYPOINT || name==ID_JUMP_TO_LINE + || name==ID_UINPUT_GET_INTEGER || name==ID_UINPUT_GET_STRING || name==ID_GET_RANDOM || name==ID_ADD_TRIGGER + || name==ID_ADD_AI_TRIGGER || name==ID_GET_INI_KEY || name==ID_MODULO || name==ID_INSERT + || name==ID_LENGTH || name==ID_TRIM || name==ID_GETCHAR || name==ID_REPLACE || name==ID_REMOVE + || name==ID_GET_PARAM || name==ID_SET_PARAM || name==ID_GET_PARAM_COUNT || name==ID_IS_INFANTRY_DELETED + || name==ID_IS_TERRAIN_DELETED || name==ID_GET_INFANTRY || name==ID_GET_AIRCRAFT || name==ID_GET_STRUCTURE + || name==ID_GET_VEHICLE || name==ID_UINPUT_GET_TRIGGER || name==ID_UINPUT_GET_TAG + || name==ID_UINPUT_GET_HOUSE || name==ID_UINPUT_GET_COUNTRY || name==ID_MESSAGE_YES_NO + || name==ID_OR || name==ID_AND || name==ID_NOT || name==ID_UINPUT_GET_MANUAL) + { + replaceVariables[0]=FALSE; + } + + if(name==ID_GET_WAYPOINT_POS ) + { + replaceVariables[1]=FALSE; + replaceVariables[2]=FALSE; + } + + if(name==ID_IS) + { + replaceVariables[3]=FALSE; + } + + + + map<CString, CString>::iterator e; + + + for(e=variables.begin();e!=variables.end();e++) + { + for(h=0;h<paramcount;h++) + { + if(replaceVariables[h]) + { + params[h].Replace(e->first, e->second); + } + } + } + + + delete[] replaceVariables; + + + if(name==ID_ASK_CONTINUE) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + int res=MessageBox(params[0], "Continue?", MB_YESNO); + if(res==IDNO) break; + } + else if(name==ID_MESSAGE) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + MessageBox(params[0], params[1]); + } + else if(name==ID_MESSAGE_YES_NO) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + int res=MessageBox(params[1], params[2], MB_YESNO); + if(res==IDYES) + { + variables[params[0]]="1"; + } + else + variables[params[0]]="0"; + } + else if(name==ID_ADD_TRIGGER) + { + if(paramcount<5) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>5) + { + if(params[5].GetLength()>0) + { + if(!IsValSet(params[5])) goto nextline; + } + } + + if(!bAddAllowed) goto nextline; + + + CString ID_T=GetFreeID(); + + if(params[0].GetLength()>0) + { + variables[params[0]]=ID_T; + } + + ini.sections["Triggers"].values[ID_T]=params[1]; + ini.sections["Events"].values[ID_T]=params[2]; + ini.sections["Actions"].values[ID_T]=params[3]; + + BOOL tag=TRUE; + params[4].MakeLower(); + if(params[4]=="false" || params[4]=="no") tag=FALSE; + + if(tag) + { + CString ID_TAG=GetFreeID(); + ini.sections["Tags"].values[ID_TAG]="0,"; + ini.sections["Tags"].values[ID_TAG]+=GetParam(params[1],2); + ini.sections["Tags"].values[ID_TAG]+=","; + ini.sections["Tags"].values[ID_TAG]+=ID_T; + } + + report+="Trigger " + GetParam(params[1],2) + " added\r\n"; + + bUpdate=TRUE; + } + else if(name==ID_SET_INI_KEY) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + //if(ini.sections[params[0]].FindName(params[1])>=0) + { + if(bSafeMode) goto nextline; + } + + ini.sections[params[0]].values[params[1]]=params[2]; + + report +=params[0]+(CString)"->"+params[1]+(CString) " set to \"" + params[2] + "\"\r\n"; + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + else if(name==ID_GET_INI_KEY) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + if(ini.sections.find(params[1])==ini.sections.end() || ini.sections[params[1]].FindName(params[2])<0) + { + variables[params[0]]=""; + } + else + variables[params[0]]=ini.sections[params[1]].values[params[2]]; + } + else if(name==ID_SET_SAFE_MODE) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + BOOL enabled=TRUE; + params[0].MakeLower(); + if(params[0]=="false" || params[0]=="no") enabled=FALSE; + + if(!enabled) + { + CString s; + s="This script wants to disable INI protection. For some scripts this may be necessary, but it can seriously damage your Map-> Reason why script wants to disable INI protection:\n"; + s+=params[1]; + s+="\n\nDisable INI protection?"; + + int res=MessageBox(s, "Disable INI protection?", MB_YESNO | MB_DEFBUTTON2); + if(res==IDNO) goto nextline; + } + + if(!enabled) report+="INI Protection disabled\r\n"; + if(enabled) report+="INI Protection enabled\r\n"; + + bSafeMode=enabled; + } + else if(name==ID_SET_VARIABLE) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + variables[params[0]]=params[1]; + } + else if(name==ID_ADD) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int n; + n=atoi(variables[params[0]]); + int n2=atoi(params[1]); + n+=n2; + char c[50]; + itoa(n, c, 10); + variables[params[0]]=c; + } + else if(name==ID_INSERT) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + int pos=atoi(params[2]); + + if(pos<0) + { + pos=variables[params[0]].GetLength(); + } + + variables[params[0]].Insert(pos, params[1]); + } + else if(name==ID_REPLACE) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + variables[params[0]].Replace(params[1], params[2]); + } + else if(name==ID_TRIM) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + variables[params[0]].TrimLeft(); + variables[params[0]].TrimRight(); + } + else if(name==ID_NOT) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + if(IsValSet(variables[params[0]])) + variables[params[0]]="0"; + else + variables[params[0]]="1"; + } + else if(name==ID_AND) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + BOOL bSet=TRUE; + + int k; + for(k=1;k<paramcount;k++) + { + if(!IsValSet(params[k])) { bSet=FALSE; break; } + } + + CString s="0"; + if(bSet) s="1"; + + variables[params[0]]=s; + } + else if(name==ID_OR) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + BOOL bSet=FALSE; + + int k; + for(k=1;k<paramcount;k++) + { + if(IsValSet(params[k])) { bSet=TRUE; break; } + } + + CString s="0"; + if(bSet) s="1"; + + variables[params[0]]=s; + } + else if(name==ID_LENGTH) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int len=params[1].GetLength(); + char c[50]; + itoa(len, c, 10); + variables[params[0]]=c; + } + else if(name==ID_REMOVE) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + if(atoi(params[1])>=variables[params[0]].GetLength() || atoi(params[1])<0 || atoi(params[2])<0) + { + MessageBox("Invalid index or length for remove command, script cancelled.","Error"); + delete[] params; + break; + } + + variables[params[0]].Delete(atoi(params[1]),atoi(params[2])); + } + else if(name==ID_GETCHAR) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + if(atoi(params[2])>=params[1].GetLength() || atoi(params[2])<0) + { + MessageBox("Invalid index for GetChar command, script cancelled.","Error"); + delete[] params; + break; + } + + variables[params[0]]=params[1].GetAt(atoi(params[2])); + } + else if(name==ID_SUBSTRACT) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int n; + n=atoi(variables[params[0]]); + int n2=atoi(params[1]); + n-=n2; + char c[50]; + itoa(n, c, 10); + variables[params[0]]=c; + } + else if(name==ID_MULTI) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int n; + n=atoi(variables[params[0]]); + int n2=atoi(params[1]); + n=n*n2; + char c[50]; + itoa(n, c, 10); + variables[params[0]]=c; + } + else if(name==ID_DIVIDE) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int n; + n=atoi(variables[params[0]]); + int n2=atoi(params[1]); + + if(n2==0) + { + MessageBox("Division through 0, script cancelled", "Division through 0"); + delete[] params; + break; + } + + n=n/n2; + char c[50]; + itoa(n, c, 10); + variables[params[0]]=c; + } + else if(name==ID_MODULO) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int n; + n=atoi(variables[params[0]]); + int n2=atoi(params[1]); + + if(n2==0) + { + MessageBox("Division through 0, script cancelled", "Division through 0"); + delete[] params; + break; + } + + n=n%n2; + char c[50]; + itoa(n, c, 10); + variables[params[0]]=c; + } + else if(name==ID_SET_WAYPOINT) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + int n=atoi(params[0]); + CString id=params[0]; + if(n<0) + { + id=""; + } + + if(bSafeMode && n>=0) + { + if(ini.sections["Waypoints"].FindName(id)>=0) + { + goto nextline; + } + } + + + DWORD pos=atoi(params[1])+atoi(params[2])*Map->GetIsoSize(); + + if(pos<Map->GetIsoSize()*Map->GetIsoSize()) + { + //Map->m_noAutoObjectUpdate=TRUE; + Map->AddWaypoint(id, pos); + bUpdateWaypoints=TRUE; + //Map->m_noAutoObjectUpdate=bOldUpdate; + report+="Waypoint " + id + " set.\r\n"; + } + else + { + report+="Waypoint " + id + " moving failed!\r\n"; + } + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + else if(name==ID_REQUIRES_MP) + { + // check bool + if(paramcount>0) + { + if(params[0].GetLength()>0) + { + if(!IsValSet(params[0])) goto nextline; + } + } + + if(Map->IsMultiplayer()==FALSE) + { + MessageBox("This script requires a multiplayer map and cannot be used with singleplayer maps", "Error"); + break; + } + } + else if(name==ID_REQUIRES_SP) + { + // check bool + if(paramcount>0) + { + if(params[0].GetLength()>0) + { + if(!IsValSet(params[0])) goto nextline; + } + } + + if(Map->IsMultiplayer()==TRUE) + { + MessageBox("This script requires a singleplayer map and cannot be used with multiplayer maps", "Error"); + break; + } + } + else if(name==ID_ADD_AI_TRIGGER) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + if(!bAddAllowed) goto nextline; + + CString ID_T=GetFreeID(); + + if(params[0].GetLength()>0) + { + variables[params[0]]=ID_T; + } + + ini.sections["AITriggerTypes"].values[ID_T]=params[1]; + + report+="AI Trigger " + GetParam(params[1],0) + " added\r\n"; + + bUpdate=TRUE; + } + else if(name==ID_ADD_TAG) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + if(!bAddAllowed) goto nextline; + + CString ID_T=GetFreeID(); + + if(params[0].GetLength()>0) + { + variables[params[0]]=ID_T; + } + + CString ID_TAG=ID_T; //GetFreeID(); + ini.sections["Tags"].values[ID_TAG]=params[1]; + + report+="Tag " + GetParam(params[1],1) + " added\r\n"; + + bUpdate=TRUE; + } + else if(name==ID_RESIZE) + { + if(paramcount<4) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>4) + { + if(params[4].GetLength()>0) + { + if(!IsValSet(params[4])) goto nextline; + } + } + + int res=MessageBox("This script wants to resize the map. Resize map?", "Resize map?", MB_YESNO); + if(res==IDNO) goto nextline; + + + if(atoi(params[2])>200 || atoi(params[3])>200) + { + MessageBox("Resizing map failed. Script cancelled.", "Error"); + break; + } + + Map->ResizeMap(atoi(params[0]), atoi(params[1]), atoi(params[2]), atoi(params[3])); + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + bNoRepos=FALSE; + } + else if(name==ID_IS) + { + if(paramcount<4) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>4) + { + if(params[4].GetLength()>0) + { + if(!IsValSet(params[4])) goto nextline; + } + } + + BOOL bIs=FALSE; + + if(params[1]=="<") + { + if(atoi(params[0])<atoi(params[2])) bIs=TRUE; + } + if(params[1]=="<=") + { + if(atoi(params[0])<=atoi(params[2])) bIs=TRUE; + } + if(params[1]=="=") + { + if(atoi(params[0])==atoi(params[2])) + { + bIs=TRUE; + + } + if(params[0]==params[2]) {bIs=TRUE;} + } + if(params[1]==">=") + { + if(atoi(params[0])>=atoi(params[2])) bIs=TRUE; + } + if(params[1]==">") + { + if(atoi(params[0])>atoi(params[2])) bIs=TRUE; + } + if(params[1]=="!=") + { + if(atoi(params[0])!=atoi(params[2])) bIs=TRUE; + if(params[0]!=params[2]) bIs=TRUE; + } + + + + CString s="0"; + if(bIs) s="1"; + + + + variables[params[3]]=s; + + } + else if(name==ID_CANCEL) + { + // check bool + if(paramcount>0) + { + if(params[0].GetLength()>0) + { + if(!IsValSet(params[0])) goto nextline; + } + } + + break; + } + else if(name==ID_PRINT) + { + + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + report+=params[0]; + report+="\r\n"; + + + } + else if(name==ID_TOLOWER) + { + + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + variables[params[0]].MakeLower(); + + + } + else if(name==ID_TOUPPER) + { + + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + variables[params[0]].MakeUpper(); + + } + else if(name==ID_GET_FREE_WAYPOINT) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + variables[params[0]]=GetFree("Waypoints"); + } + else if(name==ID_UINPUT_GET_INTEGER) + { + + if(paramcount<4) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>4) + { + if(params[4].GetLength()>0) + { + if(!IsValSet(params[4])) goto nextline; + } + } + + BOOL ok=FALSE; + int n=0; + while(!ok) + { + CString s=InputBox(params[1], "Enter Integer"); + ok=TRUE; + + if(s.GetLength()==0) ok=FALSE; + + n=atoi(s); + if(params[2].GetLength()>0) + { + if(n<atoi(params[2])) ok=FALSE; + } + + if(params[3].GetLength()>0) + { + if(n>atoi(params[3])) ok=FALSE; + } + } + + char c[50]; + itoa(n, c, 10); + variables[params[0]]=c; + } + else if(name==ID_UINPUT_GET_STRING) + { + + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + BOOL ok=FALSE; + CString s; + while(!ok) + { + s=InputBox(params[1], "Enter String"); + ok=TRUE; + + if (s.GetLength()==0) ok=FALSE; + } + variables[params[0]]=s; + } + else if(name==ID_UINPUT_GET_HOUSE) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + CComboUInputDlg dlg; + dlg.m_type=COMBOUINPUT_HOUSES; + dlg.m_Caption=params[1]; + + dlg.DoModal(); + + variables[params[0]]=dlg.m_Combo; + } + else if(name==ID_UINPUT_GET_COUNTRY) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + CComboUInputDlg dlg; + dlg.m_type=COMBOUINPUT_COUNTRIES; + dlg.m_Caption=params[1]; + + dlg.DoModal(); + + variables[params[0]]=dlg.m_Combo; + } + else if(name==ID_UINPUT_GET_TRIGGER) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + CComboUInputDlg dlg; + dlg.m_type=COMBOUINPUT_TRIGGERS; + dlg.m_Caption=params[1]; + + dlg.DoModal(); + + variables[params[0]]=dlg.m_Combo; + } + else if(name==ID_UINPUT_GET_TAG) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + CComboUInputDlg dlg; + dlg.m_type=COMBOUINPUT_TAGS; + dlg.m_Caption=params[1]; + + dlg.DoModal(); + + variables[params[0]]=dlg.m_Combo; + } + /*else if(name==ID_UINPUT_GET_MANUAL) + { + if(paramcount<4) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>4) + { + if(params[4].GetLength()>0) + { + if(!IsValSet(params[4])) goto nextline; + } + } + + CComboUInputDlg dlg; + dlg.m_type=COMBOUINPUT_MANUAL; + dlg.m_Caption=params[1]; + dlg.bTruncateStrings=IsValSet(params[2]); + + + + dlg.DoModal(); + + variables[params[0]]=dlg.m_Combo; + }*/ + else if(name==ID_JUMP_TO_LINE) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + + if(!bAllowLoop) + { + int res=MessageBox("This script tries to use loops. Some scripts may require this. However, this holds the risk of infinite loops, which may cause the FinalSun/FinalAlert2 to crash. Do you want to allow looping for this script?", "Allow looping?", MB_YESNO); + if(res==IDYES) + { + bAllowLoop=TRUE; + }else + + goto nextline; // not allowed in safe mode because of possible infinte loops# + } + + if(!bIgnoreLoopCounts) + { + loop_count++; + + if(loop_count>300) + { + int res=MessageBox("This script has exceeded the 300 loops limit. Do you want to remove the loop limit (not recommended, inherits risk of infinite loops if script has bugs)? If you press no, the script will stop after another 300 loops to ask you again. If you press cancel, the script will be cancelled.", "Loop Limit exceeded", MB_YESNOCANCEL | MB_DEFBUTTON2); + if(res==IDYES) bIgnoreLoopCounts=TRUE; + if(res==IDNO) loop_count=0; + if(res==IDCANCEL) + { + delete[] params; + break; + } + + } + } + + + int n=s.FindJumpLine(params[0]); + if(n<0 || n>s.functioncount) + { + + ReportScriptError(i); + delete[] params; + break; + } + + + i=n-1; // not n, as the for loop adds 1 again! + goto nextline_no_update; + } + else if(name==ID_SET_AUTO_UPDATE) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + bAutoUpdate=IsValSet(params[0]); + + goto nextline; + } + else if(name==ID_GET_RANDOM) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + int n=rand(); // 0 and 32767 + + char c[50]; + itoa(n, c, 10); + variables[params[0]]=c; + } + else if(name==ID_ADD_TERRAIN) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + if(!bAddAllowed) goto nextline; + + DWORD pos; + pos=atoi(params[1])+atoi(params[2])*Map->GetIsoSize(); + + if(Map->GetTerrainAt(pos)<0) + { + Map->AddTerrain(params[0], pos); + + report+="Terrain added: " + params[0] + (CString)" at " + params[1] + (CString)"/" + params[2] + "\r\n"; + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + } +#ifdef SMUDGE_SUPP + else if(name==ID_ADD_SMUDGE) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + DWORD pos; + pos=atoi(params[1])+atoi(params[2])*Map->GetIsoSize(); + + FIELDDATA* fd=Map->GetFielddataAt(pos); + if(fd->smudge<0) + { + SMUDGE s; + s.deleted=0; + s.type=params[0]; + s.x=atoi(params[1]); + s.y=atoi(params[2]); + Map->AddSmudge(&s); + + report+="Smudge added: " + params[0] + (CString) " at " + params[1] + (CString)"/" + params[2] + "\r\n"; + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + } +#endif + else if(name==ID_GET_WAYPOINT_POS) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + BOOL bFound=FALSE; + DWORD pos; + int k; + for(k=0;k<Map->GetWaypointCount();k++) + { + CString id; + Map->GetWaypointData(k, &id, &pos); + + if(id==params[0]) + { + bFound=TRUE; + break; + } + } + + if(!bFound) pos=0; + + int x=pos%Map->GetIsoSize(); + int y=pos/Map->GetIsoSize(); + + char c[50]; + itoa(x, c, 10); + variables[params[1]]=c; + itoa(y, c, 10); + variables[params[2]]=c; + } + else if(name==ID_GET_PARAM) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + variables[params[0]]=GetParam(params[1], atoi(params[2])); + } + else if(name==ID_SET_PARAM) + { + if(paramcount<3) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>3) + { + if(params[3].GetLength()>0) + { + if(!IsValSet(params[3])) goto nextline; + } + } + + variables[params[0]]=SetParam(variables[params[0]], atoi(params[1]), params[2]); + } + else if(name==ID_GET_PARAM_COUNT) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int k; + int count=1; // we start at 1 param even if no , exists! + for(k=0;k<params[1].GetLength();k++) + { + if(params[1].GetAt(k)==',') count++; + } + + char c[50]; + itoa(count, c, 10); + + variables[params[0]]=c; + } + else if(name==ID_ALLOW_DELETE) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + + { + CString s; + s="This script wants to delete objects or triggers from your map. For some scripts this may be necessary, but it can seriously damage your map. Reason why script wants to delete objects:\n"; + s+=params[0]; + s+="\n\nDo you want to allow the script to do this?"; + + int res=MessageBox(s, "Allow deletion of objects?", MB_YESNO | MB_DEFBUTTON2); + if(res==IDNO) goto nextline; + } + + bDeleteAllowed=TRUE; + } + else if(name==ID_ALLOW_ADD) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + + { + CString s; + s="This script wants to add objects or triggers to your map. For some scripts this may be necessary, but it can seriously damage your map. Reason why script wants to add objects:\n"; + s+=params[0]; + s+="\n\nDo you want to allow the script to do this?"; + + int res=MessageBox(s, "Allow adding of objects?", MB_YESNO | MB_DEFBUTTON2); + if(res==IDNO) goto nextline; + } + + bAddAllowed=TRUE; + } + else if(name==ID_DELETE_TERRAIN) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + if(!bDeleteAllowed ) goto nextline; + + int index=atoi(params[0]); + if(index<0 || index>=Map->GetTerrainCount()) + { + report+="Terrain deletion failed, invalid index\r\n"; + goto nextline; + } + + lastTerrainDeleted=index; + Map->DeleteTerrain(index); + + report+="Terrain deleted\r\n"; + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + else if(name==ID_DELETE_INFANTRY) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + if(!bDeleteAllowed ) goto nextline; + + int index=atoi(params[0]); + if(index<0 || index>=Map->GetInfantryCount()) + { + report+="Infantry deletion failed, invalid index\r\n"; + goto nextline; + } + + lastInfantryDeleted=index; + Map->DeleteInfantry(index); + + report+="Infantry deleted\r\n"; + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + else if(name==ID_DELETE_STRUCTURE) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + if(!bDeleteAllowed ) goto nextline; + + int index=atoi(params[0]); + if(index<0 || index>=Map->GetStructureCount()) + { + report+="Structure deletion failed, invalid index\r\n"; + goto nextline; + } + + lastStructureDeleted=*ini.sections["Structures"].GetValueName(index); + Map->DeleteStructure(index); + + report+="Structure deleted\r\n"; + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + else if(name==ID_DELETE_VEHICLE) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + if(!bDeleteAllowed ) goto nextline; + + int index=atoi(params[0]); + if(index<0 || index>=Map->GetUnitCount()) + { + report+="Vehicle deletion failed, invalid index\r\n"; + goto nextline; + } + + lastUnitDeleted=*ini.sections["Units"].GetValueName(index); + Map->DeleteUnit(index); + + report+="Vehicle deleted\r\n"; + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + else if(name==ID_DELETE_AIRCRAFT) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + + if(!bDeleteAllowed ) goto nextline; + + int index=atoi(params[0]); + if(index<0 || index>=Map->GetAircraftCount()) + { + report+="Aircraft deletion failed, invalid index\r\n"; + goto nextline; + } + + lastAircraftDeleted=*ini.sections["Aircraft"].GetValueName(index); + Map->DeleteAircraft(index); + + report+="Aircraft deleted\r\n"; + + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + else if(name==ID_IS_INFANTRY_DELETED) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + CString deleted="1"; + int index=atoi(params[1]); + if(index>=0 && index<Map->GetInfantryCount()) + { + INFANTRY id; + Map->GetInfantryData(index, &id); + if(id.deleted==0) deleted="0"; + } + + variables[params[0]]=deleted; + } + else if(name==ID_IS_TERRAIN_DELETED) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + CString deleted="1"; + int index=atoi(params[1]); + if(index>=0 && index<Map->GetTerrainCount()) + { + TERRAIN id; + Map->GetTerrainData(index, &id); + if(id.deleted==0) deleted="0"; + } + + variables[params[0]]=deleted; + } + else if(name==ID_ADD_INFANTRY) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + // check param count + int count=1; // we start at 1 param even if no , exists! + int k; + for(k=0;k<params[0].GetLength();k++) + { + if(params[0].GetAt(k)==',') count++; + } + + if(count!=14) + { + report+="AddInfantry failed\r\n"; + goto nextline; + } + + CString data=params[0]; + + INFANTRY id; + id.deleted=0; + id.house=GetParam(data, 0); + id.type=GetParam(data, 1); + id.strength=GetParam(data, 2); + id.y=GetParam(data, 3); + id.x=GetParam(data, 4); + //id.pos=GetParam(data, 5); + id.pos="-1"; // ignore pos values! + id.action=GetParam(data, 6); + id.direction=GetParam(data, 7); + id.tag=GetParam(data, 8); + id.flag1=GetParam(data, 9); + id.flag2=GetParam(data, 10); + id.flag3=GetParam(data, 11); + id.flag4=GetParam(data, 12); + id.flag5=GetParam(data, 13); + + if(Map->AddInfantry(&id, NULL, NULL, NULL, lastInfantryDeleted)==FALSE) + { + report+="AddInfantry failed\r\n"; + } + else + { + report+="Infantry added\r\n"; + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + } + else if(name==ID_ADD_VEHICLE) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + // check param count + int count=1; // we start at 1 param even if no , exists! + int k; + for(k=0;k<params[0].GetLength();k++) + { + if(params[0].GetAt(k)==',') count++; + } + + if(count!=14) + { + report+="AddVehicle failed\r\n"; + goto nextline; + } + + CString data=params[0]; + + UNIT unit; + unit.house=GetParam(data, 0); + unit.type=GetParam(data, 1); + unit.strength=GetParam(data, 2); + unit.y=GetParam(data, 3); + unit.x=GetParam(data, 4); + unit.direction=GetParam(data, 5); + unit.action=GetParam(data, 6); + unit.tag=GetParam(data, 7); + unit.flag1=GetParam(data, 8); + unit.flag2=GetParam(data, 9); + unit.flag3=GetParam(data, 10); + unit.flag4=GetParam(data, 11); + unit.flag5=GetParam(data, 12); + unit.flag6=GetParam(data, 13); + + if(Map->GetUnitAt(atoi(unit.x)+atoi(unit.y)*Map->GetIsoSize())>=0) + { + report+="AddVehicle failed\r\n"; + goto nextline; + } + + if(Map->AddUnit(&unit, NULL, NULL, NULL, lastUnitDeleted)==FALSE) + { + report+="AddVehicle failed\r\n"; + } + else + { + report+="Vehicle added\r\n"; + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + } + else if(name==ID_ADD_AIRCRAFT) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + // check param count + int count=1; // we start at 1 param even if no , exists! + int k; + for(k=0;k<params[0].GetLength();k++) + { + if(params[0].GetAt(k)==',') count++; + } + + if(count!=12) + { + report+="AddAircraft failed\r\n"; + goto nextline; + } + + CString data=params[0]; + + AIRCRAFT air; + air.house=GetParam(data, 0); + air.type=GetParam(data, 1); + air.strength=GetParam(data, 2); + air.y=GetParam(data, 3); + air.x=GetParam(data, 4); + air.direction=GetParam(data, 5); + air.action=GetParam(data, 6); + air.tag=GetParam(data, 7); + air.flag1=GetParam(data, 8); + air.flag2=GetParam(data, 9); + air.flag3=GetParam(data, 10); + air.flag4=GetParam(data, 11); + + if(Map->GetAirAt(atoi(air.x)+atoi(air.y)*Map->GetIsoSize())>=0) + { + report+="AddAircraft failed\r\n"; + goto nextline; + } + + if(Map->AddAircraft(&air, NULL, NULL, NULL, lastAircraftDeleted)==FALSE) + { + report+="AddAircraft failed\r\n"; + } + else + { + report+="Aircraft added\r\n"; + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + } + else if(name==ID_ADD_STRUCTURE) + { + if(paramcount<1) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>1) + { + if(params[1].GetLength()>0) + { + if(!IsValSet(params[1])) goto nextline; + } + } + + // check param count + int count=1; // we start at 1 param even if no , exists! + int k; + for(k=0;k<params[0].GetLength();k++) + { + if(params[0].GetAt(k)==',') count++; + } + + if(count!=17) + { + report+="AddStructure failed\r\n"; + goto nextline; + } + + CString data=params[0]; + + STRUCTURE structure; + structure.house=GetParam(data, 0); + structure.type=GetParam(data, 1); + structure.strength=GetParam(data, 2); + structure.y=GetParam(data, 3); + structure.x=GetParam(data, 4); + structure.direction=GetParam(data, 5); + structure.tag=GetParam(data, 6); + structure.flag1=GetParam(data, 7); + structure.flag2=GetParam(data, 8); + structure.energy=GetParam(data, 9); + structure.upgradecount=GetParam(data, 10); + structure.spotlight=GetParam(data, 11); + structure.upgrade1=GetParam(data, 12); + structure.upgrade2=GetParam(data, 13); + structure.upgrade3=GetParam(data, 14); + structure.flag3=GetParam(data, 15); + structure.flag4=GetParam(data, 16); + + if(Map->GetStructureAt(atoi(structure.x)+atoi(structure.y)*Map->GetIsoSize())>=0) + { + report+="AddStructure failed\r\n"; + goto nextline; + } + + if(Map->AddStructure(&structure, NULL, NULL, NULL, lastStructureDeleted)==FALSE) + { + report+="AddStructure failed\r\n"; + } + else + { + report+="Structure added\r\n"; + bUpdate=TRUE; + bUpdateOnlyMission=FALSE; + } + } + else if(name==ID_GET_INFANTRY) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int index=atoi(params[1]); + CString s; + if(index>=0 && index<Map->GetInfantryCount()) + { + INFANTRY id; + Map->GetInfantryINIData(index, &s); + } + + variables[params[0]]=s; + } + else if(name==ID_GET_AIRCRAFT) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int index=atoi(params[1]); + CString s; + if(index>=0 && index<Map->GetAircraftCount()) + { + s=*ini.sections["Aircraft"].GetValue(index); + } + + variables[params[0]]=s; + } + else if(name==ID_GET_STRUCTURE) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int index=atoi(params[1]); + CString s; + if(index>=0 && index<Map->GetStructureCount()) + { + s=*ini.sections["Structures"].GetValue(index); + } + + variables[params[0]]=s; + } + else if(name==ID_GET_VEHICLE) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int index=atoi(params[1]); + CString s; + if(index>=0 && index<Map->GetUnitCount()) + { + s=*ini.sections["Units"].GetValue(index); + } + + variables[params[0]]=s; + } + else if(name==ID_GET_HOUSE) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int index=atoi(params[1]); + + CString s; + if(index>=0 && index<Map->GetHousesCount(FALSE)) + { + s=Map->GetHouseID(index, FALSE); + } + + variables[params[0]]=s; + } + else if(name==ID_GET_COUNTRY) + { + if(paramcount<2) + { + ReportScriptError(i); + delete[] params; + break; + } + + // check bool + if(paramcount>2) + { + if(params[2].GetLength()>0) + { + if(!IsValSet(params[2])) goto nextline; + } + } + + int index=atoi(params[1]); + + CString s; + if(index>=0 && index<Map->GetHousesCount(TRUE)) + { + s=Map->GetHouseID(index, TRUE); + } + + variables[params[0]]=s; + } + + else + { + ReportScriptError(i); + delete[] params; + break; + } + +nextline: + if(bAutoUpdate) + { + m_Report=report; + UpdateData(FALSE); + } + +nextline_no_update: + + delete[] params; + + } + + for(i=0;i<functions.size();i++) + { + delete[] functions[i].params; + functions[i].params=NULL; + } + + m_Report=report; + UpdateData(FALSE); + + //if(bUpdateWaypoints) Map->UpdateIniFile(MAPDATA_UPDATE_FROM_INI); + + if(bUpdate) ((CFinalSunDlg*)theApp.GetMainWnd())->UpdateDialogs(bUpdateOnlyMission, bNoRepos); + + // CDialog::OnOK(); +} + +BOOL CUserScriptsDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + int k; + CFileFind ff; + + + CString scripts=(CString)AppPath+"\\Scripts\\*.fscript"; + { + + CFileFind ff; + if(ff.FindFile(scripts)) + { + CListBox* lb=(CListBox*)GetDlgItem(IDC_SCRIPTS); + + BOOL bWorking=TRUE; + + while(bWorking) + { + bWorking=ff.FindNextFile(); + lb->AddString(ff.GetFileName()); + } + } + } + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} + +void CUserScriptsDlg::ReportScriptError(int line) +{ + char c[50]; + itoa(line, c, 10); + + MessageBox("Script error in line " + (CString)c + ". Probably wrong parameter count or unknown function call.","Error"); +} diff --git a/MissionEditor/UserScriptsDlg.h b/MissionEditor/UserScriptsDlg.h new file mode 100644 index 0000000..f04f550 --- /dev/null +++ b/MissionEditor/UserScriptsDlg.h @@ -0,0 +1,69 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_USERSCRIPTSDLG_H__6A37EE40_9653_11D5_89B3_00E07D97C331__INCLUDED_) +#define AFX_USERSCRIPTSDLG_H__6A37EE40_9653_11D5_89B3_00E07D97C331__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// UserScriptsDlg.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CUserScriptsDlg + +class CUserScriptsDlg : public CDialog +{ +// Konstruktion +public: + void ReportScriptError(int line); + CUserScriptsDlg(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CUserScriptsDlg) + enum { IDD = IDD_USERSCRIPTS }; + CString m_Script; + CString m_Report; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CUserScriptsDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CUserScriptsDlg) + virtual void OnOK(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_USERSCRIPTSDLG_H__6A37EE40_9653_11D5_89B3_00E07D97C331__INCLUDED_ diff --git a/MissionEditor/Vec2.h b/MissionEditor/Vec2.h new file mode 100644 index 0000000..2876ff8 --- /dev/null +++ b/MissionEditor/Vec2.h @@ -0,0 +1,243 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cstdint> + +struct CSMap {}; +struct CSProjected {}; + +template<class CS, class T> +struct Vec2 +{ +public: + Vec2() = default; + Vec2(T x_, T y_) : x(x_), y(y_) {} + bool operator==(const Vec2& other) const = default; + + inline Vec2& operator +=(const Vec2& other) { + x += other.x; + y += other.y; + return *this; + } + + inline Vec2& operator -=(const Vec2& other) { + x -= other.x; + y -= other.y; + return *this; + } + + inline Vec2& operator *=(const T v) + { + x *= v; + y *= v; + return *this; + } + + inline Vec2& operator *=(const Vec2& other) + { + x *= other.x; + y *= other.y; + return *this; + } + + inline Vec2& operator /=(const Vec2& other) + { + x /= other.x; + y /= other.y; + return *this; + } + + inline Vec2& operator /=(const T v) + { + x /= v; + y /= v; + return *this; + } + + void set(const T x_, const T y_) + { + x = x_; + y = y_; + } + + template<class T1> + inline Vec2<CS, T1> convertT() const + { + return Vec2<CS, T1>(static_cast<T1>(x), static_cast<T1>(y)); + } + + inline Vec2<CS, float> inverted() const + { + return Vec2<CS, float>(1.0f / static_cast<float>(x), 1.0f / static_cast<float>(y)); + } + + inline Vec2 negated() const + { + return Vec2(-x, -y); + } + +public: + T x = 0; + T y = 0; +}; + +template<class CS, class T> +inline Vec2<CS, T> operator+(const Vec2<CS, T>& l, const Vec2<CS, T>& r) +{ + auto res = l; + res += r; + return res; +} + +template<class CS, class T> +inline Vec2<CS, T> operator-(const Vec2<CS, T>& l, const Vec2<CS, T>& r) +{ + auto res = l; + res -= r; + return res; +} + +template<class CS, class T> +inline Vec2<CS, T> operator*(const Vec2<CS, T>& l, const Vec2<CS, T>& r) +{ + auto res = l; + res *= r; + return res; +} + +template<class CS> +inline Vec2<CS, float> operator*(const Vec2<CS, std::int32_t>& l, const Vec2<CS, float>& r) +{ + return Vec2<CS, float>(l.x * r.x, l.y * r.y); +} + +template<class CS, class T> +inline Vec2<CS, T> operator*(const Vec2<CS, T>& l, const T r) +{ + auto res = l; + res *= r; + return res; +} + +template<class CS, class T> +inline Vec2<CS, T> operator/(const Vec2<CS, T>& l, const Vec2<CS, T>& r) +{ + auto res = l; + res /= r; + return res; +} + +template<class CS> +inline Vec2<CS, float> operator/(const Vec2<CS, std::int32_t>& l, const Vec2<CS, float>& r) +{ + return Vec2<CS, float>(l.x / r.x, l.y / r.y); +} + +template<class CS, class T> +inline Vec2<CS, T> operator/(const Vec2<CS, T>& l, const T r) +{ + auto res = l; + res /= r; + return res; +} + +template<class CS, class T> +struct Coords2 +{ + Coords2() = default; + Coords2(T x_, T y_) : x(x_), y(y_) {} + bool operator==(const Coords2& other) const = default; + T x = 0; + T y = 0; + Coords2& operator +=(const Vec2<CS, T>& other) { + x += other.x; + y += other.y; + return *this; + } + Coords2& operator -=(const Vec2<CS, T>& other) { + x -= other.x; + y -= other.y; + return *this; + } + void set(const T x_, const T y_) + { + x = x_; + y = y_; + } + template<class T1> + inline Coords2<CS, T1> convertT() const + { + return Coords2<CS, T1>(static_cast<T1>(x), static_cast<T1>(y)); + } +}; + + +template<class CS, class T> +inline Coords2<CS, T> operator+(const Coords2<CS, T>& l, const Vec2<CS, T>& r) +{ + auto res = l; + res += r; + return res; +} + +template<class CS, class T> +inline Coords2<CS, T> operator-(const Coords2<CS, T>& l, const Vec2<CS, T>& r) +{ + auto res = l; + res -= r; + return res; +} + +template<class CS, class T> +inline Vec2<CS, T> operator-(const Coords2<CS, T>& l, const Coords2<CS, T >& r) +{ + return Vec2<CS, T>(l.x - r.x, l.y - r.y); +} + +template<class CS, class T> +inline Coords2<CS, T> operator*(const Coords2<CS, T>& l, const Vec2<CS, T>& r) +{ + return Coords2<CS, float>(l.x * r.x, l.y * r.y); +} + +template<class CS> +inline Coords2<CS, float> operator*(const Coords2<CS, std::int32_t>& l, const Vec2<CS, float>& r) +{ + return Coords2<CS, float>(l.x * r.x, l.y * r.y); +} + +template<class CS> +inline Coords2<CS, float> operator/(const Coords2<CS, std::int32_t>& l, const Vec2<CS, float>& r) +{ + return Coords2<CS, float>(l.x / r.x, l.y / r.y); +} + + +typedef Vec2<CSMap, std::int16_t> MapVec; + +/// <summary> +/// Logical map coordinates in tiles +/// </summary> +typedef Coords2<CSMap, std::int16_t> MapCoords; + +typedef Vec2<CSProjected, std::int32_t> ProjectedVec; +typedef Coords2<CSProjected, std::int32_t> ProjectedCoords; \ No newline at end of file diff --git a/MissionEditor/ViewObjects.cpp b/MissionEditor/ViewObjects.cpp new file mode 100644 index 0000000..28a0782 --- /dev/null +++ b/MissionEditor/ViewObjects.cpp @@ -0,0 +1,1407 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// ViewObjects.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "ViewObjects.h" +#include "FinalSunDlg.h" +#include "structs.h" +#include "mapdata.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" +#include "rtpdlg.h" +#include "TubeTool.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CViewObjects + +const int valadded=10000; + +IMPLEMENT_DYNCREATE(CViewObjects, CTreeView) + +CViewObjects::CViewObjects() +{ + m_ready=FALSE; + +} + +CViewObjects::~CViewObjects() +{ +} + + +BEGIN_MESSAGE_MAP(CViewObjects, CTreeView) + //{{AFX_MSG_MAP(CViewObjects) + ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged) + ON_WM_CREATE() + ON_NOTIFY_REFLECT(TVN_KEYDOWN, OnKeydown) + ON_WM_KEYDOWN() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +extern int overlay_number[]; +extern CString overlay_name[]; +extern BOOL overlay_visible[]; +extern BOOL overlay_trail[]; + + +extern int overlay_count; + + +extern ACTIONDATA AD; + +///////////////////////////////////////////////////////////////////////////// +// Zeichnung CViewObjects + +void CViewObjects::OnDraw(CDC* pDC) +{ + CDocument* pDoc = GetDocument(); + // ZU ERLEDIGEN: Code zum Zeichnen hier einfĂ¼gen +} + +///////////////////////////////////////////////////////////////////////////// +// Diagnose CViewObjects + +#ifdef _DEBUG +void CViewObjects::AssertValid() const +{ + CTreeView::AssertValid(); +} + +void CViewObjects::Dump(CDumpContext& dc) const +{ + CTreeView::Dump(dc); +} +#endif //_DEBUG + +CString GetTheaterLanguageString(LPCSTR lpString) +{ + CString s=lpString; + CString t=lpString; + + if((tiledata)==&t_tiledata) t+="TEM"; + if((tiledata)==&s_tiledata) t+="SNO"; + if((tiledata)==&u_tiledata) t+="URB"; + if((tiledata)==&un_tiledata) t+="UBN"; + if((tiledata)==&l_tiledata) t+="LUN"; + if((tiledata)==&d_tiledata) t+="DES"; + + CString res=GetLanguageStringACP(t); + if(res.GetLength()==0) res=GetLanguageStringACP(s); + + return res; +} + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CViewObjects + + +void CViewObjects::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) +{ + CIniFile& ini=Map->GetIniFile(); + + NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; + + int val=pNMTreeView->itemNew.lParam; + if(val<0){ // return; + if(val==-2) { + AD.reset(); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + return; + } + + if(val<valadded) + { + // standard selection (maybe erasing etc) + switch(val) + { + case 10: // erase field + { + AD.mode=ACTIONMODE_ERASEFIELD; + break; + } + case 20: // waypoint stuff now + { + AD.mode=ACTIONMODE_WAYPOINT; + AD.type=0; + break; + } + case 21: + { + AD.mode=3; + AD.type=1; + break; + } + case 22: + { + AD.mode=3; + AD.type=2; + break; + } + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + { + AD.mode=3; + AD.type=3+val-23; + break; + } + case 36: // celltag stuff + { + AD.mode=4; + AD.type=0; + break; + } + case 37: + { + AD.mode=4; + AD.type=1; + break; + } + case 38: + { + AD.mode=4; + AD.type=2; + break; + } + case 40: // node stuff + { + AD.mode=5; + AD.type=0; + break; + } + case 41: + { + AD.mode=5; + AD.type=1; + break; + } + case 42: + { + AD.mode=5; + AD.type=2; + break; + } + case 50: + { + AD.mode=ACTIONMODE_MAPTOOL; + AD.tool.reset(new AddTubeTool(*Map, *((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview, true)); + break; + } + case 51: + { + AD.mode = ACTIONMODE_MAPTOOL; + AD.tool.reset(new ModifyTubeTool(*Map, *((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview, true)); + break; + } + case 52: + { + AD.mode = ACTIONMODE_MAPTOOL; + AD.tool.reset(new AddTubeTool(*Map, *((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview, false)); + break; + } + case 53: + { + AD.mode = ACTIONMODE_MAPTOOL; + AD.tool.reset(new ModifyTubeTool(*Map, *((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview, false)); + break; + } + case 54: + { + AD.mode=ACTIONMODE_MAPTOOL; + AD.tool.reset(new RemoveTubeTool(*Map, *((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview)); + break; + } + + case 61: + if(!tiledata_count) break; + AD.type=0; + AD.mode=ACTIONMODE_SETTILE; + AD.data=0; + AD.z_data=0; + HandleBrushSize(0); + break; + + case 62: + int i; + if(!tiledata_count) break; + for(i=0;i<(*tiledata_count);i++) + if((*tiledata)[i].wTileSet==atoi((*tiles).sections["General"].values["SandTile"])) break; + AD.type=i; + AD.mode=ACTIONMODE_SETTILE; + AD.data=0; + AD.z_data=0; + HandleBrushSize(i); + break; + case 63: + if(!tiledata_count) break; + for(i=0;i<(*tiledata_count);i++) + if((*tiledata)[i].wTileSet==atoi((*tiles).sections["General"].values["RoughTile"])) break; + AD.type=i; + AD.mode=ACTIONMODE_SETTILE; + AD.data=0; + AD.z_data=0; + HandleBrushSize(i); + break; + case 64: + if(!tiledata_count) break; + for(i=0;i<(*tiledata_count);i++) + if((*tiledata)[i].wTileSet==waterset) break; + + if(((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_x<2 || + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_y<2) + { + + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.m_BrushSize=1; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.UpdateData(FALSE); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_x=2; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_y=2; + } + + AD.type=i; + AD.mode=ACTIONMODE_SETTILE; + AD.data=1; // use water placement logic + AD.z_data=0; + break; + case 65: + if(!tiledata_count) break; + for(i=0;i<(*tiledata_count);i++) + if((*tiledata)[i].wTileSet==atoi((*tiles).sections["General"].values["GreenTile"])) break; + AD.type=i; + AD.mode=ACTIONMODE_SETTILE; + AD.data=0; + AD.z_data=0; + HandleBrushSize(i); + break; + case 66: + if(!tiledata_count) break; + for(i=0;i<(*tiledata_count);i++) + if((*tiledata)[i].wTileSet==atoi((*tiles).sections["General"].values["PaveTile"])) break; + AD.type=i; + AD.mode=ACTIONMODE_SETTILE; + AD.data=0; + AD.z_data=0; + HandleBrushSize(i); + break; + case 67: + if(!tiledata_count) break; + for(i=0;i<(*tiledata_count);i++) + if((*tiledata)[i].wTileSet==atoi(g_data.sections["NewUrbanInfo"].values["Morphable2"])) break; + AD.type=i; + AD.mode=ACTIONMODE_SETTILE; + AD.data=0; + AD.z_data=0; + HandleBrushSize(i); + break; + + + } + } + else + { + int subpos=val%valadded; + int pos=val/valadded; + + AD.mode=1; + AD.type=pos; + AD.data=subpos; + + if(pos==1) + { + CString sec="InfantryTypes"; + + if(subpos<rules.sections[sec].values.size()) + { + // standard unit! + + AD.data_s=*rules.sections[sec].GetValue(subpos); + } + else{ + + AD.data_s=*ini.sections[sec].GetValue(subpos-rules.sections[sec].values.size()); + } + } + else if(pos==2) + { + CString sec="BuildingTypes"; + + if(subpos<rules.sections[sec].values.size()) + { + // standard unit! + + AD.data_s=*rules.sections[sec].GetValue(subpos); + } + else{ + + AD.data_s=*ini.sections[sec].GetValue(subpos-rules.sections[sec].values.size()); + } + } + else if(pos==3) + { + CString sec="AircraftTypes"; + + if(subpos<rules.sections[sec].values.size()) + { + // standard unit! + + AD.data_s=*rules.sections[sec].GetValue(subpos); + } + else{ + + AD.data_s=*ini.sections[sec].GetValue(subpos-rules.sections[sec].values.size()); + } + } + else if(pos==4) + { + CString sec="VehicleTypes"; + + if(subpos<rules.sections[sec].values.size()) + { + // standard unit! + + AD.data_s=*rules.sections[sec].GetValue(subpos); + } + else{ + + AD.data_s=*ini.sections[sec].GetValue(subpos-rules.sections[sec].values.size()); + } + } + else if(pos==5) + { + + CString sec="TerrainTypes"; + + if(subpos==999) + { + + CRTPDlg dlg; + if(dlg.DoModal()==IDOK) + { + AD.mode=ACTIONMODE_RANDOMTERRAIN; + } + } + else + { + if(subpos<rules.sections[sec].values.size()) + { + // standard unit! + + AD.data_s=*rules.sections[sec].GetValue(subpos); + } + else{ + + AD.data_s=*ini.sections[sec].GetValue(subpos-rules.sections[sec].values.size()); + } + } + } + else if(pos==6) + { + if(subpos<100) + { + // general overlay functions! + if(subpos==1) + { + AD.data=31; + AD.data2=atoi(InputBox("Please enter the value (0-255) of the overlay. Don´t exceed this range.","Set overlay manually")); + + } + else if(subpos==2) + { + AD.data=32; + AD.data2=atoi(InputBox("Please enter the value (0-255) of the overlay-data. Don´t exceed this range.","Set overlay manually")); + + } + + } + else + { + AD.data2=subpos%100; + AD.data=subpos/100; + if(AD.data>=30) {AD.data=30;AD.data2=subpos%1000;} + } + } + else if(pos==7) + { + // set owner + //if(ini.sections.find(MAPHOUSES)!=ini.sections.end() && ini.sections[MAPHOUSES].values.size()>0) + if(ini.sections.find(MAPHOUSES)!=ini.sections.end() && ini.sections[MAPHOUSES].values.size()>0) + { + AD.data_s=*ini.sections[MAPHOUSES].GetValue(subpos); + } + else + { + AD.data_s=*rules.sections[HOUSES].GetValue(subpos); + } + + currentOwner=AD.data_s; + } +#ifdef SMUDGE_SUPP + else if(pos==8) + { + + + CString sec="SmudgeTypes"; + + if(subpos<rules.sections[sec].values.size()) + { + // standard unit! + + AD.data_s=*rules.sections[sec].GetValue(subpos); + } + else + { + AD.data_s=*ini.sections[sec].GetValue(subpos-rules.sections[sec].values.size()); + } + + } +#endif + + + } + + + + *pResult = 0; +} + +__inline HTREEITEM TV_InsertItemW(HWND hWnd, WCHAR* lpString, int len, HTREEITEM hInsertAfter, HTREEITEM hParent, int param) +{ + if(!lpString) return NULL; + + TVINSERTSTRUCTW tvis; + tvis.hInsertAfter=hInsertAfter; + tvis.hParent=hParent; + tvis.itemex.mask=TVIF_PARAM | TVIF_TEXT; + tvis.itemex.cchTextMax=len; + tvis.itemex.pszText=lpString; + tvis.itemex.lParam=param; + + // MW 07/17/2001: Updated to use Ascii if Unicode fails: + HTREEITEM res=(HTREEITEM)::SendMessage(hWnd, TVM_INSERTITEMW, 0,((LPARAM)(&tvis))); + + if(!res) + { + // failed... Probably because of missing Unicode support + + // convert text to ascii, then add it + BYTE* lpAscii=new(BYTE[len+1]); + BOOL bUsedDefault; + memset(lpAscii, 0, len+1); + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + lpString, len+1, (LPSTR)lpAscii, len+1,NULL,&bUsedDefault); + + TVINSERTSTRUCT tvis; + tvis.hInsertAfter=hInsertAfter; + tvis.hParent=hParent; + tvis.itemex.mask=TVIF_PARAM | TVIF_TEXT; + tvis.itemex.cchTextMax=len; + tvis.itemex.lParam=param; + tvis.itemex.pszText=(char*)lpAscii; + + res=TreeView_InsertItem(hWnd, &tvis); + + delete[] lpAscii; + } + + return res; +} + +void CViewObjects::UpdateDialog() +{ + OutputDebugString("Objectbrowser redrawn\n"); + + CTreeCtrl& tree=GetTreeCtrl(); + CIniFile& ini=Map->GetIniFile(); + + tree.Select(0,TVGN_CARET ); + tree.DeleteAllItems(); + + CString sTreeRoots[15]; + sTreeRoots[0]=GetLanguageStringACP("InfantryObList"); + sTreeRoots[1]=GetLanguageStringACP("VehiclesObList"); + sTreeRoots[2]=GetLanguageStringACP("AircraftObList"); + sTreeRoots[3]=GetLanguageStringACP("StructuresObList"); + sTreeRoots[4]=GetLanguageStringACP("TerrainObList"); + sTreeRoots[5]=GetLanguageStringACP("OverlayObList"); + sTreeRoots[6]=GetLanguageStringACP("WaypointsObList"); + sTreeRoots[7]=GetLanguageStringACP("CelltagsObList"); + sTreeRoots[8]=GetLanguageStringACP("BaseNodesObList"); + sTreeRoots[9]=GetLanguageStringACP("TunnelObList"); + sTreeRoots[10]=GetLanguageStringACP("DelObjObList"); + sTreeRoots[11]=GetLanguageStringACP("ChangeOwnerObList"); + sTreeRoots[12]=GetLanguageStringACP("StartpointsObList"); + sTreeRoots[13]=GetLanguageStringACP("GroundObList"); + sTreeRoots[14]=GetLanguageStringACP("SmudgesObList"); + + int i=0; + + //TV_InsertItemW(tree.m_hWnd, L"HELLO", 5, TVI_LAST, TVI_ROOT, -2); + + HTREEITEM first=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + TranslateStringACP(GetLanguageStringACP("NothingObList")), i, i, 0, 0, -2, TVI_ROOT, TVI_LAST); + + HTREEITEM rootitems[15]; + + // we want the change owner at the top + + if(!Map->IsMultiplayer() || !theApp.m_Options.bEasy) + rootitems[11]=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + TranslateStringACP(sTreeRoots[11]), i, i, 0, 0, i, TVI_ROOT, TVI_LAST); + + + for(i=0;i<10;i++) + { + BOOL bAllow=TRUE; + if(theApp.m_Options.bEasy) + { + if(i>=6 && i<=9) + bAllow=FALSE; + } + + // no tunnels in ra2 mode + if(editor_mode==ra2_mode && i==9 && !isTrue(g_data.sections["Debug"].values["AllowTunnels"])) bAllow=FALSE; + + if(bAllow) + rootitems[i]=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + sTreeRoots[i], i, i, 0, 0, i, TVI_ROOT, TVI_LAST); + } + + + rootitems[13]=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, TranslateStringACP(sTreeRoots[13]), 13, 13, 0, 0, 13, TVI_ROOT, first); + + rootitems[12]=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + TranslateStringACP(sTreeRoots[12]), 12,12, 0, 0, 12, TVI_ROOT, TVI_LAST); + + rootitems[10]=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + TranslateStringACP(sTreeRoots[10]), 10, 10, 0, 0, 10, TVI_ROOT, TVI_LAST); + +#ifdef SMUDGE_SUPP + rootitems[14]=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + TranslateStringACP(sTreeRoots[14]), 14, 14, 0, 0, 10, TVI_ROOT, rootitems[4]); +#endif + + + HTREEITEM structhouses[64]; +#ifdef RA2_MODE + HTREEITEM hAllied=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("Allied"), 0, 0,0,0,-1,rootitems[3], TVI_LAST); + HTREEITEM hSoviet=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("Soviet"), 0, 0,0,0,-1,rootitems[3], TVI_LAST); + HTREEITEM hYuri=NULL; + if(yuri_mode) + { + hYuri=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("Yuri"), 0, 0, 0, 0, -1, rootitems[3], TVI_LAST); + } + + for(i=0;i<sides.size();i++) + { + if(sides[i].orig_n==0) + structhouses[i]=hAllied; + else if(yuri_mode && sides[i].orig_n==2) + structhouses[i]=hYuri; + else + structhouses[i]=hSoviet; + + } + + structhouses[sides.size()]=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("Other"), 0, 0,0,0,-1,rootitems[3], TVI_LAST); +#else + for(i=0;i<sides.size();i++) + { + structhouses[i]=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, sides[i].name, 0,0,0,0, -1, rootitems[3], TVI_LAST ); + } + structhouses[sides.size()]=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, "Other", 0,0,0,0, -1, rootitems[3], TVI_LAST ); +#endif + + + if(!theApp.m_Options.bEasy) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateWaypObList"), 0,0,0,0, 20, rootitems[6], TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateSpecWaypObList"), 0,0,0,0, 22, rootitems[6], TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelWaypObList"), 0,0,0,0, 21, rootitems[6], TVI_LAST ); + } + + + int e; + int max=8; + //if(ini.sections.find(HOUSES)!=ini.sections.end() && ini.sections.find(MAPHOUSES)!=ini.sections.end()) + if(!Map->IsMultiplayer()) + max=1; + else + { + + } + for(e=0;e<max;e++) + { + CString ins=GetLanguageStringACP("StartpointsPlayerObList"); + char c[50]; + itoa(e+1,c,10); + ins=TranslateStringVariables(1, ins, c); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, ins, 0,0,0,0, 23+e, rootitems[12], TVI_LAST ); + } + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("StartpointsDelete"), 0,0,0,0, 21, rootitems[12], TVI_LAST ); + + + + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundClearObList"),0,0,0,0,61,rootitems[13], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundSandObList"),0,0,0,0,62,rootitems[13], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundRoughObList"),0,0,0,0,63,rootitems[13], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundGreenObList"),0,0,0,0,65,rootitems[13], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundPaveObList"),0,0,0,0,66,rootitems[13], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundWaterObList"),0,0,0,0,64,rootitems[13], TVI_LAST); +#ifdef RA2_MODE + if(Map->GetTheater()==THEATER3) + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundPave2ObList"),0,0,0,0,67,rootitems[13], TVI_LAST); +#endif + + if(!theApp.m_Options.bEasy) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateCelltagObList"), 0,0,0,0, 36, rootitems[7], TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelCelltagObList"), 0,0,0,0, 37, rootitems[7], TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CelltagPropObList"), 0,0,0,0, 38, rootitems[7], TVI_LAST ); + } + + if(!theApp.m_Options.bEasy) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateNodeNoDelObList"), 0,0,0,0, 40, rootitems[8], TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateNodeDelObList"), 0,0,0,0, 41, rootitems[8], TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelNodeObList"), 0,0,0,0, 42, rootitems[8], TVI_LAST ); + } + + + HTREEITEM deleteoverlay=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelOvrlObList"), 0,0,0,0, -1, rootitems[5], TVI_LAST ); + HTREEITEM tiberium=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("GrTibObList"), 0,0,0,0, -1, rootitems[5], TVI_LAST ); + //HTREEITEM bluetiberium=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("BlTibObList"), 0,0,0,0, -1, rootitems[5], TVI_LAST ); +#ifndef RA2_MODE + HTREEITEM veinhole=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("VeinholeObList"), 0,0,0,0, -1, rootitems[5], TVI_LAST ); +#endif + HTREEITEM bridges=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("BridgesObList"), 0,0,0,0, -1, rootitems[5], TVI_LAST ); + HTREEITEM alloverlay=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("OthObList"), 0,0,0,0, -1, rootitems[5], TVI_LAST ); + HTREEITEM everyoverlay=NULL; + + if(!theApp.m_Options.bEasy) + { + everyoverlay=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("AllObList"), 0,0,0,0, -1, rootitems[5], TVI_LAST ); + } + + + if(!theApp.m_Options.bEasy) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("OvrlManuallyObList"), 0,0,0,0, valadded*6+1, rootitems[5], TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("OvrlDataManuallyObList"), 0,0,0,0, valadded*6+2, rootitems[5], TVI_LAST ); + } + + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelOvrl0ObList"), 0,0,0,0, valadded*6+100+0, deleteoverlay, TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelOvrl1ObList"), 0,0,0,0, valadded*6+100+1, deleteoverlay, TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelOvrl2ObList"), 0,0,0,0, valadded*6+100+2, deleteoverlay, TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelOvrl3ObList"), 0,0,0,0, valadded*6+100+3, deleteoverlay, TVI_LAST ); + + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DrawRanTibObList"), 0,0,0,0, valadded*6+200+0, tiberium, TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DrawTibObList"), 0,0,0,0, valadded*6+200+10, tiberium, TVI_LAST ); + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("IncTibSizeObList"), 0,0,0,0, valadded*6+200+20, tiberium, TVI_LAST ); + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DecTibSizeObList"), 0,0,0,0, valadded*6+200+21, tiberium, TVI_LAST ); + + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DrawRanTibObList"), 0,0,0,0, valadded*6+300+0, bluetiberium, TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DrawTib2ObList"), 0,0,0,0, valadded*6+300+10, tiberium, TVI_LAST ); + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("IncTibSizeObList"), 0,0,0,0, valadded*6+300+20, bluetiberium, TVI_LAST ); + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DecTibSizeObList"), 0,0,0,0, valadded*6+300+21, bluetiberium, TVI_LAST ); +#ifndef RA2_MODE + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("VeinholeObList"), 0,0,0,0, valadded*6+400+0, veinhole, TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("VeinsObList"), 0,0,0,0, valadded*6+400+1, veinhole, TVI_LAST ); +#endif + + if(Map->GetTheater()!=THEATER4 && Map->GetTheater()!=THEATER5) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("SmallBridgeObList"), 0,0,0,0, valadded*6+500+1, bridges, TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("BigBridgeObList"), 0,0,0,0, valadded*6+500+0, bridges, TVI_LAST ); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("BigTrackBridgeObList"), 0,0,0,0, valadded*6+500+2, bridges, TVI_LAST ); +#ifdef RA2_MODE + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("SmallConcreteBridgeObList"), 0,0,0,0, valadded*6+500+3, bridges, TVI_LAST ); +#endif + } + else + { + if(Map->GetTheater()==THEATER5) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("SmallBridgeObList"), 0,0,0,0, valadded*6+500+1, bridges, TVI_LAST ); +#ifdef RA2_MODE + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("SmallConcreteBridgeObList"), 0,0,0,0, valadded*6+500+3, bridges, TVI_LAST ); +#endif + } + + } + +#ifndef RA2_MODE + if (!theApp.m_Options.bEasy && isTrue(g_data.sections["Debug"].values["AllowTunnels"])) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelObList"), 0, 0, 0, 0, 50, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelObList"), 0, 0, 0, 0, 51, rootitems[9], TVI_LAST); + if (isTrue(g_data.sections["Debug"].values["AllowUnidirectionalTunnels"])) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelSingleObList"), 0, 0, 0, 0, 52, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelSingleObList"), 0, 0, 0, 0, 53, rootitems[9], TVI_LAST); + } + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelTunnelObList"), 0, 0, 0, 0, 54, rootitems[9], TVI_LAST); + } +#else + if (!theApp.m_Options.bEasy && isTrue(g_data.sections["Debug"].values["AllowTunnels"])) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelObList"), 0, 0, 0, 0, 50, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelObList"), 0, 0, 0, 0, 51, rootitems[9], TVI_LAST); + if (isTrue(g_data.sections["Debug"].values["AllowUnidirectionalTunnels"])) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelSingleObList"), 0, 0, 0, 0, 52, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelSingleObList"), 0, 0, 0, 0, 53, rootitems[9], TVI_LAST); + } + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelTunnelObList"), 0,0,0,0, 54, rootitems[9], TVI_LAST ); + } +#endif + + + int lv=1; + + if(!theApp.m_Options.bEasy || !Map->IsMultiplayer()) + { + if(ini.sections.find(MAPHOUSES)!=ini.sections.end() && ini.sections[MAPHOUSES].values.size()>0) + { + for(i=0;i<ini.sections[MAPHOUSES].values.size();i++) + { +#ifdef RA2_MODE + CString j=*ini.sections[MAPHOUSES].GetValue(i); + j.MakeLower(); + if(j=="nod" || j=="gdi") continue; +#endif + + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, TranslateHouse(*ini.sections[MAPHOUSES].GetValue(i), TRUE), 0,0,0,0, valadded*7+i, rootitems[11], TVI_LAST ); + } + + } + else + { + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + if(rules.sections[HOUSES].GetValueOrigPos(i)<0) continue; + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, CCStrings[*rules.sections[HOUSES].GetValue(i)].cString, + //0,0,0,0, valadded*7+i, rootitems[11], TVI_LAST ); +#ifdef RA2_MODE + CString j=*rules.sections[HOUSES].GetValue(i); + j.MakeLower(); + if(j=="nod" || j=="gdi") continue; +#endif + TV_InsertItemW(tree.m_hWnd, CCStrings[*rules.sections[HOUSES].GetValue(i)].wString, CCStrings[*rules.sections[HOUSES].GetValue(i)].len, TVI_LAST, rootitems[11],valadded*7+i); + } + } + } + else + { + // change owner to neutral + if(ini.sections.find(MAPHOUSES)!=ini.sections.end() && ini.sections[MAPHOUSES].values.size()>0) + { + if(ini.sections[MAPHOUSES].FindValue("Neutral")>=0) + currentOwner="Neutral"; + else + currentOwner=*ini.sections[MAPHOUSES].GetValue(0); + } + else + currentOwner="Neutral"; + + } + + + for(i=0;i<overlay_count;i++) + { + if(overlay_visible[i] && (!yr_only[i] || yuri_mode)) + { + if(!overlay_trdebug[i] || isTrue(g_data.sections["Debug"].values["EnableTrackLogic"])) + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, TranslateStringACP(overlay_name[i]), 0,0,0,0, valadded*6+3000+overlay_number[i], alloverlay, TVI_LAST ); + } + } + + e=0; + if(!theApp.m_Options.bEasy) + { + for(i=0;i<rules.sections["OverlayTypes"].values.size();i++) + { + // it seems there is somewhere a bug that lists empty overlay ids... though they are not in the rules.ini + // so this here is the workaround: + CString id=*rules.sections["OverlayTypes"].GetValue(i); + //if(strchr(id,' ')!=NULL){ id[strchr(id,' ')-id;}; + if(id.Find(' ')>=0) id = id.Left(id.Find(' ')); + if(id.GetLength()>0) + { + + CString unitname=*rules.sections["OverlayTypes"].GetValue(i); + +#ifdef RA2_MODE + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER2 && g_data.sections["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER3 && g_data.sections["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER4 && g_data.sections["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER5 && g_data.sections["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; +#else + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; +#endif + +#ifdef RA2_MODE + if((i>=39 && i<=60) || (i>=180 && i<=201) || i==239 || i==178 || i==167 || i==126 + || (i>=122 && i<=125) || i==1 || (i>=0x03 && i<=0x17) || (i>=0x3d && i<=0x43) + || (i>=0x4a && i<=0x65) || (i>=0xcd && i<=0xec)) + { + if(!isTrue(g_data.sections["Debug"].values["DisplayAllOverlay"])) + { + e++; + continue; + } + } + + +#endif + + CString val=*rules.sections["OverlayTypes"].GetValue(i); +#ifdef RA2_MODE + val.Replace("TIB", "ORE"); +#endif + + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, val , 0,0,0,0, valadded*6+3000+e, everyoverlay, TVI_LAST ); + e++; + } + } + } + + + for(i=0;i<rules.sections["InfantryTypes"].values.size();i++) + { + CString unitname=*rules.sections["InfantryTypes"].GetValue(i); + + if(unitname.GetLength()==0) continue; + +#ifdef RA2_MODE + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER2 && g_data.sections["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER3 && g_data.sections["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER4 && g_data.sections["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER5 && g_data.sections["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; +#else + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; +#endif + +#ifdef RA2_MODE + if(g_data.sections["IgnoreRA2"].FindValue(unitname)>=0) continue; +#else + if(g_data.sections["IgnoreTS"].FindValue(unitname) >= 0) continue; +#endif + + WCHAR* addedString=Map->GetUnitName(unitname); + if(!addedString) continue; + + //addedString=TranslateStringACP(addedString); + + //addedString+=" ("; + //addedString+=unitname+")"; + + TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, rootitems[0], valadded*1+i); + + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*1+i, rootitems[0], TVI_LAST ); + lv=i; + } + lv+=1; + // okay, now the user-defined types: + for(i=0;i<ini.sections["InfantryTypes"].values.size();i++) + { + if(ini.sections["InfantryTypes"].GetValue(i)->GetLength()==0) continue; + + if(strlen(ini.sections[*ini.sections["InfantryTypes"].GetValue(i)].values["Name"])>0) + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, ini.sections[*ini.sections["InfantryTypes"].GetValue(i)].values["Name"], 0,0,0,0, valadded*1+rules.sections["InfantryTypes"].values.size()+i, rootitems[0], TVI_LAST ); + else + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, (*ini.sections["InfantryTypes"].GetValue(i)+" NOTDEFINED"), 0,0,0,0, valadded*1+rules.sections["InfantryTypes"].values.size()+i, rootitems[0], TVI_LAST ); + + + } + + CString theater=Map->GetTheater(); + + + auto needed_terrain=TheaterChar::None; + if(tiledata==&s_tiledata) needed_terrain=TheaterChar::A; + else if(tiledata==&t_tiledata) needed_terrain=TheaterChar::T; + + for(i=0;i<rules.sections["BuildingTypes"].values.size();i++) + { + + CString unitname=*rules.sections["BuildingTypes"].GetValue(i); + + if(unitname.GetLength()==0) continue; + +#ifdef RA2_MODE + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER2 && g_data.sections["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER3 && g_data.sections["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER4 && g_data.sections["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER5 && g_data.sections["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; +#else + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; +#endif + +#ifdef RA2_MODE + if (g_data.sections["IgnoreRA2"].FindValue(unitname) >= 0) continue; +#else + if (g_data.sections["IgnoreTS"].FindValue(unitname) >= 0) continue; +#endif + if (!isTrue(g_data.sections["Debug"].GetValueByName("ShowBuildingsWithToTile", "0")) && !rules.sections[unitname].GetValueByName("ToTile").IsEmpty()) + continue; + + + WCHAR* addedString=Map->GetUnitName(unitname); + if(!addedString) continue; + + + + CString owner=rules.sections[unitname].values["Owner"]; + int baseplanningside=-1; +#ifdef RA2_MODE + baseplanningside=-1; +#endif + if(rules.sections[unitname].values.find("AIBasePlanningSide")!=rules.sections[unitname].values.end()) + { + baseplanningside=atoi(rules.sections[unitname].values["AIBasePlanningSide"]); + } + if(g_data.sections.find(unitname)!=g_data.sections.end() && g_data.sections[unitname].values.find("AIBasePlanningSide")!=g_data.sections[unitname].values.end()) + { + baseplanningside=atoi(g_data.sections[unitname].values["AIBasePlanningSide"]); + } + + + int id=Map->GetBuildingID(unitname); + if(id<0 /*|| (buildinginfo[id].pic[0].bTerrain!=0 && buildinginfo[id].pic[0].bTerrain!=needed_terrain)*/) + continue; + + if(theater==THEATER0 && !buildinginfo[id].bTemp) { /*MessageBox("Ignored", unitname,0);*/ continue;} + if(theater==THEATER1 && !buildinginfo[id].bSnow) { /*MessageBox("Ignored", unitname,0);*/ continue;} + if(theater==THEATER2 && !buildinginfo[id].bUrban) { /*MessageBox("Ignored", unitname,0);*/ continue;} + + // check if mapfile contains other value for owner + if(ini.sections.find(unitname)!=ini.sections.end()) + { + if(ini.sections[unitname].values.find("Owner")!=ini.sections[unitname].values.end()) + owner=ini.sections[unitname].values["Owner"]; + } + + //addedString=TranslateStringACP(addedString); + + //addedString+=" ("; + //addedString+=unitname+")"; + + BOOL addedfor[3]={FALSE,FALSE,FALSE}; + + // MW fixed below for YR... uhhh... + int e; + BOOL bAdded=FALSE; + for(e=0;e<sides.size();e++) + { + //MessageBox(sides[e].name); + + if(isIncluded(owner,sides[e].name)) + { + +#ifdef RA2_MODE + if(!addedfor[sides[e].orig_n]) +#endif + if(baseplanningside==-1 || baseplanningside==sides[e].orig_n) + { + + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*2+i, structhouses[e], TVI_LAST ); + TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, structhouses[e], valadded*2+i); + bAdded=TRUE; + addedfor[sides[e].orig_n]=TRUE; + + } + } + + + } + + if(bAdded==FALSE) + { + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*2+i, structhouses[e+1], TVI_LAST ); + TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, structhouses[sides.size()], valadded*2+i); + } + + lv=i; + } + lv+=1; + // okay, now the user-defined types: + for(i=0;i<ini.sections["BuildingTypes"].values.size();i++) + { + if(ini.sections["BuildingTypes"].GetValue(i)->GetLength()==0) continue; + + int id=Map->GetBuildingID(*ini.sections["BuildingTypes"].GetValue(i)); + if(id<0 || (buildinginfo[id].pic[0].bTerrain!=TheaterChar::None && buildinginfo[id].pic[0].bTerrain!=needed_terrain)) + continue; + + int e=2; + CString owner; + BOOL bAdded=FALSE; + owner=ini.sections[*ini.sections["BuildingTypes"].GetValue(i)].values["Owner"]; + owner.MakeUpper(); + if(strlen(ini.sections[*ini.sections["BuildingTypes"].GetValue(i)].values["Name"])>0) + { + CString addedString=ini.sections[*ini.sections["BuildingTypes"].GetValue(i)].values["Name"]; + int e; + for(e=0;e<sides.size();e++) + { + if(isIncluded(owner, sides[e].name)) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*2+i, structhouses[e], TVI_LAST ); + bAdded=TRUE; + } + else if(e==sides.size()-1 && bAdded==FALSE) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*2+i, structhouses[e+1], TVI_LAST ); + } + } + } + else + { + CString addedString=(*ini.sections["BuildingTypes"].GetValue(i)+" UNDEFINED"); + BOOL addedfor[2]={FALSE,FALSE}; + + int e; + for(e=0;e<sides.size();e++) + { +#ifdef RA2_MODE + if(!addedfor[sides[e].orig_n]) +#endif + if(isIncluded(owner, sides[e].name) || (yuri_mode && e==2 && owner=="YuriCountry")) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*2+i, structhouses[e], TVI_LAST ); + bAdded=TRUE; + addedfor[sides[e].orig_n]=TRUE; + + } + else if(e==sides.size()-1 && bAdded==FALSE) + { + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*2+i, structhouses[e+1], TVI_LAST ); + } + } + } + + } + + + + for(i=0;i<rules.sections["AircraftTypes"].values.size();i++) + { + CString unitname=*rules.sections["AircraftTypes"].GetValue(i); + if(unitname.GetLength()==0) continue; + +#ifdef RA2_MODE + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER2 && g_data.sections["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER3 && g_data.sections["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER4 && g_data.sections["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER5 && g_data.sections["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; +#else + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; +#endif + +#ifdef RA2_MODE + if (g_data.sections["IgnoreRA2"].FindValue(unitname) >= 0) continue; +#else + if (g_data.sections["IgnoreTS"].FindValue(unitname) >= 0) continue; +#endif + + WCHAR* addedString=Map->GetUnitName(unitname); + if(!addedString) continue; + + //addedString=TranslateStringACP(addedString); + + //addedString+=" ("; + //addedString+=unitname+")"; + + TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, rootitems[2], valadded*3+i); + + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*3+i, rootitems[2], TVI_LAST ); + lv=i; + } + lv+=1; + // okay, now the user-defined types: + for(i=0;i<ini.sections["AircraftTypes"].values.size();i++) + { + if(ini.sections["AircraftTypes"].GetValue(i)->GetLength()==0) continue; + + if(strlen(ini.sections[*ini.sections["AircraftTypes"].GetValue(i)].values["Name"])>0) + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, ini.sections[*ini.sections["AircraftTypes"].GetValue(i)].values["Name"], 0,0,0,0, valadded*3+i+rules.sections["AircraftTypes"].values.size(), rootitems[2], TVI_LAST ); + else + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, (*ini.sections["AircraftTypes"].GetValue(i)+" NOTDEFINED"), 0,0,0,0, valadded*3+i+rules.sections["AircraftTypes"].values.size(), rootitems[2], TVI_LAST ); + + + } + + + for(i=0;i<rules.sections["VehicleTypes"].values.size();i++) + { + CString unitname=*rules.sections["VehicleTypes"].GetValue(i); + if(unitname.GetLength()==0) continue; + +#ifdef RA2_MODE + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER2 && g_data.sections["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER3 && g_data.sections["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER4 && g_data.sections["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER5 && g_data.sections["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; +#else + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; +#endif + +#ifdef RA2_MODE + if (g_data.sections["IgnoreRA2"].FindValue(unitname) >= 0) continue; +#else + if (g_data.sections["IgnoreTS"].FindValue(unitname) >= 0) continue; +#endif + + WCHAR* addedString=Map->GetUnitName(unitname); + if(!addedString) continue; + + //addedString=TranslateStringACP(addedString); + + //addedString+=" ("; + //addedString+=unitname+")"; + + TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, rootitems[1], valadded*4+i); + + //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*4+i, rootitems[1], TVI_LAST ); + lv=i; + } + lv+=1; + // okay, now the user-defined types: + for(i=0;i<ini.sections["VehicleTypes"].values.size();i++) + { + if(ini.sections["VehicleTypes"].GetValue(i)->GetLength()==0) continue; + + if(strlen(ini.sections[*ini.sections["VehicleTypes"].GetValue(i)].values["Name"])>0) + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, ini.sections[*ini.sections["VehicleTypes"].GetValue(i)].values["Name"], 0,0,0,0, valadded*4+i+rules.sections["VehicleTypes"].values.size(), rootitems[1], TVI_LAST ); + else + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, (*ini.sections["VehicleTypes"].GetValue(i)+" NOTDEFINED"), 0,0,0,0, valadded*4+i+rules.sections["VehicleTypes"].values.size(), rootitems[1], TVI_LAST ); + + + } + + + #ifdef RA2_MODE + HTREEITEM hTrees=tree.InsertItem(GetLanguageStringACP("TreesObList"), rootitems[4], TVI_LAST); + HTREEITEM hTL=tree.InsertItem(GetLanguageStringACP("TrafficLightsObList"), rootitems[4], TVI_LAST); + HTREEITEM hSigns=tree.InsertItem(GetLanguageStringACP("SignsObList"), rootitems[4], TVI_LAST); + HTREEITEM hLightPosts=tree.InsertItem(GetLanguageStringACP("LightPostsObList"), rootitems[4], TVI_LAST); + #endif + + // random tree placer +#ifdef RA2_MODE + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("RndTreeObList"), 0,0,0,0, valadded*5+999, hTrees, TVI_LAST); +#else + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("RndTreeObList"), 0,0,0,0, valadded*5+999, rootitems[4], TVI_LAST); +#endif + + for(i=0;i<rules.sections["TerrainTypes"].values.size();i++) + { + CString unitname=*rules.sections["TerrainTypes"].GetValue(i); + CString addedString=Map->GetUnitName(unitname); + +#ifdef RA2_MODE + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER2 && g_data.sections["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER3 && g_data.sections["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER4 && g_data.sections["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER5 && g_data.sections["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; +#else + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; +#endif + +#ifdef RA2_MODE + if (g_data.sections["IgnoreRA2"].FindValue(unitname) >= 0) continue; +#else + if (g_data.sections["IgnoreTS"].FindValue(unitname) >= 0) continue; +#endif +#ifdef RA2_MODE + if (g_data.sections["IgnoreTerrainRA2"].FindValue(unitname) >= 0) continue; +#else + if (g_data.sections["IgnoreTerrainTS"].FindValue(unitname) >= 0) continue; +#endif + + addedString=TranslateStringACP(addedString); + + UINT flags=MF_STRING; + + HTREEITEM howner=rootitems[4]; + + #ifdef RA2_MODE + if(unitname.Find("SIGN")>=0) howner=hSigns; + if(unitname.Find("TRFF")>=0) howner=hTL; + if(unitname.Find("TREE")>=0) howner=hTrees; + if(unitname.Find("LT")>=0) howner=hLightPosts; + #endif + +#ifdef RA2_MODE + if(howner==hTrees) + { + int TreeMin=atoi(g_data.sections[Map->GetTheater()+"Limits"].values["TreeMin"]); + int TreeMax=atoi(g_data.sections[Map->GetTheater()+"Limits"].values["TreeMax"]); + + CString id=unitname; + id.Delete(0, 4); + int n=atoi(id); + + if(n<TreeMin || n>TreeMax) continue; + } +#endif + + if(unitname.GetLength()>0 && unitname!="VEINTREE" && unitname.Find("ICE")<0 && unitname.Find("BOXES")<0 && unitname.Find("SPKR")<0) // out with it :-) + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, (addedString+ " (" + unitname +")"), 0,0,0,0, valadded*5+i, howner, TVI_LAST ); + + lv=i; + } + +#ifdef SMUDGE_SUPP + for(i=0;i<rules.sections["SmudgeTypes"].values.size();i++) + { + CString unitname=*rules.sections["SmudgeTypes"].GetValue(i); + CString addedString=unitname; + +#ifdef RA2_MODE + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER2 && g_data.sections["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER3 && g_data.sections["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER4 && g_data.sections["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER5 && g_data.sections["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; +#else + if (Map->GetTheater()==THEATER0 && g_data.sections["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; + if (Map->GetTheater()==THEATER1 && g_data.sections["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; +#endif + +#ifdef RA2_MODE + if (g_data.sections["IgnoreRA2"].FindValue(unitname) >= 0) continue; +#else + if (g_data.sections["IgnoreTS"].FindValue(unitname) >= 0) continue; +#endif + + addedString=TranslateStringACP(addedString); + + UINT flags=MF_STRING; + + HTREEITEM howner=rootitems[14]; + + + if(unitname.GetLength()>0) + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, unitname, 0,0,0,0, valadded*8+i, howner, TVI_LAST ); + + lv=i; + } +#endif + + + + OutputDebugString("Objectbrowser redraw finished\n"); + + +} + +int CViewObjects::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + lpCreateStruct->style|=TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_SHOWSELALWAYS; + if (CTreeView::OnCreate(lpCreateStruct) == -1) + return -1; + + + return 0; +} + +void CViewObjects::OnInitialUpdate() +{ + CTreeView::OnInitialUpdate(); + + + m_ready=TRUE; +} + +void CViewObjects::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult) +{ + TV_KEYDOWN* pTVKeyDown = (TV_KEYDOWN*)pNMHDR; + // TODO: Code fĂ¼r die Behandlungsroutine der Steuerelement-Benachrichtigung hier einfĂ¼gen + + *pResult = 0; +} + +void CViewObjects::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + // TODO: Code fĂ¼r die Behandlungsroutine fĂ¼r Nachrichten hier einfĂ¼gen und/oder Standard aufrufen + + // CTreeView::OnKeyDown(nChar, nRepCnt, nFlags); +} + +void CViewObjects::HandleBrushSize(int iTile) +{ + if(iTile>=*tiledata_count) return; + + int i; + for(i=0;i<g_data.sections["StdBrushSize"].values.size();i++) + { + CString n=*g_data.sections["StdBrushSize"].GetValueName(i); + if((*tiles).sections["General"].FindName(n)>=0) + { + int tset=atoi((*tiles).sections["General"].values[n]); + if(tset==(*tiledata)[iTile].wTileSet) + { + int bs=atoi(*g_data.sections["StdBrushSize"].GetValue(i)); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.m_BrushSize=bs-1; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_settingsbar.UpdateData(FALSE); + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_x=bs; + ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->m_BrushSize_y=bs; + } + } + } + +} diff --git a/MissionEditor/ViewObjects.h b/MissionEditor/ViewObjects.h new file mode 100644 index 0000000..a431e83 --- /dev/null +++ b/MissionEditor/ViewObjects.h @@ -0,0 +1,86 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_VIEWOBJECTS_H__360F4320_9B82_11D3_B63B_EC44EDA1D441__INCLUDED_) +#define AFX_VIEWOBJECTS_H__360F4320_9B82_11D3_B63B_EC44EDA1D441__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ViewObjects.h : Header-Datei +// +#include <afxcview.h> + + + +///////////////////////////////////////////////////////////////////////////// +// Ansicht CViewObjects + +class CViewObjects : public CTreeView +{ +protected: + CViewObjects(); // Dynamische Erstellung verwendet geschĂ¼tzten Konstruktor + DECLARE_DYNCREATE(CViewObjects) + +// Attribute +public: + +// Operationen +public: + CTreeCtrl* tree; + BOOL m_ready; + void UpdateDialog(); + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CViewObjects) + public: + virtual void OnInitialUpdate(); + protected: + virtual void OnDraw(CDC* pDC); // Ăœberschrieben zum Zeichnen dieser Ansicht + //}}AFX_VIRTUAL + +// Implementierung +protected: + virtual ~CViewObjects(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + + // Generierte Nachrichtenzuordnungsfunktionen +protected: + //{{AFX_MSG(CViewObjects) + afx_msg void OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnKeydown(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + void HandleBrushSize(int iTile); +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_VIEWOBJECTS_H__360F4320_9B82_11D3_B63B_EC44EDA1D441__INCLUDED_ diff --git a/MissionEditor/WaypointID.cpp b/MissionEditor/WaypointID.cpp new file mode 100644 index 0000000..8d59d70 --- /dev/null +++ b/MissionEditor/WaypointID.cpp @@ -0,0 +1,110 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// WaypointID.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "FinalSun.h" +#include "WaypointID.h" +#include "mapdata.h" +#include "variables.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CWaypointID + + +CWaypointID::CWaypointID(CWnd* pParent /*=NULL*/) + : CDialog(CWaypointID::IDD, pParent) +{ + //{{AFX_DATA_INIT(CWaypointID) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + + +void CWaypointID::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CWaypointID) + DDX_Control(pDX, IDC_ID, m_id); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CWaypointID, CDialog) + //{{AFX_MSG_MAP(CWaypointID) + ON_BN_CLICKED(IDC_FREE, OnFree) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CWaypointID + +void CWaypointID::OnFree() +{ + CIniFile& ini=Map->GetIniFile(); + + int i; + CString freen; + + for(i=0;i>-1;i++) + { + char d[50]; + itoa(i,d,10); + if(ini.sections["Waypoints"].values.find(d)==ini.sections["Waypoints"].values.end()) + { + freen=d; + break; + } + } + + m_id.SetWindowText(freen); +} + +void CWaypointID::OnOK() +{ + CString h; + m_id.GetWindowText(h); + if(h.GetLength()<1) + { + return; + } + + m_value=atoi(h); + + CDialog::OnOK(); +} + +BOOL CWaypointID::OnInitDialog() +{ + CDialog::OnInitDialog(); + + OnFree(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} diff --git a/MissionEditor/WaypointID.h b/MissionEditor/WaypointID.h new file mode 100644 index 0000000..11f023a --- /dev/null +++ b/MissionEditor/WaypointID.h @@ -0,0 +1,69 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_WAYPOINTID_H__7F75C740_89FE_11D3_B63B_F82C84AD2A41__INCLUDED_) +#define AFX_WAYPOINTID_H__7F75C740_89FE_11D3_B63B_F82C84AD2A41__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// WaypointID.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CWaypointID + +class CWaypointID : public CDialog +{ +// Konstruktion +public: + int m_value; + CWaypointID(CWnd* pParent = NULL); // Standardkonstruktor + +// Dialogfelddaten + //{{AFX_DATA(CWaypointID) + enum { IDD = IDD_WAYPOINT }; + CEdit m_id; + //}}AFX_DATA + + +// Ăœberschreibungen + // Vom Klassen-Assistenten generierte virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CWaypointID) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CWaypointID) + afx_msg void OnFree(); + virtual void OnOK(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_WAYPOINTID_H__7F75C740_89FE_11D3_B63B_F82C84AD2A41__INCLUDED_ diff --git a/MissionEditor/Waypoints.cpp b/MissionEditor/Waypoints.cpp new file mode 100644 index 0000000..ef9a014 --- /dev/null +++ b/MissionEditor/Waypoints.cpp @@ -0,0 +1,205 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// Waypoints.cpp: Implementierungsdatei +// + +#include "stdafx.h" +#include "TiberianSun Mission Editor.h" +#include "Waypoints.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Eigenschaftenseite CWaypoints + +IMPLEMENT_DYNCREATE(CWaypoints, CPropertyPage) + +CWaypoints::CWaypoints() : CPropertyPage(CWaypoints::IDD) +{ + //{{AFX_DATA_INIT(CWaypoints) + // HINWEIS: Der Klassen-Assistent fĂ¼gt hier Elementinitialisierung ein + //}}AFX_DATA_INIT +} + +CWaypoints::~CWaypoints() +{ +} + +void CWaypoints::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CWaypoints) + DDX_Control(pDX, IDC_DBG, m_dbg); + DDX_Control(pDX, IDC_WAYPOINTS, m_Waypoints); + DDX_Control(pDX, IDC_POS, m_Pos); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CWaypoints, CPropertyPage) + //{{AFX_MSG_MAP(CWaypoints) + ON_LBN_SELCHANGE(IDC_WAYPOINTS, OnSelchangeWaypoints) + ON_EN_KILLFOCUS(IDC_POS, OnKillfocusPos) + ON_WM_KILLFOCUS() + ON_WM_SHOWWINDOW() + ON_BN_CLICKED(IDC_DELETE, OnDelete) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fĂ¼r Nachrichten CWaypoints + +void CWaypoints::UpdateDialog() +{ + m_Waypoints.SetRedraw(FALSE); + + // first clear the list + while(m_Waypoints.DeleteString(0)!=LB_ERR); + + // okay add all trees + + int i; + CIniFileSection& sec=ini.sections["Waypoints"]; + + char c[50]; + for(i=0;i<sec.values.size();i++) + { + CString str; + str=sec.GetValueName(i)->data(); + + + str+=", "; + str+=sec.GetValue(i)->data(); + + int x,y,z; + GetXYPos((char*)sec.GetValue(i)->data(), &x, &y); + + + itoa(x, c,10); + str+=", "; + str+=c; + itoa(y, c,10); + str+="/"; + str+=c; + + z=GetPos(x, y, 0); + itoa(z, c, 10); + str+="/"; + str+=c; + + /*int pos=atoi(str); + + str+=(CString)" "+ sec.GetValue(i)->data(); + int x,y; + GetXYPos(atoi(sec.GetValueName(i)->data()), x, y); + char c[50]; + itoa(x, c, 10); + str+=" ("; + str+=c; + str+="/"; + itoa(y, c, 10); + str+=c; + str+=")";*/ + + m_Waypoints.InsertString(-1, str); + + } + + m_Waypoints.SetRedraw(TRUE); + +} + +void CWaypoints::OnSelchangeWaypoints() +{ + int i=m_Waypoints.GetCurSel(); + if(i==-1) return; + + CString str; + m_Waypoints.GetText(i, str); + + str.SetAt(str.Find(",",0), 0); + + // ok str now specifies the waypoint id + m_Pos.SetWindowText(ini.sections["Waypoints"].values[(char*)(LPCTSTR)str].data()); +} + +void CWaypoints::OnKillfocusPos() +{ + int i=m_Waypoints.GetCurSel(); + if(i==-1) return; + + CString str; + m_Waypoints.GetText(i, str); + + str.SetAt(str.Find(",",0), 0); + + // ok str now specifies the waypoint id + ini.sections["Waypoints"].values[(char*)(LPCTSTR)str]=GetText(&m_Pos); + + UpdateDialog(); + m_Waypoints.SetCurSel(i); +} + +void CWaypoints::OnKillFocus(CWnd* pNewWnd) +{ + CPropertyPage::OnKillFocus(pNewWnd); + + +} + +void CWaypoints::OnShowWindow(BOOL bShow, UINT nStatus) +{ + CPropertyPage::OnShowWindow(bShow, nStatus); + + OnKillfocusPos(); +} + +void CWaypoints::OnDelete() +{ + int pos=m_Waypoints.GetCurSel(); + if(pos==-1) return; + + CString cuwayp; + //m_TreeList.GetText(pos, cutree); + cuwayp=ini.sections["Waypoints"].GetValueName(pos)->data(); + + ini.sections["Waypoints"].values.erase((string)(char*)(LPCTSTR) cuwayp); + + m_Waypoints.SetRedraw(FALSE); + UpdateDialog(); + m_Waypoints.SetCurSel(pos); + m_Waypoints.SetRedraw(TRUE); +} + +BOOL CWaypoints::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + CBitmap m; + m.LoadBitmap(IDB_DBG); + m_dbg.SetBitmap(m); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurĂ¼ckgeben +} diff --git a/MissionEditor/Waypoints.h b/MissionEditor/Waypoints.h new file mode 100644 index 0000000..ab438a0 --- /dev/null +++ b/MissionEditor/Waypoints.h @@ -0,0 +1,77 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#if !defined(AFX_WAYPOINTS_H__B0ED0400_7374_11D3_99E1_BB3FC259EC06__INCLUDED_) +#define AFX_WAYPOINTS_H__B0ED0400_7374_11D3_99E1_BB3FC259EC06__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// Waypoints.h : Header-Datei +// + +///////////////////////////////////////////////////////////////////////////// +// Dialogfeld CWaypoints + +class CWaypoints : public CPropertyPage +{ + DECLARE_DYNCREATE(CWaypoints) + +// Konstruktion +public: + void UpdateDialog(); + CWaypoints(); + ~CWaypoints(); + +// Dialogfelddaten + //{{AFX_DATA(CWaypoints) + enum { IDD = IDD_WAYPOINTS }; + CStatic m_dbg; + CListBox m_Waypoints; + CEdit m_Pos; + //}}AFX_DATA + + +// Ăœberschreibungen + // Der Klassen-Assistent generiert virtuelle FunktionsĂ¼berschreibungen + //{{AFX_VIRTUAL(CWaypoints) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-UnterstĂ¼tzung + //}}AFX_VIRTUAL + +// Implementierung +protected: + // Generierte Nachrichtenzuordnungsfunktionen + //{{AFX_MSG(CWaypoints) + afx_msg void OnSelchangeWaypoints(); + afx_msg void OnKillfocusPos(); + afx_msg void OnKillFocus(CWnd* pNewWnd); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + afx_msg void OnDelete(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ fĂ¼gt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. + +#endif // AFX_WAYPOINTS_H__B0ED0400_7374_11D3_99E1_BB3FC259EC06__INCLUDED_ diff --git a/MissionEditor/constants.cpp b/MissionEditor/constants.cpp new file mode 100644 index 0000000..76c60e9 --- /dev/null +++ b/MissionEditor/constants.cpp @@ -0,0 +1,19 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ diff --git a/MissionEditor/data/FinalAlert2/FAData.ini b/MissionEditor/data/FinalAlert2/FAData.ini new file mode 100644 index 0000000..16d63d0 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/FAData.ini @@ -0,0 +1,1245 @@ +; FAData.ini - Data file for FinalAlert 2: Yuri's Revenge +; This file offers data for FinalAlert 2 +; last change: Matthias Wagner, Feb 12, 2024 + +; Debug section: use carefully! +[Debug] +;DisplayAllOverlay=Yes ; Doesn´t cripple the overlay list in any way +;EnableTrackLogic=Yes ; Enables Track Logic +;IgnoreSHPImageHeadUnused=Yes ; Use this *carefully* to make SHP graphics of some mods work that incorrectly have the shadow flag set +AllowTunnels=yes +AllowUnidirectionalTunnels=yes +;ShowBuildingsWithToTile=no + +[ForceUnitPalettePrefix] +0=TIBTRE + +[ForceIsoPalettePrefix] + +; voxel turret locations (Original FA2 values) +[BuildingVoxelTurretsRA2OLD] +GTGCANX=00 +GTGCANY=44;-6 +NASAMY=-3;2 +NALASRX=0 +NALASRY=10;-3 +NAFLAKY=6;10 ; flak needs additional correction below for every direction +NAFLAKX=-5; +NAFLAKX0=5 +NAFLAKX2=-4; +NAFLAKY2=5 +NAFLAKX3=-5; +NAFLAKY3=10 +NAFLAKX4=5 +NAFLAKY4=14 +NAFLAKX5=10 +NAFLAKY5=8 +NAFLAKX6=15 +NAFLAKY6=5 +NAFLAKX7=12 +NAFLAKY7=1 +CAOUTPX=-30 +CAOUTPY=12 +YAREFNX=-30 +YAREFNY=30 +YAGGUNY=7 +YAGGUNX=-5 +YAGGUNX7=5; gattling gun needs some correction +YAGGUNY7=-3 +YAGGUNX6=11 +YAGGUNY6=3 +YAGGUNX5=10 +YAGGUNY5=3 +YAGGUNX4=3 +YAGGUNY4=2 +YAGGUNX0=5 + +[BuildingVoxelTurretsRA2] +GTGCANX=-5 +GTGCANY=5 +GTGCANX=-2 +GTGCANY=2 + +; voxel barrel locations (Original FA2 values) +[BuildingVoxelBarrelsRA2OLD] +GTGCANX0=0 +GTGCANY0=30;-6 +GTGCANX1=-18 +GTGCANY1=35;-6 +GTGCANX2=-28 +GTGCANY2=50;-6 +GTGCANX3=-27 +GTGCANY3=67;-6 +GTGCANX4=00 +GTGCANY4=73;-6 +GTGCANX5=23 +GTGCANY5=60;-6 +GTGCANX6=30 +GTGCANY6=48;-6 +GTGCANX7=20 +GTGCANY7=35;-6 + + +[BuildingVoxelBarrelsRA2] +GTGCANX=-5 +GTGCANY=5 + + +; not NOSURFACES: +;[BuildingVoxelTurretsRA2] +;GTGCANX=-1 +;GTGCANY=0;-6 +;NASAMY=0;2 +;NALASRX=0 +;NALASRY=0;-3 +;NAFLAKY=10;10 + +[VehicleVoxelTurretsRA2Disabled] +;DISKX=-10 +;DISKY=-10 +;YTNKY=-30 +SREFX=4 +SREFY=3 + +[IgnoreArtImage] +BFRT=1 +CAML=1 + +[IgnoreSuperAnim1] +[IgnoreSuperAnim2] +NAMISL=1 +GACSPH=1 + +[IgnoreSuperAnim3] +NAMISL=1 +GACSPH=1 + +[IgnoreSuperAnim4] +NAMISL=1 +GACSPH=1 + +; fix for building list: +[GTGCAN] +AIBasePlanningSide=0 + +[YACOMD] +AIBasePlanningSide=2 + +[YADEPT] +AIBasePlanningSide=0 + +[NASPYB] +AIBasePlanningSide=2 + +; rename list for objects. ObjectID=StringID +[Rename] +AMRADR=N_AMRADR +SENGINEER=N_SENGINEER +ENGINEER=N_ENGINEER +YENGINEER=N_YENGINEER +SCHD=N_SCHD +GACSPH=N_GACSPH +CALOND04=N_CALOND04 +CALOND05=N_CALOND05 +CATRAN03=N_CATRAN03 + +[MovieList] +Start=66; Anything below will not be listed! + +[StdBrushSize] +ClearTile=2 +RoughTile=2 +SandTile=2 +GreenTile=2 +PaveTile=2 +WaterSet=2 + +[MinBrushSizeInWater] ; if completely surrounded by water ; currently ignored +ClearTile=2 +RoughTile=2 +SandTile=2 +GreenTile=2 +PaveTile=2 + +; SlopeSetPieces for cliffs have a specific direction. +; used for AutoLevel logic +; CURRENTLY IGNORED +[SlopeSetPiecesDirections] +Count=10 +0=Right_1 +1=Left_1 +2=Top_1 +3=Bottom_1 +4=Right_2 +5=Left_2 +6=Left_2 +7=Bottom_2 +8=Top_2 +9=Top_2 + +[LUNARLimits] +TreeMax=999 +TreeMin=999 + +[URBANLimits] +TreeMax=999 +;TreeMax=27 + +[TEMPERATELimits] +TreeMax=999 +;TreeMax=27 + +[SNOWLimits] +TreeMax=999 +;TreeMax=27 + +[NEWURBANLimits] +TreeMax=999 +;TreeMax=27 + +[DESERTLimits] +TreeMin=30 +TreeMax=999 + +; tileset ini overwritings +; only used by FinalAlert +[IgnoreSetTEMPERATE] +0=77 +1=78 +2=79 + +[IgnoreSetSNOW] +0=8 +1=46 + +[IgnoreSetURBAN] +0=49 +1=50 +2=51 +5=56 +7=30 +8=91 +9=92 +10=93 +11=94 +12=95 +13=96 +14=97 +15=98 +16=99 +17=100 +;3=53; Tunnel +;4=54; Tunnel Side +;6=73; Dirt Tunnel + +[IgnoreSetNEWURBAN] +0=101 + +[IgnoreSetDESERT] +0=19 +1=54 +2=53 +3=56 +4=73 +5=80 + +[IgnoreSetLUNAR] + +[UseSetTEMPERATE] +0=57 + +[UseSetSNOW] +[UseSetURBAN] + +[NewUrbanInfo] +Morphable2=114 +Ramps2=117 +Cliffs2=110 +CliffsWater2=112 + +; The following section is for finding out if a map is RA2 original or Yuri's Revenge only! +; If a ground tile id exceeds this number, FA2 will assume the map is a YR map +[RA2TileMax] +Temperat=838 +Urban=1077 +Snow=798 + +[YRInfantry] +YENGINEER=1 +GGI=1 +INIT=1 +BORIS=1 +BRUTE=1 +VIRUS=1 +CLNT=1 +ARND=1 +STLN=1 +CAML=1 +EINS=1 +MUMY=1 +RMNV=1 +LUNR=1 +DNOA=1 +DNOB=1 +SLAV=1 +WWLF=1 +YDOG=1 +YADOG=1 + +[YRUnits] +YHVR=1 +PCV=1 +SMIN=1 +SMON=1 +YCAB=1 +YTNK=1 +BFRT=1 +TELE=1 +CAOS=1 +DDBX=1 +BCAB=1 +BSUB=1 +SCHP=1 +JEEP=1 +MIND=1 +DISK=1 +UTNK=1 +ROBO=1 +YDUM=1 +SCHD=1 +DOLY=1 +CBLC=1 +FTRK=1 +AMBU=1 +CIVP=1 + +[YRBuildings] +YACNST=1 +YAPOWR=1 +YABRCK=1 +YAWEAP=1 +YAYARD=1 +YADEPT=1 +YATECH=1 +GAFWLL=1 +YAGGUN=1 +YAPSYT=1 +NAINDP=1 +YAGRND=1 +YAGNTC=1 +CASLAB=1 +CATIME=1 +YAPPET=1 +CALOND04=1 +CALOND05=1 +CALOND06=1 +CAMOON01=1 +CATRAN03=1 +CAEAST01=1 +CAEGYP01=1 +CAEGYP02=1 +CAEGYP03=1 +CALA01=1 +CALA02=1 +CALA03=1 +CALA04=1 +CALA05=1 +CALOND01=1 +CALOND02=1 +CALOND03=1 +CAMORR01=1 +CAMORR02=1 +CAMORR03=1 +CASANF01=1 +CASANF02=1 +CASANF03=1 +CASANF04=1 +CASANF05=1 +CASEAT01=1 +NATBNK=1 +GAGATE_A=1 +CASANF09=1 +CASANF10=1 +CASANF11=1 +CASANF12=1 +CASANF13=1 +CASANF14=1 +CASANF06=1 +CASANF07=1 +CASANF08=1 +CASEAT02=1 +YACOMD=1 +YAPPPT=1 +GAROBO=1 +YAREFN=1 +YAROCK=1 +NABNKR=1 +CASANF15=1 +CASANF16=1 +CASANF17=1 +CASANF18=1 +CASIN03E=1 +CASIN03S=1 +CAURB01=1 +CAURB02=1 +CAURB03=1 +CAPOWR=1 +CALA07=1 +CAEGYP06=1 +CALA08=1 +CAEAST02=1 +CABARR01=1 +CABARR02=1 +CAMORR04=1 +CAMORR05=1 +CALA09=1 +CAEGYP04=1 +CAEGYP05=1 +CALA06=1 +CAMORR06=1 +CAMORR07=1 +CAMORR08=1 +CAMORR09=1 +CAMORR10=1 +CATIME01=1 +CATIME02=1 +CALA10=1 +CALA11=1 +CALA12=1 +CALA13=1 +CAPARK04=1 +CAPARK05=1 +CAPARK06=1 +CALA14=1 +CALA15=1 +CABUNK03=1 +CABUNK04=1 +CALUNR01=1 +CALUNR02=1 + +[YRTerrain] +TREE31=1 +TREE32=1 +TREE33=1 +TREE34=1 +TREE35=1 +TREE36=1 + +[YRAircraft] +BPLN=1 +SPYP=1 +CMISL=1 + +[YROverlay] +Begin=243; which number is the first from new YR overlay? + +; things only FinalAlert will ignore +; these are usually all dummies and leftovers from TS +[IgnoreRA2] +0=GAARMORY +1=APACHE +2=DeathDummy +3=WEEDGUY +4=GADUMY +5=NAWAST +6=GARADR +7=CAIRSFGL +8=CALIT01E +9=CALIT01N +10=CALIT01S +11=CALIT01W +12=CALIT03E +13=CALIT03N +14=CALIT03S +15=CALIT03W +16=CALIT02L +17=CALIT02R +18=NAHPAD +19=CAEURO01 +20=CACITY01 +21=CACITY02 +22=CACITY03 +23=CACITY04 +24=CITY06 +25=CITY05 +26=CITY04 +27=CITY03 +28=CITY02 +29=CITY01 +30=CAARMR +31=TREE29 +32=TREE30 +33=CANEWY05 +34=REDLAMP +35=GRENLAMP +36=BLUELAMP +37=YELWLAMP +38=PURPLAMP +39=INORANLAMP +;40=NEGLAMP ; NEGLAMP added again, invisible in game +41=NEGRED +42=TSTLAMP +43=CAPOL01E +44=CAPOL01N +45=CAPOL01S +46=CAPOL01W +47=CASIN01E +48=CASIN01N +49=CASIN01W +50=CASIN01S +51=GAGREEN +52=GALITE +53=CARGOPLANE +54=CAHOSP +55=XCOMET +56=CAKRMW +57=CAFNCB +58=CAFNCW +59=CAFNCP +60=CR1 +61=CR2 +62=CR3 +63=CR4 +64=CR5 +65=CR6 +66=BURN01 +67=BURN02 +68=BURN03 +69=BURN04 +70=BURN05 +71=BURN06 +72=BURN07 +73=BURN08 +74=BURN09 +75=BURN10 +76=BURN11 +77=BURN12 +78=BURN13 +79=BURN14 +80=BURN15 +Another one :) =BURN16 +82=CASYDN01 +83=CATIME +84=CALOND02;? +;85=CAMORR01 +;86=CAMORR02 +;87=CAMORR03 +;88=CAEGYP06 +;89=CAMORR04 +;90=CAEGYP04 +;91=CAEGYP05 +;92=CALA06 + +97=DNOB;? +98=GAWRONG +99=CALA02;? +100=CAMOON01 +;101=CAEGYP01 +102=UTNK +103=YDUM +104=WWLF +105=YADOG +106=YDOG +107=SMON +108=CMON +109=YADEPT +110=CALOND06;? +;111=TREE32 + +; hacks for shore pieces +; shore id_pos=iswater +; pos: count from left top to right, then next "row" + +; RA2 only needs one fix (for URBAN specifically) +[ShoreTerrainRA2] +12_4=1 +12_5=1 + +; But TS needs all :( +[ShoreTerrainTS] +0_0=0 +0_1=0 +0_2=1 +0_3=1 +1_0=0 +1_1=0 +2_0=0 +2_1=0 +3_0=0 +4_0=0 +4_1=0 +4_3=0 +5_0=0 +5_1=0 +5_2=0 +6_0=0 +7_0=0 +8_0=0 +8_2=0 +9_0=0 +9_2=0 +10_0=0 +10_2=0 +11_0=0 +12_0=0 +12_1=0 +12_3=0 +13_0=0 +13_3=0 +13_4=0 +14_2=0 +15_2=0 +16_2=0 +16_3=0 +17_2=0 +17_3=0 +18_2=0 +18_3=0 +19_1=0 +20_3=0 +20_4=0 +20_5=0 +21_2=0 +21_4=0 +21_5=0 +22_3=0 +23_3=0 +24_1=0 +24_3=0 +25_1=0 +25_3=0 +26_1=0 +26_3=0 +27_1=0 +28_1=0 +28_2=0 +28_5=0 +29_2=0 +29_4=0 +29_5=0 +30_1=0 +31_1=0 +32_0=0 +32_1=0 +32_2=0 +33_0=0 +33_1=0 +33_2=0 +34_0=0 +34_2=0 +34_3=0 +35_0=0 +35_2=0 +35_3=0 +36_1=0 +36_2=0 +36_3=0 +37_1=0 +37_2=0 +37_3=0 +38_0=0 +38_1=0 +38_3=0 +39_0=0 +39_1=0 +39_3=0 + +; tilesets that may be modified using the shore or a similar logic +[SoftTileSets] +ClearTile=1 +RoughTile=1 +ClearToRoughLat=1 +SandTile =1 +ClearToSandLat=1 +GreenTile=1 +ClearToGreenLat=1 +PaveTile=1 +MiscPaveTile =1 +ClearToPaveLat=1 +RoughGround=0; no +WaterSet=1 +ShorePieces=1 + +; corner strings are: cornerleft, cornerright, cornerbottom, cornertop + +[CliffBackData] +vertic_diag_c=2 +;vertic_diag_2=0 +vertic_diag_0=2 +vertic_diag_1=3 +;vertic_diag_3=1 ; unused at moment +vertic_diag_cornertop_c=1 +;vertic_diag_cornertop_1=0 +vertic_diag_cornertop_0=1 +horiz_c=4 +horiz_0=22 +horiz_1=23 +horiz_2=24 +horiz_3=25 ;2x1, not 2x2, unused at moment +horiz_cornerbottom_c=2 +horiz_cornerbottom_0=28 +horiz_cornerbottom_1=29 +horiz_cornertop_c=0 +;horiz_cornertop_0=31 +vertic_c=4 +vertic_0=34 +vertic_1=35 +vertic_2=36 +vertic_3=37 ;2x1, not 2x2, unused at moment +vertic_cornerright_c=2 +vertic_cornerright_0=29 +vertic_cornerright_1=28 + +[CliffBackDataAlt] +vertic_diag_c=2 +;vertic_diag_2=0 +vertic_diag_0=2 +vertic_diag_1=3 +;vertic_diag_3=1 ; unused at moment +vertic_diag_cornertop_c=1 +;vertic_diag_cornertop_1=0 +vertic_diag_cornertop_0=1 +horiz_c=4 +horiz_0=22 +horiz_1=23 +horiz_2=24 +horiz_3=25 ;2x1, not 2x2, unused at moment +horiz_cornerbottom_c=2 +horiz_cornerbottom_0=28 +horiz_cornerbottom_1=29 +horiz_cornertop_c=0 +;horiz_cornertop_0=31 +vertic_c=4 +vertic_0=34 +vertic_1=35 +vertic_2=36 +vertic_3=37 ;2x1, not 2x2, unused at moment +vertic_cornerright_c=2 +vertic_cornerright_0=29 +vertic_cornerright_1=28 + +[CliffBackDataURBAN] +vertic_diag_c=1 +;vertic_diag_4=0 +vertic_diag_0=2 +;vertic_diag_1=3; other cliff type +;vertic_diag_3=1 ; unused at moment +vertic_diag_cornertop_c=2 +vertic_diag_cornertop_0=0 +vertic_diag_cornertop_1=1 +horiz_c=2 +horiz_0=22 +;horiz_3=23 +;horiz_2=24 +horiz_1=25 ;2x1, not 2x2, unused at moment +horiz_cornerbottom_c=2 +horiz_cornerbottom_0=28 +horiz_cornerbottom_1=29 +vertic_c=4 +vertic_0=34 +vertic_1=35 +vertic_2=36 +vertic_3=37 ;2x1, not 2x2, unused at moment +vertic_cornerright_c=2 +vertic_cornerright_0=29 +vertic_cornerright_1=28 + +[CliffBackDataNEWURBAN] +vertic_diag_c=1 +;vertic_diag_4=0 +vertic_diag_0=2 +;vertic_diag_1=3; other cliff type +;vertic_diag_3=1 ; unused at moment +vertic_diag_cornertop_c=2 +vertic_diag_cornertop_0=0 +vertic_diag_cornertop_1=1 +horiz_c=2 +horiz_0=22 +;horiz_3=23 +;horiz_2=24 +horiz_1=25 ;2x1, not 2x2, unused at moment +horiz_cornerbottom_c=2 +horiz_cornerbottom_0=28 +horiz_cornerbottom_1=29 +vertic_c=4 +vertic_0=34 +vertic_1=35 +vertic_2=36 +vertic_3=37 ;2x1, not 2x2, unused at moment +vertic_cornerright_c=2 +vertic_cornerright_0=29 +vertic_cornerright_1=28 + +[CliffFrontData] +vertic_diag_c=2 +vertic_diag_0=18 +vertic_diag_1=19 +;vertic_diag_2=20 +;vertic_diag_3=21 ; unused at moment +vertic_diag_cornerleft_c=1 +vertic_diag_cornerleft_0=20 +;vertic_diag_cornerleft_1=21 +vertic_diag_cornerright_c=2 +vertic_diag_cornerright_0=32 +vertic_diag_cornerright_1=33 +horiz_c=4 +horiz_0=4 +horiz_1=5 +horiz_2=6 +horiz_3=7 ;2x1, not 2x2, unused at moment +horiz_cornertop_c=1 +horiz_cornertop_0=1 +horiz_diag_c=6 +horiz_diag_0=8 +horiz_diag_1=9 +horiz_diag_2=10 +horiz_diag_3=11 ; unused at moment +horiz_diag_4=12 ; unused at moment +horiz_diag_5=13 ; unused at moment +vertic_c=4 +vertic_0=14 +vertic_1=15 +vertic_2=16 +vertic_3=17 ;2x1, not 2x2, unused at moment +vertic_cornerleft_c=1 +vertic_cornerleft_0=21 + +[CliffFrontDataAlt] +vertic_diag_c=2 +vertic_diag_0=18 +vertic_diag_1=19 +;vertic_diag_2=20 +;vertic_diag_3=21 ; unused at moment +vertic_diag_cornerleft_c=1 +vertic_diag_cornerleft_0=20 +;vertic_diag_cornerleft_1=21 +vertic_diag_cornerright_c=2 +vertic_diag_cornerright_0=32 +vertic_diag_cornerright_1=33 +horiz_c=4 +horiz_0=4 +horiz_1=5 +horiz_2=6 +horiz_3=7 ;2x1, not 2x2, unused at moment +horiz_cornertop_c=1 +horiz_cornertop_0=1 +horiz_diag_c=6 +horiz_diag_0=8 +horiz_diag_1=9 +horiz_diag_2=10 +horiz_diag_3=11 ; unused at moment +horiz_diag_4=12 ; unused at moment +horiz_diag_5=13 ; unused at moment +vertic_c=4 +vertic_0=14 +vertic_1=15 +vertic_2=16 +vertic_3=17 ;2x1, not 2x2, unused at moment +vertic_cornerleft_c=1 +vertic_cornerleft_0=21 + +[CliffFrontDataURBAN] +vertic_diag_c=1 +vertic_diag_0=18 +;vertic_diag_2=19 ; other cliff type +;vertic_diag_3=20 ; other cliff type +;vertic_diag_1=21 ; unused at moment +vertic_diag_cornerleft_c=1 +vertic_diag_cornerleft_0=20 +;vertic_diag_cornerleft_1=21 +vertic_diag_cornerright_c=2 +vertic_diag_cornerright_0=32 +vertic_diag_cornerright_1=33 +horiz_c=2 +horiz_0=4 +;horiz_3=5 ; other cliff type +;horiz_2=6 ; other cliff type +horiz_1=7 ;2x1, not 2x2, unused at moment +horiz_cornertop_c=1 +horiz_cornertop_0=1 +horiz_diag_c=2 +horiz_diag_0=8 +;horiz_diag_4=9 ; other cliff type +;horiz_diag_2=10 ; other cliff type +horiz_diag_1=11 ; unused at moment +;horiz_diag_3=12 ; unused at moment +;horiz_diag_5=13 ; unused at moment +vertic_c=2 +vertic_0=14 +;vertic_3=15 ; other cliff type +;vertic_2=16 ; other cliff type +vertic_1=17 ;2x1, not 2x2, unused at moment +vertic_cornerleft_c=1 +vertic_cornerleft_0=21 + +[CliffFrontDataNEWURBAN] +vertic_diag_c=1 +vertic_diag_0=18 +;vertic_diag_2=19 ; other cliff type +;vertic_diag_3=20 ; other cliff type +;vertic_diag_1=21 ; unused at moment +vertic_diag_cornerleft_c=1 +vertic_diag_cornerleft_0=20 +;vertic_diag_cornerleft_1=21 +vertic_diag_cornerright_c=2 +vertic_diag_cornerright_0=32 +vertic_diag_cornerright_1=33 +horiz_c=2 +horiz_0=4 +;horiz_3=5 ; other cliff type +;horiz_2=6 ; other cliff type +horiz_1=7 ;2x1, not 2x2, unused at moment +horiz_cornertop_c=1 +horiz_cornertop_0=1 +horiz_diag_c=2 +horiz_diag_0=8 +;horiz_diag_4=9 ; other cliff type +;horiz_diag_2=10 ; other cliff type +horiz_diag_1=11 ; unused at moment +;horiz_diag_3=12 ; unused at moment +;horiz_diag_5=13 ; unused at moment +vertic_c=2 +vertic_0=14 +;vertic_3=15 ; other cliff type +;vertic_2=16 ; other cliff type +vertic_1=17 ;2x1, not 2x2, unused at moment +vertic_cornerleft_c=1 +vertic_cornerleft_0=21 + +; EVENTS AND ACTIONS +; param type format: Description,ListType +; ListTypes (all those not implemented yet but stubbed when this ini was written are marked with *): +; 0-Nothing +; 1-Houses +; 2-Teamtypes +; 3-UnitTypes +; 4-InfantryTypes +; 5-AircraftTypes +; 6-BuildingTypes +; 7-Videos +; 8-tutorial texts +; 9-Triggers +; 10-yes/no +; 11=sounds +; 12=themes +; 13=speeches +; 14=special weapons +; 15=animations +; 16=particles +; 17=waypoints +; 18=crate types * +; 19=speech bubble types * +; 20=Global variables <--- wrong, local variables! +; 21=.CSF strings (RA2 only) * +; 22=Tag * +; 23=Meteors * +; 24=Weapons * +; 25=Light behavior * +; 26=Shower * +; 27=Rules Global variables +; 28=Building INI names +; 29=Techtypes + + +; ParamTypes +; Name, ListType, [Code] +[ParamTypes] +-1=Unused,0,1;not listed in FA2 +0=Unused,0 +1=Unknown,0 +2=House,1 +3=Local variable,20 +4=Time,0 +5=Credits,0 +6=Number,0 +7=Teamtype,2 +8=Building,6 +9=Aircraft,5 +10=Infantry,4 +11=Unit,3 +12=Movie,7 +13=Text,8 +14=Trigger,9 +15=Enabled,10 +16=Sound,11 +17=Theme,12 +18=Speech,13 +19=Steps,0 +20=Super weapon,14 +21=Left,0 +22=Top,0 +23=Right,0 +24=Bottom,0 +25=Animation,15 +26=Particle,16 +27=Duration,0 +28=Speed,0 +29=Meteor size,29 +30=Waypoint,17 +31=Crate type,18 +32=Speech bubble,19 +33=String,21 +34=Action,9 +35=Global variable,27 +36=Special Weapon,14 +37=Activated,10 +38=Tag,22 +39=Techtype,0 +40=Quarry,0 +41=Weapon,24 +42=Light behavior,25 +43=Event,9 +44=Shower,26 +45=Float value,0 +46=Techtype,29;,2 +47=Building,28 +48=Number,0,2 + +[DontSaveAsWP] ; which code values indicate that the waypoint param must be saved as normal integer? +0=5 +1=9 +;2=10 +3=11 + +; events format: +; #=Description, P1 type, P2 type, TagNeeded, Obsolete,Desc2,UsedInTS,UsedInRA2,ID,[NeedsYR optional] +; negative number for type currently not supported (only Actions do support yet)! +; NOTE: Actions not listed in [Events] but in [EventsRA2] will be ignored. Use the "used in RA2" to support them. +; NOTE: To overwrite TS events with RA2 special ones, add the new event to the [EventsRA2] section. +; NOTE: ID must be the same like # +[EventsRA2] +0=-No Event-,0,0,0,0,This is a null event. There is no need to ever use this in a real trigger.,0,1,0 +1=Entered by...,0,2,0,0,Triggers when an infantry or vehicle enters the attached object. Typically this trigger is attached to a building or a cell.,0,1,1 +2=Spied upon,0,0,0,0,Detects when a spy has entered the attached building.,0,1,2 +3=Thieved by...,0,2,0,0,Triggers when a thief steals money from the specified house.,0,1,3 +4=Discovered by player,0,0,0,0,Detects when the attached object has been discovered by the player. Discovered means reavealed from under the shroud.,0,1,4 +5=House Discovered...,0,2,0,0,Triggers when the specified house has any of its units or buildings discovered by the player.,0,1,5 +6=Attacked by any house,0,0,0,0,Triggers when the attached unit is attacked in some manner. Incidental damage or friendly fire does not count.,0,1,6 +7=Destroyed by any house,0,0,0,0,Triggers when the attached object has been destroyed. Destroyed by incidental damage or friendly fire doesn't count.,0,1,7 +8=Any Event,0,0,0,0,When used alone%1 it will force the trigger to spring immediately.,0,1,8 +9=Destroyed%1 Units%1 All...,0,2,0,0,Triggers when all units of the specified house have been destroyed. Typically used for end of game conditions.,0,1,9 +10=Destroyed%1 Buildings%1 All...,0,2,0,0,Triggers when all buildings of the specified side have been destroyed. Typically used for end of game conditions.,0,1,10 +11=Destroyed%1 All...,0,2,0,0,Triggers when all objects owned by the specified house have been destroyed. This is the normal (destroy everyone) trigger condition for end of game.,0,1,11 +12=Credits exceed...,0,6,0,0,Triggers when the house (for this trigger) credit total exceeds this specified amount.,0,1,12 +13=Elapsed Time...,0,6,0,0,Triggers when the elapsed time has expired. This time is initialized when the trigger is created. Timer is reset whenever trigger is sprung when trigger is 'persistant'.,0,1,13 +14=Mission Timer Expired,0,0,0,0,Triggers when the global mission timer (as displayed on the screen) has reached zero.,0,1,14 +15=Destroyed%1 Buildings%1 #...,0,6,0,0,Triggers when the number of buildings%1 owned by the trigger's specified house%1 have been destroyed.,0,1,15 +16=Destroyed%1 Units%1 #...,0,6,0,0,Triggers when the number of units%1 owned by the trigger's specified house%1 have been destroyed.,0,1,16 +17=No Factories left,0,0,0,0,Triggers when there are no factories left for the house specified in the trigger.,0,1,17 +18=Civilians Evacuated,0,0,0,0,Triggers when civilians have been evacuated (left the map).,0,1,18 +19=Build Building Type...,0,8,0,0,When the trigger's house builds the building type specified%1 then this event will spring.,0,1,19 +20=Build Unit Type...,0,11,0,0,When the trigger's house builds the unit type specified%1 then this event will spring.,0,1,20 +21=Build Infantry Type...,0,10,0,0,When the trigger's house builds the infantry type specified%1 then this event will spring.,0,1,21 +22=Build Aircraft Type...,0,9,0,0,When the trigger's house builds the aircraft type specified%1 then this event will spring.,0,1,22 +23=Leaves map (team)...,-1,7,0,0,Triggers when the specified team leaves the map. If the team is destroyed%1 it won't trigger. If all but one member is destroyed and that last member leaves the map%1 it WILL spring.,0,1,23 +24=Zone Entry by...,0,2,0,0,Triggers when a unit of the dpecified house enters the same zone that this trigger is located in. This trigger must be located in a cell and only a cell.,0,1,24 +25=Crosses Horizontal Line...,0,2,0,0,Triggers when a unit of the specified house crosses the horizontal line as indicated by the location of this trigger. This trigger must be placed in a cell.,0,1,25 +26=Crosses Vertical Line...,0,2,0,0,Triggers when a unit of the specified house crosses the vertical line as indicated by the location of this trigger. This trigger must be placed in a cell.,0,1,26 +27=Global is set...,0,35,0,0,Triggers when the specifed global (named in Globals.INI) is turned on.,0,1,27 +28=Global is clear...,0,35,0,0,Triggers when the specified global (named in Globals.INI) is turned off.,0,1,28 +29=Destroyed by anything [not infiltrate],0,0,0,0,Triggers when attached object is destroyed%1 but not if it infiltrates a building/unit.,0,1,29 +30=Low Power...,0,2,0,0,Triggers when the specified house's power falls below 100% level.,0,1,30 +31=Bridge destroyed,0,0,0,0,Triggers when the attached bridge is destroyed. A bridge is considered destroyed when an impassable gap is created in the bridge.,0,1,31 +32=Building exists...,0,8,0,0,Triggers when the building (owned by the house of this trigger) specified exists on the map. This works for buildings that are preexisting or constructed by deploying.,0,1,32 +33=Selected by player,0,0,0,0,Triggers when the unit is selected by the player. Use in single-player only.,0,1,33 +34=Comes near waypoint...,0,30,0,0,Triggers when the object comes near the specified waypoint.,0,1,34 +35=Enemy In Spotlight...,0,0,0,0,Triggers when an enemy unit enters the spotlight cast by the attached building.,0,1,35 +36=Local is set...,0,3,0,0,Triggers when the specifed local is turned on.,0,1,36 +37=Local is clear...,0,3,0,0,Triggers when the specified local is turned off.,0,1,37 +38=First damaged (combat only),0,0,0,0,Triggers when first suffering from combat damage from combat damage only.,0,1,38 +39=Half health (combat only),0,0,0,0,Triggers when damaged to half health >from combat damage only.,0,1,39 +40=Quarter health (combat only),0,0,0,0,Triggers when damaged to quarter health from combat damage only.,0,1,40 +41=First damaged (any source),0,0,0,0,Triggers when first suffering from combat damage from any source.,0,1,41 +42=Half health (any source),0,0,0,0,Triggers when damaged to half health >from any source.,0,1,42 +43=Quarter health (any source),0,0,0,0,Triggers when damaged to quarter health from any source.,0,1,43 +44=Attacked by (house)...,0,2,0,0,When attacked by some unit of specified house.,0,1,44 +45=Ambient light <= ...,0,6,0,0,Triggers when the ambient light drops below a certain level. Use numbers between 0 and 100.,0,1,45 +46=Ambient light >= ...,0,6,0,0,Triggers when the ambient light rises above a certain level. Use numbers between 0 and 100.,0,1,46 +47=Elapsed Scenario Time...,0,6,0,0,When time has elapsed since start of scenario.,0,1,47 +48=Destroyed by anything,0,0,0,0,Triggers when destroyed by anything what-so-ever.,0,1,48 +49=Pickup Crate,0,0,0,0,When crate is picked up object the trigger is attached to.,0,1,49 +50=Pickup Crate (any),0,0,0,0,When crate is picked up by any unit.,0,1,50 +51=Random delay...,0,6,0,0,Delays a random time between 50 and 150 percent of time specified.,0,1,51 +52=Credits below...,0,6,0,0,Triggers when the house (for this trigger) credit total is below this specified amount.,0,1,52 +53=Spy entering as House...,0,2,0,0,Triggers if a spy disguised as house specified enters this.,0,1,53 +54=Spy entering as Infantry...,0,10,0,0,Triggers if a spy disguised as this type of infantry enters.,0,1,54 +55=Destroyed%1 Units%1 Naval...,0,2,0,0,Triggers when all naval units of the specified house have been destroyed. Typically used for end of game conditions.,0,1,55 +56=Destroyed%1 Units%1 Land...,0,2,0,0,Triggers when all land units of the specified house have been destroyed. Typically used for end of game conditions.,0,1,56 +57=Building does not exist,0,8,0,0,Triggers when the building (owned by the house of this trigger) specified does not exist on the map.,0,1,57 + +; YR +58=Power Full...,0,2,0,0,Triggers if the specified house's power is at 100%.,0,1,58,1 +59=Entered or Overflown By...,0,2,0,0,Triggers when unit%1 infantry%1 or aircraft move over this cell. <THEM = House of entering unit>,0,1,59,1 + +; 60 and 61 are tricky! They use code + 2 params... param type 46 includes the code 2, which is put in front of the 2 parameters +60=TechType Exists,48,46,0,0,True if there are at least this many of this type%1 belonging to anyone,0,1,60,1 +61=TechType does not Exist,48,46,0,0,True if there are none of these on the map at all. Number doesn't mean anything.,0,1,61,1 + + +; action format: +; #=Description, P1 type, P2 type, P3 type, P4 type, P5Type, P6Type, uses waypoint, uses tag, Obsolete, used in TS, used in RA2, ID, [YR only - optional] +; if using negative number for type, param will be set to the absolute value of this number +; NOTE: Actions not listed in [Actions] but in [ActionsRA2] will be ignored. Use the "used in RA2" to support them. +; NOTE: To overwrite TS actions with RA2 special ones, add the new action to the [ActionsRA2] section. +; NOTE: ID must be the same like # +[ActionsRA2] +0=-No Action-,0,0,0,0,0,0,0,0,0,This is a null action. It will do nothing and is equivalent to not having an action at all. Why use it?,0,1,0 +1=Winner is...,0,2,0,0,0,0,0,0,0,The winner will be forced to be the house specified. The game will end immediately. Typically%1 the player's house is specified.,0,1,1 +2=Loser is...,0,2,0,0,0,0,0,0,0,The loser will be force to be the house specified. The game will end immediately. Typically%1 the player's house is specified.,0,1,2 +3=Production Begins...,0,2,0,0,0,0,0,0,0,The computer's house (as specified) will begin production of units and structures.,0,1,3 +4=Create Team...,-1,7,0,0,0,0,0,0,0,Creates a team of the type specified (owned by the house of this trigger). The team member are NOT automatically created however.,0,1,4 +5=Destroy Team...,-1,7,0,0,0,0,0,0,0,Destroys all instances of the team type specified. The units in those existing teams will remain and be available for recruiting into other teams.,0,1,5 +6=All to Hunt...,0,2,0,0,0,0,0,0,0,Forces all units%1 of the house specified%1 into 'hunt' mode. They will seek out and destroy their enemies.,0,1,6 +7=Reinforcement (team)...,-1,7,0,0,0,0,0,0,0,Create a reinforcement of the specified team. The members of the team WILL be created magically by this action.,0,1,7 +8=Drop Zone Flare (waypoint)...,0,30,0,0,0,0,0,0,0,Display a drop zone flair at the waypoint specified. The map will also be reaveald around that location.,0,1,8 +9=Fire Sale...,0,2,0,0,0,0,0,0,0,Cause all buildings of the specified house to be sold (for cash and prizes). Typically this is used in the final assault by the computer.,0,1,9 +10=Play Movie...,0,12,0,0,0,0,0,0,0,Displays the specified movie (full screen). The game is paused while this occurs and resumes normally after it completes.,0,1,10 +11=Text Trigger...,-4,13,0,0,0,0,0,0,0,Display the text identified by the string file <label>.,0,1,11 +12=Destroy Trigger...,-2,14,0,0,0,0,0,0,0,Destroy all current instances of the trigger type specified. This does not prevent future instances of that trigger >from being created.,0,1,12 +13=Autocreate Begins...,0,2,0,0,0,0,0,0,0,Initiates autocreate for the house specified. This will cause the computer's house to build autocreate teams as it sees fit.,0,1,13 +14=Change House...,0,2,0,0,0,0,0,0,0,Changes owning house to the one specified for attached objects.,0,1,14 +15=Allow Win,0,0,0,0,0,0,0,0,0,Removes one 'blockage' from allowing the player to win. The blockage number is equal the number of triggers created that have this action.,0,1,15 +16=Reveal all map,0,0,0,0,0,0,0,0,0,Reveals the entire map to the player.,0,1,16 +17=Reveal around waypoint...,0,30,0,0,0,0,0,0,0,Reveals a region of the map to the player around the waypoint specified.,0,1,17 +18=Reveal zone of waypoint...,0,30,0,0,0,0,0,0,0,Reveals all cells that share the same zone as the waypoing specified. This yields some wierd results. Use with caution.,0,1,18 +19=Play sound effect...,-7,16,0,0,0,0,0,0,0,Plays the sound effect specified.,0,1,19 +20=Play music theme...,-8,17,0,0,0,0,0,0,0,Plays the music theme specified.,0,1,20 +21=Play speech...,-6,18,0,0,0,0,0,0,0,Plays the speech sound specified.,0,1,21 +22=Force Trigger...,-2,14,0,0,0,0,0,0,0,Force all triggers of this specified type to spring regardless of what it's event flags may indicate.,0,1,22 +23=Timer Start,0,0,0,0,0,0,0,0,0,Start the global mission timer.,0,1,23 +24=Timer Stop,0,0,0,0,0,0,0,0,0,Stop the global mission timer.,0,1,24 +25=Timer Extend...,0,6,0,0,0,0,0,0,0,Extend the global mission timer by the time specified.,0,1,25 +26=Timer Shorten...,0,6,0,0,0,0,0,0,0,Short the global mission timer by the time specified. It can never be reduced below 'zero' time.,0,1,26 +27=Timer Set...,0,6,0,0,0,0,0,0,0,Set the global mission timer to the value specified.,0,1,27 +28=Global Set...,0,35,0,0,0,0,0,0,0,Set the global flag. Global flags are named in the file Globals.INI. Global flags can be either 'on/set/true' or 'off/clear/false'.,0,1,28 +29=Global Clear...,0,35,0,0,0,0,0,0,0,Clear the global flag. Global flags are named in the file Globals.INI. Global flags can either be 'on/set/true' or 'off/clear/false'.,0,1,29 +30=Auto Base Building...,0,37,0,0,0,0,0,0,0,Initialize the computer skirmish mode build control to either 'on' or 'off' state. When 'on'%1 the computer takes over as if it were in skirmish mode. (gs make sure he has a con yard),0,1,30 +31=Grow shroud one 'step',0,0,0,0,0,0,0,0,0,Increase the shroud darkness by one step (cell).,0,1,31 +32=Destroy attached building,0,0,0,0,0,0,0,0,0,Destroy any buildings%1 bridges%1 or units that this trigger is attached to.,0,1,32 +33=Add 1-time special weapon...,0,36,0,0,0,0,0,0,0,Add a one-shot special weapon (as indicated) to the trigger's house.,0,1,33 +34=Add repeating special weapon...,0,36,0,0,0,0,0,0,0,Add a permanent special weapon (as indicated) to the trigger's house.,0,1,34 +35=Preferred target...,0,40,0,0,0,0,0,0,0,Specify what the trigger's house should use as its preferred target when using special weapon attacks.,0,1,35 +36=All change house...,0,2,0,0,0,0,0,0,0,All objects of one house change ownership to specified house.,0,1,36 +37=Make ally...,0,2,0,0,0,0,0,0,0,Cause this trigger's house to ally with the house specified.,0,1,37 +38=Make enemy...,0,2,0,0,0,0,0,0,0,Cause this trigger's house to un-ally (declare war) with the house specified.,0,1,38 +39=Change Zoom Level...,0,6,0,0,0,0,0,0,0,Changes the zoom out level of the player's radar map. Use 1 for normal view%1 2 for zoomed out.,0,1,39 +40=Resize Player View...,0,0,21,22,23,24,0,0,0,Changes the player's viewing rectangle into the map. Enter as: x%1y%1w%1h where x%1y gives the upper left corner and w%1h give the width and height.,0,1,40 +41=Play Anim At...,0,25,0,0,0,0,1,0,0,Plays the specified anim in the specified cell.,0,1,41 +42=Do Explosion At...,0,41,0,0,0,0,1,0,0,Creates an explosion in the specified cell%1 using the specified warhead.,0,1,42 +43=Meteor Impact At...,0,29,0,0,0,0,1,0,0,Sends a meteor at the specified cell.,0,0,43 +44=Ion Storm start...,0,6,0,0,0,0,0,0,0,Starts an ion storm sequence to run for the specified number of game frames.,0,0,44 +45=Ion Storm stop...,0,0,0,0,0,0,0,0,0,End an Ion storm in progress.,0,0,45 +46=Lock input,0,0,0,0,0,0,0,0,0,Disables user input.,0,1,46 +47=Unlock input,0,0,0,0,0,0,0,0,0,Enables user input.,0,1,47 +48=Center Camera at Waypoint...,0,28,0,0,0,0,1,0,0,Moves the tactical view to a specified waypoint.,0,1,48 +49=Zoom in,0,0,0,0,0,0,0,0,0,Zooms the tactical map in.,0,1,49 +50=Zoom out,0,0,0,0,0,0,0,0,0,Zooms the tactical map out.,0,1,50 +51=Reshroud Map,0,0,0,0,0,0,0,0,0,Reshrouds the entire map.,0,1,51 +52=Change Light Behavior,0,42,0,0,0,0,0,0,0,Changes the way a building spotlight behaves. Attach this trigger to a building that casts a spotlight.,0,1,52 +53=Enable Trigger,-2,14,0,0,0,0,0,0,0,Enables the target trigger.,0,1,53 +54=Disable Trigger,-2,14,0,0,0,0,0,0,0,Disables the target trigger.,0,1,54 +55=Create Radar Event,0,43,0,0,0,0,1,0,0,Creates a radar event at the specified waypoint,0,1,55 +56=Local Set...,0,3,0,0,0,0,0,0,0,Set the local flag. Local flags can be either 'on/set/true' or 'off/clear/false'.,0,1,56 +57=Local Clear...,0,3,0,0,0,0,0,0,0,Clear the local flag. Local flags can either be 'on/set/true' or 'off/clear/false'.,0,1,57 +58=Meteor Shower At...,0,44,0,0,0,0,1,0,0,Creates a meteor shower around the specified waypoint.,0,1,58 +59=Reduce Tiberium At...,0,30,0,0,0,0,0,0,0,Reduces Tiberium around the specified waypoint.,0,0,59 +60=Sell building,0,0,0,0,0,0,0,0,0,Sells the building attached to this trigger.,0,1,60 +61=Turn off building,0,0,0,0,0,0,0,0,0,Turn off building attached to this trigger.,0,1,61 +62=Turn on building,0,0,0,0,0,0,0,0,0,Turn on building attached to this trigger.,0,1,62 +63=Apply 100 damage at...,0,30,0,0,0,0,0,0,0,Applies 100 points of HE damage at location.,0,1,63 +64=Light flash (small) at...,0,30,0,0,0,0,0,0,0,Shows a small light flash at location.,0,1,64 +65=Light flash (medium) at...,0,30,0,0,0,0,0,0,0,Shows a medium light flash at location.,0,1,65 +66=Light flash (large) at...,0,30,0,0,0,0,0,0,0,Shows a large light flash at location.,0,1,66 +67=Announce Win,0,0,0,0,0,0,0,0,0,Announce that player has won.,0,1,67 +68=Announce Lose,0,0,0,0,0,0,0,0,0,Announce that player has lost.,0,1,68 +69=Force end,0,0,0,0,0,0,0,0,0,Force end of scenario.,0,1,69 +70=Destroy Tag...,-3,38,0,0,0,0,0,0,0,Destroy tag and all attached triggers.,0,1,70 +71=Set ambient step...,0,45,0,0,0,0,0,0,0,Sets ambient light fade step value.,0,1,71 +72=Set ambient rate...,0,45,0,0,0,0,0,0,0,Sets ambient light fade rate.,0,1,72 +73=Set ambient light...,0,6,0,0,0,0,0,0,0,Fades ambient light to new lighting level.,0,1,73 +74=AI triggers begin...,0,2,0,0,0,0,0,0,0,Start AI triggers for specified house.,0,1,74 +75=AI triggers stop...,0,2,0,0,0,0,0,0,0,Stop AI triggers for specified house.,0,1,75 +76=Ratio of AI trigger teams...,0,6,0,0,0,0,0,0,0,AI percentage of teams created for AI triggers (100 = all for AI trigger teams%1 0 = all for regular teams),0,1,76 +77=Ratio of team aircraft...,0,6,0,0,0,0,0,0,0,AI percentage of aircraft created for teams (100 = all for teams%1 0 = all random),0,1,77 +78=Ratio of team infantry...,0,6,0,0,0,0,0,0,0,AI percentage of infantry created for teams (100 = all for teams%1 0 = all random),0,1,78 +79=Ratio of team units...,0,6,0,0,0,0,0,0,0,AI percentage of units created for teams (100 = all for teams%1 0 = all random),0,1,79 +80=Reinforcement (team) [at waypoint]...,-1,7,0,0,0,0,1,0,0,Create reinforcement team at special waypoint location.,0,1,80 +81=Wakeup self,0,0,0,0,0,0,0,0,0,Breaks out of sleep or harmless mode so as to enter guard mode.,0,1,81 +82=Wakeup all sleepers,0,0,0,0,0,0,0,0,0,Breaks all units out of sleep mode.,0,1,82 +83=Wakeup all harmless,0,0,0,0,0,0,0,0,0,Breaks all out of harmless mode.,0,1,83 +84=Wakeup group...,0,6,0,0,0,0,0,0,0,Wakeup all units of specified group.,0,1,84 +85=Vein growth...,0,37,0,0,0,0,0,0,0,Control if veins grow or not.,0,1,85 +86=Tiberium growth...,0,37,0,0,0,0,0,0,0,Control if Tiberium grows or not.,0,1,86 +87=Ice growth...,0,37,0,0,0,0,0,0,0,Control if ice grows or not.,0,1,87 +88=Particle Anim at...,0,26,0,0,0,0,1,0,0,Show particle animation at location.,0,1,88 +89=Remove Particle Anim at...,0,30,0,0,0,0,0,0,0,Delete particle anims at specified location.,0,1,89 +90=Lightning strike at...,0,30,0,0,0,0,0,0,0,A single Ion Storm lightning strike.,0,1,90 +91=Go Berzerk,0,0,0,0,0,0,0,0,0,Attached object (cyborg) goes berzerk.,0,1,91 +92=Activate Firestorm Defense,0,0,0,0,0,0,0,0,0,Turns on a house's firestorm defense.,0,0,92 +93=Deactivate Firestorm Defense,0,0,0,0,0,0,0,0,0,Turns off a house's firestorm defense.,0,0,93 +94=Ion-cannon strike...,0,30,0,0,0,0,0,0,0,Fires Ion-Cannon at waypoint specified.,0,0,94 +95=Nuke strike...,0,0,0,0,0,0,1,0,0,Fires Nuke at waypoint specified from nearest edge.,0,1,95 +96=Chem-missile strike...,0,30,0,0,0,0,0,0,0,Fires Chemical missile at waypoint specified.,0,0,96 +97=Toggle Train Cargo,0,0,0,0,0,0,0,0,0,Toggles state of cargo train dropping crate.,0,1,97 +98=Play Sound Effect (Random)...,-7,16,0,0,0,0,0,0,0,Plays sound effect at random waypoint.,0,1,98 +99=Play Sound Effect At...,-7,16,0,0,0,0,1,0,0,Plays sound effect specified at waypoint specified. ,0,1,99 +100=Play Ingame Movie...,0,12,0,0,0,0,0,0,0,Displays the specified movie ingame. Player still has control of interface and units.,0,1,100 +101=Reshroud Map At...,0,30,0,0,0,0,0,0,0,Does an anti-map ping at waypoint specified.,0,1,101 +102=Lightning Storm strike...,0,0,0,0,0,0,1,0,0,Lightning storm owned by owner of trigger at waypoint.,0,1,102 +103=Timer Text...,-4,13,0,0,0,0,0,0,0,What text label to display with timer (i.e. actual text is in game.str).,0,1,103 +104=Flash Team...,-5,7,0,0,0,0,0,0,0,Flashes the specified team for the specified number of frames,0,1,104 +105=Talk Bubble...,-1,7,0,0,0,0,0,0,0,Displays talk bubble over unit,0,1,105 +106=Set Tech Level (Techno)[Level]... ,-9,39,0,0,0,0,1,0,0,Sets the specified Techno to the specified tech level.,0,1,106 +107=Reinforcement by Chrono... ,-1,7,0,0,0,0,1,0,0,Teleport reinforcement team to special waypoint location.,0,1,107 +108=Create Crate...,0,31,0,0,0,0,1,0,0,Create a Goodie Crate with specific contents at a waypoint. You are responsible for knowing which contents are currently supported by the game.,0,1,108 +109=Iron Curtain At...,0,0,0,0,0,0,1,0,0,Iron Curtain Super effect at Waypoint.,0,1,109 +110=Pause Game for (seconds)...,0,6,0,0,0,0,0,0,0,This will pause the game for the specified seconds.,0,1,110 +111=Evict Occupiers,0,0,0,0,0,0,0,0,0,This Action will Evict Urban Combat occupants >from the attached Building.,0,1,111 +112=Center (Jump) Camera at Waypoint...,0,30,0,0,0,0,1,0,0,Moves the tactical view to a specified waypoint instantly.,0,1,112 +113=Make side cheer,0,2,0,0,0,0,0,0,0,Will make all infantry who aren't busy do their cheer animation.,0,1,113 +114=Set Tab to (0-3)...,0,6,0,0,0,0,0,0,0,Forces the sidebar to the desired tab.,0,1,114 +115=Flash Cameo,-9,39,0,0,0,0,1,0,0,Flashes the Cameo for this type for this long in frames.,0,1,115 +116=Stop Sounds At,0,30,0,0,0,0,1,0,0,Stops all sounds at waypoint that were started using the Play Sound At trigger,0,1,116 +117=Play Ingame Movie (pause game)...,0,12,0,0,0,0,0,0,0,Displays the specified movie ingame. Game pauses while movie playing. Player has no control during movie.,0,1,117 +118=Clear all smudges,0,0,0,0,0,0,0,0,0,Will delete all Smudge objects from the map.,0,1,118 +119=Destroy all of...,0,2,0,0,0,0,0,0,0,Kills everything of the specified house.,0,1,119 +120=Destroy all Buildings of...,0,2,0,0,0,0,0,0,0,Kills all buildings for specified house.,0,1,120 +121=Destroy all Land Units of...,0,2,0,0,0,0,0,0,0,Kills all land units for specified house.,0,1,121 +122=Destroy all Naval Units of...,0,2,0,0,0,0,0,0,0,Kills all naval units for specified house.,0,1,122 +123=Mind Control Base of...,0,2,0,0,0,0,0,0,0,The owner of the trigger will mind control the argument's base.,0,1,123 +124=Restore Mind Controlled Base to...,0,2,0,0,0,0,0,0,0,The owner of the trigger will give all buildings that were the argument's back to it.,0,1,124 +125=Create Building At...,-10,47,0,0,0,0,1,0,0,Owner of the trigger will gain this type of building at this waypoint. Overlays will be cleared and units bumped.,0,1,125 +126=Restore Starting Technos of...,0,2,0,0,0,0,0,0,0,All Buildings and units this house had at the start of the game will be recreated. Will bump units and erase Overlays.,0,1,126 +127=Chrono Screen Effect for ...,0,6,0,0,0,0,0,0,0,Will tile the screen with the full screen chrono effect for this many frames.,0,1,127 +128=Teleport All to...,0,30,0,0,0,0,1,0,0,All Units of trigger owning House will teleport to Waypoint.,0,1,128 +129=Set Superweapon Charge,-11,20,0,0,0,0,1,0,0,The owner of this trigger will have this superweapon charged to this percent%1 if they have the superweapon. Takes an int (0-100).,0,1,129 + +; YR +130=Restore Starting Buildings of...,0,2,0,0,0,0,0,0,0,All Buildings this house had at the start of the game will be healed or recreated. Will bump units and erase Overlays.,0,1,130,1 +;131=Flash Buildings of Type...,-12,8,0,0,0,0,1,0,0,All buildings of this type owned by trigger owner will flash for this long.,0,1,131,1 +131=Flash Buildings of Type...,-9,47,0,0,0,0,1,0,0,All buildings of this type owned by trigger owner will flash for this long.,0,1,131,1 +132=Superweapon Set Recharge Time,-11,20,0,0,0,0,1,0,0,Changes the time (in frames) this superweapon takes to charge the next time it is reset%1 set%1 or fired.,0,1,132,1 +133=Superweapon Reset Recharge Time,-11,20,0,0,0,0,1,0,0,Changes the time (in frames) this superweapon takes to charge back to normal.,0,1,133,1 +134=Superweapon Reset,0,36,0,0,0,0,0,0,0,Resets a superweapon like a spy had gotten in.,0,1,134,1 +135=Preferred Target Cell Set,0,30,0,0,0,0,0,0,0,The owner of this trigger will aim all future targetable superweapons at this waypoint.,0,1,135,1 +136=Preferred Target Cell Clear,0,0,0,0,0,0,0,0,0,The owner of this trigger will go back to targeting its superweapons normally.,0,1,136,1 +137=Center Base Cell Set,0,30,0,0,0,0,0,0,0,Owner of this trigger will consider the center of its base to be this waypoint.,0,1,137,1 +138=Center Base Cell Clear,0,0,0,0,0,0,0,0,0,Owner of this trigger will go back to computing its center.,0,1,138,1 +139=Blackout Radar,0,6,0,0,0,0,0,0,0,Trigger Owner will have radar blackout for this many frames.,0,1,139,1 +140=Defensive Target Cell Set,0,30,0,0,0,0,0,0,0,The owner of this trigger will aim all future force shields at this waypoint.,0,1,140,1 +141=Defensive Target Cell Clear,0,0,0,0,0,0,0,0,0,The owner of this trigger will go back to targeting its force shields normally.,0,1,141,1 +142=Retint Red,0,6,0,0,0,0,0,0,0,Retint the Red portion of the screen,0,1,142,1 +143=Retint Green,0,6,0,0,0,0,0,0,0,Retint the Green portion of the screen,0,1,143,1 +144=Retint Blue,0,6,0,0,0,0,0,0,0,Retint the Blue portion of the screen,0,1,144,1 +145=Jump camera home,0,0,0,0,0,0,0,0,0,Just like hitting the 'H' key.,0,1,145,1 + + +[BridgesTS] + +[BridgesRA2] + +[SpecialOverlayTS] + +[SpecialOverlayRA2] + +[IgnoreTerrainRA2] \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/FALanguage.ini b/MissionEditor/data/FinalAlert2/FALanguage.ini new file mode 100644 index 0000000..10bb38e --- /dev/null +++ b/MissionEditor/data/FinalAlert2/FALanguage.ini @@ -0,0 +1,994 @@ +; ******************************* +; FALanguage.ini +; +; String file of FinalAlert 2 +; Last change: MW 10.4.2001 +; ******************************* + +; The languages available in FinalAlert 2 +[Languages] +0=English +1=German + + +; Every language has a own header section, defining the name of the language as it is called in that language, +; the version of the language data, and the file extension used for this language +; Note that the "Name" must be unique (so, "Name" of English must not be the same like "Name" of German)! + +[EnglishHeader] +Name=English +Version=1 +ExtensionName=ENG + +[GermanHeader] +Name=Deutsch +Version=1 +ExtensionName=DEU + +[SwedishHeader] +Name=Svenska +Version=1 +ExtensionName=SWE + +[NederlandsHeader] +Name=Nederlands +Version=1 +ExtensionName=NL + +; Now all the strings for each language +; If a specific string is not found in a language, the english string will be used. +; %9 is translated to FinalSun or FinalAlert 2 + +[German-StringsRA2] +Err_TSNotInstalled=C&C Alarmstufe Rot 2 ist nicht korrekt installiert (TibSun.mix konnte nicht geladen werden) +FileRunTiberianSunHelp=C&C Alarmstufe Rot 2 starten +;SAVEDLG_FILETYPES=AR2 Karten|*.mpr%8*.map|AR2 Mehrspielerkarten-Erweiterungen (*.mmx)|*.mmx|AR2 Mehrspielerkarten (*.mpr)|*.mpr|AR2 Einzelspielerkarten (*.map)|*.map| +SAVEDLG_FILETYPES_YR=Alle Karten|*.mpr%8*.yrm%8*.map%8*.mmx|Mehrspielerkarten Yuri's Rache|*.yrm|Mehrspielerkarten Red Alert 2|*.mpr%8*.mmx|Einzelspielerkarten|*.map| +GrTibObList=Erz und Kristalle +BlTibObList=Kristalle +DrawTibObList=Erz zeichnen +DrawTib2ObList=Kristalle zeichnen +GroundSandObListURB=Helles Pflaster +GroundRoughObListURB=Erde +GroundGreenObListURB=Gras +GroundPaveObListURB=Dunkles Pflaster +GroundClearObListTEM=Helles Gras +GroundRoughObListTEM=Dunkles Gras +GroundGreenObListTEM=Sand +GroundClearObListSNO=Schnee +GroundSandObListSNO=Verschmutzter Schnee +GroundRoughObListSNO=Gras +GroundGreenObListSNO=Eis +SAVEDLG_FILETYPES=AR2-Karten|*.mpr%8*.map%8*.mmx|AR2 Mehrspielerkarten|*.mpr|AR2 Einzelspielerkarten|*.map|AR2 Mehrspielerkarten-Erweiterungen|*.mmx| +Allied=Allierte +Soviet=Sowjets +Other=Andere +BasicTiberiumGrowthEnabled=Erz wachsend: +SingleplayerFillSilos=Raffinerien fĂ¼llen: + +[German-Strings] +; messages for message boxes +Err_InsufficientResources=Aufgrund ungenĂ¼gender Ressourcen konnte zumindest ein Dialog nicht erstellt werden. Sie sollten deswegen Windows komplett neu starten. Das Programm wird jetzt beendet... Tip: Beenden Sie alle Programme, bevor Sie %9 starten +Err_TSNotInstalled=Tiberian Sun ist nicht korrekt installiert (TibSun.mix konnte nicht geladen werden) +Err_CreateErr=Fenster konnte nicht erstellt werden. Versuchen Sie, andere Fenster zu schliessen. +MainDialogExitQuestion=Sind Sie sicher, dass Sie das Programm beenden wollen? Ă„nderungen an der Karte gehen dabei verloren! +MainDialogExitQuestionCap=%9 beenden +AttachMapToShell=Dateien mit der Endung mpr und/oder map sind momentan mit einem anderen Programm verbunden. Wollen Sie, dass bei einem Doppelklick auf diese Dateien %9 diese Dateien öffnet? +AddHouse=Bitte geben Sie die ID des neuen Hauses an (wie GDI und Nod): +AddHouseCap=Neues Haus +DeleteHouse=Sind Sie sicher, dass Sie das Haus %1 löschen wollen? +DeleteHouseCap=Haus löschen +RestartNeeded=Um die Ă„nderungen komplett zu Ă¼bernehmen, ist ein Neustart von %9 erforderlich. +ReInitPic=Es ist nötig, die Grafiken neu zu laden. Dies kann einige Zeit dauern, bitte Geduld. +ReInitPicCap=Neuladen der Grafiken +StrChangeHeight=Geben Sie den Höhenunterschied an, um den jedes Feld auf der Karte verschoben wird. Der Wert muss zwischen %1 und %2 liegen. +StrChangeHeightCap=Höhe ändern +StrChangeHeightErr=Fehler, durch diese Ă„nderung wĂ¼rde die Karte falsch dargestellt! +StrChangeHeightErrCap=Fehler +ExplainEasyView=%9 startet automatisch im Anfänger-Modus. Dabei sind einige Optionen nicht verfĂ¼gbar, die im Profi-Modus unterstĂ¼tzt werden. Um in den Profi-Modus zu wechseln, deaktivieren Sie die Option "Anfängermodus" im MenĂ¼ Optionen +ExplainEasyViewCap=Anfänger-Modus +FileSaved=Karte "%1" gespeichert + +; general strings +OK=OK +Cancel=Abbrechen +None=Keiner +Yes=Ja +No=Nein + +; name replacements +N_SENGINEER=Sowjetischer Ingenieur +N_ENGINEER=Allierter Ingenieur +N_YENGINEER=Yuri Ingenieur +N_SCHD=Gelandeter Siege Helikopter +N_GACSPH=Chronosphäre + +; saving dialog +SAVEDLG_FILETYPES=TS Karten|*.mpr%8*.map|TS Mehrspielerkarten|*.mpr|TS Einzelspielerkarten|*.map| + +; tool tip strings +TT_TriggerHouse=Bestimmt das Haus, fĂ¼r das der Auslöser ausgefĂ¼hrt wird + +; error strings for map validation +MV_NoMap=Dies ist keine Karte +MV_NoBasic=Generelle Einstellungen sind nicht vorhanden +MV_NoName=Die Karte hat keinen Namen (Bearbeiten->Generell) +MV_PackMissing=Ein oder mehrere Packs (wie IsoMapPack5, OverlayPack, etc.) fehlen. Tiberian Sun akzeptiert die Karte möglicherweise nicht. +MV_>100Waypoint=Die Karte hat mindestens einen Wegpunkt mit einer ID grĂ¶ĂŸer als 99 +MV_HousesButNoPlayer=Es sind Häuser definiert, jedoch wurde der menschliche Spieler nicht korrekt gesetzt +MV_HousesInMultiplayer=Dies scheint eine Mehrspielerkarte zu sein, auf der Häuser definiert sind +MV_HousesNoWaypoints=Multiplayerkarten benötigen die Wegpunkte 0-7 als Startposition +MV_TriggerMissing=Trigger %1 fehlt (Verweis von %2 %3) +MV_TaskForceMissing=Taskforce %1 fehlt (Verweis von Teamtype %2) +MV_ScripttypeMissing=Scripttype %1 fehlt (Verweis von Teamtype %2) +MV_TagMissing=Tag %1 fehlt (Verweis von %2 %3) +MV_OfficialYes=Offizielle Karte - automatischer Kartentransfer abgeschaltet (Bei Speicherung als MMX Datei ignorieren) +MV_Not8Waypoints=Nur bei AR2 Version vor 1.005: Offiziell ist auf Nein gesetzt, aber die Wegpunkte 0-7 sind nicht alle vorhanden (teilweise zufällige Startpunkte, bei Speicherung als MMX Datei ignorieren) +MV_TubeCounterpartMissing=Die Tunnelröhre %5 (%1, %2) -> (%3, %4) hat kein GegenstĂ¼ck (%3, %4) -> (%1, %2).\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nDas GegenstĂ¼ck muss nicht dem gleichen Pfad folgen, aber die Start- und Endkoordinaten mĂ¼ssen umgedreht sein. +MV_TubeStartNotUnique=Die Tunnelröhre %5 (%1, %2) -> (%3, %4) hat dieselben Anfangskoordinaten wie %6 andere Tunnelröhren.\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nNur eine Tunnelröhre darf in einer Zelle anfangen. +MV_TubeEndNotUnique=Die Tunnelröhre %5 (%1, %2) -> (%3, %4) hat dieselben Endkoordinaten wie %6 andere Tunnelröhren.\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nNur eine Tunnelröhre darf in einer Zelle enden. +MV_TubeInvalidCounterpartEnd=Zur Tunnelröhre %5 (%1, %2) -> (%3, %4) gibt es %6 andere Tunnelröhren die die Startkoordinaten dieser Röhre als Endkoordinaten haben, aber die Endkoordinaten dieser Röhre entsprechen nicht den Startkoordinaten der anderen Röhren.\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nEin GegenstĂ¼ck einer Tunnelröhre muss sowohl Start- als auch Endkoordinaten umgedreht haben. +MV_TubeInvalidCounterpartStart=Zur Tunnelröhre %5 (%1, %2) -> (%3, %4) gibt es %6 andere Tunnelröhren die die Endkoordinaten dieser Röhre als Startkoordinaten haben, aber die Startkoordinaten dieser Röhre entsprechen nicht den Endkoordinaten der anderen Röhren.\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nEin GegenstĂ¼ck einer Tunnelröhre muss sowohl Start- als auch Endkoordinaten umgedreht haben. + +; tip dialog +CG_IDS_DIDYOUKNOW=Wussten Sie bereits.... +CG_IDS_FILE_ABSENT=Tips-Datei nicht gefunden +CG_IDP_FILE_CORRUPT=Syntax-Fehler in der Tips-Datei +TipDialogNext=Nächster Tip +TipDialogShowAtStartup=Tips beim Starten anzeigen +TipDialogClose=Schliessen +TipDialogCaption=Tip des Tages + + +; main dialog strings +MainDialogCaption=%9 +NoMapLoaded=keine Karte geladen +NewMap=Neue Karte +FileNewHelp=Assistenten zum Erstellen einer neuen Karte starten +FileOpenHelp=Ă–ffen einer bereits bestehenden Karte +FileSaveHelp=Speichern der Karte +FileSaveAsHelp=Speichern der Karte unter einem anderen Dateinamen +FileImportModHelp=Importieren eines *.rul - Mods in die Karte +FileCheckMapHelp=ĂœberprĂ¼fen der Karte auf mögliche Fehler +FileQuitHelp=%9 beenden +FileRunTiberianSunHelp=C&C 3 Tiberian Sun starten +HelpInfoHelp=Informationen Ă¼ber %9 anzeigen +HelpTipOfTheDayHelp=Tip des Tages anzeigen +OptionsShowMapViewHelp=Isometrische Kartenansicht zeigen + + +; new map dialog +NewMapDesc=Momentan mĂ¼ssen Sie noch eine Karte angeben, von der das Kartenpaket, also der Boden, Ă¼bernommen wird. +NewMapBrowse=Durchsuchen +NewMapMultiplayer=Mehrspieler-Karte +NewMapPrepareStandardHouses=Standard-Häuser erstellen +NewMapSetAutoProduction=Auslöser fĂ¼r Auto-Produktion hinzufĂ¼gen +NewMapPlayerHouse=Spieler-Haus +NewMapImportOptions=Optionen fĂ¼r Ăœbernehmen +NewMapImportTrees=Bäume Ă¼bernehmen +NewMapImportOverlay=Ăœberlagerung Ă¼bernehmen +NewMapImportUnits=Einheiten und Gebäude Ă¼bernehmen +NewMapCap=Assistent fĂ¼r neue Karte + +; map-validator dialog +MapValidatorProblemsFound=Folgende möglichen Probleme wurden gefunden: +MapValidatorCap=Karte Ă¼berprĂ¼fen + +; loading dialog +LoadLoadRules=Lade Gesetze +LoadLoadAI=Lade KI-Einstellungen +LoadLoadArt=Lade Kunst +LoadLoadTutorial=Lade Tutorial.ini +LoadLoadSound=Lade Sounds +LoadLoadSnow=Lade Temperat.ini +LoadLoadTemperat=Lade Snow.ini +LoadLoadUrban=Lade Urban.ini +LoadLoading=Laden +LoadBuiltBy=Erstellt von: +LoadVersion=Version: +LoadInitDDraw=Initialisiere Direct Draw 6 +LoadInitPics=Lade Grafiken +LoadExtractStdMixFiles=Ă–ffnen der Standard-MIX-Dateien (kann etwas dauern) + +; basic dialog +BasicDesc=Achtung: Einige Einstellungen werden möglicherweise ignoriert. +BasicName=Name: +BasicNextScenario=Nächstes Szenario: +BasicAltNextScenario=Alt. nächstes Szenario: +BasicNewIniFormat=Neues INI-Format: +BasicCarryOverCap=CarryOverCap ?: +BasicEndOfGame=Ende des Spiels: +BasicSkipScore=Statistik auslassen: +BasicOneTimeOnly=Nur einmal: +BasicSkipMapSelect=Kartenauswahl auslassen: +BasicOfficial=Offiziell: +BasicIgnoreGlobalAITriggers=Ignorieren der allgemeinen KI-Auslöser: +BasicTruckCrate=Kiste bei zerstörtem Lastwagen: +BasicTrainCrate=Kiste bei zerstörtem Zug: +BasicPercent=Prozent GeldĂ¼bernahme: +BasicMultiplayerOnly=Nur Mehrspieler: +BasicTiberiumGrowthEnabled=Wachsendes Tiberium: +BasicVeinGrowthEnabled=Wachsende Venen: +BasicIceGrowthEnabled=Wachsendes Eis: +BasicTiberiumDeathToVisceroid=Visceroid bei Tod in Tiberium: +BasicFreeRadar=Kostenloses Radar: +BasicInitTime=Anfangszeit: +BasicAddOnNeeded=Benötigtes Zusatzpaket: + +; mapinfo dialog +MapDesc=GrĂ¶ĂŸeneinstellungen der Karte: +MapSizeFrame=Kartengrösse +MapSize=Die Gesamtgrösse der Karte. +MapVisibleSizeFrame=Sichtbarer Bereich +MapVisibleSize=Sichtbarer Bereich der Karte. Format: Links, Oben, Breite, Höhe. +MapTheater=Klima: + +; singleplayer basics dialog +SingleplayerDesc=Weitere Einstellungen bezĂ¼glich einer Einzelspieler-Karte. +SingleplayerStartingDropships=Landetransporter am Anfang: +SingleplayerCarryOverMoney=GeldĂ¼bernahme: +SingleplayerTimerInherit=ZeitĂ¼bernahme: +SingleplayerFillSilos=Silos fĂ¼llen: +SingleplayerMovies=Videos +SingleplayerIntro=Intro: +SingleplayerBrief=Besprechung: +SingleplayerWin=Sieg: +SingleplayerLose=Niederlage: +SingleplayerAction=Aktion: +SingleplayerPostScore=Nach Punktebildschirm: +SingleplayerPreMapSelect=Vor Kartenauswahl: + +; houses dialog +HousesDesc=Häuser sind die verschiedenen Spieler, ob Mensch oder KI, in einer Karte. Erstellen Sie in einer Mehrspieler-Karte hier keine neuen Häuser! Falls dies eine Einzelspieler-Karte ist und noch keine Häuser existieren, klicken Sie zuerst auf "Standardhäuser", erstellen Sie eventuelle zusätzliche Häuser, und wählen Sie dann den menschlichen Spieler aus (vergessen Sie nicht, Spieler-Kontrolle ebenfalls zu aktivieren)! +HousesPlayerHouse=Haus des menschl. Spielers: +HousesHouse=Gewähltes Haus: +HousesIQ=Intelligenz: +HousesEdge=Kartenkante: +HousesSide=Seite: +HousesColor=Farbe: +HousesAllies=VerbĂ¼ndete: +HousesAlliesHelp=Alle verbĂ¼ndeten Häuser, durch Kommas ohne Leerzeichen getrennt, aneinanderreichen. +HousesCredits=Geld (x100): +HousesActsLike=Verhält sich wie +HousesNodeCount=Knotenpunkt- Anzahl: +HousesTechlevel=Technologiestufe: +HousesBuildActivity=Bau-Aktivität (%): +HousesPlayerControl=Spielerkontrolle: +HousesPrepareHouses=Standardhäuser +HousesAddHouse=Neues Haus +HousesDeleteHouse=Haus löschen + +; iso view +IsoCaption=Kartenansicht + +; iso view status bar +StructStatus=Gebäude: +InfStatus=Infantrie: +AirStatus=Flugzeug: +UnitStatus=Fahrzeug: +OvrlStatus=Ăœberlagerung: +OvrlDataStatus=Ăœberlagerungs-Daten: +CellTagStatus=Feld-Tag: +TilePlaceStatus=Strg: FĂ¼llen-Modus, Shift: beständiges Zeichnen, Strg+Shift: Zeichnen ohne auto. LAT oder KĂ¼ste + +; iso view object list +GroundObList=Boden +GroundClearObList=Standard-Bodentyp +GroundSandObList=Bodentyp 1 +GroundRoughObList=Bodentyp 2 +GroundGreenObList=Bodentyp 3 +GroundPaveObList=Pflaster +GroundWaterObList=Wasser +NothingObList=Nichts +TunnelObList=Tunnels +NewTunnelObList=Tunnel platzieren (bidirektional) +ModifyTunnelObList=Tunnel verändern (bidirektional) +NewTunnelSingleObList=Tunnel platzieren (unidirektional) +ModifyTunnelSingleObList=Tunnel verändern (unidirektional) +DelTunnelObList=Tunnel löschen +InfantryObList=Infantrie +VehiclesObList=Fahrzeuge +AircraftObList=Flugzeuge +StructuresObList=Gebäude +TerrainObList=Landschaftsobjekte +TreesObList=Bäume +TrafficLightsObList=Ampeln +SignsObList=Schilder +LightPostsObList=Lampen +RndTreeObList=Zufälligen Wald zeichnen +OverlayObList=Spezial / Ăœberlagerung +DelOvrlObList=Ăœberlagerung entfernen +DelOvrl0ObList=Einzelnes Feld entfernen +DelOvrl1ObList=Im Radius von 1 Feld entfernen +DelOvrl2ObList=Im Radius von 2 Feldern entfernen +DelOvrl3ObList=Im Radius von 3 Feldern entfernen +GrTibObList=GrĂ¼nes Tiberium +BlTibObList=Blaues Tiberium +DrawRanTibObList=Zufälliges Tiberium-Feld zeichnen +DrawTibObList=Tiberium zeichnen +DrawTib2ObList=Blaues Tiberium zeichnen +IncTibSizeObList=Tiberiumstärke erhöhen +DecTibSizeObList=Tiberiumstärke erniedrigen +VeinholeObList=Tiberium-Monster +VeinsObList=Venen +BridgesObList=BrĂ¼cken +BigBridgeObList=Grosse BrĂ¼cke (oberhalb des Bodens) +SmallBridgeObList=Kleine BrĂ¼cke (am Boden) +BigTrackBridgeObList=Grosse EisenbahnbrĂ¼cke (oberhalb des Bodens) +OthObList=Anderes +AllObList=Alles +OvrlManuallyObList=Ăœberlagerung manuell setzen (nicht empfohlen) +OvrlDataManuallyObList=Ăœberlagerungsdaten manuell setzen (nicht empfohlen) +WaypointsObList=Wegpunkte +CreateWaypObList=Wegpunkt erstellen +CreateSpecWaypObList=Wegpunkt mit spezieller Nummer erstellen +DelWaypObList=Wegpunkt entfernen +StartpointsObList=Startpunkte +StartpointsPlayerObList=Spieler %1 +StartpointsDelete=Startpunkt löschen +CelltagsObList=Feld-Tags +CreateCelltagObList=Feld-Tag erstellen +DelCelltagObList=Feld-Tag entfernen +CelltagPropObList=Feld-Tag Eigenschaften ändern +BaseNodesObList=Basis-Knotenpunkte +CreateNodeNoDelObList=Knotenpunkt erstellen und Gebäude nicht löschen +CreateNodeDelObList=Knotenpunkt erstellen und Gebäude löschen +DelNodeObList=Knotenpunkt löschen +DelObjObList=Objekte löschen +ChangeOwnerObList=Besitzer wechseln + +; celltag dialog +CellTagCap=Feld-Tag +CellTagDesc=Benutzen Sie einen Feld-Tag, um ein Feld mit einem Tag zu verbinden. +CellTagTag=Zugeordneter Tag: + +; aircraft dialog +AirCap=Lufteinheit-Einstellungen +AirDesc= +AirHouse=Besitzer +AirStrength=Stärke: +AirState=Status: +AirDirection=Richtung: +AirTag=Zugeordneter Tag: +AirP1=Veteranen- status: +AirP2=Gruppe: +AirP3=Rekrutierbar: +AirP4=KI rekrutierbar: + +; structure dialog +StructCap=Gebäude-Einstellungen +StructDesc=Um Erweiterungen fĂ¼r das Gebäude hinzuzufĂ¼gen, erst die Anzahl an Erweiterungen angeben und dann die Erweiterungen, beginnend mit Erweiterung 1, setzen. +StructHouse=Besitzer +StructStrength=Stärke: +StructDirection=Richtung: +StructTag=Zugeordneter Tag: +StructP1=Sellable +StructAIRepairs=Neu bauen:;faaaallllsch!!!! +StructEnergy=Strom- versorgung: +StructUpgradeCount=Erweiterungs- Anzahl: +StructSpotlight=Schein- werfer: +StructUpgrade1=Erweiterung 1: +StructUpgrade2=Erweiterung 2: +StructUpgrade3=Erweiterung 3: +StructP2=AI repariert: +StructP3=Namensanzeige: + +; unit dialog +UnitCap=Fahrzeug +UnitDesc= +UnitHouse=Besitzer: +UnitStrength=Stärke: +UnitState=Status: +UnitDirection=Richtung: +UnitTag=Zugeordneter Tag: +UnitP1=Veteranen- status: +UnitP2=Gruppe: +UnitP3=Auf BrĂ¼cke: +UnitP4=Folge ID: +UnitP5=Rekrutierbar: +UnitP6=KI rekrutierbar: + +; infantry dialog +InfCap=Infantrie-Einstellungen +InfDesc= +InfHouse=Besitzer +InfStrength=Stärke: +InfPos=Feldposition: +InfState=Status: +InfDirection=Richtung: +InfTag=Zugeordneter Tag: +InfP1=Veteranenstatus: +InfP2=Gruppe: +InfP3=Auf BrĂ¼cke: +InfP4=Rekrutierbar: +InfP5=KI rekrutierbar: + +[English-StringsRA2] +GrTibObList=Ore and Gems +BlTibObList=Gems +DrawRanTibObList=Paint random field +DrawTibObList=Paint Ore +DrawTib2ObList=Paint Gems +IncTibSizeObList=Increase size +DecTibSizeObList=Decrease size +FileRunTiberianSunHelp=Launch C&C Red Alert 2 +Err_TSNotInstalled=Red Alert 2 is not correctly installed (ra2.mix could not be loaded) +GroundSandObListURB=Bright pavement +GroundRoughObListURB=Soil +GroundGreenObListURB=Grass +GroundPaveObListURB=Dark pavement +GroundClearObListTEM=Bright grass +GroundRoughObListTEM=Dark grass +GroundGreenObListTEM=Sand +GroundClearObListSNO=Snow +GroundSandObListSNO=Dirty snow +GroundRoughObListSNO=Grass +GroundGreenObListSNO=Ice +GroundRoughObListUBN=Dark grass +GroundGreenObListUBN=Sand +GroundPave2ObListUBN=Urban pavement +;SAVEDLG_FILETYPES=RA2 maps|*.mpr%8*.map%8*.mmx|RA2 multi maps|*.mpr|RA2 single maps|*.map|RA2 multiplayer map extensions|*.mmx| +;SAVEDLG_FILETYPES=RA2 maps|*.mpr%8*.map%8*.mmx|RA2 multiplayer map extension (*.mmx)|*.mmx|RA2 multiplayer map (*.mpr)|*.mpr|RA2 singleplayer map (*.map)|*.map| +;SAVEDLG_FILETYPES_YR=RA2 maps|*.mpr%8*.yrm%8*.map%8*.mmx|RA2 multiplayer map extension (*.mmx)|*.mmx|RA2 multiplayer map (*.mpr)|*.mpr|RA2:YR multiplayer map (*.yrm)|*.yrm|RA2 singleplayer map (*.map)|*.map| +SAVEDLG_FILETYPES_YR=All maps|*.mpr%8*.yrm%8*.map%8*.mmx|Yuri's Revenge Multiplayer maps|*.yrm|RA2 Multiplayer maps|*.mpr%8*.mmx|Singleplayer maps|*.map| +SAVEDLG_FILETYPES=RA2 maps|*.mpr%8*.map%8*.mmx|RA2 multiplayer maps|*.mpr%8*.mmx|RA2 singleplayer maps|*.map| +BigTrackBridgeObList=High wood bridge +Allied=Allied +Soviet=Soviet +Yuri=Yuri +Other=Other +BasicTiberiumGrowthEnabled=Growing Ore: +SingleplayerFillSilos=Fill refineries: + +[English-Strings] +; messages for message boxes +Err_InsufficientResources=Because of insufficient resources at least one dialog wasn´t created. You should restart Windows. The program will now quit... Tip: You should quit any programs before you start %9. Also, restarting Windows may help. +Err_TSNotInstalled=Tiberian Sun is not correctly installed (TibSun.mix could not be loaded) +Err_CreateErr=Window could not be created. You should try to close other windows first. +MainDialogExitQuestion=Are you sure that you want to quit the program? Changes will not be saved! +MainDialogExitQuestionCap=Quit %9 +AttachMapToShell=.map and/or .mpr files are currently attached to another program. Do you want that %9 opens all .map and .mpr files when you double click on them? +AddHouse=Please set the ID of the house (like GDI or Nod): +AddHouseCap=Add House +DeleteHouse=Are you sure that you want to delete the house %1? +DeleteHouseCap=Delete house +RestartNeeded=To apply all changes, you need to restart %9 +ReInitPic=The graphics must be reloaded. This may take some time, please be patient. +ReInitPicCap=Reloading graphics +StrChangeHeight=Enter the height difference that is applied to every field. The value must be between %1 and %2 +StrChangeHeightCap=Change height +StrChangeHeightErr=Cannot change map height, as this exceeds the height limits. +StrChangeHeightErrCap=Error +ExplainEasyView=%9 automatically starts in beginner mode. Some advanced editing features are not available in this mode, although they are supported in the advanced mode. To activate the advanced mode, disable the option "Beginner mode" in the options menu. +ExplainEasyViewCap=Beginner mode +FileSaved=Map saved as "%1" + +; general strings +OK=OK +Cancel=Cancel +None=None +Yes=Yes +No=No + +; YRM +NeedsYR=This map will need Yuri's Revenge to be played. + +; name replacements +N_AMRADR=American Air Force Command HQ +N_SENGINEER=Soviet Engineer +N_ENGINEER=Allied Engineer +N_YENGINEER=Yuri Engineer +N_SCHD=Deployed Siege Helicopter +N_GACSPH=Chronosphere +N_CALOND04=London Parliament +N_CALOND05=London Big Ben +N_CATRAN03=Trans Fortress + +; saving dialog +SAVEDLG_FILETYPES=TS maps|*.mpr%8*.map|TS multi maps|*.mpr|TS single maps|*.map| + +; tool tip strings +TT_TriggerHouse=Defines the house the trigger applies to + +; error strings for map validation +MV_NoMap=This is no map +MV_NoBasic=Basic settings don´t exist +MV_NoName=The map has no name (Edit->Basic) +MV_PackMissing=One or more packs (like IsoMapPack5 or OverlayPack) are missing. Tiberian Sun probably won´t accept the map. +MV_>100Waypoint=The map has at least one waypoint with an ID greater than 99 +MV_HousesButNoPlayer=Houses are defined, but the human player is not set up correctly +MV_HousesInMultiplayer=This seems to be a multiplayer map with houses +MV_HousesNoWaypoints=Multiplayermaps need the waypoints 0-7 as starting locations +MV_TriggerMissing=Trigger %1 missing (Linked by %2 %3) +MV_TaskForceMissing=Taskforce %1 missing (Linked by Teamtype %2) +MV_ScripttypeMissing=Scripttype %1 missing (Linked by Teamtype %2) +MV_TagMissing=Tag %1 missing (Linked by %2 %3) +MV_OfficialYes=Official is set to yes - automatic map transfer disabled (ignore this warning when saving as MMX map) +MV_Not8Waypoints=Only for RA2 before version 1.005: Official is set to no, but not all waypoints 0-7 do exist (probably random starting points, ignore this warning when saving as MMX map) +MV_TubeCounterpartMissing=The tunnel tube %5 (%1, %2) -> (%3, %4) has no counterpart that leads from (%3, %4) -> (%1, %2).\nThis will lead to unpredictable errors and crashes in the game.\nThe counterpart does not have to have the same path, but it must have opposite start and end cells. +MV_TubeStartNotUnique=The tunnel tube %5 (%1, %2) -> (%3, %4) has the same start coordinates as %6 other tunnel tubes.\nThis will lead to unpredictable errors and crashes in the game.\nThere may only be one tube starting at each cell. +MV_TubeEndNotUnique=The tunnel tube %5 (%1, %2) -> (%3, %4) has the same end coordinates as %6 other tunnel tubes.\nThis will lead to unpredictable errors and crashes in the game.\nThere may only be one tube starting at each cell. +MV_TubeInvalidCounterpartEnd=The tunnel tube %5 (%1, %2) -> (%3, %4) has %6 other tunnel tubes that have this tube's start location as their end location, but this tube's end location does not match their start location.\nThis will lead to unpredictable errors and crashes in the game.\nA counterpart must have both the start and end coordinates reversed. +MV_TubeInvalidCounterpartStart=The tunnel tube %5 (%1, %2) -> (%3, %4) has %6 other tunnel tubes that have this tube's end location as their start location, but this tube's start location does not match their end location.\nThis will lead to unpredictable errors and crashes in the game.\nA counterpart must have both the start and end coordinates reversed. + +; tip dialog +CG_IDS_DIDYOUKNOW=Did you know... +CG_IDS_FILE_ABSENT=Tips file not found +CG_IDP_FILE_CORRUPT=Syntax error in the tips file +TipDialogNext=Next tip +TipDialogShowAtStartup=Show tips at program start +TipDialogClose=Close +TipDialogCaption=Tip of the day + +; main dialog strings +MainDialogCaption=%9 +MainDialogCaptionRA2=%9 +NoMapLoaded=No map loaded +NewMap=New map +FileNewHelp=Start new map assistant +FileOpenHelp=Open a already existing map +FileSaveHelp=Save map +FileSaveAsHelp=Save map with another filename +FileCheckMapHelp=Check the map for possible errors +FileImportModHelp=Import a *.rul - Mod in the map +FileQuitHelp=Quit %9 +FileRunTiberianSunHelp=Launch C&C 2 Tiberian Sun +HelpInfoHelp=Show information about %9 +HelpTipOfTheDayHelp=Show Tip of the Day +OptionsShowMapViewHelp=Show the isometric map view +TabBasic=Basic +TabSingleplayerSettings=Additional +TabMap=Map +TabLighting=Lighting +TabSpecial=Special +TabHouses=Houses +TabTaskForces=Task forces +TabScriptTypes=Scripts +TabTeamTypes=Team types +TabTriggers=Trigger +TabTags=Tags +TabAITriggers=AI Trigger +TabAITriggerEnable=Enable AI Trigger +TabOther=All + +; new map dialog +NewMapDesc=At the moment you need to specify a map that provides the mappack information needed for the ground +NewMapBrowse=Browse +NewMapMultiplayer=Multiplayer map +NewMapPrepareStandardHouses=Prepare standard houses +NewMapSetAutoProduction=Add Auto-Production triggers +NewMapPlayerHouse=Player house +NewMapImportOptions=Import options +NewMapImportTrees=Import trees +NewMapImportOverlay=Import overlay +NewMapImportUnits=Import units +NewMapCap=Assistant for new map + +; map-validator dialog +MapValidatorProblemsFound=The following possible problems have been found: +MapValidatorCap=Check map + +; basic dialog +BasicDesc=Note: Some settings may be ignored. +BasicName=Name: +BasicNextScenario=Next scenario: +BasicAltNextScenario=Alt. next scenario: +BasicNewIniFormat=New INI format: +BasicCarryOverCap=CarryOverCap ?: +BasicEndOfGame=End of game: +BasicSkipScore=Skip score stats: +BasicOneTimeOnly=One time only: +BasicSkipMapSelect=Skip map selection: +BasicOfficial=Official: +BasicIgnoreGlobalAITriggers=Ignore global AI Triggers: +BasicTruckCrate=Crate for destroyed trucks: +BasicTrainCrate=Crate for destroyed trains: +BasicPercent=Percent (money?): +BasicMultiplayerOnly=Only Multiplayer: +BasicTiberiumGrowthEnabled=Growing tiberium: +BasicVeinGrowthEnabled=Growing veins: +BasicIceGrowthEnabled=Growing ice: +BasicTiberiumDeathToVisceroid=Visceroid because of death in tiberium: +BasicFreeRadar=Free radar: +BasicInitTime=Initial time: +BasicAddOnNeeded=Addon needed: + +; mapinfo dialog +MapDesc=General map properties: +MapSizeFrame=Map size +MapSize=Size of the whole map, used for MapPack. +MapVisibleSizeFrame=Visible area +MapVisibleSize=Visible area of the map. Format: Left, Top, Width, Height. +MapTheater=Theater: + +; singleplayer basics dialog +SingleplayerDesc=Additional settings regarding a singleplayer map. +SingleplayerStartingDropships=Dropships at start: +SingleplayerCarryOverMoney=Inherit money: +SingleplayerTimerInherit=Inherit timer: +SingleplayerFillSilos=Fill silos: +SingleplayerMovies=Movies +SingleplayerIntro=Intro: +SingleplayerBrief=Briefing: +SingleplayerWin=Won: +SingleplayerLose=Lost: +SingleplayerAction=Action: +SingleplayerPostScore=After score screen: +SingleplayerPreMapSelect=Pre map select screen: + +; houses dialog +HousesDesc=Houses are the different players, AI and humans. If this is a multiplayer map, don´t create any new houses here! If this is a singleplayer map and if there are no houses yet, click on "Standard houses" first, create your additional houses if you need some, and then choose the human player (don´t forget to activate "Player control" for this house)! +HousesPlayerHouse=House of human player: +HousesHouse=Current house: +HousesIQ=IQ: +HousesEdge=Map edge: +HousesSide=Side: +HousesColor=Color: +HousesAllies=Allies: +HousesAlliesHelp=List all allied houses like that: GDI,Nod,Neutral +HousesCredits=Money (x100): +HousesActsLike=Acts like +HousesNodeCount=Node count: +HousesTechlevel=Technology level: +HousesBuildActivity=Build activity (%): +HousesPlayerControl=Player control: +HousesPrepareHouses=Standard houses +HousesAddHouse=New house +HousesDeleteHouse=Delete house + +; loading dialog +LoadLoadRules=Loading rules +LoadLoadAI=Loading AI settings +LoadLoadArt=Loading art +LoadLoadEva=Loading speeches +LoadLoadTheme=Loading themes +LoadLoadTutorial=Loading tutorial.ini +LoadLoadSound=Loading sounds +LoadLoadSnow=Loading Temperat.ini +LoadLoadTemperat=Loading Snow.ini +LoadLoadUrban=Loading Urban.ini +LoadLoading=Loading +LoadBuiltBy=Built by: +LoadVersion=Version: +LoadInitDDraw=Initializing Direct Draw 6 +LoadInitPics=Loading Graphics +LoadExtractStdMixFiles=Opening std. MIX files (may take some time) + +; iso view +IsoCaption=Map view + +; iso view status bar +StructStatus=Structure: +InfStatus=Infantry: +AirStatus=Aircraft: +UnitStatus=Vehicle: +OvrlStatus=Overlay: +OvrlDataStatus=Overlay-Data: +CellTagStatus=CellTag: +TilePlaceStatus=Ctrl: Fill mode, Shift: continuous drawing, Ctrl+Shift: no auto smoothing of LAT or coast/shore +CopyHelp=Please specify the area that you want to be copied by clicking on the start and end position + +; iso view object/unit list +NothingObList=Nothing +GroundObList=Ground +GroundClearObList=Clear +GroundSandObList=Ground 1 +GroundRoughObList=Ground 2 +GroundGreenObList=Ground 3 +GroundPaveObList=Pavement +GroundWaterObList=Water +NewTunnelObList=Create tunnel (bidirectional) +ModifyTunnelObList=Modify tunnel (bidirectional) +NewTunnelSingleObList=Create tunnel (unidirectional) +ModifyTunnelSingleObList=Modify tunnel (unidirectional) +DelTunnelObList=Delete tunnel +TunnelObList=Tunnels +InfantryObList=Infantry +VehiclesObList=Vehicles +AircraftObList=Aircraft +StructuresObList=Buildings +TerrainObList=Terrain objects +SmudgesObList=Smudges +TreesObList=Trees +TrafficLightsObList=Traffic lights +SignsObList=Signs +LightPostsObList=Light posts +RndTreeObList=Paint random trees +OverlayObList=Special / Overlay +DelOvrlObList=Erase Overlay +DelOvrl0ObList=Erase single field +DelOvrl1ObList=Erase with 1-field radius +DelOvrl2ObList=Erase with 2-field radius +DelOvrl3ObList=Erase with 3-field radius +GrTibObList=Green Tiberium +BlTibObList=Blue Tiberium +DrawRanTibObList=Paint random tiberium field +DrawTibObList=Paint tiberium +IncTibSizeObList=Increase tiberium size +DecTibSizeObList=Decrease tiberium size +VeinholeObList=Veinhole monster +VeinsObList=Veins +BridgesObList=Bridges +BigBridgeObList=Big bridge (in the air) +SmallBridgeObList=Small bridge (at the ground) +BigTrackBridgeObList=Big track bridge (in the air) +SmallConcreteBridgeObList=Small concrete bridge +OthObList=Other +AllObList=All overlay +OvrlManuallyObList=Set overlay manually (not recommended) +OvrlDataManuallyObList=Set overlay data manually (not recommended) +WaypointsObList=Waypoints +CreateWaypObList=Create waypoint +CreateSpecWaypObList=Create waypoint with special ID +DelWaypObList=Delete waypoint +StartpointsObList=Player locations +StartpointsPlayerObList=Player %1 +StartpointsDelete=Delete player location +CelltagsObList=Celltags +CreateCelltagObList=Create celltag +DelCelltagObList=Delete celltag +CelltagPropObList=Edit celltag properties +BaseNodesObList=Base nodes +CreateNodeNoDelObList=Create node and don´t delete building +CreateNodeDelObList=Create node and delete building +DelNodeObList=Delete node +DelObjObList=Delete objects +ChangeOwnerObList=Change owner + +; celltag dialog +CellTagCap=Cell tag +CellTagDesc=Use a celltag to attach a specific cell to a tag: +CellTagTag=Attached tag: + +; aircraft dialog +AirCap=Aircraft options +AirDesc= +AirHouse=Owner: +AirStrength=Strength: +AirState=State: +AirDirection=Direction: +AirTag=Attached tag: +AirP1=Veteran status: +AirP2=Group: +AirP3=Recruitable: +AirP4=AI recruitable: + +; structure dialog +StructCap=Structure options +StructDesc=To add upgrades to this building, first set the upgrade count and then set the upgrades, beginning with upgrade 1. +StructHouse=Owner: +StructStrength=Strength: +StructDirection=Direction: +StructTag=Attached tag: +StructP1=Sellable: +StructAIRepairs=Rebuild:; sheek! that´s wrong... well... doesn´t really matter, just think it is Param2 +StructEnergy=Energy- support: +StructUpgradeCount=Upgradecount: +StructSpotlight=Spotlight: +StructUpgrade1=Upgrade 1: +StructUpgrade2=Upgrade 2: +StructUpgrade3=Upgrade 3: +StructP2=AI repairs: +StructP3=Show name: + +; unit dialog +UnitCap=Vehicle +UnitDesc= +UnitHouse=Owner: +UnitStrength=Strength: +UnitState=State: +UnitDirection=Direction: +UnitTag=Attached tag: +UnitP1=Veteran status: +UnitP2=Group: +UnitP3=On bridge: +UnitP4=Follows ID: +UnitP5=Recruitable: +UnitP6=AI recruitable: + +; infantry dialog +InfCap=Infantry +InfDesc= +InfHouse=Owner: +InfStrength=Strength: +InfPos=Field pos: +InfState=State: +InfDirection=Direction: +InfTag=Attached tag: +InfP1=Veteran status: +InfP2=Group: +InfP3=On Bridge: +InfP4=Recruitable: +InfP5=AI recruitable: + + + +; Now some translations from english to the used language (used for some combo-boxes, menus/listviews and of course unit names) +; currently used for: menu, iso-view status bar, unit/building/stuff list, overlay browser, terrain browser + +[German-TranslationsRA2] +Tiberium=Erz +Gems=Kristalle +Run Tiberian Sun=Red Alert 2 starten +Tiberium Tree=Erzmine +Countries=Häuser; fĂ¼r Edit->Houses Dialog +FinalSun Homepage=FinalAlert Homepage +FinalSun support forum=FinalAlert Hilfeforum +AutoCreate shores=Strand erstellen (AutoShore) +Tiberium (Blue)=Erz +Tiberium (Green)=Erz + +[German-Translations] +; tooltips +Heighten ground (slope logic)=Boden anheben +Lower ground (slope logic)=Boden absenken +Make terrain flat=Boden abflachen +Show all tilesets=Alle Tilesets anzeigen +Raise a single tile=Einzelnes Feld anheben (Nicht empfohlen!) +Lower a single tile=Einzelnes Feld absenken (Nicht empfohlen!) +Paint cliff front=Zugewendete Klippen zeichnen +Paint cliff back=Abgewendete Klippen zeichnen +AutoCreate shores=Strand automatisch erstellen (nur fĂ¼r FinalAlert) +Autocreate shores=Strand erstellen (AutoShore) +AutoLevel terrain height using cliffs=Bodenhöhe an Klippen anpassen (AutoLevel) +Auto level using cliffs=Bodenhöhe an Klippen anpassen (AutoLevel) + +; other strings +FinalSun Homepage=FinalSun Homepage +FinalSun support forum=FinalSun Hilfeforum +Manual F1=Anleitung F1 +Undo Ctrl+Z=RĂ¼ckgängig Strg+Z +Redo Ctrl+Y=Wiederholen Strg+Y +Event=Ereignis +Action=Aktion +Events=Ereignisse +Actions=Aktionen +Trigger=Auslöser +Trigger options=Auslöser-Optionen +Edit=Bearbeiten +Map=Karte +Basic=Generell +Special flags=Spezialeinstellungen +Lighting=Lichteinstellungen +Singleplayer settings=Einzelspieler-Einstellungen +Houses=Häuser +Trigger editor=Auslöser-Editor +Tags (for experts)=Tags (fĂ¼r Experten) +Old trigger editor (obsolete)=Alter Auslöser-Editor (veraltet) +Scripts=Skripte +Taskforces=Truppen / Taskforces +Teams=Teams +AI Triggers=KI-Auslöser +AI Trigger enabling=KI-Auslöser aktivieren +INI editing=INI-Editierung +Terrain=Terrain +Raise ground=Boden anheben +Lower ground=Boden absenken +Flatten ground=Boden angleichen +Hide tileset=Tileset verstecken +Show every tileset=Tilesets alle anzeigen +Hide single field=Einzelnes Feld verstecken +Show all fields=Alle Felder anzeigen +Raise single tile (Be careful!)=Einzelnes Feld anheben (Vorsicht!) +Lower single tile (Be careful!)=Einzelnes Feld absenken (Vorsicht!) +Map tools=Kartentools +Change map height=Kartenhöhe ändern +Ready=Bereit +None=Keiner +Aaargh=AAAAAAAAAH!; :) LET´S SCREEEEAAAAM!!!! +File=Datei +New=Neu +Quit=Beenden +Open=Ă–ffnen +Save=Speichern +Save as=Speichern unter +Check map=Karte Ă¼berprĂ¼fen +Import mod=Mod importieren +Run Tiberian Sun=Tiberian Sun starten +Launch FinalSun version=%9 Version starten +Options=Optionen +Settings=Einstellungen +Show map view=Kartenansicht zeigen +Show minimap=Ăœbersichtskarte zeigen +Easy mode=Anfängermodus +Help=Hilfe +Tip of the day=Tip des Tages +GDI Wall=GDI-Mauer +Nod Wall=Nod-Mauer +Tracks=Eisenbahnschienen +Other=Anderes +Mobile Construction Vehicle=Mobiles Baufahrzeug +Amphibious APC=Amphibien-APC +Titan=Titan +School Bus=Schulbus +Artillery=Artillerie +Wolverine=Werwolf +Hover MLRS=Schwebepanzer +Locomotive=Lokomotive +Harvester=Sammler +Mammoth Tank=Mammut +Devil's Tongue=Teufelszunge +Light Infantry=Leichte Infantrie +Engineer=Ingenieur +Civilian=Zivilist +Cyborg Commando=Cyborg-Kommando +Technician=Techniker +Orca Fighter=Orca-Jäger +GDI Power Plant=GDI Kraftwerk +Tiberium Refinery=Tiberium-Raffinerie +Construction Yard=Bauhof +Barracks=Barracken +Sandbags=Sandsäcke +Gate=Tor +Power Turbine=Kraftwerks-Turbine +Pavement=Pflaster +Temple of Nod=Tempel von Nod +Obelisk of Light=Obelisk des Lichts +Missile Silo=Raketensilo +Bridge repair hut=BrĂ¼cken-Reparatur-HĂ¼tte +Red Light Post=Rote Lampe +Green Light Post=GrĂ¼ne Lampe +Blue Light Post=Blaue Lampe +Yellow Light Post=Gelbe Lampe +Purple Light Post=Lila Lampe +Orange Light Post=Orange Lampe +Invisible Red Light Post=Unsichtbare rote Lampe +Invisible Green Light Post=Unsichtbare grĂ¼ne Lampe +Invisible Blue Light Post=Unsichtbare blaue Lampe +Invisible Yellow Light Post=Unsichtbare gelbe Lampe +Invisible Purple Light Post=Unsichtbare lila Lampe +Invisible Orange Light Post=Unsichtbare orange Lampe +Invisible Light Post=Unsichtbare Lampe +Light Post=Lampe +Light Tower=Leuchtturm +Dam=Damm +Church=Kirche +Pyramid=Pyramide +Scrin Ship=Scrin-Schiff +Tree=Baum +Tiberium Tree=Tiberium-Baum +Boxes=Kisten +Bridge 1=BrĂ¼cke obenlinks-untenrechts +Bridge 2=BrĂ¼cke untenlinks-obenrechts +Railroad Bridge 1=EisenbahnbrĂ¼cke obenlinks-untenrechts +Railroad Bridge 2=EisenbahnbrĂ¼cke untenlinks-obenrechts +Wood Bridge 1=HolzbrĂ¼cke obenlinks-untenrechts +Wood Bridge 2=HolzbrĂ¼cke untenlinks-obenrechts + +; FA2:YR +FinalAlert 2 Fansite link=%9 Fansite link +FinalAlert 2 Forum=%9 Forum + +[English-TranslationsRA2] +Tiberium=Ore +Run Tiberian Sun=Run Red Alert 2 +Tiberium Tree=Ore mine +Countries=Houses; For the edit->houses dialog +FinalSun Homepage=FinalAlert Homepage +FinalSun support forum=FinalAlert support forum +AutoCreate shores=Automatically create shore (AutoShore) +Tiberium (Blue)=Ore +Tiberium (Green)=Ore + +[English-Translations] +; tooltips +Make terrain flat=Flatten ground +Raise a single tile=Raise single field (Not recommended!) +Lower a single tile=Lower single field (Not recommended!) +AutoCreate shores=Automatically create shore (only supported in FinalAlert) +Autocreate shores=Automatically create shore (AutoShore) +AutoLevel terrain height using cliffs=AutoLevel ground height using cliffs +Auto level using cliffs=AutoLevel ground height using cliffs + +; other +Bridge 1=Bridge topleft-bottomright +Bridge 2=Bridge bottomleft-topright +Railroad Bridge 1=Railroad bridge topleft-bottomright +Railroad Bridge 2=Railroad bridge bottomleft-topright +Wood Bridge 1=Wood bridge topleft-bottomright +Wood Bridge 2=Wood bridge bottomleft-topright +Easy mode=Beginner mode + +; FA2:YR +FinalAlert 2 Fansite link=%9 Fansite link +FinalAlert 2 Forum=%9 Forum diff --git a/MissionEditor/data/FinalAlert2/FinalAlertDefaults.ini b/MissionEditor/data/FinalAlert2/FinalAlertDefaults.ini new file mode 100644 index 0000000..7c4944c --- /dev/null +++ b/MissionEditor/data/FinalAlert2/FinalAlertDefaults.ini @@ -0,0 +1,16 @@ +[Files] + +[FinalAlert] +Language=English +FileSearchLikeGame=yes + +[RA2] + +[UserInterface] +LoadScreenDelay=4.0 +UseDefaultMouseCursor=1 +ShowBuildingCells=1 +EasyView=0 + +[MiniMap] +Scale=2.000000 diff --git a/MissionEditor/data/FinalAlert2/README.TXT b/MissionEditor/data/FinalAlert2/README.TXT new file mode 100644 index 0000000..8f0b0f3 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/README.TXT @@ -0,0 +1,114 @@ +Command & Conquer - Red Alert 2 (c): FinalAlert 2: Yuri's Revenge Editor 2.0 +---------------------------------------------------------------------------- + Copyright 2001-2024 Electronic Arts Inc. All rights reserved. + Westwood Studios [TM] is an Electronic Arts [TM] brand. + + Microsoft, DirectX and Windows are trademarks of the Microsoft group of companies. + +----------------------------------------------------------------------------- + +TECHNICAL SUPPORT DISCLAIMER +---------- +In order to ask questions about FinalAlert 2: Yuri's Revenge, please visit https://www.ea.com. +We will review the message board and reply to questions as often as we can. Technical support +is limited. FinalAlert 2: Yuri's Revenge is distributed free of charge for the benefit of Red Alert 2 +fans. + + +MINIMUM SPECS +---------- +FinalAlert 2: Yuri's Revenge: +- Microsoft Windows 10, 11 (older versions may work but are unsupported) +- 2 GB physical RAM +- Red Alert 2 installed + +Command & Conquer: Red Alert 2 +- see system requirements on box +- You must have the Yuri's Revenge expansion installed. + + +LICENSE +------- +Copyright 2001-2024 Electronic Arts Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. + + +THIRD PARTY LICENSES +-------------------- +This program uses several third party libraries. Their copyright notices +and license terms are available in the 3rdParty\licenses folder. + + + + +KNOWN ISSUES/BUGS +---------- +- Problems may occur if you have one or more mods installed. If you experience problems, + please try first to remove these mods. + + + + +HOW TO START +---------- +After FinalAlert 2: Yuri's Revenge has finished loading, press F1 to show the manual and +some tutorials. + + + +Please read the manual by pressing F1 in FinalAlert 2: Yuri's Revenge. You should also +begin with the tutorials included. + + + +FAQ +---------- +Q: How can I create a zoom trigger? +A: If you want to zoom on a particular place, you must first use the 'move camera + and scroll to waypoint' action (#48) and then zoom in. The zoom rate is controlled + by an undocumented keyword which must be placed in the [General] section of RULES.INI + or your map file: ZoomInFactor=N } It works to use Edit->Ini to create a [General] + section inside the map file and insert the key. + +Q: Can I play the maps online? And use the new unit types online? +A: Yes, the synchronization limit is 180 seconds. You can use the unit types online. + +Q: How can I keep the map file small so that I'm able to play with 4 players online? +A: One possibility is to "hide" the preview. Just select the appropiate options when you + save the map. Since Patch 1.005 will allow longer synch times, this problem should be + less of an issue.. + +Q: Ok I've made a multiplayer map. How can I play it? +A: In the Yuri's Revenge map settings dialog, choose "multiplayer maps" and click on + your's (usually near the bottom). Note that you cannot load the map in the random + map editor. + +Q: What is that drag & drop feature? How can I copy units/buildings or move them? +A: Instead of deleting a building and placing it somewhere else, you can simply click + with the left mouse button on the building and move your mouse while holding down the + mouse button. You can now see a line that shows where the building/unit will be placed. + If you stop holding down the button, the unit/building will be moved there. If you hold + down the shift key also, it will be "copied" there. That means you can create a big + army without having to create every unit yourself. Note: if you move/copy a building + and it is to big to be placed at the new position, no warning appears! That means you + will probably have problems if you don't make sure that there is enough space! + + + + + + + + diff --git a/MissionEditor/data/FinalAlert2/Scripts/Add Apoc Attack AI Trigger.fscript b/MissionEditor/data/FinalAlert2/Scripts/Add Apoc Attack AI Trigger.fscript new file mode 100644 index 0000000..f9ecd0f --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Add Apoc Attack AI Trigger.fscript @@ -0,0 +1,71 @@ +// FinalAlert2:YR Script file +// Name: Move 4 starting points close to corners +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + + +AskContinue("This script will add AI Triggers and Teams that makes soviet AIs attack with a certain amount of Apocs. Continue?"); + +// disable safe mode so that we can move already existing waypoints, not just create new ones +// user must allow the script to do this. If he does not, the waypoints won�t be moved if they +// already exist. +SetSafeMode("FALSE","Necessary for moving waypoints"); + +AllowAdd("Necessary for adding AI trigger"); + +UInputGetInteger("%Count%","How many Apocalypse tanks shall be in the attack force?","1","20"); + +SetIniKey("ScriptTypes","63811929","63811929"); +SetIniKey("TaskForces","63811928","63811928"); +SetIniKey("TeamTypes","63811930","63811930"); + +// taskforce +SetIniKey("63811928","0","%Count%,APOC"); +SetIniKey("63811928","Name","%Count% Apocs"); +SetIniKey("63811928","Group","-1"); + +// script +SetIniKey("63811929","0","54,0"); +SetIniKey("63811929","1","53,0"); +SetIniKey("63811929","2","0,1"); +SetIniKey("63811929","3","11,15"); +SetIniKey("63811929","Name","AI Apoc Attack"); + +// teamtype +SetIniKey("63811930","Max","5"); +SetIniKey("63811930","Full","no"); +SetIniKey("63811930","Name","Apoc Attack"); +SetIniKey("63811930","Group","-1"); +SetIniKey("63811930","House","Neutral"); +SetIniKey("63811930","Script","63811929"); +SetIniKey("63811930","Whiner","no"); +SetIniKey("63811930","Droppod","no"); +SetIniKey("63811930","Suicide","no"); +SetIniKey("63811930","Loadable","no"); +SetIniKey("63811930","Prebuild","no"); +SetIniKey("63811930","Priority","5"); +SetIniKey("63811930","Waypoint","A"); +SetIniKey("63811930","Annoyance","yes"); +SetIniKey("63811930","IonImmune","no"); +SetIniKey("63811930","Recruiter","yes"); +SetIniKey("63811930","Reinforce","no"); +SetIniKey("63811930","TaskForce","63811928"); +SetIniKey("63811930","TechLevel","0"); +SetIniKey("63811930","Aggressive","yes"); +SetIniKey("63811930","Autocreate","no"); +SetIniKey("63811930","GuardSlower","no"); +SetIniKey("63811930","OnTransOnly","no"); +SetIniKey("63811930","AvoidThreats","no"); +SetIniKey("63811930","LooseRecruit","no"); +SetIniKey("63811930","VeteranLevel","1"); +SetIniKey("63811930","IsBaseDefense","no"); +SetIniKey("63811930","UseTransportOrigin","no"); +SetIniKey("63811930","MindControlDecision","0"); +SetIniKey("63811930","OnlyTargetHouseEnemy","no"); +SetIniKey("63811930","TransportsReturnOnUnload","no"); +SetIniKey("63811930","AreTeamMembersRecruitable","yes"); + +AddAITrigger("%AITrigID%","Apoc Attack,63811930,<all>,1,1,NATECH,01000000030000000000000000000000000000000000670100000000cc869412,250.000000,230.000000,250.000000,1,0,2,0,<none>,1,1,1"); +SetIniKey("AITriggerTypesEnable","%AITrigID%","yes"); diff --git a/MissionEditor/data/FinalAlert2/Scripts/Add Prism + Mirage Attack AI Trigger.fscript b/MissionEditor/data/FinalAlert2/Scripts/Add Prism + Mirage Attack AI Trigger.fscript new file mode 100644 index 0000000..c32a6e0 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Add Prism + Mirage Attack AI Trigger.fscript @@ -0,0 +1,73 @@ +// FinalAlert2:YR Script file +// Name: Move 4 starting points close to corners +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + + +AskContinue("This script will add AI Triggers and Teams that makes allied AIs attack with a certain amount of Prism tanks and Mirages. Continue?"); + +// disable safe mode so that we can move already existing waypoints, not just create new ones +// user must allow the script to do this. If he does not, the waypoints won�t be moved if they +// already exist. +SetSafeMode("FALSE","Necessary for moving waypoints"); + +AllowAdd("Necessary for adding AI trigger"); + +UInputGetInteger("%Count%","How many Prism tanks shall be in the attack force?","1","20"); +UInputGetInteger("%MCount%","How many Mirage tanks shall be in the attack force?","1","20"); + +SetIniKey("ScriptTypes","63811829","63811829"); +SetIniKey("TaskForces","63811828","63811828"); +SetIniKey("TeamTypes","63811830","63811830"); + +// taskforce +SetIniKey("63811828","0","%MCount%,MGTK"); +SetIniKey("63811828","1","%Count%,SREF"); +SetIniKey("63811828","Name","%Count% Prism Tanks, %MCount% Mirages"); +SetIniKey("63811828","Group","-1"); + +// script +SetIniKey("63811829","0","54,0"); +SetIniKey("63811829","1","53,0"); +SetIniKey("63811829","2","0,1"); +SetIniKey("63811829","3","11,15"); +SetIniKey("63811829","Name","AI Prism+Mirage Attack"); + +// teamtype +SetIniKey("63811830","Max","5"); +SetIniKey("63811830","Full","no"); +SetIniKey("63811830","Name","Prism+Mirage Attack"); +SetIniKey("63811830","Group","-1"); +SetIniKey("63811830","House","Neutral"); +SetIniKey("63811830","Script","63811829"); +SetIniKey("63811830","Whiner","no"); +SetIniKey("63811830","Droppod","no"); +SetIniKey("63811830","Suicide","no"); +SetIniKey("63811830","Loadable","no"); +SetIniKey("63811830","Prebuild","no"); +SetIniKey("63811830","Priority","5"); +SetIniKey("63811830","Waypoint","A"); +SetIniKey("63811830","Annoyance","yes"); +SetIniKey("63811830","IonImmune","no"); +SetIniKey("63811830","Recruiter","yes"); +SetIniKey("63811830","Reinforce","no"); +SetIniKey("63811830","TaskForce","63811828"); +SetIniKey("63811830","TechLevel","0"); +SetIniKey("63811830","Aggressive","yes"); +SetIniKey("63811830","Autocreate","no"); +SetIniKey("63811830","GuardSlower","no"); +SetIniKey("63811830","OnTransOnly","no"); +SetIniKey("63811830","AvoidThreats","no"); +SetIniKey("63811830","LooseRecruit","no"); +SetIniKey("63811830","VeteranLevel","1"); +SetIniKey("63811830","IsBaseDefense","no"); +SetIniKey("63811830","UseTransportOrigin","no"); +SetIniKey("63811830","MindControlDecision","0"); +SetIniKey("63811830","OnlyTargetHouseEnemy","no"); +SetIniKey("63811830","TransportsReturnOnUnload","no"); +SetIniKey("63811830","AreTeamMembersRecruitable","yes"); + +AddAITrigger("%AITrigID%","Prism+Mirage Attack,63811830,<all>,1,1,GATECH,01000000030000000000000000000000000000000000670100000000cc869412,250.000000,230.000000,250.000000,1,0,1,0,<none>,1,1,1"); +SetIniKey("AITriggerTypesEnable","%AITrigID%","yes"); diff --git a/MissionEditor/data/FinalAlert2/Scripts/Add Reveal Map Debug Trigger.fscript b/MissionEditor/data/FinalAlert2/Scripts/Add Reveal Map Debug Trigger.fscript new file mode 100644 index 0000000..80279e9 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Add Reveal Map Debug Trigger.fscript @@ -0,0 +1,15 @@ +// FinalAlert2:YR Script file +// Name: Add Reveal Map Debug trigger +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AskContinue("This script will add a trigger that reveals the whole map after 10 seconds. Continue?"); +AllowAdd("TRUE"); + +// now add the trigger, use the variable %TriggerID% as ID filler, and let a tag be created automatically +AddTrigger("%TriggerID%", "Americans,<none>,Reveal Map Debug Trigger,0,1,1,1,0", "1,13,0,10", "1,16,0,0,0,0,0,0,A", "TRUE"); +Message("Trigger %TriggerID% added","Success"); + + diff --git a/MissionEditor/data/FinalAlert2/Scripts/Create Afternoon Lighting.fscript b/MissionEditor/data/FinalAlert2/Scripts/Create Afternoon Lighting.fscript new file mode 100644 index 0000000..8a14e0f --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Create Afternoon Lighting.fscript @@ -0,0 +1,20 @@ +// FinalAlert2:YR Script file +// Name: Create Morning Lighting +// Written By: Matthias Wagner +// Last Change: August 27, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +SetSafeMode("FALSE","Necessary for setting lighting values"); + +SetIniKey("Lighting","Level","0.028000"); +SetIniKey("Lighting","IonLevel","0.028000"); + +SetIniKey("Lighting","Ambient","1.000000"); +SetIniKey("Lighting","Red","1.080000"); +SetIniKey("Lighting","Green","0.940000"); +SetIniKey("Lighting","Blue","0.680000"); + +SetIniKey("Lighting","IonAmbient","0.650000"); +SetIniKey("Lighting","IonRed","0.695000"); +SetIniKey("Lighting","IonGreen","0.445000"); +SetIniKey("Lighting","IonBlue","0.775000"); \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/Scripts/Create Evening Lighting.fscript b/MissionEditor/data/FinalAlert2/Scripts/Create Evening Lighting.fscript new file mode 100644 index 0000000..e11953d --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Create Evening Lighting.fscript @@ -0,0 +1,20 @@ +// FinalAlert2:YR Script file +// Name: Create Morning Lighting +// Written By: Matthias Wagner +// Last Change: August 27, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +SetSafeMode("FALSE","Necessary for setting lighting values"); + +SetIniKey("Lighting","Level","0.028000"); +SetIniKey("Lighting","IonLevel","0.028000"); + +SetIniKey("Lighting","Ambient","0.750000"); +SetIniKey("Lighting","Red","0.710000"); +SetIniKey("Lighting","Green","0.810000"); +SetIniKey("Lighting","Blue","1.190000"); + +SetIniKey("Lighting","IonAmbient","0.650000"); +SetIniKey("Lighting","IonRed","0.695000"); +SetIniKey("Lighting","IonGreen","0.445000"); +SetIniKey("Lighting","IonBlue","0.775000"); \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/Scripts/Create Morning Lighting.fscript b/MissionEditor/data/FinalAlert2/Scripts/Create Morning Lighting.fscript new file mode 100644 index 0000000..85f3bd1 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Create Morning Lighting.fscript @@ -0,0 +1,20 @@ +// FinalAlert2:YR Script file +// Name: Create Morning Lighting +// Written By: Matthias Wagner +// Last Change: August 27, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +SetSafeMode("FALSE","Necessary for setting lighting values"); + +SetIniKey("Lighting","Level","0.028000"); +SetIniKey("Lighting","IonLevel","0.028000"); + +SetIniKey("Lighting","Ambient","0.750000"); +SetIniKey("Lighting","Red","1.090000"); +SetIniKey("Lighting","Green","0.800000"); +SetIniKey("Lighting","Blue","0.490000"); + +SetIniKey("Lighting","IonAmbient","0.650000"); +SetIniKey("Lighting","IonRed","0.695000"); +SetIniKey("Lighting","IonGreen","0.445000"); +SetIniKey("Lighting","IonBlue","0.775000"); \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/Scripts/Create Night Lighting.fscript b/MissionEditor/data/FinalAlert2/Scripts/Create Night Lighting.fscript new file mode 100644 index 0000000..2c8cef5 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Create Night Lighting.fscript @@ -0,0 +1,20 @@ +// FinalAlert2:YR Script file +// Name: Create Morning Lighting +// Written By: Matthias Wagner +// Last Change: August 27, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +SetSafeMode("FALSE","Necessary for setting lighting values"); + +SetIniKey("Lighting","Level","0.028000"); +SetIniKey("Lighting","IonLevel","0.028000"); + +SetIniKey("Lighting","Ambient","0.350000"); +SetIniKey("Lighting","Red","0.510000"); +SetIniKey("Lighting","Green","0.460000 "); +SetIniKey("Lighting","Blue","1.410000"); + +SetIniKey("Lighting","IonAmbient","0.650000"); +SetIniKey("Lighting","IonRed","0.695000"); +SetIniKey("Lighting","IonGreen","0.445000"); +SetIniKey("Lighting","IonBlue","0.775000"); \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/Scripts/Enlarge Map by 50x50.fscript b/MissionEditor/data/FinalAlert2/Scripts/Enlarge Map by 50x50.fscript new file mode 100644 index 0000000..dbb15ea --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Enlarge Map by 50x50.fscript @@ -0,0 +1,28 @@ +// FinalAlert2:YR Script file +// Name: Enlarge map by 50x50 +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +Is("%Width%", ">", "150", "WidthTooLarge"); +Is("%Height%", ">", "150", "HeightTooLarge"); + +Print("Script cannot resize map, because the map width is too large.","WidthTooLarge"); +Print("Script cannot resize map, because the map height is too large.","HeightTooLarge"); +Cancel("WidthTooLarge"); +Cancel("HeightTooLarge"); + +SetVariable("NW", "%Width%"); +SetVariable("NH", "%Height%"); +SetVariable("X", "25"); +SetVariable("Y", "25"); + +Add("NW", "50"); +Add("NH", "50"); + +AskContinue("This script will resize the map from %Width%x%Height% to NWxNH. Continue?"); + +Resize("X","Y","NW","NH"); + + + diff --git a/MissionEditor/data/FinalAlert2/Scripts/List Objects.fscript b/MissionEditor/data/FinalAlert2/Scripts/List Objects.fscript new file mode 100644 index 0000000..92074f7 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/List Objects.fscript @@ -0,0 +1,54 @@ +// FinalAlert2:YR Script file +// Name: Change Unit Facing +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + + +SetAutoUpdate("FALSE"); // no screen flickering... + + +SetVariable("%TCounter%","%InfantryCount%"); + +// LOOP BEGIN +:LoopInfantry: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetInfantry("%data%","%pos%"); +Print("Infantry %pos%: %data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("LoopInfantry","%TCounter%"); + +SetVariable("%TCounter%","%UnitCount%"); + +// LOOP BEGIN +:LoopVehicle: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetVehicle("%data%","%pos%"); +Print("Vehicle %pos%: %data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("LoopVehicle","%TCounter%"); + +SetVariable("%TCounter%","%AircraftCount%"); + +// LOOP BEGIN +:LoopAircraft: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetAircraft("%data%","%pos%"); +Print("Aircraft %pos%: %data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("LoopAircraft","%TCounter%"); + +SetVariable("%TCounter%","%StructureCount%"); + +// LOOP BEGIN +:LoopStructure: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetStructure("%data%","%pos%"); +Print("Structure %pos%: %data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("LoopStructure","%TCounter%"); \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/Scripts/List general map stats.fscript b/MissionEditor/data/FinalAlert2/Scripts/List general map stats.fscript new file mode 100644 index 0000000..aa2e083 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/List general map stats.fscript @@ -0,0 +1,27 @@ +// FinalAlert2:YR Script file +// Name: Move 4 starting points close to corners +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +Print("Player count: %PlayerCount%"); +Print("Waypoint count: %WaypointCount%"); +Print("Unit count: %UnitCount%"); +Print("Infantry count: %InfantryCount%"); +Print("Structure count: %StructureCount%"); +Print("Aircraft count: %AircraftCount%"); + +SetVariable("%WPCounter%","100"); + +// BEGIN WAYPOINT LOOP +:WaypointLoop: + +SetVariable("%WPID%","100"); +Substract("%WPID%","%WPCounter%"); +GetWaypointPos("%WPID%","%X%","%Y%"); +Print("Waypoint %WPID%: %X% / %Y%","%X%"); // List waypoint if x coordinate !=0, as we have non-existing waypoints +Substract("%WPCounter%","1"); + +JumpTo("WaypointLoop", "%WPCounter%"); +// END WAYPOINT LOOP \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/Scripts/MP Move 4 starting points into corners.fscript b/MissionEditor/data/FinalAlert2/Scripts/MP Move 4 starting points into corners.fscript new file mode 100644 index 0000000..1014d39 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/MP Move 4 starting points into corners.fscript @@ -0,0 +1,52 @@ +// FinalAlert2:YR Script file +// Name: Move 4 starting points close to corners +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +// only for multiplayer maps: +RequiresMP(); + +Is("%PlayerCount%","!=", "4", "4Players?"); +Print("Warning: Script usually should be used only on 4 player maps.","4Players?"); +Print("This map currently has %PlayerCount% players.","4Players?"); +Print("The map will be set up for at least 4 players","4Players?"); + +AskContinue("This tool will move the starting locations of the first 4 players into the corners of the map. It needs to disable INI protection to do this."); + +// disable safe mode so that we can move already existing waypoints, not just create new ones +// user must allow the script to do this. If he does not, the waypoints won�t be moved if they +// already exist. +SetSafeMode("FALSE","Necessary for moving waypoints"); + +// Waypoint 0: +SetVariable("Y", "20"); +SetVariable("X", "%Width%"); + +SetWaypoint("0", "X", "Y"); + + +// Waypoint 1: +SetVariable("X", "20"); +SetVariable("Y", "%Width%"); + +SetWaypoint("1", "X", "Y"); + + +// helper variable for 2,3: +SetVariable("V", "%IsoSize%"); +Substract("V", "20"); + +// Waypoint 2: +SetVariable("X", "%Height%"); +SetVariable("Y", "V"); + +SetWaypoint("2", "X", "Y"); + +// Waypoint 3: +SetVariable("Y", "%Height%"); +SetVariable("X", "V"); + +SetWaypoint("3", "X", "Y"); + diff --git a/MissionEditor/data/FinalAlert2/Scripts/Make all aircraft recruitable.fscript b/MissionEditor/data/FinalAlert2/Scripts/Make all aircraft recruitable.fscript new file mode 100644 index 0000000..76a8bf5 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Make all aircraft recruitable.fscript @@ -0,0 +1,56 @@ +// FinalAlert2:YR Script file +// Name: Make Aircraft Recruitable +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing aircraft"); +AllowAdd("Necessary for changing aircraft"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit changes to a specific house?","Limit to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%AircraftCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%AircraftCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetAircraft("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteAircraft("%pos%"); + +// recruitable & AI recruitable +SetParam("%data%","10","1"); +SetParam("%data%","11","1"); + +AddAircraft("%data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); + + diff --git a/MissionEditor/data/FinalAlert2/Scripts/Make all infantry recruitable.fscript b/MissionEditor/data/FinalAlert2/Scripts/Make all infantry recruitable.fscript new file mode 100644 index 0000000..d073a1d --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Make all infantry recruitable.fscript @@ -0,0 +1,58 @@ +// FinalAlert2:YR Script file +// Name: Make Infantry Recruitable +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing infantry"); +AllowAdd("Necessary for changing infantry"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit changes to a specific house?","Limit to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%InfantryCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%InfantryCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +IsInfantryDeleted("%deleted?%","%pos%"); +Is("%deleted?%","=","0","%existing%"); +GetInfantry("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteInfantry("%pos%","%existing%"); + +// recruitable & AI recruitable +SetParam("%data%","12","1","%existing%"); +SetParam("%data%","13","1","%existing%"); + +AddInfantry("%data%","%existing%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); + + diff --git a/MissionEditor/data/FinalAlert2/Scripts/Make all units recruitable.fscript b/MissionEditor/data/FinalAlert2/Scripts/Make all units recruitable.fscript new file mode 100644 index 0000000..98aaaef --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Make all units recruitable.fscript @@ -0,0 +1,56 @@ +// FinalAlert2:YR Script file +// Name: Make Vehicle Recruitable +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing vehicles"); +AllowAdd("Necessary for changing vehicles"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit changes to a specific house?","Limit to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%UnitCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%UnitCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetVehicle("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteVehicle("%pos%"); + +// recruitable & AI recruitable +SetParam("%data%","12","1"); +SetParam("%data%","13","1"); + +AddVehicle("%data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); + + diff --git a/MissionEditor/data/FinalAlert2/Scripts/Random Aircraft facing.fscript b/MissionEditor/data/FinalAlert2/Scripts/Random Aircraft facing.fscript new file mode 100644 index 0000000..c433d91 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Random Aircraft facing.fscript @@ -0,0 +1,61 @@ +// FinalAlert2:YR Script file +// Name: Change Unit Facing +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing infantry"); +AllowAdd("Necessary for changing infantry"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit random aircraft facing to a specific house?","Limit Random Aircraft facing to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%AircraftCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%AircraftCount%"); + + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); + +GetAircraft("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteAircraft("%pos%"); +GetRandom("%Facing%"); + +// convert random (0-32767) to 8 directions +Divide("%Facing%","4096"); + +// convert 8 directions to degrees +Multi("%Facing%","32"); + +SetParam("%data%","5","%Facing%"); + +AddAircraft("%data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/Scripts/Random Infantry Facing.fscript b/MissionEditor/data/FinalAlert2/Scripts/Random Infantry Facing.fscript new file mode 100644 index 0000000..de692c4 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Random Infantry Facing.fscript @@ -0,0 +1,65 @@ +// FinalAlert2:YR Script file +// Name: Change Infantry Facing +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing infantry"); +AllowAdd("Necessary for changing infantry"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit random infantry facing to a specific house?","Limit Random Infantry facing to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%InfantryCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%InfantryCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +IsInfantryDeleted("%deleted?%","%pos%"); +Is("%deleted?%","=","0","%existing%"); +GetInfantry("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteInfantry("%pos%","%existing%"); +GetRandom("%Facing%"); + +// convert random (0-32767) to 8 directions +Divide("%Facing%","4096"); + +// convert 8 directions to degrees +Multi("%Facing%","32"); + +Print("%Facing%"); + +SetParam("%data%","7","%Facing%","%existing%"); + +AddInfantry("%data%","%existing%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); + + diff --git a/MissionEditor/data/FinalAlert2/Scripts/Random Unit Facing.fscript b/MissionEditor/data/FinalAlert2/Scripts/Random Unit Facing.fscript new file mode 100644 index 0000000..34c5967 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/Random Unit Facing.fscript @@ -0,0 +1,61 @@ +// FinalAlert2:YR Script file +// Name: Change Unit Facing +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing infantry"); +AllowAdd("Necessary for changing infantry"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit random unit facing to a specific house?","Limit Random Unit facing to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%UnitCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%UnitCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); + +GetVehicle("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + + +DeleteVehicle("%pos%"); +GetRandom("%Facing%"); + +// convert random (0-32767) to 8 directions +Divide("%Facing%","4096"); + +// convert 8 directions to degrees +Multi("%Facing%","32"); + +SetParam("%data%","5","%Facing%"); + +AddVehicle("%data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/Scripts/TEST TreesAroundPoint.fscript b/MissionEditor/data/FinalAlert2/Scripts/TEST TreesAroundPoint.fscript new file mode 100644 index 0000000..3019dad --- /dev/null +++ b/MissionEditor/data/FinalAlert2/Scripts/TEST TreesAroundPoint.fscript @@ -0,0 +1,38 @@ +AllowAdd("Necessary"); + +SetVariable("%X%", "%IsoSize%"); +SetVariable("%Y%", "%IsoSize%"); +Divide("%X%", "2"); +Divide("%Y%", "2"); + +SetVariable("%XCounter%","-5"); + +:XLoop: + +SetVariable("%YCounter%","-5"); + +:YLoop: + +Add("%YCounter%", "1"); +Is("%YCounter%","<","5","YLoopAgain"); + +GetRandom("%Val%"); +Add("%Val%","6000"); +Divide("%Val%","32767") + +SetVariable("%MX%","%X%"); +Add("%MX%","%XCounter%"); +SetVariable("%MY%","%Y%"); +Add("%MY%","%YCounter%"); + +AddTerrain("TREE01", "%MX%","%MY%","%Val%"); + +JumpTo("YLoop", "YLoopAgain"); +// :YLoop: + +Add("%XCounter%","1"); + +Is("%XCounter%","<","5","XLoopAgain"); +JumpTo("XLoop","XLoopAgain"); +// :XLoop: + diff --git a/MissionEditor/data/FinalAlert2/StdMapRA2.ini b/MissionEditor/data/FinalAlert2/StdMapRA2.ini new file mode 100644 index 0000000..c44584a --- /dev/null +++ b/MissionEditor/data/FinalAlert2/StdMapRA2.ini @@ -0,0 +1,69 @@ +; This file provides a standard template for every new map created in FinalAlert +; Be careful editing this file! +; [Map] section is ignored as FinalAlert will automatically create it +; Packed sections may work, but I haven�t tried this! +; You should not edit this file, as it may cause FinalSun�s created maps to crash +; Last change: April 18th 2002 + +[Basic] +NextScenario= +AltNextScenario= +Name=No name +NewINIFormat=4 +CarryOverCap=0 +EndOfGame=no +SkipScore=no +OneTimeOnly=no +SkipMapSelect=no +Official=no +IgnoreGlobalAITriggers=no +TruckCrate=no +TrainCrate=no +Percent=0 +CarryOverMoney=0.000000 +HomeCell=98 +AltHomeCell=99 +MultiplayerOnly=0 +TiberiumGrowthEnabled=yes +VeinGrowthEnabled=yes +IceGrowthEnabled=yes +TiberiumDeathToVisceroid=no +FreeRadar=no +InitTime=10000 + +[Lighting] +Ambient=1.000000 +Red=1.000000 +Green=1.000000 +Blue=1.000000 +Ground=0.000000 +Level=0.032000 +IonAmbient=1.000000 +IonRed=1.000000 +IonGreen=1.000000 +IonBlue=1.000000 +IonGround=0.000000 +IonLevel=0.032000 +DominatorRed=0.850000 +DominatorBlue=0.300000 +DominatorGreen=0.200000 +DominatorLevel=0.000000 +DominatorGround=0.000000 +DominatorAmbient=1.500000 +DominatorAmbientChangeRate=0.009000 + +[SpecialFlags] +TiberiumGrows=yes +TiberiumSpreads=yes +TiberiumExplosive=no +DestroyableBridges=yes +MCVDeploy=no +InitialVeteran=no +FixedAlliance=no +HarvesterImmune=no +FogOfWar=no +Inert=no +IonStorms=no +Meteorites=no +Visceroids=yes + diff --git a/MissionEditor/data/FinalAlert2/TIPS.DEU b/MissionEditor/data/FinalAlert2/TIPS.DEU new file mode 100644 index 0000000..76fcb5e --- /dev/null +++ b/MissionEditor/data/FinalAlert2/TIPS.DEU @@ -0,0 +1,9 @@ +Diese Tips & Tricks sollten Ihnen helfen, tolle neue Karten fĂ¼r Alarmstufe Rot 2 und Yuri's Rache zu erstellen. Lesen Sie bitte möglichst viele durch, es lohnt sich. +Falls AutoShore beim Plazieren von Tiles stören sollte, können Sie es Ă¼ber das Optionen-MenĂ¼ deaktivieren. +Sie sollten unbedingt die neuen Klippen-Plazierungs-Werkzeuge ausprobieren. Sie finden sie in der Werkzeugleiste. Einfach auswählen, auf die Karte klicken, gedrĂ¼ckt halten, und Maus in Klippenrichtung bewegen. +Nachdem Sie in den Terrain-Plazierungsmodus gewechselt haben, können Sie die Pfeiltasten benutzen, um durch die verfĂ¼gbaren Tilesets und Tiles zu scrollen. +Benutzen Sie die Show/Hide Funktionen, um einzelne Felder oder Terraintypen unsichtbar zu machen. Damit ist es oft viel leichter, gewisse Kartenabschnitte zu editieren. +Haben Sie bereits den Assistenten fĂ¼r neue Karten (unter Datei->Neu) getestet? Er bereitet automatisch alles vor, was Sie fĂ¼r eine Einzelspieler und Mehrspieler-Karte benötigen. +Erstellen Sie komplett neue Karten durch die Fähigkeit von FinalAlert 2: Yuri's Revenge(tm), das Terrain zu editieren! +Beachten Sie auch die Statusleiste am unteren Fensterrand. Sie hat oft hilfreiche Informationen parat. +Beachten Sie, dass die Brush/Pinsel-Grösse sowohl fĂ¼r "paint terrain", als auch fĂ¼r "flatten terrain" und "raise/lower" terrain benutzt wird. diff --git a/MissionEditor/data/FinalAlert2/TIPS.ENG b/MissionEditor/data/FinalAlert2/TIPS.ENG new file mode 100644 index 0000000..b195f8e --- /dev/null +++ b/MissionEditor/data/FinalAlert2/TIPS.ENG @@ -0,0 +1,9 @@ +These tips should help you to create cool Red Alert 2 and Yuri's Revenge maps. +If you do not want AutoShore to be applied when placing tiles, you can disable AutoShore (and AutoLat) in the Options menu. +You should really try the new cliff painting tools. They both are in the toolbar. Select them, click on the map, hold down the mouse button, and move the mouse into the cliff direction. +After you have activated the tile/terrain placing mode, you can use the arrow keys to scroll through the different tilesets and tiles. +Use the show/hide functions to make certain fields or terrain types invisible. Using this, map editing in certain parts of the map becomes much easier. +Have you already tried out the "New map assistant" (File->New)? It creates all the stuff you need for a singleplayer and multiplayer map. +Create completely new maps with FinalAlert 2: Yuri's Revenge(tm)! +Pay attention to the status bar at the bottom of the window. It often contains useful information. +Consider that the brush size works for "paint terrain", "flatten terrain" (important!) and for "raise/lower" terrain. diff --git a/MissionEditor/data/FinalAlert2/marble.mix b/MissionEditor/data/FinalAlert2/marble.mix new file mode 100644 index 0000000..134cc0c Binary files /dev/null and b/MissionEditor/data/FinalAlert2/marble.mix differ diff --git a/MissionEditor/data/FinalAlert2/show_appdata.bat b/MissionEditor/data/FinalAlert2/show_appdata.bat new file mode 100644 index 0000000..1b7fce4 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/show_appdata.bat @@ -0,0 +1 @@ +start explorer "%LOCALAPPDATA%\FinalAlert 2" \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/show_log.bat b/MissionEditor/data/FinalAlert2/show_log.bat new file mode 100644 index 0000000..e682507 --- /dev/null +++ b/MissionEditor/data/FinalAlert2/show_log.bat @@ -0,0 +1 @@ +start notepad "%LOCALAPPDATA%/FinalAlert 2/finalalert2log.txt" \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/FSData.ini b/MissionEditor/data/FinalSun/FSData.ini new file mode 100644 index 0000000..ef65e53 --- /dev/null +++ b/MissionEditor/data/FinalSun/FSData.ini @@ -0,0 +1,580 @@ +; FSData.ini - Data file for FinalSun +; This file is used for some things which are not known how to parse from the rules.ini +; or for other data +; last change: Matthias Wagner, Feb 12, 2024 + +[Debug] +;DisplayAllOverlay=Yes ; Doesn´t cripple the overlay list in any way +;EnableTrackLogic=Yes ; Enables Track Logic +;IgnoreSHPImageHeadUnused=Yes ; Use this *carefully* to make SHP graphics of some mods work that incorrectly have the shadow flag set +AllowTunnels=yes +AllowUnidirectionalTunnels=yes +;ShowBuildingsWithToTile=no + +[ForceUnitPalettePrefix] +0=TIBTRE +1=VEINHOLE +2=BIGBLU + +[ForceIsoPalettePrefix] + +[ForceOvrlIsoPalettePrefix] +0=CRAT + +[ForceOvrlUnitPalettePrefix] + +; actually, barrels for non-voxel base units +[BuildingVoxelBarrels] +MMCHX=0 +MMCHY=-20 + +[VehicleVoxelTurrets] + +[StdBrushSize] +ClearTile=2 +RoughTile=2 +SandTile=2 +GreenTile=2 +PaveTile=2 +WaterSet=2 + +[MinBrushSizeInWater] ; if completely surrounded by water +ClearTile=2 +RoughTile=2 +SandTile=2 +GreenTile=2 +PaveTile=2 + +; SlopeSetPieces for cliffs have a specific direction. +; used for AutoLevel logic +; CURRENTLY IGNORED +[SlopeSetPiecesDirections] +Count=10 +0=Right_1 +1=Left_1 +2=Top_1 +3=Bottom_1 +4=Right_2 +5=Left_2 +6=Left_2 +7=Bottom_2 +8=Top_2 +9=Top_2 + +[TEMPERATELimits] +TreeMax=999 +;TreeMax=27 + +[SNOWLimits] +TreeMax=999 +;TreeMax=27 + +[URBANLimits] +TreeMax=999 +;TreeMax=27 + +; tileset ini overwritings +; only used by FinalAlert +[IgnoreSetTEMPERATE] + +[IgnoreSetSNOW] +0=8 +1=46 + +[UseSetTEMPERATE] +0=57 +1=79 + +[UseSetSNOW] + +[UseSetURBAN] + +; hacks for shore pieces +; shore id_pos=iswater +; pos: count from left top to right, then next "row" + +; But TS needs all :( +[ShoreTerrainTS] +0_0=0 +0_1=0 +0_2=1 +0_3=1 +1_0=0 +1_1=0 +2_0=0 +2_1=0 +3_0=0 +4_0=0 +4_1=0 +4_3=0 +5_0=0 +5_1=0 +5_2=0 +6_0=0 +7_0=0 +8_0=0 +8_2=0 +9_0=0 +9_2=0 +10_0=0 +10_2=0 +11_0=0 +12_0=0 +12_1=0 +12_3=0 +13_0=0 +13_3=0 +13_4=0 +14_2=0 +15_2=0 +16_2=0 +16_3=0 +17_2=0 +17_3=0 +18_2=0 +18_3=0 +19_1=0 +20_3=0 +20_4=0 +20_5=0 +21_2=0 +21_4=0 +21_5=0 +22_3=0 +23_3=0 +24_1=0 +24_3=0 +25_1=0 +25_3=0 +26_1=0 +26_3=0 +27_1=0 +28_1=0 +28_2=0 +28_5=0 +29_2=0 +29_4=0 +29_5=0 +30_1=0 +31_1=0 +32_0=0 +32_1=0 +32_2=0 +33_0=0 +33_1=0 +33_2=0 +34_0=0 +34_2=0 +34_3=0 +35_0=0 +35_2=0 +35_3=0 +36_1=0 +36_2=0 +36_3=0 +37_1=0 +37_2=0 +37_3=0 +38_0=0 +38_1=0 +38_3=0 +39_0=0 +39_1=0 +39_3=0 + +; tilesets that may be modified using the shore or a similar logic +[SoftTileSets] +ClearTile=1 +RoughTile=1 +ClearToRoughLat=1 +SandTile =1 +ClearToSandLat=1 +GreenTile=1 +ClearToGreenLat=1 +PaveTile=1 +MiscPaveTile =1 +ClearToPaveLat=1 +RoughGround=0; no +WaterSet=1 +ShorePieces=1 + +; corner strings are: cornerleft, cornerright, cornerbottom, cornertop + +[CliffBackData] +vertic_diag_c=2 +;vertic_diag_2=0 +vertic_diag_0=2 +vertic_diag_1=3 +;vertic_diag_3=1 ; unused at moment +vertic_diag_cornertop_c=1 +;vertic_diag_cornertop_1=0 +vertic_diag_cornertop_0=1 +horiz_c=4 +horiz_0=22 +horiz_1=23 +horiz_2=24 +horiz_3=25 ;2x1, not 2x2, unused at moment +horiz_cornerbottom_c=2 +horiz_cornerbottom_0=28 +horiz_cornerbottom_1=29 +horiz_cornertop_c=0 +;horiz_cornertop_0=31 +vertic_c=4 +vertic_0=34 +vertic_1=35 +vertic_2=36 +vertic_3=37 ;2x1, not 2x2, unused at moment +vertic_cornerright_c=2 +vertic_cornerright_0=29 +vertic_cornerright_1=28 + +[CliffFrontData] +vertic_diag_c=2 +vertic_diag_0=18 +vertic_diag_1=19 +;vertic_diag_2=20 +;vertic_diag_3=21 ; unused at moment +vertic_diag_cornerleft_c=1 +vertic_diag_cornerleft_0=20 +;vertic_diag_cornerleft_1=21 +vertic_diag_cornerright_c=2 +vertic_diag_cornerright_0=32 +vertic_diag_cornerright_1=33 +horiz_c=4 +horiz_0=4 +horiz_1=5 +horiz_2=6 +horiz_3=7 ;2x1, not 2x2, unused at moment +horiz_cornertop_c=1 +horiz_cornertop_0=1 +horiz_diag_c=6 +horiz_diag_0=8 +horiz_diag_1=9 +horiz_diag_2=10 +horiz_diag_3=11 ; unused at moment +horiz_diag_4=12 ; unused at moment +horiz_diag_5=13 ; unused at moment +vertic_c=4 +vertic_0=14 +vertic_1=15 +vertic_2=16 +vertic_3=17 ;2x1, not 2x2, unused at moment +vertic_cornerleft_c=1 +vertic_cornerleft_0=21 + +; EVENTS AND ACTIONS +; param type format: Description,ListType +; ListTypes (all those not implemented yet but stubbed when this ini was written are marked with *): +; 0-Nothing +; 1-Houses +; 2-Teamtypes +; 3-UnitTypes +; 4-InfantryTypes +; 5-AircraftTypes +; 6-BuildingTypes +; 7-Videos +; 8-tutorial texts +; 9-Triggers +; 10-yes/no +; 11=sounds * +; 12=themes * +; 13=speeches * +; 14=special weapons +; 15=animations +; 16=particles +; 17=waypoints +; 18=crate types * +; 19=speech bubble types * +; 20=Global variables <--- wrong, local variables! +; 21=.CSF strings (RA2 only) * +; 22=Tag * +; 23=Meteors * +; 24=Weapons * +; 25=Light behavior * +; 26=Shower * + + +[ParamTypes] +0=Unused,0 +1=Unknown,0 +2=House,1 +3=Local variable,20 +4=Time,0 +5=Credits,0 +6=Number,0 +7=Teamtype,2 +8=Building,6 +9=Aircraft,5 +10=Infantry,4 +11=Unit,3 +12=Movie,7 +13=Text,8 +14=Trigger,9 +15=Enabled,10 +16=Sound,11 +17=Theme,12 +18=Speech,13 +19=Steps,0 +20=Super weapon,14 +21=Left,0 +22=Top,0 +23=Right,0 +24=Bottom,0 +25=Animation,15 +26=Particle,16 +27=Duration,0 +28=Speed,0 +29=Meteor size,29 +30=Waypoint,17 +31=Crate type,18 +32=Speech bubble,19 +33=String,21 +34=Action,9 +35=Global variable,0 +36=Special,0 +37=Activated,10 +38=Tag,22 +39=Techtype,0 +40=Quarry,0 +41=Weapon,24 +42=Light behavior,25 +43=Event,9 +44=Shower,26 +45=Float value,0 + + +; events format: +; #=Description, P1 type, P2 type, TagNeeded, Obsolete,Desc2,UsedInTS,UsedInRA2,ID +; negative number for type currently not supported (only Actions do support yet)! +; NOTE: Actions not listed in [Events] but in [EventsRA2] will be ignored. Use the "used in RA2" to support them. +; NOTE: To overwrite TS events with RA2 special ones, add the new event to the [EventsRA2] section. +; NOTE: ID must be the same like # +[Events] +0=-No Event-,0,0,0,0,This is a null event. There is no need to ever use this in a real trigger.,1,1,0 +1=Entered by...,0,2,0,0,Triggers when an infantry or vehicle enters the attached object. Typically this trigger is attached to a building or a cell.,1,1,1 +2=Spied upon,0,0,0,0,Detects when a spy has entered the attached building.,1,1,2 +3=Thieved by...,0,2,0,0,Triggers when a thief steals money from the specified house.,1,1,3 +4=Discovered by player,0,0,0,0,Detects when the attached object has been discovered by the player. Discovered means reavealed from under the shroud.,1,1,4 +5=House Discovered...,0,2,0,0,Triggers when the specified house has any of its units or buildings discovered by the player.,1,1,5 +6=Attacked by any house,0,0,0,0,Triggers when the attached unit is attacked in some manner. Incidental damage or friendly fire does not count.,1,1,6 +7=Destroyed by any house,0,0,0,0,Triggers when the attached object has been destroyed. Destroyed by incidental damage or friendly fire doesn't count.,1,1,7 +8=Any Event,0,0,0,0,When used alone%1 it will force the trigger to spring immediately.,1,1,8 +9=Destroyed%1 Units%1 All...,0,2,0,0,Triggers when all units of the specified house have been destroyed. Typically used for end of game conditions.,1,1,9 +10=Destroyed%1 Buildings%1 All...,0,2,0,0,Triggers when all buildings of the specified side have been destroyed. Typically used for end of game conditions.,1,1,10 +11=Destroyed%1 All...,0,2,0,0,Triggers when all objects owned by the specified house have been destroyed. This is the normal (destroy everyone) trigger condition for end of game.,1,1,11 +12=Credits exceed...,0,6,0,0,Triggers when the house (for this trigger) credit total exceeds this specified amount.,1,1,12 +13=Elapsed Time...,0,6,0,0,Triggers when the elapsed time has expired. This time is initialized when the trigger is created. Timer is reset whenever trigger is sprung when trigger is 'persistant'.,1,1,13 +14=Mission Timer Expired,0,0,0,0,Triggers when the global mission timer (as displayed on the screen) has reached zero.,1,1,14 +15=Destroyed%1 Buildings%1 #...,0,6,0,0,Triggers when the number of buildings%1 owned by the trigger's specified house%1 have been destroyed.,1,1,15 +16=Destroyed%1 Units%1 #...,0,6,0,0,Triggers when the number of units%1 owned by the trigger's specified house%1 have been destroyed.,1,1,16 +17=No Factories left,0,0,0,0,Triggers when there are no factories left for the house specified in the trigger.,1,1,17 +18=Civilians Evacuated,0,0,0,0,Triggers when civilians have been evacuated (left the map).,1,1,18 +19=Build Building Type...,0,8,0,0,When the trigger's house builds the building type specified%1 then this event will spring.,1,1,19 +20=Build Unit Type...,0,11,0,0,When the trigger's house builds the unit type specified%1 then this event will spring.,1,1,20 +21=Build Infantry Type...,0,10,0,0,When the trigger's house builds the infantry type specified%1 then this event will spring.,1,1,21 +22=Build Aircraft Type...,0,9,0,0,When the trigger's house builds the aircraft type specified%1 then this event will spring.,1,1,22 +23=Leaves map (team)...,-1,7,0,0,Triggers when the specified team leaves the map. If the team is destroyed%1 it won't trigger. If all but one member is destroyed and that last member leaves the map%1 it WILL spring.,1,1,23 +24=Zone Entry by...,0,2,0,0,Triggers when a unit of the dpecified house enters the same zone that this trigger is located in. This trigger must be located in a cell and only a cell.,1,1,24 +25=Crosses Horizontal Line...,0,2,0,0,Triggers when a unit of the specified house crosses the horizontal line as indicated by the location of this trigger. This trigger must be placed in a cell.,1,1,25 +26=Crosses Vertical Line...,0,2,0,0,Triggers when a unit of the specified house crosses the vertical line as indicated by the location of this trigger. This trigger must be placed in a cell.,1,1,26 +27=Global is set...,0,35,0,0,Triggers when the specifed global (named in Globals.INI) is turned on.,1,1,27 +28=Global is clear...,0,35,0,0,Triggers when the specified global (named in Globals.INI) is turned off.,1,1,28 +29=Destroyed by anything [not infiltrate],0,0,0,0,Triggers when attached object is destroyed%1 but not if it infiltrates a building/unit.,1,1,29 +30=Low Power...,0,2,0,0,Triggers when the specified house's power falls below 100% level.,1,1,30 +31=Bridge destroyed,0,0,0,0,Triggers when the attached bridge is destroyed. A bridge is considered destroyed when an impassable gap is created in the bridge.,1,1,31 +32=Building exists...,0,8,0,0,Triggers when the building (owned by the house of this trigger) specified exists on the map. This works for buildings that are preexisting or constructed by deploying.,1,1,32 +33=Selected by player,0,0,0,0,Triggers when the unit is selected by the player. Use in single-player only.,1,1,33 +34=Comes near waypoint...,0,30,0,0,Triggers when the object comes near the specified waypoint.,1,1,34 +35=Enemy In Spotlight...,0,0,0,0,Triggers when an enemy unit enters the spotlight cast by the attached building.,1,1,35 +36=Local is set...,0,3,0,0,Triggers when the specifed local is turned on.,1,1,36 +37=Local is clear...,0,3,0,0,Triggers when the specified local is turned off.,1,1,37 +38=First damaged (combat only),0,0,0,0,Triggers when first suffering from combat damage from combat damage only.,1,1,38 +39=Half health (combat only),0,0,0,0,Triggers when damaged to half health >from combat damage only.,1,1,39 +40=Quarter health (combat only),0,0,0,0,Triggers when damaged to quarter health from combat damage only.,1,1,40 +41=First damaged (any source),0,0,0,0,Triggers when first suffering from combat damage from any source.,1,1,41 +42=Half health (any source),0,0,0,0,Triggers when damaged to half health >from any source.,1,1,42 +43=Quarter health (any source),0,0,0,0,Triggers when damaged to quarter health from any source.,1,1,43 +44=Attacked by (house)...,0,2,0,0,When attacked by some unit of specified house.,1,1,44 +45=Ambient light <= ...,0,6,0,0,Triggers when the ambient light drops below a certain level. Use numbers between 0 and 100.,1,1,45 +46=Ambient light >= ...,0,6,0,0,Triggers when the ambient light rises above a certain level. Use numbers between 0 and 100.,1,1,46 +47=Elapsed Scenario Time...,0,6,0,0,When time has elapsed since start of scenario.,1,1,47 +48=Destroyed by anything,0,0,0,0,Triggers when destroyed by anything what-so-ever.,1,1,48 +49=Pickup Crate,0,0,0,0,When crate is picked up object the trigger is attached to.,1,1,49 +50=Pickup Crate (any),0,0,0,0,When crate is picked up by any unit.,1,1,50 +51=Random delay...,0,6,0,0,Delays a random time between 50 and 150 percent of time specified.,1,1,51 +52=Credits below...,0,6,0,0,Triggers when the house (for this trigger) credit total is below this specified amount.,1,1,52 +53=Player under EMP effect,0,2,0,0,Specific house is under EMP effect,1,1,53 + + +; action format: +; #=Description, P1 type, P2 type, P3 type, P4 type, P5Type, P6Type, uses waypoint, uses tag, Obsolete, used in TS, used in RA2, ID +; if using negative number for type, param will be set to the absolute value of this number +; NOTE: Actions not listed in [Actions] but in [ActionsRA2] will be ignored. Use the "used in RA2" to support them. +; NOTE: To overwrite TS actions with RA2 special ones, add the new action to the [ActionsRA2] section. +; NOTE: ID must be the same like # +[Actions] +0=-No Action-,0,0,0,0,0,0,0,0,0,This is a null action. It will do nothing and is equivalent to not having an action at all. Why use it?,1,1,0 +1=Winner is...,0,2,0,0,0,0,0,0,0,The winner will be forced to be the house specified. The game will end immediately. Typically%1 the player's house is specified.,1,1,1 +2=Loser is...,0,2,0,0,0,0,0,0,0,The loser will be force to be the house specified. The game will end immediately. Typically%1 the player's house is specified.,1,1,2 +3=Production Begins...,0,2,0,0,0,0,0,0,0,The computer's house (as specified) will begin production of units and structures.,1,1,3 +4=Create Team...,-1,7,0,0,0,0,0,0,0,Creates a team of the type specified (owned by the house of this trigger). The team member are NOT automatically created however.,1,1,4 +5=Destroy Team...,-1,7,0,0,0,0,0,0,0,Destroys all instances of the team type specified. The units in those existing teams will remain and be available for recruiting into other teams.,1,1,5 +6=All to Hunt...,0,2,0,0,0,0,0,0,0,Forces all units%1 of the house specified%1 into 'hunt' mode. They will seek out and destroy their enemies.,1,1,6 +7=Reinforcement (team)...,-1,7,0,0,0,0,0,0,0,Create a reinforcement of the specified team. The members of the team WILL be created magically by this action.,1,1,7 +8=Drop Zone Flare (waypoint)...,0,30,0,0,0,0,0,0,0,Display a drop zone flair at the waypoint specified. The map will also be reaveald around that location.,1,1,8 +9=Fire Sale...,0,2,0,0,0,0,0,0,0,Cause all buildings of the specified house to be sold (for cash and prizes). Typically this is used in the final assault by the computer.,1,1,9 +10=Play Movie...,0,12,0,0,0,0,0,0,0,Displays the specified movie (full screen). The game is paused while this occurs and resumes normally after it completes.,1,1,10 +11=Text Trigger...,0,13,0,0,0,0,0,0,0,Display the text identified by the label in Tutorial.ini.,1,1,11 +12=Destroy Trigger...,-2,14,0,0,0,0,0,0,0,Destroy all current instances of the trigger type specified. This does not prevent future instances of that trigger >from being created.,1,1,12 +13=Autocreate Begins...,0,2,0,0,0,0,0,0,0,Initiates autocreate for the house specified. This will cause the computer's house to build autocreate teams as it sees fit.,1,1,13 +14=Change House...,0,2,0,0,0,0,0,0,0,Changes owning house to the one specified for attached objects.,1,1,14 +15=Allow Win,0,0,0,0,0,0,0,0,0,Removes one 'blockage' from allowing the player to win. The blockage number is equal the number of triggers created that have this action.,1,1,15 +16=Reveal all map,0,0,0,0,0,0,0,0,0,Reveals the entire map to all players.,1,1,16 +17=Reveal around waypoint...,0,30,0,0,0,0,0,0,0,Reveals a region of the map to the player around the waypoint specified.,1,1,17 +18=Reveal zone of waypoint...,0,30,0,0,0,0,0,0,0,Reveals all cells that share the same zone as the waypoing specified. This yields some wierd results. Use with caution.,1,1,18 +19=Play sound effect...,0,16,0,0,0,0,0,0,0,Plays the sound effect specified. Use numbers from Sound.ini and Sound01.ini and then apply the sound system.,1,1,19 +20=Play music theme...,0,17,0,0,0,0,0,0,0,Plays the music theme specified. Look up the number of the song in Theme.ini then Add 1.,1,1,20 +21=Play speech...,0,18,0,0,0,0,0,0,0,Plays the speech sound specified,1,1,21 +22=Force Trigger...,-2,14,0,0,0,0,0,0,0,Force all triggers of this specified type to spring regardless of what it's event flags may indicate.,1,1,22 +23=Timer Start,0,0,0,0,0,0,0,0,0,Start the global mission timer.,1,1,23 +24=Timer Stop,0,0,0,0,0,0,0,0,0,Stop the global mission timer.,1,1,24 +25=Timer Extend...,0,6,0,0,0,0,0,0,0,Extend the global mission timer by the time specified.,1,1,25 +26=Timer Shorten...,0,6,0,0,0,0,0,0,0,Short the global mission timer by the time specified. It can never be reduced below 'zero' time.,1,1,26 +27=Timer Set...,0,6,0,0,0,0,0,0,0,Set the global mission timer to the value specified.,1,1,27 +28=Global Set...,0,35,0,0,0,0,0,0,0,Set the global flag. Global flags are named in the file Globals.INI. Global flags can be either 'on/set/true' or 'off/clear/false'. Globals are reset by saved games.,1,1,28 +29=Global Clear...,0,35,0,0,0,0,0,0,0,Clear the global flag. Global flags are named in the file Globals.INI. Global flags can either be 'on/set/true' or 'off/clear/false'. Globals are reset by saved games.,1,1,29 +30=Auto Base Building...,0,37,0,0,0,0,0,0,0,Initialize the computer skirmish mode build control to either 'on' or 'off' state. When 'on'%1 the computer takes over as if it were in skirmish mode. (gs make sure he has a con yard),1,1,30 +31=Grow shroud one 'step',0,0,0,0,0,0,0,0,0,Increase the shroud darkness by one step (cell).,1,1,31 +32=Destroy attached building,0,0,0,0,0,0,0,0,0,Destroy any buildings%1 bridges%1 or units that this trigger is attached to.,1,1,32 +33=Add 1-time special weapon...,0,36,0,0,0,0,0,0,0,Add a one-shot special weapon (as indicated) to the trigger's house.,1,1,33 +34=Add repeating special weapon...,0,36,0,0,0,0,0,0,0,Add a permanent special weapon (as indicated) to the trigger's house.,1,1,34 +35=Preferred target...,0,40,0,0,0,0,0,0,0,Specify what the trigger's house should use as its preferred target when using special weapon attacks.,1,1,35 +36=All change house...,0,2,0,0,0,0,0,0,0,All objects of one house change ownership to specified house.,1,1,36 +37=Make ally...,0,2,0,0,0,0,0,0,0,Cause this trigger's house to ally with the house specified.,1,1,37 +38=Make enemy...,0,2,0,0,0,0,0,0,0,Cause this trigger's house to un-ally (declare war) with the house specified.,1,1,38 +39=Change Zoom Level...,0,6,0,0,0,0,0,0,0,Changes the zoom out level of the player's radar map. Use 1 for normal view%1 2 for zoomed out.,1,1,39 +40=Resize Player View...,0,0,21,22,23,24,0,0,0,Changes the player's viewing rectangle into the map. Enter as: x%1y%1w%1h where x%1y gives the upper left corner and w%1h give the width and height.,1,1,40 +41=Play Anim At...,0,25,0,0,0,0,1,0,0,Plays the specified anim in the specified cell. Use numbers from [Animations] and either subtract 2 or 5 (depending on the position in the list),1,1,41 +42=Do Explosion At...,0,41,0,0,0,0,1,0,0,Creates an explosion in the specified cell%1 using the specified warhead.,1,1,42 +43=Meteor Impact At...,0,29,0,0,0,0,1,0,0,Sends a meteor at the specified cell.,1,0,43 +44=Ion Storm start...,0,6,0,0,0,0,0,0,0,Starts an ion storm sequence to run for the specified number of game frames.,1,0,44 +45=Ion Storm stop...,0,0,0,0,0,0,0,0,0,End an Ion storm in progress.,1,0,45 +46=Lock input,0,0,0,0,0,0,0,0,0,Disables user input.,1,1,46 +47=Unlock input,0,0,0,0,0,0,0,0,0,Enables user input.,1,1,47 +48=Center Camera at Waypoint...,0,28,0,0,0,0,1,0,0,Moves the tactical view to a specified waypoint at the specified speed. Use 1 through 4 for good results.,1,1,48 +49=Zoom in,0,0,0,0,0,0,0,0,0,Zooms the tactical map in.,1,1,49 +50=Zoom out,0,0,0,0,0,0,0,0,0,Zooms the tactical map out.,1,1,50 +51=Reshroud Map,0,0,0,0,0,0,0,0,0,Reshrouds the entire map for all players.,1,1,51 +52=Change Light Behavior,0,42,0,0,0,0,0,0,0,Changes the way a building spotlight behaves. Attach this trigger to a building that casts a spotlight. 0= no Spotlight - 1= Circle - 2= Rules.ini settings (affected by direction) - 3= Unit in Spotlight,1,1,52 +53=Enable Trigger,-2,14,0,0,0,0,0,0,0,Enables the target trigger.,1,1,53 +54=Disable Trigger,-2,14,0,0,0,0,0,0,0,Disables the target trigger.,1,1,54 +55=Create Radar Event,0,43,0,0,0,0,1,0,0,Creates a radar event at the specified waypoint,1,1,55 +56=Local Set...,0,3,0,0,0,0,0,0,0,Set the local flag. Local flags can be either 'on/set/true' or 'off/clear/false'.,1,1,56 +57=Local Clear...,0,3,0,0,0,0,0,0,0,Clear the local flag. Local flags can either be 'on/set/true' or 'off/clear/false'.,1,1,57 +58=Meteor Shower At...,0,44,0,0,0,0,1,0,0,Creates a meteor shower around the specified waypoint.,1,1,58 +59=Reduce Tiberium At...,0,30,0,0,0,0,0,0,0,Reduces Tiberium around the specified waypoint.,0,0,59 +60=Sell building,0,0,0,0,0,0,0,0,0,Sells the building attached to this trigger.,1,1,60 +61=Turn off building,0,0,0,0,0,0,0,0,0,Turn off building attached to this trigger.,1,1,61 +62=Turn on building,0,0,0,0,0,0,0,0,0,Turn on building attached to this trigger.,1,1,62 +63=Apply 100 damage at...,0,30,0,0,0,0,0,0,0,Applies 100 points of HE damage at location.,1,1,63 +64=Light flash (small) at...,0,30,0,0,0,0,0,0,0,Shows a small light flash at location.,1,1,64 +65=Light flash (medium) at...,0,30,0,0,0,0,0,0,0,Shows a medium light flash at location.,1,1,65 +66=Light flash (large) at...,0,30,0,0,0,0,0,0,0,Shows a large light flash at location.,1,1,66 +67=Announce Win,0,0,0,0,0,0,0,0,0,Announce that player has won.,1,1,67 +68=Announce Lose,0,0,0,0,0,0,0,0,0,Announce that player has lost.,1,1,68 +69=Force end,0,0,0,0,0,0,0,0,0,Force end of scenario.,1,1,69 +70=Destroy Tag...,-3,38,0,0,0,0,0,0,0,Destroy tag and all attached triggers.,1,1,70 +71=Set ambient step...,0,45,0,0,0,0,0,0,0,Sets ambient light fade step value.,1,1,71 +72=Set ambient rate...,0,45,0,0,0,0,0,0,0,Sets ambient light fade rate.,1,1,72 +73=Set ambient light...,0,6,0,0,0,0,0,0,0,Fades ambient light to new lighting level. Use numbers between 0 and 100.,1,1,73 +74=AI triggers begin...,0,2,0,0,0,0,0,0,0,Start AI triggers for specified house.,1,1,74 +75=AI triggers stop...,0,2,0,0,0,0,0,0,0,Stop AI triggers for specified house.,1,1,75 +76=Ratio of AI trigger teams...,0,6,0,0,0,0,0,0,0,AI percentage of teams created for AI triggers (100 = all for AI trigger teams%1 0 = all for regular teams),1,1,76 +77=Ratio of team aircraft...,0,6,0,0,0,0,0,0,0,AI percentage of aircraft created for teams (100 = all for teams%1 0 = all random),1,1,77 +78=Ratio of team infantry...,0,6,0,0,0,0,0,0,0,AI percentage of infantry created for teams (100 = all for teams%1 0 = all random),1,1,78 +79=Ratio of team units...,0,6,0,0,0,0,0,0,0,AI percentage of units created for teams (100 = all for teams%1 0 = all random),1,1,79 +80=Reinforcement (team) [at waypoint]...,-1,7,0,0,0,0,1,0,0,Create reinforcement team at special waypoint location. The units will appear at this point. Magical-poof style.,1,1,80 +81=Wakeup self,0,0,0,0,0,0,0,0,0,Breaks out of sleep or harmless mode so as to enter guard mode.,1,1,81 +82=Wakeup all sleepers,0,0,0,0,0,0,0,0,0,Breaks all units out of sleep mode.,1,1,82 +83=Wakeup all harmless,0,0,0,0,0,0,0,0,0,Breaks all out of harmless mode.,1,1,83 +84=Wakeup group...,0,6,0,0,0,0,0,0,0,Wakeup all units of specified group.,1,1,84 +85=Vein growth...,0,37,0,0,0,0,0,0,0,Control if veins grow or not.,1,1,85 +86=Tiberium growth...,0,37,0,0,0,0,0,0,0,Control if Tiberium grows or not.,1,1,86 +87=Ice growth...,0,37,0,0,0,0,0,0,0,Control if ice grows or not.,1,1,87 +88=Particle Anim at...,0,26,0,0,0,0,1,0,0,Show particle animation at location.,1,1,88 +89=Remove Particle Anim at...,0,30,0,0,0,0,0,0,0,Delete particle anims at specified location.,1,1,89 +90=Lightning strike at...,0,30,0,0,0,0,0,0,0,A single Ion Storm lightning strike.,1,1,90 +91=Go Berzerk,0,0,0,0,0,0,0,0,0,Attached object (cyborg) goes berzerk.,1,1,91 +92=Activate Firestorm Defense,0,0,0,0,0,0,0,0,0,Turns on a house's firestorm defense.,0,0,92 +93=Deactivate Firestorm Defense,0,0,0,0,0,0,0,0,0,Turns off a house's firestorm defense.,0,0,93 +94=Ion-cannon strike...,0,30,0,0,0,0,0,0,0,Fires Ion-Cannon at waypoint specified.,0,0,94 +95=Nuke strike...,0,0,0,0,0,0,1,0,0,Fires Nuke at waypoint specified from nearest edge.,1,1,95 +96=Chem-missile strike...,0,30,0,0,0,0,0,0,0,Fires Chemical missile at waypoint specified.,0,0,96 +97=Toggle Train Cargo,0,0,0,0,0,0,0,0,0,Toggles state of cargo train dropping crate.,1,1,97 +98=Play Sound Effect (Random)...,0,16,0,0,0,0,0,0,0,Plays sound effect at random waypoint. Rules of action 19 apply.,1,1,98 +99=Play Sound Effect At waypoint...,0,16,0,0,0,0,1,0,0,Plays sound effect specified at waypoint specified. Rules of action 19 apply.,1,1,99 +100=Play Ingame Movie...,0,12,0,0,0,0,0,0,0,Displays the specified movie ingame. Player still has control of interface and units.,1,1,100 +101=Reshroud Map At...,0,30,0,0,0,0,0,0,0,Does an anti-map ping at waypoint specified.,1,1,101 +102=Lightning Storm strike...,0,0,0,0,0,0,1,0,0,Lightning storm owned by owner of trigger at waypoint.,1,1,102 +103=Timer Text...,-4,13,0,0,0,0,0,0,0,What text label to display with timer (i.e. actual text is in game.str).,1,1,103 +104=Flash Team...,-5,7,0,0,0,0,0,0,0,Flashes the specified team for the specified number of frames,1,1,104 +105=Talk Bubble...,-1,7,0,0,0,0,0,0,0,Displays talk bubble over unit,1,1,105 + +[BridgesTS] + +[SpecialOverlayTS] + +[IgnoreTS] +0=WEEDGUY +1=NHUNTER +2=GHUNTER +3=JEEP +; legacy Red Alert leftovers +60=CR1 +61=CR2 +62=CR3 +63=CR4 +64=CR5 +65=CR6 +66=BURN01 +67=BURN02 +68=BURN03 +69=BURN04 +70=BURN05 +71=BURN06 +72=BURN07 +73=BURN08 +74=BURN09 +75=BURN10 +76=BURN11 +77=BURN12 +78=BURN13 +79=BURN14 +80=BURN15 +81=BURN16 + +[IgnoreTerrainTS] +0=NAWALL +1=GAWALL + +[IgnoreTemperateTS] +0=ABAN01 +1=ABAN02 +2=ABAN03 +3=ABAN04 +4=ABAN05 +5=ABAN06 +6=ABAN07 +7=ABAN08 +8=ABAN09 +9=ABAN10 +10=ABAN11 +11=ABAN12 +12=ABAN13 +13=ABAN14 +14=ABAN15 +15=ABAN16 +16=ABAN17 +17=ABAN18 + +[IgnoreSnowTS] diff --git a/MissionEditor/data/FinalSun/FSLanguage.ini b/MissionEditor/data/FinalSun/FSLanguage.ini new file mode 100644 index 0000000..fb606ec --- /dev/null +++ b/MissionEditor/data/FinalSun/FSLanguage.ini @@ -0,0 +1,949 @@ +; ******************************* +; FSLanguage.ini +; +; String file of FinalSun +; Last change: MW 10.4.2001 +; ******************************* + +; The languages available in FinalSun +[Languages] +0=English +1=German +2=Swedish +3=Nederlands + +; Every language has a own header section, defining the name of the language as it is called in that language, +; the version of the language data, and the file extension used for this language +; Note that the "Name" must be unique (so, "Name" of English must not be the same like "Name" of German)! + +[EnglishHeader] +Name=English +Version=1 +ExtensionName=ENG + +[GermanHeader] +Name=Deutsch +Version=1 +ExtensionName=DEU + +[SwedishHeader] +Name=Svenska +Version=1 +ExtensionName=SWE + +[NederlandsHeader] +Name=Nederlands +Version=1 +ExtensionName=NL + +; Now all the strings for each language +; If a specific string is not found in a language, the english string will be used. +; %9 is translated to FinalSun or FinalAlert + +[German-StringsRA2] +Err_TSNotInstalled=C&C Alarmstufe Rot 2 ist nicht korrekt installiert (TibSun.mix konnte nicht geladen werden) +FileRunTiberianSunHelp=C&C Alarmstufe Rot 2 starten +SAVEDLG_FILETYPES=AR2 Karten|*.mpr%8*.map|AR2 Mehrspielerkarten-Erweiterungen (*.mmx)|*.mmx|AR2 Mehrspielerkarten (*.mpr)|*.mpr|AR2 Einzelspielerkarten (*.map)|*.map| +GrTibObList=Erz +BlTibObList=Kristalle +GroundSandObListURB=Helles Pflaster +GroundRoughObListURB=Erde +GroundGreenObListURB=Gras +GroundPaveObListURB=Dunkles Pflaster +GroundClearObListTEM=Helles Gras +GroundRoughObListTEM=Dunkles Gras +GroundGreenObListTEM=Sand +GroundClearObListSNO=Schnee +GroundSandObListSNO=Verschmutzter Schnee +GroundRoughObListSNO=Gras +GroundGreenObListSNO=Eis +SAVEDLG_FILETYPES=AR2-Karten|*.mpr%8*.map%8*.mmx|AR2 Mehrspielerkarten|*.mpr|AR2 Einzelspielerkarten|*.map|AR2 Mehrspielerkarten-Erweiterungen|*.mmx| +Allied=Allierte +Soviet=Sowjets +Other=Andere + +[German-Strings] +; messages for message boxes +Err_InsufficientResources=Aufgrund ungenĂ¼gender Ressourcen konnte zumindest ein Dialog nicht erstellt werden. Sie sollten deswegen Windows komplett neu starten. Das Programm wird jetzt beendet... Tip: Beenden Sie alle Programme, bevor Sie %9 starten +Err_TSNotInstalled=Tiberian Sun ist nicht korrekt installiert (TibSun.mix konnte nicht geladen werden) +Err_CreateErr=Fenster konnte nicht erstellt werden. Versuchen Sie, andere Fenster zu schliessen. +MainDialogExitQuestion=Sind Sie sicher, dass Sie das Programm beenden wollen? Ă„nderungen an der Karte gehen dabei verloren! +MainDialogExitQuestionCap=%9 beenden +AttachMapToShell=Dateien mit der Endung mpr und/oder map sind momentan mit einem anderen Programm verbunden. Wollen Sie, dass bei einem Doppelklick auf diese Dateien %9 diese Dateien öffnet? +AddHouse=Bitte geben Sie die ID des neuen Hauses an (wie GDI und Nod): +AddHouseCap=Neues Haus +DeleteHouse=Sind Sie sicher, dass Sie das Haus %1 löschen wollen? +DeleteHouseCap=Haus löschen +RestartNeeded=Um die Ă„nderungen komplett zu Ă¼bernehmen, ist ein Neustart von %9 erforderlich. +ReInitPic=Es ist nötig, die Grafiken neu zu laden. Dies kann einige Zeit dauern, bitte Geduld. +ReInitPicCap=Neuladen der Grafiken +StrChangeHeight=Geben Sie den Höhenunterschied an, um den jedes Feld auf der Karte verschoben wird. Negative Werte sind erlaubt. +StrChangeHeightCap=Höhe ändern +StrChangeHeightErr=Fehler, durch diese Ă„nderung wĂ¼rde die Karte falsch dargestellt! +StrChangeHeightErrCap=Fehler +ExplainEasyView=%9 startet automatisch im Anfänger-Modus. Dabei sind einige Optionen nicht verfĂ¼gbar, die im Profi-Modus unterstĂ¼tzt werden. Um in den Profi-Modus zu wechseln, deaktivieren Sie die Option "Anfängermodus" im MenĂ¼ Optionen +ExplainEasyViewCap=Anfänger-Modus +FileSaved=Karte "%1" gespeichert + +; general strings +OK=OK +Cancel=Abbrechen +None=Keiner +Yes=Ja +No=Nein + +; saving dialog +SAVEDLG_FILETYPES=TS Karten|*.mpr%8*.map|TS Mehrspielerkarten|*.mpr|TS Einzelspielerkarten|*.map| + +; tool tip strings +TT_TriggerHouse=Bestimmt das Haus, fĂ¼r das der Auslöser ausgefĂ¼hrt wird + +; error strings for map validation +MV_NoMap=Dies ist keine Karte +MV_NoBasic=Generelle Einstellungen sind nicht vorhanden +MV_NoName=Die Karte hat keinen Namen (Bearbeiten->Generell) +MV_PackMissing=Ein oder mehrere Packs (wie IsoMapPack5, OverlayPack, etc.) fehlen. Tiberian Sun akzeptiert die Karte möglicherweise nicht. +MV_>100Waypoint=Die Karte hat mindestens einen Wegpunkt mit einer ID grĂ¶ĂŸer als 99 +MV_HousesButNoPlayer=Es sind Häuser definiert, jedoch wurde der menschliche Spieler nicht korrekt gesetzt +MV_HousesInMultiplayer=Dies scheint eine Mehrspielerkarte zu sein, auf der Häuser definiert sind +MV_HousesNoWaypoints=Multiplayerkarten benötigen die Wegpunkte 0-7 als Startposition +MV_TriggerMissing=Trigger %1 fehlt (Verweis von %2 %3) +MV_TaskForceMissing=Taskforce %1 fehlt (Verweis von Teamtype %2) +MV_ScripttypeMissing=Scripttype %1 fehlt (Verweis von Teamtype %2) +MV_TagMissing=Tag %1 fehlt (Verweis von %2 %3) +MV_OfficialYes=Offizielle Karte - automatischer Kartentransfer abgeschaltet (Bei Speicherung als MMX Datei ignorieren) +MV_Not8Waypoints=Nur bei AR2 Version vor 1.005: Offiziell ist auf Nein gesetzt, aber die Wegpunkte 0-7 sind nicht alle vorhanden (teilweise zufällige Startpunkte, bei Speicherung als MMX Datei ignorieren) +MV_TubeCounterpartMissing=Die Tunnelröhre %5 (%1, %2) -> (%3, %4) hat kein GegenstĂ¼ck (%3, %4) -> (%1, %2).\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nDas GegenstĂ¼ck muss nicht dem gleichen Pfad folgen, aber die Start- und Endkoordinaten mĂ¼ssen umgedreht sein. +MV_TubeStartNotUnique=Die Tunnelröhre %5 (%1, %2) -> (%3, %4) hat dieselben Anfangskoordinaten wie %6 andere Tunnelröhren.\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nNur eine Tunnelröhre darf in einer Zelle anfangen. +MV_TubeEndNotUnique=Die Tunnelröhre %5 (%1, %2) -> (%3, %4) hat dieselben Endkoordinaten wie %6 andere Tunnelröhren.\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nNur eine Tunnelröhre darf in einer Zelle enden. +MV_TubeInvalidCounterpartEnd=Zur Tunnelröhre %5 (%1, %2) -> (%3, %4) gibt es %6 andere Tunnelröhren die die Startkoordinaten dieser Röhre als Endkoordinaten haben, aber die Endkoordinaten dieser Röhre entsprechen nicht den Startkoordinaten der anderen Röhren.\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nEin GegenstĂ¼ck einer Tunnelröhre muss sowohl Start- als auch Endkoordinaten umgedreht haben. +MV_TubeInvalidCounterpartStart=Zur Tunnelröhre %5 (%1, %2) -> (%3, %4) gibt es %6 andere Tunnelröhren die die Endkoordinaten dieser Röhre als Startkoordinaten haben, aber die Startkoordinaten dieser Röhre entsprechen nicht den Endkoordinaten der anderen Röhren.\nDies wird zu falschem Verhalten und AbstĂ¼rzen im Spiel fĂ¼hren.\nEin GegenstĂ¼ck einer Tunnelröhre muss sowohl Start- als auch Endkoordinaten umgedreht haben. + +; tip dialog +CG_IDS_DIDYOUKNOW=Wussten Sie bereits.... +CG_IDS_FILE_ABSENT=Tips-Datei nicht gefunden +CG_IDP_FILE_CORRUPT=Syntax-Fehler in der Tips-Datei +TipDialogNext=Nächster Tip +TipDialogShowAtStartup=Tips beim Starten anzeigen +TipDialogClose=Schliessen +TipDialogCaption=Tip des Tages + + +; main dialog strings +MainDialogCaption=%9 +NoMapLoaded=keine Karte geladen +NewMap=Neue Karte +FileNewHelp=Assistenten zum Erstellen einer neuen Karte starten +FileOpenHelp=Ă–ffen einer bereits bestehenden Karte +FileSaveHelp=Speichern der Karte +FileSaveAsHelp=Speichern der Karte unter einem anderen Dateinamen +FileImportModHelp=Importieren eines *.rul - Mods in die Karte +FileCheckMapHelp=ĂœberprĂ¼fen der Karte auf mögliche Fehler +FileQuitHelp=%9 beenden +FileRunTiberianSunHelp=C&C 3 Tiberian Sun starten +HelpInfoHelp=Informationen Ă¼ber %9 anzeigen +HelpTipOfTheDayHelp=Tip des Tages anzeigen +OptionsShowMapViewHelp=Isometrische Kartenansicht zeigen + + +; new map dialog +NewMapDesc=Momentan mĂ¼ssen Sie noch eine Karte angeben, von der das Kartenpaket, also der Boden, Ă¼bernommen wird. +NewMapBrowse=Durchsuchen +NewMapMultiplayer=Mehrspieler-Karte +NewMapPrepareStandardHouses=Standard-Häuser erstellen +NewMapSetAutoProduction=Auslöser fĂ¼r Auto-Produktion hinzufĂ¼gen +NewMapPlayerHouse=Spieler-Haus +NewMapImportOptions=Optionen fĂ¼r Ăœbernehmen +NewMapImportTrees=Bäume Ă¼bernehmen +NewMapImportOverlay=Ăœberlagerung Ă¼bernehmen +NewMapImportUnits=Einheiten und Gebäude Ă¼bernehmen +NewMapCap=Assistent fĂ¼r neue Karte + +; map-validator dialog +MapValidatorProblemsFound=Folgende möglichen Probleme wurden gefunden: +MapValidatorCap=Karte Ă¼berprĂ¼fen + +; loading dialog +LoadLoadRules=Lade Gesetze +LoadLoadAI=Lade KI-Einstellungen +LoadLoadArt=Lade Kunst +LoadLoadTutorial=Lade Tutorial.ini +LoadLoadSound=Lade Sounds +LoadLoadSnow=Lade Temperat.ini +LoadLoadTemperat=Lade Snow.ini +LoadLoadUrban=Lade Urban.ini +LoadLoading=Laden +LoadBuiltBy=Erstellt von: +LoadVersion=Version: +LoadInitDDraw=Initialisiere Direct Draw 6 +LoadInitPics=Lade Grafiken +LoadExtractStdMixFiles=Ă–ffnen der Standard-MIX-Dateien (kann etwas dauern) + +; basic dialog +BasicDesc=Achtung: Einige Einstellungen werden möglicherweise ignoriert. +BasicName=Name: +BasicNextScenario=Nächstes Szenario: +BasicAltNextScenario=Alt. nächstes Szenario: +BasicNewIniFormat=Neues INI-Format: +BasicCarryOverCap=CarryOverCap ?: +BasicEndOfGame=Ende des Spiels: +BasicSkipScore=Statistik auslassen: +BasicOneTimeOnly=Nur einmal: +BasicSkipMapSelect=Kartenauswahl auslassen: +BasicOfficial=Offiziell: +BasicIgnoreGlobalAITriggers=Ignorieren der allgemeinen KI-Auslöser: +BasicTruckCrate=Kiste bei zerstörtem Lastwagen: +BasicTrainCrate=Kiste bei zerstörtem Zug: +BasicPercent=Prozent GeldĂ¼bernahme: +BasicMultiplayerOnly=Nur Mehrspieler: +BasicTiberiumGrowthEnabled=Wachsendes Tiberium: +BasicVeinGrowthEnabled=Wachsende Venen: +BasicIceGrowthEnabled=Wachsendes Eis: +BasicTiberiumDeathToVisceroid=Visceroid bei Tod in Tiberium: +BasicFreeRadar=Kostenloses Radar: +BasicInitTime=Anfangszeit: +BasicAddOnNeeded=Benötigtes Zusatzpaket: + +; mapinfo dialog +MapDesc=GrĂ¶ĂŸeneinstellungen der Karte: +MapSizeFrame=Kartengrösse +MapSize=Die Gesamtgrösse der Karte. +MapVisibleSizeFrame=Sichtbarer Bereich +MapVisibleSize=Sichtbarer Bereich der Karte. Format: Links, Oben, Breite, Höhe. +MapTheater=Klima: + +; singleplayer basics dialog +SingleplayerDesc=Weitere Einstellungen bezĂ¼glich einer Einzelspieler-Karte. +SingleplayerStartingDropships=Landetransporter am Anfang: +SingleplayerCarryOverMoney=GeldĂ¼bernahme: +SingleplayerTimerInherit=ZeitĂ¼bernahme: +SingleplayerFillSilos=Silos fĂ¼llen: +SingleplayerMovies=Videos +SingleplayerIntro=Intro: +SingleplayerBrief=Besprechung: +SingleplayerWin=Sieg: +SingleplayerLose=Niederlage: +SingleplayerAction=Aktion: +SingleplayerPostScore=Nach Punktebildschirm: +SingleplayerPreMapSelect=Vor Kartenauswahl: + +; houses dialog +HousesDesc=Häuser sind die verschiedenen Spieler, ob Mensch oder KI, in einer Karte. Erstellen Sie in einer Mehrspieler-Karte hier keine Häuser! Falls dies eine Einzelspieler-Karte ist und noch keine Häuser existieren, klicken Sie zuerst auf "Standardhäuser", erstellen Sie eventuelle zusätzliche Häuser, und wählen Sie dann den menschlichen Spieler aus (vergessen Sie nicht, Spieler-Kontrolle ebenfalls zu aktivieren)! +HousesPlayerHouse=Haus des menschl. Spielers: +HousesHouse=Gewähltes Haus: +HousesIQ=Intelligenz: +HousesEdge=Kartenkante: +HousesSide=Seite: +HousesColor=Farbe: +HousesAllies=VerbĂ¼ndete: +HousesAlliesHelp=Alle verbĂ¼ndeten Häuser, durch Kommas ohne Leerzeichen getrennt, aneinanderreichen. +HousesCredits=Geld (x100): +HousesActsLike=Verhält sich wie +HousesNodeCount=Knotenpunkt- Anzahl: +HousesTechlevel=Technologiestufe: +HousesBuildActivity=Bau-Aktivität (%): +HousesPlayerControl=Spielerkontrolle: +HousesPrepareHouses=Standardhäuser +HousesAddHouse=Neues Haus +HousesDeleteHouse=Haus löschen + +; iso view +IsoCaption=Kartenansicht + +; iso view status bar +StructStatus=Gebäude: +InfStatus=Infantrie: +AirStatus=Flugzeug: +UnitStatus=Fahrzeug: +OvrlStatus=Ăœberlagerung: +OvrlDataStatus=Ăœberlagerungs-Daten: +CellTagStatus=Feld-Tag: +TilePlaceStatus=Strg: FĂ¼llen-Modus, Shift: beständiges Zeichnen, Strg+Shift: Zeichnen ohne auto. LAT oder KĂ¼ste + +; iso view object list +GroundObList=Boden +GroundClearObList=Standard-Bodentyp +GroundSandObList=Bodentyp 1 +GroundRoughObList=Bodentyp 2 +GroundGreenObList=Bodentyp 3 +GroundPaveObList=Pflaster +GroundWaterObList=Wasser +NothingObList=Nichts +TunnelObList=Tunnels +NewTunnelObList=Tunnel platzieren (bidirektional) +ModifyTunnelObList=Tunnel verändern (bidirektional) +NewTunnelSingleObList=Tunnel platzieren (unidirektional) +ModifyTunnelSingleObList=Tunnel verändern (unidirektional) +DelTunnelObList=Tunnel löschen +InfantryObList=Infantrie +VehiclesObList=Fahrzeuge +AircraftObList=Flugzeuge +StructuresObList=Gebäude +TerrainObList=Landschaftsobjekte +TreesObList=Bäume +TrafficLightsObList=Ampeln +SignsObList=Schilder +LightPostsObList=Lampen +OverlayObList=Spezial / Ăœberlagerung +DelOvrlObList=Ăœberlagerung entfernen +DelOvrl0ObList=Einzelnes Feld entfernen +DelOvrl1ObList=Im Radius von 1 Feld entfernen +DelOvrl2ObList=Im Radius von 2 Feldern entfernen +DelOvrl3ObList=Im Radius von 3 Feldern entfernen +GrTibObList=Tiberium +; BlTibObList=Blaues Tiberium +DrawRanTibObList=Zufälliges Tiberium-Feld zeichnen +DrawTibObList=Tiberium zeichnen +IncTibSizeObList=Tiberiumstärke erhöhen +DecTibSizeObList=Tiberiumstärke erniedrigen +VeinholeObList=Tiberium-Monster +VeinsObList=Venen +BridgesObList=BrĂ¼cken +BigBridgeObList=Grosse BrĂ¼cke (oberhalb des Bodens) +SmallBridgeObList=Kleine BrĂ¼cke (am Boden) +BigTrackBridgeObList=Grosse EisenbahnbrĂ¼cke (oberhalb des Bodens) +OthObList=Anderes +AllObList=Alles +OvrlManuallyObList=Ăœberlagerung manuell setzen (nicht empfohlen) +OvrlDataManuallyObList=Ăœberlagerungsdaten manuell setzen (nicht empfohlen) +WaypointsObList=Wegpunkte +CreateWaypObList=Wegpunkt erstellen +CreateSpecWaypObList=Wegpunkt mit spezieller Nummer erstellen +DelWaypObList=Wegpunkt entfernen +StartpointsObList=Startpunkte +StartpointsPlayerObList=Spieler %1 +StartpointsDelete=Startpunkt löschen +CelltagsObList=Feld-Tags +CreateCelltagObList=Feld-Tag erstellen +DelCelltagObList=Feld-Tag entfernen +CelltagPropObList=Feld-Tag Eigenschaften ändern +BaseNodesObList=Basis-Knotenpunkte +CreateNodeNoDelObList=Knotenpunkt erstellen und Gebäude nicht löschen +CreateNodeDelObList=Knotenpunkt erstellen und Gebäude löschen +DelNodeObList=Knotenpunkt löschen +DelObjObList=Objekte löschen +ChangeOwnerObList=Besitzer wechseln + +; celltag dialog +CellTagCap=Feld-Tag +CellTagDesc=Benutzen Sie einen Feld-Tag, um ein Feld mit einem Tag zu verbinden. +CellTagTag=Zugeordneter Tag: + +; aircraft dialog +AirCap=Lufteinheit-Einstellungen +AirDesc= +AirHouse=Besitzer +AirStrength=Stärke: +AirState=Status: +AirDirection=Richtung: +AirTag=Zugeordneter Tag: +AirP1=Veteranen- status: +AirP2=Gruppe: +AirP3=Rekrutierbar: +AirP4=KI rekrutierbar: + +; structure dialog +StructCap=Gebäude-Einstellungen +StructDesc=Um Erweiterungen fĂ¼r das Gebäude hinzuzufĂ¼gen, erst die Anzahl an Erweiterungen angeben und dann die Erweiterungen, beginnend mit Erweiterung 1, setzen. +StructHouse=Besitzer +StructStrength=Stärke: +StructDirection=Richtung: +StructTag=Zugeordneter Tag: +StructP1=Sellable +StructAIRepairs=Neu bauen:;faaaallllsch!!!! +StructEnergy=Strom- versorgung: +StructUpgradeCount=Erweiterungs- Anzahl: +StructSpotlight=Schein- werfer: +StructUpgrade1=Erweiterung 1: +StructUpgrade2=Erweiterung 2: +StructUpgrade3=Erweiterung 3: +StructP2=AI repariert: +StructP3=Namensanzeige: + +; unit dialog +UnitCap=Fahrzeug +UnitDesc= +UnitHouse=Besitzer: +UnitStrength=Stärke: +UnitState=Status: +UnitDirection=Richtung: +UnitTag=Zugeordneter Tag: +UnitP1=Veteranen- status: +UnitP2=Gruppe: +UnitP3=Auf BrĂ¼cke: +UnitP4=Folge ID: +UnitP5=Rekrutierbar: +UnitP6=KI rekrutierbar: + +; infantry dialog +InfCap=Infantrie-Einstellungen +InfDesc= +InfHouse=Besitzer +InfStrength=Stärke: +InfPos=Feldposition: +InfState=Status: +InfDirection=Richtung: +InfTag=Zugeordneter Tag: +InfP1=Veteranenstatus: +InfP2=Gruppe: +InfP3=Auf BrĂ¼cke: +InfP4=Rekrutierbar: +InfP5=KI rekrutierbar: + +[English-StringsRA2] +GrTibObList=Ore +BlTibObList=Gems +DrawRanTibObList=Paint random field +DrawTibObList=Paint +IncTibSizeObList=Increase size +DecTibSizeObList=Decrease size +FileRunTiberianSunHelp=Launch C&C Red Alert 2 +Err_TSNotInstalled=Red Alert 2 is not correctly installed (ra2.mix could not be loaded) +GroundSandObListURB=Bright pavement +GroundRoughObListURB=Soil +GroundGreenObListURB=Grass +GroundPaveObListURB=Dark pavement +GroundClearObListTEM=Bright grass +GroundRoughObListTEM=Dark grass +GroundGreenObListTEM=Sand +GroundClearObListSNO=Snow +GroundSandObListSNO=Dirty snow +GroundRoughObListSNO=Grass +GroundGreenObListSNO=Ice +;SAVEDLG_FILETYPES=RA2 maps|*.mpr%8*.map%8*.mmx|RA2 multi maps|*.mpr|RA2 single maps|*.map|RA2 multiplayer map extensions|*.mmx| +SAVEDLG_FILETYPES=RA2 maps|*.mpr%8*.map%8*.mmx|RA2 multiplayer map extension (*.mmx)|*.mmx|RA2 multiplayer map (*.mpr)|*.mpr|RA2 singleplayer map (*.map)|*.map| +BigTrackBridgeObList=High wood bridge +Allied=Allied +Soviet=Soviet +Other=Other + +[English-Strings] +; messages for message boxes +Err_InsufficientResources=Because of insufficient resources at least one dialog wasn´t created. You should restart Windows. The program will now quit... Tip: You should quit any programs before you start %9. Also, restarting Windows may help. +Err_TSNotInstalled=Tiberian Sun is not correctly installed (TibSun.mix could not be loaded) +Err_CreateErr=Window could not be created. You should try to close other windows first. +MainDialogExitQuestion=Are you sure that you want to quit the program? Changes will not be saved! +MainDialogExitQuestionCap=Quit %9 +AttachMapToShell=.map and/or .mpr files are currently attached to another program. Do you want that %9 opens all .map and .mpr files when you double click on them? +AddHouse=Please set the ID of the house (like GDI or Nod): +AddHouseCap=Add House +DeleteHouse=Are you sure that you want to delete the house %1? +DeleteHouseCap=Delete house +RestartNeeded=To apply all changes, you need to restart %9 +ReInitPic=The graphics must be reloaded. This may take some time, please be patient. +ReInitPicCap=Reloading graphics +StrChangeHeight=Enter the height difference that is applied to every field. Negative values are allowed! +StrChangeHeightCap=Change height +StrChangeHeightErr=Error, this would screw up the map! +StrChangeHeightErrCap=Error +ExplainEasyView=%9 automatically starts in beginner mode. Some advanced editing features are not available in this mode, although they are supported in the advanced mode. To activate the advanced mode, disable the option "Beginner mode" in the options menu. +ExplainEasyViewCap=Beginner mode +FileSaved=Map saved as "%1" + +; general strings +OK=OK +Cancel=Cancel +None=None +Yes=Yes +No=No + +; saving dialog +SAVEDLG_FILETYPES=TS maps|*.mpr%8*.map|TS multi maps|*.mpr|TS single maps|*.map| + +; tool tip strings +TT_TriggerHouse=Defines the house the trigger applies to + +; error strings for map validation +MV_NoMap=This is no map +MV_NoBasic=Basic settings don´t exist +MV_NoName=The map has no name (Edit->Basic) +MV_PackMissing=One or more packs (like IsoMapPack5 or OverlayPack) are missing. Tiberian Sun probably won´t accept the map. +MV_>100Waypoint=The map has at least one waypoint with an ID greater than 99 +MV_HousesButNoPlayer=Houses are defined, but the human player is not set up correctly +MV_HousesInMultiplayer=This seems to be a multiplayer map with houses +MV_HousesNoWaypoints=Multiplayermaps need the waypoints 0-7 as starting locations +MV_TriggerMissing=Trigger %1 missing (Linked by %2 %3) +MV_TaskForceMissing=Taskforce %1 missing (Linked by Teamtype %2) +MV_ScripttypeMissing=Scripttype %1 missing (Linked by Teamtype %2) +MV_TagMissing=Tag %1 missing (Linked by %2 %3) +MV_OfficialYes=Official is set to yes - automatic map transfer disabled (ignore this warning when saving as MMX map) +MV_Not8Waypoints=Only for RA2 before version 1.005: Official is set to no, but not all waypoints 0-7 do exist (probably random starting points, ignore this warning when saving as MMX map) +MV_TubeCounterpartMissing=The tunnel tube %5 (%1, %2) -> (%3, %4) has no counterpart that leads from (%3, %4) -> (%1, %2).\nThis will lead to unpredictable errors and crashes in the game.\nThe counterpart does not have to have the same path, but it must have opposite start and end cells. +MV_TubeStartNotUnique=The tunnel tube %5 (%1, %2) -> (%3, %4) has the same start coordinates as %6 other tunnel tubes.\nThis will lead to unpredictable errors and crashes in the game.\nThere may only be one tube starting at each cell. +MV_TubeEndNotUnique=The tunnel tube %5 (%1, %2) -> (%3, %4) has the same end coordinates as %6 other tunnel tubes.\nThis will lead to unpredictable errors and crashes in the game.\nThere may only be one tube starting at each cell. +MV_TubeInvalidCounterpartEnd=The tunnel tube %5 (%1, %2) -> (%3, %4) has %6 other tunnel tubes that have this tube's start location as their end location, but this tube's end location does not match their start location.\nThis will lead to unpredictable errors and crashes in the game.\nA counterpart must have both the start and end coordinates reversed. +MV_TubeInvalidCounterpartStart=The tunnel tube %5 (%1, %2) -> (%3, %4) has %6 other tunnel tubes that have this tube's end location as their start location, but this tube's start location does not match their end location.\nThis will lead to unpredictable errors and crashes in the game.\nA counterpart must have both the start and end coordinates reversed. + + +; tip dialog +CG_IDS_DIDYOUKNOW=Did you know... +CG_IDS_FILE_ABSENT=Tips file not found +CG_IDP_FILE_CORRUPT=Syntax error in the tips file +TipDialogNext=Next tip +TipDialogShowAtStartup=Show tips at program start +TipDialogClose=Close +TipDialogCaption=Tip of the day + +; main dialog strings +MainDialogCaption=%9 +MainDialogCaptionRA2=%9 +NoMapLoaded=No map loaded +NewMap=New map +FileNewHelp=Start new map assistant +FileOpenHelp=Open a already existing map +FileSaveHelp=Save map +FileSaveAsHelp=Save map with another filename +FileCheckMapHelp=Check the map for possible errors +FileImportModHelp=Import a *.rul - Mod in the map +FileQuitHelp=Quit %9 +FileRunTiberianSunHelp=Launch C&C 2 Tiberian Sun +HelpInfoHelp=Show information about %9 +HelpTipOfTheDayHelp=Show Tip of the Day +OptionsShowMapViewHelp=Show the isometric map view +TabBasic=Basic +TabSingleplayerSettings=Additional +TabMap=Map +TabLighting=Lighting +TabSpecial=Special +TabHouses=Houses +TabTaskForces=Task forces +TabScriptTypes=Scripts +TabTeamTypes=Team types +TabTriggers=Trigger +TabTags=Tags +TabAITriggers=AI Trigger +TabAITriggerEnable=Enable AI Trigger +TabOther=All + +; new map dialog +NewMapDesc=At the moment you need to specify a map that provides the mappack information needed for the ground +NewMapBrowse=Browse +NewMapMultiplayer=Multiplayer map +NewMapPrepareStandardHouses=Prepare standard houses +NewMapSetAutoProduction=Add Auto-Production triggers +NewMapPlayerHouse=Player house +NewMapImportOptions=Import options +NewMapImportTrees=Import trees +NewMapImportOverlay=Import overlay +NewMapImportUnits=Import units +NewMapCap=Assistant for new map + +; map-validator dialog +MapValidatorProblemsFound=The following possible problems have been found: +MapValidatorCap=Check map + +; basic dialog +BasicDesc=Note: Some settings may be ignored. +BasicName=Name: +BasicNextScenario=Next scenario: +BasicAltNextScenario=Alt. next scenario: +BasicNewIniFormat=New INI format: +BasicCarryOverCap=CarryOverCap ?: +BasicEndOfGame=End of game: +BasicSkipScore=Skip score stats: +BasicOneTimeOnly=One time only: +BasicSkipMapSelect=Skip map selection: +BasicOfficial=Official: +BasicIgnoreGlobalAITriggers=Ignore global AI Triggers: +BasicTruckCrate=Crate for destroyed trucks: +BasicTrainCrate=Crate for destroyed trains: +BasicPercent=Percent (money?): +BasicMultiplayerOnly=Only Multiplayer: +BasicTiberiumGrowthEnabled=Growing tiberium: +BasicVeinGrowthEnabled=Growing veins: +BasicIceGrowthEnabled=Growing ice: +BasicTiberiumDeathToVisceroid=Visceroid because of death in tiberium: +BasicFreeRadar=Free radar: +BasicInitTime=Initial time: +BasicAddOnNeeded=Addon needed: + +; mapinfo dialog +MapDesc=General map properties: +MapSizeFrame=Map size +MapSize=Size of the whole map, used for MapPack. +MapVisibleSizeFrame=Visible area +MapVisibleSize=Visible area of the map. Format: Left, Top, Width, Height. +MapTheater=Theater: + +; singleplayer basics dialog +SingleplayerDesc=Additional settings regarding a singleplayer map. +SingleplayerStartingDropships=Dropships at start: +SingleplayerCarryOverMoney=Inherit money: +SingleplayerTimerInherit=Inherit timer: +SingleplayerFillSilos=Fill silos: +SingleplayerMovies=Movies +SingleplayerIntro=Intro: +SingleplayerBrief=Briefing: +SingleplayerWin=Won: +SingleplayerLose=Lost: +SingleplayerAction=Action: +SingleplayerPostScore=After score screen: +SingleplayerPreMapSelect=Pre map select screen: + +; houses dialog +HousesDesc=Houses are the different players, AI and humans. If this is a multiplayer map, don´t create any houses here! If this is a singleplayer map and if there are no houses yet, click on "Standard houses" first, create your additional houses if you need some, and then choose the human player (don´t forget to activate "Player control" for this house)! +HousesPlayerHouse=House of human player: +HousesHouse=Current house: +HousesIQ=IQ: +HousesEdge=Map edge: +HousesSide=Side: +HousesColor=Color: +HousesAllies=Allies: +HousesAlliesHelp=List all allied houses like that: GDI,Nod,Neutral +HousesCredits=Money (x100): +HousesActsLike=Acts like +HousesNodeCount=Node count: +HousesTechlevel=Technology level: +HousesBuildActivity=Build activity (%): +HousesPlayerControl=Player control: +HousesPrepareHouses=Standard houses +HousesAddHouse=New house +HousesDeleteHouse=Delete house + +; loading dialog +LoadLoadRules=Loading rules +LoadLoadAI=Loading AI settings +LoadLoadArt=Loading art +LoadLoadTutorial=Loading tutorial.ini +LoadLoadSound=Loading sounds +LoadLoadSnow=Loading Temperat.ini +LoadLoadTemperat=Loading Snow.ini +LoadLoadUrban=Loading Urban.ini +LoadLoading=Loading +LoadBuiltBy=Built by: +LoadVersion=Version: +LoadInitDDraw=Initializing Direct Draw 6 +LoadInitPics=Loading Graphics +LoadExtractStdMixFiles=Opening std. MIX files (may take some time) + +; iso view +IsoCaption=Map view + +; iso view status bar +StructStatus=Structure: +InfStatus=Infantry: +AirStatus=Aircraft: +UnitStatus=Vehicle: +OvrlStatus=Overlay: +OvrlDataStatus=Overlay-Data: +CellTagStatus=CellTag: +TilePlaceStatus=Ctrl: Fill mode, Shift: continuous drawing, Ctrl+Shift: no auto smoothing of LAT or coast/shore +CopyHelp=Please specify the area that you want to be copied by clicking on the start and end position + +; iso view object/unit list +NothingObList=Nothing +GroundObList=Ground +GroundClearObList=Clear +GroundSandObList=Ground 1 +GroundRoughObList=Ground 2 +GroundGreenObList=Ground 3 +GroundPaveObList=Pavement +GroundWaterObList=Water +NewTunnelObList=Create tunnel (bidirectional) +ModifyTunnelObList=Modify tunnel (bidirectional) +NewTunnelSingleObList=Create tunnel (unidirectional) +ModifyTunnelSingleObList=Modify tunnel (unidirectional) +DelTunnelObList=Delete tunnel +TunnelObList=Tunnels +InfantryObList=Infantry +VehiclesObList=Vehicles +AircraftObList=Aircraft +StructuresObList=Buildings +TerrainObList=Terrain objects +SmudgesObList=Smudges +TreesObList=Trees +TrafficLightsObList=Traffic lights +SignsObList=Signs +LightPostsObList=Light posts +RndTreeObList=Paint random trees +OverlayObList=Special / Overlay +DelOvrlObList=Erase Overlay +DelOvrl0ObList=Erase single field +DelOvrl1ObList=Erase with 1-field radius +DelOvrl2ObList=Erase with 2-field radius +DelOvrl3ObList=Erase with 3-field radius +GrTibObList=Tiberium +; BlTibObList=Blue Tiberium +DrawRanTibObList=Paint random tiberium field +DrawTibObList=Paint green tiberium +DrawTib2ObList=Paint blue tiberium +IncTibSizeObList=Increase tiberium size +DecTibSizeObList=Decrease tiberium size +VeinholeObList=Veinhole monster +VeinsObList=Veins +BridgesObList=Bridges +BigBridgeObList=Big bridge (in the air) +SmallBridgeObList=Small bridge (at the ground) +BigTrackBridgeObList=Big track bridge (in the air) +SmallConcreteBridgeObList=Small concrete bridge +OthObList=Other +AllObList=All overlay +OvrlManuallyObList=Set overlay manually (not recommended) +OvrlDataManuallyObList=Set overlay data manually (not recommended) +WaypointsObList=Waypoints +CreateWaypObList=Create waypoint +CreateSpecWaypObList=Create waypoint with special ID +DelWaypObList=Delete waypoint +StartpointsObList=Player locations +StartpointsPlayerObList=Player %1 +StartpointsDelete=Delete player location +CelltagsObList=Celltags +CreateCelltagObList=Create celltag +DelCelltagObList=Delete celltag +CelltagPropObList=Edit celltag properties +BaseNodesObList=Base nodes +CreateNodeNoDelObList=Create node and don´t delete building +CreateNodeDelObList=Create node and delete building +DelNodeObList=Delete node +DelObjObList=Delete objects +ChangeOwnerObList=Change owner + +; celltag dialog +CellTagCap=Cell tag +CellTagDesc=Use a celltag to attach a specific cell to a tag: +CellTagTag=Attached tag: + +; aircraft dialog +AirCap=Aircraft options +AirDesc= +AirHouse=Owner: +AirStrength=Strength: +AirState=State: +AirDirection=Direction: +AirTag=Attached tag: +AirP1=Veteran status: +AirP2=Group: +AirP3=Recruitable: +AirP4=AI recruitable: + +; structure dialog +StructCap=Structure options +StructDesc=To add upgrades to this building, first set the upgrade count and then set the upgrades, beginning with upgrade 1. +StructHouse=Owner: +StructStrength=Strength: +StructDirection=Direction: +StructTag=Attached tag: +StructP1=Sellable: +StructAIRepairs=Rebuild:; sheek! that´s wrong... well... doesn´t really matter, just think it is Param2 +StructEnergy=Energy- support: +StructUpgradeCount=Upgradecount: +StructSpotlight=Spotlight: +StructUpgrade1=Upgrade 1: +StructUpgrade2=Upgrade 2: +StructUpgrade3=Upgrade 3: +StructP2=AI repairs: +StructP3=Show name: + +; unit dialog +UnitCap=Vehicle +UnitDesc= +UnitHouse=Owner: +UnitStrength=Strength: +UnitState=State: +UnitDirection=Direction: +UnitTag=Attached tag: +UnitP1=Veteran status: +UnitP2=Group: +UnitP3=On bridge: +UnitP4=Follows ID: +UnitP5=Recruitable: +UnitP6=AI recruitable: + +; infantry dialog +InfCap=Infantry +InfDesc= +InfHouse=Owner: +InfStrength=Strength: +InfPos=Field pos: +InfState=State: +InfDirection=Direction: +InfTag=Attached tag: +InfP1=Veteran status: +InfP2=Group: +InfP3=On Bridge: +InfP4=Recruitable: +InfP5=AI recruitable: + + + +; Now some translations from english to the used language (used for some combo-boxes, menus/listviews and of course unit names) +; currently used for: menu, iso-view status bar, unit/building/stuff list, overlay browser, terrain browser + +[German-TranslationsRA2] +Tiberium=Erz +Gems=Kristalle +Run Tiberian Sun=Red Alert 2 starten +Tiberium Tree=Erzmine +Countries=Häuser; fĂ¼r Edit->Houses Dialog +FinalSun Homepage=FinalAlert Homepage +FinalSun support forum=FinalAlert Hilfeforum +AutoCreate shores=Strand erstellen (AutoShore) +Tiberium (Blue)=Erz +Tiberium (Green)=Erz + +[German-Translations] +; tooltips +Heighten ground (slope logic)=Boden anheben +Lower ground (slope logic)=Boden absenken +Make terrain flat=Boden abflachen +Show all tilesets=Alle Tilesets anzeigen +Raise a single tile=Einzelnes Feld anheben (Nicht empfohlen!) +Lower a single tile=Einzelnes Feld absenken (Nicht empfohlen!) +Paint cliff front=Zugewendete Klippen zeichnen +Paint cliff back=Abgewendete Klippen zeichnen +AutoCreate shores=Strand automatisch erstellen (nur fĂ¼r FinalAlert) +Autocreate shores=Strand erstellen (AutoShore) +AutoLevel terrain height using cliffs=Bodenhöhe an Klippen anpassen (AutoLevel) +Auto level using cliffs=Bodenhöhe an Klippen anpassen (AutoLevel) + +; other strings +FinalSun Homepage=FinalSun Homepage +FinalSun support forum=FinalSun Hilfeforum +Manual F1=Anleitung F1 +Undo Ctrl+Z=RĂ¼ckgängig Strg+Z +Redo Ctrl+Y=Wiederholen Strg+Y +Event=Ereignis +Action=Aktion +Events=Ereignisse +Actions=Aktionen +Trigger=Auslöser +Trigger options=Auslöser-Optionen +Edit=Bearbeiten +Map=Karte +Basic=Generell +Special flags=Spezialeinstellungen +Lighting=Lichteinstellungen +Singleplayer settings=Einzelspieler-Einstellungen +Houses=Häuser +Trigger editor=Auslöser-Editor +Tags (for experts)=Tags (fĂ¼r Experten) +Old trigger editor (obsolete)=Alter Auslöser-Editor (veraltet) +Scripts=Skripte +Taskforces=Truppen / Taskforces +Teams=Teams +AI Triggers=KI-Auslöser +AI Trigger enabling=KI-Auslöser aktivieren +INI editing=INI-Editierung +Terrain=Terrain +Raise ground=Boden anheben +Lower ground=Boden absenken +Flatten ground=Boden angleichen +Hide tileset=Tileset verstecken +Show every tileset=Tilesets alle anzeigen +Hide single field=Einzelnes Feld verstecken +Show all fields=Alle Felder anzeigen +Raise single tile (Be careful!)=Einzelnes Feld anheben (Vorsicht!) +Lower single tile (Be careful!)=Einzelnes Feld absenken (Vorsicht!) +Map tools=Kartentools +Change map height=Kartenhöhe ändern +Ready=Bereit +None=Keiner +Aaargh=AAAAAAAAAH!; :) LET´S SCREEEEAAAAM!!!! +File=Datei +New=Neu +Quit=Beenden +Open=Ă–ffnen +Save=Speichern +Save as=Speichern unter +Check map=Karte Ă¼berprĂ¼fen +Import mod=Mod importieren +Run Tiberian Sun=Tiberian Sun starten +Launch FinalSun version=%9 Version starten +Options=Optionen +Settings=Einstellungen +Show map view=Kartenansicht zeigen +Show minimap=Ăœbersichtskarte zeigen +Easy mode=Anfängermodus +Help=Hilfe +Tip of the day=Tip des Tages +GDI Wall=GDI-Mauer +Nod Wall=Nod-Mauer +Tracks=Eisenbahnschienen +Other=Anderes +Mobile Construction Vehicle=Mobiles Baufahrzeug +Amphibious APC=Amphibien-APC +Titan=Titan +School Bus=Schulbus +Artillery=Artillerie +Wolverine=Werwolf +Hover MLRS=Schwebepanzer +Locomotive=Lokomotive +Harvester=Sammler +Mammoth Tank=Mammut +Devil's Tongue=Teufelszunge +Light Infantry=Leichte Infantrie +Engineer=Ingenieur +Civilian=Zivilist +Cyborg Commando=Cyborg-Kommando +Technician=Techniker +Orca Fighter=Orca-Jäger +GDI Power Plant=GDI Kraftwerk +Tiberium Refinery=Tiberium-Raffinerie +Construction Yard=Bauhof +Barracks=Barracken +Sandbags=Sandsäcke +Gate=Tor +Power Turbine=Kraftwerks-Turbine +Pavement=Pflaster +Temple of Nod=Tempel von Nod +Obelisk of Light=Obelisk des Lichts +Missile Silo=Raketensilo +Bridge repair hut=BrĂ¼cken-Reparatur-HĂ¼tte +Red Light Post=Rote Lampe +Green Light Post=GrĂ¼ne Lampe +Blue Light Post=Blaue Lampe +Yellow Light Post=Gelbe Lampe +Purple Light Post=Lila Lampe +Orange Light Post=Orange Lampe +Invisible Red Light Post=Unsichtbare rote Lampe +Invisible Green Light Post=Unsichtbare grĂ¼ne Lampe +Invisible Blue Light Post=Unsichtbare blaue Lampe +Invisible Yellow Light Post=Unsichtbare gelbe Lampe +Invisible Purple Light Post=Unsichtbare lila Lampe +Invisible Orange Light Post=Unsichtbare orange Lampe +Invisible Light Post=Unsichtbare Lampe +Light Post=Lampe +Light Tower=Leuchtturm +Dam=Damm +Church=Kirche +Pyramid=Pyramide +Scrin Ship=Scrin-Schiff +Tree=Baum +Tiberium Tree=Tiberium-Baum +Boxes=Kisten +Bridge 1=BrĂ¼cke obenlinks-untenrechts +Bridge 2=BrĂ¼cke untenlinks-obenrechts +Railroad Bridge 1=EisenbahnbrĂ¼cke obenlinks-untenrechts +Railroad Bridge 2=EisenbahnbrĂ¼cke untenlinks-obenrechts +Wood Bridge 1=HolzbrĂ¼cke obenlinks-untenrechts +Wood Bridge 2=HolzbrĂ¼cke untenlinks-obenrechts + +[English-TranslationsRA2] +Tiberium=Ore +Run Tiberian Sun=Run Red Alert 2 +Tiberium Tree=Ore mine +Countries=Houses; For the edit->houses dialog +FinalSun Homepage=FinalAlert Homepage +FinalSun support forum=FinalAlert support forum +AutoCreate shores=Automatically create shore (AutoShore) +Tiberium (Blue)=Ore +Tiberium (Green)=Ore + +[English-Translations] +; tooltips +Make terrain flat=Flatten ground +Raise a single tile=Raise single field (Not recommended!) +Lower a single tile=Lower single field (Not recommended!) +AutoCreate shores=Automatically create shore (only supported in FinalAlert) +Autocreate shores=Automatically create shore (AutoShore) +AutoLevel terrain height using cliffs=AutoLevel ground height using cliffs +Auto level using cliffs=AutoLevel ground height using cliffs + +; other +Bridge 1=Bridge topleft-bottomright +Bridge 2=Bridge bottomleft-topright +Railroad Bridge 1=Railroad bridge topleft-bottomright +Railroad Bridge 2=Railroad bridge bottomleft-topright +Wood Bridge 1=Wood bridge topleft-bottomright +Wood Bridge 2=Wood bridge bottomleft-topright +Easy mode=Beginner mode diff --git a/MissionEditor/data/FinalSun/FinalSunDefaults.ini b/MissionEditor/data/FinalSun/FinalSunDefaults.ini new file mode 100644 index 0000000..9b52055 --- /dev/null +++ b/MissionEditor/data/FinalSun/FinalSunDefaults.ini @@ -0,0 +1,17 @@ +[Files] + +[FinalSun] +Language=English +FileSearchLikeGame=yes +PreferLocalTheaterFiles=1 + +[TS] + +[UserInterface] +LoadScreenDelay=4.0 +UseDefaultMouseCursor=1 +ShowBuildingCells=1 +EasyView=0 + +[MiniMap] +Scale=2.000000 diff --git a/MissionEditor/data/FinalSun/README.TXT b/MissionEditor/data/FinalSun/README.TXT new file mode 100644 index 0000000..1ee8287 --- /dev/null +++ b/MissionEditor/data/FinalSun/README.TXT @@ -0,0 +1,109 @@ +Command & Conquer - Tiberian Sun (c): FinalSun Editor 2.0 +--------------------------------------------------------- + Copyright 2001-2024 Electronic Arts Inc. All rights reserved. + Westwood Studios [TM] is an Electronic Arts [TM] brand. + + Microsoft, DirectX and Windows are trademarks of the Microsoft group of companies. + +--------------------------------------------------------- + +TECHNICAL SUPPORT DISCLAIMER +---------- +In order to ask questions about FinalSun, please visit https://www.ea.com. +We will review the message board and reply to questions as often as we can. Technical support +is limited. FinalSun is distributed free of charge for the benefit of Tiberian Sun +fans. + + +MINIMUM SPECS +---------- +FinalSun: +- Microsoft Windows 10, 11 (older versions may work but are unsupported) +- 2 GB physical RAM +- Tiberian Sun installed + +Command & Conquer: Tiberian Sun +- see system requirements on box + + +LICENSE +------- +Copyright 2001-2024 Electronic Arts Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. + + +THIRD PARTY LICENSES +-------------------- +This program uses several third party libraries. Their copyright notices +and license terms are available in the 3rdParty\licenses folder. + + +KNOWN ISSUES/BUGS +---------- +- Problems may occur if you have one or more mods installed. If you experience problems, + please try first to remove these mods. + + + +HOW TO START +---------- +After FinalSun has finished loading, press F1 to show the manual and +some tutorials. + + + +Please read the manual by pressing F1 in FinalSun. You should also +begin with the tutorials included. + + + +FAQ +---------- +Q: How can I create a zoom trigger? +A: If you want to zoom on a particular place, you must first use the 'move camera + and scroll to waypoint' action (#48) and then zoom in. The zoom rate is controlled + by an undocumented keyword which must be placed in the [General] section of RULES.INI + or your map file: ZoomInFactor=N } It works to use Edit->Ini to create a [General] + section inside the map file and insert the key. + +Q: Can I play the maps online? And use the new unit types online? +A: Yes, but there is a synchronization time limit. You can use the unit types online. + +Q: How can I keep the map file small so that I'm able to play with 4 players online? +A: One possibility is to "hide" the preview. Just select the appropiate options when you + save the map. + +Q: Ok I've made a multiplayer map. How can I play it? +A: In the FinalSun map settings dialog, choose "multiplayer maps" and click on + your's (usually near the bottom). Note that you cannot load the map in the random + map editor. + +Q: What is that drag & drop feature? How can I copy units/buildings or move them? +A: Instead of deleting a building and placing it somewhere else, you can simply click + with the left mouse button on the building and move your mouse while holding down the + mouse button. You can now see a line that shows where the building/unit will be placed. + If you stop holding down the button, the unit/building will be moved there. If you hold + down the shift key also, it will be "copied" there. That means you can create a big + army without having to create every unit yourself. Note: if you move/copy a building + and it is to big to be placed at the new position, no warning appears! That means you + will probably have problems if you don't make sure that there is enough space! + + + + + + + + diff --git a/MissionEditor/data/FinalSun/Scripts/Add Reveal Map Debug Trigger.fscript b/MissionEditor/data/FinalSun/Scripts/Add Reveal Map Debug Trigger.fscript new file mode 100644 index 0000000..1e78966 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Add Reveal Map Debug Trigger.fscript @@ -0,0 +1,15 @@ +// FinalSun Script file +// Name: Add Reveal Map Debug trigger +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AskContinue("This script will add a trigger that reveals the whole map after 2 seconds. Continue?"); +AllowAdd("TRUE"); + +// now add the trigger, use the variable %TriggerID% as ID filler, and let a tag be created automatically +AddTrigger("%TriggerID%", "GDI,<none>,Reveal Map Debug Trigger,0,1,1,1,0", "1,13,0,2", "1,16,0,0,0,0,0,0,A", "TRUE"); +Message("Trigger %TriggerID% added","Success"); + + diff --git a/MissionEditor/data/FinalSun/Scripts/After Glow.fscript b/MissionEditor/data/FinalSun/Scripts/After Glow.fscript new file mode 100644 index 0000000..3e127b0 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/After Glow.fscript @@ -0,0 +1,316 @@ +// FinalSun Script file +// Name: After Glow +// Written By: Bill Brislin aka RVMECH +// Last Change: Dec,24,2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AskContinue("This script will add sections to the sturcture parameters so that they will glow in the dark. Ready...hope this works?"); +AllowAdd("Because it makes your life easier when someone else does all the dirty work"); + + +SetSafeMode("FALSE","This makes all structures and units glow in the darkness..here we go"); + +SetIniKey("AudioVisual","ExtraAircraftLight",".4"); +SetIniKey("AudioVisual","ExtraInfantryLight",".4"); +SetIniKey("AudioVisual","ExtraUnitLight",".4"); +SetIniKey("GAPOWR","LightRedTint","0.05"); +SetIniKey("GAPOWR","LightBlueTint","0.01"); +SetIniKey("GAPOWR","LightGreenTint","0.05"); +SetIniKey("GAPOWR","LightIntensity","0.01"); +SetIniKey("GAPOWR","LightVisibility","1500"); + + + +SetIniKey("PROC","LightRedTint","0.05"); +SetIniKey("PROC","LightBlueTint","0.01"); +SetIniKey("PROC","LightGreenTint","0.05"); +SetIniKey("PROC","LightIntensity","0.01"); +SetIniKey("PROC","LightVisibility","1500"); + + + + +SetIniKey("GASILO","LightRedTint","0.05"); +SetIniKey("GASILO","LightBlueTint","0.01"); +SetIniKey("GASILO","LightGreenTint","0.05"); +SetIniKey("GASILO","LightIntensity","0.01"); +SetIniKey("GASILO","LightVisibility","1500"); + + + +SetIniKey("GAPILE","LightRedTint","0.05"); +SetIniKey("GAPILE","LightBlueTint","0.01"); +SetIniKey("GAPILE","LightGreenTint","0.05"); +SetIniKey("GAPILE","LightIntensity","0.01"); +SetIniKey("GAPILE","LightVisibility","1500"); + + +SetIniKey("CATHOSP","LightRedTint","0.05"); +SetIniKey("CATHOSP","LightBlueTint","0.01"); +SetIniKey("CATHOSP","LightGreenTint","0.05"); +SetIniKey("CATHOSP","LightIntensity","0.01"); +SetIniKey("CATHOSP","LightVisibility","1500"); + + + +SetIniKey("GAPLUG","LightRedTint","0.05"); +SetIniKey("GAPLUG","LightBlueTint","0.01"); +SetIniKey("GAPLUG","LightGreenTint","0.05"); +SetIniKey("GAPLUG","LightIntensity","0.01"); +SetIniKey("GAPLUG","LightVisibility","1500"); + + +SetIniKey("GACNST","LightRedTint","0.05"); +SetIniKey("GACNST","LightBlueTint","0.01"); +SetIniKey("GACNST","LightGreenTint","0.05"); +SetIniKey("GACNST","LightIntensity","0.01"); +SetIniKey("GACNST","LightVisibility","1500"); + + + +SetIniKey("GAVULC","LightRedTint","0.05"); +SetIniKey("GAVULC","LightBlueTint","0.01"); +SetIniKey("GAVULC","LightGreenTint","0.05"); +SetIniKey("GAVULC","LightIntensity","0.01"); +SetIniKey("GAVULC","LightVisibility","1500"); + + + +SetIniKey("GADEPT","LightRedTint","0.05"); +SetIniKey("GADEPT","LightBlueTint","0.01"); +SetIniKey("GADEPT","LightGreenTint","0.05"); +SetIniKey("GADEPT","LightIntensity","0.01"); +SetIniKey("GADEPT","LightVisibility","1500"); + + +SetIniKey("GATECH","LightRedTint","0.05"); +SetIniKey("GATECH","LightBlueTint","0.01"); +SetIniKey("GATECH","LightGreenTint","0.05"); +SetIniKey("GATECH","LightIntensity","0.01"); +SetIniKey("GATECH","LightVisibility","1500"); + + +SetIniKey("GAWEAP","LightRedTint","0.05"); +SetIniKey("GAWEAP","LightBlueTint","0.01"); +SetIniKey("GAWEAP","LightGreenTint","0.05"); +SetIniKey("GAWEAP","LightIntensity","0.01"); +SetIniKey("GAWEAP","LightVisibility","1500"); + + +SetIniKey("GAHPAD","LightRedTint","0.05"); +SetIniKey("GAHPAD","LightBlueTint","0.01"); +SetIniKey("GAHPAD","LightGreenTint","0.05"); +SetIniKey("GAHPAD","LightIntensity","0.01"); +SetIniKey("GAHPAD","LightVisibility","1500"); + + + +SetIniKey("GAPOWR","LightRedTint","0.05"); +SetIniKey("GAPOWR","LightBlueTint","0.01"); +SetIniKey("GAPOWR","LightGreenTint","0.05"); +SetIniKey("GAPOWR","LightIntensity","0.01"); +SetIniKey("GAPOWR","LightVisibility","1500"); + + + + +SetIniKey("NAPOWR","LightRedTint","0.05"); +SetIniKey("NAPOWR","LightBlueTint","0.01"); +SetIniKey("NAPOWR","LightGreenTint","0.05"); +SetIniKey("NAPOWR","LightIntensity","0.01"); +SetIniKey("NAPOWR","LightVisibility","1500"); + + +SetIniKey("NATECH","LightRedTint","0.05"); +SetIniKey("NATECH","LightBlueTint","0.01"); +SetIniKey("NATECH","LightGreenTint","0.05"); +SetIniKey("NATECH","LightIntensity","0.01"); +SetIniKey("NATECH","LightVisibility","1500"); + + + +SetIniKey("NAHAND","LightRedTint","0.05"); +SetIniKey("NAHAND","LightBlueTint","0.01"); +SetIniKey("NAHAND","LightGreenTint","0.05"); +SetIniKey("NAHAND","LightIntensity","0.01"); +SetIniKey("NAHAND","LightVisibility","1500"); + + +SetIniKey("GATECH","LightRedTint","0.05"); +SetIniKey("GATECH","LightBlueTint","0.01"); +SetIniKey("GATECH","LightGreenTint","0.05"); +SetIniKey("GATECH","LightIntensity","0.01"); +SetIniKey("GATECH","LightVisibility","1500"); + + +SetIniKey("GAWEAP","LightRedTint","0.05"); +SetIniKey("GAWEAP","LightBlueTint","0.01"); +SetIniKey("GAWEAP","LightGreenTint","0.05"); +SetIniKey("GAWEAP","LightIntensity","0.01"); +SetIniKey("GAWEAP","LightVisibility","1500"); + + + +SetIniKey("NAAPWR","LightRedTint","0.05"); +SetIniKey("NAAPWR","LightBlueTint","0.01"); +SetIniKey("NAAPWR","LightGreenTint","0.05"); +SetIniKey("NAAPWR","LightIntensity","0.01"); +SetIniKey("NAAPWR","LightVisibility","1500"); + + +SetIniKey("NAPULS","LightRedTint","0.05"); +SetIniKey("NAPULS","LightBlueTint","0.01"); +SetIniKey("NAPULS","LightGreenTint","0.05"); +SetIniKey("NAPULS","LightIntensity","0.01"); +SetIniKey("NAPULS","LightVisibility","1500"); + + + + +SetIniKey("NASTLH","LightRedTint","0.05"); +SetIniKey("NASTLH","LightBlueTint","0.01"); +SetIniKey("NASTLH","LightGreenTint","0.05"); +SetIniKey("NASTLH","LightIntensity","0.01"); +SetIniKey("NASTLH","LightVisibility","1500"); + + +SetIniKey("NATMPL","LightRedTint","0.05"); +SetIniKey("NATMPL","LightBlueTint","0.01"); +SetIniKey("NATMPL","LightGreenTint","0.05"); +SetIniKey("NATMPL","LightIntensity","0.01"); +SetIniKey("NATMPL","LightVisibility","1500"); + + + +SetIniKey("NAWAST","LightRedTint","0.05"); +SetIniKey("NAWAST","LightBlueTint","0.01"); +SetIniKey("NAWAST","LightGreenTint","0.05"); +SetIniKey("NAWAST","LightIntensity","0.01"); +SetIniKey("NAWAST","LightVisibility","1500"); + + +SetIniKey("NACNST","LightRedTint","0.05"); +SetIniKey("NACNST","LightBlueTint","0.01"); +SetIniKey("NACNST","LightGreenTint","0.05"); +SetIniKey("NACNST","LightIntensity","0.01"); +SetIniKey("NACNST","LightVisibility","1500"); + + +SetIniKey("NADEPT","LightRedTint","0.05"); +SetIniKey("NADEPT","LightBlueTint","0.01"); +SetIniKey("NADEPT","LightGreenTint","0.05"); +SetIniKey("NADEPT","LightIntensity","0.01"); +SetIniKey("NADEPT","LightVisibility","1500"); + + +SetIniKey("NAOBEL","LightRedTint","0.05"); +SetIniKey("NAOBEL","LightBlueTint","0.01"); +SetIniKey("NAOBEL","LightGreenTint","0.05"); +SetIniKey("NAOBEL","LightIntensity","0.01"); +SetIniKey("NAOBEL","LightVisibility","1500"); + + +SetIniKey("NAHAND","LightRedTint","0.05"); +SetIniKey("NAHAND","LightBlueTint","0.01"); +SetIniKey("NAHAND","LightGreenTint","0.05"); +SetIniKey("NAHAND","LightIntensity","0.01"); +SetIniKey("NAHAND","LightVisibility","1500"); + + +SetIniKey("NAMISL","LightRedTint","0.05"); +SetIniKey("NAMISL","LightBlueTint","0.01"); +SetIniKey("NAMISL,"LightGreenTint","0.05"); +SetIniKey("NAMISL","LightIntensity","0.01"); +SetIniKey("NAMISL","LightVisibility","1500"); + + +SetIniKey("NAIRON","LightRedTint","0.05"); +SetIniKey("NAIRON","LightBlueTint","0.01"); +SetIniKey("NAIRON","LightGreenTint","0.05"); +SetIniKey("NAIRON","LightIntensity","0.01"); +SetIniKey("NAIRON","LightVisibility","1500"); + + +SetIniKey("NALASR","LightRedTint","0.05"); +SetIniKey("NALASR","LightBlueTint","0.01"); +SetIniKey("NALASR","LightGreenTint","0.05"); +SetIniKey("NALASR","LightIntensity","0.01"); +SetIniKey("NALASR","LightVisibility","1500"); + + +SetIniKey("NAMISL","LightRedTint","0.05"); +SetIniKey("NAMISL","LightBlueTint","0.01"); +SetIniKey("NAMISL","LightGreenTint","0.05"); +SetIniKey("NAMISL","LightIntensity","0.01"); +SetIniKey("NAMISL","LightVisibility","1500"); + + +SetIniKey("GARADR","LightRedTint","0.05"); +SetIniKey("GARADR","LightBlueTint","0.01"); +SetIniKey("GARADR","LightGreenTint","0.05"); +SetIniKey("GARADR","LightIntensity","0.01"); +SetIniKey("GARADR","LightVisibility","1500"); + + + +SetIniKey("NAPOWR","LightRedTint","0.05"); +SetIniKey("NAPOWR","LightBlueTint","0.01"); +SetIniKey("NAPOWR","LightGreenTint","0.05"); +SetIniKey("NAPOWR","LightIntensity","0.01"); +SetIniKey("NAPOWR","LightVisibility","1500"); + + +SetIniKey("NAHPAD","LightRedTint","0.05"); +SetIniKey("NAHPAD","LightBlueTint","0.01"); +SetIniKey("NAHPAD","LightGreenTint","0.05"); +SetIniKey("NAHPAD","LightIntensity","0.01"); +SetIniKey("NAHPAD","LightVisibility","1500"); + + +SetIniKey("NARADR","LightRedTint","0.05"); +SetIniKey("NARADR","LightBlueTint","0.01"); +SetIniKey("NARADR","LightGreenTint","0.05"); +SetIniKey("NARADR","LightIntensity","0.01"); +SetIniKey("NARADR","LightVisibility","1500"); + + +SetIniKey("NAREFN","LightRedTint","0.05"); +SetIniKey("NAREFN","LightBlueTint","0.01"); +SetIniKey("NAREFN","LightGreenTint","0.05"); +SetIniKey("NAREFN","LightIntensity","0.01"); +SetIniKey("NAREFN","LightVisibility","1500"); + + +SetIniKey("NASAM","LightRedTint","0.05"); +SetIniKey("NASAM","LightBlueTint","0.01"); +SetIniKey("NASAM","LightGreenTint","0.05"); +SetIniKey("NASAM","LightIntensity","0.01"); +SetIniKey("NASAM","LightVisibility","1500"); + + +); + + +SetIniKey("NATECH","LightRedTint","0.05"); +SetIniKey("NATECH","LightBlueTint","0.01"); +SetIniKey("NATECH","LightGreenTint","0.05"); +SetIniKey("NATECH","LightIntensity","0.01"); +SetIniKey("NATECH","LightVisibility","1500"); + + +SetIniKey("NAWEAP","LightRedTint","0.05"); +SetIniKey("NAWEAP","LightBlueTint","0.01"); +SetIniKey("NAWEAP","LightGreenTint","0.05"); +SetIniKey("NAWEAP","LightIntensity","0.01"); +SetIniKey("NAWEAP","LightVisibility","1500"); + + + + + + + +Message("Lighting Levels have been changed for the structures and units","Success"); + + diff --git a/MissionEditor/data/FinalSun/Scripts/Create Afternoon Lighting.fscript b/MissionEditor/data/FinalSun/Scripts/Create Afternoon Lighting.fscript new file mode 100644 index 0000000..ecfaff9 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Create Afternoon Lighting.fscript @@ -0,0 +1,20 @@ +// FinalSun Script file +// Name: Create Morning Lighting +// Written By: Matthias Wagner +// Last Change: August 27, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +SetSafeMode("FALSE","Necessary for setting lighting values"); + +SetIniKey("Lighting","Level","0.028000"); +SetIniKey("Lighting","IonLevel","0.028000"); + +SetIniKey("Lighting","Ambient","1.000000"); +SetIniKey("Lighting","Red","1.080000"); +SetIniKey("Lighting","Green","0.940000"); +SetIniKey("Lighting","Blue","0.680000"); + +SetIniKey("Lighting","IonAmbient","0.650000"); +SetIniKey("Lighting","IonRed","0.695000"); +SetIniKey("Lighting","IonGreen","0.445000"); +SetIniKey("Lighting","IonBlue","0.775000"); \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/Scripts/Create Evening Lighting.fscript b/MissionEditor/data/FinalSun/Scripts/Create Evening Lighting.fscript new file mode 100644 index 0000000..805ab32 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Create Evening Lighting.fscript @@ -0,0 +1,20 @@ +// FinalSun Script file +// Name: Create Morning Lighting +// Written By: Matthias Wagner +// Last Change: August 27, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +SetSafeMode("FALSE","Necessary for setting lighting values"); + +SetIniKey("Lighting","Level","0.028000"); +SetIniKey("Lighting","IonLevel","0.028000"); + +SetIniKey("Lighting","Ambient","0.750000"); +SetIniKey("Lighting","Red","0.710000"); +SetIniKey("Lighting","Green","0.810000"); +SetIniKey("Lighting","Blue","1.190000"); + +SetIniKey("Lighting","IonAmbient","0.650000"); +SetIniKey("Lighting","IonRed","0.695000"); +SetIniKey("Lighting","IonGreen","0.445000"); +SetIniKey("Lighting","IonBlue","0.775000"); \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/Scripts/Create Morning Lighting.fscript b/MissionEditor/data/FinalSun/Scripts/Create Morning Lighting.fscript new file mode 100644 index 0000000..c41fca5 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Create Morning Lighting.fscript @@ -0,0 +1,20 @@ +// FinalSun Script file +// Name: Create Morning Lighting +// Written By: Matthias Wagner +// Last Change: August 27, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +SetSafeMode("FALSE","Necessary for setting lighting values"); + +SetIniKey("Lighting","Level","0.028000"); +SetIniKey("Lighting","IonLevel","0.028000"); + +SetIniKey("Lighting","Ambient","0.750000"); +SetIniKey("Lighting","Red","1.090000"); +SetIniKey("Lighting","Green","0.800000"); +SetIniKey("Lighting","Blue","0.490000"); + +SetIniKey("Lighting","IonAmbient","0.650000"); +SetIniKey("Lighting","IonRed","0.695000"); +SetIniKey("Lighting","IonGreen","0.445000"); +SetIniKey("Lighting","IonBlue","0.775000"); \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/Scripts/Create Night Lighting.fscript b/MissionEditor/data/FinalSun/Scripts/Create Night Lighting.fscript new file mode 100644 index 0000000..13fce80 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Create Night Lighting.fscript @@ -0,0 +1,20 @@ +// FinalSun Script file +// Name: Create Morning Lighting +// Written By: Matthias Wagner +// Last Change: August 27, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +SetSafeMode("FALSE","Necessary for setting lighting values"); + +SetIniKey("Lighting","Level","0.028000"); +SetIniKey("Lighting","IonLevel","0.028000"); + +SetIniKey("Lighting","Ambient","0.350000"); +SetIniKey("Lighting","Red","0.510000"); +SetIniKey("Lighting","Green","0.460000 "); +SetIniKey("Lighting","Blue","1.410000"); + +SetIniKey("Lighting","IonAmbient","0.650000"); +SetIniKey("Lighting","IonRed","0.695000"); +SetIniKey("Lighting","IonGreen","0.445000"); +SetIniKey("Lighting","IonBlue","0.775000"); \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/Scripts/Day Night Loop (TS) sno.fscript b/MissionEditor/data/FinalSun/Scripts/Day Night Loop (TS) sno.fscript new file mode 100644 index 0000000..1338f1d --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Day Night Loop (TS) sno.fscript @@ -0,0 +1,82 @@ +// FinalSun Script file +// Name: Start Day\Night Loop +// Written By: Bill Brislin aka RVMECH +// Last Change: Dec,24,2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AskContinue("This script will add a trigger that starts the Day and Night loop after 50 seconds, it will also set your lighting levels for the proper operation of the loop. Remember to set the enable & disable parameters in the triggers when when you are finished. Ready...hope this works?"); +AllowAdd("Because it makes your life easier when someone else does all the dirty work"); + +// now add the trigger, use the variable %TriggerID% as ID filler, and let a tag be created automatically +AddTrigger("%trig1%", "Neutral,<none>,Start_Day_Night_Loop,0,1,1,1,0", "1,13,0,2", "1,53,2,Please_select_Sunrise,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig1%"); +SetParam("%action%", "1","%trig2%"); +SetIniKey("Actions","%trig1%", "%action%"); + +AddTag("%newtag1%", "0,Start_Day_Night_Loop,%trig1%"); + + +AddTrigger("%trig2%", "Neutral,<none>,Sunrise,1,1,1,1,0", "1,13,0,50", "5,53,2,please_select_Ambient_up,0,0,0,0,A,54,2,please_select_Sunrise,0,0,0,0,A,73,0,95,0,0,0,0,A,72,0,1070000000,0,0,0,0,A,71,0,1019000000,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig2%"); +SetParam("%action%", "3", "%trig2%"); +SetIniKey("Actions", "%trig2%", "%action%"); + +AddTag("%newtag2%", "2,Sunrise,%trig2%"); + +AddTrigger("%trig3%", "Neutral,<none>,Ambient_is_Up,1,1,1,1,0", "1,46,0,95", "2,53,2,please_select_Sunset,0,0,0,0,A,54,0,please_select_Ambient_up,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig3%"); +SetParam("%action%", "3", "%trig3%"); +SetIniKey("Actions", "%trig3%", "%action%"); + +AddTag("%newtag3%", "2,Ambient_is_Up,%trig3%"); + + + +AddTrigger("%trig4%", "Neutral,<none>,Sunset,1,1,1,1,0", "1,13,0,50", "5,53,2,please_select_Ambient_Down,0,0,0,0,A,54,2,please_select_Sunset,0,0,0,0,A,73,0,28,0,0,0,0,A,72,0,1070000000,0,0,0,0,A,71,0,1019000000,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig4%"); +SetParam("%action%", "3", "%trig4%"); +SetIniKey("Actions", "%trig4%", "%action%"); + +AddTag("%newtag4%", "2,Sunset,%trig4%"); + + +AddTrigger("%trig5%", "Neutral,<none>,Ambient_is_Down,1,1,1,1,0", "1,45,0,28", "2,53,2,please_select_Sunrise,0,0,0,0,A,54,0,please_select_Ambient_Down,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig5%"); +SetParam("%action%", "3", "%trig5%"); +SetIniKey("Actions", "%trig3%", "%action%"); + +AddTag("%newtag5%", "2,Ambient_is_Down,%trig5%"); + + + +SetSafeMode("FALSE","This is necessary for setting lighting values..hang on to your hat"); + +SetIniKey("Lighting","Level","0.015000"); +SetIniKey("Lighting","IonLevel","0.010000"); + +SetIniKey("Lighting","Ambient","0.280000"); +SetIniKey("Lighting","Red",".950000"); +SetIniKey("Lighting","Green","0.950000"); +SetIniKey("Lighting","Blue","1.100000"); + +SetIniKey("Lighting","IonAmbient","0.380000"); +SetIniKey("Lighting","IonRed","1.000000"); +SetIniKey("Lighting","IonGreen","1.000000"); +SetIniKey("Lighting","IonBlue","1.400000"); + +SetSafeMode("FALSE","This makes the units glow in the darkness..here we go"); + +SetIniKey("AudioVisual","ExtraAircraftLight",".4"); +SetIniKey("AudioVisual","ExtraInfantryLight",".4"); +SetIniKey("AudioVisual","ExtraUnitLight",".4"); + + +Message("Lighting Levels have been changed and the Day Night Loop has been added","Success"); + + diff --git a/MissionEditor/data/FinalSun/Scripts/Day-Night Loop.fscript b/MissionEditor/data/FinalSun/Scripts/Day-Night Loop.fscript new file mode 100644 index 0000000..42a8e7f --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Day-Night Loop.fscript @@ -0,0 +1,84 @@ +// FinalSun Script file +// Name: Start Day\Night Loop +// Written By: Bill Brislin aka RVMECH +// Last Change: Dec,24,2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AskContinue("This script will add a trigger that starts the Day and Night loop after 50 seconds, it will also set your lighting levels for the proper operation of the loop. Remember to set the enable & disable parameters in the triggers when when you are finished. Ready...hope this works?"); +AllowAdd("Because it makes your life easier when someone else does all the dirty work"); + +// now add the trigger, use the variable %TriggerID% as ID filler, and let a tag be created automatically +AddTrigger("%trig1%", "Neutral,<none>,Start_Day_Night_Loop,0,1,1,1,0", "1,13,0,2", "1,53,2,Please_select_Sunrise,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig1%"); +SetParam("%action%", "1","%trig2%"); +SetIniKey("Actions","%trig1%", "%action%"); + +AddTag("%newtag1%", "0,Start_Day_Night_Loop,%trig1%"); + + +AddTrigger("%trig2%", "Neutral,<none>,Sunrise,1,1,1,1,0", "1,13,0,32", "5,53,2,please_select_Ambient_up,0,0,0,0,A,54,2,please_select_Sunrise,0,0,0,0,A,73,0,95,0,0,0,0,A,72,0,1070000000,0,0,0,0,A,71,0,1019000000,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig2%"); +SetParam("%action%", "3", "%trig2%"); +SetIniKey("Actions", "%trig2%", "%action%"); + +AddTag("%newtag2%", "2,Sunrise,%trig2%"); + +AddTrigger("%trig3%", "Neutral,<none>,Ambient_is_Up,1,1,1,1,0", "1,46,0,95", "2,53,2,please_select_Sunset,0,0,0,0,A,54,0,please_select_Ambient_up,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig3%"); +SetParam("%action%", "3", "%trig3%"); +SetIniKey("Actions", "%trig3%", "%action%"); + +AddTag("%newtag3%", "2,Ambient_is_Up,%trig3%"); + + + +AddTrigger("%trig4%", "Neutral,<none>,Sunset,1,1,1,1,0", "1,13,0,32", "5,53,2,please_select_Ambient_Down,0,0,0,0,A,54,2,please_select_Sunset,0,0,0,0,A,73,0,40,0,0,0,0,A,72,0,1070000000,0,0,0,0,A,71,0,1019000000,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig4%"); +SetParam("%action%", "3", "%trig4%"); +SetIniKey("Actions", "%trig4%", "%action%"); + +AddTag("%newtag4%", "2,Sunset,%trig4%"); + + +AddTrigger("%trig5%", "Neutral,<none>,Ambient_is_Down,1,1,1,1,0", "1,45,0,40", "2,53,2,please_select_Sunrise,0,0,0,0,A,54,0,please_select_Ambient_Down,0,0,0,0,A", "FALSE"); + +GetIniKey("%action%", "Actions","%trig5%"); +SetParam("%action%", "3", "%trig5%"); +SetIniKey("Actions", "%trig3%", "%action%"); + +AddTag("%newtag5%", "2,Ambient_is_Down,%trig5%"); + + + +SetSafeMode("FALSE","Necessary for setting lighting values..hang on to your hat"); + +SetIniKey("Lighting","Level","0.015000"); +SetIniKey("Lighting","IonLevel","0.010000"); + +SetIniKey("Lighting","Ambient","0.400000"); +SetIniKey("Lighting","Red",".950000"); +SetIniKey("Lighting","Green","0.950000"); +SetIniKey("Lighting","Blue","1.100000"); + +SetIniKey("Lighting","IonAmbient","0.380000"); +SetIniKey("Lighting","IonRed","1.000000"); +SetIniKey("Lighting","IonGreen","1.000000"); +SetIniKey("Lighting","IonBlue","1.400000"); + +SetIniKey("Lighting","DominatorRed","0.850000"); +SetIniKey("Lighting","DominatorBlue","0.300000"); +SetIniKey("Lighting","DominatorGreen","0.200000"); +SetIniKey("Lighting","DominatorLevel","0.000000"); +SetIniKey("Lighting","DominatorGround","0.000000"); +SetIniKey("Lighting","DominatorAmbient","1.500000"); +SetIniKey("Lighting","DominatorAmbientChangeRate"'"0.001000"); + + +Message("Lighting Levels have been changed and the Day Night Loop has been added","Success"); + + diff --git a/MissionEditor/data/FinalSun/Scripts/Enlarge Map by 100x100.fscript b/MissionEditor/data/FinalSun/Scripts/Enlarge Map by 100x100.fscript new file mode 100644 index 0000000..558c25b --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Enlarge Map by 100x100.fscript @@ -0,0 +1,29 @@ +// FinalSun Script file +// Name: Enlarge map by100x100 +// Written By: Bill Brislin +// Last Change:December,30 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +Is("%Width%", ">", "200", "WidthTooLarge"); +Is("%Height%", ">", "200", "HeightTooLarge"); + +Print("Script cannot resize map, because the map width is too large.","WidthTooLarge"); +Print("Script cannot resize map, because the map height is too large.","HeightTooLarge"); +Cancel("WidthTooLarge"); +Cancel("HeightTooLarge"); + +SetVariable("NW", "%Width%"); +SetVariable("NH", "%Height%"); +SetVariable("X", "50"); +SetVariable("Y", "50"); + +Add("NW", "100"); +Add("NH", "100"); + +AskContinue("This script will resize the map from %Width%x%Height% to NWxNH. Continue?"); + +Resize("X","Y","NW","NH"); + + + + diff --git a/MissionEditor/data/FinalSun/Scripts/Enlarge Map by 50x50.fscript b/MissionEditor/data/FinalSun/Scripts/Enlarge Map by 50x50.fscript new file mode 100644 index 0000000..71b8c7b --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Enlarge Map by 50x50.fscript @@ -0,0 +1,28 @@ +// FinalSun Script file +// Name: Enlarge map by 50x50 +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + +Is("%Width%", ">", "150", "WidthTooLarge"); +Is("%Height%", ">", "150", "HeightTooLarge"); + +Print("Script cannot resize map, because the map width is too large.","WidthTooLarge"); +Print("Script cannot resize map, because the map height is too large.","HeightTooLarge"); +Cancel("WidthTooLarge"); +Cancel("HeightTooLarge"); + +SetVariable("NW", "%Width%"); +SetVariable("NH", "%Height%"); +SetVariable("X", "25"); +SetVariable("Y", "25"); + +Add("NW", "50"); +Add("NH", "50"); + +AskContinue("This script will resize the map from %Width%x%Height% to NWxNH. Continue?"); + +Resize("X","Y","NW","NH"); + + + diff --git a/MissionEditor/data/FinalSun/Scripts/InVisLmps.fscript b/MissionEditor/data/FinalSun/Scripts/InVisLmps.fscript new file mode 100644 index 0000000..1ff677b --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/InVisLmps.fscript @@ -0,0 +1,23 @@ +// FinalSun Script file +// Name: Special Lamps +// Written By: Bill Brislin aka RVMECH +// Last Change:Feb,12,2002 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AskContinue("This script will make the INREDLMP. INGRNLMP,and the INBLULMP less bright and shorter in range. Ready...hope this works?"); +AllowAdd("Because it makes your life easier when someone else does all the dirty work"); + + +SetSafeMode("FALSE","This will make the INREDLMP. INGRNLMP,and the INBLULMP less bright and shorter in range...here we go"); + +SetIniKey("INREDLMP","LightIntensity","0.005"); +SetIniKey("INREDLMP","LightVisibility","550"); +SetIniKey("INGRNLMP","LightIntensity","0.005"); + +SetIniKey("INGRNLMP","LightVisibility","550"); +SetIniKey("INBLULMP",LightVisibility","550");; +SetIniKey("INBLULMP","LightIntensity","0.005"); +Message("The INREDLMP, INGRNLMP, and INBLULMP have been modified","Success"); + + diff --git a/MissionEditor/data/FinalSun/Scripts/List Objects.fscript b/MissionEditor/data/FinalSun/Scripts/List Objects.fscript new file mode 100644 index 0000000..90f1a2c --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/List Objects.fscript @@ -0,0 +1,54 @@ +// FinalSun Script file +// Name: Change Unit Facing +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + + +SetAutoUpdate("FALSE"); // no screen flickering... + + +SetVariable("%TCounter%","%InfantryCount%"); + +// LOOP BEGIN +:LoopInfantry: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetInfantry("%data%","%pos%"); +Print("Infantry %pos%: %data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("LoopInfantry","%TCounter%"); + +SetVariable("%TCounter%","%UnitCount%"); + +// LOOP BEGIN +:LoopVehicle: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetVehicle("%data%","%pos%"); +Print("Vehicle %pos%: %data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("LoopVehicle","%TCounter%"); + +SetVariable("%TCounter%","%AircraftCount%"); + +// LOOP BEGIN +:LoopAircraft: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetAircraft("%data%","%pos%"); +Print("Aircraft %pos%: %data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("LoopAircraft","%TCounter%"); + +SetVariable("%TCounter%","%StructureCount%"); + +// LOOP BEGIN +:LoopStructure: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetStructure("%data%","%pos%"); +Print("Structure %pos%: %data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("LoopStructure","%TCounter%"); \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/Scripts/List general map stats.fscript b/MissionEditor/data/FinalSun/Scripts/List general map stats.fscript new file mode 100644 index 0000000..108a303 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/List general map stats.fscript @@ -0,0 +1,27 @@ +// FinalSun Script file +// Name: Move 4 starting points close to corners +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +Print("Player count: %PlayerCount%"); +Print("Waypoint count: %WaypointCount%"); +Print("Unit count: %UnitCount%"); +Print("Infantry count: %InfantryCount%"); +Print("Structure count: %StructureCount%"); +Print("Aircraft count: %AircraftCount%"); + +SetVariable("%WPCounter%","100"); + +// BEGIN WAYPOINT LOOP +:WaypointLoop: + +SetVariable("%WPID%","100"); +Substract("%WPID%","%WPCounter%"); +GetWaypointPos("%WPID%","%X%","%Y%"); +Print("Waypoint %WPID%: %X% / %Y%","%X%"); // List waypoint if x coordinate !=0, as we have non-existing waypoints +Substract("%WPCounter%","1"); + +JumpTo("WaypointLoop", "%WPCounter%"); +// END WAYPOINT LOOP \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/Scripts/MP Move 4 starting points into corners.fscript b/MissionEditor/data/FinalSun/Scripts/MP Move 4 starting points into corners.fscript new file mode 100644 index 0000000..63fc5d9 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/MP Move 4 starting points into corners.fscript @@ -0,0 +1,52 @@ +// FinalSun Script file +// Name: Move 4 starting points close to corners +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +// only for multiplayer maps: +RequiresMP(); + +Is("%PlayerCount%","!=", "4", "4Players?"); +Print("Warning: Script usually should be used only on 4 player maps.","4Players?"); +Print("This map currently has %PlayerCount% players.","4Players?"); +Print("The map will be set up for at least 4 players","4Players?"); + +AskContinue("This tool will move the starting locations of the first 4 players into the corners of the map. It needs to disable INI protection to do this."); + +// disable safe mode so that we can move already existing waypoints, not just create new ones +// user must allow the script to do this. If he does not, the waypoints won�t be moved if they +// already exist. +SetSafeMode("FALSE","Necessary for moving waypoints"); + +// Waypoint 0: +SetVariable("Y", "20"); +SetVariable("X", "%Width%"); + +SetWaypoint("0", "X", "Y"); + + +// Waypoint 1: +SetVariable("X", "20"); +SetVariable("Y", "%Width%"); + +SetWaypoint("1", "X", "Y"); + + +// helper variable for 2,3: +SetVariable("V", "%IsoSize%"); +Substract("V", "20"); + +// Waypoint 2: +SetVariable("X", "%Height%"); +SetVariable("Y", "V"); + +SetWaypoint("2", "X", "Y"); + +// Waypoint 3: +SetVariable("Y", "%Height%"); +SetVariable("X", "V"); + +SetWaypoint("3", "X", "Y"); + diff --git a/MissionEditor/data/FinalSun/Scripts/Make all aircraft recruitable.fscript b/MissionEditor/data/FinalSun/Scripts/Make all aircraft recruitable.fscript new file mode 100644 index 0000000..fc336a4 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Make all aircraft recruitable.fscript @@ -0,0 +1,56 @@ +// FinalSun Script file +// Name: Make Aircraft Recruitable +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing aircraft"); +AllowAdd("Necessary for changing aircraft"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit changes to a specific house?","Limit to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%AircraftCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%AircraftCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetAircraft("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteAircraft("%pos%"); + +// recruitable & AI recruitable +SetParam("%data%","10","1"); +SetParam("%data%","11","1"); + +AddAircraft("%data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); + + diff --git a/MissionEditor/data/FinalSun/Scripts/Make all infantry recruitable.fscript b/MissionEditor/data/FinalSun/Scripts/Make all infantry recruitable.fscript new file mode 100644 index 0000000..098c72f --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Make all infantry recruitable.fscript @@ -0,0 +1,58 @@ +// FinalSun Script file +// Name: Make Infantry Recruitable +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing infantry"); +AllowAdd("Necessary for changing infantry"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit changes to a specific house?","Limit to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%InfantryCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%InfantryCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +IsInfantryDeleted("%deleted?%","%pos%"); +Is("%deleted?%","=","0","%existing%"); +GetInfantry("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteInfantry("%pos%","%existing%"); + +// recruitable & AI recruitable +SetParam("%data%","12","1","%existing%"); +SetParam("%data%","13","1","%existing%"); + +AddInfantry("%data%","%existing%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); + + diff --git a/MissionEditor/data/FinalSun/Scripts/Make all units recruitable.fscript b/MissionEditor/data/FinalSun/Scripts/Make all units recruitable.fscript new file mode 100644 index 0000000..a331a11 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Make all units recruitable.fscript @@ -0,0 +1,56 @@ +// FinalSun Script file +// Name: Make Vehicle Recruitable +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing vehicles"); +AllowAdd("Necessary for changing vehicles"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit changes to a specific house?","Limit to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%UnitCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%UnitCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +GetVehicle("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteVehicle("%pos%"); + +// recruitable & AI recruitable +SetParam("%data%","12","1"); +SetParam("%data%","13","1"); + +AddVehicle("%data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); + + diff --git a/MissionEditor/data/FinalSun/Scripts/Random Aircraft facing.fscript b/MissionEditor/data/FinalSun/Scripts/Random Aircraft facing.fscript new file mode 100644 index 0000000..2c04b3f --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Random Aircraft facing.fscript @@ -0,0 +1,61 @@ +// FinalSun Script file +// Name: Change Unit Facing +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing infantry"); +AllowAdd("Necessary for changing infantry"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit random aircraft facing to a specific house?","Limit Random Aircraft facing to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%AircraftCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%AircraftCount%"); + + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); + +GetAircraft("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteAircraft("%pos%"); +GetRandom("%Facing%"); + +// convert random (0-32767) to 8 directions +Divide("%Facing%","4096"); + +// convert 8 directions to degrees +Multi("%Facing%","32"); + +SetParam("%data%","5","%Facing%"); + +AddAircraft("%data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/Scripts/Random Infantry Facing.fscript b/MissionEditor/data/FinalSun/Scripts/Random Infantry Facing.fscript new file mode 100644 index 0000000..0049e01 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Random Infantry Facing.fscript @@ -0,0 +1,65 @@ +// FinalSun Script file +// Name: Change Infantry Facing +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing infantry"); +AllowAdd("Necessary for changing infantry"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit random infantry facing to a specific house?","Limit Random Infantry facing to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%InfantryCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%InfantryCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); +IsInfantryDeleted("%deleted?%","%pos%"); +Is("%deleted?%","=","0","%existing%"); +GetInfantry("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + +DeleteInfantry("%pos%","%existing%"); +GetRandom("%Facing%"); + +// convert random (0-32767) to 8 directions +Divide("%Facing%","4096"); + +// convert 8 directions to degrees +Multi("%Facing%","32"); + +Print("%Facing%"); + +SetParam("%data%","7","%Facing%","%existing%"); + +AddInfantry("%data%","%existing%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); + + diff --git a/MissionEditor/data/FinalSun/Scripts/Random Unit Facing.fscript b/MissionEditor/data/FinalSun/Scripts/Random Unit Facing.fscript new file mode 100644 index 0000000..d82e241 --- /dev/null +++ b/MissionEditor/data/FinalSun/Scripts/Random Unit Facing.fscript @@ -0,0 +1,61 @@ +// FinalSun Script file +// Name: Change Unit Facing +// Written By: Matthias Wagner +// Last Change: August 21, 2001 +// Be careful when editing scripts, they may cause damage to maps if used improperly + + +AllowDelete("Necessary for changing infantry"); +AllowAdd("Necessary for changing infantry"); +Is("%DeleteAllowed%","=","0","%NoDelete%"); +Print("Deletion must be allowed for this script to run!","%NoDelete%"); +Cancel("%NoDelete%"); +Is("%AddAllowed%","=","0","%NoAdd%"); +Print("Adding must be allowed for this script to run!","%NoAdd%"); +Cancel("%NoAdd%"); + +Ask("%specified%","Do you want to limit random unit facing to a specific house?","Limit Random Unit facing to house"); + +SetVariable("%House%",""); +UInputGetHouse("%House%","House:","%specified%"); + +SetAutoUpdate("FALSE"); // no screen flickering... + +Is("%UnitCount%","=","0","%Abort%"); +Cancel("%Abort%"); + +SetVariable("%TCounter%","%UnitCount%"); + +// LOOP BEGIN +:Loop: +SetVariable("%pos%","%TCounter%"); +Substract("%pos%","1"); + +GetVehicle("%data%","%pos%"); + +SetVariable("%Differ%","0"); +GetParam("%param%", "%data%", "0", "%specified%"); +Is("%param%","!=","%House%","%Differ%","%specified%"); + +Substract("%TCounter%","1", "%Differ%"); +And("%cancelloop%","%Differ%", "%TCounter%"); +JumpTo("Loop", "%cancelloop%"); + +// if we are here, and Differ is set to TRUE, TCounter must be 0, so cancel script. +Cancel("%Differ%"); + + +DeleteVehicle("%pos%"); +GetRandom("%Facing%"); + +// convert random (0-32767) to 8 directions +Divide("%Facing%","4096"); + +// convert 8 directions to degrees +Multi("%Facing%","32"); + +SetParam("%data%","5","%Facing%"); + +AddVehicle("%data%"); +Substract("%TCounter%", "1", "%TCounter%"); // only substract if >=0, else infinite loop! +JumpTo("Loop","%TCounter%"); \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/StdMapTS.ini b/MissionEditor/data/FinalSun/StdMapTS.ini new file mode 100644 index 0000000..81c2dba --- /dev/null +++ b/MissionEditor/data/FinalSun/StdMapTS.ini @@ -0,0 +1,62 @@ +; This file provides a standard template for every new map created in FinalSun +; Be careful editing this file! +; [Map] section is ignored as FinalSun will automatically create it +; Packed sections may work, but I haven�t tried this! +; You should not edit this file, as it may cause FinalSun�s created maps to crash +; Last change: November 14th 2000 + +[Basic] +NextScenario= +AltNextScenario= +Name=No name +NewINIFormat=4 +CarryOverCap=0 +EndOfGame=no +SkipScore=no +OneTimeOnly=no +SkipMapSelect=no +Official=yes +IgnoreGlobalAITriggers=no +TruckCrate=no +TrainCrate=no +Percent=0 +CarryOverMoney=0.000000 +HomeCell=98 +AltHomeCell=99 +MultiplayerOnly=0 +TiberiumGrowthEnabled=yes +VeinGrowthEnabled=yes +IceGrowthEnabled=yes +TiberiumDeathToVisceroid=no +FreeRadar=no +InitTime=10000 + +[Lighting] +Ambient=1.000000 +Red=1.000000 +Green=1.000000 +Blue=1.000000 +Ground=0.000000 +Level=0.032000 +IonAmbient=1.000000 +IonRed=1.000000 +IonGreen=1.000000 +IonBlue=1.000000 +IonGround=0.000000 +IonLevel=0.032000 + +[SpecialFlags] +TiberiumGrows=yes +TiberiumSpreads=yes +TiberiumExplosive=no +DestroyableBridges=yes +MCVDeploy=no +InitialVeteran=no +FixedAlliance=no +HarvesterImmune=no +FogOfWar=no +Inert=no +IonStorms=no +Meteorites=no +Visceroids=yes + diff --git a/MissionEditor/data/FinalSun/TIPS.DEU b/MissionEditor/data/FinalSun/TIPS.DEU new file mode 100644 index 0000000..f49e3bb --- /dev/null +++ b/MissionEditor/data/FinalSun/TIPS.DEU @@ -0,0 +1,9 @@ +Diese Tips & Tricks sollten Ihnen helfen, tolle neue Karten fĂ¼r Tiberian Sun und Firestorm zu erstellen. Lesen Sie bitte möglichst viele durch, es lohnt sich. +Falls AutoShore beim Plazieren von Tiles stören sollte, können Sie es Ă¼ber das Optionen-MenĂ¼ deaktivieren. +Sie sollten unbedingt die neuen Klippen-Plazierungs-Werkzeuge ausprobieren. Sie finden sie in der Werkzeugleiste. Einfach auswählen, auf die Karte klicken, gedrĂ¼ckt halten, und Maus in Klippenrichtung bewegen. +Nachdem Sie in den Terrain-Plazierungsmodus gewechselt haben, können Sie die Pfeiltasten benutzen, um durch die verfĂ¼gbaren Tilesets und Tiles zu scrollen. +Benutzen Sie die Show/Hide Funktionen, um einzelne Felder oder Terraintypen unsichtbar zu machen. Damit ist es oft viel leichter, gewisse Kartenabschnitte zu editieren. +Haben Sie bereits den Assistenten fĂ¼r neue Karten (unter Datei->Neu) getestet? Er bereitet automatisch alles vor, was Sie fĂ¼r eine Einzelspieler und Mehrspieler-Karte benötigen. +Erstellen Sie komplett neue Karten durch die Fähigkeit von FinalSun, das Terrain zu editieren! +Beachten Sie auch die Statusleiste am unteren Fensterrand. Sie hat oft hilfreiche Informationen parat. +Beachten Sie, dass die Brush/Pinsel-Grösse sowohl fĂ¼r "paint terrain", als auch fĂ¼r "flatten terrain" und "raise/lower" terrain benutzt wird. diff --git a/MissionEditor/data/FinalSun/TIPS.ENG b/MissionEditor/data/FinalSun/TIPS.ENG new file mode 100644 index 0000000..4305bb7 --- /dev/null +++ b/MissionEditor/data/FinalSun/TIPS.ENG @@ -0,0 +1,9 @@ +These tips should help you to create cool Tiberian Sun and Firestorm maps. +If you do not want AutoShore to be applied when placing tiles, you can disable AutoShore (and AutoLat) in the Options menu. +You should really try the new cliff painting tools. They both are in the toolbar. Select them, click on the map, hold down the mouse button, and move the mouse into the cliff direction. +After you have activated the tile/terrain placing mode, you can use the arrow keys to scroll through the different tilesets and tiles. +Use the show/hide functions to make certain fields or terrain types invisible. Using this, map editing in certain parts of the map becomes much easier. +Have you already tried out the "New map assistant" (File->New)? It creates all the stuff you need for a singleplayer and multiplayer map. +Create completely new maps with FinalSun 2.0! +Pay attention to the status bar at the bottom of the window. It often contains useful information. +Consider that the brush size works for "paint terrain", "flatten terrain" (important!) and for "raise/lower" terrain. diff --git a/MissionEditor/data/FinalSun/show_appdata.bat b/MissionEditor/data/FinalSun/show_appdata.bat new file mode 100644 index 0000000..2ad2f4a --- /dev/null +++ b/MissionEditor/data/FinalSun/show_appdata.bat @@ -0,0 +1 @@ +start explorer "%LOCALAPPDATA%\FinalSun" \ No newline at end of file diff --git a/MissionEditor/data/FinalSun/show_log.bat b/MissionEditor/data/FinalSun/show_log.bat new file mode 100644 index 0000000..26b2a83 --- /dev/null +++ b/MissionEditor/data/FinalSun/show_log.bat @@ -0,0 +1 @@ +start notepad "%LOCALAPPDATA%/FinalSun/finalsunlog.txt" \ No newline at end of file diff --git a/MissionEditor/data/shared/3rdParty/licenses/lzo/copyright.txt b/MissionEditor/data/shared/3rdParty/licenses/lzo/copyright.txt new file mode 100644 index 0000000..e4df8cb --- /dev/null +++ b/MissionEditor/data/shared/3rdParty/licenses/lzo/copyright.txt @@ -0,0 +1,21 @@ +Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer +All Rights Reserved. + +The LZO library is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of +the License, or (at your option) any later version. + +The LZO library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the LZO library; see the file COPYING. +If not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Markus F.X.J. Oberhumer +<markus@oberhumer.com> +http://www.oberhumer.com/opensource/lzo/ \ No newline at end of file diff --git a/MissionEditor/data/shared/3rdParty/licenses/xcc/copyright.txt b/MissionEditor/data/shared/3rdParty/licenses/xcc/copyright.txt new file mode 100644 index 0000000..1052164 --- /dev/null +++ b/MissionEditor/data/shared/3rdParty/licenses/xcc/copyright.txt @@ -0,0 +1,15 @@ +XCC Utilities and Library +Copyright (C) 2000 Olaf van der Spek <olafvdspek@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. diff --git a/MissionEditor/data/shared/3rdParty/licenses/xcc/modifications.txt b/MissionEditor/data/shared/3rdParty/licenses/xcc/modifications.txt new file mode 100644 index 0000000..d6a5010 --- /dev/null +++ b/MissionEditor/data/shared/3rdParty/licenses/xcc/modifications.txt @@ -0,0 +1,5 @@ +This software contains parts of the XCC library by Olaf van der Spek available under https://github.com/OlafvdSpek/xcc/ (specifically a modified subset of https://github.com/OlafvdSpek/xcc/tree/70358b46858973426c1ecf204485cb2a88716217/). +It has been stripped down to only the required parts and uses the dynamically linked C runtime. + +Please see copyright.txt and COPYING for the copyright notice and the license of the included files and https://github.com/OlafvdSpek/xcc/ for all legal and licensing terms. + diff --git a/MissionEditor/data/shared/Changelog.txt b/MissionEditor/data/shared/Changelog.txt new file mode 100644 index 0000000..801235e --- /dev/null +++ b/MissionEditor/data/shared/Changelog.txt @@ -0,0 +1,25 @@ +New features for FinalSun and FinalAlert 2 (Yuri's Revenge) + +2.0 +--- +- Fixed a few code issues to allow the application to run on modern operating systems. +- Updated the application icons with new 256x256 graphics. +- You can now zoom in & out with the middle mouse button or wheel +- You don't need administrator access anymore if the program is installed in the program folder, as all user data and settings are now stored in your AppData folder +- Tunnel tube editing completely reimplemented + + Tunnel tilesets available + + You can edit existing tubes by using the tool on the end of an existing tube + + You can now create curved tubes + + You can now create unidirectional tubes +- LAT support for Crystal and Swamp terrain in Tiberian Sun temperate maps +- House colors are now read from map or rules.ini +- Units and buildings are now shaded in the house colors correctly +- Voxel units now have shading applied +- Minimap can now be resized +- Undo steps increased to 64 +- Map rendering performance improved +- Several fixes for crashes +- Fixed addon turrets display +- SHP turrets and Voxel turrets + barrels have their positioning fixed. +- Maps up to 400x112 (or 112x400) are now allowed. +- Fixed minimap for non-quadratic maps. diff --git a/MissionEditor/data/shared/voxel_normal_tables.bin b/MissionEditor/data/shared/voxel_normal_tables.bin new file mode 100644 index 0000000..6588fe4 Binary files /dev/null and b/MissionEditor/data/shared/voxel_normal_tables.bin differ diff --git a/MissionEditor/functions.cpp b/MissionEditor/functions.cpp new file mode 100644 index 0000000..4974653 --- /dev/null +++ b/MissionEditor/functions.cpp @@ -0,0 +1,1773 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// standard functions + +#include "stdafx.h" +#include "FinalSunDlg.h" +#include "TSoptions.h" +#include "variables.h" +#include "functions.h" +#include "inlines.h" +#include "mmsystem.h" + + +#define DBG +#undef DBG + +#define DBG2 +#undef DBG2 + +bool isValidUtf8(const char* utf8) +{ + // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32 + auto utf8Count = strlen(utf8); + if (utf8Count == 0) + return true; + + // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1) + auto unterminatedCountWChars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8, utf8Count, nullptr, 0); + return unterminatedCountWChars > 0; +} + +std::wstring utf8ToUtf16(const std::string& utf8) +{ + // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32 + if (utf8.size() == 0) + // MultiByteToWideChar does not support passing in cbMultiByte == 0 + return L""; + + // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1) + auto utf8Count = utf8.size(); + auto unterminatedCountWChars = MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8.data(), utf8Count, nullptr, 0); + if (unterminatedCountWChars == 0) + { + throw std::runtime_error("UTF8 -> UTF16 conversion failed"); + } + + std::wstring utf16; + utf16.resize(unterminatedCountWChars); + if (MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8.data(), utf8Count, utf16.data(), unterminatedCountWChars) == 0) + { + throw std::runtime_error("UTF8 -> UTF16 conversion failed"); + } + return utf16; +} + +std::wstring utf8ToUtf16(const char* utf8) +{ + // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32 + auto utf8Count = strlen(utf8); + if (utf8Count == 0) + // MultiByteToWideChar does not support passing in cbMultiByte == 0 + return L""; + + // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1) + auto unterminatedCountWChars = MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8, utf8Count, nullptr, 0); + if (unterminatedCountWChars == 0) + { + throw std::runtime_error("UTF8 -> UTF16 conversion failed"); + } + + std::wstring utf16; + utf16.resize(unterminatedCountWChars); + if (MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8, utf8Count, utf16.data(), unterminatedCountWChars) == 0) + { + throw std::runtime_error("UTF8 -> UTF16 conversion failed"); + } + return utf16; +} + +std::string utf16ToCP(const std::wstring& utf16, int CP) +{ + // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32 + if (utf16.size() == 0) + // WideCharToMultiByte does not support passing in cbMultiByte == 0 + return ""; + + // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1) + auto utf16Count = utf16.size(); + auto unterminatedCountChars = WideCharToMultiByte(CP, CP == CP_UTF8 ? WC_ERR_INVALID_CHARS : 0, utf16.data(), utf16Count, nullptr, 0, nullptr, nullptr); + if (unterminatedCountChars == 0) + { + throw std::runtime_error(CP == CP_UTF8 ? "UTF16 -> UTF8 conversion failed" : "UTF16 -> MultiByte conversion failed"); + } + + std::string cps; + cps.resize(unterminatedCountChars); + if (WideCharToMultiByte(CP, CP == CP_UTF8 ? WC_ERR_INVALID_CHARS : 0, utf16.data(), utf16Count, cps.data(), unterminatedCountChars, nullptr, nullptr) == 0) + { + throw std::runtime_error(CP == CP_UTF8 ? "UTF16 -> UTF8 conversion failed" : "UTF16 -> MultiByte conversion failed"); + } + return cps; +} + +std::string utf16ToUtf8(const std::wstring& utf16) +{ + return utf16ToCP(utf16, CP_UTF8); +} + +std::string utf16ToACP(const std::wstring& utf16) +{ + return utf16ToCP(utf16, CP_ACP); +} + +// strcpy for overlapping strings +char *strcpy_safe( char *strDestination, const char *strSource ) +{ + /*char* buffer=new(char[strlen(strSource)+1]); + strcpy(buffer, strSource); + + strcpy(strDestination, buffer);*/ + + int len=strlen(strSource)+1; + memmove(strDestination, strSource, len); + + return strDestination; +} + +CString TranslateHouse(CString original, BOOL bToUI) +{ +#ifdef RA2_MODE + if(bToUI) + { + // CCStrings[*rules.sections[HOUSES].GetValue(i)].wString + int i; + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + original.Replace(*rules.sections[HOUSES].GetValue(i), CCStrings[*rules.sections[HOUSES].GetValue(i)].cString); + } + } + else + { + + int i; + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + original.Replace(CCStrings[*rules.sections[HOUSES].GetValue(i)].cString, *rules.sections[HOUSES].GetValue(i)); + } + } +#endif + return original; +} + + +bool deleteFile(const std::string& u8FilePath) +{ + return DeleteFileW(utf8ToUtf16(u8FilePath).c_str()) ? true : false; +} + +// set the status bar text in the main dialog +void SetMainStatusBar(const char* text) +{ + CFinalSunDlg* dlg=(CFinalSunDlg*)theApp.GetMainWnd(); + dlg->SetText(text); +} + +// set the status bar text in the main dialog to ready +void SetMainStatusBarReady() +{ + CFinalSunDlg* dlg=(CFinalSunDlg*)theApp.GetMainWnd(); + dlg->SetReady();; +} + +// Should not be required anymore +void RepairTrigger(CString& triggerdata) +{ + if(GetParam(triggerdata, 3).GetLength()==0) triggerdata=SetParam(triggerdata, 3, "0"); + if(GetParam(triggerdata, 4).GetLength()==0) triggerdata=SetParam(triggerdata, 4, "1"); + if(GetParam(triggerdata, 5).GetLength()==0) triggerdata=SetParam(triggerdata, 5, "1"); + if(GetParam(triggerdata, 6).GetLength()==0) triggerdata=SetParam(triggerdata, 6, "1"); + if(GetParam(triggerdata, 7).GetLength()==0) { + triggerdata=SetParam(triggerdata, 7, "0"); + } +} + +// make some UI noise +void Sound(int ID) +{ + if(theApp.m_Options.bNoSounds) return; + + if(ID==SOUND_NONE) return; + + LPCSTR lpSound=NULL; + + if(ID==SOUND_POSITIVE) + { + lpSound=MAKEINTRESOURCE(IDR_WAVE1); + } + else if(ID==SOUND_NEGATIVE) + lpSound=MAKEINTRESOURCE(IDR_WAVE2); + else if(ID==SOUND_LAYDOWNTILE) + lpSound=MAKEINTRESOURCE(IDR_WAVE3); + + + if(lpSound) + { + PlaySound(lpSound, GetModuleHandle(NULL), SND_ASYNC | SND_RESOURCE); + } +} + +void HandleParamList(CComboBox &cb, int type) +{ + CString oldText; + cb.GetWindowText(oldText); + + switch(type) + { + case PARAMTYPE_NOTHING: + { + while(cb.DeleteString(0)!=CB_ERR); + cb.SetWindowText(oldText); + + + //cb.AddString("0"); + } + break; + case PARAMTYPE_HOUSES: + ListHouses(cb, TRUE, TRUE, TRUE); + break; + case PARAMTYPE_WAYPOINTS: + ListWaypoints(cb); + break; + case PARAMTYPE_TEAMTYPES: + ListTeamTypes(cb, FALSE); + break; + case PARAMTYPE_UNITTYPES: + ListUnits(cb); + break; + case PARAMTYPE_INFANTRYTYPES: + ListInfantry(cb); + break; + case PARAMTYPE_AIRCRAFTTYPES: + ListAircraft(cb); + break; + case PARAMTYPE_BUILDINGTYPES: + ListBuildings(cb); + break; + case PARAMTYPE_VIDEOS: + ListMovies(cb, FALSE, TRUE); + break; + case PARAMTYPE_TUTORIALTEXTS: + ListTutorial(cb); + break; + case PARAMTYPE_TRIGGERS: + ListTriggers(cb); + break; + case PARAMTYPE_YESNO: + ListYesNo(cb); + break; + case PARAMTYPE_SOUNDS: + ListSounds(cb); + break; + case PARAMTYPE_THEMES: + ListThemes(cb); + break; + case PARAMTYPE_SPEECHES: + ListSpeeches(cb); + break; + case PARAMTYPE_SPECIALWEAPONS: + ListSpecialWeapons(cb); + break; + case PARAMTYPE_ANIMATIONS: + ListAnimations(cb); + break; + case PARAMTYPE_PARTICLES: + ListParticles(cb); + break; + case PARAMTYPE_CRATETYPES: + ListCrateTypes(cb); + break; + case PARAMTYPE_SPEECHBUBBLETYPES: + ListSpeechBubbleTypes(cb); + break; + case PARAMTYPE_GLOBALS: + ListGlobals(cb); + break; + case PARAMTYPE_RULESGLOBALS: + ListRulesGlobals(cb); + break; + case PARAMTYPE_BUILDINGTYPESINI: + ListBuildings(cb, TRUE); + break; + case PARAMTYPE_TECHTYPES: + ListTechtypes(cb); + break; + } +} + +void ShowOptionsDialog() +{ + // show the options dialog, and save the options. + +#ifdef RA2_MODE + CString game = "RA2"; + CString app = "FinalAlert"; +#else + CString game = "TS"; + CString app = "FinalSun"; +#endif + + std::string iniFile=""; + CIniFile optini; + iniFile=u8AppDataPath; +#ifndef RA2_MODE + iniFile+="\\FinalSun.ini"; +#else + iniFile+="\\FinalAlert.ini"; +#endif + optini.LoadFile(iniFile); + CTSOptions opt; + opt.m_TSEXE=theApp.m_Options.TSExe; + if(opt.DoModal()==IDCANCEL) return; + theApp.m_Options.TSExe=opt.m_TSEXE; + optini.sections[game].values["Exe"]=theApp.m_Options.TSExe; + optini.sections[app].values["Language"]=opt.m_LanguageName; + + BOOL bOldSearch=theApp.m_Options.bSearchLikeTS; + if(!(opt.m_LikeTS==1)) { + optini.sections[app].values["FileSearchLikeGame"]="yes"; + theApp.m_Options.bSearchLikeTS=TRUE; + } + else { + theApp.m_Options.bSearchLikeTS=FALSE; + optini.sections[app].values["FileSearchLikeGame"]="no"; + } + + auto bOldPreferLocalTheaterFiles = theApp.m_Options.bPreferLocalTheaterFiles; + theApp.m_Options.bPreferLocalTheaterFiles = opt.m_PreferLocalTheaterFiles ? true : false; + optini.sections[app].values["PreferLocalTheaterFiles"] = theApp.m_Options.bPreferLocalTheaterFiles ? "1" : "0"; + + + if ( + ( + (bOldPreferLocalTheaterFiles != theApp.m_Options.bPreferLocalTheaterFiles) || + (bOldSearch != theApp.m_Options.bSearchLikeTS) + ) && bOptionsStartup == FALSE) + MessageBox(0, GetLanguageStringACP("RestartNeeded"), "Restart", 0); + + + CString oldLang=theApp.m_Options.LanguageName; + theApp.m_Options.LanguageName=opt.m_LanguageName; + if(oldLang!=theApp.m_Options.LanguageName && theApp.m_pMainWnd!=NULL && theApp.m_pMainWnd->m_hWnd!=NULL) + ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateStrings(); + + optini.SaveFile(iniFile); +} + + +BOOL DoesFileExist(LPCSTR szFile) +{ + std::wstring file = utf8ToUtf16(szFile); + HANDLE hFound=CreateFileW(file.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL); + + if (hFound != INVALID_HANDLE_VALUE) + { + CloseHandle(hFound); + return TRUE; + } + return FALSE; +} + +CString ToACP(const CString& utf8) +{ + // convert to process codepage (should be UTF8 on newer systems) + auto cp = GetACP(); + return (cp == CP_UTF8) ? utf8 : CString(utf16ToACP(utf8ToUtf16(utf8)).c_str()); +} + +// change all %n (where n is an int) in an string, to another specified string +CString TranslateStringVariables(int n, const char* originaltext, const char* inserttext) +{ + char c[50]; + itoa(n,c,10); + + char seekedstring[50]; + seekedstring[0]='%'; + seekedstring[1]=0; + strcat(seekedstring, c); + + CString orig=originaltext; + if(orig.Find(seekedstring)<0) return orig; + + orig.Replace(seekedstring, inserttext); + + return orig; +} + +// retrieve the string name in the correct language (name is an ID). +CString GetLanguageStringACP(CString name) +{ +#ifdef RA2_MODE + CString sec2=theApp.m_Options.LanguageName+"-StringsRA2"; + if(language.sections[sec2].values.end()==language.sections[sec2].values.find(name)) + { + if(language.sections["English-StringsRA2"].FindName(name)>=0) + { + CString s=language.sections["English-StringsRA2"].values[name]; + return ToACP(s); + } + } + else + return ToACP(language.sections[sec2].values[name]); +#endif + + + if(language.sections[theApp.m_Options.LanguageName+"-Strings"].values.find(name)==language.sections[theApp.m_Options.LanguageName+"-Strings"].values.end()) + { + CString s=language.sections["English-Strings"].values[name]; +#ifndef RA2_MODE + s=TranslateStringVariables(9, s, "FinalSun"); +#else +#ifdef YR_MODE + s=TranslateStringVariables(9, s, "FinalAlert 2: Yuri's Revenge"); +#else + s=TranslateStringVariables(9, s, "FinalAlert 2"); +#endif +#endif + return ToACP(s); + } + + CString s; + s= language.sections[theApp.m_Options.LanguageName+"-Strings"].values[name]; + +#ifndef RA2_MODE + if(s.Find("%9")>=0) s=TranslateStringVariables(9,s,"FinalSun"); +#else +#ifdef YR_MODE + if(s.Find("%9")>=0) s=TranslateStringVariables(9,s,"FinalAlert 2: Yuri's Revenge"); +#else + if(s.Find("%9")>=0) s=TranslateStringVariables(9,s,"FinalAlert 2"); +#endif +#endif + + + + return ToACP(s); +} + +CString TranslateStringACP(WCHAR* u16EnglishString) +{ + return TranslateStringACP(utf16ToUtf8(u16EnglishString).c_str()); +} + +// tranlate a string/word by using the table from english to the current language +CString TranslateStringACP(CString u8EnglishString) +{ + if (!isValidUtf8(u8EnglishString)) + { + errstream << "TranslateStringACP(\"" << u8EnglishString << "\") called with an invalid UTF-8 string" << std::endl; + return u8EnglishString; + } + +#ifdef RA2_MODE + CString sec2=theApp.m_Options.LanguageName+"-TranslationsRA2"; + if(language.sections[sec2].values.end()==language.sections[sec2].values.find(u8EnglishString)) + { + if(language.sections["English-TranslationsRA2"].FindName(u8EnglishString)>=0) + { + CString s=language.sections["English-TranslationsRA2"].values[u8EnglishString]; + return ToACP(s); + } + } + else + return ToACP(language.sections[sec2].values[u8EnglishString]); +#endif + + + CString sec=theApp.m_Options.LanguageName+"-Translations"; + + // check if the string can be translated + if(language.sections[sec].values.end()==language.sections[sec].values.find(u8EnglishString)) + { + CString seceng; + seceng="English-Translations"; + if(language.sections[seceng].FindName(u8EnglishString)>=0) + { + CString s=language.sections[seceng].values[u8EnglishString]; +#ifndef RA2_MODE + s=TranslateStringVariables(9, s, "FinalSun"); +#else +#ifdef YR_MODE + s=TranslateStringVariables(9, s, "FinalAlert 2: Yuri's Revenge"); +#else + s=TranslateStringVariables(9, s, "FinalAlert 2"); +#endif +#endif + return ToACP(s); + } +#ifndef RA2_MODE + return ToACP(TranslateStringVariables(9,u8EnglishString,"FinalSun")); +#else +#ifdef YR_MODE + return ToACP(TranslateStringVariables(9,u8EnglishString,"FinalAlert 2: Yuri's Revenge")); +#else + return ToACP(TranslateStringVariables(9,u8EnglishString,"FinalAlert 2")); +#endif +#endif + } + + CString s=language.sections[sec].values[u8EnglishString]; +#ifndef RA2_MODE + s=TranslateStringVariables(9,s,"FinalSun"); +#else +#ifdef YR_MODE + s=TranslateStringVariables(9,s,"FinalAlert 2: Yuri's Revenge"); +#else + s=TranslateStringVariables(9,s,"FinalAlert 2"); +#endif +#endif + + return ToACP(s); +} + + + +void TruncSpace(string& str) +{ + CString cstr=str.data(); + TruncSpace(cstr); + str=cstr; +} +void TruncSpace(CString& str) +{ + str.TrimLeft(); + str.TrimRight(); + if(str.Find(" ")>=0) str.Delete(str.Find(" "), str.GetLength()-str.Find(" ")); +} + +CString GetText(CWnd* wnd){ + CString str; + wnd->GetWindowText(str); + return str; +} + +CString GetText(CSliderCtrl* wnd) +{ + int v=wnd->GetPos(); + char c[150]; + itoa(v,c,10); + return(c); +} + +CString GetText(CComboBox* wnd){ + + CString str; + if(wnd->GetCurSel()!=-1) + { + wnd->GetLBText(wnd->GetCurSel(), str); + return str; + } + + wnd->GetWindowText(str); + + return(str); +} + + + +void Info(const char* data, string& house, string& type, int& strength, int& x, int& y, string & other) +{ + other=""; + house=GetParam(data, 0); + type=GetParam(data, 1); + strength=atoi(GetParam(data, 2)); + y=atoi(GetParam(data, 3)); + x=atoi(GetParam(data, 4)); + + CString tmp; + BOOL takeABreak=FALSE; + int i=1; + do{ + + tmp=GetParam(data, 4+i); + //MessageBox(0,tmp.data(),"",0); + if(tmp!="") + { + other+=","; + other+=tmp; + } + else + { + takeABreak=TRUE; + break; + } + i++; + }while(takeABreak==FALSE); +}; + +void UnitInfo(const char* data, string& house, string& type, int& strength, int& x, int& y, int& direction, string& action, string& actiontrigger, int & u1, int & u2, int& u3, int& u4, int& u5, int& u6) +{ + house=GetParam(data, 0); + type=GetParam(data, 1); + strength=atoi(GetParam(data, 2)); + y=atoi(GetParam(data, 3)); + x=atoi(GetParam(data, 4)); + direction=atoi(GetParam(data, 5)); + action=GetParam(data, 6); + actiontrigger=GetParam(data, 7); + u1=atoi(GetParam(data, 8)); + u2=atoi(GetParam(data, 9)); + u3=atoi(GetParam(data, 10)); + u4=atoi(GetParam(data, 11)); + u5=atoi(GetParam(data, 12)); + u6=atoi(GetParam(data, 13)); +} + +void AirInfo(const char* data, string& house, string& type, int& strength, int& x, int& y, int& direction, string& action, string& actiontrigger, int & u1, int & u2, int& u3, int& u4) +{ + house=GetParam(data, 0); + type=GetParam(data, 1); + strength=atoi(GetParam(data, 2)); + y=atoi(GetParam(data, 3)); + x=atoi(GetParam(data, 4)); + direction=atoi(GetParam(data, 5)); + action=GetParam(data, 6); + actiontrigger=GetParam(data, 7); + u1=atoi(GetParam(data, 8)); + u2=atoi(GetParam(data, 9)); + u3=atoi(GetParam(data, 10)); + u4=atoi(GetParam(data, 11)); +} + + + +void InfanteryInfo(const char* data, string& house, string& type, int& strength, int& x, int& y, int& pos, string& action, int& direction, string& actiontrigger, int & u1, int & u2, int& u3, int& u4, int& u5) +{ + house=GetParam(data, 0); + type=GetParam(data, 1); + strength=atoi(GetParam(data, 2)); + y=atoi(GetParam(data, 3)); + x=atoi(GetParam(data, 4)); + pos=atoi(GetParam(data, 5)); + action=GetParam(data, 6); + direction=atoi(GetParam(data, 7)); + actiontrigger=GetParam(data, 8); + u1=atoi(GetParam(data, 9)); + u2=atoi(GetParam(data, 10)); + u3=atoi(GetParam(data, 11)); + u4=atoi(GetParam(data, 12)); + u5=atoi(GetParam(data, 12)); +} + +void StructureInfo(const char* data, string& house, string& type, int& strength, int& x, int& y, int& direction, string& action, int & u1, int & u2, int& energy, int& upgrades, int& u5, string& upgrade1, string& upgrade2, string& upgrade3, int& u9, int& u10) +{ + house=GetParam(data, 0); + type=GetParam(data, 1); + strength=atoi(GetParam(data, 2)); + y=atoi(GetParam(data, 3)); + x=atoi(GetParam(data, 4)); + direction=atoi(GetParam(data, 5)); + action=GetParam(data, 6); + u1=atoi(GetParam(data, 7)); + u2=atoi(GetParam(data, 8)); + energy=atoi(GetParam(data, 9)); + upgrades=atoi(GetParam(data, 10)); + u5=atoi(GetParam(data, 11)); + upgrade1=GetParam(data, 12); + upgrade2=GetParam(data, 13); + upgrade3=GetParam(data, 14); + u9=atoi(GetParam(data, 15)); + u10=atoi(GetParam(data, 16)); +} + +void PosToXY(const char* pos, int* X, int* Y) +{ + int Posleng; + //int XX, YY; + char Pos[100]; + strcpy(Pos, pos); + char XS[10], YS[10]; + Posleng = strlen(Pos); + strcpy(YS, Pos+Posleng-3); + Pos[Posleng-3]=0; + strcpy(XS, Pos); + + *X = atoi(XS); + *Y = atoi(YS); + +} + +bool HSVToRGB(const float h, const float s, const float v, float& r, float& g, float& b) +{ + if (h < 0.0 || h >= 360.0 || s < 0.0 || s > 1.0 || v < 0.0 || v > 1.0) + return false; + const int h_ = floor(h / 60.0); + const float c = s * v; + const float x = c * (1 - fabs(fmod(h / 60.0, 2.0) - 1)); + const float m = v - c; + switch(h_) + { + case 0: + r = c, g = x, b = 0.0; + break; + case 1: + r = x, g = c, b = 0.0; + break; + case 2: + r = 0.0, g = c, b = x; + break; + case 3: + r = 0.0, g = x, b = c; + break; + case 4: + r = x, g = 0.0, b = c; + break; + case 5: + r = c, g = 0.0, b = x; + break; + } + r += m; + g += m; + b += m; + return true; +} + +void HSVToRGB(const unsigned char hsv[3], unsigned char rgb[3]) +{ + float frgb[3]; + HSVToRGB(hsv[0] * 360.0 / 255.0, hsv[1] / 255.0, hsv[2] / 255.0, frgb[0], frgb[1], frgb[2]); + for (int i = 0; i < 3; ++i) + rgb[i] = (frgb[i] < 0.0 ? 0.0 : (frgb[i] > 1.0 ? 1.0 : frgb[i])) * 255.0; +} + +std::array<unsigned char, 3> HSVToRGB(const float h, const float s, const float v) +{ + std::array<float, 3> frgb; + HSVToRGB(h, s, v, frgb[0], frgb[1], frgb[2]); + std::array<unsigned char, 3> ret; + for (int i = 0; i < 3; ++i) + ret[i] = (frgb[i] < 0.0 ? 0.0 : (frgb[i] > 1.0 ? 1.0 : frgb[i])) * 255.0; + return ret; +} + +std::array<unsigned char, 3> HSVToRGB(const unsigned char hsv[3]) +{ + std::array<unsigned char, 3> ret; + HSVToRGB(hsv, ret.data()); + return ret; +} + +void ListBuildings(CComboBox& cb, BOOL bININame) +{ + while(cb.DeleteString(0)!=CB_ERR); + + int i; + for(i=0;i<rules.sections["BuildingTypes"].values.size();i++) + { + if(rules.sections["BuildingTypes"].GetValueOrigPos(i)<0) continue; + + char c[50]; + itoa(rules.sections["BuildingTypes"].GetValueOrigPos(i),c,10); + CString s=c; + + + //s+=rules.sections[*rules.sections["BuildingTypes"].GetValue(i)].values["Name"]; + //s+=Map->GetUnitName(*rules.sections["BuildingTypes"].GetValue(i)); + + if(bININame) s=*rules.sections["BuildingTypes"].GetValue(i); + + s+=" "; + + CString t=Map->GetUnitName(*rules.sections["BuildingTypes"].GetValue(i)); + //if(t!="MISSING") + { + s+=t; + cb.AddString(s); + } + } +} + +void ListInfantry(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<rules.sections["InfantryTypes"].values.size();i++) + { + if(rules.sections["InfantryTypes"].GetValueOrigPos(i)<0) continue; + + char c[50]; + itoa(rules.sections["InfantryTypes"].GetValueOrigPos(i),c,10); + CString s=c; + + s+=" "; + //s+=Map->GetUnitName(*rules.sections["InfantryTypes"].GetValue(i)); + CString t=Map->GetUnitName(*rules.sections["InfantryTypes"].GetValue(i)); + //if(t!="MISSING") + { + s+=t; + cb.AddString(s); + } + } +} + +void ListUnits(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<rules.sections["VehicleTypes"].values.size();i++) + { + if(rules.sections["VehicleTypes"].GetValueOrigPos(i)<0) continue; + + char c[50]; + itoa(rules.sections["VehicleTypes"].GetValueOrigPos(i),c,10); + CString s=c; + + s+=" "; + //s+=rules.sections[*rules.sections["VehicleTypes"].GetValue(i)].values["Name"]; + CString t=Map->GetUnitName(*rules.sections["VehicleTypes"].GetValue(i)); + //if(t!="MISSING") + { + s+=t; + cb.AddString(s); + } + } +} + +void ListAircraft(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<rules.sections["AircraftTypes"].values.size();i++) + { + if(rules.sections["AircraftTypes"].GetValueOrigPos(i)<0) continue; + + char c[50]; + itoa(rules.sections["AircraftTypes"].GetValueOrigPos(i),c,10); + CString s=c; + + s+=" "; + //s+=rules.sections[*rules.sections["AircraftTypes"].GetValue(i)].values["Name"]; + CString t=Map->GetUnitName(*rules.sections["AircraftTypes"].GetValue(i)); + //if(t!="MISSING") + { + s+=t; + cb.AddString(s); + } + } +} + +void ListTechtypes(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<rules.sections["AircraftTypes"].values.size();i++) + { + if(rules.sections["AircraftTypes"].GetValueOrigPos(i)<0) continue; + + //char c[50]; + //itoa(rules.sections["AircraftTypes"].GetValueOrigPos(i),c,10); + CString s=*rules.sections["AircraftTypes"].GetValue(i); + + s+=" "; + //s+=rules.sections[*rules.sections["AircraftTypes"].GetValue(i)].values["Name"]; + CString t=Map->GetUnitName(*rules.sections["AircraftTypes"].GetValue(i)); + //if(t!="MISSING") + { + s+=t; + cb.AddString(s); + } + } + for(i=0;i<rules.sections["InfantryTypes"].values.size();i++) + { + if(rules.sections["InfantryTypes"].GetValueOrigPos(i)<0) continue; + + //char c[50]; + //itoa(rules.sections["InfantryTypes"].GetValueOrigPos(i),c,10); + CString s=*rules.sections["InfantryTypes"].GetValue(i); + + s+=" "; + //s+=rules.sections[*rules.sections["InfantryTypes"].GetValue(i)].values["Name"]; + CString t=Map->GetUnitName(*rules.sections["InfantryTypes"].GetValue(i)); + //if(t!="MISSING") + { + s+=t; + cb.AddString(s); + } + } + for(i=0;i<rules.sections["VehicleTypes"].values.size();i++) + { + if(rules.sections["VehicleTypes"].GetValueOrigPos(i)<0) continue; + + //char c[50]; + //itoa(rules.sections["VehicleTypes"].GetValueOrigPos(i),c,10); + CString s=*rules.sections["VehicleTypes"].GetValue(i); + + s+=" "; + //s+=rules.sections[*rules.sections["VehicleTypes"].GetValue(i)].values["Name"]; + CString t=Map->GetUnitName(*rules.sections["VehicleTypes"].GetValue(i)); + //if(t!="MISSING") + { + s+=t; + cb.AddString(s); + } + } + for(i=0;i<rules.sections["BuildingTypes"].values.size();i++) + { + if(rules.sections["BuildingTypes"].GetValueOrigPos(i)<0) continue; + + //char c[50]; + //itoa(rules.sections["BuildingTypes"].GetValueOrigPos(i),c,10); + CString s=*rules.sections["BuildingTypes"].GetValue(i); + + s+=" "; + //s+=rules.sections[*rules.sections["BuildingTypes"].GetValue(i)].values["Name"]; + CString t=Map->GetUnitName(*rules.sections["BuildingTypes"].GetValue(i)); + //if(t!="MISSING") + { + s+=t; + cb.AddString(s); + } + } +} + +// should be ListLocals() +void ListGlobals(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + CIniFile& ini=Map->GetIniFile(); + for(i=0;i<ini.sections["VariableNames"].values.size();i++) + { + CString s=*ini.sections["VariableNames"].GetValueName(i); + s+=" "; + s+=*ini.sections["VariableNames"].GetValue(i); + + cb.AddString(s); + } +} + +void ListRulesGlobals(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<rules.sections["VariableNames"].values.size();i++) + { + CString s=*rules.sections["VariableNames"].GetValueName(i); + s+=" "; + s+=*rules.sections["VariableNames"].GetValue(i); + + cb.AddString(s); + } +} + +extern map<CString, XCString> AllStrings; +void ListTutorial(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + +#ifndef RA2_MODE + int i; + for(i=0;i<tutorial.sections["Tutorial"].values.size();i++) + { + CString s; + s=*tutorial.sections["Tutorial"].GetValueName(i); + + s+=" "; + + s+=*tutorial.sections["Tutorial"].GetValue(i); + + cb.AddString(s); + } +#else + + typedef map<CString, XCString>::iterator it; + it _it=AllStrings.begin(); + /*it begin; + it end; + begin=CCStrings.begin(); + end=CCStrings.end();*/ + + int i; + for(i=0;i<CCStrings.size();i++) + { + + CString s; + s=_it->first; + s+=" : "; + s+=_it->second.cString; + + cb.AddString(s); + _it++; + } + +#endif +} + +void ListTriggers(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + CIniFile& ini=Map->GetIniFile(); + for(i=0;i<ini.sections["Triggers"].values.size();i++) + { + CString type; + CString s; + type=*ini.sections["Triggers"].GetValueName(i); + + s=type; + s+=" ("; + s+=GetParam(ini.sections["Triggers"].values[type], 2); + s+=")"; + + cb.AddString(s); + } +} + +void ListYesNo(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + cb.AddString("1 " + GetLanguageStringACP("Yes")); + cb.AddString("0 " + GetLanguageStringACP("No")); +} + +void ListSounds(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); +#ifdef RA2_MODE + int i; + for(i=0;i<sound.sections["SoundList"].values.size();i++) + { + CString s; + s=*sound.sections["SoundList"].GetValue(i); + + cb.AddString(s); + } +#endif +} +void ListThemes(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); +#ifdef RA2_MODE + int i; + for(i=0;i<theme.sections["Themes"].values.size();i++) + { + CString s; + s=*theme.sections["Themes"].GetValue(i); + + TruncSpace(s); + + if(s.GetLength()==0) continue; + + s+=" "; + s+=AllStrings[sound.sections[s].values["Name"]].cString; + + cb.AddString(s); + } +#endif +} +void ListSpeeches(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); +#ifdef RA2_MODE + int i; + for(i=0;i<eva.sections["DialogList"].values.size();i++) + { + CString s; + s=*eva.sections["DialogList"].GetValue(i); + + cb.AddString(s); + } +#endif +} +void ListSpecialWeapons(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<rules.sections["SuperWeaponTypes"].values.size();i++) + { + CString s; + char c[50]; + itoa(rules.sections["SuperWeaponTypes"].GetValueOrigPos(i),c,10); + s=c; + + s+=" "; + + s+=*rules.sections["SuperWeaponTypes"].GetValue(i); + + cb.AddString(s); + } +} + +void ListAnimations(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<rules.sections["Animations"].values.size();i++) + { + CString s; + char c[50]; + itoa(rules.sections["Animations"].GetValueOrigPos(i),c,10); + s=c; + + s+=" "; + s+=*rules.sections["Animations"].GetValue(i); + + cb.AddString(s); + } +} + +void ListParticles(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); + int i; + for(i=0;i<rules.sections["Particles"].values.size();i++) + { + CString s; + char c[50]; + itoa(rules.sections["Particles"].GetValueOrigPos(i),c,10); + s=c; + + s+=" "; + s+=*rules.sections["Particles"].GetValue(i); + + cb.AddString(s); + } +} + +void ListCrateTypes(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); +} +void ListSpeechBubbleTypes(CComboBox& cb) +{ + while(cb.DeleteString(0)!=CB_ERR); +} + +void ListMovies(CComboBox& cb, BOOL bListNone, BOOL bListParam) +{ + if(!bListParam) + { + int sel=cb.GetCurSel(); + + while(cb.DeleteString(0)!=CB_ERR); + + int i; + if(bListNone) cb.AddString("<none>"); + for(i=0;i<art.sections["Movies"].values.size();i++) + { + if(i<atoi(g_data.sections["MovieList"].values["Start"])) continue; + + CString s=*art.sections["Movies"].GetValue(i); + cb.AddString(s); + } + if(sel>=0) cb.SetCurSel(sel); + } + else + { + + while(cb.DeleteString(0)!=CB_ERR); + + int i; + for(i=0;i<art.sections["Movies"].values.size();i++) + { + if(i<atoi(g_data.sections["MovieList"].values["Start"])) continue; + + CString s; + char c[50]; + itoa(art.sections["Movies"].GetValueOrigPos(i),c,10); + s=c; + s+=" "; + s+=*art.sections["Movies"].GetValue(i); + + cb.AddString(s); + + } + + } +} + +void ListTags(CComboBox& cb, BOOL bListNone) +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=cb.GetCurSel(); + + while(cb.DeleteString(0)!=CB_ERR); + + int i; + if(bListNone) cb.AddString("None"); + for(i=0;i<ini.sections["Tags"].values.size();i++) + { + CString type=*ini.sections["Tags"].GetValueName(i); + CString s=type; + s+=" "; + s+=GetParam(*ini.sections["Tags"].GetValue(i), 1); + + cb.AddString(s); + } + + if(sel>=0) cb.SetCurSel(sel); +} + +int GetRulesHousesSize() +{ + int i; + int count=0; + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + if(rules.sections[HOUSES].GetValueOrigPos(i)<0) continue; + count++; + } + + return count; +} + +// a bug adds an empty house to the rules section, delete it here +int RepairRulesHouses() +{ + int i; + int count=0; + int delcount=0; + CString* toDelete; + toDelete=new(CString[rules.sections[HOUSES].values.size()]); + + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + if(rules.sections[HOUSES].GetValueOrigPos(i)<0) + { + toDelete[delcount]=*rules.sections[HOUSES].GetValueName(i); + delcount++; + } + else + count++; + } + + for(i=0;i<delcount;i++) + rules.sections[HOUSES].values.erase(toDelete[i]); + + delete[] toDelete; + + return count; +} + +// MW 07/27/01: Modified for <Player @ A> etc in YR +void ListHouses(CComboBox &cb, BOOL bNumbers, BOOL bCountries, BOOL bPlayers) +{ + CIniFile& ini=Map->GetIniFile(); + + int i; + int sel=cb.GetCurSel(); + int crulesh=GetRulesHousesSize(); + + if(Map->IsMultiplayer()==FALSE) bPlayers=FALSE; // really only for multi maps! + + //for(i=0;i<ini.sections[HOUSES] + + CString sSection=MAPHOUSES; + if(bCountries) sSection=HOUSES; + + while(cb.DeleteString(0)!=CB_ERR); + // houses: rules.ini + map definitions! + if(ini.sections.find(sSection)!=ini.sections.end()) + { + if(ini.sections[sSection].values.size()==0) goto wasnohouse; + // we use the map definitions! + + if(yuri_mode && bPlayers) + { + if(bNumbers) + { + cb.AddString("4475 <Player @ A>"); + cb.AddString("4476 <Player @ B>"); + cb.AddString("4477 <Player @ C>"); + cb.AddString("4478 <Player @ D>"); + cb.AddString("4479 <Player @ E>"); + cb.AddString("4480 <Player @ F>"); + cb.AddString("4481 <Player @ G>"); + cb.AddString("4482 <Player @ H>"); + } + else + { + cb.AddString("<Player @ A>"); + cb.AddString("<Player @ B>"); + cb.AddString("<Player @ C>"); + cb.AddString("<Player @ D>"); + cb.AddString("<Player @ E>"); + cb.AddString("<Player @ F>"); + cb.AddString("<Player @ G>"); + cb.AddString("<Player @ H>"); + } + + + } + + for(i=0;i<ini.sections[sSection].values.size();i++) + { + CString j; + +#ifdef RA2_MODE + j=*ini.sections[sSection].GetValue(i); + j.MakeLower(); + if(j=="nod" || j=="gdi") continue; +#endif + + if(bNumbers) + { + char c[50]; + int n=atoi(*ini.sections[sSection].GetValueName(i)); + itoa(n, c, 10); +#ifdef RA2_MODE + if(bCountries) + { + int preexisting=0; + int e; + for(e=0;e<i;e++) + { + if(rules.sections[sSection].FindValue(*ini.sections[sSection].GetValue(e))>=0) + preexisting++; + } + if(rules.sections[sSection].FindValue(*ini.sections[sSection].GetValue(i))>=0) + { + itoa(rules.sections[sSection].value_orig_pos[*rules.sections[sSection].GetValueName(rules.sections[sSection].FindValue(*ini.sections[sSection].GetValue(i)))], c, 10); + } + else + { + itoa(n+crulesh-preexisting, c, 10); + } + } +#endif + j=c; + j+=" "; + j+=TranslateHouse(*ini.sections[sSection].GetValue(i), TRUE); + } + else + j=TranslateHouse(*ini.sections[sSection].GetValue(i), TRUE); + + cb.AddString(j); + } + } + else + { + wasnohouse: + + if(bNumbers) + { + + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + CString j; + +#ifdef RA2_MODE + j=*rules.sections[HOUSES].GetValue(i); + j.MakeLower(); + if(j=="nod" || j=="gdi") continue; +#endif + j=*rules.sections[HOUSES].GetValueName(i); + j+=" "; + j+=TranslateHouse(*rules.sections[HOUSES].GetValue(i), TRUE); + + cb.AddString(j); + } + + + if(!yuri_mode || !bPlayers ) + { + for(i=0;i<8;i++) + { + int k=i; + #ifdef RA2_MODE + k+=crulesh; + + + //rules.sections[HOUSES].values.size(); + #endif + CString j; + char c[50]; + itoa(k,c,10); + j+=c; + j+=" Multi-Player "; + itoa(i,c,10); + j+=c; + cb.AddString(j); + } + } + else + { + cb.AddString("4475 <Player @ A>"); + cb.AddString("4476 <Player @ B>"); + cb.AddString("4477 <Player @ C>"); + cb.AddString("4478 <Player @ D>"); + cb.AddString("4479 <Player @ E>"); + cb.AddString("4480 <Player @ F>"); + cb.AddString("4481 <Player @ G>"); + cb.AddString("4482 <Player @ H>"); + } + } + else + { + if(yuri_mode && bPlayers) + { + cb.AddString("<Player @ A>"); + cb.AddString("<Player @ B>"); + cb.AddString("<Player @ C>"); + cb.AddString("<Player @ D>"); + cb.AddString("<Player @ E>"); + cb.AddString("<Player @ F>"); + cb.AddString("<Player @ G>"); + cb.AddString("<Player @ H>"); + } + + for(i=0;i<rules.sections[HOUSES].values.size();i++) + { + CString j; + +#ifdef RA2_MODE + j=*rules.sections[HOUSES].GetValue(i); + j.MakeLower(); + if(j=="nod" || j=="gdi") continue; +#endif + + if(bNumbers) + { + j=*rules.sections[HOUSES].GetValueName(i); + j+=" "; + j+=TranslateHouse(*rules.sections[HOUSES].GetValue(i), TRUE); + } + else + j=TranslateHouse(*rules.sections[HOUSES].GetValue(i), TRUE); + + cb.AddString(j); + } + } + } + + if(sel>=0) cb.SetCurSel(sel); + +} + + +void ListTeamTypes(CComboBox &cb, BOOL bListNone) +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=cb.GetCurSel(); + + while(cb.DeleteString(0)!=CB_ERR); + + int i; + if(bListNone) cb.AddString("<none>"); + for(i=0;i<ini.sections["TeamTypes"].values.size();i++) + { + CIniFileSection& sec=ini.sections[*ini.sections["TeamTypes"].GetValue(i)]; + CString type=*ini.sections["TeamTypes"].GetValue(i); + CString s=type; + s+=" "; + s+=sec.values["Name"]; + + cb.AddString(s); + } + + if(sel>=0) cb.SetCurSel(sel); +} + +void ListWaypoints(CComboBox &cb) +{ + CIniFile& ini=Map->GetIniFile(); + + int sel=cb.GetCurSel(); + + while(cb.DeleteString(0)!=CB_ERR); + + int i; + for(i=0;i<ini.sections["Waypoints"].values.size();i++) + { + + CString s=*ini.sections["Waypoints"].GetValueName(i); //type; + + cb.AddString(s); + } + + if(sel>=0) cb.SetCurSel(sel); +} + +void ListTargets(CComboBox &cb) +{ + int sel=cb.GetCurSel(); + + while(cb.DeleteString(0)!=CB_ERR); + + cb.AddString("1 - Not specified"); + cb.AddString("2 - Buildings"); + cb.AddString("3 - Harvesters"); + cb.AddString("4 - Infantry"); + cb.AddString("5 - Vehicles"); + cb.AddString("6 - Factories"); + cb.AddString("7 - Base defenses"); + cb.AddString("9 - Power plants"); + + if(sel>=0) cb.SetCurSel(sel); + +} + + +CString GetHouseSectionName(CString lpHouse) +{ +#ifndef RA2_MODE + return lpHouse; +#else + return lpHouse+" House"; +#endif + +} + + +CString GetFreeID() +{ + CIniFile& ini=Map->GetIniFile(); + + int n=1000000; + while(TRUE) + { + char p[50]; + p[0]='0'; + itoa(n,p+1,10); + if(ini.sections["ScriptTypes"].FindValue(p)==-1) + { + if(ini.sections["TaskForces"].FindValue(p)==-1) + { + if(ini.sections["TeamTypes"].FindValue(p)==-1) + { + if(ini.sections["Triggers"].values.find(p)==ini.sections["Triggers"].values.end()) + { + if(ini.sections["Events"].values.find(p)==ini.sections["Events"].values.end()) + { + if(ini.sections["Tags"].values.find(p)==ini.sections["Tags"].values.end()) + { + if(ini.sections["Actions"].values.find(p)==ini.sections["Actions"].values.end()) + { + if(ini.sections["AITriggerTypes"].values.find(p)==ini.sections["AITriggerTypes"].values.end()) + { + if(ini.sections.find(p)==ini.sections.end()) + return p; + } + } + } + } + } + } + } + } + n++; + } + return ""; +} + +void GetNodeName(CString & name, int n) +{ + char c[5]; + char p[6]; + memset(p,0,6); + itoa(n,c,10); + strcpy(p,c); + + if(strlen(c)==1) + { + memcpy(c,"00", 2); + strcpy(c+2, p); + } + else if(strlen(c)==2) + { + memcpy(c,"0", 1); + strcpy(c+1, p); + } + else if(strlen(c)==3) + { + strcpy(c, p); + } + + name=c; +} + +int GetNodeAt(CString& owner, CString& type, int x, int y) +{ + CIniFile& ini=Map->GetIniFile(); + + type=""; + owner=""; + + int owners; + if(ini.sections.find(HOUSES)!=ini.sections.end()) + { + for(owners=0;owners<ini.sections[HOUSES].values.size();owners++) + { + owner=*ini.sections[HOUSES].GetValue(owners); + + // okay now owner is correct! + int i,c=atoi(ini.sections[owner].values["NodeCount"]); + + for(i=0;i<c;i++) + { + CString p; + GetNodeName(p, i); + + CString sx, sy; + type=GetParam(ini.sections[owner].values[p], 0); + sy=GetParam(ini.sections[owner].values[p], 1); + sx=GetParam(ini.sections[owner].values[p], 2); + + CString arttype=type; + if(rules.sections[type].values.find("Image")!=rules.sections[type].values.end()) + { + // other art! + arttype=rules.sections[type].values["Image"]; + } + if(ini.sections.find(type)!=ini.sections.end()) + if(ini.sections[type].values.find("Image")!=ini.sections[type].values.end()) + { + // other art! + arttype=rules.sections[type].values["Image"]; + } + + int w,h; + char d[6]; + memcpy(d, (LPCTSTR)art.sections[arttype].values["Foundation"],1); + d[1]=0; + w=atoi(d); + if(w==0) w=1; + memcpy(d, (LPCTSTR)art.sections[arttype].values["Foundation"]+2,1); + d[1]=0; + h=atoi(d); + if(h==0) h=1; + + int j,k; + for(j=0;j<h;j++) + { + for(k=0;k<w;k++) + { + if(atoi(sx)+j==x && atoi(sy)+k==y) + return i; + } + } + } + } + } + else + return -1; + + + + return -1; +} + + +std::unique_ptr<CBitmap> BitmapFromResource(int resource_id) +{ + std::unique_ptr<CBitmap> bm(new CBitmap); + if (!bm->LoadBitmap(resource_id)) + throw BitmapNotFound(); + return bm; +} + +std::unique_ptr<CBitmap> BitmapFromFile(const CString& filepath) +{ + std::unique_ptr<CBitmap> bm(new CBitmap); + if (!bm->LoadBitmap(filepath)) + throw BitmapNotFound(); + return bm; +} + +/* +Returns the area in the current line that should be painted +Truncates areas that are transparent, and therefore increases display speed! +flags must be set to 0 +*/ +void GetDrawBorder(const BYTE* data, int width, int line, int& left, int& right, unsigned int flags, BOOL* TranspInside) +{ + int i; + const BYTE* lpStart = data + line * width; + + if (flags == 0) + { + // left border: + for (i = 0;i < width;i++) + { + if (lpStart[i] || i == width - 1) + { + left = i; + break; + } + } + + // right border: + for (i = width - 1;i >= 0;i--) + { + if (lpStart[i] || i == 0) + { + right = i; + break; + } + } + + if (TranspInside) + { + for (i = left;i <= right;i++) + { + if (!lpStart[i]) + { + *TranspInside = TRUE; + break; + } + } + } + } +} + +CComPtr<IDirectDrawSurface4> BitmapToSurface(IDirectDraw4 * pDD, const CBitmap& bitmap) +{ + BITMAP bm; + GetObject(bitmap, sizeof(bm), &bm); + + DDSURFACEDESC2 desc = { 0 }; + ZeroMemory(&desc, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + desc.dwWidth = bm.bmWidth; + desc.dwHeight = bm.bmHeight; + + auto pSurface = CComPtr<IDirectDrawSurface4>(); + if (pDD->CreateSurface(&desc, &pSurface, nullptr) != DD_OK) + return nullptr; + + pSurface->Restore(); + + CDC bitmapDC; + if (!bitmapDC.CreateCompatibleDC(nullptr)) + return nullptr; + bitmapDC.SelectObject(bitmap); + + HDC hSurfaceDC = nullptr; + if (pSurface->GetDC(&hSurfaceDC) != DD_OK) + return nullptr; + + CDC surfaceDC; + surfaceDC.Attach(hSurfaceDC); + + auto success = surfaceDC.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &bitmapDC, 0, 0, SRCCOPY); + surfaceDC.Detach(); + pSurface->ReleaseDC(hSurfaceDC); + + return pSurface; +} + + + diff --git a/MissionEditor/functions.h b/MissionEditor/functions.h new file mode 100644 index 0000000..6b738af --- /dev/null +++ b/MissionEditor/functions.h @@ -0,0 +1,156 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#ifndef FUNC_INCLUDED +#define FUNC_INCLUDED + +#include <afx.h> +#include <memory> +#include <array> + +bool deleteFile(const std::string& u8FilePath); + +// set the status bar text in the main dialog +void SetMainStatusBar(const char* text); +// set the status bar text in the main dialog to ready +void SetMainStatusBarReady(); + +// change all %n (where n is an int) in an string, to another specified string +CString TranslateStringVariables(int n, const char* originaltext, const char* inserttext); + +// Alliance->Korea etc... +CString TranslateHouse(CString original, BOOL bToUI=FALSE); + +// show options dialog +void ShowOptionsDialog(); + +// repairs a trigger (sets flags correctly) +void RepairTrigger(CString& triggerdata); + +// coordinate functions +void PosToXY(const char* pos, int* X, int* Y); + +// HSV -> RGB +void HSVToRGB(const unsigned char hsv[3], unsigned char rgb[3]); +std::array<unsigned char, 3> HSVToRGB(float h, float s, float v); +std::array<unsigned char, 3> HSVToRGB(const unsigned char hsv[3]); + +void GetDrawBorder(const BYTE* data, int width, int line, int& left, int& right, unsigned int flags, BOOL* TranspInside = NULL); + +// String conversion +std::wstring utf8ToUtf16(const char* utf8); +std::wstring utf8ToUtf16(const std::string& utf8); +std::string utf16ToUtf8(const std::wstring& utf16); +std::string utf16ToACP(const std::wstring& utf16); + +// map functions +int GetNodeAt(string& owner, string& type, int x, int y); +int SetNodeAt(string owner, string type, int x, int y); +void ClearNode(int n, string owner); +CString GetFreeID(); + + +void HandleParamList(CComboBox &cb, int type); + +// sets 0 if there is a space in the string, so truncates it at the first space occupation +void TruncSpace(string& str); +void TruncSpace(CString& str); + +// checks if a file exists +BOOL DoesFileExist(LPCSTR szFile); + + +// Lists some things +void ListHouses(CComboBox &cb, BOOL bNumbers=FALSE, BOOL bCountries=FALSE, BOOL bPlayers=FALSE); +void ListTeamTypes(CComboBox &cb, BOOL bListNone=FALSE); +void ListWaypoints(CComboBox &cb); +void ListTargets(CComboBox& cb); +void ListTags(CComboBox& cb, BOOL bListNone); +void ListMovies(CComboBox& cb, BOOL bListNone, BOOL bListParam=FALSE); +void ListBuildings(CComboBox& cb, BOOL bININame=FALSE); +void ListUnits(CComboBox& cb); +void ListAircraft(CComboBox& cb); +void ListInfantry(CComboBox& cb); +void ListTutorial(CComboBox& cb); +void ListTriggers(CComboBox& cb); +void ListYesNo(CComboBox& cb); +void ListSounds(CComboBox& cb); +void ListThemes(CComboBox& cb); +void ListSpeeches(CComboBox& cb); +void ListSpecialWeapons(CComboBox& cb); +void ListAnimations(CComboBox& cb); +void ListParticles(CComboBox& cb); +void ListCrateTypes(CComboBox& cb); +void ListSpeechBubbleTypes(CComboBox& cb); +void ListGlobals(CComboBox& cb); +void ListRulesGlobals(CComboBox& cb); +void ListTechtypes(CComboBox& cb); + + +// some easy-to-use functions +CString GetText(CWnd* wnd); +CString GetText(CComboBox* wnd); +CString GetText(CSliderCtrl* wnd); + +CString GetHouseSectionName(CString lpHouse); + +// fix bug +int RepairRulesHouses(); + +// strcpy_safe allows overlapping of source & destination. strcpy may be faster though! +char *strcpy_safe( char *strDestination, const char *strSource ); + +/**************************************** + language support functions [12/18/1999] +****************************************/ + +// retrieve the string name in the correct language (name is an ID). +// the returned string is in the active codepage (UTF-8 on Windows 10 1909+) +CString GetLanguageStringACP(CString name); + +// tranlate a string/word by using the table from english to the current language +// the returned string is in the active codepage (UTF-8 on Windows 10 1909+) +CString TranslateStringACP(CString u8EnglishString); + +// tranlate a string/word by using the table from english to the current language +// the returned string is in the active codepage (UTF-8 on Windows 10 1909+) +CString TranslateStringACP(WCHAR* u16EnglishString); + +/**************************************** + sound functions [03/16/2001] + ****************************************/ + +// general play sound function. uses parameter in defines.h. Does only play if user has not deactivated sounds +void Sound(int ID); + + +class BitmapNotFound : std::runtime_error +{ +public: + BitmapNotFound(): std::runtime_error("Bitmap not found") {} +}; + +std::unique_ptr<CBitmap> BitmapFromResource(int resource_id); +std::unique_ptr<CBitmap> BitmapFromFile(const CString& filepath); + +CComPtr<IDirectDrawSurface4> BitmapToSurface(IDirectDraw4 * pDD, const CBitmap& bitmap); + + +#endif \ No newline at end of file diff --git a/MissionEditor/inlines.h b/MissionEditor/inlines.h new file mode 100644 index 0000000..4c279a9 --- /dev/null +++ b/MissionEditor/inlines.h @@ -0,0 +1,286 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#ifndef INLINES_H_INCLUDED +#define INLINES_H_INCLUDED + +#include "functions.h" +#include "macros.h" +#include "mapdata.h" +#include "variables.h" +#include "ovrlinline.h" +#include <string> +#include <vector> +#include <ranges> + + +inline BOOL isTrue(CString expr) +{ + expr.MakeLower(); + if (expr == "yes" || expr == "true" || expr == "1") + return TRUE; + return FALSE; +} + +inline BOOL isFalse(CString expr) +{ + expr.MakeLower(); + if (expr == "no" || expr == "false" || expr == "0") + return TRUE; + return FALSE; +} + +// retrieve the picture filename of a unit (as it is saved in the pics map). The returned file may not exist in the pics map (you need to do a check!). +inline CString GetUnitPictureFilename(LPCTSTR lpUnitName, DWORD dwPicIndex) +{ + CIniFile& ini = Map->GetIniFile(); + + CString UnitName = lpUnitName; + + UnitName = rules.sections[lpUnitName].GetValueByName("Image", lpUnitName); + + if (ini.sections.find(lpUnitName) != ini.sections.end()) + UnitName = ini.sections[lpUnitName].GetValueByName("Image", UnitName); + + if (rules.sections[lpUnitName].values.find("Image") != rules.sections[lpUnitName].values.end()) + UnitName = rules.sections[lpUnitName].values["Image"]; + + CString artname = UnitName; + + if (art.sections[UnitName].values.find("Image") != art.sections[UnitName].values.end()) + { + if (!isTrue(g_data.sections["IgnoreArtImage"].AccessValueByName(UnitName))) + artname = art.sections[UnitName].AccessValueByName("Image"); + } + + + CString filename = UnitName; + + if (art.sections[UnitName].FindName("NewTheater") >= 0 && art.sections[UnitName].AccessValueByName("DemandLoad") != "yes") + if (art.sections[UnitName].AccessValueByName("NewTheater") == "yes") + filename.SetAt(1, 'T'); + + char n[50]; + itoa(dwPicIndex, n, 10); + + + if (pics.find(artname + n) != pics.end()) + { + filename = artname; // yes, found + filename += n; + } + else if (pics.find(artname + ".bmp") != pics.end()) // since June, 15th (Matze): Only use BMP if no SHP/VXL exists + { + filename = (CString)artname + ".bmp"; + } + else + filename = ""; + + return filename; +} + +inline CString GetParam(const CString& data, const int param) +{ + int paramStrPos = 0; + int curParam = param; + + while (curParam--) + { + auto nextComma = data.Find(',', paramStrPos); + if (nextComma < 0) + return CString(); // RVO; param not found + paramStrPos = nextComma + 1; + } + + auto nextComma = data.Find(',', paramStrPos); + CString res = data.Mid(paramStrPos, nextComma < 0 ? data.GetLength() - paramStrPos : nextComma - paramStrPos); + return res; // RVO +} + +inline std::string GetParam(const std::string& data, const int param) +{ + int paramStrPos = 0; + int curParam = param; + + while (curParam--) + { + auto nextComma = data.find(',', paramStrPos); + if (nextComma == std::string::npos) + return std::string(); // RVO; param not found + paramStrPos = nextComma + 1; + } + + auto nextComma = data.find(',', paramStrPos); + std::string res = data.substr(paramStrPos, nextComma == std::string::npos ? data.size() - paramStrPos : nextComma - paramStrPos); + return res; // RVO +} + +inline CString GetParam(const char* data, const int param) +{ + return GetParam(CString(data), param); +} + +inline std::vector<CString> Split(const CString& data, char separator) +{ + int nextComma = -1; + int lastComma = -1; + const auto len = data.GetLength(); + std::vector<CString> res; + while (lastComma < len) + { + nextComma = data.Find(separator, lastComma + 1); + if (nextComma < 0) + { + res.push_back(data.Mid(lastComma + 1)); + break; + } + + res.push_back(data.Mid(lastComma + 1, (nextComma - lastComma - 1))); + lastComma = nextComma; + } + return res; // RVO +} + +inline std::vector<CString> SplitParams(const CString& data) +{ + return Split(data, ','); +} + + +inline CString Join(const CString& join, const std::vector<CString>& strings) +{ + CString res; + int len = 0; + for (auto& s : strings) + len += s.GetLength() + join.GetLength(); + res.Preallocate(len + 1); + int remaining = strings.size(); + for (auto& s : strings) + { + res += s; + if (--remaining) + res += join; + } + return res; // RVO +} + +inline std::string Join(const std::string& join, const std::ranges::input_range auto&& strings) +{ + std::string res; + int len = 0; + for (const auto& s : strings) + len += s.size() + join.size(); + res.reserve(len + 1); + int remaining = strings.size(); + for (const auto& s : strings) + { + res += s; + if (--remaining) + res += join; + } + return res; // RVO +} + +inline CString SetParam(const CString& data, const int param, const CString& value) +{ + // This could be optimized, but SetParam is usually no performance issue. + if (param < 0) + return data; + std::vector<CString> params = SplitParams(data); + params.resize(max(param + 1, static_cast<int>(params.size()))); + params[param] = value; + return Join(",", params); +} + + +[[deprecated("Instead use CMapData::ToMapCoords")]] +inline void ToIso(int* x, int* y) +{ + auto r = Map->ToMapCoords(ProjectedCoords(*x, *y)); + *x = r.x; + *y = r.y; +} + +[[deprecated("Instead use CMapData::ProjectCoords")]] +inline void ToPhys(int* x, int* y) +{ + auto r = Map->ProjectCoords(MapCoords(*x, *y)); + *x = r.x; + *y = r.y; +} + +[[deprecated("Instead use CMapData::ProjectCoords3d")]] +inline void ToPhys3d(int* x, int* y) +{ + auto r = Map->ProjectCoords3d(MapCoords(*x, *y)); + *x = r.x; + *y = r.y; +} + +[[deprecated("Instead use CMapData::ProjectCoords3d")]] +inline void ToPhys3d(int* x, int* y, int mapZ) +{ + auto r = Map->ProjectCoords3d(MapCoords(*x, *y), mapZ); + *x = r.x; + *y = r.y; +} + +[[deprecated("Instead use CMapData::ToMapCoords3d")]] +inline void ToIso3d(int* x, int* y, int mapZ) +{ + auto r = Map->ToMapCoords3d(ProjectedCoords(*x, *y), mapZ); + *x = r.x; + *y = r.y; +} + + +inline BOOL isSame(CString expr1, CString expr2) +{ + expr1.MakeLower(); + expr2.MakeLower(); + if (expr1 == expr2) return TRUE; + return FALSE; +} + +inline BOOL isIncluded(CString searchString, CString base) +{ + searchString.MakeLower(); + base.MakeLower(); + if (searchString.Find(base) < 0) return FALSE; + return TRUE; +} + +inline BOOL isTrack(int type) +{ + return(type >= OVRL_TRACK_BEGIN && type <= OVRL_TRACK_END); +} + +inline BOOL isBigBridge(int type) +{ +#ifndef RA2_MODE + return((type >= 0x18 && type <= 0x19) || (type >= 0x3b && type <= 0x3c)); +#else + return((type >= 0x18 && type <= 0x19) || (type >= 0x3b && type <= 0x3c) || (type >= 0xed && type <= 0xee)); +#endif +} + + + +#endif \ No newline at end of file diff --git a/MissionEditor/ovrlinline.h b/MissionEditor/ovrlinline.h new file mode 100644 index 0000000..1706238 --- /dev/null +++ b/MissionEditor/ovrlinline.h @@ -0,0 +1,31 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#ifndef INCL_OVRL_INLINE +#define INCL_OVRL_INLINE +// this is just a small helper header +// needed because of some linking problems on certain compilers + +inline BOOL isGreenTiberium(int type) +{ + return (type>0x65 && type<=0x79) || (type>0x82 && type<0xa7); +} + +#endif \ No newline at end of file diff --git a/MissionEditor/res/BMP00005.BMP b/MissionEditor/res/BMP00005.BMP new file mode 100644 index 0000000..d8b3cc1 Binary files /dev/null and b/MissionEditor/res/BMP00005.BMP differ diff --git a/MissionEditor/res/DBGMAP.BMP b/MissionEditor/res/DBGMAP.BMP new file mode 100644 index 0000000..de69156 Binary files /dev/null and b/MissionEditor/res/DBGMAP.BMP differ diff --git a/MissionEditor/res/FinalAlert2.ico b/MissionEditor/res/FinalAlert2.ico new file mode 100644 index 0000000..06b4f22 Binary files /dev/null and b/MissionEditor/res/FinalAlert2.ico differ diff --git a/MissionEditor/res/FinalAlert2YR.ico b/MissionEditor/res/FinalAlert2YR.ico new file mode 100644 index 0000000..1a8b187 Binary files /dev/null and b/MissionEditor/res/FinalAlert2YR.ico differ diff --git a/MissionEditor/res/FinalSun.ico b/MissionEditor/res/FinalSun.ico new file mode 100644 index 0000000..6eea0e0 Binary files /dev/null and b/MissionEditor/res/FinalSun.ico differ diff --git a/MissionEditor/res/FinalSun.rc2 b/MissionEditor/res/FinalSun.rc2 new file mode 100644 index 0000000..03e4f37 --- /dev/null +++ b/MissionEditor/res/FinalSun.rc2 @@ -0,0 +1,13 @@ +// +// TIBERIANSUN MISSION EDITOR.RC2 - Ressourcen, die Microsoft Visual C++ nicht direkt bearbeitet +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// F�gen Sie hier manuell bearbeitete Ressourcen hinzu... + +///////////////////////////////////////////////////////////////////////////// diff --git a/MissionEditor/res/IDR_MAIN.ICO b/MissionEditor/res/IDR_MAIN.ICO new file mode 100644 index 0000000..ee9d6b2 Binary files /dev/null and b/MissionEditor/res/IDR_MAIN.ICO differ diff --git a/MissionEditor/res/LITEBULB.BMP b/MissionEditor/res/LITEBULB.BMP new file mode 100644 index 0000000..7e0e75c Binary files /dev/null and b/MissionEditor/res/LITEBULB.BMP differ diff --git a/MissionEditor/res/MV_PROBL.BMP b/MissionEditor/res/MV_PROBL.BMP new file mode 100644 index 0000000..3bde6c2 Binary files /dev/null and b/MissionEditor/res/MV_PROBL.BMP differ diff --git a/MissionEditor/res/Toolbar.bmp b/MissionEditor/res/Toolbar.bmp new file mode 100644 index 0000000..f8137dd Binary files /dev/null and b/MissionEditor/res/Toolbar.bmp differ diff --git a/MissionEditor/res/celltag_ra2.bmp b/MissionEditor/res/celltag_ra2.bmp new file mode 100644 index 0000000..cf5ac32 Binary files /dev/null and b/MissionEditor/res/celltag_ra2.bmp differ diff --git a/MissionEditor/res/celltag_ts.bmp b/MissionEditor/res/celltag_ts.bmp new file mode 100644 index 0000000..72e49f5 Binary files /dev/null and b/MissionEditor/res/celltag_ts.bmp differ diff --git a/MissionEditor/res/clifftoo.bmp b/MissionEditor/res/clifftoo.bmp new file mode 100644 index 0000000..1111c17 Binary files /dev/null and b/MissionEditor/res/clifftoo.bmp differ diff --git a/MissionEditor/res/ra2_arrow.cur b/MissionEditor/res/ra2_arrow.cur new file mode 100644 index 0000000..6abf401 Binary files /dev/null and b/MissionEditor/res/ra2_arrow.cur differ diff --git a/MissionEditor/res/scrollcursor_ra2.bmp b/MissionEditor/res/scrollcursor_ra2.bmp new file mode 100644 index 0000000..1d4b5b1 Binary files /dev/null and b/MissionEditor/res/scrollcursor_ra2.bmp differ diff --git a/MissionEditor/res/scrollcursor_ts.bmp b/MissionEditor/res/scrollcursor_ts.bmp new file mode 100644 index 0000000..26534fa Binary files /dev/null and b/MissionEditor/res/scrollcursor_ts.bmp differ diff --git a/MissionEditor/res/terrainb.bmp b/MissionEditor/res/terrainb.bmp new file mode 100644 index 0000000..48aefac Binary files /dev/null and b/MissionEditor/res/terrainb.bmp differ diff --git a/MissionEditor/res/ts_arrow.cur b/MissionEditor/res/ts_arrow.cur new file mode 100644 index 0000000..e9519fa Binary files /dev/null and b/MissionEditor/res/ts_arrow.cur differ diff --git a/MissionEditor/res/uacbopen.wav b/MissionEditor/res/uacbopen.wav new file mode 100644 index 0000000..229dd1b Binary files /dev/null and b/MissionEditor/res/uacbopen.wav differ diff --git a/MissionEditor/res/ugamclos.wav b/MissionEditor/res/ugamclos.wav new file mode 100644 index 0000000..fdfb691 Binary files /dev/null and b/MissionEditor/res/ugamclos.wav differ diff --git a/MissionEditor/res/umenscol.wav b/MissionEditor/res/umenscol.wav new file mode 100644 index 0000000..a6f9d4b Binary files /dev/null and b/MissionEditor/res/umenscol.wav differ diff --git a/MissionEditor/res/uqeue.wav b/MissionEditor/res/uqeue.wav new file mode 100644 index 0000000..c24dc52 Binary files /dev/null and b/MissionEditor/res/uqeue.wav differ diff --git a/MissionEditor/res/wp_ra2.bmp b/MissionEditor/res/wp_ra2.bmp new file mode 100644 index 0000000..41f645e Binary files /dev/null and b/MissionEditor/res/wp_ra2.bmp differ diff --git a/MissionEditor/res/wp_ts.bmp b/MissionEditor/res/wp_ts.bmp new file mode 100644 index 0000000..c4659f2 Binary files /dev/null and b/MissionEditor/res/wp_ts.bmp differ diff --git a/MissionEditor/resource.h b/MissionEditor/resource.h new file mode 100644 index 0000000..b630409 --- /dev/null +++ b/MissionEditor/resource.h @@ -0,0 +1,610 @@ +//{{NO_DEPENDENCIES}} +// Von Microsoft Visual C++ generierte Includedatei. +// Verwendet durch MissionEditor.rc +// +#define IDD_TIBERIANSUNMISSIONEDITOR_DIALOG 102 +#define IDD_FINALSUN_DIALOG 102 +#define IDB_LIGHTBULB 103 +#define IDD_TIP 104 + +#define IDR_MAINFRAME 128 +#define IDR_MAIN 129 +#define IDD_BASIC 135 +#define IDD_TSOPTIONS 137 +#define IDD_ALL 140 +#define IDD_MAP 141 +#define IDD_INPUTBOX 143 +#define IDR_RULES 146 +#define IDD_IMPORTINI 147 +#define IDD_LIGHTNING 148 +#define IDD_LIGHTING 148 +#define IDD_WAYPOINTS 151 +#define IDD_INFO 152 +#define IDD_SPECIALFLAGS 153 +#define IDD_TREES 155 +#define IDR_RULESPATCH 157 +#define IDB_DBG 159 +#define IDD_POS 160 +#define IDD_VIEW 161 +#define IDR_MAPVIEW 162 +#define IDI_TREE 163 +#define IDI_TANK 164 +#define IDI_MAN 165 +#define IDI_HOUSE 166 +#define IDI_FLAG 167 +#define GACNST 169 +#define IDR_ART 171 +#define IDD_INFANTRY 174 +#define IDD_BUILDING 175 +#define IDD_UNIT 176 +#define IDD_HOUSES 177 +#define IDD_AIRCRAFT 179 +#define IDI_AIR 180 +#define IDD_LOADING 181 +#define IDD_WAYPOINT 182 +#define IDB_FLAG 185 +#define IDD_CELLTAG 190 +#define IDB_CELLTAG 191 +#define IDD_TEAMTYPES 192 +#define IDD_TASKFORCES 195 +#define IDD_TAGS 196 +#define IDD_TRIGGERS 198 +#define IDD_SCRIPTTYPES 200 +#define IDD_AITRIGGERTYPESENABLE 203 +#define IDR_AI 204 +#define IDD_AITRIGGERTYPES 205 +#define IDD_MYOPENDIALOG 211 +#define IDD_NEWMAP 212 +#define IDD_SINGLEPLAYER 217 +#define IDD_MAPVALIDATOR 219 +#define IDB_MV_ICONS 220 +#define IDR_TERRAINBAR 225 +#define IDD_TERRAINBAR 227 +#define IDD_TOOLSETTINGS 229 +#define IDD_SHUTDOWN 231 +#define IDD_DYNAMICLOAD 232 +#define IDD_SAVING 235 +#define IDB_EECROSS 245 +#define IDB_EECIRCLE 246 +#define IDD_TRIGGEREDITOR 247 +#define IDD_TRIGGEROPTIONS 250 +#define IDD_TRIGGEREVENTS 251 +#define IDD_TRIGGERACTIONS 252 +#define IDD_GLOBALS 253 +#define IDD_NEWRA2HOUSE 255 +#define IDD_NEWMAPTYPE 257 +#define IDD_NEWMAPCREATE 258 +#define IDD_NEWMAPSPOPTIONS 259 +#define IDD_NEWMAPCREATENEW 260 +#define IDD_NEWMAPIMPORT 261 +#define IDR_CLIFFBAR 264 +#define IDD_MAPLOAD 264 +#define IDD_SAVEOPTIONS 266 +#define IDD_NEWMAPBITMAP 267 +#define IDD_MULTISAVEOPT 269 +#define IDD_MMXOPTIONS 270 +#define IDD_PROGRESS 272 +#define IDD_AUTOUPDATE 273 +#define IDB_SCROLLCURSOR 274 +#define IDR_WAVE1 275 +#define IDR_WAVE2 276 +#define IDR_WAVE3 277 +#define IDR_WAVE4 278 +#define IDD_CHANGESIZE 279 +#define IDD_AITRIGGERADD 280 +#define IDD_TERRAINPLACING 283 +#define IDD_SEARCHWAYPOINT 285 +#define IDD_USERSCRIPTS 288 +#define IDD_COMBO_UINPUT 289 +#define IDC_EDITOR_ARROW 299 +#define IDC_BULB 1000 +#define IDC_STARTUP 1001 +#define IDC_NEXTTIP 1002 +#define IDC_TIPSTRING 1004 +#define IDC_TAB 1007 +#define IDC_NAME 1010 +#define IDC_NEWINIFORMAT 1011 +#define IDC_PRIORITY 1011 +#define IDC_CARRYOVERCAP 1012 +#define IDC_MAX 1012 +#define IDC_ENDOFGAME 1013 +#define IDC_NEXTSCENARIO 1014 +#define IDC_ALTNEXTSCENARIO 1015 +#define IDC_SKIPSCORE 1016 +#define IDC_ONETIMEONLY 1017 +#define IDC_SKIPMAPSELECT 1018 +#define IDC_OFFICIAL 1019 +#define IDC_IGNOREGLOBALAITRIGGERS 1020 +#define IDC_TRUCKCRATE 1021 +#define IDC_TRAINCRATE 1022 +#define IDC_PERCENT 1023 +#define IDC_MULTIPLAYERONLY 1024 +#define IDC_TIBERIUMGROWTHENABLED 1025 +#define IDC_VEINGROWTHENABLED 1026 +#define IDC_ICEGROWTHENABLED 1027 +#define IDC_TIBERIUMDEATHTOVISCEROID 1028 +#define IDC_FREERADAR 1029 +#define IDC_INITTIME 1030 +#define IDC_REQUIREDADDON 1031 +#define IDC_EDIT1 1034 +#define IDC_CHOOSE 1035 +#define IDC_SECTIONS 1036 +#define IDC_LEFT 1036 +#define IDC_ADDSECTION 1037 +#define IDC_TOP 1037 +#define IDC_DELETESECTION 1038 +#define IDC_KEYS 1039 +#define IDC_ADDKEY 1040 +#define IDC_DELETEKEY 1041 +#define IDC_INISECTION 1042 +#define IDC_VALUE 1043 +#define IDC__SIZE 1044 +#define IDC__SIZEX 1044 +#define IDC_USESIZE 1045 +#define IDC_THEATER 1046 +#define IDC_VAL 1047 +#define IDC_GROUNDHEIGHT 1047 +#define IDC_STARTINGHEIGHT 1047 +#define IDC__SIZEY 1047 +#define IDC_SENTENCE 1048 +#define IDC_AVAILABLE 1049 +#define IDC_ALLSECTIONS 1052 +#define IDC_SPECIFYSECTIONS 1053 +#define IDC_CUVALUE 1057 +#define IDC_AMBIENT 1058 +#define IDC_GREEN 1059 +#define IDC_RED 1060 +#define IDC_BLUE 1061 +#define IDC_LEVEL 1062 +#define IDC_TIBERIUMGROWS 1062 +#define IDC_AMBIENT2 1063 +#define IDC_TIBERIUMSPREADS 1063 +#define IDC_TREELIST 1063 +#define IDC_GREEN2 1064 +#define IDC_TIBERIUMEXPLOSIVE 1064 +#define IDC_TYPE 1064 +#define IDC_RED2 1065 +#define IDC_DESTROYABLEBRIDGES 1065 +#define IDC_NEW 1065 +#define IDC_BLUE2 1066 +#define IDC_MCVDEPLOY 1066 +#define IDC_DELETE 1066 +#define IDC_LEVEL2 1067 +#define IDC_INITIALVETERAN 1067 +#define IDC_POS 1067 +#define IDC_FIXEDALLIANCE 1068 +#define IDC_HARVESTERIMMUNE 1069 +#define IDC_FOGOFWAR 1070 +#define IDC_WAYPOINTS 1070 +#define IDC_INERT 1071 +#define IDC_DBG 1071 +#define IDC_IONSTORMS 1072 +#define IDC_Y 1072 +#define IDC_METEORITES 1073 +#define IDC_X 1073 +#define IDC_VISCEROIDS 1074 +#define IDC_HOUSE 1079 +#define IDC_STRENGTH 1080 +#define IDC_ATTACHEDTRIGGER 1080 +#define IDC_STATE 1082 +#define IDC_TAG 1083 +#define IDC_P2 1084 +#define IDC_P3 1085 +#define IDC_P4 1086 +#define IDC_P1 1087 +#define IDC_DIRECTION 1088 +#define IDC_P6 1089 +#define IDC_P5 1090 +#define IDC_P7 1091 +#define IDC_HOUSES 1091 +#define IDC_P8 1092 +#define IDC_ADDHOUSE 1092 +#define IDC_P9 1093 +#define IDC_PREPAREHOUSES 1093 +#define IDC_P10 1094 +#define IDC_DELETEHOUSE 1094 +#define IDC_IQ 1095 +#define IDC_EDGE 1096 +#define IDC_SIDE 1097 +#define IDC_COLOR 1098 +#define IDC_ALLIES 1099 +#define IDC_CREDITS 1100 +#define IDC_ACTSLIKE 1101 +#define IDC_PROGRESS1 1101 +#define IDC_NODECOUNT 1102 +#define IDC_CAP 1102 +#define IDC_TECHLEVEL 1103 +#define IDC_FREE 1103 +#define IDC_PERCENTBUILT 1104 +#define IDC_ID 1104 +#define IDC_PLAYERCONTROL 1105 +#define IDC_TEAMTYPES 1109 +#define IDC_NEWTEAMTYPE 1110 +#define IDC_DELETETEAMTYPE 1111 +#define IDC_LOADABLE 1113 +#define IDC_FULL 1114 +#define IDC_ANNOYANCE 1115 +#define IDC_GUARDSLOWER 1116 +#define IDC_RECRUITER 1117 +#define IDC_AUTOCREATE 1119 +#define IDC_PREBUILD 1120 +#define IDC_GROUP 1122 +#define IDC_WAYPOINT 1123 +#define IDC_SCRIPT 1124 +#define IDC_TASKFORCE 1125 +#define IDC_TRANSPORTWAYPOINT 1126 +#define IDC_REINFORCE 1127 +#define IDC_DROPPOD 1128 +#define IDC_WHINER 1129 +#define IDC_LOOSERECRUIT 1130 +#define IDC_AGGRESSIVE 1131 +#define IDC_SUICIDE 1132 +#define IDC_ONTRANSONLY 1133 +#define IDC_AVOIDTHREATS 1134 +#define IDC_IONIMMUNE 1135 +#define IDC_TRANSPORTRETURNSONUNLOAD 1136 +#define IDC_ARETEAMMEMBERSRECRUITABLE 1137 +#define IDC_ISBASEDEFENSE 1138 +#define IDC_ONLYTARGETHOUSEENEMY 1139 +#define IDC_MINDCONTROLDECISION 1140 +#define IDC_VETERANLEVEL 1143 +#define IDC_TASKFORCES 1144 +#define IDC_UNITS 1145 +#define IDC_ADDUNIT 1146 +#define IDC_DELETEUNIT 1147 +#define IDC_NUMBERUNITS 1148 +#define IDC_UNITTYPE 1149 +#define IDC_DELETETASKFORCE 1150 +#define IDC_ADDTASKFORCE 1151 +#define IDC_ADD 1154 +#define IDC_REPEAT 1156 +#define IDC_TRIGGER 1157 +#define IDC_ADDTRIGGER 1160 +#define IDC_DELETETRIGGER 1161 +#define IDC_FLAG1 1162 +#define IDC_PLACEONMAP 1162 +#define IDC_FLAG2 1163 +#define IDC_CLONE 1163 +#define IDC_FLAG3 1164 +#define IDC_FLAG4 1165 +#define IDC_FLAG5 1166 +#define IDC_EVENT 1167 +#define IDC_FLAG6 1167 +#define IDC_ADDEVENT 1168 +#define IDC_FLAG7 1168 +#define IDC_DELETEEVENT 1169 +#define IDC_FLAG8 1169 +#define IDC_ACTION 1170 +#define IDC_FLAG9 1170 +#define IDC_EVENTPARAM1 1171 +#define IDC_EVENTPARAM2 1172 +#define IDC_ADDACTION 1173 +#define IDC_DELETEACTION 1174 +#define IDC_EVENTTYPE 1175 +#define IDC_ACTIONPARAM1 1176 +#define IDC_ACTIONWAYPOINT 1177 +#define IDC_ACTIONTYPE 1178 +#define IDC_ACTIONPARAM2 1179 +#define IDC_ACTIONPARAM3 1180 +#define IDC_ACTIONPARAM4 1181 +#define IDC_ACTIONPARAM5 1182 +#define IDC_ACTIONPARAM6 1183 +#define IDC_LABEL_E1 1184 +#define IDC_LABEL_E2 1185 +#define IDC_LABEL_A1 1186 +#define IDC_LABEL_A4 1187 +#define IDC_LABEL_A2 1188 +#define IDC_LABEL_A3 1189 +#define IDC_LABEL_A5 1190 +#define IDC_LABEL_A6 1191 +#define IDC_TRIGGER2 1192 +#define IDC_SCRIPTTYPE 1193 +#define IDC_PARAM 1196 +#define IDC_PDESC 1198 +#define IDC_AITRIGGERTYPE 1199 +#define IDC_ENABLEALL 1200 +#define IDC_TEAMTYPE1 1204 +#define IDC_OWNER 1205 +#define IDC_TEAMTYPE2 1206 +#define IDC_DATALABEL 1210 +#define IDC_DATA 1211 +#define IDC_FLOAT1 1213 +#define IDC_FLOAT2 1215 +#define IDC_FLOAT3 1216 +#define IDC_ENABLED 1218 +#define IDC_POOL 1219 +#define IDC_MAPNAME 1220 +#define IDC_BROWSE 1221 +#define IDC_IMPORTTREES 1222 +#define IDC_IMPORTOVERLAY 1223 +#define IDC_IMPORTUNITS 1224 +#define IDC_MULTIPLAYER 1226 +#define IDC_IMPORTFILE 1228 +#define IDC_LANGUAGE 1231 +#define IDC_VERSION 1232 +#define IDC_BUILTBY 1233 +#define IDC_LDESC 1233 +#define IDC_LNAME 1234 +#define IDC_LNEXTSCENARIO 1235 +#define IDC_LALTNEXTSCENARIO 1236 +#define IDC_LNEWINIFORMAT 1237 +#define IDC_LCARRYOVERCAP 1238 +#define IDC_LENDOFGAME 1239 +#define IDC_LSKIPSCORE 1240 +#define IDC_LONETIMEONLY 1241 +#define IDC_LSKIPMAPSELECT 1242 +#define IDC_LOFFICIAL 1243 +#define IDC_LIGNOREGLOBALAITRIGGERS 1244 +#define IDC_LTRUCKCRATE 1245 +#define IDC_LTRAINCRATE 1246 +#define IDC_LPERCENT 1247 +#define IDC_LMULTIPLAYERONLY 1248 +#define IDC_LTIBERIUMGROWTHENABLED 1249 +#define IDC_LVEINGROWTHENABLED 1250 +#define IDC_LICEGROWTHENABLED 1251 +#define IDC_LTIBERIUMDEATHTOVISCEROID 1252 +#define IDC_LFREERADAR 1253 +#define IDC_LINITIME 1254 +#define IDC_LPLAYER 1255 +#define IDC_HUMANPLAYER 1256 +#define IDC_AUTOPROD 1257 +#define IDC_LHOUSE 1258 +#define IDC_LSTRENGTH 1259 +#define IDC_LPOS 1260 +#define IDC_LSTATE 1261 +#define IDC_LDIRECTION 1262 +#define IDC_LTAG 1263 +#define IDC_LP1 1264 +#define IDC_LP2 1265 +#define IDC_LP3 1266 +#define IDC_LP4 1267 +#define IDC_LP5 1268 +#define IDC_LAIREPAIRS 1271 +#define IDC_LENERGY 1272 +#define IDC_LUPGRADECOUNT 1273 +#define IDC_LSPOTLIGHT 1274 +#define IDC_LUPGRADE1 1275 +#define IDC_LUPGRADE2 1276 +#define IDC_LUPGRADE3 1277 +#define IDC_LVERSION 1279 +#define IDC_LBUILTBY 1280 +#define IDC_LINFO 1281 +#define IDC_LDOWNLOAD 1282 +#define IDC_LPLAYERHOUSE 1283 +#define IDC_LIMPORTOPTIONS 1284 +#define IDC_DESC 1285 +#define IDC_LIQ 1287 +#define IDC_LEDGE 1288 +#define IDC_LSIDE 1289 +#define IDC_LCOLOR 1290 +#define IDC_LALLIES 1291 +#define IDC_LCREDITS 1292 +#define IDC_LACTSLIKE 1293 +#define IDC_LNODECOUNT 1294 +#define IDC_LTECHLEVEL 1295 +#define IDC_LBUILDACTIVITY 1296 +#define IDC_LPLAYERCONTROL 1297 +#define IDC_LNORMAL 1298 +#define IDC_LIONSTORM 1299 +#define IDC_LAMBIENT1 1300 +#define IDC_LLEVEL1 1301 +#define IDC_LAMBIENT2 1302 +#define IDC_LLEVEL2 1303 +#define IDC_LRED1 1304 +#define IDC_LGREEN1 1305 +#define IDC_LBLUE1 1306 +#define IDC_LRED2 1307 +#define IDC_LGREEN2 1308 +#define IDC_LBLUE2 1309 +#define IDC_LID 1310 +#define IDC_LP6 1312 +#define IDC_LTIBERIUMGROWS 1314 +#define IDC_LTIBERIUMSPREADS 1315 +#define IDC_LTIBERIUMEXPLOSIVE 1316 +#define IDC_LDESTROYABLEBRIDGES 1317 +#define IDC_LMCVDEPLOY 1318 +#define IDC_LINITIALVETERAN 1319 +#define IDC_LFIXEDALLIANCE 1320 +#define IDC_LHARVESTERIMMUNE 1321 +#define IDC_LFOGOFWAR 1322 +#define IDC_LINERT 1323 +#define IDC_LIONSTORMS 1324 +#define IDC_LMETEORITES 1325 +#define IDC_LVISCEROIDS 1326 +#define IDC_INTRO 1327 +#define IDC_BRIEF 1328 +#define IDC_WIN 1329 +#define IDC_LOSE 1330 +#define IDC_STARTINGDROPSHIPS 1331 +#define IDC_POSTSCORE 1332 +#define IDC_PREMAPSELECT 1333 +#define IDC_CARRYOVERMONEY 1334 +#define IDC_TIMERINHERIT 1335 +#define IDC_FILLSILOS 1336 +#define IDC_LSTARTINGDROPSHIPS 1337 +#define IDC_LCARRYOVERMONEY 1338 +#define IDC_LINHERITTIMER 1339 +#define IDC_LFILLSILOS 1340 +#define IDC_LMOVIES 1341 +#define IDC_LINTRO 1342 +#define IDC_LBRIEF 1343 +#define IDC_LWIN 1344 +#define IDC_LLOSE 1345 +#define IDC_LACTION 1346 +#define IDC_LPOSTSCORE 1347 +#define IDC_LPREMAPSELECT 1348 +#define IDC_SIZEFRAME 1349 +#define IDC_LSIZE 1350 +#define IDC_USEABLEFRAME 1351 +#define IDC_LUSEABLE 1352 +#define IDC_LTHEATER 1353 +#define IDC_MAPPROBLEMS 1357 +#define IDC_LPROBLEMSFOUND 1358 +#define IDC_RULESLIKETS 1360 +#define IDC_ONLYORIGINAL 1364 +#define IDC_LADDONNEEDED 1365 +#define IDC_TILESET 1366 +#define IDC_OVERLAY 1367 +#define IDC_IMPORT 1370 +#define IDC_WIDTH 1373 +#define IDC_HEIGHT 1374 +#define IDC_BRUSHSIZE 1377 +#define IDC_SAVEOFTEN 1378 +#define IDC_NEWTRIGGER 1383 +#define IDC_TRIGGERTAB 1393 +#define IDC_TRIGGERTYPE 1394 +#define IDC_NEWEVENT 1396 +#define IDC_EVENTDESCRIPTION 1399 +#define IDC_PARAMETER 1401 +#define IDC_PARAMVALUE 1402 +#define IDC_NEWACTION 1403 +#define IDC_ACTIONDESCRIPTION 1404 +#define IDC_GLOBAL 1405 +#define IDC_DESCRIPTION 1407 +#define IDC_COUNTRY 1411 +#define IDC_DISABLED 1412 +#define IDC_LTRANSPORTWAYPOINT 1413 +#define IDC_SINGLE 1414 +#define IDC_MULTI 1415 +#define IDC_CREATE 1415 +#define IDC_COMPRESS 1417 +#define IDC_NOCOMPRESSION 1418 +#define IDC_PREVIEWMODE 1419 +#define IDC_EXISTINGPREVIEW 1420 +#define IDC_NOPREVIEW 1421 +#define IDC_PROGRESS 1423 +#define IDC_EASY 1424 +#define IDC_MEDIUM 1425 +#define IDC_MMX 1425 +#define IDC_HARD 1426 +#define IDC_MMX2 1426 +#define IDC_STANDARD 1426 +#define IDC_MEATGRIND 1427 +#define IDC_NAVALWAR 1428 +#define IDC_NUKEWAR 1429 +#define IDC_AIRWAR 1430 +#define IDC_MEGAWEALTH 1431 +#define IDC_DUEL 1432 +#define IDC_COOPERATIVE 1433 +#define IDC_MINPLAYERS 1434 +#define IDC_TEAMGAME 1434 +#define IDC_MAXPLAYERS 1435 +#define IDC_LABEL 1435 +#define IDC_UPDATELIST 1436 +#define IDC_DOWNLOADLIST 1437 +#define IDC_PROGLABEL 1438 +#define IDC_CHANGELOCAL 1439 +#define IDC_CHANGE 1440 +#define IDC_AITRIGGERS 1440 +#define IDC_AVAIL 1442 +#define IDC_USED 1443 +#define IDC_REMOVE 1444 +#define IDC_MCD_L 1446 +#define IDC_PREVIEW 1448 +#define IDC_CONDITION 1449 +#define IDC_NUMBER 1450 +#define IDC_BASEDEFENSE 1452 +#define IDC_SKIRMISH 1453 +#define IDC_MULTISIDE 1456 +#define IDC_SCRIPTS 1457 +#define IDC_REPORT 1458 +#define IDC_CAPTION 1459 +#define IDC_COMBO1 1460 +#define IDC_LICENSE_AND_COPYRIGHT 1461 +#define IDC_PREFER_LOCAL_THEATER_INI_FILES 1462 +#define IDC_PREFER_LOCAL_THEATER_FILES 1463 +#define ID_FILE_OPENMAP 40001 +#define ID_FILE_SAVEAS 40002 +#define ID_FILE_QUIT 40003 +#define ID_OPTIONS_TIBERIANSUNOPTIONS 40004 +#define ID_OPTIONS_EXPORTRULESINI 40005 +#define ID_HELP_INFO 40006 +#define ID_MAPVIEW 40007 +#define ID_INSERT_TREES 40008 +#define ID_INSERT_UNITS 40009 +#define ID_INSERT_BUILDINGS 40010 +#define ID_INSERT_INFANTRY 40011 +#define ID_FILE_IMPORTMOD 40016 +#define ID_FILE_RUNTIBERIANSUN 40017 +#define IDS_BUILTBY 40017 +#define ID_DEBUG_EXPORTMAPPACK 40018 +#define IDS_VERSIONTEXT 40018 +#define ID_DEBUG_EXPORTMAPPACKNOSECTIONS 40019 +#define IDS_VERSION 40019 +#define IDS_VERSIONTEXTTS 40020 +#define ID_HELP_TIPOFTHEDAY 40022 +#define ID_OPTIONS_SIMPLEVIEW 40023 +#define ID_OPTIONS_SHOWMINIMAP 40024 +#define ID_FILE_VALIDATEMAP 40025 +#define ID_MAPPACKTOOLS_EXPORTMAPPACK 40031 +#define ID_MAPPACKTOOLS_IMPORTMAPPACKRAWHEXDATA 40032 +#define ID_MAPPACKTOOLS_USEFORMAT80DECODINGONBINARYFILE 40033 +#define ID_MAPPACKTOOLS_USEFORMAT80ENCODINGONBINARYFILE 40034 +#define ID_MAPPACKTOOLS_EXPORTONLYSECTION1OFMAPPACKRAWHEXDATABASE64DECODED 40035 +#define ID_EDIT_BASICSETTINGS 40036 +#define ID_EDIT_SINGLEPLAYERSETTINGS 40037 +#define ID_EDIT_SPECIALFLAGS 40038 +#define ID_EDIT_HOUSES 40039 +#define ID_EDIT_MAP 40040 +#define ID_EDIT_TRIGGERS 40041 +#define ID_EDIT_TAGS 40042 +#define ID_EDIT_LIGHTING 40043 +#define ID_EDIT_SCRIPTS 40044 +#define ID_EDIT_TEAMS 40045 +#define ID_EDIT_TASKFORCES 40046 +#define ID_EDIT_AITRIGGERS 40047 +#define ID_EDIT_AITRIGGERENABLING 40048 +#define ID_EDIT_INIEDITING 40049 +#define ID_TERRAIN_HEIGHTENGROUND 40053 +#define ID_TERRAIN_LOWERGROUND 40054 +#define ID_TERRAIN_PAINT 40055 +#define ID_TERRAIN_RISETILE 40060 +#define ID_TERRAIN_RAISETILE 40062 +#define ID_TERRAIN_LOWERTILE 40063 +#define ID_TERRAIN_FLATTEN 40064 +#define ID_TERRAIN_CLOAK 40065 +#define ID_TERRAIN_SHOWEVERYTILE 40066 +#define ID_TERRAIN_SHOWALLFIELDS 40071 +#define ID_TERRAIN_HIDEFIELD 40072 +#define ID_EDIT_TRIGGEREDITOR 40076 +#define ID_MAPTOOLS_CHANGEMAPHEIGHT 40077 +#define ID_EDIT_GLOBALVARIABLES 40082 +#define ID_MAPTOOLS_AUTOLEVEL 40085 +#define ID_MAPTOOLS_FRONTCLIFF 40092 +#define ID_MAPTOOLS_BACKCLIFF 40093 +#define ID_MAPTOOLS_AUTOCREATESHORES 40096 +#define ID_OPTIONS_DISABLEAUTOSHORE 40104 +#define ID_OPTIONS_DISABLEAUTOLAT 40105 +#define ID_ONLINE_AUTOMATICUPDATE 40106 +#define ID_EDIT_COPYWHOLEMAP 40109 +#define ID_EDIT_PASTEWHOLEMAP 40110 +#define ID_MARBLEMADNESS 40115 +#define ID_OPTIONS_SOUNDS 40118 +#define ID_ONLINE_UNOFFICIALSUPPORTFORUM 40119 +#define ID_OPTIONS_DISABLESLOPECORRECTION 40120 +#define ID_OPTIONS_SHOWBUILDINGOUTLINE 40123 +#define ID_FILE_FILE1 40129 +#define ID_FILE_FILE2 40130 +#define ID_FILE_FILE3 40131 +#define ID_FILE_FILE4 40132 +#define ID_MAPTOOLS_SEARCHWAYPOINT 40133 +#define ID_MAPTOOLS_TOOLSCRIPTS 40135 +#define ID_HELP_SHOWLOGS 40138 +#define ID_HELP_ 40139 +#define ID_HELP_SHOWLOGS40140 40140 +#define ID_OPTIONS_SMOOTHZOOM 40141 +#define ID_OPTIONS_USEDEFAULTMOUSECURSOR 40142 + +#define IDS_LINEARVERSION 57604 +#define IDC_TOOLTIPCENTER 65535 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 300 +#define _APS_NEXT_COMMAND_VALUE 40144 +#define _APS_NEXT_CONTROL_VALUE 1464 +#define _APS_NEXT_SYMED_VALUE 111 +#endif +#endif diff --git a/MissionEditor/structs.cpp b/MissionEditor/structs.cpp new file mode 100644 index 0000000..113f18f --- /dev/null +++ b/MissionEditor/structs.cpp @@ -0,0 +1,56 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "StdAfx.h" +#include "Structs.h" +#include "functions.h" + +#include "MapTool.h" + +ACTIONDATA::~ACTIONDATA() +{ +} + +void ACTIONDATA::reset() { + mode = 0; + type = 0; + data = 0; + data2 = 0; + data3 = 0; + z_data = 0; + data_s = ""; + tool.reset(); +} + +void PICDATA::createVBorder() +{ + ASSERT(!vborder); + ASSERT(pic && bType != PICDATA_TYPE_BMP); + _vBorder = std::make_shared<std::vector<VBORDER>>(wMaxHeight); + vborder = _vBorder->data(); + int k; + for (k = 0;k < wMaxHeight;k++) + { + int l, r; + GetDrawBorder(static_cast<BYTE*>(pic), wMaxWidth, k, l, r, 0); + vborder[k].left = l; + vborder[k].right = r; + } +} \ No newline at end of file diff --git a/MissionEditor/tests.cpp b/MissionEditor/tests.cpp new file mode 100644 index 0000000..308959b --- /dev/null +++ b/MissionEditor/tests.cpp @@ -0,0 +1,247 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version BR of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "tests.h" +#include "inlines.h" +#include <string> +#include <functional> +#include <iostream> +#include "Tube.h" + +class TestError : public std::runtime_error +{ +public: + TestError(const std::string text) : std::runtime_error(text) + { + + } +}; + +bool RaiseTestError(const char* file, int line, const char* function, const char* assertion) +{ + const std::string error = std::string("Test assertion: ") + assertion + " in file " + file + ", line " + std::to_string(line); + throw TestError(error); + return false; +} + +bool ReportTest(const char* file, int line, const char* function, const char* assertion) +{ + const std::string error = std::string("Test succeeded in ") + function + " " + assertion + " in file " + file + ", line " + std::to_string(line); + std::cout << error << std::endl; + return true; +} + +#define STR( s ) # s +#define REPORT_TEST(COND) (void) (((!!(COND)) && ReportTest(THIS_FILE, __LINE__, __FUNCTION__, STR(COND) )) || RaiseTestError(THIS_FILE, __LINE__, __FUNCTION__, STR(COND))) +#define TEST(COND) (void) ((!!(COND)) || RaiseTestError(THIS_FILE, __LINE__, __FUNCTION__, STR(COND))) + +bool run_test(const std::function<void()>& f) +{ + try + { + f(); + return true; + } + catch(const TestError& e) + { + std::cout << e.what() << std::endl; + } + catch (const std::exception& e) + { + std::cout << "ERROR: Exception occurred: " << e.what() << std::endl; + } + return false; +} + +int main(int argc, char* argv[]) +{ + Tests t; + return t.run(); +} + +int Tests::run() +{ + int failed_tests = 0; + std::vector<std::function<void()>> test_functions({ + [this]() { test_inlines(); }, + [this]() { test_tube_create(); }, + [this]() { test_tube_reverse(); }, + [this]() { test_tube_append(); }, + [this]() { test_tube_delimiter(); }, + [this]() { test_hsv(); }, + [this]() { test_iso(); }, + }); + for (const auto f : test_functions) + { + if (!run_test(f)) + ++failed_tests; + } + + std::cout << "Failed: " << failed_tests << std::endl; + std::cout << "Succeeded: " << test_functions.size() - failed_tests << std::endl; + return failed_tests ? 1 : 0; +} + +void Tests::test_inlines() +{ + REPORT_TEST(GetParam("SOME,,Value", 1) == CString("")); + REPORT_TEST(GetParam("SOME,,Value", 2) == CString("Value")); + REPORT_TEST(GetParam("SOME,,Value", 0) == CString("SOME")); + REPORT_TEST(GetParam("SOME,,Value", 77) == CString("")); + REPORT_TEST(GetParam("SOME,,Value,", 3) == CString("")); + REPORT_TEST(GetParam("SOME,,Value,0", 3) == CString("0")); + REPORT_TEST(GetParam(" SOME,", 0) == CString(" SOME")); + REPORT_TEST(SplitParams("SOME,,Value,0") == std::vector<CString>({ "SOME","","Value","0" })); + REPORT_TEST(SplitParams("") == std::vector<CString>({ "" })); + REPORT_TEST(SplitParams("SOME,,Value,0,") == std::vector<CString>({ "SOME","","Value","0", "" })); + REPORT_TEST(Join("::", { "my", "value" }) == "my::value"); + REPORT_TEST(SetParam("SOME,,Value,0,", 0, "NOTSOME") == "NOTSOME,,Value,0,"); + REPORT_TEST(SetParam("SOME,,Value,0,", 1, "NOTSOME") == "SOME,NOTSOME,Value,0,"); + REPORT_TEST(SetParam("SOME,,Value,0,", 3, "1") == "SOME,,Value,1,"); + REPORT_TEST(SetParam("SOME,,Value,0,", 10, "A") == "SOME,,Value,0,,,,,,,A"); +} + +namespace TubeDirections +{ + auto TL = ETubeDirection::TopLeft; + auto TC = ETubeDirection::Top; + auto TR = ETubeDirection::TopRight; + auto CR = ETubeDirection::Right; + auto BR = ETubeDirection::BottomRight; + auto BC = ETubeDirection::Bottom; + auto BL = ETubeDirection::BottomLeft; + auto CL = ETubeDirection::Left; + auto XX = ETubeDirection::Undefined; +} + +void Tests::test_tube_create() +{ + using namespace TubeDirections; + + REPORT_TEST(CTube::autocreate(50, 50, 50, 50) == CTube(50, 50, XX, 50, 50, std::vector<ETubeDirection>({ XX }))); + REPORT_TEST(CTube::autocreate(50, 50, 55, 50) == CTube(50, 50, BC, 55, 50, std::vector<ETubeDirection>({ BC, BC, BC, BC, BC, XX}))); + REPORT_TEST(CTube::autocreate(50, 50, 45, 50) == CTube(50, 50, TC, 45, 50, std::vector<ETubeDirection>({ TC, TC, TC, TC, TC, XX }))); + REPORT_TEST(CTube::autocreate(50, 50, 45, 45, 0) == CTube(50, 50, CL, 45, 45, std::vector<ETubeDirection>({ TL, TL, TL, TL, TL, XX }))); + REPORT_TEST(CTube::autocreate(50, 50, 45, 45) == CTube(50, 50, CL, 45, 45, std::vector<ETubeDirection>({ CL, TL, TL, TL, TL, TC, XX }))); + REPORT_TEST(CTube::autocreate(50, 50, 45, 46, 0) == CTube(50, 50, TC, 45, 46, std::vector<ETubeDirection>({ TL, TL, TL, TL, TC, XX }))); + REPORT_TEST(CTube::autocreate(50, 50, 45, 46, 1) == CTube(50, 50, TC, 45, 46, std::vector<ETubeDirection>({ TC, TL, TL, TL, TL, XX }))); + REPORT_TEST(CTube::autocreate(50, 50, 46, 45, 1) == CTube(50, 50, CL, 46, 45, std::vector<ETubeDirection>({ CL, TL, TL, TL, TL, XX }))); + +} + +void Tests::test_tube_reverse() +{ + using namespace TubeDirections; + + REPORT_TEST(CTube(50, 50, BC, 55, 50, std::vector<ETubeDirection>({ BC, BC, BC, BC, BC, XX})).reverse() == + CTube(55, 50, TC, 50, 50, std::vector<ETubeDirection>({ TC, TC, TC, TC, TC, XX }))); + REPORT_TEST(CTube(50, 50, TC, 45, 46, std::vector<ETubeDirection>({ TC, TL, TL, TL, TL, XX })).reverse() == + CTube(45, 46, BR, 50, 50, std::vector<ETubeDirection>({ BR, BR, BR, BR, BC, XX }))); + REPORT_TEST(CTube(50, 50, BC, 51, 50, std::vector<ETubeDirection>({ BC, XX })).reverse() == + CTube(51, 50, TC, 50, 50, std::vector<ETubeDirection>({ TC, XX }))); + REPORT_TEST(CTube(50, 50, BC, 52, 50, std::vector<ETubeDirection>({ BC, BC, XX })).reverse() == + CTube(52, 50, TC, 50, 50, std::vector<ETubeDirection>({ TC, TC, XX }))); + +} + +void Tests::test_tube_append() +{ + using namespace TubeDirections; + + CTube tubeToBottom(50, 50, BC, 53, 50, std::vector<ETubeDirection>({ BC, BC, BC, XX })); + tubeToBottom.append(55, 50); + REPORT_TEST(tubeToBottom == CTube(50, 50, BC, 55, 50, std::vector<ETubeDirection>({ BC, BC, BC, BC, BC, XX }))); + + CTube tubeToTL(50, 50, TC, 49, 49, std::vector<ETubeDirection>({ TL, XX })); + tubeToTL.append(49, 47); + REPORT_TEST(tubeToTL == CTube(50, 50, TC, 49, 47, std::vector<ETubeDirection>({ TL, CL, CL, XX }))); + + CTube nullLen(50, 50, XX, 50, 50, std::vector<ETubeDirection>({ XX })); + nullLen.append(55, 50); + REPORT_TEST(nullLen == CTube(50, 50, BC, 55, 50, std::vector<ETubeDirection>({ BC, BC, BC, BC, BC, XX }))); + + CTube nullLenYMajor(50, 50, XX, 50, 50, std::vector<ETubeDirection>({ XX })); + nullLenYMajor.append(51, 53); + REPORT_TEST(nullLenYMajor == CTube(50, 50, CR, 51, 53, std::vector<ETubeDirection>({ CR, BR, CR, XX }))); + + CTube nullAppend(50, 50, BC, 52, 50, std::vector<ETubeDirection>({ BC, BC, XX })); + nullAppend.append(52, 50); + REPORT_TEST(nullAppend == CTube(50, 50, BC, 52, 50, std::vector<ETubeDirection>({ BC, BC, XX }))); + + CTube zeroTube(50, 50, XX, 50, 50, std::vector<ETubeDirection>()); + zeroTube.append(55, 50); + REPORT_TEST(zeroTube == CTube(50, 50, BC, 55, 50, std::vector<ETubeDirection>({ BC, BC, BC, BC, BC, XX }))); + + // Intersection - for now assume TS allows this + CTube tubeWithIntersection(50, 50, TC, 49, 49, std::vector<ETubeDirection>({ TL, XX })); + tubeWithIntersection.append(51, 51); + REPORT_TEST(tubeWithIntersection == CTube(50, 50, TC, 51, 51, std::vector<ETubeDirection>({ TL, BR, BR, XX }))); + + // Shorten + CTube tubeShorten(50, 50, TC, 47, 47, std::vector<ETubeDirection>({ TL, TL, TL, XX })); + tubeShorten.append(48, 48); + REPORT_TEST(tubeShorten == CTube(50, 50, TC, 48, 48, std::vector<ETubeDirection>({ TL, TL, XX }))); + +} + +void Tests::test_tube_delimiter() +{ + using namespace TubeDirections; + + // delimiter needs to be auto-added in any case as it causes crashes in TS/RA2 if it's missing somehow + //REPORT_TEST(CTube(50, 50, XX, 50, 50, std::vector<ETubeDirection>()) == CTube(50, 50, XX, 50, 50, std::vector<ETubeDirection>({ XX }))); + //REPORT_TEST(CTube(50, 50, XX, 49, 49, std::vector<ETubeDirection>({ TL })) == CTube(50, 50, XX, 49, 49, std::vector<ETubeDirection>({ TL, XX }))); + REPORT_TEST(CTube(1, "50, 50, -1, 50, 50").toString() == "50,50,-1,50,50,-1"); + + // right now we're also fixing when loading the map, TBD: + REPORT_TEST(CTube(0xFFFF, "50, 50, -1, 50, 50") == CTube(50, 50, XX, 50, 50, std::vector<ETubeDirection>({ XX }))); +} + +void Tests::test_hsv() +{ + typedef std::array<unsigned char, 3> ba; + REPORT_TEST(HSVToRGB(0, 1.0, 1.0) == ba({ 255, 0, 0 })); + REPORT_TEST(HSVToRGB(0, 0.0, 1.0) == ba({ 255, 255, 255 })); + REPORT_TEST(HSVToRGB(0, 0.0, 0.0) == ba({ 0, 0, 0 })); + REPORT_TEST(HSVToRGB(45.0, 1.0, 1.0) == ba({ 255, 191, 0 })); + REPORT_TEST(HSVToRGB(75.0, 1.0, 1.0) == ba({ 191, 255, 0 })); + REPORT_TEST(HSVToRGB(135.0, 1.0, 1.0) == ba({ 0, 255, 63 })); + REPORT_TEST(HSVToRGB(240.0, 1.0, 1.0) == ba({ 0, 0, 255 })); + REPORT_TEST(HSVToRGB(184.0, 1.0, 1.0) == ba({ 0, 238, 255 })); + REPORT_TEST(HSVToRGB(285.0, 1.0, 1.0) == ba({ 191, 0, 255 })); + REPORT_TEST(HSVToRGB(330.0, 1.0, 1.0) == ba({ 255, 0, 127 })); + REPORT_TEST(HSVToRGB(180.0, 1.0, 0.5) == ba({ 0, 127, 127 })); + REPORT_TEST(HSVToRGB(180.0, 0.5, 0.5) == ba({ 63, 127, 127 })); +} + +void Tests::test_iso() +{ + CMapData d; + d.CreateMap(16, 10, 0, 0); + REPORT_TEST(d.ProjectCoords3d(MapCoords(0, 0)) == ProjectedCoords((26 - 2) * f_x / 2, 0)); + REPORT_TEST(d.ProjectCoords3d(MapCoords(1, 0)) == ProjectedCoords((26 - 2 - 1) * f_x / 2, f_y / 2)); + REPORT_TEST(d.ProjectCoords3d(MapCoords(0, 1)) == ProjectedCoords((26 - 2 + 1) * f_x / 2, f_y / 2)); + REPORT_TEST(d.ProjectCoords3d(MapCoords(1, 1)) == ProjectedCoords((26 - 2) * f_x / 2, f_y)); + REPORT_TEST(d.ProjectCoords3d(MapCoords(1, 1), 1) == ProjectedCoords((26 - 2) * f_x / 2, f_y / 2)); + + REPORT_TEST(d.ToMapCoords3d(ProjectedCoords((26 - 2) * f_x / 2, 0), 0) == MapCoords(0, 0)); + +} diff --git a/MissionEditor/tests.h b/MissionEditor/tests.h new file mode 100644 index 0000000..cc8d9ea --- /dev/null +++ b/MissionEditor/tests.h @@ -0,0 +1,35 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +#pragma once + +class Tests +{ +public: + int run(); + +private: + void test_inlines(); + void test_tube_create(); + void test_tube_reverse(); + void test_tube_append(); + void test_tube_delimiter(); + void test_hsv(); + void test_iso(); +}; \ No newline at end of file diff --git a/MissionEditor/variables.cpp b/MissionEditor/variables.cpp new file mode 100644 index 0000000..c60f3e6 --- /dev/null +++ b/MissionEditor/variables.cpp @@ -0,0 +1,230 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +/************************************* +VARIABLES.CPP + +INCLUDES ALL FINAL SUN CONSTANTS AND +VARIABLES USED +*************************************/ + +#include "stdafx.h" +#include "mapdata.h" +#include "structs.h" +#include "FinalSun.h" +#include <Shlobj.h> +#include "MapTool.h" +#include "inlines.h" +#include <string> +#include <codecvt> + +/**INI Files**/ +CIniFile rules; +CIniFile art; +CIniFile ai; +CIniFile sound; +CIniFile tutorial; +CIniFile eva; +CIniFile theme; +CIniFile g_data; +CIniFile language; +CIniFile tiles_t; // temperat.ini shouldn´t be used except in CMapData::UpdateIniFile() and CLoading +CIniFile tiles_s; // snow.ini shouldn´t be used except in CMapData::UpdateIniFile() and CLoading +CIniFile tiles_u; // urban.ini ... +CIniFile tiles_un; // new urbannmd.ini +CIniFile tiles_l; // lunarmd.ini +CIniFile tiles_d; // desertmd.ini +CIniFile* tiles=NULL; // this should be used by every class/function except CMapData::UpdateIniFile(); +/*************/ + +/* the mapdata! */ +CMapData* Map; + +/* actiondata used for iso view */ +ACTIONDATA AD; + +/* A map with all the pictures in the pics directory, and some special pics */ +map<CString, PICDATA> pics; +TILEDATA* t_tiledata=NULL; +DWORD t_tiledata_count=0; +TILEDATA* s_tiledata=NULL; +DWORD s_tiledata_count=0; +TILEDATA* u_tiledata=NULL; +DWORD u_tiledata_count=0; + +// MW new tilesets +TILEDATA* un_tiledata=NULL; +DWORD un_tiledata_count=0; +TILEDATA* l_tiledata=NULL; +DWORD l_tiledata_count=0; +TILEDATA* d_tiledata=NULL; +DWORD d_tiledata_count=0; + +TILEDATA** tiledata=NULL; + +DWORD* tiledata_count=NULL; + +map<int, int> tilesets_start; + +// Palettes: +RGBTRIPLE palIso[256]; +RGBTRIPLE palUnit[256]; +RGBTRIPLE palStd[256]; +RGBTRIPLE palTheater[256]; +RGBTRIPLE palLib[256]; + +int iPalIso[256]; +int iPalUnit[256]; +int iPalStd[256]; +int iPalTheater[256]; +int iPalLib[256]; + +int bpp; + +map<CString, int> color_conv; +map<COLORREF, int> colorref_conv; + +map<int, HOUSEINFO> houses; +map<int, SIDEINFO> sides; + +map<CString, BOOL> missingimages; + +vector<CString> rndterrainsrc; + +/* Overlay tile data */ +#ifndef RA2_MODE +int overlay_number[]={0x0,0x2, 0x1a, 0x7e, 0xa7, 0x27}; +CString overlay_name[]={"Sandbags","GDI Wall", "Nod Wall", "Veins", "Veinhole monster", "Tracks"}; +BOOL overlay_visible[]={TRUE,TRUE,TRUE,FALSE,FALSE, TRUE}; +BOOL overlay_trail[]={TRUE,TRUE,TRUE,FALSE,FALSE, TRUE}; +BOOL overlay_trdebug[]={FALSE,FALSE,FALSE,FALSE,FALSE, FALSE}; +BOOL yr_only[]={FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; +int overlay_count=6; +const std::string editor_name = "FinalSun"; +#else +int overlay_number[]={0x0,0x2, 0x1a, 0xcb, 0xf1, 0xcc,0xf3,0xf0, 0x27}; +BOOL overlay_trdebug[]={FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}; +CString overlay_name[]={"Sandbags","Allied Wall", "Soviet Wall", "Black fence", "Prison camp fence", "White fence", "Yuri Wall", "Kremlin Wall", "Tracks"}; +BOOL overlay_visible[]={TRUE,TRUE,TRUE,TRUE,TRUE,TRUE, TRUE, TRUE, TRUE}; +BOOL overlay_trail[]={TRUE,TRUE,TRUE,TRUE,TRUE,TRUE, TRUE, TRUE, TRUE}; +BOOL yr_only[]={FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE}; +int overlay_count=9; +const std::string editor_name = "FinalAlert 2"; +#endif + +static const std::string GetAppDataPath() +{ + _setmbcp(CP_UTF8); + setlocale(LC_ALL, "C"); + if (!setlocale(LC_CTYPE, ".65001")) + setlocale(LC_CTYPE, ""); + CoInitializeEx(NULL, COINIT_MULTITHREADED); + CComPtr<IKnownFolderManager> manager; + CComPtr<IKnownFolder> local_app_data; + CComHeapPtr<WCHAR> local_app_data_folder; + HRESULT hr = CoCreateInstance(CLSID_KnownFolderManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&manager)); + if (SUCCEEDED(hr)) { + //std::shared_ptr<LPWSTR> x() + + if (SUCCEEDED(manager->GetFolder(FOLDERID_LocalAppData, &local_app_data))) { + LPWSTR b; + local_app_data->GetPath(KF_FLAG_CREATE, &b); + local_app_data_folder.Attach(b); + int a = 0; + std::string AppFolder = utf16ToUtf8(std::wstring(local_app_data_folder)); + //return CString(CW2A(CStringW(local_app_data_folder), CP_ACP)) + "\\" + editor_name + "\\"; + return AppFolder + "\\" + editor_name + "\\"; + } + } + + // fallback: use app directory + wchar_t app_path[MAX_PATH] = { 0 }; + GetModuleFileNameW(NULL, app_path, MAX_PATH); + std::wstring appPath = app_path; + std::size_t end = appPath.rfind(L'\\'); + if (end != std::wstring::npos) + appPath.resize(end + 1); + return utf16ToUtf8(appPath); +} + +/* Application specific global variables */ +char AppPath[MAX_PATH + 1] = { 0 }; +const std::string u8AppDataPath = GetAppDataPath(); +const std::wstring u16AppDataPath = utf8ToUtf16(u8AppDataPath); +char TSPath[MAX_PATH + 1] = { 0 }; +char currentMapFile[MAX_PATH + 1] = { 0 }; +BOOL bOptionsStartup=FALSE; +bool bAllowAccessBehindCliffs=false; + + +// infos for buildings and trees (should be extended to infantry, units, and aircraft) +// they are initialized in CIsoView, should be changed to CMapData +BUILDING_INFO buildinginfo[0x0F00]; +TREE_INFO treeinfo[0x0F00]; +#ifdef SMUDGE_SUPP +SMUDGE_INFO smudgeinfo[0x0F00]; +#endif + +/* error output */ +ofstream errstream; + +/* the finalsun app object */ +CFinalSunApp theApp; + +CString currentOwner="Neutral"; + +map<CString, XCString> CCStrings; +map<CString, XCString> AllStrings; + +// tilesets +int cliffset; +int cliffset_start; +int rampset; +int rampsmoothset; +int slopesetpiecesset; +int tunnelset; +int tracktunnelset; +int dirttunnelset; +int dirttracktunnelset; +int waterset; +int shoreset; +int ramp2set_start; +int pave2set_start; +int rampset_start; +int ramp2set; +int pave2set; +int cliff2set; +int cliff2set_start; +int cliffwater2set; + +// debug information +int last_succeeded_operation=0; + +#ifdef RA2_MODE +int editor_mode=1; +#ifdef YR_MODE +int yuri_mode=1; +#else +int yuri_mode=0; +#endif +#else +int editor_mode=0; +int yuri_mode=0; +#endif \ No newline at end of file diff --git a/MissionEditor/variables.h b/MissionEditor/variables.h new file mode 100644 index 0000000..721ad19 --- /dev/null +++ b/MissionEditor/variables.h @@ -0,0 +1,162 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +/******************************************* + Declare the global variables here +*******************************************/ + +#ifndef VARIABLES_H_INCLUDED +#define VARIABLES_H_INCLUDED + +#include "structs.h" +#include "FinalSun.h" +#include "MapData.h" + +// the map +extern CMapData* Map; + +// the ini files: +extern CIniFile rules; +extern CIniFile art; +extern CIniFile ai; +extern CIniFile sound; +extern CIniFile tutorial; +extern CIniFile eva; +extern CIniFile theme; +extern CIniFile g_data; +extern CIniFile language; +extern CIniFile tiles_t; +extern CIniFile tiles_s; +extern CIniFile tiles_u; +extern CIniFile tiles_un; // new urbannmd.ini +extern CIniFile tiles_l; // new lunarmd.ini +extern CIniFile tiles_d; // new desertmd.ini +extern CIniFile* tiles; + +// first time options are shown (at startup) +extern BOOL bOptionsStartup; + +// the current file beeing edited. +extern char currentMapFile[MAX_PATH + 1]; + +// all the pictures shown in the mapview +extern map<CString, PICDATA> pics; +extern TILEDATA* t_tiledata; +extern TILEDATA* s_tiledata; +extern TILEDATA* u_tiledata; +extern TILEDATA** tiledata; +extern DWORD s_tiledata_count; +extern DWORD t_tiledata_count; +extern DWORD u_tiledata_count; +extern DWORD* tiledata_count; + +// MW new tilesets +extern TILEDATA* un_tiledata; +extern DWORD un_tiledata_count; +extern TILEDATA* l_tiledata; +extern DWORD l_tiledata_count; +extern TILEDATA* d_tiledata; +extern DWORD d_tiledata_count; + +extern map<int, int> tilesets_start; + +extern RGBTRIPLE palIso[256]; +extern RGBTRIPLE palUnit[256]; +extern RGBTRIPLE palStd[256]; +extern RGBTRIPLE palTheater[256]; +extern RGBTRIPLE palLib[256]; + +extern int iPalIso[256]; +extern int iPalUnit[256]; +extern int iPalStd[256]; +extern int iPalTheater[256]; +extern int iPalLib[256]; +extern int bpp; + +extern map<CString, int> color_conv; +extern map<COLORREF, int> colorref_conv; + +extern map<int, HOUSEINFO> houses; +extern map<int, SIDEINFO> sides; + +extern map<CString, BOOL> missingimages; + +extern vector<CString> rndterrainsrc; + +// infos for buildings and trees (should be extended to infantry, units, and aircraft) +// they are initialized in CIsoView, should be changed to CMapData +extern BUILDING_INFO buildinginfo[0x0F00]; +extern TREE_INFO treeinfo[0x0F00]; +#ifdef SMUDGE_SUPP +extern SMUDGE_INFO smudgeinfo[0x0F00]; +#endif + +// the app object: +extern CFinalSunApp theApp; + +/* error output */ +extern ofstream errstream; + +// application path +extern char AppPath[MAX_PATH + 1]; +extern const std::string u8AppDataPath; +extern const std::wstring u16AppDataPath; +extern char TSPath[MAX_PATH + 1]; + +extern bool bAllowAccessBehindCliffs; + +// overlay types (the ones with additional information like name etc.) +extern int overlay_count; // number of overlay ids that have additional information +extern int overlay_number[]; // what overlay id? +extern CString overlay_name[]; // what name? +extern BOOL overlay_trail[]; // is it handled as trail? +extern BOOL overlay_trdebug[]; +extern BOOL yr_only[]; + + +extern CString currentOwner; +extern map<CString, XCString> CCStrings; + +// tileset ids +extern int cliffset; +extern int cliffset_start; +extern int rampset; +extern int rampsmoothset; +extern int slopesetpiecesset; +extern int waterset; +extern int shoreset; +extern int ramp2set; +extern int pave2set; +extern int ramp2set_start; +extern int pave2set_start; +extern int rampset_start; +extern int cliff2set; +extern int cliff2set_start; +extern int cliffwater2set; + + +// ra2 or TS mode? +extern int editor_mode; +extern int yuri_mode; + +// debug +extern int last_succeeded_operation; + +#endif \ No newline at end of file diff --git a/MissionEditorPackLib/MissionEditorPackLib.cpp b/MissionEditorPackLib/MissionEditorPackLib.cpp new file mode 100644 index 0000000..d8fc816 --- /dev/null +++ b/MissionEditorPackLib/MissionEditorPackLib.cpp @@ -0,0 +1,2269 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#define _HAS_STD_BYTE 0 // see https://developercommunity.visualstudio.com/t/error-c2872-byte-ambiguous-symbol/93889 +struct IUnknown; + +#include "MissionEditorPackLib.h" + +#include <map> +#include <vector> +#include "mix_file.h" + +#include "cc_file.h" +#include "xcc_dirs.h" +#include "shp_ts_file.h" +#include "tmp_ts_file.h" +#include "cc_file.h" +#include "pal_file.h" +#include "shp_ts_file.h" +#include "tmp_ts_file.h" +#include <shp_decode.h> +#include <mix_file.h> +#include <ddpf_conversion.h> +#include <vxl_file.h> +#include <math.h> +#include <hva_file.h> +#include "mix_file_write.h" +#include <locale> + +#include <windows.h> +#include <windowsx.h> +#include <ddraw.h> +#include <commctrl.h> +#include <regex> + +#include "VoxelNormals.h" + + +Cmix_file mixfiles[2000]; +std::string mixfiles_names[2000]; +Cshp_ts_file cur_shp; // for now only support one shp at once +Ctmp_ts_file cur_tmp; + + +DWORD dwMixFileCount = 0; + + +t_palet ts_palettes[256]; +DWORD dwPalCount = 0; +DWORD conv_color[256][256]; +DWORD transp_conv_color[256]; +DDPIXELFORMAT cur_pf[256]; +BOOL bFirstConv[256]; + +HBRUSH hTranspBrush = (HBRUSH)INVALID_HANDLE_VALUE; +HPEN hTranspPen = (HPEN)INVALID_HANDLE_VALUE; + + +#define MYASSERT(a,b) if(!a){ FSunPackLib::FSPL_EXCEPTION e; e.err_code=b; throw(e); } + + + + + +__forceinline void CreateConvLookUpTable(DDPIXELFORMAT& pf, HTSPALETTE hPalette) +{ + + /*fstream f; + f.open("c:\\convtable.log", ios_base::out | ios_base::trunc ); + + f << "CreateConvLookUpTable() called" << endl; + f.flush();*/ + if (memcmp(&pf, &cur_pf[hPalette - 1], sizeof(DDPIXELFORMAT)) || bFirstConv[hPalette - 1]) + { + bFirstConv[hPalette - 1] = FALSE; + cur_pf[hPalette - 1] = pf; + + /*f << "Setting Conversion" << endl; + f.flush();*/ + Cddpf_conversion conv; + conv.set_pf(pf); + + /*f << "Calculating colors" << endl; + f.flush();*/ + int i; + for (i = 0;i < 256;i++) + { + conv_color[hPalette - 1][i] = conv.get_color(ts_palettes[hPalette - 1][i].r, ts_palettes[hPalette - 1][i].g, ts_palettes[hPalette - 1][i].b); + } + transp_conv_color[hPalette - 1] = conv.get_color(245, 245, 245); + } + +} + + +namespace FSunPackLib +{ + std::wstring utf8ToUtf16(const std::string& utf8) + { + // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32 + if (utf8.size() == 0) + // MultiByteToWideChar does not support passing in cbMultiByte == 0 + return L""; + + // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1) + auto utf8Count = utf8.size(); + auto unterminatedCountWChars = MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8.data(), utf8Count, nullptr, 0); + if (unterminatedCountWChars == 0) + { + throw std::runtime_error("UTF8 -> UTF16 conversion failed"); + } + + std::wstring utf16; + utf16.resize(unterminatedCountWChars); + if (MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8.data(), utf8Count, utf16.data(), unterminatedCountWChars) == 0) + { + throw std::runtime_error("UTF8 -> UTF16 conversion failed"); + } + return utf16; + } + + // XCC uses CreateFileA to load files which does not support UTF8 filenames if you don't opt in through the app manifest (and that's only possible on Win10 1903+) + // so provide some helpers that open the file through Cwin_handle with CreateFileW instead: + + template<class F> + int open_write(F& file, const std::string& u8FilePath) + { + try + { + auto u16FilePath = utf8ToUtf16(u8FilePath); + Cwin_handle target_file_handle(CreateFileW(u16FilePath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); + if (target_file_handle) + return file.open(target_file_handle); + } + catch (std::runtime_error) + { + return 2; + } + return 1; + } + + template<class F> + int open_read(F& file, const std::string& u8FilePath) + { + try + { + auto u16FilePath = utf8ToUtf16(u8FilePath); + Cwin_handle target_file_handle(CreateFileW(u16FilePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + if (target_file_handle) + return file.open(target_file_handle); + } + catch (std::runtime_error) + { + return 2; + } + return 1; + } + + extern "C" bool _DEBUG_EnableLogs = 0; // only useable in debug library builds + extern "C" bool _DEBUG_EnableBreakpoints = 0; // only useable in debug library builds + + extern "C" int last_succeeded_operation = 0; + + + BYTE* EncodeBase64(BYTE* sp, UINT len) + { + auto encoded = encode64(data_ref(sp, std::size_t(len))); + // for now make a copy, we might refactor this + auto copy = new BYTE[encoded.size() + 1]; + copy[encoded.size()] = 0; // null terminate + memcpy(copy, encoded.data(), encoded.size()); + return copy; + } + + // dest should be at least as large as sp + INT ConvertToF80(BYTE* sp, UINT len, BYTE* dest) + { + return encode80(sp, dest, len); + } + + + + INT EncodeF80(BYTE* sp, UINT len, UINT nSections, BYTE** dest) + { + *dest = new(BYTE[len * 4]); // as large as sp, to make sure it works + + BYTE* data = *dest; + + int length = len / nSections; + // each section has this length + +#ifdef DBG2 + int sections = 0; + AllocConsole(); + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); + char tmp[50]; + string out; + out = "PackData() called\n------------\n\n"; + DWORD dw; + WriteFile(hOut, out.data(), out.size(), &dw, NULL); +#endif + + UINT i; + UINT DP = 0; + UINT SP = 0; + for (i = 0;i < nSections;i++) + { + UINT packLen = encode80(&sp[SP], &data[DP + 4], length); //ConvertToF80(&sp[SP], length, &data[DP+4]); + + memcpy(&data[DP], &packLen, 3); + DP += 3; + data[DP] = 0x20; + DP++; + SP += length; + DP += packLen; + +#ifdef DBG2 + itoa(i, tmp, 10); + out = "\nHandled section "; + out += tmp; + out += ", packed length: "; + itoa(packLen, tmp, 10); + out += tmp; + out += " bytes, DP="; + itoa(DP, tmp, 10); + out += tmp; + out += "\n"; + WriteFile(hOut, out.data(), out.size(), &dw, NULL); + + ReadFile(hIn, tmp, 2, &dw, NULL); +#endif + + } + + + + return DP; + } + + UINT EncodeIsoMapPack5(BYTE* sp, UINT SourceLength, BYTE** dp) + { + *dp = new(BYTE[SourceLength * 2]); // as big as source, makes sure it works! + + UINT DP = encode5(sp, *dp, SourceLength, 5); + + return DP; + } + + bool DecodeF80(const BYTE* const sp, const UINT SourceLength, std::vector<BYTE>& dp, const std::size_t max_size) + { + static_assert(4 == sizeof(t_pack_section_header)); + + const auto spEnd = sp + SourceLength; + const t_pack_section_header* secHeader = nullptr; + size_t totalSize = 0; + for (auto curSP = sp; curSP < sp + SourceLength;) + { + secHeader = (reinterpret_cast<const t_pack_section_header*>(curSP)); + curSP += secHeader->size_in + sizeof(t_pack_section_header); + totalSize += secHeader->size_out; + } + if (totalSize > max_size) + { + return false; + } + + dp.resize(totalSize); + decode5(sp, dp.data(), SourceLength, 80); + return true; + } + + int DecodeBase64(const char* sp, std::vector<BYTE>& dest) + { + auto len = strlen(reinterpret_cast<const char*>(sp)); + auto res = decode64(data_ref(sp, len)); + dest.assign(res.data(), res.data() + res.size()); + return res.size(); + } + + UINT DecodeIsoMapPack5(BYTE* sp, UINT SourceLength, BYTE* dp, HWND hProgressBar, BOOL bDebugMode) + { + + //if(bDebugMode) k.open("c:\\decode.txt", ios_base::out | ios_base::trunc); + + //if(hProgressBar) SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, SourceLength)); + //if(hProgressBar) UpdateWindow(hProgressBar); + + UINT SP = 0; + UINT DP = 0; + + while (SP < SourceLength) + { + WORD wSrcSize; + WORD wExtrSize; + memcpy(&wSrcSize, sp + SP, 2); + SP += 2; + memcpy(&wExtrSize, sp + SP, 2); + SP += 2; + + decode5s(sp + SP, dp + DP, wSrcSize); + + SP += wSrcSize; + DP += wExtrSize; + + //if(hProgressBar) SendMessage(hProgressBar, PBM_SETPOS, (WPARAM) SP, 0); + //if(hProgressBar) UpdateWindow(hProgressBar); + } + + return DP; + } + + std::int32_t GetFirstPixelColor(IDirectDrawSurface4* pDDS) + { + std::int32_t color = 0; + + DDSURFACEDESC2 desc = { 0 }; + desc.dwSize = sizeof(DDSURFACEDESC2); + + if (pDDS->Lock(nullptr, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, nullptr) != DD_OK) + return color; + if (desc.lpSurface == nullptr) + { + pDDS->Unlock(nullptr); + return color; + } + else + { + auto bytes_per_pixel = (desc.ddpfPixelFormat.dwRGBBitCount + 7) / 8; + memcpy(&color, desc.lpSurface, bytes_per_pixel > 4 ? 4 : bytes_per_pixel); + pDDS->Unlock(nullptr); + + return color; + } + + } + + HRESULT SetColorKey(IDirectDrawSurface4* pDDS, COLORREF rgb) + { + DDPIXELFORMAT pf = { 0 }; + pf.dwSize = sizeof(DDPIXELFORMAT); + pDDS->GetPixelFormat(&pf); + + ColorConverter c(pf); + auto col = rgb == CLR_INVALID ? GetFirstPixelColor(pDDS) : c.GetColor(rgb); + DDCOLORKEY color_key = { static_cast<DWORD>(col), static_cast<DWORD>(col) }; + return pDDS->SetColorKey(DDCKEY_SRCBLT, &color_key); + } + + BOOL XCC_Initialize(BOOL bLoadFromRegistry) + { + if (bLoadFromRegistry) + xcc_dirs::load_from_registry(); + + return TRUE; + } + + HMIXFILE XCC_OpenMix(LPCTSTR szMixFile, HMIXFILE hOwner) + { + DWORD i, d = 0xFFFFFFFF; + for (i = 0;i <= dwMixFileCount && i < 2000;i++) + { + if (mixfiles[i].is_open() == false) + { + d = i; + break; + } + } + if (d == 0xFFFFFFFF) + return NULL; + + std::string sMixFile = szMixFile; + + if (hOwner == NULL) + { + if (open_read(mixfiles[d], sMixFile)) + return NULL; + //mixfiles[dwMixFileCount].enable_mix_expansion(); + mixfiles_names[d] = szMixFile; + if (d == dwMixFileCount) + dwMixFileCount++; + + return d + 1;//dwMixFileCount; + } + else if (hOwner > 0 && (hOwner - 1) < dwMixFileCount) + { + if (szMixFile[0] == L'_' && szMixFile[1] == L'I' && szMixFile[2] == L'D') + { + char id[256]; + strcpy_s(id, &sMixFile[3]); + int iId = atoi(id); + if (mixfiles[d].open(iId, mixfiles[hOwner - 1])) return NULL; + } + else + { + if (mixfiles[d].open(sMixFile, mixfiles[hOwner - 1])) + return NULL; + } + + mixfiles_names[d] = szMixFile; + if (d == dwMixFileCount) + dwMixFileCount++; + return d + 1; + } + + return NULL; + } + + BOOL XCC_GetMixName(HMIXFILE hOwner, std::string& sMixFile) + { + if (hOwner == 0) + return FALSE; + if (hOwner > dwMixFileCount) + return FALSE; + + sMixFile = mixfiles_names[hOwner - 1]; + return TRUE; + } + + BOOL XCC_DoesFileExist(LPCSTR szFile, HMIXFILE hOwner) + { + if (hOwner == 0) + return FALSE; + if (hOwner > dwMixFileCount) + return FALSE; + + t_game game = mixfiles[hOwner - 1].get_game(); + + + int id = mixfiles[hOwner - 1].get_id(game, szFile); + + if (mixfiles[hOwner - 1].get_index(id) < 0) + return FALSE; + + return TRUE; + } + + BOOL XCC_CloseMix(HMIXFILE hMixFile) + { + if (hMixFile<1 || hMixFile>dwMixFileCount) + return FALSE; + + hMixFile--; // -1 to make it to an array index + + mixfiles_names[hMixFile].clear(); + + if (mixfiles[hMixFile].is_open()) mixfiles[hMixFile].close(); + else + return FALSE; + + return TRUE; + } + + BOOL XCC_ExtractFile(const std::string& szFilename, const std::string& szSaveTo, HMIXFILE hOwner) + { + if (hOwner == NULL) + return FALSE; // not supported yet + + hOwner--; // -1 to make it to an array index + + if (hOwner >= dwMixFileCount) + return FALSE; + + if (!mixfiles[hOwner].is_open()) + return FALSE; + + Ccc_file file(true); + + if (szFilename[0] == '_' && szFilename[1] == 'I' && szFilename[2] == 'D') + { + char id[256]; + strcpy_s(id, &szFilename[3]); + int iId = atoi(id); + if (file.open(iId, mixfiles[hOwner])) + return NULL; + } + else + { + if (file.open(szFilename, mixfiles[hOwner]) != 0) + return FALSE; + } + + + Cfile32 target_file; + if (open_write(target_file, szSaveTo)) + return FALSE; + + const int bufferSize = static_cast<int>(min(file.get_size(), 1024 * 1024)); + std::vector<byte> buffer(bufferSize); + for (auto p = 0; p < file.get_size();) + { + const auto toRead = static_cast<int>(min(file.get_size() - p, bufferSize)); + if (file.read(buffer.data(), toRead)) + return FALSE; + if (target_file.write(buffer.data(), toRead)) + return FALSE; + p += toRead; + } + + return TRUE; + } + + BOOL XCC_ExtractFile(LPCSTR szFilename, LPCSTR szSaveTo, HMIXFILE hOwner) + { + return XCC_ExtractFile(std::string(szFilename), std::string(szSaveTo), hOwner); + } + + + + BOOL XCC_GetSHPHeader(SHPHEADER* pHeader) + { + if (pHeader == NULL) + return FALSE; + + if (!cur_shp.is_open()) + return FALSE; + + auto& head = cur_shp.header(); + memcpy(pHeader, &head, sizeof(SHPHEADER)); + + + return TRUE; + } + + /* + Returns the SHP image header of a image in a SHP file + */ + BOOL XCC_GetSHPImageHeader(int iImageIndex, SHPIMAGEHEADER* pImageHeader) + { + t_shp_ts_image_header imagehead; + + if (pImageHeader == NULL || iImageIndex < 0) + return FALSE; + + + if (!cur_shp.is_open()) + return FALSE; + + auto& head = cur_shp.header(); + + if (iImageIndex >= head.c_images) + return FALSE; + + imagehead = *cur_shp.get_image_header(iImageIndex); + + memcpy(pImageHeader, &imagehead, sizeof(SHPIMAGEHEADER)); + + return TRUE; + } + + + + BOOL SetCurrentTMP(LPCSTR szTMP, HMIXFILE hOwner) + { + if (cur_tmp.is_open()) + cur_tmp.close(); + + if (hOwner == NULL) + { + if (open_read(cur_tmp, szTMP)) + return FALSE; + } + else + { + if (cur_tmp.open(szTMP, mixfiles[hOwner - 1])) + return FALSE; + } + + //if(cur_tmp.get_data()==NULL) return FALSE; + //if(!cur_tmp.is_valid()) return FALSE; + + return TRUE; + }; + + BOOL SetCurrentSHP(LPCSTR szSHP, HMIXFILE hOwner) + { + if (cur_shp.is_open()) cur_shp.close(); + + if (hOwner == NULL) + { + if (open_read(cur_shp, szSHP) != 0) + { + return FALSE; + } + } + else + { + int id = mixfiles[hOwner - 1].get_id(mixfiles[hOwner - 1].get_game(), szSHP); + int size = mixfiles[hOwner - 1].get_size(id); + if (size == 0) + OutputDebugString("NULL size"); + BYTE* b = new(BYTE[size]); + mixfiles[hOwner - 1].seek(mixfiles[hOwner - 1].get_offset(id)); + mixfiles[hOwner - 1].read(b, size); + cur_shp.load(Cvirtual_binary(b, size)); + } + + return TRUE; + }; + + BOOL XCC_GetTMPTileInfo(int iTile, POINT* lpPos, int* lpWidth, int* lpHeight, BYTE* lpDirection, BYTE* lpTileHeight, BYTE* lpTileType, RGBTRIPLE* lpRgbLeft, RGBTRIPLE* lpRgbRight) + { + if (!cur_tmp.is_open()) return FALSE; + if (iTile >= cur_tmp.get_c_tiles() || iTile < 0) return FALSE; + + t_tmp_image_header ihead = *cur_tmp.get_image_header(iTile); + if (lpDirection) + *lpDirection = ihead.ramp_type; + if (lpTileHeight) + *lpTileHeight = ihead.height; + if (lpTileType) + *lpTileType = ihead.terrain_type; + + if (lpRgbLeft) + { + lpRgbLeft->rgbtRed = ihead.radar_red_left; + lpRgbLeft->rgbtGreen = ihead.radar_green_left; + lpRgbLeft->rgbtBlue = ihead.radar_blue_left; + } + + if (lpRgbRight) + { + lpRgbRight->rgbtRed = ihead.radar_red_right; + lpRgbRight->rgbtGreen = ihead.radar_green_right; + lpRgbRight->rgbtBlue = ihead.radar_blue_right; + } + + int cx = cur_tmp.get_cx(); + int cy = cur_tmp.get_cy(); + if (cur_tmp.has_extra_graphics(iTile)) + { + int cy_extra = cur_tmp.get_cy_extra(iTile); + int y_extra = cur_tmp.get_y_extra(iTile) - cur_tmp.get_y(iTile); + int cx_extra = cur_tmp.get_cx_extra(iTile); + int x_extra = cur_tmp.get_x_extra(iTile) - cur_tmp.get_x(iTile); + int y_added = 0;//cur_tmp.get_x(iTile); + int x_added = 0;//cur_tmp.get_y(iTile); + + if (y_extra < 0) + { + y_added -= y_extra; + cy -= y_extra; + y_extra = 0; + + } + if (x_extra < 0) + { + x_added -= x_extra; + cx -= x_extra; + x_extra = 0; + } + + + if (cy_extra + y_extra > cy) cy = cy_extra + y_extra; + if (cx_extra + x_extra > cx) cx = cx_extra + x_extra; + + if (lpPos != NULL) + { + //int xTile, yTile; + //xTile=iTile%cur_tmp.get_cblocks_x(); + //yTile=iTile/cur_tmp.get_cblocks_x(); + + //lpPos->x=-x_added; + //lpPos->y=-y_added; + lpPos->x =/*cur_tmp.get_x(iTile)-(24*xTile-24*yTile)*/-x_added; + lpPos->y =/*cur_tmp.get_y(iTile)-(12*yTile+12*xTile)*/-y_added; + } + if (lpWidth != NULL) *lpWidth = cx; + if (lpHeight != NULL) *lpHeight = cy; + + } + else + { + if (lpPos != NULL) + { + lpPos->x = 0;//cur_tmp.get_x(iTile);; + lpPos->y = 0;//cur_tmp.get_y(iTile); + } + if (lpHeight != NULL) *lpHeight = cur_tmp.get_cy(); + if (lpWidth != NULL) *lpWidth = cur_tmp.get_cx(); + } + + return TRUE; + } + + BOOL XCC_GetTMPInfo(RECT* lpRect, int* iTileCount, int* iTilesX, int* iTilesY) + { + + // if(!cur_tmp.is_open()) return FALSE; + + int x, y, cx, cy; + cur_tmp.get_rect(x, y, cx, cy); + if (lpRect != NULL) + { + lpRect->left = x; + lpRect->top = y; + lpRect->right = x + cx; + lpRect->bottom = y + cy; + } + + if (iTileCount != NULL) *iTileCount = cur_tmp.get_c_tiles(); + if (iTilesX != NULL) *iTilesX = cur_tmp.get_cblocks_y(); + if (iTilesY != NULL) *iTilesY = cur_tmp.get_cblocks_x(); + + + + return TRUE; + } + + + BOOL LoadSHPImageInSurface(IDirectDraw4* pdd, HTSPALETTE hPalette, int iImageIndex, int iCount, LPDIRECTDRAWSURFACE4* pdds) + { + RGBTRIPLE rgb_transp; + t_shp_ts_image_header imghead; + DDSURFACEDESC2 ddsd; + BYTE* image; + + + if (hPalette == NULL || hPalette > dwPalCount) return NULL; + + + auto& head = cur_shp.header(); + + if (head.cx == 0 || head.cy == 0) + { + return FALSE; + } + + + rgb_transp.rgbtRed = 245; + rgb_transp.rgbtGreen = 245; + rgb_transp.rgbtBlue = 245; + + + + int pic; + std::vector<byte> decode_image_buffer; + for (pic = 0;pic < iCount;pic++) + { + if (cur_shp.get_image_header(iImageIndex + pic)) + { + imghead = *(cur_shp.get_image_header(iImageIndex + pic)); + // if(imghead.offset!=0) + { + + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwWidth = head.cx; + ddsd.dwHeight = head.cy; + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH /*| DDSD_PIXELFORMAT*/; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + + if (pdd->CreateSurface(&ddsd, &pdds[pic], NULL) != DD_OK) + return NULL; + + ddsd.dwFlags = DDSD_PITCH; + pdds[pic]->GetSurfaceDesc(&ddsd); + long pitch = ddsd.lPitch; + + DDPIXELFORMAT pf; + memset(&pf, 0, sizeof(DDPIXELFORMAT)); + pf.dwSize = sizeof(DDPIXELFORMAT); + + pdds[pic]->GetPixelFormat(&pf); + + + if (cur_shp.is_compressed(iImageIndex + pic)) + { + decode_image_buffer.resize(imghead.cx * imghead.cy); + image = decode_image_buffer.data(); + decode3(cur_shp.get_image(iImageIndex + pic), image, imghead.cx, imghead.cy); + } + else + image = (unsigned char*)cur_shp.get_image(iImageIndex + pic); + + + if ((pf.dwFlags & DDPF_RGB) && pf.dwRBitMask && pf.dwGBitMask && pf.dwBBitMask) + { + + CreateConvLookUpTable(pf, hPalette); + + if (pdds[pic]->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL) == DD_OK) + { + + BYTE* dest = (BYTE*)ddsd.lpSurface; + pitch = ddsd.lPitch; + + int bytesize = (pf.dwRGBBitCount + 1) / 8; + if (bytesize < 1) bytesize = 1; + + if (pf.dwRGBBitCount <= 8) bytesize = 1; + else if (pf.dwRGBBitCount <= 16) bytesize = 2; + else if (pf.dwRGBBitCount <= 24) bytesize = 3; + else if (pf.dwRGBBitCount <= 32) bytesize = 4; + + if (dest) + { + int i, e; + for (i = 0; i < head.cx; i++) + { + for (e = 0;e < head.cy;e++) + { + DWORD dwRead = 0xFFFFFFFF; + DWORD dwWrite = i * bytesize + e * pitch; + + if (i >= imghead.x && e >= imghead.y && i < imghead.x + imghead.cx && e < imghead.y + imghead.cy) + dwRead = (i - imghead.x) + (e - imghead.y) * imghead.cx; + + if (dwRead != 0xFFFFFFFF && image[dwRead] != 0) + { + DWORD col = conv_color[hPalette - 1][image[dwRead]]; + memcpy(&dest[dwWrite], &col, bytesize); + } + else + { + DWORD col = transp_conv_color[hPalette - 1]; + memcpy(&dest[dwWrite], &col, bytesize); + } + + } + } + } + pdds[pic]->Unlock(NULL); + } + + } + else + { + HDC hDC; + while (pdds[pic]->GetDC(&hDC) == DDERR_WASSTILLDRAWING); + { + int i, e; + for (i = 0; i < head.cx; i++) + { + for (e = 0;e < head.cy;e++) + { + DWORD dwRead = 0xFFFFFFFF; + //DWORD dwWrite=i*bytesize+e*pitch; + + if (i >= imghead.x && e >= imghead.y && i < imghead.x + imghead.cx && e < imghead.y + imghead.cy) + dwRead = (i - imghead.x) + (e - imghead.y) * imghead.cx; + + if (dwRead != 0xFFFFFFFF && image[dwRead] != 0) + { + t_palet_entry& p = ts_palettes[hPalette - 1][image[dwRead]]; + SetPixel(hDC, i, e, RGB(p.r, p.g, p.b)); + } + else + { + SetPixel(hDC, i, e, RGB(245, 245, 245)); + } + + } + } + + } + + pdds[pic]->ReleaseDC(hDC); + + } + + SetColorKey(pdds[pic], -1); + + } + } + } + + return TRUE; + + } + + BOOL LoadSHPImage(int iImageIndex, std::vector<BYTE>& pic) + { + t_shp_ts_image_header imghead; + BYTE* image = NULL; + + + + + auto& head = cur_shp.header(); + if (head.cx == 0 || head.cy == 0) + { + return FALSE; + } + + + std::vector<byte> decode_image_buffer; + if (cur_shp.get_image_header(iImageIndex)) + { + imghead = *(cur_shp.get_image_header(iImageIndex)); + // if(imghead.offset!=0) + { + + if (cur_shp.is_compressed(iImageIndex)) + { + decode_image_buffer.resize(imghead.cx * imghead.cy); + image = decode_image_buffer.data(); + decode3(cur_shp.get_image(iImageIndex), image, imghead.cx, imghead.cy); + } + else + image = (unsigned char*)cur_shp.get_image(iImageIndex); + + + pic.resize(head.cx * head.cy); + + int i, e; + for (i = 0; i < head.cx; i++) + { + for (e = 0;e < head.cy;e++) + { + DWORD dwRead = 0xFFFFFFFF; + DWORD dwWrite = i + e * head.cx; + + if (i >= imghead.x && e >= imghead.y && i < imghead.x + imghead.cx && e < imghead.y + imghead.cy) + dwRead = (i - imghead.x) + (e - imghead.y) * imghead.cx; + + if (dwRead != 0xFFFFFFFF) + { + pic[dwWrite] = image[dwRead]; + } + else + pic[dwWrite] = 0; + + } + + } + + } + } + + return TRUE; + + } + + BOOL LoadSHPImage(int iImageIndex, int iCount, BYTE** lpPics) + { + t_shp_ts_image_header imghead; + BYTE* image = NULL; + + + + + auto& head = cur_shp.header(); + if (head.cx == 0 || head.cy == 0) + { + return FALSE; + } + + + + + int pic; + std::vector<byte> decode_image_buffer; + for (pic = 0;pic < iCount;pic++) + { + if (cur_shp.get_image_header(iImageIndex + pic)) + { + imghead = *(cur_shp.get_image_header(iImageIndex + pic)); + // if(imghead.offset!=0) + { + + if (cur_shp.is_compressed(iImageIndex + pic)) + { + decode_image_buffer.resize(imghead.cx * imghead.cy); + image = decode_image_buffer.data(); + decode3(cur_shp.get_image(iImageIndex + pic), image, imghead.cx, imghead.cy); + } + else + image = (unsigned char*)cur_shp.get_image(iImageIndex + pic); + + + lpPics[pic] = new(BYTE[head.cx * head.cy]); + + int i, e; + for (i = 0; i < head.cx; i++) + { + for (e = 0;e < head.cy;e++) + { + DWORD dwRead = 0xFFFFFFFF; + DWORD dwWrite = i + e * head.cx; + + if (i >= imghead.x && e >= imghead.y && i < imghead.x + imghead.cx && e < imghead.y + imghead.cy) + dwRead = (i - imghead.x) + (e - imghead.y) * imghead.cx; + + if (dwRead != 0xFFFFFFFF) + { + lpPics[pic][dwWrite] = image[dwRead]; + } + else + lpPics[pic][dwWrite] = 0; + + } + + } + + } + } + } + + + + return TRUE; + + } + + void tmp_ts_draw(Ctmp_ts_file& f, byte* d, int i) + { + int tile_cx, tile_cy; + int skip_x; + int skip_y; + + + tile_cx = f.get_cx(); + tile_cy = f.get_cy(); + int std_cx = tile_cx; + int std_cy = tile_cy; + int cy_extra = 0; + int y_extra = 0; + int cx_extra = 0; + int x_extra = 0; + int y_added = 0; + int x_added = 0; + + + if (f.has_extra_graphics(i)) + { + cy_extra = f.get_cy_extra(i); + y_extra = f.get_y_extra(i) - f.get_y(i); + cx_extra = f.get_cx_extra(i); + x_extra = f.get_x_extra(i) - f.get_x(i); + + if (y_extra < 0) + { + y_added = -y_extra; + tile_cy -= y_extra; + y_extra = 0; + } + if (x_extra < 0) + { + x_added = -x_extra; + tile_cx -= x_extra; + x_extra = 0; + } + + if (cy_extra + y_extra > tile_cy) tile_cy = cy_extra + y_extra; + if (cx_extra + x_extra > tile_cx) tile_cx = cx_extra + x_extra; + } + + memset(d, 0, tile_cx * tile_cy); + + const byte* r = f.get_image(i); + + + + byte* w_line = d; + if (f.has_extra_graphics(i)) + w_line = d + tile_cx * y_added + x_added; + + + int x = f.header().cx / 2; + int cx = 0; + int y; + for (y = 0; y < f.header().cy / 2; y++) + { + cx += 4; + x -= 2; + if (w_line + x < d + tile_cx * tile_cy) + memcpy(w_line + x, r, cx); + r += cx; + w_line += tile_cx; + } + for (; y < f.header().cy - 1; y++) + { + cx -= 4; + x += 2; + if (w_line + x < d + tile_cx * tile_cy) + memcpy(w_line + x, r, cx); + r += cx; + w_line += tile_cx; + } + + + if (f.has_extra_graphics(i)) + { + r += std_cx * std_cy / 2; + + w_line = d; + + skip_x = 0; + skip_y = 0; + + int cx, cy; + if (x_extra < 0) + { + cx = cx_extra; + } + else + { + cx = cx_extra; + w_line += x_extra; + } + if (y_extra < 0) + { + cy = cy_extra; + } + else + { + cy = cy_extra; + w_line += y_extra * (tile_cx); + } + + for (y = 0; y < cy - skip_y; y++) + { + byte* w = w_line; + for (int x = 0; x < cx - skip_x; x++) + { + int v = *r++; + if (v) + *w = v; + + + w++; + } + w_line += tile_cx; + } + + } + } + + + BOOL LoadTMPImageInSurface(IDirectDraw4* pdd, int iStart, int iCount, LPDIRECTDRAWSURFACE4* pdds, HTSPALETTE hPalette) + { + last_succeeded_operation = 2100; + + + + DDSURFACEDESC2 ddsd; + RGBTRIPLE rgb_transp; + + if (hPalette == NULL || hPalette > dwPalCount) return NULL; + + rgb_transp.rgbtRed = 245; + rgb_transp.rgbtGreen = 245; + rgb_transp.rgbtBlue = 245; + + + int pic; + for (pic = 0;pic < iCount;pic++) + { + int cx, cy; + int z = pic + iStart; + + + if (!cur_tmp.get_index()[z]) + { + + pdds[pic] = NULL; + } + else + { + + + + XCC_GetTMPTileInfo(z, NULL, &cx, &cy, NULL, NULL, NULL, NULL, NULL); + + + if (cx > 0 && cy > 0) + { + //const byte* r = cur_tmp.get_image(iStart+pic); //new byte[cx * cy]; + // byte transp=r[0]; + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwWidth = cx; + ddsd.dwHeight = cy; + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH /*| DDSD_PIXELFORMAT*/; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + + byte* image = NULL; + if (pdd->CreateSurface(&ddsd, &pdds[pic], NULL) == DD_OK) + { + + + last_succeeded_operation = 2101; + + DDPIXELFORMAT pf; + memset(&pf, 0, sizeof(DDPIXELFORMAT)); + pf.dwSize = sizeof(DDPIXELFORMAT); + pdds[pic]->GetPixelFormat(&pf); + + BOOL bFastLoaded = FALSE; + + if ((pf.dwFlags & DDPF_RGB) && pf.dwRBitMask && pf.dwGBitMask && pf.dwBBitMask) + { + + last_succeeded_operation = 21011; + + CreateConvLookUpTable(pf, hPalette); + int i, e; + + + + + image = new byte[cx * cy]; + tmp_ts_draw(cur_tmp, image, iStart + pic); + int bytesize = 1;//(pf.dwRGBBitCount+1)/8; + if (pf.dwRGBBitCount <= 8) bytesize = 1; + else if (pf.dwRGBBitCount <= 16) bytesize = 2; + else if (pf.dwRGBBitCount <= 24) bytesize = 3; + else if (pf.dwRGBBitCount <= 32) bytesize = 4; + if (bytesize < 1) bytesize = 1; + + last_succeeded_operation = 21012; + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_PITCH | DDSD_LPSURFACE; + + RECT lockr; + lockr.left = 0; + lockr.top = 0; + lockr.right = cx; + lockr.bottom = cy; + + if (pdds[pic]->Lock(&lockr, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL) == DD_OK) + { + last_succeeded_operation = 21013; + + + BYTE* dest = (BYTE*)ddsd.lpSurface; + int pitch = ddsd.lPitch; + + + if (ddsd.dwFlags & DDSD_PIXELFORMAT) + { + + + // pixel format overwritten + CreateConvLookUpTable(ddsd.ddpfPixelFormat, hPalette); + + int bytesize = 1;//(pf.dwRGBBitCount+1)/8; + if (ddsd.ddpfPixelFormat.dwRGBBitCount <= 8) bytesize = 1; + else if (ddsd.ddpfPixelFormat.dwRGBBitCount <= 16) bytesize = 2; + else if (ddsd.ddpfPixelFormat.dwRGBBitCount <= 24) bytesize = 3; + else if (ddsd.ddpfPixelFormat.dwRGBBitCount <= 32) bytesize = 4; + if (bytesize < 1) bytesize = 1; + + + } + + if (ddsd.dwFlags & DDSD_LINEARSIZE) + { + pitch = ddsd.dwLinearSize / cy; + } + + + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; + + pdds[pic]->GetSurfaceDesc(&ddsd); + + + + last_succeeded_operation = 21016; + + if (dest && !IsBadWritePtr(dest, pitch * cy)) // TODO: debug this case when using surfaces + { + + bFastLoaded = TRUE; + + for (i = 0; i < cx; i++) + { + for (e = 0;e < cy;e++) + { + DWORD dwWrite = i * bytesize + e * pitch; + DWORD dwRead = i + e * cx; + + if (image[dwRead] != 0) + { + DWORD col = conv_color[hPalette - 1][image[dwRead]]; + memcpy(&dest[dwWrite], &col, bytesize); + } + else + { + DWORD col = transp_conv_color[hPalette - 1]; + memcpy(&dest[dwWrite], &col, bytesize); + } + + } + } + + } + + + + + pdds[pic]->Unlock(&lockr); + + + + last_succeeded_operation = 21014; + + + + } + + last_succeeded_operation = 21015; + + DDCOLORKEY ddck; + ddck.dwColorSpaceLowValue = transp_conv_color[hPalette - 1]; + ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue; + pdds[pic]->SetColorKey(DDCKEY_SRCBLT, &ddck); + } + + if (!bFastLoaded) // use GDI + { + int i, e; + image = new byte[cx * cy]; + tmp_ts_draw(cur_tmp, image, iStart + pic); + HDC hDC; + while (pdds[pic]->GetDC(&hDC) == DDERR_WASSTILLDRAWING) {}; + + for (i = 0; i < cx; i++) + { + for (e = 0;e < cy;e++) + { + DWORD dwRead = i + e * cx; + + if (image[dwRead] != 0) + { + t_palet_entry& p = ts_palettes[hPalette - 1][image[dwRead]]; + SetPixel(hDC, i, e, RGB(p.r, p.g, p.b)); + } + else + { + SetPixel(hDC, i, e, RGB(245, 245, 245)); + } + + } + } + + pdds[pic]->ReleaseDC(hDC); + SetColorKey(pdds[pic], RGB(245, 245, 245)); + + } + } + + if (image) delete[] image; + image = NULL; + + + } + } + } + + return TRUE; + } + + + BOOL LoadTMPImage(int iStart, int iCount, BYTE** lpTileArray) + { + last_succeeded_operation = 2100; + + + int pic; + for (pic = 0;pic < iCount;pic++) + { + int cx, cy; + int z = pic + iStart; + + + if (!cur_tmp.get_index()[z]) + { + + lpTileArray[pic] = NULL; + } + else + { + + XCC_GetTMPTileInfo(z, NULL, &cx, &cy, NULL, NULL, NULL, NULL, NULL); + + + if (cx > 0 && cy > 0) + { + byte* image = NULL; + + + last_succeeded_operation = 2101; + + image = new byte[cx * cy]; + tmp_ts_draw(cur_tmp, image, iStart + pic); + + lpTileArray[pic] = image; + + image = NULL; + } + } + } + + return TRUE; + } + + + + + + Cvxl_file cur_vxl; + Chva_file cur_hva; + + t_palet32bgr_entry color_table[256]; + + void load_color_table(const t_palet palet, bool convert_palet) + { + t_palet p; + + memcpy(p, palet, sizeof(t_palet)); + if (convert_palet) + convert_palet_18_to_24(p); + + for (long i = 0; i < 256; i++) + { + color_table[i].r = p[i].r; + color_table[i].g = p[i].g; + color_table[i].b = p[i].b; + } + } + + /*struct t_vector + { + double x; + double y; + double z; + };*/ + + const double pi = 3.141592654; + + template<class T> + __forceinline void rotate_x(Vec3<T>& v, T a) + { + T l = sqrt(v.y() * v.y() + v.z() * v.z()); + T d_a = atan2(v.y(), v.z()) + a; + v[1] = l * sin(d_a); + v[2] = l * cos(d_a); + } + + template<class T> + __forceinline void rotate_y(Vec3<T>& v, T a) + { + T l = sqrt(v.x() * v.x() + v.z() * v.z()); + T d_a = atan2(v.x(), v.z()) + a; + v[0] = l * sin(d_a); + v[2] = l * cos(d_a); + } + + template<class T> + __forceinline void rotate_z(Vec3<T>& v, T a) + { + T l = sqrt(v.x() * v.x() + v.y() * v.y()); + T d_a = atan2(v.x(), v.y()) + a; + v[0] = l * sin(d_a); + v[1] = l * cos(d_a);; + } + + template<class T> + __forceinline void rotate_zxy(Vec3<T>& v, const Vec3<T>& r) + { + rotate_z(v, r.z()); + rotate_x(v, r.x()); + rotate_y(v, r.y()); + } + + BOOL SetCurrentVXL(LPCSTR lpVXLFile, HMIXFILE hMixFile) + { + last_succeeded_operation = 500; + + if (cur_vxl.is_open()) cur_vxl.close(); + if (cur_hva.is_open()) cur_hva.close(); + + auto HVA = std::string(lpVXLFile); + std::transform(HVA.begin(), HVA.end(), HVA.begin(), [](unsigned char c) { return std::tolower(c); }); + HVA = std::regex_replace(HVA, std::regex(".vxl$"), ".hva"); + + if (hMixFile == NULL) + { + if (open_read(cur_vxl, lpVXLFile)) + return FALSE; + if (open_read(cur_hva, HVA)) + return FALSE; + } + else + { + if (cur_vxl.open(lpVXLFile, mixfiles[hMixFile - 1])) + return FALSE; + if (cur_hva.open(HVA, mixfiles[hMixFile - 1])) + return FALSE; + } + + if (!cur_vxl.is_open()) + return FALSE; + if (!cur_hva.is_open()) + return FALSE; + + return TRUE; + } + + BOOL GetVXLInfo(int* cSections) + { + if (!cur_vxl.is_open()) + return FALSE; + + if (cSections) *cSections = cur_vxl.get_c_section_headers(); + + return TRUE; + } + + BOOL GetVXLSectionInfo(int section, VoxelNormalClass& normalClass) + { + if (!cur_vxl.is_open()) + return FALSE; + if (section >= cur_vxl.get_c_section_headers()) + return FALSE; + + switch (cur_vxl.get_section_tailer(section)->unknown) + { + case 1: + normalClass = VoxelNormalClass::Gen1; + break; + case 2: + normalClass = VoxelNormalClass::TS; + break; + case 3: + normalClass = VoxelNormalClass::Gen3; + break; + case 4: + normalClass = VoxelNormalClass::RA2; + break; + default: + normalClass = VoxelNormalClass::Unknown; + } + + return TRUE; + } + + + + + void GetVXLSectionBounds(int iSection, const Vec3f& rotation, const Vec3f& modelOffset, Vec3f& minVec, Vec3f& maxVec) + { + const t_vxl_section_tailer& section_tailer = *cur_vxl.get_section_tailer(iSection); + auto& header = *cur_vxl.get_section_header(iSection); + auto& tailer = *cur_vxl.get_section_tailer(iSection); + //const auto matrix = Matrix3_4f(tailer.transform).scaledColumn(3, tailer.scale); + const auto matrix = Matrix3_4f(cur_hva.get_transform_matrix(0, iSection)).scaledColumn(3, tailer.scale); + maxVec = minVec = Vec3f(section_tailer.x_min_scale, section_tailer.y_min_scale, section_tailer.z_min_scale); + + // get projected coordinates of all bounding box corners + for (int x = 0; x < 2; ++x) + { + for (int y = 0; y < 2; ++y) + { + for (int z = 0; z < 2; ++z) + { + Vec3f cur = matrix * (Vec3f( + x == 0 ? section_tailer.x_min_scale : section_tailer.x_max_scale, + y == 0 ? section_tailer.y_min_scale : section_tailer.y_max_scale, + z == 0 ? section_tailer.z_min_scale : section_tailer.z_max_scale + ) + modelOffset); + rotate_zxy(cur, rotation); + minVec.minimum(cur); + maxVec.maximum(cur); + } + } + } + // for Debug, ensure center is visible +#ifdef _DEBUG + Vec3f cur = matrix * Vec3f(); + rotate_zxy(cur, rotation); + minVec.minimum(cur); + maxVec.maximum(cur); +#endif + } + + + void RenderVXLSection(const VoxelNormalTable& normalTable, Vec3f lightDirection, const int iSection, int rtWidth, int rtHeight, const Vec3f& modelOffset, const Vec3f& rotation, const Vec3f& postHVAOffset, BYTE* image, BYTE* lighting, char* image_z, int* i_center_x, int* i_center_y, int ZAdjust, int* i_center_x_zmax, int* i_center_y_zmax, int i3dCenterX, int i3dCenterY) + { + // normals: + // - positive x is facing screen right + // - positive y is facing screen bottom + // - positive z is facing viewer + const Vec3f inverseLightDirection = negate(normalize(lightDirection)); + + last_succeeded_operation = 10; + + const auto& header = *cur_vxl.get_section_header(iSection); + const auto& tailer = *cur_vxl.get_section_tailer(iSection); + const int cx1 = tailer.cx; + const int cy1 = tailer.cy; + const int cz1 = tailer.cz; + //const Matrix3_4f matrix(tailer.transform); + const Matrix3_4f matrix(cur_hva.get_transform_matrix(0, iSection)); + const Matrix3_4f normalMatrix = Matrix3_4f(matrix).setColumn(3, Vec3f()); + const Matrix3_4f scaledMatrix = matrix.scaleColumn(3, tailer.scale); + const Vec3f minScale = Vec3f(tailer.x_min_scale, tailer.y_min_scale, tailer.z_min_scale) + postHVAOffset; + const Vec3f maxScale = Vec3f(tailer.x_max_scale, tailer.y_max_scale, tailer.z_max_scale) + postHVAOffset; + const Matrix3_4f translateToWorldMatrix = Matrix3_4f::translation(minScale); + const Matrix3_4f scaleToWorldMatrix = Matrix3_4f::scale((maxScale - minScale) / Vec3f(tailer.cx, tailer.cy, tailer.cz)); + + + const float _center_x = 0.0f; //(tailer.x_max_scale + tailer.x_min_scale) / 2.f; + const float _center_y = 0.0f; //(tailer.y_max_scale + tailer.y_min_scale) / 2.f; + const float _center_z = 0.0f; //(tailer.z_max_scale + tailer.z_min_scale) / 2.f; + + if (i3dCenterX < 0) + i3dCenterX = static_cast<int>(_center_x); + if (i3dCenterY < 0) + i3dCenterY = static_cast<int>(_center_y); + + Vec3f center(_center_x, _center_y, _center_z); + + last_succeeded_operation = 11; + // output center 2d coordinates + if (i_center_x || i_center_y) + { + Vec3f s_pixel = center + Vec3f(0.0f, 0.f, 0.0f); + Vec3f d_pixel = scaledMatrix * s_pixel; + + rotate_zxy(d_pixel, rotation); + + d_pixel += modelOffset; + + if (i_center_x) + *i_center_x = static_cast<int>(d_pixel.x() + 0.5f); + if (i_center_y) + *i_center_y = static_cast<int>(d_pixel.y() + 0.5f); + + } + + last_succeeded_operation = 12; + if (i_center_x_zmax || i_center_y_zmax) + { + Vec3f s_pixel = center; + Vec3f d_pixel = scaledMatrix * s_pixel; + + rotate_zxy(d_pixel, rotation); + + d_pixel += modelOffset; + + if (i_center_x_zmax) *i_center_x_zmax = static_cast<int>(d_pixel.x()); + if (i_center_y_zmax) *i_center_y_zmax = static_cast<int>(d_pixel.y()); + + } + + last_succeeded_operation = 13; + + // Vec3f minPixel(1000, 1000, 1000); + int j = 0; + for (int y = 0; y < cy1; y++) + { + for (int x = 0; x < cx1; x++) + { + const byte* r = cur_vxl.get_span_data(iSection, j); + if (r) + { + int z = 0; + int last_z_reported = -5000; + while (z < cz1) + { + z += *r++; + int count = *r++; + while (count--) + { + Vec3f s_pixel = Vec3f(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)); + Vec3f m_pixel = (translateToWorldMatrix * (scaleToWorldMatrix * s_pixel)); + assert(minimum(m_pixel, minScale).equals(minScale, 0.001f)); + assert(maximum(m_pixel, maxScale).equals(maxScale, 0.001f)); + Vec3f t_pixel = scaledMatrix * m_pixel; + Vec3f d_pixel = t_pixel; + + rotate_zxy(d_pixel, rotation); + + d_pixel += modelOffset; + // minPixel.minimum(d_pixel); + + if (x == i3dCenterX && y == i3dCenterY) + { + if (z >= last_z_reported) + { + last_z_reported = z; + if (i_center_x_zmax) *i_center_x_zmax = static_cast<int>(d_pixel.x()); + if (i_center_y_zmax) *i_center_y_zmax = static_cast<int>(d_pixel.y()); + } + } + + + int px = static_cast<int>(d_pixel.x() + 0.5f); + int py = static_cast<int>(d_pixel.y() + 0.5f); + int ofs = px + rtWidth * py; + + if (px >= 0 && py >= 0 && px < rtWidth && py < rtHeight && d_pixel.z() > image_z[ofs]) + { + image[ofs] = *r++; + // lighting calc + auto normalIndex = *r++; + auto normal = (normalMatrix * normalTable[normalIndex]); + rotate_zxy(normal, rotation); + auto normalDotLightingVec = normal.dot(inverseLightDirection); + auto lightVal = normalDotLightingVec < 0.0f ? 0.0f : normalDotLightingVec; + assert(fabs(normal.squaredLength() - 1.0f) < 0.01f); + lighting[ofs] = max(0, static_cast<BYTE>(lightVal * 255.0f)); + image_z[ofs] = static_cast<char>(d_pixel.z()); + } + else + r += 2;; + z++; + } + r++; + } + } + j++; + } + } + + } + + VoxelNormalTable emptyNormalTable; + + BOOL LoadVXLImageInSurface(const VoxelNormalTables& normalTables, Vec3f lightDirection, IDirectDraw4* pdd, int iStart, int iCount, const Vec3f rotation, const Vec3f postHVAOffset, LPDIRECTDRAWSURFACE4* pdds, HTSPALETTE hPalette, int* lpXCenter, int* lpYCenter, int ZAdjust, int* lpXCenterZMax, int* lpYCenterZMax, int i3dCenterX, int i3dCenterY) + { + if (hPalette == NULL || hPalette > dwPalCount) return NULL; + + last_succeeded_operation = 1; + + int i; + int cx_max = 0, cy_max = 0, cz_max = 0; + + Vec3f minCoords(10000, 10000, 10000); + Vec3f maxCoords(-10000, -10000, -10000); + + // Calculate projected bounding box for the virtual render target + int iBodySection = -1; + int iLargestSection = 0; + int iLargestVolume = 0; + for (i = 0; i < cur_vxl.get_c_section_tailers(); i++) + { + const auto& header = cur_vxl.get_section_header(i); + const auto& tailer = cur_vxl.get_section_tailer(i); + Vec3f secMinVec, secMaxVec; + GetVXLSectionBounds(i, rotation, postHVAOffset, secMinVec, secMaxVec); + auto extent = secMaxVec - secMinVec; + auto volume = extent.x() * extent.y() * extent.z(); + if (volume >= iLargestVolume) + { + iLargestVolume = volume; + iLargestSection = i; + } + if (strstr(header->id, "BODY") == 0) + iBodySection = i; + minCoords.minimum(secMinVec); + maxCoords.maximum(secMaxVec); + } + + const int iMainSection = iBodySection >= 0 ? iBodySection : iLargestSection; + + const Vec3f renderOffset = negate(minCoords); + + last_succeeded_operation = 2; + + + const auto extents = (maxCoords - minCoords); + int rtWidth = ceil(extents.x()); + int rtHeight = ceil(extents.y()); + const int c_pixels = rtWidth * rtHeight; + + // MYASSERT(c_pixels,1); + + byte* image = new byte[c_pixels]; + byte* image_s = new byte[c_pixels]; + char* image_z = new char[c_pixels]; + + memset(image, 0, c_pixels); + memset(image_s, 0, c_pixels); + memset(image_z, CHAR_MIN, c_pixels); + + int x_center = 0, y_center = 0; + int x_center_zmax = 0, y_center_zmax = 0; + + for (i = 0; i < cur_vxl.get_c_section_headers(); i++) + { + auto iNormalTable = cur_vxl.get_section_tailer(i)->unknown; + const auto& normalTable = normalTables.isValidTable(iNormalTable) ? normalTables.getTable(iNormalTable) : emptyNormalTable; + if (i != iMainSection) + RenderVXLSection(normalTable, lightDirection, i, rtWidth, rtHeight, renderOffset, rotation, postHVAOffset, image, image_s, image_z, NULL, NULL, 0, NULL, NULL, -1, -1); + else + RenderVXLSection(normalTable, lightDirection, i, rtWidth, rtHeight, renderOffset, rotation, postHVAOffset, image, image_s, image_z, &x_center, &y_center, ZAdjust, &x_center_zmax, &y_center_zmax, i3dCenterX, i3dCenterY); + } + + last_succeeded_operation = 3; + + if (lpXCenter) *lpXCenter = x_center; + if (lpYCenter) *lpYCenter = y_center; + if (lpXCenterZMax) *lpXCenterZMax = x_center_zmax; + if (lpYCenterZMax) *lpYCenterZMax = y_center_zmax; + + // calculate x/y values + int left = 0, right = rtWidth, top = 0, bottom = rtHeight; + + + + // draw pic + DDSURFACEDESC2 ddsd; + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwWidth = right - left; + ddsd.dwHeight = bottom - top; + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH /*| DDSD_PIXELFORMAT*/; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + + + + if (pdd->CreateSurface(&ddsd, &pdds[0], NULL) != DD_OK) + return NULL; + + ddsd.dwFlags = DDSD_PITCH; + pdds[0]->GetSurfaceDesc(&ddsd); + long pitch = ddsd.lPitch; + + DDPIXELFORMAT pf; + memset(&pf, 0, sizeof(DDPIXELFORMAT)); + pf.dwSize = sizeof(DDPIXELFORMAT); + + pdds[0]->GetPixelFormat(&pf); + + last_succeeded_operation = 5; + + BOOL bUseGDI = FALSE; + + if (pf.dwFlags & DDPF_RGB && pf.dwRBitMask && pf.dwGBitMask && pf.dwBBitMask) + { + + CreateConvLookUpTable(pf, hPalette); + + + /*DDBLTFX fx; + memset(&fx, 0, sizeof(DDBLTFX)); + fx.dwSize=sizeof(DDBLTFX); + pdds[0]->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + */ + + last_succeeded_operation = 6; + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + if (pdds[0]->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL) == DD_OK) + { + pitch = ddsd.lPitch; + + BYTE* dest = (BYTE*)ddsd.lpSurface; + + if (dest) + { + int bytesize = (pf.dwRGBBitCount + 1) / 8; + if (bytesize < 1) bytesize = 1; + + if (pf.dwRGBBitCount <= 8) bytesize = 1; + else if (pf.dwRGBBitCount <= 16) bytesize = 2; + else if (pf.dwRGBBitCount <= 24) bytesize = 3; + else if (pf.dwRGBBitCount <= 32) bytesize = 4; + + last_succeeded_operation = 7; + int k, e; + //HDC dc; + //pdds[0]->GetDC(&dc); + for (k = 0;k < rtWidth;k++) + { + for (e = 0;e < rtHeight;e++) + { + //t_palet_entry p=ts_palettes[hPalette-1][image[k+e*cl_max]]; + + if (k >= left && e >= top && k < right && e < bottom) + { + //SetPixel(dc, k-left, e-top, RGB(p.r, p.g, p.b) ); + DWORD dwWrite = k * bytesize + e * ddsd.lPitch; + int pos = k + e * rtWidth; + if (pos < c_pixels && image[pos] != 0) + { + DWORD col = conv_color[hPalette - 1][image[k + e * rtWidth]]; + memcpy(&dest[dwWrite], &col, bytesize); + } + else + { + DWORD col = transp_conv_color[hPalette - 1]; + memcpy(&dest[dwWrite], &col, bytesize); + } + + + } + } + + } + memcpy(&dest[0], &transp_conv_color[hPalette - 1], bytesize); + //pdds[0]->ReleaseDC(dc); + + } + pdds[0]->Unlock(NULL); + } + else bUseGDI = TRUE; + } + else bUseGDI = TRUE; + + if (bUseGDI) + { + HDC hDC; + while (pdds[0]->GetDC(&hDC) == DDERR_WASSTILLDRAWING); + + + last_succeeded_operation = 7; + int k, e; + //HDC dc; + //pdds[0]->GetDC(&dc); + for (k = 0;k < rtWidth;k++) + { + for (e = 0;e < rtHeight;e++) + { + //t_palet_entry p=ts_palettes[hPalette-1][image[k+e*cl_max]]; + + if (k >= left && e >= top && k < right && e < bottom) + { + //SetPixel(dc, k-left, e-top, RGB(p.r, p.g, p.b) ); + //DWORD dwWrite=k*bytesize+e*ddsd.lPitch; + int pos = k + e * rtWidth; + if (pos < c_pixels && image[pos] != 0) + { + t_palet_entry& p = ts_palettes[hPalette - 1][image[k + e * rtWidth]]; + SetPixel(hDC, k, e, RGB(p.r, p.g, p.b)); + } + else + { + SetPixel(hDC, k, e, RGB(245, 245, 245)); + } + + } + } + } + + SetPixel(hDC, 0, 0, RGB(245, 245, 245)); + pdds[0]->ReleaseDC(hDC); + + } + + last_succeeded_operation = 70001; + + SetColorKey(pdds[0], -1); + + last_succeeded_operation = 70002; + + if (image) delete[] image; + if (image_s) delete[] image_s; + if (image_z) delete[] image_z; + + //pal.close(); + return TRUE; + } + + BOOL LoadVXLImage(const VoxelNormalTables& normalTables, Vec3f lightDirection, const Vec3f rotation, const Vec3f modelOffset, std::vector<BYTE>& image, std::vector<BYTE>& lighting, int* lpXCenter, int* lpYCenter, int ZAdjust, int* lpXCenterZMax, int* lpYCenterZMax, int i3dCenterX, int i3dCenterY, RECT* vxlrect) + { + last_succeeded_operation = 1; + + int i; + int cx_max = 0, cy_max = 0, cz_max = 0; + + Vec3f minCoords(10000, 10000, 10000); + Vec3f maxCoords(-10000, -10000, -10000); + + // Calculate projected bounding box for the virtual render target + int iBodySection = -1; + int iLargestSection = 0; + int iLargestVolume = 0; + for (i = 0; i < cur_vxl.get_c_section_tailers(); i++) + { + const auto& header = cur_vxl.get_section_header(i); + const auto& tailer = cur_vxl.get_section_tailer(i); + Vec3f secMinVec, secMaxVec; + GetVXLSectionBounds(i, rotation, modelOffset, secMinVec, secMaxVec); + auto extent = secMaxVec - secMinVec; + auto volume = extent.x() * extent.y() * extent.z(); + if (volume >= iLargestVolume) + { + iLargestVolume = volume; + iLargestSection = i; + } + if (strcmp(header->id, "BODY") == 0) + iBodySection = i; + minCoords.minimum(secMinVec); + maxCoords.maximum(secMaxVec); + } + + const int iMainSection = iBodySection >= 0 ? iBodySection : iLargestSection; + + + const Vec3f renderOffset = negate(minCoords); + + last_succeeded_operation = 2; + + + const auto extents = (maxCoords - minCoords); + int rtWidth = ceil(extents.x()) + 1; + int rtHeight = ceil(extents.y()) + 1; + const int c_pixels = rtWidth * rtHeight; + + MYASSERT(c_pixels, 1); + + image.clear(); + lighting.clear(); + image.resize(c_pixels, 0); + lighting.resize(c_pixels, 255); + std::vector<char> image_z(c_pixels, CHAR_MIN); + + int x_center = 0, y_center = 0; + int x_center_zmax = 0, y_center_zmax = 0; + + for (i = 0; i < cur_vxl.get_c_section_headers(); i++) + { + auto iNormalTable = cur_vxl.get_section_tailer(i)->unknown; + const auto& normalTable = normalTables.isValidTable(iNormalTable) ? normalTables.getTable(iNormalTable) : emptyNormalTable; + if (i != iMainSection) + RenderVXLSection(normalTable, lightDirection, i, rtWidth, rtHeight, renderOffset, rotation, modelOffset, image.data(), lighting.data(), image_z.data(), NULL, NULL, ZAdjust, NULL, NULL, -1, -1); + else + RenderVXLSection(normalTable, lightDirection, i, rtWidth, rtHeight, renderOffset, rotation, modelOffset, image.data(), lighting.data(), image_z.data(), &x_center, &y_center, ZAdjust, &x_center_zmax, &y_center_zmax, i3dCenterX, i3dCenterY); + } + + last_succeeded_operation = 3; + + if (lpXCenter) + *lpXCenter = x_center; + if (lpYCenter) + *lpYCenter = y_center; + if (lpXCenterZMax) + *lpXCenterZMax = x_center_zmax; + if (lpYCenterZMax) + *lpYCenterZMax = y_center_zmax; + + // calculate x/y values + int left = 0, right = rtWidth, top = 0, bottom = rtHeight; + + int width = right - left; + int height = bottom - top; + + if (vxlrect) + { + vxlrect->left = 0; + vxlrect->right = width; + vxlrect->bottom = height; + vxlrect->top = 0; + } + +#ifdef _DEBUG + // draw lines around RT + for (i = 0; i < width; ++i) + { + lighting[i] = 1; + lighting[i + (height - 1) * width] = 1; + image[i] = 1; + image[i + (height - 1) * width] = 1; + } + for (i = 0; i < height; ++i) + { + image[i * width + width - 1] = 1; + image[i * width] = 1; + } + // draw center + if (x_center > 0 && y_center > 0 && x_center < width - 1 && y_center < height - 1) + { + image[x_center + y_center * width] = 1; + image[x_center - 1 + y_center * width] = 1; + image[x_center + 1 + y_center * width] = 1; + image[x_center + (y_center + 1) * width] = 1; + image[x_center + (y_center - 1) * width] = 1; + } +#endif + + image.resize(width * height); + lighting.resize(width * height); + + return TRUE; + } + + + + HTSPALETTE LoadTSPalette(const std::string& szPalette, HMIXFILE hPaletteOwner) + { + Cpal_file pal; + RGBTRIPLE* paldata; + + if (dwPalCount > 255) + return NULL; + if (hPaletteOwner == NULL) + { + if (open_read(pal, szPalette)) + return NULL; + } + else + { + if (szPalette[0] == '_' && szPalette[1] == 'I' && szPalette[2] == 'D') + { + char id[256]; + strcpy_s(id, &szPalette[3]); + int iId = atoi(id); + if (pal.open(iId, mixfiles[hPaletteOwner - 1])) + return NULL; + } + else + { + if (pal.open(szPalette, mixfiles[hPaletteOwner - 1]) != 0) + return NULL; + } + } + + if (!pal.is_open()) + return NULL; + + dwPalCount++; + + + paldata = (RGBTRIPLE*)pal.get_data(); + //t_palet t_p; + memcpy(ts_palettes[dwPalCount - 1], paldata, 768); + bFirstConv[dwPalCount - 1] = TRUE; + convert_palet_18_to_24(ts_palettes[dwPalCount - 1]); + + pal.close(); + return dwPalCount; + + } + + HTSPALETTE LoadTSPalette(LPCSTR szPalette, HMIXFILE hPaletteOwner) + { + return LoadTSPalette(std::string(szPalette), hPaletteOwner); + } + + BOOL SetTSPaletteEntry(HTSPALETTE hPalette, BYTE bIndex, RGBTRIPLE* rgb, RGBTRIPLE* orig) + { + if (hPalette == NULL || hPalette > dwPalCount) + return FALSE; + if (orig != NULL) + { + orig->rgbtRed = ts_palettes[hPalette - 1][bIndex].r; + orig->rgbtGreen = ts_palettes[hPalette - 1][bIndex].g; + orig->rgbtBlue = ts_palettes[hPalette - 1][bIndex].b; + } + if (rgb != NULL) + { + ts_palettes[hPalette - 1][bIndex].r = rgb->rgbtRed; + ts_palettes[hPalette - 1][bIndex].g = rgb->rgbtGreen; + ts_palettes[hPalette - 1][bIndex].b = rgb->rgbtBlue; + + bFirstConv[hPalette - 1] = TRUE; + CreateConvLookUpTable(cur_pf[hPalette - 1], hPalette); + } + + return TRUE; + } + + t_game GameToXCCGame(FSunPackLib::Game game) + { + t_game xcc_game(game_unknown); + switch (game) + { + case TS: + xcc_game = game_ts; + break; + case RA2: + xcc_game = game_ra2; + break; + case TS_FS: + xcc_game = game_ts_fs; + break; + case RA2_YR: + xcc_game = game_ra2_yr; + break; + } + return xcc_game; + } + + BOOL WriteMixFile(LPCTSTR lpMixFile, LPCSTR* lpFiles, DWORD dwFileCount, Game game) + { + if (!lpFiles) + return FALSE; + if (!lpMixFile) + return FALSE; + + Cmix_file_write mix(GameToXCCGame(game)); + + DWORD i; + for (i = 0;i < dwFileCount;i++) + { + LPCSTR lpFile = lpFiles[i]; + Cvirtual_binary file = Cvirtual_binary(std::string(lpFile)); + + if (file.data()) + { + mix.add_file(lpFile, file); + } + } + + auto binary = mix.write(); + return binary.save(lpMixFile) == 0; + } + + class ColorConverterImpl + { + public: + ColorConverterImpl(const DDPIXELFORMAT& pf) + { + m_conf.set_pf(pf); + } + + int GetColor(int r, int g, int b) const + { + return m_conf.get_color(r, g, b); + } + + int GetColor(int a, int r, int g, int b) const + { + return m_conf.get_color(a, r, g, b); + } + + private: + mutable Cddpf_conversion m_conf; + }; + + ColorConverter::ColorConverter(const DDPIXELFORMAT& pf) : + m_impl(new ColorConverterImpl(pf)) + { + } + + int ColorConverter::GetColor(int r, int g, int b) const + { + return m_impl->GetColor(r, g, b); + } + + int ColorConverter::GetColor(int a, int r, int g, int b) const + { + return m_impl->GetColor(a, r, g, b); + } + + int ColorConverter::GetColor(COLORREF col) const + { + return GetColor((LOBYTE((col) >> 24)), GetRValue(col), GetGValue(col), GetBValue(col)); + } + +}; \ No newline at end of file diff --git a/MissionEditorPackLib/MissionEditorPackLib.h b/MissionEditorPackLib/MissionEditorPackLib.h new file mode 100644 index 0000000..0e7a50a --- /dev/null +++ b/MissionEditorPackLib/MissionEditorPackLib.h @@ -0,0 +1,227 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#ifndef FSUNPACKLIB_INCLUDED +#define FSUNPACKLIB_INCLUDED + +#include <windows.h> +#include <ddraw.h> +#include <memory> +#include <vector> +#include <string> +#include "Vec3.h" + +class VoxelNormalTables; + +typedef DWORD HMIXFILE; +typedef DWORD HTSPALETTE; + +struct SHPHEADER +{ + __int16 zero; + __int16 cx; + __int16 cy; + __int16 c_images; +}; + +struct SHPIMAGEHEADER +{ + __int16 x; + __int16 y; + __int16 cx; + __int16 cy; + __int32 compression; + __int32 unknown; + __int32 zero; + __int32 offset; +}; + +namespace FSunPackLib +{ + enum Game + { + RA2, + RA2_YR, + TS, + TS_FS + }; + + enum class VoxelNormalClass: std::uint8_t + { + Unknown = 0, + Gen1 = 1, + TS = 2, + Gen3 = 3, + RA2 = 4, + }; + + extern "C" extern bool _DEBUG_EnableLogs; // only useable in debug library builds + extern "C" extern bool _DEBUG_EnableBreakpoints; // only useable in debug library builds + + struct FSPL_EXCEPTION + { + int err_code; + }; + + extern "C" extern int last_succeeded_operation; + + class ColorConverterImpl; + class ColorConverter + { + public: + ColorConverter(const DDPIXELFORMAT& pf); + int GetColor(int a, int r, int g, int b) const; + int GetColor(int r, int g, int b) const; + int GetColor(COLORREF col) const; + + private: + std::shared_ptr<ColorConverterImpl> m_impl; + }; + +// base 64 +/* +Converts hex data to Base64 data. +sp - source poINTer +len - length of hex data +Returns a poINTer to the base64 data. Caller must free this memory. +*/ + BYTE* EncodeBase64(BYTE* sp, UINT len); +/* +Converts Base64 data to hex data. +sp - source poINTer +dp - dest buffer (should be as large as sp) +Returns the hex data length +*/ + int DecodeBase64(const char* sp, std::vector<BYTE>& dest); + + +// format 80 +/* +Pack to a simple format 80 pack like Overlay & OverlayData-Pack +sp - source poINTer (should be the 262144 bytes for overlay & overlaydata) +len - length of the source data (should be 262144) +nSections - section count. should be 32 +dest - poINTer to dest poINTer. Function allocates memory, caller must free this memory. +Returns the length of the packed data. +*/ + INT EncodeF80(BYTE* sp, UINT len, UINT nSections, BYTE** dest); + +/* +Extracts a simple format 80 pack like the Overlay & OverlayData-Pack +Note that it extracts a whole pack, not just a simple section. +In order to simply decode/encode Format80, you should use ConvertFromF80 and ConvertToF80 + sp - source poINTer +SourceLength - length of the source + dp - dest buffer + max_size - maximum allowed destination size +*/ + bool DecodeF80(const BYTE* sp, UINT SourceLength, std::vector<BYTE>& dp, std::size_t max_size); + +// IsoMapPack5 +/* +Pack IsoMapPack5. +sp - source poINTer +SourceLength - length of source +dp - destination buffer +Returns size of packed data +*/ + UINT EncodeIsoMapPack5(BYTE* sp, UINT SourceLength, BYTE** dp); + +/* +Unpack IsoMapPack5. +sp - source poINTer +SourceLength - length of source +dp - destination buffer +*/ + UINT DecodeIsoMapPack5(BYTE* sp, UINT SourceLength, BYTE* dp, HWND hProgressBar, BOOL bDebugMode); + + BOOL XCC_Initialize(BOOL bUseCache); + + + HMIXFILE XCC_OpenMix(LPCTSTR szMixFile, HMIXFILE hOwner); + + BOOL XCC_GetMixName(HMIXFILE hOwner, std::string& sMixFile); + + + BOOL XCC_DoesFileExist(LPCSTR szFile, HMIXFILE hOwner); + + + BOOL XCC_CloseMix(HMIXFILE hMixFile); + + BOOL XCC_ExtractFile(const std::string& szFilename, const std::string& szSaveTo, HMIXFILE hOwner); + BOOL XCC_ExtractFile(LPCSTR szFilename, LPCSTR szSaveTo, HMIXFILE hOwner); + + BOOL XCC_GetSHPHeader(SHPHEADER* pHeader); + + +/* +Returns the SHP image header of a image in a SHP file +*/ + BOOL XCC_GetSHPImageHeader(int iImageIndex, SHPIMAGEHEADER* pImageHeader); + + + + BOOL SetCurrentTMP(LPCSTR szTMP, HMIXFILE hOwner); + + + BOOL SetCurrentSHP(LPCSTR szSHP, HMIXFILE hOwner); + + + BOOL XCC_GetTMPTileInfo(int iTile, POINT* lpPos, int* lpWidth, int* lpHeight, BYTE* lpDirection, BYTE* lpTileHeight, BYTE* lpTileType, RGBTRIPLE* lpRgbLeft, RGBTRIPLE* lpRgbRight); + + + BOOL XCC_GetTMPInfo(RECT* lpRect, int* iTileCount, int* iTilesX, int* iTilesY); + + + + BOOL LoadTMPImageInSurface(IDirectDraw4* pdd, int iStart, int iCount, LPDIRECTDRAWSURFACE4* pdds, HTSPALETTE hPalette); + BOOL LoadTMPImage(int iStart, int iCount, BYTE** lpTileArray); + + BOOL LoadSHPImageInSurface(IDirectDraw4* pdd, HTSPALETTE hPalette, int iImageIndex, int iCount, LPDIRECTDRAWSURFACE4* pdds); + BOOL LoadSHPImage(int iImageIndex, int iCount, BYTE** lpPics); + BOOL LoadSHPImage(int iImageIndex, std::vector<BYTE>& pic); + + HTSPALETTE LoadTSPalette(LPCSTR szPalette, HMIXFILE hPaletteOwner); + HTSPALETTE LoadTSPalette(const std::string& szPalette, HMIXFILE hPaletteOwner); + + + BOOL SetTSPaletteEntry(HTSPALETTE hPalette, BYTE bIndex, RGBTRIPLE* rgb, RGBTRIPLE* orig); + + + BOOL SetCurrentVXL(LPCSTR lpVXLFile, HMIXFILE hMixFile); + + + BOOL GetVXLInfo(int* cSections); + + BOOL GetVXLSectionInfo(int section, VoxelNormalClass& normalClass); + + BOOL LoadVXLImageInSurface(const VoxelNormalTables& normalTables, Vec3f lightDirection, IDirectDraw4* pdd, int iStart, int iCount, Vec3f rotation, Vec3f modelOffset, LPDIRECTDRAWSURFACE4* pdds, HTSPALETTE hPalette, int* lpXCenter = NULL, int* lpYCenter = NULL, int ZAdjust = 0, int* lpXCenterZMax = NULL, int* lpYCenterZMax = NULL, int i3dCenterX = -1, int i3dCenterY = -1); + + // modelOffset is applied before VXL/HVA translates and scales and before model-to-world rotation + BOOL LoadVXLImage(const VoxelNormalTables& normalTables, Vec3f lightDirection, Vec3f rotation, Vec3f modelOffset, std::vector<BYTE>& image, std::vector<BYTE>& lighting, int* lpXCenter = NULL, int* lpYCenter = NULL, int ZAdjust = 0, int* lpXCenterZMax = NULL, int* lpYCenterZMax = NULL, int i3dCenterX = -1, int i3dCenterY = -1, RECT* vxlrect = NULL); + + + BOOL WriteMixFile(LPCTSTR lpMixFile, LPCSTR* lpFiles, DWORD dwFileCount, Game game); + + HRESULT SetColorKey(IDirectDrawSurface4* pDDS, COLORREF rgb); + +}; + +#endif \ No newline at end of file diff --git a/MissionEditorPackLib/Vec3.h b/MissionEditorPackLib/Vec3.h new file mode 100644 index 0000000..5c46886 --- /dev/null +++ b/MissionEditorPackLib/Vec3.h @@ -0,0 +1,321 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <cassert> + +template<class T> +class Vec3 +{ +public: + Vec3() = default; + Vec3(T x, T y, T z) : v{ x, y, z } + { + } + Vec3(T v_[3]) : v{ v_[0], v_[1], v_[2] } + { + } + + T& operator[](unsigned int i) { + assert(i < 3); + return v[i]; + } + + const T& operator[](unsigned int i) const { + assert(i < 3); + return v[i]; + } + + inline T dot(const Vec3& other) const { + return v[0] * other.v[0] + v[1] * other.v[1] + v[2] * other.v[2]; + } + + inline T length() const + { + return sqrt(squaredLength()); + } + + inline T squaredLength() const + { + return dot(*this); + } + + inline Vec3& normalize() + { + T invL = T(1) / length(); + v[0] *= invL; + v[1] *= invL; + v[2] *= invL; + return *this; + } + + inline Vec3& negate() + { + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; + return *this; + } + + inline Vec3& inverse() + { + v[0] = T(1) / v[0]; + v[1] = T(1) / v[1]; + v[2] = T(1) / v[2]; + return *this; + } + + inline Vec3& minimum(const Vec3& v2) + { + v[0] = min(v[0], v2[0]); + v[1] = min(v[1], v2[1]); + v[2] = min(v[2], v2[2]); + return *this; + } + + inline Vec3& maximum(const Vec3& v2) + { + v[0] = max(v[0], v2[0]); + v[1] = max(v[1], v2[1]); + v[2] = max(v[2], v2[2]); + return *this; + } + + inline Vec3& operator *=(const Vec3& v2) { + v[0] *= v2[0]; + v[1] *= v2[1]; + v[2] *= v2[2]; + return *this; + } + + inline Vec3& operator *=(const T scale) { + v[0] *= scale; + v[1] *= scale; + v[2] *= scale; + return *this; + } + + inline Vec3& operator /=(const Vec3& v2) { + v[0] /= v2[0]; + v[1] /= v2[1]; + v[2] /= v2[2]; + return *this; + } + + inline Vec3& operator /=(const T scale) { + v[0] /= scale; + v[1] /= scale; + v[2] /= scale; + return *this; + } + + inline Vec3& operator +=(const Vec3& other) { + v[0] += other.v[0]; + v[1] += other.v[1]; + v[2] += other.v[2]; + return *this; + } + + inline Vec3& operator -=(const Vec3& other) { + v[0] -= other.v[0]; + v[1] -= other.v[1]; + v[2] -= other.v[2]; + return *this; + } + + inline bool equals(const Vec3& other, T epsilon=T(0.001)) + { + return fabs(v[0] - other.v[0]) <= epsilon && fabs(v[1] - other.v[1]) <= epsilon && fabs(v[2] - other.v[2]) <= epsilon; + } + + T x() const { return v[0]; } + T y() const { return v[1]; } + T z() const { return v[2]; } + + T v[3] = { 0, 0, 0 }; +}; + +template< class T> +inline Vec3<T> operator+(const Vec3<T>& l, const Vec3<T>& r) +{ + auto res = l; + res += r; + return res; +} + +template< class T> +inline Vec3<T> operator-(const Vec3<T>& l, const Vec3<T>& r) +{ + auto res = l; + res -= r; + return res; +} + +template< class T> +inline Vec3<T> normalize(Vec3<T> v) +{ + return v.normalize(); +} + +template< class T> +inline Vec3<T> negate(Vec3<T> v) +{ + return v.negate(); +} + +template< class T> +inline Vec3<T> inverse(Vec3<T> v) +{ + return v.inverse(); +} + +template< class T> +inline Vec3<T> minimum(Vec3<T> v, const Vec3<T>& v2) +{ + v.minimum(v2); + return v; +} + +template< class T> +inline Vec3<T> maximum(Vec3<T> v, const Vec3<T>& v2) +{ + v.maximum(v2); + return v; +} + +template< class T> +inline Vec3<T> operator /(Vec3<T> v, T scale) +{ + v /= scale; + return v; +} + +template< class T> +inline Vec3<T> operator *(Vec3<T> v, Vec3<T> v2) +{ + v *= v2; + return v; +} + +template< class T> +inline Vec3<T> operator /(Vec3<T> v, Vec3<T> v2) +{ + v /= v2; + return v; +} + +template< class T> +inline Vec3<T> operator *(Vec3<T> v, T scale) +{ + v *= scale; + return v; +} + +typedef Vec3<float> Vec3f; + + +template<class T> +class Matrix3_4 +{ +public: + Matrix3_4(const T (&m_)[3][4]) + { + for (int row = 0; row < 3; ++row) + { + for (int col = 0; col < 4; ++col) + { + m[row][col] = m_[row][col]; + } + } + } + + Matrix3_4(const T* m_) + { + for (int row = 0; row < 3; ++row) + { + for (int col = 0; col < 4; ++col) + { + m[row][col] = m_[row * 4 + col]; + } + } + } + + Vec3<T> operator *(const Vec3<T> v) const + { + auto x = v[0]; + auto y = v[1]; + auto z = v[2]; + return Vec3<T>( + x * m[0][0] + y * m[0][1] + z * m[0][2] + m[0][3], + x * m[1][0] + y * m[1][1] + z * m[1][2] + m[1][3], + x * m[2][0] + y * m[2][1] + z * m[2][2] + m[2][3] + ); + } + + Matrix3_4& scaledColumn(unsigned int iColumn, T scale) + { + assert(iColumn < 4); + m[0][iColumn] *= scale; + m[1][iColumn] *= scale; + m[2][iColumn] *= scale; + return *this; + } + + Matrix3_4 scaleColumn(unsigned int iColumn, T scale) const + { + assert(iColumn < 4); + Matrix3_4 copy(*this); + copy.m[0][iColumn] *= scale; + copy.m[1][iColumn] *= scale; + copy.m[2][iColumn] *= scale; + return copy; + } + + Matrix3_4& setColumn(unsigned int iColumn, const Vec3<T>& v) + { + assert(iColumn < 4); + m[0][iColumn] = v[0]; + m[1][iColumn] = v[1]; + m[2][iColumn] = v[2]; + return *this; + } + + Vec3f getColumn(unsigned int iColumn) const + { + assert(iColumn < 4); + return Vec3f(m[0][iColumn], m[1][iColumn], m[2][iColumn]); + } + + static Matrix3_4 translation(const Vec3<T> v) + { + return Matrix3_4({ {1, 0, 0, v.x()}, {0, 1, 0, v.y()}, {0, 0, 1, v.z()}}); + } + + static Matrix3_4 scale(const Vec3<T> v) + { + return Matrix3_4({ {v.x(), 0, 0, 0}, {0, v.y(), 0, 0}, {0, 0, v.z(), 0}}); + } + +public: + T m[3][4] = { {1, 0, 0, 1}, {0, 1, 0, 1}, {0, 0, 1, 1}}; +}; + +typedef Matrix3_4<float> Matrix3_4f; \ No newline at end of file diff --git a/MissionEditorPackLib/VoxelNormals.cpp b/MissionEditorPackLib/VoxelNormals.cpp new file mode 100644 index 0000000..97e4281 --- /dev/null +++ b/MissionEditorPackLib/VoxelNormals.cpp @@ -0,0 +1,103 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" +#include "VoxelNormals.h" +#include <array> +#include <math.h> + +template<class T> +T read(std::istream& s) +{ + T t; + auto p1 = s.tellg(); + auto n = sizeof(T); + s.read(reinterpret_cast<char*>(&t), sizeof(T)); + auto p2 = s.tellg(); + auto p3 = p2 - p1; + //s >> t; + return t; +}; + +template<class T, int N> +std::array<T, N> read(std::istream& s) +{ + std::array<T, N> t; + s.read(reinterpret_cast<char*>(t.data()), sizeof(T) * N); + return t; +}; + +VoxelNormalTable::VoxelNormalTable(std::istream& f) +{ + auto oldEx = f.exceptions(); + f.exceptions(f.failbit | f.badbit); + try + { + load(f); + } + catch (const std::exception& ex) + { + f.exceptions(oldEx); + throw ex; + } + +} + +void VoxelNormalTable::load(std::istream& f) +{ + auto count = read<std::uint8_t>(f); + m_normals.clear(); + m_normals.reserve(count); + for (auto i = 0; i < count; ++i) + { + auto v = read<float, 3>(f); + m_normals.push_back(Vec3f(v.data())); + } +} + +VoxelNormalTables::VoxelNormalTables(std::istream& f) +{ + auto oldEx = f.exceptions(); + f.exceptions(f.failbit | f.badbit); + try + { + + load(f); + + } + catch(const std::exception& ex) + { + f.exceptions(oldEx); + throw ex; + } +} + +void VoxelNormalTables::load(std::istream& f) +{ + auto tableCount = read<std::uint8_t>(f); + for (std::uint32_t i = 0; i < tableCount; ++i) + { + auto normalClass = read<std::uint8_t>(f); + VoxelNormalTable table(f); + auto normalIndex = normalClass - 1; + m_tables.resize(std::max(m_tables.size(), static_cast<std::size_t>(normalClass))); + m_tables[normalIndex] = std::move(table); + } +} diff --git a/MissionEditorPackLib/VoxelNormals.h b/MissionEditorPackLib/VoxelNormals.h new file mode 100644 index 0000000..b589cb3 --- /dev/null +++ b/MissionEditorPackLib/VoxelNormals.h @@ -0,0 +1,73 @@ +/* + FinalSun/FinalAlert 2 Mission Editor + + Copyright (C) 1999-2024 Electronic Arts, Inc. + Authored by Matthias Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <istream> +#include <vector> +#include "Vec3.h" + +class VoxelNormalTable +{ +public: + VoxelNormalTable() = default; + VoxelNormalTable(std::istream& f); + VoxelNormalTable(VoxelNormalTable&& other) noexcept = default; + VoxelNormalTable& operator=(const VoxelNormalTable& other) = default; + VoxelNormalTable& operator=(VoxelNormalTable&& other) noexcept = default; + + Vec3f operator[] (unsigned int iNormal) const + { + return iNormal < m_normals.size() ? m_normals[iNormal] : Vec3f(0, 1, 0); + } + +private: + void load(std::istream& f); + +private: + std::vector<Vec3f> m_normals; +}; + +class VoxelNormalTables +{ +public: + VoxelNormalTables() = default; + VoxelNormalTables(std::istream& f); + + bool isValidTable(const std::uint8_t normalClass) const + { + return normalClass > 0 && normalClass <= m_tables.size(); + } + + // Returns the given normal table. Throws on invalid normalClass. + const VoxelNormalTable& getTable(const std::uint8_t normalClass) const + { + if (!isValidTable(normalClass)) + throw std::range_error("Table for normal class does not exist"); + return m_tables[normalClass - 1]; + } + +private: + void load(std::istream& f); + +private: + // we use a vector instead of map for fast lookup + std::vector<VoxelNormalTable> m_tables; +}; diff --git a/README.md b/README.md new file mode 100644 index 0000000..b8ad42e --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +# FinalSun / FinalAlert (YR) 2 Mission Editor + +This repository contains the source code for the FinalSun/FinalAlert (YR) Mission Editor. + +The official version for both applications has been increased to v2.0 in order to illustrate they now run properly on modern operating systems. We also used this opporunity to update the application and fix some known issues. + +# Fixes and Changes +- Fixed a few code issues to allow the application to run on modern operating systems. +- Updated the application icons with new 256x256 graphics. +- You can now zoom in & out with the middle mouse button or wheel +- You don't need administrator access anymore if the program is installed in the program folder, as all user data and settings are now stored in your AppData folder +- Tunnel tube editing completely reimplemented + + Tunnel tilesets available + + You can edit existing tubes by using the tool on the end of an existing tube + + You can now create curved tubes + + You can now create unidirectional tubes +- LAT support for Crystal and Swamp terrain in Tiberian Sun temperate maps +- House colors are now read from map or rules.ini +- Units and buildings are now shaded in the house colors correctly +- Voxel units now have shading applied +- Minimap can now be resized +- Undo steps increased to 64 +- Map rendering performance improved +- Several fixes for crashes +- Fixed addon turrets display +- SHP turrets and Voxel turrets + barrels have their positioning fixed. +- Maps up to 400x112 (or 112x400) are now allowed. +- Fixed minimap for non-quadratic maps. + +# Install build requirements +- Microsoft Visual Studio 2022 + 1. Install Visual Studio 2022 if you haven't done so already. + 2. (Re-)Start the Visual Studio Installer + 3. Apply any updates to Visual Studio 2022 + 4. Click on Modify. + 5. Under Workloads ensure "Desktop Development with C++" is enabled. Ensure the details are visible on the right panel below "Desktop Development with C++" and enable the following checkboxes: + - MSVC v143 - VS 2022 C++-x64/x86 build tools + - C++-ATL for v143 build tools x86 & x64 + - vcpkg package manager: if this item is missing, please check that you have updated Visual Studio 2022! + - newest Windows 10 SDK + - newest Windows 11 SDK + - C++-MFC for v143 build tools x86 & x64 + - Do not untick any other checkboxes! + 6. Apply the changes. +- Gitâ„¢ for Windows - Ensure you do not run any other git implementation when using vcpkg. + +# Building the source code +The source code consists of 2 projects: +- MissionEditor: The main mission editor application code. +- MissionEditorPackLib: Wraps XCC objects with C functions and includes some loading and packing code. + +## Compilation +1) In this example, we are going to build Final Alert 2 (for Red Alert 2). +1) Open MissionEditor.sln with Visual Studio 2022 and set the project configuration to "FinalAlertYRRelease". This will cause an automatic switch to FinalAlert2YR.exe. +2) Build the project by pressing F7 (Build Solution), once completed it will produce FinalAlert2YR.exe in the "dist/FinalAlert2" subdirectory +3) You can now run and debug the editor by pressing F5 + +## Updating third-party libraries +In order to update zlib, bzip, boost and lzo to newest version, start a "Developer Command Prompt for VS 2022", move to the "3rdParty\xcc" folder with vcpkg and Git for Windows in PATH: + + git --version + vcpkg x-update-baseline + +A version of XCC is directly included in "3rdParty\xcc". It is a slightly modified and heavily stripped down version. The changes are available in `3rdParty\xcc\patch.<COMMIT_HASH>.diff`, where `COMMIT_HASH` is the commit hash of the XCC repository (at the time of this writing `3rdParty\xcc\patch.70358b46858973426c1ecf204485cb2a88716217.diff`). If you update XCC to a newer version by replacing the files, please also apply the (eventually updated) patch afterwards. + +# Creating a distribution +After modifying the source code you might want to create a distribution. +Please ensure that you have taken care of everything required by the licenses (e.g. notices of source code changes and your copyright statement) and that the program itself does make clear it has been modified by you. + +There is a helper script that can create the distributions in the script folder: + + cd scripts + build_and_distribute.bat + +This rebuilds everything and creates several files in the dist folder: + + - FinalSun.zip + - Contains a FinalSun distribution + - FinalAlert2.zip + - Contains a FinalAlert2 distribution + - FinalAlert2YR.zip + - Contains a FinalAlert2 Yuri's Revenge distribution + - MissionEditorSource.zip + - The source code of this git repository (no uncommitted changes included) + - MissionEditorExternalSources.zip + - A best-effort dump of third party source code and binaries used for the build. This possibly contains material not for distribution! You should archive this for reference and/or in the event that original sources become unavailable. + +When distributing, you yourself are responsible for fulfilling all license requirements both of this repository and of all third party libraries being used. +There is no warranty that the helper script automatically fulfills all requirements. + +# Directories +MissionEditor\data\shared - Data copied to both FS/FA2 distribution +MissionEditor\data\FinalAlert2 - Additional data copied to FA2 distribution +MissionEditor\data\FinalSun - Additional data copied to FS distribution + +MissionEditor\PropertySheets - Some property sheets to ease managing the many project configurations + +dist - Will contain the output binaries in subfolders. Required DLLs of third-party libraries and the data directory will be copied there using MissionEditor\PropertySheets\common.props + +# Contributions +This is an archive repository and will not be maintained. We suggest you fork this repository to fix any issues or add new features. + +# Source +Most of the source code has been written around 1999-2001 and does not take advantage of modern C++ features (e.g. smart pointers or RAII) or hardware rendering. However, we've enabled C++20 support and refactored some critical parts to be up to date. + +# Authors +- Electronic Arts Inc. +- Matthias Wagner + + Author of the original FinalSun and FinalAlert 2 (YR) + + Bug fixes, updates and refactorings + + Updating the build system +- Olaf van der Spek + + For the XCC Library +- Luke "CCHyper" Feenan + + Additional programming + + Preparing the source code for open source release + + New icons and various other graphics + +# Special Thanks +We'd like to thank the team at Electronic Arts for approving and making the release of the source code possible. + +# Legal +The video games "Command & Conquer: Tiberian Sun", "Command & Conquer: Red Alert 2", and "Command & Conquer: Yuri's Revenge" are copyright of Westwood Studios. All Rights Reserved. Westwood Studios is a trademark or registered trademark of Electronic Arts in the U.S. and/or other countries. All rights reserved. + +Microsoft, DirectX, Visual C++, Visual Studio and Windows are trademarks of the Microsoft group of companies. + +Git and the Git logo are either registered trademarks or trademarks of Software Freedom Conservancy, Inc., corporate home of the Git Project, in the United States and/or other countries. + +# License +Unless otherwise stated, the source code provided in this repository is licenced under the [GNU General Public License version 3](<https://www.gnu.org/licenses/gpl-3.0.html>). Please see the accompanying LICENSE file and the actual files of interest. + +Third party libraries in the 3rdParty folder may be licensed differently. Please see their accompanying LICENSE or COPYING file and the actual files of interest. diff --git a/scripts/build_and_distribute.bat b/scripts/build_and_distribute.bat new file mode 100644 index 0000000..23d792a --- /dev/null +++ b/scripts/build_and_distribute.bat @@ -0,0 +1,26 @@ +@echo off +echo This script is a convenience script for building a full FinalSun and FinalAlert 2 YR distribution. It is not required for daily development. + +if "%VCINSTALLDIR%" == "" ( + if not exist "%ProgramFiles%\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" ( + echo Visual Studio 2022 Community Edition is not installed in "%ProgramFiles%\Microsoft Visual Studio\2022\Community". If you use another edition of Visual Studio, please activate a developer command prompt. + exit /b 1 + ) + call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" -arch=x86 -host_arch=x86 +) + + +@echo on +pushd "%~dp0\.." +rmdir /Q /S "%~dp0..\3rdParty\xcc\vcpkg_installed" +msbuild "-p:VcpkgAdditionalInstallOptions=--binarysource clear """--downloads-root=%~dp0..\3rdParty\xcc\vcpkg_downloads""" """--x-buildtrees-root=%~dp0..\3rdParty\xcc\vcpkg_installed\x86-windows\_buildtrees"""" "-p:Configuration=FinalAlertRelease YR" -p:Platform=Win32 -p:DistributeMissionEditor=true /t:Rebuild MissionEditor.sln +msbuild "-p:VcpkgAdditionalInstallOptions=--binarysource clear """--downloads-root=%~dp0..\3rdParty\xcc\vcpkg_downloads""" """--x-buildtrees-root=%~dp0..\3rdParty\xcc\vcpkg_installed\x86-windows\_buildtrees"""" "-p:Configuration=FinalAlertRelease" -p:Platform=Win32 -p:DistributeMissionEditor=true /t:Rebuild MissionEditor.sln +msbuild "-p:VcpkgAdditionalInstallOptions=--binarysource clear """--downloads-root=%~dp0..\3rdParty\xcc\vcpkg_downloads""" """--x-buildtrees-root=%~dp0..\3rdParty\xcc\vcpkg_installed\x86-windows\_buildtrees"""" "-p:Configuration=FinalSunRelease" -p:Platform=Win32 -p:DistributeMissionEditor=true /t:Rebuild MissionEditor.sln + +popd + +pushd "%~dp0" +call zip_sources.bat +call zip_3rdParty_sources.bat +popd + diff --git a/scripts/install_sources_for_distribution.bat b/scripts/install_sources_for_distribution.bat new file mode 100644 index 0000000..84bf48e --- /dev/null +++ b/scripts/install_sources_for_distribution.bat @@ -0,0 +1,15 @@ +@echo off +echo This script not only installs the vcpkg packages (this is usually done automatically when building), but also makes the downloaded sources and the build sources (with VCPKG patches applied) available in this repository. This may be helpful for distributing, archiving and license compliance and is not required for daily development. + +if "%VCINSTALLDIR%" == "" ( + if not exist "%ProgramFiles%\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" ( + echo Please activate a developer command prompt. + exit /b 1 + ) +) + +@echo on +pushd "%~dp0..\3rdParty\xcc" +rmdir /Q /S "%~dp0..\3rdParty\xcc\vcpkg_installed" +vcpkg install --binarysource clear "--downloads-root=%~dp0..\3rdParty\xcc\vcpkg_downloads" "--x-install-root=%~dp0..\3rdParty\xcc\vcpkg_installed\x86-windows" "--x-buildtrees-root=%~dp0..\3rdParty\xcc\vcpkg_installed\x86-windows\_buildtrees" --triplet x86-windows +popd \ No newline at end of file diff --git a/scripts/zip_3rdParty_sources.bat b/scripts/zip_3rdParty_sources.bat new file mode 100644 index 0000000..cf3016c --- /dev/null +++ b/scripts/zip_3rdParty_sources.bat @@ -0,0 +1,7 @@ +pushd %~dp0..\3rdParty\xcc +echo "Creating a zip of the (possibly patched) sources (and their original downloads) that have been used to build the MissionEditor. This is for reference and ensuring the original sources are still available on demand. Otherwise, this is not for distribution as it contains a lot of temporary (and possibly legally restricted) files"" +if EXIST "%~dp0..\dist\MissionEditorExternalSources.zip" ( + del "%~dp0..\dist\MissionEditorExternalSources.zip" +) +tar.exe -a -c --exclude="PowerShell-*.zip" --exclude="powershell-*" --exclude="x86-windows-dbg" --exclude="x86-windows-rel" --exclude="vcpkg" --exclude="x64-windows" -f "%~dp0..\dist\MissionEditorExternalSources.zip" vcpkg_downloads vcpkg_installed +popd diff --git a/scripts/zip_sources.bat b/scripts/zip_sources.bat new file mode 100644 index 0000000..8f73f51 --- /dev/null +++ b/scripts/zip_sources.bat @@ -0,0 +1,6 @@ +pushd "%~dp0\.." +if EXIST "dist\MissionEditorSource.zip" ( + del dist\MissionEditorSource.zip +) +git archive -o "dist\MissionEditorSource.zip" HEAD +popd \ No newline at end of file