Initial commit

This commit is contained in:
Electroblob
2018-01-19 20:33:04 +00:00
commit da6b007a3a
945 changed files with 60616 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
+22
View File
@@ -0,0 +1,22 @@
# eclipse
bin
*.launch
.settings
.metadata
.classpath
.project
# idea
out
*.ipr
*.iws
*.iml
.idea
# gradle
build
.gradle
# other
eclipse
run
+28
View File
@@ -0,0 +1,28 @@
This is Forge Mod Loader.
You can find the source code at all times at https://github.com/MinecraftForge/FML
This minecraft mod is a clean open source implementation of a mod loader for minecraft servers
and minecraft clients.
The code is authored by cpw.
It began by partially implementing an API defined by the client side ModLoader, authored by Risugami.
http://www.minecraftforum.net/topic/75440-
This support has been dropped as of Minecraft release 1.7, as Risugami no longer maintains ModLoader.
It also contains suggestions and hints and generous helpings of code from LexManos, author of MinecraftForge.
http://www.minecraftforge.net/
Additionally, it contains an implementation of topological sort based on that
published at http://keithschwarz.com/interesting/code/?dir=topological-sort
It also contains code from the Maven project for performing versioned dependency
resolution. http://maven.apache.org/
It also contains a partial repackaging of the javaxdelta library from http://sourceforge.net/projects/javaxdelta/
with credit to it's authors.
Forge Mod Loader downloads components from the Minecraft Coder Pack
(http://mcp.ocean-labs.de/index.php/Main_Page) with kind permission from the MCP team.
+483
View File
@@ -0,0 +1,483 @@
Minecraft Forge is licensed under the terms of the LGPL 2.1 found
here http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt and copied
below.
A note on authorship:
All source artifacts are property of their original author, with
the exclusion of the contents of the patches directory and others
copied from it from time to time. Authorship of the contents of
the patches directory is retained by the Minecraft Forge project.
This is because the patches are partially machine generated
artifacts, and are changed heavily due to the way forge works.
Individual attribution within them is impossible.
Consent:
All contributions to Forge must consent to the release of any
patch content to the Forge project.
A note on infectivity:
The LGPL is chosen specifically so that projects may depend on Forge
features without being infected with its license. That is the
purpose of the LGPL. Mods and others using this code via ordinary
Java mechanics for referencing libraries are specifically not bound
by Forge's license for the Mod code.
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
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 this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
+26
View File
@@ -0,0 +1,26 @@
* Eloraam *
* FlowerChild *
* Hawkye *
* MALfunction84 *
Submitted the sleep handler code for his mod (Somnia) and others to use.
* Scokeev9 *
Gave permission for ScotTools API to be integrated into MCF, and also supported the Forge by converting his mods to use it.
ScotTools Background: ScotTools was an API that enabled modders to add blocks to harvesting levels (and many other ease-of-use features to create new tools), and the first tool API that used block material for block breaking efficiency which allowed blocks from mods that didn't use ScotTools API to break with the correct speed.
* SpaceToad *
* LexManos *
* cpw *
* Minecraft Coder Pack (MCP) *
Forge Mod Loader and Minecraft Forge have permission to distribute and automatically download components of MCP and distribute MCP data files.
This permission is not transitive and others wishing to redistribute the Minecraft Forge source independently should seek permission of MCP or
remove the MCP data files and request their users to download MCP separately.
+10
View File
@@ -0,0 +1,10 @@
IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,40 @@
SoundSystem CodecIBXM Class License:
You are free to use this class for any purpose, commercial or otherwise.
You may modify this class or source code, and distribute it any way you
like, provided the following conditions are met:
1) You may not falsely claim to be the author of this class or any
unmodified portion of it.
2) You may not copyright this class or a modified version of it and then
sue me for copyright infringement.
3) If you modify the source code, you must clearly document the changes
made before redistributing the modified source code, so other users know
it is not the original code.
4) You are not required to give me credit for this class in any derived
work, but if you do, you must also mention my website:
http://www.paulscode.com
5) I the author will not be responsible for any damages (physical,
financial, or otherwise) caused by the use if this class or any
portion of it.
6) I the author do not guarantee, warrant, or make any representations,
either expressed or implied, regarding the use of this class or any
portion of it.
Author: Paul Lamb
http://www.paulscode.com
This software is based on or using the IBXM library available from
http://www.geocities.com/sunet2000/
IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+1
View File
@@ -0,0 +1 @@
# Wizardry
+59
View File
@@ -0,0 +1,59 @@
-------------------------------------------
Source installation information for modders
-------------------------------------------
This code follows the Minecraft Forge installation methodology. It will apply
some small patches to the vanilla MCP source code, giving you and it access
to some of the data and functions you need to build a successful mod.
Note also that the patches are built against "unrenamed" MCP source code (aka
srgnames) - this means that you will not be able to read them directly against
normal code.
Source pack installation information:
Standalone source installation
==============================
Step 1: Open your command-line and browse to the folder where you extracted the zip file.
Step 2: Once you have a command window up in the folder that the downloaded material was placed, type:
Windows: "gradlew setupDecompWorkspace"
Linux/Mac OS: "./gradlew setupDecompWorkspace"
Step 3: After all that finished, you're left with a choice.
For eclipse, run "gradlew eclipse" (./gradlew eclipse if you are on Mac/Linux)
If you preffer to use IntelliJ, steps are a little different.
1. Open IDEA, and import project.
2. Select your build.gradle file and have it import.
3. Once it's finished you must close IntelliJ and run the following command:
"gradlew genIntellijRuns" (./gradlew genIntellijRuns if you are on Mac/Linux)
Step 4: The final step is to open Eclipse and switch your workspace to /eclipse/ (if you use IDEA, it should automatically start on your project)
If at any point you are missing libraries in your IDE, or you've run into problems you can run "gradlew --refresh-dependencies" to refresh the local cache. "gradlew clean" to reset everything {this does not effect your code} and then start the processs again.
Should it still not work,
Refer to #ForgeGradle on EsperNet for more information about the gradle environment.
Tip:
If you do not care about seeing Minecraft's source code you can replace "setupDecompWorkspace" with one of the following:
"setupDevWorkspace": Will patch, deobfusicated, and gather required assets to run minecraft, but will not generated human readable source code.
"setupCIWorkspace": Same as Dev but will not download any assets. This is useful in build servers as it is the fastest because it does the least work.
Tip:
When using Decomp workspace, the Minecraft source code is NOT added to your workspace in a editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes and usually can be accessed under the 'referenced libraries' section of your IDE.
Forge source installation
=========================
MinecraftForge ships with this code and installs it as part of the forge
installation process, no further action is required on your part.
LexManos' Install Video
=======================
https://www.youtube.com/watch?v=8VEdtQLuLO0&feature=youtu.be
For more details update more often refer to the Forge Forums:
http://www.minecraftforge.net/forum/index.php/topic,14048.0.html
+76
View File
@@ -0,0 +1,76 @@
buildscript {
repositories {
jcenter()
maven { url = "http://files.minecraftforge.net/maven" }
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the nessasary things for Forge to be setup.
version = " 2.1.0 - MC 1.10.2"
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "Electroblob's Wizardry "
srcCompat = JavaVersion.VERSION_1_8
targetCompat = JavaVersion.VERSION_1_8
minecraft {
version = "1.10.2-12.18.3.2185"
runDir = "run"
// the mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD snapshot are built nightly.
// stable_# stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not allways work.
// simply re-run your setup task after changing the mappings to update your workspace.
mappings = "snapshot_20161111"
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
}
dependencies {
// you may put jars on which you depend on in ./libs
// or you may define them like so..
//compile "some.group:artifact:version:classifier"
//compile "some.group:artifact:version"
// real examples
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
//provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided,
// except that these dependencies get remapped to your current MCP mappings
//deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev'
//deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// for more info...
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html
}
processResources
{
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
// replace version and mcversion
expand 'version':project.version, 'mcversion':project.minecraft.version
}
// copy everything else, thats not the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
#Mon Sep 14 12:28:28 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
Vendored
+164
View File
@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
Vendored
+90
View File
@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -0,0 +1,176 @@
package electroblob.wizardry;
import electroblob.wizardry.item.ItemSpectralBow;
import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketCastSpell;
import electroblob.wizardry.packet.PacketClairvoyance;
import electroblob.wizardry.packet.PacketGlyphData;
import electroblob.wizardry.packet.PacketNPCCastSpell.Message;
import electroblob.wizardry.packet.PacketPlayerSync;
import electroblob.wizardry.packet.PacketTransportation;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.WizardryParticleType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.world.World;
import net.minecraftforge.common.config.Property;
/**
* The common proxy for wizardry, serving the usual purpose of dealing with all things that need to be handled
* differently on the client and the server. A lot of the methods here appear to do absolutely nothing; this is
* because they do client-only things which are only handled in the client proxy.
* @see {@link electroblob.wizardry.client.ClientProxy}
* @author Electroblob
* @since Wizardry 1.0
* */
@SuppressWarnings("deprecation")
public class CommonProxy {
// SECTION Registry
// ===============================================================================================================
public void registerRenderers(){}
public void initialiseLayers(){}
public void registerKeyBindings(){}
public void registerSpellHUD(){}
public net.minecraft.client.model.ModelBiped getWizardArmourModel(){ return null; }
public void initMixedFontRenderer(){}
// SECTION Particles
// ===============================================================================================================
/**
* Spawns a custom particle of the specified type.
*
* @param type EnumParticleType of the particle
* @param world Reference to the World object
* @param x Particle x position
* @param y Particle y position
* @param z Particle z position
* @param velX Particle x velocity
* @param velY Particle y velocity
* @param velZ Particle z velocity
* @param maxAge Lifetime of the particle in ticks
* @param r Red component of particle colour; will be clamped to between 0 and 1
* @param g Red component of particle colour; will be clamped to between 0 and 1
* @param b Red component of particle colour; will be clamped to between 0 and 1
* @param doGravity Whether the particle is affected by gravity (only affects SPARKLE at the moment)
* @param radius The radius of the particle's motion, for cirular motion particles
*/
public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b, boolean doGravity, double radius){
// Does nothing since particles are client-side only
}
/** Spawns a custom particle of the specified type. doGravity defaults to false and radius defaults to 0.
* Note that some of these settings may not affect the particle; some particles are always affected by
* gravity, for instance.
*
* @param type EnumParticleType of the particle
* @param world Reference to the World object
* @param x Particle x position
* @param y Particle y position
* @param z Particle z position
* @param velX Particle x velocity
* @param velY Particle y velocity
* @param velZ Particle z velocity
* @param maxAge Lifetime of the particle in ticks
* @param r Red component of particle colour; will be clamped to between 0 and 1 (unless this is a MAGIC_FIRE particle, in which case this is the scale)
* @param g Red component of particle colour; will be clamped to between 0 and 1
* @param b Red component of particle colour; will be clamped to between 0 and 1
*/
public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b){
this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, r, g, b, false, 0);
}
/** Spawns a custom particle of the specified type. Colour defaults to white, doGravity defaults to false and radius
* defaults to 0. Note that some of these settings may not affect the particle; some particles are always affected by
* gravity, for instance.
*
* @param type EnumParticleType of the particle
* @param world Reference to the World object
* @param x Particle x position
* @param y Particle y position
* @param z Particle z position
* @param velX Particle x velocity
* @param velY Particle y velocity
* @param velZ Particle z velocity
* @param maxAge Lifetime of the particle in ticks
*/
public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge){
this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, 1, 1, 1, false, 0);
}
public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){}
// SECTION Items
// ===============================================================================================================
public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack) {
return null;
}
/** Returns the translated name of the scroll, taking spell discovery into account. If, for some reason, this gets
* called server-side, it uses the deprecated server version of I18n, with a warning. Since any likely server-side
* use of this method will be for text-based logic purposes (like Bibliocraft's book checking system), and since no
* particular player instance can be accessed, spell discovery is ignored. */
public String getScrollDisplayName(ItemStack scroll){
// I have now learnt that the server side I18n always translates to the default en_US, so I could just return
// a hardcoded name in English instead.
Wizardry.logger.info("A mod has called ItemScroll#getItemStackDisplayName from the server side. Using the"
+ "deprecated server-side translation methods as a fallback.");
// Displays [Empty slot] if spell is continuous.
Spell spell = Spell.get(scroll.getItemDamage());
if(spell.isContinuous) spell = Spells.none;
return I18n.translateToLocalFormatted("item.wizardry:wizardry:scroll.name", I18n.translateToLocal("spell." + spell.getUnlocalisedName())).trim();
}
public double getConjuredBowDurability(ItemStack stack){
return ((ItemSpectralBow)WizardryItems.spectral_bow).getDefaultDurabilityForDisplay(stack);
}
// SECTION Packet Handlers
// ===============================================================================================================
public void handlePlayerSyncPacket(PacketPlayerSync.Message message){}
public void handleGlyphDataPacket(PacketGlyphData.Message message){}
public void handleCastSpellPacket(PacketCastSpell.Message message){}
public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){}
public void handleNPCCastSpellPacket(Message message){}
public void handleTransportationPacket(PacketTransportation.Message message){}
public void handleClairvoyancePacket(PacketClairvoyance.Message message){}
// SECTION Misc
// ===============================================================================================================
public void setToNumberSliderEntry(Property property){}
//public void setToEntityNameEntry(Property property){}
/** Plays a sound which moves with the given entity.
*
* @param entity The source of the sound
* @param sound The SoundEvent to play
* @param volume Volume relative to 1
* @param pitch Pitch relative to 1
* @param repeat Whether to repeat the sound for as long as the entity is alive (or until stopped manually)
*/
public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){}
/** Gets the client side world using Minecraft.getMinecraft().theWorld. <b>Only to be called client side!</b>
* Returns null on the server side. */
public World getTheWorld(){ return null; }
}
@@ -0,0 +1,507 @@
package electroblob.wizardry;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import electroblob.wizardry.packet.PacketSyncSettings;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.translation.I18n;
import net.minecraftforge.common.config.ConfigCategory;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
/** Singleton class which deals with everything related to wizardry's config file. To access individual settings, use
* {@link Wizardry#settings}. Also stores a few string constants for easy access.
* <p>
* As part of the 1.2 update and code overhaul, the way the config settings work in multiplayer has been tightened up.
* Importantly, there are <b>three</b> different types of config options:
* <p>
* <li>Server-only settings. These only affect server-side code and hence are not synced. Changing these locally only
* has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world. Examples
* include worldgen, mob drops and commands.
* <li>Synchronised settings. These settings affect both client-side AND server-side code, and are synchronised with
* each client on login via {@link Settings#sync(EntityPlayerMP)}. Changing these locally
* only has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world.
* Examples include discovery mode and crafting recipes. <i> Note that as far as users are concerned,
* there is no difference in behaviour between server-only and synchronised settings.</i>
* <li>Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys
* its own values for these, and changing them on a dedicated server will have no effect. These are usually only display
* and controls settings.</li>
* <p>
* Each of the settings fields in this class is marked with one of the above categories to indicate which it belongs
* to. This in turn dictates which logical side it should be called from: client, server or both. <b> Do not access a
* config setting from the wrong side, because it may cause unexpected or strange behaviour.</b>
* @since Wizardry 1.2
* @author Electroblob */
// NOTE: We could convert over to the @Config system IF it is sufficiently complete in this Forge version for my purposes.
// (For one, I know that the LangKey annotation is not applicable to type declarations in 1.10.2, unlike in 1.11.2)
//@Config(modid = Wizardry.MODID)
@SuppressWarnings("deprecation") // Used server I18n deliberately; we want to write the comments in english.
public final class Settings {
// Category names
/** The unlocalised name of the spells config category. */
public static final String SPELLS_CATEGORY = "spells";
/** The unlocalised name of the resistances config category. */
public static final String RESISTANCES_CATEGORY = "resistances";
/** The unlocalised name of the client config category. */
public static final String CLIENT_CATEGORY = "client";
/** The unlocalised name of the commands config category. */
public static final String COMMANDS_CATEGORY = "commands";
/** The unlocalised name of the worldgen config category. */
public static final String WORLDGEN_CATEGORY = "worldgen";
/** The unlocalised name of the global config category. */
public static final String GLOBAL_CATEGORY = "global";
/** The wizardry config file. */
private Configuration config;
// Server-only settings. These only affect server-side code and hence are not synced. Changing these locally only
// has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world.
// Worldgen
/** <b>[Server-only]</b> The rarity of wizard towers, used by the world generator. Larger numbers are rarer. */
public int towerRarity = 8;
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
public int[] oreDimensions = {0};
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
public int[] flowerDimensions = {0};
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
public int[] towerDimensions = {0};
/** <b>[Server-only]</b> Whether or not wizardry loot should generate in dungeon chests. Note that this does not
* affect the generation of loot in wizard towers. */
public boolean generateLoot = true;
// Entities' drops, targeting, damage, etc.
/** <b>[Server-only]</b> Chance (out of 200) for mobs to drop spell books. */
public int spellBookDropChance = 3;
/** <b>[Server-only]</b> Whether or not players can teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. */
public boolean teleportThroughUnbreakableBlocks = false;
/** <b>[Server-only]</b> Whether to allow players to damage their designated allies using magic. */
public boolean friendlyFire = true;
/** <b>[Server-only]</b> Whether to allow players to disarm other players using the telekinesis spell. */
public boolean telekineticDisarmament = true;
/** <b>[Server-only]</b> Whether summoned creatures can revenge attack their caster if their caster attacks them. */
public boolean minionRevengeTargeting = true;
/** <b>[Server-only]</b> List of names of entities which summoned creatures are allowed to attack, in addition to the defaults. */
public String[] summonedCreatureTargetsWhitelist = {};
/** <b>[Server-only]</b> List of names of entities which summoned creatures are specifically not allowed to attack, overriding the defaults and the whitelist. */
public String[] summonedCreatureTargetsBlacklist = {"creeper"};
/** <b>[Server-only]</b> Global damage scaling factor for all player magic damage. */
public double playerDamageScale = 1.0f;
/** <b>[Server-only]</b> Global damage scaling factor for all npc magic damage. */
public double npcDamageScale = 1.0f;
// Commands (these don't need synchronising since typing a command always queries the server).
/** <b>[Server-only]</b> The maximum allowed multiplier for the /cast command. This limit is here to stop people from accidentally
* breaking their worlds! */
public double maxSpellCommandMultiplier = 20d;
/** <b>[Server-only]</b> The name of the /cast command. */
public String castCommandName = "cast";
/** <b>[Server-only]</b> The name of the /discoverspell command. */
public String discoverspellCommandName = "discoverspell";
/** <b>[Server-only]</b> The name of the /ally command. */
public String allyCommandName = "ally";
/** <b>[Server-only]</b> The name of the /allies command. */
public String alliesCommandName = "allies";
// Synchronised settings. These settings affect both client-side AND server-side code. Changing these locally
// only has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world.
// Recipes (only need syncing for display in the wizard's handbook)
/** <b>[Synchronised]</b> Whether or not firebombs should be craftable. */
public boolean firebombIsCraftable = true;
/** <b>[Synchronised]</b> Whether or not poison bombs should be craftable. */
public boolean poisonBombIsCraftable = true;
/** <b>[Synchronised]</b> Whether or not poison bombs should be craftable. */
public boolean smokeBombIsCraftable = true;
/** <b>[Synchronised]</b> Whether to require a magic crystal in the blank scroll crafting recipe (in case it conflicts with another mod). */
public boolean useAlternateScrollRecipe = false;
// Gamemodes
/** <b>[Synchronised]</b> When set to true, spells a player hasn't cast yet will be unreadable until they are cast (on a per-world basis). Has no effect when in creative mode. Spells of
* identification will be unobtainable in survival mode if this is false. */
public boolean discoveryMode = true;
// Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys
// its own values for these, and changing them on a dedicated server will have no effect.
// Controls
/** <b>[Client-only]</b> Whether the player can switch between spells on a wand by scrolling with the mouse wheel while
* sneaking. */
public boolean enableShiftScrolling = true;
// Display
/** <b>[Client-only]</b> Whether to show summoned creatures' names and owners above their heads. */
public boolean showSummonedCreatureNames = true;
/** <b>[Client-only]</b> The position of the spell HUD. */
public GuiPosition spellHUDPosition = GuiPosition.BOTTOM_LEFT;
/** Set of constants for each of the four positions that the spell HUD can be in. */
public enum GuiPosition {
BOTTOM_LEFT("Bottom left"),
TOP_LEFT("Top left"),
TOP_RIGHT("Top right"),
BOTTOM_RIGHT("Bottom right");
/** Constant array storing the names of each of the constants, in the order they are declared. */
public static final String[] names;
static {
names = new String[values().length];
for(GuiPosition position : values()){
names[position.ordinal()] = position.name;
}
}
/** The readable name for this GUI position that will be displayed on the button in the config GUI. */
public final String name;
GuiPosition(String name){
this.name = name;
}
/** Gets a GUI position from its string name (ignoring case), or BOTTOM_LEFT if the given name is not a valid position. */
public static GuiPosition fromName(String name){
for(GuiPosition position : values()){
if(position.name.equalsIgnoreCase(name)) return position;
}
Wizardry.logger.info("Invalid string for the spell HUD position. Using default (bottom left) instead.");
return BOTTOM_LEFT;
}
}
// As of Wizardry 1.1, all keys used in the config file itself are now hardcoded, not localised. The localisations
// are done in the config GUI. The config file has to be written in one language or it will end up with multiple
// options for different languages.
// These methods are package-protected to stop anyone else from calling them.
/** Called from preInit to initialise the config file. The first part of the config file has to be done here (as is
* conventional) so that the various registries can change what they do accordingly. The spell part of the config
* has to be done in the init method.*/
void initConfig(FMLPreInitializationEvent event){
config = new Configuration(event.getSuggestedConfigurationFile());
config.load();
Wizardry.logger.info("Setting up main config");
setupGeneralConfig();
config.save();
}
/** Called from init to initialise the parts of the config file that depend on other mods. For example, the spell
* config is done here and not in preInit because all spells must be registered before it is added, including
* those in other mods. */
void initConfigExtras(){
Wizardry.logger.info("Setting up spells config for " + Spell.getTotalSpellCount() + " spells");
setupSpellsConfig();
config.save();
}
/** Called to save changes to the config file after it has been edited in game from the menus. */
void saveConfigChanges(){
Wizardry.logger.info("Saving in-game config changes");
setupGeneralConfig();
setupSpellsConfig();
config.save();
}
/** Sends a packet to the specified player's client containing all the <b>synchronised</b> settings. */
public void sync(EntityPlayerMP player){
Wizardry.logger.info("Synchronising config settings for " + player.getName());
IMessage message = new PacketSyncSettings.Message(this);
WizardryPacketHandler.net.sendTo(message, player);
}
public ConfigCategory getConfigCategory(String name){
return config.getCategory(name);
}
private void setupSpellsConfig(){
config.addCustomCategoryComment(SPELLS_CATEGORY, "Set a spell to false to disable it. Disabled spells will still have their associated spell book (mainly so the spell books don't all change) and can still be bound to wands, but cannot be cast in game, will not appear in any subsequently generated chests or wizard trades and will not drop from mobs. Disable a spell if it is causing problems, conflicts with another mod or creates an unintended exploit.");
Property property;
for(Spell spell : Spell.getSpells(Spell.allSpells)){
property = config.get(SPELLS_CATEGORY, spell.getRegistryName().toString(), true,
I18n.translateToLocal("spell." + spell.getUnlocalisedName() + ".desc"));
// Uses the same config key as the spell name, because - well, that's what it's called!
property.setLanguageKey("spell." + spell.getUnlocalisedName());
spell.setEnabled(property.getBoolean());
}
}
private void setupGeneralConfig(){
// This trick is borrowed from forge; it sorts the config options into the order you want them.
List<String> propOrder = new ArrayList<String>();
Property property;
config.addCustomCategoryComment(Configuration.CATEGORY_GENERAL, "Please note that changing some of these settings may make the mod very difficult to play.");
property = config.get(Configuration.CATEGORY_GENERAL, "towerRarity", 8, "Rarity of wizard towers. Higher numbers are rarer. Set to 0 to disable wizard towers completely.", 0, 50);
property.setLanguageKey("config.wizardry.tower_rarity");
property.setRequiresWorldRestart(true);
Wizardry.proxy.setToNumberSliderEntry(property);
towerRarity = property.getInt();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "spellBookDropChance", 3, "The chance for mobs to drop a spell book when killed. The greater this number, the more often they will drop. Set to 0 to disable spell book drops. Set to 200 for guaranteed drops.", 0, 200);
property.setLanguageKey("config.wizardry.spell_book_drop_chance");
Wizardry.proxy.setToNumberSliderEntry(property);
spellBookDropChance = property.getInt();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "oreDimensions", new int[]{0}, "List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!");
property.setLanguageKey("config.wizardry.ore_dimensions");
property.setRequiresWorldRestart(true);
oreDimensions = property.getIntList();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "flowerDimensions", new int[]{0}, "List of dimension ids in which crystal flowers will generate.");
property.setLanguageKey("config.wizardry.flower_dimensions");
property.setRequiresWorldRestart(true);
flowerDimensions = property.getIntList();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate.");
property.setLanguageKey("config.wizardry.tower_dimensions");
property.setRequiresWorldRestart(true);
towerDimensions = property.getIntList();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "generateLoot", true, "Whether to generate wizardry loot in dungeon chests.");
property.setLanguageKey("config.wizardry.generate_loot");
property.setRequiresWorldRestart(true);
generateLoot = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "firebombIsCraftable", true, "Whether firebombs can be crafted or not.");
property.setLanguageKey("config.wizardry.firebomb_is_craftable");
property.setRequiresMcRestart(true);
firebombIsCraftable = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "poisonBombIsCraftable", true, "Whether poison bombs can be crafted or not.");
property.setLanguageKey("config.wizardry.poison_bomb_is_craftable");
property.setRequiresMcRestart(true);
poisonBombIsCraftable = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "smokeBombIsCraftable", true, "Whether smoke bombs can be crafted or not.");
property.setLanguageKey("config.wizardry.smoke_bomb_is_craftable");
property.setRequiresMcRestart(true);
smokeBombIsCraftable = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "useAlternateScrollRecipe", false, "Whether to require a magic crystal in the shapeless crafting recipe for blank scrolls. Set to true if another mod adds a conflicting recipe.");
property.setLanguageKey("config.wizardry.use_alternate_scroll_recipe");
property.setRequiresMcRestart(true);
useAlternateScrollRecipe = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "teleportThroughUnbreakableBlocks", false, "Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell.");
property.setLanguageKey("config.wizardry.teleport_through_unbreakable_blocks");
teleportThroughUnbreakableBlocks = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "showSummonedCreatureNames", true, "Whether to show summoned creatures' names and owners above their heads.");
property.setLanguageKey("config.wizardry.show_summoned_creature_names");
showSummonedCreatureNames = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "friendlyFire", true, "Whether to allow players to damage their designated allies using magic.");
property.setLanguageKey("config.wizardry.friendly_fire");
friendlyFire = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "telekineticDisarmament", true, "Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items.");
property.setLanguageKey("config.wizardry.telekinetic_disarmament");
telekineticDisarmament = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "discoveryMode", true, "For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false.");
property.setLanguageKey("config.wizardry.discovery_mode");
property.setRequiresWorldRestart(true);
discoveryMode = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "enableShiftScrolling", true, "Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings.");
property.setLanguageKey("config.wizardry.enable_shift_scrolling");
property.setRequiresWorldRestart(false);
enableShiftScrolling = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "minionRevengeTargeting", true, "Whether summoned creatures can revenge attack their owner if their owner attacks them.");
property.setLanguageKey("config.wizardry.minion_revenge_targeting");
property.setRequiresWorldRestart(false);
minionRevengeTargeting = property.getBoolean();
propOrder.add(property.getName());
// These two aren't sliders because using a slider makes it difficult to fine-tune the numbers; the nature of a
// scaling factor means that 0.5 is as big a change as 2.0, so whilst a slider is fine for increasing the damage,
// it doesn't give fine enough control for values less than 1.
property = config.get(Configuration.CATEGORY_GENERAL, "playerDamageScaling", 1.0, "Global damage scaling factor for the damage dealt by players casting spells, relative to 1.", 0, 20);
property.setLanguageKey("config.wizardry.player_damage_scaling");
playerDamageScale = property.getDouble();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "npcDamageScaling", 1.0, "Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1.", 0, 20);
property.setLanguageKey("config.wizardry.npc_damage_scaling");
npcDamageScale = property.getDouble();
propOrder.add(property.getName());
// This one isn't a slider either because people are likely to want exact values ("it must be at most 50.3" is a bit strange!).
property = config.get(Configuration.CATEGORY_GENERAL, "castCommandMultiplierLimit", 20.0, "Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned!", 1, 255);
property.setLanguageKey("config.wizardry.cast_command_multiplier_limit");
maxSpellCommandMultiplier = property.getDouble();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "summonedCreatureTargetsWhitelist", new String[0], "List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.summoned_creature_targets_whitelist");
property.setRequiresWorldRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
summonedCreatureTargetsWhitelist = property.getStringList();
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<summonedCreatureTargetsWhitelist.length; i++){
summonedCreatureTargetsWhitelist[i] = summonedCreatureTargetsWhitelist[i].toLowerCase(Locale.ROOT).trim();
}
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "summonedCreatureTargetsBlacklist", new String[]{"creeper"}, "List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.summoned_creature_targets_blacklist");
property.setRequiresWorldRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
summonedCreatureTargetsBlacklist = property.getStringList();
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<summonedCreatureTargetsBlacklist.length; i++){
summonedCreatureTargetsBlacklist[i] = summonedCreatureTargetsBlacklist[i].toLowerCase(Locale.ROOT).trim();
}
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "spellHUDPosition", GuiPosition.BOTTOM_LEFT.name, "The position of the spell HUD.", GuiPosition.names);
property.setLanguageKey("config.wizardry.spell_hud_position");
spellHUDPosition = GuiPosition.fromName(property.getString());
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "castCommandName", "cast", "The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead.");
property.setLanguageKey("config.wizardry.cast_command_name");
property.setRequiresWorldRestart(true);
castCommandName = property.getString();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "discoverspellCommandName", "discoverspell", "The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead.");
property.setLanguageKey("config.wizardry.discoverspell_command_name");
property.setRequiresWorldRestart(true);
discoverspellCommandName = property.getString();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "allyCommandName", "ally", "The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead.");
property.setLanguageKey("config.wizardry.ally_command_name");
property.setRequiresWorldRestart(true);
allyCommandName = property.getString();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "alliesCommandName", "allies", "The name of the /allies command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /allies you would type /magic instead.");
property.setLanguageKey("config.wizardry.allies_command_name");
property.setRequiresWorldRestart(true);
alliesCommandName = property.getString();
propOrder.add(property.getName());
config.setCategoryPropertyOrder(Configuration.CATEGORY_GENERAL, propOrder);
// Resistances
List<String> propOrder1 = new ArrayList<String>();
config.addCustomCategoryComment(RESISTANCES_CATEGORY, "Settings which allow entities to be made immune to certain types of magic. In multiplayer, the server/LAN host settings will apply.");
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToFire", new String[]{}, "List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_fire");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.FIRE);
}
propOrder1.add(property.getName());
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToIce", new String[]{}, "List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_ice");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.FROST);
}
propOrder1.add(property.getName());
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToLightning", new String[]{}, "List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_lightning");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.SHOCK);
}
propOrder1.add(property.getName());
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToWither", new String[]{}, "List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_wither");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.WITHER);
}
propOrder1.add(property.getName());
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToPoison", new String[]{}, "List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_poison");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.POISON);
}
propOrder1.add(property.getName());
config.setCategoryPropertyOrder(RESISTANCES_CATEGORY, propOrder1);
// config.addCustomCategoryComment(CLIENT_CATEGORY, "Client-side settings that only affect the local minecraft game. They have no effect on a server; each player obeys their own settings.");
// config.addCustomCategoryComment(COMMANDS_CATEGORY, "Settings for the commands added by Wizardry. In multiplayer, the server/LAN host settings will apply.");
// config.addCustomCategoryComment(WORLDGEN_CATEGORY, "Settings that affect world generation. In multiplayer, the server/LAN host settings will apply.");
// config.addCustomCategoryComment(GLOBAL_CATEGORY, "Global settings that affect game mechanics. In multiplayer, the server/LAN host settings will apply.");
}
}
@@ -0,0 +1,161 @@
package electroblob.wizardry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.commons.lang3.RandomStringUtils;
import electroblob.wizardry.packet.PacketGlyphData;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraft.world.WorldSavedData;
import net.minecraftforge.common.util.Constants.NBT;
/** Class responsible for generating and storing the randomised spell names and descriptions for each world, which are
* displayed as glyphs using the SGA font renderer.
* @since Wizardry 1.1 */
public class SpellGlyphData extends WorldSavedData {
public static final String NAME = Wizardry.MODID + "_glyphData";
public Map<Spell, String> randomNames = new HashMap<Spell, String>(Spell.getTotalSpellCount());
public Map<Spell, String> randomDescriptions = new HashMap<Spell, String>(Spell.getTotalSpellCount());
// Required constructors
public SpellGlyphData() {
this(NAME);
}
public SpellGlyphData(String name){
super(name);
}
/** Generates random names and descriptions for any spells which don't already have them. */
public void generateGlyphNames(World world){
for(Spell spell : Spell.getSpells(Spell.allSpells)){
if(!randomNames.containsKey(spell)) randomNames.put(spell, generateRandomName(world.rand));
}
for(Spell spell : Spell.getSpells(Spell.allSpells)){
if(!randomDescriptions.containsKey(spell)) randomDescriptions.put(spell, generateRandomDescription(world.rand));
}
this.markDirty();
}
private String generateRandomName(Random random){
String name = "";
for(int i=0; i<random.nextInt(2)+2; i++){
name = name + RandomStringUtils.random(3 + random.nextInt(5), "abcdefghijklmnopqrstuvwxyz") + " ";
}
return name.trim();
}
private String generateRandomDescription(Random random){
String name = "";
for(int i=0; i<random.nextInt(16)+8; i++){
name = name + RandomStringUtils.random(2 + random.nextInt(7), "abcdefghijklmnopqrstuvwxyz") + " ";
}
return name.trim();
}
/** Returns the spell glyph data for this world, or creates a new instance if it doesn't exist yet. Also checks
* for any spells that are missing glyph data and adds it accordingly. */
public static SpellGlyphData get(World world) {
SpellGlyphData instance = (SpellGlyphData) world.loadItemData(SpellGlyphData.class, NAME);
if(instance == null){
instance = new SpellGlyphData();
}
// These two conditions are a bit of backwards compatibility from when I added the descriptions to the
// glyph data. Shouldn't be needed in normal operation, but I might as well leave it here.
// Edit: More backwards compatibility, this time for the future - should any new spells be added, this now ensures
// existing worlds will generate random names and descriptions for any new spells whilst keeping the old ones.
if(instance.randomNames.size() < Spell.getTotalSpellCount() || instance.randomDescriptions.size() < Spell.getTotalSpellCount()){
instance.generateGlyphNames(world);
world.setItemData(NAME, instance);
}
return instance;
}
/** Sends the random spell names for this world to the specified player's client. */
public void sync(EntityPlayerMP player){
List<String> names = new ArrayList<String>();
List<String> descriptions = new ArrayList<String>();
for(Spell spell : Spell.getSpells(Spell.allSpells)){
names.add(this.randomNames.get(spell));
descriptions.add(this.randomDescriptions.get(spell));
}
PacketGlyphData.Message msg = new PacketGlyphData.Message(names, descriptions);
WizardryPacketHandler.net.sendTo(msg, player);
}
/** Helper method to retrieve the random glyph name for the given spell from the map stored in the given world. */
public static String getGlyphName(Spell spell, World world){
Map<Spell, String> names = SpellGlyphData.get(world).randomNames;
return names == null ? "" : names.get(spell);
}
/** Helper method to retrieve the random glyph description for the given spell from the map stored in the given world. */
public static String getGlyphDescription(Spell spell, World world){
Map<Spell, String> descriptions = SpellGlyphData.get(world).randomDescriptions;
return descriptions == null ? "" : descriptions.get(spell);
}
@Override
public void readFromNBT(NBTTagCompound nbt){
this.randomNames = new HashMap<Spell, String>();
this.randomDescriptions = new HashMap<Spell, String>();
NBTTagList tagList = nbt.getTagList("spellGlyphData", NBT.TAG_COMPOUND);
for(int i=0; i<tagList.tagCount(); i++){
NBTTagCompound tag = tagList.getCompoundTagAt(i);
randomNames.put(Spell.get(tag.getInteger("spell")), tag.getString("name"));
randomDescriptions.put(Spell.get(tag.getInteger("spell")), tag.getString("description"));
}
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound nbt){
NBTTagList tagList = new NBTTagList();
for(Spell spell : Spell.getSpells(Spell.allSpells)){
// Much like the enchantments tag for items, this stores a list of spell-id-to-name tag pairs
// The description is now also included; there's no point in making a second compound tag!
NBTTagCompound tag = new NBTTagCompound();
tag.setInteger("spell", spell.id());
tag.setString("name", this.randomNames.get(spell));
tag.setString("description", this.randomDescriptions.get(spell));
tagList.appendTag(tag);
}
nbt.setTag("spellGlyphData", tagList);
return nbt;
}
}
@@ -0,0 +1,581 @@
package electroblob.wizardry;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.enchantment.Imbuement;
import electroblob.wizardry.entity.EntityShield;
import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketPlayerSync;
import electroblob.wizardry.packet.PacketTransportation;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryAchievements;
import electroblob.wizardry.spell.None;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagInt;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
/** Capability-based replacement for the old ExtendedPlayer class from 1.7.10. This has been reworked to leave
* minimum external changes (for my own sanity, mainly!). Turns out the only major difference between an internal
* capability and an IEEP is a couple of redundant classes and a different way of registering it.
* <p>
* Forge seems to have separate classes to hold the Capability<...> instance ('key') and
* methods for getting the capability, but in my opinion there are already too many classes to deal with, so I'm not
* adding any more than are necessary, meaning those constants and values are kept here instead.
* @since Wizardry 1.2
* @author Electroblob */
// On the plus side, having to rethink this class allowed me to clean it up a lot.
public class WizardData implements INBTSerializable<NBTTagCompound> {
/** Static instance of what I like to refer to as the capability key. Private because, well, it's internal! */
// This annotation does some crazy Forge magic behind the scenes and assigns this field a value.
@CapabilityInject(WizardData.class)
private static final Capability<WizardData> WIZARD_DATA_CAPABILITY = null;
private final EntityPlayer player;
// This one is still necessary, because I can't override the equip animation for items that aren't from Wizardry.
private Map<Imbuement, Integer> imbuementDurations;
public boolean hasSpiritWolf;
public boolean hasSpiritHorse;
/** Whether this player is currently casting a continuous spell via commands. Not saved over world reload
* and reset on player death. */
private Spell currentlyCasting;
/** The time for which this player has been casting a continuous spell via commands. Increments by 1 each tick.
* Not saved over world reload and reset on player death. */
private int castingTick;
/** SpellModifiers object for the current continuous spell cast via commands. Not saved over world reload and
* reset on player death. */
private SpellModifiers spellModifiers;
/** Coordinates for the saved transportation stone circle location. Will be null if no location is saved. */
private BlockPos stoneCircleLocation;
/** Dimension id which the saved stone circle is in. */
private int stoneCircleDimension;
/** Time left until the player teleports under the effect of transportation */
private int tpCountdown;
/** Coordinates for the saved clairvoyance location. Will be null if no location is saved. */
private BlockPos clairvoyanceLocation;
/** Dimension id which the saved clairvoyance point is in. */
private int clairvoyanceDimension;
public EntityShield shield;
public WeakReference<ISummonedCreature> selectedMinion;
/** Set of this player's discovered spells. <b>Do not write to this list directly</b>, use
* {@link WizardData#discoverSpell(Spell)} instead. */
public Set<Spell> spellsDiscovered;
private Set<UUID> allies;
/** List of usernames of this player's allies. May not be accurate 100% of the time. This is here so that a player
* can view the usernames of their allies even when those allies are not online.
* <b> Do not use this for any other purpose than displaying the names! */
public Set<String> allyNames;
private Set<UUID> soulboundCreatures;
public WizardData(EntityPlayer player){
this.player = player;
this.imbuementDurations = new HashMap<Imbuement, Integer>();
this.spellsDiscovered = new HashSet<Spell>();
// All players can recognise magic missile. This is not done using discoverSpell because that seems to cause
// a crash on load occasionally (probably something to do with achievements being initalised)
this.spellsDiscovered.add(Spells.magic_missile);
this.hasSpiritWolf = false;
this.hasSpiritHorse = false;
this.currentlyCasting = Spells.none;
this.spellModifiers = new SpellModifiers();
this.castingTick = 0;
this.stoneCircleDimension = 0;
this.clairvoyanceDimension = 0;
this.setTpCountdown(0);
this.allies = new HashSet<UUID>();
this.allyNames = new HashSet<String>();
this.soulboundCreatures = new HashSet<UUID>();
}
public boolean hasSpellBeenDiscovered(Spell spell){
return spellsDiscovered.contains(spell) || spell instanceof None;
}
/**
* Adds the given spell to the list of discovered spells for this player. Automatically takes into account
* whether the spell has been discovered. Use this method rather than adding directly to the list because it
* handles achievements.
* @param spell The spell to be discovered
* @return True if the spell had not already been discovered; false otherwise.
*/
public boolean discoverSpell(Spell spell){
if(spellsDiscovered == null){
spellsDiscovered = new HashSet<Spell>();
}
// The 'none' spell cannot be discovered
if(spell instanceof None) return false;
// Tries to add the spell to the list of discovered spells, and returns false if it was already present
if(!spellsDiscovered.add(spell)) return false;
// If the spell had not already been discovered, achievements can be triggered and the method returns true
if(spellsDiscovered.containsAll(Spell.getSpells(Spell::isEnabled))){
this.player.addStat(WizardryAchievements.all_spells);
}
for(Element element : Element.values()){
if(element != Element.MAGIC && spellsDiscovered.containsAll(Spell.getSpells(new Spell.TierElementFilter(null, element)))){
this.player.addStat(WizardryAchievements.element_master);
}
}
return true;
}
/** Sets the player's saved transportation stone location and dimension. */
public void setStoneCircleLocation(BlockPos pos, int dimensionID){
this.stoneCircleLocation = pos;
this.stoneCircleDimension = dimensionID;
}
/** Returns the coordinates of the associated player's saved transportation stone circle. */
public BlockPos getStoneCircleLocation(){ return stoneCircleLocation; }
/** Returns the dimension ID of the associated player's saved transportation stone circle. */
public int getStoneCircleDimension(){ return stoneCircleDimension; }
public int getTpCountdown() { return tpCountdown; }
public void setTpCountdown(int tpCountdown) { this.tpCountdown = tpCountdown; }
/** Sets the player's saved clairvoyance location. */
public void setClairvoyancePoint(BlockPos pos, int dimensionID){
this.clairvoyanceLocation = pos;
this.clairvoyanceDimension = dimensionID;
}
/** Returns the coordinates for the saved clairvoyance location. Will be null if no location is saved. */
public BlockPos getClairvoyanceLocation(){ return clairvoyanceLocation; }
/** Returns the dimension ID for the saved clairvoyance location. Will be null if no location is saved. */
public int getClairvoyanceDimension(){ return clairvoyanceDimension; }
/** Overwrites the imbuement duration associated with the given imubement for this player, or creates it if there
* was none previously.
* @throws IllegalArgumentException if the given {@link Enchantment} is not an {@link Imbuement}. */
public void setImbuementDuration(Enchantment enchantment, int duration){
// It is best to throw an exception here, because otherwise the error would either go unnoticed (if non-imbuements
// were ignored) or cause a ClassCastException later (if non-imbuements were allowed to be added).
if(enchantment instanceof Imbuement){
this.imbuementDurations.put((Imbuement) enchantment, duration);
}else{
throw new IllegalArgumentException("Attempted to set an imbuement duration for something that isn't an Imbuement! (This exception has been thrown now to prevent a ClassCastException from occurring later.)");
}
}
/** Returns the imbuement duration associated with the given imbuement for this player, or 0 if it does not exist. */
public int getImbuementDuration(Enchantment enchantment){
// Need to check that i is not null, otherwise it throws an NPE when Java auto-unboxes it.
// What's nice here is that the map simply accepts objects as keys, so there's no need to cast or throw exceptions.
Integer i = this.imbuementDurations.get(enchantment);
// If i is null, returns 0; otherwise returns i, auto-unboxed to an int.
return i == null ? 0 : i;
}
/** Decrements the duration for each conjured item by 1, and removes from the map any that are 0 or less or that
* the player no longer has. Also deletes the item from the player's inventory if it runs out of time. */
private void updateImbuedItems(){
Set<Imbuement> activeImbuements = new HashSet<Imbuement>();
// For each item in the player's inventory
for(ItemStack stack : player.inventory.mainInventory){
if(stack != null && stack.isItemEnchanted()){
Map<Enchantment, Integer> enchantments = EnchantmentHelper.getEnchantments(stack);
Iterator<Entry<Enchantment, Integer>> iterator = enchantments.entrySet().iterator();
// For each of the item's enchantments
while(iterator.hasNext()){
Enchantment enchantment = iterator.next().getKey();
// Ignores the enchantment unless it is an imbuement
if(enchantment instanceof Imbuement){
int duration = this.getImbuementDuration(enchantment);
// If the imbuement is still active:
if(duration > 0){
// Decrements the timer
this.imbuementDurations.put((Imbuement)enchantment, duration-1);
// Adds this imbuement to the set of imbuements that need to be kept
activeImbuements.add((Imbuement)enchantment);
// Otherwise:
}else{
// Removes the enchantment from the enchantment map
iterator.remove();
// Applies the new enchantment map to the item
EnchantmentHelper.setEnchantments(enchantments, stack);
}
}
}
}
}
// Removes all imbuements from the map that are no longer active
this.imbuementDurations.keySet().retainAll(activeImbuements);
}
/** Adds the given player to the list of allies belonging to the associated player, or removes the player if
* they are already in the list of allies. Returns true if the player was added, false if they were removed. */
public boolean toggleAlly(EntityPlayer player){
if(this.isPlayerAlly(player)){
this.allies.remove(player.getUniqueID());
// The remove method uses .equals() rather than == so this will work fine.
this.allyNames.remove(player.getName());
return false;
}else{
this.allies.add(player.getUniqueID());
this.allyNames.add(player.getName());
return true;
}
}
/** Returns whether the given player is in this player's list of allies, or is on the same team as this player. */
public boolean isPlayerAlly(EntityPlayer player){
return this.allies.contains(player.getUniqueID()) || this.player.isOnSameTeam(player);
}
/** Adds the given entity to this player's list of soulbound creatures, and returns whether it succeeded. */
public boolean soulbind(EntityLivingBase target){
return this.soulboundCreatures.add(target.getUniqueID());
}
/** Returns whether the given entity has been soulbound to this player. */
public boolean isCreatureSoulbound(EntityPlayer target){
return this.soulboundCreatures.contains(target.getUniqueID());
}
/** Damages all creatures soulbound to this player by the given amount, and removes from the list any that no
* longer exist. */
public void damageAllSoulboundCreatures(float damage){
for(Iterator<UUID> iterator = this.soulboundCreatures.iterator(); iterator.hasNext();){
Entity entity = WizardryUtilities.getEntityByUUID(this.player.worldObj, iterator.next());
if(entity == null) iterator.remove();
if(entity instanceof EntityLivingBase){
// Retaliatory effect
if(entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(this.player, DamageType.MAGIC, true), damage)){
// Sound only plays if the damage succeeds
player.playSound(SoundEvents.ENTITY_WITHER_HURT, 1.0F, player.worldObj.rand.nextFloat() * 0.2F + 1.0F);
}
}
}
}
/** Starts casting the given spell with the given modifiers. */
public void startCastingContinuousSpell(Spell spell, SpellModifiers modifiers){
this.currentlyCasting = spell;
this.spellModifiers = modifiers;
if(!this.player.worldObj.isRemote){
PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(),
spell.id(), this.spellModifiers);
WizardryPacketHandler.net.sendToDimension(message, this.player.worldObj.provider.getDimension());
}
}
/** Stops casting the current spell. */
public void stopCastingContinuousSpell(){
this.currentlyCasting = Spells.none;
this.castingTick = 0;
this.spellModifiers.reset();
if(!this.player.worldObj.isRemote){
PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(),
Spells.none.id(), this.spellModifiers);
WizardryPacketHandler.net.sendToDimension(message, this.player.worldObj.provider.getDimension());
}
}
/** Returns whether this player is currently casting a continuous spell via commands. */
public boolean isCasting(){
return this.currentlyCasting != null && this.currentlyCasting != Spells.none;
}
/** Returns the continuous spell this player is currently casting via commands, or the 'none' spell if they aren't
* casting anything. */
public Spell currentlyCasting(){
return currentlyCasting;
}
/** Called from the event handler each time the associated player is updated. */
public void update(){
if(this.selectedMinion != null && this.selectedMinion.get() == null) this.selectedMinion = null;
// This new system removes a lot of repetitive event handler code and inflexible variables which had duplicate
// functions, just for different enchantments.
updateImbuedItems();
if(!player.worldObj.isRemote){
if(getTpCountdown() == 1){
player.setPositionAndUpdate(this.stoneCircleLocation.getX() + 0.5, this.stoneCircleLocation.getY(),
this.stoneCircleLocation.getZ() + 0.5);
player.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, 50, 0));
IMessage msg = new PacketTransportation.Message(player.getEntityId());
WizardryPacketHandler.net.sendToDimension(msg, player.worldObj.provider.getDimension());
}
if(getTpCountdown() > 0){
setTpCountdown(getTpCountdown() - 1);
}
}
if(this.currentlyCasting != null && this.currentlyCasting.isContinuous){
this.currentlyCasting.cast(player.worldObj, player, EnumHand.MAIN_HAND, castingTick++, this.spellModifiers);
}else{
this.castingTick = 0;
}
}
/**
* Returns the WizardData instance for the specified player.
*/
public static final WizardData get(EntityPlayer player){
return player.getCapability(WIZARD_DATA_CAPABILITY, null);
}
/** Called from the event handler each time the associated player entity is cloned, i.e. on respawn or when
* travelling to a different dimension. Used to copy over any variables that should persist over player death.
* This is the inverse of the old onPlayerDeath method, which reset the variables that shouldn't persist.
* @param data The old WizardData whose variables are to be copied over.
* @param respawn True if the player died and is respawning, false if they are just travelling between dimensions. */
public void copyFrom(WizardData data, boolean respawn){
// TODO: What happens with spirit wolf and spirit horse?
this.hasSpiritHorse = data.hasSpiritHorse;
this.hasSpiritWolf = data.hasSpiritWolf;
this.allies = data.allies;
this.allyNames = data.allyNames;
this.clairvoyanceDimension = data.clairvoyanceDimension;
this.clairvoyanceLocation = data.clairvoyanceLocation;
this.selectedMinion = data.selectedMinion;
// Curse of soulbinding is lifted when the caster dies, but not when they switch dimensions.
if(!respawn) this.soulboundCreatures = data.soulboundCreatures;
this.spellsDiscovered = data.spellsDiscovered;
this.stoneCircleDimension = data.stoneCircleDimension;
this.stoneCircleLocation = data.stoneCircleLocation;
// Imbuements are lost on death so their durations do not persist.
// Command spell casting is reset on death so the associated variables do not persist.
// tpCountdown is reset both when the player dies and when they switch dimensions.
}
/** Sends a packet to this player's client to synchronise necessary information. Only called server side. */
public void sync(){
if(this.player instanceof EntityPlayerMP){
int id = -1;
if(this.selectedMinion != null && this.selectedMinion.get() instanceof Entity) id = ((Entity)this.selectedMinion.get()).getEntityId();
IMessage msg = new PacketPlayerSync.Message(this.spellsDiscovered, id);
WizardryPacketHandler.net.sendTo(msg, (EntityPlayerMP)this.player);
}
}
@Override
public NBTTagCompound serializeNBT() {
NBTTagCompound properties = new NBTTagCompound();
// ...so Java 8 allows you to do stuff like this:
properties.setTag("imbuements", WizardryUtilities.mapToNBT(this.imbuementDurations,
imbuement -> new NBTTagInt(Enchantment.getEnchantmentID((Enchantment)imbuement)), NBTTagInt::new));
properties.setBoolean("hasSpiritWolf", this.hasSpiritWolf);
properties.setBoolean("hasSpiritHorse", this.hasSpiritHorse);
if(this.stoneCircleLocation != null) properties.setLong("stoneCircleLocation", this.stoneCircleLocation.toLong());
properties.setInteger("stoneCircleDimension", this.stoneCircleDimension);
properties.setInteger("tpCountdown", this.tpCountdown);
if(this.clairvoyanceLocation != null) properties.setLong("clairvoyanceLocation", this.clairvoyanceLocation.toLong());
properties.setInteger("clairvoyanceDimension", this.getClairvoyanceDimension());
// THIS is why I wrote the list/map <-> NBT methods. Look how neat this is!
properties.setTag("allies", WizardryUtilities.listToNBT(this.allies, WizardryUtilities::UUIDtoTagCompound));
properties.setTag("allyNames", WizardryUtilities.listToNBT(this.allyNames, NBTTagString::new));
properties.setTag("soulboundCreatures", WizardryUtilities.listToNBT(this.soulboundCreatures, WizardryUtilities::UUIDtoTagCompound));
// Might be worth converting this over to WizardryUtilities.listToNBT.
int[] spells = new int[this.spellsDiscovered.size()];
int i=0;
for(Spell spell : this.spellsDiscovered){
spells[i] = spell.id();
i++;
}
properties.setIntArray("discoveredSpells", spells);
return properties;
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
if(nbt != null){
this.imbuementDurations = WizardryUtilities.NBTToMap(nbt.getTagList("imbuements", NBT.TAG_COMPOUND),
(NBTTagInt tag) -> (Imbuement)Enchantment.getEnchantmentByID(tag.getInt()), NBTTagInt::getInt);
this.hasSpiritWolf = nbt.getBoolean("hasSpiritWolf");
this.hasSpiritHorse = nbt.getBoolean("hasSpiritHorse");
this.stoneCircleLocation = BlockPos.fromLong(nbt.getLong("stoneCircleLocation"));
this.stoneCircleDimension = nbt.getInteger("stoneCircleDimension");
this.tpCountdown = nbt.getInteger("tpCountdown");
this.clairvoyanceLocation = BlockPos.fromLong(nbt.getLong("clairvoyanceLocation"));
this.clairvoyanceDimension = nbt.getInteger("clairvoyanceDimension");
this.allies = new HashSet<UUID>(WizardryUtilities.NBTToList(nbt.getTagList("allies", NBT.TAG_COMPOUND),
WizardryUtilities::tagCompoundToUUID));
this.allyNames = new HashSet<String>(WizardryUtilities.NBTToList(nbt.getTagList("allyNames", NBT.TAG_STRING),
NBTTagString::getString));
this.soulboundCreatures = new HashSet<UUID>(WizardryUtilities.NBTToList(nbt.getTagList("soulboundCreatures", NBT.TAG_COMPOUND),
WizardryUtilities::tagCompoundToUUID));
this.spellsDiscovered = new HashSet<Spell>();
for(int id : nbt.getIntArray("discoveredSpells")){
spellsDiscovered.add(Spell.get(id));
}
}
}
/** This is a nested class for a few reasons: firstly, it makes sense because instances of this and WizardData go
* hand-in-hand; secondly, it's too short to be worth a separate file; and thirdly (and most importantly) it allows
* me to access WIZARD_DATA_CAPABILITY while keeping it private. */
public static class Provider implements ICapabilitySerializable<NBTTagCompound> {
private final WizardData data;
public Provider(EntityPlayer player){
data = new WizardData(player);
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
return capability == WIZARD_DATA_CAPABILITY;
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
if(capability == WIZARD_DATA_CAPABILITY){
return WIZARD_DATA_CAPABILITY.cast(data);
}
return null;
}
@Override
public NBTTagCompound serializeNBT() {
return data.serializeNBT();
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
data.deserializeNBT(nbt);
}
}
// Ended up deleting IWizardData because it was unnecessary. This is the comment that was at the start of it:
/* I'm not going to lie, I will never find the capabilities system even remotely intuitive so this is a bare-minimum
* approach just to get things working (four classes where one would have done?!) At one point I considered simply
* wrapping my old IEEP inside a single-field capability, but I eventually decided I would at least *try* to do it
* properly.
*
* "...without having to directly implement many interfaces." - Forge Docs. I still can't see what's wrong with
* implementing many interfaces; surely that's what Java interfaces are designed for?
*
* Other things I find annoying:
* - IStorage. It's completely redundant in the majority of cases, and I don't understand why we need yet another
* separate class.
* - Making an interface, only to implement it once and once only. This completely defeats the point of interfaces.
* - The EnumFacing parameter, which is again redundant for everything that isn't a tile entity. So much for a clean,
* neat system.
*
* What Forge has effectively done is conflated two different functions: attaching data to stuff and cross-mod
* integration/soft dependencies. I think this is bad design; it would have been better to keep the two features separate.
*
* Here's my current understanding of how the capability system works:
* - You make an interface which defines the things your capability can do (this class). I will call this the TEMPLATE.
* - You implement that interface with your default implementation (WizardData). This is the closest analog to your old
* IEEP implementation class. THIS CLASS STORES ALL THE VARIABLES, and hence has one instance for each instance of whatever
* it is attached to. I will call this the DATA.
* - The DATA class implements INBTSerializable (assuming you want it to be saved, which is nearly always the case)
* - Despite its name, Capability<T> does NOT represent a capability itself. Instead, it acts as a sort of identifier/key,
* the idea being that you can access a particular instance of your DATA given the key (which tells forge that you want a
* capability of type TEMPLATE) and the object you want the DATA for. This is what Entity.getCapability(...) does.
*
* To really understand what's going on though, you need to sift through Forge's verbose data structures and find where
* capabilities are actually hooked into vanilla:
* - Anything that implements ICapabilityProvider will have a private CapabilityDispatcher field. This holds other
* ICapabilityProviders. (I know. This inheritance pattern DOES NOT MAKE SENSE, because these could, in theory, be OTHER
* ENTITIES!)
* - This field is assigned a value through Forge's event factory, which, as we are all familiar with, calls all the
* methods marked with @SubscribeEvent. These methods add individual ICapabilityProviders to a Map stored in the event,
* which the event factory then wraps in a CapabilityDispatcher (which is itself an ICapabilityProvider) for the object
* that called it.
* - In your event handler, you return a custom ICapabilityProvider which is effectively bolted on to the player, and
* duplicates the ICapabilityProvider methods so you can hook into them and return an instance of your DATA class.
* - Where before there was a simple collection of IEEPs stored in the player, there is now a tree of ICapabilityProviders:
*
* - Entity/TileEntity/ItemStack
* - Vanilla ICapabilityProviders, mostly IItemHandlers, stored as fields.
* - CapabilityDispatcher, stored as a field.
* - Custom ICapabilityProviders
* - Custom CapabilityDispatchers
* - ...
*
* Most importantly, EACH PLAYER HOLDS THEIR OWN INSTANCE OF THIS TREE.
*
* When a capability is retrieved, the following process happens:
* 1. For the Entity/TileEntity/ItemStack instance, ICapabilityProvider.getCapability(...) is called.
* 2. The request propogates through the tree and finds the requested capability. */
}
@@ -0,0 +1,265 @@
package electroblob.wizardry;
import org.apache.logging.log4j.Logger;
import electroblob.wizardry.command.CommandCastSpell;
import electroblob.wizardry.command.CommandDiscoverSpell;
import electroblob.wizardry.command.CommandSetAlly;
import electroblob.wizardry.command.CommandViewAllies;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.WizardryAchievements;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryRegistry;
import electroblob.wizardry.registry.WizardryTabs;
import net.minecraft.item.Item;
import net.minecraft.nbt.NBTBase;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.AchievementPage;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.Capability.IStorage;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry.Type;
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, guiFactory = "electroblob." + Wizardry.MODID + ".WizardryGuiFactory")
public class Wizardry {
/** Wizardry's mod ID. */
public static final String MODID = "wizardry";
/** Wizardry's mod name, in readable form. */
public static final String NAME = "Electroblob's Wizardry";
/** The version number for this version of wizardry. The following system is used for version numbers:
* <p><center><b>[major Minecraft version].[major mod version].[minor mod version/patch]<p></center></b>
* The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same features as
* Wizardry 2.1, but they are for different versions of Minecraft and have separate minor versioning. 1.x.x
* represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft
* 1.11.x versions, and so on. */
public static final String VERSION = "2.1.0";
// IDEA: Improve the algorithm that finds a place to summon creatures to take walls into account.
// IDEA: Replace all uses of Math.cos and Math.sin with MathHelper versions
// IDEA: API feature that automatically injects custom wand upgrades into wizardry's loot tables
// IDEA: Support for the @e selector in the /cast command (the methods already exist, just plug them in)
// IDEA: Dispensers shooting spells from scrolls! Imagine the possibilities!
// == Rendering overhaul! ==
// IDEA: Make spirit animals fade away when dispelled
// IDEA: Use your newfound knowledge of OpenGL to render animated boxes around entities being buffed, similar to creeper charge
// IDEA: Redo RenderArc so it looks like lightning (it's literally a load of translucent boxes inside each other)
// IDEA: The arcane workbench could use a few particles
// IDEA: Add a box to the wizard armour model so that the robes bend when the wearer is sneaking
// IDEA: Flash particle (I think it exists in vanilla somewhere) on spell impact
// IDEA: Dust particles spray out from projectiles as they move
// IDEA: Colour fading for particles
// IDEA: Make lightning and other effects particles. There's no reason why you can't pass in a player argument and have the particles move with them!
/* Minor bugs that need fixing at some point:
* - Player skin hat layer shows through wizard hats
* - Wizard armour breaks rather than just running out of mana (I can't seem to replicate this bug, but I have had
* it happen to me before...)
* - Shift-clicking a stack of special upgrades when in the arcane workbench causes the whole stack to be
* transferred when it should be just one (this is a bug with vanilla as well - try putting a stack of bottles into
* a brewing stand). I have at least made it so only one gets used now, so it has no impact on the game.
* - When a spell is on cooldown, you can't break blocks when holding a wand. */
// FIXME: Wizardry enchantments appear on enchanted books in dungeon chests when they shouldn't.
// TODO: So somehow I have managed to overlook the fact that health is actually a float. What this means is that
// I can make the healing spells use damage multipliers - hurrah!
// TODO: Switch from IInventory to IItemHandler (Or don't. It's only useful for automation really.)
// TODO: Triggering of inbuilt Forge events in relevant places?
// TODO: Implement custom events
// TODO: Rearrange the config gui and file
// TODO: Have particles obey Minecraft's particle setting where appropriate
// (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java)
// NOTE: Add melee upgrades to loot tables when they are added.
/** Static instance of the {@link Settings} object for Wizardry. */
public static final Settings settings = new Settings();
/** Static instance of the {@link Logger} object for Wizardry. */
public static Logger logger;
//private static Pattern entityNamePattern;
// EventManager
WizardryWorldGenerator generator = new WizardryWorldGenerator();
// The instance of wizardry that Forge uses.
@Instance(Wizardry.MODID)
public static Wizardry instance;
// Location of the proxy code, used by Forge.
@SidedProxy(clientSide="electroblob.wizardry.client.ClientProxy", serverSide="electroblob.wizardry.CommonProxy")
public static CommonProxy proxy;
@EventHandler
public void preInit(FMLPreInitializationEvent event){
logger = event.getModLog();
// The array in question no longer exists, so I'm pretty sure this isn't necessary any more.
// expandPotionTypesArray();
settings.initConfig(event);
// Yes - by the looks of it, having an interface is completely unnecessary in this case.
CapabilityManager.INSTANCE.register(WizardData.class, new IStorage<WizardData>(){
// These methods are only called by Capability.writeNBT() or Capability.readNBT(), which in turn are
// NEVER CALLED. Unless I'm missing some reflective invocation, that means this entire class serves only
// to allow capabilities to be saved and loaded manually. What that would be useful for I don't know.
// (If an API forces most users to write redundant code for no reason, it's not user friendly, is it?)
// ... well, that's my rant for today!
@Override public NBTBase writeNBT(Capability<WizardData> capability, WizardData instance, EnumFacing side){ return null; }
@Override public void readNBT(Capability<WizardData> capability, WizardData instance, EnumFacing side, NBTBase nbt){}
}, WizardData.class);
WizardryRegistry.registerTileEntities();
WizardryRegistry.registerEntities(this);
// The check for the generateLoot setting is now done within this method.
WizardryRegistry.registerLoot();
// NOTE: Will need to be moved to init for 1.12, as will anything that needs to be after the registry events.
WizardryTabs.sort();
// Moved to preInit, because apparently it has to be here now.
proxy.registerRenderers();
}
@EventHandler
public void init(FMLInitializationEvent event){
settings.initConfigExtras();
proxy.registerKeyBindings();
// Event Handlers
GameRegistry.registerWorldGenerator(generator, 0);
MinecraftForge.EVENT_BUS.register(new WizardryKeyHandler());
MinecraftForge.EVENT_BUS.register(instance);
proxy.registerSpellHUD(); // This can't easily be converted to use the new @Mod.EventBusSubscriber system
NetworkRegistry.INSTANCE.registerGuiHandler(this, new WizardryGuiHandler());
WizardryPacketHandler.initPackets();
// Achievements
AchievementPage.registerAchievementPage(WizardryAchievements.WIZARDRY_ACHIEVEMENT_PAGE);
// Recipes
WizardryRegistry.registerRecipes();
proxy.initMixedFontRenderer();
}
@EventHandler
public void postInit(FMLPostInitializationEvent event){
// This needs to be here or it won't necessarily include all the mods' entities.
// TODO: Re-implement this when the Forge bug is fixed.
/* Doesn't seem to be doing anything...
String entityNames = "";
for(Object name : EntityList.classToStringMapping.values()){
if(name instanceof String){
entityNames = entityNames + name + '|';
}
}
// Cuts off the last '|'
entityNames = entityNames.substring(0, entityNames.length()-1);
entityNamePattern = Pattern.compile(entityNames);
*/
proxy.initialiseLayers();
}
@EventHandler
public void serverStarting(FMLServerStartingEvent event){
event.registerServerCommand(new CommandCastSpell());
event.registerServerCommand(new CommandSetAlly());
event.registerServerCommand(new CommandViewAllies());
event.registerServerCommand(new CommandDiscoverSpell());
}
@SubscribeEvent
public void onConfigChanged(net.minecraftforge.fml.client.event.ConfigChangedEvent.OnConfigChangedEvent event){
if(event.getModID().equals(Wizardry.MODID)){
settings.saveConfigChanges();
// All of the synchronised settings require a world restart anyway so this doesn't need syncing.
}
}
// 2.1 changed some item ids, so this fixes them for existing worlds
// NOTE: Needs changing to RegistryEvent.MissingMapping in 1.12, or just removing since nobody updates minecraft
// versions when using mods.
@EventHandler
public static void onMissingMappingEvent(FMLMissingMappingsEvent event){
// Just get, not getAll, since the mod id didn't change!
for(FMLMissingMappingsEvent.MissingMapping mapping : event.get()){
if(mapping.type == Type.ITEM && mapping.resourceLocation.getResourceDomain().equals(Wizardry.MODID)){
Item replacement = null;
switch(mapping.resourceLocation.getResourcePath()){
case "wand_basic": replacement = WizardryItems.magic_wand; break;
case "wand_basic_fire": replacement = WizardryItems.basic_fire_wand; break;
case "wand_basic_ice": replacement = WizardryItems.basic_ice_wand; break;
case "wand_basic_lightning": replacement = WizardryItems.basic_lightning_wand; break;
case "wand_basic_necromancy": replacement = WizardryItems.basic_necromancy_wand; break;
case "wand_basic_earth": replacement = WizardryItems.basic_earth_wand; break;
case "wand_basic_sorcery": replacement = WizardryItems.basic_sorcery_wand; break;
case "wand_basic_healing": replacement = WizardryItems.basic_healing_wand; break;
case "wand_apprentice": replacement = WizardryItems.apprentice_wand; break;
case "wand_apprentice_fire": replacement = WizardryItems.apprentice_fire_wand; break;
case "wand_apprentice_ice": replacement = WizardryItems.apprentice_ice_wand; break;
case "wand_apprentice_lightning": replacement = WizardryItems.apprentice_lightning_wand; break;
case "wand_apprentice_necromancy": replacement = WizardryItems.apprentice_necromancy_wand; break;
case "wand_apprentice_earth": replacement = WizardryItems.apprentice_earth_wand; break;
case "wand_apprentice_sorcery": replacement = WizardryItems.apprentice_sorcery_wand; break;
case "wand_apprentice_healing": replacement = WizardryItems.apprentice_healing_wand; break;
case "wand_advanced": replacement = WizardryItems.advanced_wand; break;
case "wand_advanced_fire": replacement = WizardryItems.advanced_fire_wand; break;
case "wand_advanced_ice": replacement = WizardryItems.advanced_ice_wand; break;
case "wand_advanced_lightning": replacement = WizardryItems.advanced_lightning_wand; break;
case "wand_advanced_necromancy": replacement = WizardryItems.advanced_necromancy_wand; break;
case "wand_advanced_earth": replacement = WizardryItems.advanced_earth_wand; break;
case "wand_advanced_sorcery": replacement = WizardryItems.advanced_sorcery_wand; break;
case "wand_advanced_healing": replacement = WizardryItems.advanced_healing_wand; break;
case "wand_master": replacement = WizardryItems.master_wand; break;
case "wand_master_fire": replacement = WizardryItems.master_fire_wand; break;
case "wand_master_ice": replacement = WizardryItems.master_ice_wand; break;
case "wand_master_lightning": replacement = WizardryItems.master_lightning_wand; break;
case "wand_master_necromancy": replacement = WizardryItems.master_necromancy_wand; break;
case "wand_master_earth": replacement = WizardryItems.master_earth_wand; break;
case "wand_master_sorcery": replacement = WizardryItems.master_sorcery_wand; break;
case "wand_master_healing": replacement = WizardryItems.master_healing_wand; break;
case "upgrade_storage": replacement = WizardryItems.storage_upgrade; break;
case "upgrade_siphon": replacement = WizardryItems.siphon_upgrade; break;
case "upgrade_condenser": replacement = WizardryItems.condenser_upgrade; break;
case "upgrade_range": replacement = WizardryItems.range_upgrade; break;
case "upgrade_duration": replacement = WizardryItems.duration_upgrade; break;
case "upgrade_cooldown": replacement = WizardryItems.cooldown_upgrade; break;
case "upgrade_blast": replacement = WizardryItems.blast_upgrade; break;
case "upgrade_attunement": replacement = WizardryItems.attunement_upgrade; break;
// If it didn't match any of the ones that changed, do nothing.
default: return;
}
// No need to log, Forge does that.
mapping.remap(replacement);
}
}
}
}
@@ -0,0 +1,938 @@
package electroblob.wizardry;
import java.util.List;
import java.util.Map;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.enchantment.Imbuement;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.entity.construct.EntityBubble;
import electroblob.wizardry.entity.construct.EntityDecay;
import electroblob.wizardry.entity.living.EntityEvilWizard;
import electroblob.wizardry.entity.living.EntityWizard;
import electroblob.wizardry.entity.living.ISpellCaster;
import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.item.IConjuredItem;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.item.ItemWizardArmour;
import electroblob.wizardry.potion.ICustomPotionParticles;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryAchievements;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryEnchantments;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Clairvoyance;
import electroblob.wizardry.spell.FreezingWeapon;
import electroblob.wizardry.spell.Intimidate;
import electroblob.wizardry.spell.MindControl;
import electroblob.wizardry.spell.ShadowWard;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.IElementalDamage;
import electroblob.wizardry.util.IndirectMinionDamage;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.MinionDamage;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryParticleType;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.passive.EntityPig;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.init.Blocks;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.ContainerPlayer;
import net.minecraft.inventory.ContainerWorkbench;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemBow;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSource;
import net.minecraft.util.EntityDamageSourceIndirect;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraft.world.storage.loot.LootEntry;
import net.minecraft.world.storage.loot.LootEntryTable;
import net.minecraft.world.storage.loot.LootPool;
import net.minecraft.world.storage.loot.RandomValueRange;
import net.minecraft.world.storage.loot.conditions.LootCondition;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.LootTableLoadEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.EntityStruckByLightningEvent;
import net.minecraftforge.event.entity.item.ItemTossEvent;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.event.entity.player.BonemealEvent;
import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerEvent.BreakSpeed;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
// TODO: This class is waaaay too long. We need to either:
// - Split it into several separate handlers, each with a logical area to deal with
// - Remove most of the stuff, and have individual spell, item, block, entity, etc. classes handle their own events
// - Keep all the methods, but delegate near-repeated behaviours to their individual spell/potion/whatever classes
/**
* Wizardry's main event handler class for common code.
* @author Electroblob
* @since Wizardry 1.0
*/
@Mod.EventBusSubscriber
public final class WizardryEventHandler {
@SubscribeEvent
// The type parameter here has to be Entity, not EntityPlayer, or the event won't get fired.
public static void onCapabilityLoad(AttachCapabilitiesEvent<Entity> event){
if(event.getObject() instanceof EntityPlayer)
event.addCapability(new ResourceLocation(Wizardry.MODID, "WizardData"), new WizardData.Provider((EntityPlayer)event.getObject()));
// This demonstrates why capabilities are badly structured: The following code compiles, but what it does is put
// a player into a CapabilityDispatcher, which is in turn stored in that very same player, which makes no sense
// at all!
//event.addCapability(new ResourceLocation(Wizardry.MODID, "WizardData"), event.getObject());
}
@SubscribeEvent
public static void onPlayerCloneEvent(PlayerEvent.Clone event){
WizardData newData = WizardData.get(event.getEntityPlayer());
WizardData oldData = WizardData.get(event.getOriginal());
newData.copyFrom(oldData, event.isWasDeath());
}
@SubscribeEvent
public static void onWorldLoadEvent(WorldEvent.Load event){
if(!event.getWorld().isRemote && event.getWorld().provider.getDimension() == 0){
// Called to initialise the spell glyph data when a world loads, if it isn't already.
// NOTE: Do we actually need this, or can we just let it initialise the first time it is needed? (see below)
SpellGlyphData.get(event.getWorld());
}
}
// IDEA: Config option allowing users to specify loot locations
private static final String[] LOOT_INJECTION_LOCATIONS = {
"minecraft:chests/simple_dungeon",
"minecraft:chests/abandoned_mineshaft",
"minecraft:chests/desert_pyramid",
"minecraft:chests/jungle_temple",
"minecraft:chests/stronghold_corridor",
"minecraft:chests/stronghold_crossing",
"minecraft:chests/stronghold_library",
"minecraft:chests/igloo_chest"
};
@SubscribeEvent
public static void onLootTableLoadEvent(LootTableLoadEvent event){
if(Wizardry.settings.generateLoot){
for(String location : LOOT_INJECTION_LOCATIONS){
if(event.getName().toString().matches(location)){
event.getTable().addPool(getAdditive("wizardry:chests/dungeon_additions"));
}
}
}
}
private static LootPool getAdditive(String entryName){
return new LootPool(new LootEntry[] { getAdditiveEntry(entryName, 1) }, new LootCondition[0], new RandomValueRange(1), new RandomValueRange(0, 1), Wizardry.MODID + "_additive_pool");
}
private static LootEntryTable getAdditiveEntry(String name, int weight){
return new LootEntryTable(new ResourceLocation(name), weight, 0, new LootCondition[0], Wizardry.MODID + "_additive_entry");
}
/* There is a subtle but important difference between LivingAttackEvent and LivingHurtEvent - LivingAttackEvent
* fires immediately when attackEntityFrom is called, whereas LivingHurtEvent only fires if the attack actually
* succeeded, i.e. if the entity in question takes damage (though the event is fired before that so you can cancel
* the damage). Things are processed in the following order:
* * LivingAttackEvent *
* - Invulnerability
* - Already-dead-ness
* - Fire resistance
* - Helmets vs. falling things
* - Hurt resistant time
* - Invulnerability (again)
* * LivingHurtEvent *
* - Armour
* - Potions
* - Health is finally changed
* Of course, there are no guarantees that other mods hooking into these two events will be called before or after
* yours, but you can have some degree of control by choosing which event to use.
* EDIT: Actually, there are. Firstly, you can set a priority in the @SubscribeEvent annotation which defines how
* early (higher priority) or late (lower priority) the method is called. Methods with the same priority are sorted
* alphabetically by mod id (so it's safe to assume wizardry would be fairly late on!). I wonder if there are any
* conventions for what sort of things take what priority...? */
@SubscribeEvent
public static void onLivingAttackEvent(LivingAttackEvent event){
// Rather than bother overriding entire attack methods in ISummonedCreature implementations, it's easier (and
// more robust) to use LivingAttackEvent to modify the damage source.
if(event.getSource().getEntity() instanceof ISummonedCreature){
EntityLivingBase summoner = ((ISummonedCreature)event.getSource().getEntity()).getCaster();
if(summoner != null){
event.setCanceled(true);
DamageSource newSource = event.getSource();
// Copies over the original DamageType if appropriate.
DamageType type = event.getSource() instanceof IElementalDamage ? ((IElementalDamage)event.getSource()).getType() : DamageType.MAGIC;
// Copies over the original isRetaliatory flag if appropriate.
boolean isRetaliatory = event.getSource() instanceof IElementalDamage && ((IElementalDamage)event.getSource()).isRetaliatory();
// All summoned creatures are classified as magic, so it makes sense to do it this way.
if(event.getSource() instanceof EntityDamageSourceIndirect){
newSource = new IndirectMinionDamage(event.getSource().damageType, event.getSource().getSourceOfDamage(), event.getSource().getEntity(), summoner, type, isRetaliatory);
}else if(event.getSource() instanceof EntityDamageSource){
// Name is copied over so it uses the appropriate vanilla death message
newSource = new MinionDamage(event.getSource().damageType, event.getSource().getEntity(), summoner, type, isRetaliatory);
}
// Copy over any relevant 'attributes' the original DamageSource might have had.
if(event.getSource().isExplosion()) newSource.setExplosion();
if(event.getSource().isFireDamage()) newSource.setFireDamage();
if(event.getSource().isProjectile()) newSource.setProjectile();
// For some reason Minecraft calculates knockback relative to DamageSource#getEntity. In vanilla this
// is unnoticeable, but it looks a bit weird with summoned creatures involved - so let's fix that!
if(WizardryUtilities.attackEntityWithoutKnockback(event.getEntity(), newSource, event.getAmount())){
WizardryUtilities.applyStandardKnockback(event.getSource().getEntity(), event.getEntityLiving());
((ISummonedCreature)event.getSource().getEntity()).onSuccessfulAttack(event.getEntityLiving());
}
return;
}
}
// Prevents any damage to allies from magic if friendly fire is enabled
if(!Wizardry.settings.friendlyFire && event.getSource() != null && event.getSource().getEntity() instanceof EntityPlayer
&& event.getEntity() instanceof EntityPlayer && event.getSource() instanceof IElementalDamage){
if(WizardryUtilities.isPlayerAlly((EntityPlayer)event.getSource().getEntity(), (EntityPlayer)event.getEntity())){
event.setCanceled(true);
// I think this ought to be here, since if the event is cancelled nothing else needs to happen.
return;
}
}
if(event.getSource() instanceof IElementalDamage){
if(MagicDamage.isEntityImmune(((IElementalDamage)event.getSource()).getType(), event.getEntity())){
event.setCanceled(true);
// I would have liked to have done the 'resist' chat message here, but I overlooked the fact that I
// would need an instance of the spell to get its display name!
return;
}
// One convenient side effect of the new damage type system is that I can get rid of all the places where
// creepers are charged and just put them here under shock damage - this is precisely the sort of
// repetitive code I was trying to get rid of, since errors can (and did!) occur.
if(event.getEntityLiving() instanceof EntityCreeper && !((EntityCreeper)event.getEntityLiving()).getPowered()
&& ((IElementalDamage)event.getSource()).getType() == DamageType.SHOCK){
// Charges creepers when they are hit by shock damage
WizardryUtilities.chargeCreeper((EntityCreeper)event.getEntityLiving());
// Gives the player that caused the shock damage the 'It's Gonna Blow' achievement
if(event.getSource().getEntity() instanceof EntityPlayer){
((EntityPlayer)event.getSource().getEntity()).addStat(WizardryAchievements.charge_creeper);
}
}
}
// Bursts bubble when the creature inside takes damage
if(event.getEntityLiving().getRidingEntity() instanceof EntityBubble &&
!((EntityBubble)event.getEntityLiving().getRidingEntity()).isDarkOrb){
event.getEntityLiving().getRidingEntity().playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f);
event.getEntityLiving().getRidingEntity().setDead();
}
// Prevents all unblockable damage while transience is active
if(event.getEntityLiving().isPotionActive(WizardryPotions.transience) && event.getSource() != null && !event.getSource().isUnblockable()){
event.setCanceled(true);
// Again, I think this ought to be here, since if the event is cancelled nothing else needs to happen.
return;
}
if(event.getSource() != null && event.getSource().getEntity() instanceof EntityLivingBase){
// Cancels the mind trick effect if the creature takes damage
// This has been moved to within the (event.getSource().getEntity() instanceof EntityLivingBase) check so it doesn't
// crash the game with a ConcurrentModificationException. If you think about it, mind trick only ought to be
// cancelled if something attacks the entity since potions, drowning, cacti etc. don't affect the targeting.
if(event.getEntityLiving().isPotionActive(WizardryPotions.mind_trick)){
event.getEntityLiving().removePotionEffect(WizardryPotions.mind_trick);
}
// 'Revenge' effects
EntityLivingBase attacker = (EntityLivingBase)event.getSource().getEntity();
World world = event.getEntityLiving().worldObj;
if(event.getEntityLiving().isPotionActive(WizardryPotions.fireskin) && !event.getSource().isProjectile()){
if(!MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving())) attacker.setFire(5);
}
if(event.getEntityLiving().isPotionActive(WizardryPotions.ice_shroud) && !event.getSource().isProjectile()){
if(!MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving()))
attacker.addPotionEffect(new PotionEffect(WizardryPotions.frost, 100, 0));
}
if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura) && !event.getSource().isProjectile()){
if(!world.isRemote){
EntityArc arc = new EntityArc(world);
arc.setEndpointCoords(event.getEntityLiving().posX, event.getEntityLiving().posY + 1, event.getEntityLiving().posZ,
attacker.posX, attacker.posY + attacker.height/2, attacker.posZ);
world.spawnEntityInWorld(arc);
}else{
for(int i=0;i<8;i++){
Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, attacker.posX + world.rand.nextFloat() - 0.5, attacker.getEntityBoundingBox().minY + attacker.height/2 + world.rand.nextFloat()*2 - 1, attacker.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3);
world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, attacker.posX + world.rand.nextFloat() - 0.5, attacker.getEntityBoundingBox().minY + attacker.height/2 + world.rand.nextFloat()*2 - 1, attacker.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0);
}
}
attacker.attackEntityFrom(MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), DamageType.SHOCK, true), 4.0f);
attacker.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F);
}
// Shadow ward
if(event.getEntityLiving() instanceof EntityPlayer){
ItemStack wand = event.getEntityLiving().getActiveItemStack();
if(wand != null && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand
&& WandHelper.getCurrentSpell(wand) instanceof ShadowWard && !event.getSource().isUnblockable()){
event.setCanceled(true);
// This DamageSource.magic and not event.getSource() because the latter would cause an infinite loop.
event.getEntityLiving().attackEntityFrom(DamageSource.magic, event.getAmount()/2);
attacker.attackEntityFrom(MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), DamageType.MAGIC, true), event.getAmount()/2);
}
}
// Transience
if(attacker.isPotionActive(WizardryPotions.transience)){
event.setCanceled(true);
}
}
}
@SubscribeEvent
public static void onLivingHurtEvent(LivingHurtEvent event){
// Curse of soulbinding
if(!event.getEntity().worldObj.isRemote && event.getEntityLiving() instanceof EntityPlayer && !event.getSource().isUnblockable()){
WizardData properties = WizardData.get((EntityPlayer)event.getEntityLiving());
if(properties != null){
properties.damageAllSoulboundCreatures(event.getAmount());
}
}
// Flaming and freezing swords
if(event.getSource().getEntity() instanceof EntityLivingBase){
EntityLivingBase attacker = (EntityLivingBase)event.getSource().getEntity();
// Players can only ever attack with their main hand, so this is the right method to use here.
if(attacker.getHeldItemMainhand() != null && attacker.getHeldItemMainhand().getItem() instanceof ItemSword){
int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon, attacker.getHeldItemMainhand());
if(level > 0 && !MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving()))
event.getEntityLiving().setFire(level*4);
level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.freezing_weapon, attacker.getHeldItemMainhand());
// Frost lasts for longer because it doesn't do any actual damage
if(level > 0 && !MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving()))
event.getEntityLiving().addPotionEffect(new PotionEffect(WizardryPotions.frost, level*200, 0));
}
}
// Freezing bow
if(event.getSource().getSourceOfDamage() instanceof EntityArrow && event.getSource().getSourceOfDamage().getEntityData() != null){
int level = event.getSource().getSourceOfDamage().getEntityData().getInteger(FreezingWeapon.FREEZING_ARROW_NBT_KEY);
if(level > 0 && !MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving()))
event.getEntityLiving().addPotionEffect(new PotionEffect(WizardryPotions.frost, level*150, 0));
}
// Damage scaling
if(event.getSource() != null && event.getSource() instanceof IElementalDamage){
if(event.getSource().getEntity() instanceof EntityPlayer){
event.setAmount((float)(event.getAmount() * Wizardry.settings.playerDamageScale));
}else{
event.setAmount((float)(event.getAmount() * Wizardry.settings.npcDamageScale));
}
}
}
@SubscribeEvent
public static void onBlockPlaceEvent(BlockEvent.PlaceEvent event){
if(event.getPlayer().isPotionActive(WizardryPotions.transience)){
event.setCanceled(true);
return;
}
// Spectral blocks cannot be built on
if(event.getPlacedAgainst() == WizardryBlocks.spectral_block){
event.setCanceled(true);
return;
}
}
@SubscribeEvent
public static void onBlockBreakEvent(BlockEvent.BreakEvent event){
if(event.getPlayer().isPotionActive(WizardryPotions.transience)){
event.setCanceled(true);
return;
}
// Makes wizards angry if a player breaks a block in their tower
if(!(event.getPlayer() instanceof FakePlayer)){
List<EntityWizard> wizards = WizardryUtilities.getEntitiesWithinRadius(64, event.getPos().getX(),
event.getPos().getY(), event.getPos().getZ(), event.getWorld(), EntityWizard.class);
if(!wizards.isEmpty()){
for(EntityWizard wizard : wizards){
if(wizard.isBlockPartOfTower(event.getPos())){
wizard.setRevengeTarget(event.getPlayer());
event.getPlayer().addStat(WizardryAchievements.anger_wizard);
}
}
}
}
}
@SubscribeEvent
public static void onEntityStruckByLightningEvent(EntityStruckByLightningEvent event){
if(event.getLightning().getEntityData() != null && event.getLightning().getEntityData().hasKey("summoningPlayer")){
EntityPlayer player = (EntityPlayer)WizardryUtilities.getEntityByUUID(event.getLightning().worldObj, event.getLightning().getEntityData().getUniqueId("summoningPlayer"));
if(event.getEntity() instanceof EntityCreeper){
player.addStat(WizardryAchievements.charge_creeper);
}
if(event.getEntity() instanceof EntityPig){
player.addStat(WizardryAchievements.frankenstein);
}
}
}
@SubscribeEvent
public static void onLivingUpdateEvent(LivingUpdateEvent event){
// TODO: Move the player stuff to a PlayerTickEvent and separate methods out for clarity
if(event.getEntityLiving() instanceof EntityPlayer){
EntityPlayer entityplayer = (EntityPlayer)event.getEntityLiving();
if(WizardData.get(entityplayer) != null){
WizardData.get(entityplayer).update();
}
if(entityplayer.openContainer instanceof ContainerWorkbench){
craftingTableTick(entityplayer);
}
if(entityplayer.openContainer instanceof ContainerPlayer){
// Unfortunately I have no choice but to call this method every tick when the player isn't using another
// inventory, since the only thing tracking whether the player is looking at their inventory is the GUI
// itself, which is client-side only.
playerInventoryTick(entityplayer);
}
testForArmourSet:{
for(ItemStack stack : entityplayer.getArmorInventoryList()){
if(stack == null || !(stack.getItem() instanceof ItemWizardArmour)){
break testForArmourSet;
}
}
entityplayer.addStat(WizardryAchievements.armour_set);
}
}
if(event.getEntityLiving().worldObj.isRemote){
// Behold the power of interfaces! TODO: Backport.
for(PotionEffect effect : event.getEntityLiving().getActivePotionEffects()){
if(effect.getPotion() instanceof ICustomPotionParticles && effect.doesShowParticles()){
double x = event.getEntityLiving().posX + (event.getEntityLiving().worldObj.rand.nextDouble() - 0.5)*event.getEntityLiving().width;
double y = event.getEntityLiving().getEntityBoundingBox().minY + event.getEntityLiving().worldObj.rand.nextDouble()*event.getEntityLiving().height;
double z = event.getEntityLiving().posZ + (event.getEntityLiving().worldObj.rand.nextDouble() - 0.5)*event.getEntityLiving().width;
((ICustomPotionParticles)effect.getPotion()).spawnCustomParticle(event.getEntityLiving().worldObj, x, y, z);
}
}
// Client-side continuous spell casting for NPCs
if(event.getEntity() instanceof ISpellCaster && event.getEntity() instanceof EntityLiving){
Spell spell = ((ISpellCaster)event.getEntity()).getContinuousSpell();
if(spell != null && spell != Spells.none){
spell.cast(event.getEntity().worldObj, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, 0,
// TODO: This implementation of modifiers relies on them being accessible client-side.
((EntityLiving)event.getEntity()).getAttackTarget(), ((ISpellCaster)event.getEntity()).getModifiers());
}
}
}else{
if(event.getEntityLiving().isPotionActive(WizardryPotions.decay) && event.getEntityLiving().onGround && event.getEntityLiving().ticksExisted % Constants.DECAY_SPREAD_INTERVAL == 0){
List<Entity> list = event.getEntityLiving().worldObj.getEntitiesWithinAABBExcludingEntity(event.getEntityLiving(), event.getEntityLiving().getEntityBoundingBox());
boolean flag = true;
for(Object object : list){
if(object instanceof EntityDecay) flag = false;
}
if(flag){
// The victim spreading the decay is the 'caster' here, so that it can actually wear off, otherwise it just gets infected with its own decay and the effect lasts forever.
event.getEntityLiving().worldObj.spawnEntityInWorld(new EntityDecay(event.getEntityLiving().worldObj, event.getEntityLiving().posX, event.getEntityLiving().posY, event.getEntityLiving().posZ, event.getEntityLiving()));
}
}
}
// Mind Control
// This was added because something got changed in the AI classes which means LivingSetAttackTargetEvent doesn't
// get fired when I want it to... so I'm firing it myself.
if(event.getEntityLiving().isPotionActive(WizardryPotions.mind_control) && event.getEntityLiving() instanceof EntityLiving
&& ((EntityLiving)event.getEntityLiving()).getAttackTarget() != null
&& !((EntityLiving)event.getEntityLiving()).getAttackTarget().isEntityAlive())
((EntityLiving)event.getEntityLiving()).setAttackTarget(null); // Causes the event to be fired
/* Old AI no longer exists!
// Mind trick
if(event.getEntityLiving().isPotionActive(Wizardry.mindTrick) && event.getEntityLiving() instanceof EntityLiving){
// Old AI (this can't be done in onLivingSetAttackTargetEvent because that only fires for the new AI).
if(event.getEntityLiving() instanceof EntityCreature) ((EntityCreature)event.getEntityLiving()).setTarget(null);
}
// Mind control - old AI (this can't be done in onLivingSetAttackTargetEvent because that only fires for the new AI).
mindcontrol:
if(event.getEntityLiving().isPotionActive(Wizardry.mindControl) && event.getEntityLiving() instanceof EntityLiving){
NBTTagCompound entityNBT = event.getEntityLiving().getEntityData();
if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){
Entity caster = WizardryUtilities.getEntityByUUID(event.getEntity().worldObj, UUID.fromString(entityNBT.getString(MindControl.NBT_KEY)));
if(caster instanceof EntityLivingBase){
if(MindControl.findMindControlTarget((EntityLiving)event.getEntityLiving(), (EntityLivingBase)caster, event.getEntity().worldObj)){
// If it worked, skip setting the target to null.
break mindcontrol;
}
}
}
// If the caster couldn't be found or no valid target was found, this just acts like mind trick.
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
}
*/
// Intimidate
if(event.getEntityLiving().isPotionActive(WizardryPotions.fear) && event.getEntityLiving() instanceof EntityCreature){
NBTTagCompound entityNBT = event.getEntityLiving().getEntityData();
EntityCreature creature = (EntityCreature)event.getEntityLiving();
if(entityNBT != null && entityNBT.hasKey(Intimidate.NBT_KEY)){
Entity caster = WizardryUtilities.getEntityByUUID(creature.worldObj, entityNBT.getUniqueId(Intimidate.NBT_KEY));
if(caster instanceof EntityLivingBase){
Intimidate.runAway(creature, (EntityLivingBase)caster);
}
}
}
}
@SubscribeEvent
public static void onBreakSpeedEvent(BreakSpeed event){
if(event.getEntityPlayer().isPotionActive(WizardryPotions.frost)){
// Amplifier + 1 because it starts at 0
event.setNewSpeed(event.getOriginalSpeed() * (1 - Constants.FROST_FATIGUE_PER_LEVEL*(event.getEntityPlayer().getActivePotionEffect(WizardryPotions.frost).getAmplifier() + 1)));
}
}
private static void playerInventoryTick(EntityPlayer player) {
// Charges wand using mana flask. It is here rather than in the crafting handler so the result displays
// the proper damage before it is actually crafted.
boolean flag = false;
ItemStack wand = null;
ItemStack armour = null;
IInventory craftMatrix = ((ContainerPlayer)player.openContainer).craftMatrix;
ItemStack outputItem = ((ContainerPlayer)player.openContainer).craftResult.getStackInSlot(0);
for(int i = 0; i < craftMatrix.getSizeInventory(); i++){
if(craftMatrix.getStackInSlot(i) != null){
ItemStack itemstack = craftMatrix.getStackInSlot(i);
if(itemstack.getItem() == WizardryItems.mana_flask){
flag = true;
}
if(itemstack.getItem() instanceof ItemWand){
wand = itemstack;
}
if(itemstack.getItem() instanceof ItemWizardArmour){
armour = itemstack;
}
}
}
if(outputItem != null && outputItem.getItem() instanceof ItemWand && flag && wand != null){
outputItem.setTagCompound((wand.getTagCompound()));
if(wand.getItemDamage()-Constants.MANA_PER_FLASK < 0){
outputItem.setItemDamage(0);
}else{
outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK);
}
}
if(outputItem != null && outputItem.getItem() instanceof ItemWizardArmour && flag && armour != null){
outputItem.setTagCompound((armour.getTagCompound()));
if(armour.getItemDamage()-Constants.MANA_PER_FLASK < 0){
outputItem.setItemDamage(0);
}else{
outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK);
}
}
}
private static void craftingTableTick(EntityPlayer player) {
// Charges wand using mana flask. It is here rather than in the crafting handler so the result displays
// the proper damage before it is actually crafted.
boolean flag = false;
ItemStack wand = null;
ItemStack armour = null;
IInventory craftMatrix = ((ContainerWorkbench)player.openContainer).craftMatrix;
ItemStack outputItem = ((ContainerWorkbench)player.openContainer).craftResult.getStackInSlot(0);
for (int i = 0; i < craftMatrix.getSizeInventory(); i++){
if(craftMatrix.getStackInSlot(i) != null){
ItemStack itemstack = craftMatrix.getStackInSlot(i);
if(itemstack.getItem() == WizardryItems.mana_flask){
flag = true;
}
if(itemstack.getItem() instanceof ItemWand){
wand = itemstack;
}
if(itemstack.getItem() instanceof ItemWizardArmour){
armour = itemstack;
}
}
}
if(outputItem != null && outputItem.getItem() instanceof ItemWand && flag && wand != null){
outputItem.setTagCompound((wand.getTagCompound()));
if(wand.getItemDamage()-Constants.MANA_PER_FLASK < 0){
outputItem.setItemDamage(0);
}else{
outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK);
}
}
if(outputItem != null && outputItem.getItem() instanceof ItemWizardArmour && flag && armour != null){
outputItem.setTagCompound((armour.getTagCompound()));
if(armour.getItemDamage()-Constants.MANA_PER_FLASK < 0){
outputItem.setItemDamage(0);
}else{
outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK);
}
}
}
@SubscribeEvent
public static void onLivingDeathEvent(LivingDeathEvent event){
if(event.getSource().getEntity() instanceof EntityPlayer){
EntityPlayer player = (EntityPlayer)event.getSource().getEntity();
for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){
if(stack != null && stack.getItem() instanceof ItemWand && stack.isItemDamaged() && WandHelper.getUpgradeLevel(stack, WizardryItems.siphon_upgrade) > 0){
int damage = stack.getItemDamage() - Constants.SIPHON_MANA_PER_LEVEL*WandHelper.getUpgradeLevel(stack, WizardryItems.siphon_upgrade) - player.worldObj.rand.nextInt(Constants.SIPHON_MANA_PER_LEVEL);
if(damage < 0) damage = 0;
stack.setItemDamage(damage);
break;
}
}
if(event.getEntityLiving() == player && event.getSource() instanceof IElementalDamage){
player.addStat(WizardryAchievements.self_destruct);
}
}
}
@SubscribeEvent
public static void onPlayerLoggedInEvent(PlayerLoggedInEvent event){
// When a player logs in, they are sent the glyph data and the server's settings.
if(event.player instanceof EntityPlayerMP){
SpellGlyphData.get(event.player.worldObj).sync((EntityPlayerMP)event.player);
Wizardry.settings.sync((EntityPlayerMP)event.player);
}
}
@SubscribeEvent
public static void onEntityJoinWorld(EntityJoinWorldEvent event){
if(!event.getEntity().worldObj.isRemote && event.getEntity() instanceof EntityPlayerMP){
// Synchronises wizard data after loading.
WizardData data = WizardData.get((EntityPlayer)event.getEntity());
if(data != null) data.sync();
}
// Rather long-winded (but necessary) way of getting an arrow just after it has been fired, checking if the bow
// that fired it has the imbuement enchantment, and applying extra damage accordingly.
if(!event.getEntity().worldObj.isRemote && event.getEntity() instanceof EntityArrow){
EntityArrow arrow = (EntityArrow)event.getEntity();
magicBow:
if(arrow.shootingEntity instanceof EntityLivingBase){
EntityLivingBase archer = (EntityLivingBase)arrow.shootingEntity;
ItemStack bow = archer.getHeldItemMainhand();
if(bow == null || !(bow.getItem() instanceof ItemBow)){
bow = archer.getHeldItemOffhand();
// Break used because return would skip the entire method, bypassing anything that might be added
// further down.
if(bow == null || !(bow.getItem() instanceof ItemBow)) break magicBow;
}
// Taken directly from ItemBow, so it works exactly the same as the power enchantment.
int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.magic_bow, bow);
if(level > 0){
arrow.setDamage(arrow.getDamage() + (double)level * 0.5D + 0.5D);
}
if(EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon, bow) > 0){
// Again, this is exactly what happens in ItemBow (flame is flame; level does nothing).
arrow.setFire(100);
}
level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.freezing_weapon, bow);
if(level > 0){
if(arrow.getEntityData() != null){
arrow.getEntityData().setInteger(FreezingWeapon.FREEZING_ARROW_NBT_KEY, level);
}
}
}
}
}
@SubscribeEvent
public static void onLivingDropsEvent(LivingDropsEvent event){
// TODO: Really, this should be in a loot table (mob_additions), however I can't seem to find a way of
// automatically adding it to all subclasses of IMob.
// Evil wizards drop spell books themselves
if(event.getEntityLiving() instanceof IMob && !(event.getEntityLiving() instanceof EntityEvilWizard)
// TODO: Backport when you backport the new summoned creature system.
&& !(event.getEntityLiving() instanceof ISummonedCreature) && event.getSource().getEntity() instanceof EntityPlayer
&& Wizardry.settings.spellBookDropChance > 0){
// This does exactly what the entity drop method does, but with a different random number so that the
// spell book doesn't always drop with other rare drops.
int rareDropNumber = event.getEntity().worldObj.rand.nextInt(200) - event.getLootingLevel();
if(rareDropNumber < Wizardry.settings.spellBookDropChance){
// Drops a spell book
int id = WizardryUtilities.getStandardWeightedRandomSpellId(event.getEntity().worldObj.rand);
event.getDrops().add(new EntityItem(event.getEntityLiving().worldObj, event.getEntityLiving().posX, event.getEntityLiving().posY, event.getEntityLiving().posZ,
new ItemStack(WizardryItems.spell_book, 1, id)));
}
}
for(EntityItem item : event.getDrops()){
// Destroys conjured items if their caster dies.
if(item.getEntityItem().getItem() instanceof IConjuredItem){
item.setDead();
}
// Instantly disenchants an imbued weapon if it is dropped when the player dies.
if(item.getEntityItem().isItemEnchanted()){
// No need to check what enchantments the item has, since remove() does nothing if the element does not exist.
Map<Enchantment, Integer> enchantments = EnchantmentHelper.getEnchantments(item.getEntityItem());
// Removes the magic weapon enchantments from the enchantment map
// An excellent demonstration of the usefulness of both interfaces and Java 8.
enchantments.entrySet().removeIf(entry -> entry.getKey() instanceof Imbuement);
// Applies the new enchantment map to the item
EnchantmentHelper.setEnchantments(enchantments, item.getEntityItem());
}
}
}
@SubscribeEvent
public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){
// Mind trick
// If the target is null already, no need to set it to null, or infinite loops will occur.
if((event.getEntityLiving().isPotionActive(WizardryPotions.mind_trick) || event.getEntityLiving().isPotionActive(WizardryPotions.fear)) && event.getEntityLiving() instanceof EntityLiving && event.getTarget() != null){
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
}
// Mind control
mindcontrol:
if(event.getEntityLiving().isPotionActive(WizardryPotions.mind_control) && event.getEntityLiving() instanceof EntityLiving){
NBTTagCompound entityNBT = event.getEntityLiving().getEntityData();
if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY + "Most")){
Entity caster = WizardryUtilities.getEntityByUUID(event.getEntity().worldObj, entityNBT.getUniqueId(MindControl.NBT_KEY));
// If the target that the event tried to set is already a valid mind control target, nothing happens.
if(event.getTarget() != null && WizardryUtilities.isValidTarget(caster, event.getTarget())) break mindcontrol;
if(caster instanceof EntityLivingBase){
if(MindControl.findMindControlTarget((EntityLiving)event.getEntityLiving(), (EntityLivingBase)caster, event.getEntity().worldObj)){
// If it worked, skip setting the target to null.
break mindcontrol;
}
}
}
// If the caster couldn't be found or no valid target was found, this just acts like mind trick.
// If the target is null already, no need to set it to null, or infinite loops will occur.
if(event.getTarget() != null) ((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
}
}
@SubscribeEvent
public static void onItemPickupEvent(EntityItemPickupEvent event){
if(event.getItem().getEntityItem().getItem() == WizardryItems.magic_crystal){
event.getEntityPlayer().addStat(WizardryAchievements.crystal, 1);
}
}
@SubscribeEvent
public static void onItemTossEvent(ItemTossEvent event){
// Prevents conjured items being thrown by dragging and dropping outside the inventory.
if(event.getEntityItem().getEntityItem().getItem() instanceof IConjuredItem){
event.setCanceled(true);
event.getPlayer().inventory.addItemStackToInventory(event.getEntityItem().getEntityItem());
}
// Instantly disenchants an imbued weapon if it is thrown on the ground.
if(event.getEntityItem().getEntityItem().isItemEnchanted()){
// No need to check what enchantments the item has, since remove() does nothing if the element does not exist.
Map<Enchantment, Integer> enchantments = EnchantmentHelper.getEnchantments(event.getEntityItem().getEntityItem());
// Removes the magic weapon enchantments from the enchantment map
enchantments.entrySet().removeIf(entry -> entry.getKey() instanceof Imbuement);
// Applies the new enchantment map to the item
EnchantmentHelper.setEnchantments(enchantments, event.getEntityItem().getEntityItem());
}
}
@SubscribeEvent
public static void onRightClickBlockEvent(PlayerInteractEvent.RightClickBlock event){
if(event.getEntityPlayer().isSneaking()){
// The event now has an ItemStack, which greatly simplifies hand-related stuff.
ItemStack wand = event.getItemStack();
if(wand != null && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Clairvoyance){
WizardData properties = WizardData.get(event.getEntityPlayer());
if(properties != null){
// THIS is why BlockPos is a thing - in 1.7.10 this requires a clumsy switch statement.
BlockPos pos = event.getPos().offset(event.getFace());
properties.setClairvoyancePoint(pos, event.getWorld().provider.getDimension());
if(!event.getWorld().isRemote){
event.getEntityPlayer().addChatMessage(new TextComponentTranslation("spell.clairvoyance.confirm", Spells.clairvoyance.getNameForTranslationFormatted()));
}
event.setCanceled(true);
}
}
}
}
@SubscribeEvent
public static void onBonemealEvent(BonemealEvent event){
// Grows crystal flowers when bonemeal is used on grass
if(event.getBlock().getBlock() == Blocks.GRASS){
BlockPos pos = event.getPos().add(event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8),
event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4),
event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8));
if (event.getWorld().isAirBlock(new BlockPos(pos)) && (!event.getWorld().provider.getHasNoSky() || pos.getY() < 127) && WizardryBlocks.crystal_flower.canPlaceBlockAt(event.getWorld(), pos))
{
event.getWorld().setBlockState(pos, WizardryBlocks.crystal_flower.getDefaultState(), 2);
}
}
}
}
@@ -0,0 +1,36 @@
package electroblob.wizardry;
import java.util.Set;
import electroblob.wizardry.client.GuiConfigWizardry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.IModGuiFactory;
public class WizardryGuiFactory implements IModGuiFactory {
@Override
public void initialize(Minecraft minecraftInstance)
{
}
@Override
public Class<? extends GuiScreen> mainConfigGuiClass()
{
return GuiConfigWizardry.class;
}
@Override
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories()
{
return null;
}
@SuppressWarnings("deprecation") // It's a bit of Forge that hasn't been tidied up, but we have to implement it.
@Override
public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element)
{
return null;
}
}
@@ -0,0 +1,66 @@
package electroblob.wizardry;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.item.ItemWizardHandbook;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.tileentity.ContainerPortableWorkbench;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.IGuiHandler;
public class WizardryGuiHandler implements IGuiHandler {
/** Incrementable index for the gui ID */
private static int nextGuiId = 0;
public static final int SPELL_BOOK = nextGuiId++;
public static final int ARCANE_WORKBENCH = nextGuiId++;
public static final int WIZARD_HANDBOOK = nextGuiId++;
public static final int PORTABLE_CRAFTING = nextGuiId++;
@Override
public Object getServerGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
if(id == ARCANE_WORKBENCH){
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
if(tileEntity instanceof TileEntityArcaneWorkbench){
return new ContainerArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench) tileEntity);
}
}
else if(id == PORTABLE_CRAFTING){
return new ContainerPortableWorkbench(player.inventory, world, new BlockPos(x, y, z));
}
return null;
}
@Override
public Object getClientGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
if(id == ARCANE_WORKBENCH){
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
if(tileEntity instanceof TileEntityArcaneWorkbench){
return new electroblob.wizardry.client.GuiArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench) tileEntity);
}
}
else if(id == WIZARD_HANDBOOK
&& ((player.getHeldItemMainhand() != null && player.getHeldItemMainhand().getItem() instanceof ItemWizardHandbook)
|| (player.getHeldItemOffhand() != null && player.getHeldItemOffhand().getItem() instanceof ItemWizardHandbook))){
return new electroblob.wizardry.client.GuiWizardHandbook();
}
else if(id == SPELL_BOOK){
if(player.getHeldItemMainhand() != null && player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){
return new electroblob.wizardry.client.GuiSpellBook(Spell.get(player.getHeldItemMainhand().getItemDamage()));
}else if(player.getHeldItemOffhand() != null && player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){
return new electroblob.wizardry.client.GuiSpellBook(Spell.get(player.getHeldItemOffhand().getItemDamage()));
}
}
else if(id == PORTABLE_CRAFTING){
return new electroblob.wizardry.client.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z));
}
return null;
}
}
@@ -0,0 +1,67 @@
package electroblob.wizardry;
import org.lwjgl.input.Keyboard;
import electroblob.wizardry.client.ClientProxy;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.InputEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class WizardryKeyHandler {
boolean NkeyPressed = false;
boolean BkeyPressed = false;
boolean NkeyAlreadyPressed = false;
boolean BkeyAlreadyPressed = false;
@SubscribeEvent
public void onKeyInput(InputEvent.KeyInputEvent event) {
// Key pressed
if(Keyboard.getEventKeyState()){
if(Wizardry.proxy instanceof ClientProxy){
if(ClientProxy.NEXT_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){
if(!NkeyPressed){
NkeyPressed = true;
}else{
NkeyAlreadyPressed = true;
}
if(!NkeyAlreadyPressed){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
}
}
if(ClientProxy.PREVIOUS_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){
if(!BkeyPressed){
BkeyPressed = true;
}else{
BkeyAlreadyPressed = true;
}
if(!BkeyAlreadyPressed){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
}
}
}
}
// Key released
else{
if(NkeyPressed){
NkeyPressed = false;
NkeyAlreadyPressed = false;
}else if(BkeyPressed){
BkeyPressed = false;
BkeyAlreadyPressed = false;
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,120 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockArcaneWorkbench extends BlockContainer {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.75D, 1.0D);
public BlockArcaneWorkbench(){
super(Material.ROCK);
this.setLightLevel(0.8f);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityArcaneWorkbench();
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) {
return false;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state) {
return EnumBlockRenderType.MODEL;
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player,
EnumHand hand, ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ){
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity == null || player.isSneaking()){
return false;
}
player.openGui(Wizardry.instance, WizardryGuiHandler.ARCANE_WORKBENCH, world, pos.getX(), pos.getY(), pos.getZ());
return true;
}
@Override
public void breakBlock(World world, BlockPos pos, IBlockState block)
{
Random random = new Random();
TileEntityArcaneWorkbench tileentityarcaneworkbench = (TileEntityArcaneWorkbench)world.getTileEntity(pos);
if (tileentityarcaneworkbench != null)
{
for (int j1 = 0; j1 < tileentityarcaneworkbench.getSizeInventory(); ++j1)
{
ItemStack itemstack = tileentityarcaneworkbench.getStackInSlot(j1);
if (itemstack != null)
{
float f = random.nextFloat() * 0.8F + 0.1F;
float f1 = random.nextFloat() * 0.8F + 0.1F;
EntityItem entityitem;
for (float f2 = random.nextFloat() * 0.8F + 0.1F; itemstack.stackSize > 0; world.spawnEntityInWorld(entityitem))
{
int k1 = random.nextInt(21) + 10;
if (k1 > itemstack.stackSize)
{
k1 = itemstack.stackSize;
}
itemstack.stackSize -= k1;
entityitem = new EntityItem(world, (double)((float)pos.getX() + f), (double)((float)pos.getY() + f1), (double)((float)pos.getZ() + f2), new ItemStack(itemstack.getItem(), k1, itemstack.getItemDamage()));
float f3 = 0.05F;
entityitem.motionX = (double)((float)random.nextGaussian() * f3);
entityitem.motionY = (double)((float)random.nextGaussian() * f3 + 0.2F);
entityitem.motionZ = (double)((float)random.nextGaussian() * f3);
if (itemstack.hasTagCompound())
{
entityitem.getEntityItem().setTagCompound(((NBTTagCompound)itemstack.getTagCompound().copy()));
}
}
}
}
//par1World.func_96440_m(par2, par3, par4, block);
}
super.breakBlock(world, pos, block);
}
}
@@ -0,0 +1,46 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.WizardryParticleType;
import net.minecraft.block.BlockBush;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.EnumPlantType;
// Extending BlockBush allows me to remove nearly everything from this class.
public class BlockCrystalFlower extends BlockBush {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.5F - 0.2f, 0.0F, 0.5F - 0.2f, 0.5F + 0.2f, 0.2f * 3.0F, 0.5F + 0.2f);
public BlockCrystalFlower(Material par2Material) {
super(par2Material);
this.setLightLevel(0.5f);
this.setTickRandomly(true);
this.setSoundType(SoundType.PLANT);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos)
{
return AABB;
}
@Override
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
if(world.isRemote && random.nextBoolean()){
Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, pos.getX()+random.nextDouble(), pos.getY()+random.nextDouble()/2+0.5, pos.getZ()+random.nextDouble(), 0d, 0.01, 0d, 20 + random.nextInt(10), 0.5f + (random.nextFloat()/2), 0.5f + (random.nextFloat()/2), 0.5f + (random.nextFloat()/2));
}
}
@Override
public EnumPlantType getPlantType(IBlockAccess world, BlockPos pos) {
return EnumPlantType.Plains;
}
}
@@ -0,0 +1,35 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.registry.WizardryItems;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
public class BlockCrystalOre extends Block {
public BlockCrystalOre(Material material) {
super(material);
this.setSoundType(SoundType.STONE);
setResistance(5.0F);
setHarvestLevel("pickaxe", 2);
}
@Override
public int quantityDropped(IBlockState state, int fortune, Random random)
{
if(fortune > 0){
return random.nextInt(2) + 1 + random.nextInt(fortune);
}else{
return random.nextInt(2) + 1;
}
}
@Override
public Item getItemDropped(IBlockState state, Random random, int fortune){
return WizardryItems.magic_crystal;
}
}
@@ -0,0 +1,58 @@
package electroblob.wizardry.block;
import electroblob.wizardry.tileentity.TileEntityMagicLight;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockMagicLight extends BlockContainer {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0, 0, 0, 0, 0, 0);
public BlockMagicLight(Material par2Material) {
super(par2Material);
this.setLightLevel(1.0f);
}
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos){
// The other two bounding box methods in Block aren't nullable, so this is the only one that can return NULL_AABB.
return NULL_AABB;
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public boolean isCollidable(){
return false;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityMagicLight(600);
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) {
return false;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state) {
return EnumBlockRenderType.ENTITYBLOCK_ANIMATED;
}
}
@@ -0,0 +1,110 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.tileentity.TileEntityPlayerSave;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.MobEffects;
import net.minecraft.item.Item;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
// TODO: Apparently you shouldn't extend BlockContainer. I feel like BlockArcaneWorkbench should, but what about the rest?
public class BlockSnare extends BlockContainer {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0f, 0.0f, 0.0f, 1.0f, 0.0625f, 1.0f);
public BlockSnare(Material par2Material){
super(par2Material);
this.setSoundType(SoundType.PLANT);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos){
return NULL_AABB;
}
@Override
public boolean hasTileEntity(IBlockState state){
return true;
}
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
if(!world.isRemote && entity instanceof EntityLivingBase){
if(world.getTileEntity(pos) instanceof TileEntityPlayerSave){
TileEntityPlayerSave tileentity = (TileEntityPlayerSave)world.getTileEntity(pos);
if(WizardryUtilities.isValidTarget(tileentity.getCaster(), entity)){
((EntityLivingBase)entity).attackEntityFrom(MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC), 6);
((EntityLivingBase)entity).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 100, 2));
world.destroyBlock(pos, false);
}
}
}
}
// The similarly named onNeighborChange method does NOT do the same thing.
@SuppressWarnings("deprecation")
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block blockIn){
super.neighborChanged(state, world, pos, blockIn);
if(!world.isSideSolid(pos.down(), EnumFacing.UP, false)){
world.setBlockToAir(pos);
}
}
@Override
public BlockRenderLayer getBlockLayer(){
return BlockRenderLayer.CUTOUT;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.MODEL;
}
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Override
public Item getItemDropped(IBlockState state, Random rand, int fortune){
return null;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityPlayerSave();
}
}
@@ -0,0 +1,94 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.tileentity.TileEntityTimer;
import electroblob.wizardry.util.WizardryParticleType;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on
// block break.
public class BlockSpectral extends BlockContainer {
public BlockSpectral(Material material) {
super(material);
this.setSoundType(SoundType.GLASS);
}
// Replaces getRenderBlockPass
@Override
public BlockRenderLayer getBlockLayer(){
return BlockRenderLayer.TRANSLUCENT;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state) {
return EnumBlockRenderType.MODEL;
}
// Apparently it's OK to override this, despite it being deprecated. More importantly, it being deprecated is not
// Forge's doing, rather it is Mojang themselves misusing the @Deprecated annotation to mean 'internal, don't call'.
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) {
return false;
}
@Override
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random) {
// Middle of block
Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX()+random.nextDouble(), pos.getY()+random.nextDouble(), pos.getZ()+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)),
0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f);
// Top surface
Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX()+random.nextDouble(), pos.getY()+1, pos.getZ()+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)),
0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f);
Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX()+random.nextDouble(), pos.getY()+1, pos.getZ()+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)),
0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f);
}
// Overriden to make the block always look full brightness despite not emitting full light.
@Override
public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos) {
return 15;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityTimer(1200);
}
@Override
public int quantityDropped(Random par1Random){
return 0;
}
@SuppressWarnings("deprecation")
@SideOnly(Side.CLIENT)
@Override
public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side){
IBlockState iblockstate = blockAccess.getBlockState(pos.offset(side));
Block block = iblockstate.getBlock();
return block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side);
}
}
@@ -0,0 +1,146 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.spell.Petrify;
import electroblob.wizardry.tileentity.TileEntityStatue;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class BlockStatue extends BlockContainer {
private boolean isIce;
public BlockStatue(Material material) {
super(material);
this.isIce = material == Material.ICE;
if(this.isIce){
this.slipperiness = 0.98F;
this.setSoundType(SoundType.GLASS);
}
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
// Not a good idea to call getBlockBoundsMinX() or whatever from in here, since this method changes those!
if(!this.isIce){
if(world.getTileEntity(pos) instanceof TileEntityStatue){
TileEntityStatue statue = (TileEntityStatue)world.getTileEntity(pos);
if(statue.creature != null){
// Block bounds are set to match the width and height of the entity, clamped to within 1 block.
return new AxisAlignedBB((float)Math.max(0.5 - statue.creature.width/2, 0), 0,
(float)Math.max(0.5 - statue.creature.width/2, 0),
(float)Math.min(0.5 + statue.creature.width/2, 1),
// This checks if the block is the top one and if so reduces its height so the top lines up with
// the top of the entity model.
statue.position == statue.parts ? (float)Math.min(statue.creature.height - statue.parts + 1, 1) : 1,
(float)Math.min(0.5 + statue.creature.width/2, 1));
}
}
}
return FULL_BLOCK_AABB;
}
// getCollisionBoundingBox eventually calls getBoundingBox anyway, and since I want the collision box and the block
// outline to be the same here, I've removed that getCollisionBoundingBox entirely.
// The number of these methods is quite simply ridiculous. This one seems to be for placement logic and block
// connections (fences, glass panes, etc.)...
@Override public boolean isFullCube(IBlockState state) { return false; }
// ...this one isn't used much but has something to do with redstone...
@Override public boolean isBlockNormalCube(IBlockState state) { return false; }
// ... this one is for most other game logic...
@Override public boolean isNormalCube(IBlockState state) { return false; }
// Forge version of the above method. I still need to override both though because vanilla uses the other one.
@Override public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { return false; }
// ... and this one is for rendering.
@Override public boolean isOpaqueCube(IBlockState state){ return false; }
@Override
public BlockRenderLayer getBlockLayer(){
return this.isIce ? BlockRenderLayer.TRANSLUCENT : BlockRenderLayer.SOLID;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return this.isIce ? EnumBlockRenderType.MODEL : EnumBlockRenderType.ENTITYBLOCK_ANIMATED;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityStatue(this.isIce);
}
@Override
public int quantityDropped(Random random){
return 0;
}
@Override
public void breakBlock(World world, BlockPos pos, IBlockState state){
if(!world.isRemote){
TileEntityStatue tileentity = (TileEntityStatue)world.getTileEntity(pos);
if(tileentity != null){
if(tileentity.parts == 2){
if(tileentity.position == 2){
world.destroyBlock(pos.down(), false);
}else{
world.destroyBlock(pos.up(), false);
}
}else if(tileentity.parts == 3){
if(tileentity.position == 3){
world.destroyBlock(pos.down(), false);
world.destroyBlock(pos.down(2), false);
}else if(tileentity.position == 2){
world.destroyBlock(pos.down(), false);
world.destroyBlock(pos.up(), false);
}else{
world.destroyBlock(pos.up(), false);
world.destroyBlock(pos.up(2), false);
}
}
}
// This is only when position == 1 because world.destroyBlock calls this function for the other blocks.
if(tileentity != null && tileentity.position == 1 && tileentity.creature != null){
tileentity.creature.getEntityData().removeTag(Petrify.NBT_KEY);
tileentity.creature.isDead = false;
world.spawnEntityInWorld(tileentity.creature);
}
}
super.breakBlock(world, pos, state);
}
@SuppressWarnings("deprecation")
@SideOnly(Side.CLIENT)
@Override
public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side){
IBlockState iblockstate = blockAccess.getBlockState(pos.offset(side));
Block block = iblockstate.getBlock();
return this.isIce && block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side);
}
}
@@ -0,0 +1,115 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryBlocks;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockTransportationStone extends Block {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0625f*5, 0, 0.0625f*5, 0.0625f*11, 0.0625f*6, 0.0625f*11);
public BlockTransportationStone(Material material){
super(material);
this.setTickRandomly(true);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
// The number of these methods is quite simply ridiculous. This one seems to be for placement logic and block
// connections (fences, glass panes, etc.)...
@Override public boolean isFullCube(IBlockState state) { return false; }
// ...this one isn't used much but has something to do with redstone...
@Override public boolean isBlockNormalCube(IBlockState state) { return false; }
// ... this one is for most other game logic...
@Override public boolean isNormalCube(IBlockState state) { return false; }
// Forge version of the above method. I still need to override both though because vanilla uses the other one.
@Override public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { return false; }
// ... and this one is for rendering.
@Override public boolean isOpaqueCube(IBlockState state){ return false; }
@Override
public void onNeighborChange(IBlockAccess world, BlockPos pos, BlockPos neighbor){
super.onNeighborChange(world, pos, neighbor);
if(!world.isSideSolid(pos.down(), EnumFacing.UP, false) && world instanceof World){
this.dropBlockAsItem((World) world, pos, world.getBlockState(pos), 0);
((World)world).setBlockToAir(pos);
}
}
@Override
public void updateTick(World world, BlockPos pos, IBlockState state, Random random) {
if(!world.isSideSolid(pos.down(), EnumFacing.UP)){
this.dropBlockAsItem(world, pos, world.getBlockState(pos), 0);
world.setBlockToAir(pos);
}
}
@Override
public boolean canPlaceBlockAt(World world, BlockPos pos){
return super.canPlaceBlockAt(world, pos) && world.isSideSolid(pos.down(), EnumFacing.UP);
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player,
EnumHand hand, ItemStack stack, EnumFacing side, float hitX, float hitY, float hitZ) {
if(stack != null && stack.getItem() instanceof ItemWand){
if(WizardData.get(player) != null){
WizardData data = WizardData.get(player);
for(int x=-1; x<=1; x++){
for(int z=-1; z<=1; z++){
BlockPos pos1 = pos.add(x, 0, z);
if(testForCircle(world, pos1)){
data.setStoneCircleLocation(pos1, world.provider.getDimension());
if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("tile.wizardry:transportation_stone.confirm", Spells.transportation.getNameForTranslationFormatted()));
return true;
}
}
}
if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("tile.wizardry:transportation_stone.invalid"));
return true;
}
}
return false;
}
/** Returns whether the specified location is surrounded by a complete cicle of 8 transportation stones. */
public static boolean testForCircle(World world, BlockPos pos){
if(world.getBlockState(pos).getMaterial().blocksMovement()) return false;
for(int x=-1; x<=1; x++){
for(int z=-1; z<=1; z++){
if(world.getBlockState(pos.add(x, 0, z)).getBlock() != WizardryBlocks.transportation_stone){
if(x != 0 || z != 0) return false;
}
}
}
return true;
}
}
@@ -0,0 +1,70 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.tileentity.TileEntityTimer;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on block break.
public class BlockVanishingCobweb extends BlockContainer {
public BlockVanishingCobweb(Material material) {
super(material);
}
@SideOnly(Side.CLIENT)
public BlockRenderLayer getBlockLayer()
{
return BlockRenderLayer.CUTOUT;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.MODEL;
}
@Override
public boolean isOpaqueCube(IBlockState state)
{
return false;
}
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos)
{
return NULL_AABB;
}
@Override
public boolean isFullCube(IBlockState state)
{
return false;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityTimer(400);
}
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity){
entity.setInWeb();
}
@Override
public int quantityDropped(Random par1Random){
return 0;
}
}
@@ -0,0 +1,579 @@
package electroblob.wizardry.client;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import org.lwjgl.input.Keyboard;
import electroblob.wizardry.CommonProxy;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelWizardArmour;
import electroblob.wizardry.client.particle.ParticleBlizzard;
import electroblob.wizardry.client.particle.ParticleDarkMagic;
import electroblob.wizardry.client.particle.ParticleDust;
import electroblob.wizardry.client.particle.ParticleGiantBubble;
import electroblob.wizardry.client.particle.ParticleIce;
import electroblob.wizardry.client.particle.ParticleLeaf;
import electroblob.wizardry.client.particle.ParticleMagicFlame;
import electroblob.wizardry.client.particle.ParticlePath;
import electroblob.wizardry.client.particle.ParticleRotatingSparkle;
import electroblob.wizardry.client.particle.ParticleSnow;
import electroblob.wizardry.client.particle.ParticleSpark;
import electroblob.wizardry.client.particle.ParticleSparkle;
import electroblob.wizardry.client.particle.ParticleTornado;
import electroblob.wizardry.client.renderer.LayerStone;
import electroblob.wizardry.client.renderer.RenderArc;
import electroblob.wizardry.client.renderer.RenderArcaneWorkbench;
import electroblob.wizardry.client.renderer.RenderBlackHole;
import electroblob.wizardry.client.renderer.RenderBlank;
import electroblob.wizardry.client.renderer.RenderBubble;
import electroblob.wizardry.client.renderer.RenderDecay;
import electroblob.wizardry.client.renderer.RenderDecoy;
import electroblob.wizardry.client.renderer.RenderEvilWizard;
import electroblob.wizardry.client.renderer.RenderFireRing;
import electroblob.wizardry.client.renderer.RenderForceArrow;
import electroblob.wizardry.client.renderer.RenderHammer;
import electroblob.wizardry.client.renderer.RenderIceGiant;
import electroblob.wizardry.client.renderer.RenderIceSpike;
import electroblob.wizardry.client.renderer.RenderLightningDisc;
import electroblob.wizardry.client.renderer.RenderLightningPulse;
import electroblob.wizardry.client.renderer.RenderMagicArrow;
import electroblob.wizardry.client.renderer.RenderMagicLight;
import electroblob.wizardry.client.renderer.RenderPhoenix;
import electroblob.wizardry.client.renderer.RenderProjectile;
import electroblob.wizardry.client.renderer.RenderSigil;
import electroblob.wizardry.client.renderer.RenderSpiritHorse;
import electroblob.wizardry.client.renderer.RenderSpiritWolf;
import electroblob.wizardry.client.renderer.RenderStatue;
import electroblob.wizardry.client.renderer.RenderWizard;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.entity.EntityShield;
import electroblob.wizardry.entity.construct.EntityArrowRain;
import electroblob.wizardry.entity.construct.EntityBlackHole;
import electroblob.wizardry.entity.construct.EntityBlizzard;
import electroblob.wizardry.entity.construct.EntityBubble;
import electroblob.wizardry.entity.construct.EntityDecay;
import electroblob.wizardry.entity.construct.EntityEarthquake;
import electroblob.wizardry.entity.construct.EntityFireRing;
import electroblob.wizardry.entity.construct.EntityFireSigil;
import electroblob.wizardry.entity.construct.EntityForcefield;
import electroblob.wizardry.entity.construct.EntityFrostSigil;
import electroblob.wizardry.entity.construct.EntityHailstorm;
import electroblob.wizardry.entity.construct.EntityHammer;
import electroblob.wizardry.entity.construct.EntityHealAura;
import electroblob.wizardry.entity.construct.EntityIceSpike;
import electroblob.wizardry.entity.construct.EntityLightningPulse;
import electroblob.wizardry.entity.construct.EntityLightningSigil;
import electroblob.wizardry.entity.construct.EntityTornado;
import electroblob.wizardry.entity.living.EntityDecoy;
import electroblob.wizardry.entity.living.EntityEvilWizard;
import electroblob.wizardry.entity.living.EntityIceGiant;
import electroblob.wizardry.entity.living.EntityIceWraith;
import electroblob.wizardry.entity.living.EntityLightningWraith;
import electroblob.wizardry.entity.living.EntityPhoenix;
import electroblob.wizardry.entity.living.EntityShadowWraith;
import electroblob.wizardry.entity.living.EntitySpiritHorse;
import electroblob.wizardry.entity.living.EntitySpiritWolf;
import electroblob.wizardry.entity.living.EntityStormElemental;
import electroblob.wizardry.entity.living.EntityWizard;
import electroblob.wizardry.entity.living.ISpellCaster;
import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.entity.projectile.EntityDarknessOrb;
import electroblob.wizardry.entity.projectile.EntityDart;
import electroblob.wizardry.entity.projectile.EntityFirebolt;
import electroblob.wizardry.entity.projectile.EntityFirebomb;
import electroblob.wizardry.entity.projectile.EntityForceArrow;
import electroblob.wizardry.entity.projectile.EntityForceOrb;
import electroblob.wizardry.entity.projectile.EntityIceCharge;
import electroblob.wizardry.entity.projectile.EntityIceLance;
import electroblob.wizardry.entity.projectile.EntityIceShard;
import electroblob.wizardry.entity.projectile.EntityLightningArrow;
import electroblob.wizardry.entity.projectile.EntityLightningDisc;
import electroblob.wizardry.entity.projectile.EntityMagicMissile;
import electroblob.wizardry.entity.projectile.EntityPoisonBomb;
import electroblob.wizardry.entity.projectile.EntitySmokeBomb;
import electroblob.wizardry.entity.projectile.EntitySpark;
import electroblob.wizardry.entity.projectile.EntitySparkBomb;
import electroblob.wizardry.entity.projectile.EntityThunderbolt;
import electroblob.wizardry.item.ItemScroll;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketCastSpell;
import electroblob.wizardry.packet.PacketNPCCastSpell;
import electroblob.wizardry.packet.PacketPlayerSync.Message;
import electroblob.wizardry.packet.PacketTransportation;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Clairvoyance;
import electroblob.wizardry.spell.None;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityMagicLight;
import electroblob.wizardry.tileentity.TileEntityStatue;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryParticleType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.entity.RenderBlaze;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityBlaze;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.fml.client.config.GuiConfigEntries.NumberSliderEntry;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
/**
* The client proxy for wizardry.
* @author Electroblob
* @since Wizardry 1.0
*/
public class ClientProxy extends CommonProxy {
/** Static instance of the mixed font renderer */
public static MixedFontRenderer mixedFontRenderer;
// Key Bindings
public static final KeyBinding NEXT_SPELL = new KeyBinding("key.wizardry:next_spell", Keyboard.KEY_N, "key.categories.wizardry");
public static final KeyBinding PREVIOUS_SPELL = new KeyBinding("key.wizardry:previous_spell", Keyboard.KEY_B, "key.categories.wizardry");
// Armour Model
public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f);
// SECTION Registry
// ===============================================================================================================
@Override
public ModelBiped getWizardArmourModel(){
return WIZARD_ARMOUR_MODEL;
}
@Override
public void registerKeyBindings(){
ClientRegistry.registerKeyBinding(NEXT_SPELL);
ClientRegistry.registerKeyBinding(PREVIOUS_SPELL);
}
@Override
public void registerSpellHUD(){
MinecraftForge.EVENT_BUS.register(new GuiSpellDisplay(Minecraft.getMinecraft()));
}
@Override
public void initMixedFontRenderer(){
mixedFontRenderer = new MixedFontRenderer(Minecraft.getMinecraft().gameSettings,
new ResourceLocation("textures/font/ascii.png"), Minecraft.getMinecraft().renderEngine, false);
}
// SECTION Misc
// ===============================================================================================================
@Override
public void setToNumberSliderEntry(Property property) {
property.setConfigEntryClass(NumberSliderEntry.class);
}
@Override
public World getTheWorld() {
return Minecraft.getMinecraft().theWorld;
}
@Override
public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){
Minecraft.getMinecraft().getSoundHandler().playSound(new MovingSoundEntity(entity, sound, volume, pitch, repeat));
}
// SECTION Items
// ===============================================================================================================
@Override
public FontRenderer getFontRenderer(ItemStack stack){
Spell spell = Spells.none;
if(stack.getItem() instanceof ItemWand){
spell = WandHelper.getCurrentSpell(stack);
}else if(stack.getItem() instanceof ItemSpellBook || stack.getItem() instanceof ItemScroll){
spell = Spell.get(stack.getItemDamage());
}
if(Minecraft.getMinecraft().thePlayer != null && Wizardry.settings.discoveryMode
&& WizardData.get(Minecraft.getMinecraft().thePlayer) != null
&& !Minecraft.getMinecraft().thePlayer.capabilities.isCreativeMode
&& !WizardData.get(Minecraft.getMinecraft().thePlayer).hasSpellBeenDiscovered(spell)){
return mixedFontRenderer;
}
return null;
}
@Override
public String getScrollDisplayName(ItemStack scroll){
// Displays [Empty slot] if spell is continuous.
Spell spell = Spell.get(scroll.getItemDamage());
if(spell.isContinuous) spell = Spells.none;
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
boolean discovered = true;
// It seems that this method is called when the world is loading, before thePlayer has been initialised.
// If the player is null, the spell is assumed to be discovered.
if(player != null && Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode
&& WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){
discovered = false;
}
if(discovered){
return I18n.format("item.wizardry:scroll.name", spell.getDisplayName()).trim();
}else{
return I18n.format("item.wizardry:scroll.undiscovered.name", "#" + SpellGlyphData.getGlyphName(spell, player.worldObj) + "#").trim();
}
}
@Override
public double getConjuredBowDurability(ItemStack stack){
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
if(player.getActiveItemStack() == stack){
return (double)(stack.getItemDamage() + (player.getItemInUseMaxCount()) ) / (double)stack.getMaxDamage();
}
return super.getConjuredBowDurability(stack);
}
// SECTION Particles
// ===============================================================================================================
@Override
public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b, boolean doGravity, double radius){
// Colour values are now automatically clamped to between 0 and 1, as values outside this range seem to
// cause strange effects in 1.10 (or more specifically, particles that are bright pink!)
// TODO: This is a terrible dirty fix, but it'll do for now. Find a nicer way in future.
if(type != WizardryParticleType.MAGIC_FIRE) r = MathHelper.clamp_float(r, 0, 1);
g = MathHelper.clamp_float(g, 0, 1);
b = MathHelper.clamp_float(b, 0, 1);
switch(type){
case BLIZZARD:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleBlizzard(world, maxAge, x, z, radius, y));
break;
case BRIGHT_DUST:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDust(world, x, y, z, velX, velY, velZ, r, g, b, false));
break;
case DARK_MAGIC:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDarkMagic(world, x, y, z, velX, velY, velZ, r, g, b));
break;
case DUST:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDust(world, x, y, z, velX, velY, velZ, r, g, b, true));
break;
case ICE:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleIce(world, x, y, z, velX, velY, velZ, maxAge));
break;
case LEAF:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleLeaf(world, x, y, z, velX, velY, velZ, maxAge));
break;
case MAGIC_BUBBLE:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleGiantBubble(world, x, y, z, velX, velY, velZ));
break;
case MAGIC_FIRE:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleMagicFlame(world, x, y, z, velX, velY, velZ, maxAge, r == 0 ? 1 + world.rand.nextFloat() : r));
break;
case PATH:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticlePath(world, x, y, z, velX, velY, velZ, r, g, b, maxAge));
break;
case SNOW:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSnow(world, x, y, z, velX, velY, velZ));
break;
case SPARK:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSpark(world, x, y, z, velX, velY, velZ));
break;
case SPARKLE:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSparkle(world, x, y, z, velX, velY, velZ, r, g, b, maxAge, doGravity));
break;
case SPARKLE_ROTATING:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleRotatingSparkle(world, maxAge, x, z, radius, y, r, g, b));
break;
default:
break;
}
}
@Override
public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTornado(world, maxAge, x, z, radius, y, velX, velZ, block).setBlockPos(pos));//, world.rand.nextInt(6)));
}
// SECTION Packet Handlers
// ===============================================================================================================
@Override
public void handleCastSpellPacket(PacketCastSpell.Message message){
World world = Minecraft.getMinecraft().theWorld;
Entity caster = world.getEntityByID(message.casterID);
Spell spell = Spell.get(message.spellID);
// Should always be true
if(caster instanceof EntityPlayer){
((EntityPlayer)caster).setActiveHand(message.hand);
// Duration isn't needed because it only ever affects things server-side, and anything that is
// seen client-side gets synced elsewhere.
spell.cast(world, (EntityPlayer)caster, message.hand, 0, new SpellModifiers());
// Updates the spell discovery data client-side. Could be done by calling sync(), but that means sending
// another packet unnecessarily.
if(WizardData.get((EntityPlayer)caster) != null){
WizardData.get((EntityPlayer)caster).discoverSpell(spell);
}
}else{
Wizardry.logger.warn("Recieved a PacketCastSpell, but the caster ID was not the ID of a player");
}
}
@Override
public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){
World world = Minecraft.getMinecraft().theWorld;
Entity caster = world.getEntityByID(message.casterID);
Spell spell = Spell.get(message.spellID);
// Should always be true
if(caster instanceof EntityPlayer){
WizardData data = WizardData.get((EntityPlayer)caster);
if(data != null){
if(data.isCasting()){
WizardData.get((EntityPlayer)caster).stopCastingContinuousSpell();
}else{
WizardData.get((EntityPlayer)caster).startCastingContinuousSpell(spell, message.modifiers);
}
}
}else{
Wizardry.logger.warn("Recieved a PacketCastContinuousSpell, but the caster ID was not the ID of a player");
}
}
@Override
public void handleNPCCastSpellPacket(PacketNPCCastSpell.Message message){
World world = Minecraft.getMinecraft().theWorld;
Entity caster = world.getEntityByID(message.casterID);
Entity target = message.targetID == -1 ? null : world.getEntityByID(message.targetID);
Spell spell = Spell.get(message.spellID);
// Should always be true
if(caster instanceof EntityLiving){
if(target instanceof EntityLivingBase){
spell.cast(world, (EntityLiving)caster, message.hand, 0, (EntityLivingBase)target, message.modifiers);
}
if(caster instanceof ISpellCaster){
if(spell.isContinuous || spell instanceof None){
((ISpellCaster)caster).setContinuousSpell(spell);
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
}
}
}else{
Wizardry.logger.warn("Recieved a PacketNPCCastSpell, but the caster ID was not the ID of an EntityLiving");
}
}
@Override
public void handleTransportationPacket(PacketTransportation.Message message){
World world = Minecraft.getMinecraft().theWorld;
Entity caster = world.getEntityByID(message.casterID);
// Moved from when the packet is sent to when it is received; fixes the sound not playing in first person.
caster.playSound(SoundEvents.BLOCK_PORTAL_TRAVEL, 1, 1);
for(int i=0; i<20; i++){
double radius = 1;
double angle = world.rand.nextDouble()*Math.PI*2;
double x = caster.posX + radius*Math.cos(angle);
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble()*2;
double z = caster.posZ + radius*Math.sin(angle);
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSparkle(world, x, y, z, 0, 0.02, 0, 0.6f, 1.0f, 0.6f, 80 + world.rand.nextInt(10)));
}
for(int i=0; i<20; i++){
double radius = 1;
double angle = world.rand.nextDouble()*Math.PI*2;
double x = caster.posX + radius*Math.cos(angle);
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble()*2;
double z = caster.posZ + radius*Math.sin(angle);
world.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, x, y, z, 0, 0.02, 0);
}
for(int i=0; i<20; i++){
double radius = 1;
double angle = world.rand.nextDouble()*Math.PI*2;
double x = caster.posX + radius*Math.cos(angle);
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble()*2;
double z = caster.posZ + radius*Math.sin(angle);
world.spawnParticle(EnumParticleTypes.ENCHANTMENT_TABLE, x, y, z, 0, 0.02, 0);
}
}
@Override
public void handlePlayerSyncPacket(Message message){
WizardData properties = WizardData.get(Minecraft.getMinecraft().thePlayer);
if(properties != null){
properties.spellsDiscovered = message.spellsDiscovered;
if(message.selectedMinionID == -1){
properties.selectedMinion = null;
}else{
Entity entity = Minecraft.getMinecraft().theWorld.getEntityByID(message.selectedMinionID);
if(entity instanceof ISummonedCreature){
properties.selectedMinion = new WeakReference<ISummonedCreature>((ISummonedCreature)entity);
}else{
properties.selectedMinion = null;
}
}
}
}
@Override
public void handleGlyphDataPacket(electroblob.wizardry.packet.PacketGlyphData.Message message){
SpellGlyphData data = SpellGlyphData.get(Minecraft.getMinecraft().theWorld);
data.randomNames = new HashMap<Spell, String>();
data.randomDescriptions = new HashMap<Spell, String>();
for(Spell spell : Spell.getSpells(Spell.allSpells)){
// -1 because the none spell isn't included
data.randomNames.put(spell, message.names.get(spell.id() - 1));
data.randomDescriptions.put(spell, message.descriptions.get(spell.id() - 1));
}
}
@Override
public void handleClairvoyancePacket(electroblob.wizardry.packet.PacketClairvoyance.Message message) {
Clairvoyance.spawnPathPaticles(Minecraft.getMinecraft().theWorld, message.path, message.durationMultiplier);
}
// SECTION Rendering
// ===============================================================================================================
private static final ResourceLocation ICE_WRAITH_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_wraith.png");
private static final ResourceLocation LIGHTNING_WRAITH_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_wraith.png");
/** Static instance of the statue renderer, used to access the block breaking texture. */
public static RenderStatue renderStatue;
@Override
public void initialiseLayers(){
LayerStone.initialiseLayers();
}
@Override
public void registerRenderers(){
// Minions
// Yet another advantage to the new system: turns out you don't even need to register the renderer if you
// just want the vanilla one for the mob you're extending.
// An anonymous class in a lambda expression! No point writing a separate class really, is there?
RenderingRegistry.registerEntityRenderingHandler(EntityLightningWraith.class, manager -> new RenderBlaze(manager){
@Override
protected ResourceLocation getEntityTexture(EntityBlaze entity){
return LIGHTNING_WRAITH_TEXTURE;
}
});
RenderingRegistry.registerEntityRenderingHandler(EntityIceWraith.class, manager -> new RenderBlaze(manager){
@Override
protected ResourceLocation getEntityTexture(EntityBlaze entity){
return ICE_WRAITH_TEXTURE;
}
});
RenderingRegistry.registerEntityRenderingHandler(EntityIceGiant.class, RenderIceGiant::new);
RenderingRegistry.registerEntityRenderingHandler(EntityPhoenix.class, RenderPhoenix::new);
// Projectiles
RenderingRegistry.registerEntityRenderingHandler(EntityMagicMissile.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/magic_missile.png"), false, 8.0, 4.0, 16, 9, false));
RenderingRegistry.registerEntityRenderingHandler(EntityIceShard.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ice_shard.png"), false, 8.0, 2.0, 16, 5, false));
RenderingRegistry.registerEntityRenderingHandler(EntityLightningArrow.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_arrow.png"), true, 8.0, 2.0, 16, 5, false));
RenderingRegistry.registerEntityRenderingHandler(EntityDart.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/dart.png"), false, 8.0, 2.0, 16, 5, true));
RenderingRegistry.registerEntityRenderingHandler(EntityIceLance.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ice_lance.png"), false, 16.0, 3.0, 22, 5, true));
RenderingRegistry.registerEntityRenderingHandler(EntityForceArrow.class, RenderForceArrow::new);
// Creatures
RenderingRegistry.registerEntityRenderingHandler(EntitySpiritWolf.class, manager -> new RenderSpiritWolf(manager, 0.5f));
RenderingRegistry.registerEntityRenderingHandler(EntitySpiritHorse.class, manager -> new RenderSpiritHorse(manager, 0.5f));
RenderingRegistry.registerEntityRenderingHandler(EntityWizard.class, RenderWizard::new);
RenderingRegistry.registerEntityRenderingHandler(EntityEvilWizard.class, RenderEvilWizard::new);
RenderingRegistry.registerEntityRenderingHandler(EntityDecoy.class, RenderDecoy::new);
// Throwables
RenderingRegistry.registerEntityRenderingHandler(EntitySparkBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/spark_bomb.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityFirebomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/firebomb.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityPoisonBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/poison_bomb.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityIceCharge.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/ice_charge.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityForceOrb.class, manager -> new RenderProjectile(manager, 0.7f, new ResourceLocation(Wizardry.MODID, "textures/entity/force_orb.png"), true));
RenderingRegistry.registerEntityRenderingHandler(EntitySpark.class, manager -> new RenderProjectile(manager, 0.4f, new ResourceLocation(Wizardry.MODID, "textures/entity/spark.png"), true));
RenderingRegistry.registerEntityRenderingHandler(EntityDarknessOrb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/darkness_orb.png"), true));
RenderingRegistry.registerEntityRenderingHandler(EntityFirebolt.class, manager -> new RenderProjectile(manager, 0.2f, new ResourceLocation(Wizardry.MODID, "textures/entity/firebolt.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityLightningDisc.class, manager -> new RenderLightningDisc(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_sigil.png"), 2.0f));
RenderingRegistry.registerEntityRenderingHandler(EntitySmokeBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/smoke_bomb.png"), false));
// Effects and constructs
RenderingRegistry.registerEntityRenderingHandler(EntityArc.class, RenderArc::new);
RenderingRegistry.registerEntityRenderingHandler(EntityBlackHole.class, RenderBlackHole::new);
RenderingRegistry.registerEntityRenderingHandler(EntityShield.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityBubble.class, RenderBubble::new);
RenderingRegistry.registerEntityRenderingHandler(EntityHammer.class, RenderHammer::new);
RenderingRegistry.registerEntityRenderingHandler(EntityIceSpike.class, RenderIceSpike::new);
// Stuff that doesn't render
RenderingRegistry.registerEntityRenderingHandler(EntityBlizzard.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityTornado.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityArrowRain.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityShadowWraith.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityForcefield.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityThunderbolt.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityStormElemental.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityEarthquake.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityHailstorm.class, RenderBlank::new);
// Runes on ground
RenderingRegistry.registerEntityRenderingHandler(EntityHealAura.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/healing_aura.png"), 5.0f, false));
RenderingRegistry.registerEntityRenderingHandler(EntityFireSigil.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/fire_sigil.png"), 2.0f, true));
RenderingRegistry.registerEntityRenderingHandler(EntityFrostSigil.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/frost_sigil.png"), 2.0f, true));
RenderingRegistry.registerEntityRenderingHandler(EntityLightningSigil.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_sigil.png"), 2.0f, true));
RenderingRegistry.registerEntityRenderingHandler(EntityFireRing.class, manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png"), 5.0f));
RenderingRegistry.registerEntityRenderingHandler(EntityDecay.class, RenderDecay::new);
RenderingRegistry.registerEntityRenderingHandler(EntityLightningPulse.class, manager -> new RenderLightningPulse(manager, 8.0f));
// TESRs
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench());
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityStatue.class, renderStatue = new RenderStatue());
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityMagicLight.class, new RenderMagicLight());
}
}
@@ -0,0 +1,76 @@
package electroblob.wizardry.client;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.EntityList;
import net.minecraftforge.fml.client.config.GuiButtonExt;
import net.minecraftforge.fml.client.config.GuiEditArray;
import net.minecraftforge.fml.client.config.GuiEditArrayEntries;
import net.minecraftforge.fml.client.config.GuiEditArrayEntries.StringEntry;
import net.minecraftforge.fml.client.config.GuiSelectString;
import net.minecraftforge.fml.client.config.IConfigElement;
/** [NYI] Intended as a way of choosing entities by name from all those currently registered, within the config file, so
* that users don't have to look up the entity IDs. I can't get this to work correctly at the moment. */
public class EntityNameEntry extends StringEntry {
protected final GuiButtonExt btnValue;
protected Object entityClass;
public EntityNameEntry(GuiEditArray owningScreen, GuiEditArrayEntries owningEntryList, IConfigElement configElement, Object value)
{
super(owningScreen, owningEntryList, configElement, value);
this.btnValue = new GuiButtonExt(0, 0, 0, owningEntryList.controlWidth, 18, I18n.format(this.textFieldValue.getText()));
//this.btnValue.enabled = owningScreen.enabled;
}
@Override
public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected)
{
//super.drawEntry(slotIndex, x, y, listWidth, slotHeight, tessellator, mouseX, mouseY, isSelected);
this.btnValue.xPosition = listWidth / 4;
this.btnValue.yPosition = y;
String trans = I18n.format(this.textFieldValue.getText());
if (!trans.equals(this.textFieldValue.getText()))
this.btnValue.displayString = trans;
else
this.btnValue.displayString = this.textFieldValue.getText();
//btnValue.packedFGColour = value ? GuiUtils.getColorCode('2', true) : GuiUtils.getColorCode('4', true);
this.btnValue.drawButton(owningEntryList.getMC(), mouseX, mouseY);
}
@Override
public boolean mousePressed(int index, int x, int y, int mouseEvent, int relativeX, int relativeY)
{
if (this.btnValue.mousePressed(owningEntryList.getMC(), x, y))
{
btnValue.playPressSound(owningEntryList.getMC().getSoundHandler());
// Some sort of type incompatiblity meant that I had to do this first.
Map<Object, String> map = new HashMap<Object, String>(EntityList.CLASS_TO_NAME);
Minecraft.getMinecraft().displayGuiScreen(new GuiSelectString(this.owningScreen, configElement, index, map, this.getValue(), true));
owningEntryList.recalculateState();
return true;
}
return super.mousePressed(index, x, y, mouseEvent, relativeX, relativeY);
}
@Override
public void mouseReleased(int index, int x, int y, int mouseEvent, int relativeX, int relativeY)
{
this.btnValue.mouseReleased(x, y);
super.mouseReleased(index, x, y, mouseEvent, relativeX, relativeY);
}
@Override
public Object getValue()
{
return this.textFieldValue.getText();
}
}
@@ -0,0 +1,230 @@
package electroblob.wizardry.client;
import org.lwjgl.input.Keyboard;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class GuiArcaneWorkbench extends GuiContainer {
private GuiButton applyBtn;
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png");
private IInventory playerInventory;
private IInventory arcaneWorkbenchInventory;
private final int tooltipWidth = 164;
public GuiArcaneWorkbench(InventoryPlayer invPlayer, TileEntityArcaneWorkbench entity) {
super(new ContainerArcaneWorkbench(invPlayer, entity));
this.playerInventory = invPlayer;
this.arcaneWorkbenchInventory = entity;
xSize = 176;
ySize = 220;
}
@Override
public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_){
// Tests if there is a wand in the workbench and edits the positioning accordingly
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){
guiLeft = (this.width - this.xSize - tooltipWidth)/2;
this.applyBtn.xPosition = (this.width - tooltipWidth)/2 + 48;
}else{
guiLeft = (this.width - this.xSize)/2;
this.applyBtn.xPosition = this.width/2 + 48;
}
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack()){
this.applyBtn.enabled = true;
}else{
this.applyBtn.enabled = false;
}
super.drawScreen(p_73863_1_, p_73863_2_, p_73863_3_);
}
@Override
public void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
GlStateManager.pushAttrib();
GlStateManager.color(1F, 1F, 1F, 1F);
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
// Main inventory
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize);
// Changing slots
for(int i=0; i<ContainerArcaneWorkbench.CRYSTAL_SLOT; i++){
Slot slot = this.inventorySlots.getSlot(i);
if(slot.xDisplayPosition >=0 && slot.yDisplayPosition >= 0)
this.drawTexturedModalRect(guiLeft + slot.xDisplayPosition - 10, guiTop + slot.yDisplayPosition - 10,
0, 220, 36, 36);
}
// Tooltip only drawn if there is a wand
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){
// Tooltip box
drawTexturedModalRect(guiLeft + xSize, guiTop, xSize, 0, 256 - xSize - 4, ySize);
drawTexturedModalRect(guiLeft + 252, guiTop, xSize + 4, 0, tooltipWidth - 2*(256 - xSize - 4), ySize);
drawTexturedModalRect(guiLeft + xSize + tooltipWidth - (256 - xSize - 4), guiTop, xSize + 4, 0, 256 - xSize - 4, ySize);
ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack();
Spell[] spells = WandHelper.getSpells(wand);
int i=0;
for(Spell spell : spells){
boolean discovered = true;
if(!this.mc.thePlayer.capabilities.isCreativeMode && WizardData.get(this.mc.thePlayer) != null){
discovered = WizardData.get(this.mc.thePlayer).hasSpellBeenDiscovered(spell);
}
// As of Wizardry 1.2, the icons have been split off into their own texture files to allow for add-on
// mods to add their own.
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.element.getIcon() : Element.MAGIC.getIcon());
// Renders the little element icon
WizardryUtilities.drawTexturedRect(guiLeft + xSize + 5, guiTop + 34 + 10*i++, 8, 8);
}
int x = 0;
int y = guiTop + 50 + spells.length*10;
// Look how much shorter this is with the WandHelper class!
for(Item item : WandHelper.getSpecialUpgrades()){
int level = WandHelper.getUpgradeLevel(wand, item);
if(level > 0){
ItemStack stack = new ItemStack(item, level);
GlStateManager.enableDepth();
this.itemRender.renderItemAndEffectIntoGUI(stack, guiLeft + xSize + 6 + x, y);
this.itemRender.renderItemOverlayIntoGUI(this.fontRendererObj, stack, guiLeft + xSize + 6 + x, y, null);
x += 18;
GlStateManager.disableDepth();
}
}
}
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
// Fixes the bug that caused the slot hightlight to render opaque. I don't know why it works, it just works!
GlStateManager.disableBlend();
GlStateManager.enableAlpha();
GlStateManager.popAttrib();
}
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){
this.fontRendererObj.drawString(this.arcaneWorkbenchInventory.hasCustomName() ? this.arcaneWorkbenchInventory.getName() : I18n.format(this.arcaneWorkbenchInventory.getName()), 8, 6, 4210752);
this.fontRendererObj.drawString(this.playerInventory.hasCustomName() ? this.playerInventory.getName() : I18n.format(this.playerInventory.getName()), 8, this.ySize - 96 + 2, 4210752);
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){
ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack();
this.fontRendererObj.drawStringWithShadow("\u00A7f" + wand.getDisplayName(), xSize + 6, 6, 0);
this.fontRendererObj.drawStringWithShadow("\u00A77" + I18n.format("container.wizardry:arcane_workbench.mana") + " " + (wand.getMaxDamage() - wand.getItemDamage()) + "/" + wand.getMaxDamage(), xSize + 6, 20, 0);
Spell[] spells = WandHelper.getSpells(wand);
int y = 34;
for(Spell spell : spells){
boolean discovered = true;
if(!this.mc.thePlayer.capabilities.isCreativeMode && WizardData.get(this.mc.thePlayer) != null){
discovered = WizardData.get(this.mc.thePlayer).hasSpellBeenDiscovered(spell);
}
if(discovered){
this.fontRendererObj.drawStringWithShadow(spell.getDisplayNameWithFormatting(), xSize + 16, y, 0);
}else{
this.mc.standardGalacticFontRenderer.drawStringWithShadow("\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.theWorld), xSize + 16, y, 0);
}
y += 10;
}
if(WandHelper.getTotalUpgrades(wand) > 0){
this.fontRendererObj.drawStringWithShadow("\u00A7f" + I18n.format("container.wizardry:arcane_workbench.upgrades"), xSize + 6, y + 6, 0);
int x = 0;
y = 50 + spells.length*10;
// Wand upgrade tooltips
for(Item item : WandHelper.getSpecialUpgrades()){
int level = WandHelper.getUpgradeLevel(wand, item);
if(level > 0){
// The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is
// relative to the GUI but the POINT isn't.
if(isPointInRegion(xSize + 6 + x, y, 16, 16, mouseX, mouseY)){
ItemStack stack = new ItemStack(item, level);
this.renderToolTip(stack, mouseX - guiLeft, mouseY - guiTop);
}
x += 18;
}
}
}
}
}
@Override
public void initGui(){
this.mc.thePlayer.openContainer = this.inventorySlots;
this.guiLeft = (this.width - this.xSize) / 2;
this.guiTop = (this.height - this.ySize) / 2;
Keyboard.enableRepeatEvents(true);
this.buttonList.clear();
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width/2 + 48, this.height/2 + 3));
}
@Override
public void onGuiClosed(){
super.onGuiClosed();
Keyboard.enableRepeatEvents(false);
}
@Override
protected void actionPerformed(GuiButton button){
if(button.enabled){
if(button.id == 0){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.APPLY_BUTTON);
WizardryPacketHandler.net.sendToServer(msg);
}
}
}
}
@@ -0,0 +1,41 @@
package electroblob.wizardry.client;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.resources.I18n;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
class GuiButtonApply extends GuiButton {
public GuiButtonApply(int id, int x, int y){
super(id, x, y, 32, 16, I18n.format("container.wizardry:arcane_workbench.apply"));
}
@Override
public void drawButton(Minecraft minecraft, int mouseX, int mouseY){
// Whether the button is highlighted
this.hovered = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height;
int k = 36;
int l = 220;
int colour = 14737632;
if(this.enabled){
if(this.hovered){
k += this.width*2;
colour = 16777120;
}
}else{
k += this.width;
colour = 10526880;
}
WizardryUtilities.drawTexturedRect(this.xPosition, this.yPosition, k, l, this.width, this.height, 256, 256);
this.drawCenteredString(minecraft.fontRendererObj, this.displayString, this.xPosition + this.width / 2, this.yPosition + (this.height - 8) / 2, colour);
}
}
@@ -0,0 +1,23 @@
package electroblob.wizardry.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
class GuiButtonInvisible extends GuiButton {
public GuiButtonInvisible(int id, int x, int y, int width, int height){
super(id, x, y, width, height, "");
}
/**
* Draws this button to the screen.
*/
public void drawButton(Minecraft par1Minecraft, int par2, int par3){
this.hovered = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height;
}
}
@@ -0,0 +1,52 @@
package electroblob.wizardry.client;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
class GuiButtonTurnPage extends GuiButton {
/** True for pointing right (next page), false for pointing left (previous page). */
private final boolean nextPage;
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png");
public GuiButtonTurnPage(int id, int x, int y, boolean isNextPage)
{
super(id, x, y, 23, 13, "");
this.nextPage = isNextPage;
}
/**
* Draws this button to the screen.
*/
public void drawButton(Minecraft par1Minecraft, int par2, int par3)
{
if (this.visible)
{
boolean flag = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height;
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
par1Minecraft.getTextureManager().bindTexture(texture);
int k = 0;
int l = 192;
if (flag)
{
k += 23;
}
if (!this.nextPage)
{
l += 13;
}
WizardryUtilities.drawTexturedRect(this.xPosition, this.yPosition, k, l, 23, 13, 288, 256);
}
}
}
@@ -0,0 +1,80 @@
package electroblob.wizardry.client;
import java.util.ArrayList;
import java.util.List;
import electroblob.wizardry.Settings;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
import net.minecraftforge.common.config.ConfigElement;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.client.config.DummyConfigElement.DummyCategoryElement;
import net.minecraftforge.fml.client.config.GuiConfig;
import net.minecraftforge.fml.client.config.GuiConfigEntries;
import net.minecraftforge.fml.client.config.GuiConfigEntries.CategoryEntry;
import net.minecraftforge.fml.client.config.IConfigElement;
public class GuiConfigWizardry extends GuiConfig {
public GuiConfigWizardry(GuiScreen parent){
super(parent, getConfigEntries(), Wizardry.MODID, false, false, Wizardry.NAME + " - " + I18n.format("config.wizardry.title.general"));
//this.titleLine2 = "File location: " + Wizardry.config.getConfigFile().getAbsolutePath();
}
private static List<IConfigElement> getConfigEntries(){
List<IConfigElement> configList = new ArrayList<IConfigElement>(1);
configList.add(new DummyCategoryElement("spellsConfig", "config.wizardry.category." + Settings.SPELLS_CATEGORY, SpellsCategory.class));
configList.add(new DummyCategoryElement("resistancesConfig", "config.wizardry.category." + Settings.RESISTANCES_CATEGORY, ResistancesCategory.class));
configList.addAll(new ConfigElement(Wizardry.settings.getConfigCategory(Configuration.CATEGORY_GENERAL)).getChildElements());
return configList;
}
/** Spells category of the config gui. This adds a button which opens up the spells category config. */
public static class SpellsCategory extends CategoryEntry
{
public SpellsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
{
super(owningScreen, owningEntryList, prop);
}
@Override
protected GuiScreen buildChildScreen()
{
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed.
// The parent GuiConfig object's entryList will also be refreshed to reflect the changes.
GuiConfig spellsMenu = new GuiConfig(this.owningScreen,
(new ConfigElement(Wizardry.settings.getConfigCategory(Settings.SPELLS_CATEGORY))).getChildElements(),
this.owningScreen.modID, Settings.SPELLS_CATEGORY, false, false,
Wizardry.NAME + " - " + I18n.format("config.wizardry.title." + Settings.SPELLS_CATEGORY));
spellsMenu.titleLine2 = I18n.format("config.wizardry.subtitle." + Settings.SPELLS_CATEGORY);
return spellsMenu;
}
}
/** Resistances category of the config gui. */
public static class ResistancesCategory extends CategoryEntry
{
public ResistancesCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
{
super(owningScreen, owningEntryList, prop);
}
@Override
protected GuiScreen buildChildScreen()
{
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed.
// The parent GuiConfig object's entryList will also be refreshed to reflect the changes.
GuiConfig idsMenu = new GuiConfig(this.owningScreen,
(new ConfigElement(Wizardry.settings.getConfigCategory(Settings.RESISTANCES_CATEGORY))).getChildElements(),
this.owningScreen.modID, Settings.RESISTANCES_CATEGORY, false, false,
Wizardry.NAME + " - " + I18n.format("config.wizardry.title." + Settings.RESISTANCES_CATEGORY));
idsMenu.titleLine2 = I18n.format("config.wizardry.subtitle." + Settings.RESISTANCES_CATEGORY);
return idsMenu;
}
}
}
@@ -0,0 +1,39 @@
package electroblob.wizardry.client;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.ContainerWorkbench;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
/** Crafting table GUI that doesn't require a crafting table container object. */
public class GuiPortableCrafting extends GuiContainer {
private static final ResourceLocation craftingTableGuiTextures = new ResourceLocation("textures/gui/container/crafting_table.png");
public GuiPortableCrafting(InventoryPlayer p_i1084_1_, World p_i1084_2_, BlockPos pos)
{
super(new ContainerWorkbench(p_i1084_1_, p_i1084_2_, pos));
}
/**
* Draw the foreground layer for the GuiContainer (everything in front of the items)
*/
protected void drawGuiContainerForegroundLayer(int p_146979_1_, int p_146979_2_)
{
this.fontRendererObj.drawString(I18n.format("container.crafting"), 28, 6, 4210752);
this.fontRendererObj.drawString(I18n.format("container.inventory"), 8, this.ySize - 96 + 2, 4210752);
}
protected void drawGuiContainerBackgroundLayer(float p_146976_1_, int p_146976_2_, int p_146976_3_)
{
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.getTextureManager().bindTexture(craftingTableGuiTextures);
int k = (this.width - this.xSize) / 2;
int l = (this.height - this.ySize) / 2;
this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.ySize);
}
}
@@ -0,0 +1,127 @@
package electroblob.wizardry.client;
import org.lwjgl.input.Keyboard;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation;
public class GuiSpellBook extends GuiScreen {
private int xSize, ySize;
private Spell spell;
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/spellbook.png");
public GuiSpellBook(Spell spell) {
super();
xSize = 288;
ySize = 180;
this.spell = spell;
}
/**
* Draws the screen and all the components in it.
*/
public void drawScreen(int par1, int par2, float par3) {
int xPos = this.width/2 - xSize/2;
int yPos = this.height/2 - this.ySize/2;
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
boolean discovered = true;
if(Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null
&& !WizardData.get(player).hasSpellBeenDiscovered(spell)){
discovered = false;
}
// Draws spell illustration on opposite page, underneath the book so it shows through the hole.
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
WizardryUtilities.drawTexturedRect(xPos + 145, yPos + 20, 0, 0, 128, 128, 128, 128);
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
WizardryUtilities.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
super.drawScreen(par1, par2, par3);
if(discovered){
this.fontRendererObj.drawString(spell.getDisplayName(), xPos+17, yPos+14, 0);
this.fontRendererObj.drawString(spell.type.getDisplayName(), xPos+17, yPos+25, 0x777777);
}else{
this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(spell, player.worldObj), xPos+17, yPos+14, 0);
this.mc.standardGalacticFontRenderer.drawString(spell.type.getDisplayName(), xPos+17, yPos+25, 0x777777);
}
this.fontRendererObj.drawString("-------------------", xPos+17, yPos+34, 0);
if(spell.tier == Tier.BASIC){
// Basic is usually white but this doesn't show up.
this.fontRendererObj.drawString("Tier: \u00A77" + Tier.BASIC.getDisplayName(), xPos+17, yPos+44, 0);
}else{
this.fontRendererObj.drawString("Tier: " + spell.tier.getDisplayNameWithFormatting(), xPos+17, yPos+44, 0);
}
String element = "Element: " + spell.element.getFormattingCode() + spell.element.getDisplayName();
if(!discovered) element = "Element: ?";
this.fontRendererObj.drawString(element, xPos+17, yPos+56, 0);
String manaCost = "Mana Cost: " + spell.cost;
if(spell.isContinuous) manaCost = "Mana Cost: " + spell.cost + "/second";
if(!discovered) manaCost = "Mana Cost: ?";
this.fontRendererObj.drawString(manaCost, xPos+17, yPos+68, 0);
if(discovered){
this.fontRendererObj.drawSplitString(spell.getDescription(), xPos+17, yPos+82, 118, 0);
}else{
this.mc.standardGalacticFontRenderer.drawSplitString(SpellGlyphData.getGlyphDescription(spell, player.worldObj), xPos+17, yPos+82, 118, 0);
}
/*
// Word wrapping
int charNumber = 0;
int lineNumber = 0;
while(charNumber < spell.desc.length()){
int lineLength = 0;
String line;
if(spell.desc.length() - charNumber > 22){
for(int i = charNumber; i < charNumber+23; i++){
if(spell.desc.charAt(i) == ' '){
lineLength = i - charNumber;
}
}
line = spell.desc.substring(charNumber, charNumber + lineLength);
}else{
line = spell.desc.substring(charNumber, spell.desc.length());
charNumber = spell.desc.length();
}
this.fontRendererObj.drawString("\u00A7o" + line, xPos+17, yPos+82+10*lineNumber, 0);
charNumber+=(lineLength+1);
lineNumber++;
}
*/
}
public void initGui()
{
super.initGui();
Keyboard.enableRepeatEvents(true);
this.buttonList.clear();
}
public void onGuiClosed()
{
super.onGuiClosed();
Keyboard.enableRepeatEvents(false);
}
}
@@ -0,0 +1,155 @@
package electroblob.wizardry.client;
import java.util.List;
import electroblob.wizardry.Settings.GuiPosition;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
public class GuiSpellDisplay extends Gui {
private Minecraft mc;
private static final ResourceLocation hudTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_hud.png");
public GuiSpellDisplay(Minecraft par1Minecraft) {
super();
this.mc = par1Minecraft;
}
@SubscribeEvent
public void draw(RenderGameOverlayEvent event){
EntityPlayer player = this.mc.thePlayer;
// If the player has a wand in each hand, only displays for the one in the main hand.
ItemStack wand = player.getHeldItemMainhand();
if(wand == null || !(wand.getItem() instanceof ItemWand)){
wand = player.getHeldItemOffhand();
// If the player isn't holding a wand, then nothing else needs to be done.
if(wand == null || !(wand.getItem() instanceof ItemWand)) return;
}
int width = event.getResolution().getScaledWidth();
int height = event.getResolution().getScaledHeight();
Spell spell = WandHelper.getCurrentSpell(wand);
int cooldown = WandHelper.getCurrentCooldown(wand);
float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(wand, WizardryItems.cooldown_upgrade)*Constants.COOLDOWN_REDUCTION_PER_LEVEL;
if(player.isPotionActive(WizardryPotions.font_of_mana)){
// Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously
cooldownMultiplier /= 2 + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier();
}
// Coordinates of the top left corner of the HUD.
int left = 0;
int top = 0;
boolean mirror = false;
if(Wizardry.settings.spellHUDPosition == GuiPosition.BOTTOM_LEFT){
left = 0;
top = height-36;
}else if(Wizardry.settings.spellHUDPosition == GuiPosition.TOP_LEFT){
left = 0;
top = 0;
}else if(Wizardry.settings.spellHUDPosition == GuiPosition.TOP_RIGHT){
left = width-128;
top = 0;
mirror = true;
}else if(Wizardry.settings.spellHUDPosition == GuiPosition.BOTTOM_RIGHT){
left = width-128;
top = height-36;
mirror = true;
}
boolean discovered = true;
if(!player.capabilities.isCreativeMode && WizardData.get(player) != null){
discovered = WizardData.get(player).hasSpellBeenDiscovered(spell);
}
if(event.getType() == RenderGameOverlayEvent.ElementType.TEXT){
// Makes spells greyed out if they are in cooldown or if the player has the arcane jammer effect
String colour = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.element.getFormattingCode();
if(!discovered) colour = "\u00A79";
String spellName = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.worldObj);
FontRenderer font = discovered ? this.mc.fontRendererObj : this.mc.standardGalacticFontRenderer;
int maxWidth = 90;
if(font.getStringWidth(spellName) <= maxWidth){
// Single line is rendered more centrally
font.drawStringWithShadow(colour + spellName, mirror ? left+5 : left+41, top+13, 0xffffffff);
}else{
int lineNumber = 0;
List<String> lines = font.listFormattedStringToWidth(spellName, maxWidth);
for(Object line : lines){
if(line instanceof String){
font.drawStringWithShadow(colour + (String)line, mirror ? left+5 : left+41, top+6 + 11*lineNumber, 0xffffffff);
}
lineNumber++;
}
}
}else if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR){
GlStateManager.pushAttrib();
GlStateManager.enableBlend();
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
GlStateManager.color(1, 1, 1);
this.mc.renderEngine.bindTexture(hudTexture);
// Background of spell hud
this.drawTexturedModalRect(left, top, 0, mirror ? 36 : 0, 128, 36);
// Cooldown bar
if(cooldown > 0){
this.drawTexturedModalRect(mirror ? left+5 : left+41, height-8, 128, 6, 82, 6);
int l = (int)(((double)(spell.cooldown * cooldownMultiplier - cooldown)
/ (double)(spell.cooldown * cooldownMultiplier)) * 82);
this.drawTexturedModalRect(mirror ? left+5 : left+41, height-8, 128, 0, l, 6);
}
// Spell illustration
this.mc.renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
WizardryUtilities.drawTexturedRect(mirror ? left+94 : left+2, top+2, 0, 0, 32, 32, 32, 32);
GlStateManager.popAttrib();
}
}
}
@@ -0,0 +1,809 @@
package electroblob.wizardry.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.Charsets;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
public class GuiWizardHandbook extends GuiScreen {
private int xSize, ySize;
private int pageNumber = 0;
private static final int PAGE_WIDTH = 120;
/** The integer colour for black passed into the font renderer methods. This used to be 0 but that's now white
* for some reason, so I've made a it a constant in case it changes again. */
// I think this is actually ever-so-slightly lighter than pure black, but the difference is unnoticeable.
private static final int BLACK = 1;
public static final ResourceLocation regularHandbook = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png");
public static final ResourceLocation ore = new ResourceLocation(Wizardry.MODID, "textures/gui/ore_picture.png");
public static final ResourceLocation crystal = new ResourceLocation(Wizardry.MODID, "textures/items/magic_crystal.png");
public static final ResourceLocation workbenchGui = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png");
public static final ResourceLocation craftingGrids = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook_recipes.png");
private ArrayList<ArrayList<String>> text;
private ArrayList<Section> sections;
private int guiPage, imagePage;
public GuiWizardHandbook() {
super();
xSize = 288;
ySize = 180;
}
@Override
public void drawScreen(int mouseX, int mouseY, float par3){
int xPos = this.width/2 - xSize/2;
int yPos = this.height/2 - this.ySize/2;
// Tests for crafting recipes section
if(pageNumber >= (sections.get(sections.size()-1).pageNumber-1)/2 && pageNumber < (sections.get(sections.size()-1).pageNumber-1)/2 + 4){
Minecraft.getMinecraft().renderEngine.bindTexture(craftingGrids);
}else{
Minecraft.getMinecraft().renderEngine.bindTexture(regularHandbook);
}
WizardryUtilities.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
// Arcane workbench gui picture
if(pageNumber == (this.guiPage-1)/2){
Minecraft.getMinecraft().renderEngine.bindTexture(workbenchGui);
this.drawTexturedModalRect(this.guiPage % 2 == 1 ? xPos + 17 : this.width/2 + 7, yPos + 14, 28, 12, 120, 118);
}
// Magic crystal and crystal ore images
if(pageNumber == (this.imagePage-1)/2){
Minecraft.getMinecraft().renderEngine.bindTexture(ore);
WizardryUtilities.drawTexturedRect(this.imagePage % 2 == 1 ? xPos + 17 : this.width/2 + 7, yPos + 80, 0, 0, 64, 64, 64, 64);
Minecraft.getMinecraft().renderEngine.bindTexture(crystal);
drawTexturedStretchedRect(this.imagePage % 2 == 1 ? xPos + 17 + 64 : this.width/2 + 7 + 62, yPos + 80, 0, 0, 64, 64, 1, 1);
}
this.fontRendererObj.drawString("" + (pageNumber*2 + 1), xPos + xSize/4 - 3, yPos + ySize - 20, 0);
this.fontRendererObj.drawString("" + (pageNumber*2 + 2), xPos + 3*xSize/4 - 5, yPos + ySize - 20, 0);
super.drawScreen(mouseX, mouseY, par3);
int lineNumber = 0;
if(pageNumber == 1){
for(Section s : sections){
s.drawContents();
}
}else{
for(Section s : sections){
s.hideButton();
}
}
for(String paragraph : text.get(pageNumber*2)){
this.fontRendererObj.drawSplitString(paragraph, xPos + 17, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, PAGE_WIDTH, BLACK);
List<String> list = new ArrayList<String>(this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH));
lineNumber += list.size();
}
lineNumber = 0;
// Prevents crash when the last page is blank (and hence is not in the list of pages)
if(text.size() > pageNumber*2 + 1){
for(String paragraph : text.get(pageNumber*2 + 1)){
// First page is centred
if(pageNumber == 0){
int startX = this.width/2 + 7 + PAGE_WIDTH/2 - this.fontRendererObj.getStringWidth(paragraph)/2;
this.fontRendererObj.drawSplitString(paragraph, startX, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, PAGE_WIDTH, BLACK);
}else{
this.fontRendererObj.drawSplitString(paragraph, this.width/2 + 7, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, PAGE_WIDTH, BLACK);
}
List<String> list = new ArrayList<String>(this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH));
lineNumber += list.size();
}
}
ItemStack[][] craftingGrid;
ItemStack craftingResult;
// Tooltips are rendered after recipes to prevent tooltips on the left appearing behind items on the right.
if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.GOLD_NUGGET);
craftingGrid[1][0] = new ItemStack(Blocks.CARPET, 1, 10);
craftingGrid[2][0] = new ItemStack(Items.GOLD_NUGGET);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Blocks.LAPIS_BLOCK);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][2] = new ItemStack(Blocks.STONE);
craftingGrid[1][2] = new ItemStack(Blocks.STONE);
craftingGrid[2][2] = new ItemStack(Blocks.STONE);
craftingResult = new ItemStack(WizardryBlocks.arcane_workbench);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.STICK);
craftingGrid[0][2] = new ItemStack(Items.GOLD_NUGGET);
craftingResult = new ItemStack(WizardryItems.magic_wand);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.BOOK);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.spell_book, 1, 1);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.BOOK);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.wizard_handbook);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 1){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryBlocks.crystal_flower);
craftingResult = new ItemStack(WizardryItems.magic_crystal, 2);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.mana_flask);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Blocks.STONE);
craftingGrid[0][1] = new ItemStack(Blocks.STONE);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(Blocks.STONE);
craftingGrid[2][1] = new ItemStack(Blocks.STONE);
craftingResult = new ItemStack(WizardryBlocks.transportation_stone, 2);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingGrid[0][1] = new ItemStack(Items.STRING);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(Items.STRING);
craftingGrid[2][1] = new ItemStack(Items.STRING);
craftingResult = new ItemStack(WizardryItems.magic_silk, 2);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_hat);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_robe);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_leggings);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_boots);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 3){
if(Wizardry.settings.useAlternateScrollRecipe){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.PAPER);
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.blank_scroll);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}else{
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.PAPER);
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingResult = new ItemStack(WizardryItems.blank_scroll);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.firebombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.BLAZE_POWDER);
craftingGrid[1][0] = new ItemStack(Items.BLAZE_POWDER);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.firebomb, 3);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.poisonBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.SPIDER_EYE);
craftingGrid[1][0] = new ItemStack(Items.SPIDER_EYE);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.poison_bomb, 3);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.smokeBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.COAL);
craftingGrid[1][0] = new ItemStack(Items.COAL);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.smoke_bomb, 3);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
}
if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.GOLD_NUGGET);
craftingGrid[1][0] = new ItemStack(Blocks.CARPET, 1, 10);
craftingGrid[2][0] = new ItemStack(Items.GOLD_NUGGET);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Blocks.LAPIS_BLOCK);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][2] = new ItemStack(Blocks.STONE);
craftingGrid[1][2] = new ItemStack(Blocks.STONE);
craftingGrid[2][2] = new ItemStack(Blocks.STONE);
craftingResult = new ItemStack(WizardryBlocks.arcane_workbench);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.STICK);
craftingGrid[0][2] = new ItemStack(Items.GOLD_NUGGET);
craftingResult = new ItemStack(WizardryItems.magic_wand);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.BOOK);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.spell_book, 1, 1);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.BOOK);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.wizard_handbook);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 1){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryBlocks.crystal_flower);
craftingResult = new ItemStack(WizardryItems.magic_crystal, 2);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.mana_flask);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Blocks.STONE);
craftingGrid[0][1] = new ItemStack(Blocks.STONE);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(Blocks.STONE);
craftingGrid[2][1] = new ItemStack(Blocks.STONE);
craftingResult = new ItemStack(WizardryBlocks.transportation_stone, 2);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingGrid[0][1] = new ItemStack(Items.STRING);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(Items.STRING);
craftingGrid[2][1] = new ItemStack(Items.STRING);
craftingResult = new ItemStack(WizardryItems.magic_silk, 2);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_hat);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_robe);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_leggings);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_boots);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 3){
if(Wizardry.settings.useAlternateScrollRecipe){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.PAPER);
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.blank_scroll);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}else{
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.PAPER);
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingResult = new ItemStack(WizardryItems.blank_scroll);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.firebombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.BLAZE_POWDER);
craftingGrid[1][0] = new ItemStack(Items.BLAZE_POWDER);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.firebomb, 3);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.poisonBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.SPIDER_EYE);
craftingGrid[1][0] = new ItemStack(Items.SPIDER_EYE);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.poison_bomb, 3);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.smokeBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.COAL);
craftingGrid[1][0] = new ItemStack(Items.COAL);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.smoke_bomb, 3);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
}
}
private void renderCraftingRecipe(int xPos, int yPos, int mouseX, int mouseY, ItemStack[][] craftingGrid, ItemStack craftingResult) {
GlStateManager.pushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.disableLighting();
GlStateManager.enableRescaleNormal();
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
GlStateManager.enableLighting();
itemRender.zLevel = 100.0F;
for(int i=0; i<craftingGrid.length; i++){
for(int j=0; j<craftingGrid[i].length; j++){
if(craftingGrid[i][j] != null){
itemRender.renderItemAndEffectIntoGUI(craftingGrid[i][j], xPos + 18*i, yPos + 18*j);
itemRender.renderItemOverlays(this.fontRendererObj, craftingGrid[i][j], xPos + 18*i, yPos + 18*j);
}
}
}
if(craftingResult != null){
itemRender.renderItemAndEffectIntoGUI(craftingResult, xPos + 86, yPos + 18);
itemRender.renderItemOverlays(this.fontRendererObj, craftingResult, xPos + 86, yPos + 18);
}
GlStateManager.popMatrix();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
}
private void renderCraftingTooltips(int xPos, int yPos, int mouseX, int mouseY, ItemStack[][] craftingGrid, ItemStack craftingResult) {
int guiLeft = this.width/2 - xSize/2;
int guiTop = this.height/2 - this.ySize/2;
GlStateManager.pushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.disableLighting();
GlStateManager.enableRescaleNormal();
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
itemRender.zLevel = 0.0F;
GlStateManager.disableLighting();
for(int i=0; i<craftingGrid.length; i++){
for(int j=0; j<craftingGrid[i].length; j++){
if(craftingGrid[i][j] != null && isPointInRegion(xPos + 18*i, yPos + 18*j, 16, 16, mouseX + guiLeft, mouseY + guiTop)){
this.renderToolTip(craftingGrid[i][j], mouseX, mouseY);
}
}
}
if(craftingResult != null && isPointInRegion(xPos + 86, yPos + 18, 16, 16, mouseX + guiLeft, mouseY + guiTop)){
this.renderToolTip(craftingResult, mouseX, mouseY);
}
GlStateManager.popMatrix();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
}
@Override
public void initGui(){
super.initGui();
Keyboard.enableRepeatEvents(true);
int nextButtonId = 0;
this.buttonList.clear();
this.buttonList.add(new GuiButtonTurnPage(nextButtonId++, this.width/2 + this.xSize/2 - 22 - 23, this.height/2 + this.ySize/2 - 10 - 13, true));
this.buttonList.add(new GuiButtonTurnPage(nextButtonId++, this.width/2 - this.xSize/2 + 21, this.height/2 + this.ySize/2 - 10 - 13, false));
text = new ArrayList<ArrayList<String>>(1);
sections = new ArrayList<Section>(1);
BufferedReader bufferedreader = null;
String textFilepath = "wizardry:texts/handbook_" + Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".txt";
try {
bufferedreader = new BufferedReader(new InputStreamReader(this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), Charsets.UTF_8));
} catch (IOException e){
Wizardry.logger.info("Wizard handbook text file missing for the current language. Using default (English - US) instead.");
textFilepath = "wizardry:texts/handbook_en_US.txt";
try {
bufferedreader = new BufferedReader(new InputStreamReader(this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), Charsets.UTF_8));
} catch (IOException x){
Wizardry.logger.error("Couldn't find file: wizardry:assets/texts/handbook_en_US.txt. The file may be"
+ "missing; please try re-downloading and reinstalling Wizardry.", x);
}
}
if(bufferedreader != null){
try {
String paragraph = bufferedreader.readLine();
ArrayList<String> page = new ArrayList<String>(1);
int linesPerPage = 16;
int lineNumber = 0;
while(paragraph != null){
//System.out.println(paragraph);
if(paragraph.contains("PAGEBREAK") || lineNumber >= linesPerPage){
text.add(page);
page = new ArrayList<String>(1);
lineNumber = 0;
if(paragraph.contains("PAGEBREAK")) paragraph = bufferedreader.readLine();
}else if(paragraph.contains("LINEBREAK")){
lineNumber++;
page.add("");
paragraph = bufferedreader.readLine();
}else if(paragraph.contains("SECTION")){
sections.add(new Section(paragraph.replace("SECTION ", ""), text.size() + 1, this.width/2 + 7,
this.height/2 - this.ySize/2 + 14 + (sections.size()+2)*this.fontRendererObj.FONT_HEIGHT, nextButtonId++));
paragraph = bufferedreader.readLine();
}else if(paragraph.contains("IMAGE")){
if(paragraph.contains("WORKBENCH")){
this.guiPage = text.size() + 1;
}else if(paragraph.contains("CRYSTAL")){
this.imagePage = text.size() + 1;
}
paragraph = bufferedreader.readLine();
}else{
paragraph = paragraph.replaceAll("NEXT_SPELL_KEY", Keyboard.getKeyName(ClientProxy.NEXT_SPELL.getKeyCode()));
paragraph = paragraph.replaceAll("PREVIOUS_SPELL_KEY", Keyboard.getKeyName(ClientProxy.PREVIOUS_SPELL.getKeyCode()));
paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL_MINUS_30", "" + (Constants.MANA_PER_CRYSTAL - 30));
paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL", "" + Constants.MANA_PER_CRYSTAL);
paragraph = paragraph.replaceAll("BASIC_MAX_CHARGE", "" + Tier.BASIC.maxCharge);
paragraph = paragraph.replaceAll("APPRENTICE_MAX_CHARGE", "" + Tier.APPRENTICE.maxCharge);
paragraph = paragraph.replaceAll("ADVANCED_MAX_CHARGE", "" + Tier.ADVANCED.maxCharge);
paragraph = paragraph.replaceAll("MASTER_MAX_CHARGE", "" + Tier.MASTER.maxCharge);
paragraph = paragraph.replaceAll("BASIC_COLOUR", "\u00A77");
paragraph = paragraph.replaceAll("APPRENTICE_COLOUR", Tier.APPRENTICE.getFormattingCode());
paragraph = paragraph.replaceAll("ADVANCED_COLOUR", Tier.ADVANCED.getFormattingCode());
paragraph = paragraph.replaceAll("MASTER_COLOUR", Tier.MASTER.getFormattingCode());
paragraph = paragraph.replaceAll("FIRE_COLOUR", Element.FIRE.getFormattingCode());
paragraph = paragraph.replaceAll("ICE_COLOUR", Element.ICE.getFormattingCode());
paragraph = paragraph.replaceAll("LIGHTNING_COLOUR", Element.LIGHTNING.getFormattingCode());
paragraph = paragraph.replaceAll("NECROMANCY_COLOUR", Element.NECROMANCY.getFormattingCode());
paragraph = paragraph.replaceAll("EARTH_COLOUR", Element.EARTH.getFormattingCode());
paragraph = paragraph.replaceAll("SORCERY_COLOUR", Element.SORCERY.getFormattingCode());
paragraph = paragraph.replaceAll("HEALING_COLOUR", Element.HEALING.getFormattingCode());
paragraph = paragraph.replaceAll("RESET_COLOUR", "\u00A70");
paragraph = paragraph.replaceAll("VERSION", Wizardry.VERSION);
int linesInParagraph = this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH).size();
// Ignores empty lines at the top of a page.
if(paragraph.isEmpty() && lineNumber == 0){
paragraph = bufferedreader.readLine();
// Normal paragraph, all on one page
}else if(lineNumber + linesInParagraph <= linesPerPage){
page.add(paragraph);
lineNumber += linesInParagraph;
paragraph = bufferedreader.readLine();
// Paragraphs split across two pages (or more?)
}else{
int linesInFirstPart = linesPerPage - lineNumber;
String paragraphFirstPart = "";
String paragraphLastPart = "";
int i = 0;
List<String> strings = this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH);
for(Object s : strings){
if(i < linesInFirstPart){
paragraphFirstPart = paragraphFirstPart.concat((String)s + " ");
}else{
paragraphLastPart = paragraphLastPart.concat((String)s + " ");
}
i++;
}
//System.out.println("Paragraph crosses page boundary; string split into: \"" + paragraphFirstPart + "\" and \"" + paragraphLastPart + "\"");
page.add(paragraphFirstPart);
lineNumber += linesInFirstPart;
paragraph = paragraphLastPart;
}
}
}
text.add(page);
} catch (IOException e){
Wizardry.logger.error("Something went wrong reading file: " + textFilepath + ". The file may be damaged;"
+ "please try re-downloading and reinstalling wizardry.", e);
}
}
}
private class Section {
/** The integer text colour used for the section when it is moused over. Currently orange. */
private static final int HIGHLIGHT_COLOUR = 0xdd4c1d;
String name;
int pageNumber;
int x, y;
int buttonId;
Section(String name, int pageNumber, int x, int y, int id){
this.name = name;
this.pageNumber = pageNumber;
this.x = x;
this.y = y;
this.buttonId = id;
GuiWizardHandbook.this.buttonList.add(new GuiButtonInvisible(id, x, y, GuiWizardHandbook.PAGE_WIDTH, GuiWizardHandbook.this.fontRendererObj.FONT_HEIGHT));
}
void hideButton(){
GuiWizardHandbook.this.buttonList.get(buttonId).visible = false;
}
void drawContents(){
GuiWizardHandbook.this.buttonList.get(buttonId).visible = true;
GuiWizardHandbook.this.fontRendererObj.drawString(name, x, y, GuiWizardHandbook.this.buttonList.get(buttonId).isMouseOver() ? HIGHLIGHT_COLOUR : BLACK);
int nameWidth = GuiWizardHandbook.this.fontRendererObj.getStringWidth(name);
String dotsAndNumber = " " + this.pageNumber;
while(GuiWizardHandbook.this.fontRendererObj.getStringWidth(dotsAndNumber) < GuiWizardHandbook.PAGE_WIDTH - nameWidth - 2){
dotsAndNumber = "." + dotsAndNumber;
}
GuiWizardHandbook.this.fontRendererObj.drawString(dotsAndNumber, x + GuiWizardHandbook.PAGE_WIDTH - GuiWizardHandbook.this.fontRendererObj.getStringWidth(dotsAndNumber), y, BLACK);
}
}
@Override
public void onGuiClosed()
{
super.onGuiClosed();
Keyboard.enableRepeatEvents(false);
}
/**
* Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e).
*/
@Override
protected void actionPerformed(GuiButton par1GuiButton){
if(par1GuiButton.enabled){
if(par1GuiButton.id == 0){
if(pageNumber < (text.size()-1)/2) pageNumber++;
}else if(par1GuiButton.id == 1){
if(pageNumber > 0) pageNumber--;
}else{
if(pageNumber == 1) pageNumber = (sections.get(par1GuiButton.id - 2).pageNumber-1)/2;
}
}
}
/**
* Args: left, top, width, height, pointX, pointY. Note: left, top are local to Gui, pointX, pointY are local to
* screen
*/
protected boolean isPointInRegion(int par1, int par2, int par3, int par4, int par5, int par6)
{
int k1 = this.width/2 - xSize/2;
int l1 = this.height/2 - this.ySize/2;
par5 -= k1;
par6 -= l1;
return par5 >= par1 - 1 && par5 < par1 + par3 + 1 && par6 >= par2 - 1 && par6 < par2 + par4 + 1;
}
/**
* Draws a textured rectangle, stretching the section of the image to fit the size given.
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted, expressed as a fraction of the image width
* @param v The y position of the top left corner of the section of the image wanted, expressed as a fraction of the image width
* @param finalWidth The width as rendered
* @param finalHeight The height as rendered
* @param width The width of the section, expressed as a fraction of the image width
* @param height The height of the section, expressed as a fraction of the image width
*/
public static void drawTexturedStretchedRect(int x, int y, int u, int v, int finalWidth, int finalHeight, int width, int height){
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos((x), y + finalHeight, 0).tex(u, v + height).endVertex();
buffer.pos(x + finalWidth, y + finalHeight, 0).tex(u + width, v + height).endVertex();
buffer.pos(x + finalWidth, (y), 0).tex(u + width, v).endVertex();
buffer.pos((x), (y), 0).tex(u, v).endVertex();
tessellator.draw();
}
}
@@ -0,0 +1,94 @@
package electroblob.wizardry.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
/** Font renderer that renders parts of strings surrounded by '#' (without quotes) in the SGA instead of normal text.
* @since Wizardry 1.1 */
@SideOnly(Side.CLIENT)
public class MixedFontRenderer extends FontRenderer {
public MixedFontRenderer(GameSettings p_i1035_1_, ResourceLocation p_i1035_2_, TextureManager p_i1035_3_,
boolean p_i1035_4_) {
super(p_i1035_1_, p_i1035_2_, p_i1035_3_, p_i1035_4_);
}
@Override
public int drawString(String string, float x, float y, int colour, boolean shadow){
int l = 0;
boolean sga = false;
while(string.indexOf('#') > -1){
String section = string.substring(0, string.indexOf('#'));
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(section, x, y, colour, shadow);
x += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(section);
}else{
l += Minecraft.getMinecraft().fontRendererObj.drawString(section, x, y, colour, shadow);
x += Minecraft.getMinecraft().fontRendererObj.getStringWidth(section);
}
string = string.substring(string.indexOf('#') + 1);
sga = !sga;
}
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(string, x, y, colour, shadow);
}else{
l += Minecraft.getMinecraft().fontRendererObj.drawString(string, x, y, colour, shadow);
}
return l;
}
@Override
public int getStringWidth(String string){
int l = 0;
boolean sga = false;
while(string.indexOf('#') > -1){
String section = string.substring(0, string.indexOf('#'));
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(section);
}else{
l += Minecraft.getMinecraft().fontRendererObj.getStringWidth(section);
}
string = string.substring(string.indexOf('#') + 1);
sga = !sga;
}
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(string);
}else{
l += Minecraft.getMinecraft().fontRendererObj.getStringWidth(string);
}
return l;
}
// This doesn't work the same way yet
@Override
public void drawSplitString(String string, int x, int y, int width, int colour){
if(string.contains("#")){
Minecraft.getMinecraft().standardGalacticFontRenderer.drawSplitString(string.substring(1), x, y, width, colour);
}else{
Minecraft.getMinecraft().fontRendererObj.drawSplitString(string, x, y, width, colour);
}
}
}
@@ -0,0 +1,59 @@
package electroblob.wizardry.client;
import net.minecraft.client.audio.MovingSound;
import net.minecraft.entity.Entity;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// Copied from MovingSoundMinecart; if it ever breaks between updates take a look at that.
@SideOnly(Side.CLIENT)
public class MovingSoundEntity extends MovingSound
{
private final Entity source;
private float distance = 0.0F;
public MovingSoundEntity(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat)
{
// Uses BLOCKS because that's the closest thing to inanimate entities. Could use NEUTRAL like MovingSoundMinecart.
super(sound, SoundCategory.BLOCKS);
this.source = entity;
this.repeat = repeat;
this.volume = volume;
this.pitch = pitch;
this.repeatDelay = 0;
}
/**
* Updates the JList with a new model.
*/
@Override
public void update()
{
if (this.source.isDead && repeat)
{
this.donePlaying = true;
}
else
{
this.xPosF = (float)this.source.posX;
this.yPosF = (float)this.source.posY;
this.zPosF = (float)this.source.posZ;
float f = MathHelper.sqrt_double(this.source.motionX * this.source.motionX + this.source.motionY * this.source.motionY + this.source.motionZ * this.source.motionZ);
// Is this something to do with the Doppler effect?
if ((double)f >= 0.01D)
{
this.distance = MathHelper.clamp_float(this.distance + 0.0025F, 0.0F, 1.0F);
this.volume = 0.0F + MathHelper.clamp_float(f, 0.0F, 0.5F) * 0.7F;
}
else
{
//this.pitch = 0.0F;
//this.volume = 0.0F;
}
}
}
}
@@ -0,0 +1,752 @@
package electroblob.wizardry.client;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.item.ItemSpectralBow;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.spell.Flight;
import electroblob.wizardry.spell.ShadowWard;
import electroblob.wizardry.spell.Shield;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.RayTraceResult;
import net.minecraftforge.client.event.FOVUpdateEvent;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
/**
* Event handler responsible for all client-side only events, mostly rendering.
* @author Electroblob
* @since Wizardry 1.0
*/
@Mod.EventBusSubscriber(Side.CLIENT)
public final class WizardryClientEventHandler {
private static final ResourceLocation shieldTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/shield.png");
private static final ResourceLocation wingTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/wing.png");
private static final ResourceLocation shadowWardTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/shadow_ward.png");
private static final ResourceLocation sixthSenseTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/sixth_sense.png");
private static final ResourceLocation sixthSenseOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/sixth_sense_overlay.png");
private static final ResourceLocation frostOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/frost_overlay.png");
private static final ResourceLocation pointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/pointer.png");
private static final ResourceLocation targetPointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/target_pointer.png");
@SubscribeEvent
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_CRYSTAL);
event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_UPGRADE);
}
// Shift-scrolling to change spells
@SubscribeEvent
public static void onMouseEvent(MouseEvent event){
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
ItemStack wand = player.getHeldItemMainhand();
if(wand == null || !(wand.getItem() instanceof ItemWand)){
wand = player.getHeldItemOffhand();
// If the player isn't holding a wand, then nothing else needs to be done.
if(wand == null || !(wand.getItem() instanceof ItemWand)) return;
}
if(Minecraft.getMinecraft().inGameHasFocus && wand != null && event.getDwheel() != 0 && player.isSneaking()
&& Wizardry.settings.enableShiftScrolling){
event.setCanceled(true);
if(event.getDwheel() > 0){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
}else if(event.getDwheel() < 0){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
}
}
}
@SubscribeEvent
public static void onFOVUpdateEvent(FOVUpdateEvent event){
// Bow zoom. Taken directly from AbstractClientPlayer so it works exactly like vanilla.
if(event.getEntity().isHandActive() && event.getEntity().getActiveItemStack() != null
&& event.getEntity().getActiveItemStack().getItem() instanceof ItemSpectralBow){
int maxUseTicks = event.getEntity().getItemInUseMaxCount();
float maxUseSeconds = (float)maxUseTicks / 20.0F;
if(maxUseSeconds > 1.0F){
maxUseSeconds = 1.0F;
}else{
maxUseSeconds = maxUseSeconds * maxUseSeconds;
}
event.setNewfov(event.getFov() * 1.0F - maxUseSeconds * 0.15F);
}
}
// Third person
@SubscribeEvent
public static void onRenderPlayerEvent(RenderPlayerEvent.Post event){
renderShieldIfActive(event.getEntityPlayer());
renderWingsIfActive(event.getEntityPlayer(), event.getPartialRenderTick());
renderShadowWardIfActive(event.getEntityPlayer());
}
// First person
@SubscribeEvent
public static void onRenderWorldLastEvent(RenderWorldLastEvent event){
// Now only fires in first person.
if(Minecraft.getMinecraft().gameSettings.thirdPersonView == 0){
renderShieldFirstPerson(Minecraft.getMinecraft().thePlayer);
renderShadowWardFirstPerson(Minecraft.getMinecraft().thePlayer);
}
}
@SubscribeEvent
public static void onRenderLivingEvent(RenderLivingEvent.Post<EntityLivingBase> event){
/*
// Frost effect
if(event.entity.isPotionActive(Wizardry.frost)){
GlStateManager.pushMatrix();
GL11.glDisable(GL11.GL_TEXTURE_2D);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float someScalingFactor = 0.0625f;
float yaw = event.entity.prevRotationYaw;
//int brightness = event.entity.getBrightnessForRender(0);
//int j = brightness % 65536;
//int k = brightness / 65536;
//OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);
//GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.translate(event.x, event.y, event.z);
GlStateManager.rotate(-yaw + 180, 0F, 1F, 0F);
Render render = renderManager.getEntityRenderObject(event.entity);
RenderLiving renderliving = event.renderer;
// Reflection
try {
Timer timer = ReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "timer");
// Chooses the appropriate zombie model, normal or villager
// Fixed by moving before the model fields are accessed
if(render instanceof RenderZombie && event.entity instanceof EntityZombie){
// The second argument is never used...
ReflectionHelper.findMethod(RenderZombie.class, (RenderZombie)render, new String[]{"func_82427_a"}, EntityZombie.class)
.invoke(renderliving, (EntityZombie)event.entity);
}
// Turns out that java automatically infers the type parameter T in this method from the type
// I am assigning the returned value to. Neat!
ModelBase mainModel = ReflectionHelper.getPrivateValue(RenderLiving.class, renderliving, "mainModel");
mainModel.isRiding = event.entity.isRiding();
mainModel.isChild = event.entity.isChild();
GlStateManager.enableRescaleNormal();
GlStateManager.scale(-1.0F, -1.0F, 1.0F);
// The second argument is never used...
ReflectionHelper.findMethod(RenderLiving.class, renderliving, new String[]{"preRenderCallback"}, EntityLivingBase.class, float.class)
.invoke(renderliving, event.entity, someScalingFactor);
// Why is this -1.5f? No idea!
GlStateManager.translate(0, -1.5f, 0);
float f6 = event.entity.prevLimbSwingAmount + (event.entity.limbSwingAmount - event.entity.prevLimbSwingAmount) * timer.renderPartialTicks;
float f7 = event.entity.limbSwing - event.entity.limbSwingAmount * (1.0F - timer.renderPartialTicks);
if (event.entity.isChild())
{
f7 *= 3.0F;
}
if (f6 > 1.0F)
{
f6 = 1.0F;
}
mainModel.setLivingAnimations(event.entity, f7, f6, timer.renderPartialTicks);
GlStateManager.enableAlpha();
GlStateManager.color(0.5f, 0.7f, 1, 0.5f);
mainModel.render(event.entity, f7, f6, 0, 0, 0, someScalingFactor);
GL11.glDepthMask(true);
// 'Pokemon' exception handling... Because why not?!
} catch (Exception e) {
System.err.println("Something went very wrong! Error while rendering frost effect:");
e.printStackTrace();
}
GlStateManager.disableAlpha();
GlStateManager.disableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.disableRescaleNormal();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GlStateManager.popMatrix();
}
*/
Minecraft mc = Minecraft.getMinecraft();
WizardData properties = WizardData.get(mc.thePlayer);
RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.theWorld, mc.thePlayer, 16);
RenderManager renderManager = event.getRenderer().getRenderManager();
ItemStack wand = mc.thePlayer.getHeldItemMainhand();
if(wand == null || !(wand.getItem() instanceof ItemWand)){
wand = mc.thePlayer.getHeldItemOffhand();
}
// Target selection pointer
if(mc.thePlayer.isSneaking() && wand != null && wand.getItem() instanceof ItemWand && rayTrace != null
&& rayTrace.entityHit instanceof EntityLivingBase && rayTrace.entityHit == event.getEntity()
&& properties != null && properties.selectedMinion != null){
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
// Disabling depth test allows it to be seen through everything.
GL11.glDisable(GL11.GL_DEPTH_TEST);
GlStateManager.color(1, 1, 1, 1);
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ());
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
mc.renderEngine.bindTexture(targetPointerTexture);
buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex();
buffer.pos(0.2, 0.24, 0).tex(9f/16f, 0).endVertex();
buffer.pos(0.2, -0.24, 0).tex(9f/16f, 11f/16f).endVertex();
buffer.pos(-0.2, -0.24, 0).tex(0, 11f/16f).endVertex();
tessellator.draw();
GlStateManager.enableCull();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.popMatrix();
}
// Summoned creature selection pointer
if(properties != null && properties.selectedMinion != null && properties.selectedMinion.get() == event.getEntity()){
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
// Disabling depth test allows it to be seen through everything.
GL11.glDisable(GL11.GL_DEPTH_TEST);
GlStateManager.color(1, 1, 1, 1);
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ());
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
mc.renderEngine.bindTexture(pointerTexture);
buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex();
buffer.pos(0.2, 0.24, 0).tex(9f/16f, 0).endVertex();
buffer.pos(0.2, -0.24, 0).tex(9f/16f, 11f/16f).endVertex();
buffer.pos(-0.2, -0.24, 0).tex(0, 11f/16f).endVertex();
tessellator.draw();
GlStateManager.enableCull();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.popMatrix();
}
// Sixth sense
if(mc.thePlayer.isPotionActive(WizardryPotions.sixth_sense) && event.getEntity() != mc.thePlayer
&& mc.thePlayer.getActivePotionEffect(WizardryPotions.sixth_sense) != null
&& event.getEntity().getDistanceToEntity(mc.thePlayer) < 20*(1+mc.thePlayer.getActivePotionEffect(WizardryPotions.sixth_sense).getAmplifier()*Constants.RANGE_INCREASE_PER_LEVEL)){
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// Disabling depth test allows it to be seen through everything.
GL11.glDisable(GL11.GL_DEPTH_TEST);
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height * 0.6, event.getZ());
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
mc.renderEngine.bindTexture(sixthSenseTexture);
buffer.pos(-0.6, 0.6, 0).tex(0, 0).endVertex();
buffer.pos(0.6, 0.6, 0).tex(1, 0).endVertex();
buffer.pos(0.6, -0.6, 0).tex(1, 1).endVertex();
buffer.pos(-0.6, -0.6, 0).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.enableCull();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.popMatrix();
}
}
@SubscribeEvent
public static void onRenderGameOverlayEvent(RenderGameOverlayEvent.Post event){
if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET
&& Minecraft.getMinecraft().thePlayer.isPotionActive(WizardryPotions.sixth_sense)){
GlStateManager.pushMatrix();
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDepthMask(false);
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.disableAlpha();
Minecraft.getMinecraft().renderEngine.bindTexture(sixthSenseOverlayTexture);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex();
buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D).endVertex();
buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex();
buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex();
tessellator.draw();
GL11.glDepthMask(true);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.enableAlpha();
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.popMatrix();
}
if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET
&& Minecraft.getMinecraft().thePlayer.isPotionActive(WizardryPotions.frost)){
GlStateManager.pushMatrix();
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDepthMask(false);
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.disableAlpha();
Minecraft.getMinecraft().renderEngine.bindTexture(frostOverlayTexture);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex();
buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D).endVertex();
buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex();
buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex();
tessellator.draw();
GL11.glDepthMask(true);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.enableAlpha();
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.popMatrix();
}
}
// FIXME: Something in here is making the first person shadow ward rather translucent.
private static void renderShadowWardFirstPerson(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer) != null && WizardData.get(entityplayer).currentlyCasting() instanceof ShadowWard || (entityplayer.isHandActive() && wand != null && wand.getItemDamage() < wand.getMaxDamage()
&& wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
GlStateManager.disableAlpha();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.translate(0, 1.2, 0);
GlStateManager.rotate(-entityplayer.rotationYaw, 0, 1, 0);
GlStateManager.rotate(entityplayer.rotationPitch, 1, 0, 0);
Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture);
GlStateManager.pushMatrix();
GlStateManager.translate(0, 0, 1.2);
GlStateManager.rotate(entityplayer.worldObj.getWorldTime()*-2, 0, 0, 1);
GlStateManager.scale(1.1, 1.1, 1.1);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex();
buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex();
buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex();
buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex();
buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex();
buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex();
buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
}
private static void renderShadowWardIfActive(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer).currentlyCasting() instanceof ShadowWard || (entityplayer.isHandActive() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.rotate(180, 0, 1, 0);
GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0);
Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.translate(0, 1.2, 0);
GlStateManager.rotate(entityplayer.worldObj.getWorldTime()*-2, 0, 0, 1);
GlStateManager.scale(1.1, 1.1, 1.1);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex();
buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex();
buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex();
buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex();
buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex();
buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex();
buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex();
tessellator.draw();
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
}
private static void renderWingsIfActive(EntityPlayer entityplayer, float partialTickTime){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer).currentlyCasting() instanceof Flight || (entityplayer.isHandActive() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Flight)){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
//GlStateManager.rotate(-entityplayer.rotationYawHead, 0, 1, 0);
GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0);
//GlStateManager.rotate(180, 1, 0, 0);
Minecraft.getMinecraft().renderEngine.bindTexture(wingTexture);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.translate(0.1, 0.4, -0.15);
GlStateManager.rotate(20 + 20*(float)Math.sin(entityplayer.worldObj.getWorldTime()*0.3), 0, 1, 0);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 2, 0).tex(0, 0).endVertex();
buffer.pos(2, 2, 0).tex(1, 0).endVertex();
buffer.pos(2, 0, 0).tex(1, 1).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 2, 0).tex(0, 0).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
buffer.pos(2, 0, 0).tex(1, 1).endVertex();
buffer.pos(2, 2, 0).tex(1, 0).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
GlStateManager.pushMatrix();
GlStateManager.translate(-0.1, 0.4, -0.15);
GlStateManager.rotate(-200 - 20*(float)Math.sin(entityplayer.worldObj.getWorldTime()*0.3), 0, 1, 0);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 2, 0).tex(0, 0).endVertex();
buffer.pos(2, 2, 0).tex(1, 0).endVertex();
buffer.pos(2, 0, 0).tex(1, 1).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 2, 0).tex(0, 0).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
buffer.pos(2, 0, 0).tex(1, 1).endVertex();
buffer.pos(2, 2, 0).tex(1, 0).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
}
private static void renderShieldFirstPerson(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer) != null && WizardData.get(entityplayer).shield != null && (WizardData.get(entityplayer).currentlyCasting() instanceof Shield || (entityplayer.isHandActive() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Shield))){
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.translate(0, 1.4, 0);
GlStateManager.rotate(-entityplayer.rotationYaw, 0, 1, 0);
GlStateManager.rotate(entityplayer.rotationPitch, 1, 0, 0);
GlStateManager.translate(0, 0, 0.8);
Tessellator tessellator = Tessellator.getInstance();
Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture);
renderShield(tessellator);
GlStateManager.enableLighting();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableCull();
GlStateManager.disableBlend();
//RenderHelper.enableStandardItemLighting();
GlStateManager.popMatrix();
}
}
private static void renderShieldIfActive(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer).shield != null && (WizardData.get(entityplayer).currentlyCasting() instanceof Shield || (entityplayer.isHandActive() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Shield))){
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
// For some reason, the old blend function (GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA) caused the inner
// edges to appear black, so I have changed it to this, which looks very slightly different.
GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.translate(0, 1.3, 0);
//GlStateManager.rotate(180, 0, 1, 0);
GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0);
//GlStateManager.rotate(-entityplayer.rotationPitch, 1, 0, 0);
GlStateManager.translate(0, 0, 0.8);
Tessellator tessellator = Tessellator.getInstance();
Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture);
renderShield(tessellator);
GlStateManager.enableLighting();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableCull();
GlStateManager.disableBlend();
//RenderHelper.enableStandardItemLighting();
GlStateManager.popMatrix();
}
}
private static void renderShield(Tessellator tessellator){
VertexBuffer buffer = tessellator.getBuffer();
double widthOuter = 0.6d;
double heightOuter = 0.7d;
double widthInner = 0.3d;
double heightInner = 0.4d;
double depth = 0.2d;
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR);
buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthInner, heightOuter, -depth).tex(0.2, 0).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(widthInner, heightOuter, -depth).tex(0.8, 0).color(0, 0, 0, 255).endVertex();
buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(widthOuter, heightInner, -depth).tex(1, 0.2).color(0, 0, 0, 255).endVertex();
buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(widthOuter, -heightInner, -depth).tex(1, 0.8).color(0, 0, 0, 255).endVertex();
buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(widthInner, -heightOuter, -depth).tex(0.8, 1).color(0, 0, 0, 255).endVertex();
buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthInner, -heightOuter, -depth).tex(0.2, 1).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthOuter, -heightInner, -depth).tex(0, 0.8).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR);
buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex();
tessellator.draw();
}
}
@@ -0,0 +1,83 @@
package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
public class ModelHammer extends ModelBase
{
ModelRenderer Shape1;
ModelRenderer Shape2;
ModelRenderer Shape3;
ModelRenderer Shape4;
ModelRenderer Shape5;
ModelRenderer Shape6;
public ModelHammer()
{
textureWidth = 64;
textureHeight = 64;
Shape1 = new ModelRenderer(this, 0, 0);
Shape1.addBox(0F, 0F, 0F, 20, 12, 12);
Shape1.setRotationPoint(-10F, 12F, -6F);
Shape1.setTextureSize(64, 64);
Shape1.mirror = true;
setRotation(Shape1, 0F, 0F, 0F);
Shape2 = new ModelRenderer(this, 0, 24);
Shape2.addBox(0F, 0F, 0F, 4, 14, 4);
Shape2.setRotationPoint(-2F, -2F, -2F);
Shape2.setTextureSize(64, 64);
Shape2.mirror = true;
setRotation(Shape2, 0F, 0F, 0F);
Shape3 = new ModelRenderer(this, 0, 49);
Shape3.addBox(0F, 0F, 0F, 5, 5, 5);
Shape3.setRotationPoint(-2.5F, -7F, -2.5F);
Shape3.setTextureSize(64, 64);
Shape3.mirror = true;
setRotation(Shape3, 0F, 0F, 0F);
Shape4 = new ModelRenderer(this, 0, 42);
Shape4.addBox(0F, 0F, 0F, 5, 2, 5);
Shape4.setRotationPoint(-2.5F, 10F, -2.5F);
Shape4.setTextureSize(64, 64);
Shape4.mirror = true;
setRotation(Shape4, 0F, 0F, 0F);
Shape5 = new ModelRenderer(this, 20, 24);
Shape5.addBox(0F, 0F, 0F, 2, 14, 14);
Shape5.setRotationPoint(-8F, 11F, -7F);
Shape5.setTextureSize(64, 64);
Shape5.mirror = true;
setRotation(Shape5, 0F, 0F, 0F);
Shape6 = new ModelRenderer(this, 20, 24);
Shape6.addBox(0F, 0F, 0F, 2, 14, 14);
Shape6.setRotationPoint(6F, 11F, -7F);
Shape6.setTextureSize(64, 64);
Shape6.mirror = true;
setRotation(Shape6, 0F, 0F, 0F);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
Shape1.render(f5);
Shape2.render(f5);
Shape3.render(f5);
Shape4.render(f5);
Shape5.render(f5);
Shape6.render(f5);
}
private void setRotation(ModelRenderer model, float x, float y, float z)
{
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity)
{
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
}
@@ -0,0 +1,321 @@
package electroblob.wizardry.client.model;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import electroblob.wizardry.entity.living.EntityIceGiant;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ModelIceGiant extends ModelBase
{
/** The head model for the iron golem. */
public ModelRenderer iceGiantHead;
/** The body model for the iron golem. */
public ModelRenderer iceGiantBody;
/** The right arm model for the iron golem. */
public ModelRenderer iceGiantRightArm;
/** The left arm model for the iron golem. */
public ModelRenderer iceGiantLeftArm;
/** The left leg model for the Iron Golem. */
public ModelRenderer iceGiantLeftLeg;
/** The right leg model for the Iron Golem. */
public ModelRenderer iceGiantRightLeg;
ModelRenderer headSpike1;
ModelRenderer headSpike2;
ModelRenderer headSpike3;
ModelRenderer headSpike4;
ModelRenderer headSpike5;
ModelRenderer headSpike6;
ModelRenderer headSpike7;
ModelRenderer rightArmSpike1;
ModelRenderer rightArmSpike2;
ModelRenderer leftArmSpike1;
ModelRenderer leftArmSpike2;
ModelRenderer bodySpike1;
ModelRenderer bodySpike2;
ModelRenderer bodySpike3;
ModelRenderer bodySpike4;
ModelRenderer bodySpike5;
public ModelIceGiant()
{
this(0.0F);
}
public ModelIceGiant(float par1)
{
this(par1, -7.0F);
}
public ModelIceGiant(float par1, float par2)
{
short short1 = 128;
short short2 = 128;
this.iceGiantHead = (new ModelRenderer(this)).setTextureSize(short1, short2);
this.iceGiantHead.setRotationPoint(0.0F, 0.0F + par2, -1.0F);
this.iceGiantHead.setTextureOffset(0, 10).addBox(-6.0F, -14.0F, -6.5F, 12, 12, 12, par1);
this.iceGiantBody = (new ModelRenderer(this)).setTextureSize(short1, short2);
this.iceGiantBody.setRotationPoint(0.0F, 0.0F + par2, 0.0F);
this.iceGiantBody.setTextureOffset(0, 40).addBox(-9.0F, -2.0F, -6.0F, 18, 12, 11, par1);
this.iceGiantBody.setTextureOffset(0, 70).addBox(-4.5F, 10.0F, -3.0F, 9, 5, 6, par1 + 0.5F);
this.iceGiantRightArm = (new ModelRenderer(this)).setTextureSize(short1, short2);
this.iceGiantRightArm.setRotationPoint(0.0F, -7.0F, 0.0F);
this.iceGiantRightArm.setTextureOffset(60, 21).addBox(-13.0F, -2.5F, -3.0F, 4, 30, 6, par1);
this.iceGiantLeftArm = (new ModelRenderer(this)).setTextureSize(short1, short2);
this.iceGiantLeftArm.setRotationPoint(0.0F, -7.0F, 0.0F);
this.iceGiantLeftArm.setTextureOffset(60, 58).addBox(9.0F, -2.5F, -3.0F, 4, 30, 6, par1);
this.iceGiantLeftLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2);
this.iceGiantLeftLeg.setRotationPoint(-4.0F, 18.0F + par2, 0.0F);
this.iceGiantLeftLeg.setTextureOffset(37, 0).addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1);
this.iceGiantRightLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2);
this.iceGiantRightLeg.mirror = true;
this.iceGiantRightLeg.setTextureOffset(60, 0).setRotationPoint(5.0F, 18.0F + par2, 0.0F);
this.iceGiantRightLeg.addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1);
headSpike1 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike1.addBox(-4F, -4F, 0F, 4, 4, 4);
headSpike1.setRotationPoint(-4F, -10F, -5F);
headSpike1.mirror = true;
setRotationWithEulerYzx(headSpike1, -0.1047198F, -0.5235988F, 0.9599311F);
headSpike2 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike2.addBox(0F, -4F, 0F, 4, 4, 4);
headSpike2.setRotationPoint(4F, -16F, 0F);
headSpike2.mirror = true;
setRotationWithEulerYzx(headSpike2, 0.5585054F, 0.9250245F, -0.5235988F);
headSpike3 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike3.addBox(-2F, -2F, -2F, 4, 4, 4);
headSpike3.setRotationPoint(4F, -13F, 4F);
headSpike3.mirror = true;
setRotationWithEulerYzx(headSpike3, 0.7853982F, -1.396263F, 0.7853982F);
headSpike4 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike4.addBox(-4F, -4F, 0F, 4, 4, 4);
headSpike4.setRotationPoint(-4F, -16F, 0F);
headSpike4.mirror = true;
setRotationWithEulerYzx(headSpike4, 0.5585054F, -0.9250245F, 0.5235988F);
headSpike5 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike5.addBox(0F, -4F, 0F, 4, 4, 4);
headSpike5.setRotationPoint(4F, -10F, -5F);
headSpike5.mirror = true;
setRotationWithEulerYzx(headSpike5, 0.5235988F, -0.9599311F, 0.1047198F);
rightArmSpike1 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
rightArmSpike1.addBox(-2F, -2F, -2F, 4, 4, 4);
rightArmSpike1.setRotationPoint(-11F, -8F, 0F);
rightArmSpike1.mirror = true;
setRotationWithEulerYzx(rightArmSpike1, 0.7853982F, 1.134464F, 0.9599311F);
headSpike6 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike6.addBox(-2F, -2F, -2F, 4, 4, 4);
headSpike6.setRotationPoint(-4F, -13F, 4F);
headSpike6.mirror = true;
setRotationWithEulerYzx(headSpike6, 0.7853982F, -1.745329F, 0.7853982F);
leftArmSpike1 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
leftArmSpike1.addBox(-2F, -2F, -2F, 4, 4, 4);
leftArmSpike1.setRotationPoint(11F, -8F, 0F);
leftArmSpike1.mirror = true;
setRotationWithEulerYzx(leftArmSpike1, 0.7853982F, -1.134464F, -0.9599311F);
leftArmSpike2 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
leftArmSpike2.addBox(-2F, -2F, -2F, 4, 4, 4);
leftArmSpike2.setRotationPoint(12F, -4F, 0F);
leftArmSpike2.mirror = true;
setRotationWithEulerYzx(leftArmSpike2, 0.7853982F, 0F, -0.9599311F);
bodySpike1 = new ModelRenderer(this, 32, 69).setTextureSize(short1, short2);
bodySpike1.addBox(-3F, -3F, -3F, 6, 6, 6);
bodySpike1.setRotationPoint(-4F, -4F, 3F);
bodySpike1.mirror = true;
setRotationWithEulerYzx(bodySpike1, 0.2808018F, 0.8096675F, 0.8339369F);
rightArmSpike2 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
rightArmSpike2.addBox(-2F, -2F, -2F, 4, 4, 4);
rightArmSpike2.setRotationPoint(-12F, -4F, 0F);
rightArmSpike2.mirror = true;
setRotationWithEulerYzx(rightArmSpike2, 0.7853982F, 0F, 0.9599311F);
bodySpike2 = new ModelRenderer(this, 32, 69).setTextureSize(short1, short2);
bodySpike2.addBox(-3F, -3F, -3F, 6, 6, 6);
bodySpike2.setRotationPoint(4F, -4F, 3F);
bodySpike2.mirror = true;
setRotationWithEulerYzx(bodySpike2, 0.2808018F, -0.8096757F, -0.8339358F);
bodySpike3 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
bodySpike3.addBox(-2F, -2F, -2F, 4, 4, 4);
bodySpike3.setRotationPoint(6F, -2F, -5F);
bodySpike3.mirror = true;
setRotationWithEulerYzx(bodySpike3, 1.120006F, -1.347726F, -0.8969422F);
bodySpike4 = new ModelRenderer(this, 32, 69).setTextureSize(short1, short2);
bodySpike4.addBox(-3F, -3F, -3F, 6, 6, 6);
bodySpike4.setRotationPoint(0F, -4F, -4F);
bodySpike4.mirror = true;
setRotationWithEulerYzx(bodySpike4, 0.7853982F, -1.570796F, 0.9599311F);
headSpike7 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike7.addBox(-2F, -2F, -2F, 4, 4, 4);
headSpike7.setRotationPoint(0F, -20F, 4F);
headSpike7.mirror = true;
setRotationWithEulerYzx(headSpike7, 0.7853982F, 1.570796F, 0.7853982F);
bodySpike5 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
bodySpike5.addBox(-2F, -2F, -2F, 4, 4, 4);
bodySpike5.setRotationPoint(-6F, -2F, -5F);
bodySpike5.mirror = true;
setRotationWithEulerYzx(bodySpike5, 1.120006F, 1.347725F, 0.896934F);
this.convertToChild(this.iceGiantHead, headSpike1);
this.convertToChild(this.iceGiantHead, headSpike2);
this.convertToChild(this.iceGiantHead, headSpike3);
this.convertToChild(this.iceGiantHead, headSpike4);
this.convertToChild(this.iceGiantHead, headSpike5);
this.convertToChild(this.iceGiantHead, headSpike6);
this.convertToChild(this.iceGiantHead, headSpike7);
this.convertToChild(this.iceGiantRightArm, rightArmSpike1);
this.convertToChild(this.iceGiantRightArm, rightArmSpike2);
this.convertToChild(this.iceGiantLeftArm, leftArmSpike1);
this.convertToChild(this.iceGiantLeftArm, leftArmSpike2);
this.convertToChild(this.iceGiantBody, bodySpike1);
this.convertToChild(this.iceGiantBody, bodySpike2);
this.convertToChild(this.iceGiantBody, bodySpike3);
this.convertToChild(this.iceGiantBody, bodySpike4);
this.convertToChild(this.iceGiantBody, bodySpike5);
}
/**
* Sets the models various rotation angles then renders the model.
*/
public void render(Entity par1Entity, float par2, float par3, float par4, float par5, float par6, float par7)
{
this.setRotationAngles(par2, par3, par4, par5, par6, par7, par1Entity);
this.iceGiantHead.render(par7);
this.iceGiantBody.render(par7);
this.iceGiantLeftLeg.render(par7);
this.iceGiantRightLeg.render(par7);
this.iceGiantRightArm.render(par7);
this.iceGiantLeftArm.render(par7);
}
/**
* Sets the model's various rotation angles. For bipeds, par1 and par2 are used for animating the movement of arms
* and legs, where par1 represents the time(so that arms and legs swing back and forth) and par2 represents how
* "far" arms and legs can swing at most.
*/
public void setRotationAngles(float par1, float par2, float par3, float par4, float par5, float par6, Entity par7Entity)
{
this.iceGiantHead.rotateAngleY = par4 / (180F / (float)Math.PI);
this.iceGiantHead.rotateAngleX = par5 / (180F / (float)Math.PI);
this.iceGiantLeftLeg.rotateAngleX = -1.5F * this.func_78172_a(par1, 13.0F) * par2;
this.iceGiantRightLeg.rotateAngleX = 1.5F * this.func_78172_a(par1, 13.0F) * par2;
this.iceGiantLeftLeg.rotateAngleY = 0.0F;
this.iceGiantRightLeg.rotateAngleY = 0.0F;
}
/**
* Used for easily adding entity-dependent animations. The second and third float params here are the same second
* and third as in the setRotationAngles method.
*/
public void setLivingAnimations(EntityLivingBase par1EntityLivingBase, float par2, float par3, float par4)
{
EntityIceGiant entityicegiant = (EntityIceGiant)par1EntityLivingBase;
int i = entityicegiant.getAttackTimer();
if (i > 0)
{
this.iceGiantRightArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F);
this.iceGiantLeftArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F);
}
else
{
this.iceGiantRightArm.rotateAngleX = (-0.2F + 1.5F * this.func_78172_a(par2, 13.0F)) * par3;
this.iceGiantLeftArm.rotateAngleX = (-0.2F - 1.5F * this.func_78172_a(par2, 13.0F)) * par3;
}
}
private float func_78172_a(float par1, float par2)
{
return (Math.abs(par1 % par2 - par2 * 0.5F) - par2 * 0.25F) / (par2 * 0.25F);
}
/** This is really useful for converting the source from a Techne model export
* which will have absolute rotation points that need to be converted before
* creating the addChild() relationship. [Courtesy of jabelar] */
protected void convertToChild(ModelRenderer parent, ModelRenderer child)
{
// move child rotation point to be relative to parent
child.rotationPointX -= parent.rotationPointX;
child.rotationPointY -= parent.rotationPointY;
child.rotationPointZ -= parent.rotationPointZ;
// make rotations relative to parent
child.rotateAngleX -= parent.rotateAngleX;
child.rotateAngleY -= parent.rotateAngleY;
child.rotateAngleZ -= parent.rotateAngleZ;
// create relationship
parent.addChild(child);
}
/** Fixes the Techne rotation order bug. [Courtesy of tprk77] */
private Vector3f ConvertEulerYzxToZyx(Vector3f eulerYzx) {
// Create a matrix from YZX ordered Euler angles
float a = MathHelper.cos(eulerYzx.x);
float b = MathHelper.sin(eulerYzx.x);
float c = MathHelper.cos(eulerYzx.y);
float d = MathHelper.sin(eulerYzx.y);
float e = MathHelper.cos(eulerYzx.z);
float f = MathHelper.sin(eulerYzx.z);
Matrix4f matrix = new Matrix4f();
matrix.m00 = c * e;
matrix.m01 = b * d - a * c * f;
matrix.m02 = b * c * f + a * d;
matrix.m10 = f;
matrix.m11 = a * e;
matrix.m12 = -b * e;
matrix.m20 = -d * e;
matrix.m21 = a * d * f + b * c;
matrix.m22 = a * c - b * d * f;
matrix.m33 = 1.0F;
// Create ZYX ordered Euler angles from the matrix
Vector3f eulerZyx = new Vector3f();
eulerZyx.y = (float) Math.asin(MathHelper.clamp_float(-matrix.m20, -1, 1));
if (MathHelper.abs(matrix.m20) < 0.99999) {
eulerZyx.x = (float) Math.atan2(matrix.m21, matrix.m22);
eulerZyx.z = (float) Math.atan2(matrix.m10, matrix.m00);
} else {
eulerZyx.x = 0.0F;
eulerZyx.z = (float) Math.atan2(-matrix.m01, matrix.m11);
}
return eulerZyx;
}
private void setRotationWithEulerYzx(ModelRenderer model, float x, float y, float z) {
Vector3f eulerYzx = new Vector3f(x, y, z);
Vector3f eulerZyx = ConvertEulerYzxToZyx(eulerYzx);
model.rotateAngleX = eulerZyx.x;
model.rotateAngleY = eulerZyx.y;
model.rotateAngleZ = eulerZyx.z;
}
}
@@ -0,0 +1,139 @@
package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
public class ModelPhoenix extends ModelBase {
ModelRenderer body;
ModelRenderer rightWing;
ModelRenderer leftWing;
ModelRenderer tailFeathers;
ModelRenderer tail;
ModelRenderer head;
ModelRenderer neck;
ModelRenderer beak;
ModelRenderer plume;
public ModelPhoenix()
{
textureWidth = 64;
textureHeight = 64;
/* For future reference:
* - setRotationPoint sets the origin of a part relative to that of its parent.
* - The first 3 arguments of addBox set the position of a part relative to its rotation point, and the last
* 3 arguments are the size of the part.
* (This means that rotation point and position seem to be the wrong way round, since changing the rotation point
* will move the component without changing which point on the component it rotates about.)
* - The two integer arguments in the ModelRenderer constructor are the texture offset.
* - Mirror does nothing unless you set it before addBox.
* - Rotation is the usual pitch, yaw, roll.
*/
body = new ModelRenderer(this, 0, 34);
body.addBox(0F, 0F, -3F, 6, 15, 6);
body.setRotationPoint(-3F, 0F, -5F);
body.setTextureSize(64, 64);
body.mirror = true;
setRotation(body, 0.296706F, 0F, 0F);
rightWing = new ModelRenderer(this, 0, 0);
rightWing.mirror = true;
rightWing.addBox(-27F, -27F, 0F, 27, 34, 0);
rightWing.setRotationPoint(0F, 5F, 0F);
rightWing.setTextureSize(64, 64);
setRotation(rightWing, 0.1745329F, 0F, 0F);
leftWing = new ModelRenderer(this, 0, 0);
leftWing.addBox(0F, -27F, 0F, 27, 34, 0);
leftWing.setRotationPoint(6F, 5F, 0F);
leftWing.setTextureSize(64, 64);
setRotation(leftWing, 0.1745329F, 0F, 0F);
tailFeathers = new ModelRenderer(this, 0, 57);
tailFeathers.addBox(-5F, 0F, 0F, 10, 7, 0);
tailFeathers.setRotationPoint(0F, 7F, 1F);
tailFeathers.setTextureSize(64, 64);
tailFeathers.mirror = true;
setRotation(tailFeathers, 0.5235988F, 0F, 0F);
tail = new ModelRenderer(this, 20, 55);
tail.addBox(-1F, 0F, -1F, 2, 7, 2);
tail.setRotationPoint(3F, 15F, 2F);
tail.setTextureSize(64, 64);
tail.mirror = true;
setRotation(tail, 0.4014257F, 0F, 0F);
head = new ModelRenderer(this, 24, 34);
head.addBox(-2F, -4F, -5F, 4, 4, 6);
head.setRotationPoint(0F, -4F, 0F);
head.setTextureSize(64, 64);
head.mirror = true;
setRotation(head, 0F, 0F, 0F);
neck = new ModelRenderer(this, 24, 44);
neck.addBox(-1F, -4F, -1F, 2, 4, 2);
neck.setRotationPoint(0F, 0F, -4F);
neck.setTextureSize(64, 64);
neck.mirror = true;
setRotation(neck, 0.2443461F, 0F, 0F);
beak = new ModelRenderer(this, 32, 44);
beak.addBox(-0.5F, 4F, -1F, 1, 2, 3);
beak.setRotationPoint(0F, -5F, -8F);
beak.setTextureSize(64, 64);
beak.mirror = true;
setRotation(beak, 0.2792527F, 0F, 0F);
plume = new ModelRenderer(this, 28, 50);
plume.addBox(-0.03333334F, 1F, 0F, 0, 5, 5);
plume.setRotationPoint(0F, -7F, 0F);
plume.setTextureSize(64, 64);
plume.mirror = true;
setRotation(plume, 0F, 0F, 0F);
neck.addChild(head);
head.addChild(plume);
head.addChild(beak);
tail.addChild(tailFeathers);
body.addChild(tail);
body.addChild(rightWing);
body.addChild(leftWing);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
//float f6 = (180F / (float)Math.PI);
this.neck.rotateAngleX = f4 / (180F / (float)Math.PI);
this.neck.rotateAngleY = f3 / (180F / (float)Math.PI);
this.neck.rotateAngleZ = 0.0F;
this.body.rotateAngleX = 0.3f + MathHelper.cos(f2 * 0.1F) * 0.15F;
this.body.rotateAngleY = 0.0F;
this.tail.rotateAngleX = this.body.rotateAngleX * 1.1f;
this.tailFeathers.rotateAngleX = this.body.rotateAngleX * 1.2f;
this.rightWing.rotateAngleY = MathHelper.cos(f2 * 0.3F) * (float)Math.PI * 0.15F;
this.leftWing.rotateAngleY = -this.rightWing.rotateAngleY;
body.render(f5);
neck.render(f5);
}
private void setRotation(ModelRenderer model, float x, float y, float z)
{
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity)
{
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
}
@@ -0,0 +1,174 @@
package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.model.ModelRenderer;
public class ModelWizard extends ModelBiped
{
//fields
ModelRenderer Shape5;
ModelRenderer Shape8;
ModelRenderer Shape9;
ModelRenderer Shape10;
ModelRenderer Shape7;
ModelRenderer Shape11;
ModelRenderer Shape12;
ModelRenderer beard;
ModelRenderer Shape13;
public ModelWizard()
{
//super(0, 0, 64, 32);
/*
bipedRightLeg = new ModelRenderer(this, 32, 0); // 32 and 0 are the x and y texture offsets respectively.
bipedRightLeg.addBox(-2F, 0F, -2F, 4, 12, 4); // x, y, z, u, v, w.
bipedRightLeg.setRotationPoint(-2F, 12F, 0F); // Rotation point xyz (absolute, not relative)
bipedRightLeg.setTextureSize(64, 64);
bipedRightLeg.mirror = true;
setRotation(bipedRightLeg, 0F, 0F, 0F);
bipedLeftLeg.mirror = true;
bipedLeftLeg = new ModelRenderer(this, 32, 0);
bipedLeftLeg.addBox(-2F, 0F, -2F, 4, 12, 4);
bipedLeftLeg.setRotationPoint(2F, 12F, 0F);
bipedLeftLeg.setTextureSize(64, 64);
bipedLeftLeg.mirror = true;
setRotation(bipedLeftLeg, 0F, 0F, 0F);
bipedLeftLeg.mirror = false;
bipedBody = new ModelRenderer(this, 0, 16);
bipedBody.addBox(0F, 0F, 0F, 8, 12, 4);
bipedBody.setRotationPoint(-4F, 0F, -2F);
bipedBody.setTextureSize(64, 64);
bipedBody.mirror = true;
setRotation(bipedBody, 0F, 0F, 0F);
bipedLeftArm.mirror = true;
bipedLeftArm = new ModelRenderer(this, 48, 0);
bipedLeftArm.addBox(-1F, 0F, -2F, 4, 12, 4);
bipedLeftArm.setRotationPoint(4F, 0F, 0F);
bipedLeftArm.setTextureSize(64, 64);
bipedLeftArm.mirror = true;
setRotation(bipedLeftArm, 0F, 0F, 0F);
bipedLeftArm.mirror = false;
bipedRightArm = new ModelRenderer(this, 48, 0);
bipedRightArm.addBox(-3F, 0F, -2F, 4, 12, 4);
bipedRightArm.setRotationPoint(-4F, 0F, 0F);
bipedRightArm.setTextureSize(64, 64);
bipedRightArm.mirror = true;
setRotation(bipedRightArm, 0F, 0F, 0F);
bipedHead = new ModelRenderer(this, 0, 0);
bipedHead.addBox(-4F, -8F, -4F, 8, 8, 8);
bipedHead.setRotationPoint(0F, 0F, 0F);
bipedHead.setTextureSize(64, 64);
bipedHead.mirror = true;
setRotation(bipedHead, 0F, 0F, 0F);
*/
Shape5 = new ModelRenderer(this, 0, 51);
Shape5.addBox(0F, 0F, 0F, 12, 1, 12);
Shape5.setRotationPoint(-6F, -7F, -6F);
Shape5.setTextureSize(64, 64);
Shape5.mirror = true;
setRotation(Shape5, 0F, 0F, 0F);
Shape8 = new ModelRenderer(this, 0, 32);
Shape8.addBox(0F, 0F, 0F, 6, 1, 6);
Shape8.setRotationPoint(-3F, -9F, -3F);
Shape8.setTextureSize(64, 64);
Shape8.mirror = true;
setRotation(Shape8, -0.0349066F, 0F, 0F);
Shape9 = new ModelRenderer(this, 24, 32);
Shape9.addBox(0F, 0F, 0F, 3, 3, 3);
Shape9.setRotationPoint(-1.5F, -13F, -0.5F);
Shape9.setTextureSize(64, 64);
Shape9.mirror = true;
setRotation(Shape9, -0.2511622F, 0F, 0F);
Shape10 = new ModelRenderer(this, 0, 39);
Shape10.addBox(0F, 0F, 0F, 5, 1, 5);
Shape10.setRotationPoint(-2.5F, -10F, -2.5F);
Shape10.setTextureSize(64, 64);
Shape10.mirror = true;
setRotation(Shape10, -0.0698132F, 0F, 0F);
Shape7 = new ModelRenderer(this, 0, 45);
Shape7.addBox(0F, 0F, 0F, 4, 2, 4);
Shape7.setRotationPoint(-2F, -11F, -1.5F);
Shape7.setTextureSize(64, 64);
Shape7.mirror = true;
setRotation(Shape7, -0.1396263F, 0F, 0F);
Shape11 = new ModelRenderer(this, 20, 39);
Shape11.addBox(0F, 0F, 0F, 2, 3, 2);
Shape11.setRotationPoint(-1F, -15F, 1F);
Shape11.setTextureSize(64, 64);
Shape11.mirror = true;
setRotation(Shape11, -0.4363323F, 0F, 0F);
Shape12 = new ModelRenderer(this, 28, 39);
Shape12.addBox(0F, 0F, 0F, 1, 2, 1);
Shape12.setRotationPoint(-0.5F, -16F, 2.5F);
Shape12.setTextureSize(64, 64);
Shape12.mirror = true;
setRotation(Shape12, -0.715585F, 0F, 0F);
beard = new ModelRenderer(this, 32, 0);
beard.addBox(0F, 0F, 0F, 8, 5, 0);
beard.setRotationPoint(-4F, 0F, -4F);
beard.setTextureSize(64, 64);
beard.mirror = true;
setRotation(beard, 0F, 0F, 0F);
Shape13 = new ModelRenderer(this, 36, 16);
Shape13.addBox(4F, 0F, 2F, 8, 20, 6);
Shape13.setRotationPoint(-4F, 0F, -3F);
Shape13.setTextureSize(64, 64);
Shape13.mirror = true;
setRotation(Shape13, 0F, 0F, 0F);
// Makes head bits move with head
//bipedHead.addChild(Shape5);
bipedHead.addChild(beard);
//bipedHead.addChild(Shape7);
//bipedHead.addChild(Shape8);
//bipedHead.addChild(Shape9);
//bipedHead.addChild(Shape10);
//bipedHead.addChild(Shape11);
//bipedHead.addChild(Shape12);
// Makes cloak attached to body
//bipedBody.addChild(Shape13);
// No outer head layer
this.bipedHeadwear.isHidden = true;
}
/*
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
bipedRightLeg.render(f5);
bipedLeftLeg.render(f5);
bipedBody.render(f5);
bipedLeftArm.render(f5);
bipedRightArm.render(f5);
bipedHead.render(f5);
Shape5.render(f5);
Shape8.render(f5);
Shape9.render(f5);
Shape10.render(f5);
Shape7.render(f5);
Shape11.render(f5);
Shape12.render(f5);
Shape6.render(f5);
Shape13.render(f5);
}
*/
private void setRotation(ModelRenderer model, float x, float y, float z)
{
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
/*
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity)
{
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
*/
}
@@ -0,0 +1,111 @@
package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
public class ModelWizardArmour extends ModelBiped
{
ModelRenderer Shape1;
ModelRenderer Shape2;
ModelRenderer Shape3;
ModelRenderer Shape4;
ModelRenderer Shape5;
ModelRenderer Shape6;
ModelRenderer Shape7;
ModelRenderer robe;
public ModelWizardArmour(float scale){
super(scale, 0, 64, 64);
// This is necessary to stop the head from scaling.
this.bipedHead = new ModelRenderer(this, 0, 0);
this.bipedHead.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, 0.1f);
this.bipedHead.setRotationPoint(0.0F, 0.0F + 0, 0.0F);
Shape1 = new ModelRenderer(this, -16, 32);
Shape1.addBox(-8F, -7F, -8F, 16, 0, 16);
Shape1.setRotationPoint(0F, 0F, 0F);
Shape1.setTextureSize(64, 64);
Shape1.mirror = true;
setRotation(Shape1, 0F, 0F, 0F);
Shape2 = new ModelRenderer(this, 0, 48);
Shape2.addBox(0F, 0F, 0F, 6, 2, 6);
Shape2.setRotationPoint(-3F, -10F, -3F);
Shape2.setTextureSize(64, 64);
Shape2.mirror = true;
setRotation(Shape2, -0.1396263F, 0F, 0F);
Shape3 = new ModelRenderer(this, 0, 56);
Shape3.addBox(0F, 0F, 0F, 5, 2, 5);
Shape3.setRotationPoint(-2.5F, -11.53333F, -2F);
Shape3.setTextureSize(64, 64);
Shape3.mirror = true;
setRotation(Shape3, -0.2443461F, 0F, 0F);
Shape4 = new ModelRenderer(this, 24, 48);
Shape4.addBox(0F, 0F, 0F, 4, 2, 4);
Shape4.setRotationPoint(-2F, -13F, -1F);
Shape4.setTextureSize(64, 64);
Shape4.mirror = true;
setRotation(Shape4, -0.4014257F, 0F, 0F);
Shape5 = new ModelRenderer(this, 24, 54);
Shape5.addBox(0F, 0F, 0F, 3, 2, 3);
Shape5.setRotationPoint(-1.5F, -14F, 0F);
Shape5.setTextureSize(64, 64);
Shape5.mirror = true;
setRotation(Shape5, -0.5759587F, 0F, 0F);
Shape6 = new ModelRenderer(this, 20, 59);
Shape6.addBox(0F, 0F, 0F, 2, 2, 2);
Shape6.setRotationPoint(-1F, -14F, 0F);
Shape6.setTextureSize(64, 64);
Shape6.mirror = true;
setRotation(Shape6, 0.3316126F, 0F, 0F);
Shape7 = new ModelRenderer(this, 28, 59);
Shape7.addBox(0F, 0F, 0F, 1, 1, 3);
Shape7.setRotationPoint(-0.5F, -14.5F, 2F);
Shape7.setTextureSize(64, 64);
Shape7.mirror = true;
setRotation(Shape7, -0.5585054F, 0F, 0F);
// The robe is now the body
bipedBody = new ModelRenderer(this, 40, 42);
bipedBody.addBox(-4F, 0F, -2F, 8, 18, 4, scale);
bipedBody.setRotationPoint(0F, 0F, 0F);
bipedBody.setTextureSize(64, 64);
bipedBody.mirror = true;
setRotation(bipedBody, 0F, 0F, 0F);
// Makes the hat rotate with the head.
bipedHead.addChild(Shape1);
bipedHead.addChild(Shape2);
bipedHead.addChild(Shape3);
bipedHead.addChild(Shape4);
bipedHead.addChild(Shape5);
bipedHead.addChild(Shape6);
bipedHead.addChild(Shape7);
// Makes the robe move with the body
//bipedBody.addChild(robe);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
private void setRotation(ModelRenderer model, float x, float y, float z){
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity){
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
}
@@ -0,0 +1,192 @@
package electroblob.wizardry.client.model;
import java.util.ArrayList;
import java.util.List;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryItems;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary;
/**
* Class responsible for registering all of wizardry's item (and itemblock) models.
* @author Electroblob
* @since Wizardry 2.1
*/
@SideOnly(Side.CLIENT)
@Mod.EventBusSubscriber(Side.CLIENT)
public final class WizardryItemModels {
@SubscribeEvent
public static void register(ModelRegistryEvent event){
// ItemBlocks
registerItemModel(Item.getItemFromBlock(WizardryBlocks.arcane_workbench));
registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_ore));
registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_flower));
registerItemModel(Item.getItemFromBlock(WizardryBlocks.transportation_stone));
registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_block));
// Items
registerItemModel(WizardryItems.magic_crystal);
registerItemModel(WizardryItems.magic_wand);
registerItemModel(WizardryItems.apprentice_wand);
registerItemModel(WizardryItems.advanced_wand);
registerItemModel(WizardryItems.master_wand);
registerItemModel(WizardryItems.spell_book);
// Wildcard registered for wizard trades.
registerItemModel(WizardryItems.spell_book, OreDictionary.WILDCARD_VALUE, "normal");
registerItemModel(WizardryItems.arcane_tome);
registerItemModel(WizardryItems.wizard_handbook);
registerItemModel(WizardryItems.basic_fire_wand);
registerItemModel(WizardryItems.basic_ice_wand);
registerItemModel(WizardryItems.basic_lightning_wand);
registerItemModel(WizardryItems.basic_necromancy_wand);
registerItemModel(WizardryItems.basic_earth_wand);
registerItemModel(WizardryItems.basic_sorcery_wand);
registerItemModel(WizardryItems.basic_healing_wand);
registerItemModel(WizardryItems.apprentice_fire_wand);
registerItemModel(WizardryItems.apprentice_ice_wand);
registerItemModel(WizardryItems.apprentice_lightning_wand);
registerItemModel(WizardryItems.apprentice_necromancy_wand);
registerItemModel(WizardryItems.apprentice_earth_wand);
registerItemModel(WizardryItems.apprentice_sorcery_wand);
registerItemModel(WizardryItems.apprentice_healing_wand);
registerItemModel(WizardryItems.advanced_fire_wand);
registerItemModel(WizardryItems.advanced_ice_wand);
registerItemModel(WizardryItems.advanced_lightning_wand);
registerItemModel(WizardryItems.advanced_necromancy_wand);
registerItemModel(WizardryItems.advanced_earth_wand);
registerItemModel(WizardryItems.advanced_sorcery_wand);
registerItemModel(WizardryItems.advanced_healing_wand);
registerItemModel(WizardryItems.master_fire_wand);
registerItemModel(WizardryItems.master_ice_wand);
registerItemModel(WizardryItems.master_lightning_wand);
registerItemModel(WizardryItems.master_necromancy_wand);
registerItemModel(WizardryItems.master_earth_wand);
registerItemModel(WizardryItems.master_sorcery_wand);
registerItemModel(WizardryItems.master_healing_wand);
registerItemModel(WizardryItems.spectral_sword);
registerItemModel(WizardryItems.spectral_pickaxe);
registerItemModel(WizardryItems.spectral_bow);
registerItemModel(WizardryItems.mana_flask);
registerItemModel(WizardryItems.storage_upgrade);
registerItemModel(WizardryItems.siphon_upgrade);
registerItemModel(WizardryItems.condenser_upgrade);
registerItemModel(WizardryItems.range_upgrade);
registerItemModel(WizardryItems.duration_upgrade);
registerItemModel(WizardryItems.cooldown_upgrade);
registerItemModel(WizardryItems.blast_upgrade);
registerItemModel(WizardryItems.attunement_upgrade);
registerItemModel(WizardryItems.flaming_axe);
registerItemModel(WizardryItems.frost_axe);
registerItemModel(WizardryItems.firebomb);
registerItemModel(WizardryItems.poison_bomb);
registerItemModel(WizardryItems.blank_scroll);
registerItemModel(WizardryItems.scroll);
registerItemModel(WizardryItems.armour_upgrade);
registerItemModel(WizardryItems.magic_silk);
registerItemModel(WizardryItems.wizard_hat);
registerItemModel(WizardryItems.wizard_robe);
registerItemModel(WizardryItems.wizard_leggings);
registerItemModel(WizardryItems.wizard_boots);
registerItemModel(WizardryItems.wizard_hat_fire);
registerItemModel(WizardryItems.wizard_robe_fire);
registerItemModel(WizardryItems.wizard_leggings_fire);
registerItemModel(WizardryItems.wizard_boots_fire);
registerItemModel(WizardryItems.wizard_hat_ice);
registerItemModel(WizardryItems.wizard_robe_ice);
registerItemModel(WizardryItems.wizard_leggings_ice);
registerItemModel(WizardryItems.wizard_boots_ice);
registerItemModel(WizardryItems.wizard_hat_lightning);
registerItemModel(WizardryItems.wizard_robe_lightning);
registerItemModel(WizardryItems.wizard_leggings_lightning);
registerItemModel(WizardryItems.wizard_boots_lightning);
registerItemModel(WizardryItems.wizard_hat_necromancy);
registerItemModel(WizardryItems.wizard_robe_necromancy);
registerItemModel(WizardryItems.wizard_leggings_necromancy);
registerItemModel(WizardryItems.wizard_boots_necromancy);
registerItemModel(WizardryItems.wizard_hat_earth);
registerItemModel(WizardryItems.wizard_robe_earth);
registerItemModel(WizardryItems.wizard_leggings_earth);
registerItemModel(WizardryItems.wizard_boots_earth);
registerItemModel(WizardryItems.wizard_hat_sorcery);
registerItemModel(WizardryItems.wizard_robe_sorcery);
registerItemModel(WizardryItems.wizard_leggings_sorcery);
registerItemModel(WizardryItems.wizard_boots_sorcery);
registerItemModel(WizardryItems.wizard_hat_healing);
registerItemModel(WizardryItems.wizard_robe_healing);
registerItemModel(WizardryItems.wizard_leggings_healing);
registerItemModel(WizardryItems.wizard_boots_healing);
registerItemModel(WizardryItems.spectral_helmet);
registerItemModel(WizardryItems.spectral_chestplate);
registerItemModel(WizardryItems.spectral_leggings);
registerItemModel(WizardryItems.spectral_boots);
registerItemModel(WizardryItems.smoke_bomb);
registerItemModel(WizardryItems.identification_scroll);
}
// Moved from the proxies
/** Registers an item model, using the item's registry name as the model name (this
* convention makes it easier to keep track of everything). Variant defaults to "normal". Registers the model
* for metadata 0 automatically, plus all the other metadata values that the item can take, as defined in
* {@link Item#getSubItems(Item, net.minecraft.creativetab.CreativeTabs, java.util.List)}. The passed in item
* <b>must</b> allow null to be passed in for the creative tab parameter in the aforementioned method, or a
* {@link NullPointerException} will result. */
private static void registerItemModel(Item item){
if(item.getHasSubtypes()){
List<ItemStack> items = new ArrayList<ItemStack>();
item.getSubItems(item, null, items); // Client-only method, but we're client-side so this is OK.
for(ItemStack stack : items){
ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(), new ModelResourceLocation(item.getRegistryName(), "inventory"));
}
}
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(item.getRegistryName(), "inventory"));
}
/** Registers an item model for the given metadata, using the item's registry name as the model name (this
* convention makes it easier to keep track of everything). This is intended for registering additional metadata
* values which aren't displayed in the creative menu, for example the wildcard spell book used in wizard trades. */
private static void registerItemModel(Item item, int metadata, String variant) {
ModelLoader.setCustomModelResourceLocation(item, metadata, new ModelResourceLocation(item.getRegistryName(), variant));
}
}
@@ -0,0 +1,72 @@
package electroblob.wizardry.client.particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleBlizzard extends ParticleSnow {
private double angle;
private double radius;
private double speed;
public ParticleBlizzard(World world, int maxAge, double originX, double originZ, double radius, double yPos){
super(world, 0, 0, 0, 0, 0, 0, maxAge);
this.angle = this.rand.nextDouble() * Math.PI * 2;
double x = originX - Math.cos(angle)*radius;
double z = originZ + radius*Math.sin(angle);
this.radius = radius;
this.setPosition(x, yPos, z);
this.prevPosX = x;
this.prevPosY = yPos;
this.prevPosZ = z;
if(rand.nextBoolean()){
speed = rand.nextDouble()*2 + 1;
}else{
speed = rand.nextDouble()*-2 - 1;
}
this.multipleParticleScaleBy(1.5f);
}
@Override
public void init(){
super.init();
this.fullBrightness = true;
}
// @Override
// public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){
// if(this.particleAge < this.particleMaxAge / 3 || (this.particleAge + this.particleMaxAge) / 3 % 2 == 0){
// super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
// }
// }
@Override
public void onUpdate(){
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if(this.particleAge++ >= this.particleMaxAge){
this.setExpired();
}
// This is in radians per tick...
double omega = Math.signum(speed) * ((Math.PI*2)/20 - speed/(20*radius));
// v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi.
this.angle += omega;
this.motionY -= 0.04D * (double)this.particleGravity;
this.motionZ = radius * omega * Math.cos(angle);
this.motionX = radius * omega * Math.sin(angle);
this.moveEntity(motionX, motionY, motionZ);
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
}
}
}
@@ -0,0 +1,195 @@
package electroblob.wizardry.client.particle;
import java.util.List;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
/**
* Abstract superclass for all particles that use custom textures. This is intended to centralise as much code as
* possible; all subclasses need to do is to define the texture to use, how the frames are arranged (and which to
* choose), and any properties like gravity and collisions.
* @author Electroblob
* @since Wizardry 1.2
*/
@SideOnly(Side.CLIENT)
public abstract class ParticleCustomTexture extends Particle {
/** True if the particle always renders at full brightness. Defaults to false. */
protected boolean fullBrightness = false;
public ParticleCustomTexture(World world, double x, double y, double z, double vx, double vy, double vz){
super(world, x, y, z, vx, vy, vz);
this.motionX = vx;
this.motionY = vy;
this.motionZ = vz;
this.init();
}
public ParticleCustomTexture(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){
this(world, x, y, z, vx, vy, vz);
this.particleMaxAge = maxAge;
}
/** Called from both constructors to set constants, avoiding duplicate code. Common fields to set here
* include: particleScale, particleGravity, canCollide, fullBrightness and setting the texture index. */
public abstract void init();
/** Returns a ResourceLocation for the particle's texture sheet. Do not create a new ResourceLocation in this
* method, only return a constant. */
public abstract ResourceLocation getTexture();
/** Returns how many 'frames' there are in the x direction on the texture. */
protected abstract int getXFrames();
/** Returns how many 'frames' there are in the y direction on the texture. */
protected abstract int getYFrames();
/* There are 4 layers of particles, specified as 0-3 by the method below.
* - Layer 0 causes the normal particles.png to be bound to the render engine for normal particles.
* - Layer 1 causes the block textures to be bound to the render engine for digging fx and falling fx.
* - Layer 2 causes the item textures to be bound to the render engine for tool breaking fx, snowballpoofs, slime particles, etc.
* - Layer 3 is not used in vanilla minecraft and was presumably added by forge for exactly this reason.
* This means no texture is bound by vanilla minecraft, meaning you are free to do as you wish without possibly
* overwriting vanilla particles. Mod particles won't be overwritten anyway since they bind their own textures.
* It is of course important to bind the texture every time you render a custom particle, but I don't see how
* you could do it any other way, since you don't have access to EffectRenderer. */
@Override
public int getFXLayer() {
// This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer.
return 3;
}
@Override
public void setParticleTextureIndex(int index){
this.particleTextureIndexX = index % getXFrames();
this.particleTextureIndexY = index / getYFrames();
}
// Overridden to fix the bug with vanilla that makes particles frictionless. (y != y... seriously, Mojang?)
@Override
public void moveEntity(double x, double y, double z){
double d0 = y;
if (this.canCollide)
{
List<AxisAlignedBB> list = this.worldObj.getCollisionBoxes((Entity)null, this.getEntityBoundingBox().addCoord(x, y, z));
for (AxisAlignedBB axisalignedbb : list)
{
y = axisalignedbb.calculateYOffset(this.getEntityBoundingBox(), y);
}
this.setEntityBoundingBox(this.getEntityBoundingBox().offset(0.0D, y, 0.0D));
for (AxisAlignedBB axisalignedbb1 : list)
{
x = axisalignedbb1.calculateXOffset(this.getEntityBoundingBox(), x);
}
this.setEntityBoundingBox(this.getEntityBoundingBox().offset(x, 0.0D, 0.0D));
for (AxisAlignedBB axisalignedbb2 : list)
{
z = axisalignedbb2.calculateZOffset(this.getEntityBoundingBox(), z);
}
this.setEntityBoundingBox(this.getEntityBoundingBox().offset(0.0D, 0.0D, z));
}
else
{
this.setEntityBoundingBox(this.getEntityBoundingBox().offset(x, y, z));
}
this.resetPositionToBB();
this.isCollided = d0 != y && d0 < 0.0D;
/* Can never be true! - But this doesn't seem to make any difference anyway.
if (x != x)
{
this.motionX = 0.0D;
}
if (z != z)
{
this.motionZ = 0.0D;
}
*/
}
// Overridden to bind the new texture. I think this can be done with TextureAtlasSprite, but this works as it is
// so I'm not changing it for the time being.
@Override
public void renderParticle(VertexBuffer buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){
GlStateManager.pushMatrix();
GlStateManager.pushAttrib();
this.applyGLStateChanges();
// This stuff does the shading. It vanilla does this later on for each point, but this also seems to work.
int brightness = this.getBrightnessForRender(partialTicks);
int lightmapX = brightness % 65536;
int lightmapY = brightness / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)lightmapX / 1.0F, (float)lightmapY / 1.0F);
RenderHelper.disableStandardItemLighting();
Minecraft.getMinecraft().getTextureManager().bindTexture(getTexture());
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
float u1 = (float)this.particleTextureIndexX / (float)getXFrames();
float u2 = u1 + 1.0f/getXFrames();
float v1 = (float)this.particleTextureIndexY / (float)getYFrames();
float v2 = v1 + 1.0f/getYFrames();
float scale = 0.1F * this.particleScale;
// I'm pretty sure these were always static.
Particle.interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks;
Particle.interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks;
Particle.interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks;
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
buffer.pos((double)(x - rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), (double)(z - rotationYZ * scale - rotationXZ * scale)).tex(u2, v2).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos((double)(x - rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), (double)(z - rotationYZ * scale + rotationXZ * scale)).tex(u2, v1).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos((double)(x + rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), (double)(z + rotationYZ * scale + rotationXZ * scale)).tex(u1, v1).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos((double)(x + rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), (double)(z + rotationYZ * scale - rotationXZ * scale)).tex(u1, v2).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();;
Tessellator.getInstance().draw();
this.undoGLStateChanges();
GlStateManager.popAttrib();
GlStateManager.popMatrix();
}
/** Override to add any GL state changes, like blending. Does nothing by default. <b>State changes should be
* done using GLStateManager, not using GL11 directly</b> (as is the case with all rendering code now). */
public void applyGLStateChanges(){}
/** Override to undo any GL state changes, like blending. Does nothing by default. <b>State changes should be
* done using GLStateManager, not using GL11 directly</b> (as is the case with all rendering code now). */
public void undoGLStateChanges(){}
@Override
public int getBrightnessForRender(float partialTick){
return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTick);
}
}
@@ -0,0 +1,90 @@
package electroblob.wizardry.client.particle;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleDarkMagic extends Particle {
/** Base spell texture index */
private int baseSpellTextureIndex = 128;
public ParticleDarkMagic(World par1World, double par2, double par4, double par6, double par8, double par10, double par12, float r, float g, float b)
{
super(par1World, par2, par4, par6, par8, par10, par12);
this.motionY *= 0.20000000298023224D;
this.particleRed = r;
this.particleGreen = g;
this.particleBlue = b;
this.particleScale *= 0.75F;
this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D));
this.canCollide = true;
}
@Override
public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ)
{
float f6 = ((float)this.particleAge + partialTicks) / (float)this.particleMaxAge * 32.0F;
if (f6 < 0.0F)
{
f6 = 0.0F;
}
if (f6 > 1.0F)
{
f6 = 1.0F;
}
super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
}
/**
* Called to update the entity's position/logic.
*/
public void onUpdate()
{
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if (this.particleAge++ >= this.particleMaxAge)
{
this.setExpired();
}
this.setParticleTextureIndex(this.baseSpellTextureIndex + (7 - this.particleAge * 8 / this.particleMaxAge));
this.motionY += 0.004D;
this.moveEntity(this.motionX, this.motionY, this.motionZ);
/*
if (this.posY == this.prevPosY)
{
this.motionX *= 1.1D;
this.motionZ *= 1.1D;
}
*/
this.motionX *= 0.9599999785423279D;
this.motionY *= 0.9599999785423279D;
this.motionZ *= 0.9599999785423279D;
if (this.isCollided)
{
this.motionX *= 0.699999988079071D;
this.motionZ *= 0.699999988079071D;
}
}
/**
* Sets the base spell texture index
*/
public void setBaseSpellTextureIndex(int par1)
{
this.baseSpellTextureIndex = par1;
}
}
@@ -0,0 +1,57 @@
package electroblob.wizardry.client.particle;
import net.minecraft.client.particle.Particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleDust extends Particle {
private final boolean shaded;
public ParticleDust(World par1World, double x, double y, double z, double par8, double par10, double par12, float r, float g, float b, boolean shaded)
{
super(par1World, x, y, z, par8, par10, par12);
this.particleRed = r;
this.particleGreen = g;
this.particleBlue = b;
this.setParticleTextureIndex(0);
this.setSize(0.01F, 0.01F);
this.particleScale *= this.rand.nextFloat() + 0.2F;
this.motionX = par8;
this.motionY = par10;
this.motionZ = par12;
this.particleMaxAge = (int)(16.0D / (Math.random() * 0.8D + 0.2D));
this.shaded = shaded;
}
/**
* Called to update the entity's position/logic.
*/
public void onUpdate()
{
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
//this.moveEntity(this.motionX, this.motionY, this.motionZ);
if (this.particleMaxAge-- <= 0)
{
this.setExpired();
}
}
@Override
public int getBrightnessForRender(float par1)
{
return shaded ? super.getBrightnessForRender(par1) : 15728880;
}
/*
@Override
public float getBrightness(float par1)
{
return shaded ? super.getBrightness(par1) : 1.0F;
}
*/
}
@@ -0,0 +1,50 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.particle.Particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleGiantBubble extends Particle
{
/** The name used to identify this particle. Uses the mod id to avoid any possible conflicts (Not that there would
* be any, but I may as well.) */
public static final String NAME = Wizardry.MODID + "magicbubble";
public ParticleGiantBubble(World par1World, double par2, double par4, double par6, double par8, double par10, double par12)
{
super(par1World, par2, par4, par6, par8, par10, par12);
this.particleRed = 1.0F;
this.particleGreen = 1.0F;
this.particleBlue = 1.0F;
this.setParticleTextureIndex(32);
this.setSize(0.02F, 0.02F);
this.particleScale *= this.rand.nextFloat() * 0.6F + 0.2F;
this.motionX = par8 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
this.motionY = par10 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
this.motionZ = par12 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D));
}
/**
* Called to update the entity's position/logic.
*/
public void onUpdate()
{
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
this.motionY += 0.002D;
this.moveEntity(this.motionX, this.motionY, this.motionZ);
this.motionX *= 0.8500000238418579D;
this.motionY *= 0.8500000238418579D;
this.motionZ *= 0.8500000238418579D;
if (this.particleMaxAge-- <= 0)
{
this.setExpired();
}
}
}
@@ -0,0 +1,34 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleIce extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/ice_particles.png");
public ParticleIce(World world, double x, double y, double z, double vx, double vy, double vz){
super(world, x, y, z, vx, vy, vz);
}
public ParticleIce(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
}
@Override
public void init(){
this.setParticleTextureIndex(rand.nextInt(8));
this.particleScale *= 0.75f;
this.particleGravity = 1;
this.canCollide = true;
this.fullBrightness = true;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 4; }
}
@@ -0,0 +1,33 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleLeaf extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/leaf_particles.png");
public ParticleLeaf(World world, double x, double y, double z, double vx, double vy, double vz){
super(world, x, y, z, vx, vy, vz);
}
public ParticleLeaf(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
}
@Override
public void init() {
this.setParticleTextureIndex(rand.nextInt(16));
this.particleScale *= 1.4f;
this.particleGravity = 0;
this.canCollide = true;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 4; }
}
@@ -0,0 +1,47 @@
package electroblob.wizardry.client.particle;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleMagicFlame extends Particle {
/** The scale of the flame particle */
private float flameScale;
public ParticleMagicFlame(World par1World, double par2, double par4, double par6, double par8, double par10, double par12, int maxAge, float scale)
{
super(par1World, par2, par4, par6, par8, par10, par12);
this.motionX = this.motionX * 0.009999999776482582D + par8;
this.motionY = this.motionY * 0.009999999776482582D + par10;
this.motionZ = this.motionZ * 0.009999999776482582D + par12;
this.flameScale = scale;
this.particleRed = this.particleGreen = this.particleBlue = 1.0F;
if(maxAge == 0){
this.particleMaxAge = (int)(2.0D / (Math.random() * 0.8D + 0.2D));
}else{
this.particleMaxAge = maxAge;
}
// IDEA: Make the particles for ray spells collide properly and not spawn on the other side of stuff.
this.canCollide = false;
this.setParticleTextureIndex(48);
}
@Override
public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ)
{
float f6 = ((float)this.particleAge + partialTicks) / (float)this.particleMaxAge;
this.particleScale = this.flameScale * (1.0F - f6 * f6 * 0.5F);
super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
}
@Override
public int getBrightnessForRender(float par1)
{
return 256;
}
}
@@ -0,0 +1,93 @@
package electroblob.wizardry.client.particle;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.spell.Clairvoyance;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticlePath extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/path_particles.png");
private final double originX, originY, originZ;
public ParticlePath(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b){
super(world, x, y, z, vx, vy, vz);
this.setRBGColorF(r, g, b);
this.originX = x;
this.originY = y;
this.originZ = z;
}
public ParticlePath(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
this.setRBGColorF(r, g, b);
this.originX = x;
this.originY = y;
this.originZ = z;
}
@Override
public void init(){
this.setParticleTextureIndex(0);
// Set to a constant to remove the randomness from Particle.
this.particleScale = 1.25f;
this.particleGravity = 0;
this.fullBrightness = true;
this.canCollide = false;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 1; }
@Override protected int getYFrames(){ return 1; }
@Override
public void onUpdate(){
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if (this.particleAge++ >= this.particleMaxAge)
{
this.setExpired();
}
this.moveEntity(this.motionX, this.motionY, this.motionZ);
// Fading
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - 2 * (((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge));
}
if(this.particleAge % Clairvoyance.PARTICLE_MOVEMENT_INTERVAL == 0){
this.setPosition(this.originX, this.originY, this.originZ);
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
}
}
@Override
public void applyGLStateChanges(){
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// TESTME: Are these two actually necessary?
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
}
@Override
public void undoGLStateChanges(){
GlStateManager.disableBlend();
GlStateManager.enableLighting();
}
}
@@ -0,0 +1,59 @@
package electroblob.wizardry.client.particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleRotatingSparkle extends ParticleSparkle {
private double angle;
private double radius;
private double speed;
public ParticleRotatingSparkle(World world, int maxAge, double originX, double originZ, double radius, double yPos, float r, float g , float b){
super(world, 0, 0, 0, 0, 0, 0, r, g, b, maxAge);
this.angle = this.rand.nextDouble() * Math.PI * 2;
double x = originX - Math.cos(angle)*radius;
double z = originZ + radius*Math.sin(angle);
this.radius = radius;
this.setPosition(x, yPos, z);
this.prevPosX = x;
this.prevPosY = yPos;
this.prevPosZ = z;
if(rand.nextBoolean()){
speed = rand.nextDouble()*2 + 1;
}else{
speed = rand.nextDouble()*-2 - 1;
}
this.multipleParticleScaleBy(1.5f);
}
@Override
public void onUpdate(){
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if(this.particleAge++ >= this.particleMaxAge){
this.setExpired();
}
// This is in radians per tick...
double omega = Math.signum(speed) * ((Math.PI*2)/20 - speed/(20*radius));
// v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi.
this.angle += omega;
this.motionY -= 0.04D * (double)this.particleGravity;
this.motionZ = radius * omega * Math.cos(angle);
this.motionX = radius * omega * Math.sin(angle);
this.moveEntity(motionX, motionY, motionZ);
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
}
}
}
@@ -0,0 +1,33 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleSnow extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/snow_particles.png");
public ParticleSnow(World world, double x, double y, double z, double vx, double vy, double vz){
super(world, x, y, z, vx, vy, vz);
}
public ParticleSnow(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
}
@Override
public void init(){
this.setParticleTextureIndex(rand.nextInt(8));
this.particleScale *= 0.6f;
this.particleGravity = 0;
this.canCollide = true;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 4; }
}
@@ -0,0 +1,58 @@
package electroblob.wizardry.client.particle;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleSpark extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/lightning_particles.png");
public ParticleSpark(World world, double x, double y, double z, double vx, double vy, double vz){
// Max age is always 3.
super(world, x, y, z, vx, vy, vz, 3);
}
@Override
public void init(){
// Multiplied by 4 because the index works slightly differently for spark particles.
this.setParticleTextureIndex(rand.nextInt(8)*4);
this.particleScale *= 1.4f;
this.fullBrightness = true;
this.canCollide = false;
}
@Override
public void onUpdate(){
super.onUpdate();
// Well this is handy! Looks like vanilla uses the texture index like this too.
this.nextTextureIndexX();
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 8; }
@Override
public void applyGLStateChanges(){
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// TESTME: Are these two actually necessary?
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
}
@Override
public void undoGLStateChanges(){
GlStateManager.disableBlend();
GlStateManager.enableLighting();
}
}
@@ -0,0 +1,96 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleSparkle extends ParticleCustomTexture {
/* I have now figured out what particle factories are for: they separate out the individual uses of the varargs
* parameter in spawnParticle so they are kept with the particle class. For my purposes, it would be easier to do
* that in the particle spawning method itself. */
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/sparkle_particles.png");
// NOTE: Uncomment once 2.1.0 is released
//private final float initialRed;
//private final float initialGreen;
//private final float initialBlue;
// TODO: Assign these via the constructors, as part of the refactoring for particle parameters.
// NOTE: Uncomment once 2.1.0 is released
// private final float fadeRed = 1;
// private final float fadeGreen = 1;
// private final float fadeBlue = 0;
public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b){
super(world, x, y, z, vx, vy, vz);
this.setRBGColorF(r, g, b);
// NOTE: Uncomment once 2.1.0 is released
//initialRed = r;
//initialGreen = g;
//initialBlue = b;
this.particleMaxAge = 48 + this.rand.nextInt(12);
}
public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
this.setRBGColorF(r, g, b);
// NOTE: Uncomment once 2.1.0 is released
//initialRed = r;
//initialGreen = g;
//initialBlue = b;
}
public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, boolean doGravity){
this(world, x, y, z, vx, vy, vz, r, g, b);
this.particleGravity = doGravity ? 1 : 0;
}
public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, int maxAge, boolean doGravity){
this(world, x, y, z, vx, vy, vz, r, g, b, maxAge);
this.particleGravity = doGravity ? 1 : 0;
}
@Override
public void init(){
this.setParticleTextureIndex(rand.nextInt(16));
this.particleScale *= 0.75f;
this.particleGravity = 0;
this.canCollide = false;
this.fullBrightness = true;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 4; }
@Override
public void onUpdate(){
super.onUpdate();
// Fading
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
}
// Colour fading TODO Uncomment once 2.1.0 is released
// float ageFraction = (float)this.particleAge / (float)this.particleMaxAge;
// this.setRBGColorF(this.initialRed + (this.fadeRed - this.initialRed)*ageFraction,
// this.initialGreen + (this.fadeGreen - this.initialGreen)*ageFraction,
// this.initialBlue + (this.fadeBlue - this.initialBlue)*ageFraction);
//
// this.setParticleTextureIndex((this.particleAge * 11)/this.particleMaxAge);
}
/*
* As a side note, I see a lot of magic mods with fancy-looking particle effects that really seem to 'glow'. It's
* actually not that hard - you simply create a reasonably high-res texture with translucency and then set the
* OpenGL blend function to something like SRC_ALPHA, SRC_ALPHA or ONE, ONE. The thing is... they're not very
* Minecraft-y. I still maintain that part of wizardry's appeal is that it stays true to the game's pixelated charm,
* rather than trying to make it something it's not. Still, the newer textures are much better than the defaults I
* used to use.
*/
}
@@ -0,0 +1,83 @@
package electroblob.wizardry.client.particle;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.particle.ParticleDigging;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleTornado extends ParticleDigging {
private double angle;
private double radius;
private double speed;
/** Velocity of the tornado itself; in other words the velocity of the point the particle circles around. */
private double velX, velZ;
private boolean fullBrightness = false;
public ParticleTornado(World world, int maxAge, double originX, double originZ, double radius, double yPos, double velX, double velZ, IBlockState block){
super(world, 0, 0, 0, 0, 0, 0, block);
this.angle = this.rand.nextDouble() * Math.PI * 2;
double x = originX - Math.cos(angle)*radius;
double z = originZ + radius*Math.sin(angle);
this.radius = radius;
this.setPosition(x, yPos, z);
this.prevPosX = x;
this.prevPosY = yPos;
this.prevPosZ = z;
//this.particleScale *= 0.75F;
this.particleMaxAge = maxAge;
this.canCollide = false;
// Grass has special treatment, since it has a colourised top but the rest is normal.
// Commented out for now since vanilla does something about this now, but I'm not sure what exactly
//if(block.getBlock() != Blocks.GRASS || side == 1) this.setColour(block.getRenderColor(side));
// Blocks that emit light are rendered with full brightness.
if(block.getLightValue(world, new BlockPos(this.posX, this.posY, this.posZ)) == 0){
this.particleRed *= 0.75;
this.particleGreen *= 0.75;
this.particleBlue *= 0.75;
}else{
this.fullBrightness = true;
}
speed = rand.nextDouble()*2 + 1;
this.velX = velX;
this.velZ = velZ;
}
@Override
public void onUpdate(){
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if(this.particleAge++ >= this.particleMaxAge){
this.setExpired();
}
// This is in radians per tick...
double omega = Math.signum(speed) * ((Math.PI*2)/20 - speed/(20*radius));
// v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi.
this.angle += omega;
this.motionZ = radius * omega * Math.cos(angle);
this.motionX = radius * omega * Math.sin(angle);
this.moveEntity(motionX + velX, 0, motionZ + velZ);
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
}
}
@Override
public int getBrightnessForRender(float partialTicks){
return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTicks);
}
}
@@ -0,0 +1,191 @@
package electroblob.wizardry.client.renderer;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map.Entry;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.ClientProxy;
import electroblob.wizardry.spell.Petrify;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderLivingBase;
import net.minecraft.client.renderer.entity.RenderZombie;
import net.minecraft.client.renderer.entity.layers.LayerRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
/**
* Layer used to render the stone texture on a petrified creature. Handles dynamic tiling of the stone texture and
* reflective access for classes that don't play nicely (looking at you, {@link RenderZombie}).
* @author Electroblob
* @since Wizardry 1.2
*/
public class LayerStone implements LayerRenderer<EntityLivingBase> {
protected ModelBase model;
private final RenderLivingBase<?> renderer;
private static final ResourceLocation texture = new ResourceLocation("textures/blocks/stone.png");
private static final Field zombieLayers = ReflectionHelper.findField(RenderZombie.class, "defaultLayers", "field_177122_o");
private static final Field zombieVillagerLayers = ReflectionHelper.findField(RenderZombie.class, "villagerLayers", "field_177121_n");
private static final Method swapZombieModel = ReflectionHelper.findMethod(RenderZombie.class, null,
new String[]{"swapArmor", "func_82427_a"}, EntityZombie.class); // Second parameter (null) is unused
@SuppressWarnings("unchecked") // The compiler is being annoying and I know that what I'm doing is type-safe.
public static void initialiseLayers(){
for(Entry<Class<? extends Entity>, Render<? extends Entity>> entry : Minecraft.getMinecraft().getRenderManager().entityRenderMap.entrySet()){
// Zombies don't play nicely because they have their own, private lists of layers for the regular zombie
// and the zombie villager, which are assigned within the constructor for RenderZombie and swapped out
// as necessary. However, Mojang, in their infinite wisdom, haven't bothered to override addLayer to
// modify those internal lists, so that method is useless.
if(entry.getValue() instanceof RenderZombie){
try {
Object layers = zombieLayers.get(entry.getValue());
if(layers instanceof List<?>){
// Nice as the layer renderer system is, it doesn't lend itself to reflective access.
// I KNOW that 'layers' (which was obtained using reflection) is of the type
// List<LayerRenderer<EntityZombie>>, because that's what it's declared as. However, if I cast
// 'layers' to List<LayerRenderer<EntityZombie>>, I can't add a LayerStone because it's only a
// LayerRenderer<EntityLivingBase>, not a LayerRenderer<EntityZombie>.
((List<LayerRenderer<EntityLivingBase>>)layers).add(new LayerStone((RenderLivingBase<?>)entry.getValue()));
}
layers = zombieVillagerLayers.get(entry.getValue());
if(layers instanceof List<?>){
((List<LayerRenderer<EntityLivingBase>>)layers).add(new LayerStone((RenderLivingBase<?>)entry.getValue()));
}
} catch (IllegalArgumentException | IllegalAccessException e){
Wizardry.logger.error("Error while reflectively accessing zombie render layers");
e.printStackTrace();
}
}else if(entry.getValue() instanceof RenderLivingBase){
// Adds a stone layer to all the living entity renderers in the game. Whether it is actually rendered
// is decided in doRenderLayer below on a per-entity basis.
((RenderLivingBase<?>)entry.getValue()).addLayer(new LayerStone((RenderLivingBase<?>)entry.getValue()));
}
// NOTE: May have to do some special stuff for players if they are to be added; see Minecraft.getMinecraft().getRenderManager().getSkinMap()
}
}
public LayerStone(RenderLivingBase<?> renderer){
this.renderer = renderer;
this.model = renderer.getMainModel();
}
@Override
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){
if(entity.getEntityData().getBoolean(Petrify.NBT_KEY)){
GlStateManager.enableLighting();
int i = this.getBlockBrightnessForEntity(entity, partialTicks);
int j = i % 65536;
int k = i / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);
ResourceLocation breakingTexture = ClientProxy.renderStatue.getBlockBreakingTexture();
if(breakingTexture != null){
// Block breaking animation
// TODO: Spider eyes and enderman eyes (any others?) show through the stone when the block is being broken...
GlStateManager.enableBlend();
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
this.renderer.bindTexture(breakingTexture);
this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
GlStateManager.disableBlend();
}else{
// Stone texture
this.renderer.bindTexture(texture);
this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
}
}
}
private int getBlockBrightnessForEntity(Entity entity, float partialTicks){
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(MathHelper.floor_double(entity.posX), 0, MathHelper.floor_double(entity.posZ));
if(entity.worldObj.isBlockLoaded(pos)){
pos.setY(MathHelper.floor_double(entity.posY + (double)entity.getEyeHeight()));
return entity.worldObj.getCombinedLight(pos, 0);
}else{
return 0;
}
}
private void renderEntityModel(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){
GlStateManager.pushMatrix();
// Enables tiling (Also used for guardian beam, beacon beam and ender crystal beam)
// TODO: Backport this improvement
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
GlStateManager.depthMask(true); // Some entities set depth mask to false (i.e. no sorting of faces by depth)
// In particular, LayerSpiderEyes sets it to false when the spider is invisible, for some reason.
// Changes the scale at which the texture is applied to the model. See LayerCreeper for a similar example,
// but with translation instead of scaling.
GlStateManager.matrixMode(GL11.GL_TEXTURE);
GlStateManager.loadIdentity();
double scaleX = 1, scaleY = 1;
// It's more logical to use the model's texture size, but some classes don't bother setting it properly
// (e.g. ModelVillager), so to get the correct dimensions I'm getting them from the first box instead.
if(model.boxList != null && model.boxList.get(0) != null){
scaleX = (double)model.boxList.get(0).textureWidth/16d;
scaleY = (double)model.boxList.get(0).textureHeight/16d;
}else{ // Fallback to model fields; should never be needed
scaleX = (double)model.textureWidth/16d;
scaleY = (double)model.textureHeight/16d;
}
GlStateManager.scale(scaleX, scaleY, 1);
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
// Lets RenderZombie do its (stupid and inflexible) model switching thing
if(this.renderer instanceof RenderZombie && entity instanceof EntityZombie){
try {
swapZombieModel.invoke(this.renderer, entity);
this.model = this.renderer.getMainModel();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
Wizardry.logger.error("Error while reflectively calling RenderZombie#swapArmor");
e.printStackTrace();
}
}
// Hides the hat layer for bipeds
if(this.model instanceof ModelBiped) ((ModelBiped) this.model).bipedHeadwear.isHidden = true;
this.model.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks);
this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale);
if(this.model instanceof ModelBiped) ((ModelBiped) this.model).bipedHeadwear.isHidden = false;
// Undoes the texture scaling
GlStateManager.matrixMode(GL11.GL_TEXTURE);
GlStateManager.loadIdentity();
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
GlStateManager.popMatrix();
}
@Override
public boolean shouldCombineTextures(){
return false;
}
}
@@ -0,0 +1,48 @@
package electroblob.wizardry.client.renderer;
/** Instances of this class can calculate their distance from the camera viewpoint and sort themselves accordingly. */
class RayHelper implements Comparable<RayHelper> {
int ordinal;
double x1, y1, z1;
double x2, y2, z2;
double offsetX, offsetY, offsetZ;
RayHelper(int ordinal, double x1, double y1, double z1, double x2, double y2, double z2, double offsetX, double offsetY, double offsetZ){
this.ordinal = ordinal;
this.x1 = x1;
this.y1 = y1;
this.z1 = z1;
this.x2 = x2;
this.y2 = y2;
this.z2 = z2;
this.offsetX = offsetX;
this.offsetY = offsetY;
this.offsetZ = offsetZ;
}
double getDistanceFromViewpoint(){
double midX = (x1+x2)/2;
double midY = (y1+y2)/2;
double midZ = (z1+z2)/2;
double absoluteX = offsetX+midX;
double absoluteY = offsetY+midY;
double absoluteZ = offsetZ+midZ;
return Math.sqrt(absoluteX*absoluteX + absoluteY*absoluteY + absoluteZ*absoluteZ);
}
@Override
public int compareTo(RayHelper ray){
if(this.getDistanceFromViewpoint() > ray.getDistanceFromViewpoint()){
return -1;
}else if(this.getDistanceFromViewpoint() < ray.getDistanceFromViewpoint()){
return 1;
}else{
return 0;
}
}
}
@@ -0,0 +1,129 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.EntityArc;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderArc extends Render<EntityArc> {
private static final ResourceLocation[] textures = new ResourceLocation[16];
public RenderArc(RenderManager renderManager){
super(renderManager);
for(int i=0;i<16;i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/arc_" + i + ".png");
}
}
@Override
public void doRender(EntityArc arc, double d0, double d1, double d2,
float fa, float fb) {
GlStateManager.pushMatrix();
GlStateManager.translate((float)d0, (float)d1, (float)d2);
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); //This line fixes the weird brightness bug.
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
//System.out.println("Entity coords: " + entity.posX + ", " + entity.posY + ", " + entity.posZ);
//System.out.println("doRender parameters: " + d0 + ", " + d1 + ", " + d2 + ", " + fa + ", " + fb);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
bindTexture(textures[arc.textureIndex]); // This MUST be after the tessellator declaration and the gl stuff
/**
* Note: A lot of the maths here works on similar triangles and the ratios between them, avoiding too much
* pythagoras and eliminating the need for any trig. Ratios are used for the positioning of the arc endpoints.
* Ratios are usually used swapping x and z because the triangles are rotated through 90 degrees.
*/
double dx = -d0;
double dy = -d1;
double dz = -d2;
if(arc.x1 != 0){
dx = arc.x1 - arc.posX;// - d2/lengthOffsetRatio;
dy = arc.y1 - arc.posY + 0.3;
dz = arc.z1 - arc.posZ;// + d0/lengthOffsetRatio;
//The distance from caster to target
double arcLength = Math.sqrt(dz*dz+dx*dx);
//The ratio between the length of the arc and the offset of the start point from the player's centre (which is always 0.3).
//double lengthOffsetRatio = arcLength/0.3;
//EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer;
//double xViewDist = player.posX - d0;
//double yViewDist = player.posY + player.eyeHeight - d1;
//double zViewDist = player.posZ - d2;
//double xzViewDist = Math.sqrt(xViewDist * xViewDist + zViewDist * zViewDist);
//The angle above the horizontal that this particular player is viewing the arc from
//double viewAngle = Math.atan(yViewDist/xzViewDist);
//Half the width of the arc
double arcWidth = 0.3d;
//Right hand side of vertical plane
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//Target end
buffer.pos(0, -0.5, 0).tex(1, 1).endVertex();
buffer.pos(0, 0.5, 0).tex(1, 0).endVertex();
//Caster end
buffer.pos(dx, dy, dz).tex(0, 0).endVertex();
buffer.pos(dx, dy-1, dz).tex(0, 1).endVertex();
tessellator.draw();
//Left
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
//Target end
buffer.pos(0, -0.5, 0).tex(1, 1).endVertex();
//Caster end
buffer.pos(dx, dy-1, dz).tex(0, 1).endVertex();
buffer.pos(dx, dy, dz).tex(0, 0).endVertex();
//Target end
buffer.pos(0, 0.5, 0).tex(1, 0).endVertex();
tessellator.draw();
//Bottom of horizontal plane
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos((arcWidth/arcLength)*dz, 0, (-arcWidth/arcLength)*dx).tex(1, 1).endVertex();
buffer.pos(dx + (arcWidth/arcLength)*dz, dy-0.5, dz - (arcWidth/arcLength)*dx).tex(0, 1).endVertex();
buffer.pos(dx - (arcWidth/arcLength)*dz, dy-0.5, dz + (arcWidth/arcLength)*dx).tex(0, 0).endVertex();
buffer.pos((-arcWidth/arcLength)*dz, 0, (arcWidth/arcLength)*dx).tex(1, 0).endVertex();
tessellator.draw();
//Top
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos((arcWidth/arcLength)*dz, 0, (-arcWidth/arcLength)*dx).tex(1, 1).endVertex();
buffer.pos((-arcWidth/arcLength)*dz, 0, (arcWidth/arcLength)*dx).tex(1, 0).endVertex();
buffer.pos(dx - (arcWidth/arcLength)*dz, dy-0.5, dz + (arcWidth/arcLength)*dx).tex(0, 0).endVertex();
buffer.pos(dx + (arcWidth/arcLength)*dz, dy-0.5, dz - (arcWidth/arcLength)*dx).tex(0, 1).endVertex();
tessellator.draw();
}
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityArc entity) {
return textures[entity.textureIndex];
}
}
@@ -0,0 +1,99 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
public class RenderArcaneWorkbench extends TileEntitySpecialRenderer<TileEntityArcaneWorkbench> {
private static final ResourceLocation runeTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/rune.png");
public RenderArcaneWorkbench(){}
@Override
public void renderTileEntityAt(TileEntityArcaneWorkbench tileentity, double x, double y, double z, float partialTicks, int destroyStage) {
GlStateManager.pushMatrix();
// This line makes stuff render in the same place relative to the world wherever the player is.
GlStateManager.translate((float)x + 0.5F, (float)y + 1.5F, (float)z + 0.5F);
GlStateManager.rotate(180, 0F, 0F, 1F);
GlStateManager.pushMatrix();
double angle = 0.0d;
if(x < -0.5){
angle = Math.toDegrees(Math.atan((z+0.5)/(x+0.5))) + 180;
}else{
angle = Math.toDegrees(Math.atan((z+0.5)/(x+0.5)));
}
this.renderEffect(tileentity);
this.renderWand(tileentity, angle);
GlStateManager.popMatrix();
GlStateManager.popMatrix();
}
private void renderEffect(TileEntityArcaneWorkbench tileentity) {
ItemStack itemstack = tileentity.getStackInSlot(ContainerArcaneWorkbench.WAND_SLOT);
if(itemstack != null){
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); //This line fixes the weird brightness bug.
GlStateManager.rotate(tileentity.timer, 0.0f, 1.0f, 0.0f);
GlStateManager.translate(0.0f, 0.65f, 0.0f);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
bindTexture(runeTexture);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5f, 0, -0.5f).tex(0, 0).endVertex();
buffer.pos(0.5f, 0, -0.5f).tex(1, 0).endVertex();
buffer.pos(0.5f, 0, 0.5f).tex(1, 1).endVertex();
buffer.pos(-0.5f, 0, 0.5f).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
}
/**
* Renders the wand on the workbench as 3D on the model. Currently doesn't do much on 'fast' graphics!
* @param tileentity The instance of the workbench tile entity
*/
private void renderWand(TileEntityArcaneWorkbench tileentity, double viewAngle)
{
ItemStack stack = tileentity.getStackInSlot(ContainerArcaneWorkbench.WAND_SLOT);
if(stack != null){
GlStateManager.pushMatrix();
GlStateManager.rotate(180.0F, 1.0F, 0.0F, 0.0F);
GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F);
GlStateManager.rotate(180, 0, 1, 0);
// View angle is negated because of the 180 flip.
GlStateManager.rotate((float)(-viewAngle-90f), 0, 0, 1);
// Does the floaty thing
GlStateManager.translate(0.0F, 0.0F, (float)tileentity.yOffset/5000.0F - 0.55f);
GlStateManager.scale(0.75F, 0.75F, 0.75F);
// This is what the item frame uses so it's definitely what we want.
Minecraft.getMinecraft().getRenderItem().renderItem(stack, TransformType.FIXED);
GlStateManager.popMatrix();
}
}
}
@@ -0,0 +1,180 @@
package electroblob.wizardry.client.renderer;
import java.util.ArrayList;
import java.util.Collections;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityBlackHole;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderBlackHole extends Render<EntityBlackHole> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/dark_ray.png");
private static final ResourceLocation texture2 = new ResourceLocation(Wizardry.MODID, "textures/entity/black_hole.png");
public RenderBlackHole(RenderManager renderManager) {
super(renderManager);
}
@Override
public void doRender(EntityBlackHole blackhole, double x, double y, double z, float fa, float fb) {
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
RenderHelper.disableStandardItemLighting();
GlStateManager.translate(x, y, z);
//float pitch = (float) Math.toDegrees(Math.atan(y/(x*x+z*z)));
//float yaw = (float) Math.toDegrees(Math.atan(x/z));
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
if(blackhole.ticksExisted < 10){
GlStateManager.scale((float)blackhole.ticksExisted/10, (float)blackhole.ticksExisted/10, (float)blackhole.ticksExisted/10);
}
if(blackhole.ticksExisted > blackhole.lifetime - 10){
GlStateManager.scale((float)(blackhole.lifetime-blackhole.ticksExisted)/10, (float)(blackhole.lifetime-blackhole.ticksExisted)/10, (float)(blackhole.lifetime-blackhole.ticksExisted)/10);
}
this.bindTexture(texture);
// In theory this stuff should sort the rays into the correct render order based on the distance from
// the 'camera' (i.e. the player's viewpoint)
// In the end it was easier to do away with the openGL rotation because for some reason it produced
// coordinates which were inconsistent with my calculated ones. Since I know those will give the desired
// effect anyway, I just used them directly instead.
ArrayList<RayHelper> rays = new ArrayList<RayHelper>(1);
for(int j=0; j<30; j++){
float scale = 3.0f;
int a = blackhole.randomiser[j];
int b = blackhole.randomiser2[j];
int sliceAngle = 20 + a;
double x1 = scale*Math.sin((blackhole.ticksExisted + 40*j)*(Math.PI/180));
//double y1 = 0.7*Math.cos((blackhole.timer - 40*j)*(Math.PI/180))*j/10;
double z1 = scale*Math.cos((blackhole.ticksExisted + 40*j)*(Math.PI/180));
double x2 = scale*Math.sin((blackhole.ticksExisted + 40*j - sliceAngle)*(Math.PI/180));
//double y2 = 0.7*Math.sin((blackhole.timer - 40*j)*(Math.PI/180))*j/10;
double z2 = scale*Math.cos((blackhole.ticksExisted + 40*j - sliceAngle)*(Math.PI/180));
double absoluteX = x1*Math.cos(31*b);
double absoluteY = z1*Math.sin(31*a) + x1*Math.cos(31*a)*Math.sin(31*b);
double absoluteZ = z1*Math.cos(31*a);
double absoluteX2 = x2*Math.cos(31*b);
double absoluteY2 = z2*Math.sin(31*a) + x2*Math.cos(31*a)*Math.sin(31*b);
double absoluteZ2 = z2*Math.cos(31*a);
/*
buffer.begin(0, DefaultVertexFormats.POSITION_TEX);
tessellator.setColorOpaque(255, 255, 255);
GL11.glPointSize(5);
tessellator.addVertex(absoluteX-x, 0, 0);
tessellator.addVertex(0, absoluteY-y, 0);
tessellator.addVertex(0, 0, absoluteZ-z);
tessellator.draw();
*/
rays.add(new RayHelper(j, absoluteX, absoluteY, absoluteZ, absoluteX2, absoluteY2, absoluteZ2, x, y, z));
}
Collections.sort(rays);
for(RayHelper ray : rays){
GlStateManager.pushMatrix();
//GlStateManager.rotate(31*blackhole.randomiser[ray.ordinal], 1, 0, 0);
//GlStateManager.rotate(31*blackhole.randomiser2[ray.ordinal], 0, 0, 1);
buffer.begin(5, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA(255, 255, 255, 0);
buffer.pos(0, 0, 0).tex(0, 0).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
//tessellator.setColorRGBA(0, 0, 0, 255);
buffer.pos(ray.x1, ray.y1, ray.z1).tex(1, 0).endVertex();
buffer.pos(ray.x2, ray.y2, ray.z2).tex(1, 1).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
}
GlStateManager.pushMatrix();
/* Deprecated in favour of particle style method.
GlStateManager.rotate(yaw, 0, 1, 0);
// GL transformations are relative, hence only x rotation
if(z < 0){
GlStateManager.rotate(pitch, 1, 0, 0);
}else{
GlStateManager.rotate(-1*pitch, 1, 0, 0);
}
*/
// Renders the aura effect
// This counteracts the reverse rotation behaviour when in front f5 view. Vanilla now has this fix too.
float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? this.renderManager.playerViewX : -this.renderManager.playerViewX;
GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
this.bindTexture(texture2);
buffer.pos(-0.4, 0.4, 0).tex(0, 0).endVertex();
buffer.pos(0.4, 0.4, 0).tex(1, 0).endVertex();
buffer.pos(0.4, -0.4, 0).tex(1, 1).endVertex();
buffer.pos(-0.4, -0.4, 0).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableCull();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
RenderHelper.enableStandardItemLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityBlackHole entity) {
return texture;
}
}
@@ -0,0 +1,25 @@
package electroblob.wizardry.client.renderer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
public class RenderBlank extends Render<Entity> {
public RenderBlank(RenderManager renderManager) {
super(renderManager);
}
@Override
public void doRender(Entity entity, double d0, double d1, double d2,
float f, float f1) {
}
@Override
protected ResourceLocation getEntityTexture(Entity entity) {
return null;
}
}
@@ -0,0 +1,104 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityBubble;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderBubble extends Render<EntityBubble> {
private static final ResourceLocation particleTextures = new ResourceLocation("textures/particle/particles.png");
private static final ResourceLocation darkOrbTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/dark_orb.png");
public RenderBubble(RenderManager renderManager) {
super(renderManager);
}
@Override
public void doRender(EntityBubble entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
if(WizardryUtilities.getRider(entity) != null){
yOffset = WizardryUtilities.getRider(entity).height/2;
}
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(((EntityBubble)entity).isDarkOrb ? darkOrbTexture : particleTextures);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
if(((EntityBubble)entity).isDarkOrb){
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
}else{
int j = entity.getBrightnessForRender(par9);
int k = j % 65536;
int l = j / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)k / 1.0F, (float)l / 1.0F);
}
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? this.renderManager.playerViewX : -this.renderManager.playerViewX;
GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
float f11 = 3.0F;
GlStateManager.scale(f11, f11, f11);
double pixelwidth = (1.0d/128);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA_I(k1, 128);
//buffer.normal(0.0F, 1.0F, 0.0F);
if(((EntityBubble)entity).isDarkOrb){
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.0D).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.0D).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.0D).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.0D).tex(0, 0).endVertex();
}else{
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.0D).tex(pixelwidth, pixelwidth * 24).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.0D).tex(pixelwidth*8, pixelwidth * 24).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.0D).tex(pixelwidth*8, pixelwidth * 17).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.0D).tex(pixelwidth, pixelwidth * 17).endVertex();
}
tessellator.draw();
GlStateManager.disableBlend();
if(((EntityBubble)entity).isDarkOrb){
GlStateManager.enableLighting();
}
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityBubble entity) {
return null;
}
}
@@ -0,0 +1,74 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityDecay;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderDecay extends Render<EntityDecay> {
private static final ResourceLocation[] textures = new ResourceLocation[10];
public RenderDecay(RenderManager renderManager){
super(renderManager);
for(int i=0;i<10;i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/decay_" + i + ".png");
}
}
@Override
public void doRender(EntityDecay entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(textures[((EntityDecay)entity).textureIndex]);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
float scale = 2*Math.min(1, (float)(EntityDecay.LIFETIME - entity.ticksExisted)/50f);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA_I(k1, 128);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityDecay entity) {
return null;
}
}
@@ -0,0 +1,108 @@
package electroblob.wizardry.client.renderer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.living.EntityDecoy;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderBiped;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// TODO: Backport the rewrite of this entire class.
@SideOnly(Side.CLIENT)
public class RenderDecoy extends RenderBiped<EntityDecoy> {
private static final ResourceLocation steveTextures = new ResourceLocation("textures/entity/steve.png");
private static final Method getEntityTexture = ReflectionHelper.findMethod(Render.class, null,
new String[]{"getEntityTexture", "func_110775_a"}, Entity.class); // Generic parameter T is erased to Entity at runtime.
public RenderDecoy(RenderManager manager){
super(manager, new ModelBiped(0.0f), 0.5f);
}
@Override
public void doRender(EntityDecoy entity, double x, double y, double z, float entityYaw, float partialTicks) {
if(entity.getCaster() != null){
this.renderName(entity, x, y, z);
// Save relevant animation fields from the caster to local variables
float pitch = entity.getCaster().rotationPitch;
float prevPitch = entity.getCaster().prevRotationPitch;
float swing = entity.getCaster().swingProgress;
float prevSwing = entity.getCaster().prevSwingProgress;
float yawOffset = entity.getCaster().renderYawOffset;
float prevYawOffset = entity.getCaster().prevRenderYawOffset;
float yaw = entity.getCaster().rotationYawHead;
float prevYaw = entity.getCaster().prevRotationYawHead;
float limbSwing = entity.getCaster().limbSwing;
float limbSwingAmount = entity.getCaster().limbSwingAmount;
float prevLimbSwingAmount = entity.getCaster().prevLimbSwingAmount;
int hurtTime = entity.getCaster().hurtTime;
boolean sneak = entity.getCaster().isSneaking();
Entity mount = entity.getCaster().getRidingEntity();
// Assign decoy's animation fields to the caster
entity.getCaster().rotationPitch = entity.rotationPitch;
entity.getCaster().prevRotationPitch = entity.prevRotationPitch;
entity.getCaster().swingProgress = entity.swingProgress;
entity.getCaster().prevSwingProgress = entity.prevSwingProgress;
entity.getCaster().renderYawOffset = entity.renderYawOffset;
entity.getCaster().prevRenderYawOffset = entity.prevRenderYawOffset;
entity.getCaster().rotationYawHead = entity.rotationYawHead;
entity.getCaster().prevRotationYawHead = entity.prevRotationYawHead;
entity.getCaster().limbSwing = entity.limbSwing;
entity.getCaster().limbSwingAmount = entity.limbSwingAmount;
entity.getCaster().prevLimbSwingAmount = entity.prevLimbSwingAmount;
entity.getCaster().hurtTime = entity.hurtTime;
entity.getCaster().setSneaking(false); // Decoys can't sneak FIXME Not working!
entity.getCaster().dismountRidingEntity(); // Decoys can't ride anything
// Do the rendering
renderManager.getEntityRenderObject(entity.getCaster()).doRender(entity.getCaster(), x, y, z, entityYaw, partialTicks);
// Reset caster's animation fields to their original values
entity.getCaster().rotationPitch = pitch;
entity.getCaster().prevRotationPitch = prevPitch;
entity.getCaster().swingProgress = swing;
entity.getCaster().prevSwingProgress = prevSwing;
entity.getCaster().renderYawOffset = yawOffset;
entity.getCaster().prevRenderYawOffset = prevYawOffset;
entity.getCaster().rotationYawHead = yaw;
entity.getCaster().prevRotationYawHead = prevYaw;
entity.getCaster().limbSwing = limbSwing;
entity.getCaster().limbSwingAmount = limbSwingAmount;
entity.getCaster().prevLimbSwingAmount = prevLimbSwingAmount;
entity.getCaster().hurtTime = hurtTime;
entity.getCaster().setSneaking(sneak);
if(mount != null) entity.getCaster().startRiding(mount);
}else{
super.doRender(entity, x, y, z, entityYaw, partialTicks);
}
}
@Override
protected ResourceLocation getEntityTexture(EntityDecoy entity){
if(entity.getCaster() != null){
try {
return (ResourceLocation)getEntityTexture.invoke(renderManager.getEntityRenderObject(entity.getCaster()));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassCastException e){
Wizardry.logger.error("Error while reflectively calling Render#getEntityTexture as part of decoy rendering");
e.printStackTrace();
}
}
// Fallback to steve textures
return steveTextures;
}
}
@@ -0,0 +1,34 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelWizard;
import electroblob.wizardry.entity.living.EntityEvilWizard;
import net.minecraft.client.renderer.entity.RenderBiped;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.layers.LayerBipedArmor;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderEvilWizard extends RenderBiped<EntityEvilWizard>
{
static final ResourceLocation[] textures = new ResourceLocation[6];
public RenderEvilWizard(RenderManager renderManager){
super(renderManager, new ModelWizard(), 0.5F);
for(int i=0;i<6;i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/evil_wizard_" + i + ".png");
}
// Just using the default without overriding models, since the armour sets its own model anyway.
this.addLayer(new LayerBipedArmor(this));
}
@Override
protected ResourceLocation getEntityTexture(EntityEvilWizard wizard) {
return textures[wizard.textureIndex];
}
}
@@ -0,0 +1,180 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.construct.EntityFireRing;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation;
public class RenderFireRing extends Render<EntityFireRing> {
private final ResourceLocation texture;
private float scale = 1.0f;
public RenderFireRing(RenderManager renderManager, ResourceLocation texture, float scale) {
super(renderManager);
this.texture = texture;
this.scale = scale;
}
@Override
public void doRender(EntityFireRing entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(texture);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
// Fire
GlStateManager.disableLighting();
TextureAtlasSprite icon = Minecraft.getMinecraft().getBlockRendererDispatcher().getModelForState(Blocks.FIRE.getDefaultState()).getParticleTexture();
int sides = 16;
float height = 1.0f;
for(int k=0; k<sides; k++){
GlStateManager.pushMatrix();
GlStateManager.translate((float)par2, (float)par4 + 0.05f, (float)par6);
float f1 = 1.0f;
GlStateManager.scale(f1, f1, f1);
float f2 = 0.5F;
float f3 = 0.0F;
float f4 = 0.2f;
float f5 = (float)(entity.posY - entity.getEntityBoundingBox().minY);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
float f61 = 0.0F;
int i = 0;
GlStateManager.rotate((360f/(float)sides)*k, 0, 1, 0);
GlStateManager.translate(0, 0, -2.3f);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
while (f4 > 0.0F){
this.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
float f71 = icon.getMinU();
float f81 = icon.getMinV();
float f9 = icon.getMaxU();
float f10 = icon.getMaxV();
if (i / 2 % 2 == 0)
{
float f11 = f9;
f9 = f71;
f71 = f11;
}
buffer.pos((double)(f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f9, (double)f10).endVertex();
buffer.pos((double)(-f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f71, (double)f10).endVertex();
buffer.pos((double)(-f2 - f3), (double)(height - f5), (double)f61).tex((double)f71, (double)f81).endVertex();
buffer.pos((double)(f2 - f3), (double)(height - f5), (double)f61).tex((double)f9, (double)f81).endVertex();
f4 -= 0.45F;
f5 -= 0.45F;
f2 *= 0.9F;
f61 += 0.03F;
++i;
}
tessellator.draw();
GlStateManager.popMatrix();
}
for(int k=0; k<sides; k++){
GlStateManager.pushMatrix();
GlStateManager.translate((float)par2, (float)par4 + 0.05f, (float)par6);
float f1 = 1.0f;
GlStateManager.scale(f1, f1, f1);
float f2 = 0.5F;
float f3 = 0.0F;
float f4 = 0.2f;
float f5 = (float)(entity.posY - entity.getEntityBoundingBox().minY);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
float f61 = 0.0F;
int i = 0;
GlStateManager.rotate((360f/(float)sides)*k, 0, 1, 0);
GlStateManager.translate(0, 0, 2.3f);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
while (f4 > 0.0F){
this.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
float f71 = icon.getMinU();
float f81 = icon.getMinV();
float f9 = icon.getMaxU();
float f10 = icon.getMaxV();
if (i / 2 % 2 == 0)
{
float f11 = f9;
f9 = f71;
f71 = f11;
}
buffer.pos((double)(f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f9, (double)f10).endVertex();
buffer.pos((double)(-f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f71, (double)f10).endVertex();
buffer.pos((double)(-f2 - f3), (double)(height - f5), (double)f61).tex((double)f71, (double)f81).endVertex();
buffer.pos((double)(f2 - f3), (double)(height - f5), (double)f61).tex((double)f9, (double)f81).endVertex();
f4 -= 0.45F;
f5 -= 0.45F;
f2 *= 0.9F;
f61 += 0.03F;
++i;
}
tessellator.draw();
GlStateManager.popMatrix();
}
GlStateManager.enableLighting();
}
@Override
protected ResourceLocation getEntityTexture(EntityFireRing entity) {
return null;
}
}
@@ -0,0 +1,127 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.projectile.EntityForceArrow;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderForceArrow extends Render<EntityForceArrow>{
private static final ResourceLocation arrowTextures = new ResourceLocation(Wizardry.MODID, "textures/entity/force_arrow.png");
public RenderForceArrow(RenderManager renderManager){
super(renderManager);
}
@Override
public void doRender(EntityForceArrow arrow, double par2, double par4, double par6, float par8, float par9){
this.bindEntityTexture(arrow);
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.translate((float)par2, (float)par4, (float)par6);
GlStateManager.rotate(arrow.prevRotationYaw + (arrow.rotationYaw - arrow.prevRotationYaw) * par9 - 90.0F, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(arrow.prevRotationPitch + (arrow.rotationPitch - arrow.prevRotationPitch) * par9, 0.0F, 0.0F, 1.0F);
GlStateManager.rotate(180, 0, 1, 0);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
float pixel = 1.0f/32.0f;
float u1 = 0.0f;
float u2 = pixel*14;
float v1 = 0.0f;
float v2 = pixel*7;
float u3 = pixel*16;
float u4 = 1.0f;
float v3 = 0.0f;
float v4 = pixel*16;
float u5 = 0.0f;
float u6 = pixel*7;
float v5 = pixel*25;
float v6 = 1.0f;
float scale = 0.05625F;
float f11 = 0.0f;
GlStateManager.enableRescaleNormal();
//f11 = (float)par1EntityArrow.arrowShake - par9;
if (f11 > 0.0F)
{
float f12 = -MathHelper.sin(f11 * 3.0F) * f11;
GlStateManager.rotate(f12, 0.0F, 0.0F, 1.0F);
}
scale*=0.8f;
GlStateManager.rotate(45.0F, 1.0F, 0.0F, 0.0F);
GlStateManager.scale(scale, scale, scale);
GlStateManager.translate(-4.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-5, 3.5, -3.5).tex((double)u5, (double)v5).endVertex();
buffer.pos(-5, 3.5, 3.5).tex((double)u6, (double)v5).endVertex();
buffer.pos(-5, -3.5, 3.5).tex((double)u6, (double)v6).endVertex();
buffer.pos(-5, -3.5, -3.5).tex((double)u5, (double)v6);
tessellator.draw();
for(int i=0; i<5; i++){
GlStateManager.color(1, 1, 1, 1 - i*0.2f);
double j = i + ((double)arrow.ticksExisted%3)/3;
double width = 2.0d + (Math.sqrt(j*2)-0.6)*2;
GL11.glNormal3f(scale, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-10 + j*4, -width, -width).tex((double)u3, (double)v3).endVertex();
buffer.pos(-10 + j*4, -width, width).tex((double)u4, (double)v3).endVertex();
buffer.pos(-10 + j*4, width, width).tex((double)u4, (double)v4).endVertex();
buffer.pos(-10 + j*4, width, -width).tex((double)u3, (double)v4).endVertex();
tessellator.draw();
GL11.glNormal3f(-scale, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-10 + j*4, width, -width).tex((double)u3, (double)v3).endVertex();
buffer.pos(-10 + j*4, width, width).tex((double)u4, (double)v3).endVertex();
buffer.pos(-10 + j*4, -width, width).tex((double)u4, (double)v4).endVertex();
buffer.pos(-10 + j*4, -width, -width).tex((double)u3, (double)v4).endVertex();
tessellator.draw();
}
GlStateManager.color(1, 1, 1, 1);
for (int i = 0; i < 4; ++i)
{
GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F);
GL11.glNormal3f(0.0F, 0.0F, scale);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-10.0D, -4.0D, 0.0D).tex((double)u1, (double)v1).endVertex();
buffer.pos(10.0D, -4.0D, 0.0D).tex((double)u2, (double)v1).endVertex();
buffer.pos(10.0D, 4.0D, 0.0D).tex((double)u2, (double)v2).endVertex();
buffer.pos(-10.0D, 4.0D, 0.0D).tex((double)u1, (double)v2).endVertex();
tessellator.draw();
}
GlStateManager.disableBlend();
GlStateManager.disableRescaleNormal();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityForceArrow par1Entity)
{
return arrowTextures;
}
}
@@ -0,0 +1,39 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelHammer;
import electroblob.wizardry.entity.construct.EntityHammer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
public class RenderHammer extends Render<EntityHammer> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_hammer.png");
private ModelHammer model = new ModelHammer();
public RenderHammer(RenderManager renderManager){
super(renderManager);
}
@Override
public void doRender(EntityHammer entity, double x, double y, double z, float f, float f1) {
GlStateManager.pushMatrix();
GlStateManager.translate(x, y+1.5, z);
GlStateManager.rotate(180, 0F, 0F, 1F);
this.bindTexture(texture);
model.render(entity, 0, 0, 0, 0, 0, 0.0625f);
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityHammer entity) {
return texture;
}
}
@@ -0,0 +1,39 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelIceGiant;
import electroblob.wizardry.entity.living.EntityIceGiant;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderIceGiant extends RenderLiving<EntityIceGiant> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_giant.png");
public RenderIceGiant(RenderManager renderManager){
super(renderManager, new ModelIceGiant(), 0.5F);
}
@Override
protected ResourceLocation getEntityTexture(EntityIceGiant entity){
return texture;
}
@Override
protected void rotateCorpse(EntityIceGiant entityLiving, float pitch, float yaw, float partialTicks){
super.rotateCorpse(entityLiving, pitch, yaw, partialTicks);
if ((double)entityLiving.limbSwingAmount >= 0.01D){
float f3 = 13.0F;
float f4 = entityLiving.limbSwing - entityLiving.limbSwingAmount * (1.0F - partialTicks) + 6.0F;
float f5 = (Math.abs(f4 % f3 - f3 * 0.5F) - f3 * 0.25F) / (f3 * 0.25F);
GlStateManager.rotate(6.5F * f5, 0.0F, 0.0F, 1.0F);
}
}
}
@@ -0,0 +1,84 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityIceSpike;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderIceSpike extends Render<EntityIceSpike> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_spike.png");
public RenderIceSpike(RenderManager renderManager){
super(renderManager);
}
@Override
public void doRender(EntityIceSpike entity, double x, double y, double z, float fa, float partialTickTime) {
GlStateManager.pushMatrix();
GlStateManager.translate((float)x, (float)y, (float)z);
// Apparently, disabling lighting... doesn't disable lighting. Or at least, you can still set the brightness
// with setLightmapTextureCoords.
GlStateManager.disableLighting();
int j = entity.getBrightnessForRender(partialTickTime);
int k = j % 65536;
int l = j / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)k / 1.0F, (float)l / 1.0F);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
bindTexture(texture);
// West face
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 0, 0.5).tex(1, 1).endVertex();
buffer.pos(0, 1, 0.5).tex(1, 0).endVertex();
buffer.pos(0, 1, -0.5).tex(0, 0).endVertex();
buffer.pos(0, 0, -0.5).tex(0, 1).endVertex();
tessellator.draw();
// South face
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos( 0.5, 0, 0).tex(1, 1).endVertex();
buffer.pos( 0.5, 1, 0).tex(1, 0).endVertex();
buffer.pos(-0.5, 1, 0).tex(0, 0).endVertex();
buffer.pos(-0.5, 0, 0).tex(0, 1).endVertex();
tessellator.draw();
// East face
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 0, -0.5).tex(0, 1).endVertex();
buffer.pos(0, 1, -0.5).tex(0, 0).endVertex();
buffer.pos(0, 1, 0.5).tex(1, 0).endVertex();
buffer.pos(0, 0, 0.5).tex(1, 1).endVertex();
tessellator.draw();
// North face
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0, 0).tex(0, 1).endVertex();
buffer.pos(-0.5, 1, 0).tex(0, 0).endVertex();
buffer.pos( 0.5, 1, 0).tex(1, 0).endVertex();
buffer.pos( 0.5, 0, 0).tex(1, 1).endVertex();
tessellator.draw();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityIceSpike entity) {
return texture;
}
}
@@ -0,0 +1,82 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.projectile.EntityLightningDisc;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderLightningDisc extends Render<EntityLightningDisc> {
private final ResourceLocation texture;
private float scale = 1.0f;
public RenderLightningDisc(RenderManager renderManager, ResourceLocation texture, float scale) {
super(renderManager);
this.texture = texture;
this.scale = scale;
}
@Override
public void doRender(EntityLightningDisc entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(texture);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
GlStateManager.rotate(entity.ticksExisted*8, 0, 0, 1);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA_I(k1, 128);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityLightningDisc entity) {
return null;
}
}
@@ -0,0 +1,72 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityLightningPulse;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderLightningPulse extends Render<EntityLightningPulse> {
private final ResourceLocation[] textures = new ResourceLocation[8];
private float scale = 1.0f;
public RenderLightningPulse(RenderManager renderManager, float scale) {
super(renderManager);
for(int i=0; i<textures.length; i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_pulse_" + i + ".png");
}
this.scale = scale;
}
@Override
public void doRender(EntityLightningPulse entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(textures[entity.ticksExisted]);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityLightningPulse entity) {
return null;
}
}
@@ -0,0 +1,122 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.projectile.EntityMagicArrow;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderMagicArrow extends Render<EntityMagicArrow> {
private final ResourceLocation texture;
private boolean blend;
private boolean renderEnds;
private double length = 8.0, width = 2.0;
private int pixelsLong = 16, pixelsWide = 5;
public RenderMagicArrow(RenderManager renderManager, ResourceLocation texture, boolean blend, double length, double width, int pixelsLong, int pixelsWide, boolean renderEnds){
super(renderManager);
this.texture = texture;
this.blend = blend;
this.renderEnds = renderEnds;
this.length = length;
this.width = width;
this.pixelsLong = pixelsLong;
this.pixelsWide = pixelsWide;
}
@Override
public void doRender(EntityMagicArrow entity, double par2, double par4, double par6, float par8, float par9){
this.bindEntityTexture(entity);
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
if(this.blend){
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
GlStateManager.translate((float)par2, (float)par4, (float)par6);
GlStateManager.rotate(entity.prevRotationYaw + (entity.rotationYaw - entity.prevRotationYaw) * par9 - 90.0F, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(entity.prevRotationPitch + (entity.rotationPitch - entity.prevRotationPitch) * par9, 0.0F, 0.0F, 1.0F);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
float f2 = 0.0F;
float f3 = pixelsLong / 32.0F;
float f4 = 0.0F;
float f5 = pixelsWide / 32.0F;
float f6 = 0.0F;
float f7 = 0.15625F;
float f8 = (float)5 / 32.0F;
float f9 = (float)10 / 32.0F;
float f10 = 0.05625F;
float f11 = 0.0f;
GlStateManager.enableRescaleNormal();
//f11 = (float)par1EntityArrow.arrowShake - par9;
if (f11 > 0.0F)
{
float f12 = -MathHelper.sin(f11 * 3.0F) * f11;
GlStateManager.rotate(f12, 0.0F, 0.0F, 1.0F);
}
GlStateManager.rotate(45.0F, 1.0F, 0.0F, 0.0F);
GlStateManager.scale(f10, f10, f10);
GlStateManager.translate(-4.0F, 0.0F, 0.0F);
GL11.glNormal3f(f10, 0.0F, 0.0F);
if(renderEnds){
// Ends
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-7.0D, -width, -width).tex((double)f6, (double)f8).endVertex();
buffer.pos(-7.0D, -width, width).tex((double)f7, (double)f8).endVertex();
buffer.pos(-7.0D, width, width).tex((double)f7, (double)f9).endVertex();
buffer.pos(-7.0D, width, -width).tex((double)f6, (double)f9).endVertex();
tessellator.draw();
GL11.glNormal3f(-f10, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-7.0D, width, -width).tex((double)f6, (double)f8).endVertex();
buffer.pos(-7.0D, width, width).tex((double)f7, (double)f8).endVertex();
buffer.pos(-7.0D, -width, width).tex((double)f7, (double)f9).endVertex();
buffer.pos(-7.0D, -width, -width).tex((double)f6, (double)f9).endVertex();
tessellator.draw();
}
for (int i = 0; i < 4; ++i){
// Sides
GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F);
GL11.glNormal3f(0.0F, 0.0F, f10);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-length, -width, 0.0D).tex((double)f2, (double)f4).endVertex();
buffer.pos(length, -width, 0.0D).tex((double)f3, (double)f4).endVertex();
buffer.pos(length, width, 0.0D).tex((double)f3, (double)f5).endVertex();
buffer.pos(-length, width, 0.0D).tex((double)f2, (double)f5).endVertex();
tessellator.draw();
}
if(this.blend){
GlStateManager.disableBlend();
}
GlStateManager.disableRescaleNormal();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityMagicArrow arrow)
{
return texture;
}
}
@@ -0,0 +1,130 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.tileentity.TileEntityMagicLight;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderMagicLight extends TileEntitySpecialRenderer<TileEntityMagicLight> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/light_ray.png");
private static final ResourceLocation texture2 = new ResourceLocation(Wizardry.MODID, "textures/entity/light_aura.png");
@Override
public void renderTileEntityAt(TileEntityMagicLight tileentity, double x, double y, double z, float f, int destroyStage){
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
RenderHelper.disableStandardItemLighting();
GlStateManager.translate(x + 0.5, y + 0.5, z + 0.5);
if(tileentity.timer < 10){
GlStateManager.scale((float)tileentity.timer/10, (float)tileentity.timer/10, (float)tileentity.timer/10);
}
if(tileentity.timer > tileentity.maxTimer-10){
GlStateManager.scale((float)(tileentity.maxTimer-tileentity.timer)/10, (float)(tileentity.maxTimer-tileentity.timer)/10, (float)(tileentity.maxTimer-tileentity.timer)/10);
}
// Renders the aura effect
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? Minecraft.getMinecraft().getRenderManager().playerViewX : -Minecraft.getMinecraft().getRenderManager().playerViewX;
GlStateManager.rotate(180.0F - Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
this.bindTexture(texture2);
buffer.pos(-0.6, 0.6, 0).tex(0, 0).endVertex();
buffer.pos(0.6, 0.6, 0).tex(1, 0).endVertex();
buffer.pos(0.6, -0.6, 0).tex(1, 1).endVertex();
buffer.pos(-0.6, -0.6, 0).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
// Renders the rays
// For some reason, the old blend function (GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA) caused the innermost
// ends of the rays to appear black, so I have changed it to this, which looks very slightly different.
GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA);
this.bindTexture(texture);
if(tileentity.randomiser.length >= 30){
for(int j=0; j<30; j++){
int sliceAngle = 20 + tileentity.randomiser[j];
float scale = 0.5f;
GlStateManager.pushMatrix();
GlStateManager.rotate(31*tileentity.randomiser[j], 1, 0, 0);
GlStateManager.rotate(31*tileentity.randomiser2[j], 0, 0, 1);
/*
* OK, so here are the changes to rendering as far as I know:
* Vertex formats specify how the methods are arranged
* Color has to be called for every vertex, I think.
* The new methods thing is a bit weird, because other than the number of arguments there is
* essentially no difference between pos, tex, color, normal and lightmap. At least they make
* the code more readable.
*/
buffer.begin(5, DefaultVertexFormats.POSITION_TEX_COLOR);
buffer.pos(0, 0, 0).tex(0, 0).color(255, 255, 255, 0).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).color(255, 255, 255, 0).endVertex();
double x1 = scale*Math.sin((tileentity.timer + 40*j)*(Math.PI/180));
//double y1 = 0.7*Math.cos((timerentity.timer - 40*j)*(Math.PI/180))*j/10;
double z1 = scale*Math.cos((tileentity.timer + 40*j)*(Math.PI/180));
double x2 = scale*Math.sin((tileentity.timer + 40*j - sliceAngle)*(Math.PI/180));
//double y2 = 0.7*Math.sin((timerentity.timer - 40*j)*(Math.PI/180))*j/10;
double z2 = scale*Math.cos((tileentity.timer + 40*j - sliceAngle)*(Math.PI/180));
buffer.pos(x1, 0, z1).tex(1, 0).color(0, 0, 0, 255).endVertex();
buffer.pos(x2, 0, z2).tex(1, 1).color(0, 0, 0, 255).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
}
}
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableCull();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
RenderHelper.enableStandardItemLighting();
GlStateManager.popMatrix();
}
}
@@ -0,0 +1,52 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelPhoenix;
import electroblob.wizardry.entity.living.EntityPhoenix;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderPhoenix extends RenderLiving<EntityPhoenix> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/phoenix.png");
public RenderPhoenix(RenderManager renderManager){
super(renderManager, new ModelPhoenix(), 1.0f);
}
@Override
protected ResourceLocation getEntityTexture(EntityPhoenix entity){
return texture;
}
@Override
protected void rotateCorpse(EntityPhoenix par1EntityPhoenix, float par2, float par3, float par4){
GlStateManager.translate(0.0F, -0.1F, 0.0F);
super.rotateCorpse(par1EntityPhoenix, par2, par3, par4);
}
@Override
public void doRender(EntityPhoenix phoenix, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
super.doRender(phoenix, par2, par4, par6, par8, par9);
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
}
@@ -0,0 +1,88 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.projectile.EntityMagicProjectile;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderProjectile extends Render<EntityMagicProjectile> {
private float scale;
private boolean blend = false;
private final ResourceLocation texture;
public RenderProjectile(RenderManager renderManager, float scale, ResourceLocation texture, boolean doBlending)
{
super(renderManager);
this.scale = scale;
this.texture = texture;
this.blend = doBlending;
}
@Override
public void doRender(EntityMagicProjectile entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
this.bindTexture(texture);
GlStateManager.translate((float)par2, (float)par4, (float)par6);
GlStateManager.enableRescaleNormal();
if(blend){
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
float f2 = this.scale;
GlStateManager.scale(f2 / 1.0F, f2 / 1.0F, f2 / 1.0F);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
float f3 = 0.0f;
float f4 = 1.0f;
float f5 = 0.0f;
float f6 = 1.0f;
float f7 = 1.0F;
float f8 = 0.5F;
float f9 = 0.25F;
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? this.renderManager.playerViewX : -this.renderManager.playerViewX;
GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f8), (double)(0.0F - f9), 0.0D).tex((double)f3, (double)f6).endVertex();
buffer.pos((double)(f7 - f8), (double)(0.0F - f9), 0.0D).tex((double)f4, (double)f6).endVertex();
buffer.pos((double)(f7 - f8), (double)(1.0F - f9), 0.0D).tex((double)f4, (double)f5).endVertex();
buffer.pos((double)(0.0F - f8), (double)(1.0F - f9), 0.0D).tex((double)f3, (double)f5).endVertex();
tessellator.draw();
GlStateManager.disableRescaleNormal();
if(blend){
GlStateManager.disableBlend();
}
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityMagicProjectile par1Entity){
return texture;
}
}
@@ -0,0 +1,89 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.construct.EntityHealAura;
import electroblob.wizardry.entity.construct.EntityMagicConstruct;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation;
public class RenderSigil extends Render<EntityMagicConstruct> {
private final ResourceLocation texture;
private float scale = 1.0f;
private boolean invisibleToEnemies;
public RenderSigil(RenderManager renderManager, ResourceLocation texture, float scale, boolean invisibleToEnemies) {
super(renderManager);
this.texture = texture;
this.scale = scale;
this.invisibleToEnemies = invisibleToEnemies;
}
@Override
public void doRender(EntityMagicConstruct entity, double par2, double par4, double par6, float par8, float par9){
// Makes the sigil invisible to enemies of the player that created it
if(this.invisibleToEnemies){
if(entity.getCaster() instanceof EntityPlayer
&& !WizardryUtilities.isPlayerAlly((EntityPlayer)entity.getCaster(), Minecraft.getMinecraft().thePlayer)){
return;
}
}
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(texture);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
// Healing aura rotates slowly
if(entity instanceof EntityHealAura) GlStateManager.rotate(entity.ticksExisted/3.0f, 0, 0, 1);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA_I(k1, 128);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityMagicConstruct entity) {
return null;
}
}
@@ -0,0 +1,36 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.model.ModelHorse;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderHorse;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.passive.EntityHorse;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderSpiritHorse extends RenderHorse {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/spirit_horse.png");
public RenderSpiritHorse(RenderManager renderManager, float par2){
super(renderManager, new ModelHorse(), par2);
}
@Override
protected ResourceLocation getEntityTexture(EntityHorse entity) {
return texture;
}
@Override
protected void preRenderCallback(EntityHorse entitylivingbaseIn, float partialTickTime){
super.preRenderCallback(entitylivingbaseIn, partialTickTime);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
}
@@ -0,0 +1,35 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.model.ModelWolf;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.RenderWolf;
import net.minecraft.entity.passive.EntityWolf;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderSpiritWolf extends RenderWolf {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/spirit_wolf.png");
public RenderSpiritWolf(RenderManager renderManager, float par3){
super(renderManager, new ModelWolf(), par3);
}
@Override
protected ResourceLocation getEntityTexture(EntityWolf entity) {
return texture;
}
@Override
protected void preRenderCallback(EntityWolf entity, float partialTickTime){
super.preRenderCallback(entity, partialTickTime);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
}
@@ -0,0 +1,64 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.tileentity.TileEntityStatue;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
public class RenderStatue extends TileEntitySpecialRenderer<TileEntityStatue> {
private int destroyStage = 0; // Gets set each time a statue is rendered to allow access from the layer renderer
@Override
public void renderTileEntityAt(TileEntityStatue statue, double x, double y, double z, float partialTicks, int destroyStage){
// Multiblock support for the breaking animation. The chest has its own way of doing this in
// TileEntityRendererDispatcher, but I don't have access to that.
if(statue.position != 1 && destroyStage >= 0){
TileEntity tileentity = statue.getWorld().getTileEntity(statue.getPos().down(statue.position-1));
//System.out.println(tileentity);
if(tileentity instanceof TileEntityStatue){
// If this is the block breaking animation pass and this isn't the bottom block, divert the call to
// the bottom block.
this.renderTileEntityAt((TileEntityStatue)tileentity, x, y - (statue.position-1), z, partialTicks, destroyStage);
}
}
if(statue.creature != null && statue.position == 1){
this.destroyStage = destroyStage;
GlStateManager.pushMatrix();
// The next line makes stuff render in the same place relative to the world wherever the player is.
GlStateManager.translate((float)x + 0.5F, (float)y, (float)z + 0.5F);
GlStateManager.enableLighting();
float yaw = statue.creature.prevRotationYaw;
int i = statue.creature.getBrightnessForRender(0);
int j = i % 65536;
int k = i / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.rotate(-yaw, 0F, 1F, 0F);
// Stops the normal model from rendering.
if(!statue.isIce) statue.creature.setInvisible(true);
// Setting the last parameter to true prevents the debug bounding box from rendering.
// For some reason, passing in the partialTicks causes the entity to spin round really fast
Minecraft.getMinecraft().getRenderManager().doRenderEntity(statue.creature, 0, 0, 0, 0, 0, true);
if(!statue.isIce) statue.creature.setInvisible(false);
GlStateManager.popMatrix();
}
}
public ResourceLocation getBlockBreakingTexture(){
return destroyStage < 0 ? null : DESTROY_STAGES[destroyStage];
}
}
@@ -0,0 +1,34 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelWizard;
import electroblob.wizardry.entity.living.EntityWizard;
import net.minecraft.client.renderer.entity.RenderBiped;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.layers.LayerBipedArmor;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderWizard extends RenderBiped<EntityWizard> {
static final ResourceLocation[] textures = new ResourceLocation[6];
public RenderWizard(RenderManager renderManager){
super(renderManager, new ModelWizard(), 0.5F);
for(int i=0;i<6;i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/wizard_" + i + ".png");
}
// Just using the default without overriding models, since the armour sets its own model anyway.
this.addLayer(new LayerBipedArmor(this));
}
@Override
protected ResourceLocation getEntityTexture(EntityWizard wizard) {
return textures[wizard.textureIndex];
}
}
@@ -0,0 +1,26 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.entity.living.EntityBlazeMinion;
import net.minecraft.client.model.ModelBlaze;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderWraithMinion extends RenderLiving<EntityBlazeMinion>
{
private ResourceLocation texture = new ResourceLocation("textures/entity/blaze.png");
public RenderWraithMinion(RenderManager renderManagerIn)
{
super(renderManagerIn, new ModelBlaze(), 0.5F);
}
@Override
protected ResourceLocation getEntityTexture(EntityBlazeMinion entity)
{
return texture;
}
}
@@ -0,0 +1,183 @@
package electroblob.wizardry.command;
import java.util.List;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.packet.PacketCastSpell;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.NumberInvalidException;
import net.minecraft.command.PlayerNotFoundException;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class CommandCastSpell extends CommandBase {
@Override
public String getCommandName(){
return Wizardry.settings.castCommandName;
}
@Override
public int getRequiredPermissionLevel(){
// I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console...
return 2;
}
@Override
public String getCommandUsage(ICommandSender p_71518_1_){
// Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there
// the custom command name will not display.
return "commands.wizardry:cast.usage";
//return I18n.format("commands.wizardry:cast.usage", Wizardry.settings.castCommandName);
}
@Override
public List<String> getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) {
switch(arguments.length){
case 1: return getListOfStringsMatchingLastWord(arguments, Spell.getSpellNames());
case 2: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
}
return super.getTabCompletionOptions(server, sender, arguments, pos);
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException {
if(arguments.length < 1){
throw new WrongUsageException("commands.wizardry:cast.usage", Wizardry.settings.castCommandName);
}else{
int i=0;
EntityPlayerMP entityplayermp = null;
try{
entityplayermp = getCommandSenderAsPlayer(sender);
}catch(PlayerNotFoundException exception){
// Nothing here since the player specifying is done later, I just don't want it to throw an exception here.
}
Spell spell = Spell.get(arguments[i++]);
if(spell == null){
throw new NumberInvalidException("commands.wizardry:cast.not_found", new Object[]{arguments[i-1]});
}
boolean castAsOtherPlayer = false;
if(i < arguments.length){
try{
// If the second argument is a player and is not the player that gave the command, the spell is cast
// as the given player rather than the command sender, and there is a different chat readout.
EntityPlayerMP entityplayermp1 = getPlayer(server, sender, arguments[i++]);
if(entityplayermp != entityplayermp1){
castAsOtherPlayer = true;
entityplayermp = entityplayermp1;
}
}catch(PlayerNotFoundException exception){
// If no player was found, rather than give an error it simply assumes the player was unspecified.
i--;
}
}
// If, after this point, the player is still null, the sender must be a command block or the console and the
// player must not have been specified, meaning an exception should be thrown.
if(entityplayermp == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on.");
SpellModifiers modifiers = new SpellModifiers();
if(i < arguments.length){
// Copied from CommandGive. Why it doesn't just use arguments[i] itself I don't know.
String nbt = getChatComponentFromNthArg(sender, arguments, i++).getUnformattedText();
try{
modifiers = SpellModifiers.fromNBT(JsonToNBT.getTagFromJson(nbt));
}catch(NBTException nbtexception){
throw new CommandException("commands.wizardry:cast.tag_error", nbtexception.getMessage());
}
for(float multiplier : modifiers.getModifiers().values()){
if(multiplier < 0){
throw new NumberInvalidException("commands.generic.double.tooSmall", multiplier, 0);
}else if(multiplier > Wizardry.settings.maxSpellCommandMultiplier){
throw new NumberInvalidException("commands.generic.double.tooBig", multiplier, Wizardry.settings.maxSpellCommandMultiplier);
}
}
}
if(spell.isContinuous){
WizardData properties = WizardData.get((EntityPlayer)entityplayermp);
if(properties != null){
if(properties.isCasting()){
WizardData.get((EntityPlayer)entityplayermp).stopCastingContinuousSpell();
}else{
WizardData.get((EntityPlayer)entityplayermp).startCastingContinuousSpell(spell, modifiers);
if(castAsOtherPlayer){
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success_remote_continuous", spell.getNameForTranslationFormatted(), entityplayermp.getName()));
}else{
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success_continuous", spell.getNameForTranslationFormatted()));
}
}
return;
}
}else{
if(spell.cast(entityplayermp.worldObj, entityplayermp, EnumHand.MAIN_HAND, 0, modifiers)){
if(spell.doesSpellRequirePacket()){
// Sends a packet to all players in dimension to tell them to spawn particles.
// Only sent if the spell succeeded, because if the spell failed, you wouldn't
// need to spawn any particles!
IMessage msg = new PacketCastSpell.Message(entityplayermp.getEntityId(), null, spell.id(), modifiers);
WizardryPacketHandler.net.sendToDimension(msg, entityplayermp.worldObj.provider.getDimension());
}
if(WizardData.get((EntityPlayer)entityplayermp) != null){
// Added optimisation from 1.7.10: if the spell was already discovered, nothing happens.
if(WizardData.get((EntityPlayer)entityplayermp).discoverSpell(spell)){
// If the spell didn't send a packet itself, the extended player needs to be synced so the
// spell discovery updates on the client.
if(!spell.doesSpellRequirePacket()) WizardData.get((EntityPlayer)entityplayermp).sync();
}
}
if(castAsOtherPlayer){
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success_remote", spell.getNameForTranslationFormatted(), entityplayermp.getName()));
}else{
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success", spell.getNameForTranslationFormatted()));
}
return;
}
}
ITextComponent message = new TextComponentTranslation("commands.wizardry:cast.fail", spell.getNameForTranslationFormatted());
message.getStyle().setColor(TextFormatting.RED);
sender.addChatMessage(message);
}
}
}
@@ -0,0 +1,130 @@
package electroblob.wizardry.command;
import java.util.List;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.NumberInvalidException;
import net.minecraft.command.PlayerNotFoundException;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
public class CommandDiscoverSpell extends CommandBase {
@Override
public String getCommandName(){
return Wizardry.settings.discoverspellCommandName;
}
@Override
public int getRequiredPermissionLevel(){
// I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console...
return 2;
}
/*
@Override
public boolean checkPermission(MinecraftServer server, ICommandSender sender){
// Only ops (multiplayer) or players with cheats enabled (singleplayer/LAN) can use /discoverspell.
return !(sender instanceof EntityPlayer) || server.getServer().getConfigurationManager().func_152596_g(((EntityPlayer)sender).getGameProfile());
}
*/
@Override
public String getCommandUsage(ICommandSender p_71518_1_){
// Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there
// the custom command name will not display.
return "commands.wizardry:discoverspell.usage";
//return I18n.format("commands.wizardry:discoverspell.usage", Wizardry.settings.discoverspellCommandName);
}
@Override
public List<String> getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) {
switch(arguments.length){
case 1: return getListOfStringsMatchingLastWord(arguments, Spell.getSpellNames());
case 2: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
}
return super.getTabCompletionOptions(server, sender, arguments, pos);
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException {
if(arguments.length < 1){
throw new WrongUsageException("commands.wizardry:discoverspell.usage", Wizardry.settings.discoverspellCommandName);
}else{
int i=0;
boolean clear = false;
boolean all = false;
EntityPlayerMP entityplayermp = null;
try{
entityplayermp = getCommandSenderAsPlayer(sender);
}catch(PlayerNotFoundException exception){
// Nothing here since the player specifying is done later, I just don't want it to throw an exception here.
}
Spell spell = Spells.none;
if(arguments[i].equals("clear")){
clear = true;
i++;
}else if(arguments[i].equals("all")){
all = true;
i++;
}else{
spell = Spell.get(arguments[i++]);
if(spell == null){
throw new NumberInvalidException("commands.wizardry:discoverspell.not_found", new Object[]{arguments[i-1]});
}
}
if(i < arguments.length){
// If the second argument is a player and is not the player that gave the command, the spell is
// discovered as the given player rather than the command sender.
EntityPlayerMP entityplayermp1 = getPlayer(server, sender, arguments[i++]);
if(entityplayermp != entityplayermp1){
entityplayermp = entityplayermp1;
}
}
// If, after this point, the player is still null, the sender must be a command block or the console and the
// player must not have been specified, meaning an exception should be thrown.
if(entityplayermp == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on.");
WizardData properties = WizardData.get(entityplayermp);
if(properties != null){
if(clear){
properties.spellsDiscovered.clear();
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.clear", entityplayermp.getName()));
}else if(all){
properties.spellsDiscovered.addAll(Spell.getSpells(Spell.allSpells));
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.all", entityplayermp.getName()));
}else{
if(properties.hasSpellBeenDiscovered(spell)){
properties.spellsDiscovered.remove(spell);
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.removespell", spell.getNameForTranslationFormatted(), entityplayermp.getName()));
}else{
properties.discoverSpell(spell);
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.addspell", spell.getNameForTranslationFormatted(), entityplayermp.getName()));
}
}
properties.sync();
}
}
}
}
@@ -0,0 +1,113 @@
package electroblob.wizardry.command;
import java.util.List;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.NumberInvalidException;
import net.minecraft.command.PlayerNotFoundException;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
public class CommandSetAlly extends CommandBase {
@Override
public String getCommandName(){
return Wizardry.settings.allyCommandName;
}
@Override
public int getRequiredPermissionLevel(){
// I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console...
return 0;
}
@Override
public boolean checkPermission(MinecraftServer server, ICommandSender p_71519_1_)
{
return true;
}
@Override
public String getCommandUsage(ICommandSender p_71518_1_){
// Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there
// the custom command name will not display.
return "commands.wizardry:ally.usage";
//return I18n.format("commands.wizardry:ally.usage", Wizardry.settings.allyCommandName);
}
@Override
public List<String> getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) {
switch(arguments.length){
case 1: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
case 2: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
}
return super.getTabCompletionOptions(server, sender, arguments, pos);
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException {
if(arguments.length < 1){
throw new WrongUsageException("commands.wizardry:ally.usage", Wizardry.settings.allyCommandName);
}else{
EntityPlayerMP allyOf = null;
try{
allyOf = getCommandSenderAsPlayer(sender);
}catch(PlayerNotFoundException exception){
// Nothing here since the player specifying is done later, I just don't want it to throw an exception here.
}
boolean executeAsOtherPlayer = false;
EntityPlayerMP ally = getPlayer(server, sender, arguments[0]);
// Don't want to catch the exception here, because the first player argument is always required.
if(arguments.length > 1){
allyOf = getPlayer(server, sender, arguments[1]);
// Don't want to catch the exception here either, because there can be no other second argument.
if(allyOf != sender && sender instanceof EntityPlayer && !WizardryUtilities.isPlayerOp((EntityPlayer)sender, server)){
// Displays a chat message if a non-op tries to modify another player's allies.
TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation("commands.wizardry:ally.permission");
TextComponentTranslation2.getStyle().setColor(TextFormatting.RED);
allyOf.addChatMessage(TextComponentTranslation2);
return;
}
if(allyOf != sender) executeAsOtherPlayer = true;
}
// If, after this point, allyOf is still null, the sender must be a command block or the console and two
// players must not have been specified, meaning an exception should be thrown.
if(allyOf == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on.");
if(allyOf == ally) throw new NumberInvalidException("commands.wizardry:ally.self");
if(WizardData.get(allyOf) != null){
String string = WizardData.get(allyOf).toggleAlly(ally) ? "add" : "remove";
if(executeAsOtherPlayer){
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:ally." + string + "ally", ally.getName(), allyOf.getName()));
// In this case, the player whose allies have been modified is also notified.
allyOf.addChatMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName()));
}else{
sender.addChatMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName()));
}
}
}
}
}
@@ -0,0 +1,112 @@
package electroblob.wizardry.command;
import java.util.List;
import java.util.Set;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.resources.I18n;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.PlayerNotFoundException;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
public class CommandViewAllies extends CommandBase {
@Override
public String getCommandName(){
return Wizardry.settings.alliesCommandName;
}
@Override
public int getRequiredPermissionLevel(){
// I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console...
return 0;
}
@Override
public boolean checkPermission(MinecraftServer server, ICommandSender p_71519_1_)
{
return true;
}
@Override
public String getCommandUsage(ICommandSender p_71518_1_){
// Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there
// the custom command name will not display.
return "commands.wizardry:allies.usage";
//return I18n.format("commands.wizardry:allies.usage", Wizardry.settings.alliesCommandName);
}
@Override
public List<String> getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) {
switch(arguments.length){
case 1: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
}
return super.getTabCompletionOptions(server, sender, arguments, pos);
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException {
EntityPlayerMP player = null;
try{
player = getCommandSenderAsPlayer(sender);
}catch(PlayerNotFoundException exception){
// Nothing here since the player specifying is done later, I just don't want it to throw an exception here.
}
boolean executeAsOtherPlayer = false;
if(arguments.length > 0){
player = getPlayer(server, sender, arguments[0]);
// Don't want to catch the exception here either, because there can be no other first argument.
if(player != sender && sender instanceof EntityPlayer && !WizardryUtilities.isPlayerOp((EntityPlayer)sender, server)){
// Displays a chat message if a non-op tries to view another player's allies.
TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation("commands.wizardry:allies.permission");
TextComponentTranslation2.getStyle().setColor(TextFormatting.RED);
player.addChatMessage(TextComponentTranslation2);
return;
}
if(player != sender) executeAsOtherPlayer = true;
}
// If, after this point, player is still null, the sender must be a command block or the console and the
// player must not have been specified, meaning an exception should be thrown.
if(player == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on.");
if(WizardData.get(player) != null){
String string = "";
Set<String> names = WizardData.get(player).allyNames;
if(!names.isEmpty()){
for(String name : names){
string = string + name + ", ";
}
// Cuts the last " ," off of the string.
string = string.substring(0, string.length() - 2);
}else{
string = I18n.format("commands.wizardry:allies.none");
}
if(executeAsOtherPlayer){
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:allies.list_other", player.getName(), string));
}else{
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:allies.list", string));
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More