diff --git a/.gitattributes b/.gitattributes index 412eeda..a0ccd6f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -20,3 +20,6 @@ *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain + +#Declaring CRLF files for windows. +*.bat text eol=crlf diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..85b85be --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,33 @@ +name: Java CI with Maven + +on: + push: + branches: ['master', 'develop'] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up JDK 21 + uses: actions/setup-java@v3 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + - name: Build with Maven - Install + run: mvn install:install-file -Dfile=res/jars/JSplashScreen.jar -DgroupId=com.thehowtotutorial.splashscreen -DartifactId=JSplashScreen -Dversion=1.0 -Dpackaging=jar + - name: Build with Maven - From Pom + run: mvn -B package --file pom.xml + + - name: Upload build artifacts + uses: actions/upload-artifact@v3.1.2 + with: + name: my-artifacts + path: target/*.jar + + # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive + - name: Update dependency graph + uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 diff --git a/.gitignore b/.gitignore index c745d3c..25ad1df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -################# -## Eclipse -################# +############# +## Eclipse ## +############# *.pydevproject .project @@ -29,9 +29,9 @@ local.properties .buildpath -################# -## Visual Studio -################# +################### +## Visual Studio ## +################### ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. @@ -58,7 +58,6 @@ local.properties *.tlb *.tli *.tlh -*.tmp *.vspscc .builds *.dotCover @@ -116,9 +115,9 @@ UpgradeLog*.XML -############ -## Windows -############ +############# +## Windows ## +############# # Windows image file caches Thumbs.db @@ -127,9 +126,9 @@ Thumbs.db Desktop.ini -############# -## Python -############# +############ +## Python ## +############ *.py[co] @@ -162,9 +161,9 @@ pip-log.txt # Mac crap .DS_Store -########## -## NetBeans -########## +############## +## NetBeans ## +############## nbproject/* build/ nbbuild/ @@ -173,4 +172,23 @@ nbdist/ nbactions.xml nb-configuration.xml manifest.mf -.build.xml \ No newline at end of file +.build.xmlJavaGame.iml + +################### +## IntelliJ IDEA ## +################### +JavaGame.ipr +JavaGame.iws +JavaGame.iml +out/ +.idea/ + +############### +## Debugging ## +############### + +.log.txt +/.gradle/ +Package game.png +target/* +.PrintType-TEST.txt \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index f5c99a7..12f9c59 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1 +1,15 @@ -language: java \ No newline at end of file +language: java +dist: focal +jdk: + - openjdk8 + +branches: + only: + - master + - develop + +before_install: + - mvn install:install-file -Dfile=res/jars/JSplashScreen.jar -DgroupId=com.thehowtotutorial.splashscreen -DartifactId=JSplashScreen -Dversion=1.0 -Dpackaging=jar + +script: + - mvn -B package --file pom.xml diff --git a/CONTROLS.md b/CONTROLS.md new file mode 100644 index 0000000..adf1612 --- /dev/null +++ b/CONTROLS.md @@ -0,0 +1,30 @@ +![Image of the keybaord controls for the game](/res/controls/controls.png?raw=true "Keyboard Controls") + +#####ENGLISH KEYBOARDS + +W = MOVE UP +A = MOVE LEFT +S = MOVE DOWN +D = MOVE RIGHT + +Q = QUIT +Z = TELEPORT (Only from second map to first map) + +M = MUSIC +N = NEW NPC (Does nothing yet, just follows player) +K = REMOVE NPC + +#####FRENCH KEYBOARDS (AZERTY) + +Z = MOVE UP +Q = MOVE LEFT +S = MOVE DOWN +D = MOVE RIGHT + +A = QUIT +W = TELEPORT (Only from second map to first map) + +M = MUSIC +N = NEW NPC (Does nothing yet, just follows player) +K = REMOVE NPC + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..dbbe355 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are 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. + + 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. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + 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 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 work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero 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 Affero 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 Affero 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 Affero 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. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + 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 AGPL, see +. diff --git a/README.md b/README.md index 64c37d8..907a83b 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,28 @@ -JavaGame Alpha v1.8.1 -=================== +JavaGame [![GitHub release](https://img.shields.io/github/release/redomar/JavaGame.svg?style=flat-square&label=Alpha)](https://github.com/redomar/JavaGame/releases/latest)[![JDK version](https://img.shields.io/badge/JDK-OpenJDK%208-007396?style=flat-square&logo=Java)](https://openjdk.java.net/install/)[![GitHub license](https://img.shields.io/badge/license-AGPLv3-red.svg?style=flat-square)](https://raw.githubusercontent.com/Redomar/JavaGame/master/LICENSE)[![Travis-CI Build Status](https://img.shields.io/travis/com/redomar/JavaGame.svg?label=Travis+C.I&style=flat-square)](https://travis-ci.org/redomar/JavaGame)[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/redomar/JavaGame/maven.yml?label=GitHub&style=flat-square)](https://github.com/redomar/JavaGame/actions/workflows/maven.yml) -#####What is JavaGame? +== + +#### What is JavaGame? JavaGame is a game project that have been working on since May 2013. I have added many features to the game over the last year and I plan on adding even more features. This game is purely for my own sake to practice my skills in Java. -#####Why name it JavaGame? +#### Why name it JavaGame? Well i'm still not sure what exactly i'm going to do with it, and I haven't thought of a suitable name either. I hope to change the name in the near future -#####Play the Game +#### Play the Game * For latest version get - * [v1.8](https://github.com/redomar/JavaGame/releases/tag/v1.8) + * [![GitHub release](https://img.shields.io/github/release/redomar/JavaGame.svg?style=flat-square&label=Alpha)](https://github.com/redomar/JavaGame/releases/latest) * For multiplayer enabled get - * [v1.5.4](https://github.com/redomar/JavaGame/releases/tag/v1.5.4) + * [![GitHub release](https://img.shields.io/badge/Alpha-v1.5.4-cc0000.svg)](https://github.com/redomar/JavaGame/releases/v1.5.4) -#####Your version naming is all wrong +#### Your version naming is all wrong Yes, I recently noticed that there is a standard called Semantic Versioning that I should follow. Currently my project isn't organised as well as I hoped so starting from the Beta I will follow Semantic Versioning schema. -#####Your project is lacking comments +#### Your project is lacking comments I don't know why I have not commented my code but now I'm at a stage where I cannot go back to comment the entire project, I should of commented my code from the outset. This is going to be a reminder for me in the future. -#####How to download this repository for eclipse tutorial +#### How to download this repository for eclipse tutorial Watch this video [here](http://youtu.be/_3nCgac3KKM) or checkout the [GitHub Pages](http://redomar.github.io/JavaGame/) -####How to use this repository +### How to use this repository * Fork it. * Create a branch (```git checkout -b my_branch```) @@ -34,4 +35,6 @@ Watch this video [here](http://youtu.be/_3nCgac3KKM) or checkout the [GitHub Pag * Make the changes in the /src folder * Commit your changes (```git commit -m "Change Title"```) * Push to the branch (```git push origin my_branch```) -* Open a [Pull Request](https://github.com/redomar/JavaGame/pull/new/master) \ No newline at end of file +* Open a [Pull Request](https://github.com/redomar/JavaGame/pull/new/master) + +Inspired from [vanZeben](https://github.com/vanZeben). diff --git a/build.xml b/build.xml deleted file mode 100644 index 9bf6f7c..0000000 --- a/build.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/jar-in-jar-loader.zip b/jar-in-jar-loader.zip deleted file mode 100644 index 6ee1217..0000000 Binary files a/jar-in-jar-loader.zip and /dev/null differ diff --git a/jar/javagame.jar b/jar/javagame.jar deleted file mode 100644 index ec375db..0000000 Binary files a/jar/javagame.jar and /dev/null differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..8692d4b --- /dev/null +++ b/pom.xml @@ -0,0 +1,155 @@ + + + 4.0.0 + com.redomar.game + javagame + Alpha 1.8.7 + JavaGame is a game project that have been working on since May 2013. I have added many features to the game over the last year and I plan on adding even more features. This game is purely for my own sake to practice my skills in Java. + https://github.com/redomar/JavaGame + 2013 + + + GNU AFFERO GENERAL PUBLIC LICENSE 3.0 + https://www.gnu.org/licenses/agpl-3.0.txt + repo + + + + + local-maven-repo + file://${project.basedir}/res/jars + + + + + org.apache.commons + commons-text + 1.11.0 + + + org.apache.commons + commons-lang3 + 3.14.0 + + + org.jetbrains + annotations + 23.1.0 + + + com.thehowtotutorial.splashscreen + JSplashScreen + 1.0 + + + junit + junit + 4.13.2 + test + + + + 21 + 21 + UTF-8 + UTF-8 + + + src + + + res + + + + test + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + false + + ${*} + @ + + UTF-8 + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.6.1 + + + copy-dependencies + prepare-package + + copy-dependencies + + + ${project.build.directory}/lib + false + false + true + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + + true + lib/ + com.redomar.game.Launcher + + + + + + com.thehowtotutorial.splashscreen + JSplashScreen + 1.0 + + + + + org.apache.maven.plugins + maven-install-plugin + 3.1.1 + + + install-external-non-maven-jar-MWS-Client-into-local-maven-repo + clean + + com.thehowtotutorial.splashscreen + JSplashScreen + 1.0 + ${project.basedir}/res/jars/JSplashScreen.jar + jar + true + + + install-file + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 3.5.0 + + + + diff --git a/res/controls/controls.png b/res/controls/controls.png new file mode 100644 index 0000000..c69a4bd Binary files /dev/null and b/res/controls/controls.png differ diff --git a/res/jars/commons-lang3-3.1.jar b/res/jars/commons-lang3-3.1.jar deleted file mode 100644 index a85e539..0000000 Binary files a/res/jars/commons-lang3-3.1.jar and /dev/null differ diff --git a/res/jars/jl1.0.1.jar b/res/jars/jl1.0.1.jar deleted file mode 100644 index bd5fb8b..0000000 Binary files a/res/jars/jl1.0.1.jar and /dev/null differ diff --git a/res/music/Towards The End.wav b/res/music/Towards The End.wav new file mode 100644 index 0000000..70b84dd Binary files /dev/null and b/res/music/Towards The End.wav differ diff --git a/res/music/small.mp3 b/res/music/small.mp3 new file mode 100644 index 0000000..bf24d8a Binary files /dev/null and b/res/music/small.mp3 differ diff --git a/res/music/small.wav b/res/music/small.wav new file mode 100644 index 0000000..a519d5e Binary files /dev/null and b/res/music/small.wav differ diff --git a/res/music/yoshi song.mp3 b/res/music/yoshi song.mp3 deleted file mode 100644 index ed43677..0000000 Binary files a/res/music/yoshi song.mp3 and /dev/null differ diff --git a/res/sprite_sheet.png b/res/sprite_sheet.png index fa82e7f..1279b4e 100644 Binary files a/res/sprite_sheet.png and b/res/sprite_sheet.png differ diff --git a/src/com/redomar/game/Game.java b/src/com/redomar/game/Game.java index d30a402..f5b5709 100644 --- a/src/com/redomar/game/Game.java +++ b/src/com/redomar/game/Game.java @@ -1,231 +1,404 @@ package com.redomar.game; -import java.awt.BorderLayout; -import java.awt.Canvas; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.im.InputContext; -import java.awt.image.BufferStrategy; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; - -import javax.swing.JFrame; -import javax.swing.JOptionPane; - -import org.apache.commons.lang3.text.WordUtils; - +import com.redomar.game.audio.AudioHandler; import com.redomar.game.entities.Dummy; import com.redomar.game.entities.Player; -import com.redomar.game.entities.PlayerMP; import com.redomar.game.entities.Vendor; +import com.redomar.game.entities.trees.Spruce; +import com.redomar.game.event.InputHandler; +import com.redomar.game.event.MouseHandler; import com.redomar.game.gfx.Screen; import com.redomar.game.gfx.SpriteSheet; +import com.redomar.game.gfx.lighting.Night; import com.redomar.game.level.LevelHandler; +import com.redomar.game.lib.Either; import com.redomar.game.lib.Font; -import com.redomar.game.lib.Music; import com.redomar.game.lib.Time; -import com.redomar.game.net.GameClient; -import com.redomar.game.net.GameServer; -import com.redomar.game.net.packets.Packet00Login; -import com.redomar.game.script.PrintTypes; -import com.redomar.game.script.Printing; +import com.redomar.game.log.PrintTypes; +import com.redomar.game.log.Printer; +import org.apache.commons.text.WordUtils; +import javax.swing.*; +import java.awt.*; +import java.awt.im.InputContext; +import java.awt.image.BufferStrategy; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.Serial; + +/* + * This module forms the core architecture of the JavaGame. It coordinates the various + * audio and input handler components, generates the frame, renders the screen graphics, spawns + * NPCs and customizes the player. Game is also responsible for changing the maps and levels, as well + * as displaying various messages on the screen (e.g. fps) + */ public class Game extends Canvas implements Runnable { // Setting the size and name of the frame/canvas + @Serial private static final long serialVersionUID = 1L; - private static final String game_Version = "v1.8.1 Alpha"; - private static final int WIDTH = 160; - private static final int HEIGHT = (WIDTH / 3 * 2); - private static final int SCALE = 3; - private static final String NAME = "Game"; + private static final String game_Version = "v1.8.7 Alpha"; + private static final int SCALE = 100; + private static final int WIDTH = 3 * SCALE; + private static final int SCREEN_WIDTH = WIDTH * 2; + private static final int HEIGHT = (2 * SCALE); + private static final int SCREEN_HEIGHT = (HEIGHT * 2) + 30; + private static final Screen screen = new Screen(WIDTH, HEIGHT, new SpriteSheet("/sprite_sheet.png")); + private static final Screen screen2 = new Screen(WIDTH, HEIGHT, new SpriteSheet("/sprite_sheet.png")); + private static final String NAME = "Game"; // The name of the JFrame panel + private static final Time time = new Time(); // Represents the calendar's time value, in hh:mm:ss + private static final boolean[] alternateCols = new boolean[2]; // Boolean array describing shirt and face colour private static Game game; - private static Time time = new Time(); - private static int Jdata_Host; - private static String Jdata_UserName = ""; - private static String Jdata_IP = "127.0.0.1"; - private static boolean changeLevel = false; - private static boolean npc = false; - private static int map = 0; - private static int shirtCol; - private static int faceCol; - private static boolean[] alternateCols = new boolean[2]; - private static int fps; - private static int tps; + // The properties of the player, npc, and fps/tps + private static boolean changeLevel = false; // Determines whether the player teleports to another level + private static boolean npc = false; // Non-player character (NPC) initialized to non-existing + private static int map = 0; // Map of the level, initialized to map default map + private static int shirtCol; // The colour of the character's shirt + private static int faceCol; // The colour (ethnicity) of the character (their face) + private static int fps; // The frame rate (frames per second), frequency at which images are displayed on the canvas + private static int tps; // The ticks (ticks per second), unit measure of time for one iteration of the game logic loop. private static int steps; - private static boolean devMode; - private static boolean closingMode; - + private static boolean devMode; // Determines whether the game is in developer mode + private static boolean closingMode; // Determines whether the game will exit + private static int tileX = 0; + private static int tileY = 0; + // Audio, input, and mouse handler objects private static JFrame frame; - - private static boolean running = false; + private static AudioHandler backgroundMusic; + private static boolean running = false; // Determines whether the game is currently in process + private static InputHandler input; // Accepts keyboard input and follows the appropriate actions + private static MouseHandler mouse; // Tracks mouse movement and clicks, and follows the appropriate actions + private static InputContext context; // Provides methods to control text input facilities + // Graphics + private final BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB); + private final BufferedImage image3 = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB); + private final int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); // Array of red, green and blue values for each pixel + private final int[] pixels3 = ((DataBufferInt) image3.getRaster().getDataBuffer()).getData(); // Array of red, green and blue values for each pixel + private final int[] colours = new int[6 * 6 * 6]; // Array of 216 unique colours (6 shades of red, 6 of green, and 6 of blue) + private final BufferedImage image2 = new BufferedImage(WIDTH, HEIGHT - 30, BufferedImage.TYPE_INT_RGB); + private final Font font = new Font(); // Font object capable of displaying 2 fonts: Arial and Segoe UI + private final Printer printer = new Printer(); + boolean musicPlaying = false; private int tickCount = 0; - - private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, - BufferedImage.TYPE_INT_RGB); - private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()) - .getData(); - private int[] colours = new int[6 * 6 * 6]; - - private BufferedImage image2 = new BufferedImage(WIDTH, HEIGHT - 30, - BufferedImage.TYPE_INT_RGB); - private Screen screen; - private static InputHandler input; - private static MouseHandler mouse; - private WindowHandler window; - private LevelHandler level; + private LevelHandler level; // Loads and renders levels along with tiles, entities, projectiles and more. + //The entities of the game private Player player; - private Dummy dummy; - private Vendor vendor; - private Music music = new Music(); - private Font font = new Font(); - private Thread musicThread = new Thread(music, "MUSIC"); - private String nowPlaying; - private boolean notActive = true; - private boolean noAudioDevice = false; - private int trigger = 0; - private static GameClient socketClient; - private GameServer socketServer; - private Printing print = new Printing(); - private static InputContext context; + private Dummy dummy; // Dummy NPC follows the player around + private Vendor vendor; // Vendor NPC exhibits random movement and is only found on custom_level /** * @author Redomar - * @version Alpha 1.8.1 */ public Game() { context = InputContext.getInstance(); - setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE)); - setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE)); - setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE)); - setFrame(new JFrame(NAME)); - getFrame().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // The game can only be played in one distinct window size + setMinimumSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT)); + setMaximumSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT)); + setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT)); + + setFrame(new JFrame(NAME)); // Creates the frame with a defined name + getFrame().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Exits the program when user closes the frame getFrame().setLayout(new BorderLayout()); - getFrame().add(this, BorderLayout.CENTER); - getFrame().pack(); + getFrame().add(this, BorderLayout.CENTER); // Centers the canvas inside the JFrame + getFrame().pack(); // Sizes the frame so that all its contents are at or above their preferred sizes getFrame().setResizable(false); - getFrame().setLocationRelativeTo(null); + getFrame().setLocationRelativeTo(null); // Centres the window on the screen getFrame().setVisible(true); + requestFocus(); setDevMode(false); setClosing(false); } - public void init() { - setGame(this); - int index = 0; - for (int r = 0; r < 6; r++) { - for (int g = 0; g < 6; g++) { - for (int b = 0; b < 6; b++) { - int rr = (r * 255 / 5); - int gg = (g * 255 / 5); - int bb = (b * 255 / 5); - colours[index++] = rr << 16 | gg << 8 | bb; - } - } + /** + * This method will spawn a dummy NPC into the level only if they are allowed to be spawned in. + * They will be spawned at position (100, 150) with a red shirt and caucasian face. + */ + public static void npcSpawn() { + // If NPCs are allowed in the level + if (isNpc()) { + // Create a new dummy NPC to the current game level + game.setDummy(new Dummy(game.level, "Dummy", 100, 150, 500, 543)); + game.level.addEntity(Game.getDummy()); } + } - screen = new Screen(WIDTH, HEIGHT, new SpriteSheet("/sprite_sheet.png")); - input = new InputHandler(this); - setMouse(new MouseHandler(this)); - setWindow(new WindowHandler(this)); - setMap("/levels/custom_level.png"); - setMap(1); - Packet00Login loginPacket = new Packet00Login(player.getUsername(), - (int) player.getX(), (int) player.getY()); - - if (socketServer != null) { - socketServer.addConnection((PlayerMP) getPlayer(), loginPacket); + /** + * This method will remove a dummy NPC from the level only if they are not allowed to be in it. + */ + public static void npcKill() { + if (!isNpc()) { // If NPCs are not allowed in the level + game.level.removeEntity(Game.getDummy()); } + } - // socketClient.sendData("ping".getBytes()); - loginPacket.writeData(getSocketClient()); + public static JFrame getFrame() { + return Game.frame; + } - game.setVendor(new Vendor(level, "Vendor", 215, 215, 304, 543)); - level.addEntity(getVendor()); + public static void setFrame(JFrame frame) { + Game.frame = frame; + } + + public static Player getPlayer() { + return game.player; + } + + public void setPlayer(Player player) { + game.player = player; + } + + public static LevelHandler getLevel() { + return game.level; + } + + public void setLevel(LevelHandler level) { + this.level = level; + } + + + public static Game getGame() { + return game; + } + + public static void setGame(Game game) { + Game.game = game; + } + + public static boolean isRunning() { + return running; + } + + public static void setRunning(boolean running) { + Game.running = running; } + public static boolean isChangeLevel() { + return changeLevel; + } + + public static void setChangeLevel(boolean changeLevel) { + Game.changeLevel = changeLevel; + } + + public static int getMap() { + return map; + } + + /** + * Sets the level to the map [.png] provided. Starts at x100 y100. + * + * @param Map_str Also sets predefined character colours. + */ public void setMap(String Map_str) { setLevel(new LevelHandler(Map_str)); - if (alternateCols[0]) { - Game.setShirtCol(240); + if (alternateCols[0]) { // If the first element (shirt colour) is set to True + Game.setShirtCol(240); // The player's shirt colour will be green } - if (!alternateCols[0]) { - Game.setShirtCol(111); + if (!alternateCols[0]) { // If the first element (shirt colour) is set to False + Game.setShirtCol(111); // The player's shirt colour will be black } - if (alternateCols[1]) { - Game.setFaceCol(310); + if (alternateCols[1]) { // If the last element (face colour) is set to True + Game.setFaceCol(310); // The player will be African } - if (!alternateCols[1]) { - Game.setFaceCol(543); + if (!alternateCols[1]) { // If the last element (face colour) is set to False + Game.setFaceCol(543); // The player will be caucasian } - setPlayer(new PlayerMP(level, 100, 100, input, - getJdata_UserName(), null, -1, shirtCol, faceCol)); + setPlayer(new Player(level, 100, 100, input, "", shirtCol, faceCol)); level.addEntity(player); + // Tree -- Spruce + Spruce spruce = new Spruce(level, 70, 170, 2); + level.addEntity(spruce); } - public static void npcSpawn() { - if (isNpc() == true) { - game.setDummy(new Dummy(game.level, "Dummy", 100, 150, 500, - 543)); - game.level.addEntity(Game.getDummy()); - } + public static void setMap(int map) { + Game.map = map; } - public static void npcKill() { - if (isNpc() == false) { - game.level.removeEntity(Game.getDummy()); - } + public static boolean isNpc() { + return npc; } - public synchronized void start() { - Game.setRunning(true); - new Thread(this, "GAME").start(); + public static void setNpc(boolean npc) { + Game.npc = npc; + } + + public static Dummy getDummy() { + return game.dummy; + } + + public void setDummy(Dummy dummy) { + this.dummy = dummy; + } + + public static String getGameVersion() { + return game_Version; + } + + public static int getShirtCol() { + return shirtCol; + } + + public static void setShirtCol(int shirtCol) { + Game.shirtCol = shirtCol; + } + + public static int getFaceCol() { + return faceCol; + } + + public static void setFaceCol(int faceCol) { + Game.faceCol = faceCol; + } + + // Sets ethnicity/face colour for the player + public static void setAlternateColsR(boolean alternateCols) { + Game.alternateCols[1] = alternateCols; + } + + // Sets the shirt colour for the player + public static void setAlternateColsS(boolean alternateCols) { + Game.alternateCols[0] = alternateCols; + } + + public static AudioHandler getBackgroundMusic() { + return Game.backgroundMusic; + } + + public static void setBackgroundMusic(AudioHandler backgroundMusic) { + Game.backgroundMusic = backgroundMusic; + } + + public static MouseHandler getMouse() { + return mouse; + } + + public static void setMouse(MouseHandler mouse) { + Game.mouse = mouse; + } + + public static boolean isDevMode() { + return devMode; + } + + public static void setDevMode(boolean devMode) { + Game.devMode = devMode; + } + + public static boolean isClosing() { + return closingMode; + } + + public static void setClosing(boolean closing) { + Game.closingMode = closing; + } + + private static void mousePositionTracker() { + MouseHandler mouseHandler = Game.getMouse(); + int mouseX = mouseHandler.getX(); + int mouseY = mouseHandler.getY(); + + // Adjust mouse coordinates based on the current offset and scale of the game world + tileX = ((mouseX + 4 + screen.getxOffset()) / (8 * 2)) + screen.getxOffset() / 16; + tileY = ((mouseY + 4 + screen.getyOffset()) / (8 * 2)) + screen.getyOffset() / 16; + } + + public static int getTileX() { + return tileX; + } + + public static int getTileY() { + return tileY; + } + + public static Screen getScreen() { + return screen; + } + + /* + * This method initializes the game once it starts. It populates the colour array with actual colours (6 shades each of RGB). + * This method also builds the initial game level (custom_level), spawns a new vendor NPC, and begins accepting keyboard and mouse input/tracking. + */ + public void init() { + setGame(this); + int index = 0; + for (int r = 0; r < 6; r++) { // For all 6 shades of red + for (int g = 0; g < 6; g++) { // For all 6 shades of green + for (int b = 0; b < 6; b++) { // For all 6 shades of blue + int rr = (r * 255 / 5); // Split all 256 colours into 6 shades (0, 51, 102 ... 255) + int gg = (g * 255 / 5); + int bb = (b * 255 / 5); + // All colour values (RGB) are placed into one 32-bit integer, populating the colour array + // The first 8 bits are for alpha, the next 8 for red, the next 8 for green, and the last 8 for blue + // 0xFF000000 is ignored in BufferedImage.TYPE_INT_RGB, but is used in BufferedImage.TYPE_INT_ARGB + colours[index++] = 0xFF << 24 | rr << 16 | gg << 8 | bb; + } + } + } - if (getJdata_Host() == 0) { - socketServer = new GameServer(this); - socketServer.start(); + screen.setViewPortHeight(SCREEN_HEIGHT); + screen2.setViewPortHeight(SCREEN_HEIGHT); + screen.setViewPortWidth(SCREEN_WIDTH); + screen2.setViewPortWidth(SCREEN_WIDTH); + input = new InputHandler(this); // Input begins to record key presses + setMouse(new MouseHandler(this)); // Mouse tracking and clicking is now recorded +// setWindow(new WindowHandler(this)); + try { + setMap("/levels/custom_level.png"); + } catch (Exception e) { + printer.print(e.toString(), PrintTypes.ERROR); } + setMap(1); // 1 corresponds to custom_level + + game.setVendor(new Vendor(level, "Vendor", 215, 215, 304, 543)); + level.addEntity(getVendor()); + } - setSocketClient(new GameClient(this, getJdata_IP())); - getSocketClient().start(); + /** + * This method will start the game and allow the user to start playing + */ + public synchronized void start() { + Game.setRunning(true); // Game will run + new Thread(this, "GAME").start(); // Thread is an instance of Runnable. Whenever it is started, it will run the run() method } + /** + * This method will stop the game + */ public synchronized void stop() { - Game.setRunning(false); + Game.getBackgroundMusic().close(); + Game.setRunning(false); // Game will not run } + /** + * This method forms the game loop, determining how the game runs. It runs throughout the entire game, + * continuously updating the game state and rendering the game. + */ public void run() { long lastTime = System.nanoTime(); - double nsPerTick = 1000000000D / 60D; - + int nsPerS = 1_000_000_000; + double nsPerTick = nsPerS / 60D; // The number of nanoseconds in one tick (number of ticks limited to 60 per update) + // 1 billion nanoseconds in one second int ticks = 0; int frames = 0; - long lastTimer = System.currentTimeMillis(); + long lastTimer = System.nanoTime(); // Used for updating ticks and frames once every second double delta = 0; - init(); + init(); // Initialize the game environment while (Game.isRunning()) { - long now = System.nanoTime(); - delta += (now - lastTime) / nsPerTick; + long now = System.nanoTime(); // Current time (now) compared to lastTime to calculate elapsed time + delta += (now - lastTime) / nsPerTick; // Elapsed time in seconds multiplied by 60 lastTime = now; boolean shouldRender = false; - while (delta >= 1) { + while (delta >= 1) { // Once 1/60 seconds or more have passed ticks++; - tick(); - delta -= 1; - shouldRender = true; - } - - try { - Thread.sleep(2); - } catch (InterruptedException e) { - e.printStackTrace(); + tick(); // Tick updates + delta -= 1; // Delta becomes less than one again and the loop will close + shouldRender = true; // Limits the frames to 60 per second } if (shouldRender) { @@ -233,26 +406,40 @@ public void run() { render(); } - if (System.currentTimeMillis() - lastTimer >= 1000) { - lastTimer += 1000; - getFrame().setTitle( - "JavaGame - Version " - + WordUtils.capitalize(game_Version).substring( - 1, game_Version.length())); + if (System.nanoTime() - lastTimer >= nsPerS) { // If elapsed time is greater than or equal to 1 second, update + lastTimer += nsPerS; // Updates in another second + getFrame().setTitle("JavaGame - Version " + WordUtils.capitalize(game_Version).substring(1, game_Version.length())); fps = frames; tps = ticks; - frames = 0; - ticks = 0; + frames = 0; // Reset the frames once per second + ticks = 0; // Reset the ticks once per second } } } + /** + * This method updates the logic of the game. + */ public void tick() { setTickCount(getTickCount() + 1); + Either musicKeyAction = input.toggleActionWithCheckedRunnable(input.getM_KEY(), musicPlaying, () -> Game.getBackgroundMusic().play(), () -> Game.getBackgroundMusic().stop()); + musicKeyAction.either(exception -> { + printer.cast().print("Failed to play music", PrintTypes.MUSIC); + printer.exception(exception.toString()); + musicPlaying = false; + }, isPlaying -> { + musicPlaying = isPlaying; + if (musicPlaying && !Game.getBackgroundMusic().getActive()) { + input.overWriteKey(input.getM_KEY(), false); + } + }); level.tick(); } + /** + * This method displays the current state of the game. + */ public void render() { BufferStrategy bs = getBufferStrategy(); if (bs == null) { @@ -260,18 +447,11 @@ public void render() { return; } + int xOffset = (int) getPlayer().getX() - (screen.getWidth() / 2); int yOffset = (int) getPlayer().getY() - (screen.getHeight() / 2); level.renderTiles(screen, xOffset, yOffset); - - /* - * for (int x = 0; x < level.width; x++) { int colour = Colours.get(-1, - * -1, -1, 000); if (x % 10 == 0 && x != 0) { colour = Colours.get(-1, - * -1, -1, 500); } Font.render((x % 10) + "", screen, 0 + (x * 8), 0, - * colour, 1); } - */ - level.renderEntities(screen); level.renderProjectileEntities(screen); @@ -283,34 +463,28 @@ public void render() { } } } - - if (noAudioDevice == false) { - if (input.isPlayMusic() == true && notActive == true) { - int musicOption = JOptionPane.showConfirmDialog(this, - "You are about to turn on music and can be VERY loud", - "Music Options", 2, 2); - if (musicOption == 0) { - musicThread.start(); - notActive = false; - } else { - // System.out.println("[GAME] Canceled music option"); - print.print(" Canceled music option", PrintTypes.GAME); - input.setPlayMusic(false); + for (int y = 0; y < screen2.getHeight(); y++) { + for (int x = 0; x < screen2.getWidth(); x++) { + int colourCode = screen2.getPixels()[x + y * screen2.getWidth()]; + if (colourCode < 1){ + pixels3[x + y * WIDTH] = 0xff0000; + } else if (colourCode < 255) { + pixels3[x + y * WIDTH] = colours[colourCode]; } } } - if (isChangeLevel() == true && getTickCount() % 60 == 0) { + if (isChangeLevel() && getTickCount() % 60 == 0) { Game.setChangeLevel(true); setChangeLevel(false); } - if (changeLevel == true) { - print.print("Teleported into new world", PrintTypes.GAME); + if (changeLevel) { + printer.print("Teleported into new world", PrintTypes.GAME); if (getMap() == 1) { setMap("/levels/water_level.png"); - if (getDummy() != null) { // Gave nullPointerException(); upon - // entering new world. + if (getDummy() != null) { + level.removeEntity(getDummy()); setNpc(false); } @@ -326,66 +500,56 @@ public void render() { changeLevel = false; } - Graphics g = bs.getDrawGraphics(); - g.drawRect(0, 0, getWidth(), getHeight()); + Graphics2D g = (Graphics2D) bs.getDrawGraphics(); g.drawImage(image, 0, 0, getWidth(), getHeight() - 30, null); status(g, isDevMode(), isClosing()); - // Font.render("Hi", screen, 0, 0, Colours.get(-1, -1, -1, 555), 1); + overlayRender(g); g.drawImage(image2, 0, getHeight() - 30, getWidth(), getHeight(), null); g.setColor(Color.WHITE); g.setFont(font.getSegoe()); - g.drawString( - "Welcome " - + WordUtils.capitalizeFully(player - .getSantizedUsername()), 3, getHeight() - 17); + g.drawString("Welcome " + WordUtils.capitalize(player.getName()), 3, getHeight() - 17); g.setColor(Color.ORANGE); - if (context.getLocale().getCountry().equals("BE") - || context.getLocale().getCountry().equals("FR")) { - g.drawString("Press A to quit", (getWidth() / 2) - - ("Press A to quit".length() * 3), getHeight() - 17); + if (context.getLocale().getCountry().equals("BE") || context.getLocale().getCountry().equals("FR")) { + g.drawString("Press A to quit", (getWidth() / 2) - ("Press A to quit".length() * 3), getHeight() - 17); } else { - g.drawString("Press Q to quit", (getWidth() / 2) - - ("Press Q to quit".length() * 3), getHeight() - 17); + g.drawString("Press Q to quit", (getWidth() / 2) - ("Press Q to quit".length() * 3), getHeight() - 17); } + g.setColor(Color.YELLOW); - g.drawString(time.getTime(), (getWidth() - 58), (getHeight() - 3)); - g.setColor(Color.WHITE); - if (noAudioDevice == true) { - g.setColor(Color.RED); - g.drawString("MUSIC is OFF | no audio device for playback", 3, - getHeight() - 3); - trigger++; - if (trigger == 25) { - JOptionPane.showMessageDialog(this, "No Audio device found", - "Audio Issue", 0); - } - } else if (notActive == true) { - g.setColor(Color.RED); - g.drawString("MUSIC is OFF | press 'M' to start", 3, - getHeight() - 3); - } else { - g.setColor(Color.GREEN); - g.drawString("MUSIC is ON | You cannot turn off the music", 3, - getHeight() - 3); - g.setColor(Color.WHITE); - setNowPlaying(WordUtils.capitalize(music.getSongName()[music - .getSongNumber()].substring(7, - (music.getSongName()[music.getSongNumber()].length() - 4)))); - if (getNowPlaying().startsWith("T")) { - g.drawString(nowPlaying, getWidth() - (nowPlaying.length() * 9) - + 12, getHeight() - 17); - } else { - g.drawString(nowPlaying, getWidth() - (nowPlaying.length() * 9) - + 8, getHeight() - 17); - } + g.drawString(time.getTime(), (getWidth() - 63), (getHeight() - 3)); + if (devMode) { + g.setColor(Color.CYAN); + g.drawString("Debug Mode Enabled", (getWidth() - 153), (getHeight() - 17)); + } + g.setColor(Color.GREEN); + + if (backgroundMusic.getActive()) { + g.drawString("MUSIC is ON ", 3, getHeight() - 3); } + g.dispose(); bs.show(); } - private void status(Graphics g, boolean TerminalMode, boolean TerminalQuit) { - if (TerminalMode == true) { + /** + * This method renders the overlay of the game, which is a transparent layer that is drawn over the game. + */ + private void overlayRender(Graphics2D g) { + g.setColor(new Color(0f, 0f, 0f, 0f)); // Transparent color + g.fillRect(0, 0, getWidth(), getHeight()-30); + } + + /* + * This method displays information regarding various aspects/stats of the game, dependent upon + * whether it is running in developer mode, or if the application is closing. + */ + private void status(Graphics2D g, boolean TerminalMode, boolean TerminalQuit) { + if (TerminalMode) { + new Night(g, screen).render(player.getPlayerAbsX(), player.getPlayerAbsY()); + // make the background transparent + g.setColor(new Color(0, 0, 0, 100)); + g.fillRect(0, 0, 195, 165); g.setColor(Color.CYAN); g.drawString("JavaGame Stats", 0, 10); g.drawString("FPS/TPS: " + fps + "/" + tps, 0, 25); @@ -393,80 +557,41 @@ private void status(Graphics g, boolean TerminalMode, boolean TerminalQuit) { steps += 1; } g.drawString("Foot Steps: " + steps, 0, 40); - g.drawString( - "NPC: " + WordUtils.capitalize(String.valueOf(isNpc())), 0, - 55); - g.drawString("Mouse: " + getMouse().getX() + "x |" - + getMouse().getY() + "y", 0, 70); - if (getMouse().getButton() != -1) - g.drawString("Button: " + getMouse().getButton(), 0, 85); - g.setColor(Color.CYAN); - g.fillRect(getMouse().getX() - 12, getMouse().getY() - 12, 24, 24); - } - if (TerminalQuit == true) { - g.setColor(Color.BLACK); - g.fillRect(0, 0, getWidth(), getHeight()); - g.setColor(Color.RED); - g.drawString("Shutting down the Game", (getWidth() / 2) - 70, - (getHeight() / 2) - 8); - g.dispose(); - } - } - - public static JFrame getFrame() { - return Game.frame; - } - - public static void setFrame(JFrame frame) { - Game.frame = frame; - } - - public static GameClient getSocketClient() { - return socketClient; - } - - public void setSocketClient(GameClient socketClient) { - Game.socketClient = socketClient; - } - - public static Player getPlayer() { - return game.player; - } - - public void setPlayer(Player player) { - game.player = player; - } - - public static LevelHandler getLevel() { - return game.level; - } - - public void setLevel(LevelHandler level) { - this.level = level; - } - - public static Time getTime() { - return Game.time; - } - - public void setTime(Time time) { - Game.time = time; - } - - public WindowHandler getWindow() { - return window; - } - - public void setWindow(WindowHandler window) { - this.window = window; - } + g.drawString("NPC: " + WordUtils.capitalize(String.valueOf(isNpc())), 0, 55); + g.drawString("Mouse: " + getMouse().getX() + "x |" + getMouse().getY() + "y", 0, 70); + g.drawString("Mouse: " + (getMouse().getX() - 639 / 2d) + "x |" + (getMouse().getY() - 423 / 2d) + "y", 0, 85); + if (getMouse().getButton() != -1) g.drawString("Button: " + getMouse().getButton(), 0, 100); + mousePositionTracker(); + g.drawString("Player: " + (int) player.getX() + "x |" + (int) player.getY() + "y", 0, 115); + double angle = Math.atan2(getMouse().getY() - player.getPlayerAbsY(), getMouse().getX() - player.getPlayerAbsX()) * (180.0 / Math.PI); + g.drawString("Angle: " + angle, 0, 130); + + g.setColor(Color.cyan); + g.drawString("Player: \t\t\t\t\t\t\t\t\t\t\t\t" + player.getPlayerAbsX() + "x |" + player.getPlayerAbsY() + "y", 0, 145); + g.drawString("Player Offset: \t" + screen.getxOffset() + "x |" + screen.getyOffset() + "y", 0, 160); + + // Set a different color for the player-origin line + g.setStroke(new BasicStroke(1)); + g.setColor(Color.GREEN); // Green for the new line from the player's origin + g.drawLine(player.getPlayerAbsX(), player.getPlayerAbsY(), getMouse().getX(), getMouse().getY()); // Draw the line from the player's origin to the cursor + g.setColor(Color.DARK_GRAY); + g.drawLine(getWidth() / 2 + 8, getHeight() / 2 - 8, getMouse().getX(), getMouse().getY()); // Draw the line from the player's origin to the cursor + g.drawLine(getWidth() / 2 + 8, 0, getWidth() / 2 + 8, getHeight() - 30); + g.drawLine(0, getHeight() / 2 - 8, getWidth(), getHeight() / 2 - 8); + g.setColor(Color.yellow); + g.fillRect(player.getPlayerAbsX(), player.getPlayerAbsY(), 1, 1); - public String getNowPlaying() { - return nowPlaying; - } - public void setNowPlaying(String nowPlaying) { - this.nowPlaying = nowPlaying; + } + // If the game is shutting off + if (!TerminalQuit) { + return; + } + g.setColor(Color.BLACK); + g.fillRect(0, 0, getWidth(), getHeight()); + g.setColor(Color.RED); + g.drawString("Shutting down the Game", (getWidth() / 2) - 70, (getHeight() / 2) - 8); + g.dispose(); } public int getTickCount() { @@ -477,54 +602,6 @@ public void setTickCount(int tickCount) { this.tickCount = tickCount; } - public static Game getGame() { - return game; - } - - public static void setGame(Game game) { - Game.game = game; - } - - public static boolean isRunning() { - return running; - } - - public static void setRunning(boolean running) { - Game.running = running; - } - - public static boolean isChangeLevel() { - return changeLevel; - } - - public static void setChangeLevel(boolean changeLevel) { - Game.changeLevel = changeLevel; - } - - public static int getMap() { - return map; - } - - public static void setMap(int map) { - Game.map = map; - } - - public static boolean isNpc() { - return npc; - } - - public static void setNpc(boolean npc) { - Game.npc = npc; - } - - public static Dummy getDummy() { - return game.dummy; - } - - public void setDummy(Dummy dummy) { - this.dummy = dummy; - } - public Vendor getVendor() { return vendor; } @@ -532,97 +609,4 @@ public Vendor getVendor() { public void setVendor(Vendor vendor) { this.vendor = vendor; } - - public static String getJdata_IP() { - return Jdata_IP; - } - - public static void setJdata_IP(String jdata_IP) { - Jdata_IP = jdata_IP; - } - - public static int getJdata_Host() { - return Jdata_Host; - } - - public static void setJdata_Host(int jdata_Host) { - Jdata_Host = jdata_Host; - } - - public static String getJdata_UserName() { - return Jdata_UserName; - } - - public static void setJdata_UserName(String jdata_UserName) { - Jdata_UserName = jdata_UserName; - } - - public static String getGameVersion() { - return game_Version; - } - - public static int getShirtCol() { - return shirtCol; - } - - public static void setShirtCol(int shirtCol) { - Game.shirtCol = shirtCol; - } - - public static int getFaceCol() { - return faceCol; - } - - public static void setFaceCol(int faceCol) { - Game.faceCol = faceCol; - } - - public static boolean[] getAlternateCols() { - return alternateCols; - } - - public static void setAlternateCols(boolean[] alternateCols) { - Game.alternateCols = alternateCols; - } - - public static void setAternateColsR(boolean alternateCols) { - Game.alternateCols[1] = alternateCols; - } - - public static void setAternateColsS(boolean alternateCols) { - Game.alternateCols[0] = alternateCols; - } - - public static InputHandler getInput() { - return input; - } - - public void setInput(InputHandler input) { - Game.input = input; - } - - public static MouseHandler getMouse() { - return mouse; - } - - public static void setMouse(MouseHandler mouse) { - Game.mouse = mouse; - } - - public static boolean isDevMode() { - return devMode; - } - - public static void setDevMode(boolean devMode) { - Game.devMode = devMode; - } - - public static boolean isClosing() { - return closingMode; - } - - public static void setClosing(boolean closing) { - Game.closingMode = closing; - } - } diff --git a/src/com/redomar/game/InputHandler.java b/src/com/redomar/game/InputHandler.java deleted file mode 100644 index 80e661b..0000000 --- a/src/com/redomar/game/InputHandler.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.redomar.game; - -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.im.InputContext; - -import com.redomar.game.lib.SleepThread; -import com.redomar.game.script.PopUp; -import com.redomar.game.script.PrintTypes; -import com.redomar.game.script.Printing; - -public class InputHandler implements KeyListener { - - private boolean isAzertyCountry; - - public InputHandler(Game game) { - InputContext context = InputContext.getInstance(); - // Important to know wether the keyboard is in Azerty or Qwerty. - // Azerty countries used QZSD instead of WASD keys. - isAzertyCountry = context.getLocale().getCountry().equals("BE") - || context.getLocale().getCountry().equals("FR"); - game.addKeyListener(this); - } - - public class Key { - private int numTimesPressed = 0; - private boolean pressed = false; - - public int getNumTimesPressed() { - return numTimesPressed; - } - - public boolean isPressed() { - return pressed; - } - - public void toggle(boolean isPressed) { - pressed = isPressed; - if (isPressed) { - numTimesPressed++; - } - } - - public void off() { - pressed = false; - numTimesPressed = 0; - } - } - - private Key up = new Key(); - private Key down = new Key(); - private Key left = new Key(); - private Key right = new Key(); - private Printing print = new Printing(); - private boolean PlayMusic = false; - private int map; - private boolean ignoreInput = false; - private PopUp popup = new PopUp(); - - public void keyPressed(KeyEvent e) { - toggleKey(e.getKeyCode(), true); - } - - public void keyReleased(KeyEvent e) { - toggleKey(e.getKeyCode(), false); - } - - public void keyTyped(KeyEvent e) { - - } - - public void toggleKey(int keyCode, boolean isPressed) { - if (isIgnoreInput() == false) { - if (isAzertyCountry) { - if (keyCode == KeyEvent.VK_Z || keyCode == KeyEvent.VK_UP) { - up.toggle(isPressed); - } - - if (keyCode == KeyEvent.VK_Q || keyCode == KeyEvent.VK_LEFT) { - left.toggle(isPressed); - } - } else { - if (keyCode == KeyEvent.VK_W || keyCode == KeyEvent.VK_UP) { - up.toggle(isPressed); - } - - if (keyCode == KeyEvent.VK_A || keyCode == KeyEvent.VK_LEFT) { - left.toggle(isPressed); - } - } - - if (keyCode == KeyEvent.VK_S || keyCode == KeyEvent.VK_DOWN) { - down.toggle(isPressed); - } - - if (keyCode == KeyEvent.VK_D || keyCode == KeyEvent.VK_RIGHT) { - right.toggle(isPressed); - } - } - if (isIgnoreInput() == true) { - up.toggle(false); - down.toggle(false); - left.toggle(false); - right.toggle(false); - } - if (keyCode == KeyEvent.VK_M) { - this.setPlayMusic(true); - } - - if (isAzertyCountry) { - if (keyCode == KeyEvent.VK_W) { - // if (map == 0){ - // Game.getGame().setMap("/levels/water_level.png"); - // map++; - // } else{ - // Game.getGame().setMap("/levels/custom_level.png"); - // map--; - // } - if (Game.getMap() == 2) { - Game.setChangeLevel(true); - Game.setNpc(false); - } - } - } else { - if (keyCode == KeyEvent.VK_Z) { - // if (map == 0){ - // Game.getGame().setMap("/levels/water_level.png"); - // map++; - // } else{ - // Game.getGame().setMap("/levels/custom_level.png"); - // map--; - // } - if (Game.getMap() == 2) { - Game.setChangeLevel(true); - Game.setNpc(false); - } - } - } - if (keyCode == KeyEvent.VK_N) { - if (Game.getPlayer().isMoving()) { - setIgnoreInput(true); - int n = popup.Warn("Stop moving before spawing dummy AI"); - if (n == 0) { - setIgnoreInput(false); - } - return; - } - if (Game.isNpc() == false) { - Game.setNpc(true); - Game.npcSpawn(); - print.print("Dummy has been spawned", PrintTypes.GAME); - } - } - if (keyCode == KeyEvent.VK_K) { - if (Game.isNpc() == true) { - Game.setNpc(false); - Game.npcKill(); - print.print("Dummy has been despawned", PrintTypes.GAME); - } - } - if (isAzertyCountry) { - if (keyCode == KeyEvent.VK_A) { - Game.setClosing(true); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - Game.getLevel().removeEntity( - Game.getPlayer().getSantizedUsername()); - Game.setRunning(false); - Game.getFrame().dispose(); - System.exit(1); - } - } else { - if (keyCode == KeyEvent.VK_Q) { - Game.setClosing(true); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - Game.getLevel().removeEntity( - Game.getPlayer().getSantizedUsername()); - Game.setRunning(false); - Game.getFrame().dispose(); - System.exit(1); - } - } - - if (keyCode == KeyEvent.VK_BACK_QUOTE) { - if (Game.isClosing() == false && Game.isDevMode() == false) { - Game.setDevMode(true); - new Thread(new SleepThread()); - } - } - } - - public void untoggle(boolean toggle) { - this.ignoreInput = toggle; - } - - public int getMap() { - return map; - } - - public void setMap(int map) { - this.map = map; - } - - public boolean isPlayMusic() { - return PlayMusic; - } - - public void setPlayMusic(boolean playMusic) { - PlayMusic = playMusic; - } - - public Key getUp() { - return up; - } - - public void setUp(Key up) { - this.up = up; - } - - public Key getDown() { - return down; - } - - public void setDown(Key down) { - this.down = down; - } - - public Key getLeft() { - return left; - } - - public void setLeft(Key left) { - this.left = left; - } - - public Key getRight() { - return right; - } - - public void setRight(Key right) { - this.right = right; - } - - public boolean isIgnoreInput() { - return ignoreInput; - } - - public void setIgnoreInput(boolean ignoreInput) { - this.ignoreInput = ignoreInput; - } - -} diff --git a/src/com/redomar/game/Launcher.java b/src/com/redomar/game/Launcher.java index 224ac35..784b9f9 100644 --- a/src/com/redomar/game/Launcher.java +++ b/src/com/redomar/game/Launcher.java @@ -2,10 +2,8 @@ import com.redomar.game.menu.Menu; -public class Launcher -{ - public static void main(String[] args) - { +public class Launcher { + public static void main(String[] args) { new Menu().start(); } } diff --git a/src/com/redomar/game/UML.ucls b/src/com/redomar/game/UML.ucls deleted file mode 100644 index 6c9da34..0000000 --- a/src/com/redomar/game/UML.ucls +++ /dev/null @@ -1,1119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/com/redomar/game/audio/AudioHandler.java b/src/com/redomar/game/audio/AudioHandler.java new file mode 100644 index 0000000..695918e --- /dev/null +++ b/src/com/redomar/game/audio/AudioHandler.java @@ -0,0 +1,120 @@ +package com.redomar.game.audio; + +import com.redomar.game.log.PrintTypes; +import com.redomar.game.log.Printer; +import org.jetbrains.annotations.NotNull; + +import javax.sound.sampled.*; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; + +public class AudioHandler { + + public static final Printer musicPrinter = new Printer(PrintTypes.MUSIC); + private Clip clip; + private boolean active = false; + private boolean music = false; + + public AudioHandler(String path) { + check(path); + } + + public AudioHandler(@NotNull File file) { + check(file.toString()); + } + + public AudioHandler(String path, boolean music) { + this.music = music; + check(path); + } + + private void check(String path) { + try { + if (!path.isEmpty()) { + initiate(path); + } else { + throw new NullPointerException(); + } + } catch (NullPointerException e) { + musicPrinter.print("Destination Cannot be empty", PrintTypes.ERROR); + throw e; + } + } + + /** + * Initialises an audio clip by loading an audio file from the specified path. This method sets up the audio stream and prepares the clip for playback. + * + * @param path the relative file path to the audio clip resource. The path must be accessible from the classpath and should not be null. + */ + private void initiate(@NotNull String path) { + try { + InputStream inputStream = new BufferedInputStream(Objects.requireNonNull(AudioHandler.class.getResourceAsStream(path))); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(inputStream); + audioInputStream.mark(Integer.MAX_VALUE); + AudioFormat baseFormat = audioInputStream.getFormat(); + AudioFormat decodeFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16, baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false); + AudioInputStream decodedAudioInputStream = AudioSystem.getAudioInputStream(decodeFormat, audioInputStream); + clip = AudioSystem.getClip(); + clip.open(decodedAudioInputStream); + clip.addLineListener(event -> { + if (event.getType() == LineEvent.Type.STOP) { + stop(); + } + }); + + } catch (IOException e) { + musicPrinter.cast().exception("Audio file not found " + path); + musicPrinter.cast().exception(e.getMessage()); + + } catch (Exception e) { + musicPrinter.print("Audio Failed to initiate", PrintTypes.ERROR); + musicPrinter.cast().exception(e.getMessage()); + } + } + + + public void play() { + try { + if (clip == null) return; + clip.setFramePosition(0); + clip.start(); + if (music) musicPrinter.print("Playing Music"); + active = true; + } catch (Exception e) { + musicPrinter.print("Audio Failed to play", PrintTypes.ERROR); + throw e; + } + } + + public void setVolume(float velocity) throws NullPointerException { + FloatControl volume = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); + volume.setValue(velocity); + } + + public void stop() { + try { + if (clip == null) throw new RuntimeException("Empty clip"); + if (clip.isRunning()) { + clip.stop(); + if (!music) clip.close(); + } + if (music & active) musicPrinter.print("Stopping Music"); + } catch (Exception e) { + musicPrinter.print("Audio Handler Clip not found"); + } finally { + active = false; + } + } + + public void close() { + stop(); + clip.close(); + } + + public boolean getActive() { + return this.active; + } +} diff --git a/src/com/redomar/game/entities/Dummy.java b/src/com/redomar/game/entities/Dummy.java index 6f164f5..9916101 100644 --- a/src/com/redomar/game/entities/Dummy.java +++ b/src/com/redomar/game/entities/Dummy.java @@ -1,43 +1,22 @@ package com.redomar.game.entities; -import java.util.List; - import com.redomar.game.Game; import com.redomar.game.entities.efx.Swim; -import com.redomar.game.gfx.Colours; -import com.redomar.game.gfx.Screen; import com.redomar.game.level.LevelHandler; -import com.redomar.game.level.Node; public class Dummy extends Mob { - private int colour, shirtCol, faceCol; // = Colours.get(-1, 111, 240, 310); - private int tickCount = 0; - private double xa = 0; - private double ya = 0; - private boolean[] swimType; - private int[] swimColour; - private static double speed = 0.75; - private List path = null; - private int time = 0; - private static int[] collisionBoders = {0, 7, 0, 7}; - - private Swim swim; + private static final double SPEED = 0.75; + private static final int[] MOB_TILE = {8, 28}; + private static final int[] COLLISION_BORDERS = {0, 7, 0, 7}; - public Dummy(LevelHandler level, String name, int x, int y, int shirtCol, - int faceCol) { - super(level, name, x, y, speed, collisionBoders); - this.faceCol = faceCol; - this.shirtCol = shirtCol; - this.colour = Colours.get(-1, 111, shirtCol, faceCol); + public Dummy(LevelHandler level, String name, int x, int y, int shirtCol, int faceCol) { + super(level, name, x, y, MOB_TILE, SPEED, COLLISION_BORDERS, shirtCol, faceCol); } public void tick() { + aStarMovementAI((int) getX(), (int) getY(), (int) Game.getPlayer().getX(), (int) Game.getPlayer().getY(), SPEED, this); - //List players = level.getPlayers(this, 8); - aStarMovementAI((int) getX(), (int) getY(), (int) Game.getPlayer().getX(), (int) Game - .getPlayer().getY(), xa, ya, speed, this, path, time); - setSwim(new Swim(level, (int) getX(), (int) getY())); swimType = swim.swimming(isSwimming, isMagma, isMuddy); @@ -49,78 +28,6 @@ public void tick() { } - public void render(Screen screen) { - time++; - int xTile = 8; - int yTile = 28; - int walkingSpeed = 4; - int flipTop = (numSteps >> walkingSpeed) & 1; - int flipBottom = (numSteps >> walkingSpeed) & 1; - - if (movingDir == 1) { - xTile += 2; - if (!isMoving || swim.isActive(swimType)){ - yTile -= 2; - } - } else if (movingDir == 0 && !isMoving || movingDir == 0 && swim.isActive(swimType)) { - yTile -= 2; - } else if (movingDir > 1) { - xTile += 4 + ((numSteps >> walkingSpeed) & 1) * 2; - flipTop = (movingDir - 1) % 2; - if(!isMoving){ - xTile = 4; - } - } - - int modifier = 8 * scale; - int xOffset = (int) getX() - modifier / 2; - int yOffset = (int) getY() - modifier / 2 - 4; - - if (isSwimming || isMagma || isMuddy) { - swimColour = swim.waveCols(isSwimming, isMagma, isMuddy); - - int waterColour = 0; - yOffset += 4; - - colour = Colours.get(-1, 111, -1, faceCol); - - if (tickCount % 60 < 15) { - waterColour = Colours.get(-1, -1, swimColour[0], -1); - } else if (15 <= tickCount % 60 && tickCount % 60 < 30) { - yOffset--; - waterColour = Colours.get(-1, swimColour[1], swimColour[2], -1); - } else if (30 <= tickCount % 60 && tickCount % 60 < 45) { - waterColour = Colours.get(-1, swimColour[2], -1, swimColour[1]); - } else { - yOffset--; - waterColour = Colours.get(-1, -1, swimColour[1], swimColour[2]); - } - - screen.render(xOffset, yOffset + 3, 31 + 31 * 32, waterColour, - 0x00, 1); - screen.render(xOffset + 8, yOffset + 3, 31 + 31 * 32, waterColour, - 0x01, 1); - } - - screen.render((xOffset + (modifier * flipTop)), yOffset, - (xTile + yTile * 32), colour, flipTop, scale); - screen.render((xOffset + modifier - (modifier * flipTop)), yOffset, - ((xTile + 1) + yTile * 32), colour, flipTop, scale); - if (!isSwimming && !isMagma && !isMuddy) { - screen.render((xOffset + (modifier * flipBottom)), - (yOffset + modifier), (xTile + (yTile + 1) * 32), colour, - flipBottom, scale); - screen.render((xOffset + modifier - (modifier * flipBottom)), - (yOffset + modifier), ((xTile + 1) + (yTile + 1) * 32), - colour, flipBottom, scale); - colour = Colours.get(-1, 111, shirtCol, faceCol); - } - } - - public Swim getSwim() { - return swim; - } - public void setSwim(Swim swim) { this.swim = swim; } diff --git a/src/com/redomar/game/entities/Entity.java b/src/com/redomar/game/entities/Entity.java index c423d44..7bb9a82 100644 --- a/src/com/redomar/game/entities/Entity.java +++ b/src/com/redomar/game/entities/Entity.java @@ -2,12 +2,16 @@ import com.redomar.game.gfx.Screen; import com.redomar.game.level.LevelHandler; +import com.redomar.game.log.PrintTypes; +import com.redomar.game.log.Printer; public abstract class Entity { protected double x, y; + protected int xTile, yTile; protected String name; protected LevelHandler level; + protected Printer entityPrinter = new Printer(PrintTypes.ENTITY); public Entity(LevelHandler level) { init(level); @@ -19,6 +23,8 @@ public final void init(LevelHandler level) { public abstract void tick(); + public abstract void render(Screen screen, int xTile, int yTile); + public abstract void render(Screen screen); public double getX() { @@ -44,4 +50,20 @@ public String getName() { public void setName(String name) { this.name = name; } + + public int getXTile() { + return xTile; + } + + public void setXTile(int xTile) { + this.xTile = xTile; + } + + public int getYTile() { + return yTile; + } + + public void setYTile(int yTile) { + this.yTile = yTile; + } } diff --git a/src/com/redomar/game/entities/Mob.java b/src/com/redomar/game/entities/Mob.java index eec7b8a..1c71e05 100644 --- a/src/com/redomar/game/entities/Mob.java +++ b/src/com/redomar/game/entities/Mob.java @@ -1,19 +1,27 @@ package com.redomar.game.entities; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import com.redomar.game.entities.projectiles.Medium; +import com.redomar.game.Game; +import com.redomar.game.entities.efx.Swim; +import com.redomar.game.entities.efx.WaterType; import com.redomar.game.entities.projectiles.Projectile; import com.redomar.game.entities.projectiles.Small; +import com.redomar.game.gfx.Colours; +import com.redomar.game.gfx.Screen; import com.redomar.game.level.LevelHandler; import com.redomar.game.level.Node; import com.redomar.game.level.tiles.Tile; +import com.redomar.game.lib.Font; import com.redomar.game.lib.utils.Vector2i; +import com.redomar.game.objects.Inventory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; public abstract class Mob extends Entity { + protected final int shirtColour; + protected final int faceColour; protected Random random = new Random(); protected double speed; protected int numSteps = 0; @@ -24,24 +32,34 @@ public abstract class Mob extends Entity { protected boolean isMagma = false; protected boolean isMuddy = false; protected boolean changeLevels = false; - protected int ticker; + protected boolean showName = false; /** * [0] Contains the xMin
* [1] Contains the xMax
* [2] Contains the yMin
* [3] Contains the yMax */ - protected int[] collisionBoders = new int[4]; - - protected List projectiles = new ArrayList(); + protected int[] collisionBorders; - public Mob(LevelHandler level, String name, int x, int y, double speed, int[] collisionBoders) { + protected List projectiles = new ArrayList<>(); + protected int colour; + protected int tickCount = 0; + protected Swim swim; + protected boolean[] swimType; + + + public Mob(LevelHandler level, String name, int x, int y, int[] tile, double speed, int[] collisionBorders, int shirtColour, int faceColour) { super(level); this.name = name; this.setX(x); this.setY(y); + this.setXTile(tile[0]); + this.setYTile(tile[1]); this.speed = speed; - this.collisionBoders = collisionBoders; + this.collisionBorders = collisionBorders; + this.shirtColour = shirtColour; + this.faceColour = faceColour; + this.colour = Colours.get(-1, 111, shirtColour, faceColour); } public void move(double xa, double ya) { @@ -52,13 +70,13 @@ public void move(double xa, double ya) { return; } numSteps++; - + //Moving Directions //0 = Facing UP //1 = Facing Down //2 = Facing Left //3 = Facing Right - + if (ya < 0) { movingDir = 0; } @@ -72,84 +90,65 @@ public void move(double xa, double ya) { movingDir = 3; } - while (xa != 0){ - if (Math.abs(xa) > 1){ - if (!hasCollided(abs(xa), ya)) { + while (xa != 0) { + if (Math.abs(xa) > 1) { + if (hasCollided(abs(xa), ya)) { this.x += abs(xa); } xa -= abs(xa); } else { - if (!hasCollided(abs(xa), ya)) { + if (hasCollided(abs(xa), ya)) { this.x += xa; } xa = 0; } } - - while (ya != 0){ - if (Math.abs(ya) > 1){ - if (!hasCollided(xa, abs(ya))) { + + while (ya != 0) { + if (Math.abs(ya) > 1) { + if (hasCollided(xa, abs(ya))) { this.y += abs(ya); } ya -= abs(ya); } else { - if (!hasCollided(xa, abs(ya))) { + if (hasCollided(xa, abs(ya))) { this.y += ya; } ya = 0; } } - + } - public boolean hasCollided(double xa, double ya){ - int xMin = collisionBoders[0]; - int xMax = collisionBoders[1]; - int yMin = collisionBoders[2]; - int yMax = collisionBoders[3]; + public boolean hasCollided(double xa, double ya) { + int xMin = collisionBorders[0]; + int xMax = collisionBorders[1]; + int yMin = collisionBorders[2]; + int yMax = collisionBorders[3]; for (int x = xMin; x < xMax; x++) { if (isSolid((int) xa, (int) ya, x, yMin)) { - return true; + return false; } - } - - for (int x = xMin; x < xMax; x++) { if (isSolid((int) xa, (int) ya, x, yMax)) { - return true; + return false; } } for (int y = yMin; y < yMax; y++) { if (isSolid((int) xa, (int) ya, xMin, y)) { - return true; + return false; } - } - - for (int y = yMin; y < yMax; y++) { if (isSolid((int) xa, (int) ya, xMax, y)) { - return true; + return false; } } - return false; + return true; } - - public boolean hasCollidedAlt(int xa, int ya){ - boolean solid = false; - for (int c = 0; c < 4; c++) { - double xt = ((x + xa) - c % 2 * 8) / 8; - double yt = ((y + ya) - c / 2 * 8) / 8; - int ix = (int) Math.ceil(xt); - int iy = (int) Math.ceil(yt); - if (c % 2 == 0) ix = (int) Math.floor(xt); - if (c / 2 == 0) iy = (int) Math.floor(yt); - if(level.getTile(ix, iy).isSolid()) solid = true; - } - return solid; - } - - private int abs(double i){ + + @Deprecated + private int abs(double i) { if (i < 0) return -1; return 1; } @@ -160,52 +159,42 @@ protected boolean isSolid(int xa, int ya, int x, int y) { return false; } - Tile lastTile = level.getTile(((int) this.getX() + x) >> 3, - ((int) this.getY() + y) >> 3); - Tile newtTile = level.getTile(((int) this.getX() + x + xa) >> 3, ((int) this.getY() - + y + ya) >> 3); + Tile lastTile = level.getTile(((int) this.getX() + x) >> 3, ((int) this.getY() + y) >> 3); + Tile newtTile = level.getTile(((int) this.getX() + x + xa) >> 3, ((int) this.getY() + y + ya) >> 3); - if (!lastTile.equals(newtTile) && newtTile.isSolid()) { - return true; - } + return !lastTile.equals(newtTile) && newtTile.isSolid(); - return false; } - - protected void aStarMovementAI(int x, int y, int px, int py, double xa, - double ya, double speed, Mob mob, List path, int time){ - xa = 0; - ya = 0; + + protected void aStarMovementAI(int x, int y, int px, int py, double speed, Mob mob) { + double xa = 0; + double ya = 0; Vector2i start = new Vector2i(x >> 3, y >> 3); Vector2i goal = new Vector2i(px >> 3, py >> 3); - path = level.findPath(start, goal); - if(path != null) { - if(path.size() > 0){ + List path = level.findPath(start, goal); + if (path != null) { + if (path.size() > 0) { Vector2i vector = path.get(path.size() - 1).tile; - if(x < vector.getX() << 3) xa =+ speed; - if(x > vector.getX() << 3) xa =- speed; - if(y < vector.getY() << 3) ya =+ speed; - if(y > vector.getY() << 3) ya =- speed; + if (x < vector.getX() << 3) xa = speed; + if (x > vector.getX() << 3) xa = -speed; + if (y < vector.getY() << 3) ya = speed; + if (y > vector.getY() << 3) ya = -speed; moveMob(xa, ya, mob); } } } - protected void followMovementAI(int x, int y, int px, int py, double xa, - double ya, double speed, Mob mob) { - ya = 0; - xa = 0; - if (px > x) - xa+=speed; - if (px < x) - xa-=speed; - if (py > y) - ya+=speed; - if (py < y) - ya-=speed; + @SuppressWarnings("unused") + protected void followMovementAI(int x, int y, int px, int py, double speed, Mob mob) { + double ya = 0; + double xa = 0; + if (px > x) xa += speed; + if (px < x) xa -= speed; + if (py > y) ya += speed; + if (py < y) ya -= speed; moveMob(xa, ya, mob); } - + protected double[] randomMovementAI(double x, double y, double xa, double ya, int tick) { if (tick % (random.nextInt(50) + 30) == 0) { xa = random.nextInt(3) - 1; @@ -215,11 +204,13 @@ protected double[] randomMovementAI(double x, double y, double xa, double ya, in ya = 0; } } - if(x <= 180){ + if (x <= 180) { xa = 1; + } + if (y <= 180) { ya = -1; } - double move[] = new double[2]; + double[] move = new double[2]; move[0] = xa; move[1] = ya; return move; @@ -233,17 +224,10 @@ protected void moveMob(double xa, double ya, Mob mob) { mob.isMoving = false; } } - - protected void shoot(double x, double y, double dir, double buttonId, boolean secondry){ -// dir = dir * (180 /Math.PI); -// Printing print = new Printing(); -// print.print("Angle: "+ dir, PrintTypes.GAME); - if(buttonId == 1){ - Projectile p = new Small(level, (int) x,(int) y, dir); - projectiles.add(p); - level.addProjectileEntities(p); - } else if(buttonId == 3 && secondry == true){ - Projectile p = new Medium(level, (int) x,(int) y, dir); + + protected void shoot(double x, double y, double dir, double buttonId) { + if (buttonId == 1) { + Projectile p = new Small(level, (int) x, (int) y, dir); projectiles.add(p); level.addProjectileEntities(p); } @@ -253,24 +237,109 @@ public String getName() { return name; } + public int getNumSteps() { + return numSteps; + } + public void setNumSteps(int numSteps) { this.numSteps = numSteps; } - public int getNumSteps() { - return numSteps; + public void setSwim(Swim swim) { + this.swim = swim; } public void setMoving(boolean isMoving) { this.isMoving = isMoving; } - - public boolean isMoving(){ - return this.isMoving; - } public void setMovingDir(int movingDir) { this.movingDir = movingDir; } + @Override + public void render(Screen screen) { + int xTile = getXTile(); + int yTile = getYTile(); + int modifier = 8 * scale; + int xOffset = (int) getX() - modifier / 2; + int yOffset = (int) getY() - modifier / 2 - 4; + int walkingSpeed = 4; + int flipTop = (numSteps >> walkingSpeed) & 1; + int flipBottom = (numSteps >> walkingSpeed) & 1; + + Inventory.activate(); + + if (movingDir == 1) { + xTile += 2; + if (!isMoving || swim.isActive(swimType)) { + yTile -= 2; + } + } else if (movingDir == 0 && !isMoving || movingDir == 0 && swim.isActive(swimType)) { + yTile -= 2; + } else if (movingDir > 1) { + xTile += 4 + ((numSteps >> walkingSpeed) & 1) * 2; + flipTop = (movingDir - 1) % 2; + if (!isMoving) { + xTile = 4; + } + } + + if (changeLevels) { + Game.setChangeLevel(true); + } + + WaterType type = isSwimming ? WaterType.SWIMMING : isMagma ? WaterType.MAGMA : isMuddy ? WaterType.SWAMP : null; + if (type != null) { + int[] swimColour = swim.waveCols(type); + + int waterColour; + yOffset += 4; + + colour = Colours.get(-1, 111, -1, faceColour); + + if (tickCount % 60 < 15) { + waterColour = Colours.get(-1, -1, swimColour[0], -1); + } else if (tickCount % 60 < 30) { + yOffset--; + waterColour = Colours.get(-1, swimColour[1], swimColour[2], -1); + } else if (tickCount % 60 < 45) { + waterColour = Colours.get(-1, swimColour[2], -1, swimColour[1]); + } else { + yOffset--; + waterColour = Colours.get(-1, -1, swimColour[1], swimColour[2]); + } + + screen.render(xOffset, yOffset + 3, 31 + 31 * 32, waterColour, 0x00, 1); + screen.render(xOffset + 8, yOffset + 3, 31 + 31 * 32, waterColour, 0x01, 1); + } + + screen.render((xOffset + (modifier * flipTop)), yOffset, (xTile + yTile * 32), colour, flipTop, scale); + screen.render((xOffset + modifier - (modifier * flipTop)), yOffset, ((xTile + 1) + yTile * 32), colour, flipTop, scale); + if (!isSwimming && !isMagma && !isMuddy) { + screen.render((xOffset + (modifier * flipBottom)), (yOffset + modifier), (xTile + (yTile + 1) * 32), colour, flipBottom, scale); + screen.render((xOffset + modifier - (modifier * flipBottom)), (yOffset + modifier), ((xTile + 1) + (yTile + 1) * 32), colour, flipBottom, scale); + colour = Colours.get(-1, 111, shirtColour, faceColour); + } + + if (name != null && showName) { + /* + * Improved name centering above player's sprite. + * Using player's own x value cast to int with an adjusted formula + * -posmicanomaly + */ + + int fontCharSize = 8; + int offsetUnit = ((name.length() & 1) == 0 ? fontCharSize / 2 : 0); + int nameOffset = (name.length() / 2) * fontCharSize - offsetUnit; + Font.render(name, screen, (int) x - nameOffset, yOffset - 10, Colours.get(-1, -1, -1, 111), 1); + + } + } + + public void render(Screen screen, int xTile, int yTile) { + setXTile(xTile); + setYTile(yTile); + render(screen); + } } diff --git a/src/com/redomar/game/entities/Player.java b/src/com/redomar/game/entities/Player.java index dc406ff..59caf87 100644 --- a/src/com/redomar/game/entities/Player.java +++ b/src/com/redomar/game/entities/Player.java @@ -1,89 +1,95 @@ package com.redomar.game.entities; import com.redomar.game.Game; -import com.redomar.game.InputHandler; import com.redomar.game.entities.efx.Swim; import com.redomar.game.entities.projectiles.Medium; import com.redomar.game.entities.projectiles.Projectile; import com.redomar.game.entities.projectiles.Small; -import com.redomar.game.gfx.Colours; -import com.redomar.game.gfx.Screen; +import com.redomar.game.event.InputHandler; import com.redomar.game.level.LevelHandler; -import com.redomar.game.lib.Font; -import com.redomar.game.lib.Name; -import com.redomar.game.net.packets.Packet02Move; -import com.redomar.game.objects.Inventory; +import com.redomar.game.lib.HashGen; -public class Player extends Mob { +import java.util.Objects; - private InputHandler input; - private static Name customeName = new Name(); - private Swim swim; +public class Player extends Mob { + private static final String PLAYER_ID = new HashGen(false, 3).getHash(); + private static final int[] PLAYER_TILE = {0, 28}; + private static final int[] COLLISION_BORDERS = {-2, 8, 0, 7}; private static double speed = 1; - - private int colour, shirtCol, faceCol; - private int tickCount = 0; - private String userName; - private boolean[] swimType; - private int[] swimColour; - private static int[] collisionBoders = {-2, 8, 0, 7}; - private int fireRate = 0; - - public static String guestPlayerName = customeName.setName("Player "); - - public Player(LevelHandler level, int x, int y, InputHandler input, - String userName, int shirtCol, int faceCol) { - super(level, "Player", x, y, speed, collisionBoders); - this.input = input; - this.userName = userName; - this.faceCol = faceCol; - this.shirtCol = shirtCol; - this.colour = Colours.get(-1, 111, shirtCol, faceCol); + private final InputHandler inputHandler; + private int fireRate; + private int playerAbsX; + private int playerAbsY; + + public Player(LevelHandler level, int x, int y, InputHandler inputHandler, String name, int shirtColour, int faceColour) { + super(level, "Player", x, y, PLAYER_TILE, speed, COLLISION_BORDERS, shirtColour, faceColour); + this.inputHandler = inputHandler; + this.name = !Objects.equals(name, "") ? name : String.format("Player %s", PLAYER_ID); fireRate = Small.FIRE_RATE; + showName = true; } public void tick() { double xa = 0; double ya = 0; - if (input != null) { - if (input.getUp().isPressed() && input.isIgnoreInput() == false) { + // Calculate and set player's absolute X and Y positions + setPlayerAbsX((((int) getX() - Game.getScreen().getxOffset()) * 2) + 8); + setPlayerAbsY((((int) getY() - Game.getScreen().getyOffset()) * 2) + 7); + + + if (inputHandler != null) { + + speed = inputHandler.getSHIFTED().isPressed() ? 2.5D : 1D; + + if (inputHandler.getUP_KEY().isPressed()) { ya -= speed; } - if (input.getDown().isPressed() && input.isIgnoreInput() == false) { + if (inputHandler.getDOWN_KEY().isPressed()) { ya += speed; } - if (input.getLeft().isPressed() && input.isIgnoreInput() == false) { + if (inputHandler.getLEFT_KEY().isPressed()) { xa -= speed; } - if (input.getRight().isPressed() && input.isIgnoreInput() == false) { + if (inputHandler.getRIGHT_KEY().isPressed()) { xa += speed; } } - - if(fireRate > 0) fireRate--; - - if (Game.getMouse().getButton() == 1 || Game.getMouse().getButton() == 3){ - if(fireRate <= 0){ - if(Game.getMouse().getButton()== 1){ - fireRate = Small.FIRE_RATE; - }else if(Game.getMouse().getButton() == 3){ + + if (fireRate > 0) fireRate--; + + if (Game.getMouse().getButton() == 1 || Game.getMouse().getButton() == 3) { + if (fireRate <= 0) { + if (Game.getMouse().getButton() == 1) { + fireRate = Small.FIRE_RATE; + } else if (Game.getMouse().getButton() == 3) { fireRate = Medium.FIRE_RATE; } - if(!swim.isActive(swimType)){ - double dx = Game.getMouse().getX() - 480/2; - double dy = Game.getMouse().getY() - 320/2; + if (!swim.isActive(swimType)) { + + // Cursor position + int cursorX = Game.getMouse().getX(); + int cursorY = Game.getMouse().getY(); + + // Calculate differences (dx, dy) between cursor and origin + double dx = cursorX - playerAbsX; + double dy = cursorY - playerAbsY; + + // Calculate direction using atan2 double dir = Math.atan2(dy, dx); - shoot(x, y, dir, Game.getMouse().getButton(), false); - } + + // Continue with shooting logic + shoot(x, y, dir, Game.getMouse().getButton()); + + entityPrinter.highlight().print("Direction: " + dir + "º\t" + dx + "x\t" + dy + "y"); + } } } - - for (int i = 0; i < projectiles.size(); i++) { - Projectile p = projectiles.get(i); - if(p.isRemoved()){ - projectiles.remove(i); + + for (Projectile p : projectiles) { + if (p.isRemoved()) { + p.remove(); Game.getLevel().removeProjectileEntities(p); } } @@ -91,18 +97,11 @@ public void tick() { if (xa != 0 || ya != 0) { move(xa, ya); isMoving = true; - - Packet02Move packet = new Packet02Move(this.getUsername(), - (int) this.getX(), (int) this.getY(), this.numSteps, this.isMoving, - this.movingDir); - Game.getGame(); - packet.writeData(Game.getSocketClient()); - } else { isMoving = false; } - setSwim(new Swim(level, (int) getX(), (int) getY())); + swim = new Swim(level, (int) getX(), (int) getY()); swimType = swim.swimming(isSwimming, isMagma, isMuddy); isSwimming = swimType[0]; isMagma = swimType[1]; @@ -115,128 +114,29 @@ public void tick() { tickCount++; } - public void render(Screen screen) { - int xTile = 0; - int yTile = 28; - int walkingSpeed = 4; - int flipTop = (numSteps >> walkingSpeed) & 1; - int flipBottom = (numSteps >> walkingSpeed) & 1; - - Inventory.activate(); - - if (movingDir == 1) { - xTile += 2; - if (!isMoving || swim.isActive(swimType)){ - yTile -= 2; - } - } else if (movingDir == 0 && !isMoving || movingDir == 0 && swim.isActive(swimType)) { - yTile -= 2; - } else if (movingDir > 1) { - xTile += 4 + ((numSteps >> walkingSpeed) & 1) * 2; - flipTop = (movingDir - 1) % 2; - if(!isMoving){ - xTile = 4; - } - } - - int modifier = 8 * scale; - int xOffset = (int) getX() - modifier / 2; - int yOffset = (int) getY() - modifier / 2 - 4; - - if (changeLevels) { - Game.setChangeLevel(true); - } - - if(isSwimming || isMagma || isMuddy){ - swimColour = swim.waveCols(isSwimming, isMagma, isMuddy); - - int waterColour = 0; - yOffset += 4; - - colour = Colours.get(-1, 111, -1, faceCol); - - if (tickCount % 60 < 15) { - waterColour = Colours.get(-1, -1, swimColour[0], -1); - } else if (15 <= tickCount % 60 && tickCount % 60 < 30) { - yOffset--; - waterColour = Colours.get(-1, swimColour[1], swimColour[2], -1); - } else if (30 <= tickCount % 60 && tickCount % 60 < 45) { - waterColour = Colours.get(-1, swimColour[2], -1, swimColour[1]); - } else { - yOffset--; - waterColour = Colours.get(-1, -1, swimColour[1], swimColour[2]); - } - - screen.render(xOffset, yOffset + 3, 31 + 31 * 32, waterColour, - 0x00, 1); - screen.render(xOffset + 8, yOffset + 3, 31 + 31 * 32, waterColour, - 0x01, 1); - } - - screen.render((xOffset + (modifier * flipTop)), yOffset, - (xTile + yTile * 32), colour, flipTop, scale); - screen.render((xOffset + modifier - (modifier * flipTop)), yOffset, - ((xTile + 1) + yTile * 32), colour, flipTop, scale); - if (!isSwimming && !isMagma && !isMuddy) { - screen.render((xOffset + (modifier * flipBottom)), - (yOffset + modifier), (xTile + (yTile + 1) * 32), colour, - flipBottom, scale); - screen.render((xOffset + modifier - (modifier * flipBottom)), - (yOffset + modifier), ((xTile + 1) + (yTile + 1) * 32), - colour, flipBottom, scale); - colour = Colours.get(-1, 111, shirtCol, faceCol); - ; - } - - if (userName != null) { - /* - * Improved userName centering above player's sprite. - * Using player's own x value cast to int with an adjusted formula - * -posmicanomaly - */ - int fontCharSize = 8; - Font.render(userName, - screen, - (int)x - ((userName.length() /2) * fontCharSize), - yOffset - 10, - Colours.get(-1, -1, -1, 555), 1); - - } - } - + @Deprecated public String getUsername() { - if (this.userName.isEmpty()) { - return guestPlayerName; - } - return this.userName; - } - - public void setUsername(String name) { - this.userName = name; + return this.name; } - public String getSantizedUsername() { - if (this.getUsername() == null || this.userName.isEmpty()) { - setUsername(guestPlayerName); - return guestPlayerName; - } else - return this.getUsername(); + @Deprecated + public String getSanitisedUsername() { + return this.name; } - public Swim getSwim() { - return swim; + public int getPlayerAbsX() { + return playerAbsX; } - public void setSwim(Swim swim) { - this.swim = swim; + public void setPlayerAbsX(int playerAbsX) { + this.playerAbsX = playerAbsX; } - public static double getSpeed() { - return speed; + public int getPlayerAbsY() { + return playerAbsY; } - public static void setSpeed(double speed) { - Player.speed = speed; + public void setPlayerAbsY(int playerAbsY) { + this.playerAbsY = playerAbsY; } - } diff --git a/src/com/redomar/game/entities/PlayerMP.java b/src/com/redomar/game/entities/PlayerMP.java index f45142b..14d4cdd 100644 --- a/src/com/redomar/game/entities/PlayerMP.java +++ b/src/com/redomar/game/entities/PlayerMP.java @@ -1,26 +1,25 @@ package com.redomar.game.entities; -import java.net.InetAddress; - -import com.redomar.game.InputHandler; +import com.redomar.game.event.InputHandler; import com.redomar.game.level.LevelHandler; +import java.net.InetAddress; + +@Deprecated public class PlayerMP extends Player { - public InetAddress ipAddess; + public InetAddress ipAddress; public int port; - public PlayerMP(LevelHandler level, int x, int y, InputHandler input, - String userName, InetAddress ipAddress, int port, int shirtCol, int faceCol) { + public PlayerMP(LevelHandler level, int x, int y, InputHandler input, String userName, InetAddress ipAddress, int port, int shirtCol, int faceCol) { super(level, x, y, input, userName, shirtCol, faceCol); - this.ipAddess = ipAddress; + this.ipAddress = ipAddress; this.port = port; } - public PlayerMP(LevelHandler level, int x, int y, String userName, - InetAddress ipAddress, int port, int shirtCol, int faceCol) { + public PlayerMP(LevelHandler level, int x, int y, String userName, InetAddress ipAddress, int port, int shirtCol, int faceCol) { super(level, x, y, null, userName, shirtCol, faceCol); - this.ipAddess = ipAddress; + this.ipAddress = ipAddress; this.port = port; } diff --git a/src/com/redomar/game/entities/Vendor.java b/src/com/redomar/game/entities/Vendor.java index bf47887..e377ae6 100644 --- a/src/com/redomar/game/entities/Vendor.java +++ b/src/com/redomar/game/entities/Vendor.java @@ -1,48 +1,30 @@ package com.redomar.game.entities; -import java.util.List; - import com.redomar.game.entities.efx.Swim; -import com.redomar.game.gfx.Colours; -import com.redomar.game.gfx.Screen; import com.redomar.game.level.LevelHandler; -import com.redomar.game.level.Node; public class Vendor extends Mob { - private int colour, shirtCol, faceCol; // = Colours.get(-1, 111, 240, 310); - private int tickCount = 0; + private static final double SPEED = 0.75; + private static final int[] MOB_TILE = {0, 28}; + private static final int[] COLLISION_BORDERS = {0, 7, 0, 7}; private int tick = 0; private double xa = 0; private double ya = 0; - private double[] movement; - private boolean[] swimType; - private int[] swimColour; - private static double speed = 0.75; - private List path = null; - private int time = 0; - private static int[] collisionBoders = {0, 7, 0, 7}; - - private Swim swim; - public Vendor(LevelHandler level, String name, int x, int y, int shirtCol, - int faceCol) { - super(level, name, x, y, speed, collisionBoders); - this.faceCol = faceCol; - this.shirtCol = shirtCol; - this.colour = Colours.get(-1, 111, shirtCol, faceCol); + public Vendor(LevelHandler level, String name, int x, int y, int shirtCol, int faceCol) { + super(level, name, x, y, MOB_TILE, SPEED, COLLISION_BORDERS, shirtCol, faceCol); } public void tick() { - tick++; - movement = randomMovementAI(x, y, xa, ya, tick); - + double[] movement = randomMovementAI(x, y, xa, ya, tick); + this.xa = movement[0]; this.ya = movement[1]; - + moveMob(xa, ya, this); - + setSwim(new Swim(level, (int) getX(), (int) getY())); swimType = swim.swimming(isSwimming, isMagma, isMuddy); isSwimming = swimType[0]; @@ -50,98 +32,6 @@ public void tick() { isMuddy = swimType[2]; tickCount++; - - } - - public void render(Screen screen) { - setTime(time + 1); - int xTile = 8; - int yTile = 28; - int walkingSpeed = 4; - int flipTop = (numSteps >> walkingSpeed) & 1; - int flipBottom = (numSteps >> walkingSpeed) & 1; - - if (movingDir == 1) { - xTile += 2; - if (!isMoving || swim.isActive(swimType)){ - yTile -= 2; - } - } else if (movingDir == 0 && !isMoving || movingDir == 0 && swim.isActive(swimType)) { - yTile -= 2; - } else if (movingDir > 1) { - xTile += 4 + ((numSteps >> walkingSpeed) & 1) * 2; - flipTop = (movingDir - 1) % 2; - if(!isMoving){ - xTile = 4; - } - } - - int modifier = 8 * scale; - int xOffset = (int) getX() - modifier / 2; - int yOffset = (int) getY() - modifier / 2 - 4; - - if (isSwimming || isMagma || isMuddy) { - swimColour = swim.waveCols(isSwimming, isMagma, isMuddy); - - int waterColour = 0; - yOffset += 4; - - colour = Colours.get(-1, 111, -1, faceCol); - - if (tickCount % 60 < 15) { - waterColour = Colours.get(-1, -1, swimColour[0], -1); - } else if (15 <= tickCount % 60 && tickCount % 60 < 30) { - yOffset--; - waterColour = Colours.get(-1, swimColour[1], swimColour[2], -1); - } else if (30 <= tickCount % 60 && tickCount % 60 < 45) { - waterColour = Colours.get(-1, swimColour[2], -1, swimColour[1]); - } else { - yOffset--; - waterColour = Colours.get(-1, -1, swimColour[1], swimColour[2]); - } - - screen.render(xOffset, yOffset + 3, 31 + 31 * 32, waterColour, - 0x00, 1); - screen.render(xOffset + 8, yOffset + 3, 31 + 31 * 32, waterColour, - 0x01, 1); - } - - screen.render((xOffset + (modifier * flipTop)), yOffset, - (xTile + yTile * 32), colour, flipTop, scale); - screen.render((xOffset + modifier - (modifier * flipTop)), yOffset, - ((xTile + 1) + yTile * 32), colour, flipTop, scale); - if (!isSwimming && !isMagma && !isMuddy) { - screen.render((xOffset + (modifier * flipBottom)), - (yOffset + modifier), (xTile + (yTile + 1) * 32), colour, - flipBottom, scale); - screen.render((xOffset + modifier - (modifier * flipBottom)), - (yOffset + modifier), ((xTile + 1) + (yTile + 1) * 32), - colour, flipBottom, scale); - colour = Colours.get(-1, 111, shirtCol, faceCol); - } - } - - public Swim getSwim() { - return swim; } - public void setSwim(Swim swim) { - this.swim = swim; - } - - public List getPath() { - return path; - } - - public void setPath(List path) { - this.path = path; - } - - public int getTime() { - return time; - } - - public void setTime(int time) { - this.time = time; - } } diff --git a/src/com/redomar/game/entities/efx/Swim.java b/src/com/redomar/game/entities/efx/Swim.java index 65f70bf..354f173 100644 --- a/src/com/redomar/game/entities/efx/Swim.java +++ b/src/com/redomar/game/entities/efx/Swim.java @@ -2,37 +2,36 @@ import com.redomar.game.level.LevelHandler; +import java.util.HashMap; +import java.util.Map; + public class Swim { + private static final Map COLORS = new HashMap<>(); private static LevelHandler level; - private int x; - private int y; - private int[] swimCols = new int[3]; + + static { + COLORS.put(WaterType.SWIMMING, new int[]{255, 255, 115}); + COLORS.put(WaterType.MAGMA, new int[]{541, 521, 510}); + COLORS.put(WaterType.SWAMP, new int[]{422, 410, 321}); + } + + private final int x; + private final int y; public Swim(LevelHandler level, int x, int y) { Swim.level = level; this.x = x; this.y = y; } - - public int[] waveCols(boolean isSwimming, boolean isMagma, boolean isMuddy){ - - if(isSwimming){ - swimCols[0] = 255; - swimCols[1] = 255; - swimCols[2] = 115; - } - if(isMagma){ - swimCols[0] = 541; - swimCols[1] = 521; - swimCols[2] = 510; - } - if(isMuddy){ - swimCols[0] = 422; - swimCols[1] = 410; - swimCols[2] = 321; - } - return swimCols; + + @Deprecated + public int[] waveCols(boolean isSwimming, boolean isMagma, boolean isMuddy) { + return COLORS.get(isSwimming ? WaterType.SWIMMING : isMagma ? WaterType.MAGMA : isMuddy ? WaterType.SWAMP : null); + } + + public int[] waveCols(WaterType type) { + return COLORS.get(type); } public boolean water(boolean isSwimming) { @@ -71,23 +70,19 @@ public boolean mud(boolean isMuddy) { } public boolean[] swimming(boolean isSwimming, boolean isMagma, boolean isMuddy) { - boolean[] swimminhType; - swimminhType = new boolean[3]; - swimminhType[0] = water(isSwimming); - swimminhType[1] = magma(isMagma); - swimminhType[2] = mud(isMuddy); - return swimminhType; + boolean[] swimmingType; + swimmingType = new boolean[3]; + swimmingType[0] = water(isSwimming); + swimmingType[1] = magma(isMagma); + swimmingType[2] = mud(isMuddy); + return swimmingType; } - - public boolean isActive(boolean[] swimmingType){ - if(swimmingType[0] == true){ - return true; - }else if(swimmingType[1] == true){ + + public boolean isActive(boolean[] swimmingType) { + if (swimmingType[0]) { return true; - }else if(swimmingType[2] == true){ + } else if (swimmingType[1]) { return true; - } else { - return false; - } + } else return swimmingType[2]; } } diff --git a/src/com/redomar/game/entities/efx/WaterType.java b/src/com/redomar/game/entities/efx/WaterType.java new file mode 100644 index 0000000..5796eca --- /dev/null +++ b/src/com/redomar/game/entities/efx/WaterType.java @@ -0,0 +1,5 @@ +package com.redomar.game.entities.efx; + +public enum WaterType { + SWIMMING, MAGMA, SWAMP +} \ No newline at end of file diff --git a/src/com/redomar/game/entities/projectiles/Medium.java b/src/com/redomar/game/entities/projectiles/Medium.java index 32395b9..72262aa 100644 --- a/src/com/redomar/game/entities/projectiles/Medium.java +++ b/src/com/redomar/game/entities/projectiles/Medium.java @@ -5,7 +5,7 @@ import com.redomar.game.level.LevelHandler; public class Medium extends Projectile{ - + public static final int FIRE_RATE = 20; public Medium(LevelHandler level, int x, int y, double dir) { @@ -13,11 +13,11 @@ public Medium(LevelHandler level, int x, int y, double dir) { range = 60 - life.nextInt(10); damage = 80; speed = 1; - + nx = speed * Math.cos(angle); ny = speed * Math.sin(angle); } - + public void tick() { if (tileCollision(x, y,(int) nx,(int) ny)) remove(); move(); @@ -26,7 +26,7 @@ public void tick() { protected void move() { x += nx; y += ny; - + double distance = Math.sqrt(Math.abs((xOrigin - x)*(xOrigin - x)+(yOrigin - y)*(yOrigin - y))); this.distance = distance; if(this.distance > range) remove(); diff --git a/src/com/redomar/game/entities/projectiles/Projectile.java b/src/com/redomar/game/entities/projectiles/Projectile.java index 94b5d2c..0633fe9 100644 --- a/src/com/redomar/game/entities/projectiles/Projectile.java +++ b/src/com/redomar/game/entities/projectiles/Projectile.java @@ -1,21 +1,22 @@ package com.redomar.game.entities.projectiles; -import java.util.Random; - import com.redomar.game.entities.Entity; +import com.redomar.game.gfx.Screen; import com.redomar.game.level.LevelHandler; import com.redomar.game.level.tiles.Tile; -public abstract class Projectile extends Entity{ +import java.util.Random; + +public abstract class Projectile extends Entity { protected final double xOrigin, yOrigin; protected double angle; protected double nx, ny; protected double speed, range, damage, distance; protected Random life = new Random(); - + private boolean removed = false; - + public Projectile(LevelHandler level, int x, int y, double dir) { super(level); xOrigin = x; @@ -26,8 +27,8 @@ public Projectile(LevelHandler level, int x, int y, double dir) { } protected abstract void move(); - - public boolean tileCollision(double xa, double ya, int nx, int ny){ + + public boolean tileCollision(double xa, double ya, int nx, int ny) { int xMin = 0; int xMax = 7; int yMin = 0; @@ -59,25 +60,25 @@ public boolean tileCollision(double xa, double ya, int nx, int ny){ return false; } - + + @Override + public void render(Screen screen, int xTile, int yTile) { + + } + private boolean isSolid(int xa, int ya, int x, int y, int nx, int ny) { if (level == null) { return false; } - Tile lastTile = level.getTile((nx + x) >> 3, - (ny + y) >> 3); - Tile newtTile = level.getTile((nx + x + xa) >> 3, (ny - + y + ya) >> 3); + Tile lastTile = level.getTile((nx + x) >> 3, (ny + y) >> 3); + Tile newtTile = level.getTile((nx + x + xa) >> 3, (ny + y + ya) >> 3); - if (!lastTile.equals(newtTile) && newtTile.isSolid()) { - return true; - } + return !lastTile.equals(newtTile) && newtTile.isSolid(); - return false; } - public void remove(){ + public void remove() { setRemoved(true); } @@ -88,5 +89,5 @@ public boolean isRemoved() { public void setRemoved(boolean removed) { this.removed = removed; } - + } diff --git a/src/com/redomar/game/entities/projectiles/Small.java b/src/com/redomar/game/entities/projectiles/Small.java index c3193a0..e1c8054 100644 --- a/src/com/redomar/game/entities/projectiles/Small.java +++ b/src/com/redomar/game/entities/projectiles/Small.java @@ -1,39 +1,50 @@ package com.redomar.game.entities.projectiles; +import com.redomar.game.audio.AudioHandler; import com.redomar.game.gfx.Colours; import com.redomar.game.gfx.Screen; import com.redomar.game.level.LevelHandler; -public class Small extends Projectile{ - - public static final int FIRE_RATE = 7; +import java.io.File; + +public class Small extends Projectile { + + public static final int FIRE_RATE = 10; + private static final File smallShot = new File("/music/small.wav"); public Small(LevelHandler level, int x, int y, double dir) { super(level, x, y, dir); range = 125 - life.nextInt(30); damage = 20; speed = 2; - + nx = speed * Math.cos(angle); ny = speed * Math.sin(angle); + + try { + AudioHandler smallSound = new AudioHandler(smallShot); + smallSound.setVolume(-15); + smallSound.play(); + } catch (Exception e) { + entityPrinter.cast().exception(e.toString()).exception("Unable to load Audio file " + smallShot.getName()); + } } public void tick() { - if (tileCollision(x, y,(int) nx,(int) ny)) remove(); + if (tileCollision(x, y, (int) nx, (int) ny)) remove(); move(); } - - protected void move(){ + + protected void move() { x += nx; y += ny; - - double distance = Math.sqrt(Math.abs((xOrigin - x)*(xOrigin - x)+(yOrigin - y)*(yOrigin - y))); - this.distance = distance; - if(this.distance > range) remove(); + + this.distance = Math.sqrt(Math.abs((xOrigin - x) * (xOrigin - x) + (yOrigin - y) * (yOrigin - y))); + if (this.distance > range) remove(); } public void render(Screen screen) { - screen.render((int)x,(int)y, 8 * 32, Colours.get(-1, 222, 333, 555), 0x00, 1); + screen.render((int) x, (int) y, 8 * 32, Colours.get(-1, 522, 540, 555), 0x00, 1); } } diff --git a/src/com/redomar/game/entities/trees/Spruce.java b/src/com/redomar/game/entities/trees/Spruce.java new file mode 100644 index 0000000..e05abdc --- /dev/null +++ b/src/com/redomar/game/entities/trees/Spruce.java @@ -0,0 +1,103 @@ +package com.redomar.game.entities.trees; + +import com.redomar.game.gfx.Colours; +import com.redomar.game.gfx.Screen; +import com.redomar.game.level.LevelHandler; + +public class Spruce extends Tree { + + /** + * Spruce Tree by MOHAMED OMAR + * + */ + + //BIT MASK variables in Bits. Used to select bits by using comparing. + private final int BIT_MASK_MOVE_RIGHT = 0b0001; + private final int BIT_MASK_MOVE_UP_1 = 0b0010; + private final int BIT_MASK_MOVE_UP_2 = 0b0100; + + private int scale; + + /** + * Spruce tree + * @param level LevelHandler level which spruces spawns + * @param x X co-ordinate + * @param y Y co-ordinate + * @param scale Size of tree + */ + public Spruce(LevelHandler level, double x, double y, int scale) { + super(level, x, y); + this.setX((int)x); + this.setY((int)y); + this.setName("Spruce_Tree"); + this.setScale(scale); + } + + @Override + public void tick() { + + } + + /** + * This Renders the spruce tree + * + * Spruce is 3x2 on the sprite sheet + * + * 0 1 + * +---------+ + * 6 |0100|0101| + * 7 |0010|0011| + * 8 |0000|0001| + * +---------+ + * + * @param screen Screen to render on. + */ + public void render(Screen screen) { + + //Spruce uses 6 tiles from sprite sheet. + int spruceSize = 0; + + //This will go through a while loop for each 8*8 section of the spruce + while (spruceSize < 6){ + int right = 0; + int up1 = 0; + int up2 = 0; + int tileX = 0; + int tileY = 4; + + + //BIT MASK for all the right sided sprites. comparing it to 0b0001 (last bit). + if ((spruceSize & BIT_MASK_MOVE_RIGHT) > 0){ + //MOVE RIGHT + right = scale * 8; + tileX = tileX + 1; + } + + //it will only move up 1 time if it does not move up twice. + if ((spruceSize & BIT_MASK_MOVE_UP_2) > 0){ + //MOVE UP 2 TIMES + up2 = scale * 8; + tileY = tileY -2; + } else if ((spruceSize & BIT_MASK_MOVE_UP_1) > 0){ + //MOVE UP ONCE + up1 = scale * 8; + tileY = tileY -1; + } + + //rendering to game. Inline if statement ensures that tree trunk has a unique colour + screen.render((int)getX()+right,((int)getY() - up1) - up2*2,(tileY*32+tileX), Colours.get(-1,020,241, spruceSize > 0b0001? 251: 110), 0x00, scale); + + spruceSize++; + } + + } + + //Some getters and setters + public int getScale() { + return scale; + } + + public void setScale(int scale) { + this.scale = scale; + } +} diff --git a/src/com/redomar/game/entities/trees/Tree.java b/src/com/redomar/game/entities/trees/Tree.java new file mode 100644 index 0000000..575c8f4 --- /dev/null +++ b/src/com/redomar/game/entities/trees/Tree.java @@ -0,0 +1,35 @@ +package com.redomar.game.entities.trees; + +import com.redomar.game.entities.Entity; +import com.redomar.game.gfx.Screen; +import com.redomar.game.level.LevelHandler; + +public abstract class Tree extends Entity { + + /** + * Tree abstract class + * -- Used by Spruce Class + */ + + //Position variables + protected final double x; + protected final double y; + + /** + * Constructor for tree entities + * + * @param level LevelHandler in which tree spawns + * @param x X co-ordinate + * @param y Y co-ordinate + */ + Tree(LevelHandler level, double x, double y) { + super(level); + this.x = x; + this.y = y; + } + + @Override + public void render(Screen screen, int xTile, int yTile) { + + } +} diff --git a/src/com/redomar/game/event/InputHandler.java b/src/com/redomar/game/event/InputHandler.java new file mode 100644 index 0000000..93b7c65 --- /dev/null +++ b/src/com/redomar/game/event/InputHandler.java @@ -0,0 +1,178 @@ +package com.redomar.game.event; + +import com.redomar.game.Game; +import com.redomar.game.lib.Either; +import com.redomar.game.lib.SleepThread; +import com.redomar.game.log.PrintTypes; +import com.redomar.game.log.Printer; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.im.InputContext; +import java.util.HashMap; +import java.util.Map; + +import static com.redomar.game.lib.Either.tryCatch; + +public class InputHandler implements KeyListener { + + private final boolean frenchKeyboardLayout; + private final Printer inputPrinter = new Printer(PrintTypes.INPUT); + private final KeyHandler UP_KEY = new KeyHandler(); + private final KeyHandler DOWN_KEY = new KeyHandler(); + private final KeyHandler LEFT_KEY = new KeyHandler(); + private final KeyHandler RIGHT_KEY = new KeyHandler(); + private final KeyHandler SHIFTED = new KeyHandler(); + private final KeyHandler M_KEY = new KeyHandler(); + + + public InputHandler(Game game) { + InputContext context = InputContext.getInstance(); + frenchKeyboardLayout = context.getLocale().getCountry().equals("BE") || context.getLocale().getCountry().equals("FR"); + game.addKeyListener(this); + } + + public void keyPressed(KeyEvent e) { + toggleKey(e.getKeyCode(), true); + } + + /** + * Toggles between two actions depending on the value of a boolean flag. + * + * @param key the key to be pressed to trigger the action + * @param isToggled the boolean flag that determines which action to activate + * @param actionA the function to execute the first action + * @param actionB the function to execute the second action + * @return an Either object with the result of the action on the right side and an Exception on the left side if an exception is thrown + */ + public Either toggleActionWithCheckedRunnable(KeyHandler key, boolean isToggled, Either.CheckedRunnable actionA, Either.CheckedRunnable actionB) { + boolean pressed = key.isPressed(); + if (pressed) { + if (!isToggled) { + Either result = tryCatch(actionA); + if (result.isLeft()) { + return result.map(__ -> false); + } + isToggled = true; + } else { + Either result = tryCatch(actionB); + if (result.isLeft()) { + return result.map(__ -> true); + } + isToggled = false; + } + key.reset(); + } + return Either.right(isToggled); + } + + public void keyReleased(KeyEvent e) { + int keyCode = e.getKeyCode(); + toggleKey(keyCode, false); + if (keyCode == KeyEvent.VK_BACK_QUOTE) { + if (!Game.isClosing()) { + Game.setDevMode(!Game.isDevMode()); + new Thread(new SleepThread()); + inputPrinter.print(String.format("Debug Mode %s", Game.isDevMode() ? "Enabled" : "Disabled")); + } + } + + if (keyCode == KeyEvent.VK_N) { + if (!Game.isNpc()) { + Game.setNpc(true); + Game.npcSpawn(); + inputPrinter.print("Dummy has been spawned", PrintTypes.GAME); + } + } + } + + public void keyTyped(KeyEvent e) { + + } + + private void toggleKey(int keyCode, boolean isPressed) { + Map keyCodeActions = new HashMap<>(); + + keyCodeActions.put(KeyEvent.VK_S, () -> DOWN_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_D, () -> RIGHT_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_UP, () -> UP_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_LEFT, () -> LEFT_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_DOWN, () -> DOWN_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_RIGHT, () -> RIGHT_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_SHIFT, () -> SHIFTED.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_M, () -> M_KEY.setPressedToggle(isPressed)); + + if (frenchKeyboardLayout) { + keyCodeActions.put(KeyEvent.VK_Q, () -> LEFT_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_Z, () -> UP_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_A, this::quitGame); + } else { + keyCodeActions.put(KeyEvent.VK_A, () -> LEFT_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_W, () -> UP_KEY.setPressed(isPressed)); + keyCodeActions.put(KeyEvent.VK_Q, this::quitGame); + } + + if (keyCodeActions.containsKey(keyCode)) keyCodeActions.get(keyCode).run(); + + if (keyCode == KeyEvent.VK_W && frenchKeyboardLayout || keyCode == KeyEvent.VK_Z && !frenchKeyboardLayout) { + if (Game.getMap() == 2) { + if (Game.isNpc()) { + Game.setNpc(false); + } + Game.setChangeLevel(true); + } + } + + if (keyCode == KeyEvent.VK_K) { + if (Game.isNpc()) { + Game.setNpc(false); + Game.npcKill(); + inputPrinter.print("Dummy has been removed", PrintTypes.GAME); + } + } + + } + + public void overWriteKey(KeyHandler key, boolean isPressed) { + key.setPressedToggle(isPressed); + } + + private void quitGame() { + Game.setClosing(true); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + inputPrinter.exception(e.getMessage()); + } + Game.getLevel().removeEntity(Game.getPlayer().getName()); + Game.getGame().stop(); + Game.getFrame().dispose(); + if (!inputPrinter.removeLog()) System.err.println("Could not delete Log file"); + System.exit(0); + } + + public KeyHandler getUP_KEY() { + return UP_KEY; + } + + public KeyHandler getDOWN_KEY() { + return DOWN_KEY; + } + + public KeyHandler getLEFT_KEY() { + return LEFT_KEY; + } + + public KeyHandler getRIGHT_KEY() { + return RIGHT_KEY; + } + + public KeyHandler getSHIFTED() { + return SHIFTED; + } + + public KeyHandler getM_KEY() { + return M_KEY; + } + +} diff --git a/src/com/redomar/game/event/KeyHandler.java b/src/com/redomar/game/event/KeyHandler.java new file mode 100644 index 0000000..56b0d06 --- /dev/null +++ b/src/com/redomar/game/event/KeyHandler.java @@ -0,0 +1,35 @@ +package com.redomar.game.event; + +@SuppressWarnings("unused") +public class KeyHandler { + private int numTimesPressed = 0; + private boolean pressed = false; + + @Deprecated + public int getNumTimesPressed() { + return numTimesPressed; + } + + public boolean isPressed() { + return pressed; + } + + void setPressed(boolean isPressed) { + pressed = isPressed; + if (isPressed) numTimesPressed++; + } + + void setPressedToggle(boolean isPressed) { + if (isPressed) return; + pressed = !pressed; + } + + public void on() { + pressed = true; + } + + public void reset() { + pressed = false; + numTimesPressed = 0; + } +} diff --git a/src/com/redomar/game/lib/Mouse.java b/src/com/redomar/game/event/Mouse.java similarity index 81% rename from src/com/redomar/game/lib/Mouse.java rename to src/com/redomar/game/event/Mouse.java index 6a334bd..f05807a 100644 --- a/src/com/redomar/game/lib/Mouse.java +++ b/src/com/redomar/game/event/Mouse.java @@ -1,12 +1,12 @@ -package com.redomar.game.lib; +package com.redomar.game.event; + +import com.redomar.game.Game; +import com.redomar.game.menu.Menu; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; -import com.redomar.game.Game; -import com.redomar.game.menu.Menu; - public class Mouse implements MouseListener, MouseMotionListener { public void mouseDragged(MouseEvent e) { @@ -16,17 +16,9 @@ public void mouseDragged(MouseEvent e) { public void mouseMoved(MouseEvent e) { if (e.getX() > 35 && e.getX() < 455) { // START is being selected - if (e.getY() > 38 && e.getY() < 150) { - Menu.setSelectedStart(true); - } else { - Menu.setSelectedStart(false); - } + Menu.setSelectedStart(e.getY() > 38 && e.getY() < 150); // EXIT is being selected - if (e.getY() > 170 && e.getY() < 280) { - Menu.setSelectedExit(true); - } else { - Menu.setSelectedExit(false); - } + Menu.setSelectedExit(e.getY() > 170 && e.getY() < 280); } else { Menu.setSelectedStart(false); Menu.setSelectedExit(false); diff --git a/src/com/redomar/game/MouseHandler.java b/src/com/redomar/game/event/MouseHandler.java similarity index 89% rename from src/com/redomar/game/MouseHandler.java rename to src/com/redomar/game/event/MouseHandler.java index 8e5e4b3..3cb3c2a 100644 --- a/src/com/redomar/game/MouseHandler.java +++ b/src/com/redomar/game/event/MouseHandler.java @@ -1,16 +1,18 @@ -package com.redomar.game; +package com.redomar.game.event; + +import com.redomar.game.Game; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; -public class MouseHandler implements MouseListener, MouseMotionListener{ - +public class MouseHandler implements MouseListener, MouseMotionListener { + private static int mouseX = -1; private static int mouseY = -1; private static int mouseB = -1; - - public MouseHandler(Game game){ + + public MouseHandler(Game game) { game.addMouseListener(this); game.addMouseMotionListener(this); } @@ -38,9 +40,9 @@ public void mouseMoved(MouseEvent e) { } public void mouseClicked(MouseEvent e) { - + } - + public void mousePressed(MouseEvent e) { mouseB = e.getButton(); } @@ -50,11 +52,11 @@ public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { - + } public void mouseExited(MouseEvent e) { - + } - + } diff --git a/src/com/redomar/game/WindowHandler.java b/src/com/redomar/game/event/WindowHandler.java similarity index 69% rename from src/com/redomar/game/WindowHandler.java rename to src/com/redomar/game/event/WindowHandler.java index b5263fa..2180662 100644 --- a/src/com/redomar/game/WindowHandler.java +++ b/src/com/redomar/game/event/WindowHandler.java @@ -1,17 +1,15 @@ -package com.redomar.game; +package com.redomar.game.event; + +import com.redomar.game.Game; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; -import com.redomar.game.net.packets.Packet01Disconnect; - +@Deprecated +@SuppressWarnings("unused") public class WindowHandler implements WindowListener { - @SuppressWarnings("unused") - private final Game game; - public WindowHandler(Game game) { - this.game = game; Game.getFrame().addWindowListener(this); } @@ -27,9 +25,7 @@ public void windowClosed(WindowEvent event) { @Override public void windowClosing(WindowEvent event) { - Packet01Disconnect packet = new Packet01Disconnect(Game.getPlayer() - .getUsername()); - packet.writeData(Game.getSocketClient()); + } @Override diff --git a/src/com/redomar/game/gfx/Colours.java b/src/com/redomar/game/gfx/Colours.java index 630ff16..0cf6bf3 100644 --- a/src/com/redomar/game/gfx/Colours.java +++ b/src/com/redomar/game/gfx/Colours.java @@ -3,8 +3,7 @@ public class Colours { public static int get(int colour1, int colour2, int colour3, int colour4) { - return (get(colour4) << 24) + (get(colour3) << 16) - + (get(colour2) << 8) + (get(colour1)); + return (get(colour4) << 24) + (get(colour3) << 16) + (get(colour2) << 8) + (get(colour1)); } private static int get(int colour) { @@ -13,10 +12,51 @@ private static int get(int colour) { return 255; } - int r = colour / 100 % 10; - int g = colour / 10 % 10; - int b = colour % 10; + int r = Math.min(Math.abs((colour / 100 % 10)), 5); + int g = Math.min(Math.abs((colour / 10 % 10)), 5); + int b = Math.min(Math.abs((colour % 10)), 5); return r * 36 + g * 6 + b; } + + public static int highlight(int colour) { + + if (colour < 0) { + return 255; + } + + int r = Math.min(Math.abs((colour / 100 % 10) + 1), 5); + int g = Math.min(Math.abs((colour / 10 % 10) + 1), 5); + int b = Math.min(Math.abs((colour % 10) + 1), 5); + + return r * 36 + g * 6 + b; + } + + public static int[] getColours(int packedColours) { + int[] colours = new int[4]; + + // Extract each colour component + colours[3] = reverseGet((packedColours >> 24) & 0xFF); // colour4 + colours[2] = reverseGet((packedColours >> 16) & 0xFF); // colour3 + colours[1] = reverseGet((packedColours >> 8) & 0xFF); // colour2 + colours[0] = reverseGet(packedColours & 0xFF); // colour1 + + return colours; + } + + private static int reverseGet(int colour) { + if (colour == 255) { + return -1; // Original colour was less than 0 + } + + int r = colour / 36; + int g = (colour / 6) % 6; + int b = colour % 6; + + return r * 100 + g * 10 + b; + } + + public static int highlight(int colour, int colour1, int colour2, int colour3) { + return (highlight(colour3) << 24) + (highlight(colour2) << 16) + (highlight(colour1) << 8) + (highlight(colour)); + } } diff --git a/src/com/redomar/game/gfx/Screen.java b/src/com/redomar/game/gfx/Screen.java index 23e9ec4..695f232 100644 --- a/src/com/redomar/game/gfx/Screen.java +++ b/src/com/redomar/game/gfx/Screen.java @@ -7,17 +7,24 @@ public class Screen { private static final byte BIT_MIRROR_X = 0x01; private static final byte BIT_MIRROR_Y = 0x02; - + private final SpriteSheet sheet; private int[] pixels; - private int xOffset = 0; private int yOffset = 0; - private int width; private int height; - private SpriteSheet sheet; - + private int viewPortWidth; + private int viewPortHeight; + + /** + * Constructs the draw area + * + * @param width width of the screen + * @param height height of the screen + * @param sheet Sprite-sheet selector. Constructed sprite sheet needs to be here, + * Sprite-sheet cp requires path only. + */ public Screen(int width, int height, SpriteSheet sheet) { this.setWidth(width); @@ -27,8 +34,24 @@ public Screen(int width, int height, SpriteSheet sheet) { setPixels(new int[width * height]); } - public void render(int xPos, int yPos, int tile, int colour, int mirrorDir, - int scale) { + @SuppressWarnings("unused") + public static int getMapWidthMask() { + return MAP_WIDTH_MASK; + } + + + /** + * Rendering sprites from sprite sheet onto the game world. + * Render constructor requires + * + * @param xPos X Position of subject + * @param yPos Y Position of subject + * @param tile tile location. e.g 7 * 32 + 1 is the oblong bullet on the 7th row 2nd column + * @param colour Using established colouring nomenclature. i.e. use com.redomar.game.gfx.Colours + * @param mirrorDir flip Direction: 0x01 flip vertical, 0x02 flip horizontal. + * @param scale Scale + */ + public void render(int xPos, int yPos, int tile, int colour, int mirrorDir, int scale) { xPos -= xOffset; yPos -= yOffset; @@ -58,26 +81,22 @@ public void render(int xPos, int yPos, int tile, int colour, int mirrorDir, int xPixel = x + xPos + (x * scaleMap) - ((scaleMap << 3) / 2); - int col = (colour >> (sheet.pixels[xSheet + ySheet - * sheet.getWidth() + tileOffset] * 8)) & 255; + int col = (colour >> (sheet.pixels[xSheet + ySheet * sheet.getWidth() + tileOffset] * 8)) & 255; if (col < 255) { for (int yScale = 0; yScale < scale; yScale++) { - if (yPixel + yScale < 0 - | yPixel + yScale >= getHeight()) { + if (yPixel + yScale < 0 | yPixel + yScale >= getHeight()) { continue; } for (int xScale = 0; xScale < scale; xScale++) { - if (xPixel + xScale < 0 - | xPixel + xScale >= getWidth()) { + if (xPixel + xScale < 0 | xPixel + xScale >= getWidth()) { continue; } - getPixels()[(xPixel + xScale) + (yPixel + yScale) - * getWidth()] = col; + getPixels()[(xPixel + xScale) + (yPixel + yScale) * getWidth()] = col; } } @@ -86,14 +105,60 @@ public void render(int xPos, int yPos, int tile, int colour, int mirrorDir, } } + private static final String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ " + "0123456789.,:;'\"!?$%()-=+/ "; + + public void renderText(String msg, int xPos, int yPos, int colour, int scale) { + for (int i = 0; i < msg.length(); i++) { + int charIndex = chars.indexOf(msg.charAt(i)); + if (charIndex >= 0) { // Only render if the character is found + int tileInSprite = charIndex + 30 * 32; // Calculate the tile position based on the charIndex + renderCharacter(xPos + i * (8 * scale), yPos, tileInSprite, colour, scale); + } + } + } + + private void renderCharacter(int xPos, int yPos, int tile, int colour, int scale) { + xPos -= xOffset; + yPos -= yOffset; + + int xTile = tile % 32; + int yTile = tile / 32; + int tileOffset = (xTile << 3) + (yTile << 3) * sheet.getWidth(); + + for (int y = 0; y < 8; y++) { + int yPixel = yPos + y * scale; + + for (int x = 0; x < 8; x++) { + int xPixel = xPos + x * scale; + + int col = (colour >> (sheet.pixels[x + y * sheet.getWidth() + tileOffset] * 8)) & 255; + if (col < 255) { + for (int yScale = 0; yScale < scale; yScale++) { + if (yPixel + yScale < 0 || yPixel + yScale >= height) continue; + for (int xScale = 0; xScale < scale; xScale++) { + if (xPixel + xScale < 0 || xPixel + xScale >= width) continue; + pixels[(xPixel + xScale) + (yPixel + yScale) * width] = col; + } + } + } + } + } + } + + + public void setOffset(int xOffset, int yOffset) { this.xOffset = xOffset; this.yOffset = yOffset; } - public static int getMapWidthMask() { - return MAP_WIDTH_MASK; + public int getxOffset() { + return xOffset; + } + + public int getyOffset() { + return yOffset; } public int getWidth() { @@ -119,4 +184,20 @@ public int getHeight() { public void setHeight(int height) { this.height = height; } + + public int getViewPortWidth() { + return viewPortWidth; + } + + public void setViewPortWidth(int viewPortWidth) { + this.viewPortWidth = viewPortWidth; + } + + public int getViewPortHeight() { + return viewPortHeight; + } + + public void setViewPortHeight(int viewPortHeight) { + this.viewPortHeight = viewPortHeight; + } } diff --git a/src/com/redomar/game/gfx/SpriteSheet.java b/src/com/redomar/game/gfx/SpriteSheet.java index f6f34c9..6d0faa4 100644 --- a/src/com/redomar/game/gfx/SpriteSheet.java +++ b/src/com/redomar/game/gfx/SpriteSheet.java @@ -1,23 +1,21 @@ package com.redomar.game.gfx; +import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; - -import javax.imageio.ImageIO; +import java.util.Objects; public class SpriteSheet { + public int[] pixels; private String path; private int width; - private int height; - - public int[] pixels; public SpriteSheet(String path) { BufferedImage image = null; try { - image = ImageIO.read(SpriteSheet.class.getResourceAsStream(path)); + image = ImageIO.read(Objects.requireNonNull(SpriteSheet.class.getResourceAsStream(path))); } catch (IOException e) { e.printStackTrace(); } @@ -28,7 +26,7 @@ public SpriteSheet(String path) { this.setPath(path); this.setWidth(image.getWidth()); - this.height = image.getHeight(); + int height = image.getHeight(); pixels = image.getRGB(0, 0, width, height, null, 0, width); @@ -36,11 +34,9 @@ public SpriteSheet(String path) { pixels[i] = (pixels[i] & 0xff) / 64; // removes alpha (transparency) } - for (int i = 0; i < 8; i++) { - // System.out.println(pixels[i]); - } } + @SuppressWarnings("unused") public String getPath() { return path; } diff --git a/src/com/redomar/game/gfx/lighting/Night.java b/src/com/redomar/game/gfx/lighting/Night.java new file mode 100644 index 0000000..39e1699 --- /dev/null +++ b/src/com/redomar/game/gfx/lighting/Night.java @@ -0,0 +1,38 @@ +package com.redomar.game.gfx.lighting; + +import com.redomar.game.Game; +import com.redomar.game.gfx.Screen; + +import java.awt.*; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; + +public class Night { + + private final Graphics2D g; + private final Screen screen; + + public Night(Graphics2D g, Screen screen) { + this.g = g; + this.screen = screen; + } + + public void render(int playerX, int playerY) { + double size = 160; + + g.setColor(new Color(0f, 0f, 0f, 0.8f)); + Shape rectangle = new Rectangle(0, 0, screen.getViewPortWidth(), screen.getViewPortHeight() - 30); + Shape circle = new Ellipse2D.Double(playerX - size / 2, playerY - size / 2, size, size); + int mouseX = Game.getMouse().getX(); + int mouseY = Game.getMouse().getY(); + + // Adjust mouse coordinates based on the current offset and scale of the game world + int tileX = ((mouseX) / (8 * 2)); + int tileY = ((mouseY) / (8 * 2)); + Shape smallRectangle = new Rectangle(tileX * 16 - 16, tileY * 16 - 16, 48, 48); + Area area = new Area(rectangle); + area.subtract(new Area(circle)); + area.subtract(new Area(smallRectangle)); + g.fill(area); + } +} diff --git a/src/com/redomar/game/level/LevelHandler.java b/src/com/redomar/game/level/LevelHandler.java index dce4ebd..d121919 100644 --- a/src/com/redomar/game/level/LevelHandler.java +++ b/src/com/redomar/game/level/LevelHandler.java @@ -1,49 +1,36 @@ package com.redomar.game.level; +import com.redomar.game.entities.Entity; +import com.redomar.game.entities.Player; +import com.redomar.game.gfx.Screen; +import com.redomar.game.level.tiles.Tile; +import com.redomar.game.lib.utils.Vector2i; +import com.redomar.game.log.PrintTypes; +import com.redomar.game.log.Printer; +import com.redomar.game.scenes.Scene; + +import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.logging.Level; -import javax.imageio.ImageIO; - -import com.redomar.game.Game; -import com.redomar.game.entities.Entity; -import com.redomar.game.entities.Player; -import com.redomar.game.entities.PlayerMP; -import com.redomar.game.gfx.Screen; -import com.redomar.game.level.tiles.Tile; -import com.redomar.game.lib.utils.Vector2i; -import com.redomar.game.net.packets.Packet01Disconnect; -import com.redomar.game.scenes.Scene; -import com.redomar.game.script.PrintTypes; -import com.redomar.game.script.Printing; - public class LevelHandler { + private final List entities; + private final List entities_p; + private final Printer print; + private final Comparator nodeSorter; private byte[] tiles; private int width; private int height; - private List entities = new ArrayList(); - private List entities_p = new ArrayList(); private String imagePath; private BufferedImage image; - private Printing print; - - private Comparator nodeSorter = new Comparator() { - public int compare(Node n0, Node n1) { - if(n1.fCost < n0.fCost) return +1; - if(n1.fCost > n0.fCost) return -1; - return 0; - } - - }; - public LevelHandler(String imagePath) { if (imagePath != null) { @@ -55,13 +42,16 @@ public LevelHandler(String imagePath) { this.setHeight(64); this.generateLevel(); } - - print = new Printing(); + + print = new Printer(); + entities = new ArrayList<>(); + entities_p = new ArrayList<>(); + nodeSorter = Comparator.comparingDouble(n0 -> n0.fCost); } private void loadLevelFromFile() { try { - this.image = ImageIO.read(Level.class.getResource(this.imagePath)); + this.image = ImageIO.read(Objects.requireNonNull(LevelHandler.class.getResource(this.imagePath))); this.setWidth(image.getWidth()); this.setHeight(image.getHeight()); tiles = new byte[getWidth() * getHeight()]; @@ -72,17 +62,14 @@ private void loadLevelFromFile() { } private void loadTiles() { - int[] tileColours = this.image.getRGB(0, 0, getWidth(), getHeight(), null, 0, - getWidth()); + int[] tileColours = this.image.getRGB(0, 0, getWidth(), getHeight(), null, 0, getWidth()); for (int y = 0; y < getHeight(); y++) { for (int x = 0; x < getWidth(); x++) { - tileCheck: for (Tile t : Tile.getTiles()) { - if (t != null - && t.getLevelColour() == tileColours[x + y * getWidth()]) { + for (Tile t : Tile.getTiles()) + if (t != null && t.getLevelColour() == tileColours[x + y * getWidth()]) { this.tiles[x + y * getWidth()] = t.getId(); - break tileCheck; + break; } - } } } } @@ -90,8 +77,7 @@ private void loadTiles() { @SuppressWarnings("unused") private void saveLevelToFile() { try { - ImageIO.write(image, "png", - new File(Level.class.getResource(this.imagePath).getFile())); + ImageIO.write(image, "png", new File(Objects.requireNonNull(Level.class.getResource(this.imagePath)).getFile())); } catch (IOException e) { e.printStackTrace(); } @@ -118,7 +104,7 @@ private void generateLevel() { public synchronized List getEntities() { return this.entities; } - + public synchronized List getProjectileEntities() { return this.entities_p; } @@ -127,11 +113,11 @@ public void tick() { for (Entity e : entities) { e.tick(); } - + for (Entity e : getProjectileEntities()) { e.tick(); } - + for (Tile t : Tile.getTiles()) { if (t == null) { break; @@ -163,12 +149,12 @@ public void renderTiles(Screen screen, int xOffset, int yOffset) { public void renderEntities(Screen screen) { for (Entity e : entities) { - e.render(screen); + e.render(screen, e.getXTile(), e.getYTile()); } } - - public void renderProjectileEntities(Screen screen){ - for (Entity e : getProjectileEntities()){ + + public void renderProjectileEntities(Screen screen) { + for (Entity e : getProjectileEntities()) { e.render(screen); } } @@ -182,28 +168,36 @@ public Tile getTile(int x, int y) { public void addEntity(Entity entity) { this.entities.add(entity); - print.print("Added "+entity.getName()+" Entity", PrintTypes.LEVEL); + print.print("Added " + entity.getName() + " Entity", PrintTypes.LEVEL); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } - + public void addProjectileEntities(Entity entity) { this.getProjectileEntities().add(entity); } + + /** + * Removes the entity that is passed through + * + * @param entity Specifies which entity needs to be removed + */ public void removeEntity(Entity entity) { + if (entity == null) return; + print.print("Removed " + entity.getName() + " Entity", PrintTypes.LEVEL); this.entities.remove(entity); - print.print("Removed "+entity.getName()+" Entity", PrintTypes.LEVEL); try { Thread.sleep(100); } catch (InterruptedException e) { + print.print("Interruption error: " + e, PrintTypes.ERROR); e.printStackTrace(); } } - + public void removeProjectileEntities(Entity entity) { this.getProjectileEntities().remove(entity); } @@ -211,50 +205,25 @@ public void removeProjectileEntities(Entity entity) { public void removeEntity(String username) { int index = 0; for (Entity e : entities) { - if (e instanceof PlayerMP - && ((PlayerMP) e).getUsername().equalsIgnoreCase(username)) { + if (e instanceof Player && e.getName().equalsIgnoreCase(username)) { break; } index++; } this.entities.remove(index); - Packet01Disconnect packet = new Packet01Disconnect(Game.getPlayer().getUsername()); - packet.writeData(Game.getSocketClient()); } - private int getPlayerMPIndex(String username) { - int index = 0; - for (Entity e : entities) { - if (e instanceof PlayerMP - && ((PlayerMP) e).getUsername().equalsIgnoreCase(username)) { - break; - } - index++; - } - return index; - } - public void movePlayer(String username, int x, int y, int numSteps, - boolean isMoving, int movingDir) { - int index = getPlayerMPIndex(username); - PlayerMP player = (PlayerMP) this.entities.get(index); - player.setX(x); - player.setY(y); - player.setNumSteps(numSteps); - player.setMoving(isMoving); - player.setMovingDir(movingDir); - } - - public List findPath(Vector2i start, Vector2i goal){ - List openList = new ArrayList(); - List closedList = new ArrayList(); + public List findPath(Vector2i start, Vector2i goal) { + List openList = new ArrayList<>(); + List closedList = new ArrayList<>(); Node current = new Node(start, null, 0, getDistance(start, goal)); openList.add(current); - while(openList.size() > 0){ - Collections.sort(openList, nodeSorter); + while (openList.size() > 0) { + openList.sort(nodeSorter); current = openList.get(0); - if(current.tile.equals(goal)){ - List path = new ArrayList(); + if (current.tile.equals(goal)) { + List path = new ArrayList<>(); while (current.parent != null) { path.add(current); current = current.parent; @@ -265,70 +234,60 @@ public List findPath(Vector2i start, Vector2i goal){ } openList.remove(current); closedList.add(current); - for(int i = 0; i < 9; i++){ - if(i == 4) continue; + for (int i = 0; i < 9; i++) { + if (i == 4) continue; int x = current.tile.getX(); int y = current.tile.getY(); int xi = (i % 3) - 1; int yi = (i / 3) - 1; - Tile at = getTile(x + xi,y + yi); - if(at == null) continue; - if(at.isSolid()) continue; + Tile at = getTile(x + xi, y + yi); + if (at == null) continue; + if (at.isSolid()) continue; Vector2i a = new Vector2i(x + xi, y + yi); double gCost = current.gCost + (getDistance(current.tile, a) == 1 ? 1 : 0.95); double hCost = getDistance(a, goal); Node node = new Node(a, current, gCost, hCost); - if(isVectorInList(closedList, a) && gCost >= node.gCost) continue; - if(!isVectorInList(openList, a) || gCost < node.gCost) openList.add(node); + if (isVectorInList(closedList, a) && gCost >= node.gCost) continue; + if (!isVectorInList(openList, a) || gCost < node.gCost) openList.add(node); } } closedList.clear(); return null; } - - private boolean isVectorInList(List list, Vector2i vector){ - for(Node n : list){ - if(n.tile.equals(vector)) return true; + + private boolean isVectorInList(List list, Vector2i vector) { + for (Node n : list) { + if (n.tile.equals(vector)) return true; } return false; } - - private double getDistance(Vector2i tile, Vector2i goal){ + + private double getDistance(Vector2i tile, Vector2i goal) { double dx = tile.getX() - goal.getX(); double dy = tile.getY() - goal.getY(); return Math.sqrt(dx * dx + dy * dy); } - - public List getEntities(Entity e, int radius){ - List result = new ArrayList(); + + @Deprecated + public List getEntities(Entity e, int radius) { + List result = new ArrayList<>(); int ex = (int) e.getX(); int ey = (int) e.getY(); - for (int i = 0; i < entities.size(); i++) { - Entity entity = entities.get(i); + for (Entity entity : entities) { int x = (int) entity.getX(); int y = (int) entity.getY(); - + int dx = Math.abs(x - ex); int dy = Math.abs(y - ey); - - double distance = Math.sqrt((dx*2) + (dy*2)); - if(distance <= radius){ + + double distance = Math.sqrt((dx * 2) + (dy * 2)); + if (distance <= radius) { result.add(entity); } } return result; } - - public List getPlayers(Entity e, int radius){ - List entities = getEntities(e, radius); - List result = new ArrayList(); - for (int i = 0; i < entities.size(); i++) { - if (entities.get(i) instanceof Player) { - result.add((Player) entities.get(i)); - } - } - return result; - } + public int getWidth() { return width; diff --git a/src/com/redomar/game/level/Node.java b/src/com/redomar/game/level/Node.java index bd1d4a6..02ed733 100644 --- a/src/com/redomar/game/level/Node.java +++ b/src/com/redomar/game/level/Node.java @@ -3,12 +3,12 @@ import com.redomar.game.lib.utils.Vector2i; public class Node { - + public Vector2i tile; public Node parent; public double fCost, gCost, hCost; - - public Node(Vector2i tile, Node parent, double gCost, double hCost){ + + public Node(Vector2i tile, Node parent, double gCost, double hCost) { this.tile = tile; this.parent = parent; this.gCost = gCost; diff --git a/src/com/redomar/game/level/tiles/AnimatedTile.java b/src/com/redomar/game/level/tiles/AnimatedTile.java index b5d53bd..705d80f 100644 --- a/src/com/redomar/game/level/tiles/AnimatedTile.java +++ b/src/com/redomar/game/level/tiles/AnimatedTile.java @@ -2,27 +2,25 @@ public class AnimatedTile extends BasicTile { - private int[][] animationTileCoords; + private final int[][] animationTileCoords; private int currentAnimationIndex; private long lastIterationTime; - private int animationSwitchDelay; + private final int animationSwitchDelay; - public AnimatedTile(int id, int[][] animationCoords, int tileColour, - int levelColour, int animationSwitchDelay) { - super(id, animationCoords[0][0], animationCoords[0][1], tileColour, - levelColour); + public AnimatedTile(int id, int[][] animationCoords, int tileColour, int levelColour, int animationSwitchDelay) { + super(id, animationCoords[0][0], animationCoords[0][1], tileColour, levelColour); this.animationTileCoords = animationCoords; this.currentAnimationIndex = 0; this.lastIterationTime = System.currentTimeMillis(); this.animationSwitchDelay = animationSwitchDelay; } + @Override public void tick() { - if ((System.currentTimeMillis() - lastIterationTime) >= (animationSwitchDelay)) { + if ((System.currentTimeMillis() - lastIterationTime) >= animationSwitchDelay) { lastIterationTime = System.currentTimeMillis(); - currentAnimationIndex = (currentAnimationIndex + 1) - % animationTileCoords.length; - this.tileId = (animationTileCoords[currentAnimationIndex][0] + (animationTileCoords[currentAnimationIndex][1] * 32)); + currentAnimationIndex = (currentAnimationIndex + 1) % animationTileCoords.length; + this.tileId = animationTileCoords[currentAnimationIndex][0] + (animationTileCoords[currentAnimationIndex][1] * 32); } } } diff --git a/src/com/redomar/game/level/tiles/BasicSolidTile.java b/src/com/redomar/game/level/tiles/BasicSolidTile.java deleted file mode 100644 index c78e58d..0000000 --- a/src/com/redomar/game/level/tiles/BasicSolidTile.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.redomar.game.level.tiles; - -public class BasicSolidTile extends BasicTile { - - public BasicSolidTile(int id, int x, int y, int tileColour, int levelColour) { - super(id, x, y, tileColour, levelColour); - this.solid = true; - } - -} diff --git a/src/com/redomar/game/level/tiles/BasicTile.java b/src/com/redomar/game/level/tiles/BasicTile.java index ea2faaf..01b0447 100644 --- a/src/com/redomar/game/level/tiles/BasicTile.java +++ b/src/com/redomar/game/level/tiles/BasicTile.java @@ -1,25 +1,37 @@ package com.redomar.game.level.tiles; +import com.redomar.game.Game; +import com.redomar.game.gfx.Colours; import com.redomar.game.gfx.Screen; import com.redomar.game.level.LevelHandler; public class BasicTile extends Tile { + protected final int tileColour; protected int tileId; - protected int tileColour; public BasicTile(int id, int x, int y, int tileColour, int levelColour) { super(id, false, false, levelColour); - this.tileId = x + y * 32; this.tileColour = tileColour; } + @Override public void tick() { + // Basic tiles do not update } + @Override public void render(Screen screen, LevelHandler level, int x, int y) { - screen.render(x, y, tileId, tileColour, 0x00, 1); + int[] colours = Colours.getColours(tileColour); + int mouseOverTileX = Game.getTileX(); + int mouseOverTileY = Game.getTileY(); + + if (mouseOverTileX == x / 8 && mouseOverTileY == y / 8) { + screen.render(x, y, tileId, Colours.highlight(colours[0], colours[1], colours[2], colours[3]), 0x00, 1); + } else { + screen.render(x, y, tileId, Colours.get(colours[0], colours[1], colours[2], colours[3]), 0x00, 1); + } } } diff --git a/src/com/redomar/game/level/tiles/SolidTile.java b/src/com/redomar/game/level/tiles/SolidTile.java new file mode 100644 index 0000000..a8913da --- /dev/null +++ b/src/com/redomar/game/level/tiles/SolidTile.java @@ -0,0 +1,18 @@ +package com.redomar.game.level.tiles; + +public class SolidTile extends BasicTile { + + /** + * This is a solid tile, but does not emit any light. This tile does not have any animations. + * + * @param id Unique ID for the Tile + * @param x Specifies the x-coordinate from the SpriteSheet, measured in 8 pixels. Must be 0 - 31 + * @param y Specifies the y-coordinate from the SpriteSheet, measured in 8 pixels. Must be 0 - 31 + * @param tileColour Colours from the SpriteSheet. + * @param levelColour Colours to be displayed in the Game World. + */ + public SolidTile(int id, int x, int y, int tileColour, int levelColour) { + super(id, x, y, tileColour, levelColour); + this.solid = true; + } +} diff --git a/src/com/redomar/game/level/tiles/Tile.java b/src/com/redomar/game/level/tiles/Tile.java index 0804e1b..cd66594 100644 --- a/src/com/redomar/game/level/tiles/Tile.java +++ b/src/com/redomar/game/level/tiles/Tile.java @@ -4,126 +4,97 @@ import com.redomar.game.gfx.Screen; import com.redomar.game.level.LevelHandler; + +@SuppressWarnings({"StaticInitializerReferencesSubClass", "OctalInteger"}) public abstract class Tile { private static final Tile[] tiles = new Tile[256]; - private static final Tile VOID = new BasicSolidTile(0, 0, 0, Colours.get(0, -1, -1, -1), 0xFF000000); - private static final Tile STONE = new BasicSolidTile(1, 1, 0, Colours.get(-1, 444, 333, -1), 0xFF555555); - private static final Tile CHISELED_stone = new BasicTile(2, 2, 0, Colours.get(-1, 333, 222, -1), 0xFF666666); - private static final Tile GRASS = new BasicTile(3, 3, 0, Colours.get(-1, 131, 141, -1), 0xFF00FF00); - private static final Tile WATER = new AnimatedTile(4, new int[][] { { 0, 5 }, { 1, 5 }, { 2, 5 }, { 1, 5 } }, Colours.get(-1, 004, 115, -1), 0xFF0000FF, 1000); - private static final Tile FLOWER_rose = new BasicTile(5, 4, 0, Colours.get(131, 151, 510, 553), 0xFFCCFF33); - private static final Tile FLOWER_dandelion = new BasicTile(6, 4, 0, Colours.get(131, 151, 553, 510), 0xFFFFCC33); - private static final Tile SAND = new BasicTile(7, 5, 0, Colours.get(-1, 553, 554, 555), 0xFFFFFF99); - private static final Tile CHEST_a = new BasicSolidTile(8, 0, 1, Colours.get(333, 111, 420, 000), 0xFFFF0001); - private static final Tile CHEST_b = new BasicSolidTile(9, 1, 1, Colours.get(333, 111, 420, 000), 0xFFFF0002); - private static final Tile CARPET_red = new BasicTile(10, 5, 0, Colours.get(-1, 311, 411, 311), 0xFFAA3636); - private static final Tile PORTAL = new AnimatedTile(11, new int[][] { { 3, 5 }, { 4, 5 }, { 5, 5 }, { 6, 5 }, { 7, 5 }, { 8, 5 }, { 9, 5 }, { 10, 5 } }, Colours.get(-1, 005, 305, -1), 0xFF00EAFF, 100); - private static final Tile MAGMA = new AnimatedTile(12, new int [][] { { 0, 5 }, { 1, 5 }, { 2, 5 }, { 1, 5 } }, Colours.get(-1, 400, 511, -1), 0xFFF00F0F, 1000); - private static final Tile DIRT = new BasicTile(13, 3, 0, Colours.get(0, 210, 321, -1), 0xFF442200); - private static final Tile DIRT_WET = new AnimatedTile(14, new int[][] { { 1, 5 }, { 2, 5 } }, Colours.get(-1, 211, 322, -1), 0xFF663300, 1500); - - protected byte id; + + static { + /* VOID */ + tiles[0] = new SolidTile(0, 0, 0, Colours.get(0, -1, -1, -1), 0xFF000000); + /* STONE */ + tiles[1] = new SolidTile(1, 1, 0, Colours.get(-1, 444, 333, -1), 0xFF555555); + /* CHISELED_stone */ + tiles[2] = new BasicTile(2, 2, 0, Colours.get(-1, 333, 222, -1), 0xFF666666); + /* GRASS */ + tiles[3] = new BasicTile(3, 3, 0, Colours.get(-1, 131, 141, -1), 0xFF00FF00); + /* WATER */ + tiles[4] = new AnimatedTile(4, new int[][]{{0, 5}, {1, 5}, {2, 5}, {1, 5}}, Colours.get(-1, 004, 115, -1), 0xFF0000FF, 1000); + /* FLOWER_rose */ + tiles[5] = new BasicTile(5, 4, 0, Colours.get(131, 151, 510, 553), 0xFFCCFF33); + /* FLOWER_dandelion */ + tiles[6] = new BasicTile(6, 4, 0, Colours.get(131, 151, 553, 510), 0xFFFFCC33); + /* SAND */ + tiles[7] = new BasicTile(7, 5, 0, Colours.get(-1, 553, 554, 555), 0xFFFFFF99); + /* CHEST_a */ + tiles[8] = new SolidTile(8, 0, 1, Colours.get(333, 111, 420, 000), 0xFFFF0001); + /* CHEST_b */ + tiles[9] = new SolidTile(9, 1, 1, Colours.get(333, 111, 420, 000), 0xFFFF0002); + /* CARPET_red */ + tiles[10] = new BasicTile(10, 5, 0, Colours.get(-1, 311, 411, 311), 0xFFAA3636); + /* PORTAL */ + tiles[11] = new AnimatedTile(11, new int[][]{{3, 5}, {4, 5}, {5, 5}, {6, 5}, {7, 5}, {8, 5}, {9, 5}, {10, 5}}, Colours.get(-1, 005, 305, -1), 0xFF00EAFF, 100); + /* MAGMA */ + tiles[12] = new AnimatedTile(12, new int[][]{{0, 5}, {1, 5}, {2, 5}, {1, 5}}, Colours.get(-1, 400, 511, -1), 0xFFF00F0F, 1000); + /* DIRT */ + tiles[13] = new BasicTile(13, 3, 0, Colours.get(0, 210, 321, -1), 0xFF442200); + /* DIRT_WET */ + tiles[14] = new AnimatedTile(14, new int[][]{{1, 5}, {2, 5}}, Colours.get(-1, 211, 322, -1), 0xFF663300, 1500); + } + + protected final byte id; + protected final boolean emitter; + protected final int levelColour; protected boolean solid; - protected boolean emitter; - private int levelColour; - public Tile(int id, boolean isSolid, boolean isEmitter, int colour) { + protected Tile(int id, boolean solid, boolean emitter, int levelColour) { this.id = (byte) id; + this.solid = solid; + this.emitter = emitter; + this.levelColour = levelColour; - if (getTiles()[id] != null) { - throw new RuntimeException("Duplicate tile id on:" + id); - } - - this.solid = isSolid; - this.emitter = isEmitter; - this.levelColour = colour; - getTiles()[id] = this; - } - - public byte getId() { - return id; + tiles[id] = this; } - public boolean isSolid() { - return solid; - } - - public boolean isEmitter() { - return emitter; - } - - public abstract void tick(); - - public abstract void render(Screen screen, LevelHandler level, int x, int y); - - public int getLevelColour() { - return levelColour; + public static Tile getTile(int id) { + return tiles[id]; } public static Tile getStone() { - return STONE; - } - - public static Tile getChiseledStone() { - return CHISELED_stone; + return getTile(1); } public static Tile getGrass() { - return GRASS; - } - - public static Tile getFlowerRose() { - return FLOWER_rose; - } - - public static Tile getFlowerDandelion() { - return FLOWER_dandelion; - } - - public static Tile getSand() { - return SAND; - } - - public static Tile getWater() { - return WATER; + return getTile(2); } public static Tile getVoid() { - return VOID; + return getTile(0); } public static Tile[] getTiles() { return tiles; } - public static Tile getChestA() { - return CHEST_a; - } - - public static Tile getChestB() { - return CHEST_b; + public byte getId() { + return id; } - public static Tile getCarpetRed() { - return CARPET_red; + public boolean isSolid() { + return solid; } - public static Tile getPortal() { - return PORTAL; + public boolean isEmitter() { + return emitter; } - public static Tile getMagma() { - return MAGMA; - } + public abstract void tick(); - public static Tile getDirt() { - return DIRT; - } + public abstract void render(Screen screen, LevelHandler level, int x, int y); - public static Tile getDirtWet() { - return DIRT_WET; + public int getLevelColour() { + return levelColour; } - } diff --git a/src/com/redomar/game/lib/Either.java b/src/com/redomar/game/lib/Either.java new file mode 100644 index 0000000..edf658f --- /dev/null +++ b/src/com/redomar/game/lib/Either.java @@ -0,0 +1,107 @@ +package com.redomar.game.lib; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; + +@SuppressWarnings({"OptionalUsedAsFieldOrParameterType", "OptionalGetWithoutIsPresent", "unused"}) +public class Either { + + private final Optional left; + private final Optional right; + + public Either(final Optional left, final Optional right) { + this.left = left; + this.right = right; + } + + @Contract("_ -> new") + public static @NotNull Either left(final L value) { + return new Either<>(Optional.of(value), Optional.empty()); + } + + @Contract("_ -> new") + public static @NotNull Either right(final R value) { + return new Either<>(Optional.empty(), Optional.ofNullable(value)); + } + + public static Either tryCatch(CheckedRunnable runnable) { + try { + runnable.run(); + return Either.right(null); + } catch (Exception e) { + return Either.left(e); + } + } + + public static Either tryCatch(CheckedFunction function) { + try { + return Either.right(function.apply()); + } catch (Exception e) { + return Either.left(e); + } + } + + public static Either tryCatch(CheckedSupplier supplier) { + try { + return Either.right(supplier.get()); + } catch (Exception e) { + return Either.left(e); + } + } + + public boolean isLeft() { + return left.isPresent(); + } + + public L getLeft() { + return left.get(); + } + + public R getRight() { + return right.get(); + } + + public void either(Consumer leftConsumer, Consumer rightConsumer) { + if (isLeft()) { + leftConsumer.accept(getLeft()); + } else { + rightConsumer.accept(getRight()); + } + } + + public T either(Function leftFunction, Function rightFunction) { + if (isLeft()) { + return leftFunction.apply(getLeft()); + } else { + return rightFunction.apply(getRight()); + } + } + + public Either map(Function mapper) { + if (isLeft()) { + return Either.left(getLeft()); + } else { + return Either.right(mapper.apply(getRight())); + } + } + + @FunctionalInterface + public interface CheckedRunnable { + void run() throws Exception; + } + + @FunctionalInterface + public interface CheckedSupplier { + T get() throws Exception; + } + + @FunctionalInterface + public interface CheckedFunction { + T apply() throws Exception; + } + +} diff --git a/src/com/redomar/game/lib/Font.java b/src/com/redomar/game/lib/Font.java index 538c177..b17de5d 100644 --- a/src/com/redomar/game/lib/Font.java +++ b/src/com/redomar/game/lib/Font.java @@ -6,24 +6,20 @@ public class Font { private static java.awt.Font arial; private static java.awt.Font segoe; + private static final String chars = "" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ " + "0123456789.,:;'\"!?$%()-=+/ "; public Font() { Font.setArial(new java.awt.Font("Arial", java.awt.Font.BOLD, 14)); Font.setSegoe(new java.awt.Font("Segoe UI", java.awt.Font.BOLD, 14)); } - private static String chars = "" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ " - + "0123456789.,:;'\"!?$%()-=+/ "; - - public static void render(String msg, Screen screen, int x, int y, - int colour, int scale) { + public static void render(String msg, Screen screen, int x, int y, int colour, int scale) { msg = msg.toUpperCase(); for (int i = 0; i < msg.length(); i++) { int charIndex = chars.indexOf(msg.charAt(i)); if (charIndex >= 0) { - screen.render(x + (i * 8), y, charIndex + 30 * 32, colour, - 0x00, scale); + screen.render(x + (i * 8), y, charIndex + 30 * 32, colour, 0x00, scale); } } } diff --git a/src/com/redomar/game/lib/HashGen.java b/src/com/redomar/game/lib/HashGen.java new file mode 100644 index 0000000..3044a40 --- /dev/null +++ b/src/com/redomar/game/lib/HashGen.java @@ -0,0 +1,74 @@ +package com.redomar.game.lib; + +import org.apache.commons.lang3.StringUtils; + +public class HashGen { + + private String hexHash; + private boolean prefix; + private int hexLength; + private String previousHash; + + /** + * Use for generating a hex Hash. Requires two parameters; + * + * @param showPrefix to show 0x prefix. + * @param length Length of hash. + */ + public HashGen(boolean showPrefix, int length) { + setPrefix(showPrefix); + setHexLength(length); + init(); + } + + //Remove null char or prepend 0x + private void init() { + if (prefix) { + hexHash = "0x"; + } else { + hexHash = ""; + } + } + + /** + * Retrieve hash + * + * @return String containing hash + */ + public String getHash() { + setHash(hexLength); + return hexHash; + } + + private void setHash(int hexLength) { + + String hex; + + for (int i = 0; i < hexLength; i++) { + hex = Integer.toHexString(randNumGen()); + hex = StringUtils.capitalize(hex); + hexHash = String.format("%s%s", hexHash, hex); + } + previousHash = hexHash; + + } + + private int randNumGen() { + return (int) (Math.random() * 16); + } + + //getters and setters + + public void setPrefix(boolean prefix) { + this.prefix = prefix; + } + + public void setHexLength(int hexLength) { + this.hexLength = hexLength; + } + + public String getPreviousHash() { + if (previousHash == null) return null; + return previousHash; + } +} diff --git a/src/com/redomar/game/lib/Keys.java b/src/com/redomar/game/lib/Keys.java deleted file mode 100644 index 3533e40..0000000 --- a/src/com/redomar/game/lib/Keys.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.redomar.game.lib; - -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; - -import com.redomar.game.Game; - -public class Keys implements KeyListener { - public Keys(Game game) { - game.addKeyListener(this); - } - - public class Key { - private int numTimesPressed = 0; - private boolean pressed = false; - - public int getNumTimesPressed() { - return numTimesPressed; - } - - public boolean isPressed() { - return pressed; - } - - public void toggle(boolean isPressed) { - pressed = isPressed; - if (isPressed) { - numTimesPressed++; - } - } - } - - private Key up = new Key(); - private Key down = new Key(); - - public void keyPressed(KeyEvent arg0) { - - } - - public void keyReleased(KeyEvent arg0) { - - } - - public void keyTyped(KeyEvent arg0) { - - } - - public void toggleKey(int keyCode, boolean isPressed) { - if (keyCode == KeyEvent.VK_W || keyCode == KeyEvent.VK_UP) { - up.toggle(isPressed); - } - if (keyCode == KeyEvent.VK_S || keyCode == KeyEvent.VK_DOWN) { - getDown().toggle(isPressed); - } - } - - public Key getUp() { - return up; - } - - public void setUp(Key up) { - this.up = up; - } - - public Key getDown() { - return down; - } - - public void setDown(Key down) { - this.down = down; - } - -} diff --git a/src/com/redomar/game/lib/Music.java b/src/com/redomar/game/lib/Music.java deleted file mode 100644 index fbf7848..0000000 --- a/src/com/redomar/game/lib/Music.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.redomar.game.lib; - -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.util.Random; - -import com.redomar.game.Game; -import com.redomar.game.script.*; - -import javazoom.jl.player.Player; - -public class Music implements Runnable { - - private InputStream file; - private Player musicPlayer; - private static String songName[] = { "/music/yoshi song.mp3", - "/music/Towards The End.mp3", "/music/Towards The End.mp3" }; - private static int songNumber; - private Printing print = new Printing(); - - private static Random rand = new Random(); - - public Music(InputStream url) { - this.file = url; - } - - public Music() { - Music.songNumber = rand.nextInt(3); - } - - public void Play() { - try { - BufferedInputStream buffered = new BufferedInputStream(file); - musicPlayer = new Player(buffered); - musicPlayer.play(); - } catch (Exception e) { - print.print(" Problem playing file " + file, PrintTypes.ERROR); - print.print(e.toString(), PrintTypes.ERROR); - } - } - - public synchronized void start() { - this.run(); - } - - @Override - public void run() { - try { - Thread.sleep(300); - initSongNumber(); - // System.out.println("[MUSIC] loading song: " + - // songName[songNumber].substring(7, (songName[songNumber].length() - // - 4))); - Music music = new Music( - Game.class.getResourceAsStream(songName[songNumber])); - // Thread.sleep(100); - print.print(" Playing song: " - + songName[songNumber].substring(7, - (songName[songNumber].length() - 4)), PrintTypes.MUSIC); - music.Play(); - this.run(); - } catch (InterruptedException e) { - print.print(" Could not stop, nothing currenly playing", PrintTypes.ERROR); - } - } - - public void stop() { - - } - - private void initSongNumber() { - Music.songNumber = rand.nextInt(3); - } - - public String[] getSongName() { - return songName; - } - - public int getSongNumber() { - return songNumber; - } -} diff --git a/src/com/redomar/game/lib/Name.java b/src/com/redomar/game/lib/Name.java index a216932..7133819 100644 --- a/src/com/redomar/game/lib/Name.java +++ b/src/com/redomar/game/lib/Name.java @@ -2,19 +2,20 @@ import java.util.Random; +@Deprecated public class Name { - private Random rand = new Random(); private static int name_ID; public Name() { + Random rand = new Random(); setRand(rand); } + @Deprecated public String setName(String name) { - String finalName = name + name_ID; - return finalName; + return name + name_ID; } public static void setRand(Random rand) { diff --git a/src/com/redomar/game/lib/SleepThread.java b/src/com/redomar/game/lib/SleepThread.java index 92dc7db..7a9ada6 100644 --- a/src/com/redomar/game/lib/SleepThread.java +++ b/src/com/redomar/game/lib/SleepThread.java @@ -2,8 +2,8 @@ import com.redomar.game.Game; -public class SleepThread implements Runnable{ - +public class SleepThread implements Runnable { + public void run() { try { Thread.sleep(1500); diff --git a/src/com/redomar/game/lib/Time.java b/src/com/redomar/game/lib/Time.java index aa248ee..bc477fc 100644 --- a/src/com/redomar/game/lib/Time.java +++ b/src/com/redomar/game/lib/Time.java @@ -15,4 +15,11 @@ public synchronized String getTime() { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); return (sdf.format(cal.getTime())); } + + public synchronized String getTimeDate() { + Calendar cal = Calendar.getInstance(); + cal.getTime(); + SimpleDateFormat sdf = new SimpleDateFormat("E dd MMM Y HH:mm:ss"); + return (sdf.format(cal.getTime())); + } } diff --git a/src/com/redomar/game/lib/utils/Vector2i.java b/src/com/redomar/game/lib/utils/Vector2i.java index 5d08a0b..908301d 100644 --- a/src/com/redomar/game/lib/utils/Vector2i.java +++ b/src/com/redomar/game/lib/utils/Vector2i.java @@ -1,41 +1,34 @@ package com.redomar.game.lib.utils; public class Vector2i { - + private int x, y; - - public Vector2i(){ - set(0, 0); - } - - public Vector2i(int x, int y){ + + + public Vector2i(int x, int y) { set(x, y); } - - public Vector2i(Vector2i vector){ - set(vector.x, vector.y); - } - - public Vector2i add(Vector2i vector){ + + public Vector2i add(Vector2i vector) { this.x += vector.x; this.y += vector.y; return this; } - - public Vector2i subtract(Vector2i vector){ + + @SuppressWarnings("unused") + public Vector2i subtract(Vector2i vector) { this.x -= vector.x; this.y -= vector.y; return this; } - - public boolean equals(Object object){ + + public boolean equals(Object object) { if (!(object instanceof Vector2i)) return false; Vector2i vector = (Vector2i) object; - if(vector.getX() == this.getX() && vector.getY() == this.getY()) return true; - return false; + return vector.getX() == this.getX() && vector.getY() == this.getY(); } - - public void set(int x, int y){ + + public void set(int x, int y) { this.x = x; this.y = y; } diff --git a/src/com/redomar/game/log/PrintToLog.java b/src/com/redomar/game/log/PrintToLog.java new file mode 100644 index 0000000..e3622e4 --- /dev/null +++ b/src/com/redomar/game/log/PrintToLog.java @@ -0,0 +1,35 @@ +package com.redomar.game.log; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintWriter; + +public class PrintToLog { + + private static PrintWriter printer; + private final File url; + + public PrintToLog(String url) { + this.url = new File(url); + initiate(); + } + + public void log(String data) { + printer.println(data); + printer.close(); + } + + private void initiate() { + try { + printer = new PrintWriter(new FileOutputStream(url, true)); + } catch (FileNotFoundException e) { + //throw new FileNotFoundException(); + System.err.println(e.getMessage()); + } + } + + public File getUrl() { + return this.url; + } +} diff --git a/src/com/redomar/game/log/PrintTypes.java b/src/com/redomar/game/log/PrintTypes.java new file mode 100644 index 0000000..c2708f3 --- /dev/null +++ b/src/com/redomar/game/log/PrintTypes.java @@ -0,0 +1,5 @@ +package com.redomar.game.log; + +public enum PrintTypes { + GAME, LEVEL, ENTITY, INPUT, MUSIC, NETWORK, SERVER, ERROR, TEST, SYSTEM +} diff --git a/src/com/redomar/game/log/Printer.java b/src/com/redomar/game/log/Printer.java new file mode 100644 index 0000000..a27205f --- /dev/null +++ b/src/com/redomar/game/log/Printer.java @@ -0,0 +1,134 @@ +package com.redomar.game.log; + +import com.redomar.game.lib.Time; + +import java.io.File; +import java.util.Arrays; + +public class Printer { + + private static int lineNumber = 0; + private final Time time = new Time(); + private PrintTypes type; + private String message; + private boolean evalTypeAsException = false; + private boolean mute = false; + private boolean highlight = false; + + public Printer() { + this.type = PrintTypes.GAME; + } + + public Printer(PrintTypes type) { + this.type = type; + } + + public void print(String message, PrintTypes type) { + this.type = type; + this.message = message; + printOut(); + } + + public void print(String message) { + this.message = message; + printOut(); + } + + private void printOut() { + String ANSI_RESET = "\u001B[0m"; + String ANSI_CYAN = "\u001B[36m"; + String ANSI_BACKGROUND_BLACK = "\u001B[40m"; + String msgTime = "[" + time.getTime() + "]"; + String msgType = "[" + type.toString() + "]"; + + PrintToLog logFile = printToLogType(type); + if (lineNumber == 0) { + + String dashes = ""; + String title = ("[" + time.getTimeDate() + "]"); + char dash = '-'; + int number = Math.max((title.length() / 3), 10); + + char[] repeat = new char[number]; + Arrays.fill(repeat, dash); + dashes += new String(repeat); + + logFile.log(String.format("%s%s%s", dashes, title, dashes)); + lineNumber++; + } + logFile.log(String.format("%s%s\t%s", msgTime, msgType, message)); + + if (mute) return; + String formattedStringForConsole = String.format("%s %s\t %s%n", msgTime, msgType, message); + if (highlight) { + formattedStringForConsole = String.format("%s %s\t%s %s%s %s%n", msgTime, msgType, ANSI_BACKGROUND_BLACK, ANSI_CYAN, message, ANSI_RESET); + highlight = false; + } + + if (type.equals(PrintTypes.ERROR) || evalTypeAsException) { + System.err.printf(formattedStringForConsole); + evalTypeAsException = false; + } else { + System.out.printf(formattedStringForConsole); + } + } + + private PrintToLog printToLogType(PrintTypes type) { + if (type == PrintTypes.TEST) { + return new PrintToLog(".PrintType-TEST.txt"); + } else { + return new PrintToLog(".log.txt"); + } + } + + /** + * Highlight the message in the console + * + * @return Printer + */ + public Printer highlight() { + this.highlight = true; + return this; + } + + public boolean removeLog() { + return new File(".log.txt").delete(); + } + + public String getMessage() { + return message; + } + + public void mute() { + this.mute = true; + } + + @SuppressWarnings("unused") + public void unmute() { + this.mute = false; + } + + /** + * Error that keeps the current {@link PrintTypes PrintType } instead of using {@link PrintTypes PrintTypes.ERROR} + * + * @return Printer + */ + public Printer cast() { + this.evalTypeAsException = true; + return this; + } + + /** + * Print exception as message, cast to keep {@link PrintTypes PrintType } + * + * @param exceptionMessage message to print + * @return Printer + */ + public Printer exception(String exceptionMessage) { + if (!this.evalTypeAsException) this.type = PrintTypes.ERROR; + print(exceptionMessage); + return this; + } + + +} diff --git a/src/com/redomar/game/menu/DedicatedJFrame.java b/src/com/redomar/game/menu/DedicatedJFrame.java index 2ba5857..ca356fa 100644 --- a/src/com/redomar/game/menu/DedicatedJFrame.java +++ b/src/com/redomar/game/menu/DedicatedJFrame.java @@ -1,10 +1,7 @@ package com.redomar.game.menu; -import java.awt.BorderLayout; -import java.awt.Canvas; -import java.awt.Dimension; - -import javax.swing.JFrame; +import javax.swing.*; +import java.awt.*; public class DedicatedJFrame extends Canvas { @@ -26,11 +23,11 @@ public DedicatedJFrame(int WIDTH, int HEIGHT, int SCALE, String NAME) { frame.setVisible(true); } - public JFrame getFrame() { + public static JFrame getFrameStatic() { return frame; } - - public static JFrame getFrameStatic(){ + + public JFrame getFrame() { return frame; } diff --git a/src/com/redomar/game/menu/HelpMenu.java b/src/com/redomar/game/menu/HelpMenu.java new file mode 100644 index 0000000..0979621 --- /dev/null +++ b/src/com/redomar/game/menu/HelpMenu.java @@ -0,0 +1,68 @@ +package com.redomar.game.menu; + +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.URL; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Credit to Gagandeep Bali @ stackoverflow + */ +public class HelpMenu { + + private final JFrame frame = new JFrame("Help Menu"); + + private static void run() { + Runnable runnable = () -> new HelpMenu().displayGUI(); + EventQueue.invokeLater(runnable); + } + + private void displayGUI() { + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + MyPanel contentPane = new MyPanel(); + + frame.setContentPane(contentPane); + frame.setLocationRelativeTo(null); + frame.pack(); + frame.setLocationByPlatform(true); + frame.setVisible(true); + } + + public void helpMenuLaunch() { + run(); + } + + public void helpMenuClose() { + frame.setVisible(false); + frame.dispose(); + } + + private static class MyPanel extends JPanel { + + private BufferedImage image; + + private MyPanel() { + try { + AtomicReference controlsImageResource = new AtomicReference<>(MyPanel.class.getResource("/controls/controls.png")); + image = ImageIO.read(controlsImageResource.get()); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + + @Override + public Dimension getPreferredSize() { + return image == null ? new Dimension(400, 300) : new Dimension(image.getWidth(), image.getHeight()); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + g.drawImage(image, 0, 0, this); + } + } +} diff --git a/src/com/redomar/game/menu/Menu.java b/src/com/redomar/game/menu/Menu.java index 2bca48f..79d50f7 100644 --- a/src/com/redomar/game/menu/Menu.java +++ b/src/com/redomar/game/menu/Menu.java @@ -1,54 +1,117 @@ package com.redomar.game.menu; -import java.awt.Color; -import java.awt.Graphics; +import com.redomar.game.Game; +import com.redomar.game.audio.AudioHandler; +import com.redomar.game.event.Mouse; +import com.redomar.game.lib.Font; +import com.redomar.game.log.PrintTypes; +import com.redomar.game.log.Printer; +import com.thehowtotutorial.splashscreen.JSplash; + +import javax.swing.*; +import java.awt.*; import java.awt.event.KeyListener; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.BufferStrategy; - -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.UIManager; - -import org.apache.commons.lang3.text.WordUtils; - -import com.redomar.game.Game; -import com.redomar.game.lib.Font; -import com.redomar.game.lib.Mouse; -import com.thehowtotutorial.splashscreen.JSplash; +import java.net.URL; +import java.util.concurrent.atomic.AtomicReference; public class Menu implements Runnable { + private static final int VOLUME_IN_DB = -20; + private static final String NAME = "Menu"; private static final int WIDTH = 160; private static final int HEIGHT = (WIDTH / 3 * 2); private static final int SCALE = 3; - private static final String NAME = "Menu"; - private static boolean running = false; - private static boolean selectedStart = false; + private static boolean selectedStart = true; private static boolean selectedExit = false; - private static boolean gameOver = false; + private static DedicatedJFrame frame; - private static DedicatedJFrame frame;// = new DedicatedJFrame(WIDTH, HEIGHT, - // SCALE, NAME); - private Font font = new Font(); - private MouseListener Mouse = new Mouse(); - private KeyListener Key = new MenuInput(); + private final Font font = new Font(); + private final MouseListener menuMouseListener = new Mouse(); + private final KeyListener menuKeyListener = new MenuInput(); - private Color selected = new Color(0xFFFF8800); - private Color deSelected = new Color(0xFFCC5500); + private final Color SELECTED_COLOUR = new Color(0xFFFF8800); + private final Color UNSELECTED_COLOUR = new Color(0xFFCC5500); - public synchronized void start() { - running = true; - play(); - new Thread(this, "MENU").start(); + public static void play() { + Printer printer = new Printer(); + String property = System.getProperty("java.version"); + printer.print("RUNTIME JAVA VERSION " + property, PrintTypes.SYSTEM); + try { + // Splash screen + AtomicReference splashImageResource = new AtomicReference<>(Game.class.getResource("/splash/splash.png")); + JSplash splash = new JSplash(splashImageResource.get(), true, true, false, Game.getGameVersion(), null, Color.RED, Color.ORANGE); + splash.toFront(); + splash.requestFocus(); + splash.splashOn(); + + // Background tasks + try { + Game.setBackgroundMusic(new AudioHandler("/music/Towards The End.wav", true)); + Game.getBackgroundMusic().setVolume(VOLUME_IN_DB); + } catch (Exception e) { + printer.exception(e.getMessage()); + } + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + Game.setAlternateColsR(true); + Game.setAlternateColsS(true); + splash.setProgress(100, "Starting Game..."); + Thread.sleep(650); + + // Frame Init + frame = new DedicatedJFrame(WIDTH, HEIGHT, SCALE, NAME); + frame.getFrame().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.requestFocus(); + + // Hide splash + splash.splashOff(); + splash.removeAll(); + } catch (Exception e) { + printer.exception(e.getMessage()); + } + } + + public static DedicatedJFrame getFrame() { + return Menu.frame; + } + + public static boolean isRunning() { + return running; + } + + public static void setRunning(boolean running) { + Menu.running = running; + } + + public static boolean isSelectedStart() { + return selectedStart; + } + + public static void setSelectedStart(boolean selectedStart) { + Menu.selectedStart = selectedStart; + } + + public static boolean isSelectedExit() { + return selectedExit; + } + + public static void setSelectedExit(boolean selectedExit) { + Menu.selectedExit = selectedExit; } public static synchronized void stop() { running = false; } + public synchronized void start() { + running = true; + play(); + new Thread(this, "MENU").start(); + } + public void run() { long lastTime = System.nanoTime(); double nsPerTick = 1000000000D / 30D; @@ -71,12 +134,6 @@ public void run() { shouldRender = true; } - try { - Thread.sleep(2); - } catch (InterruptedException e) { - e.printStackTrace(); - } - if (shouldRender) { frames++; render(); @@ -84,8 +141,7 @@ public void run() { if (System.currentTimeMillis() - lastTimer >= 1000) { lastTimer += 1000; - frame.getFrame().setTitle( - "Frames: " + frames + " Ticks: " + ticks); + frame.getFrame().setTitle("Frames: " + frames + " Ticks: " + ticks); frames = 0; ticks = 0; } @@ -94,9 +150,9 @@ public void run() { private void render() { // frame.getFrame().getContentPane().setBackground(Color.GREEN); - frame.addMouseMotionListener((MouseMotionListener) Mouse); - frame.addMouseListener(Mouse); - frame.addKeyListener(Key); + frame.addMouseMotionListener((MouseMotionListener) menuMouseListener); + frame.addMouseListener(menuMouseListener); + frame.addKeyListener(menuKeyListener); BufferStrategy bs = frame.getBufferStrategy(); if (bs == null) { frame.createBufferStrategy(3); @@ -106,21 +162,14 @@ private void render() { g.setColor(Color.BLACK); g.fillRect(0, 0, frame.getWidth(), frame.getHeight()); g.setColor(new Color(0xFF660000)); - g.fillRect(10, 10, (WIDTH * 3) - 10, (HEIGHT * 3) - 10); + g.fillRect(0, 0, WIDTH * 3, HEIGHT * 3); g.setColor(new Color(0xFFFF9900)); g.setFont(font.getArial()); - if (isGameOver()) { - g.drawString("GAME OVER... What will you do now?", 35, 30); - } else { - String name = (Game.getJdata_UserName().length() >= 1) ? WordUtils - .capitalizeFully(Game.getJdata_UserName()).toString() - : "Player"; - g.drawString("Welcome to JavaGame " + name, 35, 30); - } - g.drawLine(10, (HEIGHT * 3), 10, 10); - g.drawLine(10, 10, (WIDTH * 3), 10); - g.drawLine((WIDTH * 3), 10, (WIDTH * 3), (HEIGHT * 3)); - g.drawLine(10, (HEIGHT * 3), (WIDTH * 3), (HEIGHT * 3)); + g.drawString("Welcome to JavaGame", 35, 30); + g.drawLine(0, HEIGHT * 3, 0, 0); + g.drawLine(0, 0, (WIDTH * 3), 0); + g.drawLine((WIDTH * 3), 0, (WIDTH * 3), (HEIGHT * 3)); + g.drawLine(0, (HEIGHT * 3), (WIDTH * 3), (HEIGHT * 3)); // (LEFT,DOWN,WIDTH,HEIGHT) paintButtons(isSelectedStart(), isSelectedExit(), g); bs.show(); @@ -133,176 +182,28 @@ private void paintButtons(boolean start, boolean exit, Graphics g) { if (!start) { g.setColor(new Color(0xFFBB4400)); g.fillRect(35, 40, (frame.getWidth() - 67), 113); - g.setColor(getDeSelected()); - g.fillRect(35, 40, (frame.getWidth() - 70), 110); - g.setColor(Color.BLACK); - g.drawString("Start", 220, 95); + g.setColor(UNSELECTED_COLOUR); } else { g.setColor(new Color(0xFFDD6600)); g.fillRect(35, 40, (frame.getWidth() - 67), 113); - g.setColor(getSelected()); - g.fillRect(35, 40, (frame.getWidth() - 70), 110); - g.setColor(Color.BLACK); - g.drawString("Start", 220, 95); + g.setColor(SELECTED_COLOUR); } + g.fillRect(35, 40, (frame.getWidth() - 70), 110); + g.setColor(Color.BLACK); + g.drawString("Start", 220, 95); // EXIT if (!exit) { g.setColor(new Color(0xFFBB4400)); g.fillRect(35, 170, (frame.getWidth() - 67), 113); - g.setColor(getDeSelected()); - g.fillRect(35, 170, (frame.getWidth() - 70), 110); - g.setColor(Color.BLACK); - g.drawString("Exit", 220, 220); + g.setColor(UNSELECTED_COLOUR); } else { g.setColor(new Color(0xFFDD6600)); g.fillRect(35, 170, (frame.getWidth() - 67), 113); - g.setColor(getSelected()); - g.fillRect(35, 170, (frame.getWidth() - 70), 110); - g.setColor(Color.BLACK); - g.drawString("Exit", 220, 220); - } - } - - public static void play() { - try { - JSplash splash = new JSplash( - Game.class.getResource("/splash/splash.png"), true, true, - false, Game.getGameVersion(), null, Color.RED, Color.ORANGE); - splash.toFront(); - splash.requestFocus(); - splash.splashOn(); - splash.setProgress(10, "Initializing Game"); - Thread.sleep(250); - splash.setProgress(25, "Loading Classes"); - Thread.sleep(125); - splash.setProgress(35, "Applying Configurations"); - Thread.sleep(125); - splash.setProgress(40, "Loading Sprites"); - Thread.sleep(250); - splash.setProgress(50, "Loading Textures"); - Thread.sleep(125); - splash.setProgress(60, "Loading Map"); - Thread.sleep(500); - splash.setProgress(80, "Configuring Map"); - Thread.sleep(125); - splash.setProgress(90, "Pulling InputPanes"); - Thread.sleep(250); - splash.setProgress(92, "Acquiring data: Multiplayer"); - Thread.sleep(125); - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - String multiMsg = "Sorry but multiplayer has been disabled on this version.\nIf you would like multiplayer checkout Alpha 1.6"; - JOptionPane.showMessageDialog(Game.getGame(), multiMsg, - "Multiplayer Warning", JOptionPane.WARNING_MESSAGE); - // Game.setJdata_Host(JOptionPane.showConfirmDialog(Game.getGame(), - // "Do you want to be the HOST?")); - Game.setJdata_Host(1); - if (Game.getJdata_Host() != 1) { // Game.getJdata_Host() == 1 - Game.setJdata_IP(JOptionPane.showInputDialog(Game.getGame(), - "Enter the name \nleave blank for local")); - } - Thread.sleep(125); - splash.setProgress(94, "Acquiring data: Username"); - String s = JOptionPane.showInputDialog(Game.getGame(), - "Enter a name"); - if (s != null) { - Game.setJdata_UserName(s); - } - Thread.sleep(125); - splash.setProgress(96, "Collecting Player Data"); - Object[] options = { "African", "Caucasian" }; - int n = JOptionPane.showOptionDialog(frame, - "Choose a race for the charater to be", "Choose a race", - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, - null, options, options[0]); - if (n == 0) { - Game.setAternateColsR(true); - } else { - Game.setAternateColsR(false); - } - Thread.sleep(250); - Object[] options1 = { "Orange", "Black" }; - int n1 = JOptionPane.showOptionDialog(frame, - "Which Colour do you want the shirt to be?", - "Choose a shirt Colour", JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE, null, options1, options1[0]); - if (n1 == 0) { - Game.setAternateColsS(true); - } else { - Game.setAternateColsS(false); - } - splash.setProgress(97, "Connecting as" + Game.getJdata_UserName()); - Thread.sleep(250); - splash.splashOff(); - frame = new DedicatedJFrame(WIDTH, HEIGHT, SCALE, NAME); - frame.getFrame(); - frame.getFrame().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - } catch (Exception e) { - e.printStackTrace(); + g.setColor(SELECTED_COLOUR); } - } - - public static DedicatedJFrame getFrame() { - return Menu.frame; - } - - public static void setFrame(DedicatedJFrame frame) { - Menu.frame = frame; - } - - public static boolean isRunning() { - return running; - } - - public static void setRunning(boolean running) { - Menu.running = running; - } - - public static boolean isSelectedStart() { - return selectedStart; - } - - public static void setSelectedStart(boolean selectedStart) { - Menu.selectedStart = selectedStart; - } - - public static boolean isSelectedExit() { - return selectedExit; - } - - public static void setSelectedExit(boolean selectedExit) { - Menu.selectedExit = selectedExit; - } - - public Color getSelected() { - return selected; - } - - public void setSelected(Color selected) { - this.selected = selected; - } - - public Color getDeSelected() { - return deSelected; - } - - public void setDeSelected(Color deSelected) { - this.deSelected = deSelected; - } - - public static int getWidth() { - return WIDTH; - } - - public static int getHeight() { - return HEIGHT; - } - - public static boolean isGameOver() { - return gameOver; - } - - public static void setGameOver(boolean gameOver) { - Menu.gameOver = gameOver; + g.fillRect(35, 170, (frame.getWidth() - 70), 110); + g.setColor(Color.BLACK); + g.drawString("Exit", 220, 220); } } diff --git a/src/com/redomar/game/menu/MenuInput.java b/src/com/redomar/game/menu/MenuInput.java index ebc46a1..ea4f60b 100644 --- a/src/com/redomar/game/menu/MenuInput.java +++ b/src/com/redomar/game/menu/MenuInput.java @@ -1,13 +1,15 @@ package com.redomar.game.menu; +import com.redomar.game.Game; + import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import com.redomar.game.Game; - public class MenuInput implements KeyListener { - + + private static final HelpMenu HELP_MENU = new HelpMenu(); private boolean ticket = false; + private boolean help = false; public void keyPressed(KeyEvent e) { toggleKey(e.getKeyCode()); @@ -22,25 +24,26 @@ public void keyTyped(KeyEvent e) { } private void toggleKey(int keyCode) { - + if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_W) { Menu.setSelectedStart(true); Menu.setSelectedExit(false); } - + if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_S) { Menu.setSelectedExit(true); Menu.setSelectedStart(false); } - - if(!ticket){ - if (keyCode == KeyEvent.VK_ENTER) { + + if (!ticket) { + if (keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_SPACE) { if (Menu.isSelectedStart()) { this.ticket = true; + new Game().start(); Menu.setRunning(false); Menu.getFrame().setVisible(false); Menu.getFrame().stopFrame(); - new Game().start(); + Menu.stop(); } if (Menu.isSelectedExit()) { @@ -48,12 +51,20 @@ private void toggleKey(int keyCode) { Menu.setRunning(false); Menu.getFrame().setVisible(false); Menu.getFrame().stopFrame(); + Menu.stop(); } } } - + if (keyCode == KeyEvent.VK_ESCAPE) { - System.exit(1); + HELP_MENU.helpMenuClose(); + help = false; + System.exit(0); + } + + if (keyCode == KeyEvent.VK_H) { + if (!help) HELP_MENU.helpMenuLaunch(); + help = true; } } diff --git a/src/com/redomar/game/menu/PopUp.java b/src/com/redomar/game/menu/PopUp.java new file mode 100644 index 0000000..3f35171 --- /dev/null +++ b/src/com/redomar/game/menu/PopUp.java @@ -0,0 +1,22 @@ +package com.redomar.game.menu; + +import com.redomar.game.Game; + +import javax.swing.*; + +public class PopUp { + + public boolean active; + + public PopUp() { + active = true; + } + + public int Warn(String msg) { + Object[] options = {"Continue"}; + if (active) { + JFrame frame = Game.getFrame(); + return JOptionPane.showOptionDialog(frame, msg, "Notice", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + } else return 1; + } +} diff --git a/src/com/redomar/game/net/GameClient.java b/src/com/redomar/game/net/GameClient.java index be15718..6fb0f2f 100644 --- a/src/com/redomar/game/net/GameClient.java +++ b/src/com/redomar/game/net/GameClient.java @@ -1,99 +1,67 @@ package com.redomar.game.net; -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; -import java.net.UnknownHostException; - import com.redomar.game.Game; import com.redomar.game.entities.PlayerMP; import com.redomar.game.net.packets.Packet; +import com.redomar.game.net.packets.Packet.PacketTypes; import com.redomar.game.net.packets.Packet00Login; import com.redomar.game.net.packets.Packet01Disconnect; -import com.redomar.game.net.packets.Packet.PacketTypes; import com.redomar.game.net.packets.Packet02Move; -import com.redomar.game.script.*; +import com.redomar.game.log.PrintTypes; +import com.redomar.game.log.Printer; + +import java.io.IOException; +import java.net.*; +@Deprecated public class GameClient extends Thread { + private final Printer print = new Printer(); private InetAddress ipAddress; private DatagramSocket socket; private Game game; - private Printing print = new Printing(); public GameClient(Game game, String ipAddress) { this.setGame(game); try { this.socket = new DatagramSocket(); this.ipAddress = InetAddress.getByName(ipAddress); - } catch (SocketException e) { + } catch (SocketException | UnknownHostException e) { e.printStackTrace(); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - } - - public void run() { - while (true) { - byte[] data = new byte[1024]; - DatagramPacket packet = new DatagramPacket(data, data.length); - try { - socket.receive(packet); - } catch (IOException e) { - e.printStackTrace(); - } - this.parsePacket(packet.getData(), packet.getAddress(), - packet.getPort()); - // System.out.println("SERVER > "+new String(packet.getData())); } } private void parsePacket(byte[] data, InetAddress address, int port) { String message = new String(data).trim(); PacketTypes type = Packet.lookupPacket(message.substring(0, 2)); - Packet packet = null; + Packet packet; switch (type) { - default: - case INVALID: - break; - case LOGIN: - packet = new Packet00Login(data); - handleLogin((Packet00Login) packet, address, port); - break; - case DISCONNECT: - packet = new Packet01Disconnect(data); - print.print("[" + address.getHostAddress() + ":" + port - + "] " + ((Packet01Disconnect) packet).getUsername() - + " has disconnected...", PrintTypes.NETWORK); - Game.getLevel().removeEntity( - ((Packet01Disconnect) packet).getUsername()); - break; - case MOVE: - packet = new Packet02Move(data); - this.handleMove((Packet02Move) packet); - break; + default: + case INVALID: + break; + case LOGIN: + packet = new Packet00Login(data); + handleLogin((Packet00Login) packet, address, port); + break; + case DISCONNECT: + packet = new Packet01Disconnect(data); + print.print("[" + address.getHostAddress() + ":" + port + "] " + ((Packet01Disconnect) packet).getUsername() + " has disconnected...", PrintTypes.NETWORK); + Game.getLevel().removeEntity(((Packet01Disconnect) packet).getUsername()); + break; + case MOVE: + packet = new Packet02Move(data); + break; } } private void handleLogin(Packet00Login packet, InetAddress address, int port) { - print.print("[" + address.getHostAddress() + ":" + port + "] " - + packet.getUsername() + " has joined...", PrintTypes.NETWORK); - PlayerMP player = new PlayerMP(Game.getLevel(), packet.getX(), - packet.getY(), packet.getUsername(), address, port, Game.getShirtCol(), Game.getFaceCol()); + print.print("[" + address.getHostAddress() + ":" + port + "] " + packet.getUsername() + " has joined...", PrintTypes.NETWORK); + PlayerMP player = new PlayerMP(Game.getLevel(), packet.getX(), packet.getY(), packet.getUsername(), address, port, Game.getShirtCol(), Game.getFaceCol()); Game.getLevel().addEntity(player); } - private void handleMove(Packet02Move packet) { - Game.getLevel().movePlayer(packet.getUsername(), packet.getX(), - packet.getY(), packet.getNumSteps(), packet.isMoving(), - packet.getMovingDir()); - } - public void sendData(byte[] data) { - DatagramPacket packet = new DatagramPacket(data, data.length, - ipAddress, 1331); + DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, 1331); try { socket.send(packet); } catch (IOException e) { diff --git a/src/com/redomar/game/net/GameServer.java b/src/com/redomar/game/net/GameServer.java index a38bf49..bd96e00 100644 --- a/src/com/redomar/game/net/GameServer.java +++ b/src/com/redomar/game/net/GameServer.java @@ -1,5 +1,15 @@ package com.redomar.game.net; +import com.redomar.game.Game; +import com.redomar.game.entities.PlayerMP; +import com.redomar.game.log.PrintTypes; +import com.redomar.game.log.Printer; +import com.redomar.game.net.packets.Packet; +import com.redomar.game.net.packets.Packet.PacketTypes; +import com.redomar.game.net.packets.Packet00Login; +import com.redomar.game.net.packets.Packet01Disconnect; +import com.redomar.game.net.packets.Packet02Move; + import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; @@ -8,21 +18,13 @@ import java.util.ArrayList; import java.util.List; -import com.redomar.game.Game; -import com.redomar.game.entities.PlayerMP; -import com.redomar.game.net.packets.Packet; -import com.redomar.game.net.packets.Packet00Login; -import com.redomar.game.net.packets.Packet.PacketTypes; -import com.redomar.game.net.packets.Packet01Disconnect; -import com.redomar.game.net.packets.Packet02Move; -import com.redomar.game.script.*; - +@Deprecated public class GameServer extends Thread { + private final List connectedPlayers = new ArrayList<>(); + private final Printer print = new Printer(); private DatagramSocket socket; private Game game; - private List connectedPlayers = new ArrayList(); - private Printing print = new Printing(); public GameServer(Game game) { this.setGame(game); @@ -41,47 +43,41 @@ public void run() { socket.receive(packet); } catch (IOException e) { e.printStackTrace(); + break; } - this.parsePacket(packet.getData(), packet.getAddress(), - packet.getPort()); + this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort()); - // String message = new String(packet.getData()); - // System.out.println("CLIENT ["+packet.getAddress().getHostAddress()+":"+packet.getPort()+"] "+message); - // if(message.trim().equalsIgnoreCase("ping")){ - // sendData("pong".getBytes(), packet.getAddress(), - // packet.getPort()); - // } + String message = new String(packet.getData()); + System.out.println("CLIENT [" + packet.getAddress().getHostAddress() + ":" + packet.getPort() + "] " + message); + if (message.trim().equalsIgnoreCase("ping")) { + sendData("pong".getBytes(), packet.getAddress(), packet.getPort()); + } } } private void parsePacket(byte[] data, InetAddress address, int port) { String message = new String(data).trim(); PacketTypes type = Packet.lookupPacket(message.substring(0, 2)); - Packet packet = null; + Packet packet; switch (type) { - default: - case INVALID: - break; - case LOGIN: - packet = new Packet00Login(data); - print.print("[" + address.getHostAddress() + ":" + port - + "] " + ((Packet00Login) packet).getUsername() - + " has connected...", PrintTypes.SERVER); - PlayerMP player = new PlayerMP(Game.getLevel(), 10, 10, - ((Packet00Login) packet).getUsername(), address, port, Game.getShirtCol(), Game.getFaceCol()); - this.addConnection(player, (Packet00Login) packet); - break; - case DISCONNECT: - packet = new Packet01Disconnect(data); - print.print("[" + address.getHostAddress() + ":" + port - + "] " + ((Packet01Disconnect) packet).getUsername() - + " has disconnected...", PrintTypes.SERVER); - this.removeConnection((Packet01Disconnect) packet); - break; - case MOVE: - packet = new Packet02Move(data); - this.handleMove(((Packet02Move) packet)); + default: + case INVALID: + break; + case LOGIN: + packet = new Packet00Login(data); + print.print("[" + address.getHostAddress() + ":" + port + "] " + ((Packet00Login) packet).getUsername() + " has connected...", PrintTypes.SERVER); + PlayerMP player = new PlayerMP(Game.getLevel(), 10, 10, ((Packet00Login) packet).getUsername(), address, port, Game.getShirtCol(), Game.getFaceCol()); + this.addConnection(player, (Packet00Login) packet); + break; + case DISCONNECT: + packet = new Packet01Disconnect(data); + print.print("[" + address.getHostAddress() + ":" + port + "] " + ((Packet01Disconnect) packet).getUsername() + " has disconnected...", PrintTypes.SERVER); + this.removeConnection((Packet01Disconnect) packet); + break; + case MOVE: + packet = new Packet02Move(data); + this.handleMove(((Packet02Move) packet)); } } @@ -102,8 +98,8 @@ public void addConnection(PlayerMP player, Packet00Login packet) { boolean alreadyConnected = false; for (PlayerMP p : this.connectedPlayers) { if (player.getUsername().equalsIgnoreCase(p.getUsername())) { - if (p.ipAddess == null) { - p.ipAddess = player.ipAddess; + if (p.ipAddress == null) { + p.ipAddress = player.ipAddress; } if (p.port == -1) { @@ -112,10 +108,10 @@ public void addConnection(PlayerMP player, Packet00Login packet) { alreadyConnected = true; } else { - sendData(packet.getData(), p.ipAddess, p.port); + sendData(packet.getData(), p.ipAddress, p.port); packet = new Packet00Login(p.getUsername(), (int) p.getX(), (int) p.getY()); - sendData(packet.getData(), player.ipAddess, player.port); + sendData(packet.getData(), player.ipAddress, player.port); } } if (!alreadyConnected) { @@ -150,8 +146,7 @@ public int getPlayerMPIndex(String username) { } public void sendData(byte[] data, InetAddress ipAddress, int port) { - DatagramPacket packet = new DatagramPacket(data, data.length, - ipAddress, port); + DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, port); try { this.socket.send(packet); } catch (IOException e) { @@ -161,7 +156,7 @@ public void sendData(byte[] data, InetAddress ipAddress, int port) { public void sendDataToAllClients(byte[] data) { for (PlayerMP p : connectedPlayers) { - sendData(data, p.ipAddess, p.port); + sendData(data, p.ipAddress, p.port); } } diff --git a/src/com/redomar/game/net/packets/Packet.java b/src/com/redomar/game/net/packets/Packet.java index 743784f..938c085 100644 --- a/src/com/redomar/game/net/packets/Packet.java +++ b/src/com/redomar/game/net/packets/Packet.java @@ -3,39 +3,15 @@ import com.redomar.game.net.GameClient; import com.redomar.game.net.GameServer; +@Deprecated public abstract class Packet { - public static enum PacketTypes { - INVALID(-1), LOGIN(00), DISCONNECT(01), MOVE(02); - - private int packetId; - - private PacketTypes(int packetId) { - this.packetId = packetId; - } - - public int getId() { - return packetId; - } - } - public byte packetId; public Packet(int packetId) { this.packetId = (byte) packetId; } - public abstract byte[] getData(); - - public abstract void writeData(GameClient client); - - public abstract void writeData(GameServer server); - - public String readData(byte[] data) { - String message = new String(data).trim(); - return message.substring(2); - } - public static PacketTypes lookupPacket(String packetId) { try { return lookupPacket(Integer.parseInt(packetId)); @@ -52,4 +28,29 @@ public static PacketTypes lookupPacket(int id) { } return PacketTypes.INVALID; } + + public abstract byte[] getData(); + + public abstract void writeData(GameClient client); + + public abstract void writeData(GameServer server); + + public String readData(byte[] data) { + String message = new String(data).trim(); + return message.substring(2); + } + + public enum PacketTypes { + INVALID(-1), LOGIN(0x00), DISCONNECT(0x01), MOVE(0x02); + + private final int packetId; + + PacketTypes(int packetId) { + this.packetId = packetId; + } + + public int getId() { + return packetId; + } + } } diff --git a/src/com/redomar/game/net/packets/Packet00Login.java b/src/com/redomar/game/net/packets/Packet00Login.java index 4e61dc4..6382b83 100644 --- a/src/com/redomar/game/net/packets/Packet00Login.java +++ b/src/com/redomar/game/net/packets/Packet00Login.java @@ -3,13 +3,15 @@ import com.redomar.game.net.GameClient; import com.redomar.game.net.GameServer; +@Deprecated public class Packet00Login extends Packet { - private String username; - private int x, y; + private final String username; + private final int x; + private final int y; public Packet00Login(byte[] data) { - super(00); + super(0x00); String[] dataArray = readData(data).split(","); this.username = dataArray[0]; this.x = Integer.parseInt(dataArray[1]); @@ -17,7 +19,7 @@ public Packet00Login(byte[] data) { } public Packet00Login(String username, int x, int y) { - super(00); + super(0x00); this.username = username; this.x = x; this.y = y; diff --git a/src/com/redomar/game/net/packets/Packet01Disconnect.java b/src/com/redomar/game/net/packets/Packet01Disconnect.java index d95eec5..4ac5e20 100644 --- a/src/com/redomar/game/net/packets/Packet01Disconnect.java +++ b/src/com/redomar/game/net/packets/Packet01Disconnect.java @@ -3,17 +3,18 @@ import com.redomar.game.net.GameClient; import com.redomar.game.net.GameServer; +@Deprecated public class Packet01Disconnect extends Packet { - private String username; + private final String username; public Packet01Disconnect(byte[] data) { - super(01); + super(0x01); this.username = readData(data); } public Packet01Disconnect(String username) { - super(01); + super(0x01); this.username = username; } diff --git a/src/com/redomar/game/net/packets/Packet02Move.java b/src/com/redomar/game/net/packets/Packet02Move.java index cff6c14..1336ee0 100644 --- a/src/com/redomar/game/net/packets/Packet02Move.java +++ b/src/com/redomar/game/net/packets/Packet02Move.java @@ -3,16 +3,18 @@ import com.redomar.game.net.GameClient; import com.redomar.game.net.GameServer; +@Deprecated public class Packet02Move extends Packet { - private String username; - private int x, y; - private int numSteps = 0; - private boolean isMoving; - private int movingDir = 1; + private final String username; + private final int x; + private final int y; + private final int numSteps; + private final boolean isMoving; + private final int movingDir; public Packet02Move(byte[] data) { - super(02); + super(0x02); String[] dataArray = readData(data).split(","); this.username = dataArray[0]; this.x = Integer.parseInt(dataArray[1]); @@ -22,9 +24,8 @@ public Packet02Move(byte[] data) { this.movingDir = Integer.parseInt(dataArray[5]); } - public Packet02Move(String username, int x, int y, int numSteps, - boolean isMoving, int movingDir) { - super(02); + public Packet02Move(String username, int x, int y, int numSteps, boolean isMoving, int movingDir) { + super(0x02); this.username = username; this.x = x; this.y = y; @@ -35,9 +36,7 @@ public Packet02Move(String username, int x, int y, int numSteps, @Override public byte[] getData() { - return ("02" + this.username + "," + this.x + "," + this.y + "," - + this.getNumSteps() + "," + (this.isMoving ? 1 : 0) + "," + this - .getMovingDir()).getBytes(); + return ("02" + this.username + "," + this.x + "," + this.y + "," + this.getNumSteps() + "," + (this.isMoving ? 1 : 0) + "," + this.getMovingDir()).getBytes(); } @Override diff --git a/src/com/redomar/game/objects/Inventory.java b/src/com/redomar/game/objects/Inventory.java index ad181a5..96a24e1 100644 --- a/src/com/redomar/game/objects/Inventory.java +++ b/src/com/redomar/game/objects/Inventory.java @@ -10,7 +10,7 @@ public class Inventory { public static boolean closing; public static boolean reset; public static boolean enabled; - private static InventoryWindow inv_window = new InventoryWindow(); + private static final InventoryWindow inv_window = new InventoryWindow(); public static void activate() { x = (int) Game.getPlayer().getX(); @@ -20,17 +20,14 @@ public static void activate() { if (enabled) { if (!open) { if (!closing) { - System.out.println("Opened\nInside this Bag their is:" - + inside()); + System.out.println("Opened\nInside this Bag their is:" + inside()); open = true; Game.getPlayer().setMoving(false); - Game.getInput().untoggle(true); inv_window.start(); } } else { if (closing) { Game.getPlayer().setMoving(true); - Game.getInput().untoggle(false); inv_window.stop(); inv_window.getFrame().setVisible(false); inv_window.getFrame().stopFrame(); @@ -42,7 +39,7 @@ public static void activate() { } } } else { - if (open == true || reset == true || closing == true) { + if (open || reset || closing) { reset = false; open = false; closing = false; @@ -53,7 +50,7 @@ public static void activate() { private static String inside() { String items = " "; for (Items item : Items.values()) { - items = items + item.toString() + ", "; + items = String.format("%s%s, ", items, item.toString()); } return items; } diff --git a/src/com/redomar/game/objects/InventoryHandler.java b/src/com/redomar/game/objects/InventoryHandler.java index 7ee22ca..e7b1cdd 100644 --- a/src/com/redomar/game/objects/InventoryHandler.java +++ b/src/com/redomar/game/objects/InventoryHandler.java @@ -1,28 +1,24 @@ package com.redomar.game.objects; +import com.redomar.game.menu.DedicatedJFrame; + import java.awt.event.WindowEvent; import java.awt.event.WindowListener; -import com.redomar.game.menu.DedicatedJFrame; - public class InventoryHandler implements WindowListener { - - @SuppressWarnings("unused") - private DedicatedJFrame frame; - + public InventoryHandler(DedicatedJFrame frame) { - this.frame = frame; DedicatedJFrame.getFrameStatic().addWindowListener(this); } @Override public void windowActivated(WindowEvent e) { - + } @Override public void windowClosed(WindowEvent e) { - + } public void windowClosing(WindowEvent e) { @@ -32,22 +28,22 @@ public void windowClosing(WindowEvent e) { @Override public void windowDeactivated(WindowEvent e) { - + } @Override public void windowDeiconified(WindowEvent e) { - + } @Override public void windowIconified(WindowEvent e) { - + } @Override public void windowOpened(WindowEvent e) { - + } } diff --git a/src/com/redomar/game/objects/InventoryWindow.java b/src/com/redomar/game/objects/InventoryWindow.java index 3a92e8a..94d7d45 100644 --- a/src/com/redomar/game/objects/InventoryWindow.java +++ b/src/com/redomar/game/objects/InventoryWindow.java @@ -1,33 +1,40 @@ package com.redomar.game.objects; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.image.BufferStrategy; - import com.redomar.game.menu.DedicatedJFrame; -public class InventoryWindow implements Runnable{ +import java.awt.*; +import java.awt.image.BufferStrategy; + +public class InventoryWindow implements Runnable { private static final int WIDTH = 160; private static final int HEIGHT = (WIDTH / 3 * 2); private static final int SCALE = 2; private static final String NAME = "Inventory"; - + private static boolean running = false; - + private static DedicatedJFrame frame; private static InventoryHandler window; - public synchronized void start(){ + public static InventoryHandler getWindow() { + return window; + } + + public static void setWindow(InventoryHandler inventoryHandler) { + InventoryWindow.window = inventoryHandler; + } + + public synchronized void start() { running = true; setFrame(new DedicatedJFrame(WIDTH, HEIGHT, SCALE, NAME)); new Thread(this, NAME).start(); } - - public synchronized void stop(){ + + public synchronized void stop() { running = false; } - + public void run() { long lastTime = System.nanoTime(); double nsPerTick = 1000000000D / 30D; @@ -37,7 +44,7 @@ public void run() { long lastTimer = System.currentTimeMillis(); double delta = 0; - + setWindow(new InventoryHandler(frame)); while (running) { @@ -65,24 +72,23 @@ public void run() { if (System.currentTimeMillis() - lastTimer >= 1000) { lastTimer += 1000; - frame.getFrame().setTitle( - "Frames: " + frames + " Ticks: " + ticks); + frame.getFrame().setTitle("Frames: " + frames + " Ticks: " + ticks); frames = 0; ticks = 0; } } } - + private void render() { BufferStrategy bs = frame.getBufferStrategy(); - if(bs == null){ + if (bs == null) { frame.createBufferStrategy(3); return; } - + Graphics g = bs.getDrawGraphics(); g.setColor(Color.BLACK); - g.fillRect(0, 0, WIDTH*SCALE+10, HEIGHT*SCALE+10); + g.fillRect(0, 0, WIDTH * SCALE + 10, HEIGHT * SCALE + 10); g.setColor(Color.WHITE); g.drawString(NAME, 50, 50); bs.show(); @@ -96,12 +102,4 @@ public DedicatedJFrame getFrame() { public static void setFrame(DedicatedJFrame frame) { InventoryWindow.frame = frame; } - - public static InventoryHandler getWindow() { - return window; - } - - public static void setWindow(InventoryHandler inventoryHandler) { - InventoryWindow.window = inventoryHandler; - } } diff --git a/src/com/redomar/game/objects/Items.java b/src/com/redomar/game/objects/Items.java index 1726d0f..55f705a 100644 --- a/src/com/redomar/game/objects/Items.java +++ b/src/com/redomar/game/objects/Items.java @@ -1,8 +1,5 @@ package com.redomar.game.objects; public enum Items { - Stick, - Torch, - Sword, - Apple; + Stick, Torch, Sword, Apple } diff --git a/src/com/redomar/game/scenes/Scene.java b/src/com/redomar/game/scenes/Scene.java index 73b5ab7..2b869c6 100644 --- a/src/com/redomar/game/scenes/Scene.java +++ b/src/com/redomar/game/scenes/Scene.java @@ -4,19 +4,19 @@ import com.redomar.game.level.LevelHandler; public class Scene { - + private int xOffset, yOffset; - private Screen screen; - private LevelHandler level; - - public Scene(int xOffset, int yOffset, Screen screen, LevelHandler level){ + private final Screen screen; + private final LevelHandler level; + + public Scene(int xOffset, int yOffset, Screen screen, LevelHandler level) { this.xOffset = xOffset; this.yOffset = yOffset; this.screen = screen; this.level = level; } - - public void playerScene(){ + + public void playerScene() { if (xOffset < 0) { xOffset = 0; } diff --git a/src/com/redomar/game/script/PopUp.java b/src/com/redomar/game/script/PopUp.java deleted file mode 100644 index 7d402f6..0000000 --- a/src/com/redomar/game/script/PopUp.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.redomar.game.script; - -import javax.swing.JFrame; -import javax.swing.JOptionPane; - -import com.redomar.game.Game; - -public class PopUp{ - - private JFrame frame; - - public PopUp(){ - frame = Game.getFrame(); - } - - public int Warn(String msg){ - Object[] options = {"Continue"}; - return JOptionPane.showOptionDialog(frame, msg, "Notice", JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, - null, options, options[0]); - } -} diff --git a/src/com/redomar/game/script/PrintTypes.java b/src/com/redomar/game/script/PrintTypes.java deleted file mode 100644 index e192e44..0000000 --- a/src/com/redomar/game/script/PrintTypes.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.redomar.game.script; - -public enum PrintTypes { - GAME, - LEVEL, - MUSIC, - ERROR, - NETWORK, - SERVER; -} diff --git a/src/com/redomar/game/script/Printing.java b/src/com/redomar/game/script/Printing.java deleted file mode 100644 index 26a5c15..0000000 --- a/src/com/redomar/game/script/Printing.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.redomar.game.script; - -import com.redomar.game.lib.Time; -import com.redomar.game.script.PrintTypes; - -public class Printing { - - private PrintTypes type; - private Time time = new Time(); - private String message; - private boolean redMode = false; - - public Printing() { - - } - - public void print(String message, PrintTypes type) { - this.type = type; - setMessage(message); - readMessageType(type); - printOut(); - } - - private void printOut(){ - String msgTime = "[" + time.getTime() + "]"; - String msgType = "[" + type.toString() + "]"; - if(redMode == true){ - System.err.println(msgType + msgTime + message); - }else{ - System.out.println(msgType + msgTime + message); - } - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - private void readMessageType(PrintTypes type){ - if(type == PrintTypes.ERROR){ - this.redMode = true; - } else { - this.redMode = false; - } - } -} diff --git a/test/com/redomar/game/audio/AudioHandlerTest.java b/test/com/redomar/game/audio/AudioHandlerTest.java new file mode 100644 index 0000000..c17faa7 --- /dev/null +++ b/test/com/redomar/game/audio/AudioHandlerTest.java @@ -0,0 +1,43 @@ +package com.redomar.game.audio; + +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.assertTrue; + +/** + * Created by Mohamed on 28/08/2016. + * This file tests the com.redomar.game.audio.AudioHandler class + */ +public class AudioHandlerTest { + + @Before + public void before() { + AudioHandler.musicPrinter.mute(); + } + + @Test + public void bgMusicExists() { + File sfx = new File("res/music/Towards The End.mp3"); + assertTrue(sfx.exists()); + } + + @Test(expected = NullPointerException.class) + public void expectReturnExceptionFileEmptyDir() { + File empty = new File(""); + new AudioHandler(empty); + } + + @Test(expected = NullPointerException.class) + public void expectReturnExceptionFileEmptyPath() { + new AudioHandler(""); + } + + @Test() + public void tryInitiatingAndPlayingNonExistingFile() { + new AudioHandler("//").play(); + } + +} \ No newline at end of file diff --git a/test/com/redomar/game/lib/HashTest.java b/test/com/redomar/game/lib/HashTest.java new file mode 100644 index 0000000..bb5055d --- /dev/null +++ b/test/com/redomar/game/lib/HashTest.java @@ -0,0 +1,64 @@ +package com.redomar.game.lib; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class HashTest { + + private HashGen hashGen; + + @Before + public void setUp() throws Exception{ + hashGen = new HashGen(false,10); + } + + @Test + public void hashNotEmpty(){ + assertNotNull(hashGen.getHash()); + } + + @Test + public void hashZeroLengthNotNull(){ + HashGen hg = new HashGen(false,0); + assertNotNull(hg.getHash()); + } + + @Test + public void compareHashAndPrevious(){ + hashGen.setHexLength(8); + assertEquals(hashGen.getHash(), hashGen.getPreviousHash()); + } + + @Test + public void previousShouldNotGenNewHash(){ + assertEquals(hashGen.getPreviousHash(), hashGen.getPreviousHash()); + } + + @Test + public void hashLengthEqualsZero(){ + HashGen hg = new HashGen(false, 0); + assertEquals(0,hg.getHash().length()); + } + + @Test + public void hashLengthEqualsGivenLength(){ + HashGen hg = new HashGen(false, 80); + assertEquals(80, hg.getHash().length()); + } + + @Test + public void hashLengthEqualsSetLength(){ + HashGen hg = new HashGen(false, 80); + hg.setHexLength(5); + assertEquals(5,hg.getHash().length()); + } + + @Test + public void hashPrefix(){ + HashGen hg = new HashGen(true,0); + assertEquals("0x", hg.getHash()); + } + +} diff --git a/test/com/redomar/game/log/PopUpTest.java b/test/com/redomar/game/log/PopUpTest.java new file mode 100644 index 0000000..3ccb68d --- /dev/null +++ b/test/com/redomar/game/log/PopUpTest.java @@ -0,0 +1,23 @@ +package com.redomar.game.log; + +import com.redomar.game.menu.PopUp; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class PopUpTest { + private PopUp popUp; + + @Before + public void setUp() { + popUp = new PopUp(); + popUp.active = false; + } + + @Test + public void warnIntEfflux() { + assertEquals(1, popUp.Warn("TEST")); + } + +} diff --git a/test/com/redomar/game/log/PrintToLogTest.java b/test/com/redomar/game/log/PrintToLogTest.java new file mode 100644 index 0000000..f38dda5 --- /dev/null +++ b/test/com/redomar/game/log/PrintToLogTest.java @@ -0,0 +1,28 @@ +package com.redomar.game.log; + +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +/** + * Created by Mohamed on 23/08/2016. + *

+ * This file tests the com.redomar.game.script.PrintToLog class + */ +public class PrintToLogTest { + + private PrintToLog print; + + @Test(expected = NullPointerException.class) + public void PrintToLogNullFile() { + print = new PrintToLog(null); + } + + @Test + public void PrintToLogDoesWork() { + print = new PrintToLog(".PrintToLogDoesWork.txt"); + assertTrue(print.getUrl().exists()); + assertTrue(print.getUrl().delete()); + } + +} diff --git a/test/com/redomar/game/log/PrinterTest.java b/test/com/redomar/game/log/PrinterTest.java new file mode 100644 index 0000000..187f524 --- /dev/null +++ b/test/com/redomar/game/log/PrinterTest.java @@ -0,0 +1,48 @@ +package com.redomar.game.log; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.*; + +/** + * Created by Mohamed on 28/08/2016. + * This file tests the com.redomar.game.script.Printing class + */ +public class PrinterTest { + + private Printer printer; + + @Before + public void setUp() { + printer = new Printer(); + } + + @Test + public void printToFileWorks() { + printer.print("TESTING STRING", PrintTypes.TEST); + File file = new File(".PrintType-TEST.txt"); + assertTrue(file.exists()); + assertTrue(file.delete()); + } + + @Test + public void getMessageIsNull() { + assertNull(printer.getMessage()); + } + + @Test + public void messageShouldBeNullAfterPrinting() { + printer.print("Not Null", PrintTypes.TEST); + assertNotNull(printer.getMessage()); + } + + @After + public void cleanUp() { + printer = null; + } + +} \ No newline at end of file