summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--3rdparty/libconfig/LICENSE674
-rw-r--r--3rdparty/libconfig/Makefile.in24
-rw-r--r--3rdparty/libconfig/grammar.c2001
-rw-r--r--3rdparty/libconfig/grammar.h113
-rw-r--r--3rdparty/libconfig/libconfig-1.4.8 (renamed from conf/import-tmpl/atcommand_conf.txt)0
-rw-r--r--3rdparty/libconfig/libconfig.c1615
-rw-r--r--3rdparty/libconfig/libconfig.h320
-rw-r--r--3rdparty/libconfig/parsectx.h47
-rw-r--r--3rdparty/libconfig/scanctx.c170
-rw-r--r--3rdparty/libconfig/scanctx.h61
-rw-r--r--3rdparty/libconfig/scanner.c2362
-rw-r--r--3rdparty/libconfig/scanner.h326
-rw-r--r--3rdparty/libconfig/strbuf.c57
-rw-r--r--3rdparty/libconfig/strbuf.h39
-rw-r--r--3rdparty/libconfig/wincompat.h89
-rw-r--r--Makefile.in13
-rw-r--r--conf/atcommand_athena.conf813
-rw-r--r--conf/battle/gm.conf87
-rw-r--r--conf/char_athena.conf6
-rw-r--r--conf/groups.conf274
-rw-r--r--conf/help.txt402
-rw-r--r--conf/help2.txt94
-rw-r--r--conf/log_athena.conf6
-rw-r--r--conf/login_athena.conf7
-rw-r--r--conf/msg_athena.conf12
-rwxr-xr-xconfigure288
-rw-r--r--configure.in6
-rw-r--r--doc/atcommands.txt213
-rw-r--r--doc/permissions.txt21
-rw-r--r--sql-files/upgrade_svn15572.sql3
-rw-r--r--src/char/Makefile.in20
-rw-r--r--src/char/char.c22
-rw-r--r--src/common/Makefile.in30
-rw-r--r--src/common/conf.c109
-rw-r--r--src/common/conf.h13
-rw-r--r--src/common/showmsg.c16
-rw-r--r--src/common/showmsg.h3
-rw-r--r--src/login/Makefile.in21
-rw-r--r--src/login/account.h2
-rw-r--r--src/login/account_sql.c12
-rw-r--r--src/login/login.c24
-rw-r--r--src/login/login.h4
-rw-r--r--src/map/Makefile.in24
-rw-r--r--src/map/atcommand.c1587
-rw-r--r--src/map/atcommand.h30
-rw-r--r--src/map/battle.c26
-rw-r--r--src/map/battle.h27
-rw-r--r--src/map/buyingstore.c10
-rw-r--r--src/map/chat.c4
-rw-r--r--src/map/chrif.c8
-rw-r--r--src/map/clif.c499
-rw-r--r--src/map/clif.h2
-rw-r--r--src/map/intif.c34
-rw-r--r--src/map/intif.h2
-rw-r--r--src/map/log.c15
-rw-r--r--src/map/log.h4
-rw-r--r--src/map/mail.c8
-rw-r--r--src/map/party.c8
-rw-r--r--src/map/pc.c144
-rw-r--r--src/map/pc.h37
-rw-r--r--src/map/pc_groups.c459
-rw-r--r--src/map/pc_groups.h20
-rw-r--r--src/map/script.c59
-rw-r--r--src/map/skill.c13
-rw-r--r--src/map/storage.c8
-rw-r--r--src/map/trade.c30
-rw-r--r--src/map/vending.c4
-rw-r--r--src/tool/Makefile.in14
-rw-r--r--vcproj-10/char-server_sql.vcxproj20
-rw-r--r--vcproj-10/char-server_sql.vcxproj.filters54
-rw-r--r--vcproj-10/login-server_sql.vcxproj20
-rw-r--r--vcproj-10/login-server_sql.vcxproj.filters54
-rw-r--r--vcproj-10/map-server_sql.vcxproj24
-rw-r--r--vcproj-10/map-server_sql.vcxproj.filters85
-rw-r--r--vcproj-10/mapcache.vcxproj8
-rw-r--r--vcproj-9/char-server_sql.vcproj86
-rw-r--r--vcproj-9/login-server_sql.vcproj88
-rw-r--r--vcproj-9/map-server_sql.vcproj140
-rw-r--r--vcproj-9/mapcache.vcproj12
79 files changed, 11240 insertions, 2846 deletions
diff --git a/3rdparty/libconfig/LICENSE b/3rdparty/libconfig/LICENSE
new file mode 100644
index 000000000..94a9ed024
--- /dev/null
+++ b/3rdparty/libconfig/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <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>.
diff --git a/3rdparty/libconfig/Makefile.in b/3rdparty/libconfig/Makefile.in
new file mode 100644
index 000000000..22642413d
--- /dev/null
+++ b/3rdparty/libconfig/Makefile.in
@@ -0,0 +1,24 @@
+
+LIBCONFIG_OBJ = libconfig.o grammar.o scanctx.o scanner.o strbuf.o
+LIBCONFIG_H = libconfig.h grammar.h parsectx.h scanctx.h scanner.h strbuf.h wincompat.h
+
+@SET_MAKE@
+
+#####################################################################
+.PHONY : all clean help
+
+all: $(LIBCONFIG_OBJ)
+
+clean:
+ rm -rf *.o
+
+help:
+ @echo "possible targets are 'all' 'clean' 'help'"
+ @echo "'all' - builds $(LIBCONFIG_OBJ)"
+ @echo "'clean' - deletes $(LIBCONFIG_OBJ)"
+ @echo "'help' - outputs this message"
+
+#####################################################################
+
+%.o: %.c $(LIBCONFIG_H)
+ @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
diff --git a/3rdparty/libconfig/grammar.c b/3rdparty/libconfig/grammar.c
new file mode 100644
index 000000000..e95a569f6
--- /dev/null
+++ b/3rdparty/libconfig/grammar.c
@@ -0,0 +1,2001 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.4.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names. */
+#define yyparse libconfig_yyparse
+#define yylex libconfig_yylex
+#define yyerror libconfig_yyerror
+#define yylval libconfig_yylval
+#define yychar libconfig_yychar
+#define yydebug libconfig_yydebug
+#define yynerrs libconfig_yynerrs
+
+
+/* Copy the first part of user declarations. */
+
+/* Line 189 of yacc.c */
+#line 32 "grammar.y"
+
+#include <string.h>
+#include <stdlib.h>
+#include "libconfig.h"
+#ifdef WIN32
+#include "wincompat.h"
+
+/* prevent warnings about redefined malloc/free in generated code: */
+#ifndef _STDLIB_H
+#define _STDLIB_H
+#endif
+
+#include <malloc.h>
+#endif
+#include "parsectx.h"
+#include "scanctx.h"
+
+/* these delcarations are provided to suppress compiler warnings */
+extern int libconfig_yylex();
+extern int libconfig_yyget_lineno();
+
+static const char *err_array_elem_type = "mismatched element type in array";
+static const char *err_duplicate_setting = "duplicate setting name";
+
+#define _delete(P) free((void *)(P))
+
+#define IN_ARRAY() \
+ (ctx->parent && (ctx->parent->type == CONFIG_TYPE_ARRAY))
+
+#define IN_LIST() \
+ (ctx->parent && (ctx->parent->type == CONFIG_TYPE_LIST))
+
+static void capture_parse_pos(void *scanner, struct scan_context *scan_ctx,
+ config_setting_t *setting)
+{
+ setting->line = (unsigned int)libconfig_yyget_lineno(scanner);
+ setting->file = scanctx_current_filename(scan_ctx);
+}
+
+#define CAPTURE_PARSE_POS(S) \
+ capture_parse_pos(scanner, scan_ctx, (S))
+
+void libconfig_yyerror(void *scanner, struct parse_context *ctx,
+ struct scan_context *scan_ctx, char const *s)
+{
+ if(ctx->config->error_text) return;
+ ctx->config->error_line = libconfig_yyget_lineno(scanner);
+ ctx->config->error_text = s;
+}
+
+
+
+/* Line 189 of yacc.c */
+#line 134 "grammar.c"
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ TOK_BOOLEAN = 258,
+ TOK_INTEGER = 259,
+ TOK_HEX = 260,
+ TOK_INTEGER64 = 261,
+ TOK_HEX64 = 262,
+ TOK_FLOAT = 263,
+ TOK_STRING = 264,
+ TOK_NAME = 265,
+ TOK_EQUALS = 266,
+ TOK_NEWLINE = 267,
+ TOK_ARRAY_START = 268,
+ TOK_ARRAY_END = 269,
+ TOK_LIST_START = 270,
+ TOK_LIST_END = 271,
+ TOK_COMMA = 272,
+ TOK_GROUP_START = 273,
+ TOK_GROUP_END = 274,
+ TOK_SEMICOLON = 275,
+ TOK_GARBAGE = 276,
+ TOK_ERROR = 277
+ };
+#endif
+/* Tokens. */
+#define TOK_BOOLEAN 258
+#define TOK_INTEGER 259
+#define TOK_HEX 260
+#define TOK_INTEGER64 261
+#define TOK_HEX64 262
+#define TOK_FLOAT 263
+#define TOK_STRING 264
+#define TOK_NAME 265
+#define TOK_EQUALS 266
+#define TOK_NEWLINE 267
+#define TOK_ARRAY_START 268
+#define TOK_ARRAY_END 269
+#define TOK_LIST_START 270
+#define TOK_LIST_END 271
+#define TOK_COMMA 272
+#define TOK_GROUP_START 273
+#define TOK_GROUP_END 274
+#define TOK_SEMICOLON 275
+#define TOK_GARBAGE 276
+#define TOK_ERROR 277
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c */
+#line 85 "grammar.y"
+
+ int ival;
+ long long llval;
+ double fval;
+ char *sval;
+
+
+
+/* Line 214 of yacc.c */
+#line 223 "grammar.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 264 of yacc.c */
+#line 235 "grammar.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 6
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 35
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 23
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 20
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 39
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 47
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 277
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 4, 6, 8, 11, 12, 14, 15,
+ 17, 19, 20, 26, 27, 32, 33, 38, 40, 42,
+ 44, 46, 48, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 71, 72, 74, 76, 80, 81, 83, 84
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 24, 0, -1, -1, 25, -1, 28, -1, 25, 28,
+ -1, -1, 25, -1, -1, 20, -1, 17, -1, -1,
+ 10, 29, 11, 34, 27, -1, -1, 13, 31, 40,
+ 14, -1, -1, 15, 33, 38, 16, -1, 36, -1,
+ 30, -1, 32, -1, 41, -1, 9, -1, 35, 9,
+ -1, 3, -1, 4, -1, 6, -1, 5, -1, 7,
+ -1, 8, -1, 35, -1, 34, -1, 37, 17, 34,
+ -1, -1, 37, -1, 36, -1, 39, 17, 36, -1,
+ -1, 39, -1, -1, 18, 42, 26, 19, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 100, 100, 102, 106, 107, 110, 112, 115, 117,
+ 118, 123, 122, 142, 141, 165, 164, 187, 188, 189,
+ 190, 194, 195, 199, 219, 241, 263, 285, 307, 325,
+ 353, 354, 357, 359, 363, 364, 367, 369, 374, 373
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "TOK_BOOLEAN", "TOK_INTEGER", "TOK_HEX",
+ "TOK_INTEGER64", "TOK_HEX64", "TOK_FLOAT", "TOK_STRING", "TOK_NAME",
+ "TOK_EQUALS", "TOK_NEWLINE", "TOK_ARRAY_START", "TOK_ARRAY_END",
+ "TOK_LIST_START", "TOK_LIST_END", "TOK_COMMA", "TOK_GROUP_START",
+ "TOK_GROUP_END", "TOK_SEMICOLON", "TOK_GARBAGE", "TOK_ERROR", "$accept",
+ "configuration", "setting_list", "setting_list_optional",
+ "setting_terminator", "setting", "$@1", "array", "$@2", "list", "$@3",
+ "value", "string", "simple_value", "value_list", "value_list_optional",
+ "simple_value_list", "simple_value_list_optional", "group", "$@4", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 27, 29, 28, 31, 30, 33, 32, 34, 34, 34,
+ 34, 35, 35, 36, 36, 36, 36, 36, 36, 36,
+ 37, 37, 38, 38, 39, 39, 40, 40, 42, 41
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 1, 1, 2, 0, 1, 0, 1,
+ 1, 0, 5, 0, 4, 0, 4, 1, 1, 1,
+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 0, 1, 1, 3, 0, 1, 0, 4
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 11, 0, 3, 4, 0, 1, 5, 0, 23,
+ 24, 26, 25, 27, 28, 21, 13, 15, 38, 18,
+ 19, 8, 29, 17, 20, 36, 32, 6, 10, 9,
+ 12, 22, 34, 37, 0, 30, 33, 0, 7, 0,
+ 0, 14, 0, 16, 39, 35, 31
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 2, 3, 39, 30, 4, 5, 19, 25, 20,
+ 26, 21, 22, 23, 36, 37, 33, 34, 24, 27
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -26
+static const yytype_int8 yypact[] =
+{
+ -8, -26, 12, -8, -26, 5, -26, -26, 0, -26,
+ -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
+ -26, -6, 10, -26, -26, 23, 0, -8, -26, -26,
+ -26, -26, -26, 3, 7, -26, 6, 8, -8, 14,
+ 23, -26, 0, -26, -26, -26, -26
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -26, -26, -5, -26, -26, -3, -26, -26, -26, -26,
+ -26, -25, -26, -15, -26, -26, -26, -26, -26, -26
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 7, 35, 1, 9, 10, 11, 12, 13, 14, 15,
+ 32, 28, 6, 16, 29, 17, 8, 46, 18, 31,
+ 40, 41, 38, 42, 43, 45, 9, 10, 11, 12,
+ 13, 14, 15, 44, 0, 7
+};
+
+static const yytype_int8 yycheck[] =
+{
+ 3, 26, 10, 3, 4, 5, 6, 7, 8, 9,
+ 25, 17, 0, 13, 20, 15, 11, 42, 18, 9,
+ 17, 14, 27, 17, 16, 40, 3, 4, 5, 6,
+ 7, 8, 9, 19, -1, 38
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 10, 24, 25, 28, 29, 0, 28, 11, 3,
+ 4, 5, 6, 7, 8, 9, 13, 15, 18, 30,
+ 32, 34, 35, 36, 41, 31, 33, 42, 17, 20,
+ 27, 9, 36, 39, 40, 34, 37, 38, 25, 26,
+ 17, 14, 17, 16, 19, 36, 34
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (scanner, ctx, scan_ctx, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, scanner)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, scanner, ctx, scan_ctx); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner, ctx, scan_ctx)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ void *scanner;
+ struct parse_context *ctx;
+ struct scan_context *scan_ctx;
+#endif
+{
+ if (!yyvaluep)
+ return;
+ YYUSE (scanner);
+ YYUSE (ctx);
+ YYUSE (scan_ctx);
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, scanner, ctx, scan_ctx)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ void *scanner;
+ struct parse_context *ctx;
+ struct scan_context *scan_ctx;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner, ctx, scan_ctx);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, scanner, ctx, scan_ctx)
+ YYSTYPE *yyvsp;
+ int yyrule;
+ void *scanner;
+ struct parse_context *ctx;
+ struct scan_context *scan_ctx;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , scanner, ctx, scan_ctx);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule, scanner, ctx, scan_ctx); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, scanner, ctx, scan_ctx)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+ void *scanner;
+ struct parse_context *ctx;
+ struct scan_context *scan_ctx;
+#endif
+{
+ YYUSE (yyvaluep);
+ YYUSE (scanner);
+ YYUSE (ctx);
+ YYUSE (scan_ctx);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+/* Prevent warnings from -Wmissing-prototypes. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse. |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx)
+#else
+int
+yyparse (scanner, ctx, scan_ctx)
+ void *scanner;
+ struct parse_context *ctx;
+ struct scan_context *scan_ctx;
+#endif
+#endif
+{
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 11:
+
+/* Line 1455 of yacc.c */
+#line 123 "grammar.y"
+ {
+ ctx->setting = config_setting_add(ctx->parent, (yyvsp[(1) - (1)].sval), CONFIG_TYPE_NONE);
+
+ if(ctx->setting == NULL)
+ {
+ libconfig_yyerror(scanner, ctx, scan_ctx, err_duplicate_setting);
+ YYABORT;
+ }
+ else
+ {
+ CAPTURE_PARSE_POS(ctx->setting);
+ }
+ }
+ break;
+
+ case 13:
+
+/* Line 1455 of yacc.c */
+#line 142 "grammar.y"
+ {
+ if(IN_LIST())
+ {
+ ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_ARRAY);
+ CAPTURE_PARSE_POS(ctx->parent);
+ }
+ else
+ {
+ ctx->setting->type = CONFIG_TYPE_ARRAY;
+ ctx->parent = ctx->setting;
+ ctx->setting = NULL;
+ }
+ }
+ break;
+
+ case 14:
+
+/* Line 1455 of yacc.c */
+#line 157 "grammar.y"
+ {
+ if(ctx->parent)
+ ctx->parent = ctx->parent->parent;
+ }
+ break;
+
+ case 15:
+
+/* Line 1455 of yacc.c */
+#line 165 "grammar.y"
+ {
+ if(IN_LIST())
+ {
+ ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_LIST);
+ CAPTURE_PARSE_POS(ctx->parent);
+ }
+ else
+ {
+ ctx->setting->type = CONFIG_TYPE_LIST;
+ ctx->parent = ctx->setting;
+ ctx->setting = NULL;
+ }
+ }
+ break;
+
+ case 16:
+
+/* Line 1455 of yacc.c */
+#line 180 "grammar.y"
+ {
+ if(ctx->parent)
+ ctx->parent = ctx->parent->parent;
+ }
+ break;
+
+ case 21:
+
+/* Line 1455 of yacc.c */
+#line 194 "grammar.y"
+ { parsectx_append_string(ctx, (yyvsp[(1) - (1)].sval)); free((yyvsp[(1) - (1)].sval)); }
+ break;
+
+ case 22:
+
+/* Line 1455 of yacc.c */
+#line 195 "grammar.y"
+ { parsectx_append_string(ctx, (yyvsp[(2) - (2)].sval)); free((yyvsp[(2) - (2)].sval)); }
+ break;
+
+ case 23:
+
+/* Line 1455 of yacc.c */
+#line 200 "grammar.y"
+ {
+ if(IN_ARRAY() || IN_LIST())
+ {
+ config_setting_t *e = config_setting_set_bool_elem(ctx->parent, -1,
+ (int)(yyvsp[(1) - (1)].ival));
+
+ if(! e)
+ {
+ libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+ YYABORT;
+ }
+ else
+ {
+ CAPTURE_PARSE_POS(e);
+ }
+ }
+ else
+ config_setting_set_bool(ctx->setting, (int)(yyvsp[(1) - (1)].ival));
+ }
+ break;
+
+ case 24:
+
+/* Line 1455 of yacc.c */
+#line 220 "grammar.y"
+ {
+ if(IN_ARRAY() || IN_LIST())
+ {
+ config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, (yyvsp[(1) - (1)].ival));
+ if(! e)
+ {
+ libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+ YYABORT;
+ }
+ else
+ {
+ config_setting_set_format(e, CONFIG_FORMAT_DEFAULT);
+ CAPTURE_PARSE_POS(e);
+ }
+ }
+ else
+ {
+ config_setting_set_int(ctx->setting, (yyvsp[(1) - (1)].ival));
+ config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT);
+ }
+ }
+ break;
+
+ case 25:
+
+/* Line 1455 of yacc.c */
+#line 242 "grammar.y"
+ {
+ if(IN_ARRAY() || IN_LIST())
+ {
+ config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, (yyvsp[(1) - (1)].llval));
+ if(! e)
+ {
+ libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+ YYABORT;
+ }
+ else
+ {
+ config_setting_set_format(e, CONFIG_FORMAT_DEFAULT);
+ CAPTURE_PARSE_POS(e);
+ }
+ }
+ else
+ {
+ config_setting_set_int64(ctx->setting, (yyvsp[(1) - (1)].llval));
+ config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT);
+ }
+ }
+ break;
+
+ case 26:
+
+/* Line 1455 of yacc.c */
+#line 264 "grammar.y"
+ {
+ if(IN_ARRAY() || IN_LIST())
+ {
+ config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, (yyvsp[(1) - (1)].ival));
+ if(! e)
+ {
+ libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+ YYABORT;
+ }
+ else
+ {
+ config_setting_set_format(e, CONFIG_FORMAT_HEX);
+ CAPTURE_PARSE_POS(e);
+ }
+ }
+ else
+ {
+ config_setting_set_int(ctx->setting, (yyvsp[(1) - (1)].ival));
+ config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX);
+ }
+ }
+ break;
+
+ case 27:
+
+/* Line 1455 of yacc.c */
+#line 286 "grammar.y"
+ {
+ if(IN_ARRAY() || IN_LIST())
+ {
+ config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, (yyvsp[(1) - (1)].llval));
+ if(! e)
+ {
+ libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+ YYABORT;
+ }
+ else
+ {
+ config_setting_set_format(e, CONFIG_FORMAT_HEX);
+ CAPTURE_PARSE_POS(e);
+ }
+ }
+ else
+ {
+ config_setting_set_int64(ctx->setting, (yyvsp[(1) - (1)].llval));
+ config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX);
+ }
+ }
+ break;
+
+ case 28:
+
+/* Line 1455 of yacc.c */
+#line 308 "grammar.y"
+ {
+ if(IN_ARRAY() || IN_LIST())
+ {
+ config_setting_t *e = config_setting_set_float_elem(ctx->parent, -1, (yyvsp[(1) - (1)].fval));
+ if(! e)
+ {
+ libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+ YYABORT;
+ }
+ else
+ {
+ CAPTURE_PARSE_POS(e);
+ }
+ }
+ else
+ config_setting_set_float(ctx->setting, (yyvsp[(1) - (1)].fval));
+ }
+ break;
+
+ case 29:
+
+/* Line 1455 of yacc.c */
+#line 326 "grammar.y"
+ {
+ if(IN_ARRAY() || IN_LIST())
+ {
+ const char *s = parsectx_take_string(ctx);
+ config_setting_t *e = config_setting_set_string_elem(ctx->parent, -1, s);
+ _delete(s);
+
+ if(! e)
+ {
+ libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type);
+ YYABORT;
+ }
+ else
+ {
+ CAPTURE_PARSE_POS(e);
+ }
+ }
+ else
+ {
+ const char *s = parsectx_take_string(ctx);
+ config_setting_set_string(ctx->setting, s);
+ _delete(s);
+ }
+ }
+ break;
+
+ case 38:
+
+/* Line 1455 of yacc.c */
+#line 374 "grammar.y"
+ {
+ if(IN_LIST())
+ {
+ ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_GROUP);
+ CAPTURE_PARSE_POS(ctx->parent);
+ }
+ else
+ {
+ ctx->setting->type = CONFIG_TYPE_GROUP;
+ ctx->parent = ctx->setting;
+ ctx->setting = NULL;
+ }
+ }
+ break;
+
+ case 39:
+
+/* Line 1455 of yacc.c */
+#line 389 "grammar.y"
+ {
+ if(ctx->parent)
+ ctx->parent = ctx->parent->parent;
+ }
+ break;
+
+
+
+/* Line 1455 of yacc.c */
+#line 1788 "grammar.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (scanner, ctx, scan_ctx, YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (scanner, ctx, scan_ctx, yymsg);
+ }
+ else
+ {
+ yyerror (scanner, ctx, scan_ctx, YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, scanner, ctx, scan_ctx);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, scanner, ctx, scan_ctx);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (scanner, ctx, scan_ctx, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, scanner, ctx, scan_ctx);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, scanner, ctx, scan_ctx);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+/* Line 1675 of yacc.c */
+#line 395 "grammar.y"
+
+
diff --git a/3rdparty/libconfig/grammar.h b/3rdparty/libconfig/grammar.h
new file mode 100644
index 000000000..2ce199dde
--- /dev/null
+++ b/3rdparty/libconfig/grammar.h
@@ -0,0 +1,113 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ TOK_BOOLEAN = 258,
+ TOK_INTEGER = 259,
+ TOK_HEX = 260,
+ TOK_INTEGER64 = 261,
+ TOK_HEX64 = 262,
+ TOK_FLOAT = 263,
+ TOK_STRING = 264,
+ TOK_NAME = 265,
+ TOK_EQUALS = 266,
+ TOK_NEWLINE = 267,
+ TOK_ARRAY_START = 268,
+ TOK_ARRAY_END = 269,
+ TOK_LIST_START = 270,
+ TOK_LIST_END = 271,
+ TOK_COMMA = 272,
+ TOK_GROUP_START = 273,
+ TOK_GROUP_END = 274,
+ TOK_SEMICOLON = 275,
+ TOK_GARBAGE = 276,
+ TOK_ERROR = 277
+ };
+#endif
+/* Tokens. */
+#define TOK_BOOLEAN 258
+#define TOK_INTEGER 259
+#define TOK_HEX 260
+#define TOK_INTEGER64 261
+#define TOK_HEX64 262
+#define TOK_FLOAT 263
+#define TOK_STRING 264
+#define TOK_NAME 265
+#define TOK_EQUALS 266
+#define TOK_NEWLINE 267
+#define TOK_ARRAY_START 268
+#define TOK_ARRAY_END 269
+#define TOK_LIST_START 270
+#define TOK_LIST_END 271
+#define TOK_COMMA 272
+#define TOK_GROUP_START 273
+#define TOK_GROUP_END 274
+#define TOK_SEMICOLON 275
+#define TOK_GARBAGE 276
+#define TOK_ERROR 277
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1676 of yacc.c */
+#line 85 "grammar.y"
+
+ int ival;
+ long long llval;
+ double fval;
+ char *sval;
+
+
+
+/* Line 1676 of yacc.c */
+#line 105 "grammar.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+
+
diff --git a/conf/import-tmpl/atcommand_conf.txt b/3rdparty/libconfig/libconfig-1.4.8
index e69de29bb..e69de29bb 100644
--- a/conf/import-tmpl/atcommand_conf.txt
+++ b/3rdparty/libconfig/libconfig-1.4.8
diff --git a/3rdparty/libconfig/libconfig.c b/3rdparty/libconfig/libconfig.c
new file mode 100644
index 000000000..e64213c16
--- /dev/null
+++ b/3rdparty/libconfig/libconfig.c
@@ -0,0 +1,1615 @@
+/* ----------------------------------------------------------------------------
+ libconfig - A library for processing structured configuration files
+ Copyright (C) 2005-2010 Mark A Lindner
+
+ This file is part of libconfig.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------------
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "ac_config.h"
+#endif
+
+#include "libconfig.h"
+#include "grammar.h"
+#include "scanner.h"
+#include "scanctx.h"
+#include "parsectx.h"
+#include "wincompat.h"
+
+#include <locale.h>
+
+#ifdef HAVE_XLOCALE_H
+#include <xlocale.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define PATH_TOKENS ":./"
+#define CHUNK_SIZE 16
+#define FLOAT_PRECISION 10
+
+#define _new(T) (T *)calloc(sizeof(T), 1) /* zeroed */
+#define _delete(P) free((void *)(P))
+
+/* ------------------------------------------------------------------------- */
+
+#ifndef LIBCONFIG_STATIC
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ return(TRUE);
+}
+
+#endif /* WIN32 */
+#endif /* LIBCONFIG_STATIC */
+
+/* ------------------------------------------------------------------------- */
+
+static const char *__io_error = "file I/O error";
+
+static void __config_list_destroy(config_list_t *list);
+static void __config_write_setting(const config_setting_t *setting,
+ FILE *stream, int depth,
+ unsigned short tab_width);
+
+extern int libconfig_yyparse(void *scanner, struct parse_context *ctx,
+ struct scan_context *scan_ctx);
+extern int libconfig_yylex_init_extra(struct scan_context *scan_ctx,
+ yyscan_t *scanner);
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_locale_override(void)
+{
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
+ && ! defined(__MINGW32__)
+
+ _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
+ setlocale(LC_NUMERIC, "C");
+
+#elif defined(__APPLE__)
+
+ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL);
+ uselocale(loc);
+
+#elif ((defined HAVE_NEWLOCALE) && (defined HAVE_USELOCALE))
+
+ locale_t loc = newlocale(LC_NUMERIC, "C", NULL);
+ uselocale(loc);
+
+#else
+
+#warning "No way to modify calling thread's locale!"
+
+#endif
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_locale_restore(void)
+{
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
+ && ! defined(__MINGW32__)
+
+ _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
+
+#elif ((defined HAVE_USELOCALE) && (defined HAVE_FREELOCALE))
+
+ locale_t loc = uselocale(LC_GLOBAL_LOCALE);
+ freelocale(loc);
+
+#else
+
+#warning "No way to modify calling thread's locale!"
+
+#endif
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_name_compare(const char *a, const char *b)
+{
+ const char *p, *q;
+
+ for(p = a, q = b; ; p++, q++)
+ {
+ int pd = ((! *p) || strchr(PATH_TOKENS, *p));
+ int qd = ((! *q) || strchr(PATH_TOKENS, *q));
+
+ if(pd && qd)
+ break;
+ else if(pd)
+ return(-1);
+ else if(qd)
+ return(1);
+ else if(*p < *q)
+ return(-1);
+ else if(*p > *q)
+ return(1);
+ }
+
+ return(0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_indent(FILE *stream, int depth, unsigned short w)
+{
+ if(w)
+ fprintf(stream, "%*s", (depth - 1) * w, " ");
+ else
+ {
+ int i;
+ for(i = 0; i < (depth - 1); ++i)
+ fputc('\t', stream);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_write_value(const config_value_t *value, int type,
+ int format, int depth,
+ unsigned short tab_width, FILE *stream)
+{
+ char fbuf[64];
+
+ switch(type)
+ {
+ /* boolean */
+ case CONFIG_TYPE_BOOL:
+ fputs(value->ival ? "true" : "false", stream);
+ break;
+
+ /* int */
+ case CONFIG_TYPE_INT:
+ switch(format)
+ {
+ case CONFIG_FORMAT_HEX:
+ fprintf(stream, "0x%X", value->ival);
+ break;
+
+ case CONFIG_FORMAT_DEFAULT:
+ default:
+ fprintf(stream, "%d", value->ival);
+ break;
+ }
+ break;
+
+ /* 64-bit int */
+ case CONFIG_TYPE_INT64:
+ switch(format)
+ {
+ case CONFIG_FORMAT_HEX:
+ fprintf(stream, "0x" INT64_HEX_FMT "L", value->llval);
+ break;
+
+ case CONFIG_FORMAT_DEFAULT:
+ default:
+ fprintf(stream, INT64_FMT "L", value->llval);
+ break;
+ }
+ break;
+
+ /* float */
+ case CONFIG_TYPE_FLOAT:
+ {
+ char *q;
+
+ snprintf(fbuf, sizeof(fbuf) - 3, "%.*g", FLOAT_PRECISION, value->fval);
+
+ /* check for exponent */
+ q = strchr(fbuf, 'e');
+ if(! q)
+ {
+ /* no exponent */
+ if(! strchr(fbuf, '.')) /* no decimal point */
+ strcat(fbuf, ".0");
+ else
+ {
+ /* has decimal point */
+ char *p;
+
+ for(p = fbuf + strlen(fbuf) - 1; p > fbuf; --p)
+ {
+ if(*p != '0')
+ {
+ *(++p) = '\0';
+ break;
+ }
+ }
+ }
+ }
+
+ fputs(fbuf, stream);
+ break;
+ }
+
+ /* string */
+ case CONFIG_TYPE_STRING:
+ {
+ char *p;
+
+ fputc('\"', stream);
+
+ if(value->sval)
+ {
+ for(p = value->sval; *p; p++)
+ {
+ int c = (int)*p & 0xFF;
+ switch(c)
+ {
+ case '\"':
+ case '\\':
+ fputc('\\', stream);
+ fputc(c, stream);
+ break;
+
+ case '\n':
+ fputs("\\n", stream);
+ break;
+
+ case '\r':
+ fputs("\\r", stream);
+ break;
+
+ case '\f':
+ fputs("\\f", stream);
+ break;
+
+ case '\t':
+ fputs("\\t", stream);
+ break;
+
+ default:
+ if(c >= ' ')
+ fputc(c, stream);
+ else
+ fprintf(stream, "\\x%02X", c);
+ }
+ }
+ }
+ fputc('\"', stream);
+ break;
+ }
+
+ /* list */
+ case CONFIG_TYPE_LIST:
+ {
+ config_list_t *list = value->list;
+
+ fprintf(stream, "( ");
+
+ if(list)
+ {
+ int len = list->length;
+ config_setting_t **s;
+
+ for(s = list->elements; len--; s++)
+ {
+ __config_write_value(&((*s)->value), (*s)->type,
+ config_setting_get_format(*s),
+ depth + 1, tab_width, stream);
+
+ if(len)
+ fputc(',', stream);
+
+ fputc(' ', stream);
+ }
+ }
+
+ fputc(')', stream);
+ break;
+ }
+
+ /* array */
+ case CONFIG_TYPE_ARRAY:
+ {
+ config_list_t *list = value->list;
+
+ fprintf(stream, "[ ");
+
+ if(list)
+ {
+ int len = list->length;
+ config_setting_t **s;
+
+ for(s = list->elements; len--; s++)
+ {
+ __config_write_value(&((*s)->value), (*s)->type,
+ config_setting_get_format(*s),
+ depth + 1, tab_width, stream);
+
+ if(len)
+ fputc(',', stream);
+
+ fputc(' ', stream);
+ }
+ }
+
+ fputc(']', stream);
+ break;
+ }
+
+ /* group */
+ case CONFIG_TYPE_GROUP:
+ {
+ config_list_t *list = value->list;
+
+ if(depth > 0)
+ {
+#ifdef K_AND_R_STYLE /* Horrendous, but many people like it. */
+ fputc(' ', stream);
+#else
+ fputc('\n', stream);
+
+ if(depth > 1)
+ __config_indent(stream, depth, tab_width);
+#endif
+ fprintf(stream, "{\n");
+ }
+
+ if(list)
+ {
+ int len = list->length;
+ config_setting_t **s;
+
+ for(s = list->elements; len--; s++)
+ __config_write_setting(*s, stream, depth + 1, tab_width);
+ }
+
+ if(depth > 1)
+ __config_indent(stream, depth, tab_width);
+
+ if(depth > 0)
+ fputc('}', stream);
+
+ break;
+ }
+
+ default:
+ /* this shouldn't happen, but handle it gracefully... */
+ fputs("???", stream);
+ break;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_list_add(config_list_t *list, config_setting_t *setting)
+{
+ if((list->length % CHUNK_SIZE) == 0)
+ {
+ list->elements = (config_setting_t **)realloc(
+ list->elements,
+ (list->length + CHUNK_SIZE) * sizeof(config_setting_t *));
+ }
+
+ list->elements[list->length] = setting;
+ list->length++;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static config_setting_t *__config_list_search(config_list_t *list,
+ const char *name,
+ unsigned int *idx)
+{
+ config_setting_t **found = NULL;
+ unsigned int i;
+
+ if(! list)
+ return(NULL);
+
+ for(i = 0, found = list->elements; i < list->length; i++, found++)
+ {
+ if(! (*found)->name)
+ continue;
+
+ if(! __config_name_compare(name, (*found)->name))
+ {
+ if(idx)
+ *idx = i;
+
+ return(*found);
+ }
+ }
+
+ return(NULL);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static config_setting_t *__config_list_remove(config_list_t *list, int idx)
+{
+ config_setting_t *removed = *(list->elements + idx);
+ int offset = (idx * sizeof(config_setting_t *));
+ int len = list->length - 1 - idx;
+ char *base = (char *)list->elements + offset;
+
+ memmove(base, base + sizeof(config_setting_t *),
+ len * sizeof(config_setting_t *));
+
+ list->length--;
+
+ /* possibly realloc smaller? */
+
+ return(removed);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_setting_destroy(config_setting_t *setting)
+{
+ if(setting)
+ {
+ if(setting->name)
+ _delete(setting->name);
+
+ if(setting->type == CONFIG_TYPE_STRING)
+ _delete(setting->value.sval);
+
+ else if((setting->type == CONFIG_TYPE_GROUP)
+ || (setting->type == CONFIG_TYPE_ARRAY)
+ || (setting->type == CONFIG_TYPE_LIST))
+ {
+ if(setting->value.list)
+ __config_list_destroy(setting->value.list);
+ }
+
+ if(setting->hook && setting->config->destructor)
+ setting->config->destructor(setting->hook);
+
+ _delete(setting);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_list_destroy(config_list_t *list)
+{
+ config_setting_t **p;
+ unsigned int i;
+
+ if(! list)
+ return;
+
+ if(list->elements)
+ {
+ for(p = list->elements, i = 0; i < list->length; p++, i++)
+ __config_setting_destroy(*p);
+
+ _delete(list->elements);
+ }
+
+ _delete(list);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_vector_checktype(const config_setting_t *vector, int type)
+{
+ /* if the array is empty, then it has no type yet */
+
+ if(! vector->value.list)
+ return(CONFIG_TRUE);
+
+ if(vector->value.list->length == 0)
+ return(CONFIG_TRUE);
+
+ /* if it's a list, any type is allowed */
+
+ if(vector->type == CONFIG_TYPE_LIST)
+ return(CONFIG_TRUE);
+
+ /* otherwise the first element added determines the type of the array */
+
+ return((vector->value.list->elements[0]->type == type)
+ ? CONFIG_TRUE : CONFIG_FALSE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_validate_name(const char *name)
+{
+ const char *p = name;
+
+ if(*p == '\0')
+ return(CONFIG_FALSE);
+
+ if(! isalpha(*p) && (*p != '*'))
+ return(CONFIG_FALSE);
+
+ for(++p; *p; ++p)
+ {
+ if(! (isalpha(*p) || isdigit(*p) || strchr("*_-", (int)*p)))
+ return(CONFIG_FALSE);
+ }
+
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_read(config_t *config, FILE *stream, const char *filename,
+ const char *str)
+{
+ yyscan_t scanner;
+ struct scan_context scan_ctx;
+ struct parse_context parse_ctx;
+ YY_BUFFER_STATE buffer = NULL;
+ int r;
+
+ /* Reinitialize the config */
+ void (*destructor)(void *) = config->destructor;
+ const char *include_dir = config->include_dir;
+ unsigned short tab_width = config->tab_width;
+ unsigned short flags = config->flags;
+
+ config->include_dir = NULL;
+ config_destroy(config);
+ config_init(config);
+
+ config->destructor = destructor;
+ config->include_dir = include_dir;
+ config->tab_width = tab_width;
+ config->flags = flags;
+
+ parsectx_init(&parse_ctx);
+ parse_ctx.config = config;
+ parse_ctx.parent = config->root;
+ parse_ctx.setting = config->root;
+
+ __config_locale_override();
+
+ scanctx_init(&scan_ctx, filename);
+ scan_ctx.config = config;
+ libconfig_yylex_init_extra(&scan_ctx, &scanner);
+
+ if(stream)
+ libconfig_yyrestart(stream, scanner);
+ else /* read from string */
+ buffer = libconfig_yy_scan_string(str, scanner);
+
+ libconfig_yyset_lineno(1, scanner);
+ r = libconfig_yyparse(scanner, &parse_ctx, &scan_ctx);
+
+ if(r != 0)
+ {
+ YY_BUFFER_STATE buf;
+
+ config->error_file = scanctx_current_filename(&scan_ctx);
+ config->error_type = CONFIG_ERR_PARSE;
+
+ /* Unwind the include stack, freeing the buffers and closing the files. */
+ while((buf = (YY_BUFFER_STATE)scanctx_pop_include(&scan_ctx)) != NULL)
+ libconfig_yy_delete_buffer(buf, scanner);
+ }
+
+ libconfig_yylex_destroy(scanner);
+ config->filenames = scanctx_cleanup(&scan_ctx, &(config->num_filenames));
+ parsectx_cleanup(&parse_ctx);
+
+ __config_locale_restore();
+
+ return(r == 0 ? CONFIG_TRUE : CONFIG_FALSE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_read(config_t *config, FILE *stream)
+{
+ return(__config_read(config, stream, NULL, NULL));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_read_string(config_t *config, const char *str)
+{
+ return(__config_read(config, NULL, NULL, str));
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __config_write_setting(const config_setting_t *setting,
+ FILE *stream, int depth,
+ unsigned short tab_width)
+{
+ if(depth > 1)
+ __config_indent(stream, depth, tab_width);
+
+ if(setting->name)
+ {
+ fputs(setting->name, stream);
+ fprintf(stream, " %c ", (setting->type == CONFIG_TYPE_GROUP ? ':' : '='));
+ }
+
+ __config_write_value(&(setting->value), setting->type,
+ config_setting_get_format(setting),
+ depth, tab_width, stream);
+
+ if(depth > 0)
+ {
+ fputc(';', stream);
+ fputc('\n', stream);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_write(const config_t *config, FILE *stream)
+{
+ __config_locale_override();
+
+ __config_write_setting(config->root, stream, 0, config->tab_width);
+
+ __config_locale_restore();
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_read_file(config_t *config, const char *filename)
+{
+ int ret;
+ FILE *stream = fopen(filename, "rt");
+ if(! stream)
+ {
+ config->error_text = __io_error;
+ config->error_type = CONFIG_ERR_FILE_IO;
+ return(CONFIG_FALSE);
+ }
+
+ ret = __config_read(config, stream, filename, NULL);
+ fclose(stream);
+
+ return(ret);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_write_file(config_t *config, const char *filename)
+{
+ FILE *f = fopen(filename, "wt");
+ if(! f)
+ {
+ config->error_text = __io_error;
+ config->error_type = CONFIG_ERR_FILE_IO;
+ return(CONFIG_FALSE);
+ }
+
+ config_write(config, f);
+ fclose(f);
+ config->error_type = CONFIG_ERR_NONE;
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_destroy(config_t *config)
+{
+ unsigned int count = config->num_filenames;
+ const char **f;
+
+ __config_setting_destroy(config->root);
+
+ for(f = config->filenames; count > 0; ++f, --count)
+ _delete(*f);
+
+ _delete(config->filenames);
+ _delete(config->include_dir);
+
+ memset((void *)config, 0, sizeof(config_t));
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_init(config_t *config)
+{
+ memset((void *)config, 0, sizeof(config_t));
+
+ config->root = _new(config_setting_t);
+ config->root->type = CONFIG_TYPE_GROUP;
+ config->root->config = config;
+ config->tab_width = 2;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_set_auto_convert(config_t *config, int flag)
+{
+ if(flag)
+ config->flags |= CONFIG_OPTION_AUTOCONVERT;
+ else
+ config->flags &= ~CONFIG_OPTION_AUTOCONVERT;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_get_auto_convert(const config_t *config)
+{
+ return((config->flags & CONFIG_OPTION_AUTOCONVERT) != 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static config_setting_t *config_setting_create(config_setting_t *parent,
+ const char *name, int type)
+{
+ config_setting_t *setting;
+ config_list_t *list;
+
+ if((parent->type != CONFIG_TYPE_GROUP)
+ && (parent->type != CONFIG_TYPE_ARRAY)
+ && (parent->type != CONFIG_TYPE_LIST))
+ return(NULL);
+
+ setting = _new(config_setting_t);
+ setting->parent = parent;
+ setting->name = (name == NULL) ? NULL : strdup(name);
+ setting->type = type;
+ setting->config = parent->config;
+ setting->hook = NULL;
+ setting->line = 0;
+
+ list = parent->value.list;
+
+ if(! list)
+ list = parent->value.list = _new(config_list_t);
+
+ __config_list_add(list, setting);
+
+ return(setting);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_setting_get_int(const config_setting_t *setting,
+ int *value)
+{
+ switch(setting->type)
+ {
+ case CONFIG_TYPE_INT:
+ *value = setting->value.ival;
+ return(CONFIG_TRUE);
+
+ case CONFIG_TYPE_INT64:
+ if((setting->value.llval > INT32_MAX)
+ || (setting->value.llval < INT32_MIN))
+ *value = 0;
+ else
+ *value = (int)(setting->value.llval);
+ return(CONFIG_TRUE);
+
+ case CONFIG_TYPE_FLOAT:
+ if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
+ {
+ *value = (int)(setting->value.fval);
+ return(CONFIG_TRUE);
+ }
+ else
+ { /* fall through */ }
+
+ default:
+ return(CONFIG_FALSE);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_get_int(const config_setting_t *setting)
+{
+ int value = 0;
+ __config_setting_get_int(setting, &value);
+ return(value);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_setting_get_int64(const config_setting_t *setting,
+ long long *value)
+{
+ switch(setting->type)
+ {
+ case CONFIG_TYPE_INT64:
+ *value = setting->value.llval;
+ return(CONFIG_TRUE);
+
+ case CONFIG_TYPE_INT:
+ *value = (long long)(setting->value.ival);
+ return(CONFIG_TRUE);
+
+ case CONFIG_TYPE_FLOAT:
+ if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
+ {
+ *value = (long long)(setting->value.fval);
+ return(CONFIG_TRUE);
+ }
+ else
+ { /* fall through */ }
+
+ default:
+ return(CONFIG_FALSE);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+long long config_setting_get_int64(const config_setting_t *setting)
+{
+ long long value = 0;
+ __config_setting_get_int64(setting, &value);
+ return(value);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_int(const config_setting_t *setting,
+ const char *name, int *value)
+{
+ config_setting_t *member = config_setting_get_member(setting, name);
+ if(! member)
+ return(CONFIG_FALSE);
+
+ return(__config_setting_get_int(member, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_int64(const config_setting_t *setting,
+ const char *name, long long *value)
+{
+ config_setting_t *member = config_setting_get_member(setting, name);
+ if(! member)
+ return(CONFIG_FALSE);
+
+ return(__config_setting_get_int64(member, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __config_setting_get_float(const config_setting_t *setting,
+ double *value)
+{
+ switch(setting->type)
+ {
+ case CONFIG_TYPE_FLOAT:
+ *value = setting->value.fval;
+ return(CONFIG_TRUE);
+
+ case CONFIG_TYPE_INT:
+ if(config_get_auto_convert(setting->config))
+ {
+ *value = (double)(setting->value.ival);
+ return(CONFIG_TRUE);
+ }
+ else
+ return(CONFIG_FALSE);
+
+ case CONFIG_TYPE_INT64:
+ if(config_get_auto_convert(setting->config))
+ {
+ *value = (double)(setting->value.llval);
+ return(CONFIG_TRUE);
+ }
+ else
+ { /* fall through */ }
+
+ default:
+ return(CONFIG_FALSE);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+double config_setting_get_float(const config_setting_t *setting)
+{
+ double value = 0.0;
+ __config_setting_get_float(setting, &value);
+ return(value);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_float(const config_setting_t *setting,
+ const char *name, double *value)
+{
+ config_setting_t *member = config_setting_get_member(setting, name);
+ if(! member)
+ return(CONFIG_FALSE);
+
+ return(__config_setting_get_float(member, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_string(const config_setting_t *setting,
+ const char *name, const char **value)
+{
+ config_setting_t *member = config_setting_get_member(setting, name);
+ if(! member)
+ return(CONFIG_FALSE);
+
+ if(config_setting_type(member) != CONFIG_TYPE_STRING)
+ return(CONFIG_FALSE);
+
+ *value = config_setting_get_string(member);
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_lookup_bool(const config_setting_t *setting,
+ const char *name, int *value)
+{
+ config_setting_t *member = config_setting_get_member(setting, name);
+ if(! member)
+ return(CONFIG_FALSE);
+
+ if(config_setting_type(member) != CONFIG_TYPE_BOOL)
+ return(CONFIG_FALSE);
+
+ *value = config_setting_get_bool(member);
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_int(config_setting_t *setting, int value)
+{
+ switch(setting->type)
+ {
+ case CONFIG_TYPE_NONE:
+ setting->type = CONFIG_TYPE_INT;
+ /* fall through */
+
+ case CONFIG_TYPE_INT:
+ setting->value.ival = value;
+ return(CONFIG_TRUE);
+
+ case CONFIG_TYPE_FLOAT:
+ if(config_get_auto_convert(setting->config))
+ {
+ setting->value.fval = (float)value;
+ return(CONFIG_TRUE);
+ }
+ else
+ return(CONFIG_FALSE);
+
+ default:
+ return(CONFIG_FALSE);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_int64(config_setting_t *setting, long long value)
+{
+ switch(setting->type)
+ {
+ case CONFIG_TYPE_NONE:
+ setting->type = CONFIG_TYPE_INT64;
+ /* fall through */
+
+ case CONFIG_TYPE_INT64:
+ setting->value.llval = value;
+ return(CONFIG_TRUE);
+
+ case CONFIG_TYPE_INT:
+ if((value > INT32_MAX) || (value < INT32_MIN))
+ setting->value.ival = 0;
+ else
+ setting->value.ival = (int)value;
+ return(CONFIG_TRUE);
+
+ case CONFIG_TYPE_FLOAT:
+ if(config_get_auto_convert(setting->config))
+ {
+ setting->value.fval = (float)value;
+ return(CONFIG_TRUE);
+ }
+ else
+ return(CONFIG_FALSE);
+
+ default:
+ return(CONFIG_FALSE);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_float(config_setting_t *setting, double value)
+{
+ switch(setting->type)
+ {
+ case CONFIG_TYPE_NONE:
+ setting->type = CONFIG_TYPE_FLOAT;
+ /* fall through */
+
+ case CONFIG_TYPE_FLOAT:
+ setting->value.fval = value;
+ return(CONFIG_TRUE);
+
+ case CONFIG_TYPE_INT:
+ if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
+ {
+ setting->value.ival = (int)value;
+ return(CONFIG_TRUE);
+ }
+ else
+ return(CONFIG_FALSE);
+
+ case CONFIG_TYPE_INT64:
+ if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
+ {
+ setting->value.llval = (long long)value;
+ return(CONFIG_TRUE);
+ }
+ else
+ return(CONFIG_FALSE);
+
+ default:
+ return(CONFIG_FALSE);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_get_bool(const config_setting_t *setting)
+{
+ return((setting->type == CONFIG_TYPE_BOOL) ? setting->value.ival : 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_bool(config_setting_t *setting, int value)
+{
+ if(setting->type == CONFIG_TYPE_NONE)
+ setting->type = CONFIG_TYPE_BOOL;
+ else if(setting->type != CONFIG_TYPE_BOOL)
+ return(CONFIG_FALSE);
+
+ setting->value.ival = value;
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+const char *config_setting_get_string(const config_setting_t *setting)
+{
+ return((setting->type == CONFIG_TYPE_STRING) ? setting->value.sval : NULL);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_string(config_setting_t *setting, const char *value)
+{
+ if(setting->type == CONFIG_TYPE_NONE)
+ setting->type = CONFIG_TYPE_STRING;
+ else if(setting->type != CONFIG_TYPE_STRING)
+ return(CONFIG_FALSE);
+
+ if(setting->value.sval)
+ _delete(setting->value.sval);
+
+ setting->value.sval = (value == NULL) ? NULL : strdup(value);
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_set_format(config_setting_t *setting, short format)
+{
+ if(((setting->type != CONFIG_TYPE_INT)
+ && (setting->type != CONFIG_TYPE_INT64))
+ || ((format != CONFIG_FORMAT_DEFAULT) && (format != CONFIG_FORMAT_HEX)))
+ return(CONFIG_FALSE);
+
+ setting->format = format;
+
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+short config_setting_get_format(const config_setting_t *setting)
+{
+ return(setting->format != 0 ? setting->format
+ : setting->config->default_format);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_lookup_from(config_setting_t *setting,
+ const char *path)
+{
+ const char *p = path;
+ config_setting_t *found;
+
+ for(;;)
+ {
+ while(*p && strchr(PATH_TOKENS, *p))
+ p++;
+
+ if(! *p)
+ break;
+
+ if(*p == '[')
+ found = config_setting_get_elem(setting, atoi(++p));
+ else
+ found = config_setting_get_member(setting, p);
+
+ if(! found)
+ break;
+
+ setting = found;
+
+ while(! strchr(PATH_TOKENS, *p))
+ p++;
+ }
+
+ return(*p ? NULL : setting);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_lookup(const config_t *config, const char *path)
+{
+ return(config_lookup_from(config->root, path));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_string(const config_t *config, const char *path,
+ const char **value)
+{
+ const config_setting_t *s = config_lookup(config, path);
+ if(! s)
+ return(CONFIG_FALSE);
+
+ if(config_setting_type(s) != CONFIG_TYPE_STRING)
+ return(CONFIG_FALSE);
+
+ *value = config_setting_get_string(s);
+
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_int(const config_t *config, const char *path,
+ int *value)
+{
+ const config_setting_t *s = config_lookup(config, path);
+ if(! s)
+ return(CONFIG_FALSE);
+
+ return(__config_setting_get_int(s, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_int64(const config_t *config, const char *path,
+ long long *value)
+{
+ const config_setting_t *s = config_lookup(config, path);
+ if(! s)
+ return(CONFIG_FALSE);
+
+ return(__config_setting_get_int64(s, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_float(const config_t *config, const char *path,
+ double *value)
+{
+ const config_setting_t *s = config_lookup(config, path);
+ if(! s)
+ return(CONFIG_FALSE);
+
+ return(__config_setting_get_float(s, value));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_lookup_bool(const config_t *config, const char *path, int *value)
+{
+ const config_setting_t *s = config_lookup(config, path);
+ if(! s)
+ return(CONFIG_FALSE);
+
+ if(config_setting_type(s) != CONFIG_TYPE_BOOL)
+ return(CONFIG_FALSE);
+
+ *value = config_setting_get_bool(s);
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_get_int_elem(const config_setting_t *vector, int idx)
+{
+ const config_setting_t *element = config_setting_get_elem(vector, idx);
+
+ return(element ? config_setting_get_int(element) : 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_int_elem(config_setting_t *vector,
+ int idx, int value)
+{
+ config_setting_t *element = NULL;
+
+ if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+ return(NULL);
+
+ if(idx < 0)
+ {
+ if(! __config_vector_checktype(vector, CONFIG_TYPE_INT))
+ return(NULL);
+
+ element = config_setting_create(vector, NULL, CONFIG_TYPE_INT);
+ }
+ else
+ {
+ element = config_setting_get_elem(vector, idx);
+
+ if(! element)
+ return(NULL);
+ }
+
+ if(! config_setting_set_int(element, value))
+ return(NULL);
+
+ return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+long long config_setting_get_int64_elem(const config_setting_t *vector,
+ int idx)
+{
+ const config_setting_t *element = config_setting_get_elem(vector, idx);
+
+ return(element ? config_setting_get_int64(element) : 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_int64_elem(config_setting_t *vector,
+ int idx, long long value)
+{
+ config_setting_t *element = NULL;
+
+ if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+ return(NULL);
+
+ if(idx < 0)
+ {
+ if(! __config_vector_checktype(vector, CONFIG_TYPE_INT64))
+ return(NULL);
+
+ element = config_setting_create(vector, NULL, CONFIG_TYPE_INT64);
+ }
+ else
+ {
+ element = config_setting_get_elem(vector, idx);
+
+ if(! element)
+ return(NULL);
+ }
+
+ if(! config_setting_set_int64(element, value))
+ return(NULL);
+
+ return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+double config_setting_get_float_elem(const config_setting_t *vector, int idx)
+{
+ config_setting_t *element = config_setting_get_elem(vector, idx);
+
+ return(element ? config_setting_get_float(element) : 0.0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_float_elem(config_setting_t *vector,
+ int idx, double value)
+{
+ config_setting_t *element = NULL;
+
+ if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+ return(NULL);
+
+ if(idx < 0)
+ {
+ if(! __config_vector_checktype(vector, CONFIG_TYPE_FLOAT))
+ return(NULL);
+
+ element = config_setting_create(vector, NULL, CONFIG_TYPE_FLOAT);
+ }
+ else
+ element = config_setting_get_elem(vector, idx);
+
+ if(! element)
+ return(NULL);
+
+ if(! config_setting_set_float(element, value))
+ return(NULL);
+
+ return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_get_bool_elem(const config_setting_t *vector, int idx)
+{
+ config_setting_t *element = config_setting_get_elem(vector, idx);
+
+ if(! element)
+ return(CONFIG_FALSE);
+
+ if(element->type != CONFIG_TYPE_BOOL)
+ return(CONFIG_FALSE);
+
+ return(element->value.ival);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_bool_elem(config_setting_t *vector,
+ int idx, int value)
+{
+ config_setting_t *element = NULL;
+
+ if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+ return(NULL);
+
+ if(idx < 0)
+ {
+ if(! __config_vector_checktype(vector, CONFIG_TYPE_BOOL))
+ return(NULL);
+
+ element = config_setting_create(vector, NULL, CONFIG_TYPE_BOOL);
+ }
+ else
+ element = config_setting_get_elem(vector, idx);
+
+ if(! element)
+ return(NULL);
+
+ if(! config_setting_set_bool(element, value))
+ return(NULL);
+
+ return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+const char *config_setting_get_string_elem(const config_setting_t *vector,
+ int idx)
+{
+ config_setting_t *element = config_setting_get_elem(vector, idx);
+
+ if(! element)
+ return(NULL);
+
+ if(element->type != CONFIG_TYPE_STRING)
+ return(NULL);
+
+ return(element->value.sval);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_set_string_elem(config_setting_t *vector,
+ int idx, const char *value)
+{
+ config_setting_t *element = NULL;
+
+ if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
+ return(NULL);
+
+ if(idx < 0)
+ {
+ if(! __config_vector_checktype(vector, CONFIG_TYPE_STRING))
+ return(NULL);
+
+ element = config_setting_create(vector, NULL, CONFIG_TYPE_STRING);
+ }
+ else
+ element = config_setting_get_elem(vector, idx);
+
+ if(! element)
+ return(NULL);
+
+ if(! config_setting_set_string(element, value))
+ return(NULL);
+
+ return(element);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_get_elem(const config_setting_t *vector,
+ unsigned int idx)
+{
+ config_list_t *list = vector->value.list;
+
+ if(((vector->type != CONFIG_TYPE_ARRAY)
+ && (vector->type != CONFIG_TYPE_LIST)
+ && (vector->type != CONFIG_TYPE_GROUP)) || ! list)
+ return(NULL);
+
+ if(idx >= list->length)
+ return(NULL);
+
+ return(list->elements[idx]);
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_get_member(const config_setting_t *setting,
+ const char *name)
+{
+ if(setting->type != CONFIG_TYPE_GROUP)
+ return(NULL);
+
+ return(__config_list_search(setting->value.list, name, NULL));
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_set_destructor(config_t *config, void (*destructor)(void *))
+{
+ config->destructor = destructor;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_set_include_dir(config_t *config, const char *include_dir)
+{
+ _delete(config->include_dir);
+ config->include_dir = strdup(include_dir);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_length(const config_setting_t *setting)
+{
+ if((setting->type != CONFIG_TYPE_GROUP)
+ && (setting->type != CONFIG_TYPE_ARRAY)
+ && (setting->type != CONFIG_TYPE_LIST))
+ return(0);
+
+ if(! setting->value.list)
+ return(0);
+
+ return(setting->value.list->length);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void config_setting_set_hook(config_setting_t *setting, void *hook)
+{
+ setting->hook = hook;
+}
+
+/* ------------------------------------------------------------------------- */
+
+config_setting_t *config_setting_add(config_setting_t *parent,
+ const char *name, int type)
+{
+ if((type < CONFIG_TYPE_NONE) || (type > CONFIG_TYPE_LIST))
+ return(NULL);
+
+ if(! parent)
+ return(NULL);
+
+ if((parent->type == CONFIG_TYPE_ARRAY) || (parent->type == CONFIG_TYPE_LIST))
+ name = NULL;
+
+ if(name)
+ {
+ if(! __config_validate_name(name))
+ return(NULL);
+ }
+
+ if(config_setting_get_member(parent, name) != NULL)
+ return(NULL); /* already exists */
+
+ return(config_setting_create(parent, name, type));
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_remove(config_setting_t *parent, const char *name)
+{
+ unsigned int idx;
+ config_setting_t *setting;
+
+ if(! parent)
+ return(CONFIG_FALSE);
+
+ if(parent->type != CONFIG_TYPE_GROUP)
+ return(CONFIG_FALSE);
+
+ if(! (setting = __config_list_search(parent->value.list, name, &idx)))
+ return(CONFIG_FALSE);
+
+ __config_list_remove(parent->value.list, idx);
+ __config_setting_destroy(setting);
+
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_remove_elem(config_setting_t *parent, unsigned int idx)
+{
+ config_list_t *list;
+ config_setting_t *removed = NULL;
+
+ if(! parent)
+ return(CONFIG_FALSE);
+
+ list = parent->value.list;
+
+ if(((parent->type != CONFIG_TYPE_ARRAY)
+ && (parent->type != CONFIG_TYPE_LIST)
+ && (parent->type != CONFIG_TYPE_GROUP)) || ! list)
+ return(CONFIG_FALSE);
+
+ if(idx >= list->length)
+ return(CONFIG_FALSE);
+
+ removed = __config_list_remove(list, idx);
+ __config_setting_destroy(removed);
+
+ return(CONFIG_TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int config_setting_index(const config_setting_t *setting)
+{
+ config_setting_t **found = NULL;
+ config_list_t *list;
+ int i;
+
+ if(! setting->parent)
+ return(-1);
+
+ list = setting->parent->value.list;
+
+ for(i = 0, found = list->elements; i < (int)list->length; ++i, ++found)
+ {
+ if(*found == setting)
+ return(i);
+ }
+
+ return(-1);
+}
+
+/* ------------------------------------------------------------------------- */
+/* eof */
diff --git a/3rdparty/libconfig/libconfig.h b/3rdparty/libconfig/libconfig.h
new file mode 100644
index 000000000..683bda80b
--- /dev/null
+++ b/3rdparty/libconfig/libconfig.h
@@ -0,0 +1,320 @@
+/* ----------------------------------------------------------------------------
+ libconfig - A library for processing structured configuration files
+ Copyright (C) 2005-2010 Mark A Lindner
+
+ This file is part of libconfig.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------------
+*/
+
+#ifndef __libconfig_h
+#define __libconfig_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+#if defined(LIBCONFIG_STATIC)
+#define LIBCONFIG_API
+#elif defined(LIBCONFIG_EXPORTS)
+#define LIBCONFIG_API __declspec(dllexport)
+#else /* ! LIBCONFIG_EXPORTS */
+#define LIBCONFIG_API __declspec(dllimport)
+#endif /* LIBCONFIG_STATIC */
+#else /* ! WIN32 */
+#define LIBCONFIG_API
+#endif /* WIN32 */
+
+#define LIBCONFIG_VER_MAJOR 1
+#define LIBCONFIG_VER_MINOR 4
+#define LIBCONFIG_VER_REVISION 8
+
+#include <stdio.h>
+
+#define CONFIG_TYPE_NONE 0
+#define CONFIG_TYPE_GROUP 1
+#define CONFIG_TYPE_INT 2
+#define CONFIG_TYPE_INT64 3
+#define CONFIG_TYPE_FLOAT 4
+#define CONFIG_TYPE_STRING 5
+#define CONFIG_TYPE_BOOL 6
+#define CONFIG_TYPE_ARRAY 7
+#define CONFIG_TYPE_LIST 8
+
+#define CONFIG_FORMAT_DEFAULT 0
+#define CONFIG_FORMAT_HEX 1
+
+#define CONFIG_OPTION_AUTOCONVERT 0x01
+
+#define CONFIG_TRUE (1)
+#define CONFIG_FALSE (0)
+
+typedef union config_value_t
+{
+ int ival;
+ long long llval;
+ double fval;
+ char *sval;
+ struct config_list_t *list;
+} config_value_t;
+
+typedef struct config_setting_t
+{
+ char *name;
+ short type;
+ short format;
+ config_value_t value;
+ struct config_setting_t *parent;
+ struct config_t *config;
+ void *hook;
+ unsigned int line;
+ const char *file;
+} config_setting_t;
+
+typedef enum
+{
+ CONFIG_ERR_NONE = 0,
+ CONFIG_ERR_FILE_IO = 1,
+ CONFIG_ERR_PARSE = 2
+} config_error_t;
+
+typedef struct config_list_t
+{
+ unsigned int length;
+ config_setting_t **elements;
+} config_list_t;
+
+typedef struct config_t
+{
+ config_setting_t *root;
+ void (*destructor)(void *);
+ unsigned short flags;
+ unsigned short tab_width;
+ short default_format;
+ const char *include_dir;
+ const char *error_text;
+ const char *error_file;
+ int error_line;
+ config_error_t error_type;
+ const char **filenames;
+ unsigned int num_filenames;
+} config_t;
+
+extern LIBCONFIG_API int config_read(config_t *config, FILE *stream);
+extern LIBCONFIG_API void config_write(const config_t *config, FILE *stream);
+
+extern LIBCONFIG_API void config_set_default_format(config_t *config,
+ short format);
+
+extern LIBCONFIG_API void config_set_auto_convert(config_t *config, int flag);
+extern LIBCONFIG_API int config_get_auto_convert(const config_t *config);
+
+extern LIBCONFIG_API int config_read_string(config_t *config, const char *str);
+
+extern LIBCONFIG_API int config_read_file(config_t *config,
+ const char *filename);
+extern LIBCONFIG_API int config_write_file(config_t *config,
+ const char *filename);
+
+extern LIBCONFIG_API void config_set_destructor(config_t *config,
+ void (*destructor)(void *));
+extern LIBCONFIG_API void config_set_include_dir(config_t *config,
+ const char *include_dir);
+
+extern LIBCONFIG_API void config_init(config_t *config);
+extern LIBCONFIG_API void config_destroy(config_t *config);
+
+extern LIBCONFIG_API int config_setting_get_int(
+ const config_setting_t *setting);
+extern LIBCONFIG_API long long config_setting_get_int64(
+ const config_setting_t *setting);
+extern LIBCONFIG_API double config_setting_get_float(
+ const config_setting_t *setting);
+extern LIBCONFIG_API int config_setting_get_bool(
+ const config_setting_t *setting);
+extern LIBCONFIG_API const char *config_setting_get_string(
+ const config_setting_t *setting);
+
+extern LIBCONFIG_API int config_setting_lookup_int(
+ const config_setting_t *setting, const char *name, int *value);
+extern LIBCONFIG_API int config_setting_lookup_int64(
+ const config_setting_t *setting, const char *name, long long *value);
+extern LIBCONFIG_API int config_setting_lookup_float(
+ const config_setting_t *setting, const char *name, double *value);
+extern LIBCONFIG_API int config_setting_lookup_bool(
+ const config_setting_t *setting, const char *name, int *value);
+extern LIBCONFIG_API int config_setting_lookup_string(
+ const config_setting_t *setting, const char *name, const char **value);
+
+extern LIBCONFIG_API int config_setting_set_int(config_setting_t *setting,
+ int value);
+extern LIBCONFIG_API int config_setting_set_int64(config_setting_t *setting,
+ long long value);
+extern LIBCONFIG_API int config_setting_set_float(config_setting_t *setting,
+ double value);
+extern LIBCONFIG_API int config_setting_set_bool(config_setting_t *setting,
+ int value);
+extern LIBCONFIG_API int config_setting_set_string(config_setting_t *setting,
+ const char *value);
+
+extern LIBCONFIG_API int config_setting_set_format(config_setting_t *setting,
+ short format);
+extern LIBCONFIG_API short config_setting_get_format(
+ const config_setting_t *setting);
+
+extern LIBCONFIG_API int config_setting_get_int_elem(
+ const config_setting_t *setting, int idx);
+extern LIBCONFIG_API long long config_setting_get_int64_elem(
+ const config_setting_t *setting, int idx);
+extern LIBCONFIG_API double config_setting_get_float_elem(
+ const config_setting_t *setting, int idx);
+extern LIBCONFIG_API int config_setting_get_bool_elem(
+ const config_setting_t *setting, int idx);
+extern LIBCONFIG_API const char *config_setting_get_string_elem(
+ const config_setting_t *setting, int idx);
+
+extern LIBCONFIG_API config_setting_t *config_setting_set_int_elem(
+ config_setting_t *setting, int idx, int value);
+extern LIBCONFIG_API config_setting_t *config_setting_set_int64_elem(
+ config_setting_t *setting, int idx, long long value);
+extern LIBCONFIG_API config_setting_t *config_setting_set_float_elem(
+ config_setting_t *setting, int idx, double value);
+extern LIBCONFIG_API config_setting_t *config_setting_set_bool_elem(
+ config_setting_t *setting, int idx, int value);
+extern LIBCONFIG_API config_setting_t *config_setting_set_string_elem(
+ config_setting_t *setting, int idx, const char *value);
+
+#define /* const char * */ config_get_include_dir(/* const config_t * */ C) \
+ ((C)->include_dir)
+
+#define /* int */ config_setting_type(/* const config_setting_t * */ S) \
+ ((S)->type)
+
+#define /* int */ config_setting_is_group(/* const config_setting_t * */ S) \
+ ((S)->type == CONFIG_TYPE_GROUP)
+#define /* int */ config_setting_is_array(/* const config_setting_t * */ S) \
+ ((S)->type == CONFIG_TYPE_ARRAY)
+#define /* int */ config_setting_is_list(/* const config_setting_t * */ S) \
+ ((S)->type == CONFIG_TYPE_LIST)
+
+#define /* int */ config_setting_is_aggregate( \
+ /* const config_setting_t * */ S) \
+ (((S)->type == CONFIG_TYPE_GROUP) || ((S)->type == CONFIG_TYPE_LIST) \
+ || ((S)->type == CONFIG_TYPE_ARRAY))
+
+#define /* int */ config_setting_is_number(/* const config_setting_t * */ S) \
+ (((S)->type == CONFIG_TYPE_INT) \
+ || ((S)->type == CONFIG_TYPE_INT64) \
+ || ((S)->type == CONFIG_TYPE_FLOAT))
+
+#define /* int */ config_setting_is_scalar(/* const config_setting_t * */ S) \
+ (((S)->type == CONFIG_TYPE_BOOL) || ((S)->type == CONFIG_TYPE_STRING) \
+ || config_setting_is_number(S))
+
+#define /* const char * */ config_setting_name( \
+ /* const config_setting_t * */ S) \
+ ((S)->name)
+
+#define /* config_setting_t * */ config_setting_parent( \
+ /* const config_setting_t * */ S) \
+ ((S)->parent)
+
+#define /* int */ config_setting_is_root( \
+ /* const config_setting_t * */ S) \
+ ((S)->parent ? CONFIG_FALSE : CONFIG_TRUE)
+
+extern LIBCONFIG_API int config_setting_index(const config_setting_t *setting);
+
+extern LIBCONFIG_API int config_setting_length(
+ const config_setting_t *setting);
+extern LIBCONFIG_API config_setting_t *config_setting_get_elem(
+ const config_setting_t *setting, unsigned int idx);
+
+extern LIBCONFIG_API config_setting_t *config_setting_get_member(
+ const config_setting_t *setting, const char *name);
+
+extern LIBCONFIG_API config_setting_t *config_setting_add(
+ config_setting_t *parent, const char *name, int type);
+extern LIBCONFIG_API int config_setting_remove(config_setting_t *parent,
+ const char *name);
+extern LIBCONFIG_API int config_setting_remove_elem(config_setting_t *parent,
+ unsigned int idx);
+extern LIBCONFIG_API void config_setting_set_hook(config_setting_t *setting,
+ void *hook);
+
+#define config_setting_get_hook(S) ((S)->hook)
+
+extern LIBCONFIG_API config_setting_t *config_lookup(const config_t *config,
+ const char *path);
+extern LIBCONFIG_API config_setting_t *config_lookup_from(
+ config_setting_t *setting, const char *path);
+
+extern LIBCONFIG_API int config_lookup_int(const config_t *config,
+ const char *path, int *value);
+extern LIBCONFIG_API int config_lookup_int64(const config_t *config,
+ const char *path,
+ long long *value);
+extern LIBCONFIG_API int config_lookup_float(const config_t *config,
+ const char *path, double *value);
+extern LIBCONFIG_API int config_lookup_bool(const config_t *config,
+ const char *path, int *value);
+extern LIBCONFIG_API int config_lookup_string(const config_t *config,
+ const char *path,
+ const char **value);
+
+#define /* config_setting_t * */ config_root_setting( \
+ /* const config_t * */ C) \
+ ((C)->root)
+
+#define /* void */ config_set_default_format(/* config_t * */ C, \
+ /* short */ F) \
+ (C)->default_format = (F)
+
+#define /* short */ config_get_default_format(/* config_t * */ C) \
+ ((C)->default_format)
+
+#define /* void */ config_set_tab_width(/* config_t * */ C, \
+ /* unsigned short */ W) \
+ (C)->tab_width = ((W) & 0x0F)
+
+#define /* unsigned char */ config_get_tab_width(/* const config_t * */ C) \
+ ((C)->tab_width)
+
+#define /* unsigned short */ config_setting_source_line( \
+ /* const config_setting_t * */ S) \
+ ((S)->line)
+
+#define /* const char */ config_setting_source_file( \
+ /* const config_setting_t * */ S) \
+ ((S)->file)
+
+#define /* const char * */ config_error_text(/* const config_t * */ C) \
+ ((C)->error_text)
+
+#define /* const char * */ config_error_file(/* const config_t * */ C) \
+ ((C)->error_file)
+
+#define /* int */ config_error_line(/* const config_t * */ C) \
+ ((C)->error_line)
+
+#define /* config_error_t */ config_error_type(/* const config_t * */ C) \
+ ((C)->error_type)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __libconfig_h */
diff --git a/3rdparty/libconfig/parsectx.h b/3rdparty/libconfig/parsectx.h
new file mode 100644
index 000000000..0beb1111c
--- /dev/null
+++ b/3rdparty/libconfig/parsectx.h
@@ -0,0 +1,47 @@
+/* ----------------------------------------------------------------------------
+ libconfig - A library for processing structured configuration files
+ Copyright (C) 2005-2010 Mark A Lindner
+
+ This file is part of libconfig.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------------
+*/
+
+#ifndef __libconfig_parsectx_h
+#define __libconfig_parsectx_h
+
+#include "libconfig.h"
+#include "strbuf.h"
+
+struct parse_context
+{
+ config_t *config;
+ config_setting_t *parent;
+ config_setting_t *setting;
+ char *name;
+ strbuf_t string;
+};
+
+#define parsectx_init(C) \
+ memset((C), 0, sizeof(struct parse_context))
+#define parsectx_cleanup(C) \
+ free((void *)(strbuf_release(&((C)->string))))
+
+#define parsectx_append_string(C, S) \
+ strbuf_append(&((C)->string), (S))
+#define parsectx_take_string(C) \
+ strbuf_release(&((C)->string))
+
+#endif /* __libconfig_parsectx_h */
diff --git a/3rdparty/libconfig/scanctx.c b/3rdparty/libconfig/scanctx.c
new file mode 100644
index 000000000..7d7f4994c
--- /dev/null
+++ b/3rdparty/libconfig/scanctx.c
@@ -0,0 +1,170 @@
+/* ----------------------------------------------------------------------------
+ libconfig - A library for processing structured configuration files
+ Copyright (C) 2005-2010 Mark A Lindner
+
+ This file is part of libconfig.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------------
+*/
+
+#include "scanctx.h"
+#include "wincompat.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define STRING_BLOCK_SIZE 64
+#define CHUNK_SIZE 32
+
+/* ------------------------------------------------------------------------- */
+
+static const char *err_bad_include = "cannot open include file";
+static const char *err_include_too_deep = "include file nesting too deep";
+
+/* ------------------------------------------------------------------------- */
+
+static const char *__scanctx_add_filename(struct scan_context *ctx,
+ const char *filename)
+{
+ unsigned int count = ctx->num_filenames;
+ const char **f;
+
+ for(f = ctx->filenames; count > 0; ++f, --count)
+ {
+ if(!strcmp(*f, filename))
+ {
+ free((void *)filename);
+ return(*f); /* already in list */
+ }
+ }
+
+ if((ctx->num_filenames % CHUNK_SIZE) == 0)
+ {
+ ctx->filenames = (const char **)realloc(
+ (void *)ctx->filenames,
+ (ctx->num_filenames + CHUNK_SIZE) * sizeof(const char *));
+ }
+
+ ctx->filenames[ctx->num_filenames] = filename;
+ ++ctx->num_filenames;
+ return(filename);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void scanctx_init(struct scan_context *ctx, const char *top_filename)
+{
+ memset(ctx, 0, sizeof(struct scan_context));
+ if(top_filename)
+ ctx->top_filename = __scanctx_add_filename(ctx, strdup(top_filename));
+}
+
+/* ------------------------------------------------------------------------- */
+
+const char **scanctx_cleanup(struct scan_context *ctx,
+ unsigned int *num_filenames)
+{
+ int i;
+
+ for(i = 0; i < ctx->depth; ++i)
+ fclose(ctx->streams[i]);
+
+ free((void *)(strbuf_release(&(ctx->string))));
+
+ *num_filenames = ctx->num_filenames;
+ return(ctx->filenames);
+}
+
+/* ------------------------------------------------------------------------- */
+
+FILE *scanctx_push_include(struct scan_context *ctx, void *buffer,
+ const char **error)
+{
+ FILE *fp = NULL;
+ const char *file;
+ char *full_file = NULL;
+
+ *error = NULL;
+
+ if(ctx->depth == MAX_INCLUDE_DEPTH)
+ {
+ *error = err_include_too_deep;
+ return(NULL);
+ }
+
+ file = scanctx_take_string(ctx);
+ if(ctx->config->include_dir)
+ {
+ full_file = (char *)malloc(strlen(ctx->config->include_dir) + strlen(file)
+ + 2);
+ strcpy(full_file, ctx->config->include_dir);
+ strcat(full_file, FILE_SEPARATOR);
+ strcat(full_file, file);
+ }
+
+ fp = fopen(full_file ? full_file : file, "rt");
+ free((void *)full_file);
+
+ if(fp)
+ {
+ ctx->streams[ctx->depth] = fp;
+ ctx->files[ctx->depth] = __scanctx_add_filename(ctx, file);
+ ctx->buffers[ctx->depth] = buffer;
+ ++(ctx->depth);
+ }
+ else
+ {
+ free((void *)file);
+ *error = err_bad_include;
+ }
+
+ return(fp);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void *scanctx_pop_include(struct scan_context *ctx)
+{
+ void *buffer;
+
+ if(ctx->depth == 0)
+ return(NULL); /* stack underflow */
+
+ --(ctx->depth);
+ buffer = ctx->buffers[ctx->depth];
+ fclose(ctx->streams[ctx->depth]);
+
+ return(buffer);
+}
+
+/* ------------------------------------------------------------------------- */
+
+char *scanctx_take_string(struct scan_context *ctx)
+{
+ char *r = strbuf_release(&(ctx->string));
+
+ return(r ? r : strdup(""));
+}
+
+/* ------------------------------------------------------------------------- */
+
+const char *scanctx_current_filename(struct scan_context *ctx)
+{
+ return((ctx->depth == 0) ? ctx->top_filename : ctx->files[ctx->depth - 1]);
+}
+
+/* ------------------------------------------------------------------------- */
+/* eof */
diff --git a/3rdparty/libconfig/scanctx.h b/3rdparty/libconfig/scanctx.h
new file mode 100644
index 000000000..b8cc11e3d
--- /dev/null
+++ b/3rdparty/libconfig/scanctx.h
@@ -0,0 +1,61 @@
+/* ----------------------------------------------------------------------------
+ libconfig - A library for processing structured configuration files
+ Copyright (C) 2005-2010 Mark A Lindner
+
+ This file is part of libconfig.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------------
+*/
+
+#ifndef __libconfig_scanctx_h
+#define __libconfig_scanctx_h
+
+#include "libconfig.h"
+#include "strbuf.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#define MAX_INCLUDE_DEPTH 10
+
+struct scan_context
+{
+ config_t *config;
+ const char *top_filename;
+ const char *files[MAX_INCLUDE_DEPTH];
+ void *buffers[MAX_INCLUDE_DEPTH];
+ FILE *streams[MAX_INCLUDE_DEPTH];
+ int depth;
+ strbuf_t string;
+ const char **filenames;
+ unsigned int num_filenames;
+};
+
+extern void scanctx_init(struct scan_context *ctx, const char *top_filename);
+extern const char **scanctx_cleanup(struct scan_context *ctx,
+ unsigned int *num_filenames);
+
+extern FILE *scanctx_push_include(struct scan_context *ctx, void *prev_buffer,
+ const char **error);
+extern void *scanctx_pop_include(struct scan_context *ctx);
+
+#define scanctx_append_string(C, S) \
+ strbuf_append(&((C)->string), (S))
+
+extern char *scanctx_take_string(struct scan_context *ctx);
+
+extern const char *scanctx_current_filename(struct scan_context *ctx);
+
+#endif /* __libconfig_scanctx_h */
diff --git a/3rdparty/libconfig/scanner.c b/3rdparty/libconfig/scanner.c
new file mode 100644
index 000000000..c2eb7d188
--- /dev/null
+++ b/3rdparty/libconfig/scanner.c
@@ -0,0 +1,2362 @@
+#line 2 "scanner.c"
+
+#line 4 "scanner.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE libconfig_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE libconfig_yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ int yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via libconfig_yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void libconfig_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void libconfig_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void libconfig_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void libconfig_yypop_buffer_state (yyscan_t yyscanner );
+
+static void libconfig_yyensure_buffer_stack (yyscan_t yyscanner );
+static void libconfig_yy_load_buffer_state (yyscan_t yyscanner );
+static void libconfig_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER libconfig_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE libconfig_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *libconfig_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *libconfig_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void libconfig_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer libconfig_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ libconfig_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ libconfig_yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+#define libconfig_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 41
+#define YY_END_OF_BUFFER 42
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[103] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 42, 40,
+ 21, 20, 20, 5, 40, 36, 37, 28, 40, 23,
+ 29, 40, 30, 30, 22, 38, 28, 28, 34, 35,
+ 24, 25, 21, 40, 3, 4, 3, 6, 14, 41,
+ 16, 19, 41, 21, 0, 39, 28, 29, 30, 29,
+ 0, 1, 0, 29, 0, 31, 0, 28, 28, 21,
+ 0, 0, 2, 6, 12, 0, 11, 10, 7, 8,
+ 9, 16, 18, 17, 0, 29, 29, 0, 0, 29,
+ 31, 32, 28, 28, 0, 0, 0, 29, 33, 28,
+ 26, 0, 13, 33, 27, 0, 0, 0, 0, 0,
+
+ 15, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 4, 5, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 6, 7, 1, 1, 1, 1, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 18, 19, 1,
+ 20, 1, 1, 21, 22, 23, 23, 23, 24, 25,
+ 26, 26, 26, 26, 26, 27, 26, 26, 26, 26,
+ 26, 28, 29, 30, 31, 26, 26, 32, 26, 26,
+ 33, 34, 35, 1, 36, 1, 22, 23, 37, 38,
+
+ 39, 40, 26, 26, 41, 26, 26, 42, 26, 43,
+ 26, 26, 26, 44, 29, 45, 46, 26, 26, 32,
+ 26, 26, 47, 1, 48, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[49] =
+ { 0,
+ 1, 1, 1, 1, 1, 2, 1, 1, 1, 3,
+ 1, 1, 3, 1, 1, 4, 4, 1, 1, 1,
+ 1, 4, 4, 4, 4, 3, 3, 3, 3, 3,
+ 3, 3, 1, 2, 1, 3, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[113] =
+ { 0,
+ 0, 47, 47, 48, 46, 47, 48, 49, 203, 204,
+ 200, 204, 204, 204, 198, 204, 204, 0, 45, 204,
+ 47, 50, 60, 74, 204, 204, 178, 28, 204, 204,
+ 204, 204, 64, 158, 204, 204, 183, 0, 204, 63,
+ 0, 204, 83, 195, 193, 204, 0, 88, 102, 98,
+ 62, 204, 190, 104, 119, 162, 0, 67, 65, 121,
+ 127, 124, 204, 0, 204, 0, 204, 204, 204, 204,
+ 204, 0, 204, 204, 108, 117, 122, 134, 132, 136,
+ 204, 139, 136, 116, 126, 0, 140, 142, 135, 130,
+ 0, 102, 204, 204, 0, 85, 72, 63, 98, 158,
+
+ 204, 204, 169, 173, 177, 181, 183, 187, 191, 89,
+ 66, 63
+ } ;
+
+static yyconst flex_int16_t yy_def[113] =
+ { 0,
+ 102, 1, 103, 103, 104, 104, 105, 105, 102, 102,
+ 102, 102, 102, 102, 106, 102, 102, 107, 102, 102,
+ 102, 102, 102, 102, 102, 102, 107, 107, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 108, 102, 102,
+ 109, 102, 102, 102, 106, 102, 107, 102, 102, 102,
+ 102, 102, 106, 102, 102, 102, 110, 107, 107, 102,
+ 102, 102, 102, 108, 102, 111, 102, 102, 102, 102,
+ 102, 109, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 110, 107, 107, 102, 112, 102, 102, 102, 107,
+ 107, 102, 102, 102, 107, 102, 102, 102, 102, 102,
+
+ 102, 0, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102
+ } ;
+
+static yyconst flex_int16_t yy_nxt[253] =
+ { 0,
+ 10, 11, 12, 13, 13, 14, 15, 16, 17, 18,
+ 19, 20, 19, 21, 22, 23, 24, 25, 26, 25,
+ 10, 18, 18, 18, 27, 18, 18, 18, 18, 28,
+ 18, 18, 29, 10, 30, 10, 18, 18, 18, 27,
+ 18, 18, 18, 18, 28, 18, 31, 32, 33, 36,
+ 36, 39, 39, 42, 42, 59, 37, 37, 48, 52,
+ 49, 49, 50, 50, 53, 60, 93, 34, 65, 86,
+ 51, 59, 75, 54, 75, 49, 49, 76, 76, 40,
+ 40, 43, 43, 55, 61, 51, 56, 54, 73, 49,
+ 49, 57, 82, 83, 66, 84, 67, 55, 55, 100,
+
+ 56, 99, 68, 50, 50, 69, 70, 71, 83, 98,
+ 84, 51, 55, 50, 50, 54, 74, 49, 49, 77,
+ 77, 51, 60, 76, 76, 55, 51, 78, 56, 79,
+ 97, 79, 76, 76, 80, 80, 51, 77, 77, 91,
+ 55, 61, 78, 96, 87, 78, 87, 80, 80, 88,
+ 88, 80, 80, 95, 91, 88, 88, 88, 88, 100,
+ 78, 94, 92, 101, 90, 89, 85, 62, 95, 35,
+ 35, 35, 35, 38, 38, 38, 38, 41, 41, 41,
+ 41, 45, 45, 45, 45, 47, 47, 64, 81, 64,
+ 64, 72, 46, 72, 72, 46, 44, 63, 62, 58,
+
+ 46, 44, 102, 9, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102
+ } ;
+
+static yyconst flex_int16_t yy_chk[253] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 4, 5, 6, 7, 8, 28, 3, 4, 19, 22,
+ 19, 19, 21, 21, 22, 33, 112, 2, 40, 111,
+ 21, 28, 51, 23, 51, 23, 23, 51, 51, 5,
+ 6, 7, 8, 23, 33, 21, 23, 24, 43, 24,
+ 24, 23, 110, 58, 40, 59, 40, 24, 23, 99,
+
+ 24, 98, 40, 48, 48, 40, 40, 40, 58, 97,
+ 59, 48, 24, 50, 50, 49, 43, 49, 49, 54,
+ 54, 50, 60, 75, 75, 49, 48, 54, 49, 55,
+ 96, 55, 76, 76, 55, 55, 50, 77, 77, 84,
+ 49, 60, 54, 92, 78, 77, 78, 79, 79, 78,
+ 78, 80, 80, 90, 84, 87, 87, 88, 88, 100,
+ 77, 89, 85, 100, 83, 82, 62, 61, 90, 103,
+ 103, 103, 103, 104, 104, 104, 104, 105, 105, 105,
+ 105, 106, 106, 106, 106, 107, 107, 108, 56, 108,
+ 108, 109, 53, 109, 109, 45, 44, 37, 34, 27,
+
+ 15, 11, 9, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[42] =
+ { 0,
+0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "scanner.l"
+/* -*- mode: C -*- */
+/* --------------------------------------------------------------------------
+ libconfig - A library for processing structured configuration files
+ Copyright (C) 2005-2010 Mark A Lindner
+
+ This file is part of libconfig.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, see
+ <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------------
+*/
+#define YY_NO_UNISTD_H 1
+#line 35 "scanner.l"
+
+#ifdef _MSC_VER
+#pragma warning (disable: 4996)
+#endif
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "grammar.h"
+#include "wincompat.h"
+#include "parsectx.h"
+#include "scanctx.h"
+
+#define YY_NO_INPUT // Suppress generation of useless input() function
+
+static unsigned long long fromhex(const char *s)
+{
+#ifdef __MINGW32__
+
+ /* MinGW's strtoull() seems to be broken; it only returns the lower
+ * 32 bits...
+ */
+
+ const char *p = s;
+ unsigned long long val = 0;
+
+ if(*p != '0')
+ return(0);
+
+ ++p;
+
+ if(*p != 'x' && *p != 'X')
+ return(0);
+
+ for(++p; isxdigit(*p); ++p)
+ {
+ val <<= 4;
+ val |= ((*p < 'A') ? (*p & 0xF) : (9 + (*p & 0x7)));
+ }
+
+ return(val);
+
+#else /* ! __MINGW32__ */
+
+ return(strtoull(s, NULL, 16));
+
+#endif /* __MINGW32__ */
+}
+
+
+#line 626 "scanner.c"
+
+#define INITIAL 0
+#define COMMENT 1
+#define STRING 2
+#define INCLUDE 3
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#define YY_EXTRA_TYPE struct scan_context *
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ YYSTYPE * yylval_r;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+ /* This must go here because YYSTYPE and YYLTYPE are included
+ * from bison output in section 1.*/
+ # define yylval yyg->yylval_r
+
+int libconfig_yylex_init (yyscan_t* scanner);
+
+int libconfig_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int libconfig_yylex_destroy (yyscan_t yyscanner );
+
+int libconfig_yyget_debug (yyscan_t yyscanner );
+
+void libconfig_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner );
+
+void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *libconfig_yyget_in (yyscan_t yyscanner );
+
+void libconfig_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *libconfig_yyget_out (yyscan_t yyscanner );
+
+void libconfig_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int libconfig_yyget_leng (yyscan_t yyscanner );
+
+char *libconfig_yyget_text (yyscan_t yyscanner );
+
+int libconfig_yyget_lineno (yyscan_t yyscanner );
+
+void libconfig_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner );
+
+void libconfig_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int libconfig_yywrap (yyscan_t yyscanner );
+#else
+extern int libconfig_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int libconfig_yylex \
+ (YYSTYPE * yylval_param ,yyscan_t yyscanner);
+
+#define YY_DECL int libconfig_yylex \
+ (YYSTYPE * yylval_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 100 "scanner.l"
+
+
+#line 869 "scanner.c"
+
+ yylval = yylval_param;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ libconfig_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ libconfig_yy_load_buffer_state(yyscanner );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 103 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 204 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ int yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 102 "scanner.l"
+{ BEGIN COMMENT; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 103 "scanner.l"
+{ BEGIN INITIAL; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 104 "scanner.l"
+{ /* ignore */ }
+ YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 105 "scanner.l"
+{ /* ignore */ }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 107 "scanner.l"
+{ BEGIN STRING; }
+ YY_BREAK
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+#line 108 "scanner.l"
+{ scanctx_append_string(yyextra, yytext); }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 109 "scanner.l"
+{ scanctx_append_string(yyextra, "\n"); }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 110 "scanner.l"
+{ scanctx_append_string(yyextra, "\r"); }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 111 "scanner.l"
+{ scanctx_append_string(yyextra, "\t"); }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 112 "scanner.l"
+{ scanctx_append_string(yyextra, "\f"); }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 113 "scanner.l"
+{ scanctx_append_string(yyextra, "\\"); }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 114 "scanner.l"
+{ scanctx_append_string(yyextra, "\""); }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 115 "scanner.l"
+{
+ char c[2] = { (char)(strtol(yytext + 2, NULL, 16) & 0xFF),
+ 0 };
+ scanctx_append_string(yyextra, c);
+ }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 120 "scanner.l"
+{
+ yylval->sval = scanctx_take_string(yyextra);
+ BEGIN INITIAL;
+ return(TOK_STRING);
+ }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 126 "scanner.l"
+{ BEGIN INCLUDE; }
+ YY_BREAK
+case 16:
+/* rule 16 can match eol */
+YY_RULE_SETUP
+#line 127 "scanner.l"
+{ scanctx_append_string(yyextra, yytext); }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 128 "scanner.l"
+{ scanctx_append_string(yyextra, "\\"); }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 129 "scanner.l"
+{ scanctx_append_string(yyextra, "\""); }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 130 "scanner.l"
+{
+ const char *error;
+ FILE *fp = scanctx_push_include(yyextra,
+ (void *)YY_CURRENT_BUFFER,
+ &error);
+ if(fp)
+ {
+ yyin = fp;
+ libconfig_yy_switch_to_buffer(libconfig_yy_create_buffer(yyin,YY_BUF_SIZE,yyscanner),yyscanner);
+ }
+ else
+ {
+ yyextra->config->error_text = error;
+ yyextra->config->error_file = scanctx_current_filename(
+ yyextra);
+ yyextra->config->error_line = libconfig_yyget_lineno(
+ yyscanner);
+ return TOK_ERROR;
+ }
+ BEGIN INITIAL;
+ }
+ YY_BREAK
+case 20:
+/* rule 20 can match eol */
+YY_RULE_SETUP
+#line 154 "scanner.l"
+{ /* ignore */ }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 155 "scanner.l"
+{ /* ignore */ }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 157 "scanner.l"
+{ return(TOK_EQUALS); }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 158 "scanner.l"
+{ return(TOK_COMMA); }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 159 "scanner.l"
+{ return(TOK_GROUP_START); }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 160 "scanner.l"
+{ return(TOK_GROUP_END); }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 161 "scanner.l"
+{ yylval->ival = 1; return(TOK_BOOLEAN); }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 162 "scanner.l"
+{ yylval->ival = 0; return(TOK_BOOLEAN); }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 163 "scanner.l"
+{ yylval->sval = yytext; return(TOK_NAME); }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 164 "scanner.l"
+{ yylval->fval = atof(yytext); return(TOK_FLOAT); }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 165 "scanner.l"
+{ yylval->ival = atoi(yytext); return(TOK_INTEGER); }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 166 "scanner.l"
+{ yylval->llval = atoll(yytext); return(TOK_INTEGER64); }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 167 "scanner.l"
+{
+ yylval->ival = strtoul(yytext, NULL, 16);
+ return(TOK_HEX);
+ }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 171 "scanner.l"
+{ yylval->llval = fromhex(yytext); return(TOK_HEX64); }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 172 "scanner.l"
+{ return(TOK_ARRAY_START); }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 173 "scanner.l"
+{ return(TOK_ARRAY_END); }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 174 "scanner.l"
+{ return(TOK_LIST_START); }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 175 "scanner.l"
+{ return(TOK_LIST_END); }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 176 "scanner.l"
+{ return(TOK_SEMICOLON); }
+ YY_BREAK
+case 39:
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 177 "scanner.l"
+{ /* ignore */ }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 178 "scanner.l"
+{ return(TOK_GARBAGE); }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMENT):
+case YY_STATE_EOF(STRING):
+case YY_STATE_EOF(INCLUDE):
+#line 180 "scanner.l"
+{
+ YY_BUFFER_STATE buf = (YY_BUFFER_STATE)scanctx_pop_include(
+ yyextra);
+ if(buf)
+ {
+ libconfig_yy_delete_buffer(YY_CURRENT_BUFFER,yyscanner);
+ libconfig_yy_switch_to_buffer(buf,yyscanner);
+ }
+ else
+ yyterminate();
+ }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 191 "scanner.l"
+ECHO;
+ YY_BREAK
+#line 1227 "scanner.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * libconfig_yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( libconfig_yywrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of libconfig_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = yyg->yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ libconfig_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ libconfig_yyrestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) libconfig_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 103 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ register int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ register char *yy_cp = yyg->yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 103 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 102);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ libconfig_yyrestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( libconfig_yywrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void libconfig_yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ libconfig_yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ libconfig_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ libconfig_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * libconfig_yypop_buffer_state();
+ * libconfig_yypush_buffer_state(new_buffer);
+ */
+ libconfig_yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ libconfig_yy_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (libconfig_yywrap()) processing, but the only time this flag
+ * is looked at is after libconfig_yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void libconfig_yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE libconfig_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) libconfig_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) libconfig_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ libconfig_yy_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with libconfig_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void libconfig_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ libconfig_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+ libconfig_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a libconfig_yyrestart() or at EOF.
+ */
+ static void libconfig_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ libconfig_yy_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then libconfig_yy_init_buffer was _probably_
+ * called from libconfig_yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void libconfig_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ libconfig_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ libconfig_yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from libconfig_yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from libconfig_yy_switch_to_buffer. */
+ libconfig_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void libconfig_yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ libconfig_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ libconfig_yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void libconfig_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ int num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)libconfig_yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in libconfig_yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)libconfig_yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in libconfig_yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE libconfig_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) libconfig_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ libconfig_yy_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to libconfig_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * libconfig_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return libconfig_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to libconfig_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) libconfig_yyalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = libconfig_yy_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in libconfig_yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int libconfig_yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int libconfig_yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *libconfig_yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *libconfig_yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int libconfig_yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *libconfig_yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void libconfig_yyset_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "libconfig_yyset_lineno called with no buffer" , yyscanner);
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void libconfig_yyset_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "libconfig_yyset_column called with no buffer" , yyscanner);
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see libconfig_yy_switch_to_buffer
+ */
+void libconfig_yyset_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void libconfig_yyset_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int libconfig_yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void libconfig_yyset_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylval;
+}
+
+void libconfig_yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylval = yylval_param;
+}
+
+/* User-visible API */
+
+/* libconfig_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int libconfig_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) libconfig_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* libconfig_yylex_init_extra has the same functionality as libconfig_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to libconfig_yyalloc in
+ * the yyextra field.
+ */
+
+int libconfig_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+ struct yyguts_t dummy_yyguts;
+
+ libconfig_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) libconfig_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ libconfig_yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from libconfig_yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * libconfig_yylex_init()
+ */
+ return 0;
+}
+
+/* libconfig_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int libconfig_yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ libconfig_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ libconfig_yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ libconfig_yyfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ libconfig_yyfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * libconfig_yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ libconfig_yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *libconfig_yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ return (void *) malloc( size );
+}
+
+void *libconfig_yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void libconfig_yyfree (void * ptr , yyscan_t yyscanner)
+{
+ free( (char *) ptr ); /* see libconfig_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 191 "scanner.l"
diff --git a/3rdparty/libconfig/scanner.h b/3rdparty/libconfig/scanner.h
new file mode 100644
index 000000000..baa6f771f
--- /dev/null
+++ b/3rdparty/libconfig/scanner.h
@@ -0,0 +1,326 @@
+#ifndef libconfig_yyHEADER_H
+#define libconfig_yyHEADER_H 1
+#define libconfig_yyIN_HEADER 1
+
+#line 6 "scanner.h"
+
+#line 8 "scanner.h"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 33
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+int libconfig_yylex_init (yyscan_t* scanner);
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void libconfig_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void libconfig_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void libconfig_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void libconfig_yypop_buffer_state (yyscan_t yyscanner );
+
+YY_BUFFER_STATE libconfig_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *libconfig_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *libconfig_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void libconfig_yyfree (void * ,yyscan_t yyscanner );
+
+#define libconfig_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define COMMENT 1
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int libconfig_yylex_destroy (yyscan_t yyscanner );
+
+int libconfig_yyget_debug (yyscan_t yyscanner );
+
+void libconfig_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner );
+
+void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *libconfig_yyget_in (yyscan_t yyscanner );
+
+void libconfig_yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *libconfig_yyget_out (yyscan_t yyscanner );
+
+void libconfig_yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int libconfig_yyget_leng (yyscan_t yyscanner );
+
+char *libconfig_yyget_text (yyscan_t yyscanner );
+
+int libconfig_yyget_lineno (yyscan_t yyscanner );
+
+void libconfig_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner );
+
+void libconfig_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int libconfig_yywrap (yyscan_t yyscanner );
+#else
+extern int libconfig_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int libconfig_yylex (YYSTYPE * yylval_param ,yyscan_t yyscanner);
+
+#define YY_DECL int libconfig_yylex (YYSTYPE * yylval_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 130 "scanner.l"
+
+#line 325 "scanner.h"
+#undef libconfig_yyIN_HEADER
+#endif /* libconfig_yyHEADER_H */
diff --git a/3rdparty/libconfig/strbuf.c b/3rdparty/libconfig/strbuf.c
new file mode 100644
index 000000000..d2a667a7c
--- /dev/null
+++ b/3rdparty/libconfig/strbuf.c
@@ -0,0 +1,57 @@
+/* ----------------------------------------------------------------------------
+ libconfig - A library for processing structured configuration files
+ Copyright (C) 2005-2010 Mark A Lindner
+
+ This file is part of libconfig.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------------
+*/
+
+#include "strbuf.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#define STRING_BLOCK_SIZE 64
+
+/* ------------------------------------------------------------------------- */
+
+char *strbuf_release(strbuf_t *buf)
+{
+ char *r = buf->string;
+ memset(buf, 0, sizeof(strbuf_t));
+ return(r);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void strbuf_append(strbuf_t *buf, const char *text)
+{
+ static const size_t mask = ~(STRING_BLOCK_SIZE - 1);
+ size_t len = strlen(text);
+ size_t newlen = buf->length + len + 1; /* add 1 for NUL */
+
+ if(newlen > buf->capacity)
+ {
+ buf->capacity = (newlen + (STRING_BLOCK_SIZE - 1)) & mask;
+ buf->string = (char *)realloc(buf->string, buf->capacity);
+ }
+
+ strcpy(buf->string + buf->length, text);
+ buf->length += len;
+}
+
+/* ------------------------------------------------------------------------- */
+/* eof */
diff --git a/3rdparty/libconfig/strbuf.h b/3rdparty/libconfig/strbuf.h
new file mode 100644
index 000000000..90afd44c8
--- /dev/null
+++ b/3rdparty/libconfig/strbuf.h
@@ -0,0 +1,39 @@
+/* ----------------------------------------------------------------------------
+ libconfig - A library for processing structured configuration files
+ Copyright (C) 2005-2010 Mark A Lindner
+
+ This file is part of libconfig.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------------
+*/
+
+#ifndef __libconfig_strbuf_h
+#define __libconfig_strbuf_h
+
+#include <string.h>
+#include <sys/types.h>
+
+typedef struct
+{
+ char *string;
+ size_t length;
+ size_t capacity;
+} strbuf_t;
+
+char *strbuf_release(strbuf_t *buf);
+
+void strbuf_append(strbuf_t *buf, const char *text);
+
+#endif /* __libconfig_strbuf_h */
diff --git a/3rdparty/libconfig/wincompat.h b/3rdparty/libconfig/wincompat.h
new file mode 100644
index 000000000..cfea2ec33
--- /dev/null
+++ b/3rdparty/libconfig/wincompat.h
@@ -0,0 +1,89 @@
+/* ----------------------------------------------------------------------------
+ libconfig - A library for processing structured configuration files
+ Copyright (C) 2005-2010 Mark A Lindner
+
+ This file is part of libconfig.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------------
+*/
+
+#ifndef __wincompat_h
+#define __wincompat_h
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+
+#ifdef _MSC_VER
+#pragma warning (disable: 4996)
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define snprintf _snprintf
+
+#ifndef __MINGW32__
+#define atoll _atoi64
+#define strtoull _strtoui64
+#endif /* __MINGW32__ */
+
+#endif
+
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
+ || defined(__MINGW32__))
+
+/* Why does gcc on MinGW use the Visual C++ style format directives
+ * for 64-bit integers? Inquiring minds want to know....
+ */
+
+#define INT64_FMT "%I64d"
+#define UINT64_FMT "%I64u"
+
+#define INT64_HEX_FMT "%I64X"
+
+#define FILE_SEPARATOR "\\"
+
+#else /* defined(WIN32) || defined(__MINGW32__) */
+
+#define INT64_FMT "%lld"
+#define UINT64_FMT "%llu"
+
+#define INT64_HEX_FMT "%llX"
+
+#define FILE_SEPARATOR "/"
+
+#endif /* defined(WIN32) || defined(__MINGW32__) */
+
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
+ && ! defined(__MINGW32__)
+
+#define INT64_CONST(I) (I ## i64)
+#define UINT64_CONST(I) (I ## Ui64)
+
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+
+#else /* defined(WIN32) && ! defined(__MINGW32__) */
+
+#define INT64_CONST(I) (I ## LL)
+#define UINT64_CONST(I) (I ## ULL)
+
+#endif /* defined(WIN32) && ! defined(__MINGW32__) */
+
+#endif /* __wincompat_h */
diff --git a/Makefile.in b/Makefile.in
index 02ca9b987..6fd5fff26 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -4,10 +4,10 @@ HAVE_MYSQL=@HAVE_MYSQL@
ifeq ($(HAVE_MYSQL),yes)
ALL_DEPENDS=common_sql login_sql char_sql map_sql tools import
SQL_DEPENDS=common_sql login_sql char_sql map_sql import
- COMMON_SQL_DEPENDS=mt19937ar
- LOGIN_SQL_DEPENDS=mt19937ar common_sql
- CHAR_SQL_DEPENDS=mt19937ar common_sql
- MAP_SQL_DEPENDS=mt19937ar common_sql
+ COMMON_SQL_DEPENDS=mt19937ar libconfig
+ LOGIN_SQL_DEPENDS=mt19937ar libconfig common_sql
+ CHAR_SQL_DEPENDS=mt19937ar libconfig common_sql
+ MAP_SQL_DEPENDS=mt19937ar libconfig common_sql
CONVERTERS_DEPENDS=common_sql
else
ALL_DEPENDS=needs_mysql
@@ -47,6 +47,9 @@ common_sql: $(COMMON_SQL_DEPENDS)
mt19937ar:
@$(MAKE) -C 3rdparty/mt19937ar
+libconfig:
+ @$(MAKE) -C 3rdparty/libconfig
+
login_sql: $(LOGIN_SQL_DEPENDS)
@$(MAKE) -C src/login sql
@@ -74,6 +77,7 @@ import:
clean:
@$(MAKE) -C src/common $@
@$(MAKE) -C 3rdparty/mt19937ar $@
+ @$(MAKE) -C 3rdparty/libconfig $@
@$(MAKE) -C src/login $@
@$(MAKE) -C src/char $@
@$(MAKE) -C src/map $@
@@ -85,6 +89,7 @@ help:
@echo "possible targets are:"
@echo "'common_sql' - builds object files used in SQL servers"
@echo "'mt19937ar' - builds object file of Mersenne Twister MT19937"
+ @echo "'libconfig' - builds object files of libconfig
@echo "'login_sql' - builds login server (SQL version)"
@echo "'char_sql' - builds char server (SQL version)"
@echo "'map_sql' - builds map server (SQL version)"
diff --git a/conf/atcommand_athena.conf b/conf/atcommand_athena.conf
index ce06e2b37..58813c1c7 100644
--- a/conf/atcommand_athena.conf
+++ b/conf/atcommand_athena.conf
@@ -1,753 +1,60 @@
-//--------------------------------------------------------------
-// rAthena atcommand/charcommand Configuration File
-//--------------------------------------------------------------
-
-// The symbol that will be used to recognize commands.
-// You can set any one character except control-characters (0x00-0x1f),
-// '%', '$' (party/guild chat speaking) and '/' (standard client commands).
-// command_symbol represents @commands used locally
-// char_symbol represents #commands used on other players.
-command_symbol:@
-char_symbol:#
-
-// The following settings in this file use the format "<command name>: level(@),level(#)".
-// They define the minimum GM level required to execute the associated command.
-// @ = atcommand. most work only on yourself.
-// # = charcommand. remote usage only. GMs will be able to use these on other players.
-// Adjust values as you like. Note that to activate commands for normal players,
-// (GM level 0), you also need to change the 'atcommand_gm_only' option to 'no'.
-// To completely disable a command, set its required GM level to 100.
-
-// Default levels were chosen so that they form the following hierarchy:
-// 0: Normal player
-// -> no commands accessible
-// 1: Super player
-// -> some minor advantage: storage, petrename, etc...
-// 10: Super player+
-// -> more powerful commands, like mobsearch and changegm
-// 20: Mediator
-// -> GM commands for finding players and moving to them (also kicking them)
-// 40: Sub-GM
-// -> GM commands for basic tasks, no significant impact on other players
-// 50: Sub-GM+
-// -> GM commands to spawn mobs and create guilds
-// 60: GM
-// -> almost all commands available (except administration and mass commands)
-// 80: GM Chief
-// -> can do anything, except administration commands
-// 99: Administrator
-// -> can do anything!
-// 100: Disabled
-// -> commands that will not be available to anyone
-
-// Syntax of file:
-// command: @level,#level [<alias commands seperated by commas>]
-
-// Syntax Example:
-// command: 40,40 [alias,alias2,alias3,alias4]
-// If it has more than 4 aliases you can keep adding, just like in the example below:
-
-// Example:
-// blvl: 60,60 [lvup,blevel,baselvl,baselvup,baselevel,baselvlup]
-
-//--------------------------
-// 0: normal player commands
-// None for security purposes.
-
-//-------------------------
-// 1: Super player commands
-
-// Displays a list of @ commands available to the player.
-commands: 1,1
-
-// Displays a list of # commands available to the player.
-charcommands: 1,1
-
-// Displays the server rates.
-rates: 1,1
-
-// Show server uptime since last map server restart
-uptime: 1,1
-
-// Shows/Hides the "there is a delay after a skill" message.
-showdelay: 1,1
-
-// Displays current levels and % progress.
-exp: 1,40
-
-// To change your (own) email
-// note: this command doesn't check email itself, but check structure of the email (xxx@xxx)
-// if you want be sure of each e-mail disable this option (value: 100)
-email: 1,60
-
-// Show Monster info (rates, stats, drops, MVP stuff)
-monsterinfo: 1,1 [mobinfo, mi]
-
-// Show Item info (type, price, etc)
-iteminfo: 1,1 [ii]
-
-// Show who drops an item (mobs with highest drop rate)
-whodrops: 1,1
-
-// Syncs the player's position on the client with the one stored on the server.
-refresh: 1,40
-
-// Give server time. (4 same commands)
-time: 1,1 [date,serverdate,servertime]
-
-// Displays SVN version of the server.
-version: 1,1
-
-// Suicide your character.
-die: 1,1
-
-// Enables you to rename your pet.
-petrename: 1,50
-
-// Organize a new party, with you as the party leader
-party: 1,1
-
-// Opens your Kafra storage wherever you are
-storage: 1,1
-
-// Opens your mailbox
-mail: 1,1
-
-// Opens auctions window
-auction: 1,1
-
-// Locate someone on a map, returns your coordinates if the person isn't on.
-where: 1,1
-
-// Duel organizing commands
-duel: 1,1
-invite: 1,1
-accept: 1,1
-reject: 1,1
-leave: 1,1
-
-// Main chat
-main: 1,1
-
-// Autorejecting Deals/Invites
-noask: 1,1
-
-// Displays remaining jail time
-jailtime: 1,40
-
-// Homunculus commands for players
-hominfo: 1,40
-homstats: 1,40
-
-// Kill Steal Protection
-noks: 1,1
-
-// Set Font
-font: 1,1
-
-//---------------------------
-// 10: Super player+ commands
-
-// Displays/Hides Experience gained messages
-showexp: 10,10
-
-// Displays/Hides Zeny gained messages
-showzeny: 10,10
-
-// Warps you to predefined locations in major cities.
-go: 10,10
-
-// Enables/disables autolooting from killed mobs.
-autoloot: 10,10
-
-// Enables/disables autolooting an item.
-alootid: 10,10
-
-// Allows you continue vending offline.
-autotrade: 10,10 [at]
-
-// Change Guild Master of your Guild
-changegm: 10,10
-
-// Change the leader of your party.
-changeleader: 10,10
-
-// Change the party exp- and item share rules.
-partyoption: 10,10
-
-// Command what the player's pet will say.
-pettalk: 10,10
-
-// Command what the player's homunculus will say.
-homtalk: 10,10
-
-// Locates and displays the position of a certain mob on the current map.
-mobsearch: 10,10
-// Locates and displays the position of a certain mob on your mini-map
-showmobs: 10,10
-// Prints out in which maps a monster normally spawns at (does not count script-invoked mobs)
-whereis: 10,10
-
-// Resets a Star Gladiator's marked maps
-feelreset: 10,60
-
-//----------------------
-// 20: Mediator commands
-
-// Displays helpfile in rAthena base directory (2 same commands).
-help: 20,20 [h]
-help2: 20,20 [h2]
-
-// Warp yourself to a person (3 same commands + /shift).
-goto: 20,20 [jumpto,warpto]
-
-// Displays the motd file to all players
-gmotd: 20,20
-
-// Follow a player (including warping to them)
-follow: 20,20
-
-// Sends a request to all connected GMs (via the gm whisper system)
-request: 20,100
-
-// Disconnects a user from the server (1 command + right click menu for GM "(name) force to quit").
-kick: 20,20
-
-// Changes your appearance.
-model: 20,50
-
-// To get a peco to (un)ride (2 same commands).
-mount: 20,50 [mountpeco]
-
-// Returns list of logged in characters with their position (2 same commands).
-who: 20,20 [whois]
-
-// Returns list of logged in characters with their job.
-who2: 20,20
-
-// Returns list of logged in characters with their party/guild.
-who3: 20,20
-
-// Returns list of logged in characters with their position in a specifical map.
-whomap: 20,20
-
-// Returns list of logged in characters with their job in a specifical map.
-whomap2: 20,20
-
-// Returns list of logged in characters with their party/guild in a specifical map.
-whomap3: 20,20
-
-// Displays GMs online. For those who are higher GM level than yourself,
-// only the name is shown, for the rest, it displays the same info of
-// @who+@who2+who3
-whogm: 20,20
-
-// Change your appearence to other players to a mob.
-disguise: 20,60
-
-// Restore your normal appearance.
-undisguise: 20,20
-
-// Displays the text as a normal message with the format "*name message*"
-// instead of "name : message" (Like the /me command in IRC)
-me: 20,20
-
-// Changes your name to your choice temporarily.
-fakename: 20,50
-
-// Changes your size.
-size: 20,50
-
-// Can command what other npcs (by name) can say.
-npctalk: 20,100 [npctalkc]
-
-//--------------------
-// 40: Sub-GM commands
-
-// Broadcast to the whole server. Using (1 command + /nb, /b).
-broadcast: 40,40
-
-// Broadcast to the map you are on (1 command + /lb, /nlb).
-localbroadcast: 40,40
-
-// Broadcast (with or without name)
-kami: 40,40
-// Same as kami but with blue color
-kamib: 40,40
-// Same as kami but you can choose the color (uses different packet)
-kamic: 40,40
-
-// Enables GvG on a map (2 same commands).
-gvgon: 40,100 [gpvpon]
-
-// Turns GvG (Guild vs. Guild) off on a map (2 same commands).
-gvgoff: 40,100 [gpvpoff]
-
-// Activate/Deactivate kill steal protection on a map
-allowks: 40,100
-
-// Modifies your HP/SP.
-heal: 40,60
-
-// GM Hide (total invisibility to characters and monsters) (1 command + /hide).
-hide: 40,60
-
-// Changes your job to one you specify (2 same commands).
-job: 40,60 [jobchange]
-
-// Enables you to to jump randomly on a map (that you are already on).
-jump: 40,40
-
-// Warps you to your last save point (2 same commands).
-load: 40,60 [return]
-
-// Warps you to a specific npc
-tonpc: 40,40
-
-// Saves a warp point.
-memo: 40,40
-
-// Set your character display options. (Visual effects of your character)
-option: 40,60
-
-// Sets the level of intemecy of your pet.
-petfriendly: 40,50
-
-// Sets hunger level of your pet.
-pethungry: 40,50
-
-// Turns PvP (Person vs. Person) off on a map.
-pvpoff: 40,100
-
-// Enables PvP on a map.
-pvpon: 40,100
-
-// Permanently adds a quest skill
-questskill: 40,60
-
-// Permanently removes a quest skill
-lostskill: 40,60
-
-// Sets the speed you can walk/attack at. Default is 150.
-speed: 40,60
-
-// Summons spirit spheres around you.
-spiritball: 40,60
-
-// Warp yourself to a certain map, at (x,y) coordinates (2 same commands) + also /mm or /mapmove.
-warp: 40,60 [rura,mapmove]
-
-// Changes GM clothes color (2 same commands)
-dye: 40,50 [ccolor]
-
-// Changes GM hair style (2 same commands)
-hairstyle: 40,40 [hstyle]
-
-// Changes GM hair color (2 same commands)
-haircolor: 40,50 [hcolor]
-
-// Deletes all your items.
-itemreset: 40,60
-
-// Does a skill/stat reset.
-reset: 40,60
-
-// Displays distribution of players on the server per map (% on each map which has players)
-users: 40,40
-
-// Deletes floor items in your range of sight
-cleanmap: 40,40
-
-// Kill all monsters in map (without drops)
-killmonster2: 40,40
-
-// Sets your spawn point (aka save point).
-save: 40,60
-
-// Do some visual effect on your character
-effect: 40,40
-
-// Do some visual effect on your character (misceffect)
-misceffect: 40,40
-
-// GM's magnifier
-identify: 40,40
-
-// Drop all your items
-dropall: 40,60
-
-// Store all your items
-storeall: 40,60
-
-// Allow other players to hit you out of PvP
-killable: 40,60
-
-// Look up a skill by name
-skillid: 40,40
-
-// Use a skill by id
-useskill: 40,40
-
-// What skills are required to get this skill
-skilltree: 40,40
-
-// Marriage commands
-marry: 40,40
-divorce: 40,40
-
-// Adopt a novice into a family
-adopt: 40,40
-
-// Play a Sound!
-sound: 40,40
-
-// Displays a player's storage
-storagelist: 40,40
-
-// Displays a player's cart contents
-cartlist: 40,40
-
-// Displays a player's items
-itemlist: 40,40
-
-// Displays a player's stats
-stats: 40,40
-
-//---------------------
-// 50: Sub-GM+ commands
-
-// Creates a new guild, with you as the guildmaster.
-guild: 50,50
-
-// Brings up your guild storage wherever you are.
-gstorage: 50,60
-
-// Spawns a monster, and a certain amount (2 same commands + /monster).
-monster: 50,50 [spawn]
-
-// Spawns a smaller sized version of a monster.
-monstersmall: 50,50
-
-// Spawns a larger sized version of a monster.
-monsterbig: 50,50
-
-// Spawns mobs that treat you as their master (they disappear after some time)
-summon: 50,50
-
-// It will spawn a supportive clone of the given player.
-clone: 50,50
-
-// It will spawn a supportive clone of the given player that follows the creator around.
-slaveclone: 50,50
-
-// It will spawn an aggresive clone of the given player.
-evilclone: 50,50
-
-//----------------
-// 60: GM commands
-
-// Add or Remove Cash Points to/from yourself
-cash: 60,60
-
-// Add or Remove Kafra Points to/from yourself
-points: 60,60
-
-// Starts Guild Wars
-agitstart: 60,100
-
-// Ends Guild Wars
-agitend: 60,100
-
-// Resurects yourself.
-alive: 60,60
-
-// Raises your base level by specified amount (7 same commands).
-blvl: 60,60 [lvup,blevel,baselvl,baselvup,baselevel,baselvlup]
-
-// Raises your job level by specified amount (6 same commands).
-jlvl: 60,60 [jlevel,joblvl,joblvup,joblevel,joblvlup]
-
-// Changes the sex of yourself
-changesex: 60,60
-
-// Raises your guild level by specified amount (6 same commands).
-glvl: 60,60 [glevel,guildlvl,guildlvup,guildlevel,guildlvlup]
-
-// Find an itemID based on item name
-idsearch: 60,60
-
-// Creates an item of your choosing, either Item ID or Name (1 command + /item).
-item: 60,60
-
-// Creates a complet item (card, etc...) of your choosing, either Item ID or Name.
-item2: 60,60
-
-// Deletes an item of your choosing, either Item ID or Name.
-delitem: 60,60
-
-// Kill another character without hitting them.
-kill: 60,60
-
-// Kill all monsters in map (with drops)
-killmonster: 60,60
-
-// Creates yourself a pet egg.
-makeegg: 60,60
-
-// Hatches an egg
-hatch: 60,60
-
-// Instantly kills player whose name is entered and deals insane damage to everything around
-nuke: 60,60
-
-// Enable hitting a player even when not in PvP
-killer: 60,60
-
-// Creates weapon of desired element.
-produce: 60,60
-
-// Warps a character to you (1 command + /recall).
-recall: 60,60
-
-// Refines all weapons in your items list.
-refine: 60,80
-
-// Will repair all broken items in inventory.
-repairall: 60,60
-
-// Change Status of your character
-str: 60,60
-agi: 60,60
-vit: 60,60
-int: 60,60
-dex: 60,60
-luk: 60,60
-
-// Gives all skills
-allskill: 60,60 [allskills,skillall,skillsall]
-
-// Sets GM stats to maximum
-allstats: 60,60 [allstat,statall,statsall]
-
-// Gives you stat points.
-stpoint: 60,60
-
-// Gives you skill points of desired amount.
-skpoint: 60,60
-
-// Warps all online character of a guild to you. (at least one member of that guild must be on.)
-guildrecall: 60,60
-
-// Warps all online character of a party to you.
-// (at least one party member must be online.)
-partyrecall: 60,60
-
-// Allows you to spy on any Guilds Guild chat.
-// (at least one member of that guild must be on.)
-// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes)
-guildspy: 60,60
-
-// Allows you to spy on any party's party chat.
-// (at least one party member must be online.)
-// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes)
-partyspy: 60,60
-
-// Gives you zeny (or subtracts, if amount is negative)
-zeny: 60,80
-
-// Block a player indefinitely
-block: 60,100 [charblock]
-
-// Unblock a player
-unblock: 60,100 [charunblock]
-
-// Ban a player for a limited time
-ban: 60,100 [banish,charban,charbanish]
-
-// Unban a player
-unban: 60,100 [unbanish,charunban,charunbanish]
-
-// To send specified character in jails
-jail: 60,100
-
-// To discharge a jailed character (2 same commands)
-unjail: 60,100 [discharge]
-
-// Timed jailing
-jailfor: 60,60
-
-// Create a static warp portal that lasts until the next reboot
-addwarp: 60,60
-
-// Open a trade window with any player
-trade: 60,60
-
-// Changes the player's appearance (headgear)
-changelook: 60,60
-
-// Homunculus commands for GMs
-hlvl: 60,60 [homlevel,hlevel,homlvl,homlvup]
-homevolve: 60,60 [homevolution]
-makehomun: 60,60
-homfriendly: 60,60
-homhungry: 60,60
-// Re-calculates stats, as if the homun was sent back to level 1 and re-leveled
-homshuffle: 60,60
-
-// WoE 2 start/stop commands
-agitstart2: 60,100
-agitend2: 60,100
-
-// Resets player stats
-streset: 60,60
-
-// Resets player skills
-skreset: 60,60
-
-//----------------------
-// 80: GM Chief commands
-
-// Set the server to day.
-day: 80,100
-
-// Set the server to night.
-night: 80,100
-
-// Kills everyone on the server.
-doom: 80,100
-
-// Kills everyone on the map you are on.
-doommap: 80,80
-
-// Recalls Everyone To Your Coordinates
-recallall: 80,80
-
-// Revives all players on the map.
-raisemap: 80,80
-
-// Revives all players on the server.
-raise: 80,100
-
-// Hides a NPC.
-hidenpc: 80,100
-
-// Unhides a NPC.
-shownpc: 80,100
-
-// Loads an NPC script by path
-loadnpc: 80,100
-
-// Unloads a NPC
-unloadnpc: 80,100
-
-// Move a NPC
-npcmove: 80,100
-
-// turn skills on for a map
-skillon: 80,100
-
-// turn skills off for a map
-skilloff: 80,100
-
-// Mute a player (prevents talking, usage of skills and commands)
-mute: 80,100
-
-// Unmute a player
-unmute: 80,100
-
-//---------------------------
-// 99: Administrator commands
-
-// Disconnect all users from the server
-kickall: 99,100
-
-// Closes Map-Server
-mapexit: 99,100
-
-// Used for testing packet sends from the client (debug function)
-send: 99,100
-
-// Give information about terrain/area (debug function)
-gat: 99,100
-
-// Displays a status change without really applying it (debug function)
-displaystatus: 99,100
-
-// Displays the animation of a skill without really using it (debug function)
-displayskill: 99,100
-
-// Shows information about the map
-mapinfo: 99,100
-
-// Set Map Flags
-mapflag: 99,100
-
-// Re-load item database (admin command)
-reloaditemdb: 99,100
-
-// Re-load monsters database (admin command)
-reloadmobdb: 99,100
-
-// Re-load skills database (admin command)
-reloadskilldb: 99,100
-
-// Re-load scripts (admin command)
-reloadscript: 99,100
-
-// Change a battle_config flag without rebooting server
-setbattleflag: 99,100
-
-// Re-load gm command config (admin command)
-reloadatcommand: 99,100
-
-// Re-load battle config (admin command)
-// Note that some player config settings won't take effect until relog
-// (display exp, display zeny, display skill delay fail, ...)
-reloadbattleconf: 99,100
-
-// Re-load status database (admin command)
-reloadstatusdb: 99,100
-
-// Re-load player info database (admin command)
-reloadpcdb: 99,100
-
-// Re-load the Message of the Day (admin command)
-reloadmotd: 99,100
-
-// Changes the GM level of another character
-// (lasts until reboot, or gm list reload)
-adjgmlvl: 99,100
-
-// Changes the required GM level of an @ command
-// (effect lasts until restart or command reload)
-adjcmdlvl: 99,100
-
-// [Un]Disguise All Players (admin command)
-disguiseall: 99,100
-undisguiseall: 99,100
-
-// Mutes every player on screen (admin command)
-mutearea: 99,100 [stfu]
-
-// Makes you immune to attacks (monsters/players/skills cannot target/hit you, admin command)
-battleignore: 99,100 [monsterignore]
-
-//---------------------------------------------------------------
-// 99: Weather effects
-snow: 99,100
-clouds: 99,100
-clouds2: 99,100
-fog: 99,100
-fireworks: 99,100
-sakura: 99,100
-leaves: 99,100
-
-// Stop all weather effects
-clearweather: 99,100
-
-//---------------------------------------------------------------
-// 100: Disabled commands
-
-//---------------------
-// OTHER: not a command
-import:conf/import/atcommand_conf.txt \ No newline at end of file
+/* Atcommands and charcommands configuration file */
+
+/* The symbol that will be used to recognize commands.
+You can set any one character except:
+ - control-characters (0x00-0x1f),
+ - '%' (party chat symbol)
+ - '$' (guild chat symbol)
+ - '/' (client commands symbol)
+atcommand_symbol represents @commands used locally.
+charcommand_symbol represents #commands used on other players.
+*/
+
+atcommand_symbol : "@"
+charcommand_symbol: "#"
+
+/* Command aliases
+You can define aliases for any command. Aliases work just like original
+command.
+Format is
+ <commandname>: ["<alias>", ...]
+*/
+
+aliases: {
+ mobinfo: ["monsterinfo", "mi"]
+ iteminfo: ["ii"]
+ time: ["date", "serverdate", "servertime"]
+ autotrade: ["at"]
+ help: ["h"]
+ jumpto: ["goto", "warpto"]
+ mount: ["mountpeco"]
+ who: ["whois"]
+ npctalk: ["npctalkc"]
+ gvgon: ["gpvpon"]
+ gvgoff: ["gpvpoff"]
+ jobchange: ["job"]
+ load: ["return"]
+ warp: ["rura", "mapmove"]
+ dye: ["ccolor"]
+ hairstyle: ["hstyle"]
+ haircolor: ["hcolor"]
+ monster: ["spawn"]
+ blvl: ["lvup", "blevel", "baselvl", "baselvup", "baselevel", "baselvlup"]
+ jlvl: ["jlevel", "joblvl", "joblvup", "joblevel", "joblvlup"]
+ glvl: ["glevel", "guildlvl", "guildlvup", "guildlevel", "guildlvlup"]
+ allskill: ["allskills", "skillall", "skillsall"]
+ allstats: ["allstat", "statall", "statsall"]
+ ban: ["banish"]
+ unban: ["unbanish"]
+ unjail: ["discharge"]
+ homlevel: ["hlvl", "hlevel", "homlvl", "homlvup"]
+ homevolution: ["homevolve"]
+ mutearea: ["stfu"]
+ monsterignore: ["battleignore"]
+ raise: ["revive"]
+}
+
+/* Commands help file */
+help: {
+ @include "conf/help.txt"
+} \ No newline at end of file
diff --git a/conf/battle/gm.conf b/conf/battle/gm.conf
index b7dc81909..fe07a6fc4 100644
--- a/conf/battle/gm.conf
+++ b/conf/battle/gm.conf
@@ -18,97 +18,10 @@ atcommand_slave_clone_limit: 25
// current map server.
partial_name_scan: yes
-// The level at which a player with access is considered a GM.
-// An account with an access level lower than this is not effected
-// by gm_can_drop_lv (battle_athena.conf).
-lowest_gm_level: 1
-
-// [GM] Can use all skills? (No or mimimum GM level)
-gm_all_skill: no
-
-// [GM] Can equip anything? (No or minimum GM level, can cause client errors.)
-gm_all_equipment: no
-
-// [GM] Can use skills without meeting the required conditions (items, etc...)?
-// 'no' or minimum GM level to bypass requirements.
-gm_skill_unconditional: no
-
-// [GM] Can join a password protected chat? (No or mimimum GM level)
-gm_join_chat: no
-
-// [GM] Can't be kicked from a chat? (No or mimimum GM level)
-gm_kick_chat: no
-
-// (@) GM Commands available only to GM's? (Note 1)
-// set to 'No', Normal players (gm level 0) can use GM commands _IF_ you set the command level to 0.
-// set to 'Yes', Normal players (gm level 0) can never use a GM command even if you set the command level to 0.
-atcommand_gm_only: no
-
// (@) @allstats/@str/@agi/@vit/@int/@dex/@luk
// allow gms to bypass the maximum stat parameter? ( if yes gm stats can go up to 32k ) default: no
atcommand_max_stat_bypass: no
-// Is the character of a GM account set as the object of a display by @ command etc. or not?
-hide_GM_session: no
-
-// At what GM level can you see GMs and Account/Char IDs in the @who command?
-who_display_aid: 40
-
// Ban people that try trade dupe.
// Duration of the ban, in minutes (default: 5). To disable the ban, set 0.
ban_hack_trade: 5
-
-// Set here minimum level of a (online) GM that can receive all informations about any player that try to hack, spoof a name, etc.
-// Values are from 0 to 100.
-// 100: disable information
-// 0: send to any people, including normal players
-// default: 60, according to GM definition in atcommand_athena.conf
-hack_info_GM_level: 60
-
-// The minimum GM level to bypass nowarp and nowarpto mapflags.
-// This option is mainly used in commands which modify a character's
-// map/coordinates (like @memo, @warp, @charwarp, @go, @jump, etc...).
-// default: 20 (first level after normal player or super'normal' player)
-any_warp_GM_min_level: 20
-
-// The minimum level for a GM to be unable to distribute items.
-// You should set this to the same level @item is set to in the atcommand.conf
-// NEVER SET THIS VALUE TO 0, or you will block drop/trade for normal players
-gm_cant_drop_min_lv: 1
-
-//The trust level for your GMs. Any GMs ABOVE this level will be able to distribute items
-//ie: Use Storage/Guild Storage, Drop Items, Use Vend, Trade items.
-gm_cant_drop_max_lv: 0
-
-// Minimum GM level to see the hp of every player? (Default: 60)
-// no/0 can be used to disable it.
-disp_hpmeter: 0
-
-// Minimum GM level to view players equip regardless of their setting.
-// (Default: 0 = Disabled).
-gm_viewequip_min_lv: 0
-
-// Can GMs invite non GMs to a party? (Note 1)
-// set to 'No', GMs under the party invite trust level may not invite non GMs to a party.
-// set to 'Yes', All GMs can invite any player to a party.
-// Also, as long as this is off, players cannot invite GMs to a party as well.
-gm_can_party: no
-
-//The trust level for GMs to invite to a party. Any GMs ABOVE OR EQUAL TO this level will be able to invite normal
-//players into their party in addittion to other GMs. (regardless of gm_can_party)
-gm_cant_party_min_lv: 20
-
-// Players Titles (check msg_athena.conf for title strings)
-// You may assign different titles for your Players and GMs
-title_lvl1: 1
-title_lvl2: 10
-title_lvl3: 20
-title_lvl4: 40
-title_lvl5: 50
-title_lvl6: 60
-title_lvl7: 80
-title_lvl8: 99
-
-// Minimum GM level required for client command /check (display character status) to work.
-// Default: 60
-gm_check_minlevel: 60
diff --git a/conf/char_athena.conf b/conf/char_athena.conf
index bc9e1ab1c..1b5e96a16 100644
--- a/conf/char_athena.conf
+++ b/conf/char_athena.conf
@@ -93,8 +93,10 @@ char_new_display: 0
// Maximum users able to connect to the server. Set to 0 for unlimited.
max_connect_user: 0
-// Minimum GM level that is allowed to bypass the server limit of users.
-gm_allow_level: 99
+// Group ID that is allowed to bypass the server limit of users.
+// Default: -1 = nobody (there are no groups with ID < 0)
+// See: conf/groups.conf
+gm_allow_group: -1
// How often should the server save all files? (In seconds)
// Note: Applies to all data files on TXT servers.
diff --git a/conf/groups.conf b/conf/groups.conf
new file mode 100644
index 000000000..d93d2aa09
--- /dev/null
+++ b/conf/groups.conf
@@ -0,0 +1,274 @@
+/*
+
+Player groups configuration file
+---------------------------------
+
+This file defines "player groups" and their privileges.
+
+Each group has its id and name, lists of available commands and other
+permissions, and a list of other groups it inherits from.
+
+
+Group settings
+--------------
+<id>
+Unique group number. The only required field.
+
+<name>
+Any string. If empty, defaults to "Group <id>". It is used in several @who
+commands.
+
+<level>
+Equivalent of GM level, which was used in revisions before r xxxxx. You can
+set it to any number, but usually it's between 0 (default) and 99. Members of
+groups with lower level can not perform some actions/commands (like @kick) on
+members of groups with higher level. It is what script command getgmlevel()
+returns. Group level can also be used to override trade restrictions
+(db/item_trade.txt).
+
+<commands>
+A group of settings
+ <command name> : <bool>
+or
+ <commandname> : [ <bool>, <bool> ]
+First boolean value is for atcommand, second one for charcommand. If set to
+true, group can use command. If only atcommand value is provided, false is
+assumed for charcommand. If a command name is not included, false is assumed for
+both atcommand and charcommand.
+For a full list of available commands, see: doc/atcommands.txt.
+Command names must not be aliases.
+
+<log_commands>
+Boolean value. If true then all commands used by the group will be logged to
+atcommandlog. If setting is omitted in a group definition, false is assumed.
+Requires 'log_commands' to be enabled in 'conf/log_athena.conf'.
+
+<permissions>
+A group of settings
+ <permission> : <bool>
+If a permission is not included, false is assumed.
+For a full list of available permissions, see: doc/permissions.txt
+
+<inherit>
+A list of group names that given group will inherit commands and permissions
+from. Group names are case-sensitive.
+
+Inheritance results
+-------------------
+Both multiple inheritance (Group 2 -> Group 1 and Group 3 -> Group 1) and
+recursive inheritance (Group 3 -> Group 2 -> Group 1) are allowed.
+
+Inheritance rules should not create cycles (eg Group 1 inherits from Group 2,
+and Group inherits from Group 1 at the same time). Configuration with cycles is
+considered faulty and can't be processed fully by server.
+
+Command or permission is inherited ONLY if it's not already defined for the
+group.
+If group inherits from multiple groups, and the same command or permission is
+defined for more than one of these groups, it's undefined which one will be
+inherited.
+
+Syntax
+------
+This config file uses libconfig syntax:
+http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
+
+
+Upgrading from revisions before XXXXX
+-------------------------------------
+<forum link>
+*/
+
+groups: (
+{
+ id: 0 /* group 0 is the default group for every new account */
+ name: "Player"
+ level: 0
+ inherit: ( /*empty list*/ )
+ commands: {
+ /* no commands by default */
+ }
+ permissions: {
+ /* without this basic permissions regular players could not
+ trade or party */
+ can_trade: true
+ can_party: true
+ }
+},
+{
+ id: 1
+ name: "Super Player"
+ inherit: ( "Player" ) /* can do everything Players can and more */
+ level: 0
+ commands: {
+ /* informational commands */
+ commands: true
+ charcommands: true
+ help: true
+ rates: true
+ uptime: true
+ showdelay: true
+ exp: true
+ mobinfo: true
+ iteminfo: true
+ whodrops: true
+ time: true
+ jailtime: true
+ hominfo: true
+ homstats: true
+ showexp: true
+ showzeny: true
+ whereis: true
+ /* feature commands */
+ refresh: true
+ noask: true
+ noks: true
+ main: true
+ autoloot: true
+ alootid: true
+ autotrade: true
+ request: true
+ go: true
+ }
+ permissions: {
+ }
+},
+{
+ id: 2
+ name: "Support"
+ inherit: ( "Super Player" )
+ level: 1
+ commands: {
+ version: true
+ where: true
+ jumpto: true
+ who: true
+ who2: true
+ who3: true
+ whomap: true
+ whomap2: true
+ whomap3: true
+ users: true
+ broadcast: true
+ localbroadcast: true
+ }
+ log_commands: true
+ permissions: {
+ receive_requests: true
+ view_equipment: true
+ }
+},
+{
+ id: 3
+ name: "Script Manager"
+ inherit: ( "Support" )
+ level: 1
+ commands: {
+ tonpc: true
+ hidenpc: true
+ shownpc: true
+ loadnpc: true
+ unloadnpc: true
+ npcmove: true
+ addwarp: true
+ }
+ log_commands: true
+ permissions: {
+ any_warp: true
+ }
+},
+{
+ id: 4
+ name: "Event Manager"
+ inherit: ( "Support" )
+ level: 1
+ commands: {
+ monster: true
+ monstersmall: true
+ monsterbig: true
+ killmonster2: true
+ cleanmap: true
+ item: [true, true]
+ zeny: [true, true]
+ disguise: [true, true]
+ undisguise: [true, true]
+ size: [true, true]
+ raise: true
+ raisemap: true
+ day: true
+ night: true
+ skillon: true
+ skilloff: true
+ pvpon: true
+ pvpoff: true
+ gvgon: true
+ gvgoff: true
+ allowks: true
+ me: true
+ marry: true
+ divorce: true
+ }
+ log_commands: true
+ permissions: {
+ can_trade: false
+ any_warp: true
+ }
+},
+{
+ id: 10
+ name: "Law Enforcement"
+ inherit: ( "Support" )
+ level: 2
+ commands: {
+ hide: true
+ follow: true
+ kick: true
+ disguise: true
+ fakename: true
+ option: true
+ speed: true
+ warp: true
+ kill: true
+ recall: true
+ ban: true
+ block: true
+ jail: true
+ jailfor: true
+ mute: true
+ storagelist: true
+ cartlist: true
+ itemlist: true
+ stats: true
+ }
+ log_commands: true
+ permissions: {
+ join_chat: true
+ kick_chat: true
+ hide_session: true
+ who_display_aid: true
+ hack_info: true
+ any_warp: true
+ view_hpmeter: true
+ }
+},
+{
+ id: 99
+ name: "Admin"
+ level: 99
+ inherit: ( "Support", "Law Enforcement" )
+ commands: {
+ }
+ log_commands: true
+ permissions: {
+ can_trade: true
+ can_party: true
+ all_skill: true
+ all_equipment: true
+ skill_unconditional: true
+ use_check: true
+ use_changemaptype: true
+ all_commands: true
+ }
+}
+)
+
diff --git a/conf/help.txt b/conf/help.txt
index 13a958798..5a8f5871f 100644
--- a/conf/help.txt
+++ b/conf/help.txt
@@ -1,172 +1,230 @@
-// put at first, the minimum level to display the line
- 1:To use one command, type it inside the message window where you usually type to chat.
- 20:@h/@help - display this help guide.
- 20:@h2/@help2 - displays the second help guide.
- 1:
- 1:--- MESSAGE CMD ---
- 1:@main [on|off|message] - Turns on or off global chat (@main must be on to see global chat messages)
- 1:@noask - Auto rejects Deals/Invites
- 20:@gmotd - Broadcasts the Message of The Day file to all players.
- 20:@me <message> - Displays normal text as a message in this format: *name message* (like /me in mIRC)
- 20:@fakename [Name] - Changes your name to your choice temporarly.
- 20:@npctalk [NPC Name],[Message] - Forces a NPC to display a message in normal chat.
- 40:/b/@broadcast <message> - Broadcasts a GM message with name of the GM (in yellow)
- 40:/nb <message>/@kami <message> - Broadcasts a GM message without name of the GM (in yellow)
- 40:@kamib <message> - Broadcasts a GM message without name of the GM (in blue)
- 40:/lb/@localbroadcast <message> - Broadcasts a GM message with name of the GM (in yellow) ONLY on your map
- 40:/nlb <message> - Broadcasts a GM message without name of the GM (in yellow) ONLY on your map
- 1:
- 1:--- INFORMATION CMD ---
- 1:@commands - Displays a list of commands that you can use.
- 1:@rates - Displays the server's current rates.
- 1:@uptime - Displays how long the server has been online.
- 1:@showdelay - Shows/Hides the "there is a delay after this skill" message.
- 1:@exp - Displays current levels and % progress
- 1:@mobinfo/@monsterinfo/@mi [Mob ID|Part of monster name] - Shows Monster Info (rates, stats, drops, MVP stuff)
- 1:@iteminfo/@ii [Item ID|Part of item name] - Shows Item info (type, price, etc)
- 1:@whodrops [Item ID|Part of item name] - Shows who drops an item (mobs with highest drop rates)
- 1:@version - Displays SVN version of the server
- 1:@email <actual@email> <new@email> - to change your e-mail (characters protection)
- 1:@where [char name] - Tells you the location of a character
- 1:@time/@date/@server_date/@serverdate/@server_time/@servertime - Display the date/time of the server
- 10:@showexp - Displays/Hides Experience gained.
- 10:@showzeny - Displays/Hides Zeny gained.
- 10:@mobsearch [Mob ID|Monster Name] - Shows the location of a certain mob on the current map.
- 20:@who/@whois/@w [match_text] - Display a listing of who is online and their party/guild.
- 20:@who2 [match_text] - Display a listing of who is online and their job.
- 20:@who3 [match_text] - Display a listing of who is online and where.
- 20:@whomap/@whomap2/@whomap3 [map] - like @who/@who2/@who3 but only for specifical map.
- 20:@whogm [match_text] - Like @who+@who2+who3, but only for GM.
- 40:@charcartlist <char name> - Displays all items of a player's cart.
- 60:
- 60:@guildspy <guild_name/id> - You will receive all messages of the guild channel (Chat logging must be enabled)
- 60:@partyspy <party_name/id> - You will receive all messages of the party channel (Chat logging must be enabled)
- 99:@mapinfo [<0-3> [map]] - Give information about a map (general info +: 0: no more, 1: players, 2: NPC, 3: shops/chat).
- 1:
- 1:--- CHANGE GM STATE CMD ---
- 1:@die - Kills yourself
- 10:@go <number/city_name> - Warps you to a city.
- 10: -3: (Memo point 2) 1: morocc 5: izlude 9: yuno 13: niflheim
- 10: -2: (Memo point 1) 2: geffen 6: aldebaran 10: amatsu 14: louyang
- 10: -1: (Memo point 0) 3: payon 7: xmas (lutie) 11: gonryun 15: start point
- 10: 0: prontera 4: alberta 8: comodo 12: umbala 16: prison/jail
- 10:
- 20:/shift/@jumpto/@warpto/@goto <char name> - Warps you to selected character
- 20:@follow <char_name> - follow a player
- 20:@mountpeco - Give/remove you a peco (Class is required, but not skill)
- 20:@disguise <monster_name_or_monster_ID> - Change your appearence to other players to a mob.
- 20:@undisguise - Restore your normal appearance.
- 20:@model <hair ID: 0-17> <hair color: 0-8> <clothes color: 0-4> - Changes your characters appearence.
- 20:@size <1-3> Changes your size (1-Smallest 2-Biggest 3-Normal)
- 40:/hide/@hide - Makes you character invisible (GM invisibility). Type /hide or@hide again become visible.
- 40:@save - Sets respawn point to current spot
- 40:@load/@return - Warps you to your save point
- 40:/mm//mapmove/@warp/@rura/@mapmove <mapname> <x> <y> - Warps you to the selected position
- 40:@jump [x [y]]- Randomly warps you like a flywing.
- 40:@job/@jobchange <job ID> - Changes your job
- 40: 0: Novice 18: Alchemist 4015: Paladin
- 40: 1: Swordman 19: Bard 4016: Champion
- 40: 2: Mage 20: Dancer 4017: Professor
- 40: 3: Archer 23: Super Novice 4018: Stalker
- 40: 4: Acolyte 4001: High Novice 4019: Creator
- 40: 5: Merchant 4002: High Swordman 4020: Clown
- 40: 6: Thief 4003: High Mage 4021: Gypsy
- 40: 7: Knight 4004: High Archer 4046: Taekwon
- 40: 8: Priest 4005: High Acolyte 4047: Star Gladiator
- 40: 9: Wizard 4006: High Merchant 4049: Soul Linker
- 40: 10: Blacksmith 4007: High Thief 24: Gunslinger
- 40: 11: Hunter 4008: Lord Knight 25: Ninja
- 40: 12: Assassin 4009: High Priest
- 40: 14: Crusader 4010: High Wizard
- 40: 15: Monk 4011: Whitesmith
- 40: 16: Sage 4012: Sniper
- 40: 17: Rogue 4013: Assassin Cross
- 40: ---- Baby Classes ----
- 40: 4023: Baby 4024: Baby Swordman 4025: Baby Mage
- 40: 4026: Baby Archer 4027: Baby Acolyte 4028: Baby Merchant
- 40: 4029: Baby Thief 4030: Baby Knight 4031: Baby Priest
- 40: 4032: Baby Wizard 4033: Baby Blacksmith 4034: Baby Hunter
- 40: 4035: Baby Assassin 4037: Baby Crusader 4038: Baby Monk
- 40: 4039: Baby Sage 4040: Baby Rogue 4041: Baby Alchemist
- 40: 4042: Baby Bard 4043: Baby Dancer 4045: Super Baby
- 40:
- 40: <param1> <param2> <p3>(stackable) <param3> <param3>
- 40: 1 Petrified (stackable) 01 Sight 32 Peco Peco riding 2048 Orc Head
- 40: 2 Frozen 01 Poison 02 Hide 64 GM Perfect Hide 4096 Wedding Sprites
- 40: 3 Stunned 02 Cursed 04 Cloak 128 Level 2 Cart 8192 Ruwach
- 40: 4 Sleeping 04 Silenced 08 Level 1 Cart 256 Level 3 Cart
- 40: 6 darkness 08 ??? 16 Falcon 512 Level 4 Cart
- 40: 16 darkness 1024 Level 5 Cart
- 40:
- 40:@heal [<HP> <SP>] - Heals the desired amount of HP and SP. No value specified will do a full heal.
- 40:@option <param1> <param2> <param3> - Adds different visual effects on or around your character
- 40:@dye/@ccolor <clothes color: 0-4> - Changes your characters appearence (only clothes color).
- 40:@hairstyle/@hstyle <hair ID: 0-17> - Changes your characters appearence (only hair style).
- 40:@haircolor/@hcolor <hair color: 0-8> - Changes your characters appearence (only hair color).
- 40:@speed <1-1000> - Changes you walking speed. 1 being the fastest and 1000 the slowest. Default 150.
- 40:@effect <effect_id> [flag] - Give an efect to your character.
- 40:@dropall - throws all your possession on the ground
- 40:@storeall - puts all your possessions in storage
- 40:@killable - make your character killable
- 40:@memo [memo_position] - set/change a memo location (no position: display memo points).
- 40:@spiritball <number: 1-1000> - Gives you "spirit spheres" like from the skill "Call Spirits"
- 40: (If the number you use is > 1000, your server may become instable or crash)
- 40:@questskill <#> - Gives you the specified quest skill
- 40:@lostskill <#> - Takes away the specified quest skill from you
- 40:@skillid <name> - look up a skill by name
- 40:@useskill <skillid> <skillv> <target> - use a skill on target
- 40: Novice Swordsman Thief Merchant
- 40: 142 = Emergency Care 144 = Moving HP Recovery 149 = Throw Sand 153 = Cart Revolution
- 40: 143 = Act dead 145 = Attack Weak Point 150 = Back Sliding 154 = Change Cart
- 40: Archer 146 = Auto Berserk 151 = Take Stone 155 = Crazy Uproar/Loud Voice
- 40: 147 = Arrow Creation Acolyte 152 = Stone Throw Magician
- 40: 148 = Charge Arrows 156 = Holy Light 157 = Energy Coat
- 40: @skilltree <
- 40: @marry <player1>,<player2> - marry two players
- 40: @divorce <player> - divorces the two players (you need just one name of them)
- 60:@alive - Revives yourself from death
- 60:@lvup/@blevel/@baselvlup <number of levels> - Raises your base level the desired number of levels. The max is 255 (User Defined).
- 60:@joblvup/@jlevel/@joblvlup <number of levels> -Raises your job level the desired number of levels. The max is 50 For Basic Classes. For Super Novice and Advanced Classes it is 70.
- 60:@allskill/@allskills/@skillall/@skillsall - Give you all skills.
- 60:@stpoint <number of points> - Gives you the desired number of stat points.
- 60:@skpoint <number of points> - Gives you the desired number of skill points.
- 60:@zeny <amount> - Gives you desired amount of Zeny.
- 60:@cash <amount> - Gives you the specified amount of cash points.
- 60:@points <amount> - Gives you the specified amount of Kafra Points.
- 60:@str,@agi,@vit,@int,@dex,@luk <amount> - Adds desired amount to any stat. For example "@str 10" raises your str by 10
- 60:@statall/@statsall/@allstats/@allstat [value] - Adds value in all stats (maximum if no value).
- 60: @addwarp <map name> <x coord> <y coord>
- 40:
- 40:--- MONSTERS CMD ---
- 40:@killmonster2 - kill all monsters of your map (without drops)
- 50:/monster <monster_name> - Spawns 1 of the desired monster.
- 50:@spawn/@monster/@summon <monster_name_or_monster_ID> [<number to spawn> [<desired_monster_name> [<x coord> [<y coord>]]]]
- 50:@monster2 <desired_monster_name> <monster_name_or_monster_ID> [<number to spawn> [<x coord> [<y coord>]]]
- 50:@spawn/@monster/@summon/@monster2 "desired monster name" <monster_name_or_monster_ID> [<number to spawn> [<x coord> [<y coord>]]]
- 50:@spawn/@monster/@summon/@monster2 <monster_name_or_monster_ID> "desired monster name" [<number to spawn> [<x coord> [<y coord>]]]
- 50: Spawns the desired monster with any desired name.
- 50:@monstersmall [Mob ID|Mob Name] - Spawns a smaller version of a monster.
- 50:@monsterbig [Mob ID|Mob Name] - Spawns a larger version of a monster.
- 60:@killmonster [map] - kill all monsters of the map (they drop)
- 40:
- 10:--- MISC CMD ---
- 10:@autoloot [on|off|#] - Makes items go straight into your inventory.
- 10:@autotrade/@at - Allows you to vend while you are offline.
- 10:@changegm [Player Name] - Changes the leader of your guild (You must be guild leader)
- 10:@changeleader [Player Name] - Changes the leader of your party (You must be party leader)
- 20:@request [Message] - Sends a message to all connected GMs (via the gm whisper system)
- 40:@sound [Path way to file in Data or GRF file] - Plays a sound from the data or grf file located on the client.
- 50:@clone [Player Name] - Spawns a supportive clone of the given player.
- 50:@slaveclone [Player Name] - Spawns a supportive clone of the given player that follows the creator around.
- 50:@evilclone [Player Name] - Spawns an agressive clone of the given player.
- 60:@changesex - Changes your gender.
- 10:
- 1:--- DUEL CMD ---
- 1:@duel - Starts a duel.
- 1:@invite - Invites a player to a duel.
- 1:@accept - Accepts an invitation to a duel.
- 1:@reject - Rejects an invitation to a duel.
- 1:@leave - Leaves a duel.
- 1:
- 1:--- MAIL SYSTEM --- (SQL Only)
- 1:@mail - Open mail box.
+// This is help file that contains help messages for atcommands/charcommands.
+
+// Format:
+// <command>: "<help message>"
+
+// This file uses libconfig syntax.
+
+help: "Params: <command>\n" "Shows help for specified command."
+main: "Params: [on|off|<message>]\n" "Turns on or off main (server-wide) chat. Sends message to main chat."
+noask: "Auto rejects deals/invites."
+gmotd: "Broadcasts the Message of The Day to all players."
+me: "Params: <message>\n" "Displays normal text as a message in this format: *name message* (like /me in mIRC)."
+fakename: "Params: <name>\n" "Changes your name to your choice temporarily."
+npctalk: "Params: <NPC name> <message>\n" "Forces a NPC to display a message in normal chat."
+broadcast: "Params: <message>\n" "Broadcasts a message with your name (in yellow)."
+kami: "Params: <message>\n" "Broadcasts a message without your name (in yellow)."
+kamib: "Params: <message>\n" "Broadcasts a message without your name (in blue)."
+localbroadcast: "Params: <message>\n" "Broadcasts a message with your name (in yellow) only on your map."
+commands: "Displays a list of commands that you can use."
+rates: "Displays the server's current rates."
+uptime: "Displays how long the server has been online."
+showdelay: "Shows/hides the \"There is a delay after this skill\" message."
+exp: "Displays current levels and % progress."
+mobinfo: "Params: <monster ID>|<monster name>\n" "Shows monster info (stats, exp, drops etc)."
+iteminfo: "Params: <item ID>|<item name>\n" "Shows item info (type, price etc)."
+whodrops: "Params: <item ID>|<item name>\n" "Shows who drops an item (monster with highest drop rates)."
+version: "Displays SVN version of the server."
+email: "Params: <current email> <new email>\n" "Changes your account e-mail address."
+where: "Params: <char name>\n" "Tells you the location of a character."
+time: "Shows the date and time of the server."
+showexp: "Displays/hides experience gained."
+showzeny: "Displays/hides Zeny gained."
+mobsearch: "Params: <monster ID>|<monster name>\n" "Shows the location of a certain mob on the current map."
+who: "Params: [<name>]\n" "Shows a list of online players and their party and guild."
+who2: "Params: [<name>]\n" "Shows a list of online players and their job."
+who3: "Params: [<name>]\n" "Shows a list of online players and their location."
+whomap: "@whomap/@whomap2/@whomap3 [map] - like @who/@who2/@who3 but only for specifical map."
+whogm: "Params: [match_text] - Like @who+@who2+who3, but only for GM."
+guildspy: "Params: <guild_name/id> - You will receive all messages of the guild channel (Chat logging must be enabled)"
+partyspy: "@partyspy <party_name/id> - You will receive all messages of the party channel (Chat logging must be enabled)"
+mapinfo: "Params: [<0-3> [map]] - Give information about a map (general info +: 0: no more, 1: players, 2: NPC, 3: shops/chat)."
+die: "Kills yourself."
+go: "Params: <number/city_name>\n" "Warps you to a city.\n"
+ " -3: (Memo point 2) 1: morocc 5: izlude 9: yuno 13: niflheim \n"
+ " -2: (Memo point 1) 2: geffen 6: aldebaran 10: amatsu 14: louyang\n"
+ " -1: (Memo point 0) 3: payon 7: xmas (lutie) 11: gonryun 15: start point\n"
+ " 0: prontera 4: alberta 8: comodo 12: umbala 16: prison/jail\n"
+jumpto: "Params: <char name>\n" "Warps you to selected character."
+follow: "Params: <char_name>\n" "Follow a player."
+mount: "Give/remove you a peco (Class is required, but not skill)"
+disguise: "Params: <monster_name_or_monster_ID>\n" "Change your appearence to other players to a mob."
+undisguise: "Restore your normal appearance."
+model: "Params: <hair ID: 0-17> <hair color: 0-8> <clothes color: 0-4> - Changes your characters appearence."
+size: "Params: <1-3> Changes your size (1-Smallest 2-Biggest 3-Normal)"
+hide: "Makes you character invisible (GM invisibility). Type again to become visible."
+save: "Sets respawn point to current spot."
+load: "Warps you to your save point."
+warp: "Params: <mapname> [<x> <y>]\n" "Warps you to the selected map and position."
+jump: "Params: [<x> [<y>]]\n" "Randomly warps you like a flywing."
+jobchange: "Params: <job ID>\n" "Changes your job.\n"
+" 0: Novice 18: Alchemist 4015: Paladin\n"
+" 1: Swordman 19: Bard 4016: Champion\n"
+" 2: Mage 20: Dancer 4017: Professor\n"
+" 3: Archer 23: Super Novice 4018: Stalker\n"
+" 4: Acolyte 4001: High Novice 4019: Creator\n"
+" 5: Merchant 4002: High Swordman 4020: Clown\n"
+" 6: Thief 4003: High Mage 4021: Gypsy\n"
+" 7: Knight 4004: High Archer 4046: Taekwon\n"
+" 8: Priest 4005: High Acolyte 4047: Star Gladiator\n"
+" 9: Wizard 4006: High Merchant 4049: Soul Linker\n"
+" 10: Blacksmith 4007: High Thief 24: Gunslinger\n"
+" 11: Hunter 4008: Lord Knight 25: Ninja\n"
+" 12: Assassin 4009: High Priest\n"
+" 14: Crusader 4010: High Wizard\n"
+" 15: Monk 4011: Whitesmith\n"
+" 16: Sage 4012: Sniper\n"
+" 17: Rogue 4013: Assassin Cross\n"
+" ---- Baby Classes ----\n"
+" 4023: Baby 4024: Baby Swordman 4025: Baby Mage\n"
+" 4026: Baby Archer 4027: Baby Acolyte 4028: Baby Merchant\n"
+" 4029: Baby Thief 4030: Baby Knight 4031: Baby Priest\n"
+" 4032: Baby Wizard 4033: Baby Blacksmith 4034: Baby Hunter\n"
+" 4035: Baby Assassin 4037: Baby Crusader 4038: Baby Monk\n"
+" 4039: Baby Sage 4040: Baby Rogue 4041: Baby Alchemist\n"
+" 4042: Baby Bard 4043: Baby Dancer 4045: Super Baby\n"
+option: "Params: <param1> <param2> <param3>\n" "Adds different visual effects on or around your character.\n"
+"<param1> <param2> <p3>(stackable) <param3> <param3>\n"
+"1 Petrified (stackable) 01 Sight 32 Peco Peco riding 2048 Orc Head\n"
+"2 Frozen 01 Poison 02 Hide 64 GM Perfect Hide 4096 Wedding Sprites\n"
+"3 Stunned 02 Cursed 04 Cloak 128 Level 2 Cart 8192 Ruwach\n"
+"4 Sleeping 04 Silenced 08 Level 1 Cart 256 Level 3 Cart\n"
+"6 darkness 08 ??? 16 Falcon 512 Level 4 Cart\n"
+" 16 darkness 1024 Level 5 Cart\n"
+heal: "Params: [<HP> <SP>]\n" "Heals the desired amount of HP and SP. No value specified will do a full heal."
+dye: "Params: <clothes palette no.>\n" "Changes your characters clothes color."
+hairstyle: "Params: <hairstyle no.>\n" "Changes your hair style."
+haircolor: "Params <hair palette no.>\n" "Changes your hair color."
+speed: "Params: <1-1000>\n" "Changes you walking speed. 1 being the fastest and 1000 the slowest. Default is 150."
+effect: "Params: <effect id> [<flag>]\n" "Give an effect to your character."
+dropall: "Throws all your possession on the ground."
+storeall: "Puts all your possessions in storage."
+killable: "Make your character killable."
+memo: "Params: [memo position]\n" "Set/change a memo location (no position: display memo points)."
+spiritball: "Params: <1-100>\n" "Gives you \"spirit spheres\" like from the skill \"Call Spirits\".\n"
+questskill: "Params: <#>\n" "Gives you the specified quest skill"
+lostskill: "Params: <#>\n" "Takes away the specified quest skill from you\n"
+" Novice Swordsman Thief Merchant\n"
+" 142 = Emergency Care 144 = Moving HP Recovery 149 = Throw Sand 153 = Cart Revolution\n"
+" 143 = Act dead 145 = Attack Weak Point 150 = Back Sliding 154 = Change Cart\n"
+" Archer 146 = Auto Berserk 151 = Take Stone 155 = Crazy Uproar/Loud Voice\n"
+" 147 = Arrow Creation Acolyte 152 = Stone Throw Magician\n"
+" 148 = Charge Arrows 156 = Holy Light 157 = Energy Coat\n"
+skillid: "Params: <name>\n" "Look up a skill by name"
+useskill: "Params: <skillid> <skillv> <target>\n" "Use a skill on target"
+skilltree: "Params: <"
+marry: "Params: <player1>,<player2>\n" "Marry two players."
+divorce: "Params: <player>\n" "Divorces the two players (you need just one name of them)"
+alive: "Revives yourself from death."
+blvl: "Params: <number of levels>\n" "Raises your base level the desired number of levels."
+jlvl: "Params: <number of levels>\n" "Raises your job level the desired number of levels."
+allskill: "Give you all skills."
+stpoint: "Params: <number of points> - Gives you the desired number of stat points."
+skpoint: "Params: <number of points> - Gives you the desired number of skill points."
+zeny: "Params: <amount> - Gives you desired amount of Zeny."
+cash: "Params: <amount> - Gives you the specified amount of cash points."
+points: "Params: <amount> - Gives you the specified amount of Kafra Points."
+str: "Params: <amount>\n" "Raises STR by given amount."
+agi: "Params: <amount>\n" "Raises AGI by given amount."
+dex: "Params: <amount>\n" "Raises DEX by given amount."
+vit: "Params: <amount>\n" "Raises VIT by given amount."
+int: "Params: <amount>\n" "Raises INT by given amount."
+luk: "Params: <amount>\n" "Raises LUK by given amount."
+allstats: "Params: <value>\n" "Adds value in all stats (maximum if no value)."
+addwarp: "Params: <map name> <x coord> <y coord>\n"
+killmonster2: "Kills all monsters of your map (without drops)."
+monster: "Params: <monster_name_or_monster_ID> [<number to spawn> [<desired_monster_name> [<x coord> [<y coord>]]]]\n"
+ "@monster2 <desired_monster_name> <monster_name_or_monster_ID> [<number to spawn> [<x coord> [<y coord>]]]\n"
+"@spawn/@monster/@summon/@monster2 \"desired monster name\" <monster_name_or_monster_ID> [<number to spawn> [<x coord> [<y coord>]]]\n"
+"@spawn/@monster/@summon/@monster2 <monster_name_or_monster_ID> \"desired monster name\" [<number to spawn> [<x coord> [<y coord>]]]\n"
+" Spawns the desired monster with any desired name."
+monstersmall: "Params: [Mob ID|Mob Name]\n" "Spawns a smaller version of a monster."
+monsterbig: "Params: [Mob ID|Mob Name]\n" "Spawns a larger version of a monster."
+killmonster: "Params: [map]\n" "Kill all monsters of the map (they drop)"
+autoloot: "Params: [on|off|#]\n" "Makes items go straight into your inventory."
+autotrade: "Allows you to vend while you are offline."
+changegm: "Params: [Player Name]\n" "Changes the leader of your guild (You must be guild leader)"
+changeleader: "Params: [Player Name]\n" "Changes the leader of your party (You must be party leader)"
+request: "Params: [Message]\n" "Sends a message to all connected GMs (via the gm whisper system)"
+sound: "Params: [Path way to file in Data or GRF file]\n" "Plays a sound from the data or grf file located on the client."
+clone: "Params: [Player Name]\n" "Spawns a supportive clone of the given player."
+slaveclone: "Params: [Player Name]\n" "Spawns a supportive clone of the given player that follows the creator around."
+evilclone: "Params: [Player Name]\n" "Spawns an agressive clone of the given player."
+changesex: "Changes your gender."
+duel: "Starts a duel."
+invite: "Invites a player to a duel."
+accept: "Accepts an invitation to a duel."
+reject: "Rejects an invitation to a duel."
+leave: "Leaves a duel."
+mail: "Open mail box."
+storage: "Opens storage."
+itemreset: "Remove all your items."
+guildstorage: "Opens guild storage."
+idsearch: "Params: <part_of_item_name>\n" "Search all items that name have part_of_item_name"
+refine: "Params: <equip position> <+/- amount>"
+produce: "Params: <equip name or equip ID> <element> <# of very's>\n"
+" Element: 0=None 1=Ice 2=Earth 3=Fire 4=Wind\n"
+" You can add up to 3 Star Crumbs and 1 element\n"
+repairall: "Repair all items of your inventory"
+item: "Params: <item name or ID> <quantity>\n" "Gives you the desired item."
+item2: "Params: <item name or ID> <quantity> <identified_flag> <refine> <broken_flag> <Card1> <Card2> <Card3> <Card4>\n" "Gives you the desired item."
+pvpon: "Turns pvp on on the current map"
+pvpoff: "Turns pvp off on the current map"
+gvgon: "Turns gvg on on the current map"
+gvgoff: "Turns gvg off on the current map"
+agitstart: "Starts War of Emperium"
+agitend: "End War of Emperium"
+party: "Params: <party_name>\n" "Create a party."
+guild: "Params: <guild_name>\n" "Create a guild."
+glvl: "Params: <# of levels>\n" "Raise Guild by desired number of levels"
+guildrecall: "Params: <guild_name/id>\n" "Warps all online characters of a guild to you."
+partyrecall: "Params: <party_name/id>\n" "Warps all online characters of a party to you."
+petrename: "Re-enable pet rename"
+pettalk: "Params: [Message]\n" "Makes your pet say a message."
+petfriendly: "Params: <#>\n" "Set pet friendly amount (0-1000) 1000 = Max"
+pethungry: "Params: <#>\n" "Set pet hungry amount (0-100) 100 = Max"
+hatch: "Create a pet from your inventory eggs list."
+makeegg: "Params: <pet_id>\n" "Gives pet egg for monster number in pet DB"
+kick: "Params: <char name>\n" "Kicks specified character off the server"
+unjail: "Params: <char name>\n" "Discharges specified character/prisoner"
+kill: "Params: <char name>\n" "Kills specified character."
+recall: "Params: <char name>\n" "Warps target character to you."
+raise: "Params: <char name>\n" "Revives target character."
+block: "Params: <char name>\n" "Blocks definitively a account"
+unblock: "Params: <char name>\n" "Unblocks a account"
+ban: "Params: <time> <name>\n" "Ban temporarily a account\n"
+ " time usage: adjustment (+/- value) and element (y/a, m, d/j, h, mn, s)\n"
+ " Example: @ban +1m-2mn1s-6y testplayer\n"
+unban: "Params: <name> - Unban a account"
+jail: "Params: <char name> - Sends specified character in jails"
+trade: "Params: <char name> - Open a trade window with a another player"
+recallall: "Warps every character online to you."
+doom: "Kills all NON GM chars on the server."
+doommap: "Kills all non GM characters on the map."
+raisemap: "Resurrects all characters on the map."
+night: "Uses @option 00 16 00 on all characters. All characters are in darkness."
+day: "Uses @option 00 00 00 on all characters."
+skillon: "turn skills on for a map"
+skilloff: "turn skills on for a map"
+snow: "Makes all maps to have the snow weather effect."
+clouds: "Makes all maps to have the cloudy weather effect."
+clouds2: "Makes all maps to have another cloudy weather effect."
+fog: "Makes all maps to have the fog weather effect."
+fireworks: "Makes all maps to have the fireworks weather effect."
+sakura: "Makes all maps to have the sakura weather effect."
+leaves: "Makes all maps to have the leaves weather effect."
+shownpc: "Params: <NPC name>\n" "Enable a NPC"
+hidenpc: "Params: <NPC name>\n" "Disable a NPC"
+loadnpc: "Params: <path to script>\n" "Load script"
+unloadnpc: "Params: <NPC name>\n" "Unload script"
+adjgroup: "Params: <level> <char name> - Do a temporary adjustment of the GM level of a player"
+kickall: "Kick all characters off the server"
+mapexit: "Kick all players and shut down map-server."
+reloaditemdb: "Reload item database."
+reloadmobdb: "Reload monster database."
+reloadskilldb: "Reload skills definition database."
+reloadscript: "Reload all scripts."
+gat: "For debugging (you inspect around gat)"
+send: "For debugging (packet variety)"
+nuke: "Params: <char name>\n"
+
diff --git a/conf/help2.txt b/conf/help2.txt
deleted file mode 100644
index 8f8330dbd..000000000
--- a/conf/help2.txt
+++ /dev/null
@@ -1,94 +0,0 @@
- 0:To use one command, type it inside the message window where you usually type to chat.
- 1:--- ITEMS CMD ---
- 1:@storage - Opens storage
- 40:@itemreset - Remove all your items.
- 50:@gstorage - Opens guild storage
- 60:@itemcheck - Check your items with authorised items.
- 60:@idsearch <part_of_item_name> - Search all items that name have part_of_item_name
- 60:@refine <equip position> <+/- amount>
- 60:@produce <equip name or equip ID> <element> <# of very's>
- 60: Element: 0=None 1=Ice 2=Earth 3=Fire 4=Wind
- 60: You can add up to 3 Star Crumbs and 1 element
- 60:@repairall - Repair all items of your inventory
- 60:/item <item_name> - Gives you 1 of the desired item.
- 60:@item <item name or ID> <quantity> - Gives you the desired item.
- 60:@item2 <item name or ID> <quantity> <identified_flag> <refine> <broken_flag> <Card1> <Card2> <Card3> <Card4> - Gives you the desired item.
- 40:
- 40:--- PVP CMD ---
- 40:@pvpon - Turns pvp on on the current map
- 40:@pvpoff - Turns pvp off on the current map
- 40:@gvgon/@gpvpon - Turns gvg on on the current map
- 40:@gvgoff/@gpvpoff - Turns gvg off on the current map
- 60:@agitstart - Starts War of Emperium
- 60:@agitend - End War of Emperium
- 1:
- 1:--- GROUPS CMD ---
- 1:@party <party_name> - Create a party.
- 50:@guild <guild_name> - Create a guild.
- 60:@guildlvup/@guildlvlup <# of levels> - Raise Guild by desired number of levels
- 60:@guildrecall <guild_name/id> - Warps all online characters of a guild to you.
- 60:@partyrecall <party_name/id> - Warps all online characters of a party to you.
- 1:
- 1:--- PETS CMD ---
- 1:@petrename - Re-enable pet rename
- 10:@pettalk [Message] - Makes your pet say a message.
- 40:@petfriendly <#> - Set pet friendly amount (0-1000) 1000 = Max
- 40:@pethungry <#> - Set pet hungry amount (0-100) 100 = Max
- 60:@hatch - Create a pet from your inventory eggs list.
- 60:@makeegg <pet_id> - Gives pet egg for monster number in pet DB
- 20:
- 20:--- REMOTE CHAR CMD ---
- 20:@kick <char name> - Kicks specified character off the server
- 40:@charkillable <char name> - make another character killable
- 60:@unjail/@discharge <char name> - Discharges specified character/prisoner
- 60:@kill <char name> - Kills specified character.
- 60:@chardropall <char name> - throws all a chars possession on the ground
- 60:@charstoreall <char name> - puts all of anothers charactes possessions in storage
- 60:/recall/@recall <char name> - Warps target character to you.
- 60:@revive <char name> - Revives target character.
- 60:@charblock/@block <char name> - Blocks definitively a account
- 60:@charunblock/@unblock <char name> - Unblocks a account
- 60:@charban/@ban/@banish/@charbanish <time> <name> - Ban temporarily a account
- 60: time usage: adjustment (+/- value) and element (y/a, m, d/j, h, mn, s)
- 60: Example: @ban +1m-2mn1s-6y testplayer
- 60:@charunban/@unban/@unbanish/@charunbanish <name> - Unban a account
- 60:@jail <char name> - Sends specified character in jails
- 60:@trade <char name> - Open a trade window with a another player
- 80:@recallall - Warps every character online to you.
- 80:@doom - Kills all NON GM chars on the server.
- 80:@doommap - Kills all non GM characters on the map.
- 80:@raise - Resurrects all characters on the server.
- 80:@raisemap - Resurrects all characters on the map.
- 80:
- 80:--- ENVIRONMENT CMD ---
- 80:@night - Uses @option 00 16 00 on all characters. All characters are in darkness.
- 80:@day - Uses @option 00 00 00 on all characters.
- 80:@skillon - turn skills on for a map
- 80:@skilloff - turn skills on for a map
- 99:@rain - Makes all maps to have the rain weather effect.
- 99:@snow - Makes all maps to have the snow weather effect.
- 99:@clouds - Makes all maps to have the cloudy weather effect.
- 99:@clouds2 - Makes all maps to have another cloudy weather effect.
- 99:@fog - Makes all maps to have the fog weather effect.
- 99:@fireworks - Makes all maps to have the fireworks weather effect.
- 99:@sakura - Makes all maps to have the sakura weather effect.
- 99:@leaves - Makes all maps to have the leaves weather effect.
- 80:
- 80:--- ADMIN CMD ---
- 80:@shownpc <NPC name> - Enable a NPC
- 80:@hidenpc <NPC name> - Disable a NPC
- 80:@loadnpc <path to script> - Load script
- 80:@unloadnpc <NPC name> - Unload script
- 99:@adjgmlvl <level> <char name> - Do a temporary adjustment of the GM level of a player
- 99:@adjcmdlvl <level> <command> - Do a temporary adjustment of the GM level of a command
- 99:@kickall - Kick all characters off the server
- 99:@mapexit - Kick all players and shut down map-server.
- 99:@reloaditemdb - Reload item database.
- 99:@reloadmobdb - Reload monster database.
- 99:@reloadskilldb - Reload skills definition database.
- 99:@reloadscript - Reload all scripts.
- 99:@reloadgmdb - Reload GM levels.
- 99:
- 99:@gat - For debugging (you inspect around gat)
- 99:@packet - For debugging (packet variety)
-100:@nuke <char name> -
diff --git a/conf/log_athena.conf b/conf/log_athena.conf
index 37ab1b14f..13174a018 100644
--- a/conf/log_athena.conf
+++ b/conf/log_athena.conf
@@ -84,8 +84,10 @@ log_zeny: 0
// Outdated. Use Pick_Log instead. But this log could be useful to keep track slayed MVPs
log_mvpdrop: no
-// Log GM Commands (set to minimum level of Logged Commands)
-log_gm: 40
+// Log AtCommands & Charcommands (Note 1)
+// Only commands issued by player groups ('conf/groups.conf') with
+// 'log_commands' setting set to 'true' will be logged.
+log_commands: yes
// Log NPC 'logmes' commands (Note 1)
log_npc: no
diff --git a/conf/login_athena.conf b/conf/login_athena.conf
index aab2f854c..7dda3cb5c 100644
--- a/conf/login_athena.conf
+++ b/conf/login_athena.conf
@@ -62,9 +62,10 @@ log_login: yes
// Indicate how to display date in logs, to players, etc.
date_format: %Y-%m-%d %H:%M:%S
-// Indicate the minimum GM level of player that the server accepts to connection.
-// 0: all players (normal player are 0. it's default), 1-99: GM level at least with level x
-min_level_to_connect: 0
+// Required account group id to connect to server.
+// -1: disabled
+// 0 or more: group id
+group_id_to_connect: -1
// Starting additional sec from now for the limited time at creation of account
// -1: new account are created with UNlimited time (default value)
diff --git a/conf/msg_athena.conf b/conf/msg_athena.conf
index 2f5e50eea..8de5b8ec0 100644
--- a/conf/msg_athena.conf
+++ b/conf/msg_athena.conf
@@ -44,7 +44,7 @@
24: Job level raised.
25: Job level lowered.
26: Help commands:
-27: File help.txt not found.
+27: Commands help is not available.
28: No player found.
29: 1 player found.
30: %d players found.
@@ -348,16 +348,6 @@
// 334: Thirty-Four Castles
334: Total Domination
-// Players Titles (for @who, etc commands, check battle_athena.conf for titles level setting)
-// Useful note: you may remove ':%d' from the line, then you will see only player title, w/o his level
-335: Super player:%d
-336: Super player+:%d
-337: Mediator:%d
-338: Sub-GM:%d
-339: Sub-GM+:%d
-340: GM:%d
-341: GM Chief:%d
-342: Administrator:%d
// Templates for @who output
343: Name: %s
344: (%s)
diff --git a/configure b/configure
index 9494bacd5..3050ade09 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.in Revision: 15238 .
+# From configure.in Revision: 15503 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59.
#
@@ -1334,7 +1334,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
ac_config_files="$ac_config_files Makefile src/common/Makefile"
- ac_config_files="$ac_config_files 3rdparty/mt19937ar/Makefile"
+ ac_config_files="$ac_config_files 3rdparty/mt19937ar/Makefile 3rdparty/libconfig/Makefile"
ac_config_files="$ac_config_files src/char/Makefile src/login/Makefile"
@@ -3737,6 +3737,289 @@ if test $ac_cv_func_strnlen = yes; then
fi
+# libconfig
+echo "$as_me:$LINENO: checking for uselocale" >&5
+echo $ECHO_N "checking for uselocale... $ECHO_C" >&6
+if test "${ac_cv_func_uselocale+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define uselocale to an innocuous variant, in case <limits.h> declares uselocale.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define uselocale innocuous_uselocale
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char uselocale (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef uselocale
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char uselocale ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_uselocale) || defined (__stub___uselocale)
+choke me
+#else
+char (*f) () = uselocale;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != uselocale;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_uselocale=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_uselocale=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_uselocale" >&5
+echo "${ECHO_T}$ac_cv_func_uselocale" >&6
+if test $ac_cv_func_uselocale = yes; then
+ CFLAGS="$CFLAGS -DHAVE_USELOCALE"
+fi
+
+echo "$as_me:$LINENO: checking for newlocale" >&5
+echo $ECHO_N "checking for newlocale... $ECHO_C" >&6
+if test "${ac_cv_func_newlocale+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define newlocale to an innocuous variant, in case <limits.h> declares newlocale.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define newlocale innocuous_newlocale
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char newlocale (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef newlocale
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char newlocale ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_newlocale) || defined (__stub___newlocale)
+choke me
+#else
+char (*f) () = newlocale;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != newlocale;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_newlocale=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_newlocale=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_newlocale" >&5
+echo "${ECHO_T}$ac_cv_func_newlocale" >&6
+if test $ac_cv_func_newlocale = yes; then
+ CFLAGS="$CFLAGS -DHAVE_NEWLOCALE"
+fi
+
+echo "$as_me:$LINENO: checking for freelocale" >&5
+echo $ECHO_N "checking for freelocale... $ECHO_C" >&6
+if test "${ac_cv_func_freelocale+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define freelocale to an innocuous variant, in case <limits.h> declares freelocale.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define freelocale innocuous_freelocale
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char freelocale (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef freelocale
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char freelocale ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_freelocale) || defined (__stub___freelocale)
+choke me
+#else
+char (*f) () = freelocale;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != freelocale;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_freelocale=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_freelocale=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_freelocale" >&5
+echo "${ECHO_T}$ac_cv_func_freelocale" >&6
+if test $ac_cv_func_freelocale = yes; then
+ CFLAGS="$CFLAGS -DHAVE_FREELOCALE"
+fi
+
#
# Memory manager
@@ -6166,6 +6449,7 @@ do
"Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"src/common/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/common/Makefile" ;;
"3rdparty/mt19937ar/Makefile" ) CONFIG_FILES="$CONFIG_FILES 3rdparty/mt19937ar/Makefile" ;;
+ "3rdparty/libconfig/Makefile" ) CONFIG_FILES="$CONFIG_FILES 3rdparty/libconfig/Makefile" ;;
"src/char/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/char/Makefile" ;;
"src/login/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/login/Makefile" ;;
"src/map/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/map/Makefile" ;;
diff --git a/configure.in b/configure.in
index 3269537b2..940e752a6 100644
--- a/configure.in
+++ b/configure.in
@@ -6,7 +6,7 @@ AC_REVISION($Revision$)
AC_PREREQ([2.59])
AC_CONFIG_SRCDIR([src/common/cbasetypes.h])
AC_CONFIG_FILES([Makefile src/common/Makefile])
-AC_CONFIG_FILES([3rdparty/mt19937ar/Makefile])
+AC_CONFIG_FILES([3rdparty/mt19937ar/Makefile 3rdparty/libconfig/Makefile])
AC_CONFIG_FILES([src/char/Makefile src/login/Makefile])
AC_CONFIG_FILES([src/map/Makefile src/plugins/Makefile src/tool/Makefile])
@@ -468,6 +468,10 @@ AC_CHECK_FUNC([setrlimit],[CFLAGS="$CFLAGS -DHAVE_SETRLIMIT"])
#
AC_CHECK_FUNC([strnlen],[CFLAGS="$CFLAGS -DHAVE_STRNLEN"])
+# libconfig
+AC_CHECK_FUNC([uselocale],[CFLAGS="$CFLAGS -DHAVE_USELOCALE"])
+AC_CHECK_FUNC([newlocale],[CFLAGS="$CFLAGS -DHAVE_NEWLOCALE"])
+AC_CHECK_FUNC([freelocale],[CFLAGS="$CFLAGS -DHAVE_FREELOCALE"])
#
# Memory manager
diff --git a/doc/atcommands.txt b/doc/atcommands.txt
new file mode 100644
index 000000000..b60735cac
--- /dev/null
+++ b/doc/atcommands.txt
@@ -0,0 +1,213 @@
+TODO: With such short descriptions, it's duplicated 'conf/help.txt'
+Consider explaining commands in detail, similar to 'doc/script_commands.txt'
+
+commands: Displays a list of @ commands available to the player.
+charcommands: Displays a list of # commands available to the player.
+rates: Displays the server rates.
+uptime: Show server uptime since last map server restart.
+showdelay: Shows/Hides the "there is a delay after a skill" message.
+exp: Displays current levels and % progress.
+email: To change your (own) email. Note: this command doesn't check email itself, but check structure of the email (xxx@xxx).
+monsterinfo: Show Monster info (rates, stats, drops, MVP stuff).
+iteminfo: Show Item info (type, price, etc).
+whodrops: Show who drops an item (mobs with highest drop rate).
+refresh: Syncs the player's position on the client with the one stored on the server.
+time: Give server time.
+version: Displays SVN version of the server.
+die: Suicide your character.
+petrename: Enables you to rename your pet.
+party: Organize a new party, with you as the party leader.
+storage: Opens your Kafra storage wherever you are.
+mail: Opens your mailbox.
+auction: Opens auctions window.
+where: Locate someone on a map, returns your coordinates if the person isn't on.
+duel, invite, accept, reject, leave: Duel organizing commands.
+main: Main chat.
+noask: Autorejecting Deals/Invites.
+jailtime: Displays remaining jail time.
+hominfo, homstats: Homunculus commands for players
+noks: Kill Steal Protection.
+font: Set Font.
+showexp: Displays/Hides Experience gained messages.
+showzeny: Displays/Hides Zeny gained messages.
+go: Warps you to predefined locations in major cities.
+autoloot: Enables/disables autolooting from killed mobs.
+alootid: Enables/disables autolooting an item.
+autotrade: Allows you continue vending offline.
+changegm: Change Guild Master of your Guild.
+changeleader: Change the leader of your party.
+partyoption: Change the party exp- and item share rules.
+pettalk: Command what the player's pet will say.
+homtalk: Command what the player's homunculus will say.
+mobsearch: Locates and displays the position of a certain mob on the current map.
+showmobs: Locates and displays the position of a certain mob on your mini-map.
+whereis: Prints out in which maps a monster normally spawns at (does not count script-invoked mobs).
+feelreset: Resets a Star Gladiator's marked maps
+help: Displays help about commands.
+goto: Warp yourself to a person.
+gmotd: Displays the motd file to all players.
+follow: Follow a player (including warping to them).
+request: Sends a request to all connected GMs (via the gm whisper system).
+kick: Disconnects a user from the server.
+model: Changes your appearance.
+mount: To get a peco to (un)ride.
+who: Returns list of logged in characters with their position.
+who2: Returns list of logged in characters with their job.
+who3: Returns list of logged in characters with their party/guild.
+whomap: Returns list of logged in characters with their position in a specifical map.
+whomap2: Returns list of logged in characters with their job in a specifical map.
+whomap3: Returns list of logged in characters with their party/guild in a specifical map.
+whogm: Displays GMs online. For those who are higher GM level than yourself, only the name is shown, for the rest, it displays the same info of @who+@who2+who3.
+disguise: Change your appearence to other players to a mob.
+undisguise: Restore your normal appearance.
+me: Displays the text as a normal message with the format "*name message*" instead of "name : message" (Like the /me command in IRC).
+fakename: Changes your name to your choice temporarily.
+size: Changes your size.
+npctalk: Can command what other npcs (by name) can say.
+broadcast: Broadcast to the whole server.
+localbroadcast: Broadcast to the map you are on.
+kami: Broadcast (with or without name).
+kamib: Same as kami but with blue color.
+kamic: Same as kami but you can choose the color (uses different packet).
+gvgon: Enables GvG on a map.
+gvgoff: Turns GvG (Guild vs. Guild) off on a map
+allowks: Activate/Deactivate kill steal protection on a map.
+heal: Modifies your HP/SP.
+hide: GM Hide (total invisibility to characters and monsters)
+job: Changes your job to one you specify.
+jump: Enables you to to jump randomly on a map (that you are already on).
+load: Warps you to your last save point
+tonpc: Warps you to a specific npc.
+memo: Saves a warp point.
+option: Set your character display options. (Visual effects of your character)
+petfriendly: Sets the level of intemecy of your pet.
+pethungry: Sets hunger level of your pet.
+pvpoff: Turns PvP (Person vs. Person) off on a map.
+pvpon: Enables PvP on a map.
+questskill: Permanently adds a quest skill.
+lostskill: Permanently removes a quest skill
+speed: Sets the speed you can walk/attack at. Default is 150.
+spiritball: Summons spirit spheres around you.
+warp: Warp yourself to a certain map, at (x,y) coordinates (2 same commands) + also /mm or /mapmove.
+dye: Changes clothes color.
+hairstyle: Changes hair style.
+haircolor: Changes hair color.
+itemreset: Deletes all your items.
+reset: Does a skill/stat reset.
+users: Displays distribution of players on the server per map (% on each map which has players).
+cleanmap: Deletes floor items in sight range.
+killmonster2: Kill all monsters in map (without drops).
+save: Sets spawn point (aka save point).
+effect: Do some visual effect on a character.
+misceffect: Do some visual effect on a character (misceffect)
+identify: Magnifier.
+dropall: Drop all items.
+storeall: Store all items.
+killable: Allow other players to hit you out of PvP.
+skillid: Look up a skill by name.
+useskill: Use a skill by id.
+skilltree: What skills are required to get this skill.
+marry, divorce: Marriage commands.
+adopt: Adopt a novice into a family.
+sound: Play a Sound!
+storagelist: Displays a player's storage.
+cartlist: Displays a player's cart contents.
+itemlist: Displays a player's inventory.
+stats: Displays player's stats.
+guild: Creates a new guild, with you as the guildmaster.
+gstorage: Brings up your guild storage wherever you are.
+monster: Spawns a monster, and a certain amount.
+monstersmall: Spawns a smaller sized version of a monster.
+monsterbig: Spawns a larger sized version of a monster.
+summon: Spawns mobs that treat you as their master (they disappear after some time).
+clone: It will spawn a supportive clone of the given player.
+slaveclone: It will spawn a supportive clone of the given player that follows the creator around.
+evilclone: It will spawn an aggresive clone of the given player.
+cash: Add or Remove Cash Points
+points: Add or Remove Kafra Points
+agitstart: Starts Guild Wars
+agitend: Ends Guild Wars
+alive: Resurects yourself.
+blvl: Raises your base level by specified amount
+jlvl: Raises your job level by specified amount
+changesex: Changes the sex of yourself
+glvl: Raises your guild level by specified amount
+idsearch: Find an itemID based on item name
+item: Creates an item of your choosing, either Item ID or Name
+item2: Creates a complete item (card, etc...) of your choosing, either Item ID or Name.
+delitem: Deletes an item of your choosing, either Item ID or Name.
+kill: Kill another character without hitting them.
+killmonster: Kill all monsters in map (with drops)
+makeegg: Creates yourself a pet egg.
+hatch: Hatches an egg.
+nuke: Instantly kills player whose name is entered and deals insane damage to everything around.
+killer: Enable hitting a player even when not in PvP
+produce: Creates weapon of desired element.
+recall: Warps a character to you.
+refine: Refines all weapons in your items list.
+repairall: Will repair all broken items in inventory.
+str, agi, vit, int, dex, luk: Change Status of your character.
+allskill: Gives all skills
+allstats: Sets stats to maximum
+stpoint: Gives you stat points.
+skpoint: Gives you skill points of desired amount.
+guildrecall: Warps all online character of a guild to you. (at least one member of that guild must be on.)
+partyrecall: Warps all online character of a party to you. (at least one party member must be online.)
+guildspy: Allows you to spy on any Guilds Guild chat. (at least one member of that guild must be on.) NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes)
+partyspy: Allows you to spy on any party's party chat. (at least one party member must be online.) NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes)
+zeny: Gives you zeny (or subtracts, if amount is negative).
+block: Block a player indefinitely.
+unblock: Unblock a player.
+ban: Ban a player for a limited time.
+unban: Unban a player.
+jail: To send specified character in jails.
+unjail: To discharge a jailed character.
+jailfor: Timed jailing.
+addwarp: Create a static warp portal that lasts until the next reboot.
+trade: Open a trade window with any player.
+changelook: Changes the player's appearance (headgear).
+hlvl, homevolve, makehomun, homfriendly, homhungry: Homunculus commands for GMs.
+homshuffle: Re-calculates stats, as if the homun was sent back to level 1 and re-leveled.
+agitstart2, agitend2: WoE 2 start/stop commands.
+streset: Resets player stats
+skreset: Resets player skills
+day: Set the server to day.
+night: Set the server to night.
+doom: Kills everyone on the server.
+doommap: Kills everyone on the map you are on.
+recallall: Recalls Everyone To Your Coordinates
+raisemap: Revives all players on the map.
+raise: Revives all players on the server.
+hidenpc: Hides a NPC.
+shownpc: Unhides a NPC.
+loadnpc: Loads an NPC script by path.
+unloadnpc: Unloads a NPC.
+npcmove: Move a NPC.
+skillon: Turn skills on for a map
+skilloff: Turn skills off for a map
+mute: Mute a player (prevents talking, usage of skills and commands)
+unmute: Unmute a player
+kickall: Disconnect all users from the server.
+mapexit: Closes Map-Server.
+send: Used for testing packet sends from the client (debug function).
+gat: Give information about terrain/area (debug function).
+displaystatus: Displays a status change without really applying it (debug function).
+displayskill: Displays the animation of a skill without really using it (debug function).
+mapinfo: Shows information about the map.
+mapflag: Set Map Flags
+reloaditemdb: Re-load item database (admin command)
+reloadmobdb: Re-load monsters database (admin command)
+reloadskilldb: Re-load skills database (admin command)
+reloadscript: Re-load scripts (admin command)
+setbattleflag: Change a battle_config flag without rebooting server
+reloadatcommand: Re-load atcommand config (admin command)
+reloadbattleconf: Re-load battle config (admin command) Note that some player config settings won't take effect until relog (display exp, display zeny, display skill delay fail, ...)
+reloadstatusdb: Re-load status database (admin command)
+reloadpcdb: Re-load player info database (admin command)
+reloadmotd: Re-load the Message of the Day (admin command)
+adjgroup: Changes the group of another character (lasts until relog)
+disguiseall, undisguiseall: [Un]Disguise All Players (admin command)
+mutearea: Mutes every player on screen (admin command)
+battleignore: Makes you immune to attacks (monsters/players/skills cannot target/hit you, admin command)
+snow, clouds, clouds2, fog, fireworks, sakura, leaves: Weather effects
+clearweather: Stop all weather effects
diff --git a/doc/permissions.txt b/doc/permissions.txt
new file mode 100644
index 000000000..afadb680c
--- /dev/null
+++ b/doc/permissions.txt
@@ -0,0 +1,21 @@
+These are possible permissions of player groups, configured in conf/groups.conf.
+
+can_trade : Ability to trade or otherwise distribute items (drop, storage, vending etc)
+can_party : Ability to join parties.
+all_skill : Ability to use all skills.
+all_equipment : Ability to equip anything (can cause client errors).
+skill_unconditional : Ability to use skills without meeting the required conditions (SP, items, etc...).
+join_chat : Ability to join a password protected chatrooms.
+kick_chat : Protection from being kicked from a chat.
+hide_session : Hides player session from being displayed by @commands.
+who_display_aid : Ability to see GMs and Account/Char IDs in the @who command.
+hack_info : Ability to receive all informations about any player that try to hack, spoof a name, etc.
+any_warp : Ability to bypass nowarp, nowarpto, noteleport and nomemo mapflags.
+ This option is mainly used in commands which modify a character's
+ map/coordinates (like @memo, @mapmove, @go, @jump, etc...).
+view_hpmeter : Ability to see HP bar of every player.
+view_equipment : Ability to view players equipment regardless of their setting.
+use_check : Ability to use client command /check (display character status).
+use_changemaptype : Ability to use client command /changemaptype.
+all_commands: Ability to use ALL atcommands/charcommands.
+receive_requests: Ability to receive @requests.
diff --git a/sql-files/upgrade_svn15572.sql b/sql-files/upgrade_svn15572.sql
new file mode 100644
index 000000000..821bb79d6
--- /dev/null
+++ b/sql-files/upgrade_svn15572.sql
@@ -0,0 +1,3 @@
+-- Rename `level` column to `group_id` in `login` table
+
+ALTER TABLE `login` CHANGE COLUMN `level` `group_id` TINYINT(3) NOT NULL DEFAULT '0'; \ No newline at end of file
diff --git a/src/char/Makefile.in b/src/char/Makefile.in
index e96113f0e..f48f116b8 100644
--- a/src/char/Makefile.in
+++ b/src/char/Makefile.in
@@ -3,17 +3,24 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a
../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \
../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \
../common/obj_all/strlib.o \
- ../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/random.o
+ ../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/random.o ../common/obj_all/conf.o
COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \
../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \
../common/malloc.h ../common/showmsg.h ../common/utils.h \
../common/strlib.h \
- ../common/mapindex.h ../common/ers.h ../common/random.h
+ ../common/mapindex.h ../common/ers.h ../common/random.h ../common/obj_all/conf.h
MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o
MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h
MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+ ../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+ ../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+ ../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
COMMON_SQL_OBJ = ../common/obj_sql/sql.o
COMMON_H = ../common/sql.h
@@ -36,7 +43,7 @@ endif
all: char-server_sql
char-server_sql: $(CHAR_SERVER_SQL_DEPENDS)
- @CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @MYSQL_LIBS@
+ @CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@
clean:
rm -rf *.o obj_sql ../../char-server_sql@EXEEXT@
@@ -57,8 +64,8 @@ needs_mysql:
obj_sql:
-mkdir obj_sql
-obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H)
- @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H) $(LIBCONFIG_H)
+ @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
# missing object files
../common/obj_all/%.o:
@@ -69,3 +76,6 @@ obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H)
MT19937AR_OBJ:
@$(MAKE) -C ../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ:
+ @$(MAKE) -C ../../3rdparty/libconfig
diff --git a/src/char/char.c b/src/char/char.c
index 9f5be7d59..c2490efed 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -126,7 +126,7 @@ struct char_session_data {
int found_char[MAX_CHARS]; // ids of chars on this account
char email[40]; // e-mail (default: a@a.com) by [Yor]
time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
- int gmlevel;
+ int group_id;
uint32 version;
uint8 clienttype;
char new_name[NAME_LENGTH];
@@ -134,7 +134,7 @@ struct char_session_data {
};
int max_connect_user = 0;
-int gm_allow_level = 99;
+int gm_allow_group = -1;
int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
int start_zeny = 0;
int start_weapon = 1201;
@@ -174,7 +174,7 @@ struct auth_node {
uint32 ip;
int sex;
time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
- int gmlevel;
+ int group_id;
unsigned changing_mapservers : 1;
};
@@ -1972,12 +1972,12 @@ int parse_fromlogin(int fd)
int server_id;
memcpy(sd->email, RFIFOP(fd,6), 40);
sd->expiration_time = (time_t)RFIFOL(fd,46);
- sd->gmlevel = RFIFOB(fd,50);
+ sd->group_id = RFIFOB(fd,50);
safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,51), sizeof(sd->birthdate));
ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
// continued from char_auth_ok...
if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
- ( max_connect_user && count_users() >= max_connect_user && sd->gmlevel < gm_allow_level ) ) {
+ ( max_connect_user && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
// refuse connection (over populated)
WFIFOHEAD(i,3);
WFIFOW(i,0) = 0x6c;
@@ -2741,7 +2741,7 @@ int parse_frommap(int fd)
node->sex = RFIFOB(fd,30);
node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
node->ip = ntohl(RFIFOL(fd,31));
- node->gmlevel = RFIFOL(fd,35);
+ node->group_id = RFIFOL(fd,35);
node->changing_mapservers = 1;
idb_put(auth_db, RFIFOL(fd,2), node);
@@ -3102,7 +3102,7 @@ int parse_frommap(int fd)
WFIFOL(fd,8) = node->login_id1;
WFIFOL(fd,12) = node->login_id2;
WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
- WFIFOL(fd,20) = node->gmlevel;
+ WFIFOL(fd,20) = node->group_id;
WFIFOB(fd,24) = node->changing_mapservers;
memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
WFIFOSET(fd, WFIFOW(fd,2));
@@ -3664,7 +3664,7 @@ int parse_char(int fd)
node->login_id2 = sd->login_id2;
node->sex = sd->sex;
node->expiration_time = sd->expiration_time;
- node->gmlevel = sd->gmlevel;
+ node->group_id = sd->group_id;
node->ip = ipl;
idb_put(auth_db, sd->account_id, node);
@@ -4366,10 +4366,8 @@ int char_config_read(const char* cfgName)
max_connect_user = atoi(w2);
if (max_connect_user < 0)
max_connect_user = 0; // unlimited online players
- } else if(strcmpi(w1, "gm_allow_level") == 0) {
- gm_allow_level = atoi(w2);
- if(gm_allow_level < 0)
- gm_allow_level = 99;
+ } else if(strcmpi(w1, "gm_allow_group") == 0) {
+ gm_allow_group = atoi(w2);
} else if (strcmpi(w1, "autosave_time") == 0) {
autosave_interval = atoi(w2)*1000;
if (autosave_interval <= 0)
diff --git a/src/common/Makefile.in b/src/common/Makefile.in
index 8dab1d816..7897b6cfb 100644
--- a/src/common/Makefile.in
+++ b/src/common/Makefile.in
@@ -2,11 +2,13 @@
COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o obj_all/plugins.o obj_all/lock.o \
obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \
obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \
- obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o
+ obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o \
+ obj_all/conf.o
COMMON_H = mmo.h plugin.h version.h \
core.h socket.h timer.h db.h plugins.h lock.h \
nullpo.h malloc.h showmsg.h strlib.h utils.h \
- grfio.h mapindex.h ers.h md5calc.h random.h des.h
+ grfio.h mapindex.h ers.h md5calc.h random.h des.h \
+ conf.h
COMMON_SQL_OBJ = obj_sql/sql.o
COMMON_SQL_H = sql.h
@@ -15,6 +17,13 @@ MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o
MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h
MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+ ../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+ ../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+ ../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
HAVE_MYSQL=@HAVE_MYSQL@
ifeq ($(HAVE_MYSQL),yes)
ALL_DEPENDS=txt sql
@@ -59,21 +68,24 @@ obj_all:
obj_sql:
-mkdir obj_sql
-common: obj_all $(COMMON_OBJ) $(MT19937AR_OBJ)
+common: obj_all $(COMMON_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ)
common_sql: obj_sql $(COMMON_SQL_OBJ)
-obj_all/%.o: %.c $(COMMON_H) $(MT19937AR_H)
- @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_all/%.o: %.c $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H)
+ @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
-obj_all/mini%.o: %.c $(COMMON_H) $(MT19937AR_H)
- @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_all/mini%.o: %.c $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H)
+ @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
-obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H)
- @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) $(LIBCONFIG_H)
+ @CC@ @CFLAGS@ $(LIBCONFIG_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
# missing object files
MT19937AR_OBJ:
@$(MAKE) -C ../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ:
+ @$(MAKE) -C ../../3rdparty/libconfig
diff --git a/src/common/conf.c b/src/common/conf.c
new file mode 100644
index 000000000..eed39d409
--- /dev/null
+++ b/src/common/conf.c
@@ -0,0 +1,109 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include "conf.h"
+#include <libconfig.h>
+
+#include "../common/showmsg.h" // ShowError
+
+int conf_read_file(config_t *config, const char *config_filename)
+{
+ config_init(config);
+ if (!config_read_file(config, config_filename)) {
+ ShowError("%s:%d - %s\n", config_error_file(config),
+ config_error_line(config), config_error_text(config));
+ config_destroy(config);
+ return 1;
+ }
+ return 0;
+}
+
+//
+// Functions to copy settings from libconfig/contrib
+//
+static void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src);
+static void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src);
+static void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src);
+int config_setting_copy(config_setting_t *parent, const config_setting_t *src);
+
+void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src)
+{
+ if (config_setting_is_aggregate(src)) {
+ config_setting_copy_aggregate(parent, src);
+ }
+ else {
+ config_setting_t *set = config_setting_add(parent, config_setting_name(src), config_setting_type(src));
+
+ if (set == NULL)
+ return;
+
+ if (CONFIG_TYPE_INT == config_setting_type(src)) {
+ config_setting_set_int(set, config_setting_get_int(src));
+ config_setting_set_format(set, src->format);
+ } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) {
+ config_setting_set_int64(set, config_setting_get_int64(src));
+ config_setting_set_format(set, src->format);
+ } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) {
+ config_setting_set_float(set, config_setting_get_float(src));
+ } else if (CONFIG_TYPE_STRING == config_setting_type(src)) {
+ config_setting_set_string(set, config_setting_get_string(src));
+ } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) {
+ config_setting_set_bool(set, config_setting_get_bool(src));
+ }
+ }
+}
+
+void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src)
+{
+ config_setting_t *set = NULL;
+
+ if (config_setting_is_aggregate(src))
+ config_setting_copy_aggregate(parent, src);
+ else if (CONFIG_TYPE_INT == config_setting_type(src)) {
+ set = config_setting_set_int_elem(parent, -1, config_setting_get_int(src));
+ config_setting_set_format(set, src->format);
+ } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) {
+ set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src));
+ config_setting_set_format(set, src->format);
+ } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) {
+ set = config_setting_set_float_elem(parent, -1, config_setting_get_float(src));
+ } else if (CONFIG_TYPE_STRING == config_setting_type(src)) {
+ set = config_setting_set_string_elem(parent, -1, config_setting_get_string(src));
+ } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) {
+ set = config_setting_set_bool_elem(parent, -1, config_setting_get_bool(src));
+ }
+}
+
+void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src)
+{
+ config_setting_t *newAgg;
+ int i, n;
+
+ newAgg = config_setting_add(parent, config_setting_name(src), config_setting_type(src));
+
+ if (newAgg == NULL)
+ return;
+
+ n = config_setting_length(src);
+
+ for (i = 0; i < n; i++) {
+ if (config_setting_is_group(src)) {
+ config_setting_copy_simple(newAgg, config_setting_get_elem(src, i));
+ } else {
+ config_setting_copy_elem(newAgg, config_setting_get_elem(src, i));
+ }
+ }
+}
+
+int config_setting_copy(config_setting_t *parent, const config_setting_t *src)
+{
+ if (!config_setting_is_group(parent) && !config_setting_is_list(parent))
+ return CONFIG_FALSE;
+
+ if (config_setting_is_aggregate(src)) {
+ config_setting_copy_aggregate(parent, src);
+ } else {
+ config_setting_copy_simple(parent, src);
+ }
+ return CONFIG_TRUE;
+}
diff --git a/src/common/conf.h b/src/common/conf.h
new file mode 100644
index 000000000..0b70a0c79
--- /dev/null
+++ b/src/common/conf.h
@@ -0,0 +1,13 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _CONF_H_
+#define _CONF_H_
+
+#include "../common/cbasetypes.h"
+#include <libconfig.h>
+
+int conf_read_file(config_t *config, const char *config_filename);
+int config_setting_copy(config_setting_t *parent, const config_setting_t *src);
+
+#endif // _CONF_H_ \ No newline at end of file
diff --git a/src/common/showmsg.c b/src/common/showmsg.c
index 7a6f632e7..b77bf3949 100644
--- a/src/common/showmsg.c
+++ b/src/common/showmsg.c
@@ -13,6 +13,8 @@
#include <time.h>
#include <stdlib.h> // atexit
+#include <libconfig.h>
+
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@@ -872,6 +874,20 @@ int ShowWarning(const char *string, ...) {
va_end(ap);
return ret;
}
+int ShowConfigWarning(config_setting_t *config, const char *string, ...)
+{
+ StringBuf buf;
+ int ret;
+ va_list ap;
+ StringBuf_Init(&buf);
+ StringBuf_AppendStr(&buf, string);
+ StringBuf_Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config));
+ va_start(ap, string);
+ ret = _vShowMessage(MSG_WARNING, StringBuf_Value(&buf), ap);
+ va_end(ap);
+ StringBuf_Destroy(&buf);
+ return ret;
+}
int ShowDebug(const char *string, ...) {
int ret;
va_list ap;
diff --git a/src/common/showmsg.h b/src/common/showmsg.h
index 5f80a4312..839f1dc7e 100644
--- a/src/common/showmsg.h
+++ b/src/common/showmsg.h
@@ -4,6 +4,8 @@
#ifndef _SHOWMSG_H_
#define _SHOWMSG_H_
+#include <libconfig.h>
+
// for help with the console colors look here:
// http://www.edoceo.com/liberum/?doc=printf-with-color
// some code explanation (used here):
@@ -92,5 +94,6 @@ extern int ShowWarning(const char *, ...);
extern int ShowDebug(const char *, ...);
extern int ShowError(const char *, ...);
extern int ShowFatalError(const char *, ...);
+extern int ShowConfigWarning(config_setting_t *config, const char *string, ...);
#endif /* _SHOWMSG_H_ */
diff --git a/src/login/Makefile.in b/src/login/Makefile.in
index 7dfe085c0..7938640aa 100644
--- a/src/login/Makefile.in
+++ b/src/login/Makefile.in
@@ -3,12 +3,13 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a
../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \
../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \
../common/obj_all/strlib.o ../common/obj_all/mapindex.o \
- ../common/obj_all/ers.o ../common/obj_all/md5calc.o ../common/obj_all/random.o
+ ../common/obj_all/ers.o ../common/obj_all/md5calc.o ../common/obj_all/random.o \
+ ../common/obj_all/conf.o
COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \
../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \
../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \
../common/mapindex.h \
- ../common/ers.h ../common/md5calc.h ../common/random.h
+ ../common/ers.h ../common/md5calc.h ../common/random.h ../common/conf.h
COMMON_SQL_OBJ = ../common/obj_sql/sql.o
COMMON_SQL_H = ../common/sql.h
@@ -17,6 +18,13 @@ MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o
MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h
MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+ ../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+ ../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+ ../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
LOGIN_OBJ = login.o
LOGIN_SQL_OBJ = $(LOGIN_OBJ:%=obj_sql/%) \
obj_sql/account_sql.o obj_sql/ipban_sql.o obj_sql/loginlog_sql.o
@@ -62,12 +70,12 @@ obj_sql:
#executables
login-server_sql: $(LOGIN_SERVER_SQL_DEPENDS)
- @CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @MYSQL_LIBS@
+ @CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@
# login object files
-obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H)
- @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H)
+ @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
# missing object files
../common/obj_all/%.o:
@@ -78,3 +86,6 @@ obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H)
MT19937AR_OBJ:
@$(MAKE) -C ../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ:
+ @$(MAKE) -C ../../3rdparty/libconfig
diff --git a/src/login/account.h b/src/login/account.h
index 170d60aca..1b567be70 100644
--- a/src/login/account.h
+++ b/src/login/account.h
@@ -41,7 +41,7 @@ struct mmo_account
char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords
char sex; // gender (M/F/S)
char email[40]; // e-mail (by default: a@a.com)
- int level; // GM level
+ int group_id; // player group id
unsigned int state; // packet 0x006a value + 1 (0: compte OK)
time_t unban_time; // (timestamp): ban time limit of the account (0 = no ban)
time_t expiration_time; // (timestamp): validity limit of the account (0 = unlimited)
diff --git a/src/login/account_sql.c b/src/login/account_sql.c
index bc607c59e..5073941e2 100644
--- a/src/login/account_sql.c
+++ b/src/login/account_sql.c
@@ -522,7 +522,7 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc
// retrieve login entry for the specified account
if( SQL_ERROR == Sql_Query(sql_handle,
- "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`level`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d",
+ "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d",
db->account_db, account_id )
) {
Sql_ShowDebug(sql_handle);
@@ -540,7 +540,7 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc
Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(acc->pass, data, sizeof(acc->pass));
Sql_GetData(sql_handle, 3, &data, NULL); acc->sex = data[0];
Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(acc->email, data, sizeof(acc->email));
- Sql_GetData(sql_handle, 5, &data, NULL); acc->level = atoi(data);
+ Sql_GetData(sql_handle, 5, &data, NULL); acc->group_id = atoi(data);
Sql_GetData(sql_handle, 6, &data, NULL); acc->state = strtoul(data, NULL, 10);
Sql_GetData(sql_handle, 7, &data, NULL); acc->unban_time = atol(data);
Sql_GetData(sql_handle, 8, &data, NULL); acc->expiration_time = atol(data);
@@ -596,14 +596,14 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
if( is_new )
{// insert into account table
if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
- "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `level`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
db->account_db)
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void*)&acc->account_id, sizeof(acc->account_id))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void*)&acc->email, strlen(acc->email))
- || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void*)&acc->level, sizeof(acc->level))
+ || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void*)&acc->expiration_time, sizeof(acc->expiration_time))
@@ -619,12 +619,12 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
}
else
{// update account table
- if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`level`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id)
+ if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id)
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void*)acc->email, strlen(acc->email))
- || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void*)&acc->level, sizeof(acc->level))
+ || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->expiration_time, sizeof(acc->expiration_time))
diff --git a/src/login/login.c b/src/login/login.c
index 78a9b9420..5a504ce2f 100644
--- a/src/login/login.c
+++ b/src/login/login.c
@@ -548,7 +548,7 @@ int parse_fromchar(int fd)
struct mmo_account acc;
time_t expiration_time = 0;
char email[40] = "";
- int gmlevel = 0;
+ int group_id = 0;
char birthdate[10+1] = "";
int account_id = RFIFOL(fd,2);
@@ -560,7 +560,7 @@ int parse_fromchar(int fd)
{
safestrncpy(email, acc.email, sizeof(email));
expiration_time = acc.expiration_time;
- gmlevel = acc.level;
+ group_id = acc.group_id;
safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
}
@@ -569,7 +569,7 @@ int parse_fromchar(int fd)
WFIFOL(fd,2) = account_id;
safestrncpy((char*)WFIFOP(fd,6), email, 40);
WFIFOL(fd,46) = (uint32)expiration_time;
- WFIFOB(fd,50) = gmlevel;
+ WFIFOB(fd,50) = group_id;
safestrncpy((char*)WFIFOP(fd,51), birthdate, 10+1);
WFIFOSET(fd,62);
}
@@ -1068,7 +1068,7 @@ int mmo_auth(struct login_session_data* sd)
sd->login_id2 = rnd();
safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin));
sd->sex = acc.sex;
- sd->level = acc.level;
+ sd->group_id = acc.group_id;
// update account data
timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S");
@@ -1104,9 +1104,9 @@ void login_auth_ok(struct login_session_data* sd)
return;
}
- if( sd->level < login_config.min_level_to_connect )
+ if( login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect )
{
- ShowStatus("Connection refused: the minimum GM level for connection is %d (account: %s, GM level: %d).\n", login_config.min_level_to_connect, sd->userid, sd->level);
+ ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id);
WFIFOHEAD(fd,3);
WFIFOW(fd,0) = 0x81;
WFIFOB(fd,2) = 1; // 01 = Server closed
@@ -1161,11 +1161,7 @@ void login_auth_ok(struct login_session_data* sd)
}
login_log(ip, sd->userid, 100, "login ok");
-
- if( sd->level > 0 )
- ShowStatus("Connection of the GM (level:%d) account '%s' accepted.\n", sd->level, sd->userid);
- else
- ShowStatus("Connection of the account '%s' accepted.\n", sd->userid);
+ ShowStatus("Connection of the account '%s' accepted.\n", sd->userid);
WFIFOHEAD(fd,47+32*server_num);
WFIFOW(fd,0) = 0x69;
@@ -1508,7 +1504,7 @@ void login_set_defaults()
login_config.new_account_flag = true;
login_config.new_acc_length_limit = true;
login_config.use_md5_passwds = false;
- login_config.min_level_to_connect = 0;
+ login_config.group_id_to_connect = -1;
login_config.check_client_version = false;
login_config.client_version_to_connect = 20;
@@ -1575,8 +1571,8 @@ int login_config_read(const char* cfgName)
login_config.client_version_to_connect = strtoul(w2, NULL, 10);
else if(!strcmpi(w1, "use_MD5_passwords"))
login_config.use_md5_passwds = (bool)config_switch(w2);
- else if(!strcmpi(w1, "min_level_to_connect"))
- login_config.min_level_to_connect = atoi(w2);
+ else if(!strcmpi(w1, "group_id_to_connect"))
+ login_config.group_id_to_connect = atoi(w2);
else if(!strcmpi(w1, "date_format"))
safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format));
else if(!strcmpi(w1, "console"))
diff --git a/src/login/login.h b/src/login/login.h
index 3f14ec93c..384372c75 100644
--- a/src/login/login.h
+++ b/src/login/login.h
@@ -34,7 +34,7 @@ struct login_session_data {
uint16 md5keylen;
char lastlogin[24];
- uint8 level;
+ uint8 group_id;
uint8 clienttype;
uint32 version;
@@ -64,7 +64,7 @@ struct Login_Config {
bool new_account_flag,new_acc_length_limit; // autoregistration via _M/_F ? / if yes minimum length is 4?
int start_limited_time; // new account expiration time (-1: unlimited)
bool use_md5_passwds; // work with password hashes instead of plaintext passwords?
- int min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect
+ int group_id_to_connect; // required group id to connect
bool check_client_version; // check the clientversion set in the clientinfo ?
uint32 client_version_to_connect; // the client version needed to connect (if checking is enabled)
diff --git a/src/map/Makefile.in b/src/map/Makefile.in
index dc0e48bf9..16675086d 100644
--- a/src/map/Makefile.in
+++ b/src/map/Makefile.in
@@ -4,13 +4,13 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a
../common/obj_all/nullpo.o ../common/obj_all/malloc.o ../common/obj_all/showmsg.o \
../common/obj_all/utils.o ../common/obj_all/strlib.o ../common/obj_all/grfio.o \
../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/md5calc.o \
- ../common/obj_all/random.o ../common/obj_all/des.o
+ ../common/obj_all/random.o ../common/obj_all/des.o ../common/obj_all/conf.o
COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h \
../common/db.h ../common/plugins.h ../common/lock.h \
../common/nullpo.h ../common/malloc.h ../common/showmsg.h \
../common/utils.h ../common/strlib.h ../common/grfio.h \
../common/mapindex.h ../common/ers.h ../common/md5calc.h \
- ../common/random.h ../common/des.h
+ ../common/random.h ../common/des.h ../common/conf.h
COMMON_SQL_OBJ = ../common/obj_sql/sql.o
COMMON_SQL_H = ../common/sql.h
@@ -19,12 +19,19 @@ MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o
MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h
MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+ ../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+ ../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+ ../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.o \
npc_chat.o chat.o path.o itemdb.o mob.o script.o \
storage.o skill.o atcommand.o battle.o battleground.o \
intif.o trade.o party.o vending.o guild.o pet.o \
log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o instance.o \
- buyingstore.o searchstore.o duel.o
+ buyingstore.o searchstore.o duel.o pc_groups.o
MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) \
obj_sql/mapreg_sql.o
MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \
@@ -32,7 +39,7 @@ MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \
storage.h skill.h atcommand.h battle.h battleground.h \
intif.h trade.h party.h vending.h guild.h pet.h \
log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \
- buyingstore.h searchstore.h duel.h \
+ buyingstore.h searchstore.h duel.h pc_groups.h \
config/Core.h config/Renewal.h config/Secure.h config/Data/Const.h \
config/Skills/General.h config/Skills/Mage_Classes.h config/Skills/Swordsman_Classes.h
@@ -95,12 +102,12 @@ obj_sql:
# executables
map-server_sql: obj_sql $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ)
- @CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@
+ @CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@
# map object files
-obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H)
- @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H) $(LIBCONFIG_H)
+ @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
# missing object files
../common/obj_all/%.o:
@@ -111,3 +118,6 @@ obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H)
MT19937AR_OBJ:
@$(MAKE) -C ../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ:
+ @$(MAKE) -C ../../3rdparty/libconfig
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 701ef0ee8..44249e8af 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -12,6 +12,7 @@
#include "../common/socket.h"
#include "../common/strlib.h"
#include "../common/utils.h"
+#include "../common/conf.h"
#include "atcommand.h"
#include "battle.h"
@@ -24,6 +25,7 @@
#include "log.h"
#include "map.h"
#include "pc.h"
+#include "pc_groups.h" // groupid2name
#include "status.h"
#include "skill.h"
#include "mob.h"
@@ -39,54 +41,43 @@
#include "trade.h"
#include "unit.h"
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
-// extern variables
-char atcommand_symbol = '@'; // first char of the commands
-char charcommand_symbol = '#';
-char* msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others)
-
-// local declarations
-#define ACMD_FUNC(x) int atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message)
-
-DBMap* atcommand_db = NULL;//name -> AtCommandInfo
#define ATCOMMAND_LENGTH 50
+#define ACMD_FUNC(x) static int atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message)
+#define MAX_MSG 1000
-typedef struct AtCommandInfo {
- char command[ATCOMMAND_LENGTH];
- int level;
- int level2;
+typedef struct AtCommandInfo AtCommandInfo;
+typedef struct AliasInfo AliasInfo;
+
+struct AtCommandInfo {
+ char command[ATCOMMAND_LENGTH];
AtCommandFunc func;
-} AtCommandInfo;
+};
-static AtCommandInfo* get_atcommandinfo_byname(const char* name);
+struct AliasInfo {
+ AtCommandInfo *command;
+ char alias[ATCOMMAND_LENGTH];
+};
-ACMD_FUNC(commands);
-ACMD_FUNC(charcommands);
-/*=========================================
- * Generic variables
- *-----------------------------------------*/
-char atcmd_output[CHAT_SIZE_MAX];
-char atcmd_player_name[NAME_LENGTH];
-char atcmd_temp[100];
+char atcommand_symbol = '@'; // first char of the commands
+char charcommand_symbol = '#';
-// compare function for sorting high to lowest
-int hightolow_compare (const void * a, const void * b)
-{
- return ( *(int*)b - *(int*)a );
-}
+static char* msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others)
+static DBMap* atcommand_db = NULL; //name -> AtCommandInfo
+static DBMap* atcommand_alias_db = NULL; //alias -> AtCommandInfo
+static config_t atcommand_config;
-// compare function for sorting lowest to highest
-int lowtohigh_compare (const void * a, const void * b)
-{
- return ( *(int*)a - *(int*)b );
-}
+static char atcmd_output[CHAT_SIZE_MAX];
+static char atcmd_player_name[NAME_LENGTH];
+
+static AtCommandInfo* get_atcommandinfo_byname(const char *name); // @help
+static const char* atcommand_checkalias(const char *aliasname); // @help
//-----------------------------------------------------------
// Return the message string of the specified number by [Yor]
@@ -100,26 +91,6 @@ const char* msg_txt(int msg_number)
return "??";
}
-//-----------------------------------------------------------
-// Returns Players title (from msg_athena.conf) [Lupus]
-//-----------------------------------------------------------
-static char* player_title_txt(int level)
-{
- const char* format;
- format = (level >= battle_config.title_lvl8) ? msg_txt(342)
- : (level >= battle_config.title_lvl7) ? msg_txt(341)
- : (level >= battle_config.title_lvl6) ? msg_txt(340)
- : (level >= battle_config.title_lvl5) ? msg_txt(339)
- : (level >= battle_config.title_lvl4) ? msg_txt(338)
- : (level >= battle_config.title_lvl3) ? msg_txt(337)
- : (level >= battle_config.title_lvl2) ? msg_txt(336)
- : (level >= battle_config.title_lvl1) ? msg_txt(335)
- : "";
- sprintf(atcmd_temp, format, level);
- return atcmd_temp;
-}
-
-
/*==========================================
* Read Message Data
*------------------------------------------*/
@@ -447,11 +418,11 @@ ACMD_FUNC(mapmove)
if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1))
x = y = 0; //Invalid cell, use random spot.
}
- if (map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, msg_txt(247));
return -1;
}
- if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, msg_txt(248));
return -1;
}
@@ -480,9 +451,9 @@ ACMD_FUNC(where)
}
pl_sd = map_nick2sd(atcmd_player_name);
- if( pl_sd == NULL
- || strncmp(pl_sd->status.name,atcmd_player_name,NAME_LENGTH) != 0
- || (battle_config.hide_GM_session && pc_isGM(sd) < pc_isGM(pl_sd) && !(battle_config.who_display_aid && pc_isGM(sd) >= battle_config.who_display_aid))
+ if (pl_sd == NULL ||
+ strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 ||
+ (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID))
) {
clif_displaymessage(fd, msg_txt(3)); // Character not found.
return -1;
@@ -520,13 +491,13 @@ ACMD_FUNC(jumpto)
return -1;
}
- if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd))
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
{
clif_displaymessage(fd, msg_txt(247)); // You are not authorized to warp to this map.
return -1;
}
- if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
{
clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map.
return -1;
@@ -558,7 +529,7 @@ ACMD_FUNC(jump)
sscanf(message, "%hd %hd", &x, &y);
- if (map[sd->bl.m].flag.noteleport && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map.
return -1;
}
@@ -591,7 +562,7 @@ ACMD_FUNC(who3)
struct map_session_data *pl_sd;
struct s_mapiterator* iter;
int j, count;
- int pl_GM_level, GM_level;
+ int level;
char match_text[100];
char player_name[NAME_LENGTH];
@@ -607,20 +578,19 @@ ACMD_FUNC(who3)
match_text[j] = TOLOWER(match_text[j]);
count = 0;
- GM_level = pc_isGM(sd);
+ level = pc_get_group_level(sd);
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- pl_GM_level = pc_isGM(pl_sd);
- if(!( (battle_config.hide_GM_session || (pl_sd->sc.option & OPTION_INVISIBLE)) && pl_GM_level > GM_level ))
+ if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level))
{// you can look only lower or same level
memcpy(player_name, pl_sd->status.name, NAME_LENGTH);
for (j = 0; player_name[j]; j++)
player_name[j] = TOLOWER(player_name[j]);
if (strstr(player_name, match_text) != NULL) { // search with no case sensitive
- if (battle_config.who_display_aid > 0 && pc_isGM(sd) >= battle_config.who_display_aid) {
+ if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) {
sprintf(atcmd_output, "(CID:%d/AID:%d) ", pl_sd->status.char_id, pl_sd->status.account_id);
} else {
atcmd_output[0]=0;
@@ -629,9 +599,8 @@ ACMD_FUNC(who3)
sprintf(temp0, msg_txt(343), pl_sd->status.name);
strcat(atcmd_output,temp0);
//Player title, if exists
- if (pl_GM_level > 0) {
- //sprintf(temp0, "(%s) ", player_title_txt(pl_GM_level) );
- sprintf(temp0, msg_txt(344), player_title_txt(pl_GM_level) );
+ if (pl_sd->group_id > 0) {
+ sprintf(temp0, msg_txt(344), pc_group_id2name(pl_sd->group_id) );
strcat(atcmd_output,temp0);
}
//Players Location: map x y
@@ -666,7 +635,7 @@ ACMD_FUNC(who2)
struct map_session_data *pl_sd;
struct s_mapiterator* iter;
int j, count;
- int pl_GM_level, GM_level;
+ int pl_level, level;
char match_text[100];
char player_name[NAME_LENGTH];
@@ -682,13 +651,13 @@ ACMD_FUNC(who2)
match_text[j] = TOLOWER(match_text[j]);
count = 0;
- GM_level = pc_isGM(sd);
+ level = pc_get_group_level(sd);
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- pl_GM_level = pc_isGM(pl_sd);
- if(!( (battle_config.hide_GM_session || (pl_sd->sc.option & OPTION_INVISIBLE)) && (pl_GM_level > GM_level) ))
+ pl_level = pc_get_group_level(pl_sd);
+ if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level))
{// you can look only lower or same level
memcpy(player_name, pl_sd->status.name, NAME_LENGTH);
for (j = 0; player_name[j]; j++)
@@ -698,9 +667,8 @@ ACMD_FUNC(who2)
//sprintf(atcmd_output, "Name: %s ", pl_sd->status.name);
sprintf(atcmd_output, msg_txt(343), pl_sd->status.name);
//Player title, if exists
- if (pl_GM_level > 0) {
- //sprintf(temp0, "(%s) ", player_title_txt(pl_GM_level) );
- sprintf(temp0, msg_txt(344), player_title_txt(pl_GM_level) );
+ if (pl_sd->group_id > 0) {
+ sprintf(temp0, msg_txt(344), pc_group_id2name(pl_sd->group_id) );
strcat(atcmd_output,temp0);
}
//Players Base Level / Job name
@@ -736,7 +704,7 @@ ACMD_FUNC(who)
struct map_session_data *pl_sd;
struct s_mapiterator* iter;
int j, count;
- int pl_GM_level, GM_level;
+ int pl_level, level;
char match_text[100];
char player_name[NAME_LENGTH];
struct guild *g;
@@ -755,13 +723,13 @@ ACMD_FUNC(who)
match_text[j] = TOLOWER(match_text[j]);
count = 0;
- GM_level = pc_isGM(sd);
+ level = pc_get_group_level(sd);
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- pl_GM_level = pc_isGM(pl_sd);
- if(!( (battle_config.hide_GM_session || (pl_sd->sc.option & OPTION_INVISIBLE)) && pl_GM_level > GM_level ))
+ pl_level = pc_get_group_level(pl_sd);
+ if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level))
{// you can look only lower or same level
memcpy(player_name, pl_sd->status.name, NAME_LENGTH);
for (j = 0; player_name[j]; j++)
@@ -772,8 +740,8 @@ ACMD_FUNC(who)
//Players Name
sprintf(atcmd_output, msg_txt(343), pl_sd->status.name);
//Player title, if exists
- if (pl_GM_level > 0) {
- sprintf(temp0, msg_txt(344), player_title_txt(pl_GM_level) );
+ if (pl_sd->group_id > 0) {
+ sprintf(temp0, msg_txt(344), pc_group_id2name(pl_sd->group_id) );
strcat(atcmd_output,temp0);
}
//Players Party if exists
@@ -815,7 +783,7 @@ ACMD_FUNC(whomap3)
struct map_session_data *pl_sd;
struct s_mapiterator* iter;
int count;
- int pl_GM_level, GM_level;
+ int pl_level, level;
int map_id;
char map_name[MAP_NAME_LENGTH_EXT];
@@ -831,19 +799,19 @@ ACMD_FUNC(whomap3)
}
count = 0;
- GM_level = pc_isGM(sd);
+ level = pc_get_group_level(sd);
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- pl_GM_level = pc_isGM(pl_sd);
+ pl_level = pc_get_group_level(pl_sd);
if( pl_sd->bl.m != map_id )
continue;
- if( (battle_config.hide_GM_session || (pl_sd->sc.option & OPTION_INVISIBLE)) && (pl_GM_level > GM_level) )
+ if ((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pl_level > level)
continue;
- if (pl_GM_level > 0)
- sprintf(atcmd_output, "Name: %s (GM:%d) | Location: %s %d %d", pl_sd->status.name, pl_GM_level, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y);
+ if (pl_level > 0)
+ sprintf(atcmd_output, "Name: %s (GM:%d) | Location: %s %d %d", pl_sd->status.name, pl_level, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y);
else
sprintf(atcmd_output, "Name: %s | Location: %s %d %d", pl_sd->status.name, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y);
clif_displaymessage(fd, atcmd_output);
@@ -871,7 +839,7 @@ ACMD_FUNC(whomap2)
struct map_session_data *pl_sd;
struct s_mapiterator* iter;
int count;
- int pl_GM_level, GM_level;
+ int pl_level, level;
int map_id = 0;
char map_name[MAP_NAME_LENGTH_EXT];
@@ -889,19 +857,19 @@ ACMD_FUNC(whomap2)
}
count = 0;
- GM_level = pc_isGM(sd);
+ level = pc_get_group_level(sd);
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- pl_GM_level = pc_isGM(pl_sd);
+ pl_level = pc_get_group_level(pl_sd);
if( pl_sd->bl.m != map_id )
continue;
- if( (battle_config.hide_GM_session || (pl_sd->sc.option & OPTION_INVISIBLE)) && (pl_GM_level > GM_level) )
+ if ((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pl_level > level)
continue;
- if (pl_GM_level > 0)
- sprintf(atcmd_output, "Name: %s (GM:%d) | BLvl: %d | Job: %s (Lvl: %d)", pl_sd->status.name, pl_GM_level, pl_sd->status.base_level, job_name(pl_sd->status.class_), pl_sd->status.job_level);
+ if (pl_level > 0)
+ sprintf(atcmd_output, "Name: %s (GM:%d) | BLvl: %d | Job: %s (Lvl: %d)", pl_sd->status.name, pl_level, pl_sd->status.base_level, job_name(pl_sd->status.class_), pl_sd->status.job_level);
else
sprintf(atcmd_output, "Name: %s | BLvl: %d | Job: %s (Lvl: %d)", pl_sd->status.name, pl_sd->status.base_level, job_name(pl_sd->status.class_), pl_sd->status.job_level);
clif_displaymessage(fd, atcmd_output);
@@ -931,7 +899,7 @@ ACMD_FUNC(whomap)
struct map_session_data *pl_sd;
struct s_mapiterator* iter;
int count;
- int pl_GM_level, GM_level;
+ int pl_level, level;
int map_id = 0;
char map_name[MAP_NAME_LENGTH_EXT];
struct guild *g;
@@ -953,15 +921,15 @@ ACMD_FUNC(whomap)
}
count = 0;
- GM_level = pc_isGM(sd);
+ level = pc_get_group_level(sd);
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- pl_GM_level = pc_isGM(pl_sd);
+ pl_level = pc_get_group_level(pl_sd);
if( pl_sd->bl.m != map_id )
continue;
- if( (battle_config.hide_GM_session || (pl_sd->sc.option & OPTION_INVISIBLE)) && (pl_GM_level > GM_level) )
+ if ((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pl_level > level)
continue;
g = guild_search(pl_sd->status.guild_id);
@@ -974,8 +942,8 @@ ACMD_FUNC(whomap)
sprintf(temp0, "None");
else
sprintf(temp0, "%s", p->party.name);
- if (pl_GM_level > 0)
- sprintf(atcmd_output, "Name: %s (GM:%d) | Party: '%s' | Guild: '%s'", pl_sd->status.name, pl_GM_level, temp0, temp1);
+ if (pl_level > 0)
+ sprintf(atcmd_output, "Name: %s (GM:%d) | Party: '%s' | Guild: '%s'", pl_sd->status.name, pl_level, temp0, temp1);
else
sprintf(atcmd_output, "Name: %s | Party: '%s' | Guild: '%s'", pl_sd->status.name, temp0, temp1);
clif_displaymessage(fd, atcmd_output);
@@ -1003,7 +971,7 @@ ACMD_FUNC(whogm)
struct map_session_data* pl_sd;
struct s_mapiterator* iter;
int j, count;
- int pl_GM_level, GM_level;
+ int pl_level, level;
char match_text[CHAT_SIZE_MAX];
char player_name[NAME_LENGTH];
struct guild *g;
@@ -1021,13 +989,13 @@ ACMD_FUNC(whogm)
match_text[j] = TOLOWER(match_text[j]);
count = 0;
- GM_level = pc_isGM(sd);
+ level = pc_get_group_level(sd);
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- pl_GM_level = pc_isGM(pl_sd);
- if (!pl_GM_level)
+ pl_level = pc_get_group_level(pl_sd);
+ if (!pl_level)
continue;
if (match_text[0])
@@ -1039,7 +1007,7 @@ ACMD_FUNC(whogm)
if (strstr(player_name, match_text) == NULL)
continue;
}
- if (pl_GM_level > GM_level) {
+ if (pl_level > level) {
if (pl_sd->sc.option & OPTION_INVISIBLE)
continue;
sprintf(atcmd_output, "Name: %s (GM)", pl_sd->status.name);
@@ -1049,7 +1017,7 @@ ACMD_FUNC(whogm)
}
sprintf(atcmd_output, "Name: %s (GM:%d) | Location: %s %d %d",
- pl_sd->status.name, pl_GM_level,
+ pl_sd->status.name, pl_level,
mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y);
clif_displaymessage(fd, atcmd_output);
@@ -1109,11 +1077,11 @@ ACMD_FUNC(load)
nullpo_retr(-1, sd);
m = map_mapindex2mapid(sd->status.save_point.map);
- if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, msg_txt(249)); // You are not authorized to warp to your save map.
return -1;
}
- if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map.
return -1;
}
@@ -1552,7 +1520,7 @@ ACMD_FUNC(kill)
return -1;
}
- if (pc_isGM(sd) < pc_isGM(pl_sd))
+ if (pc_get_group_level(sd) < pc_get_group_level(pl_sd))
{ // you can kill only lower or same level
clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
return -1;
@@ -1941,78 +1909,69 @@ ACMD_FUNC(joblevelup)
*------------------------------------------*/
ACMD_FUNC(help)
{
- char buf[2048], w1[2048], w2[2048];
- int i, gm_level;
- FILE* fp;
- nullpo_retr(-1, sd);
+ config_setting_t *help;
+ const char *text = NULL;
+ const char *command_name = NULL;
+ char *default_command = "help";
- memset(buf, '\0', sizeof(buf));
+ nullpo_retr(-1, sd);
- if ((fp = fopen(help_txt, "r")) != NULL) {
- clif_displaymessage(fd, msg_txt(26)); // Help commands:
- gm_level = pc_isGM(sd);
- while(fgets(buf, sizeof(buf), fp) != NULL) {
- if (buf[0] == '/' && buf[1] == '/')
- continue;
- for (i = 0; buf[i] != '\0'; i++) {
- if (buf[i] == '\r' || buf[i] == '\n') {
- buf[i] = '\0';
- break;
- }
- }
- if (sscanf(buf, "%2047[^:]:%2047[^\n]", w1, w2) < 2)
- clif_displaymessage(fd, buf);
- else if (gm_level >= atoi(w1))
- clif_displaymessage(fd, w2);
- }
- fclose(fp);
- } else {
- clif_displaymessage(fd, msg_txt(27)); // File help.txt not found.
+ help = config_lookup(&atcommand_config, "help");
+ if (help == NULL) {
+ clif_displaymessage(fd, msg_txt(27)); // "Commands help is not available."
return -1;
}
- return 0;
-}
+ if (!message || !*message) {
+ command_name = default_command; // If no command_name specified, display help for @help.
+ } else {
+ if (*message == atcommand_symbol || *message == charcommand_symbol)
+ ++message;
+ command_name = atcommand_checkalias(message);
+ }
-/*==========================================
- * @help2 - Char commands [Kayla]
- *------------------------------------------*/
-ACMD_FUNC(help2)
-{
- char buf[2048], w1[2048], w2[2048];
- int i, gm_level;
- FILE* fp;
- nullpo_retr(-1, sd);
+ if (!pc_can_use_command(sd, command_name, COMMAND_ATCOMMAND)) {
+ sprintf(atcmd_output, msg_txt(153), message); // "%s is Unknown Command"
+ clif_displaymessage(fd, atcmd_output);
+ return -1;
+ }
+
+ if (!config_setting_lookup_string(help, command_name, &text)) {
+ clif_displaymessage(fd, "There is no help for this command_name.");
+ return -1;
+ }
- memset(buf, '\0', sizeof(buf));
+ sprintf(atcmd_output, "Help for command %c%s:", atcommand_symbol, command_name);
+ clif_displaymessage(fd, atcmd_output);
- if ((fp = fopen(help2_txt, "r")) != NULL) {
- clif_displaymessage(fd, msg_txt(26)); // Help commands:
- gm_level = pc_isGM(sd);
- while(fgets(buf, sizeof(buf), fp) != NULL) {
- if (buf[0] == '/' && buf[1] == '/')
- continue;
- for (i = 0; buf[i] != '\0'; i++) {
- if (buf[i] == '\r' || buf[i] == '\n') {
- buf[i] = '\0';
- break;
- }
+ { // Display aliases
+ DBIterator* iter;
+ AtCommandInfo *command_info;
+ AliasInfo *alias_info = NULL;
+ StringBuf buf;
+ bool has_aliases = false;
+
+ StringBuf_Init(&buf);
+ StringBuf_AppendStr(&buf, "Available aliases:");
+ command_info = get_atcommandinfo_byname(command_name);
+ iter = db_iterator(atcommand_alias_db);
+ for (alias_info = (AliasInfo*)dbi_first(iter); dbi_exists(iter); alias_info = (AliasInfo*)dbi_next(iter)) {
+ if (alias_info->command == command_info) {
+ StringBuf_Printf(&buf, " %s", alias_info->alias);
+ has_aliases = true;
}
- if (sscanf(buf, "%2047[^:]:%2047[^\n]", w1, w2) < 2)
- clif_displaymessage(fd, buf);
- else if (gm_level >= atoi(w1))
- clif_displaymessage(fd, w2);
}
- fclose(fp);
- } else {
- clif_displaymessage(fd, msg_txt(27)); // File help.txt not found.
- return -1;
+ iter->destroy(iter);
+ if (has_aliases)
+ clif_displaymessage(fd, StringBuf_Value(&buf));
+ StringBuf_Destroy(&buf);
}
+ // Display help contents
+ clif_displaymessage(fd, text);
return 0;
}
-
// helper function, used in foreach calls to stop auto-attack timers
// parameter: '0' - everyone, 'id' - only those attacking someone with that id
static int atcommand_stopattack(struct block_list *bl,va_list ap)
@@ -2304,7 +2263,7 @@ ACMD_FUNC(go)
nullpo_retr(-1, sd);
- if( map[sd->bl.m].flag.nogo && battle_config.any_warp_GM_min_level > pc_isGM(sd) ) {
+ if( map[sd->bl.m].flag.nogo && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) {
clif_displaymessage(sd->fd,"You can not use @go on this map.");
return 0;
}
@@ -2429,11 +2388,11 @@ ACMD_FUNC(go)
if (town >= 0 && town < ARRAYLENGTH(data))
{
m = map_mapname2mapid(data[town].map);
- if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, msg_txt(247));
return -1;
}
- if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, msg_txt(248));
return -1;
}
@@ -2458,6 +2417,7 @@ ACMD_FUNC(monster)
{
char name[NAME_LENGTH];
char monster[NAME_LENGTH];
+ char eventname[EVENT_NAME_LENGTH] = "";
int mob_id;
int number = 0;
int count;
@@ -2513,6 +2473,11 @@ ACMD_FUNC(monster)
if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit)
number = battle_config.atc_spawn_quantity_limit;
+ if (strcmp(command+1, "monstersmall") == 0)
+ strcpy(eventname, "2");
+ else if (strcmp(command+1, "monsterbig") == 0)
+ strcpy(eventname, "4");
+
if (battle_config.etc_log)
ShowInfo("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, sd->bl.x, sd->bl.y);
@@ -2520,7 +2485,7 @@ ACMD_FUNC(monster)
range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around)
for (i = 0; i < number; i++) {
map_search_freecell(&sd->bl, 0, &mx, &my, range, range, 0);
- k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, "");
+ k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname);
count += (k != 0) ? 1 : 0;
}
@@ -2539,159 +2504,6 @@ ACMD_FUNC(monster)
return 0;
}
-// small monster spawning [Valaris]
-ACMD_FUNC(monstersmall)
-{
- char name[NAME_LENGTH] = "";
- char monster[NAME_LENGTH] = "";
- int mob_id = 0;
- int number = 0;
- int x = 0;
- int y = 0;
- int count;
- int i;
-
- nullpo_retr(-1, sd);
-
- if (!message || !*message) {
- clif_displaymessage(fd, "Give a monster name/id please.");
- return -1;
- }
-
- if (sscanf(message, "\"%23[^\"]\" %23s %d %d %d", name, monster, &number, &x, &y) < 2 &&
- sscanf(message, "%23s \"%23[^\"]\" %d %d %d", monster, name, &number, &x, &y) < 2 &&
- sscanf(message, "%23s %d %23s %d %d", monster, &number, name, &x, &y) < 1) {
- clif_displaymessage(fd, "Give a monster name/id please.");
- return -1;
- }
-
- // If monster identifier/name argument is a name
- if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number)
- mob_id = atoi(monster);
-
- if (mob_id == 0) {
- clif_displaymessage(fd, msg_txt(40));
- return -1;
- }
-
- if (mob_id == MOBID_EMPERIUM) {
- clif_displaymessage(fd, msg_txt(83)); // Cannot spawn emperium
- return -1;
- }
-
- if (mobdb_checkid(mob_id) == 0) {
- clif_displaymessage(fd, "Invalid monster ID"); // Invalid Monster ID.
- return -1;
- }
-
- if (number <= 0)
- number = 1;
-
- if( !name[0] )
- strcpy(name, "--ja--");
-
- // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive
- if (battle_config.atc_spawn_quantity_limit >= 1 && number > battle_config.atc_spawn_quantity_limit)
- number = battle_config.atc_spawn_quantity_limit;
-
- count = 0;
- for (i = 0; i < number; i++) {
- int mx, my;
- if (x <= 0)
- mx = sd->bl.x + (rnd() % 11 - 5);
- else
- mx = x;
- if (y <= 0)
- my = sd->bl.y + (rnd() % 11 - 5);
- else
- my = y;
- count += (mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, "2") != 0) ? 1 : 0;
- }
-
- if (count != 0)
- clif_displaymessage(fd, msg_txt(39)); // Monster Summoned!!
- else
- clif_displaymessage(fd, msg_txt(40)); // Invalid Monster ID.
-
- return 0;
-}
-// big monster spawning [Valaris]
-ACMD_FUNC(monsterbig)
-{
- char name[NAME_LENGTH] = "";
- char monster[NAME_LENGTH] = "";
- int mob_id = 0;
- int number = 0;
- int x = 0;
- int y = 0;
- int count;
- int i;
-
- nullpo_retr(-1, sd);
-
- if (!message || !*message) {
- clif_displaymessage(fd, "Give a monster name/id please.");
- return -1;
- }
-
- if (sscanf(message, "\"%23[^\"]\" %23s %d %d %d", name, monster, &number, &x, &y) < 2 &&
- sscanf(message, "%23s \"%23[^\"]\" %d %d %d", monster, name, &number, &x, &y) < 2 &&
- sscanf(message, "%23s %d %23s %d %d", monster, &number, name, &x, &y) < 1) {
- clif_displaymessage(fd, "Give a monster name/id please.");
- return -1;
- }
-
- // If monster identifier/name argument is a name
- if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number)
- mob_id = atoi(monster);
-
- if (mob_id == 0) {
- clif_displaymessage(fd, msg_txt(40));
- return -1;
- }
-
- if (mob_id == MOBID_EMPERIUM) {
- clif_displaymessage(fd, msg_txt(83)); // Cannot spawn emperium
- return -1;
- }
-
- if (mobdb_checkid(mob_id) == 0) {
- clif_displaymessage(fd, "Invalid monster ID"); // Invalid Monster ID.
- return -1;
- }
-
- if (number <= 0)
- number = 1;
-
- if( !name[0] )
- strcpy(name, "--ja--");
-
- // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive
- if (battle_config.atc_spawn_quantity_limit >= 1 && number > battle_config.atc_spawn_quantity_limit)
- number = battle_config.atc_spawn_quantity_limit;
-
- count = 0;
- for (i = 0; i < number; i++) {
- int mx, my;
- if (x <= 0)
- mx = sd->bl.x + (rnd() % 11 - 5);
- else
- mx = x;
- if (y <= 0)
- my = sd->bl.y + (rnd() % 11 - 5);
- else
- my = y;
- count += (mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, "4") != 0) ? 1 : 0;
- }
-
- if (count != 0)
- clif_displaymessage(fd, msg_txt(39)); // Monster Summoned!!
- else
- clif_displaymessage(fd, msg_txt(40)); // Invalid Monster ID.
-
- return 0;
-}
-
/*==========================================
*
*------------------------------------------*/
@@ -3443,17 +3255,17 @@ ACMD_FUNC(recall)
return -1;
}
- if ( pc_isGM(sd) < pc_isGM(pl_sd) )
+ if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
{
clif_displaymessage(fd, msg_txt(81)); // Your GM level doesn't authorize you to preform this action on the specified player.
return -1;
}
- if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
- clif_displaymessage(fd, "You are not authorised to warp somenone to your actual map.");
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
+ clif_displaymessage(fd, "You are not authorised to warp someone to your actual map.");
return -1;
}
- if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, "You are not authorized to warp this player from its actual map.");
return -1;
}
@@ -3571,7 +3383,7 @@ ACMD_FUNC(char_ban)
tmtime->tm_min = tmtime->tm_min + minute;
tmtime->tm_sec = tmtime->tm_sec + second;
timestamp = mktime(tmtime);
- if( timestamp <= time(NULL) && get_atcommand_level("unban") > pc_isGM(sd) ) {
+ if( timestamp <= time(NULL) && !pc_can_use_command(sd, "unban", COMMAND_ATCOMMAND) ) {
clif_displaymessage(fd,"You are not allowed to reduce the length of a ban");
return -1;
}
@@ -3671,7 +3483,7 @@ ACMD_FUNC(doom)
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- if (pl_sd->fd != fd && pc_isGM(sd) >= pc_isGM(pl_sd))
+ if (pl_sd->fd != fd && pc_get_group_level(sd) >= pc_get_group_level(pl_sd))
{
status_kill(&pl_sd->bl);
clif_specialeffect(&pl_sd->bl,450,AREA);
@@ -3698,7 +3510,7 @@ ACMD_FUNC(doommap)
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- if (pl_sd->fd != fd && sd->bl.m == pl_sd->bl.m && pc_isGM(sd) >= pc_isGM(pl_sd))
+ if (pl_sd->fd != fd && sd->bl.m == pl_sd->bl.m && pc_get_group_level(sd) >= pc_get_group_level(pl_sd))
{
status_kill(&pl_sd->bl);
clif_specialeffect(&pl_sd->bl,450,AREA);
@@ -3788,7 +3600,7 @@ ACMD_FUNC(kick)
return -1;
}
- if ( pc_isGM(sd) < pc_isGM(pl_sd) )
+ if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
{
clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
return -1;
@@ -3811,7 +3623,7 @@ ACMD_FUNC(kickall)
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can kick only lower or same gm level
+ if (pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { // you can kick only lower or same gm level
if (sd->status.account_id != pl_sd->status.account_id)
clif_GM_kick(NULL, pl_sd);
}
@@ -4104,7 +3916,7 @@ ACMD_FUNC(recallall)
memset(atcmd_output, '\0', sizeof(atcmd_output));
- if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, "You are not authorised to warp somenone to your actual map.");
return -1;
}
@@ -4113,9 +3925,9 @@ ACMD_FUNC(recallall)
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- if (sd->status.account_id != pl_sd->status.account_id && pc_isGM(sd) >= pc_isGM(pl_sd))
+ if (sd->status.account_id != pl_sd->status.account_id && pc_get_group_level(sd) >= pc_get_group_level(pl_sd))
{
- if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
count++;
else {
if (pc_isdead(pl_sd)) { //Wake them up
@@ -4157,7 +3969,7 @@ ACMD_FUNC(guildrecall)
return -1;
}
- if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, "You are not authorised to warp somenone to your actual map.");
return -1;
}
@@ -4176,9 +3988,9 @@ ACMD_FUNC(guildrecall)
{
if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.guild_id == g->guild_id)
{
- if (pc_isGM(pl_sd) > pc_isGM(sd))
+ if (pc_get_group_level(pl_sd) > pc_get_group_level(sd))
continue; //Skip GMs greater than you.
- if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
count++;
else
pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
@@ -4216,7 +4028,7 @@ ACMD_FUNC(partyrecall)
return -1;
}
- if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
clif_displaymessage(fd, "You are not authorised to warp somenone to your actual map.");
return -1;
}
@@ -4235,9 +4047,9 @@ ACMD_FUNC(partyrecall)
{
if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.party_id == p->party.party_id)
{
- if (pc_isGM(pl_sd) > pc_isGM(sd))
+ if (pc_get_group_level(pl_sd) > pc_get_group_level(sd))
continue; //Skip GMs greater than you.
- if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
count++;
else
pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
@@ -4297,11 +4109,12 @@ ACMD_FUNC(reloadskilldb)
}
/*==========================================
- * @reloadatcommand - reloads atcommand_athena.conf
+ * @reloadatcommand - reloads atcommand_athena.conf groups.conf
*------------------------------------------*/
void atcommand_doload();
ACMD_FUNC(reloadatcommand) {
atcommand_doload();
+ pc_groups_reload();
clif_displaymessage(fd, msg_txt(254));
return 0;
}
@@ -4833,7 +4646,7 @@ ACMD_FUNC(nuke)
}
if ((pl_sd = map_nick2sd(atcmd_player_name)) != NULL) {
- if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can kill only lower or same GM level
+ if (pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { // you can kill only lower or same GM level
skill_castend_nodamage_id(&pl_sd->bl, &pl_sd->bl, NPC_SELFDESTRUCTION, 99, gettick(), 0);
clif_displaymessage(fd, msg_txt(109)); // Player has been nuked!
} else {
@@ -5143,7 +4956,7 @@ ACMD_FUNC(jail)
return -1;
}
- if (pc_isGM(sd) < pc_isGM(pl_sd))
+ if (pc_get_group_level(sd) < pc_get_group_level(pl_sd))
{ // you can jail only lower or same GM
clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
return -1;
@@ -5195,7 +5008,7 @@ ACMD_FUNC(unjail)
return -1;
}
- if (pc_isGM(sd) < pc_isGM(pl_sd)) { // you can jail only lower or same GM
+ if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) { // you can jail only lower or same GM
clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
return -1;
@@ -5275,7 +5088,7 @@ ACMD_FUNC(jailfor)
return -1;
}
- if (pc_isGM(pl_sd) > pc_isGM(sd)) {
+ if (pc_get_group_level(pl_sd) > pc_get_group_level(sd)) {
clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
return -1;
}
@@ -5859,7 +5672,7 @@ ACMD_FUNC(useskill)
return -1;
}
- if ( pc_isGM(sd) < pc_isGM(pl_sd) )
+ if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
{
clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
return -1;
@@ -6817,76 +6630,29 @@ ACMD_FUNC(summon)
}
/*==========================================
- * @adjcmdlvl by [MouseJstr]
- *
- * Temp adjust the GM level required to use a GM command
- * Useful during beta testing to allow players to use GM commands for short periods of time
- *------------------------------------------*/
-ACMD_FUNC(adjcmdlvl)
-{
- int newlev, newremotelev;
- char name[100];
- AtCommandInfo* cmd;
-
- nullpo_retr(-1, sd);
-
- if (!message || !*message || sscanf(message, "%d %d %99s", &newlev, &newremotelev, name) != 3)
- {
- clif_displaymessage(fd, "Usage: @adjcmdlvl <lvl> <remote lvl> <command>.");
- return -1;
- }
-
- cmd = get_atcommandinfo_byname(name);
- if (cmd == NULL)
- {
- clif_displaymessage(fd, "@command not found.");
- return -1;
- }
- else if (newlev > pc_isGM(sd) || newremotelev > pc_isGM(sd) )
- {
- clif_displaymessage(fd, "You can't make a command require higher GM level than your own.");
- return -1;
- }
- else if (cmd->level > pc_isGM(sd) || cmd->level2 > pc_isGM(sd) )
- {
- clif_displaymessage(fd, "You can't adjust the level of a command which's level is above your own.");
- return -1;
- }
- else
- {
- cmd->level = newlev;
- cmd->level2 = newremotelev;
- clif_displaymessage(fd, "@command level changed.");
- return 0;
- }
-}
-
-/*==========================================
- * @adjgmlvl by [MouseJstr]
- * Create a temp GM
+ * @adjgroup
+ * Temporarily move player to another group
* Useful during beta testing to allow players to use GM commands for short periods of time
*------------------------------------------*/
-ACMD_FUNC(adjgmlvl)
+ACMD_FUNC(adjgroup)
{
- int newlev;
- char user[NAME_LENGTH];
- struct map_session_data *pl_sd;
+ int new_group = 0;
nullpo_retr(-1, sd);
- if (!message || !*message || sscanf(message, "%d %23[^\r\n]", &newlev, user) != 2) {
- clif_displaymessage(fd, "Usage: @adjgmlvl <lvl> <user>.");
+ if (!message || !*message || sscanf(message, "%d", &new_group) != 1) {
+ clif_displaymessage(fd, "Usage: @adjgroup <group_id>");
return -1;
}
- if ( (pl_sd = map_nick2sd(user)) == NULL )
- {
- clif_displaymessage(fd, msg_txt(3)); // Character not found.
+ if (!pc_group_exists(new_group)) {
+ clif_displaymessage(fd, "Specified group does not exists.");
return -1;
}
-
- pl_sd->gmlevel = newlev;
-
- return 0;
+
+ sd->group_id = new_group;
+ clif_displaymessage(fd, "Group changed successfully.");
+ clif_displaymessage(sd->fd, "Your group has changed.");
+ return 0;
}
/*==========================================
@@ -7023,7 +6789,7 @@ ACMD_FUNC(mute)
return -1;
}
- if ( pc_isGM(sd) < pc_isGM(pl_sd) )
+ if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
{
clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
return -1;
@@ -7819,7 +7585,7 @@ static int atcommand_mutearea_sub(struct block_list *bl,va_list ap)
id = va_arg(ap, int);
time = va_arg(ap, int);
- if (id != bl->id && !pc_isGM(pl_sd)) {
+ if (id != bl->id && !pc_get_group_level(pl_sd)) {
pl_sd->status.manner -= time;
if (pl_sd->status.manner < 0)
sc_start(&pl_sd->bl,SC_NOCHAT,100,0,0);
@@ -8316,7 +8082,7 @@ ACMD_FUNC(clone)
return 0;
}
- if(pc_isGM(pl_sd) > pc_isGM(sd)) {
+ if(pc_get_group_level(pl_sd) > pc_get_group_level(sd)) {
clif_displaymessage(fd, msg_txt(126)); // Cannot clone a player of higher GM level than yourself.
return 0;
}
@@ -8431,7 +8197,7 @@ ACMD_FUNC(request)
}
sprintf(atcmd_output, msg_txt(278), message); // (@request): %s
- intif_wis_message_to_gm(sd->status.name, battle_config.lowest_gm_level, atcmd_output);
+ intif_wis_message_to_gm(sd->status.name, PC_PERM_RECEIVE_REQUESTS, atcmd_output);
clif_disp_onlyself(sd, atcmd_output, strlen(atcmd_output));
clif_displaymessage(sd->fd,msg_txt(279)); // @request sent.
return 0;
@@ -8860,6 +8626,72 @@ ACMD_FUNC(font)
return 0;
}
+
+/*==========================================
+ * type: 1 = commands (@), 2 = charcommands (#)
+ *------------------------------------------*/
+static void atcommand_commands_sub(struct map_session_data* sd, const int fd, AtCommandType type)
+{
+ char line_buff[CHATBOX_SIZE];
+ char* cur = line_buff;
+ AtCommandInfo* cmd;
+ DBIterator* iter = atcommand_db->iterator(atcommand_db);
+ int count = 0;
+
+ memset(line_buff,' ',CHATBOX_SIZE);
+ line_buff[CHATBOX_SIZE-1] = 0;
+
+ clif_displaymessage(fd, msg_txt(273)); // "Commands available:"
+
+ for (cmd = (AtCommandInfo*)iter->first(iter, NULL); iter->exists(iter); cmd = (AtCommandInfo*)iter->next(iter, NULL)) {
+ unsigned int slen = 0;
+
+ if (!pc_can_use_command(sd, cmd->command, type))
+ continue;
+
+ slen = strlen(cmd->command);
+
+ // flush the text buffer if this command won't fit into it
+ if ( slen + cur - line_buff >= CHATBOX_SIZE )
+ {
+ clif_displaymessage(fd,line_buff);
+ cur = line_buff;
+ memset(line_buff,' ',CHATBOX_SIZE);
+ line_buff[CHATBOX_SIZE-1] = 0;
+ }
+
+ memcpy(cur,cmd->command,slen);
+ cur += slen+(10-slen%10);
+
+ count++;
+ }
+ iter->destroy(iter);
+ clif_displaymessage(fd,line_buff);
+
+ sprintf(atcmd_output, msg_txt(274), count); // "%d commands found."
+ clif_displaymessage(fd, atcmd_output);
+
+ return;
+}
+
+/*==========================================
+ * @commands Lists available @ commands to you
+ *------------------------------------------*/
+ACMD_FUNC(commands)
+{
+ atcommand_commands_sub(sd, fd, COMMAND_ATCOMMAND);
+ return 0;
+}
+
+/*==========================================
+ * @charcommands Lists available # commands to you
+ *------------------------------------------*/
+ACMD_FUNC(charcommands)
+{
+ atcommand_commands_sub(sd, fd, COMMAND_CHARCOMMAND);
+ return 0;
+}
+
ACMD_FUNC(new_mount) {
clif_displaymessage(sd->fd,"NOTICE: If you crash with mount your LUA is outdated");
if( !(sd->sc.option&OPTION_MOUNTING) ) {
@@ -8875,264 +8707,262 @@ ACMD_FUNC(new_mount) {
/**
* Fills the reference of available commands in atcommand DBMap
**/
+#define ACMD_DEF(x) { #x, atcommand_ ## x }
+#define ACMD_DEF2(x2, x) { x2, atcommand_ ## x }
void atcommand_basecommands(void) {
/**
* Command reference list, place the base of your commands here
- * Dev note: I'd love to get rid of this, if you have a better idea on this please share with the poor mortals
**/
AtCommandInfo atcommand_base[] = {
- { "warp", 40,40, atcommand_mapmove }, // + /mm
- { "where", 1,1, atcommand_where },
- { "goto", 20,20, atcommand_jumpto }, // + /shift
- { "jump", 40,40, atcommand_jump },
- { "who", 20,20, atcommand_who },
- { "who2", 20,20, atcommand_who2 },
- { "who3", 20,20, atcommand_who3 },
- { "whomap", 20,20, atcommand_whomap },
- { "whomap2", 20,20, atcommand_whomap2 },
- { "whomap3", 20,20, atcommand_whomap3 },
- { "whogm", 20,20, atcommand_whogm },
- { "save", 40,40, atcommand_save },
- { "load", 40,40, atcommand_load },
- { "speed", 40,40, atcommand_speed },
- { "storage", 1,1, atcommand_storage },
- { "gstorage", 50,50, atcommand_guildstorage },
- { "option", 40,40, atcommand_option },
- { "hide", 40,40, atcommand_hide }, // + /hide
- { "job", 40,40, atcommand_jobchange },
- { "die", 1,1, atcommand_die },
- { "kill", 60,60, atcommand_kill },
- { "alive", 60,60, atcommand_alive },
- { "kami", 40,40, atcommand_kami },
- { "kamib", 40,40, atcommand_kami },
- { "kamic", 40,40, atcommand_kami },
- { "heal", 40,60, atcommand_heal },
- { "item", 60,60, atcommand_item },
- { "item2", 60,60, atcommand_item2 },
- { "itemreset", 40,40, atcommand_itemreset },
- { "blvl", 60,60, atcommand_baselevelup },
- { "jlvl", 60,60, atcommand_joblevelup },
- { "help", 20,20, atcommand_help },
- { "help2", 20,20, atcommand_help2 },
- { "pvpoff", 40,40, atcommand_pvpoff },
- { "pvpon", 40,40, atcommand_pvpon },
- { "gvgoff", 40,40, atcommand_gvgoff },
- { "gvgon", 40,40, atcommand_gvgon },
- { "model", 20,20, atcommand_model },
- { "go", 10,10, atcommand_go },
- { "monster", 50,50, atcommand_monster },
- { "monstersmall", 50,50, atcommand_monstersmall },
- { "monsterbig", 50,50, atcommand_monsterbig },
- { "killmonster", 60,60, atcommand_killmonster },
- { "killmonster2", 40,40, atcommand_killmonster2 },
- { "refine", 60,60, atcommand_refine },
- { "produce", 60,60, atcommand_produce },
- { "memo", 40,40, atcommand_memo },
- { "gat", 99,99, atcommand_gat },
- { "displaystatus", 99,99, atcommand_displaystatus },
- { "stpoint", 60,60, atcommand_statuspoint },
- { "skpoint", 60,60, atcommand_skillpoint },
- { "zeny", 60,60, atcommand_zeny },
- { "str", 60,60, atcommand_param },
- { "agi", 60,60, atcommand_param },
- { "vit", 60,60, atcommand_param },
- { "int", 60,60, atcommand_param },
- { "dex", 60,60, atcommand_param },
- { "luk", 60,60, atcommand_param },
- { "glvl", 60,60, atcommand_guildlevelup },
- { "makeegg", 60,60, atcommand_makeegg },
- { "hatch", 60,60, atcommand_hatch },
- { "petfriendly", 40,40, atcommand_petfriendly },
- { "pethungry", 40,40, atcommand_pethungry },
- { "petrename", 1,1, atcommand_petrename },
- { "recall", 60,60, atcommand_recall }, // + /recall
- { "night", 80,80, atcommand_night },
- { "day", 80,80, atcommand_day },
- { "doom", 80,80, atcommand_doom },
- { "doommap", 80,80, atcommand_doommap },
- { "raise", 80,80, atcommand_raise },
- { "raisemap", 80,80, atcommand_raisemap },
- { "kick", 20,20, atcommand_kick }, // + right click menu for GM "(name) force to quit"
- { "kickall", 99,99, atcommand_kickall },
- { "allskill", 60,60, atcommand_allskill },
- { "questskill", 40,40, atcommand_questskill },
- { "lostskill", 40,40, atcommand_lostskill },
- { "spiritball", 40,40, atcommand_spiritball },
- { "party", 1,1, atcommand_party },
- { "guild", 50,50, atcommand_guild },
- { "agitstart", 60,60, atcommand_agitstart },
- { "agitend", 60,60, atcommand_agitend },
- { "mapexit", 99,99, atcommand_mapexit },
- { "idsearch", 60,60, atcommand_idsearch },
- { "broadcast", 40,40, atcommand_broadcast }, // + /b and /nb
- { "localbroadcast", 40,40, atcommand_localbroadcast }, // + /lb and /nlb
- { "recallall", 80,80, atcommand_recallall },
- { "reloaditemdb", 99,99, atcommand_reloaditemdb },
- { "reloadmobdb", 99,99, atcommand_reloadmobdb },
- { "reloadskilldb", 99,99, atcommand_reloadskilldb },
- { "reloadscript", 99,99, atcommand_reloadscript },
- { "reloadatcommand", 99,99, atcommand_reloadatcommand },
- { "reloadbattleconf", 99,99, atcommand_reloadbattleconf },
- { "reloadstatusdb", 99,99, atcommand_reloadstatusdb },
- { "reloadpcdb", 99,99, atcommand_reloadpcdb },
- { "reloadmotd", 99,99, atcommand_reloadmotd },
- { "mapinfo", 99,99, atcommand_mapinfo },
- { "dye", 40,40, atcommand_dye },
- { "hairstyle", 40,40, atcommand_hair_style },
- { "haircolor", 40,40, atcommand_hair_color },
- { "allstats", 60,60, atcommand_stat_all },
- { "block", 60,60, atcommand_char_block },
- { "ban", 60,60, atcommand_char_ban },
- { "unblock", 60,60, atcommand_char_unblock },
- { "unban", 60,60, atcommand_char_unban },
- { "mount", 20,20, atcommand_mount_peco },
- { "guildspy", 60,60, atcommand_guildspy },
- { "partyspy", 60,60, atcommand_partyspy },
- { "repairall", 60,60, atcommand_repairall },
- { "guildrecall", 60,60, atcommand_guildrecall },
- { "partyrecall", 60,60, atcommand_partyrecall },
- { "nuke", 60,60, atcommand_nuke },
- { "shownpc", 80,80, atcommand_shownpc },
- { "hidenpc", 80,80, atcommand_hidenpc },
- { "loadnpc", 80,80, atcommand_loadnpc },
- { "unloadnpc", 80,80, atcommand_unloadnpc },
- { "time", 1,1, atcommand_servertime },
- { "jail", 60,60, atcommand_jail },
- { "unjail", 60,60, atcommand_unjail },
- { "jailfor", 60,60, atcommand_jailfor },
- { "jailtime", 1,1, atcommand_jailtime },
- { "disguise", 20,20, atcommand_disguise },
- { "undisguise", 20,20, atcommand_undisguise },
- { "email", 1,1, atcommand_email },
- { "effect", 40,40, atcommand_effect },
- { "follow", 20,20, atcommand_follow },
- { "addwarp", 60,60, atcommand_addwarp },
- { "skillon", 80,80, atcommand_skillon },
- { "skilloff", 80,80, atcommand_skilloff },
- { "killer", 60,60, atcommand_killer },
- { "npcmove", 80,80, atcommand_npcmove },
- { "killable", 40,40, atcommand_killable },
- { "dropall", 40,40, atcommand_dropall },
- { "storeall", 40,40, atcommand_storeall },
- { "skillid", 40,40, atcommand_skillid },
- { "useskill", 40,40, atcommand_useskill },
- { "displayskill", 99,99, atcommand_displayskill },
- { "snow", 99,99, atcommand_snow },
- { "sakura", 99,99, atcommand_sakura },
- { "clouds", 99,99, atcommand_clouds },
- { "clouds2", 99,99, atcommand_clouds2 },
- { "fog", 99,99, atcommand_fog },
- { "fireworks", 99,99, atcommand_fireworks },
- { "leaves", 99,99, atcommand_leaves },
- { "summon", 60,60, atcommand_summon },
- { "adjgmlvl", 99,99, atcommand_adjgmlvl },
- { "adjcmdlvl", 99,99, atcommand_adjcmdlvl },
- { "trade", 60,60, atcommand_trade },
- { "send", 99,99, atcommand_send },
- { "setbattleflag", 99,99, atcommand_setbattleflag },
- { "unmute", 80,80, atcommand_unmute },
- { "clearweather", 99,99, atcommand_clearweather },
- { "uptime", 1,1, atcommand_uptime },
- { "changesex", 60,60, atcommand_changesex },
- { "mute", 80,80, atcommand_mute },
- { "refresh", 1,1, atcommand_refresh },
- { "identify", 40,40, atcommand_identify },
- { "gmotd", 20,20, atcommand_gmotd },
- { "misceffect", 50,50, atcommand_misceffect },
- { "mobsearch", 10,10, atcommand_mobsearch },
- { "cleanmap", 40,40, atcommand_cleanmap },
- { "npctalk", 20,20, atcommand_npctalk },
- { "pettalk", 10,10, atcommand_pettalk },
- { "users", 40,40, atcommand_users },
- { "reset", 40,40, atcommand_reset },
- { "skilltree", 40,40, atcommand_skilltree },
- { "marry", 40,40, atcommand_marry },
- { "divorce", 40,40, atcommand_divorce },
- { "sound", 40,40, atcommand_sound },
- { "undisguiseall", 99,99, atcommand_undisguiseall },
- { "disguiseall", 99,99, atcommand_disguiseall },
- { "changelook", 60,60, atcommand_changelook },
- { "autoloot", 10,10, atcommand_autoloot },
- { "alootid", 10,10, atcommand_autolootitem },
- { "monsterinfo", 1,1, atcommand_mobinfo },
- { "exp", 1,1, atcommand_exp },
- { "adopt", 40,40, atcommand_adopt },
- { "version", 1,1, atcommand_version },
- { "mutearea", 99,99, atcommand_mutearea },
- { "rates", 1,1, atcommand_rates },
- { "iteminfo", 1,1, atcommand_iteminfo },
- { "whodrops", 1,1, atcommand_whodrops },
- { "whereis", 10,10, atcommand_whereis },
- { "mapflag", 99,99, atcommand_mapflag },
- { "me", 20,20, atcommand_me },
- { "battleignore", 99,99, atcommand_monsterignore },
- { "fakename", 20,20, atcommand_fakename },
- { "size", 20,20, atcommand_size },
- { "showexp", 10,10, atcommand_showexp},
- { "showzeny", 10,10, atcommand_showzeny},
- { "showdelay", 1,1, atcommand_showdelay},
- { "autotrade", 10,10, atcommand_autotrade },
- { "changegm", 10,10, atcommand_changegm },
- { "changeleader", 10,10, atcommand_changeleader },
- { "partyoption", 10,10, atcommand_partyoption},
- { "invite", 1,1, atcommand_invite },
- { "duel", 1,1, atcommand_duel },
- { "leave", 1,1, atcommand_leave },
- { "accept", 1,1, atcommand_accept },
- { "reject", 1,1, atcommand_reject },
- { "main", 1,1, atcommand_main },
- { "clone", 50,50, atcommand_clone },
- { "slaveclone", 50,50, atcommand_clone },
- { "evilclone", 50,50, atcommand_clone },
- { "tonpc", 40,40, atcommand_tonpc },
- { "commands", 1,1, atcommand_commands },
- { "noask", 1,1, atcommand_noask },
- { "request", 20,20, atcommand_request },
- { "hlvl", 60,60, atcommand_homlevel },
- { "homevolve", 60,60, atcommand_homevolution },
- { "makehomun", 60,60, atcommand_makehomun },
- { "homfriendly", 60,60, atcommand_homfriendly },
- { "homhungry", 60,60, atcommand_homhungry },
- { "homtalk", 10,10, atcommand_homtalk },
- { "hominfo", 1,1, atcommand_hominfo },
- { "homstats", 1,1, atcommand_homstats },
- { "homshuffle", 60,60, atcommand_homshuffle },
- { "showmobs", 10,10, atcommand_showmobs },
- { "feelreset", 10,10, atcommand_feelreset },
- { "auction", 1,1, atcommand_auction },
- { "mail", 1,1, atcommand_mail },
- { "noks", 1,1, atcommand_ksprotection },
- { "allowks", 40,40, atcommand_allowks },
- { "cash", 60,60, atcommand_cash },
- { "points", 60,60, atcommand_cash },
- { "agitstart2", 60,60, atcommand_agitstart2 },
- { "agitend2", 60,60, atcommand_agitend2 },
- { "skreset", 60,60, atcommand_resetskill },
- { "streset", 60,60, atcommand_resetstat },
- { "storagelist", 40,40, atcommand_itemlist },
- { "cartlist", 40,40, atcommand_itemlist },
- { "itemlist", 40,40, atcommand_itemlist },
- { "stats", 40,40, atcommand_stats },
- { "delitem", 60,60, atcommand_delitem },
- { "charcommands", 1,1, atcommand_charcommands },
- { "font", 1,1, atcommand_font },
+ ACMD_DEF2("warp", mapmove),
+ ACMD_DEF(where),
+ ACMD_DEF(jumpto),
+ ACMD_DEF(jump),
+ ACMD_DEF(who),
+ ACMD_DEF(who2),
+ ACMD_DEF(who3),
+ ACMD_DEF(whomap),
+ ACMD_DEF(whomap2),
+ ACMD_DEF(whomap3),
+ ACMD_DEF(whogm),
+ ACMD_DEF(save),
+ ACMD_DEF(load),
+ ACMD_DEF(speed),
+ ACMD_DEF(storage),
+ ACMD_DEF(guildstorage),
+ ACMD_DEF(option),
+ ACMD_DEF(hide), // + /hide
+ ACMD_DEF(jobchange),
+ ACMD_DEF(die),
+ ACMD_DEF(kill),
+ ACMD_DEF(alive),
+ ACMD_DEF(kami),
+ ACMD_DEF2("kamib", kami),
+ ACMD_DEF2("kamic", kami),
+ ACMD_DEF(heal),
+ ACMD_DEF(item),
+ ACMD_DEF(item2),
+ ACMD_DEF(itemreset),
+ ACMD_DEF2("blvl", baselevelup),
+ ACMD_DEF2("jlvl", joblevelup),
+ ACMD_DEF(help),
+ ACMD_DEF(pvpoff),
+ ACMD_DEF(pvpon),
+ ACMD_DEF(gvgoff),
+ ACMD_DEF(gvgon),
+ ACMD_DEF(model),
+ ACMD_DEF(go),
+ ACMD_DEF(monster),
+ ACMD_DEF2("monstersmall", monster),
+ ACMD_DEF2("monsterbig", monster),
+ ACMD_DEF(killmonster),
+ ACMD_DEF(killmonster2),
+ ACMD_DEF(refine),
+ ACMD_DEF(produce),
+ ACMD_DEF(memo),
+ ACMD_DEF(gat),
+ ACMD_DEF(displaystatus),
+ ACMD_DEF2("stpoint", statuspoint),
+ ACMD_DEF2("skpoint", skillpoint),
+ ACMD_DEF(zeny),
+ ACMD_DEF2("str", param),
+ ACMD_DEF2("agi", param),
+ ACMD_DEF2("vit", param),
+ ACMD_DEF2("int", param),
+ ACMD_DEF2("dex", param),
+ ACMD_DEF2("luk", param),
+ ACMD_DEF2("glvl", guildlevelup),
+ ACMD_DEF(makeegg),
+ ACMD_DEF(hatch),
+ ACMD_DEF(petfriendly),
+ ACMD_DEF(pethungry),
+ ACMD_DEF(petrename),
+ ACMD_DEF(recall), // + /recall
+ ACMD_DEF(night),
+ ACMD_DEF(day),
+ ACMD_DEF(doom),
+ ACMD_DEF(doommap),
+ ACMD_DEF(raise),
+ ACMD_DEF(raisemap),
+ ACMD_DEF(kick), // + right click menu for GM "(name) force to quit"
+ ACMD_DEF(kickall),
+ ACMD_DEF(allskill),
+ ACMD_DEF(questskill),
+ ACMD_DEF(lostskill),
+ ACMD_DEF(spiritball),
+ ACMD_DEF(party),
+ ACMD_DEF(guild),
+ ACMD_DEF(agitstart),
+ ACMD_DEF(agitend),
+ ACMD_DEF(mapexit),
+ ACMD_DEF(idsearch),
+ ACMD_DEF(broadcast), // + /b and /nb
+ ACMD_DEF(localbroadcast), // + /lb and /nlb
+ ACMD_DEF(recallall),
+ ACMD_DEF(reloaditemdb),
+ ACMD_DEF(reloadmobdb),
+ ACMD_DEF(reloadskilldb),
+ ACMD_DEF(reloadscript),
+ ACMD_DEF(reloadatcommand),
+ ACMD_DEF(reloadbattleconf),
+ ACMD_DEF(reloadstatusdb),
+ ACMD_DEF(reloadpcdb),
+ ACMD_DEF(reloadmotd),
+ ACMD_DEF(mapinfo),
+ ACMD_DEF(dye),
+ ACMD_DEF2("hairstyle", hair_style),
+ ACMD_DEF2("haircolor", hair_color),
+ ACMD_DEF2("allstats", stat_all),
+ ACMD_DEF2("block", char_block),
+ ACMD_DEF2("ban", char_ban),
+ ACMD_DEF2("unblock", char_unblock),
+ ACMD_DEF2("unban", char_unban),
+ ACMD_DEF2("mount", mount_peco),
+ ACMD_DEF(guildspy),
+ ACMD_DEF(partyspy),
+ ACMD_DEF(repairall),
+ ACMD_DEF(guildrecall),
+ ACMD_DEF(partyrecall),
+ ACMD_DEF(nuke),
+ ACMD_DEF(shownpc),
+ ACMD_DEF(hidenpc),
+ ACMD_DEF(loadnpc),
+ ACMD_DEF(unloadnpc),
+ ACMD_DEF2("time", servertime),
+ ACMD_DEF(jail),
+ ACMD_DEF(unjail),
+ ACMD_DEF(jailfor),
+ ACMD_DEF(jailtime),
+ ACMD_DEF(disguise),
+ ACMD_DEF(undisguise),
+ ACMD_DEF(email),
+ ACMD_DEF(effect),
+ ACMD_DEF(follow),
+ ACMD_DEF(addwarp),
+ ACMD_DEF(skillon),
+ ACMD_DEF(skilloff),
+ ACMD_DEF(killer),
+ ACMD_DEF(npcmove),
+ ACMD_DEF(killable),
+ ACMD_DEF(dropall),
+ ACMD_DEF(storeall),
+ ACMD_DEF(skillid),
+ ACMD_DEF(useskill),
+ ACMD_DEF(displayskill),
+ ACMD_DEF(snow),
+ ACMD_DEF(sakura),
+ ACMD_DEF(clouds),
+ ACMD_DEF(clouds2),
+ ACMD_DEF(fog),
+ ACMD_DEF(fireworks),
+ ACMD_DEF(leaves),
+ ACMD_DEF(summon),
+ ACMD_DEF(adjgroup),
+ ACMD_DEF(trade),
+ ACMD_DEF(send),
+ ACMD_DEF(setbattleflag),
+ ACMD_DEF(unmute),
+ ACMD_DEF(clearweather),
+ ACMD_DEF(uptime),
+ ACMD_DEF(changesex),
+ ACMD_DEF(mute),
+ ACMD_DEF(refresh),
+ ACMD_DEF(identify),
+ ACMD_DEF(gmotd),
+ ACMD_DEF(misceffect),
+ ACMD_DEF(mobsearch),
+ ACMD_DEF(cleanmap),
+ ACMD_DEF(npctalk),
+ ACMD_DEF(pettalk),
+ ACMD_DEF(users),
+ ACMD_DEF(reset),
+ ACMD_DEF(skilltree),
+ ACMD_DEF(marry),
+ ACMD_DEF(divorce),
+ ACMD_DEF(sound),
+ ACMD_DEF(undisguiseall),
+ ACMD_DEF(disguiseall),
+ ACMD_DEF(changelook),
+ ACMD_DEF(autoloot),
+ ACMD_DEF2("alootid", autolootitem),
+ ACMD_DEF(mobinfo),
+ ACMD_DEF(exp),
+ ACMD_DEF(adopt),
+ ACMD_DEF(version),
+ ACMD_DEF(mutearea),
+ ACMD_DEF(rates),
+ ACMD_DEF(iteminfo),
+ ACMD_DEF(whodrops),
+ ACMD_DEF(whereis),
+ ACMD_DEF(mapflag),
+ ACMD_DEF(me),
+ ACMD_DEF(monsterignore),
+ ACMD_DEF(fakename),
+ ACMD_DEF(size),
+ ACMD_DEF(showexp),
+ ACMD_DEF(showzeny),
+ ACMD_DEF(showdelay),
+ ACMD_DEF(autotrade),
+ ACMD_DEF(changegm),
+ ACMD_DEF(changeleader),
+ ACMD_DEF(partyoption),
+ ACMD_DEF(invite),
+ ACMD_DEF(duel),
+ ACMD_DEF(leave),
+ ACMD_DEF(accept),
+ ACMD_DEF(reject),
+ ACMD_DEF(main),
+ ACMD_DEF(clone),
+ ACMD_DEF2("slaveclone", clone),
+ ACMD_DEF2("evilclone", clone),
+ ACMD_DEF(tonpc),
+ ACMD_DEF(commands),
+ ACMD_DEF(noask),
+ ACMD_DEF(request),
+ ACMD_DEF(homlevel),
+ ACMD_DEF(homevolution),
+ ACMD_DEF(makehomun),
+ ACMD_DEF(homfriendly),
+ ACMD_DEF(homhungry),
+ ACMD_DEF(homtalk),
+ ACMD_DEF(hominfo),
+ ACMD_DEF(homstats),
+ ACMD_DEF(homshuffle),
+ ACMD_DEF(showmobs),
+ ACMD_DEF(feelreset),
+ ACMD_DEF(auction),
+ ACMD_DEF(mail),
+ ACMD_DEF2("noks", ksprotection),
+ ACMD_DEF(allowks),
+ ACMD_DEF(cash),
+ ACMD_DEF2("points", cash),
+ ACMD_DEF(agitstart2),
+ ACMD_DEF(agitend2),
+ ACMD_DEF2("skreset", resetskill),
+ ACMD_DEF2("streset", resetstat),
+ ACMD_DEF2("storagelist", itemlist),
+ ACMD_DEF2("cartlist", itemlist),
+ ACMD_DEF2("itemlist", itemlist),
+ ACMD_DEF(stats),
+ ACMD_DEF(delitem),
+ ACMD_DEF(charcommands),
+ ACMD_DEF(font),
/**
* For Testing Purposes, not going to be here after we're done.
**/
- { "newmount", 0,99, atcommand_new_mount },
+ ACMD_DEF2("newmount", new_mount),
};
AtCommandInfo* atcommand;
int i;
for( i = 0; i < ARRAYLENGTH(atcommand_base); i++ ) {
-
+ if(atcommand_exists(atcommand_base[i].command)) { // Should not happen if atcommand_base[] array is OK
+ ShowDebug("atcommand_basecommands: duplicate ACMD_DEF for '%s'.\n", atcommand_base[i].command);
+ continue;
+ }
CREATE(atcommand, AtCommandInfo, 1);
-
- safestrncpy(atcommand->command,atcommand_base[i].command,sizeof(atcommand->command));
- atcommand->level = atcommand_base[i].level;
- atcommand->level2 = atcommand_base[i].level2;
+ safestrncpy(atcommand->command, atcommand_base[i].command, sizeof(atcommand->command));
atcommand->func = atcommand_base[i].func;
-
strdb_put(atcommand_db, atcommand->command, atcommand);
}
return;
@@ -9141,23 +8971,26 @@ void atcommand_basecommands(void) {
/*==========================================
* Command lookup functions
*------------------------------------------*/
-static AtCommandInfo* get_atcommandinfo_byname(const char* name) {
- if( *name == atcommand_symbol || *name == charcommand_symbol ) name++; // for backwards compatibility
- if( strdb_exists(atcommand_db,name) )
+bool atcommand_exists(const char* name)
+{
+ return strdb_exists(atcommand_db, name);
+}
+
+static AtCommandInfo* get_atcommandinfo_byname(const char *name)
+{
+ if (strdb_exists(atcommand_db, name))
return (AtCommandInfo*)strdb_get(atcommand_db, name);
return NULL;
}
-
-/*==========================================
- * Retrieve the command's required gm level
- *------------------------------------------*/
-int get_atcommand_level(const char* name) {
- AtCommandInfo* info = (AtCommandInfo*)strdb_get(atcommand_db, name);
- return ( info != NULL ) ? info->level : 100; // 100: command can not be used
+static const char* atcommand_checkalias(const char *aliasname)
+{
+ AliasInfo *alias_info = NULL;
+ if ((alias_info = (AliasInfo*)strdb_get(atcommand_alias_db, aliasname)) != NULL)
+ return alias_info->command->command;
+ return aliasname;
}
-
/// Executes an at-command.
bool is_atcommand(const int fd, struct map_session_data* sd, const char* message, int type)
{
@@ -9165,7 +8998,6 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
char charname2[NAME_LENGTH], params2[100];
char command[100];
char output[CHAT_SIZE_MAX];
- int x, y, z;
int lv = 0;
//Reconstructed message
@@ -9177,15 +9009,15 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
nullpo_retr(false, sd);
//Shouldn't happen
- if( !message || !*message )
+ if ( !message || !*message )
return false;
//Block NOCHAT but do not display it as a normal message
- if( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCOMMAND )
+ if ( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCOMMAND )
return true;
// skip 10/11-langtype's codepage indicator, if detected
- if( message[0] == '|' && strlen(message) >= 4 && (message[3] == atcommand_symbol || message[3] == charcommand_symbol) )
+ if ( message[0] == '|' && strlen(message) >= 4 && (message[3] == atcommand_symbol || message[3] == charcommand_symbol) )
message += 3;
//Should display as a normal message
@@ -9194,64 +9026,49 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
// type value 0 = server invoked: bypass restrictions
// 1 = player invoked
- if( type )
- {
+ if ( type == 1) {
//Commands are disabled on maps flagged as 'nocommand'
- if( map[sd->bl.m].nocommand && pc_isGM(sd) < map[sd->bl.m].nocommand )
- {
+ if ( map[sd->bl.m].nocommand && pc_get_group_level(sd) < map[sd->bl.m].nocommand ) {
clif_displaymessage(fd, msg_txt(143));
return false;
}
-
- //Displays as a normal message for Non-GMs
- if( battle_config.atc_gmonly != 0 && pc_isGM(sd) == 0 )
- return false;
}
- while (*message == charcommand_symbol)
- {
- //Checks to see if #command has a name or a name + parameters.
- x = sscanf(message, "%99s \"%23[^\"]\" %99[^\n]", command, charname, params);
- y = sscanf(message, "%99s %23s %99[^\n]", command, charname2, params2);
-
- //z always has the value of the scan that was successful
- z = ( x > 1 ) ? x : y;
+ if (*message == charcommand_symbol) {
+ do {
+ int x, y, z;
+
+ //Checks to see if #command has a name or a name + parameters.
+ x = sscanf(message, "%99s \"%23[^\"]\" %99[^\n]", command, charname, params);
+ y = sscanf(message, "%99s %23s %99[^\n]", command, charname2, params2);
- if ( (ssd = map_nick2sd(charname)) == NULL && ( (ssd = map_nick2sd(charname2)) == NULL ) ) {
- if( pc_isGM(sd) ) {
- sprintf(output, "%s failed. Player not found.", command);
- clif_displaymessage(fd, output);
- } else {
- sprintf(output, "Charcommand failed. Usage: #<command> <char name> <params>.");
- clif_displaymessage(fd, output);
+ //z always has the value of the scan that was successful
+ z = ( x > 1 ) ? x : y;
+
+ //#command + name means the sufficient target was used and anything else after
+ //can be looked at by the actual command function since most scan to see if the
+ //right parameters are used.
+ if ( x > 2 ) {
+ sprintf(atcmd_msg, "%s %s", command, params);
+ break;
+ }
+ else if ( y > 2 ) {
+ sprintf(atcmd_msg, "%s %s", command, params2);
+ break;
+ }
+ //Regardless of what style the #command is used, if it's correct, it will always have
+ //this value if there is no parameter. Send it as just the #command
+ else if ( z == 2 ) {
+ sprintf(atcmd_msg, "%s", command);
+ break;
}
- return true;
- }
-
- //#command + name means the sufficient target was used and anything else after
- //can be looked at by the actual command function since most scan to see if the
- //right parameters are used.
- if ( x > 2 ) {
- sprintf(atcmd_msg, "%s %s", command, params);
- break;
- }
- else if ( y > 2 ) {
- sprintf(atcmd_msg, "%s %s", command, params2);
- break;
- }
- //Regardless of what style the #command is used, if it's correct, it will always have
- //this value if there is no parameter. Send it as just the #command
- else if ( z == 2 ) {
- sprintf(atcmd_msg, "%s", command);
- break;
- }
- sprintf(output, "Charcommand failed. Usage: #<command> <char name> <params>.");
- clif_displaymessage(fd, output);
- return true;
+ sprintf(output, "Charcommand failed. Usage: %c<command> <char name> <params>.", charcommand_symbol);
+ clif_displaymessage(fd, output);
+ return true;
+ } while(0);
}
-
- if (*message == atcommand_symbol) {
+ else if (*message == atcommand_symbol) {
//atcmd_msg is constructed above differently for charcommands
//it's copied from message if not a charcommand so it can
//pass through the rest of the code compatible with both symbols
@@ -9267,9 +9084,10 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
params[0] = '\0';
//Grab the command information and check for the proper GM level required to use it or if the command exists
- if( (info = (AtCommandInfo*)strdb_get(atcommand_db, command+1)) == NULL || info->func == NULL || ( type && ((*atcmd_msg == atcommand_symbol && pc_isGM(sd) < info->level) || (*atcmd_msg == charcommand_symbol && pc_isGM(sd) < info->level2)) ) )
+ info = get_atcommandinfo_byname(atcommand_checkalias(command + 1));
+ if (info == NULL)
{
- if( pc_isGM(sd) ) {
+ if( pc_get_group_level(sd) ) { // TODO: remove or replace with proper permission
sprintf(output, msg_txt(153), command); // "%s is Unknown Command."
clif_displaymessage(fd, output);
return true;
@@ -9277,238 +9095,167 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
return false;
}
- //Log atcommands
- if( *atcmd_msg == atcommand_symbol )
- log_atcommand(sd, info->level, atcmd_msg);
- //Log Charcommands
- else if( *atcmd_msg == charcommand_symbol && ssd != NULL )
- log_atcommand(sd, info->level2, message);
-
+ // type == 1 : player invoked
+ if (type == 1) {
+ if ((*command == atcommand_symbol && !pc_can_use_command(sd, atcommand_checkalias(command + 1), COMMAND_ATCOMMAND)) ||
+ (*command == charcommand_symbol && !pc_can_use_command(sd, atcommand_checkalias(command + 1), COMMAND_CHARCOMMAND))) {
+ return false;
+ }
+ }
+
+ // Check if target is valid only if confirmed that player can use command.
+ if (*message == charcommand_symbol &&
+ (ssd = map_nick2sd(charname)) == NULL && (ssd = map_nick2sd(charname2)) == NULL ) {
+ sprintf(output, "%s failed. Player not found.", command);
+ clif_displaymessage(fd, output);
+ return true;
+ }
+
//Attempt to use the command
- if( strcmpi("adjgmlvl",command+1) && ssd ) { lv = ssd->gmlevel; ssd->gmlevel = sd->gmlevel; }
if ( (info->func(fd, (*atcmd_msg == atcommand_symbol) ? sd : ssd, command, params) != 0) )
{
sprintf(output,msg_txt(154), command); // %s failed.
clif_displaymessage(fd, output);
- }
- if( strcmpi("adjgmlvl",command+1) && ssd ) ssd->gmlevel = lv;
-
- return true;
-}
-/**
- * Splits and parses command aliases field
- * Note: I'm not good (at all) with string manipulation, if you think you can improve, please do. I beg you.
- **/
-void atcommand_parse_aliases(char aliases[1024],AtCommandInfo* base) {
- char *str[99], *p;
- int i, max = 0;
-
- p = aliases;
- while( ISSPACE(*p) )//trim
- ++p;
-
- //I assume nobody is getting over 98 alises in the same command lol
- for( i = 0; i < 99; i++ ) {
- str[i] = p;
- p = strchr(p,',');
- if( p == NULL ) {
- max = i+1;
- break;// comma not found
- }
- *p = '\0';
- ++p;
+ return true;
}
- if( !str[0] )//no aliases at all
- return;
-
- for(i = 0; i < max;i++) {
- AtCommandInfo* atcommand = NULL;
- normalize_name(str[i]," ");//trim over
- if( (atcommand = strdb_get(atcommand_db, str[i])) ) {
- atcommand->level = base->level;
- atcommand->level2 = base->level2;
- continue;
- }
-
- CREATE(atcommand, AtCommandInfo, 1);
-
- safestrncpy(atcommand->command,str[i],sizeof(atcommand->command));
- atcommand->level = base->level;
- atcommand->level2 = base->level2;
- atcommand->func = base->func;
-
- strdb_put(atcommand_db, atcommand->command, atcommand);
- }
+ //Log only if successful.
+ if ( *atcmd_msg == atcommand_symbol )
+ log_atcommand(sd, atcmd_msg);
+ else if ( *atcmd_msg == charcommand_symbol )
+ log_atcommand(sd, message);
- return;
+ return true;
}
+
/*==========================================
*
*------------------------------------------*/
-int atcommand_config_read(const char* cfgName)
+static void atcommand_config_read(const char* config_filename)
{
- char line[1024], w1[1024], w2[1024], w3[1024], w4[1024];
- AtCommandInfo* p;
- FILE* fp;
- int i;
+ config_setting_t *aliases = NULL, *help = NULL;
+ const char *symbol = NULL;
+ int num_aliases = 0;
- if( (fp = fopen(cfgName, "r")) == NULL ) {
- ShowError("AtCommand configuration file not found: %s\n", cfgName);
- return 1;
- }
-
- while( fgets(line, sizeof(line), fp) ) {
- if( line[0] == '/' && line[1] == '/' )
- continue;
- if( ( i = sscanf(line,"%1023[^:]:%1023[^,],%1023[^[][%1023[^]]",w1,w2,w3,w4) ) >= 3 ) {
- if( ( p = (AtCommandInfo*)strdb_get(atcommand_db, w1) ) != NULL ) {
-
- p->level = atoi(w2);//update @level
- p->level2 = atoi(w3);//update #level
-
- /**
- * Parse the alises
- **/
- if( i == 4 )
- atcommand_parse_aliases(w4,p);
-
- continue;//we're done move on
+ if (conf_read_file(&atcommand_config, config_filename))
+ return;
+
+ // Command symbols
+ if (config_lookup_string(&atcommand_config, "atcommand_symbol", &symbol)) {
+ if (ISPRINT(*symbol) && // no control characters
+ *symbol != '/' && // symbol of client commands
+ *symbol != '%' && // symbol of party chat
+ *symbol != '$' && // symbol of guild chat
+ *symbol != charcommand_symbol)
+ atcommand_symbol = *symbol;
+ }
+
+ if (config_lookup_string(&atcommand_config, "charcommand_symbol", &symbol)) {
+ if (ISPRINT(*symbol) && // no control characters
+ *symbol != '/' && // symbol of client commands
+ *symbol != '%' && // symbol of party chat
+ *symbol != '$' && // symbol of guild chat
+ *symbol != atcommand_symbol)
+ charcommand_symbol = *symbol;
+ }
+
+ // Command aliases
+ aliases = config_lookup(&atcommand_config, "aliases");
+ if (aliases != NULL) {
+ int i = 0;
+ int count = config_setting_length(aliases);
+
+ for (i = 0; i < count; ++i) {
+ config_setting_t *command = NULL;
+ const char *commandname = NULL;
+ int j = 0, alias_count = 0;
+ AtCommandInfo *commandinfo = NULL;
+
+ command = config_setting_get_elem(aliases, i);
+ if (config_setting_type(command) != CONFIG_TYPE_ARRAY)
+ continue;
+ commandname = config_setting_name(command);
+ if (!atcommand_exists(commandname)) {
+ ShowConfigWarning(command, "atcommand_config_read: can not set alias for non-existent command %s", commandname);
+ continue;
+ }
+ commandinfo = get_atcommandinfo_byname(commandname);
+ alias_count = config_setting_length(command);
+ for (j = 0; j < alias_count; ++j) {
+ const char *alias = config_setting_get_string_elem(command, j);
+ if (alias != NULL) {
+ AliasInfo *alias_info;
+ if (strdb_exists(atcommand_alias_db, alias)) {
+ ShowConfigWarning(command, "atcommand_config_read: alias %s already exists", alias);
+ continue;
+ }
+ CREATE(alias_info, AliasInfo, 1);
+ alias_info->command = commandinfo;
+ safestrncpy(alias_info->alias, alias, sizeof(alias_info->alias));
+ strdb_put(atcommand_alias_db, alias, alias_info);
+ ++num_aliases;
+ }
}
- } else if( strcmpi(w1, "import") != 0 && strcmpi(w1, "command_symbol") != 0 && strcmpi(w1, "char_symbol") != 0 ) {
- if( i > 1 )
- ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName);
- continue;
}
- normalize_name(w2," ");//trim
- if( strcmpi(w1, "import") == 0 )
- atcommand_config_read(w2);
- else if( strcmpi(w1, "command_symbol") == 0 &&
- w2[0] > 31 && // control characters
- w2[0] != '/' && // symbol of standard ragnarok GM commands
- w2[0] != '%' && // symbol of party chat speaking
- w2[0] != '$' && // symbol of guild chat speaking
- w2[0] != '#' ) // remote symbol
- atcommand_symbol = w2[0];
- else if( strcmpi(w1, "char_symbol") == 0 &&
- w2[0] > 31 &&
- w2[0] != '/' &&
- w2[0] != '%' &&
- w2[0] != '$' &&
- w2[0] != '@' )
- charcommand_symbol = w2[0];
}
- fclose(fp);
-
- return 0;
-}
-static int atcommand_db_free(DBKey key,void *data,va_list va) {
-
- aFree((AtCommandInfo*)data);
-
- return 1;
-}
+ // Commands help
+ // We only check if all commands exist
+ help = config_lookup(&atcommand_config, "help");
+ if (help != NULL) {
+ int count = config_setting_length(help);
+ int i;
-void atcommand_db_clear() {
+ for (i = 0; i < count; ++i) {
+ config_setting_t *command = NULL;
+ const char *commandname = NULL;
- atcommand_db->foreach(atcommand_db,atcommand_db_free);
- db_destroy(atcommand_db);
+ command = config_setting_get_elem(help, i);
+ commandname = config_setting_name(command);
+ if (!atcommand_exists(commandname))
+ ShowConfigWarning(command, "atcommand_config_read: command %s does not exist", commandname);
+ }
+ }
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' command aliases in '"CL_WHITE"%s"CL_RESET"'.\n", num_aliases, config_filename);
return;
}
-void atcommand_doload() {
-
- if( atcommand_db != NULL )
- atcommand_db_clear();
-
- atcommand_db = stridb_alloc(DB_OPT_DUP_KEY, 0);
- atcommand_basecommands();//fills initial atcommand_db with known commands
-
- atcommand_config_read(ATCOMMAND_CONF_FILENAME);
-
- return;
+static int atcommand_db_free(DBKey key, void *data, va_list va)
+{
+ aFree((AtCommandInfo*)data);
+ return 1;
}
-void do_init_atcommand() {
-
- atcommand_doload();
-
+static int atcommand_alias_db_free(DBKey key, void *data, va_list va)
+{
+ aFree((AliasInfo*)data);
+ return 1;
}
-void do_final_atcommand() {
-
- atcommand_db_clear();
-
- return;
+void atcommand_db_clear(void)
+{
+ if (atcommand_db != NULL)
+ atcommand_db->destroy(atcommand_db, atcommand_db_free);
+ if (atcommand_alias_db != NULL)
+ atcommand_alias_db->destroy(atcommand_alias_db, atcommand_alias_db_free);
}
-
-// commands that need to go _after_ the commands table
-
-/*==========================================
- * type: 1 = commands (@), 2 = charcommands (#)
- *------------------------------------------*/
-static void atcommand_commands_sub(struct map_session_data* sd, const int fd, int type) {
- char line_buff[CHATBOX_SIZE];
- int gm_lvl = pc_isGM(sd), count = 0;
- char* cur = line_buff;
- AtCommandInfo* cmd;
- DBIterator* iter = atcommand_db->iterator(atcommand_db);
-
- memset(line_buff,' ',CHATBOX_SIZE);
- line_buff[CHATBOX_SIZE-1] = 0;
-
- clif_displaymessage(fd, msg_txt(273)); // "Commands available:"
-
- for( cmd = (AtCommandInfo*)iter->first(iter,NULL); iter->exists(iter); cmd = (AtCommandInfo*)iter->next(iter,NULL) ) {
- unsigned int slen;
-
- if( type == 1 && gm_lvl < cmd->level )
- continue;
- if( type == 2 && gm_lvl < cmd->level2 )
- continue;
-
- slen = strlen(cmd->command);
-
- // flush the text buffer if this command won't fit into it
- if( slen + cur - line_buff >= CHATBOX_SIZE )
- {
- clif_displaymessage(fd,line_buff);
- cur = line_buff;
- memset(line_buff,' ',CHATBOX_SIZE);
- line_buff[CHATBOX_SIZE-1] = 0;
- }
-
- memcpy(cur,cmd->command,slen);
- cur += slen+(10-slen%10);
-
- count++;
- }
- iter->destroy(iter);
- clif_displaymessage(fd,line_buff);
-
- sprintf(atcmd_output, msg_txt(274), count); // "%d commands found."
- clif_displaymessage(fd, atcmd_output);
-
- return;
+void atcommand_doload(void)
+{
+ atcommand_db_clear();
+ atcommand_db = stridb_alloc(DB_OPT_DUP_KEY, ATCOMMAND_LENGTH);
+ atcommand_alias_db = stridb_alloc(DB_OPT_DUP_KEY, ATCOMMAND_LENGTH);
+ atcommand_basecommands(); //fills initial atcommand_db with known commands
+ atcommand_config_read(ATCOMMAND_CONF_FILENAME);
}
-/*==========================================
- * @commands Lists available @ commands to you
- *------------------------------------------*/
-ACMD_FUNC(commands)
+void do_init_atcommand(void)
{
- atcommand_commands_sub(sd, fd, 1);
- return 0;
- }
+ atcommand_doload();
+}
-/*==========================================
- * @charcommands Lists available # commands to you
- *------------------------------------------*/
-ACMD_FUNC(charcommands)
+void do_final_atcommand(void)
{
- atcommand_commands_sub(sd, fd, 2);
- return 0;
-}
+ atcommand_db_clear();
+} \ No newline at end of file
diff --git a/src/map/atcommand.h b/src/map/atcommand.h
index 415aa9305..a0a7c2286 100644
--- a/src/map/atcommand.h
+++ b/src/map/atcommand.h
@@ -4,7 +4,6 @@
#ifndef _ATCOMMAND_H_
#define _ATCOMMAND_H_
-//#include "map.h"
struct map_session_data;
//This is the distance at which @autoloot works,
@@ -15,32 +14,21 @@ struct map_session_data;
extern char atcommand_symbol;
extern char charcommand_symbol;
+
+typedef enum {
+ COMMAND_ATCOMMAND = 1,
+ COMMAND_CHARCOMMAND = 2,
+} AtCommandType;
+
typedef int (*AtCommandFunc)(const int fd, struct map_session_data* sd, const char* command, const char* message);
bool is_atcommand(const int fd, struct map_session_data* sd, const char* message, int type);
-int get_atcommand_level(const char* name);
void do_init_atcommand(void);
void do_final_atcommand(void);
-int atcommand_config_read(const char *cfgName);
-
-int atcommand_mail(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_item(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_mapmove(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_monster(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_jumpto(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_recall(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_hide(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_mute(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_kick(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_broadcast(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_localbroadcast(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_reset(const int fd, struct map_session_data* sd,const char* command, const char* message);
-int atcommand_unloadnpc(const int fd, struct map_session_data* sd, const char* command, const char* message);
-int atcommand_killmonster(const int fd, struct map_session_data* sd, const char* command, const char* message);
-
-#define MAX_MSG 1000
-extern char* msg_table[MAX_MSG];
+
+bool atcommand_exists(const char* name);
+
const char* msg_txt(int msg_number);
int msg_config_read(const char* cfgName);
void do_final_msg(void);
diff --git a/src/map/battle.c b/src/map/battle.c
index cbf0610ef..a7257406e 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -4441,18 +4441,9 @@ static const struct _battle_data {
{ "guild_max_castles", &battle_config.guild_max_castles, 0, 0, INT_MAX, },
{ "guild_skill_relog_delay", &battle_config.guild_skill_relog_delay, 0, 0, 1, },
{ "emergency_call", &battle_config.emergency_call, 11, 0, 31, },
- { "lowest_gm_level", &battle_config.lowest_gm_level, 1, 0, 99, },
- { "atcommand_gm_only", &battle_config.atc_gmonly, 0, 0, 1, },
{ "atcommand_spawn_quantity_limit", &battle_config.atc_spawn_quantity_limit, 100, 0, INT_MAX, },
{ "atcommand_slave_clone_limit", &battle_config.atc_slave_clone_limit, 25, 0, INT_MAX, },
{ "partial_name_scan", &battle_config.partial_name_scan, 0, 0, 1, },
- { "gm_all_skill", &battle_config.gm_allskill, 0, 0, 100, },
- { "gm_all_equipment", &battle_config.gm_allequip, 0, 0, 100, },
- { "gm_skill_unconditional", &battle_config.gm_skilluncond, 0, 0, 100, },
- { "gm_join_chat", &battle_config.gm_join_chat, 0, 0, 100, },
- { "gm_kick_chat", &battle_config.gm_kick_chat, 0, 0, 100, },
- { "gm_can_party", &battle_config.gm_can_party, 0, 0, 1, },
- { "gm_cant_party_min_lv", &battle_config.gm_cant_party_min_lv, 20, 0, 100, },
{ "player_skillfree", &battle_config.skillfree, 0, 0, 1, },
{ "player_skillup_limit", &battle_config.skillup_limit, 1, 0, 1, },
{ "weapon_produce_rate", &battle_config.wp_rate, 100, 0, INT_MAX, },
@@ -4588,15 +4579,11 @@ static const struct _battle_data {
{ "gx_disptype", &battle_config.gx_disptype, 1, 0, 1, },
{ "devotion_level_difference", &battle_config.devotion_level_difference, 10, 0, INT_MAX, },
{ "player_skill_partner_check", &battle_config.player_skill_partner_check, 1, 0, 1, },
- { "hide_GM_session", &battle_config.hide_GM_session, 0, 0, 1, },
{ "invite_request_check", &battle_config.invite_request_check, 1, 0, 1, },
{ "skill_removetrap_type", &battle_config.skill_removetrap_type, 0, 0, 1, },
{ "disp_experience", &battle_config.disp_experience, 0, 0, 1, },
{ "disp_zeny", &battle_config.disp_zeny, 0, 0, 1, },
{ "castle_defense_rate", &battle_config.castle_defense_rate, 100, 0, 100, },
- { "gm_cant_drop_min_lv", &battle_config.gm_cant_drop_min_lv, 1, 0, 100, },
- { "gm_cant_drop_max_lv", &battle_config.gm_cant_drop_max_lv, 0, 0, 100, },
- { "disp_hpmeter", &battle_config.disp_hpmeter, 0, 0, 100, },
{ "bone_drop", &battle_config.bone_drop, 0, 0, 2, },
{ "buyer_name", &battle_config.buyer_name, 1, 0, 1, },
{ "skill_wall_check", &battle_config.skill_wall_check, 1, 0, 1, },
@@ -4649,9 +4636,6 @@ static const struct _battle_data {
{ "night_at_start", &battle_config.night_at_start, 0, 0, 1, },
{ "show_mob_info", &battle_config.show_mob_info, 0, 0, 1|2|4, },
{ "ban_hack_trade", &battle_config.ban_hack_trade, 0, 0, INT_MAX, },
- { "hack_info_GM_level", &battle_config.hack_info_GM_level, 60, 0, 100, },
- { "any_warp_GM_min_level", &battle_config.any_warp_GM_min_level, 20, 0, 100, },
- { "who_display_aid", &battle_config.who_display_aid, 40, 0, 100, },
{ "packet_ver_flag", &battle_config.packet_ver_flag, 0xFFFFFF,0x0000,INT_MAX, },
{ "min_hair_style", &battle_config.min_hair_style, 0, 0, INT_MAX, },
{ "max_hair_style", &battle_config.max_hair_style, 23, 0, INT_MAX, },
@@ -4699,14 +4683,6 @@ static const struct _battle_data {
{ "mob_max_skilllvl", &battle_config.mob_max_skilllvl, MAX_SKILL_LEVEL, 1, MAX_SKILL_LEVEL, },
{ "retaliate_to_master", &battle_config.retaliate_to_master, 1, 0, 1, },
{ "rare_drop_announce", &battle_config.rare_drop_announce, 0, 0, 10000, },
- { "title_lvl1", &battle_config.title_lvl1, 1, 0, 100, },
- { "title_lvl2", &battle_config.title_lvl2, 10, 0, 100, },
- { "title_lvl3", &battle_config.title_lvl3, 20, 0, 100, },
- { "title_lvl4", &battle_config.title_lvl4, 40, 0, 100, },
- { "title_lvl5", &battle_config.title_lvl5, 50, 0, 100, },
- { "title_lvl6", &battle_config.title_lvl6, 60, 0, 100, },
- { "title_lvl7", &battle_config.title_lvl7, 80, 0, 100, },
- { "title_lvl8", &battle_config.title_lvl8, 99, 0, 100, },
{ "duel_allow_pvp", &battle_config.duel_allow_pvp, 0, 0, 1, },
{ "duel_allow_gvg", &battle_config.duel_allow_gvg, 0, 0, 1, },
{ "duel_allow_teleport", &battle_config.duel_allow_teleport, 0, 0, 1, },
@@ -4750,7 +4726,6 @@ static const struct _battle_data {
{ "ksprotection", &battle_config.ksprotection, 5000, 0, INT_MAX, },
{ "auction_feeperhour", &battle_config.auction_feeperhour, 12000, 0, INT_MAX, },
{ "auction_maximumprice", &battle_config.auction_maximumprice, 500000000, 0, MAX_ZENY, },
- { "gm_viewequip_min_lv", &battle_config.gm_viewequip_min_lv, 0, 0, 99, },
{ "homunculus_auto_vapor", &battle_config.homunculus_auto_vapor, 1, 0, 1, },
{ "display_status_timers", &battle_config.display_status_timers, 1, 0, 1, },
{ "skill_add_heal_rate", &battle_config.skill_add_heal_rate, 7, 0, INT_MAX, },
@@ -4760,7 +4735,6 @@ static const struct _battle_data {
{ "autospell_check_range", &battle_config.autospell_check_range, 0, 0, 1, },
{ "client_reshuffle_dice", &battle_config.client_reshuffle_dice, 0, 0, 1, },
{ "client_sort_storage", &battle_config.client_sort_storage, 0, 0, 1, },
- { "gm_check_minlevel", &battle_config.gm_check_minlevel, 60, 0, 100, },
{ "feature.buying_store", &battle_config.feature_buying_store, 1, 0, 1, },
{ "feature.search_stores", &battle_config.feature_search_stores, 1, 0, 1, },
{ "searchstore_querydelay", &battle_config.searchstore_querydelay, 10, 0, INT_MAX, },
diff --git a/src/map/battle.h b/src/map/battle.h
index 43c1d69ec..54b707f08 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -151,16 +151,9 @@ extern struct Battle_Config
int monster_max_aspd;
int view_range_rate;
int chase_range_rate;
- int lowest_gm_level;
- int atc_gmonly;
int atc_spawn_quantity_limit;
int atc_slave_clone_limit;
int partial_name_scan;
- int gm_allskill;
- int gm_allequip;
- int gm_skilluncond;
- int gm_join_chat;
- int gm_kick_chat;
int skillfree;
int skillup_limit;
int wp_rate;
@@ -327,7 +320,6 @@ extern struct Battle_Config
int gx_disptype;
int devotion_level_difference;
int player_skill_partner_check;
- int hide_GM_session;
int invite_request_check;
int skill_removetrap_type;
int disp_experience;
@@ -336,21 +328,14 @@ extern struct Battle_Config
int backstab_bow_penalty;
int hp_rate;
int sp_rate;
- int gm_cant_drop_min_lv;
- int gm_cant_drop_max_lv;
- int disp_hpmeter;
int bone_drop;
int buyer_name;
- int gm_cant_party_min_lv;
- int gm_can_party; // [SketchyPhoenix]
// eAthena additions
int night_at_start; // added by [Yor]
int day_duration; // added by [Yor]
int night_duration; // added by [Yor]
int ban_hack_trade; // added by [Yor]
- int hack_info_GM_level; // added by [Yor]
- int any_warp_GM_min_level; // added by [Yor]
int packet_ver_flag; // added by [Yor]
int min_hair_style; // added by [MouseJstr]
@@ -387,7 +372,6 @@ extern struct Battle_Config
int delay_battle_damage;
int hide_woe_damage;
int display_version;
- int who_display_aid;
int display_hallucination; // [Skotlex]
int use_statpoint_table; // [Skotlex]
@@ -415,15 +399,6 @@ extern struct Battle_Config
int retaliate_to_master; //Whether when a mob is attacked by another mob, it will retaliate versus the mob or the mob's master. [Skotlex]
- int title_lvl1; // Players titles [Lupus]
- int title_lvl2; // Players titles [Lupus]
- int title_lvl3; // Players titles [Lupus]
- int title_lvl4; // Players titles [Lupus]
- int title_lvl5; // Players titles [Lupus]
- int title_lvl6; // Players titles [Lupus]
- int title_lvl7; // Players titles [Lupus]
- int title_lvl8; // Players titles [Lupus]
-
int duel_allow_pvp; // [LuzZza]
int duel_allow_gvg; // [LuzZza]
int duel_allow_teleport; // [LuzZza]
@@ -466,7 +441,6 @@ extern struct Battle_Config
int ksprotection;
int auction_feeperhour;
int auction_maximumprice;
- int gm_viewequip_min_lv;
int homunculus_auto_vapor; //Keep Homunculus from Vaporizing when master dies. [L0ne_W0lf]
int display_status_timers; //Show or hide skill buff/delay timers in recent clients [Sara]
int skill_add_heal_rate; //skills that bHealPower has effect on [Inkfish]
@@ -476,7 +450,6 @@ extern struct Battle_Config
int autospell_check_range; //Enable range check for autospell bonus. [L0ne_W0lf]
int client_reshuffle_dice; // Reshuffle /dice
int client_sort_storage;
- int gm_check_minlevel; // min GM level for /check
int feature_buying_store;
int feature_search_stores;
int searchstore_querydelay;
diff --git a/src/map/buyingstore.c b/src/map/buyingstore.c
index 01964a56e..a556a41a2 100644
--- a/src/map/buyingstore.c
+++ b/src/map/buyingstore.c
@@ -98,7 +98,7 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
return;
}
- if( !pc_can_give_items(pc_isGM(sd)) )
+ if( !pc_can_give_items(sd) )
{// custom: GM is not allowed to buy (give zeny)
sd->buyingstore.slots = 0;
clif_displaymessage(sd->fd, msg_txt(246));
@@ -145,7 +145,7 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
break;
}
- if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_isGM(sd), pc_isGM(sd)) || ( idx = pc_search_inventory(sd, nameid) ) == -1 )
+ if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_get_group_level(sd), pc_get_group_level(sd)) || ( idx = pc_search_inventory(sd, nameid) ) == -1 )
{// restrictions: allowed, no character-bound items and at least one must be owned
break;
}
@@ -219,7 +219,7 @@ void buyingstore_open(struct map_session_data* sd, int account_id)
return;
}
- if( !pc_can_give_items(pc_isGM(sd)) )
+ if( !pc_can_give_items(sd) )
{// custom: GM is not allowed to sell
clif_displaymessage(sd->fd, msg_txt(246));
return;
@@ -257,7 +257,7 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int
return;
}
- if( !pc_can_give_items(pc_isGM(sd)) )
+ if( !pc_can_give_items(sd) )
{// custom: GM is not allowed to sell
clif_displaymessage(sd->fd, msg_txt(246));
clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
@@ -312,7 +312,7 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int
return;
}
- if( sd->status.inventory[index].expire_time || !itemdb_cantrade(&sd->status.inventory[index], pc_isGM(sd), pc_isGM(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
+ if( sd->status.inventory[index].expire_time || !itemdb_cantrade(&sd->status.inventory[index], pc_get_group_level(sd), pc_get_group_level(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
{// non-tradable item
clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
return;
diff --git a/src/map/chat.c b/src/map/chat.c
index 48c0b07f1..9a59950d4 100644
--- a/src/map/chat.c
+++ b/src/map/chat.c
@@ -125,7 +125,7 @@ int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass)
return 0;
}
- if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !(battle_config.gm_join_chat && pc_isGM(sd) >= battle_config.gm_join_chat) )
+ if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !pc_has_permission(sd, PC_PERM_JOIN_ALL_CHAT) )
{
clif_joinchatfail(sd,1);
return 0;
@@ -316,7 +316,7 @@ int chat_kickchat(struct map_session_data* sd, const char* kickusername)
if( i == cd->users )
return -1;
- if( battle_config.gm_kick_chat && pc_isGM(cd->usersd[i]) >= battle_config.gm_kick_chat )
+ if (pc_has_permission(cd->usersd[i], PC_PERM_NO_CHAT_KICK))
return 0; //gm kick protection [Valaris]
idb_put(cd->kick_list,cd->usersd[i]->status.char_id,(void*)1);
diff --git a/src/map/chrif.c b/src/map/chrif.c
index 10b7135b6..5d060a16f 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -412,7 +412,7 @@ int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port)
WFIFOW(char_fd,28) = htons(port);
WFIFOB(char_fd,30) = sd->status.sex;
WFIFOL(char_fd,31) = htonl(session[sd->fd]->client_addr);
- WFIFOL(char_fd,35) = sd->gmlevel;
+ WFIFOL(char_fd,35) = sd->group_id;
WFIFOSET(char_fd,39);
return 0;
}
@@ -578,7 +578,7 @@ void chrif_authok(int fd)
uint32 login_id1;
uint32 login_id2;
time_t expiration_time;
- int gmlevel;
+ int group_id;
struct mmo_charstatus* status;
int char_id;
struct auth_node *node;
@@ -595,7 +595,7 @@ void chrif_authok(int fd)
login_id1 = RFIFOL(fd,8);
login_id2 = RFIFOL(fd,12);
expiration_time = (time_t)(int32)RFIFOL(fd,16);
- gmlevel = RFIFOL(fd,20);
+ group_id = RFIFOL(fd,20);
changing_mapservers = (RFIFOB(fd,24));
status = (struct mmo_charstatus*)RFIFOP(fd,25);
char_id = status->char_id;
@@ -628,7 +628,7 @@ void chrif_authok(int fd)
node->char_id == char_id &&
node->login_id1 == login_id1 )
{ //Auth Ok
- if (pc_authok(sd, login_id2, expiration_time, gmlevel, status, changing_mapservers))
+ if (pc_authok(sd, login_id2, expiration_time, group_id, status, changing_mapservers))
return;
} else { //Auth Failed
pc_authfail(sd);
diff --git a/src/map/clif.c b/src/map/clif.c
index f38ce5ef2..3f7ad28ee 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -1779,7 +1779,7 @@ void clif_selllist(struct map_session_data *sd)
{
if( sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] )
{
- if( !itemdb_cansell(&sd->status.inventory[i], pc_isGM(sd)) )
+ if( !itemdb_cansell(&sd->status.inventory[i], pc_get_group_level(sd)) )
continue;
if( sd->status.inventory[i].expire_time )
@@ -2625,6 +2625,59 @@ void clif_guild_xy_remove(struct map_session_data *sd)
clif_send(buf,packet_len(0x1eb),&sd->bl,GUILD_SAMEMAP_WOS);
}
+/*==========================================
+ *
+ *------------------------------------------*/
+static int clif_hpmeter_sub(struct block_list *bl, va_list ap)
+{
+ struct map_session_data *sd, *tsd;
+#if PACKETVER < 20100126
+ const int cmd = 0x106;
+#else
+ const int cmd = 0x80e;
+#endif
+
+ sd = va_arg(ap, struct map_session_data *);
+ tsd = (TBL_PC *)bl;
+
+ nullpo_ret(sd);
+ nullpo_ret(tsd);
+
+ if( !tsd->fd || tsd == sd )
+ return 0;
+
+ if( !pc_has_permission(tsd, PC_PERM_VIEW_HPMETER) )
+ return 0;
+ WFIFOHEAD(tsd->fd,packet_len(cmd));
+ WFIFOW(tsd->fd,0) = cmd;
+ WFIFOL(tsd->fd,2) = sd->status.account_id;
+#if PACKETVER < 20100126
+ if( sd->battle_status.max_hp > INT16_MAX )
+ { //To correctly display the %hp bar. [Skotlex]
+ WFIFOW(tsd->fd,6) = sd->battle_status.hp/(sd->battle_status.max_hp/100);
+ WFIFOW(tsd->fd,8) = 100;
+ } else {
+ WFIFOW(tsd->fd,6) = sd->battle_status.hp;
+ WFIFOW(tsd->fd,8) = sd->battle_status.max_hp;
+ }
+#else
+ WFIFOL(tsd->fd,6) = sd->battle_status.hp;
+ WFIFOL(tsd->fd,10) = sd->battle_status.max_hp;
+#endif
+ WFIFOSET(tsd->fd,packet_len(cmd));
+ return 0;
+}
+
+/*==========================================
+ * Server tells all players that are allowed to view HP bars
+ * and are nearby 'sd' that 'sd' hp bar was updated.
+ *------------------------------------------*/
+static int clif_hpmeter(struct map_session_data *sd)
+{
+ nullpo_ret(sd);
+ map_foreachinarea(clif_hpmeter_sub, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_PC, sd);
+ return 0;
+}
/// Notifies client of a character parameter change.
/// 00b0 <var id>.W <value>.L (ZC_PAR_CHANGE)
@@ -2700,8 +2753,7 @@ void clif_updatestatus(struct map_session_data *sd,int type)
case SP_HP:
WFIFOL(fd,4)=sd->battle_status.hp;
// TODO: Won't these overwrite the current packet?
- if( battle_config.disp_hpmeter )
- clif_hpmeter(sd);
+ clif_hpmeter(sd);
if( !battle_config.party_hp_mode && sd->status.party_id )
clif_party_hp(sd);
if( sd->bg_id )
@@ -3922,7 +3974,6 @@ int clif_status_load_single(int fd, int id,int type,int flag,int val1, int val2,
*------------------------------------------*/
static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* dstsd)
{
- int gmlvl;
struct block_list *d_bl;
int i;
@@ -3943,7 +3994,8 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d
}
if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting.
(sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround
- (battle_config.disp_hpmeter && (gmlvl = pc_isGM(sd)) >= battle_config.disp_hpmeter && gmlvl >= pc_isGM(dstsd)) )
+ pc_has_permission(sd, PC_PERM_VIEW_HPMETER)
+ )
clif_hpmeter_single(sd->fd, dstsd->bl.id, dstsd->battle_status.hp, dstsd->battle_status.max_hp);
// display link (sd - dstsd) to sd
@@ -5235,26 +5287,31 @@ void clif_status_change(struct block_list *bl,int type,int flag,unsigned int tic
/// 008e <packet len>.W <message>.?B
void clif_displaymessage(const int fd, const char* mes)
{
- // invalid pointer?
nullpo_retv(mes);
//Scrapped, as these are shared by disconnected players =X [Skotlex]
if (fd == 0)
;
else {
- int len_mes = strlen(mes);
-
- if (len_mes > 0) { // don't send a void message (it's not displaying on the client chat). @help can send void line.
- WFIFOHEAD(fd, 5 + len_mes);
- WFIFOW(fd,0) = 0x8e;
- WFIFOW(fd,2) = 5 + len_mes; // 4 + len + NULL teminate
- memcpy(WFIFOP(fd,4), mes, len_mes + 1);
- WFIFOSET(fd, 5 + len_mes);
+ char *message, *line;
+
+ message = aStrdup(mes);
+ line = strtok(message, "\n");
+ while(line != NULL) {
+ int len = strlen(line);
+ if (len > 0) { // don't send a void message (it's not displaying on the client chat). @help can send void line.
+ WFIFOHEAD(fd, 5 + len);
+ WFIFOW(fd,0) = 0x8e;
+ WFIFOW(fd,2) = 5 + len; // 4 + len + NULL teminate
+ memcpy(WFIFOP(fd,4), line, len + 1);
+ WFIFOSET(fd, 5 + len);
+ }
+ line = strtok(NULL, "\n");
}
+ aFree(message);
}
}
-
/// Send broadcast message in yellow or blue without font formatting (ZC_BROADCAST).
/// 009a <packet len>.W <message>.?B
void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target)
@@ -5518,7 +5575,7 @@ void clif_wis_message(int fd, const char* nick, const char* mes, int mes_len)
WFIFOW(fd,2) = mes_len + NAME_LENGTH + 8;
safestrncpy((char*)WFIFOP(fd,4), nick, NAME_LENGTH);
WFIFOL(fd,28) = 0; // isAdmin; if nonzero, also displays text above char
- // TODO: WFIFOL(fd,28) = ( pc_isGM(ssd) >= battle_config.lowest_gm_level );
+ // TODO: WFIFOL(fd,28) = pc_get_group_level(ssd);
safestrncpy((char*)WFIFOP(fd,32), mes, mes_len);
WFIFOSET(fd,WFIFOW(fd,2));
#endif
@@ -6419,64 +6476,6 @@ void clif_hpmeter_single(int fd, int id, unsigned int hp, unsigned int maxhp)
WFIFOSET(fd, packet_len(cmd));
}
-/*==========================================
- *
- *------------------------------------------*/
-int clif_hpmeter_sub(struct block_list *bl, va_list ap)
-{
- struct map_session_data *sd, *tsd;
- int level;
-#if PACKETVER < 20100126
- const int cmd = 0x106;
-#else
- const int cmd = 0x80e;
-#endif
-
- sd = va_arg(ap, struct map_session_data *);
- tsd = (TBL_PC *)bl;
-
- nullpo_ret(sd);
- nullpo_ret(tsd);
-
- if( !tsd->fd || tsd == sd )
- return 0;
-
- if( (level = pc_isGM(tsd)) < battle_config.disp_hpmeter || level < pc_isGM(sd) )
- return 0;
- WFIFOHEAD(tsd->fd,packet_len(cmd));
- WFIFOW(tsd->fd,0) = cmd;
- WFIFOL(tsd->fd,2) = sd->status.account_id;
-#if PACKETVER < 20100126
- if( sd->battle_status.max_hp > INT16_MAX )
- { //To correctly display the %hp bar. [Skotlex]
- WFIFOW(tsd->fd,6) = sd->battle_status.hp/(sd->battle_status.max_hp/100);
- WFIFOW(tsd->fd,8) = 100;
- } else {
- WFIFOW(tsd->fd,6) = sd->battle_status.hp;
- WFIFOW(tsd->fd,8) = sd->battle_status.max_hp;
- }
-#else
- WFIFOL(tsd->fd,6) = sd->battle_status.hp;
- WFIFOL(tsd->fd,10) = sd->battle_status.max_hp;
-#endif
- WFIFOSET(tsd->fd,packet_len(cmd));
- return 0;
-}
-
-/*==========================================
- * Server tells all nearby gms to 'sd' that 'sd' hp bar was updated
- *------------------------------------------*/
-int clif_hpmeter(struct map_session_data *sd)
-{
- nullpo_ret(sd);
-
- if( battle_config.disp_hpmeter )
- map_foreachinarea(clif_hpmeter_sub, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_PC, sd);
-
- return 0;
-}
-
-
/// Notifies the client, that it's attack target is too far (ZC_ATTACK_FAILURE_FOR_DISTANCE).
/// 0139 <target id>.L <target x>.W <target y>.W <x>.W <y>.W <atk range>.W
void clif_movetoattack(struct map_session_data *sd,struct block_list *bl)
@@ -9417,7 +9416,7 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd)
sc = status_get_sc(bl);
if (sc && sc->option&OPTION_INVISIBLE && !disguised(bl) &&
bl->type != BL_NPC && //Skip hidden NPCs which can be seen using Maya Purple
- pc_isGM(sd) < battle_config.hack_info_GM_level
+ pc_get_group_level(sd) < battle_config.hack_info_GM_level
) {
char gm_msg[256];
sprintf(gm_msg, "Hack on NameRequest: character '%s' (account: %d) requested the name of an invisible target (id: %d).\n", sd->status.name, sd->status.account_id, id);
@@ -9506,21 +9505,13 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
/// 0140 <map name>.16B <x>.W <y>.W
void clif_parse_MapMove(int fd, struct map_session_data *sd)
{
- char output[MAP_NAME_LENGTH_EXT+15]; // Max length of a short: ' -6XXXX' -> 7 digits
- char message[MAP_NAME_LENGTH_EXT+15+5]; // "/mm "+output
+ char command[MAP_NAME_LENGTH_EXT+25];
char* map_name;
- if (battle_config.atc_gmonly && !pc_isGM(sd))
- return;
- if(pc_isGM(sd) < get_atcommand_level("warp"))
- return;
-
map_name = (char*)RFIFOP(fd,2);
map_name[MAP_NAME_LENGTH_EXT-1]='\0';
- sprintf(output, "%s %d %d", map_name, RFIFOW(fd,18), RFIFOW(fd,20));
- atcommand_mapmove(fd, sd, "@mapmove", output);
- sprintf(message, "/mm %s", output);
- log_atcommand(sd, get_atcommand_level("warp"), message);
+ sprintf(command, "@mapmove %s %d %d", map_name, RFIFOW(fd,18), RFIFOW(fd,20));
+ is_atcommand(fd, sd, command, 1);
}
@@ -9861,7 +9852,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd)
// if player ignores everyone
if (dstsd->state.ignoreAll)
{
- if (dstsd->sc.option & OPTION_INVISIBLE && pc_isGM(sd) < pc_isGM(dstsd))
+ if (dstsd->sc.option & OPTION_INVISIBLE && pc_get_group_level(sd) < pc_get_group_level(dstsd))
clif_wis_end(fd, 1); // 1: target character is not loged in
else
clif_wis_end(fd, 3); // 3: everyone ignored by target
@@ -9897,25 +9888,14 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd)
/// 0099 <packet len>.W <text>.?B 00
void clif_parse_Broadcast(int fd, struct map_session_data* sd)
{
+ char command[CHAT_SIZE_MAX+11];
char* msg = (char*)RFIFOP(fd,4);
unsigned int len = RFIFOW(fd,2)-4;
- int lv;
-
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- return;
- if( pc_isGM(sd) < (lv=get_atcommand_level("broadcast")) )
- return;
// as the length varies depending on the command used, just block unreasonably long strings
len = mes_len_check(msg, len, CHAT_SIZE_MAX);
-
- intif_broadcast(msg, len, 0);
-
- {
- char logmsg[CHAT_SIZE_MAX+4];
- sprintf(logmsg, "/b %s", msg);
- log_atcommand(sd, lv, logmsg);
- }
+ sprintf(command, "@broadcast %s", msg);
+ is_atcommand(fd, sd, command, 1);
}
@@ -11066,23 +11046,10 @@ void clif_parse_SolveCharName(int fd, struct map_session_data *sd)
/// 1 = skill
void clif_parse_ResetChar(int fd, struct map_session_data *sd)
{
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- return;
-
- if( pc_isGM(sd) < get_atcommand_level("reset") )
- return;
-
if( RFIFOW(fd,2) )
- pc_resetskill(sd,1);
- else {
- pc_resetstate(sd);
- if( sd->mission_mobid ) { //bugreport:2200
- sd->mission_mobid = 0;
- sd->mission_count = 0;
- pc_setglobalreg(sd,"TK_MISSION_ID", 0);
- }
- }
- log_atcommand(sd, get_atcommand_level("reset"), RFIFOW(fd,2) ? "/resetskill" : "/resetstate");
+ is_atcommand(fd, sd, "@resetskill", 1);
+ else
+ is_atcommand(fd, sd, "@resetstat", 1);
}
@@ -11091,26 +11058,15 @@ void clif_parse_ResetChar(int fd, struct map_session_data *sd)
/// 019c <packet len>.W <text>.?B
void clif_parse_LocalBroadcast(int fd, struct map_session_data* sd)
{
+ char command[CHAT_SIZE_MAX+16];
char* msg = (char*)RFIFOP(fd,4);
unsigned int len = RFIFOW(fd,2)-4;
- int lv;
-
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- return;
-
- if( pc_isGM(sd) < (lv=get_atcommand_level("localbroadcast")) )
- return;
-
+
// as the length varies depending on the command used, just block unreasonably long strings
len = mes_len_check(msg, len, CHAT_SIZE_MAX);
- clif_broadcast(&sd->bl, msg, len, 0, ALL_SAMEMAP);
-
- {
- char logmsg[CHAT_SIZE_MAX+5];
- sprintf(logmsg, "/lb %s", msg);
- log_atcommand(sd, lv, logmsg);
- }
+ sprintf(command, "@localbroadcast %s", msg);
+ is_atcommand(fd, sd, command, 1);
}
@@ -12168,10 +12124,7 @@ void clif_parse_ChangePetName(int fd, struct map_session_data *sd)
void clif_parse_GMKick(int fd, struct map_session_data *sd)
{
struct block_list *target;
- int tid,lv;
-
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- return;
+ int tid;
tid = RFIFOL(fd,2);
target = map_id2bl(tid);
@@ -12183,69 +12136,36 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd)
switch (target->type) {
case BL_PC:
{
- struct map_session_data *tsd = (struct map_session_data *)target;
- if (pc_isGM(sd) <= pc_isGM(tsd))
- {
- clif_GM_kickack(sd, 0);
- return;
- }
-
- lv = get_atcommand_level("kick");
- if( pc_isGM(sd) < lv )
- {
- clif_GM_kickack(sd, 0);
- return;
- }
-
- {
- char message[256];
- sprintf(message, "/kick %s (%d)", tsd->status.name, tsd->status.char_id);
- log_atcommand(sd, lv, message);
- }
-
- clif_GM_kick(sd, tsd);
+ char command[NAME_LENGTH+6];
+ sprintf(command, "@kick %s", status_get_name(target));
+ is_atcommand(fd, sd, command, 1);
}
break;
+
+ /**
+ * This one does not invoke any atcommand, so we need to check for permissions.
+ */
case BL_MOB:
{
- lv = get_atcommand_level("killmonster");
- if( pc_isGM(sd) < lv )
- {
+ char command[100];
+ if( !pc_can_use_command(sd, "killmonster", COMMAND_ATCOMMAND)) {
clif_GM_kickack(sd, 0);
return;
}
-
- {
- char message[256];
- sprintf(message, "/kick %s (%d)", status_get_name(target), status_get_class(target));
- log_atcommand(sd, lv, message);
- }
-
+ sprintf(command, "/kick %s (%d)", status_get_name(target), status_get_class(target));
+ log_atcommand(sd, command);
status_percent_damage(&sd->bl, target, 100, 0, true); // can invalidate 'target'
}
break;
+
case BL_NPC:
{
- struct npc_data* nd = (struct npc_data *)target;
- lv = get_atcommand_level("unloadnpc");
- if( pc_isGM(sd) < lv )
- {
- clif_GM_kickack(sd, 0);
- return;
- }
-
- {
- char message[256];
- sprintf(message, "/kick %s (%d)", status_get_name(target), status_get_class(target));
- log_atcommand(sd, lv, message);
- }
-
- // copy-pasted from atcommand_unloadnpc
- npc_unload_duplicates(nd);
- npc_unload(nd); // invalidates 'target'
- npc_read_event_script();
+ char command[NAME_LENGTH+11];
+ sprintf(command, "@unloadnpc %s", status_get_name(target));
+ is_atcommand(fd, sd, command, 1);
}
break;
+
default:
clif_GM_kickack(sd, 0);
}
@@ -12271,21 +12191,13 @@ void clif_parse_GMKickAll(int fd, struct map_session_data* sd)
void clif_parse_GMShift(int fd, struct map_session_data *sd)
{// FIXME: remove is supposed to receive account name for clients prior 20100803RE
char *player_name;
- int lv;
-
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- return;
- if( pc_isGM(sd) < (lv=get_atcommand_level("goto")) )
- return;
+ char command[NAME_LENGTH+8];
player_name = (char*)RFIFOP(fd,2);
player_name[NAME_LENGTH-1] = '\0';
- atcommand_jumpto(fd, sd, "@jumpto", player_name); // as @jumpto
- {
- char message[NAME_LENGTH+7];
- sprintf(message, "/shift %s", player_name);
- log_atcommand(sd, lv, message);
- }
+
+ sprintf(command, "@jumpto %s", player_name);
+ is_atcommand(fd, sd, command, 1);
}
@@ -12294,31 +12206,15 @@ void clif_parse_GMShift(int fd, struct map_session_data *sd)
/// 0843 <account id>.L
void clif_parse_GMRemove2(int fd, struct map_session_data* sd)
{
- int account_id, lv;
+ int account_id;
struct map_session_data* pl_sd;
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- {
- return;
- }
-
- if( pc_isGM(sd) < ( lv = get_atcommand_level("goto") ) )
- {
- return;
- }
-
account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
-
- if( ( pl_sd = map_id2sd(account_id) ) != NULL && pc_isGM(sd) >= pc_isGM(pl_sd) )
+ if( (pl_sd = map_id2sd(account_id)) != NULL )
{
- pc_warpto(sd, pl_sd);
- }
-
- {
- char message[32];
-
- sprintf(message, "/remove %d", account_id);
- log_atcommand(sd, lv, message);
+ char command[NAME_LENGTH+8];
+ sprintf(command, "@jumpto %s", pl_sd->status.name);
+ is_atcommand(fd, sd, command, 1);
}
}
@@ -12333,22 +12229,13 @@ void clif_parse_GMRemove2(int fd, struct map_session_data* sd)
void clif_parse_GMRecall(int fd, struct map_session_data *sd)
{// FIXME: recall is supposed to receive account name for clients prior 20100803RE
char *player_name;
- int lv;
-
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- return;
-
- if( pc_isGM(sd) < (lv=get_atcommand_level("recall")) )
- return;
+ char command [NAME_LENGTH+8];
player_name = (char*)RFIFOP(fd,2);
player_name[NAME_LENGTH-1] = '\0';
- atcommand_recall(fd, sd, "@recall", player_name); // as @recall
- {
- char message[NAME_LENGTH+8];
- sprintf(message, "/recall %s", player_name);
- log_atcommand(sd, lv, message);
- }
+
+ sprintf(command, "@recall %s", player_name);
+ is_atcommand(fd, sd, command, 1);
}
@@ -12357,31 +12244,15 @@ void clif_parse_GMRecall(int fd, struct map_session_data *sd)
/// 0842 <account id>.L
void clif_parse_GMRecall2(int fd, struct map_session_data* sd)
{
- int account_id, lv;
+ int account_id;
struct map_session_data* pl_sd;
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- {
- return;
- }
-
- if( pc_isGM(sd) < ( lv = get_atcommand_level("recall") ) )
- {
- return;
- }
-
account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
-
- if( ( pl_sd = map_id2sd(account_id) ) != NULL && pc_isGM(sd) >= pc_isGM(pl_sd) )
+ if( (pl_sd = map_id2sd(account_id)) != NULL )
{
- pc_recall(sd, pl_sd);
- }
-
- {
- char message[32];
-
- sprintf(message, "/recall %d", account_id);
- log_atcommand(sd, lv, message);
+ char command[NAME_LENGTH+8];
+ sprintf(command, "@recall %s", pl_sd->status.name);
+ is_atcommand(fd, sd, command, 1);
}
}
@@ -12392,33 +12263,21 @@ void clif_parse_GMRecall2(int fd, struct map_session_data* sd)
void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd)
{
char *monster_item_name;
- char message[NAME_LENGTH+10]; //For logging.
- int level;
-
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- return;
+ char command[NAME_LENGTH+10];
monster_item_name = (char*)RFIFOP(fd,2);
monster_item_name[NAME_LENGTH-1] = '\0';
if( mobdb_searchname(monster_item_name) ) {
- if( pc_isGM(sd) < (level=get_atcommand_level("monster")) )
- return;
- atcommand_monster(fd, sd, "@monster", monster_item_name); // as @monster
- { //Log action. [Skotlex]
- snprintf(message, sizeof(message)-1, "@monster %s", monster_item_name);
- log_atcommand(sd, level, message);
- }
+ snprintf(command, sizeof(command)-1, "@monster %s", monster_item_name);
+ is_atcommand(fd, sd, command, 1);
return;
}
- if( itemdb_searchname(monster_item_name) == NULL )
- return;
- if( pc_isGM(sd) < (level = get_atcommand_level("item")) )
+
+ if( itemdb_searchname(monster_item_name) ) {
+ snprintf(command, sizeof(command)-1, "@item %s", monster_item_name);
+ is_atcommand(fd, sd, command, 1);
return;
- atcommand_item(fd, sd, "@item", monster_item_name); // as @item
- { //Log action. [Skotlex]
- sprintf(message, "@item %s", monster_item_name);
- log_atcommand(sd, level, message);
}
}
@@ -12429,26 +12288,7 @@ void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd)
/// TODO: Any OPTION_* ?
void clif_parse_GMHide(int fd, struct map_session_data *sd)
{
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- return;
-
- if( pc_isGM(sd) < get_atcommand_level("hide") )
- return;
-
- if( sd->sc.option & OPTION_INVISIBLE ) {
- sd->sc.option &= ~OPTION_INVISIBLE;
- if (sd->disguise)
- status_set_viewdata(&sd->bl, sd->disguise);
- else
- status_set_viewdata(&sd->bl, sd->status.class_);
- clif_displaymessage(fd, "Invisible: Off.");
- } else {
- sd->sc.option |= OPTION_INVISIBLE;
- sd->vd.class_ = INVISIBLE_CLASS;
- clif_displaymessage(fd, "Invisible: On.");
- log_atcommand(sd, get_atcommand_level("hide"), "/hide");
- }
- clif_changeoption(&sd->bl);
+ is_atcommand(fd, sd, "@hide", 1);
}
@@ -12460,41 +12300,28 @@ void clif_parse_GMHide(int fd, struct map_session_data *sd)
/// 2 = self mute (+10 minutes)
void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd)
{
- int id, type, value, level;
+ int id, type, value;
struct map_session_data *dstsd;
+ char command[NAME_LENGTH+15];
id = RFIFOL(fd,2);
type = RFIFOB(fd,6);
value = RFIFOW(fd,7);
if( type == 0 )
- value = 0 - value;
+ value = -value;
//If type is 2 and the ids don't match, this is a crafted hacked packet!
//Disabled because clients keep self-muting when you give players public @ commands... [Skotlex]
- if (type == 2 /* && (pc_isGM(sd) > 0 || sd->bl.id != id)*/)
+ if (type == 2 /* && (pc_get_group_level(sd) > 0 || sd->bl.id != id)*/)
return;
dstsd = map_id2sd(id);
if( dstsd == NULL )
return;
- if( (level = pc_isGM(sd)) > pc_isGM(dstsd) && level >= get_atcommand_level("mute") )
- {
- clif_manner_message(sd, 0);
- clif_manner_message(dstsd, 5);
-
- if( dstsd->status.manner < value ) {
- dstsd->status.manner -= value;
- sc_start(&dstsd->bl,SC_NOCHAT,100,0,0);
- } else {
- dstsd->status.manner = 0;
- status_change_end(&dstsd->bl, SC_NOCHAT, INVALID_TIMER);
- }
-
- if( type != 2 )
- clif_GM_silence(sd, dstsd, type);
- }
+ sprintf(command, "@mute %d %s", value, dstsd->status.name);
+ is_atcommand(fd, sd, command, 1);
}
@@ -12503,23 +12330,12 @@ void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd)
/// 0212 <char name>.24B
void clif_parse_GMRc(int fd, struct map_session_data* sd)
{
- char* name = (char*)RFIFOP(fd,2);
- struct map_session_data* dstsd;
- name[23] = '\0';
- dstsd = map_nick2sd(name);
- if( dstsd == NULL )
- return;
-
- if( pc_isGM(sd) > pc_isGM(dstsd) && pc_isGM(sd) >= get_atcommand_level("mute") )
- {
- clif_manner_message(sd, 0);
- clif_manner_message(dstsd, 3);
-
- dstsd->status.manner -= 60;
- sc_start(&dstsd->bl,SC_NOCHAT,100,0,0);
+ char command[NAME_LENGTH+15];
+ char *name = (char*)RFIFOP(fd,2);
- clif_GM_silence(sd, dstsd, 1);
- }
+ name[NAME_LENGTH-1] = '\0';
+ sprintf(command, "@mute %d %s", 60, name);
+ is_atcommand(fd, sd, command, 1);
}
@@ -12552,10 +12368,7 @@ void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd)
{
int x,y,type;
- if( battle_config.atc_gmonly && !pc_isGM(sd) )
- return;
-
- if( pc_isGM(sd) < 99 ) //TODO: add proper check
+ if( pc_has_permission(sd, PC_PERM_USE_CHANGEMAPTYPE) )
return;
x = RFIFOW(fd,2);
@@ -12576,7 +12389,6 @@ void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd)
/// 1 = (/in nick) allow speech from nick
void clif_parse_PMIgnore(int fd, struct map_session_data* sd)
{
- char output[512];
char* nick;
uint8 type;
int i;
@@ -12592,12 +12404,7 @@ void clif_parse_PMIgnore(int fd, struct map_session_data* sd)
if( type == 0 )
{ // Add name to ignore list (block)
-
- // Bot-check...
- if (strcmp(wisp_server_name, nick) == 0)
- { // to find possible bot users who automaticaly ignore people
- sprintf(output, "Character '%s' (account: %d) has tried to block wisps from '%s' (wisp name of the server). Bot user?", sd->status.name, sd->status.account_id, wisp_server_name);
- intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, output);
+ if (strcmp(wisp_server_name, nick) == 0) {
WFIFOB(fd,3) = 1; // fail
WFIFOSET(fd, packet_len(0x0d1));
return;
@@ -13412,14 +13219,12 @@ void clif_parse_Check(int fd, struct map_session_data *sd)
char charname[NAME_LENGTH];
struct map_session_data* pl_sd;
- if( pc_isGM(sd) < battle_config.gm_check_minlevel )
- {
+ if(!pc_has_permission(sd, PC_PERM_USE_CHECK))
return;
- }
safestrncpy(charname, (const char*)RFIFOP(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]), sizeof(charname));
- if( ( pl_sd = map_nick2sd(charname) ) == NULL || pc_isGM(sd) < pc_isGM(pl_sd) )
+ if( ( pl_sd = map_nick2sd(charname) ) == NULL || pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
{
return;
}
@@ -14003,9 +13808,9 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd)
return;
}
- if( !pc_can_give_items(pc_isGM(sd)) || sd->status.inventory[idx].expire_time ||
+ if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time ||
!sd->status.inventory[idx].identify ||
- !itemdb_canauction(&sd->status.inventory[idx],pc_isGM(sd)) ) { // Quest Item or something else
+ !itemdb_canauction(&sd->status.inventory[idx],pc_get_group_level(sd)) ) { // Quest Item or something else
clif_Auction_setitem(sd->fd, idx, true);
return;
}
@@ -14158,7 +13963,7 @@ void clif_parse_Auction_bid(int fd, struct map_session_data *sd)
unsigned int auction_id = RFIFOL(fd,2);
int bid = RFIFOL(fd,6);
- if( !pc_can_give_items(pc_isGM(sd)) ) { //They aren't supposed to give zeny [Inkfish]
+ if( !pc_can_give_items(sd) ) { //They aren't supposed to give zeny [Inkfish]
clif_displaymessage(sd->fd, msg_txt(246));
return;
}
@@ -14456,7 +14261,7 @@ void clif_parse_ViewPlayerEquip(int fd, struct map_session_data* sd)
if (!tsd)
return;
- if( tsd->status.show_equip || (battle_config.gm_viewequip_min_lv && pc_isGM(sd) >= battle_config.gm_viewequip_min_lv) )
+ if( tsd->status.show_equip || pc_has_permission(sd, PC_PERM_VIEW_EQUIPMENT) )
clif_viewequip_ack(sd, tsd);
else
clif_viewequip_fail(sd);
@@ -15995,11 +15800,11 @@ static int clif_parse(int fd)
//Disassociate character from the socket connection.
session[fd]->session_data = NULL;
sd->fd = 0;
- ShowInfo("%sCharacter '"CL_WHITE"%s"CL_RESET"' logged off (using @autotrade).\n", (pc_isGM(sd))?"GM ":"", sd->status.name);
+ ShowInfo("Character '"CL_WHITE"%s"CL_RESET"' logged off (using @autotrade).\n", sd->status.name);
} else
if (sd->state.active) {
// Player logout display [Valaris]
- ShowInfo("%sCharacter '"CL_WHITE"%s"CL_RESET"' logged off.\n", (pc_isGM(sd))?"GM ":"", sd->status.name);
+ ShowInfo("Character '"CL_WHITE"%s"CL_RESET"' logged off.\n", sd->status.name);
clif_quitsave(fd, sd);
} else {
//Unusual logout (during log on/off/map-changer procedure)
diff --git a/src/map/clif.h b/src/map/clif.h
index 206b7d68e..3994541b5 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -504,8 +504,6 @@ void clif_party_xy(struct map_session_data *sd);
void clif_party_xy_single(int fd, struct map_session_data *sd);
void clif_party_hp(struct map_session_data *sd);
void clif_hpmeter_single(int fd, int id, unsigned int hp, unsigned int maxhp);
-int clif_hpmeter(struct map_session_data *sd);
-int clif_hpmeter_sub(struct block_list *bl, va_list ap);
// guild
void clif_guild_created(struct map_session_data *sd,int flag);
diff --git a/src/map/intif.c b/src/map/intif.c
index 51002f027..f074b032b 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -237,22 +237,22 @@ int intif_wis_replay(int id, int flag)
}
// The transmission of GM only Wisp/Page from server to inter-server
-int intif_wis_message_to_gm(char *Wisp_name, int min_gm_level, char *mes)
+int intif_wis_message_to_gm(char *wisp_name, int permission, char *mes)
{
int mes_len;
if (CheckForCharServer())
return 0;
mes_len = strlen(mes) + 1; // + null
- WFIFOHEAD(inter_fd, mes_len + 30);
+ WFIFOHEAD(inter_fd, mes_len + 32);
WFIFOW(inter_fd,0) = 0x3003;
- WFIFOW(inter_fd,2) = mes_len + 30;
- memcpy(WFIFOP(inter_fd,4), Wisp_name, NAME_LENGTH);
- WFIFOW(inter_fd,4+NAME_LENGTH) = (short)min_gm_level;
- memcpy(WFIFOP(inter_fd,6+NAME_LENGTH), mes, mes_len);
+ WFIFOW(inter_fd,2) = mes_len + 32;
+ memcpy(WFIFOP(inter_fd,4), wisp_name, NAME_LENGTH);
+ WFIFOL(inter_fd,4+NAME_LENGTH) = permission;
+ memcpy(WFIFOP(inter_fd,8+NAME_LENGTH), mes, mes_len);
WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
if (battle_config.etc_log)
- ShowNotice("intif_wis_message_to_gm: from: '%s', min level: %d, message: '%s'.\n", Wisp_name, min_gm_level, mes);
+ ShowNotice("intif_wis_message_to_gm: from: '%s', required permission: %d, message: '%s'.\n", wisp_name, permission, mes);
return 0;
}
@@ -860,11 +860,13 @@ int intif_parse_WisEnd(int fd)
static int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va)
{
- int min_gm_level = va_arg(va, int);
+ int permission = va_arg(va, int);
char *wisp_name;
char *message;
int len;
- if (pc_isGM(sd) < min_gm_level) return 0;
+
+ if (!pc_has_permission(sd, permission))
+ return 0;
wisp_name = va_arg(va, char*);
message = va_arg(va, char*);
len = va_arg(va, int);
@@ -873,22 +875,22 @@ static int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va)
}
// Received wisp message from map-server via char-server for ALL gm
-// 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B
+// 0x3003/0x3803 <packet_len>.w <wispname>.24B <permission>.l <message>.?B
int mapif_parse_WisToGM(int fd)
{
- int min_gm_level, mes_len;
+ int permission, mes_len;
char Wisp_name[NAME_LENGTH];
char mbuf[255];
char *message;
- mes_len = RFIFOW(fd,2) - 30;
+ mes_len = RFIFOW(fd,2) - 32;
message = (char *) (mes_len >= 255 ? (char *) aMallocA(mes_len) : mbuf);
- min_gm_level = (int)RFIFOW(fd,28);
+ permission = RFIFOL(fd,28);
safestrncpy(Wisp_name, (char*)RFIFOP(fd,4), NAME_LENGTH);
- safestrncpy(message, (char*)RFIFOP(fd,30), mes_len);
- // information is sended to all online GM
- map_foreachpc(mapif_parse_WisToGM_sub, min_gm_level, Wisp_name, message, mes_len);
+ safestrncpy(message, (char*)RFIFOP(fd,32), mes_len);
+ // information is sent to all online GM
+ map_foreachpc(mapif_parse_WisToGM_sub, permission, Wisp_name, message, mes_len);
if (message != mbuf)
aFree(message);
diff --git a/src/map/intif.h b/src/map/intif.h
index 88e1f1ce7..b1315f40c 100644
--- a/src/map/intif.h
+++ b/src/map/intif.h
@@ -20,7 +20,7 @@ int intif_broadcast(const char* mes, int len, int type);
int intif_broadcast2(const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY);
int intif_wis_message(struct map_session_data *sd,char *nick,char *mes,int mes_len);
-int intif_wis_message_to_gm(char *Wisp_name, int min_gm_level, char *mes);
+int intif_wis_message_to_gm(char *Wisp_name, int permission, char *mes);
int intif_saveregistry(struct map_session_data *sd, int type);
int intif_request_registry(struct map_session_data *sd, int flag);
diff --git a/src/map/log.c b/src/map/log.c
index 7823b5e02..4d4fa166a 100644
--- a/src/map/log.c
+++ b/src/map/log.c
@@ -282,12 +282,13 @@ void log_mvpdrop(struct map_session_data* sd, int monster_id, int* log_mvp)
}
-/// logs used GM commands
-void log_atcommand(struct map_session_data* sd, int cmdlvl, const char* message)
+/// logs used atcommands
+void log_atcommand(struct map_session_data* sd, const char* message)
{
nullpo_retv(sd);
- if( cmdlvl < log_config.gm )
+ if( !log_config.commands ||
+ !pc_should_log_commands(sd) )
return;
if( log_config.sql_logs )
@@ -460,8 +461,8 @@ int log_config_read(const char* cfgName)
log_config.filter = config_switch(w2);
else if( strcmpi(w1, "log_zeny") == 0 )
log_config.zeny = config_switch(w2);
- else if( strcmpi(w1, "log_gm") == 0 )
- log_config.gm = config_switch(w2);
+ else if( strcmpi(w1, "log_commands") == 0 )
+ log_config.commands = config_switch(w2);
else if( strcmpi(w1, "log_npc") == 0 )
log_config.npc = config_switch(w2);
else if( strcmpi(w1, "log_chat") == 0 )
@@ -508,9 +509,9 @@ int log_config_read(const char* cfgName)
{
ShowInfo("Logging chat to %s '%s'.\n", target, log_config.log_chat);
}
- if( log_config.gm )
+ if( log_config.commands )
{
- ShowInfo("Logging gm commands to %s '%s'.\n", target, log_config.log_gm);
+ ShowInfo("Logging commands to %s '%s'.\n", target, log_config.log_gm);
}
if( log_config.mvpdrop )
{
diff --git a/src/map/log.h b/src/map/log.h
index 5324bb599..ac85b7ccb 100644
--- a/src/map/log.h
+++ b/src/map/log.h
@@ -59,7 +59,7 @@ void log_zeny(struct map_session_data* sd, e_log_pick_type type, struct map_sess
void log_npc(struct map_session_data* sd, const char *message);
void log_chat(e_log_chat_type type, int type_id, int src_charid, int src_accid, const char* map, int x, int y, const char* dst_charname, const char* message);
-void log_atcommand(struct map_session_data* sd, int cmdlvl, const char* message);
+void log_atcommand(struct map_session_data* sd, const char* message);
/// old, but useful logs
void log_branch(struct map_session_data* sd);
@@ -74,7 +74,7 @@ extern struct Log_Config
bool sql_logs;
bool log_chat_woe_disable;
int rare_items_log,refine_items_log,price_items_log,amount_items_log; //for filter
- int branch, mvpdrop, zeny, gm, npc, chat;
+ int branch, mvpdrop, zeny, commands, npc, chat;
char log_branch[64], log_pick[64], log_zeny[64], log_mvpdrop[64], log_gm[64], log_npc[64], log_chat[64];
}
log_config;
diff --git a/src/map/mail.c b/src/map/mail.c
index 7c1b9be21..b839c3d1f 100644
--- a/src/map/mail.c
+++ b/src/map/mail.c
@@ -63,7 +63,7 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount)
{
if( idx == 0 )
{ // Zeny Transfer
- if( amount < 0 || !pc_can_give_items(pc_isGM(sd)) )
+ if( amount < 0 || !pc_can_give_items(sd) )
return 1;
if( amount > sd->status.zeny )
@@ -82,8 +82,8 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount)
return 1;
if( amount < 0 || amount > sd->status.inventory[idx].amount )
return 1;
- if( !pc_can_give_items(pc_isGM(sd)) || sd->status.inventory[idx].expire_time ||
- !itemdb_canmail(&sd->status.inventory[idx],pc_isGM(sd)) )
+ if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time ||
+ !itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd)) )
return 1;
sd->mail.index = idx;
@@ -184,7 +184,7 @@ void mail_deliveryfail(struct map_session_data *sd, struct mail_message *msg)
// This function only check if the mail operations are valid
bool mail_invalid_operation(struct map_session_data *sd)
{
- if( !map[sd->bl.m].flag.town && pc_isGM(sd) < get_atcommand_level("mail") )
+ if( !map[sd->bl.m].flag.town && !pc_can_use_command(sd, "mail", COMMAND_ATCOMMAND) )
{
ShowWarning("clif_parse_Mail: char '%s' trying to do invalid mail operations.\n", sd->status.name);
return true;
diff --git a/src/map/party.c b/src/map/party.c
index 2c9b45a11..8f8a0cd8a 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -344,12 +344,8 @@ int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
return 0;
}
- if ( (pc_isGM(sd) >= battle_config.lowest_gm_level && pc_isGM(tsd) < battle_config.lowest_gm_level && !battle_config.gm_can_party && pc_isGM(sd) < battle_config.gm_cant_party_min_lv)
- || ( pc_isGM(sd) < battle_config.lowest_gm_level && pc_isGM(tsd) >= battle_config.lowest_gm_level && !battle_config.gm_can_party && pc_isGM(tsd) < battle_config.gm_cant_party_min_lv) )
- {
- //GMs can't invite non GMs to the party if not above the invite trust level
- //Likewise, as long as gm_can_party is off, players can't invite GMs.
- clif_displaymessage(sd->fd, msg_txt(81));
+ if (!pc_has_permission(sd, PC_PERM_PARTY) || !pc_has_permission(tsd, PC_PERM_PARTY)) {
+ clif_displaymessage(sd->fd, msg_txt(81)); // "Your GM level doesn't authorize you to preform this action on the specified player."
return 0;
}
diff --git a/src/map/pc.c b/src/map/pc.c
index 22f165374..94d505c15 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -37,6 +37,7 @@
#include "skill.h"
#include "status.h" // struct status_data
#include "pc.h"
+#include "pc_groups.h"
#include "quest.h"
#include <stdio.h>
@@ -81,9 +82,14 @@ int pc_class2idx(int class_) {
return class_;
}
-int pc_isGM(struct map_session_data* sd)
+int inline pc_get_group_id(struct map_session_data *sd)
{
- return sd->gmlevel;
+ return sd->group_id;
+}
+
+int inline pc_get_group_level(struct map_session_data *sd)
+{
+ return pc_group_id2level(pc_get_group_id(sd));
}
static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr_t data)
@@ -478,13 +484,12 @@ void pc_inventory_rental_add(struct map_session_data *sd, int seconds)
sd->rental_timer = add_timer(gettick() + min(tick,3600000), pc_inventory_rental_end, sd->bl.id, 0);
}
-/*==========================================
- Determines if the GM can give / drop / trade / vend items
- Args: GM Level (current player GM level)
- *------------------------------------------*/
-bool pc_can_give_items(int level)
+/**
+ * Determines if player can give / drop / trade / vend items
+ */
+bool pc_can_give_items(struct map_session_data *sd)
{
- return( level < battle_config.gm_cant_drop_min_lv || level > battle_config.gm_cant_drop_max_lv );
+ return pc_has_permission(sd, PC_PERM_TRADE);
}
/*==========================================
@@ -815,7 +820,7 @@ int pc_isequip(struct map_session_data *sd,int n)
item = sd->inventory_data[n];
- if( battle_config.gm_allequip>0 && pc_isGM(sd)>=battle_config.gm_allequip )
+ if(pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT))
return 1;
if(item == NULL)
@@ -885,14 +890,14 @@ int pc_isequip(struct map_session_data *sd,int n)
* session idɖ薳
* charI瑗ĂXe?^Xݒ
*------------------------------------------*/
-bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int gmlevel, struct mmo_charstatus *st, bool changing_mapservers)
+bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers)
{
int i;
unsigned long tick = gettick();
uint32 ip = session[sd->fd]->client_addr;
sd->login_id2 = login_id2;
- sd->gmlevel = gmlevel;
+ sd->group_id = group_id;
memcpy(&sd->status, st, sizeof(*st));
if (st->sex != sd->status.sex) {
@@ -975,7 +980,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
pc_setequipindex(sd);
status_change_init(&sd->bl);
- if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && (pc_isGM(sd) >= get_atcommand_level("hide")))
+ if (pc_can_use_command(sd, "hide", COMMAND_ATCOMMAND))
sd->status.option &= (OPTION_MASK | OPTION_INVISIBLE);
else
sd->status.option &= OPTION_MASK;
@@ -1015,20 +1020,12 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
sd->die_counter=-1;
//display login notice
- if( sd->gmlevel >= battle_config.lowest_gm_level )
- ShowInfo("GM '"CL_WHITE"%s"CL_RESET"' logged in."
- " (AID/CID: '"CL_WHITE"%d/%d"CL_RESET"',"
- " Packet Ver: '"CL_WHITE"%d"CL_RESET"', IP: '"CL_WHITE"%d.%d.%d.%d"CL_RESET"',"
- " GM Level '"CL_WHITE"%d"CL_RESET"').\n",
- sd->status.name, sd->status.account_id, sd->status.char_id,
- sd->packet_ver, CONVIP(ip), sd->gmlevel);
- else
- ShowInfo("'"CL_WHITE"%s"CL_RESET"' logged in."
- " (AID/CID: '"CL_WHITE"%d/%d"CL_RESET"',"
- " Packet Ver: '"CL_WHITE"%d"CL_RESET"', IP: '"CL_WHITE"%d.%d.%d.%d"CL_RESET"').\n",
- sd->status.name, sd->status.account_id, sd->status.char_id,
- sd->packet_ver, CONVIP(ip));
-
+ ShowInfo("'"CL_WHITE"%s"CL_RESET"' logged in."
+ " (AID/CID: '"CL_WHITE"%d/%d"CL_RESET"',"
+ " Packet Ver: '"CL_WHITE"%d"CL_RESET"', IP: '"CL_WHITE"%d.%d.%d.%d"CL_RESET"',"
+ " Group '"CL_WHITE"%d"CL_RESET"').\n",
+ sd->status.name, sd->status.account_id, sd->status.char_id,
+ sd->packet_ver, CONVIP(ip), sd->group_id);
// Send friends list
clif_friendslist_send(sd);
@@ -1280,7 +1277,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
}
}
- if( battle_config.gm_allskill > 0 && pc_isGM(sd) >= battle_config.gm_allskill ) {
+ if( pc_has_permission(sd, PC_PERM_ALL_SKILL) ) {
for( i = 0; i < MAX_SKILL; i++ ) {
switch(i) {
/**
@@ -4004,7 +4001,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun
return 1;
data = itemdb_search(item_data->nameid);
- if( !itemdb_cancartstore(item_data, pc_isGM(sd)) )
+ if( !itemdb_cancartstore(item_data, pc_get_group_level(sd)) )
{ // Check item trade restrictions [Skotlex]
clif_displaymessage (sd->fd, msg_txt(264));
return 1;
@@ -4451,45 +4448,6 @@ int pc_randomwarp(struct map_session_data *sd, clr_type type)
return 0;
}
-
-/// Warps one player to another.
-/// @param sd player to warp.
-/// @param pl_sd player to warp to.
-int pc_warpto(struct map_session_data* sd, struct map_session_data* pl_sd)
-{
- if( map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
- {
- return -2;
- }
-
- if( map[pl_sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
- {
- return -3;
- }
-
- return pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
-}
-
-
-/// Recalls one player to another.
-/// @param sd player to warp to.
-/// @param pl_sd player to warp.
-int pc_recall(struct map_session_data* sd, struct map_session_data* pl_sd)
-{
- if( map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
- {
- return -2;
- }
-
- if( map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
- {
- return -3;
- }
-
- return pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
-}
-
-
/*==========================================
* Records a memo point at sd's current position
* pos - entry to replace, (-1: shift oldest entry out)
@@ -4501,7 +4459,7 @@ int pc_memo(struct map_session_data* sd, int pos)
nullpo_ret(sd);
// check mapflags
- if( sd->bl.m >= 0 && (map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto) && battle_config.any_warp_GM_min_level > pc_isGM(sd) ) {
+ if( sd->bl.m >= 0 && (map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) {
clif_skill_teleportmessage(sd, 1); // "Saved point cannot be memorized."
return 0;
}
@@ -5586,7 +5544,7 @@ int pc_allskillup(struct map_session_data *sd)
}
//pc_calc_skilltree takes care of setting the ID to valid skills. [Skotlex]
- if (battle_config.gm_allskill > 0 && pc_isGM(sd) >= battle_config.gm_allskill)
+ if (pc_has_permission(sd, PC_PERM_ALL_SKILL))
{ //Get ALL skills except npc/guild ones. [Skotlex]
//and except SG_DEVIL [Komurka] and MO_TRIPLEATTACK and RG_SNATCHER [ultramage]
for(i=0;i<MAX_SKILL;i++){
@@ -5761,6 +5719,13 @@ int pc_resetstate(struct map_session_data* sd)
clif_updatestatus(sd,SP_ULUK); // End Addition
clif_updatestatus(sd,SP_STATUSPOINT);
+
+ if( sd->mission_mobid ) { //bugreport:2200
+ sd->mission_mobid = 0;
+ sd->mission_count = 0;
+ pc_setglobalreg(sd,"TK_MISSION_ID", 0);
+ }
+
status_calc_pc(sd,0);
return 1;
@@ -7026,14 +6991,13 @@ int pc_setriding(TBL_PC* sd, int flag)
/*==========================================
* ACehbv•s”
*------------------------------------------*/
-int pc_candrop(struct map_session_data *sd,struct item *item)
+int pc_candrop(struct map_session_data *sd, struct item *item)
{
- int level = pc_isGM(sd);
if( item && item->expire_time )
return 0;
- if( !pc_can_give_items(level) ) //check if this GM level can drop items
+ if( !pc_can_give_items(sd) ) //check if this GM level can drop items
return 0;
- return (itemdb_isdropable(item, level));
+ return (itemdb_isdropable(item, pc_get_group_level(sd)));
}
/*==========================================
@@ -8255,6 +8219,37 @@ bool pc_isautolooting(struct map_session_data *sd, int nameid)
return (i != AUTOLOOTITEM_SIZE);
}
+/**
+ * Checks if player can use @/#command
+ * @param sd Player map session data
+ * @param command Command name without @/# and params
+ * @param type is it atcommand or charcommand
+ */
+bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type)
+{
+ return pc_group_can_use_command(pc_get_group_id(sd), command, type);
+}
+
+/**
+ * Checks if player has a permission
+ * @param sd Player map session data
+ * @param permission permission to check
+ */
+bool pc_has_permission(struct map_session_data *sd, int permission)
+{
+ return pc_group_has_permission(pc_get_group_id(sd), permission);
+}
+
+/**
+ * Checks if commands used by a player should be logged
+ * according to their group setting.
+ * @param sd Player map session data
+ */
+bool pc_should_log_commands(struct map_session_data *sd)
+{
+ return pc_group_should_log_commands(pc_get_group_id(sd));
+}
+
int pc_split_str(char *str,char **val,int num)
{
int i;
@@ -8628,6 +8623,7 @@ int pc_read_motd(void)
*------------------------------------------*/
void do_final_pc(void)
{
+ do_final_pc_groups();
return;
}
@@ -8665,5 +8661,7 @@ int do_init_pc(void)
}
}
+ do_init_pc_groups();
+
return 0;
}
diff --git a/src/map/pc.h b/src/map/pc.h
index 34c05d7b8..47d9edead 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -6,6 +6,7 @@
#include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus
#include "../common/timer.h" // INVALID_TIMER
+#include "atcommand.h" // AtCommandType
#include "battle.h" // battle_config
#include "buyingstore.h" // struct s_buyingstore
#include "itemdb.h" // MAX_ITEMGROUP
@@ -159,7 +160,7 @@ struct map_session_data {
} special_state;
int login_id1, login_id2;
unsigned short class_; //This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex]
- int gmlevel;
+ int group_id;
int packet_ver; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 ... 18
struct mmo_charstatus status;
@@ -568,6 +569,27 @@ enum equip_index {
EQI_MAX
};
+enum e_pc_permission {
+ PC_PERM_NONE = 0,
+ PC_PERM_TRADE = 0x00001,
+ PC_PERM_PARTY = 0x00002,
+ PC_PERM_ALL_SKILL = 0x00004,
+ PC_PERM_USE_ALL_EQUIPMENT = 0x00008,
+ PC_PERM_SKILL_UNCONDITIONAL = 0x00010,
+ PC_PERM_JOIN_ALL_CHAT = 0x00020,
+ PC_PERM_NO_CHAT_KICK = 0x00040,
+ PC_PERM_HIDE_SESSION = 0x00080,
+ PC_PERM_WHO_DISPLAY_AID = 0x00100,
+ PC_PERM_RECEIVE_HACK_INFO = 0x00200,
+ PC_PERM_WARP_ANYWHERE = 0x00400,
+ PC_PERM_VIEW_HPMETER = 0x00800,
+ PC_PERM_VIEW_EQUIPMENT = 0x01000,
+ PC_PERM_USE_CHECK = 0x02000,
+ PC_PERM_USE_CHANGEMAPTYPE = 0x04000,
+ PC_PERM_USE_ALL_COMMANDS = 0x08000,
+ PC_PERM_RECEIVE_REQUESTS = 0x10000,
+};
+
#define pc_setdead(sd) ( (sd)->state.dead_sit = (sd)->vd.dead_sit = 1 )
#define pc_setsit(sd) ( (sd)->state.dead_sit = (sd)->vd.dead_sit = 2 )
#define pc_isdead(sd) ( (sd)->state.dead_sit == 1 )
@@ -608,15 +630,20 @@ enum equip_index {
)
int pc_class2idx(int class_);
-int pc_isGM(struct map_session_data *sd);
+int pc_get_group_level(struct map_session_data *sd);
+int pc_get_group_id(struct map_session_data *sd);
int pc_getrefinebonus(int lv,int type);
-bool pc_can_give_items(int level);
+bool pc_can_give_items(struct map_session_data *sd);
+
+bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type);
+bool pc_has_permission(struct map_session_data *sd, int permission);
+bool pc_should_log_commands(struct map_session_data *sd);
int pc_setrestartvalue(struct map_session_data *sd,int type);
int pc_makesavestatus(struct map_session_data *);
void pc_respawn(struct map_session_data* sd, clr_type clrtype);
int pc_setnewpc(struct map_session_data*,int,int,int,unsigned int,int,int);
-bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int gmlevel, struct mmo_charstatus *st, bool changing_mapservers);
+bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers);
void pc_authfail(struct map_session_data *);
int pc_reg_received(struct map_session_data *sd);
@@ -638,8 +665,6 @@ int pc_clean_skilltree(struct map_session_data *sd);
int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype);
int pc_setsavepoint(struct map_session_data*,short,int,int);
int pc_randomwarp(struct map_session_data *sd,clr_type type);
-int pc_warpto(struct map_session_data* sd, struct map_session_data* pl_sd);
-int pc_recall(struct map_session_data* sd, struct map_session_data* pl_sd);
int pc_memo(struct map_session_data* sd, int pos);
int pc_checkadditem(struct map_session_data*,int,int);
diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c
new file mode 100644
index 000000000..3ceb905ba
--- /dev/null
+++ b/src/map/pc_groups.c
@@ -0,0 +1,459 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include "../common/conf.h"
+#include "../common/db.h"
+#include "../common/malloc.h"
+#include "../common/nullpo.h"
+#include "../common/showmsg.h"
+#include "../common/strlib.h" // strcmp
+
+#include "atcommand.h" // AtCommandType
+#include "pc_groups.h"
+#include "pc.h" // e_pc_permission
+
+
+typedef struct GroupSettings GroupSettings;
+
+// Cached config settings/pointers for quick lookup
+struct GroupSettings {
+ unsigned int id; // groups.[].id
+ int level; // groups.[].level
+ const char *name; // groups.[].name
+ config_setting_t *commands; // groups.[].commands
+ unsigned int e_permissions; // packed groups.[].permissions
+ bool log_commands; // groups.[].log_commands
+ /// Following are used only during config reading
+ config_setting_t *permissions; // groups.[].permissions
+ config_setting_t *inherit; // groups.[].inherit
+ bool inheritance_done; // have all inheritance rules been evaluated?
+ config_setting_t *root; // groups.[]
+};
+
+
+static config_t pc_group_config;
+static DBMap* pc_group_db; // id -> GroupSettings
+static DBMap* pc_groupname_db; // name -> GroupSettings
+
+static const struct {
+ const char *name;
+ int permission;
+} permission_name[] = {
+ { "can_trade", PC_PERM_TRADE },
+ { "can_party", PC_PERM_PARTY },
+ { "all_skill", PC_PERM_ALL_SKILL },
+ { "all_equipment", PC_PERM_USE_ALL_EQUIPMENT },
+ { "skill_unconditional", PC_PERM_SKILL_UNCONDITIONAL },
+ { "join_chat", PC_PERM_JOIN_ALL_CHAT },
+ { "kick_chat", PC_PERM_NO_CHAT_KICK },
+ { "hide_session", PC_PERM_HIDE_SESSION },
+ { "who_display_aid", PC_PERM_WHO_DISPLAY_AID },
+ { "hack_info", PC_PERM_RECEIVE_HACK_INFO },
+ { "any_warp", PC_PERM_WARP_ANYWHERE },
+ { "view_hpmeter", PC_PERM_VIEW_HPMETER },
+ { "view_equipment", PC_PERM_VIEW_EQUIPMENT },
+ { "use_check", PC_PERM_USE_CHECK },
+ { "use_changemaptype", PC_PERM_USE_CHANGEMAPTYPE },
+ { "all_commands", PC_PERM_USE_ALL_COMMANDS },
+ { "receive_requests", PC_PERM_RECEIVE_REQUESTS },
+};
+
+/**
+ * @retval NULL if not found
+ * @private
+ */
+static inline GroupSettings* id2group(int group_id)
+{
+ return (GroupSettings*)idb_get(pc_group_db, group_id);
+}
+
+/**
+ * @retval NULL if not found
+ * @private
+ */
+static inline GroupSettings* name2group(const char* group_name)
+{
+ return (GroupSettings*)strdb_get(pc_groupname_db, group_name);
+}
+
+/**
+ * Loads group configuration from config file into memory.
+ * @private
+ */
+static void read_config(void)
+{
+ config_setting_t *groups = NULL;
+ const char *config_filename = "conf/groups.conf"; // FIXME hardcoded name
+ int group_count = 0;
+
+ if (conf_read_file(&pc_group_config, config_filename))
+ return;
+
+ groups = config_lookup(&pc_group_config, "groups");
+
+ if (groups != NULL) {
+ GroupSettings *group_settings = NULL;
+ DBIterator *iter = NULL;
+ int i, loop = 0;
+
+ group_count = config_setting_length(groups);
+ for (i = 0; i < group_count; ++i) {
+ int id = 0, level = 0;
+ const char *groupname = NULL;
+ int log_commands = 0;
+ config_setting_t *group = config_setting_get_elem(groups, i);
+
+ if (!config_setting_lookup_int(group, "id", &id)) {
+ ShowConfigWarning(group, "pc_groups:read_config: \"groups\" list member #%d has undefined id, removing...", i);
+ config_setting_remove_elem(groups, i);
+ --i;
+ --group_count;
+ continue;
+ }
+
+ if (id2group(id) != NULL) {
+ ShowConfigWarning(group, "pc_groups:read_config: duplicate group id %d, removing...", i);
+ config_setting_remove_elem(groups, i);
+ --i;
+ --group_count;
+ continue;
+ }
+
+ config_setting_lookup_int(group, "level", &level);
+ config_setting_lookup_int(group, "log_commands", &log_commands);
+
+ if (!config_setting_lookup_string(group, "name", &groupname)) {
+ char temp[20];
+ config_setting_t *name = NULL;
+ snprintf(temp, sizeof(temp), "Group %d", id);
+ if ((name = config_setting_add(group, "name", CONFIG_TYPE_STRING)) == NULL ||
+ !config_setting_set_string(name, temp)) {
+ ShowError("pc_groups:read_config: failed to set missing group name, id=%d, skipping... (%s:%d)\n",
+ id, config_setting_source_file(group), config_setting_source_line(group));
+ continue;
+ }
+ config_setting_lookup_string(group, "name", &groupname); // Retrieve the pointer
+ }
+
+ if (name2group(groupname) != NULL) {
+ ShowConfigWarning(group, "pc_groups:read_config: duplicate group name %s, removing...", groupname);
+ config_setting_remove_elem(groups, i);
+ --i;
+ --group_count;
+ continue;
+ }
+
+ CREATE(group_settings, GroupSettings, 1);
+ group_settings->id = id;
+ group_settings->level = level;
+ group_settings->name = groupname;
+ group_settings->log_commands = (bool)log_commands;
+ group_settings->inherit = config_setting_get_member(group, "inherit");
+ group_settings->commands = config_setting_get_member(group, "commands");
+ group_settings->permissions = config_setting_get_member(group, "permissions");
+ group_settings->inheritance_done = false;
+ group_settings->root = group;
+
+ strdb_put(pc_groupname_db, groupname, group_settings);
+ idb_put(pc_group_db, id, group_settings);
+
+ }
+ group_count = config_setting_length(groups); // Save number of groups
+
+ // Check if all commands and permissions exist
+ iter = pc_group_db->iterator(pc_group_db);
+ for (group_settings = (GroupSettings*)iter->first(iter, NULL);
+ iter->exists(iter);
+ group_settings = (GroupSettings*)iter->next(iter, NULL)) {
+ config_setting_t *commands = group_settings->commands, *permissions = group_settings->permissions;
+ int count = 0, i;
+
+ // Make sure there is "commands" group
+ if (commands == NULL)
+ commands = group_settings->commands = config_setting_add(group_settings->root, "commands", CONFIG_TYPE_GROUP);
+ count = config_setting_length(commands);
+
+ for (i = 0; i < count; ++i) {
+ config_setting_t *command = config_setting_get_elem(commands, i);
+ const char *name = config_setting_name(command);
+ if (!atcommand_exists(name)) {
+ ShowConfigWarning(command, "pc_groups:read_config: non-existent command name '%s', removing...", name);
+ config_setting_remove(commands, name);
+ --i;
+ --count;
+ }
+ }
+
+ // Make sure there is "permissions" group
+ if (permissions == NULL)
+ permissions = group_settings->permissions = config_setting_add(group_settings->root, "permissions", CONFIG_TYPE_GROUP);
+ count = config_setting_length(permissions);
+
+ for(i = 0; i < count; ++i) {
+ config_setting_t *permission = config_setting_get_elem(permissions, i);
+ const char *name = config_setting_name(permission);
+ int j;
+
+ ARR_FIND(0, ARRAYLENGTH(permission_name), j, strcmp(permission_name[j].name, name) == 0);
+ if (j == ARRAYLENGTH(permission_name)) {
+ ShowConfigWarning(permission, "pc_groups:read_config: non-existent permission name '%s', removing...", name);
+ config_setting_remove(permissions, name);
+ --i;
+ --count;
+ }
+ }
+ }
+ iter->destroy(iter);
+
+ // Apply inheritance
+ i = 0; // counter for processed groups
+ while (i < group_count) {
+ iter = pc_group_db->iterator(pc_group_db);
+ for (group_settings = (GroupSettings*)iter->first(iter, NULL);
+ iter->exists(iter);
+ group_settings = (GroupSettings*)iter->next(iter, NULL)) {
+ config_setting_t *inherit = NULL,
+ *commands = group_settings->commands,
+ *permissions = group_settings->permissions;
+ int j, inherit_count = 0, done = 0;
+
+ if (group_settings->inheritance_done) // group already processed
+ continue;
+
+ if ((inherit = group_settings->inherit) == NULL ||
+ (inherit_count = config_setting_length(inherit)) <= 0) { // this group does not inherit from others
+ ++i;
+ group_settings->inheritance_done = true;
+ continue;
+ }
+
+ for (j = 0; j < inherit_count; ++j) {
+ GroupSettings *inherited_group = NULL;
+ const char *groupname = config_setting_get_string_elem(inherit, j);
+
+ if (groupname == NULL) {
+ ShowConfigWarning(inherit, "pc_groups:read_config: \"inherit\" array member #%d is not a name, removing...", j);
+ config_setting_remove_elem(inherit,j);
+ continue;
+ }
+ if ((inherited_group = name2group(groupname)) == NULL) {
+ ShowConfigWarning(inherit, "pc_groups:read_config: non-existent group name \"%s\", removing...", groupname);
+ config_setting_remove_elem(inherit,j);
+ continue;
+ }
+ if (!inherited_group->inheritance_done)
+ continue; // we need to do that group first
+
+ // Copy settings (commands/permissions) that are not defined yet
+ if (inherited_group->commands != NULL) {
+ int i = 0, commands_count = config_setting_length(inherited_group->commands);
+ for (i = 0; i < commands_count; ++i)
+ config_setting_copy(commands, config_setting_get_elem(inherited_group->commands, i));
+ }
+
+ if (inherited_group->permissions != NULL) {
+ int i = 0, permissions_count = config_setting_length(inherited_group->permissions);
+ for (i = 0; i < permissions_count; ++i)
+ config_setting_copy(permissions, config_setting_get_elem(inherited_group->permissions, i));
+ }
+
+ ++done; // copied commands and permissions from one of inherited groups
+ }
+
+ if (done == inherit_count) { // copied commands from all of inherited groups
+ ++i;
+ group_settings->inheritance_done = true; // we're done with this group
+ }
+ }
+ iter->destroy(iter);
+
+ if (++loop > group_count) {
+ ShowWarning("pc_groups:read_config: Could not process inheritance rules, check your config '%s' for cycles...\n",
+ config_filename);
+ break;
+ }
+ } // while(i < group_count)
+
+ // Pack permissions into GroupSettings.e_permissions for faster checking
+ iter = db_iterator(pc_group_db);
+ for (group_settings = (GroupSettings*)dbi_first(iter);
+ dbi_exists(iter);
+ group_settings = (GroupSettings*)dbi_next(iter)) {
+ config_setting_t *permissions = group_settings->permissions;
+ int i, count = config_setting_length(permissions);
+
+ for (i = 0; i < count; ++i) {
+ config_setting_t *perm = config_setting_get_elem(permissions, i);
+ const char *name = config_setting_name(perm);
+ int j;
+
+ ARR_FIND(0, ARRAYLENGTH(permission_name), j, strcmp(permission_name[j].name, name) == 0);
+ group_settings->e_permissions |= permission_name[j].permission;
+ }
+ }
+ iter->destroy(iter);
+ }
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' groups in '"CL_WHITE"%s"CL_RESET"'.\n", group_count, config_filename);
+}
+
+/**
+ * Removes group configuration from memory.
+ * @private
+ */
+static void destroy_config(void)
+{
+ config_destroy(&pc_group_config);
+}
+
+/**
+ * In group configuration file, setting for each command is either
+ * <commandname> : <bool> (only atcommand), or
+ * <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ])
+ * Maps AtCommandType enums to indexes of <commandname> value array,
+ * COMMAND_ATCOMMAND (1) being index 0, COMMAND_CHARCOMMAND (2) being index 1.
+ * @private
+ */
+static inline int AtCommandType2idx(AtCommandType type) { return (type-1); }
+
+/**
+ * Checks if player group can use @/#command
+ * @param group_id ID of the group
+ * @param command Command name without @/# and params
+ * @param type enum AtCommanndType { COMMAND_ATCOMMAND = 1, COMMAND_CHARCOMMAND = 2 }
+ */
+bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type)
+{
+ int result = 0;
+ config_setting_t *commands = NULL;
+ GroupSettings *group = NULL;
+
+ if (pc_group_has_permission(group_id, PC_PERM_USE_ALL_COMMANDS))
+ return true;
+
+ if ((group = id2group(group_id)) == NULL)
+ return false;
+
+ commands = group->commands;
+ if (commands != NULL) {
+ config_setting_t *cmd = NULL;
+
+ // <commandname> : <bool> (only atcommand)
+ if (type == COMMAND_ATCOMMAND && config_setting_lookup_bool(commands, command, &result))
+ return (bool)result;
+
+ // <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ])
+ if ((cmd = config_setting_get_member(commands, command)) != NULL &&
+ config_setting_is_aggregate(cmd) && config_setting_length(cmd) == 2)
+ return (bool)config_setting_get_bool_elem(cmd, AtCommandType2idx(type));
+ }
+ return false;
+}
+
+/**
+ * Checks if player group has a permission
+ * @param group_id ID of the group
+ * @param permission permission to check
+ */
+bool pc_group_has_permission(int group_id, int permission)
+{
+ GroupSettings *group = NULL;
+ if ((group = id2group(group_id)) == NULL)
+ return false;
+ return ((group->e_permissions&permission) != 0);
+}
+
+/**
+ * Checks commands used by player group should be logged
+ * @param group_id ID of the group
+ */
+bool pc_group_should_log_commands(int group_id)
+{
+ GroupSettings *group = NULL;
+ if ((group = id2group(group_id)) == NULL)
+ return false;
+ return group->log_commands;
+}
+
+/**
+ * Checks if player group with given ID exists.
+ * @param group_id group id
+ * @returns true if group exists, false otherwise
+ */
+bool pc_group_exists(int group_id)
+{
+ return idb_exists(pc_group_db, group_id);
+}
+
+/**
+ * Group ID -> group name lookup. Used only in @who atcommands.
+ * @param group_id group id
+ * @return group name
+ * @public
+ */
+const char* pc_group_id2name(int group_id)
+{
+ GroupSettings *group = id2group(group_id);
+ if (group == NULL)
+ return "Non-existent group!";
+ return group->name;
+}
+
+/**
+ * Group ID -> group level lookup. A way to provide backward compatibility with GM level system.
+ * @param group id
+ * @return group level
+ * @public
+ */
+int pc_group_id2level(int group_id)
+{
+ GroupSettings *group = id2group(group_id);
+ if (group == NULL)
+ return 0;
+ return group->level;
+}
+
+/**
+ * Initialize PC Groups: allocate DBMaps and read config.
+ * @public
+ */
+void do_init_pc_groups(void)
+{
+ pc_group_db = idb_alloc(DB_OPT_BASE);
+ pc_groupname_db = stridb_alloc(DB_OPT_DUP_KEY, 0);
+ read_config();
+}
+
+/**
+ * DBApply helper function for do_final_pc_groups
+ * @private
+ */
+static int group_db_free(DBKey key, void *data, va_list args)
+{
+ aFree((GroupSettings*)data);
+ return 1;
+}
+
+/**
+ * Finalize PC Groups: free DBMaps and config.
+ * @public
+ */
+void do_final_pc_groups(void)
+{
+ if (pc_group_db != NULL)
+ pc_group_db->destroy(pc_group_db, group_db_free);
+ if (pc_groupname_db != NULL )
+ db_destroy(pc_groupname_db);
+ destroy_config();
+}
+
+/**
+ * Reload PC Groups
+ * Used in @reloadatcommand
+ * @public
+ */
+void pc_groups_reload(void)
+{
+ do_final_pc_groups();
+ do_init_pc_groups();
+} \ No newline at end of file
diff --git a/src/map/pc_groups.h b/src/map/pc_groups.h
new file mode 100644
index 000000000..1134bc01a
--- /dev/null
+++ b/src/map/pc_groups.h
@@ -0,0 +1,20 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _PC_GROUPS_H_
+#define _PC_GROUPS_H_
+
+#include "atcommand.h" // AtCommandType
+
+bool pc_group_exists(int group_id);
+bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type);
+bool pc_group_has_permission(int group_id, int permission);
+bool pc_group_should_log_commands(int group_id);
+const char* pc_group_id2name(int group_id);
+int pc_group_id2level(int group_id);
+
+void do_init_pc_groups(void);
+void do_final_pc_groups(void);
+void pc_groups_reload(void);
+
+#endif // _PC_GROUPS_H_ \ No newline at end of file
diff --git a/src/map/script.c b/src/map/script.c
index 0a92ae835..705eb041b 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -7345,7 +7345,7 @@ BUILDIN_FUNC(getgmlevel)
if( sd == NULL )
return 0;// no player attached, report source
- script_pushint(st, pc_isGM(sd));
+ script_pushint(st, pc_get_group_level(sd));
return 0;
}
@@ -8704,17 +8704,18 @@ BUILDIN_FUNC(getusers)
BUILDIN_FUNC(getusersname)
{
TBL_PC *sd, *pl_sd;
- int disp_num=1;
+ int disp_num=1, group_level = 0;
struct s_mapiterator* iter;
sd = script_rid2sd(st);
if (!sd) return 0;
+ group_level = pc_get_group_level(sd);
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
- if( battle_config.hide_GM_session && pc_isGM(pl_sd) )
- continue; // skip hidden GMs
+ if (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > group_level)
+ continue; // skip hidden sessions
if((disp_num++)%10==0)
clif_scriptnext(sd,st->oid);
@@ -11586,9 +11587,6 @@ BUILDIN_FUNC(nude)
/*==========================================
* gmcommand [MouseJstr]
- *
- * suggested on the forums...
- * splitted into atcommand & charcommand by [Skotlex]
*------------------------------------------*/
BUILDIN_FUNC(atcommand)
{
@@ -11616,51 +11614,12 @@ BUILDIN_FUNC(atcommand)
}
}
- // compatibility with previous implementation (deprecated!)
- if(cmd[0] != atcommand_symbol)
- {
- cmd += strlen(sd->status.name);
- while(*cmd != atcommand_symbol && *cmd != 0)
- cmd++;
- }
-
- is_atcommand(fd, sd, cmd, 0);
- return 0;
-}
-
-BUILDIN_FUNC(charcommand)
-{
- TBL_PC dummy_sd;
- TBL_PC* sd;
- int fd;
- const char* cmd;
-
- cmd = script_getstr(st,2);
-
- if (st->rid) {
- sd = script_rid2sd(st);
- fd = sd->fd;
- } else { //Use a dummy character.
- sd = &dummy_sd;
- fd = 0;
-
- memset(&dummy_sd, 0, sizeof(TBL_PC));
- if (st->oid)
- {
- struct block_list* bl = map_id2bl(st->oid);
- memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
- if (bl->type == BL_NPC)
- safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
- }
- }
-
- if (*cmd != charcommand_symbol) {
- ShowWarning("script: buildin_charcommand: No '#' symbol!\n");
+ if (!is_atcommand(fd, sd, cmd, 0)) {
+ ShowWarning("script: buildin_atcommand: failed to execute command '%s'\n", cmd);
script_reportsrc(st);
return 1;
}
-
- is_atcommand(fd, sd, cmd, 0);
+
return 0;
}
@@ -16170,7 +16129,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(nude,""), // nude command [Valaris]
BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT
BUILDIN_DEF(atcommand,"s"), // [MouseJstr]
- BUILDIN_DEF(charcommand,"s"), // [MouseJstr]
+ BUILDIN_DEF2(atcommand,"charcommand","s"), // [MouseJstr]
BUILDIN_DEF(movenpc,"sii?"), // [MouseJstr]
BUILDIN_DEF(message,"ss"), // [MouseJstr]
BUILDIN_DEF(npctalk,"s"), // [Valaris]
diff --git a/src/map/skill.c b/src/map/skill.c
index 2fef37baf..9bf915917 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -436,8 +436,8 @@ int skillnotok (int skillid, struct map_session_data *sd)
if (i == 0)
return 1; // invalid skill id
- if (battle_config.gm_skilluncond && pc_isGM(sd) >= battle_config.gm_skilluncond)
- return 0; // GMs can do any damn thing they want
+ if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL))
+ return 0; // can do any damn thing they want
if( skillid == AL_TELEPORT && sd->skillitem == skillid && sd->skillitemlv > 2 )
return 0; // Teleport lv 3 bypasses this check.[Inkfish]
@@ -5412,7 +5412,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case MC_VENDING:
if(sd)
{ //Prevent vending of GMs with unnecessary Level to trade/drop. [Skotlex]
- if ( !pc_can_give_items(pc_isGM(sd)) )
+ if ( !pc_can_give_items(sd) )
clif_skill_fail(sd,skillid,USESKILL_FAIL_LEVEL,0);
else {
sd->state.prevend = 1;
@@ -10256,8 +10256,7 @@ int skill_check_pc_partner (struct map_session_data *sd, short skill_id, short*
static int p_sd[2] = { 0, 0 };
int i;
- if (!battle_config.player_skill_partner_check ||
- (battle_config.gm_skilluncond && pc_isGM(sd) >= battle_config.gm_skilluncond))
+ if (!battle_config.player_skill_partner_check || pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL))
return 99; //As if there were infinite partners.
if (cast_flag)
@@ -10352,7 +10351,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
if (lv <= 0 || sd->chatID) return 0;
- if( battle_config.gm_skilluncond && pc_isGM(sd)>= battle_config.gm_skilluncond && sd->skillitem != skill )
+ if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill )
{ //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex]
sd->state.arrow_atk = skill_get_ammotype(skill)?1:0; //Need to do arrow state check.
sd->spiritball_old = sd->spiritball; //Need to do Spiritball check.
@@ -11028,7 +11027,7 @@ int skill_check_condition_castend(struct map_session_data* sd, short skill, shor
if( lv <= 0 || sd->chatID )
return 0;
- if( battle_config.gm_skilluncond && pc_isGM(sd) >= battle_config.gm_skilluncond && sd->skillitem != skill )
+ if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill )
{ //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex]
sd->state.arrow_atk = skill_get_ammotype(skill)?1:0; //Need to do arrow state check.
sd->spiritball_old = sd->spiritball; //Need to do Spiritball check.
diff --git a/src/map/storage.c b/src/map/storage.c
index 12d9a8107..4f6dfff0e 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -95,7 +95,7 @@ int storage_storageopen(struct map_session_data *sd)
if(sd->state.storage_flag)
return 1; //Already open?
- if( !pc_can_give_items(pc_isGM(sd)) )
+ if( !pc_can_give_items(sd) )
{ //check is this GM level is allowed to put items to storage
clif_displaymessage(sd->fd, msg_txt(246));
return 1;
@@ -138,7 +138,7 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
data = itemdb_search(item_data->nameid);
- if( !itemdb_canstore(item_data, pc_isGM(sd)) )
+ if( !itemdb_canstore(item_data, pc_get_group_level(sd)) )
{ //Check if item is storable. [Skotlex]
clif_displaymessage (sd->fd, msg_txt(264));
return 1;
@@ -357,7 +357,7 @@ int storage_guild_storageopen(struct map_session_data* sd)
if(sd->state.storage_flag)
return 1; //Can't open both storages at a time.
- if( !pc_can_give_items(pc_isGM(sd)) ) { //check is this GM level can open guild storage and store items [Lupus]
+ if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus]
clif_displaymessage(sd->fd, msg_txt(246));
return 1;
}
@@ -391,7 +391,7 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
data = itemdb_search(item_data->nameid);
- if( !itemdb_canguildstore(item_data, pc_isGM(sd)) || item_data->expire_time )
+ if( !itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time )
{ //Check if item is storable. [Skotlex]
clif_displaymessage (sd->fd, msg_txt(264));
return 1;
diff --git a/src/map/trade.c b/src/map/trade.c
index 3c398ab83..cfc4992e8 100644
--- a/src/map/trade.c
+++ b/src/map/trade.c
@@ -29,8 +29,6 @@
*------------------------------------------*/
void trade_traderequest(struct map_session_data *sd, struct map_session_data *target_sd)
{
- int level;
-
nullpo_retv(sd);
if (map[sd->bl.m].flag.notrade) {
@@ -61,18 +59,16 @@ void trade_traderequest(struct map_session_data *sd, struct map_session_data *ta
return;
}
- level = pc_isGM(sd);
- if ( !pc_can_give_items(level) || !pc_can_give_items(pc_isGM(target_sd)) ) //check if both GMs are allowed to trade
+ if (!pc_can_give_items(sd) || !pc_can_give_items(target_sd)) //check if both GMs are allowed to trade
{
clif_displaymessage(sd->fd, msg_txt(246));
clif_tradestart(sd, 2); // GM is not allowed to trade
return;
}
- //Fixed. Only real GMs can request trade from far away! [Lupus]
- if (level < battle_config.lowest_gm_level && (sd->bl.m != target_sd->bl.m ||
- !check_distance_bl(&sd->bl, &target_sd->bl, TRADE_DISTANCE)
- )) {
+ // Players can not request trade from far away, unless they are allowed to use @trade.
+ if (!pc_can_use_command(sd, "trade", COMMAND_ATCOMMAND) &&
+ (sd->bl.m != target_sd->bl.m || !check_distance_bl(&sd->bl, &target_sd->bl, TRADE_DISTANCE))) {
clif_tradestart(sd, 0); // too far
return ;
}
@@ -127,10 +123,10 @@ void trade_tradeack(struct map_session_data *sd, int type)
if (type != 3)
return; //If client didn't send accept, it's a broken packet?
- //Copied here as well since the original character could had warped.
- if (pc_isGM(tsd) < battle_config.lowest_gm_level && (sd->bl.m != tsd->bl.m ||
- !check_distance_bl(&sd->bl, &tsd->bl, TRADE_DISTANCE)
- )) {
+ // Players can not request trade from far away, unless they are allowed to use @trade.
+ // Check here as well since the original character could had warped.
+ if (!pc_can_use_command(sd, "trade", COMMAND_ATCOMMAND) &&
+ (sd->bl.m != tsd->bl.m || !check_distance_bl(&sd->bl, &tsd->bl, TRADE_DISTANCE))) {
clif_tradestart(sd, 0); // too far
sd->trade_partner=0;
tsd->trade_partner = 0;
@@ -196,9 +192,9 @@ int impossible_trade_check(struct map_session_data *sd)
if (inventory[index].amount < sd->deal.item[i].amount)
{ // if more than the player have -> hack
sprintf(message_to_gm, msg_txt(538), sd->status.name, sd->status.account_id); // Hack on trade: character '%s' (account: %d) try to trade more items that he has.
- intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
+ intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
sprintf(message_to_gm, msg_txt(539), inventory[index].amount, inventory[index].nameid, sd->deal.item[i].amount); // This player has %d of a kind of item (id: %d), and try to trade %d of them.
- intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
+ intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
// if we block people
if (battle_config.ban_hack_trade < 0) {
chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block
@@ -215,7 +211,7 @@ int impossible_trade_check(struct map_session_data *sd)
// message about the ban
strcpy(message_to_gm, msg_txt(508)); // This player hasn't been banned (Ban option is disabled).
- intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
+ intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
return 1;
}
inventory[index].amount -= sd->deal.item[i].amount; // remove item from inventory
@@ -345,8 +341,8 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
return;
item = &sd->status.inventory[index];
- src_lv = pc_isGM(sd);
- dst_lv = pc_isGM(target_sd);
+ src_lv = pc_get_group_level(sd);
+ dst_lv = pc_get_group_level(target_sd);
if( !itemdb_cantrade(item, src_lv, dst_lv) && //Can't trade
(pc_get_partner(sd) != target_sd || !itemdb_canpartnertrade(item, src_lv, dst_lv)) ) //Can't partner-trade
{
diff --git a/src/map/vending.c b/src/map/vending.c
index 0db4ee85b..6deba0e55 100644
--- a/src/map/vending.c
+++ b/src/map/vending.c
@@ -54,7 +54,7 @@ void vending_vendinglistreq(struct map_session_data* sd, int id)
if( !vsd->state.vending )
return; // not vending
- if ( !pc_can_give_items(pc_isGM(sd)) || !pc_can_give_items(pc_isGM(vsd)) ) //check if both GMs are allowed to trade
+ if (!pc_can_give_items(sd) || !pc_can_give_items(vsd)) //check if both GMs are allowed to trade
{ // GM is not allowed to trade
clif_displaymessage(sd->fd, msg_txt(246));
return;
@@ -281,7 +281,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, bool
|| !sd->status.cart[index].identify // unidentified item
|| sd->status.cart[index].attribute == 1 // broken item
|| sd->status.cart[index].expire_time // It should not be in the cart but just in case
- || !itemdb_cantrade(&sd->status.cart[index], pc_isGM(sd), pc_isGM(sd)) ) // untradeable item
+ || !itemdb_cantrade(&sd->status.cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // untradeable item
continue;
sd->vending[i].index = index;
diff --git a/src/tool/Makefile.in b/src/tool/Makefile.in
index a7f8afbf4..8d14d9ed2 100644
--- a/src/tool/Makefile.in
+++ b/src/tool/Makefile.in
@@ -6,6 +6,13 @@ COMMON_H = ../common/core.h ../common/mmo.h ../common/version.h \
../common/malloc.h ../common/showmsg.h ../common/strlib.h \
../common/utils.h ../common/cbasetypes.h ../common/des.h ../common/grfio.h
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+ ../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+ ../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+ ../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
MAPCACHE_OBJ = obj_all/mapcache.o
@SET_MAKE@
@@ -15,8 +22,8 @@ MAPCACHE_OBJ = obj_all/mapcache.o
all: mapcache
-mapcache: obj_all $(MAPCACHE_OBJ) $(COMMON_OBJ)
- @CC@ @LDFLAGS@ -o ../../mapcache@EXEEXT@ $(MAPCACHE_OBJ) $(COMMON_OBJ) @LIBS@
+mapcache: obj_all $(MAPCACHE_OBJ) $(COMMON_OBJ) $(LIBCONFIG_OBJ)
+ @CC@ @LDFLAGS@ $(LIBCONFIG_INCLUDE) -o ../../mapcache@EXEEXT@ $(MAPCACHE_OBJ) $(COMMON_OBJ) $(LIBCONFIG_OBJ) @LIBS@
clean:
rm -rf obj_all/*.o ../../mapcache@EXEEXT@
@@ -42,3 +49,6 @@ obj_all/%.o: %.c $(COMMON_H)
../common/obj_all/mini%.o:
@$(MAKE) -C ../common txt
+
+LIBCONFIG_OBJ:
+ @$(MAKE) -C ../../3rdparty/libconfig \ No newline at end of file
diff --git a/vcproj-10/char-server_sql.vcxproj b/vcproj-10/char-server_sql.vcxproj
index e7fd17017..afa7f85d3 100644
--- a/vcproj-10/char-server_sql.vcxproj
+++ b/vcproj-10/char-server_sql.vcxproj
@@ -51,8 +51,8 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
- <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessToFile>false</PreprocessToFile>
<PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>
<ExceptionHandling>
@@ -94,8 +94,8 @@
<OmitFramePointers>true</OmitFramePointers>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<WholeProgramOptimization>true</WholeProgramOptimization>
- <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;LIBCONFIG_STATIC;YY_USE_CONST;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
@@ -127,6 +127,13 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClInclude Include="..\3rdparty\libconfig\grammar.h" />
+ <ClInclude Include="..\3rdparty\libconfig\libconfig.h" />
+ <ClInclude Include="..\3rdparty\libconfig\parsectx.h" />
+ <ClInclude Include="..\3rdparty\libconfig\scanctx.h" />
+ <ClInclude Include="..\3rdparty\libconfig\scanner.h" />
+ <ClInclude Include="..\3rdparty\libconfig\strbuf.h" />
+ <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
<ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
<ClInclude Include="..\src\common\cbasetypes.h" />
<ClInclude Include="..\src\common\core.h" />
@@ -159,6 +166,11 @@
<ClInclude Include="..\src\char\inter.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="..\3rdparty\libconfig\grammar.c" />
+ <ClCompile Include="..\3rdparty\libconfig\libconfig.c" />
+ <ClCompile Include="..\3rdparty\libconfig\scanctx.c" />
+ <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
+ <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
<ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c" />
<ClCompile Include="..\src\common\core.c" />
<ClCompile Include="..\src\common\db.c" />
diff --git a/vcproj-10/char-server_sql.vcxproj.filters b/vcproj-10/char-server_sql.vcxproj.filters
index 189c72e79..3b11113ee 100644
--- a/vcproj-10/char-server_sql.vcxproj.filters
+++ b/vcproj-10/char-server_sql.vcxproj.filters
@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
- <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
- <Filter>3rdparty</Filter>
- </ClCompile>
<ClCompile Include="..\src\common\core.c">
<Filter>common</Filter>
</ClCompile>
@@ -79,11 +76,26 @@
<ClCompile Include="..\src\char\inter.c">
<Filter>char_sql</Filter>
</ClCompile>
+ <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
+ <Filter>3rdparty\mt19937ar</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\grammar.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\libconfig.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\scanctx.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\scanner.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\strbuf.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
- <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
- <Filter>3rdparty</Filter>
- </ClInclude>
<ClInclude Include="..\src\common\cbasetypes.h">
<Filter>common</Filter>
</ClInclude>
@@ -171,6 +183,30 @@
<ClInclude Include="..\src\char\int_storage.h">
<Filter>char_sql</Filter>
</ClInclude>
+ <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
+ <Filter>3rdparty\mt19937ar</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\grammar.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\libconfig.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\parsectx.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\scanctx.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\scanner.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\strbuf.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\wincompat.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="common">
@@ -182,5 +218,11 @@
<Filter Include="3rdparty">
<UniqueIdentifier>{b3f5c857-79c0-4a55-b8c5-7e7f56a8f948}</UniqueIdentifier>
</Filter>
+ <Filter Include="3rdparty\mt19937ar">
+ <UniqueIdentifier>{847768ab-8c4b-431b-8667-00f8ae3b915c}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="3rdparty\libconfig">
+ <UniqueIdentifier>{9e8badd7-548f-4eb4-9e87-613e87e772ff}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/vcproj-10/login-server_sql.vcxproj b/vcproj-10/login-server_sql.vcxproj
index 34f5a33af..6cd25c88c 100644
--- a/vcproj-10/login-server_sql.vcxproj
+++ b/vcproj-10/login-server_sql.vcxproj
@@ -51,8 +51,8 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
- <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_SQL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_SQL;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessToFile>false</PreprocessToFile>
<PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>
<ExceptionHandling>
@@ -94,8 +94,8 @@
<OmitFramePointers>true</OmitFramePointers>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<WholeProgramOptimization>true</WholeProgramOptimization>
- <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_SQL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_SQL;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
@@ -131,6 +131,13 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClInclude Include="..\3rdparty\libconfig\grammar.h" />
+ <ClInclude Include="..\3rdparty\libconfig\libconfig.h" />
+ <ClInclude Include="..\3rdparty\libconfig\parsectx.h" />
+ <ClInclude Include="..\3rdparty\libconfig\scanctx.h" />
+ <ClInclude Include="..\3rdparty\libconfig\scanner.h" />
+ <ClInclude Include="..\3rdparty\libconfig\strbuf.h" />
+ <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
<ClInclude Include="..\src\login\account.h" />
<ClInclude Include="..\src\login\ipban.h" />
<ClInclude Include="..\src\login\login.h" />
@@ -156,6 +163,11 @@
<ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="..\3rdparty\libconfig\grammar.c" />
+ <ClCompile Include="..\3rdparty\libconfig\libconfig.c" />
+ <ClCompile Include="..\3rdparty\libconfig\scanctx.c" />
+ <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
+ <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
<ClCompile Include="..\src\login\account_sql.c" />
<ClCompile Include="..\src\login\ipban_sql.c" />
<ClCompile Include="..\src\login\login.c" />
diff --git a/vcproj-10/login-server_sql.vcxproj.filters b/vcproj-10/login-server_sql.vcxproj.filters
index 4171d33cd..4af055584 100644
--- a/vcproj-10/login-server_sql.vcxproj.filters
+++ b/vcproj-10/login-server_sql.vcxproj.filters
@@ -13,9 +13,6 @@
<ClCompile Include="..\src\login\loginlog_sql.c">
<Filter>login_sql</Filter>
</ClCompile>
- <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
- <Filter>3rdparty</Filter>
- </ClCompile>
<ClCompile Include="..\src\common\core.c">
<Filter>common</Filter>
</ClCompile>
@@ -58,6 +55,24 @@
<ClCompile Include="..\src\common\utils.c">
<Filter>common</Filter>
</ClCompile>
+ <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
+ <Filter>3rdparty\mt19937ar</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\grammar.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\libconfig.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\scanctx.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\scanner.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\strbuf.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\login\account.h">
@@ -72,9 +87,6 @@
<ClInclude Include="..\src\login\login.h">
<Filter>login_sql</Filter>
</ClInclude>
- <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
- <Filter>3rdparty</Filter>
- </ClInclude>
<ClInclude Include="..\src\common\cbasetypes.h">
<Filter>common</Filter>
</ClInclude>
@@ -129,6 +141,30 @@
<ClInclude Include="..\src\common\utils.h">
<Filter>common</Filter>
</ClInclude>
+ <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
+ <Filter>3rdparty\mt19937ar</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\grammar.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\libconfig.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\parsectx.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\scanctx.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\scanner.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\strbuf.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\wincompat.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="common">
@@ -140,5 +176,11 @@
<Filter Include="3rdparty">
<UniqueIdentifier>{ab5c90ec-923d-4847-a214-45b40818211e}</UniqueIdentifier>
</Filter>
+ <Filter Include="3rdparty\mt19937ar">
+ <UniqueIdentifier>{68e3bcee-28d9-4b2d-8701-614d50f32999}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="3rdparty\libconfig">
+ <UniqueIdentifier>{779e8145-9bb2-4a88-9149-60586ab0bdd4}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/vcproj-10/map-server_sql.vcxproj b/vcproj-10/map-server_sql.vcxproj
index daa739ba0..55ad74671 100644
--- a/vcproj-10/map-server_sql.vcxproj
+++ b/vcproj-10/map-server_sql.vcxproj
@@ -50,8 +50,8 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
- <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;..\3rdparty\libconfig;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessToFile>false</PreprocessToFile>
<PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>
<ExceptionHandling>
@@ -93,8 +93,8 @@
<OmitFramePointers>true</OmitFramePointers>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<WholeProgramOptimization>true</WholeProgramOptimization>
- <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;..\3rdparty\libconfig;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>
@@ -126,8 +126,16 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClInclude Include="..\3rdparty\libconfig\grammar.h" />
+ <ClInclude Include="..\3rdparty\libconfig\libconfig.h" />
+ <ClInclude Include="..\3rdparty\libconfig\parsectx.h" />
+ <ClInclude Include="..\3rdparty\libconfig\scanctx.h" />
+ <ClInclude Include="..\3rdparty\libconfig\scanner.h" />
+ <ClInclude Include="..\3rdparty\libconfig\strbuf.h" />
+ <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
<ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
<ClInclude Include="..\src\common\cbasetypes.h" />
+ <ClInclude Include="..\src\common\conf.h" />
<ClInclude Include="..\src\common\core.h" />
<ClInclude Include="..\src\common\db.h" />
<ClInclude Include="..\src\common\des.h" />
@@ -172,6 +180,7 @@
<ClInclude Include="..\src\map\party.h" />
<ClInclude Include="..\src\map\path.h" />
<ClInclude Include="..\src\map\pc.h" />
+ <ClInclude Include="..\src\map\pc_groups.h" />
<ClInclude Include="..\src\map\pet.h" />
<ClInclude Include="..\src\map\quest.h" />
<ClInclude Include="..\src\map\config\Core.h" />
@@ -191,7 +200,13 @@
<ClInclude Include="..\src\map\vending.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="..\3rdparty\libconfig\grammar.c" />
+ <ClCompile Include="..\3rdparty\libconfig\libconfig.c" />
+ <ClCompile Include="..\3rdparty\libconfig\scanctx.c" />
+ <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
+ <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
<ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c" />
+ <ClCompile Include="..\src\common\conf.c" />
<ClCompile Include="..\src\common\core.c" />
<ClCompile Include="..\src\common\db.c" />
<ClCompile Include="..\src\common\des.c" />
@@ -234,6 +249,7 @@
<ClCompile Include="..\src\map\party.c" />
<ClCompile Include="..\src\map\path.c" />
<ClCompile Include="..\src\map\pc.c" />
+ <ClCompile Include="..\src\map\pc_groups.c" />
<ClCompile Include="..\src\map\pet.c" />
<ClCompile Include="..\src\map\quest.c" />
<ClCompile Include="..\src\map\script.c" />
diff --git a/vcproj-10/map-server_sql.vcxproj.filters b/vcproj-10/map-server_sql.vcxproj.filters
index 818de17b7..a1b51acce 100644
--- a/vcproj-10/map-server_sql.vcxproj.filters
+++ b/vcproj-10/map-server_sql.vcxproj.filters
@@ -88,9 +88,6 @@
<ClCompile Include="..\src\map\searchstore.c">
<Filter>map_sql</Filter>
</ClCompile>
- <ClCompile Include="..\src\common\showmsg.c">
- <Filter>map_sql</Filter>
- </ClCompile>
<ClCompile Include="..\src\map\skill.c">
<Filter>map_sql</Filter>
</ClCompile>
@@ -109,9 +106,6 @@
<ClCompile Include="..\src\map\vending.c">
<Filter>map_sql</Filter>
</ClCompile>
- <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
- <Filter>3rdparty</Filter>
- </ClCompile>
<ClCompile Include="..\src\common\core.c">
<Filter>common</Filter>
</ClCompile>
@@ -160,6 +154,33 @@
<ClCompile Include="..\src\common\utils.c">
<Filter>common</Filter>
</ClCompile>
+ <ClCompile Include="..\src\common\conf.c">
+ <Filter>common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\map\pc_groups.c">
+ <Filter>map_sql</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\common\showmsg.c">
+ <Filter>common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c">
+ <Filter>3rdparty\mt19937ar</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\grammar.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\libconfig.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\scanctx.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\scanner.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
+ <ClCompile Include="..\3rdparty\libconfig\strbuf.c">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\map\atcommand.h">
@@ -246,9 +267,6 @@
<ClInclude Include="..\src\map\searchstore.h">
<Filter>map_sql</Filter>
</ClInclude>
- <ClInclude Include="..\src\common\showmsg.h">
- <Filter>map_sql</Filter>
- </ClInclude>
<ClInclude Include="..\src\map\skill.h">
<Filter>map_sql</Filter>
</ClInclude>
@@ -267,9 +285,6 @@
<ClInclude Include="..\src\map\vending.h">
<Filter>map_sql</Filter>
</ClInclude>
- <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
- <Filter>3rdparty</Filter>
- </ClInclude>
<ClInclude Include="..\src\common\version.h">
<Filter>common</Filter>
</ClInclude>
@@ -330,6 +345,46 @@
<ClInclude Include="..\src\common\utils.h">
<Filter>common</Filter>
</ClInclude>
+ <ClInclude Include="..\src\map\config\Core.h" />
+ <ClInclude Include="..\src\map\config\Renewal.h" />
+ <ClInclude Include="..\src\map\config\Secure.h" />
+ <ClInclude Include="..\src\map\config\Data\Const.h" />
+ <ClInclude Include="..\src\map\config\Skills\General.h" />
+ <ClInclude Include="..\src\map\config\Skills\Mage_Classes.h" />
+ <ClInclude Include="..\src\map\config\Skills\Swordsman_Classes.h" />
+ <ClInclude Include="..\src\common\conf.h">
+ <Filter>common</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\map\pc_groups.h">
+ <Filter>map_sql</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\common\showmsg.h">
+ <Filter>common</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h">
+ <Filter>3rdparty\mt19937ar</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\grammar.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\libconfig.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\parsectx.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\scanctx.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\scanner.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\strbuf.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
+ <ClInclude Include="..\3rdparty\libconfig\wincompat.h">
+ <Filter>3rdparty\libconfig</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="common">
@@ -341,5 +396,11 @@
<Filter Include="3rdparty">
<UniqueIdentifier>{c4845ea8-bcc7-411b-af29-e3842adb6714}</UniqueIdentifier>
</Filter>
+ <Filter Include="3rdparty\mt19937ar">
+ <UniqueIdentifier>{fcf23386-ddba-4a72-9b41-62f8e2d0e6c0}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="3rdparty\libconfig">
+ <UniqueIdentifier>{9caf40b7-c4d1-43b4-bd1f-0376b4f920e7}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/vcproj-10/mapcache.vcxproj b/vcproj-10/mapcache.vcxproj
index 15a010c15..b0f58b70b 100644
--- a/vcproj-10/mapcache.vcxproj
+++ b/vcproj-10/mapcache.vcxproj
@@ -49,8 +49,8 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
- <AdditionalIncludeDirectories>..\3rdparty\zlib\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;MINICORE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\zlib\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;MINICORE;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessToFile>false</PreprocessToFile>
<PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>
<ExceptionHandling>
@@ -91,8 +91,8 @@
<OmitFramePointers>true</OmitFramePointers>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<WholeProgramOptimization>true</WholeProgramOptimization>
- <AdditionalIncludeDirectories>..\3rdparty\zlib\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;MINICORE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\3rdparty\libconfig;..\3rdparty\zlib\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;MINICORE;LIBCONFIG_STATIC;YY_USE_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>false</FunctionLevelLinking>
diff --git a/vcproj-9/char-server_sql.vcproj b/vcproj-9/char-server_sql.vcproj
index 06c006cd4..43b959827 100644
--- a/vcproj-9/char-server_sql.vcproj
+++ b/vcproj-9/char-server_sql.vcproj
@@ -43,8 +43,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
- PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;FD_SETSIZE=4096"
+ AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+ PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST"
GeneratePreprocessedFile="0"
ExceptionHandling="0"
BasicRuntimeChecks="3"
@@ -137,8 +137,8 @@
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
WholeProgramOptimization="true"
- AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
- PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;FD_SETSIZE=4096"
+ AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+ PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST"
StringPooling="true"
RuntimeLibrary="0"
DefaultCharIsUnsigned="false"
@@ -204,20 +204,84 @@
<Filter
Name="3rdparty"
>
+ <Filter
+ Name="mt19937ar"
+ >
+ <File
+ RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="libconfig"
+ >
+ <File
+ RelativePath="..\3rdparty\libconfig\grammar.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\grammar.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\libconfig.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\libconfig.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\parsectx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanctx.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanctx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanner.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanner.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\strbuf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\strbuf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\wincompat.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="common"
+ >
<File
- RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+ RelativePath="..\src\common\cbasetypes.h"
>
</File>
<File
- RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+ RelativePath="..\src\common\conf.c"
>
</File>
- </Filter>
- <Filter
- Name="common"
- >
<File
- RelativePath="..\src\common\cbasetypes.h"
+ RelativePath="..\src\common\conf.h"
>
</File>
<File
diff --git a/vcproj-9/login-server_sql.vcproj b/vcproj-9/login-server_sql.vcproj
index d2f9d34d9..a0ce7ceae 100644
--- a/vcproj-9/login-server_sql.vcproj
+++ b/vcproj-9/login-server_sql.vcproj
@@ -43,8 +43,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
- PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;FD_SETSIZE=4096;WITH_SQL"
+ AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+ PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;WITH_SQL"
GeneratePreprocessedFile="0"
ExceptionHandling="0"
BasicRuntimeChecks="3"
@@ -137,8 +137,8 @@
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
WholeProgramOptimization="true"
- AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
- PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;FD_SETSIZE=4096;WITH_SQL"
+ AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+ PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST;WITH_SQL"
StringPooling="true"
RuntimeLibrary="0"
DefaultCharIsUnsigned="false"
@@ -247,6 +247,14 @@
>
</File>
<File
+ RelativePath="..\src\common\conf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\common\conf.h"
+ >
+ </File>
+ <File
RelativePath="..\src\common\core.c"
>
</File>
@@ -382,14 +390,70 @@
<Filter
Name="3rdparty"
>
- <File
- RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
- >
- </File>
- <File
- RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
- >
- </File>
+ <Filter
+ Name="mt19937ar"
+ >
+ <File
+ RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="libconfig"
+ >
+ <File
+ RelativePath="..\3rdparty\libconfig\grammar.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\grammar.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\libconfig.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\libconfig.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\parsectx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanctx.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanctx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanner.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanner.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\strbuf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\strbuf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\wincompat.h"
+ >
+ </File>
+ </Filter>
</Filter>
</Files>
<Globals>
diff --git a/vcproj-9/map-server_sql.vcproj b/vcproj-9/map-server_sql.vcproj
index 14c807bcb..39a58e47d 100644
--- a/vcproj-9/map-server_sql.vcproj
+++ b/vcproj-9/map-server_sql.vcproj
@@ -42,8 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
- PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;FD_SETSIZE=4096"
+ AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+ PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST"
GeneratePreprocessedFile="0"
ExceptionHandling="0"
BasicRuntimeChecks="3"
@@ -136,8 +136,8 @@
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
WholeProgramOptimization="true"
- AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
- PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;FD_SETSIZE=4096"
+ AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar"
+ PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;FD_SETSIZE=4096;LIBCONFIG_STATIC;YY_USE_CONST"
StringPooling="true"
RuntimeLibrary="0"
DefaultCharIsUnsigned="false"
@@ -203,20 +203,84 @@
<Filter
Name="3rdparty"
>
+ <Filter
+ Name="mt19937ar"
+ >
+ <File
+ RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="libconfig"
+ >
+ <File
+ RelativePath="..\3rdparty\libconfig\grammar.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\grammar.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\libconfig.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\libconfig.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\parsectx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanctx.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanctx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanner.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\scanner.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\strbuf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\strbuf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\3rdparty\libconfig\wincompat.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="common"
+ >
<File
- RelativePath="..\3rdparty\mt19937ar\mt19937ar.c"
+ RelativePath="..\src\common\cbasetypes.h"
>
</File>
<File
- RelativePath="..\3rdparty\mt19937ar\mt19937ar.h"
+ RelativePath="..\src\common\conf.c"
>
</File>
- </Filter>
- <Filter
- Name="common"
- >
<File
- RelativePath="..\src\common\cbasetypes.h"
+ RelativePath="..\src\common\conf.h"
>
</File>
<File
@@ -436,6 +500,14 @@
>
</File>
<File
+ RelativePath="..\src\map\config\Data\Const.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\map\config\Core.h"
+ >
+ </File>
+ <File
RelativePath="..\src\map\date.c"
>
</File>
@@ -452,6 +524,10 @@
>
</File>
<File
+ RelativePath="..\src\map\config\Skills\General.h"
+ >
+ </File>
+ <File
RelativePath="..\src\map\guild.c"
>
</File>
@@ -500,6 +576,10 @@
>
</File>
<File
+ RelativePath="..\src\map\config\Skills\Mage_Classes.h"
+ >
+ </File>
+ <File
RelativePath="..\src\map\mail.c"
>
</File>
@@ -576,47 +656,31 @@
>
</File>
<File
- RelativePath="..\src\map\pet.c"
+ RelativePath="..\src\map\pc_groups.c"
>
</File>
<File
- RelativePath="..\src\map\pet.h"
+ RelativePath="..\src\map\pc_groups.h"
>
</File>
<File
- RelativePath="..\src\map\quest.c"
- >
- </File>
- <File
- RelativePath="..\src\map\quest.h"
+ RelativePath="..\src\map\pet.c"
>
</File>
<File
- RelativePath="..\src\map\config\Core.h"
+ RelativePath="..\src\map\pet.h"
>
</File>
<File
- RelativePath="..\src\map\config\Renewal.h"
+ RelativePath="..\src\map\quest.c"
>
</File>
<File
- RelativePath="..\src\map\config\Secure.h"
+ RelativePath="..\src\map\quest.h"
>
</File>
<File
- RelativePath="..\src\map\config\Data\Const.h"
- >
- </File>
- <File
- RelativePath="..\src\map\config\Skills\General.h"
- >
- </File>
- <File
- RelativePath="..\src\map\config\Skills\Mage_Classes.h"
- >
- </File>
- <File
- RelativePath="..\src\map\config\Skills\Swordsman_Classes.h"
+ RelativePath="..\src\map\config\Renewal.h"
>
</File>
<File
@@ -636,6 +700,10 @@
>
</File>
<File
+ RelativePath="..\src\map\config\Secure.h"
+ >
+ </File>
+ <File
RelativePath="..\src\map\skill.c"
>
</File>
@@ -660,6 +728,10 @@
>
</File>
<File
+ RelativePath="..\src\map\config\Skills\Swordsman_Classes.h"
+ >
+ </File>
+ <File
RelativePath="..\src\map\trade.c"
>
</File>
diff --git a/vcproj-9/mapcache.vcproj b/vcproj-9/mapcache.vcproj
index 645ae0b5e..e13f7ab27 100644
--- a/vcproj-9/mapcache.vcproj
+++ b/vcproj-9/mapcache.vcproj
@@ -42,8 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories="..\3rdparty\zlib\include;..\3rdparty\msinttypes\include"
- PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;MINICORE"
+ AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\zlib\include;..\3rdparty\msinttypes\include"
+ PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;MINICORE;LIBCONFIG_STATIC;YY_USE_CONST"
GeneratePreprocessedFile="0"
ExceptionHandling="0"
BasicRuntimeChecks="3"
@@ -135,8 +135,8 @@
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
WholeProgramOptimization="true"
- AdditionalIncludeDirectories="..\3rdparty\zlib\include;..\3rdparty\msinttypes\include"
- PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;MINICORE"
+ AdditionalIncludeDirectories="..\3rdparty\libconfig;..\3rdparty\zlib\include;..\3rdparty\msinttypes\include"
+ PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;MINICORE;LIBCONFIG_STATIC;YY_USE_CONST"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="false"
@@ -211,11 +211,11 @@
>
</File>
<File
- RelativePath="..\src\common\des.h"
+ RelativePath="..\src\common\des.c"
>
</File>
<File
- RelativePath="..\src\common\des.c"
+ RelativePath="..\src\common\des.h"
>
</File>
<File