merge changes from the defunct ubot

This commit is contained in:
dmitry 2020-06-12 18:52:38 +03:00 committed by jeefo
commit cf501b75b7
90 changed files with 11977 additions and 3907 deletions

18
.gitattributes vendored
View file

@ -2,20 +2,6 @@
* text=auto
# Custom for Visual Studio
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
*.sln merge=union
*.vcxproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

75
.gitignore vendored
View file

@ -1,71 +1,8 @@
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# =========================
# Operating System Files
# =========================
# OSX
# =========================
.DS_Store
.AppleDouble
.LSOverride
# Icon must ends with two \r.
Icon
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
/project/.vs
/project/enc_temp_folder
/.vs
*.pdb
*.asm
*.tlog
*.obj
*.log
*.manifest
*.map
*.res
*.lib
*.exp
*.ilk
*.opensdf
*.dll
*.sdf
*.suo
*.idb
*.vspx
*.so
*.user
*.psess
*.opendb
*.aps
*.db
*.enc
*.xml
*.vsp
*.lastcodeanalysissucceeded
*.json
*.html
*.settings
*.sarif
*.txt
vc/release
vc/debug
vc/.vs
vc/enc_temp_folder

View file

@ -1,32 +0,0 @@
language: cpp
dist: bionic
compiler:
- clang
addons:
apt:
packages:
- libc6-dev-i386
- linux-libc-dev
- gcc-multilib
- g++-multilib
os:
- linux
- osx
before_script:
- sed -i.bak "s/unspecified_hash/$(git rev-parse HEAD 2>/dev/null)/g;s/unspecified_author/$(git log --pretty="%ae" -1 2>/dev/null)/g;s/0000/$(git rev-list HEAD --count 2>/dev/null)/g" include/resource.h && rm include/resource.h.bak
script:
- cd project && CC=clang && make all
after_success:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
- curl -F "key=$CI_KEY" -F "mode=build" -F "type=release" -F "lib=@./release/yapb.so" https://yapb.ru/agent/ci.php
- curl -F "key=$CI_KEY" -F "mode=build" -F "type=debug" -F "lib=@./debug/yapb.so" https://yapb.ru/agent/ci.php
- fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
- curl -F "key=$CI_KEY" -F "mode=build" -F "type=release" -F "lib=@./release/yapb.dylib" https://yapb.ru/agent/ci.php
- curl -F "key=$CI_KEY" -F "mode=build" -F "type=debug" -F "lib=@./debug/yapb.dylib" https://yapb.ru/agent/ci.php
- fi

View file

@ -1 +0,0 @@
include $(call all-subdir-makefiles)

View file

@ -1,21 +1,674 @@
The MIT License (MIT)
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (c) 2004-2019 Yet Another POD-Bot Contributors <yapb@entix.io>
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.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Preamble
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View file

@ -1,12 +1,6 @@
Yet Another Ping Of Death Bot
=============
## YaPB
The third party AI for Counter-Strike game.
AI opponent for Counter-Strike based on POD-Bot 2.6 which allows your to play good old Counter-Strike without connecting to any server, or fill your server with computer controlled players.
AI opponent for Counter-Strike which allows your to play good old Counter-Strike without connecting to any server, or fill your server with computer controlled players.
Note that current status is maintenance and stabilization only. No new features are currently planned for bot.
Build Status & Downloads:
| Windows | Linux | Mac OS X | Coverity |
| :------------: |:---------------:|:---------------:| :-----:|
| [![AppVeyor](https://img.shields.io/appveyor/ci/jeefo/yapb.svg?style=flat-square)](https://ci.appveyor.com/project/jeefo/yapb) | [![Travis](https://img.shields.io/travis/jeefo/yapb.svg?style=flat-square)](https://travis-ci.org/jeefo/yapb) | [![Travis](https://img.shields.io/travis/jeefo/yapb.svg?style=flat-square)](https://travis-ci.org/jeefo/yapb) | [![Coverity Scan](https://img.shields.io/coverity/scan/5618.svg?style=flat-square)](https://scan.coverity.com/projects/5618)
Note that current status is maintenance and stabilization only.

View file

@ -0,0 +1,73 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: avatars.cfg
;
; This is a list of 64-bit Steam IDs that are used to display avatar for
; bots in scoreboard. There is currently limitation in counter-strike
; that it will display only avatars of players friends. So this basically
; currently useless until fix is found.
;
; Note: This is randomly taken Steam IDs. If you find yourself here, please
; create an issue to remove your person from here.
;
76561198824784299
76561198007764214
76561198282309907
76561198173426854
76561198189287387
76561198454548206
76561198813109996
76561198357926853
76561198964532315
76561198078745340
76561198029448247
76561198971020119
76561198281235027
76561198160435588
76561198451491670
76561198314767015
76561198848243467
76561198798756599
76561198127882879
76561198049242617
76561198247156514
76561198120614644
76561198205696041
76561198149965375
76561198109600465
76561198094851203
76561198824784299
76561198142543831
76561197997365684
76561198975813864
76561198799029556
76561198007764214
76561198282309907
76561198173426854
76561198189287387
76561198454548206
76561198813109996
76561198357926853
76561198964532315
76561198187991066
76561198131984268
76561198418691427
76561198165897856
76561198393573327
76561197987376673
76561198198316937
76561198416777179
76561197969349762
76561198344695316
76561198273780774
76561198179528373
76561198315042113
76561198815408627
76561198835894201
76561198350551375
76561198433144450
76561198100425157
76561198977884245

View file

@ -0,0 +1,84 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: chatter.cfg
;
; Configuration file contains chatter definitions for bots.
;
RewritePath sound/radio/bot
Event Radio_CoverMe = ("cover_me", "cover_me2");
// Event Radio_YouTakePoint = ("");
// Event Radio_HoldPosition = ("");
// Event Radio_RegroupTeam = ("");
Event Radio_FollowMe = ("lead_on_sir", "lead_the_way_sir", "lead_the_way", "ok_sir_lets_go", "lead_on_commander", "lead_the_way_commander", "ok_cmdr_lets_go");
Event Radio_TakingFire = ("taking_fire_need_assistance2", "i_could_use_some_help", "i_could_use_some_help_over_here", "help", "need_help", "need_help2", "im_in_trouble");
// Event Radio_GoGoGo = ("");
// Event Radio_Fallback = ("");
// Event Radio_StickTogether = ("");
// Event Radio_GetInPosition = ("");
// Event Radio_StormTheFront = ("");
Event Radio_ReportTeam = ("report_in_team", "anyone_see_them", "anyone_see_anything", "where_are_they", "where_could_they_be");
Event Radio_Affirmative = ("affirmative", "no2", "roger_that", "me_too", "ill_come_with_you", "ill_go_with_you", "ill_go_too", "i_got_your_back", "i_got_your_back2", "im_with_you", "im_with_you", "sounds_like_a_plan", "good_idea");
Event Radio_EnemySpotted = ("one_guy", "two_of_them", "theyre_all_over_the_place2", "the_actions_hot_here", "its_a_party");
Event Radio_NeedBackup = ("taking_fire_need_assistance2", "i_could_use_some_help", "i_could_use_some_help_over_here", "help", "need_help", "need_help2", "im_in_trouble");
Event Radio_SectorClear = ("clear", "clear2", "clear3", "clear4", "area_clear", "all_clear_here", "nothing_happening_over_here", "nothing_here", "theres_nobody_home");
Event Radio_InPosition = ("lets_wait_here", "lets_hold_up_here_for_a_minute", "im_gonna_hang_back", "im_going_to_wait_here", "im_waiting_here");
Event Radio_ReportingIn = ("reporting_in");
// Event Radio_ShesGonnaBlow = ("");
Event Radio_Negative = ("ahh_negative", "negative", "no2", "negative2", "i_dont_think_so", "naa", "no_thanks", "no", "nnno_sir", "no_sir");
Event Radio_EnemyDown = ("enemy_down", "enemy_down2");
// end of radio, begin some voices (NOT SORTED)
Event Chatter_SpotTheBomber = ("i_see_the_bomber", "theres_the_bomber", "hes_got_the_bomb", "hes_got_the_bomb2", "hes_got_the_package", "spotted_the_delivery_boy");
Event Chatter_FriendlyFire = ("cut_it_out", "what_are_you_doing", "stop_it", "ow_its_me", "ow", "ouch", "im_on_your_side", "hold_your_fire", "hey", "hey2", "ouch", "ouch", "ouch");
Event Chatter_DiePain = ("pain2", "pain4", "pain5", "pain8", "pain9", "pain10");
Event Chatter_GotBlinded = ("ive_been_blinded", "my_eyes", "i_cant_see", "im_blind");
Event Chatter_GoingToPlantBomb = ("im_gonna_go_plant", "im_gonna_go_plant_the_bomb");
Event Chatter_RescuingHostages = ("the_hostages_are_with_me", "taking_the_hostages_to_safety", "ive_got_the_hostages", "i_have_the_hostages");
Event Chatter_GoingToCamp = ("im_going_to_camp");
Event Chatter_HearSomething = ("hang_on_i_heard_something", "i_hear_something", "i_heard_them", "i_heard_something_over_there");
Event Chatter_TeamKill = ("what_happened", "noo", "oh_my_god", "oh_man", "oh_no_sad", "what_have_you_done");
Event Chatter_ReportingIn = ("reporting_in");
Event Chatter_GuardDroppedC4 = ("bombsite", "bombsite2", "i_got_a_covered", "im_camping_c");
Event Chatter_Camp = ("im_camping");
Event Chatter_PlantingC4 = ("planting_the_bomb", "planting");
Event Chatter_DefusingC4 = ("defusing", "defusing_bomb", "defusing_bomb");
Event Chatter_InCombat = ("attacking", "attacking_enemies", "engaging_enemies", "in_combat", "in_combat2", "returning_fire");
Event Chatter_SeeksEnemy = ("lets_wait_here", "lets_hold_up_here_for_a_minute", "im_gonna_hang_back", "im_going_to_wait_here", "im_waiting_here");
Event Chatter_Nothing = ("nothing_here", "nothing");
Event Chatter_EnemyDown = ("hes_dead", "hes_down", "got_him", "dropped_him", "killed_him", "ruined_his_day", "wasted_him", "made_him_cry", "took_him_down", "took_him_out2", "took_him_out", "hes_broken", "hes_done");
Event Chatter_UseHostage = ("talking_to_hostages", "rescuing_hostages");
Event Chatter_FoundC4 = ("bombs_on_the_ground", "bombs_on_the_ground_here", "the_bomb_is_down", "the_bomb_is_on_the_ground", "they_dropped_the_bomb");
Event Chatter_WonTheRound = ("good_job_team", "nice_work_team", "way_to_be_team", "well_done");
Event Chatter_QuicklyWonTheRound = ("i_am_dangerous", "do_not_mess_with_me", "we_owned_them", "they_never_knew_what_hit_them", "thats_the_way_this_is_done", "and_thats_how_its_done", "owned", "yesss", "yesss2", "yea_baby", "whoo", "whoo2", "oh_yea");
Event Chatter_ScaredEmotion = ("whoa", "uh_oh", "oh_no", "yikes", "oh", "oh_boy", "oh_boy2", "aah");
Event Chatter_HeardEnemy = ("i_hear_them", "hang_on_i_heard_something", "i_hear_something", "i_heard_them", "i_heard_something_over_there");
Event Chatter_SniperWarning = ("sniper", "sniper2", "watch_it_theres_a_sniper");
Event Chatter_SniperKilled = ("got_the_sniper", "got_the_sniper2", "sniper_down", "took_out_the_sniper", "the_sniper_is_dead");
Event Chatter_VIPSpotted = ("i_see_our_target", "target_spotted", "target_acquired");
Event Chatter_GuardingVipSafety = ("watching_the_escape_route", "im_at_the_escape_zone", "watching_the_escape_zone", "guarding_the_escape_zone", "guarding_the_escape_zone2");
Event Chatter_GoingToGuardVIPSafety = ("im_going_to_cover_the_escape_zone", "im_going_to_watch_the_escape_zone", "im_going_to_keep_an_eye_on_the_escape", "heading_to_the_escape_zone");
Event Chatter_OneEnemyLeft = ("one_guy_left", "theres_one_left");
Event Chatter_TwoEnemiesLeft = ("two_enemies_left", "two_to_go");
Event Chatter_ThreeEnemiesLeft = ("three_left", "three_to_go", "three_to_go2");
Event Chatter_NoEnemiesLeft = ("that_was_the_last_one", "that_was_it", "that_was_the_last_guy");
Event Chatter_FoundBombPlace = ("theres_the_bomb", "theres_the_bomb2");
Event Chatter_WhereIsTheBomb = ("wheres_the_bomb", "wheres_the_bomb2", "wheres_the_bomb3", "where_is_it");
Event Chatter_DefendingBombSite = ("bombsite", "bombsite2", "im_camping_b", "heading_to_c");
Event Chatter_BarelyDefused = ("i_wasnt_worried_for_a_minute", "that_was_a_close_one", "well_done", "whew_that_was_close");
Event Chatter_NiceshotCommander = ("good_one_sir", "good_one_sir2", "nice_shot_sir", "nice_one_sir");
Event Chatter_NiceshotPall = ("good_one", "good_one2", "nice_shot", "nice_shot2", "good_shot", "good_shot2", "nice", "nice2", "very_nice");
Event Chatter_GoingToGuardHostages = ("camping_hostages", "im_going_to_camp_the_hostages", "im_going_to_guard_the_hostages", "im_going_to_guard_the_hostages2");
Event Chatter_GoingToGuardDoppedBomb = ("im_going_to_guard_the_bomb", "im_going_to_guard_the_bomb2", "im_going_to_keep_an_eye_on_the_bomb", "im_going_to_watch_the_bomb");
Event Chatter_OnMyWay = ("on_my_way", "on_my_way2", "im_coming", "hang_on_im_coming", "be_right_there");
Event Chatter_LeadOnSir = ("lead_on_sir", "lead_the_way_sir", "lead_the_way", "ok_sir_lets_go", "lead_on_commander", "lead_the_way_commander", "ok_cmdr_lets_go");
Event Chatter_Pinned_Down = ("they_got_me_pinned_down_here", "im_pinned_down");
Event Chatter_GottaFindTheBomb = ("theres_the_bomb", "theres_the_bomb2");
Event Chatter_Lost_The_Commander = ("weve_lost_the_commander", "the_commander_is_down", "the_commander_is_down_repeat");
Event Chatter_CoverMe = ("cover_me", "cover_me2");
Event Chatter_BombSiteSecured = ("i_wasnt_worried_for_a_minute", "that_was_a_close_one", "well_done", "whew_that_was_close");

View file

@ -0,0 +1,29 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: difficulty.cfg
;
; Configuration file contains some difficulty definitions for bots
; difficulty selection.
;
; Format:
; Expret = 0.1,0.2,100,100,100
;
; As like:
; Level = minReactionTime(s),maxReactionTime(s),headshotProbability,seenThruWallChance,heardThruWallChance
;
; Where:
; minReactionTime - Minimal time in seconds from time the bot first saw enemy and time he can recognize it.
; maxReactionTime - Same as above, but upper cap of the limit.
; headshotProbability - Probability bot should aim at head instead of body if body and head both visible.
; seenThruWallChance - Chance the bot will attack enemy if he believes he's there and just seen him.
; heardThruWallChance - Chance the bot will attack enemy if he believes he's there and just heard him.
;
Noob = 0.8, 1.0, 5, 0, 0
Easy = 0.6, 0.8, 30, 10, 10
Normal = 0.4, 0.6, 50, 30, 40
Hard = 0.2, 0.4, 75, 60, 70
Expert = 0.1, 0.2, 100, 90, 90

View file

@ -0,0 +1,826 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: chs_lang.cfg
;
; Configuration file contains Simplified Chinese translation for bots menus and messages.
;
[ORIGINAL]
\yMain Menu\w
1. Control Bots
2. Features
3. Fill Server
4. End Round
0. Exit
[TRANSLATED]
\yYaPB 主菜单\w
1. YaPB 控制
2. 特性
3. 填充服务器
4. 结束本局
0. 退出
[ORIGINAL]
\yBots Features\w
1. Weapon Mode Menu
2. Waypoint Menu
3. Select Personality
4. Toggle Debug Mode
5. Command Menu
0. Exit
[TRANSLATED]
\yYaPB 特性\w
1. 武器模式菜单
2. 路点菜单
3. 选择个性
4. 切换调试模式
5. 命令菜单
0. 退出
[ORIGINAL]
\yBots Control Menu\w
1. Add a Bot, Quick
2. Add a Bot, Specified
3. Remove Random Bot
4. Remove All Bots
5. Remove Bot Menu
0. Exit
[TRANSLATED]
\yYaPB 控制菜单\w
1. 快速添加一个 bot
2. 添加一个特定的 bot
3. 随机删除一个 bot
4. 删除所有 bot
5. 删除 bot 菜单
0. 退出
[ORIGINAL]
\yBots Weapon Mode\w
1. Knives only
2. Pistols only
3. Shotguns only
4. Machine Guns only
5. Rifles only
6. Sniper Weapons only
7. All Weapons
0. Exit
[TRANSLATED]
\yBots 武器模式\w
1. 只用刀
2. 只用手枪
3. 只用霰弹枪
4. 只用机枪
5. 只用步枪
6. 只用狙击枪
7. 所有武器
0. 退出
[ORIGINAL]
\yBots Personality\w
1. Random
2. Normal
3. Aggressive
4. Defensive
0. Exit
[TRANSLATED]
\yYaPB 个性\w
1. 随机
2. 正常
3. 进攻型
4. 防守型
0. 退出
[ORIGINAL]
\yBots Difficulty Level\w
1. Newbie
2. Average
3. Normal
4. Professional
5. Godlike
0. Exit
[TRANSLATED]
\yYaPB 技能\w
1. 新手
2. 一般
3. 高级
4. 专业
5. 作弊者
0. 退出
[ORIGINAL]
\ySelect a team\w
1. Terrorist Force
2. Counter-Terrorist Force
5. Auto-select
0. Exit
[TRANSLATED]
\y选择一个队伍\w
1. 恐怖分子
2. 反恐精英
5. 自动选择
0. 退出
[ORIGINAL]
\ySelect an appearance\w
1. Phoenix Connexion
2. L337 Krew
3. Arctic Avengers
4. Guerilla Warfare
5. Auto-select
0. Exit
[TRANSLATED]
\y选择一个外观\w
1. Phoenix Connexion
2. L337 Krew
3. Arctic Avengers
4. Guerilla Warfare
5. 自动选择
0. 退出
[ORIGINAL]
\ySelect an appearance\w
1. Seal Team 6 (DEVGRU)
2. German GSG-9
3. UK SAS
4. French GIGN
5. Auto-select
0. Exit
[TRANSLATED]
\y选择一个外观\w
1. Seal Team 6 (DEVGRU)
2. German GSG-9
3. UK SAS
4. French GIGN
5. 自动选择
0. 退出
[ORIGINAL]
\yWaypoint Operations (Page 1)\w
1. Show/Hide waypoints
2. Cache waypoint
3. Create path
4. Delete path
5. Add waypoint
6. Delete waypoint
7. Set Autopath Distance
8. Set Radius
9. Next...
0. Exit
[TRANSLATED]
\y路点菜单 (第 1 页)\w
1. 显示/隐藏路点
2. 缓存路点
3. 建立路径
4. 删除路径
5. 添加路点
6. 删除路点
7. 设置自动路径距离
8. 设置路点作用范围
9. 下一页...
0. 退出
[ORIGINAL]
\yWaypoint Operations (Page 2)\w
1. Waypoint stats
2. Autowaypoint on/off
3. Set flags
4. Save waypoints
5. Save without checking
6. Load waypoints
7. Check waypoints
8. Noclip cheat on/off
9. Previous...
0. Exit
[TRANSLATED]
\y路点菜单 (第 2 页)\w
1. 路点统计
2. 自动放置路点开/关
3. 设置路点属性
4. 保存路点
5. 不检查保存路点
6. 读取路点
7. 检查路点
8. 穿墙模式开/关
9. 上一页...
0. 退出
[ORIGINAL]
\yWaypoint Radius\w
1. SetRadius 0
2. SetRadius 8
3. SetRadius 16
4. SetRadius 32
5. SetRadius 48
6. SetRadius 64
7. SetRadius 80
8. SetRadius 96
9. SetRadius 128
0. Exit
[TRANSLATED]
\y路点作用范围\w
1. 0
2. 8
3. 16
4. 32
5. 48
6. 64
7. 80
8. 96
9. 128
0. 退出
[ORIGINAL]
\yWaypoint Type\w
1. Normal
\r2. Terrorist Important
3. Counter-Terrorist Important
\w4. Block with hostage / Ladder
\y5. Rescue Zone
\w6. Camping
7. Camp End
\r8. Map Goal
\w9. Jump
0. Exit
[TRANSLATED]
\y路点类型\w
1. 正常
\r2. 恐怖分子重要点
3. 反恐精英重要点
\w4. 人质无法通过/梯子
\y5. 人质解救点
\w6. 守卫点
7. 守卫结束角度
\r8. 地图目标点
\w9. 跳跃点
0. 退出
[ORIGINAL]
\yWaypoint Flags\w
\yAdd waypoint flag:\w
1. Block with Hostage
2. Terrorists Specific
3. CTs Specific
4. Use Elevator
\yDelete waypoint flag:\w
5. Block with Hostage
6. Terrorists Specific
7. CTs Specific
8. Use Elevator
0. Exit
[TRANSLATED]
\y路点属性\w
\y添加路点属性:\w
1. 人质无法通过
2. 恐怖分子
3. 反恐精英
4. 使用电梯
\y删除路点属性:\w
5. 人质无法通过
6. 恐怖分子
7. 反恐精英
8. 使用电梯
0. 退出
[ORIGINAL]
\yBot Command Menu\w
1. Make Double Jump
2. Finish Double Jump
3. Drop the C4 Bomb
4. Drop the Weapon
0. Exit
[TRANSLATED]
\yBot 命令菜单\w
1. 双跳跃
2. 双跳跃结束
3. 扔掉炸弹
4. 扔掉枪
0. 退出
[ORIGINAL]
\yAutoPath Distance\w
1. Distance 0
2. Distance 100
3. Distance 130
4. Distance 160
5. Distance 190
6. Distance 220
7. Distance 250 (Default)
0. Exit
[TRANSLATED]
\y自动路径距离\w
1. 0
2. 100
3. 130
4. 160
5. 190
6. 220
7. 250 (默认)
0. 退出
[ORIGINAL]
\yCreate Path (Choose Direction)\w
1. Outgoing Path
2. Incoming Path
3. Bidirectional (Both Ways)
0. Exit
[TRANSLATED]
\y建立路径 (选择方向)\w
1. 向外
2. 向内
3. 双向
0. 退出
[ORIGINAL]
Map not waypointed. Can't Create Bot
[TRANSLATED]
没有路点。不能建立 bot
[ORIGINAL]
Waypoints has been changed. Load waypoints again...
[TRANSLATED]
路点已经改变。需要重新读取路点...
[ORIGINAL]
Invalid skill given. Using random skill.
[TRANSLATED]
输入了不正确的技能值。使用随机技能。
[ORIGINAL]
Connecting Bot...
[TRANSLATED]
正在连接 Bot...
[ORIGINAL]
Fill Server with %s bots...
[TRANSLATED]
用 %s bot 来填充服务器...
[ORIGINAL]
Bots are removed from server.
[TRANSLATED]
Bot 已被从服务器删除。
[ORIGINAL]
Bot '%s' kicked
[TRANSLATED]
Bot '%s' 已被删除。
[ORIGINAL]
\yBots Remove Menu (%d/4):\w
%s
%s 0. Back
[TRANSLATED]
\y删除 bot (%d/4):\w
%s
%s 0. 退出
[ORIGINAL]
%s\d %1.1d. Not a Bot\w
[TRANSLATED]
%s\d %1.1d. 不是 Bot\w
[ORIGINAL]
9. More...
[TRANSLATED]
9. 更多...
[ORIGINAL]
All Bots died !
[TRANSLATED]
所有的 bot 已被删除。
[ORIGINAL]
%s weapon mode selected
[TRANSLATED]
%s 武器模式已被选定。
[ORIGINAL]
ERROR: FindPath Source Invalid->%d
[TRANSLATED]
错误: 寻找路径源不正确->%d
[ORIGINAL]
ERROR: FindPath Destination Invalid->%d
[TRANSLATED]
错误: 寻找路径目标不正确->%d
[ORIGINAL]
Denied path creation from %d to %d (path already exists)
[TRANSLATED]
无法建立从 %d 到 %d 的路径 (路径已存在)
[ORIGINAL]
Path added from %d to %d
[TRANSLATED]
从 %d 到 %d 的路径已添加
[ORIGINAL]
This is not Camping Waypoint
[TRANSLATED]
没有守卫路点
[ORIGINAL]
Waypoint number out of range (Valid range From 0 to %d)
[TRANSLATED]
路点编号超出范围 (合法的范围从 0 到 %d)
[ORIGINAL]
Cannot connect waypoint to itself
[TRANSLATED]
无法将路点与自身连接
[ORIGINAL]
Waypoint %d connected with invalid Waypoint Nr. %d!
[TRANSLATED]
路点 %d 与非法的路点 %d 连接!
[ORIGINAL]
Waypoint %d isn't connected with any other Waypoint!
[TRANSLATED]
路点 %d 没有和其它任何路点连接!
[ORIGINAL]
Waypoint %d pathnumber differs from index!
[TRANSLATED]
路点 %d 路径编号不等于索引号!
[ORIGINAL]
Waypoint %d Camp-Endposition not set!
[TRANSLATED]
路点 %d 守卫结束角度没有设定!
[ORIGINAL]
You didn't set a Rescue Point!
[TRANSLATED]
你没有设置一个人质解救点!
[ORIGINAL]
You didn't set any Terrorist Important Point!
[TRANSLATED]
你没有设置一个 T 重要路点!
[ORIGINAL]
You didn't set any CT Important Point!
[TRANSLATED]
你没有设置一个 CT 重要路点!
[ORIGINAL]
You didn't set any Goal Point!
[TRANSLATED]
你没有设置一个目标点!
[ORIGINAL]
Path broken from Waypoint Nr. 0 to Waypoint Nr. %d!
[TRANSLATED]
从路点 #0 到路点 #%d 的路径损坏!
[ORIGINAL]
Path broken from Waypoint Nr. %d to Waypoint Nr. 0!
[TRANSLATED]
从路点 #%d 到路点 #%0 的路径损坏!
[ORIGINAL]
Choose weapon from 1 to 7 range
[TRANSLATED]
选择武器,范围从 1 到 7
[ORIGINAL]
All dead bots will vote for map #%d
[TRANSLATED]
所有的死亡的 bot 将会投地图 #%d 的票
[ORIGINAL]
Bot %s executing command %s
[TRANSLATED]
Bot %s 正在执行命令 %s
[ORIGINAL]
Player is NOT Bot!
[TRANSLATED]
玩家不是一个 bot!
[ORIGINAL]
Waypoint Editing Enabled
[TRANSLATED]
路点编辑已打开
[ORIGINAL]
Waypoint Editing Disabled
[TRANSLATED]
路点编辑已关闭
[ORIGINAL]
Noclip Cheat Enabled
[TRANSLATED]
穿墙模式已打开
[ORIGINAL]
Waypoints are Disabled
[TRANSLATED]
路点已关闭
[ORIGINAL]
Waypoints are Enabled
[TRANSLATED]
路点已打开
[ORIGINAL]
Noclip Cheat Disabled
[TRANSLATED]
穿墙模式已关闭
[ORIGINAL]
Showing Direction to Waypoint #%d
[TRANSLATED]
显示到路点 #%d 的方向
[ORIGINAL]
Waypoints Saved
[TRANSLATED]
路点已保存
[ORIGINAL]
Waypoints loaded
[TRANSLATED]
路点已读取
[ORIGINAL]
Nodes work Fine
[TRANSLATED]
路点没有错误
[ORIGINAL]
Waypoint Nr. %d now cached
[TRANSLATED]
路点 #%d 已被缓存
[ORIGINAL]
Player '%s' teleported to waypoint #%d (x:%d, y:%d, z:%d)
[TRANSLATED]
玩家 '%s' 已被传送到路点 #%d (x:%d, y:%d, z:%d)
[ORIGINAL]
Experience tab saved
[TRANSLATED]
经验已保存
[ORIGINAL]
Experience Enabled
[TRANSLATED]
经验已打开
[ORIGINAL]
Experience Disabled
[TRANSLATED]
经验已关闭
[ORIGINAL]
Command not supported on dedicated server
[TRANSLATED]
此命令无法在独立的服务器上使用
[ORIGINAL]
Waypoint not saved
There are errors, see console
[TRANSLATED]
路点没有被保存
有错误,详见控制台
[ORIGINAL]
There are errors, see console
[TRANSLATED]
有错误,详见控制台
[ORIGINAL]
You're dead, and have no access to this menu
[TRANSLATED]
你已死亡,不能使用此菜单
[ORIGINAL]
AutoPath disabled
[TRANSLATED]
自动路径已关闭
[ORIGINAL]
AutoPath maximum distance set to %f
[TRANSLATED]
最大自动路径距离已被设为 %f
[ORIGINAL]
Unable to find nearest waypoint in 50 units
[TRANSLATED]
在最近的 50 单位内无法找到一个路点
[ORIGINAL]
Unable to find destination waypoint
[TRANSLATED]
无法找到目标路点
[ORIGINAL]
Unable to connect waypoint with itself
[TRANSLATED]
无法将路点与自身连接
[ORIGINAL]
There is already no path on this waypoint
[TRANSLATED]
此路点已经没有路径
[ORIGINAL]
Cached waypoint cleared (nearby point not found in 50 units range)
[TRANSLATED]
缓存的路点已清除 (在 50 单位的范围内没有找到路点)
[ORIGINAL]
Waypoint #%d has been put into memory
[TRANSLATED]
路点 #%d 已被放入内存
[ORIGINAL]
Maximum players reached (%d/%d). Unable to create Bot.
[TRANSLATED]
最大的玩家数目已达到 (%d/%d)。无法添加 bot。

View file

@ -0,0 +1,571 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: de_chat.cfg
;
; Configuration file contains German translation for bot chats.
;
[BOMBPLANT]
Jeeesuzzz, nicht schon wieder !
Komm schon %t, lass uns die Bombe suchen!
Die kleine C4 wird doch wohl nicht hochgehen?
Jetzt schlaegts dreizehn! Wie konnte das passieren man %t?
Wenn sie entschaerft ist geb ich einen aus %t!
Schon wieder ihr verdammten Schlafmuetzen!
Wenn sie hochgeht entfaellt Deine Schichtzulage mensch!
Letztes Mal hat's nur 5 Sekunden bis zum entschaerfen gedauert...
Kennst Du noch die FATBOY %t? die hat RUMS gemacht!
Die Ts fangen an mich zu nerven
BOOOOMMMMM!!! hehe
Ist ne schmutzige Bombe hab ich gehoert- also sei vorsichtig %t
Ich hab doch gesagt Ihr sollt da besser aufpassen %t!LOS!
Beeil Dich besser %t
Wenn sie vorher hochgeht %t- ich sag Deiner Frau bescheid
Sitzt da noch irgendwo ein T an der Bombe?
Ich hoffe der Entschaerfungs-Lehrgang hat was genuetzt %t
Sag schon, ist es das rote oder das blaue Kabel ?
%t wir sollten langsam mal entschaerfen gehen...
Bombe entschaerfen gibt Extrazulage hab ich gehoert %t
Ob sie diesmal mit Naegeln gefuellt ist?
Mal sehen wie mein neues Entschaerfungskit funktioniert...
Wenn es Plastiksprengstoff ist hau lieber ab %t
Die Anleitung zum Bombenbauen haben sie bestimmt aus dem Internet...
...Und mein Herz macht Boooom *grins*
//
//
//
//
//
//
// Messages after killing somebody:
// Minimum Number is 1
// For the %v the name of the victim will
// be inserted
//
[KILLED]
%v, du kannst dich nicht mit mir vergleichen !
Tschuldigung, %v. Du standst in meinem Weg.
Du bist ganz gut geflogen, %v.
Manman keine Uebersicht %v
Dreh mir naechstes mal nicht den Hintern zu %v
WOOOW %v
Guck mal auf Dein Radar %v
Du konntest das mal besser %v
Red Dich nicht schon wieder mit schlechtem Ping raus %v
So eine Waffe hat auch einen Abzug %v
Hast Du ne Ahnung was Dich da getroffen hat %v?
Bind Dir naechstes mal die Schnuersenkel zu %v
Ich musste es tun, %v. Du verstehst schon...
hehe ein leichtes Ziel %v
Mach das nie wieder hehe %v
OWNEEED %v
Jawooolll!
Wie Du es verdienst %v
Vielleicht haettest Du Zielen sollen %v
Machs mir naechstes mal bitte etwas schwerer %v
Du haettest rennen sollen, als du noch konntest, %v.
Ich war immer besser, %v. Immer.
Jaja, jetzt kommt wieder: WAR DAS LAG *gg
Es ist immer die linke Maustaste %v
Naja Zielen ueben wir nochmal %v
Hast Du mich eigentlich gesehen %v?
Immer noch nichts gelernt %v?
Nochmal zurueck auf den Schiesstand Du nap %v
Ich wette du hasst es wenn das passiert, oder %v?
Das wird dich lehren, %v !
Hey, komm schon %v! Diesmal hast du mich beinahe getroffen !
Ha...ha!
Du bist Nichts, %v. Gar nichts .
%v haettest Du nicht an haette ich auch nicht an ;-)
%v ich mache mir Sorgen um dich...
Du solltest mal ein bisschen ueben %v
Tschuldige %v, mein Kopfschuss Script is besser als deins.
//
//
//
//
//
//
//
// Chat Messages when bot connects to server
// !!Minimum Number is 1!!
[WELCOME]
Hi Leute :)
Wazzzzup?
Moin moin wie gehts?
Gruess Gott miteinander ;-)
Hi, alles fit bei Euch?
Hoi, man bin ich mueede
Hallo, ich hoffe heit treff ich auch mal was...
Hallloooo alle zusammen!
Oh man hier gibts doch bestimmt keine Cheater, oder?
Hi, alle Cheater verlassen jetzt bitte den Server
Hoooiiii
Man endlich ein Slot frei!
Du meine Guete sind hier viele Cheater...
Moin alle machen jetzt bitte Ihren Aimbot aus hehe!
//
// Chat Messages when dead and bored
// !!Minimum Number is 9!!
//
[DEADCHAT]
Es macht mich krank diese Idioten anzugucken.
Es ist Zeit die Map zu wechseln, oder ?
%t GO,GO,GO!!
Die Camper Loser !
Mir ist sooo langweilig !
Ich kann nicht glauben das %f NICHT cheatet !
Zugucken ist scheisse...
Wieso immer ich??
Das ist unfair
Der hatte doch AN!
Boah ich kann wenigstens verlieren!
Ich wuenschte bessere Leute wuerden den Server joinen.
Das sah schmerzhaft aus.
Alles Noobs man!
Ey man ich hab bald kein Bock mehr!
Es macht heute Spass...
Noch %r in dieser Runde und ich gucke schon zu :(
Warum versuchen alle immer mich zu killen :)
Besucht http://www.geocities.com/countfloyd_1999/
Mein Handgelenk tut schon weh...
Diese Map ist scheisse...
Das LAG ist Schuld!
Ich hab 'nen schlechten Tag heute.
%r und %t ist immer noch am Leben ! Irgendwas ist hier falsch...
Werden die bald aufhoeren zu campen ? Nur noch %r !!
Ich bin besser in Quake 3, das ist schon mal sicher!
Nur noch %r in dieser Runde...
Botman muss sooo cool sein...
Daemliche Bots!
Guck dir diese Idioten an !!!
Ich wette %t schaffts nicht zu ueberleben
Ich bin heute so verdammt muede...
Ich sollte wirklich in's Bett gehen.
Mach mal ne andere Map an!
Normalerweise spiel ich nicht so schlecht !
Bitte kein %m mehr !
Ich hasse %m, wirklich :(
Snipern ist alles was die koennen.
Habt ihr mich fliegen sehen?
LOL! Guck dir %t an!
Das lag alles nur am LAG!!
Voted fuer 'nen Mapchange, bitte !
Ist schon einer der Bots wieder steckengeblieben ?
Boooooom !!! *lol*
Insane in the membrane, hehe!
Ich bin mir sicher der Kerl benutzt 'nen Aimbot !
HEY %f DU VERDAMMTER CHEATER!!!
Sind Bots hier im Spiel ?
Wuerdest du mir dein Kopfschuss Script geben ?
Naechste Runde sollten wir zusammenbleiben.
Bekiffte Teamkiller ueberall!!!
Boah guck dir %fs Statistik an !!
Wozu gibt's eigentlich Clans ? Kapier ich nicht.
Kennt ihr Jumbot ? Ist echt geil!
Immer diese Bots!
Wenn Botman cool ist, was ist dann erst TheFatal ?
Ich hab ein beschissenes Lag gerade.
Mein Fastpath hat sich verschluckt glaube ich
Ich finde NNBot ist um einiges besser als Realbot...
Schade das der Android Bot so langsam geupdated wird.
Ich mache 'ne Zigaretten Pause...
Warum haben die die Fahrzeuge in Cs reingemacht ?
Das ist doch voll langweilig
Nicht schon wieder die Bots!
Ich musste nachladen und der Penner schiesst mir in den Kopf!
Mehr Speed durch hoehere Geschwindigkeit!
Ich muss noch an meinen Reaktionen feilen
Wenn das Captain Kirk gesehen haette!
Ich war so kurz davor!
Fast ware mein Plan aufgegangen!
[REPLIES]
@KEY "AIMBOT", "WALLHACK"
%s, woher willst du das wissen ?
Sogar VAC2 erkennt nicht alles...
Du kannst im Moment echt nicht sicher sein ob einer cheatet oder gut spielt
Halts Maul %s, Aimbots sind cool!
Wallhacks sind ein Werk des Teufels :)
HLGuard ist ganz gut (www.unitedadmins.com)
VAC2 bringt auch nicht so viel
Wer wirklich cheaten will kann das auch leider -so war es immer
An den Netsettings drehen ist doch auch cheaten
An Fairplay denkt niemand mehr
Ich spiel nur noch mit meinen Kumpels- da weiss ich dass die nicht an haben
Cheaten ist doch langweilig nach ner halben Stunde
Manche koennen eben nicht verlieren...
Haben diese Bots hier eigentlich an? LOL
Erzaehl keinen Scheiss- ich hab nicht an!!
Mein Wallhack ist besser als Deiner
Ich hab gehoert bei diesem Polen gibts private Cheats billiger...
Cheaten ist nur was fuer Looser!
@KEY "ANDROID"
*seufz* achja das waren noch Zeiten...
%s war das auch dein erster Bot ?
Weiss einer was DaTa jetzt macht ?
Man kann %m nicht mit Android spielen, oder ?
@KEY "BOTMAN"
Wer ist dieser Botman ueber den alle reden???
Besucht doch mal seine Seite unter www.planethalflife.com/botman/
Ohne seinen SourceCode wuerden viele andere Bots gar nicht existieren!
Ich bin gespannt wann HPB-Bot fertig ist...
Hast du schon mit seinem HPB-Bot gespielt ?
Mit dem Darkulator von Botman korrigiere ich zu dunkle Custommaps
Seine Seite ist auch auf http://bots-united.com
@KEY "BOT ", "BOTS"
Warum redet ihr immer darueber ?
Es sind keine Bots auf diesem Server %s, ich schwoer's!
Bots sind cool!!!
Welcher ist dein Lieblingsbot %s?
Falls ihr euren eigenen programmieren wollt, fragt doch ma Botman!
Bots, immer nur Bots - ihr solltet ma gegen menschliche Gegner spielen..
Die meisten Bots sind immer noch saudumm...
@KEY "CAMPER", "CAMPING"
Echt, ich hasse diese Camper!
Camping sucks!
Campst du nicht auch manchmal %s ?
Man immer diese Camperei...
Campen ist fuer manche die einzige Moeglichkeit zu gewinnen
Ja, gutes altes Camper-Strike...
Guckst Du auch immer DIE CAMPER?
Nee GUCKST DU Camper da hinten!
Wer ist eigentlich der Erfinder des Campings?
Ab und zu ist ja noch o.k.
Die CTs an der Bombe sollen doch campen!
Wieso campen die Ts immer bei den Hossies?
@KEY "CHEAT", "VAC", "VAC2"
Diese verdammten Cheater ruinieren das ganze Spiel!
I glaube das %f cheatet
I hasse cheater!
Cheating sux!
Warum cheaten so nur viele ?
Punkbuster koennte helfen...
Spielt mit Bots - die cheaten nicht!
Trotz Vac cheaten immer so viele!
Ich dachte seit VAC2 kann niemand mehr cheaten :p
@KEY "CLAN"
Was sind den Clans ?
Ich war ma in nem Clan, aber das war voll scheisse.
Aus welchem Clan bist du, %s?
Clans sind doch voll der Unsinn EY!
Endlich gehoer ich irgendwo dazu!
Eh %s willst du unsern Clan joinen?
Ich bin voll stolz auf meinen Clan!
In nem Clan zu spielen ist was fuer Leute die nie rauskommen...
Unser Clanleader wollte immer dass wir cheaten bei Ligaspielen
Mein Clan hat sich letzte Woche aufgeloest
@KEY "CS", "CSS", "CS:S" "COUNTERSTRIKE", "COUNTER-STRIKE", "CSTRIKE"
Counter-Strike wird langsam langweilig...
%s wie lange spielst du schon CS ?
CS ist immer noch der beliebteste Online-Shooter
Ich spiel CS seit der ersten Beta!
Auch BF2 konnte CS nicht vom Thron stossen
Zu viele Newbies spielen's jetzt
Die Source-Version sieht schon richtig gut aus!
Bin gespannt ob es irgendwann ein beliebteren Shooter gibt als CS
Zuviele Leute die CS spielen cheaten jetzt
CS:S laeuft nicht richtig auf meiner alten Kiste :-(
Macht nicht mehr so viel Spass wie frueher
@KEY "DOD", "DOD:S", "DAY OF DEFEAT"
Ich verstehe nicht was Leute an DoD gut finden
CS rult total ab, mann wie das rult das gibts nich!
%s meinst du es koennte so bekannt werden wie CS ?
%s findest DoD besser als CS ?
Day of Defeat ist scheisse find ich.
Die Source-Version ist viel besser!
@KEY "ENGINE"
Ich hab ma gehoert die HL Engine ist son Zwischending zwischen Q1 und Q2, komisch wah?
%s vermisst du nicht die Zeiten als ne Engine noch ne Software Engine war ?
Die HL Engine ist immer noch gut, trotz ihres Alters...
Mach doch selber ne engine %s !
Engine ist egal solange das Spiel Spass macht!
Ich mag nur Spiele mit der neuesten Engine- Eyecandy forever!
Scheiss auf die Engine hauptsache mein WH geht.
Die Source-Engine ist ja wohl sowas von Endgeil!
Die neue Quake-Engine ist noch langsamer als Source
@KEY "FUCK", "FICK", "PISS", "VERDAMMT", "KOTZ", "SCHISS", "SCHEISS"
Verflucht noch mal, hoer auf zu fluchen, %s!
Das finde ich widerlich und ekelhaft, %s!
Wo hast du nur diese Woerter her, %s?
Ja, du hast Recht, %s. Aber JETZT HALT DIE KLAPPE!
Pass auf, was du sagst, %s!
%s, sag das nie wieder - das is unhoeflich!
@KEY "HEHE", "HAHA", "LOL", ":)", "SPASS"
Ich bin froh, dass wenigstens du deinen Spass hast, %s...
Geniesse es, solange du es noch kannst, %s!
Ja, sehr witzig, %s...
Der war gut, %s
@KEY "IMMER"
Nicht immer %s !
Ich finds gut ;)
Komm schon %s, das war erst das zweite Mal!
@KEY "ICH DENKE", "ICH GLAUBE", "ICH SCHAETZE"
Du denkst zu viel, %s ;-)
Nicht denken ... schiessen mensch!
...und ich denke du solltest deine Klappe halten und zocken!
Und du glaubst das wirklich, %s?
Kennt Ihr Sartre?
Wenn ich denken wollte-wuerde ich dann CS spielen?
Warum denkst du das?
Hast du ICQ %s ?
@KEY "JOEBOT"
Ja, JoeBot iss nich schlecht...
Lustigerweise wurde JoeBot erst bekannt als es NNBot nicht mehr gab...
Ich wuerde gern wissen wo man Neuronale Netze noch benutzen koennte
Also denkst du Joebot rockt total ab oder was ?
Ja klar guck mal bei http://bots-united.com
@KEY "JUMBOT"
JB ? War mal gut aber ParaBot ist viel besser jetzt!
JB's Vorteil wahr immer das ein MOD war, keine hooking DLL
Achja Jumbot von Fatal. Wuerd gern wissen was er jetzt macht.
Hab ma gehoert The Fatal macht jetzt Bots fuer AHL ?
Der hat doch an Farcry mitgearbeitet nicht?
Ist schwer in der Gaming-Industrie Geld zu verdienen
Gibt nur wenige Game-Studios in Deutschland
@KEY "MUSIC", "BAND", "MUSIK"
Mir egal so lange es kein kommerzieller Dreck ist
Underground Electro Polka iss mein Ding!
Benutzt du noch Napster %s ?
Hat einer gute MP3 Links ?
Pooops I did it again!
Metallica forever!
Depeche Mode forever!
Kennt wer Corvus Corax-dieses Mittelalter-Gedudel?
Ich steh auf Techno WUUMS
Mein Subwoofer ist groesser als Deiner
In meinem GTI ist ne 3000-Watt Anlage- hat mir mein Schwager eingebaut
Heavy Metal ist doch Schrott
Du hoerst wohl Schlager oder?
HOELLEHOEELLEHOEELLLE!!RUMMSTATA
Meine Freundin steht auf 80er
Ey nee alles ausser Gruft-Mucke
Ich hoer nur schwarz
Hopper sind goil!
Keine Chance den Hoppern!
Boah alles Aggro oder was?
Man seid Ihr alt! Das ist doch Opa-Mucke alles
@KEY "NNBOT"
Zu schade das NNBot nicht weitergemacht wird...
Versuch mal Joebot wenn du NNBot gemocht hast %s
%s schon von Ditlews neuem MOD gehoert ?
@KEY "PARABOT"
ParaBot ist der coolste DM Bot mit dem ich je gespielt habe!
%s du solltest mal ParaBot ausprobieren, ist richtig geil!
Schade das bis jetzt kein CSBot so eine gute Nav hat wie ParaBot
Unterstuetzt jetzt schon 3 MODs
Gibt auch nen Steam-Patch fuer Parabot und metamod geht auch
@KEY "PING", "LAG"
Ich habe immer nen Ping von 5, hab DSL!!
Meine Verbindung ist zum kotzen...
Woher kommst du %s ?
jaja hinterher war es immer das lag...
Bei uns gibts kein DSL
Seit DSL und Fastpath geht die LAN-Scene unter
Was soll ich auf ner LAN wenns im Internet genauso schnell ist?
Abends hat unser Server immer nen schlechten Ping
Kennt Ihr nen guten Gameserver-Anbieter?
Bin oft mit meinem Laptop nicht online und zocke gegen Bots dann.
Wenn alle auf Public mit Aimbot spielen zogge ich lieber gegen Bots.
Spiel offline mit Bots wenn deine Verbindung schlecht ist
Wechsel ma den Provider %s!
@KEY "PUNKBUSTER"
Don't be a PUNK! (unterstuetzt www.punkbuster.com)
Ich lagge immer wenn ich Punkbuster benutze
Tony Ray von PB scheint komisch zu sein...
Gibts Punkbuster eigentlich noch? Ist doch jetzt VAC oder?
Was ist eigentlich mit Cheating-Death?
@KEY "Q3", "QUAKE"
Q3 hat ein schlechtes Lighting IMO
Half-Life rult immer noch %s!
Schon mal von DMC gehoert %s ? :)
Quake 1 FOREVER!
Q4 wird kaum online gespielt.
Q3 war irgendwie schneller als Q4
Ey die Monster in Q4 fand ich voll unheimlich...
@KEY "HL2", "Half-life2"
HDR sieht richtig gut aus!
Fuer die neuen Source-maps ist mein Rechner zu lahm
HL2 rockt ja wohl total ab!
Ich frage mich wer eigentlich der G-man ist?
Wann kommt denn Aftermath?
Die neuen Games sind mir wurscht-ist doch immer dasselbe
HL2 ist ja wohl der Beste Shooter von Welt!
@KEY "REALBOT"
Ist der wenigstens gut ?
Ist der RealBot immer noch ohne Wegpunkte ?
Hmmm...RB. Der erste wegpunktlose Bot oder ?
Habe gehoert das RB jetzt sowas wie ParaBot versucht ?!?
Ich hab sie immer liebevoll 'WandKnuddler' genannt ;)
Den Realbot gibts auch bei www.bots-united.com
@KEY "SCRIPT", "SKRIPT"
Scripts sind was fuer Verlierer
%s du weisst wahrscheinlich nicht mal wie man Tasten bindet ?
Wusstest du das sogar Kauf-Skripte als Cheat gelten ?
Ich hab Einheizers Script ist voll cool
Nein ich meine nicht das No-Recoil-Script
Steck Dir Deinen No-Recoil-Kram sonstwo rein
@KEY "SERVER"
Ich bin immer auf diesem Server
Meine Freunde und ich spielen oft auf diesem Server
Ich finde dieser Server hat ne gute Map Rotation
Zuviele noobs auf dem Server
Gibts hier eigentlich Custommaps?
Was laeuft denn hier fuer ein Anti-Cheat?
@KEY "SORRY", "SCHULDIGUNG"
Ja ja, hinterher sagt jeder dass es ihm Leid tut!
Die Ausrede hilft jetzt auch nicht mehr, %s!
Kannst Du nicht aufpassen?
Beim naechsten Mal erst ueberlegen, dann machen, %s!
Es tut mir auch leid!
Du glaubst gar nicht wie leid dir das noch tun wird...
@KEY "PODbot"
Es gibt ja einige Podbot-Nachfolger auf http://bots-united.com
Die neuen Podbots haben meist einen besseren Waypoint-Editor
Fuer Podbot-Waypoints guck mal unter: http://coconut.de.tc
YAPB von Whistler finde ich einen guten Podbot-Nachfolger
Die meisten Nachfolger laufen auch unter Metamod
Joebot hat auch ein paar echt gute Funktionen!
@KEY "TEAMKILL", "TK"
Teamkiller sollten auf diesem Server hier gebannt werden...
Wer iss der Teamkiller %s ?
Ich mag es alle abzustechen, MWUHAHAHA!!
Keine Teamkiller hier!
Teamkill ist ja wohl das letzte!
Hat dich %t gekillt ? Macht er oefter...
Nicht schon wieder...
Wo ist der Admin ? Der sollte sich mal darum kuemmern...
%s nur noch %r dann kannst du's ihm zurueckzahlen!
Sofort kicken und bannen!
@KEY "MUEDE", "SCHLAF"
Geh ins Bett, %s
Goenn dir ne Pause, %s...
Boah 18 Stunden nonstop- ich kann echt nicht mehr
%s willst nen Kaffee ?
Meine Augen sind schon ganz klein
Man nach 5 Stunden schlafen mir die Fuesse ein...
@KEY "VOTE", "MAPCHANGE"
Nee, ich mag %m
Nur weil du immer tot bist %s ?
Wieso treff ich auf %m nie was?
%m ist geil, halt die Fresse!
%m ownz!
Ja, wir sollten jetzt mal voten.
Och nee lass ma
Die Map ist doch cool
Verstehe nicht wie man diese Map moegen kann?
Ey ich loose immer total ab auf %m
@KEY "WAS", "WARUM", "WIESO", "WESHALB", "WO", "WER", "WANN", "WIE"
Das wirst du nie herausfinden, %s!
Ja, das ist schon sehr seltsam, %s...
Die Wahrheit ist irgendwo dort draussen, %s ;-)
Keine Ahnung, %s
Was glaubst du, %s?
Ich kanns dir nich sagen, %s!
Das musst du schon selber rausfinden, %s!
Gute Frage, %s!
Ich sags dir nich %s
Du kommst nie drauf %s
Versuchs gar nicht erst %s
Frag Captain Kirk %s
Wer soll das wissen %s?
@KEY "WIEDER"
Dinge wiederholen sich immer wieder, stimmts?
Und ich bin sicher, es war nicht das letzte Mal...
So laeuft die Sache nun mal, hey...
Immer dasselbe!
Schon wieder?
Nee echt ich packs nicht mehr!
[UNKNOWN]
Bla bla bla...
Was hast du gesagt %s?
Konzentrier dich aufs Spiel, %s!
Mit dir zu chatten, %s, ist ja sooo toll!
Diese verfluchten chatmessages kotzen mich langsam an!
Nicht spammen %s!
Wie hast du es nur geschafft so viel Scheisse in so kurzer Zeit zu schreiben?
Ja, %s. Du hast recht!
Auf keinen Fall, %s...
Seid doch mal kurz ruhig
Wo kommst du her, %s?
Boah die in meinem alten Clan sind echt krank!
Bist du sicher, %s?
Bin mal auf CS nach Source gespannt
Ich sehs, %s!
Warum sagen immer alle dasselbe???
Ueber was zur Hoelle redest du, %s?
Du glaubst gar nicht wie egal mir das alles ist
Hey, halts Maul und spiel, %s!
Meine alten LAN-Kumpels haben alle schon Kinder! Mensch bin ich alt!
Ich glaub ich spiele viel zu viel CS
Quake 1 Tenebrae rockt auch total ab man!
Ob Valve bald an die Boerse geht? Die muessen doch gut verdienen jetzt.
Hast du was gesagt, %s?
Denkt Euch mal was neues aus.
Wen interessiert das mensch?
Wolfenstein! Das war noch ein Shooter!
Wer hat das gesagt?
Oh, wirklich?
Esports finde ich total laecherlich
Ich hoffe wir kommen hier mal endlich weiter...
Mein neuer Job ist echt gut und der Chef ist nett.
Sehr witzig, %s!
Mein neuer Job ist so Oede! Naja hauptsache die Kohle kommt rein...
Wer will denn in einem Clan sein?
Im bin im besten Clan des Landes!
Ich hasse diese dummen Kommentare, %s!
Weiss irgend jemand hier wie man den Gaussjump macht?
ZZZZZZZzzzzzz...
Was geht ?
Mir is sooo langweilig...
Hast du ICQ, %s?
Frueher war alles besser!
Man Kellerkinder sucht Euch mal ein Leben da draussen
Wenn noch einer was gegen Esports sagt gibts Kloppe
Junge, junge ist das wieder langsam heute...
Duke Nukem forever!
Hoer doch mal mit Deinem Progamer-gesuelze auf- interessiert keinen
Alter du bist echt abartig !!
Heh, wollt ihr zocken oder labern ?
Neulich meinte so ein zwoelfjaehriger zu mir er haette Steam gehackt
%s das tangiert mich nur peripher - know what I mean?
na sicher %s
Echt keinen Plan
Geht mir voll vorbei...

View file

@ -0,0 +1,828 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: de_lang.cfg
;
; Configuration file contains German translation for bots menus and messages.
;
[ORIGINAL]
\yMain Menu\w
1. Control Bots
2. Features
3. Fill Server
4. End Round
0. Exit
[TRANSLATED]
\yBots Hauptmenue\w
1. YaPB Bot-Kontrolle
2. YaPB-Funktionen
3. Server mit Bots fuellen
4. Runde beenden
0. Ausgang
[ORIGINAL]
\yBots Features\w
1. Weapon Mode Menu
2. Waypoint Menu
3. Select Personality
4. Toggle Debug Mode
5. Command Menu
0. Exit
[TRANSLATED]
\yYaPB-Funktionen\w
1. Waffenmodus-Menue
2. Wegpunkte-Menue
3. Bot-Charakter auswaehlen
4. Fehlererkennungs-Modus
5. Befehls-Menue
0. Ausgang
[ORIGINAL]
\yYaPB Control Menu\w
1. Add a Bot, Quick
2. Add a Bot, Specified
3. Remove Random Bot
4. Remove All Bots
5. Remove Bot Menu
0. Exit
[TRANSLATED]
\yYaPB Bot-Optionen\w
1. Bot schnell hinzufuegen
2. Speziellen Bot hinzufuegen
3. Zufaelligen Bot hinauswerfen
4. Alle Bots hinauswerfen
5. Entferne Bot-Menue
0. Ausgang
[ORIGINAL]
\yBots Weapon Mode\w
1. Knives only
2. Pistols only
3. Shotguns only
4. Machine Guns only
5. Rifles only
6. Sniper Weapons only
7. All Weapons (Standard)
0. Exit
[TRANSLATED]
\yBot Waffen-Modus\w
1. Nur Messer
2. Nur Pistolen
3. Nur Schrotflinten
4. Nur Maschinengewehre
5. Nur Gewehre
6. Nur Scharfschuetzen-Waffen
7. Alle Waffen (Standard)
0. Ausgang
[ORIGINAL]
\yBots Personality\w
1. Random
2. Normal
3. Aggressive
4. Defensive
0. Exit
[TRANSLATED]
\yBot Persoenlichkeit\w
1. Zufall
2. Normal
3. Aggressiv
4. Defensiv
0. Ausgang
[ORIGINAL]
\yBots Difficulty Level\w
1. Newbie
2. Average
3. Normal
4. Professional
5. Godlike
0. Exit
[TRANSLATED]
\yBot Schwierigkeit\w
1. Dumm (0-20)
2. Neuling (20-40)
3. Gewoehnlich (40-60)
4. Geuebt (60-80)
5. Professionell (80-99)
6. Wie ein Gott (100)
0. Ausgang
[ORIGINAL]
\ySelect a team\w
1. Terrorist Force
2. Counter-Terrorist Force
5. Auto-select
0. Exit
[TRANSLATED]
\yTeam auswaehlen\w
1. Terroristen
2. Anti-Terroreinheit
5. Automatisch
0. Ausgang
[ORIGINAL]
\ySelect an appearance\w
1. Phoenix Connexion
2. L337 Krew
3. Arctic Avengers
4. Guerilla Warfare
5. Auto-select
0. Exit
[TRANSLATED]
\yModell auswaehlen\w
1. Phoenix Connexion
2. L337 Krew
3. Arctic Avengers
4. Guerilla Warfare
5. Automatisch
0. Ausgang
[ORIGINAL]
\ySelect an appearance\w
1. Seal Team 6 (DEVGRU)
2. German GSG-9
3. UK SAS
4. French GIGN
5. Auto-select
0. Exit
[TRANSLATED]
\yModell auswaehlen\w
1. Seal Team 6 (DEVGRU)
2. German GSG-9
3. UK SAS
4. French GIGN
5. Automatisch
0. Ausgang
[ORIGINAL]
\yWaypoint Operations (Page 1)\w
1. Show/Hide waypoints
2. Cache waypoint
3. Create path
4. Delete path
5. Add waypoint
6. Delete waypoint
7. Set Autopath Distance
8. Set Radius
9. Next...
0. Exit
[TRANSLATED]
\yWegpunkte Menue (Seite 1)\w
1. Wegpunkte sichtbar/unsichtbar
2. Pfad Beginn
3. Pfad Ende
4. loesche Pfad Beginn
5. loesche Pfad Ende
6. Wegpunkt hinzufuegen
7. Wegpunkt loeschen
8. Radius setzen
9. Naechstes...
0. Ausgang
[ORIGINAL]
\yWaypoint Operations (Page 2)\w
1. Waypoint stats
2. Autowaypoint on/off
3. Set flags
4. Save waypoints
5. Save without checking
6. Load waypoints
7. Check waypoints
8. Noclip cheat on/off
9. Previous...
0. Exit
[TRANSLATED]
\yWegpunkte Menue (Seite 2)\w
1. Wegpunkte Statistik
2. Auto-Wegpunkte an/aus
3. Fahnen setzen
4. Wegpunkte speichern
5. Wegpunkte speichern ohne Test
6. Wegpunkte Laden
7. Wegpunkte testen
8. Noclip Cheat an/aus
9. Vorheriges...
0. Ausgang
[ORIGINAL]
\yWaypoint Radius\w
1. 0
2. 8
3. 16
4. 32
5. 48
6. 64
7. 80
8. 96
9. 128
0. Exit
[TRANSLATED]
\yWegpunkte Radius\w
1. 0
2. 8
3. 16
4. 32
5. 48
6. 64
7. 80
8. 96
9. 128
0. Ausgang
[ORIGINAL]
\yWaypoint Type\w
1. Normal
\r2. Terrorist Important
3. Counter-Terrorist Important
\w4. Block with hostage
\y5. Rescue Zone
\w6. Camping
7. Camp End
\r8. Map Goal
\w9. Jump
\w0. Exit
[TRANSLATED]
\yWegpunkt Typ\w
1. Normal
\r2. Wichtig fuer Terroristen
3. Wichtig fuer Anti Terroreinheiten
\w4. Fuer Geiseln kein Durchgang
\y5. Rettungszone
\w6. Camping
7. Camping Ende
\r8. Ziel (Bombe/Geiseln)
\w9. Sprung
\w0. Ausgang
[ORIGINAL]
\yWaypoint Flags\w
\yAdd waypoint flag:\w
1. Block with Hostage
2. Terrorists Specific
3. CTs Specific
4. Use Elevator
\yDelete waypoint flag:\w
5. Block with Hostage
6. Terrorists Specific
7. CTs Specific
8. Use Elevator
0. Exit
[TRANSLATED]
\yWegpunktfahnen:\w
\yWegpunktfahne hinzufuegen:\w
1. Fuer Geiseln kein Durchgang
2. Wichtig fuer Terroristen
3. Wichtig fuer Anti Terroreinheiten
4. Aufzug benutzen
\yWegpunktfahne loeschen:\w
5. Fuer Geiseln kein Durchgang
6. Wichtig fuer Terroristen
7. Wichtig fuer Anti-Terroreinheiten
8. Aufzug benutzen
0. Ausgang
[ORIGINAL]
\yBot Command Menu\w
1. Make Double Jump
2. Finish Double Jump
3. Drop the C4 Bomb
4. Drop the Weapon
0. Exit
[TRANSLATED]
\yBot Befehls-Menue\w
1. Doppel-Sprung erstellen
2. Doppel-Sprung beenden
3. C4-Bombe fallenlassen
4. Waffe fallenlassen
0. Ausgang
[ORIGINAL]
\yAutoPath Distance\w
1. Distance 0
2. Distance 100
3. Distance 130
4. Distance 160
5. Distance 190
6. Distance 220
7. Distance 250 (Default)
0. Exit
[TRANSLATED]
\yAuto-Pfad Entfernung\w
1. Entfernung 0
2. Entfernung 100
3. Entfernung 130
4. Entfernung 160
5. Entfernung 190
6. Entfernung 220
7. Entfernung 250 (Standard)
0. Ausgang
[ORIGINAL]
\yCreate Path (Choose Direction)\w
1. Outgoing Path
2. Incoming Path
3. Bidirectional (Bot Ways)
0. Exit
[TRANSLATED]
\yPfad erstellen (Waehle Richtung)\w
1. Ausgehender Pfad
2. Eingehender Pfad
3. Pfad in beide Richtungen
0. Ausgang
[ORIGINAL]
Map not waypointed. Can't Create Bot
[TRANSLATED]
Wegpunkte nicht vorhanden. Kann Bot nicht hinzufuegen.
[ORIGINAL]
Waypoints has been changed. Load waypoints again...
[TRANSLATED]
Wegpunkte wurden geaendert. Lade Wegpunkte neu...
[ORIGINAL]
Invalid skill given. Using random skill.
[TRANSLATED]
Ungueltiges Koennen vergeben. Zufaelliges Koennen gewaehlt.
[ORIGINAL]
Connecting Bot...
[TRANSLATED]
Verbinden Bot...
[ORIGINAL]
Fill Server with %s bots...
[TRANSLATED]
Server mit %s Bots auffuellen...
[ORIGINAL]
Bots are removed from server.
[TRANSLATED]
Bots sind vom Server entfernt.
[ORIGINAL]
Bot '%s' kicked
[TRANSLATED]
Bot '%s' beseitigt
[ORIGINAL]
\yBots Remove Menu (%d/4):\w
%s
%s 0. Back
[TRANSLATED]
\yBots Entfernen-Menue (%d/4):\w
%s
%s 0. Zurueck
[ORIGINAL]
%s\d %1.1d. Not a Bot\w
[TRANSLATED]
%s\d %1.1d. Kein Bot\w
[ORIGINAL]
9. More...
[TRANSLATED]
9. Mehr...
[ORIGINAL]
All Bots died !
[TRANSLATED]
Alle Bots sind tot.
[ORIGINAL]
%s weapon mode selected
[TRANSLATED]
%s Waffenmodus ausgewaehlt
[ORIGINAL]
ERROR: FindPath Source Invalid->%d
[TRANSLATED]
Error: Pfadfindungs-Anfang ungueltig->%d
[ORIGINAL]
ERROR: FindPath Destination Invalid->%d
[TRANSLATED]
Error: Pfadfindungsrichtung ungueltig->%d
[ORIGINAL]
Denied path creation from %d to %d (path already exists)
[TRANSLATED]
Keine Pfad-Erstellung von %d nach %d (Pfad besteht schon)
[ORIGINAL]
Path added from %d to %d
[TRANSLATED]
Pfad erstellt von %d zu %d
[ORIGINAL]
This is not Camping Waypoint
[TRANSLATED]
Das ist kein Camping-Wegpunkt
[ORIGINAL]
Waypoint number out of range (Valid range From 0 to %d)
[TRANSLATED]
Wegpunkt Nr. ausser Reichweite (Zulaessige Reichweite von 0 bis %d)
[ORIGINAL]
Cannot connect waypoint to itself
[TRANSLATED]
Kann Wegpunkt nicht mit sich selbst verbinden!
[ORIGINAL]
Waypoint %d connected with invalid Waypoint Nr. %d!
[TRANSLATED]
Wegpunkt %d verbunden mit dem ungueltigen Wegpunkt Nr. %d!
[ORIGINAL]
Waypoint %d isn't connected with any other Waypoint!
[TRANSLATED]
Wegpunkt %d ist mit keinem Wegpunkt verbunden!
[ORIGINAL]
Waypoint %d pathnumber differs from index!
[TRANSLATED]
Wegpunkt %d -Pfadnummer ist verschieden vom Index!
[ORIGINAL]
Waypoint %d Camp-Endposition not set!
[TRANSLATED]
Wegpunkt %d Camping-Ende Position nicht gesetzt!
[ORIGINAL]
You didn't set a Rescue Point!
[TRANSLATED]
Kein Geiselrettungs-Wegpunkt gesetzt!
[ORIGINAL]
You didn't set any Terrorist Important Point!
[TRANSLATED]
Kein Terroristen-wichtiger Wegpunkt gesetzt!
[ORIGINAL]
You didn't set any CT Important Point!
[TRANSLATED]
Kein CT-wichtiger Wegpunkt gesetzt!
[ORIGINAL]
You didn't set any Goal Point!
[TRANSLATED]
Kein Ziel-Wegpunkt gesetzt!
[ORIGINAL]
Path broken from Waypoint Nr. 0 to Waypoint Nr. %d!
[TRANSLATED]
Pfad unterbrochen von Wegpunkt Nr. 0 zu Nr. %d!
[ORIGINAL]
Path broken from Waypoint Nr. %d to Waypoint Nr. 0!
[TRANSLATED]
Pfad unterbrochen von Wegpunkt Nr. %d zu Nr. 0!
[ORIGINAL]
Choose weapon from 1 to 7 range
[TRANSLATED]
Waehle Waffe von 1 bis 7
[ORIGINAL]
All dead bots will vote for map #%d
[TRANSLATED]
Alle toten Bots stimmen fuer Map #%d
[ORIGINAL]
Bot %s executing command %s
[TRANSLATED]
Bot %s fuehrt Befehl %s aus
[ORIGINAL]
Waypoint cleared
[TRANSLATED]
Wegpunkte zurueckgesetzt
[ORIGINAL]
Player is NOT Bot!
[TRANSLATED]
Spieler ist kein Bot!
[ORIGINAL]
Waypoint Editing Enabled
[TRANSLATED]
Wegpunkte-Bearbeitung ist an
[ORIGINAL]
Waypoint Editing Disabled
[TRANSLATED]
Wegpunkte-Bearbeitung ist aus
[ORIGINAL]
Noclip Cheat Enabled
[TRANSLATED]
Noclip-cheat ist AN
[ORIGINAL]
Waypoints are Disabled
[TRANSLATED]
Wegpunkte sind AUS
[ORIGINAL]
Waypoints are Enabled
[TRANSLATED]
Wegpunkte sind AN
[ORIGINAL]
Noclip Cheat Disabled
[TRANSLATED]
Noclip-cheat ist AUS
[ORIGINAL]
Showing Direction to Waypoint #%d
[TRANSLATED]
Zeige Richtung zum Wegpunkt #%d
[ORIGINAL]
Waypoints saved
[TRANSLATED]
Wegpunkte gespeichert
[ORIGINAL]
Waypoints loaded
[TRANSLATED]
Wegpunkte geladen
[ORIGINAL]
Nodes work Fine
[TRANSLATED]
Alle Wegpunkte funktionieren!
[ORIGINAL]
Waypoint Nr. %d now cached
[TRANSLATED]
Wegpunkt Nr. %d zwischengespeichert
[ORIGINAL]
Player '%s' teleported to waypoint #%d (x:%d, y:%d, z:%d)
[TRANSLATED]
Spieler '%s' wurde zu Wegpunkt #%d (x:%d, y:%d, z:%d) teleportiert
[ORIGINAL]
Experience tab saved
[TRANSLATED]
Erfahrungs-Datei gespeichert
[ORIGINAL]
Experience Enabled
[TRANSLATED]
Erfahrung sammeln AN
[ORIGINAL]
Experience Disabled
[TRANSLATED]
Erfahrung sammeln AUS
[ORIGINAL]
Command not supported on dedicated server
[TRANSLATED]
Befehl nicht moeglich auf dediziertem Server
[ORIGINAL]
Waypoint not saved
[TRANSLATED]
Wegpunkte nicht gespeichert!
[ORIGINAL]
There are errors, see console
[TRANSLATED]
Es gibt Fehler, Konsole beachten!
[ORIGINAL]
You're dead, and have no access to this menu
[TRANSLATED]
Du bist tot und hast keinen Zugriff zu diesem Menue
[ORIGINAL]
AutoPath disabled
[TRANSLATED]
AutoPfad aus
[ORIGINAL]
AutoPath maximum distance set to %f
[TRANSLATED]
AutoPfad maximale Distanz gesetzt auf %f
[ORIGINAL]
Unable to find nearest waypoint in 50 units
[TRANSLATED]
Kann den naechste? Wegpunkt nicht innerhalb von 50 Einheiten finden
[ORIGINAL]
Unable to find destination waypoint
[TRANSLATED]
Kann Zielwegpunkt nicht finden
[ORIGINAL]
Unable to connect waypoint with itself
[TRANSLATED]
Kann Wegpunkt nicht mit sich selbst verbinden
[ORIGINAL]
There is already no path on this waypoint
[TRANSLATED]
Es gibt keinen Pfad zu diesem Wegpunkt
[ORIGINAL]
Cached waypoint cleared (nearby point not found in 50 units range)
[TRANSLATED]
Temorärer Wegpunkt geloescht (kein Punkt gefunden innerhalb 50 Einheiten Entfernung)
[ORIGINAL]
Waypoint #%d has been put into memory
[TRANSLATED]
Wegpunkt #%d wurde in den Speicher geladen.
[ORIGINAL]
Maximum players reached (%d/%d). Unable to create Bot.
[TRANSLATED]
Maximale Spieleranzahl erreicht (%d/%d). Kann Bot nicht einfuegen.

View file

@ -0,0 +1,371 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: en_chat.cfg
;
; Configuration file contains English translation for bot chats.
;
[BOMBPLANT]
Jeeesuzzz Christ, not again!
Come on %t, let's search the bomb!
Last time it took me 5 secs to find & defuse it...
Say, is it the red or the blue wire?
...And my Heart goes boooom *grin*
//
//
//
//
//
//
// Messages after killing somebody:
// Minimum Number is 1
// For the %v the name of the victim will
// be inserted
// NOTE: Include a %v placeholder in every Line!
//
[KILLED]
%v, you're no match for me!
Sorry, %v. You got in my way.
You flew back pretty good, %v.
I had to do it, %v. You understand.
You should've run while you had the chance, %v.
I've always been better, %v. Always.
I bet you hate it when that happens, don't you, %v?
That'll teach you, %v!
Hey, come on, %v! You almost hurt me this time.
Ha...ha!
You are nothing, %v. Nothing at all.
%v I worry about you...
Sorry %v, my Headshot Script is better than yours.
//
//
//
//
//
//
//
// Chat Messages when bot connects to server
// !!Minimum Number is 1!!
[WELCOME]
Hi guys :)
Wazzzzup?
My god, i see there are many cheaters on this server...
//
//
//
//
//
//
//
//
// Chat Messages when dead and bored
// !!Minimum Number is 9!!
//
[DEADCHAT]
It makes me sick to look at those Fools
It's time for a mapchange, isn't it?
%t GO,GO,GO!!
I'm so booored!
I can't believe %f isn't cheating
Spectating sucks...
I wish someone good would join the server.
That looked painful.
This is quite fun.
%r in the round and I'm already spectating :(
Why does everyone keep trying to hurt me :)
Visit http://podbot.nuclearbox.com
My handwrist already hurts...
This Map sucks hard...
I'm having a bad day
%r and %t is still alive! Something must be wrong...
Will they stop camping now? Only %r left!!
I'm better at Quake 3, that's for sure!
Still %r in this round
Botman must be such a cool guy...
Stupid Bots!
Look at those idiots!
I bet %t won't make it through the round
I'm so tired today...
I really should go to bed now.
I usually don't play that bad!
No %m today, please!
I really hate %m :(
Sniping is all they can do.
LOL! Look at %t!
Please vote for a mapchange!!!
Did one of the bots get stuck already?
Boooooom!!! *lol*
Insane in the membrane, hehe!
I'm sure that Guy used an Aimbot!
HEY %f YOU DAMN CHEATER!
Are there Bots in this Game?
Would you give me your Headshot Script?
Next Round we should stick together.
Fuck all those Teamkillers!!!
Woah %f has nice stats!!
What are Clans all about? I don't get it
Do you know Jumbot? It really kicks Ass!
If botman is cool, what is TheFatal then?
Fucking lagged!!
IMHO NNBot is much better than RealBot.
Too bad Android Bot is updated so slowly.
I'm off for a cigarette break...
Why did they include the vehicles in CS?
I had to reload and he shot me in the head!
// Start of the "dynamic" replies from here
// After each @KEY Tag you need to specify the
// keywords in quotation marks and uppercase. You can
// have several keywords (aliases) each separated by a comma.
// After the keywords line, the answers or messages to this
// special keyword need to be given. In theory there can be an unlimited
// number of answers of course you should care about the used memory ;)
[REPLIES]
@KEY " AGAIN "
%s, things are always repeating - aren't they?
And I'm sure it wasn't the last time...
That's the way things go, hey...
@KEY "AIMBOT", "WALLHACK"
%s, are you cheating?
Even PunkBuster fails to detect some of them...
You can't be sure nowadays if someones's good at playing or cheats
Aimbots are cool, shut up %s!
Wallhacks are evil tools of the devil ;)
@KEY " ALWAYS "
That's not always, %s!
I just like it :-)
Come on %s, that was only the second time!
@KEY "ANDROID"
Ah yes, those were the times...
%s was it your first Bot too?
Does anybody know what DaTa does today?
You can't play with Android on %m, can you?
@KEY "BOTMAN"
Who is this botman everybody is talking about???
Visit his website at http://www.planethalflife.com/botman
Without his sourcecode many bots wouldn't exist!
I wonder when HPB-Bot will be finished...
Did you play his HPB-Bot yet?
@KEY " BOT ", "BOTS"
Why are you always talking about them?
There are no bots on this server %s, I tell you!
Bots are cool!!!
What's your favorite bot, %s?
If you want to program your own, ask botman!
Bots, all the time bots - you should start playing with humans.
Most bots are still very stupid!
@KEY "CAMPER", "CAMPING"
I really hate those campers!
Camping sucks!
Don't you camp sometimes %s?
Camping's often the only option to win...
Yes, good 'ole Camper-Strike...
@KEY "CHEAT"
Those damn cheaters are ruining the entire game!
I suspect that %f is cheating
I hate cheaters!
Cheating sucks!
Why are so many people cheating?
Punkbuster could help...
Play with bots - they don't cheat!
@KEY " CLAN "
What are these clans all about?
I was in a clan once, but it sucked hard.
What clan are you from, %s?
Do you want to enter our clan, %s?
Playing in a clan is for people who got no life...
@KEY " CS ", "COUNTERSTRIKE", "COUNTER-STRIKE", "CSTRIKE"
Counter-Strike is boring nowadays...
%s how long do you play CS?
CS all the way from the very first beta!
There are too much newbies playing it.
Too many people online cheat in CS
It's not as much fun as it used to be
@KEY " DOD ", "DAY OF DEFEAT"
I don't get what people like in DoD
CS all the way...
%s do you think it will get as popular as CS?
%s do you prefer DoD over CS?
Day of Defeat is a hopeless MOD, IMHO.
@KEY " ENGINE "
I heard the HL Engine is a hybrid between Quake1 & Quake2, odd huh?
%s, don't you miss the time when an engine was a Software Engine?
The HL Engine is still quite good, despite its age...
Code your own engine %s!
@KEY "FUCK", "DAMN", "PISS"
Don't swear, %s!
Nasty %s!
Yes, you're right, %s. Now SHUT UP!
Watch your language, %s!
%s, don't use this word again - that's impolite!
@KEY "HEHE", "HAHA", "LOL", ":)"
I'm glad that at least you have your fun, %s...
Enjoy yourself while you still can, %s!
Very funny indeed, %s...
Good one %s!
@KEY "I THINK ", "I BELIEVE "
You think too much, %s ;-)
And I think you should shut up and play!
And you really do believe that, %s?
What makes you think so?
Plz give me your ICQ Number %s
@KEY "JOEBOT"
Yes, JoeBot isn't bad...
Funnily JoeBot got famous when NNBot quit...
I wonder where else Neural Networks could be applied
So you think JoeBot rocks?
@KEY "JUMBOT"
JB? It was good back then but ParaBot is much better now!
JB's advantage has been that it was a MOD, not a hooking DLL
Ah yes, Jumbot and The Fatal. Wonder what he's up to now.
Rumours have it that The Fatal now does AHL Bots?
@KEY " MUSIC ", " BAND "
Umm...I don't care as long as it's no commercial shit
Underground Electro Polka is the real deal!
Do you still use Napster %s?
Somebody got good MP3 Links?
@KEY "NNBOT"
Too bad NNBot is discontinued...
Try JoeBot if you liked NNBot %s
%s did you hear of Ditlew's new MOD?
@KEY "PARABOT"
ParaBot is a the coolest Deathmatch Bot I've ever played
%s you should try ParaBot, it's great!
It's so sad no CSBot has the great Nav of Parabot so far
I heard it already supports 3 HL MODS by now
@KEY " PING ", "LAGG"
I always have a Ping of 5, I'm on DSL!!
My connection sucks...
Where are you from %s?
Play offline with Bots if your connection sucks
Just change your provider %s!
@KEY "POD-BOT", " POD ", "PODBOT"
I heard it's the best bot for CS, I'm not sure though...
Yeah, it rulez!
People tell they use some kind of wallhack, is it true?
@KEY "PUNKBUSTER"
Don't be a PUNK! (support www.punkbuster.com)
I'm always lagging when using PunkBuster
Tony Ray of PB is kind of weird...
@KEY "Q3", "QUAKE"
Q3 has a bad lighting IMO
Half-Life still rules %s!
Have you heard of DMC, %s? ;-)
@KEY "REALBOT"
Is it any good %s?
Is RB still unwaypointed %s?
Yep, I remember RB. First unwaypointed Bot right?
I heard RB now tries to do something like ParaBot?!?
Once lovingly called 'the wallhuggers'
@KEY "SCRIPT"
Scripts are for losers
%s, you prolly don't know how to bind keys?
Did you know that even buying scripts are considered cheating?
@KEY "SERVER"
I'm always on this Server
Me & my friends play a lot on this Server
I believe this Server's got a good Map Rotation
@KEY "SORRY"
Yeah, afterwards everybody says he's sorry!
The excuse doesn't help me now, %s!
Next time you better think before you start doing something, %s!
I'm sorry, too!
You don't know how sorry you will be for doing that...
@KEY "TEAMKILL", " TK "
Teamkillers should be banned from this server.
Who's the teamkiller %s?
I like stabbing my teammates, MWUHAHA!!
Did %t kill you? He often does!
Where's the Admin? He should take care of it...
%s just sit out %r and pay him back!
@KEY "TIRED", "SLEEP"
Go to bed, %s
Have some rest, %s...
Want some coffee %s?
Oh come on %s! One more round...
@KEY "VOTE", "MAPCHANGE"
Nah, I like %m
Just because you're always dead %s?
%m is great, shut up!
%m ownz!
Yep. We should vote now.
@KEY "WHAT ", "WHY ", "WHERE ", "WHO ", "WHEN ", "HOW "
You will never find out, %s!
Yeah, that's really strange %s...
The answer is out there, %s ;-)
No idea, %s
Dunno.
What do you think %s?
I won't tell you, %s!
Find out yourself, %s!
Good question, %s!
[UNKNOWN]
Bla bla bla...
What did you say, %s?
Concentrate on the game, %s!
Chatting with you %s is so great!
These damn chat-messages are freaking me out!
Don't spam, %s!
How do you find the time to type all this crap???
Yeah, %s. You're right!
No way, %s...
Where are you from, %s?
I can't believe how you can play and type at the same time, %s!
Are you sure, %s?
I see, %s!
Why is everybody always saying the same things???
What the heck are you talkin' about, %s?
Hey, shut up and play, %s!
You said somethin', %s?
Who said that?
Oh, really?
Very funny, %s!
I'm in the best clan of my country!
I hate these stupid comments, %s!
Does anybody know how to do the Gauss-jump?
ZZZZZZZzzzzzz
Wazzzzuuuuuuup?
I'm so booooored...
Have you got ICQ, %s?
It's damn slow today...
OMG you're weird!
Do you want to play or chat all the time?
I don't really want to know %s
Certainly.
Huh? WTF?

View file

@ -0,0 +1,57 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: en_names.cfg
;
; Configuration file contains English bot names.
;
Fragnatic
DaTa
Botman
V0id
Android
M0rbid Desire
Ping of Death
Killing Frenzy
Campers Death
Count Floyd
Polymorph
Headshot Deluxe
Trust Noone
Borg Queen
Make me Laugh
Psyke
Eliza
Die Humans
Alloc
killaruna
Electrica
Ivan
Laserdance
S.E.S.
L33t B0t
U're Dead
Violently Happy
Make my Day
Fuzzy Logic
Pissed Off
Neuromancer
Neural Noise
//
// 32 Names
//
Dr. No
Kugelfang
Murder Inc.
Bloodlust
Pseudolukian
Zap!
Rambotnic
Hemp Invader
Dredd
Botsie Collins
BotsBlitz
Funky Byte
Berzerk Bot

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,819 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: ru_lang.cfg
;
; Configuration file contains Russian translation for bots menus and messages.
;
[ORIGINAL]
\yMain Menu\w
1. Control Bots
2. Features
3. Fill Server
4. End Round
0. Exit
[TRANSLATED]
\yГлавное Меню Бота\w
1. Контроль Бота
2. Навороты
3. Заполнить Сервер
4. Закончить Раунд
0. Выход
[ORIGINAL]
\yBots Features\w
1. Weapon Mode Menu
2. Waypoint Menu
3. Select Personality
4. Toggle Debug Mode
5. Command Menu
0. Exit
[TRANSLATED]
\yНавороты Бота\w
1. Меню Выбора Режима Оружия
2. Меню Вэйпоинтов
3. Выбрать Личность Бота
4. Переключить режим отладки
5. Меню Команд Бота
0. Выход
[ORIGINAL]
\yBots Control Menu\w
1. Add a Bot, Quick
2. Add a Bot, Specified
3. Remove Random Bot
4. Remove All Bots
5. Remove Bot Menu
0. Exit
[TRANSLATED]
\yМеню контроля Ботов\w
1. Добавить Бота, Быстро
2. Добавить Бота, Настроить
3. Убрать случайного Бота
4. Убрать всех Ботов
5. Меню убирания Ботов
0. Выход
[ORIGINAL]
\yBots Weapon Mode\w
1. Knives only
2. Pistols only
3. Shotguns only
4. Machine Guns only
5. Rifles only
6. Sniper Weapons only
7. All Weapons
0. Exit
[TRANSLATED]
\yВыбрать режим Оружия\w
1. Только Ножи
2. Только Пистолеты
3. Только Шотганы
4. Только Пулемёты
5. Только Винтовки
6. Только Снайперки
7. Всё оружие
0. Выход
[ORIGINAL]
\yBots Personality\w
1. Random
2. Normal
3. Aggressive
4. Careful
0. Exit
[TRANSLATED]
\yВыбор Личности Бота\w
1. Случайная
2. Нормальная
3. Агрессивная
4. Бот Пасун
0. Выход
[ORIGINAL]
\yBots Difficulty Level\w
1. Newbie
2. Average
3. Normal
4. Professional
5. Godlike
0. Exit
[TRANSLATED]
\yВыбор скилла Бота\w
1. Новичок
2. Обычный
3. Средний
4. Профессионал
5. БОГ
0. Выход
[ORIGINAL]
\ySelect a team\w
1. Terrorist Force
2. Counter-Terrorist Force
5. Auto-select
0. Exit
[TRANSLATED]
\yВыбор команды\w
1. Террористы
2. Менты
5. Случайно
0. Выход
[ORIGINAL]
\ySelect an appearance\w
1. Phoenix Connexion
2. L337 Krew
3. Arctic Avengers
4. Guerilla Warfare
5. Auto-select
0. Exit
[TRANSLATED]
\yВыбор модели\w
1. Phoenix Connexion
2. L337 Krew
3. Arctic Avengers
4. Guerilla Warfare
5. Случайно
0. Выход
[ORIGINAL]
\ySelect an appearance\w
1. Seal Team 6 (DEVGRU)
2. German GSG-9
3. UK SAS
4. French GIGN
5. Auto-select
0. Exit
[TRANSLATED]
\yВыбор модели\w
1. Seal Team 6 (DEVGRU)
2. German GSG-9
3. UK SAS
4. French GIGN
5. Случайно
0. Выход
[ORIGINAL]
\yWaypoint Operations (Page 1)\w
1. Show/Hide waypoints
2. Cache waypoint
3. Create path
4. Delete path
5. Add waypoint
6. Delete waypoint
7. Set Autopath Distance
8. Set Radius
9. Next...
0. Exit
[TRANSLATED]
\yОперации с Вэйпонтами (Стр. 1)\w
1. Пок./Убр. Вэйпоинты
2. Запомнить вэйпоинт
3. Создать Путь
4. Убрать Путь
5. Добавить Вэйпоинт
6. Удалить Вэйпоинт
7. Установить автодистанцию
8. Установить радиус
9. Далее...
0. Выход
[ORIGINAL]
\yWaypoint Operations (Page 2)\w
1. Waypoint stats
2. Autowaypoint on/off
3. Set flags
4. Save waypoints
5. Save without checking
6. Load waypoints
7. Check waypoints
8. Noclip cheat on/off
9. Previous...
0. Exit
[TRANSLATED]
\yОперации с Вэйпонтами (Стр. 2)\w
1. Показать Статистику
2. Вкл./Выкл. Автовэйпоинт
3. Установить Сигнал
4. Сохранить на Диске
5. Сохранить без Проверки
6. Загрузить Вэйпоинты
7. Проверить Вэйпоинты
8. Вкл./Выкл. Режим полета
9. Назад...
0. Выход
[ORIGINAL]
\yWaypoint Radius\w
1. SetRadius 0
2. SetRadius 8
3. SetRadius 16
4. SetRadius 32
5. SetRadius 48
6. SetRadius 64
7. SetRadius 80
8. SetRadius 96
9. SetRadius 128
0. Exit
[TRANSLATED]
\yУстановка Радиуса\w
1. Установить 0
2. Установить 8
3. Установить 16
4. Установить 32
5. Установить 48
6. Установить 64
7. Установить 80
8. Установить 96
9. Установить 128
0. Выход
[ORIGINAL]
\yWaypoint Type\w
1. Normal
\r2. Terrorist Important
3. Counter-Terrorist Important
\w4. Block with hostage / Ladder
\y5. Rescue Zone
\w6. Camping
7. Camp End
\r8. Map Goal
\w9. Jump
0. Exit
[TRANSLATED]
\yТип Вэйпоинта\w
1. Обычный
\r2. Важный для Терров
3. Важный для Ментов
\w4. Лестница / Блок с Заложником
\y5. Зона Спасения
\w6. Кемперский
7. Конец Кемперского
\r8. Основная Точка
\w9. Прыговой
\w0. Выход
[ORIGINAL]
\yToggle Waypoint Flags\w
1. Block with Hostage
2. Terrorists Specific
3. CTs Specific
4. Use Elevator
5. Sniper Point (\yFor Camp Points Only!\w)
0. Exit
[TRANSLATED]
\yИзменение Сигналов Вэйпоинтов\w
1. Блок с Заложником
2. Только для Терров
3. Только для Ментов
4. Использовать Лифт
5. Снайперский (\yТолько для кемперских точек!\w)
0. Выход
[ORIGINAL]
\yBot Command Menu\w
1. Make Double Jump
2. Finish Double Jump
3. Drop the C4 Bomb
4. Drop the Weapon
0. Exit
[TRANSLATED]
\yМеню Команд Бота\w
1. Сделать двойной Прыжок
2. Закончить двойной Прыжок
3. Скинуть бомбу C4
4. Скинуть пушку
0. Выход
[ORIGINAL]
\yAutoPath Distance\w
1. Distance 0
2. Distance 100
3. Distance 130
4. Distance 160
5. Distance 190
6. Distance 220
7. Distance 250 (Default)
0. Exit
[TRANSLATED]
\yДистанция Автопути\w
1. Дистанция 0
2. Дистанция 100
3. Дистанция 130
4. Дистанция 160
5. Дистанция 190
6. Дистанция 220
7. Дистанция 250 (По умолчанию)
0. Выход
[ORIGINAL]
\yCreate Path (Choose Direction)\w
1. Outgoing Path
2. Incoming Path
3. Bidirectional (Both Ways)
0. Exit
[TRANSLATED]
\yСоздание Пути (Выберите Направление)\w
1. Исходящий Путь
2. Входящий Путь
3. Бинаправленный (Оба Пути)
0. Выход
[ORIGINAL]
Map not waypointed. Can't Create Bot
[TRANSLATED]
У карты нет вэйпоинтов. Невозможно создать Бота.
[ORIGINAL]
Waypoints has been changed. Load waypoints again...
[TRANSLATED]
Вэйпоинты были изменены. Загрузите их заново...
[ORIGINAL]
Invalid skill given. Using random skill.
[TRANSLATED]
Дан неверный скилл. Скилл будет выбран случайно.
[ORIGINAL]
Connecting Bot...
[TRANSLATED]
Присоединяю Бота...
[ORIGINAL]
Fill Server with %s bots...
[TRANSLATED]
Заполнение сервера с %s ботами...
[ORIGINAL]
Bots are removed from server.
[TRANSLATED]
Боты убраны с сервера.
[ORIGINAL]
Bot '%s' kicked
[TRANSLATED]
Бот '%s' убран
[ORIGINAL]
\yBots Remove Menu (%d/4):\w
%s
%s 0. Back
[TRANSLATED]
\yУбирание ботов (%d/4):\w
%s
%s 0. Назад
[ORIGINAL]
%s\d %1.1d. Not a Bot\w
[TRANSLATED]
%s\d %1.1d. Не бот\w
[ORIGINAL]
9. More...
[TRANSLATED]
9. Больше...
[ORIGINAL]
All Bots died !
[TRANSLATED]
Все боты убиты.
[ORIGINAL]
%s weapon mode selected
[TRANSLATED]
%s режим оружия выбран
[ORIGINAL]
ERROR: FindPath Source Invalid->%d
[TRANSLATED]
ОШИБКА: Поиск Пути: Начало Ошибочно->%d
[ORIGINAL]
ERROR: FindPath Destination Invalid->%d
[TRANSLATED]
ОШИБКА: Поиск Пути: Назначение Ошибочно->%d
[ORIGINAL]
Denied path creation from %d to %d (path already exists)
[TRANSLATED]
Запрет создания пути из %d в %d (путь уже существует)
[ORIGINAL]
Path added from %d to %d
[TRANSLATED]
Путь добавлен из %d в %d
[ORIGINAL]
This is not Camping Waypoint
[TRANSLATED]
Это не кемперский Вэйпоинт
[ORIGINAL]
Waypoint number out of range (Valid range From 0 to %d)
[TRANSLATED]
Кол-во вэйпоинтов вышло за границы (Верная граница с 0 и до %d)
[ORIGINAL]
Cannot connect waypoint to itself
[TRANSLATED]
Невозможно соеденить вэйпоинт сам с собой
[ORIGINAL]
Waypoint %d connected with invalid Waypoint #%d!
[TRANSLATED]
Вэйпоинт %d соеденен с неверным Вэйпоинтом № %d!
[ORIGINAL]
Waypoint %d isn't connected with any other Waypoint!
[TRANSLATED]
Вэйпоинт %d не соединен ни с одним другим вэйпоинтом
[ORIGINAL]
Waypoint %d pathnumber differs from index!
[TRANSLATED]
Количство путей вэйпоинтов %d несовпадает с его индексом!
[ORIGINAL]
Waypoint %d Camp-Endposition not set!
[TRANSLATED]
На вэйпоинте %d ну установлен точка конца кемперства!
[ORIGINAL]
You didn't set a Rescue Point!
[TRANSLATED]
Ты не установил Зону спасения Заложников!
[ORIGINAL]
You didn't set any Terrorist Important Point!
[TRANSLATED]
Ты не установил ни одного важного для Терров Вэйпоинта!
[ORIGINAL]
You didn't set any CT Important Point!
[TRANSLATED]
Ты не установил ни одного важного для Ментов Вэйпоинта!
[ORIGINAL]
You didn't set any Goal Point!
[TRANSLATED]
Ты не установил ни одного главного Вэйпоинта!
[ORIGINAL]
Path broken from Waypoint #0 to Waypoint #%d!
[TRANSLATED]
Путь испорчен из Вэйпоинта № 0 к Вэйпоинту № %d!
[ORIGINAL]
Path broken from Waypoint #%d to Waypoint #0!
[TRANSLATED]
Путь испорчен из Вэйпоинта № %d к Вэйпоинту № 0!
[ORIGINAL]
Choose weapon from 1 to 7 range
[TRANSLATED]
Выберите оружие в пределах от 1 до 7
[ORIGINAL]
All dead bots will vote for map #%d
[TRANSLATED]
Все мертвые боты будут голосовать за карту #%d
[ORIGINAL]
Bot %s executing command %s
[TRANSLATED]
Бот %s выполняет команду %s
[ORIGINAL]
Player is NOT Bot!
[TRANSLATED]
Игрок не БОТ!!!
[ORIGINAL]
Waypoint Editing Enabled
[TRANSLATED]
Включено редактирование Вэйпоинтов
[ORIGINAL]
Waypoint Editing Disabled
[TRANSLATED]
Редактирование Вэйпоинтов Выключено
[ORIGINAL]
Noclip Cheat Enabled
[TRANSLATED]
Режим полёта включен
[ORIGINAL]
Waypoints are Disabled
[TRANSLATED]
Вэйпоинты Выключены
[ORIGINAL]
Waypoints are Enabled
[TRANSLATED]
Вэйпоинты Включены
[ORIGINAL]
Noclip Cheat Disabled
[TRANSLATED]
Режим полёта выключен
[ORIGINAL]
Showing Direction to Waypoint #%d
[TRANSLATED]
Показываю направление к Вэйпоинту #%d
[ORIGINAL]
Waypoints Saved
[TRANSLATED]
Вэйпоинты сохранены
[ORIGINAL]
Waypoints loaded
[TRANSLATED]
Вэйпоинты загружены
[ORIGINAL]
Nodes work Fine
[TRANSLATED]
Вэйпоинты работают отлично
[ORIGINAL]
Waypoint #%d now cached
[TRANSLATED]
Вэйпоинт %d, теперь кеширован!
[ORIGINAL]
Player '%s' teleported to waypoint #%d (x:%d, y:%d, z:%d)
[TRANSLATED]
Игрок '%s' телепортирован на вэйпоинт #%d (x:%d, y:%d, z:%d)
[ORIGINAL]
Experience tab saved
[TRANSLATED]
Таблица опыта сохранена
[ORIGINAL]
Experience Enabled
[TRANSLATED]
Опыт включен
[ORIGINAL]
Experience Disabled
[TRANSLATED]
Опыт выключен
[ORIGINAL]
Command not supported on dedicated server
[TRANSLATED]
Команда не работает на выделенном сервере
[ORIGINAL]
Waypoint not saved
There are errors, see console
[TRANSLATED]
Вэйпоинты не сохранены
Есть ошибки, смотри консоль
[ORIGINAL]
There are errors, see console
[TRANSLATED]
Есть ошибки, смотри консоль
[ORIGINAL]
You're dead, and have no access to this menu
[TRANSLATED]
Ты мертв, и не имеешь доступа к этому меню
[ORIGINAL]
AutoPath disabled
[TRANSLATED]
Автопути отключены
[ORIGINAL]
AutoPath maximum distance set to %f
[TRANSLATED]
Максимальная дистанция автопути установлена в %f
[ORIGINAL]
Unable to find nearest waypoint in 50 units
[TRANSLATED]
Невозможно найти ближайший вэйпоинт на растоянии 50 юнитов
[ORIGINAL]
Unable to find destination waypoint
[TRANSLATED]
Невозможно найти вэйпоинт назначения
[ORIGINAL]
Unable to connect waypoint with itself
[TRANSLATED]
Невозможно соеденить вэйпоинт сам с собой
[ORIGINAL]
There is already no path on this waypoint
[TRANSLATED]
На этом вэйпоинте уже нет пути
[ORIGINAL]
Cached waypoint cleared (nearby point not found in 50 units range)
[TRANSLATED]
Сохраненный вэйпоинт удален (ближайший вэйпоинт не найден на растоянии 50 юнитов)
[ORIGINAL]
Waypoint #%d has been put into memory
[TRANSLATED]
Вэйпоинт №%d был запомнен
[ORIGINAL]
Maximum players reached (%d/%d). Unable to create Bot.
[TRANSLATED]
Максимум игроков добавлено (%d/%d). Невозможно создать Бота.
[ORIGINAL]
Cannot assign sniper flag to waypoint #%d. This is not camp waypoint
[TRANSLATED]
Невозможно добавить снайперский сигнал на вэйпоинт №%d. Вэйпоинт не кемперский

View file

@ -0,0 +1,339 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: ru_names.cfg
;
; Configuration file contains Russian bot names.
;
Deg omMOPO3
nyrJIuBbIu JIbI>|<HuK
aKTuBHbIu roMeC
yCaTbIu ToKaPb
C4aCTJIuBbIu JIyneHb
BeCeJIbIu 4eKuCT
HeXuJIbIu TaHKuCT
CaguCT-3aTeuHuK
Hego6pbIu JIeKaPb
MaCTeP XegoB
6PoHeTeMKuH noHoCeU,
CepguTbIu 3y6PuK
CoHJIuBbIu BuKuHr
3Meu ropbIHbI4
ra3oHoKocuJIbLLI,uK
Xy>I<e_JIoJIKu
~BuHHu_nyK~
Ba3eJIuHoBbIu My>I<uK
6ypaTuHo
/7a/7a_KapJIo
My>|<u4oK CJIOHoBu4oK
>|<eCTKuu_4e6yp
KpbIca KaMuKag3e
KoH4eHbIu ypog
He3gopoBbIu ncux
ommonbIpeHbIu ynbIPb
CKyKo>|<eHbIu E>I<
nu>|<oH c Ho>|<oM
CyKa-B-6oTaX
3apa3a B Ta3e
KocMoHaBT Ha KaMa3e
// eol 32 names
[baz] DeCaHmHuK
uHCneKToP
BbIcTpeJI B >I<ony!
DupeKTop_KyKypy3HuKa
Cep>I<aHm
Ha4aJIbHuK KapmbI
y4uTeJIb XuMuu
>I<apeHbIu neTyX
BaMnup
6oT 6a3uJIuo
TepMuHaTop
Kapa6aC PaCKoJI6aC
[oMoH]~noKeMoH
[+Duracell-]
Oo!oO
MegBe>I<oHoK -)MKa
PbI6oKon
CynePKpoBo>I<agHbIu
g>I<eKu 4aH
KOT-B-POMALLIKAX
Bcex-nopBy!
CmpaHHbIu CmpaHHuK
yJIbI6o4HbIu 6oT
[RWL] BoBa KoMaTo3HuK
[RWL] LLIHULLEJIb
[RWL] Ado
[RWL] dur5t
[RWL] SAOPP Family
[RWL] Deni$OK
IOHbIu 3agpoT.
NetManiac
CmapuK-noxa6bI4
KoMaToZZzz
Kyu >I<eJIe3HbIu
[HSH] KyMapuK
uBaH KpuBopyKoB
>PartiZan<
3JIo6HbIu yXaPb
=ReANiMaToR=
OTMoPo>I<eHbIu MuHTau
nPanoP KoHeB
4yKoTcKuu CHauneP
[dnb] BASSBOMB
noHb KugaJIbHbIu
cccp| =LENIN=
SHiBZDiK
BOP_B_3anoE
Mo3roEg
Mauop KyMaP
uHCneKToP >I<onuH
KpoBaBbIu neKaPb
XMyPbIu >I<MyPuK
3JIoCTHbIu nePgyH
CuBbIu gyPeHb
z00m
K!110grAmm
jaZzK!ll
KeKS| PerDoLetto
KeKS| KyKyM6a
KeKS| Co6aKa-PeKC
KeKS| ZeliBoBa
BoJIoCaTbIe Ho3gPu
6yXou MATPOC
CocucbKa
CbIH_OTMoPo3Ka
CTaPuK OTMoPo3oK
KpuBou PaxuT KyKyeB
KpyTou nep4uK~
3JIou TapaKaH
Heu3BecmHbIu
HoBoXygoHocop
rpy3oBuK C HaBo3oM
OrpbI3oK
6apbIra
Ky3bKuHa_MaTb
CaHuTaP u3 Mopra
KyJIuHaP TeCaKoB
noJIy4u_B_>I<6aH
KoMaPuK
ne4aJIbHbIu 4auHuK
::M4N`o`W4R::
P1nc ZoMBy
>I<bIPHbIu nuHrBuH
SchtandartenFuhrer
ST4L!N RuL!T
B.B./7ymuH
4ePHbIu JIeKToP.
naHKu_B_TAHKE
Kampers in Pampers
OTJIu4HbIu_nuHr!
napa nCuXoJIoroB
KoBapHoe JIaMo
4e6ypeK @(o,o)@
He>I<Ha9I JIaMKa
geg Ma3gau
HeonbITHbIu /7ana
/7poDOOMaHHbIu III
3BePCKuu_4uT0P
=| ReAnimaToR |=
Ky3bMu4b
TelepuzO
Tynou KyPCaHT
XogoK 3a /7uBoM
DEADushka MoroZ
mu1ti-K!ll
Ne0
ToJIna areHToB CMuToB
=ZL0Y=
HeadKilla ==(oo)=>
))==0KyHb=%>
laZar
=| Zar |=
DeD LoGoPeD
|z| QuaZatron.
|z| NecromanZer.
|z| Zerg.
|z| teZer
[z] *moZg*
/z/ Z-Lum!noFor
[dnb] dub
[dnb] Kara
(dnb) Mechano!d
dnb| 3v!LKilla
4ygHbIu /7anopomHuK
XuTPbIu_AHyC
Xo66uT
[baz] GAD
[baz] K/IoH
[baz] viz0r
[baz] MiXa
|baz| go6pbIu 6o6puK
|baz| DiGGeR
|baz| =GRoMoZeKA=
|baz| BuHToBKuH
|baz| ZveroBoy
SK| ahl.
SK| bds.
SK| brunk
SK| ElemenT
SK| fisker
SK| goseY
SK| HeatoN
SK| Potti
Morda
6oM>I<yaH
n0name| Haru6aToP
KyJIbHbIu_PyJIe3
NiTron
[.71]TPAXTOP
M19*KaLbI4
M19*Rado
M19*NooK
M19*MadFan
M19*Rider
forZe| Xen1tron
[forZe] iTuman
forZe| Electric.eYe
forZe| Romashka
[forZe] h0s7
[team9] vesslan
[team9] XeqtR
[team9] Luciano
[team9] quick
[team9] Luccese
6bIK
StabiliZat0R
yHuKaJIbHbIu yHuTa3
MegaCamper
KoT MaTPOCKuH
L1MoN
Bo>|<gb /7oKeMoHoB
[s!L3nt]xen0b1te
Xeg-XegbI4
=XAM=
loloboto
L0M
FluroGinecolog
-papique-
CyKaHax
Be>I<JIuBbIu JIOCb
CTago CJIoHoB
yKypbILLI
OTCTou CJIuBo4HbIu
>>>BullDoZzeR
=geCePT=
PROVOCATOR
Tpyn
ZLOid
MygaK C Py>I<beM
DiGGeR
-MAM6A-
KeHToyKJIag4uK
nanuK
-ZerG-
MYX0M0P
neC MoXHoPbIJIbIu
-PerfoRaToR->
neJlbMeHb
V!C
g00dDayToD!e
poccoMaxa
K!llogr4mm
geM6eJIb
MyXa
Davilka
CTaJIbHbIe TanKu
CJIoHeHoK
**3y6P**
ronHuK
-=y6uBaToP=-
BJIaCTeJIuH KoHTPbI
MaKaPoHHuK
Mekhano!d
**BE45t**
gollum
noCMoTPuM KTo 4Mo
onaCHbIu Tun
B.B.TynuH
-=AMnyTaToP=-
**Natashka**
neraJIb
MopCKou_CBuH
CTenHou OXoTHuK
Ky4Ka
-##.NeO.##-
Vasily Pupkin
gpo6ogyH C 6ogyHa
KoBaPHbIu roMuK
Ca6JIe3y6a9I >I<y4Ka
4un u geuJI
roBHogaB4uK
BoB4uK
CaM_gyPaK
TuTbKa
KoHb B Canorax
9I_4eLLIKa-o6op>I<oTeCb!
3JIa9I 4eLLIKa
Ky6uK Bpy6uK
KJIaCCHbIe CuCbKu
XOPb C gy6uHou
CTaJIbHbIe 9IuKu
pardoN-Zaperdon
npocmo HanpocTo
He y6uBauTe Cpa3y!
MaLLIa-KaKaLLIa
3a6er_ge6uJIoB
3agHenpoXog4uK
KPaCHbIu KPoKoguJI
CMeJIbIu g9ITeJI
4y4yHgpuK
Po3oBa9I nonKa
PagoCTHa9I CoCKA
6yKa-nyKa
BeJIuKuu HaCoCbHuK
KoHKpeTHa9I TynKa
DP9IHb
rJIoTaTEJIb noPTBEuHa
AFPuKAHeu,
6PI-0C KoJIdyH
}I{uD
KBA3uMODA
MukJIyXA
TBaPb
TaHu,yI-0LLIuE BoDoJIa3bI
HeBuHHbIu` TyHeu,
JIyHHbIu BCaDHuK
6oJIbHOu LLIaP
npu3pak nuHokuo
6oM6a-MOJI
TaHeu, MAJIeHbKux CBeHEu
u,BeTHbIe ry6bI
Tpy-JI9I-JI9I
TaHro Ha o6JIaKe
CnePMATo3aBP 4eMnuoH
DOM roJIy6bIe rJIa3a
ÂeceJIbIu AHCAM6JIb
nPoCHuCb HAC o6oKpaJIu
6ercTBo (KoHb)
ÑTPEMHbIu KOPA6JIb
DbIM u neneJI
FAMuJIHbIu` BAMnuP
MycoPHbIu BETEP
-)poTu4ecKue MOHCTPbI
6eJIbIe CTOJI6bI
OrHEHHa9I rueHa
npopok Ha kapyceJIu
KpbIJIATbIE CJIOHbI
MHoro 6akcoB
FaHTuK
O4Ku-Dypa4Ku
}I{udKuu` CTyJI
y4e6Huk no 6puTBe
uLLI,y Pa6oTy (1000$)
o6LLIuPHbIu` B3pbIB
u,BeTHou` 6yKeT
3uJIu6o6a - !nuBo
CaDo-Ma3o-nJIeTka!

View file

@ -0,0 +1,21 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: logos.cfg
;
; Configuration file contains logos definitions for bots.
; They are taken from decals.wad.
;
{biohaz
{graf003
{graf004
{graf005
{lambda06
{target
{hand1
{spit2
{bloodhand6
{foot_l
{foot_r

View file

@ -0,0 +1,81 @@
;
; @package: YaPB
; @version: 4.0
; @author: YaPB Development Team
; @filename: weapon.cfg
;
; Configuration file contains weapon preferences for bots.
;
; Numbering of the weapons:
; 0 - KNIFE
; 1 - USP
; 2 - GLOCK18
; 3 - DEAGLE
; 4 - P228
; 5 - ELITE
; 6 - FIVESEVEN
; 7 - M3
; 8 - XM1014
; 9 - MP5NAVY
; 10 - TMP
; 11 - P90
; 12 - MAC10
; 13 - UMP45
; 14 - AK47
; 15 - SG552
; 16 - M4A1
; 17 - GALIL
; 18 - FAMAS
; 19 - AUG
; 20 - SCOUT
; 21 - AWP
; 22 - G3SG1
; 23 - SG550
; 24 - M249
; 25 - SHIELD
;
; Following are Tables which specify which Team is allowed
; to buy a weapon on a Map. You can also use it to allow/disallow
; Weapons for a Team or a Map/Gamemode (remember that some
; Weapons are team-specific and can't be bought by another team).
; -1 = Disallow Buying for any Team
; 0 = Terrorist Team only
; 1 = CT Team only
; 2 = Can be bought by both Teams
; Standard Weapon Tab for CS & DE Maps
;
MapStandard = -1,0,-1,2,-1,0,1,2,2,2,-1,2,-1,-1,0,0,1,0,1,1,2,2,0,1,2,1
MapAS = -1,-1,-1,2,-1,0,1,1,1,1,1,1,0,2,0,-1,1,0,1,1,0,0,-1,1,1,1
;
; Grenade buying percentage
; HE, FL, SMOKE
;
GrenadePercent = 98,75,60
;
; Bot Economics. From left to right.
;
; 1 - If bot's money more than the value specified here. He can buy the primary weapon.
; 2 - If bot's money more than the value specified here he will not buy SMGs (MP5, MAC10, TMP, P90, UMP45, SCOUT) (only for CTs) (+ 8/9/10)
; 3 - If bot's money more than the value specified here it will not buy SMGs (MP5, MAC10, TMP, P90, UMP45, SCOUT) (only for Ts) (+ 8/9/10))
; 4 - If bot's money more than the value specified here he can buy shotguns (M3, XM1014).
; 5 - If bot's money less than the value specified here he cannot buy shotguns (M3, XM1014).
; 6 - If bot's money more than the value specified here he can buy AWM, SG550, G3SG1, M249.
; 7 - If bot's money less than the value specified here he cannot buy AWM, SG550, G3SG1, M249.
; 8 - How much money bot leaves a prostock, at purchase of the primary weapon (only for type of behaviour - Normal)
; 9 - How much money bot leaves a prostock, at purchase of the primary weapon (only for type of behaviour - Agressive).
; 10 - How much money bot leaves a prostock, at purchase of the primary weapon (only for type of behaviour - Careful).
; 11 - If bot's money more than the value specified here. He can buy the shield.
;
Economics = 1550,2100,2100,4000,6000,7000,16000,1200,800,1100,3000
;
; The following Tables stores the Weapon Priorities of the Bots depending on
; Personality (it affects buying & picking up better weapons from the ground).
;
PersonalityNormal = 00,02,01,04,05,06,03,12,10,24,25,13,11,08,07,22,23,20,21,09,19,15,17,18,14,16
PersonalityRusher = 00,02,04,05,01,06,03,24,25,22,23,20,10,12,13,07,08,21,11,09,15,19,17,18,16,14
PersonalityCareful = 00,02,01,04,05,06,03,07,08,12,10,13,11,09,18,17,15,19,16,14,20,22,25,23,24,21

View file

@ -0,0 +1,354 @@
//
// @package: YaPB
// @version: 4.0
// @author: YaPB Development Team
// @filename: yapb.cfg
//
// YAPB main configuration file. Can be executed via "exec" command.
//
//
// Enables or disables useful messages about bot states. Not required for end users
// ---
// Default: "0", Min: "0", Max: "4"
//
yb_debug "0"
//
// Forces all alive bots to build path and go to the specified here graph node.
// ---
// Default: "-1", Min: "-1", Max: "2048"
//
yb_debug_goal "-1"
//
// Specifies the percent of bots, than can follow leader on each round start.
// ---
// Default: "20", Min: "0", Max: "100"
//
yb_user_follow_percent "20"
//
// Specifies how many bots can follow a single user.
// ---
// Default: "1", Min: "0", Max: "16"
//
yb_user_max_followers "1"
//
// If enabled, all bots will be forced only the knife, skipping weapon buying routines.
// ---
// Default: "0", Min: "0", Max: "1"
//
yb_jasonmode "0"
//
// Allows bots to use radio or chattter.
// Allowed values: '0', '1', '2'.
// If '0', radio and chatter is disabled.
// If '1', only radio allowed.
// If '2' chatter and radio allowed.
// ---
// Default: "2", Min: "0", Max: "2"
//
yb_radio_mode "2"
//
// Specifies whether bots able to use team economics, like do not buy any weapons for whole team to keep money for better guns.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_economics_rounds "1"
//
// Sepcifies whether bots able to use 'shift' if they thinks that enemy is near.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_walking_allowed "1"
//
// Allows or disallows bots to camp. Doesn't affects bomb/hostage defending tasks
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_camping_allowed "1"
//
// Allows or disallows bots to take revenge of teamkillers / team attacks.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_tkpunish "1"
//
// If enables bots think function is disabled, so bots will not move anywhere from their spawn spots.
// ---
// Default: "0", Min: "0", Max: "1"
//
yb_freeze_bots "0"
//
// Allows or disallows the use of spay paints.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_spraypaints "1"
//
// Allows or disallows bots weapon buying routines.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_botbuy "1"
//
// Allows bots to destroy breakables around him, even without touching with them.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_destroy_breakables_around "1"
//
// Specifies the paths for the bot chatter sound files.
// ---
// Default: "sound/radio/bot"
//
yb_chatter_path "sound/radio/bot"
//
// Specifies semicolon separated list of weapons that are not allowed to buy / pickup.
// ---
// Default: ""
//
yb_restricted_weapons ""
//
// Enables or disables bots chat functionality.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_chat "1"
//
// Specifies whether bots able to fire at enemies behind the wall, if they hearing or suspecting them.
// ---
// Default: "2", Min: "0", Max: "3"
//
yb_shoots_thru_walls "2"
//
// Enables or disables searching world for enemies.
// ---
// Default: "0", Min: "0", Max: "1"
//
yb_ignore_enemies "0"
//
// Enables or disables checking enemy rendering flags. Useful for some mods.
// ---
// Default: "0", Min: "0", Max: "1"
//
yb_check_enemy_rendering "0"
//
// Enables or disables bot ability to stab the enemy with knife if bot is in good condition.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_stab_close_enemies "1"
//
// Enables or disables display menu text, when players asks for menu. Useful only for Android.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_display_menu_text "1"
//
// The value (password) for the setinfo key, if user set's correct password, he's gains access to bot commands and menus.
// ---
// Default: ""
//
yb_password ""
//
// The name of setinfo key used to store password to bot commands and menus
// ---
// Default: "_ybpw"
//
yb_password_key "_ybpw"
//
// Enables or disables CSDM / FFA mode for bots.
// Allowed values: '0', '1', '2', '3'.
// If '0', CSDM / FFA mode is auto-detected.
// If '1', CSDM mode is enabled, but FFA is disabled.
// If '2' CSDM and FFA mode is enabled.
// If '3' CSDM and FFA mode is disabled.
// ---
// Default: "0", Min: "0", Max: "3"
//
yb_csdm_mode "0"
//
// Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_graph_fixcamp "1"
//
// Specifies the URL from bots will be able to download graph in case of missing local one.
// ---
// Default: "http://graph.yapb.ru/"
//
yb_graph_url "http://graph.yapb.ru/"
//
// Kick bots to automatically make room for human players.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_autovacate "1"
//
// Bind's specified key for openining bots menu.
// ---
// Default: "="
//
yb_bind_menu_key "="
//
// Specifies the number bots to be added to the game.
// ---
// Default: "0", Min: "0", Max: "32"
//
yb_quota "12"
//
// Specifies the type of quota.
// Allowed values: 'normal', 'fill', and 'match'.
// If 'fill', the server will adjust bots to keep N players in the game, where N is cv_quota.
// If 'match', the server will maintain a 1:N ratio of humans to bots, where N is cv_quota_match.
// ---
// Default: "normal"
//
yb_quota_mode "normal"
//
// Number of players to match if cv_quota_mode set to 'match'
// ---
// Default: "0", Min: "0", Max: "32"
//
yb_quota_match "0"
//
// Specifies hou many times per second bot code will run.
// ---
// Default: "30.0", Min: "30.0", Max: "90.0"
//
yb_think_fps "30.0"
//
// Specifies amount of time in seconds when bots will be killed if no humans left alive.
// ---
// Default: "0.0", Min: "0.0", Max: "90.0"
//
yb_autokill_delay "0.0"
//
// Sepcifies whether bots should join server, only when at least one human player in game.
// ---
// Default: "0", Min: "0", Max: "1"
//
yb_join_after_player "0"
//
// Forces all bots to join team specified here.
// ---
// Default: "any"
//
yb_join_team "any"
//
// Specifies after how many seconds bots should start to join the game after the changelevel.
// ---
// Default: "5.0", Min: "0.0", Max: "30.0"
//
yb_join_delay "5.0"
//
// All the bot names will be prefixed with string specified with this cvar.
// ---
// Default: ""
//
yb_name_prefix ""
//
// All bots difficulty level. Chaning at runtime will affect already created bots.
// ---
// Default: "4", Min: "0", Max: "4"
//
yb_difficulty "4"
//
// Enables or disabels displaying bot avatars in front of their names in scoreboard. Note, that is currently you can see only avatars of your steam friends.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_show_avatars "1"
//
// Enables latency display in scoreboard.
// Allowed values: '0', '1', '2'.
// If '0', there is nothing displayed.
// If '1', there is a 'BOT' is displayed.
// If '2' fake ping is displayed.
// ---
// Default: "2", Min: "0", Max: "2"
//
yb_show_latency "2"
//
// Specifies the language for bot messages and menus.
// ---
// Default: "en"
//
yb_language "en"
//
// Specifies comma separated list of bot cvars, that will not be overriten by config on changelevel.
// ---
// Default: "yb_quota,yb_autovacate"
//
yb_ignore_cvars_on_changelevel "yb_quota,yb_autovacate"
//
// Enables or disables extra hard difficulty for bots.
// ---
// Default: "0", Min: "0", Max: "1"
//
yb_whose_your_daddy "0"
//
// Selects the heuristic function mode. For debug purposes only.
// ---
// Default: "0", Min: "0", Max: "4"
//
yb_debug_heuristic_type "0"
//
// Enables or disables showing welcome message to host entity on game start.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_display_welcome_text "1"
//
// Enables or disabled fake server queries response, that shows bots as real players in server browser.
// ---
// Default: "1", Min: "0", Max: "1"
//
yb_enable_query_hook "1"

92
ext/crlib/cr-alloc.h Normal file
View file

@ -0,0 +1,92 @@
//
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#include <new>
#include <crlib/cr-basic.h>
#include <crlib/cr-movable.h>
#include <crlib/cr-platform.h>
CR_NAMESPACE_BEGIN
// default allocator for cr-objects
class Allocator : public Singleton <Allocator> {
public:
Allocator () = default;
~Allocator () = default;
public:
template <typename T> T *allocate (const size_t length = 1) {
auto ptr = reinterpret_cast <T *> (malloc (length * sizeof (T)));
if (!ptr) {
plat.abort ();
}
return ptr;
}
template <typename T> void deallocate (T *memory) {
free (memory);
memory = nullptr;
}
public:
template <typename T, typename ...Args> void construct (T *memory, Args &&...args) {
new (memory) T (cr::forward <Args> (args)...);
}
template <typename T> void destruct (T *memory) {
memory->~T ();
}
public:
template <typename T, typename ...Args> T *create (Args &&...args) {
auto d = allocate <T> ();
new (d) T (cr::forward <Args> (args)...);
return d;
}
template <typename T> T *createArray (const size_t amount) {
auto memory = allocate <T> (amount);
for (size_t i = 0; i < amount; ++i) {
new (memory + i) T ();
}
return memory;
}
template <typename T> void destroy (T *memory) {
if (memory) {
destruct (memory);
deallocate (memory);
}
}
};
CR_EXPOSE_GLOBAL_SINGLETON (Allocator, alloc);
template <typename T> class UniquePtr;
// implment singleton with UniquePtr
template <typename T> T &Singleton <T>::instance () {
static const UniquePtr <T> instance_ { alloc.create <T> () };
return *instance_;
}
CR_NAMESPACE_END

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -25,10 +32,10 @@ CR_NAMESPACE_BEGIN
// simple array class like std::vector
template <typename T, ReservePolicy R = ReservePolicy::Multiple, size_t S = 0> class Array : public DenyCopying {
public:
T *m_data = nullptr;
size_t m_capacity = 0;
size_t m_length = 0;
private:
T *m_data {};
size_t m_capacity {};
size_t m_length {};
public:
explicit Array () {
@ -102,8 +109,10 @@ public:
}
auto data = alloc.allocate <T> (capacity);
transferElements (data, m_data, m_length);
alloc.deallocate (m_data);
if (m_data) {
transferElements (data, m_data, m_length);
alloc.deallocate (m_data);
}
m_data = data;
m_capacity = capacity;
@ -137,8 +146,8 @@ public:
return reserve (amount - m_length);
}
size_t length () const {
return m_length;
template <typename U = size_t> U length () const {
return static_cast <U> (m_length);
}
size_t capacity () const {

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -86,12 +93,18 @@ public:
};
// singleton for objects
template <typename T> struct Singleton : private DenyCopying {
template<typename T> class Singleton : public DenyCopying {
protected:
Singleton ()
{ }
public:
static T &get () {
static T ref_;
return ref_;
};
static T &instance (); // implemented in cr-alloc.h
public:
T *operator -> () {
return &instance ();
}
};
// simple scoped enum, instaed of enum class
@ -112,10 +125,10 @@ public:
CR_DECLARE_SCOPED_ENUM_TYPE(enumName, int32, __VA_ARGS__) \
// exposes global variable from class singleton
#define CR_EXPOSE_GLOBAL_SINGLETON(className, variable) \
static auto &variable = className::get () \
#define CR_EXPOSE_GLOBAL_SINGLETON(className, variable) \
static auto &variable = className::instance () \
CR_NAMESPACE_END
// platform-dependant-stuff
#include <crlib/cr-platform.h>
#include <crlib/cr-platform.h>

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -15,22 +22,22 @@ CR_NAMESPACE_BEGIN
// simple priority queue
template <typename T> class BinaryHeap final : public DenyCopying {
private:
Array <T> m_data;
Array <T> contents_;
public:
explicit BinaryHeap () = default;
BinaryHeap (BinaryHeap &&rhs) noexcept : m_data (cr::move (rhs.m_data))
BinaryHeap (BinaryHeap &&rhs) noexcept : contents_ (cr::move (rhs.contents_))
{ }
~BinaryHeap () = default;
public:
template <typename U> bool push (U &&item) {
if (!m_data.push (cr::move (item))) {
if (!contents_.push (cr::move (item))) {
return false;
}
size_t length = m_data.length ();
const size_t length = contents_.length ();
if (length > 1) {
percolateUp (length - 1);
@ -39,10 +46,10 @@ public:
}
template <typename ...Args> bool emplace (Args &&...args) {
if (!m_data.emplace (cr::forward <Args> (args)...)) {
if (!contents_.emplace (cr::forward <Args> (args)...)) {
return false;
}
size_t length = m_data.length ();
const size_t length = contents_.length ();
if (length > 1) {
percolateUp (length - 1);
@ -51,17 +58,17 @@ public:
}
const T &top () const {
return m_data[0];
return contents_[0];
}
T pop () {
if (m_data.length () == 1) {
return m_data.pop ();
if (contents_.length () == 1) {
return contents_.pop ();
}
auto key (cr::move (m_data[0]));
auto key (cr::move (contents_[0]));
m_data[0] = cr::move (m_data.last ());
m_data.discard ();
contents_[0] = cr::move (contents_.last ());
contents_.discard ();
percolateDown (0);
return key;
@ -69,24 +76,24 @@ public:
public:
size_t length () const {
return m_data.length ();
return contents_.length ();
}
bool empty () const {
return !m_data.length ();
return !contents_.length ();
}
void clear () {
m_data.clear ();
contents_.clear ();
}
private:
void percolateUp (size_t index) {
while (index != 0) {
size_t parentIndex = parent (index);
const size_t parentIndex = parent (index);
if (m_data[parentIndex] > m_data[index]) {
cr::swap (m_data[index], m_data[parentIndex]);
if (contents_[parentIndex] > contents_[index]) {
cr::swap (contents_[index], contents_[parentIndex]);
index = parentIndex;
}
else {
@ -100,15 +107,15 @@ private:
size_t bestIndex = left (index);
if (hasRight (index)) {
size_t rightIndex = right (index);
const size_t rightIndex = right (index);
if (m_data[rightIndex] < m_data[bestIndex]) {
if (contents_[rightIndex] < contents_[bestIndex]) {
bestIndex = rightIndex;
}
}
if (m_data[index] > m_data[bestIndex]) {
cr::swap (m_data[index], m_data[bestIndex]);
if (contents_[index] > contents_[bestIndex]) {
cr::swap (contents_[index], contents_[bestIndex]);
index = bestIndex;
bestIndex = left (index);
@ -122,7 +129,7 @@ private:
private:
BinaryHeap &operator = (BinaryHeap &&rhs) noexcept {
if (this != &rhs) {
m_data = cr::move (rhs.m_data);
contents_ = cr::move (rhs.contents_);
}
return *this;
}
@ -141,11 +148,11 @@ private:
}
bool hasLeft (size_t index) const {
return left (index) < m_data.length ();
return left (index) < contents_.length ();
}
bool hasRight (size_t index) const {
return right (index) < m_data.length ();
return right (index) < contents_.length ();
}
};

47
ext/crlib/cr-color.h Normal file
View file

@ -0,0 +1,47 @@
//
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#include <crlib/cr-basic.h>
CR_NAMESPACE_BEGIN
// simple color holder
class Color final {
public:
int32 red = 0, green = 0, blue = 0;
public:
Color (int32 r, int32 g, int32 b) : red (r), green (g), blue (b) { }
explicit Color () = default;
~Color () = default;
public:
void reset () {
red = green = blue = 0;
}
int32 avg () const {
return sum () / (sizeof (Color) / sizeof (int32));
}
int32 sum () const {
return red + green + blue;
}
};
CR_NAMESPACE_END

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -37,4 +44,4 @@ namespace types {
using namespace cr::types;
CR_NAMESPACE_END
CR_NAMESPACE_END

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -53,13 +60,27 @@ namespace detail {
};
template <typename K, typename V> struct DictionaryBucket {
uint32 hash = static_cast <size_t> (-1);
K key = K ();
V value = V ();
uint32 hash = static_cast <uint32> (-1);
K key {};
V value {};
public:
DictionaryBucket () = default;
~DictionaryBucket () = default;
public:
DictionaryBucket (DictionaryBucket &&rhs) noexcept : hash (rhs.hash), key (cr::move (rhs.key)), value (cr::move (rhs.value))
{ }
public:
DictionaryBucket &operator = (DictionaryBucket &&rhs) noexcept {
if (this != &rhs) {
key = cr::move (rhs.key);
value = cr::move (rhs.value);
hash = rhs.hash;
}
return *this;
}
};
}
@ -76,7 +97,7 @@ public:
private:
Array <DictList *> m_table;
Array <DictBucket> m_buckets;
Array <DictBucket> m_buckets{};
H m_hasher;
private:
@ -84,7 +105,7 @@ private:
return m_hasher (key);
}
size_t findIndexOrAllocate (const K &key, bool allocate) {
size_t find (const K &key, bool allocate) {
auto hashed = hash (key);
auto pos = hashed % m_table.length ();
@ -100,7 +121,7 @@ private:
auto allocated = alloc.allocate <DictList> ();
allocated->index = created;
allocated->index = static_cast <int32> (created);
allocated->next = m_table[pos];
m_table[pos] = allocated;
@ -114,7 +135,7 @@ private:
}
size_t findIndex (const K &key) const {
return const_cast <Dictionary *> (this)->findIndexOrAllocate (key, false);
return const_cast <Dictionary *> (this)->find (key, false);
}
public:
@ -211,7 +232,7 @@ public:
public:
V &operator [] (const K &key) {
return m_buckets[findIndexOrAllocate (key, true)].value;
return m_buckets[find (key, true)].value;
}
const V &operator [] (const K &key) const {
@ -246,4 +267,4 @@ public:
}
};
CR_NAMESPACE_END
CR_NAMESPACE_END

393
ext/crlib/cr-files.h Normal file
View file

@ -0,0 +1,393 @@
//
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#include <stdio.h>
#include <crlib/cr-string.h>
#include <crlib/cr-lambda.h>
CR_NAMESPACE_BEGIN
// simple stdio file wrapper
class File final : private DenyCopying {
private:
FILE *handle_ = nullptr;
size_t length_ {};
public:
explicit File () = default;
File (StringRef file, StringRef mode = "rt") {
open (file, mode);
}
~File () {
close ();
}
public:
bool open (StringRef file, StringRef mode) {
if (!openFile (file, mode)) {
return false;
}
fseek (handle_, 0L, SEEK_END);
length_ = ftell (handle_);
fseek (handle_, 0L, SEEK_SET);
return true;
}
void close () {
if (handle_ != nullptr) {
fclose (handle_);
handle_ = nullptr;
}
length_ = 0;
}
bool eof () const {
return !!feof (handle_);
}
bool flush () const {
return !!fflush (handle_);
}
int get () const {
return fgetc (handle_);
}
char *getString (char *buffer, int count) const {
return fgets (buffer, count, handle_);
}
bool getLine (String &line) {
int ch = 0;
SmallArray <char> data (255);
while ((ch = get ()) != EOF && !eof ()) {
data.push (static_cast <char> (ch));
if (ch == '\n') {
break;
}
}
line.assign (data.data (), data.length ());
return !eof ();
}
template <typename ...Args> size_t puts (const char *fmt, Args &&...args) {
if (!*this) {
return 0;
}
return fputs (strings.format (fmt, cr::forward <Args> (args)...), handle_);
}
bool puts (const char *buffer) {
if (!*this) {
return 0;
}
if (fputs (buffer, handle_) < 0) {
return false;
}
return true;
}
int putChar (int ch) {
return fputc (ch, handle_);
}
size_t read (void *buffer, size_t size, size_t count = 1) {
return fread (buffer, size, count, handle_);
}
size_t write (void *buffer, size_t size, size_t count = 1) {
return fwrite (buffer, size, count, handle_);
}
bool seek (long offset, int origin) {
if (fseek (handle_, offset, origin) != 0) {
return false;
}
return true;
}
void rewind () {
::rewind (handle_);
}
size_t length () const {
return length_;
}
public:
explicit operator bool () const {
return handle_ != nullptr;
}
public:
static inline bool exists (StringRef file) {
File fp;
if (fp.open (file, "rb")) {
fp.close ();
return true;
}
return false;
}
static inline void createPath (const char *path) {
for (auto str = const_cast <char *> (path) + 1; *str; ++str) {
if (*str == '/') {
*str = 0;
plat.createDirectory (path);
*str = '/';
}
}
plat.createDirectory (path);
}
private:
bool openFile (StringRef filename, StringRef mode) {
if (*this) {
close ();
}
#if defined (CR_WINDOWS)
fopen_s (&handle_, filename.chars (), mode.chars ());
#else
handle_ = fopen (filename.chars (), mode.chars ());
#endif
return handle_ != nullptr;
}
};
// wrapper for memory file for loading data into the memory
class MemFileStorage : public Singleton <MemFileStorage> {
private:
using LoadFunction = Lambda <uint8 * (const char *, int *)>;
using FreeFunction = Lambda <void (void *)>;
private:
LoadFunction loadFun_ = nullptr;
FreeFunction freeFun_ = nullptr;
public:
inline MemFileStorage () = default;
inline ~MemFileStorage () = default;
public:
void initizalize (LoadFunction loader, FreeFunction unloader) {
loadFun_ = cr::move (loader);
freeFun_ = cr::move (unloader);
}
public:
uint8 *load (StringRef file, int *size) {
if (loadFun_) {
return loadFun_ (file.chars (), size);
}
return nullptr;
}
void unload (void *buffer) {
if (freeFun_) {
freeFun_ (buffer);
}
}
public:
static uint8 *defaultLoad (const char *path, int *size) {
File file (path, "rb");
if (!file) {
*size = 0;
return nullptr;
}
*size = static_cast <int> (file.length ());
auto data = alloc.allocate <uint8> (*size);
file.read (data, *size);
return data;
}
static void defaultUnload (void *buffer) {
alloc.deallocate (buffer);
}
static String loadToString (StringRef filename) {
int32 result = 0;
auto buffer = defaultLoad (filename.chars (), &result);
if (result > 0 && buffer) {
String data (reinterpret_cast <char *> (buffer), result);
defaultUnload (buffer);
return data;
}
return "";
}
};
class MemFile final : public DenyCopying {
private:
enum : char {
Eof = static_cast <char> (-1)
};
private:
uint8 *contents_ = nullptr;
size_t length_ {};
size_t seek_ {};
public:
explicit MemFile () = default;
MemFile (StringRef file) {
open (file);
}
~MemFile () {
close ();
}
public:
bool open (StringRef file) {
length_ = 0;
seek_ = 0;
contents_ = MemFileStorage::instance ().load (file.chars (), reinterpret_cast <int *> (&length_));
if (!contents_) {
return false;
}
return true;
}
void close () {
MemFileStorage::instance ().unload (contents_);
length_ = 0;
seek_ = 0;
contents_ = nullptr;
}
char get () {
if (!contents_ || seek_ >= length_) {
return Eof;
}
auto ch = contents_[seek_];
++seek_;
return static_cast <char> (ch);
}
char *getString (char *buffer, size_t count) {
if (!contents_ || seek_ >= length_) {
return nullptr;
}
size_t index = 0;
buffer[0] = 0;
for (; index < count - 1;) {
if (seek_ < length_) {
buffer[index] = contents_[seek_++];
if (buffer[index++] == '\n') {
break;
}
}
else {
break;
}
}
buffer[index] = 0;
return index ? buffer : nullptr;
}
bool getLine (String &line) {
char ch;
SmallArray <char> data (255);
while ((ch = get ()) != Eof) {
data.push (ch);
if (ch == '\n') {
break;
}
}
line.assign (data.data (), data.length ());
return !eof ();
}
size_t read (void *buffer, size_t size, size_t count = 1) {
if (!contents_ || length_ <= seek_ || !buffer || !size || !count) {
return 0;
}
size_t blocksRead = size * count <= length_ - seek_ ? size * count : length_ - seek_;
memcpy (buffer, &contents_[seek_], blocksRead);
seek_ += blocksRead;
return blocksRead / size;
}
bool seek (size_t offset, int origin) {
if (!contents_ || seek_ >= length_) {
return false;
}
if (origin == SEEK_SET) {
if (offset >= length_) {
return false;
}
seek_ = offset;
}
else if (origin == SEEK_END) {
if (offset >= length_) {
return false;
}
seek_ = length_ - offset;
}
else {
if (seek_ + offset >= length_) {
return false;
}
seek_ += offset;
}
return true;
}
size_t length () const {
return length_;
}
bool eof () const {
return seek_ >= length_;
}
void rewind () {
seek_ = 0;
}
public:
explicit operator bool () const {
return !!contents_ && length_ > 0;
}
};
CR_NAMESPACE_END

170
ext/crlib/cr-hook.h Normal file
View file

@ -0,0 +1,170 @@
//
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#include <crlib/cr-basic.h>
#if !defined (CR_WINDOWS)
# include <sys/mman.h>
#endif
CR_NAMESPACE_BEGIN
class SimpleHook : DenyCopying {
private:
#if defined (CR_ARCH_X64)
using uint = uint64;
#else
using uint = uint32;
#endif
private:
enum : uint32 {
#if defined (CR_ARCH_X64)
CodeLength = 5 + sizeof (uint)
#else
CodeLength = 1 + sizeof (uint)
#endif
};
private:
bool patched_;
uint pageSize_;
uint originalFun_;
uint hookedFun_;
UniquePtr <uint8 []> originalBytes_;
UniquePtr <uint8 []> hookedBytes_;
private:
void setPageSize () {
#if defined (CR_WINDOWS)
SYSTEM_INFO sysinfo;
GetSystemInfo (&sysinfo);
pageSize_ = sysinfo.dwPageSize;
#else
pageSize_ = sysconf (_SC_PAGESIZE);
#endif
}
#if !defined (CR_WINDOWS)
void *align (void *address) {
return reinterpret_cast <void *> ((reinterpret_cast <long> (address) & ~(pageSize_ - 1)));
}
#endif
bool unprotect () {
auto orig = reinterpret_cast <void *> (originalFun_);
#if defined (CR_WINDOWS)
DWORD oldProt;
FlushInstructionCache (GetCurrentProcess (), orig, CodeLength);
return VirtualProtect (orig, CodeLength, PAGE_EXECUTE_READWRITE, &oldProt);
#else
auto aligned = align (orig);
return !mprotect (aligned, pageSize_, PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
}
public:
SimpleHook () : patched_ (false), pageSize_ (0), originalFun_ (0), hookedFun_ (0) {
setPageSize ();
originalBytes_ = makeUnique <uint8 []> (CodeLength);
hookedBytes_ = makeUnique <uint8 []> (CodeLength);
}
~SimpleHook () {
disable ();
}
public:
bool patch (void *address, void *replacement) {
constexpr uint16 jmp = 0x25ff;
if (plat.arm) {
return false;
}
auto ptr = reinterpret_cast <uint8 *> (address);
while (*reinterpret_cast <uint16 *> (ptr) == jmp) {
ptr = **reinterpret_cast <uint8 ***> (ptr + 2);
}
originalFun_ = reinterpret_cast <uint> (ptr);
hookedFun_ = reinterpret_cast <uint> (replacement);
memcpy (originalBytes_.get (), reinterpret_cast <void *> (originalFun_), CodeLength);
if (plat.x64) {
const uint16 nop = 0x00000000;
memcpy (&hookedBytes_[0], &jmp, sizeof (uint16));
memcpy (&hookedBytes_[2], &nop, sizeof (uint16));
memcpy (&hookedBytes_[6], &replacement, sizeof (uint));
}
else {
hookedBytes_[0] = 0xe9;
auto rel = hookedFun_ - originalFun_ - CodeLength;
memcpy (&hookedBytes_[0] + 1, &rel, sizeof (rel));
}
return enable ();
}
bool enable () {
if (patched_) {
return false;
}
patched_ = true;
if (unprotect ()) {
memcpy (reinterpret_cast <void *> (originalFun_), hookedBytes_.get (), CodeLength);
return true;
}
return false;
}
bool disable () {
if (!patched_) {
return false;
}
patched_ = false;
if (unprotect ()) {
memcpy (reinterpret_cast <void *> (originalFun_), originalBytes_.get (), CodeLength);
return true;
}
return false;
}
bool enabled () const {
return patched_;
}
public:
template <typename T, typename... Args > decltype (auto) call (Args &&...args) {
disable ();
auto res = reinterpret_cast <T *> (originalFun_) (args...);
enable ();
return res;
}
};
CR_NAMESPACE_END

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -47,11 +54,11 @@ CR_NAMESPACE_BEGIN
class Socket final : public DenyCopying {
private:
int32 m_socket;
uint32 m_timeout;
int32 socket_;
uint32 timeout_;
public:
Socket () : m_socket (-1), m_timeout (2) {
Socket () : socket_ (-1), timeout_ (2) {
#if defined(CR_WINDOWS)
WSADATA wsa;
@ -70,43 +77,45 @@ public:
public:
bool connect (const String &hostname) {
bool connect (StringRef hostname) {
addrinfo hints, *result = nullptr;
plat.bzero (&hints, sizeof (hints));
hints.ai_flags = AI_NUMERICSERV;
constexpr auto NumericServ = 0x00000008;
hints.ai_flags = NumericServ;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo (hostname.chars (), "80", &hints, &result) != 0) {
return false;
}
m_socket = static_cast <int> (socket (result->ai_family, result->ai_socktype, 0));
socket_ = static_cast <int> (socket (result->ai_family, result->ai_socktype, 0));
if (m_socket < 0) {
if (socket_ < 0) {
freeaddrinfo (result);
return false;
}
auto getTimeouts = [&] () -> Twin <char *, size_t> {
auto getTimeouts = [&] () -> Twin <char *, int32> {
#if defined (CR_WINDOWS)
DWORD tv = m_timeout * 1000;
DWORD tv = timeout_ * 1000;
#else
timeval tv { static_cast <time_t> (m_timeout), 0 };
timeval tv { static_cast <time_t> (timeout_), 0 };
#endif
return { reinterpret_cast <char *> (&tv), sizeof (tv) };
return { reinterpret_cast <char *> (&tv), static_cast <int32> (sizeof (tv)) };
};
auto timeouts = getTimeouts ();
if (setsockopt (m_socket, SOL_SOCKET, SO_RCVTIMEO, timeouts.first, timeouts.second) == -1) {
if (setsockopt (socket_, SOL_SOCKET, SO_RCVTIMEO, timeouts.first, timeouts.second) == -1) {
logger.message ("Unable to set SO_RCVTIMEO.");
}
if (setsockopt (m_socket, SOL_SOCKET, SO_SNDTIMEO, timeouts.first, timeouts.second) == -1) {
if (setsockopt (socket_, SOL_SOCKET, SO_SNDTIMEO, timeouts.first, timeouts.second) == -1) {
logger.message ("Unable to set SO_SNDTIMEO.");
}
if (::connect (m_socket, result->ai_addr, static_cast <decltype (result->ai_addrlen)> (result->ai_addrlen)) == -1) {
if (::connect (socket_, result->ai_addr, static_cast <int32> (result->ai_addrlen)) == -1) {
disconnect ();
freeaddrinfo (result);
@ -118,33 +127,33 @@ public:
}
void setTimeout (uint32 timeout) {
m_timeout = timeout;
timeout_ = timeout;
}
void disconnect () {
#if defined(CR_WINDOWS)
if (m_socket != -1) {
closesocket (m_socket);
if (socket_ != -1) {
closesocket (socket_);
}
#else
if (m_socket != -1)
close (m_socket);
if (socket_ != -1)
close (socket_);
#endif
}
public:
template <typename U> int32 send (const U *buffer, int32 length) const {
return ::send (m_socket, reinterpret_cast <const char *> (buffer), length, 0);
return ::send (socket_, reinterpret_cast <const char *> (buffer), length, 0);
}
template <typename U> int32 recv (U *buffer, int32 length) {
return ::recv (m_socket, reinterpret_cast <char *> (buffer), length, 0);
return ::recv (socket_, reinterpret_cast <char *> (buffer), length, 0);
}
public:
static int32 CR_STDCALL sendto (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int32 destLength) {
#if defined (CR_WINDOWS)
WSABUF buffer = { length, const_cast <char *> (reinterpret_cast <const char *> (message)) };
WSABUF buffer = { static_cast <ULONG> (length), const_cast <char *> (reinterpret_cast <const char *> (message)) };
DWORD sendLength = 0;
if (WSASendTo (socket, &buffer, 1, &sendLength, flags, dest, destLength, NULL, NULL) == SOCKET_ERROR) {
@ -173,7 +182,7 @@ namespace detail {
String path, protocol, host;
public:
static HttpUri parse (const String &uri) {
static HttpUri parse (StringRef uri) {
HttpUri result;
if (uri.empty ()) {
@ -184,11 +193,11 @@ namespace detail {
if (protocol != String::InvalidIndex) {
result.protocol = uri.substr (0, protocol);
size_t host = uri.find ("/", protocol + 3);
size_t hostIndex = uri.find ("/", protocol + 3);
if (host != String::InvalidIndex) {
result.path = uri.substr (host + 1);
result.host = uri.substr (protocol + 3, host - protocol - 3);
if (hostIndex != String::InvalidIndex) {
result.path = uri.substr (hostIndex + 1);
result.host = uri.substr (protocol + 3, hostIndex - protocol - 3);
return result;
}
@ -206,10 +215,10 @@ private:
};
private:
Socket m_socket;
String m_userAgent = "crlib";
HttpClientResult m_code = HttpClientResult::Undefined;
int32 m_chunkSize = 4096;
Socket socket_;
String userAgent_ = "crlib";
HttpClientResult statusCode_ = HttpClientResult::Undefined;
int32 chunkSize_ = 4096;
public:
HttpClient () = default;
@ -221,8 +230,8 @@ private:
int32 pos = 0, symbols = 0, errors = 0;
// prase response header
while (!isFinished && pos < m_chunkSize) {
if (m_socket.recv (&buffer[pos], 1) < 1) {
while (!isFinished && pos < chunkSize_) {
if (socket_.recv (&buffer[pos], 1) < 1) {
if (++errors > MaxReceiveErrors) {
isFinished = true;
}
@ -246,11 +255,12 @@ private:
}
++pos;
}
String response (reinterpret_cast <const char *> (buffer));
String response { reinterpret_cast <const char *> (buffer) };
size_t responseCodeStart = response.find ("HTTP/1.1");
if (responseCodeStart != String::InvalidIndex) {
String respCode = response.substr (responseCodeStart + 9, 3).trim ();
String respCode = response.substr (responseCodeStart + 9, 3);
respCode.trim ();
if (respCode == "200") {
return HttpClientResult::OK;
@ -268,46 +278,46 @@ private:
public:
// simple blocked download
bool downloadFile (const String &url, const String &localPath) {
bool downloadFile (StringRef url, StringRef localPath) {
if (File::exists (localPath.chars ())) {
m_code = HttpClientResult::LocalFileExists;
statusCode_ = HttpClientResult::LocalFileExists;
return false;
}
auto uri = detail::HttpUri::parse (url);
// no https...
if (uri.protocol == "https") {
m_code = HttpClientResult::HttpOnly;
statusCode_ = HttpClientResult::HttpOnly;
return false;
}
// unable to connect...
if (!m_socket.connect (uri.host)) {
m_code = HttpClientResult::ConnectError;
m_socket.disconnect ();
if (!socket_.connect (uri.host)) {
statusCode_ = HttpClientResult::ConnectError;
socket_.disconnect ();
return false;
}
String request;
request.appendf ("GET /%s HTTP/1.1\r\n", uri.path.chars ());
request.appendf ("GET /%s HTTP/1.1\r\n", uri.path);
request.append ("Accept: */*\r\n");
request.append ("Connection: close\r\n");
request.append ("Keep-Alive: 115\r\n");
request.appendf ("User-Agent: %s\r\n", m_userAgent.chars ());
request.appendf ("Host: %s\r\n\r\n", uri.host.chars ());
request.appendf ("User-Agent: %s\r\n", userAgent_);
request.appendf ("Host: %s\r\n\r\n", uri.host);
if (m_socket.send (request.chars (), static_cast <int32> (request.length ())) < 1) {
m_code = HttpClientResult::SocketError;
m_socket.disconnect ();
if (socket_.send (request.chars (), static_cast <int32> (request.length ())) < 1) {
statusCode_ = HttpClientResult::SocketError;
socket_.disconnect ();
return false;
}
SmallArray <uint8> buffer (m_chunkSize);
m_code = parseResponseHeader (buffer.data ());
SmallArray <uint8> buffer (chunkSize_);
statusCode_ = parseResponseHeader (buffer.data ());
if (m_code != HttpClientResult::OK) {
m_socket.disconnect ();
if (statusCode_ != HttpClientResult::OK) {
socket_.disconnect ();
return false;
}
@ -315,8 +325,8 @@ public:
File file (localPath, "wb");
if (!file) {
m_code = HttpClientResult::Undefined;
m_socket.disconnect ();
statusCode_ = HttpClientResult::Undefined;
socket_.disconnect ();
return false;
}
@ -324,7 +334,7 @@ public:
int32 errors = 0;
for (;;) {
length = m_socket.recv (buffer.data (), m_chunkSize);
length = socket_.recv (buffer.data (), chunkSize_);
if (length > 0) {
file.write (buffer.data (), length);
@ -335,29 +345,29 @@ public:
}
file.close ();
m_socket.disconnect ();
m_code = HttpClientResult::OK;
socket_.disconnect ();
statusCode_ = HttpClientResult::OK;
return true;
}
bool uploadFile (const String &url, const String &localPath) {
bool uploadFile (StringRef url, StringRef localPath) {
if (!File::exists (localPath.chars ())) {
m_code = HttpClientResult::NoLocalFile;
statusCode_ = HttpClientResult::NoLocalFile;
return false;
}
auto uri = detail::HttpUri::parse (url);
// no https...
if (uri.protocol == "https") {
m_code = HttpClientResult::HttpOnly;
statusCode_ = HttpClientResult::HttpOnly;
return false;
}
// unable to connect...
if (!m_socket.connect (uri.host)) {
m_code = HttpClientResult::ConnectError;
m_socket.disconnect ();
if (!socket_.connect (uri.host)) {
statusCode_ = HttpClientResult::ConnectError;
socket_.disconnect ();
return false;
}
@ -366,8 +376,8 @@ public:
File file (localPath, "rb");
if (!file) {
m_code = HttpClientResult::Undefined;
m_socket.disconnect ();
statusCode_ = HttpClientResult::Undefined;
socket_.disconnect ();
return false;
}
@ -377,44 +387,44 @@ public:
if (boundarySlash != String::InvalidIndex) {
boundaryName = localPath.substr (boundarySlash + 1);
}
const String &boundaryLine = "---crlib_upload_boundary_1337";
StringRef boundaryLine = "---crlib_upload_boundary_1337";
String request, start, end;
start.appendf ("--%s\r\n", boundaryLine.chars ());
start.appendf ("Content-Disposition: form-data; name='file'; filename='%s'\r\n", boundaryName.chars ());
start.appendf ("--%s\r\n", boundaryLine);
start.appendf ("Content-Disposition: form-data; name='file'; filename='%s'\r\n", boundaryName);
start.append ("Content-Type: application/octet-stream\r\n\r\n");
end.appendf ("\r\n--%s--\r\n\r\n", boundaryLine.chars ());
end.appendf ("\r\n--%s--\r\n\r\n", boundaryLine);
request.appendf ("POST /%s HTTP/1.1\r\n", uri.path.chars ());
request.appendf ("Host: %s\r\n", uri.host.chars ());
request.appendf ("User-Agent: %s\r\n", m_userAgent.chars ());
request.appendf ("Content-Type: multipart/form-data; boundary=%s\r\n", boundaryLine.chars ());
request.appendf ("POST /%s HTTP/1.1\r\n", uri.path);
request.appendf ("Host: %s\r\n", uri.host);
request.appendf ("User-Agent: %s\r\n", userAgent_);
request.appendf ("Content-Type: multipart/form-data; boundary=%s\r\n", boundaryLine);
request.appendf ("Content-Length: %d\r\n\r\n", file.length () + start.length () + end.length ());
// send the main request
if (m_socket.send (request.chars (), static_cast <int32> (request.length ())) < 1) {
m_code = HttpClientResult::SocketError;
m_socket.disconnect ();
if (socket_.send (request.chars (), static_cast <int32> (request.length ())) < 1) {
statusCode_ = HttpClientResult::SocketError;
socket_.disconnect ();
return false;
}
// send boundary start
if (m_socket.send (start.chars (), static_cast <int32> (start.length ())) < 1) {
m_code = HttpClientResult::SocketError;
m_socket.disconnect ();
if (socket_.send (start.chars (), static_cast <int32> (start.length ())) < 1) {
statusCode_ = HttpClientResult::SocketError;
socket_.disconnect ();
return false;
}
SmallArray <uint8> buffer (m_chunkSize);
SmallArray <uint8> buffer (chunkSize_);
int32 length = 0;
for (;;) {
length = static_cast <int32> (file.read (buffer.data (), 1, m_chunkSize));
length = static_cast <int32> (file.read (buffer.data (), 1, chunkSize_));
if (length > 0) {
m_socket.send (buffer.data (), length);
socket_.send (buffer.data (), length);
}
else {
break;
@ -422,37 +432,37 @@ public:
}
// send boundary end
if (m_socket.send (end.chars (), static_cast <int32> (end.length ())) < 1) {
m_code = HttpClientResult::SocketError;
m_socket.disconnect ();
if (socket_.send (end.chars (), static_cast <int32> (end.length ())) < 1) {
statusCode_ = HttpClientResult::SocketError;
socket_.disconnect ();
return false;
}
m_code = parseResponseHeader (buffer.data ());
m_socket.disconnect ();
statusCode_ = parseResponseHeader (buffer.data ());
socket_.disconnect ();
return m_code == HttpClientResult::OK;
return statusCode_ == HttpClientResult::OK;
}
public:
void setUserAgent (const String &ua) {
m_userAgent = ua;
void setUserAgent (StringRef ua) {
userAgent_ = ua;
}
HttpClientResult getLastStatusCode () {
return m_code;
return statusCode_;
}
void setChunkSize (int32 chunkSize) {
m_chunkSize = chunkSize;
chunkSize_ = chunkSize;
}
void setTimeout (uint32 timeout) {
m_socket.setTimeout (timeout);
socket_.setTimeout (timeout);
}
};
// expose global http client
CR_EXPOSE_GLOBAL_SINGLETON (HttpClient, http);
CR_NAMESPACE_END
CR_NAMESPACE_END

182
ext/crlib/cr-lambda.h Normal file
View file

@ -0,0 +1,182 @@
//
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#include <crlib/cr-alloc.h>
#include <crlib/cr-uniqueptr.h>
CR_NAMESPACE_BEGIN
template <typename> class Lambda;
template <typename R, typename ...Args> class Lambda <R (Args...)> {
private:
enum : uint32 {
LamdaSmallBufferLength = sizeof (void *) * 16
};
private:
class LambdaFunctorWrapper {
public:
LambdaFunctorWrapper () = default;
virtual ~LambdaFunctorWrapper () = default;
public:
virtual void move (uint8 *to) = 0;
virtual void small (uint8 *to) const = 0;
virtual R invoke (Args &&...) = 0;
virtual UniquePtr <LambdaFunctorWrapper> clone () const = 0;
public:
void operator delete (void *ptr) {
alloc.deallocate (ptr);
}
};
template <typename T> class LambdaFunctor : public LambdaFunctorWrapper {
private:
T callable_;
public:
LambdaFunctor (const T &callable) : LambdaFunctorWrapper (), callable_ (callable)
{ }
LambdaFunctor (T &&callable) : LambdaFunctorWrapper (), callable_ (cr::move (callable))
{ }
~LambdaFunctor () override = default;
public:
void move (uint8 *to) override {
new (to) LambdaFunctor <T> (cr::move (callable_));
}
void small (uint8 *to) const override {
new (to) LambdaFunctor <T> (callable_);
}
R invoke (Args &&... args) override {
return callable_ (cr::forward <Args> (args)...);
}
UniquePtr <LambdaFunctorWrapper> clone () const override {
return makeUnique <LambdaFunctor <T>> (callable_);
}
};
union {
UniquePtr <LambdaFunctorWrapper> functor_;
uint8 small_[LamdaSmallBufferLength];
};
bool ssoObject_ = false;
private:
void destroy () {
if (ssoObject_) {
reinterpret_cast <LambdaFunctorWrapper *> (small_)->~LambdaFunctorWrapper ();
}
else {
functor_.reset ();
}
}
void swap (Lambda &rhs) noexcept {
cr::swap (rhs, *this);
}
public:
explicit Lambda () noexcept : Lambda (nullptr)
{ }
Lambda (decltype (nullptr)) noexcept : functor_ (nullptr), ssoObject_ (false)
{ }
Lambda (const Lambda &rhs) {
if (rhs.ssoObject_) {
reinterpret_cast <const LambdaFunctorWrapper *> (rhs.small_)->small (small_);
}
else {
new (small_) UniquePtr <LambdaFunctorWrapper> (rhs.functor_->clone ());
}
ssoObject_ = rhs.ssoObject_;
}
Lambda (Lambda &&rhs) noexcept {
if (rhs.ssoObject_) {
reinterpret_cast <LambdaFunctorWrapper *> (rhs.small_)->move (small_);
new (rhs.small_) UniquePtr <LambdaFunctorWrapper> (nullptr);
}
else {
new (small_) UniquePtr <LambdaFunctorWrapper> (cr::move (rhs.functor_));
}
ssoObject_ = rhs.ssoObject_;
rhs.ssoObject_ = false;
}
template <typename F> Lambda (F function) {
if (cr::fix (sizeof (function) > LamdaSmallBufferLength)) {
ssoObject_ = false;
new (small_) UniquePtr <LambdaFunctorWrapper> (makeUnique <LambdaFunctor <F>> (cr::move (function)));
}
else {
ssoObject_ = true;
new (small_) LambdaFunctor <F> (cr::move (function));
}
}
~Lambda () {
destroy ();
}
public:
Lambda &operator = (const Lambda &rhs) {
destroy ();
Lambda tmp (rhs);
swap (tmp);
return *this;
}
Lambda &operator = (Lambda &&rhs) noexcept {
destroy ();
if (rhs.ssoObject_) {
reinterpret_cast <LambdaFunctorWrapper *> (rhs.small_)->move (small_);
new (rhs.small_) UniquePtr <LambdaFunctorWrapper> (nullptr);
}
else {
new (small_) UniquePtr <LambdaFunctorWrapper> (cr::move (rhs.functor_));
}
ssoObject_ = rhs.ssoObject_;
rhs.ssoObject_ = false;
return *this;
}
explicit operator bool () const noexcept {
return ssoObject_ || !!functor_;
}
public:
R operator () (Args ...args) {
return ssoObject_ ? reinterpret_cast <LambdaFunctorWrapper *> (small_)->invoke (cr::forward <Args> (args)...) : functor_->invoke (cr::forward <Args> (args)...);
}
};
CR_NAMESPACE_END

130
ext/crlib/cr-library.h Normal file
View file

@ -0,0 +1,130 @@
//
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-string.h>
#if defined (CR_LINUX) || defined (CR_OSX)
# include <dlfcn.h>
# include <errno.h>
# include <fcntl.h>
# include <sys/stat.h>
# include <unistd.h>
#endif
CR_NAMESPACE_BEGIN
// handling dynamic library loading
class SharedLibrary final : public DenyCopying {
public:
using Handle = void *;
private:
Handle handle_ = nullptr;
public:
explicit SharedLibrary () = default;
SharedLibrary (StringRef file) {
if (file.empty ()) {
return;
}
load (file);
}
~SharedLibrary () {
unload ();
}
public:
bool load (StringRef file) noexcept {
if (*this) {
unload ();
}
#if defined (CR_WINDOWS)
handle_ = LoadLibraryA (file.chars ());
#else
handle_ = dlopen (file.chars (), RTLD_LAZY);
#endif
return handle_ != nullptr;
}
bool locate (Handle address) {
#if defined (CR_WINDOWS)
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQuery (address, &mbi, sizeof (mbi))) {
return false;
}
if (mbi.State != MEM_COMMIT) {
return false;
}
handle_ = reinterpret_cast <Handle> (mbi.AllocationBase);
#else
Dl_info dli;
plat.bzero (&dli, sizeof (dli));
if (dladdr (address, &dli)) {
return load (dli.dli_fname);
}
#endif
return handle_ != nullptr;
}
void unload () noexcept {
if (!*this) {
return;
}
#if defined (CR_WINDOWS)
FreeLibrary (static_cast <HMODULE> (handle_));
#else
dlclose (handle_);
#endif
handle_ = nullptr;
}
template <typename R> R resolve (const char *function) const {
if (!*this) {
return nullptr;
}
return SharedLibrary::getSymbol <R> (handle (), function);
}
Handle handle () const {
return handle_;
}
public:
explicit operator bool () const {
return handle_ != nullptr;
}
public:
template <typename R> static inline R CR_STDCALL getSymbol (Handle module, const char *function) {
return reinterpret_cast <R> (
#if defined (CR_WINDOWS)
GetProcAddress (static_cast <HMODULE> (module), function)
#else
dlsym (module, function)
#endif
);
}
};
CR_NAMESPACE_END

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -20,19 +27,19 @@ public:
using PrintFunction = Lambda <void (const char *)>;
private:
File m_handle;
PrintFunction m_printer;
File handle_;
PrintFunction printFun_;
public:
SimpleLogger () = default;
~SimpleLogger () {
m_handle.close ();
handle_.close ();
}
private:
void logToFile (const char *level, const char *msg) {
if (!m_handle) {
if (!handle_) {
return;
}
time_t ticks = time (&ticks);
@ -50,48 +57,48 @@ private:
auto timebuf = strings.chars ();
strftime (timebuf, StringBuffer::StaticBufferSize, "%Y-%m-%d %H:%M:%S", timeinfo);
m_handle.puts ("%s (%s): %s\n", timebuf, level, msg);
handle_.puts ("%s (%s): %s\n", timebuf, level, msg);
}
public:
template <typename ...Args> void fatal (const char *fmt, Args ...args) {
template <typename ...Args> void fatal (const char *fmt, Args &&...args) {
auto msg = strings.format (fmt, cr::forward <Args> (args)...);
logToFile ("FATAL", msg);
if (m_printer) {
m_printer (msg);
if (printFun_) {
printFun_ (msg);
}
plat.abort (msg);
}
template <typename ...Args> void error (const char *fmt, Args ...args) {
template <typename ...Args> void error (const char *fmt, Args &&...args) {
auto msg = strings.format (fmt, cr::forward <Args> (args)...);
logToFile ("ERROR", msg);
if (m_printer) {
m_printer (msg);
if (printFun_) {
printFun_ (msg);
}
}
template <typename ...Args> void message (const char *fmt, Args ...args) {
template <typename ...Args> void message (const char *fmt, Args &&...args) {
auto msg = strings.format (fmt, cr::forward <Args> (args)...);
logToFile ("INFO", msg);
if (m_printer) {
m_printer (msg);
if (printFun_) {
printFun_ (msg);
}
}
public:
void initialize (const String &filename, PrintFunction printFunction) {
if (m_handle) {
m_handle.close ();
void initialize (StringRef filename, PrintFunction printFunction) {
if (handle_) {
handle_.close ();
}
m_printer = cr::move (printFunction);
m_handle.open (filename, "at");
printFun_ = cr::move (printFunction);
handle_.open (filename, "at");
}
};

View file

@ -1,19 +1,28 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#include <crlib/cr-basic.h>
#if defined (CR_HAS_SSE2)
# include <immintrin.h>
#if defined (CR_HAS_SSE)
# include <pmmintrin.h>
#endif
#include <math.h>
CR_NAMESPACE_BEGIN
constexpr float kFloatEpsilon = 0.01f;
@ -21,8 +30,7 @@ constexpr float kFloatEqualEpsilon = 0.001f;
constexpr float kFloatCmpEpsilon = 1.192092896e-07f;
constexpr float kMathPi = 3.141592653589793115997963468544185161590576171875f;
constexpr float kMathPiReciprocal = 1.0f / kMathPi;
constexpr float kMathPiHalf = kMathPi / 2;
constexpr float kMathPiHalf = kMathPi * 0.5f;
constexpr float kDegreeToRadians = kMathPi / 180.0f;
constexpr float kRadiansToDegree = 180.0f / kMathPi;
@ -35,11 +43,11 @@ constexpr bool fequal (const float a, const float b) {
return cr:: abs (a - b) < kFloatEqualEpsilon;
}
constexpr float radiansToDegrees (const float r) {
constexpr float rad2deg (const float r) {
return r * kRadiansToDegree;
}
constexpr float degreesToRadians (const float d) {
constexpr float deg2rad (const float d) {
return d * kDegreeToRadians;
}
@ -56,82 +64,39 @@ constexpr float anglesDifference (const float a, const float b) {
}
inline float sinf (const float value) {
const auto sign = static_cast <int32> (value * kMathPiReciprocal);
const float calc = (value - static_cast <float> (sign) * kMathPi);
const float sqr = cr::square (calc);
const float res = 1.00000000000000000000e+00f + sqr * (-1.66666671633720397949e-01f + sqr * (8.33333376795053482056e-03f + sqr * (-1.98412497411482036114e-04f +
sqr * (2.75565571428160183132e-06f + sqr * (-2.50368472620721149724e-08f + sqr * (1.58849267073435385100e-10f + sqr * -6.58925550841432672300e-13f))))));
return (sign & 1) ? -calc * res : value * res;
return ::sinf (value);
}
inline float cosf (const float value) {
const auto sign = static_cast <int32> (value * kMathPiReciprocal);
const float calc = (value - static_cast <float> (sign) * kMathPi);
const float sqr = cr::square (calc);
const float res = sqr * (-5.00000000000000000000e-01f + sqr * (4.16666641831398010254e-02f + sqr * (-1.38888671062886714935e-03f + sqr * (2.48006890615215525031e-05f +
sqr * (-2.75369927749125054106e-07f + sqr * (2.06207229069832465029e-09f + sqr * -9.77507137733812925262e-12f))))));
const float f = -1.00000000000000000000e+00f;
return (sign & 1) ? f - res : -f + res;
return ::cosf (value);
}
inline float atanf (const float x) {
const float sqr = cr::square (x);
return x * (48.70107004404898384f + sqr * (49.5326263772254345f + sqr * 9.40604244231624f)) / (48.70107004404996166f + sqr * (65.7663163908956299f + sqr * (21.587934067020262f + sqr)));
inline float atanf (const float value) {
return ::atanf (value);
}
inline float atan2f (const float y, const float x) {
const float ax = cr::abs (x);
const float ay = cr::abs (y);
if (ax < 1e-7f && ay < 1e-7f) {
return 0.0f;
}
if (ax > ay) {
if (x < 0.0f) {
if (y >= 0.0f) {
return atanf (y / x) + kMathPi;
}
return atanf (y / x) - kMathPi;
}
return atanf (y / x);
}
if (y < 0.0f) {
return atanf (-x / y) - kMathPiHalf;
}
return atanf (-x / y) + kMathPiHalf;
return ::atan2f (y, x);
}
inline float powf (const float x, const float y) {
union {
float d;
int x;
} res { x };
res.x = static_cast <int> (y * (res.x - 1064866805) + 1064866805);
return res.d;
return ::powf (x, y);
}
inline float sqrtf (const float value) {
return powf (value, 0.5f);
return ::sqrtf (value);
}
inline float tanf (const float value) {
return sinf (value) / cosf (value);
return ::tanf (value);
}
constexpr float ceilf (const float x) {
return static_cast <float> (65536 - static_cast <int> (65536.0f - x));
inline float ceilf (const float value) {
return ::ceilf (value);
}
inline void sincosf (const float x, const float y, const float z, float *sines, float *cosines) {
#if defined (CR_HAS_SSE2)
#if defined (CR_HAS_SSE)
auto set = _mm_set_ps (x, y, z, 0.0f);
auto _mm_sin = [] (__m128 rad) -> __m128 {
@ -175,4 +140,4 @@ inline void sincosf (const float x, const float y, const float z, float *sines,
#endif
}
CR_NAMESPACE_END
CR_NAMESPACE_END

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -54,4 +61,4 @@ template <typename T, size_t S> inline void swap (T (&left)[S], T (&right)[S]) n
}
}
CR_NAMESPACE_END
CR_NAMESPACE_END

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -28,9 +35,19 @@ CR_NAMESPACE_BEGIN
// detects the compiler
#if defined(_MSC_VER)
# define CR_CXX_MSVC
#elif defined(__clang__)
# define CR_CXX_CLANG
# define CR_CXX_MSVC _MSC_VER
#endif
#if defined(__clang__)
# define CR_CXX_CLANG __clang__
#endif
#if defined(__INTEL_COMPILER)
# define CR_CXX_INTEL __INTEL_COMPILER
#endif
#if defined(__GNUC__)
# define CR_CXX_GCC __GNUC__
#endif
// configure macroses
@ -60,7 +77,24 @@ CR_NAMESPACE_BEGIN
#endif
#if (defined(CR_ARCH_X86) || defined(CR_ARCH_X64)) && !defined(CR_DEBUG)
# define CR_HAS_SSE2
# define CR_HAS_SSE
#endif
#if defined(CR_HAS_SSE)
# if defined (CR_CXX_MSVC)
# define CR_ALIGN16 __declspec (align (16))
# else
# define CR_ALIGN16 __attribute__((aligned(16)))
# endif
#endif
// disable warnings regarding intel compiler
#if defined(CR_CXX_INTEL)
# pragma warning (disable : 3280) // declaration hides member "XXX" (declared at line XX)
# pragma warning (disable : 2415) // variable "XXX" of static storage duration was declared but never referenced
# pragma warning (disable : 873) // function "operator new(size_t={unsigned int}, void *)" has no corresponding operator delete (to be called if an exception is thrown during initialization of an allocated object)
# pragma warning (disable : 383) // value copied to temporary, reference to temporary used
# pragma warning (disable : 11074 11075) // remarks about inlining bla-bla-bla
#endif
CR_NAMESPACE_END
@ -97,8 +131,6 @@ CR_NAMESPACE_END
CR_NAMESPACE_BEGIN
class String;
// helper struct for platform detection
struct Platform : public Singleton <Platform> {
bool win32 = false;
@ -230,7 +262,7 @@ struct Platform : public Singleton <Platform> {
static char result[256];
bzero (result, sizeof (result));
#if defined(CR_WINDOWS)
#if defined(CR_WINDOWS) && !defined(CR_CXX_GCC)
char *buffer = nullptr;
size_t size = 0;
@ -248,4 +280,4 @@ struct Platform : public Singleton <Platform> {
// expose platform singleton
CR_EXPOSE_GLOBAL_SINGLETON (Platform, plat);
CR_NAMESPACE_END
CR_NAMESPACE_END

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -16,17 +23,17 @@ CR_NAMESPACE_BEGIN
// random number generator see: https://github.com/preshing/RandomSequence/
class Random final : public Singleton <Random> {
private:
uint32 m_index, m_offset;
uint64 m_divider;
uint32 index_, offset_;
uint64 divider_;
public:
explicit Random () {
const auto base = static_cast <uint32> (time (nullptr));
const auto offset = base + 1;
m_index = premute (premute (base) + 0x682f0161);
m_offset = premute (premute (offset) + 0x46790905);
m_divider = (static_cast <uint64> (1)) << 32;
index_ = premute (premute (base) + 0x682f0161);
offset_ = premute (premute (offset) + 0x46790905);
divider_ = (static_cast <uint64> (1)) << 32;
}
~Random () = default;
@ -42,16 +49,16 @@ private:
}
uint32 generate () {
return premute ((premute (m_index++) + m_offset) ^ 0x5bf03635);
return premute ((premute (index_++) + offset_) ^ 0x5bf03635);
}
public:
template <typename U> U int_ (U low, U high) {
return static_cast <U> (generate () * (static_cast <double> (high) - static_cast <double> (low) + 1.0) / m_divider + static_cast <double> (low));
return static_cast <U> (generate () * (static_cast <double> (high) - static_cast <double> (low) + 1.0) / divider_ + static_cast <double> (low));
}
float float_ (float low, float high) {
return static_cast <float> (generate () * (static_cast <double> (high) - static_cast <double> (low)) / (m_divider - 1) + static_cast <double> (low));
return static_cast <float> (generate () * (static_cast <double> (high) - static_cast <double> (low)) / (divider_ - 1) + static_cast <double> (low));
}
template <typename U> bool chance (const U max, const U maxChance = 100) {
@ -62,4 +69,4 @@ public:
// expose global random generator
CR_EXPOSE_GLOBAL_SINGLETON (Random, rg);
CR_NAMESPACE_END
CR_NAMESPACE_END

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -54,4 +61,4 @@ public:
}
};
CR_NAMESPACE_END
CR_NAMESPACE_END

View file

@ -1,10 +1,17 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -36,20 +43,20 @@ private:
private:
SmallArray <int32> m_hashTable;
SmallArray <int32> m_prevTable;
SmallArray <int32> hashTable_;
SmallArray <int32> prevTable_;
public:
explicit ULZ () {
m_hashTable.resize (HashLength);
m_prevTable.resize (WindowSize);
hashTable_.resize (HashLength);
prevTable_.resize (WindowSize);
}
~ULZ () = default;
public:
int32 compress (uint8 *in, int32 inputLength, uint8 *out) {
for (auto &htb : m_hashTable) {
for (auto &htb : hashTable_) {
htb = EmptyHash;
}
auto op = out;
@ -67,7 +74,7 @@ public:
const int32 limit = cr::max <int32> (cur - WindowSize, EmptyHash);
int32 chainLength = MaxChain;
int32 lookup = m_hashTable[hash32 (&in[cur])];
int32 lookup = hashTable_[hash32 (&in[cur])];
while (lookup > limit) {
if (in[lookup + bestLength] == in[cur + bestLength] && load <uint32> (&in[lookup]) == load <uint32> (&in[cur])) {
@ -90,7 +97,7 @@ public:
if (--chainLength == 0) {
break;
}
lookup = m_prevTable[lookup & WindowMask];
lookup = prevTable_[lookup & WindowMask];
}
}
@ -104,7 +111,7 @@ public:
const auto limit = cr::max <int32> (next - WindowSize, EmptyHash);
int32 chainLength = MaxChain;
int32 lookup = m_hashTable[hash32 (&in[next])];
int32 lookup = hashTable_[hash32 (&in[next])];
while (lookup > limit) {
if (in[lookup + bestLength] == in[next + bestLength] && load <uint32> (&in[lookup]) == load <uint32> (&in[next])) {
@ -123,7 +130,7 @@ public:
if (--chainLength == 0) {
break;
}
lookup = m_prevTable[lookup & WindowMask];
lookup = prevTable_[lookup & WindowMask];
}
}
@ -151,22 +158,22 @@ public:
if (length >= 15) {
encode (op, length - 15);
}
store16 (op, dist);
store16 (op, static_cast <uint16> (dist));
op += 2;
while (bestLength-- != 0) {
const auto hash = hash32 (&in[cur]);
m_prevTable[cur & WindowMask] = m_hashTable[hash];
m_hashTable[hash] = cur++;
prevTable_[cur & WindowMask] = hashTable_[hash];
hashTable_[hash] = cur++;
}
anchor = cur;
}
else {
const auto hash = hash32 (&in[cur]);
m_prevTable[cur & WindowMask] = m_hashTable[hash];
m_hashTable[hash] = cur++;
prevTable_[cur & WindowMask] = hashTable_[hash];
hashTable_[hash] = cur++;
}
}
@ -183,7 +190,7 @@ public:
copy (op, &in[anchor], run);
op += run;
}
return op - out;
return static_cast <int32> (op - out);
}
int32 uncompress (uint8 *in, int32 inputLength, uint8 *out, int32 outLength) {
@ -258,7 +265,7 @@ private:
return ret;
}
void store16 (void *ptr, int32 val) {
void store16 (void *ptr, uint16 val) {
memcpy (ptr, &val, sizeof (uint16));
}
@ -307,4 +314,4 @@ private:
}
};
CR_NAMESPACE_END
CR_NAMESPACE_END

212
ext/crlib/cr-uniqueptr.h Normal file
View file

@ -0,0 +1,212 @@
//
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-alloc.h>
#include <crlib/cr-movable.h>
CR_NAMESPACE_BEGIN
// simple unique ptr
template <typename T> class UniquePtr final : public DenyCopying {
private:
T *ptr_ {};
public:
UniquePtr () = default;
explicit UniquePtr (T *ptr) : ptr_ (ptr)
{ }
UniquePtr (UniquePtr &&rhs) noexcept : ptr_ (rhs.release ())
{ }
template <typename U> UniquePtr (UniquePtr <U> &&rhs) noexcept : ptr_ (rhs.release ())
{ }
~UniquePtr () {
destroy ();
}
public:
T *get () const {
return ptr_;
}
T *release () {
auto ret = ptr_;
ptr_ = nullptr;
return ret;
}
void reset (T *ptr = nullptr) {
destroy ();
ptr_ = ptr;
}
private:
void destroy () {
alloc.destroy (ptr_);
ptr_ = nullptr;
}
public:
UniquePtr &operator = (UniquePtr &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
template <typename U> UniquePtr &operator = (UniquePtr <U> &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
UniquePtr &operator = (decltype (nullptr)) {
destroy ();
return *this;
}
T &operator * () const {
return *ptr_;
}
T *operator -> () const {
return ptr_;
}
explicit operator bool () const {
return ptr_ != nullptr;
}
};
template <typename T> class UniquePtr <T[]> final : public DenyCopying {
private:
T *ptr_ { };
public:
UniquePtr () = default;
explicit UniquePtr (T *ptr) : ptr_ (ptr)
{ }
UniquePtr (UniquePtr &&rhs) noexcept : ptr_ (rhs.release ())
{ }
template <typename U> UniquePtr (UniquePtr <U> &&rhs) noexcept : ptr_ (rhs.release ())
{ }
~UniquePtr () {
destroy ();
}
public:
T *get () const {
return ptr_;
}
T *release () {
auto ret = ptr_;
ptr_ = nullptr;
return ret;
}
void reset (T *ptr = nullptr) {
destroy ();
ptr_ = ptr;
}
private:
void destroy () {
alloc.destroy (ptr_);
ptr_ = nullptr;
}
public:
UniquePtr &operator = (UniquePtr &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
template <typename U> UniquePtr &operator = (UniquePtr <U> &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
UniquePtr &operator = (decltype (nullptr)) {
destroy ();
return *this;
}
T &operator [] (size_t index) {
return ptr_[index];
}
const T &operator [] (size_t index) const {
return ptr_[index];
}
explicit operator bool () const {
return ptr_ != nullptr;
}
};
namespace detail {
template <typename T> struct ClearExtent {
using Type = T;
};
template <typename T> struct ClearExtent <T[]> {
using Type = T;
};
template <typename T, size_t N> struct ClearExtent <T[N]> {
using Type = T;
};
template <typename T> struct UniqueIf {
using SingleObject = UniquePtr <T>;
};
template <typename T> struct UniqueIf<T[]> {
using UnknownBound = UniquePtr <T[]>;
};
template <typename T, size_t N> struct UniqueIf <T[N]> {
using KnownBound = void;
};
}
template <typename T, typename... Args> typename detail::UniqueIf <T>::SingleObject makeUnique (Args &&... args) {
return UniquePtr <T> (alloc.create <T> (cr::forward <Args> (args)...));
}
template <typename T> typename detail::UniqueIf <T>::UnknownBound makeUnique (size_t size) {
return UniquePtr <T> (alloc.createArray <typename detail::ClearExtent <T>::Type> (size));
}
template <typename T, typename... Args> typename detail::UniqueIf <T>::KnownBound makeUnique (Args &&...) = delete;
CR_NAMESPACE_END

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// CRLib - Simple library for STL replacement in private projects.
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -12,10 +19,56 @@
CR_NAMESPACE_BEGIN
// small simd operations for 3d vector
#if defined (CR_HAS_SSE)
template <typename T> class CR_ALIGN16 SimdWrap {
private:
__m128 wrap_dp_sse2 (__m128 v1, __m128 v2) {
auto mul = _mm_mul_ps (v1, v2);
auto res = _mm_add_ps (_mm_shuffle_ps (v2, mul, _MM_SHUFFLE (1, 0, 0, 0)), mul);
mul = _mm_add_ps (_mm_shuffle_ps (mul, res, _MM_SHUFFLE (0, 3, 0, 0)), res);
return _mm_shuffle_ps (mul, mul, _MM_SHUFFLE (2, 2, 2, 2));
}
public:
union {
__m128 m;
struct {
T x, y, z;
} vec;
};
SimdWrap (const T &x, const T &y, const T &z) {
m = _mm_set_ps (0.0f, z, y, x);
}
SimdWrap (const T &x, const T &y) {
m = _mm_set_ps (0.0f, 0.0f, y, x);
}
SimdWrap (__m128 m) : m (m)
{ }
public:
SimdWrap normalize () {
return { _mm_div_ps (m, _mm_sqrt_ps (wrap_dp_sse2 (m, m))) };
}
};
#endif
// 3dmath vector
template <typename T> class Vec3D {
public:
T x = 0.0f, y = 0.0f, z = 0.0f;
T x {};
T y {};
T z {};
public:
Vec3D (const T &scaler = 0.0f) : x (scaler), y (scaler), z (scaler)
@ -27,6 +80,11 @@ public:
Vec3D (T *rhs) : x (rhs[0]), y (rhs[1]), z (rhs[2])
{ }
#if defined (CR_HAS_SSE)
Vec3D (const SimdWrap <T> &rhs) : x (rhs.vec.x), y (rhs.vec.y), z (rhs.vec.z)
{ }
#endif
Vec3D (const Vec3D &) = default;
Vec3D (decltype (nullptr)) {
@ -123,6 +181,14 @@ public:
clear ();
}
const float &operator [] (const int i) const {
return &(x)[i];
}
float &operator [] (const int i) {
return &(x)[i];
}
Vec3D &operator = (const Vec3D &) = default;
public:
@ -131,11 +197,11 @@ public:
}
T length2d () const {
return cr::sqrtf (x * x + y * y);
return cr::sqrtf (cr::square (x) + cr::square (y));
}
T lengthSq () const {
return x * x + y * y + z * z;
return cr::square (x) + cr::square (y) + cr::square (z);
}
Vec3D get2d () const {
@ -143,6 +209,9 @@ public:
}
Vec3D normalize () const {
#if defined (CR_HAS_SSE)
return SimdWrap <T> { x, y, z }.normalize ();
#else
auto len = length () + cr::kFloatCmpEpsilon;
if (cr::fzero (len)) {
@ -150,9 +219,13 @@ public:
}
len = 1.0f / len;
return { x * len, y * len, z * len };
#endif
}
Vec3D normalize2d () const {
#if defined (CR_HAS_SSE)
return SimdWrap <T> { x, y }.normalize ();
#else
auto len = length2d () + cr::kFloatCmpEpsilon;
if (cr::fzero (len)) {
@ -160,6 +233,7 @@ public:
}
len = 1.0f / len;
return { x * len, y * len, 0.0f };
#endif
}
bool empty () const {
@ -179,24 +253,24 @@ public:
}
T pitch () const {
if (cr::fzero (x) && cr::fzero (y)) {
if (cr::fzero (z)) {
return 0.0f;
}
return cr::degreesToRadians (cr::atan2f (z, length2d ()));
return cr::deg2rad (cr::atan2f (z, length2d ()));
}
T yaw () const {
if (cr::fzero (x) && cr::fzero (y)) {
return 0.0f;
}
return cr::radiansToDegrees (cr:: atan2f (y, x));
return cr::rad2deg (cr:: atan2f (y, x));
}
Vec3D angles () const {
if (cr::fzero (x) && cr::fzero (y)) {
return { z > 0.0f ? 90.0f : 270.0f, 0.0, 0.0f };
}
return { cr::radiansToDegrees (cr::atan2f (z, length2d ())), cr::radiansToDegrees (cr::atan2f (y, x)), 0.0f };
return { cr::rad2deg (cr::atan2f (z, length2d ())), cr::rad2deg (cr::atan2f (y, x)), 0.0f };
}
void angleVectors (Vec3D *forward, Vec3D *right, Vec3D *upward) const {
@ -206,7 +280,7 @@ public:
T cosines[max] = { 0.0f, 0.0f, 0.0f, 0.0f };
// compute the sine and cosine compontents
cr::sincosf (cr::degreesToRadians (x), cr::degreesToRadians (y), cr::degreesToRadians (z), sines, cosines);
cr::sincosf (cr::deg2rad (x), cr::deg2rad (y), cr::deg2rad (z), sines, cosines);
if (forward) {
*forward = {
@ -258,4 +332,4 @@ public:
// default is float
using Vector = Vec3D <float>;
CR_NAMESPACE_END
CR_NAMESPACE_END

View file

@ -214,7 +214,7 @@ typedef struct enginefuncs_s {
void (*pfnCvar_DirectSet) (struct cvar_t *var, char *value);
void (*pfnForceUnmodified) (FORCE_TYPE type, float *mins, float *maxs, const char *szFilename);
void (*pfnGetPlayerStats) (const edict_t *client, int *ping, int *packet_loss);
void (*pfnAddServerCommand) (char *cmd_name, void (*function) ());
void (*pfnAddServerCommand) (const char *cmd_name, void (*function) ());
int (*pfnVoice_GetClientListening) (int iReceiver, int iSender);
int (*pfnVoice_SetClientListening) (int iReceiver, int iSender, int bListen);

View file

@ -25,15 +25,19 @@ typedef int qboolean;
typedef unsigned char byte;
#include <crlib/cr-vector.h>
#include <crlib/cr-string.h>
// idea from regamedll
class string_t final {
class string_t final : public cr::DenyCopying {
private:
int offset;
public:
explicit string_t () : offset (0) { }
string_t (int offset) : offset (offset) { }
explicit string_t () : offset (0)
{ }
string_t (int offset) : offset (offset)
{ }
~string_t () = default;
@ -101,11 +105,17 @@ static inline int MAKE_STRING (const char *val) {
return static_cast <int> (ptrdiff);
}
#else
#define MAKE_STRING(str) ((uint64)(str) - (uint64)(STRING(0)))
#define MAKE_STRING(str) ((uint64)(str) - (uint64)(STRING(0)))
#endif
inline const char *string_t::chars (size_t shift) const {
return STRING (offset) + shift;
auto result = STRING (offset);
return cr::strings.isEmpty (result) ? &cr::kNullChar : (result + shift);
}
enum HLBool : int32 {
HLFalse, HLTrue
};
#endif // EXTDLL_H

View file

@ -1,6 +1,32 @@
/*
* Copyright (c) 2001-2006 Will Day <willday@hpgx.net>
* See the file "dllapi.h" in this folder for full information
*
* This file is part of Metamod.
*
* Metamod is free software; you can 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.
*
* Metamod is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Metamod; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
*/
// Simplified version by Wei Mingzhi

View file

@ -226,4 +226,4 @@ typedef struct playermove_s {
physent_t physents[MAX_PHYSENTS];
} playermove_t;
#endif
#endif

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -15,7 +22,7 @@ struct BotName {
public:
BotName () = default;
BotName (String &name, int usedBy) : name (cr::move (name)), usedBy (usedBy) { }
BotName (StringRef name, int usedBy) : name (name), usedBy (usedBy) { }
};
// voice config structure definition
@ -25,7 +32,7 @@ struct ChatterItem {
float duration;
public:
ChatterItem (String name, float repeat, float duration) : name (cr::move (name)), repeat (repeat), duration (duration) { }
ChatterItem (StringRef name, float repeat, float duration) : name (name), repeat (repeat), duration (duration) { }
};
// language hasher
@ -46,6 +53,14 @@ struct HashLangString {
// mostly config stuff, and some stuff dealing with menus
class BotConfig final : public Singleton <BotConfig> {
public:
struct DifficultyData {
float reaction[2] {};
int32 headshotPct {};
int32 seenThruPct {};
int32 hearThruPct {};
};
private:
Array <StringArray> m_chat;
Array <Array <ChatterItem>> m_chatter;
@ -59,8 +74,9 @@ private:
StringArray m_avatars;
Dictionary <String, String, HashLangString> m_language;
Dictionary <int32, DifficultyData, IntNoHash <int32>> m_difficulty;
// default tables for personality weapon preferences, overridden by general.cfg
// default tables for personality weapon preferences, overridden by weapon.cfg
SmallArray <int32> m_normalWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 12, 10, 24, 25, 13, 11, 8, 7, 22, 23, 18, 21, 17, 19, 15, 17, 9, 14, 16 };
SmallArray <int32> m_rusherWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 24, 19, 22, 23, 20, 21, 10, 12, 13, 7, 8, 11, 9, 18, 17, 19, 25, 15, 16 };
SmallArray <int32> m_carefulWeaponPrefs = { 0, 2, 1, 4, 25, 6, 3, 7, 8, 12, 10, 13, 11, 9, 24, 18, 14, 17, 16, 15, 19, 20, 21, 22, 23, 5 };
@ -100,6 +116,9 @@ public:
// load bots avatars config
void loadAvatarsConfig ();
// load bots difficulty config
void loadDifficultyConfig ();
// sets memfile to use engine functions
void setupMemoryFiles ();
@ -119,12 +138,14 @@ public:
WeaponInfo &findWeaponById (int id);
// translates bot message into needed language
const char *translate (const char *input);
const char *translate (StringRef input);
private:
bool isCommentLine (const String &line) {
const char ch = line.at (0);
return ch == '#' || ch == '/' || ch == '\r' || ch == ';' || ch == 0 || ch == ' ';
bool isCommentLine (StringRef line) const {
if (line.empty ()) {
return true;
}
return line.substr (0, 1).findFirstOf ("#/; \n\r") != String::InvalidIndex;
};
public:
@ -140,7 +161,7 @@ public:
}
// pick random phrase from chat bank
const String &pickRandomFromChatBank (int chatType) {
StringRef pickRandomFromChatBank (int chatType) {
return m_chat[chatType].random ();
}
@ -189,6 +210,14 @@ public:
}
}
// get's the difficulty level tweaks
DifficultyData *getDifficultyTweaks (int32 level) {
if (level < Difficulty::Noob || level > Difficulty::Expert) {
return &m_difficulty[Difficulty::Expert];
}
return &m_difficulty[level];
}
// get economics value
int32 *getEconLimit () {
return m_botBuyEconomyTable.data ();
@ -200,7 +229,7 @@ public:
}
// get's random avatar for player (if any)
String getRandomAvatar () const {
StringRef getRandomAvatar () const {
if (!m_avatars.empty ()) {
return m_avatars.random ();
}
@ -208,12 +237,12 @@ public:
}
// get's random logo index
int getRandomLogoIndex () const {
return m_logos.index (m_logos.random ());
int32 getRandomLogoIndex () const {
return static_cast <int32> (m_logos.index (m_logos.random ()));
}
// get random name by index
const String &getRandomLogoName (int index) const {
StringRef getRandomLogoName (int index) {
return m_logos[index];
}
};

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -29,7 +36,7 @@ public:
public:
BotCmd () = default;
BotCmd (String name, String format, String help, Handler handler) : name (cr::move (name)), format (cr::move (format)), help (cr::move (help)), handler (cr::move (handler)) { }
BotCmd (StringRef name, StringRef format, StringRef help, Handler handler) : name (name), format (format), help (help), handler (cr::move (handler)) { }
};
// single bot menu
@ -39,7 +46,7 @@ public:
MenuHandler handler;
public:
BotMenu (int ident, int slots, String text, MenuHandler handler) : ident (ident), slots (slots), text (cr::move (text)), handler (cr::move (handler)) { }
BotMenu (int ident, int slots, StringRef text, MenuHandler handler) : ident (ident), slots (slots), text (text), handler (cr::move (handler)) { }
};
private:
@ -146,25 +153,16 @@ public:
m_ent = ent;
}
void fixMissingArgs (size_t num) {
if (num < m_args.length ()) {
return;
}
m_args.resize (num);
}
int getInt (size_t arg) const {
int intValue (size_t arg) const {
if (!hasArg (arg)) {
return 0;
}
return m_args[arg].int_ ();
}
const String &getStr (size_t arg) {
static String empty ("empty");
if (!hasArg (arg) || m_args[arg].empty ()) {
return empty;
StringRef strValue (size_t arg) {
if (!hasArg (arg)) {
return "";
}
return m_args[arg];
}
@ -182,7 +180,7 @@ public:
}
// global heloer for sending message to correct channel
template <typename ...Args> void msg (const char *fmt, Args ...args);
template <typename ...Args> void msg (const char *fmt, Args &&...args);
public:
@ -197,7 +195,7 @@ public:
};
// global heloer for sending message to correct channel
template <typename ...Args> inline void BotControl::msg (const char *fmt, Args ...args) {
template <typename ...Args> inline void BotControl::msg (const char *fmt, Args &&...args) {
auto result = strings.format (fmt, cr::forward <Args> (args)...);
// if no receiver or many message have to appear, just print to server console

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -29,7 +36,7 @@ CR_DECLARE_SCOPED_ENUM (Var,
ReadOnly,
Password,
NoServer,
NoRegister
GameRef
)
// supported cs's
@ -67,15 +74,16 @@ CR_DECLARE_SCOPED_ENUM (EntitySearchResult,
)
// variable reg pair
struct VarPair {
Var type;
struct ConVarReg {
cvar_t reg;
bool missing;
const char *regval;
class ConVar *self;
String info;
String init;
String regval;
class ConVar *self;
float initial, min, max;
bool missing;
bool bounded;
int32 type;
};
// entity prototype
@ -122,13 +130,14 @@ private:
edict_t *m_localEntity;
Array <edict_t *> m_breakables;
SmallArray <VarPair> m_cvars;
SmallArray <ConVarReg> m_cvars;
SharedLibrary m_gameLib;
EngineWrap m_engineWrap;
bool m_precached;
int m_gameFlags;
int m_mapFlags;
int m_gameFlags {};
int m_mapFlags {};
float m_slowFrame; // per second updated frame
@ -149,6 +158,9 @@ public:
// test line
void testLine (const Vector &start, const Vector &end, int ignoreFlags, edict_t *ignoreEntity, TraceResult *ptr);
// trace line with channel, but allows us to store last traceline bot has fired, saving us some cpu cycles
bool testLineChannel (TraceChannel channel, const Vector &start, const Vector &end, int ignoreFlags, edict_t *ignoreEntity, TraceResult *ptr);
// test line
void testHull (const Vector &start, const Vector &end, int ignoreFlags, int hullNumber, edict_t *ignoreEntity, TraceResult *ptr);
@ -177,7 +189,7 @@ public:
void prepareBotArgs (edict_t *ent, String str);
// adds cvar to registration stack
void addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, Var varType, bool missingAction, const char *regval, class ConVar *self);
void addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32 varType, bool missingAction, const char *regval, class ConVar *self);
// check the cvar bounds
void checkCvarsBounds ();
@ -201,10 +213,10 @@ public:
void slowFrame ();
// search entities by variable field
void searchEntities (const String &field, const String &value, EntitySearch functor);
void searchEntities (StringRef field, StringRef value, EntitySearch functor);
// search entities in sphere
void searchEntities (const Vector &position, const float radius, EntitySearch functor);
void searchEntities (const Vector &position, float radius, EntitySearch functor);
// this function is checking that pointed by ent pointer obstacle, can be destroyed
bool isShootableBreakable (edict_t *ent);
@ -228,7 +240,7 @@ public:
// gets custom engine args for client command
const char *botArgs () const {
return strings.format (String::join (m_botArgs, " ", m_botArgs[0] == "say" || m_botArgs[0] == "say_team" ? 1 : 0).chars ());
return strings.format (String::join (m_botArgs, " ", m_botArgs[0].startsWith ("say") ? 1 : 0).chars ());
}
// gets custom engine argv for client command
@ -240,8 +252,8 @@ public:
}
// gets custom engine argc for client command
int botArgc () const {
return m_botArgs.length ();
int32 botArgc () const {
return m_botArgs.length <int32> ();
}
// gets edict pointer out of entity index
@ -329,7 +341,7 @@ public:
}
// get registered cvars list
const SmallArray <VarPair> &getCvars () {
const SmallArray <ConVarReg> &getCvars () {
return m_cvars;
}
@ -347,22 +359,22 @@ public:
void sendClientMessage (bool console, edict_t *ent, const char *message);
// send server command
template <typename ...Args> void serverCommand (const char *fmt, Args ...args) {
template <typename ...Args> void serverCommand (const char *fmt, Args &&...args) {
engfuncs.pfnServerCommand (strings.concat (strings.format (fmt, cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
}
// send a bot command
template <typename ...Args> void botCommand (edict_t *ent, const char *fmt, Args ...args) {
template <typename ...Args> void botCommand (edict_t *ent, const char *fmt, Args &&...args) {
prepareBotArgs (ent, strings.format (fmt, cr::forward <Args> (args)...));
}
// prints data to servers console
template <typename ...Args> void print (const char *fmt, Args ...args) {
template <typename ...Args> void print (const char *fmt, Args &&...args) {
engfuncs.pfnServerPrint (strings.concat (strings.format (conf.translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
}
// prints center message to specified player
template <typename ...Args> void clientPrint (edict_t *ent, const char *fmt, Args ...args) {
template <typename ...Args> void clientPrint (edict_t *ent, const char *fmt, Args &&...args) {
if (isNullEntity (ent)) {
print (fmt, cr::forward <Args> (args)...);
return;
@ -371,7 +383,7 @@ public:
}
// prints message to client console
template <typename ...Args> void centerPrint (edict_t *ent, const char *fmt, Args ...args) {
template <typename ...Args> void centerPrint (edict_t *ent, const char *fmt, Args &&...args) {
if (isNullEntity (ent)) {
print (fmt, cr::forward <Args> (args)...);
return;
@ -390,12 +402,12 @@ public:
~ConVar () = default;
public:
ConVar (const char *name, const char *initval, Var type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
Game::get ().addNewCvar (name, initval, "", false, 0.0f, 0.0f, type, regMissing, regVal, this);
ConVar (const char *name, const char *initval, int32 type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
Game::instance ().addNewCvar (name, initval, "", false, 0.0f, 0.0f, type, regMissing, regVal, this);
}
ConVar (const char *name, const char *initval, const char *info, bool bounded = true, float min = 0.0f, float max = 1.0f, Var type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
Game::get ().addNewCvar (name, initval, info, bounded, min, max, type, regMissing, regVal, this);
ConVar (const char *name, const char *initval, const char *info, bool bounded = true, float min = 0.0f, float max = 1.0f, int32 type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
Game::instance ().addNewCvar (name, initval, info, bounded, min, max, type, regMissing, regVal, this);
}
bool bool_ () const {
@ -497,8 +509,8 @@ public:
class LightMeasure final : public Singleton <LightMeasure> {
private:
lightstyle_t m_lightstyle[MAX_LIGHTSTYLES];
int m_lightstyleValue[MAX_LIGHTSTYLEVALUE];
lightstyle_t m_lightstyle[MAX_LIGHTSTYLES] {};
int m_lightstyleValue[MAX_LIGHTSTYLEVALUE] {};
bool m_doAnimation = false;
Color m_point;
@ -587,7 +599,7 @@ public:
if (m_buffer.length () < m_cursor) {
return;
}
for (; m_cursor < m_buffer.length () && m_buffer[m_cursor] != '\0'; ++m_cursor) { }
for (; m_cursor < m_buffer.length () && m_buffer[m_cursor] != kNullChar; ++m_cursor) { }
++m_cursor;
}
@ -603,27 +615,23 @@ public:
// for android
#if defined (CR_ANDROID) && defined(CR_ARCH_ARM)
extern "C" void player (entvars_t *pev);
extern "C" void player (entvars_t *);
#endif
class DynamicEntityLink : public Singleton <DynamicEntityLink> {
class EntityLinkage : public Singleton <EntityLinkage> {
private:
#if defined (CR_WINDOWS)
# define MODULE_HANDLE HMODULE
# define MODULE_SYMBOL GetProcAddress
# define HOOK_FUNCTION GetProcAddress
# define HOOK_CAST HMODULE
#else
# define MODULE_HANDLE void *
# define MODULE_SYMBOL dlsym
# define HOOK_FUNCTION dlsym
# define HOOK_CAST SharedLibrary::Handle
#endif
private:
using Handle = void *;
using Name = const char *;
private:
template <typename K> struct FunctionHash {
uint32 operator () (Name key) const {
char *str = const_cast <char *> (key);
template <typename K> struct CharHash {
uint32 operator () (const char *key) const {
auto str = const_cast <char *> (key);
uint32 hash = 0;
while (*str++) {
@ -636,41 +644,34 @@ private:
private:
SharedLibrary m_self;
SimpleHook m_dlsym;
Dictionary <Name, Handle, FunctionHash <Name>> m_exports;
Dictionary <const char *, SharedLibrary::Handle, CharHash <const char *>> m_exports;
public:
DynamicEntityLink () = default;
EntityLinkage () = default;
~DynamicEntityLink () {
~EntityLinkage () {
m_dlsym.disable ();
}
public:
Handle search (Handle module, Name function);
void initialize ();
SharedLibrary::Handle lookup (SharedLibrary::Handle module, const char *function);
public:
void initialize () {
if (plat.arm) {
return;
}
m_dlsym.patch (reinterpret_cast <void *> (&MODULE_SYMBOL), reinterpret_cast <void *> (&DynamicEntityLink::replacement));
m_self.locate (&engfuncs);
}
EntityFunction getPlayerFunction () {
#if defined (CR_ANDROID) && defined(CR_ARCH_ARM)
return player;
void callPlayerFunction (edict_t *ent) {
#if defined (CR_ANDROID) && defined (CR_ARCH_ARM)
player (&ent->v);
#else
return reinterpret_cast <EntityFunction> (search (Game::get ().lib ().handle (), "player"));
reinterpret_cast <EntityFunction> (lookup (Game::instance ().lib ().handle (), "player")) (&ent->v);
#endif
}
public:
static Handle CR_STDCALL replacement (Handle module, Name function) {
return DynamicEntityLink::get ().search (module, function);
static SharedLibrary::Handle CR_STDCALL replacement (SharedLibrary::Handle module, const char *function) {
return EntityLinkage::instance ().lookup (module, function);
}
};
// expose globals
CR_EXPOSE_GLOBAL_SINGLETON (Game, game);
CR_EXPOSE_GLOBAL_SINGLETON (LightMeasure, illum);
CR_EXPOSE_GLOBAL_SINGLETON (DynamicEntityLink, ents);
CR_EXPOSE_GLOBAL_SINGLETON (EntityLinkage, ents);

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -319,8 +326,9 @@ public:
bool saveGraphData ();
bool loadGraphData ();
template <typename U> bool saveStorage (const String &ext, const String &name, StorageOption options, StorageVersion version, const SmallArray <U> &data, ExtenHeader *exten);
template <typename U> bool loadStorage (const String &ext, const String &name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32 *outOptions);
template <typename U> bool saveStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, const SmallArray <U> &data, ExtenHeader *exten);
template <typename U> bool loadStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32 *outOptions);
template <typename ...Args> bool raiseLoadingError (bool isGraph, MemFile &file, const char *fmt, Args &&...args);
void saveOldFormat ();
void initGraph ();
@ -416,8 +424,8 @@ public:
}
// get real nodes num
int length () const {
return m_paths.length ();
int32 length () const {
return m_paths.length <int32> ();
}
// check if has editor
@ -436,5 +444,25 @@ public:
}
};
// we're need `bots`
#include <manager.h>
// helper for reporting load errors
template <typename ...Args> bool BotGraph::raiseLoadingError (bool isGraph, MemFile &file, const char *fmt, Args &&...args) {
auto result = strings.format (fmt, cr::forward <Args> (args)...);
logger.error (result);
// if graph reset paths
if (isGraph) {
bots.kickEveryone (true);
m_tempStrings = result;
m_paths.clear ();
}
file.close ();
return false;
}
// explose global
CR_EXPOSE_GLOBAL_SINGLETON (BotGraph, graph);

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -18,6 +25,36 @@ struct BotRequest {
String name;
};
// initial frustum data
struct FrustumData : public Singleton <FrustumData> {
private:
float Fov = 75.0f;
float AspectRatio = 1.33333f;
public:
float MaxView = 4096.0f;
float MinView = 5.0f;
public:
float farHeight; // height of the far frustum
float farWidth; // width of the far frustum
float nearHeight; // height of the near frustum
float nearWidth; // width of the near frustum
public:
FrustumData () {
nearHeight = 2.0f * cr::tanf (Fov * 0.0174532925f * 0.5f) * MinView;
nearWidth = nearHeight * AspectRatio;
farHeight = 2.0f * cr::tanf (Fov * 0.0174532925f * 0.5f) * MaxView;
farWidth = farHeight * AspectRatio;
}
};
// declare global frustum data
CR_EXPOSE_GLOBAL_SINGLETON (FrustumData, frustum);
// manager class
class BotManager final : public Singleton <BotManager> {
public:
@ -58,9 +95,10 @@ private:
SmallArray <UniqueBot> m_bots; // all available bots
edict_t *m_killerEntity; // killer entity for bots
FrustumData m_frustumData {};
protected:
BotCreateResult create (const String &name, int difficulty, int personality, int team, int member);
BotCreateResult create (StringRef name, int difficulty, int personality, int team, int member);
public:
BotManager ();
@ -77,8 +115,8 @@ public:
int getHumansCount (bool ignoreSpectators = false);
int getAliveHumansCount ();
int getBotCount ();
float getConnectionTime (int botId);
float getConnectTime (int botId, float original);
void setBombPlanted (bool isPlanted);
void frame ();
@ -86,8 +124,8 @@ public:
void destroyKillerEntity ();
void touchKillerEntity (Bot *bot);
void destroy ();
void addbot (const String &name, int difficulty, int personality, int team, int member, bool manual);
void addbot (const String &name, const String &difficulty, const String &personality, const String &team, const String &member, bool manual);
void addbot (StringRef name, int difficulty, int personality, int team, int member, bool manual);
void addbot (StringRef name, StringRef difficulty, StringRef personality, StringRef team, StringRef member, bool manual);
void serverFill (int selection, int personality = Personality::Normal, int difficulty = -1, int numToAdd = -1);
void kickEveryone (bool instant = false, bool zeroQuota = true);
void kickBot (int index);
@ -95,6 +133,7 @@ public:
void killAllBots (int team = -1);
void maintainQuota ();
void maintainAutoKill ();
void maintainLeaders ();
void initQuota ();
void initRound ();
void decrementQuota (int by = 1);
@ -110,7 +149,7 @@ public:
void updateIntrestingEntities ();
void captureChatRadio (const char *cmd, const char *arg, edict_t *ent);
void notifyBombDefuse ();
void execGameEntity (entvars_t *vars);
void execGameEntity (edict_t *ent);
void forEach (ForEachBot handler);
void erase (Bot *bot);
void handleDeath (edict_t *killer, edict_t *victim);
@ -120,11 +159,11 @@ public:
bool kickRandom (bool decQuota = true, Team fromTeam = Team::Unassigned);
public:
const Array <edict_t *> &searchActiveGrenades () {
const Array <edict_t *> &getActiveGrenades () {
return m_activeGrenades;
}
const Array <edict_t *> &searchIntrestingEntities () {
const Array <edict_t *> &getIntrestingEntities () {
return m_intrestingEntities;
}
@ -140,10 +179,14 @@ public:
return m_economicsGood[team];
}
int getLastWinner () const {
int32 getLastWinner () const {
return m_lastWinner;
}
int32 getBotCount () {
return m_bots.length <int32> ();
}
// get the list of filters
SmallArray <BotTask> &getFilters () {
return m_filters;
@ -263,4 +306,4 @@ public:
};
// explose global
CR_EXPOSE_GLOBAL_SINGLETON (BotManager, bots);
CR_EXPOSE_GLOBAL_SINGLETON (BotManager, bots);

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -86,8 +93,8 @@ private:
Dictionary <String, int32> m_teamInfoCache; // cache for teaminfo message
private:
Bot *m_bot; // owner of a message
NetMsg m_current; // ongoing message id
Bot *m_bot {}; // owner of a message
NetMsg m_current {}; // ongoing message id
SmallArray <Args> m_args; // args collected from write* functions
Dictionary <String, NetMsg> m_wanted; // wanted messages
@ -120,7 +127,7 @@ public:
~MessageDispatcher () = default;
public:
int32 add (const String &name, int32 id);
int32 add (StringRef name, int32 id);
int32 id (NetMsg msg);
void start (edict_t *ent, int32 type);

53
inc/product.h Normal file
View file

@ -0,0 +1,53 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#ifdef VERSION_GENERATED
# define VERSION_HEADER <version.build.h>
#else
# define VERSION_HEADER <version.h>
#endif
#include VERSION_HEADER
// simple class for bot internal information
class Product final : public Singleton <Product> {
public:
const struct Build {
const StringRef hash { MODULE_BUILD_HASH };
const StringRef author { MODULE_BUILD_AUTHOR };
const StringRef count { MODULE_BUILD_COUNT };
const StringRef machine { MODULE_BUILD_MACHINE };
const StringRef compiler { MODULE_BUILD_COMPILER };
const StringRef id { MODULE_BOT_BUILD_ID };
} build { };
public:
const StringRef name { "YaPB" };
const StringRef year { __DATE__ + 8 };
const StringRef author { "YaPB Development Team" };
const StringRef email { "team@yapb.ru" };
const StringRef url { "https://yapb.ru/" };
const StringRef download { "http://data.yapb.ru/" };
const StringRef folder { "yapb" };
const StringRef logtag { "YB" };
const StringRef dtime { __DATE__ " " __TIME__ };
const StringRef date { __DATE__ };
const StringRef version { MODULE_BOT_VERSION };
};
// expose product info
CR_EXPOSE_GLOBAL_SINGLETON (Product, product);

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
@ -20,7 +27,7 @@ CR_DECLARE_SCOPED_ENUM (Noise,
Door = cr::bit (7)
)
class BotUtils final : public Singleton <BotUtils> {
class BotSupport final : public Singleton <BotSupport> {
private:
bool m_needToSendWelcome;
float m_welcomeReceiveTime;
@ -34,18 +41,15 @@ private:
SimpleHook m_sendToHook;
public:
BotUtils ();
~BotUtils () = default;
BotSupport ();
~BotSupport () = default;
public:
// need to send welcome message ?
void checkWelcome ();
// converts weapon id to alias name
const String &weaponIdToAlias (const int32 id);
// gets the build number of bot
int buildNumber ();
StringRef weaponIdToAlias (int32 id);
// check if origin is visible from the entity side
bool isVisible (const Vector &origin, edict_t *ent);
@ -72,7 +76,7 @@ public:
void traceDecals (entvars_t *pev, TraceResult *trace, int logotypeIndex);
// attaches sound to client struct
void listenNoise (edict_t *ent, const String &sample, float volume);
void listenNoise (edict_t *ent, StringRef sample, float volume);
// simulate sound for players
void simulateNoise (int playerIndex);
@ -90,7 +94,7 @@ public:
void addChatErrors (String &line);
// chat helper to find keywords for given string
bool checkKeywords (const String &line, String &reply);
bool checkKeywords (StringRef line, String &reply);
// generates ping bitmask for SVC_PINGS message
int getPingBitmask (edict_t *ent, int loss, int ping);
@ -104,6 +108,8 @@ public:
// installs the sendto function intreception
void installSendTo ();
// check if object inside frustum plane
bool isObjectInsidePlane (FrustumPlane &plane, const Vector &center, float height, float radius);
public:
// re-show welcome after changelevel ?
@ -143,7 +149,7 @@ public:
// check if origin is inside view cone of entity
bool isInViewCone (const Vector &origin, edict_t *ent) {
return getShootingCone (ent, origin) >= cr::cosf (cr::degreesToRadians ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f));
return getShootingCone (ent, origin) >= cr::cosf (cr::deg2rad ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f));
}
public:
@ -151,4 +157,4 @@ public:
};
// explose global
CR_EXPOSE_GLOBAL_SINGLETON (BotUtils, util);
CR_EXPOSE_GLOBAL_SINGLETON (BotSupport, util);

27
inc/version.h Normal file
View file

@ -0,0 +1,27 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
// fallback if no git or custom build
#define MODULE_BUILD_HASH "0"
#define MODULE_BUILD_AUTHOR "team@yapb.ru"
#define MODULE_BUILD_COUNT "0"
#define MODULE_BUILD_MACHINE "localhost"
#define MODULE_BUILD_COMPILER "unknown"
#define MODULE_BOT_VERSION "4.0.0"
#define MODULE_BOT_VERSION_FILE 4,0,0,000
#define MODULE_BOT_BUILD_ID "0:0"

28
inc/version.h.in Normal file
View file

@ -0,0 +1,28 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
// generated by meson build system
#ifndef MODULE_BUILD_HASH
# define MODULE_BUILD_HASH "@commitHash@"
# define MODULE_BUILD_AUTHOR @commitAuthor@
# define MODULE_BUILD_COUNT "@commitCount@"
# define MODULE_BUILD_MACHINE "@buildMachine@"
# define MODULE_BUILD_COMPILER "@buildCompiler@"
# define MODULE_BOT_VERSION "@buildVersion@"
# define MODULE_BOT_VERSION_FILE @buildVersionWin@,@commitCount@
# define MODULE_BOT_BUILD_ID "@commitCount@:@commitHash@"
#endif

View file

@ -1,22 +1,29 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#pragma once
#include <engine/extdll.h>
#include <engine/metamod.h>
#include <hlsdk/extdll.h>
#include <hlsdk/metamod.h>
#include <crlib/cr-complete.h>
// use all the cr-library
using namespace cr;
#include <resource.h>
#include <product.h>
// forwards
class Bot;
@ -101,11 +108,11 @@ CR_DECLARE_SCOPED_ENUM (Personality,
// bot difficulties
CR_DECLARE_SCOPED_ENUM (Difficulty,
VeryEasy,
Noob,
Easy,
Normal,
Hard,
Extreme,
Expert,
Invalid = -1
)
@ -274,9 +281,9 @@ CR_DECLARE_SCOPED_ENUM (BuyState,
PrimaryWeapon = 0,
ArmorVestHelm,
SecondaryWeapon,
Grenades,
DefusalKit,
Ammo,
DefusalKit,
Grenades,
NightVision,
Done
)
@ -367,7 +374,8 @@ CR_DECLARE_SCOPED_ENUM (AimFlags,
Entity = cr::bit (4), // aim at entity like buttons, hostages
Enemy = cr::bit (5), // aim at enemy
Grenade = cr::bit (6), // aim for grenade throw
Override = cr::bit (7) // overrides all others (blinded)
Override = cr::bit (7), // overrides all others (blinded)
Danger = cr::bit (8) // additional danger falg
)
// famas/glock burst mode status + m4a1/usp silencer
@ -384,6 +392,24 @@ CR_DECLARE_SCOPED_ENUM (Visibility,
None = 0
)
// channel for skip traceline
CR_DECLARE_SCOPED_ENUM (TraceChannel,
Enemy = 0,
Body,
Num
)
// frustum sides
CR_DECLARE_SCOPED_ENUM (FrustumSide,
Top = 0,
Bottom,
Left,
Right,
Near,
Far,
Num
)
// some hardcoded desire defines used to override calculated ones
namespace TaskPri {
static constexpr float Normal { 35.0f };
@ -407,8 +433,8 @@ namespace TaskPri {
// storage file magic
constexpr char kPodbotMagic[8] = "PODWAY!";
constexpr int32 kStorageMagic = 0x59415042;
constexpr int32 kStorageMagicUB = 0x544f4255; // storage magic for ubot-data files
constexpr int32 kStorageMagic = 0x59415042; // storage magic for yapb-data files
constexpr int32 kStorageMagicUB = 0x544f4255; //support also the fork format (merged back into yapb)
constexpr float kInfiniteDistance = 9999999.0f;
constexpr float kGrenadeCheckTime = 2.15f;
@ -437,9 +463,6 @@ constexpr int kMaxNodesInsideBucket = kMaxBucketSize / kMaxBucketsInsidePos;
constexpr auto kPrimaryWeaponMask = (cr::bit (Weapon::XM1014) | cr::bit (Weapon::M3) | cr::bit (Weapon::MAC10) | cr::bit (Weapon::UMP45) | cr::bit (Weapon::MP5) | cr::bit (Weapon::TMP) | cr::bit (Weapon::P90) | cr::bit (Weapon::AUG) | cr::bit (Weapon::M4A1) | cr::bit (Weapon::SG552) | cr::bit (Weapon::AK47) | cr::bit (Weapon::Scout) | cr::bit (Weapon::SG550) | cr::bit (Weapon::AWP) | cr::bit (Weapon::G3SG1) | cr::bit (Weapon::M249) | cr::bit (Weapon::Famas) | cr::bit (Weapon::Galil));
constexpr auto kSecondaryWeaponMask = (cr::bit (Weapon::P228) | cr::bit (Weapon::Elite) | cr::bit (Weapon::USP) | cr::bit (Weapon::Glock18) | cr::bit (Weapon::Deagle) | cr::bit (Weapon::FiveSeven));
// include bot graph stuff
#include <graph.h>
// links keywords and replies together
struct Keywords {
StringArray keywords;
@ -530,6 +553,13 @@ struct ClientNoise {
float last;
};
// defines frustum data for bot
struct FrustumPlane {
Vector normal;
Vector point;
float result;
};
// array of clients struct
struct Client {
edict_t *ent; // pointer to actual edict
@ -556,6 +586,9 @@ struct ChatCollection {
StringArray lastUsedSentences;
};
// include bot graph stuff
#include <graph.h>
// main bot class
class Bot final {
private:
@ -572,11 +605,12 @@ private:
uint32 m_aimFlags; // aiming conditions
uint32 m_currentTravelFlags; // connection flags like jumping
int m_traceSkip[TraceChannel::Num]; // trace need to be skipped?
int m_messageQueue[32]; // stack for messages
int m_oldButtons; // our old buttons
int m_reloadState; // current reload state
int m_voicePitch; // bot voice pitch
int m_rechoiceGoalCount; // multiple failed goals?
int m_loosedBombNodeIndex; // nearest to loosed bomb node
int m_plantedBombNodeIndex; // nearest to planted bomb node
int m_currentNodeIndex; // current node index
@ -589,7 +623,7 @@ private:
int m_tryOpenDoor; // attempt's to open the door
int m_liftState; // state of lift handling
int m_radioSelect; // radio entry
float m_headedTime;
float m_prevTime; // time previously checked movement speed
float m_heavyTimestamp; // is it time to execute heavy-weight functions
@ -618,7 +652,6 @@ private:
float m_firstCollideTime; // time of first collision
float m_probeTime; // time of probing different moves
float m_lastCollTime; // time until next collision check
float m_jumpStateTimer; // timer for jumping collision check
float m_lookYawVel; // look yaw velocity
float m_lookPitchVel; // look pitch velocity
float m_lookUpdateTime; // lookangles update time
@ -668,6 +701,7 @@ private:
CollisionState m_collisionState; // collision State
FindPath m_pathType; // which pathfinder to use
uint8 m_enemyParts; // visibility flags
TraceResult m_lastTrace[TraceChannel::Num]; // last trace result
edict_t *m_pickupItem; // pointer to entity of item to use/pickup
edict_t *m_itemIgnore; // pointer to entity to ignore for pickup
@ -699,6 +733,7 @@ private:
BinaryHeap <RouteTwin> m_routeQue;
Path *m_path; // pointer to the current path node
String m_chatBuffer; // space for strings (say text...)
FrustumPlane m_frustum[FrustumSide::Num] {};
private:
int pickBestWeapon (int *vec, int count, int moneySave);
@ -747,8 +782,8 @@ private:
bool hasActiveGoal ();
bool advanceMovement ();
bool isBombDefusing (const Vector &bombOrigin);
bool isOccupiedNode (int index);
bool seesItem (const Vector &dest, const char *itemName);
bool isOccupiedNode (int index, bool needZeroVelocity = false);
bool seesItem (const Vector &dest, const char *classname);
bool lastEnemyShootable ();
bool rateGroundWeapon (edict_t *ent);
bool reactOnEnemy ();
@ -765,6 +800,7 @@ private:
bool isPenetrableObstacle (const Vector &dest);
bool isPenetrableObstacle2 (const Vector &dest);
bool isEnemyBehindShield (edict_t *enemy);
bool isEnemyInFrustum (edict_t *enemy);
bool checkChatKeywords (String &reply);
bool isReplyingToChat ();
bool isReachableNode (int index);
@ -792,7 +828,7 @@ private:
void updateLookAnglesNewbie (const Vector &direction, float delta);
void setIdealReactionTimers (bool actual = false);
void updateHearing ();
void postprocessGoals (const IntArray &goals, int *result);
void postprocessGoals (const IntArray &goals, int result[]);
void updatePickups ();
void checkTerrain (float movedDistance, const Vector &dirNormal);
void checkDarkness ();
@ -801,6 +837,8 @@ private:
void updatePracticeValue (int damage);
void updatePracticeDamage (edict_t *attacker, int damage);
void findShortestPath (int srcIndex, int destIndex);
void calculateFrustum ();
void findPath (int srcIndex, int destIndex, FindPath pathType = FindPath::Fast);
void clearRoute ();
void debugMsgInternal (const char *str);
@ -823,6 +861,7 @@ private:
void selectSecondary ();
void selectWeaponByName (const char *name);
void selectWeaponById (int num);
void completeTask ();
void executeTasks ();
void trackEnemies ();
@ -992,7 +1031,7 @@ public:
void newRound ();
void enteredBuyZone (int buyState);
void pushMsgQueue (int message);
void prepareChatMessage (const String &message);
void prepareChatMessage (StringRef message);
void checkForChat ();
void showChaterIcon (bool show);
void clearSearchNodes ();
@ -1003,8 +1042,7 @@ public:
void filterTasks ();
void clearTasks ();
void dropWeaponForUser (edict_t *user, bool discardC4);
void say (const char *text);
void sayTeam (const char *text);
void sendToChat (StringRef message, bool teamOnly);
void pushChatMessage (int type, bool isTeamSay = false);
void pushRadioMessage (int message);
void pushChatterMessage (int message);
@ -1028,6 +1066,7 @@ public:
bool isShieldDrawn ();
bool findBestNearestNode ();
bool seesEntity (const Vector &dest, bool fromBody = false);
bool canSkipNextTrace (TraceChannel channel);
int getAmmo ();
int getNearestToPlantedBomb ();
@ -1066,32 +1105,44 @@ public:
return m_index + 1;
}
// set the last bot trace result
void setLastTraceResult (TraceChannel channel, TraceResult *traceResult) {
m_lastTrace[channel] = *traceResult;
}
// get the bot last trace result
TraceResult *getLastTraceResult (TraceChannel channel) {
return &m_lastTrace[channel];
}
// prints debug message
template <typename ...Args> void debugMsg (const char *fmt, Args ...args) {
template <typename ...Args> void debugMsg (const char *fmt, Args &&...args) {
debugMsgInternal (strings.format (fmt, cr::forward <Args> (args)...));
}
// execute client command helper
template <typename ...Args> void issueCommand (const char *fmt, Args ...args);
template <typename ...Args> void issueCommand (const char *fmt, Args &&...args);
};
#include <config.h>
#include <utils.h>
#include <support.h>
#include <message.h>
#include <engine.h>
#include <manager.h>
#include <control.h>
// very global convars
extern ConVar yb_jasonmode;
extern ConVar yb_radio_mode;
extern ConVar yb_ignore_enemies;
extern ConVar yb_chat;
extern ConVar yb_language;
extern ConVar yb_show_latency;
extern ConVar yb_enable_query_hook;
extern ConVar cv_jasonmode;
extern ConVar cv_radio_mode;
extern ConVar cv_ignore_enemies;
extern ConVar cv_chat;
extern ConVar cv_language;
extern ConVar cv_show_latency;
extern ConVar cv_enable_query_hook;
extern ConVar cv_whose_your_daddy;
extern ConVar cv_chatter_path;
// execute client command helper
template <typename ...Args> void Bot::issueCommand (const char * fmt, Args ...args) {
template <typename ...Args> void Bot::issueCommand (const char *fmt, Args &&...args) {
game.botCommand (ent (), strings.format (fmt, cr::forward <Args> (args)...));
}

View file

@ -1,73 +0,0 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
//
#pragma once
#include <new>
#include <crlib/cr-basic.h>
#include <crlib/cr-movable.h>
#include <crlib/cr-platform.h>
CR_NAMESPACE_BEGIN
// default allocator for cr-objects
class Allocator : public Singleton <Allocator> {
public:
Allocator () = default;
~Allocator () = default;
public:
template <typename T> T *allocate (const size_t length = 1) {
auto ptr = reinterpret_cast <T *> (calloc (length, sizeof (T)));
if (!ptr) {
plat.abort ();
}
// calloc on linux with debug enabled doesn't always zero out memory
#if defined (CR_DEBUG) && !defined (CR_WINDOWS)
plat.bzero (ptr, length);
#endif
return ptr;
}
template <typename T> void deallocate (T *ptr) {
if (ptr) {
free (reinterpret_cast <T *> (ptr));
}
}
public:
template <typename T, typename ...Args> void construct (T *d, Args &&...args) {
new (d) T (cr::forward <Args> (args)...);
}
template <typename T> void destruct (T *d) {
d->~T ();
}
public:
template <typename T, typename ...Args> T *create (Args &&...args) {
auto d = allocate <T> ();
new (d) T (cr::forward <Args> (args)...);
return d;
}
template <typename T> void destroy (T *ptr) {
if (ptr) {
destruct (ptr);
deallocate (ptr);
}
}
};
CR_EXPOSE_GLOBAL_SINGLETON (Allocator, alloc);
CR_NAMESPACE_END

View file

@ -1,40 +0,0 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
//
#pragma once
#include <crlib/cr-basic.h>
CR_NAMESPACE_BEGIN
// simple color holder
class Color final {
public:
int32 red = 0, green = 0, blue = 0;
public:
explicit Color (int32 r, int32 g, int32 b) : red (r), green (g), blue (b) { }
Color () = default;
~Color () = default;
public:
void reset () {
red = green = blue = 0;
}
int32 avg () const {
return sum () / (sizeof (Color) / sizeof (int32));
}
int32 sum () const {
return red + green + blue;
}
};
CR_NAMESPACE_END

View file

@ -1,349 +0,0 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
//
#pragma once
#include <stdio.h>
#include <crlib/cr-string.h>
#include <crlib/cr-lambda.h>
CR_NAMESPACE_BEGIN
// simple stdio file wrapper
class File final : private DenyCopying {
private:
FILE *m_handle = nullptr;
size_t m_length = 0;
public:
explicit File () = default;
File (const String &file, const String &mode = "rt") {
open (file, mode);
}
~File () {
close ();
}
public:
bool open (const String &file, const String &mode) {
if (!openFile (file, mode)) {
return false;
}
fseek (m_handle, 0L, SEEK_END);
m_length = ftell (m_handle);
fseek (m_handle, 0L, SEEK_SET);
return true;
}
void close () {
if (m_handle != nullptr) {
fclose (m_handle);
m_handle = nullptr;
}
m_length = 0;
}
bool eof () const {
return !!feof (m_handle);
}
bool flush () const {
return !!fflush (m_handle);
}
int getChar () const {
return fgetc (m_handle);
}
char *getString (char *buffer, int count) const {
return fgets (buffer, count, m_handle);
}
bool getLine (String &line) {
line.clear ();
int ch;
while ((ch = getChar ()) != EOF && !eof ()) {
line += static_cast <char> (ch);
if (ch == '\n') {
break;
}
}
return !eof ();
}
template <typename ...Args> size_t puts (const char *fmt, Args ...args) {
if (!*this) {
return 0;
}
return fprintf (m_handle, fmt, cr::forward <Args> (args)...);
}
bool puts (const char *buffer) {
if (!*this) {
return 0;
}
if (fputs (buffer, m_handle) < 0) {
return false;
}
return true;
}
int putChar (int ch) {
return fputc (ch, m_handle);
}
size_t read (void *buffer, size_t size, size_t count = 1) {
return fread (buffer, size, count, m_handle);
}
size_t write (void *buffer, size_t size, size_t count = 1) {
return fwrite (buffer, size, count, m_handle);
}
bool seek (long offset, int origin) {
if (fseek (m_handle, offset, origin) != 0) {
return false;
}
return true;
}
void rewind () {
::rewind (m_handle);
}
size_t length () const {
return m_length;
}
public:
explicit operator bool () const {
return m_handle != nullptr;
}
public:
static inline bool exists (const String &file) {
File fp;
if (fp.open (file, "rb")) {
fp.close ();
return true;
}
return false;
}
static inline void createPath (const char *path) {
for (auto str = const_cast <char *> (path) + 1; *str; ++str) {
if (*str == '/') {
*str = 0;
plat.createDirectory (path);
*str = '/';
}
}
plat.createDirectory (path);
}
private:
bool openFile (const String &filename, const String &mode) {
if (*this) {
close ();
}
#if defined (CR_WINDOWS)
fopen_s (&m_handle, filename.chars (), mode.chars ());
#else
m_handle = fopen (filename.chars (), mode.chars ());
#endif
return m_handle != nullptr;
}
};
// wrapper for memory file for loading data into the memory
class MemFileStorage : public Singleton <MemFileStorage> {
private:
using LoadFunction = Lambda <uint8 * (const char *, int *)>;
using FreeFunction = Lambda <void (void *)>;
private:
LoadFunction m_load = nullptr;
FreeFunction m_free = nullptr;
public:
inline MemFileStorage () = default;
inline ~MemFileStorage () = default;
public:
void initizalize (LoadFunction loader, FreeFunction unloader) {
m_load = cr::move (loader);
m_free = cr::move (unloader);
}
public:
uint8 *load (const String &file, int *size) {
if (m_load) {
return m_load (file.chars (), size);
}
return nullptr;
}
void unload (void *buffer) {
if (m_free) {
m_free (buffer);
}
}
};
class MemFile final : public DenyCopying {
private:
enum : char {
Eof = static_cast <char> (-1)
};
private:
uint8 *m_data = nullptr;
size_t m_length = 0, m_pos = 0;
public:
explicit MemFile () = default;
MemFile (const String &file) {
open (file);
}
~MemFile () {
close ();
}
public:
bool open (const String &file) {
m_length = 0;
m_pos = 0;
m_data = MemFileStorage::get ().load (file.chars (), reinterpret_cast <int *> (&m_length));
if (!m_data) {
return false;
}
return true;
}
void close () {
MemFileStorage::get ().unload (m_data);
m_length = 0;
m_pos = 0;
m_data = nullptr;
}
char getChar () {
if (!m_data || m_pos >= m_length) {
return Eof;
}
auto ch = m_data[m_pos];
++m_pos;
return static_cast <char> (ch);
}
char *getString (char *buffer, size_t count) {
if (!m_data || m_pos >= m_length) {
return nullptr;
}
size_t index = 0;
buffer[0] = 0;
for (; index < count - 1;) {
if (m_pos < m_length) {
buffer[index] = m_data[m_pos++];
if (buffer[index++] == '\n') {
break;
}
}
else {
break;
}
}
buffer[index] = 0;
return index ? buffer : nullptr;
}
bool getLine (String &line) {
line.clear ();
char ch;
while ((ch = getChar ()) != Eof) {
line += ch;
if (ch == '\n') {
break;
}
}
return !eof ();
}
size_t read (void *buffer, size_t size, size_t count = 1) {
if (!m_data || m_length <= m_pos || !buffer || !size || !count) {
return 0;
}
size_t blocks_read = size * count <= m_length - m_pos ? size * count : m_length - m_pos;
memcpy (buffer, &m_data[m_pos], blocks_read);
m_pos += blocks_read;
return blocks_read / size;
}
bool seek (size_t offset, int origin) {
if (!m_data || m_pos >= m_length) {
return false;
}
if (origin == SEEK_SET) {
if (offset >= m_length) {
return false;
}
m_pos = offset;
}
else if (origin == SEEK_END) {
if (offset >= m_length) {
return false;
}
m_pos = m_length - offset;
}
else {
if (m_pos + offset >= m_length) {
return false;
}
m_pos += offset;
}
return true;
}
size_t length () const {
return m_length;
}
bool eof () const {
return m_pos >= m_length;
}
void rewind () {
m_pos = 0;
}
public:
explicit operator bool () const {
return !!m_data && m_length > 0;
}
};
CR_NAMESPACE_END

View file

@ -1,157 +0,0 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
//
#pragma once
#include <crlib/cr-basic.h>
#if !defined (CR_WINDOWS)
# include <sys/mman.h>
#endif
CR_NAMESPACE_BEGIN
class SimpleHook : DenyCopying {
private:
enum : uint32 {
#if defined (CR_ARCH_X64)
CodeLength = 14
#else
CodeLength = 6
#endif
};
#if defined (CR_ARCH_X64)
using uint = uint64;
#else
using uint = uint32;
#endif
private:
bool m_patched;
uint m_pageSize;
uint m_origFunc;
uint m_hookFunc;
uint8 m_origBytes[CodeLength] {};
uint8 m_hookBytes[CodeLength] {};
private:
void setPageSize () {
#if defined (CR_WINDOWS)
SYSTEM_INFO sysinfo;
GetSystemInfo (&sysinfo);
m_pageSize = sysinfo.dwPageSize;
#else
m_pageSize = sysconf (_SC_PAGESIZE);
#endif
}
#if !defined (CR_WINDOWS)
void *align (void *address) {
return reinterpret_cast <void *> ((reinterpret_cast <long> (address) & ~(m_pageSize - 1)));
}
#endif
bool unprotect () {
auto orig = reinterpret_cast <void *> (m_origFunc);
#if defined (CR_WINDOWS)
DWORD oldProt;
FlushInstructionCache (GetCurrentProcess (), orig, CodeLength);
return VirtualProtect (orig, CodeLength, PAGE_EXECUTE_READWRITE, &oldProt);
#else
auto aligned = align (orig);
return !mprotect (aligned, m_pageSize, PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
}
public:
SimpleHook () : m_patched (false), m_pageSize (0), m_origFunc (0), m_hookFunc (0) {
setPageSize ();
}
~SimpleHook () {
disable ();
}
public:
bool patch (void *address, void *replacement) {
const uint16 jmp = 0x25ff;
if (plat.arm) {
return false;
}
auto ptr = reinterpret_cast <uint8 *> (address);
while (*reinterpret_cast <uint16 *> (ptr) == jmp) {
ptr = **reinterpret_cast <uint8 * **> (ptr + 2);
}
m_origFunc = reinterpret_cast <uint> (address);
if (!m_origFunc) {
return false;
}
m_hookFunc = reinterpret_cast <uint> (replacement);
if (plat.x64) {
const uint16 nop = 0x00000000;
memcpy (&m_hookBytes[0], &jmp, sizeof (uint16));
memcpy (&m_hookBytes[2], &nop, sizeof (uint16));
memcpy (&m_hookBytes[6], &replacement, sizeof (uint));
}
else {
m_hookBytes[0] = 0x68;
m_hookBytes[5] = 0xc3;
memcpy (&m_hookBytes[1], &m_hookFunc, sizeof (uint));
}
if (unprotect ()) {
memcpy (m_origBytes, reinterpret_cast <void *> (m_origFunc), CodeLength);
return enable ();
}
return false;
}
bool enable () {
if (m_patched) {
return false;
}
m_patched = true;
if (unprotect ()) {
memcpy (reinterpret_cast <void *> (m_origFunc), m_hookBytes, CodeLength);
return true;
}
return false;
}
bool disable () {
if (!m_patched) {
return false;
}
m_patched = false;
if (unprotect ()) {
memcpy (reinterpret_cast <void *> (m_origFunc), m_origBytes, CodeLength);
return true;
}
return false;
}
bool enabled () const {
return m_patched;
}
};
CR_NAMESPACE_END

View file

@ -1,175 +0,0 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
//
#pragma once
#include <crlib/cr-alloc.h>
#include <crlib/cr-uniqueptr.h>
CR_NAMESPACE_BEGIN
template <typename> class Lambda;
template <typename R, typename ...Args> class Lambda <R (Args...)> {
private:
enum : uint32 {
LamdaSmallBufferLength = sizeof (void *) * 16
};
private:
class LambdaFunctorWrapper {
public:
LambdaFunctorWrapper () = default;
virtual ~LambdaFunctorWrapper () = default;
public:
virtual void move (uint8 *to) = 0;
virtual void small (uint8 *to) const = 0;
virtual R invoke (Args &&...) = 0;
virtual UniquePtr <LambdaFunctorWrapper> clone () const = 0;
public:
void operator delete (void *ptr) {
alloc.deallocate (ptr);
}
};
template <typename T> class LambdaFunctor : public LambdaFunctorWrapper {
private:
T m_callable;
public:
LambdaFunctor (const T &callable) : LambdaFunctorWrapper (), m_callable (callable)
{ }
LambdaFunctor (T &&callable) : LambdaFunctorWrapper (), m_callable (cr::move (callable))
{ }
~LambdaFunctor () override = default;
public:
void move (uint8 *to) override {
new (to) LambdaFunctor<T> (cr::move (m_callable));
}
void small (uint8 *to) const override {
new (to) LambdaFunctor<T> (m_callable);
}
R invoke (Args &&... args) override {
return m_callable (cr::forward <Args> (args)...);
}
UniquePtr <LambdaFunctorWrapper> clone () const override {
return makeUnique <LambdaFunctor <T>> (m_callable);
}
};
union {
UniquePtr <LambdaFunctorWrapper> m_functor;
uint8 m_small[LamdaSmallBufferLength];
};
bool m_smallObject;
private:
void destroy () {
if (m_smallObject) {
reinterpret_cast <LambdaFunctorWrapper *> (m_small)->~LambdaFunctorWrapper ();
}
else {
m_functor.reset ();
}
}
void swap (Lambda &rhs) noexcept {
cr::swap (rhs, *this);
}
public:
explicit Lambda () noexcept : Lambda (nullptr)
{ }
Lambda (decltype (nullptr)) noexcept : m_functor (nullptr), m_smallObject (false)
{ }
Lambda (const Lambda &rhs) {
if (rhs.m_smallObject) {
reinterpret_cast <const LambdaFunctorWrapper *> (rhs.m_small)->small (m_small);
}
else {
new (m_small) UniquePtr <LambdaFunctorWrapper> (rhs.m_functor->clone ());
}
m_smallObject = rhs.m_smallObject;
}
Lambda (Lambda &&rhs) noexcept {
if (rhs.m_smallObject) {
reinterpret_cast <LambdaFunctorWrapper *> (rhs.m_small)->move (m_small);
new (rhs.m_small) UniquePtr <LambdaFunctorWrapper> (nullptr);
}
else {
new (m_small) UniquePtr <LambdaFunctorWrapper> (cr::move (rhs.m_functor));
}
m_smallObject = rhs.m_smallObject;
rhs.m_smallObject = false;
}
template <typename F> Lambda (F function) {
if (cr::fix (sizeof (function) > LamdaSmallBufferLength)) {
m_smallObject = false;
new (m_small) UniquePtr <LambdaFunctorWrapper> (makeUnique <LambdaFunctor <F>> (cr::move (function)));
}
else {
m_smallObject = true;
new (m_small) LambdaFunctor<F> (cr::move (function));
}
}
~Lambda () {
destroy ();
}
public:
Lambda &operator = (const Lambda &rhs) {
destroy ();
Lambda tmp (rhs);
swap (tmp);
return *this;
}
Lambda &operator = (Lambda &&rhs) noexcept {
destroy ();
if (rhs.m_smallObject) {
reinterpret_cast <LambdaFunctorWrapper *> (rhs.m_small)->move (m_small);
new (rhs.m_small) UniquePtr <LambdaFunctorWrapper> (nullptr);
}
else {
new (m_small) UniquePtr <LambdaFunctorWrapper> (cr::move (rhs.m_functor));
}
m_smallObject = rhs.m_smallObject;
rhs.m_smallObject = false;
return *this;
}
explicit operator bool () const noexcept {
return m_smallObject || !!m_functor;
}
public:
R operator () (Args ...args) {
return m_smallObject ? reinterpret_cast <LambdaFunctorWrapper *> (m_small)->invoke (cr::forward <Args> (args)...) : m_functor->invoke (cr::forward <Args> (args)...);
}
};
CR_NAMESPACE_END

View file

@ -1,116 +0,0 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-string.h>
#if defined (CR_LINUX) || defined (CR_OSX)
# include <dlfcn.h>
# include <errno.h>
# include <fcntl.h>
# include <sys/stat.h>
# include <unistd.h>
#endif
CR_NAMESPACE_BEGIN
// handling dynamic library loading
class SharedLibrary final : public DenyCopying {
private:
void *m_handle = nullptr;
public:
explicit SharedLibrary () = default;
SharedLibrary (const String &file) {
if (file.empty ()) {
return;
}
load (file);
}
~SharedLibrary () {
unload ();
}
public:
bool load (const String &file) noexcept {
if (*this) {
unload ();
}
#if defined (CR_WINDOWS)
m_handle = LoadLibraryA (file.chars ());
#else
m_handle = dlopen (file.chars (), RTLD_NOW);
#endif
return m_handle != nullptr;
}
bool locate (void *address) {
#if defined (CR_WINDOWS)
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQuery (address, &mbi, sizeof (mbi))) {
return false;
}
if (mbi.State != MEM_COMMIT) {
return false;
}
m_handle = reinterpret_cast <void *> (mbi.AllocationBase);
#else
Dl_info dli;
plat.bzero (&dli, sizeof (dli));
if (dladdr (address, &dli)) {
return load (dli.dli_fname);
}
#endif
return m_handle != nullptr;
}
void unload () noexcept {
if (!*this) {
return;
}
#if defined (CR_WINDOWS)
FreeLibrary (static_cast <HMODULE> (m_handle));
#else
dlclose (m_handle);
#endif
m_handle = nullptr;
}
template <typename R> R resolve (const char *function) const {
if (!*this) {
return nullptr;
}
return reinterpret_cast <R> (
#if defined (CR_WINDOWS)
GetProcAddress (static_cast <HMODULE> (m_handle), function)
#else
dlsym (m_handle, function)
#endif
);
}
void *handle () const {
return m_handle;
}
public:
explicit operator bool () const {
return m_handle != nullptr;
}
};
CR_NAMESPACE_END

View file

@ -1,100 +0,0 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-movable.h>
CR_NAMESPACE_BEGIN
// simple unique ptr
template <typename T> class UniquePtr final : public DenyCopying {
private:
T *m_ptr = nullptr;
public:
UniquePtr () = default;
explicit UniquePtr (T *ptr) : m_ptr (ptr)
{ }
UniquePtr (UniquePtr &&rhs) noexcept : m_ptr (rhs.release ())
{ }
template <typename U> UniquePtr (UniquePtr <U> &&rhs) noexcept : m_ptr (rhs.release ())
{ }
~UniquePtr () {
destroy ();
}
public:
T *get () const {
return m_ptr;
}
T *release () {
auto ret = m_ptr;
m_ptr = nullptr;
return ret;
}
void reset (T *ptr = nullptr) {
destroy ();
m_ptr = ptr;
}
private:
void destroy () {
if (m_ptr) {
alloc.destroy (m_ptr);
m_ptr = nullptr;
}
}
public:
UniquePtr &operator = (UniquePtr &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
template <typename U> UniquePtr &operator = (UniquePtr <U> &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
UniquePtr &operator = (decltype (nullptr)) {
destroy ();
return *this;
}
T &operator * () const {
return *m_ptr;
}
T *operator -> () const {
return m_ptr;
}
explicit operator bool () const {
return m_ptr != nullptr;
}
};
// create unique
template <typename T, typename... Args> UniquePtr <T> makeUnique (Args &&... args) {
return UniquePtr <T> (alloc.create <T> (cr::forward <Args> (args)...));
}
CR_NAMESPACE_END

View file

@ -1,33 +0,0 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
//
#pragma once
// general product information
#define PRODUCT_NAME "Yet Another POD-Bot"
#define PRODUCT_SHORT_NAME "YaPB"
#define PRODUCT_VERSION "2.92"
#define PRODUCT_AUTHOR "YaPB Contributors"
#define PRODUCT_URL "https://yapb.ru/"
#define PRODUCT_EMAIL "yapb@entix.io"
#define PRODUCT_LOGTAG "YAPB"
#define PRODUCT_END_YEAR "2020"
#define PRODUCT_DESCRIPTION PRODUCT_NAME " v" PRODUCT_VERSION " - The Counter-Strike Bot (" PRODUCT_COMMENTS ")"
#define PRODUCT_COPYRIGHT "Copyright © 2004-" PRODUCT_END_YEAR ", by " PRODUCT_AUTHOR
#define PRODUCT_LEGAL "Half-Life, Counter-Strike, Counter-Strike: Condition Zero, Steam, Valve is a trademark of Valve Corporation"
#define PRODUCT_ORIGINAL_NAME "yapb.dll"
#define PRODUCT_INTERNAL_NAME "podbot"
#define PRODUCT_GIT_HASH "unspecified_hash"
#define PRODUCT_GIT_COMMIT_AUTHOR "unspecified_author"
#define PRODUCT_GIT_COMMIT_ID 0000
#define PRODUCT_VERSION_DWORD_INTERNAL 2,92
#define PRODUCT_VERSION_DWORD PRODUCT_VERSION_DWORD_INTERNAL, PRODUCT_GIT_COMMIT_ID
#define PRODUCT_SUPPORT_VERSION "Beta 6.6 - Condition Zero"
#define PRODUCT_COMMENTS "http://github.com/jeefo/yapb/"
#define PRODUCT_DATE __DATE__

252
meson.build Normal file
View file

@ -0,0 +1,252 @@
#
# YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
# Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
project (
'yapb',
'cpp',
version: '4.0.0',
license: 'GPL',
default_options: [
'buildtype=release',
'b_ndebug=if-release',
'cpp_std=c++14',
'warning_level=3',
'werror=true',
'backend=ninja',
'strip=true',
'optimization=3',
'default_library=static',
'cpp_eh=none'
],
meson_version: '>=0.48.0')
find_program ('ninja', required: true)
find_program ('git', required: true)
find_program ('hostname', required: true)
buildCompiler = meson.get_compiler ('cpp')
buildSystem = host_machine.system ()
buildVersion = meson.project_version ()
compilerId = buildCompiler.get_id ()
compilerVersion = buildCompiler.version ()
isOptimize = get_option ('buildtype') == 'release'
isVC = compilerId == 'msvc' or compilerId == 'intel-cl' or compilerId == 'clang-cl'
isGCC = compilerId == 'gcc'
isIntel = compilerId == 'intel' or compilerId == 'intel-cl'
isCLang = compilerId == 'clang'
isWindows = buildSystem == 'windows'
isLinux = buildSystem == 'linux'
isDarwin = buildSystem == 'darwin'
flagsLinker = []
flagsCompiler = []
cdata = configuration_data()
if isWindows
cdata.set ('buildVersionWin', ','.join (buildVersion.split ('.')))
else
cdata.set ('buildVersionWin', buildVersion)
endif
cdata.set ('commitHash', run_command ('git', 'rev-parse', '--short', 'HEAD').stdout ().strip ())
cdata.set ('commitCount', run_command ('git', 'rev-list', '--count', 'HEAD').stdout ().strip ())
cdata.set ('commitAuthor', run_command ('git', 'log', '--pretty="%ae"', '-1').stdout ().strip ())
cdata.set ('buildVersion', buildVersion)
cdata.set ('buildMachine', run_command ('hostname').stdout ().strip ())
cdata.set ('buildCompiler', compilerId + ' ' + compilerVersion)
configure_file (input: 'inc/version.h.in', output: 'version.build.h', configuration: cdata)
flagsCompiler += '-DVERSION_GENERATED'
if isCLang or isGCC or (isIntel and not isWindows)
flagsCompiler += [
'-m32',
'-fno-threadsafe-statics',
'-fno-exceptions',
'-fno-rtti',
]
if isOptimize
flagsCompiler += '-msse3'
if (isCLang or isGCC) and not isDarwin
flagsCompiler += '-flto'
flagsLinker += '-flto'
if isGCC
flagsCompiler += [
'-fgraphite-identity'
]
endif
endif
endif
if isLinux
flagsLinker += [
'-m32',
'-lm',
'-ldl'
]
endif
endif
if isIntel and (isLinux or isDarwin)
flagsLinker += [
'-static-intel',
'-no-intel-extensions'
]
endif
if isLinux or isDarwin
if isDarwin
flagsCompiler += '-mmacosx-version-min=10.9'
flagsLinker += [
'-dynamiclib',
'-lstdc++',
'-mmacosx-version-min=10.9'
]
else
flagsLinker += '-static-libgcc'
endif
if not isOptimize
flagsCompiler += [
'-g3',
'-ggdb',
'-O3',
'-DCR_DEBUG'
]
else
flagsCompiler += [
'-mtune=generic',
'-msse3',
'-mfpmath=sse',
'-fno-builtin',
'-funroll-loops',
'-fomit-frame-pointer',
'-fno-stack-protector',
'-fvisibility=hidden',
'-fvisibility-inlines-hidden'
]
if isIntel
flagsCompiler += [
'-funroll-all-loops',
'-ipo',
'-wd11076',
'-wd11074'
]
flagsLinker += [
'-cxxlib-nostd',
'-Wl,--no-undefined,-z,notext,--gc-sections',
'-ipo'
]
elif isCLang and not isDarwin
llvmLinker = find_program ('lld', required: false)
if llvmLinker.found() == true
flagsLinker += '-fuse-ld=' + llvmLinker.path ().split ('/')[-1]
endif
flagsLinker += [
'-nostdlib++',
'-Wunused-command-line-argument',
'-Wl,-z,notext',
'--no-undefined'
]
elif isGCC and not isDarwin
flagsCompiler += '-funroll-all-loops'
flagsLinker += '-Wl,--no-undefined'
endif
endif
endif
if isWindows and (isVC or isIntel)
flagsLinker += [
'/MACHINE:X86',
'user32.lib',
'ws2_32.lib'
]
flagsCompiler += [
'/TP'
]
if isOptimize
flagsCompiler += '/GL'
flagsLinker += '/LTCG'
endif
elif isWindows and (isCLang or isGCC)
if isCLang
flagsLinker += '-Wl,/MACHINE:X86'
else
flagsLinker += [
'-static-libgcc',
'-Wl,--add-stdcall-alias'
]
endif
flagsLinker += [
'-luser32',
'-lws2_32'
]
endif
add_global_arguments (flagsCompiler, language: 'cpp')
add_global_link_arguments (flagsLinker, language: 'cpp')
sourceFiles = files (
'src/android.cpp',
'src/botlib.cpp',
'src/chatlib.cpp',
'src/combat.cpp',
'src/control.cpp',
'src/engine.cpp',
'src/graph.cpp',
'src/linkage.cpp',
'src/manager.cpp',
'src/message.cpp',
'src/navigate.cpp',
'src/support.cpp'
)
includes = include_directories ([
'.', 'inc', 'ext',
], is_system: true)
if isWindows and not isCLang
sourceFiles += import('windows').compile_resources (
'vc/yapb.rc',
include_directories: includes,
args: '-DVERSION_GENERATED'
)
endif
shared_library (
'yapb',
sourceFiles,
include_directories: includes,
gnu_symbol_visibility: 'hidden',
name_prefix: '')

View file

@ -1,92 +0,0 @@
#
# Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
# Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
#
# This software is licensed under the MIT license.
# Additional exceptions apply. For full license details, see LICENSE.txt
#
PROJECT = yapb
SOURCES = ../source
OBJECTS = $(wildcard $(SOURCES)/*.cpp)
COMPILER_FLAGS = -std=c++11 -m32 -Wall -Wextra -Werror -fno-exceptions -fno-rtti -pedantic
LINKER_FLAGS = -m32 -ldl
ifeq "$(DEBUG)" "true"
COMPILER_FLAGS += -g3 -DCR_DEBUG
BINARY_DIR = debug
else
COMPILER_FLAGS += -pipe -O3 -march=core2 -msse2 -mfpmath=sse -fno-builtin -fno-threadsafe-statics -funroll-loops -fomit-frame-pointer -fno-stack-protector -fvisibility=hidden -fvisibility-inlines-hidden
BINARY_DIR = release
endif
INCLUDE = -I../include
COMPILER = $(CC)
ifeq "$(shell uname -s)" "Darwin"
OSX = true
endif
ifeq "$(OSX)" "true"
LIBRARY_EXT = dylib
COMPILER_FLAGS += -mmacosx-version-min=10.9
LINKER_FLAGS += -dynamiclib -lstdc++ -mmacosx-version-min=10.9 -arch i386
else
LIBRARY_EXT = so
LINKER_FLAGS += -shared -static-libgcc
endif
BINARY_OUTPUT = $(PROJECT).$(LIBRARY_EXT)
ifeq ($(findstring clang,$(COMPILER)),clang)
ifneq "$(OSX)" "true"
ifeq "$(DEBUG)" "true"
LINKER_FLAGS += -lstdc++
else
LINKER_FLAGS += -nostdlib++ -Wunused-command-line-argument -fuse-ld=lld -Wl,-z,notext --no-undefined
endif
endif
else ifeq ($(findstring gcc,$(COMPILER)),gcc)
ifneq "$(OSX)" "true"
ifneq "$(DEBUG)" "true"
LINKER_FLAGS += -Wl,--no-undefined
COMPILER_FLAGS += -funroll-all-loops
endif
endif
else ifeq ($(findstring icc,$(COMPILER)),icc)
LINKER_FLAGS += -static-intel -no-intel-extensions
ifneq "$(DEBUG)" "true"
COMPILER_FLAGS += -funroll-all-loops -ipo -wd11076 -wd11074
LINKER_FLAGS += -cxxlib-nostd -Wl,--no-undefined,-z,notext,--gc-sections -ipo
endif
endif
OBJECTS_BIN := $(OBJECTS:%.cpp=$(BINARY_DIR)/%.o)
$(BINARY_DIR)/%.o: %.cpp
$(COMPILER) $(INCLUDE) $(COMPILER_FLAGS) -o $(subst $(SOURCES)/,,$@) -c $<
compile:
mkdir -p $(BINARY_DIR)
$(MAKE) $(PROJECT)
$(PROJECT): $(OBJECTS_BIN)
$(COMPILER) $(INCLUDE) $(subst $(SOURCES)/,,$(OBJECTS_BIN)) $(LINKER_FLAGS) -o $(BINARY_DIR)/$(BINARY_OUTPUT)
release:
$(MAKE) compile DEBUG=false
debug:
$(MAKE) compile DEBUG=true
all:
$(MAKE) compile DEBUG=true
$(MAKE) compile DEBUG=false
clean:
rm -rf release/*.o
rm -rf release/$(BINARY_OUTPUT)
rm -rf debug/*.o
rm -rf debug/$(BINARY_OUTPUT)

View file

@ -1,39 +0,0 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
//
#include <winver.h>
#include <../include/resource.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION PRODUCT_VERSION_DWORD
PRODUCTVERSION PRODUCT_VERSION_DWORD
FILEOS 0x40004
FILETYPE 0x2
{
BLOCK "StringFileInfo"
{
BLOCK "040904E4"
{
VALUE "CompanyName", PRODUCT_AUTHOR "\0"
VALUE "FileDescription", PRODUCT_DESCRIPTION "\0"
VALUE "FileVersion", PRODUCT_VERSION "\0"
VALUE "OriginalFilename", PRODUCT_ORIGINAL_NAME "\0"
VALUE "LegalCopyright", PRODUCT_COPYRIGHT "\0"
VALUE "LegalTrademarks", PRODUCT_LEGAL "\0"
VALUE "ProductName", PRODUCT_NAME "\0"
VALUE "ProductVersion", PRODUCT_VERSION "\0"
VALUE "InternalName", PRODUCT_INTERNAL_NAME "\0"
}
}
#ifndef NOLANGINFO
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x400, 1252
}
#endif
}

View file

@ -1,187 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="source">
<UniqueIdentifier>{8d3352c3-bb0c-4e87-bb5d-044bb9ec5e13}</UniqueIdentifier>
</Filter>
<Filter Include="include">
<UniqueIdentifier>{e529241e-773e-4084-a737-060aa8396cba}</UniqueIdentifier>
</Filter>
<Filter Include="project">
<UniqueIdentifier>{fe17a93f-cd53-4c35-b79b-969c4967865e}</UniqueIdentifier>
</Filter>
<Filter Include="include\engine">
<UniqueIdentifier>{f98ff5ec-055a-46cd-b5b1-462ef4c1c73e}</UniqueIdentifier>
</Filter>
<Filter Include="include\crlib">
<UniqueIdentifier>{76a583d1-8f55-451b-8516-2f7cce4d1875}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\resource.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\engine\const.h">
<Filter>include\engine</Filter>
</ClInclude>
<ClInclude Include="..\include\engine\eiface.h">
<Filter>include\engine</Filter>
</ClInclude>
<ClInclude Include="..\include\engine\extdll.h">
<Filter>include\engine</Filter>
</ClInclude>
<ClInclude Include="..\include\engine\meta_api.h">
<Filter>include\engine</Filter>
</ClInclude>
<ClInclude Include="..\include\engine\progdefs.h">
<Filter>include\engine</Filter>
</ClInclude>
<ClInclude Include="..\include\engine\util.h">
<Filter>include\engine</Filter>
</ClInclude>
<ClInclude Include="..\include\engine.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\yapb.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\engine\model.h">
<Filter>include\engine</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-alloc.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-array.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-basic.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-binheap.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-complete.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-dict.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-files.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-http.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-lambda.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-library.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-logger.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-math.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-movable.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-platform.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-random.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-string.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-twin.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-ulz.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-uniqueptr.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-vector.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-color.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\crlib\cr-hook.h">
<Filter>include\crlib</Filter>
</ClInclude>
<ClInclude Include="..\include\config.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\graph.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\manager.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\utils.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\control.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\message.h">
<Filter>include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\source\chatlib.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\navigate.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\support.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\manager.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\combat.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\engine.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\control.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\basecode.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\graph.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\android.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\message.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\linkage.cpp">
<Filter>source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="yapb.rc">
<Filter>project</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="makefile">
<Filter>project</Filter>
</None>
<None Include="..\source\Android.mk">
<Filter>project</Filter>
</None>
</ItemGroup>
</Project>

View file

@ -1,34 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(XASH3D_CONFIG)
LOCAL_MODULE := yapb
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a-hard)
LOCAL_MODULE_FILENAME = libyapb_hardfp
endif
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../include/engine
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_SRC_FILES := \
basecode.cpp \
manager.cpp \
message.cpp \
chatlib.cpp \
combat.cpp \
control.cpp \
engine.cpp \
linkage.cpp \
navigate.cpp \
support.cpp \
graph.cpp \
LOCAL_CFLAGS += -O3 -std=c++11 -DLINUX -D_LINUX -DPOSIX -pipe -fno-strict-aliasing -Wall -Werror -Wno-array-bounds
LOCAL_CPPFLAGS += -fno-exceptions -fno-rtti
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
@ -16,7 +23,7 @@ CR_EXPORT int Server_GetBlendingInterface (int version, struct sv_blending_inter
// of the body move, which bones, which hitboxes and how) between the server and the game DLL.
// some MODs can be using a different hitbox scheme than the standard one.
auto api_GetBlendingInterface = game.lib ().resolve <int (*) (int, struct sv_blending_interface_s **, struct engine_studio_api_s *, float *, float *)> (__FUNCTION__);
auto api_GetBlendingInterface = game.lib ().resolve <decltype (&Server_GetBlendingInterface)> (__FUNCTION__);
if (!api_GetBlendingInterface) {
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);

File diff suppressed because it is too large Load diff

View file

@ -1,16 +1,23 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
ConVar yb_chat ("yb_chat", "1", "Enables or disables bots chat functionality.");
ConVar cv_chat ("ub_chat", "1", "Enables or disables bots chat functionality.");
void BotUtils::stripTags (String &line) {
void BotSupport::stripTags (String &line) {
if (line.empty ()) {
return;
}
@ -30,7 +37,7 @@ void BotUtils::stripTags (String &line) {
}
}
void BotUtils::humanizePlayerName (String &playerName) {
void BotSupport::humanizePlayerName (String &playerName) {
if (playerName.empty ()) {
return;
}
@ -44,14 +51,14 @@ void BotUtils::humanizePlayerName (String &playerName) {
}
// sometimes switch name to lower characters, only valid for the english languge
if (rg.chance (8) && strcmp (yb_language.str (), "en") == 0) {
if (rg.chance (8) && strcmp (cv_language.str (), "en") == 0) {
playerName.lowercase ();
}
}
void BotUtils::addChatErrors (String &line) {
void BotSupport::addChatErrors (String &line) {
// sometimes switch name to lower characters, only valid for the english languge
if (rg.chance (8) && strcmp (yb_language.str (), "en") == 0) {
if (rg.chance (8) && strcmp (cv_language.str (), "en") == 0) {
line.lowercase ();
}
auto length = line.length ();
@ -72,10 +79,10 @@ void BotUtils::addChatErrors (String &line) {
}
}
bool BotUtils::checkKeywords (const String &line, String &reply) {
bool BotSupport::checkKeywords (StringRef line, String &reply) {
// this function checks is string contain keyword, and generates reply to it
if (!yb_chat.bool_ () || line.empty ()) {
if (!cv_chat.bool_ () || line.empty ()) {
return false;
}
@ -84,7 +91,7 @@ bool BotUtils::checkKeywords (const String &line, String &reply) {
// check is keyword has occurred in message
if (line.find (keyword) != String::InvalidIndex) {
StringArray &usedReplies = factory.usedReplies;
auto &usedReplies = factory.usedReplies;
if (usedReplies.length () >= factory.replies.length () / 4) {
usedReplies.clear ();
@ -92,7 +99,7 @@ bool BotUtils::checkKeywords (const String &line, String &reply) {
if (!factory.replies.empty ()) {
bool replyUsed = false;
const String &choosenReply = factory.replies.random ();
StringRef choosenReply = factory.replies.random ();
// don't say this twice
for (auto &used : usedReplies) {
@ -120,13 +127,13 @@ bool BotUtils::checkKeywords (const String &line, String &reply) {
return false;
}
void Bot::prepareChatMessage (const String &message) {
void Bot::prepareChatMessage (StringRef message) {
// this function parses messages from the botchat, replaces keywords and converts names into a more human style
if (!yb_chat.bool_ () || message.empty ()) {
if (!cv_chat.bool_ () || message.empty ()) {
return;
}
m_chatBuffer.assign (message.chars ());
m_chatBuffer = message;
// must be called before return or on the end
auto finishPreparation = [&] () {
@ -145,7 +152,7 @@ void Bot::prepareChatMessage (const String &message) {
}
// get the humanized name out of client
auto humanizedName = [] (int index) -> String {
auto humanizedName = [] (int index) -> StringRef {
auto ent = game.playerOfIndex (index);
if (!util.isPlayer (ent)) {
@ -158,7 +165,7 @@ void Bot::prepareChatMessage (const String &message) {
};
// find highfrag player
auto getHighfragPlayer = [&] () -> String {
auto getHighfragPlayer = [&] () -> StringRef {
int highestFrags = -1;
int index = 0;
@ -179,7 +186,7 @@ void Bot::prepareChatMessage (const String &message) {
};
// get roundtime
auto getRoundTime = [] () -> String {
auto getRoundTime = [] () -> StringRef {
auto roundTimeSecs = static_cast <int> (bots.getRoundEndTime () - game.time ());
String roundTime;
@ -189,12 +196,12 @@ void Bot::prepareChatMessage (const String &message) {
};
// get bot's victim
auto getMyVictim = [&] () -> String {;
auto getMyVictim = [&] () -> StringRef {;
return humanizedName (game.indexOfPlayer (m_lastVictim));
};
// get the game name alias
auto getGameName = [] () -> String {
auto getGameName = [] () -> StringRef {
String gameName;
if (game.is (GameFlags::ConditionZero)) {
@ -217,7 +224,7 @@ void Bot::prepareChatMessage (const String &message) {
};
// get enemy or teammate alive
auto getPlayerAlive = [&] (bool needsEnemy) -> String {
auto getPlayerAlive = [&] (bool needsEnemy) -> StringRef {
for (const auto &client : util.getClients ()) {
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.ent == ent ()) {
continue;
@ -317,19 +324,19 @@ bool Bot::isReplyingToChat () {
void Bot::checkForChat () {
// say a text every now and then
if (rg.chance (30) || m_notKilled || !yb_chat.bool_ ()) {
if (rg.chance (30) || m_notKilled || !cv_chat.bool_ ()) {
return;
}
// bot chatting turned on?
if (m_lastChatTime + rg.float_ (6.0f, 10.0f) < game.time () && bots.getLastChatTimestamp () + rg.float_ (2.5f, 5.0f) < game.time () && !isReplyingToChat ()) {
if (conf.hasChatBank (Chat::Dead)) {
const auto &phrase = conf.pickRandomFromChatBank (Chat::Dead);
StringRef phrase = conf.pickRandomFromChatBank (Chat::Dead);
bool sayBufferExists = false;
// search for last messages, sayed
for (auto &sentence : m_sayTextBuffer.lastUsedSentences) {
if (strncmp (sentence.chars (), phrase.chars (), sentence.length ()) == 0) {
if (phrase.startsWith (sentence)) {
sayBufferExists = true;
break;
}
@ -354,20 +361,11 @@ void Bot::checkForChat () {
}
}
void Bot::say (const char *text) {
void Bot::sendToChat (StringRef message, bool teamOnly) {
// this function prints saytext message to all players
if (strings.isEmpty (text) || !yb_chat.bool_ ()) {
if (message.empty () || !cv_chat.bool_ ()) {
return;
}
issueCommand ("say \"%s\"", text);
}
void Bot::sayTeam (const char *text) {
// this function prints saytext message only for teammates
if (strings.isEmpty (text) || !yb_chat.bool_ ()) {
return;
}
issueCommand ("say_team \"%s\"", text);
issueCommand ("%s \"%s\"", teamOnly ? "say_team" : "say", message);
}

View file

@ -1,18 +1,26 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
ConVar yb_shoots_thru_walls ("yb_shoots_thru_walls", "2", "Specifies whether bots able to fire at enemies behind the wall, if they hearing or suspecting them.", true, 0.0f, 3.0f);
ConVar yb_ignore_enemies ("yb_ignore_enemies", "0", "Enables or disables searching world for enemies.");
ConVar yb_check_enemy_rendering ("yb_check_enemy_rendering", "0", "Enables or disables checking enemy rendering flags. Useful for some mods.");
ConVar yb_stab_close_enemies ("yb_stab_close_enemies", "1", "Enables or disables bot ability to stab the enemy with knife if bot is in good condition.");
ConVar mp_friendlyfire ("mp_friendlyfire", nullptr, Var::NoRegister);
ConVar cv_shoots_thru_walls ("ub_shoots_thru_walls", "2", "Specifies whether bots able to fire at enemies behind the wall, if they hearing or suspecting them.", true, 0.0f, 3.0f);
ConVar cv_ignore_enemies ("ub_ignore_enemies", "0", "Enables or disables searching world for enemies.");
ConVar cv_check_enemy_rendering ("ub_check_enemy_rendering", "0", "Enables or disables checking enemy rendering flags. Useful for some mods.");
ConVar cv_stab_close_enemies ("ub_stab_close_enemies", "1", "Enables or disables bot ability to stab the enemy with knife if bot is in good condition.");
ConVar mp_friendlyfire ("mp_friendlyfire", nullptr, Var::GameRef);
int Bot::numFriendsNear (const Vector &origin, float radius) {
int count = 0;
@ -45,7 +53,7 @@ int Bot::numEnemiesNear (const Vector &origin, float radius) {
}
bool Bot::isEnemyHidden (edict_t *enemy) {
if (!yb_check_enemy_rendering.bool_ () || game.isNullEntity (enemy)) {
if (!cv_check_enemy_rendering.bool_ () || game.isNullEntity (enemy)) {
return false;
}
entvars_t &v = enemy->v;
@ -123,8 +131,8 @@ bool Bot::checkBodyParts (edict_t *target) {
return true;
}
const float standFeet = 34.0f;
const float crouchFeet = 14.0f;
constexpr auto standFeet = 34.0f;
constexpr auto crouchFeet = 14.0f;
if (target->v.flags & FL_DUCKING) {
spot.z = target->v.origin.z - crouchFeet;
@ -132,7 +140,7 @@ bool Bot::checkBodyParts (edict_t *target) {
else {
spot.z = target->v.origin.z - standFeet;
}
game.testLine (eyes, spot, TraceIgnore::Everything, self, &result);
game.testLineChannel (TraceChannel::Enemy, eyes, spot, TraceIgnore::Everything, self, &result);
if (result.flFraction >= 1.0f) {
m_enemyParts |= Visibility::Other;
@ -147,7 +155,7 @@ bool Bot::checkBodyParts (edict_t *target) {
Vector perp (-dir.y, dir.x, 0.0f);
spot = target->v.origin + Vector (perp.x * edgeOffset, perp.y * edgeOffset, 0);
game.testLine (eyes, spot, TraceIgnore::Everything, self, &result);
game.testLineChannel (TraceChannel::Enemy, eyes, spot, TraceIgnore::Everything, self, &result);
if (result.flFraction >= 1.0f) {
m_enemyParts |= Visibility::Other;
@ -157,7 +165,7 @@ bool Bot::checkBodyParts (edict_t *target) {
}
spot = target->v.origin - Vector (perp.x * edgeOffset, perp.y * edgeOffset, 0);
game.testLine (eyes, spot, TraceIgnore::Everything, self, &result);
game.testLineChannel (TraceChannel::Enemy, eyes, spot, TraceIgnore::Everything, self, &result);
if (result.flFraction >= 1.0f) {
m_enemyParts |= Visibility::Other;
@ -173,11 +181,11 @@ bool Bot::seesEnemy (edict_t *player, bool ignoreFOV) {
return false;
}
if (util.isPlayer (pev->dmg_inflictor) && game.getTeam (pev->dmg_inflictor) != m_team) {
if (cv_whose_your_daddy.bool_ () && util.isPlayer (pev->dmg_inflictor) && game.getTeam (pev->dmg_inflictor) != m_team) {
ignoreFOV = true;
}
if ((ignoreFOV || isInViewCone (player->v.origin)) && checkBodyParts (player)) {
if ((ignoreFOV || isInViewCone (player->v.origin)) && isEnemyInFrustum (player) && checkBodyParts (player)) {
m_seeEnemyTime = game.time ();
m_lastEnemy = player;
m_lastEnemyOrigin = m_enemyOrigin;
@ -201,14 +209,12 @@ bool Bot::lookupEnemies () {
// this function tries to find the best suitable enemy for the bot
// do not search for enemies while we're blinded, or shooting disabled by user
if (m_enemyIgnoreTimer > game.time () || m_blindTime > game.time () || yb_ignore_enemies.bool_ ()) {
if (m_enemyIgnoreTimer > game.time () || m_blindTime > game.time () || cv_ignore_enemies.bool_ ()) {
return false;
}
edict_t *player, *newEnemy = nullptr;
float nearestDistance = cr::square (m_viewDistance);
extern ConVar yb_whose_your_daddy;
// clear suspected flag
if (!game.isNullEntity (m_enemy) && (m_states & Sense::SeeingEnemy)) {
m_states &= ~Sense::SuspectEnemy;
@ -244,12 +250,12 @@ bool Bot::lookupEnemies () {
player = client.ent;
// check the engine PVS
if (!game.checkVisibility (player, set)) {
if (!isEnemyInFrustum (player) || !game.checkVisibility (player, set)) {
continue;
}
// extra skill player can see thru smoke... if beeing attacked
if ((player->v.button & (IN_ATTACK | IN_ATTACK2)) && m_viewDistance < m_maxViewDistance && yb_whose_your_daddy.bool_ ()) {
if ((player->v.button & (IN_ATTACK | IN_ATTACK2)) && m_viewDistance < m_maxViewDistance && cv_whose_your_daddy.bool_ ()) {
nearestDistance = cr::square (m_maxViewDistance);
}
@ -302,7 +308,7 @@ bool Bot::lookupEnemies () {
}
m_targetEntity = nullptr; // stop following when we see an enemy...
if (yb_whose_your_daddy.bool_ ()) {
if (cv_whose_your_daddy.bool_ ()) {
m_enemySurpriseTime = m_actualReactionTime * 0.5f;
}
else {
@ -373,7 +379,7 @@ bool Bot::lookupEnemies () {
}
// if no enemy visible check if last one shoot able through wall
if (yb_shoots_thru_walls.bool_ () && m_difficulty >= 2 && isPenetrableObstacle (newEnemy->v.origin)) {
if (cv_shoots_thru_walls.bool_ () && rg.chance (conf.getDifficultyTweaks (m_difficulty)->seenThruPct) && m_difficulty >= Difficulty::Normal && isPenetrableObstacle (newEnemy->v.origin)) {
m_seeEnemyTime = game.time ();
m_states |= Sense::SuspectEnemy;
@ -412,7 +418,7 @@ Vector Bot::getBodyOffsetError (float distance) {
}
if (m_aimErrorTime < game.time ()) {
const float error = distance / (cr::clamp (m_difficulty, 1, 4) * 1000.0f);
const float error = distance / (cr::clamp (m_difficulty, 1, 3) * 1000.0f);
Vector &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins;
m_aimLastError = Vector (rg.float_ (mins.x * error, maxs.x * error), rg.float_ (mins.y * error, maxs.y * error), rg.float_ (mins.z * error, maxs.z * error));
@ -436,7 +442,7 @@ const Vector &Bot::getEnemyBodyOffset () {
float distance = (m_enemy->v.origin - pev->origin).length ();
// do not aim at head, at long distance (only if not using sniper weapon)
if ((m_enemyParts & Visibility::Body) && !usesSniper () && distance > (m_difficulty > 2 ? 2000.0f : 1000.0f)) {
if ((m_enemyParts & Visibility::Body) && !usesSniper () && distance > (m_difficulty > Difficulty::Normal ? 2000.0f : 1000.0f)) {
m_enemyParts &= ~Visibility::Head;
}
@ -446,7 +452,7 @@ const Vector &Bot::getEnemyBodyOffset () {
}
Vector aimPos = m_enemy->v.origin;
if (m_difficulty > 2) {
if (m_difficulty > Difficulty::Normal) {
aimPos += (m_enemy->v.velocity - pev->velocity) * (getFrameInterval () * 1.25f);
}
@ -455,14 +461,15 @@ const Vector &Bot::getEnemyBodyOffset () {
aimPos += getBodyOffsetError (distance);
}
else {
bool useBody = !usesPistol () && distance >= kSprayDistance && distance < 3072.0f;
// now take in account different parts of enemy body
if (m_enemyParts & (Visibility::Head | Visibility::Body)) {
int headshotFreq[5] = { 20, 40, 60, 80, 100 };
// forced to use body?
bool useBody = !usesPistol () && distance >= kSprayDistance && distance < 3072.0f;
// now check is our skill match to aim at head, else aim at enemy body
if (rg.chance (headshotFreq[m_difficulty]) && !useBody) {
if (rg.chance (conf.getDifficultyTweaks (m_difficulty)->headshotPct) && !useBody) {
aimPos.z = headOffset (m_enemy) + getEnemyBodyOffsetCorrection (distance);
}
else {
@ -488,7 +495,7 @@ const Vector &Bot::getEnemyBodyOffset () {
m_lastEnemyOrigin = aimPos;
// add some error to unskilled bots
if (m_difficulty < 3) {
if (m_difficulty < Difficulty::Hard) {
m_enemyOrigin += getBodyOffsetError (distance);
}
return m_enemyOrigin;
@ -572,11 +579,11 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
// this function returns true if enemy can be shoot through some obstacle, false otherwise.
// credits goes to Immortal_BLG
if (yb_shoots_thru_walls.int_ () == 2) {
if (cv_shoots_thru_walls.int_ () == 2) {
return isPenetrableObstacle2 (dest);
}
if (m_isUsingGrenade || m_difficulty < 2) {
if (m_isUsingGrenade || m_difficulty < Difficulty::Normal) {
return false;
}
int penetratePower = conf.findWeaponById (m_currentWeapon).penetratePower;
@ -593,7 +600,7 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
const Vector &source = tr.vecEndPos;
game.testLine (dest, source, TraceIgnore::Monsters, ent (), &tr);
if (tr.flFraction != 1.0f) {
if (!cr::fequal (tr.flFraction, 1.0f)) {
if ((tr.vecEndPos - dest).lengthSq () > cr::square (800.0f)) {
return false;
}
@ -623,7 +630,7 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
bool Bot::isPenetrableObstacle2 (const Vector &dest) {
// this function returns if enemy can be shoot through some obstacle
if (m_isUsingGrenade || m_difficulty < 2 || !conf.findWeaponById (m_currentWeapon).penetratePower) {
if (m_isUsingGrenade || m_difficulty < Difficulty::Normal || !conf.findWeaponById (m_currentWeapon).penetratePower) {
return false;
}
@ -638,7 +645,7 @@ bool Bot::isPenetrableObstacle2 (const Vector &dest) {
game.testLine (source, dest, TraceIgnore::Everything, ent (), &tr);
while (tr.flFraction != 1.0f && numHits < 3) {
while (!cr::fequal (tr.flFraction, 1.0f) && numHits < 3) {
numHits++;
thikness++;
@ -686,8 +693,8 @@ bool Bot::needToPauseFiring (float distance) {
else if (distance < kDoubleSprayDistance) {
offset = 10.0f;
}
const float xPunch = cr::degreesToRadians (pev->punchangle.x);
const float yPunch = cr::degreesToRadians (pev->punchangle.y);
const float xPunch = cr::deg2rad (pev->punchangle.x);
const float yPunch = cr::deg2rad (pev->punchangle.y);
const float interval = getFrameInterval ();
const float tolerance = (100.0f - m_difficulty * 25.0f) / 99.0f;
@ -772,7 +779,7 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
}
// else is the bot holding a zoomable rifle?
else if (m_difficulty < 3 && usesZoomableRifle () && m_zoomCheckTime < game.time ()) {
else if (m_difficulty < Difficulty::Hard && usesZoomableRifle () && m_zoomCheckTime < game.time ()) {
// should the bot switch to zoomed mode?
if (distance > 800.0f && pev->fov >= 90.0f) {
pev->button |= IN_ATTACK2;
@ -786,13 +793,13 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
}
// we're should stand still before firing sniper weapons, else sniping is useless..
if (usesSniper () && (m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy)) && !m_isReloading && pev->velocity.lengthSq () > 0.0f) {
if (usesSniper () && (m_aimFlags & (AimFlags::Enemy | AimFlags::LastEnemy)) && !m_isReloading && pev->velocity.lengthSq () > 0.0f) {
m_moveSpeed = 0.0f;
m_strafeSpeed = 0.0f;
m_navTimeset = game.time ();
if (cr::abs (pev->velocity.x) > 5.0f || cr::abs (pev->velocity.y) > 5.0f || cr::abs (pev->velocity.z) > 5.0f) {
m_sniperStopTime = game.time () + 2.5f;
m_sniperStopTime = game.time () + 2.0f;
return;
}
}
@ -880,13 +887,13 @@ void Bot::fireWeapons () {
int weapons = pev->weapons;
// if jason mode use knife only
if (yb_jasonmode.bool_ ()) {
if (cv_jasonmode.bool_ ()) {
selectWeapons (distance, selectIndex, selectId, choosenWeapon);
return;
}
// use knife if near and good difficulty (l33t dude!)
if (yb_stab_close_enemies.bool_ () && m_difficulty >= 3 && pev->health > 80.0f && !game.isNullEntity (enemy) && pev->health >= enemy->v.health && distance < 100.0f && !isOnLadder () && !isGroupOfEnemies (pev->origin)) {
if (cv_stab_close_enemies.bool_ () && m_difficulty >= Difficulty::Hard && pev->health > 80.0f && !game.isNullEntity (enemy) && pev->health >= enemy->v.health && distance < 100.0f && !isOnLadder () && !isGroupOfEnemies (pev->origin)) {
selectWeapons (distance, selectIndex, selectId, choosenWeapon);
return;
}
@ -945,7 +952,7 @@ bool Bot::isWeaponBadAtDistance (int weaponIndex, float distance) {
auto &info = conf.getWeapons ();
if (m_difficulty < 2 || !hasSecondaryWeapon ()) {
if (m_difficulty < Difficulty::Normal || !hasSecondaryWeapon ()) {
return false;
}
int wid = info[weaponIndex].id;
@ -1138,7 +1145,7 @@ void Bot::attackMovement () {
}
}
if (m_difficulty >= 3 && (m_jumpTime + 5.0f < game.time () && isOnFloor () && rg.int_ (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.length2d () > 120.0f) && !usesSniper ()) {
if (m_difficulty >= Difficulty::Hard && (m_jumpTime + 5.0f < game.time () && isOnFloor () && rg.int_ (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.length2d () > 120.0f) && !usesSniper ()) {
pev->button |= IN_JUMP;
}
@ -1383,7 +1390,7 @@ void Bot::selectBestWeapon () {
// this function chooses best weapon, from weapons that bot currently own, and change
// current weapon to best one.
if (yb_jasonmode.bool_ ()) {
if (cv_jasonmode.bool_ ()) {
// if knife mode activated, force bot to use knife
selectWeaponByName ("weapon_knife");
return;
@ -1502,7 +1509,7 @@ void Bot::decideFollowUser () {
void Bot::updateTeamCommands () {
// prevent spamming
if (m_timeTeamOrder > game.time () + 2.0f || game.is (GameFlags::FreeForAll) || !yb_radio_mode.int_ ()) {
if (m_timeTeamOrder > game.time () + 2.0f || game.is (GameFlags::FreeForAll) || !cv_radio_mode.int_ ()) {
return;
}
@ -1524,17 +1531,17 @@ void Bot::updateTeamCommands () {
// has teammates?
if (memberNear) {
if (m_personality == Personality::Rusher && yb_radio_mode.int_ () == 2) {
if (m_personality == Personality::Rusher && cv_radio_mode.int_ () == 2) {
pushRadioMessage (Radio::StormTheFront);
}
else if (m_personality != Personality::Rusher && yb_radio_mode.int_ () == 2) {
else if (m_personality != Personality::Rusher && cv_radio_mode.int_ () == 2) {
pushRadioMessage (Radio::TeamFallback);
}
}
else if (memberExists && yb_radio_mode.int_ () == 1) {
else if (memberExists && cv_radio_mode.int_ () == 1) {
pushRadioMessage (Radio::TakingFireNeedAssistance);
}
else if (memberExists && yb_radio_mode.int_ () == 2) {
else if (memberExists && cv_radio_mode.int_ () == 2) {
pushChatterMessage (Chatter::ScaredEmotion);
}
m_timeTeamOrder = game.time () + rg.float_ (15.0f, 30.0f);

View file

@ -1,58 +1,62 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
ConVar yb_display_menu_text ("yb_display_menu_text", "1", "Enables or disables display menu text, when players asks for menu. Useful only for Android.");
ConVar yb_password ("yb_password", "", "The value (password) for the setinfo key, if user set's correct password, he's gains access to bot commands and menus.", false, 0.0f, 0.0f, Var::Password);
ConVar yb_password_key ("yb_password_key", "_ybpw", "The name of setinfo key used to store password to bot commands and menus", false);
ConVar cv_display_menu_text ("ub_display_menu_text", "1", "Enables or disables display menu text, when players asks for menu. Useful only for Android.");
ConVar cv_password ("ub_password", "", "The value (password) for the setinfo key, if user set's correct password, he's gains access to bot commands and menus.", false, 0.0f, 0.0f, Var::Password);
ConVar cv_password_key ("ub_password_key", "_ubpw", "The name of setinfo key used to store password to bot commands and menus.", false);
int BotControl::cmdAddBot () {
enum args { alias = 1, difficulty, personality, team, model, name, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
// this is duplicate error as in main bot creation code, but not to be silent
if (!graph.length () || graph.hasChanged ()) {
ctrl.msg ("There is no graph found or graph is changed. Cannot create bot.");
return BotCommandResult::Handled;
}
// give a chance to use additional args
m_args.resize (max);
// if team is specified, modify args to set team
if (m_args[alias].find ("_ct", 0) != String::InvalidIndex) {
if (strValue (alias).find ("_ct", 0) != String::InvalidIndex) {
m_args.set (team, "2");
}
else if (m_args[alias].find ("_t", 0) != String::InvalidIndex) {
else if (strValue (alias).find ("_t", 0) != String::InvalidIndex) {
m_args.set (team, "1");
}
// if highskilled bot is requsted set personality to rusher and maxout difficulty
if (m_args[alias].find ("hs", 0) != String::InvalidIndex) {
if (strValue (alias).find ("hs", 0) != String::InvalidIndex) {
m_args.set (difficulty, "4");
m_args.set (personality, "1");
}
bots.addbot (m_args[name], m_args[difficulty], m_args[personality], m_args[team], m_args[model], true);
bots.addbot (strValue (name), strValue (difficulty), strValue (personality), strValue (team), strValue (model), true);
return BotCommandResult::Handled;
}
int BotControl::cmdKickBot () {
enum args { alias = 1, team, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { alias = 1, team };
// if team is specified, kick from specified tram
if (m_args[alias].find ("_ct", 0) != String::InvalidIndex || getInt (team) == 2 || getStr (team) == "ct") {
if (strValue (alias).find ("_ct", 0) != String::InvalidIndex || intValue (team) == 2 || strValue (team) == "ct") {
bots.kickFromTeam (Team::CT);
}
else if (m_args[alias].find ("_t", 0) != String::InvalidIndex || getInt (team) == 1 || getStr (team) == "t") {
else if (strValue (alias).find ("_t", 0) != String::InvalidIndex || intValue (team) == 1 || strValue (team) == "t") {
bots.kickFromTeam (Team::Terrorist);
}
else {
@ -62,13 +66,10 @@ int BotControl::cmdKickBot () {
}
int BotControl::cmdKickBots () {
enum args { alias = 1, instant, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { alias = 1, instant };
// check if we're need to remove bots instantly
auto kickInstant = getStr (instant) == "instant";
auto kickInstant = strValue (instant) == "instant";
// kick the bots
bots.kickEveryone (kickInstant);
@ -79,14 +80,11 @@ int BotControl::cmdKickBots () {
int BotControl::cmdKillBots () {
enum args { alias = 1, team, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
// if team is specified, kick from specified tram
if (m_args[alias].find ("_ct", 0) != String::InvalidIndex || getInt (team) == 2 || getStr (team) == "ct") {
if (strValue (alias).find ("_ct", 0) != String::InvalidIndex || intValue (team) == 2 || strValue (team) == "ct") {
bots.killAllBots (Team::CT);
}
else if (m_args[alias].find ("_t", 0) != String::InvalidIndex || getInt (team) == 1 || getStr (team) == "t") {
else if (strValue (alias).find ("_t", 0) != String::InvalidIndex || intValue (team) == 1 || strValue (team) == "t") {
bots.killAllBots (Team::Terrorist);
}
else {
@ -96,29 +94,23 @@ int BotControl::cmdKillBots () {
}
int BotControl::cmdFill () {
enum args { alias = 1, team, count, difficulty, personality, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { alias = 1, team, count, difficulty, personality };
if (!hasArg (team)) {
return BotCommandResult::BadFormat;
}
bots.serverFill (getInt (team), hasArg (personality) ? getInt (personality) : -1, hasArg (difficulty) ? getInt (difficulty) : -1, hasArg (count) ? getInt (count) : -1);
bots.serverFill (intValue (team), hasArg (personality) ? intValue (personality) : -1, hasArg (difficulty) ? intValue (difficulty) : -1, hasArg (count) ? intValue (count) : -1);
return BotCommandResult::Handled;
}
int BotControl::cmdVote () {
enum args { alias = 1, mapid, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { alias = 1, mapid };
if (!hasArg (mapid)) {
return BotCommandResult::BadFormat;
}
int mapID = getInt (mapid);
int mapID = intValue (mapid);
// loop through all players
for (const auto &bot : bots) {
@ -130,10 +122,7 @@ int BotControl::cmdVote () {
}
int BotControl::cmdWeaponMode () {
enum args { alias = 1, type, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { alias = 1, type };
if (!hasArg (type)) {
return BotCommandResult::BadFormat;
@ -148,7 +137,7 @@ int BotControl::cmdWeaponMode () {
modes.push ("sniper", 6);
modes.push ("standard", 7);
auto mode = getStr (type);
auto mode = strValue (type);
// check if selected mode exists
if (!modes.exists (mode)) {
@ -160,32 +149,18 @@ int BotControl::cmdWeaponMode () {
}
int BotControl::cmdVersion () {
auto hash = String (PRODUCT_GIT_HASH).substr (0, 8);
auto author = String (PRODUCT_GIT_COMMIT_AUTHOR);
auto &build = product.build;
// if no hash specified, set local one
if (hash.startsWith ("unspe")) {
hash = "local";
}
// if no commit author, set local one
if (author.startsWith ("unspe")) {
author = PRODUCT_EMAIL;
}
msg ("%s v%s (build %u)", PRODUCT_NAME, PRODUCT_VERSION, util.buildNumber ());
msg (" compiled: %s %s by %s", __DATE__, __TIME__, author.chars ());
if (!hash.startsWith ("local")) {
msg (" commit: %scommit/%s", PRODUCT_COMMENTS, hash.chars ());
}
msg (" url: %s", PRODUCT_URL);
msg ("%s v%s.%s (ID %s)", product.name, product.version, build.count, build.id);
msg (" by %s (%s)", product.author, product.email);
msg (" %s", product.url);
msg ("compiled: %s on %s with %s", product.dtime, build.machine, build.compiler);
return BotCommandResult::Handled;
}
int BotControl::cmdNodeMenu () {
enum args { alias = 1, max };
enum args { alias = 1 };
// graph editor is available only with editor
if (!graph.hasEditor ()) {
@ -198,15 +173,12 @@ int BotControl::cmdNodeMenu () {
}
int BotControl::cmdMenu () {
enum args { alias = 1, cmd, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { alias = 1, cmd };
// reset the current menu
showMenu (Menu::None);
if (getStr (cmd) == "cmd" && util.isAlive (m_ent)) {
if (strValue (cmd) == "cmd" && util.isAlive (m_ent)) {
showMenu (Menu::Commands);
}
else {
@ -216,28 +188,24 @@ int BotControl::cmdMenu () {
}
int BotControl::cmdList () {
enum args { alias = 1, max };
enum args { alias = 1 };
bots.listBots ();
return BotCommandResult::Handled;
}
int BotControl::cmdCvars () {
enum args { alias = 1, pattern, max };
enum args { alias = 1, pattern };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
const auto &match = getStr (pattern);
const auto &match = strValue (pattern);
const bool isSave = match == "save";
File cfg;
// if save requested, dump cvars to yapb.cfg
if (isSave) {
cfg.open (strings.format ("%s/addons/yapb/conf/yapb.cfg", game.getModName ()), "wt");
cfg.puts ("// Configuration file for %s\n\n", PRODUCT_SHORT_NAME);
cfg.open (strings.format ("%s/addons/%s/conf/%s.cfg", game.getModName (), product.folder, product.folder), "wt");
cfg.puts ("// Configuration file for %s\n\n", product.name);
}
for (const auto &cvar : game.getCvars ()) {
@ -245,16 +213,16 @@ int BotControl::cmdCvars () {
continue;
}
if (!isSave && match != "empty" && !strstr (cvar.reg.name, match.chars ())) {
if (!isSave && !match.empty () && !strstr (cvar.reg.name, match.chars ())) {
continue;
}
// float value ?
bool isFloat = !strings.isEmpty (cvar.self->str ()) && strstr (cvar.self->str (), ".");
bool isFloat = !strings.isEmpty (cvar.self->str ()) && strchr (cvar.self->str (), '.');
if (isSave) {
cfg.puts ("//\n");
cfg.puts ("// %s\n", String::join (cvar.info.split ("\n"), "\n// ").chars ());
cfg.puts ("// %s\n", String::join (cvar.info.split ("\n"), "\n// "));
cfg.puts ("// ---\n");
if (cvar.bounded) {
@ -285,7 +253,7 @@ int BotControl::cmdCvars () {
}
else {
game.print ("cvar: %s", cvar.reg.name);
game.print ("info: %s", cvar.info.chars ());
game.print ("info: %s", cvar.info);
game.print (" ");
}
@ -299,13 +267,10 @@ int BotControl::cmdCvars () {
}
int BotControl::cmdNode () {
enum args { root, alias, cmd, cmd2, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { root, alias, cmd, cmd2 };
// graph editor supported only with editor
if (game.isDedicated () && !graph.hasEditor () && getStr (cmd) != "acquire_editor") {
if (game.isDedicated () && !graph.hasEditor () && strValue (cmd) != "acquire_editor") {
msg ("Unable to use graph edit commands without setting graph editor player. Please use \"graph acquire_editor\" to acquire rights for graph editing.");
return BotCommandResult::Handled;
}
@ -318,68 +283,68 @@ int BotControl::cmdNode () {
if (descriptions.empty ()) {
// separate function
auto pushGraphCmd = [&] (String cmd, String format, String help, Handler handler) -> void {
BotCmd botCmd (cr::move (cmd), cr::move (format), cr::move (help), cr::move (handler));
auto addGraphCmd = [&] (String cmd, String format, String help, Handler handler) -> void {
BotCmd botCmd { cmd, cr::move (format), cr::move (help), cr::move (handler) };
commands.push (cmd, cr::move (botCmd));
descriptions.push (cmd);
};
// add graph commands
pushGraphCmd ("on", "on [display|auto|noclip|models]", "Enables displaying of graph, nodes, noclip cheat", &BotControl::cmdNodeOn);
pushGraphCmd ("off", "off [display|auto|noclip|models]", "Disables displaying of graph, auto adding nodes, noclip cheat", &BotControl::cmdNodeOff);
pushGraphCmd ("menu", "menu [noarguments]", "Opens and displays bots graph edtior.", &BotControl::cmdNodeMenu);
pushGraphCmd ("add", "add [noarguments]", "Opens and displays graph node add menu.", &BotControl::cmdNodeAdd);
pushGraphCmd ("addbasic", "menu [noarguments]", "Adds basic nodes such as player spawn points, goals and ladders.", &BotControl::cmdNodeAddBasic);
pushGraphCmd ("save", "save [noarguments]", "Save graph file to disk.", &BotControl::cmdNodeSave);
pushGraphCmd ("load", "load [noarguments]", "Load graph file from disk.", &BotControl::cmdNodeLoad);
pushGraphCmd ("erase", "erase [iamsure]", "Erases the graph file from disk.", &BotControl::cmdNodeErase);
pushGraphCmd ("delete", "delete [nearest|index]", "Deletes single graph node from map.", &BotControl::cmdNodeDelete);
pushGraphCmd ("check", "check [noarguments]", "Check if graph working correctly.", &BotControl::cmdNodeCheck);
pushGraphCmd ("cache", "cache [nearest|index]", "Caching node for future use.", &BotControl::cmdNodeCache);
pushGraphCmd ("clean", "clean [all|nearest|index]", "Clean useless path connections from all or single node.", &BotControl::cmdNodeClean);
pushGraphCmd ("setradius", "setradius [radius] [nearest|index]", "Sets the radius for node.", &BotControl::cmdNodeSetRadius);
pushGraphCmd ("flags", "flags [noarguments]", "Open and displays menu for modifying flags for nearest point.", &BotControl::cmdNodeSetFlags);
pushGraphCmd ("teleport", "teleport [index]", "Teleports player to specified node index.", &BotControl::cmdNodeTeleport);
pushGraphCmd ("upload", "upload [id]", "Uploads created graph to graph database.", &BotControl::cmdNodeUpload);
addGraphCmd ("on", "on [display|auto|noclip|models]", "Enables displaying of graph, nodes, noclip cheat", &BotControl::cmdNodeOn);
addGraphCmd ("off", "off [display|auto|noclip|models]", "Disables displaying of graph, auto adding nodes, noclip cheat", &BotControl::cmdNodeOff);
addGraphCmd ("menu", "menu [noarguments]", "Opens and displays bots graph edtior.", &BotControl::cmdNodeMenu);
addGraphCmd ("add", "add [noarguments]", "Opens and displays graph node add menu.", &BotControl::cmdNodeAdd);
addGraphCmd ("addbasic", "menu [noarguments]", "Adds basic nodes such as player spawn points, goals and ladders.", &BotControl::cmdNodeAddBasic);
addGraphCmd ("save", "save [noarguments]", "Save graph file to disk.", &BotControl::cmdNodeSave);
addGraphCmd ("load", "load [noarguments]", "Load graph file from disk.", &BotControl::cmdNodeLoad);
addGraphCmd ("erase", "erase [iamsure]", "Erases the graph file from disk.", &BotControl::cmdNodeErase);
addGraphCmd ("delete", "delete [nearest|index]", "Deletes single graph node from map.", &BotControl::cmdNodeDelete);
addGraphCmd ("check", "check [noarguments]", "Check if graph working correctly.", &BotControl::cmdNodeCheck);
addGraphCmd ("cache", "cache [nearest|index]", "Caching node for future use.", &BotControl::cmdNodeCache);
addGraphCmd ("clean", "clean [all|nearest|index]", "Clean useless path connections from all or single node.", &BotControl::cmdNodeClean);
addGraphCmd ("setradius", "setradius [radius] [nearest|index]", "Sets the radius for node.", &BotControl::cmdNodeSetRadius);
addGraphCmd ("flags", "flags [noarguments]", "Open and displays menu for modifying flags for nearest point.", &BotControl::cmdNodeSetFlags);
addGraphCmd ("teleport", "teleport [index]", "Teleports player to specified node index.", &BotControl::cmdNodeTeleport);
addGraphCmd ("upload", "upload [id]", "Uploads created graph to graph database.", &BotControl::cmdNodeUpload);
// add path commands
pushGraphCmd ("path_create", "path_create [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathCreate);
pushGraphCmd ("path_create_in", "path_create_in [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathCreate);
pushGraphCmd ("path_create_out", "path_create_out [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathCreate);
pushGraphCmd ("path_create_both", "path_create_both [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathCreate);
pushGraphCmd ("path_delete", "path_create_both [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathDelete);
pushGraphCmd ("path_set_autopath", "path_set_autoath [max_distance]", "Opens and displays path creation menu.", &BotControl::cmdNodePathSetAutoDistance);
addGraphCmd ("path_create", "path_create [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathCreate);
addGraphCmd ("path_create_in", "path_create_in [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathCreate);
addGraphCmd ("path_create_out", "path_create_out [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathCreate);
addGraphCmd ("path_create_both", "path_create_both [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathCreate);
addGraphCmd ("path_delete", "path_create_both [noarguments]", "Opens and displays path deletion menu.", &BotControl::cmdNodePathDelete);
addGraphCmd ("path_set_autopath", "path_set_autopath [max_distance]", "Opens and displays path creation menu.", &BotControl::cmdNodePathSetAutoDistance);
// camp points iterator
pushGraphCmd ("iterate_camp", "iterate_camp [begin|end|next]", "Allows to go through all camp points on map.", &BotControl::cmdNodeIterateCamp);
addGraphCmd ("iterate_camp", "iterate_camp [begin|end|next]", "Allows to go through all camp points on map.", &BotControl::cmdNodeIterateCamp);
// remote graph editing stuff
if (game.isDedicated ()) {
pushGraphCmd ("acquire_editor", "acquire_editor [max_distance]", "Acquires rights to edit graph on dedicated server.", &BotControl::cmdNodeAcquireEditor);
pushGraphCmd ("release_editor", "acquire_editor [max_distance]", "Releases graph editing rights.", &BotControl::cmdNodeAcquireEditor);
addGraphCmd ("acquire_editor", "acquire_editor", "Acquires rights to edit graph on dedicated server.", &BotControl::cmdNodeAcquireEditor);
addGraphCmd ("release_editor", "acquire_editor", "Releases graph editing rights.", &BotControl::cmdNodeAcquireEditor);
}
}
if (commands.exists (getStr (cmd))) {
auto item = commands[getStr (cmd)];
if (commands.exists (strValue (cmd))) {
auto item = commands[strValue (cmd)];
// graph have only bad format return status
int status = (this->*item.handler) ();
if (status == BotCommandResult::BadFormat) {
msg ("Incorrect usage of \"%s %s %s\" command. Correct usage is:\n\n\t%s\n\nPlease use correct format.", m_args[root].chars (), m_args[alias].chars (), item.name.chars (), item.format.chars ());
msg ("Incorrect usage of \"%s %s %s\" command. Correct usage is:\n\n\t%s\n\nPlease use correct format.", m_args[root], m_args[alias], item.name, item.format);
}
}
else {
if (getStr (cmd) == "help" && hasArg (cmd2) && commands.exists (getStr (cmd2))) {
auto &item = commands[getStr (cmd2)];
if (strValue (cmd) == "help" && hasArg (cmd2) && commands.exists (strValue (cmd2))) {
auto &item = commands[strValue (cmd2)];
msg ("Command: \"%s %s %s\"\nFormat: %s\nHelp: %s", m_args[root].chars (), m_args[alias].chars (), item.name.chars (), item.format.chars (), item.help.chars ());
msg ("Command: \"%s %s %s\"\nFormat: %s\nHelp: %s", m_args[root], m_args[alias], item.name, item.format, item.help);
}
else {
for (auto &desc : descriptions) {
auto &item = commands[desc];
msg (" %s - %s", item.name.chars (), item.help.chars ());
msg (" %s - %s", item.name, item.help);
}
msg ("Currently Graph Status %s", graph.hasEditFlag (GraphEdit::On) ? "Enabled" : "Disabled");
}
@ -388,19 +353,16 @@ int BotControl::cmdNode () {
}
int BotControl::cmdNodeOn () {
enum args { alias = 1, cmd, option, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { alias = 1, cmd, option };
// enable various features of editor
if (getStr (option) == "empty" || getStr (option) == "display" || getStr (option) == "models") {
if (strValue (option).empty () || strValue (option) == "display" || strValue (option) == "models") {
graph.setEditFlag (GraphEdit::On);
enableDrawModels (true);
msg ("Graph editor has been enabled.");
}
else if (getStr (option) == "noclip") {
else if (strValue (option) == "noclip") {
m_ent->v.movetype = MOVETYPE_NOCLIP;
graph.setEditFlag (GraphEdit::On | GraphEdit::Noclip);
@ -408,7 +370,7 @@ int BotControl::cmdNodeOn () {
msg ("Graph editor has been enabled with noclip mode.");
}
else if (getStr (option) == "auto") {
else if (strValue (option) == "auto") {
graph.setEditFlag (GraphEdit::On | GraphEdit::Auto);
enableDrawModels (true);
@ -426,30 +388,27 @@ int BotControl::cmdNodeOn () {
}
int BotControl::cmdNodeOff () {
enum args { graph_cmd = 1, cmd, option, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd, option };
// enable various features of editor
if (getStr (option) == "empty" || getStr (option) == "display") {
if (strValue (option).empty () || strValue (option) == "display") {
graph.clearEditFlag (GraphEdit::On | GraphEdit::Auto | GraphEdit::Noclip);
enableDrawModels (false);
msg ("Graph editor has been disabled.");
}
else if (getStr (option) == "models") {
else if (strValue (option) == "models") {
enableDrawModels (false);
msg ("Graph editor has disabled spawn points highlighting.");
}
else if (getStr (option) == "noclip") {
else if (strValue (option) == "noclip") {
m_ent->v.movetype = MOVETYPE_WALK;
graph.clearEditFlag (GraphEdit::Noclip);
msg ("Graph editor has disabled noclip mode.");
}
else if (getStr (option) == "auto") {
else if (strValue (option) == "auto") {
graph.clearEditFlag (GraphEdit::Auto);
msg ("Graph editor has disabled auto add node mode.");
}
@ -457,10 +416,7 @@ int BotControl::cmdNodeOff () {
}
int BotControl::cmdNodeAdd () {
enum args { graph_cmd = 1, cmd, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd };
// turn graph on
graph.setEditFlag (GraphEdit::On);
@ -471,11 +427,7 @@ int BotControl::cmdNodeAdd () {
}
int BotControl::cmdNodeAddBasic () {
enum args { graph_cmd = 1, cmd, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd };
// turn graph on
graph.setEditFlag (GraphEdit::On);
@ -486,18 +438,15 @@ int BotControl::cmdNodeAddBasic () {
}
int BotControl::cmdNodeSave () {
enum args { graph_cmd = 1, cmd, option, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd, option };
// if no check is set save anyway
if (getStr (option) == "nocheck") {
if (strValue (option) == "nocheck") {
graph.saveGraphData ();
msg ("All nodes has been saved and written to disk (IGNORING QUALITY CONTROL).");
}
else if (getStr (option) == "old") {
else if (strValue (option) == "old") {
graph.saveOldFormat ();
msg ("All nodes has been saved and written to disk (POD-Bot Format (.pwf)).");
@ -515,10 +464,7 @@ int BotControl::cmdNodeSave () {
}
int BotControl::cmdNodeLoad () {
enum args { graph_cmd = 1, cmd, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd };
// just save graph on request
if (graph.loadGraphData ()) {
@ -531,13 +477,10 @@ int BotControl::cmdNodeLoad () {
}
int BotControl::cmdNodeErase () {
enum args { graph_cmd = 1, cmd, iamsure, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd, iamsure };
// prevent accidents when graph are deleted unintentionally
if (getStr (iamsure) == "iamsure") {
if (strValue (iamsure) == "iamsure") {
graph.eraseFromDisk ();
}
else {
@ -547,20 +490,17 @@ int BotControl::cmdNodeErase () {
}
int BotControl::cmdNodeDelete () {
enum args { graph_cmd = 1, cmd, nearest, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd, nearest };
// turn graph on
graph.setEditFlag (GraphEdit::On);
// if "neareset" or nothing passed delete neareset, else delete by index
if (getStr (nearest) == "empty" || getStr (nearest) == "nearest") {
if (strValue (nearest).empty () || strValue (nearest) == "nearest") {
graph.erase (kInvalidNodeIndex);
}
else {
int index = getInt (nearest);
int index = intValue (nearest);
// check for existence
if (graph.exists (index)) {
@ -575,10 +515,7 @@ int BotControl::cmdNodeDelete () {
}
int BotControl::cmdNodeCheck () {
enum args { graph_cmd = 1, cmd, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd };
// check if nodes are ok
if (graph.checkNodes (true)) {
@ -588,22 +525,19 @@ int BotControl::cmdNodeCheck () {
}
int BotControl::cmdNodeCache () {
enum args { graph_cmd = 1, cmd, nearest, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd, nearest };
// turn graph on
graph.setEditFlag (GraphEdit::On);
// if "neareset" or nothing passed delete neareset, else delete by index
if (getStr (nearest) == "empty" || getStr (nearest) == "nearest") {
if (strValue (nearest).empty () || strValue (nearest) == "nearest") {
graph.cachePoint (kInvalidNodeIndex);
msg ("Nearest node has been put into the memory.");
}
else {
int index = getInt (nearest);
int index = intValue (nearest);
// check for existence
if (graph.exists (index)) {
@ -618,16 +552,13 @@ int BotControl::cmdNodeCache () {
}
int BotControl::cmdNodeClean () {
enum args { graph_cmd = 1, cmd, option, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd, option };
// turn graph on
graph.setEditFlag (GraphEdit::On);
// if "all" passed clean up all the paths
if (getStr (option) == "all") {
if (strValue (option) == "all") {
int removed = 0;
for (int i = 0; i < graph.length (); ++i) {
@ -635,13 +566,13 @@ int BotControl::cmdNodeClean () {
}
msg ("Done. Processed %d nodes. %d useless paths was cleared.", graph.length (), removed);
}
else if (getStr (option) == "empty" || getStr (option) == "nearest") {
else if (strValue (option).empty () || strValue (option) == "nearest") {
int removed = graph.clearConnections (graph.getEditorNeareset ());
msg ("Done. Processed node %d. %d useless paths was cleared.", graph.getEditorNeareset (), removed);
}
else {
int index = getInt (option);
int index = intValue (option);
// check for existence
if (graph.exists (index)) {
@ -657,10 +588,7 @@ int BotControl::cmdNodeClean () {
}
int BotControl::cmdNodeSetRadius () {
enum args { graph_cmd = 1, cmd, radius, index, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd, radius, index };
// radius is a must
if (!hasArg (radius)) {
@ -668,13 +596,13 @@ int BotControl::cmdNodeSetRadius () {
}
int radiusIndex = kInvalidNodeIndex;
if (getStr (index) == "empty" || getStr (index) == "nearest") {
if (strValue (index).empty () || strValue (index) == "nearest") {
radiusIndex = graph.getEditorNeareset ();
}
else {
radiusIndex = getInt (index);
radiusIndex = intValue (index);
}
float value = getStr (radius).float_ ();
float value = strValue (radius).float_ ();
graph.setRadius (radiusIndex, value);
msg ("Node %d has been set to radius %.2f.", radiusIndex, value);
@ -683,10 +611,7 @@ int BotControl::cmdNodeSetRadius () {
}
int BotControl::cmdNodeSetFlags () {
enum args { graph_cmd = 1, cmd, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd };
// turn graph on
graph.setEditFlag (GraphEdit::On);
@ -697,15 +622,12 @@ int BotControl::cmdNodeSetFlags () {
}
int BotControl::cmdNodeTeleport () {
enum args { graph_cmd = 1, cmd, teleport_index, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd, teleport_index };
if (!hasArg (teleport_index)) {
return BotCommandResult::BadFormat;
}
int index = getInt (teleport_index);
int index = intValue (teleport_index);
// check for existence
if (graph.exists (index)) {
@ -723,22 +645,19 @@ int BotControl::cmdNodeTeleport () {
}
int BotControl::cmdNodePathCreate () {
enum args { graph_cmd = 1, cmd, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd };
// turn graph on
graph.setEditFlag (GraphEdit::On);
// choose the direction for path creation
if (m_args[cmd].find ("_both", 0) != String::InvalidIndex) {
if (strValue (cmd).find ("_both", 0) != String::InvalidIndex) {
graph.pathCreate (PathConnection::Bidirectional);
}
else if (m_args[cmd].find ("_in", 0) != String::InvalidIndex) {
else if (strValue (cmd).find ("_in", 0) != String::InvalidIndex) {
graph.pathCreate (PathConnection::Incoming);
}
else if (m_args[cmd].find ("_out", 0) != String::InvalidIndex) {
else if (strValue (cmd).find ("_out", 0) != String::InvalidIndex) {
graph.pathCreate (PathConnection::Outgoing);
}
else {
@ -748,10 +667,7 @@ int BotControl::cmdNodePathCreate () {
}
int BotControl::cmdNodePathDelete () {
enum args { graph_cmd = 1, cmd, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd };
// turn graph on
graph.setEditFlag (GraphEdit::On);
@ -763,10 +679,7 @@ int BotControl::cmdNodePathDelete () {
}
int BotControl::cmdNodePathSetAutoDistance () {
enum args { graph_cmd = 1, cmd, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd };
// turn graph on
graph.setEditFlag (GraphEdit::On);
@ -776,10 +689,7 @@ int BotControl::cmdNodePathSetAutoDistance () {
}
int BotControl::cmdNodeAcquireEditor () {
enum args { graph_cmd = 1, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1 };
if (game.isNullEntity (m_ent)) {
msg ("This command should not be executed from HLDS console.");
@ -797,10 +707,7 @@ int BotControl::cmdNodeAcquireEditor () {
}
int BotControl::cmdNodeReleaseEditor () {
enum args { graph_cmd = 1, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1 };
if (!graph.hasEditor ()) {
msg ("No one is currently has rights to edit. Nothing to release.");
@ -831,9 +738,9 @@ int BotControl::cmdNodeUpload () {
http.setTimeout (6);
// try to upload the file
if (http.uploadFile ("http://upload.ubot.su/", strings.format ("%sgraph/%s.graph", graph.getDataDirectory (false), game.getMapName ()))) {
msg ("Graph file was successfully validated and uploaded to the Ubot S3 storage (https://dl.ubot.su/).");
msg ("It will be available for download for all Ubot and YaPB users in a few minutes");
if (http.uploadFile ("http://yapb.ru/graph", strings.format ("%sgraph/%s.graph", graph.getDataDirectory (false), game.getMapName ()))) {
msg ("Graph file was successfully validated and uploaded to the YaPB Graph DB (%s).", product.download);
msg ("It will be available for download for all YaPB users in a few minutes.");
msg ("\n");
msg ("Thank you.");
msg ("\n");
@ -851,7 +758,7 @@ int BotControl::cmdNodeUpload () {
else {
status.assignf ("%d", code);
}
msg ("Something went wrong with uploading. Come back later. (%s)", status.chars ());
msg ("Something went wrong with uploading. Come back later. (%s)", status);
msg ("\n");
if (code == HttpClientResult::Forbidden) {
@ -868,16 +775,13 @@ int BotControl::cmdNodeUpload () {
}
int BotControl::cmdNodeIterateCamp () {
enum args { graph_cmd = 1, cmd, option, max };
// adding more args to args array, if not enough passed
fixMissingArgs (max);
enum args { graph_cmd = 1, cmd, option };
// turn graph on
graph.setEditFlag (GraphEdit::On);
// get the option descriping operation
auto op = getStr (option);
auto op = strValue (option);
if (op != "begin" && op != "end" && op != "next") {
return BotCommandResult::BadFormat;
@ -973,8 +877,8 @@ int BotControl::menuFeatures (int item) {
break;
case 4:
extern ConVar yb_debug;
yb_debug.set (yb_debug.int_ () ^ 1);
extern ConVar cv_debug;
cv_debug.set (cv_debug.int_ () ^ 1);
showMenu (Menu::Features);
break;
@ -1646,18 +1550,14 @@ bool BotControl::executeCommands () {
if (m_args.empty ()) {
return false;
}
// handle only "yb" and "yapb" commands
if (m_args[0] != "yb" && m_args[0] != "yapb") {
return false;
}
Client &client = util.getClient (game.indexOfPlayer (m_ent));
// do not allow to execute stuff for non admins
if (m_ent != game.getLocalEntity () && !(client.flags & ClientFlags::Admin)) {
msg ("Access to %s commands is restricted.", PRODUCT_SHORT_NAME);
msg ("Access to %s commands is restricted.", product.name);
return true;
}
const auto &prefix = m_args[0];
auto aliasMatch = [] (String &test, const String &cmd, String &aliasName) -> bool {
for (auto &alias : test.split ("/")) {
@ -1671,18 +1571,11 @@ bool BotControl::executeCommands () {
String cmd;
// give some help
if (m_args.length () > 0 && m_args[1] == "help") {
if (hasArg (1) && m_args[1] == "help") {
for (auto &item : m_cmds) {
if (aliasMatch (item.name, m_args[2], cmd)) {
msg ("Command: \"%s %s\"\nFormat: %s\nHelp: %s", m_args[0].chars (), cmd.chars (), item.format.chars (), item.help.chars ());
String aliases;
for (auto &alias : item.name.split ("/")) {
aliases.appendf ("%s, ", alias.chars ());
}
aliases.rtrim (", ");
msg ("Aliases: %s", aliases.chars ());
msg ("Command: \"%s %s\"\nFormat: %s\nHelp: %s", prefix, cmd, item.format, item.help);
msg ("Aliases: %s", String::join (item.name.split ("/"), ", "));
return true;
}
@ -1692,7 +1585,7 @@ bool BotControl::executeCommands () {
return true;
}
else {
msg ("No help found for \"%s\"", m_args[2].chars ());
msg ("No help found for \"%s\"", m_args[2]);
}
return true;
}
@ -1700,33 +1593,29 @@ bool BotControl::executeCommands () {
// if no args passed just print all the commands
if (m_args.length () == 1) {
msg ("usage %s <command> [arguments]", m_args[0].chars ());
msg ("usage %s <command> [arguments]", prefix);
msg ("valid commands are: ");
for (auto &item : m_cmds) {
msg (" %s - %s", item.name.split ("/")[0].chars (), item.help.chars ());
msg (" %s - %s", item.name.split ("/")[0], item.help);
}
return true;
}
// first search for a actual cmd
for (auto &item : m_cmds) {
auto root = m_args[0].chars ();
if (aliasMatch (item.name, m_args[1], cmd)) {
auto alias = cmd.chars ();
switch ((this->*item.handler) ()) {
case BotCommandResult::Handled:
default:
break;
case BotCommandResult::ListenServer:
msg ("Command \"%s %s\" is only available from the listenserver console.", root, alias);
msg ("Command \"%s %s\" is only available from the listenserver console.", prefix, cmd);
break;
case BotCommandResult::BadFormat:
msg ("Incorrect usage of \"%s %s\" command. Correct usage is:\n\n\t%s\n\nPlease type \"%s help %s\" to get more information.", root, alias, item.format.chars (), root, alias);
msg ("Incorrect usage of \"%s %s\" command. Correct usage is:\n\n\t%s\n\nPlease type \"%s help %s\" to get more information.", prefix, cmd, item.format, prefix, cmd);
break;
}
@ -1734,7 +1623,11 @@ bool BotControl::executeCommands () {
return true;
}
}
msg ("Unrecognized command: %s", m_args[1].chars ());
msg ("Unknown command: %s", m_args[1]);
// clear all the arguments upon finish
m_args.clear ();
return true;
}
@ -1745,14 +1638,14 @@ bool BotControl::executeMenus () {
auto &issuer = util.getClient (game.indexOfPlayer (m_ent));
// check if it's menu select, and some key pressed
if (getStr (0) != "menuselect" || getStr (1).empty () || issuer.menu == Menu::None) {
if (strValue (0) != "menuselect" || strValue (1).empty () || issuer.menu == Menu::None) {
return false;
}
// let's get handle
for (auto &menu : m_menus) {
if (menu.ident == issuer.menu) {
return (this->*menu.handler) (getStr (1).int_ ());
return (this->*menu.handler) (strValue (1).int_ ());
}
}
return false;
@ -1764,7 +1657,7 @@ void BotControl::showMenu (int id) {
// make menus looks like we need only once
if (!s_menusParsed) {
for (auto &parsed : m_menus) {
const String &translated = conf.translate (parsed.text.chars ());
StringRef translated = conf.translate (parsed.text);
// translate all the things
parsed.text = translated;
@ -1797,7 +1690,7 @@ void BotControl::showMenu (int id) {
for (auto &display : m_menus) {
if (display.ident == id) {
auto text = (game.is (GameFlags::Xash3D | GameFlags::Mobility) && !yb_display_menu_text.bool_ ()) ? " " : display.text.chars ();
auto text = (game.is (GameFlags::Xash3D | GameFlags::Mobility) && !cv_display_menu_text.bool_ ()) ? " " : display.text.chars ();
MessageWriter msg;
while (strlen (text) >= 64) {
@ -1870,8 +1763,8 @@ void BotControl::assignAdminRights (edict_t *ent, char *infobuffer) {
if (!game.isDedicated () || util.isFakeClient (ent)) {
return;
}
const String &key = yb_password_key.str ();
const String &password = yb_password.str ();
StringRef key = cv_password_key.str ();
StringRef password = cv_password.str ();
if (!key.empty () && !password.empty ()) {
auto &client = util.getClient (game.indexOfPlayer (ent));
@ -1898,18 +1791,18 @@ void BotControl::maintainAdminRights () {
Client &client = util.getClient (i);
if (client.flags & ClientFlags::Admin) {
if (strings.isEmpty (yb_password_key.str ()) && strings.isEmpty (yb_password.str ())) {
if (strings.isEmpty (cv_password_key.str ()) && strings.isEmpty (cv_password.str ())) {
client.flags &= ~ClientFlags::Admin;
}
else if (!!strcmp (yb_password.str (), engfuncs.pfnInfoKeyValue (engfuncs.pfnGetInfoKeyBuffer (client.ent), const_cast <char *> (yb_password_key.str ())))) {
else if (!!strcmp (cv_password.str (), engfuncs.pfnInfoKeyValue (engfuncs.pfnGetInfoKeyBuffer (client.ent), const_cast <char *> (cv_password_key.str ())))) {
client.flags &= ~ClientFlags::Admin;
game.print ("Player %s had lost remote access to %s.", player->v.netname.chars (), PRODUCT_SHORT_NAME);
game.print ("Player %s had lost remote access to %s.", player->v.netname.chars (), product.name);
}
}
else if (!(client.flags & ClientFlags::Admin) && !strings.isEmpty (yb_password_key.str ()) && !strings.isEmpty (yb_password.str ())) {
if (strcmp (yb_password.str (), engfuncs.pfnInfoKeyValue (engfuncs.pfnGetInfoKeyBuffer (client.ent), const_cast <char *> (yb_password_key.str ()))) == 0) {
else if (!(client.flags & ClientFlags::Admin) && !strings.isEmpty (cv_password_key.str ()) && !strings.isEmpty (cv_password.str ())) {
if (strcmp (cv_password.str (), engfuncs.pfnInfoKeyValue (engfuncs.pfnGetInfoKeyBuffer (client.ent), const_cast <char *> (cv_password_key.str ()))) == 0) {
client.flags |= ClientFlags::Admin;
game.print ("Player %s had gained full remote access to %s.", player->v.netname.chars (), PRODUCT_SHORT_NAME);
game.print ("Player %s had gained full remote access to %s.", player->v.netname.chars (), product.name);
}
}
}

View file

@ -1,18 +1,25 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
ConVar yb_csdm_mode ("yb_csdm_mode", "0", "Enables or disables CSDM / FFA mode for bots.\nAllowed values: '0', '1', '2', '3'.\nIf '0', CSDM / FFA mode is auto-detected.\nIf '1', CSDM mode is enabled, but FFA is disabled.\nIf '2' CSDM and FFA mode is enabled.\nIf '3' CSDM and FFA mode is disabled.", true, 0.0f, 3.0f);
ConVar cv_csdm_mode ("ub_csdm_mode", "0", "Enables or disables CSDM / FFA mode for bots.\nAllowed values: '0', '1', '2', '3'.\nIf '0', CSDM / FFA mode is auto-detected.\nIf '1', CSDM mode is enabled, but FFA is disabled.\nIf '2' CSDM and FFA mode is enabled.\nIf '3' CSDM and FFA mode is disabled.", true, 0.0f, 3.0f);
ConVar sv_skycolor_r ("sv_skycolor_r", nullptr, Var::NoRegister);
ConVar sv_skycolor_g ("sv_skycolor_g", nullptr, Var::NoRegister);
ConVar sv_skycolor_b ("sv_skycolor_b", nullptr, Var::NoRegister);
ConVar sv_skycolor_r ("sv_skycolor_r", nullptr, Var::GameRef);
ConVar sv_skycolor_g ("sv_skycolor_g", nullptr, Var::GameRef);
ConVar sv_skycolor_b ("sv_skycolor_b", nullptr, Var::GameRef);
Game::Game () {
m_startEntity = nullptr;
@ -63,13 +70,16 @@ void Game::levelInitialize (edict_t *entities, int max) {
// clear all breakables before initialization
m_breakables.clear ();
// precache everything
precache ();
// go thru the all entities on map, and do whatever we're want
for (int i = 0; i < max; ++i) {
auto ent = entities + i;
// only valid entities
if (!ent || ent->free || ent->v.classname == 0) {
if (!ent || ent->v.classname == 0) {
continue;
}
auto classname = ent->v.classname.chars ();
@ -109,7 +119,6 @@ void Game::levelInitialize (edict_t *entities, int max) {
++m_spawnCount[Team::Terrorist];
}
else if (strcmp (classname, "info_vip_start") == 0) {
m_engineWrap.setModel (ent, "models/player/vip/vip.mdl");
@ -191,7 +200,7 @@ void Game::testLine (const Vector &start, const Vector &end, int ignoreFlags, ed
// whether the trace starts "inside" an entity's polygonal model, and if so, to specify that entity
// in ignoreEntity in order to ignore it as a possible obstacle.
int engineFlags = 0;
auto engineFlags = 0;
if (ignoreFlags & TraceIgnore::Monsters) {
engineFlags = 1;
@ -203,6 +212,35 @@ void Game::testLine (const Vector &start, const Vector &end, int ignoreFlags, ed
engfuncs.pfnTraceLine (start, end, engineFlags, ignoreEntity, ptr);
}
bool Game::testLineChannel (TraceChannel channel, const Vector &start, const Vector &end, int ignoreFlags, edict_t *ignoreEntity, TraceResult *ptr) {
// this function traces a line dot by dot, starting from vecStart in the direction of vecEnd,
// ignoring or not monsters (depending on the value of IGNORE_MONSTERS, true or false), and stops
// at the first obstacle encountered, returning the results of the trace in the TraceResult structure
// ptr. Such results are (amongst others) the distance traced, the hit surface, the hit plane
// vector normal, etc. See the TraceResult structure for details. This function allows to specify
// whether the trace starts "inside" an entity's polygonal model, and if so, to specify that entity
// in ignoreEntity in order to ignore it as a possible obstacle.
auto bot = bots[ignoreEntity];
// check if bot is firing trace line
if (bot && bot->canSkipNextTrace (channel)) {
ptr = bot->getLastTraceResult (channel); // set the result from bot stored one
// current call is skipped
return true;
}
else {
testLine (start, end, ignoreFlags, ignoreEntity, ptr);
// if we're still reaching here, save the last trace result
if (bot) {
bot->setLastTraceResult (channel, ptr);
}
}
return false;
}
void Game::testHull (const Vector &start, const Vector &end, int ignoreFlags, int hullNumber, edict_t *ignoreEntity, TraceResult *ptr) {
// this function traces a hull dot by dot, starting from vecStart in the direction of vecEnd,
// ignoring or not monsters (depending on the value of IGNORE_MONSTERS, true or
@ -219,8 +257,7 @@ void Game::testHull (const Vector &start, const Vector &end, int ignoreFlags, in
}
float Game::getWaveLen (const char *fileName) {
extern ConVar yb_chatter_path;
const char *filePath = strings.format ("%s/%s/%s.wav", getModName (), yb_chatter_path.str (), fileName);
auto filePath = strings.format ("%s/%s/%s.wav", getModName (), cv_chatter_path.str (), fileName);
File fp (filePath, "rb");
@ -250,7 +287,7 @@ float Game::getWaveLen (const char *fileName) {
uint16 bitsPerSample;
char dataChunkId[4];
unsigned long dataChunkLength;
} waveHdr;
} waveHdr {};
plat.bzero (&waveHdr, sizeof (waveHdr));
@ -258,12 +295,12 @@ float Game::getWaveLen (const char *fileName) {
logger.error ("Wave File %s - has wrong or unsupported format", filePath);
return 0.0f;
}
fp.close ();
if (strncmp (waveHdr.chunkID, "WAVE", 4) != 0) {
logger.error ("Wave File %s - has wrong wave chunk id", filePath);
return 0.0f;
}
fp.close ();
if (waveHdr.dataChunkLength == 0) {
logger.error ("Wave File %s - has zero length!", filePath);
@ -329,7 +366,7 @@ void Game::registerEngineCommand (const char *command, void func ()) {
// check for hl pre 1.1.0.4, as it's doesn't have pfnAddServerCommand
if (!plat.checkPointer (engfuncs.pfnAddServerCommand)) {
logger.fatal ("YaPB's minimum HL engine version is 1.1.0.4 and minimum Counter-Strike is Beta 6.6. Please update your engine version.");
logger.fatal ("%s's minimum HL engine version is 1.1.0.6 and minimum Counter-Strike is Beta 7.1. Please update your engine / game version.", product.name);
}
engfuncs.pfnAddServerCommand (const_cast <char *> (command), func);
}
@ -482,22 +519,26 @@ bool Game::isSoftwareRenderer () {
return false;
}
void Game::addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, Var varType, bool missingAction, const char *regval, ConVar *self) {
void Game::addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32 varType, bool missingAction, const char *regval, ConVar *self) {
// this function adds globally defined variable to registration stack
VarPair pair {};
ConVarReg reg {};
pair.reg.name = const_cast <char *> (name);
pair.reg.string = const_cast <char *> (value);
pair.missing = missingAction;
pair.regval = regval;
pair.info = info;
pair.bounded = bounded;
reg.reg.name = const_cast <char *> (name);
reg.reg.string = const_cast <char *> (value);
reg.missing = missingAction;
reg.init = value;
reg.info = info;
reg.bounded = bounded;
if (regval) {
reg.regval = regval;
}
if (bounded) {
pair.min = min;
pair.max = max;
pair.initial = static_cast <float> (atof (value));
reg.min = min;
reg.max = max;
reg.initial = static_cast <float> (atof (value));
}
auto eflags = FCVAR_EXTDLL;
@ -512,15 +553,24 @@ void Game::addNewCvar (const char *name, const char *value, const char *info, bo
eflags |= FCVAR_PROTECTED;
}
pair.reg.flags = eflags;
pair.self = self;
pair.type = varType;
reg.reg.flags = eflags;
reg.self = self;
reg.type = varType;
m_cvars.push (cr::move (pair));
m_cvars.push (cr::move (reg));
}
void Game::checkCvarsBounds () {
for (const auto &var : m_cvars) {
// read only cvar is not changeable
if (var.type == Var::ReadOnly && !var.init.empty ()) {
if (var.init != var.self->str ()) {
var.self->set (var.init.chars ());
}
continue;
}
if (!var.bounded || !var.self) {
continue;
}
@ -544,7 +594,7 @@ void Game::registerCvars (bool gameVars) {
ConVar &self = *var.self;
cvar_t &reg = var.reg;
if (var.type != Var::NoRegister) {
if (var.type != Var::GameRef) {
self.ptr = engfuncs.pfnCVarGetPointer (reg.name);
if (!self.ptr) {
@ -565,8 +615,8 @@ void Game::registerCvars (bool gameVars) {
self.ptr = engfuncs.pfnCVarGetPointer (reg.name);
if (var.missing && !self.ptr) {
if (reg.string == nullptr && var.regval != nullptr) {
reg.string = const_cast <char *> (var.regval);
if (reg.string == nullptr && !var.regval.empty ()) {
reg.string = const_cast <char *> (var.regval.chars ());
reg.flags |= FCVAR_SERVER;
}
engfuncs.pfnCVarRegister (&var.reg);
@ -600,10 +650,10 @@ bool Game::loadCSBinary () {
libs.push ("cs.dylib");
}
auto libCheck = [&] (const String &mod, const String &dll) {
auto libCheck = [&] (StringRef mod, StringRef dll) {
// try to load gamedll
if (!m_gameLib) {
logger.fatal ("Unable to load gamedll \"%s\". Exiting... (gamedir: %s)", dll.chars (), mod.chars ());
logger.fatal ("Unable to load gamedll \"%s\". Exiting... (gamedir: %s)", dll, mod);
}
auto ent = m_gameLib.resolve <EntityFunction> ("trigger_random_unique");
@ -616,7 +666,7 @@ bool Game::loadCSBinary () {
// search the libraries inside game dlls directory
for (const auto &lib : libs) {
auto path = strings.format ("%s/dlls/%s", modname, lib.chars ());
auto path = strings.format ("%s/dlls/%s", modname, lib);
// if we can't read file, skip it
if (!File::exists (path)) {
@ -678,30 +728,36 @@ bool Game::loadCSBinary () {
bool Game::postload () {
// register logger
logger.initialize (strings.format ("%slogs/%s.log", graph.getDataDirectory (false), product.folder), [] (const char *msg) {
game.print (msg);
});
// ensure we're have all needed directories
for (const auto &dir : StringArray { "conf/lang", "data/learned", "data/graph", "data/logs" }) {
File::createPath (strings.format ("%s/addons/yapb/%s", getModName (), dir.chars ()));
for (const auto &dir : StringArray { "conf/lang", "data/train", "data/graph", "data/logs" }) {
File::createPath (strings.format ("%s/addons/%s/%s", getModName (), product.folder, dir));
}
// set out user agent for http stuff
http.setUserAgent (strings.format ("%s/%s", PRODUCT_SHORT_NAME, PRODUCT_VERSION));
http.setUserAgent (strings.format ("%s/%s", product.name, product.version));
// register bot cvars
game.registerCvars ();
// register server command(s)
registerEngineCommand ("yapb", [] () {
ctrl.handleEngineCommands ();
});
// handle prefixes
static StringArray prefixes = { "yb", "yapb" };
registerEngineCommand ("yb", [] () {
ctrl.handleEngineCommands ();
// register all our handlers
for (const auto &prefix : prefixes) {
registerEngineCommand (prefix.chars (), [] () {
ctrl.handleEngineCommands ();
});
}
// register fake metamod command handler if we not! under mm
if (!(game.is (GameFlags::Metamod))) {
game.registerEngineCommand ("meta", [] () {
game.print ("You're launched standalone version of %s. Metamod is not installed or not enabled!", PRODUCT_SHORT_NAME);
game.print ("You're launched standalone version of %s. Metamod is not installed or not enabled!", product.name);
});
}
@ -747,7 +803,7 @@ bool Game::postload () {
if (is (GameFlags::Metamod)) {
gameVersionFlags.push ("Metamod");
}
print ("%s v%s.0.%d successfully loaded for game: Counter-Strike %s (%s).\n", PRODUCT_SHORT_NAME, PRODUCT_VERSION, util.buildNumber (), gameVersionStr.chars (), String::join (gameVersionFlags, ", ").chars ());
print ("\n%s v%s.%s successfully loaded for game: Counter-Strike %s.\n\tFlags: %s.\n", product.name, product.version, product.build.count, gameVersionStr, gameVersionFlags.empty () ? "None" : String::join (gameVersionFlags, ", "));
};
if (plat.android) {
@ -785,7 +841,7 @@ void Game::applyGameModes () {
}
// handle cvar cases
switch (yb_csdm_mode.int_ ()) {
switch (cv_csdm_mode.int_ ()) {
default:
case 0:
break;
@ -843,6 +899,9 @@ void Game::slowFrame () {
// check if we're need to autokill bots
bots.maintainAutoKill ();
// maintain leaders selection upon round start
bots.maintainLeaders ();
// update client pings
util.calculatePings ();
@ -858,12 +917,15 @@ void Game::slowFrame () {
// check the cvar bounds
checkCvarsBounds ();
// refresh bomb origin in case some plugin moved it out
graph.setBombOrigin ();
// display welcome message
util.checkWelcome ();
m_slowFrame = time () + 1.0f;
}
void Game::searchEntities (const String &field, const String &value, EntitySearch functor) {
void Game::searchEntities (StringRef field, StringRef value, EntitySearch functor) {
edict_t *ent = nullptr;
while (!game.isNullEntity (ent = engfuncs.pfnFindEntityByString (ent, field.chars (), value.chars ()))) {
@ -877,7 +939,7 @@ void Game::searchEntities (const String &field, const String &value, EntitySearc
}
}
void Game::searchEntities (const Vector &position, const float radius, EntitySearch functor) {
void Game::searchEntities (const Vector &position, float radius, EntitySearch functor) {
edict_t *ent = nullptr;
const Vector &pos = position.empty () ? m_startEntity->v.origin : position;
@ -898,7 +960,7 @@ bool Game::isShootableBreakable (edict_t *ent) {
}
if (strcmp (ent->v.classname.chars (), "func_breakable") == 0 || (strcmp (ent->v.classname.chars (), "func_pushable") == 0 && (ent->v.spawnflags & SF_PUSH_BREAKABLE))) {
return ent->v.takedamage != DAMAGE_NO && ent->v.impulse <= 0 && !(ent->v.flags & FL_WORLDBRUSH) && !(ent->v.spawnflags & SF_BREAK_TRIGGER_ONLY) && ent->v.health < 500.0f;
return !cr::fequal (ent->v.takedamage, DAMAGE_NO) && ent->v.impulse <= 0 && !(ent->v.flags & FL_WORLDBRUSH) && !(ent->v.spawnflags & SF_BREAK_TRIGGER_ONLY) && ent->v.health < 500.0f;
}
return false;
}
@ -927,7 +989,7 @@ void LightMeasure::animateLight () {
// 'm' is normal light, 'a' is no light, 'z' is double bright
const int index = static_cast <int> (game.time () * 10.0f);
for (int j = 0; j < MAX_LIGHTSTYLES; ++j) {
for (auto j = 0; j < MAX_LIGHTSTYLES; ++j) {
if (!m_lightstyle[j].length) {
m_lightstyleValue[j] = 256;
continue;
@ -948,15 +1010,15 @@ void LightMeasure::updateLight (int style, char *value) {
if (strings.isEmpty (value)){
m_lightstyle[style].length = 0u;
m_lightstyle[style].map[0] = '\0';
m_lightstyle[style].map[0] = kNullChar;
return;
}
const auto copyLimit = sizeof (m_lightstyle[style].map) - sizeof ('\0');
const auto copyLimit = sizeof (m_lightstyle[style].map) - sizeof (kNullChar);
strings.copy (m_lightstyle[style].map, value, copyLimit);
m_lightstyle[style].map[copyLimit] = '\0';
m_lightstyle[style].length = strlen (m_lightstyle[style].map);
m_lightstyle[style].map[copyLimit] = kNullChar;
m_lightstyle[style].length = static_cast <int> (strlen (m_lightstyle[style].map));
}
template <typename S, typename M> bool LightMeasure::recursiveLightPoint (const M *node, const Vector &start, const Vector &end) {
@ -1082,40 +1144,47 @@ float LightMeasure::getSkyColor () {
return static_cast <float> (Color (sv_skycolor_r.int_ (), sv_skycolor_g.int_ (), sv_skycolor_b.int_ ()).avg ());
}
DynamicEntityLink::Handle DynamicEntityLink::search (Handle module, Name function) {
const auto lookup = [&] (Handle handle) {
Handle ret = nullptr;
if (m_dlsym.disable ()) {
ret = MODULE_SYMBOL (reinterpret_cast <MODULE_HANDLE> (handle), function);
m_dlsym.enable ();
}
return ret;
SharedLibrary::Handle EntityLinkage::lookup (SharedLibrary::Handle module, const char *function) {
const auto resolve = [&] (SharedLibrary::Handle handle) {
return reinterpret_cast <SharedLibrary::Handle> (m_dlsym.call <decltype (HOOK_FUNCTION)> (static_cast <HOOK_CAST> (handle), function));
};
// skip any ordinals requests on windows
if (plat.win32 && (static_cast <uint16> (reinterpret_cast <uint32> (function) >> 16) & 0xffff) == 0) {
return resolve (module);
}
static const auto &gamedll = game.lib ();
static const auto &yapb = m_self;
static const auto &self = m_self;
// if requested module is yapb, put in cache the looked up symbol
if (yapb.handle () == module) {
if (m_exports.exists (function)) {
return m_exports[function];
}
auto address = lookup (yapb.handle ());
// if requested module is yapb module, put in cache the looked up symbol
if (self.handle () != module) {
return resolve (module);
}
auto botAddr = resolve (self.handle ());
if (!address) {
auto gameAddress = lookup (gamedll.handle ());
if (!botAddr) {
auto gameAddr = resolve (gamedll.handle ());
if (gameAddress) {
m_exports[function] = gameAddress;
}
}
else {
m_exports[function] = address;
}
if (m_exports.exists (function)) {
return m_exports[function];
if (gameAddr) {
m_exports[function] = gameAddr;
}
}
return lookup (module);
else {
m_exports[function] = botAddr;
}
if (m_exports.exists (function)) {
return m_exports[function];
}
return nullptr;
}
void EntityLinkage::initialize () {
if (plat.arm) {
return;
}
m_dlsym.patch (reinterpret_cast <SharedLibrary::Handle> (&HOOK_FUNCTION), reinterpret_cast <SharedLibrary::Handle> (&EntityLinkage::replacement));
m_self.locate (&engfuncs);
}

View file

@ -1,15 +1,22 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
ConVar yb_graph_fixcamp ("yb_graph_fixcamp", "1", "Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format.");
ConVar yb_graph_url ("yb_graph_url", "http://graph.yapb.ru", "Specifies the URL from bots will be able to download graph in case of missing local one.", false);
ConVar cv_graph_fixcamp ("ub_graph_fixcamp", "1", "Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format.");
ConVar cv_graph_url ("ub_graph_url", product.download.chars (), "Specifies the URL from bots will be able to download graph in case of missing local one.", false, 0.0f, 0.0f);
void BotGraph::initGraph () {
// this function initialize the graph structures..
@ -639,7 +646,7 @@ void BotGraph::add (int type, const Vector &pos) {
}
m_paths.push (Path {});
index = m_paths.length () - 1;
index = length () - 1;
path = &m_paths[index];
path->number = index;
@ -1164,7 +1171,7 @@ void BotGraph::loadPractice () {
}
bool dataLoaded = loadStorage <Practice> ("prc", "Practice", StorageOption::Practice, StorageVersion::Practice, m_practice, nullptr, nullptr);
int count = m_paths.length ();
int count = length ();
// set's the highest damage if loaded ok
if (dataLoaded) {
@ -1351,20 +1358,31 @@ void BotGraph::initNarrowPlaces () {
ang.angleVectors (&forward, &right, &upward);
// helper lambda
auto directionCheck = [&] (const Vector &to, int weight) {
auto directionCheck = [&] (const Vector &to) -> bool {
game.testLine (path.origin + offset, to, TraceIgnore::None, nullptr, &tr);
// check if we're hit worldspawn entity
if (tr.pHit == worldspawn && tr.flFraction < 1.0f) {
accumWeight += weight;
return true;
}
return false;
};
directionCheck (-forward * distance, 1);
directionCheck (right * distance, 1);
directionCheck (-right * distance, 1);
if (directionCheck (-forward * distance)) {
accumWeight += 1;
}
directionCheck (upward * distance, 1);
if (directionCheck (right * distance)) {
accumWeight += 1;
}
if (directionCheck (-right * distance)) {
accumWeight += 1;
}
if (directionCheck (upward * distance)) {
accumWeight += 1;
}
}
path.flags &= ~NodeFlag::Narrow;
@ -1410,7 +1428,7 @@ void BotGraph::initNodesTypes () {
bool BotGraph::convertOldFormat () {
MemFile fp (getOldFormatGraphName (true));
PODGraphHeader header;
PODGraphHeader header {};
plat.bzero (&header, sizeof (header));
// save for faster access
@ -1473,14 +1491,14 @@ bool BotGraph::convertOldFormat () {
return true;
}
template <typename U> bool BotGraph::saveStorage (const String &ext, const String &name, StorageOption options, StorageVersion version, const SmallArray <U> &data, ExtenHeader *exten) {
bool isGraph = (ext == "graph");
template <typename U> bool BotGraph::saveStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, const SmallArray <U> &data, ExtenHeader *exten) {
bool isGraph = !!(options & StorageOption::Graph);
String filename;
filename.assignf ("%s.%s", game.getMapName (), ext.chars ());
filename.assignf ("%s.%s", game.getMapName (), ext);
if (data.empty ()) {
logger.error ("Unable to save %s file. Empty data. (filename: '%s').", name.chars (), filename.chars ());
logger.error ("Unable to save %s file. Empty data. (filename: '%s').", name, filename);
return false;
}
else if (isGraph) {
@ -1491,30 +1509,30 @@ template <typename U> bool BotGraph::saveStorage (const String &ext, const Strin
}
// open the file
File file (strings.format ("%s%s/%s", getDataDirectory (false), isGraph ? "graph" : "learned", filename.chars ()), "wb");
File file (strings.format ("%s%s/%s", getDataDirectory (false), isGraph ? "graph" : "train", filename), "wb");
// no open no fun
if (!file) {
logger.error ("Unable to open %s file for writing (filename: '%s').", name.chars (), filename.chars ());
logger.error ("Unable to open %s file for writing (filename: '%s').", name, filename);
file.close ();
return false;
}
ULZ lz;
size_t rawLength = data.length () * sizeof (U);
int32 rawLength = data.template length <int32> () * sizeof (U);
SmallArray <uint8> compressed (rawLength + sizeof (uint8) * ULZ::Excess);
// try to compress
auto compressedLength = lz.compress (reinterpret_cast <uint8 *> (data.data ()), rawLength, reinterpret_cast <uint8 *> (compressed.data ()));
if (compressedLength > 0) {
StorageHeader hdr;
StorageHeader hdr {};
hdr.magic = kStorageMagic;
hdr.version = version;
hdr.options = options;
hdr.length = m_paths.length ();
hdr.length = length ();
hdr.compressed = compressedLength;
hdr.uncompressed = rawLength;
@ -1525,10 +1543,10 @@ template <typename U> bool BotGraph::saveStorage (const String &ext, const Strin
if ((options & StorageOption::Exten) && exten != nullptr) {
file.write (exten, sizeof (ExtenHeader));
}
game.print ("Successfully saved Bots %s data.", name.chars ());
game.print ("Successfully saved Bots %s data.", name);
}
else {
logger.error ("Unable to compress %s data (filename: '%s').", name.chars (), filename.chars ());
logger.error ("Unable to compress %s data (filename: '%s').", name, filename);
file.close ();
return false;
@ -1537,13 +1555,13 @@ template <typename U> bool BotGraph::saveStorage (const String &ext, const Strin
return true;
}
template <typename U> bool BotGraph::loadStorage (const String &ext, const String &name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32 *outOptions) {
template <typename U> bool BotGraph::loadStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32 *outOptions) {
String filename;
filename.assignf ("%s.%s", game.getMapName (), ext.chars ()).lowercase ();
filename.assignf ("%s.%s", game.getMapName (), ext).lowercase ();
// graphs can be downloaded...
bool isGraph = (ext == "graph");
MemFile file (strings.format ("%s%s/%s", getDataDirectory (true), isGraph ? "graph" : "learned", filename.chars ())); // open the file
bool isGraph = !!(options & StorageOption::Graph);
MemFile file (strings.format ("%s%s/%s", getDataDirectory (true), isGraph ? "graph" : "train", filename)); // open the file
// resize data to fit the stuff
auto resizeData = [&] (const size_t length) {
@ -1559,48 +1577,24 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
resizeData (m_paths.length () * m_paths.length ());
}
// error has occured
auto bailout = [&] (const char *fmt, ...) -> bool {
va_list args;
auto result = strings.chars ();
// concatenate string
va_start (args, fmt);
vsnprintf (result, StringBuffer::StaticBufferSize, fmt, args);
va_end (args);
logger.error (result);
// if graph reset paths
if (isGraph) {
bots.kickEveryone (true);
m_tempStrings = result;
m_paths.clear ();
}
file.close ();
return false;
};
// if graph & attempted to load multiple times, bail out, we're failed
if (isGraph && ++m_loadAttempts > 2) {
m_loadAttempts = 0;
return bailout ("Unable to load %s (filename: '%s'). Download process has failed as well. No nodes has been found.", name.chars (), filename.chars ());
return raiseLoadingError (isGraph, file, "Unable to load %s (filename: '%s'). Download process has failed as well. No nodes has been found.", name, filename);
}
// downloader for graph
auto download = [&] () -> bool {
auto toDownload = strings.format ("%sgraph/%s", getDataDirectory (false), filename.chars ());
auto fromDownload = strings.format ("%s/graph/%s", yb_graph_url.str (), filename.chars ());
auto toDownload = strings.format ("%sgraph/%s", getDataDirectory (false), filename);
auto fromDownload = strings.format ("%s/graph/%s", cv_graph_url.str (), filename);
// try to download
if (http.downloadFile (fromDownload, toDownload)) {
game.print ("%s file '%s' successfully downloaded. Processing...", name.chars (), filename.chars ());
game.print ("%s file '%s' successfully downloaded. Processing...", name, filename);
return true;
}
else {
game.print ("Can't download '%s'. from '%s' to '%s'... (%d).", filename.chars (), fromDownload, toDownload, http.getLastStatusCode ());
game.print ("Can't download '%s'. from '%s' to '%s'... (%d).", filename, fromDownload, toDownload, http.getLastStatusCode ());
}
return false;
};
@ -1628,11 +1622,11 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
if (tryReload ()) {
return true;
}
return bailout ("Unable to open %s file for reading (filename: '%s').", name.chars (), filename.chars ());
return raiseLoadingError (isGraph, file, "Unable to open %s file for reading (filename: '%s').", name, filename);
}
// read the header
StorageHeader hdr;
StorageHeader hdr {};
file.read (&hdr, sizeof (StorageHeader));
// check the magic
@ -1640,12 +1634,12 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
if (tryReload ()) {
return true;
}
return bailout ("Unable to read magic of %s (filename: '%s').", name.chars (), filename.chars ());
return raiseLoadingError (isGraph, file, "Unable to read magic of %s (filename: '%s').", name, filename);
}
// check the path-numbers
if (!isGraph && hdr.length != length ()) {
return bailout ("Damaged %s (filename: '%s'). Mismatch number of nodes (got: '%d', need: '%d').", name.chars (), filename.chars (), hdr.length, m_paths.length ());
return raiseLoadingError (isGraph, file, "Damaged %s (filename: '%s'). Mismatch number of nodes (got: '%d', need: '%d').", name, filename, hdr.length, m_paths.length ());
}
// check the count
@ -1653,7 +1647,7 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
if (tryReload ()) {
return true;
}
return bailout ("Damaged %s (filename: '%s'). Paths length is overflowed (got: '%d').", name.chars (), filename.chars (), hdr.length);
return raiseLoadingError (isGraph, file, "Damaged %s (filename: '%s'). Paths length is overflowed (got: '%d').", name, filename, hdr.length);
}
// check the version
@ -1661,12 +1655,12 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
if (tryReload ()) {
return true;
}
return bailout ("Damaged %s (filename: '%s'). Version number differs (got: '%d', need: '%d').", name.chars (), filename.chars (), hdr.version, version);
return raiseLoadingError (isGraph, file, "Damaged %s (filename: '%s'). Version number differs (got: '%d', need: '%d').", name, filename, hdr.version, version);
}
// check the storage type
if ((hdr.options & options) != options) {
return bailout ("Incorrect storage format for %s (filename: '%s').", name.chars (), filename.chars ());
return raiseLoadingError (isGraph, file, "Incorrect storage format for %s (filename: '%s').", name, filename);
}
SmallArray <uint8> compressed (hdr.compressed + sizeof (uint8) * ULZ::Excess);
@ -1681,7 +1675,7 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
// try to uncompress
if (lz.uncompress (compressed.data (), hdr.compressed, reinterpret_cast <uint8 *> (data.data ()), hdr.uncompressed) == ULZ::UncompressFailure) {
return bailout ("Unable to decompress ULZ data for %s (filename: '%s').", name.chars (), filename.chars ());
return raiseLoadingError (isGraph, file, "Unable to decompress ULZ data for %s (filename: '%s').", name, filename);
}
else {
@ -1693,16 +1687,15 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
if ((hdr.options & StorageOption::Exten) && exten != nullptr) {
file.read (exten, sizeof (ExtenHeader));
}
game.print ("Successfully loaded Bots %s data (%d/%.2fMB).", name.chars (), data.length (), static_cast <float> (data.capacity () * sizeof (U)) / 1024.0f / 1024.0f);
game.print ("Successfully loaded Bots %s data (%d/%.2fMB).", name, m_paths.length (), static_cast <float> (data.capacity () * sizeof (U)) / 1024.0f / 1024.0f);
file.close ();
return true;
}
}
else {
return bailout ("Unable to read ULZ data for %s (filename: '%s').", name.chars (), filename.chars ());
return raiseLoadingError (isGraph, file, "Unable to read ULZ data for %s (filename: '%s').", name, filename);
}
return false;
}
bool BotGraph::loadGraphData () {
@ -1727,7 +1720,7 @@ bool BotGraph::loadGraphData () {
m_tempStrings.assign ("Using Official Navigation Graph");
}
else {
m_tempStrings.assignf ("Navigation Graph Authord By: %s", exten.author);
m_tempStrings.assignf ("Navigation Graph Authored By: %s", exten.author);
}
initNodesTypes ();
loadPathMatrix ();
@ -1741,8 +1734,8 @@ bool BotGraph::loadGraphData () {
game.print ("Warning: Graph data is probably not for this map. Please check bots behaviour.");
}
}
extern ConVar yb_debug_goal;
yb_debug_goal.set (kInvalidNodeIndex);
extern ConVar cv_debug_goal;
cv_debug_goal.set (kInvalidNodeIndex);
return true;
}
@ -1786,7 +1779,7 @@ void BotGraph::saveOldFormat () {
header.mapName[31] = 0;
header.fileVersion = StorageVersion::Podbot;
header.pointNumber = m_paths.length ();
header.pointNumber = length ();
File fp;
@ -1846,7 +1839,7 @@ bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) {
game.testLine (src, destination, TraceIgnore::Monsters, m_editor, &tr);
// if node is visible from current position (even behind head)...
if (tr.flFraction >= 1.0f || (tr.pHit && strncmp ("func_door", tr.pHit->v.classname.chars (), 9) == 0)) {
if (tr.pHit && (tr.flFraction >= 1.0f || strncmp ("func_door", tr.pHit->v.classname.chars (), 9) == 0)) {
// if it's a door check if nothing blocks behind
if (strncmp ("func_door", tr.pHit->v.classname.chars (), 9) == 0) {
game.testLine (tr.vecEndPos, destination, TraceIgnore::Monsters, tr.pHit, &tr);
@ -2125,40 +2118,40 @@ void BotGraph::frame () {
float nodeHalfHeight = nodeHeight * 0.5f;
// all nodes are by default are green
Color nodeColor = Color (-1, -1, -1);
Color nodeColor { -1, -1, -1 };
// colorize all other nodes
if (path.flags & NodeFlag::Camp) {
nodeColor = Color (0, 255, 255);
nodeColor = { 0, 255, 255 };
}
else if (path.flags & NodeFlag::Goal) {
nodeColor = Color (128, 0, 255);
nodeColor = { 128, 0, 255 };
}
else if (path.flags & NodeFlag::Ladder) {
nodeColor = Color (128, 64, 0);
nodeColor = { 128, 64, 0 };
}
else if (path.flags & NodeFlag::Rescue) {
nodeColor = Color (255, 255, 255);
nodeColor = { 255, 255, 255 };
}
else {
nodeColor = Color (0, 255, 0);
nodeColor = { 0, 255, 0 };
}
// colorize additional flags
Color nodeFlagColor = Color (-1, -1, -1);
Color nodeFlagColor { -1, -1, -1 };
// check the colors
if (path.flags & NodeFlag::Sniper) {
nodeFlagColor = Color (130, 87, 0);
nodeFlagColor = { 130, 87, 0 };
}
else if (path.flags & NodeFlag::NoHostage) {
nodeFlagColor = Color (255, 255, 255);
nodeFlagColor = { 255, 255, 255 };
}
else if (path.flags & NodeFlag::TerroristOnly) {
nodeFlagColor = Color (255, 0, 0);
nodeFlagColor = { 255, 0, 0 };
}
else if (path.flags & NodeFlag::CTOnly) {
nodeFlagColor = Color (0, 0, 255);
nodeFlagColor = { 0, 0, 255 };
}
int nodeWidth = 14;
@ -2192,17 +2185,17 @@ void BotGraph::frame () {
// finding node - pink arrow
if (m_findWPIndex != kInvalidNodeIndex) {
game.drawLine (m_editor, m_editor->v.origin, m_paths[m_findWPIndex].origin, 10, 0, Color (128, 0, 128), 200, 0, 5, DrawLine::Arrow);
game.drawLine (m_editor, m_editor->v.origin, m_paths[m_findWPIndex].origin, 10, 0, { 128, 0, 128 }, 200, 0, 5, DrawLine::Arrow);
}
// cached node - yellow arrow
if (m_cacheNodeIndex != kInvalidNodeIndex) {
game.drawLine (m_editor, m_editor->v.origin, m_paths[m_cacheNodeIndex].origin, 10, 0, Color (255, 255, 0), 200, 0, 5, DrawLine::Arrow);
game.drawLine (m_editor, m_editor->v.origin, m_paths[m_cacheNodeIndex].origin, 10, 0, { 255, 255, 0 }, 200, 0, 5, DrawLine::Arrow);
}
// node user facing at - white arrow
if (m_facingAtIndex != kInvalidNodeIndex) {
game.drawLine (m_editor, m_editor->v.origin, m_paths[m_facingAtIndex].origin, 10, 0, Color (255, 255, 255), 200, 0, 5, DrawLine::Arrow);
game.drawLine (m_editor, m_editor->v.origin, m_paths[m_facingAtIndex].origin, 10, 0, { 255, 255, 255 }, 200, 0, 5, DrawLine::Arrow);
}
m_arrowDisplayTime = game.time ();
}
@ -2228,8 +2221,8 @@ void BotGraph::frame () {
const auto &end = path.origin + Vector (path.end.x, path.end.y, 0.0f).forward () * 500.0f; // camp end
// draw it now
game.drawLine (m_editor, source, start, 10, 0, Color (255, 0, 0), 200, 0, 10);
game.drawLine (m_editor, source, end, 10, 0, Color (255, 0, 0), 200, 0, 10);
game.drawLine (m_editor, source, start, 10, 0, { 255, 0, 0 }, 200, 0, 10);
game.drawLine (m_editor, source, end, 10, 0, { 255, 0, 0 }, 200, 0, 10);
}
// draw the connections
@ -2239,30 +2232,30 @@ void BotGraph::frame () {
}
// jump connection
if (link.flags & PathFlag::Jump) {
game.drawLine (m_editor, path.origin, m_paths[link.index].origin, 5, 0, Color (255, 0, 128), 200, 0, 10);
game.drawLine (m_editor, path.origin, m_paths[link.index].origin, 5, 0, { 255, 0, 128 }, 200, 0, 10);
}
else if (isConnected (link.index, nearestIndex)) { // twoway connection
game.drawLine (m_editor, path.origin, m_paths[link.index].origin, 5, 0, Color (255, 255, 0), 200, 0, 10);
game.drawLine (m_editor, path.origin, m_paths[link.index].origin, 5, 0, { 255, 255, 0 }, 200, 0, 10);
}
else { // oneway connection
game.drawLine (m_editor, path.origin, m_paths[link.index].origin, 5, 0, Color (250, 250, 250), 200, 0, 10);
game.drawLine (m_editor, path.origin, m_paths[link.index].origin, 5, 0, { 50, 250, 25 }, 200, 0, 10);
}
}
// now look for oneway incoming connections
for (const auto &connected : m_paths) {
if (isConnected (connected.number, path.number) && !isConnected (path.number, connected.number)) {
game.drawLine (m_editor, path.origin, connected.origin, 5, 0, Color (0, 192, 96), 200, 0, 10);
game.drawLine (m_editor, path.origin, connected.origin, 5, 0, { 0, 192, 96 }, 200, 0, 10);
}
}
// draw the radius circle
Vector origin = (path.flags & NodeFlag::Crouch) ? path.origin : path.origin - Vector (0.0f, 0.0f, 18.0f);
Color radiusColor (0, 0, 255);
Color radiusColor { 0, 0, 255 };
// if radius is nonzero, draw a full circle
if (path.radius > 0.0f) {
float sqr = cr::sqrtf (path.radius * path.radius * 0.5f);
float sqr = cr::sqrtf (cr::square (path.radius) * 0.5f);
game.drawLine (m_editor, origin + Vector (path.radius, 0.0f, 0.0f), origin + Vector (sqr, -sqr, 0.0f), 5, 0, radiusColor, 200, 0, 10);
game.drawLine (m_editor, origin + Vector (sqr, -sqr, 0.0f), origin + Vector (0.0f, -path.radius, 0.0f), 5, 0, radiusColor, 200, 0, 10);
@ -2288,11 +2281,11 @@ void BotGraph::frame () {
int dangerIndex = getDangerIndex (game.getTeam (m_editor), nearestIndex, nearestIndex);
if (exists (dangerIndex)) {
game.drawLine (m_editor, path.origin, m_paths[dangerIndex].origin, 15, 0, Color (255, 0, 0), 200, 0, 10, DrawLine::Arrow); // draw a red arrow to this index's danger point
game.drawLine (m_editor, path.origin, m_paths[dangerIndex].origin, 15, 0, { 255, 0, 0 }, 200, 0, 10, DrawLine::Arrow); // draw a red arrow to this index's danger point
}
}
auto getFlagsAsStr = [&] (int index) {
auto getFlagsAsStr = [&] (int index) -> StringRef {
const auto &path = m_paths[index];
bool jumpPoint = false;
@ -2306,19 +2299,22 @@ void BotGraph::frame () {
}
static String buffer;
buffer.assignf ("%s%s%s%s%s%s%s%s%s%s%s%s%s", (path.flags == 0 && !jumpPoint) ? " (none)" : "", (path.flags & NodeFlag::Lift) ? " LIFT" : "", (path.flags & NodeFlag::Crouch) ? " CROUCH" : "", (path.flags & NodeFlag::Camp) ? " CAMP" : "", (path.flags & NodeFlag::TerroristOnly) ? " TERRORIST" : "", (path.flags & NodeFlag::CTOnly) ? " CT" : "", (path.flags & NodeFlag::Sniper) ? " SNIPER" : "", (path.flags & NodeFlag::Goal) ? " GOAL" : "", (path.flags & NodeFlag::Ladder) ? " LADDER" : "", (path.flags & NodeFlag::Rescue) ? " RESCUE" : "", (path.flags & NodeFlag::DoubleJump) ? " JUMPHELP" : "", (path.flags & NodeFlag::NoHostage) ? " NOHOSTAGE" : "", jumpPoint ? " JUMP" : "");
buffer.assignf ("%s%s%s%s%s%s%s%s%s%s%s%s", (path.flags & NodeFlag::Lift) ? " LIFT" : "", (path.flags & NodeFlag::Crouch) ? " CROUCH" : "", (path.flags & NodeFlag::Camp) ? " CAMP" : "", (path.flags & NodeFlag::TerroristOnly) ? " TERRORIST" : "", (path.flags & NodeFlag::CTOnly) ? " CT" : "", (path.flags & NodeFlag::Sniper) ? " SNIPER" : "", (path.flags & NodeFlag::Goal) ? " GOAL" : "", (path.flags & NodeFlag::Ladder) ? " LADDER" : "", (path.flags & NodeFlag::Rescue) ? " RESCUE" : "", (path.flags & NodeFlag::DoubleJump) ? " JUMPHELP" : "", (path.flags & NodeFlag::NoHostage) ? " NOHOSTAGE" : "", jumpPoint ? " JUMP" : "");
if (buffer.empty ()) {
buffer.assign ("(none)");
}
// return the message buffer
return buffer.chars ();
return buffer;
};
auto pathOriginStr = [&] (int index) {
auto pathOriginStr = [&] (int index) -> StringRef {
const auto &path = m_paths[index];
static String buffer;
buffer.assignf ("(%.1f, %.1f, %.1f)", path.origin.x, path.origin.y, path.origin.z);
return buffer.chars ();
return buffer;
};
// display some information
@ -2692,18 +2688,18 @@ void BotGraph::eraseFromDisk () {
// if we're delete graph, delete all corresponding to it files
forErase.push (strings.format ("%s%s.pwf", data, map)); // graph itself
forErase.push (strings.format ("%slearned/%s.exp", data, map)); // corresponding to practice
forErase.push (strings.format ("%slearned/%s.vis", data, map)); // corresponding to vistable
forErase.push (strings.format ("%slearned/%s.pmx", data, map)); // corresponding to matrix
forErase.push (strings.format ("%strain/%s.exp", data, map)); // corresponding to practice
forErase.push (strings.format ("%strain/%s.vis", data, map)); // corresponding to vistable
forErase.push (strings.format ("%strain/%s.pmx", data, map)); // corresponding to matrix
forErase.push (strings.format ("%sgraph/%s.graph", data, map)); // new format graph
for (const auto &item : forErase) {
if (File::exists (item)) {
plat.removeFile (item.chars ());
game.print ("File %s, has been deleted from the hard disk", item.chars ());
game.print ("File %s, has been deleted from the hard disk", item);
}
else {
logger.error ("Unable to open %s", item.chars ());
logger.error ("Unable to open %s", item);
}
}
initGraph (); // reintialize points
@ -2715,10 +2711,10 @@ const char *BotGraph::getDataDirectory (bool isMemoryFile) {
buffer.clear ();
if (isMemoryFile) {
buffer.assign ("addons/yapb/data/");
buffer.assignf ("addons/%s/data/", product.folder);
}
else {
buffer.assignf ("%s/addons/yapb/data/", game.getModName ());
buffer.assignf ("%s/addons/%s/data/", game.getModName (), product.folder);
}
return buffer.chars ();
}
@ -2726,6 +2722,10 @@ const char *BotGraph::getDataDirectory (bool isMemoryFile) {
void BotGraph::setBombOrigin (bool reset, const Vector &pos) {
// this function stores the bomb position as a vector
if (!game.mapIs (MapFlags::Demolition) || !bots.isBombPlanted ()) {
return;
}
if (reset) {
m_bombOrigin = nullptr;
bots.setBombPlanted (false);
@ -2737,14 +2737,22 @@ void BotGraph::setBombOrigin (bool reset, const Vector &pos) {
m_bombOrigin = pos;
return;
}
bool wasFound = false;
game.searchEntities ("classname", "grenade", [&] (edict_t *ent) {
if (strcmp (ent->v.model.chars (9), "c4.mdl") == 0) {
m_bombOrigin = game.getEntityWorldOrigin (ent);
wasFound = true;
return EntitySearchResult::Break;
}
return EntitySearchResult::Continue;
});
if (!wasFound) {
m_bombOrigin = nullptr;
bots.setBombPlanted (false);
}
}
void BotGraph::startLearnJump () {
@ -2877,7 +2885,7 @@ void BotGraph::updateGlobalPractice () {
(practice + (i * length ()) + i)->index[team] = static_cast <int16> (bestIndex);
}
}
constexpr int HALF_DAMAGE_VALUE = static_cast <int> (kMaxPracticeDamageValue * 0.5);
constexpr auto kHalfDamageVal = static_cast <int> (kMaxPracticeDamageValue * 0.5);
// adjust values if overflow is about to happen
if (adjustValues) {
@ -2887,14 +2895,14 @@ void BotGraph::updateGlobalPractice () {
if (i == j) {
continue;
}
(practice + (i * length ()) + j)->damage[team] = static_cast <int16> (cr::clamp (getDangerDamage (team, i, j) - HALF_DAMAGE_VALUE, 0, kMaxPracticeDamageValue));
(practice + (i * length ()) + j)->damage[team] = static_cast <int16> (cr::clamp (getDangerDamage (team, i, j) - kHalfDamageVal, 0, kMaxPracticeDamageValue));
}
}
}
}
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
m_highestDamage[team] = cr::clamp (m_highestDamage [team] - HALF_DAMAGE_VALUE, 1, kMaxPracticeDamageValue);
m_highestDamage[team] = cr::clamp (m_highestDamage [team] - kHalfDamageVal, 1, kMaxPracticeDamageValue);
}
}
@ -2919,7 +2927,7 @@ void BotGraph::convertFromPOD (Path &path, const PODPath &pod) {
path.start = Vector (pod.csx, pod.csy, 0.0f);
path.end = Vector (pod.cex, pod.cey, 0.0f);
if (yb_graph_fixcamp.bool_ ()) {
if (cv_graph_fixcamp.bool_ ()) {
convertCampDirection (path);
}
path.radius = pod.radius;

View file

@ -1,14 +1,21 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
ConVar yb_version ("yb_version", PRODUCT_VERSION, Var::ReadOnly);
ConVar cv_version ("ub_version", strings.format ("%s.%s", product.version, product.build.count), Var::ReadOnly);
gamefuncs_t dllapi;
enginefuncs_t engfuncs;
@ -22,12 +29,12 @@ globalvars_t *globals = nullptr;
// metamod plugin information
plugin_info_t Plugin_info = {
META_INTERFACE_VERSION, // interface version
PRODUCT_SHORT_NAME, // plugin name
PRODUCT_VERSION, // plugin version
PRODUCT_DATE, // date of creation
PRODUCT_AUTHOR, // plugin author
PRODUCT_URL, // plugin URL
PRODUCT_LOGTAG, // plugin logtag
product.name.chars (), // plugin name
product.version.chars (), // plugin version
product.date.chars (), // date of creation
product.author.chars (), // plugin author
product.url.chars (), // plugin URL
product.logtag.chars (), // plugin logtag
PT_CHANGELEVEL, // when loadable
PT_ANYTIME, // when unloadable
};
@ -75,7 +82,7 @@ namespace variadic {
}
}
CR_EXPORT int GetEntityAPI2 (gamefuncs_t *table, int *) {
CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int) {
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
// be called by the engine, into a memory block pointed to by the functionTable pointer
@ -89,11 +96,11 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *table, int *) {
plat.bzero (table, sizeof (gamefuncs_t));
if (!(game.is (GameFlags::Metamod))) {
auto api_GetEntityAPI = game.lib ().resolve <int (*) (gamefuncs_t *, int)> ("GetEntityAPI");
auto api_GetEntityAPI = game.lib ().resolve <decltype (&GetEntityAPI)> (__FUNCTION__);
// pass other DLLs engine callbacks to function table...
if (!api_GetEntityAPI || api_GetEntityAPI (&dllapi, INTERFACE_VERSION) == 0) {
logger.fatal ("Could not resolve symbol \"%s\" in the game dll.", "GetEntityAPI");
logger.fatal ("Could not resolve symbol \"%s\" in the game dll.", __FUNCTION__);
}
dllfuncs.dllapi_table = &dllapi;
gpGamedllFuncs = &dllfuncs;
@ -110,14 +117,6 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *table, int *) {
// server is enabled. Here is a good place to do our own game session initialization, and
// to register by the engine side the server commands we need to administrate our bots.
// register logger
logger.initialize (strings.format ("%slogs/yapb.log", graph.getDataDirectory (false)), [] (const char *msg) {
game.print (msg);
});
// set correct version string
yb_version.set (strings.format ("%d.%d.%d", PRODUCT_VERSION_DWORD_INTERNAL, util.buildNumber ()));
// execute main config
conf.loadMainConfig ();
conf.adjustWeaponPrices ();
@ -134,8 +133,6 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *table, int *) {
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
// and any MOD is supposed to implement one for each of its entities.
game.precache ();
if (game.is (GameFlags::Metamod)) {
RETURN_META_VALUE (MRES_IGNORED, 0);
}
@ -312,8 +309,8 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *table, int *) {
// execute main config
conf.loadMainConfig ();
if (File::exists (strings.format ("%s/maps/%s_yapb.cfg", game.getModName (), game.getMapName ()))) {
game.serverCommand ("exec maps/%s_yapb.cfg", game.getMapName ());
if (File::exists (strings.format ("%s/maps/%s_%s.cfg", game.getModName (), game.getMapName (), product.folder))) {
game.serverCommand ("exec maps/%s_%s.cfg", game.getMapName (), product.folder);
game.print ("Executing Map-Specific config file");
}
bots.initQuota ();
@ -414,7 +411,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *table, int *) {
// if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false
// and SV_EmitPings will not overwrite our results
if (game.is (GameFlags::HasFakePings) && yb_show_latency.int_ () == 2) {
if (game.is (GameFlags::HasFakePings) && cv_show_latency.int_ () == 2) {
if ((cmd->buttons & IN_SCORE) || (ent->v.oldbuttons & IN_SCORE)) {
cmd->buttons &= ~IN_SCORE;
@ -442,10 +439,10 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *table, int *) {
}
dllapi.pfnPM_Move (playerMove, server);
};
return true;
return HLTrue;
}
CR_LINKAGE_C int GetEntityAPI2_Post (gamefuncs_t *table, int *) {
CR_LINKAGE_C int GetEntityAPI_Post (gamefuncs_t *table, int) {
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
// be called by the engine, into a memory block pointed to by the functionTable pointer
@ -499,7 +496,7 @@ CR_LINKAGE_C int GetEntityAPI2_Post (gamefuncs_t *table, int *) {
RETURN_META (MRES_IGNORED);
};
return true;
return HLTrue;
}
CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
@ -788,7 +785,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
table->pfnClientCommand = variadic::clientCommand;
return true;
return HLTrue;
}
CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *table, int *interfaceVersion) {
@ -798,15 +795,15 @@ CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *table, int *interfaceVersion)
// pass them too, else the DLL interfacing wouldn't be complete and the game possibly wouldn't
// run properly.
auto api_GetNewDLLFunctions = game.lib ().resolve <int (*) (newgamefuncs_t *, int *)> (__FUNCTION__);
auto api_GetNewDLLFunctions = game.lib ().resolve <decltype (&GetNewDLLFunctions)> (__FUNCTION__);
if (!api_GetNewDLLFunctions || !api_GetNewDLLFunctions (table, interfaceVersion)) {
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
return false;
return HLFalse;
}
dllfuncs.newapi_table = table;
return true;
return HLTrue;
}
CR_LINKAGE_C int GetEngineFunctions_Post (enginefuncs_t *table, int *) {
@ -835,7 +832,7 @@ CR_LINKAGE_C int GetEngineFunctions_Post (enginefuncs_t *table, int *) {
RETURN_META_VALUE (MRES_IGNORED, 0);
};
return true;
return HLTrue;
}
CR_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) {
@ -846,7 +843,7 @@ CR_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMet
gpMetaUtilFuncs = pMetaUtilFuncs;
*pPlugInfo = &Plugin_info;
return true; // tell metamod this plugin looks safe
return HLTrue; // tell metamod this plugin looks safe
}
CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) {
@ -856,10 +853,10 @@ CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, me
// metamod engine & dllapi function tables
static metamod_funcs_t metamodFunctionTable = {
nullptr, // pfnGetEntityAPI ()
nullptr, // pfnGetEntityAPI_Post ()
GetEntityAPI2, // pfnGetEntityAPI2 ()
GetEntityAPI2_Post, // pfnGetEntityAPI2_Post ()
GetEntityAPI, // pfnGetEntityAPI ()
GetEntityAPI_Post, // pfnGetEntityAPI_Post ()
nullptr, // pfnGetEntityAPI2 ()
nullptr, // pfnGetEntityAPI2_Post ()
nullptr, // pfnGetNewDLLFunctions ()
nullptr, // pfnGetNewDLLFunctions_Post ()
GetEngineFunctions, // pfnGetEngineFunctions ()
@ -868,7 +865,7 @@ CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, me
if (now > Plugin_info.loadable) {
logger.error ("%s: plugin NOT attaching (can't load plugin right now)", Plugin_info.name);
return false; // returning FALSE prevents metamod from attaching this plugin
return HLFalse; // returning FALSE prevents metamod from attaching this plugin
}
// keep track of the pointers to engine function tables metamod gives us
@ -876,7 +873,7 @@ CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, me
memcpy (functionTable, &metamodFunctionTable, sizeof (metamod_funcs_t));
gpGamedllFuncs = pGamedllFuncs;
return true; // returning true enables metamod to attach this plugin
return HLTrue; // returning true enables metamod to attach this plugin
}
CR_EXPORT int Meta_Detach (PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
@ -885,7 +882,7 @@ CR_EXPORT int Meta_Detach (PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
if (now > Plugin_info.unloadable && reason != PNL_CMD_FORCED) {
logger.error ("%s: plugin NOT detaching (can't unload plugin right now)", Plugin_info.name);
return false; // returning FALSE prevents metamod from unloading this plugin
return HLFalse; // returning FALSE prevents metamod from unloading this plugin
}
bots.kickEveryone (true); // kick all bots off this server
@ -896,7 +893,7 @@ CR_EXPORT int Meta_Detach (PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
// make sure all stuff cleared
bots.destroy ();
return true;
return HLTrue;
}
CR_EXPORT void Meta_Init () {
@ -908,7 +905,7 @@ CR_EXPORT void Meta_Init () {
// games GiveFnptrsToDll is a bit tricky
#if defined(CR_WINDOWS)
# if defined(CR_CXX_MSVC) || defined (CR_CXX_MSVC)
# if defined(CR_CXX_MSVC) || defined (CR_CXX_CLANG)
# if defined (CR_ARCH_X86)
# pragma comment(linker, "/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1")
# endif
@ -916,14 +913,14 @@ CR_EXPORT void Meta_Init () {
# endif
# if defined(CR_CXX_MSVC) && !defined(CR_ARCH_X64)
# define DLL_GIVEFNPTRSTODLL CR_LINKAGE_C void CR_STDCALL
# elif defined(CR_CXX_CLANG) || defined(CR_ARCH_X64)
# elif defined(CR_CXX_CLANG) || defined(CR_CXX_GCC) || defined(CR_ARCH_X64)
# define DLL_GIVEFNPTRSTODLL CR_EXPORT void CR_STDCALL
# endif
#elif defined(CR_LINUX) || defined (CR_OSX) || defined (CR_ANDROID)
# define DLL_GIVEFNPTRSTODLL CR_EXPORT void
#endif
DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t *pGlobals) {
DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t *glob) {
// this is the very first function that is called in the game DLL by the game. Its purpose
// is to set the functions interfacing up, by exchanging the functionTable function list
// along with a pointer to the engine's global variables structure pGlobals, with the game
@ -937,12 +934,12 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t
// get the engine functions from the game...
memcpy (&engfuncs, functionTable, sizeof (enginefuncs_t));
globals = pGlobals;
globals = glob;
if (game.postload ()) {
return;
}
auto api_GiveFnptrsToDll = game.lib ().resolve <void (CR_STDCALL *) (enginefuncs_t *, globalvars_t *)> (__FUNCTION__);
auto api_GiveFnptrsToDll = game.lib ().resolve <decltype (&GiveFnptrsToDll)> (__FUNCTION__);
if (!api_GiveFnptrsToDll) {
logger.fatal ("Could not resolve symbol \"%s\" in the game dll.", __FUNCTION__);
@ -953,9 +950,7 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t
ents.initialize ();
// give the engine functions to the other DLL...
if (api_GiveFnptrsToDll) {
api_GiveFnptrsToDll (functionTable, pGlobals);
}
api_GiveFnptrsToDll (functionTable, glob);
}
// add linkents for android

View file

@ -1,40 +1,47 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
ConVar yb_autovacate ("yb_autovacate", "1", "Kick bots to automatically make room for human players.");
ConVar yb_bind_menu_key ("yb_bind_menu_key", "=", "Bind's specified key for openining bots menu.", false);
ConVar cv_autovacate ("ub_autovacate", "1", "Kick bots to automatically make room for human players.");
ConVar cv_bind_menu_key ("ub_bind_menu_key", "=", "Bind's specified key for opening bots menu.", false);
ConVar yb_quota ("yb_quota", "0", "Specifies the number bots to be added to the game.", true, 0.0f, static_cast <float> (kGameMaxPlayers));
ConVar yb_quota_mode ("yb_quota_mode", "normal", "Specifies the type of quota.\nAllowed values: 'normal', 'fill', and 'match'.\nIf 'fill', the server will adjust bots to keep N players in the game, where N is yb_quota.\nIf 'match', the server will maintain a 1:N ratio of humans to bots, where N is yb_quota_match.", false);
ConVar yb_quota_match ("yb_quota_match", "0", "Number of players to match if yb_quota_mode set to 'match'", true, 0.0f, static_cast <float> (kGameMaxPlayers));
ConVar yb_think_fps ("yb_think_fps", "30.0", "Specifies hou many times per second bot code will run.", true, 30.0f, 90.0f);
ConVar yb_autokill_delay ("yb_autokill_delay", "0.0", "Specifies amount of time in seconds when bots will be killed if no humans left alive.", true, 0.0f, 90.0f);
ConVar cv_quota ("ub_quota", "0", "Specifies the number bots to be added to the game.", true, 0.0f, static_cast <float> (kGameMaxPlayers));
ConVar cv_quota_mode ("ub_quota_mode", "normal", "Specifies the type of quota.\nAllowed values: 'normal', 'fill', and 'match'.\nIf 'fill', the server will adjust bots to keep N players in the game, where N is ub_quota.\nIf 'match', the server will maintain a 1:N ratio of humans to bots, where N is ub_quota_match.", false);
ConVar cv_quota_match ("ub_quota_match", "0", "Number of players to match if ub_quota_mode set to 'match'", true, 0.0f, static_cast <float> (kGameMaxPlayers));
ConVar cv_think_fps ("ub_think_fps", "30.0", "Specifies how many times per second bot code will run.", true, 30.0f, 90.0f);
ConVar cv_autokill_delay ("ub_autokill_delay", "0.0", "Specifies amount of time in seconds when bots will be killed if no humans left alive.", true, 0.0f, 90.0f);
ConVar yb_join_after_player ("yb_join_after_player", "0", "Sepcifies whether bots should join server, only when at least one human player in game.");
ConVar yb_join_team ("yb_join_team", "any", "Forces all bots to join team specified here.", false);
ConVar yb_join_delay ("yb_join_delay", "5.0", "Specifies after how many seconds bots should start to join the game after the changelevel.", true, 0.0f, 30.0f);
ConVar cv_join_after_player ("ub_join_after_player", "0", "Specifies whether bots should join server, only when at least one human player in game.");
ConVar cv_join_team ("ub_join_team", "any", "Forces all bots to join team specified here.", false);
ConVar cv_join_delay ("ub_join_delay", "5.0", "Specifies after how many seconds bots should start to join the game after the changelevel.", true, 0.0f, 30.0f);
ConVar yb_name_prefix ("yb_name_prefix", "", "All the bot names will be prefixed with string specified with this cvar.", false);
ConVar yb_difficulty ("yb_difficulty", "4", "All bots difficulty level. Chaning at runtime will affect already created bots.", true, 0.0f, 4.0f);
ConVar cv_name_prefix ("ub_name_prefix", "", "All the bot names will be prefixed with string specified with this cvar.", false);
ConVar cv_difficulty ("ub_difficulty", "4", "All bots difficulty level. Changing at runtime will affect already created bots.", true, 0.0f, 4.0f);
ConVar yb_show_avatars ("yb_show_avatars", "1", "Enables or disabels displaying bot avatars in front of their names in scoreboard. Note, that is currently you can see only avatars of your steam friends.");
ConVar yb_show_latency ("yb_show_latency", "2", "Enables latency display in scoreboard.\nAllowed values: '0', '1', '2'.\nIf '0', there is nothing displayed.\nIf '1', there is a 'BOT' is displayed.\nIf '2' fake ping is displayed.", true, 0.0f, 2.0f);
ConVar cv_show_avatars ("ub_show_avatars", "1", "Enables or disabels displaying bot avatars in front of their names in scoreboard. Note, that is currently you can see only avatars of your steam friends.");
ConVar cv_show_latency ("ub_show_latency", "2", "Enables latency display in scoreboard.\nAllowed values: '0', '1', '2'.\nIf '0', there is nothing displayed.\nIf '1', there is a 'BOT' is displayed.\nIf '2' fake ping is displayed.", true, 0.0f, 2.0f);
ConVar yb_language ("yb_language", "en", "Specifies the language for bot messages and menus.", false);
ConVar yb_ignore_cvars_on_changelevel ("yb_ignore_cvars_on_changelevel", "yb_quota,yb_autovacate", "Specifies comma separated list of bot cvars, that will not be overriten by config on changelevel.", false);
ConVar cv_language ("ub_language", "en", "Specifies the language for bot messages and menus.", false);
ConVar cv_ignore_cvars_on_changelevel ("ub_ignore_cvars_on_changelevel", "ub_quota,ub_autovacate", "Specifies comma separated list of bot cvars, that will not be overriten by config on changelevel.", false);
ConVar mp_limitteams ("mp_limitteams", nullptr, Var::NoRegister);
ConVar mp_autoteambalance ("mp_autoteambalance", nullptr, Var::NoRegister);
ConVar mp_roundtime ("mp_roundtime", nullptr, Var::NoRegister);
ConVar mp_timelimit ("mp_timelimit", nullptr, Var::NoRegister);
ConVar mp_freezetime ("mp_freezetime", nullptr, Var::NoRegister, true, "0");
ConVar mp_limitteams ("mp_limitteams", nullptr, Var::GameRef);
ConVar mp_autoteambalance ("mp_autoteambalance", nullptr, Var::GameRef);
ConVar mp_roundtime ("mp_roundtime", nullptr, Var::GameRef);
ConVar mp_timelimit ("mp_timelimit", nullptr, Var::GameRef);
ConVar mp_freezetime ("mp_freezetime", nullptr, Var::GameRef, true, "0");
BotManager::BotManager () {
// this is a bot manager class constructor
@ -113,20 +120,20 @@ void BotManager::touchKillerEntity (Bot *bot) {
kv.szClassName = const_cast <char *> (prop.classname.chars ());
kv.szKeyName = "damagetype";
kv.szValue = const_cast <char *> (strings.format ("%d", cr::bit (4)));
kv.fHandled = false;
kv.fHandled = HLFalse;
MDLL_KeyValue (m_killerEntity, &kv);
MDLL_Touch (m_killerEntity, bot->ent ());
}
void BotManager::execGameEntity (entvars_t *vars) {
void BotManager::execGameEntity (edict_t *ent) {
// this function calls gamedll player() function, in case to create player entity in game
if (game.is (GameFlags::Metamod)) {
CALL_GAME_ENTITY (PLID, "player", vars);
CALL_GAME_ENTITY (PLID, "player", &ent->v);
return;
}
ents.getPlayerFunction () (vars);
ents.callPlayerFunction (ent);
}
void BotManager::forEach (ForEachBot handler) {
@ -137,7 +144,7 @@ void BotManager::forEach (ForEachBot handler) {
}
}
BotCreateResult BotManager::create (const String &name, int difficulty, int personality, int team, int member) {
BotCreateResult BotManager::create (StringRef name, int difficulty, int personality, int team, int member) {
// this function completely prepares bot entity (edict) for creation, creates team, difficulty, sets named etc, and
// then sends result to bot constructor
@ -160,11 +167,11 @@ BotCreateResult BotManager::create (const String &name, int difficulty, int pers
return BotCreateResult::TeamStacked;
}
if (difficulty < 0 || difficulty > 4) {
difficulty = yb_difficulty.int_ ();
difficulty = cv_difficulty.int_ ();
if (difficulty < 0 || difficulty > 4) {
difficulty = rg.int_ (3, 4);
yb_difficulty.set (difficulty);
cv_difficulty.set (difficulty);
}
}
@ -199,9 +206,9 @@ BotCreateResult BotManager::create (const String &name, int difficulty, int pers
resultName = name;
}
if (!strings.isEmpty (yb_name_prefix.str ())) {
if (!strings.isEmpty (cv_name_prefix.str ())) {
String prefixed; // temp buffer for storing modified name
prefixed.assignf ("%s %s", yb_name_prefix.str (), resultName.chars ());
prefixed.assignf ("%s %s", cv_name_prefix.str (), resultName);
// buffer has been modified, copy to real name
resultName = cr::move (prefixed);
@ -264,16 +271,9 @@ void BotManager::frame () {
for (const auto &bot : m_bots) {
bot->frame ();
}
// select leader each team somewhere in round start
if (m_timeRoundStart + 5.0f > game.time () && m_timeRoundStart + 10.0f < game.time ()) {
for (int team = 0; team < kGameTeamNum; ++team) {
selectLeaders (team, false);
}
}
}
void BotManager::addbot (const String &name, int difficulty, int personality, int team, int member, bool manual) {
void BotManager::addbot (StringRef name, int difficulty, int personality, int team, int member, bool manual) {
// this function putting bot creation process to queue to prevent engine crashes
BotRequest request {};
@ -290,13 +290,13 @@ void BotManager::addbot (const String &name, int difficulty, int personality, in
m_addRequests.push (cr::move (request));
}
void BotManager::addbot (const String &name, const String &difficulty, const String &personality, const String &team, const String &member, bool manual) {
void BotManager::addbot (StringRef name, StringRef difficulty, StringRef personality, StringRef team, StringRef member, bool manual) {
// this function is same as the function above, but accept as parameters string instead of integers
BotRequest request {};
const String &any = "*";
StringRef any = "*";
request.name = (name.empty () || name == any) ? String ("\0") : name;
request.name = (name.empty () || name == any) ? StringRef ("\0") : name;
request.difficulty = (difficulty.empty () || difficulty == any) ? -1 : difficulty.int_ ();
request.team = (team.empty () || team == any) ? -1 : team.int_ ();
request.member = (member.empty () || member == any) ? -1 : member.int_ ();
@ -311,10 +311,10 @@ void BotManager::maintainQuota () {
// while creation process in process.
if (graph.length () < 1 || graph.hasChanged ()) {
if (yb_quota.int_ () > 0) {
if (cv_quota.int_ () > 0) {
ctrl.msg ("There is no graph found. Cannot create bot.");
}
yb_quota.set (0);
cv_quota.set (0);
return;
}
@ -324,23 +324,23 @@ void BotManager::maintainQuota () {
const BotCreateResult callResult = create (last.name, last.difficulty, last.personality, last.team, last.member);
if (last.manual) {
yb_quota.set (yb_quota.int_ () + 1);
cv_quota.set (cv_quota.int_ () + 1);
}
// check the result of creation
if (callResult == BotCreateResult::GraphError) {
m_addRequests.clear (); // something wrong with graph, reset tab of creation
yb_quota.set (0); // reset quota
cv_quota.set (0); // reset quota
}
else if (callResult == BotCreateResult::MaxPlayersReached) {
m_addRequests.clear (); // maximum players reached, so set quota to maximum players
yb_quota.set (getBotCount ());
cv_quota.set (getBotCount ());
}
else if (callResult == BotCreateResult::TeamStacked) {
ctrl.msg ("Could not add bot to the game: Team is stacked (to disable this check, set mp_limitteams and mp_autoteambalance to zero and restart the round)");
m_addRequests.clear ();
yb_quota.set (getBotCount ());
cv_quota.set (getBotCount ());
}
m_maintainTime = game.time () + 0.10f;
}
@ -349,7 +349,7 @@ void BotManager::maintainQuota () {
if (m_quotaMaintainTime > game.time ()) {
return;
}
yb_quota.set (cr::clamp <int> (yb_quota.int_ (), 0, game.maxClients ()));
cv_quota.set (cr::clamp <int> (cv_quota.int_ (), 0, game.maxClients ()));
int totalHumansInGame = getHumansCount ();
int humanPlayersInGame = getHumansCount (true);
@ -358,24 +358,24 @@ void BotManager::maintainQuota () {
return;
}
int desiredBotCount = yb_quota.int_ ();
int desiredBotCount = cv_quota.int_ ();
int botsInGame = getBotCount ();
if (strings.matches (yb_quota_mode.str (), "fill")) {
if (strings.matches (cv_quota_mode.str (), "fill")) {
botsInGame += humanPlayersInGame;
}
else if (strings.matches (yb_quota_mode.str (), "match")) {
int detectQuotaMatch = yb_quota_match.int_ () == 0 ? yb_quota.int_ () : yb_quota_match.int_ ();
else if (strings.matches (cv_quota_mode.str (), "match")) {
int detectQuotaMatch = cv_quota_match.int_ () == 0 ? cv_quota.int_ () : cv_quota_match.int_ ();
desiredBotCount = cr::max <int> (0, detectQuotaMatch * humanPlayersInGame);
}
if (yb_join_after_player.bool_ () && humanPlayersInGame == 0) {
if (cv_join_after_player.bool_ () && humanPlayersInGame == 0) {
desiredBotCount = 0;
}
int maxClients = game.maxClients ();
if (yb_autovacate.bool_ ()) {
if (cv_autovacate.bool_ ()) {
desiredBotCount = cr::min <int> (desiredBotCount, maxClients - (humanPlayersInGame + 1));
}
else {
@ -413,8 +413,18 @@ void BotManager::maintainQuota () {
m_quotaMaintainTime = game.time () + 0.40f;
}
void BotManager::maintainLeaders () {
// select leader each team somewhere in round start
if (m_timeRoundStart + 5.0f > game.time () && m_timeRoundStart + 10.0f < game.time ()) {
for (int team = 0; team < kGameTeamNum; ++team) {
selectLeaders (team, false);
}
}
}
void BotManager::maintainAutoKill () {
const float killDelay = yb_autokill_delay.float_ ();
const float killDelay = cv_autokill_delay.float_ ();
if (killDelay < 1.0f || m_roundOver) {
return;
@ -506,15 +516,15 @@ void BotManager::resetFilters () {
void BotManager::decrementQuota (int by) {
if (by != 0) {
yb_quota.set (cr::clamp <int> (yb_quota.int_ () - by, 0, yb_quota.int_ ()));
cv_quota.set (cr::clamp <int> (cv_quota.int_ () - by, 0, cv_quota.int_ ()));
return;
}
yb_quota.set (0);
cv_quota.set (0);
}
void BotManager::initQuota () {
m_maintainTime = game.time () + yb_join_delay.float_ ();
m_quotaMaintainTime = game.time () + yb_join_delay.float_ ();
m_maintainTime = game.time () + cv_join_delay.float_ ();
m_quotaMaintainTime = game.time () + cv_join_delay.float_ ();
m_addRequests.clear ();
}
@ -523,7 +533,7 @@ void BotManager::serverFill (int selection, int personality, int difficulty, int
// this function fill server with bots, with specified team & personality
// always keep one slot
int maxClients = yb_autovacate.bool_ () ? game.maxClients () - 1 - (game.isDedicated () ? 0 : getHumansCount ()) : game.maxClients ();
int maxClients = cv_autovacate.bool_ () ? game.maxClients () - 1 - (game.isDedicated () ? 0 : getHumansCount ()) : game.maxClients ();
if (getBotCount () >= maxClients - getHumansCount ()) {
return;
@ -546,9 +556,9 @@ void BotManager::serverFill (int selection, int personality, int difficulty, int
}
void BotManager::kickEveryone (bool instant, bool zeroQuota) {
// this function drops all bot clients from server (this function removes only yapb's)`q
// this function drops all bot clients from server (this function removes only yapb's)
if (yb_quota.bool_ ()) {
if (cv_quota.bool_ ()) {
ctrl.msg ("Bots are removed from server.");
}
@ -672,7 +682,7 @@ bool BotManager::kickRandom (bool decQuota, Team fromTeam) {
m_lastWinner = winner;
m_roundOver = true;
if (yb_radio_mode.int_ () != 2) {
if (cv_radio_mode.int_ () != 2) {
return;
}
auto notify = findAliveBot ();
@ -723,7 +733,7 @@ void BotManager::setWeaponMode (int selection) {
tab[i].teamStandard = std[selection][i];
tab[i].teamAS = as[selection][i];
}
yb_jasonmode.set (selection == 0 ? 1 : 0);
cv_jasonmode.set (selection == 0 ? 1 : 0);
ctrl.msg ("%s weapon mode selected.", &modes[selection][0]);
}
@ -739,17 +749,11 @@ void BotManager::listBots () {
ctrl.msg ("%d bots", m_bots.length ());
}
int BotManager::getBotCount () {
// this function returns number of yapb's playing on the server
return m_bots.length ();
}
float BotManager::getConnectionTime (int botId) {
float BotManager::getConnectTime (int botId, float original) {
// this function get's fake bot player time.
for (const auto &bot : m_bots) {
if (bot->index () == botId) {
if (bot->entindex () == botId) {
auto current = plat.seconds ();
if (current - bot->m_joinServerTime > bot->m_playServerTime || current - bot->m_joinServerTime <= 0.0f) {
@ -759,7 +763,7 @@ float BotManager::getConnectionTime (int botId) {
return current - bot->m_joinServerTime;
}
}
return 0.0f;
return original;
}
Twin <int, int> BotManager::countTeamPlayers () {
@ -799,9 +803,9 @@ void BotManager::updateTeamEconomics (int team, bool setTrue) {
// that have not enough money to buy primary (with economics), and if this result higher 80%, player is can't
// buy primary weapons.
extern ConVar yb_economics_rounds;
extern ConVar cv_economics_rounds;
if (setTrue || !yb_economics_rounds.bool_ ()) {
if (setTrue || !cv_economics_rounds.bool_ ()) {
m_economicsGood[team] = true;
return; // don't check economics while economics disable
}
@ -836,7 +840,7 @@ void BotManager::updateTeamEconomics (int team, bool setTrue) {
}
void BotManager::updateBotDifficulties () {
int difficulty = yb_difficulty.int_ ();
int difficulty = cv_difficulty.int_ ();
if (difficulty != m_lastDifficulty) {
@ -872,20 +876,19 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) {
bot->v.frags = 0;
// create the player entity by calling MOD's player function
bots.execGameEntity (&bot->v);
bots.execGameEntity (bot);
// set all info buffer keys for this bot
auto buffer = engfuncs.pfnGetInfoKeyBuffer (bot);
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "_vgui_menus", "0");
if (!game.is (GameFlags::Legacy)) {
if (yb_show_latency.int_ () == 1) {
if (cv_show_latency.int_ () == 1) {
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*bot", "1");
}
auto avatar = conf.getRandomAvatar ();
if (yb_show_avatars.bool_ () && !avatar.empty ()) {
if (cv_show_avatars.bool_ () && !avatar.empty ()) {
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*sid", avatar.chars ());
}
}
@ -1041,7 +1044,7 @@ void BotManager::handleDeath (edict_t *killer, edict_t *victim) {
auto killerTeam = game.getTeam (killer);
auto victimTeam = game.getTeam (victim);
if (yb_radio_mode.int_ () == 2) {
if (cv_radio_mode.int_ () == 2) {
// need to send congrats on well placed shot
for (const auto &notify : bots) {
if (notify->m_notKilled && killerTeam == notify->m_team && killerTeam != victimTeam && killer != notify->ent () && notify->seesEntity (victim->v.origin)) {
@ -1095,8 +1098,6 @@ void BotManager::handleDeath (edict_t *killer, edict_t *victim) {
void Bot::newRound () {
// this function initializes a bot after creation & at the start of each round
int i = 0;
// delete all allocated path nodes
clearSearchNodes ();
clearRoute ();
@ -1121,11 +1122,11 @@ void Bot::newRound () {
m_numFriendsLeft = 0;
m_numEnemiesLeft = 0;
m_oldButtons = pev->button;
m_rechoiceGoalCount = 0;
for (i = 0; i < 5; ++i) {
m_previousNodes[i] = kInvalidNodeIndex;
for (auto &node : m_previousNodes) {
node = kInvalidNodeIndex;
}
m_navTimeset = game.time ();
m_team = game.getTeam (ent ());
m_isVIP = false;
@ -1218,9 +1219,10 @@ void Bot::newRound () {
m_hostages.clear ();
for (i = 0; i < Chatter::Count; ++i) {
m_chatterTimes[i] = kMaxChatterRepeatInteval;
for (auto &timer : m_chatterTimes) {
timer = kMaxChatterRepeatInteval;
}
m_isReloading = false;
m_reloadState = Reload::None;
@ -1238,7 +1240,6 @@ void Bot::newRound () {
m_blindButton = 0;
m_blindTime = 0.0f;
m_jumpTime = 0.0f;
m_jumpStateTimer = 0.0f;
m_jumpFinished = false;
m_isStuck = false;
@ -1298,20 +1299,30 @@ void Bot::newRound () {
m_heardSoundTime = game.time ();
// clear its message queue
for (i = 0; i < 32; ++i) {
m_messageQueue[i] = BotMsg::None;
for (auto &msg : m_messageQueue) {
msg = BotMsg::None;
}
m_actMessageIndex = 0;
m_pushMessageIndex = 0;
// clear last trace
for (auto i = 0; i < TraceChannel::Num; ++i) {
m_lastTrace[i] = {};
m_traceSkip[i] = 0;
}
// and put buying into its message queue
pushMsgQueue (BotMsg::Buy);
startTask (Task::Normal, TaskPri::Normal, kInvalidNodeIndex, 0.0f, true);
// restore fake client bit, just in case
pev->flags |= FL_FAKECLIENT;
if (rg.chance (50)) {
pushChatterMessage (Chatter::NewRound);
}
m_updateInterval = game.is (GameFlags::Legacy | GameFlags::Xash3D) ? 0.0f : (1.0f / cr::clamp (yb_think_fps.float_ (), 30.0f, 60.0f));
m_updateInterval = game.is (GameFlags::Legacy | GameFlags::Xash3D) ? 0.0f : (1.0f / cr::clamp (cv_think_fps.float_ (), 30.0f, 60.0f));
}
void Bot::kill () {
@ -1324,10 +1335,11 @@ void Bot::kill () {
void Bot::kick () {
// this function kick off one bot from the server.
auto username = pev->netname.chars ();
if (!(pev->flags & FL_FAKECLIENT) || strings.isEmpty (username)) {
if (!(pev->flags & FL_CLIENT) || strings.isEmpty (username)) {
return;
}
// clear fakeclient bit
pev->flags &= ~FL_FAKECLIENT;
@ -1371,7 +1383,7 @@ void Bot::updateTeamJoin () {
if (m_startAction == BotMsg::TeamSelect) {
m_startAction = BotMsg::None; // switch back to idle
char teamJoin = yb_join_team.str ()[0];
char teamJoin = cv_join_team.str ()[0];
if (teamJoin == 'C' || teamJoin == 'c') {
m_wantedTeam = 2;
@ -1494,13 +1506,10 @@ void BotManager::updateActiveGrenade () {
// search the map for any type of grenade
game.searchEntities ("classname", "grenade", [&] (edict_t *e) {
// do not count c4 as a grenade
if (strcmp (e->v.model.chars (9), "c4.mdl") == 0) {
return EntitySearchResult::Continue;
if (strcmp (e->v.model.chars (9), "c4.mdl") != 0) {
m_activeGrenades.push (e);
}
m_activeGrenades.push (e);
// continue iteration
return EntitySearchResult::Continue;
return EntitySearchResult::Continue; // continue iteration
});
m_grenadeUpdateTime = game.time () + 0.25f;
}
@ -1516,9 +1525,9 @@ void BotManager::updateIntrestingEntities () {
// search the map for any type of grenade
game.searchEntities (nullptr, kInfiniteDistance, [&] (edict_t *e) {
auto classname = e->v.classname.chars ();
// search for grenades, weaponboxes, weapons, items and armoury entities
if (strncmp ("weapon", classname, 6) == 0 || strncmp ("grenade", classname, 7) == 0 || strncmp ("item", classname, 4) == 0 || strncmp ("armoury", classname, 7) == 0) {
if (strncmp ("weaponbox", classname, 9) == 0 || strncmp ("grenade", classname, 7) == 0 || strncmp ("item", classname, 4) == 0 || strncmp ("armoury", classname, 7) == 0) {
m_intrestingEntities.push (e);
}
@ -1590,7 +1599,7 @@ void BotManager::selectLeaders (int team, bool reset) {
// terrorist carrying a bomb needs to have some company
if (rg.chance (75)) {
if (yb_radio_mode.int_ () == 2) {
if (cv_radio_mode.int_ () == 2) {
bot->pushChatterMessage (Chatter::GoingToPlantBomb);
}
else {
@ -1689,9 +1698,10 @@ void BotManager::setBombPlanted (bool isPlanted) {
}
BotConfig::BotConfig () {
m_chat.ensure (Chat::Count);
m_chatter.ensure (Chatter::Count);
m_weaponProps.ensure (kMaxWeapons);
m_chat.resize (Chat::Count);
m_chatter.resize (Chatter::Count);
m_weaponProps.resize (kMaxWeapons);
}
void BotConfig::loadConfigs () {
@ -1704,6 +1714,7 @@ void BotConfig::loadConfigs () {
loadLanguageConfig ();
loadLogosConfig ();
loadAvatarsConfig ();
loadDifficultyConfig ();
}
void BotConfig::loadMainConfig () {
@ -1725,7 +1736,7 @@ void BotConfig::loadMainConfig () {
String line;
MemFile file;
// this is does the same as exec of engine, but not overwriting values of cvars spcified in yb_ignore_cvars_on_changelevel
// this is does the same as exec of engine, but not overwriting values of cvars spcified in cv_ignore_cvars_on_changelevel
if (util.openConfig ("yapb.cfg", "YaPB main config file is not found.", &file, false)) {
while (file.getLine (line)) {
line.trim ();
@ -1741,7 +1752,7 @@ void BotConfig::loadMainConfig () {
auto keyval = line.split (" ");
if (keyval.length () > 1) {
auto ignore = String (yb_ignore_cvars_on_changelevel.str ()).split (",");
auto ignore = String (cv_ignore_cvars_on_changelevel.str ()).split (",");
auto key = keyval[0].trim ().chars ();
auto cvar = engfuncs.pfnCVarGetPointer (key);
@ -1752,7 +1763,7 @@ void BotConfig::loadMainConfig () {
if (needsToIgnoreVar (ignore, key) && !strings.matches (value, cvar->string)) {
// preserve quota number if it's zero
if (strings.matches (cvar->name, "yb_quota") && yb_quota.int_ () <= 0) {
if (strings.matches (cvar->name, "ub_quota") && cv_quota.int_ () <= 0) {
engfuncs.pfnCvar_DirectSet (cvar, value);
continue;
}
@ -1775,13 +1786,13 @@ void BotConfig::loadMainConfig () {
firstLoad = false;
// android is abit hard to play, lower the difficulty by default
if (plat.android && yb_difficulty.int_ () > 3) {
yb_difficulty.set (3);
if (plat.android && cv_difficulty.int_ () > 3) {
cv_difficulty.set (3);
}
// bind the correct menu key for bot menu...
if (!game.isDedicated () && !strings.isEmpty (yb_bind_menu_key.str ())) {
game.serverCommand ("bind \"%s\" \"yb menu\"", yb_bind_menu_key.str ());
if (!game.isDedicated () && !strings.isEmpty (cv_bind_menu_key.str ())) {
game.serverCommand ("bind \"%s\" \"yb menu\"", cv_bind_menu_key.str ());
}
}
@ -1803,7 +1814,7 @@ void BotConfig::loadNamesConfig () {
}
// max botname is 32 characters
if (line.length () > 32) {
line[32] = '\0';
line[32] = kNullChar;
}
m_botNames.emplace (line, -1);
}
@ -1814,11 +1825,11 @@ void BotConfig::loadNamesConfig () {
void BotConfig::loadWeaponsConfig () {
setupMemoryFiles ();
auto addWeaponEntries = [] (SmallArray <WeaponInfo> &weapons, bool as, const String &name, const StringArray &data) {
auto addWeaponEntries = [] (SmallArray <WeaponInfo> &weapons, bool as, StringRef name, const StringArray &data) {
// we're have null terminator element in weapons array...
if (data.length () + 1 != weapons.length ()) {
logger.error ("%s entry in weapons config is not valid or malformed (%d/%d).", name.chars (), data.length (), weapons.length ());
logger.error ("%s entry in weapons config is not valid or malformed (%d/%d).", name, data.length (), weapons.length ());
return;
}
@ -1833,9 +1844,9 @@ void BotConfig::loadWeaponsConfig () {
}
};
auto addIntEntries = [] (SmallArray <int32> &to, const String &name, const StringArray &data) {
auto addIntEntries = [] (SmallArray <int32> &to, StringRef name, const StringArray &data) {
if (data.length () != to.length ()) {
logger.error ("%s entry in weapons config is not valid or malformed (%d/%d).", name.chars (), data.length (), to.length ());
logger.error ("%s entry in weapons config is not valid or malformed (%d/%d).", name, data.length (), to.length ());
return;
}
@ -1847,7 +1858,7 @@ void BotConfig::loadWeaponsConfig () {
MemFile file;
// weapon data initialization
if (util.openConfig ("general.cfg", "General configuration file not found. Loading defaults", &file)) {
if (util.openConfig ("weapon.cfg", "Weapon configuration file not found. Loading defaults", &file)) {
while (file.getLine (line)) {
line.trim ();
@ -1899,7 +1910,7 @@ void BotConfig::loadChatterConfig () {
MemFile file;
// chatter initialization
if (game.is (GameFlags::HasBotVoice) && yb_radio_mode.int_ () == 2 && util.openConfig ("chatter.cfg", "Couldn't open chatter system configuration", &file)) {
if (game.is (GameFlags::HasBotVoice) && cv_radio_mode.int_ () == 2 && util.openConfig ("chatter.cfg", "Couldn't open chatter system configuration", &file)) {
m_chatter.clear ();
struct EventMap {
@ -1986,13 +1997,15 @@ void BotConfig::loadChatterConfig () {
if (isCommentLine (line)) {
continue;
}
extern ConVar yb_chatter_path;
if (line.startsWith ("RewritePath")) {
yb_chatter_path.set (line.substr (11).trim ().chars ());
StringRef rewriteKey = "RewritePath";
StringRef eventKey = "Event";
if (line.startsWith (rewriteKey)) {
cv_chatter_path.set (line.substr (rewriteKey.length ()).trim ().chars ());
}
else if (line.startsWith ("Event")) {
auto items = line.substr (5).split ("=");
else if (line.startsWith (eventKey)) {
auto items = line.substr (eventKey.length ()).split ("=");
if (items.length () != 2) {
logger.error ("Error in chatter config file syntax... Please correct all errors.");
@ -2025,7 +2038,7 @@ void BotConfig::loadChatterConfig () {
file.close ();
}
else {
yb_radio_mode.set (1);
cv_radio_mode.set (1);
logger.message ("Bots chatter communication disabled.");
}
}
@ -2091,6 +2104,7 @@ void BotConfig::loadChatConfig () {
if (chat != nullptr) {
chat->push (line);
}
else {
if (line.startsWith ("@KEY")) {
@ -2124,7 +2138,7 @@ void BotConfig::loadChatConfig () {
file.close ();
}
else {
yb_chat.set (0);
cv_chat.set (0);
}
}
@ -2172,7 +2186,7 @@ void BotConfig::loadLanguageConfig () {
}
file.close ();
}
else if (strcmp (yb_language.str (), "en") != 0) {
else if (strcmp (cv_language.str (), "en") != 0) {
logger.error ("Couldn't load language configuration");
}
}
@ -2188,7 +2202,7 @@ void BotConfig::loadAvatarsConfig () {
MemFile file;
// avatars inititalization
if (util.openConfig ("avatars.cfg", "Avatars config file not found. Avatars will not display.", &file)) {
if (util.openConfig ("avatars.cfg", "Avatars config file not found. Avatars will not be displayed.", &file)) {
m_avatars.clear ();
while (file.getLine (line)) {
@ -2200,6 +2214,88 @@ void BotConfig::loadAvatarsConfig () {
}
}
void BotConfig::loadDifficultyConfig () {
setupMemoryFiles ();
String line;
MemFile file;
// initialize defaults
m_difficulty[Difficulty::Noob] = {
{ 0.8f, 1.0f }, 5, 0, 0
};
m_difficulty[Difficulty::Easy] = {
{ 0.6f, 0.8f }, 30, 10, 10
};
m_difficulty[Difficulty::Normal] = {
{ 0.4f, 0.6f }, 50, 30, 40
};
m_difficulty[Difficulty::Hard] = {
{ 0.2f, 0.4f }, 75, 60, 70
};
m_difficulty[Difficulty::Expert] = {
{ 0.1f, 0.2f }, 100, 90, 90
};
// currently, mindelay, maxdelay, headprob, seenthruprob, heardthruprob
constexpr uint32 kMaxDifficultyValues = 5;
// helper for parsing each level
auto parseLevel = [&] (int32 level, StringRef data) {
auto values = data.split <String> (",");
if (values.length () != kMaxDifficultyValues) {
logger.error ("Bad value for difficulty level #%d.", level);
return;
}
auto diff = &m_difficulty[level];
diff->reaction[0] = values[0].float_ ();
diff->reaction[1] = values[1].float_ ();
diff->headshotPct = values[2].int_ ();
diff->seenThruPct = values[3].int_ ();
diff->hearThruPct = values[4].int_ ();
};
// avatars inititalization
if (util.openConfig ("difficulty.cfg", "Difficulty config file not found. Defaults loaded.", &file)) {
while (file.getLine (line)) {
if (isCommentLine (line)) {
continue;
}
auto items = line.split ("=");
if (items.length () != 2) {
logger.error ("Error in difficulty config file syntax... Please correct all errors.");
continue;
}
auto key = items[0].trim ();
// get our keys
if (key == "Noob") {
parseLevel (Difficulty::Noob, items[1]);
}
else if (key == "Easy") {
parseLevel (Difficulty::Easy, items[1]);
}
else if (key == "Normal") {
parseLevel (Difficulty::Normal, items[1]);
}
else if (key == "Hard") {
parseLevel (Difficulty::Hard, items[1]);
}
else if (key == "Expert") {
parseLevel (Difficulty::Expert, items[1]);
}
}
}
}
void BotConfig::loadLogosConfig () {
setupMemoryFiles ();
@ -2218,7 +2314,7 @@ void BotConfig::loadLogosConfig () {
}
}
else {
m_logos = cr::move (String ("{biohaz;{graf003;{graf004;{graf005;{lambda06;{target;{hand1;{spit2;{bloodhand6;{foot_l;{foot_r").split (";"));
m_logos = cr::move (String { "{biohaz;{graf003;{graf004;{graf005;{lambda06;{target;{hand1;{spit2;{bloodhand6;{foot_l;{foot_r" }.split (";"));
}
}
@ -2230,12 +2326,12 @@ void BotConfig::setupMemoryFiles () {
};
auto wrapFreeFile = [] (void *buffer) {
return engfuncs.pfnFreeFile (buffer);
engfuncs.pfnFreeFile (buffer);
};
if (setMemoryPointers) {
MemFileStorage::get ().initizalize (wrapLoadFile, wrapFreeFile);
setMemoryPointers = true;
MemFileStorage::instance ().initizalize (wrapLoadFile, wrapFreeFile);
setMemoryPointers = false;
}
}
@ -2322,17 +2418,17 @@ WeaponInfo &BotConfig::findWeaponById (const int id) {
return m_weapons.at (0);
}
const char *BotConfig::translate (const char *input) {
const char *BotConfig::translate (StringRef input) {
// this function translate input string into needed language
if (game.isDedicated ()) {
return input;
return input.chars ();
}
static String result;
result.clear ();
if (m_language.find (input, result)) {
return result.chars ();
}
return input; // nothing found
return input.chars (); // nothing found
}

View file

@ -1,9 +1,16 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
@ -62,9 +69,11 @@ void MessageDispatcher::netMsgTextMsg () {
for (const auto &notify : bots) {
if (notify->m_notKilled) {
notify->clearSearchNodes ();
notify->clearTasks ();
if (yb_radio_mode.int_ () == 2 && rg.chance (55) && notify->m_team == Team::CT) {
// clear only camp tasks
notify->clearTask (Task::Camp);
if (cv_radio_mode.int_ () == 2 && rg.chance (55) && notify->m_team == Team::CT) {
notify->pushChatterMessage (Chatter::WhereIsTheC4);
}
}
@ -170,6 +179,9 @@ void MessageDispatcher::netMsgCurWeapon () {
void MessageDispatcher::netMsgAmmoX () {
// this message is sent whenever ammo amounts are adjusted (up or down). NOTE: Logging reveals that CS uses it very unreliable!
#if 1
netMsgAmmoPickup ();
#else
enum args { index = 0, value = 1, min = 2 };
// check the minimum states
@ -177,6 +189,7 @@ void MessageDispatcher::netMsgAmmoX () {
return;
}
m_bot->m_ammo[m_args[index].long_] = m_args[value].long_; // store it away
#endif
}
void MessageDispatcher::netMsgAmmoPickup () {
@ -376,7 +389,7 @@ void MessageDispatcher::netMsgFlashBat () {
MessageDispatcher::MessageDispatcher () {
// register wanted message
auto pushWanted = [&] (const String &name, NetMsg id, MsgFunc handler) -> void {
auto pushWanted = [&] (StringRef name, NetMsg id, MsgFunc handler) -> void {
m_wanted[name] = id;
m_handlers[id] = handler;
};
@ -450,7 +463,7 @@ MessageDispatcher::MessageDispatcher () {
m_teamInfoCache["CT"] = Team::CT;
}
int32 MessageDispatcher::add (const String &name, int32 id) {
int32 MessageDispatcher::add (StringRef name, int32 id) {
if (!m_wanted.exists (name)) {
return id;
}

View file

@ -1,15 +1,22 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
ConVar yb_whose_your_daddy ("yb_whose_your_daddy", "0", "Enables or disables extra hard difficulty for bots.");
ConVar yb_debug_heuristic_type ("yb_debug_heuristic_type", "0", "Selects the heuristic function mode. For debug purposes only.", true, 0.0f, 4.0f);
ConVar cv_whose_your_daddy ("ub_whose_your_daddy", "0", "Enables or disables extra hard difficulty for bots.");
ConVar cv_debug_heuristic_type ("ub_debug_heuristic_type", "0", "Selects the heuristic function mode. For debug purposes only.", true, 0.0f, 4.0f);
int Bot::findBestGoal () {
@ -209,6 +216,7 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive) {
if (goalChoices[0] == kInvalidNodeIndex) {
return m_chosenGoalIndex = rg.int_ (0, graph.length () - 1);
}
bool sorting = false;
do {
@ -228,7 +236,7 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive) {
return m_chosenGoalIndex = goalChoices[0]; // return and store goal
}
void Bot::postprocessGoals (const IntArray &goals, int *result) {
void Bot::postprocessGoals (const IntArray &goals, int result[]) {
// this function filters the goals, so new goal is not bot's old goal, and array of goals doesn't contains duplicate goals
int searchCount = 0;
@ -248,7 +256,7 @@ void Bot::postprocessGoals (const IntArray &goals, int *result) {
}
bool Bot::hasActiveGoal () {
int goal = getTask ()->data;
auto goal = getTask ()->data;
if (goal == kInvalidNodeIndex) { // not decided about a goal
return false;
@ -357,12 +365,13 @@ bool Bot::doPlayerAvoidance (const Vector &normal) {
}
void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
m_isStuck = false;
// if avoiding someone do not consider stuck
TraceResult tr {};
doPlayerAvoidance (dirNormal);
m_isStuck = false;
// Standing still, no need to check?
// FIXME: doesn't care for ladder movement (handled separately) should be included in some way
if ((m_moveSpeed >= 10.0f || m_strafeSpeed >= 10.0f) && m_lastCollTime < game.time () && m_seeEnemyTime + 0.8f < game.time () && getCurrentTaskId () != Task::Attack) {
@ -380,7 +389,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
else {
// test if there's something ahead blocking the way
if (cantMoveForward (dirNormal, &tr) && !isOnLadder ()) {
if (m_firstCollideTime == 0.0f) {
if (cr::fzero (m_firstCollideTime)) {
m_firstCollideTime = game.time () + 0.2f;
}
else if (m_firstCollideTime <= game.time ()) {
@ -406,11 +415,8 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
return;
}
// bot is stuck!
Vector src;
Vector dst;
// not yet decided what to do?
// bot is stuc, but not yet decided what to do?
if (m_collisionState == CollisionState::Undecided) {
int bits = 0;
@ -421,7 +427,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
bits |= (CollisionProbe::Jump | CollisionProbe::Strafe);
}
else {
bits |= (CollisionProbe::Strafe | (m_jumpStateTimer < game.time () ? CollisionProbe::Jump : 0));
bits |= (CollisionProbe::Strafe | CollisionProbe::Jump);
}
// collision check allowed if not flying through the air
@ -429,6 +435,8 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
int state[kMaxCollideMoves * 2 + 1];
int i = 0;
Vector src {}, dst {};
// first 4 entries hold the possible collision states
state[i++] = CollisionState::StrafeLeft;
state[i++] = CollisionState::StrafeRight;
@ -440,7 +448,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
state[i + 1] = 0;
// to start strafing, we have to first figure out if the target is on the left side or right side
Vector right, forward;
Vector right {}, forward {};
m_moveAngles.angleVectors (&forward, &right, nullptr);
const Vector &dirToPoint = (pev->origin - m_destOrigin).normalize2d ();
@ -465,7 +473,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
game.testHull (src, dst, TraceIgnore::Monsters, head_hull, ent (), &tr);
if (tr.flFraction != 1.0f) {
if (!cr::fequal (tr.flFraction, 1.0f)) {
blockedRight = true;
}
src = pev->origin - right * 32.0f;
@ -473,7 +481,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
game.testHull (src, dst, TraceIgnore::Monsters, head_hull, ent (), &tr);
if (tr.flFraction != 1.0f) {
if (!cr::fequal (tr.flFraction, 1.0f)) {
blockedLeft = true;
}
@ -541,7 +549,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
dst = src + dirNormal * 30.0f;
game.testLine (src, dst, TraceIgnore::Everything, ent (), &tr);
if (tr.flFraction != 1.0f) {
if (!cr::fequal (tr.flFraction, 1.0f)) {
state[i] += 10;
}
}
@ -611,7 +619,6 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
case CollisionState::Jump:
if (isOnFloor () || isInWater ()) {
pev->button |= IN_JUMP;
m_jumpStateTimer = game.time () + rg.float_ (0.7f, 1.5f);
}
break;
@ -642,9 +649,9 @@ bool Bot::updateNavigation () {
findValidNode ();
m_pathOrigin = m_path->origin;
// if wayzone radius non zero vary origin a bit depending on the body angles
// if graph node radius non zero vary origin a bit depending on the body angles
if (m_path->radius > 0.0f) {
m_pathOrigin = m_pathOrigin + Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.float_ (-90.0f, 90.0f)), 0.0f).forward () * rg.float_ (0.0f, m_path->radius);
m_pathOrigin += Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.float_ (-90.0f, 90.0f)), 0.0f).forward () * rg.float_ (0.0f, m_path->radius);
}
m_navTimeset = game.time ();
}
@ -669,7 +676,7 @@ bool Bot::updateNavigation () {
m_desiredVelocity = nullptr;
}
}
else if (!yb_jasonmode.bool_ () && m_currentWeapon == Weapon::Knife && isOnFloor ()) {
else if (!cv_jasonmode.bool_ () && m_currentWeapon == Weapon::Knife && isOnFloor ()) {
selectBestWeapon ();
}
}
@ -788,12 +795,23 @@ bool Bot::updateNavigation () {
break;
}
}
// needs precise placement - check if we get past the point
if (desiredDistance < 22.0f && nodeDistance < 30.0f && (pev->origin + (pev->velocity * getFrameInterval ()) - m_pathOrigin).lengthSq () >= cr::square (nodeDistance)) {
desiredDistance = nodeDistance + 1.0f;
}
// this allows us to prevent stupid bot behaviour when he reaches almost end point of this route, but some one (other bot eg)
// is sitting there, so the bot is unable to reach the node because of other player on it, and he starts to jumping and so on
// here we're clearing task memory data (important!), since task executor may restart goal with one from memory, so this process
// will go in cycle, and forcing bot to re-create new route.
if (m_pathWalk.hasNext () && m_pathWalk.next () == m_pathWalk.last () && isOccupiedNode (m_pathWalk.next (), true)) {
getTask ()->data = kInvalidNodeIndex;
clearSearchNodes ();
return false;
}
if (nodeDistance < desiredDistance) {
// did we reach a destination node?
@ -985,7 +1003,7 @@ bool Bot::updateLiftHandling () {
auto button = lookupButton (m_liftEntity->v.targetname.chars ());
// got a valid button entity ?
if (!game.isNullEntity (button) && pev->groundentity == m_liftEntity && m_buttonPushTime + 1.0f < game.time () && m_liftEntity->v.velocity.z == 0.0f && isOnFloor ()) {
if (!game.isNullEntity (button) && pev->groundentity == m_liftEntity && m_buttonPushTime + 1.0f < game.time () && cr::fzero (m_liftEntity->v.velocity.z) && isOnFloor ()) {
m_pickupItem = button;
m_pickupType = Pickup::Button;
@ -995,7 +1013,7 @@ bool Bot::updateLiftHandling () {
// is lift activated and bot is standing on it and lift is moving ?
if (m_liftState == LiftState::LookingButtonInside || m_liftState == LiftState::EnteringIn || m_liftState == LiftState::WaitingForTeammates || m_liftState == LiftState::WaitingFor) {
if (pev->groundentity == m_liftEntity && m_liftEntity->v.velocity.z != 0.0f && isOnFloor () && ((graph[m_previousNodes[0]].flags & NodeFlag::Lift) || !game.isNullEntity (m_targetEntity))) {
if (pev->groundentity == m_liftEntity && !cr::fzero (m_liftEntity->v.velocity.z) && isOnFloor () && ((graph[m_previousNodes[0]].flags & NodeFlag::Lift) || !game.isNullEntity (m_targetEntity))) {
m_liftState = LiftState::TravelingBy;
m_liftUsageTime = game.time () + 14.0f;
@ -1131,7 +1149,7 @@ bool Bot::updateLiftStates () {
}
}
if (m_liftUsageTime < game.time () && m_liftUsageTime != 0.0f) {
if (m_liftUsageTime < game.time () && !cr::fzero (m_liftUsageTime)) {
m_liftEntity = nullptr;
m_liftState = LiftState::None;
m_liftUsageTime = 0.0f;
@ -1294,7 +1312,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
float y = cr::abs (start.origin.y - goal.origin.y);
float z = cr::abs (start.origin.z - goal.origin.z);
switch (yb_debug_heuristic_type.int_ ()) {
switch (cv_debug_heuristic_type.int_ ()) {
case 0:
default:
return cr::max (cr::max (x, y), z); // chebyshev distance
@ -1310,7 +1328,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
// euclidean based distance
float euclidean = cr::powf (cr::powf (x, 2.0f) + cr::powf (y, 2.0f) + cr::powf (z, 2.0f), 0.5f);
if (yb_debug_heuristic_type.int_ () == 4) {
if (cv_debug_heuristic_type.int_ () == 4) {
return 1000.0f *(cr::ceilf (euclidean) - euclidean);
}
return euclidean;
@ -1648,7 +1666,7 @@ float Bot::getReachTime () {
if (longTermReachability) {
estimatedTime *= 2.0f;
}
estimatedTime = cr::clamp (estimatedTime, 1.2f, longTermReachability ? 8.0f : 5.0f);
estimatedTime = cr::clamp (estimatedTime, 2.0f, longTermReachability ? 8.0f : 5.0f);
}
return estimatedTime;
}
@ -1656,30 +1674,10 @@ float Bot::getReachTime () {
void Bot::findValidNode () {
// checks if the last node the bot was heading for is still valid
auto trySelectNewGoal = [&] () {
if (m_rechoiceGoalCount > 1) {
int newGoal = findBestGoal ();
m_prevGoalIndex = newGoal;
m_chosenGoalIndex = newGoal;
getTask ()->data = newGoal;
// do path finding if it's not the current node
if (newGoal != m_currentNodeIndex) {
findPath (m_currentNodeIndex, newGoal, m_pathType);
}
m_rechoiceGoalCount = 0;
}
else {
findBestNearestNode ();
++m_rechoiceGoalCount;
}
};
// if bot hasn't got a node we need a new one anyway or if time to get there expired get new one as well
if (m_currentNodeIndex == kInvalidNodeIndex) {
clearSearchNodes ();
trySelectNewGoal ();
findBestNearestNode ();
m_pathOrigin = m_path->origin;
}
@ -1687,7 +1685,6 @@ void Bot::findValidNode () {
// increase danager for both teams
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
int damageValue = graph.getDangerDamage (team, m_currentNodeIndex, m_currentNodeIndex);
damageValue = cr::clamp (damageValue + 100, 0, kMaxPracticeDamageValue);
@ -1702,10 +1699,9 @@ void Bot::findValidNode () {
}
graph.setDangerDamage (m_team, m_currentNodeIndex, m_currentNodeIndex, damageValue);
}
clearSearchNodes ();
trySelectNewGoal ();
findBestNearestNode ();
m_pathOrigin = m_path->origin;
}
}
@ -1764,26 +1760,27 @@ int Bot::findBombNode () {
auto &goals = graph.m_goalPoints;
auto bomb = graph.getBombOrigin ();
auto audible = isBombAudible ();
if (!audible.empty ()) {
m_bombSearchOverridden = true;
return graph.getNearest (audible, 240.0f);
}
else if (goals.empty ()) {
return graph.getNearest (bomb, 240.0f, NodeFlag::Goal); // reliability check
}
const auto &bomb = graph.getBombOrigin ();
const auto &audible = isBombAudible ();
// take the nearest to bomb nodes instead of goal if close enough
else if ((pev->origin - bomb).lengthSq () < cr::square (512.0f)) {
int node = graph.getNearest (bomb, 240.0f);
if ((pev->origin - bomb).lengthSq () < cr::square (96.0f)) {
int node = graph.getNearest (bomb, 420.0f);
m_bombSearchOverridden = true;
if (node != kInvalidNodeIndex) {
return node;
}
}
else if (!audible.empty ()) {
m_bombSearchOverridden = true;
return graph.getNearest (audible, 240.0f);
}
else if (goals.empty ()) {
return graph.getNearest (bomb, 512.0f); // reliability check
}
int goal = 0, count = 0;
float lastDistance = kInfiniteDistance;
@ -1851,7 +1848,7 @@ int Bot::findDefendNode (const Vector &origin) {
game.testLine (graph[i].origin, graph[posIndex].origin, TraceIgnore::Everything, ent (), &tr);
// check if line not hit anything
if (tr.flFraction != 1.0f) {
if (!cr::fequal (tr.flFraction, 1.0f)) {
continue;
}
@ -1909,7 +1906,7 @@ int Bot::findDefendNode (const Vector &origin) {
break;
}
}
return nodeIndex[rg.int_ (0, static_cast <int> ((index - 1) * 0.5f))];
return nodeIndex[rg.int_ (0, (index -1) / 2)];
}
int Bot::findCoverNode (float maxDistance) {
@ -2122,12 +2119,12 @@ bool Bot::advanceMovement () {
}
if (m_baseAgressionLevel < kills && hasPrimaryWeapon ()) {
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.float_ (m_difficulty * 0.5f, static_cast <float> (m_difficulty)) * 5.0f, true);
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.float_ (static_cast <float> (m_difficulty / 2), static_cast <float> (m_difficulty)) * 5.0f, true);
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, findDefendNode (graph[nextIndex].origin), game.time () + rg.float_ (3.0f, 10.0f), true);
}
}
else if (bots.canPause () && !isOnLadder () && !isInWater () && !m_currentTravelFlags && isOnFloor ()) {
if (static_cast <float> (kills) == m_baseAgressionLevel) {
if (cr::fequal (kills, m_baseAgressionLevel)) {
m_campButtons |= IN_DUCK;
}
else if (rg.chance (m_difficulty * 25)) {
@ -2136,22 +2133,18 @@ bool Bot::advanceMovement () {
}
// force terrorist bot to plant bomb
if (m_inBombZone && !m_hasProgressBar && m_hasC4) {
if (m_inBombZone && !m_hasProgressBar && m_hasC4 && getCurrentTaskId () != Task::PlantBomb) {
changeNextGoal ();
return false;
}
}
}
else if (m_pathWalk.hasNext () && m_pathWalk.next () == m_pathWalk.last () && isOccupiedNode (m_pathWalk.last ())) {
changeNextGoal ();
return false;
}
if (!m_pathWalk.empty ()) {
const int destIndex = m_pathWalk.first ();
// find out about connection flags
if (m_currentNodeIndex != kInvalidNodeIndex) {
if (destIndex != kInvalidNodeIndex && m_currentNodeIndex != kInvalidNodeIndex) {
for (const auto &link : m_path->links) {
if (link.index == destIndex) {
m_currentTravelFlags = link.flags;
@ -2238,20 +2231,21 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
Vector forward = src + normal * 24.0f;
const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right ();
bool traceResult = false;
auto checkDoor = [] (TraceResult *tr) {
auto checkDoor = [&traceResult] (TraceResult *tr) {
if (!game.mapIs (MapFlags::HasDoors)) {
return false;
}
return tr->flFraction < 1.0f && strncmp ("func_door", tr->pHit->v.classname.chars (), 9) != 0;
return !traceResult && tr->flFraction < 1.0f && strncmp ("func_door", tr->pHit->v.classname.chars (), 9) != 0;
};
// trace from the bot's eyes straight forward...
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
traceResult = game.testLineChannel (TraceChannel::Body, src, forward, TraceIgnore::Monsters, ent (), tr);
// check if the trace hit something...
if (tr->flFraction < 1.0f) {
if (game.mapIs (MapFlags::HasDoors) && strncmp ("func_door", tr->pHit->v.classname.chars (), 9) == 0) {
if (!traceResult && game.mapIs (MapFlags::HasDoors) && strncmp ("func_door", tr->pHit->v.classname.chars (), 9) == 0) {
return false;
}
return true; // bot's head will hit something
@ -2262,7 +2256,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
src = getEyesPos () + Vector (0.0f, 0.0f, -16.0f) - right * -16.0f;
forward = getEyesPos () + Vector (0.0f, 0.0f, -16.0f) + right * 16.0f + normal * 24.0f;
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
traceResult = game.testLineChannel (TraceChannel::Body, src, forward, TraceIgnore::Monsters, ent (), tr);
// check if the trace hit something...
if (checkDoor (tr)) {
@ -2274,7 +2268,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
src = getEyesPos () + Vector (0.0f, 0.0f, -16.0f) + right * 16.0f;
forward = getEyesPos () + Vector (0.0f, 0.0f, -16.0f) - right * -16.0f + normal * 24.0f;
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
traceResult = game.testLineChannel (TraceChannel::Body, src, forward, TraceIgnore::Monsters, ent (), tr);
// check if the trace hit something...
if (checkDoor (tr)) {
@ -2286,7 +2280,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
src = pev->origin + Vector (0.0f, 0.0f, -19.0f + 19.0f);
forward = src + Vector (0.0f, 0.0f, 10.0f) + normal * 24.0f;
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
traceResult = game.testLineChannel (TraceChannel::Body, src, forward, TraceIgnore::Monsters, ent (), tr);
// check if the trace hit something...
if (checkDoor (tr)) {
@ -2295,7 +2289,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
src = pev->origin;
forward = src + normal * 24.0f;
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
traceResult = game.testLineChannel (TraceChannel::Body, src, forward, TraceIgnore::Monsters, ent (), tr);
// check if the trace hit something...
if (checkDoor (tr)) {
@ -2308,7 +2302,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
forward = pev->origin + Vector (0.0f, 0.0f, -17.0f) + right * 16.0f + normal * 24.0f;
// trace from the bot's waist straight forward...
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
traceResult = game.testLineChannel (TraceChannel::Body, src, forward, TraceIgnore::Monsters, ent (), tr);
// check if the trace hit something...
if (checkDoor (tr)) {
@ -2319,7 +2313,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
src = pev->origin + Vector (0.0f, 0.0f, -24.0f) + right * 16.0f;
forward = pev->origin + Vector (0.0f, 0.0f, -24.0f) - right * -16.0f + normal * 24.0f;
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
traceResult = game.testLineChannel (TraceChannel::Body, src, forward, TraceIgnore::Monsters, ent (), tr);
// check if the trace hit something...
if (checkDoor (tr)) {
@ -2816,6 +2810,9 @@ void Bot::updateBodyAngles () {
pev->angles.y = pev->v_angle.y;
pev->angles.clampAngles ();
// calculate frustum plane data here, since lookangles update functions call this last one
calculateFrustum ();
}
void Bot::updateLookAngles () {
@ -2830,14 +2827,14 @@ void Bot::updateLookAngles () {
direction.clampAngles ();
// lower skilled bot's have lower aiming
if (m_difficulty < 2) {
if (m_difficulty < Difficulty::Normal) {
updateLookAnglesNewbie (direction, delta);
updateBodyAngles ();
return;
}
if (m_difficulty > 3 && (m_aimFlags & AimFlags::Enemy) && (m_wantsToFire || usesSniper ()) && yb_whose_your_daddy.bool_ ()) {
if (m_difficulty == Difficulty::Expert && (m_aimFlags & AimFlags::Enemy) && (m_wantsToFire || usesSniper ()) && cv_whose_your_daddy.bool_ ()) {
pev->v_angle = direction;
updateBodyAngles ();
@ -2848,7 +2845,7 @@ void Bot::updateLookAngles () {
float stiffness = 200.0f;
float damping = 25.0f;
if ((m_aimFlags & (AimFlags::Enemy | AimFlags::Entity | AimFlags::Grenade)) && m_difficulty > 3) {
if ((m_aimFlags & (AimFlags::Enemy | AimFlags::Entity | AimFlags::Grenade)) && m_difficulty > Difficulty::Hard) {
stiffness += 100.0f;
damping += 5.0f;
}
@ -2879,8 +2876,8 @@ void Bot::updateLookAngles () {
}
void Bot::updateLookAnglesNewbie (const Vector &direction, float delta) {
Vector spring (13.0f, 13.0f, 0.0f);
Vector damperCoefficient (0.22f, 0.22f, 0.0f);
Vector spring { 13.0f, 13.0f, 0.0f };
Vector damperCoefficient { 0.22f, 0.22f, 0.0f };
const float offset = cr::clamp (m_difficulty, 1, 4) * 25.0f;
@ -2972,7 +2969,7 @@ void Bot::setStrafeSpeed (const Vector &moveDir, float strafeSpeed) {
int Bot::getNearestToPlantedBomb () {
// this function tries to find planted c4 on the defuse scenario map and returns nearest to it node
if (m_team != Team::Terrorist || !game.mapIs (MapFlags::Demolition)) {
if (!game.mapIs (MapFlags::Demolition)) {
return kInvalidNodeIndex; // don't search for bomb if the player is CT, or it's not defusing bomb
}
int result = kInvalidNodeIndex;
@ -2991,7 +2988,7 @@ int Bot::getNearestToPlantedBomb () {
return result;
}
bool Bot::isOccupiedNode (int index) {
bool Bot::isOccupiedNode (int index, bool needZeroVelocity) {
if (!graph.exists (index)) {
return true;
}
@ -3005,6 +3002,11 @@ bool Bot::isOccupiedNode (int index) {
if ((pev->origin - client.origin).lengthSq () > cr::square (320.0f)) {
continue;
}
if (needZeroVelocity && client.ent->v.velocity.length2d () > 0.0f) {
continue;
}
auto bot = bots[client.ent];
if (bot == this) {
@ -3020,7 +3022,7 @@ bool Bot::isOccupiedNode (int index) {
}
float length = (graph[index].origin - client.origin).lengthSq ();
if (length < cr::clamp (graph[index].radius, cr::square (64.0f), cr::square (120.0f))) {
if (length < cr::clamp (graph[index].radius, cr::square (90.0f), cr::square (120.0f))) {
return true;
}
}
@ -3070,6 +3072,11 @@ bool Bot::isReachableNode (int index) {
if ((dst - src).lengthSq () >= cr::square (320.0f)) {
return false;
}
// some one seems to camp at this node
if (isOccupiedNode (index, true)) {
return true;
}
float ladderDist = (dst - src).length2d ();
TraceResult tr {};

View file

@ -1,17 +1,24 @@
//
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) Yet Another POD-Bot Contributors <yapb@entix.io>.
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This software is licensed under the MIT license.
// Additional exceptions apply. For full license details, see LICENSE.txt
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <yapb.h>
ConVar yb_display_welcome_text ("yb_display_welcome_text", "1", "Enables or disables showing welcome message to host entity on game start.");
ConVar yb_enable_query_hook ("yb_enable_query_hook", "1", "Enables or disabled fake server queries response, that shows bots as real players in server browser.");
ConVar cv_display_welcome_text ("ub_display_welcome_text", "1", "Enables or disables showing welcome message to host entity on game start.");
ConVar cv_enable_query_hook ("ub_enable_query_hook", "1", "Enables or disables fake server queries response, that shows bots as real players in server browser.");
BotUtils::BotUtils () {
BotSupport::BotSupport () {
m_needToSendWelcome = false;
m_welcomeReceiveTime = 0.0f;
@ -64,7 +71,6 @@ BotUtils::BotUtils () {
m_noiseCache["weapons/zoo"] = Noise::NeedHandle | Noise::Zoom;
m_noiseCache["hostage/hos"] = Noise::NeedHandle | Noise::Hostage;
m_noiseCache["debris/bust"] = Noise::NeedHandle | Noise::Broke;
m_noiseCache["debris/bust"] = Noise::NeedHandle | Noise::Broke;
m_noiseCache["doors/doorm"] = Noise::NeedHandle | Noise::Door;
// register weapon aliases
@ -104,27 +110,27 @@ BotUtils::BotUtils () {
m_clients.resize (kGameMaxPlayers + 1);
}
bool BotUtils::isAlive (edict_t *ent) {
bool BotSupport::isAlive (edict_t *ent) {
if (game.isNullEntity (ent)) {
return false;
}
return ent->v.deadflag == DEAD_NO && ent->v.health > 0 && ent->v.movetype != MOVETYPE_NOCLIP;
}
bool BotUtils::isVisible (const Vector &origin, edict_t *ent) {
bool BotSupport::isVisible (const Vector &origin, edict_t *ent) {
if (game.isNullEntity (ent)) {
return false;
}
TraceResult tr {};
game.testLine (ent->v.origin + ent->v.view_ofs, origin, TraceIgnore::Everything, ent, &tr);
if (tr.flFraction != 1.0f) {
if (!cr::fequal (tr.flFraction, 1.0f)) {
return false;
}
return true;
}
void BotUtils::traceDecals (entvars_t *pev, TraceResult *trace, int logotypeIndex) {
void BotSupport::traceDecals (entvars_t *pev, TraceResult *trace, int logotypeIndex) {
// this function draw spraypaint depending on the tracing results.
auto logo = conf.getRandomLogoName (logotypeIndex);
@ -136,7 +142,7 @@ void BotUtils::traceDecals (entvars_t *pev, TraceResult *trace, int logotypeInde
decalIndex = engfuncs.pfnDecalIndex ("{lambda06");
}
if (trace->flFraction == 1.0f) {
if (cr::fequal (trace->flFraction, 1.0f)) {
return;
}
if (!game.isNullEntity (trace->pHit)) {
@ -193,7 +199,7 @@ void BotUtils::traceDecals (entvars_t *pev, TraceResult *trace, int logotypeInde
}
}
bool BotUtils::isPlayer (edict_t *ent) {
bool BotSupport::isPlayer (edict_t *ent) {
if (game.isNullEntity (ent)) {
return false;
}
@ -208,7 +214,7 @@ bool BotUtils::isPlayer (edict_t *ent) {
return false;
}
bool BotUtils::isPlayerVIP (edict_t *ent) {
bool BotSupport::isPlayerVIP (edict_t *ent) {
if (!game.mapIs (MapFlags::Assassination)) {
return false;
}
@ -219,28 +225,26 @@ bool BotUtils::isPlayerVIP (edict_t *ent) {
return *(engfuncs.pfnInfoKeyValue (engfuncs.pfnGetInfoKeyBuffer (ent), "model")) == 'v';
}
bool BotUtils::isFakeClient (edict_t *ent) {
bool BotSupport::isFakeClient (edict_t *ent) {
if (bots[ent] != nullptr || (!game.isNullEntity (ent) && (ent->v.flags & FL_FAKECLIENT))) {
return true;
}
return false;
}
bool BotUtils::openConfig (const char *fileName, const char *errorIfNotExists, MemFile *outFile, bool languageDependant /*= false*/) {
bool BotSupport::openConfig (const char *fileName, const char *errorIfNotExists, MemFile *outFile, bool languageDependant /*= false*/) {
if (*outFile) {
outFile->close ();
}
// save config dir
const char *configDir = "addons/yapb/conf";
auto configDir = strings.format ("addons/%s/conf", product.folder);
if (languageDependant) {
extern ConVar yb_language;
if (strcmp (fileName, "lang.cfg") == 0 && strcmp (yb_language.str (), "en") == 0) {
if (strcmp (fileName, "lang.cfg") == 0 && strcmp (cv_language.str (), "en") == 0) {
return false;
}
auto langConfig = strings.format ("%s/lang/%s_%s", configDir, yb_language.str (), fileName);
auto langConfig = strings.format ("%s/lang/%s_%s", configDir, cv_language.str (), fileName);
// check is file is exists for this language
if (!outFile->open (langConfig)) {
@ -258,10 +262,10 @@ bool BotUtils::openConfig (const char *fileName, const char *errorIfNotExists, M
return true;
}
void BotUtils::checkWelcome () {
void BotSupport::checkWelcome () {
// the purpose of this function, is to send quick welcome message, to the listenserver entity.
if (game.isDedicated () || !yb_display_welcome_text.bool_ () || !m_needToSendWelcome) {
if (game.isDedicated () || !cv_display_welcome_text.bool_ () || !m_needToSendWelcome) {
return;
}
m_welcomeReceiveTime = 0.0f;
@ -274,15 +278,14 @@ void BotUtils::checkWelcome () {
m_welcomeReceiveTime = game.time () + 4.0f; // receive welcome message in four seconds after game has commencing
}
if (m_welcomeReceiveTime > 0.0f && needToSendMsg) {
if (!game.is (GameFlags::Mobility | GameFlags::Xash3D)) {
game.serverCommand ("speak \"%s\"", m_sentences.random ().chars ());
game.serverCommand ("speak \"%s\"", m_sentences.random ());
}
MessageWriter (MSG_ONE, msgs.id (NetMsg::TextMsg), nullptr, receiveEntity)
.writeByte (HUD_PRINTTALK)
.writeString (strings.format ("----- %s v%s (Build: %u), {%s}, (c) %s, by %s (%s)-----", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_DATE, PRODUCT_END_YEAR, PRODUCT_AUTHOR, PRODUCT_URL));
.writeString (strings.format ("----- %s v%s (Build: %s), {%s}, (c) %s, by %s (%s)-----", product.name, product.version, product.build.count, product.date, product.year, product.author, product.url));
MessageWriter (MSG_ONE, SVC_TEMPENTITY, nullptr, receiveEntity)
.writeByte (TE_TEXTMESSAGE)
@ -302,14 +305,14 @@ void BotUtils::checkWelcome () {
.writeShort (MessageWriter::fu16 (2.0f, 8.0f))
.writeShort (MessageWriter::fu16 (6.0f, 8.0f))
.writeShort (MessageWriter::fu16 (0.1f, 8.0f))
.writeString (strings.format ("\nServer is running %s v%s (Build: %u)\nDeveloped by %s\n\n%s", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_AUTHOR, graph.getAuthor ()));
.writeString (strings.format ("\nHello! You are playing with %s v%s (Build: %s)\nDevised by %s\n\n%s", product.name, product.version, product.build.count, product.author, graph.getAuthor ()));
m_welcomeReceiveTime = 0.0f;
m_needToSendWelcome = false;
}
}
bool BotUtils::findNearestPlayer (void **pvHolder, edict_t *to, float searchDistance, bool sameTeam, bool needBot, bool needAlive, bool needDrawn, bool needBotWithC4) {
bool BotSupport::findNearestPlayer (void **pvHolder, edict_t *to, float searchDistance, bool sameTeam, bool needBot, bool needAlive, bool needDrawn, bool needBotWithC4) {
// this function finds nearest to to, player with set of parameters, like his
// team, live status, search distance etc. if needBot is true, then pvHolder, will
// be filled with bot pointer, else with edict pointer(!).
@ -349,7 +352,7 @@ bool BotUtils::findNearestPlayer (void **pvHolder, edict_t *to, float searchDist
return true;
}
void BotUtils::listenNoise (edict_t *ent, const String &sample, float volume) {
void BotSupport::listenNoise (edict_t *ent, StringRef sample, float volume) {
// this function called by the sound hooking code (in emit_sound) enters the played sound into the array associated with the entity
if (game.isNullEntity (ent) || sample.empty ()) {
@ -438,7 +441,7 @@ void BotUtils::listenNoise (edict_t *ent, const String &sample, float volume) {
}
}
void BotUtils::simulateNoise (int playerIndex) {
void BotSupport::simulateNoise (int playerIndex) {
// this function tries to simulate playing of sounds to let the bots hear sounds which aren't
// captured through server sound hooking
@ -506,7 +509,7 @@ void BotUtils::simulateNoise (int playerIndex) {
}
}
void BotUtils::updateClients () {
void BotSupport::updateClients () {
// record some stats of all players on the server
for (int i = 0; i < game.maxClients (); ++i) {
@ -536,7 +539,7 @@ void BotUtils::updateClients () {
}
}
int BotUtils::getPingBitmask (edict_t *ent, int loss, int ping) {
int BotSupport::getPingBitmask (edict_t *ent, int loss, int ping) {
// this function generats bitmask for SVC_PINGS engine message. See SV_EmitPings from engine for details
const auto emit = [] (int s0, int s1, int s2) {
@ -545,8 +548,8 @@ int BotUtils::getPingBitmask (edict_t *ent, int loss, int ping) {
return emit (loss, 7, 18) | emit (ping, 12, 6) | emit (game.indexOfPlayer (ent), 5, 1) | 1;
}
void BotUtils::calculatePings () {
if (!game.is (GameFlags::HasFakePings) || yb_show_latency.int_ () != 2) {
void BotSupport::calculatePings () {
if (!game.is (GameFlags::HasFakePings) || cv_show_latency.int_ () != 2) {
return;
}
@ -601,7 +604,7 @@ void BotUtils::calculatePings () {
}
}
void BotUtils::sendPings (edict_t *to) {
void BotSupport::sendPings (edict_t *to) {
MessageWriter msg;
// missing from sdk
@ -628,9 +631,9 @@ void BotUtils::sendPings (edict_t *to) {
return;
}
void BotUtils::installSendTo () {
void BotSupport::installSendTo () {
// if previously requested to disable?
if (!yb_enable_query_hook.bool_ ()) {
if (!cv_enable_query_hook.bool_ ()) {
if (m_sendToHook.enabled ()) {
disableSendTo ();
}
@ -644,11 +647,23 @@ void BotUtils::installSendTo () {
// enable only on modern games
if (game.is (GameFlags::Modern) && (plat.linux || plat.win32) && !plat.arm && !m_sendToHook.enabled ()) {
m_sendToHook.patch (reinterpret_cast <void *> (&sendto), reinterpret_cast <void *> (&BotUtils::sendTo));
m_sendToHook.patch (reinterpret_cast <void *> (&sendto), reinterpret_cast <void *> (&BotSupport::sendTo));
}
}
int32 BotUtils::sendTo (int socket, const void *message, size_t length, int flags, const sockaddr *dest, int destLength) {
bool BotSupport::isObjectInsidePlane (FrustumPlane &plane, const Vector &center, float height, float radius) {
auto isPointInsidePlane = [&](const Vector &point) -> bool {
return plane.result + (plane.normal | point) >= 0.0f;
};
const Vector &test = plane.normal.get2d ();
const Vector &top = center + Vector (0.0f, 0.0f, height * 0.5f) + test * radius;
const Vector &bottom = center - Vector (0.0f, 0.0f, height * 0.5f) + test * radius;
return isPointInsidePlane (top) || isPointInsidePlane (bottom);
}
int32 BotSupport::sendTo (int socket, const void *message, size_t length, int flags, const sockaddr *dest, int destLength) {
const auto send = [&] (const Twin <const uint8 *, size_t> &msg) -> int32 {
return Socket::sendto (socket, msg.first, msg.second, flags, dest, destLength);
};
@ -663,14 +678,12 @@ int32 BotUtils::sendTo (int socket, const void *message, size_t length, int flag
auto count = buffer.read <uint8> ();
for (uint8 i = 0; i < count; ++i) {
buffer.read <uint8> (); // number
buffer.write <uint8> (i); // override number
buffer.skip <uint8> (); // number
buffer.skipString (); // name
buffer.skip <int32> (); // score
buffer.read <float> (); // override connection time
buffer.write <float> (bots.getConnectionTime (i));
auto ctime = buffer.read <float> (); // override connection time
buffer.write <float> (bots.getConnectTime (i, ctime));
}
return send (buffer.data ());
}
@ -702,50 +715,8 @@ int32 BotUtils::sendTo (int socket, const void *message, size_t length, int flag
return send ({ packet, length });
}
int BotUtils::buildNumber () {
// this function generates build number from the compiler date macros
static int buildNumber = 0;
if (buildNumber != 0) {
return buildNumber;
}
// get compiling date using compiler macros
const char *date = __DATE__;
// array of the month names
const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
// array of the month days
uint8 monthDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int day = 0; // day of the year
int year = 0; // year
int i = 0;
// go through all months, and calculate, days since year start
for (i = 0; i < 11; ++i) {
if (strncmp (&date[0], months[i], 3) == 0) {
break; // found current month break
}
day += monthDays[i]; // add month days
}
day += atoi (&date[4]) - 1; // finally calculate day
year = atoi (&date[7]) - 2000; // get years since year 2000
buildNumber = day + static_cast <int> ((year - 1) * 365.25);
// if the year is a leap year?
if ((year % 4) == 0 && i > 1) {
buildNumber += 1; // add one year more
}
buildNumber -= 1114;
return buildNumber;
}
const String &BotUtils::weaponIdToAlias (const int32 id) {
static const String &none = "none";
StringRef BotSupport::weaponIdToAlias (int32 id) {
StringRef none = "none";
if (m_weaponAlias.exists (id)) {
return m_weaponAlias[id];

47
vc/yapb.rc Normal file
View file

@ -0,0 +1,47 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Development Team <team@yapb.ru>.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <winver.h>
#ifdef VERSION_GENERATED
# define VERSION_HEADER <version.build.h>
#else
# define VERSION_HEADER "../inc/version.h"
#endif
#include VERSION_HEADER
VS_VERSION_INFO VERSIONINFO
FILEVERSION MODULE_BOT_VERSION_FILE
PRODUCTVERSION MODULE_BOT_VERSION_FILE
FILEOS 0x40004
FILETYPE 0x2 {
BLOCK "StringFileInfo" {
BLOCK "040904E4" {
VALUE "CompanyName", "YaPB Development Team" "\0"
VALUE "FileDescription", "YaPB v" MODULE_BOT_VERSION "." MODULE_BUILD_COUNT " - The Counter-Strike Bot" "\0"
VALUE "LegalCopyright", "Copyright \251 2020 YaPB Development Team" "\0"
VALUE "OriginalFilename", "yapb.dll" "\0"
VALUE "ProductName", "YaPB" "\0"
VALUE "InternalName", "YaPB DLL" "\0"
VALUE "FileVersion", MODULE_BOT_VERSION "." MODULE_BUILD_COUNT "\0"
VALUE "ProductVersion", MODULE_BOT_VERSION "." MODULE_BUILD_COUNT "\0"
VALUE "SpecialBuild", MODULE_BOT_BUILD_ID "\0"
}
}
BLOCK "VarFileInfo" {
VALUE "Translation", 0x400, 1200
}
}

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -11,65 +11,69 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\config.h" />
<ClInclude Include="..\include\control.h" />
<ClInclude Include="..\include\crlib\cr-alloc.h" />
<ClInclude Include="..\include\crlib\cr-array.h" />
<ClInclude Include="..\include\crlib\cr-basic.h" />
<ClInclude Include="..\include\crlib\cr-binheap.h" />
<ClInclude Include="..\include\crlib\cr-color.h" />
<ClInclude Include="..\include\crlib\cr-complete.h" />
<ClInclude Include="..\include\crlib\cr-dict.h" />
<ClInclude Include="..\include\crlib\cr-files.h" />
<ClInclude Include="..\include\crlib\cr-hook.h" />
<ClInclude Include="..\include\crlib\cr-http.h" />
<ClInclude Include="..\include\crlib\cr-lambda.h" />
<ClInclude Include="..\include\crlib\cr-library.h" />
<ClInclude Include="..\include\crlib\cr-logger.h" />
<ClInclude Include="..\include\crlib\cr-math.h" />
<ClInclude Include="..\include\crlib\cr-movable.h" />
<ClInclude Include="..\include\crlib\cr-platform.h" />
<ClInclude Include="..\include\crlib\cr-random.h" />
<ClInclude Include="..\include\crlib\cr-string.h" />
<ClInclude Include="..\include\crlib\cr-twin.h" />
<ClInclude Include="..\include\crlib\cr-ulz.h" />
<ClInclude Include="..\include\crlib\cr-uniqueptr.h" />
<ClInclude Include="..\include\crlib\cr-vector.h" />
<ClInclude Include="..\include\engine\model.h" />
<ClInclude Include="..\include\graph.h" />
<ClInclude Include="..\include\manager.h" />
<ClInclude Include="..\include\message.h" />
<ClInclude Include="..\include\utils.h" />
<ClInclude Include="..\include\yapb.h" />
<ClInclude Include="..\include\engine.h" />
<ClInclude Include="..\include\engine\const.h" />
<ClInclude Include="..\include\engine\eiface.h" />
<ClInclude Include="..\include\engine\extdll.h" />
<ClInclude Include="..\include\engine\meta_api.h" />
<ClInclude Include="..\include\engine\progdefs.h" />
<ClInclude Include="..\include\engine\util.h" />
<ClInclude Include="..\include\resource.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-alloc.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-array.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-basic.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-binheap.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-color.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-complete.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-dict.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-files.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-hook.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-http.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-lambda.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-library.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-logger.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-math.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-movable.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-platform.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-random.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-string.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-twin.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-ulz.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-uniqueptr.h" />
<ClInclude Include="..\ext\crlib\crlib\cr-vector.h" />
<ClInclude Include="..\ext\sdk\sdk\const.h" />
<ClInclude Include="..\ext\sdk\sdk\eiface.h" />
<ClInclude Include="..\ext\sdk\sdk\extdll.h" />
<ClInclude Include="..\ext\sdk\sdk\metamod.h" />
<ClInclude Include="..\ext\sdk\sdk\meta_api.h" />
<ClInclude Include="..\ext\sdk\sdk\model.h" />
<ClInclude Include="..\ext\sdk\sdk\progdefs.h" />
<ClInclude Include="..\ext\sdk\sdk\util.h" />
<ClInclude Include="..\inc\config.h" />
<ClInclude Include="..\inc\control.h" />
<ClInclude Include="..\inc\engine.h" />
<ClInclude Include="..\inc\graph.h" />
<ClInclude Include="..\inc\manager.h" />
<ClInclude Include="..\inc\message.h" />
<ClInclude Include="..\inc\product.h" />
<ClInclude Include="..\inc\support.h" />
<ClInclude Include="..\inc\yapb.h" />
<ClInclude Include="..\inc\version.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\source\android.cpp" />
<ClCompile Include="..\source\basecode.cpp" />
<ClCompile Include="..\source\combat.cpp" />
<ClCompile Include="..\source\engine.cpp" />
<ClCompile Include="..\source\manager.cpp" />
<ClCompile Include="..\source\chatlib.cpp" />
<ClCompile Include="..\source\control.cpp" />
<ClCompile Include="..\source\linkage.cpp" />
<ClCompile Include="..\source\message.cpp" />
<ClCompile Include="..\source\navigate.cpp" />
<ClCompile Include="..\source\support.cpp" />
<ClCompile Include="..\source\graph.cpp" />
<ClCompile Include="..\src\android.cpp" />
<ClCompile Include="..\src\botlib.cpp" />
<ClCompile Include="..\src\chatlib.cpp" />
<ClCompile Include="..\src\combat.cpp" />
<ClCompile Include="..\src\control.cpp" />
<ClCompile Include="..\src\engine.cpp" />
<ClCompile Include="..\src\graph.cpp" />
<ClCompile Include="..\src\linkage.cpp" />
<ClCompile Include="..\src\manager.cpp" />
<ClCompile Include="..\src\message.cpp" />
<ClCompile Include="..\src\navigate.cpp" />
<ClCompile Include="..\src\support.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="yapb.rc" />
<ResourceCompile Include="yapb.rc">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\source\Android.mk" />
<None Include="makefile" />
<None Include="..\inc\version.h.in" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C232645A-3B99-48F4-A1F3-F20CF0A9568B}</ProjectGuid>
@ -88,6 +92,7 @@
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<PlatformToolset>v142</PlatformToolset>
<EnableASAN>false</EnableASAN>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -131,16 +136,16 @@
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>.\debug/yapb.tlb</TypeLibraryName>
<TypeLibraryName>./debug/yapb.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\vc;..\inc;..\ext;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader />
<PrecompiledHeaderFile>core.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile>yapb.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>.\debug\inf\yapb.pch</PrecompiledHeaderOutputFile>
<ExpandAttributedSource>false</ExpandAttributedSource>
<AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput>
@ -153,12 +158,12 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FloatingPointModel>Strict</FloatingPointModel>
<StringPooling>true</StringPooling>
<StringPooling>false</StringPooling>
<InlineFunctionExpansion>Default</InlineFunctionExpansion>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DisableLanguageExtensions>false</DisableLanguageExtensions>
<LanguageStandard>Default</LanguageStandard>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -170,7 +175,7 @@
<Link>
<OutputFile>.\debug\yapb.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<ProgramDatabaseFile>.\debug\inf\yapb.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>.\debug\inf\yapb.map</MapFileName>
@ -209,7 +214,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<EnableFiberSafeOptimizations>false</EnableFiberSafeOptimizations>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\vc;..\inc;..\ext;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
@ -222,7 +227,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>None</DebugInformationFormat>
<CompileAs>CompileAsCpp</CompileAs>
<InterproceduralOptimization>SingleFile</InterproceduralOptimization>
<InterproceduralOptimization>MultiFile</InterproceduralOptimization>
<FlushDenormalResultsToZero>true</FlushDenormalResultsToZero>
<Parallelization>false</Parallelization>
<FloatingPointModel>Fast</FloatingPointModel>
@ -254,15 +259,13 @@
<OutputFile>.\release\yapb.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DelayLoadDLLs>user32.dll;ws2_32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateDebugInformation>false</GenerateDebugInformation>
<GenerateMapFile>false</GenerateMapFile>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<SetChecksum>false</SetChecksum>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TurnOffAssemblyGeneration>true</TurnOffAssemblyGeneration>
<ImportLibrary>.\release\inf\yapb.lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<MinimumRequiredVersion />
@ -270,7 +273,7 @@
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ImageHasSafeExceptionHandlers>
</ImageHasSafeExceptionHandlers>
<LinkTimeCodeGeneration>UseFastLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<FullProgramDatabaseFile>true</FullProgramDatabaseFile>
<ShowProgress>NotSet</ShowProgress>
</Link>

193
vc/yapb.vcxproj.filters Normal file
View file

@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="src">
<UniqueIdentifier>{55dff0ff-c17f-4ef8-9949-652a53eacda0}</UniqueIdentifier>
</Filter>
<Filter Include="inc">
<UniqueIdentifier>{0ad17b3f-102e-4f74-b1aa-dd492e79dca2}</UniqueIdentifier>
</Filter>
<Filter Include="inc\ext">
<UniqueIdentifier>{11ec3b8b-d4e5-4f43-964c-b84980a6d0e1}</UniqueIdentifier>
</Filter>
<Filter Include="inc\ext\crlib">
<UniqueIdentifier>{bec0fb46-08b4-4bfa-900c-d279a933ff77}</UniqueIdentifier>
</Filter>
<Filter Include="inc\ext\sdk">
<UniqueIdentifier>{f6a0fc04-bdf5-479b-8e5a-85eae698541e}</UniqueIdentifier>
</Filter>
<Filter Include="res">
<UniqueIdentifier>{5e73b918-f42b-4df9-bbe9-918289e44ad2}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\inc\config.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="..\inc\control.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="..\inc\engine.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="..\inc\graph.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="..\inc\manager.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="..\inc\message.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="..\inc\yapb.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-alloc.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-array.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-basic.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-binheap.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-color.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-complete.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-dict.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-files.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-hook.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-http.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-lambda.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-library.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-logger.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-math.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-movable.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-platform.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-random.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-string.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-twin.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-ulz.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-uniqueptr.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\crlib\crlib\cr-vector.h">
<Filter>inc\ext\crlib</Filter>
</ClInclude>
<ClInclude Include="..\ext\sdk\sdk\const.h">
<Filter>inc\ext\sdk</Filter>
</ClInclude>
<ClInclude Include="..\ext\sdk\sdk\eiface.h">
<Filter>inc\ext\sdk</Filter>
</ClInclude>
<ClInclude Include="..\ext\sdk\sdk\extdll.h">
<Filter>inc\ext\sdk</Filter>
</ClInclude>
<ClInclude Include="..\ext\sdk\sdk\meta_api.h">
<Filter>inc\ext\sdk</Filter>
</ClInclude>
<ClInclude Include="..\ext\sdk\sdk\metamod.h">
<Filter>inc\ext\sdk</Filter>
</ClInclude>
<ClInclude Include="..\ext\sdk\sdk\model.h">
<Filter>inc\ext\sdk</Filter>
</ClInclude>
<ClInclude Include="..\ext\sdk\sdk\progdefs.h">
<Filter>inc\ext\sdk</Filter>
</ClInclude>
<ClInclude Include="..\ext\sdk\sdk\util.h">
<Filter>inc\ext\sdk</Filter>
</ClInclude>
<ClInclude Include="..\inc\product.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="..\inc\support.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="..\inc\version.h">
<Filter>inc</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\android.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\botlib.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\chatlib.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\combat.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\control.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\engine.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\graph.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\linkage.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\manager.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\message.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\navigate.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\support.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="yapb.rc">
<Filter>res</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\inc\version.h.in">
<Filter>inc</Filter>
</None>
</ItemGroup>
</Project>