From ecddc1dd042645ead07724204efc7bc0f5e8ad57 Mon Sep 17 00:00:00 2001 From: Timo Smit Date: Sat, 13 Feb 2016 12:19:37 +0100 Subject: [PATCH] 1.0.0 --- INSTALL | 68 +++ LICENSE | 674 +++++++++++++++++++++++++ config/cvars.cfg | 27 + config/greetings.cfg | 8 + config/rules.cfg | 40 ++ config/sprees.cfg | 0 config/wolfadmin.cfg | 8 + database/new/wolfadmin.sql | 67 +++ database/upgrade/1.0.0a1/wolfadmin.sql | 21 + database/upgrade/1.0.0b/wolfadmin.sql | 2 + luascripts/admin/admin.lua | 158 ++++++ luascripts/admin/balancer.lua | 107 ++++ luascripts/admin/rules.lua | 57 +++ luascripts/admin/warns.lua | 52 ++ luascripts/commands.lua | 311 ++++++++++++ luascripts/commands/balance.lua | 26 + luascripts/commands/dewarn.lua | 59 +++ luascripts/commands/enablevote.lua | 28 + luascripts/commands/greeting.lua | 32 ++ luascripts/commands/help.lua | 69 +++ luascripts/commands/incognito.lua | 77 +++ luascripts/commands/kickbots.lua | 28 + luascripts/commands/listaliases.lua | 74 +++ luascripts/commands/listlevels.lua | 91 ++++ luascripts/commands/listmaps.lua | 38 ++ luascripts/commands/needbots.lua | 28 + luascripts/commands/plock.lua | 64 +++ luascripts/commands/punlock.lua | 56 ++ luascripts/commands/putbots.lua | 47 ++ luascripts/commands/readconfig.lua | 32 ++ luascripts/commands/resetsprees.lua | 28 + luascripts/commands/rules.lua | 45 ++ luascripts/commands/setlevel.lua | 48 ++ luascripts/commands/showwarns.lua | 65 +++ luascripts/commands/sprees.lua | 40 ++ luascripts/commands/stats.lua | 97 ++++ luascripts/commands/vmute.lua | 78 +++ luascripts/commands/vunmute.lua | 54 ++ luascripts/commands/warn.lua | 43 ++ luascripts/db/cfg.lua | 201 ++++++++ luascripts/db/db.lua | 47 ++ luascripts/db/mysql.lua | 259 ++++++++++ luascripts/game/bots.lua | 54 ++ luascripts/game/game.lua | 114 +++++ luascripts/game/sprees.lua | 209 ++++++++ luascripts/game/voting.lua | 139 +++++ luascripts/license.txt | 674 +++++++++++++++++++++++++ luascripts/main.lua | 159 ++++++ luascripts/players/greetings.lua | 109 ++++ luascripts/players/stats.lua | 97 ++++ luascripts/util/constants.lua | 67 +++ luascripts/util/debug.lua | 44 ++ luascripts/util/events.lua | 127 +++++ luascripts/util/files.lua | 136 +++++ luascripts/util/settings.lua | 107 ++++ luascripts/util/timers.lua | 69 +++ luascripts/util/util.lua | 134 +++++ 57 files changed, 5593 insertions(+) create mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 config/cvars.cfg create mode 100644 config/greetings.cfg create mode 100644 config/rules.cfg create mode 100644 config/sprees.cfg create mode 100644 config/wolfadmin.cfg create mode 100644 database/new/wolfadmin.sql create mode 100644 database/upgrade/1.0.0a1/wolfadmin.sql create mode 100644 database/upgrade/1.0.0b/wolfadmin.sql create mode 100644 luascripts/admin/admin.lua create mode 100644 luascripts/admin/balancer.lua create mode 100644 luascripts/admin/rules.lua create mode 100644 luascripts/admin/warns.lua create mode 100644 luascripts/commands.lua create mode 100644 luascripts/commands/balance.lua create mode 100644 luascripts/commands/dewarn.lua create mode 100644 luascripts/commands/enablevote.lua create mode 100644 luascripts/commands/greeting.lua create mode 100644 luascripts/commands/help.lua create mode 100644 luascripts/commands/incognito.lua create mode 100644 luascripts/commands/kickbots.lua create mode 100644 luascripts/commands/listaliases.lua create mode 100644 luascripts/commands/listlevels.lua create mode 100644 luascripts/commands/listmaps.lua create mode 100644 luascripts/commands/needbots.lua create mode 100644 luascripts/commands/plock.lua create mode 100644 luascripts/commands/punlock.lua create mode 100644 luascripts/commands/putbots.lua create mode 100644 luascripts/commands/readconfig.lua create mode 100644 luascripts/commands/resetsprees.lua create mode 100644 luascripts/commands/rules.lua create mode 100644 luascripts/commands/setlevel.lua create mode 100644 luascripts/commands/showwarns.lua create mode 100644 luascripts/commands/sprees.lua create mode 100644 luascripts/commands/stats.lua create mode 100644 luascripts/commands/vmute.lua create mode 100644 luascripts/commands/vunmute.lua create mode 100644 luascripts/commands/warn.lua create mode 100644 luascripts/db/cfg.lua create mode 100644 luascripts/db/db.lua create mode 100644 luascripts/db/mysql.lua create mode 100644 luascripts/game/bots.lua create mode 100644 luascripts/game/game.lua create mode 100644 luascripts/game/sprees.lua create mode 100644 luascripts/game/voting.lua create mode 100644 luascripts/license.txt create mode 100644 luascripts/main.lua create mode 100644 luascripts/players/greetings.lua create mode 100644 luascripts/players/stats.lua create mode 100644 luascripts/util/constants.lua create mode 100644 luascripts/util/debug.lua create mode 100644 luascripts/util/events.lua create mode 100644 luascripts/util/files.lua create mode 100644 luascripts/util/settings.lua create mode 100644 luascripts/util/timers.lua create mode 100644 luascripts/util/util.lua diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..54504a1 --- /dev/null +++ b/INSTALL @@ -0,0 +1,68 @@ +WolfAdmin module for Wolfenstein: Enemy Territory servers. +Copyright (C) 2015 Timo 'Timothy' Smit + +REQUIREMENTS + + * Wolfenstein: Enemy Territory server + * NoQuarter mod (1.2.7 or higher, maybe 1.2.5 works as well) + * Lua 5.1 library and Lua modules enabled (installed binaries) + * A MySQL server is required if you want to use alias listing, warn and + level history. Otherwise the module will not work, so please make sure + you have one. If you want to make use of a MySQL server, the module + requires an additional MySQL library (luasql.mysql). + In case you do not have the LuaSQL MySQL library installed, you are + able to download this library from the WolfAdmin file database at + http://dev.timosmit.com/files/wolfadmin/. + +INSTRUCTIONS (NEW) + + * Unpack the /luascripts folder into your /nq directory + * Unpack the contents of the /config folder into your /nq directory (or + /.etwolf/nq on Linux systems) + * Optionally, copy the contents of the cvars.cfg to your own server + configuration file + * Copy the .pk3 file corresponding to this WolfAdmin version to your + /nq directory + * Modify /nq/wolfadmin.cfg to your needs + * Modify /nq/shrubbot.cfg to add WolfAdmin specific flags + * Add /luascripts/wolfadmin/main.lua to the lua_modules cvar + * Run the .sql script in /database/new on your MySQL server + * Run your server + +INSTRUCTIONS (UPGRADE) + + * Unpack the /luascripts folder into your /nq directory + * Run the .sql script in /database/upgrade/previous-version-here on your + MySQL server + * Run your server + +TROUBLESHOOTING + + * libmysqlclient.so.15: cannot open shared object file: No such file or + directory + This means you need an additional library for the LuaSQL module, which is + used by WolfAdmin for the database connection. This file can usually be + downloaded via your package manager or from the WolfAdmin file database + at http://dev.timosmit.com/files/wolfadmin/. After downloading you will + have to copy this file to your fs_basepath (usually the root folder of + the server, where the etded file is located). + * WolfAdmin config will not get loaded/one of greetings/rules is not loaded + Make sure that there are two empty lines (containing no spaces) at the + end of your .cfg files. Due to the loading mechanism WolfAdmin uses, you + have to add these completely empty lines, right at the end. Additionally, + between two blocks of information you also have to leave an empty line. + Check the config files in the /config folder for an example. + +WEBSITE + +Check out the website for a full documentation. + + http://dev.timosmit.com/wolfadmin/ + +BUGS + +Please report your bugs at + + http://dev.timosmit.com/bugtracker/?project_id=1 + +Thanks in advance :-) Happy bug hunting! \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU 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. + + + Copyright (C) + + 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 . + +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: + + Copyright (C) + 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 +. + + 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 +. diff --git a/config/cvars.cfg b/config/cvars.cfg new file mode 100644 index 0000000..940d8a0 --- /dev/null +++ b/config/cvars.cfg @@ -0,0 +1,27 @@ +// WolfAdmin specific CVARs +set g_fileGreetings "greetings.cfg" +set g_fileRules "rules.cfg" +set g_fileSprees "sprees.cfg" + +set g_welcomeMessage "^dwolfadmin: ^9This server is running WolfAdmin, type ^7/wolfadmin ^9for more information." +set g_welcomeArea 3 + +set g_greetingArea 3 +set g_botGreetings 1 + +set g_evenerMinDifference 2 +set g_evenerMaxDifference 5 +set g_evenerInterval 30 + +set g_voteNextMapTimeout 0 +set g_restrictedVotes "" + +set g_renameLimit 3 +set g_renameInterval 60 + +set g_spreeRecords 1 +set g_botRecords 1 + +set g_warnHistory 1 + +set g_announceRevives 1 \ No newline at end of file diff --git a/config/greetings.cfg b/config/greetings.cfg new file mode 100644 index 0000000..8a314e6 --- /dev/null +++ b/config/greetings.cfg @@ -0,0 +1,8 @@ +[level] +level = 0 +greeting = Welcome ^7[N]^9! + +[user] +guid = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +greeting = Welcome the console! + diff --git a/config/rules.cfg b/config/rules.cfg new file mode 100644 index 0000000..a43b9f0 --- /dev/null +++ b/config/rules.cfg @@ -0,0 +1,40 @@ +[rule] +shortcut = sk +rule = ^1NO ^7spawnkilling^9! + +[rule] +shortcut = tk +rule = ^1NO ^7teamkilling^9! + +[rule] +shortcut = tb +rule = ^1NO ^7teambleeding^9! + +[rule] +shortcut = xp +rule = ^1NO ^7XP whoring^9! + +[rule] +shortcut = lan +rule = ^7English ^9in ^7main ^9and ^7team chat^9. + +[rule] +shortcut = chat +rule = ^1NO ^7insulting ^9or ^7swearing^9! + +[rule] +shortcut = advert +rule = ^7Do ^1NOT ^7advertise^9! + +[rule] +shortcut = push +rule = ^7Do ^1NOT ^9push your ^7team mates^9! + +[rule] +shortcut = level +rule = ^7Do ^1NOT ^9ask for ^7admin levels^9! + +[rule] +shortcut = bug +rule = ^7Do ^1NOT ^9use ^7map bugs^9/^7exploits^9! + diff --git a/config/sprees.cfg b/config/sprees.cfg new file mode 100644 index 0000000..e69de29 diff --git a/config/wolfadmin.cfg b/config/wolfadmin.cfg new file mode 100644 index 0000000..c8a6d6c --- /dev/null +++ b/config/wolfadmin.cfg @@ -0,0 +1,8 @@ +[db] +type = mysql +hostname = localhost +port = 3306 +database = wolfadmin +username = wolfadmin +password = suchasecret + diff --git a/database/new/wolfadmin.sql b/database/new/wolfadmin.sql new file mode 100644 index 0000000..706aa83 --- /dev/null +++ b/database/new/wolfadmin.sql @@ -0,0 +1,67 @@ +CREATE TABLE IF NOT EXISTS `players` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `guid` char(32) NOT NULL, + `ip` varchar(40) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `guid` (`guid`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `aliases` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `player` int(10) unsigned NOT NULL, + `alias` varchar(128) NOT NULL, + `cleanalias` varchar(128) NOT NULL, + `lastused` int(10) unsigned NOT NULL, + `used` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `playerid_idx` (`player`), + CONSTRAINT `aliasplayer` FOREIGN KEY (`player`) REFERENCES `players` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `levels` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `player` int(10) unsigned NOT NULL, + `level` int(11) NOT NULL, + `admin` int(10) unsigned NOT NULL, + `datetime` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `leveladmin_idx` (`admin`), + KEY `levelplayer` (`player`), + CONSTRAINT `leveladmin` FOREIGN KEY (`admin`) REFERENCES `players` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + CONSTRAINT `levelplayer` FOREIGN KEY (`player`) REFERENCES `players` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `warns` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `player` int(10) unsigned NOT NULL, + `reason` varchar(128) NOT NULL, + `admin` int(10) unsigned NOT NULL, + `datetime` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `playerid_idx` (`player`), + KEY `invoker_idx` (`admin`), + CONSTRAINT `warnadmin` FOREIGN KEY (`admin`) REFERENCES `players` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + CONSTRAINT `warnplayer` FOREIGN KEY (`player`) REFERENCES `players` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `maps` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL, + `lastplayed` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `records` ( + `mapid` int(10) unsigned NOT NULL, + `type` tinyint(3) unsigned NOT NULL, + `date` int(10) unsigned NOT NULL, + `record` smallint(5) unsigned NOT NULL, + `player` int(10) unsigned NOT NULL, + PRIMARY KEY (`mapid`,`type`), + KEY `ksplayer_idx` (`player`), + CONSTRAINT `kspreeplayer` FOREIGN KEY (`player`) REFERENCES `players` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + CONSTRAINT `spreemap` FOREIGN KEY (`mapid`) REFERENCES `maps` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `players` (`id`, `guid`, `ip`) VALUES (1, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', '127.0.0.1'); +INSERT INTO `aliases` (`id`, `player`, `alias`, `lastused`, `used`) VALUES (1, 1, 'console', 0, 0); \ No newline at end of file diff --git a/database/upgrade/1.0.0a1/wolfadmin.sql b/database/upgrade/1.0.0a1/wolfadmin.sql new file mode 100644 index 0000000..c8f4943 --- /dev/null +++ b/database/upgrade/1.0.0a1/wolfadmin.sql @@ -0,0 +1,21 @@ +CREATE TABLE `maps` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL, + `lastplayed` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; + +CREATE TABLE `records` ( + `mapid` int(10) unsigned NOT NULL, + `type` tinyint(3) unsigned NOT NULL, + `date` int(10) unsigned NOT NULL, + `record` smallint(5) unsigned NOT NULL, + `player` int(10) unsigned NOT NULL, + PRIMARY KEY (`mapid`,`type`), + KEY `ksplayer_idx` (`player`), + CONSTRAINT `kspreeplayer` FOREIGN KEY (`player`) REFERENCES `players` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + CONSTRAINT `spreemap` FOREIGN KEY (`mapid`) REFERENCES `maps` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `wolfadmin`.`players` (`id`, `guid`, `ip`) VALUES (1, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', '127.0.0.1'); +INSERT INTO `wolfadmin`.`aliases` (`id`, `player`, `alias`, `lastused`, `used`) VALUES (1, 1, 'console', 0, 0); \ No newline at end of file diff --git a/database/upgrade/1.0.0b/wolfadmin.sql b/database/upgrade/1.0.0b/wolfadmin.sql new file mode 100644 index 0000000..dd57064 --- /dev/null +++ b/database/upgrade/1.0.0b/wolfadmin.sql @@ -0,0 +1,2 @@ +ALTER TABLE `wolfadmin`.`aliases` +ADD COLUMN `cleanalias` VARCHAR(128) NOT NULL AFTER `alias`; \ No newline at end of file diff --git a/luascripts/admin/admin.lua b/luascripts/admin/admin.lua new file mode 100644 index 0000000..4e2f450 --- /dev/null +++ b/luascripts/admin/admin.lua @@ -0,0 +1,158 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local events = require "luascripts.wolfadmin.util.events" +local settings = require "luascripts.wolfadmin.util.settings" +local files = require "luascripts.wolfadmin.util.files" +local db = require "luascripts.wolfadmin.db.db" +local stats = require "luascripts.wolfadmin.players.stats" + +local admin = {} + +function admin.isVoiceMuted(clientId) + if stats.get(clientId, "voiceMute") then + if stats.get(clientId, "voiceMute") - os.time() > 0 then + return true + else + admin.unmuteVoice(clientId) + end + end + + return false +end + +function admin.isPlayerLocked(clientId) + if stats.get(clientId, "playerLock") then + return true + end + + return false +end + +function admin.muteVoice(clientId, length) + stats.set(clientId, "voiceMute", length) +end + +function admin.unmuteVoice(clientId) + stats.set(clientId, "voiceMute", false) +end + +function admin.lockTeam(clientId, team) + stats.set(clientId, "voiceMute", length) +end + +function admin.unlockTeam(clientId) + stats.set(clientId, "voiceMute", length) +end + +function admin.updatePlayer(clientId) + local player = db.getplayer(stats.get(clientId, "playerGUID")) + + if player then + local guid = stats.get(clientId, "playerGUID") + local ip = stats.get(clientId, "playerIP") + + db.updateplayer(guid, ip) + else + local guid = stats.get(clientId, "playerGUID") + local ip = stats.get(clientId, "playerIP") + + db.addplayer(guid, ip) + admin.setPlayerLevel(clientId, et.G_shrubbot_level(clientId), 1) + end +end + +function admin.updateAlias(clientId) + local playerid = db.getplayer(stats.get(clientId, "playerGUID"))["id"] + local name = stats.get(clientId, "playerName") + local alias = db.getaliasbyname(playerid, name) + + if alias then + db.updatealias(alias["id"], os.time()) + if alias["cleanalias"] == "" then + db.updatecleanalias(alias["id"], name) + end + else + db.addalias(playerid, name, os.time()) + end +end + +function admin.setPlayerLevel(clientId, level, adminId) + local playerid = db.getplayer(stats.get(clientId, "playerGUID"))["id"] + local adminid = db.getplayer(stats.get(adminId, "playerGUID"))["id"] + + db.addsetlevel(playerid, level, adminid, os.time()) +end + +function admin.onconnect(clientId, firstTime, isBot) + -- only increase the counter on first connection (fixes counter increase on + -- clientbegin which is also triggered on warmup/maprestart/etc) + stats.set(clientId, "namechangeStart", os.time()) + stats.set(clientId, "namechangePts", 0) + + if firstTime then + if stats.get(clientId, "playerGUID") == "NO_GUID" or stats.get(clientId, "playerGUID") == "unknown" then + return "\n\nIt appears you do not have a ^7GUID^9/^7etkey^9. In order to play on this server, enable ^7PunkBuster ^9(use ^7\pb_cl_enable^9) ^9and/or create an ^7etkey^9.\n\nMore info: ^7www.etkey.org" + end + + if settings.get("db_type") ~= "cfg" then + admin.updatePlayer(clientId) + admin.updateAlias(clientId) + end + end +end +events.handle("onClientConnect", admin.onconnect) + +function stats.oninfochange(clientId) + local clientInfo = et.trap_GetUserinfo(clientId) + local old = stats.get(clientId, "playerName") + local new = et.Info_ValueForKey(clientInfo, "name") + + if new ~= old then + if (os.time() - stats.get(clientId, "namechangeStart")) < settings.get("g_renameInterval") and stats.get(clientId, "namechangePts") >= settings.get("g_renameLimit") and not stats.get(clientId, "namechangeForce") then + stats.set(clientId, "namechangeForce", true) + + clientInfo = et.Info_SetValueForKey(clientInfo, "name", old) + et.trap_SetUserinfo(clientId, clientInfo) + et.ClientUserinfoChanged(clientId) + + stats.set(clientId, "namechangeForce", false) + + et.trap_SendServerCommand(clientId, "cp \"Too many name changes in 1 minute.\";") + else + stats.set(clientId, "playerName", new) + + if (os.time() - stats.get(clientId, "namechangeStart")) > settings.get("g_renameInterval") then + stats.set(clientId, "namechangeStart", os.time()) + stats.get(clientId, "namechangePts", 0) + end + + stats.add(clientId, "namechangePts", 1) + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay -1 \""..old.." ^7is now known as "..new.."\";") + + if settings.get("db_type") ~= "cfg" then + admin.updateAlias(clientId) + end + + events.trigger("onClientNameChange", clientId, old, new) + end + end +end +events.handle("onClientInfoChange", stats.oninfochange) + +return admin \ No newline at end of file diff --git a/luascripts/admin/balancer.lua b/luascripts/admin/balancer.lua new file mode 100644 index 0000000..154739b --- /dev/null +++ b/luascripts/admin/balancer.lua @@ -0,0 +1,107 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local timers = require "luascripts.wolfadmin.util.timers" +local settings = require "luascripts.wolfadmin.util.settings" + +local balancer = {} + +local evenerCount = 0 + +function balancer.balance(byAdmin, forceBalance) + local teams = { + [1] = {}, + [2] = {}, + [3] = {} + } + + for playerId = 0, et.trap_Cvar_Get("sv_maxclients") - 1 do + if wolfa_isPlayer(playerId) then + local team = tonumber(et.gentity_get(playerId, "sess.sessionTeam")) + + table.insert(teams[team], playerId) + end + end + + local teamGreater = constants.TEAM_SPECTATORS + local teamSmaller = constants.TEAM_SPECTATORS + + local teamsDifference = math.abs(#teams[constants.TEAM_AXIS] - #teams[constants.TEAM_ALLIES]) + + if #teams[constants.TEAM_AXIS] > #teams[constants.TEAM_ALLIES] then + teamGreater = constants.TEAM_AXIS + teamSmaller = constants.TEAM_ALLIES + elseif #teams[constants.TEAM_ALLIES] > #teams[constants.TEAM_AXIS] then + teamGreater = constants.TEAM_ALLIES + teamSmaller = constants.TEAM_AXIS + end + + local teamGreaterName = util.getTeamName(teamGreater) + local teamSmallerName = util.getTeamName(teamSmaller) + + local teamGreaterColor = util.getTeamColor(teamGreater) + local teamSmallerColor = util.getTeamColor(teamSmaller) + + if settings.get("g_evenerMaxDifference") > 0 and teamsDifference >= settings.get("g_evenerMaxDifference") then + evenerCount = evenerCount + 1 + + if forceBalance or evenerCount >= 2 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "!shuffle;") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cpm \"^devener: ^7THE TEAMS HAVE BEEN ^qSHUFFLED^7!\";") + + evenerCount = 0 + else + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cpm \"^devener: ^1EVEN THE TEAMS ^7OR ^1SHUFFLE\";") + end + elseif teamsDifference >= settings.get("g_evenerMinDifference") then + evenerCount = evenerCount + 1 + + if forceBalance or evenerCount >= 3 then + for i = 1, (teamsDifference / 2) do + local rand = math.random(#teams[teamGreater]) + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "!put "..teams[teamGreater][rand].." "..(teamGreater == constants.TEAM_AXIS and constants.TEAM_ALLIES_SC or constants.TEAM_AXIS_SC)..";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^devener: ^9thank you, ^7"..et.gentity_get(teams[teamGreater][rand], "pers.netname")..", ^9for helping to even the teams.\";") + + teams[teamSmaller][rand] = teams[teamGreater][rand] + teams[teamGreater][rand] = nil + end + + evenerCount = 0 + else + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^devener: ^9teams seem unfair, would someone from "..teamGreaterColor..teamGreaterName.." ^9please switch to "..teamSmallerColor..teamSmallerName.."^9?\";") + end + else + evenerCount = 0 + + if byAdmin then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^devener: ^9teams are even.\";") + end + end +end + +function balancer.oninit() + if settings.get("g_evenerInterval") > 0 then + timers.add(balancer.balance, settings.get("g_evenerInterval") * 1000, 0, false, false) + end +end +events.handle("onGameInit", balancer.oninit) + +return balancer diff --git a/luascripts/admin/rules.lua b/luascripts/admin/rules.lua new file mode 100644 index 0000000..b95ce83 --- /dev/null +++ b/luascripts/admin/rules.lua @@ -0,0 +1,57 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local events = require "luascripts.wolfadmin.util.events" +local files = require "luascripts.wolfadmin.util.files" +local settings = require "luascripts.wolfadmin.util.settings" + +local rules = {} + +local data = {} + +function rules.get(shortcut) + if shortcut then + return data[shortcut] + end + + return data +end + +function rules.load() + local fileName = settings.get("g_fileRules") + + if fileName == "" then + return 0 + end + + local amount, array = files.loadCFG(fileName, "[a-z]+", true) + + if amount == 0 then return 0 end + + for id, rule in ipairs(array["rule"]) do + data[rule["shortcut"]] = rule["rule"] + end + + return amount +end + +function rules.oninit(levelTime, randomSeed, restartMap) + rules.load() +end +events.handle("onGameInit", rules.oninit) + +return rules \ No newline at end of file diff --git a/luascripts/admin/warns.lua b/luascripts/admin/warns.lua new file mode 100644 index 0000000..d326a6a --- /dev/null +++ b/luascripts/admin/warns.lua @@ -0,0 +1,52 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local db = require "luascripts.wolfadmin.db.db" +local events = require "luascripts.wolfadmin.util.events" +local settings = require "luascripts.wolfadmin.util.settings" +local stats = require "luascripts.wolfadmin.players.stats" + +local warns = {} + +local data = {} + +function warns.get(clientId, warnId) + if warnId then + return db.getwarn(warnId) + else + local playerid = db.getplayer(stats.get(clientId, "playerGUID"))["id"] + + return db.getwarns(playerid) + end +end + +function warns.add(clientId, reason, adminId, datetime) + local playerid = db.getplayer(stats.get(clientId, "playerGUID"))["id"] + local adminid = db.getplayer(stats.get(adminId, "playerGUID"))["id"] + + db.addwarn(playerid, reason, adminid, datetime) +end + +function warns.remove(clientId, warnId) + if not warns.get(clientId, warnId) then + return + end + + db.removewarn(warnId) +end + +return warns \ No newline at end of file diff --git a/luascripts/commands.lua b/luascripts/commands.lua new file mode 100644 index 0000000..8114f51 --- /dev/null +++ b/luascripts/commands.lua @@ -0,0 +1,311 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local files = require "luascripts.wolfadmin.util.files" +local admin = require "luascripts.wolfadmin.admin.admin" +local stats = require "luascripts.wolfadmin.players.stats" + +local commands = {} + +-- available shrubflags: lqyFHY +local data = {} + +function commands.get(command) + if command then + return data[command] + end + + return data +end + +function commands.register(command, func, flag, help, syntax, hidden) + data[command] = { + ["function"] = func, + ["flag"] = flag, + ["help"] = help or "N/A", + ["syntax"] = "^2!"..command..(syntax and " "..syntax or ""), + ["hidden"] = hidden + } +end + +function commands.load() + local functionStart = et.trap_Milliseconds() + local files = files.ls("commands/") + local amount = 0 + + for _, file in pairs(files) do + if string.match(string.lower(file), "^[a-z]+%.lua$") then + require("luascripts/wolfadmin/commands/"..string.sub(file, 1, string.len(file) - 4)) + + amount = amount + 1 + end + end + + outputDebug("commands.load(): "..amount.." entries loaded in "..et.trap_Milliseconds() - functionStart.." ms") + + return amount +end + +function commands.log(clientId, command, cmdArguments) + local functionStart = et.trap_Milliseconds() + local fileDescriptor = files.open(et.trap_Cvar_Get("g_logAdmin"), et.FS_APPEND) + + local logLine + local levelTime = wolfa_getLevelTime() / 1000 + + local clientGUID = clientId and stats.get(clientId, "playerGUID") or "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + local clientName = clientId and stats.get(clientId, "playerName") or "console" + local clientFlags = "" + + local victimId + + -- funny, NoQuarter actually checks EACH command for a victim (so even + -- !help [playername] will log a victimname). so why not do the same :D + -- todo: do this more nicely, maybe change .register() function + if cmdArguments[1] then + local cmdClient + + if tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient ~= -1 and et.gentity_get(cmdClient, "pers.netname") then + victimId = cmdClient + end + end + + if victimId then + local victimName = stats.get(victimId, "playerName") + logLine = string.format("%3i:%02i: %i: %s: %s: %s: %s: %s: %s: \"%s\"\n", math.floor(levelTime / 60), (levelTime % 60), clientId, clientGUID, clientName, clientFlags, command, victimId, victimName, table.concat(cmdArguments, " ", 2)) + else + logLine = string.format("%3i:%02i: %i: %s: %s: %s: %s: \"%s\"\n", math.floor(levelTime / 60), (levelTime % 60), clientId, clientGUID, clientName, clientFlags, command, table.concat(cmdArguments, " ")) + end + + et.trap_FS_Write(logLine, string.len(logLine), fileDescriptor) + + et.trap_FS_FCloseFile(fileDescriptor) +end + +function commands.oninit() + commands.load() +end +events.handle("onGameInit", commands.oninit) + +function commands.onservercommand(cmdText) + -- this if statement definitely sucks. + if string.lower(et.trap_Argv(0)) == "csay" and et.trap_Argc() >= 3 then + local clientId = tonumber(et.trap_Argv(1)) + + if clientId and clientId ~= -1337 then -- -1337 because -1 is a magic number/broadcasted to all clients + et.trap_SendServerCommand(clientId, "print \""..et.trap_Argv(2).."\n\";") + elseif clientId then + et.G_Print(util.removeColors(et.trap_Argv(2)).."\n") + end + elseif string.lower(et.trap_Argv(0)) == "ccpm" and et.trap_Argc() >= 3 then + local clientId = tonumber(et.trap_Argv(1)) + + if clientId and clientId ~= -1337 then -- -1337 because -1 is a magic number/broadcasted to all clients + et.trap_SendServerCommand(clientId, "cpm \""..et.trap_Argv(2).."\";") + elseif clientId then + et.G_Print(util.removeColors(et.trap_Argv(2)).."\n") + end + elseif string.lower(et.trap_Argv(0)) == "cchat" and et.trap_Argc() >= 3 then + local clientId = tonumber(et.trap_Argv(1)) + + if clientId and clientId ~= -1337 then -- -1337 because -1 is a magic number/broadcasted to all clients + et.trap_SendServerCommand(clientId, "chat \""..et.trap_Argv(2).."\";") + elseif clientId then + et.G_Print(util.removeColors(et.trap_Argv(2)).."\n") + end + elseif string.lower(et.trap_Argv(0)) == "cannounce" and et.trap_Argc() >= 3 then + local clientId = tonumber(et.trap_Argv(1)) + + if clientId and clientId ~= -1337 then -- -1337 because -1 is a magic number/broadcasted to all clients + et.trap_SendServerCommand(clientId, "announce \""..et.trap_Argv(2).."\";") + elseif clientId then + et.G_Print(util.removeColors(et.trap_Argv(2)).."\n") + end + elseif string.lower(et.trap_Argv(0)) == "cmusic" and et.trap_Argc() >= 3 then + local clientId = tonumber(et.trap_Argv(1)) + + if clientId and clientId ~= -1337 then -- -1337 because -1 is a magic number/broadcasted to all clients + et.trap_SendServerCommand(clientId, "mu_play \""..et.trap_Argv(2).."\";") + elseif clientId then + et.G_Print(util.removeColors(et.trap_Argv(2)).."\n") + end + elseif et.trap_Argv(0) == "cmdclient" then + local cmd = et.trap_Argv(1) + local clientId = tonumber(et.trap_Argv(2)) + + et.trap_SendServerCommand(clientId, cmd.." \""..et.trap_Argv(3).."\n\";") + else + -- TODO: merge with commands.onclientcommand + local shrubCmd = cmdText + local shrubArgumentsOffset = 1 + local shrubArguments = {} + + if string.find(cmdText, "!") == 1 then + shrubCmd = string.lower(string.sub(cmdText, 2, string.len(cmdText))) + end + + if data[shrubCmd] and data[shrubCmd]["function"] and data[shrubCmd]["flag"] then + for i = 1, et.trap_Argc() - shrubArgumentsOffset do + shrubArguments[i] = et.trap_Argv(i + shrubArgumentsOffset - 1) + end + + data[shrubCmd]["function"](-1337, shrubArguments) + + if not data[shrubCmd]["hidden"] then + commands.log(-1, shrubCmd, shrubArguments) + end + end + end +end +events.handle("onServerCommand", commands.onservercommand) + +function commands.onclientcommand(clientId, cmdText) + local wolfCmd = string.lower(et.trap_Argv(0)) + local shrubCmd = nil + local shrubArguments = {} + local shrubArgumentsOffset = 0 + + if wolfCmd == "adminchat" or wolfCmd == "ac" then + if et.G_shrubbot_permission(clientId, "~") == 1 then + if et.trap_Argc() == 1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^9usage: ^7"..wolfCmd.." [^2message^7]\";") + else + local message = {} + local recipients = {} + + for i = 1, et.trap_Argc() - 1 do + message[i] = et.trap_Argv(i) + end + + for playerId = 0, et.trap_Cvar_Get("sv_maxclients") - 1 do + if wolfa_isPlayer(playerId) and et.G_shrubbot_permission(playerId, "~") == 1 then + table.insert(recipients, playerId) + end + end + + for _, recipient in ipairs(recipients) do + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..recipient.." \"^7"..et.gentity_get(clientId, "pers.netname").."^7 -> adminchat ("..#recipients.." recipients): ^a"..table.concat(message, " ").."\";") + et.trap_SendServerCommand(recipient, "cp \"^jadminchat message from ^7"..et.gentity_get(clientId, "pers.netname")) + end + + et.G_LogPrint("adminchat: "..et.gentity_get(clientId, "pers.netname")..": "..table.concat(message, " ").."\n") + end + end + + return 1 + elseif wolfCmd == "wolfadmin" then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^3This server is running ^7Wolf^1Admin ^7"..wolfa_getVersion().." ^3("..wolfa_getRelease().."^3)\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^3Created by ^7Timo '^aTimo^qthy^7' ^7Smit^3. More info on\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \" ^7http://dev.timosmit.com/wolfadmin/\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^3Thanks for using!\";") + + return 1 + elseif wolfCmd == "team" then + if admin.isPlayerLocked(clientId) then + local clientTeam = tonumber(et.gentity_get(clientId, "sess.sessionTeam")) + local teamName = util.getTeamName(clientTeam) + local teamColor = util.getTeamColor(clientTeam) + + et.trap_SendServerCommand(clientId, "cp \"^7You are locked to the "..teamColor..teamName.." ^7team") + + return 1 + end + + stats.set(clientId, "currentKillSpree", 0) + stats.set(clientId, "currentDeathSpree", 0) + stats.set(clientId, "currentReviveSpree", 0) + elseif wolfCmd == "callvote" then + local voteArguments = {} + for i = 2, et.trap_Argc() - 1 do + voteArguments[(i - 1)] = et.trap_Argv(i) + end + + return events.trigger("onCallvote", clientId, et.trap_Argv(1), voteArguments) + elseif wolfCmd == "say" or wolfCmd == "say_team" or wolfCmd == "say_teamnl" or wolfCmd == "say_buddy" then + if et.gentity_get(clientId, "sess.muted") == 1 then + et.trap_SendServerCommand(clientId, "cp \"^1You are muted\"") + + return 1 + end + elseif wolfCmd == "vsay" or wolfCmd == "vsay_team" then + if admin.isVoiceMuted(clientId) then + et.trap_SendServerCommand(clientId, "cp \"^1You are voicemuted\"") + + return 1 + end + end + + if (wolfCmd == "say" or wolfCmd == "say_team" or wolfCmd == "say_buddy") and string.find(et.trap_Argv(1), "!") == 1 then + shrubArguments = util.split(et.trap_Argv(1), " ") + if #shrubArguments > 1 then + shrubCmd = string.sub(shrubArguments[1], 2, string.len(shrubArguments[1])) + table.remove(shrubArguments, 1) + else + shrubCmd = string.sub(et.trap_Argv(1), 2, string.len(et.trap_Argv(1))) + shrubArgumentsOffset = 2 + + for i = 1, et.trap_Argc() - shrubArgumentsOffset do + shrubArguments[i] = et.trap_Argv(i + shrubArgumentsOffset - 1) + end + if shrubArguments[1] == et.trap_Argv(1) then table.remove(shrubArguments, 1) end + end + elseif string.find(wolfCmd, "!") == 1 then + shrubCmd = string.sub(wolfCmd, 2, string.len(wolfCmd)) + shrubArgumentsOffset = 1 + + for i = 1, et.trap_Argc() - shrubArgumentsOffset do + shrubArguments[i] = et.trap_Argv(i + shrubArgumentsOffset - 1) + end + end + + if shrubCmd then + shrubCmd = string.lower(shrubCmd) + + if data[shrubCmd] and data[shrubCmd]["function"] and data[shrubCmd]["flag"] then + if wolfCmd == "say" or (((wolfCmd == "say_team" and et.gentity_get(cmdClient, "sess.sessionTeam") ~= et.TEAM_SPECTATORS) or wolfCmd == "say_buddy") and et.G_shrubbot_permission(clientId, "9") == 1) or (wolfCmd == "!"..shrubCmd and et.G_shrubbot_permission(clientId, "3") == 1) then + if data[shrubCmd]["flag"] ~= "" and et.G_shrubbot_permission(clientId, data[shrubCmd]["flag"]) == 1 then + local isFinished = data[shrubCmd]["function"](clientId, shrubArguments) + + if not data[shrubCmd]["hidden"] then + commands.log(clientId, shrubCmd, shrubArguments) + end + + if isFinished and "!"..shrubCmd == wolfCmd then -- silent command via console, removes "unknown command" message + return 1 + end + else + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \""..shrubCmd..": permission denied\";") + end + end + end + end + + return 0 +end +events.handle("onClientCommand", commands.onclientcommand) + +return commands \ No newline at end of file diff --git a/luascripts/commands/balance.lua b/luascripts/commands/balance.lua new file mode 100644 index 0000000..0ed0c06 --- /dev/null +++ b/luascripts/commands/balance.lua @@ -0,0 +1,26 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" +local balancer = require "luascripts.wolfadmin.admin.balancer" + +function commandBalance(clientId, cmdArguments) + balancer.balance(true, (cmdArguments[1] and cmdArguments[1] == "force")) + + return true +end +commands.register("balance", commandBalance, "p", "either asks the players to even up or evens them by moving or shuffling players", "^2!balance ^9(^hforce^9)") \ No newline at end of file diff --git a/luascripts/commands/dewarn.lua b/luascripts/commands/dewarn.lua new file mode 100644 index 0000000..982e6de --- /dev/null +++ b/luascripts/commands/dewarn.lua @@ -0,0 +1,59 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local settings = require "luascripts.wolfadmin.util.settings" +local commands = require "luascripts.wolfadmin.commands" +local warns = require "luascripts.wolfadmin.admin.warns" + +function commandRemoveWarn(clientId, cmdArguments) + if settings.get("g_warnHistory") == 0 or settings.get("db_type") == "cfg" then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^ddewarn: ^9warn history is disabled.\";") + + return true + elseif #cmdArguments < 2 or tonumber(cmdArguments[2]) == nil then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^ddewarn usage: "..commands.get("dewarn")["syntax"].."\";") + + return true + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^ddewarn: ^9no or multiple matches for '^7"..cmdArguments[1].."^9'.\";") + + return true + elseif not et.gentity_get(cmdClient, "pers.netname") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^ddewarn: ^9no connected player by that name or slot #\";") + + return true + end + + local playerWarn = warns.get(cmdClient, tonumber(cmdArguments[2])) + + if not playerWarn then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^ddewarn: ^9warn #"..cmdArguments[2].." does not exist for ^7"..et.gentity_get(cmdClient, "pers.netname").."^9.\";") + else + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^ddewarn: ^9warn #"..cmdArguments[2].." removed for ^7"..et.gentity_get(cmdClient, "pers.netname").."^9.\";") + + warns.remove(cmdClient, tonumber(cmdArguments[2])) + end + + return true +end +commands.register("dewarn", commandRemoveWarn, "R", "remove a warning for a certain player", "^9[^3name|slot#^9] ^9[^3warn#^9]", function() return (settings.get("g_warnHistory") == 0 or settings.get("db_type") == "cfg") end) \ No newline at end of file diff --git a/luascripts/commands/enablevote.lua b/luascripts/commands/enablevote.lua new file mode 100644 index 0000000..4c9a6cd --- /dev/null +++ b/luascripts/commands/enablevote.lua @@ -0,0 +1,28 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" +local voting = require "luascripts.wolfadmin.game.voting" + +function commandEnableVote(clientId, cmdArguments) + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^denablevote: ^9next map voting has been enabled.\";") + + voting.force("nextmap") + + return true +end +commands.register("enablevote", commandEnableVote, "c", "enables next map voting") \ No newline at end of file diff --git a/luascripts/commands/greeting.lua b/luascripts/commands/greeting.lua new file mode 100644 index 0000000..58939af --- /dev/null +++ b/luascripts/commands/greeting.lua @@ -0,0 +1,32 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local commands = require "luascripts.wolfadmin.commands" +local settings = require "luascripts.wolfadmin.util.settings" +local greetings = require "luascripts.wolfadmin.players.greetings" + +function commandGreeting(clientId, cmdArguments) + local greetingText = greetings.get(clientId) + + if greetingText then + greetings.show(clientId) + else + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dgreeting: ^9you do not have a personal greeting.\";") + end +end +commands.register("greeting", commandGreeting, "Q", "display your personal greeting, if you have one") \ No newline at end of file diff --git a/luascripts/commands/help.lua b/luascripts/commands/help.lua new file mode 100644 index 0000000..baeb634 --- /dev/null +++ b/luascripts/commands/help.lua @@ -0,0 +1,69 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" + +function commandHelp(clientId, cmdArguments) + local cmds = commands.get() + + if #cmdArguments == 0 then + local availableCommands = {} + + for command, data in pairs(cmds) do + if data["function"] and data["flag"] and et.G_shrubbot_permission(clientId, data["flag"]) == 1 and (not data["hidden"] or (type(data["hidden"]) == "function" and not data["hidden"]())) then + table.insert(availableCommands, command) + end + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \"^dhelp: ^9"..#availableCommands.." additional commands (open console for the full list)\";") + + local cmdsOnLine, cmdsBuffer = 0, "" + + for _, command in pairs(availableCommands) do + cmdsBuffer = cmdsBuffer ~= "" and cmdsBuffer..string.format("%-12s", command) or string.format("%-12s", command) + cmdsOnLine = cmdsOnLine + 1 + + if cmdsOnLine == 6 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^f"..cmdsBuffer.."\";") + cmdsBuffer = "" + cmdsOnLine = 0 + end + end + + if cmdsBuffer ~= "" then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^f"..cmdsBuffer.."\";") + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^9Type ^2!help ^d[command] ^9for help with a specific command.\";") + + return false + elseif #cmdArguments > 0 then + local helpCmd = string.lower(cmdArguments[1]) + + if cmds[helpCmd] ~= nil and (not cmds[helpCmd]["hidden"] or (type(cmds[helpCmd]["hidden"]) == "function" and not cmds[helpCmd]["hidden"]())) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dhelp: ^9help for '^2"..helpCmd.."^9':\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dfunction: ^9"..cmds[helpCmd]["help"].."\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dsyntax: ^9"..cmds[helpCmd]["syntax"].."\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dflag: ^9'^2"..cmds[helpCmd]["flag"].."^9'\";") + + return true + end + end + + return false +end +commands.register("help", commandHelp, "h", "display commands available to you or help on a specific command", "^9(^hcommand^9)", true) \ No newline at end of file diff --git a/luascripts/commands/incognito.lua b/luascripts/commands/incognito.lua new file mode 100644 index 0000000..f688fd4 --- /dev/null +++ b/luascripts/commands/incognito.lua @@ -0,0 +1,77 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" +local stats = require "luascripts.wolfadmin.players.stats" + +function commandIncognito(clientId, cmdArguments) + local fileName = et.trap_Cvar_Get("g_shrubbot") + local functionStart = et.trap_Milliseconds() + local fileDescriptor, fileLength = et.trap_FS_FOpenFile(fileName, et.FS_READ) + + if fileLength == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dincognito: ^9an error happened (shrubbot file could not be opened)\";") + + error("failed to open "..fileName.."\n") + end + + local fileString = et.trap_FS_Read(fileDescriptor, fileLength) + + et.trap_FS_FCloseFile(fileDescriptor) + + for entry, adminName, adminGUID, adminLevel, adminFlags in string.gmatch(fileString, "(%[admin%]\nname%s+=%s+([%a%d%p]+)\nguid%s+=%s+([%u%d]+)\nlevel%s+=%s+([%d]+)\nflags%s+=%s+([%a%d%p]*)\n\n)") do + -- et.G_Print(string.format("%s %s %d %s\n", adminName, adminGUID, adminLevel, adminFlags)) + + if stats.get(clientId, "playerGUID") == adminGUID then + if et.G_shrubbot_permission(clientId, "@") ~= 1 then + adminFlags = adminFlags.."+@" + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \"^dincognito: ^9you are now playing incognito.\";") + else + if string.find(adminFlags, "+@") then + adminFlags = string.gsub(adminFlags, "+@", "") + elseif string.find(adminFlags, "@") then + adminFlags = string.gsub(adminFlags, "@", "") + else + adminFlags = adminFlags.."-@" + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \"^dincognito: ^9you stopped playing incognito.\";") + end + + local adminNameEscaped = string.gsub(adminName, "([%*%+%-%?%^%$%%%[%]%(%)%.])", "%%%1") -- fix for special captures + fileString = string.gsub(fileString, "%[admin%]\nname%s+=%s+"..adminNameEscaped.."\nguid%s+=%s+"..adminGUID.."\nlevel%s+=%s+"..adminLevel.."\nflags%s+=%s+([%a%d%p]*)\n\n", "[admin]\nname = "..adminName.."\nguid = "..adminGUID.."\nlevel = "..adminLevel.."\nflags = "..adminFlags.."\n\n") + + break + end + end + + local fileDescriptor, fileLength = et.trap_FS_FOpenFile(fileName, et.FS_WRITE) + + local writeCount = et.trap_FS_Write(fileString, string.len(fileString), fileDescriptor) + + if not writeCount or writeCount < 1 then + error("failed to write "..fileName.."\n") + end + + et.trap_FS_FCloseFile(fileDescriptor) + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "readconfig;") + + return true +end +commands.register("incognito", commandIncognito, "s", "fakes your level to guest (no aka)") \ No newline at end of file diff --git a/luascripts/commands/kickbots.lua b/luascripts/commands/kickbots.lua new file mode 100644 index 0000000..574b3ba --- /dev/null +++ b/luascripts/commands/kickbots.lua @@ -0,0 +1,28 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" +local bots = require "luascripts.wolfadmin.game.bots" + +function commandBotsOff(clientId, cmdArguments) + bots.enable(false) + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dkickbots: ^9bots were toggled off.\";") + + return true +end +commands.register("kickbots", commandBotsOff, "O", "kicks all bots from the game") \ No newline at end of file diff --git a/luascripts/commands/listaliases.lua b/luascripts/commands/listaliases.lua new file mode 100644 index 0000000..bb8cf8a --- /dev/null +++ b/luascripts/commands/listaliases.lua @@ -0,0 +1,74 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local settings = require "luascripts.wolfadmin.util.settings" +local db = require "luascripts.wolfadmin.db.db" +local commands = require "luascripts.wolfadmin.commands" +local stats = require "luascripts.wolfadmin.players.stats" + +function commandListAliases(clientId, cmdArguments) + if settings.get("db_type") == "cfg" then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistaliases: ^9alias history is disabled.\";") + + return true + elseif cmdArguments[1] == nil then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistaliases usage: "..commands.get("listaliases")["syntax"].."\";") + + return true + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistaliases: ^9no or multiple matches for '^7"..cmdArguments[1].."^9'.\";") + + return true + elseif not et.gentity_get(cmdClient, "pers.netname") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistaliases: ^9no connected player by that name or slot #\";") + + return true + end + + if et.G_shrubbot_permission(cmdClient, "!") == 1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistaliases: ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9is immune to this command.\";") + + return true + elseif et.G_shrubbot_level(cmdClient) > et.G_shrubbot_level(clientId) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistaliases: ^9sorry, but your intended victim has a higher admin level than you do.\";") + + return true + end + + local player = db.getplayer(stats.get(cmdClient, "playerGUID"))["id"] + local aliases = db.getaliases(player) + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dAliases for ^7"..et.gentity_get(cmdClient, "pers.netname").."^d:\";") + for _, alias in pairs(aliases) do + local numberOfSpaces = 24 - string.len(util.removeColors(alias["alias"])) + local spaces = string.rep(" ", numberOfSpaces) + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^7"..spaces..alias["alias"].." ^7"..string.format("%8s", alias["used"]).." times\";") + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \"^dlistaliases: ^9"..#aliases.." known aliases for ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9 (open console for the full list).\";") + + return true +end +commands.register("listaliases", commandListAliases, "f", "display all known aliases for a player", "^9[^3name|slot#^9]", function() return (settings.get("db_type") == "cfg") end) \ No newline at end of file diff --git a/luascripts/commands/listlevels.lua b/luascripts/commands/listlevels.lua new file mode 100644 index 0000000..72c9cbc --- /dev/null +++ b/luascripts/commands/listlevels.lua @@ -0,0 +1,91 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local settings = require "luascripts.wolfadmin.util.settings" +local db = require "luascripts.wolfadmin.db.db" +local commands = require "luascripts.wolfadmin.commands" +local stats = require "luascripts.wolfadmin.players.stats" + +function commandListLevels(clientId, cmdArguments) + if cmdArguments[1] == nil then + local fileName = et.trap_Cvar_Get("g_shrubbot") + local functionStart = et.trap_Milliseconds() + local fileDescriptor, fileLength = et.trap_FS_FOpenFile(fileName, et.FS_READ) + local levelsCount = 0 + + if fileLength == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistlevels: ^9an error happened (shrubbot file could not be opened)\";") + + error("failed to open "..fileName.."\n") + end + + local fileString = et.trap_FS_Read(fileDescriptor, fileLength) + + et.trap_FS_FCloseFile(fileDescriptor) + + for entry, levelNr, levelName, levelFlags in string.gmatch(fileString, "(%[level%]\nlevel%s+=%s+(-?[0-9]+)\nname%s+=%s+([%a%d%p ]+)\nflags%s+=%s+([%a%d%p]*)\n\n)") do + -- et.G_Print(string.format("%d %s %s\n", levelNr, levelName, levelFlags)) + + local numberOfSpaces = 24 - string.len(util.removeColors(levelName)) + local spaces = string.rep(" ", numberOfSpaces) + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^7"..string.format("%5s", levelNr).." ^7"..spaces..levelName.." ^7"..levelFlags.."\";") + + levelsCount = levelsCount + 1 + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \"^dlistlevels: ^9"..levelsCount.." available levels (open console for the full list)\";") + + return true + elseif settings.get("db_type") == "cfg" then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistlevels: ^9level history is disabled.\";") + + return true + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistlevels: ^9no or multiple matches for '^7"..cmdArguments[1].."^9'.\";") + + return true + elseif not et.gentity_get(cmdClient, "pers.netname") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistlevels: ^9no connected player by that name or slot #\";") + + return true + end + + local player = db.getplayer(stats.get(cmdClient, "playerGUID"))["id"] + local levels = db.getlevels(player) + + if not (levels and #levels > 0) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dlistlevels: ^9there are no recorded levels for player ^7"..et.gentity_get(cmdClient, "pers.netname").."^9.\";") + else + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dLevels for ^7"..et.gentity_get(cmdClient, "pers.netname").."^d:\";") + for id, level in pairs(levels) do + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^f"..string.format("%4s", level["id"]).." ^7"..string.format("%-20s", util.removeColors(db.getlastalias(level["admin"])["alias"])).." ^f"..os.date("%d/%m/%Y", level["datetime"]).." ^7"..level["level"].."\";") + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \"^dlistlevels: ^9recorded levels for ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9were printed to the console.\";") + end + + return true +end +commands.register("listlevels", commandListLevels, "s", "display all levels on the server") \ No newline at end of file diff --git a/luascripts/commands/listmaps.lua b/luascripts/commands/listmaps.lua new file mode 100644 index 0000000..0946f02 --- /dev/null +++ b/luascripts/commands/listmaps.lua @@ -0,0 +1,38 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local commands = require "luascripts.wolfadmin.commands" +local game = require "luascripts.wolfadmin.game.game" + +function commandListMaps(clientId, cmdArguments) + local output = "" + + local maps = game.getMaps() + + for _, map in ipairs(maps) do + local prefix = "^9" + if map == game.getMap() then prefix = "^7" end + + output = (output ~= "") and output.." "..prefix..map or map + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dlistmaps: ^9"..output.. "\";") + + return true +end +commands.register("listmaps", commandListMaps, "C", "display the maps in the rotation") \ No newline at end of file diff --git a/luascripts/commands/needbots.lua b/luascripts/commands/needbots.lua new file mode 100644 index 0000000..8cdc73a --- /dev/null +++ b/luascripts/commands/needbots.lua @@ -0,0 +1,28 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" +local bots = require "luascripts.wolfadmin.game.bots" + +function commandBotsOn(clientId, cmdArguments) + bots.enable(true) + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dneedbots: ^9bots were toggled on.\";") + + return true +end +commands.register("needbots", commandBotsOn, "O", "adds bots to the game") \ No newline at end of file diff --git a/luascripts/commands/plock.lua b/luascripts/commands/plock.lua new file mode 100644 index 0000000..baa00c2 --- /dev/null +++ b/luascripts/commands/plock.lua @@ -0,0 +1,64 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local commands = require "luascripts.wolfadmin.commands" +local admin = require "luascripts.wolfadmin.admin.admin" +local stats = require "luascripts.wolfadmin.players.stats" + +function commandPlayerLock(clientId, cmdArguments) + if cmdArguments[1] == nil then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dplock usage: "..commands.get("vmute")["syntax"].."\";") + + return true + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dplock: ^9no or multiple matches for '^7"..cmdArguments[1].."^9'.\";") + + return true + elseif not et.gentity_get(cmdClient, "pers.netname") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dplock: ^9no connected player by that name or slot #\";") + + return true + end + + if admin.isPlayerLocked(cmdClient) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dplock: ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9is already locked to a team.\";") + + return true + elseif et.G_shrubbot_permission(cmdClient, "!") == 1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dplock: ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9is immune to this command.\";") + + return true + elseif et.G_shrubbot_level(cmdClient) > et.G_shrubbot_level(clientId) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dplock: ^9sorry, but your intended victim has a higher admin level than you do.\";") + + return true + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dplock: ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9has been locked to his team\";") + + stats.set(cmdClient, "playerLock", true) + + return true +end +commands.register("plock", commandPlayerLock, "K", "locks a player to a specific team", "^9[^3name|slot#^9]") \ No newline at end of file diff --git a/luascripts/commands/punlock.lua b/luascripts/commands/punlock.lua new file mode 100644 index 0000000..64fcfaf --- /dev/null +++ b/luascripts/commands/punlock.lua @@ -0,0 +1,56 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local commands = require "luascripts.wolfadmin.commands" +local admin = require "luascripts.wolfadmin.admin.admin" +local stats = require "luascripts.wolfadmin.players.stats" + +function commandPlayerUnlock(clientId, cmdArguments) + if cmdArguments[1] == nil then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dpunlock usage: "..commands.get("vmute")["syntax"].."\";") + + return true + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dpunlock: ^9no or multiple matches for '^7"..cmdArguments[1].."^9'.\";") + + return true + elseif not et.gentity_get(cmdClient, "pers.netname") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dpunlock: ^9no connected player by that name or slot #\";") + + return true + end + + if not admin.isPlayerLocked(cmdClient) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dpunlock: ^9no player by that name or slot # is locked to a team\";") + + return true + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dpunlock: ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9has been unlocked from his team\";") + + stats.set(cmdClient, "playerLock", false) + + return true +end +commands.register("punlock", commandPlayerUnlock, "K", "unlocks a player", "^9[^3name|slot#^9]") \ No newline at end of file diff --git a/luascripts/commands/putbots.lua b/luascripts/commands/putbots.lua new file mode 100644 index 0000000..488dc32 --- /dev/null +++ b/luascripts/commands/putbots.lua @@ -0,0 +1,47 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" +local commands = require "luascripts.wolfadmin.commands" +local bots = require "luascripts.wolfadmin.game.bots" + +function commandPutBots(clientId, cmdArguments) + if cmdArguments[1] == nil and cmdArguments[1] ~= constants.TEAM_AXIS_SC and cmdArguments[1] ~= constants.TEAM_ALLIES_SC and cmdArguments[1] ~= constants.TEAM_SPECTATORS_SC then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dputbots usage: "..commands.get("vmute")["syntax"].."\";") + + return true + end + + local team + if cmdArguments[1] == constants.TEAM_AXIS_SC then + team = constants.TEAM_AXIS + elseif cmdArguments[1] == constants.TEAM_ALLIES_SC then + team = constants.TEAM_ALLIES + elseif cmdArguments[1] == constants.TEAM_SPECTATORS_SC then + team = constants.TEAM_SPECTATORS + end + + local teamname = util.getTeamColor(team)..util.getTeamName(team) + + bots.put(team) + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dputbots: ^9all bots were set to ^7"..teamname.." ^9team.\";") + + return true +end +commands.register("putbots", commandPutBots, "p", "puts all bots into a specific team", "^9[r|b|s]") \ No newline at end of file diff --git a/luascripts/commands/readconfig.lua b/luascripts/commands/readconfig.lua new file mode 100644 index 0000000..acef3a5 --- /dev/null +++ b/luascripts/commands/readconfig.lua @@ -0,0 +1,32 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local settings = require "luascripts.wolfadmin.util.settings" +local commands = require "luascripts.wolfadmin.commands" +local rules = require "luascripts.wolfadmin.admin.rules" +local greetings = require "luascripts.wolfadmin.players.greetings" + +function commandReadconfig(clientId, cmdArguments) + settings.load() + local rulesCount = rules.load() + local greetingsCount = greetings.load() + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"readconfig: loaded "..greetingsCount.." greetings, "..rulesCount.." rules\";") + + return false +end +commands.register("readconfig", commandReadconfig, "G", "reloads the shrubbot config file and refreshes user flags", nil, true) \ No newline at end of file diff --git a/luascripts/commands/resetsprees.lua b/luascripts/commands/resetsprees.lua new file mode 100644 index 0000000..3a1eaf9 --- /dev/null +++ b/luascripts/commands/resetsprees.lua @@ -0,0 +1,28 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" +local sprees = require "luascripts.wolfadmin.game.sprees" + +function commandResetSprees(clientId, cmdArguments) + sprees.reset() + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dresetsprees: ^9spree records have been reset.\";") + + return true +end +commands.register("resetsprees", commandResetSprees, "G", "resets the spree records") \ No newline at end of file diff --git a/luascripts/commands/rules.lua b/luascripts/commands/rules.lua new file mode 100644 index 0000000..6653e15 --- /dev/null +++ b/luascripts/commands/rules.lua @@ -0,0 +1,45 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" +local rules = require "luascripts.wolfadmin.admin.rules" + +function commandRules(clientId, cmdArguments) + if #cmdArguments == 0 then + local amountOfRules = 0 + + local list = rules.get() + + for shortcut, rule in pairs(list) do + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^f"..string.format("%8s", shortcut).." ^9- "..rule.."\";") + + amountOfRules = amountOfRules + 1 + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \"^drules: ^9"..amountOfRules.." rules (open console for the full list)\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^9Type ^2!rules ^d[rule] ^9to announce a specific rule.\";") + elseif #cmdArguments > 0 then + local rule = rules.get(string.lower(cmdArguments[1])) + + if rule then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^drules: "..rules.get(string.lower(cmdArguments[1])).."\";") + end + end + + return true +end +commands.register("rules", commandRules, "C", "display the rules on the server", "^9(^hrule^9)") \ No newline at end of file diff --git a/luascripts/commands/setlevel.lua b/luascripts/commands/setlevel.lua new file mode 100644 index 0000000..00b160c --- /dev/null +++ b/luascripts/commands/setlevel.lua @@ -0,0 +1,48 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local settings = require "luascripts.wolfadmin.util.settings" +local commands = require "luascripts.wolfadmin.commands" +local admin = require "luascripts.wolfadmin.admin.admin" + +function commandSetLevel(clientId, cmdArguments) + if #cmdArguments < 2 then + return false + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + return false + elseif not et.gentity_get(cmdClient, "pers.netname") then + return false + end + + -- plays a promotion sound + et.trap_SendConsoleCommand(et.EXEC_APPEND, "playsound \"/sound/vo/general/axis/hq_promogen.wav\";") + + if settings.get("db_type") ~= "cfg" then + cmdArguments[2] = tonumber(cmdArguments[2]) or 0 + + admin.setPlayerLevel(cmdClient, tonumber(cmdArguments[2]), clientId) + end + + return false +end +commands.register("setlevel", commandSetLevel, "s", "sets the admin level of a player", "^9[^3name|slot#^9] ^9[^3level^9]", true) \ No newline at end of file diff --git a/luascripts/commands/showwarns.lua b/luascripts/commands/showwarns.lua new file mode 100644 index 0000000..c6481f4 --- /dev/null +++ b/luascripts/commands/showwarns.lua @@ -0,0 +1,65 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local settings = require "luascripts.wolfadmin.util.settings" +local db = require "luascripts.wolfadmin.db.db" + +local commands = require "luascripts.wolfadmin.commands" +local warns = require "luascripts.wolfadmin.admin.warns" + +function commandShowWarns(clientId, cmdArguments) + if settings.get("g_warnHistory") == 0 or settings.get("db_type") == "cfg" then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dshowwarns: ^9warn history is disabled.\";") + + return true + elseif cmdArguments[1] == nil then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dshowwarns usage: "..commands.get("showwarns")["syntax"].."\";") + + return true + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dshowwarns: ^9no or multiple matches for '^7"..cmdArguments[1].."^9'.\";") + + return true + elseif not et.gentity_get(cmdClient, "pers.netname") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dshowwarns: ^9no connected player by that name or slot #\";") + + return true + end + + local playerWarns = warns.get(cmdClient) + + if not (playerWarns and #playerWarns > 0) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dshowwarns: ^9there are no warnings for player ^7"..et.gentity_get(cmdClient, "pers.netname").."^9.\";") + else + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dWarns for ^7"..et.gentity_get(cmdClient, "pers.netname").."^d:\";") + for _, warn in pairs(playerWarns) do + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^f"..string.format("%4s", warn["id"]).." ^7"..string.format("%-20s", util.removeColors(db.getlastalias(warn["admin"])["alias"])).." ^f"..os.date("%d/%m/%Y", warn["datetime"]).." ^7"..warn["reason"].."\";") + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \"^dshowwarns: ^9warnings for ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9were printed to the console.\";") + end + + return true +end +commands.register("showwarns", commandShowWarns, "R", "display warnings for a specific player", "^9[^3name|slot#^9]", function() return (settings.get("g_warnHistory") == 0 or settings.get("db_type") == "cfg") end) \ No newline at end of file diff --git a/luascripts/commands/sprees.lua b/luascripts/commands/sprees.lua new file mode 100644 index 0000000..b96bc5c --- /dev/null +++ b/luascripts/commands/sprees.lua @@ -0,0 +1,40 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" +local sprees = require "luascripts.wolfadmin.game.sprees" + +function commandShowSprees(clientId, cmdArguments) + local records = sprees.get() + + if not (records["ksrecord"] or records["dsrecord"] or records["rsrecord"]) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dsprees: ^9there are no records for this map yet.\"") + else + if records["ksrecord"] and records["ksrecord"] > 0 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dsprees: ^9longest kill spree (^7"..records["ksrecord"].."^9) by ^7"..records["ksname"].."^9.\";") + end + if records["dsrecord"] and records["dsrecord"] > 0 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dsprees: ^9longest death spree (^7"..records["dsrecord"].."^9) by ^7"..records["dsname"].."^9.\";") + end + if records["rsrecord"] and records["rsrecord"] > 0 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dsprees: ^9longest revive spree (^7"..records["rsrecord"].."^9) by ^7"..records["rsname"].."^9.\";") + end + end + + return true +end +commands.register("sprees", commandShowSprees, "I", "display the current spree records") \ No newline at end of file diff --git a/luascripts/commands/stats.lua b/luascripts/commands/stats.lua new file mode 100644 index 0000000..ed4fed5 --- /dev/null +++ b/luascripts/commands/stats.lua @@ -0,0 +1,97 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local commands = require "luascripts.wolfadmin.commands" + +function commandShowStats(clientId, cmdArguments) + if cmdArguments[1] == nil then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dstats usage: "..commands.get("stats")["syntax"].."\";") + + return true + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dstats: ^9no or multiple matches for '^7"..cmdArguments[1].."^9'.\";") + + return true + elseif not et.gentity_get(cmdClient, "pers.netname") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dstats: ^9no connected player by that name or slot #\";") + + return true + end + + local stats = { + ["name"] = et.gentity_get(cmdClient, "pers.netname"), + ["cleanname"] = et.gentity_get(cmdClient, "pers.netname"):gsub("%^[^^]", ""), + ["codedsname"] = et.gentity_get(cmdClient, "pers.netname"):gsub("%^([^^])", "^^2%1"), + ["slot"] = cmdClient, + ["team"] = et.gentity_get(cmdClient, "sess.sessionTeam"), + ["class"] = et.gentity_get(cmdClient, "sess.playerType"), + ["health"] = et.gentity_get(cmdClient, "ps.stats"), -- -10 = ungibbed, -30 = gibbed + ["kills"] = et.gentity_get(cmdClient, "sess.kills"), + ["teamkills"] = et.gentity_get(cmdClient, "sess.team_kills"), + ["totalkills"] = et.gentity_get(cmdClient, "sess.kills") + et.gentity_get(cmdClient, "sess.team_kills"), + ["damage"] = et.gentity_get(cmdClient, "sess.damage_given"), + ["damagereceived"] = et.gentity_get(cmdClient, "sess.damage_received"), + ["teamdamage"] = et.gentity_get(cmdClient, "sess.team_damage"), + -- ["teamdamagereceived"] = et.gentity_get(cmdClient, "sess.team_received"), -- ETPro only + ["totaldamage"] = et.gentity_get(cmdClient, "sess.damage_given") + et.gentity_get(cmdClient, "sess.team_damage"), + ["deaths"] = et.gentity_get(cmdClient, "sess.deaths"), + ["suicides"] = et.gentity_get(cmdClient, "sess.suicides") + } + + if stats["totalkills"] == 0 then stats["totalkills"] = 1 end + if stats["totaldamage"] == 0 then stats["totaldamage"] = 1 end + + --[[ for key, value in pairs(stats) do + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dstats: ^9"..string.format("%-15s", key..":").." ^7"..value.."\";") + end ]] + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dStatistics for ^7"..stats["name"].."^d:\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dName: ^2"..stats["cleanname"].." ("..stats["codedsname"]..")\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dSlot: ^2"..stats["slot"]..(stats["slot"] < tonumber(et.trap_Cvar_Get("sv_privateClients")) and " ^9(private)" or "").."\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dTeam: ^2"..util.getTeamName(stats["team"]).."\";") + + if stats["team"] ~= et.TEAM_SPECTATORS then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dClass: ^2"..util.getClassName(stats["class"]).."\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dHealth: ^2"..(stats["health"] < 0 and "dead" or stats["health"]).."\";") + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dKills: ^2"..string.format("%-8s", stats["kills"]).." ^dTeam kills: ^2"..stats["teamkills"].." ^9("..string.format("%0.2f", (stats["teamkills"] / (stats["totalkills"] or 1) * 100)).." percent)\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dDamage: ^2"..string.format("%-8s", stats["damage"]).." ^dTeam damage: ^2"..stats["teamdamage"].." ^9("..string.format("%0.2f", (stats["teamdamage"] / (stats["totaldamage"] or 1) * 100)).." percent)\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dDeaths: ^2"..string.format("%-8s", stats["deaths"]).." ^dSuicides: ^2"..stats["suicides"].."\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dK/D: ^2"..string.format("%0.2f", (stats["kills"] / ((stats["deaths"] > 0) and stats["deaths"] or 1))).."\";") + + -- NQ 1.3.0 and higher + --[[ for key, value in ipairs(stats["weapstats"]) do + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dstats: ^9"..stats["weapstats"].."\";") + end ]] + + -- NQ 1.3.0 and higher + --[[ local weapstats = et.gentity_get(cmdClient, "sess.aWeaponStats", WP_THOMPSON) + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dstats: ^9"..weapstats.."\";") ]] + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \"^dstats: ^9stats for ^7"..stats["name"].." ^9were printed to the console.\";") + + return true +end +commands.register("stats", commandShowStats, "I", "display the statistics for a specific player", "^9[^3name|slot#^9]") \ No newline at end of file diff --git a/luascripts/commands/vmute.lua b/luascripts/commands/vmute.lua new file mode 100644 index 0000000..db47fb6 --- /dev/null +++ b/luascripts/commands/vmute.lua @@ -0,0 +1,78 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local commands = require "luascripts.wolfadmin.commands" +local admin = require "luascripts.wolfadmin.admin.admin" + +function commandVoiceMute(clientId, cmdArguments) + if cmdArguments[1] == nil then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvmute usage: "..commands.get("vmute")["syntax"].."\";") + + return true + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvmute: ^9no or multiple matches for '^7"..cmdArguments[1].."^9'.\";") + + return true + elseif not et.gentity_get(cmdClient, "pers.netname") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvmute: ^9no connected player by that name or slot #\";") + + return true + end + + local vmuteTime, vmuteReason = 600, "muted by admin" + + if cmdArguments[2] and util.getTimeFromString(cmdArguments[2]) and cmdArguments[3] then + vmuteTime = util.getTimeFromString(cmdArguments[2]) + vmuteReason = table.concat(cmdArguments, " ", 3) + elseif cmdArguments[2] and util.getTimeFromString(cmdArguments[2]) then + vmuteTime = util.getTimeFromString(cmdArguments[2]) + elseif cmdArguments[2] then + vmuteReason = table.concat(cmdArguments, " ", 2) + elseif et.G_shrubbot_permission(clientId, "8") ~= 1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvmute usage: "..commands.get("vmute")["syntax"].."\";") + + return true + end + + if admin.isVoiceMuted(cmdClient) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvmute: ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9is already muted.\";") + + return true + elseif et.G_shrubbot_permission(cmdClient, "!") == 1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvmute: ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9is immune to this command.\";") + + return true + elseif et.G_shrubbot_level(cmdClient) > et.G_shrubbot_level(clientId) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvmute: ^9sorry, but your intended victim has a higher admin level than you do.\";") + + return true + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dvmute: ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9has been voicemuted for "..vmuteTime.." seconds\";") + + admin.muteVoice(cmdClient, os.time() + vmuteTime) + + return true +end +commands.register("vmute", commandVoiceMute, "m", "voicemutes a player", "^9[^3name|slot#^9]") \ No newline at end of file diff --git a/luascripts/commands/vunmute.lua b/luascripts/commands/vunmute.lua new file mode 100644 index 0000000..e6b5dbc --- /dev/null +++ b/luascripts/commands/vunmute.lua @@ -0,0 +1,54 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local commands = require "luascripts.wolfadmin.commands" +local admin = require "luascripts.wolfadmin.admin.admin" + +function commandVoiceUnmute(clientId, cmdArguments) + if cmdArguments[1] == nil then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvunmute usage: "..commands.get("vunmute")["syntax"].."\";") + + return true + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvunmute: ^9no or multiple matches for '^7"..cmdArguments[1].."^9'.\";") + + return true + elseif not et.gentity_get(cmdClient, "pers.netname") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvunmute: ^9no connected player by that name or slot #\";") + + return true + end + + if not admin.isVoiceMuted(cmdClient) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dvunmute: ^9no player by that name or slot # is voicemuted\";") + + return true + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dvunmute: ^7"..et.gentity_get(cmdClient, "pers.netname").." ^9has been unvoicemuted\";") + + admin.unmuteVoice(cmdClient) + + return true +end +commands.register("vunmute", commandVoiceUnmute, "m", "unvoicemutes a player", "^9[^3name|slot#^9]") \ No newline at end of file diff --git a/luascripts/commands/warn.lua b/luascripts/commands/warn.lua new file mode 100644 index 0000000..bf83f04 --- /dev/null +++ b/luascripts/commands/warn.lua @@ -0,0 +1,43 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local settings = require "luascripts.wolfadmin.util.settings" +local commands = require "luascripts.wolfadmin.commands" +local warns = require "luascripts.wolfadmin.admin.warns" + +function commandAddWarn(clientId, cmdArguments) + if settings.get("g_warnHistory") == 0 then + return false + elseif #cmdArguments < 2 then + return false + elseif tonumber(cmdArguments[1]) == nil then + cmdClient = et.ClientNumberFromString(cmdArguments[1]) + else + cmdClient = tonumber(cmdArguments[1]) + end + + if cmdClient == -1 then + return false + elseif not et.gentity_get(cmdClient, "pers.netname") then + return false + end + + warns.add(cmdClient, table.concat(cmdArguments, " ", 2), clientId, os.time()) + + return false +end +commands.register("warn", commandAddWarn, "R", "warns a player by displaying the reason", "^9[^3name|slot#^9] ^9[^3reason^9]", true) \ No newline at end of file diff --git a/luascripts/db/cfg.lua b/luascripts/db/cfg.lua new file mode 100644 index 0000000..37f0a07 --- /dev/null +++ b/luascripts/db/cfg.lua @@ -0,0 +1,201 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local files = require "luascripts.wolfadmin.util.files" +local settings = require "luascripts.wolfadmin.util.settings" + +local stats = require "luascripts.wolfadmin.players.stats" + +local cfg = {} + +local maps = {} +local records = {} + +function cfg.addmap(mapname, lastplayed) + table.insert(records, { + ["map"] = mapname, + }) +end + +function cfg.updatemap(mapid, lastplayed) +end + +function cfg.getmap(mapname) + for id, record in ipairs(records) do + if record["map"] == mapname then + return {["id"] = id} + end + end +end + +function cfg.addrecord(mapid, recorddate, recordtype, record, playerid) + cfg.updaterecord(mapid, recorddate, recordtype, record, playerid) +end + +function cfg.updaterecord(mapid, recorddate, recordtype, record, playerid) + local typestr = "" + if recordtype == constants.RECORD_KILL then + typestr = "ks" + elseif recordtype == constants.RECORD_DEATH then + typestr = "ds" + elseif recordtype == constants.RECORD_REVIVE then + typestr = "rs" + end + + records[mapid][typestr.."record"] = record + records[mapid][typestr.."name"] = playerid +end + +function cfg.removerecords(mapid) + records[mapid] = { + ["map"] = records[mapid]["map"], + } +end + +function cfg.getrecords(mapid) + return records[mapid] +end + +function cfg.getrecordscount(mapid) + return #records +end + +function cfg.getrecord(mapid, recordtype) + local row = records[mapid] + + if row then + local record, typestr = {}, "" + + if recordtype == constants.RECORD_KILL then + typestr = "ks" + elseif recordtype == constants.RECORD_DEATH then + typestr = "ds" + elseif recordtype == constants.RECORD_REVIVE then + typestr = "rs" + end + + if not record[typestr.."player"] then return end + + record[typestr.."player"] = tonumber(row["player"]) + record[typestr.."record"] = tonumber(row["record"]) + + return record + end +end + +function cfg.addplayer(guid, ip) +end + +function cfg.updateplayer(guid, ip) +end + +function cfg.getplayerid(clientid) + if type(clientid) == "number" then + return stats.get(clientid, "playerName") + end + + return clientid +end + +function mysql.isplayerbot(clientid) + return string.match(stats.get(clientid, "playerGUID"), 'OMNIBOT%d%d%d+') +end + +function cfg.getplayer(guid) +end + +function cfg.addalias(playerid, alias, lastused) +end + +function cfg.updatealias(aliasid, lastused) +end + +function cfg.getaliases(playerid) +end + +function cfg.getaliasbyid(aliasid) +end + +function cfg.getaliasbyname(playerid, aliasname) +end + +function cfg.getlastalias(playerid) + return {["alias"] = playerid} +end + +function cfg.addsetlevel(playerid, level, adminid, datetime) +end + +function cfg.getlevels(playerid) +end + +function cfg.addwarn(playerid, reason, adminid, datetime) +end + +function cfg.removewarn(warnid) +end + +function cfg.getwarns(playerid) +end + +function cfg.getwarn(warnid) +end + +function cfg.isconnected() +end + +function cfg.start() + local fileName = settings.get("g_fileSprees") + + if fileName == "" then + return + end + + local amount, array = files.loadCFG(fileName, "record", true) + records = array["record"] or {} + + for id, record in ipairs(records) do + record["ksrecord"] = tonumber(record["ksrecord"]) + record["dsrecord"] = tonumber(record["dsrecord"]) + record["rsrecord"] = tonumber(record["rsrecord"]) + end +end + +function cfg.close(doSave) + -- in case of a map restart for example + if not doSave then return end + + local fileName = settings.get("g_fileSprees") + + if fileName == "" then + return true + end + + local array = {["record"] = {}} + + -- add back the indices we removed + for _, record in ipairs(records) do + table.insert(array["record"], record) + end + + files.save(fileName, array) +end + +return cfg \ No newline at end of file diff --git a/luascripts/db/db.lua b/luascripts/db/db.lua new file mode 100644 index 0000000..691409c --- /dev/null +++ b/luascripts/db/db.lua @@ -0,0 +1,47 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local settings = require "luascripts.wolfadmin.util.settings" + +local db = {} + +local con + +-- as this module serves as a wrapper/super class, we load the selected database +-- system in this function. might have to think of a better way to implement +-- this, but it will suffice. +function db.oninit() + if settings.get("db_type") == "mysql" and settings.get("db_username") ~= "" then + con = require "luascripts.wolfadmin.db.mysql" + else + con = require "luascripts.wolfadmin.db.cfg" + end + + setmetatable(db, {__index = con}) + + db.start() +end +events.handle("onGameInit", db.oninit) + +function db.onshutdown(restartMap) + db.close(not restartMap) +end +events.handle("onGameShutdown", db.onshutdown) + +return db \ No newline at end of file diff --git a/luascripts/db/mysql.lua b/luascripts/db/mysql.lua new file mode 100644 index 0000000..8aa418f --- /dev/null +++ b/luascripts/db/mysql.lua @@ -0,0 +1,259 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local settings = require "luascripts.wolfadmin.util.settings" + +local stats = require "luascripts.wolfadmin.players.stats" + +require "luasql.mysql" + +local mysql = {} + +local env = assert(luasql.mysql()) +local con = nil +local cur = nil + +function mysql.addmap(mapname, lastplayed) + cur = assert(con:execute("INSERT INTO `maps` (`name`, `lastplayed`) VALUES ('"..util.escape(mapname).."', "..tonumber(lastplayed)..")")) +end + +function mysql.updatemap(mapid, lastplayed) + cur = assert(con:execute("UPDATE `maps` SET `lastplayed`="..tonumber(lastplayed).." WHERE `id`="..tonumber(mapid).."")) +end + +function mysql.getmap(mapname) + cur = assert(con:execute("SELECT * FROM `maps` WHERE `name`='"..util.escape(mapname).."'")) + + local map = cur:fetch({}, "a") + cur:close() + + return map +end + +function mysql.addrecord(mapid, recorddate, recordtype, record, playerid) + cur = assert(con:execute("INSERT INTO `records` (`mapid`, `date`, `type`, `record`, `player`) VALUES ("..tonumber(mapid)..", "..tonumber(recorddate)..", "..tonumber(recordtype)..", "..tonumber(record)..", "..tonumber(playerid)..")")) +end + +function mysql.updaterecord(mapid, recorddate, recordtype, record, playerid) + cur = assert(con:execute("UPDATE `records` SET `date`="..tonumber(recorddate)..", `record`="..tonumber(record)..", `player`="..tonumber(playerid).." WHERE `mapid`="..tonumber(mapid).." AND `type`="..tonumber(recordtype).."")) +end + +function mysql.removerecords(mapid) + cur = assert(con:execute("DELETE FROM `records` WHERE `mapid`="..tonumber(mapid).."")) +end + +function mysql.getrecords(mapid) + cur = assert(con:execute("SELECT * FROM `records` WHERE `mapid`="..tonumber(mapid).."")) + local numrows = cur:numrows() + local records = {} + + for i = 1, numrows do + local record = cur:fetch({}, "a") + local typestr = "" + + if tonumber(record["type"]) == constants.RECORD_KILL then + typestr = "ks" + elseif tonumber(record["type"]) == constants.RECORD_DEATH then + typestr = "ds" + elseif tonumber(record["type"]) == constants.RECORD_REVIVE then + typestr = "rs" + end + + records[typestr.."player"] = tonumber(record["player"]) + records[typestr.."record"] = tonumber(record["record"]) + end + + cur:close() + + return records +end + +function mysql.getrecordscount(mapid) + cur = assert(con:execute("SELECT COUNT(*) AS `count` FROM `records` WHERE `mapid`="..tonumber(mapid).."")) + + local count = cur:fetch({}, "a") + cur:close() + + return count["count"] +end + +function mysql.getrecord(mapid, recordtype) + cur = assert(con:execute("SELECT * FROM `records` WHERE `mapid`="..tonumber(mapid).." AND `type`="..tonumber(recordtype).."")) + + local row = cur:fetch({}, "a") + cur:close() + + if row then + local record, typestr = {}, "" + + if tonumber(row["type"]) == constants.RECORD_KILL then + typestr = "ks" + elseif tonumber(row["type"]) == constants.RECORD_DEATH then + typestr = "ds" + elseif tonumber(row["type"]) == constants.RECORD_REVIVE then + typestr = "rs" + end + + record[typestr.."player"] = tonumber(row["player"]) + record[typestr.."record"] = tonumber(row["record"]) + + return record + end +end + +function mysql.addplayer(guid, ip) + cur = assert(con:execute("INSERT INTO `players` (`guid`, `ip`) VALUES ('"..util.escape(guid).."', '"..util.escape(ip).."')")) +end + +function mysql.updateplayer(guid, ip) + cur = assert(con:execute("UPDATE `players` SET `ip`='"..util.escape(ip).."' WHERE `guid`='"..util.escape(guid).."'")) +end + +function mysql.getplayerid(clientid) + return mysql.getplayer(stats.get(clientid, "playerGUID"))["id"] +end + +function mysql.isplayerbot(clientid) + return mysql.getplayer(stats.get(clientid, "playerGUID"))["bot"] == 1 +end + +function mysql.getplayer(guid) + cur = assert(con:execute("SELECT * FROM `players` WHERE `guid`='"..util.escape(guid).."'")) + + local player = cur:fetch({}, "a") + cur:close() + + return player +end + +function mysql.addalias(playerid, alias, lastused) + cur = assert(con:execute("INSERT INTO `aliases` (`player`, `alias`, `cleanalias`, `lastused`, `used`) VALUES ("..tonumber(playerid)..", '"..util.escape(alias).."', '"..util.escape(util.removeColors(alias)).."', "..tonumber(lastused)..", 1)")) +end + +function mysql.updatecleanalias(aliasid, alias) + cur = assert(con:execute("UPDATE `aliases` SET `cleanalias`='"..util.escape(util.removeColors(alias)).."' WHERE `id`='"..util.escape(aliasid).."'")) +end + +function mysql.updatealias(aliasid, lastused) + cur = assert(con:execute("UPDATE `aliases` SET `lastused`="..tonumber(lastused)..", `used`=`used`+1 WHERE `id`='"..util.escape(aliasid).."'")) +end + +function mysql.getaliases(playerid) + cur = assert(con:execute("SELECT * FROM `aliases` WHERE `player`="..tonumber(playerid).." ORDER BY `used` DESC")) + local numrows = cur:numrows() + local aliases = {} + + for i = 1, numrows do + aliases[i] = cur:fetch({}, "a") + end + + cur:close() + + return aliases +end + +function mysql.getaliasbyid(aliasid) + cur = assert(con:execute("SELECT * FROM `aliases` WHERE `id`="..tonumber(aliasid).."")) + + local alias = cur:fetch({}, "a") + cur:close() + + return alias +end + +function mysql.getaliasbyname(playerid, aliasname) + cur = assert(con:execute("SELECT * FROM `aliases` WHERE `player`="..tonumber(playerid).." AND `alias`='"..util.escape(aliasname).."'")) + + local alias = cur:fetch({}, "a") + cur:close() + + return alias +end + +function mysql.getlastalias(playerid) + cur = assert(con:execute("SELECT * FROM `aliases` WHERE `player`="..tonumber(playerid).." ORDER BY `lastused` DESC LIMIT 1")) + + local alias = cur:fetch({}, "a") + cur:close() + + return alias +end + +function mysql.addsetlevel(playerid, level, adminid, datetime) + cur = assert(con:execute("INSERT INTO `levels` (`player`, `level`, `admin`, `datetime`) VALUES ("..tonumber(playerid)..", "..tonumber(level)..", "..tonumber(adminid)..", "..tonumber(datetime)..")")) +end + +function mysql.getlevels(playerid) + cur = assert(con:execute("SELECT * FROM `levels` WHERE `player`="..tonumber(playerid).."")) + local numrows = cur:numrows() + local levels = {} + + for i = 1, numrows do + levels[i] = cur:fetch({}, "a") + end + + cur:close() + + return levels +end + +function mysql.addwarn(playerid, reason, adminid, datetime) + cur = assert(con:execute("INSERT INTO `warns` (`player`, `reason`, `admin`, `datetime`) VALUES ("..tonumber(playerid)..", '"..util.escape(reason).."', "..tonumber(adminid)..", "..tonumber(datetime)..")")) +end + +function mysql.removewarn(warnid) + cur = assert(con:execute("DELETE FROM `warns` WHERE `id`="..tonumber(warnid).."")) +end + +function mysql.getwarns(playerid) + cur = assert(con:execute("SELECT * FROM `warns` WHERE `player`="..tonumber(playerid).."")) + local numrows = cur:numrows() + local warns = {} + + for i = 1, numrows do + warns[i] = cur:fetch({}, "a") + end + + cur:close() + + return warns +end + +function mysql.getwarn(warnid) + cur = assert(con:execute("SELECT * FROM `warns` WHERE `id`="..tonumber(warnid).."")) + + local warn = cur:fetch({}, "a") + cur:close() + + return warn +end + +function mysql.isconnected() + return (con ~= nil) +end + +function mysql.start() + con = assert(env:connect(settings.get("db_database"), settings.get("db_username"), settings.get("db_password"), settings.get("db_hostname"), settings.get("db_port"))) +end + +function mysql.close(doSave) +end + +return mysql \ No newline at end of file diff --git a/luascripts/game/bots.lua b/luascripts/game/bots.lua new file mode 100644 index 0000000..810c19b --- /dev/null +++ b/luascripts/game/bots.lua @@ -0,0 +1,54 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local settings = require "luascripts.wolfadmin.util.settings" +local stats = require "luascripts.wolfadmin.players.stats" + +local bots = {} + +function bots.is(clientId) + return stats.get(clientId, "isBot") +end + +function bots.put(team) + local team = util.getTeamCode(team) + + for playerId = 0, et.trap_Cvar_Get("sv_maxclients") - 1 do + if wolfa_isPlayer(playerId) and bots.is(playerId) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "!put "..playerId.." "..team..";") + end + end +end + +function bots.enable(enable) + if enable then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "bot minbots -1;") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "bot maxbots "..settings.get("omnibot_maxbots")..";") + else + et.trap_SendConsoleCommand(et.EXEC_APPEND, "bot minbots -1;") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "bot maxbots -1;") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "bot kickall;") + end +end + +function bots.oninit(levelTime, randomSeed, restartMap) +end +events.handle("onGameInit", bots.oninit) + +return bots \ No newline at end of file diff --git a/luascripts/game/game.lua b/luascripts/game/game.lua new file mode 100644 index 0000000..a41bb8e --- /dev/null +++ b/luascripts/game/game.lua @@ -0,0 +1,114 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local settings = require "luascripts.wolfadmin.util.settings" +local stats = require "luascripts.wolfadmin.players.stats" + +local game = {} + +local killCount = 0 +local lastKillerId = nil + +local currentState = nil +local currentMaps, currentMap, nextMap = {}, nil, nil + +function game.getState() + return currentState +end + +function game.getMode() + return tonumber(et.trap_Cvar_Get("g_gametype")) +end + +function game.getMaps() + return currentMaps +end + +function game.getMap() + return currentMap +end + +function game.getNextMap() + return nextMap +end + +function game.oninit() + local gameType = game.getMode() -- 2: objective, 3: stopwatch, 4: campaign, 5: LMS + local campaignMaps = tostring(et.trap_Cvar_Get("campaign_maps")) + local objectiveMaps = tostring(et.trap_Cvar_Get("objective_maps")) + + if gameType == 4 then + currentMaps = util.split(campaignMaps, ",") + else + currentMaps = util.split(objectiveMaps, ",") + end + + currentMap = et.trap_Cvar_Get("mapname") + + for i, map in ipairs(currentMaps) do + if map == game.getMap() then nextMap = currentMaps[i + 1] break end + end + + nextMap = nextMap and nextMap or "unknown" +end +events.handle("onGameInit", game.oninit) + +function game.onstatechange(gameState) + currentState = gameState + + if gameState == 3 then + -- do not display when there haven't been any kills + if lastKillerId ~= nil then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dAnd the last kill of the round goes to.. ^7"..et.gentity_get(lastKillerId, "pers.netname").."^d!\";") + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dA total of ^7"..killCount.." ^dsoldiers died during this battle.\";") + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dNext map: ^7"..game.getNextMap().."^d.\";") + end +end +events.handle("onGameStateChange", game.onstatechange) + +function game.ondeath(victimId, killerId, mod) + if killerId ~= 1022 and victimId ~= killerId then -- regular kills + lastKillerId = killerId + end + + killCount = killCount + 1 +end +events.handle("onPlayerDeath", game.ondeath) + +function game.onrevive(clientMedic, clientVictim) + if settings.get("g_announceRevives") ~= 0 then + for playerId = 0, et.trap_Cvar_Get("sv_maxclients") - 1 do + if wolfa_isPlayer(playerId) and tonumber(et.gentity_get(playerId, "sess.sessionTeam")) == tonumber(et.gentity_get(clientMedic, "sess.sessionTeam")) then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..playerId.." \"^drevive: ^7"..et.gentity_get(clientMedic, "pers.netname").." ^9revived ^7"..et.gentity_get(clientVictim, "pers.netname").."^9.\";") + end + end + end +end +events.handle("onPlayerRevive", game.onrevive) + +function game.onbegin(clientId, firstTime) + if firstTime and settings.get("g_welcomeMessage") ~= "" then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "cchat "..clientId.." \""..settings.get("g_welcomeMessage").."\";") + end +end +events.handle("onClientBegin", game.onbegin) + +return game \ No newline at end of file diff --git a/luascripts/game/sprees.lua b/luascripts/game/sprees.lua new file mode 100644 index 0000000..b74003a --- /dev/null +++ b/luascripts/game/sprees.lua @@ -0,0 +1,209 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local events = require "luascripts.wolfadmin.util.events" +local settings = require "luascripts.wolfadmin.util.settings" +local files = require "luascripts.wolfadmin.util.files" +local db = require "luascripts.wolfadmin.db.db" +local game = require "luascripts.wolfadmin.game.game" +local stats = require "luascripts.wolfadmin.players.stats" + +local sprees = {} + +local revivespreeMessages = { + [3] = { + ["msg"] = "^dis on a ^2revive spree^d!", + ["sound"] = "", + }, + [5] = { + ["msg"] = "^dis a ^2revive magnet^d!", + ["sound"] = "", + }, + [10] = { + ["msg"] = "^dis a ^2syringe maniac^d!", + ["sound"] = "", + }, + [15] = { + ["msg"] = "^dis the new ^2Dr. Frankenstein^d!", + ["sound"] = "", + }, +} + +local currentRecords -- cached version +local currentMapId + +function sprees.get() + local records = currentRecords + + if records["ksrecord"] and records["ksrecord"] > 0 then + records["ksname"] = db.getlastalias(records["ksplayer"])["alias"] + end + if records["dsrecord"] and records["dsrecord"] > 0 then + records["dsname"] = db.getlastalias(records["dsplayer"])["alias"] + end + if records["rsrecord"] and records["rsrecord"] > 0 then + records["rsname"] = db.getlastalias(records["rsplayer"])["alias"] + end + + return records +end + +function sprees.reset() + db.removerecords(currentMapId) + + currentRecords = db.getrecords(currentMapId) +end + +function sprees.load() + local map = db.getmap(game.getMap()) + + if map then + currentMapId = map["id"] + db.updatemap(currentMapId, os.time()) + else + db.addmap(game.getMap(), os.time()) + currentMapId = db.getmap(game.getMap())["id"] + end + + currentRecords = db.getrecords(currentMapId) + + return db.getrecordscount(currentMapId) +end + +function sprees.oninit(levelTime, randomSeed, restartMap) + if (settings.get("db_type") == "cfg" and settings.get("g_fileSprees") ~= "") or (settings.get("db_type") ~= "cfg" and settings.get("g_spreeRecords") ~= 0) then + sprees.load() + + events.handle("onGameStateChange", sprees.ongamestatechange) + events.handle("onPlayerDeath", sprees.ondeath) + events.handle("onPlayerRevive", sprees.onrevive) + end +end +events.handle("onGameInit", sprees.oninit) + +function sprees.onconnect(clientId, firstTime, isBot) + stats.set(clientId, "currentKillSpree", 0) + stats.set(clientId, "longestKillSpree", 0) + stats.set(clientId, "currentDeathSpree", 0) + stats.set(clientId, "longestDeathSpree", 0) + stats.set(clientId, "currentReviveSpree", 0) + stats.set(clientId, "longestReviveSpree", 0) +end +events.handle("onClientConnect", sprees.onconnect) + +function sprees.ongamestatechange(gameState) + if gameState == 3 then + if currentRecords["ksrecord"] and currentRecords["ksrecord"] > 0 then + if db.getrecord(currentMapId, constants.RECORD_KILL) then + db.updaterecord(currentMapId, os.time(), constants.RECORD_KILL, currentRecords["ksrecord"], currentRecords["ksplayer"]) + else + db.addrecord(currentMapId, os.time(), constants.RECORD_KILL, currentRecords["ksrecord"], currentRecords["ksplayer"]) + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dsprees: ^9longest kill spree (^7"..currentRecords["ksrecord"].."^9) by ^7"..db.getlastalias(currentRecords["ksplayer"])["alias"].."^9.\";") + end + if currentRecords["dsrecord"] and currentRecords["dsrecord"] > 0 then + if db.getrecord(currentMapId, constants.RECORD_DEATH) then + db.updaterecord(currentMapId, os.time(), constants.RECORD_DEATH, currentRecords["dsrecord"], currentRecords["dsplayer"]) + else + db.addrecord(currentMapId, os.time(), constants.RECORD_DEATH, currentRecords["dsrecord"], currentRecords["dsplayer"]) + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dsprees: ^9longest death spree (^7"..currentRecords["dsrecord"].."^9) by ^7"..db.getlastalias(currentRecords["dsplayer"])["alias"].."^9.\";") + end + if currentRecords["rsrecord"] and currentRecords["rsrecord"] > 0 then + if db.getrecord(currentMapId, constants.RECORD_REVIVE) then + db.updaterecord(currentMapId, os.time(), constants.RECORD_REVIVE, currentRecords["rsrecord"], currentRecords["rsplayer"]) + else + db.addrecord(currentMapId, os.time(), constants.RECORD_REVIVE, currentRecords["rsrecord"], currentRecords["rsplayer"]) + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dsprees: ^9longest revive spree (^7"..currentRecords["rsrecord"].."^9) by ^7"..db.getlastalias(currentRecords["rsplayer"])["alias"].."^9.\";") + end + end +end + +function sprees.ondeath(victimId, killerId, mod) + if killerId == 1022 then -- killed by map + stats.set(victimId, "currentKillSpree", 0) + stats.add(victimId, "currentDeathSpree", 1) + stats.set(victimId, "currentReviveSpree", 0) + + stats.set(victimId, "longestDeathSpree", stats.get(victimId, "currentDeathSpree") > stats.get(victimId, "longestDeathSpree") and stats.get(victimId, "currentDeathSpree") or stats.get(victimId, "longestDeathSpree")) + elseif victimId == killerId then -- suicides + -- happens when a bot disconnects, it selfkills before leaving, thus emptying the + -- player data table, resulting in errors. I'm sorry for your spree records, bots. + if not wolfa_isPlayer(victimId) then return end + + stats.set(victimId, "currentKillSpree", 0) + stats.add(victimId, "currentDeathSpree", 1) + stats.set(victimId, "currentReviveSpree", 0) + + stats.set(victimId, "longestDeathSpree", stats.get(victimId, "currentDeathSpree") > stats.get(victimId, "longestDeathSpree") and stats.get(victimId, "currentDeathSpree") or stats.get(victimId, "longestDeathSpree")) + + if (settings.get("g_botRecords") == 1 or not db.isplayerbot(victimId)) and (not currentRecords["dsrecord"] or stats.get(victimId, "longestDeathSpree") > currentRecords["dsrecord"]) then + currentRecords["dsplayer"] = db.getplayerid(victimId) + currentRecords["dsrecord"] = stats.get(victimId, "longestDeathSpree") + end + else -- regular kills + if et.gentity_get(victimId, "sess.sessionTeam") == et.gentity_get(killerId, "sess.sessionTeam") then + -- teamkill handling + else + stats.add(killerId, "currentKillSpree", 1) + stats.set(killerId, "currentDeathSpree", 0) + + stats.set(killerId, "longestKillSpree", stats.get(killerId, "currentKillSpree") > stats.get(killerId, "longestKillSpree") and stats.get(killerId, "currentKillSpree") or stats.get(killerId, "longestKillSpree")) + + if (settings.get("g_botRecords") == 1 or not db.isplayerbot(killerId)) and (not currentRecords["ksrecord"] or stats.get(killerId, "longestKillSpree") > currentRecords["ksrecord"]) then + currentRecords["ksplayer"] = db.getplayerid(killerId) + currentRecords["ksrecord"] = stats.get(killerId, "longestKillSpree") + end + + -- happens when a bot disconnects, it selfkills before leaving, thus emptying the + -- player data table, resulting in errors. I'm sorry for your spree records, bots. + if not wolfa_isPlayer(victimId) then return end + + stats.set(victimId, "currentKillSpree", 0) + stats.add(victimId, "currentDeathSpree", 1) + stats.set(victimId, "currentReviveSpree", 0) + + stats.set(victimId, "longestDeathSpree", stats.get(victimId, "currentDeathSpree") > stats.get(victimId, "longestDeathSpree") and stats.get(victimId, "currentDeathSpree") or stats.get(victimId, "longestDeathSpree")) + + if (settings.get("g_botRecords") == 1 or not db.isplayerbot(victimId)) and (not currentRecords["dsrecord"] or stats.get(victimId, "longestDeathSpree") > currentRecords["dsrecord"]) then + currentRecords["dsplayer"] = db.getplayerid(victimId) + currentRecords["dsrecord"] = stats.get(victimId, "longestDeathSpree") + end + end + end +end + +function sprees.onrevive(clientMedic, clientVictim) + stats.add(clientMedic, "currentReviveSpree", 1) + stats.set(clientMedic, "longestReviveSpree", stats.get(clientMedic, "currentReviveSpree") > stats.get(clientMedic, "longestReviveSpree") and stats.get(clientMedic, "currentReviveSpree") or stats.get(clientMedic, "longestReviveSpree")) + + if revivespreeMessages[stats.get(clientMedic, "currentReviveSpree")] then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^1REVIVE SPREE! ^*"..stats.get(clientMedic, "playerName").." ^*"..revivespreeMessages[stats.get(clientMedic, "currentReviveSpree")]["msg"].." ^d(^3"..stats.get(clientMedic, "currentReviveSpree").." ^drevives in a row!)\";") + end + + if (settings.get("g_botRecords") == 1 or not db.isplayerbot(clientMedic)) and (not currentRecords["rsrecord"] or stats.get(clientMedic, "longestReviveSpree") > currentRecords["rsrecord"]) then + currentRecords["rsplayer"] = db.getplayerid(clientMedic) + currentRecords["rsrecord"] = stats.get(clientMedic, "longestReviveSpree") + end +end + +return sprees \ No newline at end of file diff --git a/luascripts/game/voting.lua b/luascripts/game/voting.lua new file mode 100644 index 0000000..19cdbac --- /dev/null +++ b/luascripts/game/voting.lua @@ -0,0 +1,139 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local timers = require "luascripts.wolfadmin.util.timers" +local settings = require "luascripts.wolfadmin.util.settings" +local bots = require "luascripts.wolfadmin.game.bots" + +local voting = {} + +local allowed = {} +local forced = {} +local restricted = {} + +function voting.allow(type, value) + allowed[type] = value + et.trap_Cvar_Set("vote_allow_"..type, value) +end + +function voting.isallowed(type) + return (allowed[type] == 1) +end + +function voting.force(type) + forced[type] = 1 + voting.allow(type, 1) +end + +function voting.isforced(type) + return (forced[type] == 1) +end + +function voting.isrestricted(type) + return (restricted[type] == 1) +end + +function voting.disablenextmap() + et.trap_SendConsoleCommand(et.EXEC_APPEND, "chat \"^dvote: ^9next map voting has automatically been disabled.\";") + + voting.allow("nextmap", 0) +end + +function voting.load() + for _, type in pairs(constants.VOTE_TYPES) do + allowed[type] = tonumber(et.trap_Cvar_Get("vote_allow_"..type)) + forced[type] = 0 + end + + local restrictedVotes = util.split(settings.get("g_restrictedVotes"), ",") + + for _, type in pairs(restrictedVotes) do + restricted[type] = 1 + end +end + +function voting.oninit(levelTime, randomSeed, restartMap) + voting.load() + + if settings.get("g_voteNextMapTimeout") > 0 then + voting.allow("nextmap", 1) + end +end +events.handle("onGameInit", voting.oninit) + +function voting.ongamestatechange(gameState) + if gameState == 0 and settings.get("g_voteNextMapTimeout") > 0 then + timers.add(voting.disablenextmap, settings.get("g_voteNextMapTimeout") * 1000, 1) + end +end +events.handle("onGameStateChange", voting.ongamestatechange) + +function voting.oncallvote(clientId, type, args) + if et.gentity_get(clientId, "sess.sessionTeam") == constants.TEAM_SPECTATORS or args[1] == "?" then + return 0 + elseif voting.isrestricted(type) and et.G_shrubbot_permission(clientId, "%") ~= 1 then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"callvote: you are not allowed to call this type of vote.\";") + et.trap_SendServerCommand(clientId, "cp \"You are not allowed to call this type of vote.") + + return 1 + end +end +events.handle("onCallvote", voting.oncallvote) + +function voting.onpollfinish(passed, poll) + if passed then + if poll == "enable bots" then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "needbots") + elseif poll == "disable bots" then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "kickbots") + elseif string.find(poll, "put bots") == 1 then + local team = string.sub(poll, 10) + + if team == "axis" then + team = constants.TEAM_AXIS_SC + elseif team == "allies" then + team = constants.TEAM_ALLIES_SC + else + return + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "putbots "..team) + elseif string.find(poll, "set bot difficulty") == 1 then + local difficulty = string.sub(poll, 20) + + if difficulty == "epic" then + difficulty = 6 + elseif difficulty == "hard" then + difficulty = 5 + elseif difficulty == "normal" then + difficulty = 4 + else + return + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "bot difficulty "..difficulty) + -- else + -- et.trap_SendConsoleCommand(et.EXEC_APPEND, command) + end + end +end +events.handle("onPollFinish", voting.onpollfinish) + +return voting \ No newline at end of file diff --git a/luascripts/license.txt b/luascripts/license.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/luascripts/license.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU 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. + + + Copyright (C) + + 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 . + +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: + + Copyright (C) + 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 +. + + 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 +. diff --git a/luascripts/main.lua b/luascripts/main.lua new file mode 100644 index 0000000..d9b2b21 --- /dev/null +++ b/luascripts/main.lua @@ -0,0 +1,159 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +require "luascripts.wolfadmin.util.debug" + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local timers = require "luascripts.wolfadmin.util.timers" +local settings = require "luascripts.wolfadmin.util.settings" + +local db = require "luascripts.wolfadmin.db.db" + +local admin = require "luascripts.wolfadmin.admin.admin" +local balancer = require "luascripts.wolfadmin.admin.balancer" +local rules = require "luascripts.wolfadmin.admin.rules" +local warns = require "luascripts.wolfadmin.admin.warns" + +local commands = require "luascripts.wolfadmin.commands" + +local game = require "luascripts.wolfadmin.game.game" +local bots = require "luascripts.wolfadmin.game.bots" +local sprees = require "luascripts.wolfadmin.game.sprees" +local voting = require "luascripts.wolfadmin.game.voting" + +local stats = require "luascripts.wolfadmin.players.stats" +local greetings = require "luascripts.wolfadmin.players.greetings" + +local version = "1.0.0" +local release = "25 January 2016" + +local basepath = nil + +-- game related data +local currentLevelTime = nil + +-- need to do this somewhere else +function wolfa_getLevelTime() + return currentLevelTime +end + +function wolfa_getVersion() + return version +end + +function wolfa_getRelease() + return release +end + +function wolfa_getBasePath() + return basepath +end + +function et_InitGame(levelTime, randomSeed, restartMap) + et.RegisterModname("WolfAdmin "..wolfa_getVersion()) + + outputDebug("Module "..wolfa_getVersion().." ("..wolfa_getRelease()..") loaded successfully. Created by Timo 'Timothy' Smit.") + + et.trap_SendConsoleCommand(et.EXEC_APPEND, "sets mod_wolfadmin "..wolfa_getVersion()..";") + + basepath = string.gsub(et.trap_Cvar_Get("fs_basepath"), "\\", "/").."/"..et.trap_Cvar_Get("fs_game").."/luascripts/wolfadmin/" + + if not (et.trap_Cvar_Get("fs_game") == "noquarter" or et.trap_Cvar_Get("fs_game") == "nq") then + outputDebug("Warning! Not running NoQuarter, this may cause bugs. Use at your own risk.") + end + + currentLevelTime = levelTime + + events.trigger("onGameInit", levelTime, randomSeed, (restartMap == 1)) +end + +function et_ShutdownGame(restartMap) + events.trigger("onGameShutdown", (restartMap == 1)) +end + +function et_ConsoleCommand(cmdText) + return events.trigger("onServerCommand", cmdText) +end + +function et_ClientConnect(clientId, firstTime, isBot) + if firstTime == 1 then + stats.set(clientId, "newConnection", true) + end + + return events.trigger("onClientConnect", clientId, (firstTime == 1), (isBot == 1)) +end + +function et_ClientBegin(clientId) + events.trigger("onClientBegin", clientId, stats.get(clientId, "newConnection")) + + stats.set(clientId, "newConnection", false) +end + +function et_ClientDisconnect(clientId) + events.trigger("onClientDisconnect", clientId) +end + +function et_ClientUserinfoChanged(clientId) + events.trigger("onClientInfoChange", clientId) +end + +function et_ClientCommand(clientId, cmdText) + return events.trigger("onClientCommand", clientId, cmdText) +end + +-- gameState +-- 0 - game (also when paused) +-- 1 - warmup +-- 2 - unknown +-- 3 - intermission +function et_RunFrame(levelTime) + local gameState = tonumber(et.trap_Cvar_Get("gamestate")) + + if game.getState() ~= gameState then + events.trigger("onGameStateChange", gameState) + end + + events.trigger("onGameFrame", levelTime) +end + +-- no callbacks defined for these things, so had to invent some special regexes +-- note for etlegacy team: please take a look at this, might come in handy :-) +function et_Print(consoleText) + local result, poll = string.match(consoleText, "^Vote (%w+): %[poll%] ([%w%s]+)\n$") + if result then + events.trigger("onPollFinish", (result == "Passed"), poll) + end + + local clientMedic, clientVictim = string.match(consoleText, "^Medic_Revive:%s+(%d+)%s+(%d+)\n$") + clientMedic = tonumber(clientMedic) + clientVictim = tonumber(clientVictim) + if clientMedic and clientVictim then + events.trigger("onPlayerRevive", clientMedic, clientVictim) + end +end + +function et_Obituary(victimId, killerId, mod) + events.trigger("onPlayerDeath", victimId, killerId, mod) +end + +function et_ClientSpawn(clientId, revived) + if revived == 0 then + events.trigger("onPlayerSpawn", clientId) + end +end diff --git a/luascripts/players/greetings.lua b/luascripts/players/greetings.lua new file mode 100644 index 0000000..c14dcd4 --- /dev/null +++ b/luascripts/players/greetings.lua @@ -0,0 +1,109 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" +local settings = require "luascripts.wolfadmin.util.settings" +local files = require "luascripts.wolfadmin.util.files" + +local stats = require "luascripts.wolfadmin.players.stats" + +local greetings = {} + +local userGreetings = {} +local levelGreetings = {} + +function greetings.get(clientId) + local lvl = et.G_shrubbot_level(clientId) + + if et.G_shrubbot_permission(clientId, "@") ~= 1 then + if userGreetings[stats.get(clientId, "playerGUID")] ~= nil then + return userGreetings[stats.get(clientId, "playerGUID")] + elseif levelGreetings[lvl] ~= nil then + return levelGreetings[lvl] + end + else + if levelGreetings[0] then + return levelGreetings[0] + end + end +end + +function greetings.show(clientId) + local greetingText = greetings.get(clientId) + + if greetingText then + local prefix = (util.getAreaName(settings.get("g_greetingArea")) ~= "cp") and "^dgreeting: ^9" or "^7" + local greeting = prefix..greetingText:gsub("%[N%]", et.gentity_get(clientId, "pers.netname")) + local out = "" + + while util.getAreaName(settings.get("g_greetingArea")) == "cp" and string.len(greeting) > constants.MAX_LENGTH_CP do + local sub = greeting:sub(1, constants.MAX_LENGTH_CP) + local rev = sub:reverse() + + local pos = rev:find(" [^^]") -- some epic smiley exclusion here + + if pos then + pos = constants.MAX_LENGTH_CP - pos + out = out..greeting:sub(1, pos).."\\n" + greeting = greeting:sub(pos + 2) + else + pos = sub:len() + out = out..greeting:sub(1, pos).."\\n" + greeting = greeting:sub(pos + 1) + end + end + + et.trap_SendConsoleCommand(et.EXEC_APPEND, util.getAreaName(settings.get("g_greetingArea")).." \""..out..greeting.."\";") + end +end + +function greetings.load() + local fileName = settings.get("g_fileGreetings") + + local amount, array = files.loadCFG(fileName, "[a-z]+", true) + + if amount == 0 then return 0 end + + for id, greeting in ipairs(array["level"]) do + levelGreetings[tonumber(greeting["level"])] = greeting["greeting"] + end + + for id, greeting in ipairs(array["user"]) do + userGreetings[greeting["guid"]] = greeting["greeting"] + end + + return amount +end + +function greetings.oninit(levelTime, randomSeed, restartMap) + if settings.get("g_fileGreetings") ~= "" then + greetings.load() + + events.handle("onClientBegin", greetings.onbegin) + end +end +events.handle("onGameInit", greetings.oninit) + +function greetings.onbegin(clientId, firstTime) + if firstTime and (not stats.get(clientId, "isBot") or settings.get("g_botGreetings") == 1) then + greetings.show(clientId) + end +end + +return greetings \ No newline at end of file diff --git a/luascripts/players/stats.lua b/luascripts/players/stats.lua new file mode 100644 index 0000000..c95c69a --- /dev/null +++ b/luascripts/players/stats.lua @@ -0,0 +1,97 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local events = require "luascripts.wolfadmin.util.events" + +local stats = {} + +local data = {[-1337] = {["playerGUID"] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}} + +-- TODO: need to check this in stat functions, apparently goes wrong +function wolfa_isPlayer(clientId) + if data[clientId] then + return true + end + + return false +end + +function stats.get(clientId, statKey) + -- if not wolfa_isPlayer(clientId) then return false end + + if statKey and type(statKey) == "string" and data[clientId] then + return data[clientId][statKey] + end + + return false +end + +function stats.set(clientId, statKey, statValue) + -- if not wolfa_isPlayer(clientId) then return false end + + if not data[clientId] then data[clientId] = {} end + + if statKey and type(statKey) == "string" then + data[clientId][statKey] = statValue + + return true + end + + return false +end + +function stats.add(clientId, statKey, statAdd) -- alias + statAdd = statAdd and statAdd or 1 + + return stats.set(clientId, statKey, stats.get(clientId, statKey) + statAdd) +end + +function stats.take(clientId, statKey, statTake) -- alias + statTake = statTake and statTake or 1 + + return stats.set(clientId, statKey, stats.get(clientId, statKey) - statTake) +end + +function stats.remove(clientId) + -- if not wolfa_isPlayer(clientId) then return false end + + data[clientId] = nil + + return true +end + +function stats.onconnect(clientId, firstTime, isBot) + local clientInfo = et.trap_GetUserinfo(clientId) + + -- name is NOT yet set in pers.netname, so get all info out of infostring + stats.set(clientId, "playerName", et.Info_ValueForKey(clientInfo, "name")) + stats.set(clientId, "playerGUID", et.Info_ValueForKey(clientInfo, "cl_guid")) + stats.set(clientId, "playerIP", string.gsub(et.Info_ValueForKey(clientInfo, "ip"), ":%d*", "")) + stats.set(clientId, "isBot", isBot) + + if firstTime then + stats.set(clientId, "voiceMute", false) + end +end +events.handle("onClientConnect", stats.onconnect) + +function stats.ondisconnect(clientId) + stats.remove(clientId) +end +events.handle("onClientDisconnect", stats.ondisconnect) + +return stats \ No newline at end of file diff --git a/luascripts/util/constants.lua b/luascripts/util/constants.lua new file mode 100644 index 0000000..645bdac --- /dev/null +++ b/luascripts/util/constants.lua @@ -0,0 +1,67 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = {} + +constants.COLOR_MAIN = "^7" + +constants.MAX_LENGTH_CP = 56 +constants.MAX_LENGTH_CVAR = 254 +constants.MAX_LENGTH_CONSOLE = 255 + +constants.TEAM_AXIS = 1 +constants.TEAM_ALLIES = 2 +constants.TEAM_SPECTATORS = 3 + +constants.TEAM_AXIS_SC = "r" +constants.TEAM_ALLIES_SC = "b" +constants.TEAM_SPECTATORS_SC = "s" + +constants.TEAM_AXIS_COLOR = "^1" +constants.TEAM_ALLIES_COLOR = "^4" +constants.TEAM_SPECTATORS_COLOR = "^2" + +constants.CLASS_SOLDIER = 0 +constants.CLASS_MEDIC = 1 +constants.CLASS_ENGINEER = 2 +constants.CLASS_FIELDOPS = 3 +constants.CLASS_COVERTOPS = 4 + +constants.SKILL_BATTLESENSE = 0 +constants.SKILL_ENGINEER = 1 +constants.SKILL_MEDIC = 2 +constants.SKILL_FIELDOPS = 3 +constants.SKILL_LIGHTWEAPONS = 4 +constants.SKILL_SOLDIER = 5 +constants.SKILL_COVERTOPS = 6 + +constants.AREA_CONSOLE = 0 +constants.AREA_POPUPS = 1 +constants.AREA_CHAT = 2 +constants.AREA_CP = 3 + +constants.VOTE_TYPES = { "antilag", "balancedteams", "comp", "friendlyfire", "gamconstantsype", "kick", + "map", "maprestart", "matchresconstants", "mutespecs", "muting", "nextcampaign", "nextmap", + "poll", "pub", "referee", "restartcampaign", "shufflconstantseamsxp", "shufflconstantseamsxp_norestart", + "surrender", "swapteams", "timelimit", "warmupdamage" +} + +constants.RECORD_KILL = 0 +constants.RECORD_DEATH = 1 +constants.RECORD_REVIVE = 2 + +return constants \ No newline at end of file diff --git a/luascripts/util/debug.lua b/luascripts/util/debug.lua new file mode 100644 index 0000000..651e6b0 --- /dev/null +++ b/luascripts/util/debug.lua @@ -0,0 +1,44 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" +local settings = require "luascripts.wolfadmin.util.settings" + +local SEVERITY_LEVELS = { + [1] = "^_", -- termination + [2] = "^1", -- error + [3] = "^8", -- warning + [4] = "^2", -- success + [5] = "^7", -- information +} + +local neededSeverity = 5 + +function outputDebug(msg, severity) + local severity = severity or 5 + + if severity <= neededSeverity then + et.G_Print("[WolfAdmin] "..msg.."\n") + + for playerId = 0, et.trap_Cvar_Get("sv_maxclients") - 1 do + if settings.get("g_debugWolfAdmin") ~= 0 and et.G_shrubbot_permission(playerId, "*") then + et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..playerId.." \"^:[WolfAdmin DEBUG] "..SEVERITY_LEVELS[severity]..msg.."\";") + end + end + end +end \ No newline at end of file diff --git a/luascripts/util/events.lua b/luascripts/util/events.lua new file mode 100644 index 0000000..7172a0d --- /dev/null +++ b/luascripts/util/events.lua @@ -0,0 +1,127 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" + +local events = {} + +local data = {} + +function events.get(name) + return data[name] +end + +function events.add(name) + if events.get(name) then + error("event is already added: "..name) + end + + data[name] = {} +end + +function events.ishandled(name, func) + if not events.get(name) then + error("event not added: "..name) + end + + local handlers = events.get(name) + + for i = 0, #handlers do + if handlers[i] == func then + return true + end + end + + return false +end + +function events.handle(name, func) + if not events.get(name) then + error("event not added: "..name) + end + + if events.ishandled(name, func) then + error("event "..name.." is already handled by this function") + end + + table.insert(data[name], func) +end + +function events.unhandle(name, func) + if not events.get(name) then + error("event not added: "..name) + end + + if not events.ishandled(name, func) then + error("event "..name.." is not handled by this function") + end + + local handlers = events.get(name) + + for i = 0, #handlers do + if handlers[i] == func then + table.remove(handlers, i) + end + end +end + +function events.trigger(name, ...) + local handlers = events.get(name) + + if not handlers then + error("event not added: "..name) + end + + local returnValue = nil + + for _, handler in pairs(handlers) do + local handlerReturn = handler(...) + + if not returnValue and returnValue ~= 0 and handlerReturn ~= nil then + returnValue = handlerReturn + end + end + + return returnValue +end + +events.add("onCallvote") +events.add("onPollStart") +events.add("onPollFinish") + +events.add("onClientConnect") +events.add("onClientDisconnect") +events.add("onClientBegin") +events.add("onClientCommand") +events.add("onClientInfoChange") +events.add("onClientNameChange") + +events.add("onGameInit") +events.add("onGameStateChange") +events.add("onGameFrame") +events.add("onGameShutdown") + +events.add("onPlayerSpawn") +events.add("onPlayerDeath") +events.add("onPlayerRevive") + +events.add("onPlayerSkillUpdate") + +events.add("onServerCommand") + +return events \ No newline at end of file diff --git a/luascripts/util/files.lua b/luascripts/util/files.lua new file mode 100644 index 0000000..fdd3adc --- /dev/null +++ b/luascripts/util/files.lua @@ -0,0 +1,136 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local settings = require "luascripts.wolfadmin.util.settings" + +local files = {} + +function files.ls(directory) + local platform, command = settings.get("sv_os"), "" + local entries = {} + + if platform == "unix" then + command = 'ls -1 "'..wolfa_getBasePath()..directory..'"' + elseif platform == "windows" then + command = 'dir "'..wolfa_getBasePath()..directory..'" /b' + end + + for filename in io.popen(command):lines() do + table.insert(entries, filename) + end + + return entries +end + +function files.create(fileName) + local fileDescriptor, fileLength = et.trap_FS_FOpenFile(fileName, et.FS_WRITE) + + return fileDescriptor, fileLength +end + +function files.open(fileName, fileMode, fileCreate) + local fileDescriptor, fileLength = et.trap_FS_FOpenFile(fileName, fileMode) + + if fileLength == -1 then + if not fileCreate then + error("failed to open "..fileName.."\n") + end + + fileDescriptor, fileLength = files.create(fileName) + end + + outputDebug("util.files.open(): file "..fileName.." opened") + + if fileMode == et.FS_READ then + local fileString = et.trap_FS_Read(fileDescriptor, fileLength) + + et.trap_FS_FCloseFile(fileDescriptor) + + return fileString + else + return fileDescriptor + end + + return false +end + +function files.loadCFG(fileName, idExpr, fileCreate) + local functionStart = et.trap_Milliseconds() + local fileString = files.open(fileName, et.FS_READ, fileCreate) + local arrayCount = 0 + local array = {} + + if not fileString then return 0, {} end + + local blockExpr = "%[("..idExpr..")%][\r\n]+(.-[\r\n]+)[\r\n]+" + local attrExpr = "([a-z0-9_]+) += +(.-)[\r\n]+" + + for id, values in string.gmatch(fileString, blockExpr) do + if not array[id] then array[id] = {} end + + local data = {} + + for k, v in string.gmatch(values, attrExpr) do + data[k] = v + end + + arrayCount = arrayCount + 1 + + table.insert(array[id], data) + end + + outputDebug("util.files.loadCFG(): "..arrayCount.." entries loaded in "..et.trap_Milliseconds() - functionStart.." ms") + + return arrayCount, array +end + +function files.save(fileName, array) + local functionStart = et.trap_Milliseconds() + local fileDescriptor = files.open(fileName, et.FS_WRITE) + local arrayCount = 0 + + for id, subdata in pairs(array) do + for _, data in pairs(subdata) do + local blockId = "["..id.."]\n" + et.trap_FS_Write(blockId, string.len(blockId), fileDescriptor) + + local maxKeyLength = 0 + + for k, v in pairs(data) do + maxKeyLength = math.max(maxKeyLength, string.len(k)) + end + + for k, v in pairs(data) do + dataLine = string.format("%-"..maxKeyLength.."s = %s\n", k, v) + et.trap_FS_Write(dataLine, string.len(dataLine), fileDescriptor) + end + + et.trap_FS_Write("\n", string.len("\n"), fileDescriptor) + + arrayCount = arrayCount + 1 + end + end + + et.trap_FS_FCloseFile(fileDescriptor) + + outputDebug("util.files.save(): "..arrayCount.." entries saved in "..et.trap_Milliseconds() - functionStart.." ms") + + return true +end + +return files \ No newline at end of file diff --git a/luascripts/util/settings.lua b/luascripts/util/settings.lua new file mode 100644 index 0000000..7a522c6 --- /dev/null +++ b/luascripts/util/settings.lua @@ -0,0 +1,107 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" + +local settings = {} + +local data = { + ["g_fileGreetings"] = "greetings.cfg", + ["g_fileRules"] = "rules.cfg", + ["g_fileSprees"] = "sprees.cfg", + ["g_jukeboxEnabled"] = 0, + ["g_spreeRecords"] = 1, + ["g_warnHistory"] = 1, + ["g_announceRevives"] = 1, + ["g_greetingArea"] = 3, + ["g_botGreetings"] = 1, + ["g_botRecords"] = 1, + ["g_welcomeMessage"] = "^dwolfadmin: ^9This server is running WolfAdmin, type ^7/wolfadmin ^9for more information.", + ["g_welcomeArea"] = 3, + ["g_evenerMinDifference"] = 2, + ["g_evenerMaxDifference"] = 5, + ["g_evenerInterval"] = 30, + ["g_voteNextMapTimeout"] = 0, + ["g_restrictedVotes"] = "", + ["g_renameLimit"] = 3, + ["g_renameInterval"] = 60, + ["g_debugWolfAdmin"] = 0, + ["omnibot_maxbots"] = 10, + ["db_type"] = "cfg", + ["db_hostname"] = "localhost", + ["db_port"] = 3306, + ["db_database"] = "wolfadmin", + ["db_username"] = "", + ["db_password"] = "", + ["sv_os"] = "unix" +} + +function settings.get(name) + return data[name] +end + +function settings.set(name, value) + data[name] = value +end + +function settings.load() + for setting, default in pairs(data) do + local cvar = et.trap_Cvar_Get(setting) + + if type(default) == "string" then + data[setting] = (cvar ~= "" and tostring(cvar) or default) + elseif type(default) == "number" then + data[setting] = (cvar ~= "" and tonumber(cvar) or default) + end + end + + local files = require "luascripts.wolfadmin.util.files" + local amount, array = files.loadCFG("wolfadmin.cfg", "[a-z]+", true) + + for blocksname, settings in pairs(array) do + for k, v in pairs(settings[1]) do + data[blocksname.."_"..k] = v + end + end + + local platform = string.lower(et.trap_Cvar_Get("sv_os")) + if not (platform == "unix" or platform == "windows") then + settings.set("sv_os", settings.determineOS()) + end +end + +function settings.determineOS() + local system = io.popen("uname -s"):read("*l") + + if system == "Linux" or system == "unix" or system == "FreeBSD" or system == "OpenBSD" or system == "NetBSD" or system == "Darwin" or system == "SunOS" or (system and system:match("^CYGWIN")) then + platform = "unix" + elseif system and (system:match("^Windows") or system:match("^MINGW")) then + platform = "windows" + else -- likely it's unix now + platform = "unix" + end + + return platform +end + +function settings.oninit(levelTime, randomSeed, restartMap) + settings.load() +end +events.handle("onGameInit", settings.oninit) + +return settings \ No newline at end of file diff --git a/luascripts/util/timers.lua b/luascripts/util/timers.lua new file mode 100644 index 0000000..d2e9126 --- /dev/null +++ b/luascripts/util/timers.lua @@ -0,0 +1,69 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" +local util = require "luascripts.wolfadmin.util.util" +local events = require "luascripts.wolfadmin.util.events" + +local timers = {} + +local data = {} +local nextId = 0 + +function timers.add(func, interval, rep, ...) + local args = {...} + + table.insert(data, { + ["id"] = nextId, + ["function"] = func, + ["start"] = et.trap_Milliseconds(), + ["interval"] = interval, + ["iteration"] = 0, + ["repeat"] = rep, + ["args"] = args + }) + + nextId = nextId + 1 + + return nextId - 1 +end + +function timers.remove(id) + for i = 1, #data do + if data[i]["id"] == id then + table.remove(data, i) + end + end +end + +function timers.ongameframe(levelTime) + for id, timer in pairs(data) do + if (et.trap_Milliseconds() - timer["start"]) > timer["interval"] then + timer["function"](unpack(timer["args"])) + timer["iteration"] = timer["iteration"] + 1 + + if timer["repeat"] == 0 or timer["iteration"] < timer["repeat"] then + timer["start"] = et.trap_Milliseconds() + else + timers.remove(timer["id"]) + end + end + end +end +events.handle("onGameFrame", timers.ongameframe) + +return timers \ No newline at end of file diff --git a/luascripts/util/util.lua b/luascripts/util/util.lua new file mode 100644 index 0000000..70605cf --- /dev/null +++ b/luascripts/util/util.lua @@ -0,0 +1,134 @@ + +-- WolfAdmin module for Wolfenstein: Enemy Territory servers. +-- Copyright (C) 2015 Timo 'Timothy' Smit + +-- 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 . + +local constants = require "luascripts.wolfadmin.util.constants" + +local util = {} + +function util.split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + + return t +end + +function util.escape(str) + return string.gsub(str, "([\"'])", "\\%1") +end + +function util.removeColors(str) + return string.gsub(str, "(\^[%a%d%p])", "") +end + +function util.getTeamName(teamId) + if teamId == constants.TEAM_AXIS then + return "Axis" + elseif teamId == constants.TEAM_ALLIES then + return "Allies" + elseif teamId == constants.TEAM_SPECTATORS then + return "Spectators" + else + return "unknown" + end +end + +function util.getTeamColor(teamId) + if teamId == constants.TEAM_AXIS then + return constants.TEAM_AXIS_COLOR + elseif teamId == constants.TEAM_ALLIES then + return constants.TEAM_ALLIES_COLOR + elseif teamId == constants.TEAM_SPECTATORS then + return constants.TEAM_SPECTATORS_COLOR + else + return constants.COLOR_MAIN + end +end + +function util.getTeamCode(teamId) + if teamId == constants.TEAM_AXIS then + return constants.TEAM_AXIS_SC + elseif teamId == constants.TEAM_ALLIES then + return constants.TEAM_ALLIES_SC + elseif teamId == constants.TEAM_SPECTATORS then + return constants.TEAM_SPECTATORS_SC + else + return "unknown" + end +end + +function util.getClassName(classId) + if classId == constants.CLASS_SOLDIER then + return "Soldier" + elseif classId == constants.CLASS_MEDIC then + return "Medic" + elseif classId == constants.CLASS_ENGINEER then + return "Engineer" + elseif classId == constants.CLASS_FIELDOPS then + return "Field Ops" + elseif classId == constants.CLASS_COVERTOPS then + return "Covert Ops" + else + return "unknown" + end +end + +function util.getAreaName(areaId) + if areaId == constants.AREA_CONSOLE then + return "csay -1" + elseif areaId == constants.AREA_POPUPS then + return "cpm" + elseif areaId == constants.AREA_CHAT then + return "chat" + elseif areaId == constants.AREA_CP then + return "cp" + else + return "cp" + end +end + +function util.getTimeFromString(str) + local amount, unit = string.match(str, "^([0-9]+)([smhdwy])$") + + if not (amount and unit) then return false end + + local multiplier = { + ["s"] = function(a) return a end, + ["m"] = function(a) return a * 60 end, + ["h"] = function(a) return a * 60 * 60 end, + ["d"] = function(a) return a * 60 * 60 * 24 end, + ["w"] = function(a) return a * 60 * 60 * 24 * 7 end, + ["y"] = function(a) return a * 60 * 60 * 24 * 365 end + } + + return multiplier[unit](amount) +end + +return util \ No newline at end of file