mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Merge fixes
This commit is contained in:
commit
c4432bcd7e
339
GPL.txt
339
GPL.txt
@ -1,339 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 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.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
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 Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
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 Program, 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 Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) 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; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, 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 executable. However, as a
|
|
||||||
special exception, the source code 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.
|
|
||||||
|
|
||||||
If distribution of executable or 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 counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program 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.
|
|
||||||
|
|
||||||
5. 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 Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program 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 to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. 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 Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program 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 Program.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program 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.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies 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 Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, 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
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
|
||||||
when it starts in an interactive mode:
|
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, the commands you use may
|
|
||||||
be called something other than `show w' and `show c'; they could even be
|
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License.
|
|
||||||
165
LICENSE
Normal file
165
LICENSE
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
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 that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU 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 as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
||||||
12
LICENSE.md
12
LICENSE.md
@ -1,12 +0,0 @@
|
|||||||
The server code and utilities are released under GPLv3.
|
|
||||||
|
|
||||||
We also include some small libraries for convienence that may be under different licensing:
|
|
||||||
|
|
||||||
SocketLib - GPL
|
|
||||||
LibXML - ZLib License
|
|
||||||
StackWalker - New BSD License
|
|
||||||
ZLib - ZLib License
|
|
||||||
MySQL - GPL
|
|
||||||
Perl - GPL / ActiveState (under the assumption that this is a free project).
|
|
||||||
CPPUnit - GLP
|
|
||||||
StringUtilities - Apache
|
|
||||||
21
README.md
21
README.md
@ -53,7 +53,24 @@ forum, although pull requests will be much quicker and easier on all parties.
|
|||||||
- **User Discord Channel**: `#general`
|
- **User Discord Channel**: `#general`
|
||||||
- **Developer Discord Channel**: `#eqemucoders`
|
- **Developer Discord Channel**: `#eqemucoders`
|
||||||
|
|
||||||
Resources
|
## Resources
|
||||||
---
|
|
||||||
- [EQEmulator Forums](http://www.eqemulator.org/forums)
|
- [EQEmulator Forums](http://www.eqemulator.org/forums)
|
||||||
- [EQEmulator Wiki](https://github.com/EQEmu/Server/wiki)
|
- [EQEmulator Wiki](https://github.com/EQEmu/Server/wiki)
|
||||||
|
- [EQEmulator Wiki](http://wiki.eqemulator.org/i?M=Wiki)
|
||||||
|
|
||||||
|
## Related Repositories
|
||||||
|
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)
|
||||||
|
* [Maps](https://github.com/Akkadius/EQEmuMaps)
|
||||||
|
* [Installer Resources](https://github.com/Akkadius/EQEmuInstall)
|
||||||
|
* [Zone Utilities](https://github.com/EQEmu/zone-utilities) - Various utilities and libraries for parsing, rendering and manipulating EQ Zone files.
|
||||||
|
|
||||||
|
## Other License Info
|
||||||
|
|
||||||
|
* The server code and utilities are released under **GPLv3**
|
||||||
|
* We also include some small libraries for convienence that may be under different licensing
|
||||||
|
* SocketLib - GPL LibXML
|
||||||
|
* zlib - zlib license
|
||||||
|
* MariaDB/MySQL - GPL
|
||||||
|
* GPL Perl - GPL / ActiveState (under the assumption that this is a free project)
|
||||||
|
* CPPUnit - GLP StringUtilities - Apache
|
||||||
|
* LUA - MIT
|
||||||
|
|||||||
@ -1,5 +1,32 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
== 10/08/2017 ==
|
||||||
|
Mackal: Rework regens
|
||||||
|
|
||||||
|
Regen will now match whats reported by modern clients, besides where they lie due to known bugs
|
||||||
|
|
||||||
|
HP and END regens are now based on the BaseData.txt values allowing easy customization
|
||||||
|
Those cases:
|
||||||
|
- The client always applies hunger penalties, it appears they don't exist anymore on live you can turn them on with a rule
|
||||||
|
- The way the client gets buff mana/end regen benefits incorrectly applies the bard mod making these values lie sometimes
|
||||||
|
|
||||||
|
== 9/17/2017 ==
|
||||||
|
Akkadius: Add model/race offset to FixZ calc (KLS)
|
||||||
|
Akkadius: Fix 95% of food/water consumption issues, if there are additional modifiers for race/class combos - those will need to be applied
|
||||||
|
|
||||||
|
Stages should be put in place if not already:
|
||||||
|
https://wiki.project1999.com/Food_and_drink#Stages_of_Hunger_and_Thirst
|
||||||
|
|
||||||
|
Values stored in the database are 0-6000, previously we capped it at 6000 but previous math would have normal values in the 60k+ range in order for food to be consumed at a reasonable rate. We are now using more native logic where 1 = 1 minute, following logic:
|
||||||
|
|
||||||
|
(Minutes)
|
||||||
|
0 - 5 - This is a snack.
|
||||||
|
6 - 20 - This is a meal.
|
||||||
|
21 - 30 - This is a hearty meal.
|
||||||
|
31 - 40 - This is a banquet size meal.
|
||||||
|
41 - 50 - This meal is a feast!
|
||||||
|
51 - 60 - This is an enduring meal!
|
||||||
|
61 - X - This is a miraculous meal!
|
||||||
|
|
||||||
== 7/14/2017 ==
|
== 7/14/2017 ==
|
||||||
Akkadius: HP Update tuning - HP Updates are now forced when a client is targeted
|
Akkadius: HP Update tuning - HP Updates are now forced when a client is targeted
|
||||||
|
|||||||
@ -24,8 +24,8 @@ struct BaseDataStruct
|
|||||||
double base_hp;
|
double base_hp;
|
||||||
double base_mana;
|
double base_mana;
|
||||||
double base_end;
|
double base_end;
|
||||||
double unk1;
|
double hp_regen;
|
||||||
double unk2;
|
double end_regen;
|
||||||
double hp_factor;
|
double hp_factor;
|
||||||
double mana_factor;
|
double mana_factor;
|
||||||
double endurance_factor;
|
double endurance_factor;
|
||||||
|
|||||||
@ -78,6 +78,8 @@ namespace EQEmu
|
|||||||
SLOT_CURSOR_BAG_END = 340,
|
SLOT_CURSOR_BAG_END = 340,
|
||||||
SLOT_TRIBUTE_BEGIN = 400,
|
SLOT_TRIBUTE_BEGIN = 400,
|
||||||
SLOT_TRIBUTE_END = 404,
|
SLOT_TRIBUTE_END = 404,
|
||||||
|
SLOT_GUILD_TRIBUTE_BEGIN = 450,
|
||||||
|
SLOT_GUILD_TRIBUTE_END = 451,
|
||||||
SLOT_BANK_BEGIN = 2000,
|
SLOT_BANK_BEGIN = 2000,
|
||||||
SLOT_BANK_END = 2023,
|
SLOT_BANK_END = 2023,
|
||||||
SLOT_BANK_BAGS_BEGIN = 2031,
|
SLOT_BANK_BAGS_BEGIN = 2031,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ N(OP_AcceptNewTask),
|
|||||||
N(OP_AckPacket),
|
N(OP_AckPacket),
|
||||||
N(OP_Action),
|
N(OP_Action),
|
||||||
N(OP_Action2),
|
N(OP_Action2),
|
||||||
|
N(OP_AddNimbusEffect),
|
||||||
N(OP_AdventureData),
|
N(OP_AdventureData),
|
||||||
N(OP_AdventureDetails),
|
N(OP_AdventureDetails),
|
||||||
N(OP_AdventureFinish),
|
N(OP_AdventureFinish),
|
||||||
@ -339,6 +340,7 @@ N(OP_MOTD),
|
|||||||
N(OP_MoveCoin),
|
N(OP_MoveCoin),
|
||||||
N(OP_MoveDoor),
|
N(OP_MoveDoor),
|
||||||
N(OP_MoveItem),
|
N(OP_MoveItem),
|
||||||
|
N(OP_MoveMultipleItems),
|
||||||
N(OP_MoveLogDisregard),
|
N(OP_MoveLogDisregard),
|
||||||
N(OP_MoveLogRequest),
|
N(OP_MoveLogRequest),
|
||||||
N(OP_MultiLineMsg),
|
N(OP_MultiLineMsg),
|
||||||
|
|||||||
@ -551,6 +551,7 @@ struct BlockedBuffs_Struct
|
|||||||
/*86*/ uint16 Flags;
|
/*86*/ uint16 Flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// same for adding
|
||||||
struct RemoveNimbusEffect_Struct
|
struct RemoveNimbusEffect_Struct
|
||||||
{
|
{
|
||||||
/*00*/ uint32 spawnid; // Spawn ID
|
/*00*/ uint32 spawnid; // Spawn ID
|
||||||
@ -854,6 +855,7 @@ static const uint32 MAX_PP_REF_SPELLBOOK = 480; // Set for Player Profile size r
|
|||||||
static const uint32 MAX_PP_REF_MEMSPELL = 9; // Set for Player Profile size retain
|
static const uint32 MAX_PP_REF_MEMSPELL = 9; // Set for Player Profile size retain
|
||||||
|
|
||||||
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
||||||
|
static const uint32 MAX_PP_INNATE_SKILL = 25;
|
||||||
static const uint32 MAX_PP_AA_ARRAY = 240;
|
static const uint32 MAX_PP_AA_ARRAY = 240;
|
||||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||||
static const uint32 MAX_RECAST_TYPES = 20;
|
static const uint32 MAX_RECAST_TYPES = 20;
|
||||||
@ -993,7 +995,8 @@ struct PlayerProfile_Struct
|
|||||||
/*4768*/ int32 platinum_shared; // Platinum shared between characters
|
/*4768*/ int32 platinum_shared; // Platinum shared between characters
|
||||||
/*4772*/ uint8 unknown4808[24];
|
/*4772*/ uint8 unknown4808[24];
|
||||||
/*4796*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
/*4796*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
||||||
/*5196*/ uint8 unknown5132[184];
|
/*5196*/ uint32 InnateSkills[MAX_PP_INNATE_SKILL];
|
||||||
|
/*5296*/ uint8 unknown5132[84];
|
||||||
/*5380*/ uint32 pvp2; //
|
/*5380*/ uint32 pvp2; //
|
||||||
/*5384*/ uint32 unknown5420; //
|
/*5384*/ uint32 unknown5420; //
|
||||||
/*5388*/ uint32 pvptype; //
|
/*5388*/ uint32 pvptype; //
|
||||||
@ -4764,6 +4767,7 @@ struct BuffIconEntry_Struct
|
|||||||
uint32 spell_id;
|
uint32 spell_id;
|
||||||
int32 tics_remaining;
|
int32 tics_remaining;
|
||||||
uint32 num_hits;
|
uint32 num_hits;
|
||||||
|
char caster[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BuffIcon_Struct
|
struct BuffIcon_Struct
|
||||||
@ -4773,6 +4777,7 @@ struct BuffIcon_Struct
|
|||||||
uint16 count;
|
uint16 count;
|
||||||
uint8 type; // 0 = self buff window, 1 = self target window, 4 = group, 5 = PC, 7 = NPC
|
uint8 type; // 0 = self buff window, 1 = self target window, 4 = group, 5 = PC, 7 = NPC
|
||||||
int32 tic_timer;
|
int32 tic_timer;
|
||||||
|
int32 name_lengths; // so ahh we kind of do these packets hacky, this is the total length of all the names to make creating the real packets in the translators easier
|
||||||
BuffIconEntry_Struct entries[0];
|
BuffIconEntry_Struct entries[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -88,6 +88,8 @@ enum LogCategory {
|
|||||||
Headless_Client,
|
Headless_Client,
|
||||||
HP_Update,
|
HP_Update,
|
||||||
FixZ,
|
FixZ,
|
||||||
|
Food,
|
||||||
|
Traps,
|
||||||
MaxCategoryID /* Don't Remove this*/
|
MaxCategoryID /* Don't Remove this*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,7 +142,9 @@ static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
|
|||||||
"Client Login",
|
"Client Login",
|
||||||
"Headless Client",
|
"Headless Client",
|
||||||
"HP Update",
|
"HP Update",
|
||||||
"FixZ"
|
"FixZ",
|
||||||
|
"Food",
|
||||||
|
"Traps"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -276,6 +276,11 @@ enum {
|
|||||||
#define SAYLINK_ITEM_ID 0xFFFFF
|
#define SAYLINK_ITEM_ID 0xFFFFF
|
||||||
|
|
||||||
|
|
||||||
|
// consumption timers for food/drink here instead of rules because the client
|
||||||
|
// uses these. Times in ms.
|
||||||
|
#define CONSUMPTION_TIMER 46000
|
||||||
|
#define CONSUMPTION_MNK_TIMER 92000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Developer configuration
|
Developer configuration
|
||||||
|
|||||||
@ -460,7 +460,7 @@ namespace RoF
|
|||||||
{
|
{
|
||||||
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
||||||
|
|
||||||
uint32 sz = 12 + (17 * emu->count);
|
uint32 sz = 12 + (17 * emu->count) + emu->name_lengths; // 17 includes nullterm
|
||||||
__packet->size = sz;
|
__packet->size = sz;
|
||||||
__packet->pBuffer = new unsigned char[sz];
|
__packet->pBuffer = new unsigned char[sz];
|
||||||
memset(__packet->pBuffer, 0, sz);
|
memset(__packet->pBuffer, 0, sz);
|
||||||
@ -476,7 +476,7 @@ namespace RoF
|
|||||||
__packet->WriteUInt32(emu->entries[i].spell_id);
|
__packet->WriteUInt32(emu->entries[i].spell_id);
|
||||||
__packet->WriteUInt32(emu->entries[i].tics_remaining);
|
__packet->WriteUInt32(emu->entries[i].tics_remaining);
|
||||||
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
|
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
|
||||||
__packet->WriteString("");
|
__packet->WriteString(emu->entries[i].caster);
|
||||||
}
|
}
|
||||||
__packet->WriteUInt8(emu->type); // Unknown
|
__packet->WriteUInt8(emu->type); // Unknown
|
||||||
|
|
||||||
@ -2184,11 +2184,11 @@ namespace RoF
|
|||||||
outapp->WriteUInt32(emu->skills[r]);
|
outapp->WriteUInt32(emu->skills[r]);
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteUInt32(25); // Unknown count
|
outapp->WriteUInt32(structs::MAX_PP_INNATE_SKILL); // Innate Skills count
|
||||||
|
|
||||||
for (uint32 r = 0; r < 25; r++)
|
for (uint32 r = 0; r < structs::MAX_PP_INNATE_SKILL; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(emu->InnateSkills[r]); // Innate Skills (regen, slam, etc)
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteUInt32(structs::MAX_PP_DISCIPLINES); // Discipline count
|
outapp->WriteUInt32(structs::MAX_PP_DISCIPLINES); // Discipline count
|
||||||
|
|||||||
@ -528,7 +528,7 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
||||||
|
|
||||||
uint32 sz = 12 + (17 * emu->count);
|
uint32 sz = 12 + (17 * emu->count) + emu->name_lengths; // 17 includes nullterm
|
||||||
__packet->size = sz;
|
__packet->size = sz;
|
||||||
__packet->pBuffer = new unsigned char[sz];
|
__packet->pBuffer = new unsigned char[sz];
|
||||||
memset(__packet->pBuffer, 0, sz);
|
memset(__packet->pBuffer, 0, sz);
|
||||||
@ -544,7 +544,7 @@ namespace RoF2
|
|||||||
__packet->WriteUInt32(emu->entries[i].spell_id);
|
__packet->WriteUInt32(emu->entries[i].spell_id);
|
||||||
__packet->WriteUInt32(emu->entries[i].tics_remaining);
|
__packet->WriteUInt32(emu->entries[i].tics_remaining);
|
||||||
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
|
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
|
||||||
__packet->WriteString("");
|
__packet->WriteString(emu->entries[i].caster);
|
||||||
}
|
}
|
||||||
__packet->WriteUInt8(emu->type); // Unknown
|
__packet->WriteUInt8(emu->type); // Unknown
|
||||||
|
|
||||||
@ -2261,11 +2261,11 @@ namespace RoF2
|
|||||||
outapp->WriteUInt32(emu->skills[r]);
|
outapp->WriteUInt32(emu->skills[r]);
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteUInt32(25); // Unknown count
|
outapp->WriteUInt32(structs::MAX_PP_INNATE_SKILL); // Innate Skills count
|
||||||
|
|
||||||
for (uint32 r = 0; r < 25; r++)
|
for (uint32 r = 0; r < structs::MAX_PP_INNATE_SKILL; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(emu->InnateSkills[r]); // Innate Skills (regen, slam, etc)
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteUInt32(structs::MAX_PP_DISCIPLINES); // Discipline count
|
outapp->WriteUInt32(structs::MAX_PP_DISCIPLINES); // Discipline count
|
||||||
|
|||||||
@ -164,7 +164,7 @@ namespace RoF2
|
|||||||
ItemPacket11 = 111,
|
ItemPacket11 = 111,
|
||||||
ItemPacket12 = 112,
|
ItemPacket12 = 112,
|
||||||
ItemPacketRecovery = 113,
|
ItemPacketRecovery = 113,
|
||||||
ItemPacket14 = 115
|
ItemPacket14 = 115 // Parcel? adds to merchant window too
|
||||||
};
|
};
|
||||||
|
|
||||||
} /*item*/
|
} /*item*/
|
||||||
|
|||||||
@ -131,6 +131,7 @@ static const uint32 MAX_PP_LANGUAGE = 32; // was 25
|
|||||||
static const uint32 MAX_PP_SPELLBOOK = 720; // was 480
|
static const uint32 MAX_PP_SPELLBOOK = 720; // was 480
|
||||||
static const uint32 MAX_PP_MEMSPELL = 16; // was 12
|
static const uint32 MAX_PP_MEMSPELL = 16; // was 12
|
||||||
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
||||||
|
static const uint32 MAX_PP_INNATE_SKILL = 25;
|
||||||
static const uint32 MAX_PP_AA_ARRAY = 300;
|
static const uint32 MAX_PP_AA_ARRAY = 300;
|
||||||
static const uint32 MAX_PP_DISCIPLINES = 300; // was 200
|
static const uint32 MAX_PP_DISCIPLINES = 300; // was 200
|
||||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||||
@ -617,7 +618,7 @@ struct NewZone_Struct {
|
|||||||
/*0704*/ char zone_short_name2[32]; //zone file name? excludes instance number which can be in previous version.
|
/*0704*/ char zone_short_name2[32]; //zone file name? excludes instance number which can be in previous version.
|
||||||
/*0736*/ char WeatherString[32];
|
/*0736*/ char WeatherString[32];
|
||||||
/*0768*/ char SkyString2[32];
|
/*0768*/ char SkyString2[32];
|
||||||
/*0800*/ int32 SkyRelated2; //seen -1
|
/*0800*/ int32 SkyRelated2; //seen -1 -- maybe some default sky time?
|
||||||
/*0804*/ char WeatherString2[32]; //
|
/*0804*/ char WeatherString2[32]; //
|
||||||
/*0836*/ float WeatherChangeTime; // not sure :P
|
/*0836*/ float WeatherChangeTime; // not sure :P
|
||||||
/*0840*/ uint32 Climate;
|
/*0840*/ uint32 Climate;
|
||||||
@ -1155,8 +1156,8 @@ union
|
|||||||
/*01012*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; // [300] 3600 bytes - AAs 12 bytes each
|
/*01012*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; // [300] 3600 bytes - AAs 12 bytes each
|
||||||
/*04612*/ uint32 skill_count; // Seen 100
|
/*04612*/ uint32 skill_count; // Seen 100
|
||||||
/*04616*/ uint32 skills[MAX_PP_SKILL]; // [100] 400 bytes - List of skills
|
/*04616*/ uint32 skills[MAX_PP_SKILL]; // [100] 400 bytes - List of skills
|
||||||
/*05016*/ uint32 unknown15_count; // Seen 25
|
/*05016*/ uint32 InnateSkills_count; // Seen 25
|
||||||
/*05020*/ uint32 unknown_rof15[25]; // Most are 255 or 0
|
/*05020*/ uint32 InnateSkills[MAX_PP_INNATE_SKILL]; // Most are 255 or 0
|
||||||
/*05120*/ uint32 discipline_count; // Seen 200
|
/*05120*/ uint32 discipline_count; // Seen 200
|
||||||
/*05124*/ Disciplines_Struct disciplines; // [200] 800 bytes Known disciplines
|
/*05124*/ Disciplines_Struct disciplines; // [200] 800 bytes Known disciplines
|
||||||
/*05924*/ uint32 timestamp_count; // Seen 20
|
/*05924*/ uint32 timestamp_count; // Seen 20
|
||||||
@ -1826,6 +1827,20 @@ struct MoveItem_Struct
|
|||||||
/*0028*/
|
/*0028*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MultiMoveItemSub_Struct
|
||||||
|
{
|
||||||
|
/*0000*/ InventorySlot_Struct from_slot;
|
||||||
|
/*0012*/ InventorySlot_Struct to_slot;
|
||||||
|
/*0024*/ uint32 number_in_stack;
|
||||||
|
/*0028*/ uint8 unknown[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiMoveItem_Struct
|
||||||
|
{
|
||||||
|
/*0000*/ uint32 count;
|
||||||
|
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// from_slot/to_slot
|
// from_slot/to_slot
|
||||||
// -1 - destroy
|
// -1 - destroy
|
||||||
|
|||||||
@ -131,6 +131,7 @@ static const uint32 MAX_PP_LANGUAGE = 32; // was 25
|
|||||||
static const uint32 MAX_PP_SPELLBOOK = 720; // was 480
|
static const uint32 MAX_PP_SPELLBOOK = 720; // was 480
|
||||||
static const uint32 MAX_PP_MEMSPELL = 16; // was 12
|
static const uint32 MAX_PP_MEMSPELL = 16; // was 12
|
||||||
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
||||||
|
static const uint32 MAX_PP_INNATE_SKILL = 25;
|
||||||
static const uint32 MAX_PP_AA_ARRAY = 300;
|
static const uint32 MAX_PP_AA_ARRAY = 300;
|
||||||
static const uint32 MAX_PP_DISCIPLINES = 200; // was 100
|
static const uint32 MAX_PP_DISCIPLINES = 200; // was 100
|
||||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||||
@ -1096,8 +1097,8 @@ union
|
|||||||
/*01012*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; // [300] 3600 bytes - AAs 12 bytes each
|
/*01012*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; // [300] 3600 bytes - AAs 12 bytes each
|
||||||
/*04612*/ uint32 skill_count; // Seen 100
|
/*04612*/ uint32 skill_count; // Seen 100
|
||||||
/*04616*/ uint32 skills[MAX_PP_SKILL]; // [100] 400 bytes - List of skills
|
/*04616*/ uint32 skills[MAX_PP_SKILL]; // [100] 400 bytes - List of skills
|
||||||
/*05016*/ uint32 unknown15_count; // Seen 25
|
/*05016*/ uint32 InnateSkills_count; // Seen 25
|
||||||
/*05020*/ uint32 unknown_rof15[25]; // Most are 255 or 0
|
/*05020*/ uint32 InnateSkills[MAX_PP_INNATE_SKILL]; // Most are 255 or 0
|
||||||
/*05120*/ uint32 discipline_count; // Seen 200
|
/*05120*/ uint32 discipline_count; // Seen 200
|
||||||
/*05124*/ Disciplines_Struct disciplines; // [200] 800 bytes Known disciplines
|
/*05124*/ Disciplines_Struct disciplines; // [200] 800 bytes Known disciplines
|
||||||
/*05924*/ uint32 timestamp_count; // Seen 20
|
/*05924*/ uint32 timestamp_count; // Seen 20
|
||||||
|
|||||||
@ -1605,6 +1605,7 @@ namespace SoD
|
|||||||
OUT(copper_cursor);
|
OUT(copper_cursor);
|
||||||
|
|
||||||
OUT_array(skills, structs::MAX_PP_SKILL); // 1:1 direct copy (100 dword)
|
OUT_array(skills, structs::MAX_PP_SKILL); // 1:1 direct copy (100 dword)
|
||||||
|
OUT_array(InnateSkills, structs::MAX_PP_INNATE_SKILL); // 1:1 direct copy (25 dword)
|
||||||
|
|
||||||
// OUT(unknown04760[236]);
|
// OUT(unknown04760[236]);
|
||||||
OUT(toxicity);
|
OUT(toxicity);
|
||||||
|
|||||||
@ -818,6 +818,7 @@ static const uint32 MAX_PP_LANGUAGE = 25; //
|
|||||||
static const uint32 MAX_PP_SPELLBOOK = 480; // Confirmed 60 pages on Live now
|
static const uint32 MAX_PP_SPELLBOOK = 480; // Confirmed 60 pages on Live now
|
||||||
static const uint32 MAX_PP_MEMSPELL = 10; //was 9 now 10 on Live
|
static const uint32 MAX_PP_MEMSPELL = 10; //was 9 now 10 on Live
|
||||||
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
||||||
|
static const uint32 MAX_PP_INNATE_SKILL = 25;
|
||||||
static const uint32 MAX_PP_AA_ARRAY = 300; //was 299
|
static const uint32 MAX_PP_AA_ARRAY = 300; //was 299
|
||||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||||
static const uint32 MAX_RECAST_TYPES = 20;
|
static const uint32 MAX_RECAST_TYPES = 20;
|
||||||
@ -923,7 +924,8 @@ struct PlayerProfile_Struct
|
|||||||
/*06488*/ uint32 silver_cursor; // Silver Pieces on cursor
|
/*06488*/ uint32 silver_cursor; // Silver Pieces on cursor
|
||||||
/*06492*/ uint32 copper_cursor; // Copper Pieces on cursor
|
/*06492*/ uint32 copper_cursor; // Copper Pieces on cursor
|
||||||
/*06496*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
/*06496*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
||||||
/*06896*/ uint8 unknown04760[136];
|
/*06896*/ uint32 InnateSkills[MAX_PP_SKILL];
|
||||||
|
/*06996*/ uint8 unknown04760[36];
|
||||||
/*07032*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
/*07032*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
||||||
/*07036*/ uint32 thirst_level; // Drink (ticks till next drink)
|
/*07036*/ uint32 thirst_level; // Drink (ticks till next drink)
|
||||||
/*07040*/ uint32 hunger_level; // Food (ticks till next eat)
|
/*07040*/ uint32 hunger_level; // Food (ticks till next eat)
|
||||||
|
|||||||
@ -1276,6 +1276,7 @@ namespace SoF
|
|||||||
OUT(copper_cursor);
|
OUT(copper_cursor);
|
||||||
|
|
||||||
OUT_array(skills, structs::MAX_PP_SKILL); // 1:1 direct copy (100 dword)
|
OUT_array(skills, structs::MAX_PP_SKILL); // 1:1 direct copy (100 dword)
|
||||||
|
OUT_array(InnateSkills, structs::MAX_PP_INNATE_SKILL); // 1:1 direct copy (25 dword)
|
||||||
|
|
||||||
// OUT(unknown04760[236]);
|
// OUT(unknown04760[236]);
|
||||||
OUT(toxicity);
|
OUT(toxicity);
|
||||||
|
|||||||
@ -52,6 +52,25 @@ struct EnterWorld_Struct {
|
|||||||
struct WorldObjectsSent_Struct {
|
struct WorldObjectsSent_Struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// yep, even SoF had a version of the new inventory system, used by OP_MoveMultipleItems
|
||||||
|
struct InventorySlot_Struct
|
||||||
|
{
|
||||||
|
/*000*/ int32 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Trade = 3, World = 4, Limbo = 5
|
||||||
|
/*004*/ int32 Slot;
|
||||||
|
/*008*/ int32 SubIndex;
|
||||||
|
/*012*/ int32 AugIndex;
|
||||||
|
/*016*/ int32 Unknown01;
|
||||||
|
};
|
||||||
|
|
||||||
|
// unsure if they have a version of this, completeness though
|
||||||
|
struct TypelessInventorySlot_Struct
|
||||||
|
{
|
||||||
|
/*000*/ int32 Slot;
|
||||||
|
/*004*/ int32 SubIndex;
|
||||||
|
/*008*/ int32 AugIndex;
|
||||||
|
/*012*/ int32 Unknown01;
|
||||||
|
};
|
||||||
|
|
||||||
/* Name Approval Struct */
|
/* Name Approval Struct */
|
||||||
/* Len: */
|
/* Len: */
|
||||||
/* Opcode: 0x8B20*/
|
/* Opcode: 0x8B20*/
|
||||||
@ -799,6 +818,7 @@ static const uint32 MAX_PP_LANGUAGE = 25; //
|
|||||||
static const uint32 MAX_PP_SPELLBOOK = 480; // Confirmed 60 pages on Live now
|
static const uint32 MAX_PP_SPELLBOOK = 480; // Confirmed 60 pages on Live now
|
||||||
static const uint32 MAX_PP_MEMSPELL = 10; //was 9 now 10 on Live
|
static const uint32 MAX_PP_MEMSPELL = 10; //was 9 now 10 on Live
|
||||||
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
||||||
|
static const uint32 MAX_PP_INNATE_SKILL = 25;
|
||||||
static const uint32 MAX_PP_AA_ARRAY = 300; //was 299
|
static const uint32 MAX_PP_AA_ARRAY = 300; //was 299
|
||||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||||
static const uint32 MAX_RECAST_TYPES = 20;
|
static const uint32 MAX_RECAST_TYPES = 20;
|
||||||
@ -903,7 +923,8 @@ struct PlayerProfile_Struct //23576 Octets
|
|||||||
/*06488*/ uint32 silver_cursor; // Silver Pieces on cursor
|
/*06488*/ uint32 silver_cursor; // Silver Pieces on cursor
|
||||||
/*06492*/ uint32 copper_cursor; // Copper Pieces on cursor
|
/*06492*/ uint32 copper_cursor; // Copper Pieces on cursor
|
||||||
/*06496*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
/*06496*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
||||||
/*06896*/ uint8 unknown04760[136];
|
/*06896*/ uint32 InnateSkills[MAX_PP_INNATE_SKILL];
|
||||||
|
/*06996*/ uint8 unknown04760[36];
|
||||||
/*07032*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
/*07032*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
||||||
/*07036*/ uint32 thirst_level; // Drink (ticks till next drink)
|
/*07036*/ uint32 thirst_level; // Drink (ticks till next drink)
|
||||||
/*07040*/ uint32 hunger_level; // Food (ticks till next eat)
|
/*07040*/ uint32 hunger_level; // Food (ticks till next eat)
|
||||||
@ -1555,6 +1576,19 @@ struct MoveItem_Struct
|
|||||||
/*0012*/
|
/*0012*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MultiMoveItemSub_Struct
|
||||||
|
{
|
||||||
|
/*0000*/ InventorySlot_Struct from_slot;
|
||||||
|
/*0020*/ uint32 number_in_stack; // so the amount we are moving from the source
|
||||||
|
/*0024*/ InventorySlot_Struct to_slot;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiMoveItem_Struct
|
||||||
|
{
|
||||||
|
/*0000*/ uint32 count;
|
||||||
|
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// from_slot/to_slot
|
// from_slot/to_slot
|
||||||
// -1 - destroy
|
// -1 - destroy
|
||||||
|
|||||||
@ -1020,6 +1020,7 @@ namespace Titanium
|
|||||||
OUT(copper_cursor);
|
OUT(copper_cursor);
|
||||||
|
|
||||||
OUT_array(skills, structs::MAX_PP_SKILL); // 1:1 direct copy (100 dword)
|
OUT_array(skills, structs::MAX_PP_SKILL); // 1:1 direct copy (100 dword)
|
||||||
|
OUT_array(InnateSkills, structs::MAX_PP_INNATE_SKILL); // 1:1 direct copy (25 dword)
|
||||||
|
|
||||||
// OUT(unknown04760[236]);
|
// OUT(unknown04760[236]);
|
||||||
OUT(toxicity);
|
OUT(toxicity);
|
||||||
|
|||||||
@ -48,6 +48,23 @@ struct EnterWorld_Struct {
|
|||||||
/*068*/ uint32 return_home; // 01 on "Return Home", 00 if not
|
/*068*/ uint32 return_home; // 01 on "Return Home", 00 if not
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// yep, even tit had a version of the new inventory system, used by OP_MoveMultipleItems
|
||||||
|
struct InventorySlot_Struct
|
||||||
|
{
|
||||||
|
/*000*/ int32 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Trade = 3, World = 4, Limbo = 5
|
||||||
|
/*004*/ int32 Slot;
|
||||||
|
/*008*/ int32 SubIndex; // no aug index in Tit
|
||||||
|
/*012*/ int32 Unknown01;
|
||||||
|
};
|
||||||
|
|
||||||
|
// unsure if they have a version of this, completeness though
|
||||||
|
struct TypelessInventorySlot_Struct
|
||||||
|
{
|
||||||
|
/*000*/ int32 Slot;
|
||||||
|
/*004*/ int32 SubIndex; // no aug index in Tit
|
||||||
|
/*008*/ int32 Unknown01;
|
||||||
|
};
|
||||||
|
|
||||||
/* Name Approval Struct */
|
/* Name Approval Struct */
|
||||||
/* Len: */
|
/* Len: */
|
||||||
/* Opcode: 0x8B20*/
|
/* Opcode: 0x8B20*/
|
||||||
@ -740,6 +757,7 @@ static const uint32 MAX_PP_LANGUAGE = 28;
|
|||||||
static const uint32 MAX_PP_SPELLBOOK = 400;
|
static const uint32 MAX_PP_SPELLBOOK = 400;
|
||||||
static const uint32 MAX_PP_MEMSPELL = 9;
|
static const uint32 MAX_PP_MEMSPELL = 9;
|
||||||
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
||||||
|
static const uint32 MAX_PP_INNATE_SKILL = 25;
|
||||||
static const uint32 MAX_PP_AA_ARRAY = 240;
|
static const uint32 MAX_PP_AA_ARRAY = 240;
|
||||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||||
static const uint32 MAX_RECAST_TYPES = 20;
|
static const uint32 MAX_RECAST_TYPES = 20;
|
||||||
@ -844,7 +862,8 @@ struct PlayerProfile_Struct
|
|||||||
/*04452*/ uint32 silver_cursor; // Silver Pieces on cursor
|
/*04452*/ uint32 silver_cursor; // Silver Pieces on cursor
|
||||||
/*04456*/ uint32 copper_cursor; // Copper Pieces on cursor
|
/*04456*/ uint32 copper_cursor; // Copper Pieces on cursor
|
||||||
/*04460*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
/*04460*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
||||||
/*04860*/ uint8 unknown04760[136];
|
/*04860*/ uint32 InnateSkills[MAX_PP_INNATE_SKILL];
|
||||||
|
/*04960*/ uint8 unknown04760[36];
|
||||||
/*04996*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
/*04996*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
||||||
/*05000*/ uint32 thirst_level; // Drink (ticks till next drink)
|
/*05000*/ uint32 thirst_level; // Drink (ticks till next drink)
|
||||||
/*05004*/ uint32 hunger_level; // Food (ticks till next eat)
|
/*05004*/ uint32 hunger_level; // Food (ticks till next eat)
|
||||||
@ -1327,6 +1346,19 @@ struct MoveItem_Struct
|
|||||||
/*0012*/
|
/*0012*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MultiMoveItemSub_Struct
|
||||||
|
{
|
||||||
|
/*0000*/ InventorySlot_Struct from_slot;
|
||||||
|
/*0016*/ uint32 number_in_stack; // so the amount we are moving from the source
|
||||||
|
/*0020*/ InventorySlot_Struct to_slot;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiMoveItem_Struct
|
||||||
|
{
|
||||||
|
/*0000*/ uint32 count;
|
||||||
|
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// from_slot/to_slot
|
// from_slot/to_slot
|
||||||
// -1 - destroy
|
// -1 - destroy
|
||||||
|
|||||||
@ -391,7 +391,7 @@ namespace UF
|
|||||||
{
|
{
|
||||||
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
||||||
|
|
||||||
uint32 sz = 12 + (17 * emu->count);
|
uint32 sz = 12 + (17 * emu->count) + emu->name_lengths; // 17 includes nullterm
|
||||||
__packet->size = sz;
|
__packet->size = sz;
|
||||||
__packet->pBuffer = new unsigned char[sz];
|
__packet->pBuffer = new unsigned char[sz];
|
||||||
memset(__packet->pBuffer, 0, sz);
|
memset(__packet->pBuffer, 0, sz);
|
||||||
@ -407,7 +407,7 @@ namespace UF
|
|||||||
__packet->WriteUInt32(emu->entries[i].spell_id);
|
__packet->WriteUInt32(emu->entries[i].spell_id);
|
||||||
__packet->WriteUInt32(emu->entries[i].tics_remaining);
|
__packet->WriteUInt32(emu->entries[i].tics_remaining);
|
||||||
__packet->WriteUInt32(emu->entries[i].num_hits);
|
__packet->WriteUInt32(emu->entries[i].num_hits);
|
||||||
__packet->WriteString("");
|
__packet->WriteString(emu->entries[i].caster);
|
||||||
}
|
}
|
||||||
__packet->WriteUInt8(emu->type);
|
__packet->WriteUInt8(emu->type);
|
||||||
|
|
||||||
@ -1850,6 +1850,7 @@ namespace UF
|
|||||||
OUT(copper_cursor);
|
OUT(copper_cursor);
|
||||||
|
|
||||||
OUT_array(skills, structs::MAX_PP_SKILL); // 1:1 direct copy (100 dword)
|
OUT_array(skills, structs::MAX_PP_SKILL); // 1:1 direct copy (100 dword)
|
||||||
|
OUT_array(InnateSkills, structs::MAX_PP_INNATE_SKILL); // 1:1 direct copy (25 dword)
|
||||||
|
|
||||||
// OUT(unknown04760[236]);
|
// OUT(unknown04760[236]);
|
||||||
OUT(toxicity);
|
OUT(toxicity);
|
||||||
|
|||||||
@ -848,6 +848,7 @@ static const uint32 MAX_PP_LANGUAGE = 25; //
|
|||||||
static const uint32 MAX_PP_SPELLBOOK = 720; // Confirmed 60 pages on Underfoot now
|
static const uint32 MAX_PP_SPELLBOOK = 720; // Confirmed 60 pages on Underfoot now
|
||||||
static const uint32 MAX_PP_MEMSPELL = 12; //was 9 now 10 on Underfoot
|
static const uint32 MAX_PP_MEMSPELL = 12; //was 9 now 10 on Underfoot
|
||||||
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
||||||
|
static const uint32 MAX_PP_INNATE_SKILL = 25;
|
||||||
static const uint32 MAX_PP_AA_ARRAY = 300; //was 299
|
static const uint32 MAX_PP_AA_ARRAY = 300; //was 299
|
||||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||||
static const uint32 MAX_RECAST_TYPES = 20;
|
static const uint32 MAX_RECAST_TYPES = 20;
|
||||||
@ -954,7 +955,8 @@ struct PlayerProfile_Struct
|
|||||||
/*07336*/ uint32 silver_cursor; // Silver Pieces on cursor
|
/*07336*/ uint32 silver_cursor; // Silver Pieces on cursor
|
||||||
/*07340*/ uint32 copper_cursor; // Copper Pieces on cursor
|
/*07340*/ uint32 copper_cursor; // Copper Pieces on cursor
|
||||||
/*07344*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
/*07344*/ uint32 skills[MAX_PP_SKILL]; // [400] List of skills // 100 dword buffer
|
||||||
/*07744*/ uint8 unknown07644[136];
|
/*07744*/ uint32 InnateSkills[MAX_PP_INNATE_SKILL];
|
||||||
|
/*07844*/ uint8 unknown07644[36];
|
||||||
/*07880*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
/*07880*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3)
|
||||||
/*07884*/ uint32 thirst_level; // Drink (ticks till next drink)
|
/*07884*/ uint32 thirst_level; // Drink (ticks till next drink)
|
||||||
/*07888*/ uint32 hunger_level; // Food (ticks till next eat)
|
/*07888*/ uint32 hunger_level; // Food (ticks till next eat)
|
||||||
|
|||||||
@ -44,6 +44,7 @@ RULE_INT(Character, DeathExpLossMaxLevel, 255) // Any level greater than this wi
|
|||||||
RULE_INT(Character, DeathItemLossLevel, 10)
|
RULE_INT(Character, DeathItemLossLevel, 10)
|
||||||
RULE_INT(Character, DeathExpLossMultiplier, 3) //Adjust how much exp is lost
|
RULE_INT(Character, DeathExpLossMultiplier, 3) //Adjust how much exp is lost
|
||||||
RULE_BOOL(Character, UseDeathExpLossMult, false) //Adjust to use the above multiplier or to use code default.
|
RULE_BOOL(Character, UseDeathExpLossMult, false) //Adjust to use the above multiplier or to use code default.
|
||||||
|
RULE_BOOL(Character, UseOldRaceRezEffects, false) // older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore
|
||||||
RULE_INT(Character, CorpseDecayTimeMS, 10800000)
|
RULE_INT(Character, CorpseDecayTimeMS, 10800000)
|
||||||
RULE_INT(Character, CorpseResTimeMS, 10800000) // time before cant res corpse(3 hours)
|
RULE_INT(Character, CorpseResTimeMS, 10800000) // time before cant res corpse(3 hours)
|
||||||
RULE_BOOL(Character, LeaveCorpses, true)
|
RULE_BOOL(Character, LeaveCorpses, true)
|
||||||
@ -66,11 +67,12 @@ RULE_INT(Character, AutosaveIntervalS, 300) //0=disabled
|
|||||||
RULE_INT(Character, HPRegenMultiplier, 100)
|
RULE_INT(Character, HPRegenMultiplier, 100)
|
||||||
RULE_INT(Character, ManaRegenMultiplier, 100)
|
RULE_INT(Character, ManaRegenMultiplier, 100)
|
||||||
RULE_INT(Character, EnduranceRegenMultiplier, 100)
|
RULE_INT(Character, EnduranceRegenMultiplier, 100)
|
||||||
|
RULE_BOOL(Character, OldMinMana, false) // this is used for servers that want to follow older skill cap formulas so they can still have some regen w/o mediate
|
||||||
RULE_INT(Character, ConsumptionMultiplier, 100) //item's hunger restored = this value * item's food level, 100 = normal, 50 = people eat 2x as fast, 200 = people eat 2x as slow
|
RULE_INT(Character, ConsumptionMultiplier, 100) //item's hunger restored = this value * item's food level, 100 = normal, 50 = people eat 2x as fast, 200 = people eat 2x as slow
|
||||||
RULE_BOOL(Character, HealOnLevel, false)
|
RULE_BOOL(Character, HealOnLevel, false)
|
||||||
RULE_BOOL(Character, FeignKillsPet, false)
|
RULE_BOOL(Character, FeignKillsPet, false)
|
||||||
RULE_INT(Character, ItemManaRegenCap, 15)
|
RULE_INT(Character, ItemManaRegenCap, 15)
|
||||||
RULE_INT(Character, ItemHealthRegenCap, 35)
|
RULE_INT(Character, ItemHealthRegenCap, 30)
|
||||||
RULE_INT(Character, ItemDamageShieldCap, 30)
|
RULE_INT(Character, ItemDamageShieldCap, 30)
|
||||||
RULE_INT(Character, ItemAccuracyCap, 150)
|
RULE_INT(Character, ItemAccuracyCap, 150)
|
||||||
RULE_INT(Character, ItemAvoidanceCap, 100)
|
RULE_INT(Character, ItemAvoidanceCap, 100)
|
||||||
@ -91,10 +93,12 @@ RULE_INT(Character, HasteCap, 100) // Haste cap for non-v3(overhaste) haste.
|
|||||||
RULE_INT(Character, SkillUpModifier, 100) //skill ups are at 100%
|
RULE_INT(Character, SkillUpModifier, 100) //skill ups are at 100%
|
||||||
RULE_BOOL(Character, SharedBankPlat, false) //off by default to prevent duping for now
|
RULE_BOOL(Character, SharedBankPlat, false) //off by default to prevent duping for now
|
||||||
RULE_BOOL(Character, BindAnywhere, false)
|
RULE_BOOL(Character, BindAnywhere, false)
|
||||||
RULE_INT(Character, RestRegenPercent, 0) // Set to >0 to enable rest state bonus HP and mana regen.
|
RULE_BOOL(Character, RestRegenEnabled, true) // Enable OOC Regen
|
||||||
|
RULE_INT(Character, RestRegenHP, 180) // seconds until full from 0. this is actually zone setable, but most or all zones are 180
|
||||||
|
RULE_INT(Character, RestRegenMana, 180) // seconds until full from 0. this is actually zone setable, but most or all zones are 180
|
||||||
|
RULE_INT(Character, RestRegenEnd, 180) // seconds until full from 0. this is actually zone setable, but most or all zones are 180
|
||||||
RULE_INT(Character, RestRegenTimeToActivate, 30) // Time in seconds for rest state regen to kick in.
|
RULE_INT(Character, RestRegenTimeToActivate, 30) // Time in seconds for rest state regen to kick in.
|
||||||
RULE_INT(Character, RestRegenRaidTimeToActivate, 300) // Time in seconds for rest state regen to kick in with a raid target.
|
RULE_INT(Character, RestRegenRaidTimeToActivate, 300) // Time in seconds for rest state regen to kick in with a raid target.
|
||||||
RULE_BOOL(Character, RestRegenEndurance, false) // Whether rest regen will work for endurance or not.
|
|
||||||
RULE_INT(Character, KillsPerGroupLeadershipAA, 250) // Number of dark blues or above per Group Leadership AA
|
RULE_INT(Character, KillsPerGroupLeadershipAA, 250) // Number of dark blues or above per Group Leadership AA
|
||||||
RULE_INT(Character, KillsPerRaidLeadershipAA, 250) // Number of dark blues or above per Raid Leadership AA
|
RULE_INT(Character, KillsPerRaidLeadershipAA, 250) // Number of dark blues or above per Raid Leadership AA
|
||||||
RULE_INT(Character, MaxFearDurationForPlayerCharacter, 4) //4 tics, each tic calculates every 6 seconds.
|
RULE_INT(Character, MaxFearDurationForPlayerCharacter, 4) //4 tics, each tic calculates every 6 seconds.
|
||||||
@ -117,7 +121,8 @@ RULE_BOOL(Character, EnableDiscoveredItems, true) // If enabled, it enables EVEN
|
|||||||
RULE_BOOL(Character, EnableXTargetting, true) // Enable Extended Targetting Window, for users with UF and later clients.
|
RULE_BOOL(Character, EnableXTargetting, true) // Enable Extended Targetting Window, for users with UF and later clients.
|
||||||
RULE_BOOL(Character, EnableAggroMeter, true) // Enable Aggro Meter, for users with RoF and later clients.
|
RULE_BOOL(Character, EnableAggroMeter, true) // Enable Aggro Meter, for users with RoF and later clients.
|
||||||
RULE_BOOL(Character, KeepLevelOverMax, false) // Don't delevel a character that has somehow gone over the level cap
|
RULE_BOOL(Character, KeepLevelOverMax, false) // Don't delevel a character that has somehow gone over the level cap
|
||||||
RULE_INT(Character, FoodLossPerUpdate, 35) // How much food/water you lose per stamina update
|
RULE_INT(Character, FoodLossPerUpdate, 32) // How much food/water you lose per stamina update
|
||||||
|
RULE_BOOL(Character, EnableHungerPenalties, false) // being hungry/thirsty has negative effects -- it does appear normal live servers do not have penalties
|
||||||
RULE_INT(Character, BaseInstrumentSoftCap, 36) // Softcap for instrument mods, 36 commonly referred to as "3.6" as well.
|
RULE_INT(Character, BaseInstrumentSoftCap, 36) // Softcap for instrument mods, 36 commonly referred to as "3.6" as well.
|
||||||
RULE_BOOL(Character, UseSpellFileSongCap, true) // When they removed the AA that increased the cap they removed the above and just use the spell field
|
RULE_BOOL(Character, UseSpellFileSongCap, true) // When they removed the AA that increased the cap they removed the above and just use the spell field
|
||||||
RULE_INT(Character, BaseRunSpeedCap, 158) // Base Run Speed Cap, on live it's 158% which will give you a runspeed of 1.580 hard capped to 225.
|
RULE_INT(Character, BaseRunSpeedCap, 158) // Base Run Speed Cap, on live it's 158% which will give you a runspeed of 1.580 hard capped to 225.
|
||||||
@ -186,12 +191,14 @@ RULE_INT(Skills, MaxTrainSpecializations, 50) // Max level a GM trainer will tra
|
|||||||
RULE_INT(Skills, SwimmingStartValue, 100)
|
RULE_INT(Skills, SwimmingStartValue, 100)
|
||||||
RULE_BOOL(Skills, TrainSenseHeading, false)
|
RULE_BOOL(Skills, TrainSenseHeading, false)
|
||||||
RULE_INT(Skills, SenseHeadingStartValue, 200)
|
RULE_INT(Skills, SenseHeadingStartValue, 200)
|
||||||
|
RULE_BOOL(Skills, SelfLanguageLearning, true)
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Pets)
|
RULE_CATEGORY(Pets)
|
||||||
RULE_REAL(Pets, AttackCommandRange, 150)
|
RULE_REAL(Pets, AttackCommandRange, 150)
|
||||||
RULE_BOOL(Pets, UnTargetableSwarmPet, false)
|
RULE_BOOL(Pets, UnTargetableSwarmPet, false)
|
||||||
RULE_REAL(Pets, PetPowerLevelCap, 10) // Max number of levels your pet can go up with pet power
|
RULE_REAL(Pets, PetPowerLevelCap, 10) // Max number of levels your pet can go up with pet power
|
||||||
|
RULE_BOOL(Pets, CanTakeNoDrop, false) // Can everyone trade nodrop gear to pets
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(GM)
|
RULE_CATEGORY(GM)
|
||||||
@ -502,6 +509,7 @@ RULE_INT(Combat, NPCAssistCapTimer, 6000) // Time in milliseconds a NPC will tak
|
|||||||
RULE_BOOL(Combat, UseRevampHandToHand, false) // use h2h revamped dmg/delays I believe this was implemented during SoF
|
RULE_BOOL(Combat, UseRevampHandToHand, false) // use h2h revamped dmg/delays I believe this was implemented during SoF
|
||||||
RULE_BOOL(Combat, ClassicMasterWu, false) // classic master wu uses a random special, modern doesn't
|
RULE_BOOL(Combat, ClassicMasterWu, false) // classic master wu uses a random special, modern doesn't
|
||||||
RULE_INT(Combat, LevelToStopDamageCaps, 0) // 1 will effectively disable them, 20 should give basically same results as old incorrect system
|
RULE_INT(Combat, LevelToStopDamageCaps, 0) // 1 will effectively disable them, 20 should give basically same results as old incorrect system
|
||||||
|
RULE_BOOL(Combat, ClassicNPCBackstab, false) // true disables npc facestab - npcs get normal attack if not behind
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(NPC)
|
RULE_CATEGORY(NPC)
|
||||||
@ -563,6 +571,8 @@ RULE_INT(Range, DamageMessages, 50)
|
|||||||
RULE_INT(Range, SpellMessages, 75)
|
RULE_INT(Range, SpellMessages, 75)
|
||||||
RULE_INT(Range, SongMessages, 75)
|
RULE_INT(Range, SongMessages, 75)
|
||||||
RULE_INT(Range, MobPositionUpdates, 600)
|
RULE_INT(Range, MobPositionUpdates, 600)
|
||||||
|
RULE_INT(Range, ClientPositionUpdates, 300)
|
||||||
|
RULE_INT(Range, ClientForceSpawnUpdateRange, 1000)
|
||||||
RULE_INT(Range, CriticalDamage, 80)
|
RULE_INT(Range, CriticalDamage, 80)
|
||||||
RULE_INT(Range, ClientNPCScan, 300)
|
RULE_INT(Range, ClientNPCScan, 300)
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|||||||
@ -1817,8 +1817,8 @@ void SharedDatabase::LoadBaseData(void *data, int max_level) {
|
|||||||
bd->base_hp = atof(row[2]);
|
bd->base_hp = atof(row[2]);
|
||||||
bd->base_mana = atof(row[3]);
|
bd->base_mana = atof(row[3]);
|
||||||
bd->base_end = atof(row[4]);
|
bd->base_end = atof(row[4]);
|
||||||
bd->unk1 = atof(row[5]);
|
bd->hp_regen = atof(row[5]);
|
||||||
bd->unk2 = atof(row[6]);
|
bd->end_regen = atof(row[6]);
|
||||||
bd->hp_factor = atof(row[7]);
|
bd->hp_factor = atof(row[7]);
|
||||||
bd->mana_factor = atof(row[8]);
|
bd->mana_factor = atof(row[8]);
|
||||||
bd->endurance_factor = atof(row[9]);
|
bd->endurance_factor = atof(row[9]);
|
||||||
|
|||||||
@ -131,6 +131,11 @@ enum SpellAffectIndex {
|
|||||||
SAI_NPC_Special_80 = 80,
|
SAI_NPC_Special_80 = 80,
|
||||||
SAI_Trap_Lock = 88
|
SAI_Trap_Lock = 88
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GlobalGroup {
|
||||||
|
Lich = 46,
|
||||||
|
};
|
||||||
|
|
||||||
enum RESISTTYPE
|
enum RESISTTYPE
|
||||||
{
|
{
|
||||||
RESIST_NONE = 0,
|
RESIST_NONE = 0,
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9114
|
#define CURRENT_BINARY_DATABASE_VERSION 9115
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -1719,6 +1719,8 @@ FMT_DEFINE_INT_FORMATTERS(unsigned long)
|
|||||||
FMT_DEFINE_INT_FORMATTERS(LongLong)
|
FMT_DEFINE_INT_FORMATTERS(LongLong)
|
||||||
FMT_DEFINE_INT_FORMATTERS(ULongLong)
|
FMT_DEFINE_INT_FORMATTERS(ULongLong)
|
||||||
|
|
||||||
|
#define CHAR_WIDTH 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Returns a string formatter that pads the formatted argument with the fill
|
Returns a string formatter that pads the formatted argument with the fill
|
||||||
@ -1823,7 +1825,7 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
|||||||
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
||||||
Char fill = internal::CharTraits<Char>::cast(spec_.fill());
|
Char fill = internal::CharTraits<Char>::cast(spec_.fill());
|
||||||
CharPtr out = CharPtr();
|
CharPtr out = CharPtr();
|
||||||
const unsigned CHAR_WIDTH = 1;
|
|
||||||
if (spec_.width_ > CHAR_WIDTH) {
|
if (spec_.width_ > CHAR_WIDTH) {
|
||||||
out = writer_.grow_buffer(spec_.width_);
|
out = writer_.grow_buffer(spec_.width_);
|
||||||
if (spec_.align_ == ALIGN_RIGHT) {
|
if (spec_.align_ == ALIGN_RIGHT) {
|
||||||
|
|||||||
@ -248,6 +248,7 @@ OP_AutoAttack=0x0d14
|
|||||||
OP_AutoAttack2=0x3912
|
OP_AutoAttack2=0x3912
|
||||||
OP_Consume=0x4692
|
OP_Consume=0x4692
|
||||||
OP_MoveItem=0x62a2
|
OP_MoveItem=0x62a2
|
||||||
|
OP_MoveMultipleItems=0x55ef
|
||||||
OP_DeleteItem=0x3eb5
|
OP_DeleteItem=0x3eb5
|
||||||
OP_DeleteCharge=0x2d5b
|
OP_DeleteCharge=0x2d5b
|
||||||
OP_ItemPacket=0x5e0e
|
OP_ItemPacket=0x5e0e
|
||||||
@ -341,6 +342,7 @@ OP_MobUpdate=0x6b5a
|
|||||||
OP_NPCMoveUpdate=0x5bd9
|
OP_NPCMoveUpdate=0x5bd9
|
||||||
OP_CameraEffect=0x5712
|
OP_CameraEffect=0x5712
|
||||||
OP_SpellEffect=0x72b6
|
OP_SpellEffect=0x72b6
|
||||||
|
OP_AddNimbusEffect=0x2954
|
||||||
OP_RemoveNimbusEffect=0x3ba7
|
OP_RemoveNimbusEffect=0x3ba7
|
||||||
OP_AltCurrency=0x8fcb
|
OP_AltCurrency=0x8fcb
|
||||||
OP_AltCurrencyMerchantRequest=0x7e3e
|
OP_AltCurrencyMerchantRequest=0x7e3e
|
||||||
|
|||||||
@ -247,6 +247,7 @@ OP_AutoAttack=0x109d
|
|||||||
OP_AutoAttack2=0x3526
|
OP_AutoAttack2=0x3526
|
||||||
OP_Consume=0x4b70
|
OP_Consume=0x4b70
|
||||||
OP_MoveItem=0x32ee
|
OP_MoveItem=0x32ee
|
||||||
|
OP_MoveMultipleItems=0x5623
|
||||||
OP_DeleteItem=0x18ad
|
OP_DeleteItem=0x18ad
|
||||||
OP_DeleteCharge=0x01b8
|
OP_DeleteCharge=0x01b8
|
||||||
OP_ItemPacket=0x368e
|
OP_ItemPacket=0x368e
|
||||||
@ -340,6 +341,7 @@ OP_MobUpdate=0x2c84
|
|||||||
OP_NPCMoveUpdate=0x5892
|
OP_NPCMoveUpdate=0x5892
|
||||||
OP_CameraEffect=0x127f
|
OP_CameraEffect=0x127f
|
||||||
OP_SpellEffect=0x5936
|
OP_SpellEffect=0x5936
|
||||||
|
OP_AddNimbusEffect=0xc693
|
||||||
OP_RemoveNimbusEffect=0x7b1e
|
OP_RemoveNimbusEffect=0x7b1e
|
||||||
OP_AltCurrency=0x6b6d
|
OP_AltCurrency=0x6b6d
|
||||||
OP_AltCurrencyMerchantRequest=0x5409
|
OP_AltCurrencyMerchantRequest=0x5409
|
||||||
|
|||||||
@ -241,6 +241,7 @@ OP_AutoAttack=0x3d86 # C
|
|||||||
OP_AutoAttack2=0x4ca1 # C
|
OP_AutoAttack2=0x4ca1 # C
|
||||||
OP_Consume=0x7ce4 # C
|
OP_Consume=0x7ce4 # C
|
||||||
OP_MoveItem=0x7f56 # C
|
OP_MoveItem=0x7f56 # C
|
||||||
|
OP_MoveMultipleItems=0x4572
|
||||||
OP_DeleteItem=0x36f8 # C
|
OP_DeleteItem=0x36f8 # C
|
||||||
OP_DeleteCharge=0x1df9 # C
|
OP_DeleteCharge=0x1df9 # C
|
||||||
OP_ItemPacket=0x34f8 # C
|
OP_ItemPacket=0x34f8 # C
|
||||||
@ -345,6 +346,7 @@ OP_AltCurrencySell=0x7a21
|
|||||||
OP_AltCurrencySellSelection=0x26d9
|
OP_AltCurrencySellSelection=0x26d9
|
||||||
OP_AltCurrencyReclaim=0x712c
|
OP_AltCurrencyReclaim=0x712c
|
||||||
OP_ShroudProgress=0x0296
|
OP_ShroudProgress=0x0296
|
||||||
|
OP_AddNimbusEffect=0x6840
|
||||||
OP_RemoveNimbusEffect=0x5272 # C
|
OP_RemoveNimbusEffect=0x5272 # C
|
||||||
OP_Untargetable=0x5ea1 # 0x301d on UF?
|
OP_Untargetable=0x5ea1 # 0x301d on UF?
|
||||||
OP_IncreaseStats=0x71eb
|
OP_IncreaseStats=0x71eb
|
||||||
|
|||||||
@ -237,6 +237,7 @@ OP_AutoAttack=0x3427 #Trevius 01/20/09
|
|||||||
OP_AutoAttack2=0x6017 #Trevius 01/20/09
|
OP_AutoAttack2=0x6017 #Trevius 01/20/09
|
||||||
OP_Consume=0x729a #Trevius 02/08/09
|
OP_Consume=0x729a #Trevius 02/08/09
|
||||||
OP_MoveItem=0x14B3 #Trevius 02/08/09
|
OP_MoveItem=0x14B3 #Trevius 02/08/09
|
||||||
|
OP_MoveMultipleItems=0x2d3e
|
||||||
OP_DeleteItem=0x7DD4 #Xinu 03/08/09 0x41EE 0x018E 0x070C
|
OP_DeleteItem=0x7DD4 #Xinu 03/08/09 0x41EE 0x018E 0x070C
|
||||||
OP_DeleteCharge=0x32e2 #Trevius 03/23/09
|
OP_DeleteCharge=0x32e2 #Trevius 03/23/09
|
||||||
OP_ItemPacket=0x78Cd #Trevius 02/08/09
|
OP_ItemPacket=0x78Cd #Trevius 02/08/09
|
||||||
@ -329,6 +330,7 @@ OP_AltCurrencyPurchase=0x3994
|
|||||||
OP_AltCurrencySell=0x2ac3
|
OP_AltCurrencySell=0x2ac3
|
||||||
OP_AltCurrencySellSelection=0x7d00
|
OP_AltCurrencySellSelection=0x7d00
|
||||||
OP_AltCurrencyReclaim=0x1996
|
OP_AltCurrencyReclaim=0x1996
|
||||||
|
OP_AddNimbusEffect=0x45e2
|
||||||
OP_RemoveNimbusEffect=0x5872 # C
|
OP_RemoveNimbusEffect=0x5872 # C
|
||||||
OP_InspectMessageUpdate=0x67e9 # C
|
OP_InspectMessageUpdate=0x67e9 # C
|
||||||
OP_OpenInventory=0x66c8
|
OP_OpenInventory=0x66c8
|
||||||
|
|||||||
@ -198,6 +198,7 @@ OP_Split=0x4848 # ShowEQ 10/27/05
|
|||||||
OP_Surname=0x4668 # ShowEQ 10/27/05
|
OP_Surname=0x4668 # ShowEQ 10/27/05
|
||||||
OP_ClearSurname=0x6cdb
|
OP_ClearSurname=0x6cdb
|
||||||
OP_MoveItem=0x420f # ShowEQ 10/27/05
|
OP_MoveItem=0x420f # ShowEQ 10/27/05
|
||||||
|
OP_MoveMultipleItems=0x463b
|
||||||
OP_FaceChange=0x0f8e # ShowEQ 10/27/05
|
OP_FaceChange=0x0f8e # ShowEQ 10/27/05
|
||||||
OP_ItemPacket=0x3397 # ShowEQ 10/27/05
|
OP_ItemPacket=0x3397 # ShowEQ 10/27/05
|
||||||
OP_ItemLinkResponse=0x667c # ShowEQ 10/27/05
|
OP_ItemLinkResponse=0x667c # ShowEQ 10/27/05
|
||||||
|
|||||||
@ -251,6 +251,7 @@ OP_AutoAttack=0x1df9 # C
|
|||||||
OP_AutoAttack2=0x517b # C
|
OP_AutoAttack2=0x517b # C
|
||||||
OP_Consume=0x24c5 # V
|
OP_Consume=0x24c5 # V
|
||||||
OP_MoveItem=0x2641 # C
|
OP_MoveItem=0x2641 # C
|
||||||
|
OP_MoveMultipleItems=0x40e8
|
||||||
OP_DeleteItem=0x66e0 # C
|
OP_DeleteItem=0x66e0 # C
|
||||||
OP_DeleteCharge=0x4ca1 # C
|
OP_DeleteCharge=0x4ca1 # C
|
||||||
OP_ItemPacket=0x7b6e # C
|
OP_ItemPacket=0x7b6e # C
|
||||||
@ -346,6 +347,7 @@ OP_MobUpdate=0x4656 # Same as OP_SpawnPositionUpdate
|
|||||||
OP_NPCMoveUpdate=0x0f3e #
|
OP_NPCMoveUpdate=0x0f3e #
|
||||||
OP_CameraEffect=0x6b0e # V
|
OP_CameraEffect=0x6b0e # V
|
||||||
OP_SpellEffect=0x57a3 # V
|
OP_SpellEffect=0x57a3 # V
|
||||||
|
OP_AddNimbusEffect=0x6361
|
||||||
OP_RemoveNimbusEffect=0x2c77 # C
|
OP_RemoveNimbusEffect=0x2c77 # C
|
||||||
OP_AltCurrency=0x659e
|
OP_AltCurrency=0x659e
|
||||||
OP_AltCurrencyMerchantRequest=0x214C
|
OP_AltCurrencyMerchantRequest=0x214C
|
||||||
|
|||||||
@ -357,7 +357,7 @@
|
|||||||
9101|2016_12_01_pcnpc_only.sql|SHOW COLUMNS FROM `spells_new` LIKE 'pcnpc_only_flag'|empty|
|
9101|2016_12_01_pcnpc_only.sql|SHOW COLUMNS FROM `spells_new` LIKE 'pcnpc_only_flag'|empty|
|
||||||
9102|2017_01_10_book_languages.sql|SHOW COLUMNS FROM `books` LIKE 'language'|empty|
|
9102|2017_01_10_book_languages.sql|SHOW COLUMNS FROM `books` LIKE 'language'|empty|
|
||||||
9103|2017_01_30_book_languages_fix.sql|SELECT `language` from `books` WHERE `language` IS NULL|not_empty|
|
9103|2017_01_30_book_languages_fix.sql|SELECT `language` from `books` WHERE `language` IS NULL|not_empty|
|
||||||
9104|2017_02_09_npc_spells_entries_type_update.sql|SHOW COLUMNS IN `npc_spells_entries` LIKE `type`|contains|smallint(5) unsigned
|
9104|2017_02_09_npc_spells_entries_type_update.sql|SHOW COLUMNS IN `npc_spells_entries` LIKE 'type'|contains|smallint(5) unsigned
|
||||||
9105|2017_02_15_bot_spells_entries.sql|SELECT `id` FROM `npc_spells_entries` WHERE `npc_spells_id` >= 701 AND `npc_spells_id` <= 712|not_empty|
|
9105|2017_02_15_bot_spells_entries.sql|SELECT `id` FROM `npc_spells_entries` WHERE `npc_spells_id` >= 701 AND `npc_spells_id` <= 712|not_empty|
|
||||||
9106|2017_02_26_npc_spells_update_for_bots.sql|SELECT * FROM `npc_spells` WHERE `id` = '701' AND `name` = 'Cleric Bot'|not_empty|
|
9106|2017_02_26_npc_spells_update_for_bots.sql|SELECT * FROM `npc_spells` WHERE `id` = '701' AND `name` = 'Cleric Bot'|not_empty|
|
||||||
9107|2017_03_09_inventory_version.sql|SHOW TABLES LIKE 'inventory_version'|empty|
|
9107|2017_03_09_inventory_version.sql|SHOW TABLES LIKE 'inventory_version'|empty|
|
||||||
@ -368,6 +368,8 @@
|
|||||||
9112|2017_06_24_rule_values_expand.sql|SHOW COLUMNS FROM rule_values WHERE Field = 'rule_value' and Type = 'varchar(30)'|empty|
|
9112|2017_06_24_rule_values_expand.sql|SHOW COLUMNS FROM rule_values WHERE Field = 'rule_value' and Type = 'varchar(30)'|empty|
|
||||||
9113|2017_07_19_show_name.sql|SHOW COLUMNS FROM `npc_types` LIKE 'show_name'|empty|
|
9113|2017_07_19_show_name.sql|SHOW COLUMNS FROM `npc_types` LIKE 'show_name'|empty|
|
||||||
9114|2017_07_22_aura.sql|SHOW TABLES LIKE 'auras'|empty|
|
9114|2017_07_22_aura.sql|SHOW TABLES LIKE 'auras'|empty|
|
||||||
|
9115|2017_10_28_traps.sql|SHOW COLUMNS FROM `traps` LIKE 'triggered_number'|empty|
|
||||||
|
9116|2017_12_16_GroundSpawn_Respawn_Timer.sql|SHOW COLUMNS FROM `ground_spawns` WHERE Field = 'respawn_timer' AND Type = 'int(11) unsigned'|empty|
|
||||||
|
|
||||||
# Upgrade conditions:
|
# Upgrade conditions:
|
||||||
# This won't be needed after this system is implemented, but it is used database that are not
|
# This won't be needed after this system is implemented, but it is used database that are not
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
UPDATE `rule_values` SET `rule_value` = '32' WHERE `rule_name` = 'Character:FoodLossPerUpdate';
|
||||||
|
UPDATE `rule_values` SET `rule_value` = '30' WHERE `rule_name` = 'Character:ItemHealthRegenCap';
|
||||||
|
|
||||||
4
utils/sql/git/required/2017_10_28_traps.sql
Normal file
4
utils/sql/git/required/2017_10_28_traps.sql
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
alter table `traps` add column `triggered_number` tinyint(4) not null default 0;
|
||||||
|
alter table `traps` add column `group` tinyint(4) not null default 0;
|
||||||
|
alter table `traps` add column `despawn_when_triggered` tinyint(4) not null default 0;
|
||||||
|
alter table `traps` add column `undetectable` tinyint(4) not null default 0;
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE `ground_spawns` MODIFY `respawn_timer` int(11) unsigned NOT NULL default 300;
|
||||||
|
UPDATE `ground_spawns` SET `respawn_timer` = `respawn_timer` / 1000;
|
||||||
@ -380,7 +380,7 @@ void Adventure::MoveCorpsesToGraveyard()
|
|||||||
std::list<uint32> dbid_list;
|
std::list<uint32> dbid_list;
|
||||||
std::list<uint32> charid_list;
|
std::list<uint32> charid_list;
|
||||||
|
|
||||||
std::string query = StringFormat("SELECT id, charid FROM character_corpses WHERE instanceid=%d", GetInstanceID());
|
std::string query = StringFormat("SELECT id, charid FROM character_corpses WHERE instance_id=%d", GetInstanceID());
|
||||||
auto results = database.QueryDatabase(query);
|
auto results = database.QueryDatabase(query);
|
||||||
if(!results.Success())
|
if(!results.Success())
|
||||||
|
|
||||||
@ -395,8 +395,8 @@ void Adventure::MoveCorpsesToGraveyard()
|
|||||||
float z = GetTemplate()->graveyard_z;
|
float z = GetTemplate()->graveyard_z;
|
||||||
|
|
||||||
query = StringFormat("UPDATE character_corpses "
|
query = StringFormat("UPDATE character_corpses "
|
||||||
"SET zoneid = %d, instanceid = 0, "
|
"SET zone_id = %d, instance_id = 0, "
|
||||||
"x = %f, y = %f, z = %f WHERE instanceid = %d",
|
"x = %f, y = %f, z = %f WHERE instance_id = %d",
|
||||||
GetTemplate()->graveyard_zone_id,
|
GetTemplate()->graveyard_zone_id,
|
||||||
x, y, z, GetInstanceID());
|
x, y, z, GetInstanceID());
|
||||||
database.QueryDatabase(query);
|
database.QueryDatabase(query);
|
||||||
|
|||||||
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "../common/string_util.h"
|
||||||
#include "../common/eqemu_logsys.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
#include "../common/queue.h"
|
#include "../common/queue.h"
|
||||||
#include "../common/timer.h"
|
#include "../common/timer.h"
|
||||||
@ -105,6 +106,12 @@ WebInterfaceList web_interface;
|
|||||||
void CatchSignal(int sig_num);
|
void CatchSignal(int sig_num);
|
||||||
void CheckForServerScript(bool force_download = false);
|
void CheckForServerScript(bool force_download = false);
|
||||||
|
|
||||||
|
inline void UpdateWindowTitle(std::string new_title) {
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
SetConsoleTitle(new_title.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
RegisterExecutablePlatform(ExePlatformWorld);
|
RegisterExecutablePlatform(ExePlatformWorld);
|
||||||
LogSys.LoadLogSettingsDefaults();
|
LogSys.LoadLogSettingsDefaults();
|
||||||
@ -539,8 +546,7 @@ int main(int argc, char** argv) {
|
|||||||
database.PurgeExpiredInstances();
|
database.PurgeExpiredInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EQTimeTimer.Check())
|
if (EQTimeTimer.Check()) {
|
||||||
{
|
|
||||||
TimeOfDay_Struct tod;
|
TimeOfDay_Struct tod;
|
||||||
zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(0), &tod);
|
zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(0), &tod);
|
||||||
if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year))
|
if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year))
|
||||||
@ -557,6 +563,9 @@ int main(int argc, char** argv) {
|
|||||||
if (InterserverTimer.Check()) {
|
if (InterserverTimer.Check()) {
|
||||||
InterserverTimer.Start();
|
InterserverTimer.Start();
|
||||||
database.ping();
|
database.ping();
|
||||||
|
|
||||||
|
std::string window_title = StringFormat("World: %s Clients: %i", Config->LongName.c_str(), client_list.GetClientCount());
|
||||||
|
UpdateWindowTitle(window_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
EQ::EventLoop::Get().Process();
|
EQ::EventLoop::Get().Process();
|
||||||
|
|||||||
@ -31,7 +31,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void CatchSignal(int sig_num);
|
void CatchSignal(int sig_num);
|
||||||
void UpdateWindowTitle(char* iNewTitle);
|
|
||||||
|
|
||||||
#define EQ_WORLD_PORT 9000 //mandated by the client
|
#define EQ_WORLD_PORT 9000 //mandated by the client
|
||||||
#define LOGIN_PORT 5997
|
#define LOGIN_PORT 5997
|
||||||
|
|||||||
@ -1274,6 +1274,11 @@ void Mob::ClearFeignMemory() {
|
|||||||
AI_feign_remember_timer->Disable();
|
AI_feign_remember_timer->Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mob::IsOnFeignMemory(Client *attacker) const
|
||||||
|
{
|
||||||
|
return feign_memory_list.find(attacker->CharacterID()) != feign_memory_list.end();
|
||||||
|
}
|
||||||
|
|
||||||
bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
|
bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
106
zone/attack.cpp
106
zone/attack.cpp
@ -852,16 +852,56 @@ int Mob::ACSum()
|
|||||||
return ac;
|
return ac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Mob::GetBestMeleeSkill()
|
||||||
|
{
|
||||||
|
int bestSkill=0;
|
||||||
|
EQEmu::skills::SkillType meleeSkills[]=
|
||||||
|
{ EQEmu::skills::Skill1HBlunt,
|
||||||
|
EQEmu::skills::Skill1HSlashing,
|
||||||
|
EQEmu::skills::Skill2HBlunt,
|
||||||
|
EQEmu::skills::Skill2HSlashing,
|
||||||
|
EQEmu::skills::SkillHandtoHand,
|
||||||
|
EQEmu::skills::Skill1HPiercing,
|
||||||
|
EQEmu::skills::Skill2HPiercing,
|
||||||
|
EQEmu::skills::SkillCount
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; meleeSkills[i] != EQEmu::skills::SkillCount; ++i) {
|
||||||
|
int value;
|
||||||
|
value = GetSkill(meleeSkills[i]);
|
||||||
|
bestSkill = std::max(value, bestSkill);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestSkill;
|
||||||
|
}
|
||||||
|
|
||||||
int Mob::offense(EQEmu::skills::SkillType skill)
|
int Mob::offense(EQEmu::skills::SkillType skill)
|
||||||
{
|
{
|
||||||
int offense = GetSkill(skill);
|
int offense = GetSkill(skill);
|
||||||
int stat_bonus = 0;
|
int stat_bonus = GetSTR();
|
||||||
if (skill == EQEmu::skills::SkillArchery || skill == EQEmu::skills::SkillThrowing)
|
|
||||||
|
switch (skill) {
|
||||||
|
case EQEmu::skills::SkillArchery:
|
||||||
|
case EQEmu::skills::SkillThrowing:
|
||||||
stat_bonus = GetDEX();
|
stat_bonus = GetDEX();
|
||||||
else
|
break;
|
||||||
stat_bonus = GetSTR();
|
|
||||||
|
// Mobs with no weapons default to H2H.
|
||||||
|
// Since H2H is capped at 100 for many many classes,
|
||||||
|
// lets not handicap mobs based on not spawning with a
|
||||||
|
// weapon.
|
||||||
|
//
|
||||||
|
// Maybe we tweak this if Disarm is actually implemented.
|
||||||
|
|
||||||
|
case EQEmu::skills::SkillHandtoHand:
|
||||||
|
offense = GetBestMeleeSkill();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (stat_bonus >= 75)
|
if (stat_bonus >= 75)
|
||||||
offense += (2 * stat_bonus - 150) / 3;
|
offense += (2 * stat_bonus - 150) / 3;
|
||||||
|
|
||||||
offense += GetATK();
|
offense += GetATK();
|
||||||
return offense;
|
return offense;
|
||||||
}
|
}
|
||||||
@ -1262,6 +1302,7 @@ int Client::DoDamageCaps(int base_damage)
|
|||||||
return std::min(cap, base_damage);
|
return std::min(cap, base_damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// other is the defender, this is the attacker
|
||||||
void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
||||||
{
|
{
|
||||||
if (!other)
|
if (!other)
|
||||||
@ -1288,6 +1329,20 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
|||||||
|
|
||||||
if (hit.damage_done >= 0) {
|
if (hit.damage_done >= 0) {
|
||||||
if (other->CheckHitChance(this, hit)) {
|
if (other->CheckHitChance(this, hit)) {
|
||||||
|
if (IsNPC() && other->IsClient() && other->animation > 0 && GetLevel() >= 5 && BehindMob(other, GetX(), GetY())) {
|
||||||
|
// ~ 12% chance
|
||||||
|
if (zone->random.Roll(12)) {
|
||||||
|
int stun_resist2 = other->spellbonuses.FrontalStunResist + other->itembonuses.FrontalStunResist + other->aabonuses.FrontalStunResist;
|
||||||
|
int stun_resist = other->spellbonuses.StunResist + other->itembonuses.StunResist + other->aabonuses.StunResist;
|
||||||
|
if (zone->random.Roll(stun_resist2)) {
|
||||||
|
other->Message_StringID(MT_Stun, AVOID_STUNNING_BLOW);
|
||||||
|
} else if (zone->random.Roll(stun_resist)) {
|
||||||
|
other->Message_StringID(MT_Stun, SHAKE_OFF_STUN);
|
||||||
|
} else {
|
||||||
|
other->Stun(3000); // yuck -- 3 seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
other->MeleeMitigation(this, hit, opts);
|
other->MeleeMitigation(this, hit, opts);
|
||||||
if (hit.damage_done > 0) {
|
if (hit.damage_done > 0) {
|
||||||
ApplyDamageTable(hit);
|
ApplyDamageTable(hit);
|
||||||
@ -1674,6 +1729,15 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
|
|||||||
exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000);
|
exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RuleB(Zone, LevelBasedEXPMods)) {
|
||||||
|
// Death in levels with xp_mod (such as hell levels) was resulting
|
||||||
|
// in losing more that appropriate since the loss was the same but
|
||||||
|
// getting it back would take way longer. This makes the death the
|
||||||
|
// same amount of time to recover. Will also lose more if level is
|
||||||
|
// granting a bonus.
|
||||||
|
exploss *= zone->level_exp_mod[GetLevel()].ExpMod;
|
||||||
|
}
|
||||||
|
|
||||||
if ((GetLevel() < RuleI(Character, DeathExpLossLevel)) || (GetLevel() > RuleI(Character, DeathExpLossMaxLevel)) || IsBecomeNPC())
|
if ((GetLevel() < RuleI(Character, DeathExpLossLevel)) || (GetLevel() > RuleI(Character, DeathExpLossMaxLevel)) || IsBecomeNPC())
|
||||||
{
|
{
|
||||||
exploss = 0;
|
exploss = 0;
|
||||||
@ -2518,6 +2582,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
|||||||
if (other == this)
|
if (other == this)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (other->IsTrap())
|
||||||
|
return;
|
||||||
|
|
||||||
if (damage < 0) {
|
if (damage < 0) {
|
||||||
hate = 1;
|
hate = 1;
|
||||||
}
|
}
|
||||||
@ -2617,7 +2684,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
|||||||
|
|
||||||
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
|
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
|
||||||
|
|
||||||
if (other->IsClient() && !on_hatelist)
|
if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other->CastToClient()))
|
||||||
other->CastToClient()->AddAutoXTarget(this);
|
other->CastToClient()->AddAutoXTarget(this);
|
||||||
|
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
@ -2658,9 +2725,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
|||||||
// owner must get on list, but he's not actually gained any hate yet
|
// owner must get on list, but he's not actually gained any hate yet
|
||||||
if (!owner->GetSpecialAbility(IMMUNE_AGGRO))
|
if (!owner->GetSpecialAbility(IMMUNE_AGGRO))
|
||||||
{
|
{
|
||||||
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
|
|
||||||
if (owner->IsClient() && !CheckAggro(owner))
|
if (owner->IsClient() && !CheckAggro(owner))
|
||||||
owner->CastToClient()->AddAutoXTarget(this);
|
owner->CastToClient()->AddAutoXTarget(this);
|
||||||
|
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3349,7 +3416,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
|||||||
// pets that have GHold will never automatically add NPCs
|
// pets that have GHold will never automatically add NPCs
|
||||||
// pets that have Hold and no Focus will add NPCs if they're engaged
|
// pets that have Hold and no Focus will add NPCs if they're engaged
|
||||||
// pets that have Hold and Focus will not add NPCs
|
// pets that have Hold and Focus will not add NPCs
|
||||||
if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse() && !pet->IsGHeld())
|
if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse() && !pet->IsGHeld() && !attacker->IsTrap())
|
||||||
{
|
{
|
||||||
if (!pet->IsHeld()) {
|
if (!pet->IsHeld()) {
|
||||||
Log(Logs::Detail, Logs::Aggro, "Sending pet %s into battle due to attack.", pet->GetName());
|
Log(Logs::Detail, Logs::Aggro, "Sending pet %s into battle due to attack.", pet->GetName());
|
||||||
@ -3907,10 +3974,10 @@ void Mob::TryWeaponProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *
|
|||||||
float WPC = ProcChance * (100.0f + // Proc chance for this weapon
|
float WPC = ProcChance * (100.0f + // Proc chance for this weapon
|
||||||
static_cast<float>(weapon->ProcRate)) / 100.0f;
|
static_cast<float>(weapon->ProcRate)) / 100.0f;
|
||||||
if (zone->random.Roll(WPC)) { // 255 dex = 0.084 chance of proc. No idea what this number should be really.
|
if (zone->random.Roll(WPC)) { // 255 dex = 0.084 chance of proc. No idea what this number should be really.
|
||||||
if (weapon->Proc.Level > ourlevel) {
|
if (weapon->Proc.Level2 > ourlevel) {
|
||||||
Log(Logs::Detail, Logs::Combat,
|
Log(Logs::Detail, Logs::Combat,
|
||||||
"Tried to proc (%s), but our level (%d) is lower than required (%d)",
|
"Tried to proc (%s), but our level (%d) is lower than required (%d)",
|
||||||
weapon->Name, ourlevel, weapon->Proc.Level);
|
weapon->Name, ourlevel, weapon->Proc.Level2);
|
||||||
if (IsPet()) {
|
if (IsPet()) {
|
||||||
Mob *own = GetOwner();
|
Mob *own = GetOwner();
|
||||||
if (own)
|
if (own)
|
||||||
@ -3947,7 +4014,7 @@ void Mob::TryWeaponProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *
|
|||||||
float APC = ProcChance * (100.0f + // Proc chance for this aug
|
float APC = ProcChance * (100.0f + // Proc chance for this aug
|
||||||
static_cast<float>(aug->ProcRate)) / 100.0f;
|
static_cast<float>(aug->ProcRate)) / 100.0f;
|
||||||
if (zone->random.Roll(APC)) {
|
if (zone->random.Roll(APC)) {
|
||||||
if (aug->Proc.Level > ourlevel) {
|
if (aug->Proc.Level2 > ourlevel) {
|
||||||
if (IsPet()) {
|
if (IsPet()) {
|
||||||
Mob *own = GetOwner();
|
Mob *own = GetOwner();
|
||||||
if (own)
|
if (own)
|
||||||
@ -5232,12 +5299,23 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
|
|||||||
// extra off hand non-sense, can only double with skill of 150 or above
|
// extra off hand non-sense, can only double with skill of 150 or above
|
||||||
// or you have any amount of GiveDoubleAttack
|
// or you have any amount of GiveDoubleAttack
|
||||||
if (candouble && hand == EQEmu::inventory::slotSecondary)
|
if (candouble && hand == EQEmu::inventory::slotSecondary)
|
||||||
candouble = GetSkill(EQEmu::skills::SkillDoubleAttack) > 149 || (aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack) > 0;
|
candouble =
|
||||||
|
GetSkill(EQEmu::skills::SkillDoubleAttack) > 149 ||
|
||||||
|
(aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack) > 0;
|
||||||
|
|
||||||
if (candouble) {
|
if (candouble) {
|
||||||
CheckIncreaseSkill(EQEmu::skills::SkillDoubleAttack, target, -10);
|
CheckIncreaseSkill(EQEmu::skills::SkillDoubleAttack, target, -10);
|
||||||
if (CheckDoubleAttack()) {
|
if (CheckDoubleAttack()) {
|
||||||
Attack(target, hand, false, false, IsFromSpell);
|
Attack(target, hand, false, false, IsFromSpell);
|
||||||
|
|
||||||
|
// Modern AA description: Increases your chance of ... performing one additional hit with a 2-handed weapon when double attacking by 2%.
|
||||||
|
if (hand == EQEmu::inventory::slotPrimary) {
|
||||||
|
auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance +
|
||||||
|
itembonuses.ExtraAttackChance;
|
||||||
|
if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance))
|
||||||
|
Attack(target, hand, false, false, IsFromSpell);
|
||||||
|
}
|
||||||
|
|
||||||
// you can only triple from the main hand
|
// you can only triple from the main hand
|
||||||
if (hand == EQEmu::inventory::slotPrimary && CanThisClassTripleAttack()) {
|
if (hand == EQEmu::inventory::slotPrimary && CanThisClassTripleAttack()) {
|
||||||
CheckIncreaseSkill(EQEmu::skills::SkillTripleAttack, target, -10);
|
CheckIncreaseSkill(EQEmu::skills::SkillTripleAttack, target, -10);
|
||||||
@ -5255,12 +5333,6 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hand == EQEmu::inventory::slotPrimary) {
|
|
||||||
auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance;
|
|
||||||
if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance))
|
|
||||||
Attack(target, hand, false, false, IsFromSpell);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::CheckDualWield()
|
bool Mob::CheckDualWield()
|
||||||
|
|||||||
@ -120,6 +120,13 @@ void Client::CalcBonuses()
|
|||||||
|
|
||||||
if (GetMaxXTargets() != 5 + aabonuses.extra_xtargets)
|
if (GetMaxXTargets() != 5 + aabonuses.extra_xtargets)
|
||||||
SetMaxXTargets(5 + aabonuses.extra_xtargets);
|
SetMaxXTargets(5 + aabonuses.extra_xtargets);
|
||||||
|
|
||||||
|
// hmm maybe a better way to do this
|
||||||
|
int metabolism = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism;
|
||||||
|
int timer = GetClass() == MONK ? CONSUMPTION_MNK_TIMER : CONSUMPTION_TIMER;
|
||||||
|
timer = timer * (100 + metabolism) / 100;
|
||||||
|
if (timer != consume_food_timer.GetTimerTime())
|
||||||
|
consume_food_timer.SetTimer(timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Client::CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat)
|
int Client::CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat)
|
||||||
@ -908,7 +915,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
newbon->GivePetGroupTarget = true;
|
newbon->GivePetGroupTarget = true;
|
||||||
break;
|
break;
|
||||||
case SE_ItemHPRegenCapIncrease:
|
case SE_ItemHPRegenCapIncrease:
|
||||||
newbon->ItemHPRegenCap = +base1;
|
newbon->ItemHPRegenCap += base1;
|
||||||
break;
|
break;
|
||||||
case SE_Ambidexterity:
|
case SE_Ambidexterity:
|
||||||
newbon->Ambidexterity += base1;
|
newbon->Ambidexterity += base1;
|
||||||
@ -1003,6 +1010,15 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
case SE_RiposteChance:
|
case SE_RiposteChance:
|
||||||
newbon->RiposteChance += base1;
|
newbon->RiposteChance += base1;
|
||||||
break;
|
break;
|
||||||
|
case SE_DodgeChance:
|
||||||
|
newbon->DodgeChance += base1;
|
||||||
|
break;
|
||||||
|
case SE_ParryChance:
|
||||||
|
newbon->ParryChance += base1;
|
||||||
|
break;
|
||||||
|
case SE_IncreaseBlockChance:
|
||||||
|
newbon->IncreaseBlockChance += base1;
|
||||||
|
break;
|
||||||
case SE_Flurry:
|
case SE_Flurry:
|
||||||
newbon->FlurryChance += base1;
|
newbon->FlurryChance += base1;
|
||||||
break;
|
break;
|
||||||
@ -2494,8 +2510,17 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
|||||||
new_bonus->MagicWeapon = true;
|
new_bonus->MagicWeapon = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SE_Hunger:
|
||||||
|
new_bonus->hunger = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case SE_IncreaseBlockChance:
|
case SE_IncreaseBlockChance:
|
||||||
|
if (AdditiveWornBonus)
|
||||||
new_bonus->IncreaseBlockChance += effect_value;
|
new_bonus->IncreaseBlockChance += effect_value;
|
||||||
|
else if (effect_value < 0 && new_bonus->IncreaseBlockChance > effect_value)
|
||||||
|
new_bonus->IncreaseBlockChance = effect_value;
|
||||||
|
else if (new_bonus->IncreaseBlockChance < effect_value)
|
||||||
|
new_bonus->IncreaseBlockChance = effect_value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_PersistantCasting:
|
case SE_PersistantCasting:
|
||||||
|
|||||||
11
zone/bot.cpp
11
zone/bot.cpp
@ -2841,6 +2841,8 @@ void Bot::Spawn(Client* botCharacterOwner) {
|
|||||||
FaceTarget(botCharacterOwner);
|
FaceTarget(botCharacterOwner);
|
||||||
UpdateEquipmentLight();
|
UpdateEquipmentLight();
|
||||||
UpdateActiveLight();
|
UpdateActiveLight();
|
||||||
|
|
||||||
|
this->m_targetable = true;
|
||||||
entity_list.AddBot(this, true, true);
|
entity_list.AddBot(this, true, true);
|
||||||
// Load pet
|
// Load pet
|
||||||
LoadPet();
|
LoadPet();
|
||||||
@ -6725,7 +6727,7 @@ int32 Bot::CalcATK() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Bot::CalcRestState() {
|
void Bot::CalcRestState() {
|
||||||
if(!RuleI(Character, RestRegenPercent))
|
if(!RuleB(Character, RestRegenEnabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RestRegenHP = RestRegenMana = RestRegenEndurance = 0;
|
RestRegenHP = RestRegenMana = RestRegenEndurance = 0;
|
||||||
@ -6741,10 +6743,9 @@ void Bot::CalcRestState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RestRegenHP = (GetMaxHP() * RuleI(Character, RestRegenPercent) / 100);
|
RestRegenHP = 6 * (GetMaxHP() / RuleI(Character, RestRegenHP));
|
||||||
RestRegenMana = (GetMaxMana() * RuleI(Character, RestRegenPercent) / 100);
|
RestRegenMana = 6 * (GetMaxMana() / RuleI(Character, RestRegenMana));
|
||||||
if(RuleB(Character, RestRegenEndurance))
|
RestRegenEndurance = 6 * (GetMaxEndurance() / RuleI(Character, RestRegenEnd));
|
||||||
RestRegenEndurance = (GetMaxEndurance() * RuleI(Character, RestRegenPercent) / 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Bot::LevelRegen() {
|
int32 Bot::LevelRegen() {
|
||||||
|
|||||||
289
zone/client.cpp
289
zone/client.cpp
@ -123,7 +123,7 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
hpupdate_timer(2000),
|
hpupdate_timer(2000),
|
||||||
camp_timer(29000),
|
camp_timer(29000),
|
||||||
process_timer(100),
|
process_timer(100),
|
||||||
stamina_timer(40000),
|
consume_food_timer(CONSUMPTION_TIMER),
|
||||||
zoneinpacket_timer(1000),
|
zoneinpacket_timer(1000),
|
||||||
linkdead_timer(RuleI(Zone,ClientLinkdeadMS)),
|
linkdead_timer(RuleI(Zone,ClientLinkdeadMS)),
|
||||||
dead_timer(2000),
|
dead_timer(2000),
|
||||||
@ -160,7 +160,8 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
npc_close_scan_timer(6000),
|
npc_close_scan_timer(6000),
|
||||||
hp_self_update_throttle_timer(300),
|
hp_self_update_throttle_timer(300),
|
||||||
hp_other_update_throttle_timer(500),
|
hp_other_update_throttle_timer(500),
|
||||||
position_update_timer(10000)
|
position_update_timer(10000),
|
||||||
|
tmSitting(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
for (int client_filter = 0; client_filter < _FilterCount; client_filter++)
|
for (int client_filter = 0; client_filter < _FilterCount; client_filter++)
|
||||||
@ -270,9 +271,10 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
m_ClientVersion = EQEmu::versions::ClientVersion::Unknown;
|
m_ClientVersion = EQEmu::versions::ClientVersion::Unknown;
|
||||||
m_ClientVersionBit = 0;
|
m_ClientVersionBit = 0;
|
||||||
AggroCount = 0;
|
AggroCount = 0;
|
||||||
RestRegenHP = 0;
|
ooc_regen = false;
|
||||||
RestRegenMana = 0;
|
AreaHPRegen = 1.0f;
|
||||||
RestRegenEndurance = 0;
|
AreaManaRegen = 1.0f;
|
||||||
|
AreaEndRegen = 1.0f;
|
||||||
XPRate = 100;
|
XPRate = 100;
|
||||||
current_endurance = 0;
|
current_endurance = 0;
|
||||||
|
|
||||||
@ -329,6 +331,11 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
|
|
||||||
interrogateinv_flag = false;
|
interrogateinv_flag = false;
|
||||||
|
|
||||||
|
trapid = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < InnateSkillMax; ++i)
|
||||||
|
m_pp.InnateSkills[i] = InnateDisabled;
|
||||||
|
|
||||||
AI_Init();
|
AI_Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,13 +665,18 @@ bool Client::Save(uint8 iCommitNow) {
|
|||||||
m_pp.tribute_time_remaining = 0xFFFFFFFF; m_pp.tribute_active = 0;
|
m_pp.tribute_time_remaining = 0xFFFFFFFF; m_pp.tribute_active = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_pp.hunger_level < 0)
|
||||||
|
m_pp.hunger_level = 0;
|
||||||
|
|
||||||
|
if (m_pp.thirst_level < 0)
|
||||||
|
m_pp.thirst_level = 0;
|
||||||
|
|
||||||
p_timers.Store(&database);
|
p_timers.Store(&database);
|
||||||
|
|
||||||
database.SaveCharacterTribute(this->CharacterID(), &m_pp);
|
database.SaveCharacterTribute(this->CharacterID(), &m_pp);
|
||||||
SaveTaskState(); /* Save Character Task */
|
SaveTaskState(); /* Save Character Task */
|
||||||
|
|
||||||
m_pp.hunger_level = EQEmu::Clamp(m_pp.hunger_level, 0, 50000);
|
Log(Logs::General, Logs::Food, "Client::Save - hunger_level: %i thirst_level: %i", m_pp.hunger_level, m_pp.thirst_level);
|
||||||
m_pp.thirst_level = EQEmu::Clamp(m_pp.thirst_level, 0, 50000);
|
|
||||||
|
|
||||||
// perform snapshot before SaveCharacterData() so that m_epp will contain the updated time
|
// perform snapshot before SaveCharacterData() so that m_epp will contain the updated time
|
||||||
if (RuleB(Character, ActiveInvSnapshots) && time(nullptr) >= GetNextInvSnapshotTime()) {
|
if (RuleB(Character, ActiveInvSnapshots) && time(nullptr) >= GetNextInvSnapshotTime()) {
|
||||||
@ -1211,20 +1223,20 @@ void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num
|
|||||||
EffSkill = 100;
|
EffSkill = 100;
|
||||||
cm->skill_in_language = EffSkill;
|
cm->skill_in_language = EffSkill;
|
||||||
|
|
||||||
// Garble the message based on listener skill
|
|
||||||
if (ListenerSkill < 100) {
|
|
||||||
GarbleMessage(buffer, (100 - ListenerSkill));
|
|
||||||
}
|
|
||||||
|
|
||||||
cm->chan_num = chan_num;
|
cm->chan_num = chan_num;
|
||||||
strcpy(&cm->message[0], buffer);
|
strcpy(&cm->message[0], buffer);
|
||||||
QueuePacket(&app);
|
QueuePacket(&app);
|
||||||
|
|
||||||
|
bool senderCanTrainSelf = RuleB(Client, SelfLanguageLearning);
|
||||||
|
bool weAreNotSender = strcmp(this->GetCleanName(), cm->sender);
|
||||||
|
|
||||||
|
if (senderCanTrainSelf || weAreNotSender) {
|
||||||
if ((chan_num == 2) && (ListenerSkill < 100)) { // group message in unmastered language, check for skill up
|
if ((chan_num == 2) && (ListenerSkill < 100)) { // group message in unmastered language, check for skill up
|
||||||
if (m_pp.languages[language] <= lang_skill)
|
if (m_pp.languages[language] <= lang_skill)
|
||||||
CheckLanguageSkillIncrease(language, lang_skill);
|
CheckLanguageSkillIncrease(language, lang_skill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Client::Message(uint32 type, const char* message, ...) {
|
void Client::Message(uint32 type, const char* message, ...) {
|
||||||
if (GetFilter(FilterSpellDamage) == FilterHide && type == MT_NonMelee)
|
if (GetFilter(FilterSpellDamage) == FilterHide && type == MT_NonMelee)
|
||||||
@ -4588,7 +4600,7 @@ void Client::IncrementAggroCount() {
|
|||||||
//
|
//
|
||||||
AggroCount++;
|
AggroCount++;
|
||||||
|
|
||||||
if(!RuleI(Character, RestRegenPercent))
|
if(!RuleB(Character, RestRegenEnabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If we already had aggro before this method was called, the combat indicator should already be up for SoF clients,
|
// If we already had aggro before this method was called, the combat indicator should already be up for SoF clients,
|
||||||
@ -4625,7 +4637,7 @@ void Client::DecrementAggroCount() {
|
|||||||
|
|
||||||
AggroCount--;
|
AggroCount--;
|
||||||
|
|
||||||
if(!RuleI(Character, RestRegenPercent))
|
if(!RuleB(Character, RestRegenEnabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Something else is still aggro on us, can't rest yet.
|
// Something else is still aggro on us, can't rest yet.
|
||||||
@ -6712,7 +6724,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
|||||||
cap_regen_field = itoa(CalcHPRegenCap());
|
cap_regen_field = itoa(CalcHPRegenCap());
|
||||||
spell_regen_field = itoa(spellbonuses.HPRegen);
|
spell_regen_field = itoa(spellbonuses.HPRegen);
|
||||||
aa_regen_field = itoa(aabonuses.HPRegen);
|
aa_regen_field = itoa(aabonuses.HPRegen);
|
||||||
total_regen_field = itoa(CalcHPRegen());
|
total_regen_field = itoa(CalcHPRegen(true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
@ -6725,7 +6737,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
|||||||
cap_regen_field = itoa(CalcManaRegenCap());
|
cap_regen_field = itoa(CalcManaRegenCap());
|
||||||
spell_regen_field = itoa(spellbonuses.ManaRegen);
|
spell_regen_field = itoa(spellbonuses.ManaRegen);
|
||||||
aa_regen_field = itoa(aabonuses.ManaRegen);
|
aa_regen_field = itoa(aabonuses.ManaRegen);
|
||||||
total_regen_field = itoa(CalcManaRegen());
|
total_regen_field = itoa(CalcManaRegen(true));
|
||||||
}
|
}
|
||||||
else { continue; }
|
else { continue; }
|
||||||
break;
|
break;
|
||||||
@ -6739,7 +6751,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
|||||||
cap_regen_field = itoa(CalcEnduranceRegenCap());
|
cap_regen_field = itoa(CalcEnduranceRegenCap());
|
||||||
spell_regen_field = itoa(spellbonuses.EnduranceRegen);
|
spell_regen_field = itoa(spellbonuses.EnduranceRegen);
|
||||||
aa_regen_field = itoa(aabonuses.EnduranceRegen);
|
aa_regen_field = itoa(aabonuses.EnduranceRegen);
|
||||||
total_regen_field = itoa(CalcEnduranceRegen());
|
total_regen_field = itoa(CalcEnduranceRegen(true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: { break; }
|
default: { break; }
|
||||||
@ -8585,50 +8597,51 @@ void Client::SetConsumption(int32 in_hunger, int32 in_thirst)
|
|||||||
|
|
||||||
void Client::Consume(const EQEmu::ItemData *item, uint8 type, int16 slot, bool auto_consume)
|
void Client::Consume(const EQEmu::ItemData *item, uint8 type, int16 slot, bool auto_consume)
|
||||||
{
|
{
|
||||||
if(!item) { return; }
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
uint32 cons_mod = 180;
|
int increase = item->CastTime_ * 100;
|
||||||
|
if (!auto_consume) // force feeding is half as effective
|
||||||
|
increase /= 2;
|
||||||
|
|
||||||
int32 metabolism_bonus = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism;
|
if (increase < 0) // wasn't food? oh well
|
||||||
|
return;
|
||||||
|
|
||||||
if (metabolism_bonus)
|
if (type == EQEmu::item::ItemTypeFood) {
|
||||||
cons_mod = cons_mod * metabolism_bonus * RuleI(Character, ConsumptionMultiplier) / 10000;
|
increase = mod_food_value(item, increase);
|
||||||
else
|
|
||||||
cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100;
|
|
||||||
|
|
||||||
if (type == EQEmu::item::ItemTypeFood)
|
if (increase < 0)
|
||||||
{
|
return;
|
||||||
int hchange = item->CastTime_ * cons_mod;
|
|
||||||
hchange = mod_food_value(item, hchange);
|
|
||||||
|
|
||||||
if(hchange < 0) { return; }
|
m_pp.hunger_level += increase;
|
||||||
|
|
||||||
|
Log(Logs::General, Logs::Food, "Consuming food, points added to hunger_level: %i - current_hunger: %i",
|
||||||
|
increase, m_pp.hunger_level);
|
||||||
|
|
||||||
m_pp.hunger_level += hchange;
|
|
||||||
DeleteItemInInventory(slot, 1, false);
|
DeleteItemInInventory(slot, 1, false);
|
||||||
|
|
||||||
if (!auto_consume) // no message if the client consumed for us
|
if (!auto_consume) // no message if the client consumed for us
|
||||||
entity_list.MessageClose_StringID(this, true, 50, 0, EATING_MESSAGE, GetName(), item->Name);
|
entity_list.MessageClose_StringID(this, true, 50, 0, EATING_MESSAGE, GetName(), item->Name);
|
||||||
|
|
||||||
#if EQDEBUG >= 5
|
Log(Logs::General, Logs::Food, "Eating from slot: %i", (int)slot);
|
||||||
Log(Logs::General, Logs::None, "Eating from slot:%i", (int)slot);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int tchange = item->CastTime_ * cons_mod;
|
|
||||||
tchange = mod_drink_value(item, tchange);
|
|
||||||
|
|
||||||
if(tchange < 0) { return; }
|
} else {
|
||||||
|
increase = mod_drink_value(item, increase);
|
||||||
|
|
||||||
|
if (increase < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_pp.thirst_level += increase;
|
||||||
|
|
||||||
m_pp.thirst_level += tchange;
|
|
||||||
DeleteItemInInventory(slot, 1, false);
|
DeleteItemInInventory(slot, 1, false);
|
||||||
|
|
||||||
|
Log(Logs::General, Logs::Food, "Consuming drink, points added to thirst_level: %i current_thirst: %i",
|
||||||
|
increase, m_pp.thirst_level);
|
||||||
|
|
||||||
if (!auto_consume) // no message if the client consumed for us
|
if (!auto_consume) // no message if the client consumed for us
|
||||||
entity_list.MessageClose_StringID(this, true, 50, 0, DRINKING_MESSAGE, GetName(), item->Name);
|
entity_list.MessageClose_StringID(this, true, 50, 0, DRINKING_MESSAGE, GetName(), item->Name);
|
||||||
|
|
||||||
#if EQDEBUG >= 5
|
Log(Logs::General, Logs::Food, "Drinking from slot: %i", (int)slot);
|
||||||
Log(Logs::General, Logs::None, "Drinking from slot:%i", (int)slot);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9055,3 +9068,193 @@ void Client::SetPetCommandState(int button, int state)
|
|||||||
FastQueuePacket(&app);
|
FastQueuePacket(&app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Client::CanMedOnHorse()
|
||||||
|
{
|
||||||
|
// no horse is false
|
||||||
|
if (GetHorseId() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// can't med while attacking
|
||||||
|
if (auto_attack)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return animation == 0 && m_Delta.x == 0.0f && m_Delta.y == 0.0f; // TODO: animation is SpeedRun
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::EnableAreaHPRegen(int value)
|
||||||
|
{
|
||||||
|
AreaHPRegen = value * 0.001f;
|
||||||
|
SendAppearancePacket(AT_AreaHPRegen, value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::DisableAreaHPRegen()
|
||||||
|
{
|
||||||
|
AreaHPRegen = 1.0f;
|
||||||
|
SendAppearancePacket(AT_AreaHPRegen, 1000, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::EnableAreaManaRegen(int value)
|
||||||
|
{
|
||||||
|
AreaManaRegen = value * 0.001f;
|
||||||
|
SendAppearancePacket(AT_AreaManaRegen, value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::DisableAreaManaRegen()
|
||||||
|
{
|
||||||
|
AreaManaRegen = 1.0f;
|
||||||
|
SendAppearancePacket(AT_AreaManaRegen, 1000, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::EnableAreaEndRegen(int value)
|
||||||
|
{
|
||||||
|
AreaEndRegen = value * 0.001f;
|
||||||
|
SendAppearancePacket(AT_AreaEndRegen, value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::DisableAreaEndRegen()
|
||||||
|
{
|
||||||
|
AreaEndRegen = 1.0f;
|
||||||
|
SendAppearancePacket(AT_AreaEndRegen, 1000, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::EnableAreaRegens(int value)
|
||||||
|
{
|
||||||
|
EnableAreaHPRegen(value);
|
||||||
|
EnableAreaManaRegen(value);
|
||||||
|
EnableAreaEndRegen(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::DisableAreaRegens()
|
||||||
|
{
|
||||||
|
DisableAreaHPRegen();
|
||||||
|
DisableAreaManaRegen();
|
||||||
|
DisableAreaEndRegen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::InitInnates()
|
||||||
|
{
|
||||||
|
// this function on the client also inits the level one innate skills (like swimming, hide, etc)
|
||||||
|
// we won't do that here, lets just do the InnateSkills for now. Basically translation of what the client is doing
|
||||||
|
// A lot of these we could probably have ignored because they have no known use or are 100% client side
|
||||||
|
// but I figured just in case we'll do them all out
|
||||||
|
//
|
||||||
|
// The client calls this in a few places. When you remove a vision buff and in SetHeights, which is called in
|
||||||
|
// illusions, mounts, and a bunch of other cases. All of the calls to InitInnates are wrapped in restoring regen
|
||||||
|
// besides the call initializing the first time
|
||||||
|
auto race = GetRace();
|
||||||
|
auto class_ = GetClass();
|
||||||
|
|
||||||
|
for (int i = 0; i < InnateSkillMax; ++i)
|
||||||
|
m_pp.InnateSkills[i] = InnateDisabled;
|
||||||
|
|
||||||
|
m_pp.InnateSkills[InnateInspect] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateOpen] = InnateEnabled;
|
||||||
|
if (race >= RT_FROGLOK_3) {
|
||||||
|
if (race == RT_SKELETON_2 || race == RT_FROGLOK_3)
|
||||||
|
m_pp.InnateSkills[InnateUltraVision] = InnateEnabled;
|
||||||
|
else
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
}
|
||||||
|
switch (race) {
|
||||||
|
case RT_BARBARIAN:
|
||||||
|
case RT_BARBARIAN_2:
|
||||||
|
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_ERUDITE:
|
||||||
|
case RT_ERUDITE_2:
|
||||||
|
m_pp.InnateSkills[InnateLore] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_WOOD_ELF:
|
||||||
|
case RT_GUARD_3:
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_HIGH_ELF:
|
||||||
|
case RT_GUARD_2:
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateLore] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_DARK_ELF:
|
||||||
|
case RT_DARK_ELF_2:
|
||||||
|
case RT_VAMPIRE_2:
|
||||||
|
m_pp.InnateSkills[InnateUltraVision] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_TROLL:
|
||||||
|
case RT_TROLL_2:
|
||||||
|
m_pp.InnateSkills[InnateRegen] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_DWARF:
|
||||||
|
case RT_DWARF_2:
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_OGRE:
|
||||||
|
case RT_OGRE_2:
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateNoBash] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateBashDoor] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_HALFLING:
|
||||||
|
case RT_HALFLING_2:
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_GNOME:
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateLore] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_IKSAR:
|
||||||
|
m_pp.InnateSkills[InnateRegen] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_VAH_SHIR:
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_FROGLOK_2:
|
||||||
|
case RT_GHOST:
|
||||||
|
case RT_GHOUL:
|
||||||
|
case RT_SKELETON:
|
||||||
|
case RT_VAMPIRE:
|
||||||
|
case RT_WILL_O_WISP:
|
||||||
|
case RT_ZOMBIE:
|
||||||
|
case RT_SPECTRE:
|
||||||
|
case RT_GHOST_2:
|
||||||
|
case RT_GHOST_3:
|
||||||
|
case RT_DRAGON_2:
|
||||||
|
case RT_INNORUUK:
|
||||||
|
m_pp.InnateSkills[InnateUltraVision] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RT_HUMAN:
|
||||||
|
case RT_GUARD:
|
||||||
|
case RT_BEGGAR:
|
||||||
|
case RT_HUMAN_2:
|
||||||
|
case RT_HUMAN_3:
|
||||||
|
case RT_FROGLOK_3: // client does froglok weird, but this should work out fine
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (class_) {
|
||||||
|
case DRUID:
|
||||||
|
m_pp.InnateSkills[InnateHarmony] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case BARD:
|
||||||
|
m_pp.InnateSkills[InnateReveal] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case ROGUE:
|
||||||
|
m_pp.InnateSkills[InnateSurprise] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateReveal] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case RANGER:
|
||||||
|
m_pp.InnateSkills[InnateAwareness] = InnateEnabled;
|
||||||
|
break;
|
||||||
|
case MONK:
|
||||||
|
m_pp.InnateSkills[InnateSurprise] = InnateEnabled;
|
||||||
|
m_pp.InnateSkills[InnateAwareness] = InnateEnabled;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -199,6 +199,27 @@ struct RespawnOption
|
|||||||
float heading;
|
float heading;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// do not ask what all these mean because I have no idea!
|
||||||
|
// named from the client's CEverQuest::GetInnateDesc, they're missing some
|
||||||
|
enum eInnateSkill {
|
||||||
|
InnateEnabled = 0,
|
||||||
|
InnateAwareness = 1,
|
||||||
|
InnateBashDoor = 2,
|
||||||
|
InnateBreathFire = 3,
|
||||||
|
InnateHarmony = 4,
|
||||||
|
InnateInfravision = 6,
|
||||||
|
InnateLore = 8,
|
||||||
|
InnateNoBash = 9,
|
||||||
|
InnateRegen = 10,
|
||||||
|
InnateSlam = 11,
|
||||||
|
InnateSurprise = 12,
|
||||||
|
InnateUltraVision = 13,
|
||||||
|
InnateInspect = 14,
|
||||||
|
InnateOpen = 15,
|
||||||
|
InnateReveal = 16,
|
||||||
|
InnateSkillMax = 25, // size of array in client
|
||||||
|
InnateDisabled = 255
|
||||||
|
};
|
||||||
|
|
||||||
const uint32 POPUPID_UPDATE_SHOWSTATSWINDOW = 1000000;
|
const uint32 POPUPID_UPDATE_SHOWSTATSWINDOW = 1000000;
|
||||||
|
|
||||||
@ -406,6 +427,16 @@ public:
|
|||||||
const int32& SetMana(int32 amount);
|
const int32& SetMana(int32 amount);
|
||||||
int32 CalcManaRegenCap();
|
int32 CalcManaRegenCap();
|
||||||
|
|
||||||
|
// guild pool regen shit. Sends a SpawnAppearance with a value that regens to value * 0.001
|
||||||
|
void EnableAreaHPRegen(int value);
|
||||||
|
void DisableAreaHPRegen();
|
||||||
|
void EnableAreaManaRegen(int value);
|
||||||
|
void DisableAreaManaRegen();
|
||||||
|
void EnableAreaEndRegen(int value);
|
||||||
|
void DisableAreaEndRegen();
|
||||||
|
void EnableAreaRegens(int value);
|
||||||
|
void DisableAreaRegens();
|
||||||
|
|
||||||
void ServerFilter(SetServerFilter_Struct* filter);
|
void ServerFilter(SetServerFilter_Struct* filter);
|
||||||
void BulkSendTraderInventory(uint32 char_id);
|
void BulkSendTraderInventory(uint32 char_id);
|
||||||
void SendSingleTraderItem(uint32 char_id, int uniqueid);
|
void SendSingleTraderItem(uint32 char_id, int uniqueid);
|
||||||
@ -540,7 +571,7 @@ public:
|
|||||||
/*Endurance and such*/
|
/*Endurance and such*/
|
||||||
void CalcMaxEndurance(); //This calculates the maximum endurance we can have
|
void CalcMaxEndurance(); //This calculates the maximum endurance we can have
|
||||||
int32 CalcBaseEndurance(); //Calculates Base End
|
int32 CalcBaseEndurance(); //Calculates Base End
|
||||||
int32 CalcEnduranceRegen(); //Calculates endurance regen used in DoEnduranceRegen()
|
int32 CalcEnduranceRegen(bool bCombat = false); //Calculates endurance regen used in DoEnduranceRegen()
|
||||||
int32 GetEndurance() const {return current_endurance;} //This gets our current endurance
|
int32 GetEndurance() const {return current_endurance;} //This gets our current endurance
|
||||||
int32 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call
|
int32 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call
|
||||||
int32 CalcEnduranceRegenCap();
|
int32 CalcEnduranceRegenCap();
|
||||||
@ -719,6 +750,7 @@ public:
|
|||||||
void SendTradeskillDetails(uint32 recipe_id);
|
void SendTradeskillDetails(uint32 recipe_id);
|
||||||
bool TradeskillExecute(DBTradeskillRecipe_Struct *spec);
|
bool TradeskillExecute(DBTradeskillRecipe_Struct *spec);
|
||||||
void CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, EQEmu::skills::SkillType tradeskill);
|
void CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, EQEmu::skills::SkillType tradeskill);
|
||||||
|
void InitInnates();
|
||||||
|
|
||||||
void GMKill();
|
void GMKill();
|
||||||
inline bool IsMedding() const {return medding;}
|
inline bool IsMedding() const {return medding;}
|
||||||
@ -760,6 +792,9 @@ public:
|
|||||||
void SummonHorse(uint16 spell_id);
|
void SummonHorse(uint16 spell_id);
|
||||||
void SetHorseId(uint16 horseid_in);
|
void SetHorseId(uint16 horseid_in);
|
||||||
uint16 GetHorseId() const { return horseId; }
|
uint16 GetHorseId() const { return horseId; }
|
||||||
|
bool CanMedOnHorse();
|
||||||
|
|
||||||
|
bool CanFastRegen() const { return ooc_regen; }
|
||||||
|
|
||||||
void NPCSpawn(NPC *target_npc, const char *identifier, uint32 extra = 0);
|
void NPCSpawn(NPC *target_npc, const char *identifier, uint32 extra = 0);
|
||||||
|
|
||||||
@ -862,6 +897,7 @@ public:
|
|||||||
void SetHunger(int32 in_hunger);
|
void SetHunger(int32 in_hunger);
|
||||||
void SetThirst(int32 in_thirst);
|
void SetThirst(int32 in_thirst);
|
||||||
void SetConsumption(int32 in_hunger, int32 in_thirst);
|
void SetConsumption(int32 in_hunger, int32 in_thirst);
|
||||||
|
bool IsStarved() const { if (GetGM() || !RuleB(Character, EnableHungerPenalties)) return false; return m_pp.hunger_level == 0 || m_pp.thirst_level == 0; }
|
||||||
|
|
||||||
bool CheckTradeLoreConflict(Client* other);
|
bool CheckTradeLoreConflict(Client* other);
|
||||||
bool CheckTradeNonDroppable();
|
bool CheckTradeNonDroppable();
|
||||||
@ -1266,6 +1302,8 @@ public:
|
|||||||
|
|
||||||
int32 CalcATK();
|
int32 CalcATK();
|
||||||
|
|
||||||
|
uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Mob;
|
friend class Mob;
|
||||||
void CalcItemBonuses(StatBonuses* newbon);
|
void CalcItemBonuses(StatBonuses* newbon);
|
||||||
@ -1345,13 +1383,13 @@ private:
|
|||||||
int32 CalcCorrup();
|
int32 CalcCorrup();
|
||||||
int32 CalcMaxHP();
|
int32 CalcMaxHP();
|
||||||
int32 CalcBaseHP();
|
int32 CalcBaseHP();
|
||||||
int32 CalcHPRegen();
|
int32 CalcHPRegen(bool bCombat = false);
|
||||||
int32 CalcManaRegen();
|
int32 CalcManaRegen(bool bCombat = false);
|
||||||
int32 CalcBaseManaRegen();
|
int32 CalcBaseManaRegen();
|
||||||
uint32 GetClassHPFactor();
|
uint32 GetClassHPFactor();
|
||||||
void DoHPRegen();
|
void DoHPRegen();
|
||||||
void DoManaRegen();
|
void DoManaRegen();
|
||||||
void DoStaminaUpdate();
|
void DoStaminaHungerUpdate();
|
||||||
void CalcRestState();
|
void CalcRestState();
|
||||||
|
|
||||||
uint32 pLastUpdate;
|
uint32 pLastUpdate;
|
||||||
@ -1410,6 +1448,7 @@ private:
|
|||||||
std::string BuyerWelcomeMessage;
|
std::string BuyerWelcomeMessage;
|
||||||
bool AbilityTimer;
|
bool AbilityTimer;
|
||||||
int Haste; //precalced value
|
int Haste; //precalced value
|
||||||
|
uint32 tmSitting; // time stamp started sitting, used for HP regen bonus added on MAY 5, 2004
|
||||||
|
|
||||||
int32 max_end;
|
int32 max_end;
|
||||||
int32 current_endurance;
|
int32 current_endurance;
|
||||||
@ -1458,7 +1497,7 @@ private:
|
|||||||
Timer hpupdate_timer;
|
Timer hpupdate_timer;
|
||||||
Timer camp_timer;
|
Timer camp_timer;
|
||||||
Timer process_timer;
|
Timer process_timer;
|
||||||
Timer stamina_timer;
|
Timer consume_food_timer;
|
||||||
Timer zoneinpacket_timer;
|
Timer zoneinpacket_timer;
|
||||||
Timer linkdead_timer;
|
Timer linkdead_timer;
|
||||||
Timer dead_timer;
|
Timer dead_timer;
|
||||||
@ -1489,7 +1528,9 @@ private:
|
|||||||
Timer hp_self_update_throttle_timer; /* This is to prevent excessive packet sending under trains/fast combat */
|
Timer hp_self_update_throttle_timer; /* This is to prevent excessive packet sending under trains/fast combat */
|
||||||
Timer hp_other_update_throttle_timer; /* This is to keep clients from DOSing the server with macros that change client targets constantly */
|
Timer hp_other_update_throttle_timer; /* This is to keep clients from DOSing the server with macros that change client targets constantly */
|
||||||
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
|
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
|
||||||
|
|
||||||
glm::vec3 m_Proximity;
|
glm::vec3 m_Proximity;
|
||||||
|
glm::vec4 last_major_update_position;
|
||||||
|
|
||||||
void BulkSendInventoryItems();
|
void BulkSendInventoryItems();
|
||||||
|
|
||||||
@ -1511,9 +1552,10 @@ private:
|
|||||||
|
|
||||||
unsigned int AggroCount; // How many mobs are aggro on us.
|
unsigned int AggroCount; // How many mobs are aggro on us.
|
||||||
|
|
||||||
unsigned int RestRegenHP;
|
bool ooc_regen;
|
||||||
unsigned int RestRegenMana;
|
float AreaHPRegen;
|
||||||
unsigned int RestRegenEndurance;
|
float AreaManaRegen;
|
||||||
|
float AreaEndRegen;
|
||||||
|
|
||||||
bool EngagedRaidTarget;
|
bool EngagedRaidTarget;
|
||||||
uint32 SavedRaidRestTimer;
|
uint32 SavedRaidRestTimer;
|
||||||
|
|||||||
@ -22,6 +22,8 @@
|
|||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
#include "../common/spdat.h"
|
#include "../common/spdat.h"
|
||||||
|
|
||||||
|
#include "../common/data_verification.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "mob.h"
|
#include "mob.h"
|
||||||
|
|
||||||
@ -231,16 +233,81 @@ int32 Client::LevelRegen()
|
|||||||
return hp;
|
return hp;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Client::CalcHPRegen()
|
int32 Client::CalcHPRegen(bool bCombat)
|
||||||
{
|
{
|
||||||
int32 regen = LevelRegen() + itembonuses.HPRegen + spellbonuses.HPRegen;
|
int item_regen = itembonuses.HPRegen; // worn spells and +regen, already capped
|
||||||
regen += aabonuses.HPRegen + GroupLeadershipAAHealthRegeneration();
|
item_regen += GetHeroicSTA() / 20;
|
||||||
|
|
||||||
|
item_regen += aabonuses.HPRegen;
|
||||||
|
|
||||||
|
int base = 0;
|
||||||
|
auto base_data = database.GetBaseData(GetLevel(), GetClass());
|
||||||
|
if (base_data)
|
||||||
|
base = static_cast<int>(base_data->hp_regen);
|
||||||
|
|
||||||
|
auto level = GetLevel();
|
||||||
|
bool skip_innate = false;
|
||||||
|
|
||||||
|
if (IsSitting()) {
|
||||||
|
if (level >= 50) {
|
||||||
|
base++;
|
||||||
|
if (level >= 65)
|
||||||
|
base++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Timer::GetCurrentTime() - tmSitting) > 60000) {
|
||||||
|
if (!IsAffectedByBuffByGlobalGroup(GlobalGroup::Lich)) {
|
||||||
|
auto tic_diff = std::min((Timer::GetCurrentTime() - tmSitting) / 60000, static_cast<uint32>(9));
|
||||||
|
if (tic_diff != 1) { // starts at 2 mins
|
||||||
|
int tic_bonus = tic_diff * 1.5 * base;
|
||||||
|
if (m_pp.InnateSkills[InnateRegen] != InnateDisabled)
|
||||||
|
tic_bonus = tic_bonus * 1.2;
|
||||||
|
base = tic_bonus;
|
||||||
|
skip_innate = true;
|
||||||
|
} else if (m_pp.InnateSkills[InnateRegen] == InnateDisabled) { // no innate regen gets first tick
|
||||||
|
int tic_bonus = base * 1.5;
|
||||||
|
base = tic_bonus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skip_innate && m_pp.InnateSkills[InnateRegen] != InnateDisabled) {
|
||||||
|
if (level >= 50) {
|
||||||
|
++base;
|
||||||
|
if (level >= 55)
|
||||||
|
++base;
|
||||||
|
}
|
||||||
|
base *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsStarved())
|
||||||
|
base = 0;
|
||||||
|
|
||||||
|
base += GroupLeadershipAAHealthRegeneration();
|
||||||
|
// some IsKnockedOut that sets to -1
|
||||||
|
base = base * 100.0f * AreaHPRegen * 0.01f + 0.5f;
|
||||||
|
// another check for IsClient && !(base + item_regen) && Cur_HP <= 0 do --base; do later
|
||||||
|
|
||||||
|
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||||
|
auto fast_mod = RuleI(Character, RestRegenHP); // TODO: this is actually zone based
|
||||||
|
auto max_hp = GetMaxHP();
|
||||||
|
int fast_regen = 6 * (max_hp / fast_mod);
|
||||||
|
if (base < fast_regen) // weird, but what the client is doing
|
||||||
|
base = fast_regen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int regen = base + item_regen + spellbonuses.HPRegen; // TODO: client does this in buff tick
|
||||||
return (regen * RuleI(Character, HPRegenMultiplier) / 100);
|
return (regen * RuleI(Character, HPRegenMultiplier) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Client::CalcHPRegenCap()
|
int32 Client::CalcHPRegenCap()
|
||||||
{
|
{
|
||||||
int cap = RuleI(Character, ItemHealthRegenCap) + itembonuses.HeroicSTA / 25;
|
int cap = RuleI(Character, ItemHealthRegenCap);
|
||||||
|
if (GetLevel() > 60)
|
||||||
|
cap = std::max(cap, GetLevel() - 30); // if the rule is set greater than normal I guess
|
||||||
|
if (GetLevel() > 65)
|
||||||
|
cap += GetLevel() - 65;
|
||||||
cap += aabonuses.ItemHPRegenCap + spellbonuses.ItemHPRegenCap + itembonuses.ItemHPRegenCap;
|
cap += aabonuses.ItemHPRegenCap + spellbonuses.ItemHPRegenCap + itembonuses.ItemHPRegenCap;
|
||||||
return (cap * RuleI(Character, HPRegenMultiplier) / 100);
|
return (cap * RuleI(Character, HPRegenMultiplier) / 100);
|
||||||
}
|
}
|
||||||
@ -1169,43 +1236,80 @@ int32 Client::CalcBaseManaRegen()
|
|||||||
return regen;
|
return regen;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Client::CalcManaRegen()
|
int32 Client::CalcManaRegen(bool bCombat)
|
||||||
{
|
{
|
||||||
uint8 clevel = GetLevel();
|
int regen = 0;
|
||||||
int32 regen = 0;
|
auto level = GetLevel();
|
||||||
//this should be changed so we dont med while camping, etc...
|
// so the new formulas break down with older skill caps where you don't have the skill until 4 or 8
|
||||||
if (IsSitting() || (GetHorseId() != 0)) {
|
// so for servers that want to use the old skill progression they can set this rule so they
|
||||||
BuffFadeBySitModifier();
|
// will get at least 1 for standing and 2 for sitting.
|
||||||
if (HasSkill(EQEmu::skills::SkillMeditate)) {
|
bool old = RuleB(Character, OldMinMana);
|
||||||
this->medding = true;
|
if (!IsStarved()) {
|
||||||
regen = (((GetSkill(EQEmu::skills::SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4;
|
// client does some base regen for shrouds here
|
||||||
regen += spellbonuses.ManaRegen + itembonuses.ManaRegen;
|
if (IsSitting() || CanMedOnHorse()) {
|
||||||
CheckIncreaseSkill(EQEmu::skills::SkillMeditate, nullptr, -5);
|
// kind of weird to do it here w/e
|
||||||
}
|
// client does some base medding regen for shrouds here
|
||||||
else {
|
if (GetClass() != BARD) {
|
||||||
regen = 2 + spellbonuses.ManaRegen + itembonuses.ManaRegen;
|
auto skill = GetSkill(EQEmu::skills::SkillMeditate);
|
||||||
|
if (skill > 0) {
|
||||||
|
regen++;
|
||||||
|
if (skill > 1)
|
||||||
|
regen++;
|
||||||
|
if (skill >= 15)
|
||||||
|
regen += skill / 15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
if (old)
|
||||||
this->medding = false;
|
regen = std::max(regen, 2);
|
||||||
regen = 2 + spellbonuses.ManaRegen + itembonuses.ManaRegen;
|
} else if (old) {
|
||||||
|
regen = std::max(regen, 1);
|
||||||
}
|
}
|
||||||
//AAs
|
}
|
||||||
|
|
||||||
|
if (level > 61) {
|
||||||
|
regen++;
|
||||||
|
if (level > 63)
|
||||||
|
regen++;
|
||||||
|
}
|
||||||
|
|
||||||
regen += aabonuses.ManaRegen;
|
regen += aabonuses.ManaRegen;
|
||||||
|
// add in + 1 bonus for SE_CompleteHeal, but we don't do anything for it yet?
|
||||||
|
|
||||||
|
int item_bonus = itembonuses.ManaRegen; // this is capped already
|
||||||
|
int heroic_bonus = 0;
|
||||||
|
|
||||||
|
switch (GetCasterClass()) {
|
||||||
|
case 'W':
|
||||||
|
heroic_bonus = GetHeroicWIS();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
heroic_bonus = GetHeroicINT();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
item_bonus += heroic_bonus / 25;
|
||||||
|
regen += item_bonus;
|
||||||
|
|
||||||
|
if (level <= 70 && regen > 65)
|
||||||
|
regen = 65;
|
||||||
|
|
||||||
|
regen = regen * 100.0f * AreaManaRegen * 0.01f + 0.5f;
|
||||||
|
|
||||||
|
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||||
|
auto fast_mod = RuleI(Character, RestRegenMana); // TODO: this is actually zone based
|
||||||
|
auto max_mana = GetMaxMana();
|
||||||
|
int fast_regen = 6 * (max_mana / fast_mod);
|
||||||
|
if (regen < fast_regen) // weird, but what the client is doing
|
||||||
|
regen = fast_regen;
|
||||||
|
}
|
||||||
|
|
||||||
|
regen += spellbonuses.ManaRegen; // TODO: live does this in buff tick
|
||||||
return (regen * RuleI(Character, ManaRegenMultiplier) / 100);
|
return (regen * RuleI(Character, ManaRegenMultiplier) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Client::CalcManaRegenCap()
|
int32 Client::CalcManaRegenCap()
|
||||||
{
|
{
|
||||||
int32 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap;
|
int32 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap;
|
||||||
switch (GetCasterClass()) {
|
|
||||||
case 'I':
|
|
||||||
cap += (itembonuses.HeroicINT / 25);
|
|
||||||
break;
|
|
||||||
case 'W':
|
|
||||||
cap += (itembonuses.HeroicWIS / 25);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (cap * RuleI(Character, ManaRegenMultiplier) / 100);
|
return (cap * RuleI(Character, ManaRegenMultiplier) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2091,16 +2195,91 @@ int32 Client::CalcBaseEndurance()
|
|||||||
return base_end;
|
return base_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Client::CalcEnduranceRegen()
|
int32 Client::CalcEnduranceRegen(bool bCombat)
|
||||||
{
|
{
|
||||||
int32 regen = int32(GetLevel() * 4 / 10) + 2;
|
int base = 0;
|
||||||
regen += aabonuses.EnduranceRegen + spellbonuses.EnduranceRegen + itembonuses.EnduranceRegen;
|
if (!IsStarved()) {
|
||||||
|
auto base_data = database.GetBaseData(GetLevel(), GetClass());
|
||||||
|
if (base_data) {
|
||||||
|
base = static_cast<int>(base_data->end_regen);
|
||||||
|
if (!auto_attack && base > 0)
|
||||||
|
base += base / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// so when we are mounted, our local client SpeedRun is always 0, so this is always false, but the packets we process it to our own shit :P
|
||||||
|
bool is_running = runmode && animation != 0 && GetHorseId() == 0; // TODO: animation is really what MQ2 calls SpeedRun
|
||||||
|
|
||||||
|
int weight_limit = GetSTR();
|
||||||
|
auto level = GetLevel();
|
||||||
|
if (GetClass() == MONK) {
|
||||||
|
if (level > 99)
|
||||||
|
weight_limit = 58;
|
||||||
|
else if (level > 94)
|
||||||
|
weight_limit = 57;
|
||||||
|
else if (level > 89)
|
||||||
|
weight_limit = 56;
|
||||||
|
else if (level > 84)
|
||||||
|
weight_limit = 55;
|
||||||
|
else if (level > 79)
|
||||||
|
weight_limit = 54;
|
||||||
|
else if (level > 64)
|
||||||
|
weight_limit = 53;
|
||||||
|
else if (level > 63)
|
||||||
|
weight_limit = 50;
|
||||||
|
else if (level > 61)
|
||||||
|
weight_limit = 47;
|
||||||
|
else if (level > 59)
|
||||||
|
weight_limit = 45;
|
||||||
|
else if (level > 54)
|
||||||
|
weight_limit = 40;
|
||||||
|
else if (level > 50)
|
||||||
|
weight_limit = 38;
|
||||||
|
else if (level > 44)
|
||||||
|
weight_limit = 36;
|
||||||
|
else if (level > 29)
|
||||||
|
weight_limit = 34;
|
||||||
|
else if (level > 14)
|
||||||
|
weight_limit = 32;
|
||||||
|
else
|
||||||
|
weight_limit = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool encumbered = (CalcCurrentWeight() / 10) >= weight_limit;
|
||||||
|
|
||||||
|
if (is_running)
|
||||||
|
base += level / -15;
|
||||||
|
|
||||||
|
if (encumbered)
|
||||||
|
base += level / -15;
|
||||||
|
|
||||||
|
auto item_bonus = GetHeroicAGI() + GetHeroicDEX() + GetHeroicSTA() + GetHeroicSTR();
|
||||||
|
item_bonus = item_bonus / 4 / 50;
|
||||||
|
item_bonus += itembonuses.EnduranceRegen; // this is capped already
|
||||||
|
base += item_bonus;
|
||||||
|
|
||||||
|
base = base * AreaEndRegen + 0.5f;
|
||||||
|
|
||||||
|
auto aa_regen = aabonuses.EnduranceRegen;
|
||||||
|
|
||||||
|
int regen = base;
|
||||||
|
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||||
|
auto fast_mod = RuleI(Character, RestRegenEnd); // TODO: this is actually zone based
|
||||||
|
auto max_end = GetMaxEndurance();
|
||||||
|
int fast_regen = 6 * (max_end / fast_mod);
|
||||||
|
if (aa_regen < fast_regen) // weird, but what the client is doing
|
||||||
|
aa_regen = fast_regen;
|
||||||
|
}
|
||||||
|
|
||||||
|
regen += aa_regen;
|
||||||
|
regen += spellbonuses.EnduranceRegen; // TODO: client does this in buff tick
|
||||||
|
|
||||||
return (regen * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
return (regen * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Client::CalcEnduranceRegenCap()
|
int32 Client::CalcEnduranceRegenCap()
|
||||||
{
|
{
|
||||||
int cap = (RuleI(Character, ItemEnduranceRegenCap) + itembonuses.HeroicSTR / 25 + itembonuses.HeroicDEX / 25 + itembonuses.HeroicAGI / 25 + itembonuses.HeroicSTA / 25);
|
int cap = RuleI(Character, ItemEnduranceRegenCap);
|
||||||
return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -204,6 +204,7 @@
|
|||||||
void Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app);
|
void Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app);
|
||||||
void Handle_OP_MoveCoin(const EQApplicationPacket *app);
|
void Handle_OP_MoveCoin(const EQApplicationPacket *app);
|
||||||
void Handle_OP_MoveItem(const EQApplicationPacket *app);
|
void Handle_OP_MoveItem(const EQApplicationPacket *app);
|
||||||
|
void Handle_OP_MoveMultipleItems(const EQApplicationPacket *app);
|
||||||
void Handle_OP_OpenContainer(const EQApplicationPacket *app);
|
void Handle_OP_OpenContainer(const EQApplicationPacket *app);
|
||||||
void Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app);
|
void Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app);
|
||||||
void Handle_OP_OpenInventory(const EQApplicationPacket *app);
|
void Handle_OP_OpenInventory(const EQApplicationPacket *app);
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "../common/data_verification.h"
|
||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
#include "../common/skills.h"
|
#include "../common/skills.h"
|
||||||
#include "../common/spdat.h"
|
#include "../common/spdat.h"
|
||||||
@ -243,24 +244,42 @@ bool Client::Process() {
|
|||||||
|
|
||||||
/* Build a close range list of NPC's */
|
/* Build a close range list of NPC's */
|
||||||
if (npc_close_scan_timer.Check()) {
|
if (npc_close_scan_timer.Check()) {
|
||||||
|
|
||||||
close_mobs.clear();
|
close_mobs.clear();
|
||||||
|
|
||||||
auto &mob_list = entity_list.GetMobList();
|
/* Force spawn updates when traveled far */
|
||||||
float scan_range = (RuleI(Range, ClientNPCScan) * RuleI(Range, ClientNPCScan));
|
bool force_spawn_updates = false;
|
||||||
float client_update_range = (RuleI(Range, MobPositionUpdates) * RuleI(Range, MobPositionUpdates));
|
float client_update_range = (RuleI(Range, ClientForceSpawnUpdateRange) * RuleI(Range, ClientForceSpawnUpdateRange));
|
||||||
|
if (DistanceSquared(last_major_update_position, m_Position) >= client_update_range) {
|
||||||
|
last_major_update_position = m_Position;
|
||||||
|
force_spawn_updates = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scan_range = (RuleI(Range, ClientNPCScan) * RuleI(Range, ClientNPCScan));
|
||||||
|
auto &mob_list = entity_list.GetMobList();
|
||||||
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
|
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
|
||||||
Mob* mob = itr->second;
|
Mob* mob = itr->second;
|
||||||
|
|
||||||
float distance = DistanceSquared(m_Position, mob->GetPosition());
|
float distance = DistanceSquared(m_Position, mob->GetPosition());
|
||||||
if (mob->IsNPC()) {
|
if (mob->IsNPC()) {
|
||||||
if (distance <= scan_range) {
|
if (distance <= scan_range) {
|
||||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||||
}
|
}
|
||||||
else if (mob->GetAggroRange() > scan_range) {
|
else if ((mob->GetAggroRange() * mob->GetAggroRange()) > scan_range) {
|
||||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (force_spawn_updates && mob != this) {
|
||||||
|
|
||||||
|
if (mob->is_distance_roamer) {
|
||||||
|
mob->SendPositionUpdateToClient(this);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distance <= client_update_range)
|
||||||
|
mob->SendPositionUpdateToClient(this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,6 +532,10 @@ bool Client::Process() {
|
|||||||
DoEnduranceUpkeep();
|
DoEnduranceUpkeep();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is independent of the tick timer
|
||||||
|
if (consume_food_timer.Check())
|
||||||
|
DoStaminaHungerUpdate();
|
||||||
|
|
||||||
if (tic_timer.Check() && !dead) {
|
if (tic_timer.Check() && !dead) {
|
||||||
CalcMaxHP();
|
CalcMaxHP();
|
||||||
CalcMaxMana();
|
CalcMaxMana();
|
||||||
@ -523,7 +546,6 @@ bool Client::Process() {
|
|||||||
DoManaRegen();
|
DoManaRegen();
|
||||||
DoEnduranceRegen();
|
DoEnduranceRegen();
|
||||||
BuffProcess();
|
BuffProcess();
|
||||||
DoStaminaUpdate();
|
|
||||||
|
|
||||||
if (tribute_timer.Check()) {
|
if (tribute_timer.Check()) {
|
||||||
ToggleTribute(true); //re-activate the tribute.
|
ToggleTribute(true); //re-activate the tribute.
|
||||||
@ -1041,7 +1063,8 @@ void Client::OPRezzAnswer(uint32 Action, uint32 SpellID, uint16 ZoneID, uint16 I
|
|||||||
SetMana(0);
|
SetMana(0);
|
||||||
SetHP(GetMaxHP()/5);
|
SetHP(GetMaxHP()/5);
|
||||||
int rez_eff = 756;
|
int rez_eff = 756;
|
||||||
if (GetRace() == BARBARIAN || GetRace() == DWARF || GetRace() == TROLL || GetRace() == OGRE)
|
if (RuleB(Character, UseOldRaceRezEffects) &&
|
||||||
|
(GetRace() == BARBARIAN || GetRace() == DWARF || GetRace() == TROLL || GetRace() == OGRE))
|
||||||
rez_eff = 757;
|
rez_eff = 757;
|
||||||
SpellOnTarget(rez_eff, this); // Rezz effects
|
SpellOnTarget(rez_eff, this); // Rezz effects
|
||||||
}
|
}
|
||||||
@ -1806,7 +1829,7 @@ void Client::OPGMSummon(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::DoHPRegen() {
|
void Client::DoHPRegen() {
|
||||||
SetHP(GetHP() + CalcHPRegen() + RestRegenHP);
|
SetHP(GetHP() + CalcHPRegen());
|
||||||
SendHPUpdate();
|
SendHPUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1814,41 +1837,55 @@ void Client::DoManaRegen() {
|
|||||||
if (GetMana() >= max_mana && spellbonuses.ManaRegen >= 0)
|
if (GetMana() >= max_mana && spellbonuses.ManaRegen >= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SetMana(GetMana() + CalcManaRegen() + RestRegenMana);
|
if (GetMana() < max_mana && (IsSitting() || CanMedOnHorse()) && HasSkill(EQEmu::skills::SkillMeditate))
|
||||||
|
CheckIncreaseSkill(EQEmu::skills::SkillMeditate, nullptr, -5);
|
||||||
|
|
||||||
|
SetMana(GetMana() + CalcManaRegen());
|
||||||
CheckManaEndUpdate();
|
CheckManaEndUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::DoStaminaHungerUpdate()
|
||||||
void Client::DoStaminaUpdate() {
|
{
|
||||||
if(!stamina_timer.Check())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto outapp = new EQApplicationPacket(OP_Stamina, sizeof(Stamina_Struct));
|
auto outapp = new EQApplicationPacket(OP_Stamina, sizeof(Stamina_Struct));
|
||||||
Stamina_Struct *sta = (Stamina_Struct *)outapp->pBuffer;
|
Stamina_Struct *sta = (Stamina_Struct *)outapp->pBuffer;
|
||||||
|
|
||||||
if(zone->GetZoneID() != 151) {
|
Log(Logs::General, Logs::Food, "Client::DoStaminaHungerUpdate() hunger_level: %i thirst_level: %i before loss",
|
||||||
|
m_pp.hunger_level, m_pp.thirst_level);
|
||||||
|
|
||||||
|
if (zone->GetZoneID() != 151 && !GetGM()) {
|
||||||
int loss = RuleI(Character, FoodLossPerUpdate);
|
int loss = RuleI(Character, FoodLossPerUpdate);
|
||||||
if (m_pp.hunger_level > 0)
|
if (GetHorseId() != 0)
|
||||||
m_pp.hunger_level-=loss;
|
loss *= 3;
|
||||||
if (m_pp.thirst_level > 0)
|
|
||||||
m_pp.thirst_level-=loss;
|
m_pp.hunger_level = EQEmu::Clamp(m_pp.hunger_level - loss, 0, 6000);
|
||||||
sta->food = m_pp.hunger_level > 6000 ? 6000 : m_pp.hunger_level;
|
m_pp.thirst_level = EQEmu::Clamp(m_pp.thirst_level - loss, 0, 6000);
|
||||||
sta->water = m_pp.thirst_level> 6000 ? 6000 : m_pp.thirst_level;
|
if (spellbonuses.hunger) {
|
||||||
|
m_pp.hunger_level = EQEmu::ClampLower(m_pp.hunger_level, 3500);
|
||||||
|
m_pp.thirst_level = EQEmu::ClampLower(m_pp.thirst_level, 3500);
|
||||||
}
|
}
|
||||||
else {
|
sta->food = m_pp.hunger_level;
|
||||||
|
sta->water = m_pp.thirst_level;
|
||||||
|
} else {
|
||||||
// No auto food/drink consumption in the Bazaar
|
// No auto food/drink consumption in the Bazaar
|
||||||
sta->food = 6000;
|
sta->food = 6000;
|
||||||
sta->water = 6000;
|
sta->water = 6000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log(Logs::General, Logs::Food,
|
||||||
|
"Client::DoStaminaHungerUpdate() Current hunger_level: %i = (%i minutes left) thirst_level: %i = (%i "
|
||||||
|
"minutes left) - after loss",
|
||||||
|
m_pp.hunger_level, m_pp.hunger_level, m_pp.thirst_level, m_pp.thirst_level);
|
||||||
|
|
||||||
FastQueuePacket(&outapp);
|
FastQueuePacket(&outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::DoEnduranceRegen()
|
void Client::DoEnduranceRegen()
|
||||||
{
|
{
|
||||||
if(GetEndurance() >= GetMaxEndurance())
|
// endurance has some negative mods that could result in a negative regen when starved
|
||||||
return;
|
int regen = CalcEnduranceRegen();
|
||||||
|
|
||||||
SetEndurance(GetEndurance() + CalcEnduranceRegen() + RestRegenEndurance);
|
if (regen < 0 || (regen > 0 && GetEndurance() < GetMaxEndurance()))
|
||||||
|
SetEndurance(GetEndurance() + regen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::DoEnduranceUpkeep() {
|
void Client::DoEnduranceUpkeep() {
|
||||||
@ -1897,12 +1934,12 @@ void Client::CalcRestState() {
|
|||||||
// The client must have been out of combat for RuleI(Character, RestRegenTimeToActivate) seconds,
|
// The client must have been out of combat for RuleI(Character, RestRegenTimeToActivate) seconds,
|
||||||
// must be sitting down, and must not have any detrimental spells affecting them.
|
// must be sitting down, and must not have any detrimental spells affecting them.
|
||||||
//
|
//
|
||||||
if(!RuleI(Character, RestRegenPercent))
|
if(!RuleB(Character, RestRegenEnabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RestRegenHP = RestRegenMana = RestRegenEndurance = 0;
|
ooc_regen = false;
|
||||||
|
|
||||||
if(AggroCount || !IsSitting())
|
if(AggroCount || !(IsSitting() || CanMedOnHorse()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(!rest_timer.Check(false))
|
if(!rest_timer.Check(false))
|
||||||
@ -1917,12 +1954,8 @@ void Client::CalcRestState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RestRegenHP = (GetMaxHP() * RuleI(Character, RestRegenPercent) / 100);
|
ooc_regen = true;
|
||||||
|
|
||||||
RestRegenMana = (GetMaxMana() * RuleI(Character, RestRegenPercent) / 100);
|
|
||||||
|
|
||||||
if(RuleB(Character, RestRegenEndurance))
|
|
||||||
RestRegenEndurance = (GetMaxEndurance() * RuleI(Character, RestRegenPercent) / 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::DoTracking()
|
void Client::DoTracking()
|
||||||
|
|||||||
@ -321,6 +321,7 @@ int command_init(void)
|
|||||||
command_add("reloadqst", " - Clear quest cache (any argument causes it to also stop all timers)", 150, command_reloadqst) ||
|
command_add("reloadqst", " - Clear quest cache (any argument causes it to also stop all timers)", 150, command_reloadqst) ||
|
||||||
command_add("reloadrulesworld", "Executes a reload of all rules in world specifically.", 80, command_reloadworldrules) ||
|
command_add("reloadrulesworld", "Executes a reload of all rules in world specifically.", 80, command_reloadworldrules) ||
|
||||||
command_add("reloadstatic", "- Reload Static Zone Data", 150, command_reloadstatic) ||
|
command_add("reloadstatic", "- Reload Static Zone Data", 150, command_reloadstatic) ||
|
||||||
|
command_add("reloadtraps", "- Repops all traps in the current zone.", 80, command_reloadtraps) ||
|
||||||
command_add("reloadtitles", "- Reload player titles from the database", 150, command_reloadtitles) ||
|
command_add("reloadtitles", "- Reload player titles from the database", 150, command_reloadtitles) ||
|
||||||
command_add("reloadworld", "[0|1] - Clear quest cache (0 - no repop, 1 - repop)", 255, command_reloadworld) ||
|
command_add("reloadworld", "[0|1] - Clear quest cache (0 - no repop, 1 - repop)", 255, command_reloadworld) ||
|
||||||
command_add("reloadzps", "- Reload zone points from database", 150, command_reloadzps) ||
|
command_add("reloadzps", "- Reload zone points from database", 150, command_reloadzps) ||
|
||||||
@ -375,6 +376,7 @@ int command_init(void)
|
|||||||
command_add("task", "(subcommand) - Task system commands", 150, command_task) ||
|
command_add("task", "(subcommand) - Task system commands", 150, command_task) ||
|
||||||
command_add("tattoo", "- Change the tattoo of your target (Drakkin Only)", 80, command_tattoo) ||
|
command_add("tattoo", "- Change the tattoo of your target (Drakkin Only)", 80, command_tattoo) ||
|
||||||
command_add("tempname", "[newname] - Temporarily renames your target. Leave name blank to restore the original name.", 100, command_tempname) ||
|
command_add("tempname", "[newname] - Temporarily renames your target. Leave name blank to restore the original name.", 100, command_tempname) ||
|
||||||
|
command_add("petname", "[newname] - Temporarily renames your pet. Leave name blank to restore the original name.", 100, command_petname) ||
|
||||||
command_add("texture", "[texture] [helmtexture] - Change your or your target's appearance, use 255 to show equipment", 10, command_texture) ||
|
command_add("texture", "[texture] [helmtexture] - Change your or your target's appearance, use 255 to show equipment", 10, command_texture) ||
|
||||||
command_add("time", "[HH] [MM] - Set EQ time", 90, command_time) ||
|
command_add("time", "[HH] [MM] - Set EQ time", 90, command_time) ||
|
||||||
command_add("timers", "- Display persistent timers for target", 200, command_timers) ||
|
command_add("timers", "- Display persistent timers for target", 200, command_timers) ||
|
||||||
@ -382,6 +384,7 @@ int command_init(void)
|
|||||||
command_add("title", "[text] [1 = create title table row] - Set your or your player target's title", 50, command_title) ||
|
command_add("title", "[text] [1 = create title table row] - Set your or your player target's title", 50, command_title) ||
|
||||||
command_add("titlesuffix", "[text] [1 = create title table row] - Set your or your player target's title suffix", 50, command_titlesuffix) ||
|
command_add("titlesuffix", "[text] [1 = create title table row] - Set your or your player target's title suffix", 50, command_titlesuffix) ||
|
||||||
command_add("traindisc", "[level] - Trains all the disciplines usable by the target, up to level specified. (may freeze client for a few seconds)", 150, command_traindisc) ||
|
command_add("traindisc", "[level] - Trains all the disciplines usable by the target, up to level specified. (may freeze client for a few seconds)", 150, command_traindisc) ||
|
||||||
|
command_add("trapinfo", "- Gets infomation about the traps currently spawned in the zone.", 81, command_trapinfo) ||
|
||||||
command_add("tune", "Calculate ideal statical values related to combat.", 100, command_tune) ||
|
command_add("tune", "Calculate ideal statical values related to combat.", 100, command_tune) ||
|
||||||
command_add("undyeme", "- Remove dye from all of your armor slots", 0, command_undyeme) ||
|
command_add("undyeme", "- Remove dye from all of your armor slots", 0, command_undyeme) ||
|
||||||
command_add("unfreeze", "- Unfreeze your target", 80, command_unfreeze) ||
|
command_add("unfreeze", "- Unfreeze your target", 80, command_unfreeze) ||
|
||||||
@ -4157,6 +4160,26 @@ void command_tempname(Client *c, const Seperator *sep)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void command_petname(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
Mob *target;
|
||||||
|
target = c->GetTarget();
|
||||||
|
|
||||||
|
if(!target)
|
||||||
|
c->Message(0, "Usage: #petname newname (requires a target)");
|
||||||
|
else if(target->IsPet() && (target->GetOwnerID() == c->GetID()) && strlen(sep->arg[1]) > 0)
|
||||||
|
{
|
||||||
|
char *oldname = strdup(target->GetName());
|
||||||
|
target->TempName(sep->arg[1]);
|
||||||
|
c->Message(0, "Renamed %s to %s", oldname, sep->arg[1]);
|
||||||
|
free(oldname);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
target->TempName();
|
||||||
|
c->Message(0, "Restored the original name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void command_npcspecialattk(Client *c, const Seperator *sep)
|
void command_npcspecialattk(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
if (c->GetTarget()==0 || c->GetTarget()->IsClient() || strlen(sep->arg[1]) <= 0 || strlen(sep->arg[2]) <= 0)
|
if (c->GetTarget()==0 || c->GetTarget()->IsClient() || strlen(sep->arg[1]) <= 0 || strlen(sep->arg[2]) <= 0)
|
||||||
@ -7257,7 +7280,7 @@ void command_bestz(Client *c, const Seperator *sep) {
|
|||||||
|
|
||||||
float best_z = zone->zonemap->FindBestZ(me, &hit);
|
float best_z = zone->zonemap->FindBestZ(me, &hit);
|
||||||
|
|
||||||
if (best_z != -999999)
|
if (best_z != BEST_Z_INVALID)
|
||||||
{
|
{
|
||||||
c->Message(0, "Z is %.3f at (%.3f, %.3f).", best_z, me.x, me.y);
|
c->Message(0, "Z is %.3f at (%.3f, %.3f).", best_z, me.x, me.y);
|
||||||
}
|
}
|
||||||
@ -10851,6 +10874,16 @@ void command_reloadperlexportsettings(Client *c, const Seperator *sep)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void command_trapinfo(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
entity_list.GetTrapInfo(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_reloadtraps(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
entity_list.UpdateAllTraps(true, true);
|
||||||
|
c->Message(CC_Default, "Traps reloaded for %s.", zone->GetShortName());
|
||||||
|
}
|
||||||
|
|
||||||
// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block.
|
// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block.
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
|
|||||||
@ -228,6 +228,7 @@ void command_reloadperlexportsettings(Client *c, const Seperator *sep);
|
|||||||
void command_reloadqst(Client *c, const Seperator *sep);
|
void command_reloadqst(Client *c, const Seperator *sep);
|
||||||
void command_reloadstatic(Client *c, const Seperator *sep);
|
void command_reloadstatic(Client *c, const Seperator *sep);
|
||||||
void command_reloadtitles(Client *c, const Seperator *sep);
|
void command_reloadtitles(Client *c, const Seperator *sep);
|
||||||
|
void command_reloadtraps(Client* c, const Seperator *sep);
|
||||||
void command_reloadworld(Client *c, const Seperator *sep);
|
void command_reloadworld(Client *c, const Seperator *sep);
|
||||||
void command_reloadworldrules(Client *c, const Seperator *sep);
|
void command_reloadworldrules(Client *c, const Seperator *sep);
|
||||||
void command_reloadzps(Client *c, const Seperator *sep);
|
void command_reloadzps(Client *c, const Seperator *sep);
|
||||||
@ -286,6 +287,7 @@ void command_synctod(Client *c, const Seperator *sep);
|
|||||||
void command_task(Client *c, const Seperator *sep);
|
void command_task(Client *c, const Seperator *sep);
|
||||||
void command_tattoo(Client *c, const Seperator *sep);
|
void command_tattoo(Client *c, const Seperator *sep);
|
||||||
void command_tempname(Client *c, const Seperator *sep);
|
void command_tempname(Client *c, const Seperator *sep);
|
||||||
|
void command_petname(Client *c, const Seperator *sep);
|
||||||
void command_testspawn(Client *c, const Seperator *sep);
|
void command_testspawn(Client *c, const Seperator *sep);
|
||||||
void command_testspawnkill(Client *c, const Seperator *sep);
|
void command_testspawnkill(Client *c, const Seperator *sep);
|
||||||
void command_texture(Client *c, const Seperator *sep);
|
void command_texture(Client *c, const Seperator *sep);
|
||||||
@ -295,6 +297,7 @@ void command_timezone(Client *c, const Seperator *sep);
|
|||||||
void command_title(Client *c, const Seperator *sep);
|
void command_title(Client *c, const Seperator *sep);
|
||||||
void command_titlesuffix(Client *c, const Seperator *sep);
|
void command_titlesuffix(Client *c, const Seperator *sep);
|
||||||
void command_traindisc(Client *c, const Seperator *sep);
|
void command_traindisc(Client *c, const Seperator *sep);
|
||||||
|
void command_trapinfo(Client* c, const Seperator *sep);
|
||||||
void command_tune(Client *c, const Seperator *sep);
|
void command_tune(Client *c, const Seperator *sep);
|
||||||
void command_undye(Client *c, const Seperator *sep);
|
void command_undye(Client *c, const Seperator *sep);
|
||||||
void command_undyeme(Client *c, const Seperator *sep);
|
void command_undyeme(Client *c, const Seperator *sep);
|
||||||
|
|||||||
@ -550,6 +550,7 @@ struct StatBonuses {
|
|||||||
int FeignedMinionChance; // SPA 281 base1 = chance, just like normal FD
|
int FeignedMinionChance; // SPA 281 base1 = chance, just like normal FD
|
||||||
int aura_slots;
|
int aura_slots;
|
||||||
int trap_slots;
|
int trap_slots;
|
||||||
|
bool hunger; // Song of Sustenance -- min caps to 3500
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -603,6 +604,11 @@ enum { //type arguments to DoAnim
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SKILLUP_UNKNOWN = 0,
|
||||||
|
SKILLUP_SUCCESS = 1,
|
||||||
|
SKILLUP_FAILURE = 2
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
petFamiliar, //only listens to /pet get lost
|
petFamiliar, //only listens to /pet get lost
|
||||||
|
|||||||
@ -611,9 +611,13 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the client does this check before calling CastSpell, should prevent discs being eaten
|
||||||
|
if (spell.buffdurationformula != 0 && spell.targettype == ST_Self && HasDiscBuff())
|
||||||
|
return false;
|
||||||
|
|
||||||
//Check the disc timer
|
//Check the disc timer
|
||||||
pTimerType DiscTimer = pTimerDisciplineReuseStart + spell.EndurTimerIndex;
|
pTimerType DiscTimer = pTimerDisciplineReuseStart + spell.EndurTimerIndex;
|
||||||
if(!p_timers.Expired(&database, DiscTimer)) {
|
if(!p_timers.Expired(&database, DiscTimer, false)) { // lets not set the reuse timer in case CastSpell fails (or we would have to turn off the timer, but CastSpell will set it as well)
|
||||||
/*char val1[20]={0};*/ //unused
|
/*char val1[20]={0};*/ //unused
|
||||||
/*char val2[20]={0};*/ //unused
|
/*char val2[20]={0};*/ //unused
|
||||||
uint32 remain = p_timers.GetRemainingTime(DiscTimer);
|
uint32 remain = p_timers.GetRemainingTime(DiscTimer);
|
||||||
|
|||||||
@ -237,6 +237,7 @@ void Embperl::init_eval_file(void)
|
|||||||
{
|
{
|
||||||
eval_pv(
|
eval_pv(
|
||||||
"our %Cache;"
|
"our %Cache;"
|
||||||
|
"no warnings;"
|
||||||
"use Symbol qw(delete_package);"
|
"use Symbol qw(delete_package);"
|
||||||
"sub eval_file {"
|
"sub eval_file {"
|
||||||
"my($package, $filename) = @_;"
|
"my($package, $filename) = @_;"
|
||||||
@ -247,7 +248,8 @@ void Embperl::init_eval_file(void)
|
|||||||
" return;"
|
" return;"
|
||||||
"} else {"
|
"} else {"
|
||||||
// we 'my' $filename,$mtime,$package,$sub to prevent them from changing our state up here.
|
// we 'my' $filename,$mtime,$package,$sub to prevent them from changing our state up here.
|
||||||
" eval(\"package $package; my(\\$filename,\\$mtime,\\$package,\\$sub); \\$isloaded = 1; require '$filename'; \");"
|
" eval(\"package $package; my(\\$filename,\\$mtime,\\$package,\\$sub); \\$isloaded = 1; require './$filename'; \");"
|
||||||
|
// " print $@ if $@;"
|
||||||
/* "local *FH;open FH, $filename or die \"open '$filename' $!\";"
|
/* "local *FH;open FH, $filename or die \"open '$filename' $!\";"
|
||||||
"local($/) = undef;my $sub = <FH>;close FH;"
|
"local($/) = undef;my $sub = <FH>;close FH;"
|
||||||
"my $eval = qq{package $package; sub handler { $sub; }};"
|
"my $eval = qq{package $package; sub handler { $sub; }};"
|
||||||
|
|||||||
@ -99,6 +99,10 @@ XS(XS_EQEmuIO_PRINT)
|
|||||||
/* Strip newlines from log message 'str' */
|
/* Strip newlines from log message 'str' */
|
||||||
*std::remove(str, str + strlen(str), '\n') = '\0';
|
*std::remove(str, str + strlen(str), '\n') = '\0';
|
||||||
|
|
||||||
|
std::string log_string = str;
|
||||||
|
if (log_string.find("did not return a true") != std::string::npos)
|
||||||
|
return;;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|||||||
@ -648,7 +648,7 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
|
|||||||
|
|
||||||
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
|
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
|
||||||
|
|
||||||
npc->FixZ();
|
npc->FixZ(1);
|
||||||
|
|
||||||
uint16 emoteid = npc->GetEmoteID();
|
uint16 emoteid = npc->GetEmoteID();
|
||||||
if (emoteid != 0)
|
if (emoteid != 0)
|
||||||
@ -1419,10 +1419,10 @@ void EntityList::RemoveFromTargets(Mob *mob, bool RemoveFromXTargets)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (RemoveFromXTargets) {
|
if (RemoveFromXTargets) {
|
||||||
if (m->IsClient() && mob->CheckAggro(m))
|
if (m->IsClient() && (mob->CheckAggro(m) || mob->IsOnFeignMemory(m->CastToClient())))
|
||||||
m->CastToClient()->RemoveXTarget(mob, false);
|
m->CastToClient()->RemoveXTarget(mob, false);
|
||||||
// FadingMemories calls this function passing the client.
|
// FadingMemories calls this function passing the client.
|
||||||
else if (mob->IsClient() && m->CheckAggro(mob))
|
else if (mob->IsClient() && (m->CheckAggro(mob) || m->IsOnFeignMemory(mob->CastToClient())))
|
||||||
mob->CastToClient()->RemoveXTarget(m, false);
|
mob->CastToClient()->RemoveXTarget(m, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1461,7 +1461,7 @@ void EntityList::RefreshAutoXTargets(Client *c)
|
|||||||
if (!m || m->GetHP() <= 0)
|
if (!m || m->GetHP() <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (m->CheckAggro(c) && !c->IsXTarget(m)) {
|
if ((m->CheckAggro(c) || m->IsOnFeignMemory(c)) && !c->IsXTarget(m)) {
|
||||||
c->AddAutoXTarget(m, false); // we only call this before a bulk, so lets not send right away
|
c->AddAutoXTarget(m, false); // we only call this before a bulk, so lets not send right away
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2617,12 +2617,13 @@ void EntityList::RemoveFromHateLists(Mob *mob, bool settoone)
|
|||||||
auto it = npc_list.begin();
|
auto it = npc_list.begin();
|
||||||
while (it != npc_list.end()) {
|
while (it != npc_list.end()) {
|
||||||
if (it->second->CheckAggro(mob)) {
|
if (it->second->CheckAggro(mob)) {
|
||||||
if (!settoone)
|
if (!settoone) {
|
||||||
it->second->RemoveFromHateList(mob);
|
it->second->RemoveFromHateList(mob);
|
||||||
else
|
|
||||||
it->second->SetHateAmountOnEnt(mob, 1);
|
|
||||||
if (mob->IsClient())
|
if (mob->IsClient())
|
||||||
mob->CastToClient()->RemoveXTarget(it->second, false); // gotta do book keeping
|
mob->CastToClient()->RemoveXTarget(it->second, false); // gotta do book keeping
|
||||||
|
} else {
|
||||||
|
it->second->SetHateAmountOnEnt(mob, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
@ -3079,7 +3080,10 @@ void EntityList::ClearAggro(Mob* targ)
|
|||||||
c->RemoveXTarget(it->second, false);
|
c->RemoveXTarget(it->second, false);
|
||||||
it->second->RemoveFromHateList(targ);
|
it->second->RemoveFromHateList(targ);
|
||||||
}
|
}
|
||||||
it->second->RemoveFromFeignMemory(targ->CastToClient()); //just in case we feigned
|
if (c && it->second->IsOnFeignMemory(c)) {
|
||||||
|
it->second->RemoveFromFeignMemory(c); //just in case we feigned
|
||||||
|
c->RemoveXTarget(it->second, false);
|
||||||
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3088,7 +3092,8 @@ void EntityList::ClearFeignAggro(Mob *targ)
|
|||||||
{
|
{
|
||||||
auto it = npc_list.begin();
|
auto it = npc_list.begin();
|
||||||
while (it != npc_list.end()) {
|
while (it != npc_list.end()) {
|
||||||
if (it->second->CheckAggro(targ)) {
|
// add Feign Memory check because sometimes weird stuff happens
|
||||||
|
if (it->second->CheckAggro(targ) || (targ->IsClient() && it->second->IsOnFeignMemory(targ->CastToClient()))) {
|
||||||
if (it->second->GetSpecialAbility(IMMUNE_FEIGN_DEATH)) {
|
if (it->second->GetSpecialAbility(IMMUNE_FEIGN_DEATH)) {
|
||||||
++it;
|
++it;
|
||||||
continue;
|
continue;
|
||||||
@ -3252,7 +3257,7 @@ void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 hate)
|
|||||||
|
|
||||||
for (auto &e : npc_list) {
|
for (auto &e : npc_list) {
|
||||||
auto &npc = e.second;
|
auto &npc = e.second;
|
||||||
if (!npc->CheckAggro(target) || npc->IsFeared())
|
if (!npc->CheckAggro(target) || npc->IsFeared() || npc->IsPet())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (zone->random.Roll(50)) // witness check -- place holder
|
if (zone->random.Roll(50)) // witness check -- place holder
|
||||||
|
|||||||
@ -365,7 +365,7 @@ public:
|
|||||||
//trap stuff
|
//trap stuff
|
||||||
Mob* GetTrapTrigger(Trap* trap);
|
Mob* GetTrapTrigger(Trap* trap);
|
||||||
void SendAlarm(Trap* trap, Mob* currenttarget, uint8 kos);
|
void SendAlarm(Trap* trap, Mob* currenttarget, uint8 kos);
|
||||||
Trap* FindNearbyTrap(Mob* searcher, float max_dist);
|
Trap* FindNearbyTrap(Mob* searcher, float max_dist, float &curdist, bool detected = false);
|
||||||
|
|
||||||
void AddHealAggro(Mob* target, Mob* caster, uint16 hate);
|
void AddHealAggro(Mob* target, Mob* caster, uint16 hate);
|
||||||
Mob* FindDefenseNPC(uint32 npcid);
|
Mob* FindDefenseNPC(uint32 npcid);
|
||||||
@ -473,6 +473,10 @@ public:
|
|||||||
void RefreshClientXTargets(Client *c);
|
void RefreshClientXTargets(Client *c);
|
||||||
void SendAlternateAdvancementStats();
|
void SendAlternateAdvancementStats();
|
||||||
|
|
||||||
|
void GetTrapInfo(Client* client);
|
||||||
|
bool IsTrapGroupSpawned(uint32 trap_id, uint8 group);
|
||||||
|
void UpdateAllTraps(bool respawn, bool repopnow = false);
|
||||||
|
void ClearTrapPointers();
|
||||||
protected:
|
protected:
|
||||||
friend class Zone;
|
friend class Zone;
|
||||||
void Depop(bool StartSpawnTimer = false);
|
void Depop(bool StartSpawnTimer = false);
|
||||||
|
|||||||
@ -327,8 +327,7 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
|||||||
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
|
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shouldn't race not affect AA XP?
|
||||||
|
|
||||||
if(RuleB(Character,UseRaceClassExpBonuses))
|
if(RuleB(Character,UseRaceClassExpBonuses))
|
||||||
{
|
{
|
||||||
if(GetBaseRace() == HALFLING){
|
if(GetBaseRace() == HALFLING){
|
||||||
@ -340,6 +339,12 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// why wasn't this here? Where should it be?
|
||||||
|
if(zone->IsHotzone())
|
||||||
|
{
|
||||||
|
aatotalmod += RuleR(Zone, HotZoneBonus);
|
||||||
|
}
|
||||||
|
|
||||||
if(RuleB(Zone, LevelBasedEXPMods)){
|
if(RuleB(Zone, LevelBasedEXPMods)){
|
||||||
if(zone->level_exp_mod[GetLevel()].ExpMod){
|
if(zone->level_exp_mod[GetLevel()].ExpMod){
|
||||||
add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
|
add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
|
||||||
|
|||||||
@ -163,7 +163,7 @@ void Mob::CalculateNewFearpoint()
|
|||||||
ranx = GetX()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1);
|
ranx = GetX()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1);
|
||||||
rany = GetY()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1);
|
rany = GetY()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1);
|
||||||
ranz = FindGroundZ(ranx,rany);
|
ranz = FindGroundZ(ranx,rany);
|
||||||
if (ranz == -999999)
|
if (ranz == BEST_Z_INVALID)
|
||||||
continue;
|
continue;
|
||||||
float fdist = ranz - GetZ();
|
float fdist = ranz - GetZ();
|
||||||
if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz))
|
if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz))
|
||||||
|
|||||||
@ -2464,3 +2464,33 @@ bool Group::HasRole(Mob *m, uint8 Role)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Group::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/) {
|
||||||
|
if (sender && sender->IsClient()) {
|
||||||
|
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||||
|
|
||||||
|
if (!members[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!members[i]->IsClient())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ignore_sender && members[i] == sender)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If we don't have a distance requirement - send to all members */
|
||||||
|
if (distance == 0) {
|
||||||
|
members[i]->CastToClient()->QueuePacket(app, ack_required);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* If negative distance - we check if current distance is greater than X */
|
||||||
|
if (distance <= 0 && DistanceSquared(sender->GetPosition(), members[i]->GetPosition()) >= (distance * distance)) {
|
||||||
|
members[i]->CastToClient()->QueuePacket(app, ack_required);
|
||||||
|
}
|
||||||
|
/* If positive distance - we check if current distance is less than X */
|
||||||
|
else if (distance >= 0 && DistanceSquared(sender->GetPosition(), members[i]->GetPosition()) <= (distance * distance)) {
|
||||||
|
members[i]->CastToClient()->QueuePacket(app, ack_required);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -140,6 +140,7 @@ public:
|
|||||||
inline int GetLeadershipAA(int AAID) { return LeaderAbilities.ranks[AAID]; }
|
inline int GetLeadershipAA(int AAID) { return LeaderAbilities.ranks[AAID]; }
|
||||||
void ClearAllNPCMarks();
|
void ClearAllNPCMarks();
|
||||||
void QueueHPPacketsForNPCHealthAA(Mob* sender, const EQApplicationPacket* app);
|
void QueueHPPacketsForNPCHealthAA(Mob* sender, const EQApplicationPacket* app);
|
||||||
|
void QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required = true, bool ignore_sender = true, float distance = 0);
|
||||||
void ChangeLeader(Mob* newleader);
|
void ChangeLeader(Mob* newleader);
|
||||||
const char *GetClientNameByIndex(uint8 index);
|
const char *GetClientNameByIndex(uint8 index);
|
||||||
void UpdateXTargetMarkedNPC(uint32 Number, Mob *m);
|
void UpdateXTargetMarkedNPC(uint32 Number, Mob *m);
|
||||||
|
|||||||
@ -151,6 +151,7 @@ void Client::SummonHorse(uint16 spell_id) {
|
|||||||
|
|
||||||
uint16 tmpID = horse->GetID();
|
uint16 tmpID = horse->GetID();
|
||||||
SetHorseId(tmpID);
|
SetHorseId(tmpID);
|
||||||
|
BuffFadeBySitModifier();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -336,6 +336,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
|||||||
eslot = EQEmu::textures::weaponPrimary;
|
eslot = EQEmu::textures::weaponPrimary;
|
||||||
if (item2->Damage > 0) {
|
if (item2->Damage > 0) {
|
||||||
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
|
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
|
||||||
|
if (!RuleB(Combat, ClassicNPCBackstab))
|
||||||
SetFacestab(true);
|
SetFacestab(true);
|
||||||
}
|
}
|
||||||
if (item2->IsType2HWeapon())
|
if (item2->IsType2HWeapon())
|
||||||
|
|||||||
@ -1440,6 +1440,54 @@ void Lua_Client::FilteredMessage(Mob *sender, uint32 type, int filter, const cha
|
|||||||
self->FilteredMessage(sender, type, (eqFilterType)filter, message);
|
self->FilteredMessage(sender, type, (eqFilterType)filter, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Lua_Client::EnableAreaHPRegen(int value)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->EnableAreaHPRegen(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::DisableAreaHPRegen()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->DisableAreaHPRegen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::EnableAreaManaRegen(int value)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->EnableAreaManaRegen(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::DisableAreaManaRegen()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->DisableAreaManaRegen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::EnableAreaEndRegen(int value)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->EnableAreaEndRegen(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::DisableAreaEndRegen()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->DisableAreaEndRegen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::EnableAreaRegens(int value)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->EnableAreaRegens(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::DisableAreaRegens()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->DisableAreaRegens();
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_client() {
|
luabind::scope lua_register_client() {
|
||||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@ -1712,7 +1760,15 @@ luabind::scope lua_register_client() {
|
|||||||
.def("IsDead", &Lua_Client::IsDead)
|
.def("IsDead", &Lua_Client::IsDead)
|
||||||
.def("CalcCurrentWeight", &Lua_Client::CalcCurrentWeight)
|
.def("CalcCurrentWeight", &Lua_Client::CalcCurrentWeight)
|
||||||
.def("CalcATK", &Lua_Client::CalcATK)
|
.def("CalcATK", &Lua_Client::CalcATK)
|
||||||
.def("FilteredMessage", &Lua_Client::FilteredMessage);
|
.def("FilteredMessage", &Lua_Client::FilteredMessage)
|
||||||
|
.def("EnableAreaHPRegen", &Lua_Client::EnableAreaHPRegen)
|
||||||
|
.def("DisableAreaHPRegen", &Lua_Client::DisableAreaHPRegen)
|
||||||
|
.def("EnableAreaManaRegen", &Lua_Client::EnableAreaManaRegen)
|
||||||
|
.def("DisableAreaManaRegen", &Lua_Client::DisableAreaManaRegen)
|
||||||
|
.def("EnableAreaEndRegen", &Lua_Client::EnableAreaEndRegen)
|
||||||
|
.def("DisableAreaEndRegen", &Lua_Client::DisableAreaEndRegen)
|
||||||
|
.def("EnableAreaRegens", &Lua_Client::EnableAreaRegens)
|
||||||
|
.def("DisableAreaRegens", &Lua_Client::DisableAreaRegens);
|
||||||
}
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_inventory_where() {
|
luabind::scope lua_register_inventory_where() {
|
||||||
|
|||||||
@ -301,6 +301,14 @@ public:
|
|||||||
int CalcCurrentWeight();
|
int CalcCurrentWeight();
|
||||||
int CalcATK();
|
int CalcATK();
|
||||||
void FilteredMessage(Mob *sender, uint32 type, int filter, const char* message);
|
void FilteredMessage(Mob *sender, uint32 type, int filter, const char* message);
|
||||||
|
void EnableAreaHPRegen(int value);
|
||||||
|
void DisableAreaHPRegen();
|
||||||
|
void EnableAreaManaRegen(int value);
|
||||||
|
void DisableAreaManaRegen();
|
||||||
|
void EnableAreaEndRegen(int value);
|
||||||
|
void DisableAreaEndRegen();
|
||||||
|
void EnableAreaRegens(int value);
|
||||||
|
void DisableAreaRegens();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1686,6 +1686,11 @@ void Lua_Mob::DoKnockback(Lua_Mob caster, uint32 pushback, uint32 pushup) {
|
|||||||
self->DoKnockback(caster, pushback, pushup);
|
self->DoKnockback(caster, pushback, pushup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Lua_Mob::AddNimbusEffect(int effect_id) {
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->AddNimbusEffect(effect_id);
|
||||||
|
}
|
||||||
|
|
||||||
void Lua_Mob::RemoveNimbusEffect(int effect_id) {
|
void Lua_Mob::RemoveNimbusEffect(int effect_id) {
|
||||||
Lua_Safe_Call_Void();
|
Lua_Safe_Call_Void();
|
||||||
self->RemoveNimbusEffect(effect_id);
|
self->RemoveNimbusEffect(effect_id);
|
||||||
@ -2367,6 +2372,7 @@ luabind::scope lua_register_mob() {
|
|||||||
.def("SetSlotTint", (void(Lua_Mob::*)(int,int,int,int))&Lua_Mob::SetSlotTint)
|
.def("SetSlotTint", (void(Lua_Mob::*)(int,int,int,int))&Lua_Mob::SetSlotTint)
|
||||||
.def("WearChange", (void(Lua_Mob::*)(int,int,uint32))&Lua_Mob::WearChange)
|
.def("WearChange", (void(Lua_Mob::*)(int,int,uint32))&Lua_Mob::WearChange)
|
||||||
.def("DoKnockback", (void(Lua_Mob::*)(Lua_Mob,uint32,uint32))&Lua_Mob::DoKnockback)
|
.def("DoKnockback", (void(Lua_Mob::*)(Lua_Mob,uint32,uint32))&Lua_Mob::DoKnockback)
|
||||||
|
.def("AddNimbusEffect", (void(Lua_Mob::*)(int))&Lua_Mob::AddNimbusEffect)
|
||||||
.def("RemoveNimbusEffect", (void(Lua_Mob::*)(int))&Lua_Mob::RemoveNimbusEffect)
|
.def("RemoveNimbusEffect", (void(Lua_Mob::*)(int))&Lua_Mob::RemoveNimbusEffect)
|
||||||
.def("IsFeared", (bool(Lua_Mob::*)(void))&Lua_Mob::IsFeared)
|
.def("IsFeared", (bool(Lua_Mob::*)(void))&Lua_Mob::IsFeared)
|
||||||
.def("IsBlind", (bool(Lua_Mob::*)(void))&Lua_Mob::IsBlind)
|
.def("IsBlind", (bool(Lua_Mob::*)(void))&Lua_Mob::IsBlind)
|
||||||
|
|||||||
@ -323,6 +323,7 @@ public:
|
|||||||
void SetSlotTint(int material_slot, int red_tint, int green_tint, int blue_tint);
|
void SetSlotTint(int material_slot, int red_tint, int green_tint, int blue_tint);
|
||||||
void WearChange(int material_slot, int texture, uint32 color);
|
void WearChange(int material_slot, int texture, uint32 color);
|
||||||
void DoKnockback(Lua_Mob caster, uint32 pushback, uint32 pushup);
|
void DoKnockback(Lua_Mob caster, uint32 pushback, uint32 pushup);
|
||||||
|
void AddNimbusEffect(int effect_id);
|
||||||
void RemoveNimbusEffect(int effect_id);
|
void RemoveNimbusEffect(int effect_id);
|
||||||
bool IsRunning();
|
bool IsRunning();
|
||||||
void SetRunning(bool running);
|
void SetRunning(bool running);
|
||||||
|
|||||||
@ -1154,7 +1154,7 @@ void Merc::CalcRestState() {
|
|||||||
// The bot must have been out of combat for RuleI(Character, RestRegenTimeToActivate) seconds,
|
// The bot must have been out of combat for RuleI(Character, RestRegenTimeToActivate) seconds,
|
||||||
// must be sitting down, and must not have any detrimental spells affecting them.
|
// must be sitting down, and must not have any detrimental spells affecting them.
|
||||||
//
|
//
|
||||||
if(!RuleI(Character, RestRegenPercent))
|
if(!RuleB(Character, RestRegenEnabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RestRegenHP = RestRegenMana = RestRegenEndurance = 0;
|
RestRegenHP = RestRegenMana = RestRegenEndurance = 0;
|
||||||
@ -1174,12 +1174,11 @@ void Merc::CalcRestState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RestRegenHP = (GetMaxHP() * RuleI(Character, RestRegenPercent) / 100);
|
RestRegenHP = 6 * (GetMaxHP() / RuleI(Character, RestRegenHP));
|
||||||
|
|
||||||
RestRegenMana = (GetMaxMana() * RuleI(Character, RestRegenPercent) / 100);
|
RestRegenMana = 6 * (GetMaxMana() / RuleI(Character, RestRegenMana));
|
||||||
|
|
||||||
if(RuleB(Character, RestRegenEndurance))
|
RestRegenEndurance = 6 * (GetMaxEndurance() / RuleI(Character, RestRegenEnd));
|
||||||
RestRegenEndurance = (GetMaxEndurance() * RuleI(Character, RestRegenPercent) / 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Merc::HasSkill(EQEmu::skills::SkillType skill_id) const {
|
bool Merc::HasSkill(EQEmu::skills::SkillType skill_id) const {
|
||||||
|
|||||||
98
zone/mob.cpp
98
zone/mob.cpp
@ -75,7 +75,6 @@ Mob::Mob(const char* in_name,
|
|||||||
uint32 in_drakkin_tattoo,
|
uint32 in_drakkin_tattoo,
|
||||||
uint32 in_drakkin_details,
|
uint32 in_drakkin_details,
|
||||||
EQEmu::TintProfile in_armor_tint,
|
EQEmu::TintProfile in_armor_tint,
|
||||||
|
|
||||||
uint8 in_aa_title,
|
uint8 in_aa_title,
|
||||||
uint8 in_see_invis, // see through invis/ivu
|
uint8 in_see_invis, // see through invis/ivu
|
||||||
uint8 in_see_invis_undead,
|
uint8 in_see_invis_undead,
|
||||||
@ -98,7 +97,7 @@ Mob::Mob(const char* in_name,
|
|||||||
tic_timer(6000),
|
tic_timer(6000),
|
||||||
mana_timer(2000),
|
mana_timer(2000),
|
||||||
spellend_timer(0),
|
spellend_timer(0),
|
||||||
rewind_timer(30000), //Timer used for determining amount of time between actual player position updates for /rewind.
|
rewind_timer(30000),
|
||||||
bindwound_timer(10000),
|
bindwound_timer(10000),
|
||||||
stunned_timer(0),
|
stunned_timer(0),
|
||||||
spun_timer(0),
|
spun_timer(0),
|
||||||
@ -123,9 +122,8 @@ Mob::Mob(const char* in_name,
|
|||||||
tar_vector = 0;
|
tar_vector = 0;
|
||||||
currently_fleeing = false;
|
currently_fleeing = false;
|
||||||
|
|
||||||
last_z = 0;
|
|
||||||
|
|
||||||
last_major_update_position = m_Position;
|
last_major_update_position = m_Position;
|
||||||
|
is_distance_roamer = false;
|
||||||
|
|
||||||
AI_Init();
|
AI_Init();
|
||||||
SetMoving(false);
|
SetMoving(false);
|
||||||
@ -172,7 +170,8 @@ Mob::Mob(const char* in_name,
|
|||||||
fearspeed = 0.625f;
|
fearspeed = 0.625f;
|
||||||
base_fearspeed = 25;
|
base_fearspeed = 25;
|
||||||
// npcs
|
// npcs
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
base_walkspeed = base_runspeed * 100 / 265;
|
base_walkspeed = base_runspeed * 100 / 265;
|
||||||
walkspeed = ((float)base_walkspeed) * 0.025f;
|
walkspeed = ((float)base_walkspeed) * 0.025f;
|
||||||
base_fearspeed = base_runspeed * 100 / 127;
|
base_fearspeed = base_runspeed * 100 / 127;
|
||||||
@ -1383,7 +1382,7 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
|||||||
if(IsClient()){
|
if(IsClient()){
|
||||||
Raid *raid = entity_list.GetRaidByClient(CastToClient());
|
Raid *raid = entity_list.GetRaidByClient(CastToClient());
|
||||||
if (raid)
|
if (raid)
|
||||||
raid->SendHPPacketsFrom(this);
|
raid->SendHPManaEndPacketsFrom(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pet - Update master - group and raid if exists */
|
/* Pet - Update master - group and raid if exists */
|
||||||
@ -1396,7 +1395,7 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
|||||||
|
|
||||||
Raid *raid = entity_list.GetRaidByClient(GetOwner()->CastToClient());
|
Raid *raid = entity_list.GetRaidByClient(GetOwner()->CastToClient());
|
||||||
if(raid)
|
if(raid)
|
||||||
raid->SendHPPacketsFrom(this);
|
raid->SendHPManaEndPacketsFrom(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send to pet */
|
/* Send to pet */
|
||||||
@ -1447,6 +1446,7 @@ void Mob::SendPosition() {
|
|||||||
if (DistanceSquared(last_major_update_position, m_Position) >= (100 * 100)) {
|
if (DistanceSquared(last_major_update_position, m_Position) >= (100 * 100)) {
|
||||||
entity_list.QueueClients(this, app, true, true);
|
entity_list.QueueClients(this, app, true, true);
|
||||||
last_major_update_position = m_Position;
|
last_major_update_position = m_Position;
|
||||||
|
is_distance_roamer = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
entity_list.QueueCloseClients(this, app, true, RuleI(Range, MobPositionUpdates), nullptr, false);
|
entity_list.QueueCloseClients(this, app, true, RuleI(Range, MobPositionUpdates), nullptr, false);
|
||||||
@ -1455,6 +1455,20 @@ void Mob::SendPosition() {
|
|||||||
safe_delete(app);
|
safe_delete(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mob::SendPositionUpdateToClient(Client *client) {
|
||||||
|
auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||||
|
PlayerPositionUpdateServer_Struct* spawn_update = (PlayerPositionUpdateServer_Struct*)app->pBuffer;
|
||||||
|
|
||||||
|
if(this->IsMoving())
|
||||||
|
MakeSpawnUpdate(spawn_update);
|
||||||
|
else
|
||||||
|
MakeSpawnUpdateNoDelta(spawn_update);
|
||||||
|
|
||||||
|
client->QueuePacket(app, false);
|
||||||
|
|
||||||
|
safe_delete(app);
|
||||||
|
}
|
||||||
|
|
||||||
/* Position updates for mobs on the move */
|
/* Position updates for mobs on the move */
|
||||||
void Mob::SendPositionUpdate(uint8 iSendToSelf) {
|
void Mob::SendPositionUpdate(uint8 iSendToSelf) {
|
||||||
auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||||
@ -1466,6 +1480,11 @@ void Mob::SendPositionUpdate(uint8 iSendToSelf) {
|
|||||||
CastToClient()->FastQueuePacket(&app, false);
|
CastToClient()->FastQueuePacket(&app, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (DistanceSquared(last_major_update_position, m_Position) >= (100 * 100)) {
|
||||||
|
entity_list.QueueClients(this, app, true, true);
|
||||||
|
last_major_update_position = m_Position;
|
||||||
|
is_distance_roamer = true;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
entity_list.QueueCloseClients(this, app, (iSendToSelf == 0), RuleI(Range, MobPositionUpdates), nullptr, false);
|
entity_list.QueueCloseClients(this, app, (iSendToSelf == 0), RuleI(Range, MobPositionUpdates), nullptr, false);
|
||||||
}
|
}
|
||||||
@ -3383,13 +3402,18 @@ int Mob::GetHaste()
|
|||||||
else // 1-25
|
else // 1-25
|
||||||
h += itembonuses.haste > 10 ? 10 : itembonuses.haste;
|
h += itembonuses.haste > 10 ? 10 : itembonuses.haste;
|
||||||
|
|
||||||
// 60+ 100, 51-59 85, 1-50 level+25
|
// mobs are different!
|
||||||
if (level > 59) // 60+
|
Mob *owner = nullptr;
|
||||||
cap = RuleI(Character, HasteCap);
|
if (IsPet())
|
||||||
else if (level > 50) // 51-59
|
owner = GetOwner();
|
||||||
cap = 85;
|
else if (IsNPC() && CastToNPC()->GetSwarmOwner())
|
||||||
else // 1-50
|
owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner());
|
||||||
cap = level + 25;
|
if (owner) {
|
||||||
|
cap = 10 + level;
|
||||||
|
cap += std::max(0, owner->GetLevel() - 39) + std::max(0, owner->GetLevel() - 60);
|
||||||
|
} else {
|
||||||
|
cap = 150;
|
||||||
|
}
|
||||||
|
|
||||||
if(h > cap)
|
if(h > cap)
|
||||||
h = cap;
|
h = cap;
|
||||||
@ -3425,9 +3449,22 @@ void Mob::SetTarget(Mob* mob) {
|
|||||||
this->GetTarget()->SendHPUpdate(false, true);
|
this->GetTarget()->SendHPUpdate(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For when we want a Ground Z at a location we are not at yet
|
||||||
|
// Like MoveTo.
|
||||||
|
float Mob::FindDestGroundZ(glm::vec3 dest, float z_offset)
|
||||||
|
{
|
||||||
|
float best_z = BEST_Z_INVALID;
|
||||||
|
if (zone->zonemap != nullptr)
|
||||||
|
{
|
||||||
|
dest.z += z_offset;
|
||||||
|
best_z = zone->zonemap->FindBestZ(dest, nullptr);
|
||||||
|
}
|
||||||
|
return best_z;
|
||||||
|
}
|
||||||
|
|
||||||
float Mob::FindGroundZ(float new_x, float new_y, float z_offset)
|
float Mob::FindGroundZ(float new_x, float new_y, float z_offset)
|
||||||
{
|
{
|
||||||
float ret = -999999;
|
float ret = BEST_Z_INVALID;
|
||||||
if (zone->zonemap != nullptr)
|
if (zone->zonemap != nullptr)
|
||||||
{
|
{
|
||||||
glm::vec3 me;
|
glm::vec3 me;
|
||||||
@ -3436,7 +3473,7 @@ float Mob::FindGroundZ(float new_x, float new_y, float z_offset)
|
|||||||
me.z = m_Position.z + z_offset;
|
me.z = m_Position.z + z_offset;
|
||||||
glm::vec3 hit;
|
glm::vec3 hit;
|
||||||
float best_z = zone->zonemap->FindBestZ(me, &hit);
|
float best_z = zone->zonemap->FindBestZ(me, &hit);
|
||||||
if (best_z != -999999)
|
if (best_z != BEST_Z_INVALID)
|
||||||
{
|
{
|
||||||
ret = best_z;
|
ret = best_z;
|
||||||
}
|
}
|
||||||
@ -3447,7 +3484,7 @@ float Mob::FindGroundZ(float new_x, float new_y, float z_offset)
|
|||||||
// Copy of above function that isn't protected to be exported to Perl::Mob
|
// Copy of above function that isn't protected to be exported to Perl::Mob
|
||||||
float Mob::GetGroundZ(float new_x, float new_y, float z_offset)
|
float Mob::GetGroundZ(float new_x, float new_y, float z_offset)
|
||||||
{
|
{
|
||||||
float ret = -999999;
|
float ret = BEST_Z_INVALID;
|
||||||
if (zone->zonemap != 0)
|
if (zone->zonemap != 0)
|
||||||
{
|
{
|
||||||
glm::vec3 me;
|
glm::vec3 me;
|
||||||
@ -3456,7 +3493,7 @@ float Mob::GetGroundZ(float new_x, float new_y, float z_offset)
|
|||||||
me.z = m_Position.z+z_offset;
|
me.z = m_Position.z+z_offset;
|
||||||
glm::vec3 hit;
|
glm::vec3 hit;
|
||||||
float best_z = zone->zonemap->FindBestZ(me, &hit);
|
float best_z = zone->zonemap->FindBestZ(me, &hit);
|
||||||
if (best_z != -999999)
|
if (best_z != BEST_Z_INVALID)
|
||||||
{
|
{
|
||||||
ret = best_z;
|
ret = best_z;
|
||||||
}
|
}
|
||||||
@ -3761,7 +3798,7 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
|
|||||||
if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5)
|
if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5)
|
||||||
use_spell = true;
|
use_spell = true;
|
||||||
|
|
||||||
else if (base2 = 1004 && GetHPRatio() < 80)
|
else if (base2 == 1004 && GetHPRatio() < 80)
|
||||||
use_spell = true;
|
use_spell = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3769,12 +3806,12 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
|
|||||||
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40))
|
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40))
|
||||||
use_spell = true;
|
use_spell = true;
|
||||||
|
|
||||||
else if (base2 = 38311 && GetManaRatio() < 10)
|
else if (base2 == 38311 && GetManaRatio() < 10)
|
||||||
use_spell = true;
|
use_spell = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (IsEndur){
|
else if (IsEndur){
|
||||||
if (base2 = 522 && GetEndurancePercent() < 40){
|
if (base2 == 522 && GetEndurancePercent() < 40){
|
||||||
use_spell = true;
|
use_spell = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3935,10 +3972,17 @@ int16 Mob::GetHealRate(uint16 spell_id, Mob* caster) {
|
|||||||
|
|
||||||
bool Mob::TryFadeEffect(int slot)
|
bool Mob::TryFadeEffect(int slot)
|
||||||
{
|
{
|
||||||
|
if (!buffs[slot].spellid)
|
||||||
|
return false;
|
||||||
|
|
||||||
if(IsValidSpell(buffs[slot].spellid))
|
if(IsValidSpell(buffs[slot].spellid))
|
||||||
{
|
{
|
||||||
for(int i = 0; i < EFFECT_COUNT; i++)
|
for(int i = 0; i < EFFECT_COUNT; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (!spells[buffs[slot].spellid].effectid[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnFadeEffectAlways ||
|
if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnFadeEffectAlways ||
|
||||||
spells[buffs[slot].spellid].effectid[i] == SE_CastOnRuneFadeEffect)
|
spells[buffs[slot].spellid].effectid[i] == SE_CastOnRuneFadeEffect)
|
||||||
{
|
{
|
||||||
@ -4980,6 +5024,18 @@ void Mob::SpreadVirus(uint16 spell_id, uint16 casterID)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mob::AddNimbusEffect(int effectid)
|
||||||
|
{
|
||||||
|
SetNimbusEffect(effectid);
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket(OP_AddNimbusEffect, sizeof(RemoveNimbusEffect_Struct));
|
||||||
|
auto ane = (RemoveNimbusEffect_Struct *)outapp->pBuffer;
|
||||||
|
ane->spawnid = GetID();
|
||||||
|
ane->nimbus_effect = effectid;
|
||||||
|
entity_list.QueueClients(this, outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
|
}
|
||||||
|
|
||||||
void Mob::RemoveNimbusEffect(int effectid)
|
void Mob::RemoveNimbusEffect(int effectid)
|
||||||
{
|
{
|
||||||
if (effectid == nimbus_effect1)
|
if (effectid == nimbus_effect1)
|
||||||
|
|||||||
19
zone/mob.h
19
zone/mob.h
@ -162,6 +162,8 @@ public:
|
|||||||
inline virtual bool IsMob() const { return true; }
|
inline virtual bool IsMob() const { return true; }
|
||||||
inline virtual bool InZone() const { return true; }
|
inline virtual bool InZone() const { return true; }
|
||||||
|
|
||||||
|
bool is_distance_roamer;
|
||||||
|
|
||||||
//Somewhat sorted: needs documenting!
|
//Somewhat sorted: needs documenting!
|
||||||
|
|
||||||
//Attack
|
//Attack
|
||||||
@ -199,6 +201,7 @@ public:
|
|||||||
void ApplyMeleeDamageMods(uint16 skill, int &damage, Mob * defender = nullptr, ExtraAttackOptions *opts = nullptr);
|
void ApplyMeleeDamageMods(uint16 skill, int &damage, Mob * defender = nullptr, ExtraAttackOptions *opts = nullptr);
|
||||||
int ACSum();
|
int ACSum();
|
||||||
int offense(EQEmu::skills::SkillType skill);
|
int offense(EQEmu::skills::SkillType skill);
|
||||||
|
int GetBestMeleeSkill();
|
||||||
void CalcAC() { mitigation_ac = ACSum(); }
|
void CalcAC() { mitigation_ac = ACSum(); }
|
||||||
int GetACSoftcap();
|
int GetACSoftcap();
|
||||||
double GetSoftcapReturns();
|
double GetSoftcapReturns();
|
||||||
@ -278,6 +281,7 @@ public:
|
|||||||
float ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override = false,
|
float ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override = false,
|
||||||
int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false,
|
int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false,
|
||||||
int level_override = -1);
|
int level_override = -1);
|
||||||
|
int GetResist(uint8 resist_type);
|
||||||
int ResistPhysical(int level_diff, uint8 caster_level);
|
int ResistPhysical(int level_diff, uint8 caster_level);
|
||||||
int ResistElementalWeaponDmg(const EQEmu::ItemInstance *item);
|
int ResistElementalWeaponDmg(const EQEmu::ItemInstance *item);
|
||||||
int CheckBaneDamage(const EQEmu::ItemInstance *item);
|
int CheckBaneDamage(const EQEmu::ItemInstance *item);
|
||||||
@ -336,6 +340,7 @@ public:
|
|||||||
void BuffFadeDetrimentalByCaster(Mob *caster);
|
void BuffFadeDetrimentalByCaster(Mob *caster);
|
||||||
void BuffFadeBySitModifier();
|
void BuffFadeBySitModifier();
|
||||||
bool IsAffectedByBuff(uint16 spell_id);
|
bool IsAffectedByBuff(uint16 spell_id);
|
||||||
|
bool IsAffectedByBuffByGlobalGroup(GlobalGroup group);
|
||||||
void BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration);
|
void BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration);
|
||||||
int AddBuff(Mob *caster, const uint16 spell_id, int duration = 0, int32 level_override = -1);
|
int AddBuff(Mob *caster, const uint16 spell_id, int duration = 0, int32 level_override = -1);
|
||||||
int CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite = false);
|
int CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite = false);
|
||||||
@ -348,6 +353,7 @@ public:
|
|||||||
virtual int GetMaxSongSlots() const { return 0; }
|
virtual int GetMaxSongSlots() const { return 0; }
|
||||||
virtual int GetMaxDiscSlots() const { return 0; }
|
virtual int GetMaxDiscSlots() const { return 0; }
|
||||||
virtual int GetMaxTotalSlots() const { return 0; }
|
virtual int GetMaxTotalSlots() const { return 0; }
|
||||||
|
bool HasDiscBuff();
|
||||||
virtual uint32 GetFirstBuffSlot(bool disc, bool song);
|
virtual uint32 GetFirstBuffSlot(bool disc, bool song);
|
||||||
virtual uint32 GetLastBuffSlot(bool disc, bool song);
|
virtual uint32 GetLastBuffSlot(bool disc, bool song);
|
||||||
virtual void InitializeBuffSlots() { buffs = nullptr; current_buff_count = 0; }
|
virtual void InitializeBuffSlots() { buffs = nullptr; current_buff_count = 0; }
|
||||||
@ -376,6 +382,7 @@ public:
|
|||||||
inline virtual uint32 GetNimbusEffect1() const { return nimbus_effect1; }
|
inline virtual uint32 GetNimbusEffect1() const { return nimbus_effect1; }
|
||||||
inline virtual uint32 GetNimbusEffect2() const { return nimbus_effect2; }
|
inline virtual uint32 GetNimbusEffect2() const { return nimbus_effect2; }
|
||||||
inline virtual uint32 GetNimbusEffect3() const { return nimbus_effect3; }
|
inline virtual uint32 GetNimbusEffect3() const { return nimbus_effect3; }
|
||||||
|
void AddNimbusEffect(int effectid);
|
||||||
void RemoveNimbusEffect(int effectid);
|
void RemoveNimbusEffect(int effectid);
|
||||||
inline const glm::vec3& GetTargetRingLocation() const { return m_TargetRing; }
|
inline const glm::vec3& GetTargetRingLocation() const { return m_TargetRing; }
|
||||||
inline float GetTargetRingX() const { return m_TargetRing.x; }
|
inline float GetTargetRingX() const { return m_TargetRing.x; }
|
||||||
@ -543,6 +550,7 @@ public:
|
|||||||
virtual void GMMove(float x, float y, float z, float heading = 0.01, bool SendUpdate = true);
|
virtual void GMMove(float x, float y, float z, float heading = 0.01, bool SendUpdate = true);
|
||||||
void SetDelta(const glm::vec4& delta);
|
void SetDelta(const glm::vec4& delta);
|
||||||
void SetTargetDestSteps(uint8 target_steps) { tar_ndx = target_steps; }
|
void SetTargetDestSteps(uint8 target_steps) { tar_ndx = target_steps; }
|
||||||
|
void SendPositionUpdateToClient(Client *client);
|
||||||
void SendPositionUpdate(uint8 iSendToSelf = 0);
|
void SendPositionUpdate(uint8 iSendToSelf = 0);
|
||||||
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
|
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
|
||||||
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
|
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
|
||||||
@ -585,6 +593,7 @@ public:
|
|||||||
void AddFeignMemory(Client* attacker);
|
void AddFeignMemory(Client* attacker);
|
||||||
void RemoveFromFeignMemory(Client* attacker);
|
void RemoveFromFeignMemory(Client* attacker);
|
||||||
void ClearFeignMemory();
|
void ClearFeignMemory();
|
||||||
|
bool IsOnFeignMemory(Client *attacker) const;
|
||||||
void PrintHateListToClient(Client *who) { hate_list.PrintHateListToClient(who); }
|
void PrintHateListToClient(Client *who) { hate_list.PrintHateListToClient(who); }
|
||||||
std::list<struct_HateList*>& GetHateList() { return hate_list.GetHateList(); }
|
std::list<struct_HateList*>& GetHateList() { return hate_list.GetHateList(); }
|
||||||
bool CheckLosFN(Mob* other);
|
bool CheckLosFN(Mob* other);
|
||||||
@ -949,7 +958,9 @@ public:
|
|||||||
float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
|
float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||||
void SendTo(float new_x, float new_y, float new_z);
|
void SendTo(float new_x, float new_y, float new_z);
|
||||||
void SendToFixZ(float new_x, float new_y, float new_z);
|
void SendToFixZ(float new_x, float new_y, float new_z);
|
||||||
void FixZ();
|
float GetZOffset() const;
|
||||||
|
void FixZ(int32 z_find_offset = 5);
|
||||||
|
float GetFixedZ(glm::vec3 position, int32 z_find_offset = 5);
|
||||||
void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false);
|
void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false);
|
||||||
inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; }
|
inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; }
|
||||||
inline uint32 DontBuffMeBefore() const { return pDontBuffMeBefore; }
|
inline uint32 DontBuffMeBefore() const { return pDontBuffMeBefore; }
|
||||||
@ -1103,8 +1114,6 @@ public:
|
|||||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item);
|
int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item);
|
||||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr);
|
int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr);
|
||||||
|
|
||||||
float last_z;
|
|
||||||
|
|
||||||
// Bots HealRotation methods
|
// Bots HealRotation methods
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }
|
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }
|
||||||
@ -1221,7 +1230,8 @@ protected:
|
|||||||
glm::vec4 m_Position;
|
glm::vec4 m_Position;
|
||||||
/* Used to determine when an NPC has traversed so many units - to send a zone wide pos update */
|
/* Used to determine when an NPC has traversed so many units - to send a zone wide pos update */
|
||||||
glm::vec4 last_major_update_position;
|
glm::vec4 last_major_update_position;
|
||||||
uint16 animation;
|
|
||||||
|
int animation; // this is really what MQ2 calls SpeedRun just packed like (int)(SpeedRun * 40.0f)
|
||||||
float base_size;
|
float base_size;
|
||||||
float size;
|
float size;
|
||||||
float runspeed;
|
float runspeed;
|
||||||
@ -1262,6 +1272,7 @@ protected:
|
|||||||
virtual int16 GetFocusEffect(focusType type, uint16 spell_id) { return 0; }
|
virtual int16 GetFocusEffect(focusType type, uint16 spell_id) { return 0; }
|
||||||
void CalculateNewFearpoint();
|
void CalculateNewFearpoint();
|
||||||
float FindGroundZ(float new_x, float new_y, float z_offset=0.0);
|
float FindGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||||
|
float FindDestGroundZ(glm::vec3 dest, float z_offset=0.0);
|
||||||
glm::vec3 UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached);
|
glm::vec3 UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached);
|
||||||
void PrintRoute();
|
void PrintRoute();
|
||||||
|
|
||||||
|
|||||||
@ -57,7 +57,11 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
|||||||
if(AI_HasSpells() == false)
|
if(AI_HasSpells() == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (iChance < 100) {
|
// Rooted mobs were just standing around when tar out of range.
|
||||||
|
// Any sane mob would cast if they can.
|
||||||
|
bool cast_only_option = (IsRooted() && !CombatRange(tar));
|
||||||
|
|
||||||
|
if (!cast_only_option && iChance < 100) {
|
||||||
if (zone->random.Int(0, 100) >= iChance)
|
if (zone->random.Int(0, 100) >= iChance)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -123,7 +127,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
|||||||
}
|
}
|
||||||
case SpellType_Root: {
|
case SpellType_Root: {
|
||||||
Mob *rootee = GetHateRandom();
|
Mob *rootee = GetHateRandom();
|
||||||
if (rootee && !rootee->IsRooted() && zone->random.Roll(50)
|
if (rootee && !rootee->IsRooted() && !rootee->IsFeared() && zone->random.Roll(50)
|
||||||
&& rootee->DontRootMeBefore() < Timer::GetCurrentTime()
|
&& rootee->DontRootMeBefore() < Timer::GetCurrentTime()
|
||||||
&& rootee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
|
&& rootee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
|
||||||
) {
|
) {
|
||||||
@ -499,7 +503,7 @@ void NPC::AI_Start(uint32 iMoveDelay) {
|
|||||||
AIautocastspell_timer->Disable();
|
AIautocastspell_timer->Disable();
|
||||||
} else {
|
} else {
|
||||||
AIautocastspell_timer = std::unique_ptr<Timer>(new Timer(750));
|
AIautocastspell_timer = std::unique_ptr<Timer>(new Timer(750));
|
||||||
AIautocastspell_timer->Start(RandomTimer(0, 15000), false);
|
AIautocastspell_timer->Start(RandomTimer(0, 300), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NPCTypedata) {
|
if (NPCTypedata) {
|
||||||
@ -1001,10 +1005,9 @@ void Mob::AI_Process() {
|
|||||||
if (this->GetTarget()) {
|
if (this->GetTarget()) {
|
||||||
/* If we are engaged, moving and following client, let's look for best Z more often */
|
/* If we are engaged, moving and following client, let's look for best Z more often */
|
||||||
float target_distance = DistanceNoZ(this->GetPosition(), this->GetTarget()->GetPosition());
|
float target_distance = DistanceNoZ(this->GetPosition(), this->GetTarget()->GetPosition());
|
||||||
if (target_distance >= 25) {
|
|
||||||
this->FixZ();
|
this->FixZ();
|
||||||
}
|
|
||||||
else if (!this->CheckLosFN(this->GetTarget())) {
|
if (target_distance <= 15 && !this->CheckLosFN(this->GetTarget())) {
|
||||||
Mob* target = this->GetTarget();
|
Mob* target = this->GetTarget();
|
||||||
|
|
||||||
m_Position.x = target->GetX();
|
m_Position.x = target->GetX();
|
||||||
@ -1295,7 +1298,7 @@ void Mob::AI_Process() {
|
|||||||
if (AI_PursueCastCheck()) {
|
if (AI_PursueCastCheck()) {
|
||||||
//we did something, so do not process movement.
|
//we did something, so do not process movement.
|
||||||
}
|
}
|
||||||
else if (AI_movement_timer->Check())
|
else if (AI_movement_timer->Check() && target)
|
||||||
{
|
{
|
||||||
if (!IsRooted()) {
|
if (!IsRooted()) {
|
||||||
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName());
|
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName());
|
||||||
@ -1388,19 +1391,33 @@ void Mob::AI_Process() {
|
|||||||
//if(owner->IsClient())
|
//if(owner->IsClient())
|
||||||
// printf("Pet start pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ());
|
// printf("Pet start pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ());
|
||||||
|
|
||||||
float dist = DistanceSquared(m_Position, owner->GetPosition());
|
glm::vec4 ownerPos = owner->GetPosition();
|
||||||
if (dist >= 400)
|
float dist = DistanceSquared(m_Position, ownerPos);
|
||||||
|
float distz = ownerPos.z - m_Position.z;
|
||||||
|
|
||||||
|
if (dist >= 400 || distz > 100)
|
||||||
{
|
{
|
||||||
int speed = GetWalkspeed();
|
int speed = GetWalkspeed();
|
||||||
if (dist >= 5625)
|
if (dist >= 5625)
|
||||||
speed = GetRunspeed();
|
speed = GetRunspeed();
|
||||||
|
|
||||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
if (distz > 100)
|
||||||
|
{
|
||||||
|
m_Position = ownerPos;
|
||||||
|
SendPositionUpdate();
|
||||||
|
moved = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CalculateNewPosition2(owner->GetX(),
|
||||||
|
owner->GetY(), owner->GetZ(), speed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(moved)
|
if(moved)
|
||||||
{
|
{
|
||||||
|
this->FixZ();
|
||||||
SetCurrentSpeed(0);
|
SetCurrentSpeed(0);
|
||||||
moved = false;
|
moved = false;
|
||||||
}
|
}
|
||||||
@ -1532,16 +1549,17 @@ void NPC::AI_DoMovement() {
|
|||||||
roambox_movingto_x = zone->random.Real(roambox_min_x+1,roambox_max_x-1);
|
roambox_movingto_x = zone->random.Real(roambox_min_x+1,roambox_max_x-1);
|
||||||
if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y)
|
if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y)
|
||||||
roambox_movingto_y = zone->random.Real(roambox_min_y+1,roambox_max_y-1);
|
roambox_movingto_y = zone->random.Real(roambox_min_y+1,roambox_max_y-1);
|
||||||
|
Log(Logs::Detail, Logs::AI,
|
||||||
|
"Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)",
|
||||||
|
roambox_distance, roambox_min_x, roambox_max_x, roambox_min_y,
|
||||||
|
roambox_max_y, roambox_movingto_x, roambox_movingto_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(Logs::Detail, Logs::AI, "Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)",
|
// Keep calling with updates, using wherever we are in Z.
|
||||||
roambox_distance, roambox_min_x, roambox_max_x, roambox_min_y, roambox_max_y, roambox_movingto_x, roambox_movingto_y);
|
if (!MakeNewPositionAndSendUpdate(roambox_movingto_x,
|
||||||
|
roambox_movingto_y, m_Position.z, walksp))
|
||||||
float new_z = this->FindGroundZ(m_Position.x, m_Position.y, 5);
|
|
||||||
new_z += (this->GetSize() / 1.55);
|
|
||||||
|
|
||||||
if (!CalculateNewPosition2(roambox_movingto_x, roambox_movingto_y, new_z, walksp, true))
|
|
||||||
{
|
{
|
||||||
|
this->FixZ(); // FixZ on final arrival point.
|
||||||
roambox_movingto_x = roambox_max_x + 1; // force update
|
roambox_movingto_x = roambox_max_x + 1; // force update
|
||||||
pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay);
|
pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay);
|
||||||
SetMoving(false);
|
SetMoving(false);
|
||||||
@ -1578,18 +1596,22 @@ void NPC::AI_DoMovement() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->FixZ();
|
this->FixZ();
|
||||||
|
|
||||||
SendPosition();
|
SendPosition();
|
||||||
|
|
||||||
//kick off event_waypoint arrive
|
//kick off event_waypoint arrive
|
||||||
char temp[16];
|
char temp[16];
|
||||||
sprintf(temp, "%d", cur_wp);
|
sprintf(temp, "%d", cur_wp);
|
||||||
parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0);
|
parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0);
|
||||||
// start moving directly to next waypoint if we're at a 0 pause waypoint and we didn't get quest halted.
|
// No need to move as we are there. Next loop will
|
||||||
if (!AI_walking_timer->Enabled())
|
// take care of normal grids, even at pause 0.
|
||||||
AI_SetupNextWaypoint();
|
// We do need to call and setup a wp if we're cur_wp=-2
|
||||||
else
|
// as that is where roamer is unset and we don't want
|
||||||
|
// the next trip through to move again based on grid stuff.
|
||||||
doMove = false;
|
doMove = false;
|
||||||
|
if (cur_wp == -2) {
|
||||||
|
AI_SetupNextWaypoint();
|
||||||
|
}
|
||||||
|
|
||||||
// wipe feign memory since we reached our first waypoint
|
// wipe feign memory since we reached our first waypoint
|
||||||
if(cur_wp == 1)
|
if(cur_wp == 1)
|
||||||
ClearFeignMemory();
|
ClearFeignMemory();
|
||||||
@ -2589,7 +2611,7 @@ void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType,
|
|||||||
|
|
||||||
// If we're going from an empty list, we need to start the timer
|
// If we're going from an empty list, we need to start the timer
|
||||||
if (AIspells.size() == 1)
|
if (AIspells.size() == 1)
|
||||||
AIautocastspell_timer->Start(RandomTimer(0, 15000), false);
|
AIautocastspell_timer->Start(RandomTimer(0, 300), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::RemoveSpellFromNPCList(int16 spell_id)
|
void NPC::RemoveSpellFromNPCList(int16 spell_id)
|
||||||
|
|||||||
@ -542,9 +542,11 @@ int main(int argc, char** argv) {
|
|||||||
process_timer.Stop();
|
process_timer.Stop();
|
||||||
process_timer.Start(1000, true);
|
process_timer.Start(1000, true);
|
||||||
|
|
||||||
|
if (zone && zone->GetZoneID() && zone->GetInstanceVersion()) {
|
||||||
uint32 shutdown_timer = database.getZoneShutDownDelay(zone->GetZoneID(), zone->GetInstanceVersion());
|
uint32 shutdown_timer = database.getZoneShutDownDelay(zone->GetZoneID(), zone->GetInstanceVersion());
|
||||||
zone->StartShutdownTimer(shutdown_timer);
|
zone->StartShutdownTimer(shutdown_timer);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (!previous_loaded && current_loaded) {
|
else if (!previous_loaded && current_loaded) {
|
||||||
process_timer.Stop();
|
process_timer.Stop();
|
||||||
process_timer.Start(32, true);
|
process_timer.Start(32, true);
|
||||||
|
|||||||
20
zone/npc.cpp
20
zone/npc.cpp
@ -436,6 +436,26 @@ void NPC::SetTarget(Mob* mob) {
|
|||||||
//attack_timer.Disable();
|
//attack_timer.Disable();
|
||||||
attack_dw_timer.Disable();
|
attack_dw_timer.Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// either normal pet and owner is client or charmed pet and owner is client
|
||||||
|
Mob *owner = nullptr;
|
||||||
|
if (IsPet() && IsPetOwnerClient()) {
|
||||||
|
owner = GetOwner();
|
||||||
|
} else if (IsCharmed()) {
|
||||||
|
owner = GetOwner();
|
||||||
|
if (owner && !owner->IsClient())
|
||||||
|
owner = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (owner) {
|
||||||
|
auto client = owner->CastToClient();
|
||||||
|
if (client->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) {
|
||||||
|
auto app = new EQApplicationPacket(OP_PetHoTT, sizeof(ClientTarget_Struct));
|
||||||
|
auto ct = (ClientTarget_Struct *)app->pBuffer;
|
||||||
|
ct->new_target = mob ? mob->GetID() : 0;
|
||||||
|
client->FastQueuePacket(&app);
|
||||||
|
}
|
||||||
|
}
|
||||||
Mob::SetTarget(mob);
|
Mob::SetTarget(mob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -70,7 +70,7 @@ Object::Object(uint32 id, uint32 type, uint32 icon, const Object_Struct& object,
|
|||||||
|
|
||||||
//creating a re-ocurring ground spawn.
|
//creating a re-ocurring ground spawn.
|
||||||
Object::Object(const EQEmu::ItemInstance* inst, char* name,float max_x,float min_x,float max_y,float min_y,float z,float heading,uint32 respawntimer)
|
Object::Object(const EQEmu::ItemInstance* inst, char* name,float max_x,float min_x,float max_y,float min_y,float z,float heading,uint32 respawntimer)
|
||||||
: respawn_timer(respawntimer), decay_timer(300000)
|
: respawn_timer(respawntimer * 1000), decay_timer(300000)
|
||||||
{
|
{
|
||||||
|
|
||||||
user = nullptr;
|
user = nullptr;
|
||||||
|
|||||||
@ -475,22 +475,6 @@ Pet::Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 po
|
|||||||
// Class should use npc constructor to set light properties
|
// Class should use npc constructor to set light properties
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pet::SetTarget(Mob *mob)
|
|
||||||
{
|
|
||||||
if (mob == GetTarget())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto owner = GetOwner();
|
|
||||||
if (owner && owner->IsClient() && owner->CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) {
|
|
||||||
auto app = new EQApplicationPacket(OP_PetHoTT, sizeof(ClientTarget_Struct));
|
|
||||||
auto ct = (ClientTarget_Struct *)app->pBuffer;
|
|
||||||
ct->new_target = mob ? mob->GetID() : 0;
|
|
||||||
owner->CastToClient()->QueuePacket(app);
|
|
||||||
safe_delete(app);
|
|
||||||
}
|
|
||||||
NPC::SetTarget(mob);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZoneDatabase::GetPetEntry(const char *pet_type, PetRecord *into) {
|
bool ZoneDatabase::GetPetEntry(const char *pet_type, PetRecord *into) {
|
||||||
return GetPoweredPetEntry(pet_type, 0, into);
|
return GetPoweredPetEntry(pet_type, 0, into);
|
||||||
}
|
}
|
||||||
@ -671,13 +655,18 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const EQEmu::ItemData* item2 = database.GetItem(items[i]);
|
const EQEmu::ItemData* item2 = database.GetItem(items[i]);
|
||||||
if (item2 && item2->NoDrop != 0) {
|
|
||||||
//dont bother saving item charges for now, NPCs never use them
|
if (item2) {
|
||||||
//and nobody should be able to get them off the corpse..?
|
bool noDrop=(item2->NoDrop == 0); // Field is reverse logic
|
||||||
|
bool petCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) &&
|
||||||
|
_CLIENTPET(this) && GetPetType() <= petOther);
|
||||||
|
|
||||||
|
if (!noDrop || petCanHaveNoDrop) {
|
||||||
AddLootDrop(item2, &itemlist, 0, 1, 255, true, true);
|
AddLootDrop(item2, &itemlist, 0, 1, 255, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load the equipmentset from the DB. Might be worthwhile to load these into
|
// Load the equipmentset from the DB. Might be worthwhile to load these into
|
||||||
// shared memory at some point due to the number of queries needed to load a
|
// shared memory at some point due to the number of queries needed to load a
|
||||||
|
|||||||
@ -7,7 +7,6 @@ struct NPCType;
|
|||||||
class Pet : public NPC {
|
class Pet : public NPC {
|
||||||
public:
|
public:
|
||||||
Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 power);
|
Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 power);
|
||||||
virtual void SetTarget(Mob *mob);
|
|
||||||
virtual bool CheckSpellLevelRestriction(uint16 spell_id);
|
virtual bool CheckSpellLevelRestriction(uint16 spell_id);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -149,7 +149,7 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
|||||||
raid_update = c->GetRaid();
|
raid_update = c->GetRaid();
|
||||||
if (raid_update) {
|
if (raid_update) {
|
||||||
raid_update->SendHPManaEndPacketsTo(c);
|
raid_update->SendHPManaEndPacketsTo(c);
|
||||||
raid_update->SendHPPacketsFrom(c);
|
raid_update->SendHPManaEndPacketsFrom(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct));
|
auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct));
|
||||||
@ -323,6 +323,10 @@ void Raid::SaveRaidLeaderAA()
|
|||||||
|
|
||||||
void Raid::UpdateGroupAAs(uint32 gid)
|
void Raid::UpdateGroupAAs(uint32 gid)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (gid < 0 || gid > MAX_RAID_GROUPS)
|
||||||
|
return;
|
||||||
|
|
||||||
Client *gl = GetGroupLeader(gid);
|
Client *gl = GetGroupLeader(gid);
|
||||||
|
|
||||||
if (gl)
|
if (gl)
|
||||||
@ -1591,7 +1595,7 @@ void Raid::SendHPManaEndPacketsTo(Client *client)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Raid::SendHPPacketsFrom(Mob *mob)
|
void Raid::SendHPManaEndPacketsFrom(Mob *mob)
|
||||||
{
|
{
|
||||||
if(!mob)
|
if(!mob)
|
||||||
return;
|
return;
|
||||||
@ -1779,3 +1783,42 @@ void Raid::SetDirtyAutoHaters()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/, bool group_only /*= true*/) {
|
||||||
|
if (sender && sender->IsClient()) {
|
||||||
|
|
||||||
|
uint32 group_id = this->GetGroup(sender->CastToClient());
|
||||||
|
|
||||||
|
/* If this is a group only packet and we're not in a group -- return */
|
||||||
|
if (!group_id == 0xFFFFFFFF && group_only)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) {
|
||||||
|
if (!members[i].member)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!members[i].member->IsClient())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ignore_sender && members[i].member == sender)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (group_only && members[i].GroupNumber != group_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If we don't have a distance requirement - send to all members */
|
||||||
|
if (distance == 0) {
|
||||||
|
members[i].member->CastToClient()->QueuePacket(app, ack_required);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* If negative distance - we check if current distance is greater than X */
|
||||||
|
if (distance <= 0 && DistanceSquared(sender->GetPosition(), members[i].member->GetPosition()) >= (distance * distance)) {
|
||||||
|
members[i].member->CastToClient()->QueuePacket(app, ack_required);
|
||||||
|
}
|
||||||
|
/* If positive distance - we check if current distance is less than X */
|
||||||
|
else if (distance >= 0 && DistanceSquared(sender->GetPosition(), members[i].member->GetPosition()) <= (distance * distance)) {
|
||||||
|
members[i].member->CastToClient()->QueuePacket(app, ack_required);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -174,7 +174,7 @@ public:
|
|||||||
void VerifyRaid();
|
void VerifyRaid();
|
||||||
void MemberZoned(Client *c);
|
void MemberZoned(Client *c);
|
||||||
void SendHPManaEndPacketsTo(Client *c);
|
void SendHPManaEndPacketsTo(Client *c);
|
||||||
void SendHPPacketsFrom(Mob *mob);
|
void SendHPManaEndPacketsFrom(Mob *mob);
|
||||||
void SendManaPacketFrom(Mob *mob);
|
void SendManaPacketFrom(Mob *mob);
|
||||||
void SendEndurancePacketFrom(Mob *mob);
|
void SendEndurancePacketFrom(Mob *mob);
|
||||||
void RaidSay(const char *msg, Client *c);
|
void RaidSay(const char *msg, Client *c);
|
||||||
@ -237,6 +237,8 @@ public:
|
|||||||
void SetDirtyAutoHaters();
|
void SetDirtyAutoHaters();
|
||||||
inline XTargetAutoHaters *GetXTargetAutoMgr() { return &m_autohatermgr; }
|
inline XTargetAutoHaters *GetXTargetAutoMgr() { return &m_autohatermgr; }
|
||||||
|
|
||||||
|
void QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required = true, bool ignore_sender = true, float distance = 0, bool group_only = true);
|
||||||
|
|
||||||
RaidMember members[MAX_RAID_MEMBERS];
|
RaidMember members[MAX_RAID_MEMBERS];
|
||||||
char leadername[64];
|
char leadername[64];
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@ -37,6 +37,7 @@ int Mob::GetBaseSkillDamage(EQEmu::skills::SkillType skill, Mob *target)
|
|||||||
case EQEmu::skills::SkillDragonPunch:
|
case EQEmu::skills::SkillDragonPunch:
|
||||||
case EQEmu::skills::SkillEagleStrike:
|
case EQEmu::skills::SkillEagleStrike:
|
||||||
case EQEmu::skills::SkillTigerClaw:
|
case EQEmu::skills::SkillTigerClaw:
|
||||||
|
case EQEmu::skills::SkillRoundKick:
|
||||||
if (skill_level >= 25)
|
if (skill_level >= 25)
|
||||||
base++;
|
base++;
|
||||||
if (skill_level >= 75)
|
if (skill_level >= 75)
|
||||||
|
|||||||
@ -60,6 +60,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
|
|
||||||
const SPDat_Spell_Struct &spell = spells[spell_id];
|
const SPDat_Spell_Struct &spell = spells[spell_id];
|
||||||
|
|
||||||
|
if (spell.disallow_sit && IsBuffSpell(spell_id) && IsClient() && (CastToClient()->IsSitting() || CastToClient()->GetHorseId() != 0))
|
||||||
|
return false;
|
||||||
|
|
||||||
bool c_override = false;
|
bool c_override = false;
|
||||||
if (caster && caster->IsClient() && GetCastedSpellInvSlot() > 0) {
|
if (caster && caster->IsClient() && GetCastedSpellInvSlot() > 0) {
|
||||||
const EQEmu::ItemInstance *inst = caster->CastToClient()->GetInv().GetItem(GetCastedSpellInvSlot());
|
const EQEmu::ItemInstance *inst = caster->CastToClient()->GetInv().GetItem(GetCastedSpellInvSlot());
|
||||||
@ -134,6 +137,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
buffs[buffslot].magic_rune = 0;
|
buffs[buffslot].magic_rune = 0;
|
||||||
buffs[buffslot].numhits = 0;
|
buffs[buffslot].numhits = 0;
|
||||||
|
|
||||||
|
if (spells[spell_id].numhits > 0) {
|
||||||
|
|
||||||
|
int numhit = spells[spell_id].numhits;
|
||||||
|
|
||||||
|
numhit += numhit * caster->GetFocusEffect(focusFcLimitUse, spell_id) / 100;
|
||||||
|
numhit += caster->GetFocusEffect(focusIncreaseNumHits, spell_id);
|
||||||
|
buffs[buffslot].numhits = numhit;
|
||||||
|
}
|
||||||
|
|
||||||
if (spells[spell_id].EndurUpkeep > 0)
|
if (spells[spell_id].EndurUpkeep > 0)
|
||||||
SetEndurUpkeep(true);
|
SetEndurUpkeep(true);
|
||||||
|
|
||||||
@ -181,14 +193,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(spells[spell_id].numhits > 0 && buffslot >= 0){
|
|
||||||
|
|
||||||
int numhit = spells[spell_id].numhits;
|
|
||||||
|
|
||||||
numhit += numhit*caster->GetFocusEffect(focusFcLimitUse, spell_id)/100;
|
|
||||||
numhit += caster->GetFocusEffect(focusIncreaseNumHits, spell_id);
|
|
||||||
buffs[buffslot].numhits = numhit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsPowerDistModSpell(spell_id))
|
if (!IsPowerDistModSpell(spell_id))
|
||||||
SetSpellPowerDistanceMod(0);
|
SetSpellPowerDistanceMod(0);
|
||||||
@ -277,8 +281,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
caster->SetMana(0);
|
caster->SetMana(0);
|
||||||
} else if (spell_id == 2755 && caster) //Lifeburn
|
} else if (spell_id == 2755 && caster) //Lifeburn
|
||||||
{
|
{
|
||||||
dmg = -1 * caster->GetHP(); // just your current HP or should it be Max HP?
|
dmg = caster->GetHP(); // just your current HP
|
||||||
caster->SetHP(dmg / 4); // 2003 patch notes say ~ 1/4 HP. Should this be 1/4 your current HP or do 3/4 max HP dmg? Can it kill you?
|
caster->SetHP(dmg / 4); // 2003 patch notes say ~ 1/4 HP. Should this be 1/4 your current HP or do 3/4 max HP dmg? Can it kill you?
|
||||||
|
dmg = -dmg;
|
||||||
}
|
}
|
||||||
|
|
||||||
//do any AAs apply to these spells?
|
//do any AAs apply to these spells?
|
||||||
@ -1791,8 +1796,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
Message_StringID(4, CORPSE_CANT_SENSE);
|
Message_StringID(4, CORPSE_CANT_SENSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (caster)
|
else if (caster) {
|
||||||
caster->Message_StringID(MT_SpellFailure, SPELL_LEVEL_REQ);
|
char level[4];
|
||||||
|
ConvertArray(effect_value, level);
|
||||||
|
caster->Message_StringID(MT_SpellFailure,
|
||||||
|
SPELL_LEVEL_REQ, level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Message_StringID(4, TARGET_NOT_FOUND);
|
Message_StringID(4, TARGET_NOT_FOUND);
|
||||||
@ -3655,16 +3664,6 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SE_Hunger: {
|
|
||||||
// this procedure gets called 7 times for every once that the stamina update occurs so we add
|
|
||||||
// 1/7 of the subtraction.
|
|
||||||
// It's far from perfect, but works without any unnecessary buff checks to bog down the server.
|
|
||||||
if (IsClient()) {
|
|
||||||
CastToClient()->m_pp.hunger_level += 5;
|
|
||||||
CastToClient()->m_pp.thirst_level += 5;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_Invisibility:
|
case SE_Invisibility:
|
||||||
case SE_InvisVsAnimals:
|
case SE_InvisVsAnimals:
|
||||||
case SE_InvisVsUndead: {
|
case SE_InvisVsUndead: {
|
||||||
|
|||||||
154
zone/spells.cpp
154
zone/spells.cpp
@ -1427,8 +1427,10 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
|||||||
ZeroCastingVars();
|
ZeroCastingVars();
|
||||||
|
|
||||||
// set the rapid recast timer for next time around
|
// set the rapid recast timer for next time around
|
||||||
|
// Why do we have this? It mostly just causes issues when things are working correctly
|
||||||
|
// It also needs to be <users's ping to not cause issues
|
||||||
delaytimer = true;
|
delaytimer = true;
|
||||||
spellend_timer.Start(400,true);
|
spellend_timer.Start(10, true);
|
||||||
|
|
||||||
Log(Logs::Detail, Logs::Spells, "Spell casting of %d is finished.", spell_id);
|
Log(Logs::Detail, Logs::Spells, "Spell casting of %d is finished.", spell_id);
|
||||||
|
|
||||||
@ -3188,6 +3190,12 @@ uint32 Client::GetLastBuffSlot(bool disc, bool song)
|
|||||||
return GetCurrentBuffSlots();
|
return GetCurrentBuffSlots();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mob::HasDiscBuff()
|
||||||
|
{
|
||||||
|
int slot = GetFirstBuffSlot(true, false);
|
||||||
|
return buffs[slot].spellid != SPELL_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
// returns the slot the buff was added to, -1 if it wasn't added due to
|
// returns the slot the buff was added to, -1 if it wasn't added due to
|
||||||
// stacking problems, and -2 if this is not a buff
|
// stacking problems, and -2 if this is not a buff
|
||||||
// if caster is null, the buff will be added with the caster level being
|
// if caster is null, the buff will be added with the caster level being
|
||||||
@ -3307,8 +3315,8 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
|
|
||||||
buffs[emptyslot].spellid = spell_id;
|
buffs[emptyslot].spellid = spell_id;
|
||||||
buffs[emptyslot].casterlevel = caster_level;
|
buffs[emptyslot].casterlevel = caster_level;
|
||||||
if (caster && caster->IsClient())
|
if (caster && !caster->IsAura()) // maybe some other things we don't want to ...
|
||||||
strcpy(buffs[emptyslot].caster_name, caster->GetName());
|
strcpy(buffs[emptyslot].caster_name, caster->GetCleanName());
|
||||||
else
|
else
|
||||||
memset(buffs[emptyslot].caster_name, 0, 64);
|
memset(buffs[emptyslot].caster_name, 0, 64);
|
||||||
buffs[emptyslot].casterid = caster ? caster->GetID() : 0;
|
buffs[emptyslot].casterid = caster ? caster->GetID() : 0;
|
||||||
@ -4232,6 +4240,19 @@ bool Mob::IsAffectedByBuff(uint16 spell_id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mob::IsAffectedByBuffByGlobalGroup(GlobalGroup group)
|
||||||
|
{
|
||||||
|
int buff_count = GetMaxTotalSlots();
|
||||||
|
for (int i = 0; i < buff_count; ++i) {
|
||||||
|
if (buffs[i].spellid == SPELL_UNKNOWN)
|
||||||
|
continue;
|
||||||
|
if (spells[buffs[i].spellid].spell_category == static_cast<int>(group))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// checks if 'this' can be affected by spell_id from caster
|
// checks if 'this' can be affected by spell_id from caster
|
||||||
// returns true if the spell should fail, false otherwise
|
// returns true if the spell should fail, false otherwise
|
||||||
bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
||||||
@ -4416,6 +4437,36 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Mob::GetResist(uint8 resist_type)
|
||||||
|
{
|
||||||
|
switch(resist_type)
|
||||||
|
{
|
||||||
|
case RESIST_FIRE:
|
||||||
|
return GetFR();
|
||||||
|
case RESIST_COLD:
|
||||||
|
return GetCR();
|
||||||
|
case RESIST_MAGIC:
|
||||||
|
return GetMR();
|
||||||
|
case RESIST_DISEASE:
|
||||||
|
return GetDR();
|
||||||
|
case RESIST_POISON:
|
||||||
|
return GetPR();
|
||||||
|
case RESIST_CORRUPTION:
|
||||||
|
return GetCorrup();
|
||||||
|
case RESIST_PRISMATIC:
|
||||||
|
return (GetFR() + GetCR() + GetMR() + GetDR() + GetPR()) / 5;
|
||||||
|
case RESIST_CHROMATIC:
|
||||||
|
return std::min({GetFR(), GetCR(), GetMR(), GetDR(), GetPR()});
|
||||||
|
case RESIST_PHYSICAL:
|
||||||
|
if (IsNPC())
|
||||||
|
return GetPhR();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Spell resists:
|
// Spell resists:
|
||||||
// returns an effectiveness index from 0 to 100. for most spells, 100 means
|
// returns an effectiveness index from 0 to 100. for most spells, 100 means
|
||||||
@ -4499,68 +4550,16 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
|||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
int target_resist;
|
int target_resist = GetResist(resist_type);
|
||||||
switch(resist_type)
|
|
||||||
{
|
|
||||||
case RESIST_FIRE:
|
|
||||||
target_resist = GetFR();
|
|
||||||
break;
|
|
||||||
case RESIST_COLD:
|
|
||||||
target_resist = GetCR();
|
|
||||||
break;
|
|
||||||
case RESIST_MAGIC:
|
|
||||||
target_resist = GetMR();
|
|
||||||
break;
|
|
||||||
case RESIST_DISEASE:
|
|
||||||
target_resist = GetDR();
|
|
||||||
break;
|
|
||||||
case RESIST_POISON:
|
|
||||||
target_resist = GetPR();
|
|
||||||
break;
|
|
||||||
case RESIST_CORRUPTION:
|
|
||||||
target_resist = GetCorrup();
|
|
||||||
break;
|
|
||||||
case RESIST_PRISMATIC:
|
|
||||||
target_resist = (GetFR() + GetCR() + GetMR() + GetDR() + GetPR()) / 5;
|
|
||||||
break;
|
|
||||||
case RESIST_CHROMATIC:
|
|
||||||
{
|
|
||||||
target_resist = GetFR();
|
|
||||||
int temp = GetCR();
|
|
||||||
if(temp < target_resist)
|
|
||||||
{
|
|
||||||
target_resist = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
temp = GetMR();
|
// JULY 24, 2002 changes
|
||||||
if(temp < target_resist)
|
int level = GetLevel();
|
||||||
{
|
if (IsPetOwnerClient() && caster->IsNPC() && !caster->IsPetOwnerClient()) {
|
||||||
target_resist = temp;
|
auto owner = GetOwner();
|
||||||
|
if (owner != nullptr) {
|
||||||
|
target_resist = std::max(target_resist, owner->GetResist(resist_type));
|
||||||
|
level = owner->GetLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
temp = GetDR();
|
|
||||||
if(temp < target_resist)
|
|
||||||
{
|
|
||||||
target_resist = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
temp = GetPR();
|
|
||||||
if(temp < target_resist)
|
|
||||||
{
|
|
||||||
target_resist = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RESIST_PHYSICAL:
|
|
||||||
{
|
|
||||||
if (IsNPC())
|
|
||||||
target_resist = GetPhR();
|
|
||||||
else
|
|
||||||
target_resist = 0;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
|
|
||||||
target_resist = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Setup our base resist chance.
|
//Setup our base resist chance.
|
||||||
@ -4569,7 +4568,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
|||||||
|
|
||||||
//Adjust our resist chance based on level modifiers
|
//Adjust our resist chance based on level modifiers
|
||||||
uint8 caster_level = level_override > 0 ? level_override : caster->GetLevel();
|
uint8 caster_level = level_override > 0 ? level_override : caster->GetLevel();
|
||||||
int temp_level_diff = GetLevel() - caster_level;
|
int temp_level_diff = level - caster_level;
|
||||||
|
|
||||||
//Physical Resists are calclated using their own formula derived from extensive parsing.
|
//Physical Resists are calclated using their own formula derived from extensive parsing.
|
||||||
if (resist_type == RESIST_PHYSICAL) {
|
if (resist_type == RESIST_PHYSICAL) {
|
||||||
@ -4578,7 +4577,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
|||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
||||||
if(IsNPC() && GetLevel() >= RuleI(Casting,ResistFalloff))
|
if(IsNPC() && level >= RuleI(Casting,ResistFalloff))
|
||||||
{
|
{
|
||||||
int a = (RuleI(Casting,ResistFalloff)-1) - caster_level;
|
int a = (RuleI(Casting,ResistFalloff)-1) - caster_level;
|
||||||
if(a > 0)
|
if(a > 0)
|
||||||
@ -4591,7 +4590,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsClient() && GetLevel() >= 21 && temp_level_diff > 15)
|
if(IsClient() && level >= 21 && temp_level_diff > 15)
|
||||||
{
|
{
|
||||||
temp_level_diff = 15;
|
temp_level_diff = 15;
|
||||||
}
|
}
|
||||||
@ -4607,16 +4606,16 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
|||||||
level_mod = -level_mod;
|
level_mod = -level_mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsNPC() && (caster_level - GetLevel()) < -20)
|
if(IsNPC() && (caster_level - level) < -20)
|
||||||
{
|
{
|
||||||
level_mod = 1000;
|
level_mod = 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Even more level stuff this time dealing with damage spells
|
//Even more level stuff this time dealing with damage spells
|
||||||
if(IsNPC() && IsDamageSpell(spell_id) && GetLevel() >= 17)
|
if(IsNPC() && IsDamageSpell(spell_id) && level >= 17)
|
||||||
{
|
{
|
||||||
int level_diff;
|
int level_diff;
|
||||||
if(GetLevel() >= RuleI(Casting,ResistFalloff))
|
if(level >= RuleI(Casting,ResistFalloff))
|
||||||
{
|
{
|
||||||
level_diff = (RuleI(Casting,ResistFalloff)-1) - caster_level;
|
level_diff = (RuleI(Casting,ResistFalloff)-1) - caster_level;
|
||||||
if(level_diff < 0)
|
if(level_diff < 0)
|
||||||
@ -4626,7 +4625,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
level_diff = GetLevel() - caster_level;
|
level_diff = level - caster_level;
|
||||||
}
|
}
|
||||||
level_mod += (2 * level_diff);
|
level_mod += (2 * level_diff);
|
||||||
}
|
}
|
||||||
@ -4737,17 +4736,17 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
|||||||
|
|
||||||
if(IsNPC())
|
if(IsNPC())
|
||||||
{
|
{
|
||||||
if(GetLevel() > caster_level && GetLevel() >= 17 && caster_level <= 50)
|
if(level > caster_level && level >= 17 && caster_level <= 50)
|
||||||
{
|
{
|
||||||
partial_modifier += 5;
|
partial_modifier += 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetLevel() >= 30 && caster_level < 50)
|
if(level >= 30 && caster_level < 50)
|
||||||
{
|
{
|
||||||
partial_modifier += (caster_level - 25);
|
partial_modifier += (caster_level - 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetLevel() < 15)
|
if(level < 15)
|
||||||
{
|
{
|
||||||
partial_modifier -= 5;
|
partial_modifier -= 5;
|
||||||
}
|
}
|
||||||
@ -4755,9 +4754,9 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
|||||||
|
|
||||||
if(caster->IsNPC())
|
if(caster->IsNPC())
|
||||||
{
|
{
|
||||||
if((GetLevel() - caster_level) >= 20)
|
if((level - caster_level) >= 20)
|
||||||
{
|
{
|
||||||
partial_modifier += (GetLevel() - caster_level) * 1.5;
|
partial_modifier += (level - caster_level) * 1.5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5533,6 +5532,8 @@ void Client::SendBuffNumHitPacket(Buffs_Struct &buff, int slot)
|
|||||||
bi->entries[0].spell_id = buff.spellid;
|
bi->entries[0].spell_id = buff.spellid;
|
||||||
bi->entries[0].tics_remaining = buff.ticsremaining;
|
bi->entries[0].tics_remaining = buff.ticsremaining;
|
||||||
bi->entries[0].num_hits = buff.numhits;
|
bi->entries[0].num_hits = buff.numhits;
|
||||||
|
strn0cpy(bi->entries[0].caster, buff.caster_name, 64);
|
||||||
|
bi->name_lengths = strlen(bi->entries[0].caster);
|
||||||
FastQueuePacket(&outapp);
|
FastQueuePacket(&outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5618,6 +5619,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
|
|||||||
else
|
else
|
||||||
buff->type = 0;
|
buff->type = 0;
|
||||||
|
|
||||||
|
buff->name_lengths = 0; // hacky shit
|
||||||
uint32 index = 0;
|
uint32 index = 0;
|
||||||
for(int i = 0; i < buff_count; ++i)
|
for(int i = 0; i < buff_count; ++i)
|
||||||
{
|
{
|
||||||
@ -5627,6 +5629,8 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
|
|||||||
buff->entries[index].spell_id = buffs[i].spellid;
|
buff->entries[index].spell_id = buffs[i].spellid;
|
||||||
buff->entries[index].tics_remaining = buffs[i].ticsremaining;
|
buff->entries[index].tics_remaining = buffs[i].ticsremaining;
|
||||||
buff->entries[index].num_hits = buffs[i].numhits;
|
buff->entries[index].num_hits = buffs[i].numhits;
|
||||||
|
strn0cpy(buff->entries[index].caster, buffs[i].caster_name, 64);
|
||||||
|
buff->name_lengths += strlen(buff->entries[index].caster);
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
#define PROC_TOOLOW 126 //Your will is not sufficient to command this weapon.
|
#define PROC_TOOLOW 126 //Your will is not sufficient to command this weapon.
|
||||||
#define PROC_PETTOOLOW 127 //Your pet's will is not sufficient to command its weapon.
|
#define PROC_PETTOOLOW 127 //Your pet's will is not sufficient to command its weapon.
|
||||||
#define YOU_FLURRY 128 //You unleash a flurry of attacks.
|
#define YOU_FLURRY 128 //You unleash a flurry of attacks.
|
||||||
|
#define FAILED_DISARM_TRAP 129 //You failed to disarm the trap.
|
||||||
#define DOORS_LOCKED 130 //It's locked and you're not holding the key.
|
#define DOORS_LOCKED 130 //It's locked and you're not holding the key.
|
||||||
#define DOORS_CANT_PICK 131 //This lock cannot be picked.
|
#define DOORS_CANT_PICK 131 //This lock cannot be picked.
|
||||||
#define DOORS_INSUFFICIENT_SKILL 132 //You are not sufficiently skilled to pick this lock.
|
#define DOORS_INSUFFICIENT_SKILL 132 //You are not sufficiently skilled to pick this lock.
|
||||||
@ -98,6 +99,7 @@
|
|||||||
#define DUP_LORE 290 //Duplicate lore items are not allowed.
|
#define DUP_LORE 290 //Duplicate lore items are not allowed.
|
||||||
#define TGB_ON 293 //Target other group buff is *ON*.
|
#define TGB_ON 293 //Target other group buff is *ON*.
|
||||||
#define TGB_OFF 294 //Target other group buff is *OFF*.
|
#define TGB_OFF 294 //Target other group buff is *OFF*.
|
||||||
|
#define DISARMED_TRAP 305 //You have disarmed the trap.
|
||||||
#define LDON_SENSE_TRAP1 306 //You do not Sense any traps.
|
#define LDON_SENSE_TRAP1 306 //You do not Sense any traps.
|
||||||
#define TRADESKILL_NOCOMBINE 334 //You cannot combine these items in this container type!
|
#define TRADESKILL_NOCOMBINE 334 //You cannot combine these items in this container type!
|
||||||
#define TRADESKILL_FAILED 336 //You lacked the skills to fashion the items together.
|
#define TRADESKILL_FAILED 336 //You lacked the skills to fashion the items together.
|
||||||
@ -114,6 +116,8 @@
|
|||||||
#define MEND_WORSEN 351 //You have worsened your wounds!
|
#define MEND_WORSEN 351 //You have worsened your wounds!
|
||||||
#define MEND_FAIL 352 //You have failed to mend your wounds.
|
#define MEND_FAIL 352 //You have failed to mend your wounds.
|
||||||
#define LDON_SENSE_TRAP2 367 //You have not detected any traps.
|
#define LDON_SENSE_TRAP2 367 //You have not detected any traps.
|
||||||
|
#define TRAP_TOO_FAR 368 //You are too far away from that trap to affect it.
|
||||||
|
#define FAIL_DISARM_DETECTED_TRAP 370 //You fail to disarm the detected trap.
|
||||||
#define LOOT_LORE_ERROR 371 //You cannot loot this Lore Item. You already have one.
|
#define LOOT_LORE_ERROR 371 //You cannot loot this Lore Item. You already have one.
|
||||||
#define PICK_LORE 379 //You cannot pick up a lore item you already possess.
|
#define PICK_LORE 379 //You cannot pick up a lore item you already possess.
|
||||||
#define CONSENT_DENIED 390 //You do not have consent to summon that corpse.
|
#define CONSENT_DENIED 390 //You do not have consent to summon that corpse.
|
||||||
@ -421,6 +425,7 @@
|
|||||||
#define SENSE_ANIMAL 12472 //You sense an animal in this direction.
|
#define SENSE_ANIMAL 12472 //You sense an animal in this direction.
|
||||||
#define SENSE_SUMMONED 12473 //You sense a summoned being in this direction.
|
#define SENSE_SUMMONED 12473 //You sense a summoned being in this direction.
|
||||||
#define SENSE_NOTHING 12474 //You don't sense anything.
|
#define SENSE_NOTHING 12474 //You don't sense anything.
|
||||||
|
#define SENSE_TRAP 12475 //You sense a trap in this direction.
|
||||||
#define LDON_SENSE_TRAP3 12476 //You don't sense any traps.
|
#define LDON_SENSE_TRAP3 12476 //You don't sense any traps.
|
||||||
#define INTERRUPT_SPELL_OTHER 12478 //%1's casting is interrupted!
|
#define INTERRUPT_SPELL_OTHER 12478 //%1's casting is interrupted!
|
||||||
#define YOU_HIT_NONMELEE 12481 //You were hit by non-melee for %1 damage.
|
#define YOU_HIT_NONMELEE 12481 //You were hit by non-melee for %1 damage.
|
||||||
|
|||||||
@ -523,7 +523,6 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
else
|
else
|
||||||
qs_audit->char1_count += detail->charges;
|
qs_audit->char1_count += detail->charges;
|
||||||
|
|
||||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
|
||||||
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
||||||
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
||||||
|
|
||||||
@ -743,7 +742,6 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
qs_audit->char1_count += detail->charges;
|
qs_audit->char1_count += detail->charges;
|
||||||
|
|
||||||
// 'step 3' should never really see containers..but, just in case...
|
// 'step 3' should never really see containers..but, just in case...
|
||||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
|
||||||
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
||||||
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
||||||
|
|
||||||
@ -888,8 +886,12 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
|
|
||||||
const EQEmu::ItemData* item = inst->GetItem();
|
const EQEmu::ItemData* item = inst->GetItem();
|
||||||
if(item && quest_npc == false) {
|
if(item && quest_npc == false) {
|
||||||
|
bool isPetAndCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) &&
|
||||||
|
_CLIENTPET(tradingWith) &&
|
||||||
|
tradingWith->GetPetType()<=petOther);
|
||||||
// if it was not a NO DROP or Attuned item (or if a GM is trading), let the NPC have it
|
// if it was not a NO DROP or Attuned item (or if a GM is trading), let the NPC have it
|
||||||
if(GetGM() || (item->NoDrop != 0 && inst->IsAttuned() == false)) {
|
if(GetGM() || (inst->IsAttuned() == false &&
|
||||||
|
(item->NoDrop != 0 || isPetAndCanHaveNoDrop))) {
|
||||||
// pets need to look inside bags and try to equip items found there
|
// pets need to look inside bags and try to equip items found there
|
||||||
if (item->IsClassBag() && item->BagSlots > 0) {
|
if (item->IsClassBag() && item->BagSlots > 0) {
|
||||||
for (int16 bslot = EQEmu::inventory::containerBegin; bslot < item->BagSlots; bslot++) {
|
for (int16 bslot = EQEmu::inventory::containerBegin; bslot < item->BagSlots; bslot++) {
|
||||||
|
|||||||
286
zone/trap.cpp
286
zone/trap.cpp
@ -52,10 +52,12 @@ CREATE TABLE traps (
|
|||||||
Trap::Trap() :
|
Trap::Trap() :
|
||||||
Entity(),
|
Entity(),
|
||||||
respawn_timer(600000),
|
respawn_timer(600000),
|
||||||
chkarea_timer(500),
|
chkarea_timer(1000),
|
||||||
|
reset_timer(5000),
|
||||||
m_Position(glm::vec3())
|
m_Position(glm::vec3())
|
||||||
{
|
{
|
||||||
trap_id = 0;
|
trap_id = 0;
|
||||||
|
db_id = 0;
|
||||||
maxzdiff = 0;
|
maxzdiff = 0;
|
||||||
radius = 0;
|
radius = 0;
|
||||||
effect = 0;
|
effect = 0;
|
||||||
@ -64,12 +66,20 @@ Trap::Trap() :
|
|||||||
skill = 0;
|
skill = 0;
|
||||||
level = 0;
|
level = 0;
|
||||||
respawn_timer.Disable();
|
respawn_timer.Disable();
|
||||||
|
reset_timer.Disable();
|
||||||
detected = false;
|
detected = false;
|
||||||
disarmed = false;
|
disarmed = false;
|
||||||
respawn_time = 0;
|
respawn_time = 0;
|
||||||
respawn_var = 0;
|
respawn_var = 0;
|
||||||
hiddenTrigger = nullptr;
|
hiddenTrigger = nullptr;
|
||||||
ownHiddenTrigger = false;
|
ownHiddenTrigger = false;
|
||||||
|
chance = 0;
|
||||||
|
triggered_number = 0;
|
||||||
|
times_triggered = 0;
|
||||||
|
group = 0;
|
||||||
|
despawn_when_triggered = false;
|
||||||
|
charid = 0;
|
||||||
|
undetectable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trap::~Trap()
|
Trap::~Trap()
|
||||||
@ -80,8 +90,7 @@ Trap::~Trap()
|
|||||||
|
|
||||||
bool Trap::Process()
|
bool Trap::Process()
|
||||||
{
|
{
|
||||||
if (chkarea_timer.Enabled() && chkarea_timer.Check()
|
if (chkarea_timer.Enabled() && chkarea_timer.Check() && !reset_timer.Enabled())
|
||||||
/*&& zone->GetClientCount() > 0*/ )
|
|
||||||
{
|
{
|
||||||
Mob* trigger = entity_list.GetTrapTrigger(this);
|
Mob* trigger = entity_list.GetTrapTrigger(this);
|
||||||
if (trigger && !(trigger->IsClient() && trigger->CastToClient()->GetGM()))
|
if (trigger && !(trigger->IsClient() && trigger->CastToClient()->GetGM()))
|
||||||
@ -89,6 +98,13 @@ bool Trap::Process()
|
|||||||
Trigger(trigger);
|
Trigger(trigger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (reset_timer.Enabled() && reset_timer.Check())
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Reset timer disabled in Reset Check Process for trap %d.", trap_id);
|
||||||
|
reset_timer.Disable();
|
||||||
|
charid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (respawn_timer.Enabled() && respawn_timer.Check())
|
if (respawn_timer.Enabled() && respawn_timer.Check())
|
||||||
{
|
{
|
||||||
detected = false;
|
detected = false;
|
||||||
@ -96,11 +112,15 @@ bool Trap::Process()
|
|||||||
chkarea_timer.Enable();
|
chkarea_timer.Enable();
|
||||||
respawn_timer.Disable();
|
respawn_timer.Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trap::Trigger(Mob* trigger)
|
void Trap::Trigger(Mob* trigger)
|
||||||
{
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap %d triggered by %s for the %d time!", trap_id, trigger->GetName(), times_triggered + 1);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
const NPCType* tmp = 0;
|
const NPCType* tmp = 0;
|
||||||
switch (effect)
|
switch (effect)
|
||||||
@ -128,7 +148,7 @@ void Trap::Trigger(Mob* trigger)
|
|||||||
entity_list.MessageClose(trigger,false,effectvalue,13,"%s",message.c_str());
|
entity_list.MessageClose(trigger,false,effectvalue,13,"%s",message.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_list.SendAlarm(this,trigger,effectvalue);
|
entity_list.SendAlarm(this,trigger, effectvalue2);
|
||||||
break;
|
break;
|
||||||
case trapTypeMysticSpawn:
|
case trapTypeMysticSpawn:
|
||||||
if (message.empty())
|
if (message.empty())
|
||||||
@ -201,12 +221,41 @@ void Trap::Trigger(Mob* trigger)
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
respawn_timer.Start((respawn_time + zone->random.Int(0, respawn_var)) * 1000);
|
|
||||||
chkarea_timer.Disable();
|
if (trigger && trigger->IsClient())
|
||||||
disarmed = true;
|
{
|
||||||
|
trigger->CastToClient()->trapid = trap_id;
|
||||||
|
charid = trigger->CastToClient()->CharacterID();
|
||||||
}
|
}
|
||||||
|
|
||||||
Trap* EntityList::FindNearbyTrap(Mob* searcher, float max_dist) {
|
bool update = false;
|
||||||
|
if (despawn_when_triggered)
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap %d is despawning after being triggered.", trap_id);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reset_timer.Start(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triggered_number > 0)
|
||||||
|
++times_triggered;
|
||||||
|
|
||||||
|
if (triggered_number > 0 && triggered_number <= times_triggered)
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Triggered number for trap %d reached. %d/%d", trap_id, times_triggered, triggered_number);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update)
|
||||||
|
{
|
||||||
|
UpdateTrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Trap* EntityList::FindNearbyTrap(Mob* searcher, float max_dist, float &trap_curdist, bool detected)
|
||||||
|
{
|
||||||
float dist = 999999;
|
float dist = 999999;
|
||||||
Trap* current_trap = nullptr;
|
Trap* current_trap = nullptr;
|
||||||
|
|
||||||
@ -215,61 +264,161 @@ Trap* EntityList::FindNearbyTrap(Mob* searcher, float max_dist) {
|
|||||||
|
|
||||||
for (auto it = trap_list.begin(); it != trap_list.end(); ++it) {
|
for (auto it = trap_list.begin(); it != trap_list.end(); ++it) {
|
||||||
cur = it->second;
|
cur = it->second;
|
||||||
if(cur->disarmed)
|
if(cur->disarmed || (detected && !cur->detected) || cur->undetectable)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto diff = glm::vec3(searcher->GetPosition()) - cur->m_Position;
|
auto diff = glm::vec3(searcher->GetPosition()) - cur->m_Position;
|
||||||
float curdist = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
|
float curdist = diff.x*diff.x + diff.y*diff.y;
|
||||||
|
diff.z = std::abs(diff.z);
|
||||||
|
|
||||||
if (curdist < max_dist2 && curdist < dist)
|
if (curdist < max_dist2 && curdist < dist && diff.z <= cur->maxzdiff)
|
||||||
{
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap %d is curdist %0.1f", cur->db_id, curdist);
|
||||||
dist = curdist;
|
dist = curdist;
|
||||||
current_trap = cur;
|
current_trap = cur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (current_trap != nullptr)
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap %d is the closest trap.", current_trap->db_id);
|
||||||
|
trap_curdist = dist;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
trap_curdist = INVALID_INDEX;
|
||||||
|
|
||||||
return current_trap;
|
return current_trap;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mob* EntityList::GetTrapTrigger(Trap* trap) {
|
Mob* EntityList::GetTrapTrigger(Trap* trap)
|
||||||
Mob* savemob = 0;
|
{
|
||||||
|
|
||||||
float maxdist = trap->radius * trap->radius;
|
float maxdist = trap->radius * trap->radius;
|
||||||
|
for (auto it = client_list.begin(); it != client_list.end(); ++it)
|
||||||
for (auto it = client_list.begin(); it != client_list.end(); ++it) {
|
{
|
||||||
Client* cur = it->second;
|
Client* cur = it->second;
|
||||||
|
|
||||||
auto diff = glm::vec3(cur->GetPosition()) - trap->m_Position;
|
auto diff = glm::vec3(cur->GetPosition()) - trap->m_Position;
|
||||||
diff.z = std::abs(diff.z);
|
diff.z = std::abs(diff.z);
|
||||||
|
|
||||||
if ((diff.x*diff.x + diff.y*diff.y) <= maxdist
|
if ((diff.x*diff.x + diff.y*diff.y) <= maxdist
|
||||||
&& diff.z < trap->maxzdiff)
|
&& diff.z <= trap->maxzdiff)
|
||||||
{
|
{
|
||||||
if (zone->random.Roll(trap->chance))
|
//This prevents the trap from triggering on players while zoning.
|
||||||
return(cur);
|
if (strcmp(cur->GetName(), "No name") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cur->trapid == 0 && !cur->GetGM() && (trap->chance == 0 || zone->random.Roll(trap->chance)))
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "%s is about to trigger trap %d of chance %d. diff: %0.2f maxdist: %0.2f zdiff: %0.2f maxzdiff: %0.2f", cur->GetName(), trap->trap_id, trap->chance, (diff.x*diff.x + diff.y*diff.y), maxdist, diff.z, trap->maxzdiff);
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
savemob = cur;
|
{
|
||||||
|
if (cur->trapid == trap->trap_id)
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "%s is clearing trapid for trap %d", cur->GetName(), trap->trap_id);
|
||||||
|
cur->trapid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return savemob;
|
bool EntityList::IsTrapGroupSpawned(uint32 trap_id, uint8 group)
|
||||||
|
{
|
||||||
|
auto it = trap_list.begin();
|
||||||
|
while (it != trap_list.end())
|
||||||
|
{
|
||||||
|
Trap* cur = it->second;
|
||||||
|
if (cur->IsTrap() && cur->group == group && cur->trap_id != trap_id)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: rewrite this to not need direct access to trap members.
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityList::UpdateAllTraps(bool respawn, bool repopnow)
|
||||||
|
{
|
||||||
|
auto it = trap_list.begin();
|
||||||
|
while (it != trap_list.end())
|
||||||
|
{
|
||||||
|
Trap* cur = it->second;
|
||||||
|
if (cur->IsTrap())
|
||||||
|
{
|
||||||
|
cur->UpdateTrap(respawn, repopnow);
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(Logs::General, Logs::Traps, "All traps updated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityList::GetTrapInfo(Client* client)
|
||||||
|
{
|
||||||
|
uint8 count = 0;
|
||||||
|
auto it = trap_list.begin();
|
||||||
|
while (it != trap_list.end())
|
||||||
|
{
|
||||||
|
Trap* cur = it->second;
|
||||||
|
if (cur->IsTrap())
|
||||||
|
{
|
||||||
|
bool isset = (cur->chkarea_timer.Enabled() && !cur->reset_timer.Enabled());
|
||||||
|
client->Message(CC_Default, " Trap: (%d) found at %0.2f,%0.2f,%0.2f. Times Triggered: %d Is Active: %d Group: %d Message: %s", cur->trap_id, cur->m_Position.x, cur->m_Position.y, cur->m_Position.z, cur->times_triggered, isset, cur->group, cur->message.c_str());
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
client->Message(CC_Default, "%d traps found.", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityList::ClearTrapPointers()
|
||||||
|
{
|
||||||
|
auto it = trap_list.begin();
|
||||||
|
while (it != trap_list.end())
|
||||||
|
{
|
||||||
|
Trap* cur = it->second;
|
||||||
|
if (cur->IsTrap())
|
||||||
|
{
|
||||||
|
cur->DestroyHiddenTrigger();
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
|
bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
|
||||||
|
|
||||||
std::string query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
std::string query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||||
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level "
|
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
|
||||||
"FROM traps WHERE zone='%s' AND version=%u", zonename, version);
|
"`group`, triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND version=%u", zonename, version);
|
||||||
|
|
||||||
auto results = QueryDatabase(query);
|
auto results = QueryDatabase(query);
|
||||||
if (!results.Success()) {
|
if (!results.Success()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
uint32 tid = atoi(row[0]);
|
||||||
|
uint8 grp = atoi(row[15]);
|
||||||
|
|
||||||
|
if (grp > 0)
|
||||||
|
{
|
||||||
|
// If a member of our group is already spawned skip loading this trap.
|
||||||
|
if (entity_list.IsTrapGroupSpawned(tid, grp))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
auto trap = new Trap();
|
auto trap = new Trap();
|
||||||
trap->trap_id = atoi(row[0]);
|
trap->trap_id = tid;
|
||||||
|
trap->db_id = tid;
|
||||||
trap->m_Position = glm::vec3(atof(row[1]), atof(row[2]), atof(row[3]));
|
trap->m_Position = glm::vec3(atof(row[1]), atof(row[2]), atof(row[3]));
|
||||||
trap->effect = atoi(row[4]);
|
trap->effect = atoi(row[4]);
|
||||||
trap->effectvalue = atoi(row[5]);
|
trap->effectvalue = atoi(row[5]);
|
||||||
@ -282,8 +431,13 @@ bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
|
|||||||
trap->respawn_time = atoi(row[12]);
|
trap->respawn_time = atoi(row[12]);
|
||||||
trap->respawn_var = atoi(row[13]);
|
trap->respawn_var = atoi(row[13]);
|
||||||
trap->level = atoi(row[14]);
|
trap->level = atoi(row[14]);
|
||||||
|
trap->group = grp;
|
||||||
|
trap->triggered_number = atoi(row[16]);
|
||||||
|
trap->despawn_when_triggered = atobool(row[17]);
|
||||||
|
trap->undetectable = atobool(row[18]);
|
||||||
entity_list.AddTrap(trap);
|
entity_list.AddTrap(trap);
|
||||||
trap->CreateHiddenTrigger();
|
trap->CreateHiddenTrigger();
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap %d successfully loaded.", trap->trap_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -318,3 +472,87 @@ void Trap::CreateHiddenTrigger()
|
|||||||
hiddenTrigger = npca;
|
hiddenTrigger = npca;
|
||||||
ownHiddenTrigger = true;
|
ownHiddenTrigger = true;
|
||||||
}
|
}
|
||||||
|
bool ZoneDatabase::SetTrapData(Trap* trap, bool repopnow) {
|
||||||
|
|
||||||
|
uint32 dbid = trap->db_id;
|
||||||
|
std::string query;
|
||||||
|
|
||||||
|
if (trap->group > 0)
|
||||||
|
{
|
||||||
|
query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||||
|
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
|
||||||
|
"triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND `group`=%d AND id != %d ORDER BY RAND() LIMIT 1", zone->GetShortName(), trap->group, dbid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We could just use the existing data here, but querying the DB is not expensive, and allows content developers to change traps without rebooting.
|
||||||
|
query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||||
|
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
|
||||||
|
"triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND id = %d", zone->GetShortName(), dbid);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
|
||||||
|
trap->db_id = atoi(row[0]);
|
||||||
|
trap->m_Position = glm::vec3(atof(row[1]), atof(row[2]), atof(row[3]));
|
||||||
|
trap->effect = atoi(row[4]);
|
||||||
|
trap->effectvalue = atoi(row[5]);
|
||||||
|
trap->effectvalue2 = atoi(row[6]);
|
||||||
|
trap->skill = atoi(row[7]);
|
||||||
|
trap->maxzdiff = atof(row[8]);
|
||||||
|
trap->radius = atof(row[9]);
|
||||||
|
trap->chance = atoi(row[10]);
|
||||||
|
trap->message = row[11];
|
||||||
|
trap->respawn_time = atoi(row[12]);
|
||||||
|
trap->respawn_var = atoi(row[13]);
|
||||||
|
trap->level = atoi(row[14]);
|
||||||
|
trap->triggered_number = atoi(row[15]);
|
||||||
|
trap->despawn_when_triggered = atobool(row[16]);
|
||||||
|
trap->undetectable = atobool(row[17]);
|
||||||
|
trap->CreateHiddenTrigger();
|
||||||
|
|
||||||
|
if (repopnow)
|
||||||
|
{
|
||||||
|
trap->chkarea_timer.Enable();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trap->respawn_timer.Start((trap->respawn_time + zone->random.Int(0, trap->respawn_var)) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trap->trap_id != trap->db_id)
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap (%d) DBID has changed from %d to %d", trap->trap_id, dbid, trap->db_id);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trap::UpdateTrap(bool respawn, bool repopnow)
|
||||||
|
{
|
||||||
|
respawn_timer.Disable();
|
||||||
|
chkarea_timer.Disable();
|
||||||
|
reset_timer.Disable();
|
||||||
|
if (hiddenTrigger)
|
||||||
|
{
|
||||||
|
hiddenTrigger->Depop();
|
||||||
|
hiddenTrigger = nullptr;
|
||||||
|
}
|
||||||
|
times_triggered = 0;
|
||||||
|
Client* trigger = entity_list.GetClientByCharID(charid);
|
||||||
|
if (trigger)
|
||||||
|
{
|
||||||
|
trigger->trapid = 0;
|
||||||
|
}
|
||||||
|
charid = 0;
|
||||||
|
if (respawn)
|
||||||
|
{
|
||||||
|
database.SetTrapData(this, repopnow);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
zone/trap.h
13
zone/trap.h
@ -49,11 +49,14 @@ public:
|
|||||||
NPC * GetHiddenTrigger() { return hiddenTrigger; }
|
NPC * GetHiddenTrigger() { return hiddenTrigger; }
|
||||||
void SetHiddenTrigger(NPC* n) { hiddenTrigger = n; }
|
void SetHiddenTrigger(NPC* n) { hiddenTrigger = n; }
|
||||||
void CreateHiddenTrigger();
|
void CreateHiddenTrigger();
|
||||||
|
void DestroyHiddenTrigger() { hiddenTrigger = nullptr; }
|
||||||
|
void UpdateTrap(bool respawn = true, bool repopnow = false);
|
||||||
//Trap data, leave this unprotected
|
//Trap data, leave this unprotected
|
||||||
Timer respawn_timer; //Respawn Time when Trap's been disarmed
|
Timer respawn_timer; //Respawn Time when Trap's been disarmed
|
||||||
Timer chkarea_timer;
|
Timer chkarea_timer;
|
||||||
uint32 trap_id; //Database ID of trap
|
Timer reset_timer; //How long a trap takes to reset before triggering again.
|
||||||
|
uint32 trap_id; //Original ID of the trap from DB. This value never changes.
|
||||||
|
uint32 db_id; //The DB ID of the trap that currently is spawned.
|
||||||
glm::vec3 m_Position;
|
glm::vec3 m_Position;
|
||||||
float maxzdiff; //maximum z diff to be triggerable
|
float maxzdiff; //maximum z diff to be triggerable
|
||||||
float radius; //radius around trap to be triggerable
|
float radius; //radius around trap to be triggerable
|
||||||
@ -67,6 +70,12 @@ public:
|
|||||||
bool disarmed;
|
bool disarmed;
|
||||||
uint32 respawn_time;
|
uint32 respawn_time;
|
||||||
uint32 respawn_var;
|
uint32 respawn_var;
|
||||||
|
uint8 triggered_number;
|
||||||
|
uint8 times_triggered;
|
||||||
|
uint8 group;
|
||||||
|
bool despawn_when_triggered;
|
||||||
|
uint32 charid; //ID of character that triggered trap. This is cleared when the trap despawns are resets.
|
||||||
|
bool undetectable;
|
||||||
|
|
||||||
std::string message;
|
std::string message;
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@ -176,9 +176,15 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot)
|
|||||||
cur_wp = -2; // flag as quest controlled w/no grid
|
cur_wp = -2; // flag as quest controlled w/no grid
|
||||||
Log(Logs::Detail, Logs::AI, "MoveTo %s without a grid.", to_string(static_cast<glm::vec3>(position)).c_str());
|
Log(Logs::Detail, Logs::AI, "MoveTo %s without a grid.", to_string(static_cast<glm::vec3>(position)).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 dest(position);
|
||||||
|
|
||||||
|
m_CurrentWayPoint = position;
|
||||||
|
m_CurrentWayPoint.z = GetFixedZ(dest);
|
||||||
|
|
||||||
if (saveguardspot)
|
if (saveguardspot)
|
||||||
{
|
{
|
||||||
m_GuardPoint = position;
|
m_GuardPoint = m_CurrentWayPoint;
|
||||||
|
|
||||||
if (m_GuardPoint.w == 0)
|
if (m_GuardPoint.w == 0)
|
||||||
m_GuardPoint.w = 0.0001; //hack to make IsGuarding simpler
|
m_GuardPoint.w = 0.0001; //hack to make IsGuarding simpler
|
||||||
@ -189,7 +195,6 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot)
|
|||||||
Log(Logs::Detail, Logs::AI, "Setting guard position to %s", to_string(static_cast<glm::vec3>(m_GuardPoint)).c_str());
|
Log(Logs::Detail, Logs::AI, "Setting guard position to %s", to_string(static_cast<glm::vec3>(m_GuardPoint)).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_CurrentWayPoint = position;
|
|
||||||
cur_wp_pause = 0;
|
cur_wp_pause = 0;
|
||||||
pLastFightingDelayMoving = 0;
|
pLastFightingDelayMoving = 0;
|
||||||
if (AI_walking_timer->Enabled())
|
if (AI_walking_timer->Enabled())
|
||||||
@ -838,35 +843,50 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::FixZ() {
|
float Mob::GetFixedZ(glm::vec3 dest, int32 z_find_offset)
|
||||||
|
{
|
||||||
BenchTimer timer;
|
BenchTimer timer;
|
||||||
timer.reset();
|
timer.reset();
|
||||||
|
float new_z = dest.z;
|
||||||
|
|
||||||
if (zone->HasMap() && RuleB(Map, FixZWhenMoving) && (flymode != 1 && flymode != 2))
|
if (zone->HasMap() && RuleB(Map, FixZWhenMoving) &&
|
||||||
|
(flymode != 1 && flymode != 2))
|
||||||
{
|
{
|
||||||
if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
|
if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap()
|
||||||
(zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
|
|| (zone->HasWaterMap() &&
|
||||||
|
!zone->watermap->InWater(glm::vec3(m_Position))))
|
||||||
{
|
{
|
||||||
/* Any more than 5 in the offset makes NPC's hop/snap to ceiling in small corridors */
|
/* Any more than 5 in the offset makes NPC's hop/snap to ceiling in small corridors */
|
||||||
float new_z = this->FindGroundZ(m_Position.x, m_Position.y, 5);
|
new_z = this->FindDestGroundZ(dest, z_find_offset);
|
||||||
new_z += (this->GetSize() / 1.55);
|
if (new_z != BEST_Z_INVALID)
|
||||||
|
{
|
||||||
|
new_z += this->GetZOffset();
|
||||||
|
|
||||||
|
// If bad new Z restore old one
|
||||||
|
if (new_z < -2000) {
|
||||||
|
new_z = m_Position.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto duration = timer.elapsed();
|
auto duration = timer.elapsed();
|
||||||
|
|
||||||
Log(
|
Log(Logs::Moderate, Logs::FixZ,
|
||||||
Logs::Moderate,
|
"Mob::GetFixedZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf",
|
||||||
Logs::FixZ,
|
this->GetCleanName(), new_z, dest.x, dest.y, dest.z, duration);
|
||||||
"Mob::FixZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf",
|
}
|
||||||
this->GetCleanName(),
|
|
||||||
new_z,
|
|
||||||
m_Position.x,
|
|
||||||
m_Position.y,
|
|
||||||
m_Position.z,
|
|
||||||
duration
|
|
||||||
);
|
|
||||||
|
|
||||||
if ((new_z > -2000) && new_z != -999999) {
|
return new_z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::FixZ(int32 z_find_offset /*= 5*/)
|
||||||
|
{
|
||||||
|
glm::vec3 current_loc(m_Position);
|
||||||
|
float new_z = GetFixedZ(current_loc, z_find_offset);
|
||||||
|
|
||||||
|
if (!IsClient() && new_z != m_Position.z)
|
||||||
|
{
|
||||||
|
if ((new_z > -2000) && new_z != BEST_Z_INVALID) {
|
||||||
if (RuleB(Map, MobZVisualDebug))
|
if (RuleB(Map, MobZVisualDebug))
|
||||||
this->SendAppearanceEffect(78, 0, 0, 0, 0);
|
this->SendAppearanceEffect(78, 0, 0, 0, 0);
|
||||||
|
|
||||||
@ -876,12 +896,117 @@ void Mob::FixZ() {
|
|||||||
if (RuleB(Map, MobZVisualDebug))
|
if (RuleB(Map, MobZVisualDebug))
|
||||||
this->SendAppearanceEffect(103, 0, 0, 0, 0);
|
this->SendAppearanceEffect(103, 0, 0, 0, 0);
|
||||||
|
|
||||||
Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f", this->GetCleanName(), std::abs(m_Position.z - new_z));
|
Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f",
|
||||||
|
this->GetCleanName(), std::abs(m_Position.z - new_z));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last_z = m_Position.z;
|
float Mob::GetZOffset() const {
|
||||||
}
|
float offset = 3.125f;
|
||||||
|
|
||||||
|
switch (race) {
|
||||||
|
case 436:
|
||||||
|
offset = 0.577f;
|
||||||
|
break;
|
||||||
|
case 430:
|
||||||
|
offset = 0.5f;
|
||||||
|
break;
|
||||||
|
case 432:
|
||||||
|
offset = 1.9f;
|
||||||
|
break;
|
||||||
|
case 435:
|
||||||
|
offset = 0.93f;
|
||||||
|
break;
|
||||||
|
case 450:
|
||||||
|
offset = 0.938f;
|
||||||
|
break;
|
||||||
|
case 479:
|
||||||
|
offset = 0.8f;
|
||||||
|
break;
|
||||||
|
case 451:
|
||||||
|
offset = 0.816f;
|
||||||
|
break;
|
||||||
|
case 437:
|
||||||
|
offset = 0.527f;
|
||||||
|
break;
|
||||||
|
case 439:
|
||||||
|
offset = 1.536f;
|
||||||
|
break;
|
||||||
|
case 415:
|
||||||
|
offset = 1.0f;
|
||||||
|
break;
|
||||||
|
case 438:
|
||||||
|
offset = 0.776f;
|
||||||
|
break;
|
||||||
|
case 452:
|
||||||
|
offset = 0.776f;
|
||||||
|
break;
|
||||||
|
case 441:
|
||||||
|
offset = 0.816f;
|
||||||
|
break;
|
||||||
|
case 440:
|
||||||
|
offset = 0.938f;
|
||||||
|
break;
|
||||||
|
case 468:
|
||||||
|
offset = 1.0f;
|
||||||
|
break;
|
||||||
|
case 459:
|
||||||
|
offset = 1.0f;
|
||||||
|
break;
|
||||||
|
case 462:
|
||||||
|
offset = 1.5f;
|
||||||
|
break;
|
||||||
|
case 530:
|
||||||
|
offset = 1.2f;
|
||||||
|
break;
|
||||||
|
case 549:
|
||||||
|
offset = 0.5f;
|
||||||
|
break;
|
||||||
|
case 548:
|
||||||
|
offset = 0.5f;
|
||||||
|
break;
|
||||||
|
case 547:
|
||||||
|
offset = 0.5f;
|
||||||
|
break;
|
||||||
|
case 604:
|
||||||
|
offset = 1.2f;
|
||||||
|
break;
|
||||||
|
case 653:
|
||||||
|
offset = 5.9f;
|
||||||
|
break;
|
||||||
|
case 658:
|
||||||
|
offset = 4.0f;
|
||||||
|
break;
|
||||||
|
case 323:
|
||||||
|
offset = 5.0f;
|
||||||
|
break;
|
||||||
|
case 663:
|
||||||
|
offset = 5.0f;
|
||||||
|
break;
|
||||||
|
case 664:
|
||||||
|
offset = 4.0f;
|
||||||
|
break;
|
||||||
|
case 703:
|
||||||
|
offset = 9.0f;
|
||||||
|
break;
|
||||||
|
case 688:
|
||||||
|
offset = 5.0f;
|
||||||
|
break;
|
||||||
|
case 669:
|
||||||
|
offset = 7.0f;
|
||||||
|
break;
|
||||||
|
case 687:
|
||||||
|
offset = 2.0f;
|
||||||
|
break;
|
||||||
|
case 686:
|
||||||
|
offset = 2.0f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
offset = 3.125f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0.2 * GetSize() * offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZoneDatabase::GetHighestGrid(uint32 zoneid) {
|
int ZoneDatabase::GetHighestGrid(uint32 zoneid) {
|
||||||
|
|||||||
@ -1428,7 +1428,8 @@ void Zone::StartShutdownTimer(uint32 set_time) {
|
|||||||
bool Zone::Depop(bool StartSpawnTimer) {
|
bool Zone::Depop(bool StartSpawnTimer) {
|
||||||
std::map<uint32,NPCType *>::iterator itr;
|
std::map<uint32,NPCType *>::iterator itr;
|
||||||
entity_list.Depop(StartSpawnTimer);
|
entity_list.Depop(StartSpawnTimer);
|
||||||
|
entity_list.ClearTrapPointers();
|
||||||
|
entity_list.UpdateAllTraps(false);
|
||||||
/* Refresh npctable (cache), getting current info from database. */
|
/* Refresh npctable (cache), getting current info from database. */
|
||||||
while(!npctable.empty()) {
|
while(!npctable.empty()) {
|
||||||
itr = npctable.begin();
|
itr = npctable.begin();
|
||||||
@ -1496,6 +1497,8 @@ void Zone::Repop(uint32 delay) {
|
|||||||
iterator.RemoveCurrent();
|
iterator.RemoveCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entity_list.ClearTrapPointers();
|
||||||
|
|
||||||
quest_manager.ClearAllTimers();
|
quest_manager.ClearAllTimers();
|
||||||
|
|
||||||
if (!database.PopulateZoneSpawnList(zoneid, spawn2_list, GetInstanceVersion(), delay))
|
if (!database.PopulateZoneSpawnList(zoneid, spawn2_list, GetInstanceVersion(), delay))
|
||||||
@ -1503,6 +1506,8 @@ void Zone::Repop(uint32 delay) {
|
|||||||
|
|
||||||
initgrids_timer.Start();
|
initgrids_timer.Start();
|
||||||
|
|
||||||
|
entity_list.UpdateAllTraps(true, true);
|
||||||
|
|
||||||
//MODDING HOOK FOR REPOP
|
//MODDING HOOK FOR REPOP
|
||||||
mod_repop();
|
mod_repop();
|
||||||
}
|
}
|
||||||
@ -1510,7 +1515,7 @@ void Zone::Repop(uint32 delay) {
|
|||||||
void Zone::GetTimeSync()
|
void Zone::GetTimeSync()
|
||||||
{
|
{
|
||||||
if (worldserver.Connected() && !zone_has_current_time) {
|
if (worldserver.Connected() && !zone_has_current_time) {
|
||||||
auto pack = new ServerPacket(ServerOP_GetWorldTime, 0);
|
auto pack = new ServerPacket(ServerOP_GetWorldTime, 1);
|
||||||
worldserver.SendPacket(pack);
|
worldserver.SendPacket(pack);
|
||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1433,6 +1433,11 @@ bool ZoneDatabase::SaveCharacterInventorySnapshot(uint32 character_id){
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp){
|
bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp){
|
||||||
|
|
||||||
|
/* If this is ever zero - the client hasn't fully loaded and potentially crashed during zone */
|
||||||
|
if (account_id <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
clock_t t = std::clock(); /* Function timer start */
|
clock_t t = std::clock(); /* Function timer start */
|
||||||
std::string query = StringFormat(
|
std::string query = StringFormat(
|
||||||
"REPLACE INTO `character_data` ("
|
"REPLACE INTO `character_data` ("
|
||||||
@ -2953,11 +2958,13 @@ uint32 ZoneDatabase::GetKarma(uint32 acct_id)
|
|||||||
if (!results.Success())
|
if (!results.Success())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
auto row = results.begin();
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
|
||||||
return atoi(row[0]);
|
return atoi(row[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ZoneDatabase::UpdateKarma(uint32 acct_id, uint32 amount)
|
void ZoneDatabase::UpdateKarma(uint32 acct_id, uint32 amount)
|
||||||
{
|
{
|
||||||
std::string query = StringFormat("UPDATE account SET karma = %i WHERE id = %i", amount, acct_id);
|
std::string query = StringFormat("UPDATE account SET karma = %i WHERE id = %i", amount, acct_id);
|
||||||
|
|||||||
@ -16,6 +16,7 @@ class NPC;
|
|||||||
class Petition;
|
class Petition;
|
||||||
class Spawn2;
|
class Spawn2;
|
||||||
class SpawnGroupList;
|
class SpawnGroupList;
|
||||||
|
class Trap;
|
||||||
struct CharacterEventLog_Struct;
|
struct CharacterEventLog_Struct;
|
||||||
struct Door;
|
struct Door;
|
||||||
struct ExtendedProfile_Struct;
|
struct ExtendedProfile_Struct;
|
||||||
@ -478,7 +479,7 @@ public:
|
|||||||
|
|
||||||
/* Traps */
|
/* Traps */
|
||||||
bool LoadTraps(const char* zonename, int16 version);
|
bool LoadTraps(const char* zonename, int16 version);
|
||||||
char* GetTrapMessage(uint32 trap_id);
|
bool SetTrapData(Trap* trap, bool repopnow = false);
|
||||||
|
|
||||||
/* Time */
|
/* Time */
|
||||||
uint32 GetZoneTZ(uint32 zoneid, uint32 version);
|
uint32 GetZoneTZ(uint32 zoneid, uint32 version);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user